summary refs log tree commit diff
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2014-08-26 17:39:02 -0400
committerOren Novotny <oren@novotny.org>2014-08-26 17:39:02 -0400
commit6dbc12162af086bbcfbd583dcaa8144d049c7fcc (patch)
tree3cf9443720ad508eb5ff615130d57fc118cb7145
parentrename Crypto dir to crypto to match bc-git (diff)
parentRework the nonce-random initialisation and avoid GenerateSeed (diff)
downloadBouncyCastle.NET-ed25519-6dbc12162af086bbcfbd583dcaa8144d049c7fcc.tar.xz
Merge in bc-git to this repo
-rw-r--r--.gitattributes96
-rw-r--r--.gitignore158
-rw-r--r--FxCop/CustomDictionary.xml119
-rw-r--r--crypto-test/App.icobin0 -> 1078 bytes
-rw-r--r--crypto-test/CryptoTest.cs51
-rw-r--r--crypto-test/crypto-test.csproj104
-rw-r--r--crypto/Contributors.html6
-rw-r--r--crypto/License.html2
-rw-r--r--crypto/NBuild.build247
-rw-r--r--crypto/Readme.html4
-rw-r--r--crypto/bzip2/src/BZip2Constants.cs103
-rw-r--r--crypto/bzip2/src/CBZip2InputStream.cs2
-rw-r--r--crypto/bzip2/src/CBZip2OutputStream.cs21
-rw-r--r--crypto/bzip2/src/CRC.cs134
-rw-r--r--crypto/checklist.txt16
-rw-r--r--crypto/crypto.csproj15006
-rw-r--r--crypto/src/AssemblyInfo.cs20
-rw-r--r--crypto/src/asn1/ASN1Generator.cs27
-rw-r--r--crypto/src/asn1/ASN1OctetStringParser.cs10
-rw-r--r--crypto/src/asn1/ASN1SequenceParser.cs8
-rw-r--r--crypto/src/asn1/ASN1SetParser.cs8
-rw-r--r--crypto/src/asn1/ASN1StreamParser.cs14
-rw-r--r--crypto/src/asn1/ASN1TaggedObjectParser.cs10
-rw-r--r--crypto/src/asn1/Asn1Encodable.cs78
-rw-r--r--crypto/src/asn1/Asn1EncodableVector.cs93
-rw-r--r--crypto/src/asn1/Asn1Exception.cs5
-rw-r--r--crypto/src/asn1/Asn1InputStream.cs687
-rw-r--r--crypto/src/asn1/Asn1Null.cs18
-rw-r--r--crypto/src/asn1/Asn1Object.cs63
-rw-r--r--crypto/src/asn1/Asn1OctetString.cs119
-rw-r--r--crypto/src/asn1/Asn1OutputStream.cs35
-rw-r--r--crypto/src/asn1/Asn1ParsingException.cs5
-rw-r--r--crypto/src/asn1/Asn1Sequence.cs257
-rw-r--r--crypto/src/asn1/Asn1Set.cs383
-rw-r--r--crypto/src/asn1/Asn1TaggedObject.cs178
-rw-r--r--crypto/src/asn1/Asn1Tags.cs36
-rw-r--r--crypto/src/asn1/BERGenerator.cs102
-rw-r--r--crypto/src/asn1/BEROctetStringGenerator.cs146
-rw-r--r--crypto/src/asn1/BEROctetStringParser.cs36
-rw-r--r--crypto/src/asn1/BERSequenceGenerator.cs24
-rw-r--r--crypto/src/asn1/BERSequenceParser.cs24
-rw-r--r--crypto/src/asn1/BERSetGenerator.cs24
-rw-r--r--crypto/src/asn1/BERSetParser.cs24
-rw-r--r--crypto/src/asn1/BERTaggedObjectParser.cs71
-rw-r--r--crypto/src/asn1/BerApplicationSpecific.cs15
-rw-r--r--crypto/src/asn1/BerApplicationSpecificParser.cs29
-rw-r--r--crypto/src/asn1/BerNull.cs35
-rw-r--r--crypto/src/asn1/BerOctetString.cs135
-rw-r--r--crypto/src/asn1/BerOutputStream.cs36
-rw-r--r--crypto/src/asn1/BerSequence.cs69
-rw-r--r--crypto/src/asn1/BerSet.cs70
-rw-r--r--crypto/src/asn1/BerTaggedObject.cs108
-rw-r--r--crypto/src/asn1/ConstructedOctetStream.cs102
-rw-r--r--crypto/src/asn1/DERExternal.cs207
-rw-r--r--crypto/src/asn1/DERExternalParser.cs26
-rw-r--r--crypto/src/asn1/DERGenerator.cs107
-rw-r--r--crypto/src/asn1/DEROctetStringParser.cs36
-rw-r--r--crypto/src/asn1/DERSequenceGenerator.cs40
-rw-r--r--crypto/src/asn1/DERSequenceParser.cs24
-rw-r--r--crypto/src/asn1/DERSetGenerator.cs40
-rw-r--r--crypto/src/asn1/DERSetParser.cs24
-rw-r--r--crypto/src/asn1/DefiniteLengthInputStream.cs12
-rw-r--r--crypto/src/asn1/DerApplicationSpecific.cs237
-rw-r--r--crypto/src/asn1/DerBMPString.cs115
-rw-r--r--crypto/src/asn1/DerBitString.cs248
-rw-r--r--crypto/src/asn1/DerBoolean.cs86
-rw-r--r--crypto/src/asn1/DerEnumerated.cs66
-rw-r--r--crypto/src/asn1/DerGeneralString.cs81
-rw-r--r--crypto/src/asn1/DerGeneralizedTime.cs347
-rw-r--r--crypto/src/asn1/DerIA5String.cs145
-rw-r--r--crypto/src/asn1/DerInteger.cs117
-rw-r--r--crypto/src/asn1/DerNull.cs41
-rw-r--r--crypto/src/asn1/DerNumericString.cs138
-rw-r--r--crypto/src/asn1/DerObjectIdentifier.cs427
-rw-r--r--crypto/src/asn1/DerOctetString.cs34
-rw-r--r--crypto/src/asn1/DerOutputStream.cs160
-rw-r--r--crypto/src/asn1/DerPrintableString.cs163
-rw-r--r--crypto/src/asn1/DerSequence.cs2
-rw-r--r--crypto/src/asn1/DerSet.cs2
-rw-r--r--crypto/src/asn1/DerStringBase.cs22
-rw-r--r--crypto/src/asn1/DerT61String.cs102
-rw-r--r--crypto/src/asn1/DerTaggedObject.cs72
-rw-r--r--crypto/src/asn1/DerUTCTime.cs263
-rw-r--r--crypto/src/asn1/DerUTF8String.cs96
-rw-r--r--crypto/src/asn1/DerUniversalString.cs107
-rw-r--r--crypto/src/asn1/DerVisibleString.cs111
-rw-r--r--crypto/src/asn1/IAsn1ApplicationSpecificParser.cs10
-rw-r--r--crypto/src/asn1/IAsn1Choice.cs17
-rw-r--r--crypto/src/asn1/IAsn1Convertible.cs7
-rw-r--r--crypto/src/asn1/IAsn1String.cs10
-rw-r--r--crypto/src/asn1/IndefiniteLengthInputStream.cs12
-rw-r--r--crypto/src/asn1/LazyASN1InputStream.cs33
-rw-r--r--crypto/src/asn1/LazyDERSequence.cs10
-rw-r--r--crypto/src/asn1/LazyDERSet.cs10
-rw-r--r--crypto/src/asn1/LimitedInputStream.cs35
-rw-r--r--crypto/src/asn1/OidTokenizer.cs45
-rw-r--r--crypto/src/asn1/bc/BCObjectIdentifiers.cs39
-rw-r--r--crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs60
-rw-r--r--crypto/src/asn1/cmp/CertConfirmContent.cs47
-rw-r--r--crypto/src/asn1/cmp/CertOrEncCert.cs85
-rw-r--r--crypto/src/asn1/cmp/CertRepMessage.cs94
-rw-r--r--crypto/src/asn1/cmp/CertResponse.cs115
-rw-r--r--crypto/src/asn1/cmp/CertStatus.cs84
-rw-r--r--crypto/src/asn1/cmp/CertifiedKeyPair.cs114
-rw-r--r--crypto/src/asn1/cmp/Challenge.cs79
-rw-r--r--crypto/src/asn1/cmp/CmpCertificate.cs80
-rw-r--r--crypto/src/asn1/cmp/CmpObjectIdentifiers.cs106
-rw-r--r--crypto/src/asn1/cmp/CrlAnnContent.cs49
-rw-r--r--crypto/src/asn1/cmp/ErrorMsgContent.cs94
-rw-r--r--crypto/src/asn1/cmp/GenMsgContent.cs52
-rw-r--r--crypto/src/asn1/cmp/GenRepContent.cs52
-rw-r--r--crypto/src/asn1/cmp/InfoTypeAndValue.cs121
-rw-r--r--crypto/src/asn1/cmp/KeyRecRepContent.cs115
-rw-r--r--crypto/src/asn1/cmp/OobCertHash.cs87
-rw-r--r--crypto/src/asn1/cmp/PKIBody.cs186
-rw-r--r--crypto/src/asn1/cmp/PKIConfirmContent.cs34
-rw-r--r--crypto/src/asn1/cmp/PKIFailureInfo.cs73
-rw-r--r--crypto/src/asn1/cmp/PKIFreeText.cs97
-rw-r--r--crypto/src/asn1/cmp/PKIHeader.cs237
-rw-r--r--crypto/src/asn1/cmp/PKIHeaderBuilder.cs223
-rw-r--r--crypto/src/asn1/cmp/PKIMessage.cs140
-rw-r--r--crypto/src/asn1/cmp/PKIMessages.cs52
-rw-r--r--crypto/src/asn1/cmp/PKIStatus.cs62
-rw-r--r--crypto/src/asn1/cmp/PKIStatusInfo.cs165
-rw-r--r--crypto/src/asn1/cmp/PbmParameter.cs100
-rw-r--r--crypto/src/asn1/cmp/PollRepContent.cs66
-rw-r--r--crypto/src/asn1/cmp/PollReqContent.cs59
-rw-r--r--crypto/src/asn1/cmp/PopoDecKeyChallContent.cs47
-rw-r--r--crypto/src/asn1/cmp/PopoDecKeyRespContent.cs47
-rw-r--r--crypto/src/asn1/cmp/ProtectedPart.cs58
-rw-r--r--crypto/src/asn1/cmp/RevAnnContent.cs86
-rw-r--r--crypto/src/asn1/cmp/RevDetails.cs75
-rw-r--r--crypto/src/asn1/cmp/RevRepContent.cs112
-rw-r--r--crypto/src/asn1/cmp/RevRepContentBuilder.cs55
-rw-r--r--crypto/src/asn1/cmp/RevReqContent.cs52
-rw-r--r--crypto/src/asn1/cms/Attribute.cs70
-rw-r--r--crypto/src/asn1/cms/AttributeTable.cs6
-rw-r--r--crypto/src/asn1/cms/Attributes.cs88
-rw-r--r--crypto/src/asn1/cms/AuthEnvelopedData.cs203
-rw-r--r--crypto/src/asn1/cms/AuthEnvelopedDataParser.cs145
-rw-r--r--crypto/src/asn1/cms/AuthenticatedData.cs270
-rw-r--r--crypto/src/asn1/cms/AuthenticatedDataParser.cs182
-rw-r--r--crypto/src/asn1/cms/CMSAttributes.cs14
-rw-r--r--crypto/src/asn1/cms/CMSObjectIdentifiers.cs16
-rw-r--r--crypto/src/asn1/cms/CompressedData.cs96
-rw-r--r--crypto/src/asn1/cms/CompressedDataParser.cs47
-rw-r--r--crypto/src/asn1/cms/ContentInfo.cs155
-rw-r--r--crypto/src/asn1/cms/ContentInfoParser.cs40
-rw-r--r--crypto/src/asn1/cms/EncryptedContentInfo.cs94
-rw-r--r--crypto/src/asn1/cms/EncryptedContentInfoParser.cs46
-rw-r--r--crypto/src/asn1/cms/EncryptedData.cs95
-rw-r--r--crypto/src/asn1/cms/EnvelopedData.cs141
-rw-r--r--crypto/src/asn1/cms/EnvelopedDataParser.cs107
-rw-r--r--crypto/src/asn1/cms/Evidence.cs47
-rw-r--r--crypto/src/asn1/cms/IssuerAndSerialNumber.cs40
-rw-r--r--crypto/src/asn1/cms/KEKIdentifier.cs119
-rw-r--r--crypto/src/asn1/cms/KEKRecipientInfo.cs106
-rw-r--r--crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs92
-rw-r--r--crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs141
-rw-r--r--crypto/src/asn1/cms/KeyTransRecipientInfo.cs99
-rw-r--r--crypto/src/asn1/cms/MetaData.cs94
-rw-r--r--crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs168
-rw-r--r--crypto/src/asn1/cms/OriginatorInfo.cs121
-rw-r--r--crypto/src/asn1/cms/OriginatorPublicKey.cs87
-rw-r--r--crypto/src/asn1/cms/OtherKeyAttribute.cs70
-rw-r--r--crypto/src/asn1/cms/OtherRecipientInfo.cs50
-rw-r--r--crypto/src/asn1/cms/OtherRevocationInfoFormat.cs77
-rw-r--r--crypto/src/asn1/cms/PasswordRecipientInfo.cs133
-rw-r--r--crypto/src/asn1/cms/RecipientEncryptedKey.cs88
-rw-r--r--crypto/src/asn1/cms/RecipientIdentifier.cs89
-rw-r--r--crypto/src/asn1/cms/RecipientInfo.cs145
-rw-r--r--crypto/src/asn1/cms/RecipientKeyIdentifier.cs137
-rw-r--r--crypto/src/asn1/cms/SCVPReqRes.cs77
-rw-r--r--crypto/src/asn1/cms/SignedData.cs363
-rw-r--r--crypto/src/asn1/cms/SignedDataParser.cs112
-rw-r--r--crypto/src/asn1/cms/SignerIdentifier.cs89
-rw-r--r--crypto/src/asn1/cms/SignerInfo.cs136
-rw-r--r--crypto/src/asn1/cms/Time.cs118
-rw-r--r--crypto/src/asn1/cms/TimeStampAndCRL.cs62
-rw-r--r--crypto/src/asn1/cms/TimeStampTokenEvidence.cs65
-rw-r--r--crypto/src/asn1/cms/TimeStampedData.cs95
-rw-r--r--crypto/src/asn1/cms/TimeStampedDataParser.cs76
-rw-r--r--crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs103
-rw-r--r--crypto/src/asn1/crmf/AttributeTypeAndValue.cs66
-rw-r--r--crypto/src/asn1/crmf/CertId.cs58
-rw-r--r--crypto/src/asn1/crmf/CertReqMessages.cs52
-rw-r--r--crypto/src/asn1/crmf/CertReqMsg.cs106
-rw-r--r--crypto/src/asn1/crmf/CertRequest.cs82
-rw-r--r--crypto/src/asn1/crmf/CertTemplate.cs149
-rw-r--r--crypto/src/asn1/crmf/CertTemplateBuilder.cs125
-rw-r--r--crypto/src/asn1/crmf/Controls.cs52
-rw-r--r--crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs23
-rw-r--r--crypto/src/asn1/crmf/EncKeyWithID.cs103
-rw-r--r--crypto/src/asn1/crmf/EncryptedKey.cs78
-rw-r--r--crypto/src/asn1/crmf/EncryptedValue.cs154
-rw-r--r--crypto/src/asn1/crmf/OptionalValidity.cs15
-rw-r--r--crypto/src/asn1/crmf/PKIArchiveOptions.cs105
-rw-r--r--crypto/src/asn1/crmf/PKIPublicationInfo.cs64
-rw-r--r--crypto/src/asn1/crmf/PKMacValue.cs89
-rw-r--r--crypto/src/asn1/crmf/PopoPrivKey.cs84
-rw-r--r--crypto/src/asn1/crmf/PopoSigningKey.cs115
-rw-r--r--crypto/src/asn1/crmf/PopoSigningKeyInput.cs115
-rw-r--r--crypto/src/asn1/crmf/ProofOfPossession.cs98
-rw-r--r--crypto/src/asn1/crmf/SinglePubInfo.cs58
-rw-r--r--crypto/src/asn1/crmf/SubsequentMessage.cs27
-rw-r--r--crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs7
-rw-r--r--crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs79
-rw-r--r--crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs86
-rw-r--r--crypto/src/asn1/cryptopro/GOST28147Parameters.cs63
-rw-r--r--crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs123
-rw-r--r--crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs87
-rw-r--r--crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs99
-rw-r--r--crypto/src/asn1/eac/EACObjectIdentifiers.cs50
-rw-r--r--crypto/src/asn1/esf/CertificateValues.cs85
-rw-r--r--crypto/src/asn1/esf/CommitmentTypeIdentifier.cs17
-rw-r--r--crypto/src/asn1/esf/CommitmentTypeIndication.cs95
-rw-r--r--crypto/src/asn1/esf/CommitmentTypeQualifier.cs119
-rw-r--r--crypto/src/asn1/esf/CompleteCertificateRefs.cs84
-rw-r--r--crypto/src/asn1/esf/CompleteRevocationRefs.cs84
-rw-r--r--crypto/src/asn1/esf/CrlIdentifier.cs110
-rw-r--r--crypto/src/asn1/esf/CrlListID.cs89
-rw-r--r--crypto/src/asn1/esf/CrlOcspRef.cs111
-rw-r--r--crypto/src/asn1/esf/CrlValidatedID.cs89
-rw-r--r--crypto/src/asn1/esf/ESFAttributes.cs25
-rw-r--r--crypto/src/asn1/esf/OcspIdentifier.cs77
-rw-r--r--crypto/src/asn1/esf/OcspListID.cs88
-rw-r--r--crypto/src/asn1/esf/OcspResponsesID.cs92
-rw-r--r--crypto/src/asn1/esf/OtherCertID.cs93
-rw-r--r--crypto/src/asn1/esf/OtherHash.cs88
-rw-r--r--crypto/src/asn1/esf/OtherHashAlgAndValue.cs94
-rw-r--r--crypto/src/asn1/esf/OtherRevRefs.cs78
-rw-r--r--crypto/src/asn1/esf/OtherRevVals.cs78
-rw-r--r--crypto/src/asn1/esf/OtherSigningCertificate.cs138
-rw-r--r--crypto/src/asn1/esf/RevocationValues.cs165
-rw-r--r--crypto/src/asn1/esf/SigPolicyQualifierInfo.cs71
-rw-r--r--crypto/src/asn1/esf/SignaturePolicyId.cs145
-rw-r--r--crypto/src/asn1/esf/SignaturePolicyIdentifier.cs64
-rw-r--r--crypto/src/asn1/esf/SignerAttribute.cs96
-rw-r--r--crypto/src/asn1/esf/SignerLocation.cs144
-rw-r--r--crypto/src/asn1/ess/ContentHints.cs92
-rw-r--r--crypto/src/asn1/ess/ContentIdentifier.cs65
-rw-r--r--crypto/src/asn1/ess/ESSCertID.cs93
-rw-r--r--crypto/src/asn1/ess/ESSCertIDv2.cs266
-rw-r--r--crypto/src/asn1/ess/OtherCertID.cs132
-rw-r--r--crypto/src/asn1/ess/OtherSigningCertificate.cs109
-rw-r--r--crypto/src/asn1/ess/SigningCertificate.cs108
-rw-r--r--crypto/src/asn1/ess/SigningCertificateV2.cs204
-rw-r--r--crypto/src/asn1/gnu/GNUObjectIdentifiers.cs31
-rw-r--r--crypto/src/asn1/iana/IANAObjectIdentifiers.cs18
-rw-r--r--crypto/src/asn1/icao/CscaMasterList.cs83
-rw-r--r--crypto/src/asn1/icao/DataGroupHash.cs86
-rw-r--r--crypto/src/asn1/icao/ICAOObjectIdentifiers.cs34
-rw-r--r--crypto/src/asn1/icao/LDSSecurityObject.cs145
-rw-r--r--crypto/src/asn1/icao/LDSVersionInfo.cs61
-rw-r--r--crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs177
-rw-r--r--crypto/src/asn1/isismtt/ocsp/CertHash.cs121
-rw-r--r--crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs186
-rw-r--r--crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs70
-rw-r--r--crypto/src/asn1/isismtt/x509/AdmissionSyntax.csbin20844 -> 11549 bytes
-rw-r--r--crypto/src/asn1/isismtt/x509/Admissions.cs186
-rw-r--r--crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs170
-rw-r--r--crypto/src/asn1/isismtt/x509/MonetaryLimit.cs121
-rw-r--r--crypto/src/asn1/isismtt/x509/NamingAuthority.cs214
-rw-r--r--crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs232
-rw-r--r--crypto/src/asn1/isismtt/x509/ProfessionInfo.cs386
-rw-r--r--crypto/src/asn1/isismtt/x509/Restriction.cs81
-rw-r--r--crypto/src/asn1/kisa/KISAObjectIdentifiers.cs8
-rw-r--r--crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs18
-rw-r--r--crypto/src/asn1/misc/CAST5CBCParameters.cs74
-rw-r--r--crypto/src/asn1/misc/IDEACBCPar.cs68
-rw-r--r--crypto/src/asn1/misc/MiscObjectIdentifiers.cs48
-rw-r--r--crypto/src/asn1/misc/NetscapeCertType.cs54
-rw-r--r--crypto/src/asn1/misc/NetscapeRevocationURL.cs18
-rw-r--r--crypto/src/asn1/misc/VerisignCzagExtension.cs18
-rw-r--r--crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs67
-rw-r--r--crypto/src/asn1/nist/NISTNamedCurves.cs164
-rw-r--r--crypto/src/asn1/nist/NISTObjectIdentifiers.cs36
-rw-r--r--crypto/src/asn1/ntt/NTTObjectIdentifiers.cs14
-rw-r--r--crypto/src/asn1/ocsp/BasicOCSPResponse.cs131
-rw-r--r--crypto/src/asn1/ocsp/CertID.cs98
-rw-r--r--crypto/src/asn1/ocsp/CertStatus.cs94
-rw-r--r--crypto/src/asn1/ocsp/CrlID.cs82
-rw-r--r--crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs23
-rw-r--r--crypto/src/asn1/ocsp/OCSPRequest.cs89
-rw-r--r--crypto/src/asn1/ocsp/OCSPResponse.cs90
-rw-r--r--crypto/src/asn1/ocsp/OCSPResponseStatus.cs41
-rw-r--r--crypto/src/asn1/ocsp/Request.cs90
-rw-r--r--crypto/src/asn1/ocsp/ResponderID.cs107
-rw-r--r--crypto/src/asn1/ocsp/ResponseBytes.cs82
-rw-r--r--crypto/src/asn1/ocsp/ResponseData.cs158
-rw-r--r--crypto/src/asn1/ocsp/RevokedInfo.cs96
-rw-r--r--crypto/src/asn1/ocsp/ServiceLocator.cs95
-rw-r--r--crypto/src/asn1/ocsp/Signature.cs110
-rw-r--r--crypto/src/asn1/ocsp/SingleResponse.cs137
-rw-r--r--crypto/src/asn1/ocsp/TBSRequest.cs151
-rw-r--r--crypto/src/asn1/oiw/ElGamalParameter.cs47
-rw-r--r--crypto/src/asn1/oiw/OIWObjectIdentifiers.cs29
-rw-r--r--crypto/src/asn1/pkcs/Attribute.cs79
-rw-r--r--crypto/src/asn1/pkcs/AuthenticatedSafe.cs37
-rw-r--r--crypto/src/asn1/pkcs/CertBag.cs46
-rw-r--r--crypto/src/asn1/pkcs/CertificationRequest.cs81
-rw-r--r--crypto/src/asn1/pkcs/CertificationRequestInfo.cs123
-rw-r--r--crypto/src/asn1/pkcs/ContentInfo.cs56
-rw-r--r--crypto/src/asn1/pkcs/DHParameter.cs72
-rw-r--r--crypto/src/asn1/pkcs/EncryptedData.cs104
-rw-r--r--crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs78
-rw-r--r--crypto/src/asn1/pkcs/EncryptionScheme.cs49
-rw-r--r--crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs71
-rw-r--r--crypto/src/asn1/pkcs/KeyDerivationFunc.cs21
-rw-r--r--crypto/src/asn1/pkcs/MacData.cs96
-rw-r--r--crypto/src/asn1/pkcs/PBEParameter.cs60
-rw-r--r--crypto/src/asn1/pkcs/PBES2Parameters.cs66
-rw-r--r--crypto/src/asn1/pkcs/PBKDF2Params.cs86
-rw-r--r--crypto/src/asn1/pkcs/PKCS12PBEParams.cs63
-rw-r--r--crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs256
-rw-r--r--crypto/src/asn1/pkcs/Pfx.cs65
-rw-r--r--crypto/src/asn1/pkcs/PrivateKeyInfo.cs147
-rw-r--r--crypto/src/asn1/pkcs/RC2CBCParameter.cs81
-rw-r--r--crypto/src/asn1/pkcs/RSAESOAEPparams.cs145
-rw-r--r--crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs145
-rw-r--r--crypto/src/asn1/pkcs/RSASSAPSSparams.cs165
-rw-r--r--crypto/src/asn1/pkcs/SafeBag.cs70
-rw-r--r--crypto/src/asn1/pkcs/SignedData.cs126
-rw-r--r--crypto/src/asn1/pkcs/SignerInfo.cs154
-rw-r--r--crypto/src/asn1/sec/ECPrivateKeyStructure.cs226
-rw-r--r--crypto/src/asn1/sec/SECNamedCurves.cs2411
-rw-r--r--crypto/src/asn1/sec/SECObjectIdentifiers.cs52
-rw-r--r--crypto/src/asn1/smime/SMIMEAttributes.cs11
-rw-r--r--crypto/src/asn1/smime/SMIMECapabilities.cs2
-rw-r--r--crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs16
-rw-r--r--crypto/src/asn1/smime/SMIMECapability.cs101
-rw-r--r--crypto/src/asn1/smime/SMIMECapabilityVector.cs37
-rw-r--r--crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs44
-rw-r--r--crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs872
-rw-r--r--crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs45
-rw-r--r--crypto/src/asn1/tsp/Accuracy.cs149
-rw-r--r--crypto/src/asn1/tsp/MessageImprint.cs74
-rw-r--r--crypto/src/asn1/tsp/TSTInfo.cs249
-rw-r--r--crypto/src/asn1/tsp/TimeStampReq.cs164
-rw-r--r--crypto/src/asn1/tsp/TimeStampResp.cs80
-rw-r--r--crypto/src/asn1/util/Asn1Dump.cs289
-rw-r--r--crypto/src/asn1/util/Dump.cs4
-rw-r--r--crypto/src/asn1/util/FilterStream.cs9
-rw-r--r--crypto/src/asn1/x500/DirectoryString.cs75
-rw-r--r--crypto/src/asn1/x509/AccessDescription.cs83
-rw-r--r--crypto/src/asn1/x509/AlgorithmIdentifier.cs87
-rw-r--r--crypto/src/asn1/x509/AttCertIssuer.cs86
-rw-r--r--crypto/src/asn1/x509/AttCertValidityPeriod.cs78
-rw-r--r--crypto/src/asn1/x509/Attribute.cs82
-rw-r--r--crypto/src/asn1/x509/AttributeCertificate.cs81
-rw-r--r--crypto/src/asn1/x509/AttributeCertificateInfo.cs156
-rw-r--r--crypto/src/asn1/x509/AttributeTable.cs6
-rw-r--r--crypto/src/asn1/x509/AuthorityInformationAccess.cs183
-rw-r--r--crypto/src/asn1/x509/AuthorityKeyIdentifier.cs211
-rw-r--r--crypto/src/asn1/x509/BasicConstraints.cs133
-rw-r--r--crypto/src/asn1/x509/CRLDistPoint.cs93
-rw-r--r--crypto/src/asn1/x509/CRLNumber.cs30
-rw-r--r--crypto/src/asn1/x509/CRLReason.cs61
-rw-r--r--crypto/src/asn1/x509/CertPolicyId.cs20
-rw-r--r--crypto/src/asn1/x509/CertificateList.cs108
-rw-r--r--crypto/src/asn1/x509/CertificatePair.cs160
-rw-r--r--crypto/src/asn1/x509/CertificatePolicies.cs81
-rw-r--r--crypto/src/asn1/x509/DSAParameter.cs77
-rw-r--r--crypto/src/asn1/x509/DigestInfo.cs76
-rw-r--r--crypto/src/asn1/x509/DisplayText.cs172
-rw-r--r--crypto/src/asn1/x509/DistributionPoint.cs161
-rw-r--r--crypto/src/asn1/x509/DistributionPointName.cs130
-rw-r--r--crypto/src/asn1/x509/ExtendedKeyUsage.cs87
-rw-r--r--crypto/src/asn1/x509/GeneralName.cs418
-rw-r--r--crypto/src/asn1/x509/GeneralNames.cs95
-rw-r--r--crypto/src/asn1/x509/GeneralSubtree.cs189
-rw-r--r--crypto/src/asn1/x509/Holder.cs257
-rw-r--r--crypto/src/asn1/x509/IetfAttrSyntax.cs161
-rw-r--r--crypto/src/asn1/x509/IssuerSerial.cs98
-rw-r--r--crypto/src/asn1/x509/IssuingDistributionPoint.cs247
-rw-r--r--crypto/src/asn1/x509/KeyPurposeId.cs36
-rw-r--r--crypto/src/asn1/x509/KeyUsage.cs79
-rw-r--r--crypto/src/asn1/x509/NameConstraints.cs2
-rw-r--r--crypto/src/asn1/x509/NoticeReference.cs261
-rw-r--r--crypto/src/asn1/x509/ObjectDigestInfo.cs177
-rw-r--r--crypto/src/asn1/x509/PolicyInformation.cs80
-rw-r--r--crypto/src/asn1/x509/PolicyMappings.cs2
-rw-r--r--crypto/src/asn1/x509/PolicyQualifierId.cs28
-rw-r--r--crypto/src/asn1/x509/PolicyQualifierInfo.cs160
-rw-r--r--crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs82
-rw-r--r--crypto/src/asn1/x509/RSAPublicKeyStructure.cs92
-rw-r--r--crypto/src/asn1/x509/ReasonFlags.cs46
-rw-r--r--crypto/src/asn1/x509/RoleSyntax.cs230
-rw-r--r--crypto/src/asn1/x509/SubjectDirectoryAttributes.cs2
-rw-r--r--crypto/src/asn1/x509/SubjectKeyIdentifier.cs141
-rw-r--r--crypto/src/asn1/x509/SubjectPublicKeyInfo.cs102
-rw-r--r--crypto/src/asn1/x509/TBSCertList.cs274
-rw-r--r--crypto/src/asn1/x509/TBSCertificateStructure.cs185
-rw-r--r--crypto/src/asn1/x509/Target.cs139
-rw-r--r--crypto/src/asn1/x509/TargetInformation.cs123
-rw-r--r--crypto/src/asn1/x509/Targets.cs121
-rw-r--r--crypto/src/asn1/x509/Time.cs76
-rw-r--r--crypto/src/asn1/x509/UserNotice.cs102
-rw-r--r--crypto/src/asn1/x509/V1TBSCertificateGenerator.cs108
-rw-r--r--crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs137
-rw-r--r--crypto/src/asn1/x509/V2Form.cs84
-rw-r--r--crypto/src/asn1/x509/V2TBSCertListGenerator.cs201
-rw-r--r--crypto/src/asn1/x509/V3TBSCertificateGenerator.cs168
-rw-r--r--crypto/src/asn1/x509/X509Attributes.cs9
-rw-r--r--crypto/src/asn1/x509/X509CertificateStructure.cs86
-rw-r--r--crypto/src/asn1/x509/X509DefaultEntryConverter.cs63
-rw-r--r--crypto/src/asn1/x509/X509Extension.cs79
-rw-r--r--crypto/src/asn1/x509/X509Extensions.cs2
-rw-r--r--crypto/src/asn1/x509/X509ExtensionsGenerator.cs81
-rw-r--r--crypto/src/asn1/x509/X509Name.cs1100
-rw-r--r--crypto/src/asn1/x509/X509NameEntryConverter.cs89
-rw-r--r--crypto/src/asn1/x509/X509NameTokenizer.cs104
-rw-r--r--crypto/src/asn1/x509/X509ObjectIdentifiers.cs59
-rw-r--r--crypto/src/asn1/x509/qualified/BiometricData.cs112
-rw-r--r--crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs19
-rw-r--r--crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs84
-rw-r--r--crypto/src/asn1/x509/qualified/MonetaryValue.cs83
-rw-r--r--crypto/src/asn1/x509/qualified/QCStatement.cs85
-rw-r--r--crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs21
-rw-r--r--crypto/src/asn1/x509/qualified/SemanticsInformation.cs124
-rw-r--r--crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs91
-rw-r--r--crypto/src/asn1/x509/sigi/NameOrPseudonym.cs177
-rw-r--r--crypto/src/asn1/x509/sigi/PersonalData.cs210
-rw-r--r--crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs49
-rw-r--r--crypto/src/asn1/x9/DHDomainParameters.cs116
-rw-r--r--crypto/src/asn1/x9/DHPublicKey.cs44
-rw-r--r--crypto/src/asn1/x9/DHValidationParms.cs62
-rw-r--r--crypto/src/asn1/x9/ECNamedCurveTable.cs118
-rw-r--r--crypto/src/asn1/x9/KeySpecificInfo.cs58
-rw-r--r--crypto/src/asn1/x9/OtherInfo.cs88
-rw-r--r--crypto/src/asn1/x9/X962NamedCurves.cs1456
-rw-r--r--crypto/src/asn1/x9/X962Parameters.cs53
-rw-r--r--crypto/src/asn1/x9/X9Curve.cs161
-rw-r--r--crypto/src/asn1/x9/X9ECParameters.cs108
-rw-r--r--crypto/src/asn1/x9/X9ECParametersHolder.cs22
-rw-r--r--crypto/src/asn1/x9/X9ECPoint.cs12
-rw-r--r--crypto/src/asn1/x9/X9FieldElement.cs90
-rw-r--r--crypto/src/asn1/x9/X9FieldID.cs144
-rw-r--r--crypto/src/asn1/x9/X9IntegerConverter.cs56
-rw-r--r--crypto/src/asn1/x9/X9ObjectIdentifiers.cs168
-rw-r--r--crypto/src/bcpg/ArmoredInputStream.cs14
-rw-r--r--crypto/src/bcpg/ArmoredOutputStream.cs51
-rw-r--r--crypto/src/bcpg/BcpgInputStream.cs14
-rw-r--r--crypto/src/bcpg/BcpgObject.cs8
-rw-r--r--crypto/src/bcpg/BcpgOutputStream.cs14
-rw-r--r--crypto/src/bcpg/CompressedDataPacket.cs24
-rw-r--r--crypto/src/bcpg/CompressionAlgorithmTags.cs11
-rw-r--r--crypto/src/bcpg/ContainedPacket.cs22
-rw-r--r--crypto/src/bcpg/Crc24.cs46
-rw-r--r--crypto/src/bcpg/DsaPublicBcpgKey.cs102
-rw-r--r--crypto/src/bcpg/DsaSecretBcpgKey.cs61
-rw-r--r--crypto/src/bcpg/ElGamalPublicBcpgKey.cs71
-rw-r--r--crypto/src/bcpg/ElGamalSecretBcpgKey.cs61
-rw-r--r--crypto/src/bcpg/ExperimentalPacket.cs38
-rw-r--r--crypto/src/bcpg/HashAlgorithmTags.cs19
-rw-r--r--crypto/src/bcpg/IBcpgKey.cs16
-rw-r--r--crypto/src/bcpg/InputStreamPacket.cs20
-rw-r--r--crypto/src/bcpg/LiteralDataPacket.cs57
-rw-r--r--crypto/src/bcpg/MPInteger.cs59
-rw-r--r--crypto/src/bcpg/MarkerPacket.cs24
-rw-r--r--crypto/src/bcpg/ModDetectionCodePacket.cs42
-rw-r--r--crypto/src/bcpg/OnePassSignaturePacket.cs93
-rw-r--r--crypto/src/bcpg/OutputStreamPacket.cs24
-rw-r--r--crypto/src/bcpg/Packet.cs7
-rw-r--r--crypto/src/bcpg/PacketTags.cs30
-rw-r--r--crypto/src/bcpg/PublicKeyAlgorithmTags.cs28
-rw-r--r--crypto/src/bcpg/PublicKeyEncSessionPacket.cs103
-rw-r--r--crypto/src/bcpg/PublicKeyPacket.cs48
-rw-r--r--crypto/src/bcpg/PublicSubkeyPacket.cs30
-rw-r--r--crypto/src/bcpg/RsaPublicBcpgKey.cs66
-rw-r--r--crypto/src/bcpg/RsaSecretBcpgKey.cs114
-rw-r--r--crypto/src/bcpg/S2k.cs147
-rw-r--r--crypto/src/bcpg/SecretKeyPacket.cs170
-rw-r--r--crypto/src/bcpg/SecretSubkeyPacket.cs43
-rw-r--r--crypto/src/bcpg/SignaturePacket.cs472
-rw-r--r--crypto/src/bcpg/SignatureSubpacket.cs76
-rw-r--r--crypto/src/bcpg/SignatureSubpacketTags.cs33
-rw-r--r--crypto/src/bcpg/SignatureSubpacketsReader.cs88
-rw-r--r--crypto/src/bcpg/SymmetricEncDataPacket.cs15
-rw-r--r--crypto/src/bcpg/SymmetricEncIntegrityPacket.cs18
-rw-r--r--crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs25
-rw-r--r--crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs91
-rw-r--r--crypto/src/bcpg/TrustPacket.cs43
-rw-r--r--crypto/src/bcpg/UserAttributePacket.cs61
-rw-r--r--crypto/src/bcpg/UserAttributeSubpacket.cs42
-rw-r--r--crypto/src/bcpg/UserAttributeSubpacketTags.cs10
-rw-r--r--crypto/src/bcpg/UserAttributeSubpacketsReader.cs100
-rw-r--r--crypto/src/bcpg/UserIdPacket.cs37
-rw-r--r--crypto/src/bcpg/attr/ImageAttrib.cs70
-rw-r--r--crypto/src/bcpg/sig/EmbeddedSignature.cs18
-rw-r--r--crypto/src/bcpg/sig/Exportable.cs47
-rw-r--r--crypto/src/bcpg/sig/IssuerKeyId.cs61
-rw-r--r--crypto/src/bcpg/sig/KeyExpirationTime.cs56
-rw-r--r--crypto/src/bcpg/sig/KeyFlags.cs74
-rw-r--r--crypto/src/bcpg/sig/NotationData.cs112
-rw-r--r--crypto/src/bcpg/sig/PreferredAlgorithms.cs54
-rw-r--r--crypto/src/bcpg/sig/PrimaryUserId.cs48
-rw-r--r--crypto/src/bcpg/sig/Revocable.cs48
-rw-r--r--crypto/src/bcpg/sig/RevocationKey.cs1
-rw-r--r--crypto/src/bcpg/sig/RevocationKeyTags.cs9
-rw-r--r--crypto/src/bcpg/sig/RevocationReason.cs1
-rw-r--r--crypto/src/bcpg/sig/RevocationReasonTags.cs14
-rw-r--r--crypto/src/bcpg/sig/SignatureCreationTime.cs47
-rw-r--r--crypto/src/bcpg/sig/SignatureExpirationTime.cs54
-rw-r--r--crypto/src/bcpg/sig/SignerUserId.cs52
-rw-r--r--crypto/src/bcpg/sig/TrustSignature.cs43
-rw-r--r--crypto/src/cms/BaseDigestCalculator.cs23
-rw-r--r--crypto/src/cms/CMSAttributeTableGenerationException.cs5
-rw-r--r--crypto/src/cms/CMSAttributeTableGenerator.cs25
-rw-r--r--crypto/src/cms/CMSAuthEnvelopedData.cs112
-rw-r--r--crypto/src/cms/CMSAuthEnvelopedGenerator.cs16
-rw-r--r--crypto/src/cms/CMSAuthenticatedData.cs137
-rw-r--r--crypto/src/cms/CMSAuthenticatedDataGenerator.cs4
-rw-r--r--crypto/src/cms/CMSAuthenticatedDataParser.cs214
-rw-r--r--crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs27
-rw-r--r--crypto/src/cms/CMSAuthenticatedGenerator.cs35
-rw-r--r--crypto/src/cms/CMSCompressedData.cs2
-rw-r--r--crypto/src/cms/CMSCompressedDataGenerator.cs2
-rw-r--r--crypto/src/cms/CMSCompressedDataParser.cs57
-rw-r--r--crypto/src/cms/CMSCompressedDataStreamGenerator.cs28
-rw-r--r--crypto/src/cms/CMSContentInfoParser.cs2
-rw-r--r--crypto/src/cms/CMSEnvelopedData.cs115
-rw-r--r--crypto/src/cms/CMSEnvelopedDataGenerator.cs2
-rw-r--r--crypto/src/cms/CMSEnvelopedDataParser.cs161
-rw-r--r--crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs32
-rw-r--r--crypto/src/cms/CMSEnvelopedGenerator.cs331
-rw-r--r--crypto/src/cms/CMSEnvelopedHelper.cs311
-rw-r--r--crypto/src/cms/CMSException.cs9
-rw-r--r--crypto/src/cms/CMSPBEKey.cs109
-rw-r--r--crypto/src/cms/CMSProcessable.cs19
-rw-r--r--crypto/src/cms/CMSProcessableByteArray.cs36
-rw-r--r--crypto/src/cms/CMSProcessableFile.cs3
-rw-r--r--crypto/src/cms/CMSProcessableInputStream.cs2
-rw-r--r--crypto/src/cms/CMSReadable.cs10
-rw-r--r--crypto/src/cms/CMSSecureReadable.cs14
-rw-r--r--crypto/src/cms/CMSSignedData.cs425
-rw-r--r--crypto/src/cms/CMSSignedDataGenerator.cs6
-rw-r--r--crypto/src/cms/CMSSignedDataParser.cs9
-rw-r--r--crypto/src/cms/CMSSignedDataStreamGenerator.cs150
-rw-r--r--crypto/src/cms/CMSSignedGenerator.cs261
-rw-r--r--crypto/src/cms/CMSSignedHelper.cs319
-rw-r--r--crypto/src/cms/CMSStreamException.cs3
-rw-r--r--crypto/src/cms/CMSTypedStream.cs4
-rw-r--r--crypto/src/cms/CMSUtils.cs186
-rw-r--r--crypto/src/cms/CounterSignatureDigestCalculator.cs28
-rw-r--r--crypto/src/cms/DefaultAuthenticatedAttributeTableGenerator.cs90
-rw-r--r--crypto/src/cms/DefaultSignedAttributeTableGenerator.cs4
-rw-r--r--crypto/src/cms/DigOutputStream.cs28
-rw-r--r--crypto/src/cms/IDigestCalculator.cs9
-rw-r--r--crypto/src/cms/KEKRecipientInfoGenerator.cs137
-rw-r--r--crypto/src/cms/KEKRecipientInformation.cs62
-rw-r--r--crypto/src/cms/KeyAgreeRecipientInfoGenerator.cs171
-rw-r--r--crypto/src/cms/KeyAgreeRecipientInformation.cs410
-rw-r--r--crypto/src/cms/KeyTransRecipientInfoGenerator.cs87
-rw-r--r--crypto/src/cms/KeyTransRecipientInformation.cs113
-rw-r--r--crypto/src/cms/MacOutputStream.cs28
-rw-r--r--crypto/src/cms/OriginatorId.cs51
-rw-r--r--crypto/src/cms/OriginatorInfoGenerator.cs42
-rw-r--r--crypto/src/cms/OriginatorInformation.cs96
-rw-r--r--crypto/src/cms/PKCS5Scheme2PBEKey.cs64
-rw-r--r--crypto/src/cms/PKCS5Scheme2UTF8PBEKey.cs64
-rw-r--r--crypto/src/cms/PasswordRecipientInfoGenerator.cs69
-rw-r--r--crypto/src/cms/PasswordRecipientInformation.cs79
-rw-r--r--crypto/src/cms/RecipientId.cs58
-rw-r--r--crypto/src/cms/RecipientInfoGenerator.cs26
-rw-r--r--crypto/src/cms/RecipientInformation.cs126
-rw-r--r--crypto/src/cms/RecipientInformationStore.cs86
-rw-r--r--crypto/src/cms/SigOutputStream.cs43
-rw-r--r--crypto/src/cms/SignerId.cs51
-rw-r--r--crypto/src/cms/SignerInfoGenerator.cs14
-rw-r--r--crypto/src/cms/SignerInformation.cs758
-rw-r--r--crypto/src/cms/SignerInformationStore.cs74
-rw-r--r--crypto/src/cms/SimpleAttributeTableGenerator.cs28
-rw-r--r--crypto/src/crypto/AsymmetricCipherKeyPair.cs52
-rw-r--r--crypto/src/crypto/AsymmetricKeyParameter.cs47
-rw-r--r--crypto/src/crypto/BufferedAeadBlockCipher.cs50
-rw-r--r--crypto/src/crypto/BufferedAsymmetricBlockCipher.cs152
-rw-r--r--crypto/src/crypto/BufferedBlockCipher.cs9
-rw-r--r--crypto/src/crypto/BufferedCipherBase.cs113
-rw-r--r--crypto/src/crypto/BufferedIesCipher.cs113
-rw-r--r--crypto/src/crypto/BufferedStreamCipher.cs131
-rw-r--r--crypto/src/crypto/CipherKeyGenerator.cs83
-rw-r--r--crypto/src/crypto/CryptoException.cs3
-rw-r--r--crypto/src/crypto/DataLengthException.cs3
-rw-r--r--crypto/src/crypto/IAsymmetricBlockCipher.cs30
-rw-r--r--crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs24
-rw-r--r--crypto/src/crypto/IBasicAgreement.cs5
-rw-r--r--crypto/src/crypto/IBlockCipher.cs36
-rw-r--r--crypto/src/crypto/IBufferedCipher.cs44
-rw-r--r--crypto/src/crypto/ICipherParameters.cs11
-rw-r--r--crypto/src/crypto/IDSA.cs40
-rw-r--r--crypto/src/crypto/IDerivationFunction.cs24
-rw-r--r--crypto/src/crypto/IDerivationParameters.cs11
-rw-r--r--crypto/src/crypto/IDigest.cs61
-rw-r--r--crypto/src/crypto/IMac.cs69
-rw-r--r--crypto/src/crypto/ISigner.cs50
-rw-r--r--crypto/src/crypto/ISignerWithRecovery.cs37
-rw-r--r--crypto/src/crypto/IStreamCipher.cs45
-rw-r--r--crypto/src/crypto/IWrapper.cs18
-rw-r--r--crypto/src/crypto/InvalidCipherTextException.cs3
-rw-r--r--crypto/src/crypto/KeyGenerationParameters.cs55
-rw-r--r--crypto/src/crypto/MaxBytesExceededException.cs5
-rw-r--r--crypto/src/crypto/PbeParametersGenerator.cs366
-rw-r--r--crypto/src/crypto/StreamBlockCipher.cs109
-rw-r--r--crypto/src/crypto/agreement/DHAgreement.cs93
-rw-r--r--crypto/src/crypto/agreement/DHBasicAgreement.cs104
-rw-r--r--crypto/src/crypto/agreement/DHStandardGroups.cs206
-rw-r--r--crypto/src/crypto/agreement/ECDHBasicAgreement.cs31
-rw-r--r--crypto/src/crypto/agreement/ECDHCBasicAgreement.cs32
-rw-r--r--crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs7
-rw-r--r--crypto/src/crypto/agreement/ECMqvBasicAgreement.cs154
-rw-r--r--crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs7
-rw-r--r--crypto/src/crypto/agreement/kdf/DHKdfParameters.cs57
-rw-r--r--crypto/src/crypto/agreement/kdf/DHKekGenerator.cs227
-rw-r--r--crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs106
-rw-r--r--crypto/src/crypto/agreement/srp/SRP6Client.cs93
-rw-r--r--crypto/src/crypto/agreement/srp/SRP6Server.cs90
-rw-r--r--crypto/src/crypto/agreement/srp/SRP6Utilities.cs85
-rw-r--r--crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs49
-rw-r--r--crypto/src/crypto/digests/GOST3411Digest.cs49
-rw-r--r--crypto/src/crypto/digests/GeneralDigest.cs15
-rw-r--r--crypto/src/crypto/digests/LongDigest.cs15
-rw-r--r--crypto/src/crypto/digests/MD2Digest.cs26
-rw-r--r--crypto/src/crypto/digests/MD4Digest.cs23
-rw-r--r--crypto/src/crypto/digests/MD5Digest.cs288
-rw-r--r--crypto/src/crypto/digests/NullDigest.cs49
-rw-r--r--crypto/src/crypto/digests/RipeMD128Digest.cs26
-rw-r--r--crypto/src/crypto/digests/RipeMD160Digest.cs22
-rw-r--r--crypto/src/crypto/digests/RipeMD256Digest.cs21
-rw-r--r--crypto/src/crypto/digests/RipeMD320Digest.cs21
-rw-r--r--crypto/src/crypto/digests/SHA3Digest.cs560
-rw-r--r--crypto/src/crypto/digests/SM3Digest.cs328
-rw-r--r--crypto/src/crypto/digests/Sha1Digest.cs265
-rw-r--r--crypto/src/crypto/digests/Sha224Digest.cs21
-rw-r--r--crypto/src/crypto/digests/Sha256Digest.cs21
-rw-r--r--crypto/src/crypto/digests/Sha384Digest.cs14
-rw-r--r--crypto/src/crypto/digests/Sha512Digest.cs46
-rw-r--r--crypto/src/crypto/digests/Sha512tDigest.cs200
-rw-r--r--crypto/src/crypto/digests/ShortenedDigest.cs82
-rw-r--r--crypto/src/crypto/digests/SkeinDigest.cs117
-rw-r--r--crypto/src/crypto/digests/SkeinEngine.cs804
-rw-r--r--crypto/src/crypto/digests/TigerDigest.cs41
-rw-r--r--crypto/src/crypto/digests/WhirlpoolDigest.cs44
-rw-r--r--crypto/src/crypto/ec/CustomNamedCurves.cs366
-rw-r--r--crypto/src/crypto/encodings/ISO9796d1Encoding.cs273
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs674
-rw-r--r--crypto/src/crypto/encodings/Pkcs1Encoding.cs592
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs1041
-rw-r--r--crypto/src/crypto/engines/AesFastEngine.cs1221
-rw-r--r--crypto/src/crypto/engines/AesLightEngine.cs830
-rw-r--r--crypto/src/crypto/engines/AesWrapEngine.cs16
-rw-r--r--crypto/src/crypto/engines/BlowfishEngine.cs561
-rw-r--r--crypto/src/crypto/engines/CamelliaEngine.cs669
-rw-r--r--crypto/src/crypto/engines/CamelliaLightEngine.cs581
-rw-r--r--crypto/src/crypto/engines/CamelliaWrapEngine.cs16
-rw-r--r--crypto/src/crypto/engines/Cast5Engine.cs802
-rw-r--r--crypto/src/crypto/engines/Cast6Engine.cs279
-rw-r--r--crypto/src/crypto/engines/ChaChaEngine.cs189
-rw-r--r--crypto/src/crypto/engines/DesEdeEngine.cs88
-rw-r--r--crypto/src/crypto/engines/DesEdeWrapEngine.cs322
-rw-r--r--crypto/src/crypto/engines/DesEngine.cs475
-rw-r--r--crypto/src/crypto/engines/ElGamalEngine.cs178
-rw-r--r--crypto/src/crypto/engines/GOST28147Engine.cs7
-rw-r--r--crypto/src/crypto/engines/HC128Engine.cs235
-rw-r--r--crypto/src/crypto/engines/HC256Engine.cs224
-rw-r--r--crypto/src/crypto/engines/ISAACEngine.cs450
-rw-r--r--crypto/src/crypto/engines/IdeaEngine.cs46
-rw-r--r--crypto/src/crypto/engines/IesEngine.cs73
-rw-r--r--crypto/src/crypto/engines/NaccacheSternEngine.cs40
-rw-r--r--crypto/src/crypto/engines/NoekeonEngine.cs240
-rw-r--r--crypto/src/crypto/engines/NullEngine.cs70
-rw-r--r--crypto/src/crypto/engines/RC2Engine.cs312
-rw-r--r--crypto/src/crypto/engines/RC2WrapEngine.cs370
-rw-r--r--crypto/src/crypto/engines/RC4Engine.cs147
-rw-r--r--crypto/src/crypto/engines/RC532Engine.cs294
-rw-r--r--crypto/src/crypto/engines/RC564Engine.cs295
-rw-r--r--crypto/src/crypto/engines/RC6Engine.cs362
-rw-r--r--crypto/src/crypto/engines/RFC3211WrapEngine.cs168
-rw-r--r--crypto/src/crypto/engines/RFC3394WrapEngine.cs6
-rw-r--r--crypto/src/crypto/engines/RSABlindedEngine.cs124
-rw-r--r--crypto/src/crypto/engines/RSABlindingEngine.cs139
-rw-r--r--crypto/src/crypto/engines/RSACoreEngine.cs156
-rw-r--r--crypto/src/crypto/engines/RijndaelEngine.cs747
-rw-r--r--crypto/src/crypto/engines/RsaEngine.cs78
-rw-r--r--crypto/src/crypto/engines/SEEDEngine.cs361
-rw-r--r--crypto/src/crypto/engines/SEEDWrapEngine.cs16
-rw-r--r--crypto/src/crypto/engines/Salsa20Engine.cs277
-rw-r--r--crypto/src/crypto/engines/SerpentEngine.cs779
-rw-r--r--crypto/src/crypto/engines/SkipjackEngine.cs255
-rw-r--r--crypto/src/crypto/engines/TEAEngine.cs168
-rw-r--r--crypto/src/crypto/engines/ThreefishEngine.cs1490
-rw-r--r--crypto/src/crypto/engines/TwofishEngine.cs675
-rw-r--r--crypto/src/crypto/engines/VMPCEngine.cs265
-rw-r--r--crypto/src/crypto/engines/VMPCKSA3Engine.cs51
-rw-r--r--crypto/src/crypto/engines/XSalsa20Engine.cs71
-rw-r--r--crypto/src/crypto/engines/XTEAEngine.cs168
-rw-r--r--crypto/src/crypto/generators/BaseKdfBytesGenerator.cs257
-rw-r--r--crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs38
-rw-r--r--crypto/src/crypto/generators/DHKeyGeneratorHelper.cs105
-rw-r--r--crypto/src/crypto/generators/DHKeyPairGenerator.cs38
-rw-r--r--crypto/src/crypto/generators/DHParametersGenerator.cs45
-rw-r--r--crypto/src/crypto/generators/DHParametersHelper.cs354
-rw-r--r--crypto/src/crypto/generators/DesEdeKeyGenerator.cs67
-rw-r--r--crypto/src/crypto/generators/DesKeyGenerator.cs57
-rw-r--r--crypto/src/crypto/generators/DsaKeyPairGenerator.cs79
-rw-r--r--crypto/src/crypto/generators/DsaParametersGenerator.cs547
-rw-r--r--crypto/src/crypto/generators/ECKeyPairGenerator.cs269
-rw-r--r--crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs40
-rw-r--r--crypto/src/crypto/generators/ElGamalParametersGenerator.cs46
-rw-r--r--crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs123
-rw-r--r--crypto/src/crypto/generators/GOST3410ParametersGenerator.cs530
-rw-r--r--crypto/src/crypto/generators/Kdf1BytesGenerator.cs3
-rw-r--r--crypto/src/crypto/generators/Kdf2BytesGenerator.cs3
-rw-r--r--crypto/src/crypto/generators/Mgf1BytesGenerator.cs117
-rw-r--r--crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs56
-rw-r--r--crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs167
-rw-r--r--crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs470
-rw-r--r--crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs162
-rw-r--r--crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs326
-rw-r--r--crypto/src/crypto/generators/Poly1305KeyGenerator.cs123
-rw-r--r--crypto/src/crypto/generators/RSABlindingFactorGenerator.cs69
-rw-r--r--crypto/src/crypto/generators/RsaKeyPairGenerator.cs151
-rw-r--r--crypto/src/crypto/generators/SCrypt.cs140
-rw-r--r--crypto/src/crypto/io/CipherStream.cs19
-rw-r--r--crypto/src/crypto/io/DigestStream.cs11
-rw-r--r--crypto/src/crypto/io/MacStream.cs11
-rw-r--r--crypto/src/crypto/io/SignerStream.cs11
-rw-r--r--crypto/src/crypto/macs/CMac.cs481
-rw-r--r--crypto/src/crypto/macs/CbcBlockCipherMac.cs209
-rw-r--r--crypto/src/crypto/macs/CfbBlockCipherMac.cs368
-rw-r--r--crypto/src/crypto/macs/GMac.cs112
-rw-r--r--crypto/src/crypto/macs/GOST28147Mac.cs296
-rw-r--r--crypto/src/crypto/macs/HMac.cs94
-rw-r--r--crypto/src/crypto/macs/ISO9797Alg3Mac.cs275
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs291
-rw-r--r--crypto/src/crypto/macs/SipHash.cs199
-rw-r--r--crypto/src/crypto/macs/SkeinMac.cs117
-rw-r--r--crypto/src/crypto/macs/VMPCMac.cs173
-rw-r--r--crypto/src/crypto/modes/CbcBlockCipher.cs12
-rw-r--r--crypto/src/crypto/modes/CcmBlockCipher.cs326
-rw-r--r--crypto/src/crypto/modes/CfbBlockCipher.cs8
-rw-r--r--crypto/src/crypto/modes/CtsBlockCipher.cs253
-rw-r--r--crypto/src/crypto/modes/EAXBlockCipher.cs174
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs896
-rw-r--r--crypto/src/crypto/modes/GOFBBlockCipher.cs6
-rw-r--r--crypto/src/crypto/modes/IAeadBlockCipher.cs17
-rw-r--r--crypto/src/crypto/modes/OCBBlockCipher.cs558
-rw-r--r--crypto/src/crypto/modes/OfbBlockCipher.cs8
-rw-r--r--crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs337
-rw-r--r--crypto/src/crypto/modes/SicBlockCipher.cs185
-rw-r--r--crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs40
-rw-r--r--crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs6
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs360
-rw-r--r--crypto/src/crypto/modes/gcm/IGcmExponentiator.cs10
-rw-r--r--crypto/src/crypto/modes/gcm/IGcmMultiplier.cs10
-rw-r--r--crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs62
-rw-r--r--crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs117
-rw-r--r--crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs163
-rw-r--r--crypto/src/crypto/paddings/BlockCipherPadding.cs43
-rw-r--r--crypto/src/crypto/paddings/ISO10126d2Padding.cs76
-rw-r--r--crypto/src/crypto/paddings/ISO7816d4Padding.cs79
-rw-r--r--crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs288
-rw-r--r--crypto/src/crypto/paddings/Pkcs7Padding.cs79
-rw-r--r--crypto/src/crypto/paddings/TbcPadding.cs79
-rw-r--r--crypto/src/crypto/paddings/X923Padding.cs82
-rw-r--r--crypto/src/crypto/paddings/ZeroBytePadding.cs68
-rw-r--r--crypto/src/crypto/parameters/AEADParameters.cs14
-rw-r--r--crypto/src/crypto/parameters/CcmParameters.cs1
-rw-r--r--crypto/src/crypto/parameters/DHKeyGenerationParameters.cs31
-rw-r--r--crypto/src/crypto/parameters/DHKeyParameters.cs76
-rw-r--r--crypto/src/crypto/parameters/DHParameters.cs184
-rw-r--r--crypto/src/crypto/parameters/DHPrivateKeyParameters.cs60
-rw-r--r--crypto/src/crypto/parameters/DHPublicKeyParameters.cs66
-rw-r--r--crypto/src/crypto/parameters/DHValidationParameters.cs59
-rw-r--r--crypto/src/crypto/parameters/DSAParameterGenerationParameters.cs74
-rw-r--r--crypto/src/crypto/parameters/DesEdeParameters.cs95
-rw-r--r--crypto/src/crypto/parameters/DesParameters.cs130
-rw-r--r--crypto/src/crypto/parameters/DsaKeyGenerationParameters.cs26
-rw-r--r--crypto/src/crypto/parameters/DsaKeyParameters.cs59
-rw-r--r--crypto/src/crypto/parameters/DsaParameters.cs85
-rw-r--r--crypto/src/crypto/parameters/DsaPrivateKeyParameters.cs53
-rw-r--r--crypto/src/crypto/parameters/DsaPublicKeyParameters.cs52
-rw-r--r--crypto/src/crypto/parameters/DsaValidationParameters.cs69
-rw-r--r--crypto/src/crypto/parameters/ECDomainParameters.cs82
-rw-r--r--crypto/src/crypto/parameters/ECKeyGenerationParameters.cs41
-rw-r--r--crypto/src/crypto/parameters/ECKeyParameters.cs235
-rw-r--r--crypto/src/crypto/parameters/ECPrivateKeyParameters.cs132
-rw-r--r--crypto/src/crypto/parameters/ECPublicKeyParameters.cs106
-rw-r--r--crypto/src/crypto/parameters/ElGamalKeyGenerationParameters.cs31
-rw-r--r--crypto/src/crypto/parameters/ElGamalKeyParameters.cs59
-rw-r--r--crypto/src/crypto/parameters/ElGamalParameters.cs81
-rw-r--r--crypto/src/crypto/parameters/ElGamalPrivateKeyParameters.cs53
-rw-r--r--crypto/src/crypto/parameters/ElGamalPublicKeyParameters.cs53
-rw-r--r--crypto/src/crypto/parameters/GOST3410KeyGenerationParameters.cs55
-rw-r--r--crypto/src/crypto/parameters/GOST3410KeyParameters.cs58
-rw-r--r--crypto/src/crypto/parameters/GOST3410Parameters.cs86
-rw-r--r--crypto/src/crypto/parameters/GOST3410PrivateKeyParameters.cs41
-rw-r--r--crypto/src/crypto/parameters/GOST3410PublicKeyParameters.cs40
-rw-r--r--crypto/src/crypto/parameters/GOST3410ValidationParameters.cs51
-rw-r--r--crypto/src/crypto/parameters/ISO18033KDFParameters.cs25
-rw-r--r--crypto/src/crypto/parameters/IesParameters.cs49
-rw-r--r--crypto/src/crypto/parameters/IesWithCipherParameters.cs33
-rw-r--r--crypto/src/crypto/parameters/KdfParameters.cs33
-rw-r--r--crypto/src/crypto/parameters/KeyParameter.cs43
-rw-r--r--crypto/src/crypto/parameters/MgfParameters.cs31
-rw-r--r--crypto/src/crypto/parameters/MqvPrivateParameters.cs44
-rw-r--r--crypto/src/crypto/parameters/MqvPublicParameters.cs29
-rw-r--r--crypto/src/crypto/parameters/NaccacheSternKeyGenerationParameters.cs101
-rw-r--r--crypto/src/crypto/parameters/NaccacheSternKeyParameters.cs44
-rw-r--r--crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs4
-rw-r--r--crypto/src/crypto/parameters/ParametersWithIV.cs3
-rw-r--r--crypto/src/crypto/parameters/ParametersWithRandom.cs48
-rw-r--r--crypto/src/crypto/parameters/ParametersWithSBox.cs24
-rw-r--r--crypto/src/crypto/parameters/ParametersWithSalt.cs39
-rw-r--r--crypto/src/crypto/parameters/RC2Parameters.cs47
-rw-r--r--crypto/src/crypto/parameters/RC5Parameters.cs27
-rw-r--r--crypto/src/crypto/parameters/RSABlindingParameters.cs34
-rw-r--r--crypto/src/crypto/parameters/RsaKeyGenerationParameters.cs55
-rw-r--r--crypto/src/crypto/parameters/RsaKeyParameters.cs63
-rw-r--r--crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs104
-rw-r--r--crypto/src/crypto/parameters/SkeinParameters.cs285
-rw-r--r--crypto/src/crypto/parameters/TweakableBlockCipherParameters.cs40
-rw-r--r--crypto/src/crypto/prng/CryptoApiRandomGenerator.cs2
-rw-r--r--crypto/src/crypto/prng/DigestRandomGenerator.cs129
-rw-r--r--crypto/src/crypto/prng/IRandomGenerator.cs26
-rw-r--r--crypto/src/crypto/prng/ReversedWindowGenerator.cs98
-rw-r--r--crypto/src/crypto/prng/ThreadedSeedGenerator.cs26
-rw-r--r--crypto/src/crypto/prng/VMPCRandomGenerator.cs209
-rw-r--r--crypto/src/crypto/signers/DsaDigestSigner.cs145
-rw-r--r--crypto/src/crypto/signers/DsaSigner.cs278
-rw-r--r--crypto/src/crypto/signers/ECDsaSigner.cs325
-rw-r--r--crypto/src/crypto/signers/ECGOST3410Signer.cs294
-rw-r--r--crypto/src/crypto/signers/ECNRSigner.cs350
-rw-r--r--crypto/src/crypto/signers/GOST3410DigestSigner.cs145
-rw-r--r--crypto/src/crypto/signers/GOST3410Signer.cs132
-rw-r--r--crypto/src/crypto/signers/GenericSigner.cs129
-rw-r--r--crypto/src/crypto/signers/HMacDsaKCalculator.cs150
-rw-r--r--crypto/src/crypto/signers/IDsaKCalculator.cs44
-rw-r--r--crypto/src/crypto/signers/Iso9796d2PssSigner.cs1173
-rw-r--r--crypto/src/crypto/signers/Iso9796d2Signer.cs1098
-rw-r--r--crypto/src/crypto/signers/PssSigner.cs345
-rw-r--r--crypto/src/crypto/signers/RandomDsaKCalculator.cs44
-rw-r--r--crypto/src/crypto/signers/RsaDigestSigner.cs192
-rw-r--r--crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs12
-rw-r--r--crypto/src/crypto/tls/AbstractTlsCipherFactory.cs15
-rw-r--r--crypto/src/crypto/tls/AbstractTlsClient.cs232
-rw-r--r--crypto/src/crypto/tls/AbstractTlsContext.cs132
-rw-r--r--crypto/src/crypto/tls/AbstractTlsCredentials.cs10
-rw-r--r--crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs12
-rw-r--r--crypto/src/crypto/tls/AbstractTlsKeyExchange.cs166
-rw-r--r--crypto/src/crypto/tls/AbstractTlsPeer.cs48
-rw-r--r--crypto/src/crypto/tls/AbstractTlsServer.cs318
-rw-r--r--crypto/src/crypto/tls/AbstractTlsSigner.cs50
-rw-r--r--crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs20
-rw-r--r--crypto/src/crypto/tls/AlertDescription.cs258
-rw-r--r--crypto/src/crypto/tls/AlertLevel.cs16
-rw-r--r--crypto/src/crypto/tls/BulkCipherAlgorithm.cs25
-rw-r--r--crypto/src/crypto/tls/ByteQueue.cs242
-rw-r--r--crypto/src/crypto/tls/CertChainType.cs18
-rw-r--r--crypto/src/crypto/tls/Certificate.cs221
-rw-r--r--crypto/src/crypto/tls/CertificateRequest.cs174
-rw-r--r--crypto/src/crypto/tls/CertificateStatus.cs102
-rw-r--r--crypto/src/crypto/tls/CertificateStatusRequest.cs95
-rw-r--r--crypto/src/crypto/tls/CertificateStatusType.cs12
-rw-r--r--crypto/src/crypto/tls/CertificateUrl.cs124
-rw-r--r--crypto/src/crypto/tls/Chacha20Poly1305.cs153
-rw-r--r--crypto/src/crypto/tls/ChangeCipherSpec.cs9
-rw-r--r--crypto/src/crypto/tls/CipherSuite.cs482
-rw-r--r--crypto/src/crypto/tls/CipherType.cs20
-rw-r--r--crypto/src/crypto/tls/ClientAuthenticationType.cs14
-rw-r--r--crypto/src/crypto/tls/ClientCertificateType.cs37
-rw-r--r--crypto/src/crypto/tls/CombinedHash.cs203
-rw-r--r--crypto/src/crypto/tls/CompressionMethod.cs32
-rw-r--r--crypto/src/crypto/tls/ConnectionEnd.cs15
-rw-r--r--crypto/src/crypto/tls/ContentType.cs21
-rw-r--r--crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs104
-rw-r--r--crypto/src/crypto/tls/DefaultTlsCipherFactory.cs280
-rw-r--r--crypto/src/crypto/tls/DefaultTlsClient.cs656
-rw-r--r--crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs51
-rw-r--r--crypto/src/crypto/tls/DefaultTlsServer.cs548
-rw-r--r--crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs142
-rw-r--r--crypto/src/crypto/tls/DeferredHash.cs201
-rw-r--r--crypto/src/crypto/tls/DigestInputBuffer.cs39
-rw-r--r--crypto/src/crypto/tls/DigitallySigned.cs70
-rw-r--r--crypto/src/crypto/tls/ECBasisType.cs16
-rw-r--r--crypto/src/crypto/tls/ECCurveType.cs46
-rw-r--r--crypto/src/crypto/tls/ECPointFormat.cs24
-rw-r--r--crypto/src/crypto/tls/EncryptionAlgorithm.cs91
-rw-r--r--crypto/src/crypto/tls/ExporterLabel.cs32
-rw-r--r--crypto/src/crypto/tls/ExtensionType.cs86
-rw-r--r--crypto/src/crypto/tls/HandshakeType.cs53
-rw-r--r--crypto/src/crypto/tls/HashAlgorithm.cs16
-rw-r--r--crypto/src/crypto/tls/HeartbeatExtension.cs52
-rw-r--r--crypto/src/crypto/tls/HeartbeatMessage.cs102
-rw-r--r--crypto/src/crypto/tls/HeartbeatMessageType.cs18
-rw-r--r--crypto/src/crypto/tls/HeartbeatMode.cs18
-rw-r--r--crypto/src/crypto/tls/KeyExchangeAlgorithm.cs80
-rw-r--r--crypto/src/crypto/tls/MacAlgorithm.cs25
-rw-r--r--crypto/src/crypto/tls/MaxFragmentLength.cs20
-rw-r--r--crypto/src/crypto/tls/NameType.cs12
-rw-r--r--crypto/src/crypto/tls/NamedCurve.cs123
-rw-r--r--crypto/src/crypto/tls/NewSessionTicket.cs53
-rw-r--r--crypto/src/crypto/tls/OcspStatusRequest.cs130
-rw-r--r--crypto/src/crypto/tls/PrfAlgorithm.cs24
-rw-r--r--crypto/src/crypto/tls/ProtocolVersion.cs159
-rw-r--r--crypto/src/crypto/tls/PskTlsClient.cs431
-rw-r--r--crypto/src/crypto/tls/RecordStream.cs487
-rw-r--r--crypto/src/crypto/tls/SecurityParameters.cs110
-rw-r--r--crypto/src/crypto/tls/ServerDHParams.cs60
-rw-r--r--crypto/src/crypto/tls/ServerName.cs105
-rw-r--r--crypto/src/crypto/tls/ServerNameList.cs81
-rw-r--r--crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs15
-rw-r--r--crypto/src/crypto/tls/SessionParameters.cs137
-rw-r--r--crypto/src/crypto/tls/SignatureAlgorithm.cs15
-rw-r--r--crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs94
-rw-r--r--crypto/src/crypto/tls/SignerInputBuffer.cs39
-rw-r--r--crypto/src/crypto/tls/SrpTlsClient.cs289
-rw-r--r--crypto/src/crypto/tls/SrtpProtectionProfile.cs15
-rw-r--r--crypto/src/crypto/tls/Ssl3Mac.cs206
-rw-r--r--crypto/src/crypto/tls/SupplementalDataEntry.cs26
-rw-r--r--crypto/src/crypto/tls/SupplementalDataType.cs13
-rw-r--r--crypto/src/crypto/tls/TlsAeadCipher.cs189
-rw-r--r--crypto/src/crypto/tls/TlsAgreementCredentials.cs11
-rw-r--r--crypto/src/crypto/tls/TlsAuthentication.cs31
-rw-r--r--crypto/src/crypto/tls/TlsBlockCipher.cs606
-rw-r--r--crypto/src/crypto/tls/TlsCipher.cs16
-rw-r--r--crypto/src/crypto/tls/TlsCipherFactory.cs11
-rw-r--r--crypto/src/crypto/tls/TlsClient.cs215
-rw-r--r--crypto/src/crypto/tls/TlsClientContext.cs12
-rw-r--r--crypto/src/crypto/tls/TlsClientContextImpl.cs41
-rw-r--r--crypto/src/crypto/tls/TlsClientProtocol.cs861
-rw-r--r--crypto/src/crypto/tls/TlsCompression.cs12
-rw-r--r--crypto/src/crypto/tls/TlsContext.cs45
-rw-r--r--crypto/src/crypto/tls/TlsCredentials.cs9
-rw-r--r--crypto/src/crypto/tls/TlsDHKeyExchange.cs374
-rw-r--r--crypto/src/crypto/tls/TlsDHUtilities.cs147
-rw-r--r--crypto/src/crypto/tls/TlsDeflateCompression.cs97
-rw-r--r--crypto/src/crypto/tls/TlsDheKeyExchange.cs143
-rw-r--r--crypto/src/crypto/tls/TlsDsaSigner.cs114
-rw-r--r--crypto/src/crypto/tls/TlsDssSigner.cs29
-rw-r--r--crypto/src/crypto/tls/TlsECDHKeyExchange.cs351
-rw-r--r--crypto/src/crypto/tls/TlsECDheKeyExchange.cs234
-rw-r--r--crypto/src/crypto/tls/TlsECDsaSigner.cs29
-rw-r--r--crypto/src/crypto/tls/TlsEccUtilities.cs647
-rw-r--r--crypto/src/crypto/tls/TlsEncryptionCredentials.cs12
-rw-r--r--crypto/src/crypto/tls/TlsExtensionsUtilities.cs243
-rw-r--r--crypto/src/crypto/tls/TlsFatalAlert.cs32
-rw-r--r--crypto/src/crypto/tls/TlsHandshakeHash.cs22
-rw-r--r--crypto/src/crypto/tls/TlsKeyExchange.cs80
-rw-r--r--crypto/src/crypto/tls/TlsMac.cs255
-rw-r--r--crypto/src/crypto/tls/TlsNullCipher.cs136
-rw-r--r--crypto/src/crypto/tls/TlsNullCompression.cs19
-rw-r--r--crypto/src/crypto/tls/TlsPeer.cs62
-rw-r--r--crypto/src/crypto/tls/TlsProtocol.cs1102
-rw-r--r--crypto/src/crypto/tls/TlsProtocolHandler.cs1240
-rw-r--r--crypto/src/crypto/tls/TlsPskIdentity.cs15
-rw-r--r--crypto/src/crypto/tls/TlsPskKeyExchange.cs387
-rw-r--r--crypto/src/crypto/tls/TlsRsaKeyExchange.cs265
-rw-r--r--crypto/src/crypto/tls/TlsRsaSigner.cs131
-rw-r--r--crypto/src/crypto/tls/TlsRsaUtilities.cs152
-rw-r--r--crypto/src/crypto/tls/TlsServer.cs90
-rw-r--r--crypto/src/crypto/tls/TlsServerContext.cs11
-rw-r--r--crypto/src/crypto/tls/TlsServerContextImpl.cs20
-rw-r--r--crypto/src/crypto/tls/TlsServerProtocol.cs744
-rw-r--r--crypto/src/crypto/tls/TlsSession.cs15
-rw-r--r--crypto/src/crypto/tls/TlsSessionImpl.cs54
-rw-r--r--crypto/src/crypto/tls/TlsSigner.cs33
-rw-r--r--crypto/src/crypto/tls/TlsSignerCredentials.cs13
-rw-r--r--crypto/src/crypto/tls/TlsSrpKeyExchange.cs366
-rw-r--r--crypto/src/crypto/tls/TlsSrpUtilities.cs41
-rw-r--r--crypto/src/crypto/tls/TlsSrtpUtilities.cs62
-rw-r--r--crypto/src/crypto/tls/TlsStream.cs118
-rw-r--r--crypto/src/crypto/tls/TlsStreamCipher.cs164
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs1885
-rw-r--r--crypto/src/crypto/tls/UrlAndHash.cs94
-rw-r--r--crypto/src/crypto/tls/UseSrtpData.cs56
-rw-r--r--crypto/src/crypto/tls/UserMappingType.cs13
-rw-r--r--crypto/src/crypto/util/Pack.cs475
-rw-r--r--crypto/src/math/BigInteger.cs6316
-rw-r--r--crypto/src/math/ec/ECAlgorithms.cs540
-rw-r--r--crypto/src/math/ec/ECCurve.cs1482
-rw-r--r--crypto/src/math/ec/ECFieldElement.cs2154
-rw-r--r--crypto/src/math/ec/ECPoint.cs2634
-rw-r--r--crypto/src/math/ec/ECPointMap.cs9
-rw-r--r--crypto/src/math/ec/LongArray.cs2201
-rw-r--r--crypto/src/math/ec/Mod.cs184
-rw-r--r--crypto/src/math/ec/Nat.cs1013
-rw-r--r--crypto/src/math/ec/ScaleXPointMap.cs20
-rw-r--r--crypto/src/math/ec/ScaleYPointMap.cs20
-rw-r--r--crypto/src/math/ec/abc/SimpleBigDecimal.cs241
-rw-r--r--crypto/src/math/ec/abc/Tnaf.cs1652
-rw-r--r--crypto/src/math/ec/abc/ZTauElement.cs36
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519.cs77
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519Field.cs253
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs233
-rw-r--r--crypto/src/math/ec/custom/djb/Curve25519Point.cs313
-rw-r--r--crypto/src/math/ec/custom/sec/Nat192.cs962
-rw-r--r--crypto/src/math/ec/custom/sec/Nat224.cs1176
-rw-r--r--crypto/src/math/ec/custom/sec/Nat256.cs1300
-rw-r--r--crypto/src/math/ec/custom/sec/Nat384.cs46
-rw-r--r--crypto/src/math/ec/custom/sec/Nat512.cs46
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1Curve.cs75
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1Field.cs176
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs212
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1Point.cs265
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1Curve.cs78
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1Field.cs281
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs187
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1Point.cs277
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1Curve.cs75
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1Field.cs177
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs241
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1Point.cs265
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1Curve.cs78
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1Field.cs295
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs268
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1Point.cs277
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1Curve.cs75
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1Field.cs178
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs213
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1Point.cs265
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1Curve.cs77
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1Field.cs309
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs187
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1Point.cs277
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1Curve.cs77
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1Field.cs292
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs209
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1Point.cs278
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1Curve.cs77
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1Field.cs153
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs166
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1Point.cs273
-rw-r--r--crypto/src/math/ec/endo/ECEndomorphism.cs11
-rw-r--r--crypto/src/math/ec/endo/GlvEndomorphism.cs10
-rw-r--r--crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs55
-rw-r--r--crypto/src/math/ec/endo/GlvTypeBParameters.cs60
-rw-r--r--crypto/src/math/ec/multiplier/AbstractECMultiplier.cs24
-rw-r--r--crypto/src/math/ec/multiplier/DoubleAddMultiplier.cs24
-rw-r--r--crypto/src/math/ec/multiplier/ECMultiplier.cs30
-rw-r--r--crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs59
-rw-r--r--crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs34
-rw-r--r--crypto/src/math/ec/multiplier/FixedPointUtilities.cs72
-rw-r--r--crypto/src/math/ec/multiplier/GlvMultiplier.cs40
-rw-r--r--crypto/src/math/ec/multiplier/MixedNafR2LMultiplier.cs75
-rw-r--r--crypto/src/math/ec/multiplier/MontgomeryLadderMultiplier.cs25
-rw-r--r--crypto/src/math/ec/multiplier/NafL2RMultiplier.cs30
-rw-r--r--crypto/src/math/ec/multiplier/NafR2LMultiplier.cs31
-rw-r--r--crypto/src/math/ec/multiplier/PreCompInfo.cs2
-rw-r--r--crypto/src/math/ec/multiplier/ReferenceMultiplier.cs35
-rw-r--r--crypto/src/math/ec/multiplier/WNafL2RMultiplier.cs98
-rw-r--r--crypto/src/math/ec/multiplier/WNafPreCompInfo.cs76
-rw-r--r--crypto/src/math/ec/multiplier/WNafUtilities.cs469
-rw-r--r--crypto/src/math/ec/multiplier/WTauNafMultiplier.cs200
-rw-r--r--crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs57
-rw-r--r--crypto/src/math/ec/multiplier/ZSignedDigitL2RMultiplier.cs29
-rw-r--r--crypto/src/math/ec/multiplier/ZSignedDigitR2LMultiplier.cs30
-rw-r--r--crypto/src/math/field/FiniteFields.cs54
-rw-r--r--crypto/src/math/field/GF2Polynomial.cs46
-rw-r--r--crypto/src/math/field/GenericPolynomialExtensionField.cs63
-rw-r--r--crypto/src/math/field/IExtensionField.cs12
-rw-r--r--crypto/src/math/field/IFiniteField.cs11
-rw-r--r--crypto/src/math/field/IPolynomial.cs15
-rw-r--r--crypto/src/math/field/IPolynomialExtensionField.cs10
-rw-r--r--crypto/src/math/field/PrimeField.cs44
-rw-r--r--crypto/src/ocsp/BasicOCSPResp.cs220
-rw-r--r--crypto/src/ocsp/BasicOCSPRespGenerator.cs318
-rw-r--r--crypto/src/ocsp/CertificateID.cs141
-rw-r--r--crypto/src/ocsp/CertificateStatus.cs9
-rw-r--r--crypto/src/ocsp/OCSPException.cs5
-rw-r--r--crypto/src/ocsp/OCSPReq.cs268
-rw-r--r--crypto/src/ocsp/OCSPReqGenerator.cs243
-rw-r--r--crypto/src/ocsp/OCSPResp.cs100
-rw-r--r--crypto/src/ocsp/OCSPRespGenerator.cs54
-rw-r--r--crypto/src/ocsp/OCSPRespStatus.cs22
-rw-r--r--crypto/src/ocsp/OCSPUtil.cs5
-rw-r--r--crypto/src/ocsp/Req.cs38
-rw-r--r--crypto/src/ocsp/RespData.cs60
-rw-r--r--crypto/src/ocsp/RespID.cs72
-rw-r--r--crypto/src/ocsp/RevokedStatus.cs58
-rw-r--r--crypto/src/ocsp/SingleResp.cs81
-rw-r--r--crypto/src/ocsp/UnknownStatus.cs15
-rw-r--r--crypto/src/openpgp/IStreamGenerator.cs7
-rw-r--r--crypto/src/openpgp/PGPKeyRing.cs79
-rw-r--r--crypto/src/openpgp/PGPObject.cs9
-rw-r--r--crypto/src/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs33
-rw-r--r--crypto/src/openpgp/PgpCompressedData.cs50
-rw-r--r--crypto/src/openpgp/PgpCompressedDataGenerator.cs26
-rw-r--r--crypto/src/openpgp/PgpDataValidationException.cs3
-rw-r--r--crypto/src/openpgp/PgpEncryptedData.cs151
-rw-r--r--crypto/src/openpgp/PgpEncryptedDataGenerator.cs506
-rw-r--r--crypto/src/openpgp/PgpEncryptedDataList.cs72
-rw-r--r--crypto/src/openpgp/PgpException.cs5
-rw-r--r--crypto/src/openpgp/PgpExperimental.cs16
-rw-r--r--crypto/src/openpgp/PgpKeyFlags.cs13
-rw-r--r--crypto/src/openpgp/PgpKeyPair.cs67
-rw-r--r--crypto/src/openpgp/PgpKeyRingGenerator.cs167
-rw-r--r--crypto/src/openpgp/PgpKeyValidationException.cs5
-rw-r--r--crypto/src/openpgp/PgpLiteralData.cs63
-rw-r--r--crypto/src/openpgp/PgpLiteralDataGenerator.cs20
-rw-r--r--crypto/src/openpgp/PgpMarker.cs18
-rw-r--r--crypto/src/openpgp/PgpObjectFactory.cs143
-rw-r--r--crypto/src/openpgp/PgpOnePassSignature.cs179
-rw-r--r--crypto/src/openpgp/PgpOnePassSignatureList.cs51
-rw-r--r--crypto/src/openpgp/PgpPbeEncryptedData.cs135
-rw-r--r--crypto/src/openpgp/PgpPrivateKey.cs42
-rw-r--r--crypto/src/openpgp/PgpPublicKey.cs890
-rw-r--r--crypto/src/openpgp/PgpPublicKeyEncryptedData.cs252
-rw-r--r--crypto/src/openpgp/PgpPublicKeyRing.cs176
-rw-r--r--crypto/src/openpgp/PgpPublicKeyRingBundle.cs7
-rw-r--r--crypto/src/openpgp/PgpSecretKey.cs792
-rw-r--r--crypto/src/openpgp/PgpSecretKeyRing.cs377
-rw-r--r--crypto/src/openpgp/PgpSecretKeyRingBundle.cs8
-rw-r--r--crypto/src/openpgp/PgpSignature.cs2
-rw-r--r--crypto/src/openpgp/PgpSignatureGenerator.cs4
-rw-r--r--crypto/src/openpgp/PgpSignatureList.cs51
-rw-r--r--crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs193
-rw-r--r--crypto/src/openpgp/PgpSignatureSubpacketVector.cs229
-rw-r--r--crypto/src/openpgp/PgpUserAttributeSubpacketVector.cs81
-rw-r--r--crypto/src/openpgp/PgpUtilities.cs15
-rw-r--r--crypto/src/openpgp/PgpV3SignatureGenerator.cs199
-rw-r--r--crypto/src/openpgp/WrappedGeneratorStream.cs35
-rw-r--r--crypto/src/openssl/EncryptionException.cs5
-rw-r--r--crypto/src/openssl/IPasswordFinder.cs9
-rw-r--r--crypto/src/openssl/MiscPemGenerator.cs475
-rw-r--r--crypto/src/openssl/PEMException.cs5
-rw-r--r--crypto/src/openssl/PEMReader.cs699
-rw-r--r--crypto/src/openssl/PEMUtilities.cs158
-rw-r--r--crypto/src/openssl/PEMWriter.cs61
-rw-r--r--crypto/src/openssl/PasswordException.cs5
-rw-r--r--crypto/src/openssl/Pkcs8Generator.cs111
-rw-r--r--crypto/src/pkcs/AsymmetricKeyEntry.cs2
-rw-r--r--crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs63
-rw-r--r--crypto/src/pkcs/PKCS12StoreBuilder.cs41
-rw-r--r--crypto/src/pkcs/Pkcs10CertificationRequest.cs3
-rw-r--r--crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs2
-rw-r--r--crypto/src/pkcs/Pkcs12Entry.cs64
-rw-r--r--crypto/src/pkcs/Pkcs12Store.cs2378
-rw-r--r--crypto/src/pkcs/Pkcs12Utilities.cs77
-rw-r--r--crypto/src/pkcs/PrivateKeyInfoFactory.cs386
-rw-r--r--crypto/src/pkcs/X509CertificateEntry.cs2
-rw-r--r--crypto/src/pkix/CertStatus.cs35
-rw-r--r--crypto/src/pkix/PkixAttrCertChecker.cs57
-rw-r--r--crypto/src/pkix/PkixAttrCertPathBuilder.cs215
-rw-r--r--crypto/src/pkix/PkixAttrCertPathValidator.cs76
-rw-r--r--crypto/src/pkix/PkixBuilderParameters.cs140
-rw-r--r--crypto/src/pkix/PkixCertPath.cs2
-rw-r--r--crypto/src/pkix/PkixCertPathBuilder.cs205
-rw-r--r--crypto/src/pkix/PkixCertPathBuilderException.cs5
-rw-r--r--crypto/src/pkix/PkixCertPathBuilderResult.cs45
-rw-r--r--crypto/src/pkix/PkixCertPathChecker.cs101
-rw-r--r--crypto/src/pkix/PkixCertPathValidator.cs420
-rw-r--r--crypto/src/pkix/PkixCertPathValidatorException.cs7
-rw-r--r--crypto/src/pkix/PkixCertPathValidatorResult.cs69
-rw-r--r--crypto/src/pkix/PkixCertPathValidatorUtilities.cs10
-rw-r--r--crypto/src/pkix/PkixCrlUtilities.cs114
-rw-r--r--crypto/src/pkix/PkixNameConstraintValidator.cs1937
-rw-r--r--crypto/src/pkix/PkixNameConstraintValidatorException.cs6
-rw-r--r--crypto/src/pkix/PkixParameters.cs893
-rw-r--r--crypto/src/pkix/PkixPolicyNode.cs158
-rw-r--r--crypto/src/pkix/ReasonsMask.cs96
-rw-r--r--crypto/src/pkix/Rfc3280CertPathUtilities.cs8
-rw-r--r--crypto/src/pkix/Rfc3281CertPathUtilities.cs8
-rw-r--r--crypto/src/pkix/TrustAnchor.cs259
-rw-r--r--crypto/src/security/AgreementUtilities.cs5
-rw-r--r--crypto/src/security/CipherUtilities.cs1357
-rw-r--r--crypto/src/security/DigestUtilities.cs193
-rw-r--r--crypto/src/security/DotNetUtilities.cs49
-rw-r--r--crypto/src/security/GeneralSecurityException.cs5
-rw-r--r--crypto/src/security/GeneratorUtilities.cs646
-rw-r--r--crypto/src/security/InvalidKeyException.cs5
-rw-r--r--crypto/src/security/InvalidParameterException.cs5
-rw-r--r--crypto/src/security/KeyException.cs5
-rw-r--r--crypto/src/security/MacUtilities.cs407
-rw-r--r--crypto/src/security/NoSuchAlgorithmException.cs5
-rw-r--r--crypto/src/security/ParameterUtilities.cs612
-rw-r--r--crypto/src/security/PbeUtilities.cs1255
-rw-r--r--crypto/src/security/PrivateKeyFactory.cs327
-rw-r--r--crypto/src/security/PublicKeyFactory.cs398
-rw-r--r--crypto/src/security/SecureRandom.cs6
-rw-r--r--crypto/src/security/SecurityUtilityException.cs3
-rw-r--r--crypto/src/security/SignatureException.cs5
-rw-r--r--crypto/src/security/SignerUtilities.cs728
-rw-r--r--crypto/src/security/WrapperUtilities.cs272
-rw-r--r--crypto/src/security/cert/CertificateEncodingException.cs5
-rw-r--r--crypto/src/security/cert/CertificateException.cs5
-rw-r--r--crypto/src/security/cert/CertificateExpiredException.cs5
-rw-r--r--crypto/src/security/cert/CertificateNotYetValidException.cs5
-rw-r--r--crypto/src/security/cert/CertificateParsingException.cs5
-rw-r--r--crypto/src/security/cert/CrlException.cs5
-rw-r--r--crypto/src/tsp/GenTimeAccuracy.cs33
-rw-r--r--crypto/src/tsp/TSPAlgorithms.cs48
-rw-r--r--crypto/src/tsp/TSPException.cs5
-rw-r--r--crypto/src/tsp/TSPUtil.cs202
-rw-r--r--crypto/src/tsp/TSPValidationException.cs7
-rw-r--r--crypto/src/tsp/TimeStampRequest.cs196
-rw-r--r--crypto/src/tsp/TimeStampRequestGenerator.cs139
-rw-r--r--crypto/src/tsp/TimeStampResponse.cs184
-rw-r--r--crypto/src/tsp/TimeStampResponseGenerator.cs210
-rw-r--r--crypto/src/tsp/TimeStampToken.cs305
-rw-r--r--crypto/src/tsp/TimeStampTokenGenerator.cs245
-rw-r--r--crypto/src/tsp/TimeStampTokenInfo.cs107
-rw-r--r--crypto/src/util/Arrays.cs700
-rw-r--r--crypto/src/util/BigIntegers.cs132
-rw-r--r--crypto/src/util/Enums.cs79
-rw-r--r--crypto/src/util/IMemoable.cs29
-rw-r--r--crypto/src/util/Integers.cs17
-rw-r--r--crypto/src/util/MemoableResetException.cs27
-rw-r--r--crypto/src/util/Platform.cs117
-rw-r--r--crypto/src/util/Strings.cs92
-rw-r--r--crypto/src/util/Times.cs14
-rw-r--r--crypto/src/util/collections/CollectionUtilities.cs65
-rw-r--r--crypto/src/util/collections/EmptyEnumerable.cs44
-rw-r--r--crypto/src/util/collections/EnumerableProxy.cs25
-rw-r--r--crypto/src/util/collections/HashSet.cs99
-rw-r--r--crypto/src/util/collections/ISet.cs19
-rw-r--r--crypto/src/util/collections/LinkedDictionary.cs178
-rw-r--r--crypto/src/util/collections/UnmodifiableDictionary.cs64
-rw-r--r--crypto/src/util/collections/UnmodifiableDictionaryProxy.cs66
-rw-r--r--crypto/src/util/collections/UnmodifiableList.cs67
-rw-r--r--crypto/src/util/collections/UnmodifiableListProxy.cs61
-rw-r--r--crypto/src/util/collections/UnmodifiableSet.cs59
-rw-r--r--crypto/src/util/collections/UnmodifiableSetProxy.cs56
-rw-r--r--crypto/src/util/date/DateTimeObject.cs25
-rw-r--r--crypto/src/util/date/DateTimeUtilities.cs47
-rw-r--r--crypto/src/util/encoders/Base64.cs185
-rw-r--r--crypto/src/util/encoders/Base64Encoder.cs557
-rw-r--r--crypto/src/util/encoders/BufferedDecoder.cs117
-rw-r--r--crypto/src/util/encoders/BufferedEncoder.cs117
-rw-r--r--crypto/src/util/encoders/Hex.cs241
-rw-r--r--crypto/src/util/encoders/HexEncoder.cs328
-rw-r--r--crypto/src/util/encoders/HexTranslator.cs108
-rw-r--r--crypto/src/util/encoders/IEncoder.cs18
-rw-r--r--crypto/src/util/encoders/Translator.cs19
-rw-r--r--crypto/src/util/encoders/UrlBase64.cs127
-rw-r--r--crypto/src/util/encoders/UrlBase64Encoder.cs31
-rw-r--r--crypto/src/util/io/BaseInputStream.cs11
-rw-r--r--crypto/src/util/io/BaseOutputStream.cs9
-rw-r--r--crypto/src/util/io/NullOutputStream.cs18
-rw-r--r--crypto/src/util/io/PushbackStream.cs52
-rw-r--r--crypto/src/util/io/StreamOverflowException.cs5
-rw-r--r--crypto/src/util/io/Streams.cs94
-rw-r--r--crypto/src/util/io/TeeInputStream.cs13
-rw-r--r--crypto/src/util/io/TeeOutputStream.cs13
-rw-r--r--crypto/src/util/io/pem/PemGenerationException.cs5
-rw-r--r--crypto/src/util/io/pem/PemHeader.cs55
-rw-r--r--crypto/src/util/io/pem/PemObject.cs47
-rw-r--r--crypto/src/util/io/pem/PemObjectGenerator.cs13
-rw-r--r--crypto/src/util/io/pem/PemObjectParser.cs17
-rw-r--r--crypto/src/util/io/pem/PemReader.cs94
-rw-r--r--crypto/src/util/io/pem/PemWriter.cs120
-rw-r--r--crypto/src/util/net/IPAddress.cs197
-rw-r--r--crypto/src/util/zlib/Adler32.cs88
-rw-r--r--crypto/src/util/zlib/Deflate.cs1640
-rw-r--r--crypto/src/util/zlib/InfBlocks.cs618
-rw-r--r--crypto/src/util/zlib/InfCodes.cs611
-rw-r--r--crypto/src/util/zlib/InfTree.cs523
-rw-r--r--crypto/src/util/zlib/Inflate.cs387
-rw-r--r--crypto/src/util/zlib/JZlib.cs73
-rw-r--r--crypto/src/util/zlib/StaticTree.cs152
-rw-r--r--crypto/src/util/zlib/Tree.cs367
-rw-r--r--crypto/src/util/zlib/ZDeflaterOutputStream.cs24
-rw-r--r--crypto/src/util/zlib/ZInflaterInputStream.cs8
-rw-r--r--crypto/src/util/zlib/ZInputStream.cs17
-rw-r--r--crypto/src/util/zlib/ZOutputStream.cs71
-rw-r--r--crypto/src/util/zlib/ZStream.cs214
-rw-r--r--crypto/src/x509/AttributeCertificateHolder.cs442
-rw-r--r--crypto/src/x509/AttributeCertificateIssuer.cs199
-rw-r--r--crypto/src/x509/IX509AttributeCertificate.cs57
-rw-r--r--crypto/src/x509/IX509Extension.cs27
-rw-r--r--crypto/src/x509/PEMParser.cs94
-rw-r--r--crypto/src/x509/PrincipalUtil.cs70
-rw-r--r--crypto/src/x509/SubjectPublicKeyInfoFactory.cs240
-rw-r--r--crypto/src/x509/X509AttrCertParser.cs173
-rw-r--r--crypto/src/x509/X509Attribute.cs76
-rw-r--r--crypto/src/x509/X509CertPairParser.cs95
-rw-r--r--crypto/src/x509/X509Certificate.cs595
-rw-r--r--crypto/src/x509/X509CertificatePair.cs123
-rw-r--r--crypto/src/x509/X509CertificateParser.cs183
-rw-r--r--crypto/src/x509/X509Crl.cs403
-rw-r--r--crypto/src/x509/X509CrlEntry.cs201
-rw-r--r--crypto/src/x509/X509CrlParser.cs195
-rw-r--r--crypto/src/x509/X509ExtensionBase.cs82
-rw-r--r--crypto/src/x509/X509KeyUsage.cs59
-rw-r--r--crypto/src/x509/X509SignatureUtil.cs128
-rw-r--r--crypto/src/x509/X509Utilities.cs7
-rw-r--r--crypto/src/x509/X509V1CertificateGenerator.cs205
-rw-r--r--crypto/src/x509/X509V2AttributeCertificate.cs255
-rw-r--r--crypto/src/x509/X509V2AttributeCertificateGenerator.cs180
-rw-r--r--crypto/src/x509/X509V2CRLGenerator.cs261
-rw-r--r--crypto/src/x509/X509V3CertificateGenerator.cs346
-rw-r--r--crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs102
-rw-r--r--crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs49
-rw-r--r--crypto/src/x509/extension/X509ExtensionUtil.cs89
-rw-r--r--crypto/src/x509/store/IX509Selector.cs6
-rw-r--r--crypto/src/x509/store/IX509Store.cs11
-rw-r--r--crypto/src/x509/store/IX509StoreParameters.cs8
-rw-r--r--crypto/src/x509/store/NoSuchStoreException.cs5
-rw-r--r--crypto/src/x509/store/X509AttrCertStoreSelector.cs376
-rw-r--r--crypto/src/x509/store/X509CertPairStoreSelector.cs92
-rw-r--r--crypto/src/x509/store/X509CertStoreSelector.cs337
-rw-r--r--crypto/src/x509/store/X509CollectionStore.cs51
-rw-r--r--crypto/src/x509/store/X509CollectionStoreParameters.cs60
-rw-r--r--crypto/src/x509/store/X509CrlStoreSelector.cs283
-rw-r--r--crypto/src/x509/store/X509StoreException.cs5
-rw-r--r--crypto/src/x509/store/X509StoreFactory.cs7
-rw-r--r--crypto/test/data/PKITS/README.txt3
-rw-r--r--crypto/test/data/PKITS/certs/AllCertificatesNoPoliciesTest2EE.crtbin0 -> 627 bytes
-rw-r--r--crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest10EE.crtbin0 -> 670 bytes
-rw-r--r--crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest13EE.crtbin0 -> 687 bytes
-rw-r--r--crypto/test/data/PKITS/certs/AllCertificatesanyPolicyTest11EE.crtbin0 -> 643 bytes
-rw-r--r--crypto/test/data/PKITS/certs/AnyPolicyTest14EE.crtbin0 -> 632 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BadCRLIssuerNameCACert.crtbin0 -> 640 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BadCRLSignatureCACert.crtbin0 -> 638 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BadSignedCACert.crtbin0 -> 631 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BadnotAfterDateCACert.crtbin0 -> 638 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BadnotBeforeDateCACert.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCACert.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCRLCert.crtbin0 -> 797 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyCACert.crtbin0 -> 646 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyOldWithNewCACert.crtbin0 -> 662 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyCACert.crtbin0 -> 646 bytes
-rw-r--r--crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyNewWithOldCACert.crtbin0 -> 789 bytes
-rw-r--r--crypto/test/data/PKITS/certs/CPSPointerQualifierTest20EE.crtbin0 -> 701 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DSACACert.crtbin0 -> 906 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DSAParametersInheritedCACert.crtbin0 -> 536 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DifferentPoliciesTest12EE.crtbin0 -> 643 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DifferentPoliciesTest3EE.crtbin0 -> 645 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DifferentPoliciesTest4EE.crtbin0 -> 638 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DifferentPoliciesTest5EE.crtbin0 -> 646 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DifferentPoliciesTest7EE.crtbin0 -> 672 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DifferentPoliciesTest8EE.crtbin0 -> 670 bytes
-rw-r--r--crypto/test/data/PKITS/certs/DifferentPoliciesTest9EE.crtbin0 -> 660 bytes
-rw-r--r--crypto/test/data/PKITS/certs/GeneralizedTimeCRLnextUpdateCACert.crtbin0 -> 649 bytes
-rw-r--r--crypto/test/data/PKITS/certs/GoodCACert.crtbin0 -> 625 bytes
-rw-r--r--crypto/test/data/PKITS/certs/GoodsubCACert.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/GoodsubCAPanyPolicyMapping1to2CACert.crtbin0 -> 697 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidBadCRLIssuerNameTest5EE.crtbin0 -> 659 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidBadCRLSignatureTest4EE.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crtbin0 -> 687 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crtbin0 -> 687 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedNewWithOldTest5EE.crtbin0 -> 676 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedOldWithNewTest2EE.crtbin0 -> 676 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidCASignatureTest2EE.crtbin0 -> 628 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidCAnotAfterDateTest5EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidCAnotBeforeDateTest1EE.crtbin0 -> 656 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest31EE.crtbin0 -> 710 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest33EE.crtbin0 -> 699 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest38EE.crtbin0 -> 698 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest28EE.crtbin0 -> 778 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest29EE.crtbin0 -> 780 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest10EE.crtbin0 -> 715 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest12EE.crtbin0 -> 720 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest13EE.crtbin0 -> 720 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest15EE.crtbin0 -> 690 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest16EE.crtbin0 -> 690 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest17EE.crtbin0 -> 690 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest20EE.crtbin0 -> 633 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest2EE.crtbin0 -> 685 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest3EE.crtbin0 -> 833 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest7EE.crtbin0 -> 685 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest8EE.crtbin0 -> 685 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest9EE.crtbin0 -> 685 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidDSASignatureTest6EE.crtbin0 -> 827 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidEESignatureTest3EE.crtbin0 -> 622 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidEEnotAfterDateTest6EE.crtbin0 -> 641 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidEEnotBeforeDateTest2EE.crtbin0 -> 642 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest23EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest26EE.crtbin0 -> 743 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidLongSerialNumberTest18EE.crtbin0 -> 677 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidMappingFromanyPolicyTest7EE.crtbin0 -> 665 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidMappingToanyPolicyTest8EE.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidMissingCRLTest1EE.crtbin0 -> 638 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidMissingbasicConstraintsTest1EE.crtbin0 -> 669 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidNameChainingOrderTest2EE.crtbin0 -> 728 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidNameChainingTest1EE.crtbin0 -> 643 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidNegativeSerialNumberTest15EE.crtbin0 -> 666 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidOldCRLnextUpdateTest11EE.crtbin0 -> 658 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidPolicyMappingTest10EE.crtbin0 -> 667 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidPolicyMappingTest2EE.crtbin0 -> 647 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidPolicyMappingTest4EE.crtbin0 -> 657 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest22EE.crtbin0 -> 711 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest24EE.crtbin0 -> 722 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest26EE.crtbin0 -> 711 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidRevokedCATest2EE.crtbin0 -> 638 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidRevokedEETest3EE.crtbin0 -> 632 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest10EE.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest8EE.crtbin0 -> 673 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest10EE.crtbin0 -> 681 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest11EE.crtbin0 -> 681 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest8EE.crtbin0 -> 683 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest9EE.crtbin0 -> 683 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedpathLenConstraintTest16EE.crtbin0 -> 673 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest7EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest8EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest20EE.crtbin0 -> 689 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest21EE.crtbin0 -> 689 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest35EE.crtbin0 -> 716 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest37EE.crtbin0 -> 716 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidUnknownCRLEntryExtensionTest8EE.crtbin0 -> 675 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest10EE.crtbin0 -> 664 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest9EE.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidUnknownCriticalCertificateExtensionTest2EE.crtbin0 -> 683 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidWrongCRLTest6EE.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidcAFalseTest2EE.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidcAFalseTest3EE.crtbin0 -> 667 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidcRLIssuerTest27EE.crtbin0 -> 723 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidcRLIssuerTest31EE.crtbin0 -> 855 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidcRLIssuerTest32EE.crtbin0 -> 855 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidcRLIssuerTest34EE.crtbin0 -> 768 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidcRLIssuerTest35EE.crtbin0 -> 847 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddeltaCRLIndicatorNoBaseTest1EE.crtbin0 -> 671 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddeltaCRLTest10EE.crtbin0 -> 813 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddeltaCRLTest3EE.crtbin0 -> 812 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddeltaCRLTest4EE.crtbin0 -> 812 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddeltaCRLTest6EE.crtbin0 -> 812 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddeltaCRLTest9EE.crtbin0 -> 812 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddistributionPointTest2EE.crtbin0 -> 793 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddistributionPointTest3EE.crtbin0 -> 793 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddistributionPointTest6EE.crtbin0 -> 713 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddistributionPointTest8EE.crtbin0 -> 752 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvaliddistributionPointTest9EE.crtbin0 -> 656 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest1EE.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest4EE.crtbin0 -> 652 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest5EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest6EE.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest1EE.crtbin0 -> 679 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest3EE.crtbin0 -> 672 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest5EE.crtbin0 -> 671 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest6EE.crtbin0 -> 676 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalcRLSignFalseTest4EE.crtbin0 -> 683 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crtbin0 -> 691 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crtbin0 -> 691 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crtbin0 -> 692 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlyContainsAttributeCertsTest14EE.crtbin0 -> 674 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlyContainsCACertsTest12EE.crtbin0 -> 660 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlyContainsUserCertsTest11EE.crtbin0 -> 681 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest15EE.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest16EE.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest17EE.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest20EE.crtbin0 -> 872 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest21EE.crtbin0 -> 872 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest10EE.crtbin0 -> 682 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest11EE.crtbin0 -> 669 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest12EE.crtbin0 -> 686 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest5EE.crtbin0 -> 659 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest6EE.crtbin0 -> 676 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest9EE.crtbin0 -> 664 bytes
-rw-r--r--crypto/test/data/PKITS/certs/Invalidpre2000CRLnextUpdateTest12EE.crtbin0 -> 666 bytes
-rw-r--r--crypto/test/data/PKITS/certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest3EE.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest5EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/LongSerialNumberCACert.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/Mapping1to2CACert.crtbin0 -> 689 bytes
-rw-r--r--crypto/test/data/PKITS/certs/MappingFromanyPolicyCACert.crtbin0 -> 690 bytes
-rw-r--r--crypto/test/data/PKITS/certs/MappingToanyPolicyCACert.crtbin0 -> 694 bytes
-rw-r--r--crypto/test/data/PKITS/certs/MissingbasicConstraintsCACert.crtbin0 -> 628 bytes
-rw-r--r--crypto/test/data/PKITS/certs/NameOrderingCACert.crtbin0 -> 709 bytes
-rw-r--r--crypto/test/data/PKITS/certs/NegativeSerialNumberCACert.crtbin0 -> 643 bytes
-rw-r--r--crypto/test/data/PKITS/certs/NoCRLCACert.crtbin0 -> 627 bytes
-rw-r--r--crypto/test/data/PKITS/certs/NoPoliciesCACert.crtbin0 -> 607 bytes
-rw-r--r--crypto/test/data/PKITS/certs/NoissuingDistributionPointCACert.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/OldCRLnextUpdateCACert.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/OverlappingPoliciesTest6EE.crtbin0 -> 677 bytes
-rw-r--r--crypto/test/data/PKITS/certs/P12Mapping1to3CACert.crtbin0 -> 707 bytes
-rw-r--r--crypto/test/data/PKITS/certs/P12Mapping1to3subCACert.crtbin0 -> 729 bytes
-rw-r--r--crypto/test/data/PKITS/certs/P12Mapping1to3subsubCACert.crtbin0 -> 709 bytes
-rw-r--r--crypto/test/data/PKITS/certs/P1Mapping1to234CACert.crtbin0 -> 746 bytes
-rw-r--r--crypto/test/data/PKITS/certs/P1Mapping1to234subCACert.crtbin0 -> 731 bytes
-rw-r--r--crypto/test/data/PKITS/certs/P1anyPolicyMapping1to2CACert.crtbin0 -> 1058 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PanyPolicyMapping1to2CACert.crtbin0 -> 694 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP1234CACert.crtbin0 -> 693 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP1234subCAP123Cert.crtbin0 -> 677 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP1234subsubCAP123P12Cert.crtbin0 -> 676 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP123CACert.crtbin0 -> 678 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP123subCAP12Cert.crtbin0 -> 660 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P1Cert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P2Cert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP123subsubsubCAP12P2P1Cert.crtbin0 -> 665 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP12CACert.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP12subCAP1Cert.crtbin0 -> 641 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP12subsubCAP1P2Cert.crtbin0 -> 651 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP2subCA2Cert.crtbin0 -> 647 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP2subCACert.crtbin0 -> 630 bytes
-rw-r--r--crypto/test/data/PKITS/certs/PoliciesP3CACert.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/RFC3280MandatoryAttributeTypesCACert.crtbin0 -> 709 bytes
-rw-r--r--crypto/test/data/PKITS/certs/RFC3280OptionalAttributeTypesCACert.crtbin0 -> 721 bytes
-rw-r--r--crypto/test/data/PKITS/certs/RevokedsubCACert.crtbin0 -> 626 bytes
-rw-r--r--crypto/test/data/PKITS/certs/RolloverfromPrintableStringtoUTF8StringCACert.crtbin0 -> 664 bytes
-rw-r--r--crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CRLSigningCert.crtbin0 -> 638 bytes
-rw-r--r--crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CertificateSigningCACert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCRLSigningCert.crtbin0 -> 638 bytes
-rw-r--r--crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCertificateSigningCACert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/TrustAnchorRootCertificate.crtbin0 -> 572 bytes
-rw-r--r--crypto/test/data/PKITS/certs/TwoCRLsCACert.crtbin0 -> 629 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UIDCACert.crtbin0 -> 629 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UTF8StringCaseInsensitiveMatchCACert.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UTF8StringEncodedNamesCACert.crtbin0 -> 631 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UnknownCRLEntryExtensionCACert.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UnknownCRLExtensionCACert.crtbin0 -> 642 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UserNoticeQualifierTest15EE.crtbin0 -> 755 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UserNoticeQualifierTest16EE.crtbin0 -> 874 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UserNoticeQualifierTest17EE.crtbin0 -> 743 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UserNoticeQualifierTest18EE.crtbin0 -> 969 bytes
-rw-r--r--crypto/test/data/PKITS/certs/UserNoticeQualifierTest19EE.crtbin0 -> 992 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidBasicSelfIssuedCRLSigningKeyTest6EE.crtbin0 -> 685 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest3EE.crtbin0 -> 674 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest4EE.crtbin0 -> 674 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidBasicSelfIssuedOldWithNewTest1EE.crtbin0 -> 674 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidCertificatePathTest1EE.crtbin0 -> 622 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest30EE.crtbin0 -> 705 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest32EE.crtbin0 -> 705 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNandRFC822nameConstraintsTest27EE.crtbin0 -> 773 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest11EE.crtbin0 -> 714 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest14EE.crtbin0 -> 660 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest18EE.crtbin0 -> 661 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest19EE.crtbin0 -> 685 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest1EE.crtbin0 -> 684 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest4EE.crtbin0 -> 744 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest5EE.crtbin0 -> 829 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest6EE.crtbin0 -> 684 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDSAParameterInheritanceTest5EE.crtbin0 -> 566 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidDSASignaturesTest4EE.crtbin0 -> 826 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidGeneralizedTimeCRLnextUpdateTest13EE.crtbin0 -> 678 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidGeneralizedTimenotAfterDateTest8EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidGeneralizedTimenotBeforeDateTest4EE.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest22EE.crtbin0 -> 652 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest24EE.crtbin0 -> 740 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest25EE.crtbin0 -> 740 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidLongSerialNumberTest16EE.crtbin0 -> 675 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidLongSerialNumberTest17EE.crtbin0 -> 675 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidNameChainingCapitalizationTest5EE.crtbin0 -> 651 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest3EE.crtbin0 -> 652 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest4EE.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidNameUIDsTest6EE.crtbin0 -> 630 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidNegativeSerialNumberTest14EE.crtbin0 -> 665 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidNoissuingDistributionPointTest10EE.crtbin0 -> 793 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest11EE.crtbin0 -> 665 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest12EE.crtbin0 -> 1068 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest13EE.crtbin0 -> 658 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest14EE.crtbin0 -> 658 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest1EE.crtbin0 -> 645 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest3EE.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest5EE.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest6EE.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidPolicyMappingTest9EE.crtbin0 -> 656 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crtbin0 -> 740 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidRFC3280OptionalAttributeTypesTest8EE.crtbin0 -> 751 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest21EE.crtbin0 -> 720 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest23EE.crtbin0 -> 709 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest25EE.crtbin0 -> 720 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crtbin0 -> 694 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest7EE.crtbin0 -> 668 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest9EE.crtbin0 -> 668 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitPolicyMappingTest7EE.crtbin0 -> 678 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest15EE.crtbin0 -> 667 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest17EE.crtbin0 -> 670 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidSelfIssuedrequireExplicitPolicyTest6EE.crtbin0 -> 649 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidSeparateCertificateandCRLKeysTest19EE.crtbin0 -> 687 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidTwoCRLsTest7EE.crtbin0 -> 635 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidURInameConstraintsTest34EE.crtbin0 -> 723 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidURInameConstraintsTest36EE.crtbin0 -> 726 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crtbin0 -> 691 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidUTF8StringEncodedNamesTest9EE.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidUnknownNotCriticalCertificateExtensionTest1EE.crtbin0 -> 681 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidbasicConstraintsNotCriticalTest4EE.crtbin0 -> 677 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidcRLIssuerTest28EE.crtbin0 -> 873 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidcRLIssuerTest29EE.crtbin0 -> 788 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidcRLIssuerTest30EE.crtbin0 -> 873 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidcRLIssuerTest33EE.crtbin0 -> 853 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddeltaCRLTest2EE.crtbin0 -> 810 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddeltaCRLTest5EE.crtbin0 -> 810 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddeltaCRLTest7EE.crtbin0 -> 810 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddeltaCRLTest8EE.crtbin0 -> 810 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddistributionPointTest1EE.crtbin0 -> 791 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddistributionPointTest4EE.crtbin0 -> 711 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddistributionPointTest5EE.crtbin0 -> 711 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValiddistributionPointTest7EE.crtbin0 -> 791 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidinhibitAnyPolicyTest2EE.crtbin0 -> 660 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest2EE.crtbin0 -> 667 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest4EE.crtbin0 -> 670 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidkeyUsageNotCriticalTest3EE.crtbin0 -> 661 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidonlyContainsCACertsTest13EE.crtbin0 -> 675 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest18EE.crtbin0 -> 759 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest19EE.crtbin0 -> 870 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidpathLenConstraintTest13EE.crtbin0 -> 667 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidpathLenConstraintTest14EE.crtbin0 -> 684 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidpathLenConstraintTest7EE.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidpathLenConstraintTest8EE.crtbin0 -> 671 bytes
-rw-r--r--crypto/test/data/PKITS/certs/Validpre2000UTCnotBeforeDateTest3EE.crtbin0 -> 649 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest1EE.crtbin0 -> 647 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest2EE.crtbin0 -> 646 bytes
-rw-r--r--crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest4EE.crtbin0 -> 671 bytes
-rw-r--r--crypto/test/data/PKITS/certs/WrongCRLCACert.crtbin0 -> 630 bytes
-rw-r--r--crypto/test/data/PKITS/certs/anyPolicyCACert.crtbin0 -> 640 bytes
-rw-r--r--crypto/test/data/PKITS/certs/basicConstraintsCriticalcAFalseCACert.crtbin0 -> 652 bytes
-rw-r--r--crypto/test/data/PKITS/certs/basicConstraintsNotCriticalCACert.crtbin0 -> 647 bytes
-rw-r--r--crypto/test/data/PKITS/certs/basicConstraintsNotCriticalcAFalseCACert.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/deltaCRLCA1Cert.crtbin0 -> 630 bytes
-rw-r--r--crypto/test/data/PKITS/certs/deltaCRLCA2Cert.crtbin0 -> 630 bytes
-rw-r--r--crypto/test/data/PKITS/certs/deltaCRLCA3Cert.crtbin0 -> 630 bytes
-rw-r--r--crypto/test/data/PKITS/certs/deltaCRLIndicatorNoBaseCACert.crtbin0 -> 646 bytes
-rw-r--r--crypto/test/data/PKITS/certs/distributionPoint1CACert.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/distributionPoint2CACert.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA1Cert.crtbin0 -> 633 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA2Cert.crtbin0 -> 633 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA3Cert.crtbin0 -> 633 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA3cRLIssuerCert.crtbin0 -> 734 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA4Cert.crtbin0 -> 633 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA4cRLIssuerCert.crtbin0 -> 861 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA5Cert.crtbin0 -> 633 bytes
-rw-r--r--crypto/test/data/PKITS/certs/indirectCRLCA6Cert.crtbin0 -> 633 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy0CACert.crtbin0 -> 669 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy1CACert.crtbin0 -> 669 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedCACert.crtbin0 -> 646 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedsubCA2Cert.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA1Cert.crtbin0 -> 644 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA2Cert.crtbin0 -> 644 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCAIAP5Cert.crtbin0 -> 670 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy1subsubCA2Cert.crtbin0 -> 651 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy5CACert.crtbin0 -> 669 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy5subCACert.crtbin0 -> 666 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicy5subsubCACert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitAnyPolicyTest3EE.crtbin0 -> 650 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping0CACert.crtbin0 -> 664 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping0subCACert.crtbin0 -> 699 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12CACert.crtbin0 -> 682 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCACert.crtbin0 -> 747 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCAIPM5Cert.crtbin0 -> 702 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCACert.crtbin0 -> 727 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCAIPM5Cert.crtbin0 -> 735 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1CACert.crtbin0 -> 667 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedCACert.crtbin0 -> 660 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedsubCACert.crtbin0 -> 708 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subCACert.crtbin0 -> 705 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subsubCACert.crtbin0 -> 711 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping5CACert.crtbin0 -> 664 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping5subCACert.crtbin0 -> 676 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubCACert.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubsubCACert.crtbin0 -> 711 bytes
-rw-r--r--crypto/test/data/PKITS/certs/keyUsageCriticalcRLSignFalseCACert.crtbin0 -> 652 bytes
-rw-r--r--crypto/test/data/PKITS/certs/keyUsageCriticalkeyCertSignFalseCACert.crtbin0 -> 656 bytes
-rw-r--r--crypto/test/data/PKITS/certs/keyUsageNotCriticalCACert.crtbin0 -> 639 bytes
-rw-r--r--crypto/test/data/PKITS/certs/keyUsageNotCriticalcRLSignFalseCACert.crtbin0 -> 653 bytes
-rw-r--r--crypto/test/data/PKITS/certs/keyUsageNotCriticalkeyCertSignFalseCACert.crtbin0 -> 657 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN1CACert.crtbin0 -> 733 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN1SelfIssuedCACert.crtbin0 -> 650 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN1subCA1Cert.crtbin0 -> 803 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN1subCA2Cert.crtbin0 -> 775 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN1subCA3Cert.crtbin0 -> 724 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN2CACert.crtbin0 -> 814 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN3CACert.crtbin0 -> 732 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN3subCA1Cert.crtbin0 -> 746 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN3subCA2Cert.crtbin0 -> 719 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN4CACert.crtbin0 -> 812 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDN5CACert.crtbin0 -> 842 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDNS1CACert.crtbin0 -> 683 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsDNS2CACert.crtbin0 -> 686 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsRFC822CA1Cert.crtbin0 -> 687 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsRFC822CA2Cert.crtbin0 -> 686 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsRFC822CA3Cert.crtbin0 -> 686 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsURI1CACert.crtbin0 -> 684 bytes
-rw-r--r--crypto/test/data/PKITS/certs/nameConstraintsURI2CACert.crtbin0 -> 686 bytes
-rw-r--r--crypto/test/data/PKITS/certs/onlyContainsAttributeCertsCACert.crtbin0 -> 647 bytes
-rw-r--r--crypto/test/data/PKITS/certs/onlyContainsCACertsCACert.crtbin0 -> 640 bytes
-rw-r--r--crypto/test/data/PKITS/certs/onlyContainsUserCertsCACert.crtbin0 -> 642 bytes
-rw-r--r--crypto/test/data/PKITS/certs/onlySomeReasonsCA1Cert.crtbin0 -> 637 bytes
-rw-r--r--crypto/test/data/PKITS/certs/onlySomeReasonsCA2Cert.crtbin0 -> 637 bytes
-rw-r--r--crypto/test/data/PKITS/certs/onlySomeReasonsCA3Cert.crtbin0 -> 637 bytes
-rw-r--r--crypto/test/data/PKITS/certs/onlySomeReasonsCA4Cert.crtbin0 -> 637 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint0CACert.crtbin0 -> 642 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint0SelfIssuedCACert.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint0subCA2Cert.crtbin0 -> 652 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint0subCACert.crtbin0 -> 651 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint1CACert.crtbin0 -> 642 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedCACert.crtbin0 -> 648 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedsubCACert.crtbin0 -> 654 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint1subCACert.crtbin0 -> 651 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6CACert.crtbin0 -> 642 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subCA0Cert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subCA1Cert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subCA4Cert.crtbin0 -> 655 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA00Cert.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA11Cert.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA41Cert.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA11XCert.crtbin0 -> 668 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA41XCert.crtbin0 -> 668 bytes
-rw-r--r--crypto/test/data/PKITS/certs/pre2000CRLnextUpdateCACert.crtbin0 -> 643 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy0CACert.crtbin0 -> 662 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy0subCACert.crtbin0 -> 659 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubCACert.crtbin0 -> 665 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubsubCACert.crtbin0 -> 671 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy10CACert.crtbin0 -> 663 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy10subCACert.crtbin0 -> 661 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubCACert.crtbin0 -> 667 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubsubCACert.crtbin0 -> 673 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy2CACert.crtbin0 -> 662 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedCACert.crtbin0 -> 656 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedsubCACert.crtbin0 -> 662 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy2subCACert.crtbin0 -> 659 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy4CACert.crtbin0 -> 662 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy4subCACert.crtbin0 -> 659 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubCACert.crtbin0 -> 665 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubsubCACert.crtbin0 -> 671 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy5CACert.crtbin0 -> 662 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy5subCACert.crtbin0 -> 659 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubCACert.crtbin0 -> 665 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubsubCACert.crtbin0 -> 671 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy7CACert.crtbin0 -> 662 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy7subCARE2Cert.crtbin0 -> 681 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubCARE2RE4Cert.crtbin0 -> 693 bytes
-rw-r--r--crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubsubCARE2RE4Cert.crtbin0 -> 683 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BadCRLIssuerNameCACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BadCRLSignatureCACRL.crlbin0 -> 325 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BadSignedCACRL.crlbin0 -> 318 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BadnotAfterDateCACRL.crlbin0 -> 325 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BadnotBeforeDateCACRL.crlbin0 -> 326 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCACRL.crlbin0 -> 377 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.crlbin0 -> 479 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BasicSelfIssuedNewKeyCACRL.crlbin0 -> 369 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeyCACRL.crlbin0 -> 369 bytes
-rw-r--r--crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.crlbin0 -> 462 bytes
-rw-r--r--crypto/test/data/PKITS/crls/DSACACRL.crlbin0 -> 219 bytes
-rw-r--r--crypto/test/data/PKITS/crls/DSAParametersInheritedCACRL.crlbin0 -> 241 bytes
-rw-r--r--crypto/test/data/PKITS/crls/GeneralizedTimeCRLnextUpdateCACRL.crlbin0 -> 338 bytes
-rw-r--r--crypto/test/data/PKITS/crls/GoodCACRL.crlbin0 -> 382 bytes
-rw-r--r--crypto/test/data/PKITS/crls/GoodsubCACRL.crlbin0 -> 315 bytes
-rw-r--r--crypto/test/data/PKITS/crls/GoodsubCAPanyPolicyMapping1to2CACRL.crlbin0 -> 339 bytes
-rw-r--r--crypto/test/data/PKITS/crls/LongSerialNumberCACRL.crlbin0 -> 381 bytes
-rw-r--r--crypto/test/data/PKITS/crls/Mapping1to2CACRL.crlbin0 -> 320 bytes
-rw-r--r--crypto/test/data/PKITS/crls/MappingFromanyPolicyCACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/MappingToanyPolicyCACRL.crlbin0 -> 328 bytes
-rw-r--r--crypto/test/data/PKITS/crls/MissingbasicConstraintsCACRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/NameOrderCACRL.crlbin0 -> 396 bytes
-rw-r--r--crypto/test/data/PKITS/crls/NegativeSerialNumberCACRL.crlbin0 -> 366 bytes
-rw-r--r--crypto/test/data/PKITS/crls/NoPoliciesCACRL.crlbin0 -> 319 bytes
-rw-r--r--crypto/test/data/PKITS/crls/NoissuingDistributionPointCACRL.crlbin0 -> 335 bytes
-rw-r--r--crypto/test/data/PKITS/crls/OldCRLnextUpdateCACRL.crlbin0 -> 326 bytes
-rw-r--r--crypto/test/data/PKITS/crls/P12Mapping1to3CACRL.crlbin0 -> 324 bytes
-rw-r--r--crypto/test/data/PKITS/crls/P12Mapping1to3subCACRL.crlbin0 -> 327 bytes
-rw-r--r--crypto/test/data/PKITS/crls/P12Mapping1to3subsubCACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/P1Mapping1to234CACRL.crlbin0 -> 325 bytes
-rw-r--r--crypto/test/data/PKITS/crls/P1Mapping1to234subCACRL.crlbin0 -> 328 bytes
-rw-r--r--crypto/test/data/PKITS/crls/P1anyPolicyMapping1to2CACRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PanyPolicyMapping1to2CACRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP1234CACRL.crlbin0 -> 322 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP1234subCAP123CRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP1234subsubCAP123P12CRL.crlbin0 -> 335 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP123CACRL.crlbin0 -> 321 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP123subCAP12CRL.crlbin0 -> 327 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP123subsubCAP12P1CRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP123subsubCAP2P2CRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP123subsubsubCAP12P2P1CRL.crlbin0 -> 337 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP12CACRL.crlbin0 -> 320 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP12subCAP1CRL.crlbin0 -> 325 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP12subsubCAP1P2CRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP2subCA2CRL.crlbin0 -> 323 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP2subCACRL.crlbin0 -> 322 bytes
-rw-r--r--crypto/test/data/PKITS/crls/PoliciesP3CACRL.crlbin0 -> 319 bytes
-rw-r--r--crypto/test/data/PKITS/crls/RFC3280MandatoryAttributeTypesCACRL.crlbin0 -> 396 bytes
-rw-r--r--crypto/test/data/PKITS/crls/RFC3280OptionalAttributeTypesCACRL.crlbin0 -> 408 bytes
-rw-r--r--crypto/test/data/PKITS/crls/RevokedsubCACRL.crlbin0 -> 318 bytes
-rw-r--r--crypto/test/data/PKITS/crls/RolloverfromPrintableStringtoUTF8StringCACRL.crlbin0 -> 351 bytes
-rw-r--r--crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCA2CRL.crlbin0 -> 342 bytes
-rw-r--r--crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCRL.crlbin0 -> 378 bytes
-rw-r--r--crypto/test/data/PKITS/crls/TrustAnchorRootCRL.crlbin0 -> 353 bytes
-rw-r--r--crypto/test/data/PKITS/crls/TwoCRLsCABadCRL.crlbin0 -> 364 bytes
-rw-r--r--crypto/test/data/PKITS/crls/TwoCRLsCAGoodCRL.crlbin0 -> 316 bytes
-rw-r--r--crypto/test/data/PKITS/crls/UIDCACRL.crlbin0 -> 311 bytes
-rw-r--r--crypto/test/data/PKITS/crls/UTF8StringCaseInsensitiveMatchCACRL.crlbin0 -> 341 bytes
-rw-r--r--crypto/test/data/PKITS/crls/UTF8StringEncodedNamesCACRL.crlbin0 -> 318 bytes
-rw-r--r--crypto/test/data/PKITS/crls/UnknownCRLEntryExtensionCACRL.crlbin0 -> 392 bytes
-rw-r--r--crypto/test/data/PKITS/crls/UnknownCRLExtensionCACRL.crlbin0 -> 386 bytes
-rw-r--r--crypto/test/data/PKITS/crls/WrongCRLCACRL.crlbin0 -> 353 bytes
-rw-r--r--crypto/test/data/PKITS/crls/anyPolicyCACRL.crlbin0 -> 317 bytes
-rw-r--r--crypto/test/data/PKITS/crls/basicConstraintsCriticalcAFalseCACRL.crlbin0 -> 342 bytes
-rw-r--r--crypto/test/data/PKITS/crls/basicConstraintsNotCriticalCACRL.crlbin0 -> 337 bytes
-rw-r--r--crypto/test/data/PKITS/crls/basicConstraintsNotCriticalcAFalseCACRL.crlbin0 -> 346 bytes
-rw-r--r--crypto/test/data/PKITS/crls/deltaCRLCA1CRL.crlbin0 -> 509 bytes
-rw-r--r--crypto/test/data/PKITS/crls/deltaCRLCA1deltaCRL.crlbin0 -> 472 bytes
-rw-r--r--crypto/test/data/PKITS/crls/deltaCRLCA2CRL.crlbin0 -> 441 bytes
-rw-r--r--crypto/test/data/PKITS/crls/deltaCRLCA2deltaCRL.crlbin0 -> 368 bytes
-rw-r--r--crypto/test/data/PKITS/crls/deltaCRLCA3CRL.crlbin0 -> 404 bytes
-rw-r--r--crypto/test/data/PKITS/crls/deltaCRLCA3deltaCRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/deltaCRLIndicatorNoBaseCACRL.crlbin0 -> 348 bytes
-rw-r--r--crypto/test/data/PKITS/crls/distributionPoint1CACRL.crlbin0 -> 501 bytes
-rw-r--r--crypto/test/data/PKITS/crls/distributionPoint2CACRL.crlbin0 -> 419 bytes
-rw-r--r--crypto/test/data/PKITS/crls/indirectCRLCA1CRL.crlbin0 -> 373 bytes
-rw-r--r--crypto/test/data/PKITS/crls/indirectCRLCA3CRL.crlbin0 -> 427 bytes
-rw-r--r--crypto/test/data/PKITS/crls/indirectCRLCA3cRLIssuerCRL.crlbin0 -> 481 bytes
-rw-r--r--crypto/test/data/PKITS/crls/indirectCRLCA4cRLIssuerCRL.crlbin0 -> 481 bytes
-rw-r--r--crypto/test/data/PKITS/crls/indirectCRLCA5CRL.crlbin0 -> 1408 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy0CACRL.crlbin0 -> 325 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy1CACRL.crlbin0 -> 325 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA1CRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA2CRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCAIAP5CRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy1subsubCA2CRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy5CACRL.crlbin0 -> 325 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy5subCACRL.crlbin0 -> 328 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitAnyPolicy5subsubCACRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping0CACRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping0subCACRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12CACRL.crlbin0 -> 333 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCACRL.crlbin0 -> 336 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCAIPM5CRL.crlbin0 -> 340 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCACRL.crlbin0 -> 339 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.crlbin0 -> 343 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1CACRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subCACRL.crlbin0 -> 335 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subsubCACRL.crlbin0 -> 338 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping5CACRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping5subCACRL.crlbin0 -> 332 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubCACRL.crlbin0 -> 335 bytes
-rw-r--r--crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubsubCACRL.crlbin0 -> 338 bytes
-rw-r--r--crypto/test/data/PKITS/crls/keyUsageCriticalcRLSignFalseCACRL.crlbin0 -> 339 bytes
-rw-r--r--crypto/test/data/PKITS/crls/keyUsageCriticalkeyCertSignFalseCACRL.crlbin0 -> 343 bytes
-rw-r--r--crypto/test/data/PKITS/crls/keyUsageNotCriticalCACRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/keyUsageNotCriticalcRLSignFalseCACRL.crlbin0 -> 343 bytes
-rw-r--r--crypto/test/data/PKITS/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.crlbin0 -> 347 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN1CACRL.crlbin0 -> 327 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN1subCA1CRL.crlbin0 -> 359 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN1subCA2CRL.crlbin0 -> 359 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN1subCA3CRL.crlbin0 -> 359 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN2CACRL.crlbin0 -> 327 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN3CACRL.crlbin0 -> 327 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN3subCA1CRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN3subCA2CRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN4CACRL.crlbin0 -> 327 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDN5CACRL.crlbin0 -> 327 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDNS1CACRL.crlbin0 -> 328 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsDNS2CACRL.crlbin0 -> 328 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsRFC822CA1CRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsRFC822CA2CRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsRFC822CA3CRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsURI1CACRL.crlbin0 -> 328 bytes
-rw-r--r--crypto/test/data/PKITS/crls/nameConstraintsURI2CACRL.crlbin0 -> 328 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlyContainsAttributeCertsCACRL.crlbin0 -> 351 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlyContainsCACertsCACRL.crlbin0 -> 344 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlyContainsUserCertsCACRL.crlbin0 -> 346 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA1compromiseCRL.crlbin0 -> 378 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA1otherreasonsCRL.crlbin0 -> 379 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL1.crlbin0 -> 342 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL2.crlbin0 -> 342 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA3compromiseCRL.crlbin0 -> 438 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA3otherreasonsCRL.crlbin0 -> 439 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA4compromiseCRL.crlbin0 -> 475 bytes
-rw-r--r--crypto/test/data/PKITS/crls/onlySomeReasonsCA4otherreasonsCRL.crlbin0 -> 476 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint0CACRL.crlbin0 -> 326 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint0subCA2CRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint0subCACRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint1CACRL.crlbin0 -> 326 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint1subCACRL.crlbin0 -> 329 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6CACRL.crlbin0 -> 326 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subCA0CRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subCA1CRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subCA4CRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA00CRL.crlbin0 -> 334 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA11CRL.crlbin0 -> 334 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA41CRL.crlbin0 -> 334 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA11XCRL.crlbin0 -> 338 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA41XCRL.crlbin0 -> 338 bytes
-rw-r--r--crypto/test/data/PKITS/crls/pre2000CRLnextUpdateCACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy0CACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy0subCACRL.crlbin0 -> 333 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubCACRL.crlbin0 -> 336 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubsubCACRL.crlbin0 -> 339 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy10CACRL.crlbin0 -> 331 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy10subCACRL.crlbin0 -> 334 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubCACRL.crlbin0 -> 337 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubsubCACRL.crlbin0 -> 340 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy2CACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy2subCACRL.crlbin0 -> 333 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy4CACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy4subCACRL.crlbin0 -> 333 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubCACRL.crlbin0 -> 336 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubsubCACRL.crlbin0 -> 339 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy5CACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy5subCACRL.crlbin0 -> 333 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubCACRL.crlbin0 -> 336 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubsubCACRL.crlbin0 -> 339 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy7CACRL.crlbin0 -> 330 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy7subCARE2CRL.crlbin0 -> 336 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubCARE2RE4CRL.crlbin0 -> 342 bytes
-rw-r--r--crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.crlbin0 -> 345 bytes
-rw-r--r--crypto/test/data/asn1/masterlist-content.databin0 -> 1748 bytes
-rw-r--r--crypto/test/data/cms/sigs/PSSSignData.data1
-rw-r--r--crypto/test/data/cms/sigs/PSSSignDataSHA1.sigbin0 -> 3345 bytes
-rw-r--r--crypto/test/data/cms/sigs/PSSSignDataSHA1Enc.sigbin0 -> 3371 bytes
-rw-r--r--crypto/test/data/cms/sigs/PSSSignDataSHA256.sigbin0 -> 3417 bytes
-rw-r--r--crypto/test/data/cms/sigs/PSSSignDataSHA256Enc.sigbin0 -> 3443 bytes
-rw-r--r--crypto/test/data/cms/sigs/PSSSignDataSHA512.sigbin0 -> 3450 bytes
-rw-r--r--crypto/test/data/cms/sigs/PSSSignDataSHA512Enc.sigbin0 -> 3476 bytes
-rw-r--r--crypto/test/data/cms/sigs/counterSig.p7mbin0 -> 5647 bytes
-rw-r--r--crypto/test/data/hc256/hc128/ecrypt_HC-128.txt2337
-rw-r--r--crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_128IV.txt2337
-rw-r--r--crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_256IV.txt2783
-rw-r--r--crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_128IV.txt2783
-rw-r--r--crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_256IV.txt3257
-rw-r--r--crypto/test/data/keys/README.txt4
-rw-r--r--crypto/test/data/keys/pbes1/pbeWithMD2AndDES_CBC.keybin0 -> 677 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbeWithMD2AndRC2_CBC.keybin0 -> 677 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbeWithMD5AndDES_CBC.keybin0 -> 677 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbeWithMD5AndRC2_CBC.keybin0 -> 677 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbeWithSHA1AndDES_CBC.keybin0 -> 677 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbeWithSHA1AndRC2_CBC.keybin0 -> 677 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC2_CBC.keybin0 -> 678 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC4.keybin0 -> 673 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbe_WithSHA1And2_Key_TripleDES_CBC.keybin0 -> 678 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbe_WithSHA1And3_Key_TripleDES_CBC.keybin0 -> 678 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC2_CBC.keybin0 -> 678 bytes
-rw-r--r--crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC4.keybin0 -> 673 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-128-cbc.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-128-cfb.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-128-cfb1.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-128-cfb8.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-128-ecb.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-128-ofb.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-192-cbc.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-192-cfb.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-192-cfb1.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-192-cfb8.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-192-ecb.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-192-ofb.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-256-cbc.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-256-cfb.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-256-cfb1.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-256-cfb8.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-256-ecb.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes-256-ofb.keybin0 -> 718 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes128.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes192.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.aes256.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.bf-cbc.keybin0 -> 715 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.bf.keybin0 -> 715 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.blowfish.keybin0 -> 715 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.cast-cbc.keybin0 -> 715 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.cast.keybin0 -> 715 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.cast5-cbc.keybin0 -> 715 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-cbc.keybin0 -> 711 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-cfb.keybin0 -> 706 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-cfb1.keybin0 -> 706 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-cfb8.keybin0 -> 706 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-ecb.keybin0 -> 711 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-ede.keybin0 -> 711 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-ede3-cbc.keybin0 -> 714 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des-ofb.keybin0 -> 706 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des.keybin0 -> 711 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.des3.keybin0 -> 714 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.rc2-40-cbc.keybin0 -> 723 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.rc2-64-cbc.keybin0 -> 722 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.rc2-cbc.keybin0 -> 722 bytes
-rw-r--r--crypto/test/data/keys/pbes2/pbes2.rc2.keybin0 -> 722 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/README.txt36
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-1024-160.pubbin0 -> 534 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-1024-160.secbin0 -> 597 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-15360-512.pubbin0 -> 6043 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-15360-512.secbin0 -> 6150 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-2048-224.pubbin0 -> 941 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-2048-224.secbin0 -> 1012 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-3072-256.pubbin0 -> 1337 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-3072-256.secbin0 -> 1412 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-7680-384.pubbin0 -> 3113 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/keys/DSA-7680-384.secbin0 -> 3204 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-1024-160-sign.gpg1
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-1024-224-sign.gpgbin0 -> 121 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-1024-256-sign.gpgbin0 -> 123 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-1024-384-sign.gpgbin0 -> 122 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-1024-512-sign.gpgbin0 -> 122 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-15360-512-sign.gpgbin0 -> 216 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-2048-224-sign.gpgbin0 -> 141 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-3072-256-sign.gpgbin0 -> 150 bytes
-rw-r--r--crypto/test/data/openpgp/dsa/sigs/dsa-7680-384-sign.gpgbin0 -> 184 bytes
-rw-r--r--crypto/test/data/openssl/README.txt8
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes128_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes128_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes128_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes128_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes192_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes192_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes192_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes192_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes256_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes256_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes256_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_aes256_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des1_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des1_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des1_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des1_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des2_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des2_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des2_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des2_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des3_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des3_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des3_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_des3_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cfb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ecb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ofb.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_rc2_40_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_rc2_64_cbc.pem23
-rw-r--r--crypto/test/data/openssl/dsa/openssl_dsa_unencrypted.pem20
-rw-r--r--crypto/test/data/openssl/eckey.pem9
-rw-r--r--crypto/test/data/openssl/enckey.pem30
-rw-r--r--crypto/test/data/openssl/pkcs7.pem54
-rw-r--r--crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa.pem28
-rw-r--r--crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa_enc.pem30
-rw-r--r--crypto/test/data/openssl/pkcs8test.pem175
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes128_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes128_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes128_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes128_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes192_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes192_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes192_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes192_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes256_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes256_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes256_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_aes256_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des1_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des1_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des1_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des1_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des2_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des2_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des2_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des2_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des3_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des3_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des3_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_des3_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cfb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ecb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ofb.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_rc2_40_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_rc2_64_cbc.pem30
-rw-r--r--crypto/test/data/openssl/rsa/openssl_rsa_unencrypted.pem27
-rw-r--r--crypto/test/data/openssl/test.pem133
-rw-r--r--crypto/test/data/rfc4134/3.1.binbin0 -> 55 bytes
-rw-r--r--crypto/test/data/rfc4134/3.2.bin1
-rw-r--r--crypto/test/data/rfc4134/4.1.binbin0 -> 923 bytes
-rw-r--r--crypto/test/data/rfc4134/4.10.binbin0 -> 2051 bytes
-rw-r--r--crypto/test/data/rfc4134/4.11.binbin0 -> 1676 bytes
-rw-r--r--crypto/test/data/rfc4134/4.2.binbin0 -> 854 bytes
-rw-r--r--crypto/test/data/rfc4134/4.3.binbin0 -> 891 bytes
-rw-r--r--crypto/test/data/rfc4134/4.4.binbin0 -> 2833 bytes
-rw-r--r--crypto/test/data/rfc4134/4.5.binbin0 -> 1359 bytes
-rw-r--r--crypto/test/data/rfc4134/4.6.binbin0 -> 1467 bytes
-rw-r--r--crypto/test/data/rfc4134/4.7.binbin0 -> 920 bytes
-rw-r--r--crypto/test/data/rfc4134/4.8.eml39
-rw-r--r--crypto/test/data/rfc4134/4.9.eml28
-rw-r--r--crypto/test/data/rfc4134/5.1.binbin0 -> 290 bytes
-rw-r--r--crypto/test/data/rfc4134/5.2.binbin0 -> 361 bytes
-rw-r--r--crypto/test/data/rfc4134/5.3.eml19
-rw-r--r--crypto/test/data/rfc4134/6.0.binbin0 -> 96 bytes
-rw-r--r--crypto/test/data/rfc4134/7.1.binbin0 -> 89 bytes
-rw-r--r--crypto/test/data/rfc4134/7.2.binbin0 -> 152 bytes
-rw-r--r--crypto/test/data/rfc4134/AliceDSSSignByCarlNoInherit.cerbin0 -> 736 bytes
-rw-r--r--crypto/test/data/rfc4134/AlicePrivDSSSign.pribin0 -> 335 bytes
-rw-r--r--crypto/test/data/rfc4134/AlicePrivRSASign.pribin0 -> 634 bytes
-rw-r--r--crypto/test/data/rfc4134/AliceRSASignByCarl.cerbin0 -> 560 bytes
-rw-r--r--crypto/test/data/rfc4134/BobPrivRSAEncrypt.pribin0 -> 649 bytes
-rw-r--r--crypto/test/data/rfc4134/BobRSASignByCarl.cerbin0 -> 555 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlDSSCRLEmpty.crlbin0 -> 111 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlDSSCRLForAll.crlbin0 -> 219 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlDSSCRLForCarl.crlbin0 -> 134 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlDSSSelf.cerbin0 -> 671 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlPrivDSSSign.pribin0 -> 334 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlPrivRSASign.pribin0 -> 634 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlRSACRLEmpty.crlbin0 -> 202 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlRSACRLForAll.crlbin0 -> 311 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlRSACRLForCarl.crlbin0 -> 239 bytes
-rw-r--r--crypto/test/data/rfc4134/CarlRSASelf.cerbin0 -> 495 bytes
-rw-r--r--crypto/test/data/rfc4134/DianeDSSSignByCarlInherit.cerbin0 -> 444 bytes
-rw-r--r--crypto/test/data/rfc4134/DianePrivDSSSign.pribin0 -> 335 bytes
-rw-r--r--crypto/test/data/rfc4134/DianePrivRSASignEncrypt.pribin0 -> 635 bytes
-rw-r--r--crypto/test/data/rfc4134/DianeRSASignByCarl.cerbin0 -> 560 bytes
-rw-r--r--crypto/test/data/rfc4134/ExContent.bin1
-rw-r--r--crypto/test/data/rfc4134/rfc4134.txt7619
-rw-r--r--crypto/test/data/rsa3/self-testcase-A.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-A.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-B.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-B.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-C.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-C.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-D.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-D.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-E.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-E.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-F.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-F.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-G.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-G.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-H.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-H.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-I.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-I.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-J.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-J.pem52
-rw-r--r--crypto/test/data/rsa3/self-testcase-L.p12bin0 -> 2742 bytes
-rw-r--r--crypto/test/data/rsa3/self-testcase-L.pem52
-rw-r--r--crypto/test/data/rsa3/testcases.READMEbin0 -> 14352 bytes
-rw-r--r--crypto/test/data/scrypt/TestVectors.txt20
-rw-r--r--crypto/test/data/tls/README.txt8
-rw-r--r--crypto/test/data/tls/ca.tmpl4
-rw-r--r--crypto/test/data/tls/client.tmpl5
-rw-r--r--crypto/test/data/tls/keystores/client_store.dsabin0 -> 2035 bytes
-rw-r--r--crypto/test/data/tls/keystores/client_store.rsabin0 -> 1947 bytes
-rw-r--r--crypto/test/data/tls/keystores/server_store.dsabin0 -> 2035 bytes
-rw-r--r--crypto/test/data/tls/keystores/server_store.rsabin0 -> 1947 bytes
-rw-r--r--crypto/test/data/tls/server.tmpl5
-rw-r--r--crypto/test/data/tls/x509-ca-key.pem32
-rw-r--r--crypto/test/data/tls/x509-ca.pem21
-rw-r--r--crypto/test/data/tls/x509-client-key.pem32
-rw-r--r--crypto/test/data/tls/x509-client.pem22
-rw-r--r--crypto/test/data/tls/x509-server-key.pem32
-rw-r--r--crypto/test/data/tls/x509-server.pem22
-rw-r--r--crypto/test/lib/nunit.core.dllbin0 -> 90112 bytes
-rw-r--r--crypto/test/lib/nunit.core.interfaces.dllbin0 -> 40960 bytes
-rw-r--r--crypto/test/lib/nunit.framework.dllbin0 -> 81920 bytes
-rw-r--r--crypto/test/src/asn1/test/ASN1SequenceParserTest.cs359
-rw-r--r--crypto/test/src/asn1/test/ASN1UnitTest.cs88
-rw-r--r--crypto/test/src/asn1/test/AdditionalInformationSyntaxUnitTest.cs77
-rw-r--r--crypto/test/src/asn1/test/AdmissionSyntaxUnitTest.cs99
-rw-r--r--crypto/test/src/asn1/test/AdmissionsUnitTest.cs90
-rw-r--r--crypto/test/src/asn1/test/AllTests.cs32
-rw-r--r--crypto/test/src/asn1/test/AttributeTableUnitTest.cs151
-rw-r--r--crypto/test/src/asn1/test/BiometricDataUnitTest.cs133
-rw-r--r--crypto/test/src/asn1/test/BitStringConstantTester.cs25
-rw-r--r--crypto/test/src/asn1/test/BitStringTest.cs82
-rw-r--r--crypto/test/src/asn1/test/CMSTest.cs306
-rw-r--r--crypto/test/src/asn1/test/CertHashUnitTest.cs93
-rw-r--r--crypto/test/src/asn1/test/CertificateTest.cs395
-rw-r--r--crypto/test/src/asn1/test/CommitmentTypeIndicationUnitTest.cs107
-rw-r--r--crypto/test/src/asn1/test/CommitmentTypeQualifierUnitTest.cs107
-rw-r--r--crypto/test/src/asn1/test/ContentHintsUnitTest.cs93
-rw-r--r--crypto/test/src/asn1/test/CscaMasterListTest.cs57
-rw-r--r--crypto/test/src/asn1/test/DERApplicationSpecificTest.cs88
-rw-r--r--crypto/test/src/asn1/test/DERUTF8StringTest.cs113
-rw-r--r--crypto/test/src/asn1/test/DataGroupHashUnitTest.cs106
-rw-r--r--crypto/test/src/asn1/test/DeclarationOfMajorityUnitTest.cs97
-rw-r--r--crypto/test/src/asn1/test/EncryptedPrivateKeyInfoTest.cs152
-rw-r--r--crypto/test/src/asn1/test/EnumeratedTest.cs115
-rw-r--r--crypto/test/src/asn1/test/EqualsAndHashCodeTest.cs93
-rw-r--r--crypto/test/src/asn1/test/EssCertIDv2UnitTest.cs46
-rw-r--r--crypto/test/src/asn1/test/GeneralNameTest.cs116
-rw-r--r--crypto/test/src/asn1/test/GeneralizedTimeTest.cs231
-rw-r--r--crypto/test/src/asn1/test/GenerationTest.cs325
-rw-r--r--crypto/test/src/asn1/test/InputStreamTest.cs85
-rw-r--r--crypto/test/src/asn1/test/Iso4217CurrencyCodeUnitTest.cs156
-rw-r--r--crypto/test/src/asn1/test/IssuingDistributionPointTest.cs133
-rw-r--r--crypto/test/src/asn1/test/KeyUsageTest.cs49
-rw-r--r--crypto/test/src/asn1/test/LDSSecurityObjectUnitTest.cs208
-rw-r--r--crypto/test/src/asn1/test/MiscTest.cs94
-rw-r--r--crypto/test/src/asn1/test/MonetaryLimitUnitTest.cs93
-rw-r--r--crypto/test/src/asn1/test/MonetaryValueUnitTest.cs99
-rw-r--r--crypto/test/src/asn1/test/NameOrPseudonymUnitTest.cs114
-rw-r--r--crypto/test/src/asn1/test/NamingAuthorityUnitTest.cs106
-rw-r--r--crypto/test/src/asn1/test/NetscapeCertTypeTest.cs45
-rw-r--r--crypto/test/src/asn1/test/OCSPTest.cs183
-rw-r--r--crypto/test/src/asn1/test/OIDTest.cs149
-rw-r--r--crypto/test/src/asn1/test/OctetStringTest.cs186
-rw-r--r--crypto/test/src/asn1/test/OtherCertIDUnitTest.cs100
-rw-r--r--crypto/test/src/asn1/test/OtherSigningCertificateUnitTest.cs94
-rw-r--r--crypto/test/src/asn1/test/PKCS10Test.cs95
-rw-r--r--crypto/test/src/asn1/test/PKCS12Test.cs210
-rw-r--r--crypto/test/src/asn1/test/PKIFailureInfoTest.cs76
-rw-r--r--crypto/test/src/asn1/test/ParseTest.cs303
-rw-r--r--crypto/test/src/asn1/test/ParsingTest.cs104
-rw-r--r--crypto/test/src/asn1/test/PersonalDataUnitTest.cs127
-rw-r--r--crypto/test/src/asn1/test/ProcurationSyntaxUnitTest.cs111
-rw-r--r--crypto/test/src/asn1/test/ProfessionInfoUnitTest.cs121
-rw-r--r--crypto/test/src/asn1/test/QCStatementUnitTest.cs108
-rw-r--r--crypto/test/src/asn1/test/ReasonFlagsTest.cs46
-rw-r--r--crypto/test/src/asn1/test/RegressionTest.cs85
-rw-r--r--crypto/test/src/asn1/test/RequestedCertificateUnitTest.cs117
-rw-r--r--crypto/test/src/asn1/test/RestrictionUnitTest.cs78
-rw-r--r--crypto/test/src/asn1/test/SMIMETest.cs90
-rw-r--r--crypto/test/src/asn1/test/SemanticsInformationUnitTest.cs138
-rw-r--r--crypto/test/src/asn1/test/SetTest.cs117
-rw-r--r--crypto/test/src/asn1/test/SignerLocationUnitTest.cs195
-rw-r--r--crypto/test/src/asn1/test/StringTest.cs105
-rw-r--r--crypto/test/src/asn1/test/SubjectKeyIdentifierTest.cs61
-rw-r--r--crypto/test/src/asn1/test/TagTest.cs115
-rw-r--r--crypto/test/src/asn1/test/TargetInformationTest.cs58
-rw-r--r--crypto/test/src/asn1/test/TimeTest.cs28
-rw-r--r--crypto/test/src/asn1/test/TypeOfBiometricDataUnitTest.cs152
-rw-r--r--crypto/test/src/asn1/test/UTCTimeTest.cs122
-rw-r--r--crypto/test/src/asn1/test/X509ExtensionsTest.cs117
-rw-r--r--crypto/test/src/asn1/test/X509NameTest.cs674
-rw-r--r--crypto/test/src/asn1/test/X9Test.cs168
-rw-r--r--crypto/test/src/cms/test/AllTests.cs35
-rw-r--r--crypto/test/src/cms/test/AuthenticatedDataStreamTest.cs113
-rw-r--r--crypto/test/src/cms/test/AuthenticatedDataTest.cs320
-rw-r--r--crypto/test/src/cms/test/CMSSampleMessages.cs147
-rw-r--r--crypto/test/src/cms/test/CMSTestUtil.cs480
-rw-r--r--crypto/test/src/cms/test/CompressedDataStreamTest.cs116
-rw-r--r--crypto/test/src/cms/test/CompressedDataTest.cs117
-rw-r--r--crypto/test/src/cms/test/EnvelopedDataStreamTest.cs537
-rw-r--r--crypto/test/src/cms/test/EnvelopedDataTest.cs866
-rw-r--r--crypto/test/src/cms/test/MiscDataStreamTest.cs221
-rw-r--r--crypto/test/src/cms/test/Rfc4134Test.cs344
-rw-r--r--crypto/test/src/cms/test/SignedDataStreamTest.cs1235
-rw-r--r--crypto/test/src/cms/test/SignedDataTest.cs1480
-rw-r--r--crypto/test/src/crypto/examples/DESExample.cs396
-rw-r--r--crypto/test/src/crypto/io/test/AllTests.cs27
-rw-r--r--crypto/test/src/crypto/io/test/CipherStreamTest.cs166
-rw-r--r--crypto/test/src/crypto/test/AESFastTest.cs168
-rw-r--r--crypto/test/src/crypto/test/AESLightTest.cs168
-rw-r--r--crypto/test/src/crypto/test/AESTest.cs178
-rw-r--r--crypto/test/src/crypto/test/AESWrapTest.cs214
-rw-r--r--crypto/test/src/crypto/test/AeadTestUtilities.cs14
-rw-r--r--crypto/test/src/crypto/test/AllTests.cs47
-rw-r--r--crypto/test/src/crypto/test/BlockCipherMonteCarloTest.cs83
-rw-r--r--crypto/test/src/crypto/test/BlockCipherVectorTest.cs75
-rw-r--r--crypto/test/src/crypto/test/BlowfishTest.cs55
-rw-r--r--crypto/test/src/crypto/test/CAST6Test.cs57
-rw-r--r--crypto/test/src/crypto/test/CCMTest.cs268
-rw-r--r--crypto/test/src/crypto/test/CMacTest.cs302
-rw-r--r--crypto/test/src/crypto/test/CTSTest.cs192
-rw-r--r--crypto/test/src/crypto/test/CamelliaLightTest.cs80
-rw-r--r--crypto/test/src/crypto/test/CamelliaTest.cs80
-rw-r--r--crypto/test/src/crypto/test/Cast5Test.cs49
-rw-r--r--crypto/test/src/crypto/test/ChaChaTest.cs319
-rw-r--r--crypto/test/src/crypto/test/CipherTest.cs117
-rw-r--r--crypto/test/src/crypto/test/DESTest.cs214
-rw-r--r--crypto/test/src/crypto/test/DESedeTest.cs187
-rw-r--r--crypto/test/src/crypto/test/DHKEKGeneratorTest.cs79
-rw-r--r--crypto/test/src/crypto/test/DHTest.cs403
-rw-r--r--crypto/test/src/crypto/test/DSATest.cs615
-rw-r--r--crypto/test/src/crypto/test/DeterministicDSATest.cs511
-rw-r--r--crypto/test/src/crypto/test/DigestRandomNumberTest.cs163
-rw-r--r--crypto/test/src/crypto/test/DigestTest.cs183
-rw-r--r--crypto/test/src/crypto/test/EAXTest.cs352
-rw-r--r--crypto/test/src/crypto/test/ECDHKEKGeneratorTest.cs80
-rw-r--r--crypto/test/src/crypto/test/ECGOST3410Test.cs345
-rw-r--r--crypto/test/src/crypto/test/ECIESTest.cs252
-rw-r--r--crypto/test/src/crypto/test/ECNRTest.cs118
-rw-r--r--crypto/test/src/crypto/test/ECTest.cs932
-rw-r--r--crypto/test/src/crypto/test/ElGamalTest.cs278
-rw-r--r--crypto/test/src/crypto/test/EqualsHashCodeTest.cs262
-rw-r--r--crypto/test/src/crypto/test/GCMTest.cs711
-rw-r--r--crypto/test/src/crypto/test/GMacTest.cs187
-rw-r--r--crypto/test/src/crypto/test/GOST28147MacTest.cs105
-rw-r--r--crypto/test/src/crypto/test/GOST28147Test.cs334
-rw-r--r--crypto/test/src/crypto/test/GOST3410Test.cs1604
-rw-r--r--crypto/test/src/crypto/test/GOST3411DigestTest.cs79
-rw-r--r--crypto/test/src/crypto/test/GcmReorderTest.cs362
-rw-r--r--crypto/test/src/crypto/test/HCFamilyTest.cs192
-rw-r--r--crypto/test/src/crypto/test/HCFamilyVecTest.cs184
-rw-r--r--crypto/test/src/crypto/test/IDEATest.cs53
-rw-r--r--crypto/test/src/crypto/test/ISAACTest.cs196
-rw-r--r--crypto/test/src/crypto/test/ISO9796Test.cs961
-rw-r--r--crypto/test/src/crypto/test/ISO9797Alg3MacTest.cs99
-rw-r--r--crypto/test/src/crypto/test/KDF1GeneratorTest.cs103
-rw-r--r--crypto/test/src/crypto/test/KDF2GeneratorTest.cs115
-rw-r--r--crypto/test/src/crypto/test/MD2DigestTest.cs67
-rw-r--r--crypto/test/src/crypto/test/MD4DigestTest.cs59
-rw-r--r--crypto/test/src/crypto/test/MD5DigestTest.cs59
-rw-r--r--crypto/test/src/crypto/test/MD5HMacTest.cs91
-rw-r--r--crypto/test/src/crypto/test/MGF1GeneratorTest.cs103
-rw-r--r--crypto/test/src/crypto/test/MacTest.cs214
-rw-r--r--crypto/test/src/crypto/test/ModeTest.cs108
-rw-r--r--crypto/test/src/crypto/test/NaccacheSternTest.cs354
-rw-r--r--crypto/test/src/crypto/test/NoekeonTest.cs59
-rw-r--r--crypto/test/src/crypto/test/NullTest.cs88
-rw-r--r--crypto/test/src/crypto/test/OAEPTest.cs798
-rw-r--r--crypto/test/src/crypto/test/OCBTest.cs515
-rw-r--r--crypto/test/src/crypto/test/PSSBlindTest.cs399
-rw-r--r--crypto/test/src/crypto/test/PSSTest.cs338
-rw-r--r--crypto/test/src/crypto/test/PaddingTest.cs171
-rw-r--r--crypto/test/src/crypto/test/Pkcs12Test.cs101
-rw-r--r--crypto/test/src/crypto/test/Pkcs5Test.cs243
-rw-r--r--crypto/test/src/crypto/test/Poly1305Test.cs395
-rw-r--r--crypto/test/src/crypto/test/RC2Test.cs58
-rw-r--r--crypto/test/src/crypto/test/RC2WrapTest.cs123
-rw-r--r--crypto/test/src/crypto/test/RC4Test.cs59
-rw-r--r--crypto/test/src/crypto/test/RC5Test.cs201
-rw-r--r--crypto/test/src/crypto/test/RC6Test.cs54
-rw-r--r--crypto/test/src/crypto/test/RFC3211WrapTest.cs216
-rw-r--r--crypto/test/src/crypto/test/RSABlindedTest.cs449
-rw-r--r--crypto/test/src/crypto/test/RegressionTest.cs135
-rw-r--r--crypto/test/src/crypto/test/RijndaelTest.cs135
-rw-r--r--crypto/test/src/crypto/test/RipeMD128DigestTest.cs74
-rw-r--r--crypto/test/src/crypto/test/RipeMD128HMacTest.cs100
-rw-r--r--crypto/test/src/crypto/test/RipeMD160DigestTest.cs74
-rw-r--r--crypto/test/src/crypto/test/RipeMD160HMacTest.cs102
-rw-r--r--crypto/test/src/crypto/test/RipeMD256DigestTest.cs74
-rw-r--r--crypto/test/src/crypto/test/RipeMD320DigestTest.cs74
-rw-r--r--crypto/test/src/crypto/test/RsaTest.cs596
-rw-r--r--crypto/test/src/crypto/test/SCryptTest.cs103
-rw-r--r--crypto/test/src/crypto/test/SEEDTest.cs65
-rw-r--r--crypto/test/src/crypto/test/SHA1DigestTest.cs57
-rw-r--r--crypto/test/src/crypto/test/SHA1HMacTest.cs93
-rw-r--r--crypto/test/src/crypto/test/SHA224DigestTest.cs70
-rw-r--r--crypto/test/src/crypto/test/SHA224HMacTest.cs122
-rw-r--r--crypto/test/src/crypto/test/SHA256DigestTest.cs71
-rw-r--r--crypto/test/src/crypto/test/SHA256HMacTest.cs122
-rw-r--r--crypto/test/src/crypto/test/SHA384DigestTest.cs70
-rw-r--r--crypto/test/src/crypto/test/SHA384HMacTest.cs122
-rw-r--r--crypto/test/src/crypto/test/SHA3DigestTest.cs374
-rw-r--r--crypto/test/src/crypto/test/SHA512DigestTest.cs70
-rw-r--r--crypto/test/src/crypto/test/SHA512HMacTest.cs123
-rw-r--r--crypto/test/src/crypto/test/SHA512t224DigestTest.cs62
-rw-r--r--crypto/test/src/crypto/test/SHA512t256DigestTest.cs62
-rw-r--r--crypto/test/src/crypto/test/SM3DigestTest.cs74
-rw-r--r--crypto/test/src/crypto/test/SRP6Test.cs300
-rw-r--r--crypto/test/src/crypto/test/Salsa20Test.cs318
-rw-r--r--crypto/test/src/crypto/test/SerpentTest.cs119
-rw-r--r--crypto/test/src/crypto/test/ShortenedDigestTest.cs98
-rw-r--r--crypto/test/src/crypto/test/SipHashTest.cs156
-rw-r--r--crypto/test/src/crypto/test/SkeinDigestTest.cs303
-rw-r--r--crypto/test/src/crypto/test/SkeinMacTest.cs174
-rw-r--r--crypto/test/src/crypto/test/SkipjackTest.cs46
-rw-r--r--crypto/test/src/crypto/test/StreamCipherVectorTest.cs68
-rw-r--r--crypto/test/src/crypto/test/TEATest.cs59
-rw-r--r--crypto/test/src/crypto/test/Threefish1024Test.cs74
-rw-r--r--crypto/test/src/crypto/test/Threefish256Test.cs59
-rw-r--r--crypto/test/src/crypto/test/Threefish512Test.cs64
-rw-r--r--crypto/test/src/crypto/test/TigerDigestTest.cs82
-rw-r--r--crypto/test/src/crypto/test/TwofishTest.cs54
-rw-r--r--crypto/test/src/crypto/test/VMPCKSA3Test.cs112
-rw-r--r--crypto/test/src/crypto/test/VMPCMacTest.cs68
-rw-r--r--crypto/test/src/crypto/test/VMPCTest.cs112
-rw-r--r--crypto/test/src/crypto/test/WhirlpoolDigestTest.cs119
-rw-r--r--crypto/test/src/crypto/test/XSalsa20Test.cs183
-rw-r--r--crypto/test/src/crypto/test/XTEATest.cs59
-rw-r--r--crypto/test/src/crypto/tls/test/MockTlsClient.cs158
-rw-r--r--crypto/test/src/crypto/tls/test/MockTlsServer.cs137
-rw-r--r--crypto/test/src/crypto/tls/test/TlsClientTest.cs66
-rw-r--r--crypto/test/src/crypto/tls/test/TlsServerTest.cs78
-rw-r--r--crypto/test/src/crypto/tls/test/TlsTestUtilities.cs138
-rw-r--r--crypto/test/src/math/ec/test/AllTests.cs28
-rw-r--r--crypto/test/src/math/ec/test/ECAlgorithmsTest.cs151
-rw-r--r--crypto/test/src/math/ec/test/ECPointPerformanceTest.cs209
-rw-r--r--crypto/test/src/math/ec/test/ECPointTest.cs507
-rw-r--r--crypto/test/src/math/ec/test/F2mProofer.cs201
-rw-r--r--crypto/test/src/math/ec/test/TnafTest.cs158
-rw-r--r--crypto/test/src/math/test/AllTests.cs27
-rw-r--r--crypto/test/src/math/test/BigIntegerTest.cs1048
-rw-r--r--crypto/test/src/ocsp/test/AllTests.cs29
-rw-r--r--crypto/test/src/ocsp/test/OCSPTest.cs852
-rw-r--r--crypto/test/src/ocsp/test/OCSPTestUtil.cs147
-rw-r--r--crypto/test/src/openpgp/examples/ByteArrayHandler.cs195
-rw-r--r--crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs375
-rw-r--r--crypto/test/src/openpgp/examples/DetachedSignatureProcessor.cs167
-rw-r--r--crypto/test/src/openpgp/examples/DirectKeySignature.cs140
-rw-r--r--crypto/test/src/openpgp/examples/DsaElGamalKeyRingGenerator.cs134
-rw-r--r--crypto/test/src/openpgp/examples/KeyBasedFileProcessor.cs259
-rw-r--r--crypto/test/src/openpgp/examples/KeyBasedLargeFileProcessor.cs267
-rw-r--r--crypto/test/src/openpgp/examples/PbeFileProcessor.cs183
-rw-r--r--crypto/test/src/openpgp/examples/PgpExampleUtilities.cs123
-rw-r--r--crypto/test/src/openpgp/examples/PublicKeyRingDump.cs98
-rw-r--r--crypto/test/src/openpgp/examples/RsaKeyRingGenerator.cs115
-rw-r--r--crypto/test/src/openpgp/examples/SignedFileProcessor.cs188
-rw-r--r--crypto/test/src/openpgp/examples/test/AllTests.cs403
-rw-r--r--crypto/test/src/openpgp/test/DSA2Test.cs237
-rw-r--r--crypto/test/src/openpgp/test/PGPArmoredTest.cs265
-rw-r--r--crypto/test/src/openpgp/test/PGPClearSignedSignatureTest.cs445
-rw-r--r--crypto/test/src/openpgp/test/PGPCompressionTest.cs117
-rw-r--r--crypto/test/src/openpgp/test/PGPDSAElGamalTest.cs492
-rw-r--r--crypto/test/src/openpgp/test/PGPDSATest.cs597
-rw-r--r--crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs169
-rw-r--r--crypto/test/src/openpgp/test/PGPPBETest.cs384
-rw-r--r--crypto/test/src/openpgp/test/PGPPacketTest.cs80
-rw-r--r--crypto/test/src/openpgp/test/PGPRSATest.cs1233
-rw-r--r--crypto/test/src/openpgp/test/PGPSignatureTest.cs1045
-rw-r--r--crypto/test/src/openpgp/test/PgpKeyRingTest.cs2161
-rw-r--r--crypto/test/src/openpgp/test/PgpMarkerTest.cs102
-rw-r--r--crypto/test/src/openpgp/test/RegressionTest.cs35
-rw-r--r--crypto/test/src/openssl/test/AllTests.cs133
-rw-r--r--crypto/test/src/openssl/test/ReaderTest.cs379
-rw-r--r--crypto/test/src/openssl/test/WriterTest.cs185
-rw-r--r--crypto/test/src/pkcs/examples/PKCS12Example.cs386
-rw-r--r--crypto/test/src/pkcs/test/EncryptedPrivateKeyInfoTest.cs92
-rw-r--r--crypto/test/src/pkcs/test/PKCS10Test.cs88
-rw-r--r--crypto/test/src/pkcs/test/PKCS12StoreTest.cs921
-rw-r--r--crypto/test/src/security/test/SecureRandomTest.cs150
-rw-r--r--crypto/test/src/security/test/TestDigestUtil.cs63
-rw-r--r--crypto/test/src/security/test/TestDotNetUtil.cs88
-rw-r--r--crypto/test/src/security/test/TestEncodings.cs188
-rw-r--r--crypto/test/src/security/test/TestParameterUtil.cs74
-rw-r--r--crypto/test/src/security/test/TestSignerUtil.cs181
-rw-r--r--crypto/test/src/test/AESSICTest.cs147
-rw-r--r--crypto/test/src/test/AESTest.cs363
-rw-r--r--crypto/test/src/test/AttrCertSelectorTest.cs214
-rw-r--r--crypto/test/src/test/AttrCertTest.cs621
-rw-r--r--crypto/test/src/test/BaseBlockCipherTest.cs146
-rw-r--r--crypto/test/src/test/BlockCipherTest.cs972
-rw-r--r--crypto/test/src/test/CMacTest.cs276
-rw-r--r--crypto/test/src/test/CRL5Test.cs257
-rw-r--r--crypto/test/src/test/CamelliaTest.cs204
-rw-r--r--crypto/test/src/test/CertPathBuilderTest.cs163
-rw-r--r--crypto/test/src/test/CertPathTest.cs359
-rw-r--r--crypto/test/src/test/CertPathValidatorTest.cs304
-rw-r--r--crypto/test/src/test/CertTest.cs2544
-rw-r--r--crypto/test/src/test/CipherStreamTest.cs449
-rw-r--r--crypto/test/src/test/DESedeTest.cs298
-rw-r--r--crypto/test/src/test/DHTest.cs651
-rw-r--r--crypto/test/src/test/DSATest.cs888
-rw-r--r--crypto/test/src/test/DigestTest.cs175
-rw-r--r--crypto/test/src/test/ECDSA5Test.cs300
-rw-r--r--crypto/test/src/test/ECEncodingTest.cs243
-rw-r--r--crypto/test/src/test/ECNRTest.cs204
-rw-r--r--crypto/test/src/test/ElGamalTest.cs334
-rw-r--r--crypto/test/src/test/EncryptedPrivateKeyInfoTest.cs154
-rw-r--r--crypto/test/src/test/FIPSDESTest.cs205
-rw-r--r--crypto/test/src/test/GOST28147Test.cs245
-rw-r--r--crypto/test/src/test/GOST3410Test.cs380
-rw-r--r--crypto/test/src/test/HMacTest.cs189
-rw-r--r--crypto/test/src/test/IESTest.cs245
-rw-r--r--crypto/test/src/test/MacTest.cs216
-rw-r--r--crypto/test/src/test/MqvTest.cs99
-rw-r--r--crypto/test/src/test/NamedCurveTest.cs381
-rw-r--r--crypto/test/src/test/NistCertPathTest.cs5192
-rw-r--r--crypto/test/src/test/NoekeonTest.cs157
-rw-r--r--crypto/test/src/test/PBETest.cs527
-rw-r--r--crypto/test/src/test/PEMData.cs117
-rw-r--r--crypto/test/src/test/PKCS10CertRequestTest.cs470
-rw-r--r--crypto/test/src/test/PSSTest.cs253
-rw-r--r--crypto/test/src/test/PkixNameConstraintsTest.cs433
-rw-r--r--crypto/test/src/test/PkixPolicyMappingTest.cs419
-rw-r--r--crypto/test/src/test/PkixTest.cs248
-rw-r--r--crypto/test/src/test/RSATest.cs685
-rw-r--r--crypto/test/src/test/RegressionTest.cs80
-rw-r--r--crypto/test/src/test/SEEDTest.cs190
-rw-r--r--crypto/test/src/test/SigTest.cs378
-rw-r--r--crypto/test/src/test/TestUtilities.cs264
-rw-r--r--crypto/test/src/test/WrapTest.cs94
-rw-r--r--crypto/test/src/test/X509CertificatePairTest.cs149
-rw-r--r--crypto/test/src/test/X509StoreTest.cs335
-rw-r--r--crypto/test/src/test/nist/NistCertPathTest.cs847
-rw-r--r--crypto/test/src/test/rsa3/RSA3CertTest.cs127
-rw-r--r--crypto/test/src/tsp/test/AllTests.cs32
-rw-r--r--crypto/test/src/tsp/test/GenTimeAccuracyTest.cs116
-rw-r--r--crypto/test/src/tsp/test/ParseTest.cs396
-rw-r--r--crypto/test/src/tsp/test/TSPTest.cs548
-rw-r--r--crypto/test/src/tsp/test/TSPTestUtil.cs200
-rw-r--r--crypto/test/src/tsp/test/TimeStampTokenInfoTest.cs145
-rw-r--r--crypto/test/src/util/io/pem/test/AllTests.cs77
-rw-r--r--crypto/test/src/util/net/test/IPAddressTest.cs61
-rw-r--r--crypto/test/src/util/test/FixedSecureRandom.cs64
-rw-r--r--crypto/test/src/util/test/ITest.cs17
-rw-r--r--crypto/test/src/util/test/ITestResult.cs13
-rw-r--r--crypto/test/src/util/test/NumberParsing.cs40
-rw-r--r--crypto/test/src/util/test/SimpleTest.cs164
-rw-r--r--crypto/test/src/util/test/SimpleTestResult.cs91
-rw-r--r--crypto/test/src/util/test/TestFailedException.cs24
-rw-r--r--crypto/test/src/util/test/UncloseableStream.cs22
-rw-r--r--crypto/test/src/x509/test/TestCertificateGen.cs715
-rw-r--r--crypto/testcfg.nunit6
-rw-r--r--csharp.sln29
2465 files changed, 278105 insertions, 37914 deletions
diff --git a/.gitattributes b/.gitattributes
index 1ff0c4230..ba5445104 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,63 +1,37 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* text=auto
+# Set default behaviour, in case users don't have core.autocrlf set.
+*          text=auto
 
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs     diff=csharp
+# Explicitly declare text files we want to always be normalized and converted 
+# to native line endings on checkout.
+*.build    text diff=xml
+*.cs       text diff=csharp
+*.csproj   text diff=xml
+*.eml      text
+*.html     text diff=html
+*.mdp      text diff=xml
+*.mds      text diff=xml
+*.nunit    text diff=xml
+*.pem      text
+*.README   text
+*.sln      text
+*.txt      text
+*.xml      text diff=xml
 
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following 
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln       merge=binary
-#*.csproj    merge=binary
-#*.vbproj    merge=binary
-#*.vcxproj   merge=binary
-#*.vcproj    merge=binary
-#*.dbproj    merge=binary
-#*.fsproj    merge=binary
-#*.lsproj    merge=binary
-#*.wixproj   merge=binary
-#*.modelproj merge=binary
-#*.sqlproj   merge=binary
-#*.wwaproj   merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg   binary
-#*.png   binary
-#*.gif   binary
-
-###############################################################################
-# diff behavior for common document formats
-# 
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the 
-# entries below.
-###############################################################################
-#*.doc   diff=astextplain
-#*.DOC   diff=astextplain
-#*.docx  diff=astextplain
-#*.DOCX  diff=astextplain
-#*.dot   diff=astextplain
-#*.DOT   diff=astextplain
-#*.pdf   diff=astextplain
-#*.PDF   diff=astextplain
-#*.rtf   diff=astextplain
-#*.RTF   diff=astextplain
+# Denote all files that are truly binary and should not be modified.
+*.bin      binary
+*.cer      binary
+*.crl      binary
+*.crt      binary
+*.data     binary
+*.dsa      binary
+*.jpg      binary
+*.jpeg     binary
+*.key      binary
+*.p12      binary
+*.p7m      binary
+*.png      binary
+*.pri      binary
+*.pub      binary
+*.rsa      binary
+*.sec      binary
+*.sig      binary
diff --git a/.gitignore b/.gitignore
index e73852085..8bb56e9e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,154 +1,16 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
+*.psess
+*.snk
 *.suo
+*.swp
 *.user
-*.sln.docstates
-
-# Build results
-
-[Dd]ebug/
-[Rr]elease/
-x64/
-build/
-[Bb]in/
-[Oo]bj/
-
-# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
-#packages/*/build/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-*_i.c
-*_p.c
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.log
-*.scc
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opensdf
-*.sdf
-*.cachefile
-
-# Visual Studio profiler
-*.psess
 *.vsp
-*.vspx
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-*.ncrunch*
-.*crunch*.local.xml
-
-# Installshield output folder
-[Ee]xpress/
 
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.Publish.xml
-*.pubxml
-
-# NuGet Packages Directory
-## TODO: If you have NuGet Package Restore enabled, uncomment the next line
-packages/
-
-# Windows Azure Build Output
-csx
-*.build.csdef
-
-# Windows Store app package directory
-AppPackages/
-
-# Others
-sql/
-*.Cache
-ClientBin/
-[Ss]tyle[Cc]op.*
-~$*
-*~
-*.dbmdl
-*.[Pp]ublish.xml
-*.pfx
-*.publishsettings
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-App_Data/*.mdf
-App_Data/*.ldf
-
-# =========================
-# Windows detritus
-# =========================
-
-# Windows image file caches
-Thumbs.db
-ehthumbs.db
-
-# Folder config file
-Desktop.ini
-
-# Recycle Bin used on file shares
-$RECYCLE.BIN/
+*.nupkg
 
-# Mac crap
-.DS_Store
+Backup/
+bin/
+dist/
+doc/
+obj/
 
-*.nupkg
-*.db
+_Resharper.*/
diff --git a/FxCop/CustomDictionary.xml b/FxCop/CustomDictionary.xml
new file mode 100644
index 000000000..7f9080348
--- /dev/null
+++ b/FxCop/CustomDictionary.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8" ?> 
+<Dictionary>
+   <Words>
+      <Recognized>
+         <Word>Pgp</Word>
+         <Word>Pbe</Word>
+         <Word>Rsa</Word>
+         <Word>Dsa</Word>
+         <Word>Gamal</Word>
+         <Word>Aes</Word>
+         <Word>a</Word>
+         <Word>b</Word>
+         <Word>x</Word>
+         <Word>X</Word>
+         <Word>C</Word>
+         <Word>y</Word>
+         <Word>k</Word>
+         <Word>Y</Word>
+         <Word>p</Word>
+         <Word>q</Word>
+         <Word>P</Word>
+         <Word>n</Word>
+         <Word>m</Word>
+         <Word>e</Word>
+         <Word>g</Word>
+         <Word>d</Word>
+         <Word>r</Word>
+         <Word>s</Word>
+         <Word>t</Word>
+         <Word>v</Word>
+         <Word>str</Word>
+         <Word>tokenizer</Word>
+         <Word>oid</Word>
+         <Word>Bcpg</Word>
+         <Word>Sqrt</Word>
+         <Word>Pkcs</Word>
+         <Word>Asn1</Word>
+         <Word>Ber</Word>
+         <Word>Der</Word>
+         <Word>priv</Word>
+         <Word>Videotex</Word>
+         <Word>Subpacket</Word>
+         <Word>Subpackets</Word>
+         <Word>unhashed</Word>
+         <Word>Twofish</Word>
+         <Word>Paddings</Word>
+         <Word>dP</Word>
+         <Word>dQ</Word>
+         <Word>Tbc</Word>
+         <Word>Tpb</Word>
+         <Word>Gnb</Word>
+         <Word>Kdf</Word>
+         <Word>Diffie</Word>
+         <Word>Hellman</Word>
+         <Word>Ede</Word>
+         <Word>Cbc</Word>
+         <Word>Cfb</Word>
+         <Word>Cts</Word>
+         <Word>Ofb</Word>
+         <Word>Sha</Word>
+         <Word>Oaep</Word>
+         <Word>ies</Word>
+         <Word>mgf</Word>
+         <Word>Naccache</Word>
+         <Word>ccm</Word>
+         <Word>gcd</Word>
+         <Word>Alg</Word>
+         <Word>Oids</Word>
+         <Word>Params</Word>
+         <Word>Pkix</Word>
+         <Word>Pki</Word>
+         <Word>Etsi</Word>
+         <Word>Trus</Word>
+         <Word>Nist</Word>
+         <Word>Ecb</Word>
+         <Word>Cbc</Word>
+         <Word>Cfb</Word>
+         <Word>Ofb</Word>
+         <Word>Smime</Word>
+         <Word>Unotice</Word>
+         <Word>Cps</Word>
+         <Word>Tbs</Word>
+         <Word>spki</Word>
+         <Word>Crl</Word>
+         <Word>Oiw</Word>
+         <Word>Icao</Word>
+         <Word>Esf</Word>
+         <Word>Cmp</Word>
+         <Word>Pka</Word>
+         <Word>Crc</Word>
+         <Word>Infos</Word>
+         <Word>Ori</Word>
+         <Word>o</Word>
+         <Word>datagroup</Word>
+         <Word>gost</Word>
+         <Word>param</Word>
+         <Word>req</Word>
+         <Word>resp</Word>
+         <Word>tsa</Word>
+         <Word>tst</Word>
+      </Recognized>
+   </Words>
+   <Acronyms>
+      <CasingExceptions>
+         <Acronym>El</Acronym>
+         <Acronym>ECDH</Acronym>
+         <Acronym>ECDHC</Acronym>
+         <Acronym>ECNR</Acronym>
+         <Acronym>Fp</Acronym>
+         <Acronym>F2m</Acronym>
+         <Acronym>sBox</Acronym>
+         <Acronym>cL</Acronym>
+         <Acronym>Gn</Acronym>
+         <Acronym>Pp</Acronym>
+         <Acronym>Tp</Acronym>
+         <Acronym>Qt</Acronym>
+      </CasingExceptions>
+   </Acronyms>
+</Dictionary>
\ No newline at end of file
diff --git a/crypto-test/App.ico b/crypto-test/App.ico
new file mode 100644
index 000000000..3a5525fd7
--- /dev/null
+++ b/crypto-test/App.ico
Binary files differdiff --git a/crypto-test/CryptoTest.cs b/crypto-test/CryptoTest.cs
new file mode 100644
index 000000000..1f6973e28
--- /dev/null
+++ b/crypto-test/CryptoTest.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace crypto_test
+{
+	public class CryptoTest
+	{
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		[STAThread]
+		static void Main(string[] args)
+		{
+			DateTime before = DateTime.Now;
+
+			try
+			{
+				Org.BouncyCastle.Asn1.Tests.RegressionTest.Main(args);
+				//Org.BouncyCastle.Bcpg.OpenPgp.Tests.Dsa2Test.?
+				Org.BouncyCastle.Bcpg.OpenPgp.Tests.RegressionTest.Main(args);
+				Org.BouncyCastle.Bcpg.OpenPgp.Examples.Tests.AllTests.Main(args);
+				Org.BouncyCastle.Cms.Tests.AllTests.Main(args);
+				Org.BouncyCastle.Crypto.Tests.RegressionTest.Main(args);
+				Org.BouncyCastle.Crypto.IO.Tests.AllTests.Main(args);
+				Org.BouncyCastle.Math.Tests.AllTests.Main(args);
+				Org.BouncyCastle.Math.EC.Tests.AllTests.Main(args);
+				Org.BouncyCastle.Ocsp.Tests.AllTests.Main(args);
+				//Org.BouncyCastle.Pkcs.Tests.?
+				Org.BouncyCastle.Pkcs.Tests.EncryptedPrivateKeyInfoTest.Main(args);
+				Org.BouncyCastle.Pkcs.Tests.Pkcs10Test.Main(args);
+				Org.BouncyCastle.Pkcs.Tests.Pkcs12StoreTest.Main(args);
+				//Org.BouncyCastle.OpenSsl.Tests.?
+				Org.BouncyCastle.OpenSsl.Tests.ReaderTest.Main(args);
+				Org.BouncyCastle.OpenSsl.Tests.WriterTest.Main(args);
+				//Org.BouncyCastle.Security.Tests.?
+				Org.BouncyCastle.Tests.RegressionTest.Main(args);
+				Org.BouncyCastle.Tsp.Tests.AllTests.Main(args);
+				//Org.BouncyCastle.X509.Tests.?
+			}
+			catch (Exception e)
+			{
+				Console.WriteLine("Tests failed with exception: " + e.Message);
+				Console.WriteLine(e.StackTrace);
+			}
+
+			DateTime after = DateTime.Now;
+			long elapsedTicks = after.Ticks - before.Ticks;
+
+			Console.WriteLine("Done in {0}ms.", elapsedTicks / TimeSpan.TicksPerMillisecond);
+		}
+	}
+}
diff --git a/crypto-test/crypto-test.csproj b/crypto-test/crypto-test.csproj
new file mode 100644
index 000000000..9bb4cdbb9
--- /dev/null
+++ b/crypto-test/crypto-test.csproj
@@ -0,0 +1,104 @@
+<VisualStudioProject>
+    <CSHARP
+        ProjectType = "Local"
+        ProductVersion = "7.10.3077"
+        SchemaVersion = "2.0"
+        ProjectGuid = "{C857AD68-8F1B-4C7A-A76B-3DC03CBE4FB0}"
+    >
+        <Build>
+            <Settings
+                ApplicationIcon = "App.ico"
+                AssemblyKeyContainerName = ""
+                AssemblyName = "crypto-test"
+                AssemblyOriginatorKeyFile = ""
+                DefaultClientScript = "JScript"
+                DefaultHTMLPageLayout = "Grid"
+                DefaultTargetSchema = "IE50"
+                DelaySign = "false"
+                OutputType = "Exe"
+                PreBuildEvent = ""
+                PostBuildEvent = ""
+                RootNamespace = "crypto_test"
+                RunPostBuildEvent = "OnBuildSuccess"
+                StartupObject = ""
+            >
+                <Config
+                    Name = "Debug"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "DEBUG;TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "true"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "false"
+                    NoStdLib = "false"
+                    NoWarn = ""
+                    Optimize = "false"
+                    OutputPath = "bin\Debug\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+                <Config
+                    Name = "Release"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "TRACE"
+                    DocumentationFile = ""
+                    DebugSymbols = "false"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "false"
+                    NoStdLib = "false"
+                    NoWarn = ""
+                    Optimize = "true"
+                    OutputPath = "bin\Release\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+            </Settings>
+            <References>
+                <Reference
+                    Name = "System"
+                    AssemblyName = "System"
+                    HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll"
+                />
+                <Reference
+                    Name = "System.Data"
+                    AssemblyName = "System.Data"
+                    HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
+                />
+                <Reference
+                    Name = "System.XML"
+                    AssemblyName = "System.Xml"
+                    HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
+                />
+                <Reference
+                    Name = "crypto"
+                    Project = "{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}"
+                    Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+                />
+            </References>
+        </Build>
+        <Files>
+            <Include>
+                <File
+                    RelPath = "App.ico"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "CryptoTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+            </Include>
+        </Files>
+    </CSHARP>
+</VisualStudioProject>
+
diff --git a/crypto/Contributors.html b/crypto/Contributors.html
index b37af312f..68ca699cf 100644
--- a/crypto/Contributors.html
+++ b/crypto/Contributors.html
@@ -111,6 +111,12 @@
 			<li>
 				<p>Laszlo Magyar &lt;lmagyar1973&#064gmail.com&gt; - patch to fix problem with SubjectDirectoryAttributes constructor.</p>
 			</li>
+			<li>
+				<p>Tim Whittington (https://github.com/timw) - ports of ChaCha, GMAC, Memoable, Poly1305, Skein, SM3, Threefish, XSalsa20. Registerised Salsa20 core.</p>
+			</li>
+			<li>
+				<p>Oscar Jacobsson (https://github.com/OscarAyoy) - patch to fix DerEnumerated constructor (including test coverage).</p>
+			</li>
 		</ul>
 	</body>
 </html>
diff --git a/crypto/License.html b/crypto/License.html
index 0dae3a978..1c5c7b0ec 100644
--- a/crypto/License.html
+++ b/crypto/License.html
@@ -9,7 +9,7 @@
 <h2>The Bouncy Castle Cryptographic C#&reg; API</h2>
 <h3>License:</h3>
 The Bouncy Castle License<br>
-Copyright (c) 2000-2011 The Legion Of The Bouncy Castle
+Copyright (c) 2000-2014 The Legion of the Bouncy Castle Inc.
 (http://www.bouncycastle.org)<br>
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"), to deal in the
diff --git a/crypto/NBuild.build b/crypto/NBuild.build
new file mode 100644
index 000000000..e22c35df9
--- /dev/null
+++ b/crypto/NBuild.build
@@ -0,0 +1,247 @@
+<?xml version="1.0"?>
+<project name="bccrypto-csharp" default="compile-release" basedir=".">
+
+  <!-- Source control properties -->
+  <property name="GITURL" value="bcgit@git.bouncycastle.org:bc-csharp" />
+  <property name="GITCMD" value="C:/Program Files (x86)/Git/bin/git.exe" />
+
+  <property name="api-debugpath" value="./api/bin/debug" />
+  <property name="api-releasepath" value="./api/bin/release" />
+  <property name="api-srcpath" value="./src" />
+  <property name="bzip2-srcpath" value="./bzip2/src" />
+  <property name="test-srcpath" value="./test/src" />
+  <property name="test-datapath" value="./test/data" />
+  <property name="test-libpath" value="./test/lib" />
+  <property name="test-binpath" value="./test/bin"/>
+  <property name="dist-path" value="./dist"/>
+
+  <!-- Version -->
+  <property name="version" value="1.8.0-beta.4"/>
+  <property name="name" value="BouncyCastle.Crypto"/>
+
+  <property name="OPTIONAL_STRONG_NAME" value="" />
+  <if test="${property::exists('use-strong-name') and use-strong-name}">
+    <echo>Compile targets will be signed using keyfile ../BouncyCastle.snk</echo>
+    <property name="OPTIONAL_STRONG_NAME" value=";STRONG_NAME" />
+  </if>
+
+  <target name="init">
+    <call target="set-framework-props" />
+  </target>
+
+  <target name="set-framework-props">
+    <if test="${not(target::exists('set-'+framework::get-target-framework()+'-framework-props'))}">
+      <fail message="Unsupported framework: '${framework::get-target-framework()}'." />
+    </if>
+    <call target="set-${framework::get-target-framework()}-framework-props" />
+  </target>
+  <target name="set-mono-1.0-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="dll.mdb" />
+    <property name="enable-nostdlib" value="false" />
+    <property name="nunit-console" value="nunit-console" />
+    <property name="switch" value="-" />
+  </target>
+  <target name="set-mono-2.0-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="dll.mdb" />
+    <property name="enable-nostdlib" value="false" />
+    <property name="nunit-console" value="nunit-console" />
+    <property name="switch" value="-" />
+  </target>
+  <target name="set-mono-3.5-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="dll.mdb" />
+    <property name="enable-nostdlib" value="false" />
+    <property name="nunit-console" value="nunit-console" />
+    <property name="switch" value="-" />
+  </target>
+  <target name="set-mono-4.0-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="dll.mdb" />
+    <property name="enable-nostdlib" value="false" />
+    <property name="nunit-console" value="nunit-console" />
+    <property name="switch" value="-" />
+  </target>
+  <target name="set-net-1.1-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-net-2.0-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-net-3.5-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-net-4.0-framework-props">
+    <property name="compile-defines" value="NET_1_1" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-netcf-1.0-framework-props">
+    <property name="compile-defines" value="NETCF_1_0" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-netcf-2.0-framework-props">
+    <property name="compile-defines" value="NETCF_2_0" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-silverlight-2.0-framework-props">
+    <property name="compile-defines" value="SILVERLIGHT" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-silverlight-3.0-framework-props">
+    <property name="compile-defines" value="SILVERLIGHT" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+  <target name="set-silverlight-4.0-framework-props">
+    <property name="compile-defines" value="SILVERLIGHT" />
+    <property name="debug-extension" value="pdb" />
+    <property name="enable-nostdlib" value="true" />
+    <property name="nunit-console" value="nunit-console.exe" />
+    <property name="switch" value="/" />
+  </target>
+
+  <target name="clean">
+    <delete failonerror="false" dir="./api" />
+    <delete failonerror="false" dir="${dist-path}" />
+    <delete failonerror="false" dir="${test-binpath}" />
+    <delete failonerror="false" file="./TestResult.xml" />
+  </target>
+
+  <!-- Compile api in debug mode and compile tests -->
+  <target name="compile-debug" depends="init">
+    <echo message="Compiling Debug"/>
+    <echo message="Compiling API in debug mode."/>
+    <mkdir dir="${api-debugpath}"/>
+    <csc target="library" noconfig="true" nostdlib="${enable-nostdlib}" output="${api-debugpath}/${name}.dll"
+      verbose="false" debug="true" define="${compile-defines}${OPTIONAL_STRONG_NAME}">
+      <sources>
+        <include name="${api-srcpath}/**/*.cs"/>
+        <include name="${bzip2-srcpath}/**/*.cs"/>
+      </sources>
+      <references>
+        <include name="mscorlib.dll"/>
+        <include name="System.dll"/>
+      </references>
+    </csc>
+
+    <copy todir="${test-binpath}">
+      <fileset basedir="${test-libpath}">
+        <include name="*.dll" />
+      </fileset>
+    </copy>
+    <copy file="${api-debugpath}/${name}.dll" tofile="${test-binpath}/${name}.dll" />
+    <copy file="${api-debugpath}/${name}.${debug-extension}"
+        tofile="${test-binpath}/${name}.${debug-extension}" />
+
+    <echo message="Compiling Tests."/>
+    <mkdir dir="${api-debugpath}"/>
+    <csc target="library" noconfig="true" nostdlib="${enable-nostdlib}" output="${test-binpath}/BCTest.dll"
+      verbose="false" debug="true" define="${compile-defines}${OPTIONAL_STRONG_NAME}">
+      <sources>
+        <include name="${test-srcpath}/**/*.cs"/>
+      </sources>
+      <resources prefix="crypto" dynamicprefix="true">
+        <include name="${test-datapath}/**/*.*"/>
+        <exclude name="${test-datapath}/**/README.txt"/>
+        <exclude name="${test-datapath}/tls/*.tmpl"/>
+      </resources>
+      <references>
+        <include name="mscorlib.dll"/>
+        <include name="System.dll"/>
+        <include name="${test-libpath}/*.dll"/>
+        <include name="${test-binpath}/${name}.dll"/>
+      </references>
+    </csc>
+  </target>
+
+  <!-- Compile Release.-->
+  <target name="compile-release" depends="init">
+    <echo message="Compiling Release"/>
+    <echo message="Compiling API in release mode."/>
+    <mkdir dir="${api-releasepath}"/>
+    <csc target="library" noconfig="true" nostdlib="${enable-nostdlib}" output="${api-releasepath}/${name}.dll"
+      verbose="false" debug="false" optimize="true" define="${compile-defines}${OPTIONAL_STRONG_NAME}">
+      <sources>
+        <include name="${api-srcpath}/**/*.cs"/>
+        <include name="${bzip2-srcpath}/**/*.cs"/>
+      </sources>
+      <references>
+        <include name="mscorlib.dll"/>
+        <include name="System.dll"/>
+      </references>
+    </csc>
+  </target>
+
+  <!-- Make distribution.-->
+  <target name="dist" depends="init">
+    <echo message="Building signed assemblies for release ${version}"/>
+    <mkdir dir="${dist-path}"/>
+
+    <exec program="${GITCMD}" verbose="true" workingdir="..">
+      <arg value="archive" />
+      <arg line="--format zip" />
+      <arg value="--output" />
+      <arg path="${dist-path}/bccrypto-csharp-${version}-src.zip" />
+      <arg value="--prefix" />
+      <arg value="bccrypto-csharp-${version}/" />
+      <arg value="--remote" />
+      <arg value="${GITURL}" />
+      <arg value="release-${version}" />
+      <arg value="-9" />
+    </exec>
+
+    <unzip zipfile="${dist-path}/bccrypto-csharp-${version}-src.zip" todir="${dist-path}/src" />
+
+    <csc target="library" noconfig="true" nostdlib="${enable-nostdlib}" output="${dist-path}/${name}.dll"
+      verbose="false" debug="false" optimize="true" define="${compile-defines};STRONG_NAME">
+      <sources>
+        <include name="${dist-path}/src/bccrypto-csharp-${version}/crypto/${api-srcpath}/**/*.cs"/>
+        <include name="${dist-path}/src/bccrypto-csharp-${version}/crypto/${bzip2-srcpath}/**/*.cs"/>
+      </sources>
+      <references>
+        <include name="mscorlib.dll"/>
+        <include name="System.dll"/>
+      </references>
+    </csc>
+    <zip zipfile="${dist-path}/bccrypto-csharp-${version}-bin.zip" ziplevel="9">
+      <fileset basedir="${dist-path}">
+        <include name="${name}.dll" />
+      </fileset>
+    </zip>
+
+  </target>
+
+  <target name="all" depends="compile-debug, compile-release"/>
+
+  <target name="test" depends="compile-debug">
+    <exec program="${nunit-console}" commandline="${switch}labels testcfg.nunit" workingdir="${nant.project.basedir}"></exec>
+  </target>
+
+</project>
diff --git a/crypto/Readme.html b/crypto/Readme.html
index afa75e882..2660d4ac3 100644
--- a/crypto/Readme.html
+++ b/crypto/Readme.html
@@ -75,7 +75,7 @@
 			X.509: Generators and parsers for V1 and V3 certificates, V2 CRLs and attribute 
 			certificates.
 			<li>
-			PBE algorithms supported by PBEUtil: PBEwithMD2andDES-CBC, 
+			PBE algorithms supported by PbeUtilities: PBEwithMD2andDES-CBC, 
 			PBEwithMD2andRC2-CBC, PBEwithMD5andDES-CBC, PBEwithMD5andRC2-CBC, 
 			PBEwithSHA1andDES-CBC, PBEwithSHA1andRC2-CBC, PBEwithSHA-1and128bitRC4, 
 			PBEwithSHA-1and40bitRC4, PBEwithSHA-1and3-keyDESEDE-CBC, 
@@ -112,7 +112,7 @@
 			<li>
 			Key Agreement: Diffie-Hellman, EC-DH, SRP-6a.
 			<li>
-			Macs: CBCBlockCipher, CFBBlockCipher, GOST28147, HMac, ISO9797 Alg. 3, and VMPCMAC.
+			Macs: CBCBlockCipher, CFBBlockCipher, GOST28147, HMac, ISO9797 Alg. 3, SipHash, VMPCMAC.
 			<li>
 			PBE generators: PKCS-12, and PKCS-5 - schemes 1 and 2.
 			<li>
diff --git a/crypto/bzip2/src/BZip2Constants.cs b/crypto/bzip2/src/BZip2Constants.cs
new file mode 100644
index 000000000..4a5442d8b
--- /dev/null
+++ b/crypto/bzip2/src/BZip2Constants.cs
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle, Aftex Software
+ * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+using System;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+    /**
+    * Base class for both the compress and decompress classes.
+    * Holds common arrays, and static data.
+    *
+    * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+    */
+    public class BZip2Constants {
+
+        public const int baseBlockSize = 100000;
+        public const int MAX_ALPHA_SIZE = 258;
+        public const int MAX_CODE_LEN = 23;
+        public const int RUNA = 0;
+        public const int RUNB = 1;
+        public const int N_GROUPS = 6;
+        public const int G_SIZE = 50;
+        public const int N_ITERS = 4;
+        public const int MAX_SELECTORS = (2 + (900000 / G_SIZE));
+        public const int NUM_OVERSHOOT_BYTES = 20;
+
+        public static readonly int[] rNums = {
+            619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+            985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+            733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+            419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+            878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+            862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+            150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+            170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+            73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+            909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+            641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+            161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+            382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+            98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+            227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+            469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+            184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+            715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+            951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+            652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+            645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+            609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+            653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+            411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+            170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+            857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+            669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+            944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+            344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+            897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+            433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+            686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+            946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+            978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+            680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+            707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+            297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+            134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+            343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+            140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+            170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+            369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+            804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+            896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+            661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+            768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+            61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+            372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+            780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+            920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+            645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+            936, 638
+        };
+    }
+}
\ No newline at end of file
diff --git a/crypto/bzip2/src/CBZip2InputStream.cs b/crypto/bzip2/src/CBZip2InputStream.cs
index 7411f0a21..7efb3b3ab 100644
--- a/crypto/bzip2/src/CBZip2InputStream.cs
+++ b/crypto/bzip2/src/CBZip2InputStream.cs
@@ -289,7 +289,7 @@ namespace Org.BouncyCastle.Apache.Bzip2
 		private void BsFinishedWithStream() {
             try {
                 if (this.bsStream != null) {
-                    this.bsStream.Dispose();
+                    this.bsStream.Close();
                     this.bsStream = null;
                 }
             } catch {
diff --git a/crypto/bzip2/src/CBZip2OutputStream.cs b/crypto/bzip2/src/CBZip2OutputStream.cs
index 2c6bed1df..bf43a6a6c 100644
--- a/crypto/bzip2/src/CBZip2OutputStream.cs
+++ b/crypto/bzip2/src/CBZip2OutputStream.cs
@@ -384,21 +384,16 @@ namespace Org.BouncyCastle.Apache.Bzip2
 //            Close();
 //        }
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                if (closed)
-                {
-                    return;
-                }
+        public override void Close() {
+            if (closed) {
+                return;
+            }
 
-                Finish();
+            Finish();
 
-                closed = true;
-                base.Dispose(disposing);
-                bsStream.Dispose();
-            }
+            closed = true;
+            base.Close();
+            bsStream.Close();
         }
 
         public void Finish() {
diff --git a/crypto/bzip2/src/CRC.cs b/crypto/bzip2/src/CRC.cs
new file mode 100644
index 000000000..278a9f336
--- /dev/null
+++ b/crypto/bzip2/src/CRC.cs
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ */
+
+/*
+ * This package is based on the work done by Keiron Liddle), Aftex Software
+ * <keiron@aftexsw.com> to whom the Ant project is very grateful for his
+ * great code.
+ */
+
+using System;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+	/**
+    * A simple class the hold and calculate the CRC for sanity checking
+    * of the data.
+    *
+    * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+    */
+    internal class CRC 
+	{
+        public static readonly int[] crc32Table = {
+            unchecked((int)0x00000000), unchecked((int)0x04c11db7), unchecked((int)0x09823b6e), unchecked((int)0x0d4326d9),
+            unchecked((int)0x130476dc), unchecked((int)0x17c56b6b), unchecked((int)0x1a864db2), unchecked((int)0x1e475005),
+            unchecked((int)0x2608edb8), unchecked((int)0x22c9f00f), unchecked((int)0x2f8ad6d6), unchecked((int)0x2b4bcb61),
+            unchecked((int)0x350c9b64), unchecked((int)0x31cd86d3), unchecked((int)0x3c8ea00a), unchecked((int)0x384fbdbd),
+            unchecked((int)0x4c11db70), unchecked((int)0x48d0c6c7), unchecked((int)0x4593e01e), unchecked((int)0x4152fda9),
+            unchecked((int)0x5f15adac), unchecked((int)0x5bd4b01b), unchecked((int)0x569796c2), unchecked((int)0x52568b75),
+            unchecked((int)0x6a1936c8), unchecked((int)0x6ed82b7f), unchecked((int)0x639b0da6), unchecked((int)0x675a1011),
+            unchecked((int)0x791d4014), unchecked((int)0x7ddc5da3), unchecked((int)0x709f7b7a), unchecked((int)0x745e66cd),
+            unchecked((int)0x9823b6e0), unchecked((int)0x9ce2ab57), unchecked((int)0x91a18d8e), unchecked((int)0x95609039),
+            unchecked((int)0x8b27c03c), unchecked((int)0x8fe6dd8b), unchecked((int)0x82a5fb52), unchecked((int)0x8664e6e5),
+            unchecked((int)0xbe2b5b58), unchecked((int)0xbaea46ef), unchecked((int)0xb7a96036), unchecked((int)0xb3687d81),
+            unchecked((int)0xad2f2d84), unchecked((int)0xa9ee3033), unchecked((int)0xa4ad16ea), unchecked((int)0xa06c0b5d),
+            unchecked((int)0xd4326d90), unchecked((int)0xd0f37027), unchecked((int)0xddb056fe), unchecked((int)0xd9714b49),
+            unchecked((int)0xc7361b4c), unchecked((int)0xc3f706fb), unchecked((int)0xceb42022), unchecked((int)0xca753d95),
+            unchecked((int)0xf23a8028), unchecked((int)0xf6fb9d9f), unchecked((int)0xfbb8bb46), unchecked((int)0xff79a6f1),
+            unchecked((int)0xe13ef6f4), unchecked((int)0xe5ffeb43), unchecked((int)0xe8bccd9a), unchecked((int)0xec7dd02d),
+            unchecked((int)0x34867077), unchecked((int)0x30476dc0), unchecked((int)0x3d044b19), unchecked((int)0x39c556ae),
+            unchecked((int)0x278206ab), unchecked((int)0x23431b1c), unchecked((int)0x2e003dc5), unchecked((int)0x2ac12072),
+            unchecked((int)0x128e9dcf), unchecked((int)0x164f8078), unchecked((int)0x1b0ca6a1), unchecked((int)0x1fcdbb16),
+            unchecked((int)0x018aeb13), unchecked((int)0x054bf6a4), unchecked((int)0x0808d07d), unchecked((int)0x0cc9cdca),
+            unchecked((int)0x7897ab07), unchecked((int)0x7c56b6b0), unchecked((int)0x71159069), unchecked((int)0x75d48dde),
+            unchecked((int)0x6b93dddb), unchecked((int)0x6f52c06c), unchecked((int)0x6211e6b5), unchecked((int)0x66d0fb02),
+            unchecked((int)0x5e9f46bf), unchecked((int)0x5a5e5b08), unchecked((int)0x571d7dd1), unchecked((int)0x53dc6066),
+            unchecked((int)0x4d9b3063), unchecked((int)0x495a2dd4), unchecked((int)0x44190b0d), unchecked((int)0x40d816ba),
+            unchecked((int)0xaca5c697), unchecked((int)0xa864db20), unchecked((int)0xa527fdf9), unchecked((int)0xa1e6e04e),
+            unchecked((int)0xbfa1b04b), unchecked((int)0xbb60adfc), unchecked((int)0xb6238b25), unchecked((int)0xb2e29692),
+            unchecked((int)0x8aad2b2f), unchecked((int)0x8e6c3698), unchecked((int)0x832f1041), unchecked((int)0x87ee0df6),
+            unchecked((int)0x99a95df3), unchecked((int)0x9d684044), unchecked((int)0x902b669d), unchecked((int)0x94ea7b2a),
+            unchecked((int)0xe0b41de7), unchecked((int)0xe4750050), unchecked((int)0xe9362689), unchecked((int)0xedf73b3e),
+            unchecked((int)0xf3b06b3b), unchecked((int)0xf771768c), unchecked((int)0xfa325055), unchecked((int)0xfef34de2),
+            unchecked((int)0xc6bcf05f), unchecked((int)0xc27dede8), unchecked((int)0xcf3ecb31), unchecked((int)0xcbffd686),
+            unchecked((int)0xd5b88683), unchecked((int)0xd1799b34), unchecked((int)0xdc3abded), unchecked((int)0xd8fba05a),
+            unchecked((int)0x690ce0ee), unchecked((int)0x6dcdfd59), unchecked((int)0x608edb80), unchecked((int)0x644fc637),
+            unchecked((int)0x7a089632), unchecked((int)0x7ec98b85), unchecked((int)0x738aad5c), unchecked((int)0x774bb0eb),
+            unchecked((int)0x4f040d56), unchecked((int)0x4bc510e1), unchecked((int)0x46863638), unchecked((int)0x42472b8f),
+            unchecked((int)0x5c007b8a), unchecked((int)0x58c1663d), unchecked((int)0x558240e4), unchecked((int)0x51435d53),
+            unchecked((int)0x251d3b9e), unchecked((int)0x21dc2629), unchecked((int)0x2c9f00f0), unchecked((int)0x285e1d47),
+            unchecked((int)0x36194d42), unchecked((int)0x32d850f5), unchecked((int)0x3f9b762c), unchecked((int)0x3b5a6b9b),
+            unchecked((int)0x0315d626), unchecked((int)0x07d4cb91), unchecked((int)0x0a97ed48), unchecked((int)0x0e56f0ff),
+            unchecked((int)0x1011a0fa), unchecked((int)0x14d0bd4d), unchecked((int)0x19939b94), unchecked((int)0x1d528623),
+            unchecked((int)0xf12f560e), unchecked((int)0xf5ee4bb9), unchecked((int)0xf8ad6d60), unchecked((int)0xfc6c70d7),
+            unchecked((int)0xe22b20d2), unchecked((int)0xe6ea3d65), unchecked((int)0xeba91bbc), unchecked((int)0xef68060b),
+            unchecked((int)0xd727bbb6), unchecked((int)0xd3e6a601), unchecked((int)0xdea580d8), unchecked((int)0xda649d6f),
+            unchecked((int)0xc423cd6a), unchecked((int)0xc0e2d0dd), unchecked((int)0xcda1f604), unchecked((int)0xc960ebb3),
+            unchecked((int)0xbd3e8d7e), unchecked((int)0xb9ff90c9), unchecked((int)0xb4bcb610), unchecked((int)0xb07daba7),
+            unchecked((int)0xae3afba2), unchecked((int)0xaafbe615), unchecked((int)0xa7b8c0cc), unchecked((int)0xa379dd7b),
+            unchecked((int)0x9b3660c6), unchecked((int)0x9ff77d71), unchecked((int)0x92b45ba8), unchecked((int)0x9675461f),
+            unchecked((int)0x8832161a), unchecked((int)0x8cf30bad), unchecked((int)0x81b02d74), unchecked((int)0x857130c3),
+            unchecked((int)0x5d8a9099), unchecked((int)0x594b8d2e), unchecked((int)0x5408abf7), unchecked((int)0x50c9b640),
+            unchecked((int)0x4e8ee645), unchecked((int)0x4a4ffbf2), unchecked((int)0x470cdd2b), unchecked((int)0x43cdc09c),
+            unchecked((int)0x7b827d21), unchecked((int)0x7f436096), unchecked((int)0x7200464f), unchecked((int)0x76c15bf8),
+            unchecked((int)0x68860bfd), unchecked((int)0x6c47164a), unchecked((int)0x61043093), unchecked((int)0x65c52d24),
+            unchecked((int)0x119b4be9), unchecked((int)0x155a565e), unchecked((int)0x18197087), unchecked((int)0x1cd86d30),
+            unchecked((int)0x029f3d35), unchecked((int)0x065e2082), unchecked((int)0x0b1d065b), unchecked((int)0x0fdc1bec),
+            unchecked((int)0x3793a651), unchecked((int)0x3352bbe6), unchecked((int)0x3e119d3f), unchecked((int)0x3ad08088),
+            unchecked((int)0x2497d08d), unchecked((int)0x2056cd3a), unchecked((int)0x2d15ebe3), unchecked((int)0x29d4f654),
+            unchecked((int)0xc5a92679), unchecked((int)0xc1683bce), unchecked((int)0xcc2b1d17), unchecked((int)0xc8ea00a0),
+            unchecked((int)0xd6ad50a5), unchecked((int)0xd26c4d12), unchecked((int)0xdf2f6bcb), unchecked((int)0xdbee767c),
+            unchecked((int)0xe3a1cbc1), unchecked((int)0xe760d676), unchecked((int)0xea23f0af), unchecked((int)0xeee2ed18),
+            unchecked((int)0xf0a5bd1d), unchecked((int)0xf464a0aa), unchecked((int)0xf9278673), unchecked((int)0xfde69bc4),
+            unchecked((int)0x89b8fd09), unchecked((int)0x8d79e0be), unchecked((int)0x803ac667), unchecked((int)0x84fbdbd0),
+            unchecked((int)0x9abc8bd5), unchecked((int)0x9e7d9662), unchecked((int)0x933eb0bb), unchecked((int)0x97ffad0c),
+            unchecked((int)0xafb010b1), unchecked((int)0xab710d06), unchecked((int)0xa6322bdf), unchecked((int)0xa2f33668),
+            unchecked((int)0xbcb4666d), unchecked((int)0xb8757bda), unchecked((int)0xb5365d03), unchecked((int)0xb1f740b4)
+        };
+
+        public CRC() {
+            InitialiseCRC();
+        }
+
+        internal void InitialiseCRC() {
+            globalCrc = unchecked((int)0xffffffff);
+        }
+
+        internal int GetFinalCRC() {
+            return ~globalCrc;
+        }
+
+        internal int GetGlobalCRC() {
+            return globalCrc;
+        }
+
+        internal void SetGlobalCRC(int newCrc) {
+            globalCrc = newCrc;
+        }
+
+        internal void UpdateCRC(int inCh) {
+            int temp = (globalCrc >> 24) ^ inCh;
+            if (temp < 0) {
+                temp = 256 + temp;
+            }
+            globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp];
+        }
+
+        internal int globalCrc;
+    }
+}
\ No newline at end of file
diff --git a/crypto/checklist.txt b/crypto/checklist.txt
new file mode 100644
index 000000000..0057b6e50
--- /dev/null
+++ b/crypto/checklist.txt
@@ -0,0 +1,16 @@
+-----------------
+Release Checklist
+-----------------
+
+- Update to latest from git
+- Run 'nant -t:net-1.1 clean test'
+- Run 'nant -t:netcf-1.0 clean compile-release'
+- Edit AssemblyInfo.cs: Change version and check copyright
+- Edit NBuild.build: Change version
+- Edit License.html: Check copyright
+- Edit Readme.html: Add release notes
+- Commit changes to git
+- Tag git repository with "release-${version}" 
+- Push changes/tag to git
+- Place BouncyCastle.snk in parent directory
+- Run 'nant -t:net-1.1 clean dist'
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 3835d449c..d65021a68 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -1,3469 +1,11537 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}</ProjectGuid>
-    <AssemblyKeyContainerName />
-    <AssemblyName>crypto</AssemblyName>
-    <AssemblyOriginatorKeyFile />
-    <DelaySign>false</DelaySign>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Org.BouncyCastle</RootNamespace>
-    <RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
-    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
-    <TargetFrameworkProfile>Profile328</TargetFrameworkProfile>
-    <FileAlignment>512</FileAlignment>
-    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
-    <ValidateXaml>true</ValidateXaml>
-    <ThrowErrorsInValidation>true</ThrowErrorsInValidation>
-    <SccProjectName>SAK</SccProjectName>
-    <SccLocalPath>SAK</SccLocalPath>
-    <SccAuxPath>SAK</SccAuxPath>
-    <SccProvider>SAK</SccProvider>
-    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\Src\</SolutionDir>
-    <RestorePackages>true</RestorePackages>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <OutputPath>bin\Debug\</OutputPath>
-    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
-    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
-    <DefineConstants>TRACE;DEBUG;PORTABLE</DefineConstants>
-    <DocumentationFile>doc\crypto.xml</DocumentationFile>
-    <DebugSymbols>true</DebugSymbols>
-    <Optimize>false</Optimize>
-    <RegisterForComInterop>false</RegisterForComInterop>
-    <RemoveIntegerChecks>false</RemoveIntegerChecks>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-    <WarningLevel>4</WarningLevel>
-    <DebugType>full</DebugType>
-    <ErrorReport>prompt</ErrorReport>
-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
-    <WarningsAsErrors>
-    </WarningsAsErrors>
-    <NoWarn>1591</NoWarn>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <OutputPath>bin\Release\</OutputPath>
-    <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
-    <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
-    <DefineConstants>TRACE;PORTABLE</DefineConstants>
-    <DocumentationFile>doc\crypto.xml</DocumentationFile>
-    <DebugSymbols>false</DebugSymbols>
-    <NoStdLib>true</NoStdLib>
-    <NoConfig>true</NoConfig>
-    <Optimize>true</Optimize>
-    <RegisterForComInterop>false</RegisterForComInterop>
-    <RemoveIntegerChecks>false</RemoveIntegerChecks>
-    <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
-    <WarningLevel>4</WarningLevel>
-    <DebugType>pdbonly</DebugType>
-    <ErrorReport>prompt</ErrorReport>
-    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
-    <WarningsAsErrors>
-    </WarningsAsErrors>
-    <NoWarn>1591</NoWarn>
-  </PropertyGroup>
-  <ItemGroup>
-    <!-- A reference to the entire .NET Framework is automatically included -->
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="bzip2\src\BZip2Constants.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="bzip2\src\CBZip2InputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="bzip2\src\CBZip2OutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="bzip2\src\CRC.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1Encodable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1EncodableVector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\Asn1Exception.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1Generator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1InputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1Null.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1Object.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1OctetString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1OctetStringParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1OutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\Asn1ParsingException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1Sequence.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1SequenceParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1Set.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1SetParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1StreamParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1TaggedObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1TaggedObjectParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ASN1Tags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\bc\BCObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERApplicationSpecific.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERApplicationSpecificParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERNull.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BEROctetString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BEROctetStringGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BEROctetStringParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BEROutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERSequence.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERSequenceGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERSequenceParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERSet.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERSetGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERSetParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERTaggedObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\BERTaggedObjectParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CAKeyUpdAnnContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CertConfirmContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CertifiedKeyPair.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CertOrEncCert.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CertRepMessage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CertResponse.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CertStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\Challenge.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CmpCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CmpObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\CrlAnnContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\ErrorMsgContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\GenMsgContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\GenRepContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\InfoTypeAndValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\KeyRecRepContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\OobCertHash.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PbmParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIBody.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIConfirmContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIFailureInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIFreeText.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIHeader.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIHeaderBuilder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIMessage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIMessages.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PKIStatusInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PollRepContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PollReqContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PopoDecKeyChallContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\PopoDecKeyRespContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\ProtectedPart.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\RevAnnContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\RevDetails.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\RevRepContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\RevRepContentBuilder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cmp\RevReqContent.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\Attribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\Attributes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\AttributeTable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\AuthenticatedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\AuthenticatedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\AuthEnvelopedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\AuthEnvelopedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\CMSAttributes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\CMSObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\CompressedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\CompressedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\ContentInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\ContentInfoParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\ecc\MQVuserKeyingMaterial.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\EncryptedContentInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\EncryptedContentInfoParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\EncryptedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\EnvelopedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\EnvelopedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\Evidence.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\IssuerAndSerialNumber.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\KEKIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\KEKRecipientInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\KeyAgreeRecipientIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\KeyAgreeRecipientInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\KeyTransRecipientInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\MetaData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\OriginatorIdentifierOrKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\OriginatorInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\OriginatorPublicKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\OtherKeyAttribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\OtherRecipientInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\PasswordRecipientInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\RecipientEncryptedKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\RecipientIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\RecipientInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\RecipientKeyIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\SignedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\SignedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\SignerIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\SignerInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\Time.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\TimeStampAndCRL.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\TimeStampedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\TimeStampedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cms\TimeStampTokenEvidence.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ConstructedOctetStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\AttributeTypeAndValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\CertId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\CertReqMessages.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\CertReqMsg.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\CertRequest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\CertTemplate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\CertTemplateBuilder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\Controls.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\CrmfObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\EncKeyWithID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\EncryptedKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\EncryptedValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\OptionalValidity.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\PKIArchiveOptions.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\PKIPublicationInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\PKMacValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\PopoPrivKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\PopoSigningKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\PopoSigningKeyInput.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\ProofOfPossession.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\SinglePubInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\crmf\SubsequentMessage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cryptopro\CryptoProObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cryptopro\ECGOST3410NamedCurves.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cryptopro\ECGOST3410ParamSetParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cryptopro\GOST28147Parameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cryptopro\GOST3410NamedParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cryptopro\GOST3410ParamSetParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\cryptopro\GOST3410PublicKeyAlgParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DefiniteLengthInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERApplicationSpecific.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERBitString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERBMPString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERBoolean.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DEREnumerated.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERExternal.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERExternalParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERGeneralizedTime.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERGeneralString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERIA5String.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERInteger.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERNull.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERNumericString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERObjectIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DEROctetString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DEROctetStringParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DEROutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERPrintableString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERSequence.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERSequenceGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERSequenceParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERSet.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERSetGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERSetParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DerStringBase.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERT61String.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERTaggedObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERUniversalString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERUnknownTag.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERUTCTime.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERUTF8String.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\DERVisibleString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\eac\EACObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CertificateValues.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CommitmentTypeIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CommitmentTypeIndication.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CommitmentTypeQualifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CompleteCertificateRefs.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CompleteRevocationRefs.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CrlIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CrlListID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CrlOcspRef.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\CrlValidatedID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\ESFAttributes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OcspIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OcspListID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OcspResponsesID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OtherCertID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OtherHash.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OtherHashAlgAndValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OtherRevRefs.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OtherRevVals.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\OtherSigningCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\RevocationValues.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\SignaturePolicyId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\SignaturePolicyIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\SignerAttribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\SignerLocation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\esf\SigPolicyQualifierInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\ContentHints.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\ContentIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\ESSCertID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\ESSCertIDv2.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\OtherCertID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\OtherSigningCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\SigningCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ess\SigningCertificateV2.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\gnu\GNUObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\iana\IANAObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\IAsn1ApplicationSpecificParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\IAsn1Choice.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\IAsn1Convertible.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\IAsn1String.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\icao\CscaMasterList.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\icao\DataGroupHash.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\icao\ICAOObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\icao\LDSSecurityObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\icao\LDSVersionInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\IndefiniteLengthInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\ISISMTTObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\ocsp\CertHash.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\ocsp\RequestedCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\AdditionalInformationSyntax.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\Admissions.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\AdmissionSyntax.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\DeclarationOfMajority.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\MonetaryLimit.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\NamingAuthority.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\ProcurationSyntax.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\ProfessionInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\isismtt\x509\Restriction.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\kisa\KISAObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\LazyASN1InputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\LazyDERSequence.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\LazyDERSet.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\LimitedInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\microsoft\MicrosoftObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\misc\CAST5CBCParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\misc\IDEACBCPar.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\misc\MiscObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\misc\NetscapeCertType.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\misc\NetscapeRevocationURL.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\misc\VerisignCzagExtension.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\mozilla\PublicKeyAndChallenge.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\nist\NISTNamedCurves.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\nist\NISTObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ntt\NTTObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\BasicOCSPResponse.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\CertID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\CertStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\CrlID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\OCSPObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\OCSPRequest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\OCSPResponse.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\OCSPResponseStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\Request.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\ResponderID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\ResponseBytes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\ResponseData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\RevokedInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\ServiceLocator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\Signature.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\SingleResponse.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\ocsp\TBSRequest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\OIDTokenizer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\oiw\ElGamalParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\oiw\OIWObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\Attribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\AuthenticatedSafe.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\CertBag.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\CertificationRequest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\CertificationRequestInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\ContentInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\DHParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\EncryptedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\EncryptedPrivateKeyInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\EncryptionScheme.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\IssuerAndSerialNumber.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\KeyDerivationFunc.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\MacData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\PBEParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\PBES2Parameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\PBKDF2Params.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\Pfx.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\PKCS12PBEParams.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\PKCSObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\PrivateKeyInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\RC2CBCParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\RSAESOAEPparams.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\RSAPrivateKeyStructure.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\RSASSAPSSparams.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\SafeBag.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\SignedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\pkcs\SignerInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\sec\ECPrivateKeyStructure.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\sec\SECNamedCurves.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\sec\SECObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\smime\SMIMEAttributes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\smime\SMIMECapabilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\smime\SMIMECapabilitiesAttribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\smime\SMIMECapability.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\smime\SMIMECapabilityVector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\smime\SMIMEEncryptionKeyPreferenceAttribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\teletrust\TeleTrusTNamedCurves.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\teletrust\TeleTrusTObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\tsp\Accuracy.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\tsp\MessageImprint.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\tsp\TimeStampReq.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\tsp\TimeStampResp.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\tsp\TSTInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\util\ASN1Dump.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\util\Dump.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\util\FilterStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x500\DirectoryString.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AccessDescription.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AlgorithmIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AttCertIssuer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AttCertValidityPeriod.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\Attribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AttributeCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AttributeCertificateInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AttributeTable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AuthorityInformationAccess.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\AuthorityKeyIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\BasicConstraints.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\CertificateList.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\CertificatePair.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\CertPolicyId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\CRLDistPoint.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\CRLNumber.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\CRLReason.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\DigestInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\DisplayText.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\DistributionPoint.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\DistributionPointName.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\DSAParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\ExtendedKeyUsage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\GeneralName.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\GeneralNames.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\GeneralSubtree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\Holder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\IetfAttrSyntax.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\IssuerSerial.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\IssuingDistributionPoint.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\KeyPurposeId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\KeyUsage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\NameConstraints.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\NoticeReference.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\ObjectDigestInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\PolicyInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\PolicyMappings.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\PolicyQualifierId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\PolicyQualifierInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\PrivateKeyUsagePeriod.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\BiometricData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\ETSIQCObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\Iso4217CurrencyCode.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\MonetaryValue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\QCStatement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\RFC3739QCObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\SemanticsInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\qualified\TypeOfBiometricData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\ReasonFlags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\RoleSyntax.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\RSAPublicKeyStructure.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\sigi\NameOrPseudonym.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\sigi\PersonalData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\sigi\SigIObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\SubjectDirectoryAttributes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\SubjectKeyIdentifier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\SubjectPublicKeyInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\Target.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\TargetInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\Targets.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\TBSCertificateStructure.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\TBSCertList.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\Time.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\UserNotice.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\V1TBSCertificateGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\V2AttributeCertificateInfoGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\V2Form.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\V2TBSCertListGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\V3TBSCertificateGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509Attributes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509CertificateStructure.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509DefaultEntryConverter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509Extension.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509Extensions.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509ExtensionsGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509Name.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509NameEntryConverter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509NameTokenizer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x509\X509ObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\DHDomainParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\DHPublicKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\DHValidationParms.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\KeySpecificInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\OtherInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X962NamedCurves.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X962Parameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9Curve.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9ECParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9ECParametersHolder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9ECPoint.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9FieldElement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9FieldID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9IntegerConverter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\asn1\x9\X9ObjectIdentifiers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\AssemblyInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\ArmoredInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\ArmoredOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\attr\ImageAttrib.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\BCPGInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\BCPGObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\BCPGOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\CompressedDataPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\CompressionAlgorithmTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\ContainedPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\CRC24.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\DSAPublicBCPGKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\DSASecretBCPGKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\ElGamalPublicBCPGKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\ElGamalSecretBCPGKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\ExperimentalPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\HashAlgorithmTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\IBcpgKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\InputStreamPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\LiteralDataPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\MarkerPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\ModDetectionCodePacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\MPInteger.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\OnePassSignaturePacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\OutputStreamPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\Packet.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\PacketTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\PublicKeyAlgorithmTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\PublicKeyEncSessionPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\PublicKeyPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\PublicSubkeyPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\RSAPublicBCPGKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\RSASecretBCPGKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\S2K.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SecretKeyPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SecretSubkeyPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SignaturePacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SignatureSubpacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SignatureSubpacketsReader.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SignatureSubpacketTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\EmbeddedSignature.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\Exportable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\IssuerKeyID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\KeyExpirationTime.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\KeyFlags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\NotationData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\PreferredAlgorithms.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\PrimaryUserID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\Revocable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\RevocationKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\RevocationKeyTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\RevocationReason.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\RevocationReasonTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\SignatureCreationTime.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\SignatureExpirationTime.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\SignerUserID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\sig\TrustSignature.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SymmetricEncDataPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SymmetricEncIntegrityPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SymmetricKeyAlgorithmTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\SymmetricKeyEncSessionPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\TrustPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\UserAttributePacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\UserAttributeSubpacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\UserAttributeSubpacketsReader.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\UserAttributeSubpacketTags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\bcpg\UserIDPacket.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\BaseDigestCalculator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAttributeTableGenerationException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAttributeTableGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAuthenticatedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAuthenticatedDataGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAuthenticatedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAuthenticatedDataStreamGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAuthenticatedGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAuthEnvelopedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSAuthEnvelopedGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSCompressedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSCompressedDataGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSCompressedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSCompressedDataStreamGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSContentInfoParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSEnvelopedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSEnvelopedDataGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSEnvelopedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSEnvelopedDataStreamGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSEnvelopedGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSEnvelopedHelper.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSPBEKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSProcessable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSProcessableByteArray.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSProcessableFile.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSProcessableInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSReadable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSSecureReadable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSSignedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSSignedDataGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSSignedDataParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSSignedDataStreamGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSSignedGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSSignedHelper.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSStreamException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSTypedStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CMSUtils.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\CounterSignatureDigestCalculator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\DefaultAuthenticatedAttributeTableGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\DefaultSignedAttributeTableGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\DigOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\IDigestCalculator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\KEKRecipientInfoGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\KEKRecipientInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\KeyAgreeRecipientInfoGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\KeyAgreeRecipientInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\KeyTransRecipientInfoGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\KeyTransRecipientInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\MacOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\NullOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\OriginatorId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\PasswordRecipientInfoGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\PasswordRecipientInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\PKCS5Scheme2PBEKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\PKCS5Scheme2UTF8PBEKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\RecipientId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\RecipientInfoGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\RecipientInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\RecipientInformationStore.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\SignerId.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\SignerInfoGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\SignerInformation.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\SignerInformationStore.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\SigOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\cms\SimpleAttributeTableGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\DHAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\DHBasicAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\ECDHBasicAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\ECDHCBasicAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\ECDHWithKdfBasicAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\ECMqvBasicAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\kdf\DHKdfParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\kdf\DHKekGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\kdf\ECDHKekGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\srp\SRP6Client.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\srp\SRP6Server.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\srp\SRP6Utilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\agreement\srp\SRP6VerifierGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\AsymmetricCipherKeyPair.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\AsymmetricKeyParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\BufferedAeadBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\BufferedAsymmetricBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\BufferedBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\BufferedCipherBase.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\BufferedIesCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\BufferedStreamCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\CipherKeyGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\CryptoException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\DataLengthException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\GeneralDigest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\GOST3411Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\LongDigest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\MD2Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\MD4Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\MD5Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\NullDigest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\RIPEMD128Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\RIPEMD160Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\RIPEMD256Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\RIPEMD320Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\SHA1Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\SHA224Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\SHA256Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\SHA384Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\SHA512Digest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\ShortenedDigest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\TigerDigest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\digests\WhirlpoolDigest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\encodings\ISO9796d1Encoding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\encodings\OAEPEncoding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\encodings\PKCS1Encoding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\AESEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\AESFastEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\AESLightEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\AESWrapEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\BlowfishEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\CamelliaEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\CamelliaLightEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\CamelliaWrapEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\CAST5Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\CAST6Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\DESedeEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\DESedeWrapEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\DesEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\ElGamalEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\GOST28147Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\HC128Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\HC256Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\IDEAEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\IESEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\ISAACEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\NaccacheSternEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\NoekeonEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\NullEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RC2Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RC2WrapEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RC4Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RC532Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RC564Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RC6Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RFC3211WrapEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RFC3394WrapEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RijndaelEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RSABlindedEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RSABlindingEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RSACoreEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\RSAEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\Salsa20Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\SEEDEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\SEEDWrapEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\SerpentEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\SkipjackEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\TEAEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\TwofishEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\VMPCEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\VMPCKSA3Engine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\engines\XTEAEngine.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\BaseKDFBytesGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DESedeKeyGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DESKeyGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DHBasicKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DHKeyGeneratorHelper.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DHKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DHParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DHParametersHelper.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DSAKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\DSAParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\ECKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\ElGamalKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\ElGamalParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\GOST3410KeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\GOST3410ParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\KDF1BytesGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\KDF2BytesGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\MGF1BytesGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\NaccacheSternKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\OpenSSLPBEParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\PKCS12ParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\PKCS5S1ParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\PKCS5S2ParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\RSABlindingFactorGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\RSAKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\generators\SCrypt.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IAsymmetricBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IAsymmetricCipherKeyPairGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IBasicAgreement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IBufferedCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\ICipherParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IDerivationFunction.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IDerivationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IDigest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IDSA.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IMac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\InvalidCipherTextException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\io\CipherStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\io\DigestStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\io\MacStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\io\SignerStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\ISigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\ISignerWithRecovery.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IStreamCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\IWrapper.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\KeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\macs\CBCBlockCipherMac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\macs\CFBBlockCipherMac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\macs\CMac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\macs\GOST28147Mac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\macs\HMac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\macs\ISO9797Alg3Mac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\macs\VMPCMac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\MaxBytesExceededException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\CBCBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\CCMBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\CFBBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\CTSBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\EAXBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\GCMBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\BasicGcmExponentiator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\BasicGcmMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\GcmUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\IGcmExponentiator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\IGcmMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\Tables1kGcmExponentiator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\Tables64kGcmMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\gcm\Tables8kGcmMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\GOFBBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\IAeadBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\OFBBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\OpenPGPCFBBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\modes\SICBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\BlockCipherPadding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\ISO10126d2Padding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\ISO7816d4Padding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\PaddedBufferedBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\PKCS7Padding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\TBCPadding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\X923Padding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\paddings\ZeroBytePadding.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\AEADParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\CCMParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DESedeParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DESParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DHKeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DHKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DHParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DHPrivateKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DHPublicKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DHValidationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DSAKeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DSAKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DSAParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DSAPrivateKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DSAPublicKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\DSAValidationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ECDomainParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ECKeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ECKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ECPrivateKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ECPublicKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ElGamalKeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ElGamalKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ElGamalParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ElGamalPrivateKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ElGamalPublicKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\GOST3410KeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\GOST3410KeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\GOST3410Parameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\GOST3410PrivateKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\GOST3410PublicKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\GOST3410ValidationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\IESParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\IESWithCipherParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ISO18033KDFParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\KDFParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\KeyParameter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\MGFParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\MqvPrivateParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\MqvPublicParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\NaccacheSternKeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\NaccacheSternKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\NaccacheSternPrivateKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ParametersWithIV.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ParametersWithRandom.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ParametersWithSalt.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\ParametersWithSBox.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\RC2Parameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\RC5Parameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\RSABlindingParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\RSAKeyGenerationParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\RSAKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\parameters\RSAPrivateCrtKeyParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\PBEParametersGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\prng\CryptoApiRandomGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\prng\DigestRandomGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\prng\IRandomGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\prng\ReversedWindowGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\prng\ThreadedSeedGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\prng\VMPCRandomGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\DSADigestSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\DSASigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\ECDSASigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\ECGOST3410Signer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\ECNRSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\GenericSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\GOST3410DigestSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\GOST3410Signer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\ISO9796d2PSSSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\ISO9796d2Signer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\PSSSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\signers\RSADigestSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\StreamBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\AlertDescription.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\AlertLevel.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\AlwaysValidVerifyer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\ByteQueue.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\Certificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\CertificateRequest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\CipherSuite.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\ClientCertificateType.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\CombinedHash.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\CompressionMethod.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\ContentType.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\DefaultTlsAgreementCredentials.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\DefaultTlsCipherFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\DefaultTlsClient.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\DefaultTlsSignerCredentials.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\DigestAlgorithm.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\ECCurveType.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\ECPointFormat.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\EncryptionAlgorithm.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\ExtensionType.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\HandshakeType.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\ICertificateVerifyer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\KeyExchangeAlgorithm.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\LegacyTlsAuthentication.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\LegacyTlsClient.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\NamedCurve.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\PskTlsClient.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\RecordStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\SecurityParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\SrpTlsClient.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\Ssl3Mac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsAgreementCredentials.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsAuthentication.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsBlockCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsCipherFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsClient.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsClientContext.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsClientContextImpl.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsCompression.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsCredentials.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsDeflateCompression.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsDheKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsDHKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsDHUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsDsaSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsDssSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsECDheKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsECDHKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsECDsaSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsFatalAlert.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsMac.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsNullCipher.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsNullCompression.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsProtocolHandler.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsPskIdentity.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsPskKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsRsaKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsRsaSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsRsaUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsSigner.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsSignerCredentials.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsSrpKeyExchange.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\tls\TlsUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\crypto\util\Pack.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\BigInteger.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\abc\SimpleBigDecimal.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\abc\Tnaf.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\abc\ZTauElement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\ECAlgorithms.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\ECCurve.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\ECFieldElement.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\ECPoint.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\IntArray.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\ECMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\FpNafMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\PreCompInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\ReferenceMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\WNafMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\WNafPreCompInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\WTauNafMultiplier.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\math\ec\multiplier\WTauNafPreCompInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\BasicOCSPResp.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\BasicOCSPRespGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\CertificateID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\CertificateStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\OCSPException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\OCSPReq.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\OCSPReqGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\OCSPResp.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\OCSPRespGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\OCSPRespStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\OCSPUtil.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\Req.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\RespData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\RespID.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\RevokedStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\SingleResp.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\ocsp\UnknownStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\IStreamGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPCompressedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPCompressedDataGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPDataValidationException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPEncryptedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPEncryptedDataGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPEncryptedDataList.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PgpExperimental.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPKeyFlags.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPKeyPair.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPKeyRing.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPKeyRingGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPKeyValidationException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPLiteralData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPLiteralDataGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPMarker.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPObjectFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPOnePassSignature.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPOnePassSignatureList.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPPBEEncryptedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPPrivateKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPPublicKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPPublicKeyEncryptedData.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPPublicKeyRing.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PgpPublicKeyRingBundle.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPSecretKey.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPSecretKeyRing.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PgpSecretKeyRingBundle.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPSignature.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPSignatureGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPSignatureList.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPSignatureSubpacketGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPSignatureSubpacketVector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPUserAttributeSubpacketVector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPUserAttributeSubpacketVectorGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PgpUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\PGPV3SignatureGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openpgp\WrappedGeneratorStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\EncryptionException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\IPasswordFinder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\MiscPemGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\PasswordException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\PEMException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\PEMReader.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\PEMUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\PEMWriter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\openssl\Pkcs8Generator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\AsymmetricKeyEntry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\EncryptedPrivateKeyInfoFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\PKCS10CertificationRequest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\Pkcs10CertificationRequestDelaySigned.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\PKCS12Entry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\PKCS12Store.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\PKCS12StoreBuilder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\PKCS12Utilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\PrivateKeyInfoFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkcs\X509CertificateEntry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\CertStatus.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixAttrCertChecker.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixAttrCertPathBuilder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixAttrCertPathValidator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixBuilderParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPath.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathBuilder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathBuilderException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathBuilderResult.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathChecker.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathValidator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathValidatorException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathValidatorResult.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCertPathValidatorUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixCrlUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixNameConstraintValidator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixNameConstraintValidatorException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\PkixPolicyNode.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\ReasonsMask.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\Rfc3280CertPathUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\Rfc3281CertPathUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\pkix\TrustAnchor.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\AgreementUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\cert\CertificateEncodingException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\cert\CertificateException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\cert\CertificateExpiredException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\cert\CertificateNotYetValidException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\cert\CertificateParsingException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\cert\CrlException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\CipherUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\DigestUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\DotNetUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\GeneralSecurityException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\GeneratorUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\InvalidKeyException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\InvalidParameterException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\KeyException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\MacUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\NoSuchAlgorithmException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\ParameterUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\PbeUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\PrivateKeyFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\PublicKeyFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\SecureRandom.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\SecurityUtilityException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\SignatureException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\SignerUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\security\WrapperUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\GenTimeAccuracy.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TimeStampRequest.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TimeStampRequestGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TimeStampResponse.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TimeStampResponseGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TimeStampToken.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TimeStampTokenGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TimeStampTokenInfo.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TSPAlgorithms.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TSPException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TSPUtil.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\tsp\TSPValidationException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\Arrays.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\BigIntegers.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\CollectionUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\EmptyEnumerable.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\EnumerableProxy.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\HashSet.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\ISet.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\LinkedDictionary.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\UnmodifiableDictionary.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\UnmodifiableDictionaryProxy.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\UnmodifiableList.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\UnmodifiableListProxy.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\UnmodifiableSet.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\collections\UnmodifiableSetProxy.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\date\DateTimeObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\date\DateTimeUtilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\Base64.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\Base64Encoder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\BufferedDecoder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\BufferedEncoder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\Hex.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\HexEncoder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\HexTranslator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\IEncoder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\Translator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\UrlBase64.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\encoders\UrlBase64Encoder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\Enums.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\BaseInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\BaseOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\pem\PemGenerationException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\pem\PemHeader.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\pem\PemObject.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\pem\PemObjectGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\pem\PemObjectParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\pem\PemReader.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\pem\PemWriter.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\PushbackStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\StreamOverflowException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\Streams.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\TeeInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\io\TeeOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\net\IPAddress.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\Platform.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\Strings.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\Adler32.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\Deflate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\InfBlocks.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\InfCodes.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\Inflate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\InfTree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\JZlib.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\StaticTree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\Tree.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\ZDeflaterOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\ZInflaterInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\ZInputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\ZOutputStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\util\zlib\ZStream.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\AttributeCertificateHolder.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\AttributeCertificateIssuer.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\extension\AuthorityKeyIdentifierStructure.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\extension\SubjectKeyIdentifierStructure.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\extension\X509ExtensionUtil.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\IX509AttributeCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\IX509Extension.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\PEMParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\PrincipalUtil.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\IX509Selector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\IX509Store.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\IX509StoreParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\NoSuchStoreException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509AttrCertStoreSelector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509CertPairStoreSelector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509CertStoreSelector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509CollectionStore.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509CollectionStoreParameters.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509CrlStoreSelector.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509StoreException.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\store\X509StoreFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\SubjectPublicKeyInfoFactory.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509AttrCertParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509Attribute.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509Certificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509CertificatePair.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509CertificateParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509CertPairParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509Crl.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509CrlEntry.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509CrlParser.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509ExtensionBase.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509KeyUsage.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509SignatureUtil.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509Utilities.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509V1CertificateGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509V2AttributeCertificate.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509V2AttributeCertificateGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509V2CRLGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Include="src\x509\X509V3CertificateGenerator.cs">
-      <SubType>Code</SubType>
-    </Compile>
-    <Content Include="Contributors.html" />
-    <Content Include="License.html" />
-    <Content Include="Readme.html" />
-  </ItemGroup>
-  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
-  <ProjectExtensions />
-  <PropertyGroup>
-    <PreBuildEvent />
-    <PostBuildEvent />
-  </PropertyGroup>
-  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
-       Other similar extension points exist, see Microsoft.Common.targets.
-  <Target Name="BeforeBuild">
-  </Target>
-  <Target Name="AfterBuild">
-  </Target>
-  -->
-</Project>
\ No newline at end of file
+<VisualStudioProject>
+    <CSHARP
+        ProjectType = "Local"
+        ProductVersion = "7.10.3077"
+        SchemaVersion = "2.0"
+        ProjectGuid = "{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}"
+    >
+        <Build>
+            <Settings
+                ApplicationIcon = ""
+                AssemblyKeyContainerName = ""
+                AssemblyName = "crypto"
+                AssemblyOriginatorKeyFile = ""
+                DefaultClientScript = "JScript"
+                DefaultHTMLPageLayout = "Grid"
+                DefaultTargetSchema = "IE50"
+                DelaySign = "false"
+                OutputType = "Library"
+                PreBuildEvent = ""
+                PostBuildEvent = ""
+                RootNamespace = "crypto"
+                RunPostBuildEvent = "OnBuildSuccess"
+                StartupObject = ""
+            >
+                <Config
+                    Name = "Debug"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "DEBUG;TRACE;NET_1_1"
+                    DocumentationFile = "doc\crypto.xml"
+                    DebugSymbols = "true"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "false"
+                    NoStdLib = "false"
+                    NoWarn = "1591"
+                    Optimize = "false"
+                    OutputPath = "bin\Debug\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+                <Config
+                    Name = "Release"
+                    AllowUnsafeBlocks = "false"
+                    BaseAddress = "285212672"
+                    CheckForOverflowUnderflow = "false"
+                    ConfigurationOverrideFile = ""
+                    DefineConstants = "TRACE;NET_1_1"
+                    DocumentationFile = "doc\crypto.xml"
+                    DebugSymbols = "false"
+                    FileAlignment = "4096"
+                    IncrementalBuild = "false"
+                    NoStdLib = "false"
+                    NoWarn = "1591"
+                    Optimize = "true"
+                    OutputPath = "bin\Release\"
+                    RegisterForComInterop = "false"
+                    RemoveIntegerChecks = "false"
+                    TreatWarningsAsErrors = "false"
+                    WarningLevel = "4"
+                />
+            </Settings>
+            <References>
+                <Reference
+                    Name = "System"
+                    AssemblyName = "System"
+                    HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.dll"
+                />
+                <Reference
+                    Name = "System.Data"
+                    AssemblyName = "System.Data"
+                    HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.Data.dll"
+                />
+                <Reference
+                    Name = "System.XML"
+                    AssemblyName = "System.Xml"
+                    HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.1.4322\System.XML.dll"
+                />
+                <Reference
+                    Name = "nunit.core"
+                    AssemblyName = "nunit.core"
+                    HintPath = "test\lib\nunit.core.dll"
+                />
+                <Reference
+                    Name = "nunit.framework"
+                    AssemblyName = "nunit.framework"
+                    HintPath = "test\lib\nunit.framework.dll"
+                />
+                <Reference
+                    Name = "nunit.core.interfaces"
+                    AssemblyName = "nunit.core.interfaces"
+                    HintPath = "test\lib\nunit.core.interfaces.dll"
+                />
+            </References>
+        </Build>
+        <Files>
+            <Include>
+                <File
+                    RelPath = "Contributors.html"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "License.html"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "NBuild.build"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "Readme.html"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "testcfg.nunit"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "bzip2\src\BZip2Constants.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "bzip2\src\CBZip2InputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "bzip2\src\CBZip2OutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "bzip2\src\CRC.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\AssemblyInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1Encodable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1EncodableVector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\Asn1Exception.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1Generator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1InputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1Null.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1Object.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1OctetString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1OctetStringParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1OutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\Asn1ParsingException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1Sequence.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1SequenceParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1Set.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1SetParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1StreamParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1TaggedObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1TaggedObjectParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ASN1Tags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERApplicationSpecific.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERApplicationSpecificParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERNull.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BEROctetString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BEROctetStringGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BEROctetStringParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BEROutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERSequence.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERSequenceGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERSequenceParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERSet.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERSetGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERSetParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERTaggedObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\BERTaggedObjectParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ConstructedOctetStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DefiniteLengthInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERApplicationSpecific.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERBitString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERBMPString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERBoolean.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DEREnumerated.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERExternal.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERExternalParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERGeneralizedTime.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERGeneralString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERIA5String.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERInteger.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERNull.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERNumericString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERObjectIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DEROctetString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DEROctetStringParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DEROutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERPrintableString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERSequence.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERSequenceGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERSequenceParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERSet.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERSetGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERSetParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DerStringBase.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERT61String.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERTaggedObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERUniversalString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERUTCTime.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERUTF8String.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\DERVisibleString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\IAsn1ApplicationSpecificParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\IAsn1Choice.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\IAsn1Convertible.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\IAsn1String.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\IndefiniteLengthInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\LazyASN1InputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\LazyDERSequence.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\LazyDERSet.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\LimitedInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\OIDTokenizer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\bc\BCObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CAKeyUpdAnnContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CertConfirmContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CertifiedKeyPair.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CertOrEncCert.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CertRepMessage.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CertResponse.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CertStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\Challenge.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CmpCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CmpObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\CrlAnnContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\ErrorMsgContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\GenMsgContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\GenRepContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\InfoTypeAndValue.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\KeyRecRepContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\OobCertHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PbmParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIBody.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIConfirmContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIFailureInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIFreeText.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIHeader.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIHeaderBuilder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIMessage.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIMessages.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PKIStatusInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PollRepContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PollReqContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\ProtectedPart.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PopoDecKeyChallContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\PopoDecKeyRespContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\RevAnnContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\RevDetails.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\RevRepContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\RevRepContentBuilder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cmp\RevReqContent.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\Attribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\Attributes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\AttributeTable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\AuthenticatedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\AuthenticatedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\AuthEnvelopedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\AuthEnvelopedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\CMSAttributes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\CMSObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\CompressedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\CompressedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\ContentInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\ContentInfoParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\EncryptedContentInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\EncryptedContentInfoParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\EncryptedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\EnvelopedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\EnvelopedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\Evidence.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\IssuerAndSerialNumber.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\KEKIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\KEKRecipientInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\KeyAgreeRecipientIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\KeyAgreeRecipientInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\KeyTransRecipientInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\MetaData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\OriginatorIdentifierOrKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\OriginatorInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\OriginatorPublicKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\OtherKeyAttribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\OtherRecipientInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\OtherRevocationInfoFormat.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\PasswordRecipientInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\RecipientEncryptedKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\RecipientIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\RecipientInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\RecipientKeyIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\SCVPReqRes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\SignedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\SignedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\SignerIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\SignerInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\Time.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\TimeStampAndCRL.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\TimeStampedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\TimeStampedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\TimeStampTokenEvidence.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cms\ecc\MQVuserKeyingMaterial.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\AttributeTypeAndValue.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\CertId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\CertReqMessages.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\CertReqMsg.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\CertRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\CertTemplate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\CertTemplateBuilder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\Controls.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\CrmfObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\EncKeyWithID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\EncryptedKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\EncryptedValue.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\OptionalValidity.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\PKIArchiveOptions.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\PKIPublicationInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\PKMacValue.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\PopoPrivKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\PopoSigningKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\PopoSigningKeyInput.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\ProofOfPossession.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\SinglePubInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\crmf\SubsequentMessage.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cryptopro\CryptoProObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cryptopro\ECGOST3410NamedCurves.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cryptopro\ECGOST3410ParamSetParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cryptopro\GOST28147Parameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cryptopro\GOST3410NamedParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cryptopro\GOST3410ParamSetParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\cryptopro\GOST3410PublicKeyAlgParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\eac\EACObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CertificateValues.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CommitmentTypeIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CommitmentTypeIndication.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CommitmentTypeQualifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CompleteCertificateRefs.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CompleteRevocationRefs.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CrlIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CrlListID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CrlOcspRef.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\CrlValidatedID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\ESFAttributes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OcspIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OcspListID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OcspResponsesID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OtherCertID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OtherHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OtherHashAlgAndValue.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OtherRevRefs.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OtherRevVals.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\OtherSigningCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\RevocationValues.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\SignaturePolicyId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\SignaturePolicyIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\SignerAttribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\SignerLocation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\esf\SigPolicyQualifierInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\ContentHints.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\ContentIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\ESSCertID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\ESSCertIDv2.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\OtherCertID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\OtherSigningCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\SigningCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ess\SigningCertificateV2.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\gnu\GNUObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\iana\IANAObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\icao\CscaMasterList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\icao\DataGroupHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\icao\ICAOObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\icao\LDSSecurityObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\icao\LDSVersionInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\ISISMTTObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\ocsp\CertHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\ocsp\RequestedCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\AdditionalInformationSyntax.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\Admissions.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\AdmissionSyntax.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\DeclarationOfMajority.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\MonetaryLimit.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\NamingAuthority.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\ProcurationSyntax.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\ProfessionInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\isismtt\x509\Restriction.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\kisa\KISAObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\microsoft\MicrosoftObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\misc\CAST5CBCParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\misc\IDEACBCPar.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\misc\MiscObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\misc\NetscapeCertType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\misc\NetscapeRevocationURL.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\misc\VerisignCzagExtension.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\mozilla\PublicKeyAndChallenge.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\nist\NISTNamedCurves.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\nist\NISTObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ntt\NTTObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\BasicOCSPResponse.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\CertID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\CertStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\CrlID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\OCSPObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\OCSPRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\OCSPResponse.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\OCSPResponseStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\Request.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\ResponderID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\ResponseBytes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\ResponseData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\RevokedInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\ServiceLocator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\Signature.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\SingleResponse.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\ocsp\TBSRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\oiw\ElGamalParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\oiw\OIWObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\Attribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\AuthenticatedSafe.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\CertBag.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\CertificationRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\CertificationRequestInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\ContentInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\DHParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\EncryptedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\EncryptedPrivateKeyInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\EncryptionScheme.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\IssuerAndSerialNumber.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\KeyDerivationFunc.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\MacData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\PBEParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\PBES2Parameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\PBKDF2Params.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\Pfx.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\PKCS12PBEParams.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\PKCSObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\PrivateKeyInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\RC2CBCParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\RSAESOAEPparams.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\RSAPrivateKeyStructure.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\RSASSAPSSparams.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\SafeBag.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\SignedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\pkcs\SignerInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\sec\ECPrivateKeyStructure.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\sec\SECNamedCurves.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\sec\SECObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\smime\SMIMEAttributes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\smime\SMIMECapabilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\smime\SMIMECapabilitiesAttribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\smime\SMIMECapability.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\smime\SMIMECapabilityVector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\smime\SMIMEEncryptionKeyPreferenceAttribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\teletrust\TeleTrusTNamedCurves.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\teletrust\TeleTrusTObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\tsp\Accuracy.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\tsp\MessageImprint.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\tsp\TimeStampReq.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\tsp\TimeStampResp.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\tsp\TSTInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\util\ASN1Dump.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\util\Dump.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\util\FilterStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x500\DirectoryString.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AccessDescription.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AlgorithmIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AttCertIssuer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AttCertValidityPeriod.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\Attribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AttributeCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AttributeCertificateInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AttributeTable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AuthorityInformationAccess.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\AuthorityKeyIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\BasicConstraints.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\CertificateList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\CertificatePair.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\CertificatePolicies.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\CertPolicyId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\CRLDistPoint.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\CRLNumber.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\CRLReason.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\DigestInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\DisplayText.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\DistributionPoint.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\DistributionPointName.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\DSAParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\ExtendedKeyUsage.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\GeneralName.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\GeneralNames.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\GeneralSubtree.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\Holder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\IetfAttrSyntax.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\IssuerSerial.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\IssuingDistributionPoint.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\KeyPurposeId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\KeyUsage.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\NameConstraints.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\NoticeReference.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\ObjectDigestInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\PolicyInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\PolicyMappings.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\PolicyQualifierId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\PolicyQualifierInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\PrivateKeyUsagePeriod.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\ReasonFlags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\RoleSyntax.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\RSAPublicKeyStructure.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\SubjectDirectoryAttributes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\SubjectKeyIdentifier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\SubjectPublicKeyInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\Target.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\TargetInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\Targets.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\TBSCertificateStructure.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\TBSCertList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\Time.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\UserNotice.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\V1TBSCertificateGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\V2AttributeCertificateInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\V2Form.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\V2TBSCertListGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\V3TBSCertificateGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509Attributes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509CertificateStructure.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509DefaultEntryConverter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509Extension.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509Extensions.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509ExtensionsGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509Name.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509NameEntryConverter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509NameTokenizer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\X509ObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\BiometricData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\ETSIQCObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\Iso4217CurrencyCode.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\MonetaryValue.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\QCStatement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\RFC3739QCObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\SemanticsInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\qualified\TypeOfBiometricData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\sigi\NameOrPseudonym.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\sigi\PersonalData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x509\sigi\SigIObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\DHDomainParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\DHPublicKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\DHValidationParms.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\ECNamedCurveTable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\KeySpecificInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\OtherInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X962NamedCurves.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X962Parameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9ECParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9ECParametersHolder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9ECPoint.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9FieldID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9IntegerConverter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\asn1\x9\X9ObjectIdentifiers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\ArmoredInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\ArmoredOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\BCPGInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\BCPGObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\BCPGOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\CompressedDataPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\CompressionAlgorithmTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\ContainedPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\CRC24.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\DSAPublicBCPGKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\DSASecretBCPGKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\ElGamalPublicBCPGKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\ElGamalSecretBCPGKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\ExperimentalPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\HashAlgorithmTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\IBcpgKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\InputStreamPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\LiteralDataPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\MarkerPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\ModDetectionCodePacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\MPInteger.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\OnePassSignaturePacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\OutputStreamPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\Packet.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\PacketTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\PublicKeyAlgorithmTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\PublicKeyEncSessionPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\PublicKeyPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\PublicSubkeyPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\RSAPublicBCPGKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\RSASecretBCPGKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\S2K.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SecretKeyPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SecretSubkeyPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SignaturePacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SignatureSubpacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SignatureSubpacketsReader.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SignatureSubpacketTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SymmetricEncDataPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SymmetricEncIntegrityPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SymmetricKeyAlgorithmTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\SymmetricKeyEncSessionPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\TrustPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\UserAttributePacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\UserAttributeSubpacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\UserAttributeSubpacketsReader.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\UserAttributeSubpacketTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\UserIDPacket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\attr\ImageAttrib.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\EmbeddedSignature.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\Exportable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\IssuerKeyID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\KeyExpirationTime.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\KeyFlags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\NotationData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\PreferredAlgorithms.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\PrimaryUserID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\Revocable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\RevocationKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\RevocationKeyTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\RevocationReason.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\RevocationReasonTags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\SignatureCreationTime.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\SignatureExpirationTime.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\SignerUserID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\bcpg\sig\TrustSignature.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\BaseDigestCalculator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAttributeTableGenerationException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAttributeTableGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAuthenticatedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAuthenticatedDataGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAuthenticatedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAuthenticatedDataStreamGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAuthenticatedGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAuthEnvelopedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSAuthEnvelopedGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSCompressedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSCompressedDataGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSCompressedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSCompressedDataStreamGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSContentInfoParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSEnvelopedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSEnvelopedDataGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSEnvelopedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSEnvelopedDataStreamGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSEnvelopedGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSEnvelopedHelper.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSPBEKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSProcessable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSProcessableByteArray.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSProcessableFile.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSProcessableInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSReadable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSSecureReadable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSSignedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSSignedDataGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSSignedDataParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSSignedDataStreamGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSSignedGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSSignedHelper.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSStreamException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSTypedStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CMSUtils.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\CounterSignatureDigestCalculator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\DefaultAuthenticatedAttributeTableGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\DefaultSignedAttributeTableGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\DigOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\IDigestCalculator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\KEKRecipientInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\KEKRecipientInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\KeyAgreeRecipientInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\KeyAgreeRecipientInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\KeyTransRecipientInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\KeyTransRecipientInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\MacOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\OriginatorId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\OriginatorInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\OriginatorInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\PasswordRecipientInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\PasswordRecipientInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\PKCS5Scheme2PBEKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\PKCS5Scheme2UTF8PBEKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\RecipientId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\RecipientInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\RecipientInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\RecipientInformationStore.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\SignerId.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\SignerInfoGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\SignerInformation.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\SignerInformationStore.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\SigOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\cms\SimpleAttributeTableGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\AsymmetricCipherKeyPair.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\AsymmetricKeyParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\BufferedAeadBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\BufferedAsymmetricBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\BufferedBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\BufferedCipherBase.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\BufferedIesCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\BufferedStreamCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\CipherKeyGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\CryptoException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\DataLengthException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IAsymmetricBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IAsymmetricCipherKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IBasicAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IBufferedCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\ICipherParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IDerivationFunction.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IDerivationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IDSA.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\InvalidCipherTextException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\ISigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\ISignerWithRecovery.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IStreamCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\IWrapper.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\KeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\MaxBytesExceededException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\PBEParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\StreamBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\DHAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\DHBasicAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\DHStandardGroups.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\ECDHBasicAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\ECDHCBasicAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\ECDHWithKdfBasicAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\ECMqvBasicAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\ECMqvWithKdfBasicAgreement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\kdf\DHKdfParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\kdf\DHKekGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\kdf\ECDHKekGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\srp\SRP6Client.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\srp\SRP6Server.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\srp\SRP6Utilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\agreement\srp\SRP6VerifierGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\GeneralDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\GOST3411Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\LongDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\MD2Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\MD4Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\MD5Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\NullDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\RIPEMD128Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\RIPEMD160Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\RIPEMD256Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\RIPEMD320Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\Sha1Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\Sha224Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\Sha256Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\Sha3Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\Sha384Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\Sha512Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\Sha512tDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\ShortenedDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\SkeinDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\SkeinEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\SM3Digest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\TigerDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\digests\WhirlpoolDigest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\ec\CustomNamedCurves.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\encodings\ISO9796d1Encoding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\encodings\OAEPEncoding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\encodings\PKCS1Encoding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\AESEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\AESFastEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\AESLightEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\AESWrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\BlowfishEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\CamelliaEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\CamelliaLightEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\CamelliaWrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\CAST5Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\CAST6Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\ChaChaEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\DESedeEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\DESedeWrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\DesEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\ElGamalEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\GOST28147Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\HC128Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\HC256Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\IDEAEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\IESEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\ISAACEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\NaccacheSternEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\NoekeonEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\NullEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RC2Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RC2WrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RC4Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RC532Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RC564Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RC6Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RFC3211WrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RFC3394WrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RijndaelEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RSABlindedEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RSABlindingEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RSACoreEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\RSAEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\Salsa20Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\SEEDEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\SEEDWrapEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\SerpentEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\SkipjackEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\TEAEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\ThreefishEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\TwofishEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\VMPCEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\VMPCKSA3Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\XSalsa20Engine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\engines\XTEAEngine.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\BaseKDFBytesGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DESedeKeyGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DESKeyGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DHBasicKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DHKeyGeneratorHelper.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DHKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DHParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DHParametersHelper.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DSAKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\DSAParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\ECKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\ElGamalKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\ElGamalParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\GOST3410KeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\GOST3410ParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\KDF1BytesGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\KDF2BytesGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\MGF1BytesGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\NaccacheSternKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\OpenSSLPBEParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\PKCS12ParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\PKCS5S1ParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\PKCS5S2ParametersGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\Poly1305KeyGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\RSABlindingFactorGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\RSAKeyPairGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\generators\SCrypt.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\io\CipherStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\io\DigestStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\io\MacStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\io\SignerStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\CBCBlockCipherMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\CFBBlockCipherMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\CMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\GMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\GOST28147Mac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\HMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\Poly1305.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\SipHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\SkeinMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\ISO9797Alg3Mac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\macs\VMPCMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\CBCBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\CCMBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\CFBBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\CTSBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\EAXBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\GCMBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\OCBBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\GOFBBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\IAeadBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\OFBBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\OpenPGPCFBBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\SICBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\BasicGcmExponentiator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\BasicGcmMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\GcmUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\IGcmExponentiator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\IGcmMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\Tables1kGcmExponentiator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\Tables64kGcmMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\modes\gcm\Tables8kGcmMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\BlockCipherPadding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\ISO10126d2Padding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\ISO7816d4Padding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\PaddedBufferedBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\PKCS7Padding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\TBCPadding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\X923Padding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\paddings\ZeroBytePadding.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\AEADParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\CCMParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DESedeParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DESParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DHKeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DHKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DHParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DHPrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DHPublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DHValidationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DSAKeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DSAKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DSAParameterGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DSAParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DSAPrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DSAPublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\DSAValidationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ECDomainParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ECKeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ECKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ECPrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ECPublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ElGamalKeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ElGamalKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ElGamalParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ElGamalPrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ElGamalPublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\GOST3410KeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\GOST3410KeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\GOST3410Parameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\GOST3410PrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\GOST3410PublicKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\GOST3410ValidationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\IESParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\IESWithCipherParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ISO18033KDFParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\KDFParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\KeyParameter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\MGFParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\MqvPrivateParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\MqvPublicParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\NaccacheSternKeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\NaccacheSternKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\NaccacheSternPrivateKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ParametersWithIV.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ParametersWithRandom.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ParametersWithSalt.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\ParametersWithSBox.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\RC2Parameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\RC5Parameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\RSABlindingParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\RSAKeyGenerationParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\RSAKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\RSAPrivateCrtKeyParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\SkeinParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\parameters\TweakableBlockCipherParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\prng\CryptoApiRandomGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\prng\DigestRandomGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\prng\IRandomGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\prng\ReversedWindowGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\prng\ThreadedSeedGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\prng\VMPCRandomGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\DSADigestSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\DSASigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\ECDSASigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\ECGOST3410Signer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\ECNRSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\GenericSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\GOST3410DigestSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\GOST3410Signer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\HMacDsaKCalculator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\IDsaKCalculator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\ISO9796d2PSSSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\ISO9796d2Signer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\PSSSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\RandomDsaKCalculator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\signers\RSADigestSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsAgreementCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsCipherFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsClient.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsContext.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsEncryptionCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsPeer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsServer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AbstractTlsSignerCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AlertDescription.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\AlertLevel.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\BulkCipherAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ByteQueue.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CertChainType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\Certificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CertificateStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CertificateStatusRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CertificateStatusType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CertificateRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CertificateUrl.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\Chacha20Poly1305.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ChangeCipherSpec.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CipherSuite.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CipherType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ClientAuthenticationType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ClientCertificateType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CombinedHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\CompressionMethod.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ConnectionEnd.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ContentType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DefaultTlsAgreementCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DefaultTlsCipherFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DefaultTlsClient.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DefaultTlsEncryptionCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DefaultTlsServer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DefaultTlsSignerCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DeferredHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DigestInputBuffer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\DigitallySigned.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ECBasisType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ECCurveType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ECPointFormat.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\EncryptionAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ExporterLabel.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ExtensionType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\HandshakeType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\HashAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\HeartbeatExtension.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\HeartbeatMessage.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\HeartbeatMessageType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\HeartbeatMode.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\KeyExchangeAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\MacAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\MaxFragmentLength.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\NamedCurve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\NameType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\NewSessionTicket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\OcspStatusRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\PrfAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ProtocolVersion.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\PskTlsClient.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\RecordStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SecurityParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ServerDHParams.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ServerName.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ServerNameList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\ServerOnlyTlsAuthentication.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SessionParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SignatureAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SignatureAndHashAlgorithm.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SignerInputBuffer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SrpTlsClient.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SrtpProtectionProfile.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\Ssl3Mac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SupplementalDataEntry.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\SupplementalDataType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsAeadCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsAgreementCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsAuthentication.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsBlockCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsCipherFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsClient.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsClientContext.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsClientContextImpl.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsClientProtocol.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsCompression.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsContext.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsDeflateCompression.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsDheKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsDHKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsDHUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsDsaSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsDssSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsEccUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsECDheKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsECDHKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsECDsaSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsEncryptionCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsExtensionsUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsFatalAlert.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsHandshakeHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsMac.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsNullCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsNullCompression.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsPeer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsProtocol.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsProtocolHandler.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsPskKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsPskIdentity.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsRsaKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsRsaUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsRsaSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsServer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsServerContext.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsServerContextImpl.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsServerProtocol.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsSession.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsSessionImpl.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsSigner.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsSignerCredentials.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsSrpKeyExchange.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsSrpUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsSrtpUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsStreamCipher.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\TlsUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\UrlAndHash.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\UserMappingType.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\tls\UseSrtpData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\crypto\util\Pack.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\BigInteger.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ECAlgorithms.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ECCurve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ECFieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ECPoint.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ECPointMap.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\LongArray.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\Mod.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\Nat.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ScaleXPointMap.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\ScaleYPointMap.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\abc\SimpleBigDecimal.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\abc\Tnaf.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\abc\ZTauElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\djb\Curve25519.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\djb\Curve25519Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\djb\Curve25519FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\djb\Curve25519Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\Nat192.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\Nat224.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\Nat256.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\Nat384.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\Nat512.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192K1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192K1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192K1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192K1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192R1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192R1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192R1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP192R1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224K1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224K1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224K1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224K1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224R1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224R1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224R1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP224R1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256K1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256K1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256K1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256K1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256R1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256R1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256R1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP256R1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP384R1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP384R1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP384R1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP384R1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP521R1Curve.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP521R1Field.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP521R1FieldElement.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\custom\sec\SecP521R1Point.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\endo\ECEndomorphism.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\endo\GlvEndomorphism.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\endo\GlvTypeBEndomorphism.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\endo\GlvTypeBParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\AbstractECMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\DoubleAddMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\ECMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\FixedPointCombMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\FixedPointPreCompInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\FixedPointUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\GlvMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\MixedNafR2LMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\MontgomeryLadderMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\NafL2RMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\NafR2LMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\PreCompInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\ReferenceMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\WNafL2RMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\WNafPreCompInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\WNafUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\WTauNafMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\WTauNafPreCompInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\ZSignedDigitL2RMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\ec\multiplier\ZSignedDigitR2LMultiplier.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\FiniteFields.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\GF2Polynomial.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\GenericPolynomialExtensionField.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\IExtensionField.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\IFiniteField.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\IPolynomial.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\IPolynomialExtensionField.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\math\field\PrimeField.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\BasicOCSPResp.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\BasicOCSPRespGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\CertificateID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\CertificateStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\OCSPException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\OCSPReq.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\OCSPReqGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\OCSPResp.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\OCSPRespGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\OCSPRespStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\OCSPUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\Req.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\RespData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\RespID.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\RevokedStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\SingleResp.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\ocsp\UnknownStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\IStreamGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPCompressedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPCompressedDataGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPDataValidationException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPEncryptedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPEncryptedDataGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPEncryptedDataList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PgpExperimental.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPKeyFlags.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPKeyPair.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPKeyRing.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPKeyRingGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPKeyValidationException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPLiteralData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPLiteralDataGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPMarker.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPObjectFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPOnePassSignature.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPOnePassSignatureList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPPBEEncryptedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPPrivateKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPPublicKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPPublicKeyEncryptedData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPPublicKeyRing.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PgpPublicKeyRingBundle.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPSecretKey.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPSecretKeyRing.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PgpSecretKeyRingBundle.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPSignature.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPSignatureGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPSignatureList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPSignatureSubpacketGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPSignatureSubpacketVector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPUserAttributeSubpacketVector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPUserAttributeSubpacketVectorGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PgpUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\PGPV3SignatureGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openpgp\WrappedGeneratorStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\EncryptionException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\IPasswordFinder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\MiscPemGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\PasswordException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\PEMException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\PEMReader.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\PEMUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\PEMWriter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\openssl\Pkcs8Generator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\AsymmetricKeyEntry.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\EncryptedPrivateKeyInfoFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\PKCS10CertificationRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\Pkcs10CertificationRequestDelaySigned.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\PKCS12Entry.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\PKCS12Store.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\PKCS12StoreBuilder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\PKCS12Utilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\PrivateKeyInfoFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkcs\X509CertificateEntry.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\CertStatus.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixAttrCertChecker.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixAttrCertPathBuilder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixAttrCertPathValidator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixBuilderParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPath.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathBuilder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathBuilderException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathBuilderResult.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathChecker.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathValidator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathValidatorException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathValidatorResult.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCertPathValidatorUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixCrlUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixNameConstraintValidator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixNameConstraintValidatorException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\PkixPolicyNode.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\ReasonsMask.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\Rfc3280CertPathUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\Rfc3281CertPathUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\pkix\TrustAnchor.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\AgreementUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\CipherUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\DigestUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\DotNetUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\GeneralSecurityException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\GeneratorUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\InvalidKeyException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\InvalidParameterException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\KeyException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\MacUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\NoSuchAlgorithmException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\ParameterUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\PbeUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\PrivateKeyFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\PublicKeyFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\SecureRandom.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\SecurityUtilityException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\SignatureException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\SignerUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\WrapperUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\cert\CertificateEncodingException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\cert\CertificateException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\cert\CertificateExpiredException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\cert\CertificateNotYetValidException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\cert\CertificateParsingException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\security\cert\CrlException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\GenTimeAccuracy.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TimeStampRequest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TimeStampRequestGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TimeStampResponse.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TimeStampResponseGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TimeStampToken.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TimeStampTokenGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TimeStampTokenInfo.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TSPAlgorithms.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TSPException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TSPUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\tsp\TSPValidationException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\Arrays.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\BigIntegers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\Enums.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\IMemoable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\Integers.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\MemoableResetException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\Platform.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\Strings.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\Times.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\CollectionUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\EmptyEnumerable.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\EnumerableProxy.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\HashSet.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\ISet.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\LinkedDictionary.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\UnmodifiableDictionary.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\UnmodifiableDictionaryProxy.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\UnmodifiableList.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\UnmodifiableListProxy.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\UnmodifiableSet.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\collections\UnmodifiableSetProxy.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\date\DateTimeObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\date\DateTimeUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\Base64.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\Base64Encoder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\BufferedDecoder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\BufferedEncoder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\Hex.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\HexEncoder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\HexTranslator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\IEncoder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\Translator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\UrlBase64.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\encoders\UrlBase64Encoder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\BaseInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\BaseOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\NullOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\PushbackStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\StreamOverflowException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\Streams.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\TeeInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\TeeOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\pem\PemGenerationException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\pem\PemHeader.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\pem\PemObject.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\pem\PemObjectGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\pem\PemObjectParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\pem\PemReader.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\io\pem\PemWriter.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\net\IPAddress.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\Adler32.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\Deflate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\InfBlocks.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\InfCodes.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\Inflate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\InfTree.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\JZlib.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\StaticTree.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\Tree.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\ZDeflaterOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\ZInflaterInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\ZInputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\ZOutputStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\util\zlib\ZStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\AttributeCertificateHolder.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\AttributeCertificateIssuer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\IX509AttributeCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\IX509Extension.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\PEMParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\PrincipalUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\SubjectPublicKeyInfoFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509AttrCertParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509Attribute.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509Certificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509CertificatePair.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509CertificateParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509CertPairParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509Crl.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509CrlEntry.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509CrlParser.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509ExtensionBase.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509KeyUsage.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509SignatureUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509Utilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509V1CertificateGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509V2AttributeCertificate.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509V2AttributeCertificateGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509V2CRLGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\X509V3CertificateGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\extension\AuthorityKeyIdentifierStructure.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\extension\SubjectKeyIdentifierStructure.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\extension\X509ExtensionUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\IX509Selector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\IX509Store.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\IX509StoreParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\NoSuchStoreException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509AttrCertStoreSelector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509CertPairStoreSelector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509CertStoreSelector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509CollectionStore.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509CollectionStoreParameters.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509CrlStoreSelector.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509StoreException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "src\x509\store\X509StoreFactory.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\data\asn1\masterlist-content.data"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\counterSig.p7m"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\PSSSignData.data"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\PSSSignDataSHA1.sig"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\PSSSignDataSHA1Enc.sig"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\PSSSignDataSHA256.sig"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\PSSSignDataSHA256Enc.sig"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\PSSSignDataSHA512.sig"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\cms\sigs\PSSSignDataSHA512Enc.sig"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\hc256\hc128\ecrypt_HC-128.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\hc256\hc256\ecrypt_HC-256_128K_128IV.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\hc256\hc256\ecrypt_HC-256_128K_256IV.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\hc256\hc256\ecrypt_HC-256_256K_128IV.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\hc256\hc256\ecrypt_HC-256_256K_256IV.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\README.txt"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbe_WithSHA1And128BitRC2_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbe_WithSHA1And128BitRC4.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbe_WithSHA1And2_Key_TripleDES_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbe_WithSHA1And3_Key_TripleDES_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbe_WithSHA1And40BitRC2_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbe_WithSHA1And40BitRC4.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbeWithMD2AndDES_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbeWithMD2AndRC2_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbeWithMD5AndDES_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbeWithMD5AndRC2_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbeWithSHA1AndDES_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes1\pbeWithSHA1AndRC2_CBC.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes128.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-128-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-128-cfb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-128-cfb1.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-128-cfb8.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-128-ecb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-128-ofb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes192.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-192-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-192-cfb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-192-cfb1.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-192-cfb8.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-192-ecb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-192-ofb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes256.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-256-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-256-cfb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-256-cfb1.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-256-cfb8.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-256-ecb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.aes-256-ofb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.bf.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.bf-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.blowfish.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.cast.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.cast5-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.cast-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des3.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-cfb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-cfb1.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-cfb8.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-ecb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-ede.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-ede3-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.des-ofb.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.rc2.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.rc2-40-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.rc2-64-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\keys\pbes2\pbes2.rc2-cbc.key"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\README.txt"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-1024-160.pub"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-1024-160.sec"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-15360-512.pub"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-15360-512.sec"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-2048-224.pub"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-2048-224.sec"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-3072-256.pub"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-3072-256.sec"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-7680-384.pub"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\keys\DSA-7680-384.sec"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-1024-160-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-1024-224-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-1024-256-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-1024-384-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-1024-512-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-15360-512-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-2048-224-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-3072-256-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openpgp\dsa\sigs\dsa-7680-384-sign.gpg"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\eckey.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\enckey.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\pkcs7.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\pkcs8test.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\README.txt"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "test\data\openssl\test.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes128_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes128_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes128_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes128_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes192_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes192_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes192_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes192_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes256_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes256_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes256_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_aes256_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_blowfish_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_blowfish_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_blowfish_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_blowfish_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des1_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des1_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des1_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des1_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des2_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des2_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des2_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des2_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des3_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des3_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des3_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_des3_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_rc2_128_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_rc2_128_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_rc2_128_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_rc2_128_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_rc2_40_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_rc2_64_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\dsa\openssl_dsa_unencrypted.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\pkcs8\openssl_pkcs8_rsa.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\pkcs8\openssl_pkcs8_rsa_enc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes128_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes128_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes128_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes128_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes192_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes192_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes192_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes192_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes256_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes256_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes256_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_aes256_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_blowfish_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_blowfish_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_blowfish_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_blowfish_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des1_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des1_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des1_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des1_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des2_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des2_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des2_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des2_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des3_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des3_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des3_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_des3_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_rc2_128_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_rc2_128_cfb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_rc2_128_ecb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_rc2_128_ofb.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_rc2_40_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_rc2_64_cbc.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\openssl\rsa\openssl_rsa_unencrypted.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\README.txt"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\AllCertificatesanyPolicyTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\AllCertificatesNoPoliciesTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\AllCertificatesSamePoliciesTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\AllCertificatesSamePoliciesTest13EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\anyPolicyCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\AnyPolicyTest14EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BadCRLIssuerNameCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BadCRLSignatureCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BadnotAfterDateCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BadnotBeforeDateCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BadSignedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\basicConstraintsCriticalcAFalseCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\basicConstraintsNotCriticalCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\basicConstraintsNotCriticalcAFalseCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BasicSelfIssuedCRLSigningKeyCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BasicSelfIssuedCRLSigningKeyCRLCert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BasicSelfIssuedNewKeyCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BasicSelfIssuedNewKeyOldWithNewCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BasicSelfIssuedOldKeyCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\BasicSelfIssuedOldKeyNewWithOldCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\CPSPointerQualifierTest20EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\deltaCRLCA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\deltaCRLCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\deltaCRLCA3Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\deltaCRLIndicatorNoBaseCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DifferentPoliciesTest12EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DifferentPoliciesTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DifferentPoliciesTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DifferentPoliciesTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DifferentPoliciesTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DifferentPoliciesTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DifferentPoliciesTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\distributionPoint1CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\distributionPoint2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DSACACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\DSAParametersInheritedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\GeneralizedTimeCRLnextUpdateCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\GoodCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\GoodsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\GoodsubCAPanyPolicyMapping1to2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA3Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA3cRLIssuerCert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA4Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA4cRLIssuerCert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA5Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\indirectCRLCA6Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy0CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy1CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy1SelfIssuedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy1SelfIssuedsubCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy1subCA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy1subCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy1subCAIAP5Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy1subsubCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy5CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy5subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicy5subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitAnyPolicyTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping0CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping0subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P12CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P12subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P12subCAIPM5Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P12subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P12subsubCAIPM5Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P1CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P1SelfIssuedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P1SelfIssuedsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P1subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping1P1subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping5CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping5subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping5subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\inhibitPolicyMapping5subsubsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidBadCRLIssuerNameTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidBadCRLSignatureTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidBasicSelfIssuedNewWithOldTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidBasicSelfIssuedOldWithNewTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidcAFalseTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidcAFalseTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidCAnotAfterDateTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidCAnotBeforeDateTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidCASignatureTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidcRLIssuerTest27EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidcRLIssuerTest31EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidcRLIssuerTest32EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidcRLIssuerTest34EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidcRLIssuerTest35EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddeltaCRLIndicatorNoBaseTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddeltaCRLTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddeltaCRLTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddeltaCRLTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddeltaCRLTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddeltaCRLTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddistributionPointTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddistributionPointTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddistributionPointTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddistributionPointTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvaliddistributionPointTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNandRFC822nameConstraintsTest28EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNandRFC822nameConstraintsTest29EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest12EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest13EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest15EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest16EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest17EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest20EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNnameConstraintsTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNSnameConstraintsTest31EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNSnameConstraintsTest33EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDNSnameConstraintsTest38EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidDSASignatureTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidEEnotAfterDateTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidEEnotBeforeDateTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidEESignatureTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidIDPwithindirectCRLTest23EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidIDPwithindirectCRLTest26EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitAnyPolicyTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitAnyPolicyTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitAnyPolicyTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitAnyPolicyTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitPolicyMappingTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitPolicyMappingTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitPolicyMappingTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidinhibitPolicyMappingTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidLongSerialNumberTest18EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidMappingFromanyPolicyTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidMappingToanyPolicyTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidMissingbasicConstraintsTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidMissingCRLTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidNameChainingOrderTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidNameChainingTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidNegativeSerialNumberTest15EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidOldCRLnextUpdateTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlyContainsAttributeCertsTest14EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlyContainsCACertsTest12EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlyContainsUserCertsTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlySomeReasonsTest15EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlySomeReasonsTest16EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlySomeReasonsTest17EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlySomeReasonsTest20EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidonlySomeReasonsTest21EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidpathLenConstraintTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidpathLenConstraintTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidpathLenConstraintTest12EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidpathLenConstraintTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidpathLenConstraintTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidpathLenConstraintTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidPolicyMappingTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidPolicyMappingTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidPolicyMappingTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\Invalidpre2000CRLnextUpdateTest12EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\Invalidpre2000UTCEEnotAfterDateTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidrequireExplicitPolicyTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidrequireExplicitPolicyTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidRevokedCATest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidRevokedEETest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidRFC822nameConstraintsTest22EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidRFC822nameConstraintsTest24EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidRFC822nameConstraintsTest26EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedinhibitAnyPolicyTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedinhibitAnyPolicyTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedinhibitPolicyMappingTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedinhibitPolicyMappingTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedinhibitPolicyMappingTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedinhibitPolicyMappingTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedpathLenConstraintTest16EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedrequireExplicitPolicyTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSelfIssuedrequireExplicitPolicyTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSeparateCertificateandCRLKeysTest20EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidSeparateCertificateandCRLKeysTest21EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidUnknownCriticalCertificateExtensionTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidUnknownCRLEntryExtensionTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidUnknownCRLExtensionTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidUnknownCRLExtensionTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidURInameConstraintsTest35EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidURInameConstraintsTest37EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\InvalidWrongCRLTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\keyUsageCriticalcRLSignFalseCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\keyUsageCriticalkeyCertSignFalseCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\keyUsageNotCriticalCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\keyUsageNotCriticalcRLSignFalseCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\keyUsageNotCriticalkeyCertSignFalseCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\LongSerialNumberCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\Mapping1to2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\MappingFromanyPolicyCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\MappingToanyPolicyCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\MissingbasicConstraintsCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN1CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN1SelfIssuedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN1subCA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN1subCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN1subCA3Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN3CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN3subCA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN3subCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN4CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDN5CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDNS1CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsDNS2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsRFC822CA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsRFC822CA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsRFC822CA3Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsURI1CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\nameConstraintsURI2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\NameOrderingCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\NegativeSerialNumberCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\NoCRLCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\NoissuingDistributionPointCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\NoPoliciesCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\OldCRLnextUpdateCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\onlyContainsAttributeCertsCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\onlyContainsCACertsCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\onlyContainsUserCertsCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\onlySomeReasonsCA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\onlySomeReasonsCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\onlySomeReasonsCA3Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\onlySomeReasonsCA4Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\OverlappingPoliciesTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\P12Mapping1to3CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\P12Mapping1to3subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\P12Mapping1to3subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\P1anyPolicyMapping1to2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\P1Mapping1to234CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\P1Mapping1to234subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PanyPolicyMapping1to2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint0CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint0SelfIssuedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint0subCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint0subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint1CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint1SelfIssuedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint1SelfIssuedsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint1subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subCA0Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subCA1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subCA4Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subsubCA00Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subsubCA11Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subsubCA41Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subsubsubCA11XCert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pathLenConstraint6subsubsubCA41XCert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP1234CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP1234subCAP123Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP1234subsubCAP123P12Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP123CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP123subCAP12Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP123subsubCAP12P1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP123subsubCAP12P2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP123subsubsubCAP12P2P1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP12CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP12subCAP1Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP12subsubCAP1P2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP2subCA2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP2subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\PoliciesP3CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\pre2000CRLnextUpdateCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy0CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy0subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy0subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy0subsubsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy10CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy10subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy10subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy10subsubsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy2CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy2SelfIssuedCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy2SelfIssuedsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy2subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy4CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy4subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy4subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy4subsubsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy5CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy5subCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy5subsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy5subsubsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy7CACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy7subCARE2Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy7subsubCARE2RE4Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\requireExplicitPolicy7subsubsubCARE2RE4Cert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\RevokedsubCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\RFC3280MandatoryAttributeTypesCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\RFC3280OptionalAttributeTypesCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\RolloverfromPrintableStringtoUTF8StringCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\SeparateCertificateandCRLKeysCA2CertificateSigningCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\SeparateCertificateandCRLKeysCA2CRLSigningCert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\SeparateCertificateandCRLKeysCertificateSigningCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\SeparateCertificateandCRLKeysCRLSigningCert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\TrustAnchorRootCertificate.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\TwoCRLsCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UIDCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UnknownCRLEntryExtensionCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UnknownCRLExtensionCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UserNoticeQualifierTest15EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UserNoticeQualifierTest16EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UserNoticeQualifierTest17EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UserNoticeQualifierTest18EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UserNoticeQualifierTest19EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UTF8StringCaseInsensitiveMatchCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\UTF8StringEncodedNamesCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidbasicConstraintsNotCriticalTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidBasicSelfIssuedNewWithOldTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidBasicSelfIssuedNewWithOldTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidBasicSelfIssuedOldWithNewTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidCertificatePathTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidcRLIssuerTest28EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidcRLIssuerTest29EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidcRLIssuerTest30EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidcRLIssuerTest33EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddeltaCRLTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddeltaCRLTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddeltaCRLTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddeltaCRLTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddistributionPointTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddistributionPointTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddistributionPointTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValiddistributionPointTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNandRFC822nameConstraintsTest27EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest14EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest18EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest19EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNnameConstraintsTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNSnameConstraintsTest30EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDNSnameConstraintsTest32EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDSAParameterInheritanceTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidDSASignaturesTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidGeneralizedTimeCRLnextUpdateTest13EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidGeneralizedTimenotAfterDateTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidGeneralizedTimenotBeforeDateTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidIDPwithindirectCRLTest22EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidIDPwithindirectCRLTest24EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidIDPwithindirectCRLTest25EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidinhibitAnyPolicyTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidinhibitPolicyMappingTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidinhibitPolicyMappingTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidkeyUsageNotCriticalTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidLongSerialNumberTest16EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidLongSerialNumberTest17EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidNameChainingCapitalizationTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidNameChainingWhitespaceTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidNameChainingWhitespaceTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidNameUIDsTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidNegativeSerialNumberTest14EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidNoissuingDistributionPointTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidonlyContainsCACertsTest13EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidonlySomeReasonsTest18EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidonlySomeReasonsTest19EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidpathLenConstraintTest13EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidpathLenConstraintTest14EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidpathLenConstraintTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidpathLenConstraintTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest12EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest13EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest14EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest5EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidPolicyMappingTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\Validpre2000UTCnotBeforeDateTest3EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidrequireExplicitPolicyTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidrequireExplicitPolicyTest2EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidrequireExplicitPolicyTest4EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidRFC3280MandatoryAttributeTypesTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidRFC3280OptionalAttributeTypesTest8EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidRFC822nameConstraintsTest21EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidRFC822nameConstraintsTest23EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidRFC822nameConstraintsTest25EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidSelfIssuedinhibitAnyPolicyTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidSelfIssuedinhibitAnyPolicyTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidSelfIssuedinhibitPolicyMappingTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidSelfIssuedpathLenConstraintTest15EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidSelfIssuedpathLenConstraintTest17EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidSelfIssuedrequireExplicitPolicyTest6EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidSeparateCertificateandCRLKeysTest19EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidTwoCRLsTest7EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidUnknownNotCriticalCertificateExtensionTest1EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidURInameConstraintsTest34EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidURInameConstraintsTest36EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidUTF8StringCaseInsensitiveMatchTest11EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\ValidUTF8StringEncodedNamesTest9EE.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\certs\WrongCRLCACert.crt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\anyPolicyCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BadCRLIssuerNameCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BadCRLSignatureCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BadnotAfterDateCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BadnotBeforeDateCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BadSignedCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\basicConstraintsCriticalcAFalseCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\basicConstraintsNotCriticalCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\basicConstraintsNotCriticalcAFalseCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BasicSelfIssuedCRLSigningKeyCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BasicSelfIssuedCRLSigningKeyCRLCertCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BasicSelfIssuedNewKeyCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BasicSelfIssuedOldKeyCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\BasicSelfIssuedOldKeySelfIssuedCertCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\deltaCRLCA1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\deltaCRLCA1deltaCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\deltaCRLCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\deltaCRLCA2deltaCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\deltaCRLCA3CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\deltaCRLCA3deltaCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\deltaCRLIndicatorNoBaseCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\distributionPoint1CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\distributionPoint2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\DSACACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\DSAParametersInheritedCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\GeneralizedTimeCRLnextUpdateCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\GoodCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\GoodsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\GoodsubCAPanyPolicyMapping1to2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\indirectCRLCA1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\indirectCRLCA3CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\indirectCRLCA3cRLIssuerCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\indirectCRLCA4cRLIssuerCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\indirectCRLCA5CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy0CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy1CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy1subCA1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy1subCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy1subCAIAP5CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy1subsubCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy5CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy5subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitAnyPolicy5subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping0CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping0subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P12CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P12subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P12subCAIPM5CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P12subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P12subsubCAIPM5CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P1CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P1subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping1P1subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping5CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping5subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping5subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\inhibitPolicyMapping5subsubsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\keyUsageCriticalcRLSignFalseCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\keyUsageCriticalkeyCertSignFalseCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\keyUsageNotCriticalCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\keyUsageNotCriticalcRLSignFalseCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\keyUsageNotCriticalkeyCertSignFalseCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\LongSerialNumberCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\Mapping1to2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\MappingFromanyPolicyCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\MappingToanyPolicyCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\MissingbasicConstraintsCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN1CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN1subCA1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN1subCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN1subCA3CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN3CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN3subCA1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN3subCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN4CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDN5CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDNS1CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsDNS2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsRFC822CA1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsRFC822CA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsRFC822CA3CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsURI1CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\nameConstraintsURI2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\NameOrderCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\NegativeSerialNumberCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\NoissuingDistributionPointCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\NoPoliciesCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\OldCRLnextUpdateCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlyContainsAttributeCertsCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlyContainsCACertsCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlyContainsUserCertsCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA1compromiseCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA1otherreasonsCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA2CRL1.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA2CRL2.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA3compromiseCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA3otherreasonsCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA4compromiseCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\onlySomeReasonsCA4otherreasonsCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\P12Mapping1to3CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\P12Mapping1to3subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\P12Mapping1to3subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\P1anyPolicyMapping1to2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\P1Mapping1to234CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\P1Mapping1to234subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PanyPolicyMapping1to2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint0CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint0subCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint0subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint1CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint1subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subCA0CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subCA1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subCA4CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subsubCA00CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subsubCA11CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subsubCA41CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subsubsubCA11XCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pathLenConstraint6subsubsubCA41XCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP1234CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP1234subCAP123CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP1234subsubCAP123P12CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP123CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP123subCAP12CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP123subsubCAP12P1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP123subsubCAP2P2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP123subsubsubCAP12P2P1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP12CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP12subCAP1CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP12subsubCAP1P2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP2subCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP2subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\PoliciesP3CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\pre2000CRLnextUpdateCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy0CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy0subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy0subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy0subsubsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy10CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy10subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy10subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy10subsubsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy2CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy2subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy4CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy4subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy4subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy4subsubsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy5CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy5subCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy5subsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy5subsubsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy7CACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy7subCARE2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy7subsubCARE2RE4CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\requireExplicitPolicy7subsubsubCARE2RE4CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\RevokedsubCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\RFC3280MandatoryAttributeTypesCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\RFC3280OptionalAttributeTypesCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\RolloverfromPrintableStringtoUTF8StringCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\SeparateCertificateandCRLKeysCA2CRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\SeparateCertificateandCRLKeysCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\TrustAnchorRootCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\TwoCRLsCABadCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\TwoCRLsCAGoodCRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\UIDCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\UnknownCRLEntryExtensionCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\UnknownCRLExtensionCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\UTF8StringCaseInsensitiveMatchCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\UTF8StringEncodedNamesCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\PKITS\crls\WrongCRLCACRL.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\3.1.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\3.2.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.1.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.10.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.11.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.2.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.3.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.4.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.5.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.6.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.7.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.8.eml"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\4.9.eml"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\5.1.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\5.2.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\5.3.eml"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\6.0.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\7.1.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\7.2.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\AliceDSSSignByCarlNoInherit.cer"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\AlicePrivDSSSign.pri"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\AlicePrivRSASign.pri"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\AliceRSASignByCarl.cer"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\BobPrivRSAEncrypt.pri"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\BobRSASignByCarl.cer"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlDSSCRLEmpty.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlDSSCRLForAll.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlDSSCRLForCarl.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlDSSSelf.cer"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlPrivDSSSign.pri"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlPrivRSASign.pri"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlRSACRLEmpty.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlRSACRLForAll.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlRSACRLForCarl.crl"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\CarlRSASelf.cer"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\DianeDSSSignByCarlInherit.cer"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\DianePrivDSSSign.pri"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\DianePrivRSASignEncrypt.pri"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\DianeRSASignByCarl.cer"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\ExContent.bin"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rfc4134\rfc4134.txt"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-A.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-A.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-B.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-B.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-C.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-C.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-D.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-D.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-E.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-E.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-F.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-F.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-G.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-G.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-H.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-H.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-I.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-I.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-J.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-J.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-L.p12"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\self-testcase-L.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\rsa3\testcases.README"
+                    BuildAction = "None"
+                />
+                <File
+                    RelPath = "test\data\scrypt\TestVectors.txt"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\x509-ca-key.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\x509-ca.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\x509-client-key.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\x509-client.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\x509-server-key.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\x509-server.pem"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\keystores\client_store.dsa"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\keystores\client_store.rsa"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\keystores\server_store.dsa"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\data\tls\keystores\server_store.rsa"
+                    BuildAction = "EmbeddedResource"
+                />
+                <File
+                    RelPath = "test\lib\nunit.core.dll"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "test\lib\nunit.core.interfaces.dll"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "test\lib\nunit.framework.dll"
+                    BuildAction = "Content"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\AdditionalInformationSyntaxUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\AdmissionsUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\AdmissionSyntaxUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ASN1SequenceParserTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ASN1UnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\AttributeTableUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\BiometricDataUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\BitStringConstantTester.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\BitStringTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\CertHashUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\CertificateTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\CMSTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\CommitmentTypeIndicationUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\CommitmentTypeQualifierUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ContentHintsUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\CscaMasterListTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\DataGroupHashUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\DeclarationOfMajorityUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\DERApplicationSpecificTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\DERUTF8StringTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\EncryptedPrivateKeyInfoTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\EqualsAndHashCodeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\EnumeratedTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\EssCertIDv2UnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\GeneralizedTimeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\GeneralNameTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\GenerationTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\InputStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\Iso4217CurrencyCodeUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\IssuingDistributionPointTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\KeyUsageTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\LDSSecurityObjectUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\MiscTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\MonetaryLimitUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\MonetaryValueUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\NameOrPseudonymUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\NamingAuthorityUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\NetscapeCertTypeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\OCSPTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\OctetStringTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\OIDTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\OtherCertIDUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\OtherSigningCertificateUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ParseTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ParsingTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\PersonalDataUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\PKCS10Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\PKCS12Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\PKIFailureInfoTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ProcurationSyntaxUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ProfessionInfoUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\QCStatementUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\ReasonFlagsTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\RegressionTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\RequestedCertificateUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\RestrictionUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\SemanticsInformationUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\SetTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\SignerLocationUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\SMIMETest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\StringTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\SubjectKeyIdentifierTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\TagTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\TargetInformationTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\TimeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\TypeOfBiometricDataUnitTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\UTCTimeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\X509ExtensionsTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\X509NameTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\asn1\test\X9Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\AuthenticatedDataStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\AuthenticatedDataTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\CMSSampleMessages.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\CMSTestUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\CompressedDataStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\CompressedDataTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\EnvelopedDataStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\EnvelopedDataTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\MiscDataStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\Rfc4134Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\SignedDataStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\cms\test\SignedDataTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\examples\DESExample.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\io\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\io\test\CipherStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\AeadTestUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\AESFastTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\AESLightTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\AESTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\AESWrapTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\BlockCipherMonteCarloTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\BlockCipherVectorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\BlowfishTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\CamelliaLightTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\CamelliaTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Cast5Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\CAST6Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\CCMTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ChaChaTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\CipherTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\CMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\CTSTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DESedeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DESTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DeterministicDSATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DHKEKGeneratorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DHTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DigestRandomNumberTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\DSATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\EAXTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ECDHKEKGeneratorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ECGOST3410Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ECIESTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ECNRTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ECTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ElGamalTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\EqualsHashCodeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GcmReorderTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GCMTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\OCBTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GOST28147MacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GOST28147Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GOST3410Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\GOST3411DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\HCFamilyTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\HCFamilyVecTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\IDEATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ISAACTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ISO9796Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ISO9797Alg3MacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\KDF1GeneratorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\KDF2GeneratorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\MacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\MD2DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\MD4DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\MD5DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\MD5HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\MGF1GeneratorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ModeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\NaccacheSternTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\NoekeonTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\NullTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\OAEPTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\PaddingTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Pkcs12Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Pkcs5Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Poly1305Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\PSSBlindTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\PSSTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RC2Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RC2WrapTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RC4Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RC5Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RC6Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RegressionTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RFC3211WrapTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RijndaelTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RipeMD128DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RipeMD128HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RipeMD160DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RipeMD160HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RipeMD256DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RipeMD320DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RSABlindedTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\RsaTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Salsa20Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SCryptTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SEEDTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SerpentTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA1DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA1HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA224DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA224HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA256DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA256HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA3DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA384DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA384HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA512DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA512t224DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA512t256DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SHA512HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\ShortenedDigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SipHashTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SkeinDigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SkeinMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SkipjackTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SM3DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\SRP6Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\StreamCipherVectorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\TEATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\TigerDigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Threefish1024Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Threefish256Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\Threefish512Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\TwofishTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\VMPCKSA3Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\VMPCMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\VMPCTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\WhirlpoolDigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\XSalsa20Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\test\XTEATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\MockTlsClient.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\MockTlsServer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\TlsClientTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\TlsServerTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\crypto\tls\test\TlsTestUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\ec\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\ec\test\ECPointPerformanceTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\ec\test\ECAlgorithmsTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\ec\test\ECPointTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\ec\test\F2mProofer.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\ec\test\TnafTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\math\test\BigIntegerTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\ocsp\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\ocsp\test\OCSPTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\ocsp\test\OCSPTestUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\ByteArrayHandler.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\ClearSignedFileProcessor.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\DetachedSignatureProcessor.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\DirectKeySignature.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\DsaElGamalKeyRingGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\KeyBasedFileProcessor.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\KeyBasedLargeFileProcessor.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\PbeFileProcessor.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\PgpExampleUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\PublicKeyRingDump.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\RsaKeyRingGenerator.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\SignedFileProcessor.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\examples\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\DSA2Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPArmoredTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPClearSignedSignatureTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPCompressionTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPDSAElGamalTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPDSATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PgpKeyRingTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PgpMarkerTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPNoPrivateKeyTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPPacketTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPPBETest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPRSATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\PGPSignatureTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openpgp\test\RegressionTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openssl\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openssl\test\ReaderTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\openssl\test\WriterTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\pkcs\examples\PKCS12Example.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\pkcs\test\EncryptedPrivateKeyInfoTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\pkcs\test\PKCS10Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\pkcs\test\PKCS12StoreTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\security\test\SecureRandomTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\security\test\TestDigestUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\security\test\TestDotNetUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\security\test\TestEncodings.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\security\test\TestParameterUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\security\test\TestSignerUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\AESSICTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\AESTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\AttrCertSelectorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\AttrCertTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\BaseBlockCipherTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\BlockCipherTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CamelliaTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CertPathBuilderTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CertPathTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CertPathValidatorTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CertTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CipherStreamTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\CRL5Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\DESedeTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\DHTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\DigestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\DSATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\ECDSA5Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\ECEncodingTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\ECNRTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\ElGamalTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\EncryptedPrivateKeyInfoTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\FIPSDESTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\GOST28147Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\GOST3410Test.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\HMacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\IESTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\MacTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\MqvTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\NamedCurveTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\NistCertPathTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\NoekeonTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\PBETest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\PEMData.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\PKCS10CertRequestTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\PkixNameConstraintsTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\PkixPolicyMappingTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\PkixTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\PSSTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\RegressionTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\RSATest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\SEEDTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\SigTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\TestUtilities.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\WrapTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\X509CertificatePairTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\X509StoreTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\nist\NistCertPathTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\test\rsa3\RSA3CertTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\tsp\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\tsp\test\GenTimeAccuracyTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\tsp\test\ParseTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\tsp\test\TimeStampTokenInfoTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\tsp\test\TSPTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\tsp\test\TSPTestUtil.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\io\pem\test\AllTests.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\net\test\IPAddressTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\FixedSecureRandom.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\ITest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\ITestResult.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\NumberParsing.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\SimpleTest.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\SimpleTestResult.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\TestFailedException.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\util\test\UncloseableStream.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
+                    RelPath = "test\src\x509\test\TestCertificateGen.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+            </Include>
+        </Files>
+    </CSHARP>
+</VisualStudioProject>
+
diff --git a/crypto/src/AssemblyInfo.cs b/crypto/src/AssemblyInfo.cs
index 7064bf82e..7dd625878 100644
--- a/crypto/src/AssemblyInfo.cs
+++ b/crypto/src/AssemblyInfo.cs
@@ -9,17 +9,12 @@ using System.Runtime.InteropServices;
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 //
-#if INCLUDE_IDEA
-[assembly: AssemblyTitle("BouncyCastle.CryptoExt")]
-[assembly: AssemblyDescription("Bouncy Castle Cryptography API (Extended)")]
-#else
 [assembly: AssemblyTitle("BouncyCastle.Crypto")]
 [assembly: AssemblyDescription("Bouncy Castle Cryptography API")]
-#endif
 [assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("The Legion of the Bouncy Castle")]
+[assembly: AssemblyCompany("The Legion of the Bouncy Castle Inc.")]
 [assembly: AssemblyProduct("Bouncy Castle for .NET")]
-[assembly: AssemblyCopyright("Copyright (C) 2000-2011")]
+[assembly: AssemblyCopyright("Copyright (C) 2000-2014")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -30,8 +25,11 @@ using System.Runtime.InteropServices;
 //      Minor Version
 //      Build Number
 //      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
 
-[assembly: AssemblyVersion(AssemblyInfo.Version)]
+[assembly: AssemblyVersion("1.8.*")]
 
 //
 // In order to sign your assembly you must specify a key to use. Refer to the
@@ -67,6 +65,7 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyKeyName("")]
 
 [assembly: CLSCompliant(true)]
+[assembly: ComVisible(false)]
 
 // Start with no permissions
 //[assembly: PermissionSet(SecurityAction.RequestOptional, Unrestricted=false)]
@@ -75,8 +74,3 @@ using System.Runtime.InteropServices;
 // see Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.StrictLengthEnabledProperty
 //[assembly: EnvironmentPermission(SecurityAction.RequestOptional, Read="Org.BouncyCastle.Pkcs1.Strict")]
 
-internal class AssemblyInfo
-{
-    public const string Version = @"1.7.0.0";
-}
-
diff --git a/crypto/src/asn1/ASN1Generator.cs b/crypto/src/asn1/ASN1Generator.cs
new file mode 100644
index 000000000..e56051736
--- /dev/null
+++ b/crypto/src/asn1/ASN1Generator.cs
@@ -0,0 +1,27 @@
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1Generator
+    {
+		private Stream _out;
+
+		protected Asn1Generator(
+			Stream outStream)
+        {
+            _out = outStream;
+        }
+
+		protected Stream Out
+		{
+			get { return _out; }
+		}
+
+		public abstract void AddObject(Asn1Encodable obj);
+
+		public abstract Stream GetRawOutputStream();
+
+		public abstract void Close();
+    }
+}
diff --git a/crypto/src/asn1/ASN1OctetStringParser.cs b/crypto/src/asn1/ASN1OctetStringParser.cs
new file mode 100644
index 000000000..5815aa42f
--- /dev/null
+++ b/crypto/src/asn1/ASN1OctetStringParser.cs
@@ -0,0 +1,10 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1OctetStringParser
+		: IAsn1Convertible
+	{
+		Stream GetOctetStream();
+	}
+}
diff --git a/crypto/src/asn1/ASN1SequenceParser.cs b/crypto/src/asn1/ASN1SequenceParser.cs
new file mode 100644
index 000000000..9e88ac788
--- /dev/null
+++ b/crypto/src/asn1/ASN1SequenceParser.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1SequenceParser
+		: IAsn1Convertible
+	{
+		IAsn1Convertible ReadObject();
+	}
+}
diff --git a/crypto/src/asn1/ASN1SetParser.cs b/crypto/src/asn1/ASN1SetParser.cs
new file mode 100644
index 000000000..d1b9c64e2
--- /dev/null
+++ b/crypto/src/asn1/ASN1SetParser.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1SetParser
+		: IAsn1Convertible
+	{
+		IAsn1Convertible ReadObject();
+	}
+}
diff --git a/crypto/src/asn1/ASN1StreamParser.cs b/crypto/src/asn1/ASN1StreamParser.cs
index 6c256db53..0c6b4413a 100644
--- a/crypto/src/asn1/ASN1StreamParser.cs
+++ b/crypto/src/asn1/ASN1StreamParser.cs
@@ -8,7 +8,9 @@ namespace Org.BouncyCastle.Asn1
 		private readonly Stream _in;
 		private readonly int _limit;
 
-		public Asn1StreamParser(
+        private readonly byte[][] tmpBuffers;
+
+        public Asn1StreamParser(
 			Stream inStream)
 			: this(inStream, Asn1InputStream.FindLimit(inStream))
 		{
@@ -23,7 +25,8 @@ namespace Org.BouncyCastle.Asn1
 
 			this._in = inStream;
 			this._limit = limit;
-		}
+            this.tmpBuffers = new byte[16][];
+        }
 
 		public Asn1StreamParser(
 			byte[] encoding)
@@ -184,9 +187,8 @@ namespace Org.BouncyCastle.Asn1
 						case Asn1Tags.External:
 							return new DerExternalParser(new Asn1StreamParser(defIn));
 						default:
-							// TODO Add DerUnknownTagParser class?
-							return new DerUnknownTag(true, tagNo, defIn.ToArray());
-					}
+                            throw new IOException("unknown tag " + tagNo + " encountered");
+                    }
 				}
 
 				// Some primitive encodings can be handled by parsers too...
@@ -198,7 +200,7 @@ namespace Org.BouncyCastle.Asn1
 
 				try
 				{
-					return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn.ToArray());
+					return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
 				}
 				catch (ArgumentException e)
 				{
diff --git a/crypto/src/asn1/ASN1TaggedObjectParser.cs b/crypto/src/asn1/ASN1TaggedObjectParser.cs
new file mode 100644
index 000000000..32327a269
--- /dev/null
+++ b/crypto/src/asn1/ASN1TaggedObjectParser.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface Asn1TaggedObjectParser
+		: IAsn1Convertible
+	{
+		int TagNo { get; }
+
+		IAsn1Convertible GetObjectParser(int tag, bool isExplicit);
+	}
+}
diff --git a/crypto/src/asn1/Asn1Encodable.cs b/crypto/src/asn1/Asn1Encodable.cs
new file mode 100644
index 000000000..e3dd9a14c
--- /dev/null
+++ b/crypto/src/asn1/Asn1Encodable.cs
@@ -0,0 +1,78 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public abstract class Asn1Encodable
+		: IAsn1Convertible
+    {
+		public const string Der = "DER";
+		public const string Ber = "BER";
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+            Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+
+			aOut.WriteObject(this);
+
+			return bOut.ToArray();
+        }
+
+		public byte[] GetEncoded(
+			string encoding)
+		{
+			if (encoding.Equals(Der))
+			{
+				MemoryStream bOut = new MemoryStream();
+				DerOutputStream dOut = new DerOutputStream(bOut);
+
+				dOut.WriteObject(this);
+
+				return bOut.ToArray();
+			}
+
+			return GetEncoded();
+		}
+
+		/**
+		* Return the DER encoding of the object, null if the DER encoding can not be made.
+		*
+		* @return a DER byte array, null otherwise.
+		*/
+		public byte[] GetDerEncoded()
+		{
+			try
+			{
+				return GetEncoded(Der);
+			}
+			catch (IOException)
+			{
+				return null;
+			}
+		}
+
+		public sealed override int GetHashCode()
+		{
+			return ToAsn1Object().CallAsn1GetHashCode();
+		}
+
+		public sealed override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			IAsn1Convertible other = obj as IAsn1Convertible;
+
+			if (other == null)
+				return false;
+
+			Asn1Object o1 = ToAsn1Object();
+			Asn1Object o2 = other.ToAsn1Object();
+
+			return o1 == o2 || o1.CallAsn1Equals(o2);
+		}
+
+		public abstract Asn1Object ToAsn1Object();
+    }
+}
diff --git a/crypto/src/asn1/Asn1EncodableVector.cs b/crypto/src/asn1/Asn1EncodableVector.cs
new file mode 100644
index 000000000..49532fe57
--- /dev/null
+++ b/crypto/src/asn1/Asn1EncodableVector.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class Asn1EncodableVector
+		: IEnumerable
+    {
+        private IList v = Platform.CreateArrayList();
+
+		public static Asn1EncodableVector FromEnumerable(
+			IEnumerable e)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+			foreach (Asn1Encodable obj in e)
+			{
+				v.Add(obj);
+			}
+			return v;
+		}
+
+//		public Asn1EncodableVector()
+//		{
+//		}
+
+		public Asn1EncodableVector(
+			params Asn1Encodable[] v)
+		{
+			Add(v);
+		}
+
+//		public void Add(
+//			Asn1Encodable obj)
+//		{
+//			v.Add(obj);
+//		}
+
+		public void Add(
+			params Asn1Encodable[] objs)
+		{
+			foreach (Asn1Encodable obj in objs)
+			{
+				v.Add(obj);
+			}
+		}
+
+		public void AddOptional(
+			params Asn1Encodable[] objs)
+		{
+			if (objs != null)
+			{
+				foreach (Asn1Encodable obj in objs)
+				{
+					if (obj != null)
+					{
+						v.Add(obj);
+					}
+				}
+			}
+		}
+
+		public Asn1Encodable this[
+			int index]
+		{
+			get { return (Asn1Encodable) v[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public Asn1Encodable Get(
+            int index)
+        {
+            return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return v.Count; }
+		}
+
+		public int Count
+		{
+			get { return v.Count; }
+		}
+
+		public IEnumerator GetEnumerator()
+		{
+			return v.GetEnumerator();
+		}
+	}
+}
diff --git a/crypto/src/asn1/Asn1Exception.cs b/crypto/src/asn1/Asn1Exception.cs
index dfc1641a4..806cc95d5 100644
--- a/crypto/src/asn1/Asn1Exception.cs
+++ b/crypto/src/asn1/Asn1Exception.cs
@@ -3,7 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.Asn1
 {
-	public class Asn1Exception
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class Asn1Exception
 		: IOException
 	{
 		public Asn1Exception()
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index 9a9761653..18d13c32d 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -7,333 +7,362 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Asn1
 {
-	/**
-	 * 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
-		: FilterStream
-	{
-		private readonly int limit;
-
-		internal static int FindLimit(Stream input)
-		{
-			if (input is LimitedInputStream)
-			{
-				return ((LimitedInputStream)input).GetRemaining();
-			}
-			else if (input is MemoryStream)
-			{
-				MemoryStream mem = (MemoryStream)input;
-				return (int)(mem.Length - mem.Position);
-			}
-
-			return int.MaxValue;
-		}
-
-		public Asn1InputStream(
-			Stream inputStream)
-			: this(inputStream, FindLimit(inputStream))
-		{
-		}
-
-		/**
-		 * 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(
-			Stream	inputStream,
-			int		limit)
-			: base(inputStream)
-		{
-			this.limit = limit;
-		}
-
-		/**
-		 * 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 MemoryStream(input, false), input.Length)
-		{
-		}
-
-		/**
-		* build an object given its tag and the number of bytes to construct it from.
-		*/
-		private Asn1Object BuildObject(
-			int	tag,
-			int	tagNo,
-			int	length)
-		{
-			bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
-
-			DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this.s, length);
-
-			if ((tag & Asn1Tags.Application) != 0)
-			{
-				return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
-			}
-
-			if ((tag & Asn1Tags.Tagged) != 0)
-			{
-				return new Asn1StreamParser(defIn).ReadTaggedObject(isConstructed, tagNo);
-			}
-
-			if (isConstructed)
-			{
-				// TODO There are other tags that may be constructed (e.g. BitString)
-				switch (tagNo)
-				{
-					case Asn1Tags.OctetString:
-						//
-						// yes, people actually do this...
-						//
-						return new BerOctetString(BuildDerEncodableVector(defIn));
-					case Asn1Tags.Sequence:
-						return CreateDerSequence(defIn);
-					case Asn1Tags.Set:
-						return CreateDerSet(defIn);
-					case Asn1Tags.External:
-						return new DerExternal(BuildDerEncodableVector(defIn));                
-					default:
-						return new DerUnknownTag(true, tagNo, defIn.ToArray());
-				}
-			}
-
-			return CreatePrimitiveDerObject(tagNo, defIn.ToArray());
-		}
-
-		internal Asn1EncodableVector BuildEncodableVector()
-		{
-			Asn1EncodableVector v = new Asn1EncodableVector();
-
-			Asn1Object o;
-			while ((o = ReadObject()) != null)
-			{
-				v.Add(o);
-			}
-
-			return v;
-		}
-
-		internal virtual Asn1EncodableVector BuildDerEncodableVector(
-			DefiniteLengthInputStream dIn)
-		{
-			return new Asn1InputStream(dIn).BuildEncodableVector();
-		}
-
-		internal virtual DerSequence CreateDerSequence(
-			DefiniteLengthInputStream dIn)
-		{
-			return DerSequence.FromVector(BuildDerEncodableVector(dIn));
-		}
-
-		internal virtual DerSet CreateDerSet(
-			DefiniteLengthInputStream dIn)
-		{
-			return DerSet.FromVector(BuildDerEncodableVector(dIn), false);
-		}
-
-		public Asn1Object ReadObject()
-		{
-			int tag = ReadByte();
-			if (tag <= 0)
-			{
-				if (tag == 0)
-					throw new IOException("unexpected end-of-contents marker");
-
-				return null;
-			}
-
-			//
-			// calculate tag number
-			//
-			int tagNo = ReadTagNumber(this.s, tag);
-
-			bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
-
-			//
-			// calculate length
-			//
-			int length = ReadLength(this.s, limit);
-
-			if (length < 0) // indefinite length method
-			{
-				if (!isConstructed)
-					throw new IOException("indefinite length primitive encoding encountered");
-
-				IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this.s, limit);
-            	Asn1StreamParser sp = new Asn1StreamParser(indIn, limit);
-
-				if ((tag & Asn1Tags.Application) != 0)
-				{
-					return new BerApplicationSpecificParser(tagNo, sp).ToAsn1Object();
-				}
-
-				if ((tag & Asn1Tags.Tagged) != 0)
-				{
-					return new BerTaggedObjectParser(true, tagNo, sp).ToAsn1Object();
-				}
-
-				// TODO There are other tags that may be constructed (e.g. BitString)
-				switch (tagNo)
-				{
-					case Asn1Tags.OctetString:
-						return new BerOctetStringParser(sp).ToAsn1Object();
-					case Asn1Tags.Sequence:
-						return new BerSequenceParser(sp).ToAsn1Object();
-					case Asn1Tags.Set:
-						return new BerSetParser(sp).ToAsn1Object();
-					case Asn1Tags.External:
-						return new DerExternalParser(sp).ToAsn1Object();
-					default:
-						throw new IOException("unknown BER object encountered");
-				}
-			}
-			else
-			{
-				try
-				{
-					return BuildObject(tag, tagNo, length);
-				}
-				catch (ArgumentException e)
-				{
-					throw new Asn1Exception("corrupted stream detected", e);
-				}
-			}
-		}
-
-		internal static int ReadTagNumber(
-			Stream	s,
-			int		tag)
-		{
-			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.ReadByte();
-
-				// 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.ReadByte();
-				}
-
-				if (b < 0)
-					throw new EndOfStreamException("EOF found inside tag value.");
-
-				tagNo |= (b & 0x7f);
-			}
-
-			return tagNo;
-		}
-
-		internal static int ReadLength(
-			Stream	s,
-			int		limit)
-		{
-			int length = s.ReadByte();
-			if (length < 0)
-				throw new EndOfStreamException("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.ReadByte();
-
-					if (next < 0)
-						throw new EndOfStreamException("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;
-		}
-
-		internal static Asn1Object CreatePrimitiveDerObject(
-			int		tagNo,
-			byte[]	bytes)
-		{
-			switch (tagNo)
-			{
-				case Asn1Tags.BitString:
-					return DerBitString.FromAsn1Octets(bytes);
-				case Asn1Tags.BmpString:
-					return new DerBmpString(bytes);
-				case Asn1Tags.Boolean:
-					return new DerBoolean(bytes);
-				case Asn1Tags.Enumerated:
-					return new DerEnumerated(bytes);
-				case Asn1Tags.GeneralizedTime:
-					return new DerGeneralizedTime(bytes);
-				case Asn1Tags.GeneralString:
-					return new DerGeneralString(bytes);
-				case Asn1Tags.IA5String:
-					return new DerIA5String(bytes);
-				case Asn1Tags.Integer:
-					return new DerInteger(bytes);
-				case Asn1Tags.Null:
-					return DerNull.Instance;   // actual content is ignored (enforce 0 length?)
-				case Asn1Tags.NumericString:
-					return new DerNumericString(bytes);
-				case Asn1Tags.ObjectIdentifier:
-					return new DerObjectIdentifier(bytes);
-				case Asn1Tags.OctetString:
-					return new DerOctetString(bytes);
-				case Asn1Tags.PrintableString:
-					return new DerPrintableString(bytes);
-				case Asn1Tags.T61String:
-					return new DerT61String(bytes);
-				case Asn1Tags.UniversalString:
-					return new DerUniversalString(bytes);
-				case Asn1Tags.UtcTime:
-					return new DerUtcTime(bytes);
-				case Asn1Tags.Utf8String:
-					return new DerUtf8String(bytes);
-				case Asn1Tags.VisibleString:
-					return new DerVisibleString(bytes);
-				default:
-					return new DerUnknownTag(false, tagNo, bytes);
-			}
-		}
-	}
+    /**
+     * 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
+        : FilterStream
+    {
+        private readonly int limit;
+
+        private readonly byte[][] tmpBuffers;
+
+        internal static int FindLimit(Stream input)
+        {
+            if (input is LimitedInputStream)
+            {
+                return ((LimitedInputStream)input).GetRemaining();
+            }
+            else if (input is MemoryStream)
+            {
+                MemoryStream mem = (MemoryStream)input;
+                return (int)(mem.Length - mem.Position);
+            }
+
+            return int.MaxValue;
+        }
+
+        public Asn1InputStream(
+            Stream inputStream)
+            : this(inputStream, FindLimit(inputStream))
+        {
+        }
+
+        /**
+         * 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(
+            Stream	inputStream,
+            int		limit)
+            : base(inputStream)
+        {
+            this.limit = limit;
+            this.tmpBuffers = new byte[16][];
+        }
+
+        /**
+         * 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 MemoryStream(input, false), input.Length)
+        {
+        }
+
+        /**
+        * build an object given its tag and the number of bytes to construct it from.
+        */
+        private Asn1Object BuildObject(
+            int	tag,
+            int	tagNo,
+            int	length)
+        {
+            bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+            DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this.s, length);
+
+            if ((tag & Asn1Tags.Application) != 0)
+            {
+                return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
+            }
+
+            if ((tag & Asn1Tags.Tagged) != 0)
+            {
+                return new Asn1StreamParser(defIn).ReadTaggedObject(isConstructed, tagNo);
+            }
+
+            if (isConstructed)
+            {
+                // TODO There are other tags that may be constructed (e.g. BitString)
+                switch (tagNo)
+                {
+                    case Asn1Tags.OctetString:
+                        //
+                        // yes, people actually do this...
+                        //
+                        return new BerOctetString(BuildDerEncodableVector(defIn));
+                    case Asn1Tags.Sequence:
+                        return CreateDerSequence(defIn);
+                    case Asn1Tags.Set:
+                        return CreateDerSet(defIn);
+                    case Asn1Tags.External:
+                        return new DerExternal(BuildDerEncodableVector(defIn));                
+                    default:
+                        throw new IOException("unknown tag " + tagNo + " encountered");
+                }
+            }
+
+            return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
+        }
+
+        internal Asn1EncodableVector BuildEncodableVector()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            Asn1Object o;
+            while ((o = ReadObject()) != null)
+            {
+                v.Add(o);
+            }
+
+            return v;
+        }
+
+        internal virtual Asn1EncodableVector BuildDerEncodableVector(
+            DefiniteLengthInputStream dIn)
+        {
+            return new Asn1InputStream(dIn).BuildEncodableVector();
+        }
+
+        internal virtual DerSequence CreateDerSequence(
+            DefiniteLengthInputStream dIn)
+        {
+            return DerSequence.FromVector(BuildDerEncodableVector(dIn));
+        }
+
+        internal virtual DerSet CreateDerSet(
+            DefiniteLengthInputStream dIn)
+        {
+            return DerSet.FromVector(BuildDerEncodableVector(dIn), false);
+        }
+
+        public Asn1Object ReadObject()
+        {
+            int tag = ReadByte();
+            if (tag <= 0)
+            {
+                if (tag == 0)
+                    throw new IOException("unexpected end-of-contents marker");
+
+                return null;
+            }
+
+            //
+            // calculate tag number
+            //
+            int tagNo = ReadTagNumber(this.s, tag);
+
+            bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+            //
+            // calculate length
+            //
+            int length = ReadLength(this.s, limit);
+
+            if (length < 0) // indefinite length method
+            {
+                if (!isConstructed)
+                    throw new IOException("indefinite length primitive encoding encountered");
+
+                IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this.s, limit);
+                Asn1StreamParser sp = new Asn1StreamParser(indIn, limit);
+
+                if ((tag & Asn1Tags.Application) != 0)
+                {
+                    return new BerApplicationSpecificParser(tagNo, sp).ToAsn1Object();
+                }
+
+                if ((tag & Asn1Tags.Tagged) != 0)
+                {
+                    return new BerTaggedObjectParser(true, tagNo, sp).ToAsn1Object();
+                }
+
+                // TODO There are other tags that may be constructed (e.g. BitString)
+                switch (tagNo)
+                {
+                    case Asn1Tags.OctetString:
+                        return new BerOctetStringParser(sp).ToAsn1Object();
+                    case Asn1Tags.Sequence:
+                        return new BerSequenceParser(sp).ToAsn1Object();
+                    case Asn1Tags.Set:
+                        return new BerSetParser(sp).ToAsn1Object();
+                    case Asn1Tags.External:
+                        return new DerExternalParser(sp).ToAsn1Object();
+                    default:
+                        throw new IOException("unknown BER object encountered");
+                }
+            }
+            else
+            {
+                try
+                {
+                    return BuildObject(tag, tagNo, length);
+                }
+                catch (ArgumentException e)
+                {
+                    throw new Asn1Exception("corrupted stream detected", e);
+                }
+            }
+        }
+
+        internal static int ReadTagNumber(
+            Stream	s,
+            int		tag)
+        {
+            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.ReadByte();
+
+                // 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.ReadByte();
+                }
+
+                if (b < 0)
+                    throw new EndOfStreamException("EOF found inside tag value.");
+
+                tagNo |= (b & 0x7f);
+            }
+
+            return tagNo;
+        }
+
+        internal static int ReadLength(
+            Stream	s,
+            int		limit)
+        {
+            int length = s.ReadByte();
+            if (length < 0)
+                throw new EndOfStreamException("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.ReadByte();
+
+                    if (next < 0)
+                        throw new EndOfStreamException("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;
+        }
+
+        internal static byte[] GetBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
+        {
+            int len = defIn.GetRemaining();
+            if (len >= tmpBuffers.Length)
+            {
+                return defIn.ToArray();
+            }
+
+            byte[] buf = tmpBuffers[len];
+            if (buf == null)
+            {
+                buf = tmpBuffers[len] = new byte[len];
+            }
+
+            defIn.ReadAllIntoByteArray(buf);
+
+            return buf;
+        }
+
+        internal static Asn1Object CreatePrimitiveDerObject(
+            int                         tagNo,
+            DefiniteLengthInputStream   defIn,
+            byte[][]                    tmpBuffers)
+        {
+            switch (tagNo)
+            {
+                case Asn1Tags.Boolean:
+                    return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
+                case Asn1Tags.Enumerated:
+                    return DerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
+                case Asn1Tags.ObjectIdentifier:
+                    return DerObjectIdentifier.FromOctetString(GetBuffer(defIn, tmpBuffers));
+            }
+
+            byte[] bytes = defIn.ToArray();
+
+            switch (tagNo)
+            {
+                case Asn1Tags.BitString:
+                    return DerBitString.FromAsn1Octets(bytes);
+                case Asn1Tags.BmpString:
+                    return new DerBmpString(bytes);
+                case Asn1Tags.GeneralizedTime:
+                    return new DerGeneralizedTime(bytes);
+                case Asn1Tags.GeneralString:
+                    return new DerGeneralString(bytes);
+                case Asn1Tags.IA5String:
+                    return new DerIA5String(bytes);
+                case Asn1Tags.Integer:
+                    return new DerInteger(bytes);
+                case Asn1Tags.Null:
+                    return DerNull.Instance;   // actual content is ignored (enforce 0 length?)
+                case Asn1Tags.NumericString:
+                    return new DerNumericString(bytes);
+                case Asn1Tags.OctetString:
+                    return new DerOctetString(bytes);
+                case Asn1Tags.PrintableString:
+                    return new DerPrintableString(bytes);
+                case Asn1Tags.T61String:
+                    return new DerT61String(bytes);
+                case Asn1Tags.UniversalString:
+                    return new DerUniversalString(bytes);
+                case Asn1Tags.UtcTime:
+                    return new DerUtcTime(bytes);
+                case Asn1Tags.Utf8String:
+                    return new DerUtf8String(bytes);
+                case Asn1Tags.VisibleString:
+                    return new DerVisibleString(bytes);
+                default:
+                    throw new IOException("unknown tag " + tagNo + " encountered");
+            }
+        }
+    }
 }
diff --git a/crypto/src/asn1/Asn1Null.cs b/crypto/src/asn1/Asn1Null.cs
new file mode 100644
index 000000000..d54019f67
--- /dev/null
+++ b/crypto/src/asn1/Asn1Null.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * A Null object.
+     */
+    public abstract class Asn1Null
+        : Asn1Object
+    {
+        internal Asn1Null()
+        {
+        }
+
+		public override string ToString()
+		{
+			return "NULL";
+		}
+    }
+}
diff --git a/crypto/src/asn1/Asn1Object.cs b/crypto/src/asn1/Asn1Object.cs
new file mode 100644
index 000000000..08bd599c1
--- /dev/null
+++ b/crypto/src/asn1/Asn1Object.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1Object
+		: Asn1Encodable
+    {
+		/// <summary>Create a base ASN.1 object from a byte array.</summary>
+		/// <param name="data">The byte array to parse.</param>
+		/// <returns>The base ASN.1 object represented by the byte array.</returns>
+		/// <exception cref="IOException">If there is a problem parsing the data.</exception>
+		public static Asn1Object FromByteArray(
+			byte[] data)
+		{
+			try
+			{
+				return new Asn1InputStream(data).ReadObject();
+			}
+			catch (InvalidCastException)
+			{
+				throw new IOException("cannot recognise object in stream");    
+			}
+		}
+
+		/// <summary>Read a base ASN.1 object from a stream.</summary>
+		/// <param name="inStr">The stream to parse.</param>
+		/// <returns>The base ASN.1 object represented by the byte array.</returns>
+		/// <exception cref="IOException">If there is a problem parsing the data.</exception>
+		public static Asn1Object FromStream(
+			Stream inStr)
+		{
+			try
+			{
+				return new Asn1InputStream(inStr).ReadObject();
+			}
+			catch (InvalidCastException)
+			{
+				throw new IOException("cannot recognise object in stream");    
+			}
+		}
+
+		public sealed override Asn1Object ToAsn1Object()
+        {
+            return this;
+        }
+
+		internal abstract void Encode(DerOutputStream derOut);
+
+		protected abstract bool Asn1Equals(Asn1Object asn1Object);
+		protected abstract int Asn1GetHashCode();
+
+		internal bool CallAsn1Equals(Asn1Object obj)
+		{
+			return Asn1Equals(obj);
+		}
+
+		internal int CallAsn1GetHashCode()
+		{
+			return Asn1GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/asn1/Asn1OctetString.cs b/crypto/src/asn1/Asn1OctetString.cs
new file mode 100644
index 000000000..9c738a8f2
--- /dev/null
+++ b/crypto/src/asn1/Asn1OctetString.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1OctetString
+        : Asn1Object, Asn1OctetStringParser
+    {
+        internal byte[] str;
+
+		/**
+         * return an Octet string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *              be converted.
+         */
+		public static Asn1OctetString GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is Asn1OctetString)
+			{
+				return GetInstance(o);
+			}
+
+			return BerOctetString.FromSequence(Asn1Sequence.GetInstance(o));
+		}
+
+        /**
+         * return an Octet string from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+		public static Asn1OctetString GetInstance(object obj)
+		{
+			if (obj == null || obj is Asn1OctetString)
+			{
+				return (Asn1OctetString)obj;
+			}
+
+			// TODO: this needs to be deleted in V2
+			if (obj is Asn1TaggedObject)
+				return GetInstance(((Asn1TaggedObject)obj).GetObject());
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+		}
+
+        /**
+         * @param string the octets making up the octet string.
+         */
+        internal Asn1OctetString(
+            byte[] str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        internal Asn1OctetString(
+            Asn1Encodable obj)
+        {
+            try
+            {
+				this.str = obj.GetEncoded(Asn1Encodable.Der);
+            }
+            catch (IOException e)
+            {
+                throw new ArgumentException("Error processing object : " + e.ToString());
+            }
+        }
+
+		public Stream GetOctetStream()
+		{
+			return new MemoryStream(str, false);
+		}
+
+		public Asn1OctetStringParser Parser
+		{
+			get { return this; }
+		}
+
+		public virtual byte[] GetOctets()
+        {
+            return str;
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return Arrays.GetHashCode(GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerOctetString other = asn1Object as DerOctetString;
+
+			if (other == null)
+				return false;
+
+			return Arrays.AreEqual(GetOctets(), other.GetOctets());
+		}
+
+		public override string ToString()
+		{
+			return "#" + Hex.ToHexString(str);
+		}
+	}
+}
diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs
new file mode 100644
index 000000000..39c8b1e5e
--- /dev/null
+++ b/crypto/src/asn1/Asn1OutputStream.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class Asn1OutputStream
+        : DerOutputStream
+    {
+        public Asn1OutputStream(Stream os) : base(os)
+        {
+        }
+
+		[Obsolete("Use version taking an Asn1Encodable arg instead")]
+        public override void WriteObject(
+            object    obj)
+        {
+            if (obj == null)
+            {
+                WriteNull();
+            }
+            else if (obj is Asn1Object)
+            {
+                ((Asn1Object)obj).Encode(this);
+            }
+            else if (obj is Asn1Encodable)
+            {
+                ((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+            }
+            else
+            {
+                throw new IOException("object not Asn1Encodable");
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/Asn1ParsingException.cs b/crypto/src/asn1/Asn1ParsingException.cs
index 8827d8329..40e5da480 100644
--- a/crypto/src/asn1/Asn1ParsingException.cs
+++ b/crypto/src/asn1/Asn1ParsingException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Asn1
 {
-	public class Asn1ParsingException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class Asn1ParsingException
 		: InvalidOperationException
 	{
 		public Asn1ParsingException()
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index 3131ead84..5f9ea4460 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -8,11 +8,11 @@ using Org.BouncyCastle.Utilities.Collections;
 namespace Org.BouncyCastle.Asn1
 {
     public abstract class Asn1Sequence
-		: Asn1Object, IEnumerable
+        : Asn1Object, IEnumerable
     {
         private readonly IList seq;
 
-		/**
+        /**
          * return an Asn1Sequence from the given object.
          *
          * @param obj the object we want converted.
@@ -25,22 +25,35 @@ namespace Org.BouncyCastle.Asn1
             {
                 return (Asn1Sequence)obj;
             }
-			else if (obj is byte[])
-			{
-				try
-				{
-					return Asn1Sequence.GetInstance(Asn1Object.FromByteArray((byte[])obj));
-				}
-				catch (IOException e)
-				{
-					throw new ArgumentException("Failed to construct sequence from byte[]", e);
-				}
-			}
-
-			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
-		}
-
-		/**
+            else if (obj is Asn1SequenceParser)
+            {
+                return Asn1Sequence.GetInstance(((Asn1SequenceParser)obj).ToAsn1Object());
+            }
+            else if (obj is byte[])
+            {
+                try
+                {
+                    return Asn1Sequence.GetInstance(FromByteArray((byte[])obj));
+                }
+                catch (IOException e)
+                {
+                    throw new ArgumentException("failed to construct sequence from byte[]: " + e.Message);
+                }
+            }
+            else if (obj is Asn1Encodable)
+            {
+                Asn1Object primitive = ((Asn1Encodable)obj).ToAsn1Object();
+                
+                if (primitive is Asn1Sequence)
+                {
+                    return (Asn1Sequence)primitive;
+                }
+            }
+
+            throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
+
+        /**
          * 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
@@ -60,17 +73,17 @@ namespace Org.BouncyCastle.Asn1
             Asn1TaggedObject	obj,
             bool				explicitly)
         {
-			Asn1Object inner = obj.GetObject();
+            Asn1Object inner = obj.GetObject();
 
-			if (explicitly)
+            if (explicitly)
             {
                 if (!obj.IsExplicit())
                     throw new ArgumentException("object implicit - explicit expected.");
 
-				return (Asn1Sequence) inner;
+                return (Asn1Sequence) inner;
             }
 
-			//
+            //
             // constructed object which appears to be explicitly tagged
             // when it should be implicit means we have to add the
             // surrounding sequence.
@@ -82,78 +95,78 @@ namespace Org.BouncyCastle.Asn1
                     return new BerSequence(inner);
                 }
 
-				return new DerSequence(inner);
+                return new DerSequence(inner);
             }
 
-			if (inner is Asn1Sequence)
+            if (inner is Asn1Sequence)
             {
                 return (Asn1Sequence) inner;
             }
 
-			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
-		}
+            throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
 
-		protected internal Asn1Sequence(
-			int capacity)
-		{
+        protected internal Asn1Sequence(
+            int capacity)
+        {
             seq = Platform.CreateArrayList(capacity);
-		}
+        }
 
-		public virtual IEnumerator GetEnumerator()
-		{
-			return seq.GetEnumerator();
-		}
+        public virtual IEnumerator GetEnumerator()
+        {
+            return seq.GetEnumerator();
+        }
 
-		[Obsolete("Use GetEnumerator() instead")]
-		public IEnumerator GetObjects()
+        [Obsolete("Use GetEnumerator() instead")]
+        public IEnumerator GetObjects()
         {
             return GetEnumerator();
         }
 
-		private class Asn1SequenceParserImpl
-			: Asn1SequenceParser
-		{
-			private readonly Asn1Sequence outer;
-			private readonly int max;
-			private int index;
+        private class Asn1SequenceParserImpl
+            : Asn1SequenceParser
+        {
+            private readonly Asn1Sequence outer;
+            private readonly int max;
+            private int index;
 
-			public Asn1SequenceParserImpl(
-				Asn1Sequence outer)
-			{
-				this.outer = outer;
-				this.max = outer.Count;
-			}
+            public Asn1SequenceParserImpl(
+                Asn1Sequence outer)
+            {
+                this.outer = outer;
+                this.max = outer.Count;
+            }
 
-			public IAsn1Convertible ReadObject()
-			{
-				if (index == max)
-					return null;
+            public IAsn1Convertible ReadObject()
+            {
+                if (index == max)
+                    return null;
 
-				Asn1Encodable obj = outer[index++];
+                Asn1Encodable obj = outer[index++];
 
-				if (obj is Asn1Sequence)
-					return ((Asn1Sequence)obj).Parser;
+                if (obj is Asn1Sequence)
+                    return ((Asn1Sequence)obj).Parser;
 
-				if (obj is Asn1Set)
-					return ((Asn1Set)obj).Parser;
+                if (obj is Asn1Set)
+                    return ((Asn1Set)obj).Parser;
 
-				// NB: Asn1OctetString implements Asn1OctetStringParser directly
+                // NB: Asn1OctetString implements Asn1OctetStringParser directly
 //				if (obj is Asn1OctetString)
 //					return ((Asn1OctetString)obj).Parser;
 
-				return obj;
-			}
+                return obj;
+            }
 
-			public Asn1Object ToAsn1Object()
-			{
-				return outer;
-			}
-		}
+            public Asn1Object ToAsn1Object()
+            {
+                return outer;
+            }
+        }
 
-		public virtual Asn1SequenceParser Parser
-		{
-			get { return new Asn1SequenceParserImpl(this); }
-		}
+        public virtual Asn1SequenceParser Parser
+        {
+            get { return new Asn1SequenceParserImpl(this); }
+        }
 
         /**
          * return the object at the sequence position indicated by index.
@@ -161,95 +174,95 @@ namespace Org.BouncyCastle.Asn1
          * @param index the sequence number (starting at zero) of the object
          * @return the object at the sequence position indicated by index.
          */
-		public virtual Asn1Encodable this[int index]
-		{
-			get { return (Asn1Encodable) seq[index]; }
-		}
+        public virtual Asn1Encodable this[int index]
+        {
+            get { return (Asn1Encodable) seq[index]; }
+        }
 
-		[Obsolete("Use 'object[index]' syntax instead")]
+        [Obsolete("Use 'object[index]' syntax instead")]
         public Asn1Encodable GetObjectAt(
             int index)
         {
              return this[index];
         }
 
-		[Obsolete("Use 'Count' property instead")]
-		public int Size
+        [Obsolete("Use 'Count' property instead")]
+        public int Size
         {
-			get { return Count; }
+            get { return Count; }
         }
 
-		public virtual int Count
-		{
-			get { return seq.Count; }
-		}
+        public virtual int Count
+        {
+            get { return seq.Count; }
+        }
 
-		protected override int Asn1GetHashCode()
-		{
-			int hc = Count;
+        protected override int Asn1GetHashCode()
+        {
+            int hc = Count;
 
-			foreach (object o in this)
-			{
-				hc *= 17;
-				if (o == null)
-				{
-					hc ^= DerNull.Instance.GetHashCode();
-				}
-				else
+            foreach (object o in this)
+            {
+                hc *= 17;
+                if (o == null)
                 {
-					hc ^= o.GetHashCode();
+                    hc ^= DerNull.Instance.GetHashCode();
+                }
+                else
+                {
+                    hc ^= o.GetHashCode();
                 }
             }
 
-			return hc;
+            return hc;
         }
 
-		protected override bool Asn1Equals(
-			Asn1Object asn1Object)
-		{
-			Asn1Sequence other = asn1Object as Asn1Sequence;
+        protected override bool Asn1Equals(
+            Asn1Object asn1Object)
+        {
+            Asn1Sequence other = asn1Object as Asn1Sequence;
 
-			if (other == null)
+            if (other == null)
                 return false;
 
-			if (Count != other.Count)
+            if (Count != other.Count)
                 return false;
 
-			IEnumerator s1 = GetEnumerator();
+            IEnumerator s1 = GetEnumerator();
             IEnumerator s2 = other.GetEnumerator();
 
-			while (s1.MoveNext() && s2.MoveNext())
-			{
-				Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
-				Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+            while (s1.MoveNext() && s2.MoveNext())
+            {
+                Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+                Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
 
-				if (!o1.Equals(o2))
-					return false;
-			}
+                if (!o1.Equals(o2))
+                    return false;
+            }
 
-			return true;
+            return true;
         }
 
-		private Asn1Encodable GetCurrent(IEnumerator e)
-		{
-			Asn1Encodable encObj = (Asn1Encodable)e.Current;
+        private Asn1Encodable GetCurrent(IEnumerator e)
+        {
+            Asn1Encodable encObj = (Asn1Encodable)e.Current;
 
-			// unfortunately null was allowed as a substitute for DER null
-			if (encObj == null)
-				return DerNull.Instance;
+            // unfortunately null was allowed as a substitute for DER null
+            if (encObj == null)
+                return DerNull.Instance;
 
-			return encObj;
-		}
+            return encObj;
+        }
 
-		protected internal void AddObject(
+        protected internal void AddObject(
             Asn1Encodable obj)
         {
             seq.Add(obj);
         }
 
-		public override string ToString()
-		{
-			return CollectionUtilities.ToString(seq);
-		}
+        public override string ToString()
+        {
+            return CollectionUtilities.ToString(seq);
+        }
     }
 }
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index f5b66495c..2e77ca2a9 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections;
+using System.IO;
 
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
@@ -11,7 +12,7 @@ namespace Org.BouncyCastle.Asn1
     {
         private readonly IList _set;
 
-		/**
+        /**
          * return an ASN1Set from the given object.
          *
          * @param obj the object we want converted.
@@ -24,8 +25,32 @@ namespace Org.BouncyCastle.Asn1
             {
                 return (Asn1Set)obj;
             }
+            else if (obj is Asn1SetParser)
+            {
+                return Asn1Set.GetInstance(((Asn1SetParser)obj).ToAsn1Object());
+            }
+            else if (obj is byte[])
+            {
+                try
+                {
+                    return Asn1Set.GetInstance(FromByteArray((byte[])obj));
+                }
+                catch (IOException e)
+                {
+                    throw new ArgumentException("failed to construct set from byte[]: " + e.Message);
+                }
+            }
+            else if (obj is Asn1Encodable)
+            {
+                Asn1Object primitive = ((Asn1Encodable)obj).ToAsn1Object();
+
+                if (primitive is Asn1Set)
+                {
+                    return (Asn1Set)primitive;
+                }
+            }
 
-			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+            throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
         }
 
         /**
@@ -48,17 +73,17 @@ namespace Org.BouncyCastle.Asn1
             Asn1TaggedObject	obj,
             bool				explicitly)
         {
-			Asn1Object inner = obj.GetObject();
+            Asn1Object inner = obj.GetObject();
 
-			if (explicitly)
+            if (explicitly)
             {
                 if (!obj.IsExplicit())
                     throw new ArgumentException("object implicit - explicit expected.");
 
-				return (Asn1Set) inner;
+                return (Asn1Set) inner;
             }
 
-			//
+            //
             // constructed object which appears to be explicitly tagged
             // and it's really implicit means we have to add the
             // surrounding sequence.
@@ -68,7 +93,7 @@ namespace Org.BouncyCastle.Asn1
                 return new DerSet(inner);
             }
 
-			if (inner is Asn1Set)
+            if (inner is Asn1Set)
             {
                 return (Asn1Set) inner;
             }
@@ -77,250 +102,250 @@ namespace Org.BouncyCastle.Asn1
             // in this case the parser returns a sequence, convert it
             // into a set.
             //
-			if (inner is Asn1Sequence)
+            if (inner is Asn1Sequence)
             {
-				Asn1EncodableVector v = new Asn1EncodableVector();
-				Asn1Sequence s = (Asn1Sequence) inner;
+                Asn1EncodableVector v = new Asn1EncodableVector();
+                Asn1Sequence s = (Asn1Sequence) inner;
 
-				foreach (Asn1Encodable ae in s)
-				{
+                foreach (Asn1Encodable ae in s)
+                {
                     v.Add(ae);
                 }
 
-				// TODO Should be able to construct set directly from sequence?
-				return new DerSet(v, false);
+                // TODO Should be able to construct set directly from sequence?
+                return new DerSet(v, false);
             }
 
-			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
-		}
+            throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
 
-		protected internal Asn1Set(
-			int capacity)
+        protected internal Asn1Set(
+            int capacity)
         {
-			_set = Platform.CreateArrayList(capacity);
+            _set = Platform.CreateArrayList(capacity);
         }
 
-		public virtual IEnumerator GetEnumerator()
-		{
-			return _set.GetEnumerator();
-		}
+        public virtual IEnumerator GetEnumerator()
+        {
+            return _set.GetEnumerator();
+        }
 
-		[Obsolete("Use GetEnumerator() instead")]
+        [Obsolete("Use GetEnumerator() instead")]
         public IEnumerator GetObjects()
         {
             return GetEnumerator();
         }
 
-		/**
+        /**
          * 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 virtual Asn1Encodable this[int index]
-		{
-			get { return (Asn1Encodable) _set[index]; }
-		}
+        public virtual Asn1Encodable this[int index]
+        {
+            get { return (Asn1Encodable) _set[index]; }
+        }
 
-		[Obsolete("Use 'object[index]' syntax instead")]
-		public Asn1Encodable GetObjectAt(
+        [Obsolete("Use 'object[index]' syntax instead")]
+        public Asn1Encodable GetObjectAt(
             int index)
         {
              return this[index];
         }
 
-		[Obsolete("Use 'Count' property instead")]
-		public int Size
+        [Obsolete("Use 'Count' property instead")]
+        public int Size
         {
-			get { return Count; }
+            get { return Count; }
         }
 
-		public virtual int Count
-		{
-			get { return _set.Count; }
-		}
-
-		public virtual Asn1Encodable[] ToArray()
-		{
-			Asn1Encodable[] values = new Asn1Encodable[this.Count];
-			for (int i = 0; i < this.Count; ++i)
-			{
-				values[i] = this[i];
-			}
-			return values;
-		}
-
-		private class Asn1SetParserImpl
-			: Asn1SetParser
-		{
-			private readonly Asn1Set outer;
-			private readonly int max;
-			private int index;
-
-			public Asn1SetParserImpl(
-				Asn1Set outer)
-			{
-				this.outer = outer;
-				this.max = outer.Count;
-			}
-
-			public IAsn1Convertible ReadObject()
-			{
-				if (index == max)
-					return null;
-
-				Asn1Encodable obj = outer[index++];
-				if (obj is Asn1Sequence)
-					return ((Asn1Sequence)obj).Parser;
-
-				if (obj is Asn1Set)
-					return ((Asn1Set)obj).Parser;
-
-				// NB: Asn1OctetString implements Asn1OctetStringParser directly
+        public virtual int Count
+        {
+            get { return _set.Count; }
+        }
+
+        public virtual Asn1Encodable[] ToArray()
+        {
+            Asn1Encodable[] values = new Asn1Encodable[this.Count];
+            for (int i = 0; i < this.Count; ++i)
+            {
+                values[i] = this[i];
+            }
+            return values;
+        }
+
+        private class Asn1SetParserImpl
+            : Asn1SetParser
+        {
+            private readonly Asn1Set outer;
+            private readonly int max;
+            private int index;
+
+            public Asn1SetParserImpl(
+                Asn1Set outer)
+            {
+                this.outer = outer;
+                this.max = outer.Count;
+            }
+
+            public IAsn1Convertible ReadObject()
+            {
+                if (index == max)
+                    return null;
+
+                Asn1Encodable obj = outer[index++];
+                if (obj is Asn1Sequence)
+                    return ((Asn1Sequence)obj).Parser;
+
+                if (obj is Asn1Set)
+                    return ((Asn1Set)obj).Parser;
+
+                // NB: Asn1OctetString implements Asn1OctetStringParser directly
 //				if (obj is Asn1OctetString)
 //					return ((Asn1OctetString)obj).Parser;
 
-				return obj;
-			}
+                return obj;
+            }
 
-			public virtual Asn1Object ToAsn1Object()
-			{
-				return outer;
-			}
-		}
+            public virtual Asn1Object ToAsn1Object()
+            {
+                return outer;
+            }
+        }
 
-		public Asn1SetParser Parser
-		{
-			get { return new Asn1SetParserImpl(this); }
-		}
+        public Asn1SetParser Parser
+        {
+            get { return new Asn1SetParserImpl(this); }
+        }
 
-		protected override int Asn1GetHashCode()
-		{
+        protected override int Asn1GetHashCode()
+        {
             int hc = Count;
 
-			foreach (object o in this)
-			{
-				hc *= 17;
-				if (o == null)
-				{
-					hc ^= DerNull.Instance.GetHashCode();
-				}
-				else
+            foreach (object o in this)
+            {
+                hc *= 17;
+                if (o == null)
                 {
-					hc ^= o.GetHashCode();
+                    hc ^= DerNull.Instance.GetHashCode();
+                }
+                else
+                {
+                    hc ^= o.GetHashCode();
                 }
             }
 
-			return hc;
+            return hc;
         }
 
-		protected override bool Asn1Equals(
-			Asn1Object asn1Object)
+        protected override bool Asn1Equals(
+            Asn1Object asn1Object)
         {
-			Asn1Set other = asn1Object as Asn1Set;
+            Asn1Set other = asn1Object as Asn1Set;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			if (Count != other.Count)
+            if (Count != other.Count)
             {
                 return false;
             }
 
-			IEnumerator s1 = GetEnumerator();
+            IEnumerator s1 = GetEnumerator();
             IEnumerator s2 = other.GetEnumerator();
 
-			while (s1.MoveNext() && s2.MoveNext())
-			{
-				Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
-				Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+            while (s1.MoveNext() && s2.MoveNext())
+            {
+                Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+                Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
 
-				if (!o1.Equals(o2))
-					return false;
-			}
+                if (!o1.Equals(o2))
+                    return false;
+            }
 
-			return true;
+            return true;
         }
 
-		private Asn1Encodable GetCurrent(IEnumerator e)
-		{
-			Asn1Encodable encObj = (Asn1Encodable)e.Current;
+        private Asn1Encodable GetCurrent(IEnumerator e)
+        {
+            Asn1Encodable encObj = (Asn1Encodable)e.Current;
 
-			// unfortunately null was allowed as a substitute for DER null
-			if (encObj == null)
-				return DerNull.Instance;
+            // unfortunately null was allowed as a substitute for DER null
+            if (encObj == null)
+                return DerNull.Instance;
 
-			return encObj;
-		}
+            return encObj;
+        }
 
-		/**
+        /**
          * return true if a &lt;= b (arrays are assumed padded with zeros).
          */
         private bool LessThanOrEqual(
              byte[] a,
              byte[] b)
         {
-			int len = System.Math.Min(a.Length, b.Length);
-			for (int i = 0; i != len; ++i)
-			{
-				if (a[i] != b[i])
-				{
-					return a[i] < b[i];
-				}
-			}
-			return len == a.Length;
-		}
-
-		protected internal void Sort()
+            int len = System.Math.Min(a.Length, b.Length);
+            for (int i = 0; i != len; ++i)
+            {
+                if (a[i] != b[i])
+                {
+                    return a[i] < b[i];
+                }
+            }
+            return len == a.Length;
+        }
+
+        protected internal void Sort()
         {
-			if (_set.Count > 1)
-			{
-				bool swapped = true;
-				int lastSwap = _set.Count - 1;
-
-				while (swapped)
-				{
-					int index = 0;
-					int swapIndex = 0;
-					byte[] a = ((Asn1Encodable) _set[0]).GetEncoded();
-
-					swapped = false;
-
-					while (index != lastSwap)
-					{
-						byte[] b = ((Asn1Encodable) _set[index + 1]).GetEncoded();
-
-						if (LessThanOrEqual(a, b))
-						{
-							a = b;
-						}
-						else
-						{
-							object o = _set[index];
-							_set[index] = _set[index + 1];
-							_set[index + 1] = o;
-
-							swapped = true;
-							swapIndex = index;
-						}
-
-						index++;
-					}
-
-					lastSwap = swapIndex;
-				}
-			}
+            if (_set.Count > 1)
+            {
+                bool swapped = true;
+                int lastSwap = _set.Count - 1;
+
+                while (swapped)
+                {
+                    int index = 0;
+                    int swapIndex = 0;
+                    byte[] a = ((Asn1Encodable) _set[0]).GetEncoded();
+
+                    swapped = false;
+
+                    while (index != lastSwap)
+                    {
+                        byte[] b = ((Asn1Encodable) _set[index + 1]).GetEncoded();
+
+                        if (LessThanOrEqual(a, b))
+                        {
+                            a = b;
+                        }
+                        else
+                        {
+                            object o = _set[index];
+                            _set[index] = _set[index + 1];
+                            _set[index + 1] = o;
+
+                            swapped = true;
+                            swapIndex = index;
+                        }
+
+                        index++;
+                    }
+
+                    lastSwap = swapIndex;
+                }
+            }
         }
 
-		protected internal void AddObject(
-			Asn1Encodable obj)
+        protected internal void AddObject(
+            Asn1Encodable obj)
         {
             _set.Add(obj);
         }
 
-		public override string ToString()
-		{
-			return CollectionUtilities.ToString(_set);
-		}
-	}
+        public override string ToString()
+        {
+            return CollectionUtilities.ToString(_set);
+        }
+    }
 }
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
new file mode 100644
index 000000000..2e480738a
--- /dev/null
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * 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
+		: Asn1Object, Asn1TaggedObjectParser
+    {
+        internal int            tagNo;
+//        internal bool           empty;
+        internal bool           explicitly = true;
+        internal Asn1Encodable  obj;
+
+		static public Asn1TaggedObject GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            if (explicitly)
+            {
+                return (Asn1TaggedObject) obj.GetObject();
+            }
+
+            throw new ArgumentException("implicitly tagged tagged object");
+        }
+
+		static public Asn1TaggedObject GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Asn1TaggedObject)
+			{
+				return (Asn1TaggedObject) obj;
+			}
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+         * @param tagNo the tag number for this object.
+         * @param obj the tagged object.
+         */
+        protected Asn1TaggedObject(
+            int             tagNo,
+            Asn1Encodable   obj)
+        {
+            this.explicitly = true;
+            this.tagNo = tagNo;
+            this.obj = obj;
+        }
+
+		/**
+         * @param explicitly true if the object is explicitly tagged.
+         * @param tagNo the tag number for this object.
+         * @param obj the tagged object.
+         */
+        protected Asn1TaggedObject(
+            bool            explicitly,
+            int             tagNo,
+            Asn1Encodable   obj)
+        {
+			// IAsn1Choice marker interface 'insists' on explicit tagging
+            this.explicitly = explicitly || (obj is IAsn1Choice);
+            this.tagNo = tagNo;
+            this.obj = obj;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			Asn1TaggedObject other = asn1Object as Asn1TaggedObject;
+
+			if (other == null)
+				return false;
+
+			return this.tagNo == other.tagNo
+//				&& this.empty == other.empty
+				&& this.explicitly == other.explicitly   // TODO Should this be part of equality?
+				&& Platform.Equals(GetObject(), other.GetObject());
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+            int code = tagNo.GetHashCode();
+
+			// 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...
+//			code ^= explicitly.GetHashCode();
+
+			if (obj != null)
+            {
+                code ^= obj.GetHashCode();
+            }
+
+			return code;
+        }
+
+		public int TagNo
+        {
+			get { 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.</p>
+         */
+        public bool IsExplicit()
+        {
+            return explicitly;
+        }
+
+        public bool IsEmpty()
+        {
+            return false; //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.</p>
+         */
+        public Asn1Object GetObject()
+        {
+            if (obj != null)
+            {
+                return obj.ToAsn1Object();
+            }
+
+			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 IAsn1Convertible GetObjectParser(
+			int		tag,
+			bool	isExplicit)
+		{
+			switch (tag)
+			{
+				case Asn1Tags.Set:
+					return Asn1Set.GetInstance(this, isExplicit).Parser;
+				case Asn1Tags.Sequence:
+					return Asn1Sequence.GetInstance(this, isExplicit).Parser;
+				case Asn1Tags.OctetString:
+					return Asn1OctetString.GetInstance(this, isExplicit).Parser;
+			}
+
+			if (isExplicit)
+			{
+				return GetObject();
+			}
+
+			throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag);
+		}
+
+		public override string ToString()
+		{
+			return "[" + tagNo + "]" + obj;
+		}
+	}
+}
diff --git a/crypto/src/asn1/Asn1Tags.cs b/crypto/src/asn1/Asn1Tags.cs
new file mode 100644
index 000000000..32ac6bc6c
--- /dev/null
+++ b/crypto/src/asn1/Asn1Tags.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Asn1
+{
+    public class Asn1Tags
+    {
+        public const int Boolean = 0x01;
+        public const int Integer = 0x02;
+        public const int BitString = 0x03;
+        public const int OctetString = 0x04;
+        public const int Null = 0x05;
+        public const int ObjectIdentifier = 0x06;
+        public const int External = 0x08;
+        public const int Enumerated = 0x0a;
+        public const int Sequence = 0x10;
+        public const int SequenceOf = 0x10; // for completeness
+        public const int Set = 0x11;
+        public const int SetOf = 0x11; // for completeness
+
+        public const int NumericString = 0x12;
+        public const int PrintableString = 0x13;
+        public const int T61String = 0x14;
+        public const int VideotexString = 0x15;
+        public const int IA5String = 0x16;
+        public const int UtcTime = 0x17;
+        public const int GeneralizedTime = 0x18;
+        public const int GraphicString = 0x19;
+        public const int VisibleString = 0x1a;
+        public const int GeneralString = 0x1b;
+        public const int UniversalString = 0x1c;
+        public const int BmpString = 0x1e;
+        public const int Utf8String = 0x0c;
+
+        public const int Constructed = 0x20;
+        public const int Application = 0x40;
+        public const int Tagged = 0x80;
+    }
+}
diff --git a/crypto/src/asn1/BERGenerator.cs b/crypto/src/asn1/BERGenerator.cs
new file mode 100644
index 000000000..271572c02
--- /dev/null
+++ b/crypto/src/asn1/BERGenerator.cs
@@ -0,0 +1,102 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class BerGenerator
+        : Asn1Generator
+    {
+        private bool      _tagged = false;
+        private bool      _isExplicit;
+        private int          _tagNo;
+
+        protected BerGenerator(
+            Stream outStream)
+            : base(outStream)
+        {
+        }
+
+        public BerGenerator(
+            Stream outStream,
+            int tagNo,
+            bool isExplicit)
+            : base(outStream)
+        {
+            _tagged = true;
+            _isExplicit = isExplicit;
+            _tagNo = tagNo;
+        }
+
+		public override void AddObject(
+			Asn1Encodable obj)
+		{
+			new BerOutputStream(Out).WriteObject(obj);
+		}
+
+		public override Stream GetRawOutputStream()
+        {
+            return Out;
+        }
+
+		public override void Close()
+		{
+			WriteBerEnd();
+		}
+
+        private void WriteHdr(
+            int tag)
+        {
+            Out.WriteByte((byte) tag);
+            Out.WriteByte(0x80);
+        }
+
+        protected void WriteBerHeader(
+            int tag)
+        {
+            if (_tagged)
+            {
+                int tagNum = _tagNo | Asn1Tags.Tagged;
+
+                if (_isExplicit)
+                {
+                    WriteHdr(tagNum | Asn1Tags.Constructed);
+                    WriteHdr(tag);
+                }
+                else
+                {
+                    if ((tag & Asn1Tags.Constructed) != 0)
+                    {
+                        WriteHdr(tagNum | Asn1Tags.Constructed);
+                    }
+                    else
+                    {
+                        WriteHdr(tagNum);
+                    }
+                }
+            }
+            else
+            {
+                WriteHdr(tag);
+            }
+        }
+
+		protected void WriteBerBody(
+            Stream contentStream)
+        {
+			Streams.PipeAll(contentStream, Out);
+        }
+
+		protected void WriteBerEnd()
+        {
+            Out.WriteByte(0x00);
+            Out.WriteByte(0x00);
+
+            if (_tagged && _isExplicit)  // write extra end for tag header
+            {
+                Out.WriteByte(0x00);
+                Out.WriteByte(0x00);
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/BEROctetStringGenerator.cs b/crypto/src/asn1/BEROctetStringGenerator.cs
index 644060765..7468a6b0b 100644
--- a/crypto/src/asn1/BEROctetStringGenerator.cs
+++ b/crypto/src/asn1/BEROctetStringGenerator.cs
@@ -42,80 +42,76 @@ namespace Org.BouncyCastle.Asn1
 			return new BufferedBerOctetStream(this, buf);
 		}
 
-        private class BufferedBerOctetStream
-            : BaseOutputStream
-        {
-            private byte[] _buf;
-            private int _off;
-            private readonly BerOctetStringGenerator _gen;
-            private readonly DerOutputStream _derOut;
-
-            internal BufferedBerOctetStream(
-                BerOctetStringGenerator gen,
-                byte[] buf)
-            {
-                _gen = gen;
-                _buf = buf;
-                _off = 0;
-                _derOut = new DerOutputStream(_gen.Out);
-            }
-
-            public override void WriteByte(
-                byte b)
-            {
-                _buf[_off++] = b;
-
-                if (_off == _buf.Length)
-                {
-                    DerOctetString.Encode(_derOut, _buf, 0, _off);
-                    _off = 0;
-                }
-            }
-
-            public override void Write(
-                byte[] buf,
-                int offset,
-                int len)
-            {
-                while (len > 0)
-                {
-                    int numToCopy = System.Math.Min(len, _buf.Length - _off);
-
-                    if (numToCopy == _buf.Length)
-                    {
-                        DerOctetString.Encode(_derOut, buf, offset, numToCopy);
-                    }
-                    else
-                    {
-                        Array.Copy(buf, offset, _buf, _off, numToCopy);
-
-                        _off += numToCopy;
-                        if (_off < _buf.Length)
-                            break;
-
-                        DerOctetString.Encode(_derOut, _buf, 0, _off);
-                        _off = 0;
-                    }
-
-                    offset += numToCopy;
-                    len -= numToCopy;
-                }
-            }
-
-            protected override void Dispose(bool disposing)
-            {
-                if (disposing)
-                {
-                    if (_off != 0)
-                    {
-                        DerOctetString.Encode(_derOut, _buf, 0, _off);
-                    }
-
-                    _gen.WriteBerEnd();
-                }
-
-                base.Dispose(disposing);
-            }
-        }
+		private class BufferedBerOctetStream
+			: BaseOutputStream
+		{
+			private byte[] _buf;
+			private int    _off;
+			private readonly BerOctetStringGenerator _gen;
+			private readonly DerOutputStream _derOut;
+
+			internal BufferedBerOctetStream(
+				BerOctetStringGenerator	gen,
+				byte[]					buf)
+			{
+				_gen = gen;
+				_buf = buf;
+				_off = 0;
+				_derOut = new DerOutputStream(_gen.Out);
+			}
+
+			public override void WriteByte(
+				byte b)
+			{
+				_buf[_off++] = b;
+
+				if (_off == _buf.Length)
+				{
+					DerOctetString.Encode(_derOut, _buf, 0, _off);
+					_off = 0;
+				}
+			}
+
+			public override void Write(
+				byte[] buf,
+				int    offset,
+				int    len)
+			{
+				while (len > 0)
+				{
+					int numToCopy = System.Math.Min(len, _buf.Length - _off);
+
+					if (numToCopy == _buf.Length)
+					{
+						DerOctetString.Encode(_derOut, buf, offset, numToCopy);
+					}
+					else
+					{
+						Array.Copy(buf, offset, _buf, _off, numToCopy);
+
+						_off += numToCopy;
+						if (_off < _buf.Length)
+							break;
+
+						DerOctetString.Encode(_derOut, _buf, 0, _off);
+						_off = 0;
+					}
+
+					offset += numToCopy;
+					len -= numToCopy;
+				}
+			}
+
+			public override void Close()
+			{
+				if (_off != 0)
+				{
+					DerOctetString.Encode(_derOut, _buf, 0, _off);
+				}
+
+				_gen.WriteBerEnd();
+				base.Close();
+			}
+		}
 	}
 }
diff --git a/crypto/src/asn1/BEROctetStringParser.cs b/crypto/src/asn1/BEROctetStringParser.cs
new file mode 100644
index 000000000..3bfd2a98d
--- /dev/null
+++ b/crypto/src/asn1/BEROctetStringParser.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerOctetStringParser
+		: Asn1OctetStringParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal BerOctetStringParser(
+			Asn1StreamParser parser)
+		{
+			_parser = parser;
+		}
+
+		public Stream GetOctetStream()
+		{
+			return new ConstructedOctetStream(_parser);
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			try
+			{
+				return new BerOctetString(Streams.ReadAll(GetOctetStream()));
+			}
+			catch (IOException e)
+			{
+				throw new Asn1ParsingException("IOException converting stream to byte array: " + e.Message, e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/BERSequenceGenerator.cs b/crypto/src/asn1/BERSequenceGenerator.cs
new file mode 100644
index 000000000..5ea2c9b82
--- /dev/null
+++ b/crypto/src/asn1/BERSequenceGenerator.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSequenceGenerator
+		: BerGenerator
+	{
+		public BerSequenceGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
+		}
+
+		public BerSequenceGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
+		}
+	}
+}
diff --git a/crypto/src/asn1/BERSequenceParser.cs b/crypto/src/asn1/BERSequenceParser.cs
new file mode 100644
index 000000000..8474b8d24
--- /dev/null
+++ b/crypto/src/asn1/BERSequenceParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSequenceParser
+		: Asn1SequenceParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal BerSequenceParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new BerSequence(_parser.ReadVector());
+		}
+	}
+}
diff --git a/crypto/src/asn1/BERSetGenerator.cs b/crypto/src/asn1/BERSetGenerator.cs
new file mode 100644
index 000000000..72b1f903a
--- /dev/null
+++ b/crypto/src/asn1/BERSetGenerator.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSetGenerator
+		: BerGenerator
+	{
+		public BerSetGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
+		}
+
+		public BerSetGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
+		}
+	}
+}
diff --git a/crypto/src/asn1/BERSetParser.cs b/crypto/src/asn1/BERSetParser.cs
new file mode 100644
index 000000000..aa9ccbc12
--- /dev/null
+++ b/crypto/src/asn1/BERSetParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSetParser
+		: Asn1SetParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal BerSetParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new BerSet(_parser.ReadVector(), false);
+		}
+	}
+}
diff --git a/crypto/src/asn1/BERTaggedObjectParser.cs b/crypto/src/asn1/BERTaggedObjectParser.cs
new file mode 100644
index 000000000..354437a6a
--- /dev/null
+++ b/crypto/src/asn1/BERTaggedObjectParser.cs
@@ -0,0 +1,71 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerTaggedObjectParser
+		: Asn1TaggedObjectParser
+	{
+		private bool				_constructed;
+		private int					_tagNumber;
+		private Asn1StreamParser	_parser;
+
+		[Obsolete]
+		internal BerTaggedObjectParser(
+			int		baseTag,
+			int		tagNumber,
+			Stream	contentStream)
+			: this((baseTag & Asn1Tags.Constructed) != 0, tagNumber, new Asn1StreamParser(contentStream))
+		{
+		}
+
+		internal BerTaggedObjectParser(
+			bool				constructed,
+			int					tagNumber,
+			Asn1StreamParser	parser)
+		{
+			_constructed = constructed;
+			_tagNumber = tagNumber;
+			_parser = parser;
+		}
+
+		public bool IsConstructed
+		{
+			get { return _constructed; }
+		}
+
+		public int TagNo
+		{
+			get { return _tagNumber; }
+		}
+
+		public IAsn1Convertible GetObjectParser(
+			int		tag,
+			bool	isExplicit)
+		{
+			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 Asn1Object ToAsn1Object()
+		{
+			try
+			{
+				return _parser.ReadTaggedObject(_constructed, _tagNumber);
+			}
+			catch (IOException e)
+			{
+				throw new Asn1ParsingException(e.Message);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/BerApplicationSpecific.cs b/crypto/src/asn1/BerApplicationSpecific.cs
new file mode 100644
index 000000000..65fbecbe1
--- /dev/null
+++ b/crypto/src/asn1/BerApplicationSpecific.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerApplicationSpecific
+		: DerApplicationSpecific
+	{
+		public BerApplicationSpecific(
+			int					tagNo,
+			Asn1EncodableVector	vec)
+			: base(tagNo, vec)
+		{
+		}
+	}
+}
diff --git a/crypto/src/asn1/BerApplicationSpecificParser.cs b/crypto/src/asn1/BerApplicationSpecificParser.cs
new file mode 100644
index 000000000..7d2c4b3e8
--- /dev/null
+++ b/crypto/src/asn1/BerApplicationSpecificParser.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerApplicationSpecificParser
+		: IAsn1ApplicationSpecificParser
+	{
+		private readonly int tag;
+		private readonly Asn1StreamParser parser;
+
+		internal BerApplicationSpecificParser(
+			int					tag,
+			Asn1StreamParser	parser)
+		{
+			this.tag = tag;
+			this.parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new BerApplicationSpecific(tag, parser.ReadVector());
+		}
+	}
+}
diff --git a/crypto/src/asn1/BerNull.cs b/crypto/src/asn1/BerNull.cs
new file mode 100644
index 000000000..0751bbac3
--- /dev/null
+++ b/crypto/src/asn1/BerNull.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * A BER Null object.
+	 */
+	public class BerNull
+		: DerNull
+	{
+		public static new readonly BerNull Instance = new BerNull(0);
+
+		[Obsolete("Use static Instance object")]
+		public BerNull()
+		{
+		}
+
+		private BerNull(int dummy) : base(dummy)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream  derOut)
+		{
+			if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+			{
+				derOut.WriteByte(Asn1Tags.Null);
+			}
+			else
+			{
+				base.Encode(derOut);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/BerOctetString.cs b/crypto/src/asn1/BerOctetString.cs
new file mode 100644
index 000000000..a7c8ad33e
--- /dev/null
+++ b/crypto/src/asn1/BerOctetString.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class BerOctetString
+        : DerOctetString, IEnumerable
+    {
+		public static BerOctetString FromSequence(Asn1Sequence seq)
+		{
+			IList v = Platform.CreateArrayList();
+
+			foreach (Asn1Encodable obj in seq)
+			{
+				v.Add(obj);
+			}
+
+			return new BerOctetString(v);
+		}
+
+		private const int MaxLength = 1000;
+
+		/**
+         * convert a vector of octet strings into a single byte string
+         */
+        private static byte[] ToBytes(
+            IEnumerable octs)
+        {
+            MemoryStream bOut = new MemoryStream();
+			foreach (DerOctetString o in octs)
+			{
+                byte[] octets = o.GetOctets();
+                bOut.Write(octets, 0, octets.Length);
+            }
+			return bOut.ToArray();
+        }
+
+		private readonly IEnumerable octs;
+
+		/// <param name="str">The octets making up the octet string.</param>
+		public BerOctetString(
+			byte[] str)
+			: base(str)
+		{
+		}
+
+		public BerOctetString(
+			IEnumerable octets)
+			: base(ToBytes(octets))
+        {
+            this.octs = octets;
+        }
+
+        public BerOctetString(
+			Asn1Object obj)
+			: base(obj)
+        {
+        }
+
+        public BerOctetString(
+			Asn1Encodable obj)
+			: base(obj.ToAsn1Object())
+        {
+        }
+
+        public override byte[] GetOctets()
+        {
+            return str;
+        }
+
+        /**
+         * return the DER octets that make up this string.
+         */
+		public IEnumerator GetEnumerator()
+		{
+			if (octs == null)
+			{
+				return GenerateOcts().GetEnumerator();
+			}
+
+			return octs.GetEnumerator();
+		}
+
+		[Obsolete("Use GetEnumerator() instead")]
+        public IEnumerator GetObjects()
+        {
+			return GetEnumerator();
+		}
+
+		private IList GenerateOcts()
+        {
+            IList vec = Platform.CreateArrayList();
+			for (int i = 0; i < str.Length; i += MaxLength)
+			{
+				int end = System.Math.Min(str.Length, i + MaxLength);
+
+				byte[] nStr = new byte[end - i];
+
+				Array.Copy(str, i, nStr, 0, nStr.Length);
+
+				vec.Add(new DerOctetString(nStr));
+			}
+			return vec;
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+            {
+                derOut.WriteByte(Asn1Tags.Constructed | Asn1Tags.OctetString);
+
+                derOut.WriteByte(0x80);
+
+                //
+                // write out the octet array
+                //
+                foreach (DerOctetString oct in this)
+                {
+                    derOut.WriteObject(oct);
+                }
+
+				derOut.WriteByte(0x00);
+                derOut.WriteByte(0x00);
+            }
+            else
+            {
+                base.Encode(derOut);
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/BerOutputStream.cs b/crypto/src/asn1/BerOutputStream.cs
new file mode 100644
index 000000000..b3ece10d3
--- /dev/null
+++ b/crypto/src/asn1/BerOutputStream.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	// TODO Make Obsolete in favour of Asn1OutputStream?
+    public class BerOutputStream
+        : DerOutputStream
+    {
+        public BerOutputStream(Stream os) : base(os)
+        {
+        }
+
+		[Obsolete("Use version taking an Asn1Encodable arg instead")]
+        public override void WriteObject(
+            object    obj)
+        {
+            if (obj == null)
+            {
+                WriteNull();
+            }
+            else if (obj is Asn1Object)
+            {
+                ((Asn1Object)obj).Encode(this);
+            }
+            else if (obj is Asn1Encodable)
+            {
+                ((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+            }
+            else
+            {
+                throw new IOException("object not BerEncodable");
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/BerSequence.cs b/crypto/src/asn1/BerSequence.cs
new file mode 100644
index 000000000..70b43fc79
--- /dev/null
+++ b/crypto/src/asn1/BerSequence.cs
@@ -0,0 +1,69 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerSequence
+		: DerSequence
+	{
+		public static new readonly BerSequence Empty = new BerSequence();
+
+		public static new BerSequence FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new BerSequence(v);
+		}
+
+		/**
+		 * create an empty sequence
+		 */
+		public BerSequence()
+		{
+		}
+
+		/**
+		 * create a sequence containing one object
+		 */
+		public BerSequence(
+			Asn1Encodable obj)
+			: base(obj)
+		{
+		}
+
+		public BerSequence(
+			params Asn1Encodable[] v)
+			: base(v)
+		{
+		}
+
+		/**
+		 * create a sequence containing a vector of objects.
+		 */
+		public BerSequence(
+			Asn1EncodableVector v)
+			: base(v)
+		{
+		}
+
+		/*
+		 */
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+			{
+				derOut.WriteByte(Asn1Tags.Sequence | Asn1Tags.Constructed);
+				derOut.WriteByte(0x80);
+
+				foreach (Asn1Encodable o in this)
+				{
+					derOut.WriteObject(o);
+				}
+
+				derOut.WriteByte(0x00);
+				derOut.WriteByte(0x00);
+			}
+			else
+			{
+				base.Encode(derOut);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/BerSet.cs b/crypto/src/asn1/BerSet.cs
new file mode 100644
index 000000000..a181e172d
--- /dev/null
+++ b/crypto/src/asn1/BerSet.cs
@@ -0,0 +1,70 @@
+namespace Org.BouncyCastle.Asn1
+{
+    public class BerSet
+        : DerSet
+    {
+		public static new readonly BerSet Empty = new BerSet();
+
+		public static new BerSet FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new BerSet(v);
+		}
+
+		internal static new BerSet FromVector(
+			Asn1EncodableVector v,
+			bool				needsSorting)
+		{
+			return v.Count < 1 ? Empty : new BerSet(v, needsSorting);
+		}
+
+		/**
+         * create an empty sequence
+         */
+        public BerSet()
+        {
+        }
+
+        /**
+         * create a set containing one object
+         */
+        public BerSet(Asn1Encodable obj) : base(obj)
+        {
+        }
+
+        /**
+         * create a set containing a vector of objects.
+         */
+        public BerSet(Asn1EncodableVector v) : base(v, false)
+        {
+        }
+
+        internal BerSet(Asn1EncodableVector v, bool needsSorting) : base(v, needsSorting)
+        {
+        }
+
+        /*
+         */
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+            {
+                derOut.WriteByte(Asn1Tags.Set | Asn1Tags.Constructed);
+                derOut.WriteByte(0x80);
+
+                foreach (Asn1Encodable o in this)
+				{
+                    derOut.WriteObject(o);
+                }
+
+                derOut.WriteByte(0x00);
+                derOut.WriteByte(0x00);
+            }
+            else
+            {
+                base.Encode(derOut);
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/BerTaggedObject.cs b/crypto/src/asn1/BerTaggedObject.cs
new file mode 100644
index 000000000..228b136cb
--- /dev/null
+++ b/crypto/src/asn1/BerTaggedObject.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * 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
+		: DerTaggedObject
+	{
+		/**
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public BerTaggedObject(
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(tagNo, obj)
+		{
+		}
+
+		/**
+		 * @param explicitly true if an explicitly tagged object.
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public BerTaggedObject(
+			bool			explicitly,
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(explicitly, tagNo, obj)
+		{
+		}
+
+		/**
+		 * create an implicitly tagged object that contains a zero
+		 * length sequence.
+		 */
+		public BerTaggedObject(
+			int tagNo)
+			: base(false, tagNo, BerSequence.Empty)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			if (derOut is Asn1OutputStream || derOut is BerOutputStream)
+			{
+				derOut.WriteTag((byte)(Asn1Tags.Constructed | Asn1Tags.Tagged), tagNo);
+				derOut.WriteByte(0x80);
+
+				if (!IsEmpty())
+				{
+					if (!explicitly)
+					{
+						IEnumerable eObj;
+						if (obj is Asn1OctetString)
+						{
+							if (obj is BerOctetString)
+							{
+								eObj = (BerOctetString) obj;
+							}
+							else
+							{
+								Asn1OctetString octs = (Asn1OctetString)obj;
+								eObj = new BerOctetString(octs.GetOctets());
+							}
+						}
+						else if (obj is Asn1Sequence)
+						{
+							eObj = (Asn1Sequence) obj;
+						}
+						else if (obj is Asn1Set)
+						{
+							eObj = (Asn1Set) obj;
+						}
+						else
+						{
+							throw Platform.CreateNotImplementedException(obj.GetType().Name);
+						}
+
+						foreach (Asn1Encodable o in eObj)
+						{
+							derOut.WriteObject(o);
+						}
+					}
+					else
+					{
+						derOut.WriteObject(obj);
+					}
+				}
+
+				derOut.WriteByte(0x00);
+				derOut.WriteByte(0x00);
+			}
+			else
+			{
+				base.Encode(derOut);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/ConstructedOctetStream.cs b/crypto/src/asn1/ConstructedOctetStream.cs
new file mode 100644
index 000000000..1773b22cc
--- /dev/null
+++ b/crypto/src/asn1/ConstructedOctetStream.cs
@@ -0,0 +1,102 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	internal class ConstructedOctetStream
+		: BaseInputStream
+	{
+		private readonly Asn1StreamParser _parser;
+
+		private bool _first = true;
+		private Stream _currentStream;
+
+		internal ConstructedOctetStream(
+			Asn1StreamParser parser)
+		{
+			_parser = parser;
+		}
+
+		public override int Read(byte[] buffer, int offset, int count)
+		{
+			if (_currentStream == null)
+			{
+				if (!_first)
+					return 0;
+
+				Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject();
+
+				if (s == null)
+					return 0;
+
+				_first = false;
+				_currentStream = s.GetOctetStream();
+			}
+
+			int totalRead = 0;
+
+			for (;;)
+			{
+				int numRead = _currentStream.Read(buffer, offset + totalRead, count - totalRead);
+
+				if (numRead > 0)
+				{
+					totalRead += numRead;
+
+					if (totalRead == count)
+						return totalRead;
+				}
+				else
+				{
+					Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject();
+
+					if (aos == null)
+					{
+						_currentStream = null;
+						return totalRead;
+					}
+
+					_currentStream = aos.GetOctetStream();
+				}
+			}
+		}
+
+		public override int ReadByte()
+		{
+			if (_currentStream == null)
+			{
+				if (!_first)
+					return 0;
+
+				Asn1OctetStringParser s = (Asn1OctetStringParser)_parser.ReadObject();
+
+				if (s == null)
+					return 0;
+
+				_first = false;
+				_currentStream = s.GetOctetStream();
+			}
+
+			for (;;)
+			{
+				int b = _currentStream.ReadByte();
+
+				if (b >= 0)
+				{
+					return b;
+				}
+
+				Asn1OctetStringParser aos = (Asn1OctetStringParser)_parser.ReadObject();
+
+				if (aos == null)
+				{
+					_currentStream = null;
+					return -1;
+				}
+
+				_currentStream = aos.GetOctetStream();
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/DERExternal.cs b/crypto/src/asn1/DERExternal.cs
new file mode 100644
index 000000000..a342d6520
--- /dev/null
+++ b/crypto/src/asn1/DERExternal.cs
@@ -0,0 +1,207 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	* Class representing the DER-type External
+	*/
+	public class DerExternal
+		: Asn1Object
+	{
+		private DerObjectIdentifier	directReference;
+		private DerInteger			indirectReference;
+		private Asn1Object			dataValueDescriptor;
+		private int					encoding;
+		private Asn1Object			externalContent;
+
+		public DerExternal(
+			Asn1EncodableVector vector)
+		{
+			int offset = 0;
+			Asn1Object enc = GetObjFromVector(vector, offset);
+			if (enc is DerObjectIdentifier)
+			{
+				directReference = (DerObjectIdentifier)enc;
+				offset++;
+				enc = GetObjFromVector(vector, offset);
+			}
+			if (enc is DerInteger)
+			{
+				indirectReference = (DerInteger) enc;
+				offset++;
+				enc = GetObjFromVector(vector, offset);
+			}
+			if (!(enc is DerTaggedObject))
+			{
+				dataValueDescriptor = (Asn1Object) enc;
+				offset++;
+				enc = GetObjFromVector(vector, offset);
+			}
+			if (!(enc is DerTaggedObject))
+			{
+				throw new InvalidOperationException(
+					"No tagged object found in vector. Structure doesn't seem to be of type External");
+			}
+
+			if (vector.Count != offset + 1)
+				throw new ArgumentException("input vector too large", "vector");
+
+			if (!(enc is DerTaggedObject))
+				throw new ArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External", "vector");
+
+			DerTaggedObject obj = (DerTaggedObject)enc;
+
+			// Use property accessor to include check on value
+			Encoding = obj.TagNo;
+
+			if (encoding < 0 || encoding > 2)
+				throw new InvalidOperationException("invalid encoding value");
+
+			externalContent = obj.GetObject();
+		}
+
+		/**
+		* 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(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, DerTaggedObject externalData)
+			: this(directReference, indirectReference, dataValueDescriptor, externalData.TagNo, externalData.ToAsn1Object())
+		{
+		}
+
+		/**
+		* 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(DerObjectIdentifier directReference, DerInteger indirectReference, Asn1Object dataValueDescriptor, int encoding, Asn1Object externalData)
+		{
+			DirectReference = directReference;
+			IndirectReference = indirectReference;
+			DataValueDescriptor = dataValueDescriptor;
+			Encoding = encoding;
+			ExternalContent = externalData.ToAsn1Object();
+		}
+
+		internal override void Encode(DerOutputStream derOut)
+		{
+			MemoryStream ms = new MemoryStream();
+			WriteEncodable(ms, directReference);
+			WriteEncodable(ms, indirectReference);
+			WriteEncodable(ms, dataValueDescriptor);
+			WriteEncodable(ms, new DerTaggedObject(Asn1Tags.External, externalContent));
+
+			derOut.WriteEncoded(Asn1Tags.Constructed, Asn1Tags.External, ms.ToArray());
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			int ret = externalContent.GetHashCode();
+			if (directReference != null)
+			{
+				ret ^= directReference.GetHashCode();
+			}
+			if (indirectReference != null)
+			{
+				ret ^= indirectReference.GetHashCode();
+			}
+			if (dataValueDescriptor != null)
+			{
+				ret ^= dataValueDescriptor.GetHashCode();
+			}
+			return ret;
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			if (this == asn1Object)
+				return true;
+
+			DerExternal other = asn1Object as DerExternal;
+
+			if (other == null)
+				return false;
+
+			return Platform.Equals(directReference, other.directReference)
+				&& Platform.Equals(indirectReference, other.indirectReference)
+				&& Platform.Equals(dataValueDescriptor, other.dataValueDescriptor)
+				&& externalContent.Equals(other.externalContent);
+		}
+
+		public Asn1Object DataValueDescriptor
+		{
+			get { return dataValueDescriptor; }
+			set { this.dataValueDescriptor = value; }
+		}
+
+		public DerObjectIdentifier DirectReference
+		{
+			get { return directReference; }
+			set { this.directReference = value; }
+		}
+
+		/**
+		* 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>
+		*/
+		public int Encoding
+		{
+			get
+			{
+				return encoding;
+			}
+			set
+			{
+				if (encoding < 0 || encoding > 2)
+					throw new InvalidOperationException("invalid encoding value: " + encoding);
+
+				this.encoding = value;
+			}
+		}
+
+		public Asn1Object ExternalContent
+		{
+			get { return externalContent; }
+			set { this.externalContent = value; }
+		}
+
+		public DerInteger IndirectReference
+		{
+			get { return indirectReference; }
+			set { this.indirectReference = value; }
+		}
+
+		private static Asn1Object GetObjFromVector(Asn1EncodableVector v, int index)
+		{
+			if (v.Count <= index)
+				throw new ArgumentException("too few objects in input vector", "v");
+
+			return v[index].ToAsn1Object();
+		}
+
+		private static void WriteEncodable(MemoryStream ms, Asn1Encodable e)
+		{
+			if (e != null)
+			{
+				byte[] bs = e.GetDerEncoded();
+				ms.Write(bs, 0, bs.Length);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/DERExternalParser.cs b/crypto/src/asn1/DERExternalParser.cs
new file mode 100644
index 000000000..70e426fed
--- /dev/null
+++ b/crypto/src/asn1/DERExternalParser.cs
@@ -0,0 +1,26 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerExternalParser
+		: Asn1Encodable
+	{
+		private readonly Asn1StreamParser _parser;
+
+		public DerExternalParser(Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerExternal(_parser.ReadVector());
+		}
+	}
+}
diff --git a/crypto/src/asn1/DERGenerator.cs b/crypto/src/asn1/DERGenerator.cs
new file mode 100644
index 000000000..aab40fefa
--- /dev/null
+++ b/crypto/src/asn1/DERGenerator.cs
@@ -0,0 +1,107 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class DerGenerator
+        : Asn1Generator
+    {
+        private bool _tagged = false;
+        private bool _isExplicit;
+        private int _tagNo;
+
+		protected DerGenerator(
+            Stream outStream)
+            : base(outStream)
+		{
+        }
+
+        protected DerGenerator(
+            Stream outStream,
+            int tagNo,
+            bool isExplicit)
+            : base(outStream)
+        {
+            _tagged = true;
+            _isExplicit = isExplicit;
+            _tagNo = tagNo;
+        }
+
+		private static void WriteLength(
+            Stream	outStr,
+            int		length)
+        {
+            if (length > 127)
+            {
+                int size = 1;
+                int val = length;
+
+				while ((val >>= 8) != 0)
+                {
+                    size++;
+                }
+
+				outStr.WriteByte((byte)(size | 0x80));
+
+				for (int i = (size - 1) * 8; i >= 0; i -= 8)
+                {
+                    outStr.WriteByte((byte)(length >> i));
+                }
+            }
+            else
+            {
+                outStr.WriteByte((byte)length);
+            }
+        }
+
+		internal static void WriteDerEncoded(
+            Stream	outStream,
+            int		tag,
+            byte[]	bytes)
+        {
+            outStream.WriteByte((byte) tag);
+            WriteLength(outStream, bytes.Length);
+            outStream.Write(bytes, 0, bytes.Length);
+        }
+
+		internal void WriteDerEncoded(
+            int		tag,
+            byte[]	bytes)
+        {
+            if (_tagged)
+            {
+                int tagNum = _tagNo | Asn1Tags.Tagged;
+
+                if (_isExplicit)
+                {
+                    int newTag = _tagNo | Asn1Tags.Constructed | Asn1Tags.Tagged;
+					MemoryStream bOut = new MemoryStream();
+                    WriteDerEncoded(bOut, tag, bytes);
+                    WriteDerEncoded(Out, newTag, bOut.ToArray());
+                }
+                else
+                {
+					if ((tag & Asn1Tags.Constructed) != 0)
+					{
+						tagNum |= Asn1Tags.Constructed;
+					}
+
+					WriteDerEncoded(Out, tagNum, bytes);
+                }
+            }
+            else
+            {
+                WriteDerEncoded(Out, tag, bytes);
+            }
+        }
+
+		internal static void WriteDerEncoded(
+            Stream	outStr,
+            int		tag,
+            Stream	inStr)
+        {
+			WriteDerEncoded(outStr, tag, Streams.ReadAll(inStr));
+        }
+    }
+}
diff --git a/crypto/src/asn1/DEROctetStringParser.cs b/crypto/src/asn1/DEROctetStringParser.cs
new file mode 100644
index 000000000..b0d3ad8cf
--- /dev/null
+++ b/crypto/src/asn1/DEROctetStringParser.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerOctetStringParser
+		: Asn1OctetStringParser
+	{
+		private readonly DefiniteLengthInputStream stream;
+
+		internal DerOctetStringParser(
+			DefiniteLengthInputStream stream)
+		{
+			this.stream = stream;
+		}
+
+		public Stream GetOctetStream()
+		{
+			return stream;
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			try
+			{
+				return new DerOctetString(stream.ToArray());
+			}
+			catch (IOException e)
+			{
+				throw new InvalidOperationException("IOException converting stream to byte array: " + e.Message, e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/DERSequenceGenerator.cs b/crypto/src/asn1/DERSequenceGenerator.cs
new file mode 100644
index 000000000..4c2bfd012
--- /dev/null
+++ b/crypto/src/asn1/DERSequenceGenerator.cs
@@ -0,0 +1,40 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSequenceGenerator
+		: DerGenerator
+	{
+		private readonly MemoryStream _bOut = new MemoryStream();
+
+		public DerSequenceGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+		}
+
+		public DerSequenceGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+		}
+
+		public override void AddObject(
+			Asn1Encodable obj)
+		{
+			new DerOutputStream(_bOut).WriteObject(obj);
+		}
+
+		public override Stream GetRawOutputStream()
+		{
+			return _bOut;
+		}
+
+		public override void Close()
+		{
+			WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Sequence, _bOut.ToArray());
+		}
+	}
+}
diff --git a/crypto/src/asn1/DERSequenceParser.cs b/crypto/src/asn1/DERSequenceParser.cs
new file mode 100644
index 000000000..69c2b9b2d
--- /dev/null
+++ b/crypto/src/asn1/DERSequenceParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSequenceParser
+		: Asn1SequenceParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal DerSequenceParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(_parser.ReadVector());
+		}
+	}
+}
diff --git a/crypto/src/asn1/DERSetGenerator.cs b/crypto/src/asn1/DERSetGenerator.cs
new file mode 100644
index 000000000..455ca88ac
--- /dev/null
+++ b/crypto/src/asn1/DERSetGenerator.cs
@@ -0,0 +1,40 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSetGenerator
+		: DerGenerator
+	{
+		private readonly MemoryStream _bOut = new MemoryStream();
+
+		public DerSetGenerator(
+			Stream outStream)
+			: base(outStream)
+		{
+		}
+
+		public DerSetGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+		}
+
+		public override void AddObject(
+			Asn1Encodable obj)
+		{
+			new DerOutputStream(_bOut).WriteObject(obj);
+		}
+
+		public override Stream GetRawOutputStream()
+		{
+			return _bOut;
+		}
+
+		public override void Close()
+		{
+			WriteDerEncoded(Asn1Tags.Constructed | Asn1Tags.Set, _bOut.ToArray());
+		}
+	}
+}
diff --git a/crypto/src/asn1/DERSetParser.cs b/crypto/src/asn1/DERSetParser.cs
new file mode 100644
index 000000000..d67f135be
--- /dev/null
+++ b/crypto/src/asn1/DERSetParser.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSetParser
+		: Asn1SetParser
+	{
+		private readonly Asn1StreamParser _parser;
+
+		internal DerSetParser(
+			Asn1StreamParser parser)
+		{
+			this._parser = parser;
+		}
+
+		public IAsn1Convertible ReadObject()
+		{
+			return _parser.ReadObject();
+		}
+
+		public Asn1Object ToAsn1Object()
+		{
+			return new DerSet(_parser.ReadVector(), false);
+		}
+	}
+}
diff --git a/crypto/src/asn1/DefiniteLengthInputStream.cs b/crypto/src/asn1/DefiniteLengthInputStream.cs
index cfea89f21..4ae803c0e 100644
--- a/crypto/src/asn1/DefiniteLengthInputStream.cs
+++ b/crypto/src/asn1/DefiniteLengthInputStream.cs
@@ -75,7 +75,17 @@ namespace Org.BouncyCastle.Asn1
 			return numRead;
 		}
 
-		internal byte[] ToArray()
+        internal void ReadAllIntoByteArray(byte[] buf)
+        {
+            if (_remaining != buf.Length)
+                throw new ArgumentException("buffer length not right for data");
+
+            if ((_remaining -= Streams.ReadFully(_in, buf)) != 0)
+                throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+            SetParentEofDetect(true);
+        }
+
+        internal byte[] ToArray()
 		{
 			if (_remaining == 0)
 				return EmptyBytes;
diff --git a/crypto/src/asn1/DerApplicationSpecific.cs b/crypto/src/asn1/DerApplicationSpecific.cs
new file mode 100644
index 000000000..394c7431e
--- /dev/null
+++ b/crypto/src/asn1/DerApplicationSpecific.cs
@@ -0,0 +1,237 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Base class for an application specific object
+     */
+    public class DerApplicationSpecific
+        : Asn1Object
+    {
+		private readonly bool	isConstructed;
+        private readonly int	tag;
+        private readonly byte[]	octets;
+
+		internal DerApplicationSpecific(
+			bool	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	obj) 
+			: this(true, tag, obj)
+		{
+		}
+
+		public DerApplicationSpecific(
+			bool			isExplicit,
+			int				tag,
+			Asn1Encodable	obj)
+		{
+            Asn1Object asn1Obj = obj.ToAsn1Object();
+
+            byte[] data = asn1Obj.GetDerEncoded();
+
+			this.isConstructed = isExplicit || asn1Obj is Asn1Set || asn1Obj is Asn1Sequence;
+			this.tag = tag;
+
+			if (isExplicit)
+			{
+				this.octets = data;
+			}
+			else
+			{
+				int lenBytes = GetLengthOfHeader(data);
+				byte[] tmp = new byte[data.Length - lenBytes];
+				Array.Copy(data, lenBytes, tmp, 0, tmp.Length);
+				this.octets = tmp;
+			}
+		}
+
+		public DerApplicationSpecific(
+			int					tagNo,
+			Asn1EncodableVector	vec)
+		{
+			this.tag = tagNo;
+			this.isConstructed = true;
+			MemoryStream bOut = new MemoryStream();
+
+			for (int i = 0; i != vec.Count; i++)
+			{
+				try
+				{
+					byte[] bs = vec[i].GetDerEncoded();
+					bOut.Write(bs, 0, bs.Length);
+                }
+				catch (IOException e)
+				{
+					throw new InvalidOperationException("malformed object", e);
+				}
+			}
+			this.octets = bOut.ToArray();
+		}
+
+		private int GetLengthOfHeader(
+			byte[] data)
+		{
+            int length = data[1]; // 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 InvalidOperationException("DER length more than 4 bytes: " + size);
+                }
+
+                return size + 2;
+            }
+
+            return 2;
+        }
+
+		public bool IsConstructed()
+        {
+			return isConstructed;
+        }
+
+		public byte[] GetContents()
+        {
+            return octets;
+        }
+
+		public int ApplicationTag
+        {
+            get { return tag; }
+        }
+
+		/**
+		 * Return the enclosed object assuming explicit tagging.
+		 *
+		 * @return  the resulting object
+		 * @throws IOException if reconstruction fails.
+		 */
+		public Asn1Object GetObject()
+        {
+			return FromByteArray(GetContents());
+		}
+
+		/**
+		 * 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 Asn1Object GetObject(
+			int derTagNo)
+		{
+			if (derTagNo >= 0x1f)
+				throw new IOException("unsupported tag number");
+
+			byte[] orig = this.GetEncoded();
+			byte[] tmp = ReplaceTagNumber(derTagNo, orig);
+
+			if ((orig[0] & Asn1Tags.Constructed) != 0)
+			{
+				tmp[0] |= Asn1Tags.Constructed;
+			}
+
+			return FromByteArray(tmp);;
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+        {
+			int classBits = Asn1Tags.Application;
+			if (isConstructed)
+			{
+				classBits |= Asn1Tags.Constructed; 
+			}
+
+			derOut.WriteEncoded(classBits, tag, octets);
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerApplicationSpecific other = asn1Object as DerApplicationSpecific;
+
+			if (other == null)
+				return false;
+
+			return this.isConstructed == other.isConstructed
+				&& this.tag == other.tag
+				&& Arrays.AreEqual(this.octets, other.octets);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(octets);
+        }
+
+		private byte[] ReplaceTagNumber(
+			int		newTag,
+			byte[]	input)
+		{
+			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 InvalidOperationException("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];
+
+			Array.Copy(input, index, tmp, 1, tmp.Length - 1);
+
+			tmp[0] = (byte)newTag;
+
+			return tmp;
+		}
+    }
+}
diff --git a/crypto/src/asn1/DerBMPString.cs b/crypto/src/asn1/DerBMPString.cs
new file mode 100644
index 000000000..4f7e0a635
--- /dev/null
+++ b/crypto/src/asn1/DerBMPString.cs
@@ -0,0 +1,115 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der BMPString object.
+     */
+    public class DerBmpString
+		: DerStringBase
+    {
+        private readonly string str;
+
+		/**
+         * return a BMP string from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerBmpString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerBmpString)
+            {
+                return (DerBmpString)obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a BMP string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *              be converted.
+         */
+        public static DerBmpString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerBmpString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerBmpString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+		/**
+         * basic constructor - byte encoded string.
+         */
+        public DerBmpString(
+            byte[] str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+            char[] cs = new char[str.Length / 2];
+
+			for (int i = 0; i != cs.Length; i++)
+            {
+                cs[i] = (char)((str[2 * i] << 8) | (str[2 * i + 1] & 0xff));
+            }
+
+			this.str = new string(cs);
+        }
+
+        /**
+         * basic constructor
+         */
+        public DerBmpString(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        public override string GetString()
+        {
+            return str;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerBmpString other = asn1Object as DerBmpString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            char[] c = str.ToCharArray();
+            byte[] b = new byte[c.Length * 2];
+
+			for (int i = 0; i != c.Length; i++)
+            {
+                b[2 * i] = (byte)(c[i] >> 8);
+                b[2 * i + 1] = (byte)c[i];
+            }
+
+            derOut.WriteEncoded(Asn1Tags.BmpString, b);
+        }
+    }
+}
diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs
new file mode 100644
index 000000000..d5cb872bc
--- /dev/null
+++ b/crypto/src/asn1/DerBitString.cs
@@ -0,0 +1,248 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerBitString
+		: DerStringBase
+	{
+		private static readonly char[] table
+			= { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+		private readonly byte[]	data;
+		private readonly int	padBits;
+
+		/**
+		 * return the correct number of pad bits for a bit string defined in
+		 * a 32 bit constant
+		 */
+		static internal 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 internal 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 ArgumentException if the object cannot be converted.
+		 */
+		public static DerBitString GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is DerBitString)
+			{
+				return (DerBitString) obj;
+			}
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+		}
+
+		/**
+		 * return a Bit string from a tagged object.
+		 *
+		 * @param obj the tagged object holding the object we want
+		 * @param explicitly true if the object is meant to be explicitly
+		 *              tagged false otherwise.
+		 * @exception ArgumentException if the tagged object cannot
+		 *               be converted.
+		 */
+		public static DerBitString GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerBitString)
+			{
+				return GetInstance(o);
+			}
+
+			return FromAsn1Octets(((Asn1OctetString)o).GetOctets());
+		}
+
+		internal DerBitString(
+			byte	data,
+			int		padBits)
+		{
+			this.data = new byte[]{ 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)
+		{
+			// TODO Deep copy?
+			this.data = data;
+			this.padBits = padBits;
+		}
+
+		public DerBitString(
+			byte[] data)
+		{
+			// TODO Deep copy?
+			this.data = data;
+		}
+
+		public DerBitString(
+			Asn1Encodable obj)
+		{
+			this.data = obj.GetDerEncoded();
+			//this.padBits = 0;
+		}
+
+		public byte[] GetBytes()
+		{
+			return data;
+		}
+
+		public int PadBits
+		{
+			get { return padBits; }
+		}
+
+		/**
+		 * @return the value of the bit string as an int (truncating if necessary)
+		 */
+		public int IntValue
+		{
+			get
+			{
+				int value = 0;
+
+				for (int i = 0; i != data.Length && i != 4; i++)
+				{
+					value |= (data[i] & 0xff) << (8 * i);
+				}
+
+				return value;
+			}
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			byte[] bytes = new byte[GetBytes().Length + 1];
+
+			bytes[0] = (byte) PadBits;
+			Array.Copy(GetBytes(), 0, bytes, 1, bytes.Length - 1);
+
+			derOut.WriteEncoded(Asn1Tags.BitString, bytes);
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			return padBits.GetHashCode() ^ Arrays.GetHashCode(data);
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerBitString other = asn1Object as DerBitString;
+
+			if (other == null)
+				return false;
+
+			return this.padBits == other.padBits
+				&& Arrays.AreEqual(this.data, other.data);
+		}
+
+		public override string GetString()
+		{
+			StringBuilder buffer = new StringBuilder("#");
+
+			byte[] str = GetDerEncoded();
+
+			for (int i = 0; i != str.Length; i++)
+			{
+				uint ubyte = str[i];
+				buffer.Append(table[(ubyte >> 4) & 0xf]);
+				buffer.Append(table[str[i] & 0xf]);
+			}
+
+			return buffer.ToString();
+		}
+
+		internal static DerBitString FromAsn1Octets(byte[] octets)
+		{
+	        if (octets.Length < 1)
+	            throw new ArgumentException("truncated BIT STRING detected");
+
+			int padBits = octets[0];
+			byte[] data = new byte[octets.Length - 1];
+			Array.Copy(octets, 1, data, 0, data.Length);
+			return new DerBitString(data, padBits);
+		}
+	}
+}
+
diff --git a/crypto/src/asn1/DerBoolean.cs b/crypto/src/asn1/DerBoolean.cs
index 41ccae8a1..66791d16c 100644
--- a/crypto/src/asn1/DerBoolean.cs
+++ b/crypto/src/asn1/DerBoolean.cs
@@ -7,10 +7,10 @@ namespace Org.BouncyCastle.Asn1
     {
         private readonly byte value;
 
-		public static readonly DerBoolean False = new DerBoolean(false);
+        public static readonly DerBoolean False = new DerBoolean(false);
         public static readonly DerBoolean True  = new DerBoolean(true);
 
-		/**
+        /**
          * return a bool from the passed in object.
          *
          * @exception ArgumentException if the object cannot be converted.
@@ -23,10 +23,10 @@ namespace Org.BouncyCastle.Asn1
                 return (DerBoolean) obj;
             }
 
-			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
         }
 
-		/**
+        /**
          * return a DerBoolean from the passed in bool.
          */
         public static DerBoolean GetInstance(
@@ -35,7 +35,7 @@ namespace Org.BouncyCastle.Asn1
             return value ? True : False;
         }
 
-		/**
+        /**
          * return a Boolean from a tagged object.
          *
          * @param obj the tagged object holding the object we want
@@ -48,63 +48,75 @@ namespace Org.BouncyCastle.Asn1
             Asn1TaggedObject	obj,
             bool				isExplicit)
         {
-			Asn1Object o = obj.GetObject();
+            Asn1Object o = obj.GetObject();
 
-			if (isExplicit || o is DerBoolean)
-			{
-				return GetInstance(o);
-			}
+            if (isExplicit || o is DerBoolean)
+            {
+                return GetInstance(o);
+            }
 
-			return new DerBoolean(((Asn1OctetString)o).GetOctets());
+            return FromOctetString(((Asn1OctetString)o).GetOctets());
         }
 
-		public DerBoolean(
+        public DerBoolean(
             byte[] val)
         {
-			if (val.Length != 1)
-				throw new ArgumentException("byte value should have 1 byte in it", "val");
+            if (val.Length != 1)
+                throw new ArgumentException("byte value should have 1 byte in it", "val");
 
-			// TODO Are there any constraints on the possible byte values?
+            // TODO Are there any constraints on the possible byte values?
             this.value = val[0];
         }
 
-		private DerBoolean(
+        private DerBoolean(
             bool value)
         {
             this.value = value ? (byte)0xff : (byte)0;
         }
 
-		public bool IsTrue
-		{
-			get { return value != 0; }
-		}
+        public bool IsTrue
+        {
+            get { return value != 0; }
+        }
 
-		internal override void Encode(
+        internal override void Encode(
             DerOutputStream derOut)
         {
-			// TODO Should we make sure the byte value is one of '0' or '0xff' here?
-			derOut.WriteEncoded(Asn1Tags.Boolean, new byte[]{ value });
+            // TODO Should we make sure the byte value is one of '0' or '0xff' here?
+            derOut.WriteEncoded(Asn1Tags.Boolean, new byte[]{ value });
         }
 
-		protected override bool Asn1Equals(
-			Asn1Object asn1Object)
+        protected override bool Asn1Equals(
+            Asn1Object asn1Object)
         {
-			DerBoolean other = asn1Object as DerBoolean;
+            DerBoolean other = asn1Object as DerBoolean;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			return IsTrue == other.IsTrue;
+            return IsTrue == other.IsTrue;
+        }
+
+        protected override int Asn1GetHashCode()
+        {
+            return IsTrue.GetHashCode();
         }
 
-		protected override int Asn1GetHashCode()
-		{
-			return IsTrue.GetHashCode();
+        public override string ToString()
+        {
+            return IsTrue ? "TRUE" : "FALSE";
         }
 
-		public override string ToString()
-		{
-			return IsTrue ? "TRUE" : "FALSE";
-		}
-	}
+        internal static DerBoolean FromOctetString(byte[] value)
+        {
+            if (value.Length != 1)
+            {
+                throw new ArgumentException("BOOLEAN value should have 1 byte in it", "value");
+            }
+
+            byte b = value[0];
+
+            return b == 0 ? False : b == 0xFF ? True : new DerBoolean(value);
+        }
+    }
 }
diff --git a/crypto/src/asn1/DerEnumerated.cs b/crypto/src/asn1/DerEnumerated.cs
index 0e67e6dbe..2638b0205 100644
--- a/crypto/src/asn1/DerEnumerated.cs
+++ b/crypto/src/asn1/DerEnumerated.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Asn1
     {
         private readonly byte[] bytes;
 
-		/**
+        /**
          * return an integer from the passed in object
          *
          * @exception ArgumentException if the object cannot be converted.
@@ -39,14 +39,14 @@ namespace Org.BouncyCastle.Asn1
             Asn1TaggedObject	obj,
             bool				isExplicit)
         {
-			Asn1Object o = obj.GetObject();
+            Asn1Object o = obj.GetObject();
 
-			if (isExplicit || o is DerEnumerated)
-			{
-				return GetInstance(o);
-			}
+            if (isExplicit || o is DerEnumerated)
+            {
+                return GetInstance(o);
+            }
 
-			return new DerEnumerated(((Asn1OctetString)o).GetOctets());
+            return FromOctetString(((Asn1OctetString)o).GetOctets());
         }
 
         public DerEnumerated(
@@ -69,32 +69,56 @@ namespace Org.BouncyCastle.Asn1
 
         public BigInteger Value
         {
-            get
-            {
-                return new BigInteger(bytes);
-            }
+            get { return new BigInteger(bytes); }
         }
 
-		internal override void Encode(
+        internal override void Encode(
             DerOutputStream derOut)
         {
             derOut.WriteEncoded(Asn1Tags.Enumerated, bytes);
         }
 
-		protected override bool Asn1Equals(
-			Asn1Object asn1Object)
+        protected override bool Asn1Equals(
+            Asn1Object asn1Object)
         {
-			DerEnumerated other = asn1Object as DerEnumerated;
+            DerEnumerated other = asn1Object as DerEnumerated;
+
+            if (other == null)
+                return false;
 
-			if (other == null)
-				return false;
+            return Arrays.AreEqual(this.bytes, other.bytes);
+        }
 
-			return Arrays.AreEqual(this.bytes, other.bytes);
+        protected override int Asn1GetHashCode()
+        {
+            return Arrays.GetHashCode(bytes);
         }
 
-		protected override int Asn1GetHashCode()
-		{
-			return Arrays.GetHashCode(bytes);
+        private static readonly DerEnumerated[] cache = new DerEnumerated[12];
+
+        internal static DerEnumerated FromOctetString(byte[] enc)
+        {
+            if (enc.Length == 0)
+            {
+                throw new ArgumentException("ENUMERATED has zero length", "enc");
+            }
+
+            if (enc.Length == 1)
+            {
+                int value = enc[0];
+                if (value < cache.Length)
+                {
+                    DerEnumerated cached = cache[value];
+                    if (cached != null)
+                    {
+                        return cached;
+                    }
+
+                    return cache[value] = new DerEnumerated(Arrays.Clone(enc));
+                }
+            }
+
+            return new DerEnumerated(Arrays.Clone(enc));
         }
     }
 }
diff --git a/crypto/src/asn1/DerGeneralString.cs b/crypto/src/asn1/DerGeneralString.cs
new file mode 100644
index 000000000..0e20b53bd
--- /dev/null
+++ b/crypto/src/asn1/DerGeneralString.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerGeneralString
+        : DerStringBase
+    {
+        private readonly string str;
+
+        public static DerGeneralString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerGeneralString)
+            {
+                return (DerGeneralString) obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: "
+                    + obj.GetType().Name);
+        }
+
+        public static DerGeneralString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerGeneralString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerGeneralString(((Asn1OctetString)o).GetOctets());
+        }
+
+        public DerGeneralString(
+			byte[] str)
+			: this(Strings.FromAsciiByteArray(str))
+        {
+        }
+
+		public DerGeneralString(
+			string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+			DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.GeneralString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerGeneralString other = asn1Object as DerGeneralString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+    }
+}
diff --git a/crypto/src/asn1/DerGeneralizedTime.cs b/crypto/src/asn1/DerGeneralizedTime.cs
index 0a0e6fd7c..548a268e1 100644
--- a/crypto/src/asn1/DerGeneralizedTime.cs
+++ b/crypto/src/asn1/DerGeneralizedTime.cs
@@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Asn1
     {
         private readonly string time;
 
-		/**
+        /**
          * return a generalized time from the passed in object
          *
          * @exception ArgumentException if the object cannot be converted.
@@ -22,15 +22,15 @@ namespace Org.BouncyCastle.Asn1
         public static DerGeneralizedTime GetInstance(
             object obj)
         {
-			if (obj == null || obj is DerGeneralizedTime)
+            if (obj == null || obj is DerGeneralizedTime)
             {
                 return (DerGeneralizedTime)obj;
             }
 
-			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj");
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj");
         }
 
-		/**
+        /**
          * return a Generalized Time object from a tagged object.
          *
          * @param obj the tagged object holding the object we want
@@ -43,41 +43,41 @@ namespace Org.BouncyCastle.Asn1
             Asn1TaggedObject	obj,
             bool				isExplicit)
         {
-			Asn1Object o = obj.GetObject();
+            Asn1Object o = obj.GetObject();
 
-			if (isExplicit || o is DerGeneralizedTime)
-			{
-				return GetInstance(o);
-			}
+            if (isExplicit || o is DerGeneralizedTime)
+            {
+                return GetInstance(o);
+            }
+
+            return new DerGeneralizedTime(((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 ArgumentException if string is an illegal format.
+         */
+        public DerGeneralizedTime(
+            string time)
+        {
+            this.time = time;
 
-			return new DerGeneralizedTime(((Asn1OctetString)o).GetOctets());
+            try
+            {
+                ToDateTime();
+            }
+            catch (FormatException e)
+            {
+                throw new ArgumentException("invalid date string: " + e.Message);
+            }
         }
 
-		/**
-		 * 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 ArgumentException if string is an illegal format.
-		 */
-		public DerGeneralizedTime(
-			string time)
-		{
-			this.time = time;
-
-			try
-			{
-				ToDateTime();
-			}
-			catch (FormatException e)
-			{
-				throw new ArgumentException("invalid date string: " + e.Message);
-			}
-		}
-
-		/**
+        /**
          * base constructor from a local time object
          */
         public DerGeneralizedTime(
@@ -86,7 +86,7 @@ namespace Org.BouncyCastle.Asn1
             this.time = time.ToString(@"yyyyMMddHHmmss\Z");
         }
 
-		internal DerGeneralizedTime(
+        internal DerGeneralizedTime(
             byte[] bytes)
         {
             //
@@ -95,16 +95,16 @@ namespace Org.BouncyCastle.Asn1
             this.time = Strings.FromAsciiByteArray(bytes);
         }
 
-		/**
-		 * Return the time.
-		 * @return The time string as it appeared in the encoded object.
-		 */
-		public string TimeString
-		{
-			get { return time; }
-		}
+        /**
+         * Return the time.
+         * @return The time string as it appeared in the encoded object.
+         */
+        public string TimeString
+        {
+            get { return time; }
+        }
 
-		/**
+        /**
          * return the time - always in the form of
          *  YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
          * <p>
@@ -154,151 +154,162 @@ namespace Org.BouncyCastle.Asn1
             return time + CalculateGmtOffset();
         }
 
-		private string CalculateGmtOffset()
-		{
-			char sign = '+';
+        private string CalculateGmtOffset()
+        {
+            char sign = '+';
             DateTime time = ToDateTime();
 
-#if (SILVERLIGHT || PORTABLE)
+#if SILVERLIGHT
             long offset = time.Ticks - time.ToUniversalTime().Ticks;
-			if (offset < 0)
-			{
-				sign = '-';
-				offset = -offset;
-			}
-			int hours = (int)(offset / TimeSpan.TicksPerHour);
-			int minutes = (int)(offset / TimeSpan.TicksPerMinute) % 60;
+            if (offset < 0)
+            {
+                sign = '-';
+                offset = -offset;
+            }
+            int hours = (int)(offset / TimeSpan.TicksPerHour);
+            int minutes = (int)(offset / TimeSpan.TicksPerMinute) % 60;
 #else
             // Note: GetUtcOffset incorporates Daylight Savings offset
-			TimeSpan offset =  TimeZone.CurrentTimeZone.GetUtcOffset(time);
-			if (offset.CompareTo(TimeSpan.Zero) < 0)
-			{
-				sign = '-';
-				offset = offset.Duration();
-			}
-			int hours = offset.Hours;
-			int minutes = offset.Minutes;
+            TimeSpan offset =  TimeZone.CurrentTimeZone.GetUtcOffset(time);
+            if (offset.CompareTo(TimeSpan.Zero) < 0)
+            {
+                sign = '-';
+                offset = offset.Duration();
+            }
+            int hours = offset.Hours;
+            int minutes = offset.Minutes;
 #endif
 
-			return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
-		}
-
-		private static string Convert(
-			int time)
-		{
-			if (time < 10)
-			{
-				return "0" + time;
-			}
-
-			return time.ToString();
-		}
-
-		public DateTime ToDateTime()
-		{
-			string formatStr;
-			string d = time;
-			bool makeUniversal = false;
-
-			if (d.EndsWith("Z"))
-			{
-				if (HasFractionalSeconds)
-				{
-					int fCount = d.Length - d.IndexOf('.') - 2;
-					formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
-				}
-				else
-				{
-					formatStr = @"yyyyMMddHHmmss\Z";
-				}
-			}
-			else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
-			{
-				d = GetTime();
-				makeUniversal = true;
-
-				if (HasFractionalSeconds)
-				{
-					int fCount = d.IndexOf("GMT") - 1 - d.IndexOf('.');
-					formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
-				}
-				else
-				{
-					formatStr = @"yyyyMMddHHmmss'GMT'zzz";
-				}
-			}
-			else
-			{
-				if (HasFractionalSeconds)
-				{
-					int fCount = d.Length - 1 - d.IndexOf('.');
-					formatStr = @"yyyyMMddHHmmss." + FString(fCount);
-				}
-				else
-				{
-					formatStr = @"yyyyMMddHHmmss";
-				}
-
-				// TODO?
+            return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
+        }
+
+        private static string Convert(
+            int time)
+        {
+            if (time < 10)
+            {
+                return "0" + time;
+            }
+
+            return time.ToString();
+        }
+
+        public DateTime ToDateTime()
+        {
+            string formatStr;
+            string d = time;
+            bool makeUniversal = false;
+
+            if (d.EndsWith("Z"))
+            {
+                if (HasFractionalSeconds)
+                {
+                    int fCount = d.Length - d.IndexOf('.') - 2;
+                    formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
+                }
+                else
+                {
+                    formatStr = @"yyyyMMddHHmmss\Z";
+                }
+            }
+            else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
+            {
+                d = GetTime();
+                makeUniversal = true;
+
+                if (HasFractionalSeconds)
+                {
+                    int fCount = d.IndexOf("GMT") - 1 - d.IndexOf('.');
+                    formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
+                }
+                else
+                {
+                    formatStr = @"yyyyMMddHHmmss'GMT'zzz";
+                }
+            }
+            else
+            {
+                if (HasFractionalSeconds)
+                {
+                    int fCount = d.Length - 1 - d.IndexOf('.');
+                    formatStr = @"yyyyMMddHHmmss." + FString(fCount);
+                }
+                else
+                {
+                    formatStr = @"yyyyMMddHHmmss";
+                }
+
+                // TODO?
 //				dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
-			}
-
-			return ParseDateString(d, formatStr, makeUniversal);
-		}
-
-		private string FString(
-			int count)
-		{
-			StringBuilder sb = new StringBuilder();
-			for (int i = 0; i < count; ++i)
-			{
-				sb.Append('f');
-			}
-			return sb.ToString();
-		}
-
-		private DateTime ParseDateString(
-			string	dateStr,
-			string	formatStr,
-			bool	makeUniversal)
-		{
-			DateTime dt = DateTime.ParseExact(
-				dateStr,
-				formatStr,
-				DateTimeFormatInfo.InvariantInfo);
-
-			return makeUniversal ? dt.ToUniversalTime() : dt;
-		}
-
-		private bool HasFractionalSeconds
-		{
-			get { return time.IndexOf('.') == 14; }
-		}
-
-		private byte[] GetOctets()
+            }
+
+            return ParseDateString(d, formatStr, makeUniversal);
+        }
+
+        private string FString(
+            int count)
+        {
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < count; ++i)
+            {
+                sb.Append('f');
+            }
+            return sb.ToString();
+        }
+
+        private DateTime ParseDateString(string	s, string format, bool makeUniversal)
+        {
+            /*
+             * NOTE: DateTime.Kind and DateTimeStyles.AssumeUniversal not available in .NET 1.1
+             */
+            DateTimeStyles style = DateTimeStyles.None;
+            if (format.EndsWith("Z"))
+            {
+                try
+                {
+                    style = (DateTimeStyles)Enum.Parse(typeof(DateTimeStyles), "AssumeUniversal");
+                }
+                catch (Exception)
+                {
+                }
+
+                style |= DateTimeStyles.AdjustToUniversal;
+            }
+
+            DateTime dt = DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, style);
+
+            return makeUniversal ? dt.ToUniversalTime() : dt;
+        }
+
+        private bool HasFractionalSeconds
+        {
+            get { return time.IndexOf('.') == 14; }
+        }
+
+        private byte[] GetOctets()
         {
             return Strings.ToAsciiByteArray(time);
         }
 
-		internal override void Encode(
+        internal override void Encode(
             DerOutputStream derOut)
         {
             derOut.WriteEncoded(Asn1Tags.GeneralizedTime, GetOctets());
         }
 
-		protected override bool Asn1Equals(
-			Asn1Object asn1Object)
+        protected override bool Asn1Equals(
+            Asn1Object asn1Object)
         {
-			DerGeneralizedTime other = asn1Object as DerGeneralizedTime;
+            DerGeneralizedTime other = asn1Object as DerGeneralizedTime;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			return this.time.Equals(other.time);
+            return this.time.Equals(other.time);
         }
 
-		protected override int Asn1GetHashCode()
-		{
+        protected override int Asn1GetHashCode()
+        {
             return time.GetHashCode();
         }
     }
diff --git a/crypto/src/asn1/DerIA5String.cs b/crypto/src/asn1/DerIA5String.cs
new file mode 100644
index 000000000..9fa2cba3c
--- /dev/null
+++ b/crypto/src/asn1/DerIA5String.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der IA5String object - this is an ascii string.
+     */
+    public class DerIA5String
+        : DerStringBase
+    {
+        private readonly string str;
+
+        /**
+         * return a IA5 string from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerIA5String GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerIA5String)
+            {
+                return (DerIA5String)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an IA5 string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerIA5String GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerIA5String)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerIA5String(((Asn1OctetString)o).GetOctets());
+        }
+
+        /**
+         * basic constructor - with bytes.
+         */
+        public DerIA5String(
+            byte[] str)
+            : this(Strings.FromAsciiByteArray(str), false)
+        {
+        }
+
+		/**
+		* basic constructor - without validation.
+		*/
+		public DerIA5String(
+			string str)
+			: this(str, false)
+		{
+		}
+
+		/**
+		* Constructor with optional validation.
+		*
+		* @param string the base string to wrap.
+		* @param validate whether or not to check the string.
+		* @throws ArgumentException if validate is true and the string
+		* contains characters that should not be in an IA5String.
+		*/
+		public DerIA5String(
+			string	str,
+			bool	validate)
+		{
+			if (str == null)
+				throw new ArgumentNullException("str");
+			if (validate && !IsIA5String(str))
+				throw new ArgumentException("string contains illegal characters", "str");
+
+			this.str = str;
+		}
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.IA5String, GetOctets());
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return this.str.GetHashCode();
+        }
+
+		protected override bool Asn1Equals(
+            Asn1Object asn1Object)
+        {
+			DerIA5String other = asn1Object as DerIA5String;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		/**
+		 * 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 bool IsIA5String(
+			string str)
+		{
+			foreach (char ch in str)
+			{
+				if (ch > 0x007f)
+				{
+					return false;
+				}
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerInteger.cs b/crypto/src/asn1/DerInteger.cs
new file mode 100644
index 000000000..eb0614515
--- /dev/null
+++ b/crypto/src/asn1/DerInteger.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerInteger
+        : Asn1Object
+    {
+        private readonly byte[] bytes;
+
+        /**
+         * return an integer from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerInteger GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerInteger)
+            {
+                return (DerInteger)obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an Integer from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param isExplicit true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerInteger GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            if (obj == null)
+                throw new ArgumentNullException("obj");
+
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerInteger)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerInteger(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+		public DerInteger(
+            int value)
+        {
+            bytes = BigInteger.ValueOf(value).ToByteArray();
+        }
+
+		public DerInteger(
+            BigInteger value)
+        {
+            if (value == null)
+                throw new ArgumentNullException("value");
+
+			bytes = value.ToByteArray();
+        }
+
+		public DerInteger(
+            byte[] bytes)
+        {
+            this.bytes = bytes;
+        }
+
+		public BigInteger Value
+        {
+            get { return new BigInteger(bytes); }
+        }
+
+		/**
+         * in some cases positive values Get crammed into a space,
+         * that's not quite big enough...
+         */
+        public BigInteger PositiveValue
+        {
+            get { return new BigInteger(1, bytes); }
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.Integer, bytes);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return Arrays.GetHashCode(bytes);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerInteger other = asn1Object as DerInteger;
+
+			if (other == null)
+				return false;
+
+			return Arrays.AreEqual(this.bytes, other.bytes);
+        }
+
+		public override string ToString()
+		{
+			return Value.ToString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerNull.cs b/crypto/src/asn1/DerNull.cs
new file mode 100644
index 000000000..a802f6486
--- /dev/null
+++ b/crypto/src/asn1/DerNull.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * A Null object.
+	 */
+	public class DerNull
+		: Asn1Null
+	{
+		public static readonly DerNull Instance = new DerNull(0);
+
+		byte[] zeroBytes = new byte[0];
+
+		[Obsolete("Use static Instance object")]
+		public DerNull()
+		{
+		}
+
+		protected internal DerNull(int dummy)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream  derOut)
+		{
+			derOut.WriteEncoded(Asn1Tags.Null, zeroBytes);
+		}
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			return asn1Object is DerNull;
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			return -1;
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerNumericString.cs b/crypto/src/asn1/DerNumericString.cs
new file mode 100644
index 000000000..6e2715a4d
--- /dev/null
+++ b/crypto/src/asn1/DerNumericString.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+     */
+    public class DerNumericString
+        : DerStringBase
+    {
+        private readonly string str;
+
+        /**
+         * return a Numeric string from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerNumericString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerNumericString)
+            {
+                return (DerNumericString)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an Numeric string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerNumericString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerNumericString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerNumericString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+		/**
+		 * basic constructor - with bytes.
+		 */
+		public DerNumericString(
+			byte[] str)
+            : this(Strings.FromAsciiByteArray(str), false)
+		{
+		}
+
+		/**
+		 * basic constructor -  without validation..
+		 */
+		public DerNumericString(
+			string str)
+			: this(str, false)
+		{
+		}
+
+		/**
+		* Constructor with optional validation.
+		*
+		* @param string the base string to wrap.
+		* @param validate whether or not to check the string.
+		* @throws ArgumentException if validate is true and the string
+		* contains characters that should not be in a NumericString.
+		*/
+		public DerNumericString(
+			string	str,
+			bool	validate)
+		{
+			if (str == null)
+				throw new ArgumentNullException("str");
+			if (validate && !IsNumericString(str))
+				throw new ArgumentException("string contains illegal characters", "str");
+
+			this.str = str;
+		}
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.NumericString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerNumericString other = asn1Object as DerNumericString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		/**
+		 * 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 bool IsNumericString(
+			string str)
+		{
+			foreach (char ch in str)
+			{
+				if (ch > 0x007f || (ch != ' ' && !char.IsDigit(ch)))
+					return false;
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs
index 7dc963729..f9f6a79d6 100644
--- a/crypto/src/asn1/DerObjectIdentifier.cs
+++ b/crypto/src/asn1/DerObjectIdentifier.cs
@@ -4,33 +4,32 @@ using System.Text;
 using System.Text.RegularExpressions;
 
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
     public class DerObjectIdentifier
         : Asn1Object
     {
-		private static readonly Regex OidRegex = new Regex(@"\A[0-2](\.[0-9]+)+\z");
+        private readonly string identifier;
 
-		private readonly string identifier;
+        private byte[] body = null;
 
-		/**
+        /**
          * return an Oid from the passed in object
          *
          * @exception ArgumentException if the object cannot be converted.
          */
-        public static DerObjectIdentifier GetInstance(
-            object obj)
+        public static DerObjectIdentifier GetInstance(object obj)
         {
             if (obj == null || obj is DerObjectIdentifier)
-            {
                 return (DerObjectIdentifier) obj;
-            }
-
-			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj");
+            if (obj is byte[])
+                return FromOctetString((byte[])obj);
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name, "obj");
         }
 
-		/**
+        /**
          * return an object Identifier from a tagged object.
          *
          * @param obj the tagged object holding the object we want
@@ -46,27 +45,35 @@ namespace Org.BouncyCastle.Asn1
             return GetInstance(obj.GetObject());
         }
 
-		public DerObjectIdentifier(
+        public DerObjectIdentifier(
             string identifier)
         {
-			if (identifier == null)
-				throw new ArgumentNullException("identifier");
-			if (!OidRegex.IsMatch(identifier))
-				throw new FormatException("string " + identifier + " not an OID");
+            if (identifier == null)
+                throw new ArgumentNullException("identifier");
+            if (!IsValidIdentifier(identifier))
+                throw new FormatException("string " + identifier + " not an OID");
 
-			this.identifier = identifier;
+            this.identifier = identifier;
         }
 
-		// TODO Change to ID?
-		public string Id
+        internal DerObjectIdentifier(DerObjectIdentifier oid, string branchID)
+        {
+            if (!IsValidBranchID(branchID, 0))
+                throw new ArgumentException("string " + branchID + " not a valid OID branch", "branchID");
+
+            this.identifier = oid.Id + "." + branchID;
+        }
+
+        // TODO Change to ID?
+        public string Id
         {
             get { return identifier; }
         }
 
-		public virtual DerObjectIdentifier Branch(string branchID)
-		{
-			return new DerObjectIdentifier(identifier + "." + branchID);
-		}
+        public virtual DerObjectIdentifier Branch(string branchID)
+        {
+            return new DerObjectIdentifier(this, branchID);
+        }
 
         /**
          * Return  true if this oid is an extension of the passed in branch, stem.
@@ -79,164 +86,262 @@ namespace Org.BouncyCastle.Asn1
             return id.Length > stemId.Length && id[stemId.Length] == '.' && id.StartsWith(stemId);
         }
 
-        internal DerObjectIdentifier(
-            byte[] bytes)
-            : this(MakeOidStringFromBytes(bytes))
+        internal DerObjectIdentifier(byte[] bytes)
         {
+            this.identifier = MakeOidStringFromBytes(bytes);
+            this.body = Arrays.Clone(bytes);
         }
 
-		private void WriteField(
+        private void WriteField(
             Stream	outputStream,
             long	fieldValue)
         {
-			byte[] result = new byte[9];
-			int pos = 8;
-			result[pos] = (byte)(fieldValue & 0x7f);
-			while (fieldValue >= (1L << 7))
-			{
-				fieldValue >>= 7;
-				result[--pos] = (byte)((fieldValue & 0x7f) | 0x80);
-			}
-			outputStream.Write(result, pos, 9 - pos);
-        }
-
-		private void WriteField(
-			Stream		outputStream,
-			BigInteger	fieldValue)
-		{
-			int byteCount = (fieldValue.BitLength + 6) / 7;
-			if (byteCount == 0)
-			{
-				outputStream.WriteByte(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;
-				outputStream.Write(tmp, 0, tmp.Length);
-			}
-		}
+            byte[] result = new byte[9];
+            int pos = 8;
+            result[pos] = (byte)(fieldValue & 0x7f);
+            while (fieldValue >= (1L << 7))
+            {
+                fieldValue >>= 7;
+                result[--pos] = (byte)((fieldValue & 0x7f) | 0x80);
+            }
+            outputStream.Write(result, pos, 9 - pos);
+        }
 
-        internal override void Encode(
-            DerOutputStream derOut)
+        private void WriteField(
+            Stream		outputStream,
+            BigInteger	fieldValue)
         {
-            OidTokenizer tok = new OidTokenizer(identifier);
-            MemoryStream bOut = new MemoryStream();
-            DerOutputStream dOut = new DerOutputStream(bOut);
+            int byteCount = (fieldValue.BitLength + 6) / 7;
+            if (byteCount == 0)
+            {
+                outputStream.WriteByte(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;
+                outputStream.Write(tmp, 0, tmp.Length);
+            }
+        }
 
-			string token = tok.NextToken();
-            int first = int.Parse(token);
+        private void DoOutput(MemoryStream bOut)
+        {
+            OidTokenizer tok = new OidTokenizer(identifier);
 
-			token = tok.NextToken();
-            int second = int.Parse(token);
+            string token = tok.NextToken();
+            int first = int.Parse(token) * 40;
 
-            WriteField(bOut, first * 40 + second);
+            token = tok.NextToken();
+            if (token.Length <= 18)
+            {
+                WriteField(bOut, first + Int64.Parse(token));
+            }
+            else
+            {
+                WriteField(bOut, new BigInteger(token).Add(BigInteger.ValueOf(first)));
+            }
 
             while (tok.HasMoreTokens)
             {
-				token = tok.NextToken();
-				if (token.Length < 18)
-				{
-					WriteField(bOut, Int64.Parse(token));
-				}
-				else
-				{
-					WriteField(bOut, new BigInteger(token));
-				}
-			}
+                token = tok.NextToken();
+                if (token.Length <= 18)
+                {
+                    WriteField(bOut, Int64.Parse(token));
+                }
+                else
+                {
+                    WriteField(bOut, new BigInteger(token));
+                }
+            }
+        }
 
-            dOut.Dispose();
+        internal byte[] GetBody()
+        {
+            lock (this)
+            {
+                if (body == null)
+                {
+                    MemoryStream bOut = new MemoryStream();
+                    DoOutput(bOut);
+                    body = bOut.ToArray();
+                }
+            }
+
+            return body;
+        }
 
-			derOut.WriteEncoded(Asn1Tags.ObjectIdentifier, bOut.ToArray());
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.ObjectIdentifier, GetBody());
         }
 
-		protected override int Asn1GetHashCode()
-		{
+        protected override int Asn1GetHashCode()
+        {
             return identifier.GetHashCode();
         }
 
-		protected override bool Asn1Equals(
-			Asn1Object asn1Object)
-		{
-			DerObjectIdentifier other = asn1Object as DerObjectIdentifier;
-
-			if (other == null)
-				return false;
-
-			return this.identifier.Equals(other.identifier);
-        }
-
-		public override string ToString()
-		{
-			return identifier;
-		}
-
-		private static string MakeOidStringFromBytes(
-			byte[] bytes)
-		{
-			StringBuilder	objId = new StringBuilder();
-			long			value = 0;
-			BigInteger		bigValue = null;
-			bool			first = true;
-
-			for (int i = 0; i != bytes.Length; i++)
-			{
-				int b = bytes[i];
-
-				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;
-									break;
-							}
-							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;
-					}
-				}
-			}
-
-			return objId.ToString();
-		}
-	}
+        protected override bool Asn1Equals(
+            Asn1Object asn1Object)
+        {
+            DerObjectIdentifier other = asn1Object as DerObjectIdentifier;
+
+            if (other == null)
+                return false;
+
+            return this.identifier.Equals(other.identifier);
+        }
+
+        public override string ToString()
+        {
+            return identifier;
+        }
+
+        private static bool IsValidBranchID(
+            String branchID, int start)
+        {
+            bool periodAllowed = false;
+
+            int pos = branchID.Length;
+            while (--pos >= start)
+            {
+                char ch = branchID[pos];
+
+                // TODO Leading zeroes?
+                if ('0' <= ch && ch <= '9')
+                {
+                    periodAllowed = true;
+                    continue;
+                }
+
+                if (ch == '.')
+                {
+                    if (!periodAllowed)
+                        return false;
+
+                    periodAllowed = false;
+                    continue;
+                }
+
+                return false;
+            }
+
+            return periodAllowed;
+        }
+
+        private static bool IsValidIdentifier(string identifier)
+        {
+            if (identifier.Length < 3 || identifier[1] != '.')
+                return false;
+
+            char first = identifier[0];
+            if (first < '0' || first > '2')
+                return false;
+
+            return IsValidBranchID(identifier, 2);
+        }
+
+        private const long LONG_LIMIT = (long.MaxValue >> 7) - 0x7f;
+
+        private static string MakeOidStringFromBytes(
+            byte[] bytes)
+        {
+            StringBuilder	objId = new StringBuilder();
+            long			value = 0;
+            BigInteger		bigValue = null;
+            bool			first = true;
+
+            for (int i = 0; i != bytes.Length; i++)
+            {
+                int b = bytes[i];
+
+                if (value <= LONG_LIMIT)
+                {
+                    value += (b & 0x7f);
+                    if ((b & 0x80) == 0)             // end of number reached
+                    {
+                        if (first)
+                        {
+                            if (value < 40)
+                            {
+                                objId.Append('0');
+                            }
+                            else if (value < 80)
+                            {
+                                objId.Append('1');
+                                value -= 40;
+                            }
+                            else
+                            {
+                                objId.Append('2');
+                                value -= 80;
+                            }
+                            first = false;
+                        }
+
+                        objId.Append('.');
+                        objId.Append(value);
+                        value = 0;
+                    }
+                    else
+                    {
+                        value <<= 7;
+                    }
+                }
+                else
+                {
+                    if (bigValue == null)
+                    {
+                        bigValue = BigInteger.ValueOf(value);
+                    }
+                    bigValue = bigValue.Or(BigInteger.ValueOf(b & 0x7f));
+                    if ((b & 0x80) == 0)
+                    {
+                        if (first)
+                        {
+                            objId.Append('2');
+                            bigValue = bigValue.Subtract(BigInteger.ValueOf(80));
+                            first = false;
+                        }
+
+                        objId.Append('.');
+                        objId.Append(bigValue);
+                        bigValue = null;
+                        value = 0;
+                    }
+                    else
+                    {
+                        bigValue = bigValue.ShiftLeft(7);
+                    }
+                }
+            }
+
+            return objId.ToString();
+        }
+
+        private static readonly DerObjectIdentifier[] cache = new DerObjectIdentifier[1024];
+
+        internal static DerObjectIdentifier FromOctetString(byte[] enc)
+        {
+            int hashCode = Arrays.GetHashCode(enc);
+            int first = hashCode & 1023;
+
+            lock (cache)
+            {
+                DerObjectIdentifier entry = cache[first];
+                if (entry != null && Arrays.AreEqual(enc, entry.GetBody()))
+                {
+                    return entry;
+                }
+
+                return cache[first] = new DerObjectIdentifier(enc);
+            }
+        }
+    }
 }
diff --git a/crypto/src/asn1/DerOctetString.cs b/crypto/src/asn1/DerOctetString.cs
new file mode 100644
index 000000000..c046c9402
--- /dev/null
+++ b/crypto/src/asn1/DerOctetString.cs
@@ -0,0 +1,34 @@
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerOctetString
+        : Asn1OctetString
+    {
+		/// <param name="str">The octets making up the octet string.</param>
+        public DerOctetString(
+			byte[] str)
+			: base(str)
+        {
+        }
+
+		public DerOctetString(
+			Asn1Encodable obj)
+			: base(obj)
+        {
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.OctetString, str);
+        }
+
+		internal static void Encode(
+			DerOutputStream	derOut,
+			byte[]			bytes,
+			int				offset,
+			int				length)
+		{
+			derOut.WriteEncoded(Asn1Tags.OctetString, bytes, offset, length);
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerOutputStream.cs b/crypto/src/asn1/DerOutputStream.cs
new file mode 100644
index 000000000..f95d123f9
--- /dev/null
+++ b/crypto/src/asn1/DerOutputStream.cs
@@ -0,0 +1,160 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerOutputStream
+		: FilterStream
+	{
+		public DerOutputStream(Stream os)
+			: base(os)
+		{
+		}
+
+		private void WriteLength(
+			int length)
+		{
+			if (length > 127)
+			{
+				int size = 1;
+				uint val = (uint) length;
+
+				while ((val >>= 8) != 0)
+				{
+					size++;
+				}
+
+				WriteByte((byte)(size | 0x80));
+
+				for (int i = (size - 1) * 8; i >= 0; i -= 8)
+				{
+					WriteByte((byte)(length >> i));
+				}
+			}
+			else
+			{
+				WriteByte((byte)length);
+			}
+		}
+
+		internal void WriteEncoded(
+			int		tag,
+			byte[]	bytes)
+		{
+			WriteByte((byte) tag);
+			WriteLength(bytes.Length);
+			Write(bytes, 0, bytes.Length);
+		}
+
+		internal void WriteEncoded(
+			int		tag,
+			byte[]	bytes,
+			int		offset,
+			int		length)
+		{
+			WriteByte((byte) tag);
+			WriteLength(length);
+			Write(bytes, offset, length);
+		}
+
+		internal void WriteTag(
+			int	flags,
+			int	tagNo)
+		{
+			if (tagNo < 31)
+			{
+				WriteByte((byte)(flags | tagNo));
+			}
+			else
+			{
+				WriteByte((byte)(flags | 0x1f));
+				if (tagNo < 128)
+				{
+					WriteByte((byte)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);
+				}
+			}
+		}
+
+		internal void WriteEncoded(
+			int		flags,
+			int		tagNo,
+			byte[]	bytes)
+		{
+			WriteTag(flags, tagNo);
+			WriteLength(bytes.Length);
+			Write(bytes, 0, bytes.Length);
+		}
+
+		protected void WriteNull()
+		{
+			WriteByte(Asn1Tags.Null);
+			WriteByte(0x00);
+		}
+
+		[Obsolete("Use version taking an Asn1Encodable arg instead")]
+		public virtual void WriteObject(
+			object obj)
+		{
+			if (obj == null)
+			{
+				WriteNull();
+			}
+			else if (obj is Asn1Object)
+			{
+				((Asn1Object)obj).Encode(this);
+			}
+			else if (obj is Asn1Encodable)
+			{
+				((Asn1Encodable)obj).ToAsn1Object().Encode(this);
+			}
+			else
+			{
+				throw new IOException("object not Asn1Object");
+			}
+		}
+
+		public virtual void WriteObject(
+			Asn1Encodable obj)
+		{
+			if (obj == null)
+			{
+				WriteNull();
+			}
+			else
+			{
+				obj.ToAsn1Object().Encode(this);
+			}
+		}
+
+		public virtual void WriteObject(
+			Asn1Object obj)
+		{
+			if (obj == null)
+			{
+				WriteNull();
+			}
+			else
+			{
+				obj.Encode(this);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerPrintableString.cs b/crypto/src/asn1/DerPrintableString.cs
new file mode 100644
index 000000000..cd2f46b48
--- /dev/null
+++ b/crypto/src/asn1/DerPrintableString.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der PrintableString object.
+     */
+    public class DerPrintableString
+        : DerStringBase
+    {
+        private readonly string str;
+
+		/**
+         * return a printable string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerPrintableString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerPrintableString)
+            {
+                return (DerPrintableString)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a Printable string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerPrintableString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerPrintableString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerPrintableString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerPrintableString(
+            byte[] str)
+            : this(Strings.FromAsciiByteArray(str), false)
+        {
+        }
+
+		/**
+		 * basic constructor - this does not validate the string
+		 */
+		public DerPrintableString(
+			string str)
+			: this(str, false)
+		{
+		}
+
+		/**
+		* Constructor with optional validation.
+		*
+		* @param string the base string to wrap.
+		* @param validate whether or not to check the string.
+		* @throws ArgumentException if validate is true and the string
+		* contains characters that should not be in a PrintableString.
+		*/
+		public DerPrintableString(
+			string	str,
+			bool	validate)
+		{
+			if (str == null)
+				throw new ArgumentNullException("str");
+			if (validate && !IsPrintableString(str))
+				throw new ArgumentException("string contains illegal characters", "str");
+
+			this.str = str;
+		}
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.PrintableString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerPrintableString other = asn1Object as DerPrintableString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		/**
+		 * 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 bool IsPrintableString(
+			string str)
+		{
+			foreach (char ch in str)
+			{
+				if (ch > 0x007f)
+					return false;
+
+				if (char.IsLetterOrDigit(ch))
+					continue;
+
+//				if (char.IsPunctuation(ch))
+//					continue;
+
+				switch (ch)
+				{
+					case ' ':
+					case '\'':
+					case '(':
+					case ')':
+					case '+':
+					case '-':
+					case '.':
+					case ':':
+					case '=':
+					case '?':
+					case '/':
+					case ',':
+						continue;
+				}
+
+				return false;
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerSequence.cs b/crypto/src/asn1/DerSequence.cs
index dd67d2fed..b50a77962 100644
--- a/crypto/src/asn1/DerSequence.cs
+++ b/crypto/src/asn1/DerSequence.cs
@@ -75,7 +75,7 @@ namespace Org.BouncyCastle.Asn1
 				dOut.WriteObject(obj);
 			}
 
-			dOut.Dispose();
+			dOut.Close();
 
 			byte[] bytes = bOut.ToArray();
 
diff --git a/crypto/src/asn1/DerSet.cs b/crypto/src/asn1/DerSet.cs
index 6d3f438bd..c66dde8c7 100644
--- a/crypto/src/asn1/DerSet.cs
+++ b/crypto/src/asn1/DerSet.cs
@@ -98,7 +98,7 @@ namespace Org.BouncyCastle.Asn1
 				dOut.WriteObject(obj);
 			}
 
-            dOut.Dispose();
+			dOut.Close();
 
 			byte[] bytes = bOut.ToArray();
 
diff --git a/crypto/src/asn1/DerStringBase.cs b/crypto/src/asn1/DerStringBase.cs
new file mode 100644
index 000000000..2a5fb041e
--- /dev/null
+++ b/crypto/src/asn1/DerStringBase.cs
@@ -0,0 +1,22 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public abstract class DerStringBase
+		: Asn1Object, IAsn1String
+	{
+		protected DerStringBase()
+		{
+		}
+
+		public abstract string GetString();
+
+		public override string ToString()
+		{
+			return GetString();
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			return GetString().GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerT61String.cs b/crypto/src/asn1/DerT61String.cs
new file mode 100644
index 000000000..4dee6f30c
--- /dev/null
+++ b/crypto/src/asn1/DerT61String.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der T61String (also the teletex string) - 8-bit characters
+     */
+    public class DerT61String
+        : DerStringBase
+    {
+		private readonly string str;
+
+		/**
+         * return a T61 string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerT61String GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerT61String)
+            {
+                return (DerT61String)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an T61 string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerT61String GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerT61String)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerT61String(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - with bytes.
+         */
+        public DerT61String(
+            byte[] str)
+			: this(Strings.FromByteArray(str))
+		{
+        }
+
+		/**
+         * basic constructor - with string.
+         */
+        public DerT61String(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.T61String, GetOctets());
+        }
+
+        public byte[] GetOctets()
+        {
+			return Strings.ToByteArray(str);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerT61String other = asn1Object as DerT61String;
+
+			if (other == null)
+				return false;
+
+            return this.str.Equals(other.str);
+        }
+	}
+}
diff --git a/crypto/src/asn1/DerTaggedObject.cs b/crypto/src/asn1/DerTaggedObject.cs
new file mode 100644
index 000000000..717d724b6
--- /dev/null
+++ b/crypto/src/asn1/DerTaggedObject.cs
@@ -0,0 +1,72 @@
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * 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
+		: Asn1TaggedObject
+	{
+		/**
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public DerTaggedObject(
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(tagNo, obj)
+		{
+		}
+
+		/**
+		 * @param explicitly true if an explicitly tagged object.
+		 * @param tagNo the tag number for this object.
+		 * @param obj the tagged object.
+		 */
+		public DerTaggedObject(
+			bool			explicitly,
+			int				tagNo,
+			Asn1Encodable	obj)
+			: base(explicitly, tagNo, obj)
+		{
+		}
+
+		/**
+		 * create an implicitly tagged object that contains a zero
+		 * length sequence.
+		 */
+		public DerTaggedObject(
+			int tagNo)
+			: base(false, tagNo, DerSequence.Empty)
+		{
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			if (!IsEmpty())
+			{
+				byte[] bytes = obj.GetDerEncoded();
+
+				if (explicitly)
+				{
+					derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, bytes);
+				}
+				else
+				{
+					//
+					// need to mark constructed types... (preserve Constructed tag)
+					//
+					int flags = (bytes[0] & Asn1Tags.Constructed) | Asn1Tags.Tagged;
+					derOut.WriteTag(flags, tagNo);
+					derOut.Write(bytes, 1, bytes.Length - 1);
+				}
+			}
+			else
+			{
+				derOut.WriteEncoded(Asn1Tags.Constructed | Asn1Tags.Tagged, tagNo, new byte[0]);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerUTCTime.cs b/crypto/src/asn1/DerUTCTime.cs
new file mode 100644
index 000000000..56fabeb47
--- /dev/null
+++ b/crypto/src/asn1/DerUTCTime.cs
@@ -0,0 +1,263 @@
+using System;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * UTC time object.
+     */
+    public class DerUtcTime
+        : Asn1Object
+    {
+        private readonly string time;
+
+		/**
+         * return an UTC Time from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerUtcTime GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerUtcTime)
+            {
+                return (DerUtcTime)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an UTC Time from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerUtcTime GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerUtcTime)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerUtcTime(((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.</p>
+         */
+        public DerUtcTime(
+            string time)
+        {
+			if (time == null)
+				throw new ArgumentNullException("time");
+
+			this.time = time;
+
+			try
+			{
+				ToDateTime();
+			}
+			catch (FormatException e)
+			{
+				throw new ArgumentException("invalid date string: " + e.Message);
+			}
+        }
+
+		/**
+         * base constructor from a DateTime object
+         */
+        public DerUtcTime(
+            DateTime time)
+        {
+            this.time = time.ToString("yyMMddHHmmss") + "Z";
+        }
+
+		internal DerUtcTime(
+            byte[] bytes)
+        {
+            //
+            // explicitly convert to characters
+            //
+            this.time = Strings.FromAsciiByteArray(bytes);
+        }
+
+//		public DateTime ToDateTime()
+//		{
+//			string tm = this.AdjustedTimeString;
+//
+//			return new DateTime(
+//				Int16.Parse(tm.Substring(0, 4)),
+//				Int16.Parse(tm.Substring(4, 2)),
+//				Int16.Parse(tm.Substring(6, 2)),
+//				Int16.Parse(tm.Substring(8, 2)),
+//				Int16.Parse(tm.Substring(10, 2)),
+//				Int16.Parse(tm.Substring(12, 2)));
+//		}
+
+		/**
+		 * return the time as a date based on whatever a 2 digit year will return. For
+		 * standardised processing use ToAdjustedDateTime().
+		 *
+		 * @return the resulting date
+		 * @exception ParseException if the date string cannot be parsed.
+		 */
+		public DateTime ToDateTime()
+		{
+			return ParseDateString(TimeString, @"yyMMddHHmmss'GMT'zzz");
+		}
+
+		/**
+		* 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 DateTime ToAdjustedDateTime()
+		{
+			return ParseDateString(AdjustedTimeString, @"yyyyMMddHHmmss'GMT'zzz");
+		}
+
+		private DateTime ParseDateString(
+			string	dateStr,
+			string	formatStr)
+		{
+			DateTime dt = DateTime.ParseExact(
+				dateStr,
+				formatStr,
+				DateTimeFormatInfo.InvariantInfo);
+
+			return dt.ToUniversalTime();
+		}
+
+		/**
+         * 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>
+         * <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.</p>
+         */
+        public string TimeString
+        {
+			get
+			{
+				//
+				// standardise the format.
+				//
+				if (time.IndexOf('-') < 0 && time.IndexOf('+') < 0)
+				{
+					if (time.Length == 11)
+					{
+						return time.Substring(0, 10) + "00GMT+00:00";
+					}
+					else
+					{
+						return time.Substring(0, 12) + "GMT+00:00";
+					}
+				}
+				else
+				{
+					int index = time.IndexOf('-');
+					if (index < 0)
+					{
+						index = time.IndexOf('+');
+					}
+					string d = time;
+
+					if (index == time.Length - 3)
+					{
+						d += "00";
+					}
+
+					if (index == 10)
+					{
+						return d.Substring(0, 10) + "00GMT" + d.Substring(10, 3) + ":" + d.Substring(13, 2);
+					}
+					else
+					{
+						return d.Substring(0, 12) + "GMT" + d.Substring(12, 3) + ":" +  d.Substring(15, 2);
+					}
+				}
+			}
+        }
+
+		[Obsolete("Use 'AdjustedTimeString' property instead")]
+		public string AdjustedTime
+		{
+			get { return AdjustedTimeString; }
+		}
+
+		/// <summary>
+		/// Return a time string as an adjusted date with a 4 digit year.
+		/// This goes in the range of 1950 - 2049.
+		/// </summary>
+		public string AdjustedTimeString
+		{
+			get
+			{
+				string d = TimeString;
+				string c = d[0] < '5' ? "20" : "19";
+
+				return c + d;
+			}
+		}
+
+        private byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(time);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.UtcTime, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUtcTime other = asn1Object as DerUtcTime;
+
+			if (other == null)
+				return false;
+
+			return this.time.Equals(other.time);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return time.GetHashCode();
+        }
+
+		public override string ToString()
+		{
+			return time;
+		}
+	}
+}
diff --git a/crypto/src/asn1/DerUTF8String.cs b/crypto/src/asn1/DerUTF8String.cs
new file mode 100644
index 000000000..92a50e824
--- /dev/null
+++ b/crypto/src/asn1/DerUTF8String.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der UTF8String object.
+     */
+    public class DerUtf8String
+        : DerStringBase
+    {
+        private readonly string str;
+
+		/**
+         * return an UTF8 string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerUtf8String GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerUtf8String)
+            {
+                return (DerUtf8String)obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an UTF8 string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerUtf8String GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerUtf8String)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerUtf8String(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerUtf8String(
+            byte[] str)
+			: this(Encoding.UTF8.GetString(str, 0, str.Length))
+        {
+        }
+
+		/**
+         * basic constructor
+         */
+        public DerUtf8String(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUtf8String other = asn1Object as DerUtf8String;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		internal override void Encode(
+			DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.Utf8String, Encoding.UTF8.GetBytes(str));
+        }
+    }
+}
diff --git a/crypto/src/asn1/DerUniversalString.cs b/crypto/src/asn1/DerUniversalString.cs
new file mode 100644
index 000000000..305102f2f
--- /dev/null
+++ b/crypto/src/asn1/DerUniversalString.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der UniversalString object.
+     */
+    public class DerUniversalString
+        : DerStringBase
+    {
+        private static readonly char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+		private readonly byte[] str;
+
+		/**
+         * return a Universal string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerUniversalString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerUniversalString)
+            {
+                return (DerUniversalString)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a Universal string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerUniversalString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerUniversalString)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerUniversalString(Asn1OctetString.GetInstance(o).GetOctets());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerUniversalString(
+            byte[] str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+        public override string GetString()
+        {
+			StringBuilder buffer = new StringBuilder("#");
+			byte[] enc = GetDerEncoded();
+
+			for (int i = 0; i != enc.Length; i++)
+			{
+				uint ubyte = enc[i];
+				buffer.Append(table[(ubyte >> 4) & 0xf]);
+				buffer.Append(table[enc[i] & 0xf]);
+			}
+
+            return buffer.ToString();
+        }
+
+		public byte[] GetOctets()
+        {
+            return (byte[]) str.Clone();
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.UniversalString, this.str);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUniversalString other = asn1Object as DerUniversalString;
+
+			if (other == null)
+				return false;
+
+//			return this.GetString().Equals(other.GetString());
+			return Arrays.AreEqual(this.str, other.str);
+        }
+    }
+}
diff --git a/crypto/src/asn1/DerVisibleString.cs b/crypto/src/asn1/DerVisibleString.cs
new file mode 100644
index 000000000..84c9caade
--- /dev/null
+++ b/crypto/src/asn1/DerVisibleString.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Der VisibleString object.
+     */
+    public class DerVisibleString
+        : DerStringBase
+    {
+        private readonly string str;
+
+        /**
+         * return a Visible string from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerVisibleString GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerVisibleString)
+            {
+                return (DerVisibleString)obj;
+            }
+
+            if (obj is Asn1OctetString)
+            {
+                return new DerVisibleString(((Asn1OctetString)obj).GetOctets());
+            }
+
+            if (obj is Asn1TaggedObject)
+            {
+                return GetInstance(((Asn1TaggedObject)obj).GetObject());
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return a Visible string from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *               be converted.
+         */
+        public static DerVisibleString GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+        /**
+         * basic constructor - byte encoded string.
+         */
+        public DerVisibleString(
+            byte[] str)
+			: this(Strings.FromAsciiByteArray(str))
+        {
+        }
+
+		/**
+         * basic constructor
+         */
+        public DerVisibleString(
+            string str)
+        {
+			if (str == null)
+				throw new ArgumentNullException("str");
+
+			this.str = str;
+        }
+
+		public override string GetString()
+        {
+            return str;
+        }
+
+		public byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(str);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.VisibleString, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerVisibleString other = asn1Object as DerVisibleString;
+
+			if (other == null)
+				return false;
+
+			return this.str.Equals(other.str);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return this.str.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/asn1/IAsn1ApplicationSpecificParser.cs b/crypto/src/asn1/IAsn1ApplicationSpecificParser.cs
new file mode 100644
index 000000000..89cf64c70
--- /dev/null
+++ b/crypto/src/asn1/IAsn1ApplicationSpecificParser.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public interface IAsn1ApplicationSpecificParser
+    	: IAsn1Convertible
+	{
+    	IAsn1Convertible ReadObject();
+	}
+}
diff --git a/crypto/src/asn1/IAsn1Choice.cs b/crypto/src/asn1/IAsn1Choice.cs
new file mode 100644
index 000000000..ecd76e427
--- /dev/null
+++ b/crypto/src/asn1/IAsn1Choice.cs
@@ -0,0 +1,17 @@
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * Marker interface for CHOICE objects - if you implement this in a roll-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. 
+	 * </p>
+	 */
+	public interface IAsn1Choice
+	{
+		// marker interface
+	}
+}
diff --git a/crypto/src/asn1/IAsn1Convertible.cs b/crypto/src/asn1/IAsn1Convertible.cs
new file mode 100644
index 000000000..d3f83afc9
--- /dev/null
+++ b/crypto/src/asn1/IAsn1Convertible.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Asn1
+{
+	public interface IAsn1Convertible
+	{
+		Asn1Object ToAsn1Object();
+	}
+}
diff --git a/crypto/src/asn1/IAsn1String.cs b/crypto/src/asn1/IAsn1String.cs
new file mode 100644
index 000000000..cbc2635ff
--- /dev/null
+++ b/crypto/src/asn1/IAsn1String.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * basic interface for Der string objects.
+     */
+    public interface IAsn1String
+    {
+        string GetString();
+    }
+}
diff --git a/crypto/src/asn1/IndefiniteLengthInputStream.cs b/crypto/src/asn1/IndefiniteLengthInputStream.cs
index 56c1bdfbc..09d0e3a42 100644
--- a/crypto/src/asn1/IndefiniteLengthInputStream.cs
+++ b/crypto/src/asn1/IndefiniteLengthInputStream.cs
@@ -22,12 +22,15 @@ namespace Org.BouncyCastle.Asn1
 			bool eofOn00)
 		{
 			_eofOn00 = eofOn00;
-            CheckForEof();
+            if (_eofOn00)
+            {
+                CheckForEof();
+            }
         }
 
-		private bool CheckForEof()
+        private bool CheckForEof()
 		{
-            if (_lookAhead == 0x00 && _eofOn00)
+            if (_lookAhead == 0x00)
             {
                 int extra = RequireByte();
                 if (extra != 0)
@@ -37,6 +40,7 @@ namespace Org.BouncyCastle.Asn1
 
                 _lookAhead = -1;
                 SetParentEofDetect(true);
+                return true;
             }
             return _lookAhead < 0;
         }
@@ -69,7 +73,7 @@ namespace Org.BouncyCastle.Asn1
 
 		public override int ReadByte()
 		{
-			if (CheckForEof())
+            if (_eofOn00 && CheckForEof())
 				return -1;
 
             int result = _lookAhead;
diff --git a/crypto/src/asn1/LazyASN1InputStream.cs b/crypto/src/asn1/LazyASN1InputStream.cs
new file mode 100644
index 000000000..4cf2305fd
--- /dev/null
+++ b/crypto/src/asn1/LazyASN1InputStream.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class LazyAsn1InputStream
+		: Asn1InputStream
+	{
+		public LazyAsn1InputStream(
+			byte[] input)
+			: base(input)
+		{
+		}
+
+		public LazyAsn1InputStream(
+			Stream inputStream)
+			: base(inputStream)
+		{
+		}
+
+		internal override DerSequence CreateDerSequence(
+			DefiniteLengthInputStream dIn)
+		{
+			return new LazyDerSequence(dIn.ToArray());
+		}
+
+		internal override DerSet CreateDerSet(
+			DefiniteLengthInputStream dIn)
+		{
+			return new LazyDerSet(dIn.ToArray());
+		}
+	}
+}
diff --git a/crypto/src/asn1/LazyDERSequence.cs b/crypto/src/asn1/LazyDERSequence.cs
index 5e3dd076e..7301bc158 100644
--- a/crypto/src/asn1/LazyDERSequence.cs
+++ b/crypto/src/asn1/LazyDERSequence.cs
@@ -7,10 +7,9 @@ namespace Org.BouncyCastle.Asn1
 	internal class LazyDerSequence
 		: DerSequence
 	{
-		private byte[]	encoded;
-		private bool	parsed = false;
+		private byte[] encoded;
 
-		internal LazyDerSequence(
+        internal LazyDerSequence(
 			byte[] encoded)
 		{
 			this.encoded = encoded;
@@ -20,7 +19,7 @@ namespace Org.BouncyCastle.Asn1
 		{
 			lock (this)
 			{
-				if (!parsed)
+				if (encoded != null)
 				{
 					Asn1InputStream e = new LazyAsn1InputStream(encoded);
 
@@ -31,7 +30,6 @@ namespace Org.BouncyCastle.Asn1
 					}
 
 					encoded = null;
-					parsed = true;
 				}
 			}
 		}
@@ -68,7 +66,7 @@ namespace Org.BouncyCastle.Asn1
 		{
 			lock (this)
 			{
-				if (parsed)
+				if (encoded == null)
 				{
 					base.Encode(derOut);
 				}
diff --git a/crypto/src/asn1/LazyDERSet.cs b/crypto/src/asn1/LazyDERSet.cs
index 84fce4808..e6c9319dd 100644
--- a/crypto/src/asn1/LazyDERSet.cs
+++ b/crypto/src/asn1/LazyDERSet.cs
@@ -7,10 +7,9 @@ namespace Org.BouncyCastle.Asn1
 	internal class LazyDerSet
 		: DerSet
 	{
-		private byte[]	encoded;
-		private bool	parsed = false;
+		private byte[] encoded;
 
-		internal LazyDerSet(
+        internal LazyDerSet(
 			byte[] encoded)
 		{
 			this.encoded = encoded;
@@ -20,7 +19,7 @@ namespace Org.BouncyCastle.Asn1
 		{
 			lock (this)
 			{
-				if (!parsed)
+				if (encoded != null)
 				{
 					Asn1InputStream e = new LazyAsn1InputStream(encoded);
 
@@ -31,7 +30,6 @@ namespace Org.BouncyCastle.Asn1
 					}
 
 					encoded = null;
-					parsed = true;
 				}
 			}
 		}
@@ -68,7 +66,7 @@ namespace Org.BouncyCastle.Asn1
 		{
 			lock (this)
 			{
-				if (parsed)
+				if (encoded == null)
 				{
 					base.Encode(derOut);
 				}
diff --git a/crypto/src/asn1/LimitedInputStream.cs b/crypto/src/asn1/LimitedInputStream.cs
new file mode 100644
index 000000000..62486aa77
--- /dev/null
+++ b/crypto/src/asn1/LimitedInputStream.cs
@@ -0,0 +1,35 @@
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    internal abstract class LimitedInputStream
+        : BaseInputStream
+    {
+        protected readonly Stream _in;
+		private int _limit;
+
+        internal LimitedInputStream(
+            Stream	inStream,
+			int		limit)
+        {
+            this._in = inStream;
+			this._limit = limit;
+        }
+
+	    internal virtual int GetRemaining()
+	    {
+	        // TODO: maybe one day this can become more accurate
+	        return _limit;
+	    }
+
+		protected virtual void SetParentEofDetect(bool on)
+        {
+            if (_in is IndefiniteLengthInputStream)
+            {
+                ((IndefiniteLengthInputStream)_in).SetEofOn00(on);
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/OidTokenizer.cs b/crypto/src/asn1/OidTokenizer.cs
new file mode 100644
index 000000000..6e76e8c8b
--- /dev/null
+++ b/crypto/src/asn1/OidTokenizer.cs
@@ -0,0 +1,45 @@
+namespace 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;
+        }
+
+		public bool HasMoreTokens
+        {
+			get { return index != -1; }
+        }
+
+		public string NextToken()
+        {
+            if (index == -1)
+            {
+                return null;
+            }
+
+            int end = oid.IndexOf('.', index);
+            if (end == -1)
+            {
+                string lastToken = oid.Substring(index);
+                index = -1;
+                return lastToken;
+            }
+
+            string nextToken = oid.Substring(index, end - index);
+			index = end + 1;
+            return nextToken;
+        }
+    }
+}
diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
new file mode 100644
index 000000000..075e5384c
--- /dev/null
+++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.BC
+{
+	public abstract class BCObjectIdentifiers
+	{
+		// iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle
+		// 1.3.6.1.4.1.22554
+		public static readonly DerObjectIdentifier bc = new DerObjectIdentifier("1.3.6.1.4.1.22554");
+
+		// pbe(1) algorithms
+		public static readonly DerObjectIdentifier bc_pbe = new DerObjectIdentifier(bc + ".1");
+
+		// SHA-1(1)
+		public static readonly DerObjectIdentifier bc_pbe_sha1 = new DerObjectIdentifier(bc_pbe + ".1");
+
+		// SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4))
+		public static readonly DerObjectIdentifier bc_pbe_sha256 = new DerObjectIdentifier(bc_pbe + ".2.1");
+		public static readonly DerObjectIdentifier bc_pbe_sha384 = new DerObjectIdentifier(bc_pbe + ".2.2");
+		public static readonly DerObjectIdentifier bc_pbe_sha512 = new DerObjectIdentifier(bc_pbe + ".2.3");
+		public static readonly DerObjectIdentifier bc_pbe_sha224 = new DerObjectIdentifier(bc_pbe + ".2.4");
+		
+		// PKCS-5(1)|PKCS-12(2)
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs5 = new DerObjectIdentifier(bc_pbe_sha1 + ".1");
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12 = new DerObjectIdentifier(bc_pbe_sha1 + ".2");
+		
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs5 = new DerObjectIdentifier(bc_pbe_sha256 + ".1");
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12 = new DerObjectIdentifier(bc_pbe_sha256 + ".2");
+
+		// AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42))
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.2");
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.22");
+		public static readonly DerObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha1_pkcs12 + ".1.42");
+
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.2");
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.22");
+		public static readonly DerObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new DerObjectIdentifier(bc_pbe_sha256_pkcs12 + ".1.42");
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs b/crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs
new file mode 100644
index 000000000..3cdb128a6
--- /dev/null
+++ b/crypto/src/asn1/cmp/CAKeyUpdAnnContent.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CAKeyUpdAnnContent
+		: Asn1Encodable
+	{
+		private readonly CmpCertificate oldWithNew;
+		private readonly CmpCertificate newWithOld;
+		private readonly CmpCertificate newWithNew;
+
+		private CAKeyUpdAnnContent(Asn1Sequence seq)
+		{
+			oldWithNew = CmpCertificate.GetInstance(seq[0]);
+			newWithOld = CmpCertificate.GetInstance(seq[1]);
+			newWithNew = CmpCertificate.GetInstance(seq[2]);
+		}
+
+		public static CAKeyUpdAnnContent GetInstance(object obj)
+		{
+			if (obj is CAKeyUpdAnnContent)
+				return (CAKeyUpdAnnContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new CAKeyUpdAnnContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual CmpCertificate OldWithNew
+		{
+			get { return oldWithNew; }
+		}
+		
+		public virtual CmpCertificate NewWithOld
+		{
+			get { return newWithOld; }
+		}
+
+		public virtual CmpCertificate NewWithNew
+		{
+			get { return newWithNew; }
+		}
+
+		/**
+		 * <pre>
+		 * CAKeyUpdAnnContent ::= SEQUENCE {
+		 *                             oldWithNew   CmpCertificate, -- old pub signed with new priv
+		 *                             newWithOld   CmpCertificate, -- new pub signed with old priv
+		 *                             newWithNew   CmpCertificate  -- new pub signed with new priv
+		 *  }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(oldWithNew, newWithOld, newWithNew);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/CertConfirmContent.cs b/crypto/src/asn1/cmp/CertConfirmContent.cs
new file mode 100644
index 000000000..f4016d8d8
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertConfirmContent.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertConfirmContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private CertConfirmContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static CertConfirmContent GetInstance(object obj)
+		{
+			if (obj is CertConfirmContent)
+				return (CertConfirmContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertConfirmContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual CertStatus[] ToCertStatusArray()
+		{
+			CertStatus[] result = new CertStatus[content.Count];
+			for (int i = 0; i != result.Length; i++)
+			{
+				result[i] = CertStatus.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * CertConfirmContent ::= SEQUENCE OF CertStatus
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/CertOrEncCert.cs b/crypto/src/asn1/cmp/CertOrEncCert.cs
new file mode 100644
index 000000000..4c049c180
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertOrEncCert.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertOrEncCert
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly CmpCertificate certificate;
+		private readonly EncryptedValue encryptedCert;
+
+		private CertOrEncCert(Asn1TaggedObject tagged)
+		{
+			if (tagged.TagNo == 0)
+			{
+				certificate = CmpCertificate.GetInstance(tagged.GetObject());
+			}
+			else if (tagged.TagNo == 1)
+			{
+				encryptedCert = EncryptedValue.GetInstance(tagged.GetObject());
+			}
+			else
+			{
+				throw new ArgumentException("unknown tag: " + tagged.TagNo, "tagged");
+			}
+		}
+		
+		public static CertOrEncCert GetInstance(object obj)
+		{
+			if (obj is CertOrEncCert)
+				return (CertOrEncCert)obj;
+
+			if (obj is Asn1TaggedObject)
+				return new CertOrEncCert((Asn1TaggedObject)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertOrEncCert(CmpCertificate certificate)
+		{
+			if (certificate == null)
+				throw new ArgumentNullException("certificate");
+
+			this.certificate = certificate;
+		}
+
+		public CertOrEncCert(EncryptedValue encryptedCert)
+		{
+			if (encryptedCert == null)
+				throw new ArgumentNullException("encryptedCert");
+
+			this.encryptedCert = encryptedCert;
+		}
+
+		public virtual CmpCertificate Certificate
+		{
+			get { return certificate; }
+		}
+
+		public virtual EncryptedValue EncryptedCert
+		{
+			get { return encryptedCert; }
+		}
+
+		/**
+		 * <pre>
+		 * CertOrEncCert ::= CHOICE {
+		 *                      certificate     [0] CMPCertificate,
+		 *                      encryptedCert   [1] EncryptedValue
+		 *           }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			if (certificate != null)
+			{
+				return new DerTaggedObject(true, 0, certificate);
+			}
+
+			return new DerTaggedObject(true, 1, encryptedCert);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/CertRepMessage.cs b/crypto/src/asn1/cmp/CertRepMessage.cs
new file mode 100644
index 000000000..c22b079c8
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertRepMessage.cs
@@ -0,0 +1,94 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertRepMessage
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence caPubs;
+		private readonly Asn1Sequence response;
+		
+		private CertRepMessage(Asn1Sequence seq)
+		{
+			int index = 0;
+
+			if (seq.Count > 1)
+			{
+				caPubs = Asn1Sequence.GetInstance((Asn1TaggedObject)seq[index++], true);
+			}
+
+			response = Asn1Sequence.GetInstance(seq[index]);
+		}
+
+		public static CertRepMessage GetInstance(object obj)
+		{
+			if (obj is CertRepMessage)
+				return (CertRepMessage)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertRepMessage((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertRepMessage(CmpCertificate[] caPubs, CertResponse[] response)
+		{
+			if (response == null)
+				throw new ArgumentNullException("response");
+
+			if (caPubs != null)
+			{
+				this.caPubs = new DerSequence(caPubs);
+			}
+
+			this.response = new DerSequence(response);
+		}
+
+		public virtual CmpCertificate[] GetCAPubs()
+		{
+			if (caPubs == null)
+				return null;
+
+			CmpCertificate[] results = new CmpCertificate[caPubs.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CmpCertificate.GetInstance(caPubs[i]);
+			}
+			return results;
+		}
+
+		public virtual CertResponse[] GetResponse()
+		{
+			CertResponse[] results = new CertResponse[response.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertResponse.GetInstance(response[i]);
+			}
+			return results;
+		}
+
+		/**
+		 * <pre>
+		 * CertRepMessage ::= SEQUENCE {
+		 *                          caPubs       [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+		 *                                                                             OPTIONAL,
+		 *                          response         SEQUENCE OF CertResponse
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (caPubs != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, caPubs));
+			}
+
+			v.Add(response);
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/CertResponse.cs b/crypto/src/asn1/cmp/CertResponse.cs
new file mode 100644
index 000000000..246b8ce70
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertResponse.cs
@@ -0,0 +1,115 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertResponse
+		: Asn1Encodable
+	{
+		private readonly DerInteger certReqId;
+		private readonly PkiStatusInfo status;
+		private readonly CertifiedKeyPair certifiedKeyPair;
+		private readonly Asn1OctetString rspInfo;
+
+		private CertResponse(Asn1Sequence seq)
+		{
+			certReqId = DerInteger.GetInstance(seq[0]);
+			status = PkiStatusInfo.GetInstance(seq[1]);
+
+			if (seq.Count >= 3)
+			{
+				if (seq.Count == 3)
+				{
+					Asn1Encodable o = seq[2];
+					if (o is Asn1OctetString)
+					{
+						rspInfo = Asn1OctetString.GetInstance(o);
+					}
+					else
+					{
+						certifiedKeyPair = CertifiedKeyPair.GetInstance(o);
+					}
+				}
+				else
+				{
+					certifiedKeyPair = CertifiedKeyPair.GetInstance(seq[2]);
+					rspInfo = Asn1OctetString.GetInstance(seq[3]);
+				}
+			}
+		}
+
+		public static CertResponse GetInstance(object obj)
+		{
+			if (obj is CertResponse)
+				return (CertResponse)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertResponse((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertResponse(
+			DerInteger certReqId,
+			PkiStatusInfo status)
+			: this(certReqId, status, null, null)
+		{
+		}
+
+		public CertResponse(
+			DerInteger			certReqId,
+			PkiStatusInfo		status,
+			CertifiedKeyPair	certifiedKeyPair,
+			Asn1OctetString		rspInfo)
+		{
+			if (certReqId == null)
+				throw new ArgumentNullException("certReqId");
+
+			if (status == null)
+				throw new ArgumentNullException("status");
+
+			this.certReqId = certReqId;
+			this.status = status;
+			this.certifiedKeyPair = certifiedKeyPair;
+			this.rspInfo = rspInfo;
+		}
+
+		public virtual DerInteger CertReqID
+		{
+			get { return certReqId; }
+		}
+
+		public virtual PkiStatusInfo Status
+		{
+			get { return status; }
+		}
+
+		public virtual CertifiedKeyPair CertifiedKeyPair
+		{
+			get { return certifiedKeyPair; }
+		}
+
+		/**
+		 * <pre>
+		 * CertResponse ::= SEQUENCE {
+		 *                            certReqId           INTEGER,
+		 *                            -- to match this response with corresponding request (a value
+		 *                            -- of -1 is to be used if certReqId is not specified in the
+		 *                            -- corresponding request)
+		 *                            status              PKIStatusInfo,
+		 *                            certifiedKeyPair    CertifiedKeyPair    OPTIONAL,
+		 *                            rspInfo             OCTET STRING        OPTIONAL
+		 *                            -- analogous to the id-regInfo-utf8Pairs string defined
+		 *                            -- for regInfo in CertReqMsg [CRMF]
+		 *             }
+		 * </pre> 
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certReqId, status);
+			v.AddOptional(certifiedKeyPair);
+			v.AddOptional(rspInfo);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/CertStatus.cs b/crypto/src/asn1/cmp/CertStatus.cs
new file mode 100644
index 000000000..52d5ac504
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertStatus.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertStatus
+		: Asn1Encodable
+	{
+		private readonly Asn1OctetString certHash;
+		private readonly DerInteger certReqId;
+		private readonly PkiStatusInfo statusInfo;
+
+		private CertStatus(Asn1Sequence seq)
+		{
+			certHash = Asn1OctetString.GetInstance(seq[0]);
+			certReqId = DerInteger.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				statusInfo = PkiStatusInfo.GetInstance(seq[2]);
+			}
+		}
+
+		public CertStatus(byte[] certHash, BigInteger certReqId)
+		{
+			this.certHash = new DerOctetString(certHash);
+			this.certReqId = new DerInteger(certReqId);
+		}
+
+		public CertStatus(byte[] certHash, BigInteger certReqId, PkiStatusInfo statusInfo)
+		{
+			this.certHash = new DerOctetString(certHash);
+			this.certReqId = new DerInteger(certReqId);
+			this.statusInfo = statusInfo;
+		}
+
+		public static CertStatus GetInstance(object obj)
+		{
+			if (obj is CertStatus)
+				return (CertStatus)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertStatus((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual Asn1OctetString CertHash
+		{
+			get { return certHash; }
+		}
+
+		public virtual DerInteger CertReqID
+		{
+			get { return certReqId; }
+		}
+
+		public virtual PkiStatusInfo StatusInfo
+		{
+			get { return statusInfo; }
+		}
+
+		/**
+		 * <pre>
+		 * CertStatus ::= SEQUENCE {
+		 *                   certHash    OCTET STRING,
+		 *                   -- the hash of the certificate, using the same hash algorithm
+		 *                   -- as is used to create and verify the certificate signature
+		 *                   certReqId   INTEGER,
+		 *                   -- to match this confirmation with the corresponding req/rep
+		 *                   statusInfo  PKIStatusInfo OPTIONAL
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certHash, certReqId);
+			v.AddOptional(statusInfo);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/CertifiedKeyPair.cs b/crypto/src/asn1/cmp/CertifiedKeyPair.cs
new file mode 100644
index 000000000..655dde0c5
--- /dev/null
+++ b/crypto/src/asn1/cmp/CertifiedKeyPair.cs
@@ -0,0 +1,114 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CertifiedKeyPair
+		: Asn1Encodable
+	{
+		private readonly CertOrEncCert certOrEncCert;
+		private readonly EncryptedValue privateKey;
+		private readonly PkiPublicationInfo publicationInfo;
+
+		private CertifiedKeyPair(Asn1Sequence seq)
+		{
+			certOrEncCert = CertOrEncCert.GetInstance(seq[0]);
+
+			if (seq.Count >= 2)
+			{
+				if (seq.Count == 2)
+				{
+					Asn1TaggedObject tagged = Asn1TaggedObject.GetInstance(seq[1]);
+					if (tagged.TagNo == 0)
+					{
+						privateKey = EncryptedValue.GetInstance(tagged.GetObject());
+					}
+					else
+					{
+						publicationInfo = PkiPublicationInfo.GetInstance(tagged.GetObject());
+					}
+				}
+				else
+				{
+					privateKey = EncryptedValue.GetInstance(Asn1TaggedObject.GetInstance(seq[1]));
+					publicationInfo = PkiPublicationInfo.GetInstance(Asn1TaggedObject.GetInstance(seq[2]));
+				}
+			}
+		}
+
+		public static CertifiedKeyPair GetInstance(object obj)
+		{
+			if (obj is CertifiedKeyPair)
+				return (CertifiedKeyPair)obj;
+
+			if (obj is Asn1Sequence)
+				return new CertifiedKeyPair((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public CertifiedKeyPair(
+			CertOrEncCert certOrEncCert)
+			: this(certOrEncCert, null, null)
+		{
+		}
+
+		public CertifiedKeyPair(
+			CertOrEncCert		certOrEncCert,
+			EncryptedValue		privateKey,
+			PkiPublicationInfo	publicationInfo
+		)
+		{
+			if (certOrEncCert == null)
+				throw new ArgumentNullException("certOrEncCert");
+
+			this.certOrEncCert = certOrEncCert;
+			this.privateKey = privateKey;
+			this.publicationInfo = publicationInfo;
+		}
+
+		public virtual CertOrEncCert CertOrEncCert
+		{
+			get { return certOrEncCert; }
+		}
+
+		public virtual EncryptedValue PrivateKey
+		{
+			get { return privateKey; }
+		}
+
+		public virtual PkiPublicationInfo PublicationInfo
+		{
+			get { return publicationInfo; }
+		}
+
+		/**
+		 * <pre>
+		 * CertifiedKeyPair ::= SEQUENCE {
+		 *                                  certOrEncCert       CertOrEncCert,
+		 *                                  privateKey      [0] EncryptedValue      OPTIONAL,
+		 *                                  -- see [CRMF] for comment on encoding
+		 *                                  publicationInfo [1] PKIPublicationInfo  OPTIONAL
+		 *       }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certOrEncCert);
+
+			if (privateKey != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, privateKey));
+			}
+
+			if (publicationInfo != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, publicationInfo));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/Challenge.cs b/crypto/src/asn1/cmp/Challenge.cs
new file mode 100644
index 000000000..bee5f96f5
--- /dev/null
+++ b/crypto/src/asn1/cmp/Challenge.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class Challenge
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier owf;
+		private readonly Asn1OctetString witness;
+		private readonly Asn1OctetString challenge;
+
+		private Challenge(Asn1Sequence seq)
+		{
+			int index = 0;
+
+			if (seq.Count == 3)
+			{
+				owf = AlgorithmIdentifier.GetInstance(seq[index++]);
+			}
+
+			witness = Asn1OctetString.GetInstance(seq[index++]);
+			challenge = Asn1OctetString.GetInstance(seq[index]);
+		}
+
+		public static Challenge GetInstance(object obj)
+		{
+			if (obj is Challenge)
+				return (Challenge)obj;
+
+			if (obj is Asn1Sequence)
+				return new Challenge((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual AlgorithmIdentifier Owf
+		{
+			get { return owf; }
+		}
+
+		/**
+		 * <pre>
+		 * Challenge ::= SEQUENCE {
+		 *                 owf                 AlgorithmIdentifier  OPTIONAL,
+		 *
+		 *                 -- MUST be present in the first Challenge; MAY be omitted in
+		 *                 -- any subsequent Challenge in POPODecKeyChallContent (if
+		 *                 -- omitted, then the owf used in the immediately preceding
+		 *                 -- Challenge is to be used).
+		 *
+		 *                 witness             OCTET STRING,
+		 *                 -- the result of applying the one-way function (owf) to a
+		 *                 -- randomly-generated INTEGER, A.  [Note that a different
+		 *                 -- INTEGER MUST be used for each Challenge.]
+		 *                 challenge           OCTET STRING
+		 *                 -- the encryption (under the public key for which the cert.
+		 *                 -- request is being made) of Rand, where Rand is specified as
+		 *                 --   Rand ::= SEQUENCE {
+		 *                 --      int      INTEGER,
+		 *                 --       - the randomly-generated INTEGER A (above)
+		 *                 --      sender   GeneralName
+		 *                 --       - the sender's name (as included in PKIHeader)
+		 *                 --   }
+		 *      }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+			v.AddOptional(owf);
+			v.Add(witness);
+			v.Add(challenge);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/CmpCertificate.cs b/crypto/src/asn1/cmp/CmpCertificate.cs
new file mode 100644
index 000000000..16ee30059
--- /dev/null
+++ b/crypto/src/asn1/cmp/CmpCertificate.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class CmpCertificate
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly X509CertificateStructure x509v3PKCert;
+        private readonly AttributeCertificate x509v2AttrCert;
+
+        /**
+         * Note: the addition of attribute certificates is a BC extension.
+         */
+        public CmpCertificate(AttributeCertificate x509v2AttrCert)
+        {
+            this.x509v2AttrCert = x509v2AttrCert;
+        }
+
+        public CmpCertificate(X509CertificateStructure x509v3PKCert)
+        {
+            if (x509v3PKCert.Version != 3)
+                throw new ArgumentException("only version 3 certificates allowed", "x509v3PKCert");
+
+            this.x509v3PKCert = x509v3PKCert;
+        }
+
+        public static CmpCertificate GetInstance(object obj)
+        {
+            if (obj is CmpCertificate)
+                return (CmpCertificate)obj;
+
+            if (obj is Asn1Sequence)
+                return new CmpCertificate(X509CertificateStructure.GetInstance(obj));
+
+            if (obj is Asn1TaggedObject)
+                return new CmpCertificate(AttributeCertificate.GetInstance(((Asn1TaggedObject)obj).GetObject()));
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual bool IsX509v3PKCert
+        {
+            get { return x509v3PKCert != null; }
+        }
+
+        public virtual X509CertificateStructure X509v3PKCert
+        {
+            get { return x509v3PKCert; }
+        }
+
+        public virtual AttributeCertificate X509v2AttrCert
+        {
+            get { return x509v2AttrCert; }
+        }
+
+        /**
+         * <pre>
+         * CMPCertificate ::= CHOICE {
+         *            x509v3PKCert        Certificate
+         *            x509v2AttrCert      [1] AttributeCertificate
+         *  }
+         * </pre>
+         * Note: the addition of attribute certificates is a BC extension.
+         *
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (x509v2AttrCert != null)
+            {
+                // explicit following CMP conventions
+                return new DerTaggedObject(true, 1, x509v2AttrCert);
+            }
+
+            return x509v3PKCert.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs b/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
new file mode 100644
index 000000000..7e8274175
--- /dev/null
+++ b/crypto/src/asn1/cmp/CmpObjectIdentifiers.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public abstract class CmpObjectIdentifiers
+	{
+		// RFC 4210
+
+		// id-PasswordBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 13}
+		public static readonly DerObjectIdentifier passwordBasedMac = new DerObjectIdentifier("1.2.840.113533.7.66.13");
+
+		// id-DHBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 30}
+		public static readonly DerObjectIdentifier dhBasedMac = new DerObjectIdentifier("1.2.840.113533.7.66.30");
+
+		// Example InfoTypeAndValue contents include, but are not limited
+		// to, the following (un-comment in this ASN.1 module and use as
+		// appropriate for a given environment):
+		//
+		// id-it-caProtEncCert OBJECT IDENTIFIER ::= {id-it 1}
+		// CAProtEncCertValue ::= CMPCertificate
+		// id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2}
+		// SignKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+		// id-it-encKeyPairTypes OBJECT IDENTIFIER ::= {id-it 3}
+		// EncKeyPairTypesValue ::= SEQUENCE OF AlgorithmIdentifier
+		// id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4}
+		// PreferredSymmAlgValue ::= AlgorithmIdentifier
+		// id-it-caKeyUpdateInfo OBJECT IDENTIFIER ::= {id-it 5}
+		// CAKeyUpdateInfoValue ::= CAKeyUpdAnnContent
+		// id-it-currentCRL OBJECT IDENTIFIER ::= {id-it 6}
+		// CurrentCRLValue ::= CertificateList
+		// id-it-unsupportedOIDs OBJECT IDENTIFIER ::= {id-it 7}
+		// UnsupportedOIDsValue ::= SEQUENCE OF OBJECT IDENTIFIER
+		// id-it-keyPairParamReq OBJECT IDENTIFIER ::= {id-it 10}
+		// KeyPairParamReqValue ::= OBJECT IDENTIFIER
+		// id-it-keyPairParamRep OBJECT IDENTIFIER ::= {id-it 11}
+		// KeyPairParamRepValue ::= AlgorithmIdentifer
+		// id-it-revPassphrase OBJECT IDENTIFIER ::= {id-it 12}
+		// RevPassphraseValue ::= EncryptedValue
+		// id-it-implicitConfirm OBJECT IDENTIFIER ::= {id-it 13}
+		// ImplicitConfirmValue ::= NULL
+		// id-it-confirmWaitTime OBJECT IDENTIFIER ::= {id-it 14}
+		// ConfirmWaitTimeValue ::= GeneralizedTime
+		// id-it-origPKIMessage OBJECT IDENTIFIER ::= {id-it 15}
+		// OrigPKIMessageValue ::= PKIMessages
+		// id-it-suppLangTags OBJECT IDENTIFIER ::= {id-it 16}
+		// SuppLangTagsValue ::= SEQUENCE OF UTF8String
+		//
+		// where
+		//
+		// id-pkix OBJECT IDENTIFIER ::= {
+		// iso(1) identified-organization(3)
+		// dod(6) internet(1) security(5) mechanisms(5) pkix(7)}
+		// and
+		// id-it OBJECT IDENTIFIER ::= {id-pkix 4}
+		public static readonly DerObjectIdentifier it_caProtEncCert = new DerObjectIdentifier("1.3.6.1.5.5.7.4.1");
+		public static readonly DerObjectIdentifier it_signKeyPairTypes = new DerObjectIdentifier("1.3.6.1.5.5.7.4.2");
+		public static readonly DerObjectIdentifier it_encKeyPairTypes = new DerObjectIdentifier("1.3.6.1.5.5.7.4.3");
+		public static readonly DerObjectIdentifier it_preferredSymAlg = new DerObjectIdentifier("1.3.6.1.5.5.7.4.4");
+		public static readonly DerObjectIdentifier it_caKeyUpdateInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.4.5");
+		public static readonly DerObjectIdentifier it_currentCRL = new DerObjectIdentifier("1.3.6.1.5.5.7.4.6");
+		public static readonly DerObjectIdentifier it_unsupportedOIDs = new DerObjectIdentifier("1.3.6.1.5.5.7.4.7");
+		public static readonly DerObjectIdentifier it_keyPairParamReq = new DerObjectIdentifier("1.3.6.1.5.5.7.4.10");
+		public static readonly DerObjectIdentifier it_keyPairParamRep = new DerObjectIdentifier("1.3.6.1.5.5.7.4.11");
+		public static readonly DerObjectIdentifier it_revPassphrase = new DerObjectIdentifier("1.3.6.1.5.5.7.4.12");
+		public static readonly DerObjectIdentifier it_implicitConfirm = new DerObjectIdentifier("1.3.6.1.5.5.7.4.13");
+		public static readonly DerObjectIdentifier it_confirmWaitTime = new DerObjectIdentifier("1.3.6.1.5.5.7.4.14");
+		public static readonly DerObjectIdentifier it_origPKIMessage = new DerObjectIdentifier("1.3.6.1.5.5.7.4.15");
+		public static readonly DerObjectIdentifier it_suppLangTags = new DerObjectIdentifier("1.3.6.1.5.5.7.4.16");
+
+		// RFC 4211
+
+		// id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+		// dod(6) internet(1) security(5) mechanisms(5) pkix(7) }
+		//
+		// arc for Internet X.509 PKI protocols and their components
+		// id-pkip OBJECT IDENTIFIER :: { id-pkix pkip(5) }
+		//
+		// arc for Registration Controls in CRMF
+		// id-regCtrl OBJECT IDENTIFIER ::= { id-pkip regCtrl(1) }
+		//
+		// arc for Registration Info in CRMF
+		// id-regInfo OBJECT IDENTIFIER ::= { id-pkip id-regInfo(2) }
+
+		public static readonly DerObjectIdentifier regCtrl_regToken = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.1");
+		public static readonly DerObjectIdentifier regCtrl_authenticator = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.2");
+		public static readonly DerObjectIdentifier regCtrl_pkiPublicationInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.3");
+		public static readonly DerObjectIdentifier regCtrl_pkiArchiveOptions = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.4");
+		public static readonly DerObjectIdentifier regCtrl_oldCertID = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.5");
+		public static readonly DerObjectIdentifier regCtrl_protocolEncrKey = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.6");
+
+		// From RFC4210:
+		// id-regCtrl-altCertTemplate OBJECT IDENTIFIER ::= {id-regCtrl 7}
+		public static readonly DerObjectIdentifier regCtrl_altCertTemplate = new DerObjectIdentifier("1.3.6.1.5.5.7.5.1.7");
+
+		public static readonly DerObjectIdentifier regInfo_utf8Pairs = new DerObjectIdentifier("1.3.6.1.5.5.7.5.2.1");
+		public static readonly DerObjectIdentifier regInfo_certReq = new DerObjectIdentifier("1.3.6.1.5.5.7.5.2.2");
+
+		// id-smime OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+		// us(840) rsadsi(113549) pkcs(1) pkcs9(9) 16 }
+		//
+		// id-ct OBJECT IDENTIFIER ::= { id-smime 1 } -- content types
+		//
+		// id-ct-encKeyWithID OBJECT IDENTIFIER ::= {id-ct 21}
+		public static readonly DerObjectIdentifier ct_encKeyWithID = new DerObjectIdentifier("1.2.840.113549.1.9.16.1.21");
+	}
+}
diff --git a/crypto/src/asn1/cmp/CrlAnnContent.cs b/crypto/src/asn1/cmp/CrlAnnContent.cs
new file mode 100644
index 000000000..3dc11d32c
--- /dev/null
+++ b/crypto/src/asn1/cmp/CrlAnnContent.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class CrlAnnContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private CrlAnnContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static CrlAnnContent GetInstance(object obj)
+		{
+			if (obj is CrlAnnContent)
+				return (CrlAnnContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlAnnContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual CertificateList[] ToCertificateListArray()
+		{
+			CertificateList[] result = new CertificateList[content.Count];
+			for (int i = 0; i != result.Length; ++ i)
+			{
+				result[i] = CertificateList.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * CrlAnnContent ::= SEQUENCE OF CertificateList
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/ErrorMsgContent.cs b/crypto/src/asn1/cmp/ErrorMsgContent.cs
new file mode 100644
index 000000000..f4dc584ea
--- /dev/null
+++ b/crypto/src/asn1/cmp/ErrorMsgContent.cs
@@ -0,0 +1,94 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class ErrorMsgContent
+		: Asn1Encodable
+	{
+		private readonly PkiStatusInfo pkiStatusInfo;
+		private readonly DerInteger errorCode;
+		private readonly PkiFreeText errorDetails;
+
+		private ErrorMsgContent(Asn1Sequence seq)
+		{
+			pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+
+			for (int pos = 1; pos < seq.Count; ++pos)
+			{
+				Asn1Encodable ae = seq[pos];
+				if (ae is DerInteger)
+				{
+					errorCode = DerInteger.GetInstance(ae);
+				}
+				else
+				{
+					errorDetails = PkiFreeText.GetInstance(ae);
+				}
+			}
+		}
+
+		public static ErrorMsgContent GetInstance(object obj)
+		{
+			if (obj is ErrorMsgContent)
+				return (ErrorMsgContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new ErrorMsgContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public ErrorMsgContent(PkiStatusInfo pkiStatusInfo)
+			: this(pkiStatusInfo, null, null)
+		{
+		}
+
+		public ErrorMsgContent(
+			PkiStatusInfo	pkiStatusInfo,
+			DerInteger		errorCode,
+			PkiFreeText		errorDetails)
+		{
+			if (pkiStatusInfo == null)
+				throw new ArgumentNullException("pkiStatusInfo");
+
+			this.pkiStatusInfo = pkiStatusInfo;
+			this.errorCode = errorCode;
+			this.errorDetails = errorDetails;
+		}
+		
+		public virtual PkiStatusInfo PkiStatusInfo
+		{
+			get { return pkiStatusInfo; }
+		}
+
+		public virtual DerInteger ErrorCode
+		{
+			get { return errorCode; }
+		}
+
+		public virtual PkiFreeText ErrorDetails
+		{
+			get { return errorDetails; }
+		}
+
+		/**
+		 * <pre>
+		 * ErrorMsgContent ::= SEQUENCE {
+		 *                        pKIStatusInfo          PKIStatusInfo,
+		 *                        errorCode              INTEGER           OPTIONAL,
+		 *                        -- implementation-specific error codes
+		 *                        errorDetails           PKIFreeText       OPTIONAL
+		 *                        -- implementation-specific error details
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
+			v.AddOptional(errorCode);
+			v.AddOptional(errorDetails);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/GenMsgContent.cs b/crypto/src/asn1/cmp/GenMsgContent.cs
new file mode 100644
index 000000000..9f042491c
--- /dev/null
+++ b/crypto/src/asn1/cmp/GenMsgContent.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class GenMsgContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private GenMsgContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static GenMsgContent GetInstance(object obj)
+		{
+			if (obj is GenMsgContent)
+				return (GenMsgContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new GenMsgContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public GenMsgContent(params InfoTypeAndValue[] itv)
+		{
+			content = new DerSequence(itv);
+		}
+
+		public virtual InfoTypeAndValue[] ToInfoTypeAndValueArray()
+		{
+			InfoTypeAndValue[] result = new InfoTypeAndValue[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = InfoTypeAndValue.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * GenMsgContent ::= SEQUENCE OF InfoTypeAndValue
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/GenRepContent.cs b/crypto/src/asn1/cmp/GenRepContent.cs
new file mode 100644
index 000000000..5bdc5550a
--- /dev/null
+++ b/crypto/src/asn1/cmp/GenRepContent.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class GenRepContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private GenRepContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static GenRepContent GetInstance(object obj)
+		{
+			if (obj is GenRepContent)
+				return (GenRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new GenRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public GenRepContent(params InfoTypeAndValue[] itv)
+		{
+			content = new DerSequence(itv);
+		}
+
+		public virtual InfoTypeAndValue[] ToInfoTypeAndValueArray()
+		{
+			InfoTypeAndValue[] result = new InfoTypeAndValue[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = InfoTypeAndValue.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * GenRepContent ::= SEQUENCE OF InfoTypeAndValue
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/InfoTypeAndValue.cs b/crypto/src/asn1/cmp/InfoTypeAndValue.cs
new file mode 100644
index 000000000..9b51dba02
--- /dev/null
+++ b/crypto/src/asn1/cmp/InfoTypeAndValue.cs
@@ -0,0 +1,121 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    /**
+     * Example InfoTypeAndValue contents include, but are not limited
+     * to, the following (un-comment in this ASN.1 module and use as
+     * appropriate for a given environment):
+     * <pre>
+     *   id-it-caProtEncCert    OBJECT IDENTIFIER ::= {id-it 1}
+     *      CAProtEncCertValue      ::= CMPCertificate
+     *   id-it-signKeyPairTypes OBJECT IDENTIFIER ::= {id-it 2}
+     *     SignKeyPairTypesValue   ::= SEQUENCE OF AlgorithmIdentifier
+     *   id-it-encKeyPairTypes  OBJECT IDENTIFIER ::= {id-it 3}
+     *     EncKeyPairTypesValue    ::= SEQUENCE OF AlgorithmIdentifier
+     *   id-it-preferredSymmAlg OBJECT IDENTIFIER ::= {id-it 4}
+     *      PreferredSymmAlgValue   ::= AlgorithmIdentifier
+     *   id-it-caKeyUpdateInfo  OBJECT IDENTIFIER ::= {id-it 5}
+     *      CAKeyUpdateInfoValue    ::= CAKeyUpdAnnContent
+     *   id-it-currentCRL       OBJECT IDENTIFIER ::= {id-it 6}
+     *      CurrentCRLValue         ::= CertificateList
+     *   id-it-unsupportedOIDs  OBJECT IDENTIFIER ::= {id-it 7}
+     *      UnsupportedOIDsValue    ::= SEQUENCE OF OBJECT IDENTIFIER
+     *   id-it-keyPairParamReq  OBJECT IDENTIFIER ::= {id-it 10}
+     *      KeyPairParamReqValue    ::= OBJECT IDENTIFIER
+     *   id-it-keyPairParamRep  OBJECT IDENTIFIER ::= {id-it 11}
+     *      KeyPairParamRepValue    ::= AlgorithmIdentifer
+     *   id-it-revPassphrase    OBJECT IDENTIFIER ::= {id-it 12}
+     *      RevPassphraseValue      ::= EncryptedValue
+     *   id-it-implicitConfirm  OBJECT IDENTIFIER ::= {id-it 13}
+     *      ImplicitConfirmValue    ::= NULL
+     *   id-it-confirmWaitTime  OBJECT IDENTIFIER ::= {id-it 14}
+     *      ConfirmWaitTimeValue    ::= GeneralizedTime
+     *   id-it-origPKIMessage   OBJECT IDENTIFIER ::= {id-it 15}
+     *      OrigPKIMessageValue     ::= PKIMessages
+     *   id-it-suppLangTags     OBJECT IDENTIFIER ::= {id-it 16}
+     *      SuppLangTagsValue       ::= SEQUENCE OF UTF8String
+     *
+     * where
+     *
+     *   id-pkix OBJECT IDENTIFIER ::= {
+     *      iso(1) identified-organization(3)
+     *      dod(6) internet(1) security(5) mechanisms(5) pkix(7)}
+     * and
+     *      id-it   OBJECT IDENTIFIER ::= {id-pkix 4}
+     * </pre>
+     */
+    public class InfoTypeAndValue
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier infoType;
+        private readonly Asn1Encodable infoValue;
+
+        private InfoTypeAndValue(Asn1Sequence seq)
+        {
+            infoType = DerObjectIdentifier.GetInstance(seq[0]);
+
+            if (seq.Count > 1)
+            {
+                infoValue = (Asn1Encodable)seq[1];
+            }
+        }
+
+        public static InfoTypeAndValue GetInstance(object obj)
+        {
+            if (obj is InfoTypeAndValue)
+                return (InfoTypeAndValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new InfoTypeAndValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public InfoTypeAndValue(
+            DerObjectIdentifier infoType)
+        {
+            this.infoType = infoType;
+            this.infoValue = null;
+        }
+
+        public InfoTypeAndValue(
+            DerObjectIdentifier infoType,
+            Asn1Encodable       optionalValue)
+        {
+            this.infoType = infoType;
+            this.infoValue = optionalValue;
+        }
+
+        public virtual DerObjectIdentifier InfoType
+        {
+            get { return infoType; }
+        }
+
+        public virtual Asn1Encodable InfoValue
+        {
+            get { return infoValue; }
+        }
+
+        /**
+         * <pre>
+         * InfoTypeAndValue ::= SEQUENCE {
+         *                         infoType               OBJECT IDENTIFIER,
+         *                         infoValue              ANY DEFINED BY infoType  OPTIONAL
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(infoType);
+
+            if (infoValue != null)
+            {
+                v.Add(infoValue);
+            }
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/KeyRecRepContent.cs b/crypto/src/asn1/cmp/KeyRecRepContent.cs
new file mode 100644
index 000000000..b0352f048
--- /dev/null
+++ b/crypto/src/asn1/cmp/KeyRecRepContent.cs
@@ -0,0 +1,115 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class KeyRecRepContent
+		: Asn1Encodable
+	{
+		private readonly PkiStatusInfo status;
+		private readonly CmpCertificate newSigCert;
+		private readonly Asn1Sequence caCerts;
+		private readonly Asn1Sequence keyPairHist;
+
+		private KeyRecRepContent(Asn1Sequence seq)
+		{
+			status = PkiStatusInfo.GetInstance(seq[0]);
+
+			for (int pos = 1; pos < seq.Count; ++pos)
+			{
+				Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[pos]);
+
+				switch (tObj.TagNo)
+				{
+					case 0:
+						newSigCert = CmpCertificate.GetInstance(tObj.GetObject());
+						break;
+					case 1:
+						caCerts = Asn1Sequence.GetInstance(tObj.GetObject());
+						break;
+					case 2:
+						keyPairHist = Asn1Sequence.GetInstance(tObj.GetObject());
+						break;
+					default:
+						throw new ArgumentException("unknown tag number: " + tObj.TagNo, "seq");
+				}
+			}
+		}
+
+		public static KeyRecRepContent GetInstance(object obj)
+		{
+			if (obj is KeyRecRepContent)
+				return (KeyRecRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new KeyRecRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual PkiStatusInfo Status
+		{
+			get { return status; }
+		}
+
+		public virtual CmpCertificate NewSigCert
+		{
+			get { return newSigCert; }
+		}
+
+		public virtual CmpCertificate[] GetCACerts()
+		{
+			if (caCerts == null)
+				return null;
+
+			CmpCertificate[] results = new CmpCertificate[caCerts.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CmpCertificate.GetInstance(caCerts[i]);
+			}
+			return results;
+		}
+
+		public virtual CertifiedKeyPair[] GetKeyPairHist()
+		{
+			if (keyPairHist == null)
+				return null;
+
+			CertifiedKeyPair[] results = new CertifiedKeyPair[keyPairHist.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertifiedKeyPair.GetInstance(keyPairHist[i]);
+			}
+			return results;
+		}
+
+		/**
+		 * <pre>
+		 * KeyRecRepContent ::= SEQUENCE {
+		 *                         status                  PKIStatusInfo,
+		 *                         newSigCert          [0] CMPCertificate OPTIONAL,
+		 *                         caCerts             [1] SEQUENCE SIZE (1..MAX) OF
+		 *                                                           CMPCertificate OPTIONAL,
+		 *                         keyPairHist         [2] SEQUENCE SIZE (1..MAX) OF
+		 *                                                           CertifiedKeyPair OPTIONAL
+		 *              }
+		 * </pre> 
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status);
+			AddOptional(v, 0, newSigCert);
+			AddOptional(v, 1, caCerts);
+			AddOptional(v, 2, keyPairHist);
+			return new DerSequence(v);
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/OobCertHash.cs b/crypto/src/asn1/cmp/OobCertHash.cs
new file mode 100644
index 000000000..63ddff7c4
--- /dev/null
+++ b/crypto/src/asn1/cmp/OobCertHash.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class OobCertHash
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier hashAlg;
+		private readonly CertId certId;
+		private readonly DerBitString  hashVal;
+
+		private OobCertHash(Asn1Sequence seq)
+		{
+			int index = seq.Count - 1;
+
+			hashVal = DerBitString.GetInstance(seq[index--]);
+
+			for (int i = index; i >= 0; i--)
+			{
+				Asn1TaggedObject tObj = (Asn1TaggedObject)seq[i];
+
+				if (tObj.TagNo == 0)
+				{
+					hashAlg = AlgorithmIdentifier.GetInstance(tObj, true);
+				}
+				else
+				{
+					certId = CertId.GetInstance(tObj, true);
+				}
+			}
+		}
+
+		public static OobCertHash GetInstance(object obj)
+		{
+			if (obj is OobCertHash)
+				return (OobCertHash)obj;
+
+			if (obj is Asn1Sequence)
+				return new OobCertHash((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+		
+		public virtual AlgorithmIdentifier HashAlg
+		{
+			get { return hashAlg; }
+		}
+		
+		public virtual CertId CertID
+		{
+			get { return certId; }
+		}
+		
+		/**
+		 * <pre>
+		 * OobCertHash ::= SEQUENCE {
+		 *                      hashAlg     [0] AlgorithmIdentifier     OPTIONAL,
+		 *                      certId      [1] CertId                  OPTIONAL,
+		 *                      hashVal         BIT STRING
+		 *                      -- hashVal is calculated over the Der encoding of the
+		 *                      -- self-signed certificate with the identifier certID.
+		 *       }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+			AddOptional(v, 0, hashAlg);
+			AddOptional(v, 1, certId);
+			v.Add(hashVal);
+			return new DerSequence(v);
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
+
diff --git a/crypto/src/asn1/cmp/PKIBody.cs b/crypto/src/asn1/cmp/PKIBody.cs
new file mode 100644
index 000000000..3205a907e
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIBody.cs
@@ -0,0 +1,186 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiBody
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int TYPE_INIT_REQ = 0;
+        public const int TYPE_INIT_REP = 1;
+        public const int TYPE_CERT_REQ = 2;
+        public const int TYPE_CERT_REP = 3;
+        public const int TYPE_P10_CERT_REQ = 4;
+        public const int TYPE_POPO_CHALL = 5;
+        public const int TYPE_POPO_REP = 6;
+        public const int TYPE_KEY_UPDATE_REQ = 7;
+        public const int TYPE_KEY_UPDATE_REP = 8;
+        public const int TYPE_KEY_RECOVERY_REQ = 9;
+        public const int TYPE_KEY_RECOVERY_REP = 10;
+        public const int TYPE_REVOCATION_REQ = 11;
+        public const int TYPE_REVOCATION_REP = 12;
+        public const int TYPE_CROSS_CERT_REQ = 13;
+        public const int TYPE_CROSS_CERT_REP = 14;
+        public const int TYPE_CA_KEY_UPDATE_ANN = 15;
+        public const int TYPE_CERT_ANN = 16;
+        public const int TYPE_REVOCATION_ANN = 17;
+        public const int TYPE_CRL_ANN = 18;
+        public const int TYPE_CONFIRM = 19;
+        public const int TYPE_NESTED = 20;
+        public const int TYPE_GEN_MSG = 21;
+        public const int TYPE_GEN_REP = 22;
+        public const int TYPE_ERROR = 23;
+        public const int TYPE_CERT_CONFIRM = 24;
+        public const int TYPE_POLL_REQ = 25;
+        public const int TYPE_POLL_REP = 26;
+
+        private int tagNo;
+        private Asn1Encodable body;
+
+        public static PkiBody GetInstance(object obj)
+        {
+            if (obj is PkiBody)
+                return (PkiBody)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new PkiBody((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        private PkiBody(Asn1TaggedObject tagged)
+        {
+            tagNo = tagged.TagNo;
+            body = GetBodyForType(tagNo, tagged.GetObject());
+        }
+
+        /**
+         * Creates a new PkiBody.
+         * @param type one of the TYPE_* constants
+         * @param content message content
+         */
+        public PkiBody(
+            int type,
+            Asn1Encodable content)
+        {
+            tagNo = type;
+            body = GetBodyForType(type, content);
+        }
+
+        private static Asn1Encodable GetBodyForType(
+            int type,
+            Asn1Encodable o)
+        {
+            switch (type)
+            {
+                case TYPE_INIT_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_INIT_REP:
+	                return CertRepMessage.GetInstance(o);
+                case TYPE_CERT_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_CERT_REP:
+	                return CertRepMessage.GetInstance(o);
+	            case TYPE_P10_CERT_REQ:
+	                return CertificationRequest.GetInstance(o);
+	            case TYPE_POPO_CHALL:
+	                return PopoDecKeyChallContent.GetInstance(o);
+	            case TYPE_POPO_REP:
+	                return PopoDecKeyRespContent.GetInstance(o);
+                case TYPE_KEY_UPDATE_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_KEY_UPDATE_REP:
+	                return CertRepMessage.GetInstance(o);
+                case TYPE_KEY_RECOVERY_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_KEY_RECOVERY_REP:
+	                return KeyRecRepContent.GetInstance(o);
+	            case TYPE_REVOCATION_REQ:
+	                return RevReqContent.GetInstance(o);
+	            case TYPE_REVOCATION_REP:
+	                return RevRepContent.GetInstance(o);
+                case TYPE_CROSS_CERT_REQ:
+                    return CertReqMessages.GetInstance(o);
+	            case TYPE_CROSS_CERT_REP:
+	                return CertRepMessage.GetInstance(o);
+	            case TYPE_CA_KEY_UPDATE_ANN:
+	                return CAKeyUpdAnnContent.GetInstance(o);
+	            case TYPE_CERT_ANN:
+	                return CmpCertificate.GetInstance(o);
+	            case TYPE_REVOCATION_ANN:
+	                return RevAnnContent.GetInstance(o);
+	            case TYPE_CRL_ANN:
+	                return CrlAnnContent.GetInstance(o);
+	            case TYPE_CONFIRM:
+	                return PkiConfirmContent.GetInstance(o);
+                case TYPE_NESTED:
+                    return PkiMessages.GetInstance(o);
+	            case TYPE_GEN_MSG:
+	                return GenMsgContent.GetInstance(o);
+	            case TYPE_GEN_REP:
+	                return GenRepContent.GetInstance(o);
+	            case TYPE_ERROR:
+	                return ErrorMsgContent.GetInstance(o);
+	            case TYPE_CERT_CONFIRM:
+	                return CertConfirmContent.GetInstance(o);
+	            case TYPE_POLL_REQ:
+	                return PollReqContent.GetInstance(o);
+	            case TYPE_POLL_REP:
+	                return PollRepContent.GetInstance(o);
+	            default:
+	                throw new ArgumentException("unknown tag number: " + type, "type");
+            }
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Content
+        {
+            get { return body; }
+        }
+
+        /**
+         * <pre>
+         * PkiBody ::= CHOICE {       -- message-specific body elements
+         *        ir       [0]  CertReqMessages,        --Initialization Request
+         *        ip       [1]  CertRepMessage,         --Initialization Response
+         *        cr       [2]  CertReqMessages,        --Certification Request
+         *        cp       [3]  CertRepMessage,         --Certification Response
+         *        p10cr    [4]  CertificationRequest,   --imported from [PKCS10]
+         *        popdecc  [5]  POPODecKeyChallContent, --pop Challenge
+         *        popdecr  [6]  POPODecKeyRespContent,  --pop Response
+         *        kur      [7]  CertReqMessages,        --Key Update Request
+         *        kup      [8]  CertRepMessage,         --Key Update Response
+         *        krr      [9]  CertReqMessages,        --Key Recovery Request
+         *        krp      [10] KeyRecRepContent,       --Key Recovery Response
+         *        rr       [11] RevReqContent,          --Revocation Request
+         *        rp       [12] RevRepContent,          --Revocation Response
+         *        ccr      [13] CertReqMessages,        --Cross-Cert. Request
+         *        ccp      [14] CertRepMessage,         --Cross-Cert. Response
+         *        ckuann   [15] CAKeyUpdAnnContent,     --CA Key Update Ann.
+         *        cann     [16] CertAnnContent,         --Certificate Ann.
+         *        rann     [17] RevAnnContent,          --Revocation Ann.
+         *        crlann   [18] CRLAnnContent,          --CRL Announcement
+         *        pkiconf  [19] PKIConfirmContent,      --Confirmation
+         *        nested   [20] NestedMessageContent,   --Nested Message
+         *        genm     [21] GenMsgContent,          --General Message
+         *        genp     [22] GenRepContent,          --General Response
+         *        error    [23] ErrorMsgContent,        --Error Message
+         *        certConf [24] CertConfirmContent,     --Certificate confirm
+         *        pollReq  [25] PollReqContent,         --Polling request
+         *        pollRep  [26] PollRepContent          --Polling response
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(true, tagNo, body);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/PKIConfirmContent.cs b/crypto/src/asn1/cmp/PKIConfirmContent.cs
new file mode 100644
index 000000000..98645766a
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIConfirmContent.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiConfirmContent
+		: Asn1Encodable
+	{
+		public static PkiConfirmContent GetInstance(object obj)
+		{
+			if (obj is PkiConfirmContent)
+				return (PkiConfirmContent)obj;
+
+			if (obj is Asn1Null)
+				return new PkiConfirmContent();
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public PkiConfirmContent()
+		{
+		}
+
+		/**
+		 * <pre>
+		 * PkiConfirmContent ::= NULL
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return DerNull.Instance;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PKIFailureInfo.cs b/crypto/src/asn1/cmp/PKIFailureInfo.cs
new file mode 100644
index 000000000..1df0e0693
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIFailureInfo.cs
@@ -0,0 +1,73 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	/**
+	 * <pre>
+	 * PKIFailureInfo ::= BIT STRING {
+	 * badAlg               (0),
+	 *   -- unrecognized or unsupported Algorithm Identifier
+	 * badMessageCheck      (1), -- integrity check failed (e.g., signature did not verify)
+	 * badRequest           (2),
+	 *   -- transaction not permitted or supported
+	 * badTime              (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+	 * badCertId            (4), -- no certificate could be found matching the provided criteria
+	 * badDataFormat        (5),
+	 *   -- the data submitted has the wrong format
+	 * wrongAuthority       (6), -- the authority indicated in the request is different from the one creating the response token
+	 * incorrectData        (7), -- the requester's data is incorrect (for notary services)
+	 * missingTimeStamp     (8), -- when the timestamp is missing but should be there (by policy)
+	 * badPOP               (9)  -- the proof-of-possession failed
+	 * timeNotAvailable    (14),
+	 *   -- the TSA's time source is not available
+	 * unacceptedPolicy    (15),
+	 *   -- the requested TSA policy is not supported by the TSA
+	 * unacceptedExtension (16),
+	 *   -- the requested extension is not supported by the TSA
+	 *  addInfoNotAvailable (17)
+	 *    -- the additional information requested could not be understood
+	 *    -- or is not available
+	 *  systemFailure       (25)
+	 *    -- the request cannot be handled due to system failure
+	 * </pre>
+	 */
+	public class PkiFailureInfo
+		: DerBitString
+	{
+		public const int BadAlg               = (1 << 7); // unrecognized or unsupported Algorithm Identifier
+		public const int BadMessageCheck      = (1 << 6); // integrity check failed (e.g., signature did not verify)
+		public const int BadRequest           = (1 << 5);
+		public const int BadTime              = (1 << 4); // -- messageTime was not sufficiently close to the system time, as defined by local policy
+		public const int BadCertId            = (1 << 3); // no certificate could be found matching the provided criteria
+		public const int BadDataFormat        = (1 << 2);
+		public const int WrongAuthority       = (1 << 1); // the authority indicated in the request is different from the one creating the response token
+		public const int IncorrectData        = 1;        // the requester's data is incorrect (for notary services)
+		public const int MissingTimeStamp     = (1 << 15); // when the timestamp is missing but should be there (by policy)
+		public const int BadPop               = (1 << 14); // the proof-of-possession failed
+		public const int TimeNotAvailable     = (1 << 9); // the TSA's time source is not available
+		public const int UnacceptedPolicy     = (1 << 8); // the requested TSA policy is not supported by the TSA
+		public const int UnacceptedExtension  = (1 << 23); //the requested extension is not supported by the TSA
+		public const int AddInfoNotAvailable  = (1 << 22); //the additional information requested could not be understood or is not available
+		public const int SystemFailure        = (1 << 30); //the request cannot be handled due to system failure
+
+		/**
+		 * Basic constructor.
+		 */
+		public PkiFailureInfo(
+			int info)
+			:	base(GetBytes(info), GetPadBits(info))
+		{
+		}
+
+		public PkiFailureInfo(
+			DerBitString info)
+			:	base(info.GetBytes(), info.PadBits)
+		{
+		}
+
+		public override string ToString()
+		{
+			return "PkiFailureInfo: 0x" + this.IntValue.ToString("X");
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PKIFreeText.cs b/crypto/src/asn1/cmp/PKIFreeText.cs
new file mode 100644
index 000000000..571c8d93a
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIFreeText.cs
@@ -0,0 +1,97 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiFreeText
+		: Asn1Encodable
+	{
+		internal Asn1Sequence strings;
+
+		public static PkiFreeText GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static PkiFreeText GetInstance(
+			object obj)
+		{
+			if (obj is PkiFreeText)
+			{
+				return (PkiFreeText)obj;
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new PkiFreeText((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public PkiFreeText(
+			Asn1Sequence seq)
+		{
+			foreach (object o in seq)
+			{
+				if (!(o is DerUtf8String))
+				{
+					throw new ArgumentException("attempt to insert non UTF8 STRING into PkiFreeText");
+				}
+			}
+
+			this.strings = seq;
+		}
+
+		public PkiFreeText(
+			DerUtf8String p)
+		{
+			strings = new DerSequence(p);
+		}
+
+		/**
+		 * Return the number of string elements present.
+		 *
+		 * @return number of elements present.
+		 */
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return strings.Count; }
+		}
+
+		public int Count
+		{
+			get { return strings.Count; }
+		}
+
+		/**
+		 * Return the UTF8STRING at index.
+		 *
+		 * @param index index of the string of interest
+		 * @return the string at index.
+		 */
+		public DerUtf8String this[int index]
+		{
+			get { return (DerUtf8String) strings[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public DerUtf8String GetStringAt(
+			int index)
+		{
+			return this[index];
+		}
+
+		/**
+		 * <pre>
+		 * PkiFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return strings;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PKIHeader.cs b/crypto/src/asn1/cmp/PKIHeader.cs
new file mode 100644
index 000000000..e758e9f16
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIHeader.cs
@@ -0,0 +1,237 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiHeader
+        : Asn1Encodable
+    {
+        /**
+         * Value for a "null" recipient or sender.
+         */
+        public static readonly GeneralName NULL_NAME = new GeneralName(X509Name.GetInstance(new DerSequence()));
+
+        public static readonly int CMP_1999 = 1;
+        public static readonly int CMP_2000 = 2;
+
+        private readonly DerInteger pvno;
+        private readonly GeneralName sender;
+        private readonly GeneralName recipient;
+        private readonly DerGeneralizedTime messageTime;
+        private readonly AlgorithmIdentifier protectionAlg;
+        private readonly Asn1OctetString senderKID;       // KeyIdentifier
+        private readonly Asn1OctetString recipKID;        // KeyIdentifier
+        private readonly Asn1OctetString transactionID;
+        private readonly Asn1OctetString senderNonce;
+        private readonly Asn1OctetString recipNonce;
+        private readonly PkiFreeText freeText;
+        private readonly Asn1Sequence generalInfo;
+
+        private PkiHeader(Asn1Sequence seq)
+        {
+            pvno = DerInteger.GetInstance(seq[0]);
+            sender = GeneralName.GetInstance(seq[1]);
+            recipient = GeneralName.GetInstance(seq[2]);
+
+            for (int pos = 3; pos < seq.Count; ++pos)
+            {
+                Asn1TaggedObject tObj = (Asn1TaggedObject)seq[pos];
+
+                switch (tObj.TagNo)
+                {
+                    case 0:
+                        messageTime = DerGeneralizedTime.GetInstance(tObj, true);
+                        break;
+                    case 1:
+                        protectionAlg = AlgorithmIdentifier.GetInstance(tObj, true);
+                        break;
+                    case 2:
+                        senderKID = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 3:
+                        recipKID = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 4:
+                        transactionID = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 5:
+                        senderNonce = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 6:
+                        recipNonce = Asn1OctetString.GetInstance(tObj, true);
+                        break;
+                    case 7:
+                        freeText = PkiFreeText.GetInstance(tObj, true);
+                        break;
+                    case 8:
+                        generalInfo = Asn1Sequence.GetInstance(tObj, true);
+                        break;
+                    default:
+                        throw new ArgumentException("unknown tag number: " + tObj.TagNo, "seq");
+                }
+            }
+        }
+
+        public static PkiHeader GetInstance(object obj)
+        {
+            if (obj is PkiHeader)
+                return (PkiHeader)obj;
+
+            if (obj is Asn1Sequence)
+                return new PkiHeader((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public PkiHeader(
+            int pvno,
+            GeneralName sender,
+            GeneralName recipient)
+            : this(new DerInteger(pvno), sender, recipient)
+        {
+        }
+
+        private PkiHeader(
+            DerInteger pvno,
+            GeneralName sender,
+            GeneralName recipient)
+        {
+            this.pvno = pvno;
+            this.sender = sender;
+            this.recipient = recipient;
+        }
+
+        public virtual DerInteger Pvno
+        {
+            get { return pvno; }
+        }
+
+        public virtual GeneralName Sender
+        {
+            get { return sender; }
+        }
+
+        public virtual GeneralName Recipient
+        {
+            get { return recipient; }
+        }
+
+        public virtual DerGeneralizedTime MessageTime
+        {
+            get { return messageTime; }
+        }
+
+        public virtual AlgorithmIdentifier ProtectionAlg
+        {
+            get { return protectionAlg; }
+        }
+
+        public virtual Asn1OctetString SenderKID
+        {   
+            get { return senderKID; }
+        }
+
+        public virtual Asn1OctetString RecipKID
+        {   
+            get { return recipKID; }
+        }
+
+        public virtual Asn1OctetString TransactionID
+        {   
+            get { return transactionID; }
+        }
+
+        public virtual Asn1OctetString SenderNonce
+        {   
+            get { return senderNonce; }
+        }
+
+        public virtual Asn1OctetString RecipNonce
+        {   
+            get { return recipNonce; }
+        }
+
+        public virtual PkiFreeText FreeText
+        {
+            get { return freeText; }
+        }
+
+        public virtual InfoTypeAndValue[] GetGeneralInfo()
+        {
+            if (generalInfo == null)
+            {
+                return null;
+            }
+            InfoTypeAndValue[] results = new InfoTypeAndValue[generalInfo.Count];
+            for (int i = 0; i < results.Length; i++)
+            {
+                results[i] = InfoTypeAndValue.GetInstance(generalInfo[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         *  PkiHeader ::= SEQUENCE {
+         *            pvno                INTEGER     { cmp1999(1), cmp2000(2) },
+         *            sender              GeneralName,
+         *            -- identifies the sender
+         *            recipient           GeneralName,
+         *            -- identifies the intended recipient
+         *            messageTime     [0] GeneralizedTime         OPTIONAL,
+         *            -- time of production of this message (used when sender
+         *            -- believes that the transport will be "suitable"; i.e.,
+         *            -- that the time will still be meaningful upon receipt)
+         *            protectionAlg   [1] AlgorithmIdentifier     OPTIONAL,
+         *            -- algorithm used for calculation of protection bits
+         *            senderKID       [2] KeyIdentifier           OPTIONAL,
+         *            recipKID        [3] KeyIdentifier           OPTIONAL,
+         *            -- to identify specific keys used for protection
+         *            transactionID   [4] OCTET STRING            OPTIONAL,
+         *            -- identifies the transaction; i.e., this will be the same in
+         *            -- corresponding request, response, certConf, and PKIConf
+         *            -- messages
+         *            senderNonce     [5] OCTET STRING            OPTIONAL,
+         *            recipNonce      [6] OCTET STRING            OPTIONAL,
+         *            -- nonces used to provide replay protection, senderNonce
+         *            -- is inserted by the creator of this message; recipNonce
+         *            -- is a nonce previously inserted in a related message by
+         *            -- the intended recipient of this message
+         *            freeText        [7] PKIFreeText             OPTIONAL,
+         *            -- this may be used to indicate context-specific instructions
+         *            -- (this field is intended for human consumption)
+         *            generalInfo     [8] SEQUENCE SIZE (1..MAX) OF
+         *                                 InfoTypeAndValue     OPTIONAL
+         *            -- this may be used to convey context-specific information
+         *            -- (this field not primarily intended for human consumption)
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(pvno, sender, recipient);
+
+            AddOptional(v, 0, messageTime);
+            AddOptional(v, 1, protectionAlg);
+            AddOptional(v, 2, senderKID);
+            AddOptional(v, 3, recipKID);
+            AddOptional(v, 4, transactionID);
+            AddOptional(v, 5, senderNonce);
+            AddOptional(v, 6, recipNonce);
+            AddOptional(v, 7, freeText);
+            AddOptional(v, 8, generalInfo);
+
+            return new DerSequence(v);
+        }
+
+        private static void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(true, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/PKIHeaderBuilder.cs b/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
new file mode 100644
index 000000000..00073c062
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
@@ -0,0 +1,223 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiHeaderBuilder
+	{
+		private DerInteger pvno;
+		private GeneralName sender;
+		private GeneralName recipient;
+		private DerGeneralizedTime messageTime;
+		private AlgorithmIdentifier protectionAlg;
+		private Asn1OctetString senderKID;       // KeyIdentifier
+		private Asn1OctetString recipKID;        // KeyIdentifier
+		private Asn1OctetString transactionID;
+		private Asn1OctetString senderNonce;
+		private Asn1OctetString recipNonce;
+		private PkiFreeText     freeText;
+		private Asn1Sequence    generalInfo;
+
+		public PkiHeaderBuilder(
+			int			pvno,
+			GeneralName	sender,
+			GeneralName	recipient)
+			: this(new DerInteger(pvno), sender, recipient)
+		{
+		}
+
+		private PkiHeaderBuilder(
+			DerInteger	pvno,
+			GeneralName	sender,
+			GeneralName	recipient)
+		{
+			this.pvno = pvno;
+			this.sender = sender;
+			this.recipient = recipient;
+		}
+
+		public virtual PkiHeaderBuilder SetMessageTime(DerGeneralizedTime time)
+		{
+			messageTime = time;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetProtectionAlg(AlgorithmIdentifier aid)
+		{
+			protectionAlg = aid;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetSenderKID(byte[] kid)
+		{
+            return SetSenderKID(kid == null ? null : new DerOctetString(kid));
+		}
+
+		public virtual PkiHeaderBuilder SetSenderKID(Asn1OctetString kid)
+		{
+			senderKID = kid;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetRecipKID(byte[] kid)
+		{
+            return SetRecipKID(kid == null ? null : new DerOctetString(kid));
+		}
+		
+		public virtual PkiHeaderBuilder SetRecipKID(DerOctetString kid)
+		{
+			recipKID = kid;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetTransactionID(byte[] tid)
+		{
+			return SetTransactionID(tid == null ? null : new DerOctetString(tid));
+		}
+
+		public virtual PkiHeaderBuilder SetTransactionID(Asn1OctetString tid)
+		{
+			transactionID = tid;
+			return this;
+		}
+		
+		public virtual PkiHeaderBuilder SetSenderNonce(byte[] nonce)
+		{
+            return SetSenderNonce(nonce == null ? null : new DerOctetString(nonce));
+		}
+
+		public virtual PkiHeaderBuilder SetSenderNonce(Asn1OctetString nonce)
+		{
+			senderNonce = nonce;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetRecipNonce(byte[] nonce)
+		{
+            return SetRecipNonce(nonce == null ? null : new DerOctetString(nonce));
+		}
+
+		public virtual PkiHeaderBuilder SetRecipNonce(Asn1OctetString nonce)
+		{
+			recipNonce = nonce;
+			return this;
+		}
+
+		public virtual PkiHeaderBuilder SetFreeText(PkiFreeText text)
+		{
+			freeText = text;
+			return this;
+		}
+		
+		public virtual PkiHeaderBuilder SetGeneralInfo(InfoTypeAndValue genInfo)
+		{
+			return SetGeneralInfo(MakeGeneralInfoSeq(genInfo));
+		}
+		
+		public virtual PkiHeaderBuilder SetGeneralInfo(InfoTypeAndValue[] genInfos)
+		{
+			return SetGeneralInfo(MakeGeneralInfoSeq(genInfos));
+		}
+		
+		public virtual PkiHeaderBuilder SetGeneralInfo(Asn1Sequence seqOfInfoTypeAndValue)
+		{
+			generalInfo = seqOfInfoTypeAndValue;
+			return this;
+		}
+
+		private static Asn1Sequence MakeGeneralInfoSeq(
+			InfoTypeAndValue generalInfo)
+		{
+			return new DerSequence(generalInfo);
+		}
+		
+		private static Asn1Sequence MakeGeneralInfoSeq(
+			InfoTypeAndValue[] generalInfos)
+		{
+			Asn1Sequence genInfoSeq = null;
+			if (generalInfos != null)
+			{
+				Asn1EncodableVector v = new Asn1EncodableVector();
+				for (int i = 0; i < generalInfos.Length; ++i)
+				{
+					v.Add(generalInfos[i]);
+				}
+				genInfoSeq = new DerSequence(v);
+			}
+			return genInfoSeq;
+		}
+
+		/**
+		 * <pre>
+		 *  PKIHeader ::= SEQUENCE {
+		 *            pvno                INTEGER     { cmp1999(1), cmp2000(2) },
+		 *            sender              GeneralName,
+		 *            -- identifies the sender
+		 *            recipient           GeneralName,
+		 *            -- identifies the intended recipient
+		 *            messageTime     [0] GeneralizedTime         OPTIONAL,
+		 *            -- time of production of this message (used when sender
+		 *            -- believes that the transport will be "suitable"; i.e.,
+		 *            -- that the time will still be meaningful upon receipt)
+		 *            protectionAlg   [1] AlgorithmIdentifier     OPTIONAL,
+		 *            -- algorithm used for calculation of protection bits
+		 *            senderKID       [2] KeyIdentifier           OPTIONAL,
+		 *            recipKID        [3] KeyIdentifier           OPTIONAL,
+		 *            -- to identify specific keys used for protection
+		 *            transactionID   [4] OCTET STRING            OPTIONAL,
+		 *            -- identifies the transaction; i.e., this will be the same in
+		 *            -- corresponding request, response, certConf, and PKIConf
+		 *            -- messages
+		 *            senderNonce     [5] OCTET STRING            OPTIONAL,
+		 *            recipNonce      [6] OCTET STRING            OPTIONAL,
+		 *            -- nonces used to provide replay protection, senderNonce
+		 *            -- is inserted by the creator of this message; recipNonce
+		 *            -- is a nonce previously inserted in a related message by
+		 *            -- the intended recipient of this message
+		 *            freeText        [7] PKIFreeText             OPTIONAL,
+		 *            -- this may be used to indicate context-specific instructions
+		 *            -- (this field is intended for human consumption)
+		 *            generalInfo     [8] SEQUENCE SIZE (1..MAX) OF
+		 *                                 InfoTypeAndValue     OPTIONAL
+		 *            -- this may be used to convey context-specific information
+		 *            -- (this field not primarily intended for human consumption)
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public virtual PkiHeader Build()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(pvno, sender, recipient);
+			AddOptional(v, 0, messageTime);
+			AddOptional(v, 1, protectionAlg);
+			AddOptional(v, 2, senderKID);
+			AddOptional(v, 3, recipKID);
+			AddOptional(v, 4, transactionID);
+			AddOptional(v, 5, senderNonce);
+			AddOptional(v, 6, recipNonce);
+			AddOptional(v, 7, freeText);
+			AddOptional(v, 8, generalInfo);
+
+			messageTime = null;
+			protectionAlg = null;
+			senderKID = null;
+			recipKID = null;
+			transactionID = null;
+			senderNonce = null;
+			recipNonce = null;
+			freeText = null;
+			generalInfo = null;
+
+			return PkiHeader.GetInstance(new DerSequence(v));
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PKIMessage.cs b/crypto/src/asn1/cmp/PKIMessage.cs
new file mode 100644
index 000000000..086a2d938
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIMessage.cs
@@ -0,0 +1,140 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiMessage
+        : Asn1Encodable
+    {
+        private readonly PkiHeader header;
+        private readonly PkiBody body;
+        private readonly DerBitString protection;
+        private readonly Asn1Sequence extraCerts;
+
+        private PkiMessage(Asn1Sequence seq)
+        {
+            header = PkiHeader.GetInstance(seq[0]);
+            body = PkiBody.GetInstance(seq[1]);
+
+            for (int pos = 2; pos < seq.Count; ++pos)
+            {
+                Asn1TaggedObject tObj = (Asn1TaggedObject)seq[pos].ToAsn1Object();
+
+                if (tObj.TagNo == 0)
+                {
+                    protection = DerBitString.GetInstance(tObj, true);
+                }
+                else
+                {
+                    extraCerts = Asn1Sequence.GetInstance(tObj, true);
+                }
+            }
+        }
+
+        public static PkiMessage GetInstance(object obj)
+        {
+            if (obj is PkiMessage)
+                return (PkiMessage)obj;
+
+            if (obj != null)
+                return new PkiMessage(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        /**
+         * Creates a new PkiMessage.
+         *
+         * @param header message header
+         * @param body message body
+         * @param protection message protection (may be null)
+         * @param extraCerts extra certificates (may be null)
+         */
+        public PkiMessage(
+            PkiHeader header,
+            PkiBody body,
+            DerBitString protection,
+            CmpCertificate[] extraCerts)
+        {
+            this.header = header;
+            this.body = body;
+            this.protection = protection;
+            if (extraCerts != null)
+            {
+                this.extraCerts = new DerSequence(extraCerts);
+            }
+        }
+
+        public PkiMessage(
+            PkiHeader header,
+            PkiBody body,
+            DerBitString protection)
+            : this(header, body, protection, null)
+        {
+        }
+
+        public PkiMessage(
+            PkiHeader header,
+            PkiBody body)
+            : this(header, body, null, null)
+        {
+        }
+
+        public virtual PkiHeader Header
+        {
+            get { return header; }
+        }
+
+        public virtual PkiBody Body
+        {
+            get { return body; }
+        }
+
+        public virtual DerBitString Protection
+        {
+            get { return protection; }
+        }
+
+        public virtual CmpCertificate[] GetExtraCerts()
+        {
+            if (extraCerts == null)
+                return null;
+
+            CmpCertificate[] results = new CmpCertificate[extraCerts.Count];
+            for (int i = 0; i < results.Length; ++i)
+            {
+                results[i] = CmpCertificate.GetInstance(extraCerts[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * PkiMessage ::= SEQUENCE {
+         *                  header           PKIHeader,
+         *                  body             PKIBody,
+         *                  protection   [0] PKIProtection OPTIONAL,
+         *                  extraCerts   [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+         *                                                                     OPTIONAL
+         * }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(header, body);
+
+            AddOptional(v, 0, protection);
+            AddOptional(v, 1, extraCerts);
+
+            return new DerSequence(v);
+        }
+
+        private static void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(true, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/PKIMessages.cs b/crypto/src/asn1/cmp/PKIMessages.cs
new file mode 100644
index 000000000..ddabdf4ae
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIMessages.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PkiMessages
+        : Asn1Encodable
+    {
+        private Asn1Sequence content;
+
+        private PkiMessages(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static PkiMessages GetInstance(object obj)
+        {
+            if (obj is PkiMessages)
+                return (PkiMessages)obj;
+
+            if (obj is Asn1Sequence)
+                return new PkiMessages((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public PkiMessages(params PkiMessage[] msgs)
+        {
+            content = new DerSequence(msgs);
+        }
+
+        public virtual PkiMessage[] ToPkiMessageArray()
+        {
+            PkiMessage[] result = new PkiMessage[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = PkiMessage.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * PkiMessages ::= SEQUENCE SIZE (1..MAX) OF PkiMessage
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/PKIStatus.cs b/crypto/src/asn1/cmp/PKIStatus.cs
new file mode 100644
index 000000000..b03dd3d62
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIStatus.cs
@@ -0,0 +1,62 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public enum PkiStatus
+	{
+		Granted					= 0,
+		GrantedWithMods			= 1,
+		Rejection				= 2,
+		Waiting					= 3,
+		RevocationWarning		= 4,
+		RevocationNotification	= 5,
+    	KeyUpdateWarning		= 6,
+	}
+
+	public class PkiStatusEncodable
+		: Asn1Encodable
+	{
+		public static readonly PkiStatusEncodable granted = new PkiStatusEncodable(PkiStatus.Granted);
+		public static readonly PkiStatusEncodable grantedWithMods = new PkiStatusEncodable(PkiStatus.GrantedWithMods);
+		public static readonly PkiStatusEncodable rejection = new PkiStatusEncodable(PkiStatus.Rejection);
+		public static readonly PkiStatusEncodable waiting = new PkiStatusEncodable(PkiStatus.Waiting);
+		public static readonly PkiStatusEncodable revocationWarning = new PkiStatusEncodable(PkiStatus.RevocationWarning);
+		public static readonly PkiStatusEncodable revocationNotification = new PkiStatusEncodable(PkiStatus.RevocationNotification);
+		public static readonly PkiStatusEncodable keyUpdateWaiting = new PkiStatusEncodable(PkiStatus.KeyUpdateWarning);
+
+		private readonly DerInteger status;
+
+		private PkiStatusEncodable(PkiStatus status)
+			: this(new DerInteger((int)status))
+		{
+		}
+
+		private PkiStatusEncodable(DerInteger status)
+		{
+			this.status = status;
+		}
+
+		public static PkiStatusEncodable GetInstance(object obj)
+		{
+			if (obj is PkiStatusEncodable)
+				return (PkiStatusEncodable)obj;
+
+			if (obj is DerInteger)
+				return new PkiStatusEncodable((DerInteger)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual BigInteger Value
+		{
+			get { return status.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return status;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PKIStatusInfo.cs b/crypto/src/asn1/cmp/PKIStatusInfo.cs
new file mode 100644
index 000000000..2463e0081
--- /dev/null
+++ b/crypto/src/asn1/cmp/PKIStatusInfo.cs
@@ -0,0 +1,165 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PkiStatusInfo
+		: Asn1Encodable
+	{
+		DerInteger      status;
+		PkiFreeText     statusString;
+		DerBitString    failInfo;
+
+		public static PkiStatusInfo GetInstance(
+			Asn1TaggedObject obj,
+			bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static PkiStatusInfo GetInstance(
+			object obj)
+		{
+			if (obj is PkiStatusInfo)
+			{
+				return (PkiStatusInfo)obj;
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new PkiStatusInfo((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public PkiStatusInfo(
+			Asn1Sequence seq)
+		{
+			this.status = DerInteger.GetInstance(seq[0]);
+
+			this.statusString = null;
+			this.failInfo = null;
+
+			if (seq.Count > 2)
+			{
+				this.statusString = PkiFreeText.GetInstance(seq[1]);
+				this.failInfo = DerBitString.GetInstance(seq[2]);
+			}
+			else if (seq.Count > 1)
+			{
+				object obj = seq[1];
+				if (obj is DerBitString)
+				{
+					this.failInfo = DerBitString.GetInstance(obj);
+				}
+				else
+				{
+					this.statusString = PkiFreeText.GetInstance(obj);
+				}
+			}
+		}
+
+		/**
+		 * @param status
+		 */
+		public PkiStatusInfo(int status)
+		{
+			this.status = new DerInteger(status);
+		}
+
+		/**
+		 * @param status
+		 * @param statusString
+		 */
+		public PkiStatusInfo(
+			int			status,
+			PkiFreeText	statusString)
+		{
+			this.status = new DerInteger(status);
+			this.statusString = statusString;
+		}
+
+		public PkiStatusInfo(
+			int				status,
+			PkiFreeText		statusString,
+			PkiFailureInfo	failInfo)
+		{
+			this.status = new DerInteger(status);
+			this.statusString = statusString;
+			this.failInfo = failInfo;
+		}
+
+		public BigInteger Status
+		{
+			get
+			{
+				return status.Value;
+			}
+		}
+
+		public PkiFreeText StatusString
+		{
+			get
+			{
+				return statusString;
+			}
+		}
+
+		public DerBitString FailInfo
+		{
+			get
+			{
+				return failInfo;
+			}
+		}
+
+		/**
+		 * <pre>
+		 * PkiStatusInfo ::= SEQUENCE {
+		 *     status        PKIStatus,                (INTEGER)
+		 *     statusString  PkiFreeText     OPTIONAL,
+		 *     failInfo      PkiFailureInfo  OPTIONAL  (BIT STRING)
+		 * }
+		 *
+		 * PKIStatus:
+		 *   granted                (0), -- you got exactly what you asked for
+		 *   grantedWithMods        (1), -- you got something like what you asked for
+		 *   rejection              (2), -- you don't get it, more information elsewhere in the message
+		 *   waiting                (3), -- the request body part has not yet been processed, expect to hear more later
+		 *   revocationWarning      (4), -- this message contains a warning that a revocation is imminent
+		 *   revocationNotification (5), -- notification that a revocation has occurred
+		 *   keyUpdateWarning       (6)  -- update already done for the oldCertId specified in CertReqMsg
+		 *
+		 * PkiFailureInfo:
+		 *   badAlg           (0), -- unrecognized or unsupported Algorithm Identifier
+		 *   badMessageCheck  (1), -- integrity check failed (e.g., signature did not verify)
+		 *   badRequest       (2), -- transaction not permitted or supported
+		 *   badTime          (3), -- messageTime was not sufficiently close to the system time, as defined by local policy
+		 *   badCertId        (4), -- no certificate could be found matching the provided criteria
+		 *   badDataFormat    (5), -- the data submitted has the wrong format
+		 *   wrongAuthority   (6), -- the authority indicated in the request is different from the one creating the response token
+		 *   incorrectData    (7), -- the requester's data is incorrect (for notary services)
+		 *   missingTimeStamp (8), -- when the timestamp is missing but should be there (by policy)
+		 *   badPOP           (9)  -- the proof-of-possession failed
+		 *
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status);
+
+			if (statusString != null)
+			{
+				v.Add(statusString);
+			}
+
+			if (failInfo!= null)
+			{
+				v.Add(failInfo);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PbmParameter.cs b/crypto/src/asn1/cmp/PbmParameter.cs
new file mode 100644
index 000000000..59b1bd7bb
--- /dev/null
+++ b/crypto/src/asn1/cmp/PbmParameter.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+    public class PbmParameter
+        : Asn1Encodable
+    {
+        private Asn1OctetString salt;
+        private AlgorithmIdentifier owf;
+        private DerInteger iterationCount;
+        private AlgorithmIdentifier mac;
+
+        private PbmParameter(Asn1Sequence seq)
+        {
+            salt = Asn1OctetString.GetInstance(seq[0]);
+            owf = AlgorithmIdentifier.GetInstance(seq[1]);
+            iterationCount = DerInteger.GetInstance(seq[2]);
+            mac = AlgorithmIdentifier.GetInstance(seq[3]);
+        }
+
+        public static PbmParameter GetInstance(object obj)
+        {
+            if (obj is PbmParameter)
+                return (PbmParameter)obj;
+
+            if (obj is Asn1Sequence)
+                return new PbmParameter((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public PbmParameter(
+            byte[] salt,
+            AlgorithmIdentifier owf,
+            int iterationCount,
+            AlgorithmIdentifier mac)
+            : this(new DerOctetString(salt), owf, new DerInteger(iterationCount), mac)
+        {
+        }
+
+        public PbmParameter(
+            Asn1OctetString salt,
+            AlgorithmIdentifier owf,
+            DerInteger iterationCount,
+            AlgorithmIdentifier mac)
+        {
+            this.salt = salt;
+            this.owf = owf;
+            this.iterationCount = iterationCount;
+            this.mac = mac;
+        }
+
+        public virtual Asn1OctetString Salt
+        {
+            get { return salt; }
+        }
+
+        public virtual AlgorithmIdentifier Owf
+        {
+            get { return owf; }
+        }
+
+        public virtual DerInteger IterationCount
+        {
+            get { return iterationCount; }
+        }
+
+        public virtual AlgorithmIdentifier Mac
+        {
+            get { return mac; }
+        }
+
+        /**
+         * <pre>
+         *  PbmParameter ::= SEQUENCE {
+         *                        salt                OCTET STRING,
+         *                        -- note:  implementations MAY wish to limit acceptable sizes
+         *                        -- of this string to values appropriate for their environment
+         *                        -- in order to reduce the risk of denial-of-service attacks
+         *                        owf                 AlgorithmIdentifier,
+         *                        -- AlgId for a One-Way Function (SHA-1 recommended)
+         *                        iterationCount      INTEGER,
+         *                        -- number of times the OWF is applied
+         *                        -- note:  implementations MAY wish to limit acceptable sizes
+         *                        -- of this integer to values appropriate for their environment
+         *                        -- in order to reduce the risk of denial-of-service attacks
+         *                        mac                 AlgorithmIdentifier
+         *                        -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11],
+         *    }   -- or HMAC [RFC2104, RFC2202])
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(salt, owf, iterationCount, mac);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cmp/PollRepContent.cs b/crypto/src/asn1/cmp/PollRepContent.cs
new file mode 100644
index 000000000..4045ac7ed
--- /dev/null
+++ b/crypto/src/asn1/cmp/PollRepContent.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PollRepContent
+		: Asn1Encodable
+	{
+		private readonly DerInteger certReqId;
+		private readonly DerInteger checkAfter;
+		private readonly PkiFreeText reason;
+
+		private PollRepContent(Asn1Sequence seq)
+		{
+			certReqId = DerInteger.GetInstance(seq[0]);
+			checkAfter = DerInteger.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				reason = PkiFreeText.GetInstance(seq[2]);
+			}
+		}
+
+		public static PollRepContent GetInstance(object obj)
+		{
+			if (obj is PollRepContent)
+				return (PollRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new PollRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual DerInteger CertReqID
+		{
+			get { return certReqId; }
+		}
+
+		public virtual DerInteger CheckAfter
+		{
+			get { return checkAfter; }
+		}
+
+		public virtual PkiFreeText Reason
+		{
+			get { return reason; }
+		}
+
+		/**
+		 * <pre>
+		 * PollRepContent ::= SEQUENCE OF SEQUENCE {
+		 *         certReqId              INTEGER,
+		 *         checkAfter             INTEGER,  -- time in seconds
+		 *         reason                 PKIFreeText OPTIONAL
+		 *     }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certReqId, checkAfter);
+			v.AddOptional(reason);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PollReqContent.cs b/crypto/src/asn1/cmp/PollReqContent.cs
new file mode 100644
index 000000000..ca2164151
--- /dev/null
+++ b/crypto/src/asn1/cmp/PollReqContent.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PollReqContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private PollReqContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static PollReqContent GetInstance(object obj)
+		{
+			if (obj is PollReqContent)
+				return (PollReqContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new PollReqContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual DerInteger[][] GetCertReqIDs()
+		{
+			DerInteger[][] result = new DerInteger[content.Count][];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = SequenceToDerIntegerArray((Asn1Sequence)content[i]);
+			}
+			return result;
+		}
+
+		private static DerInteger[] SequenceToDerIntegerArray(Asn1Sequence seq)
+		{
+			DerInteger[] result = new DerInteger[seq.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = DerInteger.GetInstance(seq[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * PollReqContent ::= SEQUENCE OF SEQUENCE {
+		 *                        certReqId              INTEGER
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/PopoDecKeyChallContent.cs b/crypto/src/asn1/cmp/PopoDecKeyChallContent.cs
new file mode 100644
index 000000000..20b173b85
--- /dev/null
+++ b/crypto/src/asn1/cmp/PopoDecKeyChallContent.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PopoDecKeyChallContent
+	    : Asn1Encodable
+	{
+	    private readonly Asn1Sequence content;
+
+	    private PopoDecKeyChallContent(Asn1Sequence seq)
+	    {
+	        content = seq;
+	    }
+
+	    public static PopoDecKeyChallContent GetInstance(object obj)
+	    {
+	        if (obj is PopoDecKeyChallContent)
+	            return (PopoDecKeyChallContent)obj;
+
+			if (obj is Asn1Sequence)
+	            return new PopoDecKeyChallContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+	    }
+
+	    public virtual Challenge[] ToChallengeArray()
+	    {
+	        Challenge[] result = new Challenge[content.Count];
+	        for (int i = 0; i != result.Length; ++i)
+	        {
+	            result[i] = Challenge.GetInstance(content[i]);
+	        }
+	        return result;
+	    }
+
+	    /**
+	     * <pre>
+	     * PopoDecKeyChallContent ::= SEQUENCE OF Challenge
+	     * </pre>
+	     * @return a basic ASN.1 object representation.
+	     */
+	    public override Asn1Object ToAsn1Object()
+	    {
+	        return content;
+	    }
+	}
+}
diff --git a/crypto/src/asn1/cmp/PopoDecKeyRespContent.cs b/crypto/src/asn1/cmp/PopoDecKeyRespContent.cs
new file mode 100644
index 000000000..8c322e4ec
--- /dev/null
+++ b/crypto/src/asn1/cmp/PopoDecKeyRespContent.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class PopoDecKeyRespContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+
+		private PopoDecKeyRespContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static PopoDecKeyRespContent GetInstance(object obj)
+		{
+			if (obj is PopoDecKeyRespContent)
+				return (PopoDecKeyRespContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new PopoDecKeyRespContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual DerInteger[] ToDerIntegerArray()
+		{
+			DerInteger[] result = new DerInteger[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = DerInteger.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * PopoDecKeyRespContent ::= SEQUENCE OF INTEGER
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/ProtectedPart.cs b/crypto/src/asn1/cmp/ProtectedPart.cs
new file mode 100644
index 000000000..db6798fee
--- /dev/null
+++ b/crypto/src/asn1/cmp/ProtectedPart.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class ProtectedPart
+		: Asn1Encodable
+	{
+		private readonly PkiHeader header;
+		private readonly PkiBody body;
+		
+		private ProtectedPart(Asn1Sequence seq)
+		{
+			header = PkiHeader.GetInstance(seq[0]);
+			body = PkiBody.GetInstance(seq[1]);
+		}
+
+		public static ProtectedPart GetInstance(object obj)
+		{
+			if (obj is ProtectedPart)
+				return (ProtectedPart)obj;
+
+			if (obj is Asn1Sequence)
+				return new ProtectedPart((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public ProtectedPart(PkiHeader header, PkiBody body)
+		{
+			this.header = header;
+			this.body = body;
+		}
+
+		public virtual PkiHeader Header
+		{
+			get { return header; }
+		}
+
+		public virtual PkiBody Body
+		{
+			get { return body; }
+		}
+
+		/**
+		 * <pre>
+		 * ProtectedPart ::= SEQUENCE {
+		 *                    header    PKIHeader,
+		 *                    body      PKIBody
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(header, body);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/RevAnnContent.cs b/crypto/src/asn1/cmp/RevAnnContent.cs
new file mode 100644
index 000000000..2c3bd5f77
--- /dev/null
+++ b/crypto/src/asn1/cmp/RevAnnContent.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevAnnContent
+		: Asn1Encodable
+	{
+		private readonly PkiStatusEncodable status;
+		private readonly CertId certId;
+		private readonly DerGeneralizedTime willBeRevokedAt;
+		private readonly DerGeneralizedTime badSinceDate;
+		private readonly X509Extensions crlDetails;
+
+		private RevAnnContent(Asn1Sequence seq)
+		{
+			status = PkiStatusEncodable.GetInstance(seq[0]);
+			certId = CertId.GetInstance(seq[1]);
+			willBeRevokedAt = DerGeneralizedTime.GetInstance(seq[2]);
+			badSinceDate = DerGeneralizedTime.GetInstance(seq[3]);
+
+			if (seq.Count > 4)
+			{
+				crlDetails = X509Extensions.GetInstance(seq[4]);
+			}
+		}
+
+		public static RevAnnContent GetInstance(object obj)
+		{
+			if (obj is RevAnnContent)
+				return (RevAnnContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevAnnContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public virtual PkiStatusEncodable Status
+		{
+			get { return status; }
+		}
+
+		public virtual CertId CertID
+		{
+			get { return certId; }
+		}
+
+		public virtual DerGeneralizedTime WillBeRevokedAt
+		{
+			get { return willBeRevokedAt; }
+		}
+
+		public virtual DerGeneralizedTime BadSinceDate
+		{
+			get { return badSinceDate; }
+		}
+
+		public virtual X509Extensions CrlDetails
+		{
+			get { return crlDetails; }
+		}
+
+		/**
+		 * <pre>
+		 * RevAnnContent ::= SEQUENCE {
+		 *       status              PKIStatus,
+		 *       certId              CertId,
+		 *       willBeRevokedAt     GeneralizedTime,
+		 *       badSinceDate        GeneralizedTime,
+		 *       crlDetails          Extensions  OPTIONAL
+		 *        -- extra CRL details (e.g., crl number, reason, location, etc.)
+		 * }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status, certId, willBeRevokedAt, badSinceDate);
+			v.AddOptional(crlDetails);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/RevDetails.cs b/crypto/src/asn1/cmp/RevDetails.cs
new file mode 100644
index 000000000..1bd95f1db
--- /dev/null
+++ b/crypto/src/asn1/cmp/RevDetails.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevDetails
+		: Asn1Encodable
+	{
+		private readonly CertTemplate certDetails;
+		private readonly X509Extensions crlEntryDetails;
+
+		private RevDetails(Asn1Sequence seq)
+		{
+			certDetails = CertTemplate.GetInstance(seq[0]);
+
+			if  (seq.Count > 1)
+			{
+				crlEntryDetails = X509Extensions.GetInstance(seq[1]);
+			}
+		}
+
+		public static RevDetails GetInstance(object obj)
+		{
+			if (obj is RevDetails)
+				return (RevDetails)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevDetails((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public RevDetails(CertTemplate certDetails)
+		{
+			this.certDetails = certDetails;
+		}
+		
+		public RevDetails(CertTemplate certDetails, X509Extensions crlEntryDetails)
+		{
+			this.crlEntryDetails = crlEntryDetails;
+		}
+
+		public virtual CertTemplate CertDetails
+		{
+			get { return certDetails; }
+		}
+
+		public virtual X509Extensions CrlEntryDetails
+		{
+			get { return crlEntryDetails; }
+		}
+
+		/**
+		* <pre>
+		* RevDetails ::= SEQUENCE {
+		*                  certDetails         CertTemplate,
+		*                   -- allows requester to specify as much as they can about
+		*                   -- the cert. for which revocation is requested
+		*                   -- (e.g., for cases in which serialNumber is not available)
+		*                   crlEntryDetails     Extensions       OPTIONAL
+		*                   -- requested crlEntryExtensions
+		*             }
+		* </pre>
+		* @return a basic ASN.1 object representation.
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certDetails);
+			v.AddOptional(crlEntryDetails);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/RevRepContent.cs b/crypto/src/asn1/cmp/RevRepContent.cs
new file mode 100644
index 000000000..47987265a
--- /dev/null
+++ b/crypto/src/asn1/cmp/RevRepContent.cs
@@ -0,0 +1,112 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevRepContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence status;
+		private readonly Asn1Sequence revCerts;
+		private readonly Asn1Sequence crls;
+
+		private RevRepContent(Asn1Sequence seq)
+		{
+			status = Asn1Sequence.GetInstance(seq[0]);
+
+			for (int pos = 1; pos < seq.Count; ++pos)
+			{
+				Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[pos]);
+
+				if (tObj.TagNo == 0)
+				{
+					revCerts = Asn1Sequence.GetInstance(tObj, true);
+				}
+				else
+				{
+					crls = Asn1Sequence.GetInstance(tObj, true);
+				}
+			}
+		}
+
+		public static RevRepContent GetInstance(object obj)
+		{
+			if (obj is RevRepContent)
+				return (RevRepContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevRepContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+		
+		public virtual PkiStatusInfo[] GetStatus()
+		{
+			PkiStatusInfo[] results = new PkiStatusInfo[status.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = PkiStatusInfo.GetInstance(status[i]);
+			}
+			return results;
+		}
+
+		public virtual CertId[] GetRevCerts()
+		{
+			if (revCerts == null)
+				return null;
+
+			CertId[] results = new CertId[revCerts.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertId.GetInstance(revCerts[i]);
+			}
+			return results;
+		}
+
+		public virtual CertificateList[] GetCrls()
+		{
+			if (crls == null)
+				return null;
+
+			CertificateList[] results = new CertificateList[crls.Count];
+			for (int i = 0; i != results.Length; ++i)
+			{
+				results[i] = CertificateList.GetInstance(crls[i]);
+			}
+			return results;
+		}
+
+		/**
+		 * <pre>
+		 * RevRepContent ::= SEQUENCE {
+		 *        status       SEQUENCE SIZE (1..MAX) OF PKIStatusInfo,
+		 *        -- in same order as was sent in RevReqContent
+		 *        revCerts [0] SEQUENCE SIZE (1..MAX) OF CertId OPTIONAL,
+		 *        -- IDs for which revocation was requested
+		 *        -- (same order as status)
+		 *        crls     [1] SEQUENCE SIZE (1..MAX) OF CertificateList OPTIONAL
+		 *        -- the resulting CRLs (there may be more than one)
+		 *   }
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(status);
+			AddOptional(v, 0, revCerts);
+			AddOptional(v, 1, crls);
+			return new DerSequence(v);
+		}
+
+		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+		{
+			if (obj != null)
+			{
+				v.Add(new DerTaggedObject(true, tagNo, obj));
+			}
+		}
+	}
+}
+
diff --git a/crypto/src/asn1/cmp/RevRepContentBuilder.cs b/crypto/src/asn1/cmp/RevRepContentBuilder.cs
new file mode 100644
index 000000000..cc17d1d4c
--- /dev/null
+++ b/crypto/src/asn1/cmp/RevRepContentBuilder.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevRepContentBuilder
+	{
+		private readonly Asn1EncodableVector status = new Asn1EncodableVector();
+		private readonly Asn1EncodableVector revCerts = new Asn1EncodableVector();
+		private readonly Asn1EncodableVector crls = new Asn1EncodableVector();
+
+		public virtual RevRepContentBuilder Add(PkiStatusInfo status)
+		{
+			this.status.Add(status);
+			return this;
+		}
+
+		public virtual RevRepContentBuilder Add(PkiStatusInfo status, CertId certId)
+		{
+			if (this.status.Count != this.revCerts.Count)
+				throw new InvalidOperationException("status and revCerts sequence must be in common order");
+
+			this.status.Add(status);
+			this.revCerts.Add(certId);
+			return this;
+		}
+
+		public virtual RevRepContentBuilder AddCrl(CertificateList crl)
+		{
+			this.crls.Add(crl);
+			return this;
+		}
+
+		public virtual RevRepContent Build()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			v.Add(new DerSequence(status));
+
+			if (revCerts.Count != 0)
+			{
+				v.Add(new DerTaggedObject(true, 0, new DerSequence(revCerts)));
+			}
+
+			if (crls.Count != 0)
+			{
+				v.Add(new DerTaggedObject(true, 1, new DerSequence(crls)));
+			}
+
+			return RevRepContent.GetInstance(new DerSequence(v));
+		}
+	}
+}
diff --git a/crypto/src/asn1/cmp/RevReqContent.cs b/crypto/src/asn1/cmp/RevReqContent.cs
new file mode 100644
index 000000000..fbf869203
--- /dev/null
+++ b/crypto/src/asn1/cmp/RevReqContent.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cmp
+{
+	public class RevReqContent
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence content;
+		
+		private RevReqContent(Asn1Sequence seq)
+		{
+			content = seq;
+		}
+
+		public static RevReqContent GetInstance(object obj)
+		{
+			if (obj is RevReqContent)
+				return (RevReqContent)obj;
+
+			if (obj is Asn1Sequence)
+				return new RevReqContent((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+		}
+
+		public RevReqContent(params RevDetails[] revDetails)
+		{
+			this.content = new DerSequence(revDetails);
+		}
+
+		public virtual RevDetails[] ToRevDetailsArray()
+		{
+			RevDetails[] result = new RevDetails[content.Count];
+			for (int i = 0; i != result.Length; ++i)
+			{
+				result[i] = RevDetails.GetInstance(content[i]);
+			}
+			return result;
+		}
+
+		/**
+		 * <pre>
+		 * RevReqContent ::= SEQUENCE OF RevDetails
+		 * </pre>
+		 * @return a basic ASN.1 object representation.
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return content;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/Attribute.cs b/crypto/src/asn1/cms/Attribute.cs
new file mode 100644
index 000000000..c4a104a3f
--- /dev/null
+++ b/crypto/src/asn1/cms/Attribute.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class Attribute
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	attrType;
+        private Asn1Set				attrValues;
+
+		/**
+        * return an Attribute object from the given object.
+        *
+        * @param o the object we want converted.
+        * @exception ArgumentException if the object cannot be converted.
+        */
+        public static Attribute GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Attribute)
+				return (Attribute) obj;
+
+			if (obj is Asn1Sequence)
+                return new Attribute((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public Attribute(
+            Asn1Sequence seq)
+        {
+            attrType = (DerObjectIdentifier)seq[0];
+            attrValues = (Asn1Set)seq[1];
+        }
+
+		public Attribute(
+            DerObjectIdentifier attrType,
+            Asn1Set             attrValues)
+        {
+            this.attrType = attrType;
+            this.attrValues = attrValues;
+        }
+
+        public DerObjectIdentifier AttrType
+		{
+			get { return attrType; }
+		}
+
+		public Asn1Set AttrValues
+		{
+			get { return attrValues; }
+		}
+
+		/**
+        * Produce an object suitable for an Asn1OutputStream.
+        * <pre>
+        * Attribute ::= SEQUENCE {
+        *     attrType OBJECT IDENTIFIER,
+        *     attrValues SET OF AttributeValue
+        * }
+        * </pre>
+        */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(attrType, attrValues);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/AttributeTable.cs b/crypto/src/asn1/cms/AttributeTable.cs
index 3c0164ce8..8a3ee5d0e 100644
--- a/crypto/src/asn1/cms/AttributeTable.cs
+++ b/crypto/src/asn1/cms/AttributeTable.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Asn1.Cms
     {
         private readonly IDictionary attributes;
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete]
         public AttributeTable(
             Hashtable attrs)
@@ -168,7 +168,7 @@ namespace Org.BouncyCastle.Asn1.Cms
             return Platform.CreateHashtable(attributes);
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete("Use 'ToDictionary' instead")]
 		public Hashtable ToHashtable()
         {
@@ -176,7 +176,7 @@ namespace Org.BouncyCastle.Asn1.Cms
         }
 #endif
 
-        public Asn1EncodableVector ToAsn1EncodableVector()
+		public Asn1EncodableVector ToAsn1EncodableVector()
         {
             Asn1EncodableVector v = new Asn1EncodableVector();
 
diff --git a/crypto/src/asn1/cms/Attributes.cs b/crypto/src/asn1/cms/Attributes.cs
index 47cb66bdb..5b6b13034 100644
--- a/crypto/src/asn1/cms/Attributes.cs
+++ b/crypto/src/asn1/cms/Attributes.cs
@@ -2,42 +2,54 @@ using System;
 
 namespace Org.BouncyCastle.Asn1.Cms
 {
-	public class Attributes
-		: Asn1Encodable
-	{
-		private readonly Asn1Set attributes;
-
-		private Attributes(Asn1Set attributes)
-		{
-			this.attributes = attributes;
-		}
-
-		public Attributes(Asn1EncodableVector v)
-		{
-			attributes = new BerSet(v);
-		}
-
-		public static Attributes GetInstance(object obj)
-		{
-			if (obj is Attributes)
-				return (Attributes)obj;
-
-			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 override Asn1Object ToAsn1Object()
-		{
-			return attributes;
-		}
-	}
+    public class Attributes
+        : Asn1Encodable
+    {
+        private readonly Asn1Set attributes;
+
+        private Attributes(Asn1Set attributes)
+        {
+            this.attributes = attributes;
+        }
+
+        public Attributes(Asn1EncodableVector v)
+        {
+            attributes = new BerSet(v);
+        }
+
+        public static Attributes GetInstance(object obj)
+        {
+            if (obj is Attributes)
+                return (Attributes)obj;
+
+            if (obj != null)
+                return new Attributes(Asn1Set.GetInstance(obj));
+
+            return null;
+        }
+
+        public virtual Attribute[] GetAttributes()
+        {
+            Attribute[] rv = new Attribute[attributes.Count];
+
+            for (int i = 0; i != rv.Length; i++)
+            {
+                rv[i] = Attribute.GetInstance(attributes[i]);
+            }
+
+            return rv;
+        }
+
+        /**
+         * <pre>
+         * Attributes ::=
+         *   SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
+         * </pre>
+         * @return
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return attributes;
+        }
+    }
 }
diff --git a/crypto/src/asn1/cms/AuthEnvelopedData.cs b/crypto/src/asn1/cms/AuthEnvelopedData.cs
new file mode 100644
index 000000000..4260d80f9
--- /dev/null
+++ b/crypto/src/asn1/cms/AuthEnvelopedData.cs
@@ -0,0 +1,203 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class AuthEnvelopedData
+		: Asn1Encodable
+	{
+		private DerInteger				version;
+		private OriginatorInfo			originatorInfo;
+		private Asn1Set					recipientInfos;
+		private EncryptedContentInfo	authEncryptedContentInfo;
+		private Asn1Set					authAttrs;
+		private Asn1OctetString			mac;
+		private Asn1Set					unauthAttrs;
+
+		public AuthEnvelopedData(
+			OriginatorInfo			originatorInfo,
+			Asn1Set					recipientInfos,
+			EncryptedContentInfo	authEncryptedContentInfo,
+			Asn1Set					authAttrs,
+			Asn1OctetString			mac,
+			Asn1Set					unauthAttrs)
+		{
+			// "It MUST be set to 0."
+			this.version = new DerInteger(0);
+
+			this.originatorInfo = originatorInfo;
+
+			// TODO
+			// "There MUST be at least one element in the collection."
+			this.recipientInfos = recipientInfos;
+
+			this.authEncryptedContentInfo = authEncryptedContentInfo;
+
+			// TODO
+			// "The authAttrs MUST be present if the content type carried in
+			// EncryptedContentInfo is not id-data."
+			this.authAttrs = authAttrs;
+
+			this.mac = mac;
+
+			this.unauthAttrs = unauthAttrs;
+	    }
+
+		private AuthEnvelopedData(
+			Asn1Sequence	seq)
+		{
+			int index = 0;
+
+			// TODO
+			// "It MUST be set to 0."
+			Asn1Object tmp = seq[index++].ToAsn1Object();
+			version = (DerInteger)tmp;
+
+			tmp = seq[index++].ToAsn1Object();
+			if (tmp is Asn1TaggedObject)
+			{
+				originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++].ToAsn1Object();
+			}
+
+			// TODO
+			// "There MUST be at least one element in the collection."
+			recipientInfos = Asn1Set.GetInstance(tmp);
+
+			tmp = seq[index++].ToAsn1Object();
+			authEncryptedContentInfo = EncryptedContentInfo.GetInstance(tmp);
+
+			tmp = seq[index++].ToAsn1Object();
+			if (tmp is Asn1TaggedObject)
+			{
+				authAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++].ToAsn1Object();
+			}
+			else
+			{
+				// TODO
+				// "The authAttrs MUST be present if the content type carried in
+				// EncryptedContentInfo is not id-data."
+			}
+
+			mac = Asn1OctetString.GetInstance(tmp);
+
+			if (seq.Count > index)
+			{
+				tmp = seq[index++].ToAsn1Object();
+				unauthAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+			}
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from a tagged object.
+		 *
+		 * @param obj      the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *                 tagged false otherwise.
+		 * @throws ArgumentException if the object held by the
+		 *                                  tagged object cannot be converted.
+		 */
+		public static AuthEnvelopedData GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @throws ArgumentException if the object cannot be converted.
+		 */
+		public static AuthEnvelopedData GetInstance(
+			object	obj)
+		{
+			if (obj == null || obj is AuthEnvelopedData)
+				return (AuthEnvelopedData)obj;
+
+			if (obj is Asn1Sequence)
+				return new AuthEnvelopedData((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid AuthEnvelopedData: " + obj.GetType().Name);
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo OriginatorInfo
+		{
+			get { return originatorInfo; }
+		}
+
+		public Asn1Set RecipientInfos
+		{
+			get { return recipientInfos; }
+		}
+
+		public EncryptedContentInfo AuthEncryptedContentInfo
+		{
+			get { return authEncryptedContentInfo; }
+		}
+
+		public Asn1Set AuthAttrs
+		{
+			get { return authAttrs; }
+		}
+
+		public Asn1OctetString Mac
+		{
+			get { return mac; }
+		}
+
+		public Asn1Set UnauthAttrs
+		{
+			get { return unauthAttrs; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * AuthEnvelopedData ::= SEQUENCE {
+		 *   version CMSVersion,
+		 *   originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+		 *   recipientInfos RecipientInfos,
+		 *   authEncryptedContentInfo EncryptedContentInfo,
+		 *   authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+		 *   mac MessageAuthenticationCode,
+		 *   unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+		 * </pre>
+		 */
+	    public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (originatorInfo != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, originatorInfo));
+			}
+
+			v.Add(recipientInfos, authEncryptedContentInfo);
+
+			// "authAttrs optionally contains the authenticated attributes."
+			if (authAttrs != null)
+			{
+				// "AuthAttributes MUST be DER encoded, even if the rest of the
+				// AuthEnvelopedData structure is BER encoded."
+				v.Add(new DerTaggedObject(false, 1, authAttrs));
+			}
+
+			v.Add(mac);
+
+			// "unauthAttrs optionally contains the unauthenticated attributes."
+			if (unauthAttrs != null)
+			{
+				v.Add(new DerTaggedObject(false, 2, unauthAttrs));
+			}
+
+			return new BerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/AuthEnvelopedDataParser.cs b/crypto/src/asn1/cms/AuthEnvelopedDataParser.cs
new file mode 100644
index 000000000..35cb3bfcc
--- /dev/null
+++ b/crypto/src/asn1/cms/AuthEnvelopedDataParser.cs
@@ -0,0 +1,145 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	 * Produce an object suitable for an Asn1OutputStream.
+	 * 
+	 * <pre>
+	 * AuthEnvelopedData ::= SEQUENCE {
+	 *   version CMSVersion,
+	 *   originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+	 *   recipientInfos RecipientInfos,
+	 *   authEncryptedContentInfo EncryptedContentInfo,
+	 *   authAttrs [1] IMPLICIT AuthAttributes OPTIONAL,
+	 *   mac MessageAuthenticationCode,
+	 *   unauthAttrs [2] IMPLICIT UnauthAttributes OPTIONAL }
+	 * </pre>
+	*/
+	public class AuthEnvelopedDataParser
+	{
+		private Asn1SequenceParser	seq;
+		private DerInteger			version;
+		private IAsn1Convertible	nextObject;
+		private bool				originatorInfoCalled;
+
+		public AuthEnvelopedDataParser(
+			Asn1SequenceParser	seq)
+		{
+			this.seq = seq;
+
+			// TODO
+			// "It MUST be set to 0."
+			this.version = (DerInteger)seq.ReadObject();
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo GetOriginatorInfo()
+		{
+			originatorInfoCalled = true;
+
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)nextObject).TagNo == 0)
+			{
+				Asn1SequenceParser originatorInfo = (Asn1SequenceParser) ((Asn1TaggedObjectParser)nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+				nextObject = null;
+				return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetRecipientInfos()
+		{
+			if (!originatorInfoCalled)
+			{
+				GetOriginatorInfo();
+			}
+
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			Asn1SetParser recipientInfos = (Asn1SetParser)nextObject;
+			nextObject = null;
+			return recipientInfos;
+		}
+
+		public EncryptedContentInfoParser GetAuthEncryptedContentInfo() 
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject != null)
+			{
+				Asn1SequenceParser o = (Asn1SequenceParser) nextObject;
+				nextObject = null;
+				return new EncryptedContentInfoParser(o);
+			}
+
+			return null;
+		}
+		
+		public Asn1SetParser GetAuthAttrs()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject is Asn1TaggedObjectParser)
+			{
+				IAsn1Convertible o = nextObject;
+				nextObject = null;
+				return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+			}
+
+			// TODO
+			// "The authAttrs MUST be present if the content type carried in
+			// EncryptedContentInfo is not id-data."
+
+			return null;
+		}
+		
+		public Asn1OctetString GetMac()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			IAsn1Convertible o = nextObject;
+			nextObject = null;
+
+			return Asn1OctetString.GetInstance(o.ToAsn1Object());
+		}
+		
+		public Asn1SetParser GetUnauthAttrs()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject != null)
+			{
+				IAsn1Convertible o = nextObject;
+				nextObject = null;
+				return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+			}
+
+			return null;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/AuthenticatedData.cs b/crypto/src/asn1/cms/AuthenticatedData.cs
new file mode 100644
index 000000000..15286d1aa
--- /dev/null
+++ b/crypto/src/asn1/cms/AuthenticatedData.cs
@@ -0,0 +1,270 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class AuthenticatedData
+		: Asn1Encodable
+	{
+		private DerInteger version;
+		private OriginatorInfo originatorInfo;
+		private Asn1Set recipientInfos;
+		private AlgorithmIdentifier macAlgorithm;
+		private AlgorithmIdentifier digestAlgorithm;
+		private ContentInfo encapsulatedContentInfo;
+		private Asn1Set authAttrs;
+		private Asn1OctetString mac;
+		private Asn1Set unauthAttrs;
+
+		public AuthenticatedData(
+			OriginatorInfo		originatorInfo,
+			Asn1Set				recipientInfos,
+			AlgorithmIdentifier	macAlgorithm,
+			AlgorithmIdentifier	digestAlgorithm,
+			ContentInfo			encapsulatedContent,
+			Asn1Set				authAttrs,
+			Asn1OctetString		mac,
+			Asn1Set				unauthAttrs)
+		{
+			if (digestAlgorithm != null || authAttrs != null)
+			{
+				if (digestAlgorithm == null || authAttrs == null)
+				{
+					throw new ArgumentException("digestAlgorithm and authAttrs must be set together");
+				}
+			}
+
+			version = new DerInteger(CalculateVersion(originatorInfo));
+
+			this.originatorInfo = originatorInfo;
+			this.macAlgorithm = macAlgorithm;
+			this.digestAlgorithm = digestAlgorithm;
+			this.recipientInfos = recipientInfos;
+			this.encapsulatedContentInfo = encapsulatedContent;
+			this.authAttrs = authAttrs;
+			this.mac = mac;
+			this.unauthAttrs = unauthAttrs;
+		}
+
+		private AuthenticatedData(
+			Asn1Sequence	seq)
+		{
+			int index = 0;
+
+			version = (DerInteger)seq[index++];
+
+			Asn1Encodable tmp = seq[index++];
+			if (tmp is Asn1TaggedObject)
+			{
+				originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++];
+			}
+
+			recipientInfos = Asn1Set.GetInstance(tmp);
+			macAlgorithm = AlgorithmIdentifier.GetInstance(seq[index++]);
+
+			tmp = seq[index++];
+			if (tmp is Asn1TaggedObject)
+			{
+				digestAlgorithm = AlgorithmIdentifier.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++];
+			}
+
+			encapsulatedContentInfo = ContentInfo.GetInstance(tmp);
+
+			tmp = seq[index++];
+			if (tmp is Asn1TaggedObject)
+			{
+				authAttrs = Asn1Set.GetInstance((Asn1TaggedObject)tmp, false);
+				tmp = seq[index++];
+			}
+
+			mac = Asn1OctetString.GetInstance(tmp);
+
+			if (seq.Count > index)
+			{
+				unauthAttrs = Asn1Set.GetInstance((Asn1TaggedObject)seq[index], false);
+			}
+		}
+
+		/**
+		 * return an AuthenticatedData object from a tagged object.
+		 *
+		 * @param obj      the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *                 tagged false otherwise.
+		 * @throws ArgumentException if the object held by the
+		 *                                  tagged object cannot be converted.
+		 */
+		public static AuthenticatedData GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return an AuthenticatedData object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @throws ArgumentException if the object cannot be converted.
+		 */
+		public static AuthenticatedData GetInstance(
+			object	obj)
+		{
+			if (obj == null || obj is AuthenticatedData)
+			{
+				return (AuthenticatedData)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new AuthenticatedData((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Invalid AuthenticatedData: " + obj.GetType().Name);
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo OriginatorInfo
+		{
+			get { return originatorInfo; }
+		}
+
+		public Asn1Set RecipientInfos
+		{
+			get { return recipientInfos; }
+		}
+
+		public AlgorithmIdentifier MacAlgorithm
+		{
+			get { return macAlgorithm; }
+		}
+
+        public AlgorithmIdentifier DigestAlgorithm
+        {
+            get { return digestAlgorithm; }
+        }
+
+		public ContentInfo EncapsulatedContentInfo
+		{
+			get { return encapsulatedContentInfo; }
+		}
+
+		public Asn1Set AuthAttrs
+		{
+			get { return authAttrs; }
+		}
+
+		public Asn1OctetString Mac
+		{
+			get { return mac; }
+		}
+
+		public Asn1Set UnauthAttrs
+		{
+			get { return unauthAttrs; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * AuthenticatedData ::= SEQUENCE {
+		 *       version CMSVersion,
+		 *       originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+		 *       recipientInfos RecipientInfos,
+		 *       macAlgorithm MessageAuthenticationCodeAlgorithm,
+		 *       digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+		 *       encapContentInfo EncapsulatedContentInfo,
+		 *       authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+		 *       mac MessageAuthenticationCode,
+		 *       unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+		 *
+		 * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+		 *
+		 * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+		 *
+		 * MessageAuthenticationCode ::= OCTET STRING
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (originatorInfo != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, originatorInfo));
+			}
+
+			v.Add(recipientInfos, macAlgorithm);
+
+			if (digestAlgorithm != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, digestAlgorithm));
+			}
+
+			v.Add(encapsulatedContentInfo);
+
+			if (authAttrs != null)
+			{
+				v.Add(new DerTaggedObject(false, 2, authAttrs));
+			}
+
+			v.Add(mac);
+
+			if (unauthAttrs != null)
+			{
+				v.Add(new DerTaggedObject(false, 3, unauthAttrs));
+			}
+
+			return new BerSequence(v);
+		}
+
+		public static int CalculateVersion(OriginatorInfo origInfo)
+		{
+			if (origInfo == null)
+				return 0;
+
+			int ver = 0;
+
+			foreach (object obj in origInfo.Certificates)
+			{
+				if (obj is Asn1TaggedObject)
+				{
+					Asn1TaggedObject tag = (Asn1TaggedObject)obj;
+
+					if (tag.TagNo == 2)
+					{
+						ver = 1;
+					}
+					else if (tag.TagNo == 3)
+					{
+						ver = 3;
+						break;
+					}
+				}
+			}
+
+			foreach (object obj in origInfo.Crls)
+			{
+				if (obj is Asn1TaggedObject)
+				{
+					Asn1TaggedObject tag = (Asn1TaggedObject)obj;
+
+					if (tag.TagNo == 1)
+					{
+						ver = 3;
+						break;
+					}
+				}
+			}
+
+			return ver;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/AuthenticatedDataParser.cs b/crypto/src/asn1/cms/AuthenticatedDataParser.cs
new file mode 100644
index 000000000..4b80d1b02
--- /dev/null
+++ b/crypto/src/asn1/cms/AuthenticatedDataParser.cs
@@ -0,0 +1,182 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	 * Produce an object suitable for an Asn1OutputStream.
+	 * <pre>
+	 * AuthenticatedData ::= SEQUENCE {
+	 *       version CMSVersion,
+	 *       originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+	 *       recipientInfos RecipientInfos,
+	 *       macAlgorithm MessageAuthenticationCodeAlgorithm,
+	 *       digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
+	 *       encapContentInfo EncapsulatedContentInfo,
+	 *       authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
+	 *       mac MessageAuthenticationCode,
+	 *       unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
+	 *
+	 * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
+	 *
+	 * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
+	 *
+	 * MessageAuthenticationCode ::= OCTET STRING
+	 * </pre>
+	 */
+	public class AuthenticatedDataParser
+	{
+	    private Asn1SequenceParser	seq;
+	    private DerInteger			version;
+	    private IAsn1Convertible	nextObject;
+	    private bool				originatorInfoCalled;
+
+	    public AuthenticatedDataParser(
+	        Asn1SequenceParser	seq)
+	    {
+	        this.seq = seq;
+	        this.version = (DerInteger)seq.ReadObject();
+	    }
+
+	    public DerInteger Version
+	    {
+	        get { return version; }
+	    }
+
+	    public OriginatorInfo GetOriginatorInfo()
+	    {
+	        originatorInfoCalled = true;
+
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)nextObject).TagNo == 0)
+	        {
+	            Asn1SequenceParser originatorInfo = (Asn1SequenceParser) ((Asn1TaggedObjectParser)nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+	            nextObject = null;
+	            return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+	        }
+
+	        return null;
+	    }
+
+	    public Asn1SetParser GetRecipientInfos()
+	    {
+	        if (!originatorInfoCalled)
+	        {
+	            GetOriginatorInfo();
+	        }
+
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        Asn1SetParser recipientInfos = (Asn1SetParser)nextObject;
+	        nextObject = null;
+	        return recipientInfos;
+	    }
+
+	    public AlgorithmIdentifier GetMacAlgorithm()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject != null)
+	        {
+	            Asn1SequenceParser o = (Asn1SequenceParser)nextObject;
+	            nextObject = null;
+	            return AlgorithmIdentifier.GetInstance(o.ToAsn1Object());
+	        }
+
+	        return null;
+	    }
+
+		public AlgorithmIdentifier GetDigestAlgorithm()
+		{
+			if (nextObject == null)
+			{
+				nextObject = seq.ReadObject();
+			}
+
+			if (nextObject is Asn1TaggedObjectParser)
+			{
+				AlgorithmIdentifier obj = AlgorithmIdentifier.GetInstance(
+					(Asn1TaggedObject)nextObject.ToAsn1Object(), false);
+				nextObject = null;
+				return obj;
+			}
+
+			return null;
+		}
+
+	    public ContentInfoParser GetEnapsulatedContentInfo()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject != null)
+	        {
+	            Asn1SequenceParser o = (Asn1SequenceParser)nextObject;
+	            nextObject = null;
+	            return new ContentInfoParser(o);
+	        }
+
+	        return null;
+	    }
+
+	    public Asn1SetParser GetAuthAttrs()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject is Asn1TaggedObjectParser)
+	        {
+	            IAsn1Convertible o = nextObject;
+	            nextObject = null;
+	            return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+	        }
+
+	        return null;
+	    }
+
+	    public Asn1OctetString GetMac()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        IAsn1Convertible o = nextObject;
+	        nextObject = null;
+
+	        return Asn1OctetString.GetInstance(o.ToAsn1Object());
+	    }
+
+	    public Asn1SetParser GetUnauthAttrs()
+	    {
+	        if (nextObject == null)
+	        {
+	            nextObject = seq.ReadObject();
+	        }
+
+	        if (nextObject != null)
+	        {
+	            IAsn1Convertible o = nextObject;
+	            nextObject = null;
+	            return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+	        }
+
+	        return null;
+	    }
+	}
+}
diff --git a/crypto/src/asn1/cms/CMSAttributes.cs b/crypto/src/asn1/cms/CMSAttributes.cs
new file mode 100644
index 000000000..fca2b6738
--- /dev/null
+++ b/crypto/src/asn1/cms/CMSAttributes.cs
@@ -0,0 +1,14 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public abstract class CmsAttributes
+    {
+        public static readonly DerObjectIdentifier ContentType		= PkcsObjectIdentifiers.Pkcs9AtContentType;
+        public static readonly DerObjectIdentifier MessageDigest	= PkcsObjectIdentifiers.Pkcs9AtMessageDigest;
+        public static readonly DerObjectIdentifier SigningTime		= PkcsObjectIdentifiers.Pkcs9AtSigningTime;
+		public static readonly DerObjectIdentifier CounterSignature = PkcsObjectIdentifiers.Pkcs9AtCounterSignature;
+		public static readonly DerObjectIdentifier ContentHint		= PkcsObjectIdentifiers.IdAAContentHint;
+	}
+}
diff --git a/crypto/src/asn1/cms/CMSObjectIdentifiers.cs b/crypto/src/asn1/cms/CMSObjectIdentifiers.cs
index 59009bda7..2ad0a3c7c 100644
--- a/crypto/src/asn1/cms/CMSObjectIdentifiers.cs
+++ b/crypto/src/asn1/cms/CMSObjectIdentifiers.cs
@@ -10,9 +10,19 @@ namespace Org.BouncyCastle.Asn1.Cms
         public static readonly DerObjectIdentifier SignedAndEnvelopedData = PkcsObjectIdentifiers.SignedAndEnvelopedData;
         public static readonly DerObjectIdentifier DigestedData = PkcsObjectIdentifiers.DigestedData;
         public static readonly DerObjectIdentifier EncryptedData = PkcsObjectIdentifiers.EncryptedData;
-		public static readonly DerObjectIdentifier AuthenticatedData = PkcsObjectIdentifiers.IdCTAuthData;
+        public static readonly DerObjectIdentifier AuthenticatedData = PkcsObjectIdentifiers.IdCTAuthData;
         public static readonly DerObjectIdentifier CompressedData = PkcsObjectIdentifiers.IdCTCompressedData;
-		public static readonly DerObjectIdentifier AuthEnvelopedData = PkcsObjectIdentifiers.IdCTAuthEnvelopedData;
-		public static readonly DerObjectIdentifier timestampedData = PkcsObjectIdentifiers.IdCTTimestampedData;
+        public static readonly DerObjectIdentifier AuthEnvelopedData = PkcsObjectIdentifiers.IdCTAuthEnvelopedData;
+        public static readonly DerObjectIdentifier timestampedData = PkcsObjectIdentifiers.IdCTTimestampedData;
+
+        /**
+         * The other Revocation Info arc
+         * id-ri OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+         *                                   dod(6) internet(1) security(5) mechanisms(5) pkix(7) ri(16) }
+         */
+        public static readonly DerObjectIdentifier id_ri = new DerObjectIdentifier("1.3.6.1.5.5.7.16");
+
+        public static readonly DerObjectIdentifier id_ri_ocsp_response = id_ri.Branch("2");
+        public static readonly DerObjectIdentifier id_ri_scvp = id_ri.Branch("4");
     }
 }
diff --git a/crypto/src/asn1/cms/CompressedData.cs b/crypto/src/asn1/cms/CompressedData.cs
new file mode 100644
index 000000000..5a2869b8c
--- /dev/null
+++ b/crypto/src/asn1/cms/CompressedData.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    /**
+     * RFC 3274 - CMS Compressed Data.
+     * <pre>
+     * CompressedData ::= Sequence {
+     *  version CMSVersion,
+     *  compressionAlgorithm CompressionAlgorithmIdentifier,
+     *  encapContentInfo EncapsulatedContentInfo
+     * }
+     * </pre>
+     */
+    public class CompressedData
+        : Asn1Encodable
+    {
+        private DerInteger			version;
+        private AlgorithmIdentifier	compressionAlgorithm;
+        private ContentInfo			encapContentInfo;
+
+		public CompressedData(
+            AlgorithmIdentifier	compressionAlgorithm,
+            ContentInfo			encapContentInfo)
+        {
+            this.version = new DerInteger(0);
+            this.compressionAlgorithm = compressionAlgorithm;
+            this.encapContentInfo = encapContentInfo;
+        }
+
+		public CompressedData(
+            Asn1Sequence seq)
+        {
+            this.version = (DerInteger) seq[0];
+            this.compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+            this.encapContentInfo = ContentInfo.GetInstance(seq[2]);
+        }
+
+		/**
+         * return a CompressedData object from a tagged object.
+         *
+         * @param ato the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static CompressedData GetInstance(
+            Asn1TaggedObject ato,
+            bool explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(ato, explicitly));
+        }
+
+        /**
+         * return a CompressedData object from the given object.
+         *
+         * @param _obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static CompressedData GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is CompressedData)
+                return (CompressedData)obj;
+
+			if (obj is Asn1Sequence)
+                return new CompressedData((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid CompressedData: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public AlgorithmIdentifier CompressionAlgorithmIdentifier
+		{
+			get { return compressionAlgorithm; }
+		}
+
+		public ContentInfo EncapContentInfo
+		{
+			get { return encapContentInfo; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new BerSequence(version, compressionAlgorithm, encapContentInfo);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/CompressedDataParser.cs b/crypto/src/asn1/cms/CompressedDataParser.cs
new file mode 100644
index 000000000..7c53453df
--- /dev/null
+++ b/crypto/src/asn1/cms/CompressedDataParser.cs
@@ -0,0 +1,47 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* RFC 3274 - CMS Compressed Data.
+	* <pre>
+	* CompressedData ::= SEQUENCE {
+	*  version CMSVersion,
+	*  compressionAlgorithm CompressionAlgorithmIdentifier,
+	*  encapContentInfo EncapsulatedContentInfo
+	* }
+	* </pre>
+	*/
+	public class CompressedDataParser
+	{
+		private DerInteger			_version;
+		private AlgorithmIdentifier	_compressionAlgorithm;
+		private ContentInfoParser	_encapContentInfo;
+
+		public CompressedDataParser(
+			Asn1SequenceParser seq)
+		{
+			this._version = (DerInteger)seq.ReadObject();
+			this._compressionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
+			this._encapContentInfo = new ContentInfoParser((Asn1SequenceParser)seq.ReadObject());
+		}
+
+		public DerInteger Version
+		{
+			get { return _version; }
+		}
+
+		public AlgorithmIdentifier CompressionAlgorithmIdentifier
+		{
+			get { return _compressionAlgorithm; }
+		}
+
+		public ContentInfoParser GetEncapContentInfo()
+		{
+			return _encapContentInfo;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/ContentInfo.cs b/crypto/src/asn1/cms/ContentInfo.cs
index 61a277535..278ceca46 100644
--- a/crypto/src/asn1/cms/ContentInfo.cs
+++ b/crypto/src/asn1/cms/ContentInfo.cs
@@ -5,79 +5,84 @@ using Org.BouncyCastle.Asn1;
 
 namespace Org.BouncyCastle.Asn1.Cms
 {
-	public class ContentInfo
-		: Asn1Encodable
-	{
-		private readonly DerObjectIdentifier	contentType;
-		private readonly Asn1Encodable			content;
-
-		public static ContentInfo GetInstance(
-			object obj)
-		{
-			if (obj == null || obj is ContentInfo)
-				return (ContentInfo) obj;
-
-			if (obj is Asn1Sequence)
-				return new ContentInfo((Asn1Sequence) obj);
-
-			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name);
-		}
-
-		private ContentInfo(
-			Asn1Sequence seq)
-		{
-			if (seq.Count < 1 || seq.Count > 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
-
-			contentType = (DerObjectIdentifier) seq[0];
-
-			if (seq.Count > 1)
-			{
-				Asn1TaggedObject tagged = (Asn1TaggedObject) seq[1];
-				if (!tagged.IsExplicit() || tagged.TagNo != 0)
-					throw new ArgumentException("Bad tag for 'content'", "seq");
-
-				content = tagged.GetObject();
-			}
-		}
-
-		public ContentInfo(
-			DerObjectIdentifier	contentType,
-			Asn1Encodable		content)
-		{
-			this.contentType = contentType;
-			this.content = content;
-		}
-
-		public DerObjectIdentifier ContentType
-		{
-			get { return contentType; }
-		}
-
-		public Asn1Encodable Content
-		{
-			get { return content; }
-		}
-
-		/**
-		 * Produce an object suitable for an Asn1OutputStream.
-		 * <pre>
-		 * ContentInfo ::= Sequence {
-		 *          contentType ContentType,
-		 *          content
-		 *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
-		 * </pre>
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			Asn1EncodableVector v = new Asn1EncodableVector(contentType);
-
-			if (content != null)
-			{
-				v.Add(new BerTaggedObject(0, content));
-			}
-
-			return new BerSequence(v);
-		}
-	}
+    public class ContentInfo
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	contentType;
+        private readonly Asn1Encodable			content;
+
+        public static ContentInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is ContentInfo)
+                return (ContentInfo) obj;
+
+            if (obj is Asn1Sequence)
+                return new ContentInfo((Asn1Sequence) obj);
+
+            throw new ArgumentException("unknown object in factory: " + obj.GetType().Name);
+        }
+
+        public static ContentInfo GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        private ContentInfo(
+            Asn1Sequence seq)
+        {
+            if (seq.Count < 1 || seq.Count > 2)
+                throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            contentType = (DerObjectIdentifier) seq[0];
+
+            if (seq.Count > 1)
+            {
+                Asn1TaggedObject tagged = (Asn1TaggedObject) seq[1];
+                if (!tagged.IsExplicit() || tagged.TagNo != 0)
+                    throw new ArgumentException("Bad tag for 'content'", "seq");
+
+                content = tagged.GetObject();
+            }
+        }
+
+        public ContentInfo(
+            DerObjectIdentifier	contentType,
+            Asn1Encodable		content)
+        {
+            this.contentType = contentType;
+            this.content = content;
+        }
+
+        public DerObjectIdentifier ContentType
+        {
+            get { return contentType; }
+        }
+
+        public Asn1Encodable Content
+        {
+            get { return content; }
+        }
+
+        /**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ContentInfo ::= Sequence {
+         *          contentType ContentType,
+         *          content
+         *          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(contentType);
+
+            if (content != null)
+            {
+                v.Add(new BerTaggedObject(0, content));
+            }
+
+            return new BerSequence(v);
+        }
+    }
 }
diff --git a/crypto/src/asn1/cms/ContentInfoParser.cs b/crypto/src/asn1/cms/ContentInfoParser.cs
new file mode 100644
index 000000000..541cc0f59
--- /dev/null
+++ b/crypto/src/asn1/cms/ContentInfoParser.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* Produce an object suitable for an Asn1OutputStream.
+	* <pre>
+	* ContentInfo ::= SEQUENCE {
+	*          contentType ContentType,
+	*          content
+	*          [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+	* </pre>
+	*/
+	public class ContentInfoParser
+	{
+		private DerObjectIdentifier		contentType;
+		private Asn1TaggedObjectParser	content;
+
+		public ContentInfoParser(
+			Asn1SequenceParser seq)
+		{
+			contentType = (DerObjectIdentifier)seq.ReadObject();
+			content = (Asn1TaggedObjectParser)seq.ReadObject();
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return contentType; }
+		}
+
+		public IAsn1Convertible GetContent(
+			int tag)
+		{
+			if (content == null)
+				return null;
+
+			return content.GetObjectParser(tag, true);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/EncryptedContentInfo.cs b/crypto/src/asn1/cms/EncryptedContentInfo.cs
new file mode 100644
index 000000000..4fdc47138
--- /dev/null
+++ b/crypto/src/asn1/cms/EncryptedContentInfo.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class EncryptedContentInfo
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	contentType;
+        private AlgorithmIdentifier	contentEncryptionAlgorithm;
+        private Asn1OctetString		encryptedContent;
+
+		public EncryptedContentInfo(
+            DerObjectIdentifier	contentType,
+            AlgorithmIdentifier	contentEncryptionAlgorithm,
+            Asn1OctetString		encryptedContent)
+        {
+            this.contentType = contentType;
+            this.contentEncryptionAlgorithm = contentEncryptionAlgorithm;
+            this.encryptedContent = encryptedContent;
+        }
+
+		public EncryptedContentInfo(
+            Asn1Sequence seq)
+        {
+            contentType = (DerObjectIdentifier) seq[0];
+            contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+            {
+                encryptedContent = Asn1OctetString.GetInstance(
+					(Asn1TaggedObject) seq[2], false);
+            }
+        }
+
+		/**
+         * return an EncryptedContentInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static EncryptedContentInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is EncryptedContentInfo)
+                return (EncryptedContentInfo)obj;
+
+			if (obj is Asn1Sequence)
+                return new EncryptedContentInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid EncryptedContentInfo: " + obj.GetType().Name);
+        }
+
+        public DerObjectIdentifier ContentType
+        {
+            get { return contentType; }
+        }
+
+		public AlgorithmIdentifier ContentEncryptionAlgorithm
+        {
+			get { return contentEncryptionAlgorithm; }
+        }
+
+		public Asn1OctetString EncryptedContent
+        {
+			get { return encryptedContent; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * EncryptedContentInfo ::= Sequence {
+         *     contentType ContentType,
+         *     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+         *     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				contentType, contentEncryptionAlgorithm);
+
+			if (encryptedContent != null)
+            {
+                v.Add(new BerTaggedObject(false, 0, encryptedContent));
+            }
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/EncryptedContentInfoParser.cs b/crypto/src/asn1/cms/EncryptedContentInfoParser.cs
new file mode 100644
index 000000000..af748b1b3
--- /dev/null
+++ b/crypto/src/asn1/cms/EncryptedContentInfoParser.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* <pre>
+	* EncryptedContentInfo ::= SEQUENCE {
+	*     contentType ContentType,
+	*     contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+	*     encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+	* }
+	* </pre>
+	*/
+	public class EncryptedContentInfoParser
+	{
+		private DerObjectIdentifier		_contentType;
+		private AlgorithmIdentifier		_contentEncryptionAlgorithm;
+		private Asn1TaggedObjectParser	_encryptedContent;
+
+		public EncryptedContentInfoParser(
+			Asn1SequenceParser seq)
+		{
+			_contentType = (DerObjectIdentifier)seq.ReadObject();
+			_contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
+			_encryptedContent = (Asn1TaggedObjectParser)seq.ReadObject();
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return _contentType; }
+		}
+
+		public AlgorithmIdentifier ContentEncryptionAlgorithm
+		{
+			get { return _contentEncryptionAlgorithm; }
+		}
+
+		public IAsn1Convertible GetEncryptedContent(
+			int tag)
+		{
+			return _encryptedContent.GetObjectParser(tag, false);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/EncryptedData.cs b/crypto/src/asn1/cms/EncryptedData.cs
new file mode 100644
index 000000000..5b8378282
--- /dev/null
+++ b/crypto/src/asn1/cms/EncryptedData.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class EncryptedData
+		: Asn1Encodable
+	{
+		private readonly DerInteger				version;
+		private readonly EncryptedContentInfo	encryptedContentInfo;
+		private readonly Asn1Set				unprotectedAttrs;
+
+		public static EncryptedData GetInstance(
+			object obj)
+		{
+			if (obj is EncryptedData)
+				return (EncryptedData) obj;
+
+			if (obj is Asn1Sequence)
+				return new EncryptedData((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid EncryptedData: " + obj.GetType().Name);
+		}
+
+		public EncryptedData(
+			EncryptedContentInfo encInfo)
+			: this(encInfo, null)
+		{
+		}
+
+		public EncryptedData(
+			EncryptedContentInfo	encInfo,
+			Asn1Set					unprotectedAttrs)
+		{
+			if (encInfo == null)
+				throw new ArgumentNullException("encInfo");
+
+			this.version = new DerInteger((unprotectedAttrs == null) ? 0 : 2);
+			this.encryptedContentInfo = encInfo;
+			this.unprotectedAttrs = unprotectedAttrs;
+		}
+
+		private EncryptedData(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.version = DerInteger.GetInstance(seq[0]);
+			this.encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				this.unprotectedAttrs = Asn1Set.GetInstance(seq[2]);
+			}
+		}
+
+		public virtual DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public virtual EncryptedContentInfo EncryptedContentInfo
+		{
+			get { return encryptedContentInfo; }
+		}
+
+		public virtual Asn1Set UnprotectedAttrs
+		{
+			get { return unprotectedAttrs; }
+		}
+
+		/**
+		* <pre>
+		*       EncryptedData ::= SEQUENCE {
+		*                     version CMSVersion,
+		*                     encryptedContentInfo EncryptedContentInfo,
+		*                     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
+		* </pre>
+		* @return a basic ASN.1 object representation.
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version, encryptedContentInfo);
+
+			if (unprotectedAttrs != null)
+			{
+				v.Add(new BerTaggedObject(false, 1, unprotectedAttrs));
+			}
+
+			return new BerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/EnvelopedData.cs b/crypto/src/asn1/cms/EnvelopedData.cs
index 47cd4a9f5..09f291a93 100644
--- a/crypto/src/asn1/cms/EnvelopedData.cs
+++ b/crypto/src/asn1/cms/EnvelopedData.cs
@@ -14,63 +14,58 @@ namespace Org.BouncyCastle.Asn1.Cms
         private EncryptedContentInfo	encryptedContentInfo;
         private Asn1Set					unprotectedAttrs;
 
-		public EnvelopedData(
+        public EnvelopedData(
             OriginatorInfo			originatorInfo,
             Asn1Set					recipientInfos,
             EncryptedContentInfo	encryptedContentInfo,
             Asn1Set					unprotectedAttrs)
         {
-            if (originatorInfo != null || unprotectedAttrs != null)
-            {
-                version = new DerInteger(2);
-            }
-            else
-            {
-                version = new DerInteger(0);
-
-				foreach (object o in recipientInfos)
-				{
-                    RecipientInfo ri = RecipientInfo.GetInstance(o);
-
-					if (!ri.Version.Equals(version))
-                    {
-                        version = new DerInteger(2);
-                        break;
-                    }
-                }
-            }
-
-			this.originatorInfo = originatorInfo;
+            this.version = new DerInteger(CalculateVersion(originatorInfo, recipientInfos, unprotectedAttrs));
+            this.originatorInfo = originatorInfo;
             this.recipientInfos = recipientInfos;
             this.encryptedContentInfo = encryptedContentInfo;
             this.unprotectedAttrs = unprotectedAttrs;
         }
 
-		public EnvelopedData(
+        public EnvelopedData(
+            OriginatorInfo originatorInfo,
+            Asn1Set recipientInfos,
+            EncryptedContentInfo encryptedContentInfo,
+            Attributes unprotectedAttrs)
+        {
+            this.version = new DerInteger(CalculateVersion(originatorInfo, recipientInfos, Asn1Set.GetInstance(unprotectedAttrs)));
+            this.originatorInfo = originatorInfo;
+            this.recipientInfos = recipientInfos;
+            this.encryptedContentInfo = encryptedContentInfo;
+            this.unprotectedAttrs = Asn1Set.GetInstance(unprotectedAttrs);
+        }
+
+        [Obsolete("Use 'GetInstance' instead")]
+        public EnvelopedData(
             Asn1Sequence seq)
         {
             int index = 0;
 
-			version = (DerInteger) seq[index++];
+            version = (DerInteger) seq[index++];
 
-			object tmp = seq[index++];
+            object tmp = seq[index++];
 
-			if (tmp is Asn1TaggedObject)
+            if (tmp is Asn1TaggedObject)
             {
                 originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject) tmp, false);
                 tmp = seq[index++];
             }
 
-			recipientInfos = Asn1Set.GetInstance(tmp);
+            recipientInfos = Asn1Set.GetInstance(tmp);
             encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[index++]);
 
-			if (seq.Count > index)
+            if (seq.Count > index)
             {
-				unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject) seq[index], false);
+                unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject) seq[index], false);
             }
         }
 
-		/**
+        /**
          * return an EnvelopedData object from a tagged object.
          *
          * @param obj the tagged object holding the object we want.
@@ -86,7 +81,7 @@ namespace Org.BouncyCastle.Asn1.Cms
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		/**
+        /**
          * return an EnvelopedData object from the given object.
          *
          * @param obj the object we want converted.
@@ -95,45 +90,39 @@ namespace Org.BouncyCastle.Asn1.Cms
         public static EnvelopedData GetInstance(
             object obj)
         {
-            if (obj == null || obj is EnvelopedData)
-            {
+            if (obj is EnvelopedData)
                 return (EnvelopedData)obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new EnvelopedData((Asn1Sequence)obj);
-            }
-
-			throw new ArgumentException("Invalid EnvelopedData: " + obj.GetType().Name);
+            if (obj == null)
+                return null;
+            return new EnvelopedData(Asn1Sequence.GetInstance(obj));
         }
 
-		public DerInteger Version
-		{
-			get { return version; }
-		}
+        public DerInteger Version
+        {
+            get { return version; }
+        }
 
-		public OriginatorInfo OriginatorInfo
-		{
-			get { return originatorInfo; }
-		}
+        public OriginatorInfo OriginatorInfo
+        {
+            get { return originatorInfo; }
+        }
 
-		public Asn1Set RecipientInfos
-		{
-			get { return recipientInfos; }
-		}
+        public Asn1Set RecipientInfos
+        {
+            get { return recipientInfos; }
+        }
 
-		public EncryptedContentInfo EncryptedContentInfo
-		{
-			get { return encryptedContentInfo; }
-		}
+        public EncryptedContentInfo EncryptedContentInfo
+        {
+            get { return encryptedContentInfo; }
+        }
 
-		public Asn1Set UnprotectedAttrs
-		{
-			get { return unprotectedAttrs; }
-		}
+        public Asn1Set UnprotectedAttrs
+        {
+            get { return unprotectedAttrs; }
+        }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          * EnvelopedData ::= Sequence {
@@ -149,19 +138,39 @@ namespace Org.BouncyCastle.Asn1.Cms
         {
             Asn1EncodableVector v = new Asn1EncodableVector(version);
 
-			if (originatorInfo != null)
+            if (originatorInfo != null)
             {
                 v.Add(new DerTaggedObject(false, 0, originatorInfo));
             }
 
-			v.Add(recipientInfos, encryptedContentInfo);
+            v.Add(recipientInfos, encryptedContentInfo);
 
-			if (unprotectedAttrs != null)
+            if (unprotectedAttrs != null)
             {
                 v.Add(new DerTaggedObject(false, 1, unprotectedAttrs));
             }
 
-			return new BerSequence(v);
+            return new BerSequence(v);
+        }
+
+        public static int CalculateVersion(OriginatorInfo originatorInfo, Asn1Set recipientInfos, Asn1Set unprotectedAttrs)
+        {
+            if (originatorInfo != null || unprotectedAttrs != null)
+            {
+                return 2;
+            }
+
+            foreach (object o in recipientInfos)
+            {
+                RecipientInfo ri = RecipientInfo.GetInstance(o);
+
+                if (ri.Version.Value.IntValue != 0)
+                {
+                    return 2;
+                }
+            }
+
+            return 0;
         }
     }
 }
diff --git a/crypto/src/asn1/cms/EnvelopedDataParser.cs b/crypto/src/asn1/cms/EnvelopedDataParser.cs
new file mode 100644
index 000000000..599353791
--- /dev/null
+++ b/crypto/src/asn1/cms/EnvelopedDataParser.cs
@@ -0,0 +1,107 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* Produce an object suitable for an Asn1OutputStream.
+	* <pre>
+	* EnvelopedData ::= SEQUENCE {
+	*     version CMSVersion,
+	*     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
+	*     recipientInfos RecipientInfos,
+	*     encryptedContentInfo EncryptedContentInfo,
+	*     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
+	* }
+	* </pre>
+	*/
+	public class EnvelopedDataParser
+	{
+		private Asn1SequenceParser	_seq;
+		private DerInteger			_version;
+		private IAsn1Convertible	_nextObject;
+		private bool				_originatorInfoCalled;
+
+		public EnvelopedDataParser(
+			Asn1SequenceParser seq)
+		{
+			this._seq = seq;
+			this._version = (DerInteger)seq.ReadObject();
+		}
+
+		public DerInteger Version
+		{
+			get { return _version; }
+		}
+
+		public OriginatorInfo GetOriginatorInfo() 
+		{
+			_originatorInfoCalled = true; 
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0)
+			{
+				Asn1SequenceParser originatorInfo = (Asn1SequenceParser)
+					((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Sequence, false);
+				_nextObject = null;
+				return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetRecipientInfos()
+		{
+			if (!_originatorInfoCalled)
+			{
+				GetOriginatorInfo();
+			}
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			Asn1SetParser recipientInfos = (Asn1SetParser)_nextObject;
+			_nextObject = null;
+			return recipientInfos;
+		}
+
+		public EncryptedContentInfoParser GetEncryptedContentInfo()
+		{
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject != null)
+			{
+				Asn1SequenceParser o = (Asn1SequenceParser) _nextObject;
+				_nextObject = null;
+				return new EncryptedContentInfoParser(o);
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetUnprotectedAttrs()
+		{
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject != null)
+			{
+				IAsn1Convertible o = _nextObject;
+				_nextObject = null;
+				return (Asn1SetParser)((Asn1TaggedObjectParser)o).GetObjectParser(Asn1Tags.Set, false);
+			}
+        
+			return null;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/Evidence.cs b/crypto/src/asn1/cms/Evidence.cs
new file mode 100644
index 000000000..4745e565b
--- /dev/null
+++ b/crypto/src/asn1/cms/Evidence.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class Evidence
+		: Asn1Encodable, IAsn1Choice
+	{
+		private TimeStampTokenEvidence tstEvidence;
+
+		public Evidence(TimeStampTokenEvidence tstEvidence)
+		{
+			this.tstEvidence = tstEvidence;
+		}
+
+		private Evidence(Asn1TaggedObject tagged)
+		{
+			if (tagged.TagNo == 0)
+			{
+				this.tstEvidence = TimeStampTokenEvidence.GetInstance(tagged, false);
+			}
+		}
+
+		public static Evidence GetInstance(object obj)
+		{
+			if (obj is Evidence)
+				return (Evidence)obj;
+
+			if (obj is Asn1TaggedObject)
+				return new Evidence(Asn1TaggedObject.GetInstance(obj));
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public virtual TimeStampTokenEvidence TstEvidence
+		{
+			get { return tstEvidence; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			if (tstEvidence != null)
+				return new DerTaggedObject(false, 0, tstEvidence);
+
+			return null;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/IssuerAndSerialNumber.cs b/crypto/src/asn1/cms/IssuerAndSerialNumber.cs
index ac1af961f..b509e7e19 100644
--- a/crypto/src/asn1/cms/IssuerAndSerialNumber.cs
+++ b/crypto/src/asn1/cms/IssuerAndSerialNumber.cs
@@ -12,19 +12,17 @@ namespace Org.BouncyCastle.Asn1.Cms
         private X509Name	name;
         private DerInteger	serialNumber;
 
-        public static IssuerAndSerialNumber GetInstance(
-            object obj)
+        public static IssuerAndSerialNumber GetInstance(object obj)
         {
-            if (obj is IssuerAndSerialNumber)
-                return (IssuerAndSerialNumber)obj;
-
-			if (obj is Asn1Sequence)
-                return new IssuerAndSerialNumber((Asn1Sequence)obj);
-
-			throw new ArgumentException(
-                "Illegal object in IssuerAndSerialNumber: " + obj.GetType().Name);
+            if (obj == null)
+                return null;
+            IssuerAndSerialNumber existing = obj as IssuerAndSerialNumber;
+            if (existing != null)
+                return existing;
+            return new IssuerAndSerialNumber(Asn1Sequence.GetInstance(obj));
         }
 
+        [Obsolete("Use GetInstance() instead")]
         public IssuerAndSerialNumber(
             Asn1Sequence seq)
         {
@@ -32,7 +30,7 @@ namespace Org.BouncyCastle.Asn1.Cms
             this.serialNumber = (DerInteger) seq[1];
         }
 
-		public IssuerAndSerialNumber(
+        public IssuerAndSerialNumber(
             X509Name	name,
             BigInteger	serialNumber)
         {
@@ -48,19 +46,19 @@ namespace Org.BouncyCastle.Asn1.Cms
             this.serialNumber = serialNumber;
         }
 
-		public X509Name Name
-		{
-			get { return name; }
-		}
+        public X509Name Name
+        {
+            get { return name; }
+        }
 
-		public DerInteger SerialNumber
-		{
-			get { return serialNumber; }
-		}
+        public DerInteger SerialNumber
+        {
+            get { return serialNumber; }
+        }
 
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(name, serialNumber);
+            return new DerSequence(name, serialNumber);
         }
     }
 }
diff --git a/crypto/src/asn1/cms/KEKIdentifier.cs b/crypto/src/asn1/cms/KEKIdentifier.cs
new file mode 100644
index 000000000..e5d1d9090
--- /dev/null
+++ b/crypto/src/asn1/cms/KEKIdentifier.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KekIdentifier
+        : Asn1Encodable
+    {
+        private Asn1OctetString		keyIdentifier;
+        private DerGeneralizedTime	date;
+        private OtherKeyAttribute	other;
+
+		public KekIdentifier(
+            byte[]              keyIdentifier,
+            DerGeneralizedTime  date,
+            OtherKeyAttribute   other)
+        {
+            this.keyIdentifier = new DerOctetString(keyIdentifier);
+            this.date = date;
+            this.other = other;
+        }
+
+		public KekIdentifier(
+            Asn1Sequence seq)
+        {
+            keyIdentifier = (Asn1OctetString) seq[0];
+
+			switch (seq.Count)
+            {
+            case 1:
+				break;
+            case 2:
+				if (seq[1] is DerGeneralizedTime)
+				{
+					date = (DerGeneralizedTime) seq[1];
+				}
+				else
+				{
+					other = OtherKeyAttribute.GetInstance(seq[2]);
+				}
+				break;
+            case 3:
+				date  = (DerGeneralizedTime) seq[1];
+				other = OtherKeyAttribute.GetInstance(seq[2]);
+				break;
+            default:
+				throw new ArgumentException("Invalid KekIdentifier");
+            }
+        }
+
+		/**
+         * return a KekIdentifier object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static KekIdentifier GetInstance(
+            Asn1TaggedObject obj,
+            bool explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        /**
+         * return a KekIdentifier object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KekIdentifier GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KekIdentifier)
+                return (KekIdentifier)obj;
+
+			if (obj is Asn1Sequence)
+                return new KekIdentifier((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid KekIdentifier: " + obj.GetType().Name);
+        }
+
+		public Asn1OctetString KeyIdentifier
+		{
+			get { return keyIdentifier; }
+		}
+
+		public DerGeneralizedTime Date
+		{
+			get { return date; }
+		}
+
+		public OtherKeyAttribute Other
+		{
+			get { return other; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KekIdentifier ::= Sequence {
+         *     keyIdentifier OCTET STRING,
+         *     date GeneralizedTime OPTIONAL,
+         *     other OtherKeyAttribute OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(keyIdentifier);
+			v.AddOptional(date, other);
+			return new DerSequence(v);
+        }
+    }
+}
+
diff --git a/crypto/src/asn1/cms/KEKRecipientInfo.cs b/crypto/src/asn1/cms/KEKRecipientInfo.cs
new file mode 100644
index 000000000..d847b50cc
--- /dev/null
+++ b/crypto/src/asn1/cms/KEKRecipientInfo.cs
@@ -0,0 +1,106 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KekRecipientInfo
+        : Asn1Encodable
+    {
+        private DerInteger			version;
+        private KekIdentifier       kekID;
+        private AlgorithmIdentifier keyEncryptionAlgorithm;
+        private Asn1OctetString     encryptedKey;
+
+		public KekRecipientInfo(
+            KekIdentifier       kekID,
+            AlgorithmIdentifier keyEncryptionAlgorithm,
+            Asn1OctetString     encryptedKey)
+        {
+            this.version = new DerInteger(4);
+            this.kekID = kekID;
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.encryptedKey = encryptedKey;
+        }
+
+		public KekRecipientInfo(
+            Asn1Sequence seq)
+        {
+            version = (DerInteger) seq[0];
+            kekID = KekIdentifier.GetInstance(seq[1]);
+            keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+            encryptedKey = (Asn1OctetString) seq[3];
+        }
+
+		/**
+         * return a KekRecipientInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static KekRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        /**
+         * return a KekRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KekRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KekRecipientInfo)
+                return (KekRecipientInfo)obj;
+
+			if(obj is Asn1Sequence)
+                return new KekRecipientInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid KekRecipientInfo: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public KekIdentifier KekID
+		{
+			get { return kekID; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KekRecipientInfo ::= Sequence {
+         *     version CMSVersion,  -- always set to 4
+         *     kekID KekIdentifier,
+         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *     encryptedKey EncryptedKey
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(version, kekID, keyEncryptionAlgorithm, encryptedKey);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs b/crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs
new file mode 100644
index 000000000..fa6fdb0f3
--- /dev/null
+++ b/crypto/src/asn1/cms/KeyAgreeRecipientIdentifier.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class KeyAgreeRecipientIdentifier
+		: Asn1Encodable, IAsn1Choice
+	{
+		/**
+		 * return an KeyAgreeRecipientIdentifier object from a tagged object.
+		 *
+		 * @param obj the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *              tagged false otherwise.
+		 * @exception ArgumentException if the object held by the
+		 *          tagged object cannot be converted.
+		 */
+		public static KeyAgreeRecipientIdentifier GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+    
+		/**
+		 * return an KeyAgreeRecipientIdentifier object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @exception ArgumentException if the object cannot be converted.
+		 */
+		public static KeyAgreeRecipientIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is KeyAgreeRecipientIdentifier)
+				return (KeyAgreeRecipientIdentifier)obj;
+
+			if (obj is Asn1Sequence)
+				return new KeyAgreeRecipientIdentifier(IssuerAndSerialNumber.GetInstance(obj));
+
+			if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 0)
+			{
+				return new KeyAgreeRecipientIdentifier(RecipientKeyIdentifier.GetInstance(
+					(Asn1TaggedObject)obj, false));
+			}
+
+			throw new ArgumentException("Invalid KeyAgreeRecipientIdentifier: " + obj.GetType().FullName, "obj");
+		} 
+
+		private readonly IssuerAndSerialNumber issuerSerial;
+		private readonly RecipientKeyIdentifier rKeyID;
+
+		public KeyAgreeRecipientIdentifier(
+			IssuerAndSerialNumber issuerSerial)
+		{
+			this.issuerSerial = issuerSerial;
+		}
+
+		public KeyAgreeRecipientIdentifier(
+			RecipientKeyIdentifier rKeyID)
+		{
+			this.rKeyID = rKeyID;
+		}
+
+		public IssuerAndSerialNumber IssuerAndSerialNumber
+		{
+			get { return issuerSerial; }
+		}
+
+		public RecipientKeyIdentifier RKeyID
+		{
+			get { return rKeyID; }
+		}
+
+		/** 
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * KeyAgreeRecipientIdentifier ::= CHOICE {
+		 *     issuerAndSerialNumber IssuerAndSerialNumber,
+		 *     rKeyId [0] IMPLICIT RecipientKeyIdentifier
+		 * }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			if (issuerSerial != null)
+			{
+				return issuerSerial.ToAsn1Object();
+			}
+
+			return new DerTaggedObject(false, 0, rKeyID);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs b/crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs
new file mode 100644
index 000000000..aafb008d4
--- /dev/null
+++ b/crypto/src/asn1/cms/KeyAgreeRecipientInfo.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KeyAgreeRecipientInfo
+        : Asn1Encodable
+    {
+        private DerInteger                  version;
+        private OriginatorIdentifierOrKey   originator;
+        private Asn1OctetString             ukm;
+        private AlgorithmIdentifier         keyEncryptionAlgorithm;
+        private Asn1Sequence                recipientEncryptedKeys;
+
+		public KeyAgreeRecipientInfo(
+            OriginatorIdentifierOrKey   originator,
+            Asn1OctetString             ukm,
+            AlgorithmIdentifier         keyEncryptionAlgorithm,
+            Asn1Sequence                recipientEncryptedKeys)
+        {
+            this.version = new DerInteger(3);
+            this.originator = originator;
+            this.ukm = ukm;
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.recipientEncryptedKeys = recipientEncryptedKeys;
+        }
+
+		public KeyAgreeRecipientInfo(
+            Asn1Sequence seq)
+        {
+            int index = 0;
+
+            version = (DerInteger) seq[index++];
+            originator = OriginatorIdentifierOrKey.GetInstance(
+				(Asn1TaggedObject) seq[index++], true);
+
+			if (seq[index] is Asn1TaggedObject)
+            {
+                ukm = Asn1OctetString.GetInstance(
+					(Asn1TaggedObject) seq[index++], true);
+            }
+
+			keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(
+				seq[index++]);
+
+			recipientEncryptedKeys = (Asn1Sequence) seq[index++];
+        }
+
+		/**
+         * return a KeyAgreeRecipientInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static KeyAgreeRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return a KeyAgreeRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KeyAgreeRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KeyAgreeRecipientInfo)
+                return (KeyAgreeRecipientInfo)obj;
+
+			if (obj is Asn1Sequence)
+                return new KeyAgreeRecipientInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException(
+                "Illegal object in KeyAgreeRecipientInfo: " + obj.GetType().Name);
+
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorIdentifierOrKey Originator
+		{
+			get { return originator; }
+		}
+
+		public Asn1OctetString UserKeyingMaterial
+		{
+			get { return ukm; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1Sequence RecipientEncryptedKeys
+		{
+			get { return recipientEncryptedKeys; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KeyAgreeRecipientInfo ::= Sequence {
+         *     version CMSVersion,  -- always set to 3
+         *     originator [0] EXPLICIT OriginatorIdentifierOrKey,
+         *     ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL,
+         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *     recipientEncryptedKeys RecipientEncryptedKeys
+         * }
+		 *
+		 * UserKeyingMaterial ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, new DerTaggedObject(true, 0, originator));
+
+			if (ukm != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, ukm));
+            }
+
+			v.Add(keyEncryptionAlgorithm, recipientEncryptedKeys);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/KeyTransRecipientInfo.cs b/crypto/src/asn1/cms/KeyTransRecipientInfo.cs
new file mode 100644
index 000000000..aae18c59d
--- /dev/null
+++ b/crypto/src/asn1/cms/KeyTransRecipientInfo.cs
@@ -0,0 +1,99 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class KeyTransRecipientInfo
+        : Asn1Encodable
+    {
+        private DerInteger          version;
+        private RecipientIdentifier rid;
+        private AlgorithmIdentifier keyEncryptionAlgorithm;
+        private Asn1OctetString     encryptedKey;
+
+		public KeyTransRecipientInfo(
+            RecipientIdentifier rid,
+            AlgorithmIdentifier keyEncryptionAlgorithm,
+            Asn1OctetString     encryptedKey)
+        {
+            if (rid.ToAsn1Object() is Asn1TaggedObject)
+            {
+                this.version = new DerInteger(2);
+            }
+            else
+            {
+                this.version = new DerInteger(0);
+            }
+
+			this.rid = rid;
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.encryptedKey = encryptedKey;
+        }
+
+		public KeyTransRecipientInfo(
+            Asn1Sequence seq)
+        {
+            this.version = (DerInteger) seq[0];
+            this.rid = RecipientIdentifier.GetInstance(seq[1]);
+            this.keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+            this.encryptedKey = (Asn1OctetString) seq[3];
+        }
+
+		/**
+         * return a KeyTransRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static KeyTransRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is KeyTransRecipientInfo)
+                return (KeyTransRecipientInfo) obj;
+
+			if(obj is Asn1Sequence)
+                return new KeyTransRecipientInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Illegal object in KeyTransRecipientInfo: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public RecipientIdentifier RecipientIdentifier
+		{
+			get { return rid; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * KeyTransRecipientInfo ::= Sequence {
+         *     version CMSVersion,  -- always set to 0 or 2
+         *     rid RecipientIdentifier,
+         *     keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *     encryptedKey EncryptedKey
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(version, rid, keyEncryptionAlgorithm, encryptedKey);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/MetaData.cs b/crypto/src/asn1/cms/MetaData.cs
new file mode 100644
index 000000000..ad2b5c426
--- /dev/null
+++ b/crypto/src/asn1/cms/MetaData.cs
@@ -0,0 +1,94 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class MetaData
+		: Asn1Encodable
+	{
+		private DerBoolean hashProtected;
+		private DerUtf8String fileName;
+		private DerIA5String  mediaType;
+		private Attributes otherMetaData;
+
+		public MetaData(
+			DerBoolean		hashProtected,
+			DerUtf8String	fileName,
+			DerIA5String	mediaType,
+			Attributes		otherMetaData)
+		{
+			this.hashProtected = hashProtected;
+			this.fileName = fileName;
+			this.mediaType = mediaType;
+			this.otherMetaData = otherMetaData;
+		}
+
+		private MetaData(Asn1Sequence seq)
+		{
+			this.hashProtected = DerBoolean.GetInstance(seq[0]);
+
+			int index = 1;
+
+			if (index < seq.Count && seq[index] is DerUtf8String)
+			{
+				this.fileName = DerUtf8String.GetInstance(seq[index++]);
+			}
+			if (index < seq.Count && seq[index] is DerIA5String)
+			{
+				this.mediaType = DerIA5String.GetInstance(seq[index++]);
+			}
+			if (index < seq.Count)
+			{
+				this.otherMetaData = Attributes.GetInstance(seq[index++]);
+			}
+		}
+
+		public static MetaData GetInstance(object obj)
+		{
+			if (obj is MetaData)
+				return (MetaData)obj;
+
+			if (obj != null)
+				return new MetaData(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		/**
+		 * <pre>
+		 * MetaData ::= SEQUENCE {
+		 *   hashProtected        BOOLEAN,
+		 *   fileName             UTF8String OPTIONAL,
+		 *   mediaType            IA5String OPTIONAL,
+		 *   otherMetaData        Attributes OPTIONAL
+		 * }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(hashProtected);
+			v.AddOptional(fileName, mediaType, otherMetaData);
+			return new DerSequence(v);
+		}
+
+		public virtual bool IsHashProtected
+		{
+			get { return hashProtected.IsTrue; }
+		}
+
+		public virtual DerUtf8String FileName
+		{
+			get { return fileName; }
+		}
+
+		public virtual DerIA5String MediaType
+		{
+			get { return mediaType; }
+		}
+
+		public virtual Attributes OtherMetaData
+		{
+			get { return otherMetaData; }
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs b/crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
new file mode 100644
index 000000000..d33a11725
--- /dev/null
+++ b/crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
@@ -0,0 +1,168 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OriginatorIdentifierOrKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        private Asn1Encodable id;
+
+        public OriginatorIdentifierOrKey(
+            IssuerAndSerialNumber id)
+        {
+            this.id = id;
+        }
+
+		[Obsolete("Use version taking a 'SubjectKeyIdentifier'")]
+        public OriginatorIdentifierOrKey(
+            Asn1OctetString id)
+			: this(new SubjectKeyIdentifier(id))
+        {
+        }
+
+        public OriginatorIdentifierOrKey(
+            SubjectKeyIdentifier id)
+        {
+            this.id = new DerTaggedObject(false, 0, id);
+        }
+
+        public OriginatorIdentifierOrKey(
+            OriginatorPublicKey id)
+        {
+            this.id = new DerTaggedObject(false, 1, id);
+        }
+
+		[Obsolete("Use more specific version")]
+        public OriginatorIdentifierOrKey(
+            Asn1Object id)
+        {
+            this.id = id;
+        }
+
+		private OriginatorIdentifierOrKey(
+			Asn1TaggedObject id)
+		{
+			// TODO Add validation
+			this.id = id;
+		}
+
+		/**
+         * return an OriginatorIdentifierOrKey object from a tagged object.
+         *
+         * @param o the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OriginatorIdentifierOrKey GetInstance(
+            Asn1TaggedObject	o,
+            bool				explicitly)
+        {
+            if (!explicitly)
+            {
+                throw new ArgumentException(
+                        "Can't implicitly tag OriginatorIdentifierOrKey");
+            }
+
+			return GetInstance(o.GetObject());
+        }
+
+        /**
+         * return an OriginatorIdentifierOrKey object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OriginatorIdentifierOrKey GetInstance(
+            object o)
+        {
+            if (o == null || o is OriginatorIdentifierOrKey)
+                return (OriginatorIdentifierOrKey)o;
+
+			if (o is IssuerAndSerialNumber)
+				return new OriginatorIdentifierOrKey((IssuerAndSerialNumber)o);
+
+			if (o is SubjectKeyIdentifier)
+				return new OriginatorIdentifierOrKey((SubjectKeyIdentifier)o);
+
+			if (o is OriginatorPublicKey)
+				return new OriginatorIdentifierOrKey((OriginatorPublicKey)o);
+
+			if (o is Asn1TaggedObject)
+				return new OriginatorIdentifierOrKey((Asn1TaggedObject)o);
+
+			throw new ArgumentException("Invalid OriginatorIdentifierOrKey: " + o.GetType().Name);
+        }
+
+		public Asn1Encodable ID
+		{
+			get { return id; }
+		}
+
+		public IssuerAndSerialNumber IssuerAndSerialNumber
+		{
+			get
+			{
+				if (id is IssuerAndSerialNumber)
+				{
+					return (IssuerAndSerialNumber)id;
+				}
+
+				return null;
+			}
+		}
+
+		public SubjectKeyIdentifier SubjectKeyIdentifier
+		{
+			get
+			{
+				if (id is Asn1TaggedObject && ((Asn1TaggedObject)id).TagNo == 0)
+				{
+					return SubjectKeyIdentifier.GetInstance((Asn1TaggedObject)id, false);
+				}
+
+				return null;
+			}
+		}
+
+		[Obsolete("Use 'OriginatorPublicKey' property")]
+		public OriginatorPublicKey OriginatorKey
+		{
+			get { return OriginatorPublicKey; }
+		}
+
+		public OriginatorPublicKey OriginatorPublicKey
+		{
+			get
+			{
+				if (id is Asn1TaggedObject && ((Asn1TaggedObject)id).TagNo == 1)
+				{
+					return OriginatorPublicKey.GetInstance((Asn1TaggedObject)id, false);
+				}
+
+				return null;
+			}
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OriginatorIdentifierOrKey ::= CHOICE {
+         *     issuerAndSerialNumber IssuerAndSerialNumber,
+         *     subjectKeyIdentifier [0] SubjectKeyIdentifier,
+         *     originatorKey [1] OriginatorPublicKey
+         * }
+         *
+         * SubjectKeyIdentifier ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return id.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/OriginatorInfo.cs b/crypto/src/asn1/cms/OriginatorInfo.cs
new file mode 100644
index 000000000..b4549bc36
--- /dev/null
+++ b/crypto/src/asn1/cms/OriginatorInfo.cs
@@ -0,0 +1,121 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OriginatorInfo
+        : Asn1Encodable
+    {
+        private Asn1Set certs;
+        private Asn1Set crls;
+
+        public OriginatorInfo(
+            Asn1Set certs,
+            Asn1Set crls)
+        {
+            this.certs = certs;
+            this.crls = crls;
+        }
+
+		public OriginatorInfo(
+            Asn1Sequence seq)
+        {
+            switch (seq.Count)
+            {
+            case 0:     // empty
+                break;
+            case 1:
+                Asn1TaggedObject o = (Asn1TaggedObject) seq[0];
+                switch (o.TagNo)
+                {
+                case 0 :
+                    certs = Asn1Set.GetInstance(o, false);
+                    break;
+                case 1 :
+                    crls = Asn1Set.GetInstance(o, false);
+                    break;
+                default:
+                    throw new ArgumentException("Bad tag in OriginatorInfo: " + o.TagNo);
+                }
+                break;
+            case 2:
+                certs = Asn1Set.GetInstance((Asn1TaggedObject) seq[0], false);
+                crls  = Asn1Set.GetInstance((Asn1TaggedObject) seq[1], false);
+                break;
+            default:
+                throw new ArgumentException("OriginatorInfo too big");
+            }
+        }
+
+		/**
+         * return an OriginatorInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OriginatorInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return an OriginatorInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OriginatorInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is OriginatorInfo)
+                return (OriginatorInfo)obj;
+
+			if (obj is Asn1Sequence)
+                return new OriginatorInfo((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid OriginatorInfo: " + obj.GetType().Name);
+        }
+
+		public Asn1Set Certificates
+		{
+			get { return certs; }
+		}
+
+		public Asn1Set Crls
+		{
+			get { return crls; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OriginatorInfo ::= Sequence {
+         *     certs [0] IMPLICIT CertificateSet OPTIONAL,
+         *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (certs != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, certs));
+            }
+
+			if (crls != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, crls));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/OriginatorPublicKey.cs b/crypto/src/asn1/cms/OriginatorPublicKey.cs
new file mode 100644
index 000000000..aabaf4386
--- /dev/null
+++ b/crypto/src/asn1/cms/OriginatorPublicKey.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OriginatorPublicKey
+        : Asn1Encodable
+    {
+        private AlgorithmIdentifier algorithm;
+        private DerBitString        publicKey;
+
+		public OriginatorPublicKey(
+            AlgorithmIdentifier algorithm,
+            byte[]              publicKey)
+        {
+            this.algorithm = algorithm;
+            this.publicKey = new DerBitString(publicKey);
+        }
+
+		public OriginatorPublicKey(
+            Asn1Sequence seq)
+        {
+            algorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+            publicKey = (DerBitString) seq[1];
+        }
+
+		/**
+         * return an OriginatorPublicKey object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OriginatorPublicKey GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return an OriginatorPublicKey object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OriginatorPublicKey GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is OriginatorPublicKey)
+                return (OriginatorPublicKey)obj;
+
+			if (obj is Asn1Sequence)
+                return new OriginatorPublicKey((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid OriginatorPublicKey: " + obj.GetType().Name);
+        }
+
+		public AlgorithmIdentifier Algorithm
+		{
+			get { return algorithm; }
+		}
+
+		public DerBitString PublicKey
+		{
+			get { return publicKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OriginatorPublicKey ::= Sequence {
+         *     algorithm AlgorithmIdentifier,
+         *     publicKey BIT STRING
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algorithm, publicKey);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/OtherKeyAttribute.cs b/crypto/src/asn1/cms/OtherKeyAttribute.cs
new file mode 100644
index 000000000..271059175
--- /dev/null
+++ b/crypto/src/asn1/cms/OtherKeyAttribute.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OtherKeyAttribute
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	keyAttrId;
+        private Asn1Encodable		keyAttr;
+
+		/**
+         * return an OtherKeyAttribute object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static OtherKeyAttribute GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is OtherKeyAttribute)
+                return (OtherKeyAttribute) obj;
+
+			if (obj is Asn1Sequence)
+                return new OtherKeyAttribute((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public OtherKeyAttribute(
+            Asn1Sequence seq)
+        {
+            keyAttrId = (DerObjectIdentifier) seq[0];
+            keyAttr = seq[1];
+        }
+
+		public OtherKeyAttribute(
+            DerObjectIdentifier	keyAttrId,
+            Asn1Encodable		keyAttr)
+        {
+            this.keyAttrId = keyAttrId;
+            this.keyAttr = keyAttr;
+        }
+
+		public DerObjectIdentifier KeyAttrId
+		{
+			get { return keyAttrId; }
+		}
+
+		public Asn1Encodable KeyAttr
+		{
+			get { return keyAttr; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OtherKeyAttribute ::= Sequence {
+         *     keyAttrId OBJECT IDENTIFIER,
+         *     keyAttr ANY DEFINED BY keyAttrId OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(keyAttrId, keyAttr);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/OtherRecipientInfo.cs b/crypto/src/asn1/cms/OtherRecipientInfo.cs
index 8b06b1946..80dd68e7c 100644
--- a/crypto/src/asn1/cms/OtherRecipientInfo.cs
+++ b/crypto/src/asn1/cms/OtherRecipientInfo.cs
@@ -1,16 +1,14 @@
 using System;
 
-using Org.BouncyCastle.Asn1;
-
 namespace Org.BouncyCastle.Asn1.Cms
 {
     public class OtherRecipientInfo
         : Asn1Encodable
     {
-        private DerObjectIdentifier	oriType;
-        private Asn1Encodable		oriValue;
+        private readonly DerObjectIdentifier oriType;
+        private readonly Asn1Encodable oriValue;
 
-		public OtherRecipientInfo(
+        public OtherRecipientInfo(
             DerObjectIdentifier	oriType,
             Asn1Encodable		oriValue)
         {
@@ -18,14 +16,15 @@ namespace Org.BouncyCastle.Asn1.Cms
             this.oriValue = oriValue;
         }
 
-		public OtherRecipientInfo(
+        [Obsolete("Use GetInstance() instead")]
+        public OtherRecipientInfo(
             Asn1Sequence seq)
         {
             oriType = DerObjectIdentifier.GetInstance(seq[0]);
             oriValue = seq[1];
-		}
+        }
 
-		/**
+        /**
          * return a OtherRecipientInfo object from a tagged object.
          *
          * @param obj the tagged object holding the object we want.
@@ -41,7 +40,7 @@ namespace Org.BouncyCastle.Asn1.Cms
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		/**
+        /**
          * return a OtherRecipientInfo object from the given object.
          *
          * @param obj the object we want converted.
@@ -50,26 +49,25 @@ namespace Org.BouncyCastle.Asn1.Cms
         public static OtherRecipientInfo GetInstance(
             object obj)
         {
-            if (obj == null || obj is OtherRecipientInfo)
-                return (OtherRecipientInfo)obj;
-
-			if (obj is Asn1Sequence)
-                return new OtherRecipientInfo((Asn1Sequence)obj);
-
-			throw new ArgumentException("Invalid OtherRecipientInfo: " + obj.GetType().Name);
+            if (obj == null)
+                return null;
+            OtherRecipientInfo existing = obj as OtherRecipientInfo;
+            if (existing != null)
+                return existing;
+            return new OtherRecipientInfo(Asn1Sequence.GetInstance(obj));
         }
 
-		public DerObjectIdentifier OriType
-		{
-			get { return oriType; }
-		}
+        public virtual DerObjectIdentifier OriType
+        {
+            get { return oriType; }
+        }
 
-		public Asn1Encodable OriValue
-		{
-			get { return oriValue; }
-		}
+        public virtual Asn1Encodable OriValue
+        {
+            get { return oriValue; }
+        }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          * OtherRecipientInfo ::= Sequence {
@@ -79,7 +77,7 @@ namespace Org.BouncyCastle.Asn1.Cms
          */
         public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(oriType, oriValue);
+            return new DerSequence(oriType, oriValue);
         }
     }
 }
diff --git a/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs
new file mode 100644
index 000000000..78354896f
--- /dev/null
+++ b/crypto/src/asn1/cms/OtherRevocationInfoFormat.cs
@@ -0,0 +1,77 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OtherRevocationInfoFormat
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier otherRevInfoFormat;
+        private readonly Asn1Encodable otherRevInfo;
+
+        public OtherRevocationInfoFormat(
+            DerObjectIdentifier otherRevInfoFormat,
+            Asn1Encodable otherRevInfo)
+        {
+            this.otherRevInfoFormat = otherRevInfoFormat;
+            this.otherRevInfo = otherRevInfo;
+        }
+
+        private OtherRevocationInfoFormat(Asn1Sequence seq)
+        {
+            otherRevInfoFormat = DerObjectIdentifier.GetInstance(seq[0]);
+            otherRevInfo = seq[1];
+        }
+
+        /**
+         * return a OtherRevocationInfoFormat 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 object held by the
+         *          tagged object cannot be converted.
+         */
+        public static OtherRevocationInfoFormat GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * return a OtherRevocationInfoFormat object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception IllegalArgumentException if the object cannot be converted.
+         */
+        public static OtherRevocationInfoFormat GetInstance(object obj)
+        {
+            if (obj is OtherRevocationInfoFormat)
+                return (OtherRevocationInfoFormat)obj;
+            if (obj != null)
+                return new OtherRevocationInfoFormat(Asn1Sequence.GetInstance(obj));
+            return null;
+        }
+
+        public virtual DerObjectIdentifier InfoFormat
+        {
+            get { return otherRevInfoFormat; }
+        }
+
+        public virtual Asn1Encodable Info
+        {
+            get { return otherRevInfo; }
+        }
+
+        /** 
+         * Produce an object suitable for an ASN1OutputStream.
+         * <pre>
+         * OtherRevocationInfoFormat ::= SEQUENCE {
+         *      otherRevInfoFormat OBJECT IDENTIFIER,
+         *      otherRevInfo ANY DEFINED BY otherRevInfoFormat }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(otherRevInfoFormat, otherRevInfo);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/PasswordRecipientInfo.cs b/crypto/src/asn1/cms/PasswordRecipientInfo.cs
new file mode 100644
index 000000000..800b57951
--- /dev/null
+++ b/crypto/src/asn1/cms/PasswordRecipientInfo.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class PasswordRecipientInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger				version;
+        private readonly AlgorithmIdentifier	keyDerivationAlgorithm;
+        private readonly AlgorithmIdentifier	keyEncryptionAlgorithm;
+        private readonly Asn1OctetString		encryptedKey;
+
+		public PasswordRecipientInfo(
+            AlgorithmIdentifier	keyEncryptionAlgorithm,
+            Asn1OctetString		encryptedKey)
+        {
+            this.version = new DerInteger(0);
+            this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+            this.encryptedKey = encryptedKey;
+        }
+
+		public PasswordRecipientInfo(
+			AlgorithmIdentifier	keyDerivationAlgorithm,
+			AlgorithmIdentifier	keyEncryptionAlgorithm,
+			Asn1OctetString		encryptedKey)
+		{
+			this.version = new DerInteger(0);
+			this.keyDerivationAlgorithm = keyDerivationAlgorithm;
+			this.keyEncryptionAlgorithm = keyEncryptionAlgorithm;
+			this.encryptedKey = encryptedKey;
+		}
+
+		public PasswordRecipientInfo(
+            Asn1Sequence seq)
+        {
+            version = (DerInteger) seq[0];
+
+			if (seq[1] is Asn1TaggedObject)
+            {
+                keyDerivationAlgorithm = AlgorithmIdentifier.GetInstance((Asn1TaggedObject) seq[1], false);
+                keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[2]);
+                encryptedKey = (Asn1OctetString) seq[3];
+            }
+            else
+            {
+                keyEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+                encryptedKey = (Asn1OctetString) seq[2];
+            }
+        }
+
+		/**
+         * return a PasswordRecipientInfo object from a tagged object.
+         *
+         * @param obj the tagged object holding the object we want.
+         * @param explicitly true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static PasswordRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return a PasswordRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static PasswordRecipientInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is PasswordRecipientInfo)
+                return (PasswordRecipientInfo) obj;
+
+			if (obj is Asn1Sequence)
+                return new PasswordRecipientInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid PasswordRecipientInfo: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public AlgorithmIdentifier KeyDerivationAlgorithm
+		{
+			get { return keyDerivationAlgorithm; }
+		}
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithm
+		{
+			get { return keyEncryptionAlgorithm; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * PasswordRecipientInfo ::= Sequence {
+         *   version CMSVersion,   -- Always set to 0
+         *   keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier
+         *                             OPTIONAL,
+         *  keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+         *  encryptedKey EncryptedKey }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (keyDerivationAlgorithm != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, keyDerivationAlgorithm));
+            }
+
+			v.Add(keyEncryptionAlgorithm, encryptedKey);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/RecipientEncryptedKey.cs b/crypto/src/asn1/cms/RecipientEncryptedKey.cs
new file mode 100644
index 000000000..5ba25a742
--- /dev/null
+++ b/crypto/src/asn1/cms/RecipientEncryptedKey.cs
@@ -0,0 +1,88 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class RecipientEncryptedKey
+		: Asn1Encodable
+	{
+		private readonly KeyAgreeRecipientIdentifier identifier;
+		private readonly Asn1OctetString encryptedKey;
+
+		private RecipientEncryptedKey(
+			Asn1Sequence seq)
+		{
+			identifier = KeyAgreeRecipientIdentifier.GetInstance(seq[0]);
+			encryptedKey = (Asn1OctetString) seq[1];
+		}
+
+		/**
+		 * return an RecipientEncryptedKey object from a tagged object.
+		 *
+		 * @param obj the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *              tagged false otherwise.
+		 * @exception ArgumentException if the object held by the
+		 *          tagged object cannot be converted.
+		 */
+		public static RecipientEncryptedKey GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return a RecipientEncryptedKey object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @exception ArgumentException if the object cannot be converted.
+		 */
+		public static RecipientEncryptedKey GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RecipientEncryptedKey)
+			{
+				return (RecipientEncryptedKey) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RecipientEncryptedKey((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Invalid RecipientEncryptedKey: " + obj.GetType().FullName, "obj");
+		}
+
+		public RecipientEncryptedKey(
+			KeyAgreeRecipientIdentifier	id,
+			Asn1OctetString				encryptedKey)
+		{
+			this.identifier = id;
+			this.encryptedKey = encryptedKey;
+		}
+
+		public KeyAgreeRecipientIdentifier Identifier
+		{
+			get { return identifier; }
+		}
+
+		public Asn1OctetString EncryptedKey
+		{
+			get { return encryptedKey; }
+		}
+
+		/** 
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * RecipientEncryptedKey ::= SEQUENCE {
+		 *     rid KeyAgreeRecipientIdentifier,
+		 *     encryptedKey EncryptedKey
+		 * }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(identifier, encryptedKey);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/RecipientIdentifier.cs b/crypto/src/asn1/cms/RecipientIdentifier.cs
new file mode 100644
index 000000000..4982bc16a
--- /dev/null
+++ b/crypto/src/asn1/cms/RecipientIdentifier.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class RecipientIdentifier
+        : Asn1Encodable, IAsn1Choice
+    {
+        private Asn1Encodable id;
+
+		public RecipientIdentifier(
+            IssuerAndSerialNumber id)
+        {
+            this.id = id;
+        }
+
+		public RecipientIdentifier(
+            Asn1OctetString id)
+        {
+            this.id = new DerTaggedObject(false, 0, id);
+        }
+
+		public RecipientIdentifier(
+            Asn1Object id)
+        {
+            this.id = id;
+        }
+
+		/**
+         * return a RecipientIdentifier object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static RecipientIdentifier GetInstance(
+            object o)
+        {
+            if (o == null || o is RecipientIdentifier)
+                return (RecipientIdentifier)o;
+
+			if (o is IssuerAndSerialNumber)
+                return new RecipientIdentifier((IssuerAndSerialNumber) o);
+
+			if (o is Asn1OctetString)
+                return new RecipientIdentifier((Asn1OctetString) o);
+
+			if (o is Asn1Object)
+                return new RecipientIdentifier((Asn1Object) o);
+
+			throw new ArgumentException(
+              "Illegal object in RecipientIdentifier: " + o.GetType().Name);
+        }
+
+		public bool IsTagged
+		{
+			get { return (id is Asn1TaggedObject); }
+		}
+
+		public Asn1Encodable ID
+        {
+            get
+            {
+                if (id is Asn1TaggedObject)
+                {
+                    return Asn1OctetString.GetInstance((Asn1TaggedObject) id, false);
+                }
+
+				return IssuerAndSerialNumber.GetInstance(id);
+            }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RecipientIdentifier ::= CHOICE {
+         *     issuerAndSerialNumber IssuerAndSerialNumber,
+         *     subjectKeyIdentifier [0] SubjectKeyIdentifier
+         * }
+         *
+         * SubjectKeyIdentifier ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return id.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/RecipientInfo.cs b/crypto/src/asn1/cms/RecipientInfo.cs
new file mode 100644
index 000000000..daaf5a5e4
--- /dev/null
+++ b/crypto/src/asn1/cms/RecipientInfo.cs
@@ -0,0 +1,145 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class RecipientInfo
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal Asn1Encodable info;
+
+		public RecipientInfo(
+            KeyTransRecipientInfo info)
+        {
+            this.info = info;
+        }
+
+		public RecipientInfo(
+            KeyAgreeRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 1, info);
+        }
+
+		public RecipientInfo(
+            KekRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 2, info);
+        }
+
+		public RecipientInfo(
+            PasswordRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 3, info);
+        }
+
+		public RecipientInfo(
+            OtherRecipientInfo info)
+        {
+            this.info = new DerTaggedObject(false, 4, info);
+        }
+
+		public RecipientInfo(
+            Asn1Object   info)
+        {
+            this.info = info;
+        }
+
+		public static RecipientInfo GetInstance(
+            object o)
+        {
+            if (o == null || o is RecipientInfo)
+                return (RecipientInfo) o;
+
+			if (o is Asn1Sequence)
+                return new RecipientInfo((Asn1Sequence) o);
+
+			if (o is Asn1TaggedObject)
+                return new RecipientInfo((Asn1TaggedObject) o);
+
+			throw new ArgumentException("unknown object in factory: " + o.GetType().Name);
+        }
+
+		public DerInteger Version
+        {
+			get
+			{
+				if (info is Asn1TaggedObject)
+				{
+					Asn1TaggedObject o = (Asn1TaggedObject) info;
+
+					switch (o.TagNo)
+					{
+						case 1:
+							return KeyAgreeRecipientInfo.GetInstance(o, false).Version;
+						case 2:
+							return GetKekInfo(o).Version;
+						case 3:
+							return PasswordRecipientInfo.GetInstance(o, false).Version;
+						case 4:
+							return new DerInteger(0);    // no syntax version for OtherRecipientInfo
+						default:
+							throw new InvalidOperationException("unknown tag");
+					}
+				}
+
+				return KeyTransRecipientInfo.GetInstance(info).Version;
+			}
+        }
+
+		public bool IsTagged
+		{
+			get { return info is Asn1TaggedObject; }
+		}
+
+		public Asn1Encodable Info
+        {
+			get
+			{
+				if (info is Asn1TaggedObject)
+				{
+					Asn1TaggedObject o = (Asn1TaggedObject) info;
+
+					switch (o.TagNo)
+					{
+						case 1:
+							return KeyAgreeRecipientInfo.GetInstance(o, false);
+						case 2:
+							return GetKekInfo(o);
+						case 3:
+							return PasswordRecipientInfo.GetInstance(o, false);
+						case 4:
+							return OtherRecipientInfo.GetInstance(o, false);
+						default:
+							throw new InvalidOperationException("unknown tag");
+					}
+				}
+
+				return KeyTransRecipientInfo.GetInstance(info);
+			}
+        }
+
+		private KekRecipientInfo GetKekInfo(
+			Asn1TaggedObject o)
+		{
+			// For compatibility with erroneous version, we don't always pass 'false' here
+			return KekRecipientInfo.GetInstance(o, o.IsExplicit());
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RecipientInfo ::= CHOICE {
+         *     ktri KeyTransRecipientInfo,
+         *     kari [1] KeyAgreeRecipientInfo,
+         *     kekri [2] KekRecipientInfo,
+         *     pwri [3] PasswordRecipientInfo,
+         *     ori [4] OtherRecipientInfo }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return info.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/RecipientKeyIdentifier.cs b/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
new file mode 100644
index 000000000..f3e45644b
--- /dev/null
+++ b/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
@@ -0,0 +1,137 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class RecipientKeyIdentifier
+        : Asn1Encodable
+    {
+        private Asn1OctetString      subjectKeyIdentifier;
+        private DerGeneralizedTime   date;
+        private OtherKeyAttribute    other;
+
+		public RecipientKeyIdentifier(
+            Asn1OctetString         subjectKeyIdentifier,
+            DerGeneralizedTime      date,
+            OtherKeyAttribute       other)
+        {
+            this.subjectKeyIdentifier = subjectKeyIdentifier;
+            this.date = date;
+            this.other = other;
+        }
+		
+		public RecipientKeyIdentifier(
+			byte[] subjectKeyIdentifier)
+			: this(subjectKeyIdentifier, null, null)
+		{
+		}
+
+		public RecipientKeyIdentifier(
+			byte[]				subjectKeyIdentifier,
+			DerGeneralizedTime	date,
+			OtherKeyAttribute	other)
+		{
+			this.subjectKeyIdentifier = new DerOctetString(subjectKeyIdentifier);
+			this.date = date;
+			this.other = other;
+		}
+
+		public RecipientKeyIdentifier(
+            Asn1Sequence seq)
+        {
+            subjectKeyIdentifier = Asn1OctetString.GetInstance(
+				seq[0]);
+
+			switch(seq.Count)
+            {
+				case 1:
+					break;
+				case 2:
+					if (seq[1] is DerGeneralizedTime)
+					{
+						date = (DerGeneralizedTime) seq[1];
+					}
+					else
+					{
+						other = OtherKeyAttribute.GetInstance(seq[2]);
+					}
+					break;
+				case 3:
+					date  = (DerGeneralizedTime) seq[1];
+					other = OtherKeyAttribute.GetInstance(seq[2]);
+					break;
+				default:
+					throw new ArgumentException("Invalid RecipientKeyIdentifier");
+            }
+        }
+
+		/**
+         * return a RecipientKeyIdentifier object from a tagged object.
+         *
+         * @param _ato the tagged object holding the object we want.
+         * @param _explicit true if the object is meant to be explicitly
+         *              tagged false otherwise.
+         * @exception ArgumentException if the object held by the
+         *          tagged object cannot be converted.
+         */
+        public static RecipientKeyIdentifier GetInstance(
+			Asn1TaggedObject	ato,
+			bool				explicitly)
+		{
+            return GetInstance(Asn1Sequence.GetInstance(ato, explicitly));
+        }
+
+		/**
+         * return a RecipientKeyIdentifier object from the given object.
+         *
+         * @param _obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static RecipientKeyIdentifier GetInstance(
+			object obj)
+		{
+            if (obj == null || obj is RecipientKeyIdentifier)
+                return (RecipientKeyIdentifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new RecipientKeyIdentifier((Asn1Sequence) obj);
+
+			throw new ArgumentException("Invalid RecipientKeyIdentifier: " + obj.GetType().Name);
+        }
+
+		public Asn1OctetString SubjectKeyIdentifier
+		{
+			get { return subjectKeyIdentifier; }
+		}
+
+		public DerGeneralizedTime Date
+		{
+			get { return date; }
+		}
+
+		public OtherKeyAttribute OtherKeyAttribute
+		{
+			get { return other; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RecipientKeyIdentifier ::= Sequence {
+         *     subjectKeyIdentifier SubjectKeyIdentifier,
+         *     date GeneralizedTime OPTIONAL,
+         *     other OtherKeyAttribute OPTIONAL
+         * }
+         *
+         * SubjectKeyIdentifier ::= OCTET STRING
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(subjectKeyIdentifier);
+			v.AddOptional(date, other);
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/SCVPReqRes.cs b/crypto/src/asn1/cms/SCVPReqRes.cs
new file mode 100644
index 000000000..486979a29
--- /dev/null
+++ b/crypto/src/asn1/cms/SCVPReqRes.cs
@@ -0,0 +1,77 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class ScvpReqRes
+        : Asn1Encodable
+    {
+        private readonly ContentInfo request;
+        private readonly ContentInfo response;
+
+        public static ScvpReqRes GetInstance(object  obj)
+        {
+            if (obj is ScvpReqRes)
+                return (ScvpReqRes)obj;
+            if (obj != null)
+                return new ScvpReqRes(Asn1Sequence.GetInstance(obj));
+            return null;
+        }
+
+        private ScvpReqRes(Asn1Sequence seq)
+        {
+            if (seq[0] is Asn1TaggedObject)
+            {
+                this.request = ContentInfo.GetInstance(Asn1TaggedObject.GetInstance(seq[0]), true);
+                this.response = ContentInfo.GetInstance(seq[1]);
+            }
+            else
+            {
+                this.request = null;
+                this.response = ContentInfo.GetInstance(seq[0]);
+            }
+        }
+
+        public ScvpReqRes(ContentInfo response)
+            : this(null, response)
+        {
+        }
+
+        public ScvpReqRes(ContentInfo request, ContentInfo response)
+        {
+            this.request = request;
+            this.response = response;
+        }
+
+        public virtual ContentInfo Request
+        {
+            get { return request; }
+        }
+
+        public virtual ContentInfo Response
+        {
+            get { return response; }
+        }
+
+        /**
+         * <pre>
+         *    ScvpReqRes ::= SEQUENCE {
+         *    request  [0] EXPLICIT ContentInfo OPTIONAL,
+         *    response     ContentInfo }
+         * </pre>
+         * @return  the ASN.1 primitive representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (request != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, request));
+            }
+
+            v.Add(response);
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/SignedData.cs b/crypto/src/asn1/cms/SignedData.cs
index 40ed09f32..6cea79a49 100644
--- a/crypto/src/asn1/cms/SignedData.cs
+++ b/crypto/src/asn1/cms/SignedData.cs
@@ -11,6 +11,11 @@ namespace Org.BouncyCastle.Asn1.Cms
     public class SignedData
         : Asn1Encodable
     {
+        private static readonly DerInteger Version1 = new DerInteger(1);
+        private static readonly DerInteger Version3 = new DerInteger(3);
+        private static readonly DerInteger Version4 = new DerInteger(4);
+        private static readonly DerInteger Version5 = new DerInteger(5);
+
         private readonly DerInteger		version;
         private readonly Asn1Set		digestAlgorithms;
         private readonly ContentInfo	contentInfo;
@@ -20,159 +25,159 @@ namespace Org.BouncyCastle.Asn1.Cms
         private readonly bool			certsBer;
         private readonly bool		    crlsBer;
 
-		public static SignedData GetInstance(
+        public static SignedData GetInstance(
             object obj)
         {
             if (obj is SignedData)
                 return (SignedData) obj;
 
-			if (obj is Asn1Sequence)
+            if (obj is Asn1Sequence)
                 return new SignedData((Asn1Sequence) obj);
 
-			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
-		}
-
-		public SignedData(
-			Asn1Set     digestAlgorithms,
-			ContentInfo contentInfo,
-			Asn1Set     certificates,
-			Asn1Set     crls,
-			Asn1Set     signerInfos)
-		{
-			this.version = CalculateVersion(contentInfo.ContentType, certificates, crls, signerInfos);
-			this.digestAlgorithms = digestAlgorithms;
-			this.contentInfo = contentInfo;
-			this.certificates = certificates;
-			this.crls = crls;
-			this.signerInfos = signerInfos;
-			this.crlsBer = crls is BerSet;
-			this.certsBer = certificates is 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 DerInteger CalculateVersion(
-			DerObjectIdentifier	contentOid,
-			Asn1Set				certs,
-			Asn1Set				crls,
-			Asn1Set				signerInfs)
-		{
-			bool otherCert = false;
-			bool otherCrl = false;
-			bool attrCertV1Found = false;
-			bool attrCertV2Found = false;
-
-			if (certs != null)
-			{
-				foreach (object obj in certs)
-				{
-					if (obj is Asn1TaggedObject)
-					{
-						Asn1TaggedObject tagged = (Asn1TaggedObject)obj;
-
-						if (tagged.TagNo == 1)
-						{
-							attrCertV1Found = true;
-						}
-						else if (tagged.TagNo == 2)
-						{
-							attrCertV2Found = true;
-						}
-						else if (tagged.TagNo == 3)
-						{
-							otherCert = true;
-							break;
-						}
-					}
-				}
-			}
-
-			if (otherCert)
-			{
-				return new DerInteger(5);
-			}
-
-			if (crls != null)
-			{
-				foreach (object obj in crls)
-				{
-					if (obj is Asn1TaggedObject)
-					{
-						otherCrl = true;
-						break;
-					}
-				}
-			}
-
-			if (otherCrl)
-			{
-				return new DerInteger(5);
-			}
-
-			if (attrCertV2Found)
-			{
-				return new DerInteger(4);
-			}
-
-			if (attrCertV1Found || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(signerInfs))
-			{
-				return new DerInteger(3);
-			}
-
-            return new DerInteger(1);
-		}
-
-		private bool CheckForVersion3(
-			Asn1Set signerInfs)
-		{
-			foreach (object obj in signerInfs)
-			{
-				SignerInfo s = SignerInfo.GetInstance(obj);
-
-				if (s.Version.Value.IntValue == 3)
-				{
-					return true;
-				}
-			}
-
-			return false;
-		}
-
-		private SignedData(
+            throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+        }
+
+        public SignedData(
+            Asn1Set     digestAlgorithms,
+            ContentInfo contentInfo,
+            Asn1Set     certificates,
+            Asn1Set     crls,
+            Asn1Set     signerInfos)
+        {
+            this.version = CalculateVersion(contentInfo.ContentType, certificates, crls, signerInfos);
+            this.digestAlgorithms = digestAlgorithms;
+            this.contentInfo = contentInfo;
+            this.certificates = certificates;
+            this.crls = crls;
+            this.signerInfos = signerInfos;
+            this.crlsBer = crls is BerSet;
+            this.certsBer = certificates is 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 DerInteger CalculateVersion(
+            DerObjectIdentifier	contentOid,
+            Asn1Set				certs,
+            Asn1Set				crls,
+            Asn1Set				signerInfs)
+        {
+            bool otherCert = false;
+            bool otherCrl = false;
+            bool attrCertV1Found = false;
+            bool attrCertV2Found = false;
+
+            if (certs != null)
+            {
+                foreach (object obj in certs)
+                {
+                    if (obj is Asn1TaggedObject)
+                    {
+                        Asn1TaggedObject tagged = (Asn1TaggedObject)obj;
+
+                        if (tagged.TagNo == 1)
+                        {
+                            attrCertV1Found = true;
+                        }
+                        else if (tagged.TagNo == 2)
+                        {
+                            attrCertV2Found = true;
+                        }
+                        else if (tagged.TagNo == 3)
+                        {
+                            otherCert = true;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (otherCert)
+            {
+                return Version5;
+            }
+
+            if (crls != null)
+            {
+                foreach (object obj in crls)
+                {
+                    if (obj is Asn1TaggedObject)
+                    {
+                        otherCrl = true;
+                        break;
+                    }
+                }
+            }
+
+            if (otherCrl)
+            {
+                return Version5;
+            }
+
+            if (attrCertV2Found)
+            {
+                return Version4;
+            }
+
+            if (attrCertV1Found || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(signerInfs))
+            {
+                return Version3;
+            }
+
+            return Version1;
+        }
+
+        private bool CheckForVersion3(
+            Asn1Set signerInfs)
+        {
+            foreach (object obj in signerInfs)
+            {
+                SignerInfo s = SignerInfo.GetInstance(obj);
+
+                if (s.Version.Value.IntValue == 3)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private SignedData(
             Asn1Sequence seq)
         {
             IEnumerator e = seq.GetEnumerator();
 
-			e.MoveNext();
+            e.MoveNext();
             version = (DerInteger)e.Current;
 
-			e.MoveNext();
+            e.MoveNext();
             digestAlgorithms = ((Asn1Set)e.Current);
 
-			e.MoveNext();
+            e.MoveNext();
             contentInfo = ContentInfo.GetInstance(e.Current);
 
-			while (e.MoveNext())
+            while (e.MoveNext())
             {
                 Asn1Object o = (Asn1Object)e.Current;
 
-				//
+                //
                 // an interesting feature of SignedData is that there appear
                 // to be varying implementations...
                 // for the moment we ignore anything which doesn't fit.
@@ -183,16 +188,16 @@ namespace Org.BouncyCastle.Asn1.Cms
 
                     switch (tagged.TagNo)
                     {
-						case 0:
-							certsBer = tagged is BerTaggedObject;
-							certificates = Asn1Set.GetInstance(tagged, false);
-							break;
-						case 1:
-							crlsBer = tagged is BerTaggedObject;
-							crls = Asn1Set.GetInstance(tagged, false);
-							break;
-						default:
-							throw new ArgumentException("unknown tag value " + tagged.TagNo);
+                        case 0:
+                            certsBer = tagged is BerTaggedObject;
+                            certificates = Asn1Set.GetInstance(tagged, false);
+                            break;
+                        case 1:
+                            crlsBer = tagged is BerTaggedObject;
+                            crls = Asn1Set.GetInstance(tagged, false);
+                            break;
+                        default:
+                            throw new ArgumentException("unknown tag value " + tagged.TagNo);
                     }
                 }
                 else
@@ -202,37 +207,37 @@ namespace Org.BouncyCastle.Asn1.Cms
             }
         }
 
-		public DerInteger Version
-		{
-			get { return version; }
-		}
-
-		public Asn1Set DigestAlgorithms
-		{
-			get { return digestAlgorithms; }
-		}
-
-		public ContentInfo EncapContentInfo
-		{
-			get { return contentInfo; }
-		}
-
-		public Asn1Set Certificates
-		{
-			get { return certificates; }
-		}
-
-		public Asn1Set CRLs
-		{
-			get { return crls; }
-		}
-
-		public Asn1Set SignerInfos
-		{
-			get { return signerInfos; }
-		}
-
-		/**
+        public DerInteger Version
+        {
+            get { return version; }
+        }
+
+        public Asn1Set DigestAlgorithms
+        {
+            get { return digestAlgorithms; }
+        }
+
+        public ContentInfo EncapContentInfo
+        {
+            get { return contentInfo; }
+        }
+
+        public Asn1Set Certificates
+        {
+            get { return certificates; }
+        }
+
+        public Asn1Set CRLs
+        {
+            get { return crls; }
+        }
+
+        public Asn1Set SignerInfos
+        {
+            get { return signerInfos; }
+        }
+
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          * SignedData ::= Sequence {
@@ -248,9 +253,9 @@ namespace Org.BouncyCastle.Asn1.Cms
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(
-				version, digestAlgorithms, contentInfo);
+                version, digestAlgorithms, contentInfo);
 
-			if (certificates != null)
+            if (certificates != null)
             {
                 if (certsBer)
                 {
@@ -262,7 +267,7 @@ namespace Org.BouncyCastle.Asn1.Cms
                 }
             }
 
-			if (crls != null)
+            if (crls != null)
             {
                 if (crlsBer)
                 {
@@ -274,9 +279,9 @@ namespace Org.BouncyCastle.Asn1.Cms
                 }
             }
 
-			v.Add(signerInfos);
+            v.Add(signerInfos);
 
-			return new BerSequence(v);
+            return new BerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/cms/SignedDataParser.cs b/crypto/src/asn1/cms/SignedDataParser.cs
new file mode 100644
index 000000000..341309263
--- /dev/null
+++ b/crypto/src/asn1/cms/SignedDataParser.cs
@@ -0,0 +1,112 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	/**
+	* <pre>
+	* SignedData ::= SEQUENCE {
+	*     version CMSVersion,
+	*     digestAlgorithms DigestAlgorithmIdentifiers,
+	*     encapContentInfo EncapsulatedContentInfo,
+	*     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+	*     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+	*     signerInfos SignerInfos
+	*   }
+	* </pre>
+	*/
+	public class SignedDataParser
+	{
+		private Asn1SequenceParser	_seq;
+		private DerInteger			_version;
+		private object				_nextObject;
+		private bool				_certsCalled;
+		private bool				_crlsCalled;
+
+		public static SignedDataParser GetInstance(
+			object o)
+		{
+			if (o is Asn1Sequence)
+				return new SignedDataParser(((Asn1Sequence)o).Parser);
+
+			if (o is Asn1SequenceParser)
+				return new SignedDataParser((Asn1SequenceParser)o);
+
+			throw new IOException("unknown object encountered: " + o.GetType().Name);
+		}
+
+		public SignedDataParser(
+			Asn1SequenceParser seq)
+		{
+			this._seq = seq;
+			this._version = (DerInteger)seq.ReadObject();
+		}
+
+		public DerInteger Version
+		{
+			get { return _version; }
+		}
+
+		public Asn1SetParser GetDigestAlgorithms()
+		{
+			return (Asn1SetParser)_seq.ReadObject();
+		}
+
+		public ContentInfoParser GetEncapContentInfo()
+		{
+			return new ContentInfoParser((Asn1SequenceParser)_seq.ReadObject());
+		}
+
+		public Asn1SetParser GetCertificates()
+		{
+			_certsCalled = true;
+			_nextObject = _seq.ReadObject();
+
+			if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 0)
+			{
+				Asn1SetParser certs = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false);
+				_nextObject = null;
+
+				return certs;
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetCrls()
+		{
+			if (!_certsCalled)
+				throw new IOException("GetCerts() has not been called.");
+
+			_crlsCalled = true;
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			if (_nextObject is Asn1TaggedObjectParser && ((Asn1TaggedObjectParser)_nextObject).TagNo == 1)
+			{
+				Asn1SetParser crls = (Asn1SetParser)((Asn1TaggedObjectParser)_nextObject).GetObjectParser(Asn1Tags.Set, false);
+				_nextObject = null;
+
+				return crls;
+			}
+
+			return null;
+		}
+
+		public Asn1SetParser GetSignerInfos()
+		{
+			if (!_certsCalled || !_crlsCalled)
+				throw new IOException("GetCerts() and/or GetCrls() has not been called.");
+
+			if (_nextObject == null)
+			{
+				_nextObject = _seq.ReadObject();
+			}
+
+			return (Asn1SetParser)_nextObject;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/SignerIdentifier.cs b/crypto/src/asn1/cms/SignerIdentifier.cs
new file mode 100644
index 000000000..5742cee75
--- /dev/null
+++ b/crypto/src/asn1/cms/SignerIdentifier.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class SignerIdentifier
+        : Asn1Encodable, IAsn1Choice
+    {
+        private Asn1Encodable id;
+
+		public SignerIdentifier(
+            IssuerAndSerialNumber id)
+        {
+            this.id = id;
+        }
+
+		public SignerIdentifier(
+            Asn1OctetString id)
+        {
+            this.id = new DerTaggedObject(false, 0, id);
+        }
+
+		public SignerIdentifier(
+            Asn1Object id)
+        {
+            this.id = id;
+        }
+
+		/**
+         * return a SignerIdentifier object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static SignerIdentifier GetInstance(
+            object o)
+        {
+            if (o == null || o is SignerIdentifier)
+                return (SignerIdentifier) o;
+
+			if (o is IssuerAndSerialNumber)
+                return new SignerIdentifier((IssuerAndSerialNumber) o);
+
+			if (o is Asn1OctetString)
+                return new SignerIdentifier((Asn1OctetString) o);
+
+			if (o is Asn1Object)
+                return new SignerIdentifier((Asn1Object) o);
+
+			throw new ArgumentException(
+				"Illegal object in SignerIdentifier: " + o.GetType().Name);
+        }
+
+		public bool IsTagged
+		{
+			get { return (id is Asn1TaggedObject); }
+		}
+
+		public Asn1Encodable ID
+        {
+            get
+            {
+                if (id is 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 override Asn1Object ToAsn1Object()
+        {
+            return id.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/SignerInfo.cs b/crypto/src/asn1/cms/SignerInfo.cs
index ef71ddfc4..a4e893d96 100644
--- a/crypto/src/asn1/cms/SignerInfo.cs
+++ b/crypto/src/asn1/cms/SignerInfo.cs
@@ -23,13 +23,13 @@ namespace Org.BouncyCastle.Asn1.Cms
             if (obj == null || obj is SignerInfo)
                 return (SignerInfo) obj;
 
-			if (obj is Asn1Sequence)
+            if (obj is Asn1Sequence)
                 return new SignerInfo((Asn1Sequence) obj);
 
-			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
-		}
+            throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+        }
 
-		public SignerInfo(
+        public SignerInfo(
             SignerIdentifier        sid,
             AlgorithmIdentifier     digAlgorithm,
             Asn1Set                 authenticatedAttributes,
@@ -37,16 +37,8 @@ namespace Org.BouncyCastle.Asn1.Cms
             Asn1OctetString         encryptedDigest,
             Asn1Set                 unauthenticatedAttributes)
         {
-            if (sid.IsTagged)
-            {
-                this.version = new DerInteger(3);
-            }
-            else
-            {
-                this.version = new DerInteger(1);
-            }
-
-			this.sid = sid;
+            this.version = new DerInteger(sid.IsTagged ? 3 : 1);
+            this.sid = sid;
             this.digAlgorithm = digAlgorithm;
             this.authenticatedAttributes = authenticatedAttributes;
             this.digEncryptionAlgorithm = digEncryptionAlgorithm;
@@ -54,7 +46,25 @@ namespace Org.BouncyCastle.Asn1.Cms
             this.unauthenticatedAttributes = unauthenticatedAttributes;
         }
 
-		public SignerInfo(
+        public SignerInfo(
+            SignerIdentifier        sid,
+            AlgorithmIdentifier     digAlgorithm,
+            Attributes              authenticatedAttributes,
+            AlgorithmIdentifier     digEncryptionAlgorithm,
+            Asn1OctetString         encryptedDigest,
+            Attributes              unauthenticatedAttributes)
+        {
+            this.version = new DerInteger(sid.IsTagged ? 3 : 1);
+            this.sid = sid;
+            this.digAlgorithm = digAlgorithm;
+            this.authenticatedAttributes = Asn1Set.GetInstance(authenticatedAttributes);
+            this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+            this.encryptedDigest = encryptedDigest;
+            this.unauthenticatedAttributes = Asn1Set.GetInstance(unauthenticatedAttributes);
+        }
+
+        [Obsolete("Use 'GetInstance' instead")]
+        public SignerInfo(
             Asn1Sequence seq)
         {
             IEnumerator e = seq.GetEnumerator();
@@ -62,20 +72,20 @@ namespace Org.BouncyCastle.Asn1.Cms
             e.MoveNext();
             version = (DerInteger) e.Current;
 
-			e.MoveNext();
+            e.MoveNext();
             sid = SignerIdentifier.GetInstance(e.Current);
 
-			e.MoveNext();
+            e.MoveNext();
             digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
 
-			e.MoveNext();
+            e.MoveNext();
             object obj = e.Current;
 
-			if (obj is Asn1TaggedObject)
+            if (obj is Asn1TaggedObject)
             {
                 authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false);
 
-				e.MoveNext();
+                e.MoveNext();
                 digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
             }
             else
@@ -84,10 +94,10 @@ namespace Org.BouncyCastle.Asn1.Cms
                 digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj);
             }
 
-			e.MoveNext();
+            e.MoveNext();
             encryptedDigest = DerOctetString.GetInstance(e.Current);
 
-			if (e.MoveNext())
+            if (e.MoveNext())
             {
                 unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false);
             }
@@ -97,42 +107,42 @@ namespace Org.BouncyCastle.Asn1.Cms
             }
         }
 
-		public DerInteger Version
-		{
-			get { return version; }
-		}
-
-		public SignerIdentifier SignerID
-		{
-			get { return sid; }
-		}
-
-		public Asn1Set AuthenticatedAttributes
-		{
-			get { return authenticatedAttributes; }
-		}
-
-		public AlgorithmIdentifier DigestAlgorithm
-		{
-			get { return digAlgorithm; }
-		}
-
-		public Asn1OctetString EncryptedDigest
-		{
-			get { return encryptedDigest; }
-		}
-
-		public AlgorithmIdentifier DigestEncryptionAlgorithm
-		{
-			get { return digEncryptionAlgorithm; }
-		}
-
-		public Asn1Set UnauthenticatedAttributes
-		{
-			get { return unauthenticatedAttributes; }
-		}
-
-		/**
+        public DerInteger Version
+        {
+            get { return version; }
+        }
+
+        public SignerIdentifier SignerID
+        {
+            get { return sid; }
+        }
+
+        public Asn1Set AuthenticatedAttributes
+        {
+            get { return authenticatedAttributes; }
+        }
+
+        public AlgorithmIdentifier DigestAlgorithm
+        {
+            get { return digAlgorithm; }
+        }
+
+        public Asn1OctetString EncryptedDigest
+        {
+            get { return encryptedDigest; }
+        }
+
+        public AlgorithmIdentifier DigestEncryptionAlgorithm
+        {
+            get { return digEncryptionAlgorithm; }
+        }
+
+        public Asn1Set UnauthenticatedAttributes
+        {
+            get { return unauthenticatedAttributes; }
+        }
+
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  SignerInfo ::= Sequence {
@@ -155,21 +165,21 @@ namespace Org.BouncyCastle.Asn1.Cms
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(
-				version, sid, digAlgorithm);
+                version, sid, digAlgorithm);
 
-			if (authenticatedAttributes != null)
+            if (authenticatedAttributes != null)
             {
                 v.Add(new DerTaggedObject(false, 0, authenticatedAttributes));
             }
 
-			v.Add(digEncryptionAlgorithm, encryptedDigest);
+            v.Add(digEncryptionAlgorithm, encryptedDigest);
 
-			if (unauthenticatedAttributes != null)
+            if (unauthenticatedAttributes != null)
             {
                 v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes));
             }
 
-			return new DerSequence(v);
+            return new DerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/cms/Time.cs b/crypto/src/asn1/cms/Time.cs
new file mode 100644
index 000000000..d113bfa2e
--- /dev/null
+++ b/crypto/src/asn1/cms/Time.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class Time
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly Asn1Object time;
+
+		public static Time GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+		public Time(
+            Asn1Object time)
+        {
+            if (!(time is DerUtcTime)
+                && !(time is DerGeneralizedTime))
+            {
+                throw new ArgumentException("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(
+            DateTime date)
+        {
+            string d = date.ToString("yyyyMMddHHmmss") + "Z";
+
+			int year = int.Parse(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 is Time)
+                return (Time)obj;
+
+			if (obj is DerUtcTime)
+                return new Time((DerUtcTime)obj);
+
+			if (obj is DerGeneralizedTime)
+                return new Time((DerGeneralizedTime)obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public string TimeString
+        {
+			get
+			{
+				if (time is DerUtcTime)
+				{
+					return ((DerUtcTime)time).AdjustedTimeString;
+				}
+				else
+				{
+					return ((DerGeneralizedTime)time).GetTime();
+				}
+			}
+        }
+
+		public DateTime Date
+        {
+			get
+			{
+				try
+				{
+					if (time is DerUtcTime)
+					{
+						return ((DerUtcTime)time).ToAdjustedDateTime();
+					}
+
+					return ((DerGeneralizedTime)time).ToDateTime();
+				}
+				catch (FormatException e)
+				{
+					// this should never happen
+					throw new InvalidOperationException("invalid date string: " + e.Message);
+				}
+			}
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Time ::= CHOICE {
+         *             utcTime        UTCTime,
+         *             generalTime    GeneralizedTime }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return time;
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/TimeStampAndCRL.cs b/crypto/src/asn1/cms/TimeStampAndCRL.cs
new file mode 100644
index 000000000..4cb5f2a52
--- /dev/null
+++ b/crypto/src/asn1/cms/TimeStampAndCRL.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampAndCrl
+		: Asn1Encodable
+	{
+		private ContentInfo timeStamp;
+		private X509.CertificateList crl;
+
+		public TimeStampAndCrl(ContentInfo timeStamp)
+		{
+			this.timeStamp = timeStamp;
+		}
+
+		private TimeStampAndCrl(Asn1Sequence seq)
+		{
+			this.timeStamp = ContentInfo.GetInstance(seq[0]);
+			if (seq.Count == 2)
+			{
+				this.crl = X509.CertificateList.GetInstance(seq[1]);
+			}
+		}
+
+		public static TimeStampAndCrl GetInstance(object obj)
+		{
+			if (obj is TimeStampAndCrl)
+				return (TimeStampAndCrl)obj;
+
+			if (obj != null)
+				return new TimeStampAndCrl(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual ContentInfo TimeStampToken
+		{
+			get { return this.timeStamp; }
+		}
+
+		public virtual X509.CertificateList Crl
+		{
+			get { return this.crl; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampAndCRL ::= SEQUENCE {
+		 *     timeStamp   TimeStampToken,          -- according to RFC 3161
+		 *     crl         CertificateList OPTIONAL -- according to RFC 5280
+		 *  }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(timeStamp);
+			v.AddOptional(crl);
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/TimeStampTokenEvidence.cs b/crypto/src/asn1/cms/TimeStampTokenEvidence.cs
new file mode 100644
index 000000000..8625d058e
--- /dev/null
+++ b/crypto/src/asn1/cms/TimeStampTokenEvidence.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampTokenEvidence
+		: Asn1Encodable
+	{
+		private TimeStampAndCrl[] timeStampAndCrls;
+
+		public TimeStampTokenEvidence(TimeStampAndCrl[] timeStampAndCrls)
+		{
+			this.timeStampAndCrls = timeStampAndCrls;
+		}
+
+		public TimeStampTokenEvidence(TimeStampAndCrl timeStampAndCrl)
+		{
+			this.timeStampAndCrls = new TimeStampAndCrl[]{ timeStampAndCrl };
+		}
+
+		private TimeStampTokenEvidence(Asn1Sequence seq)
+		{
+			this.timeStampAndCrls = new TimeStampAndCrl[seq.Count];
+
+			int count = 0;
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				this.timeStampAndCrls[count++] = TimeStampAndCrl.GetInstance(ae.ToAsn1Object());
+			}
+		}
+
+		public static TimeStampTokenEvidence GetInstance(Asn1TaggedObject tagged, bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(tagged, isExplicit));
+		}
+
+		public static TimeStampTokenEvidence GetInstance(object obj)
+		{
+			if (obj is TimeStampTokenEvidence)
+				return (TimeStampTokenEvidence)obj;
+
+			if (obj != null)
+				return new TimeStampTokenEvidence(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual TimeStampAndCrl[] ToTimeStampAndCrlArray()
+		{
+			return (TimeStampAndCrl[])timeStampAndCrls.Clone();
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampTokenEvidence ::=
+		 *    SEQUENCE SIZE(1..MAX) OF TimeStampAndCrl
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(timeStampAndCrls);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/TimeStampedData.cs b/crypto/src/asn1/cms/TimeStampedData.cs
new file mode 100644
index 000000000..15448a923
--- /dev/null
+++ b/crypto/src/asn1/cms/TimeStampedData.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampedData
+		: Asn1Encodable
+	{
+		private DerInteger version;
+		private DerIA5String dataUri;
+		private MetaData metaData;
+		private Asn1OctetString content;
+		private Evidence temporalEvidence;
+
+		public TimeStampedData(DerIA5String dataUri, MetaData metaData, Asn1OctetString content,
+			Evidence temporalEvidence)
+		{
+			this.version = new DerInteger(1);
+			this.dataUri = dataUri;
+			this.metaData = metaData;
+			this.content = content;
+			this.temporalEvidence = temporalEvidence;
+		}
+
+		private TimeStampedData(Asn1Sequence seq)
+		{
+			this.version = DerInteger.GetInstance(seq[0]);
+			
+			int index = 1;
+			if (seq[index] is DerIA5String)
+			{
+				this.dataUri = DerIA5String.GetInstance(seq[index++]);
+			}
+			if (seq[index] is MetaData || seq[index] is Asn1Sequence)
+			{
+				this.metaData = MetaData.GetInstance(seq[index++]);
+			}
+			if (seq[index] is Asn1OctetString)
+			{
+				this.content = Asn1OctetString.GetInstance(seq[index++]);
+			}
+			this.temporalEvidence = Evidence.GetInstance(seq[index]);
+		}
+
+		public static TimeStampedData GetInstance(object obj)
+		{
+			if (obj is TimeStampedData)
+				return (TimeStampedData)obj;
+
+			if (obj != null)
+				return new TimeStampedData(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual DerIA5String DataUri
+		{
+			get { return dataUri; }
+		}
+
+		public MetaData MetaData
+		{
+			get { return metaData; }
+		}
+
+		public Asn1OctetString Content
+		{
+			get { return content; }
+		}
+
+		public Evidence TemporalEvidence
+		{
+			get { return temporalEvidence; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampedData ::= SEQUENCE {
+		 *   version              INTEGER { v1(1) },
+		 *   dataUri              IA5String OPTIONAL,
+		 *   metaData             MetaData OPTIONAL,
+		 *   content              OCTET STRING OPTIONAL,
+		 *   temporalEvidence     Evidence
+		 * }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(version);
+			v.AddOptional(dataUri, metaData, content);
+			v.Add(temporalEvidence);
+			return new BerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/TimeStampedDataParser.cs b/crypto/src/asn1/cms/TimeStampedDataParser.cs
new file mode 100644
index 000000000..90307bff9
--- /dev/null
+++ b/crypto/src/asn1/cms/TimeStampedDataParser.cs
@@ -0,0 +1,76 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+	public class TimeStampedDataParser
+	{
+		private DerInteger version;
+		private DerIA5String dataUri;
+		private MetaData metaData;
+		private Asn1OctetStringParser content;
+		private Evidence temporalEvidence;
+		private Asn1SequenceParser parser;
+		
+		private TimeStampedDataParser(Asn1SequenceParser parser)
+		{
+			this.parser = parser;
+			this.version = DerInteger.GetInstance(parser.ReadObject());
+
+			Asn1Object obj = parser.ReadObject().ToAsn1Object();
+
+			if (obj is DerIA5String)
+			{
+				this.dataUri = DerIA5String.GetInstance(obj);
+				obj = parser.ReadObject().ToAsn1Object();
+			}
+
+            if (//obj is MetaData ||
+                obj is Asn1SequenceParser)
+			{
+				this.metaData = MetaData.GetInstance(obj.ToAsn1Object());
+				obj = parser.ReadObject().ToAsn1Object();
+			}
+
+			if (obj is Asn1OctetStringParser)
+			{
+				this.content = (Asn1OctetStringParser)obj;
+			}
+		}
+
+		public static TimeStampedDataParser GetInstance(object obj)
+		{
+			if (obj is Asn1Sequence)
+				return new TimeStampedDataParser(((Asn1Sequence)obj).Parser);
+
+			if (obj is Asn1SequenceParser)
+				return new TimeStampedDataParser((Asn1SequenceParser)obj);
+
+			return null;
+		}
+		
+		public virtual DerIA5String DataUri
+		{
+			get { return dataUri; }
+		}
+
+		public virtual MetaData MetaData
+		{
+			get { return metaData; }
+		}
+
+		public virtual Asn1OctetStringParser Content
+		{
+			get { return content; }
+		}
+
+		public virtual Evidence GetTemporalEvidence()
+		{
+			if (temporalEvidence == null)
+			{
+				temporalEvidence = Evidence.GetInstance(parser.ReadObject().ToAsn1Object());
+			}
+
+			return temporalEvidence;
+		}
+	}
+}
diff --git a/crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs b/crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs
new file mode 100644
index 000000000..53c5c706b
--- /dev/null
+++ b/crypto/src/asn1/cms/ecc/MQVuserKeyingMaterial.cs
@@ -0,0 +1,103 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Cms.Ecc
+{
+	public class MQVuserKeyingMaterial
+		: Asn1Encodable
+	{
+		private OriginatorPublicKey	ephemeralPublicKey;
+		private Asn1OctetString		addedukm;
+
+		public MQVuserKeyingMaterial(
+			OriginatorPublicKey	ephemeralPublicKey,
+			Asn1OctetString		addedukm)
+		{
+			// TODO Check ephemeralPublicKey not null
+
+			this.ephemeralPublicKey = ephemeralPublicKey;
+			this.addedukm = addedukm;
+		}
+
+		private MQVuserKeyingMaterial(
+			Asn1Sequence seq)
+		{
+			// TODO Check seq has either 1 or 2 elements
+
+			this.ephemeralPublicKey = OriginatorPublicKey.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.addedukm = Asn1OctetString.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+			}
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from a tagged object.
+		 *
+		 * @param obj      the tagged object holding the object we want.
+		 * @param isExplicit true if the object is meant to be explicitly
+		 *                 tagged false otherwise.
+		 * @throws ArgumentException if the object held by the
+		 *                                  tagged object cannot be converted.
+		 */
+		public static MQVuserKeyingMaterial GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		 * return an AuthEnvelopedData object from the given object.
+		 *
+		 * @param obj the object we want converted.
+		 * @throws ArgumentException if the object cannot be converted.
+		 */
+		public static MQVuserKeyingMaterial GetInstance(
+			object	obj)
+		{
+			if (obj == null || obj is MQVuserKeyingMaterial)
+			{
+				return (MQVuserKeyingMaterial)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new MQVuserKeyingMaterial((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Invalid MQVuserKeyingMaterial: " + obj.GetType().Name);
+		}
+		
+		public OriginatorPublicKey EphemeralPublicKey
+		{
+			get { return ephemeralPublicKey; }
+		}
+
+		public Asn1OctetString AddedUkm
+		{
+			get { return addedukm; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <pre>
+		* MQVuserKeyingMaterial ::= SEQUENCE {
+		*   ephemeralPublicKey OriginatorPublicKey,
+		*   addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL  }
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(ephemeralPublicKey);
+
+			if (addedukm != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, addedukm));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/crmf/AttributeTypeAndValue.cs b/crypto/src/asn1/crmf/AttributeTypeAndValue.cs
new file mode 100644
index 000000000..823668992
--- /dev/null
+++ b/crypto/src/asn1/crmf/AttributeTypeAndValue.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class AttributeTypeAndValue
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier type;
+        private readonly Asn1Encodable value;
+
+        private AttributeTypeAndValue(Asn1Sequence seq)
+        {
+            type = (DerObjectIdentifier)seq[0];
+            value = (Asn1Encodable)seq[1];
+        }
+
+        public static AttributeTypeAndValue GetInstance(object obj)
+        {
+            if (obj is AttributeTypeAndValue)
+                return (AttributeTypeAndValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new AttributeTypeAndValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public AttributeTypeAndValue(
+            String oid,
+            Asn1Encodable value)
+            : this(new DerObjectIdentifier(oid), value)
+        {
+        }
+
+        public AttributeTypeAndValue(
+            DerObjectIdentifier type,
+            Asn1Encodable value)
+        {
+            this.type = type;
+            this.value = value;
+        }
+
+        public virtual DerObjectIdentifier Type
+        {
+            get { return type; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return value; }
+        }
+
+        /**
+         * <pre>
+         * AttributeTypeAndValue ::= SEQUENCE {
+         *           type         OBJECT IDENTIFIER,
+         *           value        ANY DEFINED BY type }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(type, value);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertId.cs b/crypto/src/asn1/crmf/CertId.cs
new file mode 100644
index 000000000..10c2cc8b4
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertId.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertId
+        : Asn1Encodable
+    {
+        private readonly GeneralName issuer;
+        private readonly DerInteger serialNumber;
+
+        private CertId(Asn1Sequence seq)
+        {
+            issuer = GeneralName.GetInstance(seq[0]);
+            serialNumber = DerInteger.GetInstance(seq[1]);
+        }
+
+        public static CertId GetInstance(object obj)
+        {
+            if (obj is CertId)
+                return (CertId)obj;
+
+            if (obj is Asn1Sequence)
+                return new CertId((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static CertId GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        public virtual GeneralName Issuer
+        {
+            get { return issuer; }
+        }
+
+        public virtual DerInteger SerialNumber
+        {
+            get { return serialNumber; }
+        }
+
+        /**
+         * <pre>
+         * CertId ::= SEQUENCE {
+         *                 issuer           GeneralName,
+         *                 serialNumber     INTEGER }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(issuer, serialNumber);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertReqMessages.cs b/crypto/src/asn1/crmf/CertReqMessages.cs
new file mode 100644
index 000000000..9247281e8
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertReqMessages.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertReqMessages
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence content;
+
+        private CertReqMessages(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static CertReqMessages GetInstance(object obj)
+        {
+            if (obj is CertReqMessages)
+                return (CertReqMessages)obj;
+
+            if (obj is Asn1Sequence)
+                return new CertReqMessages((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public CertReqMessages(params CertReqMsg[] msgs)
+        {
+            content = new DerSequence(msgs);
+        }
+
+        public virtual CertReqMsg[] ToCertReqMsgArray()
+        {
+            CertReqMsg[] result = new CertReqMsg[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = CertReqMsg.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertReqMsg.cs b/crypto/src/asn1/crmf/CertReqMsg.cs
new file mode 100644
index 000000000..2ca319a57
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertReqMsg.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertReqMsg
+        : Asn1Encodable
+    {
+        private readonly CertRequest certReq;
+        private readonly ProofOfPossession popo;
+        private readonly Asn1Sequence regInfo;
+
+        private CertReqMsg(Asn1Sequence seq)
+        {
+            certReq = CertRequest.GetInstance(seq[0]);
+
+            for (int pos = 1; pos < seq.Count; ++pos)
+            {
+                object o = seq[pos];
+
+                if (o is Asn1TaggedObject || o is ProofOfPossession)
+                {
+                    popo = ProofOfPossession.GetInstance(o);
+                }
+                else
+                {
+                    regInfo = Asn1Sequence.GetInstance(o);
+                }
+            }
+        }
+
+        public static CertReqMsg GetInstance(object obj)
+        {
+            if (obj is CertReqMsg)
+                return (CertReqMsg)obj;
+
+            if (obj != null)
+                return new CertReqMsg(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        /**
+         * Creates a new CertReqMsg.
+         * @param certReq CertRequest
+         * @param popo may be null
+         * @param regInfo may be null
+         */
+        public CertReqMsg(
+            CertRequest				certReq,
+            ProofOfPossession		popo,
+            AttributeTypeAndValue[]	regInfo)
+        {
+            if (certReq == null)
+                throw new ArgumentNullException("certReq");
+
+            this.certReq = certReq;
+            this.popo = popo;
+
+            if (regInfo != null)
+            {
+                this.regInfo = new DerSequence(regInfo);
+            }
+        }
+
+        public virtual CertRequest CertReq
+        {
+            get { return certReq; }
+        }
+
+        public virtual ProofOfPossession Popo
+        {
+            get { return popo; }
+        }
+
+        public virtual AttributeTypeAndValue[] GetRegInfo()
+        {
+            if (regInfo == null)
+                return null;
+
+            AttributeTypeAndValue[] results = new AttributeTypeAndValue[regInfo.Count];
+            for (int i = 0; i != results.Length; ++i)
+            {
+                results[i] = AttributeTypeAndValue.GetInstance(regInfo[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * CertReqMsg ::= SEQUENCE {
+         *                    certReq   CertRequest,
+         *                    pop       ProofOfPossession  OPTIONAL,
+         *                    -- content depends upon key type
+         *                    regInfo   SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(certReq);
+            v.AddOptional(popo);
+            v.AddOptional(regInfo);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertRequest.cs b/crypto/src/asn1/crmf/CertRequest.cs
new file mode 100644
index 000000000..625a9b519
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertRequest.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertRequest
+        : Asn1Encodable
+    {
+        private readonly DerInteger certReqId;
+        private readonly CertTemplate certTemplate;
+        private readonly Controls controls;
+
+        private CertRequest(Asn1Sequence seq)
+        {
+            certReqId = DerInteger.GetInstance(seq[0]);
+            certTemplate = CertTemplate.GetInstance(seq[1]);
+            if (seq.Count > 2)
+            {
+                controls = Controls.GetInstance(seq[2]);
+            }
+        }
+
+        public static CertRequest GetInstance(object obj)
+        {
+            if (obj is CertRequest)
+                return (CertRequest)obj;
+
+            if (obj != null)
+                return new CertRequest(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public CertRequest(
+            int certReqId,
+            CertTemplate certTemplate,
+            Controls controls)
+            : this(new DerInteger(certReqId), certTemplate, controls)
+        {
+        }
+
+        public CertRequest(
+            DerInteger certReqId,
+            CertTemplate certTemplate,
+            Controls controls)
+        {
+            this.certReqId = certReqId;
+            this.certTemplate = certTemplate;
+            this.controls = controls;
+        }
+
+        public virtual DerInteger CertReqID
+        {
+            get { return certReqId; }
+        }
+
+        public virtual CertTemplate CertTemplate
+        {
+            get { return certTemplate; }
+        }
+
+        public virtual Controls Controls
+        {
+            get { return controls; }
+        }
+
+        /**
+         * <pre>
+         * CertRequest ::= SEQUENCE {
+         *                      certReqId     INTEGER,          -- ID for matching request and reply
+         *                      certTemplate  CertTemplate,  -- Selected fields of cert to be issued
+         *                      controls      Controls OPTIONAL }   -- Attributes affecting issuance
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(certReqId, certTemplate);
+            v.AddOptional(controls);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertTemplate.cs b/crypto/src/asn1/crmf/CertTemplate.cs
new file mode 100644
index 000000000..3de9f1d5a
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertTemplate.cs
@@ -0,0 +1,149 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertTemplate
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence seq;
+
+        private readonly DerInteger version;
+        private readonly DerInteger serialNumber;
+        private readonly AlgorithmIdentifier signingAlg;
+        private readonly X509Name issuer;
+        private readonly OptionalValidity validity;
+        private readonly X509Name subject;
+        private readonly SubjectPublicKeyInfo publicKey;
+        private readonly DerBitString issuerUID;
+        private readonly DerBitString subjectUID;
+        private readonly X509Extensions extensions;
+
+        private CertTemplate(Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+            foreach (Asn1TaggedObject tObj in seq)
+            {
+                switch (tObj.TagNo)
+                {
+                case 0:
+                    version = DerInteger.GetInstance(tObj, false);
+                    break;
+                case 1:
+                    serialNumber = DerInteger.GetInstance(tObj, false);
+                    break;
+                case 2:
+                    signingAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                    break;
+                case 3:
+                    issuer = X509Name.GetInstance(tObj, true); // CHOICE
+                    break;
+                case 4:
+                    validity = OptionalValidity.GetInstance(Asn1Sequence.GetInstance(tObj, false));
+                    break;
+                case 5:
+                    subject = X509Name.GetInstance(tObj, true); // CHOICE
+                    break;
+                case 6:
+                    publicKey = SubjectPublicKeyInfo.GetInstance(tObj, false);
+                    break;
+                case 7:
+                    issuerUID = DerBitString.GetInstance(tObj, false);
+                    break;
+                case 8:
+                    subjectUID = DerBitString.GetInstance(tObj, false);
+                    break;
+                case 9:
+                    extensions = X509Extensions.GetInstance(tObj, false);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag: " + tObj.TagNo, "seq");
+                }
+            }
+        }
+
+        public static CertTemplate GetInstance(object obj)
+        {
+            if (obj is CertTemplate)
+                return (CertTemplate)obj;
+
+            if (obj != null)
+                return new CertTemplate(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public virtual int Version
+        {
+            get { return version.Value.IntValue; }
+        }
+
+        public virtual DerInteger SerialNumber
+        {
+            get { return serialNumber; }
+        }
+
+        public virtual AlgorithmIdentifier SigningAlg
+        {
+            get { return signingAlg; }
+        }
+
+        public virtual X509Name Issuer
+        {
+            get { return issuer; }
+        }
+
+        public virtual OptionalValidity Validity
+        {
+            get { return validity; }
+        }
+
+        public virtual X509Name Subject
+        {
+            get { return subject; }
+        }
+
+        public virtual SubjectPublicKeyInfo PublicKey
+        {
+            get { return publicKey; }
+        }
+
+        public virtual DerBitString IssuerUID
+        {
+            get { return issuerUID; }
+        }
+
+        public virtual DerBitString SubjectUID
+        {
+            get { return subjectUID; }
+        }
+
+        public virtual X509Extensions Extensions
+        {
+            get { return extensions; }
+        }
+
+        /**
+         * <pre>
+         *  CertTemplate ::= SEQUENCE {
+         *      version      [0] Version               OPTIONAL,
+         *      serialNumber [1] INTEGER               OPTIONAL,
+         *      signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
+         *      issuer       [3] Name                  OPTIONAL,
+         *      validity     [4] OptionalValidity      OPTIONAL,
+         *      subject      [5] Name                  OPTIONAL,
+         *      publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
+         *      issuerUID    [7] UniqueIdentifier      OPTIONAL,
+         *      subjectUID   [8] UniqueIdentifier      OPTIONAL,
+         *      extensions   [9] Extensions            OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CertTemplateBuilder.cs b/crypto/src/asn1/crmf/CertTemplateBuilder.cs
new file mode 100644
index 000000000..51c73c4e1
--- /dev/null
+++ b/crypto/src/asn1/crmf/CertTemplateBuilder.cs
@@ -0,0 +1,125 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class CertTemplateBuilder
+    {
+        private DerInteger version;
+        private DerInteger serialNumber;
+        private AlgorithmIdentifier signingAlg;
+        private X509Name issuer;
+        private OptionalValidity validity;
+        private X509Name subject;
+        private SubjectPublicKeyInfo publicKey;
+        private DerBitString issuerUID;
+        private DerBitString subjectUID;
+        private X509Extensions extensions;
+
+        /** Sets the X.509 version. Note: for X509v3, use 2 here. */
+        public virtual CertTemplateBuilder SetVersion(int ver)
+        {
+            version = new DerInteger(ver);
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSerialNumber(DerInteger ser)
+        {
+            serialNumber = ser;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSigningAlg(AlgorithmIdentifier aid)
+        {
+            signingAlg = aid;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetIssuer(X509Name name)
+        {
+            issuer = name;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetValidity(OptionalValidity v)
+        {
+            validity = v;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetSubject(X509Name name)
+        {
+            subject = name;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetPublicKey(SubjectPublicKeyInfo spki)
+        {
+            publicKey = spki;
+            return this;
+        }
+
+        /** Sets the issuer unique ID (deprecated in X.509v3) */
+        public virtual CertTemplateBuilder SetIssuerUID(DerBitString uid)
+        {
+            issuerUID = uid;
+            return this;
+        }
+
+        /** Sets the subject unique ID (deprecated in X.509v3) */
+        public virtual CertTemplateBuilder SetSubjectUID(DerBitString uid)
+        {
+            subjectUID = uid;
+            return this;
+        }
+
+        public virtual CertTemplateBuilder SetExtensions(X509Extensions extens)
+        {
+            extensions = extens;
+            return this;
+        }
+
+        /**
+         * <pre>
+         *  CertTemplate ::= SEQUENCE {
+         *      version      [0] Version               OPTIONAL,
+         *      serialNumber [1] INTEGER               OPTIONAL,
+         *      signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
+         *      issuer       [3] Name                  OPTIONAL,
+         *      validity     [4] OptionalValidity      OPTIONAL,
+         *      subject      [5] Name                  OPTIONAL,
+         *      publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
+         *      issuerUID    [7] UniqueIdentifier      OPTIONAL,
+         *      subjectUID   [8] UniqueIdentifier      OPTIONAL,
+         *      extensions   [9] Extensions            OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public virtual CertTemplate Build()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            AddOptional(v, 0, false, version);
+            AddOptional(v, 1, false, serialNumber);
+            AddOptional(v, 2, false, signingAlg);
+            AddOptional(v, 3, true, issuer); // CHOICE
+            AddOptional(v, 4, false, validity);
+            AddOptional(v, 5, true, subject); // CHOICE
+            AddOptional(v, 6, false, publicKey);
+            AddOptional(v, 7, false, issuerUID);
+            AddOptional(v, 8, false, subjectUID);
+            AddOptional(v, 9, false, extensions);
+
+            return CertTemplate.GetInstance(new DerSequence(v));
+        }
+
+        private void AddOptional(Asn1EncodableVector v, int tagNo, bool isExplicit, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/Controls.cs b/crypto/src/asn1/crmf/Controls.cs
new file mode 100644
index 000000000..cc52ea4bb
--- /dev/null
+++ b/crypto/src/asn1/crmf/Controls.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class Controls
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence content;
+
+        private Controls(Asn1Sequence seq)
+        {
+            content = seq;
+        }
+
+        public static Controls GetInstance(object obj)
+        {
+            if (obj is Controls)
+                return (Controls)obj;
+
+            if (obj is Asn1Sequence)
+                return new Controls((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+		public Controls(params AttributeTypeAndValue[] atvs)
+        {
+            content = new DerSequence(atvs);
+        }
+
+        public virtual AttributeTypeAndValue[] ToAttributeTypeAndValueArray()
+        {
+            AttributeTypeAndValue[] result = new AttributeTypeAndValue[content.Count];
+            for (int i = 0; i != result.Length; ++i)
+            {
+                result[i] = AttributeTypeAndValue.GetInstance(content[i]);
+            }
+            return result;
+        }
+
+        /**
+         * <pre>
+         * Controls  ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return content;
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs b/crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
new file mode 100644
index 000000000..eaa1f7ba4
--- /dev/null
+++ b/crypto/src/asn1/crmf/CrmfObjectIdentifiers.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public abstract class CrmfObjectIdentifiers
+    {
+        public static readonly DerObjectIdentifier id_pkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+        // arc for Internet X.509 PKI protocols and their components
+
+        public static readonly DerObjectIdentifier id_pkip  = id_pkix.Branch("5");
+
+        public static readonly DerObjectIdentifier id_regCtrl = id_pkip.Branch("1");
+        public static readonly DerObjectIdentifier id_regCtrl_regToken = id_regCtrl.Branch("1");
+        public static readonly DerObjectIdentifier id_regCtrl_authenticator = id_regCtrl.Branch("2");
+        public static readonly DerObjectIdentifier id_regCtrl_pkiPublicationInfo = id_regCtrl.Branch("3");
+        public static readonly DerObjectIdentifier id_regCtrl_pkiArchiveOptions = id_regCtrl.Branch("4");
+
+        public static readonly DerObjectIdentifier id_ct_encKeyWithID = new DerObjectIdentifier(PkcsObjectIdentifiers.IdCT + ".21");
+    }
+}
diff --git a/crypto/src/asn1/crmf/EncKeyWithID.cs b/crypto/src/asn1/crmf/EncKeyWithID.cs
new file mode 100644
index 000000000..6de56fa0b
--- /dev/null
+++ b/crypto/src/asn1/crmf/EncKeyWithID.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncKeyWithID
+        : Asn1Encodable
+    {
+        private readonly PrivateKeyInfo privKeyInfo;
+        private readonly Asn1Encodable identifier;
+
+        public static EncKeyWithID GetInstance(object obj)
+        {
+            if (obj is EncKeyWithID)
+                return (EncKeyWithID)obj;
+
+            if (obj != null)
+                return new EncKeyWithID(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        private EncKeyWithID(Asn1Sequence seq)
+        {
+            this.privKeyInfo = PrivateKeyInfo.GetInstance(seq[0]);
+
+            if (seq.Count > 1)
+            {
+                if (!(seq[1] is DerUtf8String))
+                {
+                    this.identifier = GeneralName.GetInstance(seq[1]);
+                }
+                else
+                {
+                    this.identifier = (Asn1Encodable)seq[1];
+                }
+            }
+            else
+            {
+                this.identifier = null;
+            }
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = null;
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo, DerUtf8String str)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = str;
+        }
+
+        public EncKeyWithID(PrivateKeyInfo privKeyInfo, GeneralName generalName)
+        {
+            this.privKeyInfo = privKeyInfo;
+            this.identifier = generalName;
+        }
+
+        public virtual PrivateKeyInfo PrivateKey
+        {
+            get { return privKeyInfo; }
+        }
+
+        public virtual bool HasIdentifier
+        {
+            get { return identifier != null; }
+        }
+
+        public virtual bool IsIdentifierUtf8String
+        {
+            get { return identifier is DerUtf8String; }
+        }
+
+        public virtual Asn1Encodable Identifier
+        {
+            get { return identifier; }
+        }
+
+        /**
+         * <pre>
+         * EncKeyWithID ::= SEQUENCE {
+         *      privateKey           PrivateKeyInfo,
+         *      identifier CHOICE {
+         *         string               UTF8String,
+         *         generalName          GeneralName
+         *     } OPTIONAL
+         * }
+         * </pre>
+         * @return
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(privKeyInfo);
+            v.AddOptional(identifier);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/EncryptedKey.cs b/crypto/src/asn1/crmf/EncryptedKey.cs
new file mode 100644
index 000000000..850fbd219
--- /dev/null
+++ b/crypto/src/asn1/crmf/EncryptedKey.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncryptedKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly EnvelopedData envelopedData;
+        private readonly EncryptedValue encryptedValue;
+
+        public static EncryptedKey GetInstance(object o)
+        {
+            if (o is EncryptedKey)
+            {
+                return (EncryptedKey)o;
+            }
+            else if (o is Asn1TaggedObject)
+            {
+                return new EncryptedKey(EnvelopedData.GetInstance((Asn1TaggedObject)o, false));
+            }
+            else if (o is EncryptedValue)
+            {
+                return new EncryptedKey((EncryptedValue)o);
+            }
+            else
+            {
+                return new EncryptedKey(EncryptedValue.GetInstance(o));
+            }
+        }
+
+        public EncryptedKey(EnvelopedData envelopedData)
+        {
+            this.envelopedData = envelopedData;
+        }
+
+        public EncryptedKey(EncryptedValue encryptedValue)
+        {
+            this.encryptedValue = encryptedValue;
+        }
+
+        public virtual bool IsEncryptedValue
+        {
+            get { return encryptedValue != null; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get
+            {
+                if (encryptedValue != null)
+                    return encryptedValue;
+
+                return envelopedData;
+            }
+        }
+
+        /**
+         * <pre>
+         *    EncryptedKey ::= CHOICE {
+         *        encryptedValue        EncryptedValue, -- deprecated
+         *        envelopedData     [0] EnvelopedData }
+         *        -- The encrypted private key MUST be placed in the envelopedData
+         *        -- encryptedContentInfo encryptedContent OCTET STRING.
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (encryptedValue != null)
+            {
+                return encryptedValue.ToAsn1Object();
+            }
+
+            return new DerTaggedObject(false, 0, envelopedData);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/EncryptedValue.cs b/crypto/src/asn1/crmf/EncryptedValue.cs
new file mode 100644
index 000000000..83122e220
--- /dev/null
+++ b/crypto/src/asn1/crmf/EncryptedValue.cs
@@ -0,0 +1,154 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class EncryptedValue
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier intendedAlg;
+        private readonly AlgorithmIdentifier symmAlg;
+        private readonly DerBitString encSymmKey;
+        private readonly AlgorithmIdentifier keyAlg;
+        private readonly Asn1OctetString valueHint;
+        private readonly DerBitString encValue;
+
+        private EncryptedValue(Asn1Sequence seq)
+        {
+            int index = 0;
+            while (seq[index] is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tObj = (Asn1TaggedObject)seq[index];
+
+                switch (tObj.TagNo)
+                {
+                    case 0:
+                        intendedAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 1:
+                        symmAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 2:
+                        encSymmKey = DerBitString.GetInstance(tObj, false);
+                        break;
+                    case 3:
+                        keyAlg = AlgorithmIdentifier.GetInstance(tObj, false);
+                        break;
+                    case 4:
+                        valueHint = Asn1OctetString.GetInstance(tObj, false);
+                        break;
+                }
+                ++index;
+            }
+
+            encValue = DerBitString.GetInstance(seq[index]);
+        }
+
+        public static EncryptedValue GetInstance(object obj)
+        {
+            if (obj is EncryptedValue)
+                return (EncryptedValue)obj;
+
+            if (obj != null)
+                return new EncryptedValue(Asn1Sequence.GetInstance(obj));
+
+            return null;
+        }
+
+        public EncryptedValue(
+            AlgorithmIdentifier intendedAlg,
+            AlgorithmIdentifier symmAlg,
+            DerBitString encSymmKey,
+            AlgorithmIdentifier keyAlg,
+            Asn1OctetString valueHint,
+            DerBitString encValue)
+        {
+            if (encValue == null)
+            {
+                throw new ArgumentNullException("encValue");
+            }
+
+            this.intendedAlg = intendedAlg;
+            this.symmAlg = symmAlg;
+            this.encSymmKey = encSymmKey;
+            this.keyAlg = keyAlg;
+            this.valueHint = valueHint;
+            this.encValue = encValue;
+        }
+
+        public virtual AlgorithmIdentifier IntendedAlg
+        {
+            get { return intendedAlg; }
+        }
+
+        public virtual AlgorithmIdentifier SymmAlg
+        {
+            get { return symmAlg; }
+        }
+
+        public virtual DerBitString EncSymmKey
+        {
+            get { return encSymmKey; }
+        }
+
+        public virtual AlgorithmIdentifier KeyAlg
+        {
+            get { return keyAlg; }
+        }
+
+        public virtual Asn1OctetString ValueHint
+        {
+            get { return valueHint; }
+        }
+
+        public virtual DerBitString EncValue
+        {
+            get { return encValue; }
+        }
+
+        /**
+         * <pre>
+         * EncryptedValue ::= SEQUENCE {
+         *                     intendedAlg   [0] AlgorithmIdentifier  OPTIONAL,
+         *                     -- the intended algorithm for which the value will be used
+         *                     symmAlg       [1] AlgorithmIdentifier  OPTIONAL,
+         *                     -- the symmetric algorithm used to encrypt the value
+         *                     encSymmKey    [2] BIT STRING           OPTIONAL,
+         *                     -- the (encrypted) symmetric key used to encrypt the value
+         *                     keyAlg        [3] AlgorithmIdentifier  OPTIONAL,
+         *                     -- algorithm used to encrypt the symmetric key
+         *                     valueHint     [4] OCTET STRING         OPTIONAL,
+         *                     -- a brief description or identifier of the encValue content
+         *                     -- (may be meaningful only to the sending entity, and used only
+         *                     -- if EncryptedValue might be re-examined by the sending entity
+         *                     -- in the future)
+         *                     encValue       BIT STRING }
+         *                     -- the encrypted value itself
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            AddOptional(v, 0, intendedAlg);
+            AddOptional(v, 1, symmAlg);
+            AddOptional(v, 2, encSymmKey);
+            AddOptional(v, 3, keyAlg);
+            AddOptional(v, 4, valueHint);
+
+            v.Add(encValue);
+
+            return new DerSequence(v);
+        }
+
+        private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
+        {
+            if (obj != null)
+            {
+                v.Add(new DerTaggedObject(false, tagNo, obj));
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/OptionalValidity.cs b/crypto/src/asn1/crmf/OptionalValidity.cs
index c0037999a..d1a0f7ffb 100644
--- a/crypto/src/asn1/crmf/OptionalValidity.cs
+++ b/crypto/src/asn1/crmf/OptionalValidity.cs
@@ -27,13 +27,20 @@ namespace Org.BouncyCastle.Asn1.Crmf
 
         public static OptionalValidity GetInstance(object obj)
         {
-            if (obj is OptionalValidity)
+            if (obj == null || obj is OptionalValidity)
                 return (OptionalValidity)obj;
 
-            if (obj is Asn1Sequence)
-                return new OptionalValidity((Asn1Sequence)obj);
+            return new OptionalValidity(Asn1Sequence.GetInstance(obj));
+        }
 
-            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        public virtual Time NotBefore
+        {
+            get { return notBefore; }
+        }
+
+        public virtual Time NotAfter
+        {
+            get { return notAfter; }
         }
 
         /**
diff --git a/crypto/src/asn1/crmf/PKIArchiveOptions.cs b/crypto/src/asn1/crmf/PKIArchiveOptions.cs
new file mode 100644
index 000000000..910f73b22
--- /dev/null
+++ b/crypto/src/asn1/crmf/PKIArchiveOptions.cs
@@ -0,0 +1,105 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PkiArchiveOptions
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int encryptedPrivKey = 0;
+        public const int keyGenParameters = 1;
+        public const int archiveRemGenPrivKey = 2;
+
+        private readonly Asn1Encodable value;
+
+        public static PkiArchiveOptions GetInstance(object obj)
+        {
+            if (obj is PkiArchiveOptions)
+                return (PkiArchiveOptions)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new PkiArchiveOptions((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        private PkiArchiveOptions(Asn1TaggedObject tagged)
+        {
+            switch (tagged.TagNo)
+            {
+                case encryptedPrivKey:
+                    value = EncryptedKey.GetInstance(tagged.GetObject());
+                    break;
+                case keyGenParameters:
+                    value = Asn1OctetString.GetInstance(tagged, false);
+                    break;
+                case archiveRemGenPrivKey:
+                    value = DerBoolean.GetInstance(tagged, false);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag number: " + tagged.TagNo, "tagged");
+            }
+        }
+
+        public PkiArchiveOptions(EncryptedKey encKey)
+        {
+            this.value = encKey;
+        }
+
+        public PkiArchiveOptions(Asn1OctetString keyGenParameters)
+        {
+            this.value = keyGenParameters;
+        }
+
+        public PkiArchiveOptions(bool archiveRemGenPrivKey)
+        {
+            this.value = DerBoolean.GetInstance(archiveRemGenPrivKey);
+        }
+
+        public virtual int Type
+        {
+            get
+            {
+                if (value is EncryptedKey)
+                    return encryptedPrivKey;
+
+                if (value is Asn1OctetString)
+                    return keyGenParameters;
+
+                return archiveRemGenPrivKey;
+            }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return value; }
+        }
+
+        /**
+         * <pre>
+         *  PkiArchiveOptions ::= CHOICE {
+         *      encryptedPrivKey     [0] EncryptedKey,
+         *      -- the actual value of the private key
+         *      keyGenParameters     [1] KeyGenParameters,
+         *      -- parameters which allow the private key to be re-generated
+         *      archiveRemGenPrivKey [2] BOOLEAN }
+         *      -- set to TRUE if sender wishes receiver to archive the private
+         *      -- key of a key pair that the receiver generates in response to
+         *      -- this request; set to FALSE if no archival is desired.
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (value is EncryptedKey)
+            {
+                return new DerTaggedObject(true, encryptedPrivKey, value);  // choice
+            }
+
+            if (value is Asn1OctetString)
+            {
+                return new DerTaggedObject(false, keyGenParameters, value);
+            }
+
+            return new DerTaggedObject(false, archiveRemGenPrivKey, value);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PKIPublicationInfo.cs b/crypto/src/asn1/crmf/PKIPublicationInfo.cs
new file mode 100644
index 000000000..c8bc1403e
--- /dev/null
+++ b/crypto/src/asn1/crmf/PKIPublicationInfo.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PkiPublicationInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger action;
+        private readonly Asn1Sequence pubInfos;
+
+        private PkiPublicationInfo(Asn1Sequence seq)
+        {
+            action = DerInteger.GetInstance(seq[0]);
+            pubInfos = Asn1Sequence.GetInstance(seq[1]);
+        }
+
+        public static PkiPublicationInfo GetInstance(object obj)
+        {
+            if (obj is PkiPublicationInfo)
+                return (PkiPublicationInfo)obj;
+
+            if (obj is Asn1Sequence)
+                return new PkiPublicationInfo((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual DerInteger Action
+        {
+            get { return action; }
+        }
+
+        public virtual SinglePubInfo[] GetPubInfos()
+        {
+            if (pubInfos == null)
+                return null;
+
+            SinglePubInfo[] results = new SinglePubInfo[pubInfos.Count];
+            for (int i = 0; i != results.Length; ++i)
+            {
+                results[i] = SinglePubInfo.GetInstance(pubInfos[i]);
+            }
+            return results;
+        }
+
+        /**
+         * <pre>
+         * PkiPublicationInfo ::= SEQUENCE {
+         *                  action     INTEGER {
+         *                                 dontPublish (0),
+         *                                 pleasePublish (1) },
+         *                  pubInfos  SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
+         * -- pubInfos MUST NOT be present if action is "dontPublish"
+         * -- (if action is "pleasePublish" and pubInfos is omitted,
+         * -- "dontCare" is assumed)
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(action, pubInfos);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PKMacValue.cs b/crypto/src/asn1/crmf/PKMacValue.cs
new file mode 100644
index 000000000..20a08fd1d
--- /dev/null
+++ b/crypto/src/asn1/crmf/PKMacValue.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    /**
+     * Password-based MAC value for use with POPOSigningKeyInput.
+     */
+    public class PKMacValue
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier  algID;
+        private readonly DerBitString         macValue;
+
+        private PKMacValue(Asn1Sequence seq)
+        {
+            this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+            this.macValue = DerBitString.GetInstance(seq[1]);
+        }
+
+        public static PKMacValue GetInstance(object obj)
+        {
+            if (obj is PKMacValue)
+                return (PKMacValue)obj;
+
+            if (obj is Asn1Sequence)
+                return new PKMacValue((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static PKMacValue GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Creates a new PKMACValue.
+         * @param params parameters for password-based MAC
+         * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+         */
+        public PKMacValue(
+            PbmParameter pbmParams,
+            DerBitString macValue)
+            : this(new AlgorithmIdentifier(CmpObjectIdentifiers.passwordBasedMac, pbmParams), macValue)
+        {
+        }
+
+        /**
+         * Creates a new PKMACValue.
+         * @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter
+         * @param value MAC of the DER-encoded SubjectPublicKeyInfo
+         */
+        public PKMacValue(
+            AlgorithmIdentifier algID,
+            DerBitString        macValue)
+        {
+            this.algID = algID;
+            this.macValue = macValue;
+        }
+
+        public virtual AlgorithmIdentifier AlgID
+        {
+            get { return algID; }
+        }
+
+        public virtual DerBitString MacValue
+        {
+            get { return macValue; }
+        }
+
+        /**
+         * <pre>
+         * PKMACValue ::= SEQUENCE {
+         *      algId  AlgorithmIdentifier,
+         *      -- algorithm value shall be PasswordBasedMac 1.2.840.113533.7.66.13
+         *      -- parameter value is PBMParameter
+         *      value  BIT STRING }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(algID, macValue);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PopoPrivKey.cs b/crypto/src/asn1/crmf/PopoPrivKey.cs
new file mode 100644
index 000000000..0cedc5127
--- /dev/null
+++ b/crypto/src/asn1/crmf/PopoPrivKey.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoPrivKey
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int thisMessage = 0;
+        public const int subsequentMessage = 1;
+        public const int dhMAC = 2;
+        public const int agreeMAC = 3;
+        public const int encryptedKey = 4;
+
+        private readonly int tagNo;
+        private readonly Asn1Encodable obj;
+
+        private PopoPrivKey(Asn1TaggedObject obj)
+        {
+            this.tagNo = obj.TagNo;
+
+            switch (tagNo)
+            {
+            case thisMessage:
+                this.obj = DerBitString.GetInstance(obj, false);
+                break;
+            case subsequentMessage:
+                this.obj = SubsequentMessage.ValueOf(DerInteger.GetInstance(obj, false).Value.IntValue);
+                break;
+            case dhMAC:
+                this.obj = DerBitString.GetInstance(obj, false);
+                break;
+            case agreeMAC:
+                this.obj = PKMacValue.GetInstance(obj, false);
+                break;
+            case encryptedKey:
+                this.obj = EnvelopedData.GetInstance(obj, false);
+                break;
+            default:
+                throw new ArgumentException("unknown tag in PopoPrivKey", "obj");
+            }
+        }
+
+        public static PopoPrivKey GetInstance(Asn1TaggedObject tagged, bool isExplicit)
+        {
+            return new PopoPrivKey(Asn1TaggedObject.GetInstance(tagged.GetObject()));
+        }
+
+        public PopoPrivKey(SubsequentMessage msg)
+        {
+            this.tagNo = subsequentMessage;
+            this.obj = msg;
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Value
+        {
+            get { return obj; }
+        }
+
+        /**
+         * <pre>
+         * PopoPrivKey ::= CHOICE {
+         *        thisMessage       [0] BIT STRING,         -- Deprecated
+         *         -- possession is proven in this message (which contains the private
+         *         -- key itself (encrypted for the CA))
+         *        subsequentMessage [1] SubsequentMessage,
+         *         -- possession will be proven in a subsequent message
+         *        dhMAC             [2] BIT STRING,         -- Deprecated
+         *        agreeMAC          [3] PKMACValue,
+         *        encryptedKey      [4] EnvelopedData }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, obj);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PopoSigningKey.cs b/crypto/src/asn1/crmf/PopoSigningKey.cs
new file mode 100644
index 000000000..614278eda
--- /dev/null
+++ b/crypto/src/asn1/crmf/PopoSigningKey.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoSigningKey
+        : Asn1Encodable
+    {
+        private readonly PopoSigningKeyInput poposkInput;
+        private readonly AlgorithmIdentifier algorithmIdentifier;
+        private readonly DerBitString signature;
+
+        private PopoSigningKey(Asn1Sequence seq)
+        {
+            int index = 0;
+
+            if (seq[index] is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tagObj
+                    = (Asn1TaggedObject) seq[index++];
+                if (tagObj.TagNo != 0)
+                {
+                    throw new ArgumentException( "Unknown PopoSigningKeyInput tag: " + tagObj.TagNo, "seq");
+                }
+                poposkInput = PopoSigningKeyInput.GetInstance(tagObj.GetObject());
+            }
+            algorithmIdentifier = AlgorithmIdentifier.GetInstance(seq[index++]);
+            signature = DerBitString.GetInstance(seq[index]);
+        }
+
+        public static PopoSigningKey GetInstance(object obj)
+        {
+            if (obj is PopoSigningKey)
+                return (PopoSigningKey)obj;
+
+            if (obj is Asn1Sequence)
+                return new PopoSigningKey((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public static PopoSigningKey GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Creates a new Proof of Possession object for a signing key.
+         * @param poposkIn the PopoSigningKeyInput structure, or null if the
+         *     CertTemplate includes both subject and publicKey values.
+         * @param aid the AlgorithmIdentifier used to sign the proof of possession.
+         * @param signature a signature over the DER-encoded value of poposkIn,
+         *     or the DER-encoded value of certReq if poposkIn is null.
+         */
+        public PopoSigningKey(
+            PopoSigningKeyInput poposkIn,
+            AlgorithmIdentifier aid,
+            DerBitString signature)
+        {
+            this.poposkInput = poposkIn;
+            this.algorithmIdentifier = aid;
+            this.signature = signature;
+        }
+
+        public virtual PopoSigningKeyInput PoposkInput
+        {
+            get { return poposkInput; }
+        }
+
+        public virtual AlgorithmIdentifier AlgorithmIdentifier
+        {
+            get { return algorithmIdentifier; }
+        }
+
+        public virtual DerBitString Signature
+        {
+            get { return signature; }
+        }
+
+        /**
+         * <pre>
+         * PopoSigningKey ::= SEQUENCE {
+         *                      poposkInput           [0] PopoSigningKeyInput OPTIONAL,
+         *                      algorithmIdentifier   AlgorithmIdentifier,
+         *                      signature             BIT STRING }
+         *  -- The signature (using "algorithmIdentifier") is on the
+         *  -- DER-encoded value of poposkInput.  NOTE: If the CertReqMsg
+         *  -- certReq CertTemplate contains the subject and publicKey values,
+         *  -- then poposkInput MUST be omitted and the signature MUST be
+         *  -- computed on the DER-encoded value of CertReqMsg certReq.  If
+         *  -- the CertReqMsg certReq CertTemplate does not contain the public
+         *  -- key and subject values, then poposkInput MUST be present and
+         *  -- MUST be signed.  This strategy ensures that the public key is
+         *  -- not present in both the poposkInput and CertReqMsg certReq
+         *  -- CertTemplate fields.
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (poposkInput != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, poposkInput));
+            }
+
+            v.Add(algorithmIdentifier);
+            v.Add(signature);
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/PopoSigningKeyInput.cs b/crypto/src/asn1/crmf/PopoSigningKeyInput.cs
new file mode 100644
index 000000000..63695262f
--- /dev/null
+++ b/crypto/src/asn1/crmf/PopoSigningKeyInput.cs
@@ -0,0 +1,115 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class PopoSigningKeyInput
+        : Asn1Encodable
+    {
+        private readonly GeneralName            sender;
+        private readonly PKMacValue             publicKeyMac;
+        private readonly SubjectPublicKeyInfo   publicKey;
+
+        private PopoSigningKeyInput(Asn1Sequence seq)
+        {
+            Asn1Encodable authInfo = (Asn1Encodable)seq[0];
+
+            if (authInfo is Asn1TaggedObject)
+            {
+                Asn1TaggedObject tagObj = (Asn1TaggedObject)authInfo;
+                if (tagObj.TagNo != 0)
+                {
+                    throw new ArgumentException("Unknown authInfo tag: " + tagObj.TagNo, "seq");
+                }
+                sender = GeneralName.GetInstance(tagObj.GetObject());
+            }
+            else
+            {
+                publicKeyMac = PKMacValue.GetInstance(authInfo);
+            }
+
+            publicKey = SubjectPublicKeyInfo.GetInstance(seq[1]);
+        }
+
+        public static PopoSigningKeyInput GetInstance(object obj)
+        {
+            if (obj is PopoSigningKeyInput)
+                return (PopoSigningKeyInput)obj;
+
+            if (obj is Asn1Sequence)
+                return new PopoSigningKeyInput((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /** Creates a new PopoSigningKeyInput with sender name as authInfo. */
+        public PopoSigningKeyInput(
+            GeneralName sender,
+            SubjectPublicKeyInfo spki)
+        {
+            this.sender = sender;
+            this.publicKey = spki;
+        }
+
+        /** Creates a new PopoSigningKeyInput using password-based MAC. */
+        public PopoSigningKeyInput(
+            PKMacValue pkmac,
+            SubjectPublicKeyInfo spki)
+        {
+            this.publicKeyMac = pkmac;
+            this.publicKey = spki;
+        }
+
+        /** Returns the sender field, or null if authInfo is publicKeyMac */
+        public virtual GeneralName Sender
+        {
+            get { return sender; }
+        }
+
+        /** Returns the publicKeyMac field, or null if authInfo is sender */
+        public virtual PKMacValue PublicKeyMac
+        {
+            get { return publicKeyMac; }
+        }
+
+        public virtual SubjectPublicKeyInfo PublicKey
+        {
+            get { return publicKey; }
+        }
+
+        /**
+         * <pre>
+         * PopoSigningKeyInput ::= SEQUENCE {
+         *        authInfo             CHOICE {
+         *                                 sender              [0] GeneralName,
+         *                                 -- used only if an authenticated identity has been
+         *                                 -- established for the sender (e.g., a DN from a
+         *                                 -- previously-issued and currently-valid certificate
+         *                                 publicKeyMac        PKMacValue },
+         *                                 -- used if no authenticated GeneralName currently exists for
+         *                                 -- the sender; publicKeyMac contains a password-based MAC
+         *                                 -- on the DER-encoded value of publicKey
+         *        publicKey           SubjectPublicKeyInfo }  -- from CertTemplate
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (sender != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, sender));
+            }
+            else
+            {
+                v.Add(publicKeyMac);
+            }
+
+            v.Add(publicKey);
+
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/ProofOfPossession.cs b/crypto/src/asn1/crmf/ProofOfPossession.cs
new file mode 100644
index 000000000..fc00edb32
--- /dev/null
+++ b/crypto/src/asn1/crmf/ProofOfPossession.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class ProofOfPossession
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int TYPE_RA_VERIFIED = 0;
+        public const int TYPE_SIGNING_KEY = 1;
+        public const int TYPE_KEY_ENCIPHERMENT = 2;
+        public const int TYPE_KEY_AGREEMENT = 3;
+
+        private readonly int tagNo;
+        private readonly Asn1Encodable obj;
+
+        private ProofOfPossession(Asn1TaggedObject tagged)
+        {
+            tagNo = tagged.TagNo;
+            switch (tagNo)
+            {
+            case 0:
+                obj = DerNull.Instance;
+                break;
+            case 1:
+                obj = PopoSigningKey.GetInstance(tagged, false);
+                break;
+            case 2:
+            case 3:
+                obj = PopoPrivKey.GetInstance(tagged, false);
+                break;
+            default:
+                throw new ArgumentException("unknown tag: " + tagNo, "tagged");
+            }
+        }
+
+        public static ProofOfPossession GetInstance(object obj)
+        {
+            if (obj is ProofOfPossession)
+                return (ProofOfPossession)obj;
+
+            if (obj is Asn1TaggedObject)
+                return new ProofOfPossession((Asn1TaggedObject)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /** Creates a ProofOfPossession with type raVerified. */
+        public ProofOfPossession()
+        {
+            tagNo = TYPE_RA_VERIFIED;
+            obj = DerNull.Instance;
+        }
+
+        /** Creates a ProofOfPossession for a signing key. */
+        public ProofOfPossession(PopoSigningKey Poposk)
+        {
+            tagNo = TYPE_SIGNING_KEY;
+            obj = Poposk;
+        }
+
+        /**
+         * Creates a ProofOfPossession for key encipherment or agreement.
+         * @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT
+         */
+        public ProofOfPossession(int type, PopoPrivKey privkey)
+        {
+            tagNo = type;
+            obj = privkey;
+        }
+
+        public virtual int Type
+        {
+            get { return tagNo; }
+        }
+
+        public virtual Asn1Encodable Object
+        {
+            get { return obj; }
+        }
+
+        /**
+         * <pre>
+         * ProofOfPossession ::= CHOICE {
+         *                           raVerified        [0] NULL,
+         *                           -- used if the RA has already verified that the requester is in
+         *                           -- possession of the private key
+         *                           signature         [1] PopoSigningKey,
+         *                           keyEncipherment   [2] PopoPrivKey,
+         *                           keyAgreement      [3] PopoPrivKey }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, obj);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/SinglePubInfo.cs b/crypto/src/asn1/crmf/SinglePubInfo.cs
new file mode 100644
index 000000000..eaf8a3efd
--- /dev/null
+++ b/crypto/src/asn1/crmf/SinglePubInfo.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class SinglePubInfo
+        : Asn1Encodable
+    {
+        private readonly DerInteger pubMethod;
+        private readonly GeneralName pubLocation;
+
+        private SinglePubInfo(Asn1Sequence seq)
+        {
+            pubMethod = DerInteger.GetInstance(seq[0]);
+
+            if (seq.Count == 2)
+            {
+                pubLocation = GeneralName.GetInstance(seq[1]);
+            }
+        }
+
+        public static SinglePubInfo GetInstance(object obj)
+        {
+            if (obj is SinglePubInfo)
+                return (SinglePubInfo)obj;
+
+            if (obj is Asn1Sequence)
+                return new SinglePubInfo((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        public virtual GeneralName PubLocation
+        {
+            get { return pubLocation; }
+        }
+
+        /**
+         * <pre>
+         * SinglePubInfo ::= SEQUENCE {
+         *        pubMethod    INTEGER {
+         *           dontCare    (0),
+         *           x500        (1),
+         *           web         (2),
+         *           ldap        (3) },
+         *       pubLocation  GeneralName OPTIONAL }
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(pubMethod);
+            v.AddOptional(pubLocation);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/crmf/SubsequentMessage.cs b/crypto/src/asn1/crmf/SubsequentMessage.cs
new file mode 100644
index 000000000..cc1c16492
--- /dev/null
+++ b/crypto/src/asn1/crmf/SubsequentMessage.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class SubsequentMessage
+        : DerInteger
+    {
+        public static readonly SubsequentMessage encrCert = new SubsequentMessage(0);
+        public static readonly SubsequentMessage challengeResp = new SubsequentMessage(1);
+    
+        private SubsequentMessage(int value)
+            : base(value)
+        {
+        }
+
+        public static SubsequentMessage ValueOf(int value)
+        {
+            if (value == 0)
+                return encrCert;
+
+            if (value == 1)
+                return challengeResp;
+
+            throw new ArgumentException("unknown value: " + value, "value");
+        }
+    }
+}
diff --git a/crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs b/crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
index 6e0e023b9..e2f2c1848 100644
--- a/crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
+++ b/crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
@@ -11,10 +11,13 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
         public const string GostID = "1.2.643.2.2";
 
 		public static readonly DerObjectIdentifier GostR3411 = new DerObjectIdentifier(GostID + ".9");
+        public static readonly DerObjectIdentifier GostR3411Hmac = new DerObjectIdentifier(GostID + ".10");
 
-		public static readonly DerObjectIdentifier GostR28147Cbc = new DerObjectIdentifier(GostID + ".21");
+        public static readonly DerObjectIdentifier GostR28147Cbc = new DerObjectIdentifier(GostID + ".21");
 
-		public static readonly DerObjectIdentifier GostR3410x94 = new DerObjectIdentifier(GostID + ".20");
+        public static readonly DerObjectIdentifier ID_Gost28147_89_CryptoPro_A_ParamSet = new DerObjectIdentifier(GostID + ".31.1");
+
+        public static readonly DerObjectIdentifier GostR3410x94 = new DerObjectIdentifier(GostID + ".20");
         public static readonly DerObjectIdentifier GostR3410x2001 = new DerObjectIdentifier(GostID + ".19");
         public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x94 = new DerObjectIdentifier(GostID + ".4");
         public static readonly DerObjectIdentifier GostR3411x94WithGostR3410x2001 = new DerObjectIdentifier(GostID + ".3");
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
index 998e0e06f..ca57c283d 100644
--- a/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
+++ b/crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -15,9 +15,9 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
     */
     public sealed class ECGost3410NamedCurves
     {
-		private ECGost3410NamedCurves()
-		{
-		}
+        private ECGost3410NamedCurves()
+        {
+        }
 
         internal static readonly IDictionary objIds = Platform.CreateHashtable();
         internal static readonly IDictionary parameters = Platform.CreateHashtable();
@@ -31,17 +31,18 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             FpCurve curve = new FpCurve(
                 mod_p, // p
                 new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
-                new BigInteger("166")); // b
+                new BigInteger("166"), // b
+                mod_q,
+                BigInteger.One);
 
             ECDomainParameters ecParams = new ECDomainParameters(
                 curve,
-				curve.CreatePoint(
-					BigInteger.One, // x
-					new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y
-					false),
+                curve.CreatePoint(
+                    new BigInteger("1"), // x
+                    new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
                 mod_q);
 
-			parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams;
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams;
 
             mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
             mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
@@ -49,14 +50,15 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             curve = new FpCurve(
                 mod_p, // p
                 new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"),
-                new BigInteger("166"));
+                new BigInteger("166"),
+                mod_q,
+                BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
-				curve.CreatePoint(
-					BigInteger.One, // x
-					new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y
-					false),
+                curve.CreatePoint(
+                    new BigInteger("1"), // x
+                    new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
                 mod_q);
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = ecParams;
@@ -67,14 +69,15 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             curve = new FpCurve(
                 mod_p, // p
                 new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a
-                new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595")); // b
+                new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b
+                mod_q,
+                BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
-					BigInteger.One, // x
-					new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124"), // y
-					false),
+                    new BigInteger("1"), // x
+                    new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y
                 mod_q); // q
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = ecParams;
@@ -85,14 +88,15 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             curve = new FpCurve(
                 mod_p, // p
                 new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"),
-                new BigInteger("32858"));
+                new BigInteger("32858"),
+                mod_q,
+                BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
-					BigInteger.Zero, // x
-					new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y
-					false),
+                    new BigInteger("0"),
+                    new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")),
                 mod_q);
 
             parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = ecParams;
@@ -102,17 +106,18 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             curve = new FpCurve(
                 mod_p, // p
                 new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a
-                new BigInteger("32858")); // b
+                new BigInteger("32858"), // b
+                mod_q,
+                BigInteger.One);
 
             ecParams = new ECDomainParameters(
                 curve,
                 curve.CreatePoint(
-					BigInteger.Zero, // x
-					new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y
-					false),
+                    new BigInteger("0"), // x
+                    new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y
                 mod_q); // q
 
-			parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams;
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams;
 
             objIds["GostR3410-2001-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProA;
             objIds["GostR3410-2001-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProB;
@@ -139,14 +144,14 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             return (ECDomainParameters) parameters[oid];
         }
 
-		/**
-		 * returns an enumeration containing the name strings for curves
-		 * contained in this structure.
-		 */
-		public static IEnumerable Names
-		{
-			get { return new EnumerableProxy(objIds.Keys); }
-		}
+        /**
+         * returns an enumeration containing the name strings for curves
+         * contained in this structure.
+         */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(objIds.Keys); }
+        }
 
         public static ECDomainParameters GetByName(
             string name)
@@ -170,8 +175,8 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             return (string) names[oid];
         }
 
-		public static DerObjectIdentifier GetOid(
-			string name)
+        public static DerObjectIdentifier GetOid(
+            string name)
         {
             return (DerObjectIdentifier) objIds[name];
         }
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs b/crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
new file mode 100644
index 000000000..6f4435d7b
--- /dev/null
+++ b/crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class ECGost3410ParamSetParameters
+        : Asn1Encodable
+    {
+        internal readonly DerInteger p, q, a, b, x, y;
+
+        public static ECGost3410ParamSetParameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+        public static ECGost3410ParamSetParameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is ECGost3410ParamSetParameters)
+            {
+                return (ECGost3410ParamSetParameters) obj;
+            }
+
+            if (obj is Asn1Sequence)
+            {
+                return new ECGost3410ParamSetParameters((Asn1Sequence) obj);
+            }
+
+            throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+        public ECGost3410ParamSetParameters(
+            BigInteger a,
+            BigInteger b,
+            BigInteger p,
+            BigInteger q,
+            int        x,
+            BigInteger y)
+        {
+            this.a = new DerInteger(a);
+            this.b = new DerInteger(b);
+            this.p = new DerInteger(p);
+            this.q = new DerInteger(q);
+            this.x = new DerInteger(x);
+            this.y = new DerInteger(y);
+        }
+
+        public ECGost3410ParamSetParameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 6)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.a = DerInteger.GetInstance(seq[0]);
+			this.b = DerInteger.GetInstance(seq[1]);
+			this.p = DerInteger.GetInstance(seq[2]);
+			this.q = DerInteger.GetInstance(seq[3]);
+			this.x = DerInteger.GetInstance(seq[4]);
+			this.y = DerInteger.GetInstance(seq[5]);
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.PositiveValue; }
+		}
+
+		public BigInteger A
+		{
+			get { return a.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(a, b, p, q, x, y);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cryptopro/GOST28147Parameters.cs b/crypto/src/asn1/cryptopro/GOST28147Parameters.cs
new file mode 100644
index 000000000..eb7e0e3f6
--- /dev/null
+++ b/crypto/src/asn1/cryptopro/GOST28147Parameters.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class Gost28147Parameters
+        : Asn1Encodable
+    {
+        private readonly Asn1OctetString iv;
+        private readonly DerObjectIdentifier paramSet;
+
+		public static Gost28147Parameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static Gost28147Parameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Gost28147Parameters)
+            {
+                return (Gost28147Parameters) obj;
+            }
+
+            if (obj is Asn1Sequence)
+            {
+                return new Gost28147Parameters((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+        private Gost28147Parameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.iv = Asn1OctetString.GetInstance(seq[0]);
+			this.paramSet = DerObjectIdentifier.GetInstance(seq[1]);
+        }
+
+		/**
+         * <pre>
+         * Gost28147-89-Parameters ::=
+         *               SEQUENCE {
+         *                       iv                   Gost28147-89-IV,
+         *                       encryptionParamSet   OBJECT IDENTIFIER
+         *                }
+         *
+         *   Gost28147-89-IV ::= OCTET STRING (SIZE (8))
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(iv, paramSet);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs b/crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs
new file mode 100644
index 000000000..66dba51d7
--- /dev/null
+++ b/crypto/src/asn1/cryptopro/GOST3410NamedParameters.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    /**
+    * table of the available named parameters for GOST 3410-94.
+    */
+    public sealed class Gost3410NamedParameters
+    {
+		private Gost3410NamedParameters()
+		{
+		}
+
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary parameters = Platform.CreateHashtable();
+
+        private static readonly Gost3410ParamSetParameters cryptoProA = new Gost3410ParamSetParameters(
+            1024,
+            new BigInteger("127021248288932417465907042777176443525787653508916535812817507265705031260985098497423188333483401180925999995120988934130659205614996724254121049274349357074920312769561451689224110579311248812610229678534638401693520013288995000362260684222750813532307004517341633685004541062586971416883686778842537820383"),
+            new BigInteger("68363196144955700784444165611827252895102170888761442055095051287550314083023"),
+            new BigInteger("100997906755055304772081815535925224869841082572053457874823515875577147990529272777244152852699298796483356699682842027972896052747173175480590485607134746852141928680912561502802222185647539190902656116367847270145019066794290930185446216399730872221732889830323194097355403213400972588322876850946740663962")
+            //            validationAlgorithm {
+            //                    algorithm
+            //                        id-GostR3410-94-bBis,
+            //                    parameters
+            //                        GostR3410-94-ValidationBisParameters: {
+            //                            x0      1376285941,
+            //                            c       3996757427
+            //                        }
+            //                }
+
+            );
+
+        private static readonly Gost3410ParamSetParameters cryptoProB = new Gost3410ParamSetParameters(
+            1024,
+            new BigInteger("139454871199115825601409655107690713107041707059928031797758001454375765357722984094124368522288239833039114681648076688236921220737322672160740747771700911134550432053804647694904686120113087816240740184800477047157336662926249423571248823968542221753660143391485680840520336859458494803187341288580489525163"),
+            new BigInteger("79885141663410976897627118935756323747307951916507639758300472692338873533959"),
+            new BigInteger("42941826148615804143873447737955502392672345968607143066798112994089471231420027060385216699563848719957657284814898909770759462613437669456364882730370838934791080835932647976778601915343474400961034231316672578686920482194932878633360203384797092684342247621055760235016132614780652761028509445403338652341")
+            //    validationAlgorithm {
+            //            algorithm
+            //                id-GostR3410-94-bBis,
+            //            parameters
+            //                GostR3410-94-ValidationBisParameters: {
+            //                    x0      1536654555,
+            //                    c       1855361757,
+            //                    d       14408629386140014567655
+            //4902939282056547857802241461782996702017713059974755104394739915140
+            //6115284791024439062735788342744854120601660303926203867703556828005
+            //8957203818114895398976594425537561271800850306
+            //                }
+            //        }
+            //}
+            );
+
+        private static readonly Gost3410ParamSetParameters cryptoProXchA = new Gost3410ParamSetParameters(
+            1024,
+            new BigInteger("142011741597563481196368286022318089743276138395243738762872573441927459393512718973631166078467600360848946623567625795282774719212241929071046134208380636394084512691828894000571524625445295769349356752728956831541775441763139384457191755096847107846595662547942312293338483924514339614727760681880609734239"),
+            new BigInteger("91771529896554605945588149018382750217296858393520724172743325725474374979801"),
+            new BigInteger("133531813272720673433859519948319001217942375967847486899482359599369642528734712461590403327731821410328012529253871914788598993103310567744136196364803064721377826656898686468463277710150809401182608770201615324990468332931294920912776241137878030224355746606283971659376426832674269780880061631528163475887")
+            );
+
+		static Gost3410NamedParameters()
+        {
+            parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProA] = cryptoProA;
+            parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProB] = cryptoProB;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProC] = cryptoProC;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProD] = cryptoProD;
+            parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA] = cryptoProXchA;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchB] = cryptoProXchA;
+            //parameters[CryptoProObjectIdentifiers.GostR3410x94CryptoProXchC] = cryptoProXchA;
+
+			objIds["GostR3410-94-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProA;
+            objIds["GostR3410-94-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProB;
+            objIds["GostR3410-94-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x94CryptoProXchA;
+        }
+
+		/**
+        * return the GOST3410ParamSetParameters object for the given OID, null if it
+        * isn't present.
+        *
+        * @param oid an object identifier representing a named parameters, if present.
+        */
+        public static Gost3410ParamSetParameters GetByOid(
+            DerObjectIdentifier oid)
+        {
+            return (Gost3410ParamSetParameters) parameters[oid];
+        }
+
+		/**
+        * returns an enumeration containing the name strings for parameters
+        * contained in this structure.
+        */
+        public static IEnumerable Names
+        {
+			get { return new EnumerableProxy(objIds.Keys); }
+        }
+
+		public static Gost3410ParamSetParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name];
+
+            if (oid != null)
+            {
+                return (Gost3410ParamSetParameters) parameters[oid];
+            }
+
+            return null;
+        }
+
+        public static DerObjectIdentifier GetOid(
+			string name)
+        {
+            return (DerObjectIdentifier) objIds[name];
+        }
+    }
+}
diff --git a/crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs b/crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
new file mode 100644
index 000000000..f133cdf1b
--- /dev/null
+++ b/crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class Gost3410ParamSetParameters
+        : Asn1Encodable
+    {
+        private readonly int keySize;
+        private readonly DerInteger	p, q, a;
+
+		public static Gost3410ParamSetParameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static Gost3410ParamSetParameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Gost3410ParamSetParameters)
+            {
+                return (Gost3410ParamSetParameters) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Gost3410ParamSetParameters((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+		public Gost3410ParamSetParameters(
+            int			keySize,
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	a)
+        {
+            this.keySize = keySize;
+            this.p = new DerInteger(p);
+            this.q = new DerInteger(q);
+            this.a = new DerInteger(a);
+        }
+
+		private Gost3410ParamSetParameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 4)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.keySize = DerInteger.GetInstance(seq[0]).Value.IntValue;
+			this.p = DerInteger.GetInstance(seq[1]);
+            this.q = DerInteger.GetInstance(seq[2]);
+			this.a = DerInteger.GetInstance(seq[3]);
+        }
+
+		public int KeySize
+		{
+			get { return keySize; }
+		}
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.PositiveValue; }
+		}
+
+		public BigInteger A
+		{
+			get { return a.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(new DerInteger(keySize), p, q, a);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs b/crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs
new file mode 100644
index 000000000..8bc1460af
--- /dev/null
+++ b/crypto/src/asn1/cryptopro/GOST3410PublicKeyAlgParameters.cs
@@ -0,0 +1,99 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public class Gost3410PublicKeyAlgParameters
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	publicKeyParamSet;
+        private DerObjectIdentifier	digestParamSet;
+        private DerObjectIdentifier	encryptionParamSet;
+
+		public static Gost3410PublicKeyAlgParameters GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static Gost3410PublicKeyAlgParameters GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Gost3410PublicKeyAlgParameters)
+            {
+                return (Gost3410PublicKeyAlgParameters) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Gost3410PublicKeyAlgParameters((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid GOST3410Parameter: " + obj.GetType().Name);
+        }
+
+		public Gost3410PublicKeyAlgParameters(
+            DerObjectIdentifier	publicKeyParamSet,
+            DerObjectIdentifier	digestParamSet)
+			: this (publicKeyParamSet, digestParamSet, null)
+        {
+        }
+
+		public Gost3410PublicKeyAlgParameters(
+            DerObjectIdentifier  publicKeyParamSet,
+            DerObjectIdentifier  digestParamSet,
+            DerObjectIdentifier  encryptionParamSet)
+        {
+			if (publicKeyParamSet == null)
+				throw new ArgumentNullException("publicKeyParamSet");
+			if (digestParamSet == null)
+				throw new ArgumentNullException("digestParamSet");
+
+			this.publicKeyParamSet = publicKeyParamSet;
+            this.digestParamSet = digestParamSet;
+            this.encryptionParamSet = encryptionParamSet;
+        }
+
+		public Gost3410PublicKeyAlgParameters(
+            Asn1Sequence seq)
+        {
+            this.publicKeyParamSet = (DerObjectIdentifier) seq[0];
+            this.digestParamSet = (DerObjectIdentifier) seq[1];
+
+			if (seq.Count > 2)
+            {
+                this.encryptionParamSet = (DerObjectIdentifier) seq[2];
+            }
+        }
+
+		public DerObjectIdentifier PublicKeyParamSet
+		{
+			get { return publicKeyParamSet; }
+		}
+
+		public DerObjectIdentifier DigestParamSet
+		{
+			get { return digestParamSet; }
+		}
+
+		public DerObjectIdentifier EncryptionParamSet
+		{
+			get { return encryptionParamSet; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				publicKeyParamSet, digestParamSet);
+
+			if (encryptionParamSet != null)
+            {
+                v.Add(encryptionParamSet);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/eac/EACObjectIdentifiers.cs b/crypto/src/asn1/eac/EACObjectIdentifiers.cs
new file mode 100644
index 000000000..d54ef0eba
--- /dev/null
+++ b/crypto/src/asn1/eac/EACObjectIdentifiers.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Eac
+{
+	public abstract class EacObjectIdentifiers
+	{
+		// bsi-de OBJECT IDENTIFIER ::= {
+		//         itu-t(0) identified-organization(4) etsi(0)
+		//         reserved(127) etsi-identified-organization(0) 7
+		//     }
+		public static readonly DerObjectIdentifier bsi_de = new DerObjectIdentifier("0.4.0.127.0.7");
+
+		// id-PK OBJECT IDENTIFIER ::= {
+		//         bsi-de protocols(2) smartcard(2) 1
+		//     }
+		public static readonly DerObjectIdentifier id_PK = new DerObjectIdentifier(bsi_de + ".2.2.1");
+
+		public static readonly DerObjectIdentifier id_PK_DH = new DerObjectIdentifier(id_PK + ".1");
+		public static readonly DerObjectIdentifier id_PK_ECDH = new DerObjectIdentifier(id_PK + ".2");
+
+		// id-CA OBJECT IDENTIFIER ::= {
+		//         bsi-de protocols(2) smartcard(2) 3
+		//     }
+		public static readonly DerObjectIdentifier id_CA = new DerObjectIdentifier(bsi_de + ".2.2.3");
+		public static readonly DerObjectIdentifier id_CA_DH = new DerObjectIdentifier(id_CA + ".1");
+		public static readonly DerObjectIdentifier id_CA_DH_3DES_CBC_CBC = new DerObjectIdentifier(id_CA_DH + ".1");
+		public static readonly DerObjectIdentifier id_CA_ECDH = new DerObjectIdentifier(id_CA + ".2");
+		public static readonly DerObjectIdentifier id_CA_ECDH_3DES_CBC_CBC = new DerObjectIdentifier(id_CA_ECDH + ".1");
+
+		//
+		// id-TA OBJECT IDENTIFIER ::= {
+		//     bsi-de protocols(2) smartcard(2) 2
+		// }
+		public static readonly DerObjectIdentifier id_TA = new DerObjectIdentifier(bsi_de + ".2.2.2");
+
+		public static readonly DerObjectIdentifier id_TA_RSA = new DerObjectIdentifier(id_TA + ".1");
+		public static readonly DerObjectIdentifier id_TA_RSA_v1_5_SHA_1 = new DerObjectIdentifier(id_TA_RSA + ".1");
+		public static readonly DerObjectIdentifier id_TA_RSA_v1_5_SHA_256 = new DerObjectIdentifier(id_TA_RSA + ".2");
+		public static readonly DerObjectIdentifier id_TA_RSA_PSS_SHA_1 = new DerObjectIdentifier(id_TA_RSA + ".3");
+		public static readonly DerObjectIdentifier id_TA_RSA_PSS_SHA_256 = new DerObjectIdentifier(id_TA_RSA + ".4");
+		public static readonly DerObjectIdentifier id_TA_ECDSA = new DerObjectIdentifier(id_TA + ".2");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_1 = new DerObjectIdentifier(id_TA_ECDSA + ".1");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_224 = new DerObjectIdentifier(id_TA_ECDSA + ".2");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_256 = new DerObjectIdentifier(id_TA_ECDSA + ".3");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_384 = new DerObjectIdentifier(id_TA_ECDSA + ".4");
+		public static readonly DerObjectIdentifier id_TA_ECDSA_SHA_512 = new DerObjectIdentifier(id_TA_ECDSA + ".5");
+	}
+}
diff --git a/crypto/src/asn1/esf/CertificateValues.cs b/crypto/src/asn1/esf/CertificateValues.cs
new file mode 100644
index 000000000..e0fb39b83
--- /dev/null
+++ b/crypto/src/asn1/esf/CertificateValues.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.3.1 Certificate Values Attribute Definition
+	/// <code>
+	/// CertificateValues ::= SEQUENCE OF Certificate
+	/// </code>
+	/// </remarks>
+	public class CertificateValues
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence certificates;
+
+		public static CertificateValues GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertificateValues)
+				return (CertificateValues) obj;
+
+			if (obj is Asn1Sequence)
+				return new CertificateValues((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CertificateValues' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CertificateValues(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				X509CertificateStructure.GetInstance(ae.ToAsn1Object());
+			}
+
+			this.certificates = seq;
+		}
+
+		public CertificateValues(
+			params X509CertificateStructure[] certificates)
+		{
+			if (certificates == null)
+				throw new ArgumentNullException("certificates");
+
+			this.certificates = new DerSequence(certificates);
+		}
+
+		public CertificateValues(
+			IEnumerable certificates)
+		{
+			if (certificates == null)
+				throw new ArgumentNullException("certificates");
+			if (!CollectionUtilities.CheckElementsAreOfType(certificates, typeof(X509CertificateStructure)))
+				throw new ArgumentException("Must contain only 'X509CertificateStructure' objects", "certificates");
+
+			this.certificates = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(certificates));
+		}
+
+		public X509CertificateStructure[] GetCertificates()
+		{
+			X509CertificateStructure[] result = new X509CertificateStructure[certificates.Count];
+			for (int i = 0; i < certificates.Count; ++i)
+			{
+				result[i] = X509CertificateStructure.GetInstance(certificates[i]);
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return certificates;
+		}
+ 	}
+}
diff --git a/crypto/src/asn1/esf/CommitmentTypeIdentifier.cs b/crypto/src/asn1/esf/CommitmentTypeIdentifier.cs
new file mode 100644
index 000000000..65cd45b4a
--- /dev/null
+++ b/crypto/src/asn1/esf/CommitmentTypeIdentifier.cs
@@ -0,0 +1,17 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    public abstract class CommitmentTypeIdentifier
+    {
+        public static readonly DerObjectIdentifier ProofOfOrigin = PkcsObjectIdentifiers.IdCtiEtsProofOfOrigin;
+        public static readonly DerObjectIdentifier ProofOfReceipt = PkcsObjectIdentifiers.IdCtiEtsProofOfReceipt;
+        public static readonly DerObjectIdentifier ProofOfDelivery = PkcsObjectIdentifiers.IdCtiEtsProofOfDelivery;
+        public static readonly DerObjectIdentifier ProofOfSender = PkcsObjectIdentifiers.IdCtiEtsProofOfSender;
+        public static readonly DerObjectIdentifier ProofOfApproval = PkcsObjectIdentifiers.IdCtiEtsProofOfApproval;
+        public static readonly DerObjectIdentifier ProofOfCreation = PkcsObjectIdentifiers.IdCtiEtsProofOfCreation;
+    }
+}
diff --git a/crypto/src/asn1/esf/CommitmentTypeIndication.cs b/crypto/src/asn1/esf/CommitmentTypeIndication.cs
new file mode 100644
index 000000000..8342cbf8d
--- /dev/null
+++ b/crypto/src/asn1/esf/CommitmentTypeIndication.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    public class CommitmentTypeIndication
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	commitmentTypeId;
+        private readonly Asn1Sequence			commitmentTypeQualifier;
+
+		public static CommitmentTypeIndication GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CommitmentTypeIndication)
+				return (CommitmentTypeIndication) obj;
+
+			if (obj is Asn1Sequence)
+				return new CommitmentTypeIndication((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CommitmentTypeIndication' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		public CommitmentTypeIndication(
+            Asn1Sequence seq)
+        {
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.commitmentTypeId = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+			if (seq.Count > 1)
+            {
+                this.commitmentTypeQualifier = (Asn1Sequence) seq[1].ToAsn1Object();
+            }
+        }
+
+		public CommitmentTypeIndication(
+            DerObjectIdentifier commitmentTypeId)
+			: this(commitmentTypeId, null)
+        {
+        }
+
+		public CommitmentTypeIndication(
+            DerObjectIdentifier	commitmentTypeId,
+            Asn1Sequence		commitmentTypeQualifier)
+        {
+			if (commitmentTypeId == null)
+				throw new ArgumentNullException("commitmentTypeId");
+
+			this.commitmentTypeId = commitmentTypeId;
+
+			if (commitmentTypeQualifier != null)
+			{
+				this.commitmentTypeQualifier = commitmentTypeQualifier;
+			}
+        }
+
+		public DerObjectIdentifier CommitmentTypeID
+		{
+			get { return commitmentTypeId; }
+		}
+
+		public Asn1Sequence CommitmentTypeQualifier
+		{
+			get { return commitmentTypeQualifier; }
+		}
+
+		/**
+        * <pre>
+        * CommitmentTypeIndication ::= SEQUENCE {
+        *      commitmentTypeId   CommitmentTypeIdentifier,
+        *      commitmentTypeQualifier   SEQUENCE SIZE (1..MAX) OF
+        *              CommitmentTypeQualifier OPTIONAL }
+        * </pre>
+        */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(commitmentTypeId);
+
+			if (commitmentTypeQualifier != null)
+            {
+                v.Add(commitmentTypeQualifier);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/esf/CommitmentTypeQualifier.cs b/crypto/src/asn1/esf/CommitmentTypeQualifier.cs
new file mode 100644
index 000000000..09ff70714
--- /dev/null
+++ b/crypto/src/asn1/esf/CommitmentTypeQualifier.cs
@@ -0,0 +1,119 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    /**
+    * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126).
+    *
+    * <pre>
+    *   CommitmentTypeQualifier ::= SEQUENCE {
+    *       commitmentTypeIdentifier  CommitmentTypeIdentifier,
+    *       qualifier          ANY DEFINED BY commitmentTypeIdentifier OPTIONAL }
+    * </pre>
+    */
+    public class CommitmentTypeQualifier
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	commitmentTypeIdentifier;
+        private readonly Asn1Object				qualifier;
+
+        /**
+        * Creates a new <code>CommitmentTypeQualifier</code> instance.
+        *
+        * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+        */
+        public CommitmentTypeQualifier(
+            DerObjectIdentifier commitmentTypeIdentifier)
+            : this(commitmentTypeIdentifier, null)
+        {
+        }
+
+    /**
+        * Creates a new <code>CommitmentTypeQualifier</code> instance.
+        *
+        * @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+        * @param qualifier the qualifier, defined by the above field.
+        */
+        public CommitmentTypeQualifier(
+            DerObjectIdentifier	commitmentTypeIdentifier,
+            Asn1Encodable		qualifier)
+        {
+			if (commitmentTypeIdentifier == null)
+				throw new ArgumentNullException("commitmentTypeIdentifier");
+
+			this.commitmentTypeIdentifier = commitmentTypeIdentifier;
+
+			if (qualifier != null)
+			{
+				this.qualifier = qualifier.ToAsn1Object();
+			}
+        }
+
+        /**
+        * Creates a new <code>CommitmentTypeQualifier</code> instance.
+        *
+        * @param as <code>CommitmentTypeQualifier</code> structure
+        * encoded as an Asn1Sequence.
+        */
+        public CommitmentTypeQualifier(
+            Asn1Sequence seq)
+        {
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			commitmentTypeIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+			if (seq.Count > 1)
+            {
+                qualifier = seq[1].ToAsn1Object();
+            }
+        }
+
+		public static CommitmentTypeQualifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CommitmentTypeQualifier)
+				return (CommitmentTypeQualifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new CommitmentTypeQualifier((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CommitmentTypeQualifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		public DerObjectIdentifier CommitmentTypeIdentifier
+		{
+			get { return commitmentTypeIdentifier; }
+		}
+
+		public Asn1Object Qualifier
+		{
+			get { return qualifier; }
+		}
+
+		/**
+        * Returns a DER-encodable representation of this instance.
+        *
+        * @return a <code>Asn1Object</code> value
+        */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				commitmentTypeIdentifier);
+
+			if (qualifier != null)
+			{
+				v.Add(qualifier);
+			}
+
+			return new DerSequence(v);
+		}
+    }
+}
diff --git a/crypto/src/asn1/esf/CompleteCertificateRefs.cs b/crypto/src/asn1/esf/CompleteCertificateRefs.cs
new file mode 100644
index 000000000..7f1c835c9
--- /dev/null
+++ b/crypto/src/asn1/esf/CompleteCertificateRefs.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.1 Complete Certificate Refs Attribute Definition
+	/// <code>
+	/// CompleteCertificateRefs ::= SEQUENCE OF OtherCertID
+	/// </code>
+	/// </remarks>
+	public class CompleteCertificateRefs
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence otherCertIDs;
+
+		public static CompleteCertificateRefs GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CompleteCertificateRefs)
+				return (CompleteCertificateRefs) obj;
+
+			if (obj is Asn1Sequence)
+				return new CompleteCertificateRefs((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CompleteCertificateRefs' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CompleteCertificateRefs(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				OtherCertID.GetInstance(ae.ToAsn1Object());
+			}
+
+			this.otherCertIDs = seq;
+		}
+
+		public CompleteCertificateRefs(
+			params OtherCertID[] otherCertIDs)
+		{
+			if (otherCertIDs == null)
+				throw new ArgumentNullException("otherCertIDs");
+
+			this.otherCertIDs = new DerSequence(otherCertIDs);
+		}
+
+		public CompleteCertificateRefs(
+			IEnumerable otherCertIDs)
+		{
+			if (otherCertIDs == null)
+				throw new ArgumentNullException("otherCertIDs");
+			if (!CollectionUtilities.CheckElementsAreOfType(otherCertIDs, typeof(OtherCertID)))
+				throw new ArgumentException("Must contain only 'OtherCertID' objects", "otherCertIDs");
+
+			this.otherCertIDs = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(otherCertIDs));
+		}
+
+		public OtherCertID[] GetOtherCertIDs()
+		{
+			OtherCertID[] result = new OtherCertID[otherCertIDs.Count];
+			for (int i = 0; i < otherCertIDs.Count; ++i)
+			{
+				result[i] = OtherCertID.GetInstance(otherCertIDs[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return otherCertIDs;
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/CompleteRevocationRefs.cs b/crypto/src/asn1/esf/CompleteRevocationRefs.cs
new file mode 100644
index 000000000..4e1fb403d
--- /dev/null
+++ b/crypto/src/asn1/esf/CompleteRevocationRefs.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef
+	/// </code>
+	/// </remarks>
+	public class CompleteRevocationRefs
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence crlOcspRefs;
+
+		public static CompleteRevocationRefs GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CompleteRevocationRefs)
+				return (CompleteRevocationRefs) obj;
+
+			if (obj is Asn1Sequence)
+				return new CompleteRevocationRefs((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CompleteRevocationRefs' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CompleteRevocationRefs(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				CrlOcspRef.GetInstance(ae.ToAsn1Object());
+			}
+
+			this.crlOcspRefs = seq;
+		}
+
+		public CompleteRevocationRefs(
+			params CrlOcspRef[] crlOcspRefs)
+		{
+			if (crlOcspRefs == null)
+				throw new ArgumentNullException("crlOcspRefs");
+
+			this.crlOcspRefs = new DerSequence(crlOcspRefs);
+		}
+
+		public CompleteRevocationRefs(
+			IEnumerable crlOcspRefs)
+		{
+			if (crlOcspRefs == null)
+				throw new ArgumentNullException("crlOcspRefs");
+			if (!CollectionUtilities.CheckElementsAreOfType(crlOcspRefs, typeof(CrlOcspRef)))
+				throw new ArgumentException("Must contain only 'CrlOcspRef' objects", "crlOcspRefs");
+
+			this.crlOcspRefs = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(crlOcspRefs));
+		}
+
+		public CrlOcspRef[] GetCrlOcspRefs()
+		{
+			CrlOcspRef[] result = new CrlOcspRef[crlOcspRefs.Count];
+			for (int i = 0; i < crlOcspRefs.Count; ++i)
+			{
+				result[i] = CrlOcspRef.GetInstance(crlOcspRefs[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return crlOcspRefs;
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/CrlIdentifier.cs b/crypto/src/asn1/esf/CrlIdentifier.cs
new file mode 100644
index 000000000..dfff7d838
--- /dev/null
+++ b/crypto/src/asn1/esf/CrlIdentifier.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CrlIdentifier ::= SEQUENCE 
+	/// {
+	/// 	crlissuer		Name,
+	/// 	crlIssuedTime	UTCTime,
+	/// 	crlNumber		INTEGER OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class CrlIdentifier
+		: Asn1Encodable
+	{
+		private readonly X509Name	crlIssuer;
+		private readonly DerUtcTime	crlIssuedTime;
+		private readonly DerInteger	crlNumber;
+
+		public static CrlIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlIdentifier)
+				return (CrlIdentifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlIdentifier((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlIdentifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlIdentifier(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.crlIssuer = X509Name.GetInstance(seq[0]);
+			this.crlIssuedTime = DerUtcTime.GetInstance(seq[1]);
+
+			if (seq.Count > 2)
+			{
+				this.crlNumber = DerInteger.GetInstance(seq[2]);
+			}
+		}
+
+		public CrlIdentifier(
+			X509Name	crlIssuer,
+			DateTime	crlIssuedTime)
+			: this(crlIssuer, crlIssuedTime, null)
+		{
+		}
+
+		public CrlIdentifier(
+			X509Name	crlIssuer,
+			DateTime	crlIssuedTime,
+			BigInteger	crlNumber)
+		{
+			if (crlIssuer == null)
+				throw new ArgumentNullException("crlIssuer");
+
+			this.crlIssuer = crlIssuer;
+			this.crlIssuedTime = new DerUtcTime(crlIssuedTime);
+
+			if (crlNumber != null)
+			{
+				this.crlNumber = new DerInteger(crlNumber);
+			}
+		}
+
+		public X509Name CrlIssuer
+		{
+			get { return crlIssuer; }
+		}
+
+		public DateTime CrlIssuedTime
+		{
+			get { return crlIssuedTime.ToAdjustedDateTime(); }
+		}
+
+		public BigInteger CrlNumber
+		{
+			get { return crlNumber == null ? null : crlNumber.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				crlIssuer.ToAsn1Object(), crlIssuedTime);
+
+			if (crlNumber != null)
+			{
+				v.Add(crlNumber);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/CrlListID.cs b/crypto/src/asn1/esf/CrlListID.cs
new file mode 100644
index 000000000..2aae9b965
--- /dev/null
+++ b/crypto/src/asn1/esf/CrlListID.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CRLListID ::= SEQUENCE 
+	/// {
+	///		crls	SEQUENCE OF CrlValidatedID
+	/// }
+	/// </code>
+	/// </remarks>
+	public class CrlListID
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence crls;
+
+		public static CrlListID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlListID)
+				return (CrlListID) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlListID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlListID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlListID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 1)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.crls = (Asn1Sequence) seq[0].ToAsn1Object();
+
+			foreach (Asn1Encodable ae in this.crls)
+			{
+				CrlValidatedID.GetInstance(ae.ToAsn1Object());
+			}
+		}
+
+		public CrlListID(
+			params CrlValidatedID[] crls)
+		{
+			if (crls == null)
+				throw new ArgumentNullException("crls");
+
+			this.crls = new DerSequence(crls);
+		}
+
+		public CrlListID(
+			IEnumerable crls)
+		{
+			if (crls == null)
+				throw new ArgumentNullException("crls");
+			if (!CollectionUtilities.CheckElementsAreOfType(crls, typeof(CrlValidatedID)))
+				throw new ArgumentException("Must contain only 'CrlValidatedID' objects", "crls");
+
+			this.crls = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(crls));
+		}
+
+		public CrlValidatedID[] GetCrls()
+		{
+			CrlValidatedID[] result = new CrlValidatedID[crls.Count];
+			for (int i = 0; i < crls.Count; ++i)
+			{
+				result[i] = CrlValidatedID.GetInstance(crls[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(crls);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/CrlOcspRef.cs b/crypto/src/asn1/esf/CrlOcspRef.cs
new file mode 100644
index 000000000..c8e10d504
--- /dev/null
+++ b/crypto/src/asn1/esf/CrlOcspRef.cs
@@ -0,0 +1,111 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CrlOcspRef ::= SEQUENCE {
+	///		crlids		[0] CRLListID		OPTIONAL,
+	/// 	ocspids		[1] OcspListID		OPTIONAL,
+	/// 	otherRev	[2] OtherRevRefs	OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class CrlOcspRef
+		: Asn1Encodable
+	{
+		private readonly CrlListID		crlids;
+		private readonly OcspListID		ocspids;
+		private readonly OtherRevRefs	otherRev;
+
+		public static CrlOcspRef GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlOcspRef)
+				return (CrlOcspRef) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlOcspRef((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlOcspRef' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlOcspRef(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			foreach (Asn1TaggedObject taggedObj in seq)
+			{
+				Asn1Object asn1Obj = taggedObj.GetObject();
+
+				switch (taggedObj.TagNo)
+				{
+					case 0:
+						this.crlids = CrlListID.GetInstance(asn1Obj);
+						break;
+					case 1:
+						this.ocspids = OcspListID.GetInstance(asn1Obj);
+						break;
+					case 2:
+						this.otherRev = OtherRevRefs.GetInstance(asn1Obj);
+						break;
+					default:
+						throw new ArgumentException("Illegal tag in CrlOcspRef", "seq");
+				}
+			}
+		}
+
+		public CrlOcspRef(
+			CrlListID		crlids,
+			OcspListID		ocspids,
+			OtherRevRefs	otherRev)
+		{
+			this.crlids = crlids;
+			this.ocspids = ocspids;
+			this.otherRev = otherRev;
+		}
+
+		public CrlListID CrlIDs
+		{
+			get { return crlids; }
+		}
+
+		public OcspListID OcspIDs
+		{
+			get { return ocspids; }
+		}
+
+		public OtherRevRefs OtherRev
+		{
+			get { return otherRev; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (crlids != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, crlids.ToAsn1Object()));
+			}
+
+			if (ocspids != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, ocspids.ToAsn1Object()));
+			}
+
+			if (otherRev != null)
+			{
+				v.Add(new DerTaggedObject(true, 2, otherRev.ToAsn1Object()));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/CrlValidatedID.cs b/crypto/src/asn1/esf/CrlValidatedID.cs
new file mode 100644
index 000000000..165f547a8
--- /dev/null
+++ b/crypto/src/asn1/esf/CrlValidatedID.cs
@@ -0,0 +1,89 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// CrlValidatedID ::= SEQUENCE {
+	///		crlHash			OtherHash,
+	///		crlIdentifier	CrlIdentifier OPTIONAL}
+	/// </code>
+	/// </remarks>
+	public class CrlValidatedID
+		: Asn1Encodable
+	{
+		private readonly OtherHash		crlHash;
+		private readonly CrlIdentifier	crlIdentifier;
+
+		public static CrlValidatedID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CrlValidatedID)
+				return (CrlValidatedID) obj;
+
+			if (obj is Asn1Sequence)
+				return new CrlValidatedID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'CrlValidatedID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private CrlValidatedID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.crlHash = OtherHash.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.crlIdentifier = CrlIdentifier.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public CrlValidatedID(
+			OtherHash crlHash)
+			: this(crlHash, null)
+		{
+		}
+
+		public CrlValidatedID(
+			OtherHash		crlHash,
+			CrlIdentifier	crlIdentifier)
+		{
+			if (crlHash == null)
+				throw new ArgumentNullException("crlHash");
+
+			this.crlHash = crlHash;
+			this.crlIdentifier = crlIdentifier;
+		}
+
+		public OtherHash CrlHash
+		{
+			get { return crlHash; }
+		}
+
+		public CrlIdentifier CrlIdentifier
+		{
+			get { return crlIdentifier; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(crlHash.ToAsn1Object());
+
+			if (crlIdentifier != null)
+			{
+				v.Add(crlIdentifier.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/ESFAttributes.cs b/crypto/src/asn1/esf/ESFAttributes.cs
new file mode 100644
index 000000000..9401ffb8e
--- /dev/null
+++ b/crypto/src/asn1/esf/ESFAttributes.cs
@@ -0,0 +1,25 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+    public abstract class EsfAttributes
+    {
+        public static readonly DerObjectIdentifier SigPolicyId = PkcsObjectIdentifiers.IdAAEtsSigPolicyID;
+        public static readonly DerObjectIdentifier CommitmentType = PkcsObjectIdentifiers.IdAAEtsCommitmentType;
+        public static readonly DerObjectIdentifier SignerLocation = PkcsObjectIdentifiers.IdAAEtsSignerLocation;
+		public static readonly DerObjectIdentifier SignerAttr = PkcsObjectIdentifiers.IdAAEtsSignerAttr;
+		public static readonly DerObjectIdentifier OtherSigCert = PkcsObjectIdentifiers.IdAAEtsOtherSigCert;
+		public static readonly DerObjectIdentifier ContentTimestamp = PkcsObjectIdentifiers.IdAAEtsContentTimestamp;
+		public static readonly DerObjectIdentifier CertificateRefs = PkcsObjectIdentifiers.IdAAEtsCertificateRefs;
+		public static readonly DerObjectIdentifier RevocationRefs = PkcsObjectIdentifiers.IdAAEtsRevocationRefs;
+		public static readonly DerObjectIdentifier CertValues = PkcsObjectIdentifiers.IdAAEtsCertValues;
+		public static readonly DerObjectIdentifier RevocationValues = PkcsObjectIdentifiers.IdAAEtsRevocationValues;
+		public static readonly DerObjectIdentifier EscTimeStamp = PkcsObjectIdentifiers.IdAAEtsEscTimeStamp;
+		public static readonly DerObjectIdentifier CertCrlTimestamp = PkcsObjectIdentifiers.IdAAEtsCertCrlTimestamp;
+		public static readonly DerObjectIdentifier ArchiveTimestamp = PkcsObjectIdentifiers.IdAAEtsArchiveTimestamp;
+		public static readonly DerObjectIdentifier ArchiveTimestampV2 = new DerObjectIdentifier(PkcsObjectIdentifiers.IdAA + ".48");
+	}
+}
diff --git a/crypto/src/asn1/esf/OcspIdentifier.cs b/crypto/src/asn1/esf/OcspIdentifier.cs
new file mode 100644
index 000000000..949b68243
--- /dev/null
+++ b/crypto/src/asn1/esf/OcspIdentifier.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OcspIdentifier ::= SEQUENCE {
+	///		ocspResponderID		ResponderID,
+	///			-- As in OCSP response data
+	///		producedAt			GeneralizedTime
+	///			-- As in OCSP response data
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OcspIdentifier
+		: Asn1Encodable
+	{
+		private readonly ResponderID		ocspResponderID;
+		private readonly DerGeneralizedTime	producedAt;
+
+		public static OcspIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspIdentifier)
+				return (OcspIdentifier) obj;
+
+			if (obj is Asn1Sequence)
+				return new OcspIdentifier((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OcspIdentifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OcspIdentifier(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.ocspResponderID = ResponderID.GetInstance(seq[0].ToAsn1Object());
+			this.producedAt = (DerGeneralizedTime) seq[1].ToAsn1Object();
+		}
+
+		public OcspIdentifier(
+			ResponderID	ocspResponderID,
+			DateTime	producedAt)
+		{
+			if (ocspResponderID == null)
+				throw new ArgumentNullException();
+
+			this.ocspResponderID = ocspResponderID;
+			this.producedAt = new DerGeneralizedTime(producedAt);
+		}
+
+		public ResponderID OcspResponderID
+		{
+			get { return ocspResponderID; }
+		}
+
+		public DateTime ProducedAt
+		{
+			get { return producedAt.ToDateTime(); }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(ocspResponderID, producedAt);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/OcspListID.cs b/crypto/src/asn1/esf/OcspListID.cs
new file mode 100644
index 000000000..1f3f3a337
--- /dev/null
+++ b/crypto/src/asn1/esf/OcspListID.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OcspListID ::=  SEQUENCE {
+	///		ocspResponses	SEQUENCE OF OcspResponsesID
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OcspListID
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence ocspResponses;
+
+		public static OcspListID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspListID)
+				return (OcspListID) obj;
+
+			if (obj is Asn1Sequence)
+				return new OcspListID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OcspListID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OcspListID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 1)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.ocspResponses = (Asn1Sequence) seq[0].ToAsn1Object();
+
+			foreach (Asn1Encodable ae in this.ocspResponses)
+			{
+				OcspResponsesID.GetInstance(ae.ToAsn1Object());
+			}
+		}
+
+		public OcspListID(
+			params OcspResponsesID[] ocspResponses)
+		{
+			if (ocspResponses == null)
+				throw new ArgumentNullException("ocspResponses");
+
+			this.ocspResponses = new DerSequence(ocspResponses);
+		}
+
+		public OcspListID(
+			IEnumerable ocspResponses)
+		{
+			if (ocspResponses == null)
+				throw new ArgumentNullException("ocspResponses");
+			if (!CollectionUtilities.CheckElementsAreOfType(ocspResponses, typeof(OcspResponsesID)))
+				throw new ArgumentException("Must contain only 'OcspResponsesID' objects", "ocspResponses");
+
+			this.ocspResponses = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(ocspResponses));
+		}
+
+		public OcspResponsesID[] GetOcspResponses()
+		{
+			OcspResponsesID[] result = new OcspResponsesID[ocspResponses.Count];
+			for (int i = 0; i < ocspResponses.Count; ++i)
+			{
+				result[i] = OcspResponsesID.GetInstance(ocspResponses[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(ocspResponses);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/OcspResponsesID.cs b/crypto/src/asn1/esf/OcspResponsesID.cs
new file mode 100644
index 000000000..e09508a01
--- /dev/null
+++ b/crypto/src/asn1/esf/OcspResponsesID.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OcspResponsesID ::= SEQUENCE {
+	///		ocspIdentifier	OcspIdentifier,
+	///		ocspRepHash		OtherHash OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OcspResponsesID
+		: Asn1Encodable
+	{
+		private readonly OcspIdentifier	ocspIdentifier;
+		private readonly OtherHash		ocspRepHash;
+
+		public static OcspResponsesID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspResponsesID)
+				return (OcspResponsesID) obj;
+
+			if (obj is Asn1Sequence)
+				return new OcspResponsesID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OcspResponsesID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OcspResponsesID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.ocspIdentifier = OcspIdentifier.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.ocspRepHash = OtherHash.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public OcspResponsesID(
+			OcspIdentifier ocspIdentifier)
+			: this(ocspIdentifier, null)
+		{
+		}
+
+		public OcspResponsesID(
+			OcspIdentifier	ocspIdentifier,
+			OtherHash		ocspRepHash)
+		{
+			if (ocspIdentifier == null)
+				throw new ArgumentNullException("ocspIdentifier");
+
+			this.ocspIdentifier = ocspIdentifier;
+			this.ocspRepHash = ocspRepHash;
+		}
+
+		public OcspIdentifier OcspIdentifier
+		{
+			get { return ocspIdentifier; }
+		}
+
+		public OtherHash OcspRepHash
+		{
+			get { return ocspRepHash; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				ocspIdentifier.ToAsn1Object());
+
+			if (ocspRepHash != null)
+			{
+				v.Add(ocspRepHash.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+
+	}
+}
diff --git a/crypto/src/asn1/esf/OtherCertID.cs b/crypto/src/asn1/esf/OtherCertID.cs
new file mode 100644
index 000000000..6d1255535
--- /dev/null
+++ b/crypto/src/asn1/esf/OtherCertID.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// OtherCertID ::= SEQUENCE {
+	/// 	otherCertHash	OtherHash,
+	/// 	issuerSerial	IssuerSerial OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OtherCertID
+		: Asn1Encodable
+	{
+		private readonly OtherHash		otherCertHash;
+		private readonly IssuerSerial	issuerSerial;
+
+		public static OtherCertID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherCertID)
+				return (OtherCertID) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherCertID((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherCertID' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherCertID(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.otherCertHash = OtherHash.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.issuerSerial = IssuerSerial.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public OtherCertID(
+			OtherHash otherCertHash)
+			: this(otherCertHash, null)
+		{
+		}
+
+		public OtherCertID(
+			OtherHash		otherCertHash,
+			IssuerSerial	issuerSerial)
+		{
+			if (otherCertHash == null)
+				throw new ArgumentNullException("otherCertHash");
+
+			this.otherCertHash = otherCertHash;
+			this.issuerSerial = issuerSerial;
+		}
+
+		public OtherHash OtherCertHash
+		{
+			get { return otherCertHash; }
+		}
+
+		public IssuerSerial IssuerSerial
+		{
+			get { return issuerSerial; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				otherCertHash.ToAsn1Object());
+
+			if (issuerSerial != null)
+			{
+				v.Add(issuerSerial.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+
+	}
+}
diff --git a/crypto/src/asn1/esf/OtherHash.cs b/crypto/src/asn1/esf/OtherHash.cs
new file mode 100644
index 000000000..2ee162478
--- /dev/null
+++ b/crypto/src/asn1/esf/OtherHash.cs
@@ -0,0 +1,88 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// OtherHash ::= CHOICE {
+	///		sha1Hash	OtherHashValue, -- This contains a SHA-1 hash
+	/// 	otherHash	OtherHashAlgAndValue
+	///	}
+	///	
+	///	OtherHashValue ::= OCTET STRING
+	/// </code>
+	/// </remarks>
+	public class OtherHash
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly Asn1OctetString		sha1Hash;
+		private readonly OtherHashAlgAndValue	otherHash;
+
+		public static OtherHash GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherHash)
+				return (OtherHash) obj;
+
+			if (obj is Asn1OctetString)
+				return new OtherHash((Asn1OctetString) obj);
+
+			return new OtherHash(
+				OtherHashAlgAndValue.GetInstance(obj));
+		}
+
+		public OtherHash(
+			byte[] sha1Hash)
+		{
+			if (sha1Hash == null)
+				throw new ArgumentNullException("sha1Hash");
+
+			this.sha1Hash = new DerOctetString(sha1Hash);
+		}
+
+		public OtherHash(
+			Asn1OctetString sha1Hash)
+		{
+			if (sha1Hash == null)
+				throw new ArgumentNullException("sha1Hash");
+
+			this.sha1Hash = sha1Hash;
+		}
+
+		public OtherHash(
+			OtherHashAlgAndValue otherHash)
+		{
+			if (otherHash == null)
+				throw new ArgumentNullException("otherHash");
+
+			this.otherHash = otherHash;
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get
+			{
+				return otherHash == null
+					?	new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1)
+					:	otherHash.HashAlgorithm;
+			}
+		}
+
+		public byte[] GetHashValue()
+		{
+			return otherHash == null
+				?	sha1Hash.GetOctets()
+				:	otherHash.GetHashValue();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return otherHash == null
+				?	sha1Hash
+				:	otherHash.ToAsn1Object();
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/OtherHashAlgAndValue.cs b/crypto/src/asn1/esf/OtherHashAlgAndValue.cs
new file mode 100644
index 000000000..b6bd4f498
--- /dev/null
+++ b/crypto/src/asn1/esf/OtherHashAlgAndValue.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <summary>
+	/// Summary description for OtherHashAlgAndValue.
+	/// </summary>
+	/// <remarks>
+	/// <code>
+	/// OtherHashAlgAndValue ::= SEQUENCE {
+	///		hashAlgorithm	AlgorithmIdentifier,
+	/// 	hashValue		OtherHashValue
+	/// }
+	/// 
+	/// OtherHashValue ::= OCTET STRING
+	/// </code>
+	/// </remarks>
+	public class OtherHashAlgAndValue
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier	hashAlgorithm;
+		private readonly Asn1OctetString		hashValue;
+
+		public static OtherHashAlgAndValue GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherHashAlgAndValue)
+				return (OtherHashAlgAndValue) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherHashAlgAndValue((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherHashAlgAndValue' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherHashAlgAndValue(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0].ToAsn1Object());
+			this.hashValue = (Asn1OctetString) seq[1].ToAsn1Object();
+		}
+
+		public OtherHashAlgAndValue(
+			AlgorithmIdentifier	hashAlgorithm,
+			byte[]				hashValue)
+		{
+			if (hashAlgorithm == null)
+				throw new ArgumentNullException("hashAlgorithm");
+			if (hashValue == null)
+				throw new ArgumentNullException("hashValue");
+
+			this.hashAlgorithm = hashAlgorithm;
+			this.hashValue = new DerOctetString(hashValue);
+		}
+
+		public OtherHashAlgAndValue(
+			AlgorithmIdentifier	hashAlgorithm,
+			Asn1OctetString		hashValue)
+		{
+			if (hashAlgorithm == null)
+				throw new ArgumentNullException("hashAlgorithm");
+			if (hashValue == null)
+				throw new ArgumentNullException("hashValue");
+
+			this.hashAlgorithm = hashAlgorithm;
+			this.hashValue = hashValue;
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public byte[] GetHashValue()
+		{
+			return hashValue.GetOctets();
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, hashValue);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/OtherRevRefs.cs b/crypto/src/asn1/esf/OtherRevRefs.cs
new file mode 100644
index 000000000..56713e3f2
--- /dev/null
+++ b/crypto/src/asn1/esf/OtherRevRefs.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+	/// <code>
+	/// OtherRevRefs ::= SEQUENCE 
+	/// {
+	///		otherRevRefType      OtherRevRefType,
+	///		otherRevRefs         ANY DEFINED BY otherRevRefType
+	/// }
+	///
+	/// OtherRevRefType ::= OBJECT IDENTIFIER
+	/// </code>
+	/// </remarks>
+	public class OtherRevRefs
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	otherRevRefType;
+		private readonly Asn1Object				otherRevRefs;
+
+		public static OtherRevRefs GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherRevRefs)
+				return (OtherRevRefs) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherRevRefs((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherRevRefs' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherRevRefs(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.otherRevRefType = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.otherRevRefs = seq[1].ToAsn1Object();
+		}
+
+		public OtherRevRefs(
+			DerObjectIdentifier	otherRevRefType,
+			Asn1Encodable		otherRevRefs)
+		{
+			if (otherRevRefType == null)
+				throw new ArgumentNullException("otherRevRefType");
+			if (otherRevRefs == null)
+				throw new ArgumentNullException("otherRevRefs");
+
+			this.otherRevRefType = otherRevRefType;
+			this.otherRevRefs = otherRevRefs.ToAsn1Object();
+		}
+
+		public DerObjectIdentifier OtherRevRefType
+		{
+			get { return otherRevRefType; }
+		}
+
+		public Asn1Object OtherRevRefsObject
+		{
+			get { return otherRevRefs; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(otherRevRefType, otherRevRefs);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/OtherRevVals.cs b/crypto/src/asn1/esf/OtherRevVals.cs
new file mode 100644
index 000000000..b88a1a72a
--- /dev/null
+++ b/crypto/src/asn1/esf/OtherRevVals.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 3126: 4.3.2 Revocation Values Attribute Definition
+	/// <code>
+	/// OtherRevVals ::= SEQUENCE 
+	/// {
+	///		otherRevValType      OtherRevValType,
+	///		otherRevVals         ANY DEFINED BY otherRevValType
+	/// }
+	///
+	/// OtherRevValType ::= OBJECT IDENTIFIER
+	/// </code>
+	/// </remarks>
+	public class OtherRevVals
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	otherRevValType;
+		private readonly Asn1Object				otherRevVals;
+
+		public static OtherRevVals GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherRevVals)
+				return (OtherRevVals) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherRevVals((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherRevVals' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherRevVals(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.otherRevValType = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.otherRevVals = seq[1].ToAsn1Object();
+		}
+
+		public OtherRevVals(
+			DerObjectIdentifier	otherRevValType,
+			Asn1Encodable		otherRevVals)
+		{
+			if (otherRevValType == null)
+				throw new ArgumentNullException("otherRevValType");
+			if (otherRevVals == null)
+				throw new ArgumentNullException("otherRevVals");
+
+			this.otherRevValType = otherRevValType;
+			this.otherRevVals = otherRevVals.ToAsn1Object();
+		}
+
+		public DerObjectIdentifier OtherRevValType
+		{
+			get { return otherRevValType; }
+		}
+
+		public Asn1Object OtherRevValsObject
+		{
+			get { return otherRevVals; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(otherRevValType, otherRevVals);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/OtherSigningCertificate.cs b/crypto/src/asn1/esf/OtherSigningCertificate.cs
new file mode 100644
index 000000000..90e385a33
--- /dev/null
+++ b/crypto/src/asn1/esf/OtherSigningCertificate.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// OtherSigningCertificate ::= SEQUENCE {
+	/// 	certs		SEQUENCE OF OtherCertID,
+	/// 	policies	SEQUENCE OF PolicyInformation OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class OtherSigningCertificate
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence	certs;
+		private readonly Asn1Sequence	policies;
+
+		public static OtherSigningCertificate GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OtherSigningCertificate)
+				return (OtherSigningCertificate) obj;
+
+			if (obj is Asn1Sequence)
+				return new OtherSigningCertificate((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'OtherSigningCertificate' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private OtherSigningCertificate(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 1 || seq.Count > 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+
+			if (seq.Count > 1)
+			{
+				this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
+			}
+		}
+
+		public OtherSigningCertificate(
+			params OtherCertID[] certs)
+			: this(certs, null)
+		{
+		}
+
+		public OtherSigningCertificate(
+			OtherCertID[]				certs,
+			params PolicyInformation[]	policies)
+		{
+			if (certs == null)
+				throw new ArgumentNullException("certs");
+
+			this.certs = new DerSequence(certs);
+
+			if (policies != null)
+			{
+				this.policies = new DerSequence(policies);
+			}
+		}
+
+		public OtherSigningCertificate(
+			IEnumerable certs)
+			: this(certs, null)
+		{
+		}
+
+		public OtherSigningCertificate(
+			IEnumerable	certs,
+			IEnumerable	policies)
+		{
+			if (certs == null)
+				throw new ArgumentNullException("certs");
+			if (!CollectionUtilities.CheckElementsAreOfType(certs, typeof(OtherCertID)))
+				throw new ArgumentException("Must contain only 'OtherCertID' objects", "certs");
+
+			this.certs = new DerSequence(
+				Asn1EncodableVector.FromEnumerable(certs));
+
+			if (policies != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(policies, typeof(PolicyInformation)))
+					throw new ArgumentException("Must contain only 'PolicyInformation' objects", "policies");
+
+				this.policies = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(policies));
+			}
+		}
+
+		public OtherCertID[] GetCerts()
+		{
+			OtherCertID[] cs = new OtherCertID[certs.Count];
+			for (int i = 0; i < certs.Count; ++i)
+			{
+				cs[i] = OtherCertID.GetInstance(certs[i].ToAsn1Object());
+			}
+			return cs;
+		}
+
+		public PolicyInformation[] GetPolicies()
+		{
+			if (policies == null)
+				return null;
+
+			PolicyInformation[] ps = new PolicyInformation[policies.Count];
+			for (int i = 0; i < policies.Count; ++i)
+			{
+				ps[i] = PolicyInformation.GetInstance(policies[i].ToAsn1Object());
+			}
+			return ps;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+			if (policies != null)
+			{
+				v.Add(policies);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/RevocationValues.cs b/crypto/src/asn1/esf/RevocationValues.cs
new file mode 100644
index 000000000..a7b47b47a
--- /dev/null
+++ b/crypto/src/asn1/esf/RevocationValues.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// RFC 5126: 6.3.4.  revocation-values Attribute Definition
+	/// <code>
+	/// RevocationValues ::=  SEQUENCE {
+	///		crlVals			[0] SEQUENCE OF CertificateList     OPTIONAL,
+	///		ocspVals		[1] SEQUENCE OF BasicOCSPResponse   OPTIONAL,
+	///		otherRevVals	[2] OtherRevVals OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class RevocationValues
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence	crlVals;
+		private readonly Asn1Sequence	ocspVals;
+		private readonly OtherRevVals	otherRevVals;
+
+		public static RevocationValues GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RevocationValues)
+				return (RevocationValues) obj;
+
+			return new RevocationValues(Asn1Sequence.GetInstance(obj));
+		}
+
+		private RevocationValues(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			foreach (Asn1TaggedObject taggedObj in seq)
+			{
+				Asn1Object asn1Obj = taggedObj.GetObject();
+				switch (taggedObj.TagNo)
+				{
+					case 0:
+						Asn1Sequence crlValsSeq = (Asn1Sequence) asn1Obj;
+						foreach (Asn1Encodable ae in crlValsSeq)
+						{
+							CertificateList.GetInstance(ae.ToAsn1Object());
+						}
+						this.crlVals = crlValsSeq;
+						break;
+					case 1:
+						Asn1Sequence ocspValsSeq = (Asn1Sequence) asn1Obj;
+						foreach (Asn1Encodable ae in ocspValsSeq)
+						{
+							BasicOcspResponse.GetInstance(ae.ToAsn1Object());
+						}
+						this.ocspVals = ocspValsSeq;
+						break;
+					case 2:
+						this.otherRevVals = OtherRevVals.GetInstance(asn1Obj);
+						break;
+					default:
+						throw new ArgumentException("Illegal tag in RevocationValues", "seq");
+				}
+			}
+		}
+
+		public RevocationValues(
+			CertificateList[]	crlVals,
+			BasicOcspResponse[]	ocspVals,
+			OtherRevVals		otherRevVals)
+		{
+			if (crlVals != null)
+			{
+				this.crlVals = new DerSequence(crlVals);
+			}
+
+			if (ocspVals != null)
+			{
+				this.ocspVals = new DerSequence(ocspVals);
+			}
+
+			this.otherRevVals = otherRevVals;
+		}
+
+		public RevocationValues(
+			IEnumerable			crlVals,
+			IEnumerable			ocspVals,
+			OtherRevVals		otherRevVals)
+		{
+			if (crlVals != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(crlVals, typeof(CertificateList)))
+					throw new ArgumentException("Must contain only 'CertificateList' objects", "crlVals");
+
+				this.crlVals = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(crlVals));
+			}
+
+			if (ocspVals != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(ocspVals, typeof(BasicOcspResponse)))
+					throw new ArgumentException("Must contain only 'BasicOcspResponse' objects", "ocspVals");
+
+				this.ocspVals = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(ocspVals));
+			}
+
+			this.otherRevVals = otherRevVals;
+		}
+
+		public CertificateList[] GetCrlVals()
+		{
+			CertificateList[] result = new CertificateList[crlVals.Count];
+			for (int i = 0; i < crlVals.Count; ++i)
+			{
+				result[i] = CertificateList.GetInstance(crlVals[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public BasicOcspResponse[] GetOcspVals()
+		{
+			BasicOcspResponse[] result = new BasicOcspResponse[ocspVals.Count];
+			for (int i = 0; i < ocspVals.Count; ++i)
+			{
+				result[i] = BasicOcspResponse.GetInstance(ocspVals[i].ToAsn1Object());
+			}
+			return result;
+		}
+
+		public OtherRevVals OtherRevVals
+		{
+			get { return otherRevVals; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (crlVals != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, crlVals));
+			}
+
+			if (ocspVals != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, ocspVals));
+			}
+
+			if (otherRevVals != null)
+			{
+				v.Add(new DerTaggedObject(true, 2, otherRevVals.ToAsn1Object()));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/SigPolicyQualifierInfo.cs b/crypto/src/asn1/esf/SigPolicyQualifierInfo.cs
new file mode 100644
index 000000000..2d36bc751
--- /dev/null
+++ b/crypto/src/asn1/esf/SigPolicyQualifierInfo.cs
@@ -0,0 +1,71 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// SigPolicyQualifierInfo ::= SEQUENCE {
+    ///		sigPolicyQualifierId  SigPolicyQualifierId,
+	///		sigQualifier          ANY DEFINED BY sigPolicyQualifierId
+	/// }
+	/// 
+	/// SigPolicyQualifierId ::= OBJECT IDENTIFIER
+	/// </code>
+	/// </remarks>
+	public class SigPolicyQualifierInfo
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	sigPolicyQualifierId;
+		private readonly Asn1Object				sigQualifier;
+
+		public static SigPolicyQualifierInfo GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SigPolicyQualifierInfo)
+				return (SigPolicyQualifierInfo) obj;
+
+			if (obj is Asn1Sequence)
+				return new SigPolicyQualifierInfo((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'SigPolicyQualifierInfo' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private SigPolicyQualifierInfo(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.sigPolicyQualifierId = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.sigQualifier = seq[1].ToAsn1Object();
+		}
+
+		public SigPolicyQualifierInfo(
+			DerObjectIdentifier	sigPolicyQualifierId,
+			Asn1Encodable		sigQualifier)
+		{
+			this.sigPolicyQualifierId = sigPolicyQualifierId;
+			this.sigQualifier = sigQualifier.ToAsn1Object();
+		}
+
+		public DerObjectIdentifier SigPolicyQualifierId
+		{
+			get { return sigPolicyQualifierId; }
+		}
+
+		public Asn1Object SigQualifier
+		{
+			get { return sigQualifier; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(sigPolicyQualifierId, sigQualifier);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/SignaturePolicyId.cs b/crypto/src/asn1/esf/SignaturePolicyId.cs
new file mode 100644
index 000000000..545be2cf4
--- /dev/null
+++ b/crypto/src/asn1/esf/SignaturePolicyId.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// SignaturePolicyId ::= SEQUENCE {
+	/// 	sigPolicyIdentifier		SigPolicyId,
+	/// 	sigPolicyHash			SigPolicyHash,
+	/// 	sigPolicyQualifiers		SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL
+	/// }
+	/// 
+	/// SigPolicyId ::= OBJECT IDENTIFIER
+	/// 
+	/// SigPolicyHash ::= OtherHashAlgAndValue
+	/// </code>
+	/// </remarks>
+	public class SignaturePolicyId
+		: Asn1Encodable
+	{
+		private readonly DerObjectIdentifier	sigPolicyIdentifier;
+		private readonly OtherHashAlgAndValue	sigPolicyHash;
+		private readonly Asn1Sequence			sigPolicyQualifiers;
+
+		public static SignaturePolicyId GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignaturePolicyId)
+				return (SignaturePolicyId) obj;
+
+			if (obj is Asn1Sequence)
+				return new SignaturePolicyId((Asn1Sequence) obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'SignaturePolicyId' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		private SignaturePolicyId(
+			Asn1Sequence seq)
+		{
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.sigPolicyIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object();
+			this.sigPolicyHash = OtherHashAlgAndValue.GetInstance(seq[1].ToAsn1Object());
+
+			if (seq.Count > 2)
+			{
+				this.sigPolicyQualifiers = (Asn1Sequence) seq[2].ToAsn1Object();
+			}
+		}
+
+		public SignaturePolicyId(
+			DerObjectIdentifier		sigPolicyIdentifier,
+			OtherHashAlgAndValue	sigPolicyHash)
+			: this(sigPolicyIdentifier, sigPolicyHash, null)
+		{
+		}
+
+		public SignaturePolicyId(
+			DerObjectIdentifier				sigPolicyIdentifier,
+			OtherHashAlgAndValue			sigPolicyHash,
+			params SigPolicyQualifierInfo[]	sigPolicyQualifiers)
+		{
+			if (sigPolicyIdentifier == null)
+				throw new ArgumentNullException("sigPolicyIdentifier");
+			if (sigPolicyHash == null)
+				throw new ArgumentNullException("sigPolicyHash");
+
+			this.sigPolicyIdentifier = sigPolicyIdentifier;
+			this.sigPolicyHash = sigPolicyHash;
+
+			if (sigPolicyQualifiers != null)
+			{
+				this.sigPolicyQualifiers = new DerSequence(sigPolicyQualifiers);
+			}
+		}
+
+		public SignaturePolicyId(
+			DerObjectIdentifier		sigPolicyIdentifier,
+			OtherHashAlgAndValue	sigPolicyHash,
+			IEnumerable				sigPolicyQualifiers)
+		{
+			if (sigPolicyIdentifier == null)
+				throw new ArgumentNullException("sigPolicyIdentifier");
+			if (sigPolicyHash == null)
+				throw new ArgumentNullException("sigPolicyHash");
+
+			this.sigPolicyIdentifier = sigPolicyIdentifier;
+			this.sigPolicyHash = sigPolicyHash;
+
+			if (sigPolicyQualifiers != null)
+			{
+				if (!CollectionUtilities.CheckElementsAreOfType(sigPolicyQualifiers, typeof(SigPolicyQualifierInfo)))
+					throw new ArgumentException("Must contain only 'SigPolicyQualifierInfo' objects", "sigPolicyQualifiers");
+
+				this.sigPolicyQualifiers = new DerSequence(
+					Asn1EncodableVector.FromEnumerable(sigPolicyQualifiers));
+			}
+		}
+
+		public DerObjectIdentifier SigPolicyIdentifier
+		{
+			get { return sigPolicyIdentifier; }
+		}
+
+		public OtherHashAlgAndValue SigPolicyHash
+		{
+			get { return sigPolicyHash; }
+		}
+
+		public SigPolicyQualifierInfo[] GetSigPolicyQualifiers()
+		{
+			if (sigPolicyQualifiers == null)
+				return null;
+
+			SigPolicyQualifierInfo[] infos = new SigPolicyQualifierInfo[sigPolicyQualifiers.Count];
+			for (int i = 0; i < sigPolicyQualifiers.Count; ++i)
+			{
+				infos[i] = SigPolicyQualifierInfo.GetInstance(sigPolicyQualifiers[i]);
+			}
+			return infos;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				sigPolicyIdentifier, sigPolicyHash.ToAsn1Object());
+
+			if (sigPolicyQualifiers != null)
+			{
+				v.Add(sigPolicyQualifiers.ToAsn1Object());
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/SignaturePolicyIdentifier.cs b/crypto/src/asn1/esf/SignaturePolicyIdentifier.cs
new file mode 100644
index 000000000..3a639f444
--- /dev/null
+++ b/crypto/src/asn1/esf/SignaturePolicyIdentifier.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/// <remarks>
+	/// <code>
+	/// SignaturePolicyIdentifier ::= CHOICE {
+	///		SignaturePolicyId		SignaturePolicyId,
+	///		SignaturePolicyImplied	SignaturePolicyImplied
+	/// }
+	/// 
+	/// SignaturePolicyImplied ::= NULL
+	/// </code>
+	/// </remarks>
+	public class SignaturePolicyIdentifier
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly SignaturePolicyId sigPolicy;
+
+		public static SignaturePolicyIdentifier GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignaturePolicyIdentifier)
+				return (SignaturePolicyIdentifier) obj;
+
+			if (obj is SignaturePolicyId)
+				return new SignaturePolicyIdentifier((SignaturePolicyId) obj);
+
+			if (obj is Asn1Null)
+				return new SignaturePolicyIdentifier();
+
+			throw new ArgumentException(
+				"Unknown object in 'SignaturePolicyIdentifier' factory: "
+					+ obj.GetType().Name,
+				"obj");
+		}
+
+		public SignaturePolicyIdentifier()
+		{
+			this.sigPolicy = null;
+		}
+
+		public SignaturePolicyIdentifier(
+			SignaturePolicyId signaturePolicyId)
+		{
+			if (signaturePolicyId == null)
+				throw new ArgumentNullException("signaturePolicyId");
+
+			this.sigPolicy = signaturePolicyId;
+		}
+
+		public SignaturePolicyId SignaturePolicyId
+		{
+			get { return sigPolicy; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return sigPolicy == null
+				?	DerNull.Instance
+				:	sigPolicy.ToAsn1Object();
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/SignerAttribute.cs b/crypto/src/asn1/esf/SignerAttribute.cs
new file mode 100644
index 000000000..ddee53c69
--- /dev/null
+++ b/crypto/src/asn1/esf/SignerAttribute.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	public class SignerAttribute
+		: Asn1Encodable
+	{
+		private Asn1Sequence			claimedAttributes;
+		private AttributeCertificate	certifiedAttributes;
+
+		public static SignerAttribute GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignerAttribute)
+				return (SignerAttribute) obj;
+
+			if (obj is Asn1Sequence)
+				return new SignerAttribute(obj);
+
+			throw new ArgumentException(
+				"Unknown object in 'SignerAttribute' factory: "
+				+ obj.GetType().Name,
+				"obj");
+		}
+
+		private SignerAttribute(
+			object obj)
+		{
+			Asn1Sequence seq = (Asn1Sequence) obj;
+			DerTaggedObject taggedObject = (DerTaggedObject) seq[0];
+			if (taggedObject.TagNo == 0)
+			{
+				claimedAttributes = Asn1Sequence.GetInstance(taggedObject, true);
+			}
+			else if (taggedObject.TagNo == 1)
+			{
+				certifiedAttributes = AttributeCertificate.GetInstance(taggedObject);
+			}
+			else
+			{
+				throw new ArgumentException("illegal tag.", "obj");
+			}
+		}
+
+		public SignerAttribute(
+			Asn1Sequence claimedAttributes)
+		{
+			this.claimedAttributes = claimedAttributes;
+		}
+
+		public SignerAttribute(
+			AttributeCertificate certifiedAttributes)
+		{
+			this.certifiedAttributes = certifiedAttributes;
+		}
+
+		public virtual Asn1Sequence ClaimedAttributes
+		{
+			get { return claimedAttributes; }
+		}
+
+		public virtual AttributeCertificate CertifiedAttributes
+		{
+			get { return certifiedAttributes; }
+		}
+
+		/**
+		*
+		* <pre>
+		*  SignerAttribute ::= SEQUENCE OF CHOICE {
+		*      claimedAttributes   [0] ClaimedAttributes,
+		*      certifiedAttributes [1] CertifiedAttributes }
+		*
+		*  ClaimedAttributes ::= SEQUENCE OF Attribute
+		*  CertifiedAttributes ::= AttributeCertificate -- as defined in RFC 3281: see clause 4.1.
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (claimedAttributes != null)
+			{
+				v.Add(new DerTaggedObject(0, claimedAttributes));
+			}
+			else
+			{
+				v.Add(new DerTaggedObject(1, certifiedAttributes));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/esf/SignerLocation.cs b/crypto/src/asn1/esf/SignerLocation.cs
new file mode 100644
index 000000000..d2cef51bb
--- /dev/null
+++ b/crypto/src/asn1/esf/SignerLocation.cs
@@ -0,0 +1,144 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Esf
+{
+	/**
+	* Signer-Location attribute (RFC3126).
+	*
+	* <pre>
+	*   SignerLocation ::= SEQUENCE {
+	*       countryName        [0] DirectoryString OPTIONAL,
+	*       localityName       [1] DirectoryString OPTIONAL,
+	*       postalAddress      [2] PostalAddress OPTIONAL }
+	*
+	*   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+	* </pre>
+	*/
+	public class SignerLocation
+		: Asn1Encodable
+	{
+		// TODO Should these be using DirectoryString?
+		private DerUtf8String	countryName;
+		private DerUtf8String	localityName;
+		private Asn1Sequence	postalAddress;
+
+		public SignerLocation(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject obj in seq)
+			{
+				switch (obj.TagNo)
+				{
+					case 0:
+						this.countryName = DerUtf8String.GetInstance(obj, true);
+						break;
+					case 1:
+						this.localityName = DerUtf8String.GetInstance(obj, true);
+						break;
+					case 2:
+						bool isExplicit = obj.IsExplicit();	// handle erroneous implicitly tagged sequences
+						this.postalAddress = Asn1Sequence.GetInstance(obj, isExplicit);
+						if (postalAddress != null && postalAddress.Count > 6)
+							throw new ArgumentException("postal address must contain less than 6 strings");
+						break;
+					default:
+						throw new ArgumentException("illegal tag");
+				}
+			}
+		}
+
+		public SignerLocation(
+			DerUtf8String	countryName,
+			DerUtf8String	localityName,
+			Asn1Sequence	postalAddress)
+		{
+			if (postalAddress != null && postalAddress.Count > 6)
+			{
+				throw new ArgumentException("postal address must contain less than 6 strings");
+			}
+
+			if (countryName != null)
+			{
+				this.countryName = DerUtf8String.GetInstance(countryName.ToAsn1Object());
+			}
+
+			if (localityName != null)
+			{
+				this.localityName = DerUtf8String.GetInstance(localityName.ToAsn1Object());
+			}
+
+			if (postalAddress != null)
+			{
+				this.postalAddress = (Asn1Sequence) postalAddress.ToAsn1Object();
+			}
+		}
+
+		public static SignerLocation GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SignerLocation)
+			{
+				return (SignerLocation) obj;
+			}
+
+			return new SignerLocation(Asn1Sequence.GetInstance(obj));
+		}
+
+		public DerUtf8String CountryName
+		{
+			get { return countryName; }
+		}
+
+		public DerUtf8String LocalityName
+		{
+			get { return localityName; }
+		}
+
+		public Asn1Sequence PostalAddress
+		{
+			get { return postalAddress; }
+		}
+
+		/**
+		* <pre>
+		*   SignerLocation ::= SEQUENCE {
+		*       countryName        [0] DirectoryString OPTIONAL,
+		*       localityName       [1] DirectoryString OPTIONAL,
+		*       postalAddress      [2] PostalAddress OPTIONAL }
+		*
+		*   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
+		*
+		*   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 override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (countryName != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, countryName));
+			}
+
+			if (localityName != null)
+			{
+				v.Add(new DerTaggedObject(true, 1, localityName));
+			}
+
+			if (postalAddress != null)
+			{
+				v.Add(new DerTaggedObject(true, 2, postalAddress));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/ess/ContentHints.cs b/crypto/src/asn1/ess/ContentHints.cs
new file mode 100644
index 000000000..a430fea8d
--- /dev/null
+++ b/crypto/src/asn1/ess/ContentHints.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class ContentHints
+		: Asn1Encodable
+	{
+		private readonly DerUtf8String contentDescription;
+		private readonly DerObjectIdentifier contentType;
+
+		public static ContentHints GetInstance(
+			object o)
+		{
+			if (o == null || o is ContentHints)
+			{
+				return (ContentHints)o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new ContentHints((Asn1Sequence)o);
+			}
+
+			throw new ArgumentException("unknown object in 'ContentHints' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructor
+		 */
+		private ContentHints(
+			Asn1Sequence seq)
+		{
+			IAsn1Convertible field = seq[0];
+			if (field.ToAsn1Object() is DerUtf8String)
+			{
+				contentDescription = DerUtf8String.GetInstance(field);
+				contentType = DerObjectIdentifier.GetInstance(seq[1]);
+			}
+			else
+			{
+				contentType = DerObjectIdentifier.GetInstance(seq[0]);
+			}
+		}
+
+		public ContentHints(
+			DerObjectIdentifier contentType)
+		{
+			this.contentType = contentType;
+			this.contentDescription = null;
+		}
+
+		public ContentHints(
+			DerObjectIdentifier	contentType,
+			DerUtf8String		contentDescription)
+		{
+			this.contentType = contentType;
+			this.contentDescription = contentDescription;
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return contentType; }
+		}
+
+		public DerUtf8String ContentDescription
+		{
+			get { return contentDescription; }
+		}
+
+		/**
+		 * <pre>
+		 * ContentHints ::= SEQUENCE {
+		 *   contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
+		 *   contentType ContentType }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (contentDescription != null)
+			{
+				v.Add(contentDescription);
+			}
+
+			v.Add(contentType);
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/ess/ContentIdentifier.cs b/crypto/src/asn1/ess/ContentIdentifier.cs
new file mode 100644
index 000000000..8058dcc53
--- /dev/null
+++ b/crypto/src/asn1/ess/ContentIdentifier.cs
@@ -0,0 +1,65 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class ContentIdentifier
+		: Asn1Encodable
+	{
+		private Asn1OctetString value;
+
+		public static ContentIdentifier GetInstance(
+			object o)
+		{
+			if (o == null || o is ContentIdentifier)
+			{
+				return (ContentIdentifier) o;
+			}
+
+			if (o is Asn1OctetString)
+			{
+				return new ContentIdentifier((Asn1OctetString) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'ContentIdentifier' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * Create from OCTET STRING whose octets represent the identifier.
+		 */
+		public ContentIdentifier(
+			Asn1OctetString value)
+		{
+			this.value = value;
+		}
+
+		/**
+		 * Create from byte array representing the identifier.
+		 */
+		public ContentIdentifier(
+			byte[] value)
+			: this(new DerOctetString(value))
+		{
+		}
+
+		public Asn1OctetString Value
+		{
+			get { return value; }
+		}
+
+		/**
+		 * The definition of ContentIdentifier is
+		 * <pre>
+		 * ContentIdentifier ::=  OCTET STRING
+		 * </pre>
+		 * id-aa-contentIdentifier OBJECT IDENTIFIER ::= { iso(1)
+		 *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+		 *  smime(16) id-aa(2) 7 }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return value;
+		}
+	}
+}
diff --git a/crypto/src/asn1/ess/ESSCertID.cs b/crypto/src/asn1/ess/ESSCertID.cs
new file mode 100644
index 000000000..4d449a746
--- /dev/null
+++ b/crypto/src/asn1/ess/ESSCertID.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class EssCertID
+		: Asn1Encodable
+	{
+		private Asn1OctetString certHash;
+		private IssuerSerial issuerSerial;
+
+		public static EssCertID GetInstance(
+			object o)
+		{
+			if (o == null || o is EssCertID)
+			{
+				return (EssCertID) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new EssCertID((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'EssCertID' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructor
+		 */
+		public EssCertID(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.certHash = Asn1OctetString.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				issuerSerial = IssuerSerial.GetInstance(seq[1]);
+			}
+		}
+
+		public EssCertID(
+			byte[] hash)
+		{
+			certHash = new DerOctetString(hash);
+		}
+
+		public EssCertID(
+			byte[]			hash,
+			IssuerSerial	issuerSerial)
+		{
+			this.certHash = new DerOctetString(hash);
+			this.issuerSerial = issuerSerial;
+		}
+
+		public byte[] GetCertHash()
+		{
+			return certHash.GetOctets();
+		}
+
+		public IssuerSerial IssuerSerial
+		{
+			get { return issuerSerial; }
+		}
+
+		/**
+		 * <pre>
+		 * EssCertID ::= SEQUENCE {
+		 *     certHash Hash,
+		 *     issuerSerial IssuerSerial OPTIONAL }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certHash);
+
+			if (issuerSerial != null)
+			{
+				v.Add(issuerSerial);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/ess/ESSCertIDv2.cs b/crypto/src/asn1/ess/ESSCertIDv2.cs
index 1d154cd27..35ce699e8 100644
--- a/crypto/src/asn1/ess/ESSCertIDv2.cs
+++ b/crypto/src/asn1/ess/ESSCertIDv2.cs
@@ -6,133 +6,141 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Ess
 {
-	public class EssCertIDv2
-		: Asn1Encodable
-	{
-		private readonly AlgorithmIdentifier hashAlgorithm;
-		private readonly byte[]              certHash;
-		private readonly IssuerSerial        issuerSerial;
-
-		private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier(
-			NistObjectIdentifiers.IdSha256);
-
-		public static EssCertIDv2 GetInstance(
-			object o)
-		{
-			if (o == null || o is EssCertIDv2)
-				return (EssCertIDv2) o;
-
-			if (o is Asn1Sequence)
-				return new EssCertIDv2((Asn1Sequence) o);
-
-			throw new ArgumentException(
-				"unknown object in 'EssCertIDv2' factory : "
-				+ o.GetType().Name + ".");
-		}
-
-		private EssCertIDv2(
-			Asn1Sequence seq)
-		{
-			if (seq.Count > 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
-
-			int count = 0;
-
-			if (seq[0] is Asn1OctetString)
-			{
-				// Default value
-				this.hashAlgorithm = DefaultAlgID;
-			}
-			else
-			{
-				this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object());
-			}
-
-			this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets();
-
-			if (seq.Count > count)
-			{
-				this.issuerSerial = IssuerSerial.GetInstance(
-					Asn1Sequence.GetInstance(seq[count].ToAsn1Object()));
-			}
-		}
-
-		public EssCertIDv2(
-			AlgorithmIdentifier	algId,
-			byte[]				certHash)
-			: this(algId, certHash, null)
-		{
-		}
-
-		public EssCertIDv2(
-			AlgorithmIdentifier	algId,
-			byte[]				certHash,
-			IssuerSerial		issuerSerial)
-		{
-			if (algId == null)
-			{
-				// Default value
-				this.hashAlgorithm = DefaultAlgID;
-			}
-			else
-			{
-				this.hashAlgorithm = algId;
-			}
-
-			this.certHash = certHash;
-			this.issuerSerial = issuerSerial;
-		}
-
-		public AlgorithmIdentifier HashAlgorithm
-		{
-			get { return this.hashAlgorithm; }
-		}
-
-		public byte[] GetCertHash()
-		{
-			return Arrays.Clone(certHash);
-		}
-
-		public IssuerSerial IssuerSerial
-		{
-			get { return issuerSerial; }
-		}
-
-		/**
-		 * <pre>
-		 * EssCertIDv2 ::=  SEQUENCE {
-		 *     hashAlgorithm     AlgorithmIdentifier
-		 *              DEFAULT {algorithm id-sha256},
-		 *     certHash          Hash,
-		 *     issuerSerial      IssuerSerial OPTIONAL
-		 * }
-		 *
-		 * Hash ::= OCTET STRING
-		 *
-		 * IssuerSerial ::= SEQUENCE {
-		 *     issuer         GeneralNames,
-		 *     serialNumber   CertificateSerialNumber
-		 * }
-		 * </pre>
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			Asn1EncodableVector v = new Asn1EncodableVector();
-
-			if (!hashAlgorithm.Equals(DefaultAlgID))
-			{
-				v.Add(hashAlgorithm);
-			}
-
-			v.Add(new DerOctetString(certHash).ToAsn1Object());
-
-			if (issuerSerial != null)
-			{
-				v.Add(issuerSerial);
-			}
-
-			return new DerSequence(v);
-		}
-
-	}
+    public class EssCertIDv2
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier hashAlgorithm;
+        private readonly byte[]              certHash;
+        private readonly IssuerSerial        issuerSerial;
+
+        private static readonly AlgorithmIdentifier DefaultAlgID = new AlgorithmIdentifier(
+            NistObjectIdentifiers.IdSha256);
+
+        public static EssCertIDv2 GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            EssCertIDv2 existing = obj as EssCertIDv2;
+            if (existing != null)
+                return existing;
+            return new EssCertIDv2(Asn1Sequence.GetInstance(obj));
+        }
+
+        private EssCertIDv2(
+            Asn1Sequence seq)
+        {
+            if (seq.Count > 3)
+                throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            int count = 0;
+
+            if (seq[0] is Asn1OctetString)
+            {
+                // Default value
+                this.hashAlgorithm = DefaultAlgID;
+            }
+            else
+            {
+                this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[count++].ToAsn1Object());
+            }
+
+            this.certHash = Asn1OctetString.GetInstance(seq[count++].ToAsn1Object()).GetOctets();
+
+            if (seq.Count > count)
+            {
+                this.issuerSerial = IssuerSerial.GetInstance(
+                    Asn1Sequence.GetInstance(seq[count].ToAsn1Object()));
+            }
+        }
+
+        public EssCertIDv2(byte[] certHash)
+            : this(null, certHash, null)
+        {
+        }
+
+        public EssCertIDv2(
+            AlgorithmIdentifier	algId,
+            byte[]				certHash)
+            : this(algId, certHash, null)
+        {
+        }
+
+        public EssCertIDv2(
+            byte[]              certHash,
+            IssuerSerial        issuerSerial)
+            : this(null, certHash, issuerSerial)
+        {
+        }
+
+        public EssCertIDv2(
+            AlgorithmIdentifier	algId,
+            byte[]				certHash,
+            IssuerSerial		issuerSerial)
+        {
+            if (algId == null)
+            {
+                // Default value
+                this.hashAlgorithm = DefaultAlgID;
+            }
+            else
+            {
+                this.hashAlgorithm = algId;
+            }
+
+            this.certHash = certHash;
+            this.issuerSerial = issuerSerial;
+        }
+
+        public AlgorithmIdentifier HashAlgorithm
+        {
+            get { return this.hashAlgorithm; }
+        }
+
+        public byte[] GetCertHash()
+        {
+            return Arrays.Clone(certHash);
+        }
+
+        public IssuerSerial IssuerSerial
+        {
+            get { return issuerSerial; }
+        }
+
+        /**
+         * <pre>
+         * EssCertIDv2 ::=  SEQUENCE {
+         *     hashAlgorithm     AlgorithmIdentifier
+         *              DEFAULT {algorithm id-sha256},
+         *     certHash          Hash,
+         *     issuerSerial      IssuerSerial OPTIONAL
+         * }
+         *
+         * Hash ::= OCTET STRING
+         *
+         * IssuerSerial ::= SEQUENCE {
+         *     issuer         GeneralNames,
+         *     serialNumber   CertificateSerialNumber
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (!hashAlgorithm.Equals(DefaultAlgID))
+            {
+                v.Add(hashAlgorithm);
+            }
+
+            v.Add(new DerOctetString(certHash).ToAsn1Object());
+
+            if (issuerSerial != null)
+            {
+                v.Add(issuerSerial);
+            }
+
+            return new DerSequence(v);
+        }
+
+    }
 }
diff --git a/crypto/src/asn1/ess/OtherCertID.cs b/crypto/src/asn1/ess/OtherCertID.cs
new file mode 100644
index 000000000..972ef8c6b
--- /dev/null
+++ b/crypto/src/asn1/ess/OtherCertID.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	[Obsolete("Use version in Asn1.Esf instead")]
+	public class OtherCertID
+		: Asn1Encodable
+	{
+		private Asn1Encodable otherCertHash;
+		private IssuerSerial issuerSerial;
+
+		public static OtherCertID GetInstance(
+			object o)
+		{
+			if (o == null || o is OtherCertID)
+			{
+				return (OtherCertID) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new OtherCertID((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'OtherCertID' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructor
+		 */
+		public OtherCertID(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			if (seq[0].ToAsn1Object() is Asn1OctetString)
+			{
+				otherCertHash = Asn1OctetString.GetInstance(seq[0]);
+			}
+			else
+			{
+				otherCertHash = DigestInfo.GetInstance(seq[0]);
+			}
+
+			if (seq.Count > 1)
+			{
+				issuerSerial = IssuerSerial.GetInstance(Asn1Sequence.GetInstance(seq[1]));
+			}
+		}
+
+		public OtherCertID(
+			AlgorithmIdentifier	algId,
+			byte[]				digest)
+		{
+			this.otherCertHash = new DigestInfo(algId, digest);
+		}
+
+		public OtherCertID(
+			AlgorithmIdentifier	algId,
+			byte[]				digest,
+			IssuerSerial		issuerSerial)
+		{
+			this.otherCertHash = new DigestInfo(algId, digest);
+			this.issuerSerial = issuerSerial;
+		}
+
+		public AlgorithmIdentifier AlgorithmHash
+		{
+			get
+			{
+				if (otherCertHash.ToAsn1Object() is Asn1OctetString)
+				{
+					// SHA-1
+					return new AlgorithmIdentifier("1.3.14.3.2.26");
+				}
+
+				return DigestInfo.GetInstance(otherCertHash).AlgorithmID;
+			}
+		}
+
+		public byte[] GetCertHash()
+		{
+			if (otherCertHash.ToAsn1Object() is Asn1OctetString)
+			{
+				// SHA-1
+				return ((Asn1OctetString) otherCertHash.ToAsn1Object()).GetOctets();
+			}
+
+			return DigestInfo.GetInstance(otherCertHash).GetDigest();
+		}
+
+		public IssuerSerial IssuerSerial
+		{
+			get { return issuerSerial; }
+		}
+
+		/**
+		 * <pre>
+		 * OtherCertID ::= SEQUENCE {
+		 *     otherCertHash    OtherHash,
+		 *     issuerSerial     IssuerSerial OPTIONAL }
+		 *
+		 * OtherHash ::= CHOICE {
+		 *     sha1Hash     OCTET STRING,
+		 *     otherHash    OtherHashAlgAndValue }
+		 *
+		 * OtherHashAlgAndValue ::= SEQUENCE {
+		 *     hashAlgorithm    AlgorithmIdentifier,
+		 *     hashValue        OCTET STRING }
+		 *
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(otherCertHash);
+
+			if (issuerSerial != null)
+			{
+				v.Add(issuerSerial);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/ess/OtherSigningCertificate.cs b/crypto/src/asn1/ess/OtherSigningCertificate.cs
new file mode 100644
index 000000000..c165fecea
--- /dev/null
+++ b/crypto/src/asn1/ess/OtherSigningCertificate.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	[Obsolete("Use version in Asn1.Esf instead")]
+	public class OtherSigningCertificate
+		: Asn1Encodable
+	{
+		private Asn1Sequence certs, policies;
+
+		public static OtherSigningCertificate GetInstance(
+			object o)
+		{
+			if (o == null || o is OtherSigningCertificate)
+			{
+				return (OtherSigningCertificate) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new OtherSigningCertificate((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'OtherSigningCertificate' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructors
+		 */
+		public OtherSigningCertificate(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.certs = Asn1Sequence.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.policies = Asn1Sequence.GetInstance(seq[1]);
+			}
+		}
+
+		public OtherSigningCertificate(
+			OtherCertID otherCertID)
+		{
+			certs = new DerSequence(otherCertID);
+		}
+
+		public OtherCertID[] GetCerts()
+		{
+			OtherCertID[] cs = new OtherCertID[certs.Count];
+
+			for (int i = 0; i != certs.Count; ++i)
+			{
+				cs[i] = OtherCertID.GetInstance(certs[i]);
+			}
+
+			return cs;
+		}
+
+		public PolicyInformation[] GetPolicies()
+		{
+			if (policies == null)
+			{
+				return null;
+			}
+
+			PolicyInformation[] ps = new PolicyInformation[policies.Count];
+
+			for (int i = 0; i != policies.Count; i++)
+			{
+				ps[i] = PolicyInformation.GetInstance(policies[i]);
+			}
+
+			return ps;
+		}
+
+		/**
+		 * The definition of OtherSigningCertificate is
+		 * <pre>
+		 * OtherSigningCertificate ::=  SEQUENCE {
+		 *      certs        SEQUENCE OF OtherCertID,
+		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+		 * }
+		 * </pre>
+		 * id-aa-ets-otherSigCert OBJECT IDENTIFIER ::= { iso(1)
+		 *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+		 *  smime(16) id-aa(2) 19 }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+			if (policies != null)
+			{
+				v.Add(policies);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/ess/SigningCertificate.cs b/crypto/src/asn1/ess/SigningCertificate.cs
new file mode 100644
index 000000000..366749bc3
--- /dev/null
+++ b/crypto/src/asn1/ess/SigningCertificate.cs
@@ -0,0 +1,108 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ess
+{
+	public class SigningCertificate
+		: Asn1Encodable
+	{
+		private Asn1Sequence certs, policies;
+
+		public static SigningCertificate GetInstance(
+			object o)
+		{
+			if (o == null || o is SigningCertificate)
+			{
+				return (SigningCertificate) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new SigningCertificate((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'SigningCertificate' factory : "
+				+ o.GetType().Name + ".");
+		}
+
+		/**
+		 * constructors
+		 */
+		public SigningCertificate(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.certs = Asn1Sequence.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.policies = Asn1Sequence.GetInstance(seq[1]);
+			}
+		}
+
+		public SigningCertificate(
+			EssCertID essCertID)
+		{
+			certs = new DerSequence(essCertID);
+		}
+
+		public EssCertID[] GetCerts()
+		{
+			EssCertID[] cs = new EssCertID[certs.Count];
+
+			for (int i = 0; i != certs.Count; i++)
+			{
+				cs[i] = EssCertID.GetInstance(certs[i]);
+			}
+
+			return cs;
+		}
+
+		public PolicyInformation[] GetPolicies()
+		{
+			if (policies == null)
+			{
+				return null;
+			}
+
+			PolicyInformation[] ps = new PolicyInformation[policies.Count];
+
+			for (int i = 0; i != policies.Count; i++)
+			{
+				ps[i] = PolicyInformation.GetInstance(policies[i]);
+			}
+
+			return ps;
+		}
+
+		/**
+		 * The definition of SigningCertificate is
+		 * <pre>
+		 * SigningCertificate ::=  SEQUENCE {
+		 *      certs        SEQUENCE OF EssCertID,
+		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+		 * }
+		 * </pre>
+		 * id-aa-signingCertificate OBJECT IDENTIFIER ::= { iso(1)
+		 *  member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+		 *  smime(16) id-aa(2) 12 }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+			if (policies != null)
+			{
+				v.Add(policies);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/ess/SigningCertificateV2.cs b/crypto/src/asn1/ess/SigningCertificateV2.cs
index a2aff4866..cabecc1ba 100644
--- a/crypto/src/asn1/ess/SigningCertificateV2.cs
+++ b/crypto/src/asn1/ess/SigningCertificateV2.cs
@@ -4,103 +4,109 @@ using Org.BouncyCastle.Asn1.X509;
 
 namespace Org.BouncyCastle.Asn1.Ess
 {
-	public class SigningCertificateV2
-		: Asn1Encodable
-	{
-		private readonly Asn1Sequence certs;
-		private readonly Asn1Sequence policies;
-
-		public static SigningCertificateV2 GetInstance(
-			object o)
-		{
-			if (o == null || o is SigningCertificateV2)
-				return (SigningCertificateV2) o;
-
-			if (o is Asn1Sequence)
-				return new SigningCertificateV2((Asn1Sequence) o);
-
-			throw new ArgumentException(
-				"unknown object in 'SigningCertificateV2' factory : "
-				+ o.GetType().Name + ".");
-		}
-
-		private SigningCertificateV2(
-			Asn1Sequence seq)
-		{
-			if (seq.Count < 1 || seq.Count > 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
-
-			this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
-
-			if (seq.Count > 1)
-			{
-				this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
-			}
-		}
-
-		public SigningCertificateV2(
-			EssCertIDv2[] certs)
-		{
-			this.certs = new DerSequence(certs);
-		}
-
-		public SigningCertificateV2(
-			EssCertIDv2[]		certs,
-			PolicyInformation[]	policies)
-		{
-			this.certs = new DerSequence(certs);
-
-			if (policies != null)
-			{
-				this.policies = new DerSequence(policies);
-			}
-		}
-
-		public EssCertIDv2[] GetCerts()
-		{
-			EssCertIDv2[] certIds = new EssCertIDv2[certs.Count];
-			for (int i = 0; i != certs.Count; i++)
-			{
-				certIds[i] = EssCertIDv2.GetInstance(certs[i]);
-			}
-			return certIds;
-		}
-
-		public PolicyInformation[] GetPolicies()
-		{
-			if (policies == null)
-				return null;
-
-			PolicyInformation[] policyInformations = new PolicyInformation[policies.Count];
-			for (int i = 0; i != policies.Count; i++)
-			{
-				policyInformations[i] = PolicyInformation.GetInstance(policies[i]);
-			}
-			return policyInformations;
-		}
-
-		/**
-		 * The definition of SigningCertificateV2 is
-		 * <pre>
-		 * SigningCertificateV2 ::=  SEQUENCE {
-		 *      certs        SEQUENCE OF EssCertIDv2,
-		 *      policies     SEQUENCE OF PolicyInformation OPTIONAL
-		 * }
-		 * </pre>
-		 * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1)
-		 *    member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
-		 *    smime(16) id-aa(2) 47 }
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			Asn1EncodableVector v = new Asn1EncodableVector(certs);
-
-			if (policies != null)
-			{
-				v.Add(policies);
-			}
-
-			return new DerSequence(v);
-		}
-	}
+    public class SigningCertificateV2
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence certs;
+        private readonly Asn1Sequence policies;
+
+        public static SigningCertificateV2 GetInstance(
+            object o)
+        {
+            if (o == null || o is SigningCertificateV2)
+                return (SigningCertificateV2) o;
+
+            if (o is Asn1Sequence)
+                return new SigningCertificateV2((Asn1Sequence) o);
+
+            throw new ArgumentException(
+                "unknown object in 'SigningCertificateV2' factory : "
+                + o.GetType().Name + ".");
+        }
+
+        private SigningCertificateV2(
+            Asn1Sequence seq)
+        {
+            if (seq.Count < 1 || seq.Count > 2)
+                throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+
+            if (seq.Count > 1)
+            {
+                this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
+            }
+        }
+
+        public SigningCertificateV2(
+            EssCertIDv2 cert)
+        {
+            this.certs = new DerSequence(cert);
+        }
+
+        public SigningCertificateV2(
+            EssCertIDv2[] certs)
+        {
+            this.certs = new DerSequence(certs);
+        }
+
+        public SigningCertificateV2(
+            EssCertIDv2[]		certs,
+            PolicyInformation[]	policies)
+        {
+            this.certs = new DerSequence(certs);
+
+            if (policies != null)
+            {
+                this.policies = new DerSequence(policies);
+            }
+        }
+
+        public EssCertIDv2[] GetCerts()
+        {
+            EssCertIDv2[] certIds = new EssCertIDv2[certs.Count];
+            for (int i = 0; i != certs.Count; i++)
+            {
+                certIds[i] = EssCertIDv2.GetInstance(certs[i]);
+            }
+            return certIds;
+        }
+
+        public PolicyInformation[] GetPolicies()
+        {
+            if (policies == null)
+                return null;
+
+            PolicyInformation[] policyInformations = new PolicyInformation[policies.Count];
+            for (int i = 0; i != policies.Count; i++)
+            {
+                policyInformations[i] = PolicyInformation.GetInstance(policies[i]);
+            }
+            return policyInformations;
+        }
+
+        /**
+         * The definition of SigningCertificateV2 is
+         * <pre>
+         * SigningCertificateV2 ::=  SEQUENCE {
+         *      certs        SEQUENCE OF EssCertIDv2,
+         *      policies     SEQUENCE OF PolicyInformation OPTIONAL
+         * }
+         * </pre>
+         * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::= { iso(1)
+         *    member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
+         *    smime(16) id-aa(2) 47 }
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(certs);
+
+            if (policies != null)
+            {
+                v.Add(policies);
+            }
+
+            return new DerSequence(v);
+        }
+    }
 }
diff --git a/crypto/src/asn1/gnu/GNUObjectIdentifiers.cs b/crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
new file mode 100644
index 000000000..9311a3ac1
--- /dev/null
+++ b/crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Gnu
+{
+	public abstract class GnuObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier Gnu					= new DerObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius
+		public static readonly DerObjectIdentifier GnuPG				= new DerObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten)
+		public static readonly DerObjectIdentifier Notation				= new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation
+		public static readonly DerObjectIdentifier PkaAddress			= new DerObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress
+		public static readonly DerObjectIdentifier GnuRadar				= new DerObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar
+		public static readonly DerObjectIdentifier DigestAlgorithm		= new DerObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm
+		public static readonly DerObjectIdentifier Tiger192				= new DerObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192
+		public static readonly DerObjectIdentifier EncryptionAlgorithm	= new DerObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm
+		public static readonly DerObjectIdentifier Serpent				= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent
+		public static readonly DerObjectIdentifier Serpent128Ecb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB
+		public static readonly DerObjectIdentifier Serpent128Cbc		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC
+		public static readonly DerObjectIdentifier Serpent128Ofb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB
+		public static readonly DerObjectIdentifier Serpent128Cfb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB
+		public static readonly DerObjectIdentifier Serpent192Ecb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB
+		public static readonly DerObjectIdentifier Serpent192Cbc		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC
+		public static readonly DerObjectIdentifier Serpent192Ofb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB
+		public static readonly DerObjectIdentifier Serpent192Cfb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB
+		public static readonly DerObjectIdentifier Serpent256Ecb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB
+		public static readonly DerObjectIdentifier Serpent256Cbc		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC
+		public static readonly DerObjectIdentifier Serpent256Ofb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB
+		public static readonly DerObjectIdentifier Serpent256Cfb		= new DerObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB
+		public static readonly DerObjectIdentifier Crc					= new DerObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms
+		public static readonly DerObjectIdentifier Crc32				= new DerObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32
+	}
+}
diff --git a/crypto/src/asn1/iana/IANAObjectIdentifiers.cs b/crypto/src/asn1/iana/IANAObjectIdentifiers.cs
new file mode 100644
index 000000000..63343f5ce
--- /dev/null
+++ b/crypto/src/asn1/iana/IANAObjectIdentifiers.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Asn1.Iana
+{
+	public abstract class IanaObjectIdentifiers
+	{
+		// id-SHA1 OBJECT IDENTIFIER ::=
+		// {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
+		//
+
+		public static readonly DerObjectIdentifier IsakmpOakley = new DerObjectIdentifier("1.3.6.1.5.5.8.1");
+
+		public static readonly DerObjectIdentifier HmacMD5 = new DerObjectIdentifier(IsakmpOakley + ".1");
+		public static readonly DerObjectIdentifier HmacSha1 = new DerObjectIdentifier(IsakmpOakley + ".2");
+
+		public static readonly DerObjectIdentifier HmacTiger = new DerObjectIdentifier(IsakmpOakley + ".3");
+
+		public static readonly DerObjectIdentifier HmacRipeMD160 = new DerObjectIdentifier(IsakmpOakley + ".4");
+	}
+}
diff --git a/crypto/src/asn1/icao/CscaMasterList.cs b/crypto/src/asn1/icao/CscaMasterList.cs
new file mode 100644
index 000000000..6890d8a2e
--- /dev/null
+++ b/crypto/src/asn1/icao/CscaMasterList.cs
@@ -0,0 +1,83 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	/**
+	 * The CscaMasterList object. This object can be wrapped in a
+	 * CMSSignedData to be published in LDAP.
+	 *
+	 * <pre>
+	 * CscaMasterList ::= SEQUENCE {
+	 *   version                CscaMasterListVersion,
+	 *   certList               SET OF Certificate }
+	 *   
+	 * CscaMasterListVersion :: INTEGER {v0(0)}
+	 * </pre>
+	 */
+	public class CscaMasterList 
+		: Asn1Encodable 
+	{
+		private DerInteger version = new DerInteger(0);
+		private X509CertificateStructure[] certList;
+
+		public static CscaMasterList GetInstance(
+			object obj)
+		{
+			if (obj is CscaMasterList)
+				return (CscaMasterList)obj;
+
+			if (obj != null)
+				return new CscaMasterList(Asn1Sequence.GetInstance(obj));            
+
+			return null;
+		}
+
+		private CscaMasterList(
+			Asn1Sequence seq)
+		{
+			if (seq == null || seq.Count == 0)
+				throw new ArgumentException("null or empty sequence passed.");
+
+			if (seq.Count != 2)
+				throw new ArgumentException("Incorrect sequence size: " + seq.Count);
+
+			this.version = DerInteger.GetInstance(seq[0]);
+
+			Asn1Set certSet = Asn1Set.GetInstance(seq[1]);
+
+			this.certList = new X509CertificateStructure[certSet.Count];
+			for (int i = 0; i < certList.Length; i++)
+			{
+				certList[i] = X509CertificateStructure.GetInstance(certSet[i]);
+			}
+		}
+
+		public CscaMasterList(
+			X509CertificateStructure[] certStructs)
+		{
+			certList = CopyCertList(certStructs);
+		}
+
+		public virtual int Version
+		{
+			get { return version.Value.IntValue; }
+		}
+
+		public X509CertificateStructure[] GetCertStructs()
+		{
+			return CopyCertList(certList);
+		}
+
+		private static X509CertificateStructure[] CopyCertList(X509CertificateStructure[] orig)
+		{
+			return (X509CertificateStructure[])orig.Clone();
+		}
+
+		public override Asn1Object ToAsn1Object() 
+		{
+			return new DerSequence(version, new DerSet(certList));
+		}
+	}
+}
diff --git a/crypto/src/asn1/icao/DataGroupHash.cs b/crypto/src/asn1/icao/DataGroupHash.cs
new file mode 100644
index 000000000..e0d7eee7b
--- /dev/null
+++ b/crypto/src/asn1/icao/DataGroupHash.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+    /**
+    * The DataGroupHash object.
+    * <pre>
+    * DataGroupHash  ::=  SEQUENCE {
+    *      dataGroupNumber         DataGroupNumber,
+    *      dataGroupHashValue     OCTET STRING }
+    *
+    * DataGroupNumber ::= INTEGER {
+    *         dataGroup1    (1),
+    *         dataGroup1    (2),
+    *         dataGroup1    (3),
+    *         dataGroup1    (4),
+    *         dataGroup1    (5),
+    *         dataGroup1    (6),
+    *         dataGroup1    (7),
+    *         dataGroup1    (8),
+    *         dataGroup1    (9),
+    *         dataGroup1    (10),
+    *         dataGroup1    (11),
+    *         dataGroup1    (12),
+    *         dataGroup1    (13),
+    *         dataGroup1    (14),
+    *         dataGroup1    (15),
+    *         dataGroup1    (16) }
+    *
+    * </pre>
+    */
+    public class DataGroupHash
+        : Asn1Encodable
+    {
+        private readonly DerInteger dataGroupNumber;
+        private readonly Asn1OctetString dataGroupHashValue;
+
+		public static DataGroupHash GetInstance(
+            object obj)
+        {
+            if (obj is DataGroupHash)
+                return (DataGroupHash)obj;
+
+			if (obj != null)
+				return new DataGroupHash(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		private DataGroupHash(
+			Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.dataGroupNumber = DerInteger.GetInstance(seq[0]);
+            this.dataGroupHashValue = Asn1OctetString.GetInstance(seq[1]);
+        }
+
+		public DataGroupHash(
+            int				dataGroupNumber,
+            Asn1OctetString	dataGroupHashValue)
+        {
+            this.dataGroupNumber = new DerInteger(dataGroupNumber);
+            this.dataGroupHashValue = dataGroupHashValue;
+        }
+
+		public int DataGroupNumber
+		{
+			get { return dataGroupNumber.Value.IntValue; }
+		}
+
+		public Asn1OctetString DataGroupHashValue
+		{
+			get { return dataGroupHashValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(dataGroupNumber, dataGroupHashValue);
+        }
+    }
+}
diff --git a/crypto/src/asn1/icao/ICAOObjectIdentifiers.cs b/crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
new file mode 100644
index 000000000..389d4dacd
--- /dev/null
+++ b/crypto/src/asn1/icao/ICAOObjectIdentifiers.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	public abstract class IcaoObjectIdentifiers
+	{
+		//
+		// base id
+		//
+		public static readonly DerObjectIdentifier IdIcao = new DerObjectIdentifier("2.23.136");
+
+		public static readonly DerObjectIdentifier IdIcaoMrtd = IdIcao.Branch("1");
+		public static readonly DerObjectIdentifier IdIcaoMrtdSecurity = IdIcaoMrtd.Branch("1");
+
+		// LDS security object, see ICAO Doc 9303-Volume 2-Section IV-A3.2
+		public static readonly DerObjectIdentifier IdIcaoLdsSecurityObject = IdIcaoMrtdSecurity.Branch("1");
+
+		// CSCA master list, see TR CSCA Countersigning and Master List issuance
+		public static readonly DerObjectIdentifier IdIcaoCscaMasterList = IdIcaoMrtdSecurity.Branch("2");
+		public static readonly DerObjectIdentifier IdIcaoCscaMasterListSigningKey = IdIcaoMrtdSecurity.Branch("3");
+
+		// document type list, see draft TR LDS and PKI Maintenance, par. 3.2.1
+		public static readonly DerObjectIdentifier IdIcaoDocumentTypeList = IdIcaoMrtdSecurity.Branch("4");
+
+		// Active Authentication protocol, see draft TR LDS and PKI Maintenance,
+		// par. 5.2.2
+		public static readonly DerObjectIdentifier IdIcaoAAProtocolObject = IdIcaoMrtdSecurity.Branch("5");
+
+		// CSCA name change and key reoll-over, see draft TR LDS and PKI
+		// Maintenance, par. 3.2.1
+		public static readonly DerObjectIdentifier IdIcaoExtensions = IdIcaoMrtdSecurity.Branch("6");
+		public static readonly DerObjectIdentifier IdIcaoExtensionsNamechangekeyrollover = IdIcaoExtensions.Branch("1");
+	}
+}
diff --git a/crypto/src/asn1/icao/LDSSecurityObject.cs b/crypto/src/asn1/icao/LDSSecurityObject.cs
new file mode 100644
index 000000000..c33ca6877
--- /dev/null
+++ b/crypto/src/asn1/icao/LDSSecurityObject.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	/**
+	 * The LDSSecurityObject object (V1.8).
+	 * <pre>
+	 * LDSSecurityObject ::= SEQUENCE {
+	 *   version                LDSSecurityObjectVersion,
+	 *   hashAlgorithm          DigestAlgorithmIdentifier,
+	 *   dataGroupHashValues    SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup,
+	 *   ldsVersionInfo         LDSVersionInfo OPTIONAL
+	 *     -- if present, version MUST be v1 }
+	 *
+	 * DigestAlgorithmIdentifier ::= AlgorithmIdentifier,
+	 *
+	 * LDSSecurityObjectVersion :: INTEGER {V0(0)}
+	 * </pre>
+	 */
+	public class LdsSecurityObject
+		: Asn1Encodable
+	{
+		public const int UBDataGroups = 16;
+
+		private DerInteger version = new DerInteger(0);
+		private AlgorithmIdentifier digestAlgorithmIdentifier;
+		private DataGroupHash[] datagroupHash;
+		private LdsVersionInfo versionInfo;
+
+		public static LdsSecurityObject GetInstance(
+			object obj)
+		{
+			if (obj is LdsSecurityObject)
+				return (LdsSecurityObject)obj;
+
+			if (obj != null)
+				return new LdsSecurityObject(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		private LdsSecurityObject(
+			Asn1Sequence seq)
+		{
+			if (seq == null || seq.Count == 0)
+				throw new ArgumentException("null or empty sequence passed.");
+
+			IEnumerator e = seq.GetEnumerator();
+
+			// version
+			e.MoveNext();
+			version = DerInteger.GetInstance(e.Current);
+			// digestAlgorithmIdentifier
+			e.MoveNext();
+			digestAlgorithmIdentifier = AlgorithmIdentifier.GetInstance(e.Current);
+
+			e.MoveNext();
+			Asn1Sequence datagroupHashSeq = Asn1Sequence.GetInstance(e.Current);
+
+			if (version.Value.Equals(BigInteger.One))
+			{
+				e.MoveNext();
+				versionInfo = LdsVersionInfo.GetInstance(e.Current);
+			}
+
+			CheckDatagroupHashSeqSize(datagroupHashSeq.Count);
+
+			datagroupHash = new DataGroupHash[datagroupHashSeq.Count];
+			for (int i= 0; i< datagroupHashSeq.Count; i++)
+			{
+				datagroupHash[i] = DataGroupHash.GetInstance(datagroupHashSeq[i]);
+			}
+		}
+
+		public LdsSecurityObject(
+			AlgorithmIdentifier	digestAlgorithmIdentifier,
+			DataGroupHash[]		datagroupHash)
+		{
+			this.version = new DerInteger(0);
+			this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+			this.datagroupHash = datagroupHash;
+
+			CheckDatagroupHashSeqSize(datagroupHash.Length);
+		}
+
+
+		public LdsSecurityObject(
+			AlgorithmIdentifier	digestAlgorithmIdentifier,
+			DataGroupHash[]		datagroupHash,
+			LdsVersionInfo		versionInfo)
+		{
+			this.version = new DerInteger(1);
+			this.digestAlgorithmIdentifier = digestAlgorithmIdentifier;
+			this.datagroupHash = datagroupHash;
+			this.versionInfo = versionInfo;
+
+			CheckDatagroupHashSeqSize(datagroupHash.Length);
+		}
+
+		private void CheckDatagroupHashSeqSize(int size)
+		{
+			if (size < 2 || size > UBDataGroups)
+				throw new ArgumentException("wrong size in DataGroupHashValues : not in (2.."+ UBDataGroups +")");
+		}
+
+		public BigInteger Version
+		{
+			get { return version.Value; }
+		}
+
+		public AlgorithmIdentifier DigestAlgorithmIdentifier
+		{
+			get { return digestAlgorithmIdentifier; }
+		}
+
+		public DataGroupHash[] GetDatagroupHash()
+		{
+			return datagroupHash;
+		}
+
+		public LdsVersionInfo VersionInfo
+		{
+			get { return versionInfo; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			DerSequence hashSeq = new DerSequence(datagroupHash);
+
+			Asn1EncodableVector v = new Asn1EncodableVector(version, digestAlgorithmIdentifier, hashSeq);
+
+			if (versionInfo != null)
+			{
+				v.Add(versionInfo);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/icao/LDSVersionInfo.cs b/crypto/src/asn1/icao/LDSVersionInfo.cs
new file mode 100644
index 000000000..2cdcad2db
--- /dev/null
+++ b/crypto/src/asn1/icao/LDSVersionInfo.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Icao
+{
+	public class LdsVersionInfo
+		: Asn1Encodable
+	{
+		private DerPrintableString ldsVersion;
+		private DerPrintableString unicodeVersion;
+
+		public LdsVersionInfo(string ldsVersion, string unicodeVersion)
+		{
+			this.ldsVersion = new DerPrintableString(ldsVersion);
+			this.unicodeVersion = new DerPrintableString(unicodeVersion);
+		}
+
+		private LdsVersionInfo(Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("sequence wrong size for LDSVersionInfo", "seq");
+
+			this.ldsVersion = DerPrintableString.GetInstance(seq[0]);
+			this.unicodeVersion = DerPrintableString.GetInstance(seq[1]);
+		}
+
+		public static LdsVersionInfo GetInstance(object obj)
+		{
+			if (obj is LdsVersionInfo)
+				return (LdsVersionInfo)obj;
+
+			if (obj != null)
+				return new LdsVersionInfo(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		public virtual string GetLdsVersion()
+		{
+			return ldsVersion.GetString();
+		}
+
+		public virtual string GetUnicodeVersion()
+		{
+			return unicodeVersion.GetString();
+		}
+
+		/**
+		 * <pre>
+		 * LDSVersionInfo ::= SEQUENCE {
+		 *    ldsVersion PRINTABLE STRING
+		 *    unicodeVersion PRINTABLE STRING
+		 *  }
+		 * </pre>
+		 * @return
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(ldsVersion, unicodeVersion);
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs b/crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs
new file mode 100644
index 000000000..af60b030a
--- /dev/null
+++ b/crypto/src/asn1/isismtt/ISISMTTObjectIdentifiers.cs
@@ -0,0 +1,177 @@
+namespace Org.BouncyCastle.Asn1.IsisMtt
+{
+	public abstract class IsisMttObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier IdIsisMtt = new DerObjectIdentifier("1.3.36.8");
+
+		public static readonly DerObjectIdentifier IdIsisMttCP = new DerObjectIdentifier(IdIsisMtt + ".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.
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttCPAccredited = new DerObjectIdentifier(IdIsisMttCP + ".1");
+
+		public static readonly DerObjectIdentifier IdIsisMttAT = new DerObjectIdentifier(IdIsisMtt + ".3");
+
+		/**
+		 * Certificate extensionDate of certificate generation
+		 * 
+		 * <pre>
+		 *		DateOfCertGenSyntax ::= GeneralizedTime
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATDateOfCertGen = new DerObjectIdentifier(IdIsisMttAT + ".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.
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATProcuration = new DerObjectIdentifier(IdIsisMttAT + ".2");
+
+		/**
+		 * Attribute to indicate admissions to certain professions. May be used as
+		 * attribute in attribute certificate or as extension in a certificate
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATAdmission = new DerObjectIdentifier(IdIsisMttAT + ".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).
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATMonetaryLimit = new DerObjectIdentifier(IdIsisMttAT + ".4");
+
+		/**
+		 * A declaration of majority. May be used as attribute in attribute
+		 * certificate or as extension in a certificate
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATDeclarationOfMajority = new DerObjectIdentifier(IdIsisMttAT + ".5");
+
+		/**
+		 * 
+		 * Serial number of the smart card containing the corresponding private key
+		 * 
+		 * <pre>
+		 *		ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+		 * </pre>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATIccsn = new DerObjectIdentifier(IdIsisMttAT + ".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>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATPKReference = new DerObjectIdentifier(IdIsisMttAT + ".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
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATRestriction = new DerObjectIdentifier(IdIsisMttAT + ".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>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATRetrieveIfAllowed = new DerObjectIdentifier(IdIsisMttAT + ".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
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATRequestedCertificate = new DerObjectIdentifier(IdIsisMttAT + ".10");
+
+		/**
+		 * Base ObjectIdentifier for naming authorities
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATNamingAuthorities = new DerObjectIdentifier(IdIsisMttAT + ".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>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATCertInDirSince = new DerObjectIdentifier(IdIsisMttAT + ".12");
+
+		/**
+		 * Hash of a certificate in OCSP.
+		 *
+		 * @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATCertHash = new DerObjectIdentifier(IdIsisMttAT + ".13");
+
+		/**
+		 * <pre>
+		 *		NameAtBirth ::= DirectoryString(SIZE(1..64)
+		 * </pre>
+		 * 
+		 * Used in
+		 * {@link Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATNameAtBirth = new DerObjectIdentifier(IdIsisMttAT + ".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
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATAdditionalInformation = new DerObjectIdentifier(IdIsisMttAT + ".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>
+		 */
+		public static readonly DerObjectIdentifier IdIsisMttATLiabilityLimitationFlag = new DerObjectIdentifier("0.2.262.1.10.12.0");
+	}
+}
diff --git a/crypto/src/asn1/isismtt/ocsp/CertHash.cs b/crypto/src/asn1/isismtt/ocsp/CertHash.cs
new file mode 100644
index 000000000..da5b530e4
--- /dev/null
+++ b/crypto/src/asn1/isismtt/ocsp/CertHash.cs
@@ -0,0 +1,121 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
+{
+	/**
+	* ISIS-MTT PROFILE: The responder may include this extension in a response to
+	* send the hash of the requested certificate to the responder. This hash is
+	* cryptographically bound to the certificate and serves as evidence that the
+	* certificate is known to the responder (i.e. it has been issued and is present
+	* in the directory). Hence, this extension is a means to provide a positive
+	* statement of availability as described in T8.[8]. As explained in T13.[1],
+	* clients may rely on this information to be able to validate signatures after
+	* the expiry of the corresponding certificate. Hence, clients MUST support this
+	* extension. If a positive statement of availability is to be delivered, this
+	* extension syntax and OID MUST be used.
+	* <p/>
+	* <p/>
+	* <pre>
+	*     CertHash ::= SEQUENCE {
+	*       hashAlgorithm AlgorithmIdentifier,
+	*       certificateHash OCTET STRING
+	*     }
+	* </pre>
+	*/
+	public class CertHash
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier	hashAlgorithm;
+		private readonly byte[]					certificateHash;
+
+		public static CertHash GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertHash)
+			{
+				return (CertHash) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new CertHash((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type CertHash:
+		* <p/>
+		* <pre>
+		*     CertHash ::= SEQUENCE {
+		*       hashAlgorithm AlgorithmIdentifier,
+		*       certificateHash OCTET STRING
+		*     }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private CertHash(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+			this.certificateHash = DerOctetString.GetInstance(seq[1]).GetOctets();
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param hashAlgorithm   The hash algorithm identifier.
+		* @param certificateHash The hash of the whole DER encoding of the certificate.
+		*/
+		public CertHash(
+			AlgorithmIdentifier	hashAlgorithm,
+			byte[]				certificateHash)
+		{
+			if (hashAlgorithm == null)
+				throw new ArgumentNullException("hashAlgorithm");
+			if (certificateHash == null)
+				throw new ArgumentNullException("certificateHash");
+
+			this.hashAlgorithm = hashAlgorithm;
+			this.certificateHash = (byte[]) certificateHash.Clone();
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public byte[] CertificateHash
+		{
+			get { return (byte[]) certificateHash.Clone(); }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*     CertHash ::= SEQUENCE {
+		*       hashAlgorithm AlgorithmIdentifier,
+		*       certificateHash OCTET STRING
+		*     }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, new DerOctetString(certificateHash));
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs b/crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
new file mode 100644
index 000000000..7724bfed6
--- /dev/null
+++ b/crypto/src/asn1/isismtt/ocsp/RequestedCertificate.cs
@@ -0,0 +1,186 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.Ocsp
+{
+	/**
+	* ISIS-MTT-Optional: The certificate requested by the client by inserting the
+	* RetrieveIfAllowed extension in the request, will be returned in this
+	* extension.
+	* <p/>
+	* ISIS-MTT-SigG: The signature act allows publishing certificates only then,
+	* when the certificate owner gives his isExplicit permission. Accordingly, there
+	* may be �nondownloadable� certificates, about which the responder must provide
+	* status information, but MUST NOT include them in the response. Clients may
+	* get therefore the following three kind of answers on a single request
+	* including the RetrieveIfAllowed extension:
+	* <ul>
+	* <li> a) the responder supports the extension and is allowed to publish the
+	* certificate: RequestedCertificate returned including the requested
+	* certificate</li>
+	* <li>b) the responder supports the extension but is NOT allowed to publish
+	* the certificate: RequestedCertificate returned including an empty OCTET
+	* STRING</li>
+	* <li>c) the responder does not support the extension: RequestedCertificate is
+	* not included in the response</li>
+	* </ul>
+	* Clients requesting RetrieveIfAllowed MUST be able to handle these cases. If
+	* any of the OCTET STRING options is used, it MUST contain the DER encoding of
+	* the requested certificate.
+	* <p/>
+	* <pre>
+	*            RequestedCertificate ::= CHOICE {
+	*              Certificate Certificate,
+	*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
+	*              attributeCertificate [1] EXPLICIT OCTET STRING
+	*            }
+	* </pre>
+	*/
+	public class RequestedCertificate
+		: Asn1Encodable, IAsn1Choice
+	{
+		public enum Choice
+		{
+			Certificate = -1,
+			PublicKeyCertificate = 0,
+			AttributeCertificate = 1
+		}
+
+		private readonly X509CertificateStructure	cert;
+		private readonly byte[]						publicKeyCert;
+		private readonly byte[]						attributeCert;
+
+		public static RequestedCertificate GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RequestedCertificate)
+			{
+				return (RequestedCertificate) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RequestedCertificate(X509CertificateStructure.GetInstance(obj));
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new RequestedCertificate((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static RequestedCertificate GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			if (!isExplicit)
+				throw new ArgumentException("choice item must be explicitly tagged");
+
+			return GetInstance(obj.GetObject());
+		}
+
+		private RequestedCertificate(
+			Asn1TaggedObject tagged)
+		{
+			switch ((Choice) tagged.TagNo)
+			{
+				case Choice.AttributeCertificate:
+					this.attributeCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
+					break;
+				case Choice.PublicKeyCertificate:
+					this.publicKeyCert = Asn1OctetString.GetInstance(tagged, true).GetOctets();
+					break;
+				default:
+					throw new ArgumentException("unknown tag number: " + tagged.TagNo);
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* Only one parameter can be given. All other must be <code>null</code>.
+		*
+		* @param certificate Given as Certificate
+		*/
+		public RequestedCertificate(
+			X509CertificateStructure certificate)
+		{
+			this.cert = certificate;
+		}
+
+		public RequestedCertificate(
+			Choice	type,
+			byte[]	certificateOctets)
+			: this(new DerTaggedObject((int) type, new DerOctetString(certificateOctets)))
+		{
+		}
+
+		public Choice Type
+		{
+			get
+			{
+				if (cert != null)
+					return Choice.Certificate;
+
+				if (publicKeyCert != null)
+					return Choice.PublicKeyCertificate;
+
+				return Choice.AttributeCertificate;
+			}
+		}
+
+		public byte[] GetCertificateBytes()
+		{
+			if (cert != null)
+			{
+				try
+				{
+					return cert.GetEncoded();
+				}
+				catch (IOException e)
+				{
+					throw new InvalidOperationException("can't decode certificate: " + e);
+				}
+			}
+
+			if (publicKeyCert != null)
+				return publicKeyCert;
+
+			return attributeCert;
+		}
+    
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*            RequestedCertificate ::= CHOICE {
+		*              Certificate Certificate,
+		*              publicKeyCertificate [0] EXPLICIT OCTET STRING,
+		*              attributeCertificate [1] EXPLICIT OCTET STRING
+		*            }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			if (publicKeyCert != null)
+			{
+				return new DerTaggedObject(0, new DerOctetString(publicKeyCert));
+			}
+
+			if (attributeCert != null)
+			{
+				return new DerTaggedObject(1, new DerOctetString(attributeCert));
+			}
+
+			return cert.ToAsn1Object();
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs b/crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
new file mode 100644
index 000000000..f81d459c6
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/AdditionalInformationSyntax.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Some other information of non-restrictive nature regarding the usage of this
+	* certificate.
+	* 
+	* <pre>
+	*    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+	* </pre>
+	*/
+	public class AdditionalInformationSyntax
+		: Asn1Encodable
+	{
+		private readonly DirectoryString information;
+
+		public static AdditionalInformationSyntax GetInstance(
+			object obj)
+		{
+			if (obj is AdditionalInformationSyntax)
+				return (AdditionalInformationSyntax) obj;
+
+			if (obj is IAsn1String)
+				return new AdditionalInformationSyntax(DirectoryString.GetInstance(obj));
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().Name, "obj");
+		}
+
+		private AdditionalInformationSyntax(
+			DirectoryString information)
+		{
+			this.information = information;
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param information The describtion of the information.
+		*/
+		public AdditionalInformationSyntax(
+			string information)
+		{
+			this.information = new DirectoryString(information);
+		}
+
+		public virtual DirectoryString Information
+		{
+			get { return information; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*   AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return information.ToAsn1Object();
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs b/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
index f322ef88f..64b5dbec8 100644
--- a/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
+++ b/crypto/src/asn1/isismtt/x509/AdmissionSyntax.cs
Binary files differdiff --git a/crypto/src/asn1/isismtt/x509/Admissions.cs b/crypto/src/asn1/isismtt/x509/Admissions.cs
new file mode 100644
index 000000000..40290c608
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/Admissions.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* An Admissions structure.
+	* <p/>
+	* <pre>
+	*            Admissions ::= SEQUENCE
+	*            {
+	*              admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+	*              namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+	*              professionInfos SEQUENCE OF ProfessionInfo
+	*            }
+	* <p/>
+	* </pre>
+	*
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority
+	*/
+	public class Admissions
+		: Asn1Encodable
+	{
+		private readonly GeneralName		admissionAuthority;
+		private readonly NamingAuthority	namingAuthority;
+		private readonly Asn1Sequence		professionInfos;
+
+		public static Admissions GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Admissions)
+			{
+				return (Admissions) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Admissions((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type ProcurationSyntax:
+		* <p/>
+		* <pre>
+		*            Admissions ::= SEQUENCE
+		*            {
+		*              admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+		*              namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+		*              professionInfos SEQUENCE OF ProfessionInfo
+		*            }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private Admissions(
+			Asn1Sequence seq)
+		{
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+			Asn1Encodable o = (Asn1Encodable) e.Current;
+			if (o is Asn1TaggedObject)
+			{
+				switch (((Asn1TaggedObject)o).TagNo)
+				{
+					case 0:
+						admissionAuthority = GeneralName.GetInstance((Asn1TaggedObject)o, true);
+						break;
+					case 1:
+						namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+				}
+				e.MoveNext();
+				o = (Asn1Encodable) e.Current;
+			}
+			if (o is Asn1TaggedObject)
+			{
+				switch (((Asn1TaggedObject)o).TagNo)
+				{
+					case 1:
+						namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+				}
+				e.MoveNext();
+				o = (Asn1Encodable) e.Current;
+			}
+			professionInfos = Asn1Sequence.GetInstance(o);
+			if (e.MoveNext())
+			{
+				throw new ArgumentException("Bad object encountered: " + e.Current.GetType().Name);
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* Parameter <code>professionInfos</code> is mandatory.
+		*
+		* @param admissionAuthority The admission authority.
+		* @param namingAuthority    The naming authority.
+		* @param professionInfos    The profession infos.
+		*/
+		public Admissions(
+			GeneralName			admissionAuthority,
+			NamingAuthority		namingAuthority,
+			ProfessionInfo[]	professionInfos)
+		{
+			this.admissionAuthority = admissionAuthority;
+			this.namingAuthority = namingAuthority;
+			this.professionInfos = new DerSequence(professionInfos);
+		}
+
+		public virtual GeneralName AdmissionAuthority
+		{
+			get { return admissionAuthority; }
+		}
+
+		public virtual NamingAuthority NamingAuthority
+		{
+			get { return namingAuthority; }
+		}
+
+		public ProfessionInfo[] GetProfessionInfos()
+		{
+			ProfessionInfo[] infos = new ProfessionInfo[professionInfos.Count];
+			int count = 0;
+			foreach (Asn1Encodable ae in professionInfos)
+			{
+				infos[count++] = ProfessionInfo.GetInstance(ae);
+			}
+			return infos;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       Admissions ::= SEQUENCE
+		*       {
+		*         admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+		*         namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+		*         professionInfos SEQUENCE OF ProfessionInfo
+		*       }
+		* <p/>
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+
+			if (admissionAuthority != null)
+			{
+				vec.Add(new DerTaggedObject(true, 0, admissionAuthority));
+			}
+
+			if (namingAuthority != null)
+			{
+				vec.Add(new DerTaggedObject(true, 1, namingAuthority));
+			}
+
+			vec.Add(professionInfos);
+
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
new file mode 100644
index 000000000..dfac65040
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
@@ -0,0 +1,170 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* A declaration of majority.
+	* <p/>
+	* <pre>
+	*           DeclarationOfMajoritySyntax ::= CHOICE
+	*           {
+	*             notYoungerThan [0] IMPLICIT INTEGER,
+	*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
+	*             {
+	*               fullAge BOOLEAN DEFAULT TRUE,
+	*               country PrintableString (SIZE(2))
+	*             }
+	*             dateOfBirth [2] IMPLICIT GeneralizedTime
+	*           }
+	* </pre>
+	* <p/>
+	* fullAgeAtCountry indicates the majority of the owner with respect to the laws
+	* of a specific country.
+	*/
+	public class DeclarationOfMajority
+		: Asn1Encodable, IAsn1Choice
+	{
+		public enum Choice
+		{
+			NotYoungerThan = 0,
+			FullAgeAtCountry = 1,
+			DateOfBirth = 2
+		};
+
+		private readonly Asn1TaggedObject declaration;
+
+		public DeclarationOfMajority(
+			int notYoungerThan)
+		{
+			declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan));
+		}
+
+		public DeclarationOfMajority(
+			bool	fullAge,
+			string	country)
+		{
+			if (country.Length > 2)
+				throw new ArgumentException("country can only be 2 characters");
+
+			DerPrintableString countryString = new DerPrintableString(country, true);
+
+			DerSequence seq;
+			if (fullAge)
+			{
+				seq = new DerSequence(countryString);
+			}
+			else
+			{
+				seq = new DerSequence(DerBoolean.False, countryString);
+			}
+
+			this.declaration = new DerTaggedObject(false, 1, seq);
+		}
+
+		public DeclarationOfMajority(
+			DerGeneralizedTime dateOfBirth)
+		{
+			this.declaration = new DerTaggedObject(false, 2, dateOfBirth);
+		}
+
+		public static DeclarationOfMajority GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is DeclarationOfMajority)
+			{
+				return (DeclarationOfMajority) obj;
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new DeclarationOfMajority((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private DeclarationOfMajority(
+			Asn1TaggedObject o)
+		{
+			if (o.TagNo > 2)
+				throw new ArgumentException("Bad tag number: " + o.TagNo);
+
+			this.declaration = o;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*           DeclarationOfMajoritySyntax ::= CHOICE
+		*           {
+		*             notYoungerThan [0] IMPLICIT INTEGER,
+		*             fullAgeAtCountry [1] IMPLICIT SEQUENCE
+		*             {
+		*               fullAge BOOLEAN DEFAULT TRUE,
+		*               country PrintableString (SIZE(2))
+		*             }
+		*             dateOfBirth [2] IMPLICIT GeneralizedTime
+		*           }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return declaration;
+		}
+
+		public Choice Type
+		{
+			get { return (Choice) declaration.TagNo; }
+		}
+
+		/**
+		* @return notYoungerThan if that's what we are, -1 otherwise
+		*/
+		public virtual int NotYoungerThan
+		{
+			get
+			{
+				switch ((Choice) declaration.TagNo)
+				{
+					case Choice.NotYoungerThan:
+						return DerInteger.GetInstance(declaration, false).Value.IntValue;
+					default:
+						return -1;
+				}
+			}
+		}
+
+		public virtual Asn1Sequence FullAgeAtCountry
+		{
+			get
+			{
+				switch ((Choice) declaration.TagNo)
+				{
+					case Choice.FullAgeAtCountry:
+						return Asn1Sequence.GetInstance(declaration, false);
+					default:
+						return null;
+				}
+			}
+		}
+
+		public virtual DerGeneralizedTime DateOfBirth
+		{
+			get
+			{
+				switch ((Choice) declaration.TagNo)
+				{
+					case Choice.DateOfBirth:
+						return DerGeneralizedTime.GetInstance(declaration, false);
+					default:
+						return null;
+				}
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/MonetaryLimit.cs b/crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
new file mode 100644
index 000000000..80b6b684b
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/MonetaryLimit.cs
@@ -0,0 +1,121 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* 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, components SHOULD support MonetaryLimit (as well
+	* as QcEuLimitValue).
+	* <p/>
+	* Indicates a monetary limit within which the certificate holder is authorized
+	* to act. (This value DOES NOT express a limit on the liability of the
+	* certification authority).
+	* <p/>
+	* <pre>
+	*    MonetaryLimitSyntax ::= SEQUENCE
+	*    {
+	*      currency PrintableString (SIZE(3)),
+	*      amount INTEGER,
+	*      exponent INTEGER
+	*    }
+	* </pre>
+	* <p/>
+	* currency must be the ISO code.
+	* <p/>
+	* value = amount�10*exponent
+	*/
+	public class MonetaryLimit
+		: Asn1Encodable
+	{
+		private readonly DerPrintableString	currency;
+		private readonly DerInteger			amount;
+		private readonly DerInteger			exponent;
+
+		public static MonetaryLimit GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is MonetaryLimit)
+			{
+				return (MonetaryLimit) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new MonetaryLimit(Asn1Sequence.GetInstance(obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private MonetaryLimit(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			currency = DerPrintableString.GetInstance(seq[0]);
+			amount = DerInteger.GetInstance(seq[1]);
+			exponent = DerInteger.GetInstance(seq[2]);
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* <p/>
+		* value = amount�10^exponent
+		*
+		* @param currency The currency. Must be the ISO code.
+		* @param amount   The amount
+		* @param exponent The exponent
+		*/
+		public MonetaryLimit(
+			string	currency,
+			int		amount,
+			int		exponent)
+		{
+			this.currency = new DerPrintableString(currency, true);
+			this.amount = new DerInteger(amount);
+			this.exponent = new DerInteger(exponent);
+		}
+
+		public virtual string Currency
+		{
+			get { return currency.GetString(); }
+		}
+
+		public virtual BigInteger Amount
+		{
+			get { return amount.Value; }
+		}
+
+		public virtual BigInteger Exponent
+		{
+			get { return exponent.Value; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*    MonetaryLimitSyntax ::= SEQUENCE
+		*    {
+		*      currency PrintableString (SIZE(3)),
+		*      amount INTEGER,
+		*      exponent INTEGER
+		*    }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(currency, amount, exponent);
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/NamingAuthority.cs b/crypto/src/asn1/isismtt/x509/NamingAuthority.cs
new file mode 100644
index 000000000..4262fd0f4
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/NamingAuthority.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Names of authorities which are responsible for the administration of title
+	* registers.
+	* 
+	* <pre>
+	*             NamingAuthority ::= SEQUENCE 
+	*             {
+	*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+	*               namingAuthorityUrl IA5String OPTIONAL,
+	*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+	*             }
+	* </pre>
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+	* 
+	*/
+	public class NamingAuthority
+		: Asn1Encodable
+	{
+		/**
+		* Profession OIDs should always be defined under the OID branch of the
+		* responsible naming authority. At the time of this writing, the work group
+		* �Recht, Wirtschaft, Steuern� (�Law, Economy, Taxes�) is registered as the
+		* first naming authority under the OID id-isismtt-at-namingAuthorities.
+		*/
+		public static readonly DerObjectIdentifier IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern
+			= new DerObjectIdentifier(IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities + ".1");
+
+		private readonly DerObjectIdentifier	namingAuthorityID;
+		private readonly string					namingAuthorityUrl;
+		private readonly DirectoryString		namingAuthorityText;
+
+		public static NamingAuthority GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NamingAuthority)
+			{
+				return (NamingAuthority) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NamingAuthority((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static NamingAuthority GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* <p/>
+		* <pre>
+		*             NamingAuthority ::= SEQUENCE
+		*             {
+		*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+		*               namingAuthorityUrl IA5String OPTIONAL,
+		*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+		*             }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private NamingAuthority(
+			Asn1Sequence seq)
+		{
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			if (e.MoveNext())
+			{
+				Asn1Encodable o = (Asn1Encodable) e.Current;
+				if (o is DerObjectIdentifier)
+				{
+					namingAuthorityID = (DerObjectIdentifier) o;
+				}
+				else if (o is DerIA5String)
+				{
+					namingAuthorityUrl = DerIA5String.GetInstance(o).GetString();
+				}
+				else if (o is IAsn1String)
+				{
+					namingAuthorityText = DirectoryString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				Asn1Encodable o = (Asn1Encodable) e.Current;
+				if (o is DerIA5String)
+				{
+					namingAuthorityUrl = DerIA5String.GetInstance(o).GetString();
+				}
+				else if (o is IAsn1String)
+				{
+					namingAuthorityText = DirectoryString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				Asn1Encodable o = (Asn1Encodable) e.Current;
+				if (o is IAsn1String)
+				{
+					namingAuthorityText = DirectoryString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+		}
+
+		/**
+		* @return Returns the namingAuthorityID.
+		*/
+		public virtual DerObjectIdentifier NamingAuthorityID
+		{
+			get { return namingAuthorityID; }
+		}
+
+		/**
+		* @return Returns the namingAuthorityText.
+		*/
+		public virtual DirectoryString NamingAuthorityText
+		{
+			get { return namingAuthorityText; }
+		}
+
+		/**
+		* @return Returns the namingAuthorityUrl.
+		*/
+		public virtual string NamingAuthorityUrl
+		{
+			get { return namingAuthorityUrl; }
+		}
+
+		/**
+		* Constructor from given details.
+		* <p/>
+		* All parameters can be combined.
+		*
+		* @param namingAuthorityID   ObjectIdentifier for naming authority.
+		* @param namingAuthorityUrl  URL for naming authority.
+		* @param namingAuthorityText Textual representation of naming authority.
+		*/
+		public NamingAuthority(
+			DerObjectIdentifier	namingAuthorityID,
+			string				namingAuthorityUrl,
+			DirectoryString		namingAuthorityText)
+		{
+			this.namingAuthorityID = namingAuthorityID;
+			this.namingAuthorityUrl = namingAuthorityUrl;
+			this.namingAuthorityText = namingAuthorityText;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*             NamingAuthority ::= SEQUENCE
+		*             {
+		*               namingAuthorityID OBJECT IDENTIFIER OPTIONAL,
+		*               namingAuthorityUrl IA5String OPTIONAL,
+		*               namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+		*             }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (namingAuthorityID != null)
+			{
+				vec.Add(namingAuthorityID);
+			}
+			if (namingAuthorityUrl != null)
+			{
+				vec.Add(new DerIA5String(namingAuthorityUrl, true));
+			}
+			if (namingAuthorityText != null)
+			{
+				vec.Add(namingAuthorityText);
+			}
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs b/crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
new file mode 100644
index 000000000..a25df225e
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/ProcurationSyntax.cs
@@ -0,0 +1,232 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Attribute to indicate that the certificate holder may sign in the name of a
+	* third person.
+	* <p>
+	* ISIS-MTT PROFILE: The corresponding ProcurationSyntax contains either the
+	* name of the person who is represented (subcomponent thirdPerson) or a
+	* reference to his/her base certificate (in the component signingFor,
+	* subcomponent certRef), furthermore the optional components country and
+	* typeSubstitution to indicate the country whose laws apply, and respectively
+	* the type of procuration (e.g. manager, procuration, custody).
+	* </p>
+	* <p>
+	* ISIS-MTT PROFILE: The GeneralName MUST be of type directoryName and MAY only
+	* contain: - RFC3039 attributes, except pseudonym (countryName, commonName,
+	* surname, givenName, serialNumber, organizationName, organizationalUnitName,
+	* stateOrProvincename, localityName, postalAddress) and - SubjectDirectoryName
+	* attributes (title, dateOfBirth, placeOfBirth, gender, countryOfCitizenship,
+	* countryOfResidence and NameAtBirth).
+	* </p>
+	* <pre>
+	*               ProcurationSyntax ::= SEQUENCE {
+	*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+	*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+	*                 signingFor [3] EXPLICIT SigningFor 
+	*               }
+	*               
+	*               SigningFor ::= CHOICE 
+	*               { 
+	*                 thirdPerson GeneralName,
+	*                 certRef IssuerSerial 
+	*               }
+	* </pre>
+	* 
+	*/
+	public class ProcurationSyntax
+		: Asn1Encodable
+	{
+		private readonly string				country;
+		private readonly DirectoryString	typeOfSubstitution;
+		private readonly GeneralName		thirdPerson;
+		private readonly IssuerSerial		certRef;
+
+		public static ProcurationSyntax GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ProcurationSyntax)
+			{
+				return (ProcurationSyntax) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ProcurationSyntax((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type ProcurationSyntax:
+		* <p/>
+		* <pre>
+		*               ProcurationSyntax ::= SEQUENCE {
+		*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+		*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+		*                 signingFor [3] EXPLICIT SigningFor
+		*               }
+		* <p/>
+		*               SigningFor ::= CHOICE
+		*               {
+		*                 thirdPerson GeneralName,
+		*                 certRef IssuerSerial
+		*               }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private ProcurationSyntax(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			while (e.MoveNext())
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current);
+				switch (o.TagNo)
+				{
+					case 1:
+						country = DerPrintableString.GetInstance(o, true).GetString();
+						break;
+					case 2:
+						typeOfSubstitution = DirectoryString.GetInstance(o, true);
+						break;
+					case 3:
+						Asn1Object signingFor = o.GetObject();
+						if (signingFor is Asn1TaggedObject)
+						{
+							thirdPerson = GeneralName.GetInstance(signingFor);
+						}
+						else
+						{
+							certRef = IssuerSerial.GetInstance(signingFor);
+						}
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		* <p/>
+		* <p/>
+		* Either <code>generalName</code> or <code>certRef</code> MUST be
+		* <code>null</code>.
+		*
+		* @param country            The country code whose laws apply.
+		* @param typeOfSubstitution The type of procuration.
+		* @param certRef            Reference to certificate of the person who is represented.
+		*/
+		public ProcurationSyntax(
+			string			country,
+			DirectoryString	typeOfSubstitution,
+			IssuerSerial	certRef)
+		{
+			this.country = country;
+			this.typeOfSubstitution = typeOfSubstitution;
+			this.thirdPerson = null;
+			this.certRef = certRef;
+		}
+
+		/**
+		 * Constructor from a given details.
+		 * <p/>
+		 * <p/>
+		 * Either <code>generalName</code> or <code>certRef</code> MUST be
+		 * <code>null</code>.
+		 *
+		 * @param country            The country code whose laws apply.
+		 * @param typeOfSubstitution The type of procuration.
+		 * @param thirdPerson        The GeneralName of the person who is represented.
+		 */
+		public ProcurationSyntax(
+			string			country,
+			DirectoryString	typeOfSubstitution,
+			GeneralName		thirdPerson)
+		{
+			this.country = country;
+			this.typeOfSubstitution = typeOfSubstitution;
+			this.thirdPerson = thirdPerson;
+			this.certRef = null;
+		}
+
+		public virtual string Country
+		{
+			get { return country; }
+		}
+
+		public virtual DirectoryString TypeOfSubstitution
+		{
+			get { return typeOfSubstitution; }
+		}
+
+		public virtual GeneralName ThirdPerson
+		{
+			get { return thirdPerson; }
+		}
+
+		public virtual IssuerSerial CertRef
+		{
+			get { return certRef; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*               ProcurationSyntax ::= SEQUENCE {
+		*                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
+		*                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
+		*                 signingFor [3] EXPLICIT SigningFor
+		*               }
+		* <p/>
+		*               SigningFor ::= CHOICE
+		*               {
+		*                 thirdPerson GeneralName,
+		*                 certRef IssuerSerial
+		*               }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (country != null)
+			{
+				vec.Add(new DerTaggedObject(true, 1, new DerPrintableString(country, true)));
+			}
+			if (typeOfSubstitution != null)
+			{
+				vec.Add(new DerTaggedObject(true, 2, typeOfSubstitution));
+			}
+			if (thirdPerson != null)
+			{
+				vec.Add(new DerTaggedObject(true, 3, thirdPerson));
+			}
+			else
+			{
+				vec.Add(new DerTaggedObject(true, 3, certRef));
+			}
+
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/ProfessionInfo.cs b/crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
new file mode 100644
index 000000000..3bad2cbc4
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/ProfessionInfo.cs
@@ -0,0 +1,386 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Professions, specializations, disciplines, fields of activity, etc.
+	* 
+	* <pre>
+	*               ProfessionInfo ::= SEQUENCE 
+	*               {
+	*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+	*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+	*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+	*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+	*                 addProfessionInfo OCTET STRING OPTIONAL 
+	*               }
+	* </pre>
+	* 
+	* @see Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax
+	*/
+	public class ProfessionInfo
+		: Asn1Encodable
+	{
+		/**
+		* Rechtsanw�ltin
+		*/
+		public static readonly DerObjectIdentifier Rechtsanwltin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".1");
+
+		/**
+		* Rechtsanwalt
+		*/
+		public static readonly DerObjectIdentifier Rechtsanwalt = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".2");
+
+		/**
+		* Rechtsbeistand
+		*/
+		public static readonly DerObjectIdentifier Rechtsbeistand = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".3");
+
+		/**
+		* Steuerberaterin
+		*/
+		public static readonly DerObjectIdentifier Steuerberaterin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".4");
+
+		/**
+		* Steuerberater
+		*/
+		public static readonly DerObjectIdentifier Steuerberater = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".5");
+
+		/**
+		* Steuerbevollm�chtigte
+		*/
+		public static readonly DerObjectIdentifier Steuerbevollmchtigte = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".6");
+
+		/**
+		* Steuerbevollm�chtigter
+		*/
+		public static readonly DerObjectIdentifier Steuerbevollmchtigter = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".7");
+
+		/**
+		* Notarin
+		*/
+		public static readonly DerObjectIdentifier Notarin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".8");
+
+		/**
+		* Notar
+		*/
+		public static readonly DerObjectIdentifier Notar = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".9");
+
+		/**
+		* Notarvertreterin
+		*/
+		public static readonly DerObjectIdentifier Notarvertreterin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".10");
+
+		/**
+		* Notarvertreter
+		*/
+		public static readonly DerObjectIdentifier Notarvertreter = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".11");
+
+		/**
+		* Notariatsverwalterin
+		*/
+		public static readonly DerObjectIdentifier Notariatsverwalterin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".12");
+
+		/**
+		* Notariatsverwalter
+		*/
+		public static readonly DerObjectIdentifier Notariatsverwalter = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".13");
+
+		/**
+		* Wirtschaftspr�ferin
+		*/
+		public static readonly DerObjectIdentifier Wirtschaftsprferin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".14");
+
+		/**
+		* Wirtschaftspr�fer
+		*/
+		public static readonly DerObjectIdentifier Wirtschaftsprfer = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".15");
+
+		/**
+		* Vereidigte Buchpr�ferin
+		*/
+		public static readonly DerObjectIdentifier VereidigteBuchprferin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".16");
+
+		/**
+		* Vereidigter Buchpr�fer
+		*/
+		public static readonly DerObjectIdentifier VereidigterBuchprfer = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".17");
+
+		/**
+		* Patentanw�ltin
+		*/
+		public static readonly DerObjectIdentifier Patentanwltin = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".18");
+
+		/**
+		* Patentanwalt
+		*/
+		public static readonly DerObjectIdentifier Patentanwalt = new DerObjectIdentifier(
+			NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern + ".19");
+
+		private readonly NamingAuthority	namingAuthority;
+		private readonly Asn1Sequence		professionItems;
+		private readonly Asn1Sequence		professionOids;
+		private readonly string				registrationNumber;
+		private readonly Asn1OctetString	addProfessionInfo;
+
+		public static ProfessionInfo GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ProfessionInfo)
+			{
+				return (ProfessionInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ProfessionInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* <p/>
+		* <pre>
+		*               ProfessionInfo ::= SEQUENCE
+		*               {
+		*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+		*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+		*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+		*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+		*                 addProfessionInfo OCTET STRING OPTIONAL
+		*               }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private ProfessionInfo(
+			Asn1Sequence seq)
+		{
+			if (seq.Count > 5)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+			Asn1Encodable o = (Asn1Encodable) e.Current;
+
+			if (o is Asn1TaggedObject)
+			{
+				Asn1TaggedObject ato = (Asn1TaggedObject) o;
+				if (ato.TagNo != 0)
+					throw new ArgumentException("Bad tag number: " + ato.TagNo);
+
+				namingAuthority = NamingAuthority.GetInstance(ato, true);
+				e.MoveNext();
+				o = (Asn1Encodable) e.Current;
+			}
+
+			professionItems = Asn1Sequence.GetInstance(o);
+
+			if (e.MoveNext())
+			{
+				o = (Asn1Encodable) e.Current;
+				if (o is Asn1Sequence)
+				{
+					professionOids = Asn1Sequence.GetInstance(o);
+				}
+				else if (o is DerPrintableString)
+				{
+					registrationNumber = DerPrintableString.GetInstance(o).GetString();
+				}
+				else if (o is Asn1OctetString)
+				{
+					addProfessionInfo = Asn1OctetString.GetInstance(o);
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				o = (Asn1Encodable) e.Current;
+				if (o is DerPrintableString)
+				{
+					registrationNumber = DerPrintableString.GetInstance(o).GetString();
+				}
+				else if (o is DerOctetString)
+				{
+					addProfessionInfo = (DerOctetString) o;
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+
+			if (e.MoveNext())
+			{
+				o = (Asn1Encodable) e.Current;
+				if (o is DerOctetString)
+				{
+					addProfessionInfo = (DerOctetString) o;
+				}
+				else
+				{
+					throw new ArgumentException("Bad object encountered: " + o.GetType().Name);
+				}
+			}
+		}
+
+		/**
+		* Constructor from given details.
+		* <p/>
+		* <code>professionItems</code> is mandatory, all other parameters are
+		* optional.
+		*
+		* @param namingAuthority    The naming authority.
+		* @param professionItems    Directory strings of the profession.
+		* @param professionOids     DERObjectIdentfier objects for the
+		*                           profession.
+		* @param registrationNumber Registration number.
+		* @param addProfessionInfo  Additional infos in encoded form.
+		*/
+		public ProfessionInfo(
+			NamingAuthority			namingAuthority,
+			DirectoryString[]		professionItems,
+			DerObjectIdentifier[]	professionOids,
+			string					registrationNumber,
+			Asn1OctetString			addProfessionInfo)
+		{
+			this.namingAuthority = namingAuthority;
+			this.professionItems = new DerSequence(professionItems);
+			if (professionOids != null)
+			{
+				this.professionOids = new DerSequence(professionOids);
+			}
+			this.registrationNumber = registrationNumber;
+			this.addProfessionInfo = addProfessionInfo;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*               ProfessionInfo ::= SEQUENCE
+		*               {
+		*                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
+		*                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
+		*                 professionOids SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
+		*                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
+		*                 addProfessionInfo OCTET STRING OPTIONAL
+		*               }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			if (namingAuthority != null)
+			{
+				vec.Add(new DerTaggedObject(true, 0, namingAuthority));
+			}
+			vec.Add(professionItems);
+			if (professionOids != null)
+			{
+				vec.Add(professionOids);
+			}
+			if (registrationNumber != null)
+			{
+				vec.Add(new DerPrintableString(registrationNumber, true));
+			}
+			if (addProfessionInfo != null)
+			{
+				vec.Add(addProfessionInfo);
+			}
+			return new DerSequence(vec);
+		}
+
+		/**
+		* @return Returns the addProfessionInfo.
+		*/
+		public virtual Asn1OctetString AddProfessionInfo
+		{
+			get { return addProfessionInfo; }
+		}
+
+		/**
+		* @return Returns the namingAuthority.
+		*/
+		public virtual NamingAuthority NamingAuthority
+		{
+			get { return namingAuthority; }
+		}
+
+		/**
+		* @return Returns the professionItems.
+		*/
+		public virtual DirectoryString[] GetProfessionItems()
+		{
+			DirectoryString[] result = new DirectoryString[professionItems.Count];
+
+			for (int i = 0; i < professionItems.Count; ++i)
+			{
+				result[i] = DirectoryString.GetInstance(professionItems[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		* @return Returns the professionOids.
+		*/
+		public virtual DerObjectIdentifier[] GetProfessionOids()
+		{
+			if (professionOids == null)
+			{
+				return new DerObjectIdentifier[0];
+			}
+
+			DerObjectIdentifier[] result = new DerObjectIdentifier[professionOids.Count];
+
+			for (int i = 0; i < professionOids.Count; ++i)
+			{
+				result[i] = DerObjectIdentifier.GetInstance(professionOids[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		* @return Returns the registrationNumber.
+		*/
+		public virtual string RegistrationNumber
+		{
+			get { return registrationNumber; }
+		}
+	}
+}
diff --git a/crypto/src/asn1/isismtt/x509/Restriction.cs b/crypto/src/asn1/isismtt/x509/Restriction.cs
new file mode 100644
index 000000000..c97766999
--- /dev/null
+++ b/crypto/src/asn1/isismtt/x509/Restriction.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.IsisMtt.X509
+{
+	/**
+	* Some other restriction regarding the usage of this certificate.
+	* <p/>
+	* <pre>
+	*  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+	* </pre>
+	*/
+	public class Restriction
+		: Asn1Encodable
+	{
+		private readonly DirectoryString restriction;
+
+		public static Restriction GetInstance(
+			object obj)
+		{
+			if (obj is Restriction)
+				return (Restriction) obj;
+
+			if (obj is IAsn1String)
+				return new Restriction(DirectoryString.GetInstance(obj));
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from DirectoryString.
+		* <p/>
+		* The DirectoryString is of type RestrictionSyntax:
+		* <p/>
+		* <pre>
+		*      RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+		* </pre>
+		*
+		* @param restriction A IAsn1String.
+		*/
+		private Restriction(
+			DirectoryString restriction)
+		{
+			this.restriction = restriction;
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param restriction The description of the restriction.
+		*/
+		public Restriction(
+			string restriction)
+		{
+			this.restriction = new DirectoryString(restriction);
+		}
+
+		public virtual DirectoryString RestrictionString
+		{
+			get { return restriction; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*      RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+		* <p/>
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			return restriction.ToAsn1Object();
+		}
+	}
+}
diff --git a/crypto/src/asn1/kisa/KISAObjectIdentifiers.cs b/crypto/src/asn1/kisa/KISAObjectIdentifiers.cs
new file mode 100644
index 000000000..05351ec75
--- /dev/null
+++ b/crypto/src/asn1/kisa/KISAObjectIdentifiers.cs
@@ -0,0 +1,8 @@
+namespace Org.BouncyCastle.Asn1.Kisa
+{
+	public abstract class KisaObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier IdSeedCbc = new DerObjectIdentifier("1.2.410.200004.1.4");
+		public static readonly DerObjectIdentifier IdNpkiAppCmsSeedWrap = new DerObjectIdentifier("1.2.410.200004.7.1.1.1");
+	}
+}
diff --git a/crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs b/crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
new file mode 100644
index 000000000..b8aba7ee9
--- /dev/null
+++ b/crypto/src/asn1/microsoft/MicrosoftObjectIdentifiers.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Microsoft
+{
+	public abstract class MicrosoftObjectIdentifiers
+	{
+		//
+		// Microsoft
+		//       iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) Microsoft(311)
+		//
+		public static readonly DerObjectIdentifier Microsoft               = new DerObjectIdentifier("1.3.6.1.4.1.311");
+		public static readonly DerObjectIdentifier MicrosoftCertTemplateV1 = new DerObjectIdentifier(Microsoft + ".20.2");
+		public static readonly DerObjectIdentifier MicrosoftCAVersion      = new DerObjectIdentifier(Microsoft + ".21.1");
+		public static readonly DerObjectIdentifier MicrosoftPrevCACertHash = new DerObjectIdentifier(Microsoft + ".21.2");
+		public static readonly DerObjectIdentifier MicrosoftCertTemplateV2 = new DerObjectIdentifier(Microsoft + ".21.7");
+		public static readonly DerObjectIdentifier MicrosoftAppPolicies    = new DerObjectIdentifier(Microsoft + ".21.10");
+	}
+}
diff --git a/crypto/src/asn1/misc/CAST5CBCParameters.cs b/crypto/src/asn1/misc/CAST5CBCParameters.cs
new file mode 100644
index 000000000..51fd6607a
--- /dev/null
+++ b/crypto/src/asn1/misc/CAST5CBCParameters.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class Cast5CbcParameters
+        : Asn1Encodable
+    {
+        private readonly DerInteger keyLength;
+        private readonly Asn1OctetString iv;
+
+		public static Cast5CbcParameters GetInstance(
+            object o)
+        {
+            if (o is Cast5CbcParameters)
+            {
+                return (Cast5CbcParameters) o;
+            }
+
+			if (o is Asn1Sequence)
+            {
+                return new Cast5CbcParameters((Asn1Sequence) o);
+            }
+
+			throw new ArgumentException("unknown object in Cast5CbcParameters factory");
+        }
+
+		public Cast5CbcParameters(
+            byte[]	iv,
+            int		keyLength)
+        {
+            this.iv = new DerOctetString(iv);
+            this.keyLength = new DerInteger(keyLength);
+        }
+
+		private Cast5CbcParameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			iv = (Asn1OctetString) seq[0];
+            keyLength = (DerInteger) seq[1];
+        }
+
+		public byte[] GetIV()
+        {
+			return Arrays.Clone(iv.GetOctets());
+		}
+
+		public int KeyLength
+		{
+			get { return keyLength.Value.IntValue; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * cast5CBCParameters ::= Sequence {
+         *                           iv         OCTET STRING DEFAULT 0,
+         *                                  -- Initialization vector
+         *                           keyLength  Integer
+         *                                  -- Key length, in bits
+         *                      }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(iv, keyLength);
+        }
+    }
+}
diff --git a/crypto/src/asn1/misc/IDEACBCPar.cs b/crypto/src/asn1/misc/IDEACBCPar.cs
new file mode 100644
index 000000000..72a60b9dc
--- /dev/null
+++ b/crypto/src/asn1/misc/IDEACBCPar.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class IdeaCbcPar
+        : Asn1Encodable
+    {
+        internal Asn1OctetString iv;
+
+		public static IdeaCbcPar GetInstance(
+            object o)
+        {
+            if (o is IdeaCbcPar)
+            {
+                return (IdeaCbcPar) o;
+            }
+
+			if (o is Asn1Sequence)
+            {
+                return new IdeaCbcPar((Asn1Sequence) o);
+            }
+
+			throw new ArgumentException("unknown object in IDEACBCPar factory");
+        }
+
+		public IdeaCbcPar(
+            byte[] iv)
+        {
+            this.iv = new DerOctetString(iv);
+        }
+
+		private IdeaCbcPar(
+            Asn1Sequence seq)
+        {
+			if (seq.Count == 1)
+			{
+				iv = (Asn1OctetString) seq[0];
+			}
+        }
+
+		public byte[] GetIV()
+        {
+			return iv == null ? null : iv.GetOctets();
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * IDEA-CBCPar ::= Sequence {
+         *                      iv    OCTET STRING OPTIONAL -- exactly 8 octets
+         *                  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (iv != null)
+            {
+                v.Add(iv);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
new file mode 100644
index 000000000..01004d889
--- /dev/null
+++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -0,0 +1,48 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public abstract class MiscObjectIdentifiers
+    {
+        //
+        // Netscape
+        //       iso/itu(2) joint-assign(16) us(840) uscompany(1) Netscape(113730) cert-extensions(1) }
+        //
+        public static readonly DerObjectIdentifier Netscape                = new DerObjectIdentifier("2.16.840.1.113730.1");
+        public static readonly DerObjectIdentifier NetscapeCertType        = new DerObjectIdentifier(Netscape + ".1");
+        public static readonly DerObjectIdentifier NetscapeBaseUrl         = new DerObjectIdentifier(Netscape + ".2");
+        public static readonly DerObjectIdentifier NetscapeRevocationUrl   = new DerObjectIdentifier(Netscape + ".3");
+        public static readonly DerObjectIdentifier NetscapeCARevocationUrl = new DerObjectIdentifier(Netscape + ".4");
+        public static readonly DerObjectIdentifier NetscapeRenewalUrl      = new DerObjectIdentifier(Netscape + ".7");
+        public static readonly DerObjectIdentifier NetscapeCAPolicyUrl     = new DerObjectIdentifier(Netscape + ".8");
+        public static readonly DerObjectIdentifier NetscapeSslServerName   = new DerObjectIdentifier(Netscape + ".12");
+        public static readonly DerObjectIdentifier NetscapeCertComment     = new DerObjectIdentifier(Netscape + ".13");
+        //
+        // Verisign
+        //       iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
+        //
+        internal const string Verisign = "2.16.840.1.113733.1";
+
+		//
+        // CZAG - country, zip, age, and gender
+        //
+        public static readonly DerObjectIdentifier VerisignCzagExtension = new DerObjectIdentifier(Verisign + ".6.3");
+
+		// D&B D-U-N-S number
+		public static readonly DerObjectIdentifier VerisignDnbDunsNumber = new DerObjectIdentifier(Verisign + ".6.15");
+
+		//
+		// Novell
+		//       iso/itu(2) country(16) us(840) organization(1) novell(113719)
+		//
+		public static readonly string				Novell					= "2.16.840.1.113719";
+		public static readonly DerObjectIdentifier	NovellSecurityAttribs	= new DerObjectIdentifier(Novell + ".1.9.4.1");
+
+		//
+		// Entrust
+		//       iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
+		//
+		public static readonly string				Entrust					= "1.2.840.113533.7";
+		public static readonly DerObjectIdentifier	EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
+	}
+}
diff --git a/crypto/src/asn1/misc/NetscapeCertType.cs b/crypto/src/asn1/misc/NetscapeCertType.cs
new file mode 100644
index 000000000..d5db6523d
--- /dev/null
+++ b/crypto/src/asn1/misc/NetscapeCertType.cs
@@ -0,0 +1,54 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    /**
+     * 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
+        : DerBitString
+    {
+        public const int SslClient        = (1 << 7);
+        public const int SslServer        = (1 << 6);
+        public const int Smime            = (1 << 5);
+        public const int ObjectSigning    = (1 << 4);
+        public const int Reserved         = (1 << 3);
+        public const int SslCA            = (1 << 2);
+        public const int SmimeCA          = (1 << 1);
+        public const 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)
+			: base(GetBytes(usage), GetPadBits(usage))
+        {
+        }
+
+		public NetscapeCertType(DerBitString usage)
+			: base(usage.GetBytes(), usage.PadBits)
+        {
+        }
+
+		public override string ToString()
+        {
+			byte[] data = GetBytes();
+			return "NetscapeCertType: 0x" + (data[0] & 0xff).ToString("X");
+        }
+    }
+}
diff --git a/crypto/src/asn1/misc/NetscapeRevocationURL.cs b/crypto/src/asn1/misc/NetscapeRevocationURL.cs
new file mode 100644
index 000000000..6cac031f2
--- /dev/null
+++ b/crypto/src/asn1/misc/NetscapeRevocationURL.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class NetscapeRevocationUrl
+        : DerIA5String
+    {
+        public NetscapeRevocationUrl(DerIA5String str)
+			: base(str.GetString())
+        {
+        }
+
+        public override string ToString()
+        {
+            return "NetscapeRevocationUrl: " + this.GetString();
+        }
+    }
+}
diff --git a/crypto/src/asn1/misc/VerisignCzagExtension.cs b/crypto/src/asn1/misc/VerisignCzagExtension.cs
new file mode 100644
index 000000000..1c3054b32
--- /dev/null
+++ b/crypto/src/asn1/misc/VerisignCzagExtension.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Misc
+{
+    public class VerisignCzagExtension
+        : DerIA5String
+    {
+        public VerisignCzagExtension(DerIA5String str)
+			: base(str.GetString())
+        {
+        }
+
+        public override string ToString()
+        {
+            return "VerisignCzagExtension: " + this.GetString();
+        }
+    }
+}
diff --git a/crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs b/crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs
new file mode 100644
index 000000000..1e08b809d
--- /dev/null
+++ b/crypto/src/asn1/mozilla/PublicKeyAndChallenge.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Mozilla
+{
+	/**
+	 * This is designed to parse
+	 * the PublicKeyAndChallenge created by the KEYGEN tag included by
+	 * Mozilla based browsers.
+	 *  <pre>
+	 *  PublicKeyAndChallenge ::= SEQUENCE {
+	 *    spki SubjectPublicKeyInfo,
+	 *    challenge IA5STRING
+	 *  }
+	 *
+	 *  </pre>
+	 */
+	public class PublicKeyAndChallenge
+		: Asn1Encodable
+	{
+		private Asn1Sequence			pkacSeq;
+		private SubjectPublicKeyInfo	spki;
+		private DerIA5String			challenge;
+
+		public static PublicKeyAndChallenge GetInstance(
+			object obj)
+		{
+			if (obj is PublicKeyAndChallenge)
+			{
+				return (PublicKeyAndChallenge) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PublicKeyAndChallenge((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException(
+				"unknown object in 'PublicKeyAndChallenge' factory : "
+				+ obj.GetType().Name + ".");
+		}
+
+		public PublicKeyAndChallenge(
+			Asn1Sequence seq)
+		{
+			pkacSeq = seq;
+			spki = SubjectPublicKeyInfo.GetInstance(seq[0]);
+			challenge = DerIA5String.GetInstance(seq[1]);
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return pkacSeq;
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+		{
+			get { return spki; }
+		}
+
+		public DerIA5String Challenge
+		{
+			get { return challenge; }
+		}
+	}
+}
diff --git a/crypto/src/asn1/nist/NISTNamedCurves.cs b/crypto/src/asn1/nist/NISTNamedCurves.cs
index 3b4c59df2..0e82dda7a 100644
--- a/crypto/src/asn1/nist/NISTNamedCurves.cs
+++ b/crypto/src/asn1/nist/NISTNamedCurves.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Sec;
@@ -10,93 +9,100 @@ using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Asn1.Nist
 {
-	/**
-	* Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2
-	*/
-	public sealed class NistNamedCurves
-	{
-		private NistNamedCurves()
-		{
-		}
+    /**
+    * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-3
+    */
+    public sealed class NistNamedCurves
+    {
+        private NistNamedCurves()
+        {
+        }
 
-		private static readonly IDictionary objIds = Platform.CreateHashtable();
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
         private static readonly IDictionary names = Platform.CreateHashtable();
 
-		private static void DefineCurve(
-			string				name,
-			DerObjectIdentifier	oid)
-		{
-			objIds.Add(name, oid);
-			names.Add(oid, name);
-		}
+        private static void DefineCurve(
+            string				name,
+            DerObjectIdentifier	oid)
+        {
+            objIds.Add(name, oid);
+            names.Add(oid, name);
+        }
 
-		static NistNamedCurves()
-		{
-			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);
-		}
+        static NistNamedCurves()
+        {
+            DefineCurve("B-571", SecObjectIdentifiers.SecT571r1);
+            DefineCurve("B-409", SecObjectIdentifiers.SecT409r1);
+            DefineCurve("B-283", SecObjectIdentifiers.SecT283r1);
+            DefineCurve("B-233", SecObjectIdentifiers.SecT233r1);
+            DefineCurve("B-163", SecObjectIdentifiers.SecT163r2);
+            DefineCurve("K-571", SecObjectIdentifiers.SecT571k1);
+            DefineCurve("K-409", SecObjectIdentifiers.SecT409k1);
+            DefineCurve("K-283", SecObjectIdentifiers.SecT283k1);
+            DefineCurve("K-233", SecObjectIdentifiers.SecT233k1);
+            DefineCurve("K-163", SecObjectIdentifiers.SecT163k1);
+            DefineCurve("P-521", SecObjectIdentifiers.SecP521r1);
+            DefineCurve("P-384", SecObjectIdentifiers.SecP384r1);
+            DefineCurve("P-256", SecObjectIdentifiers.SecP256r1);
+            DefineCurve("P-224", SecObjectIdentifiers.SecP224r1);
+            DefineCurve("P-192", SecObjectIdentifiers.SecP192r1);
+        }
 
-		public static X9ECParameters GetByName(
-			string name)
-		{
-			DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name.ToUpperInvariant()];
+        public static X9ECParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier) objIds[
+                Platform.ToUpperInvariant(name)];
 
-			if (oid != null)
-			{
-				return GetByOid(oid);
-			}
+            if (oid != null)
+            {
+                return GetByOid(oid);
+            }
 
-			return null;
-		}
+            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(
-			DerObjectIdentifier oid)
-		{
-			return SecNamedCurves.GetByOid(oid);
-		}
+        /**
+        * 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(
+            DerObjectIdentifier 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 DerObjectIdentifier GetOid(
-			string name)
-		{
-			return (DerObjectIdentifier) objIds[name.ToUpperInvariant()];
-		}
+        /**
+        * 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 DerObjectIdentifier GetOid(
+            string name)
+        {
+            return (DerObjectIdentifier) objIds[
+                Platform.ToUpperInvariant(name)];
+        }
 
-		/**
-		* return the named curve name represented by the given object identifier.
-		*/
-		public static string GetName(
-			DerObjectIdentifier  oid)
-		{
-			return (string) names[oid];
-		}
+        /**
+        * return the named curve name represented by the given object identifier.
+        */
+        public static string GetName(
+            DerObjectIdentifier  oid)
+        {
+            return (string) names[oid];
+        }
 
-		/**
-		* returns an enumeration containing the name strings for curves
-		* contained in this structure.
-		*/
-		public static IEnumerable Names
-		{
-			get { return new EnumerableProxy(objIds.Keys); }
-		}
-	}
+        /**
+        * returns an enumeration containing the name strings for curves
+        * contained in this structure.
+        */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(objIds.Keys); }
+        }
+    }
 }
diff --git a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
index f3957062f..8eb5ed437 100644
--- a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
+++ b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
@@ -4,9 +4,9 @@ namespace Org.BouncyCastle.Asn1.Nist
 {
     public sealed class NistObjectIdentifiers
     {
-		private NistObjectIdentifiers()
-		{
-		}
+        private NistObjectIdentifiers()
+        {
+        }
 
         //
         // NIST
@@ -17,10 +17,14 @@ namespace Org.BouncyCastle.Asn1.Nist
         //
         public static readonly DerObjectIdentifier NistAlgorithm = new DerObjectIdentifier("2.16.840.1.101.3.4");
 
-        public static readonly DerObjectIdentifier IdSha256 = new DerObjectIdentifier(NistAlgorithm + ".2.1");
-        public static readonly DerObjectIdentifier IdSha384 = new DerObjectIdentifier(NistAlgorithm + ".2.2");
-        public static readonly DerObjectIdentifier IdSha512 = new DerObjectIdentifier(NistAlgorithm + ".2.3");
-        public static readonly DerObjectIdentifier IdSha224 = new DerObjectIdentifier(NistAlgorithm + ".2.4");
+        public static readonly DerObjectIdentifier HashAlgs = NistAlgorithm.Branch("2");
+
+        public static readonly DerObjectIdentifier IdSha256 = HashAlgs.Branch("1");
+        public static readonly DerObjectIdentifier IdSha384 = HashAlgs.Branch("2");
+        public static readonly DerObjectIdentifier IdSha512 = HashAlgs.Branch("3");
+        public static readonly DerObjectIdentifier IdSha224 = HashAlgs.Branch("4");
+        public static readonly DerObjectIdentifier IdSha512_224 = HashAlgs.Branch("5");
+        public static readonly DerObjectIdentifier IdSha512_256 = HashAlgs.Branch("6");
 
         public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1");
 
@@ -48,14 +52,14 @@ namespace Org.BouncyCastle.Asn1.Nist
         public static readonly DerObjectIdentifier IdAes256Gcm	= new DerObjectIdentifier(Aes + ".46");
         public static readonly DerObjectIdentifier IdAes256Ccm	= new DerObjectIdentifier(Aes + ".47");
 
-		//
-		// signatures
-		//
-		public static readonly DerObjectIdentifier IdDsaWithSha2 = new DerObjectIdentifier(NistAlgorithm + ".3");
+        //
+        // signatures
+        //
+        public static readonly DerObjectIdentifier IdDsaWithSha2 = new DerObjectIdentifier(NistAlgorithm + ".3");
 
-		public static readonly DerObjectIdentifier DsaWithSha224 = new DerObjectIdentifier(IdDsaWithSha2 + ".1");
-		public static readonly DerObjectIdentifier DsaWithSha256 = new DerObjectIdentifier(IdDsaWithSha2 + ".2");
-		public static readonly DerObjectIdentifier DsaWithSha384 = new DerObjectIdentifier(IdDsaWithSha2 + ".3");
-		public static readonly DerObjectIdentifier DsaWithSha512 = new DerObjectIdentifier(IdDsaWithSha2 + ".4"); 
-	}
+        public static readonly DerObjectIdentifier DsaWithSha224 = new DerObjectIdentifier(IdDsaWithSha2 + ".1");
+        public static readonly DerObjectIdentifier DsaWithSha256 = new DerObjectIdentifier(IdDsaWithSha2 + ".2");
+        public static readonly DerObjectIdentifier DsaWithSha384 = new DerObjectIdentifier(IdDsaWithSha2 + ".3");
+        public static readonly DerObjectIdentifier DsaWithSha512 = new DerObjectIdentifier(IdDsaWithSha2 + ".4"); 
+    }
 }
diff --git a/crypto/src/asn1/ntt/NTTObjectIdentifiers.cs b/crypto/src/asn1/ntt/NTTObjectIdentifiers.cs
new file mode 100644
index 000000000..cd2595600
--- /dev/null
+++ b/crypto/src/asn1/ntt/NTTObjectIdentifiers.cs
@@ -0,0 +1,14 @@
+namespace Org.BouncyCastle.Asn1.Ntt
+{
+	/// <summary>From RFC 3657</summary>
+	public abstract class NttObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier IdCamellia128Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.2");
+		public static readonly DerObjectIdentifier IdCamellia192Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.3");
+		public static readonly DerObjectIdentifier IdCamellia256Cbc = new DerObjectIdentifier("1.2.392.200011.61.1.1.1.4");
+
+		public static readonly DerObjectIdentifier IdCamellia128Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.2");
+		public static readonly DerObjectIdentifier IdCamellia192Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.3");
+		public static readonly DerObjectIdentifier IdCamellia256Wrap = new DerObjectIdentifier("1.2.392.200011.61.1.1.3.4");
+	}
+}
diff --git a/crypto/src/asn1/ocsp/BasicOCSPResponse.cs b/crypto/src/asn1/ocsp/BasicOCSPResponse.cs
new file mode 100644
index 000000000..dd666addf
--- /dev/null
+++ b/crypto/src/asn1/ocsp/BasicOCSPResponse.cs
@@ -0,0 +1,131 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class BasicOcspResponse
+        : Asn1Encodable
+    {
+        private readonly ResponseData			tbsResponseData;
+        private readonly AlgorithmIdentifier	signatureAlgorithm;
+        private readonly DerBitString			signature;
+        private readonly Asn1Sequence			certs;
+
+		public static BasicOcspResponse GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static BasicOcspResponse GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is BasicOcspResponse)
+			{
+				return (BasicOcspResponse)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new BasicOcspResponse((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public BasicOcspResponse(
+            ResponseData		tbsResponseData,
+            AlgorithmIdentifier	signatureAlgorithm,
+            DerBitString		signature,
+            Asn1Sequence		certs)
+        {
+            this.tbsResponseData = tbsResponseData;
+            this.signatureAlgorithm = signatureAlgorithm;
+            this.signature = signature;
+            this.certs = certs;
+        }
+
+		private BasicOcspResponse(
+            Asn1Sequence seq)
+        {
+            this.tbsResponseData = ResponseData.GetInstance(seq[0]);
+            this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+            this.signature = (DerBitString)seq[2];
+
+			if (seq.Count > 3)
+            {
+                this.certs = Asn1Sequence.GetInstance((Asn1TaggedObject)seq[3], true);
+            }
+        }
+
+		[Obsolete("Use TbsResponseData property instead")]
+		public ResponseData GetTbsResponseData()
+        {
+            return tbsResponseData;
+        }
+
+		public ResponseData TbsResponseData
+		{
+			get { return tbsResponseData; }
+		}
+
+		[Obsolete("Use SignatureAlgorithm property instead")]
+		public AlgorithmIdentifier GetSignatureAlgorithm()
+        {
+            return signatureAlgorithm;
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return signatureAlgorithm; }
+		}
+
+		[Obsolete("Use Signature property instead")]
+		public DerBitString GetSignature()
+        {
+            return signature;
+        }
+
+		public DerBitString Signature
+		{
+			get { return signature; }
+		}
+
+		[Obsolete("Use Certs property instead")]
+		public Asn1Sequence GetCerts()
+        {
+            return certs;
+        }
+
+		public Asn1Sequence Certs
+		{
+			get { return certs; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * BasicOcspResponse       ::= Sequence {
+         *      tbsResponseData      ResponseData,
+         *      signatureAlgorithm   AlgorithmIdentifier,
+         *      signature            BIT STRING,
+         *      certs                [0] EXPLICIT Sequence OF Certificate OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				tbsResponseData, signatureAlgorithm, signature);
+
+			if (certs != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, certs));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/CertID.cs b/crypto/src/asn1/ocsp/CertID.cs
new file mode 100644
index 000000000..4b251095b
--- /dev/null
+++ b/crypto/src/asn1/ocsp/CertID.cs
@@ -0,0 +1,98 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class CertID
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier    hashAlgorithm;
+        private readonly Asn1OctetString        issuerNameHash;
+        private readonly Asn1OctetString        issuerKeyHash;
+        private readonly DerInteger             serialNumber;
+
+		public static CertID GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static CertID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertID)
+			{
+				return (CertID)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new CertID((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public CertID(
+            AlgorithmIdentifier hashAlgorithm,
+            Asn1OctetString     issuerNameHash,
+            Asn1OctetString     issuerKeyHash,
+            DerInteger          serialNumber)
+        {
+            this.hashAlgorithm = hashAlgorithm;
+            this.issuerNameHash = issuerNameHash;
+            this.issuerKeyHash = issuerKeyHash;
+            this.serialNumber = serialNumber;
+        }
+
+		private CertID(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 4)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+            this.issuerNameHash = Asn1OctetString.GetInstance(seq[1]);
+            this.issuerKeyHash = Asn1OctetString.GetInstance(seq[2]);
+            this.serialNumber = DerInteger.GetInstance(seq[3]);
+        }
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public Asn1OctetString IssuerNameHash
+		{
+			get { return issuerNameHash; }
+		}
+
+		public Asn1OctetString IssuerKeyHash
+		{
+			get { return issuerKeyHash; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * CertID          ::=     Sequence {
+         *     hashAlgorithm       AlgorithmIdentifier,
+         *     issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
+         *     issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
+         *     serialNumber        CertificateSerialNumber }
+         * </pre>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, issuerNameHash, issuerKeyHash, serialNumber);
+		}
+	}
+}
diff --git a/crypto/src/asn1/ocsp/CertStatus.cs b/crypto/src/asn1/ocsp/CertStatus.cs
new file mode 100644
index 000000000..d5b1a94a2
--- /dev/null
+++ b/crypto/src/asn1/ocsp/CertStatus.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class CertStatus
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly int			tagNo;
+        private readonly Asn1Encodable	value;
+
+		/**
+         * create a CertStatus object with a tag of zero.
+         */
+        public CertStatus()
+        {
+            tagNo = 0;
+            value = DerNull.Instance;
+        }
+
+		public CertStatus(
+            RevokedInfo info)
+        {
+            tagNo = 1;
+            value = info;
+        }
+
+		public CertStatus(
+            int				tagNo,
+            Asn1Encodable	value)
+        {
+            this.tagNo = tagNo;
+            this.value = value;
+        }
+
+		public CertStatus(
+            Asn1TaggedObject choice)
+        {
+            this.tagNo = choice.TagNo;
+
+			switch (choice.TagNo)
+            {
+				case 1:
+					value = RevokedInfo.GetInstance(choice, false);
+					break;
+				case 0:
+				case 2:
+					value = DerNull.Instance;
+					break;
+            }
+        }
+
+		public static CertStatus GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is CertStatus)
+            {
+                return (CertStatus)obj;
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return new CertStatus((Asn1TaggedObject)obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public int TagNo
+		{
+			get { return tagNo; }
+		}
+
+		public Asn1Encodable Status
+		{
+			get { return value; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  CertStatus ::= CHOICE {
+         *                  good        [0]     IMPLICIT Null,
+         *                  revoked     [1]     IMPLICIT RevokedInfo,
+         *                  unknown     [2]     IMPLICIT UnknownInfo }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, tagNo, value);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/CrlID.cs b/crypto/src/asn1/ocsp/CrlID.cs
new file mode 100644
index 000000000..cfb3d6fcb
--- /dev/null
+++ b/crypto/src/asn1/ocsp/CrlID.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class CrlID
+        : Asn1Encodable
+    {
+        private readonly DerIA5String		crlUrl;
+        private readonly DerInteger			crlNum;
+        private readonly DerGeneralizedTime	crlTime;
+
+		// TODO Add GetInstance method(s) and amke this private?
+		public CrlID(
+            Asn1Sequence seq)
+        {
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+                {
+                case 0:
+                    crlUrl = DerIA5String.GetInstance(o, true);
+                    break;
+                case 1:
+                    crlNum = DerInteger.GetInstance(o, true);
+                    break;
+                case 2:
+                    crlTime = DerGeneralizedTime.GetInstance(o, true);
+                    break;
+                default:
+                    throw new ArgumentException("unknown tag number: " + o.TagNo);
+                }
+            }
+        }
+
+		public DerIA5String CrlUrl
+		{
+			get { return crlUrl; }
+		}
+
+		public DerInteger CrlNum
+		{
+			get { return crlNum; }
+		}
+
+		public DerGeneralizedTime CrlTime
+		{
+			get { return crlTime; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * CrlID ::= Sequence {
+         *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
+         *     crlNum               [1]     EXPLICIT Integer OPTIONAL,
+         *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (crlUrl != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, crlUrl));
+            }
+
+			if (crlNum != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, crlNum));
+            }
+
+			if (crlTime != null)
+            {
+                v.Add(new DerTaggedObject(true, 2, crlTime));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs b/crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs
new file mode 100644
index 000000000..a37c8552d
--- /dev/null
+++ b/crypto/src/asn1/ocsp/OCSPObjectIdentifiers.cs
@@ -0,0 +1,23 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public abstract class OcspObjectIdentifiers
+    {
+        internal const string PkixOcspId = "1.3.6.1.5.5.7.48.1";
+
+		public static readonly DerObjectIdentifier PkixOcsp = new DerObjectIdentifier(PkixOcspId);
+        public static readonly DerObjectIdentifier PkixOcspBasic = new DerObjectIdentifier(PkixOcspId + ".1");
+
+		//
+		// extensions
+		//
+		public static readonly DerObjectIdentifier PkixOcspNonce = new DerObjectIdentifier(PkixOcsp + ".2");
+		public static readonly DerObjectIdentifier PkixOcspCrl = new DerObjectIdentifier(PkixOcsp + ".3");
+
+		public static readonly DerObjectIdentifier PkixOcspResponse = new DerObjectIdentifier(PkixOcsp + ".4");
+		public static readonly DerObjectIdentifier PkixOcspNocheck = new DerObjectIdentifier(PkixOcsp + ".5");
+		public static readonly DerObjectIdentifier PkixOcspArchiveCutoff = new DerObjectIdentifier(PkixOcsp + ".6");
+		public static readonly DerObjectIdentifier PkixOcspServiceLocator = new DerObjectIdentifier(PkixOcsp + ".7");
+	}
+}
diff --git a/crypto/src/asn1/ocsp/OCSPRequest.cs b/crypto/src/asn1/ocsp/OCSPRequest.cs
new file mode 100644
index 000000000..1e804d78e
--- /dev/null
+++ b/crypto/src/asn1/ocsp/OCSPRequest.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class OcspRequest
+        : Asn1Encodable
+    {
+        private readonly TbsRequest	tbsRequest;
+        private readonly Signature	optionalSignature;
+
+		public static OcspRequest GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static OcspRequest GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspRequest)
+			{
+				return (OcspRequest)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new OcspRequest((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public OcspRequest(
+            TbsRequest	tbsRequest,
+            Signature	optionalSignature)
+        {
+			if (tbsRequest == null)
+				throw new ArgumentNullException("tbsRequest");
+
+			this.tbsRequest = tbsRequest;
+            this.optionalSignature = optionalSignature;
+        }
+
+		private OcspRequest(
+            Asn1Sequence seq)
+        {
+            tbsRequest = TbsRequest.GetInstance(seq[0]);
+
+			if (seq.Count == 2)
+            {
+                optionalSignature = Signature.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+            }
+        }
+
+		public TbsRequest TbsRequest
+		{
+			get { return tbsRequest; }
+		}
+
+		public Signature OptionalSignature
+		{
+			get { return optionalSignature; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OcspRequest     ::=     Sequence {
+         *     tbsRequest                  TBSRequest,
+         *     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(tbsRequest);
+
+			if (optionalSignature != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, optionalSignature));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/OCSPResponse.cs b/crypto/src/asn1/ocsp/OCSPResponse.cs
new file mode 100644
index 000000000..e9aad8100
--- /dev/null
+++ b/crypto/src/asn1/ocsp/OCSPResponse.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class OcspResponse
+        : Asn1Encodable
+    {
+        private readonly OcspResponseStatus	responseStatus;
+        private readonly ResponseBytes		responseBytes;
+
+		public static OcspResponse GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static OcspResponse GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is OcspResponse)
+			{
+				return (OcspResponse)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new OcspResponse((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public OcspResponse(
+            OcspResponseStatus	responseStatus,
+            ResponseBytes		responseBytes)
+        {
+			if (responseStatus == null)
+				throw new ArgumentNullException("responseStatus");
+
+			this.responseStatus = responseStatus;
+            this.responseBytes = responseBytes;
+        }
+
+		private OcspResponse(
+            Asn1Sequence seq)
+        {
+            responseStatus = new OcspResponseStatus(
+				DerEnumerated.GetInstance(seq[0]));
+
+			if (seq.Count == 2)
+            {
+                responseBytes = ResponseBytes.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+            }
+        }
+
+		public OcspResponseStatus ResponseStatus
+		{
+			get { return responseStatus; }
+		}
+
+		public ResponseBytes ResponseBytes
+		{
+			get { return responseBytes; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OcspResponse ::= Sequence {
+         *     responseStatus         OcspResponseStatus,
+         *     responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(responseStatus);
+
+			if (responseBytes != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, responseBytes));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/OCSPResponseStatus.cs b/crypto/src/asn1/ocsp/OCSPResponseStatus.cs
new file mode 100644
index 000000000..653317e33
--- /dev/null
+++ b/crypto/src/asn1/ocsp/OCSPResponseStatus.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class OcspResponseStatus
+        : DerEnumerated
+    {
+        public const int Successful = 0;
+        public const int MalformedRequest = 1;
+        public const int InternalError = 2;
+        public const int TryLater = 3;
+        public const int SignatureRequired = 5;
+        public const int Unauthorized = 6;
+
+		/**
+         * The OcspResponseStatus enumeration.
+         * <pre>
+         * OcspResponseStatus ::= Enumerated {
+         *     successful            (0),  --Response has valid confirmations
+         *     malformedRequest      (1),  --Illegal confirmation request
+         *     internalError         (2),  --Internal error in issuer
+         *     tryLater              (3),  --Try again later
+         *                                 --(4) is not used
+         *     sigRequired           (5),  --Must sign the request
+         *     unauthorized          (6)   --Request unauthorized
+         * }
+         * </pre>
+         */
+        public OcspResponseStatus(int value)
+			: base(value)
+        {
+        }
+
+		public OcspResponseStatus(DerEnumerated value)
+			: base(value.Value.IntValue)
+        {
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/Request.cs b/crypto/src/asn1/ocsp/Request.cs
new file mode 100644
index 000000000..116c15e73
--- /dev/null
+++ b/crypto/src/asn1/ocsp/Request.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class Request
+        : Asn1Encodable
+    {
+        private readonly CertID			reqCert;
+        private readonly X509Extensions	singleRequestExtensions;
+
+		public static Request GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static Request GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Request)
+			{
+				return (Request)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Request((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public Request(
+            CertID			reqCert,
+            X509Extensions	singleRequestExtensions)
+        {
+			if (reqCert == null)
+				throw new ArgumentNullException("reqCert");
+
+			this.reqCert = reqCert;
+            this.singleRequestExtensions = singleRequestExtensions;
+        }
+
+		private Request(
+			Asn1Sequence seq)
+        {
+			reqCert = CertID.GetInstance(seq[0]);
+
+			if (seq.Count == 2)
+            {
+                singleRequestExtensions = X509Extensions.GetInstance(
+					(Asn1TaggedObject)seq[1], true);
+            }
+        }
+
+		public CertID ReqCert
+		{
+			get { return reqCert; }
+		}
+
+		public X509Extensions SingleRequestExtensions
+		{
+			get { return singleRequestExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Request         ::=     Sequence {
+         *     reqCert                     CertID,
+         *     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(reqCert);
+
+			if (singleRequestExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, singleRequestExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/ResponderID.cs b/crypto/src/asn1/ocsp/ResponderID.cs
new file mode 100644
index 000000000..143b17339
--- /dev/null
+++ b/crypto/src/asn1/ocsp/ResponderID.cs
@@ -0,0 +1,107 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class ResponderID
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly Asn1Encodable id;
+
+		public static ResponderID GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ResponderID)
+			{
+				return (ResponderID)obj;
+			}
+
+			if (obj is DerOctetString)
+			{
+				return new ResponderID((DerOctetString)obj);
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)obj;
+
+				if (o.TagNo == 1)
+				{
+					return new ResponderID(X509Name.GetInstance(o, true));
+				}
+
+				return new ResponderID(Asn1OctetString.GetInstance(o, true));
+			}
+
+			return new ResponderID(X509Name.GetInstance(obj));
+		}
+
+		public ResponderID(
+            Asn1OctetString id)
+        {
+			if (id == null)
+				throw new ArgumentNullException("id");
+
+			this.id = id;
+        }
+
+		public ResponderID(
+            X509Name id)
+        {
+			if (id == null)
+				throw new ArgumentNullException("id");
+
+			this.id = id;
+        }
+
+		public static ResponderID GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(obj.GetObject()); // must be explicitly tagged
+		}
+
+		public virtual byte[] GetKeyHash()
+		{
+			if (id is Asn1OctetString)
+			{
+				return ((Asn1OctetString)id).GetOctets();
+			}
+
+			return null;
+		}
+
+		public virtual X509Name Name
+		{
+			get
+			{
+				if (id is Asn1OctetString)
+				{
+					return null;
+				}
+
+				return X509Name.GetInstance(id);
+			}
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ResponderID ::= CHOICE {
+         *      byName          [1] Name,
+         *      byKey           [2] KeyHash }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            if (id is Asn1OctetString)
+            {
+                return new DerTaggedObject(true, 2, id);
+            }
+
+			return new DerTaggedObject(true, 1, id);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/ResponseBytes.cs b/crypto/src/asn1/ocsp/ResponseBytes.cs
new file mode 100644
index 000000000..2ce59faea
--- /dev/null
+++ b/crypto/src/asn1/ocsp/ResponseBytes.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class ResponseBytes
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier responseType;
+        private readonly Asn1OctetString response;
+
+		public static ResponseBytes GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static ResponseBytes GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ResponseBytes)
+			{
+				return (ResponseBytes)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ResponseBytes((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public ResponseBytes(
+            DerObjectIdentifier	responseType,
+            Asn1OctetString		response)
+        {
+			if (responseType == null)
+				throw new ArgumentNullException("responseType");
+			if (response == null)
+				throw new ArgumentNullException("response");
+
+			this.responseType = responseType;
+            this.response = response;
+        }
+
+		private ResponseBytes(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.responseType = DerObjectIdentifier.GetInstance(seq[0]);
+            this.response = Asn1OctetString.GetInstance(seq[1]);
+        }
+
+		public DerObjectIdentifier ResponseType
+		{
+			get { return responseType; }
+		}
+
+		public Asn1OctetString Response
+		{
+			get { return response; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ResponseBytes ::=       Sequence {
+         *     responseType   OBJECT IDENTIFIER,
+         *     response       OCTET STRING }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(responseType, response);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/ResponseData.cs b/crypto/src/asn1/ocsp/ResponseData.cs
new file mode 100644
index 000000000..173829db8
--- /dev/null
+++ b/crypto/src/asn1/ocsp/ResponseData.cs
@@ -0,0 +1,158 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+	public class ResponseData
+		: Asn1Encodable
+	{
+		private static readonly DerInteger V1 = new DerInteger(0);
+
+		private readonly bool                versionPresent;
+		private readonly DerInteger          version;
+		private readonly ResponderID         responderID;
+		private readonly DerGeneralizedTime  producedAt;
+		private readonly Asn1Sequence        responses;
+		private readonly X509Extensions      responseExtensions;
+
+		public static ResponseData GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static ResponseData GetInstance(
+			object  obj)
+		{
+			if (obj == null || obj is ResponseData)
+			{
+				return (ResponseData)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ResponseData((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public ResponseData(
+			DerInteger          version,
+			ResponderID         responderID,
+			DerGeneralizedTime  producedAt,
+			Asn1Sequence        responses,
+			X509Extensions      responseExtensions)
+		{
+			this.version = version;
+			this.responderID = responderID;
+			this.producedAt = producedAt;
+			this.responses = responses;
+			this.responseExtensions = responseExtensions;
+		}
+
+		public ResponseData(
+			ResponderID         responderID,
+			DerGeneralizedTime  producedAt,
+			Asn1Sequence        responses,
+			X509Extensions      responseExtensions)
+			: this(V1, responderID, producedAt, responses, responseExtensions)
+		{
+		}
+
+		private ResponseData(
+			Asn1Sequence seq)
+		{
+			int index = 0;
+
+			Asn1Encodable enc = seq[0];
+			if (enc is Asn1TaggedObject)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)enc;
+
+				if (o.TagNo == 0)
+				{
+					this.versionPresent = true;
+					this.version = DerInteger.GetInstance(o, true);
+					index++;
+				}
+				else
+				{
+					this.version = V1;
+				}
+			}
+			else
+			{
+				this.version = V1;
+			}
+
+			this.responderID = ResponderID.GetInstance(seq[index++]);
+			this.producedAt = (DerGeneralizedTime)seq[index++];
+			this.responses = (Asn1Sequence)seq[index++];
+
+			if (seq.Count > index)
+			{
+				this.responseExtensions = X509Extensions.GetInstance(
+					(Asn1TaggedObject)seq[index], true);
+			}
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public ResponderID ResponderID
+		{
+			get { return responderID; }
+		}
+
+		public DerGeneralizedTime ProducedAt
+		{
+			get { return producedAt; }
+		}
+
+		public Asn1Sequence Responses
+		{
+			get { return responses; }
+		}
+
+		public X509Extensions ResponseExtensions
+		{
+			get { return responseExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ResponseData ::= Sequence {
+         *     version              [0] EXPLICIT Version DEFAULT v1,
+         *     responderID              ResponderID,
+         *     producedAt               GeneralizedTime,
+         *     responses                Sequence OF SingleResponse,
+         *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (versionPresent || !version.Equals(V1))
+			{
+				v.Add(new DerTaggedObject(true, 0, version));
+			}
+
+			v.Add(responderID, producedAt, responses);
+
+			if (responseExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, responseExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/RevokedInfo.cs b/crypto/src/asn1/ocsp/RevokedInfo.cs
new file mode 100644
index 000000000..7d9d590e3
--- /dev/null
+++ b/crypto/src/asn1/ocsp/RevokedInfo.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class RevokedInfo
+        : Asn1Encodable
+    {
+        private readonly DerGeneralizedTime revocationTime;
+        private readonly CrlReason revocationReason;
+
+		public static RevokedInfo GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static RevokedInfo GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RevokedInfo)
+			{
+				return (RevokedInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RevokedInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public RevokedInfo(
+			DerGeneralizedTime revocationTime)
+			: this(revocationTime, null)
+		{
+		}
+
+		public RevokedInfo(
+            DerGeneralizedTime  revocationTime,
+            CrlReason           revocationReason)
+        {
+			if (revocationTime == null)
+				throw new ArgumentNullException("revocationTime");
+
+			this.revocationTime = revocationTime;
+            this.revocationReason = revocationReason;
+        }
+
+		private RevokedInfo(
+            Asn1Sequence seq)
+        {
+            this.revocationTime = (DerGeneralizedTime) seq[0];
+
+			if (seq.Count > 1)
+            {
+                this.revocationReason = new CrlReason(
+					DerEnumerated.GetInstance((Asn1TaggedObject) seq[1], true));
+            }
+        }
+
+		public DerGeneralizedTime RevocationTime
+		{
+			get { return revocationTime; }
+		}
+
+		public CrlReason RevocationReason
+		{
+			get { return revocationReason; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * RevokedInfo ::= Sequence {
+         *      revocationTime              GeneralizedTime,
+         *      revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector(revocationTime);
+
+			if (revocationReason != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, revocationReason));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/ServiceLocator.cs b/crypto/src/asn1/ocsp/ServiceLocator.cs
new file mode 100644
index 000000000..56bc49ded
--- /dev/null
+++ b/crypto/src/asn1/ocsp/ServiceLocator.cs
@@ -0,0 +1,95 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class ServiceLocator
+        : Asn1Encodable
+    {
+        private readonly X509Name issuer;
+        private readonly Asn1Object locator;
+
+		public static ServiceLocator GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static ServiceLocator GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is ServiceLocator)
+			{
+				return (ServiceLocator) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new ServiceLocator((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public ServiceLocator(
+			X509Name	issuer)
+			: this(issuer, null)
+		{
+		}
+
+		public ServiceLocator(
+			X509Name	issuer,
+			Asn1Object	locator)
+		{
+			if (issuer == null)
+				throw new ArgumentNullException("issuer");
+
+			this.issuer = issuer;
+			this.locator = locator;
+		}
+
+		private ServiceLocator(
+			Asn1Sequence seq)
+		{
+			this.issuer = X509Name.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.locator = seq[1].ToAsn1Object();
+			}
+		}
+
+		public X509Name Issuer
+		{
+			get { return issuer; }
+		}
+
+		public Asn1Object Locator
+		{
+			get { return locator; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * ServiceLocator ::= Sequence {
+         *     issuer    Name,
+         *     locator   AuthorityInfoAccessSyntax OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(issuer);
+
+			if (locator != null)
+            {
+                v.Add(locator);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/Signature.cs b/crypto/src/asn1/ocsp/Signature.cs
new file mode 100644
index 000000000..a07e7a709
--- /dev/null
+++ b/crypto/src/asn1/ocsp/Signature.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class Signature
+        : Asn1Encodable
+    {
+        internal AlgorithmIdentifier	signatureAlgorithm;
+        internal DerBitString			signatureValue;
+        internal Asn1Sequence			certs;
+
+		public static Signature GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static Signature GetInstance(
+			object  obj)
+		{
+			if (obj == null || obj is Signature)
+			{
+				return (Signature)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Signature((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public Signature(
+            AlgorithmIdentifier signatureAlgorithm,
+            DerBitString        signatureValue)
+			: this(signatureAlgorithm, signatureValue, null)
+        {
+        }
+
+		public Signature(
+            AlgorithmIdentifier	signatureAlgorithm,
+            DerBitString		signatureValue,
+            Asn1Sequence		certs)
+        {
+			if (signatureAlgorithm == null)
+				throw new ArgumentException("signatureAlgorithm");
+			if (signatureValue == null)
+				throw new ArgumentException("signatureValue");
+
+			this.signatureAlgorithm = signatureAlgorithm;
+            this.signatureValue = signatureValue;
+            this.certs = certs;
+        }
+
+		private Signature(
+            Asn1Sequence seq)
+        {
+            signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+            signatureValue = (DerBitString)seq[1];
+
+			if (seq.Count == 3)
+            {
+                certs = Asn1Sequence.GetInstance(
+					(Asn1TaggedObject)seq[2], true);
+            }
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return signatureAlgorithm; }
+		}
+
+		public DerBitString SignatureValue
+		{
+			get { return signatureValue; }
+		}
+
+		public Asn1Sequence Certs
+		{
+			get { return certs; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Signature       ::=     Sequence {
+         *     signatureAlgorithm      AlgorithmIdentifier,
+         *     signature               BIT STRING,
+         *     certs               [0] EXPLICIT Sequence OF Certificate OPTIONAL}
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				signatureAlgorithm, signatureValue);
+
+			if (certs != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, certs));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/SingleResponse.cs b/crypto/src/asn1/ocsp/SingleResponse.cs
new file mode 100644
index 000000000..93d4c21d6
--- /dev/null
+++ b/crypto/src/asn1/ocsp/SingleResponse.cs
@@ -0,0 +1,137 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class SingleResponse
+        : Asn1Encodable
+    {
+        private readonly CertID              certID;
+        private readonly CertStatus          certStatus;
+        private readonly DerGeneralizedTime  thisUpdate;
+        private readonly DerGeneralizedTime  nextUpdate;
+        private readonly X509Extensions      singleExtensions;
+
+		public SingleResponse(
+            CertID              certID,
+            CertStatus          certStatus,
+            DerGeneralizedTime  thisUpdate,
+            DerGeneralizedTime  nextUpdate,
+            X509Extensions      singleExtensions)
+        {
+            this.certID = certID;
+            this.certStatus = certStatus;
+            this.thisUpdate = thisUpdate;
+            this.nextUpdate = nextUpdate;
+            this.singleExtensions = singleExtensions;
+        }
+
+		public SingleResponse(
+            Asn1Sequence seq)
+        {
+            this.certID = CertID.GetInstance(seq[0]);
+            this.certStatus = CertStatus.GetInstance(seq[1]);
+            this.thisUpdate = (DerGeneralizedTime)seq[2];
+
+			if (seq.Count > 4)
+            {
+                this.nextUpdate = DerGeneralizedTime.GetInstance(
+					(Asn1TaggedObject) seq[3], true);
+                this.singleExtensions = X509Extensions.GetInstance(
+					(Asn1TaggedObject) seq[4], true);
+            }
+            else if (seq.Count > 3)
+            {
+                Asn1TaggedObject o = (Asn1TaggedObject) seq[3];
+
+				if (o.TagNo == 0)
+                {
+                    this.nextUpdate = DerGeneralizedTime.GetInstance(o, true);
+                }
+                else
+                {
+                    this.singleExtensions = X509Extensions.GetInstance(o, true);
+                }
+            }
+        }
+
+		public static SingleResponse GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static SingleResponse GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is SingleResponse)
+            {
+                return (SingleResponse)obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SingleResponse((Asn1Sequence)obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public CertID CertId
+		{
+			get { return certID; }
+		}
+
+		public CertStatus CertStatus
+		{
+			get { return certStatus; }
+		}
+
+		public DerGeneralizedTime ThisUpdate
+		{
+			get { return thisUpdate; }
+		}
+
+		public DerGeneralizedTime NextUpdate
+		{
+			get { return nextUpdate; }
+		}
+
+		public X509Extensions SingleExtensions
+		{
+			get { return singleExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  SingleResponse ::= Sequence {
+         *          certID                       CertID,
+         *          certStatus                   CertStatus,
+         *          thisUpdate                   GeneralizedTime,
+         *          nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+         *          singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				certID, certStatus, thisUpdate);
+
+			if (nextUpdate != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, nextUpdate));
+            }
+
+			if (singleExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, singleExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/ocsp/TBSRequest.cs b/crypto/src/asn1/ocsp/TBSRequest.cs
new file mode 100644
index 000000000..6bf75eb96
--- /dev/null
+++ b/crypto/src/asn1/ocsp/TBSRequest.cs
@@ -0,0 +1,151 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+using System;
+
+namespace Org.BouncyCastle.Asn1.Ocsp
+{
+    public class TbsRequest
+        : Asn1Encodable
+    {
+		private static readonly DerInteger V1 = new DerInteger(0);
+
+		private readonly DerInteger      version;
+        private readonly GeneralName     requestorName;
+        private readonly Asn1Sequence    requestList;
+        private readonly X509Extensions  requestExtensions;
+
+		private bool versionSet;
+
+		public static TbsRequest GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static TbsRequest GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is TbsRequest)
+			{
+				return (TbsRequest)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new TbsRequest((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public TbsRequest(
+            GeneralName     requestorName,
+            Asn1Sequence    requestList,
+            X509Extensions  requestExtensions)
+        {
+            this.version = V1;
+            this.requestorName = requestorName;
+            this.requestList = requestList;
+            this.requestExtensions = requestExtensions;
+        }
+
+		private TbsRequest(
+            Asn1Sequence seq)
+        {
+            int index = 0;
+
+			Asn1Encodable enc = seq[0];
+			if (enc is Asn1TaggedObject)
+            {
+                Asn1TaggedObject o = (Asn1TaggedObject) enc;
+
+				if (o.TagNo == 0)
+                {
+					versionSet = true;
+					version = DerInteger.GetInstance(o, true);
+                    index++;
+                }
+                else
+                {
+                    version = V1;
+                }
+            }
+            else
+            {
+                version = V1;
+            }
+
+			if (seq[index] is Asn1TaggedObject)
+            {
+                requestorName = GeneralName.GetInstance((Asn1TaggedObject) seq[index++], true);
+            }
+
+			requestList = (Asn1Sequence) seq[index++];
+
+			if (seq.Count == (index + 1))
+            {
+                requestExtensions = X509Extensions.GetInstance((Asn1TaggedObject) seq[index], true);
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public GeneralName RequestorName
+		{
+			get { return requestorName; }
+		}
+
+		public Asn1Sequence RequestList
+		{
+			get { return requestList; }
+		}
+
+		public X509Extensions RequestExtensions
+		{
+			get { return requestExtensions; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * TBSRequest      ::=     Sequence {
+         *     version             [0]     EXPLICIT Version DEFAULT v1,
+         *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+         *     requestList                 Sequence OF Request,
+         *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			//
+			// if default don't include - unless explicitly provided. Not strictly correct
+			// but required for some requests
+			//
+			if (!version.Equals(V1) || versionSet)
+			{
+                v.Add(new DerTaggedObject(true, 0, version));
+            }
+
+			if (requestorName != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, requestorName));
+            }
+
+			v.Add(requestList);
+
+			if (requestExtensions != null)
+            {
+                v.Add(new DerTaggedObject(true, 2, requestExtensions));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/oiw/ElGamalParameter.cs b/crypto/src/asn1/oiw/ElGamalParameter.cs
new file mode 100644
index 000000000..3e020f059
--- /dev/null
+++ b/crypto/src/asn1/oiw/ElGamalParameter.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Oiw
+{
+    public class ElGamalParameter
+        : Asn1Encodable
+    {
+        internal DerInteger p, g;
+
+		public ElGamalParameter(
+            BigInteger	p,
+            BigInteger	g)
+        {
+            this.p = new DerInteger(p);
+            this.g = new DerInteger(g);
+        }
+
+		public ElGamalParameter(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			p = DerInteger.GetInstance(seq[0]);
+			g = DerInteger.GetInstance(seq[1]);
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(p, g);
+        }
+    }
+}
diff --git a/crypto/src/asn1/oiw/OIWObjectIdentifiers.cs b/crypto/src/asn1/oiw/OIWObjectIdentifiers.cs
new file mode 100644
index 000000000..3da226301
--- /dev/null
+++ b/crypto/src/asn1/oiw/OIWObjectIdentifiers.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Asn1.Oiw
+{
+	public abstract class OiwObjectIdentifiers
+	{
+		public static readonly DerObjectIdentifier MD4WithRsa			= new DerObjectIdentifier("1.3.14.3.2.2");
+		public static readonly DerObjectIdentifier MD5WithRsa			= new DerObjectIdentifier("1.3.14.3.2.3");
+		public static readonly DerObjectIdentifier MD4WithRsaEncryption	= new DerObjectIdentifier("1.3.14.3.2.4");
+
+		public static readonly DerObjectIdentifier DesEcb				= new DerObjectIdentifier("1.3.14.3.2.6");
+		public static readonly DerObjectIdentifier DesCbc				= new DerObjectIdentifier("1.3.14.3.2.7");
+		public static readonly DerObjectIdentifier DesOfb				= new DerObjectIdentifier("1.3.14.3.2.8");
+		public static readonly DerObjectIdentifier DesCfb				= new DerObjectIdentifier("1.3.14.3.2.9");
+
+		public static readonly DerObjectIdentifier DesEde				= new DerObjectIdentifier("1.3.14.3.2.17");
+
+		// id-SHA1 OBJECT IDENTIFIER ::=
+		//   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+		public static readonly DerObjectIdentifier IdSha1				= new DerObjectIdentifier("1.3.14.3.2.26");
+
+		public static readonly DerObjectIdentifier DsaWithSha1			= new DerObjectIdentifier("1.3.14.3.2.27");
+
+		public static readonly DerObjectIdentifier Sha1WithRsa			= new DerObjectIdentifier("1.3.14.3.2.29");
+
+		// ElGamal Algorithm OBJECT IDENTIFIER ::=
+		// {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+		//
+		public static readonly DerObjectIdentifier ElGamalAlgorithm		= new DerObjectIdentifier("1.3.14.7.2.1.1");
+	}
+}
diff --git a/crypto/src/asn1/pkcs/Attribute.cs b/crypto/src/asn1/pkcs/Attribute.cs
new file mode 100644
index 000000000..ceec115bd
--- /dev/null
+++ b/crypto/src/asn1/pkcs/Attribute.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class AttributePkcs
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier attrType;
+        private readonly Asn1Set attrValues;
+
+		/**
+         * return an Attribute object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static AttributePkcs GetInstance(
+            object obj)
+        {
+            AttributePkcs attr = obj as AttributePkcs;
+            if (obj == null || attr != null)
+            {
+                return attr;
+            }
+
+			Asn1Sequence seq = obj as Asn1Sequence;
+            if (seq != null)
+            {
+                return new AttributePkcs(seq);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private AttributePkcs(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			attrType = DerObjectIdentifier.GetInstance(seq[0]);
+            attrValues = Asn1Set.GetInstance(seq[1]);
+        }
+
+		public AttributePkcs(
+            DerObjectIdentifier	attrType,
+            Asn1Set				attrValues)
+        {
+            this.attrType = attrType;
+            this.attrValues = attrValues;
+        }
+
+		public DerObjectIdentifier AttrType
+		{
+			get { return attrType; }
+		}
+
+		public Asn1Set AttrValues
+		{
+			get { return attrValues; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Attr ::= Sequence {
+         *     attrType OBJECT IDENTIFIER,
+         *     attrValues Set OF AttributeValue
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(attrType, attrValues);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/AuthenticatedSafe.cs b/crypto/src/asn1/pkcs/AuthenticatedSafe.cs
new file mode 100644
index 000000000..f3dabb89c
--- /dev/null
+++ b/crypto/src/asn1/pkcs/AuthenticatedSafe.cs
@@ -0,0 +1,37 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class AuthenticatedSafe
+        : Asn1Encodable
+    {
+        private readonly ContentInfo[] info;
+
+		public AuthenticatedSafe(
+            Asn1Sequence seq)
+        {
+            info = new ContentInfo[seq.Count];
+
+			for (int i = 0; i != info.Length; i++)
+            {
+                info[i] = ContentInfo.GetInstance(seq[i]);
+            }
+        }
+
+		public AuthenticatedSafe(
+            ContentInfo[] info)
+        {
+            this.info = (ContentInfo[]) info.Clone();
+        }
+
+		public ContentInfo[] GetContentInfo()
+        {
+            return (ContentInfo[]) info.Clone();
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new BerSequence(info);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/CertBag.cs b/crypto/src/asn1/pkcs/CertBag.cs
new file mode 100644
index 000000000..b6f4c8a30
--- /dev/null
+++ b/crypto/src/asn1/pkcs/CertBag.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class CertBag
+        : Asn1Encodable
+    {
+//		private readonly Asn1Sequence seq;
+        private readonly DerObjectIdentifier certID;
+        private readonly Asn1Object certValue;
+
+		public CertBag(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+//			this.seq = seq;
+            this.certID = DerObjectIdentifier.GetInstance(seq[0]);
+            this.certValue = DerTaggedObject.GetInstance(seq[1]).GetObject();
+        }
+
+		public CertBag(
+            DerObjectIdentifier	certID,
+            Asn1Object			certValue)
+        {
+            this.certID = certID;
+            this.certValue = certValue;
+        }
+
+		public DerObjectIdentifier CertID
+		{
+			get { return certID; }
+		}
+
+		public Asn1Object CertValue
+		{
+			get { return certValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(certID, new DerTaggedObject(0, certValue));
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/CertificationRequest.cs b/crypto/src/asn1/pkcs/CertificationRequest.cs
new file mode 100644
index 000000000..32b1612d2
--- /dev/null
+++ b/crypto/src/asn1/pkcs/CertificationRequest.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * Pkcs10 Certfication request object.
+     * <pre>
+     * CertificationRequest ::= Sequence {
+     *   certificationRequestInfo  CertificationRequestInfo,
+     *   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+     *   signature                 BIT STRING
+     * }
+     * </pre>
+     */
+    public class CertificationRequest
+        : Asn1Encodable
+    {
+        protected CertificationRequestInfo	reqInfo;
+        protected AlgorithmIdentifier		sigAlgId;
+        protected DerBitString				sigBits;
+
+		public static CertificationRequest GetInstance(
+			object obj)
+		{
+			if (obj is CertificationRequest)
+				return (CertificationRequest)obj;
+
+			if (obj != null)
+				return new CertificationRequest((Asn1Sequence)obj);
+
+			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)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+            sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+            sigBits = DerBitString.GetInstance(seq[2]);
+        }
+
+		public CertificationRequestInfo GetCertificationRequestInfo()
+        {
+            return reqInfo;
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return sigAlgId; }
+		}
+
+		public DerBitString Signature
+		{
+			get { return sigBits; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(reqInfo, sigAlgId, sigBits);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/CertificationRequestInfo.cs b/crypto/src/asn1/pkcs/CertificationRequestInfo.cs
new file mode 100644
index 000000000..690d06878
--- /dev/null
+++ b/crypto/src/asn1/pkcs/CertificationRequestInfo.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * 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 Attr{{ IOSet }}
+     *
+     *  Attr { ATTRIBUTE:IOSet } ::= Sequence {
+     *    type    ATTRIBUTE.&amp;id({IOSet}),
+     *    values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+     *  }
+     * </pre>
+     */
+    public class CertificationRequestInfo
+        : Asn1Encodable
+    {
+        internal DerInteger				version = new DerInteger(0);
+        internal X509Name				subject;
+        internal SubjectPublicKeyInfo	subjectPKInfo;
+        internal Asn1Set				attributes;
+
+		public static CertificationRequestInfo GetInstance(
+            object  obj)
+        {
+            if (obj is CertificationRequestInfo)
+            {
+                return (CertificationRequestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new CertificationRequestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public CertificationRequestInfo(
+            X509Name				subject,
+            SubjectPublicKeyInfo	pkInfo,
+            Asn1Set					attributes)
+        {
+            this.subject = subject;
+            this.subjectPKInfo = pkInfo;
+            this.attributes = attributes;
+
+			if (subject == null || version == null || subjectPKInfo == null)
+            {
+                throw new ArgumentException(
+					"Not all mandatory fields set in CertificationRequestInfo generator.");
+            }
+        }
+
+		private CertificationRequestInfo(
+            Asn1Sequence seq)
+        {
+            version = (DerInteger) seq[0];
+
+			subject = X509Name.GetInstance(seq[1]);
+            subjectPKInfo = SubjectPublicKeyInfo.GetInstance(seq[2]);
+
+			//
+            // some CertificationRequestInfo objects seem to treat this field
+            // as optional.
+            //
+            if (seq.Count > 3)
+            {
+                DerTaggedObject tagobj = (DerTaggedObject) seq[3];
+                attributes = Asn1Set.GetInstance(tagobj, false);
+            }
+
+			if (subject == null || version == null || subjectPKInfo == null)
+            {
+                throw new ArgumentException(
+					"Not all mandatory fields set in CertificationRequestInfo generator.");
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public X509Name Subject
+		{
+			get { return subject; }
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+		{
+			get { return subjectPKInfo; }
+		}
+
+		public Asn1Set Attributes
+		{
+			get { return attributes; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, subject, subjectPKInfo);
+
+			if (attributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, attributes));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/ContentInfo.cs b/crypto/src/asn1/pkcs/ContentInfo.cs
index 78213c138..526a3c48e 100644
--- a/crypto/src/asn1/pkcs/ContentInfo.cs
+++ b/crypto/src/asn1/pkcs/ContentInfo.cs
@@ -11,34 +11,28 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         private readonly DerObjectIdentifier	contentType;
         private readonly Asn1Encodable			content;
 
-		public static ContentInfo GetInstance(
-            object obj)
+        public static ContentInfo GetInstance(object obj)
         {
-            if (obj is ContentInfo)
-            {
-                return (ContentInfo) obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new ContentInfo((Asn1Sequence) obj);
-            }
-
-			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+            if (obj == null)
+                return null;
+            ContentInfo existing = obj as ContentInfo;
+            if (existing != null)
+                return existing;
+            return new ContentInfo(Asn1Sequence.GetInstance(obj));
         }
 
-		private ContentInfo(
+        private ContentInfo(
             Asn1Sequence seq)
         {
-			contentType = (DerObjectIdentifier) seq[0];
+            contentType = (DerObjectIdentifier) seq[0];
 
-			if (seq.Count > 1)
-			{
-				content = ((Asn1TaggedObject) seq[1]).GetObject();
-			}
+            if (seq.Count > 1)
+            {
+                content = ((Asn1TaggedObject) seq[1]).GetObject();
+            }
         }
 
-		public ContentInfo(
+        public ContentInfo(
             DerObjectIdentifier	contentType,
             Asn1Encodable		content)
         {
@@ -46,17 +40,17 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             this.content = content;
         }
 
-		public DerObjectIdentifier ContentType
-		{
-			get { return contentType; }
-		}
+        public DerObjectIdentifier ContentType
+        {
+            get { return contentType; }
+        }
 
-		public Asn1Encodable Content
-		{
-			get { return content; }
-		}
+        public Asn1Encodable Content
+        {
+            get { return content; }
+        }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          * ContentInfo ::= Sequence {
@@ -69,12 +63,12 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         {
             Asn1EncodableVector v = new Asn1EncodableVector(contentType);
 
-			if (content != null)
+            if (content != null)
             {
                 v.Add(new BerTaggedObject(0, content));
             }
 
-			return new BerSequence(v);
+            return new BerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/pkcs/DHParameter.cs b/crypto/src/asn1/pkcs/DHParameter.cs
new file mode 100644
index 000000000..25a091a97
--- /dev/null
+++ b/crypto/src/asn1/pkcs/DHParameter.cs
@@ -0,0 +1,72 @@
+using Org.BouncyCastle.Asn1;
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class DHParameter
+        : Asn1Encodable
+    {
+        internal DerInteger p, g, l;
+
+		public DHParameter(
+            BigInteger	p,
+            BigInteger	g,
+            int			l)
+        {
+            this.p = new DerInteger(p);
+            this.g = new DerInteger(g);
+
+			if (l != 0)
+            {
+                this.l = new DerInteger(l);
+            }
+        }
+
+		public DHParameter(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            p = (DerInteger)e.Current;
+
+			e.MoveNext();
+            g = (DerInteger)e.Current;
+
+			if (e.MoveNext())
+            {
+                l = (DerInteger) e.Current;
+            }
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.PositiveValue; }
+		}
+
+		public BigInteger L
+		{
+            get { return l == null ? null : l.PositiveValue; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(p, g);
+
+			if (this.l != null)
+            {
+                v.Add(l);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/EncryptedData.cs b/crypto/src/asn1/pkcs/EncryptedData.cs
new file mode 100644
index 000000000..912064ace
--- /dev/null
+++ b/crypto/src/asn1/pkcs/EncryptedData.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * 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
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence data;
+//        private readonly DerObjectIdentifier bagId;
+//        private readonly Asn1Object bagValue;
+
+		public static EncryptedData GetInstance(
+             object obj)
+        {
+			if (obj is EncryptedData)
+			{
+				return (EncryptedData) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new EncryptedData((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private EncryptedData(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			int version = ((DerInteger) seq[0]).Value.IntValue;
+			if (version != 0)
+            {
+                throw new ArgumentException("sequence not version 0");
+            }
+
+			this.data = (Asn1Sequence) seq[1];
+        }
+
+		public EncryptedData(
+            DerObjectIdentifier	contentType,
+            AlgorithmIdentifier	encryptionAlgorithm,
+            Asn1Encodable		content)
+        {
+			data = new BerSequence(
+				contentType,
+				encryptionAlgorithm.ToAsn1Object(),
+				new BerTaggedObject(false, 0, content));
+        }
+
+		public DerObjectIdentifier ContentType
+        {
+            get { return (DerObjectIdentifier) data[0]; }
+        }
+
+		public AlgorithmIdentifier EncryptionAlgorithm
+        {
+			get { return AlgorithmIdentifier.GetInstance(data[1]); }
+        }
+
+		public Asn1OctetString Content
+        {
+			get
+			{
+				if (data.Count == 3)
+				{
+					DerTaggedObject o = (DerTaggedObject) data[2];
+
+					return Asn1OctetString.GetInstance(o, false);
+				}
+
+				return null;
+			}
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new BerSequence(new DerInteger(0), data);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs b/crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
new file mode 100644
index 000000000..b97b8f5ea
--- /dev/null
+++ b/crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class EncryptedPrivateKeyInfo
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier algId;
+        private readonly Asn1OctetString data;
+
+		private EncryptedPrivateKeyInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+            algId = AlgorithmIdentifier.GetInstance(seq[0]);
+            data = Asn1OctetString.GetInstance(seq[1]);
+        }
+
+		public EncryptedPrivateKeyInfo(
+            AlgorithmIdentifier	algId,
+            byte[]				encoding)
+        {
+            this.algId = algId;
+            this.data = new DerOctetString(encoding);
+        }
+
+		public static EncryptedPrivateKeyInfo GetInstance(
+             object obj)
+        {
+			if (obj is EncryptedPrivateKeyInfo)
+			{
+				return (EncryptedPrivateKeyInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new EncryptedPrivateKeyInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public AlgorithmIdentifier EncryptionAlgorithm
+		{
+			get { 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 override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algId, data);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/EncryptionScheme.cs b/crypto/src/asn1/pkcs/EncryptionScheme.cs
new file mode 100644
index 000000000..5b64d6f67
--- /dev/null
+++ b/crypto/src/asn1/pkcs/EncryptionScheme.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class EncryptionScheme
+        : AlgorithmIdentifier
+    {
+		public EncryptionScheme(
+            DerObjectIdentifier	objectID,
+            Asn1Encodable		parameters)
+			: base(objectID, parameters)
+		{
+		}
+
+		internal EncryptionScheme(
+			Asn1Sequence seq)
+			: this((DerObjectIdentifier)seq[0], seq[1])
+        {
+        }
+
+		public new static EncryptionScheme GetInstance(object obj)
+		{
+			if (obj is EncryptionScheme)
+			{
+				return (EncryptionScheme)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new EncryptionScheme((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public Asn1Object Asn1Object
+		{
+			get { return Parameters.ToAsn1Object(); }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(ObjectID, Parameters);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs b/crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs
new file mode 100644
index 000000000..ff608f15b
--- /dev/null
+++ b/crypto/src/asn1/pkcs/IssuerAndSerialNumber.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class IssuerAndSerialNumber
+        : Asn1Encodable
+    {
+        private readonly X509Name name;
+        private readonly DerInteger certSerialNumber;
+
+		public static IssuerAndSerialNumber GetInstance(
+            object obj)
+        {
+            if (obj is IssuerAndSerialNumber)
+            {
+                return (IssuerAndSerialNumber) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuerAndSerialNumber((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private IssuerAndSerialNumber(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.name = X509Name.GetInstance(seq[0]);
+            this.certSerialNumber = DerInteger.GetInstance(seq[1]);
+        }
+
+		public IssuerAndSerialNumber(
+            X509Name	name,
+            BigInteger	certSerialNumber)
+        {
+            this.name = name;
+            this.certSerialNumber = new DerInteger(certSerialNumber);
+        }
+
+		public IssuerAndSerialNumber(
+            X509Name	name,
+            DerInteger	certSerialNumber)
+        {
+            this.name = name;
+            this.certSerialNumber = certSerialNumber;
+        }
+
+		public X509Name Name
+		{
+			get { return name; }
+		}
+
+		public DerInteger CertificateSerialNumber
+		{
+			get { return certSerialNumber; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(name, certSerialNumber);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/KeyDerivationFunc.cs b/crypto/src/asn1/pkcs/KeyDerivationFunc.cs
new file mode 100644
index 000000000..9fc89853b
--- /dev/null
+++ b/crypto/src/asn1/pkcs/KeyDerivationFunc.cs
@@ -0,0 +1,21 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class KeyDerivationFunc
+		: AlgorithmIdentifier
+	{
+		internal KeyDerivationFunc(Asn1Sequence seq)
+			: base(seq)
+		{
+		}
+
+		public KeyDerivationFunc(
+			DerObjectIdentifier	id,
+			Asn1Encodable		parameters)
+			: base(id, parameters)
+		{
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/asn1/pkcs/MacData.cs b/crypto/src/asn1/pkcs/MacData.cs
new file mode 100644
index 000000000..780b24153
--- /dev/null
+++ b/crypto/src/asn1/pkcs/MacData.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class MacData
+        : Asn1Encodable
+    {
+        internal DigestInfo	digInfo;
+        internal byte[]		salt;
+        internal BigInteger	iterationCount;
+
+		public static MacData GetInstance(
+            object obj)
+        {
+            if (obj is MacData)
+            {
+                return (MacData) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new MacData((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private MacData(
+            Asn1Sequence seq)
+        {
+            this.digInfo = DigestInfo.GetInstance(seq[0]);
+            this.salt = ((Asn1OctetString) seq[1]).GetOctets();
+
+			if (seq.Count == 3)
+            {
+                this.iterationCount = ((DerInteger) seq[2]).Value;
+            }
+            else
+            {
+                this.iterationCount = BigInteger.One;
+            }
+        }
+
+		public MacData(
+            DigestInfo	digInfo,
+            byte[]		salt,
+            int			iterationCount)
+        {
+            this.digInfo = digInfo;
+            this.salt = (byte[]) salt.Clone();
+            this.iterationCount = BigInteger.ValueOf(iterationCount);
+        }
+
+		public DigestInfo Mac
+		{
+			get { return digInfo; }
+		}
+
+		public byte[] GetSalt()
+        {
+            return (byte[]) salt.Clone();
+        }
+
+		public BigInteger IterationCount
+		{
+			get { 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 DERObject construction.
+		 */
+		public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector(digInfo, new DerOctetString(salt));
+
+			if (!iterationCount.Equals(BigInteger.One))
+			{
+				v.Add(new DerInteger(iterationCount));
+			}
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/PBEParameter.cs b/crypto/src/asn1/pkcs/PBEParameter.cs
new file mode 100644
index 000000000..80d5ec3e1
--- /dev/null
+++ b/crypto/src/asn1/pkcs/PBEParameter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class PbeParameter
+		: Asn1Encodable
+	{
+		private readonly Asn1OctetString	salt;
+		private readonly DerInteger			iterationCount;
+
+		public static PbeParameter GetInstance(object obj)
+		{
+			if (obj is PbeParameter || obj == null)
+			{
+				return (PbeParameter) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PbeParameter((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		private PbeParameter(Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			salt = Asn1OctetString.GetInstance(seq[0]);
+			iterationCount = DerInteger.GetInstance(seq[1]);
+		}
+
+		public PbeParameter(byte[] salt, int iterationCount)
+		{
+			this.salt = new DerOctetString(salt);
+			this.iterationCount = new DerInteger(iterationCount);
+		}
+
+		public byte[] GetSalt()
+		{
+			return salt.GetOctets();
+		}
+
+		public BigInteger IterationCount
+		{
+			get { return iterationCount.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(salt, iterationCount);
+		}
+	}
+}
diff --git a/crypto/src/asn1/pkcs/PBES2Parameters.cs b/crypto/src/asn1/pkcs/PBES2Parameters.cs
index 645bb867c..fc6904eed 100644
--- a/crypto/src/asn1/pkcs/PBES2Parameters.cs
+++ b/crypto/src/asn1/pkcs/PBES2Parameters.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Collections;
 
 namespace Org.BouncyCastle.Asn1.Pkcs
 {
@@ -9,53 +8,58 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         private readonly KeyDerivationFunc func;
         private readonly EncryptionScheme scheme;
 
-		public static PbeS2Parameters GetInstance(
-			object obj)
-		{
-			if (obj == null || obj is PbeS2Parameters)
-				return (PbeS2Parameters) obj;
-
-			if (obj is Asn1Sequence)
-				return new PbeS2Parameters((Asn1Sequence) obj);
+        public static PbeS2Parameters GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            PbeS2Parameters existing = obj as PbeS2Parameters;
+            if (existing != null)
+                return existing;
+            return new PbeS2Parameters(Asn1Sequence.GetInstance(obj));
+        }
 
-			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
-		}
+        public PbeS2Parameters(KeyDerivationFunc keyDevFunc, EncryptionScheme encScheme)
+        {
+            this.func = keyDevFunc;
+            this.scheme = encScheme;
+        }
 
-		public PbeS2Parameters(
+        [Obsolete("Use GetInstance() instead")]
+        public PbeS2Parameters(
             Asn1Sequence seq)
         {
-			if (seq.Count != 2)
-				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+            if (seq.Count != 2)
+                throw new ArgumentException("Wrong number of elements in sequence", "seq");
 
-			Asn1Sequence funcSeq = (Asn1Sequence)seq[0].ToAsn1Object();
+            Asn1Sequence funcSeq = (Asn1Sequence)seq[0].ToAsn1Object();
 
-			// TODO Not sure if this special case is really necessary/appropriate
-			if (funcSeq[0].Equals(PkcsObjectIdentifiers.IdPbkdf2))
+            // TODO Not sure if this special case is really necessary/appropriate
+            if (funcSeq[0].Equals(PkcsObjectIdentifiers.IdPbkdf2))
             {
-				func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2,
-					Pbkdf2Params.GetInstance(funcSeq[1]));
-			}
+                func = new KeyDerivationFunc(PkcsObjectIdentifiers.IdPbkdf2,
+                    Pbkdf2Params.GetInstance(funcSeq[1]));
+            }
             else
             {
                 func = new KeyDerivationFunc(funcSeq);
             }
 
-			scheme = EncryptionScheme.GetInstance(seq[1].ToAsn1Object());
+            scheme = EncryptionScheme.GetInstance(seq[1].ToAsn1Object());
         }
 
-		public KeyDerivationFunc KeyDerivationFunc
-		{
-			get { return func; }
-		}
+        public KeyDerivationFunc KeyDerivationFunc
+        {
+            get { return func; }
+        }
 
-		public EncryptionScheme EncryptionScheme
-		{
-			get { return scheme; }
-		}
+        public EncryptionScheme EncryptionScheme
+        {
+            get { return scheme; }
+        }
 
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(func, scheme);
+            return new DerSequence(func, scheme);
         }
     }
 }
diff --git a/crypto/src/asn1/pkcs/PBKDF2Params.cs b/crypto/src/asn1/pkcs/PBKDF2Params.cs
new file mode 100644
index 000000000..1351b94cf
--- /dev/null
+++ b/crypto/src/asn1/pkcs/PBKDF2Params.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class Pbkdf2Params
+		: Asn1Encodable
+	{
+		private readonly Asn1OctetString	octStr;
+		private readonly DerInteger			iterationCount;
+		private readonly DerInteger			keyLength;
+
+		public static Pbkdf2Params GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is Pbkdf2Params)
+				return (Pbkdf2Params)obj;
+
+			if (obj is Asn1Sequence)
+				return new Pbkdf2Params((Asn1Sequence)obj);
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public Pbkdf2Params(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 2 || seq.Count > 3)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			octStr = (Asn1OctetString)seq[0];
+			iterationCount = (DerInteger)seq[1];
+
+			if (seq.Count > 2)
+			{
+				keyLength = (DerInteger)seq[2];
+			}
+		}
+
+		public Pbkdf2Params(
+			byte[] salt,
+			int iterationCount)
+		{
+			this.octStr = new DerOctetString(salt);
+			this.iterationCount = new DerInteger(iterationCount);
+		}
+
+        public Pbkdf2Params(
+            byte[]  salt,
+            int     iterationCount,
+            int     keyLength)
+            : this(salt, iterationCount)
+        {
+            this.keyLength = new DerInteger(keyLength);
+        }
+
+		public byte[] GetSalt()
+		{
+			return octStr.GetOctets();
+		}
+
+		public BigInteger IterationCount
+		{
+			get { return iterationCount.Value; }
+		}
+
+		public BigInteger KeyLength
+		{
+			get { return keyLength == null ? null : keyLength.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				octStr, iterationCount);
+
+			if (keyLength != null)
+			{
+				v.Add(keyLength);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/pkcs/PKCS12PBEParams.cs b/crypto/src/asn1/pkcs/PKCS12PBEParams.cs
new file mode 100644
index 000000000..7521f93ea
--- /dev/null
+++ b/crypto/src/asn1/pkcs/PKCS12PBEParams.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class Pkcs12PbeParams
+        : Asn1Encodable
+    {
+        private readonly DerInteger iterations;
+        private readonly Asn1OctetString iv;
+
+		public Pkcs12PbeParams(
+            byte[]	salt,
+            int		iterations)
+        {
+            this.iv = new DerOctetString(salt);
+            this.iterations = new DerInteger(iterations);
+        }
+
+		private Pkcs12PbeParams(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			iv = Asn1OctetString.GetInstance(seq[0]);
+            iterations = DerInteger.GetInstance(seq[1]);
+        }
+
+		public static Pkcs12PbeParams GetInstance(
+            object obj)
+        {
+            if (obj is Pkcs12PbeParams)
+            {
+                return (Pkcs12PbeParams) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Pkcs12PbeParams((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public BigInteger Iterations
+		{
+			get { return iterations.Value; }
+		}
+
+		public byte[] GetIV()
+        {
+            return iv.GetOctets();
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(iv, iterations);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
new file mode 100644
index 000000000..0b2ffa0d1
--- /dev/null
+++ b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
@@ -0,0 +1,256 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public abstract class PkcsObjectIdentifiers
+    {
+        //
+        // pkcs-1 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+        //
+        public const string Pkcs1 = "1.2.840.113549.1.1";
+
+		public static readonly DerObjectIdentifier RsaEncryption			= new DerObjectIdentifier(Pkcs1 + ".1");
+        public static readonly DerObjectIdentifier MD2WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".2");
+        public static readonly DerObjectIdentifier MD4WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".3");
+        public static readonly DerObjectIdentifier MD5WithRsaEncryption		= new DerObjectIdentifier(Pkcs1 + ".4");
+        public static readonly DerObjectIdentifier Sha1WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".5");
+        public static readonly DerObjectIdentifier SrsaOaepEncryptionSet	= new DerObjectIdentifier(Pkcs1 + ".6");
+        public static readonly DerObjectIdentifier IdRsaesOaep				= new DerObjectIdentifier(Pkcs1 + ".7");
+        public static readonly DerObjectIdentifier IdMgf1					= new DerObjectIdentifier(Pkcs1 + ".8");
+        public static readonly DerObjectIdentifier IdPSpecified				= new DerObjectIdentifier(Pkcs1 + ".9");
+        public static readonly DerObjectIdentifier IdRsassaPss				= new DerObjectIdentifier(Pkcs1 + ".10");
+        public static readonly DerObjectIdentifier Sha256WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".11");
+        public static readonly DerObjectIdentifier Sha384WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".12");
+        public static readonly DerObjectIdentifier Sha512WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".13");
+        public static readonly DerObjectIdentifier Sha224WithRsaEncryption	= new DerObjectIdentifier(Pkcs1 + ".14");
+
+		//
+        // pkcs-3 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
+        //
+        public const string Pkcs3 = "1.2.840.113549.1.3";
+
+		public static readonly DerObjectIdentifier    DhKeyAgreement          = new DerObjectIdentifier(Pkcs3 + ".1");
+
+		//
+        // pkcs-5 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
+        //
+        public const string Pkcs5 = "1.2.840.113549.1.5";
+
+		public static readonly DerObjectIdentifier PbeWithMD2AndDesCbc    = new DerObjectIdentifier(Pkcs5 + ".1");
+        public static readonly DerObjectIdentifier PbeWithMD2AndRC2Cbc    = new DerObjectIdentifier(Pkcs5 + ".4");
+        public static readonly DerObjectIdentifier PbeWithMD5AndDesCbc    = new DerObjectIdentifier(Pkcs5 + ".3");
+        public static readonly DerObjectIdentifier PbeWithMD5AndRC2Cbc    = new DerObjectIdentifier(Pkcs5 + ".6");
+        public static readonly DerObjectIdentifier PbeWithSha1AndDesCbc   = new DerObjectIdentifier(Pkcs5 + ".10");
+        public static readonly DerObjectIdentifier PbeWithSha1AndRC2Cbc   = new DerObjectIdentifier(Pkcs5 + ".11");
+
+        public static readonly DerObjectIdentifier IdPbeS2 = new DerObjectIdentifier(Pkcs5 + ".13");
+        public static readonly DerObjectIdentifier IdPbkdf2	= new DerObjectIdentifier(Pkcs5 + ".12");
+
+		//
+        // encryptionAlgorithm OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+        //
+        public const string EncryptionAlgorithm = "1.2.840.113549.3";
+
+		public static readonly DerObjectIdentifier DesEde3Cbc	= new DerObjectIdentifier(EncryptionAlgorithm + ".7");
+        public static readonly DerObjectIdentifier RC2Cbc		= new DerObjectIdentifier(EncryptionAlgorithm + ".2");
+
+		//
+        // object identifiers for digests
+        //
+        public const string DigestAlgorithm = "1.2.840.113549.2";
+
+		//
+        // md2 OBJECT IDENTIFIER ::=
+        //      {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 2}
+        //
+        public static readonly DerObjectIdentifier MD2 = new DerObjectIdentifier(DigestAlgorithm + ".2");
+
+        //
+        // md4 OBJECT IDENTIFIER ::=
+        //      {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 4}
+        //
+        public static readonly DerObjectIdentifier MD4 = new DerObjectIdentifier(DigestAlgorithm + ".4");
+
+        //
+        // md5 OBJECT IDENTIFIER ::=
+        //      {iso(1) member-body(2) US(840) rsadsi(113549) DigestAlgorithm(2) 5}
+        //
+        public static readonly DerObjectIdentifier MD5 = new DerObjectIdentifier(DigestAlgorithm + ".5");
+
+		public static readonly DerObjectIdentifier IdHmacWithSha1	= new DerObjectIdentifier(DigestAlgorithm + ".7");
+        public static readonly DerObjectIdentifier IdHmacWithSha224	= new DerObjectIdentifier(DigestAlgorithm + ".8");
+        public static readonly DerObjectIdentifier IdHmacWithSha256	= new DerObjectIdentifier(DigestAlgorithm + ".9");
+        public static readonly DerObjectIdentifier IdHmacWithSha384	= new DerObjectIdentifier(DigestAlgorithm + ".10");
+        public static readonly DerObjectIdentifier IdHmacWithSha512	= new DerObjectIdentifier(DigestAlgorithm + ".11");
+
+		//
+        // pkcs-7 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+        //
+        public const string Pkcs7 = "1.2.840.113549.1.7";
+
+		public static readonly DerObjectIdentifier Data                    = new DerObjectIdentifier(Pkcs7 + ".1");
+        public static readonly DerObjectIdentifier SignedData              = new DerObjectIdentifier(Pkcs7 + ".2");
+        public static readonly DerObjectIdentifier EnvelopedData           = new DerObjectIdentifier(Pkcs7 + ".3");
+        public static readonly DerObjectIdentifier SignedAndEnvelopedData  = new DerObjectIdentifier(Pkcs7 + ".4");
+        public static readonly DerObjectIdentifier DigestedData            = new DerObjectIdentifier(Pkcs7 + ".5");
+        public static readonly DerObjectIdentifier EncryptedData           = new DerObjectIdentifier(Pkcs7 + ".6");
+
+        //
+        // pkcs-9 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+        //
+        public const string Pkcs9 = "1.2.840.113549.1.9";
+
+		public static readonly DerObjectIdentifier Pkcs9AtEmailAddress					= new DerObjectIdentifier(Pkcs9 + ".1");
+        public static readonly DerObjectIdentifier Pkcs9AtUnstructuredName				= new DerObjectIdentifier(Pkcs9 + ".2");
+        public static readonly DerObjectIdentifier Pkcs9AtContentType					= new DerObjectIdentifier(Pkcs9 + ".3");
+        public static readonly DerObjectIdentifier Pkcs9AtMessageDigest					= new DerObjectIdentifier(Pkcs9 + ".4");
+        public static readonly DerObjectIdentifier Pkcs9AtSigningTime					= new DerObjectIdentifier(Pkcs9 + ".5");
+        public static readonly DerObjectIdentifier Pkcs9AtCounterSignature				= new DerObjectIdentifier(Pkcs9 + ".6");
+        public static readonly DerObjectIdentifier Pkcs9AtChallengePassword				= new DerObjectIdentifier(Pkcs9 + ".7");
+        public static readonly DerObjectIdentifier Pkcs9AtUnstructuredAddress			= new DerObjectIdentifier(Pkcs9 + ".8");
+        public static readonly DerObjectIdentifier Pkcs9AtExtendedCertificateAttributes	= new DerObjectIdentifier(Pkcs9 + ".9");
+        public static readonly DerObjectIdentifier Pkcs9AtSigningDescription			= new DerObjectIdentifier(Pkcs9 + ".13");
+        public static readonly DerObjectIdentifier Pkcs9AtExtensionRequest				= new DerObjectIdentifier(Pkcs9 + ".14");
+        public static readonly DerObjectIdentifier Pkcs9AtSmimeCapabilities				= new DerObjectIdentifier(Pkcs9 + ".15");
+        public static readonly DerObjectIdentifier Pkcs9AtFriendlyName					= new DerObjectIdentifier(Pkcs9 + ".20");
+        public static readonly DerObjectIdentifier Pkcs9AtLocalKeyID					= new DerObjectIdentifier(Pkcs9 + ".21");
+
+		[Obsolete("Use X509Certificate instead")]
+        public static readonly DerObjectIdentifier X509CertType = new DerObjectIdentifier(Pkcs9 + ".22.1");
+
+		public const string CertTypes = Pkcs9 + ".22";
+		public static readonly DerObjectIdentifier X509Certificate = new DerObjectIdentifier(CertTypes + ".1");
+		public static readonly DerObjectIdentifier SdsiCertificate = new DerObjectIdentifier(CertTypes + ".2");
+
+		public const string CrlTypes = Pkcs9 + ".23";
+		public static readonly DerObjectIdentifier X509Crl = new DerObjectIdentifier(CrlTypes + ".1");
+
+		public static readonly DerObjectIdentifier IdAlgPwriKek = new DerObjectIdentifier(Pkcs9 + ".16.3.9");
+
+        //
+        // SMIME capability sub oids.
+        //
+        public static readonly DerObjectIdentifier PreferSignedData				= new DerObjectIdentifier(Pkcs9 + ".15.1");
+        public static readonly DerObjectIdentifier CannotDecryptAny				= new DerObjectIdentifier(Pkcs9 + ".15.2");
+        public static readonly DerObjectIdentifier SmimeCapabilitiesVersions	= new DerObjectIdentifier(Pkcs9 + ".15.3");
+
+        //
+        // other SMIME attributes
+        //
+		public static readonly DerObjectIdentifier IdAAReceiptRequest = new DerObjectIdentifier(Pkcs9 + ".16.2.1");
+
+        //
+        // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+        // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)}
+        //
+        public const string IdCT = "1.2.840.113549.1.9.16.1";
+
+        public static readonly DerObjectIdentifier IdCTAuthData          = new DerObjectIdentifier(IdCT + ".2");
+        public static readonly DerObjectIdentifier IdCTTstInfo           = new DerObjectIdentifier(IdCT + ".4");
+        public static readonly DerObjectIdentifier IdCTCompressedData    = new DerObjectIdentifier(IdCT + ".9");
+		public static readonly DerObjectIdentifier IdCTAuthEnvelopedData = new DerObjectIdentifier(IdCT + ".23");
+		public static readonly DerObjectIdentifier IdCTTimestampedData   = new DerObjectIdentifier(IdCT + ".31");
+
+        //
+        // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+        // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
+        //
+        public const string IdCti = "1.2.840.113549.1.9.16.6";
+
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfOrigin	= new DerObjectIdentifier(IdCti + ".1");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfReceipt	= new DerObjectIdentifier(IdCti + ".2");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfDelivery	= new DerObjectIdentifier(IdCti + ".3");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfSender	= new DerObjectIdentifier(IdCti + ".4");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfApproval	= new DerObjectIdentifier(IdCti + ".5");
+        public static readonly DerObjectIdentifier IdCtiEtsProofOfCreation	= new DerObjectIdentifier(IdCti + ".6");
+
+        //
+        // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+        // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}
+        //
+        public const string IdAA = "1.2.840.113549.1.9.16.2";
+
+		public static readonly DerObjectIdentifier IdAAContentHint = new DerObjectIdentifier(IdAA + ".4"); // See RFC 2634
+    	public static readonly DerObjectIdentifier IdAAMsgSigDigest = new DerObjectIdentifier(IdAA + ".5");
+    	public static readonly DerObjectIdentifier IdAAContentReference = new DerObjectIdentifier(IdAA + ".10");
+
+		/*
+        * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
+        *
+        */
+        public static readonly DerObjectIdentifier IdAAEncrypKeyPref = new DerObjectIdentifier(IdAA + ".11");
+        public static readonly DerObjectIdentifier IdAASigningCertificate = new DerObjectIdentifier(IdAA + ".12");
+		public static readonly DerObjectIdentifier IdAASigningCertificateV2 = new DerObjectIdentifier(IdAA + ".47");
+
+		public static readonly DerObjectIdentifier IdAAContentIdentifier = new DerObjectIdentifier(IdAA + ".7"); // See RFC 2634
+
+		/*
+		 * RFC 3126
+		 */
+		public static readonly DerObjectIdentifier IdAASignatureTimeStampToken = new DerObjectIdentifier(IdAA + ".14");
+
+		public static readonly DerObjectIdentifier IdAAEtsSigPolicyID = new DerObjectIdentifier(IdAA + ".15");
+		public static readonly DerObjectIdentifier IdAAEtsCommitmentType = new DerObjectIdentifier(IdAA + ".16");
+		public static readonly DerObjectIdentifier IdAAEtsSignerLocation = new DerObjectIdentifier(IdAA + ".17");
+		public static readonly DerObjectIdentifier IdAAEtsSignerAttr = new DerObjectIdentifier(IdAA + ".18");
+		public static readonly DerObjectIdentifier IdAAEtsOtherSigCert = new DerObjectIdentifier(IdAA + ".19");
+		public static readonly DerObjectIdentifier IdAAEtsContentTimestamp = new DerObjectIdentifier(IdAA + ".20");
+		public static readonly DerObjectIdentifier IdAAEtsCertificateRefs = new DerObjectIdentifier(IdAA + ".21");
+		public static readonly DerObjectIdentifier IdAAEtsRevocationRefs = new DerObjectIdentifier(IdAA + ".22");
+		public static readonly DerObjectIdentifier IdAAEtsCertValues = new DerObjectIdentifier(IdAA + ".23");
+		public static readonly DerObjectIdentifier IdAAEtsRevocationValues = new DerObjectIdentifier(IdAA + ".24");
+		public static readonly DerObjectIdentifier IdAAEtsEscTimeStamp = new DerObjectIdentifier(IdAA + ".25");
+		public static readonly DerObjectIdentifier IdAAEtsCertCrlTimestamp = new DerObjectIdentifier(IdAA + ".26");
+		public static readonly DerObjectIdentifier IdAAEtsArchiveTimestamp = new DerObjectIdentifier(IdAA + ".27");
+
+		[Obsolete("Use 'IdAAEtsSigPolicyID' instead")]
+		public static readonly DerObjectIdentifier IdAASigPolicyID = IdAAEtsSigPolicyID;
+		[Obsolete("Use 'IdAAEtsCommitmentType' instead")]
+		public static readonly DerObjectIdentifier IdAACommitmentType = IdAAEtsCommitmentType;
+		[Obsolete("Use 'IdAAEtsSignerLocation' instead")]
+		public static readonly DerObjectIdentifier IdAASignerLocation = IdAAEtsSignerLocation;
+		[Obsolete("Use 'IdAAEtsOtherSigCert' instead")]
+		public static readonly DerObjectIdentifier IdAAOtherSigCert = IdAAEtsOtherSigCert;
+
+		//
+		// id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+		// rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}
+		//
+		public const string IdSpq = "1.2.840.113549.1.9.16.5";
+
+		public static readonly DerObjectIdentifier IdSpqEtsUri = new DerObjectIdentifier(IdSpq + ".1");
+		public static readonly DerObjectIdentifier IdSpqEtsUNotice = new DerObjectIdentifier(IdSpq + ".2");
+
+		//
+        // pkcs-12 OBJECT IDENTIFIER ::= {
+        //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }
+        //
+        public const string Pkcs12 = "1.2.840.113549.1.12";
+        public const string BagTypes = Pkcs12 + ".10.1";
+
+        public static readonly DerObjectIdentifier KeyBag				= new DerObjectIdentifier(BagTypes + ".1");
+        public static readonly DerObjectIdentifier Pkcs8ShroudedKeyBag	= new DerObjectIdentifier(BagTypes + ".2");
+        public static readonly DerObjectIdentifier CertBag				= new DerObjectIdentifier(BagTypes + ".3");
+        public static readonly DerObjectIdentifier CrlBag				= new DerObjectIdentifier(BagTypes + ".4");
+        public static readonly DerObjectIdentifier SecretBag			= new DerObjectIdentifier(BagTypes + ".5");
+        public static readonly DerObjectIdentifier SafeContentsBag		= new DerObjectIdentifier(BagTypes + ".6");
+
+        public const string Pkcs12PbeIds = Pkcs12 + ".1";
+
+        public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC4			= new DerObjectIdentifier(Pkcs12PbeIds + ".1");
+        public static readonly DerObjectIdentifier PbeWithShaAnd40BitRC4			= new DerObjectIdentifier(Pkcs12PbeIds + ".2");
+        public static readonly DerObjectIdentifier PbeWithShaAnd3KeyTripleDesCbc	= new DerObjectIdentifier(Pkcs12PbeIds + ".3");
+        public static readonly DerObjectIdentifier PbeWithShaAnd2KeyTripleDesCbc	= new DerObjectIdentifier(Pkcs12PbeIds + ".4");
+        public static readonly DerObjectIdentifier PbeWithShaAnd128BitRC2Cbc		= new DerObjectIdentifier(Pkcs12PbeIds + ".5");
+        public static readonly DerObjectIdentifier PbewithShaAnd40BitRC2Cbc			= new DerObjectIdentifier(Pkcs12PbeIds + ".6");
+
+		public static readonly DerObjectIdentifier IdAlgCms3DesWrap = new DerObjectIdentifier("1.2.840.113549.1.9.16.3.6");
+		public static readonly DerObjectIdentifier IdAlgCmsRC2Wrap = new DerObjectIdentifier("1.2.840.113549.1.9.16.3.7");
+	}
+}
diff --git a/crypto/src/asn1/pkcs/Pfx.cs b/crypto/src/asn1/pkcs/Pfx.cs
new file mode 100644
index 000000000..9676f64fc
--- /dev/null
+++ b/crypto/src/asn1/pkcs/Pfx.cs
@@ -0,0 +1,65 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * the infamous Pfx from Pkcs12
+     */
+    public class Pfx
+        : Asn1Encodable
+    {
+        private ContentInfo	contentInfo;
+        private MacData		macData;
+
+		public Pfx(
+            Asn1Sequence seq)
+        {
+            BigInteger version = ((DerInteger) seq[0]).Value;
+            if (version.IntValue != 3)
+            {
+                throw new ArgumentException("wrong version for PFX PDU");
+            }
+
+			contentInfo = ContentInfo.GetInstance(seq[1]);
+
+			if (seq.Count == 3)
+            {
+                macData = MacData.GetInstance(seq[2]);
+            }
+        }
+
+		public Pfx(
+            ContentInfo	contentInfo,
+            MacData		macData)
+        {
+            this.contentInfo = contentInfo;
+            this.macData = macData;
+        }
+
+		public ContentInfo AuthSafe
+		{
+			get { return contentInfo; }
+		}
+
+		public MacData MacData
+		{
+			get { return macData; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerInteger(3), contentInfo);
+
+			if (macData != null)
+            {
+                v.Add(macData);
+            }
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
index bd0ef7d1e..404277ba6 100644
--- a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
+++ b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -10,88 +10,100 @@ namespace Org.BouncyCastle.Asn1.Pkcs
     public class PrivateKeyInfo
         : Asn1Encodable
     {
-        private readonly Asn1Object				privKey;
+        private readonly Asn1OctetString        privKey;
         private readonly AlgorithmIdentifier	algID;
-		private readonly Asn1Set				attributes;
+        private readonly Asn1Set				attributes;
 
-		public static PrivateKeyInfo GetInstance(
-			object obj)
-		{
-			if (obj is PrivateKeyInfo)
-				return (PrivateKeyInfo) obj;
+        public static PrivateKeyInfo GetInstance(Asn1TaggedObject obj, bool explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
 
-			if (obj != null)
-				return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+        public static PrivateKeyInfo GetInstance(
+            object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is PrivateKeyInfo)
+                return (PrivateKeyInfo) obj;
+            return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+        }
 
-			return null;
-		}
+        public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Object privateKey)
+            : this(algID, privateKey, null)
+        {
+        }
 
-		public PrivateKeyInfo(
+        public PrivateKeyInfo(
             AlgorithmIdentifier	algID,
-            Asn1Object			privateKey)
-			: this(algID, privateKey, null)
-		{
-		}
-
-		public PrivateKeyInfo(
-			AlgorithmIdentifier	algID,
-			Asn1Object			privateKey,
-			Asn1Set				attributes)
-		{
-			this.privKey = privateKey;
-			this.algID = algID;
-			this.attributes = attributes;
-		}
-
-		private PrivateKeyInfo(
-            Asn1Sequence seq)
+            Asn1Object			privateKey,
+            Asn1Set				attributes)
+        {
+            this.algID = algID;
+            this.privKey = new DerOctetString(privateKey.GetEncoded(Asn1Encodable.Der));
+            this.attributes = attributes;
+        }
+
+        private PrivateKeyInfo(Asn1Sequence seq)
         {
             IEnumerator e = seq.GetEnumerator();
 
-			e.MoveNext();
-            BigInteger version = ((DerInteger) e.Current).Value;
+            e.MoveNext();
+            BigInteger version = ((DerInteger)e.Current).Value;
             if (version.IntValue != 0)
             {
-                throw new ArgumentException("wrong version for private key info");
+                throw new ArgumentException("wrong version for private key info: " + version.IntValue);
             }
 
-			e.MoveNext();
+            e.MoveNext();
             algID = AlgorithmIdentifier.GetInstance(e.Current);
+            e.MoveNext();
+            privKey = Asn1OctetString.GetInstance(e.Current);
 
-			try
+            if (e.MoveNext())
             {
-				e.MoveNext();
-				Asn1OctetString data = (Asn1OctetString) e.Current;
-
-				privKey = Asn1Object.FromByteArray(data.GetOctets());
-            }
-            catch (IOException)
-            {
-				throw new ArgumentException("Error recoverying private key from sequence");
+                attributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
             }
+        }
+
+        public virtual AlgorithmIdentifier PrivateKeyAlgorithm
+        {
+            get { return algID; }
+        }
 
-			if (e.MoveNext())
-			{
-				attributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false);
-			}
-		}
+        [Obsolete("Use 'PrivateKeyAlgorithm' property instead")]
+        public virtual AlgorithmIdentifier AlgorithmID
+        {
+            get { return algID; }
+        }
 
-		public AlgorithmIdentifier AlgorithmID
-		{
-			get { return algID; }
-		}
+        public virtual Asn1Object ParsePrivateKey()
+        {
+            return Asn1Object.FromByteArray(privKey.GetOctets());
+        }
 
-		public Asn1Object PrivateKey
-		{
-			get { return privKey; }
-		}
+        [Obsolete("Use 'ParsePrivateKey' instead")]
+        public virtual Asn1Object PrivateKey
+        {
+            get
+            {
+                try
+                {
+                    return ParsePrivateKey();
+                }
+                catch (IOException)
+                {
+                    throw new InvalidOperationException("unable to parse private key");
+                }
+            }
+        }
 
-    	public Asn1Set Attributes
-    	{
-    		get { return attributes; }
-    	}
+        public virtual Asn1Set Attributes
+        {
+            get { return attributes; }
+        }
 
-		/**
+        /**
          * write out an RSA private key with its associated information
          * as described in Pkcs8.
          * <pre>
@@ -110,17 +122,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
          */
         public override Asn1Object ToAsn1Object()
         {
-			Asn1EncodableVector v = new Asn1EncodableVector(
-				new DerInteger(0),
-				algID,
-				new DerOctetString(privKey));
+            Asn1EncodableVector v = new Asn1EncodableVector(new DerInteger(0), algID, privKey);
 
-			if (attributes != null)
-			{
-				v.Add(new DerTaggedObject(false, 0, attributes));
-			}
+            if (attributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, attributes));
+            }
 
-			return new DerSequence(v);
+            return new DerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/pkcs/RC2CBCParameter.cs b/crypto/src/asn1/pkcs/RC2CBCParameter.cs
new file mode 100644
index 000000000..f5355d012
--- /dev/null
+++ b/crypto/src/asn1/pkcs/RC2CBCParameter.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class RC2CbcParameter
+        : Asn1Encodable
+    {
+        internal DerInteger			version;
+        internal Asn1OctetString	iv;
+
+		public static RC2CbcParameter GetInstance(
+            object obj)
+        {
+            if (obj is Asn1Sequence)
+            {
+                return new RC2CbcParameter((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public RC2CbcParameter(
+            byte[] iv)
+        {
+            this.iv = new DerOctetString(iv);
+        }
+
+		public RC2CbcParameter(
+            int		parameterVersion,
+            byte[]	iv)
+        {
+            this.version = new DerInteger(parameterVersion);
+            this.iv = new DerOctetString(iv);
+        }
+
+		private RC2CbcParameter(
+            Asn1Sequence seq)
+        {
+            if (seq.Count == 1)
+            {
+                iv = (Asn1OctetString)seq[0];
+            }
+            else
+            {
+                version = (DerInteger)seq[0];
+                iv = (Asn1OctetString)seq[1];
+            }
+        }
+
+		public BigInteger RC2ParameterVersion
+        {
+            get
+            {
+				return version == null ? null : version.Value;
+            }
+        }
+
+		public byte[] GetIV()
+        {
+			return Arrays.Clone(iv.GetOctets());
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (version != null)
+            {
+                v.Add(version);
+            }
+
+			v.Add(iv);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/RSAESOAEPparams.cs b/crypto/src/asn1/pkcs/RSAESOAEPparams.cs
new file mode 100644
index 000000000..5ecb394fd
--- /dev/null
+++ b/crypto/src/asn1/pkcs/RSAESOAEPparams.cs
@@ -0,0 +1,145 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class RsaesOaepParameters
+		: Asn1Encodable
+	{
+		private AlgorithmIdentifier hashAlgorithm;
+		private AlgorithmIdentifier maskGenAlgorithm;
+		private AlgorithmIdentifier pSourceAlgorithm;
+
+		public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+		public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm);
+		public readonly static AlgorithmIdentifier DefaultPSourceAlgorithm = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]));
+
+		public static RsaesOaepParameters GetInstance(
+			object obj)
+		{
+			if (obj is RsaesOaepParameters)
+			{
+				return (RsaesOaepParameters)obj;
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new RsaesOaepParameters((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * The default version
+		 */
+		public RsaesOaepParameters()
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			pSourceAlgorithm = DefaultPSourceAlgorithm;
+		}
+
+		public RsaesOaepParameters(
+			AlgorithmIdentifier hashAlgorithm,
+			AlgorithmIdentifier maskGenAlgorithm,
+			AlgorithmIdentifier pSourceAlgorithm)
+		{
+			this.hashAlgorithm = hashAlgorithm;
+			this.maskGenAlgorithm = maskGenAlgorithm;
+			this.pSourceAlgorithm = pSourceAlgorithm;
+		}
+
+		public RsaesOaepParameters(
+			Asn1Sequence seq)
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			pSourceAlgorithm = DefaultPSourceAlgorithm;
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)seq[i];
+
+				switch (o.TagNo)
+				{
+					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 ArgumentException("unknown tag");
+				}
+			}
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public AlgorithmIdentifier MaskGenAlgorithm
+		{
+			get { return maskGenAlgorithm; }
+		}
+
+		public AlgorithmIdentifier PSourceAlgorithm
+		{
+			get { 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 override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (!hashAlgorithm.Equals(DefaultHashAlgorithm))
+			{
+				v.Add(new DerTaggedObject(true, 0, hashAlgorithm));
+			}
+
+			if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction))
+			{
+				v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm));
+			}
+
+			if (!pSourceAlgorithm.Equals(DefaultPSourceAlgorithm))
+			{
+				v.Add(new DerTaggedObject(true, 2, pSourceAlgorithm));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs b/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
index dbb07c744..721299105 100644
--- a/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
+++ b/crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
@@ -18,7 +18,21 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         private readonly BigInteger	exponent2;
         private readonly BigInteger	coefficient;
 
-		public RsaPrivateKeyStructure(
+        public static RsaPrivateKeyStructure GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        public static RsaPrivateKeyStructure GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is RsaPrivateKeyStructure)
+                return (RsaPrivateKeyStructure)obj;
+            return new RsaPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
+        }
+
+        public RsaPrivateKeyStructure(
             BigInteger	modulus,
             BigInteger	publicExponent,
             BigInteger	privateExponent,
@@ -38,64 +52,65 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             this.coefficient = coefficient;
         }
 
-		public RsaPrivateKeyStructure(
+        [Obsolete("Use 'GetInstance' method(s) instead")]
+        public RsaPrivateKeyStructure(
             Asn1Sequence seq)
         {
-			BigInteger version = ((DerInteger) seq[0]).Value;
-			if (version.IntValue != 0)
+            BigInteger version = ((DerInteger) seq[0]).Value;
+            if (version.IntValue != 0)
                 throw new ArgumentException("wrong version for RSA private key");
 
-			modulus = ((DerInteger) seq[1]).Value;
-			publicExponent = ((DerInteger) seq[2]).Value;
-			privateExponent = ((DerInteger) seq[3]).Value;
-			prime1 = ((DerInteger) seq[4]).Value;
-			prime2 = ((DerInteger) seq[5]).Value;
-			exponent1 = ((DerInteger) seq[6]).Value;
-			exponent2 = ((DerInteger) seq[7]).Value;
-			coefficient = ((DerInteger) seq[8]).Value;
-		}
-
-		public BigInteger Modulus
-		{
-			get { return modulus; }
-		}
-
-		public BigInteger PublicExponent
-		{
-			get { return publicExponent; }
-		}
-
-		public BigInteger PrivateExponent
-		{
-			get { return privateExponent; }
-		}
-
-		public BigInteger Prime1
-		{
-			get { return prime1; }
-		}
-
-		public BigInteger Prime2
-		{
-			get { return prime2; }
-		}
-
-		public BigInteger Exponent1
-		{
-			get { return exponent1; }
-		}
-
-		public BigInteger Exponent2
-		{
-			get { return exponent2; }
-		}
-
-		public BigInteger Coefficient
-		{
-			get { return coefficient; }
-		}
-
-		/**
+            modulus = ((DerInteger) seq[1]).Value;
+            publicExponent = ((DerInteger) seq[2]).Value;
+            privateExponent = ((DerInteger) seq[3]).Value;
+            prime1 = ((DerInteger) seq[4]).Value;
+            prime2 = ((DerInteger) seq[5]).Value;
+            exponent1 = ((DerInteger) seq[6]).Value;
+            exponent2 = ((DerInteger) seq[7]).Value;
+            coefficient = ((DerInteger) seq[8]).Value;
+        }
+
+        public BigInteger Modulus
+        {
+            get { return modulus; }
+        }
+
+        public BigInteger PublicExponent
+        {
+            get { return publicExponent; }
+        }
+
+        public BigInteger PrivateExponent
+        {
+            get { return privateExponent; }
+        }
+
+        public BigInteger Prime1
+        {
+            get { return prime1; }
+        }
+
+        public BigInteger Prime2
+        {
+            get { return prime2; }
+        }
+
+        public BigInteger Exponent1
+        {
+            get { return exponent1; }
+        }
+
+        public BigInteger Exponent2
+        {
+            get { return exponent2; }
+        }
+
+        public BigInteger Coefficient
+        {
+            get { return coefficient; }
+        }
+
+        /**
          * This outputs the key in Pkcs1v2 format.
          * <pre>
          *      RsaPrivateKey ::= Sequence {
@@ -116,16 +131,16 @@ namespace Org.BouncyCastle.Asn1.Pkcs
          */
         public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(
-				new DerInteger(0), // version
-				new DerInteger(Modulus),
-				new DerInteger(PublicExponent),
-				new DerInteger(PrivateExponent),
-				new DerInteger(Prime1),
-				new DerInteger(Prime2),
-				new DerInteger(Exponent1),
-				new DerInteger(Exponent2),
-				new DerInteger(Coefficient));
+            return new DerSequence(
+                new DerInteger(0), // version
+                new DerInteger(Modulus),
+                new DerInteger(PublicExponent),
+                new DerInteger(PrivateExponent),
+                new DerInteger(Prime1),
+                new DerInteger(Prime2),
+                new DerInteger(Exponent1),
+                new DerInteger(Exponent2),
+                new DerInteger(Coefficient));
         }
     }
 }
diff --git a/crypto/src/asn1/pkcs/RSASSAPSSparams.cs b/crypto/src/asn1/pkcs/RSASSAPSSparams.cs
new file mode 100644
index 000000000..941620761
--- /dev/null
+++ b/crypto/src/asn1/pkcs/RSASSAPSSparams.cs
@@ -0,0 +1,165 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+	public class RsassaPssParameters
+		: Asn1Encodable
+	{
+		private AlgorithmIdentifier hashAlgorithm;
+		private AlgorithmIdentifier maskGenAlgorithm;
+		private DerInteger saltLength;
+		private DerInteger trailerField;
+
+		public readonly static AlgorithmIdentifier DefaultHashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+		public readonly static AlgorithmIdentifier DefaultMaskGenFunction = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, DefaultHashAlgorithm);
+		public readonly static DerInteger DefaultSaltLength = new DerInteger(20);
+		public readonly static DerInteger DefaultTrailerField = new DerInteger(1);
+
+		public static RsassaPssParameters GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is RsassaPssParameters)
+			{
+				return (RsassaPssParameters)obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new RsassaPssParameters((Asn1Sequence)obj);
+			}
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * The default version
+		 */
+		public RsassaPssParameters()
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			saltLength = DefaultSaltLength;
+			trailerField = DefaultTrailerField;
+		}
+
+		public RsassaPssParameters(
+			AlgorithmIdentifier hashAlgorithm,
+			AlgorithmIdentifier maskGenAlgorithm,
+			DerInteger saltLength,
+			DerInteger trailerField)
+		{
+			this.hashAlgorithm = hashAlgorithm;
+			this.maskGenAlgorithm = maskGenAlgorithm;
+			this.saltLength = saltLength;
+			this.trailerField = trailerField;
+		}
+
+		public RsassaPssParameters(
+			Asn1Sequence seq)
+		{
+			hashAlgorithm = DefaultHashAlgorithm;
+			maskGenAlgorithm = DefaultMaskGenFunction;
+			saltLength = DefaultSaltLength;
+			trailerField = DefaultTrailerField;
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				Asn1TaggedObject o = (Asn1TaggedObject)seq[i];
+
+				switch (o.TagNo)
+				{
+					case 0:
+						hashAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+						break;
+					case 1:
+						maskGenAlgorithm = AlgorithmIdentifier.GetInstance(o, true);
+						break;
+					case 2:
+						saltLength = DerInteger.GetInstance(o, true);
+						break;
+					case 3:
+						trailerField = DerInteger.GetInstance(o, true);
+						break;
+					default:
+						throw new ArgumentException("unknown tag");
+				}
+			}
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public AlgorithmIdentifier MaskGenAlgorithm
+		{
+			get { return maskGenAlgorithm; }
+		}
+
+		public DerInteger SaltLength
+		{
+			get { return saltLength; }
+		}
+
+		public DerInteger TrailerField
+		{
+			get { return trailerField; }
+		}
+
+		/**
+		 * <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 override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (!hashAlgorithm.Equals(DefaultHashAlgorithm))
+			{
+				v.Add(new DerTaggedObject(true, 0, hashAlgorithm));
+			}
+
+			if (!maskGenAlgorithm.Equals(DefaultMaskGenFunction))
+			{
+				v.Add(new DerTaggedObject(true, 1, maskGenAlgorithm));
+			}
+
+			if (!saltLength.Equals(DefaultSaltLength))
+			{
+				v.Add(new DerTaggedObject(true, 2, saltLength));
+			}
+
+			if (!trailerField.Equals(DefaultTrailerField))
+			{
+				v.Add(new DerTaggedObject(true, 3, trailerField));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/pkcs/SafeBag.cs b/crypto/src/asn1/pkcs/SafeBag.cs
new file mode 100644
index 000000000..4b9350bac
--- /dev/null
+++ b/crypto/src/asn1/pkcs/SafeBag.cs
@@ -0,0 +1,70 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class SafeBag
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier bagID;
+        private readonly Asn1Object bagValue;
+        private readonly Asn1Set bagAttributes;
+
+		public SafeBag(
+            DerObjectIdentifier	oid,
+            Asn1Object			obj)
+        {
+            this.bagID = oid;
+            this.bagValue = obj;
+            this.bagAttributes = null;
+        }
+
+		public SafeBag(
+            DerObjectIdentifier	oid,
+            Asn1Object			obj,
+            Asn1Set				bagAttributes)
+        {
+            this.bagID = oid;
+            this.bagValue = obj;
+            this.bagAttributes = bagAttributes;
+        }
+
+		public SafeBag(
+            Asn1Sequence seq)
+        {
+            this.bagID = (DerObjectIdentifier) seq[0];
+            this.bagValue = ((DerTaggedObject) seq[1]).GetObject();
+            if (seq.Count == 3)
+            {
+                this.bagAttributes = (Asn1Set) seq[2];
+            }
+        }
+
+		public DerObjectIdentifier BagID
+		{
+			get { return bagID; }
+		}
+
+		public Asn1Object BagValue
+		{
+			get { return bagValue; }
+		}
+
+		public Asn1Set BagAttributes
+		{
+			get { return bagAttributes; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				bagID, new DerTaggedObject(0, bagValue));
+
+			if (bagAttributes != null)
+            {
+                v.Add(bagAttributes);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/SignedData.cs b/crypto/src/asn1/pkcs/SignedData.cs
index 10951d37a..6e72bd0a9 100644
--- a/crypto/src/asn1/pkcs/SignedData.cs
+++ b/crypto/src/asn1/pkcs/SignedData.cs
@@ -18,23 +18,17 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         private readonly Asn1Set		crls;
         private readonly Asn1Set		signerInfos;
 
-		public static SignedData GetInstance(
-            object obj)
+        public static SignedData GetInstance(object obj)
         {
-            if (obj is SignedData)
-            {
-                return (SignedData) obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new SignedData((Asn1Sequence) obj);
-            }
-
-			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
-		}
+            if (obj == null)
+                return null;
+            SignedData existing = obj as SignedData;
+            if (existing != null)
+                return existing;
+            return new SignedData(Asn1Sequence.GetInstance(obj));
+        }
 
-		public SignedData(
+        public SignedData(
             DerInteger        _version,
             Asn1Set           _digestAlgorithms,
             ContentInfo       _contentInfo,
@@ -50,25 +44,25 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             signerInfos      = _signerInfos;
         }
 
-		private SignedData(
+        private SignedData(
             Asn1Sequence seq)
         {
             IEnumerator e = seq.GetEnumerator();
 
-			e.MoveNext();
+            e.MoveNext();
             version = (DerInteger) e.Current;
 
-			e.MoveNext();
+            e.MoveNext();
             digestAlgorithms = (Asn1Set) e.Current;
 
-			e.MoveNext();
+            e.MoveNext();
             contentInfo = ContentInfo.GetInstance(e.Current);
 
-			while (e.MoveNext())
+            while (e.MoveNext())
             {
                 Asn1Object o = (Asn1Object) e.Current;
 
-				//
+                //
                 // an interesting feature of SignedData is that there appear to be varying implementations...
                 // for the moment we ignore anything which doesn't fit.
                 //
@@ -76,16 +70,16 @@ namespace Org.BouncyCastle.Asn1.Pkcs
                 {
                     DerTaggedObject tagged = (DerTaggedObject) o;
 
-					switch (tagged.TagNo)
+                    switch (tagged.TagNo)
                     {
-						case 0:
-							certificates = Asn1Set.GetInstance(tagged, false);
-							break;
-						case 1:
-							crls = Asn1Set.GetInstance(tagged, false);
-							break;
-						default:
-							throw new ArgumentException("unknown tag value " + tagged.TagNo);
+                        case 0:
+                            certificates = Asn1Set.GetInstance(tagged, false);
+                            break;
+                        case 1:
+                            crls = Asn1Set.GetInstance(tagged, false);
+                            break;
+                        default:
+                            throw new ArgumentException("unknown tag value " + tagged.TagNo);
                     }
                 }
                 else
@@ -95,37 +89,37 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             }
         }
 
-		public DerInteger Version
-		{
-			get { return version; }
-		}
-
-		public Asn1Set DigestAlgorithms
-		{
-			get { return digestAlgorithms; }
-		}
-
-		public ContentInfo ContentInfo
-		{
-			get { return contentInfo; }
-		}
-
-		public Asn1Set Certificates
-		{
-			get { return certificates; }
-		}
-
-		public Asn1Set Crls
-		{
-			get { return crls; }
-		}
-
-		public Asn1Set SignerInfos
-		{
-			get { return signerInfos; }
-		}
-
-		/**
+        public DerInteger Version
+        {
+            get { return version; }
+        }
+
+        public Asn1Set DigestAlgorithms
+        {
+            get { return digestAlgorithms; }
+        }
+
+        public ContentInfo ContentInfo
+        {
+            get { return contentInfo; }
+        }
+
+        public Asn1Set Certificates
+        {
+            get { return certificates; }
+        }
+
+        public Asn1Set Crls
+        {
+            get { return crls; }
+        }
+
+        public Asn1Set SignerInfos
+        {
+            get { return signerInfos; }
+        }
+
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  SignedData ::= Sequence {
@@ -143,21 +137,21 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(
-				version, digestAlgorithms, contentInfo);
+                version, digestAlgorithms, contentInfo);
 
-			if (certificates != null)
+            if (certificates != null)
             {
                 v.Add(new DerTaggedObject(false, 0, certificates));
             }
 
-			if (crls != null)
+            if (crls != null)
             {
                 v.Add(new DerTaggedObject(false, 1, crls));
             }
 
-			v.Add(signerInfos);
+            v.Add(signerInfos);
 
-			return new BerSequence(v);
+            return new BerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/pkcs/SignerInfo.cs b/crypto/src/asn1/pkcs/SignerInfo.cs
new file mode 100644
index 000000000..1e4694547
--- /dev/null
+++ b/crypto/src/asn1/pkcs/SignerInfo.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * a Pkcs#7 signer info object.
+     */
+    public class SignerInfo
+        : Asn1Encodable
+    {
+        private DerInteger              version;
+        private IssuerAndSerialNumber   issuerAndSerialNumber;
+        private AlgorithmIdentifier     digAlgorithm;
+        private Asn1Set                 authenticatedAttributes;
+        private AlgorithmIdentifier     digEncryptionAlgorithm;
+        private Asn1OctetString         encryptedDigest;
+        private Asn1Set                 unauthenticatedAttributes;
+
+		public static SignerInfo GetInstance(
+            object obj)
+        {
+            if (obj is SignerInfo)
+            {
+                return (SignerInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SignerInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public SignerInfo(
+            DerInteger              version,
+            IssuerAndSerialNumber   issuerAndSerialNumber,
+            AlgorithmIdentifier     digAlgorithm,
+            Asn1Set                 authenticatedAttributes,
+            AlgorithmIdentifier     digEncryptionAlgorithm,
+            Asn1OctetString         encryptedDigest,
+            Asn1Set                 unauthenticatedAttributes)
+        {
+            this.version = version;
+            this.issuerAndSerialNumber = issuerAndSerialNumber;
+            this.digAlgorithm = digAlgorithm;
+            this.authenticatedAttributes = authenticatedAttributes;
+            this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+            this.encryptedDigest = encryptedDigest;
+            this.unauthenticatedAttributes = unauthenticatedAttributes;
+        }
+
+		public SignerInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            version = (DerInteger) e.Current;
+
+			e.MoveNext();
+            issuerAndSerialNumber = IssuerAndSerialNumber.GetInstance(e.Current);
+
+			e.MoveNext();
+            digAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+
+			e.MoveNext();
+            object obj = e.Current;
+
+			if (obj is Asn1TaggedObject)
+            {
+                authenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject) obj, false);
+
+				e.MoveNext();
+                digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(e.Current);
+            }
+            else
+            {
+                authenticatedAttributes = null;
+                digEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(obj);
+            }
+
+			e.MoveNext();
+            encryptedDigest = DerOctetString.GetInstance(e.Current);
+
+			if (e.MoveNext())
+            {
+                unauthenticatedAttributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false);
+            }
+            else
+            {
+                unauthenticatedAttributes = null;
+            }
+        }
+
+		public DerInteger Version { get { return version; } }
+
+		public IssuerAndSerialNumber IssuerAndSerialNumber { get { return issuerAndSerialNumber; } }
+
+		public Asn1Set AuthenticatedAttributes { get { return authenticatedAttributes; } }
+
+		public AlgorithmIdentifier DigestAlgorithm { get { return digAlgorithm; } }
+
+		public Asn1OctetString EncryptedDigest { get { return encryptedDigest; } }
+
+		public AlgorithmIdentifier DigestEncryptionAlgorithm { get { return digEncryptionAlgorithm; } }
+
+		public Asn1Set UnauthenticatedAttributes { get { return unauthenticatedAttributes; } }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  SignerInfo ::= Sequence {
+         *      version Version,
+         *      issuerAndSerialNumber IssuerAndSerialNumber,
+         *      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 override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, issuerAndSerialNumber, digAlgorithm);
+
+			if (authenticatedAttributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, authenticatedAttributes));
+            }
+
+			v.Add(digEncryptionAlgorithm, encryptedDigest);
+
+			if (unauthenticatedAttributes != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, unauthenticatedAttributes));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
index 2e9c27fd2..8d805fa30 100644
--- a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
+++ b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
@@ -6,113 +6,121 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Sec
 {
-	/**
-	 * the elliptic curve private key object from SEC 1
-	 */
-	public class ECPrivateKeyStructure
-		: Asn1Encodable
-	{
-		private readonly Asn1Sequence seq;
-
-		public ECPrivateKeyStructure(
-			Asn1Sequence seq)
-		{
-			if (seq == null)
-				throw new ArgumentNullException("seq");
-
-			this.seq = seq;
-		}
-
-		public ECPrivateKeyStructure(
-			BigInteger key)
-		{
-			if (key == null)
-				throw new ArgumentNullException("key");
-
-			this.seq = new DerSequence(
-				new DerInteger(1),
-				new DerOctetString(key.ToByteArrayUnsigned()));
-		}
-
-		public ECPrivateKeyStructure(
-			BigInteger		key,
-			Asn1Encodable	parameters)
-			: this(key, null, parameters)
-		{
-		}
-
-		public ECPrivateKeyStructure(
-			BigInteger		key,
-			DerBitString	publicKey,
-			Asn1Encodable	parameters)
-		{
-			if (key == null)
-				throw new ArgumentNullException("key");
-
-			Asn1EncodableVector v = new Asn1EncodableVector(
-				new DerInteger(1),
-				new DerOctetString(key.ToByteArrayUnsigned()));
-
-			if (parameters != null)
-			{
-				v.Add(new DerTaggedObject(true, 0, parameters));
-			}
-
-			if (publicKey != null)
-			{
-				v.Add(new DerTaggedObject(true, 1, publicKey));
-			}
-
-			this.seq = new DerSequence(v);
-		}
-
-		public BigInteger GetKey()
-		{
-			Asn1OctetString octs = (Asn1OctetString) seq[1];
-
-			return new BigInteger(1, octs.GetOctets());
-		}
-
-		public DerBitString GetPublicKey()
-		{
-			return (DerBitString) GetObjectInTag(1);
-		}
-
-		public Asn1Object GetParameters()
-		{
-			return GetObjectInTag(0);
-		}
-
-		private Asn1Object GetObjectInTag(
-			int tagNo)
-		{
-			foreach (Asn1Encodable ae in seq)
-			{
-				Asn1Object obj = ae.ToAsn1Object();
-
-				if (obj is Asn1TaggedObject)
-				{
-					Asn1TaggedObject tag = (Asn1TaggedObject) obj;
-					if (tag.TagNo == tagNo)
-					{
-						return tag.GetObject();
-					}
-				}
-			}
-
-			return null;
-		}
-
-		/**
-		 * ECPrivateKey ::= SEQUENCE {
-		 *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
-		 *     privateKey OCTET STRING,
-		 *     parameters [0] Parameters OPTIONAL,
-		 *     publicKey [1] BIT STRING OPTIONAL }
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			return seq;
-		}
-	}
+    /**
+     * the elliptic curve private key object from SEC 1
+     */
+    public class ECPrivateKeyStructure
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence seq;
+
+        public static ECPrivateKeyStructure GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is ECPrivateKeyStructure)
+                return (ECPrivateKeyStructure)obj;
+            return new ECPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
+        }
+
+        public ECPrivateKeyStructure(
+            Asn1Sequence seq)
+        {
+            if (seq == null)
+                throw new ArgumentNullException("seq");
+
+            this.seq = seq;
+        }
+
+        public ECPrivateKeyStructure(
+            BigInteger key)
+        {
+            if (key == null)
+                throw new ArgumentNullException("key");
+
+            this.seq = new DerSequence(
+                new DerInteger(1),
+                new DerOctetString(key.ToByteArrayUnsigned()));
+        }
+
+        public ECPrivateKeyStructure(
+            BigInteger		key,
+            Asn1Encodable	parameters)
+            : this(key, null, parameters)
+        {
+        }
+
+        public ECPrivateKeyStructure(
+            BigInteger		key,
+            DerBitString	publicKey,
+            Asn1Encodable	parameters)
+        {
+            if (key == null)
+                throw new ArgumentNullException("key");
+
+            Asn1EncodableVector v = new Asn1EncodableVector(
+                new DerInteger(1),
+                new DerOctetString(key.ToByteArrayUnsigned()));
+
+            if (parameters != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, parameters));
+            }
+
+            if (publicKey != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, publicKey));
+            }
+
+            this.seq = new DerSequence(v);
+        }
+
+        public virtual BigInteger GetKey()
+        {
+            Asn1OctetString octs = (Asn1OctetString) seq[1];
+
+            return new BigInteger(1, octs.GetOctets());
+        }
+
+        public virtual DerBitString GetPublicKey()
+        {
+            return (DerBitString) GetObjectInTag(1);
+        }
+
+        public virtual Asn1Object GetParameters()
+        {
+            return GetObjectInTag(0);
+        }
+
+        private Asn1Object GetObjectInTag(int tagNo)
+        {
+            foreach (Asn1Encodable ae in seq)
+            {
+                Asn1Object obj = ae.ToAsn1Object();
+
+                if (obj is Asn1TaggedObject)
+                {
+                    Asn1TaggedObject tag = (Asn1TaggedObject) obj;
+                    if (tag.TagNo == tagNo)
+                    {
+                        return tag.GetObject();
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        /**
+         * ECPrivateKey ::= SEQUENCE {
+         *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+         *     privateKey OCTET STRING,
+         *     parameters [0] Parameters OPTIONAL,
+         *     publicKey [1] BIT STRING OPTIONAL }
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
 }
diff --git a/crypto/src/asn1/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs
index c7503144f..60d456ef0 100644
--- a/crypto/src/asn1/sec/SECNamedCurves.cs
+++ b/crypto/src/asn1/sec/SECNamedCurves.cs
@@ -1,1192 +1,1253 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Endo;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Asn1.Sec
 {
-	public sealed class SecNamedCurves
-	{
-		private SecNamedCurves()
-		{
-		}
-
-		private static BigInteger FromHex(
-			string hex)
-		{
-			return new BigInteger(1, Hex.Decode(hex));
-		}
-
-		/*
-		 * secp112r1
-		 */
-		internal class Secp112r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp112r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp112r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp112r2Holder
-			: X9ECParametersHolder
-		{
-			private Secp112r2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp112r2Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp128r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp128r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp128r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp128r2Holder
-			: X9ECParametersHolder
-		{
-			private Secp128r2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp128r2Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp160k1Holder
-			: X9ECParametersHolder
-		{
-			private Secp160k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp160k1Holder();
-
-			protected override 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 = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(7);
-				byte[] S = null;
-				BigInteger n = FromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
-				BigInteger h = BigInteger.ValueOf(1);
-
-				ECCurve curve = new FpCurve(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
-		 */
-		internal class Secp160r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp160r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp160r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp160r2Holder
-			: X9ECParametersHolder
-		{
-			private Secp160r2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp160r2Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp192k1Holder
-			: X9ECParametersHolder
-		{
-			private Secp192k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				// p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
-				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
-				BigInteger a = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(3);
-				byte[] S = null;
-				BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
-				BigInteger h = BigInteger.ValueOf(1);
-
-				ECCurve curve = new FpCurve(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
-		 */
-		internal class Secp192r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp192r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp224k1Holder
-			: X9ECParametersHolder
-		{
-			private Secp224k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder();
-
-			protected override 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 = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(5);
-				byte[] S = null;
-				BigInteger n = FromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
-				BigInteger h = BigInteger.ValueOf(1);
-
-				ECCurve curve = new FpCurve(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
-		 */
-		internal class Secp224r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp224r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp256k1Holder
-			: X9ECParametersHolder
-		{
-			private Secp256k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				// p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
-				BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
-				BigInteger a = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(7);
-				byte[] S = null;
-				BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
-				BigInteger h = BigInteger.ValueOf(1);
-
-				ECCurve curve = new FpCurve(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
-		 */
-		internal class Secp256r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp256r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp384r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp384r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Secp521r1Holder
-			: X9ECParametersHolder
-		{
-			private Secp521r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder();
-
-			protected override 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 FpCurve(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
-		 */
-		internal class Sect113r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect113r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect113r1Holder();
-
-			private const int m = 113;
-			private const int k = 9;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect113r2Holder
-			: X9ECParametersHolder
-		{
-			private Sect113r2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect113r2Holder();
-
-			private const int m = 113;
-			private const int k = 9;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect131r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect131r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect131r1Holder();
-
-			private const int m = 131;
-			private const int k1 = 2;
-			private const int k2 = 3;
-			private const int k3 = 8;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect131r2Holder
-			: X9ECParametersHolder
-		{
-			private Sect131r2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect131r2Holder();
-
-			private const int m = 131;
-			private const int k1 = 2;
-			private const int k2 = 3;
-			private const int k3 = 8;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect163k1Holder
-			: X9ECParametersHolder
-		{
-			private Sect163k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect163k1Holder();
-
-			private const int m = 163;
-			private const int k1 = 3;
-			private const int k2 = 6;
-			private const int k3 = 7;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect163r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect163r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect163r1Holder();
-
-			private const int m = 163;
-			private const int k1 = 3;
-			private const int k2 = 6;
-			private const int k3 = 7;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect163r2Holder
-			: X9ECParametersHolder
-		{
-			private Sect163r2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect163r2Holder();
-
-			private const int m = 163;
-			private const int k1 = 3;
-			private const int k2 = 6;
-			private const int k3 = 7;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect193r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect193r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect193r1Holder();
-
-			private const int m = 193;
-			private const int k = 15;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect193r2Holder
-			: X9ECParametersHolder
-		{
-			private Sect193r2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect193r2Holder();
-
-			private const int m = 193;
-			private const int k = 15;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect233k1Holder
-			: X9ECParametersHolder
-		{
-			private Sect233k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect233k1Holder();
-
-			private const int m = 233;
-			private const int k = 74;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger a = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(1);
-				byte[] S = null;
-				BigInteger n = FromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
-				BigInteger h = BigInteger.ValueOf(4);
-
-				ECCurve curve = new F2mCurve(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
-		 */
-		internal class Sect233r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect233r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect233r1Holder();
-
-			private const int m = 233;
-			private const int k = 74;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect239k1Holder
-			: X9ECParametersHolder
-		{
-			private Sect239k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect239k1Holder();
-
-			private const int m = 239;
-			private const int k = 158;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger a = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(1);
-				byte[] S = null;
-				BigInteger n = FromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
-				BigInteger h = BigInteger.ValueOf(4);
-
-				ECCurve curve = new F2mCurve(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
-		 */
-		internal class Sect283k1Holder
-			: X9ECParametersHolder
-		{
-			private Sect283k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect283k1Holder();
-
-			private const int m = 283;
-			private const int k1 = 5;
-			private const int k2 = 7;
-			private const int k3 = 12;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger a = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(1);
-				byte[] S = null;
-				BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
-				BigInteger h = BigInteger.ValueOf(4);
-
-				ECCurve curve = new F2mCurve(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
-		 */
-		internal class Sect283r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect283r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect283r1Holder();
-
-			private const int m = 283;
-			private const int k1 = 5;
-			private const int k2 = 7;
-			private const int k3 = 12;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect409k1Holder
-			: X9ECParametersHolder
-		{
-			private Sect409k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect409k1Holder();
-
-			private const int m = 409;
-			private const int k = 87;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger a = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(1);
-				byte[] S = null;
-				BigInteger n = FromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
-				BigInteger h = BigInteger.ValueOf(4);
-
-				ECCurve curve = new F2mCurve(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
-		 */
-		internal class Sect409r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect409r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect409r1Holder();
-
-			private const int m = 409;
-			private const int k = 87;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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
-		 */
-		internal class Sect571k1Holder
-			: X9ECParametersHolder
-		{
-			private Sect571k1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect571k1Holder();
-
-			private const int m = 571;
-			private const int k1 = 2;
-			private const int k2 = 5;
-			private const int k3 = 10;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger a = BigInteger.Zero;
-				BigInteger b = BigInteger.ValueOf(1);
-				byte[] S = null;
-				BigInteger n = FromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
-				BigInteger h = BigInteger.ValueOf(4);
-
-				ECCurve curve = new F2mCurve(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
-		 */
-		internal class Sect571r1Holder
-			: X9ECParametersHolder
-		{
-			private Sect571r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Sect571r1Holder();
-
-			private const int m = 571;
-			private const int k1 = 2;
-			private const int k2 = 5;
-			private const int k3 = 10;
-
-			protected override X9ECParameters CreateParameters()
-			{
-				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 F2mCurve(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);
-			}
-		}
-
-
-		private static readonly IDictionary objIds = Platform.CreateHashtable();
+    public sealed class SecNamedCurves
+    {
+        private SecNamedCurves()
+        {
+        }
+
+        private static ECCurve ConfigureCurve(ECCurve curve)
+        {
+            return curve;
+        }
+
+        private static ECCurve ConfigureCurveGlv(ECCurve c, GlvTypeBParameters p)
+        {
+            return c.Configure().SetEndomorphism(new GlvTypeBEndomorphism(c, p)).Create();
+        }
+
+        private static BigInteger FromHex(string hex)
+        {
+            return new BigInteger(1, Hex.Decode(hex));
+        }
+
+        /*
+         * secp112r1
+         */
+        internal class Secp112r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp112r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp112r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp112r2Holder
+            : X9ECParametersHolder
+        {
+            private Secp112r2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp112r2Holder();
+
+            protected override 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 = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp128r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp128r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp128r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp128r2Holder
+            : X9ECParametersHolder
+        {
+            private Secp128r2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp128r2Holder();
+
+            protected override 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 = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp160k1Holder
+            : X9ECParametersHolder
+        {
+            private Secp160k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp160k1Holder();
+
+            protected override 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 = BigInteger.Zero;
+                BigInteger b = BigInteger.ValueOf(7);
+                byte[] S = null;
+                BigInteger n = FromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
+                BigInteger h = BigInteger.One;
+
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16),
+                    new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16),
+                    new BigInteger[]{
+                        new BigInteger("9162fbe73984472a0a9e", 16),
+                        new BigInteger("-96341f1138933bc2f505", 16) },
+                    new BigInteger[]{
+                        new BigInteger("127971af8721782ecffa3", 16),
+                        new BigInteger("9162fbe73984472a0a9e", 16) },
+                    new BigInteger("9162fbe73984472a0a9d0590", 16),
+                    new BigInteger("96341f1138933bc2f503fd44", 16),
+                    176);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                //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
+         */
+        internal class Secp160r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp160r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp160r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp160r2Holder
+            : X9ECParametersHolder
+        {
+            private Secp160r2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp160r2Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp192k1Holder
+            : X9ECParametersHolder
+        {
+            private Secp192k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+                BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
+                BigInteger a = BigInteger.Zero;
+                BigInteger b = BigInteger.ValueOf(3);
+                byte[] S = null;
+                BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
+                BigInteger h = BigInteger.One;
+
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+                    new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+                    new BigInteger[]{
+                        new BigInteger("71169be7330b3038edb025f1", 16),
+                        new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+                    new BigInteger[]{
+                        new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+                        new BigInteger("71169be7330b3038edb025f1", 16) },
+                    new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+                    new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+                    208);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                //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
+         */
+        internal class Secp192r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp192r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp224k1Holder
+            : X9ECParametersHolder
+        {
+            private Secp224k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder();
+
+            protected override 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 = BigInteger.Zero;
+                BigInteger b = BigInteger.ValueOf(5);
+                byte[] S = null;
+                BigInteger n = FromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
+                BigInteger h = BigInteger.One;
+
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+                    new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+                    new BigInteger[]{
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+                        new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+                    new BigInteger[]{
+                        new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+                    new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+                    new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+                    240);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                //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
+         */
+        internal class Secp224r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp224r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp256k1Holder
+            : X9ECParametersHolder
+        {
+            private Secp256k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+                BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
+                BigInteger a = BigInteger.Zero;
+                BigInteger b = BigInteger.ValueOf(7);
+                byte[] S = null;
+                BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
+                BigInteger h = BigInteger.One;
+
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+                    new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+                    new BigInteger[]{
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+                        new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+                    new BigInteger[]{
+                        new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+                    new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+                    new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+                    272);
+
+                ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
+                //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
+         */
+        internal class Secp256r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp256r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp384r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp384r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Secp521r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp521r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder();
+
+            protected override 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.One;
+
+                ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
+                //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
+         */
+        internal class Sect113r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect113r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect113r1Holder();
+
+            private const int m = 113;
+            private const int k = 9;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                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 F2mCurve(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
+         */
+        internal class Sect113r2Holder
+            : X9ECParametersHolder
+        {
+            private Sect113r2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect113r2Holder();
+
+            private const int m = 113;
+            private const int k = 9;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                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 F2mCurve(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
+         */
+        internal class Sect131r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect131r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect131r1Holder();
+
+            private const int m = 131;
+            private const int k1 = 2;
+            private const int k2 = 3;
+            private const int k3 = 8;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                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 F2mCurve(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
+         */
+        internal class Sect131r2Holder
+            : X9ECParametersHolder
+        {
+            private Sect131r2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect131r2Holder();
+
+            private const int m = 131;
+            private const int k1 = 2;
+            private const int k2 = 3;
+            private const int k3 = 8;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                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 F2mCurve(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
+         */
+        internal class Sect163k1Holder
+            : X9ECParametersHolder
+        {
+            private Sect163k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect163k1Holder();
+
+            private const int m = 163;
+            private const int k1 = 3;
+            private const int k2 = 6;
+            private const int k3 = 7;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.One;
+                BigInteger b = BigInteger.One;
+                byte[] S = null;
+                BigInteger n = FromHex("04000000000000000000020108A2E0CC0D99F8A5EF");
+                BigInteger h = BigInteger.ValueOf(2);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect163r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect163r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect163r1Holder();
+
+            private const int m = 163;
+            private const int k1 = 3;
+            private const int k2 = 6;
+            private const int k3 = 7;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                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 F2mCurve(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
+         */
+        internal class Sect163r2Holder
+            : X9ECParametersHolder
+        {
+            private Sect163r2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect163r2Holder();
+
+            private const int m = 163;
+            private const int k1 = 3;
+            private const int k2 = 6;
+            private const int k3 = 7;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.One;
+                BigInteger b = FromHex("020A601907B8C953CA1481EB10512F78744A3205FD");
+                byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+                BigInteger n = FromHex("040000000000000000000292FE77E70C12A4234C33");
+                BigInteger h = BigInteger.ValueOf(2);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect193r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect193r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect193r1Holder();
+
+            private const int m = 193;
+            private const int k = 15;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                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 F2mCurve(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
+         */
+        internal class Sect193r2Holder
+            : X9ECParametersHolder
+        {
+            private Sect193r2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect193r2Holder();
+
+            private const int m = 193;
+            private const int k = 15;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                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 F2mCurve(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
+         */
+        internal class Sect233k1Holder
+            : X9ECParametersHolder
+        {
+            private Sect233k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect233k1Holder();
+
+            private const int m = 233;
+            private const int k = 74;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.Zero;
+                BigInteger b = BigInteger.One;
+                byte[] S = null;
+                BigInteger n = FromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
+                BigInteger h = BigInteger.ValueOf(4);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect233r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect233r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect233r1Holder();
+
+            private const int m = 233;
+            private const int k = 74;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.One;
+                BigInteger b = FromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD");
+                byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+                BigInteger n = FromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7");
+                BigInteger h = BigInteger.ValueOf(2);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect239k1Holder
+            : X9ECParametersHolder
+        {
+            private Sect239k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect239k1Holder();
+
+            private const int m = 239;
+            private const int k = 158;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.Zero;
+                BigInteger b = BigInteger.One;
+                byte[] S = null;
+                BigInteger n = FromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
+                BigInteger h = BigInteger.ValueOf(4);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect283k1Holder
+            : X9ECParametersHolder
+        {
+            private Sect283k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect283k1Holder();
+
+            private const int m = 283;
+            private const int k1 = 5;
+            private const int k2 = 7;
+            private const int k3 = 12;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.Zero;
+                BigInteger b = BigInteger.One;
+                byte[] S = null;
+                BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
+                BigInteger h = BigInteger.ValueOf(4);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect283r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect283r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect283r1Holder();
+
+            private const int m = 283;
+            private const int k1 = 5;
+            private const int k2 = 7;
+            private const int k3 = 12;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.One;
+                BigInteger b = FromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5");
+                byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+                BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307");
+                BigInteger h = BigInteger.ValueOf(2);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect409k1Holder
+            : X9ECParametersHolder
+        {
+            private Sect409k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect409k1Holder();
+
+            private const int m = 409;
+            private const int k = 87;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.Zero;
+                BigInteger b = BigInteger.One;
+                byte[] S = null;
+                BigInteger n = FromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
+                BigInteger h = BigInteger.ValueOf(4);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect409r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect409r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect409r1Holder();
+
+            private const int m = 409;
+            private const int k = 87;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.One;
+                BigInteger b = FromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F");
+                byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+                BigInteger n = FromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173");
+                BigInteger h = BigInteger.ValueOf(2);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect571k1Holder
+            : X9ECParametersHolder
+        {
+            private Sect571k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect571k1Holder();
+
+            private const int m = 571;
+            private const int k1 = 2;
+            private const int k2 = 5;
+            private const int k3 = 10;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.Zero;
+                BigInteger b = BigInteger.One;
+                byte[] S = null;
+                BigInteger n = FromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
+                BigInteger h = BigInteger.ValueOf(4);
+
+                ECCurve curve = new F2mCurve(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
+         */
+        internal class Sect571r1Holder
+            : X9ECParametersHolder
+        {
+            private Sect571r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Sect571r1Holder();
+
+            private const int m = 571;
+            private const int k1 = 2;
+            private const int k2 = 5;
+            private const int k3 = 10;
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger a = BigInteger.One;
+                BigInteger b = FromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A");
+                byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+                BigInteger n = FromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47");
+                BigInteger h = BigInteger.ValueOf(2);
+
+                ECCurve curve = new F2mCurve(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);
+            }
+        }
+
+
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
         private static readonly IDictionary curves = Platform.CreateHashtable();
         private static readonly IDictionary names = Platform.CreateHashtable();
 
-		private static void DefineCurve(
-			string					name,
-			DerObjectIdentifier		oid,
-			X9ECParametersHolder	holder)
-		{
-			objIds.Add(name, oid);
-			names.Add(oid, name);
-			curves.Add(oid, holder);
-		}
-
-		static SecNamedCurves()
-		{
-			DefineCurve("secp112r1", SecObjectIdentifiers.SecP112r1, Secp112r1Holder.Instance);
-			DefineCurve("secp112r2", SecObjectIdentifiers.SecP112r2, Secp112r2Holder.Instance);
-			DefineCurve("secp128r1", SecObjectIdentifiers.SecP128r1, Secp128r1Holder.Instance);
-			DefineCurve("secp128r2", SecObjectIdentifiers.SecP128r2, Secp128r2Holder.Instance);
-			DefineCurve("secp160k1", SecObjectIdentifiers.SecP160k1, Secp160k1Holder.Instance);
-			DefineCurve("secp160r1", SecObjectIdentifiers.SecP160r1, Secp160r1Holder.Instance);
-			DefineCurve("secp160r2", SecObjectIdentifiers.SecP160r2, Secp160r2Holder.Instance);
-			DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance);
-			DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance);
-			DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance);
-			DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance);
-			DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance);
-			DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance);
-			DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance);
-			DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance);
-
-			DefineCurve("sect113r1", SecObjectIdentifiers.SecT113r1, Sect113r1Holder.Instance);
-			DefineCurve("sect113r2", SecObjectIdentifiers.SecT113r2, Sect113r2Holder.Instance);
-			DefineCurve("sect131r1", SecObjectIdentifiers.SecT131r1, Sect131r1Holder.Instance);
-			DefineCurve("sect131r2", SecObjectIdentifiers.SecT131r2, Sect131r2Holder.Instance);
-			DefineCurve("sect163k1", SecObjectIdentifiers.SecT163k1, Sect163k1Holder.Instance);
-			DefineCurve("sect163r1", SecObjectIdentifiers.SecT163r1, Sect163r1Holder.Instance);
-			DefineCurve("sect163r2", SecObjectIdentifiers.SecT163r2, Sect163r2Holder.Instance);
-			DefineCurve("sect193r1", SecObjectIdentifiers.SecT193r1, Sect193r1Holder.Instance);
-			DefineCurve("sect193r2", SecObjectIdentifiers.SecT193r2, Sect193r2Holder.Instance);
-			DefineCurve("sect233k1", SecObjectIdentifiers.SecT233k1, Sect233k1Holder.Instance);
-			DefineCurve("sect233r1", SecObjectIdentifiers.SecT233r1, Sect233r1Holder.Instance);
-			DefineCurve("sect239k1", SecObjectIdentifiers.SecT239k1, Sect239k1Holder.Instance);
-			DefineCurve("sect283k1", SecObjectIdentifiers.SecT283k1, Sect283k1Holder.Instance);
-			DefineCurve("sect283r1", SecObjectIdentifiers.SecT283r1, Sect283r1Holder.Instance);
-			DefineCurve("sect409k1", SecObjectIdentifiers.SecT409k1, Sect409k1Holder.Instance);
-			DefineCurve("sect409r1", SecObjectIdentifiers.SecT409r1, Sect409r1Holder.Instance);
-			DefineCurve("sect571k1", SecObjectIdentifiers.SecT571k1, Sect571k1Holder.Instance);
-			DefineCurve("sect571r1", SecObjectIdentifiers.SecT571r1, Sect571r1Holder.Instance);
-		}
-
-		public static X9ECParameters GetByName(
-			string name)
-		{
-			DerObjectIdentifier oid = (DerObjectIdentifier)
-				objIds[name.ToLowerInvariant()];
-
-			return oid == null ? null : GetByOid(oid);
-		}
-
-		/**
-		 * 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(
-			DerObjectIdentifier oid)
-		{
-			X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
-			return holder == null ? null : holder.Parameters;
-		}
-
-		/**
-		 * 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 DerObjectIdentifier GetOid(
-			string name)
-		{
-			return (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
-		}
-
-		/**
-		 * return the named curve name represented by the given object identifier.
-		 */
-		public static string GetName(
-			DerObjectIdentifier oid)
-		{
-			return (string) names[oid];
-		}
-
-		/**
-		 * returns an enumeration containing the name strings for curves
-		 * contained in this structure.
-		 */
-		public static IEnumerable Names
-		{
-			get { return new EnumerableProxy(objIds.Keys); }
-		}
-	}
+        private static void DefineCurve(
+            string					name,
+            DerObjectIdentifier		oid,
+            X9ECParametersHolder	holder)
+        {
+            objIds.Add(name, oid);
+            names.Add(oid, name);
+            curves.Add(oid, holder);
+        }
+
+        static SecNamedCurves()
+        {
+            DefineCurve("secp112r1", SecObjectIdentifiers.SecP112r1, Secp112r1Holder.Instance);
+            DefineCurve("secp112r2", SecObjectIdentifiers.SecP112r2, Secp112r2Holder.Instance);
+            DefineCurve("secp128r1", SecObjectIdentifiers.SecP128r1, Secp128r1Holder.Instance);
+            DefineCurve("secp128r2", SecObjectIdentifiers.SecP128r2, Secp128r2Holder.Instance);
+            DefineCurve("secp160k1", SecObjectIdentifiers.SecP160k1, Secp160k1Holder.Instance);
+            DefineCurve("secp160r1", SecObjectIdentifiers.SecP160r1, Secp160r1Holder.Instance);
+            DefineCurve("secp160r2", SecObjectIdentifiers.SecP160r2, Secp160r2Holder.Instance);
+            DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance);
+            DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance);
+            DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance);
+            DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance);
+            DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance);
+            DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance);
+            DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance);
+            DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance);
+
+            DefineCurve("sect113r1", SecObjectIdentifiers.SecT113r1, Sect113r1Holder.Instance);
+            DefineCurve("sect113r2", SecObjectIdentifiers.SecT113r2, Sect113r2Holder.Instance);
+            DefineCurve("sect131r1", SecObjectIdentifiers.SecT131r1, Sect131r1Holder.Instance);
+            DefineCurve("sect131r2", SecObjectIdentifiers.SecT131r2, Sect131r2Holder.Instance);
+            DefineCurve("sect163k1", SecObjectIdentifiers.SecT163k1, Sect163k1Holder.Instance);
+            DefineCurve("sect163r1", SecObjectIdentifiers.SecT163r1, Sect163r1Holder.Instance);
+            DefineCurve("sect163r2", SecObjectIdentifiers.SecT163r2, Sect163r2Holder.Instance);
+            DefineCurve("sect193r1", SecObjectIdentifiers.SecT193r1, Sect193r1Holder.Instance);
+            DefineCurve("sect193r2", SecObjectIdentifiers.SecT193r2, Sect193r2Holder.Instance);
+            DefineCurve("sect233k1", SecObjectIdentifiers.SecT233k1, Sect233k1Holder.Instance);
+            DefineCurve("sect233r1", SecObjectIdentifiers.SecT233r1, Sect233r1Holder.Instance);
+            DefineCurve("sect239k1", SecObjectIdentifiers.SecT239k1, Sect239k1Holder.Instance);
+            DefineCurve("sect283k1", SecObjectIdentifiers.SecT283k1, Sect283k1Holder.Instance);
+            DefineCurve("sect283r1", SecObjectIdentifiers.SecT283r1, Sect283r1Holder.Instance);
+            DefineCurve("sect409k1", SecObjectIdentifiers.SecT409k1, Sect409k1Holder.Instance);
+            DefineCurve("sect409r1", SecObjectIdentifiers.SecT409r1, Sect409r1Holder.Instance);
+            DefineCurve("sect571k1", SecObjectIdentifiers.SecT571k1, Sect571k1Holder.Instance);
+            DefineCurve("sect571r1", SecObjectIdentifiers.SecT571r1, Sect571r1Holder.Instance);
+        }
+
+        public static X9ECParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier)
+                objIds[Platform.ToLowerInvariant(name)];
+
+            return oid == null ? null : GetByOid(oid);
+        }
+
+        /**
+         * 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(
+            DerObjectIdentifier oid)
+        {
+            X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
+
+            return holder == null ? null : holder.Parameters;
+        }
+
+        /**
+         * 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 DerObjectIdentifier GetOid(
+            string name)
+        {
+            return (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
+        }
+
+        /**
+         * return the named curve name represented by the given object identifier.
+         */
+        public static string GetName(
+            DerObjectIdentifier oid)
+        {
+            return (string) names[oid];
+        }
+
+        /**
+         * returns an enumeration containing the name strings for curves
+         * contained in this structure.
+         */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(objIds.Keys); }
+        }
+    }
 }
diff --git a/crypto/src/asn1/sec/SECObjectIdentifiers.cs b/crypto/src/asn1/sec/SECObjectIdentifiers.cs
new file mode 100644
index 000000000..afc10e1d6
--- /dev/null
+++ b/crypto/src/asn1/sec/SECObjectIdentifiers.cs
@@ -0,0 +1,52 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+
+namespace Org.BouncyCastle.Asn1.Sec
+{
+	public abstract class SecObjectIdentifiers
+	{
+		/**
+		 *  EllipticCurve OBJECT IDENTIFIER ::= {
+		 *        iso(1) identified-organization(3) certicom(132) curve(0)
+		 *  }
+		 */
+		public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.132.0");
+
+		public static readonly DerObjectIdentifier SecT163k1 = new DerObjectIdentifier(EllipticCurve + ".1");
+		public static readonly DerObjectIdentifier SecT163r1 = new DerObjectIdentifier(EllipticCurve + ".2");
+		public static readonly DerObjectIdentifier SecT239k1 = new DerObjectIdentifier(EllipticCurve + ".3");
+		public static readonly DerObjectIdentifier SecT113r1 = new DerObjectIdentifier(EllipticCurve + ".4");
+		public static readonly DerObjectIdentifier SecT113r2 = new DerObjectIdentifier(EllipticCurve + ".5");
+		public static readonly DerObjectIdentifier SecP112r1 = new DerObjectIdentifier(EllipticCurve + ".6");
+		public static readonly DerObjectIdentifier SecP112r2 = new DerObjectIdentifier(EllipticCurve + ".7");
+		public static readonly DerObjectIdentifier SecP160r1 = new DerObjectIdentifier(EllipticCurve + ".8");
+		public static readonly DerObjectIdentifier SecP160k1 = new DerObjectIdentifier(EllipticCurve + ".9");
+		public static readonly DerObjectIdentifier SecP256k1 = new DerObjectIdentifier(EllipticCurve + ".10");
+		public static readonly DerObjectIdentifier SecT163r2 = new DerObjectIdentifier(EllipticCurve + ".15");
+		public static readonly DerObjectIdentifier SecT283k1 = new DerObjectIdentifier(EllipticCurve + ".16");
+		public static readonly DerObjectIdentifier SecT283r1 = new DerObjectIdentifier(EllipticCurve + ".17");
+		public static readonly DerObjectIdentifier SecT131r1 = new DerObjectIdentifier(EllipticCurve + ".22");
+		public static readonly DerObjectIdentifier SecT131r2 = new DerObjectIdentifier(EllipticCurve + ".23");
+		public static readonly DerObjectIdentifier SecT193r1 = new DerObjectIdentifier(EllipticCurve + ".24");
+		public static readonly DerObjectIdentifier SecT193r2 = new DerObjectIdentifier(EllipticCurve + ".25");
+		public static readonly DerObjectIdentifier SecT233k1 = new DerObjectIdentifier(EllipticCurve + ".26");
+		public static readonly DerObjectIdentifier SecT233r1 = new DerObjectIdentifier(EllipticCurve + ".27");
+		public static readonly DerObjectIdentifier SecP128r1 = new DerObjectIdentifier(EllipticCurve + ".28");
+		public static readonly DerObjectIdentifier SecP128r2 = new DerObjectIdentifier(EllipticCurve + ".29");
+		public static readonly DerObjectIdentifier SecP160r2 = new DerObjectIdentifier(EllipticCurve + ".30");
+		public static readonly DerObjectIdentifier SecP192k1 = new DerObjectIdentifier(EllipticCurve + ".31");
+		public static readonly DerObjectIdentifier SecP224k1 = new DerObjectIdentifier(EllipticCurve + ".32");
+		public static readonly DerObjectIdentifier SecP224r1 = new DerObjectIdentifier(EllipticCurve + ".33");
+		public static readonly DerObjectIdentifier SecP384r1 = new DerObjectIdentifier(EllipticCurve + ".34");
+		public static readonly DerObjectIdentifier SecP521r1 = new DerObjectIdentifier(EllipticCurve + ".35");
+		public static readonly DerObjectIdentifier SecT409k1 = new DerObjectIdentifier(EllipticCurve + ".36");
+		public static readonly DerObjectIdentifier SecT409r1 = new DerObjectIdentifier(EllipticCurve + ".37");
+		public static readonly DerObjectIdentifier SecT571k1 = new DerObjectIdentifier(EllipticCurve + ".38");
+		public static readonly DerObjectIdentifier SecT571r1 = new DerObjectIdentifier(EllipticCurve + ".39");
+
+		public static readonly DerObjectIdentifier SecP192r1 = X9ObjectIdentifiers.Prime192v1;
+		public static readonly DerObjectIdentifier SecP256r1 = X9ObjectIdentifiers.Prime256v1;
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/asn1/smime/SMIMEAttributes.cs b/crypto/src/asn1/smime/SMIMEAttributes.cs
new file mode 100644
index 000000000..e154e5e74
--- /dev/null
+++ b/crypto/src/asn1/smime/SMIMEAttributes.cs
@@ -0,0 +1,11 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    public abstract class SmimeAttributes
+    {
+        public static readonly DerObjectIdentifier SmimeCapabilities = PkcsObjectIdentifiers.Pkcs9AtSmimeCapabilities;
+        public static readonly DerObjectIdentifier EncrypKeyPref = PkcsObjectIdentifiers.IdAAEncrypKeyPref;
+    }
+}
diff --git a/crypto/src/asn1/smime/SMIMECapabilities.cs b/crypto/src/asn1/smime/SMIMECapabilities.cs
index adf254e56..ca3c3af7d 100644
--- a/crypto/src/asn1/smime/SMIMECapabilities.cs
+++ b/crypto/src/asn1/smime/SMIMECapabilities.cs
@@ -65,7 +65,7 @@ namespace Org.BouncyCastle.Asn1.Smime
             capabilities = seq;
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete("Use 'GetCapabilitiesForOid' instead")]
         public ArrayList GetCapabilities(
             DerObjectIdentifier capability)
diff --git a/crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs b/crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs
new file mode 100644
index 000000000..310c478fe
--- /dev/null
+++ b/crypto/src/asn1/smime/SMIMECapabilitiesAttribute.cs
@@ -0,0 +1,16 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    public class SmimeCapabilitiesAttribute
+        : AttributeX509
+    {
+        public SmimeCapabilitiesAttribute(
+            SmimeCapabilityVector capabilities)
+            : base(SmimeAttributes.SmimeCapabilities,
+                    new DerSet(new DerSequence(capabilities.ToAsn1EncodableVector())))
+        {
+        }
+    }
+}
diff --git a/crypto/src/asn1/smime/SMIMECapability.cs b/crypto/src/asn1/smime/SMIMECapability.cs
new file mode 100644
index 000000000..5709cb815
--- /dev/null
+++ b/crypto/src/asn1/smime/SMIMECapability.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    public class SmimeCapability
+        : Asn1Encodable
+    {
+        /**
+         * general preferences
+         */
+        public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData;
+        public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny;
+        public static readonly DerObjectIdentifier SmimeCapabilitiesVersions = PkcsObjectIdentifiers.SmimeCapabilitiesVersions;
+
+		/**
+         * encryption algorithms preferences
+         */
+        public static readonly DerObjectIdentifier DesCbc = new DerObjectIdentifier("1.3.14.3.2.7");
+        public static readonly DerObjectIdentifier DesEde3Cbc = PkcsObjectIdentifiers.DesEde3Cbc;
+        public static readonly DerObjectIdentifier RC2Cbc = PkcsObjectIdentifiers.RC2Cbc;
+
+		private DerObjectIdentifier capabilityID;
+        private Asn1Object			parameters;
+
+		public SmimeCapability(
+            Asn1Sequence seq)
+        {
+            capabilityID = (DerObjectIdentifier) seq[0].ToAsn1Object();
+
+			if (seq.Count > 1)
+            {
+                parameters = seq[1].ToAsn1Object();
+            }
+        }
+
+		public SmimeCapability(
+            DerObjectIdentifier	capabilityID,
+            Asn1Encodable		parameters)
+        {
+			if (capabilityID == null)
+				throw new ArgumentNullException("capabilityID");
+
+			this.capabilityID = capabilityID;
+
+			if (parameters != null)
+			{
+				this.parameters = parameters.ToAsn1Object();
+			}
+        }
+
+		public static SmimeCapability GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is SmimeCapability)
+            {
+                return (SmimeCapability) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SmimeCapability((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid SmimeCapability");
+        }
+
+		public DerObjectIdentifier CapabilityID
+		{
+			get { return capabilityID; }
+		}
+
+		public Asn1Object Parameters
+		{
+			get { return parameters; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SMIMECapability ::= Sequence {
+         *     capabilityID OBJECT IDENTIFIER,
+         *     parameters ANY DEFINED BY capabilityID OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(capabilityID);
+
+			if (parameters != null)
+            {
+                v.Add(parameters);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/smime/SMIMECapabilityVector.cs b/crypto/src/asn1/smime/SMIMECapabilityVector.cs
new file mode 100644
index 000000000..842825b88
--- /dev/null
+++ b/crypto/src/asn1/smime/SMIMECapabilityVector.cs
@@ -0,0 +1,37 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    /**
+     * Handler for creating a vector S/MIME Capabilities
+     */
+    public class SmimeCapabilityVector
+    {
+        private readonly Asn1EncodableVector capabilities = new Asn1EncodableVector();
+
+		public void AddCapability(
+            DerObjectIdentifier capability)
+        {
+            capabilities.Add(new DerSequence(capability));
+        }
+
+		public void AddCapability(
+            DerObjectIdentifier capability,
+            int                 value)
+        {
+			capabilities.Add(new DerSequence(capability, new DerInteger(value)));
+        }
+
+		public void AddCapability(
+            DerObjectIdentifier capability,
+            Asn1Encodable		parameters)
+        {
+			capabilities.Add(new DerSequence(capability, parameters));
+        }
+
+		public Asn1EncodableVector ToAsn1EncodableVector()
+        {
+            return capabilities;
+        }
+    }
+}
diff --git a/crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs b/crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs
new file mode 100644
index 000000000..19c5fd78a
--- /dev/null
+++ b/crypto/src/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.cs
@@ -0,0 +1,44 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    /**
+     * The SmimeEncryptionKeyPreference object.
+     * <pre>
+     * SmimeEncryptionKeyPreference ::= CHOICE {
+     *     issuerAndSerialNumber   [0] IssuerAndSerialNumber,
+     *     receipentKeyId          [1] RecipientKeyIdentifier,
+     *     subjectAltKeyIdentifier [2] SubjectKeyIdentifier
+     * }
+     * </pre>
+     */
+    public class SmimeEncryptionKeyPreferenceAttribute
+        : AttributeX509
+    {
+        public SmimeEncryptionKeyPreferenceAttribute(
+            IssuerAndSerialNumber issAndSer)
+            : base(SmimeAttributes.EncrypKeyPref,
+                new DerSet(new DerTaggedObject(false, 0, issAndSer)))
+        {
+        }
+
+        public SmimeEncryptionKeyPreferenceAttribute(
+            RecipientKeyIdentifier rKeyID)
+            : base(SmimeAttributes.EncrypKeyPref,
+                new DerSet(new DerTaggedObject(false, 1, rKeyID)))
+        {
+        }
+
+        /**
+         * @param sKeyId the subjectKeyIdentifier value (normally the X.509 one)
+         */
+        public SmimeEncryptionKeyPreferenceAttribute(
+            Asn1OctetString sKeyID)
+            : base(SmimeAttributes.EncrypKeyPref,
+                new DerSet(new DerTaggedObject(false, 2, sKeyID)))
+        {
+        }
+    }
+}
diff --git a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
index 0cfdb8483..05060c109 100644
--- a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
+++ b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -1,5 +1,4 @@
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Math;
@@ -10,419 +9,466 @@ using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Asn1.TeleTrust
 {
-	/**
-	* elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
-	* http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt
-	*/
-	public class TeleTrusTNamedCurves
-	{
-		internal class BrainpoolP160r1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP160r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP160r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
-					new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a
-					new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16)); // b
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
-					new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP160t1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP160t1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP160t1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					//   new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z
-					new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
-					new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a'
-					new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16)); // b'
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
-					new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP192r1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP192r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP192r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
-					new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a
-					new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16)); // b
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
-					new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP192t1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP192t1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP192t1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					//new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z
-					new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
-					new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a'
-					new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16)); // b'
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
-					new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP224r1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP224r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP224r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
-					new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a
-					new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16)); // b
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
-					new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n
-					new BigInteger("01", 16)); // n
-			}
-		}
-
-		internal class BrainpoolP224t1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP224t1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP224t1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					//new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z
-					new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
-					new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a'
-					new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16)); // b'
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
-					new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP256r1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP256r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP256r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
-					new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a
-					new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16)); // b
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
-					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP256t1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP256t1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP256t1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					//new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z
-					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
-					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a'
-					new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16)); // b'
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
-					new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP320r1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP320r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP320r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
-					new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a
-					new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16)); // b
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
-					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP320t1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP320t1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP320t1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					//new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z
-					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
-					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a'
-					new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16)); // b'
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
-					new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP384r1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP384r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP384r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
-					new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a
-					new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16)); // b
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
-					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP384t1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP384t1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP384t1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					//new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z
-					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
-					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a'
-					new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16)); // b'
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
-					new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP512r1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP512r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP512r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
-					new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a
-					new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16)); // b
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
-					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-		internal class BrainpoolP512t1Holder
-			: X9ECParametersHolder
-		{
-			private BrainpoolP512t1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new BrainpoolP512t1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve curve = new FpCurve(
-					//new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z
-					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
-					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a'
-					new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16)); // b'
-
-				return new X9ECParameters(
-					curve,
-					curve.DecodePoint(Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
-					new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16), //n
-					new BigInteger("01", 16)); // h
-			}
-		}
-
-
-		private static readonly IDictionary objIds = Platform.CreateHashtable();
+    /**
+    * elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
+    * http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt
+    */
+    public class TeleTrusTNamedCurves
+    {
+        private static ECCurve ConfigureCurve(ECCurve curve)
+        {
+            return curve;
+        }
+
+        internal class BrainpoolP160r1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP160r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP160r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
+                    new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a
+                    new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16), // b
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP160t1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP160t1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP160t1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    //   new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z
+                    new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q
+                    new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a'
+                    new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16), // b'
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP192r1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP192r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP192r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
+                    new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a
+                    new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16), // b
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP192t1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP192t1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP192t1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    //new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z
+                    new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q
+                    new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a'
+                    new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16), // b'
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP224r1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP224r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP224r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
+                    new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a
+                    new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16), // b
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP224t1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP224t1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP224t1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    //new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z
+                    new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q
+                    new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a'
+                    new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16), // b'
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP256r1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP256r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP256r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
+                    new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a
+                    new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16), // b
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP256t1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP256t1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP256t1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    //new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z
+                    new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q
+                    new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a'
+                    new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16), // b'
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP320r1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP320r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP320r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
+                    new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a
+                    new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16), // b
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP320t1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP320t1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP320t1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    //new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z
+                    new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q
+                    new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a'
+                    new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16), // b'
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP384r1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP384r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP384r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
+                    new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a
+                    new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16), // b
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP384t1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP384t1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP384t1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    //new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z
+                    new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q
+                    new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a'
+                    new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16), // b'
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP512r1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP512r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP512r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
+                    new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a
+                    new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16), // b
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
+                    n, h);
+            }
+        }
+
+        internal class BrainpoolP512t1Holder
+            : X9ECParametersHolder
+        {
+            private BrainpoolP512t1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new BrainpoolP512t1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16);
+                BigInteger h = new BigInteger("01", 16);
+
+                ECCurve curve = ConfigureCurve(new FpCurve(
+                    //new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z
+                    new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q
+                    new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a'
+                    new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16), // b'
+                    n, h));
+
+                return new X9ECParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
+                    n, h);
+            }
+        }
+
+
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
         private static readonly IDictionary curves = Platform.CreateHashtable();
         private static readonly IDictionary names = Platform.CreateHashtable();
 
-		private static void DefineCurve(
-			string					name,
-			DerObjectIdentifier		oid,
-			X9ECParametersHolder	holder)
-		{
-			objIds.Add(name, oid);
-			names.Add(oid, name);
-			curves.Add(oid, holder);
-		}
-
-		static TeleTrusTNamedCurves()
-		{
-			DefineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
-			DefineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
-			DefineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
-			DefineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
-			DefineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
-			DefineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
-			DefineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
-			DefineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
-			DefineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
-			DefineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
-			DefineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
-			DefineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
-			DefineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
-			DefineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
-		}
-
-		public static X9ECParameters GetByName(
-			string name)
-		{
-			DerObjectIdentifier oid = (DerObjectIdentifier)
-				objIds[name.ToLowerInvariant()];
-
-			return oid == null ? null : GetByOid(oid);
-		}
-
-		/**
-		* 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(
-			DerObjectIdentifier oid)
-		{
-			X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
-			return holder == null ? null : holder.Parameters;
-		}
-
-		/**
-		* 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 DerObjectIdentifier GetOid(
-			string name)
-		{
-			return (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
-		}
-
-		/**
-		* return the named curve name represented by the given object identifier.
-		*/
-		public static string GetName(
-			DerObjectIdentifier oid)
-		{
-			return (string) names[oid];
-		}
-
-
-		/**
-		 * returns an enumeration containing the name strings for curves
-		 * contained in this structure.
-		 */
-		public static IEnumerable Names
-		{
-			get { return new EnumerableProxy(objIds.Keys); }
-		}
-
-		public static DerObjectIdentifier GetOid(
-			short	curvesize,
-			bool	twisted)
-		{
-			return GetOid("brainpoolP" + curvesize + (twisted ? "t" : "r") + "1");
-		}
-	}
+        private static void DefineCurve(
+            string					name,
+            DerObjectIdentifier		oid,
+            X9ECParametersHolder	holder)
+        {
+            objIds.Add(name, oid);
+            names.Add(oid, name);
+            curves.Add(oid, holder);
+        }
+
+        static TeleTrusTNamedCurves()
+        {
+            DefineCurve("brainpoolp160r1", TeleTrusTObjectIdentifiers.BrainpoolP160R1, BrainpoolP160r1Holder.Instance);
+            DefineCurve("brainpoolp160t1", TeleTrusTObjectIdentifiers.BrainpoolP160T1, BrainpoolP160t1Holder.Instance);
+            DefineCurve("brainpoolp192r1", TeleTrusTObjectIdentifiers.BrainpoolP192R1, BrainpoolP192r1Holder.Instance);
+            DefineCurve("brainpoolp192t1", TeleTrusTObjectIdentifiers.BrainpoolP192T1, BrainpoolP192t1Holder.Instance);
+            DefineCurve("brainpoolp224r1", TeleTrusTObjectIdentifiers.BrainpoolP224R1, BrainpoolP224r1Holder.Instance);
+            DefineCurve("brainpoolp224t1", TeleTrusTObjectIdentifiers.BrainpoolP224T1, BrainpoolP224t1Holder.Instance);
+            DefineCurve("brainpoolp256r1", TeleTrusTObjectIdentifiers.BrainpoolP256R1, BrainpoolP256r1Holder.Instance);
+            DefineCurve("brainpoolp256t1", TeleTrusTObjectIdentifiers.BrainpoolP256T1, BrainpoolP256t1Holder.Instance);
+            DefineCurve("brainpoolp320r1", TeleTrusTObjectIdentifiers.BrainpoolP320R1, BrainpoolP320r1Holder.Instance);
+            DefineCurve("brainpoolp320t1", TeleTrusTObjectIdentifiers.BrainpoolP320T1, BrainpoolP320t1Holder.Instance);
+            DefineCurve("brainpoolp384r1", TeleTrusTObjectIdentifiers.BrainpoolP384R1, BrainpoolP384r1Holder.Instance);
+            DefineCurve("brainpoolp384t1", TeleTrusTObjectIdentifiers.BrainpoolP384T1, BrainpoolP384t1Holder.Instance);
+            DefineCurve("brainpoolp512r1", TeleTrusTObjectIdentifiers.BrainpoolP512R1, BrainpoolP512r1Holder.Instance);
+            DefineCurve("brainpoolp512t1", TeleTrusTObjectIdentifiers.BrainpoolP512T1, BrainpoolP512t1Holder.Instance);
+        }
+
+        public static X9ECParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier)
+                objIds[Platform.ToLowerInvariant(name)];
+
+            return oid == null ? null : GetByOid(oid);
+        }
+
+        /**
+        * 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(
+            DerObjectIdentifier oid)
+        {
+            X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
+
+            return holder == null ? null : holder.Parameters;
+        }
+
+        /**
+        * 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 DerObjectIdentifier GetOid(
+            string name)
+        {
+            return (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
+        }
+
+        /**
+        * return the named curve name represented by the given object identifier.
+        */
+        public static string GetName(
+            DerObjectIdentifier oid)
+        {
+            return (string) names[oid];
+        }
+
+
+        /**
+         * returns an enumeration containing the name strings for curves
+         * contained in this structure.
+         */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(objIds.Keys); }
+        }
+
+        public static DerObjectIdentifier GetOid(
+            short	curvesize,
+            bool	twisted)
+        {
+            return GetOid("brainpoolP" + curvesize + (twisted ? "t" : "r") + "1");
+        }
+    }
 }
diff --git a/crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs b/crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs
new file mode 100644
index 000000000..56e70842a
--- /dev/null
+++ b/crypto/src/asn1/teletrust/TeleTrusTObjectIdentifiers.cs
@@ -0,0 +1,45 @@
+namespace Org.BouncyCastle.Asn1.TeleTrust
+{
+	public sealed class TeleTrusTObjectIdentifiers
+	{
+		private TeleTrusTObjectIdentifiers()
+		{
+		}
+
+		public static readonly DerObjectIdentifier TeleTrusTAlgorithm = new DerObjectIdentifier("1.3.36.3");
+
+		public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.1");
+		public static readonly DerObjectIdentifier RipeMD128 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.2");
+		public static readonly DerObjectIdentifier RipeMD256 = new DerObjectIdentifier(TeleTrusTAlgorithm + ".2.3");
+
+		public static readonly DerObjectIdentifier TeleTrusTRsaSignatureAlgorithm = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.1");
+
+		public static readonly DerObjectIdentifier RsaSignatureWithRipeMD160 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".2");
+		public static readonly DerObjectIdentifier RsaSignatureWithRipeMD128 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".3");
+		public static readonly DerObjectIdentifier RsaSignatureWithRipeMD256 = new DerObjectIdentifier(TeleTrusTRsaSignatureAlgorithm + ".4");
+
+		public static readonly DerObjectIdentifier ECSign = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2");
+
+		public static readonly DerObjectIdentifier ECSignWithSha1 = new DerObjectIdentifier(ECSign + ".1");
+		public static readonly DerObjectIdentifier ECSignWithRipeMD160 = new DerObjectIdentifier(ECSign + ".2");
+
+		public static readonly DerObjectIdentifier EccBrainpool = new DerObjectIdentifier(TeleTrusTAlgorithm + ".3.2.8");
+		public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(EccBrainpool + ".1");
+		public static readonly DerObjectIdentifier VersionOne = new DerObjectIdentifier(EllipticCurve + ".1");    
+
+		public static readonly DerObjectIdentifier BrainpoolP160R1 = new DerObjectIdentifier(VersionOne + ".1");
+		public static readonly DerObjectIdentifier BrainpoolP160T1 = new DerObjectIdentifier(VersionOne + ".2");
+		public static readonly DerObjectIdentifier BrainpoolP192R1 = new DerObjectIdentifier(VersionOne + ".3");
+		public static readonly DerObjectIdentifier BrainpoolP192T1 = new DerObjectIdentifier(VersionOne + ".4");
+		public static readonly DerObjectIdentifier BrainpoolP224R1 = new DerObjectIdentifier(VersionOne + ".5");
+		public static readonly DerObjectIdentifier BrainpoolP224T1 = new DerObjectIdentifier(VersionOne + ".6");
+		public static readonly DerObjectIdentifier BrainpoolP256R1 = new DerObjectIdentifier(VersionOne + ".7");
+		public static readonly DerObjectIdentifier BrainpoolP256T1 = new DerObjectIdentifier(VersionOne + ".8");
+		public static readonly DerObjectIdentifier BrainpoolP320R1 = new DerObjectIdentifier(VersionOne + ".9");
+		public static readonly DerObjectIdentifier BrainpoolP320T1 = new DerObjectIdentifier(VersionOne + ".10");
+		public static readonly DerObjectIdentifier BrainpoolP384R1 = new DerObjectIdentifier(VersionOne + ".11");
+		public static readonly DerObjectIdentifier BrainpoolP384T1 = new DerObjectIdentifier(VersionOne + ".12");
+		public static readonly DerObjectIdentifier BrainpoolP512R1 = new DerObjectIdentifier(VersionOne + ".13");
+		public static readonly DerObjectIdentifier BrainpoolP512T1 = new DerObjectIdentifier(VersionOne + ".14");
+	}
+}
diff --git a/crypto/src/asn1/tsp/Accuracy.cs b/crypto/src/asn1/tsp/Accuracy.cs
new file mode 100644
index 000000000..a193f52ff
--- /dev/null
+++ b/crypto/src/asn1/tsp/Accuracy.cs
@@ -0,0 +1,149 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class Accuracy
+		: Asn1Encodable
+	{
+		private readonly DerInteger seconds;
+		private readonly DerInteger millis;
+		private readonly DerInteger micros;
+
+		// constants
+		protected const int MinMillis = 1;
+		protected const int MaxMillis = 999;
+		protected const int MinMicros = 1;
+		protected const int MaxMicros = 999;
+
+		public Accuracy(
+			DerInteger seconds,
+			DerInteger millis,
+			DerInteger micros)
+		{
+			//Verifications
+			if (millis != null
+				&& (millis.Value.IntValue < MinMillis
+					|| millis.Value.IntValue > MaxMillis))
+			{
+				throw new ArgumentException(
+					"Invalid millis field : not in (1..999)");
+			}
+
+			if (micros != null
+				&& (micros.Value.IntValue < MinMicros
+					|| micros.Value.IntValue > MaxMicros))
+			{
+				throw new ArgumentException(
+					"Invalid micros field : not in (1..999)");
+			}
+
+			this.seconds = seconds;
+			this.millis = millis;
+			this.micros = micros;
+		}
+
+		private Accuracy(
+			Asn1Sequence seq)
+		{
+			for (int i = 0; i < seq.Count; ++i)
+			{
+				// seconds
+				if (seq[i] is DerInteger)
+				{
+					seconds = (DerInteger) seq[i];
+				}
+				else if (seq[i] is DerTaggedObject)
+				{
+					DerTaggedObject extra = (DerTaggedObject) seq[i];
+
+					switch (extra.TagNo)
+					{
+						case 0:
+							millis = DerInteger.GetInstance(extra, false);
+							if (millis.Value.IntValue < MinMillis
+								|| millis.Value.IntValue > MaxMillis)
+							{
+								throw new ArgumentException(
+									"Invalid millis field : not in (1..999).");
+							}
+							break;
+						case 1:
+							micros = DerInteger.GetInstance(extra, false);
+							if (micros.Value.IntValue < MinMicros
+								|| micros.Value.IntValue > MaxMicros)
+							{
+								throw new ArgumentException(
+									"Invalid micros field : not in (1..999).");
+							}
+							break;
+						default:
+							throw new ArgumentException("Invalig tag number");
+					}
+				}
+			}
+		}
+
+		public static Accuracy GetInstance(
+			object o)
+		{
+			if (o == null || o is Accuracy)
+			{
+				return (Accuracy) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new Accuracy((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'Accuracy' factory: " + o.GetType().FullName);
+		}
+
+		public DerInteger Seconds
+		{
+			get { return seconds; }
+		}
+
+		public DerInteger Millis
+		{
+			get { return millis; }
+		}
+
+		public DerInteger Micros
+		{
+			get { return micros; }
+		}
+
+		/**
+		 * <pre>
+		 * Accuracy ::= SEQUENCE {
+		 *             seconds        INTEGER              OPTIONAL,
+		 *             millis     [0] INTEGER  (1..999)    OPTIONAL,
+		 *             micros     [1] INTEGER  (1..999)    OPTIONAL
+		 *             }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (seconds != null)
+			{
+				v.Add(seconds);
+			}
+
+			if (millis != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, millis));
+			}
+
+			if (micros != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, micros));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/tsp/MessageImprint.cs b/crypto/src/asn1/tsp/MessageImprint.cs
new file mode 100644
index 000000000..0933bae21
--- /dev/null
+++ b/crypto/src/asn1/tsp/MessageImprint.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class MessageImprint
+		: Asn1Encodable
+	{
+		private readonly AlgorithmIdentifier	hashAlgorithm;
+		private readonly byte[]					hashedMessage;
+
+		/**
+		 * @param o
+		 * @return a MessageImprint object.
+		 */
+		public static MessageImprint GetInstance(
+			object o)
+		{
+			if (o == null || o is MessageImprint)
+			{
+				return (MessageImprint) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new MessageImprint((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'MessageImprint' factory: " + o.GetType().FullName);
+		}
+
+		private MessageImprint(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+			this.hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+		}
+
+		public MessageImprint(
+			AlgorithmIdentifier	hashAlgorithm,
+			byte[]				hashedMessage)
+		{
+			this.hashAlgorithm = hashAlgorithm;
+			this.hashedMessage = hashedMessage;
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public byte[] GetHashedMessage()
+		{
+			return hashedMessage;
+		}
+
+		/**
+		 * <pre>
+		 *    MessageImprint ::= SEQUENCE  {
+		 *       hashAlgorithm                AlgorithmIdentifier,
+		 *       hashedMessage                OCTET STRING  }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(hashAlgorithm, new DerOctetString(hashedMessage));
+		}
+	}
+}
diff --git a/crypto/src/asn1/tsp/TSTInfo.cs b/crypto/src/asn1/tsp/TSTInfo.cs
new file mode 100644
index 000000000..61d5399c7
--- /dev/null
+++ b/crypto/src/asn1/tsp/TSTInfo.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class TstInfo
+		: Asn1Encodable
+	{
+		private readonly DerInteger				version;
+		private readonly DerObjectIdentifier	tsaPolicyId;
+		private readonly MessageImprint			messageImprint;
+		private readonly DerInteger				serialNumber;
+		private readonly DerGeneralizedTime		genTime;
+		private readonly Accuracy				accuracy;
+		private readonly DerBoolean				ordering;
+		private readonly DerInteger				nonce;
+		private readonly GeneralName			tsa;
+		private readonly X509Extensions			extensions;
+
+		public static TstInfo GetInstance(
+			object o)
+		{
+			if (o == null || o is TstInfo)
+			{
+				return (TstInfo) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new TstInfo((Asn1Sequence) o);
+			}
+
+			if (o is Asn1OctetString)
+			{
+				try
+				{
+					byte[] octets = ((Asn1OctetString)o).GetOctets();
+					return GetInstance(Asn1Object.FromByteArray(octets));
+				}
+				catch (IOException)
+				{
+					throw new ArgumentException(
+						"Bad object format in 'TstInfo' factory.");
+				}
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'TstInfo' factory: " + o.GetType().FullName);
+		}
+
+		private TstInfo(
+			Asn1Sequence seq)
+		{
+			IEnumerator e = seq.GetEnumerator();
+
+			// version
+			e.MoveNext();
+			version = DerInteger.GetInstance(e.Current);
+
+			// tsaPolicy
+			e.MoveNext();
+			tsaPolicyId = DerObjectIdentifier.GetInstance(e.Current);
+
+			// messageImprint
+			e.MoveNext();
+			messageImprint = MessageImprint.GetInstance(e.Current);
+
+			// serialNumber
+			e.MoveNext();
+			serialNumber = DerInteger.GetInstance(e.Current);
+
+			// genTime
+			e.MoveNext();
+			genTime = DerGeneralizedTime.GetInstance(e.Current);
+
+			// default for ordering
+			ordering = DerBoolean.False;
+
+			while (e.MoveNext())
+			{
+				Asn1Object o = (Asn1Object) e.Current;
+
+				if (o is Asn1TaggedObject)
+				{
+					DerTaggedObject tagged = (DerTaggedObject) o;
+
+					switch (tagged.TagNo)
+					{
+						case 0:
+							tsa = GeneralName.GetInstance(tagged, true);
+							break;
+						case 1:
+							extensions = X509Extensions.GetInstance(tagged, false);
+							break;
+						default:
+							throw new ArgumentException("Unknown tag value " + tagged.TagNo);
+					}
+				}
+
+				if (o is DerSequence)
+				{
+					accuracy = Accuracy.GetInstance(o);
+				}
+
+				if (o is DerBoolean)
+				{
+					ordering = DerBoolean.GetInstance(o);
+				}
+
+				if (o is DerInteger)
+				{
+					nonce = DerInteger.GetInstance(o);
+				}
+			}
+		}
+
+		public TstInfo(
+			DerObjectIdentifier	tsaPolicyId,
+			MessageImprint		messageImprint,
+			DerInteger			serialNumber,
+			DerGeneralizedTime	genTime,
+			Accuracy			accuracy,
+			DerBoolean			ordering,
+			DerInteger			nonce,
+			GeneralName			tsa,
+			X509Extensions		extensions)
+		{
+			this.version = new DerInteger(1);
+			this.tsaPolicyId = tsaPolicyId;
+			this.messageImprint = messageImprint;
+			this.serialNumber = serialNumber;
+			this.genTime = genTime;
+			this.accuracy = accuracy;
+			this.ordering = ordering;
+			this.nonce = nonce;
+			this.tsa = tsa;
+			this.extensions = extensions;
+		}
+
+        public DerInteger Version
+        {
+            get { return version; }
+        }
+
+		public MessageImprint MessageImprint
+		{
+			get { return messageImprint; }
+		}
+
+		public DerObjectIdentifier Policy
+		{
+			get { return tsaPolicyId; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public Accuracy Accuracy
+		{
+			get { return accuracy; }
+		}
+
+		public DerGeneralizedTime GenTime
+		{
+			get { return genTime; }
+		}
+
+		public DerBoolean Ordering
+		{
+			get { return ordering; }
+		}
+
+		public DerInteger Nonce
+		{
+			get { return nonce; }
+		}
+
+		public GeneralName Tsa
+		{
+			get { return tsa; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get { return extensions; }
+		}
+
+		/**
+		 * <pre>
+		 *
+		 *     TstInfo ::= SEQUENCE  {
+		 *        version                      INTEGER  { v1(1) },
+		 *        policy                       TSAPolicyId,
+		 *        messageImprint               MessageImprint,
+		 *          -- MUST have the same value as the similar field in
+		 *          -- TimeStampReq
+		 *        serialNumber                 INTEGER,
+		 *         -- Time-Stamping users MUST be ready to accommodate integers
+		 *         -- up to 160 bits.
+		 *        genTime                      GeneralizedTime,
+		 *        accuracy                     Accuracy                 OPTIONAL,
+		 *        ordering                     BOOLEAN             DEFAULT FALSE,
+		 *        nonce                        INTEGER                  OPTIONAL,
+		 *          -- MUST be present if the similar field was present
+		 *          -- in TimeStampReq.  In that case it MUST have the same value.
+		 *        tsa                          [0] GeneralName          OPTIONAL,
+		 *        extensions                   [1] IMPLICIT Extensions   OPTIONAL  }
+		 *
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, tsaPolicyId, messageImprint, serialNumber, genTime);
+
+			if (accuracy != null)
+			{
+				v.Add(accuracy);
+			}
+
+			if (ordering != null && ordering.IsTrue)
+			{
+				v.Add(ordering);
+			}
+
+			if (nonce != null)
+			{
+				v.Add(nonce);
+			}
+
+			if (tsa != null)
+			{
+				v.Add(new DerTaggedObject(true, 0, tsa));
+			}
+
+			if (extensions != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, extensions));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/tsp/TimeStampReq.cs b/crypto/src/asn1/tsp/TimeStampReq.cs
new file mode 100644
index 000000000..55e973e76
--- /dev/null
+++ b/crypto/src/asn1/tsp/TimeStampReq.cs
@@ -0,0 +1,164 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class TimeStampReq
+		: Asn1Encodable
+	{
+		private readonly DerInteger				version;
+		private readonly MessageImprint			messageImprint;
+		private readonly DerObjectIdentifier	tsaPolicy;
+		private readonly DerInteger				nonce;
+		private readonly DerBoolean				certReq;
+		private readonly X509Extensions			extensions;
+
+		public static TimeStampReq GetInstance(
+			object o)
+		{
+			if (o == null || o is TimeStampReq)
+			{
+				return (TimeStampReq) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new TimeStampReq((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'TimeStampReq' factory: " + o.GetType().FullName);
+		}
+
+		private TimeStampReq(
+			Asn1Sequence seq)
+		{
+			int nbObjects = seq.Count;
+			int seqStart = 0;
+
+			// version
+			version = DerInteger.GetInstance(seq[seqStart++]);
+
+			// messageImprint
+			messageImprint = MessageImprint.GetInstance(seq[seqStart++]);
+
+			for (int opt = seqStart; opt < nbObjects; opt++)
+			{
+				// tsaPolicy
+				if (seq[opt] is DerObjectIdentifier)
+				{
+					tsaPolicy = DerObjectIdentifier.GetInstance(seq[opt]);
+				}
+				// nonce
+				else if (seq[opt] is DerInteger)
+				{
+					nonce = DerInteger.GetInstance(seq[opt]);
+				}
+				// certReq
+				else if (seq[opt] is DerBoolean)
+				{
+					certReq = DerBoolean.GetInstance(seq[opt]);
+				}
+				// extensions
+				else if (seq[opt] is Asn1TaggedObject)
+				{
+					Asn1TaggedObject tagged = (Asn1TaggedObject) seq[opt];
+					if (tagged.TagNo == 0)
+					{
+						extensions = X509Extensions.GetInstance(tagged, false);
+					}
+				}
+			}
+		}
+
+		public TimeStampReq(
+			MessageImprint		messageImprint,
+			DerObjectIdentifier	tsaPolicy,
+			DerInteger			nonce,
+			DerBoolean			certReq,
+			X509Extensions		extensions)
+		{
+			// default
+			this.version = new DerInteger(1);
+
+			this.messageImprint = messageImprint;
+			this.tsaPolicy = tsaPolicy;
+			this.nonce = nonce;
+			this.certReq = certReq;
+			this.extensions = extensions;
+		}
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public MessageImprint MessageImprint
+		{
+			get { return messageImprint; }
+		}
+
+		public DerObjectIdentifier ReqPolicy
+		{
+			get { return tsaPolicy; }
+		}
+
+		public DerInteger Nonce
+		{
+			get { return nonce; }
+		}
+
+		public DerBoolean CertReq
+		{
+			get { return certReq; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get { return extensions; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampReq ::= SEQUENCE  {
+		 *  version                      INTEGER  { v1(1) },
+		 *  messageImprint               MessageImprint,
+		 *    --a hash algorithm OID and the hash value of the data to be
+		 *    --time-stamped
+		 *  reqPolicy             TSAPolicyId              OPTIONAL,
+		 *  nonce                 INTEGER                  OPTIONAL,
+		 *  certReq               BOOLEAN                  DEFAULT FALSE,
+		 *  extensions            [0] IMPLICIT Extensions  OPTIONAL
+		 * }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, messageImprint);
+
+			if (tsaPolicy != null)
+			{
+				v.Add(tsaPolicy);
+			}
+
+			if (nonce != null)
+			{
+				v.Add(nonce);
+			}
+
+			if (certReq != null && certReq.IsTrue)
+			{
+				v.Add(certReq);
+			}
+
+			if (extensions != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, extensions));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/tsp/TimeStampResp.cs b/crypto/src/asn1/tsp/TimeStampResp.cs
new file mode 100644
index 000000000..f26fb30bd
--- /dev/null
+++ b/crypto/src/asn1/tsp/TimeStampResp.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+	public class TimeStampResp
+		: Asn1Encodable
+	{
+		private readonly PkiStatusInfo	pkiStatusInfo;
+		private readonly ContentInfo	timeStampToken;
+
+		public static TimeStampResp GetInstance(
+			object o)
+		{
+			if (o == null || o is TimeStampResp)
+			{
+				return (TimeStampResp) o;
+			}
+
+			if (o is Asn1Sequence)
+			{
+				return new TimeStampResp((Asn1Sequence) o);
+			}
+
+			throw new ArgumentException(
+				"Unknown object in 'TimeStampResp' factory: " + o.GetType().FullName);
+		}
+
+		private TimeStampResp(
+			Asn1Sequence seq)
+		{
+			this.pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				this.timeStampToken = ContentInfo.GetInstance(seq[1]);
+			}
+		}
+
+		public TimeStampResp(
+			PkiStatusInfo	pkiStatusInfo,
+			ContentInfo		timeStampToken)
+		{
+			this.pkiStatusInfo = pkiStatusInfo;
+			this.timeStampToken = timeStampToken;
+		}
+
+		public PkiStatusInfo Status
+		{
+			get { return pkiStatusInfo; }
+		}
+
+		public ContentInfo TimeStampToken
+		{
+			get { return timeStampToken; }
+		}
+
+		/**
+		 * <pre>
+		 * TimeStampResp ::= SEQUENCE  {
+		 *   status                  PkiStatusInfo,
+		 *   timeStampToken          TimeStampToken     OPTIONAL  }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
+
+			if (timeStampToken != null)
+			{
+				v.Add(timeStampToken);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/util/Asn1Dump.cs b/crypto/src/asn1/util/Asn1Dump.cs
index 43d485500..36b17c8fd 100644
--- a/crypto/src/asn1/util/Asn1Dump.cs
+++ b/crypto/src/asn1/util/Asn1Dump.cs
@@ -10,9 +10,9 @@ namespace Org.BouncyCastle.Asn1.Utilities
 {
     public sealed class Asn1Dump
     {
-		private static readonly string NewLine = Platform.NewLine;
+        private static readonly string NewLine = Platform.NewLine;
 
-		private Asn1Dump()
+        private Asn1Dump()
         {
         }
 
@@ -28,12 +28,12 @@ namespace Org.BouncyCastle.Asn1.Utilities
             string			indent,
             bool			verbose,
             Asn1Object		obj,
-			StringBuilder	buf)
+            StringBuilder	buf)
         {
             if (obj is Asn1Sequence)
             {
-				string tab = indent + Tab;
-				buf.Append(indent);
+                string tab = indent + Tab;
+                buf.Append(indent);
                 if (obj is BerSequence)
                 {
                     buf.Append("BER Sequence");
@@ -49,8 +49,8 @@ namespace Org.BouncyCastle.Asn1.Utilities
 
                 buf.Append(NewLine);
 
-				foreach (Asn1Encodable o in ((Asn1Sequence)obj))
-				{
+                foreach (Asn1Encodable o in ((Asn1Sequence)obj))
+                {
                     if (o == null || o is Asn1Null)
                     {
                         buf.Append(tab);
@@ -66,7 +66,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
             else if (obj is DerTaggedObject)
             {
                 string tab = indent + Tab;
-				buf.Append(indent);
+                buf.Append(indent);
                 if (obj is BerTaggedObject)
                 {
                     buf.Append("BER Tagged [");
@@ -76,19 +76,19 @@ namespace Org.BouncyCastle.Asn1.Utilities
                     buf.Append("Tagged [");
                 }
 
-				DerTaggedObject o = (DerTaggedObject)obj;
+                DerTaggedObject o = (DerTaggedObject)obj;
 
-				buf.Append(((int)o.TagNo).ToString());
+                buf.Append(((int)o.TagNo).ToString());
                 buf.Append(']');
 
-				if (!o.IsExplicit())
+                if (!o.IsExplicit())
                 {
                     buf.Append(" IMPLICIT ");
                 }
 
-				buf.Append(NewLine);
+                buf.Append(NewLine);
 
-				if (o.IsEmpty())
+                if (o.IsEmpty())
                 {
                     buf.Append(tab);
                     buf.Append("EMPTY");
@@ -103,12 +103,12 @@ namespace Org.BouncyCastle.Asn1.Utilities
             {
                 string tab = indent + Tab;
 
-				buf.Append(indent);
+                buf.Append(indent);
                 buf.Append("BER Set");
                 buf.Append(NewLine);
 
-				foreach (Asn1Encodable o in ((Asn1Set)obj))
-				{
+                foreach (Asn1Encodable o in ((Asn1Set)obj))
+                {
                     if (o == null)
                     {
                         buf.Append(tab);
@@ -125,12 +125,12 @@ namespace Org.BouncyCastle.Asn1.Utilities
             {
                 string tab = indent + Tab;
 
-				buf.Append(indent);
+                buf.Append(indent);
                 buf.Append("DER Set");
                 buf.Append(NewLine);
 
-				foreach (Asn1Encodable o in ((Asn1Set)obj))
-				{
+                foreach (Asn1Encodable o in ((Asn1Set)obj))
+                {
                     if (o == null)
                     {
                         buf.Append(tab);
@@ -155,33 +155,33 @@ namespace Org.BouncyCastle.Asn1.Utilities
             {
                 buf.Append(indent + "Integer(" + ((DerInteger)obj).Value + ")" + NewLine);
             }
-			else if (obj is BerOctetString)
-			{
-				byte[] octets = ((Asn1OctetString)obj).GetOctets();
-				string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
-				buf.Append(indent + "BER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
-			}
+            else if (obj is BerOctetString)
+            {
+                byte[] octets = ((Asn1OctetString)obj).GetOctets();
+                string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+                buf.Append(indent + "BER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
+            }
             else if (obj is DerOctetString)
             {
-				byte[] octets = ((Asn1OctetString)obj).GetOctets();
-				string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
-				buf.Append(indent + "DER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
-			}
-			else if (obj is DerBitString)
-			{
-				DerBitString bt = (DerBitString)obj; 
-				byte[] bytes = bt.GetBytes();
-				string extra = verbose ? dumpBinaryDataAsString(indent, bytes) : "";
-				buf.Append(indent + "DER Bit String" + "[" + bytes.Length + ", " + bt.PadBits + "] " + extra + NewLine);
-			}
+                byte[] octets = ((Asn1OctetString)obj).GetOctets();
+                string extra = verbose ? dumpBinaryDataAsString(indent, octets) : "";
+                buf.Append(indent + "DER Octet String" + "[" + octets.Length + "] " + extra + NewLine);
+            }
+            else if (obj is DerBitString)
+            {
+                DerBitString bt = (DerBitString)obj; 
+                byte[] bytes = bt.GetBytes();
+                string extra = verbose ? dumpBinaryDataAsString(indent, bytes) : "";
+                buf.Append(indent + "DER Bit String" + "[" + bytes.Length + ", " + bt.PadBits + "] " + extra + NewLine);
+            }
             else if (obj is DerIA5String)
             {
                 buf.Append(indent + "IA5String(" + ((DerIA5String)obj).GetString() + ") " + NewLine);
             }
-			else if (obj is DerUtf8String)
-			{
-				buf.Append(indent + "UTF8String(" + ((DerUtf8String)obj).GetString() + ") " + NewLine);
-			}
+            else if (obj is DerUtf8String)
+            {
+                buf.Append(indent + "UTF8String(" + ((DerUtf8String)obj).GetString() + ") " + NewLine);
+            }
             else if (obj is DerPrintableString)
             {
                 buf.Append(indent + "PrintableString(" + ((DerPrintableString)obj).GetString() + ") " + NewLine);
@@ -202,14 +202,9 @@ namespace Org.BouncyCastle.Asn1.Utilities
             {
                 buf.Append(indent + "UTCTime(" + ((DerUtcTime)obj).TimeString + ") " + NewLine);
             }
-			else if (obj is DerGeneralizedTime)
-			{
-				buf.Append(indent + "GeneralizedTime(" + ((DerGeneralizedTime)obj).GetTime() + ") " + NewLine);
-			}
-            else if (obj is DerUnknownTag)
+            else if (obj is DerGeneralizedTime)
             {
-				string hex = Hex.ToHexString(((DerUnknownTag)obj).GetData());
-                buf.Append(indent + "Unknown " + ((int)((DerUnknownTag)obj).Tag).ToString("X") + " " + hex + NewLine);
+                buf.Append(indent + "GeneralizedTime(" + ((DerGeneralizedTime)obj).GetTime() + ") " + NewLine);
             }
             else if (obj is BerApplicationSpecific)
             {
@@ -219,32 +214,32 @@ namespace Org.BouncyCastle.Asn1.Utilities
             {
                 buf.Append(outputApplicationSpecific("DER", indent, verbose, (DerApplicationSpecific)obj));
             }
-			else if (obj is DerEnumerated)
-			{
-				DerEnumerated en = (DerEnumerated)obj;
-				buf.Append(indent + "DER Enumerated(" + en.Value + ")" + NewLine);
-			}
-			else if (obj is DerExternal)
-			{
-				DerExternal ext = (DerExternal)obj;
-				buf.Append(indent + "External " + NewLine);
+            else if (obj is DerEnumerated)
+            {
+                DerEnumerated en = (DerEnumerated)obj;
+                buf.Append(indent + "DER Enumerated(" + en.Value + ")" + NewLine);
+            }
+            else if (obj is DerExternal)
+            {
+                DerExternal ext = (DerExternal)obj;
+                buf.Append(indent + "External " + NewLine);
                 string tab = indent + Tab;
 
-				if (ext.DirectReference != null)
-				{
-					buf.Append(tab + "Direct Reference: " + ext.DirectReference.Id + NewLine);
-				}
-				if (ext.IndirectReference != null)
-				{
-					buf.Append(tab + "Indirect Reference: " + ext.IndirectReference.ToString() + NewLine);
-				}
-				if (ext.DataValueDescriptor != null)
-				{
-					AsString(tab, verbose, ext.DataValueDescriptor, buf);
-				}
-				buf.Append(tab + "Encoding: " + ext.Encoding + NewLine);
-				AsString(tab, verbose, ext.ExternalContent, buf);
-			}
+                if (ext.DirectReference != null)
+                {
+                    buf.Append(tab + "Direct Reference: " + ext.DirectReference.Id + NewLine);
+                }
+                if (ext.IndirectReference != null)
+                {
+                    buf.Append(tab + "Indirect Reference: " + ext.IndirectReference.ToString() + NewLine);
+                }
+                if (ext.DataValueDescriptor != null)
+                {
+                    AsString(tab, verbose, ext.DataValueDescriptor, buf);
+                }
+                buf.Append(tab + "Encoding: " + ext.Encoding + NewLine);
+                AsString(tab, verbose, ext.ExternalContent, buf);
+            }
             else
             {
                 buf.Append(indent + obj.ToString() + NewLine);
@@ -267,7 +262,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
                     buf.Append(indent + type + " ApplicationSpecific[" + app.ApplicationTag + "]" + NewLine);
                     foreach (Asn1Encodable ae in s)
                     {
-                    	AsString(indent + Tab, verbose, ae.ToAsn1Object(), buf);
+                        AsString(indent + Tab, verbose, ae.ToAsn1Object(), buf);
                     }
                 }
                 catch (IOException e)
@@ -281,98 +276,98 @@ namespace Org.BouncyCastle.Asn1.Utilities
                 + Hex.ToHexString(app.GetContents()) + ")" + NewLine;
         }
 
-		[Obsolete("Use version accepting Asn1Encodable")]
-		public static string DumpAsString(
+        [Obsolete("Use version accepting Asn1Encodable")]
+        public static string DumpAsString(
             object   obj)
         {
             if (obj is Asn1Encodable)
             {
-				StringBuilder buf = new StringBuilder();
+                StringBuilder buf = new StringBuilder();
                 AsString("", false, ((Asn1Encodable)obj).ToAsn1Object(), buf);
-				return buf.ToString();
+                return buf.ToString();
             }
 
             return "unknown object type " + obj.ToString();
         }
 
-		/**
-		 * dump out a DER object as a formatted string, in non-verbose mode
-		 *
-		 * @param obj the Asn1Encodable to be dumped out.
-		 * @return  the resulting string.
-		 */
-		public static string DumpAsString(
-			Asn1Encodable obj)
-		{
-			return DumpAsString(obj, false);
-		}
+        /**
+         * dump out a DER object as a formatted string, in non-verbose mode
+         *
+         * @param obj the Asn1Encodable to be dumped out.
+         * @return  the resulting string.
+         */
+        public static string DumpAsString(
+            Asn1Encodable obj)
+        {
+            return DumpAsString(obj, false);
+        }
 
-		/**
-		 * Dump out the object as a string
-		 *
-		 * @param obj the Asn1Encodable to be dumped out.
-		 * @param verbose  if true, dump out the contents of octet and bit strings.
-		 * @return  the resulting string.
-		 */
-		public static string DumpAsString(
-			Asn1Encodable	obj,
-			bool			verbose)
-		{
-			StringBuilder buf = new StringBuilder();
-			AsString("", verbose, obj.ToAsn1Object(), buf);
-			return buf.ToString();
-		}
+        /**
+         * Dump out the object as a string
+         *
+         * @param obj the Asn1Encodable to be dumped out.
+         * @param verbose  if true, dump out the contents of octet and bit strings.
+         * @return  the resulting string.
+         */
+        public static string DumpAsString(
+            Asn1Encodable	obj,
+            bool			verbose)
+        {
+            StringBuilder buf = new StringBuilder();
+            AsString("", verbose, obj.ToAsn1Object(), buf);
+            return buf.ToString();
+        }
 
-		private static string dumpBinaryDataAsString(string indent, byte[] bytes)
-		{
-			indent += Tab;
+        private static string dumpBinaryDataAsString(string indent, byte[] bytes)
+        {
+            indent += Tab;
 
-			StringBuilder buf = new StringBuilder(NewLine);
+            StringBuilder buf = new StringBuilder(NewLine);
 
-			for (int i = 0; i < bytes.Length; i += SampleSize)
-			{
-				if (bytes.Length - i > SampleSize)
-				{
-					buf.Append(indent);
-					buf.Append(Hex.ToHexString(bytes, i, SampleSize));
-					buf.Append(Tab);
-					buf.Append(calculateAscString(bytes, i, SampleSize));
-					buf.Append(NewLine);
-				}
-				else
-				{
-					buf.Append(indent);
-					buf.Append(Hex.ToHexString(bytes, i, bytes.Length - i));
-					for (int j = bytes.Length - i; j != SampleSize; j++)
-					{
-						buf.Append("  ");
-					}
-					buf.Append(Tab);
-					buf.Append(calculateAscString(bytes, i, bytes.Length - i));
-					buf.Append(NewLine);
-				}
-			}
+            for (int i = 0; i < bytes.Length; i += SampleSize)
+            {
+                if (bytes.Length - i > SampleSize)
+                {
+                    buf.Append(indent);
+                    buf.Append(Hex.ToHexString(bytes, i, SampleSize));
+                    buf.Append(Tab);
+                    buf.Append(calculateAscString(bytes, i, SampleSize));
+                    buf.Append(NewLine);
+                }
+                else
+                {
+                    buf.Append(indent);
+                    buf.Append(Hex.ToHexString(bytes, i, bytes.Length - i));
+                    for (int j = bytes.Length - i; j != SampleSize; j++)
+                    {
+                        buf.Append("  ");
+                    }
+                    buf.Append(Tab);
+                    buf.Append(calculateAscString(bytes, i, bytes.Length - i));
+                    buf.Append(NewLine);
+                }
+            }
 
-			return buf.ToString();
-		}
+            return buf.ToString();
+        }
 
-		private static string calculateAscString(
-			byte[]	bytes,
-			int		off,
-			int		len)
-		{
-			StringBuilder buf = new StringBuilder();
+        private static string calculateAscString(
+            byte[]	bytes,
+            int		off,
+            int		len)
+        {
+            StringBuilder buf = new StringBuilder();
 
-			for (int i = off; i != off + len; i++)
-			{
-				char c = (char)bytes[i]; 
-				if (c >= ' ' && c <= '~')
-				{
-					buf.Append(c);
-				}
-			}
+            for (int i = off; i != off + len; i++)
+            {
+                char c = (char)bytes[i]; 
+                if (c >= ' ' && c <= '~')
+                {
+                    buf.Append(c);
+                }
+            }
 
-			return buf.ToString();
-		}
+            return buf.ToString();
+        }
     }
 }
diff --git a/crypto/src/asn1/util/Dump.cs b/crypto/src/asn1/util/Dump.cs
index 2712ca1b3..27c87f127 100644
--- a/crypto/src/asn1/util/Dump.cs
+++ b/crypto/src/asn1/util/Dump.cs
@@ -1,4 +1,3 @@
-#if !PORTABLE
 using Org.BouncyCastle.Asn1;
 
 using System;
@@ -23,8 +22,7 @@ namespace Org.BouncyCastle.Asn1.Utilities
                 Console.WriteLine(Asn1Dump.DumpAsString(obj));
             }
 
-			bIn.Dispose();
+			bIn.Close();
         }
     }
 }
-#endif
\ No newline at end of file
diff --git a/crypto/src/asn1/util/FilterStream.cs b/crypto/src/asn1/util/FilterStream.cs
index f277e33e6..2b0494b78 100644
--- a/crypto/src/asn1/util/FilterStream.cs
+++ b/crypto/src/asn1/util/FilterStream.cs
@@ -30,15 +30,10 @@ namespace Org.BouncyCastle.Asn1.Utilities
             get { return s.Position; }
             set { s.Position = value; }
         }
-
-        protected override void Dispose(bool disposing)
+        public override void Close()
         {
-            if (disposing)
-            {
-                s.Dispose();
-            }
+            s.Close();
         }
-
         public override void Flush()
         {
             s.Flush();
diff --git a/crypto/src/asn1/x500/DirectoryString.cs b/crypto/src/asn1/x500/DirectoryString.cs
new file mode 100644
index 000000000..78ecc2663
--- /dev/null
+++ b/crypto/src/asn1/x500/DirectoryString.cs
@@ -0,0 +1,75 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X500
+{
+	public class DirectoryString
+		: Asn1Encodable, IAsn1Choice, IAsn1String
+	{
+		private readonly DerStringBase str;
+
+		public static DirectoryString GetInstance(
+			object obj)
+		{
+			if (obj is DirectoryString)
+			{
+				return (DirectoryString) obj;
+			}
+
+			if (obj is DerStringBase)
+			{
+				if (obj is DerT61String
+					|| obj is DerPrintableString
+					|| obj is DerUniversalString
+					|| obj is DerUtf8String
+					|| obj is DerBmpString)
+				{
+					return new DirectoryString((DerStringBase) obj);
+				}
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static DirectoryString GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			if (!isExplicit)
+				throw new ArgumentException("choice item must be explicitly tagged");
+
+			return GetInstance(obj.GetObject());
+		}
+
+		private DirectoryString(
+			DerStringBase str)
+		{
+			this.str = str;
+		}
+
+		public DirectoryString(
+			string str)
+		{
+			this.str = new DerUtf8String(str);
+		}
+
+		public string GetString()
+		{
+			return str.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 override Asn1Object ToAsn1Object()
+		{
+			return str.ToAsn1Object();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/AccessDescription.cs b/crypto/src/asn1/x509/AccessDescription.cs
new file mode 100644
index 000000000..09b5b5920
--- /dev/null
+++ b/crypto/src/asn1/x509/AccessDescription.cs
@@ -0,0 +1,83 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * The AccessDescription object.
+	 * <pre>
+	 * AccessDescription  ::=  SEQUENCE {
+	 *       accessMethod          OBJECT IDENTIFIER,
+	 *       accessLocation        GeneralName  }
+	 * </pre>
+	 */
+	public class AccessDescription
+		: Asn1Encodable
+	{
+		public readonly static DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier("1.3.6.1.5.5.7.48.2");
+		public readonly static DerObjectIdentifier IdADOcsp = new DerObjectIdentifier("1.3.6.1.5.5.7.48.1");
+
+		private readonly DerObjectIdentifier accessMethod;
+		private readonly GeneralName accessLocation;
+
+		public static AccessDescription GetInstance(
+			object obj)
+		{
+			if (obj is AccessDescription)
+				return (AccessDescription) obj;
+
+			if (obj is Asn1Sequence)
+				return new AccessDescription((Asn1Sequence) obj);
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AccessDescription(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("wrong number of elements in sequence");
+
+			accessMethod = DerObjectIdentifier.GetInstance(seq[0]);
+			accessLocation = GeneralName.GetInstance(seq[1]);
+		}
+
+		/**
+		 * create an AccessDescription with the oid and location provided.
+		 */
+		public AccessDescription(
+			DerObjectIdentifier	oid,
+			GeneralName			location)
+		{
+			accessMethod = oid;
+			accessLocation = location;
+		}
+
+		/**
+		 *
+		 * @return the access method.
+		 */
+		public DerObjectIdentifier AccessMethod
+		{
+			get { return accessMethod; }
+		}
+
+		/**
+		 *
+		 * @return the access location
+		 */
+		public GeneralName AccessLocation
+		{
+			get { return accessLocation; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(accessMethod, accessLocation);
+		}
+
+		public override string ToString()
+		{
+			return "AccessDescription: Oid(" + this.accessMethod.Id + ")";
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/AlgorithmIdentifier.cs b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
index caf9e77c9..4ed3a400d 100644
--- a/crypto/src/asn1/x509/AlgorithmIdentifier.cs
+++ b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
@@ -7,80 +7,79 @@ namespace Org.BouncyCastle.Asn1.X509
     {
         private readonly DerObjectIdentifier	objectID;
         private readonly Asn1Encodable			parameters;
-		private readonly bool					parametersDefined;
+        private readonly bool					parametersDefined;
 
-		public static AlgorithmIdentifier GetInstance(
+        public static AlgorithmIdentifier GetInstance(
             Asn1TaggedObject	obj,
             bool				explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static AlgorithmIdentifier GetInstance(
+        public static AlgorithmIdentifier GetInstance(
             object obj)
         {
             if (obj == null || obj is AlgorithmIdentifier)
                 return (AlgorithmIdentifier) obj;
 
-			if (obj is DerObjectIdentifier)
+            // TODO: delete
+            if (obj is DerObjectIdentifier)
                 return new AlgorithmIdentifier((DerObjectIdentifier) obj);
 
-			if (obj is string)
+            // TODO: delete
+            if (obj is string)
                 return new AlgorithmIdentifier((string) obj);
 
-			if (obj is Asn1Sequence)
-                return new AlgorithmIdentifier((Asn1Sequence) obj);
-
-			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
-		}
+            return new AlgorithmIdentifier(Asn1Sequence.GetInstance(obj));
+        }
 
-		public AlgorithmIdentifier(
+        public AlgorithmIdentifier(
             DerObjectIdentifier objectID)
         {
             this.objectID = objectID;
         }
 
-		public AlgorithmIdentifier(
+        public AlgorithmIdentifier(
             string objectID)
         {
             this.objectID = new DerObjectIdentifier(objectID);
         }
 
-		public AlgorithmIdentifier(
+        public AlgorithmIdentifier(
             DerObjectIdentifier	objectID,
             Asn1Encodable		parameters)
         {
             this.objectID = objectID;
             this.parameters = parameters;
-			this.parametersDefined = true;
+            this.parametersDefined = true;
         }
 
-		internal AlgorithmIdentifier(
+        internal AlgorithmIdentifier(
             Asn1Sequence seq)
         {
-			if (seq.Count < 1 || seq.Count > 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
+            if (seq.Count < 1 || seq.Count > 2)
+                throw new ArgumentException("Bad sequence size: " + seq.Count);
 
-			this.objectID = DerObjectIdentifier.GetInstance(seq[0]);
-			this.parametersDefined = (seq.Count == 2);
+            this.objectID = DerObjectIdentifier.GetInstance(seq[0]);
+            this.parametersDefined = (seq.Count == 2);
 
-			if (parametersDefined)
+            if (parametersDefined)
             {
                 this.parameters = seq[1];
             }
         }
 
-		public virtual DerObjectIdentifier ObjectID
-		{
-			get { return objectID; }
-		}
+        public virtual DerObjectIdentifier ObjectID
+        {
+            get { return objectID; }
+        }
 
-		public Asn1Encodable Parameters
-		{
-			get { return parameters; }
-		}
+        public Asn1Encodable Parameters
+        {
+            get { return parameters; }
+        }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *      AlgorithmIdentifier ::= Sequence {
@@ -90,21 +89,21 @@ namespace Org.BouncyCastle.Asn1.X509
          */
         public override Asn1Object ToAsn1Object()
         {
-			Asn1EncodableVector v = new Asn1EncodableVector(objectID);
-
-			if (parametersDefined)
-			{
-				if (parameters != null)
-				{
-					v.Add(parameters);
-				}
-				else
-				{
-					v.Add(DerNull.Instance);
-				}
-			}
-
-			return new DerSequence(v);
+            Asn1EncodableVector v = new Asn1EncodableVector(objectID);
+
+            if (parametersDefined)
+            {
+                if (parameters != null)
+                {
+                    v.Add(parameters);
+                }
+                else
+                {
+                    v.Add(DerNull.Instance);
+                }
+            }
+
+            return new DerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/x509/AttCertIssuer.cs b/crypto/src/asn1/x509/AttCertIssuer.cs
new file mode 100644
index 000000000..e9314fa92
--- /dev/null
+++ b/crypto/src/asn1/x509/AttCertIssuer.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttCertIssuer
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal readonly Asn1Encodable	obj;
+        internal readonly Asn1Object	choiceObj;
+
+		public static AttCertIssuer GetInstance(
+			object obj)
+		{
+			if (obj is AttCertIssuer)
+			{
+				return (AttCertIssuer)obj;
+			}
+			else if (obj is V2Form)
+			{
+				return new AttCertIssuer(V2Form.GetInstance(obj));
+			}
+			else if (obj is GeneralNames)
+			{
+				return new AttCertIssuer((GeneralNames)obj);
+			}
+			else if (obj is Asn1TaggedObject)
+			{
+				return new AttCertIssuer(V2Form.GetInstance((Asn1TaggedObject)obj, false));
+			}
+			else if (obj is Asn1Sequence)
+			{
+				return new AttCertIssuer(GeneralNames.GetInstance(obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static AttCertIssuer GetInstance(
+			Asn1TaggedObject	obj,
+			bool				isExplicit)
+		{
+			return GetInstance(obj.GetObject()); // must be explictly tagged
+		}
+
+		/// <summary>
+		/// Don't use this one if you are trying to be RFC 3281 compliant.
+		/// Use it for v1 attribute certificates only.
+		/// </summary>
+		/// <param name="names">Our GeneralNames structure</param>
+		public AttCertIssuer(
+			GeneralNames names)
+		{
+			obj = names;
+			choiceObj = obj.ToAsn1Object();
+		}
+
+		public AttCertIssuer(
+            V2Form v2Form)
+        {
+            obj = v2Form;
+            choiceObj = new DerTaggedObject(false, 0, obj);
+        }
+
+		public Asn1Encodable Issuer
+		{
+			get { 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 override Asn1Object ToAsn1Object()
+        {
+            return choiceObj;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttCertValidityPeriod.cs b/crypto/src/asn1/x509/AttCertValidityPeriod.cs
new file mode 100644
index 000000000..7f86cd0b8
--- /dev/null
+++ b/crypto/src/asn1/x509/AttCertValidityPeriod.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttCertValidityPeriod
+        : Asn1Encodable
+    {
+        private readonly DerGeneralizedTime	notBeforeTime;
+        private readonly DerGeneralizedTime	notAfterTime;
+
+		public static AttCertValidityPeriod GetInstance(
+            object obj)
+        {
+            if (obj is AttCertValidityPeriod || obj == null)
+            {
+                return (AttCertValidityPeriod) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttCertValidityPeriod((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static AttCertValidityPeriod GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		private AttCertValidityPeriod(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			notBeforeTime = DerGeneralizedTime.GetInstance(seq[0]);
+			notAfterTime = DerGeneralizedTime.GetInstance(seq[1]);
+        }
+
+		public AttCertValidityPeriod(
+            DerGeneralizedTime	notBeforeTime,
+            DerGeneralizedTime	notAfterTime)
+        {
+            this.notBeforeTime = notBeforeTime;
+            this.notAfterTime = notAfterTime;
+        }
+
+		public DerGeneralizedTime NotBeforeTime
+		{
+			get { return notBeforeTime; }
+		}
+
+		public DerGeneralizedTime NotAfterTime
+		{
+			get { return notAfterTime; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttCertValidityPeriod  ::= Sequence {
+         *       notBeforeTime  GeneralizedTime,
+         *       notAfterTime   GeneralizedTime
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(notBeforeTime, notAfterTime);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/Attribute.cs b/crypto/src/asn1/x509/Attribute.cs
new file mode 100644
index 000000000..d26db93e9
--- /dev/null
+++ b/crypto/src/asn1/x509/Attribute.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeX509
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	attrType;
+        private readonly Asn1Set				attrValues;
+
+		/**
+         * return an Attr object from the given object.
+         *
+         * @param o the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static AttributeX509 GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is AttributeX509)
+            {
+                return (AttributeX509) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttributeX509((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AttributeX509(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			attrType = DerObjectIdentifier.GetInstance(seq[0]);
+			attrValues = Asn1Set.GetInstance(seq[1]);
+        }
+
+		public AttributeX509(
+            DerObjectIdentifier	attrType,
+            Asn1Set				attrValues)
+        {
+            this.attrType = attrType;
+            this.attrValues = attrValues;
+        }
+
+		public DerObjectIdentifier AttrType
+		{
+			get { return attrType; }
+		}
+
+		public Asn1Encodable[] GetAttributeValues()
+		{
+			return attrValues.ToArray();
+		}
+
+		public Asn1Set AttrValues
+		{
+			get { return attrValues; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Attr ::= Sequence {
+         *     attrType OBJECT IDENTIFIER,
+         *     attrValues Set OF AttributeValue
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(attrType, attrValues);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttributeCertificate.cs b/crypto/src/asn1/x509/AttributeCertificate.cs
new file mode 100644
index 000000000..5f85910da
--- /dev/null
+++ b/crypto/src/asn1/x509/AttributeCertificate.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeCertificate
+        : Asn1Encodable
+    {
+        private readonly AttributeCertificateInfo	acinfo;
+        private readonly AlgorithmIdentifier		signatureAlgorithm;
+        private readonly DerBitString				signatureValue;
+
+		/**
+         * @param obj
+         * @return
+         */
+        public static AttributeCertificate GetInstance(
+			object obj)
+        {
+            if (obj is AttributeCertificate)
+                return (AttributeCertificate) obj;
+
+			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;
+        }
+
+		private AttributeCertificate(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			this.acinfo = AttributeCertificateInfo.GetInstance(seq[0]);
+            this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+            this.signatureValue = DerBitString.GetInstance(seq[2]);
+        }
+
+		public AttributeCertificateInfo ACInfo
+		{
+			get { return acinfo; }
+		}
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return signatureAlgorithm; }
+		}
+
+		public DerBitString SignatureValue
+		{
+			get { return signatureValue; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  AttributeCertificate ::= Sequence {
+         *       acinfo               AttributeCertificateInfo,
+         *       signatureAlgorithm   AlgorithmIdentifier,
+         *       signatureValue       BIT STRING
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(acinfo, signatureAlgorithm, signatureValue);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttributeCertificateInfo.cs b/crypto/src/asn1/x509/AttributeCertificateInfo.cs
new file mode 100644
index 000000000..dcef3d472
--- /dev/null
+++ b/crypto/src/asn1/x509/AttributeCertificateInfo.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeCertificateInfo
+        : Asn1Encodable
+    {
+        internal readonly DerInteger			version;
+        internal readonly Holder				holder;
+        internal readonly AttCertIssuer			issuer;
+        internal readonly AlgorithmIdentifier	signature;
+        internal readonly DerInteger			serialNumber;
+        internal readonly AttCertValidityPeriod	attrCertValidityPeriod;
+        internal readonly Asn1Sequence			attributes;
+        internal readonly DerBitString			issuerUniqueID;
+        internal readonly X509Extensions		extensions;
+
+		public static AttributeCertificateInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+		public static AttributeCertificateInfo GetInstance(
+            object obj)
+        {
+            if (obj is AttributeCertificateInfo)
+            {
+                return (AttributeCertificateInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AttributeCertificateInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private AttributeCertificateInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 7 || seq.Count > 9)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.version = DerInteger.GetInstance(seq[0]);
+            this.holder = Holder.GetInstance(seq[1]);
+            this.issuer = AttCertIssuer.GetInstance(seq[2]);
+            this.signature = AlgorithmIdentifier.GetInstance(seq[3]);
+            this.serialNumber = DerInteger.GetInstance(seq[4]);
+            this.attrCertValidityPeriod = AttCertValidityPeriod.GetInstance(seq[5]);
+            this.attributes = Asn1Sequence.GetInstance(seq[6]);
+
+			for (int i = 7; i < seq.Count; i++)
+            {
+                Asn1Encodable obj = (Asn1Encodable) seq[i];
+
+				if (obj is DerBitString)
+                {
+                    this.issuerUniqueID = DerBitString.GetInstance(seq[i]);
+                }
+                else if (obj is Asn1Sequence || obj is X509Extensions)
+                {
+                    this.extensions = X509Extensions.GetInstance(seq[i]);
+                }
+            }
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public Holder Holder
+		{
+			get { return holder; }
+		}
+
+		public AttCertIssuer Issuer
+		{
+			get { return issuer; }
+		}
+
+		public AlgorithmIdentifier Signature
+		{
+			get { return signature; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public AttCertValidityPeriod AttrCertValidityPeriod
+		{
+			get { return attrCertValidityPeriod; }
+		}
+
+		public Asn1Sequence Attributes
+		{
+			get { return attributes; }
+		}
+
+		public DerBitString IssuerUniqueID
+		{
+			get { return issuerUniqueID; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get { 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 Attr,
+         *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+         *       extensions           Extensions OPTIONAL
+         *  }
+         *
+         *  AttCertVersion ::= Integer { v2(1) }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, holder, issuer, signature, serialNumber,
+				attrCertValidityPeriod, attributes);
+
+			if (issuerUniqueID != null)
+            {
+                v.Add(issuerUniqueID);
+            }
+
+			if (extensions != null)
+            {
+                v.Add(extensions);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/AttributeTable.cs b/crypto/src/asn1/x509/AttributeTable.cs
index 87b112f01..ffe0ea935 100644
--- a/crypto/src/asn1/x509/AttributeTable.cs
+++ b/crypto/src/asn1/x509/AttributeTable.cs
@@ -16,7 +16,7 @@ namespace Org.BouncyCastle.Asn1.X509
             this.attributes = Platform.CreateHashtable(attrs);
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete]
         public AttributeTable(
             Hashtable attrs)
@@ -25,7 +25,7 @@ namespace Org.BouncyCastle.Asn1.X509
         }
 #endif
 
-        public AttributeTable(
+		public AttributeTable(
             Asn1EncodableVector v)
         {
             this.attributes = Platform.CreateHashtable(v.Count);
@@ -57,7 +57,7 @@ namespace Org.BouncyCastle.Asn1.X509
             return (AttributeX509) attributes[oid];
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete("Use 'ToDictionary' instead")]
 		public Hashtable ToHashtable()
         {
diff --git a/crypto/src/asn1/x509/AuthorityInformationAccess.cs b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
index 3eeba8cd2..9329e2b98 100644
--- a/crypto/src/asn1/x509/AuthorityInformationAccess.cs
+++ b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
@@ -7,99 +7,92 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.X509
 {
-	/**
-	 * The AuthorityInformationAccess object.
-	 * <pre>
-	 * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
-	 *
-	 * AuthorityInfoAccessSyntax  ::=
-	 *      Sequence SIZE (1..MAX) OF AccessDescription
-	 * AccessDescription  ::=  Sequence {
-	 *       accessMethod          OBJECT IDENTIFIER,
-	 *       accessLocation        GeneralName  }
-	 *
-	 * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
-	 * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
-	 * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
-	 * </pre>
-	 */
-	public class AuthorityInformationAccess
-		: Asn1Encodable
-	{
-		private readonly AccessDescription[] descriptions;
-
-		public static AuthorityInformationAccess GetInstance(
-			object obj)
-		{
-			if (obj is AuthorityInformationAccess)
-				return (AuthorityInformationAccess) obj;
-
-			if (obj is Asn1Sequence)
-				return new AuthorityInformationAccess((Asn1Sequence) obj);
-
-			if (obj is X509Extension)
-				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
-
-			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
-		}
-
-		private AuthorityInformationAccess(
-			Asn1Sequence seq)
-		{
-			if (seq.Count < 1)
-				throw new ArgumentException("sequence may not be empty");
-
-			this.descriptions = new AccessDescription[seq.Count];
-
-			for (int i = 0; i < seq.Count; ++i)
-			{
-				descriptions[i] = AccessDescription.GetInstance(seq[i]);
-			}
-		}
-
-		/**
-		 * create an AuthorityInformationAccess with the oid and location provided.
-		 */
-		[Obsolete("Use version taking an AccessDescription instead")]
-		public AuthorityInformationAccess(
-			DerObjectIdentifier	oid,
-			GeneralName			location)
-		{
-			this.descriptions = new AccessDescription[]{ new AccessDescription(oid, location) };
-		}
-
-		public AuthorityInformationAccess(
-			AccessDescription description)
-		{
-			this.descriptions = new AccessDescription[]{ description };
-		}
-
-		public AccessDescription[] GetAccessDescriptions()
-		{
-			return (AccessDescription[]) descriptions.Clone();
-		}
-
-		public override Asn1Object ToAsn1Object()
-		{
-			return new DerSequence(descriptions);
-		}
-
-		public override string ToString()
-		{
-			StringBuilder buf = new StringBuilder();
-			string sep = Platform.NewLine;
-
-			buf.Append("AuthorityInformationAccess:");
-			buf.Append(sep);
-
-			foreach (AccessDescription description in descriptions)
-			{
-				buf.Append("    ");
-				buf.Append(description);
-				buf.Append(sep);
-			}
-
-			return buf.ToString();
-		}
-	}
+    /**
+     * The AuthorityInformationAccess object.
+     * <pre>
+     * id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+     *
+     * AuthorityInfoAccessSyntax  ::=
+     *      Sequence SIZE (1..MAX) OF AccessDescription
+     * AccessDescription  ::=  Sequence {
+     *       accessMethod          OBJECT IDENTIFIER,
+     *       accessLocation        GeneralName  }
+     *
+     * id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+     * id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+     * id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
+     * </pre>
+     */
+    public class AuthorityInformationAccess
+        : Asn1Encodable
+    {
+        private readonly AccessDescription[] descriptions;
+
+        public static AuthorityInformationAccess GetInstance(object obj)
+        {
+            if (obj is AuthorityInformationAccess)
+                return (AuthorityInformationAccess)obj;
+            if (obj == null)
+                return null;
+            return new AuthorityInformationAccess(Asn1Sequence.GetInstance(obj));
+        }
+
+        private AuthorityInformationAccess(
+            Asn1Sequence seq)
+        {
+            if (seq.Count < 1)
+                throw new ArgumentException("sequence may not be empty");
+
+            this.descriptions = new AccessDescription[seq.Count];
+
+            for (int i = 0; i < seq.Count; ++i)
+            {
+                descriptions[i] = AccessDescription.GetInstance(seq[i]);
+            }
+        }
+
+        public AuthorityInformationAccess(
+            AccessDescription description)
+        {
+            this.descriptions = new AccessDescription[]{ description };
+        }
+
+        /**
+         * create an AuthorityInformationAccess with the oid and location provided.
+         */
+        public AuthorityInformationAccess(DerObjectIdentifier oid, GeneralName location)
+            : this(new AccessDescription(oid, location))
+        {
+        }
+
+        public AccessDescription[] GetAccessDescriptions()
+        {
+            return (AccessDescription[])descriptions.Clone();
+        }
+
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(descriptions);
+        }
+
+        public override string ToString()
+        {
+            //return "AuthorityInformationAccess: Oid(" + this.descriptions[0].AccessMethod.Id + ")";
+
+            StringBuilder buf = new StringBuilder();
+            string sep = Platform.NewLine;
+
+            buf.Append("AuthorityInformationAccess:");
+            buf.Append(sep);
+
+            foreach (AccessDescription description in descriptions)
+            {
+                buf.Append("    ");
+                buf.Append(description);
+                buf.Append(sep);
+            }
+
+            return buf.ToString();
+        }
+    }
 }
diff --git a/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs b/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
new file mode 100644
index 000000000..12ccacfc7
--- /dev/null
+++ b/crypto/src/asn1/x509/AuthorityKeyIdentifier.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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
+        : Asn1Encodable
+    {
+        internal readonly Asn1OctetString	keyidentifier;
+        internal readonly GeneralNames		certissuer;
+        internal readonly DerInteger		certserno;
+
+		public static AuthorityKeyIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static AuthorityKeyIdentifier GetInstance(
+            object obj)
+        {
+            if (obj is AuthorityKeyIdentifier)
+            {
+                return (AuthorityKeyIdentifier) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new AuthorityKeyIdentifier((Asn1Sequence) obj);
+            }
+
+	        if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		protected internal AuthorityKeyIdentifier(
+            Asn1Sequence seq)
+        {
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+                {
+					case 0:
+						this.keyidentifier = Asn1OctetString.GetInstance(o, false);
+						break;
+					case 1:
+						this.certissuer = GeneralNames.GetInstance(o, false);
+						break;
+					case 2:
+						this.certserno = DerInteger.GetInstance(o, false);
+						break;
+					default:
+						throw new ArgumentException("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)
+        {
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(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)
+        {
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+
+			this.keyidentifier = new DerOctetString(resBuf);
+            this.certissuer = name;
+            this.certserno = new DerInteger(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.ToAsn1Object());
+			this.certserno = new DerInteger(serialNumber);
+		}
+
+		/**
+		 * create an AuthorityKeyIdentifier with a precomputed 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.ToAsn1Object());
+			this.certserno = new DerInteger(serialNumber);
+		}
+
+		public byte[] GetKeyIdentifier()
+        {
+			return keyidentifier == null ? null : keyidentifier.GetOctets();
+        }
+
+		public GeneralNames AuthorityCertIssuer
+		{
+			get { return certissuer; }
+		}
+
+		public BigInteger AuthorityCertSerialNumber
+        {
+            get { return certserno == null ? null : certserno.Value; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            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 override string ToString()
+        {
+            return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.GetOctets() + ")");
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/BasicConstraints.cs b/crypto/src/asn1/x509/BasicConstraints.cs
new file mode 100644
index 000000000..522cb61cc
--- /dev/null
+++ b/crypto/src/asn1/x509/BasicConstraints.cs
@@ -0,0 +1,133 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class BasicConstraints
+        : Asn1Encodable
+    {
+        private readonly DerBoolean	cA;
+        private readonly DerInteger	pathLenConstraint;
+
+		public static BasicConstraints GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static BasicConstraints GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is BasicConstraints)
+            {
+                return (BasicConstraints) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new BasicConstraints((Asn1Sequence) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private BasicConstraints(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 0)
+			{
+				if (seq[0] is DerBoolean)
+				{
+					this.cA = DerBoolean.GetInstance(seq[0]);
+				}
+				else
+				{
+					this.pathLenConstraint = DerInteger.GetInstance(seq[0]);
+				}
+
+				if (seq.Count > 1)
+				{
+					if (this.cA == null)
+						throw new ArgumentException("wrong sequence in constructor", "seq");
+
+					this.pathLenConstraint = DerInteger.GetInstance(seq[1]);
+				}
+			}
+        }
+
+		public BasicConstraints(
+            bool cA)
+        {
+			if (cA)
+			{
+				this.cA = DerBoolean.True;
+			}
+        }
+
+		/**
+         * create a cA=true object for the given path length constraint.
+         *
+         * @param pathLenConstraint
+         */
+        public BasicConstraints(
+            int pathLenConstraint)
+        {
+            this.cA = DerBoolean.True;
+            this.pathLenConstraint = new DerInteger(pathLenConstraint);
+        }
+
+		public bool IsCA()
+        {
+            return cA != null && cA.IsTrue;
+        }
+
+		public BigInteger PathLenConstraint
+        {
+            get { return pathLenConstraint == null ? null : pathLenConstraint.Value; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * BasicConstraints := Sequence {
+         *    cA                  Boolean DEFAULT FALSE,
+         *    pathLenConstraint   Integer (0..MAX) OPTIONAL
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            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 override string ToString()
+        {
+            if (pathLenConstraint == null)
+            {
+				return "BasicConstraints: isCa(" + this.IsCA() + ")";
+            }
+
+			return "BasicConstraints: isCa(" + this.IsCA() + "), pathLenConstraint = " + pathLenConstraint.Value;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/CRLDistPoint.cs b/crypto/src/asn1/x509/CRLDistPoint.cs
new file mode 100644
index 000000000..2b5c19798
--- /dev/null
+++ b/crypto/src/asn1/x509/CRLDistPoint.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class CrlDistPoint
+        : Asn1Encodable
+    {
+        internal readonly Asn1Sequence seq;
+
+		public static CrlDistPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static CrlDistPoint GetInstance(
+            object obj)
+        {
+            if (obj is CrlDistPoint || obj == null)
+            {
+                return (CrlDistPoint) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new CrlDistPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		private CrlDistPoint(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+        }
+
+		public CrlDistPoint(
+            DistributionPoint[] points)
+        {
+			seq = new DerSequence(points);
+        }
+
+		/**
+         * Return the distribution points making up the sequence.
+         *
+         * @return DistributionPoint[]
+         */
+        public DistributionPoint[] GetDistributionPoints()
+        {
+            DistributionPoint[] dp = new DistributionPoint[seq.Count];
+
+			for (int i = 0; i != seq.Count; ++i)
+            {
+                dp[i] = DistributionPoint.GetInstance(seq[i]);
+            }
+
+			return dp;
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			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/crypto/src/asn1/x509/CRLNumber.cs b/crypto/src/asn1/x509/CRLNumber.cs
new file mode 100644
index 000000000..d744416a5
--- /dev/null
+++ b/crypto/src/asn1/x509/CRLNumber.cs
@@ -0,0 +1,30 @@
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The CRLNumber object.
+     * <pre>
+     * CRLNumber::= Integer(0..MAX)
+     * </pre>
+     */
+    public class CrlNumber
+        : DerInteger
+    {
+        public CrlNumber(
+			BigInteger number)
+			: base(number)
+        {
+        }
+
+		public BigInteger Number
+		{
+			get { return PositiveValue; }
+		}
+
+		public override string ToString()
+		{
+			return "CRLNumber: " + Number;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/CRLReason.cs b/crypto/src/asn1/x509/CRLReason.cs
new file mode 100644
index 000000000..e8eb53a59
--- /dev/null
+++ b/crypto/src/asn1/x509/CRLReason.cs
@@ -0,0 +1,61 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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
+        : DerEnumerated
+    {
+        public const int Unspecified = 0;
+        public const int KeyCompromise = 1;
+        public const int CACompromise = 2;
+        public const int AffiliationChanged = 3;
+        public const int Superseded = 4;
+        public const int CessationOfOperation  = 5;
+        public const int CertificateHold = 6;
+		// 7 -> Unknown
+        public const int RemoveFromCrl = 8;
+        public const int PrivilegeWithdrawn = 9;
+        public const int AACompromise = 10;
+
+		private static readonly string[] ReasonString = new string[]
+		{
+			"Unspecified", "KeyCompromise", "CACompromise", "AffiliationChanged",
+			"Superseded", "CessationOfOperation", "CertificateHold", "Unknown",
+			"RemoveFromCrl", "PrivilegeWithdrawn", "AACompromise"
+		};
+
+		public CrlReason(
+			int reason)
+			: base(reason)
+        {
+        }
+
+		public CrlReason(
+			DerEnumerated reason)
+			: base(reason.Value.IntValue)
+        {
+        }
+
+		public override string ToString()
+		{
+			int reason = Value.IntValue;
+			string str = (reason < 0 || reason > 10) ? "Invalid" : ReasonString[reason];
+			return "CrlReason: " + str;
+		}    
+	}
+}
diff --git a/crypto/src/asn1/x509/CertPolicyId.cs b/crypto/src/asn1/x509/CertPolicyId.cs
new file mode 100644
index 000000000..11cebcdd7
--- /dev/null
+++ b/crypto/src/asn1/x509/CertPolicyId.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * CertPolicyId, used in the CertificatePolicies and PolicyMappings
+     * X509V3 Extensions.
+     *
+     * <pre>
+     *     CertPolicyId ::= OBJECT IDENTIFIER
+     * </pre>
+     */
+     public class CertPolicyID
+		 : DerObjectIdentifier
+    {
+       public CertPolicyID(
+		   string id)
+		   : base(id)
+       {
+       }
+    }
+}
diff --git a/crypto/src/asn1/x509/CertificateList.cs b/crypto/src/asn1/x509/CertificateList.cs
new file mode 100644
index 000000000..0412e0816
--- /dev/null
+++ b/crypto/src/asn1/x509/CertificateList.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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
+        : Asn1Encodable
+    {
+        private readonly TbsCertificateList	tbsCertList;
+        private readonly AlgorithmIdentifier sigAlgID;
+        private readonly DerBitString sig;
+
+		public static CertificateList GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static CertificateList GetInstance(
+            object obj)
+        {
+            if (obj is CertificateList)
+                return (CertificateList) obj;
+
+			if (obj != null)
+				return new CertificateList(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		private CertificateList(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("sequence wrong size for CertificateList", "seq");
+
+			tbsCertList = TbsCertificateList.GetInstance(seq[0]);
+			sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+			sig = DerBitString.GetInstance(seq[2]);
+        }
+
+		public TbsCertificateList TbsCertList
+		{
+			get { return tbsCertList; }
+		}
+
+		public CrlEntry[] GetRevokedCertificates()
+        {
+            return tbsCertList.GetRevokedCertificates();
+        }
+
+		public IEnumerable GetRevokedCertificateEnumeration()
+		{
+			return tbsCertList.GetRevokedCertificateEnumeration();
+		}
+
+		public AlgorithmIdentifier SignatureAlgorithm
+		{
+			get { return sigAlgID; }
+		}
+
+		public DerBitString Signature
+		{
+			get { return sig; }
+		}
+
+		public int Version
+		{
+			get { return tbsCertList.Version; }
+		}
+
+		public X509Name Issuer
+		{
+			get { return tbsCertList.Issuer; }
+		}
+
+		public Time ThisUpdate
+		{
+			get { return tbsCertList.ThisUpdate; }
+		}
+
+		public Time NextUpdate
+		{
+			get { return tbsCertList.NextUpdate; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(tbsCertList, sigAlgID, sig);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/CertificatePair.cs b/crypto/src/asn1/x509/CertificatePair.cs
new file mode 100644
index 000000000..8baa64719
--- /dev/null
+++ b/crypto/src/asn1/x509/CertificatePair.cs
@@ -0,0 +1,160 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	* This class helps to support crossCerfificatePairs in a LDAP directory
+	* according RFC 2587
+	*
+	* <pre>
+	*     crossCertificatePairATTRIBUTE::={
+	*       WITH SYNTAX   CertificatePair
+	*       EQUALITY MATCHING RULE certificatePairExactMatch
+	*       ID joint-iso-ccitt(2) ds(5) attributeType(4) crossCertificatePair(40)}
+	* </pre>
+	*
+	* <blockquote> The forward elements of the crossCertificatePair attribute of a
+	* CA's directory entry shall be used to store all, except self-issued
+	* certificates issued to this CA. Optionally, the reverse elements of the
+	* crossCertificatePair attribute, of a CA's directory entry may contain a
+	* subset of certificates issued by this CA to other CAs. When both the forward
+	* and the reverse elements are present in a single attribute value, issuer name
+	* in one certificate shall match the subject name in the other and vice versa,
+	* and the subject public key in one certificate shall be capable of verifying
+	* the digital signature on the other certificate and vice versa.
+	*
+	* When a reverse element is present, the forward element value and the reverse
+	* element value need not be stored in the same attribute value; in other words,
+	* they can be stored in either a single attribute value or two attribute
+	* values. </blockquote>
+	*
+	* <pre>
+	*       CertificatePair ::= SEQUENCE {
+	*         forward		[0]	Certificate OPTIONAL,
+	*         reverse		[1]	Certificate OPTIONAL,
+	*         -- at least one of the pair shall be present -- }
+	* </pre>
+	*/
+	public class CertificatePair
+		: Asn1Encodable
+	{
+		private X509CertificateStructure forward, reverse;
+
+		public static CertificatePair GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is CertificatePair)
+			{
+				return (CertificatePair) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new CertificatePair((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type CertificatePair:
+		* <p/>
+		* <pre>
+		*       CertificatePair ::= SEQUENCE {
+		*         forward		[0]	Certificate OPTIONAL,
+		*         reverse		[1]	Certificate OPTIONAL,
+		*         -- at least one of the pair shall be present -- }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private CertificatePair(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 1 && seq.Count != 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+			}
+
+			foreach (object obj in seq)
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(obj);
+				if (o.TagNo == 0)
+				{
+					forward = X509CertificateStructure.GetInstance(o, true);
+				}
+				else if (o.TagNo == 1)
+				{
+					reverse = X509CertificateStructure.GetInstance(o, true);
+				}
+				else
+				{
+					throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param forward Certificates issued to this CA.
+		* @param reverse Certificates issued by this CA to other CAs.
+		*/
+		public CertificatePair(
+			X509CertificateStructure	forward,
+			X509CertificateStructure	reverse)
+		{
+			this.forward = forward;
+			this.reverse = reverse;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       CertificatePair ::= SEQUENCE {
+		*         forward		[0]	Certificate OPTIONAL,
+		*         reverse		[1]	Certificate OPTIONAL,
+		*         -- at least one of the pair shall be present -- }
+		* </pre>
+		*
+		* @return a DERObject
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+
+			if (forward != null)
+			{
+				vec.Add(new DerTaggedObject(0, forward));
+			}
+
+			if (reverse != null)
+			{
+				vec.Add(new DerTaggedObject(1, reverse));
+			}
+
+			return new DerSequence(vec);
+		}
+
+		/**
+		* @return Returns the forward.
+		*/
+		public X509CertificateStructure Forward
+		{
+			get { return forward; }
+		}
+
+		/**
+		* @return Returns the reverse.
+		*/
+		public X509CertificateStructure Reverse
+		{
+			get { return reverse; }
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/CertificatePolicies.cs b/crypto/src/asn1/x509/CertificatePolicies.cs
new file mode 100644
index 000000000..a83565bb2
--- /dev/null
+++ b/crypto/src/asn1/x509/CertificatePolicies.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class CertificatePolicies
+        : Asn1Encodable
+    {
+        private readonly PolicyInformation[] policyInformation;
+
+        public static CertificatePolicies GetInstance(object obj)
+        {
+            if (obj == null || obj is CertificatePolicies)
+                return (CertificatePolicies)obj;
+
+            return new CertificatePolicies(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static CertificatePolicies GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+        /**
+         * Construct a CertificatePolicies object containing one PolicyInformation.
+         * 
+         * @param name the name to be contained.
+         */
+        public CertificatePolicies(PolicyInformation name)
+        {
+            this.policyInformation = new PolicyInformation[] { name };
+        }
+
+        public CertificatePolicies(PolicyInformation[] policyInformation)
+        {
+            this.policyInformation = policyInformation;
+        }
+
+        private CertificatePolicies(Asn1Sequence seq)
+        {
+            this.policyInformation = new PolicyInformation[seq.Count];
+
+            for (int i = 0; i < seq.Count; ++i)
+            {
+                policyInformation[i] = PolicyInformation.GetInstance(seq[i]);
+            }
+        }
+
+        public virtual PolicyInformation[] GetPolicyInformation()
+        {
+            return (PolicyInformation[])policyInformation.Clone();
+        }
+
+        /**
+         * Produce an object suitable for an ASN1OutputStream.
+         * <pre>
+         * CertificatePolicies ::= SEQUENCE SIZE {1..MAX} OF PolicyInformation
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(policyInformation);
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder("CertificatePolicies:");
+            if (policyInformation != null && policyInformation.Length > 0)
+            {
+                sb.Append(' ');
+                sb.Append(policyInformation[0]);
+                for (int i = 1; i < policyInformation.Length; ++i)
+                {
+                    sb.Append(", ");
+                    sb.Append(policyInformation[i]);
+                }
+            }
+            return sb.ToString();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/DSAParameter.cs b/crypto/src/asn1/x509/DSAParameter.cs
new file mode 100644
index 000000000..b2b325f4d
--- /dev/null
+++ b/crypto/src/asn1/x509/DSAParameter.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class DsaParameter
+        : Asn1Encodable
+    {
+        internal readonly DerInteger p, q, g;
+
+		public static DsaParameter GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DsaParameter GetInstance(
+            object obj)
+        {
+            if(obj == null || obj is DsaParameter)
+            {
+                return (DsaParameter) obj;
+            }
+
+			if(obj is Asn1Sequence)
+            {
+                return new DsaParameter((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid DsaParameter: " + obj.GetType().Name);
+        }
+
+		public DsaParameter(
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	g)
+        {
+            this.p = new DerInteger(p);
+            this.q = new DerInteger(q);
+            this.g = new DerInteger(g);
+        }
+
+		private DsaParameter(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.p = DerInteger.GetInstance(seq[0]);
+			this.q = DerInteger.GetInstance(seq[1]);
+			this.g = DerInteger.GetInstance(seq[2]);
+        }
+
+		public BigInteger P
+		{
+			get { return p.PositiveValue; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.PositiveValue; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.PositiveValue; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(p, q, g);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/DigestInfo.cs b/crypto/src/asn1/x509/DigestInfo.cs
new file mode 100644
index 000000000..1dec227fa
--- /dev/null
+++ b/crypto/src/asn1/x509/DigestInfo.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DigestInfo object.
+     * <pre>
+     * DigestInfo::=Sequence{
+     *          digestAlgorithm  AlgorithmIdentifier,
+     *          digest OCTET STRING }
+     * </pre>
+     */
+    public class DigestInfo
+        : Asn1Encodable
+    {
+        private readonly byte[] digest;
+        private readonly AlgorithmIdentifier algID;
+
+		public static DigestInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DigestInfo GetInstance(
+            object obj)
+        {
+            if (obj is DigestInfo)
+            {
+                return (DigestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new DigestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public DigestInfo(
+            AlgorithmIdentifier	algID,
+            byte[]				digest)
+        {
+            this.digest = digest;
+            this.algID = algID;
+        }
+
+		private DigestInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+            algID = AlgorithmIdentifier.GetInstance(seq[0]);
+			digest = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+		{
+			get { return algID; }
+		}
+
+		public byte[] GetDigest()
+        {
+            return digest;
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algID, new DerOctetString(digest));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/DisplayText.cs b/crypto/src/asn1/x509/DisplayText.cs
new file mode 100644
index 000000000..699f39031
--- /dev/null
+++ b/crypto/src/asn1/x509/DisplayText.cs
@@ -0,0 +1,172 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <code>DisplayText</code> class, used in
+	 * <code>CertificatePolicies</code> X509 V3 extensions (in policy qualifiers).
+	 *
+	 * <p>It stores a string in a chosen encoding.
+	 * <pre>
+	 * DisplayText ::= CHOICE {
+	 *      ia5String        IA5String      (SIZE (1..200)),
+	 *      visibleString    VisibleString  (SIZE (1..200)),
+	 *      bmpString        BMPString      (SIZE (1..200)),
+	 *      utf8String       UTF8String     (SIZE (1..200)) }
+	 * </pre></p>
+	 * @see PolicyQualifierInfo
+	 * @see PolicyInformation
+	 */
+	public class DisplayText
+		: Asn1Encodable, IAsn1Choice
+	{
+		/**
+		 * Constant corresponding to ia5String encoding.
+		 *
+		 */
+		public const int ContentTypeIA5String = 0;
+		/**
+		 * Constant corresponding to bmpString encoding.
+		 *
+		 */
+		public const int ContentTypeBmpString = 1;
+		/**
+		 * Constant corresponding to utf8String encoding.
+		 *
+		 */
+		public const int ContentTypeUtf8String = 2;
+		/**
+		 * Constant corresponding to visibleString encoding.
+		 *
+		 */
+		public const int ContentTypeVisibleString = 3;
+		/**
+		 * Describe constant <code>DisplayTextMaximumSize</code> here.
+		 *
+		 */
+		public const int DisplayTextMaximumSize = 200;
+
+		internal readonly int contentType;
+		internal readonly IAsn1String contents;
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 *
+		 * @param type the desired encoding type for the text.
+		 * @param text the text to store. Strings longer than 200
+		 * characters are truncated.
+		 */
+		public DisplayText(
+			int		type,
+			string	text)
+		{
+			if (text.Length > DisplayTextMaximumSize)
+			{
+				// RFC3280 limits these strings to 200 chars
+				// truncate the string
+				text = text.Substring(0, DisplayTextMaximumSize);
+			}
+
+			contentType = type;
+			switch (type)
+			{
+				case ContentTypeIA5String:
+					contents = (IAsn1String)new DerIA5String (text);
+					break;
+				case ContentTypeUtf8String:
+					contents = (IAsn1String)new DerUtf8String(text);
+					break;
+				case ContentTypeVisibleString:
+					contents = (IAsn1String)new DerVisibleString(text);
+					break;
+				case ContentTypeBmpString:
+					contents = (IAsn1String)new DerBmpString(text);
+					break;
+				default:
+					contents = (IAsn1String)new DerUtf8String(text);
+					break;
+			}
+		}
+
+//		/**
+//		 * return true if the passed in string can be represented without
+//		 * loss as a PrintableString, false otherwise.
+//		 */
+//		private bool CanBePrintable(
+//			string str)
+//		{
+//			for (int i = str.Length - 1; i >= 0; i--)
+//			{
+//				if (str[i] > 0x007f)
+//				{
+//					return false;
+//				}
+//			}
+//
+//			return true;
+//		}
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 *
+		 * @param text the text to encapsulate. Strings longer than 200
+		 * characters are truncated.
+		 */
+		public DisplayText(
+			string text)
+		{
+			// by default use UTF8String
+			if (text.Length > DisplayTextMaximumSize)
+			{
+				text = text.Substring(0, DisplayTextMaximumSize);
+			}
+
+			contentType = ContentTypeUtf8String;
+			contents = new DerUtf8String(text);
+		}
+
+		/**
+		 * Creates a new <code>DisplayText</code> instance.
+		 * <p>Useful when reading back a <code>DisplayText</code> class
+		 * from it's Asn1Encodable form.</p>
+		 *
+		 * @param contents an <code>Asn1Encodable</code> instance.
+		 */
+		public DisplayText(
+			IAsn1String contents)
+		{
+			this.contents = contents;
+		}
+
+		public static DisplayText GetInstance(
+			object obj)
+		{
+			if (obj is IAsn1String)
+			{
+				return new DisplayText((IAsn1String) obj);
+			}
+
+			if (obj is DisplayText)
+			{
+				return (DisplayText) obj;
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return (Asn1Object) contents;
+		}
+
+		/**
+		 * Returns the stored <code>string</code> object.
+		 *
+		 * @return the stored text as a <code>string</code>.
+		 */
+		public string GetString()
+		{
+			return contents.GetString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/DistributionPoint.cs b/crypto/src/asn1/x509/DistributionPoint.cs
new file mode 100644
index 000000000..ad1d3989e
--- /dev/null
+++ b/crypto/src/asn1/x509/DistributionPoint.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DistributionPoint object.
+     * <pre>
+     * DistributionPoint ::= Sequence {
+     *      distributionPoint [0] DistributionPointName OPTIONAL,
+     *      reasons           [1] ReasonFlags OPTIONAL,
+     *      cRLIssuer         [2] GeneralNames OPTIONAL
+     * }
+     * </pre>
+     */
+    public class DistributionPoint
+        : Asn1Encodable
+    {
+        internal readonly DistributionPointName	distributionPoint;
+        internal readonly ReasonFlags			reasons;
+        internal readonly GeneralNames			cRLIssuer;
+
+		public static DistributionPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static DistributionPoint GetInstance(
+            object obj)
+        {
+            if(obj == null || obj is DistributionPoint)
+            {
+                return (DistributionPoint) obj;
+            }
+
+			if(obj is Asn1Sequence)
+            {
+                return new DistributionPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid DistributionPoint: " + obj.GetType().Name);
+        }
+
+		private DistributionPoint(
+            Asn1Sequence seq)
+        {
+            for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject t = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (t.TagNo)
+                {
+                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);
+                    break;
+                }
+            }
+        }
+
+		public DistributionPoint(
+            DistributionPointName	distributionPointName,
+            ReasonFlags				reasons,
+            GeneralNames			crlIssuer)
+        {
+            this.distributionPoint = distributionPointName;
+            this.reasons = reasons;
+            this.cRLIssuer = crlIssuer;
+        }
+
+		public DistributionPointName DistributionPointName
+        {
+			get { return distributionPoint; }
+        }
+
+		public ReasonFlags Reasons
+        {
+			get { return reasons; }
+        }
+
+		public GeneralNames CrlIssuer
+        {
+			get { return cRLIssuer; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            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 override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+			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(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/DistributionPointName.cs b/crypto/src/asn1/x509/DistributionPointName.cs
new file mode 100644
index 000000000..1a9d24241
--- /dev/null
+++ b/crypto/src/asn1/x509/DistributionPointName.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The DistributionPointName object.
+     * <pre>
+     * DistributionPointName ::= CHOICE {
+     *     fullName                 [0] GeneralNames,
+     *     nameRelativeToCRLIssuer  [1] RDN
+     * }
+     * </pre>
+     */
+    public class DistributionPointName
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal readonly Asn1Encodable	name;
+        internal readonly int			type;
+
+		public const int FullName					= 0;
+        public const int NameRelativeToCrlIssuer	= 1;
+
+		public static DistributionPointName GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1TaggedObject.GetInstance(obj, true));
+        }
+
+		public static DistributionPointName GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DistributionPointName)
+            {
+                return (DistributionPointName) obj;
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return new DistributionPointName((Asn1TaggedObject) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+        public DistributionPointName(
+            int				type,
+            Asn1Encodable	name)
+        {
+            this.type = type;
+            this.name = name;
+        }
+
+		public DistributionPointName(
+			GeneralNames name)
+			:	this(FullName, name)
+		{
+		}
+
+		public int PointType
+        {
+			get { return type; }
+        }
+
+		public Asn1Encodable Name
+        {
+			get { return name; }
+        }
+
+		public DistributionPointName(
+            Asn1TaggedObject obj)
+        {
+            this.type = obj.TagNo;
+
+			if (type == FullName)
+            {
+                this.name = GeneralNames.GetInstance(obj, false);
+            }
+            else
+            {
+                this.name = Asn1Set.GetInstance(obj, false);
+            }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return new DerTaggedObject(false, type, name);
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+			buf.Append("DistributionPointName: [");
+			buf.Append(sep);
+			if (type == FullName)
+			{
+				appendObject(buf, sep, "fullName", name.ToString());
+			}
+			else
+			{
+				appendObject(buf, sep, "nameRelativeToCRLIssuer", name.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/ExtendedKeyUsage.cs b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
index 3bf79f392..a5b11f210 100644
--- a/crypto/src/asn1/x509/ExtendedKeyUsage.cs
+++ b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -17,14 +17,14 @@ namespace Org.BouncyCastle.Asn1.X509
         internal readonly IDictionary usageTable = Platform.CreateHashtable();
         internal readonly Asn1Sequence seq;
 
-		public static ExtendedKeyUsage GetInstance(
+        public static ExtendedKeyUsage GetInstance(
             Asn1TaggedObject	obj,
             bool				explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static ExtendedKeyUsage GetInstance(
+        public static ExtendedKeyUsage GetInstance(
             object obj)
         {
             if (obj is ExtendedKeyUsage)
@@ -32,45 +32,45 @@ namespace Org.BouncyCastle.Asn1.X509
                 return (ExtendedKeyUsage) obj;
             }
 
-			if (obj is Asn1Sequence)
+            if (obj is Asn1Sequence)
             {
                 return new ExtendedKeyUsage((Asn1Sequence) obj);
             }
 
-			if (obj is X509Extension)
-			{
-				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
-			}
+            if (obj is X509Extension)
+            {
+                return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+            }
 
-			throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name);
+            throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name);
         }
 
-		private ExtendedKeyUsage(
+        private ExtendedKeyUsage(
             Asn1Sequence seq)
         {
             this.seq = seq;
 
-			foreach (object o in seq)
-			{
-				if (!(o is DerObjectIdentifier))
-					throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
+            foreach (object o in seq)
+            {
+                if (!(o is DerObjectIdentifier))
+                    throw new ArgumentException("Only DerObjectIdentifier instances allowed in ExtendedKeyUsage.");
 
-				this.usageTable.Add(o, o);
+                this.usageTable[o] = o;
             }
         }
 
-		public ExtendedKeyUsage(
-			params KeyPurposeID[] usages)
-		{
-			this.seq = new DerSequence(usages);
+        public ExtendedKeyUsage(
+            params KeyPurposeID[] usages)
+        {
+            this.seq = new DerSequence(usages);
 
-			foreach (KeyPurposeID usage in usages)
-			{
-				this.usageTable.Add(usage, usage);
-			}
-		}
+            foreach (KeyPurposeID usage in usages)
+            {
+                this.usageTable[usage] = usage;
+            }
+        }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete]
         public ExtendedKeyUsage(
             ArrayList usages)
@@ -84,23 +84,24 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             Asn1EncodableVector v = new Asn1EncodableVector();
 
-			foreach (Asn1Object o in usages)
+            foreach (object usage in usages)
             {
-				v.Add(o);
+                Asn1Encodable o = KeyPurposeID.GetInstance(usage);
 
-				this.usageTable.Add(o, o);
+                v.Add(o);
+                this.usageTable[o] = o;
             }
 
-			this.seq = new DerSequence(v);
+            this.seq = new DerSequence(v);
         }
 
-		public bool HasKeyPurposeId(
+        public bool HasKeyPurposeId(
             KeyPurposeID keyPurposeId)
         {
-            return usageTable[keyPurposeId] != null;
+            return usageTable.Contains(keyPurposeId);
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete("Use 'GetAllUsages'")]
         public ArrayList GetUsages()
         {
@@ -109,21 +110,21 @@ namespace Org.BouncyCastle.Asn1.X509
 #endif
 
         /**
-		 * Returns all extended key usages.
-		 * The returned ArrayList contains DerObjectIdentifier instances.
-		 * @return An ArrayList with all key purposes.
-		 */
-		public IList GetAllUsages()
-		{
-			return Platform.CreateArrayList(usageTable.Values);
-		}
+         * Returns all extended key usages.
+         * The returned ArrayList contains DerObjectIdentifier instances.
+         * @return An ArrayList with all key purposes.
+         */
+        public IList GetAllUsages()
+        {
+            return Platform.CreateArrayList(usageTable.Values);
+        }
 
         public int Count
-		{
-			get { return usageTable.Count; }
-		}
+        {
+            get { return usageTable.Count; }
+        }
 
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
         {
             return seq;
         }
diff --git a/crypto/src/asn1/x509/GeneralName.cs b/crypto/src/asn1/x509/GeneralName.cs
new file mode 100644
index 000000000..710ddc922
--- /dev/null
+++ b/crypto/src/asn1/x509/GeneralName.cs
@@ -0,0 +1,418 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using NetUtils = Org.BouncyCastle.Utilities.Net;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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 }
+     * </pre>
+     */
+    public class GeneralName
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int OtherName					= 0;
+        public const int Rfc822Name					= 1;
+        public const int DnsName					= 2;
+        public const int X400Address				= 3;
+        public const int DirectoryName				= 4;
+        public const int EdiPartyName				= 5;
+        public const int UniformResourceIdentifier	= 6;
+        public const int IPAddress					= 7;
+        public const int RegisteredID				= 8;
+
+		internal readonly Asn1Encodable	obj;
+        internal readonly int			tag;
+
+		public GeneralName(
+            X509Name directoryName)
+        {
+            this.obj = directoryName;
+            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(
+            Asn1Object	name,
+			int			tag)
+        {
+            this.obj = name;
+            this.tag = tag;
+        }
+
+		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>
+		 * <li>iPAddress</li>
+		 * <li>directoryName</li>
+		 * <li>dNSName</li>
+		 * <li>uniformResourceIdentifier</li>
+		 * <li>registeredID</li>
+		 * </ul>
+		 * For x400Address, otherName and ediPartyName there is no common string
+		 * format defined.
+		 * </p><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.
+		 * </p>
+		 *
+		 * @param tag tag number
+		 * @param name string representation of name
+		 * @throws ArgumentException 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 DerObjectIdentifier(name);
+			}
+			else if (tag == DirectoryName)
+			{
+				this.obj = new X509Name(name);
+			}
+			else if (tag == IPAddress)
+			{
+				byte[] enc = toGeneralNameEncoding(name);
+				if (enc == null)
+					throw new ArgumentException("IP Address is invalid", "name");
+
+				this.obj = new DerOctetString(enc);
+			}
+			else
+			{
+				throw new ArgumentException("can't process string for tag: " + tag, "tag");
+			}
+		}
+
+		public static GeneralName GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is GeneralName)
+            {
+                return (GeneralName) obj;
+            }
+
+            if (obj is Asn1TaggedObject)
+            {
+                Asn1TaggedObject	tagObj = (Asn1TaggedObject) obj;
+                int					tag = tagObj.TagNo;
+
+				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 ArgumentException("unknown tag: " + tag);
+					case DirectoryName:
+						return new GeneralName(tag, X509Name.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, DerObjectIdentifier.GetInstance(tagObj, false));
+				}
+	        }
+
+            if (obj is byte[])
+	        {
+	            try
+	            {
+	                return GetInstance(Asn1Object.FromByteArray((byte[])obj));
+	            }
+	            catch (IOException)
+	            {
+	                throw new ArgumentException("unable to parse encoded general name");
+	            }
+	        }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public static GeneralName GetInstance(
+            Asn1TaggedObject	tagObj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1TaggedObject.GetInstance(tagObj, true));
+        }
+
+		public int TagNo
+		{
+			get { return tag; }
+		}
+
+		public Asn1Encodable Name
+		{
+			get { return obj; }
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			buf.Append(tag);
+			buf.Append(": ");
+
+			switch (tag)
+			{
+				case Rfc822Name:
+				case DnsName:
+				case UniformResourceIdentifier:
+					buf.Append(DerIA5String.GetInstance(obj).GetString());
+					break;
+				case DirectoryName:
+					buf.Append(X509Name.GetInstance(obj).ToString());
+					break;
+				default:
+					buf.Append(obj.ToString());
+					break;
+			}
+
+			return buf.ToString();
+		}
+
+		private byte[] toGeneralNameEncoding(
+			string ip)
+		{
+			if (NetUtils.IPAddress.IsValidIPv6WithNetmask(ip) || NetUtils.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 (NetUtils.IPAddress.IsValidIPv4WithNetmask(ip) || NetUtils.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 = Int32.Parse(mask);
+
+			for (int i = 0; i != maskVal; i++)
+			{
+				addr[(i / 8) + offset] |= (byte)(1 << (i % 8));
+			}
+		}
+
+		private void parseIPv4(string ip, byte[] addr, int offset)
+		{
+			foreach (string token in ip.Split('.', '/'))
+			{
+				addr[offset++] = (byte)Int32.Parse(token);
+			}
+		}
+
+		private int[] parseMask(string mask)
+		{
+			int[] res = new int[8];
+			int   maskVal = Int32.Parse(mask);
+
+			for (int i = 0; i != maskVal; i++)
+			{
+				res[i / 16] |= 1 << (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)
+		{
+			if (ip.StartsWith("::"))
+			{
+				ip = ip.Substring(1);
+			}
+			else if (ip.EndsWith("::"))
+			{
+				ip = ip.Substring(0, ip.Length - 1);
+			}
+
+			IEnumerator sEnum = ip.Split(':').GetEnumerator();
+
+			int index = 0;
+			int[] val = new int[8];
+
+			int doubleColon = -1;
+
+			while (sEnum.MoveNext())
+			{
+				string e = (string) sEnum.Current;
+
+				if (e.Length == 0)
+				{
+					doubleColon = index;
+					val[index++] = 0;
+				}
+				else
+				{
+					if (e.IndexOf('.') < 0)
+					{
+						val[index++] = Int32.Parse(e, NumberStyles.AllowHexSpecifier);
+					}
+					else
+					{
+						string[] tokens = e.Split('.');
+
+						val[index++] = (Int32.Parse(tokens[0]) << 8) | Int32.Parse(tokens[1]);
+						val[index++] = (Int32.Parse(tokens[2]) << 8) | Int32.Parse(tokens[3]);
+					}
+				}
+			}
+
+			if (index != val.Length)
+			{
+				Array.Copy(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 override Asn1Object ToAsn1Object()
+        {
+			// Explicitly tagged if DirectoryName
+			return new DerTaggedObject(tag == DirectoryName, tag, obj);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/GeneralNames.cs b/crypto/src/asn1/x509/GeneralNames.cs
new file mode 100644
index 000000000..6c5c8e690
--- /dev/null
+++ b/crypto/src/asn1/x509/GeneralNames.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class GeneralNames
+		: Asn1Encodable
+	{
+		private readonly GeneralName[] names;
+
+		public static GeneralNames GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is GeneralNames)
+			{
+				return (GeneralNames) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new GeneralNames((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static GeneralNames GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		/// <summary>Construct a GeneralNames object containing one GeneralName.</summary>
+		/// <param name="name">The name to be contained.</param>
+		public GeneralNames(
+			GeneralName name)
+		{
+			names = new GeneralName[]{ name };
+		}
+
+        public GeneralNames(
+            GeneralName[] names)
+        {
+            this.names = (GeneralName[])names.Clone();
+        }
+
+		private GeneralNames(
+			Asn1Sequence seq)
+		{
+			this.names = new GeneralName[seq.Count];
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				names[i] = GeneralName.GetInstance(seq[i]);
+			}
+		}
+
+		public GeneralName[] GetNames()
+		{
+			return (GeneralName[]) names.Clone();
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * <pre>
+		 * GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(names);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string sep = Platform.NewLine;
+
+			buf.Append("GeneralNames:");
+			buf.Append(sep);
+
+			foreach (GeneralName name in names)
+			{
+				buf.Append("    ");
+				buf.Append(name);
+				buf.Append(sep);
+			}
+
+			return buf.ToString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/GeneralSubtree.cs b/crypto/src/asn1/x509/GeneralSubtree.cs
new file mode 100644
index 000000000..e918a0277
--- /dev/null
+++ b/crypto/src/asn1/x509/GeneralSubtree.cs
@@ -0,0 +1,189 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Class for containing a restriction object subtrees in NameConstraints. See
+	 * RFC 3280.
+	 *
+	 * <pre>
+	 *
+	 *       GeneralSubtree ::= SEQUENCE
+	 *       {
+	 *         baseName                    GeneralName,
+	 *         minimum         [0]     BaseDistance DEFAULT 0,
+	 *         maximum         [1]     BaseDistance OPTIONAL
+	 *       }
+	 * </pre>
+	 *
+	 * @see org.bouncycastle.asn1.x509.NameConstraints
+	 *
+	 */
+	public class GeneralSubtree
+		: Asn1Encodable
+	{
+		private readonly GeneralName	baseName;
+		private readonly DerInteger		minimum;
+		private readonly DerInteger		maximum;
+
+		private GeneralSubtree(
+			Asn1Sequence seq)
+		{
+			baseName = GeneralName.GetInstance(seq[0]);
+
+			switch (seq.Count)
+			{
+				case 1:
+					break;
+				case 2:
+				{
+					Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[1]);
+					switch (o.TagNo)
+					{
+						case 0:
+							minimum = DerInteger.GetInstance(o, false);
+							break;
+						case 1:
+							maximum = DerInteger.GetInstance(o, false);
+							break;
+						default:
+							throw new ArgumentException("Bad tag number: " + o.TagNo);
+					}
+					break;
+				}
+				case 3:
+				{
+					{
+						Asn1TaggedObject oMin = Asn1TaggedObject.GetInstance(seq[1]);
+						if (oMin.TagNo != 0)
+							throw new ArgumentException("Bad tag number for 'minimum': " + oMin.TagNo);
+						minimum = DerInteger.GetInstance(oMin, false);
+					}
+
+					{
+						Asn1TaggedObject oMax = Asn1TaggedObject.GetInstance(seq[2]);
+						if (oMax.TagNo != 1)
+							throw new ArgumentException("Bad tag number for 'maximum': " + oMax.TagNo);
+						maximum = DerInteger.GetInstance(oMax, false);
+					}
+
+					break;
+				}
+				default:
+					throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+		}
+
+		/**
+		 * 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.</p>
+		 *
+		 * @param baseName
+		 *            A restriction.
+		 * @param minimum
+		 *            Minimum
+		 *
+		 * @param maximum
+		 *            Maximum
+		 */
+		public GeneralSubtree(
+			GeneralName	baseName,
+			BigInteger	minimum,
+			BigInteger	maximum)
+		{
+			this.baseName = baseName;
+			if (minimum != null)
+			{
+				this.minimum = new DerInteger(minimum);
+			}
+			if (maximum != null)
+			{
+				this.maximum = new DerInteger(maximum);
+			}
+		}
+
+		public GeneralSubtree(
+			GeneralName baseName)
+			: this(baseName, null, null)
+		{
+		}
+
+		public static GeneralSubtree GetInstance(
+			Asn1TaggedObject	o,
+			bool				isExplicit)
+		{
+			return new GeneralSubtree(Asn1Sequence.GetInstance(o, isExplicit));
+		}
+
+		public static GeneralSubtree GetInstance(
+			object obj)
+		{
+			if (obj == null)
+			{
+				return null;
+			}
+
+			if (obj is GeneralSubtree)
+			{
+				return (GeneralSubtree) obj;
+			}
+
+			return new GeneralSubtree(Asn1Sequence.GetInstance(obj));
+		}
+
+		public GeneralName Base
+		{
+			get { return baseName; }
+		}
+
+		public BigInteger Minimum
+		{
+			get { return minimum == null ? BigInteger.Zero : minimum.Value; }
+		}
+
+		public BigInteger Maximum
+		{
+			get { return maximum == null ? null : maximum.Value; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 *
+		 * Returns:
+		 *
+		 * <pre>
+		 *       GeneralSubtree ::= SEQUENCE
+		 *       {
+		 *         baseName                    GeneralName,
+		 *         minimum         [0]     BaseDistance DEFAULT 0,
+		 *         maximum         [1]     BaseDistance OPTIONAL
+		 *       }
+		 * </pre>
+		 *
+		 * @return a DERObject
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(baseName);
+
+			if (minimum != null && minimum.Value.SignValue != 0)
+			{
+				v.Add(new DerTaggedObject(false, 0, minimum));
+			}
+
+			if (maximum != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, maximum));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/Holder.cs b/crypto/src/asn1/x509/Holder.cs
new file mode 100644
index 000000000..d04f1cb60
--- /dev/null
+++ b/crypto/src/asn1/x509/Holder.cs
@@ -0,0 +1,257 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * 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>
+	 * <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>
+	 * </p>
+	 */
+	public class Holder
+        : Asn1Encodable
+    {
+		internal readonly IssuerSerial		baseCertificateID;
+        internal readonly GeneralNames		entityName;
+        internal readonly ObjectDigestInfo	objectDigestInfo;
+		private readonly int version;
+
+		public static Holder GetInstance(
+            object obj)
+        {
+            if (obj is Holder)
+            {
+                return (Holder) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new Holder((Asn1Sequence) obj);
+            }
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new Holder((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor for a holder for an v1 attribute certificate.
+		 * 
+		 * @param tagObj The ASN.1 tagged holder object.
+		 */
+		public Holder(
+			Asn1TaggedObject tagObj)
+		{
+			switch (tagObj.TagNo)
+			{
+				case 0:
+					baseCertificateID = IssuerSerial.GetInstance(tagObj, false);
+					break;
+				case 1:
+					entityName = GeneralNames.GetInstance(tagObj, false);
+					break;
+				default:
+					throw new ArgumentException("unknown tag in Holder");
+			}
+
+			this.version = 0;
+		}
+
+		/**
+		 * Constructor for a holder for an v2 attribute certificate. *
+		 * 
+		 * @param seq The ASN.1 sequence.
+		 */
+		private Holder(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject tObj = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (tObj.TagNo)
+                {
+                    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 ArgumentException("unknown tag in Holder");
+                }
+            }
+
+			this.version = 1;
+		}
+
+		public Holder(
+			IssuerSerial baseCertificateID)
+			: this(baseCertificateID, 1)
+		{
+		}
+
+		/**
+		 * Constructs a holder from a IssuerSerial.
+		 * @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 Version
+		{
+			get { return version; }
+		}
+
+		/**
+		 * 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.
+		 */
+		public Holder(
+			GeneralNames entityName)
+			: this(entityName, 1)
+		{
+		}
+
+		/**
+		 * 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;
+			this.version = 1;
+		}
+
+		public IssuerSerial BaseCertificateID
+		{
+			get { 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 EntityName
+		{
+			get { return entityName; }
+		}
+
+		public ObjectDigestInfo ObjectDigestInfo
+		{
+			get { return objectDigestInfo; }
+		}
+
+		/**
+         * 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>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			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);
+			}
+
+			if (entityName != null)
+			{
+				return new DerTaggedObject(false, 1, entityName);
+			}
+
+			return new DerTaggedObject(false, 0, baseCertificateID);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/IetfAttrSyntax.cs b/crypto/src/asn1/x509/IetfAttrSyntax.cs
new file mode 100644
index 000000000..e719865b3
--- /dev/null
+++ b/crypto/src/asn1/x509/IetfAttrSyntax.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Implementation of <code>IetfAttrSyntax</code> as specified by RFC3281.
+     */
+    public class IetfAttrSyntax
+        : Asn1Encodable
+    {
+        public const int ValueOctets	= 1;
+        public const int ValueOid		= 2;
+        public const int ValueUtf8		= 3;
+
+		internal readonly GeneralNames	policyAuthority;
+        internal readonly Asn1EncodableVector values = new Asn1EncodableVector();
+
+		internal int valueChoice = -1;
+
+		/**
+         *
+         */
+        public IetfAttrSyntax(
+			Asn1Sequence seq)
+        {
+            int i = 0;
+
+            if (seq[0] is Asn1TaggedObject)
+            {
+                policyAuthority = GeneralNames.GetInstance(((Asn1TaggedObject)seq[0]), false);
+                i++;
+            }
+            else if (seq.Count == 2)
+            { // VOMS fix
+                policyAuthority = GeneralNames.GetInstance(seq[0]);
+                i++;
+            }
+
+			if (!(seq[i] is Asn1Sequence))
+            {
+                throw new ArgumentException("Non-IetfAttrSyntax encoding");
+            }
+
+			seq = (Asn1Sequence) seq[i];
+
+			foreach (Asn1Object obj in seq)
+			{
+                int type;
+
+                if (obj is DerObjectIdentifier)
+                {
+                    type = ValueOid;
+                }
+                else if (obj is DerUtf8String)
+                {
+                    type = ValueUtf8;
+                }
+                else if (obj is DerOctetString)
+                {
+                    type = ValueOctets;
+                }
+                else
+                {
+                    throw new ArgumentException("Bad value type encoding IetfAttrSyntax");
+                }
+
+				if (valueChoice < 0)
+                {
+                    valueChoice = type;
+                }
+
+				if (type != valueChoice)
+                {
+                    throw new ArgumentException("Mix of value types in IetfAttrSyntax");
+                }
+
+				values.Add(obj);
+            }
+        }
+
+		public GeneralNames PolicyAuthority
+		{
+			get { return policyAuthority; }
+		}
+
+		public int ValueType
+		{
+			get { return valueChoice; }
+		}
+
+		public object[] GetValues()
+        {
+            if (this.ValueType == ValueOctets)
+            {
+                Asn1OctetString[] tmp = new Asn1OctetString[values.Count];
+
+				for (int i = 0; i != tmp.Length; i++)
+                {
+                    tmp[i] = (Asn1OctetString) values[i];
+                }
+
+				return tmp;
+            }
+
+			if (this.ValueType == ValueOid)
+            {
+                DerObjectIdentifier[] tmp = new DerObjectIdentifier[values.Count];
+
+                for (int i = 0; i != tmp.Length; i++)
+                {
+                    tmp[i] = (DerObjectIdentifier) values[i];
+                }
+
+				return tmp;
+            }
+
+			{
+				DerUtf8String[] tmp = new DerUtf8String[values.Count];
+
+				for (int i = 0; i != tmp.Length; i++)
+				{
+					tmp[i] = (DerUtf8String) values[i];
+				}
+
+				return tmp;
+			}
+        }
+
+		/**
+         *
+         * <pre>
+         *
+         *  IetfAttrSyntax ::= Sequence {
+         *    policyAuthority [0] GeneralNames OPTIONAL,
+         *    values Sequence OF CHOICE {
+         *      octets OCTET STRING,
+         *      oid OBJECT IDENTIFIER,
+         *      string UTF8String
+         *    }
+         *  }
+         *
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (policyAuthority != null)
+            {
+                v.Add(new DerTaggedObject(0, policyAuthority));
+            }
+
+			v.Add(new DerSequence(values));
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/IssuerSerial.cs b/crypto/src/asn1/x509/IssuerSerial.cs
new file mode 100644
index 000000000..6a24e7333
--- /dev/null
+++ b/crypto/src/asn1/x509/IssuerSerial.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class IssuerSerial
+        : Asn1Encodable
+    {
+        internal readonly GeneralNames	issuer;
+        internal readonly DerInteger	serial;
+        internal readonly DerBitString	issuerUid;
+
+		public static IssuerSerial GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is IssuerSerial)
+            {
+                return (IssuerSerial) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuerSerial((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+        public static IssuerSerial GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		private IssuerSerial(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2 && seq.Count != 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			issuer = GeneralNames.GetInstance(seq[0]);
+			serial = DerInteger.GetInstance(seq[1]);
+
+			if (seq.Count == 3)
+            {
+				issuerUid = DerBitString.GetInstance(seq[2]);
+			}
+        }
+
+		public IssuerSerial(
+			GeneralNames	issuer,
+			DerInteger		serial)
+		{
+			this.issuer = issuer;
+			this.serial = serial;
+		}
+
+		public GeneralNames Issuer
+		{
+			get { return issuer; }
+		}
+
+		public DerInteger Serial
+		{
+			get { return serial; }
+		}
+
+		public DerBitString IssuerUid
+		{
+			get { return issuerUid; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  IssuerSerial  ::=  Sequence {
+         *       issuer         GeneralNames,
+         *       serial         CertificateSerialNumber,
+         *       issuerUid      UniqueIdentifier OPTIONAL
+         *  }
+         * </pre>
+         */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				issuer, serial);
+
+			if (issuerUid != null)
+			{
+				v.Add(issuerUid);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/IssuingDistributionPoint.cs b/crypto/src/asn1/x509/IssuingDistributionPoint.cs
new file mode 100644
index 000000000..3af0d565f
--- /dev/null
+++ b/crypto/src/asn1/x509/IssuingDistributionPoint.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * <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
+        : Asn1Encodable
+    {
+		private readonly DistributionPointName	_distributionPoint;
+		private readonly bool					_onlyContainsUserCerts;
+        private readonly bool					_onlyContainsCACerts;
+		private readonly ReasonFlags			_onlySomeReasons;
+		private readonly bool					_indirectCRL;
+        private readonly bool					_onlyContainsAttributeCerts;
+
+		private readonly Asn1Sequence seq;
+
+		public static IssuingDistributionPoint GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static IssuingDistributionPoint GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is IssuingDistributionPoint)
+            {
+                return (IssuingDistributionPoint) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new IssuingDistributionPoint((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * 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,
+			bool					onlyContainsUserCerts,
+			bool					onlyContainsCACerts,
+			ReasonFlags				onlySomeReasons,
+			bool					indirectCRL,
+			bool					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)
+			{
+				vec.Add(new DerTaggedObject(false, 1, DerBoolean.True));
+			}
+			if (onlyContainsCACerts)
+			{
+				vec.Add(new DerTaggedObject(false, 2, DerBoolean.True));
+			}
+			if (onlySomeReasons != null)
+			{
+				vec.Add(new DerTaggedObject(false, 3, onlySomeReasons));
+			}
+			if (indirectCRL)
+			{
+				vec.Add(new DerTaggedObject(false, 4, DerBoolean.True));
+			}
+			if (onlyContainsAttributeCerts)
+			{
+				vec.Add(new DerTaggedObject(false, 5, DerBoolean.True));
+			}
+
+			seq = new DerSequence(vec);
+		}
+
+		/**
+         * Constructor from Asn1Sequence
+         */
+        private IssuingDistributionPoint(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			for (int i = 0; i != seq.Count; i++)
+            {
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+
+				switch (o.TagNo)
+                {
+					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 ArgumentException("unknown tag in IssuingDistributionPoint");
+                }
+            }
+        }
+
+		public bool OnlyContainsUserCerts
+		{
+			get { return _onlyContainsUserCerts; }
+		}
+
+		public bool OnlyContainsCACerts
+		{
+			get { return _onlyContainsCACerts; }
+		}
+
+		public bool IsIndirectCrl
+		{
+			get { return _indirectCRL; }
+		}
+
+		public bool OnlyContainsAttributeCerts
+		{
+			get { return _onlyContainsAttributeCerts; }
+		}
+
+		/**
+		 * @return Returns the distributionPoint.
+		 */
+		public DistributionPointName DistributionPoint
+		{
+			get { return _distributionPoint; }
+		}
+
+		/**
+		 * @return Returns the onlySomeReasons.
+		 */
+		public ReasonFlags OnlySomeReasons
+		{
+			get { return _onlySomeReasons; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+
+		public override string ToString()
+		{
+			string sep = Platform.NewLine;
+			StringBuilder buf = new StringBuilder();
+
+			buf.Append("IssuingDistributionPoint: [");
+			buf.Append(sep);
+			if (_distributionPoint != null)
+			{
+				appendObject(buf, sep, "distributionPoint", _distributionPoint.ToString());
+			}
+			if (_onlyContainsUserCerts)
+			{
+				appendObject(buf, sep, "onlyContainsUserCerts", _onlyContainsUserCerts.ToString());
+			}
+			if (_onlyContainsCACerts)
+			{
+				appendObject(buf, sep, "onlyContainsCACerts", _onlyContainsCACerts.ToString());
+			}
+			if (_onlySomeReasons != null)
+			{
+				appendObject(buf, sep, "onlySomeReasons", _onlySomeReasons.ToString());
+			}
+			if (_onlyContainsAttributeCerts)
+			{
+				appendObject(buf, sep, "onlyContainsAttributeCerts", _onlyContainsAttributeCerts.ToString());
+			}
+			if (_indirectCRL)
+			{
+				appendObject(buf, sep, "indirectCRL", _indirectCRL.ToString());
+			}
+			buf.Append("]");
+			buf.Append(sep);
+			return buf.ToString();
+		}
+
+		private void appendObject(
+			StringBuilder	buf,
+			string			sep,
+			string			name,
+			string			val)
+		{
+			string indent = "    ";
+
+			buf.Append(indent);
+			buf.Append(name);
+			buf.Append(":");
+			buf.Append(sep);
+			buf.Append(indent);
+			buf.Append(indent);
+			buf.Append(val);
+			buf.Append(sep);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/KeyPurposeId.cs b/crypto/src/asn1/x509/KeyPurposeId.cs
new file mode 100644
index 000000000..4b48a9b51
--- /dev/null
+++ b/crypto/src/asn1/x509/KeyPurposeId.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The KeyPurposeID object.
+     * <pre>
+     *     KeyPurposeID ::= OBJECT IDENTIFIER
+     * </pre>
+     */
+    public sealed class KeyPurposeID
+        : DerObjectIdentifier
+    {
+        private const string IdKP = "1.3.6.1.5.5.7.3";
+
+		private KeyPurposeID(
+			string id)
+			: base(id)
+        {
+        }
+
+		public static readonly KeyPurposeID AnyExtendedKeyUsage = new KeyPurposeID(X509Extensions.ExtendedKeyUsage.Id + ".0");
+        public static readonly KeyPurposeID IdKPServerAuth = new KeyPurposeID(IdKP + ".1");
+        public static readonly KeyPurposeID IdKPClientAuth = new KeyPurposeID(IdKP + ".2");
+        public static readonly KeyPurposeID IdKPCodeSigning = new KeyPurposeID(IdKP + ".3");
+        public static readonly KeyPurposeID IdKPEmailProtection = new KeyPurposeID(IdKP + ".4");
+        public static readonly KeyPurposeID IdKPIpsecEndSystem = new KeyPurposeID(IdKP + ".5");
+        public static readonly KeyPurposeID IdKPIpsecTunnel = new KeyPurposeID(IdKP + ".6");
+        public static readonly KeyPurposeID IdKPIpsecUser = new KeyPurposeID(IdKP + ".7");
+        public static readonly KeyPurposeID IdKPTimeStamping = new KeyPurposeID(IdKP + ".8");
+        public static readonly KeyPurposeID IdKPOcspSigning = new KeyPurposeID(IdKP + ".9");
+
+		//
+        // microsoft key purpose ids
+        //
+        public static readonly KeyPurposeID IdKPSmartCardLogon = new KeyPurposeID("1.3.6.1.4.1.311.20.2.2");
+    }
+}
diff --git a/crypto/src/asn1/x509/KeyUsage.cs b/crypto/src/asn1/x509/KeyUsage.cs
new file mode 100644
index 000000000..fef04e8b9
--- /dev/null
+++ b/crypto/src/asn1/x509/KeyUsage.cs
@@ -0,0 +1,79 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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
+        : DerBitString
+    {
+        public const int DigitalSignature = (1 << 7);
+        public const int NonRepudiation   = (1 << 6);
+        public const int KeyEncipherment  = (1 << 5);
+        public const int DataEncipherment = (1 << 4);
+        public const int KeyAgreement     = (1 << 3);
+        public const int KeyCertSign      = (1 << 2);
+        public const int CrlSign          = (1 << 1);
+        public const int EncipherOnly     = (1 << 0);
+        public const int DecipherOnly     = (1 << 15);
+
+		public static new KeyUsage GetInstance(
+			object obj)
+		{
+			if (obj is KeyUsage)
+			{
+				return (KeyUsage)obj;
+			}
+
+			if (obj is X509Extension)
+			{
+				return 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)
+			: base(GetBytes(usage), GetPadBits(usage))
+        {
+        }
+
+		private KeyUsage(
+			DerBitString usage)
+			: base(usage.GetBytes(), usage.PadBits)
+        {
+        }
+
+		public override string ToString()
+        {
+			byte[] data = GetBytes();
+            if (data.Length == 1)
+            {
+				return "KeyUsage: 0x" + (data[0] & 0xff).ToString("X");
+            }
+
+			return "KeyUsage: 0x" + ((data[1] & 0xff) << 8 | (data[0] & 0xff)).ToString("X");
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/NameConstraints.cs b/crypto/src/asn1/x509/NameConstraints.cs
index c178f5b45..8374ff60a 100644
--- a/crypto/src/asn1/x509/NameConstraints.cs
+++ b/crypto/src/asn1/x509/NameConstraints.cs
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Asn1.X509
 			}
 		}
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         public NameConstraints(
             ArrayList permitted,
             ArrayList excluded)
diff --git a/crypto/src/asn1/x509/NoticeReference.cs b/crypto/src/asn1/x509/NoticeReference.cs
index 718fe92cf..f0d3a7b7f 100644
--- a/crypto/src/asn1/x509/NoticeReference.cs
+++ b/crypto/src/asn1/x509/NoticeReference.cs
@@ -1,138 +1,143 @@
 using System;
 using System.Collections;
 
+using Org.BouncyCastle.Math;
+
 namespace Org.BouncyCastle.Asn1.X509
 {
-	/**
-	 * <code>NoticeReference</code> class, used in
-	 * <code>CertificatePolicies</code> X509 V3 extensions
-	 * (in policy qualifiers).
-	 *
-	 * <pre>
-	 *  NoticeReference ::= Sequence {
-	 *      organization     DisplayText,
-	 *      noticeNumbers    Sequence OF Integer }
-	 *
-	 * </pre>
-	 *
-	 * @see PolicyQualifierInfo
-	 * @see PolicyInformation
-	 */
-	public class NoticeReference
-		: Asn1Encodable
-	{
-		internal readonly DisplayText organization;
-		internal readonly Asn1Sequence noticeNumbers;
-
-#if !(SILVERLIGHT || PORTABLE)
-        [Obsolete]
-        public NoticeReference(
-            string orgName,
-            ArrayList numbers)
-            : this(orgName, (IList)numbers)
+    /**
+     * <code>NoticeReference</code> class, used in
+     * <code>CertificatePolicies</code> X509 V3 extensions
+     * (in policy qualifiers).
+     *
+     * <pre>
+     *  NoticeReference ::= Sequence {
+     *      organization     DisplayText,
+     *      noticeNumbers    Sequence OF Integer }
+     *
+     * </pre>
+     *
+     * @see PolicyQualifierInfo
+     * @see PolicyInformation
+     */
+    public class NoticeReference
+        : Asn1Encodable
+    {
+        private readonly DisplayText organization;
+        private readonly Asn1Sequence noticeNumbers;
+
+        private static Asn1EncodableVector ConvertVector(IList numbers)
+        {
+            Asn1EncodableVector av = new Asn1EncodableVector();
+
+            foreach (object o in numbers)
+            {
+                DerInteger di;
+
+                if (o is BigInteger)
+                {
+                    di = new DerInteger((BigInteger)o);
+                }
+                else if (o is int)
+                {
+                    di = new DerInteger((int)o);
+                }
+                else
+                {
+                    throw new ArgumentException();
+                }
+
+                av.Add(di);
+            }
+            return av;
+        }
+
+        /**
+         * Creates a new <code>NoticeReference</code> instance.
+         *
+         * @param organization a <code>String</code> value
+         * @param numbers a <code>Vector</code> value
+         */
+        public NoticeReference(string organization, IList numbers)
+            : this(organization, ConvertVector(numbers))
         {
         }
-#endif
 
         /**
-		* Creates a new <code>NoticeReference</code> instance.
-		*
-		* @param orgName a <code>string</code> value
-		* @param numbers a <code>ArrayList</code> value
-		*/
-		public NoticeReference(
-			string  orgName,
-			IList   numbers)
-		{
-			organization = new DisplayText(orgName);
-
-			object o = numbers[0];
-
-			Asn1EncodableVector av = new Asn1EncodableVector();
-			if (o is int)
-			{
-				foreach (int nm in numbers)
-				{
-					av.Add(new DerInteger(nm));
-				}
-			}
-
-			noticeNumbers = new DerSequence(av);
-		}
-
-		/**
-		 * Creates a new <code>NoticeReference</code> instance.
-		 *
-		 * @param orgName a <code>string</code> value
-		 * @param numbers an <code>Asn1Sequence</code> value
-		 */
-		public NoticeReference(
-			string			orgName,
-			Asn1Sequence	numbers)
-		{
-			organization = new DisplayText(orgName);
-			noticeNumbers = numbers;
-		}
-
-		/**
-		 * Creates a new <code>NoticeReference</code> instance.
-		 *
-		 * @param displayTextType an <code>int</code> value
-		 * @param orgName a <code>string</code> value
-		 * @param numbers an <code>Asn1Sequence</code> value
-		 */
-		public NoticeReference(
-			int				displayTextType,
-			string			orgName,
-			Asn1Sequence	numbers)
-		{
-			organization = new DisplayText(displayTextType, orgName);
-			noticeNumbers = numbers;
-		}
-
-		/**
-		 * Creates a new <code>NoticeReference</code> instance.
-		 * <p>Useful for reconstructing a <code>NoticeReference</code>
-		 * instance from its encodable/encoded form.</p>
-		 *
-		 * @param as an <code>Asn1Sequence</code> value obtained from either
-		 * calling @{link ToAsn1Object()} for a <code>NoticeReference</code>
-		 * instance or from parsing it from a Der-encoded stream.
-		 */
-		private NoticeReference(
-			Asn1Sequence seq)
-		{
-			if (seq.Count != 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
-
-			organization = DisplayText.GetInstance(seq[0]);
-			noticeNumbers = Asn1Sequence.GetInstance(seq[1]);
-		}
-
-		public static NoticeReference GetInstance(
-			object obj)
-		{
-			if (obj is NoticeReference)
-			{
-				return (NoticeReference) obj;
-			}
-
-			if (obj is Asn1Sequence)
-			{
-				return new NoticeReference((Asn1Sequence) obj);
-			}
-
-			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
-		}
-
-		/**
-		 * Describe <code>ToAsn1Object</code> method here.
-		 *
-		 * @return a <code>Asn1Object</code> value
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			return new DerSequence(organization, noticeNumbers);
-		}
-	}
+        * Creates a new <code>NoticeReference</code> instance.
+        *
+        * @param organization a <code>String</code> value
+        * @param noticeNumbers an <code>ASN1EncodableVector</code> value
+        */
+        public NoticeReference(string organization, Asn1EncodableVector noticeNumbers)
+            : this(new DisplayText(organization), noticeNumbers)
+        {
+        }
+
+        /**
+         * Creates a new <code>NoticeReference</code> instance.
+         *
+         * @param organization displayText
+         * @param noticeNumbers an <code>ASN1EncodableVector</code> value
+         */
+        public NoticeReference(DisplayText organization, Asn1EncodableVector noticeNumbers)
+        {
+            this.organization = organization;
+            this.noticeNumbers = new DerSequence(noticeNumbers);
+        }
+
+        /**
+         * Creates a new <code>NoticeReference</code> instance.
+         * <p>Useful for reconstructing a <code>NoticeReference</code>
+         * instance from its encodable/encoded form.</p>
+         *
+         * @param as an <code>Asn1Sequence</code> value obtained from either
+         * calling @{link ToAsn1Object()} for a <code>NoticeReference</code>
+         * instance or from parsing it from a Der-encoded stream.
+         */
+        private NoticeReference(Asn1Sequence seq)
+        {
+            if (seq.Count != 2)
+                throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            organization = DisplayText.GetInstance(seq[0]);
+            noticeNumbers = Asn1Sequence.GetInstance(seq[1]);
+        }
+
+        public static NoticeReference GetInstance(object obj)
+        {
+            if (obj is NoticeReference)
+                return (NoticeReference)obj;
+            if (obj == null)
+                return null;
+            return new NoticeReference(Asn1Sequence.GetInstance(obj));
+        }
+
+        public virtual DisplayText Organization
+        {
+            get { return organization; }
+        }
+
+        public virtual DerInteger[] GetNoticeNumbers()
+        {
+            DerInteger[] tmp = new DerInteger[noticeNumbers.Count];
+
+            for (int i = 0; i != noticeNumbers.Count; ++i)
+            {
+                tmp[i] = DerInteger.GetInstance(noticeNumbers[i]);
+            }
+
+            return tmp;
+        }
+
+        /**
+         * Describe <code>ToAsn1Object</code> method here.
+         *
+         * @return a <code>Asn1Object</code> value
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(organization, noticeNumbers);
+        }
+    }
 }
diff --git a/crypto/src/asn1/x509/ObjectDigestInfo.cs b/crypto/src/asn1/x509/ObjectDigestInfo.cs
new file mode 100644
index 000000000..6d5b9c692
--- /dev/null
+++ b/crypto/src/asn1/x509/ObjectDigestInfo.cs
@@ -0,0 +1,177 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * 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
+        : Asn1Encodable
+    {
+		/**
+		 * The public key is hashed.
+		 */
+		public const int PublicKey = 0;
+
+		/**
+		 * The public key certificate is hashed.
+		 */
+		public const int PublicKeyCert = 1;
+
+		/**
+		 * An other object is hashed.
+		 */
+		public const int OtherObjectDigest = 2;
+
+		internal readonly DerEnumerated			digestedObjectType;
+        internal readonly DerObjectIdentifier	otherObjectTypeID;
+        internal readonly AlgorithmIdentifier	digestAlgorithm;
+        internal readonly DerBitString			objectDigest;
+
+		public static ObjectDigestInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is ObjectDigestInfo)
+            {
+                return (ObjectDigestInfo) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new ObjectDigestInfo((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public static ObjectDigestInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+        }
+
+		/**
+		 * 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.</p>
+		 * 
+		 * @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,
+			string				otherObjectTypeID,
+			AlgorithmIdentifier	digestAlgorithm,
+			byte[]				objectDigest)
+		{
+			this.digestedObjectType = new DerEnumerated(digestedObjectType);
+
+			if (digestedObjectType == OtherObjectDigest)
+			{
+				this.otherObjectTypeID = new DerObjectIdentifier(otherObjectTypeID);
+			}
+
+			this.digestAlgorithm = digestAlgorithm; 
+
+			this.objectDigest = new DerBitString(objectDigest);
+		}
+
+		private ObjectDigestInfo(
+			Asn1Sequence seq)
+        {
+			if (seq.Count > 4 || seq.Count < 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			digestedObjectType = DerEnumerated.GetInstance(seq[0]);
+
+			int offset = 0;
+
+			if (seq.Count == 4)
+            {
+                otherObjectTypeID = DerObjectIdentifier.GetInstance(seq[1]);
+                offset++;
+            }
+
+			digestAlgorithm = AlgorithmIdentifier.GetInstance(seq[1 + offset]);
+			objectDigest = DerBitString.GetInstance(seq[2 + offset]);
+		}
+
+		public DerEnumerated DigestedObjectType
+		{
+			get { return digestedObjectType; }
+		}
+
+		public DerObjectIdentifier OtherObjectTypeID
+		{
+			get { return otherObjectTypeID; }
+		}
+
+		public AlgorithmIdentifier DigestAlgorithm
+		{
+			get { return digestAlgorithm; }
+		}
+
+		public DerBitString ObjectDigest
+		{
+			get { 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 override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(digestedObjectType);
+
+			if (otherObjectTypeID != null)
+            {
+                v.Add(otherObjectTypeID);
+            }
+
+			v.Add(digestAlgorithm, objectDigest);
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/PolicyInformation.cs b/crypto/src/asn1/x509/PolicyInformation.cs
new file mode 100644
index 000000000..29d245084
--- /dev/null
+++ b/crypto/src/asn1/x509/PolicyInformation.cs
@@ -0,0 +1,80 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class PolicyInformation
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	policyIdentifier;
+        private readonly Asn1Sequence			policyQualifiers;
+
+		private PolicyInformation(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			policyIdentifier = DerObjectIdentifier.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				policyQualifiers = Asn1Sequence.GetInstance(seq[1]);
+			}
+        }
+
+		public PolicyInformation(
+            DerObjectIdentifier policyIdentifier)
+        {
+            this.policyIdentifier = policyIdentifier;
+        }
+
+		public PolicyInformation(
+            DerObjectIdentifier	policyIdentifier,
+            Asn1Sequence		policyQualifiers)
+        {
+            this.policyIdentifier = policyIdentifier;
+            this.policyQualifiers = policyQualifiers;
+        }
+
+		public static PolicyInformation GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is PolicyInformation)
+            {
+                return (PolicyInformation) obj;
+            }
+
+			return new PolicyInformation(Asn1Sequence.GetInstance(obj));
+        }
+
+		public DerObjectIdentifier PolicyIdentifier
+		{
+			get { return policyIdentifier; }
+		}
+
+		public Asn1Sequence PolicyQualifiers
+		{
+			get { return policyQualifiers; }
+		}
+
+		/*
+         * PolicyInformation ::= Sequence {
+         *      policyIdentifier   CertPolicyId,
+         *      policyQualifiers   Sequence SIZE (1..MAX) OF
+         *              PolicyQualifierInfo OPTIONAL }
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(policyIdentifier);
+
+			if (policyQualifiers != null)
+            {
+                v.Add(policyQualifiers);
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/PolicyMappings.cs b/crypto/src/asn1/x509/PolicyMappings.cs
index 928ad134d..3ad351107 100644
--- a/crypto/src/asn1/x509/PolicyMappings.cs
+++ b/crypto/src/asn1/x509/PolicyMappings.cs
@@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Asn1.X509
 			this.seq = seq;
 		}
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         public PolicyMappings(
             Hashtable mappings)
             : this((IDictionary)mappings)
diff --git a/crypto/src/asn1/x509/PolicyQualifierId.cs b/crypto/src/asn1/x509/PolicyQualifierId.cs
new file mode 100644
index 000000000..c858f0864
--- /dev/null
+++ b/crypto/src/asn1/x509/PolicyQualifierId.cs
@@ -0,0 +1,28 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * PolicyQualifierId, used in the CertificatePolicies
+	 * X509V3 extension.
+	 *
+	 * <pre>
+	 *    id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
+	 *    id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+	 *    id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+	 *  PolicyQualifierId ::=
+	 *       OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+	 * </pre>
+	 */
+	public sealed class PolicyQualifierID : DerObjectIdentifier
+	{
+		private const string IdQt = "1.3.6.1.5.5.7.2";
+
+		private PolicyQualifierID(
+			string id)
+			: base(id)
+		{
+		}
+
+		public static readonly PolicyQualifierID IdQtCps = new PolicyQualifierID(IdQt + ".1");
+		public static readonly PolicyQualifierID IdQtUnotice = new PolicyQualifierID(IdQt + ".2");
+	}
+}
diff --git a/crypto/src/asn1/x509/PolicyQualifierInfo.cs b/crypto/src/asn1/x509/PolicyQualifierInfo.cs
index 187f8d3bb..3cf6d7e10 100644
--- a/crypto/src/asn1/x509/PolicyQualifierInfo.cs
+++ b/crypto/src/asn1/x509/PolicyQualifierInfo.cs
@@ -2,90 +2,94 @@ using System;
 
 namespace Org.BouncyCastle.Asn1.X509
 {
-	/**
-	 * Policy qualifiers, used in the X509V3 CertificatePolicies
-	 * extension.
-	 *
-	 * <pre>
-	 *   PolicyQualifierInfo ::= Sequence {
-	 *       policyQualifierId  PolicyQualifierId,
-	 *       qualifier          ANY DEFINED BY policyQualifierId }
-	 * </pre>
-	 */
-	public class PolicyQualifierInfo
-		: Asn1Encodable
-	{
-		internal readonly DerObjectIdentifier	policyQualifierId;
-		internal readonly Asn1Encodable			qualifier;
+    /**
+     * Policy qualifiers, used in the X509V3 CertificatePolicies
+     * extension.
+     *
+     * <pre>
+     *   PolicyQualifierInfo ::= Sequence {
+     *       policyQualifierId  PolicyQualifierId,
+     *       qualifier          ANY DEFINED BY policyQualifierId }
+     * </pre>
+     */
+    public class PolicyQualifierInfo
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier policyQualifierId;
+        private readonly Asn1Encodable qualifier;
 
-		/**
-		 * Creates a new <code>PolicyQualifierInfo</code> instance.
-		 *
-		 * @param policyQualifierId a <code>PolicyQualifierId</code> value
-		 * @param qualifier the qualifier, defined by the above field.
-		 */
-		public PolicyQualifierInfo(
-			DerObjectIdentifier	policyQualifierId,
-			Asn1Encodable		qualifier)
-		{
-			this.policyQualifierId = policyQualifierId;
-			this.qualifier = qualifier;
-		}
+        /**
+         * Creates a new <code>PolicyQualifierInfo</code> instance.
+         *
+         * @param policyQualifierId a <code>PolicyQualifierId</code> value
+         * @param qualifier the qualifier, defined by the above field.
+         */
+        public PolicyQualifierInfo(
+            DerObjectIdentifier	policyQualifierId,
+            Asn1Encodable		qualifier)
+        {
+            this.policyQualifierId = policyQualifierId;
+            this.qualifier = qualifier;
+        }
 
-		/**
-		 * Creates a new <code>PolicyQualifierInfo</code> containing a
-		 * cPSuri qualifier.
-		 *
-		 * @param cps the CPS (certification practice statement) uri as a
-		 * <code>string</code>.
-		 */
-		public PolicyQualifierInfo(
-			string cps)
-		{
-			policyQualifierId = PolicyQualifierID.IdQtCps;
-			qualifier = new DerIA5String(cps);
-		}
+        /**
+         * Creates a new <code>PolicyQualifierInfo</code> containing a
+         * cPSuri qualifier.
+         *
+         * @param cps the CPS (certification practice statement) uri as a
+         * <code>string</code>.
+         */
+        public PolicyQualifierInfo(
+            string cps)
+        {
+            policyQualifierId = PolicyQualifierID.IdQtCps;
+            qualifier = new DerIA5String(cps);
+        }
 
-		/**
-		 * Creates a new <code>PolicyQualifierInfo</code> instance.
-		 *
-		 * @param as <code>PolicyQualifierInfo</code> X509 structure
-		 * encoded as an Asn1Sequence.
-		 */
-		private PolicyQualifierInfo(
-			Asn1Sequence seq)
-		{
-			if (seq.Count != 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+        /**
+         * Creates a new <code>PolicyQualifierInfo</code> instance.
+         *
+         * @param as <code>PolicyQualifierInfo</code> X509 structure
+         * encoded as an Asn1Sequence.
+         */
+        private PolicyQualifierInfo(
+            Asn1Sequence seq)
+        {
+            if (seq.Count != 2)
+                throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
 
-			policyQualifierId = DerObjectIdentifier.GetInstance(seq[0]);
-			qualifier = seq[1];
-		}
+            policyQualifierId = DerObjectIdentifier.GetInstance(seq[0]);
+            qualifier = seq[1];
+        }
 
-		public static PolicyQualifierInfo GetInstance(
-			object obj)
-		{
-			if (obj is PolicyQualifierInfo)
-			{
-				return (PolicyQualifierInfo) obj;
-			}
+        public static PolicyQualifierInfo GetInstance(
+            object obj)
+        {
+            if (obj is PolicyQualifierInfo)
+                return (PolicyQualifierInfo)obj;
+            if (obj == null)
+                return null;
+            return new PolicyQualifierInfo(Asn1Sequence.GetInstance(obj));
+        }
 
-			if (obj is Asn1Sequence)
-			{
-				return new PolicyQualifierInfo((Asn1Sequence) obj);
-			}
+        public virtual DerObjectIdentifier PolicyQualifierId
+        {
+            get { return policyQualifierId; }
+        }
 
-			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
-		}
+        public virtual Asn1Encodable Qualifier
+        {
+            get { return qualifier; }
+        }
 
-		/**
-		 * Returns a Der-encodable representation of this instance.
-		 *
-		 * @return a <code>Asn1Object</code> value
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			return new DerSequence(policyQualifierId, qualifier);
-		}
-	}
+        /**
+         * Returns a Der-encodable representation of this instance.
+         *
+         * @return a <code>Asn1Object</code> value
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(policyQualifierId, qualifier);
+        }
+    }
 }
diff --git a/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs b/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
new file mode 100644
index 000000000..ad2961eb0
--- /dev/null
+++ b/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
@@ -0,0 +1,82 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/// <remarks>
+	/// <pre>
+	/// PrivateKeyUsagePeriod ::= SEQUENCE
+	/// {
+	/// notBefore       [0]     GeneralizedTime OPTIONAL,
+	/// notAfter        [1]     GeneralizedTime OPTIONAL }
+	/// </pre>
+	/// </remarks>
+	public class PrivateKeyUsagePeriod
+		: Asn1Encodable
+	{
+		public static PrivateKeyUsagePeriod GetInstance(
+			object obj)
+		{
+			if (obj is PrivateKeyUsagePeriod)
+			{
+				return (PrivateKeyUsagePeriod) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PrivateKeyUsagePeriod((Asn1Sequence) obj);
+			}
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private DerGeneralizedTime _notBefore, _notAfter;
+
+		private PrivateKeyUsagePeriod(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject tObj in seq)
+			{
+				if (tObj.TagNo == 0)
+				{
+					_notBefore = DerGeneralizedTime.GetInstance(tObj, false);
+				}
+				else if (tObj.TagNo == 1)
+				{
+					_notAfter = DerGeneralizedTime.GetInstance(tObj, false);
+				}
+			}
+		}
+
+		public DerGeneralizedTime NotBefore
+		{
+			get { return _notBefore; }
+		}
+
+		public DerGeneralizedTime NotAfter
+		{
+			get { return _notAfter; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (_notBefore != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, _notBefore));
+			}
+
+			if (_notAfter != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, _notAfter));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/RSAPublicKeyStructure.cs b/crypto/src/asn1/x509/RSAPublicKeyStructure.cs
new file mode 100644
index 000000000..bdcba783e
--- /dev/null
+++ b/crypto/src/asn1/x509/RSAPublicKeyStructure.cs
@@ -0,0 +1,92 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class RsaPublicKeyStructure
+        : Asn1Encodable
+    {
+        private BigInteger modulus;
+        private BigInteger publicExponent;
+
+		public static RsaPublicKeyStructure GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static RsaPublicKeyStructure GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is RsaPublicKeyStructure)
+            {
+                return (RsaPublicKeyStructure) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new RsaPublicKeyStructure((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("Invalid RsaPublicKeyStructure: " + obj.GetType().Name);
+        }
+
+		public RsaPublicKeyStructure(
+            BigInteger	modulus,
+            BigInteger	publicExponent)
+        {
+			if (modulus == null)
+				throw new ArgumentNullException("modulus");
+			if (publicExponent == null)
+				throw new ArgumentNullException("publicExponent");
+			if (modulus.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA modulus", "modulus");
+			if (publicExponent.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA public exponent", "publicExponent");
+
+            this.modulus = modulus;
+            this.publicExponent = publicExponent;
+        }
+
+		private RsaPublicKeyStructure(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			// Note: we are accepting technically incorrect (i.e. negative) values here
+			modulus = DerInteger.GetInstance(seq[0]).PositiveValue;
+			publicExponent = DerInteger.GetInstance(seq[1]).PositiveValue;
+		}
+
+		public BigInteger Modulus
+        {
+            get { return modulus; }
+        }
+
+		public BigInteger PublicExponent
+        {
+            get { return publicExponent; }
+        }
+
+		/**
+         * This outputs the key in Pkcs1v2 format.
+         * <pre>
+         *      RSAPublicKey ::= Sequence {
+         *                          modulus Integer, -- n
+         *                          publicExponent Integer, -- e
+         *                      }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(
+				new DerInteger(Modulus),
+				new DerInteger(PublicExponent));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/ReasonFlags.cs b/crypto/src/asn1/x509/ReasonFlags.cs
new file mode 100644
index 000000000..f204c36aa
--- /dev/null
+++ b/crypto/src/asn1/x509/ReasonFlags.cs
@@ -0,0 +1,46 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The ReasonFlags object.
+     * <pre>
+     * ReasonFlags ::= BIT STRING {
+     *    unused(0),
+     *    keyCompromise(1),
+     *    cACompromise(2),
+     *    affiliationChanged(3),
+     *    superseded(4),
+     *    cessationOfOperation(5),
+     *    certficateHold(6)
+     * }
+     * </pre>
+     */
+    public class ReasonFlags
+        : DerBitString
+    {
+        public const int Unused                 = (1 << 7);
+        public const int KeyCompromise          = (1 << 6);
+        public const int CACompromise           = (1 << 5);
+        public const int AffiliationChanged     = (1 << 4);
+        public const int Superseded             = (1 << 3);
+        public const int CessationOfOperation   = (1 << 2);
+        public const int CertificateHold        = (1 << 1);
+        public const int PrivilegeWithdrawn     = (1 << 0);
+        public const 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)
+             : base(GetBytes(reasons), GetPadBits(reasons))
+        {
+        }
+
+		public ReasonFlags(
+            DerBitString reasons)
+             : base(reasons.GetBytes(), reasons.PadBits)
+        {
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/RoleSyntax.cs b/crypto/src/asn1/x509/RoleSyntax.cs
new file mode 100644
index 000000000..48c3c6cae
--- /dev/null
+++ b/crypto/src/asn1/x509/RoleSyntax.cs
@@ -0,0 +1,230 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	* Implementation of the RoleSyntax object as specified by the RFC3281.
+	*
+	* <pre>
+	* RoleSyntax ::= SEQUENCE {
+	*                 roleAuthority  [0] GeneralNames OPTIONAL,
+	*                 roleName       [1] GeneralName
+	*           }
+	* </pre>
+	*/
+	public class RoleSyntax
+		: Asn1Encodable
+	{
+		private readonly GeneralNames	roleAuthority;
+		private readonly GeneralName	roleName;
+
+		/**
+		 * RoleSyntax factory method.
+		 * @param obj the object used to construct an instance of <code>
+		 * RoleSyntax</code>. It must be an instance of <code>RoleSyntax
+		 * </code> or <code>Asn1Sequence</code>.
+		 * @return the instance of <code>RoleSyntax</code> built from the
+		 * supplied object.
+		 * @throws java.lang.ArgumentException if the object passed
+		 * to the factory is not an instance of <code>RoleSyntax</code> or
+		 * <code>Asn1Sequence</code>.
+		 */
+		public static RoleSyntax GetInstance(
+			object obj)
+		{
+			if (obj is RoleSyntax)
+				return (RoleSyntax)obj;
+
+			if (obj != null)
+				return new RoleSyntax(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		/**
+		* Constructor.
+		* @param roleAuthority the role authority of this RoleSyntax.
+		* @param roleName    the role name of this RoleSyntax.
+		*/
+		public RoleSyntax(
+			GeneralNames	roleAuthority,
+			GeneralName		roleName)
+		{
+			if (roleName == null
+				|| roleName.TagNo != GeneralName.UniformResourceIdentifier
+				|| ((IAsn1String) roleName.Name).GetString().Equals(""))
+			{
+				throw new ArgumentException("the role name MUST be non empty and MUST " +
+					"use the URI option of GeneralName");
+			}
+
+			this.roleAuthority = roleAuthority;
+			this.roleName = roleName;
+		}
+
+		/**
+		* Constructor. Invoking this constructor is the same as invoking
+		* <code>new RoleSyntax(null, roleName)</code>.
+		* @param roleName    the role name of this RoleSyntax.
+		*/
+		public RoleSyntax(
+			GeneralName roleName)
+			: this(null, roleName)
+		{
+		}
+
+		/**
+		* Utility constructor. Takes a <code>string</code> argument representing
+		* the role name, builds a <code>GeneralName</code> to hold the role name
+		* and calls the constructor that takes a <code>GeneralName</code>.
+		* @param roleName
+		*/
+		public RoleSyntax(
+			string roleName)
+			: this(new GeneralName(GeneralName.UniformResourceIdentifier,
+				(roleName == null)? "": roleName))
+		{
+		}
+
+		/**
+		* Constructor that builds an instance of <code>RoleSyntax</code> by
+		* extracting the encoded elements from the <code>Asn1Sequence</code>
+		* object supplied.
+		* @param seq    an instance of <code>Asn1Sequence</code> that holds
+		* the encoded elements used to build this <code>RoleSyntax</code>.
+		*/
+		private RoleSyntax(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1 || seq.Count > 2)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				Asn1TaggedObject taggedObject = Asn1TaggedObject.GetInstance(seq[i]);
+				switch (taggedObject.TagNo)
+				{
+					case 0:
+						roleAuthority = GeneralNames.GetInstance(taggedObject, false);
+						break;
+					case 1:
+						roleName = GeneralName.GetInstance(taggedObject, true);
+						break;
+					default:
+						throw new ArgumentException("Unknown tag in RoleSyntax");
+				}
+			}
+		}
+
+		/**
+		* Gets the role authority of this RoleSyntax.
+		* @return    an instance of <code>GeneralNames</code> holding the
+		* role authority of this RoleSyntax.
+		*/
+		public GeneralNames RoleAuthority
+		{
+			get { return this.roleAuthority; }
+		}
+
+		/**
+		* Gets the role name of this RoleSyntax.
+		* @return    an instance of <code>GeneralName</code> holding the
+		* role name of this RoleSyntax.
+		*/
+		public GeneralName RoleName
+		{
+			get { return this.roleName; }
+		}
+
+		/**
+		* Gets the role name as a <code>java.lang.string</code> object.
+		* @return    the role name of this RoleSyntax represented as a
+		* <code>string</code> object.
+		*/
+		public string GetRoleNameAsString()
+		{
+			return ((IAsn1String) this.roleName.Name).GetString();
+		}
+
+		/**
+		* Gets the role authority as a <code>string[]</code> object.
+		* @return the role authority of this RoleSyntax represented as a
+		* <code>string[]</code> array.
+		*/
+		public string[] GetRoleAuthorityAsString()
+		{
+			if (roleAuthority == null)
+			{
+				return new string[0];
+			}
+
+			GeneralName[] names = roleAuthority.GetNames();
+			string[] namesString = new string[names.Length];
+			for(int i = 0; i < names.Length; i++)
+			{
+				Asn1Encodable asn1Value = names[i].Name;
+				if (asn1Value is IAsn1String)
+				{
+					namesString[i] = ((IAsn1String) asn1Value).GetString();
+				}
+				else
+				{
+					namesString[i] = asn1Value.ToString();
+				}
+			}
+
+			return namesString;
+		}
+
+		/**
+		* Implementation of the method <code>ToAsn1Object</code> as
+		* required by the superclass <code>ASN1Encodable</code>.
+		*
+		* <pre>
+		* RoleSyntax ::= SEQUENCE {
+		*                 roleAuthority  [0] GeneralNames OPTIONAL,
+		*                 roleName       [1] GeneralName
+		*           }
+		* </pre>
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (this.roleAuthority != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, roleAuthority));
+			}
+
+			v.Add(new DerTaggedObject(true, 1, roleName));
+
+			return new DerSequence(v);
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buff = new StringBuilder("Name: " + this.GetRoleNameAsString() +
+				" - Auth: ");
+
+			if (this.roleAuthority == null || roleAuthority.GetNames().Length == 0)
+			{
+				buff.Append("N/A");
+			}
+			else
+			{
+				string[] names = this.GetRoleAuthorityAsString();
+				buff.Append('[').Append(names[0]);
+				for(int i = 1; i < names.Length; i++)
+				{
+					buff.Append(", ").Append(names[i]);
+				}
+				buff.Append(']');
+			}
+
+			return buff.ToString();
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs b/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
index c76d94d78..fcb30290d 100644
--- a/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
+++ b/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Asn1.X509
 			}
 		}
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete]
         public SubjectDirectoryAttributes(
             ArrayList attributes)
diff --git a/crypto/src/asn1/x509/SubjectKeyIdentifier.cs b/crypto/src/asn1/x509/SubjectKeyIdentifier.cs
new file mode 100644
index 000000000..e640760f3
--- /dev/null
+++ b/crypto/src/asn1/x509/SubjectKeyIdentifier.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The SubjectKeyIdentifier object.
+     * <pre>
+     * SubjectKeyIdentifier::= OCTET STRING
+     * </pre>
+     */
+    public class SubjectKeyIdentifier
+        : Asn1Encodable
+    {
+        private readonly byte[] keyIdentifier;
+
+		public static SubjectKeyIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1OctetString.GetInstance(obj, explicitly));
+        }
+
+		public static SubjectKeyIdentifier GetInstance(
+            object obj)
+        {
+            if (obj is SubjectKeyIdentifier)
+            {
+                return (SubjectKeyIdentifier) obj;
+            }
+
+			if (obj is SubjectPublicKeyInfo)
+            {
+                return new SubjectKeyIdentifier((SubjectPublicKeyInfo) obj);
+            }
+
+			if (obj is Asn1OctetString)
+            {
+                return new SubjectKeyIdentifier((Asn1OctetString) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("Invalid SubjectKeyIdentifier: " + obj.GetType().Name);
+        }
+
+		public SubjectKeyIdentifier(
+            byte[] keyID)
+        {
+			if (keyID == null)
+				throw new ArgumentNullException("keyID");
+
+			this.keyIdentifier = keyID;
+        }
+
+		public SubjectKeyIdentifier(
+            Asn1OctetString keyID)
+        {
+            this.keyIdentifier = keyID.GetOctets();
+        }
+
+		/**
+		 * Calculates the keyIdentifier using a SHA1 hash over the BIT STRING
+		 * from SubjectPublicKeyInfo as defined in RFC3280.
+		 *
+		 * @param spki the subject public key info.
+		 */
+		public SubjectKeyIdentifier(
+			SubjectPublicKeyInfo spki)
+		{
+			this.keyIdentifier = GetDigest(spki);
+		}
+
+		public byte[] GetKeyIdentifier()
+		{
+			return keyIdentifier;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerOctetString(keyIdentifier);
+		}
+
+		/**
+		 * 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.
+		 */
+		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.
+		 */
+		public static SubjectKeyIdentifier CreateTruncatedSha1KeyIdentifier(
+			SubjectPublicKeyInfo keyInfo)
+		{
+			byte[] dig = GetDigest(keyInfo);
+			byte[] id = new byte[8];
+
+			Array.Copy(dig, dig.Length - 8, id, 0, id.Length);
+
+			id[0] &= 0x0f;
+			id[0] |= 0x40;
+
+			return new SubjectKeyIdentifier(id);
+		}
+
+		private static byte[] GetDigest(
+			SubjectPublicKeyInfo spki)
+		{
+            IDigest digest = new Sha1Digest();
+            byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			byte[] bytes = spki.PublicKeyData.GetBytes();
+            digest.BlockUpdate(bytes, 0, bytes.Length);
+            digest.DoFinal(resBuf, 0);
+            return resBuf;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
new file mode 100644
index 000000000..8ce4b2762
--- /dev/null
+++ b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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.</p>
+     */
+    public class SubjectPublicKeyInfo
+        : Asn1Encodable
+    {
+        private readonly AlgorithmIdentifier	algID;
+        private readonly DerBitString			keyData;
+
+		public static SubjectPublicKeyInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static SubjectPublicKeyInfo GetInstance(
+            object obj)
+        {
+            if (obj is SubjectPublicKeyInfo)
+                return (SubjectPublicKeyInfo) obj;
+
+			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;
+        }
+
+		private SubjectPublicKeyInfo(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            this.algID = AlgorithmIdentifier.GetInstance(seq[0]);
+			this.keyData = DerBitString.GetInstance(seq[1]);
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+        {
+			get { return algID; }
+        }
+
+		/**
+         * for when the public key is an encoded object - if the bitstring
+         * can't be decoded this routine raises an IOException.
+         *
+         * @exception IOException - if the bit string doesn't represent a Der
+         * encoded object.
+         */
+        public Asn1Object GetPublicKey()
+        {
+			return Asn1Object.FromByteArray(keyData.GetBytes());
+        }
+
+		/**
+         * for when the public key is raw bits...
+         */
+        public DerBitString PublicKeyData
+        {
+			get { return keyData; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SubjectPublicKeyInfo ::= Sequence {
+         *                          algorithm AlgorithmIdentifier,
+         *                          publicKey BIT STRING }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algID, keyData);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/TBSCertList.cs b/crypto/src/asn1/x509/TBSCertList.cs
new file mode 100644
index 000000000..b5934a230
--- /dev/null
+++ b/crypto/src/asn1/x509/TBSCertList.cs
@@ -0,0 +1,274 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class CrlEntry
+		: Asn1Encodable
+	{
+		internal Asn1Sequence	seq;
+		internal DerInteger		userCertificate;
+		internal Time			revocationDate;
+		internal X509Extensions	crlEntryExtensions;
+
+		public CrlEntry(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 2 || seq.Count > 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			this.seq = seq;
+
+			userCertificate = DerInteger.GetInstance(seq[0]);
+			revocationDate = Time.GetInstance(seq[1]);
+		}
+
+		public DerInteger UserCertificate
+		{
+			get { return userCertificate; }
+		}
+
+		public Time RevocationDate
+		{
+			get { return revocationDate; }
+		}
+
+		public X509Extensions Extensions
+		{
+			get
+			{
+				if (crlEntryExtensions == null && seq.Count == 3)
+				{
+					crlEntryExtensions = X509Extensions.GetInstance(seq[2]);
+				}
+
+				return crlEntryExtensions;
+			}
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return seq;
+		}
+	}
+
+	/**
+     * 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 TbsCertificateList
+        : Asn1Encodable
+    {
+		private class RevokedCertificatesEnumeration
+			: IEnumerable
+		{
+			private readonly IEnumerable en;
+
+			internal RevokedCertificatesEnumeration(
+				IEnumerable en)
+			{
+				this.en = en;
+			}
+
+			public IEnumerator GetEnumerator()
+			{
+				return new RevokedCertificatesEnumerator(en.GetEnumerator());
+			}
+
+			private class RevokedCertificatesEnumerator
+				: IEnumerator
+			{
+				private readonly IEnumerator e;
+
+				internal RevokedCertificatesEnumerator(
+					IEnumerator e)
+				{
+					this.e = e;
+				}
+
+				public bool MoveNext()
+				{
+					return e.MoveNext();
+				}
+
+				public void Reset()
+				{
+					e.Reset();
+				}
+
+				public object Current
+				{
+					get { return new CrlEntry(Asn1Sequence.GetInstance(e.Current)); }
+				}
+			}
+		}
+
+		internal Asn1Sequence			seq;
+		internal DerInteger				version;
+        internal AlgorithmIdentifier	signature;
+        internal X509Name				issuer;
+        internal Time					thisUpdate;
+        internal Time					nextUpdate;
+		internal Asn1Sequence			revokedCertificates;
+		internal X509Extensions			crlExtensions;
+
+		public static TbsCertificateList GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static TbsCertificateList GetInstance(
+            object obj)
+        {
+            TbsCertificateList list = obj as TbsCertificateList;
+
+			if (obj == null || list != null)
+            {
+                return list;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new TbsCertificateList((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		internal TbsCertificateList(
+            Asn1Sequence seq)
+        {
+			if (seq.Count < 3 || seq.Count > 7)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			int seqPos = 0;
+
+			this.seq = seq;
+
+			if (seq[seqPos] is DerInteger)
+            {
+				version = DerInteger.GetInstance(seq[seqPos++]);
+			}
+            else
+            {
+                version = new DerInteger(0);
+            }
+
+			signature = AlgorithmIdentifier.GetInstance(seq[seqPos++]);
+            issuer = X509Name.GetInstance(seq[seqPos++]);
+            thisUpdate = Time.GetInstance(seq[seqPos++]);
+
+			if (seqPos < seq.Count
+                && (seq[seqPos] is DerUtcTime
+                   || seq[seqPos] is DerGeneralizedTime
+                   || seq[seqPos] is Time))
+            {
+                nextUpdate = Time.GetInstance(seq[seqPos++]);
+            }
+
+			if (seqPos < seq.Count
+                && !(seq[seqPos] is DerTaggedObject))
+            {
+				revokedCertificates = Asn1Sequence.GetInstance(seq[seqPos++]);
+			}
+
+			if (seqPos < seq.Count
+                && seq[seqPos] is DerTaggedObject)
+            {
+				crlExtensions = X509Extensions.GetInstance(seq[seqPos]);
+			}
+        }
+
+		public int Version
+        {
+            get { return version.Value.IntValue + 1; }
+        }
+
+		public DerInteger VersionNumber
+        {
+            get { return version; }
+        }
+
+		public AlgorithmIdentifier Signature
+        {
+            get { return signature; }
+        }
+
+		public X509Name Issuer
+        {
+            get { return issuer; }
+        }
+
+		public Time ThisUpdate
+        {
+            get { return thisUpdate; }
+        }
+
+		public Time NextUpdate
+        {
+            get { return nextUpdate; }
+        }
+
+		public CrlEntry[] GetRevokedCertificates()
+        {
+			if (revokedCertificates == null)
+			{
+				return new CrlEntry[0];
+			}
+
+			CrlEntry[] entries = new CrlEntry[revokedCertificates.Count];
+
+			for (int i = 0; i < entries.Length; i++)
+			{
+				entries[i] = new CrlEntry(Asn1Sequence.GetInstance(revokedCertificates[i]));
+			}
+
+			return entries;
+		}
+
+		public IEnumerable GetRevokedCertificateEnumeration()
+		{
+			if (revokedCertificates == null)
+			{
+				return EmptyEnumerable.Instance;
+			}
+
+			return new RevokedCertificatesEnumeration(revokedCertificates);
+		}
+
+		public X509Extensions Extensions
+        {
+            get { return crlExtensions; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/TBSCertificateStructure.cs b/crypto/src/asn1/x509/TBSCertificateStructure.cs
new file mode 100644
index 000000000..fc7c39ba2
--- /dev/null
+++ b/crypto/src/asn1/x509/TBSCertificateStructure.cs
@@ -0,0 +1,185 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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.</p>
+     */
+	public class TbsCertificateStructure
+		: Asn1Encodable
+	{
+		internal Asn1Sequence            seq;
+		internal DerInteger              version;
+		internal DerInteger              serialNumber;
+		internal AlgorithmIdentifier     signature;
+		internal X509Name                issuer;
+		internal Time                    startDate, endDate;
+		internal X509Name                subject;
+		internal SubjectPublicKeyInfo    subjectPublicKeyInfo;
+		internal DerBitString            issuerUniqueID;
+		internal DerBitString            subjectUniqueID;
+		internal X509Extensions          extensions;
+
+		public static TbsCertificateStructure GetInstance(
+			Asn1TaggedObject	obj,
+			bool				explicitly)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+		}
+
+		public static TbsCertificateStructure GetInstance(
+			object obj)
+		{
+			if (obj is TbsCertificateStructure)
+				return (TbsCertificateStructure) obj;
+
+			if (obj != null)
+				return new TbsCertificateStructure(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		internal TbsCertificateStructure(
+			Asn1Sequence seq)
+		{
+			int seqStart = 0;
+
+			this.seq = seq;
+
+			//
+			// some certficates don't include a version number - we assume v1
+			//
+			if (seq[0] is DerTaggedObject)
+			{
+				version = DerInteger.GetInstance((Asn1TaggedObject)seq[0], true);
+			}
+			else
+			{
+				seqStart = -1;          // field 0 is missing!
+				version = new DerInteger(0);
+			}
+
+			serialNumber = DerInteger.GetInstance(seq[seqStart + 1]);
+
+			signature = AlgorithmIdentifier.GetInstance(seq[seqStart + 2]);
+			issuer = X509Name.GetInstance(seq[seqStart + 3]);
+
+			//
+			// before and after dates
+			//
+			Asn1Sequence  dates = (Asn1Sequence)seq[seqStart + 4];
+
+			startDate = Time.GetInstance(dates[0]);
+			endDate = Time.GetInstance(dates[1]);
+
+			subject = X509Name.GetInstance(seq[seqStart + 5]);
+
+			//
+			// public key info.
+			//
+			subjectPublicKeyInfo = SubjectPublicKeyInfo.GetInstance(seq[seqStart + 6]);
+
+			for (int extras = seq.Count - (seqStart + 6) - 1; extras > 0; extras--)
+			{
+				DerTaggedObject extra = (DerTaggedObject) seq[seqStart + 6 + extras];
+
+				switch (extra.TagNo)
+				{
+					case 1:
+						issuerUniqueID = DerBitString.GetInstance(extra, false);
+						break;
+					case 2:
+						subjectUniqueID = DerBitString.GetInstance(extra, false);
+						break;
+					case 3:
+						extensions = X509Extensions.GetInstance(extra);
+						break;
+				}
+			}
+		}
+
+		public int Version
+		{
+			get { return version.Value.IntValue + 1; }
+		}
+
+		public DerInteger VersionNumber
+		{
+			get { return version; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public AlgorithmIdentifier Signature
+		{
+			get { return signature; }
+		}
+
+		public X509Name Issuer
+		{
+			get { return issuer; }
+		}
+
+		public Time StartDate
+		{
+			get { return startDate; }
+		}
+
+		public Time EndDate
+		{
+			get { return endDate; }
+		}
+
+		public X509Name Subject
+		{
+			get { return subject; }
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+		{
+			get { return subjectPublicKeyInfo; }
+		}
+
+		public DerBitString IssuerUniqueID
+		{
+			get { return issuerUniqueID; }
+        }
+
+		public DerBitString SubjectUniqueID
+        {
+			get { return subjectUniqueID; }
+        }
+
+		public X509Extensions Extensions
+        {
+			get { return extensions; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/Target.cs b/crypto/src/asn1/x509/Target.cs
new file mode 100644
index 000000000..309b28c95
--- /dev/null
+++ b/crypto/src/asn1/x509/Target.cs
@@ -0,0 +1,139 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Target structure used in target information extension for attribute
+	 * certificates from RFC 3281.
+	 * 
+	 * <pre>
+	 *     Target  ::= CHOICE {
+	 *       targetName          [0] GeneralName,
+	 *       targetGroup         [1] GeneralName,
+	 *       targetCert          [2] TargetCert
+	 *     }
+	 * </pre>
+	 * 
+	 * <p>
+	 * The targetCert field is currently not supported and must not be used
+	 * according to RFC 3281.</p>
+	 */
+	public class Target
+		: Asn1Encodable, IAsn1Choice
+	{
+		public enum Choice
+		{
+			Name = 0,
+			Group = 1
+		};
+
+		private readonly GeneralName targetName;
+		private readonly GeneralName targetGroup;
+
+		/**
+		* Creates an instance of a Target from the given object.
+		* <p>
+		* <code>obj</code> can be a Target or a {@link Asn1TaggedObject}</p>
+		* 
+		* @param obj The object.
+		* @return A Target instance.
+		* @throws ArgumentException if the given object cannot be
+		*             interpreted as Target.
+		*/
+		public static Target GetInstance(
+			object obj)
+		{
+			if (obj is Target)
+			{
+				return (Target) obj;
+			}
+
+			if (obj is Asn1TaggedObject)
+			{
+				return new Target((Asn1TaggedObject) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1TaggedObject.
+		 * 
+		 * @param tagObj The tagged object.
+		 * @throws ArgumentException if the encoding is wrong.
+		 */
+		private Target(
+			Asn1TaggedObject tagObj)
+		{
+			switch ((Choice) tagObj.TagNo)
+			{
+				case Choice.Name:	// GeneralName is already a choice so explicit
+					targetName = GeneralName.GetInstance(tagObj, true);
+					break;
+				case Choice.Group:
+					targetGroup = GeneralName.GetInstance(tagObj, true);
+					break;
+				default:
+					throw new ArgumentException("unknown tag: " + tagObj.TagNo);
+			}
+		}
+
+		/**
+		 * Constructor from given details.
+		 * <p>
+		 * Exactly one of the parameters must be not <code>null</code>.</p>
+		 *
+		 * @param type the choice type to apply to the name.
+		 * @param name the general name.
+		 * @throws ArgumentException if type is invalid.
+		 */
+		public Target(
+			Choice		type,
+			GeneralName	name)
+			: this(new DerTaggedObject((int) type, name))
+		{
+		}
+
+		/**
+		 * @return Returns the targetGroup.
+		 */
+		public virtual GeneralName TargetGroup
+		{
+			get { return targetGroup; }
+		}
+
+		/**
+		 * @return Returns the targetName.
+		 */
+		public virtual GeneralName TargetName
+		{
+			get { return targetName; }
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *     Target  ::= CHOICE {
+		 *       targetName          [0] GeneralName,
+		 *       targetGroup         [1] GeneralName,
+		 *       targetCert          [2] TargetCert
+		 *     }
+		 * </pre>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			// GeneralName is a choice already so most be explicitly tagged
+			if (targetName != null)
+			{
+				return new DerTaggedObject(true, 0, targetName);
+			}
+
+			return new DerTaggedObject(true, 1, targetGroup);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/TargetInformation.cs b/crypto/src/asn1/x509/TargetInformation.cs
new file mode 100644
index 000000000..75b18c0c9
--- /dev/null
+++ b/crypto/src/asn1/x509/TargetInformation.cs
@@ -0,0 +1,123 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Target information extension for attributes certificates according to RFC
+	 * 3281.
+	 * 
+	 * <pre>
+	 *           SEQUENCE OF Targets
+	 * </pre>
+	 * 
+	 */
+	public class TargetInformation
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence targets;
+
+		/**
+		 * Creates an instance of a TargetInformation from the given object.
+		 * <p>
+		 * <code>obj</code> can be a TargetInformation or a {@link Asn1Sequence}</p>
+		 * 
+		 * @param obj The object.
+		 * @return A TargetInformation instance.
+		 * @throws ArgumentException if the given object cannot be interpreted as TargetInformation.
+		 */
+		public static TargetInformation GetInstance(
+			object obj)
+		{
+			if (obj is TargetInformation)
+			{
+				return (TargetInformation) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new TargetInformation((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from a Asn1Sequence.
+		 * 
+		 * @param seq The Asn1Sequence.
+		 * @throws ArgumentException if the sequence does not contain
+		 *             correctly encoded Targets elements.
+		 */
+		private TargetInformation(
+			Asn1Sequence targets)
+		{
+			this.targets = targets;
+		}
+
+		/**
+		 * Returns the targets in this target information extension.
+		 * <p>
+		 * The ArrayList is cloned before it is returned.</p>
+		 * 
+		 * @return Returns the targets.
+		 */
+		public virtual Targets[] GetTargetsObjects()
+		{
+			Targets[] result = new Targets[targets.Count];
+
+			for (int i = 0; i < targets.Count; ++i)
+			{
+				result[i] = Targets.GetInstance(targets[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		 * Constructs a target information from a single targets element. 
+		 * According to RFC 3281 only one targets element must be produced.
+		 * 
+		 * @param targets A Targets instance.
+		 */
+		public TargetInformation(
+			Targets targets)
+		{
+			this.targets = new DerSequence(targets);
+		}
+
+		/**
+		 * According to RFC 3281 only one targets element must be produced. If
+		 * multiple targets are given they must be merged in
+		 * into one targets element.
+		 *
+		 * @param targets An array with {@link Targets}.
+		 */
+		public TargetInformation(
+			Target[] targets)
+			: this(new Targets(targets))
+		{
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *          SEQUENCE OF Targets
+		 * </pre>
+		 * 
+		 * <p>
+		 * According to RFC 3281 only one targets element must be produced. If
+		 * multiple targets are given in the constructor they are merged into one
+		 * targets element. If this was produced from a
+		 * {@link Org.BouncyCastle.Asn1.Asn1Sequence} the encoding is kept.</p>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return targets;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/Targets.cs b/crypto/src/asn1/x509/Targets.cs
new file mode 100644
index 000000000..3e436d8d8
--- /dev/null
+++ b/crypto/src/asn1/x509/Targets.cs
@@ -0,0 +1,121 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * Targets structure used in target information extension for attribute
+	 * certificates from RFC 3281.
+	 * 
+	 * <pre>
+	 *            Targets ::= SEQUENCE OF Target
+	 *           
+	 *            Target  ::= CHOICE {
+	 *              targetName          [0] GeneralName,
+	 *              targetGroup         [1] GeneralName,
+	 *              targetCert          [2] TargetCert
+	 *            }
+	 *           
+	 *            TargetCert  ::= SEQUENCE {
+	 *              targetCertificate    IssuerSerial,
+	 *              targetName           GeneralName OPTIONAL,
+	 *              certDigestInfo       ObjectDigestInfo OPTIONAL
+	 *            }
+	 * </pre>
+	 * 
+	 * @see org.bouncycastle.asn1.x509.Target
+	 * @see org.bouncycastle.asn1.x509.TargetInformation
+	 */
+	public class Targets
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence targets;
+
+		/**
+		 * Creates an instance of a Targets from the given object.
+		 * <p>
+		 * <code>obj</code> can be a Targets or a {@link Asn1Sequence}</p>
+		 * 
+		 * @param obj The object.
+		 * @return A Targets instance.
+		 * @throws ArgumentException if the given object cannot be interpreted as Target.
+		 */
+		public static Targets GetInstance(
+			object obj)
+		{
+			if (obj is Targets)
+			{
+				return (Targets) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new Targets((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1Sequence.
+		 * 
+		 * @param targets The ASN.1 SEQUENCE.
+		 * @throws ArgumentException if the contents of the sequence are
+		 *             invalid.
+		 */
+		private Targets(
+			Asn1Sequence targets)
+		{
+			this.targets = targets;
+		}
+
+		/**
+		 * Constructor from given targets.
+		 * <p>
+		 * The ArrayList is copied.</p>
+		 * 
+		 * @param targets An <code>ArrayList</code> of {@link Target}s.
+		 * @see Target
+		 * @throws ArgumentException if the ArrayList contains not only Targets.
+		 */
+		public Targets(
+			Target[] targets)
+		{
+			this.targets = new DerSequence(targets);
+		}
+
+		/**
+		 * Returns the targets in an <code>ArrayList</code>.
+		 * <p>
+		 * The ArrayList is cloned before it is returned.</p>
+		 * 
+		 * @return Returns the targets.
+		 */
+		public virtual Target[] GetTargets()
+		{
+			Target[] result = new Target[targets.Count];
+
+			for (int i = 0; i < targets.Count; ++i)
+			{
+				result[i] = Target.GetInstance(targets[i]);
+			}
+
+			return result;
+		}
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 * 
+		 * Returns:
+		 * 
+		 * <pre>
+		 *            Targets ::= SEQUENCE OF Target
+		 * </pre>
+		 * 
+		 * @return an Asn1Object
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			return targets;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/Time.cs b/crypto/src/asn1/x509/Time.cs
index ca4e99ac7..0f2511e6d 100644
--- a/crypto/src/asn1/x509/Time.cs
+++ b/crypto/src/asn1/x509/Time.cs
@@ -7,28 +7,28 @@ namespace Org.BouncyCastle.Asn1.X509
     {
         internal Asn1Object time;
 
-		public static Time GetInstance(
+        public static Time GetInstance(
             Asn1TaggedObject	obj,
             bool				explicitly)
         {
             return GetInstance(obj.GetObject());
         }
 
-		public Time(
+        public Time(
             Asn1Object time)
         {
-			if (time == null)
-				throw new ArgumentNullException("time");
+            if (time == null)
+                throw new ArgumentNullException("time");
 
-			if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
+            if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
             {
                 throw new ArgumentException("unknown object passed to Time");
             }
 
-			this.time = 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.
@@ -38,9 +38,9 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             string d = date.ToString("yyyyMMddHHmmss") + "Z";
 
-			int year = Int32.Parse(d.Substring(0, 4));
+            int year = Int32.Parse(d.Substring(0, 4));
 
-			if (year < 1950 || year > 2049)
+            if (year < 1950 || year > 2049)
             {
                 time = new DerGeneralizedTime(d);
             }
@@ -50,56 +50,56 @@ namespace Org.BouncyCastle.Asn1.X509
             }
         }
 
-		public static Time GetInstance(
+        public static Time GetInstance(
             object obj)
         {
             if (obj == null || obj is Time)
                 return (Time) obj;
 
-			if (obj is DerUtcTime)
+            if (obj is DerUtcTime)
                 return new Time((DerUtcTime) obj);
 
-			if (obj is DerGeneralizedTime)
+            if (obj is DerGeneralizedTime)
                 return new Time((DerGeneralizedTime) obj);
 
-			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+            throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
         }
 
-		public string GetTime()
+        public string GetTime()
         {
             if (time is DerUtcTime)
             {
                 return ((DerUtcTime) time).AdjustedTimeString;
             }
 
-			return ((DerGeneralizedTime) time).GetTime();
+            return ((DerGeneralizedTime) time).GetTime();
         }
 
-		/// <summary>
+        /// <summary>
         /// Return our time as DateTime.
         /// </summary>
         /// <returns>A date time.</returns>
         public DateTime ToDateTime()
         {
-			try
-			{
-				if (time is DerUtcTime)
-				{
-					return ((DerUtcTime)time).ToAdjustedDateTime();
-				}
-				else
-				{
-					return ((DerGeneralizedTime)time).ToDateTime();
-				}
-			}
-			catch (FormatException e)
-			{
-				// this should never happen
-				throw new InvalidOperationException("invalid date string: " + e.Message);
-			}
+            try
+            {
+                if (time is DerUtcTime)
+                {
+                    return ((DerUtcTime)time).ToAdjustedDateTime();
+                }
+                else
+                {
+                    return ((DerGeneralizedTime)time).ToDateTime();
+                }
+            }
+            catch (FormatException e)
+            {
+                // this should never happen
+                throw new InvalidOperationException("invalid date string: " + e.Message);
+            }
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          * Time ::= CHOICE {
@@ -112,9 +112,9 @@ namespace Org.BouncyCastle.Asn1.X509
             return time;
         }
 
-		public override string ToString()
-		{
-			return GetTime();
-		}
-	}
+        public override string ToString()
+        {
+            return GetTime();
+        }
+    }
 }
diff --git a/crypto/src/asn1/x509/UserNotice.cs b/crypto/src/asn1/x509/UserNotice.cs
index 2878a180f..5938f7c49 100644
--- a/crypto/src/asn1/x509/UserNotice.cs
+++ b/crypto/src/asn1/x509/UserNotice.cs
@@ -19,10 +19,10 @@ namespace Org.BouncyCastle.Asn1.X509
     public class UserNotice
         : Asn1Encodable
     {
-        internal NoticeReference	noticeRef;
-        internal DisplayText		explicitText;
+        private readonly NoticeReference noticeRef;
+        private readonly DisplayText explicitText;
 
-		/**
+        /**
          * Creates a new <code>UserNotice</code> instance.
          *
          * @param noticeRef a <code>NoticeReference</code> value
@@ -36,7 +36,7 @@ namespace Org.BouncyCastle.Asn1.X509
             this.explicitText = explicitText;
         }
 
-		/**
+        /**
          * Creates a new <code>UserNotice</code> instance.
          *
          * @param noticeRef a <code>NoticeReference</code> value
@@ -45,60 +45,78 @@ namespace Org.BouncyCastle.Asn1.X509
         public UserNotice(
             NoticeReference	noticeRef,
             string			str)
+            : this(noticeRef, new DisplayText(str))
         {
-            this.noticeRef = noticeRef;
-            this.explicitText = new DisplayText(str);
         }
 
-		/**
-		 * Creates a new <code>UserNotice</code> instance.
-		 * <p>Useful from reconstructing a <code>UserNotice</code> instance
-		 * from its encodable/encoded form.
-		 *
-		 * @param as an <code>ASN1Sequence</code> value obtained from either
-		 * calling @{link toASN1Object()} for a <code>UserNotice</code>
-		 * instance or from parsing it from a DER-encoded stream.</p>
-		 */
-		public UserNotice(
-			Asn1Sequence seq)
-		{
-			if (seq.Count == 2)
-			{
-				noticeRef = NoticeReference.GetInstance(seq[0]);
-				explicitText = DisplayText.GetInstance(seq[1]);
-			}
-			else if (seq.Count == 1)
-			{
-				if (seq[0].ToAsn1Object() is Asn1Sequence)
-				{
-					noticeRef = NoticeReference.GetInstance(seq[0]);
-				}
-				else
-				{
-					explicitText = DisplayText.GetInstance(seq[0]);
-				}
-			}
-			else
-			{
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
-			}
+        /**
+         * Creates a new <code>UserNotice</code> instance.
+         * <p>Useful from reconstructing a <code>UserNotice</code> instance
+         * from its encodable/encoded form.
+         *
+         * @param as an <code>ASN1Sequence</code> value obtained from either
+         * calling @{link toASN1Object()} for a <code>UserNotice</code>
+         * instance or from parsing it from a DER-encoded stream.</p>
+         */
+        public UserNotice(
+            Asn1Sequence seq)
+        {
+            if (seq.Count == 2)
+            {
+                noticeRef = NoticeReference.GetInstance(seq[0]);
+                explicitText = DisplayText.GetInstance(seq[1]);
+            }
+            else if (seq.Count == 1)
+            {
+                if (seq[0].ToAsn1Object() is Asn1Sequence)
+                {
+                    noticeRef = NoticeReference.GetInstance(seq[0]);
+                }
+                else
+                {
+                    explicitText = DisplayText.GetInstance(seq[0]);
+                }
+            }
+            else
+            {
+                throw new ArgumentException("Bad sequence size: " + seq.Count);
+            }
+        }
+
+        public static UserNotice GetInstance(object obj)
+        {
+            if (obj is UserNotice)
+                return (UserNotice)obj;
+            if (obj == null)
+                return null;
+            return new UserNotice(Asn1Sequence.GetInstance(obj));
+        }
+
+        public virtual NoticeReference NoticeRef
+        {
+            get { return noticeRef; }
+        }
+
+        public virtual DisplayText ExplicitText
+        {
+            get { return explicitText; }
         }
 
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector av = new Asn1EncodableVector();
 
-			if (noticeRef != null)
+            if (noticeRef != null)
             {
                 av.Add(noticeRef);
             }
 
-			if (explicitText != null)
+            if (explicitText != null)
             {
                 av.Add(explicitText);
             }
 
-			return new DerSequence(av);
+            return new DerSequence(av);
         }
     }
 }
diff --git a/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs b/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
new file mode 100644
index 000000000..20b525a48
--- /dev/null
+++ b/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
@@ -0,0 +1,108 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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
+    {
+        internal DerTaggedObject		version = new DerTaggedObject(0, new DerInteger(0));
+        internal DerInteger				serialNumber;
+        internal AlgorithmIdentifier	signature;
+        internal X509Name				issuer;
+        internal Time					startDate, endDate;
+        internal X509Name				subject;
+        internal SubjectPublicKeyInfo	subjectPublicKeyInfo;
+
+		public V1TbsCertificateGenerator()
+        {
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name 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);
+        }
+
+		public void SetSubject(
+            X509Name subject)
+        {
+            this.subject = subject;
+        }
+
+		public void SetSubjectPublicKeyInfo(
+            SubjectPublicKeyInfo pubKeyInfo)
+        {
+            this.subjectPublicKeyInfo = pubKeyInfo;
+        }
+
+		public TbsCertificateStructure GenerateTbsCertificate()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+                || (subject == null) || (subjectPublicKeyInfo == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V1 TBScertificate generator");
+            }
+
+			return new TbsCertificateStructure(
+				new DerSequence(
+					//version, - not required as default value
+					serialNumber,
+					signature,
+					issuer,
+					new DerSequence(startDate, endDate), // before and after dates
+					subject,
+					subjectPublicKeyInfo));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs b/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
new file mode 100644
index 000000000..02580b5b8
--- /dev/null
+++ b/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
@@ -0,0 +1,137 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 2 AttributeCertificateInfo
+     * <pre>
+     * AttributeCertificateInfo ::= Sequence {
+     *       version              AttCertVersion -- version is v2,
+     *       holder               Holder,
+     *       issuer               AttCertIssuer,
+     *       signature            AlgorithmIdentifier,
+     *       serialNumber         CertificateSerialNumber,
+     *       attrCertValidityPeriod   AttCertValidityPeriod,
+     *       attributes           Sequence OF Attr,
+     *       issuerUniqueID       UniqueIdentifier OPTIONAL,
+     *       extensions           Extensions OPTIONAL
+     * }
+     * </pre>
+     *
+     */
+    public class V2AttributeCertificateInfoGenerator
+    {
+        internal DerInteger				version;
+        internal Holder					holder;
+        internal AttCertIssuer			issuer;
+        internal AlgorithmIdentifier	signature;
+        internal DerInteger				serialNumber;
+//        internal AttCertValidityPeriod	attrCertValidityPeriod;
+        internal Asn1EncodableVector	attributes;
+        internal DerBitString			issuerUniqueID;
+        internal X509Extensions			extensions;
+        internal DerGeneralizedTime		startDate, endDate;
+
+		public V2AttributeCertificateInfoGenerator()
+        {
+            this.version = new DerInteger(1);
+            attributes = new Asn1EncodableVector();
+        }
+
+		public void SetHolder(
+			Holder holder)
+        {
+            this.holder = holder;
+        }
+
+		public void AddAttribute(
+			string			oid,
+			Asn1Encodable	value)
+        {
+            attributes.Add(new AttributeX509(new DerObjectIdentifier(oid), new DerSet(value)));
+        }
+
+		/**
+         * @param attribute
+         */
+        public void AddAttribute(AttributeX509 attribute)
+        {
+            attributes.Add(attribute);
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            AttCertIssuer issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetStartDate(
+            DerGeneralizedTime startDate)
+        {
+            this.startDate = startDate;
+        }
+
+		public void SetEndDate(
+            DerGeneralizedTime endDate)
+        {
+            this.endDate = endDate;
+        }
+
+		public void SetIssuerUniqueID(
+            DerBitString issuerUniqueID)
+        {
+            this.issuerUniqueID = issuerUniqueID;
+        }
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+        }
+
+		public AttributeCertificateInfo GenerateAttributeCertificateInfo()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+                || (holder == null) || (attributes == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V2 AttributeCertificateInfo generator");
+            }
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, holder, issuer, signature, serialNumber);
+
+			//
+            // before and after dates => AttCertValidityPeriod
+            //
+            v.Add(new AttCertValidityPeriod(startDate, endDate));
+
+			// Attributes
+            v.Add(new DerSequence(attributes));
+
+			if (issuerUniqueID != null)
+            {
+                v.Add(issuerUniqueID);
+            }
+
+			if (extensions != null)
+            {
+                v.Add(extensions);
+            }
+
+			return AttributeCertificateInfo.GetInstance(new DerSequence(v));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V2Form.cs b/crypto/src/asn1/x509/V2Form.cs
index a9c43357c..2c6e54a77 100644
--- a/crypto/src/asn1/x509/V2Form.cs
+++ b/crypto/src/asn1/x509/V2Form.cs
@@ -9,55 +9,67 @@ namespace Org.BouncyCastle.Asn1.X509
         internal IssuerSerial        baseCertificateID;
         internal ObjectDigestInfo    objectDigestInfo;
 
-		public static V2Form GetInstance(
+        public static V2Form GetInstance(
             Asn1TaggedObject	obj,
             bool				explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static V2Form GetInstance(
-            object obj)
+        public static V2Form GetInstance(object obj)
         {
             if (obj is V2Form)
-            {
-                return (V2Form) obj;
-            }
+                return (V2Form)obj;
+            if (obj != null)
+                return new V2Form(Asn1Sequence.GetInstance(obj));
+            return null;
+        }
 
-			if (obj is Asn1Sequence)
-            {
-                return new V2Form((Asn1Sequence) obj);
-            }
+        public V2Form(GeneralNames issuerName)
+            : this(issuerName, null, null)
+        {
+        }
+
+        public V2Form(GeneralNames issuerName, IssuerSerial baseCertificateID)
+            : this(issuerName, baseCertificateID, null)
+        {
+        }
 
-			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        public V2Form(GeneralNames issuerName, ObjectDigestInfo objectDigestInfo)
+            : this(issuerName, null, objectDigestInfo)
+        {
         }
 
-		public V2Form(
-            GeneralNames issuerName)
+        public V2Form(
+            GeneralNames issuerName,
+            IssuerSerial baseCertificateID,
+            ObjectDigestInfo objectDigestInfo)
         {
             this.issuerName = issuerName;
+            this.baseCertificateID = baseCertificateID;
+            this.objectDigestInfo = objectDigestInfo;
         }
 
-		private V2Form(
+        private V2Form(
             Asn1Sequence seq)
         {
-			if (seq.Count > 3)
-			{
-				throw new ArgumentException("Bad sequence size: " + seq.Count);
-			}
+            if (seq.Count > 3)
+            {
+                throw new ArgumentException("Bad sequence size: " + seq.Count);
+            }
 
-			int index = 0;
+            int index = 0;
 
-			if (!(seq[0] is Asn1TaggedObject))
+            if (!(seq[0] is Asn1TaggedObject))
             {
                 index++;
                 this.issuerName = GeneralNames.GetInstance(seq[0]);
             }
 
-			for (int i = index; i != seq.Count; i++)
+            for (int i = index; i != seq.Count; i++)
             {
-				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
-				if (o.TagNo == 0)
+                Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+                if (o.TagNo == 0)
                 {
                     baseCertificateID = IssuerSerial.GetInstance(o, false);
                 }
@@ -65,29 +77,29 @@ namespace Org.BouncyCastle.Asn1.X509
                 {
                     objectDigestInfo = ObjectDigestInfo.GetInstance(o, false);
                 }
-				else
-				{
-					throw new ArgumentException("Bad tag number: " + o.TagNo);
-				}
-			}
+                else
+                {
+                    throw new ArgumentException("Bad tag number: " + o.TagNo);
+                }
+            }
         }
 
-		public GeneralNames IssuerName
+        public GeneralNames IssuerName
         {
             get { return issuerName; }
         }
 
-		public IssuerSerial BaseCertificateID
+        public IssuerSerial BaseCertificateID
         {
             get { return baseCertificateID; }
         }
 
-		public ObjectDigestInfo ObjectDigestInfo
+        public ObjectDigestInfo ObjectDigestInfo
         {
             get { return objectDigestInfo; }
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  V2Form ::= Sequence {
@@ -104,22 +116,22 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             Asn1EncodableVector v = new Asn1EncodableVector();
 
-			if (issuerName != null)
+            if (issuerName != null)
             {
                 v.Add(issuerName);
             }
 
-			if (baseCertificateID != null)
+            if (baseCertificateID != null)
             {
                 v.Add(new DerTaggedObject(false, 0, baseCertificateID));
             }
 
-			if (objectDigestInfo != null)
+            if (objectDigestInfo != null)
             {
                 v.Add(new DerTaggedObject(false, 1, objectDigestInfo));
             }
 
-			return new DerSequence(v);
+            return new DerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/x509/V2TBSCertListGenerator.cs b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
new file mode 100644
index 000000000..2c929188f
--- /dev/null
+++ b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * Generator for Version 2 TbsCertList structures.
+     * <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>
+     *
+     * <b>Note: This class may be subject to change</b>
+     */
+    public class V2TbsCertListGenerator
+    {
+        private DerInteger			version = new DerInteger(1);
+        private AlgorithmIdentifier	signature;
+        private X509Name			issuer;
+        private Time				thisUpdate, nextUpdate;
+        private X509Extensions		extensions;
+        private IList			    crlEntries;
+
+		public V2TbsCertListGenerator()
+        {
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name issuer)
+        {
+            this.issuer = issuer;
+        }
+
+		public void SetThisUpdate(
+            DerUtcTime thisUpdate)
+        {
+            this.thisUpdate = new Time(thisUpdate);
+        }
+
+		public void SetNextUpdate(
+            DerUtcTime nextUpdate)
+        {
+            this.nextUpdate = (nextUpdate != null)
+				?	new Time(nextUpdate)
+				:	null;
+        }
+
+		public void SetThisUpdate(
+            Time thisUpdate)
+        {
+            this.thisUpdate = thisUpdate;
+        }
+
+		public void SetNextUpdate(
+            Time nextUpdate)
+        {
+            this.nextUpdate = nextUpdate;
+        }
+
+		public void AddCrlEntry(
+			Asn1Sequence crlEntry)
+		{
+			if (crlEntries == null)
+			{
+				crlEntries = Platform.CreateArrayList();
+			}
+
+			crlEntries.Add(crlEntry);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, DerUtcTime revocationDate, int reason)
+		{
+			AddCrlEntry(userCertificate, new Time(revocationDate), reason);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason)
+		{
+			AddCrlEntry(userCertificate, revocationDate, reason, null);
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason,
+			DerGeneralizedTime invalidityDate)
+		{
+            IList extOids = Platform.CreateArrayList();
+            IList extValues = Platform.CreateArrayList();
+
+			if (reason != 0)
+			{
+				CrlReason crlReason = new CrlReason(reason);
+
+				try
+				{
+					extOids.Add(X509Extensions.ReasonCode);
+					extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
+				}
+				catch (IOException e)
+				{
+					throw new ArgumentException("error encoding reason: " + e);
+				}
+			}
+
+			if (invalidityDate != null)
+			{
+				try
+				{
+					extOids.Add(X509Extensions.InvalidityDate);
+					extValues.Add(new X509Extension(false, new DerOctetString(invalidityDate.GetEncoded())));
+				}
+				catch (IOException e)
+				{
+					throw new ArgumentException("error encoding invalidityDate: " + e);
+				}
+			}
+
+			if (extOids.Count != 0)
+			{
+				AddCrlEntry(userCertificate, revocationDate, new X509Extensions(extOids, extValues));
+			}
+			else
+			{
+				AddCrlEntry(userCertificate, revocationDate, null);
+			}
+		}
+
+		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, X509Extensions extensions)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				userCertificate, revocationDate);
+
+			if (extensions != null)
+			{
+				v.Add(extensions);
+			}
+
+			AddCrlEntry(new DerSequence(v));
+		}
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+        }
+
+		public TbsCertificateList GenerateTbsCertList()
+        {
+            if ((signature == null) || (issuer == null) || (thisUpdate == null))
+            {
+                throw new InvalidOperationException("Not all mandatory fields set in V2 TbsCertList generator.");
+            }
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, signature, issuer, thisUpdate);
+
+			if (nextUpdate != null)
+            {
+                v.Add(nextUpdate);
+            }
+
+			// Add CRLEntries if they exist
+            if (crlEntries != null)
+            {
+                Asn1Sequence[] certs = new Asn1Sequence[crlEntries.Count];
+                for (int i = 0; i < crlEntries.Count; ++i)
+                {
+                    certs[i] = (Asn1Sequence)crlEntries[i];
+                }
+				v.Add(new DerSequence(certs));
+            }
+
+			if (extensions != null)
+            {
+                v.Add(new DerTaggedObject(0, extensions));
+            }
+
+			return new TbsCertificateList(new DerSequence(v));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs b/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
new file mode 100644
index 000000000..beb469a0d
--- /dev/null
+++ b/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
@@ -0,0 +1,168 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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
+    {
+        internal DerTaggedObject         version = new DerTaggedObject(0, new DerInteger(2));
+        internal DerInteger              serialNumber;
+        internal AlgorithmIdentifier     signature;
+        internal X509Name                issuer;
+        internal Time                    startDate, endDate;
+        internal X509Name                subject;
+        internal SubjectPublicKeyInfo    subjectPublicKeyInfo;
+        internal X509Extensions          extensions;
+
+		private bool altNamePresentAndCritical;
+		private DerBitString issuerUniqueID;
+		private DerBitString subjectUniqueID;
+
+		public V3TbsCertificateGenerator()
+        {
+        }
+
+		public void SetSerialNumber(
+            DerInteger serialNumber)
+        {
+            this.serialNumber = serialNumber;
+        }
+
+		public void SetSignature(
+            AlgorithmIdentifier signature)
+        {
+            this.signature = signature;
+        }
+
+		public void SetIssuer(
+            X509Name 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;
+        }
+
+		public void SetSubject(
+            X509Name 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;
+        }
+
+		public void SetExtensions(
+            X509Extensions extensions)
+        {
+            this.extensions = extensions;
+
+			if (extensions != null)
+			{
+				X509Extension altName = extensions.GetExtension(X509Extensions.SubjectAlternativeName);
+
+				if (altName != null && altName.IsCritical)
+				{
+					altNamePresentAndCritical = true;
+				}
+			}
+		}
+
+		public TbsCertificateStructure GenerateTbsCertificate()
+        {
+            if ((serialNumber == null) || (signature == null)
+                || (issuer == null) || (startDate == null) || (endDate == null)
+				|| (subject == null && !altNamePresentAndCritical)
+				|| (subjectPublicKeyInfo == null))
+            {
+                throw new InvalidOperationException("not all mandatory fields set in V3 TBScertificate generator");
+            }
+
+			DerSequence validity = new DerSequence(startDate, endDate); // before and after dates
+
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				version, serialNumber, signature, issuer, validity);
+
+			if (subject != null)
+			{
+				v.Add(subject);
+			}
+			else
+			{
+				v.Add(DerSequence.Empty);
+			}
+
+			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(3, extensions));
+            }
+
+			return new TbsCertificateStructure(new DerSequence(v));
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/X509Attributes.cs b/crypto/src/asn1/x509/X509Attributes.cs
new file mode 100644
index 000000000..291329a62
--- /dev/null
+++ b/crypto/src/asn1/x509/X509Attributes.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class X509Attributes
+	{
+		public static readonly DerObjectIdentifier RoleSyntax = new DerObjectIdentifier("2.5.4.72");
+	}
+}
diff --git a/crypto/src/asn1/x509/X509CertificateStructure.cs b/crypto/src/asn1/x509/X509CertificateStructure.cs
index e50d3563b..c8558ae61 100644
--- a/crypto/src/asn1/x509/X509CertificateStructure.cs
+++ b/crypto/src/asn1/x509/X509CertificateStructure.cs
@@ -21,109 +21,107 @@ namespace Org.BouncyCastle.Asn1.X509
         private readonly AlgorithmIdentifier		sigAlgID;
         private readonly DerBitString				sig;
 
-		public static X509CertificateStructure GetInstance(
+        public static X509CertificateStructure GetInstance(
             Asn1TaggedObject	obj,
             bool				explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static X509CertificateStructure GetInstance(
+        public static X509CertificateStructure GetInstance(
             object obj)
         {
             if (obj is X509CertificateStructure)
                 return (X509CertificateStructure)obj;
+            if (obj == null)
+                return null;
+            return new X509CertificateStructure(Asn1Sequence.GetInstance(obj));
+        }
 
-			if (obj != null)
-				return new X509CertificateStructure(Asn1Sequence.GetInstance(obj));
-
-			return null;
+        public X509CertificateStructure(
+            TbsCertificateStructure	tbsCert,
+            AlgorithmIdentifier		sigAlgID,
+            DerBitString			sig)
+        {
+            if (tbsCert == null)
+                throw new ArgumentNullException("tbsCert");
+            if (sigAlgID == null)
+                throw new ArgumentNullException("sigAlgID");
+            if (sig == null)
+                throw new ArgumentNullException("sig");
+
+            this.tbsCert = tbsCert;
+            this.sigAlgID = sigAlgID;
+            this.sig = sig;
         }
 
-		public X509CertificateStructure(
-			TbsCertificateStructure	tbsCert,
-			AlgorithmIdentifier		sigAlgID,
-			DerBitString			sig)
-		{
-			if (tbsCert == null)
-				throw new ArgumentNullException("tbsCert");
-			if (sigAlgID == null)
-				throw new ArgumentNullException("sigAlgID");
-			if (sig == null)
-				throw new ArgumentNullException("sig");
-
-			this.tbsCert = tbsCert;
-			this.sigAlgID = sigAlgID;
-			this.sig = sig;
-		}
-
-		private X509CertificateStructure(
+        private X509CertificateStructure(
             Asn1Sequence seq)
         {
-			if (seq.Count != 3)
-				throw new ArgumentException("sequence wrong size for a certificate", "seq");
+            if (seq.Count != 3)
+                throw new ArgumentException("sequence wrong size for a certificate", "seq");
 
-			//
+            //
             // correct x509 certficate
             //
-			tbsCert = TbsCertificateStructure.GetInstance(seq[0]);
-			sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
-			sig = DerBitString.GetInstance(seq[2]);
+            tbsCert = TbsCertificateStructure.GetInstance(seq[0]);
+            sigAlgID = AlgorithmIdentifier.GetInstance(seq[1]);
+            sig = DerBitString.GetInstance(seq[2]);
         }
 
-		public TbsCertificateStructure TbsCertificate
+        public TbsCertificateStructure TbsCertificate
         {
-			get { return tbsCert; }
+            get { return tbsCert; }
         }
 
-		public int Version
+        public int Version
         {
             get { return tbsCert.Version; }
         }
 
-		public DerInteger SerialNumber
+        public DerInteger SerialNumber
         {
             get { return tbsCert.SerialNumber; }
         }
 
-		public X509Name Issuer
+        public X509Name Issuer
         {
             get { return tbsCert.Issuer; }
         }
 
-		public Time StartDate
+        public Time StartDate
         {
             get { return tbsCert.StartDate; }
         }
 
-		public Time EndDate
+        public Time EndDate
         {
             get { return tbsCert.EndDate; }
         }
 
-		public X509Name Subject
+        public X509Name Subject
         {
             get { return tbsCert.Subject; }
         }
 
-		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+        public SubjectPublicKeyInfo SubjectPublicKeyInfo
         {
             get { return tbsCert.SubjectPublicKeyInfo; }
         }
 
-		public AlgorithmIdentifier SignatureAlgorithm
+        public AlgorithmIdentifier SignatureAlgorithm
         {
             get { return sigAlgID; }
         }
 
-		public DerBitString Signature
+        public DerBitString Signature
         {
             get { return sig; }
         }
 
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(tbsCert, sigAlgID, sig);
+            return new DerSequence(tbsCert, sigAlgID, sig);
         }
-	}
+    }
 }
diff --git a/crypto/src/asn1/x509/X509DefaultEntryConverter.cs b/crypto/src/asn1/x509/X509DefaultEntryConverter.cs
new file mode 100644
index 000000000..7282ead26
--- /dev/null
+++ b/crypto/src/asn1/x509/X509DefaultEntryConverter.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The default converter for X509 DN entries when going from their
+     * string value to ASN.1 strings.
+     */
+    public class X509DefaultEntryConverter
+        : X509NameEntryConverter
+    {
+        /**
+         * Apply default conversion 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 override Asn1Object GetConvertedValue(
+            DerObjectIdentifier	oid,
+            string				value)
+        {
+            if (value.Length != 0 && value[0] == '#')
+            {
+				try
+				{
+					return ConvertHexEncoded(value, 1);
+				}
+				catch (IOException)
+				{
+					throw new Exception("can't recode value for oid " + oid.Id);
+				}
+			}
+
+			if (value.Length != 0 && value[0] == '\\')
+			{
+				value = value.Substring(1);
+			}
+
+			if (oid.Equals(X509Name.EmailAddress) || oid.Equals(X509Name.DC))
+            {
+                return new DerIA5String(value);
+            }
+
+			if (oid.Equals(X509Name.DateOfBirth)) // accept time string as well as # (for compatibility)
+			{
+				return new DerGeneralizedTime(value);
+			}
+
+			if (oid.Equals(X509Name.C)
+				|| oid.Equals(X509Name.SerialNumber)
+				|| oid.Equals(X509Name.DnQualifier)
+				|| oid.Equals(X509Name.TelephoneNumber))
+			{
+				return new DerPrintableString(value);
+			}
+
+			return new DerUtf8String(value);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/X509Extension.cs b/crypto/src/asn1/x509/X509Extension.cs
new file mode 100644
index 000000000..430ce4447
--- /dev/null
+++ b/crypto/src/asn1/x509/X509Extension.cs
@@ -0,0 +1,79 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * an object for the elements in the X.509 V3 extension block.
+     */
+    public class X509Extension
+    {
+        internal bool				critical;
+        internal Asn1OctetString	value;
+
+		public X509Extension(
+            DerBoolean		critical,
+            Asn1OctetString	value)
+        {
+            if (critical == null)
+            {
+                throw new ArgumentNullException("critical");
+            }
+
+			this.critical = critical.IsTrue;
+            this.value = value;
+        }
+
+		public X509Extension(
+            bool			critical,
+            Asn1OctetString	value)
+        {
+            this.critical = critical;
+            this.value = value;
+        }
+
+		public bool IsCritical { get { return critical; } }
+
+		public Asn1OctetString Value { get { return value; } }
+
+		public Asn1Encodable GetParsedValue()
+		{
+			return ConvertValueToObject(this);
+		}
+
+		public override int GetHashCode()
+        {
+			int vh = this.Value.GetHashCode();
+
+			return IsCritical ? vh : ~vh;
+        }
+
+		public override bool Equals(
+            object obj)
+        {
+            X509Extension other = obj as X509Extension;
+            if (other == null)
+            {
+                return false;
+            }
+
+			return Value.Equals(other.Value) && IsCritical == other.IsCritical;
+        }
+
+		/// <sumary>Convert the value of the passed in extension to an object.</sumary>
+		/// <param name="ext">The extension to parse.</param>
+		/// <returns>The object the value string contains.</returns>
+		/// <exception cref="ArgumentException">If conversion is not possible.</exception>
+		public static Asn1Object ConvertValueToObject(
+			X509Extension ext)
+		{
+			try
+			{
+				return Asn1Object.FromByteArray(ext.Value.GetOctets());
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("can't convert extension", e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/X509Extensions.cs b/crypto/src/asn1/x509/X509Extensions.cs
index 1896450f5..5dce5622d 100644
--- a/crypto/src/asn1/x509/X509Extensions.cs
+++ b/crypto/src/asn1/x509/X509Extensions.cs
@@ -278,7 +278,7 @@ namespace Org.BouncyCastle.Asn1.X509
             }
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
 		/**
          * constructor from a table of extensions.
          * <p>
diff --git a/crypto/src/asn1/x509/X509ExtensionsGenerator.cs b/crypto/src/asn1/x509/X509ExtensionsGenerator.cs
new file mode 100644
index 000000000..d6f567b22
--- /dev/null
+++ b/crypto/src/asn1/x509/X509ExtensionsGenerator.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/// <remarks>Generator for X.509 extensions</remarks>
+	public class X509ExtensionsGenerator
+	{
+		private IDictionary extensions = Platform.CreateHashtable();
+        private IList extOrdering = Platform.CreateArrayList();
+
+		/// <summary>Reset the generator</summary>
+		public void Reset()
+		{
+            extensions = Platform.CreateHashtable();
+            extOrdering = Platform.CreateArrayList();
+		}
+
+		/// <summary>
+		/// Add an extension with the given oid and the passed in value to be included
+		/// in the OCTET STRING associated with the extension.
+		/// </summary>
+		/// <param name="oid">OID for the extension.</param>
+		/// <param name="critical">True if critical, false otherwise.</param>
+		/// <param name="extValue">The ASN.1 object to be included in the extension.</param>
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			Asn1Encodable		extValue)
+		{
+			byte[] encoded;
+			try
+			{
+				encoded = extValue.GetDerEncoded();
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("error encoding value: " + e);
+			}
+
+			this.AddExtension(oid, critical, encoded);
+		}
+
+		/// <summary>
+		/// Add an extension with the given oid and the passed in byte array to be wrapped
+		/// in the OCTET STRING associated with the extension.
+		/// </summary>
+		/// <param name="oid">OID for the extension.</param>
+		/// <param name="critical">True if critical, false otherwise.</param>
+		/// <param name="extValue">The byte array to be wrapped.</param>
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			byte[]				extValue)
+		{
+			if (extensions.Contains(oid))
+			{
+				throw new ArgumentException("extension " + oid + " already added");
+			}
+
+			extOrdering.Add(oid);
+			extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue)));
+		}
+
+		/// <summary>Return true if there are no extension present in this generator.</summary>
+		/// <returns>True if empty, false otherwise</returns>
+		public bool IsEmpty
+		{
+			get { return extOrdering.Count < 1; }
+		}
+
+		/// <summary>Generate an X509Extensions object based on the current state of the generator.</summary>
+		/// <returns>An <c>X509Extensions</c> object</returns>
+		public X509Extensions Generate()
+		{
+			return new X509Extensions(extOrdering, extensions);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/X509Name.cs b/crypto/src/asn1/x509/X509Name.cs
index b459cbe1b..c183e5798 100644
--- a/crypto/src/asn1/x509/X509Name.cs
+++ b/crypto/src/asn1/x509/X509Name.cs
@@ -1,10 +1,9 @@
 using System;
 using System.Collections;
-using System.Globalization;
 using System.IO;
 using System.Text;
 
-#if (SILVERLIGHT || PORTABLE)
+#if SILVERLIGHT
 using System.Collections.Generic;
 #endif
 
@@ -53,17 +52,17 @@ namespace Org.BouncyCastle.Asn1.X509
         */
         public static readonly DerObjectIdentifier CN = new DerObjectIdentifier("2.5.4.3");
 
-		/**
-		* street - StringType(SIZE(1..64))
-		*/
-		public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9");
+        /**
+        * street - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier Street = new DerObjectIdentifier("2.5.4.9");
 
-		/**
-		* device serial number name - StringType(SIZE(1..64))
-		*/
-		public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5");
+        /**
+        * device serial number name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier SerialNumber = new DerObjectIdentifier("2.5.4.5");
 
-		/**
+        /**
         * locality name - StringType(SIZE(1..64))
         */
         public static readonly DerObjectIdentifier L = new DerObjectIdentifier("2.5.4.7");
@@ -82,89 +81,89 @@ namespace Org.BouncyCastle.Asn1.X509
         public static readonly DerObjectIdentifier Generation = new DerObjectIdentifier("2.5.4.44");
         public static readonly DerObjectIdentifier UniqueIdentifier = new DerObjectIdentifier("2.5.4.45");
 
-		/**
-		 * businessCategory - DirectoryString(SIZE(1..128)
-		 */
-		public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier(
-																	   "2.5.4.15");
-
-		/**
-		 * postalCode - DirectoryString(SIZE(1..40)
-		 */
-		public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier(
-																 "2.5.4.17");
-
-		/**
-		 * dnQualifier - DirectoryString(SIZE(1..64)
-		 */
-		public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier(
-														 "2.5.4.46");
-
-		/**
-		 * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
-		 */
-		public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier(
-																"2.5.4.65");
-
-		/**
-		 * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
-		 */
-		public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier(
-																  "1.3.6.1.5.5.7.9.1");
-
-		/**
-		 * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
-		 */
-		public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier(
-																   "1.3.6.1.5.5.7.9.2");
-
-		/**
-		 * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
-		 */
-		public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier(
-																   "1.3.6.1.5.5.7.9.3");
-
-		/**
-		 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
-		 * codes only
-		 */
-		public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier(
-																		   "1.3.6.1.5.5.7.9.4");
-
-		/**
-		 * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
-		 * codes only
-		 */
-		public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier(
-																		 "1.3.6.1.5.5.7.9.5");
-
-		/**
-		 * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
-		 */
-		public static readonly DerObjectIdentifier NameAtBirth =  new DerObjectIdentifier("1.3.36.8.3.14");
-
-		/**
-		 * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
-		 * DirectoryString(SIZE(1..30))
-		 */
-		public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16");
-
-		/**
-		 * RFC 2256 dmdName
-		 */
-		public static readonly DerObjectIdentifier DmdName = new DerObjectIdentifier("2.5.4.54");
-
-		/**
-		 * id-at-telephoneNumber
-		 */
-		public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber;
-
-		/**
-		 * id-at-name
-		 */
-		public static readonly DerObjectIdentifier Name = X509ObjectIdentifiers.id_at_name;
-
-		/**
+        /**
+         * businessCategory - DirectoryString(SIZE(1..128)
+         */
+        public static readonly DerObjectIdentifier BusinessCategory = new DerObjectIdentifier(
+                                                                       "2.5.4.15");
+
+        /**
+         * postalCode - DirectoryString(SIZE(1..40)
+         */
+        public static readonly DerObjectIdentifier PostalCode = new DerObjectIdentifier(
+                                                                 "2.5.4.17");
+
+        /**
+         * dnQualifier - DirectoryString(SIZE(1..64)
+         */
+        public static readonly DerObjectIdentifier DnQualifier = new DerObjectIdentifier(
+                                                         "2.5.4.46");
+
+        /**
+         * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+         */
+        public static readonly DerObjectIdentifier Pseudonym = new DerObjectIdentifier(
+                                                                "2.5.4.65");
+
+        /**
+         * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+         */
+        public static readonly DerObjectIdentifier DateOfBirth = new DerObjectIdentifier(
+                                                                  "1.3.6.1.5.5.7.9.1");
+
+        /**
+         * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+         */
+        public static readonly DerObjectIdentifier PlaceOfBirth = new DerObjectIdentifier(
+                                                                   "1.3.6.1.5.5.7.9.2");
+
+        /**
+         * RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+         */
+        public static readonly DerObjectIdentifier Gender = new DerObjectIdentifier(
+                                                                   "1.3.6.1.5.5.7.9.3");
+
+        /**
+         * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+         * codes only
+         */
+        public static readonly DerObjectIdentifier CountryOfCitizenship = new DerObjectIdentifier(
+                                                                           "1.3.6.1.5.5.7.9.4");
+
+        /**
+         * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+         * codes only
+         */
+        public static readonly DerObjectIdentifier CountryOfResidence = new DerObjectIdentifier(
+                                                                         "1.3.6.1.5.5.7.9.5");
+
+        /**
+         * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+         */
+        public static readonly DerObjectIdentifier NameAtBirth =  new DerObjectIdentifier("1.3.36.8.3.14");
+
+        /**
+         * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+         * DirectoryString(SIZE(1..30))
+         */
+        public static readonly DerObjectIdentifier PostalAddress = new DerObjectIdentifier("2.5.4.16");
+
+        /**
+         * RFC 2256 dmdName
+         */
+        public static readonly DerObjectIdentifier DmdName = new DerObjectIdentifier("2.5.4.54");
+
+        /**
+         * id-at-telephoneNumber
+         */
+        public static readonly DerObjectIdentifier TelephoneNumber = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+        /**
+         * id-at-name
+         */
+        public static readonly DerObjectIdentifier 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.</p>
         */
@@ -196,31 +195,31 @@ namespace Org.BouncyCastle.Asn1.X509
         * from back to front.
         */
 //        public static bool DefaultReverse = false;
-		public static bool DefaultReverse
-		{
-			get { return defaultReverse[0]; }
-			set { defaultReverse[0] = value; }
-		}
+        public static bool DefaultReverse
+        {
+            get { return defaultReverse[0]; }
+            set { defaultReverse[0] = value; }
+        }
+
+        private static readonly bool[] defaultReverse = { false };
 
-		private static readonly bool[] defaultReverse = { false };
+#if SILVERLIGHT
+        /**
+        * default look up table translating OID values into their common symbols following
+        * the convention in RFC 2253 with a few extras
+        */
+        public static readonly IDictionary DefaultSymbols = Platform.CreateHashtable();
 
-#if (SILVERLIGHT || PORTABLE)
         /**
-		* default look up table translating OID values into their common symbols following
-		* the convention in RFC 2253 with a few extras
-		*/
-		public static readonly IDictionary DefaultSymbols = Platform.CreateHashtable();
-
-		/**
-		 * look up table translating OID values into their common symbols following the convention in RFC 2253
-		 */
-		public static readonly IDictionary RFC2253Symbols = Platform.CreateHashtable();
-
-		/**
-		 * look up table translating OID values into their common symbols following the convention in RFC 1779
-		 *
-		 */
-		public static readonly IDictionary RFC1779Symbols = Platform.CreateHashtable();
+         * look up table translating OID values into their common symbols following the convention in RFC 2253
+         */
+        public static readonly IDictionary RFC2253Symbols = Platform.CreateHashtable();
+
+        /**
+         * look up table translating OID values into their common symbols following the convention in RFC 1779
+         *
+         */
+        public static readonly IDictionary RFC1779Symbols = Platform.CreateHashtable();
 
         /**
         * look up table translating common symbols into their OIDS.
@@ -228,21 +227,21 @@ namespace Org.BouncyCastle.Asn1.X509
         public static readonly IDictionary DefaultLookup = Platform.CreateHashtable();
 #else
         /**
-		* default look up table translating OID values into their common symbols following
-		* the convention in RFC 2253 with a few extras
-		*/
-		public static readonly Hashtable DefaultSymbols = new Hashtable();
-
-		/**
-		 * look up table translating OID values into their common symbols following the convention in RFC 2253
-		 */
-		public static readonly Hashtable RFC2253Symbols = new Hashtable();
-
-		/**
-		 * look up table translating OID values into their common symbols following the convention in RFC 1779
-		 *
-		 */
-		public static readonly Hashtable RFC1779Symbols = new Hashtable();
+        * default look up table translating OID values into their common symbols following
+        * the convention in RFC 2253 with a few extras
+        */
+        public static readonly Hashtable DefaultSymbols = new Hashtable();
+
+        /**
+         * look up table translating OID values into their common symbols following the convention in RFC 2253
+         */
+        public static readonly Hashtable RFC2253Symbols = new Hashtable();
+
+        /**
+         * look up table translating OID values into their common symbols following the convention in RFC 1779
+         *
+         */
+        public static readonly Hashtable RFC1779Symbols = new Hashtable();
 
         /**
         * look up table translating common symbols into their OIDS.
@@ -263,26 +262,26 @@ namespace Org.BouncyCastle.Asn1.X509
             DefaultSymbols.Add(EmailAddress, "E");
             DefaultSymbols.Add(DC, "DC");
             DefaultSymbols.Add(UID, "UID");
-			DefaultSymbols.Add(Street, "STREET");
+            DefaultSymbols.Add(Street, "STREET");
             DefaultSymbols.Add(Surname, "SURNAME");
             DefaultSymbols.Add(GivenName, "GIVENNAME");
             DefaultSymbols.Add(Initials, "INITIALS");
             DefaultSymbols.Add(Generation, "GENERATION");
             DefaultSymbols.Add(UnstructuredAddress, "unstructuredAddress");
             DefaultSymbols.Add(UnstructuredName, "unstructuredName");
-			DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier");
-			DefaultSymbols.Add(DnQualifier, "DN");
-			DefaultSymbols.Add(Pseudonym, "Pseudonym");
-			DefaultSymbols.Add(PostalAddress, "PostalAddress");
-			DefaultSymbols.Add(NameAtBirth, "NameAtBirth");
-			DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship");
-			DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence");
-			DefaultSymbols.Add(Gender, "Gender");
-			DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth");
-			DefaultSymbols.Add(DateOfBirth, "DateOfBirth");
-			DefaultSymbols.Add(PostalCode, "PostalCode");
-			DefaultSymbols.Add(BusinessCategory, "BusinessCategory");
-			DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber");
+            DefaultSymbols.Add(UniqueIdentifier, "UniqueIdentifier");
+            DefaultSymbols.Add(DnQualifier, "DN");
+            DefaultSymbols.Add(Pseudonym, "Pseudonym");
+            DefaultSymbols.Add(PostalAddress, "PostalAddress");
+            DefaultSymbols.Add(NameAtBirth, "NameAtBirth");
+            DefaultSymbols.Add(CountryOfCitizenship, "CountryOfCitizenship");
+            DefaultSymbols.Add(CountryOfResidence, "CountryOfResidence");
+            DefaultSymbols.Add(Gender, "Gender");
+            DefaultSymbols.Add(PlaceOfBirth, "PlaceOfBirth");
+            DefaultSymbols.Add(DateOfBirth, "DateOfBirth");
+            DefaultSymbols.Add(PostalCode, "PostalCode");
+            DefaultSymbols.Add(BusinessCategory, "BusinessCategory");
+            DefaultSymbols.Add(TelephoneNumber, "TelephoneNumber");
 
             RFC2253Symbols.Add(C, "C");
             RFC2253Symbols.Add(O, "O");
@@ -290,28 +289,28 @@ namespace Org.BouncyCastle.Asn1.X509
             RFC2253Symbols.Add(CN, "CN");
             RFC2253Symbols.Add(L, "L");
             RFC2253Symbols.Add(ST, "ST");
-			RFC2253Symbols.Add(Street, "STREET");
-			RFC2253Symbols.Add(DC, "DC");
+            RFC2253Symbols.Add(Street, "STREET");
+            RFC2253Symbols.Add(DC, "DC");
             RFC2253Symbols.Add(UID, "UID");
 
-			RFC1779Symbols.Add(C, "C");
-			RFC1779Symbols.Add(O, "O");
-			RFC1779Symbols.Add(OU, "OU");
-			RFC1779Symbols.Add(CN, "CN");
-			RFC1779Symbols.Add(L, "L");
-			RFC1779Symbols.Add(ST, "ST");
-			RFC1779Symbols.Add(Street, "STREET");
+            RFC1779Symbols.Add(C, "C");
+            RFC1779Symbols.Add(O, "O");
+            RFC1779Symbols.Add(OU, "OU");
+            RFC1779Symbols.Add(CN, "CN");
+            RFC1779Symbols.Add(L, "L");
+            RFC1779Symbols.Add(ST, "ST");
+            RFC1779Symbols.Add(Street, "STREET");
 
-			DefaultLookup.Add("c", C);
+            DefaultLookup.Add("c", C);
             DefaultLookup.Add("o", O);
             DefaultLookup.Add("t", T);
             DefaultLookup.Add("ou", OU);
             DefaultLookup.Add("cn", CN);
             DefaultLookup.Add("l", L);
             DefaultLookup.Add("st", ST);
-			DefaultLookup.Add("serialnumber", SerialNumber);
-			DefaultLookup.Add("street", Street);
-			DefaultLookup.Add("emailaddress", E);
+            DefaultLookup.Add("serialnumber", SerialNumber);
+            DefaultLookup.Add("street", Street);
+            DefaultLookup.Add("emailaddress", E);
             DefaultLookup.Add("dc", DC);
             DefaultLookup.Add("e", E);
             DefaultLookup.Add("uid", UID);
@@ -321,29 +320,29 @@ namespace Org.BouncyCastle.Asn1.X509
             DefaultLookup.Add("generation", Generation);
             DefaultLookup.Add("unstructuredaddress", UnstructuredAddress);
             DefaultLookup.Add("unstructuredname", UnstructuredName);
-			DefaultLookup.Add("uniqueidentifier", UniqueIdentifier);
-			DefaultLookup.Add("dn", DnQualifier);
-			DefaultLookup.Add("pseudonym", Pseudonym);
-			DefaultLookup.Add("postaladdress", PostalAddress);
-			DefaultLookup.Add("nameofbirth", NameAtBirth);
-			DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship);
-			DefaultLookup.Add("countryofresidence", CountryOfResidence);
-			DefaultLookup.Add("gender", Gender);
-			DefaultLookup.Add("placeofbirth", PlaceOfBirth);
-			DefaultLookup.Add("dateofbirth", DateOfBirth);
-			DefaultLookup.Add("postalcode", PostalCode);
-			DefaultLookup.Add("businesscategory", BusinessCategory);
-			DefaultLookup.Add("telephonenumber", TelephoneNumber);
-		}
+            DefaultLookup.Add("uniqueidentifier", UniqueIdentifier);
+            DefaultLookup.Add("dn", DnQualifier);
+            DefaultLookup.Add("pseudonym", Pseudonym);
+            DefaultLookup.Add("postaladdress", PostalAddress);
+            DefaultLookup.Add("nameofbirth", NameAtBirth);
+            DefaultLookup.Add("countryofcitizenship", CountryOfCitizenship);
+            DefaultLookup.Add("countryofresidence", CountryOfResidence);
+            DefaultLookup.Add("gender", Gender);
+            DefaultLookup.Add("placeofbirth", PlaceOfBirth);
+            DefaultLookup.Add("dateofbirth", DateOfBirth);
+            DefaultLookup.Add("postalcode", PostalCode);
+            DefaultLookup.Add("businesscategory", BusinessCategory);
+            DefaultLookup.Add("telephonenumber", TelephoneNumber);
+        }
 
         private readonly IList ordering = Platform.CreateArrayList();
-		private readonly X509NameEntryConverter converter;
+        private readonly X509NameEntryConverter converter;
 
-		private IList		    values = Platform.CreateArrayList();
+        private IList		    values = Platform.CreateArrayList();
         private IList           added = Platform.CreateArrayList();
         private Asn1Sequence	seq;
 
-		/**
+        /**
         * Return a X509Name based on the passed in tagged object.
         *
         * @param obj tag object holding name.
@@ -357,23 +356,23 @@ namespace Org.BouncyCastle.Asn1.X509
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static X509Name GetInstance(
+        public static X509Name GetInstance(
             object obj)
         {
             if (obj == null || obj is X509Name)
                 return (X509Name)obj;
 
-			if (obj != null)
-				return new X509Name(Asn1Sequence.GetInstance(obj));
+            if (obj != null)
+                return new X509Name(Asn1Sequence.GetInstance(obj));
 
-			throw new ArgumentException("null object in factory", "obj");
+            throw new ArgumentException("null object in factory", "obj");
         }
 
-		protected X509Name()
-		{
-		}
+        protected X509Name()
+        {
+        }
 
-		/**
+        /**
         * Constructor from Asn1Sequence
         *
         * the principal will be a list of constructed sets, each containing an (OID, string) pair.
@@ -383,50 +382,40 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             this.seq = seq;
 
-			foreach (Asn1Encodable asn1Obj in seq)
-			{
-				Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object());
+            foreach (Asn1Encodable asn1Obj in seq)
+            {
+                Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object());
 
-				for (int i = 0; i < asn1Set.Count; i++)
+                for (int i = 0; i < asn1Set.Count; i++)
                 {
-					Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object());
+                    Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object());
 
-					if (s.Count != 2)
-						throw new ArgumentException("badly sized pair");
+                    if (s.Count != 2)
+                        throw new ArgumentException("badly sized pair");
 
-					ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object()));
+                    ordering.Add(DerObjectIdentifier.GetInstance(s[0].ToAsn1Object()));
 
-					Asn1Object derValue = s[1].ToAsn1Object();
-					if (derValue is IAsn1String && !(derValue is DerUniversalString))
-					{
-						string v = ((IAsn1String)derValue).GetString();
-						if (v.StartsWith("#"))
-						{
-							v = "\\" + v;
-						}
+                    Asn1Object derValue = s[1].ToAsn1Object();
+                    if (derValue is IAsn1String && !(derValue is DerUniversalString))
+                    {
+                        string v = ((IAsn1String)derValue).GetString();
+                        if (v.StartsWith("#"))
+                        {
+                            v = "\\" + v;
+                        }
 
-						values.Add(v);
-					}
+                        values.Add(v);
+                    }
                     else
                     {
-						values.Add("#" + Hex.ToHexString(derValue.GetEncoded()));
+                        values.Add("#" + Hex.ToHexString(derValue.GetEncoded()));
                     }
 
-					added.Add(i != 0);
+                    added.Add(i != 0);
                 }
             }
         }
 
-#if !(SILVERLIGHT || PORTABLE)
-        [Obsolete]
-        public X509Name(
-            ArrayList ordering,
-            Hashtable attributes)
-            : this(ordering, attributes, new X509DefaultEntryConverter())
-        {
-        }
-#endif
-
         /**
         * Constructor from a table of attributes with ordering.
         * <p>
@@ -442,17 +431,6 @@ namespace Org.BouncyCastle.Asn1.X509
         {
         }
 
-#if !(SILVERLIGHT || PORTABLE)
-        [Obsolete]
-        public X509Name(
-            ArrayList				ordering,
-            Hashtable				attributes,
-            X509NameEntryConverter	converter)
-            : this((IList)ordering, (IDictionary)attributes, converter)
-        {
-        }
-#endif
-
         /**
         * Constructor from a table of attributes with ordering.
         * <p>
@@ -469,31 +447,21 @@ namespace Org.BouncyCastle.Asn1.X509
             IDictionary             attributes,
             X509NameEntryConverter	converter)
         {
-			this.converter = converter;
-
-			foreach (DerObjectIdentifier oid in ordering)
-			{
-				object attribute = attributes[oid];
-				if (attribute == null)
-				{
-					throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name");
-				}
-
-				this.ordering.Add(oid);
-				this.added.Add(false);
-				this.values.Add(attribute); // copy the hash table
-			}
-        }
+            this.converter = converter;
 
-#if !(SILVERLIGHT || PORTABLE)
-        [Obsolete]
-        public X509Name(
-            ArrayList oids,
-            ArrayList values)
-            : this(oids, values, new X509DefaultEntryConverter())
-        {
+            foreach (DerObjectIdentifier oid in ordering)
+            {
+                object attribute = attributes[oid];
+                if (attribute == null)
+                {
+                    throw new ArgumentException("No attribute for object id - " + oid + " - passed to distinguished name");
+                }
+
+                this.ordering.Add(oid);
+                this.added.Add(false);
+                this.values.Add(attribute); // copy the hash table
+            }
         }
-#endif
 
         /**
         * Takes two vectors one of the oids and the other of the values.
@@ -505,17 +473,6 @@ namespace Org.BouncyCastle.Asn1.X509
         {
         }
 
-#if !(SILVERLIGHT || PORTABLE)
-        [Obsolete]
-        public X509Name(
-            ArrayList				oids,
-            ArrayList				values,
-            X509NameEntryConverter	converter)
-            : this((IList)oids, (IList)values, converter)
-        {
-        }
-#endif
-
         /**
         * Takes two vectors one of the oids and the other of the values.
         * <p>
@@ -529,12 +486,12 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             this.converter = converter;
 
-			if (oids.Count != values.Count)
+            if (oids.Count != values.Count)
             {
                 throw new ArgumentException("'oids' must be same length as 'values'.");
             }
 
-			for (int i = 0; i < oids.Count; i++)
+            for (int i = 0; i < oids.Count; i++)
             {
                 this.ordering.Add(oids[i]);
                 this.values.Add(values[i]);
@@ -548,7 +505,7 @@ namespace Org.BouncyCastle.Asn1.X509
 //			return s.StartsWith("#");
 //		}
 
-		/**
+        /**
         * 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.
         */
@@ -558,7 +515,7 @@ namespace Org.BouncyCastle.Asn1.X509
         {
         }
 
-		/**
+        /**
         * 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
@@ -571,7 +528,7 @@ namespace Org.BouncyCastle.Asn1.X509
         {
         }
 
-		/**
+        /**
         * 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
@@ -584,7 +541,7 @@ namespace Org.BouncyCastle.Asn1.X509
         {
         }
 
-		/**
+        /**
         * 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
@@ -599,17 +556,6 @@ namespace Org.BouncyCastle.Asn1.X509
         {
         }
 
-#if !(SILVERLIGHT || PORTABLE)
-        [Obsolete]
-        public X509Name(
-            bool reverse,
-            Hashtable lookUp,
-            string dirName)
-            : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
-        {
-        }
-#endif
-
         /**
         * 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
@@ -631,11 +577,11 @@ namespace Org.BouncyCastle.Asn1.X509
         {
         }
 
-		private DerObjectIdentifier DecodeOid(
+        private DerObjectIdentifier DecodeOid(
             string		name,
             IDictionary lookUp)
         {
-            if (name.ToUpperInvariant().StartsWith("OID."))
+            if (Platform.ToUpperInvariant(name).StartsWith("OID."))
             {
                 return new DerObjectIdentifier(name.Substring(4));
             }
@@ -644,16 +590,16 @@ namespace Org.BouncyCastle.Asn1.X509
                 return new DerObjectIdentifier(name);
             }
 
-			DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[name.ToLowerInvariant()];
+            DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[Platform.ToLowerInvariant(name)];
             if (oid == null)
             {
                 throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name");
             }
 
-			return oid;
+            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
@@ -675,30 +621,30 @@ namespace Org.BouncyCastle.Asn1.X509
             this.converter = converter;
             X509NameTokenizer nTok = new X509NameTokenizer(dirName);
 
-			while (nTok.HasMoreTokens())
+            while (nTok.HasMoreTokens())
             {
                 string token = nTok.NextToken();
                 int index = token.IndexOf('=');
 
-				if (index == -1)
+                if (index == -1)
                 {
                     throw new ArgumentException("badly formated directory string");
                 }
 
-				string name = token.Substring(0, index);
+                string name = token.Substring(0, index);
                 string value = token.Substring(index + 1);
                 DerObjectIdentifier	oid = DecodeOid(name, lookUp);
 
-				if (value.IndexOf('+') > 0)
+                if (value.IndexOf('+') > 0)
                 {
                     X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
-					string v = vTok.NextToken();
+                    string v = vTok.NextToken();
 
-					this.ordering.Add(oid);
+                    this.ordering.Add(oid);
                     this.values.Add(v);
                     this.added.Add(false);
 
-					while (vTok.HasMoreTokens())
+                    while (vTok.HasMoreTokens())
                     {
                         string sv = vTok.NextToken();
                         int ndx = sv.IndexOf('=');
@@ -718,46 +664,35 @@ namespace Org.BouncyCastle.Asn1.X509
                 }
             }
 
-			if (reverse)
+            if (reverse)
             {
 //				this.ordering.Reverse();
 //				this.values.Reverse();
 //				this.added.Reverse();
-				IList o = Platform.CreateArrayList();
+                IList o = Platform.CreateArrayList();
                 IList v = Platform.CreateArrayList();
                 IList a = Platform.CreateArrayList();
-				int count = 1;
-
-				for (int i = 0; i < this.ordering.Count; i++)
-				{
-					if (!((bool) this.added[i]))
-					{
-						count = 0;
-					}
-
-					int index = count++;
-
-					o.Insert(index, this.ordering[i]);
-					v.Insert(index, this.values[i]);
-					a.Insert(index, this.added[i]);
-				}
-
-				this.ordering = o;
-				this.values = v;
-				this.added = a;
-			}
-        }
+                int count = 1;
 
-#if !(SILVERLIGHT || PORTABLE)
-		/**
-		* return an ArrayList of the oids in the name, in the order they were found.
-		*/
-        [Obsolete("Use 'GetOidList' instead")]
-        public ArrayList GetOids()
-        {
-            return new ArrayList(ordering);
+                for (int i = 0; i < this.ordering.Count; i++)
+                {
+                    if (!((bool) this.added[i]))
+                    {
+                        count = 0;
+                    }
+
+                    int index = count++;
+
+                    o.Insert(index, this.ordering[i]);
+                    v.Insert(index, this.values[i]);
+                    a.Insert(index, this.added[i]);
+                }
+
+                this.ordering = o;
+                this.values = v;
+                this.added = a;
+            }
         }
-#endif
 
         /**
         * return an IList of the oids in the name, in the order they were found.
@@ -767,57 +702,25 @@ namespace Org.BouncyCastle.Asn1.X509
             return Platform.CreateArrayList(ordering);
         }
 
-#if !(SILVERLIGHT || PORTABLE)
-		/**
-		* return an ArrayList of the values found in the name, in the order they
-		* were found.
-		*/
-        [Obsolete("Use 'GetValueList' instead")]
-		public ArrayList GetValues()
-		{
-            return new ArrayList(values);
-		}
-#endif
-
         /**
         * return an IList of the values found in the name, in the order they
         * were found.
         */
         public IList GetValueList()
         {
-            return Platform.CreateArrayList(values);
+            return GetValueList(null);
         }
 
-#if !(SILVERLIGHT || PORTABLE)
-		/**
-		 * return an ArrayList of the values found in the name, in the order they
-		 * were found, with the DN label corresponding to passed in oid.
-		 */
-		public ArrayList GetValues(
-			DerObjectIdentifier oid)
-		{
-			ArrayList v = new ArrayList();
-            DoGetValueList(oid, v);
-			return v;
-		}
-#endif
-
         /**
-		 * return an IList of the values found in the name, in the order they
-		 * were found, with the DN label corresponding to passed in oid.
-		 */
+         * return an IList of the values found in the name, in the order they
+         * were found, with the DN label corresponding to passed in oid.
+         */
         public IList GetValueList(DerObjectIdentifier oid)
         {
             IList v = Platform.CreateArrayList();
-            DoGetValueList(oid, v);
-            return v;
-        }
-
-        private void DoGetValueList(DerObjectIdentifier oid, IList v)
-        {
             for (int i = 0; i != values.Count; i++)
             {
-                if (ordering[i].Equals(oid))
+                if (null == oid || oid.Equals(ordering[i]))
                 {
                     string val = (string)values[i];
 
@@ -829,9 +732,10 @@ namespace Org.BouncyCastle.Asn1.X509
                     v.Add(val);
                 }
             }
+            return v;
         }
 
-		public override Asn1Object ToAsn1Object()
+        public override Asn1Object ToAsn1Object()
         {
             if (seq == null)
             {
@@ -839,12 +743,12 @@ namespace Org.BouncyCastle.Asn1.X509
                 Asn1EncodableVector sVec = new Asn1EncodableVector();
                 DerObjectIdentifier lstOid = null;
 
-				for (int i = 0; i != ordering.Count; i++)
+                for (int i = 0; i != ordering.Count; i++)
                 {
                     DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
-					string str = (string)values[i];
+                    string str = (string)values[i];
 
-					if (lstOid == null
+                    if (lstOid == null
                         || ((bool)this.added[i]))
                     {
                     }
@@ -854,211 +758,211 @@ namespace Org.BouncyCastle.Asn1.X509
                         sVec = new Asn1EncodableVector();
                     }
 
-					sVec.Add(
-						new DerSequence(
-							oid,
-							converter.GetConvertedValue(oid, str)));
+                    sVec.Add(
+                        new DerSequence(
+                            oid,
+                            converter.GetConvertedValue(oid, str)));
 
-					lstOid = oid;
+                    lstOid = oid;
                 }
 
-				vec.Add(new DerSet(sVec));
+                vec.Add(new DerSet(sVec));
 
-				seq = new DerSequence(vec);
+                seq = new DerSequence(vec);
             }
 
             return seq;
         }
 
         /// <param name="other">The X509Name object to test equivalency against.</param>
-		/// <param name="inOrder">If true, the order of elements must be the same,
-		/// as well as the values associated with each element.</param>
-		public bool Equivalent(
-			X509Name	other,
-			bool		inOrder)
-		{
-			if (!inOrder)
-				return this.Equivalent(other);
+        /// <param name="inOrder">If true, the order of elements must be the same,
+        /// as well as the values associated with each element.</param>
+        public bool Equivalent(
+            X509Name	other,
+            bool		inOrder)
+        {
+            if (!inOrder)
+                return this.Equivalent(other);
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			if (other == this)
-				return true;
+            if (other == this)
+                return true;
 
-			int orderingSize = ordering.Count;
+            int orderingSize = ordering.Count;
 
-			if (orderingSize != other.ordering.Count)
-				return false;
+            if (orderingSize != other.ordering.Count)
+                return false;
 
-			for (int i = 0; i < orderingSize; i++)
-			{
-				DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i];
-				DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i];
+            for (int i = 0; i < orderingSize; i++)
+            {
+                DerObjectIdentifier oid = (DerObjectIdentifier) ordering[i];
+                DerObjectIdentifier oOid = (DerObjectIdentifier) other.ordering[i];
 
-				if (!oid.Equals(oOid))
-					return false;
+                if (!oid.Equals(oOid))
+                    return false;
 
-				string val = (string) values[i];
-				string oVal = (string) other.values[i];
+                string val = (string) values[i];
+                string oVal = (string) other.values[i];
 
-				if (!equivalentStrings(val, oVal))
-					return false;
-			}
+                if (!equivalentStrings(val, oVal))
+                    return false;
+            }
 
-			return true;
-		}
+            return true;
+        }
 
         /**
-		 * test for equivalence - note: case is ignored.
-		 */
-		public bool Equivalent(
-			X509Name other)
-		{
-			if (other == null)
-				return false;
-
-			if (other == this)
-				return true;
-
-			int orderingSize = ordering.Count;
-
-			if (orderingSize != other.ordering.Count)
-			{
-				return false;
-			}
-
-			bool[] indexes = new bool[orderingSize];
-			int start, end, delta;
-
-			if (ordering[0].Equals(other.ordering[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)
-			{
-				bool found = false;
-				DerObjectIdentifier  oid = (DerObjectIdentifier)ordering[i];
-				string value = (string)values[i];
-
-				for (int j = 0; j < orderingSize; j++)
-				{
-					if (indexes[j])
-					{
-						continue;
-					}
-
-					DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j];
-
-					if (oid.Equals(oOid))
-					{
-						string oValue = (string)other.values[j];
-
-						if (equivalentStrings(value, oValue))
-						{
-							indexes[j] = true;
-							found      = true;
-							break;
-						}
-					}
-				}
-
-				if (!found)
-				{
-					return false;
-				}
-			}
-
-			return true;
-		}
-
-		private static bool equivalentStrings(
-			string	s1,
-			string	s2)
-		{
-			string v1 = canonicalize(s1);
-			string v2 = canonicalize(s2);
-
-			if (!v1.Equals(v2))
-			{
-				v1 = stripInternalSpaces(v1);
-				v2 = stripInternalSpaces(v2);
-
-				if (!v1.Equals(v2))
-				{
-					return false;
-				}
-			}
-
-			return true;
-		}
-
-		private static string canonicalize(
-			string s)
-		{
-			string v = s.ToLowerInvariant().Trim();
-
-			if (v.StartsWith("#"))
-			{
-				Asn1Object obj = decodeObject(v);
-
-				if (obj is IAsn1String)
-				{
-					v = ((IAsn1String)obj).GetString().ToLowerInvariant().Trim();
-				}
-			}
-
-			return v;
-		}
-
-		private static Asn1Object decodeObject(
-			string v)
-		{
-			try
-			{
-				return Asn1Object.FromByteArray(Hex.Decode(v.Substring(1)));
-			}
-			catch (IOException e)
-			{
-				throw new InvalidOperationException("unknown encoding in name: " + e.Message, e);
-			}
-		}
-
-		private static string stripInternalSpaces(
-			string str)
-		{
-			StringBuilder res = new StringBuilder();
-
-			if (str.Length != 0)
-			{
-				char c1 = str[0];
-
-				res.Append(c1);
-
-				for (int k = 1; k < str.Length; k++)
-				{
-					char c2 = str[k];
-					if (!(c1 == ' ' && c2 == ' '))
-					{
-						res.Append(c2);
-					}
-					c1 = c2;
-				}
-			}
-
-			return res.ToString();
-		}
-
-		private void AppendValue(
+         * test for equivalence - note: case is ignored.
+         */
+        public bool Equivalent(
+            X509Name other)
+        {
+            if (other == null)
+                return false;
+
+            if (other == this)
+                return true;
+
+            int orderingSize = ordering.Count;
+
+            if (orderingSize != other.ordering.Count)
+            {
+                return false;
+            }
+
+            bool[] indexes = new bool[orderingSize];
+            int start, end, delta;
+
+            if (ordering[0].Equals(other.ordering[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)
+            {
+                bool found = false;
+                DerObjectIdentifier  oid = (DerObjectIdentifier)ordering[i];
+                string value = (string)values[i];
+
+                for (int j = 0; j < orderingSize; j++)
+                {
+                    if (indexes[j])
+                    {
+                        continue;
+                    }
+
+                    DerObjectIdentifier oOid = (DerObjectIdentifier)other.ordering[j];
+
+                    if (oid.Equals(oOid))
+                    {
+                        string oValue = (string)other.values[j];
+
+                        if (equivalentStrings(value, oValue))
+                        {
+                            indexes[j] = true;
+                            found      = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (!found)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private static bool equivalentStrings(
+            string	s1,
+            string	s2)
+        {
+            string v1 = canonicalize(s1);
+            string v2 = canonicalize(s2);
+
+            if (!v1.Equals(v2))
+            {
+                v1 = stripInternalSpaces(v1);
+                v2 = stripInternalSpaces(v2);
+
+                if (!v1.Equals(v2))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private static string canonicalize(
+            string s)
+        {
+            string v = Platform.ToLowerInvariant(s).Trim();
+
+            if (v.StartsWith("#"))
+            {
+                Asn1Object obj = decodeObject(v);
+
+                if (obj is IAsn1String)
+                {
+                    v = Platform.ToLowerInvariant(((IAsn1String)obj).GetString()).Trim();
+                }
+            }
+
+            return v;
+        }
+
+        private static Asn1Object decodeObject(
+            string v)
+        {
+            try
+            {
+                return Asn1Object.FromByteArray(Hex.Decode(v.Substring(1)));
+            }
+            catch (IOException e)
+            {
+                throw new InvalidOperationException("unknown encoding in name: " + e.Message, e);
+            }
+        }
+
+        private static string stripInternalSpaces(
+            string str)
+        {
+            StringBuilder res = new StringBuilder();
+
+            if (str.Length != 0)
+            {
+                char c1 = str[0];
+
+                res.Append(c1);
+
+                for (int k = 1; k < str.Length; k++)
+                {
+                    char c2 = str[k];
+                    if (!(c1 == ' ' && c2 == ' '))
+                    {
+                        res.Append(c2);
+                    }
+                    c1 = c2;
+                }
+            }
+
+            return res.ToString();
+        }
+
+        private void AppendValue(
             StringBuilder		buf,
             IDictionary         oidSymbols,
             DerObjectIdentifier	oid,
@@ -1083,18 +987,18 @@ namespace Org.BouncyCastle.Asn1.X509
 
             int end = buf.Length;
 
-			if (val.StartsWith("\\#"))
-			{
-				index += 2;
-			}
+            if (val.StartsWith("\\#"))
+            {
+                index += 2;
+            }
 
-			while (index != end)
+            while (index != end)
             {
                 if ((buf[index] == ',')
                 || (buf[index] == '"')
                 || (buf[index] == '\\')
                 || (buf[index] == '+')
-				|| (buf[index] == '=')
+                || (buf[index] == '=')
                 || (buf[index] == '<')
                 || (buf[index] == '>')
                 || (buf[index] == ';'))
@@ -1107,16 +1011,6 @@ namespace Org.BouncyCastle.Asn1.X509
             }
         }
 
-#if !(SILVERLIGHT || PORTABLE)
-        [Obsolete]
-        public string ToString(
-            bool        reverse,
-            Hashtable   oidSymbols)
-        {
-            return ToString(reverse, (IDictionary)oidSymbols);
-        }
-#endif
-
         /**
         * convert the structure to a string - if reverse is true the
         * oids and values are listed out starting with the last element
@@ -1133,55 +1027,55 @@ namespace Org.BouncyCastle.Asn1.X509
             bool		reverse,
             IDictionary oidSymbols)
         {
-#if (SILVERLIGHT || PORTABLE)
+#if SILVERLIGHT
             List<object> components = new List<object>();
 #else
-			ArrayList components = new ArrayList();
+            ArrayList components = new ArrayList();
 #endif
 
             StringBuilder ava = null;
 
-			for (int i = 0; i < ordering.Count; i++)
-			{
-				if ((bool) added[i])
-				{
-					ava.Append('+');
-					AppendValue(ava, oidSymbols,
-						(DerObjectIdentifier)ordering[i],
-						(string)values[i]);
-				}
-				else
-				{
-					ava = new StringBuilder();
-					AppendValue(ava, oidSymbols,
-						(DerObjectIdentifier)ordering[i],
-						(string)values[i]);
-					components.Add(ava);
-				}
-			}
-
-			if (reverse)
-			{
-				components.Reverse();
-			}
-
-			StringBuilder buf = new StringBuilder();
-
-			if (components.Count > 0)
-			{
-				buf.Append(components[0].ToString());
-
-				for (int i = 1; i < components.Count; ++i)
-				{
-					buf.Append(',');
-					buf.Append(components[i].ToString());
-				}
-			}
-
-			return buf.ToString();
-		}
-
-		public override string ToString()
+            for (int i = 0; i < ordering.Count; i++)
+            {
+                if ((bool) added[i])
+                {
+                    ava.Append('+');
+                    AppendValue(ava, oidSymbols,
+                        (DerObjectIdentifier)ordering[i],
+                        (string)values[i]);
+                }
+                else
+                {
+                    ava = new StringBuilder();
+                    AppendValue(ava, oidSymbols,
+                        (DerObjectIdentifier)ordering[i],
+                        (string)values[i]);
+                    components.Add(ava);
+                }
+            }
+
+            if (reverse)
+            {
+                components.Reverse();
+            }
+
+            StringBuilder buf = new StringBuilder();
+
+            if (components.Count > 0)
+            {
+                buf.Append(components[0].ToString());
+
+                for (int i = 1; i < components.Count; ++i)
+                {
+                    buf.Append(',');
+                    buf.Append(components[i].ToString());
+                }
+            }
+
+            return buf.ToString();
+        }
+
+        public override string ToString()
         {
             return ToString(DefaultReverse, (IDictionary)DefaultSymbols);
         }
diff --git a/crypto/src/asn1/x509/X509NameEntryConverter.cs b/crypto/src/asn1/x509/X509NameEntryConverter.cs
new file mode 100644
index 000000000..5872656a9
--- /dev/null
+++ b/crypto/src/asn1/x509/X509NameEntryConverter.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * 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
+     *     : X509NameEntryConverter
+     * {
+     *     public Asn1Object GetConvertedValue(
+     *         DerObjectIdentifier  oid,
+     *         string               value)
+     *     {
+     *         if (str.Length() != 0 &amp;&amp; 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);
+     *         }
+     *     }
+     * }
+	 * </pre>
+	 * </p>
+     */
+    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 Asn1Object ConvertHexEncoded(
+            string	hexString,
+            int		offset)
+        {
+			string str = hexString.Substring(offset);
+
+			return Asn1Object.FromByteArray(Hex.Decode(str));
+        }
+
+		/**
+         * return true if the passed in string can be represented without
+         * loss as a PrintableString, false otherwise.
+         */
+        protected bool 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 Asn1Object GetConvertedValue(DerObjectIdentifier oid, string value);
+    }
+}
diff --git a/crypto/src/asn1/x509/X509NameTokenizer.cs b/crypto/src/asn1/x509/X509NameTokenizer.cs
new file mode 100644
index 000000000..ab5529535
--- /dev/null
+++ b/crypto/src/asn1/x509/X509NameTokenizer.cs
@@ -0,0 +1,104 @@
+using System.Text;
+
+namespace 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			separator;
+        private StringBuilder	buffer = new StringBuilder();
+
+		public X509NameTokenizer(
+            string oid)
+            : this(oid, ',')
+        {
+        }
+
+		public X509NameTokenizer(
+            string	oid,
+            char	separator)
+        {
+            this.value = oid;
+            this.index = -1;
+            this.separator = separator;
+        }
+
+		public bool HasMoreTokens()
+        {
+            return index != value.Length;
+        }
+
+		public string NextToken()
+        {
+            if (index == value.Length)
+            {
+                return null;
+            }
+
+            int end = index + 1;
+            bool quoted = false;
+            bool escaped = false;
+
+			buffer.Remove(0, buffer.Length);
+
+			while (end != value.Length)
+            {
+                char c = value[end];
+
+				if (c == '"')
+                {
+                    if (!escaped)
+                    {
+                        quoted = !quoted;
+                    }
+                    else
+                    {
+                        buffer.Append(c);
+						escaped = false;
+                    }
+                }
+                else
+                {
+                    if (escaped || quoted)
+                    {
+						if (c == '#' && buffer[buffer.Length - 1] == '=')
+						{
+							buffer.Append('\\');
+						}
+						else if (c == '+' && separator != '+')
+						{
+							buffer.Append('\\');
+						}
+						buffer.Append(c);
+                        escaped = false;
+                    }
+                    else if (c == '\\')
+                    {
+                        escaped = true;
+                    }
+                    else if (c == separator)
+                    {
+                        break;
+                    }
+                    else
+                    {
+                        buffer.Append(c);
+                    }
+                }
+
+				end++;
+            }
+
+			index = end;
+
+			return buffer.ToString().Trim();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/X509ObjectIdentifiers.cs b/crypto/src/asn1/x509/X509ObjectIdentifiers.cs
new file mode 100644
index 000000000..f00e31475
--- /dev/null
+++ b/crypto/src/asn1/x509/X509ObjectIdentifiers.cs
@@ -0,0 +1,59 @@
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public abstract class X509ObjectIdentifiers
+    {
+        //
+        // base id
+        //
+        internal const string ID = "2.5.4";
+
+		public static readonly DerObjectIdentifier CommonName              = new DerObjectIdentifier(ID + ".3");
+        public static readonly DerObjectIdentifier CountryName             = new DerObjectIdentifier(ID + ".6");
+        public static readonly DerObjectIdentifier LocalityName            = new DerObjectIdentifier(ID + ".7");
+        public static readonly DerObjectIdentifier StateOrProvinceName     = new DerObjectIdentifier(ID + ".8");
+        public static readonly DerObjectIdentifier Organization            = new DerObjectIdentifier(ID + ".10");
+        public static readonly DerObjectIdentifier OrganizationalUnitName  = new DerObjectIdentifier(ID + ".11");
+
+		public static readonly DerObjectIdentifier id_at_telephoneNumber   = new DerObjectIdentifier(ID + ".20");
+		public static readonly DerObjectIdentifier id_at_name              = new DerObjectIdentifier(ID + ".41");
+
+		// id-SHA1 OBJECT IDENTIFIER ::=
+        //   {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }    //
+        public static readonly DerObjectIdentifier IdSha1 = new DerObjectIdentifier("1.3.14.3.2.26");
+
+		//
+        // ripemd160 OBJECT IDENTIFIER ::=
+        //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RipeMD-160(1)}
+        //
+        public static readonly DerObjectIdentifier RipeMD160 = new DerObjectIdentifier("1.3.36.3.2.1");
+
+		//
+        // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+        //      {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+        //
+        public static readonly DerObjectIdentifier RipeMD160WithRsaEncryption = new DerObjectIdentifier("1.3.36.3.3.1.2");
+
+		public static readonly DerObjectIdentifier IdEARsa = new DerObjectIdentifier("2.5.8.1.1");
+
+		// id-pkix
+		public static readonly DerObjectIdentifier IdPkix = new DerObjectIdentifier("1.3.6.1.5.5.7");
+
+		//
+		// private internet extensions
+		//
+		public static readonly DerObjectIdentifier IdPE = new DerObjectIdentifier(IdPkix + ".1");
+
+		//
+		// authority information access
+		//
+		public static readonly DerObjectIdentifier IdAD = new DerObjectIdentifier(IdPkix + ".48");
+		public static readonly DerObjectIdentifier IdADCAIssuers = new DerObjectIdentifier(IdAD + ".2");
+		public static readonly DerObjectIdentifier IdADOcsp = new DerObjectIdentifier(IdAD + ".1");
+
+		//
+		// OID for ocsp and crl uri in AuthorityInformationAccess extension
+		//
+		public static readonly DerObjectIdentifier OcspAccessMethod = IdADOcsp;
+		public static readonly DerObjectIdentifier CrlAccessMethod = IdADCAIssuers;
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/BiometricData.cs b/crypto/src/asn1/x509/qualified/BiometricData.cs
new file mode 100644
index 000000000..61d7c99cb
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/BiometricData.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The BiometricData object.
+    * <pre>
+    * BiometricData  ::=  SEQUENCE {
+    *       typeOfBiometricData  TypeOfBiometricData,
+    *       hashAlgorithm        AlgorithmIdentifier,
+    *       biometricDataHash    OCTET STRING,
+    *       sourceDataUri        IA5String OPTIONAL  }
+    * </pre>
+    */
+    public class BiometricData
+        : Asn1Encodable
+    {
+        private readonly TypeOfBiometricData typeOfBiometricData;
+        private readonly AlgorithmIdentifier hashAlgorithm;
+        private readonly Asn1OctetString     biometricDataHash;
+        private readonly DerIA5String        sourceDataUri;
+
+        public static BiometricData GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is BiometricData)
+            {
+                return (BiometricData)obj;
+            }
+
+            if (obj is Asn1Sequence)
+            {
+				return new BiometricData(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private BiometricData(
+			Asn1Sequence seq)
+        {
+			typeOfBiometricData = TypeOfBiometricData.GetInstance(seq[0]);
+			hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[1]);
+			biometricDataHash = Asn1OctetString.GetInstance(seq[2]);
+
+			if (seq.Count > 3)
+			{
+				sourceDataUri = DerIA5String.GetInstance(seq[3]);
+			}
+        }
+
+		public BiometricData(
+            TypeOfBiometricData	typeOfBiometricData,
+            AlgorithmIdentifier	hashAlgorithm,
+            Asn1OctetString		biometricDataHash,
+            DerIA5String		sourceDataUri)
+        {
+            this.typeOfBiometricData = typeOfBiometricData;
+            this.hashAlgorithm = hashAlgorithm;
+            this.biometricDataHash = biometricDataHash;
+            this.sourceDataUri = sourceDataUri;
+        }
+
+        public BiometricData(
+            TypeOfBiometricData	typeOfBiometricData,
+            AlgorithmIdentifier	hashAlgorithm,
+            Asn1OctetString		biometricDataHash)
+        {
+            this.typeOfBiometricData = typeOfBiometricData;
+            this.hashAlgorithm = hashAlgorithm;
+            this.biometricDataHash = biometricDataHash;
+            this.sourceDataUri = null;
+        }
+
+        public TypeOfBiometricData TypeOfBiometricData
+        {
+			get { return typeOfBiometricData; }
+        }
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public Asn1OctetString BiometricDataHash
+		{
+			get { return biometricDataHash; }
+		}
+
+		public DerIA5String SourceDataUri
+		{
+			get { return sourceDataUri; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector(
+				typeOfBiometricData, hashAlgorithm, biometricDataHash);
+
+			if (sourceDataUri != null)
+            {
+                seq.Add(sourceDataUri);
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs b/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
new file mode 100644
index 000000000..86a4eee0a
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/ETSIQCObjectIdentifiers.cs
@@ -0,0 +1,19 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+	public abstract class EtsiQCObjectIdentifiers
+	{
+		//
+		// base id
+		//
+		public static readonly DerObjectIdentifier IdEtsiQcs                 = new DerObjectIdentifier("0.4.0.1862.1");
+
+		public static readonly DerObjectIdentifier IdEtsiQcsQcCompliance     = new DerObjectIdentifier(IdEtsiQcs+".1");
+		public static readonly DerObjectIdentifier IdEtsiQcsLimitValue       = new DerObjectIdentifier(IdEtsiQcs+".2");
+		public static readonly DerObjectIdentifier IdEtsiQcsRetentionPeriod  = new DerObjectIdentifier(IdEtsiQcs+".3");
+		public static readonly DerObjectIdentifier IdEtsiQcsQcSscd           = new DerObjectIdentifier(IdEtsiQcs+".4");
+	}
+}
diff --git a/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs b/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
new file mode 100644
index 000000000..3300562c8
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/Iso4217CurrencyCode.cs
@@ -0,0 +1,84 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The Iso4217CurrencyCode object.
+    * <pre>
+    * Iso4217CurrencyCode  ::=  CHOICE {
+    *       alphabetic              PrintableString (SIZE 3), --Recommended
+    *       numeric              INTEGER (1..999) }
+    * -- Alphabetic or numeric currency code as defined in ISO 4217
+    * -- It is recommended that the Alphabetic form is used
+    * </pre>
+    */
+    public class Iso4217CurrencyCode
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal const int AlphabeticMaxSize = 3;
+        internal const int NumericMinSize = 1;
+        internal const int NumericMaxSize = 999;
+
+		internal Asn1Encodable	obj;
+//        internal int			numeric;
+
+		public static Iso4217CurrencyCode GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Iso4217CurrencyCode)
+            {
+                return (Iso4217CurrencyCode) obj;
+            }
+
+			if (obj is DerInteger)
+            {
+                DerInteger numericobj = DerInteger.GetInstance(obj);
+                int numeric = numericobj.Value.IntValue;
+                return new Iso4217CurrencyCode(numeric);
+            }
+
+			if (obj is DerPrintableString)
+            {
+                DerPrintableString alphabetic = DerPrintableString.GetInstance(obj);
+                return new Iso4217CurrencyCode(alphabetic.GetString());
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
+
+		public Iso4217CurrencyCode(
+            int numeric)
+        {
+            if (numeric > NumericMaxSize || numeric < NumericMinSize)
+            {
+                throw new ArgumentException("wrong size in numeric code : not in (" +NumericMinSize +".."+ NumericMaxSize +")");
+            }
+
+			obj = new DerInteger(numeric);
+        }
+
+		public Iso4217CurrencyCode(
+            string alphabetic)
+        {
+            if (alphabetic.Length > AlphabeticMaxSize)
+            {
+                throw new ArgumentException("wrong size in alphabetic code : max size is " + AlphabeticMaxSize);
+            }
+
+			obj = new DerPrintableString(alphabetic);
+        }
+
+		public bool IsAlphabetic { get { return obj is DerPrintableString; } }
+
+		public string Alphabetic { get { return ((DerPrintableString) obj).GetString(); } }
+
+		public int Numeric { get { return ((DerInteger)obj).Value.IntValue; } }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return obj.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/MonetaryValue.cs b/crypto/src/asn1/x509/qualified/MonetaryValue.cs
new file mode 100644
index 000000000..45e113671
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/MonetaryValue.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The MonetaryValue object.
+    * <pre>
+    * MonetaryValue  ::=  SEQUENCE {
+    *       currency              Iso4217CurrencyCode,
+    *       amount               INTEGER,
+    *       exponent             INTEGER }
+    * -- value = amount * 10^exponent
+    * </pre>
+    */
+    public class MonetaryValue
+        : Asn1Encodable
+    {
+        internal Iso4217CurrencyCode	currency;
+        internal DerInteger				amount;
+        internal DerInteger				exponent;
+
+		public static MonetaryValue GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is MonetaryValue)
+            {
+                return (MonetaryValue) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new MonetaryValue(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private MonetaryValue(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 3)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+            currency = Iso4217CurrencyCode.GetInstance(seq[0]);
+            amount = DerInteger.GetInstance(seq[1]);
+            exponent = DerInteger.GetInstance(seq[2]);
+        }
+
+		public MonetaryValue(
+            Iso4217CurrencyCode	currency,
+            int					amount,
+            int					exponent)
+        {
+            this.currency = currency;
+            this.amount = new DerInteger(amount);
+            this.exponent = new DerInteger(exponent);
+        }
+
+		public Iso4217CurrencyCode Currency
+		{
+			get { return currency; }
+		}
+
+		public BigInteger Amount
+		{
+			get { return amount.Value; }
+		}
+
+		public BigInteger Exponent
+		{
+			get { return exponent.Value; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(currency, amount, exponent);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/QCStatement.cs b/crypto/src/asn1/x509/qualified/QCStatement.cs
new file mode 100644
index 000000000..317f03447
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/QCStatement.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The QCStatement object.
+    * <pre>
+    * QCStatement ::= SEQUENCE {
+    *   statementId        OBJECT IDENTIFIER,
+    *   statementInfo      ANY DEFINED BY statementId OPTIONAL}
+    * </pre>
+    */
+    public class QCStatement
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	qcStatementId;
+        private readonly Asn1Encodable			qcStatementInfo;
+
+		public static QCStatement GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is QCStatement)
+            {
+                return (QCStatement) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+				return new QCStatement(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		private QCStatement(
+            Asn1Sequence seq)
+        {
+			qcStatementId = DerObjectIdentifier.GetInstance(seq[0]);
+
+			if (seq.Count > 1)
+			{
+				qcStatementInfo = seq[1];
+			}
+        }
+
+		public QCStatement(
+            DerObjectIdentifier qcStatementId)
+        {
+            this.qcStatementId = qcStatementId;
+        }
+
+        public QCStatement(
+            DerObjectIdentifier qcStatementId,
+            Asn1Encodable       qcStatementInfo)
+        {
+            this.qcStatementId = qcStatementId;
+            this.qcStatementInfo = qcStatementInfo;
+        }
+
+		public DerObjectIdentifier StatementId
+		{
+			get { return qcStatementId; }
+		}
+
+		public Asn1Encodable StatementInfo
+		{
+			get { return qcStatementInfo; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector(qcStatementId);
+
+			if (qcStatementInfo != null)
+            {
+                seq.Add(qcStatementInfo);
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs b/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
new file mode 100644
index 000000000..8ebd69edb
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/RFC3739QCObjectIdentifiers.cs
@@ -0,0 +1,21 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    public sealed class Rfc3739QCObjectIdentifiers
+    {
+		private Rfc3739QCObjectIdentifiers()
+		{
+		}
+
+		//
+        // base id
+        //
+        public static readonly DerObjectIdentifier IdQcs = new DerObjectIdentifier("1.3.6.1.5.5.7.11");
+
+        public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV1 = new DerObjectIdentifier(IdQcs+".1");
+        public static readonly DerObjectIdentifier IdQcsPkixQCSyntaxV2 = new DerObjectIdentifier(IdQcs+".2");
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/SemanticsInformation.cs b/crypto/src/asn1/x509/qualified/SemanticsInformation.cs
new file mode 100644
index 000000000..72e7cd0e1
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/SemanticsInformation.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The SemanticsInformation object.
+    * <pre>
+    *       SemanticsInformation ::= SEQUENCE {
+    *         semanticsIdentifier        OBJECT IDENTIFIER   OPTIONAL,
+    *         nameRegistrationAuthorities NameRegistrationAuthorities
+    *                                                         OPTIONAL }
+    *         (WITH COMPONENTS {..., semanticsIdentifier PRESENT}|
+    *          WITH COMPONENTS {..., nameRegistrationAuthorities PRESENT})
+    *
+    *     NameRegistrationAuthorities ::=  SEQUENCE SIZE (1..MAX) OF
+    *         GeneralName
+    * </pre>
+    */
+    public class SemanticsInformation
+		: Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	semanticsIdentifier;
+        private readonly GeneralName[]			nameRegistrationAuthorities;
+
+		public static SemanticsInformation GetInstance(
+			object obj)
+        {
+            if (obj == null || obj is SemanticsInformation)
+            {
+                return (SemanticsInformation) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SemanticsInformation(Asn1Sequence.GetInstance(obj));
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public SemanticsInformation(
+			Asn1Sequence seq)
+        {
+            if (seq.Count < 1)
+            {
+                throw new ArgumentException("no objects in SemanticsInformation");
+            }
+
+			IEnumerator e = seq.GetEnumerator();
+			e.MoveNext();
+            object obj = e.Current;
+            if (obj is DerObjectIdentifier)
+            {
+                semanticsIdentifier = DerObjectIdentifier.GetInstance(obj);
+                if (e.MoveNext())
+                {
+                    obj  = e.Current;
+                }
+                else
+                {
+                    obj  = null;
+                }
+            }
+
+			if (obj  != null)
+            {
+                Asn1Sequence generalNameSeq = Asn1Sequence.GetInstance(obj );
+                nameRegistrationAuthorities = new GeneralName[generalNameSeq.Count];
+                for (int i= 0; i < generalNameSeq.Count; i++)
+                {
+                    nameRegistrationAuthorities[i] = GeneralName.GetInstance(generalNameSeq[i]);
+                }
+            }
+        }
+
+		public SemanticsInformation(
+            DerObjectIdentifier semanticsIdentifier,
+            GeneralName[] generalNames)
+        {
+            this.semanticsIdentifier = semanticsIdentifier;
+            this.nameRegistrationAuthorities = generalNames;
+        }
+
+		public SemanticsInformation(
+			DerObjectIdentifier semanticsIdentifier)
+        {
+            this.semanticsIdentifier = semanticsIdentifier;
+        }
+
+        public SemanticsInformation(
+			GeneralName[] generalNames)
+        {
+            this.nameRegistrationAuthorities = generalNames;
+        }
+
+		public DerObjectIdentifier SemanticsIdentifier { get { return semanticsIdentifier; } }
+
+		public GeneralName[] GetNameRegistrationAuthorities()
+        {
+            return nameRegistrationAuthorities;
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector seq = new Asn1EncodableVector();
+
+            if (this.semanticsIdentifier != null)
+            {
+                seq.Add(semanticsIdentifier);
+            }
+
+			if (this.nameRegistrationAuthorities != null)
+            {
+                seq.Add(new DerSequence(nameRegistrationAuthorities));
+            }
+
+			return new DerSequence(seq);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs b/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
new file mode 100644
index 000000000..a77e54acb
--- /dev/null
+++ b/crypto/src/asn1/x509/qualified/TypeOfBiometricData.cs
@@ -0,0 +1,91 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X509.Qualified
+{
+    /**
+    * The TypeOfBiometricData object.
+    * <pre>
+    * TypeOfBiometricData ::= CHOICE {
+    *   predefinedBiometricType   PredefinedBiometricType,
+    *   biometricDataOid          OBJECT IDENTIFIER }
+    *
+    * PredefinedBiometricType ::= INTEGER {
+    *   picture(0),handwritten-signature(1)}
+    *   (picture|handwritten-signature)
+    * </pre>
+    */
+    public class TypeOfBiometricData
+        : Asn1Encodable, IAsn1Choice
+    {
+        public const int Picture				= 0;
+        public const int HandwrittenSignature	= 1;
+
+		internal Asn1Encodable obj;
+
+		public static TypeOfBiometricData GetInstance(
+			object obj)
+        {
+            if (obj == null || obj is TypeOfBiometricData)
+            {
+                return (TypeOfBiometricData) obj;
+            }
+
+			if (obj is DerInteger)
+            {
+                DerInteger predefinedBiometricTypeObj = DerInteger.GetInstance(obj);
+                int predefinedBiometricType = predefinedBiometricTypeObj.Value.IntValue;
+
+				return new TypeOfBiometricData(predefinedBiometricType);
+            }
+
+			if (obj is DerObjectIdentifier)
+            {
+                DerObjectIdentifier BiometricDataOid = DerObjectIdentifier.GetInstance(obj);
+                return new TypeOfBiometricData(BiometricDataOid);
+            }
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		public TypeOfBiometricData(
+			int predefinedBiometricType)
+        {
+            if (predefinedBiometricType == Picture || predefinedBiometricType == HandwrittenSignature)
+            {
+                obj = new DerInteger(predefinedBiometricType);
+            }
+            else
+            {
+                throw new ArgumentException("unknow PredefinedBiometricType : " + predefinedBiometricType);
+            }
+        }
+
+		public TypeOfBiometricData(
+			DerObjectIdentifier biometricDataOid)
+        {
+            obj = biometricDataOid;
+        }
+
+		public bool IsPredefined
+		{
+			get { return obj is DerInteger; }
+		}
+
+		public int PredefinedBiometricType
+		{
+			get { return ((DerInteger) obj).Value.IntValue; }
+		}
+
+		public DerObjectIdentifier BiometricDataOid
+		{
+			get { return (DerObjectIdentifier) obj; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+            return obj.ToAsn1Object();
+        }
+    }
+}
diff --git a/crypto/src/asn1/x509/sigi/NameOrPseudonym.cs b/crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
new file mode 100644
index 000000000..222895cf1
--- /dev/null
+++ b/crypto/src/asn1/x509/sigi/NameOrPseudonym.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	* Structure for a name or pseudonym.
+	* 
+	* <pre>
+	*       NameOrPseudonym ::= CHOICE {
+	*     	   surAndGivenName SEQUENCE {
+	*     	     surName DirectoryString,
+	*     	     givenName SEQUENCE OF DirectoryString 
+	*         },
+	*     	   pseudonym DirectoryString 
+	*       }
+	* </pre>
+	* 
+	* @see org.bouncycastle.asn1.x509.sigi.PersonalData
+	* 
+	*/
+	public class NameOrPseudonym
+		: Asn1Encodable, IAsn1Choice
+	{
+		private readonly DirectoryString	pseudonym;
+		private readonly DirectoryString	surname;
+		private readonly Asn1Sequence		givenName;
+
+		public static NameOrPseudonym GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NameOrPseudonym)
+			{
+				return (NameOrPseudonym)obj;
+			}
+
+			if (obj is IAsn1String)
+			{
+				return new NameOrPseudonym(DirectoryString.GetInstance(obj));
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NameOrPseudonym((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from DERString.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		* @param pseudonym pseudonym value to use.
+		*/
+		public NameOrPseudonym(
+			DirectoryString pseudonym)
+		{
+			this.pseudonym = pseudonym;
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private NameOrPseudonym(
+			Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			if (!(seq[0] is IAsn1String))
+				throw new ArgumentException("Bad object encountered: " + seq[0].GetType().Name);
+
+			surname = DirectoryString.GetInstance(seq[0]);
+			givenName = Asn1Sequence.GetInstance(seq[1]);
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param pseudonym The pseudonym.
+		*/
+		public NameOrPseudonym(
+			string pseudonym)
+			: this(new DirectoryString(pseudonym))
+		{
+		}
+
+		/**
+		 * Constructor from a given details.
+		 *
+		 * @param surname   The surname.
+		 * @param givenName A sequence of directory strings making up the givenName
+		 */
+		public NameOrPseudonym(
+			DirectoryString	surname,
+			Asn1Sequence	givenName)
+		{
+			this.surname = surname;
+			this.givenName = givenName;
+		}
+
+		public DirectoryString Pseudonym
+		{
+			get { return pseudonym; }
+		}
+
+		public DirectoryString Surname
+		{
+			get { return surname; }
+		}
+
+		public DirectoryString[] GetGivenName()
+		{
+			DirectoryString[] items = new DirectoryString[givenName.Count];
+			int count = 0;
+			foreach (object o in givenName)
+			{
+				items[count++] = DirectoryString.GetInstance(o);
+			}
+			return items;
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*       NameOrPseudonym ::= CHOICE {
+		*     	   surAndGivenName SEQUENCE {
+		*     	     surName DirectoryString,
+		*     	     givenName SEQUENCE OF DirectoryString
+		*         },
+		*     	   pseudonym DirectoryString
+		*       }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			if (pseudonym != null)
+			{
+				return pseudonym.ToAsn1Object();
+			}
+
+			return new DerSequence(surname, givenName);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/sigi/PersonalData.cs b/crypto/src/asn1/x509/sigi/PersonalData.cs
new file mode 100644
index 000000000..6acdc7308
--- /dev/null
+++ b/crypto/src/asn1/x509/sigi/PersonalData.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	* Contains personal data for the otherName field in the subjectAltNames
+	* extension.
+	* <p/>
+	* <pre>
+	*     PersonalData ::= SEQUENCE {
+	*       nameOrPseudonym NameOrPseudonym,
+	*       nameDistinguisher [0] INTEGER OPTIONAL,
+	*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+	*       placeOfBirth [2] DirectoryString OPTIONAL,
+	*       gender [3] PrintableString OPTIONAL,
+	*       postalAddress [4] DirectoryString OPTIONAL
+	*       }
+	* </pre>
+	*
+	* @see org.bouncycastle.asn1.x509.sigi.NameOrPseudonym
+	* @see org.bouncycastle.asn1.x509.sigi.SigIObjectIdentifiers
+	*/
+	public class PersonalData
+		: Asn1Encodable
+	{
+		private readonly NameOrPseudonym	nameOrPseudonym;
+		private readonly BigInteger			nameDistinguisher;
+		private readonly DerGeneralizedTime	dateOfBirth;
+		private readonly DirectoryString	placeOfBirth;
+		private readonly string				gender;
+		private readonly DirectoryString	postalAddress;
+
+		public static PersonalData GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is PersonalData)
+			{
+				return (PersonalData) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PersonalData((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		* Constructor from Asn1Sequence.
+		* <p/>
+		* The sequence is of type NameOrPseudonym:
+		* <p/>
+		* <pre>
+		*     PersonalData ::= SEQUENCE {
+		*       nameOrPseudonym NameOrPseudonym,
+		*       nameDistinguisher [0] INTEGER OPTIONAL,
+		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+		*       placeOfBirth [2] DirectoryString OPTIONAL,
+		*       gender [3] PrintableString OPTIONAL,
+		*       postalAddress [4] DirectoryString OPTIONAL
+		*       }
+		* </pre>
+		*
+		* @param seq The ASN.1 sequence.
+		*/
+		private PersonalData(
+			Asn1Sequence seq)
+		{
+			if (seq.Count < 1)
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+
+			IEnumerator e = seq.GetEnumerator();
+			e.MoveNext();
+
+			nameOrPseudonym = NameOrPseudonym.GetInstance(e.Current);
+
+			while (e.MoveNext())
+			{
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(e.Current);
+				int tag = o.TagNo;
+				switch (tag)
+				{
+					case 0:
+						nameDistinguisher = DerInteger.GetInstance(o, false).Value;
+						break;
+					case 1:
+						dateOfBirth = DerGeneralizedTime.GetInstance(o, false);
+						break;
+					case 2:
+						placeOfBirth = DirectoryString.GetInstance(o, true);
+						break;
+					case 3:
+						gender = DerPrintableString.GetInstance(o, false).GetString();
+						break;
+					case 4:
+						postalAddress = DirectoryString.GetInstance(o, true);
+						break;
+					default:
+						throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+		}
+
+		/**
+		* Constructor from a given details.
+		*
+		* @param nameOrPseudonym  Name or pseudonym.
+		* @param nameDistinguisher Name distinguisher.
+		* @param dateOfBirth      Date of birth.
+		* @param placeOfBirth     Place of birth.
+		* @param gender           Gender.
+		* @param postalAddress    Postal Address.
+		*/
+		public PersonalData(
+			NameOrPseudonym		nameOrPseudonym,
+			BigInteger			nameDistinguisher,
+			DerGeneralizedTime	dateOfBirth,
+			DirectoryString		placeOfBirth,
+			string				gender,
+			DirectoryString		postalAddress)
+		{
+			this.nameOrPseudonym = nameOrPseudonym;
+			this.dateOfBirth = dateOfBirth;
+			this.gender = gender;
+			this.nameDistinguisher = nameDistinguisher;
+			this.postalAddress = postalAddress;
+			this.placeOfBirth = placeOfBirth;
+		}
+
+		public NameOrPseudonym NameOrPseudonym
+		{
+			get { return nameOrPseudonym; }
+		}
+
+		public BigInteger NameDistinguisher
+		{
+			get { return nameDistinguisher; }
+		}
+
+		public DerGeneralizedTime DateOfBirth
+		{
+			get { return dateOfBirth; }
+		}
+
+		public DirectoryString PlaceOfBirth
+		{
+			get { return placeOfBirth; }
+		}
+
+		public string Gender
+		{
+			get { return gender; }
+		}
+
+		public DirectoryString PostalAddress
+		{
+			get { return postalAddress; }
+		}
+
+		/**
+		* Produce an object suitable for an Asn1OutputStream.
+		* <p/>
+		* Returns:
+		* <p/>
+		* <pre>
+		*     PersonalData ::= SEQUENCE {
+		*       nameOrPseudonym NameOrPseudonym,
+		*       nameDistinguisher [0] INTEGER OPTIONAL,
+		*       dateOfBirth [1] GeneralizedTime OPTIONAL,
+		*       placeOfBirth [2] DirectoryString OPTIONAL,
+		*       gender [3] PrintableString OPTIONAL,
+		*       postalAddress [4] DirectoryString OPTIONAL
+		*       }
+		* </pre>
+		*
+		* @return an Asn1Object
+		*/
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+			vec.Add(nameOrPseudonym);
+			if (nameDistinguisher != null)
+			{
+				vec.Add(new DerTaggedObject(false, 0, new DerInteger(nameDistinguisher)));
+			}
+			if (dateOfBirth != null)
+			{
+				vec.Add(new DerTaggedObject(false, 1, dateOfBirth));
+			}
+			if (placeOfBirth != null)
+			{
+				vec.Add(new DerTaggedObject(true, 2, placeOfBirth));
+			}
+			if (gender != null)
+			{
+				vec.Add(new DerTaggedObject(false, 3, new DerPrintableString(gender, true)));
+			}
+			if (postalAddress != null)
+			{
+				vec.Add(new DerTaggedObject(true, 4, postalAddress));
+			}
+			return new DerSequence(vec);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs b/crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
new file mode 100644
index 000000000..682311adc
--- /dev/null
+++ b/crypto/src/asn1/x509/sigi/SigIObjectIdentifiers.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509.SigI
+{
+	/**
+	 * Object Identifiers of SigI specifciation (German Signature Law
+	 * Interoperability specification).
+	 */
+	public sealed class SigIObjectIdentifiers
+	{
+		private SigIObjectIdentifiers()
+		{
+		}
+
+		public readonly static DerObjectIdentifier IdSigI = new DerObjectIdentifier("1.3.36.8");
+
+		/**
+		* Key purpose IDs for German SigI (Signature Interoperability
+		* Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigIKP = new DerObjectIdentifier(IdSigI + ".2");
+
+		/**
+		* Certificate policy IDs for German SigI (Signature Interoperability
+		* Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigICP = new DerObjectIdentifier(IdSigI + ".1");
+
+		/**
+		* Other Name IDs for German SigI (Signature Interoperability Specification)
+		*/
+		public readonly static DerObjectIdentifier IdSigION = new DerObjectIdentifier(IdSigI + ".4");
+
+		/**
+		* To be used for for the generation of directory service certificates.
+		*/
+		public static readonly DerObjectIdentifier IdSigIKPDirectoryService = new DerObjectIdentifier(IdSigIKP + ".1");
+
+		/**
+		* ID for PersonalData
+		*/
+		public static readonly DerObjectIdentifier IdSigIONPersonalData = new DerObjectIdentifier(IdSigION + ".1");
+
+		/**
+		* Certificate is conform to german signature law.
+		*/
+		public static readonly DerObjectIdentifier IdSigICPSigConform = new DerObjectIdentifier(IdSigICP + ".1");
+	}
+}
diff --git a/crypto/src/asn1/x9/DHDomainParameters.cs b/crypto/src/asn1/x9/DHDomainParameters.cs
new file mode 100644
index 000000000..8de869694
--- /dev/null
+++ b/crypto/src/asn1/x9/DHDomainParameters.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public class DHDomainParameters
+		: Asn1Encodable
+	{
+		private readonly DerInteger p, g, q, j;
+		private readonly DHValidationParms validationParms;
+
+		public static DHDomainParameters GetInstance(Asn1TaggedObject obj, bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static DHDomainParameters GetInstance(object obj)
+		{
+			if (obj == null || obj is DHDomainParameters)
+				return (DHDomainParameters)obj;
+
+			if (obj is Asn1Sequence)
+				return new DHDomainParameters((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid DHDomainParameters: " + obj.GetType().FullName, "obj");
+		}
+
+		public DHDomainParameters(DerInteger p, DerInteger g, DerInteger q, DerInteger j,
+			DHValidationParms validationParms)
+		{
+			if (p == null)
+				throw new ArgumentNullException("p");
+			if (g == null)
+				throw new ArgumentNullException("g");
+			if (q == null)
+				throw new ArgumentNullException("q");
+
+			this.p = p;
+			this.g = g;
+			this.q = q;
+			this.j = j;
+			this.validationParms = validationParms;
+		}
+
+		private DHDomainParameters(Asn1Sequence seq)
+		{
+			if (seq.Count < 3 || seq.Count > 5)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			IEnumerator e = seq.GetEnumerator();
+			this.p = DerInteger.GetInstance(GetNext(e));
+			this.g = DerInteger.GetInstance(GetNext(e));
+			this.q = DerInteger.GetInstance(GetNext(e));
+
+			Asn1Encodable next = GetNext(e);
+
+			if (next != null && next is DerInteger)
+			{
+				this.j = DerInteger.GetInstance(next);
+				next = GetNext(e);
+			}
+
+			if (next != null)
+			{
+				this.validationParms = DHValidationParms.GetInstance(next.ToAsn1Object());
+			}
+		}
+
+		private static Asn1Encodable GetNext(IEnumerator e)
+		{
+			return e.MoveNext() ? (Asn1Encodable)e.Current : null;
+		}
+
+		public DerInteger P
+		{
+			get { return this.p; }
+		}
+
+		public DerInteger G
+		{
+			get { return this.g; }
+		}
+
+		public DerInteger Q
+		{
+			get { return this.q; }
+		}
+
+		public DerInteger J
+		{
+			get { return this.j; }
+		}
+
+		public DHValidationParms ValidationParms
+		{
+			get { return this.validationParms; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector(p, g, q);
+
+			if (this.j != null)
+			{
+				v.Add(this.j);
+			}
+
+			if (this.validationParms != null)
+			{
+				v.Add(this.validationParms);
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x9/DHPublicKey.cs b/crypto/src/asn1/x9/DHPublicKey.cs
new file mode 100644
index 000000000..1a20a8a16
--- /dev/null
+++ b/crypto/src/asn1/x9/DHPublicKey.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public class DHPublicKey
+		: Asn1Encodable
+	{
+		private readonly DerInteger y;
+
+		public static DHPublicKey GetInstance(Asn1TaggedObject obj, bool isExplicit)
+		{
+			return GetInstance(DerInteger.GetInstance(obj, isExplicit));
+		}
+
+		public static DHPublicKey GetInstance(object obj)
+		{
+			if (obj == null || obj is DHPublicKey)
+				return (DHPublicKey)obj;
+
+			if (obj is DerInteger)
+				return new DHPublicKey((DerInteger)obj);
+
+			throw new ArgumentException("Invalid DHPublicKey: " + obj.GetType().FullName, "obj");
+		}
+
+		public DHPublicKey(DerInteger y)
+		{
+			if (y == null)
+				throw new ArgumentNullException("y");
+
+			this.y = y;
+		}
+
+		public DerInteger Y
+		{
+			get { return this.y; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return this.y;
+		}
+	}
+}
diff --git a/crypto/src/asn1/x9/DHValidationParms.cs b/crypto/src/asn1/x9/DHValidationParms.cs
new file mode 100644
index 000000000..a37964cfb
--- /dev/null
+++ b/crypto/src/asn1/x9/DHValidationParms.cs
@@ -0,0 +1,62 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public class DHValidationParms
+		: Asn1Encodable
+	{
+		private readonly DerBitString seed;
+		private readonly DerInteger pgenCounter;
+
+		public static DHValidationParms GetInstance(Asn1TaggedObject obj, bool isExplicit)
+		{
+			return GetInstance(Asn1Sequence.GetInstance(obj, isExplicit));
+		}
+
+		public static DHValidationParms GetInstance(object obj)
+		{
+			if (obj == null || obj is DHDomainParameters)
+				return (DHValidationParms)obj;
+
+			if (obj is Asn1Sequence)
+				return new DHValidationParms((Asn1Sequence)obj);
+
+			throw new ArgumentException("Invalid DHValidationParms: " + obj.GetType().FullName, "obj");
+		}
+		
+		public DHValidationParms(DerBitString seed, DerInteger pgenCounter)
+		{
+			if (seed == null)
+				throw new ArgumentNullException("seed");
+			if (pgenCounter == null)
+				throw new ArgumentNullException("pgenCounter");
+
+			this.seed = seed;
+			this.pgenCounter = pgenCounter;
+		}
+
+		private DHValidationParms(Asn1Sequence seq)
+		{
+			if (seq.Count != 2)
+				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+
+			this.seed = DerBitString.GetInstance(seq[0]);
+			this.pgenCounter = DerInteger.GetInstance(seq[1]);
+		}
+
+		public DerBitString Seed
+		{
+			get { return this.seed; }
+		}
+
+		public DerInteger PgenCounter
+		{
+			get { return this.pgenCounter; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new DerSequence(seed, pgenCounter);
+		}
+	}
+}
diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs
new file mode 100644
index 000000000..0030d376b
--- /dev/null
+++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * A general class that reads all X9.62 style EC curve tables.
+     */
+    public class ECNamedCurveTable
+    {
+        /**
+         * return a X9ECParameters object 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 an X9ECParameters object or null if the curve is not available.
+         */
+        public static X9ECParameters GetByName(string name)
+        {
+            X9ECParameters ecP = X962NamedCurves.GetByName(name);
+
+            if (ecP == null)
+            {
+                ecP = SecNamedCurves.GetByName(name);
+            }
+
+            if (ecP == null)
+            {
+                ecP = TeleTrusTNamedCurves.GetByName(name);
+            }
+
+            if (ecP == null)
+            {
+                ecP = NistNamedCurves.GetByName(name);
+            }
+
+            return ecP;
+        }
+
+        /**
+         * return the object identifier signified by the passed in name. Null
+         * if there is no object identifier associated with name.
+         *
+         * @return the object identifier associated with name, if present.
+         */
+        public static DerObjectIdentifier GetOid(string name)
+        {
+            DerObjectIdentifier oid = X962NamedCurves.GetOid(name);
+
+            if (oid == null)
+            {
+                oid = SecNamedCurves.GetOid(name);
+            }
+
+            if (oid == null)
+            {
+                oid = TeleTrusTNamedCurves.GetOid(name);
+            }
+
+            if (oid == null)
+            {
+                oid = NistNamedCurves.GetOid(name);
+            }
+
+            return oid;
+        }
+
+        /**
+         * return a X9ECParameters object representing the passed in named
+         * curve.
+         *
+         * @param oid the object id of the curve requested
+         * @return an X9ECParameters object or null if the curve is not available.
+         */
+        public static X9ECParameters GetByOid(DerObjectIdentifier oid)
+        {
+            X9ECParameters ecP = X962NamedCurves.GetByOid(oid);
+
+            if (ecP == null)
+            {
+                ecP = SecNamedCurves.GetByOid(oid);
+            }
+
+            if (ecP == null)
+            {
+                ecP = TeleTrusTNamedCurves.GetByOid(oid);
+            }
+
+            // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup
+
+            return ecP;
+        }
+
+        /**
+         * return an enumeration of the names of the available curves.
+         *
+         * @return an enumeration of the names of the available curves.
+         */
+        public static IEnumerable Names
+        {
+            get
+            {
+                IList v = Platform.CreateArrayList();
+                CollectionUtilities.AddRange(v, X962NamedCurves.Names);
+                CollectionUtilities.AddRange(v, SecNamedCurves.Names);
+                CollectionUtilities.AddRange(v, NistNamedCurves.Names);
+                CollectionUtilities.AddRange(v, TeleTrusTNamedCurves.Names);
+                return v;
+            }
+        }
+    }
+}
diff --git a/crypto/src/asn1/x9/KeySpecificInfo.cs b/crypto/src/asn1/x9/KeySpecificInfo.cs
new file mode 100644
index 000000000..46298646b
--- /dev/null
+++ b/crypto/src/asn1/x9/KeySpecificInfo.cs
@@ -0,0 +1,58 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See
+     * RFC 2631, or X9.42, for further details.
+     */
+    public class KeySpecificInfo
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	algorithm;
+        private Asn1OctetString		counter;
+
+		public KeySpecificInfo(
+            DerObjectIdentifier	algorithm,
+            Asn1OctetString		counter)
+        {
+            this.algorithm = algorithm;
+            this.counter = counter;
+        }
+
+		public KeySpecificInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            algorithm = (DerObjectIdentifier)e.Current;
+            e.MoveNext();
+            counter = (Asn1OctetString)e.Current;
+        }
+
+		public DerObjectIdentifier Algorithm
+        {
+            get { return algorithm; }
+        }
+
+		public Asn1OctetString Counter
+        {
+            get { return counter; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  KeySpecificInfo ::= Sequence {
+         *      algorithm OBJECT IDENTIFIER,
+         *      counter OCTET STRING SIZE (4..4)
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(algorithm, counter);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x9/OtherInfo.cs b/crypto/src/asn1/x9/OtherInfo.cs
new file mode 100644
index 000000000..21863bd17
--- /dev/null
+++ b/crypto/src/asn1/x9/OtherInfo.cs
@@ -0,0 +1,88 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See
+     * RFC 2631, or X9.42, for further details.
+     */
+    public class OtherInfo
+        : Asn1Encodable
+    {
+        private KeySpecificInfo	keyInfo;
+        private Asn1OctetString	partyAInfo;
+        private Asn1OctetString	suppPubInfo;
+
+		public OtherInfo(
+            KeySpecificInfo	keyInfo,
+            Asn1OctetString	partyAInfo,
+            Asn1OctetString	suppPubInfo)
+        {
+            this.keyInfo = keyInfo;
+            this.partyAInfo = partyAInfo;
+            this.suppPubInfo = suppPubInfo;
+        }
+
+		public OtherInfo(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            keyInfo = new KeySpecificInfo((Asn1Sequence) e.Current);
+
+			while (e.MoveNext())
+            {
+                DerTaggedObject o = (DerTaggedObject) e.Current;
+
+				if (o.TagNo == 0)
+                {
+                    partyAInfo = (Asn1OctetString) o.GetObject();
+                }
+                else if ((int) o.TagNo == 2)
+                {
+                    suppPubInfo = (Asn1OctetString) o.GetObject();
+                }
+            }
+        }
+
+		public KeySpecificInfo KeyInfo
+        {
+			get { return keyInfo; }
+        }
+
+		public Asn1OctetString PartyAInfo
+        {
+			get { return partyAInfo; }
+        }
+
+		public Asn1OctetString SuppPubInfo
+        {
+            get { return suppPubInfo; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  OtherInfo ::= Sequence {
+         *      keyInfo KeySpecificInfo,
+         *      partyAInfo [0] OCTET STRING OPTIONAL,
+         *      suppPubInfo [2] OCTET STRING
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(keyInfo);
+
+			if (partyAInfo != null)
+            {
+                v.Add(new DerTaggedObject(0, partyAInfo));
+            }
+
+			v.Add(new DerTaggedObject(2, suppPubInfo));
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs
index de80ca280..6b76c4eb4 100644
--- a/crypto/src/asn1/x9/X962NamedCurves.cs
+++ b/crypto/src/asn1/x9/X962NamedCurves.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
@@ -10,724 +9,745 @@ using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Asn1.X9
 {
-	/**
-	 * table of the current named curves defined in X.962 EC-DSA.
-	 */
-	public sealed class X962NamedCurves
-	{
-		private X962NamedCurves()
-		{
-		}
-
-		internal class Prime192v1Holder
-			: X9ECParametersHolder
-		{
-			private Prime192v1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Prime192v1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve cFp192v1 = new FpCurve(
-					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.One,
-					Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
-			}
-		}
-
-		internal class Prime192v2Holder
-			: X9ECParametersHolder
-		{
-			private Prime192v2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Prime192v2Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve cFp192v2 = new FpCurve(
-					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.One,
-					Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
-			}
-		}
-
-		internal class Prime192v3Holder
-			: X9ECParametersHolder
-		{
-			private Prime192v3Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Prime192v3Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve cFp192v3 = new FpCurve(
-					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.One,
-					Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
-			}
-		}
-
-		internal class Prime239v1Holder
-			: X9ECParametersHolder
-		{
-			private Prime239v1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Prime239v1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve cFp239v1 = new FpCurve(
-					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.One,
-					Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
-			}
-		}
-
-		internal class Prime239v2Holder
-			: X9ECParametersHolder
-		{
-			private Prime239v2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Prime239v2Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve cFp239v2 = new FpCurve(
-					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.One,
-					Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
-			}
-		}
-
-		internal class Prime239v3Holder
-			: X9ECParametersHolder
-		{
-			private Prime239v3Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Prime239v3Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve cFp239v3 = new FpCurve(
-					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.One,
-					Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
-			}
-		}
-
-		internal class Prime256v1Holder
-			: X9ECParametersHolder
-		{
-			private Prime256v1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new Prime256v1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				ECCurve cFp256v1 = new FpCurve(
-					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.One,
-					Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90"));
-			}
-		}
-
-		/*
-		 * F2m Curves
-		 */
-		internal class C2pnb163v1Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb163v1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb163v1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16);
-				BigInteger h = BigInteger.ValueOf(2);
-
-				ECCurve c2m163v1 = new F2mCurve(
-					163,
-					1, 2, 8,
-					new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16),
-					new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m163v1,
-					c2m163v1.DecodePoint(
-						Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
-					n, h,
-					Hex.Decode("D2COFB15760860DEF1EEF4D696E6768756151754"));
-			}
-		}
-
-		internal class C2pnb163v2Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb163v2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb163v2Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16);
-				BigInteger h = BigInteger.ValueOf(2);
-
-				ECCurve c2m163v2 = new F2mCurve(
-					163,
-					1, 2, 8,
-					new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16),
-					new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m163v2,
-					c2m163v2.DecodePoint(
-						Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2pnb163v3Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb163v3Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb163v3Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16);
-				BigInteger h = BigInteger.ValueOf(2);
-
-				ECCurve c2m163v3 = new F2mCurve(
-					163,
-					1, 2, 8,
-					new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16),
-					new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m163v3,
-					c2m163v3.DecodePoint(Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2pnb176w1Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb176w1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb176w1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16);
-				BigInteger h = BigInteger.ValueOf(0xFF6E);
-
-				ECCurve c2m176w1 = new F2mCurve(
-					176,
-					1, 2, 43,
-					new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16),
-					new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m176w1,
-					c2m176w1.DecodePoint(
-						Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2tnb191v1Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb191v1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb191v1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16);
-				BigInteger h = BigInteger.ValueOf(2);
-
-				ECCurve c2m191v1 = new F2mCurve(
-					191,
-					9,
-					new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16),
-					new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m191v1,
-					c2m191v1.DecodePoint(
-						Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
-					n, h,
-					Hex.Decode("4E13CA542744D696E67687561517552F279A8C84"));
-			}
-		}
-
-		internal class C2tnb191v2Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb191v2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb191v2Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16);
-				BigInteger h = BigInteger.ValueOf(4);
-
-				ECCurve c2m191v2 = new F2mCurve(
-					191,
-					9,
-					new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16),
-					new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m191v2,
-					c2m191v2.DecodePoint(
-						Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2tnb191v3Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb191v3Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb191v3Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16);
-				BigInteger h = BigInteger.ValueOf(6);
-
-				ECCurve c2m191v3 = new F2mCurve(
-					191,
-					9,
-					new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16),
-					new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m191v3,
-					c2m191v3.DecodePoint(
-						Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2pnb208w1Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb208w1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb208w1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16);
-				BigInteger h = BigInteger.ValueOf(0xFE48);
-
-				ECCurve c2m208w1 = new F2mCurve(
-					208,
-					1, 2, 83,
-					new BigInteger("0", 16),
-					new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m208w1,
-					c2m208w1.DecodePoint(
-						Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2tnb239v1Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb239v1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb239v1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16);
-				BigInteger h = BigInteger.ValueOf(4);
-
-				ECCurve c2m239v1 = new F2mCurve(
-					239,
-					36,
-					new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16),
-					new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m239v1,
-					c2m239v1.DecodePoint(
-						Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2tnb239v2Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb239v2Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb239v2Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16);
-				BigInteger h = BigInteger.ValueOf(6);
-
-				ECCurve c2m239v2 = new F2mCurve(
-					239,
-					36,
-					new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16),
-					new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m239v2,
-					c2m239v2.DecodePoint(
-						Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2tnb239v3Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb239v3Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb239v3Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16);
-				BigInteger h = BigInteger.ValueOf(10);
-
-				ECCurve c2m239v3 = new F2mCurve(
-					239,
-					36,
-					new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16),
-					new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m239v3,
-					c2m239v3.DecodePoint(
-						Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2pnb272w1Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb272w1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb272w1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16);
-				BigInteger h = BigInteger.ValueOf(0xFF06);
-
-				ECCurve c2m272w1 = new F2mCurve(
-					272,
-					1, 3, 56,
-					new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16),
-					new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m272w1,
-					c2m272w1.DecodePoint(
-						Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2pnb304w1Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb304w1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb304w1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16);
-				BigInteger h = BigInteger.ValueOf(0xFE2E);
-
-				ECCurve c2m304w1 = new F2mCurve(
-					304,
-					1, 2, 11,
-					new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16),
-					new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m304w1,
-					c2m304w1.DecodePoint(
-						Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2tnb359v1Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb359v1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb359v1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16);
-				BigInteger h = BigInteger.ValueOf(0x4C);
-
-				ECCurve c2m359v1 = new F2mCurve(
-					359,
-					68,
-					new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16),
-					new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m359v1,
-					c2m359v1.DecodePoint(
-						Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2pnb368w1Holder
-			: X9ECParametersHolder
-		{
-			private C2pnb368w1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2pnb368w1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16);
-				BigInteger h = BigInteger.ValueOf(0xFF70);
-
-				ECCurve c2m368w1 = new F2mCurve(
-					368,
-					1, 2, 85,
-					new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16),
-					new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m368w1,
-					c2m368w1.DecodePoint(
-						Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
-					n, h,
-					null);
-			}
-		}
-
-		internal class C2tnb431r1Holder
-			: X9ECParametersHolder
-		{
-			private C2tnb431r1Holder() {}
-
-			internal static readonly X9ECParametersHolder Instance = new C2tnb431r1Holder();
-
-			protected override X9ECParameters CreateParameters()
-			{
-				BigInteger n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16);
-				BigInteger h = BigInteger.ValueOf(0x2760);
-
-				ECCurve c2m431r1 = new F2mCurve(
-					431,
-					120,
-					new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16),
-					new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16),
-					n, h);
-
-				return new X9ECParameters(
-					c2m431r1,
-					c2m431r1.DecodePoint(
-						Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
-					n, h,
-					null);
-			}
-		}
-
-		private static readonly IDictionary objIds = Platform.CreateHashtable();
+    /**
+     * table of the current named curves defined in X.962 EC-DSA.
+     */
+    public sealed class X962NamedCurves
+    {
+        private X962NamedCurves()
+        {
+        }
+
+        internal class Prime192v1Holder
+            : X9ECParametersHolder
+        {
+            private Prime192v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Prime192v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16);
+                BigInteger h = BigInteger.One;
+
+                ECCurve cFp192v1 = new FpCurve(
+                    new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                    new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                    new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    cFp192v1,
+                    cFp192v1.DecodePoint(
+                        Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
+                    n, h,
+                    Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
+            }
+        }
+
+        internal class Prime192v2Holder
+            : X9ECParametersHolder
+        {
+            private Prime192v2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Prime192v2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16);
+                BigInteger h = BigInteger.One;
+
+                ECCurve cFp192v2 = new FpCurve(
+                    new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                    new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                    new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    cFp192v2,
+                    cFp192v2.DecodePoint(
+                        Hex.Decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
+                    n, h,
+                    Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
+            }
+        }
+
+        internal class Prime192v3Holder
+            : X9ECParametersHolder
+        {
+            private Prime192v3Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Prime192v3Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16);
+                BigInteger h = BigInteger.One;
+
+                ECCurve cFp192v3 = new FpCurve(
+                    new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+                    new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+                    new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    cFp192v3,
+                    cFp192v3.DecodePoint(
+                        Hex.Decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
+                    n, h,
+                    Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
+            }
+        }
+
+        internal class Prime239v1Holder
+            : X9ECParametersHolder
+        {
+            private Prime239v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Prime239v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16);
+                BigInteger h = BigInteger.One;
+
+                ECCurve cFp239v1 = new FpCurve(
+                    new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                    new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                    new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    cFp239v1,
+                    cFp239v1.DecodePoint(
+                        Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
+                    n, h,
+                    Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
+            }
+        }
+
+        internal class Prime239v2Holder
+            : X9ECParametersHolder
+        {
+            private Prime239v2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Prime239v2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16);
+                BigInteger h = BigInteger.One;
+
+                ECCurve cFp239v2 = new FpCurve(
+                    new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                    new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                    new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    cFp239v2,
+                    cFp239v2.DecodePoint(
+                        Hex.Decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
+                    n, h,
+                    Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
+            }
+        }
+
+        internal class Prime239v3Holder
+            : X9ECParametersHolder
+        {
+            private Prime239v3Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Prime239v3Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16);
+                BigInteger h = BigInteger.One;
+
+                ECCurve cFp239v3 = new FpCurve(
+                    new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+                    new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+                    new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    cFp239v3,
+                    cFp239v3.DecodePoint(
+                        Hex.Decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
+                    n, h,
+                    Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
+            }
+        }
+
+        internal class Prime256v1Holder
+            : X9ECParametersHolder
+        {
+            private Prime256v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Prime256v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16);
+                BigInteger h = BigInteger.One;
+
+                ECCurve cFp256v1 = new FpCurve(
+                    new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
+                    new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+                    new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    cFp256v1,
+                    cFp256v1.DecodePoint(
+                        Hex.Decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
+                    n, h,
+                    Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90"));
+            }
+        }
+
+        /*
+         * F2m Curves
+         */
+        internal class C2pnb163v1Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb163v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb163v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16);
+                BigInteger h = BigInteger.Two;
+
+                ECCurve c2m163v1 = new F2mCurve(
+                    163,
+                    1, 2, 8,
+                    new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16),
+                    new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m163v1,
+                    c2m163v1.DecodePoint(
+                        Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
+                    n, h,
+                    Hex.Decode("D2C0FB15760860DEF1EEF4D696E6768756151754"));
+            }
+        }
+
+        internal class C2pnb163v2Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb163v2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb163v2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16);
+                BigInteger h = BigInteger.Two;
+
+                ECCurve c2m163v2 = new F2mCurve(
+                    163,
+                    1, 2, 8,
+                    new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16),
+                    new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m163v2,
+                    c2m163v2.DecodePoint(
+                        Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2pnb163v3Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb163v3Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb163v3Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16);
+                BigInteger h = BigInteger.Two;
+
+                ECCurve c2m163v3 = new F2mCurve(
+                    163,
+                    1, 2, 8,
+                    new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16),
+                    new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m163v3,
+                    c2m163v3.DecodePoint(Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2pnb176w1Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb176w1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb176w1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16);
+                BigInteger h = BigInteger.ValueOf(0xFF6E);
+
+                ECCurve c2m176w1 = new F2mCurve(
+                    176,
+                    1, 2, 43,
+                    new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16),
+                    new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m176w1,
+                    c2m176w1.DecodePoint(
+                        Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2tnb191v1Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb191v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb191v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16);
+                BigInteger h = BigInteger.Two;
+
+                ECCurve c2m191v1 = new F2mCurve(
+                    191,
+                    9,
+                    new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16),
+                    new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m191v1,
+                    c2m191v1.DecodePoint(
+                        Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
+                    n, h,
+                    Hex.Decode("4E13CA542744D696E67687561517552F279A8C84"));
+            }
+        }
+
+        internal class C2tnb191v2Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb191v2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb191v2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16);
+                BigInteger h = BigInteger.ValueOf(4);
+
+                ECCurve c2m191v2 = new F2mCurve(
+                    191,
+                    9,
+                    new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16),
+                    new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m191v2,
+                    c2m191v2.DecodePoint(
+                        Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2tnb191v3Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb191v3Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb191v3Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16);
+                BigInteger h = BigInteger.ValueOf(6);
+
+                ECCurve c2m191v3 = new F2mCurve(
+                    191,
+                    9,
+                    new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16),
+                    new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m191v3,
+                    c2m191v3.DecodePoint(
+                        Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2pnb208w1Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb208w1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb208w1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16);
+                BigInteger h = BigInteger.ValueOf(0xFE48);
+
+                ECCurve c2m208w1 = new F2mCurve(
+                    208,
+                    1, 2, 83,
+                    new BigInteger("0", 16),
+                    new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m208w1,
+                    c2m208w1.DecodePoint(
+                        Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2tnb239v1Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb239v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb239v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16);
+                BigInteger h = BigInteger.ValueOf(4);
+
+                ECCurve c2m239v1 = new F2mCurve(
+                    239,
+                    36,
+                    new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16),
+                    new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m239v1,
+                    c2m239v1.DecodePoint(
+                        Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2tnb239v2Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb239v2Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb239v2Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16);
+                BigInteger h = BigInteger.ValueOf(6);
+
+                ECCurve c2m239v2 = new F2mCurve(
+                    239,
+                    36,
+                    new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16),
+                    new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m239v2,
+                    c2m239v2.DecodePoint(
+                        Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2tnb239v3Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb239v3Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb239v3Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16);
+                BigInteger h = BigInteger.ValueOf(10);
+
+                ECCurve c2m239v3 = new F2mCurve(
+                    239,
+                    36,
+                    new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16),
+                    new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m239v3,
+                    c2m239v3.DecodePoint(
+                        Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2pnb272w1Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb272w1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb272w1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16);
+                BigInteger h = BigInteger.ValueOf(0xFF06);
+
+                ECCurve c2m272w1 = new F2mCurve(
+                    272,
+                    1, 3, 56,
+                    new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16),
+                    new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m272w1,
+                    c2m272w1.DecodePoint(
+                        Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2pnb304w1Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb304w1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb304w1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16);
+                BigInteger h = BigInteger.ValueOf(0xFE2E);
+
+                ECCurve c2m304w1 = new F2mCurve(
+                    304,
+                    1, 2, 11,
+                    new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16),
+                    new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m304w1,
+                    c2m304w1.DecodePoint(
+                        Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2tnb359v1Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb359v1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb359v1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16);
+                BigInteger h = BigInteger.ValueOf(0x4C);
+
+                ECCurve c2m359v1 = new F2mCurve(
+                    359,
+                    68,
+                    new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16),
+                    new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m359v1,
+                    c2m359v1.DecodePoint(
+                        Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2pnb368w1Holder
+            : X9ECParametersHolder
+        {
+            private C2pnb368w1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2pnb368w1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16);
+                BigInteger h = BigInteger.ValueOf(0xFF70);
+
+                ECCurve c2m368w1 = new F2mCurve(
+                    368,
+                    1, 2, 85,
+                    new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16),
+                    new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m368w1,
+                    c2m368w1.DecodePoint(
+                        Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
+                    n, h,
+                    null);
+            }
+        }
+
+        internal class C2tnb431r1Holder
+            : X9ECParametersHolder
+        {
+            private C2tnb431r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new C2tnb431r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                BigInteger n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16);
+                BigInteger h = BigInteger.ValueOf(0x2760);
+
+                ECCurve c2m431r1 = new F2mCurve(
+                    431,
+                    120,
+                    new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16),
+                    new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16),
+                    n, h);
+
+                return new X9ECParameters(
+                    c2m431r1,
+                    c2m431r1.DecodePoint(
+                        Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
+                    n, h,
+                    null);
+            }
+        }
+
+        private static readonly IDictionary objIds = Platform.CreateHashtable();
         private static readonly IDictionary curves = Platform.CreateHashtable();
         private static readonly IDictionary names = Platform.CreateHashtable();
 
-		private static void DefineCurve(
-			string					name,
-			DerObjectIdentifier		oid,
-			X9ECParametersHolder	holder)
-		{
-			objIds.Add(name, oid);
-			names.Add(oid, name);
-			curves.Add(oid, holder);
-		}
-
-		static X962NamedCurves()
-		{
-			DefineCurve("prime192v1", X9ObjectIdentifiers.Prime192v1, Prime192v1Holder.Instance);
-			DefineCurve("prime192v2", X9ObjectIdentifiers.Prime192v2, Prime192v2Holder.Instance);
-			DefineCurve("prime192v3", X9ObjectIdentifiers.Prime192v3, Prime192v3Holder.Instance);
-			DefineCurve("prime239v1", X9ObjectIdentifiers.Prime239v1, Prime239v1Holder.Instance);
-			DefineCurve("prime239v2", X9ObjectIdentifiers.Prime239v2, Prime239v2Holder.Instance);
-			DefineCurve("prime239v3", X9ObjectIdentifiers.Prime239v3, Prime239v3Holder.Instance);
-			DefineCurve("prime256v1", X9ObjectIdentifiers.Prime256v1, Prime256v1Holder.Instance);
-			DefineCurve("c2pnb163v1", X9ObjectIdentifiers.C2Pnb163v1, C2pnb163v1Holder.Instance);
-			DefineCurve("c2pnb163v2", X9ObjectIdentifiers.C2Pnb163v2, C2pnb163v2Holder.Instance);
-			DefineCurve("c2pnb163v3", X9ObjectIdentifiers.C2Pnb163v3, C2pnb163v3Holder.Instance);
-			DefineCurve("c2pnb176w1", X9ObjectIdentifiers.C2Pnb176w1, C2pnb176w1Holder.Instance);
-			DefineCurve("c2tnb191v1", X9ObjectIdentifiers.C2Tnb191v1, C2tnb191v1Holder.Instance);
-			DefineCurve("c2tnb191v2", X9ObjectIdentifiers.C2Tnb191v2, C2tnb191v2Holder.Instance);
-			DefineCurve("c2tnb191v3", X9ObjectIdentifiers.C2Tnb191v3, C2tnb191v3Holder.Instance);
-			DefineCurve("c2pnb208w1", X9ObjectIdentifiers.C2Pnb208w1, C2pnb208w1Holder.Instance);
-			DefineCurve("c2tnb239v1", X9ObjectIdentifiers.C2Tnb239v1, C2tnb239v1Holder.Instance);
-			DefineCurve("c2tnb239v2", X9ObjectIdentifiers.C2Tnb239v2, C2tnb239v2Holder.Instance);
-			DefineCurve("c2tnb239v3", X9ObjectIdentifiers.C2Tnb239v3, C2tnb239v3Holder.Instance);
-			DefineCurve("c2pnb272w1", X9ObjectIdentifiers.C2Pnb272w1, C2pnb272w1Holder.Instance);
-			DefineCurve("c2pnb304w1", X9ObjectIdentifiers.C2Pnb304w1, C2pnb304w1Holder.Instance);
-			DefineCurve("c2tnb359v1", X9ObjectIdentifiers.C2Tnb359v1, C2tnb359v1Holder.Instance);
-			DefineCurve("c2pnb368w1", X9ObjectIdentifiers.C2Pnb368w1, C2pnb368w1Holder.Instance);
-			DefineCurve("c2tnb431r1", X9ObjectIdentifiers.C2Tnb431r1, C2tnb431r1Holder.Instance);
-		}
-
-		public static X9ECParameters GetByName(
-			string name)
-		{
-			DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
-
-			return oid == null ? null : GetByOid(oid);
-		}
-
-		/**
-		 * 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(
-			DerObjectIdentifier oid)
-		{
-			X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
-
-			return holder == null ? null : holder.Parameters;
-		}
-
-		/**
-		 * 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 DerObjectIdentifier GetOid(
-			string name)
-		{
-			return (DerObjectIdentifier) objIds[name.ToLowerInvariant()];
-		}
-
-		/**
-		 * return the named curve name represented by the given object identifier.
-		 */
-		public static string GetName(
-			DerObjectIdentifier oid)
-		{
-			return (string) names[oid];
-		}
-
-		/**
-		 * returns an enumeration containing the name strings for curves
-		 * contained in this structure.
-		 */
-		public static IEnumerable Names
-		{
-			get { return new EnumerableProxy(objIds.Keys); }
-		}
-	}
+        private static void DefineCurve(
+            string					name,
+            DerObjectIdentifier		oid,
+            X9ECParametersHolder	holder)
+        {
+            objIds.Add(name, oid);
+            names.Add(oid, name);
+            curves.Add(oid, holder);
+        }
+
+        static X962NamedCurves()
+        {
+            DefineCurve("prime192v1", X9ObjectIdentifiers.Prime192v1, Prime192v1Holder.Instance);
+            DefineCurve("prime192v2", X9ObjectIdentifiers.Prime192v2, Prime192v2Holder.Instance);
+            DefineCurve("prime192v3", X9ObjectIdentifiers.Prime192v3, Prime192v3Holder.Instance);
+            DefineCurve("prime239v1", X9ObjectIdentifiers.Prime239v1, Prime239v1Holder.Instance);
+            DefineCurve("prime239v2", X9ObjectIdentifiers.Prime239v2, Prime239v2Holder.Instance);
+            DefineCurve("prime239v3", X9ObjectIdentifiers.Prime239v3, Prime239v3Holder.Instance);
+            DefineCurve("prime256v1", X9ObjectIdentifiers.Prime256v1, Prime256v1Holder.Instance);
+            DefineCurve("c2pnb163v1", X9ObjectIdentifiers.C2Pnb163v1, C2pnb163v1Holder.Instance);
+            DefineCurve("c2pnb163v2", X9ObjectIdentifiers.C2Pnb163v2, C2pnb163v2Holder.Instance);
+            DefineCurve("c2pnb163v3", X9ObjectIdentifiers.C2Pnb163v3, C2pnb163v3Holder.Instance);
+            DefineCurve("c2pnb176w1", X9ObjectIdentifiers.C2Pnb176w1, C2pnb176w1Holder.Instance);
+            DefineCurve("c2tnb191v1", X9ObjectIdentifiers.C2Tnb191v1, C2tnb191v1Holder.Instance);
+            DefineCurve("c2tnb191v2", X9ObjectIdentifiers.C2Tnb191v2, C2tnb191v2Holder.Instance);
+            DefineCurve("c2tnb191v3", X9ObjectIdentifiers.C2Tnb191v3, C2tnb191v3Holder.Instance);
+            DefineCurve("c2pnb208w1", X9ObjectIdentifiers.C2Pnb208w1, C2pnb208w1Holder.Instance);
+            DefineCurve("c2tnb239v1", X9ObjectIdentifiers.C2Tnb239v1, C2tnb239v1Holder.Instance);
+            DefineCurve("c2tnb239v2", X9ObjectIdentifiers.C2Tnb239v2, C2tnb239v2Holder.Instance);
+            DefineCurve("c2tnb239v3", X9ObjectIdentifiers.C2Tnb239v3, C2tnb239v3Holder.Instance);
+            DefineCurve("c2pnb272w1", X9ObjectIdentifiers.C2Pnb272w1, C2pnb272w1Holder.Instance);
+            DefineCurve("c2pnb304w1", X9ObjectIdentifiers.C2Pnb304w1, C2pnb304w1Holder.Instance);
+            DefineCurve("c2tnb359v1", X9ObjectIdentifiers.C2Tnb359v1, C2tnb359v1Holder.Instance);
+            DefineCurve("c2pnb368w1", X9ObjectIdentifiers.C2Pnb368w1, C2pnb368w1Holder.Instance);
+            DefineCurve("c2tnb431r1", X9ObjectIdentifiers.C2Tnb431r1, C2tnb431r1Holder.Instance);
+        }
+
+        public static X9ECParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
+
+            return oid == null ? null : GetByOid(oid);
+        }
+
+        /**
+         * 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(
+            DerObjectIdentifier oid)
+        {
+            X9ECParametersHolder holder = (X9ECParametersHolder) curves[oid];
+
+            return holder == null ? null : holder.Parameters;
+        }
+
+        /**
+         * 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 DerObjectIdentifier GetOid(
+            string name)
+        {
+            return (DerObjectIdentifier)objIds[Platform.ToLowerInvariant(name)];
+        }
+
+        /**
+         * return the named curve name represented by the given object identifier.
+         */
+        public static string GetName(
+            DerObjectIdentifier oid)
+        {
+            return (string) names[oid];
+        }
+
+        /**
+         * returns an enumeration containing the name strings for curves
+         * contained in this structure.
+         */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(objIds.Keys); }
+        }
+    }
 }
diff --git a/crypto/src/asn1/x9/X962Parameters.cs b/crypto/src/asn1/x9/X962Parameters.cs
new file mode 100644
index 000000000..5b7eaa1de
--- /dev/null
+++ b/crypto/src/asn1/x9/X962Parameters.cs
@@ -0,0 +1,53 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    public class X962Parameters
+        : Asn1Encodable, IAsn1Choice
+    {
+        private readonly Asn1Object _params;
+
+		public X962Parameters(
+            X9ECParameters ecParameters)
+        {
+            this._params = ecParameters.ToAsn1Object();
+        }
+
+		public X962Parameters(
+            DerObjectIdentifier namedCurve)
+        {
+            this._params = namedCurve;
+        }
+
+		public X962Parameters(
+            Asn1Object obj)
+        {
+            this._params = obj;
+        }
+
+		public bool IsNamedCurve
+        {
+			get { return (_params is DerObjectIdentifier); }
+        }
+
+		public Asn1Object Parameters
+        {
+            get { return _params; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Parameters ::= CHOICE {
+         *    ecParameters ECParameters,
+         *    namedCurve   CURVES.&amp;id({CurveNames}),
+         *    implicitlyCA Null
+         * }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return _params;
+        }
+    }
+}
diff --git a/crypto/src/asn1/x9/X9Curve.cs b/crypto/src/asn1/x9/X9Curve.cs
index b92e7b3b5..f05a946c2 100644
--- a/crypto/src/asn1/x9/X9Curve.cs
+++ b/crypto/src/asn1/x9/X9Curve.cs
@@ -15,51 +15,50 @@ namespace Org.BouncyCastle.Asn1.X9
     {
         private readonly ECCurve curve;
         private readonly byte[] seed;
-		private readonly DerObjectIdentifier fieldIdentifier;
+        private readonly DerObjectIdentifier fieldIdentifier;
 
-		public X9Curve(
+        public X9Curve(
             ECCurve curve)
-			: this(curve, null)
+            : this(curve, null)
         {
-            this.curve = curve;
         }
 
-		public X9Curve(
+        public X9Curve(
             ECCurve	curve,
             byte[]	seed)
         {
-			if (curve == null)
-				throw new ArgumentNullException("curve");
+            if (curve == null)
+                throw new ArgumentNullException("curve");
 
-			this.curve = curve;
+            this.curve = curve;
             this.seed = Arrays.Clone(seed);
 
-			if (curve is FpCurve)
-			{
-				this.fieldIdentifier = X9ObjectIdentifiers.PrimeField;
-			}
-			else if (curve is F2mCurve)
-			{
-				this.fieldIdentifier = X9ObjectIdentifiers.CharacteristicTwoField;
-			}
-			else
-			{
-				throw new ArgumentException("This type of ECCurve is not implemented");
-			}
-		}
-
-		public X9Curve(
+            if (ECAlgorithms.IsFpCurve(curve))
+            {
+                this.fieldIdentifier = X9ObjectIdentifiers.PrimeField;
+            }
+            else if (ECAlgorithms.IsF2mCurve(curve))
+            {
+                this.fieldIdentifier = X9ObjectIdentifiers.CharacteristicTwoField;
+            }
+            else
+            {
+                throw new ArgumentException("This type of ECCurve is not implemented");
+            }
+        }
+
+        public X9Curve(
             X9FieldID		fieldID,
             Asn1Sequence	seq)
         {
-			if (fieldID == null)
-				throw new ArgumentNullException("fieldID");
-			if (seq == null)
-				throw new ArgumentNullException("seq");
+            if (fieldID == null)
+                throw new ArgumentNullException("fieldID");
+            if (seq == null)
+                throw new ArgumentNullException("seq");
 
-			this.fieldIdentifier = fieldID.Identifier;
+            this.fieldIdentifier = fieldID.Identifier;
 
-			if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
+            if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
             {
                 BigInteger q = ((DerInteger) fieldID.Parameters).Value;
                 X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]);
@@ -68,54 +67,54 @@ namespace Org.BouncyCastle.Asn1.X9
             }
             else
             {
-				if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
-				{
-					// Characteristic two field
-					DerSequence parameters = (DerSequence)fieldID.Parameters;
-					int m = ((DerInteger)parameters[0]).Value.IntValue;
-					DerObjectIdentifier representation
-						= (DerObjectIdentifier)parameters[1];
-
-					int k1 = 0;
-					int k2 = 0;
-					int k3 = 0;
-					if (representation.Equals(X9ObjectIdentifiers.TPBasis)) 
-					{
-						// Trinomial basis representation
-						k1 = ((DerInteger)parameters[2]).Value.IntValue;
-					}
-					else 
-					{
-						// Pentanomial basis representation
-						DerSequence pentanomial = (DerSequence) parameters[2];
-						k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
-						k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
-						k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
-					}
-					X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]);
-					X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]);
-					// TODO Is it possible to get the order (n) and cofactor(h) too?
-					curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
-				}
-			}
-
-			if (seq.Count == 3)
+                if (fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
+                {
+                    // Characteristic two field
+                    DerSequence parameters = (DerSequence)fieldID.Parameters;
+                    int m = ((DerInteger)parameters[0]).Value.IntValue;
+                    DerObjectIdentifier representation
+                        = (DerObjectIdentifier)parameters[1];
+
+                    int k1 = 0;
+                    int k2 = 0;
+                    int k3 = 0;
+                    if (representation.Equals(X9ObjectIdentifiers.TPBasis)) 
+                    {
+                        // Trinomial basis representation
+                        k1 = ((DerInteger)parameters[2]).Value.IntValue;
+                    }
+                    else 
+                    {
+                        // Pentanomial basis representation
+                        DerSequence pentanomial = (DerSequence) parameters[2];
+                        k1 = ((DerInteger) pentanomial[0]).Value.IntValue;
+                        k2 = ((DerInteger) pentanomial[1]).Value.IntValue;
+                        k3 = ((DerInteger) pentanomial[2]).Value.IntValue;
+                    }
+                    X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[0]);
+                    X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (Asn1OctetString)seq[1]);
+                    // TODO Is it possible to get the order (n) and cofactor(h) too?
+                    curve = new F2mCurve(m, k1, k2, k3, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+                }
+            }
+
+            if (seq.Count == 3)
             {
                 seed = ((DerBitString) seq[2]).GetBytes();
             }
         }
 
-		public ECCurve Curve
+        public ECCurve Curve
         {
-			get { return curve; }
+            get { return curve; }
         }
 
-		public byte[] GetSeed()
+        public byte[] GetSeed()
         {
             return Arrays.Clone(seed);
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  Curve ::= Sequence {
@@ -127,21 +126,21 @@ namespace Org.BouncyCastle.Asn1.X9
          */
         public override Asn1Object ToAsn1Object()
         {
-			Asn1EncodableVector v = new Asn1EncodableVector();
-
-			if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)
-				|| fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
-			{ 
-				v.Add(new X9FieldElement(curve.A).ToAsn1Object());
-				v.Add(new X9FieldElement(curve.B).ToAsn1Object());
-			} 
-
-			if (seed != null)
-			{
-				v.Add(new DerBitString(seed));
-			}
-
-			return new DerSequence(v);
-		}
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField)
+                || fieldIdentifier.Equals(X9ObjectIdentifiers.CharacteristicTwoField)) 
+            { 
+                v.Add(new X9FieldElement(curve.A).ToAsn1Object());
+                v.Add(new X9FieldElement(curve.B).ToAsn1Object());
+            } 
+
+            if (seed != null)
+            {
+                v.Add(new DerBitString(seed));
+            }
+
+            return new DerSequence(v);
+        }
     }
 }
diff --git a/crypto/src/asn1/x9/X9ECParameters.cs b/crypto/src/asn1/x9/X9ECParameters.cs
index d025b36ce..a192e4c52 100644
--- a/crypto/src/asn1/x9/X9ECParameters.cs
+++ b/crypto/src/asn1/x9/X9ECParameters.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.Field;
 
 namespace Org.BouncyCastle.Asn1.X9
 {
@@ -19,7 +20,7 @@ namespace Org.BouncyCastle.Asn1.X9
         private BigInteger	h;
         private byte[]		seed;
 
-		public X9ECParameters(
+        public X9ECParameters(
             Asn1Sequence seq)
         {
             if (!(seq[0] is DerInteger)
@@ -28,7 +29,7 @@ namespace Org.BouncyCastle.Asn1.X9
                 throw new ArgumentException("bad version in X9ECParameters");
             }
 
-			X9Curve x9c = null;
+            X9Curve x9c = null;
             if (seq[2] is X9Curve)
             {
                 x9c = (X9Curve) seq[2];
@@ -36,14 +37,14 @@ namespace Org.BouncyCastle.Asn1.X9
             else
             {
                 x9c = new X9Curve(
-					new X9FieldID(
-						(Asn1Sequence) seq[1]),
-						(Asn1Sequence) seq[2]);
+                    new X9FieldID(
+                        (Asn1Sequence) seq[1]),
+                        (Asn1Sequence) seq[2]);
             }
 
-			this.curve = x9c.Curve;
+            this.curve = x9c.Curve;
 
-			if (seq[3] is X9ECPoint)
+            if (seq[3] is X9ECPoint)
             {
                 this.g = ((X9ECPoint) seq[3]).Point;
             }
@@ -52,16 +53,16 @@ namespace Org.BouncyCastle.Asn1.X9
                 this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point;
             }
 
-			this.n = ((DerInteger) seq[4]).Value;
+            this.n = ((DerInteger) seq[4]).Value;
             this.seed = x9c.GetSeed();
 
-			if (seq.Count == 6)
+            if (seq.Count == 6)
             {
                 this.h = ((DerInteger) seq[5]).Value;
             }
         }
 
-		public X9ECParameters(
+        public X9ECParameters(
             ECCurve		curve,
             ECPoint		g,
             BigInteger	n)
@@ -69,7 +70,7 @@ namespace Org.BouncyCastle.Asn1.X9
         {
         }
 
-		public X9ECParameters(
+        public X9ECParameters(
             ECCurve		curve,
             ECPoint		g,
             BigInteger	n,
@@ -78,7 +79,7 @@ namespace Org.BouncyCastle.Asn1.X9
         {
         }
 
-		public X9ECParameters(
+        public X9ECParameters(
             ECCurve		curve,
             ECPoint		g,
             BigInteger	n,
@@ -86,58 +87,73 @@ namespace Org.BouncyCastle.Asn1.X9
             byte[]		seed)
         {
             this.curve = curve;
-            this.g = g;
+            this.g = g.Normalize();
             this.n = n;
             this.h = h;
             this.seed = seed;
 
-			if (curve is FpCurve)
-			{
-				this.fieldID = new X9FieldID(((FpCurve) curve).Q);
-			}
-			else if (curve is F2mCurve)
-			{
-				F2mCurve curveF2m = (F2mCurve) curve;
-				this.fieldID = new X9FieldID(curveF2m.M, curveF2m.K1,
-					curveF2m.K2, curveF2m.K3);
-			}
+            if (ECAlgorithms.IsFpCurve(curve))
+            {
+                this.fieldID = new X9FieldID(curve.Field.Characteristic);
+            }
+            else if (ECAlgorithms.IsF2mCurve(curve))
+            {
+                IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
+                int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
+                if (exponents.Length == 3)
+                {
+                    this.fieldID = new X9FieldID(exponents[2], exponents[1]);
+                }
+                else if (exponents.Length == 5)
+                {
+                    this.fieldID = new X9FieldID(exponents[4], exponents[1], exponents[2], exponents[3]);
+                }
+                else
+                {
+                    throw new ArgumentException("Only trinomial and pentomial curves are supported");
+                }
+            }
+            else
+            {
+                throw new ArgumentException("'curve' is of an unsupported type");
+            }
         }
 
-		public ECCurve Curve
+        public ECCurve Curve
         {
-			get { return curve; }
+            get { return curve; }
         }
 
-		public ECPoint G
+        public ECPoint G
         {
             get { return g; }
         }
 
-		public BigInteger N
+        public BigInteger N
         {
             get { return n; }
         }
 
-		public BigInteger H
+        public BigInteger H
         {
             get
-			{
-				if (h == null)
-				{
-					// TODO - this should be calculated, it will cause issues with custom curves.
-					return BigInteger.One;
-				}
-
-				return h;
-			}
+            {
+                if (h == null)
+                {
+                    // TODO - this should be calculated, it will cause issues with custom curves.
+                    return BigInteger.One;
+                }
+
+                return h;
+            }
         }
 
-		public byte[] GetSeed()
+        public byte[] GetSeed()
         {
             return seed;
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  ECParameters ::= Sequence {
@@ -153,18 +169,18 @@ namespace Org.BouncyCastle.Asn1.X9
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(
-				new DerInteger(1),
-				fieldID,
-				new X9Curve(curve, seed),
-				new X9ECPoint(g),
-				new DerInteger(n));
+                new DerInteger(1),
+                fieldID,
+                new X9Curve(curve, seed),
+                new X9ECPoint(g),
+                new DerInteger(n));
 
-			if (h != null)
+            if (h != null)
             {
                 v.Add(new DerInteger(h));
             }
 
-			return new DerSequence(v);
+            return new DerSequence(v);
         }
     }
 }
diff --git a/crypto/src/asn1/x9/X9ECParametersHolder.cs b/crypto/src/asn1/x9/X9ECParametersHolder.cs
new file mode 100644
index 000000000..b3455709c
--- /dev/null
+++ b/crypto/src/asn1/x9/X9ECParametersHolder.cs
@@ -0,0 +1,22 @@
+namespace Org.BouncyCastle.Asn1.X9
+{
+	public abstract class X9ECParametersHolder
+	{
+		private X9ECParameters parameters;
+
+		public X9ECParameters Parameters
+		{
+			get
+			{
+				if (parameters == null)
+				{
+					parameters = CreateParameters();
+				}
+
+				return parameters;
+			}
+		}
+
+		protected abstract X9ECParameters CreateParameters();
+	}
+}
diff --git a/crypto/src/asn1/x9/X9ECPoint.cs b/crypto/src/asn1/x9/X9ECPoint.cs
index ba2b2bcbf..75d58cd38 100644
--- a/crypto/src/asn1/x9/X9ECPoint.cs
+++ b/crypto/src/asn1/x9/X9ECPoint.cs
@@ -10,25 +10,25 @@ namespace Org.BouncyCastle.Asn1.X9
     {
         private readonly ECPoint p;
 
-		public X9ECPoint(
+        public X9ECPoint(
             ECPoint p)
         {
-            this.p = p;
+            this.p = p.Normalize();
         }
 
-		public X9ECPoint(
+        public X9ECPoint(
             ECCurve			c,
             Asn1OctetString	s)
         {
             this.p = c.DecodePoint(s.GetOctets());
         }
 
-		public ECPoint Point
+        public ECPoint Point
         {
-			get { return p; }
+            get { return p; }
         }
 
-		/**
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  ECPoint ::= OCTET STRING
diff --git a/crypto/src/asn1/x9/X9FieldElement.cs b/crypto/src/asn1/x9/X9FieldElement.cs
index 06fa0e3dc..94bd96b24 100644
--- a/crypto/src/asn1/x9/X9FieldElement.cs
+++ b/crypto/src/asn1/x9/X9FieldElement.cs
@@ -11,59 +11,59 @@ namespace Org.BouncyCastle.Asn1.X9
     public class X9FieldElement
         : Asn1Encodable
     {
-		private ECFieldElement f;
+        private ECFieldElement f;
 
-		public X9FieldElement(
-			ECFieldElement f)
-		{
-			this.f = f;
-		}
+        public X9FieldElement(
+            ECFieldElement f)
+        {
+            this.f = f;
+        }
 
-		public X9FieldElement(
-			BigInteger		p,
-			Asn1OctetString	s)
-			: this(new FpFieldElement(p, new BigInteger(1, s.GetOctets())))
-		{
-		}
+        public X9FieldElement(
+            BigInteger		p,
+            Asn1OctetString	s)
+            : this(new FpFieldElement(p, new BigInteger(1, s.GetOctets())))
+        {
+        }
 
-		public X9FieldElement(
-			int				m,
-			int				k1,
-			int				k2,
-			int				k3,
-			Asn1OctetString	s)
-			: this(new F2mFieldElement(m, k1, k2, k3, new BigInteger(1, s.GetOctets())))
-		{
-		}
+        public X9FieldElement(
+            int				m,
+            int				k1,
+            int				k2,
+            int				k3,
+            Asn1OctetString	s)
+            : this(new F2mFieldElement(m, k1, k2, k3, new BigInteger(1, s.GetOctets())))
+        {
+        }
 
-		public ECFieldElement Value
+        public ECFieldElement Value
         {
             get { 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>
-		 * </p>
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			int byteCount = X9IntegerConverter.GetByteLength(f);
-			byte[] paddedBigInteger = X9IntegerConverter.IntegerToBytes(f.ToBigInteger(), byteCount);
+        /**
+         * 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>
+         * </p>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            int byteCount = X9IntegerConverter.GetByteLength(f);
+            byte[] paddedBigInteger = X9IntegerConverter.IntegerToBytes(f.ToBigInteger(), byteCount);
 
-			return new DerOctetString(paddedBigInteger);
-		}
+            return new DerOctetString(paddedBigInteger);
+        }
     }
 }
diff --git a/crypto/src/asn1/x9/X9FieldID.cs b/crypto/src/asn1/x9/X9FieldID.cs
index c51cc4df2..58823a285 100644
--- a/crypto/src/asn1/x9/X9FieldID.cs
+++ b/crypto/src/asn1/x9/X9FieldID.cs
@@ -1,3 +1,5 @@
+using System;
+
 using Org.BouncyCastle.Math;
 
 namespace Org.BouncyCastle.Asn1.X9
@@ -12,80 +14,100 @@ namespace Org.BouncyCastle.Asn1.X9
         private readonly DerObjectIdentifier	id;
         private readonly Asn1Object 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 = X9ObjectIdentifiers.PrimeField;
-			this.parameters = new DerInteger(primeP);
-		}
+        /**
+         * 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 = X9ObjectIdentifiers.PrimeField;
+            this.parameters = new DerInteger(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 = X9ObjectIdentifiers.CharacteristicTwoField;
+        /**
+         * 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>k1</sup> + 1</code>
+         * represents the reduction polynomial <code>f(z)</code>.
+         */
+        public X9FieldID(int m, int k1)
+            : this(m, k1, 0, 0)
+        {
+        }
 
-			Asn1EncodableVector fieldIdParams = new Asn1EncodableVector(new DerInteger(m));
+        /**
+         * 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 = X9ObjectIdentifiers.CharacteristicTwoField;
+
+            Asn1EncodableVector fieldIdParams = new Asn1EncodableVector(new DerInteger(m));
 
-			if (k2 == 0)
-			{
-				fieldIdParams.Add(
-					X9ObjectIdentifiers.TPBasis,
-					new DerInteger(k1));
-			}
-			else
-			{
-				fieldIdParams.Add(
-					X9ObjectIdentifiers.PPBasis,
-					new DerSequence(
-						new DerInteger(k1),
-						new DerInteger(k2),
-						new DerInteger(k3)));
-			}
+            if (k2 == 0)
+            {
+                if (k3 != 0)
+                    throw new ArgumentException("inconsistent k values");
 
-			this.parameters = new DerSequence(fieldIdParams);
-		}
+                fieldIdParams.Add(
+                    X9ObjectIdentifiers.TPBasis,
+                    new DerInteger(k1));
+            }
+            else
+            {
+                if (k2 <= k1 || k3 <= k2)
+                    throw new ArgumentException("inconsistent k values");
 
-		internal X9FieldID(
-			Asn1Sequence seq)
-		{
-			this.id = (DerObjectIdentifier) seq[0];
-			this.parameters = (Asn1Object) seq[1];
-		}
+                fieldIdParams.Add(
+                    X9ObjectIdentifiers.PPBasis,
+                    new DerSequence(
+                        new DerInteger(k1),
+                        new DerInteger(k2),
+                        new DerInteger(k3)));
+            }
+
+            this.parameters = new DerSequence(fieldIdParams);
+        }
+
+        internal X9FieldID(
+            Asn1Sequence seq)
+        {
+            this.id = (DerObjectIdentifier) seq[0];
+            this.parameters = (Asn1Object) seq[1];
+        }
 
-		public DerObjectIdentifier Identifier
+        public DerObjectIdentifier Identifier
         {
             get { return id; }
         }
 
-		public Asn1Object Parameters
+        public Asn1Object Parameters
         {
             get { return parameters; }
         }
 
-		/**
+        /**
          * Produce a Der encoding of the following structure.
          * <pre>
          *  FieldID ::= Sequence {
@@ -96,7 +118,7 @@ namespace Org.BouncyCastle.Asn1.X9
          */
         public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(id, parameters);
+            return new DerSequence(id, parameters);
         }
     }
 }
diff --git a/crypto/src/asn1/x9/X9IntegerConverter.cs b/crypto/src/asn1/x9/X9IntegerConverter.cs
index 2bce20488..e8f457114 100644
--- a/crypto/src/asn1/x9/X9IntegerConverter.cs
+++ b/crypto/src/asn1/x9/X9IntegerConverter.cs
@@ -5,44 +5,36 @@ using Org.BouncyCastle.Math.EC;
 
 namespace Org.BouncyCastle.Asn1.X9
 {
-    public sealed class X9IntegerConverter
+    public abstract class X9IntegerConverter
     {
-		private X9IntegerConverter()
-		{
-		}
-
-		public static int GetByteLength(
-            ECFieldElement fe)
+        public static int GetByteLength(ECFieldElement fe)
         {
-			return (fe.FieldSize + 7) / 8;
+            return (fe.FieldSize + 7) / 8;
         }
 
-		public static int GetByteLength(
-			ECCurve c)
-		{
-			return (c.FieldSize + 7) / 8;
-		}
+        public static int GetByteLength(ECCurve c)
+        {
+            return (c.FieldSize + 7) / 8;
+        }
 
-		public static byte[] IntegerToBytes(
-			BigInteger	s,
-			int			qLength)
-		{
-			byte[] bytes = s.ToByteArrayUnsigned();
+        public static byte[] IntegerToBytes(BigInteger s, int qLength)
+        {
+            byte[] bytes = s.ToByteArrayUnsigned();
 
-			if (qLength < bytes.Length)
-			{
-				byte[] tmp = new byte[qLength];
-				Array.Copy(bytes, bytes.Length - tmp.Length, tmp, 0, tmp.Length);
-				return tmp;
-			}
-			else if (qLength > bytes.Length)
-			{
-				byte[] tmp = new byte[qLength];
-				Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length);
-				return tmp;
-			}
+            if (qLength < bytes.Length)
+            {
+                byte[] tmp = new byte[qLength];
+                Array.Copy(bytes, bytes.Length - tmp.Length, tmp, 0, tmp.Length);
+                return tmp;
+            }
+            else if (qLength > bytes.Length)
+            {
+                byte[] tmp = new byte[qLength];
+                Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length);
+                return tmp;
+            }
 
-			return bytes;
-		}
+            return bytes;
+        }
     }
 }
diff --git a/crypto/src/asn1/x9/X9ObjectIdentifiers.cs b/crypto/src/asn1/x9/X9ObjectIdentifiers.cs
index 5b2fdbd2d..9d7ecae6e 100644
--- a/crypto/src/asn1/x9/X9ObjectIdentifiers.cs
+++ b/crypto/src/asn1/x9/X9ObjectIdentifiers.cs
@@ -1,3 +1,5 @@
+using System;
+
 namespace Org.BouncyCastle.Asn1.X9
 {
     public abstract class X9ObjectIdentifiers
@@ -8,128 +10,128 @@ namespace Org.BouncyCastle.Asn1.X9
         // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
         //            us(840) ansi-x962(10045) }
         //
+
         internal const string AnsiX962 = "1.2.840.10045";
-        internal const string IdFieldType = AnsiX962 + ".1";
 
-		public static readonly DerObjectIdentifier PrimeField
-                        = new DerObjectIdentifier(IdFieldType + ".1");
+        public static readonly DerObjectIdentifier ansi_X9_62 = new DerObjectIdentifier(AnsiX962);
 
-		public static readonly DerObjectIdentifier CharacteristicTwoField
-                        = new DerObjectIdentifier(IdFieldType + ".2");
+        public static readonly DerObjectIdentifier IdFieldType = ansi_X9_62.Branch("1");
 
-		public static readonly DerObjectIdentifier GNBasis
-                        = new DerObjectIdentifier(IdFieldType + ".2.3.1");
+        public static readonly DerObjectIdentifier PrimeField = IdFieldType.Branch("1");
+        public static readonly DerObjectIdentifier CharacteristicTwoField = IdFieldType.Branch("2");
 
-		public static readonly DerObjectIdentifier TPBasis
-                        = new DerObjectIdentifier(IdFieldType + ".2.3.2");
+        public static readonly DerObjectIdentifier GNBasis = CharacteristicTwoField.Branch("3.1");
+        public static readonly DerObjectIdentifier TPBasis = CharacteristicTwoField.Branch("3.2");
+        public static readonly DerObjectIdentifier PPBasis = CharacteristicTwoField.Branch("3.3");
 
-		public static readonly DerObjectIdentifier PPBasis
-                        = new DerObjectIdentifier(IdFieldType + ".2.3.3");
+        [Obsolete("Use 'id_ecSigType' instead")]
+        public const string IdECSigType = AnsiX962 + ".4";
+        public static readonly DerObjectIdentifier id_ecSigType = ansi_X9_62.Branch("4");
 
-		public const string IdECSigType = AnsiX962 + ".4";
+        public static readonly DerObjectIdentifier ECDsaWithSha1 = id_ecSigType.Branch("1");
 
-		public static readonly DerObjectIdentifier ECDsaWithSha1
-                        = new DerObjectIdentifier(IdECSigType + ".1");
+        [Obsolete("Use 'id_publicKeyType' instead")]
+        public const string IdPublicKeyType = AnsiX962 + ".2";
+        public static readonly DerObjectIdentifier id_publicKeyType = ansi_X9_62.Branch("2");
 
-		public const string IdPublicKeyType = AnsiX962 + ".2";
+        public static readonly DerObjectIdentifier IdECPublicKey = id_publicKeyType.Branch("1");
 
-		public static readonly DerObjectIdentifier IdECPublicKey
-                        = new DerObjectIdentifier(IdPublicKeyType + ".1");
+        public static readonly DerObjectIdentifier ECDsaWithSha2 = id_ecSigType.Branch("3");
 
-		public static readonly DerObjectIdentifier ECDsaWithSha2 = new DerObjectIdentifier(IdECSigType + ".3");
-		public static readonly DerObjectIdentifier ECDsaWithSha224 = new DerObjectIdentifier(ECDsaWithSha2 + ".1");
-		public static readonly DerObjectIdentifier ECDsaWithSha256 = new DerObjectIdentifier(ECDsaWithSha2 + ".2");
-		public static readonly DerObjectIdentifier ECDsaWithSha384 = new DerObjectIdentifier(ECDsaWithSha2 + ".3");
-		public static readonly DerObjectIdentifier ECDsaWithSha512 = new DerObjectIdentifier(ECDsaWithSha2 + ".4");
+        public static readonly DerObjectIdentifier ECDsaWithSha224 = ECDsaWithSha2.Branch("1");
+        public static readonly DerObjectIdentifier ECDsaWithSha256 = ECDsaWithSha2.Branch("2");
+        public static readonly DerObjectIdentifier ECDsaWithSha384 = ECDsaWithSha2.Branch("3");
+        public static readonly DerObjectIdentifier ECDsaWithSha512 = ECDsaWithSha2.Branch("4");
 
 
-		//
+        //
         // named curves
         //
-        public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(AnsiX962 + ".3");
+        public static readonly DerObjectIdentifier EllipticCurve = ansi_X9_62.Branch("3");
 
-		//
+        //
         // Two Curves
         //
-        public static readonly DerObjectIdentifier CTwoCurve = new DerObjectIdentifier(EllipticCurve + ".0");
-
-		public static readonly DerObjectIdentifier C2Pnb163v1 = new DerObjectIdentifier(CTwoCurve + ".1");
-        public static readonly DerObjectIdentifier C2Pnb163v2 = new DerObjectIdentifier(CTwoCurve + ".2");
-        public static readonly DerObjectIdentifier C2Pnb163v3 = new DerObjectIdentifier(CTwoCurve + ".3");
-        public static readonly DerObjectIdentifier C2Pnb176w1 = new DerObjectIdentifier(CTwoCurve + ".4");
-        public static readonly DerObjectIdentifier C2Tnb191v1 = new DerObjectIdentifier(CTwoCurve + ".5");
-        public static readonly DerObjectIdentifier C2Tnb191v2 = new DerObjectIdentifier(CTwoCurve + ".6");
-        public static readonly DerObjectIdentifier C2Tnb191v3 = new DerObjectIdentifier(CTwoCurve + ".7");
-        public static readonly DerObjectIdentifier C2Onb191v4 = new DerObjectIdentifier(CTwoCurve + ".8");
-        public static readonly DerObjectIdentifier C2Onb191v5 = new DerObjectIdentifier(CTwoCurve + ".9");
-        public static readonly DerObjectIdentifier C2Pnb208w1 = new DerObjectIdentifier(CTwoCurve + ".10");
-        public static readonly DerObjectIdentifier C2Tnb239v1 = new DerObjectIdentifier(CTwoCurve + ".11");
-        public static readonly DerObjectIdentifier C2Tnb239v2 = new DerObjectIdentifier(CTwoCurve + ".12");
-        public static readonly DerObjectIdentifier C2Tnb239v3 = new DerObjectIdentifier(CTwoCurve + ".13");
-        public static readonly DerObjectIdentifier C2Onb239v4 = new DerObjectIdentifier(CTwoCurve + ".14");
-        public static readonly DerObjectIdentifier C2Onb239v5 = new DerObjectIdentifier(CTwoCurve + ".15");
-        public static readonly DerObjectIdentifier C2Pnb272w1 = new DerObjectIdentifier(CTwoCurve + ".16");
-		public static readonly DerObjectIdentifier C2Pnb304w1 = new DerObjectIdentifier(CTwoCurve + ".17");
-		public static readonly DerObjectIdentifier C2Tnb359v1 = new DerObjectIdentifier(CTwoCurve + ".18");
-        public static readonly DerObjectIdentifier C2Pnb368w1 = new DerObjectIdentifier(CTwoCurve + ".19");
-        public static readonly DerObjectIdentifier C2Tnb431r1 = new DerObjectIdentifier(CTwoCurve + ".20");
-
-		//
+        public static readonly DerObjectIdentifier CTwoCurve = EllipticCurve.Branch("0");
+
+        public static readonly DerObjectIdentifier C2Pnb163v1 = CTwoCurve.Branch("1");
+        public static readonly DerObjectIdentifier C2Pnb163v2 = CTwoCurve.Branch("2");
+        public static readonly DerObjectIdentifier C2Pnb163v3 = CTwoCurve.Branch("3");
+        public static readonly DerObjectIdentifier C2Pnb176w1 = CTwoCurve.Branch("4");
+        public static readonly DerObjectIdentifier C2Tnb191v1 = CTwoCurve.Branch("5");
+        public static readonly DerObjectIdentifier C2Tnb191v2 = CTwoCurve.Branch("6");
+        public static readonly DerObjectIdentifier C2Tnb191v3 = CTwoCurve.Branch("7");
+        public static readonly DerObjectIdentifier C2Onb191v4 = CTwoCurve.Branch("8");
+        public static readonly DerObjectIdentifier C2Onb191v5 = CTwoCurve.Branch("9");
+        public static readonly DerObjectIdentifier C2Pnb208w1 = CTwoCurve.Branch("10");
+        public static readonly DerObjectIdentifier C2Tnb239v1 = CTwoCurve.Branch("11");
+        public static readonly DerObjectIdentifier C2Tnb239v2 = CTwoCurve.Branch("12");
+        public static readonly DerObjectIdentifier C2Tnb239v3 = CTwoCurve.Branch("13");
+        public static readonly DerObjectIdentifier C2Onb239v4 = CTwoCurve.Branch("14");
+        public static readonly DerObjectIdentifier C2Onb239v5 = CTwoCurve.Branch("15");
+        public static readonly DerObjectIdentifier C2Pnb272w1 = CTwoCurve.Branch("16");
+        public static readonly DerObjectIdentifier C2Pnb304w1 = CTwoCurve.Branch("17");
+        public static readonly DerObjectIdentifier C2Tnb359v1 = CTwoCurve.Branch("18");
+        public static readonly DerObjectIdentifier C2Pnb368w1 = CTwoCurve.Branch("19");
+        public static readonly DerObjectIdentifier C2Tnb431r1 = CTwoCurve.Branch("20");
+
+        //
         // Prime
         //
-        public static readonly DerObjectIdentifier PrimeCurve = new DerObjectIdentifier(EllipticCurve + ".1");
+        public static readonly DerObjectIdentifier PrimeCurve = EllipticCurve.Branch("1");
 
-		public static readonly DerObjectIdentifier Prime192v1 = new DerObjectIdentifier(PrimeCurve + ".1");
-        public static readonly DerObjectIdentifier Prime192v2 = new DerObjectIdentifier(PrimeCurve + ".2");
-        public static readonly DerObjectIdentifier Prime192v3 = new DerObjectIdentifier(PrimeCurve + ".3");
-        public static readonly DerObjectIdentifier Prime239v1 = new DerObjectIdentifier(PrimeCurve + ".4");
-        public static readonly DerObjectIdentifier Prime239v2 = new DerObjectIdentifier(PrimeCurve + ".5");
-        public static readonly DerObjectIdentifier Prime239v3 = new DerObjectIdentifier(PrimeCurve + ".6");
-        public static readonly DerObjectIdentifier Prime256v1 = new DerObjectIdentifier(PrimeCurve + ".7");
+        public static readonly DerObjectIdentifier Prime192v1 = PrimeCurve.Branch("1");
+        public static readonly DerObjectIdentifier Prime192v2 = PrimeCurve.Branch("2");
+        public static readonly DerObjectIdentifier Prime192v3 = PrimeCurve.Branch("3");
+        public static readonly DerObjectIdentifier Prime239v1 = PrimeCurve.Branch("4");
+        public static readonly DerObjectIdentifier Prime239v2 = PrimeCurve.Branch("5");
+        public static readonly DerObjectIdentifier Prime239v3 = PrimeCurve.Branch("6");
+        public static readonly DerObjectIdentifier Prime256v1 = PrimeCurve.Branch("7");
 
-		//
+        //
         // DSA
         //
         // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
         //            us(840) ansi-x957(10040) number-type(4) 1 }
         public static readonly DerObjectIdentifier IdDsa = new DerObjectIdentifier("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 readonly DerObjectIdentifier IdDsaWithSha1 = new DerObjectIdentifier("1.2.840.10040.4.3");
 
-		/**
-		 * X9.63
-		 */
-		public static readonly DerObjectIdentifier X9x63Scheme = new DerObjectIdentifier("1.3.133.16.840.63.0");
-		public static readonly DerObjectIdentifier DHSinglePassStdDHSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".2");
-		public static readonly DerObjectIdentifier DHSinglePassCofactorDHSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".3");
-		public static readonly DerObjectIdentifier MqvSinglePassSha1KdfScheme = new DerObjectIdentifier(X9x63Scheme + ".16");
+        /**
+         * X9.63
+         */
+        public static readonly DerObjectIdentifier X9x63Scheme = new DerObjectIdentifier("1.3.133.16.840.63.0");
+        public static readonly DerObjectIdentifier DHSinglePassStdDHSha1KdfScheme = X9x63Scheme.Branch("2");
+        public static readonly DerObjectIdentifier DHSinglePassCofactorDHSha1KdfScheme = X9x63Scheme.Branch("3");
+        public static readonly DerObjectIdentifier MqvSinglePassSha1KdfScheme = X9x63Scheme.Branch("16");
 
-		/**
-		 * X9.42
-		 */
+        /**
+         * X9.42
+         */
 
-		internal const string AnsiX942 = "1.2.840.10046";
+        public static readonly DerObjectIdentifier ansi_x9_42 = new DerObjectIdentifier("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 readonly DerObjectIdentifier DHPublicNumber = new DerObjectIdentifier(AnsiX942 + ".2.1");
-
-		public static readonly DerObjectIdentifier X9x42Schemes = new DerObjectIdentifier(AnsiX942 + ".3");
-		public static readonly DerObjectIdentifier DHStatic = new DerObjectIdentifier(X9x42Schemes + ".1");
-		public static readonly DerObjectIdentifier DHEphem = new DerObjectIdentifier(X9x42Schemes + ".2");
-		public static readonly DerObjectIdentifier DHOneFlow = new DerObjectIdentifier(X9x42Schemes + ".3");
-		public static readonly DerObjectIdentifier DHHybrid1 = new DerObjectIdentifier(X9x42Schemes + ".4");
-		public static readonly DerObjectIdentifier DHHybrid2 = new DerObjectIdentifier(X9x42Schemes + ".5");
-		public static readonly DerObjectIdentifier DHHybridOneFlow = new DerObjectIdentifier(X9x42Schemes + ".6");
-		public static readonly DerObjectIdentifier Mqv2 = new DerObjectIdentifier(X9x42Schemes + ".7");
-		public static readonly DerObjectIdentifier Mqv1 = new DerObjectIdentifier(X9x42Schemes + ".8");
-	}
+        public static readonly DerObjectIdentifier DHPublicNumber = ansi_x9_42.Branch("2.1");
+
+        public static readonly DerObjectIdentifier X9x42Schemes = ansi_x9_42.Branch("2.3");
+
+        public static readonly DerObjectIdentifier DHStatic = X9x42Schemes.Branch("1");
+        public static readonly DerObjectIdentifier DHEphem = X9x42Schemes.Branch("2");
+        public static readonly DerObjectIdentifier DHOneFlow = X9x42Schemes.Branch("3");
+        public static readonly DerObjectIdentifier DHHybrid1 = X9x42Schemes.Branch("4");
+        public static readonly DerObjectIdentifier DHHybrid2 = X9x42Schemes.Branch("5");
+        public static readonly DerObjectIdentifier DHHybridOneFlow = X9x42Schemes.Branch("6");
+        public static readonly DerObjectIdentifier Mqv2 = X9x42Schemes.Branch("7");
+        public static readonly DerObjectIdentifier Mqv1 = X9x42Schemes.Branch("8");
+    }
 }
diff --git a/crypto/src/bcpg/ArmoredInputStream.cs b/crypto/src/bcpg/ArmoredInputStream.cs
index 0dcc948d3..3109dd4fd 100644
--- a/crypto/src/bcpg/ArmoredInputStream.cs
+++ b/crypto/src/bcpg/ArmoredInputStream.cs
@@ -504,14 +504,10 @@ namespace Org.BouncyCastle.Bcpg
             return pos - offset;
         }
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                input.Dispose();
-            }
-
-            base.Dispose(disposing);
-        }
+		public override void Close()
+		{
+			input.Close();
+			base.Close();
+		}
     }
 }
diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs
index 7ee26886a..b3a32c6f5 100644
--- a/crypto/src/bcpg/ArmoredOutputStream.cs
+++ b/crypto/src/bcpg/ArmoredOutputStream.cs
@@ -97,7 +97,8 @@ namespace Org.BouncyCastle.Bcpg
         private static readonly string	footerStart = "-----END PGP ";
         private static readonly string	footerTail = "-----";
 
-        private static readonly string version = "BCPG C# v" + AssemblyInfo.Version;
+        private static readonly string version = "BCPG C# v"
+			+ Assembly.GetExecutingAssembly().GetName().Version;
 
 		private readonly IDictionary headers;
 
@@ -276,43 +277,39 @@ namespace Org.BouncyCastle.Bcpg
         }
 
         /**
-         * <b>Note</b>: Dispose does nor Dispose the underlying stream. So it is possible to write
+         * <b>Note</b>: close does nor close the underlying stream. So it is possible to write
          * multiple objects using armoring to a single stream.
          */
-        protected override void Dispose(bool disposing)
+        public override void Close()
         {
-            if (disposing)
+            if (type != null)
             {
-                if (type != null)
-                {
-                    if (bufPtr > 0)
-                    {
-                        Encode(outStream, buf, bufPtr);
-                    }
+				if (bufPtr > 0)
+				{
+					Encode(outStream, buf, bufPtr);
+				}
 
-                    DoWrite(nl + '=');
+                DoWrite(nl + '=');
 
-                    int crcV = crc.Value;
+                int crcV = crc.Value;
 
-                    buf[0] = ((crcV >> 16) & 0xff);
-                    buf[1] = ((crcV >> 8) & 0xff);
-                    buf[2] = (crcV & 0xff);
+				buf[0] = ((crcV >> 16) & 0xff);
+                buf[1] = ((crcV >> 8) & 0xff);
+                buf[2] = (crcV & 0xff);
 
-                    Encode(outStream, buf, 3);
+                Encode(outStream, buf, 3);
 
-                    DoWrite(nl);
-                    DoWrite(footerStart);
-                    DoWrite(type);
-                    DoWrite(footerTail);
-                    DoWrite(nl);
-
-                    outStream.Flush();
+                DoWrite(nl);
+                DoWrite(footerStart);
+                DoWrite(type);
+                DoWrite(footerTail);
+                DoWrite(nl);
 
-                    type = null;
-                    start = true;
-                }
+                outStream.Flush();
 
-                base.Dispose(disposing);
+                type = null;
+                start = true;
+				base.Close();
 			}
         }
 
diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs
index b4afab901..3c69fbdf5 100644
--- a/crypto/src/bcpg/BcpgInputStream.cs
+++ b/crypto/src/bcpg/BcpgInputStream.cs
@@ -250,15 +250,11 @@ namespace Org.BouncyCastle.Bcpg
             }
         }
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                m_in.Dispose();
-            }
-
-            base.Dispose(disposing);
-        }
+		public override void Close()
+		{
+			m_in.Close();
+			base.Close();
+		}
 
 		/// <summary>
 		/// A stream that overlays our input stream, allowing the user to only read a segment of it.
diff --git a/crypto/src/bcpg/BcpgObject.cs b/crypto/src/bcpg/BcpgObject.cs
index 92811c3d3..4807ad46e 100644
--- a/crypto/src/bcpg/BcpgObject.cs
+++ b/crypto/src/bcpg/BcpgObject.cs
@@ -3,7 +3,7 @@ using System.IO;
 
 namespace Org.BouncyCastle.Bcpg
 {
-	/// <remarks>Base class for a PGP object.</remarks>
+    /// <remarks>Base class for a PGP object.</remarks>
     public abstract class BcpgObject
     {
         public virtual byte[] GetEncoded()
@@ -11,12 +11,12 @@ namespace Org.BouncyCastle.Bcpg
             MemoryStream bOut = new MemoryStream();
             BcpgOutputStream pOut = new BcpgOutputStream(bOut);
 
-			pOut.WriteObject(this);
+            pOut.WriteObject(this);
 
-			return bOut.ToArray();
+            return bOut.ToArray();
         }
 
-		public abstract void Encode(BcpgOutputStream bcpgOut);
+        public abstract void Encode(BcpgOutputStream bcpgOut);
     }
 }
 
diff --git a/crypto/src/bcpg/BcpgOutputStream.cs b/crypto/src/bcpg/BcpgOutputStream.cs
index 365053e11..204f65b50 100644
--- a/crypto/src/bcpg/BcpgOutputStream.cs
+++ b/crypto/src/bcpg/BcpgOutputStream.cs
@@ -379,16 +379,12 @@ namespace Org.BouncyCastle.Bcpg
             }
         }
 
-        protected override void Dispose(bool disposing)
+		public override void Close()
         {
-            if (disposing)
-            {
-                this.Finish();
-                outStr.Flush();
-                outStr.Dispose();
-            }
-
-            base.Dispose(disposing);
+			this.Finish();
+			outStr.Flush();
+			outStr.Close();
+			base.Close();
         }
     }
 }
diff --git a/crypto/src/bcpg/CompressedDataPacket.cs b/crypto/src/bcpg/CompressedDataPacket.cs
new file mode 100644
index 000000000..2432825eb
--- /dev/null
+++ b/crypto/src/bcpg/CompressedDataPacket.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Generic compressed data object.</remarks>
+    public class CompressedDataPacket
+        : InputStreamPacket
+    {
+        private readonly CompressionAlgorithmTag algorithm;
+
+		internal CompressedDataPacket(
+            BcpgInputStream bcpgIn)
+			: base(bcpgIn)
+        {
+            this.algorithm = (CompressionAlgorithmTag) bcpgIn.ReadByte();
+        }
+
+		/// <summary>The algorithm tag value.</summary>
+        public CompressionAlgorithmTag Algorithm
+		{
+			get { return algorithm; }
+		}
+    }
+}
diff --git a/crypto/src/bcpg/CompressionAlgorithmTags.cs b/crypto/src/bcpg/CompressionAlgorithmTags.cs
new file mode 100644
index 000000000..0e452298e
--- /dev/null
+++ b/crypto/src/bcpg/CompressionAlgorithmTags.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic tags for compression algorithms.</remarks>
+	public enum CompressionAlgorithmTag
+	{
+		Uncompressed = 0,	// Uncompressed
+		Zip = 1,			// ZIP (RFC 1951)
+		ZLib = 2,			// ZLIB (RFC 1950)
+		BZip2 = 3,			// BZ2
+	}
+}
diff --git a/crypto/src/bcpg/ContainedPacket.cs b/crypto/src/bcpg/ContainedPacket.cs
new file mode 100644
index 000000000..e8f387ca4
--- /dev/null
+++ b/crypto/src/bcpg/ContainedPacket.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic type for a PGP packet.</remarks>
+    public abstract class ContainedPacket
+        : Packet
+    {
+        public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+			pOut.WritePacket(this);
+
+			return bOut.ToArray();
+        }
+
+		public abstract void Encode(BcpgOutputStream bcpgOut);
+    }
+}
diff --git a/crypto/src/bcpg/Crc24.cs b/crypto/src/bcpg/Crc24.cs
new file mode 100644
index 000000000..97846f4fb
--- /dev/null
+++ b/crypto/src/bcpg/Crc24.cs
@@ -0,0 +1,46 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    public class Crc24
+    {
+        private const int Crc24Init = 0x0b704ce;
+        private const int Crc24Poly = 0x1864cfb;
+
+        private int crc = Crc24Init;
+
+        public Crc24()
+        {
+        }
+
+        public void Update(
+            int b)
+        {
+            crc ^= b << 16;
+            for (int i = 0; i < 8; i++)
+            {
+                crc <<= 1;
+                if ((crc & 0x1000000) != 0)
+                {
+                    crc ^= Crc24Poly;
+                }
+            }
+        }
+
+		[Obsolete("Use 'Value' property instead")]
+        public int GetValue()
+        {
+            return crc;
+        }
+
+		public int Value
+		{
+			get { return crc; }
+		}
+
+		public void Reset()
+        {
+            crc = Crc24Init;
+        }
+    }
+}
diff --git a/crypto/src/bcpg/DsaPublicBcpgKey.cs b/crypto/src/bcpg/DsaPublicBcpgKey.cs
index 61159567c..11294cc22 100644
--- a/crypto/src/bcpg/DsaPublicBcpgKey.cs
+++ b/crypto/src/bcpg/DsaPublicBcpgKey.cs
@@ -4,46 +4,46 @@ using Org.BouncyCastle.Math;
 
 namespace Org.BouncyCastle.Bcpg
 {
-	/// <remarks>Base class for a DSA public key.</remarks>
-	public class DsaPublicBcpgKey
-		: BcpgObject, IBcpgKey
+    /// <remarks>Base class for a DSA public key.</remarks>
+    public class DsaPublicBcpgKey
+        : BcpgObject, IBcpgKey
     {
         private readonly MPInteger p, q, g, y;
 
-		/// <param name="bcpgIn">The stream to read the packet from.</param>
-		public DsaPublicBcpgKey(
-			BcpgInputStream bcpgIn)
-		{
-			this.p = new MPInteger(bcpgIn);
-			this.q = new MPInteger(bcpgIn);
-			this.g = new MPInteger(bcpgIn);
-			this.y = new MPInteger(bcpgIn);
-		}
+        /// <param name="bcpgIn">The stream to read the packet from.</param>
+        public DsaPublicBcpgKey(
+            BcpgInputStream bcpgIn)
+        {
+            this.p = new MPInteger(bcpgIn);
+            this.q = new MPInteger(bcpgIn);
+            this.g = new MPInteger(bcpgIn);
+            this.y = new MPInteger(bcpgIn);
+        }
 
-		public DsaPublicBcpgKey(
-			BigInteger	p,
-			BigInteger	q,
-			BigInteger	g,
-			BigInteger	y)
-		{
-			this.p = new MPInteger(p);
-			this.q = new MPInteger(q);
-			this.g = new MPInteger(g);
-			this.y = new MPInteger(y);
-		}
+        public DsaPublicBcpgKey(
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	g,
+            BigInteger	y)
+        {
+            this.p = new MPInteger(p);
+            this.q = new MPInteger(q);
+            this.g = new MPInteger(g);
+            this.y = new MPInteger(y);
+        }
 
-		/// <summary>The format, as a string, always "PGP".</summary>
-		public string Format
-		{
-			get { return "PGP"; }
-		}
+        /// <summary>The format, as a string, always "PGP".</summary>
+        public string Format
+        {
+            get { return "PGP"; }
+        }
 
-		/// <summary>Return the standard PGP encoding of the key.</summary>
+        /// <summary>Return the standard PGP encoding of the key.</summary>
         public override byte[] GetEncoded()
         {
             try
             {
-            	return base.GetEncoded();
+                return base.GetEncoded();
             }
             catch (Exception)
             {
@@ -51,30 +51,30 @@ namespace Org.BouncyCastle.Bcpg
             }
         }
 
-		public override void Encode(
-			BcpgOutputStream bcpgOut)
-		{
-			bcpgOut.WriteObjects(p, q, g, y);
-		}
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WriteObjects(p, q, g, y);
+        }
 
-		public BigInteger G
-		{
-			get { return g.Value; }
-		}
+        public BigInteger G
+        {
+            get { return g.Value; }
+        }
 
-		public BigInteger P
-		{
-			get { return p.Value; }
-		}
+        public BigInteger P
+        {
+            get { return p.Value; }
+        }
 
-		public BigInteger Q
-		{
-			get { return q.Value; }
-		}
+        public BigInteger Q
+        {
+            get { return q.Value; }
+        }
 
-		public BigInteger Y
-		{
-			get { return y.Value; }
-		}
+        public BigInteger Y
+        {
+            get { return y.Value; }
+        }
     }
 }
diff --git a/crypto/src/bcpg/DsaSecretBcpgKey.cs b/crypto/src/bcpg/DsaSecretBcpgKey.cs
new file mode 100644
index 000000000..41835d419
--- /dev/null
+++ b/crypto/src/bcpg/DsaSecretBcpgKey.cs
@@ -0,0 +1,61 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base class for a DSA secret key.</remarks>
+	public class DsaSecretBcpgKey
+		: BcpgObject, IBcpgKey
+    {
+		internal MPInteger x;
+
+		/**
+		* @param in
+		*/
+		public DsaSecretBcpgKey(
+			BcpgInputStream bcpgIn)
+		{
+			this.x = new MPInteger(bcpgIn);
+		}
+
+		public DsaSecretBcpgKey(
+			BigInteger x)
+		{
+			this.x = new MPInteger(x);
+		}
+
+		/// <summary>The format, as a string, always "PGP".</summary>
+		public string Format
+		{
+			get { return "PGP"; }
+		}
+
+		/// <summary>Return the standard PGP encoding of the key.</summary>
+		public override byte[] GetEncoded()
+		{
+			try
+			{
+				return base.GetEncoded();
+			}
+			catch (Exception)
+			{
+				return null;
+			}
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+		{
+			bcpgOut.WriteObject(x);
+		}
+
+		/**
+		* @return x
+		*/
+		public BigInteger X
+		{
+			get { return x.Value; }
+		}
+	}
+}
diff --git a/crypto/src/bcpg/ElGamalPublicBcpgKey.cs b/crypto/src/bcpg/ElGamalPublicBcpgKey.cs
new file mode 100644
index 000000000..808e427b2
--- /dev/null
+++ b/crypto/src/bcpg/ElGamalPublicBcpgKey.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base class for an ElGamal public key.</remarks>
+	public class ElGamalPublicBcpgKey
+		: BcpgObject, IBcpgKey
+	{
+		internal MPInteger p, g, y;
+
+		public ElGamalPublicBcpgKey(
+			BcpgInputStream bcpgIn)
+		{
+			this.p = new MPInteger(bcpgIn);
+			this.g = new MPInteger(bcpgIn);
+			this.y = new MPInteger(bcpgIn);
+		}
+
+		public ElGamalPublicBcpgKey(
+			BigInteger p,
+			BigInteger g,
+			BigInteger y)
+		{
+			this.p = new MPInteger(p);
+			this.g = new MPInteger(g);
+			this.y = new MPInteger(y);
+		}
+
+		/// <summary>The format, as a string, always "PGP".</summary>
+		public string Format
+		{
+			get { return "PGP"; }
+		}
+
+		/// <summary>Return the standard PGP encoding of the key.</summary>
+		public override byte[] GetEncoded()
+		{
+			try
+			{
+				return base.GetEncoded();
+			}
+			catch (Exception)
+			{
+				return null;
+			}
+		}
+
+		public BigInteger P
+		{
+			get { return p.Value; }
+		}
+
+		public BigInteger G
+		{
+			get { return g.Value; }
+		}
+
+		public BigInteger Y
+		{
+			get { return y.Value; }
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+		{
+			bcpgOut.WriteObjects(p, g, y);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/ElGamalSecretBcpgKey.cs b/crypto/src/bcpg/ElGamalSecretBcpgKey.cs
new file mode 100644
index 000000000..2d95b29b1
--- /dev/null
+++ b/crypto/src/bcpg/ElGamalSecretBcpgKey.cs
@@ -0,0 +1,61 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base class for an ElGamal secret key.</remarks>
+	public class ElGamalSecretBcpgKey
+		: BcpgObject, IBcpgKey
+	{
+		internal MPInteger x;
+
+		/**
+		* @param in
+		*/
+		public ElGamalSecretBcpgKey(
+			BcpgInputStream bcpgIn)
+		{
+			this.x = new MPInteger(bcpgIn);
+		}
+
+		/**
+		* @param x
+		*/
+		public ElGamalSecretBcpgKey(
+			BigInteger x)
+		{
+			this.x = new MPInteger(x);
+		}
+
+		/// <summary>The format, as a string, always "PGP".</summary>
+		public string Format
+		{
+			get { return "PGP"; }
+		}
+
+		public BigInteger X
+		{
+			get { return x.Value; }
+		}
+
+		/// <summary>Return the standard PGP encoding of the key.</summary>
+		public override byte[] GetEncoded()
+		{
+			try
+			{
+				return base.GetEncoded();
+			}
+			catch (Exception)
+			{
+				return null;
+			}
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+		{
+			bcpgOut.WriteObject(x);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/ExperimentalPacket.cs b/crypto/src/bcpg/ExperimentalPacket.cs
new file mode 100644
index 000000000..36a254be1
--- /dev/null
+++ b/crypto/src/bcpg/ExperimentalPacket.cs
@@ -0,0 +1,38 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic packet for an experimental packet.</remarks>
+    public class ExperimentalPacket
+        : ContainedPacket //, PublicKeyAlgorithmTag
+    {
+        private readonly PacketTag	tag;
+        private readonly byte[]		contents;
+
+		internal ExperimentalPacket(
+            PacketTag		tag,
+            BcpgInputStream	bcpgIn)
+        {
+            this.tag = tag;
+
+			this.contents = bcpgIn.ReadAll();
+        }
+
+		public PacketTag Tag
+        {
+			get { return tag; }
+        }
+
+		public byte[] GetContents()
+        {
+			return (byte[]) contents.Clone();
+        }
+
+		public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(tag, contents, true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/HashAlgorithmTags.cs b/crypto/src/bcpg/HashAlgorithmTags.cs
new file mode 100644
index 000000000..96c009153
--- /dev/null
+++ b/crypto/src/bcpg/HashAlgorithmTags.cs
@@ -0,0 +1,19 @@
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic tags for hash algorithms.</remarks>
+	public enum HashAlgorithmTag
+	{
+		MD5 = 1,			// MD5
+		Sha1 = 2,			// SHA-1
+		RipeMD160 = 3,		// RIPE-MD/160
+		DoubleSha = 4,		// Reserved for double-width SHA (experimental)
+		MD2 = 5,			// MD2
+		Tiger192 = 6,		// Reserved for TIGER/192
+		Haval5pass160 = 7,	// Reserved for HAVAL (5 pass, 160-bit)
+
+		Sha256 = 8,			// SHA-256
+		Sha384 = 9,			// SHA-384
+		Sha512 = 10,		// SHA-512
+		Sha224 = 11,		// SHA-224
+	}
+}
diff --git a/crypto/src/bcpg/IBcpgKey.cs b/crypto/src/bcpg/IBcpgKey.cs
new file mode 100644
index 000000000..275461772
--- /dev/null
+++ b/crypto/src/bcpg/IBcpgKey.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base interface for a PGP key.</remarks>
+    public interface IBcpgKey
+    {
+		/// <summary>
+		/// The base format for this key - in the case of the symmetric keys it will generally
+		/// be raw indicating that the key is just a straight byte representation, for an asymmetric
+		/// key the format will be PGP, indicating the key is a string of MPIs encoded in PGP format.
+		/// </summary>
+		/// <returns>"RAW" or "PGP".</returns>
+        string Format { get; }
+    }
+}
diff --git a/crypto/src/bcpg/InputStreamPacket.cs b/crypto/src/bcpg/InputStreamPacket.cs
new file mode 100644
index 000000000..c45efab7b
--- /dev/null
+++ b/crypto/src/bcpg/InputStreamPacket.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Bcpg
+{
+    public class InputStreamPacket
+        : Packet
+    {
+        private readonly BcpgInputStream bcpgIn;
+
+		public InputStreamPacket(
+            BcpgInputStream bcpgIn)
+        {
+            this.bcpgIn = bcpgIn;
+        }
+
+		/// <summary>Note: you can only read from this once...</summary>
+		public BcpgInputStream GetInputStream()
+        {
+            return bcpgIn;
+        }
+    }
+}
diff --git a/crypto/src/bcpg/LiteralDataPacket.cs b/crypto/src/bcpg/LiteralDataPacket.cs
new file mode 100644
index 000000000..63a2c6d44
--- /dev/null
+++ b/crypto/src/bcpg/LiteralDataPacket.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Generic literal data packet.</remarks>
+    public class LiteralDataPacket
+        : InputStreamPacket
+	{
+		private int		format;
+        private byte[]	fileName;
+        private long	modDate;
+
+		internal LiteralDataPacket(
+            BcpgInputStream bcpgIn)
+			: base(bcpgIn)
+        {
+            format = bcpgIn.ReadByte();
+            int len = bcpgIn.ReadByte();
+
+			fileName = new byte[len];
+			for (int i = 0; i != len; ++i)
+            {
+                fileName[i] = (byte)bcpgIn.ReadByte();
+            }
+
+			modDate = (((uint)bcpgIn.ReadByte() << 24)
+				| ((uint)bcpgIn.ReadByte() << 16)
+                | ((uint)bcpgIn.ReadByte() << 8)
+				| (uint)bcpgIn.ReadByte()) * 1000L;
+        }
+
+		/// <summary>The format tag value.</summary>
+        public int Format
+		{
+			get { return format; }
+		}
+
+		/// <summary>The modification time of the file in milli-seconds (since Jan 1, 1970 UTC)</summary>
+        public long ModificationTime
+		{
+			get { return modDate; }
+		}
+
+		public string FileName
+		{
+			get { return Strings.FromUtf8ByteArray(fileName); }
+		}
+
+		public byte[] GetRawFileName()
+		{
+			return Arrays.Clone(fileName);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/MPInteger.cs b/crypto/src/bcpg/MPInteger.cs
new file mode 100644
index 000000000..441407244
--- /dev/null
+++ b/crypto/src/bcpg/MPInteger.cs
@@ -0,0 +1,59 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>A multiple precision integer</remarks>
+    public class MPInteger
+        : BcpgObject
+    {
+        private readonly BigInteger val;
+
+        public MPInteger(
+            BcpgInputStream bcpgIn)
+        {
+			if (bcpgIn == null)
+				throw new ArgumentNullException("bcpgIn");
+
+			int length = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+            byte[] bytes = new byte[(length + 7) / 8];
+
+            bcpgIn.ReadFully(bytes);
+
+            this.val = new BigInteger(1, bytes);
+        }
+
+		public MPInteger(
+            BigInteger val)
+        {
+			if (val == null)
+				throw new ArgumentNullException("val");
+			if (val.SignValue < 0)
+				throw new ArgumentException("Values must be positive", "val");
+
+			this.val = val;
+        }
+
+		public BigInteger Value
+        {
+            get { return val; }
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+			bcpgOut.WriteShort((short) val.BitLength);
+			bcpgOut.Write(val.ToByteArrayUnsigned());
+        }
+
+		internal static void Encode(
+			BcpgOutputStream	bcpgOut,
+			BigInteger			val)
+		{
+			bcpgOut.WriteShort((short) val.BitLength);
+			bcpgOut.Write(val.ToByteArrayUnsigned());
+		}
+    }
+}
diff --git a/crypto/src/bcpg/MarkerPacket.cs b/crypto/src/bcpg/MarkerPacket.cs
new file mode 100644
index 000000000..4dc4b5a83
--- /dev/null
+++ b/crypto/src/bcpg/MarkerPacket.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic type for a marker packet.</remarks>
+    public class MarkerPacket
+        : ContainedPacket
+    {
+        // "PGP"
+        byte[] marker = { (byte)0x50, (byte)0x47, (byte)0x50 };
+
+        public MarkerPacket(
+            BcpgInputStream bcpgIn)
+        {
+            bcpgIn.ReadFully(marker);
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.Marker, marker, true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/ModDetectionCodePacket.cs b/crypto/src/bcpg/ModDetectionCodePacket.cs
new file mode 100644
index 000000000..6bb23645a
--- /dev/null
+++ b/crypto/src/bcpg/ModDetectionCodePacket.cs
@@ -0,0 +1,42 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic packet for a modification detection code packet.</remarks>
+    public class ModDetectionCodePacket
+        : ContainedPacket
+    {
+        private readonly byte[] digest;
+
+		internal ModDetectionCodePacket(
+            BcpgInputStream bcpgIn)
+        {
+			if (bcpgIn == null)
+				throw new ArgumentNullException("bcpgIn");
+
+			this.digest = new byte[20];
+            bcpgIn.ReadFully(this.digest);
+        }
+
+		public ModDetectionCodePacket(
+            byte[] digest)
+        {
+			if (digest == null)
+				throw new ArgumentNullException("digest");
+
+			this.digest = (byte[]) digest.Clone();
+        }
+
+		public byte[] GetDigest()
+        {
+			return (byte[]) digest.Clone();
+        }
+
+		public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.ModificationDetectionCode, digest, false);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/OnePassSignaturePacket.cs b/crypto/src/bcpg/OnePassSignaturePacket.cs
new file mode 100644
index 000000000..b67df0a52
--- /dev/null
+++ b/crypto/src/bcpg/OnePassSignaturePacket.cs
@@ -0,0 +1,93 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Generic signature object</remarks>
+	public class OnePassSignaturePacket
+		: ContainedPacket
+	{
+		private int version;
+		private int sigType;
+		private HashAlgorithmTag hashAlgorithm;
+		private PublicKeyAlgorithmTag keyAlgorithm;
+		private long keyId;
+		private int nested;
+
+		internal OnePassSignaturePacket(
+			BcpgInputStream	bcpgIn)
+		{
+			version = bcpgIn.ReadByte();
+			sigType = bcpgIn.ReadByte();
+			hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+			keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+
+			keyId |= (long)bcpgIn.ReadByte() << 56;
+			keyId |= (long)bcpgIn.ReadByte() << 48;
+			keyId |= (long)bcpgIn.ReadByte() << 40;
+			keyId |= (long)bcpgIn.ReadByte() << 32;
+			keyId |= (long)bcpgIn.ReadByte() << 24;
+			keyId |= (long)bcpgIn.ReadByte() << 16;
+			keyId |= (long)bcpgIn.ReadByte() << 8;
+			keyId |= (uint)bcpgIn.ReadByte();
+
+			nested = bcpgIn.ReadByte();
+		}
+
+		public OnePassSignaturePacket(
+			int						sigType,
+			HashAlgorithmTag		hashAlgorithm,
+			PublicKeyAlgorithmTag	keyAlgorithm,
+			long					keyId,
+			bool					isNested)
+		{
+			this.version = 3;
+			this.sigType = sigType;
+			this.hashAlgorithm = hashAlgorithm;
+			this.keyAlgorithm = keyAlgorithm;
+			this.keyId = keyId;
+			this.nested = (isNested) ? 0 : 1;
+		}
+
+		public int SignatureType
+		{
+			get { return sigType; }
+		}
+
+		/// <summary>The encryption algorithm tag.</summary>
+		public PublicKeyAlgorithmTag KeyAlgorithm
+		{
+			get { return keyAlgorithm; }
+		}
+
+		/// <summary>The hash algorithm tag.</summary>
+		public HashAlgorithmTag HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+		}
+
+		public long KeyId
+		{
+			get { return keyId; }
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+		{
+			MemoryStream bOut = new MemoryStream();
+			BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+			pOut.Write(
+				(byte) version,
+				(byte) sigType,
+				(byte) hashAlgorithm,
+				(byte) keyAlgorithm);
+
+			pOut.WriteLong(keyId);
+
+			pOut.WriteByte((byte) nested);
+
+			bcpgOut.WritePacket(PacketTag.OnePassSignature, bOut.ToArray(), true);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/OutputStreamPacket.cs b/crypto/src/bcpg/OutputStreamPacket.cs
new file mode 100644
index 000000000..aa8316dcb
--- /dev/null
+++ b/crypto/src/bcpg/OutputStreamPacket.cs
@@ -0,0 +1,24 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    public abstract class OutputStreamPacket
+    {
+        private readonly BcpgOutputStream bcpgOut;
+
+		internal OutputStreamPacket(
+            BcpgOutputStream bcpgOut)
+        {
+			if (bcpgOut == null)
+				throw new ArgumentNullException("bcpgOut");
+
+			this.bcpgOut = bcpgOut;
+        }
+
+		public abstract BcpgOutputStream Open();
+
+		public abstract void Close();
+    }
+}
+
diff --git a/crypto/src/bcpg/Packet.cs b/crypto/src/bcpg/Packet.cs
new file mode 100644
index 000000000..83f6d1f74
--- /dev/null
+++ b/crypto/src/bcpg/Packet.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Bcpg
+{
+    public class Packet
+        //: PacketTag
+    {
+    }
+}
diff --git a/crypto/src/bcpg/PacketTags.cs b/crypto/src/bcpg/PacketTags.cs
new file mode 100644
index 000000000..5a53d4e95
--- /dev/null
+++ b/crypto/src/bcpg/PacketTags.cs
@@ -0,0 +1,30 @@
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic PGP packet tag types.</remarks>
+    public enum PacketTag
+    {
+        Reserved =  0,								//  Reserved - a packet tag must not have this value
+        PublicKeyEncryptedSession = 1,				// Public-Key Encrypted Session Key Packet
+        Signature = 2,								// Signature Packet
+        SymmetricKeyEncryptedSessionKey = 3,		// Symmetric-Key Encrypted Session Key Packet
+        OnePassSignature = 4,						// One-Pass Signature Packet
+        SecretKey = 5,								// Secret Key Packet
+        PublicKey = 6,								// Public Key Packet
+        SecretSubkey = 7,							// Secret Subkey Packet
+        CompressedData = 8,							// Compressed Data Packet
+        SymmetricKeyEncrypted = 9,					// Symmetrically Encrypted Data Packet
+        Marker = 10,								// Marker Packet
+        LiteralData = 11,							// Literal Data Packet
+        Trust = 12,									// Trust Packet
+        UserId = 13,								// User ID Packet
+        PublicSubkey = 14,							// Public Subkey Packet
+        UserAttribute = 17,							// User attribute
+        SymmetricEncryptedIntegrityProtected = 18,	// Symmetric encrypted, integrity protected
+        ModificationDetectionCode = 19,				// Modification detection code
+
+        Experimental1 = 60,							// Private or Experimental Values
+        Experimental2 = 61,
+        Experimental3 = 62,
+        Experimental4 = 63
+    }
+}
diff --git a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
new file mode 100644
index 000000000..85ae548eb
--- /dev/null
+++ b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
@@ -0,0 +1,28 @@
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Public Key Algorithm tag numbers.</remarks>
+    public enum PublicKeyAlgorithmTag
+    {
+        RsaGeneral = 1,			// RSA (Encrypt or Sign)
+        RsaEncrypt = 2,			// RSA Encrypt-Only
+        RsaSign = 3,			// RSA Sign-Only
+        ElGamalEncrypt = 16,	// Elgamal (Encrypt-Only), see [ELGAMAL]
+        Dsa = 17,				// DSA (Digital Signature Standard)
+        EC = 18,				// Reserved for Elliptic Curve
+        ECDsa = 19,				// Reserved for ECDSA
+        ElGamalGeneral = 20,	// Elgamal (Encrypt or Sign)
+        DiffieHellman = 21,		// Reserved for Diffie-Hellman (X9.42, as defined for IETF-S/MIME)
+
+		Experimental_1 = 100,
+		Experimental_2 = 101,
+		Experimental_3 = 102,
+		Experimental_4 = 103,
+		Experimental_5 = 104,
+		Experimental_6 = 105,
+		Experimental_7 = 106,
+		Experimental_8 = 107,
+		Experimental_9 = 108,
+		Experimental_10 = 109,
+		Experimental_11 = 110,
+	}
+}
diff --git a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
new file mode 100644
index 000000000..d10605f1d
--- /dev/null
+++ b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
@@ -0,0 +1,103 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic packet for a PGP public key.</remarks>
+	public class PublicKeyEncSessionPacket
+		: ContainedPacket //, PublicKeyAlgorithmTag
+	{
+		private int version;
+		private long keyId;
+		private PublicKeyAlgorithmTag algorithm;
+		private BigInteger[] data;
+
+		internal PublicKeyEncSessionPacket(
+			BcpgInputStream bcpgIn)
+		{
+			version = bcpgIn.ReadByte();
+
+			keyId |= (long)bcpgIn.ReadByte() << 56;
+			keyId |= (long)bcpgIn.ReadByte() << 48;
+			keyId |= (long)bcpgIn.ReadByte() << 40;
+			keyId |= (long)bcpgIn.ReadByte() << 32;
+			keyId |= (long)bcpgIn.ReadByte() << 24;
+			keyId |= (long)bcpgIn.ReadByte() << 16;
+			keyId |= (long)bcpgIn.ReadByte() << 8;
+			keyId |= (uint)bcpgIn.ReadByte();
+
+			algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+
+			switch ((PublicKeyAlgorithmTag) algorithm)
+			{
+				case PublicKeyAlgorithmTag.RsaEncrypt:
+				case PublicKeyAlgorithmTag.RsaGeneral:
+					data = new BigInteger[]{ new MPInteger(bcpgIn).Value };
+					break;
+				case PublicKeyAlgorithmTag.ElGamalEncrypt:
+				case PublicKeyAlgorithmTag.ElGamalGeneral:
+					data = new BigInteger[]
+					{
+						new MPInteger(bcpgIn).Value,
+						new MPInteger(bcpgIn).Value
+					};
+					break;
+				default:
+					throw new IOException("unknown PGP public key algorithm encountered");
+			}
+		}
+
+		public PublicKeyEncSessionPacket(
+			long					keyId,
+			PublicKeyAlgorithmTag	algorithm,
+			BigInteger[]			data)
+		{
+			this.version = 3;
+			this.keyId = keyId;
+			this.algorithm = algorithm;
+			this.data = (BigInteger[]) data.Clone();
+		}
+
+		public int Version
+		{
+			get { return version; }
+		}
+
+		public long KeyId
+		{
+			get { return keyId; }
+		}
+
+		public PublicKeyAlgorithmTag Algorithm
+		{
+			get { return algorithm; }
+		}
+
+		public BigInteger[] GetEncSessionKey()
+		{
+			return (BigInteger[]) data.Clone();
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+		{
+			MemoryStream bOut = new MemoryStream();
+			BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+			pOut.WriteByte((byte) version);
+
+			pOut.WriteLong(keyId);
+
+			pOut.WriteByte((byte)algorithm);
+
+			for (int i = 0; i != data.Length; i++)
+			{
+				MPInteger.Encode(pOut, data[i]);
+			}
+
+			bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs
index 32d43149b..a45aeb469 100644
--- a/crypto/src/bcpg/PublicKeyPacket.cs
+++ b/crypto/src/bcpg/PublicKeyPacket.cs
@@ -5,11 +5,11 @@ using Org.BouncyCastle.Utilities.Date;
 
 namespace Org.BouncyCastle.Bcpg
 {
-	/// <remarks>Basic packet for a PGP public key.</remarks>
+    /// <remarks>Basic packet for a PGP public key.</remarks>
     public class PublicKeyPacket
         : ContainedPacket //, PublicKeyAlgorithmTag
     {
-		private int version;
+        private int version;
         private long time;
         private int validDays;
         private PublicKeyAlgorithmTag algorithm;
@@ -49,44 +49,44 @@ namespace Org.BouncyCastle.Bcpg
             }
         }
 
-		/// <summary>Construct a version 4 public key packet.</summary>
+        /// <summary>Construct a version 4 public key packet.</summary>
         public PublicKeyPacket(
             PublicKeyAlgorithmTag	algorithm,
             DateTime				time,
             IBcpgKey				key)
         {
-			this.version = 4;
+            this.version = 4;
             this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
             this.algorithm = algorithm;
             this.key = key;
         }
 
-        public int Version
+        public virtual int Version
         {
-			get { return version; }
+            get { return version; }
         }
 
-        public PublicKeyAlgorithmTag Algorithm
+        public virtual PublicKeyAlgorithmTag Algorithm
         {
-			get { return algorithm; }
+            get { return algorithm; }
         }
 
-        public int ValidDays
+        public virtual int ValidDays
         {
-			get { return validDays; }
+            get { return validDays; }
         }
 
-		public DateTime GetTime()
+        public virtual DateTime GetTime()
         {
             return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
         }
 
-        public IBcpgKey Key
+        public virtual IBcpgKey Key
         {
-			get { return key; }
+            get { return key; }
         }
 
-        public byte[] GetEncodedContents()
+        public virtual byte[] GetEncodedContents()
         {
             MemoryStream bOut = new MemoryStream();
             BcpgOutputStream pOut = new BcpgOutputStream(bOut);
@@ -94,22 +94,22 @@ namespace Org.BouncyCastle.Bcpg
             pOut.WriteByte((byte) version);
             pOut.WriteInt((int) time);
 
-			if (version <= 3)
+            if (version <= 3)
             {
                 pOut.WriteShort((short) validDays);
             }
 
-			pOut.WriteByte((byte) algorithm);
+            pOut.WriteByte((byte) algorithm);
 
-			pOut.WriteObject((BcpgObject)key);
+            pOut.WriteObject((BcpgObject)key);
 
-			return bOut.ToArray();
+            return bOut.ToArray();
         }
 
-		public override void Encode(
-			BcpgOutputStream bcpgOut)
-		{
-			bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
-		}
-	}
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.PublicKey, GetEncodedContents(), true);
+        }
+    }
 }
diff --git a/crypto/src/bcpg/PublicSubkeyPacket.cs b/crypto/src/bcpg/PublicSubkeyPacket.cs
new file mode 100644
index 000000000..6e1aeda98
--- /dev/null
+++ b/crypto/src/bcpg/PublicSubkeyPacket.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic packet for a PGP public subkey</remarks>
+    public class PublicSubkeyPacket
+        : PublicKeyPacket
+    {
+        internal PublicSubkeyPacket(
+            BcpgInputStream bcpgIn)
+			: base(bcpgIn)
+        {
+        }
+
+		/// <summary>Construct a version 4 public subkey packet.</summary>
+        public PublicSubkeyPacket(
+            PublicKeyAlgorithmTag	algorithm,
+            DateTime				time,
+            IBcpgKey				key)
+            : base(algorithm, time, key)
+        {
+        }
+
+		public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.PublicSubkey, GetEncodedContents(), true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/RsaPublicBcpgKey.cs b/crypto/src/bcpg/RsaPublicBcpgKey.cs
new file mode 100644
index 000000000..fd2313c89
--- /dev/null
+++ b/crypto/src/bcpg/RsaPublicBcpgKey.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base class for an RSA public key.</remarks>
+	public class RsaPublicBcpgKey
+		: BcpgObject, IBcpgKey
+	{
+		private readonly MPInteger n, e;
+
+		/// <summary>Construct an RSA public key from the passed in stream.</summary>
+		public RsaPublicBcpgKey(
+			BcpgInputStream bcpgIn)
+		{
+			this.n = new MPInteger(bcpgIn);
+			this.e = new MPInteger(bcpgIn);
+		}
+
+		/// <param name="n">The modulus.</param>
+		/// <param name="e">The public exponent.</param>
+		public RsaPublicBcpgKey(
+			BigInteger	n,
+			BigInteger	e)
+		{
+			this.n = new MPInteger(n);
+			this.e = new MPInteger(e);
+		}
+
+		public BigInteger PublicExponent
+		{
+			get { return e.Value; }
+		}
+
+		public BigInteger Modulus
+		{
+			get { return n.Value; }
+		}
+
+		/// <summary>The format, as a string, always "PGP".</summary>
+		public string Format
+		{
+			get { return "PGP"; }
+		}
+
+		/// <summary>Return the standard PGP encoding of the key.</summary>
+		public override byte[] GetEncoded()
+		{
+			try
+			{
+				return base.GetEncoded();
+			}
+			catch (Exception)
+			{
+				return null;
+			}
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+		{
+			bcpgOut.WriteObjects(n, e);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/RsaSecretBcpgKey.cs b/crypto/src/bcpg/RsaSecretBcpgKey.cs
new file mode 100644
index 000000000..5c04d9f85
--- /dev/null
+++ b/crypto/src/bcpg/RsaSecretBcpgKey.cs
@@ -0,0 +1,114 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base class for an RSA secret (or priate) key.</remarks>
+	public class RsaSecretBcpgKey
+		: BcpgObject, IBcpgKey
+	{
+		private readonly MPInteger d, p, q, u;
+		private readonly BigInteger expP, expQ, crt;
+
+		public RsaSecretBcpgKey(
+			BcpgInputStream bcpgIn)
+		{
+			this.d = new MPInteger(bcpgIn);
+			this.p = new MPInteger(bcpgIn);
+			this.q = new MPInteger(bcpgIn);
+			this.u = new MPInteger(bcpgIn);
+
+			this.expP = d.Value.Remainder(p.Value.Subtract(BigInteger.One));
+			this.expQ = d.Value.Remainder(q.Value.Subtract(BigInteger.One));
+			this.crt = q.Value.ModInverse(p.Value);
+		}
+
+		public RsaSecretBcpgKey(
+			BigInteger d,
+			BigInteger p,
+			BigInteger q)
+		{
+			// PGP requires (p < q)
+			int cmp = p.CompareTo(q);
+			if (cmp >= 0)
+			{
+				if (cmp == 0)
+					throw new ArgumentException("p and q cannot be equal");
+
+				BigInteger tmp = p;
+				p = q;
+				q = tmp;
+			}
+
+			this.d = new MPInteger(d);
+			this.p = new MPInteger(p);
+			this.q = new MPInteger(q);
+			this.u = new MPInteger(p.ModInverse(q));
+
+			this.expP = d.Remainder(p.Subtract(BigInteger.One));
+			this.expQ = d.Remainder(q.Subtract(BigInteger.One));
+			this.crt = q.ModInverse(p);
+		}
+
+		public BigInteger Modulus
+		{
+			get { return p.Value.Multiply(q.Value); }
+		}
+
+		public BigInteger PrivateExponent
+		{
+			get { return d.Value; }
+		}
+
+		public BigInteger PrimeP
+		{
+			get { return p.Value; }
+		}
+
+		public BigInteger PrimeQ
+		{
+			get { return q.Value; }
+		}
+
+		public BigInteger PrimeExponentP
+		{
+			get { return expP; }
+		}
+
+		public BigInteger PrimeExponentQ
+		{
+			get { return expQ; }
+		}
+
+		public BigInteger CrtCoefficient
+		{
+			get { return crt; }
+		}
+
+		/// <summary>The format, as a string, always "PGP".</summary>
+		public string Format
+		{
+			get { return "PGP"; }
+		}
+
+		/// <summary>Return the standard PGP encoding of the key.</summary>
+		public override byte[] GetEncoded()
+		{
+			try
+			{
+				return base.GetEncoded();
+			}
+			catch (Exception)
+			{
+				return null;
+			}
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+		{
+			bcpgOut.WriteObjects(d, p, q, u);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs
new file mode 100644
index 000000000..de08c016c
--- /dev/null
+++ b/crypto/src/bcpg/S2k.cs
@@ -0,0 +1,147 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>The string to key specifier class.</remarks>
+    public class S2k
+        : BcpgObject
+    {
+        private const int ExpBias = 6;
+
+        public const int Simple = 0;
+        public const int Salted = 1;
+        public const int SaltedAndIterated = 3;
+        public const int GnuDummyS2K = 101;
+
+        internal int type;
+        internal HashAlgorithmTag algorithm;
+        internal byte[] iv;
+        internal int itCount = -1;
+        internal int protectionMode = -1;
+
+        internal S2k(
+            Stream inStr)
+        {
+			type = inStr.ReadByte();
+            algorithm = (HashAlgorithmTag) inStr.ReadByte();
+
+            //
+            // if this happens we have a dummy-S2k packet.
+            //
+            if (type != GnuDummyS2K)
+            {
+                if (type != 0)
+                {
+					iv = new byte[8];
+					if (Streams.ReadFully(inStr, iv, 0, iv.Length) < iv.Length)
+						throw new EndOfStreamException();
+
+					if (type == 3)
+					{
+						itCount = inStr.ReadByte();
+					}
+				}
+            }
+            else
+            {
+                inStr.ReadByte(); // G
+                inStr.ReadByte(); // N
+                inStr.ReadByte(); // U
+                protectionMode = inStr.ReadByte(); // protection mode
+            }
+        }
+
+        public S2k(
+            HashAlgorithmTag algorithm)
+        {
+            this.type = 0;
+            this.algorithm = algorithm;
+        }
+
+        public S2k(
+            HashAlgorithmTag algorithm,
+            byte[] iv)
+        {
+            this.type = 1;
+            this.algorithm = algorithm;
+            this.iv = iv;
+        }
+
+        public S2k(
+            HashAlgorithmTag algorithm,
+            byte[] iv,
+            int itCount)
+        {
+            this.type = 3;
+            this.algorithm = algorithm;
+            this.iv = iv;
+            this.itCount = itCount;
+        }
+
+        public int Type
+        {
+			get { return type; }
+        }
+
+		/// <summary>The hash algorithm.</summary>
+        public HashAlgorithmTag HashAlgorithm
+        {
+			get { return algorithm; }
+		}
+
+		/// <summary>The IV for the key generation algorithm.</summary>
+        public byte[] GetIV()
+        {
+            return Arrays.Clone(iv);
+        }
+
+		[Obsolete("Use 'IterationCount' property instead")]
+        public long GetIterationCount()
+        {
+            return IterationCount;
+        }
+
+		/// <summary>The iteration count</summary>
+		public long IterationCount
+		{
+			get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); }
+		}
+
+		/// <summary>The protection mode - only if GnuDummyS2K</summary>
+        public int ProtectionMode
+        {
+			get { return protectionMode; }
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WriteByte((byte) type);
+            bcpgOut.WriteByte((byte) algorithm);
+
+            if (type != GnuDummyS2K)
+            {
+                if (type != 0)
+                {
+                    bcpgOut.Write(iv);
+                }
+
+                if (type == 3)
+                {
+                    bcpgOut.WriteByte((byte) itCount);
+                }
+            }
+            else
+            {
+                bcpgOut.WriteByte((byte) 'G');
+                bcpgOut.WriteByte((byte) 'N');
+                bcpgOut.WriteByte((byte) 'U');
+                bcpgOut.WriteByte((byte) protectionMode);
+            }
+        }
+    }
+}
diff --git a/crypto/src/bcpg/SecretKeyPacket.cs b/crypto/src/bcpg/SecretKeyPacket.cs
new file mode 100644
index 000000000..d9ceab4f1
--- /dev/null
+++ b/crypto/src/bcpg/SecretKeyPacket.cs
@@ -0,0 +1,170 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic packet for a PGP secret key.</remarks>
+    public class SecretKeyPacket
+        : ContainedPacket //, PublicKeyAlgorithmTag
+    {
+		public const int UsageNone = 0x00;
+		public const int UsageChecksum = 0xff;
+		public const int UsageSha1 = 0xfe;
+
+		private PublicKeyPacket pubKeyPacket;
+        private readonly byte[] secKeyData;
+		private int s2kUsage;
+		private SymmetricKeyAlgorithmTag encAlgorithm;
+        private S2k s2k;
+        private byte[] iv;
+
+		internal SecretKeyPacket(
+            BcpgInputStream bcpgIn)
+        {
+			if (this is SecretSubkeyPacket)
+			{
+				pubKeyPacket = new PublicSubkeyPacket(bcpgIn);
+			}
+			else
+			{
+				pubKeyPacket = new PublicKeyPacket(bcpgIn);
+			}
+
+			s2kUsage = bcpgIn.ReadByte();
+
+			if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
+            {
+                encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte();
+                s2k = new S2k(bcpgIn);
+            }
+            else
+            {
+                encAlgorithm = (SymmetricKeyAlgorithmTag) s2kUsage;
+			}
+
+			if (!(s2k != null && s2k.Type == S2k.GnuDummyS2K && s2k.ProtectionMode == 0x01))
+            {
+				if (s2kUsage != 0)
+				{
+                    if (((int) encAlgorithm) < 7)
+                    {
+                        iv = new byte[8];
+                    }
+                    else
+                    {
+                        iv = new byte[16];
+                    }
+                    bcpgIn.ReadFully(iv);
+                }
+            }
+
+			secKeyData = bcpgIn.ReadAll();
+        }
+
+		public SecretKeyPacket(
+            PublicKeyPacket				pubKeyPacket,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            S2k							s2k,
+            byte[]						iv,
+            byte[]						secKeyData)
+        {
+            this.pubKeyPacket = pubKeyPacket;
+            this.encAlgorithm = encAlgorithm;
+
+			if (encAlgorithm != SymmetricKeyAlgorithmTag.Null)
+			{
+				this.s2kUsage = UsageChecksum;
+			}
+			else
+			{
+				this.s2kUsage = UsageNone;
+			}
+
+			this.s2k = s2k;
+			this.iv = Arrays.Clone(iv);
+			this.secKeyData = secKeyData;
+        }
+
+		public SecretKeyPacket(
+			PublicKeyPacket				pubKeyPacket,
+			SymmetricKeyAlgorithmTag	encAlgorithm,
+			int							s2kUsage,
+			S2k							s2k,
+			byte[]						iv,
+			byte[]						secKeyData)
+		{
+			this.pubKeyPacket = pubKeyPacket;
+			this.encAlgorithm = encAlgorithm;
+			this.s2kUsage = s2kUsage;
+			this.s2k = s2k;
+			this.iv = Arrays.Clone(iv);
+			this.secKeyData = secKeyData;
+		}
+
+		public SymmetricKeyAlgorithmTag EncAlgorithm
+        {
+			get { return encAlgorithm; }
+        }
+
+		public int S2kUsage
+		{
+			get { return s2kUsage; }
+		}
+
+		public byte[] GetIV()
+        {
+            return Arrays.Clone(iv);
+        }
+
+		public S2k S2k
+        {
+			get { return s2k; }
+        }
+
+		public PublicKeyPacket PublicKeyPacket
+        {
+			get { return pubKeyPacket; }
+        }
+
+		public byte[] GetSecretKeyData()
+        {
+            return secKeyData;
+        }
+
+		public byte[] GetEncodedContents()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+            pOut.Write(pubKeyPacket.GetEncodedContents());
+
+			pOut.WriteByte((byte) s2kUsage);
+
+			if (s2kUsage == UsageChecksum || s2kUsage == UsageSha1)
+            {
+                pOut.WriteByte((byte) encAlgorithm);
+                pOut.WriteObject(s2k);
+            }
+
+			if (iv != null)
+            {
+                pOut.Write(iv);
+            }
+
+            if (secKeyData != null && secKeyData.Length > 0)
+            {
+                pOut.Write(secKeyData);
+            }
+
+            return bOut.ToArray();
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.SecretKey, GetEncodedContents(), true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/SecretSubkeyPacket.cs b/crypto/src/bcpg/SecretSubkeyPacket.cs
new file mode 100644
index 000000000..8f1746942
--- /dev/null
+++ b/crypto/src/bcpg/SecretSubkeyPacket.cs
@@ -0,0 +1,43 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic packet for a PGP secret key.</remarks>
+    public class SecretSubkeyPacket
+        : SecretKeyPacket
+    {
+        internal SecretSubkeyPacket(
+			BcpgInputStream bcpgIn)
+            : base(bcpgIn)
+        {
+        }
+
+		public SecretSubkeyPacket(
+            PublicKeyPacket				pubKeyPacket,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            S2k							s2k,
+            byte[]						iv,
+            byte[]						secKeyData)
+            : base(pubKeyPacket, encAlgorithm, s2k, iv, secKeyData)
+        {
+        }
+
+		public SecretSubkeyPacket(
+			PublicKeyPacket				pubKeyPacket,
+			SymmetricKeyAlgorithmTag	encAlgorithm,
+			int							s2kUsage,
+			S2k							s2k,
+			byte[]						iv,
+			byte[]						secKeyData)
+			: base(pubKeyPacket, encAlgorithm, s2kUsage, s2k, iv, secKeyData)
+		{
+		}
+
+		public override void Encode(
+			BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.SecretSubkey, GetEncodedContents(), true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs
new file mode 100644
index 000000000..605ce84c4
--- /dev/null
+++ b/crypto/src/bcpg/SignaturePacket.cs
@@ -0,0 +1,472 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Generic signature packet.</remarks>
+    public class SignaturePacket
+        : ContainedPacket //, PublicKeyAlgorithmTag
+    {
+		private int						version;
+        private int						signatureType;
+        private long					creationTime;
+        private long					keyId;
+        private PublicKeyAlgorithmTag	keyAlgorithm;
+        private HashAlgorithmTag		hashAlgorithm;
+        private MPInteger[]				signature;
+        private byte[]					fingerprint;
+        private SignatureSubpacket[]	hashedData;
+        private SignatureSubpacket[]	unhashedData;
+		private byte[]					signatureEncoding;
+
+		internal SignaturePacket(
+            BcpgInputStream bcpgIn)
+        {
+            version = bcpgIn.ReadByte();
+
+			if (version == 3 || version == 2)
+            {
+//                int l =
+                bcpgIn.ReadByte();
+
+				signatureType = bcpgIn.ReadByte();
+                creationTime = (((long)bcpgIn.ReadByte() << 24) | ((long)bcpgIn.ReadByte() << 16)
+                    | ((long)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte()) * 1000L;
+
+				keyId |= (long)bcpgIn.ReadByte() << 56;
+                keyId |= (long)bcpgIn.ReadByte() << 48;
+                keyId |= (long)bcpgIn.ReadByte() << 40;
+                keyId |= (long)bcpgIn.ReadByte() << 32;
+                keyId |= (long)bcpgIn.ReadByte() << 24;
+                keyId |= (long)bcpgIn.ReadByte() << 16;
+                keyId |= (long)bcpgIn.ReadByte() << 8;
+                keyId |= (uint)bcpgIn.ReadByte();
+
+				keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+                hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+            }
+            else if (version == 4)
+            {
+                signatureType = bcpgIn.ReadByte();
+                keyAlgorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+                hashAlgorithm = (HashAlgorithmTag) bcpgIn.ReadByte();
+
+				int hashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+                byte[] hashed = new byte[hashedLength];
+
+				bcpgIn.ReadFully(hashed);
+
+				//
+                // read the signature sub packet data.
+                //
+                SignatureSubpacketsParser sIn = new SignatureSubpacketsParser(
+                    new MemoryStream(hashed, false));
+
+				IList v = Platform.CreateArrayList();
+				SignatureSubpacket sub;
+				while ((sub = sIn.ReadPacket()) != null)
+                {
+                    v.Add(sub);
+                }
+
+				hashedData = new SignatureSubpacket[v.Count];
+
+				for (int i = 0; i != hashedData.Length; i++)
+                {
+                    SignatureSubpacket p = (SignatureSubpacket)v[i];
+                    if (p is IssuerKeyId)
+                    {
+                        keyId = ((IssuerKeyId)p).KeyId;
+                    }
+                    else if (p is SignatureCreationTime)
+                    {
+                        creationTime = DateTimeUtilities.DateTimeToUnixMs(
+							((SignatureCreationTime)p).GetTime());
+                    }
+
+					hashedData[i] = p;
+                }
+
+				int unhashedLength = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+                byte[] unhashed = new byte[unhashedLength];
+
+				bcpgIn.ReadFully(unhashed);
+
+				sIn = new SignatureSubpacketsParser(new MemoryStream(unhashed, false));
+
+				v.Clear();
+
+				while ((sub = sIn.ReadPacket()) != null)
+                {
+                    v.Add(sub);
+                }
+
+				unhashedData = new SignatureSubpacket[v.Count];
+
+				for (int i = 0; i != unhashedData.Length; i++)
+                {
+                    SignatureSubpacket p = (SignatureSubpacket)v[i];
+                    if (p is IssuerKeyId)
+                    {
+                        keyId = ((IssuerKeyId)p).KeyId;
+                    }
+
+					unhashedData[i] = p;
+                }
+            }
+            else
+            {
+                throw new Exception("unsupported version: " + version);
+            }
+
+			fingerprint = new byte[2];
+            bcpgIn.ReadFully(fingerprint);
+
+			switch (keyAlgorithm)
+            {
+                case PublicKeyAlgorithmTag.RsaGeneral:
+                case PublicKeyAlgorithmTag.RsaSign:
+                    MPInteger v = new MPInteger(bcpgIn);
+					signature = new MPInteger[]{ v };
+                    break;
+				case PublicKeyAlgorithmTag.Dsa:
+                    MPInteger r = new MPInteger(bcpgIn);
+                    MPInteger s = new MPInteger(bcpgIn);
+					signature = new MPInteger[]{ r, s };
+                    break;
+                case PublicKeyAlgorithmTag.ElGamalEncrypt: // yep, this really does happen sometimes.
+                case PublicKeyAlgorithmTag.ElGamalGeneral:
+                    MPInteger p = new MPInteger(bcpgIn);
+                    MPInteger g = new MPInteger(bcpgIn);
+                    MPInteger y = new MPInteger(bcpgIn);
+					signature = new MPInteger[]{ p, g, y };
+                    break;
+                default:
+					if (keyAlgorithm >= PublicKeyAlgorithmTag.Experimental_1 && keyAlgorithm <= PublicKeyAlgorithmTag.Experimental_11)
+					{
+						signature = null;
+						MemoryStream bOut = new MemoryStream();
+						int ch;
+						while ((ch = bcpgIn.ReadByte()) >= 0)
+						{
+							bOut.WriteByte((byte) ch);
+						}
+						signatureEncoding = bOut.ToArray();
+					}
+					else
+					{
+						throw new IOException("unknown signature key algorithm: " + keyAlgorithm);
+					}
+					break;
+            }
+        }
+
+		/**
+        * Generate a version 4 signature packet.
+        *
+        * @param signatureType
+        * @param keyAlgorithm
+        * @param hashAlgorithm
+        * @param hashedData
+        * @param unhashedData
+        * @param fingerprint
+        * @param signature
+        */
+        public SignaturePacket(
+            int						signatureType,
+            long					keyId,
+            PublicKeyAlgorithmTag	keyAlgorithm,
+            HashAlgorithmTag		hashAlgorithm,
+            SignatureSubpacket[]	hashedData,
+            SignatureSubpacket[]	unhashedData,
+            byte[]					fingerprint,
+            MPInteger[]				signature)
+            : this(4, signatureType, keyId, keyAlgorithm, hashAlgorithm, hashedData, unhashedData, fingerprint, signature)
+        {
+        }
+
+		/**
+        * Generate a version 2/3 signature packet.
+        *
+        * @param signatureType
+        * @param keyAlgorithm
+        * @param hashAlgorithm
+        * @param fingerprint
+        * @param signature
+        */
+        public SignaturePacket(
+            int						version,
+            int						signatureType,
+            long					keyId,
+            PublicKeyAlgorithmTag	keyAlgorithm,
+            HashAlgorithmTag		hashAlgorithm,
+            long					creationTime,
+            byte[]					fingerprint,
+            MPInteger[]				signature)
+            : this(version, signatureType, keyId, keyAlgorithm, hashAlgorithm, null, null, fingerprint, signature)
+        {
+			this.creationTime = creationTime;
+        }
+
+		public SignaturePacket(
+            int						version,
+            int						signatureType,
+            long					keyId,
+            PublicKeyAlgorithmTag	keyAlgorithm,
+            HashAlgorithmTag		hashAlgorithm,
+            SignatureSubpacket[]	hashedData,
+            SignatureSubpacket[]	unhashedData,
+            byte[]					fingerprint,
+            MPInteger[]				signature)
+        {
+            this.version = version;
+            this.signatureType = signatureType;
+            this.keyId = keyId;
+            this.keyAlgorithm = keyAlgorithm;
+            this.hashAlgorithm = hashAlgorithm;
+            this.hashedData = hashedData;
+            this.unhashedData = unhashedData;
+            this.fingerprint = fingerprint;
+            this.signature = signature;
+
+			if (hashedData != null)
+			{
+				setCreationTime();
+			}
+		}
+
+		public int Version
+        {
+			get { return version; }
+        }
+
+		public int SignatureType
+        {
+			get { return signatureType; }
+		}
+
+		/**
+        * return the keyId
+        * @return the keyId that created the signature.
+        */
+        public long KeyId
+        {
+            get { return keyId; }
+        }
+
+		/**
+        * return the signature trailer that must be included with the data
+        * to reconstruct the signature
+        *
+        * @return byte[]
+        */
+        public byte[] GetSignatureTrailer()
+        {
+            byte[] trailer = null;
+
+			if (version == 3)
+            {
+                trailer = new byte[5];
+
+				long time = creationTime / 1000L;
+
+				trailer[0] = (byte)signatureType;
+                trailer[1] = (byte)(time >> 24);
+                trailer[2] = (byte)(time >> 16);
+                trailer[3] = (byte)(time >> 8);
+                trailer[4] = (byte)(time);
+            }
+            else
+            {
+                MemoryStream sOut = new MemoryStream();
+
+				sOut.WriteByte((byte)this.Version);
+                sOut.WriteByte((byte)this.SignatureType);
+                sOut.WriteByte((byte)this.KeyAlgorithm);
+                sOut.WriteByte((byte)this.HashAlgorithm);
+
+				MemoryStream hOut = new MemoryStream();
+                SignatureSubpacket[] hashed = this.GetHashedSubPackets();
+
+				for (int i = 0; i != hashed.Length; i++)
+                {
+                    hashed[i].Encode(hOut);
+                }
+
+				byte[] data = hOut.ToArray();
+
+				sOut.WriteByte((byte)(data.Length >> 8));
+                sOut.WriteByte((byte)data.Length);
+                sOut.Write(data, 0, data.Length);
+
+				byte[] hData = sOut.ToArray();
+
+				sOut.WriteByte((byte)this.Version);
+                sOut.WriteByte((byte)0xff);
+                sOut.WriteByte((byte)(hData.Length>> 24));
+                sOut.WriteByte((byte)(hData.Length >> 16));
+                sOut.WriteByte((byte)(hData.Length >> 8));
+                sOut.WriteByte((byte)(hData.Length));
+
+				trailer = sOut.ToArray();
+            }
+
+			return trailer;
+        }
+
+		public PublicKeyAlgorithmTag KeyAlgorithm
+        {
+			get { return keyAlgorithm; }
+        }
+
+		public HashAlgorithmTag HashAlgorithm
+		{
+			get { return hashAlgorithm; }
+        }
+
+		/**
+		* return the signature as a set of integers - note this is normalised to be the
+        * ASN.1 encoding of what appears in the signature packet.
+        */
+        public MPInteger[] GetSignature()
+        {
+            return signature;
+        }
+
+		/**
+		 * Return the byte encoding of the signature section.
+		 * @return uninterpreted signature bytes.
+		 */
+		public byte[] GetSignatureBytes()
+		{
+			if (signatureEncoding != null)
+			{
+				return (byte[]) signatureEncoding.Clone();
+			}
+
+			MemoryStream bOut = new MemoryStream();
+			BcpgOutputStream bcOut = new BcpgOutputStream(bOut);
+
+			foreach (MPInteger sigObj in signature)
+			{
+				try
+				{
+					bcOut.WriteObject(sigObj);
+				}
+				catch (IOException e)
+				{
+					throw new Exception("internal error: " + e);
+				}
+			}
+
+			return bOut.ToArray();
+		}
+
+		public SignatureSubpacket[] GetHashedSubPackets()
+        {
+            return hashedData;
+        }
+
+		public SignatureSubpacket[] GetUnhashedSubPackets()
+        {
+            return unhashedData;
+        }
+
+		/// <summary>Return the creation time in milliseconds since 1 Jan., 1970 UTC.</summary>
+        public long CreationTime
+        {
+            get { return creationTime; }
+        }
+
+		public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            MemoryStream bOut = new MemoryStream();
+            BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+			pOut.WriteByte((byte) version);
+
+			if (version == 3 || version == 2)
+            {
+				pOut.Write(
+					5, // the length of the next block
+					(byte) signatureType);
+
+				pOut.WriteInt((int)(creationTime / 1000L));
+
+				pOut.WriteLong(keyId);
+
+				pOut.Write(
+					(byte) keyAlgorithm,
+					(byte) hashAlgorithm);
+            }
+            else if (version == 4)
+            {
+                pOut.Write(
+					(byte) signatureType,
+					(byte) keyAlgorithm,
+					(byte) hashAlgorithm);
+
+				EncodeLengthAndData(pOut, GetEncodedSubpackets(hashedData));
+
+				EncodeLengthAndData(pOut, GetEncodedSubpackets(unhashedData));
+            }
+            else
+            {
+                throw new IOException("unknown version: " + version);
+            }
+
+			pOut.Write(fingerprint);
+
+			if (signature != null)
+			{
+				pOut.WriteObjects(signature);
+			}
+			else
+			{
+				pOut.Write(signatureEncoding);
+			}
+
+			bcpgOut.WritePacket(PacketTag.Signature, bOut.ToArray(), true);
+        }
+
+		private static void EncodeLengthAndData(
+			BcpgOutputStream	pOut,
+			byte[]				data)
+		{
+			pOut.WriteShort((short) data.Length);
+			pOut.Write(data);
+		}
+
+		private static byte[] GetEncodedSubpackets(
+			SignatureSubpacket[] ps)
+		{
+			MemoryStream sOut = new MemoryStream();
+
+			foreach (SignatureSubpacket p in ps)
+			{
+				p.Encode(sOut);
+			}
+
+			return sOut.ToArray();
+		}
+
+		private void setCreationTime()
+		{
+			foreach (SignatureSubpacket p in hashedData)
+			{
+				if (p is SignatureCreationTime)
+				{
+                    creationTime = DateTimeUtilities.DateTimeToUnixMs(
+						((SignatureCreationTime)p).GetTime());
+					break;
+				}
+			}
+		}
+	}
+}
diff --git a/crypto/src/bcpg/SignatureSubpacket.cs b/crypto/src/bcpg/SignatureSubpacket.cs
new file mode 100644
index 000000000..ac26f8a3c
--- /dev/null
+++ b/crypto/src/bcpg/SignatureSubpacket.cs
@@ -0,0 +1,76 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic type for a PGP Signature sub-packet.</remarks>
+    public class SignatureSubpacket
+    {
+        private readonly SignatureSubpacketTag type;
+        private readonly bool critical;
+
+		internal readonly byte[] data;
+
+		protected internal SignatureSubpacket(
+            SignatureSubpacketTag	type,
+            bool					critical,
+            byte[]					data)
+        {
+            this.type = type;
+            this.critical = critical;
+            this.data = data;
+        }
+
+		public SignatureSubpacketTag SubpacketType
+        {
+			get { return type; }
+        }
+
+        public bool IsCritical()
+        {
+            return critical;
+        }
+
+		/// <summary>Return the generic data making up the packet.</summary>
+        public byte[] GetData()
+        {
+            return (byte[]) data.Clone();
+        }
+
+		public void Encode(
+            Stream os)
+        {
+            int bodyLen = data.Length + 1;
+
+            if (bodyLen < 192)
+            {
+                os.WriteByte((byte)bodyLen);
+            }
+            else if (bodyLen <= 8383)
+            {
+                bodyLen -= 192;
+
+                os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+                os.WriteByte((byte)bodyLen);
+            }
+            else
+            {
+                os.WriteByte(0xff);
+                os.WriteByte((byte)(bodyLen >> 24));
+                os.WriteByte((byte)(bodyLen >> 16));
+                os.WriteByte((byte)(bodyLen >> 8));
+                os.WriteByte((byte)bodyLen);
+            }
+
+            if (critical)
+            {
+                os.WriteByte((byte)(0x80 | (int) type));
+            }
+            else
+            {
+                os.WriteByte((byte) type);
+            }
+
+            os.Write(data, 0, data.Length);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/SignatureSubpacketTags.cs b/crypto/src/bcpg/SignatureSubpacketTags.cs
new file mode 100644
index 000000000..1a8e254c0
--- /dev/null
+++ b/crypto/src/bcpg/SignatureSubpacketTags.cs
@@ -0,0 +1,33 @@
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic PGP signature sub-packet tag types.
+    */
+    public enum SignatureSubpacketTag
+    {
+        CreationTime = 2,						// signature creation time
+        ExpireTime = 3,							// signature expiration time
+        Exportable = 4,							// exportable certification
+        TrustSig = 5,							// trust signature
+        RegExp = 6,								// regular expression
+        Revocable = 7,							// revocable
+        KeyExpireTime = 9,						// key expiration time
+        Placeholder = 10,						// placeholder for backward compatibility
+        PreferredSymmetricAlgorithms = 11,		// preferred symmetric algorithms
+        RevocationKey = 12,						// revocation key
+        IssuerKeyId = 16,						// issuer key ID
+        NotationData = 20,						// notation data
+        PreferredHashAlgorithms = 21,			// preferred hash algorithms
+        PreferredCompressionAlgorithms = 22,	// preferred compression algorithms
+        KeyServerPreferences = 23,				// key server preferences
+        PreferredKeyServer = 24,				// preferred key server
+        PrimaryUserId = 25,						// primary user id
+        PolicyUrl = 26,							// policy URL
+        KeyFlags = 27,							// key flags
+        SignerUserId = 28,						// signer's user id
+        RevocationReason = 29,					// reason for revocation
+		Features = 30,							// features
+		SignatureTarget = 31,					// signature target
+		EmbeddedSignature = 32					// embedded signature
+	}
+}
diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs
new file mode 100644
index 000000000..8dd1af332
--- /dev/null
+++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs
@@ -0,0 +1,88 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/**
+	* reader for signature sub-packets
+	*/
+	public class SignatureSubpacketsParser
+	{
+		private readonly Stream input;
+
+		public SignatureSubpacketsParser(
+			Stream input)
+		{
+			this.input = input;
+		}
+
+		public SignatureSubpacket ReadPacket()
+		{
+			int l = input.ReadByte();
+			if (l < 0)
+				return null;
+
+			int bodyLen = 0;
+			if (l < 192)
+			{
+				bodyLen = l;
+			}
+			else if (l <= 223)
+			{
+				bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
+			}
+			else if (l == 255)
+			{
+				bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
+					|  (input.ReadByte() << 8)  | input.ReadByte();
+			}
+			else
+			{
+				// TODO Error?
+			}
+
+			int tag = input.ReadByte();
+			if (tag < 0)
+				throw new EndOfStreamException("unexpected EOF reading signature sub packet");
+
+			byte[] data = new byte[bodyLen - 1];
+			if (Streams.ReadFully(input, data) < data.Length)
+				throw new EndOfStreamException();
+
+			bool isCritical = ((tag & 0x80) != 0);
+			SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
+			switch (type)
+			{
+				case SignatureSubpacketTag.CreationTime:
+					return new SignatureCreationTime(isCritical, data);
+				case SignatureSubpacketTag.KeyExpireTime:
+					return new KeyExpirationTime(isCritical, data);
+				case SignatureSubpacketTag.ExpireTime:
+					return new SignatureExpirationTime(isCritical, data);
+				case SignatureSubpacketTag.Revocable:
+					return new Revocable(isCritical, data);
+				case SignatureSubpacketTag.Exportable:
+					return new Exportable(isCritical, data);
+				case SignatureSubpacketTag.IssuerKeyId:
+					return new IssuerKeyId(isCritical, data);
+				case SignatureSubpacketTag.TrustSig:
+					return new TrustSignature(isCritical, data);
+				case SignatureSubpacketTag.PreferredCompressionAlgorithms:
+				case SignatureSubpacketTag.PreferredHashAlgorithms:
+				case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
+					return new PreferredAlgorithms(type, isCritical, data);
+				case SignatureSubpacketTag.KeyFlags:
+					return new KeyFlags(isCritical, data);
+				case SignatureSubpacketTag.PrimaryUserId:
+					return new PrimaryUserId(isCritical, data);
+				case SignatureSubpacketTag.SignerUserId:
+					return new SignerUserId(isCritical, data);
+				case SignatureSubpacketTag.NotationData:
+					return new NotationData(isCritical, data);
+			}
+			return new SignatureSubpacket(type, isCritical, data);
+		}
+	}
+}
diff --git a/crypto/src/bcpg/SymmetricEncDataPacket.cs b/crypto/src/bcpg/SymmetricEncDataPacket.cs
new file mode 100644
index 000000000..17ee55bb7
--- /dev/null
+++ b/crypto/src/bcpg/SymmetricEncDataPacket.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic type for a symmetric key encrypted packet.</remarks>
+    public class SymmetricEncDataPacket
+        : InputStreamPacket
+    {
+        public SymmetricEncDataPacket(
+            BcpgInputStream bcpgIn)
+            : base(bcpgIn)
+        {
+        }
+    }
+}
diff --git a/crypto/src/bcpg/SymmetricEncIntegrityPacket.cs b/crypto/src/bcpg/SymmetricEncIntegrityPacket.cs
new file mode 100644
index 000000000..a9b6d0678
--- /dev/null
+++ b/crypto/src/bcpg/SymmetricEncIntegrityPacket.cs
@@ -0,0 +1,18 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	public class SymmetricEncIntegrityPacket
+		: InputStreamPacket
+	{
+		internal readonly int version;
+
+		internal SymmetricEncIntegrityPacket(
+			BcpgInputStream bcpgIn)
+			: base(bcpgIn)
+        {
+			version = bcpgIn.ReadByte();
+        }
+    }
+}
diff --git a/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs b/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs
index 7633b1dba..e05a48616 100644
--- a/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs
+++ b/crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs
@@ -5,16 +5,19 @@ namespace Org.BouncyCastle.Bcpg
     */
     public enum SymmetricKeyAlgorithmTag
     {
-        Null = 0,        // Plaintext or unencrypted data
-        Idea = 1,        // IDEA [IDEA]
-        TripleDes = 2,  // Triple-DES (DES-EDE, as per spec -168 bit key derived from 192)
-        Cast5 = 3,       // Cast5 (128 bit key, as per RFC 2144)
-        Blowfish = 4,    // Blowfish (128 bit key, 16 rounds) [Blowfish]
-        Safer = 5,       // Safer-SK128 (13 rounds) [Safer]
-        Des = 6,         // Reserved for DES/SK
-        Aes128 = 7,     // Reserved for AES with 128-bit key
-        Aes192 = 8,     // Reserved for AES with 192-bit key
-        Aes256 = 9,     // Reserved for AES with 256-bit key
-        Twofish = 10     // Reserved for Twofish
+        Null = 0,         // Plaintext or unencrypted data
+        Idea = 1,         // IDEA [IDEA]
+        TripleDes = 2,    // Triple-DES (DES-EDE, as per spec -168 bit key derived from 192)
+        Cast5 = 3,        // Cast5 (128 bit key, as per RFC 2144)
+        Blowfish = 4,     // Blowfish (128 bit key, 16 rounds) [Blowfish]
+        Safer = 5,        // Safer-SK128 (13 rounds) [Safer]
+        Des = 6,          // Reserved for DES/SK
+        Aes128 = 7,       // Reserved for AES with 128-bit key
+        Aes192 = 8,       // Reserved for AES with 192-bit key
+        Aes256 = 9,       // Reserved for AES with 256-bit key
+        Twofish = 10,     // Reserved for Twofish
+        Camellia128 = 11, // Reserved for AES with 128-bit key
+        Camellia192 = 12, // Reserved for AES with 192-bit key
+        Camellia256 = 13  // Reserved for AES with 256-bit key
     }
 }
diff --git a/crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs b/crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs
new file mode 100644
index 000000000..0381fa386
--- /dev/null
+++ b/crypto/src/bcpg/SymmetricKeyEncSessionPacket.cs
@@ -0,0 +1,91 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic type for a symmetric encrypted session key packet
+    */
+    public class SymmetricKeyEncSessionPacket
+        : ContainedPacket
+    {
+        private int version;
+        private SymmetricKeyAlgorithmTag encAlgorithm;
+        private S2k s2k;
+        private readonly byte[] secKeyData;
+
+        public SymmetricKeyEncSessionPacket(
+            BcpgInputStream bcpgIn)
+        {
+            version = bcpgIn.ReadByte();
+            encAlgorithm = (SymmetricKeyAlgorithmTag) bcpgIn.ReadByte();
+
+            s2k = new S2k(bcpgIn);
+
+            secKeyData = bcpgIn.ReadAll();
+        }
+
+		public SymmetricKeyEncSessionPacket(
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            S2k							s2k,
+            byte[]						secKeyData)
+        {
+            this.version = 4;
+            this.encAlgorithm = encAlgorithm;
+            this.s2k = s2k;
+            this.secKeyData = secKeyData;
+        }
+
+        /**
+        * @return int
+        */
+        public SymmetricKeyAlgorithmTag EncAlgorithm
+        {
+			get { return encAlgorithm; }
+        }
+
+        /**
+        * @return S2k
+        */
+        public S2k S2k
+        {
+			get { return s2k; }
+        }
+
+        /**
+        * @return byte[]
+        */
+        public byte[] GetSecKeyData()
+        {
+            return secKeyData;
+        }
+
+        /**
+        * @return int
+        */
+        public int Version
+        {
+			get { return version; }
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            MemoryStream bOut = new MemoryStream();
+            BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+            pOut.Write(
+				(byte) version,
+				(byte) encAlgorithm);
+
+			pOut.WriteObject(s2k);
+
+			if (secKeyData != null && secKeyData.Length > 0)
+			{
+                pOut.Write(secKeyData);
+            }
+
+			bcpgOut.WritePacket(PacketTag.SymmetricKeyEncryptedSessionKey, bOut.ToArray(), true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/TrustPacket.cs b/crypto/src/bcpg/TrustPacket.cs
new file mode 100644
index 000000000..6f1969c2a
--- /dev/null
+++ b/crypto/src/bcpg/TrustPacket.cs
@@ -0,0 +1,43 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <summary>Basic type for a trust packet.</summary>
+    public class TrustPacket
+        : ContainedPacket
+    {
+        private readonly byte[] levelAndTrustAmount;
+
+		public TrustPacket(
+            BcpgInputStream bcpgIn)
+        {
+            MemoryStream bOut = new MemoryStream();
+
+			int ch;
+            while ((ch = bcpgIn.ReadByte()) >= 0)
+            {
+                bOut.WriteByte((byte) ch);
+            }
+
+			levelAndTrustAmount = bOut.ToArray();
+        }
+
+		public TrustPacket(
+            int trustCode)
+        {
+			this.levelAndTrustAmount = new byte[]{ (byte) trustCode };
+        }
+
+		public byte[] GetLevelAndTrustAmount()
+		{
+			return (byte[]) levelAndTrustAmount.Clone();
+		}
+
+		public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.Trust, levelAndTrustAmount, true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/UserAttributePacket.cs b/crypto/src/bcpg/UserAttributePacket.cs
new file mode 100644
index 000000000..20e3598ab
--- /dev/null
+++ b/crypto/src/bcpg/UserAttributePacket.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic type for a user attribute packet.
+    */
+    public class UserAttributePacket
+        : ContainedPacket
+    {
+        private readonly UserAttributeSubpacket[] subpackets;
+
+        public UserAttributePacket(
+            BcpgInputStream bcpgIn)
+        {
+            UserAttributeSubpacketsParser sIn = new UserAttributeSubpacketsParser(bcpgIn);
+            UserAttributeSubpacket sub;
+
+            IList v = Platform.CreateArrayList();
+            while ((sub = sIn.ReadPacket()) != null)
+            {
+                v.Add(sub);
+            }
+
+            subpackets = new UserAttributeSubpacket[v.Count];
+
+            for (int i = 0; i != subpackets.Length; i++)
+            {
+                subpackets[i] = (UserAttributeSubpacket)v[i];
+            }
+        }
+
+        public UserAttributePacket(
+            UserAttributeSubpacket[] subpackets)
+        {
+            this.subpackets = subpackets;
+        }
+
+        public UserAttributeSubpacket[] GetSubpackets()
+        {
+            return subpackets;
+        }
+
+        public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            MemoryStream bOut = new MemoryStream();
+
+            for (int i = 0; i != subpackets.Length; i++)
+            {
+                subpackets[i].Encode(bOut);
+            }
+
+            bcpgOut.WritePacket(PacketTag.UserAttribute, bOut.ToArray(), false);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/UserAttributeSubpacket.cs b/crypto/src/bcpg/UserAttributeSubpacket.cs
index bd49d2150..05f60ac17 100644
--- a/crypto/src/bcpg/UserAttributeSubpacket.cs
+++ b/crypto/src/bcpg/UserAttributeSubpacket.cs
@@ -10,40 +10,44 @@ namespace Org.BouncyCastle.Bcpg
     */
     public class UserAttributeSubpacket
     {
-        private readonly UserAttributeSubpacketTag	type;
-        private readonly byte[]						data;
+        internal readonly UserAttributeSubpacketTag	type;
+        private readonly bool longLength;   // we preserve this as not everyone encodes length properly.
+        protected readonly byte[] data;
 
-		internal UserAttributeSubpacket(
-            UserAttributeSubpacketTag	type,
-            byte[]						data)
+        protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, byte[] data)
+            : this(type, false, data)
+        {
+        }
+
+        protected internal UserAttributeSubpacket(UserAttributeSubpacketTag type, bool forceLongLength, byte[] data)
         {
             this.type = type;
+            this.longLength = forceLongLength;
             this.data = data;
         }
 
-		public UserAttributeSubpacketTag SubpacketType
+        public virtual UserAttributeSubpacketTag SubpacketType
         {
             get { return type; }
         }
 
-		/**
+        /**
         * return the generic data making up the packet.
         */
-        public byte[] GetData()
+        public virtual byte[] GetData()
         {
             return data;
         }
 
-        public void Encode(
-            Stream os)
+        public virtual void Encode(Stream os)
         {
             int bodyLen = data.Length + 1;
 
-            if (bodyLen < 192)
+            if (bodyLen < 192 && !longLength)
             {
                 os.WriteByte((byte)bodyLen);
             }
-            else if (bodyLen <= 8383)
+            else if (bodyLen <= 8383 && !longLength)
             {
                 bodyLen -= 192;
 
@@ -69,18 +73,18 @@ namespace Org.BouncyCastle.Bcpg
             if (obj == this)
                 return true;
 
-			UserAttributeSubpacket other = obj as UserAttributeSubpacket;
+            UserAttributeSubpacket other = obj as UserAttributeSubpacket;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			return type == other.type
-				&& Arrays.AreEqual(data, other.data);
+            return type == other.type
+                && Arrays.AreEqual(data, other.data);
         }
 
-		public override int GetHashCode()
+        public override int GetHashCode()
         {
-			return type.GetHashCode() ^ Arrays.GetHashCode(data);
+            return type.GetHashCode() ^ Arrays.GetHashCode(data);
         }
     }
 }
diff --git a/crypto/src/bcpg/UserAttributeSubpacketTags.cs b/crypto/src/bcpg/UserAttributeSubpacketTags.cs
new file mode 100644
index 000000000..7a9cd1d5d
--- /dev/null
+++ b/crypto/src/bcpg/UserAttributeSubpacketTags.cs
@@ -0,0 +1,10 @@
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic PGP user attribute sub-packet tag types.
+    */
+    public enum UserAttributeSubpacketTag
+    {
+        ImageAttribute = 1
+    }
+}
diff --git a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
index 2e5ea0f3e..f0cc1b8e4 100644
--- a/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
+++ b/crypto/src/bcpg/UserAttributeSubpacketsReader.cs
@@ -5,59 +5,61 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Bcpg
 {
-	/**
-	* reader for user attribute sub-packets
-	*/
-	public class UserAttributeSubpacketsParser
-	{
-		private readonly Stream input;
+    /**
+    * reader for user attribute sub-packets
+    */
+    public class UserAttributeSubpacketsParser
+    {
+        private readonly Stream input;
 
-		public UserAttributeSubpacketsParser(
-			Stream input)
-		{
-			this.input = input;
-		}
+        public UserAttributeSubpacketsParser(
+            Stream input)
+        {
+            this.input = input;
+        }
 
-		public UserAttributeSubpacket ReadPacket()
-		{
-			int l = input.ReadByte();
-			if (l < 0)
-				return null;
+        public virtual UserAttributeSubpacket ReadPacket()
+        {
+            int l = input.ReadByte();
+            if (l < 0)
+                return null;
 
-			int bodyLen = 0;
-			if (l < 192)
-			{
-				bodyLen = l;
-			}
-			else if (l <= 223)
-			{
-				bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
-			}
-			else if (l == 255)
-			{
-				bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
-					|  (input.ReadByte() << 8)  | input.ReadByte();
-			}
-			else
-			{
-				// TODO Error?
-			}
+            int bodyLen = 0;
+            bool longLength = false;
+            if (l < 192)
+            {
+                bodyLen = l;
+            }
+            else if (l <= 223)
+            {
+                bodyLen = ((l - 192) << 8) + (input.ReadByte()) + 192;
+            }
+            else if (l == 255)
+            {
+                bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
+                    |  (input.ReadByte() << 8)  | input.ReadByte();
+                longLength = true;
+            }
+            else
+            {
+                throw new IOException("unrecognised length reading user attribute sub packet");
+            }
 
-			int tag = input.ReadByte();
-			if (tag < 0)
-				throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
+            int tag = input.ReadByte();
+            if (tag < 0)
+                throw new EndOfStreamException("unexpected EOF reading user attribute sub packet");
 
-			byte[] data = new byte[bodyLen - 1];
-			if (Streams.ReadFully(input, data) < data.Length)
-				throw new EndOfStreamException();
+            byte[] data = new byte[bodyLen - 1];
+            if (Streams.ReadFully(input, data) < data.Length)
+                throw new EndOfStreamException();
 
-			UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
-			switch (type)
-			{
-				case UserAttributeSubpacketTag.ImageAttribute:
-					return new ImageAttrib(data);
-			}
-			return new UserAttributeSubpacket(type, data);
-		}
-	}
+            UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
+            switch (type)
+            {
+                case UserAttributeSubpacketTag.ImageAttribute:
+                    return new ImageAttrib(longLength, data);
+            }
+            return new UserAttributeSubpacket(type, longLength, data);
+        }
+    }
 }
diff --git a/crypto/src/bcpg/UserIdPacket.cs b/crypto/src/bcpg/UserIdPacket.cs
new file mode 100644
index 000000000..a175e74a6
--- /dev/null
+++ b/crypto/src/bcpg/UserIdPacket.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic type for a user ID packet.
+    */
+    public class UserIdPacket
+        : ContainedPacket
+    {
+        private readonly byte[] idData;
+
+        public UserIdPacket(
+            BcpgInputStream bcpgIn)
+        {
+            this.idData = bcpgIn.ReadAll();
+        }
+
+		public UserIdPacket(
+			string id)
+        {
+            this.idData = Encoding.UTF8.GetBytes(id);
+        }
+
+		public string GetId()
+        {
+			return Encoding.UTF8.GetString(idData, 0, idData.Length);
+        }
+
+		public override void Encode(
+            BcpgOutputStream bcpgOut)
+        {
+            bcpgOut.WritePacket(PacketTag.UserId, idData, true);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/attr/ImageAttrib.cs b/crypto/src/bcpg/attr/ImageAttrib.cs
index 73490791c..2d0fef8b8 100644
--- a/crypto/src/bcpg/attr/ImageAttrib.cs
+++ b/crypto/src/bcpg/attr/ImageAttrib.cs
@@ -3,25 +3,29 @@ using System.IO;
 
 namespace Org.BouncyCastle.Bcpg.Attr
 {
-	/// <remarks>Basic type for a image attribute packet.</remarks>
+    /// <remarks>Basic type for a image attribute packet.</remarks>
     public class ImageAttrib
-		: UserAttributeSubpacket
+        : UserAttributeSubpacket
     {
-		public enum Format : byte
-		{
-			Jpeg = 1
-		}
+        public enum Format : byte
+        {
+            Jpeg = 1
+        }
 
-		private static readonly byte[] Zeroes = new byte[12];
+        private static readonly byte[] Zeroes = new byte[12];
 
-		private int     hdrLength;
+        private int     hdrLength;
         private int     _version;
         private int     _encoding;
         private byte[]  imageData;
 
-        public ImageAttrib(
-            byte[] data)
-            : base(UserAttributeSubpacketTag.ImageAttribute, data)
+        public ImageAttrib(byte[] data)
+            : this(false, data)
+        {
+        }
+
+        public ImageAttrib(bool forceLongLength, byte[] data)
+            : base(UserAttributeSubpacketTag.ImageAttribute, forceLongLength, data)
         {
             hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff);
             _version = data[2] & 0xff;
@@ -31,36 +35,36 @@ namespace Org.BouncyCastle.Bcpg.Attr
             Array.Copy(data, hdrLength, imageData, 0, imageData.Length);
         }
 
-		public ImageAttrib(
-			Format	imageType,
-			byte[]	imageData)
-			: this(ToByteArray(imageType, imageData))
-		{
-		}
+        public ImageAttrib(
+            Format	imageType,
+            byte[]	imageData)
+            : this(ToByteArray(imageType, imageData))
+        {
+        }
 
-		private static byte[] ToByteArray(
-			Format	imageType,
-			byte[]	imageData)
-		{
-			MemoryStream bOut = new MemoryStream();
-			bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
-			bOut.WriteByte((byte) imageType);
-			bOut.Write(Zeroes, 0, Zeroes.Length);
-			bOut.Write(imageData, 0, imageData.Length);
-			return bOut.ToArray();
-		}
+        private static byte[] ToByteArray(
+            Format	imageType,
+            byte[]	imageData)
+        {
+            MemoryStream bOut = new MemoryStream();
+            bOut.WriteByte(0x10); bOut.WriteByte(0x00); bOut.WriteByte(0x01);
+            bOut.WriteByte((byte) imageType);
+            bOut.Write(Zeroes, 0, Zeroes.Length);
+            bOut.Write(imageData, 0, imageData.Length);
+            return bOut.ToArray();
+        }
 
-		public int Version
+        public virtual int Version
         {
-			get { return _version; }
+            get { return _version; }
         }
 
-        public int Encoding
+        public virtual int Encoding
         {
-			get { return _encoding; }
+            get { return _encoding; }
         }
 
-		public byte[] GetImageData()
+        public virtual byte[] GetImageData()
         {
             return imageData;
         }
diff --git a/crypto/src/bcpg/sig/EmbeddedSignature.cs b/crypto/src/bcpg/sig/EmbeddedSignature.cs
new file mode 100644
index 000000000..e47604ac8
--- /dev/null
+++ b/crypto/src/bcpg/sig/EmbeddedSignature.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+	/**
+	 * Packet embedded signature
+	 */
+	public class EmbeddedSignature
+		: SignatureSubpacket
+	{
+		public EmbeddedSignature(
+			bool	critical,
+			byte[]	data)
+			: base(SignatureSubpacketTag.EmbeddedSignature, critical, data)
+		{
+		}
+	}
+}
diff --git a/crypto/src/bcpg/sig/Exportable.cs b/crypto/src/bcpg/sig/Exportable.cs
new file mode 100644
index 000000000..4455c3814
--- /dev/null
+++ b/crypto/src/bcpg/sig/Exportable.cs
@@ -0,0 +1,47 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving signature creation time.
+    */
+    public class Exportable
+        : SignatureSubpacket
+    {
+        private static byte[] BooleanToByteArray(bool val)
+        {
+            byte[]    data = new byte[1];
+
+            if (val)
+            {
+                data[0] = 1;
+                return data;
+            }
+            else
+            {
+                return data;
+            }
+        }
+
+        public Exportable(
+            bool    critical,
+            byte[]     data)
+            : base(SignatureSubpacketTag.Exportable, critical, data)
+        {
+        }
+
+        public Exportable(
+            bool    critical,
+            bool    isExportable)
+            : base(SignatureSubpacketTag.Exportable, critical, BooleanToByteArray(isExportable))
+        {
+        }
+
+        public bool IsExportable()
+        {
+            return data[0] != 0;
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/IssuerKeyId.cs b/crypto/src/bcpg/sig/IssuerKeyId.cs
new file mode 100644
index 000000000..91490d33b
--- /dev/null
+++ b/crypto/src/bcpg/sig/IssuerKeyId.cs
@@ -0,0 +1,61 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving signature creation time.
+    */
+    public class IssuerKeyId
+        : SignatureSubpacket
+    {
+        protected static byte[] KeyIdToBytes(
+            long    keyId)
+        {
+            byte[]    data = new byte[8];
+
+            data[0] = (byte)(keyId >> 56);
+            data[1] = (byte)(keyId >> 48);
+            data[2] = (byte)(keyId >> 40);
+            data[3] = (byte)(keyId >> 32);
+            data[4] = (byte)(keyId >> 24);
+            data[5] = (byte)(keyId >> 16);
+            data[6] = (byte)(keyId >> 8);
+            data[7] = (byte)keyId;
+
+            return data;
+        }
+
+        public IssuerKeyId(
+            bool    critical,
+            byte[]     data)
+            : base(SignatureSubpacketTag.IssuerKeyId, critical, data)
+        {
+        }
+
+        public IssuerKeyId(
+            bool    critical,
+            long       keyId)
+            : base(SignatureSubpacketTag.IssuerKeyId, critical, KeyIdToBytes(keyId))
+        {
+        }
+
+        public long KeyId
+        {
+			get
+			{
+				long keyId = ((long)(data[0] & 0xff) << 56)
+					| ((long)(data[1] & 0xff) << 48)
+					| ((long)(data[2] & 0xff) << 40)
+					| ((long)(data[3] & 0xff) << 32)
+					| ((long)(data[4] & 0xff) << 24)
+					| ((long)(data[5] & 0xff) << 16)
+					| ((long)(data[6] & 0xff) << 8)
+					| ((long)data[7] & 0xff);
+
+				return keyId;
+			}
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/KeyExpirationTime.cs b/crypto/src/bcpg/sig/KeyExpirationTime.cs
new file mode 100644
index 000000000..23b4cac29
--- /dev/null
+++ b/crypto/src/bcpg/sig/KeyExpirationTime.cs
@@ -0,0 +1,56 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving time after creation at which the key expires.
+    */
+    public class KeyExpirationTime
+        : SignatureSubpacket
+    {
+        protected static byte[] TimeToBytes(
+            long    t)
+        {
+            byte[]    data = new byte[4];
+
+            data[0] = (byte)(t >> 24);
+            data[1] = (byte)(t >> 16);
+            data[2] = (byte)(t >> 8);
+            data[3] = (byte)t;
+
+            return data;
+        }
+
+        public KeyExpirationTime(
+            bool    critical,
+            byte[]     data)
+            : base(SignatureSubpacketTag.KeyExpireTime, critical, data)
+        {
+        }
+
+        public KeyExpirationTime(
+            bool    critical,
+            long       seconds)
+            : base(SignatureSubpacketTag.KeyExpireTime, critical, TimeToBytes(seconds))
+        {
+        }
+
+        /**
+        * Return the number of seconds after creation time a key is valid for.
+        *
+        * @return second count for key validity.
+        */
+        public long Time
+        {
+			get
+			{
+				long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
+					| ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
+
+				return time;
+			}
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/KeyFlags.cs b/crypto/src/bcpg/sig/KeyFlags.cs
new file mode 100644
index 000000000..0592301b3
--- /dev/null
+++ b/crypto/src/bcpg/sig/KeyFlags.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * Packet holding the key flag values.
+    */
+    public class KeyFlags
+        : SignatureSubpacket
+    {
+		public const int CertifyOther	= 0x01;
+		public const int SignData		= 0x02;
+		public const int EncryptComms	= 0x04;
+		public const int EncryptStorage	= 0x08;
+		public const int Split			= 0x10;
+		public const int Authentication	= 0x20;
+		public const int Shared			= 0x80;
+
+        private static byte[] IntToByteArray(
+            int v)
+        {
+			byte[] tmp = new byte[4];
+			int size = 0;
+
+			for (int i = 0; i != 4; i++)
+			{
+				tmp[i] = (byte)(v >> (i * 8));
+				if (tmp[i] != 0)
+				{
+					size = i;
+				}
+			}
+
+			byte[] data = new byte[size + 1];
+			Array.Copy(tmp, 0, data, 0, data.Length);
+			return data;
+		}
+
+		public KeyFlags(
+            bool	critical,
+            byte[]	data)
+            : base(SignatureSubpacketTag.KeyFlags, critical, data)
+        {
+        }
+
+		public KeyFlags(
+			bool	critical,
+			int		flags)
+            : base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags))
+        {
+        }
+
+		/// <summary>
+		/// Return the flag values contained in the first 4 octets (note: at the moment
+		/// the standard only uses the first one).
+		/// </summary>
+		public int Flags
+        {
+			get
+			{
+				int flags = 0;
+
+				for (int i = 0; i != data.Length; i++)
+				{
+					flags |= (data[i] & 0xff) << (i * 8);
+				}
+
+				return flags;
+			}
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/NotationData.cs b/crypto/src/bcpg/sig/NotationData.cs
new file mode 100644
index 000000000..ccc9aa745
--- /dev/null
+++ b/crypto/src/bcpg/sig/NotationData.cs
@@ -0,0 +1,112 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+	/**
+	* Class provided a NotationData object according to
+	* RFC2440, Chapter 5.2.3.15. Notation Data
+	*/
+	public class NotationData
+		: SignatureSubpacket
+	{
+		public const int HeaderFlagLength = 4;
+		public const int HeaderNameLength = 2;
+		public const int HeaderValueLength = 2;
+
+		public NotationData(
+			bool	critical,
+			byte[]	data)
+			: base(SignatureSubpacketTag.NotationData, critical, data)
+		{
+		}
+
+		public NotationData(
+			bool	critical,
+			bool	humanReadable,
+			string	notationName,
+			string	notationValue)
+			: base(SignatureSubpacketTag.NotationData, critical,
+				createData(humanReadable, notationName, notationValue))
+		{
+		}
+
+		private static byte[] createData(
+			bool	humanReadable,
+			string	notationName,
+			string	notationValue)
+		{
+			MemoryStream os = new MemoryStream();
+
+			// (4 octets of flags, 2 octets of name length (M),
+			// 2 octets of value length (N),
+			// M octets of name data,
+			// N octets of value data)
+
+			// flags
+			os.WriteByte(humanReadable ? (byte)0x80 : (byte)0x00);
+			os.WriteByte(0x0);
+			os.WriteByte(0x0);
+			os.WriteByte(0x0);
+
+			byte[] nameData, valueData = null;
+			int nameLength, valueLength;
+
+			nameData = Encoding.UTF8.GetBytes(notationName);
+			nameLength = System.Math.Min(nameData.Length, 0xFF);
+
+			valueData = Encoding.UTF8.GetBytes(notationValue);
+			valueLength = System.Math.Min(valueData.Length, 0xFF);
+
+			// name length
+			os.WriteByte((byte)(nameLength >> 8));
+			os.WriteByte((byte)(nameLength >> 0));
+
+			// value length
+			os.WriteByte((byte)(valueLength >> 8));
+			os.WriteByte((byte)(valueLength >> 0));
+
+			// name
+			os.Write(nameData, 0, nameLength);
+
+			// value
+			os.Write(valueData, 0, valueLength);
+
+			return os.ToArray();
+		}
+
+		public bool IsHumanReadable
+		{
+			get { return data[0] == (byte)0x80; }
+		}
+
+		public string GetNotationName()
+		{
+			int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
+			int namePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength;
+
+			return Encoding.UTF8.GetString(data, namePos, nameLength);
+		}
+
+		public string GetNotationValue()
+		{
+			int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
+			int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0));
+			int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength;
+
+			return Encoding.UTF8.GetString(data, valuePos, valueLength);
+		}
+
+		public byte[] GetNotationValueBytes()
+		{
+			int nameLength = ((data[HeaderFlagLength] << 8) + (data[HeaderFlagLength + 1] << 0));
+			int valueLength = ((data[HeaderFlagLength + HeaderNameLength] << 8) + (data[HeaderFlagLength + HeaderNameLength + 1] << 0));
+			int valuePos = HeaderFlagLength + HeaderNameLength + HeaderValueLength + nameLength;
+
+			byte[] bytes = new byte[valueLength];
+			Array.Copy(data, valuePos, bytes, 0, valueLength);
+			return bytes;
+		}
+	}
+}
diff --git a/crypto/src/bcpg/sig/PreferredAlgorithms.cs b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
new file mode 100644
index 000000000..0f282a38c
--- /dev/null
+++ b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
@@ -0,0 +1,54 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving signature creation time.
+    */
+    public class PreferredAlgorithms
+        : SignatureSubpacket
+    {
+        private static byte[] IntToByteArray(
+            int[]    v)
+        {
+            byte[]    data = new byte[v.Length];
+
+            for (int i = 0; i != v.Length; i++)
+            {
+                data[i] = (byte)v[i];
+            }
+
+            return data;
+        }
+
+        public PreferredAlgorithms(
+            SignatureSubpacketTag        type,
+            bool    critical,
+            byte[]     data)
+            : base(type, critical, data)
+        {
+        }
+
+        public PreferredAlgorithms(
+            SignatureSubpacketTag        type,
+            bool    critical,
+            int[]      preferences)
+            : base(type, critical, IntToByteArray(preferences))
+        {
+        }
+
+        public int[] GetPreferences()
+        {
+            int[]    v = new int[data.Length];
+
+            for (int i = 0; i != v.Length; i++)
+            {
+                v[i] = data[i] & 0xff;
+            }
+
+            return v;
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/PrimaryUserId.cs b/crypto/src/bcpg/sig/PrimaryUserId.cs
new file mode 100644
index 000000000..fc0353afd
--- /dev/null
+++ b/crypto/src/bcpg/sig/PrimaryUserId.cs
@@ -0,0 +1,48 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving whether or not the signature is signed using the primary user ID for the key.
+    */
+    public class PrimaryUserId
+        : SignatureSubpacket
+    {
+        private static byte[] BooleanToByteArray(
+            bool    val)
+        {
+            byte[]    data = new byte[1];
+
+            if (val)
+            {
+                data[0] = 1;
+                return data;
+            }
+            else
+            {
+                return data;
+            }
+        }
+
+        public PrimaryUserId(
+            bool    critical,
+            byte[]     data)
+            : base(SignatureSubpacketTag.PrimaryUserId, critical, data)
+        {
+        }
+
+        public PrimaryUserId(
+            bool    critical,
+            bool    isPrimaryUserId)
+            : base(SignatureSubpacketTag.PrimaryUserId, critical, BooleanToByteArray(isPrimaryUserId))
+        {
+        }
+
+        public bool IsPrimaryUserId()
+        {
+            return data[0] != 0;
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/Revocable.cs b/crypto/src/bcpg/sig/Revocable.cs
new file mode 100644
index 000000000..b5e94feec
--- /dev/null
+++ b/crypto/src/bcpg/sig/Revocable.cs
@@ -0,0 +1,48 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving whether or not is revocable.
+    */
+    public class Revocable
+        : SignatureSubpacket
+    {
+        private static byte[] BooleanToByteArray(
+            bool    value)
+        {
+            byte[]    data = new byte[1];
+
+            if (value)
+            {
+                data[0] = 1;
+                return data;
+            }
+            else
+            {
+                return data;
+            }
+        }
+
+        public Revocable(
+            bool    critical,
+            byte[]     data)
+            : base(SignatureSubpacketTag.Revocable, critical, data)
+    {
+        }
+
+        public Revocable(
+            bool    critical,
+            bool    isRevocable)
+            : base(SignatureSubpacketTag.Revocable, critical, BooleanToByteArray(isRevocable))
+    {
+        }
+
+        public bool IsRevocable()
+        {
+            return data[0] != 0;
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/RevocationKey.cs b/crypto/src/bcpg/sig/RevocationKey.cs
index 5e388246b..66982cb5a 100644
--- a/crypto/src/bcpg/sig/RevocationKey.cs
+++ b/crypto/src/bcpg/sig/RevocationKey.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Collections.Generic;
 using System.Text;
 
 namespace Org.BouncyCastle.Bcpg
diff --git a/crypto/src/bcpg/sig/RevocationKeyTags.cs b/crypto/src/bcpg/sig/RevocationKeyTags.cs
new file mode 100644
index 000000000..d76d1dcf4
--- /dev/null
+++ b/crypto/src/bcpg/sig/RevocationKeyTags.cs
@@ -0,0 +1,9 @@
+namespace Org.BouncyCastle.Bcpg
+{
+    public enum RevocationKeyTag
+		: byte
+    {
+		ClassDefault = 0x80,
+		ClassSensitive = 0x40
+	}
+}
diff --git a/crypto/src/bcpg/sig/RevocationReason.cs b/crypto/src/bcpg/sig/RevocationReason.cs
index f32c1f64a..98e9b0a3d 100644
--- a/crypto/src/bcpg/sig/RevocationReason.cs
+++ b/crypto/src/bcpg/sig/RevocationReason.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Collections.Generic;
 using System.Text;
 
 using Org.BouncyCastle.Utilities;
diff --git a/crypto/src/bcpg/sig/RevocationReasonTags.cs b/crypto/src/bcpg/sig/RevocationReasonTags.cs
new file mode 100644
index 000000000..524a58c49
--- /dev/null
+++ b/crypto/src/bcpg/sig/RevocationReasonTags.cs
@@ -0,0 +1,14 @@
+namespace Org.BouncyCastle.Bcpg
+{
+    public enum RevocationReasonTag
+		: byte
+    {
+		NoReason = 0,					// No reason specified (key revocations or cert revocations)
+		KeySuperseded = 1,				// Key is superseded (key revocations)
+		KeyCompromised = 2,				// Key material has been compromised (key revocations)
+		KeyRetired = 3,					// Key is retired and no longer used (key revocations)
+		UserNoLongerValid = 32,			// User ID information is no longer valid (cert revocations)
+
+		// 100-110 - Private Use
+	}
+}
diff --git a/crypto/src/bcpg/sig/SignatureCreationTime.cs b/crypto/src/bcpg/sig/SignatureCreationTime.cs
new file mode 100644
index 000000000..e6f241f11
--- /dev/null
+++ b/crypto/src/bcpg/sig/SignatureCreationTime.cs
@@ -0,0 +1,47 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving signature creation time.
+    */
+    public class SignatureCreationTime
+        : SignatureSubpacket
+    {
+		protected static byte[] TimeToBytes(
+            DateTime time)
+        {
+			long t = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
+			byte[] data = new byte[4];
+			data[0] = (byte)(t >> 24);
+            data[1] = (byte)(t >> 16);
+            data[2] = (byte)(t >> 8);
+            data[3] = (byte)t;
+            return data;
+        }
+        public SignatureCreationTime(
+            bool	critical,
+            byte[]	data)
+            : base(SignatureSubpacketTag.CreationTime, critical, data)
+        {
+        }
+        public SignatureCreationTime(
+            bool		critical,
+            DateTime	date)
+            : base(SignatureSubpacketTag.CreationTime, critical, TimeToBytes(date))
+        {
+        }
+        public DateTime GetTime()
+        {
+			long time = (long)(
+					((uint)data[0] << 24)
+				|	((uint)data[1] << 16)
+				|	((uint)data[2] << 8)
+				|	((uint)data[3])
+				);
+			return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/SignatureExpirationTime.cs b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
new file mode 100644
index 000000000..7fddf5743
--- /dev/null
+++ b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
@@ -0,0 +1,54 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving signature expiration time.
+    */
+    public class SignatureExpirationTime
+        : SignatureSubpacket
+    {
+        protected static byte[] TimeToBytes(
+            long      t)
+        {
+            byte[]    data = new byte[4];
+
+            data[0] = (byte)(t >> 24);
+            data[1] = (byte)(t >> 16);
+            data[2] = (byte)(t >> 8);
+            data[3] = (byte)t;
+
+            return data;
+        }
+
+        public SignatureExpirationTime(
+            bool    critical,
+            byte[]     data)
+            : base(SignatureSubpacketTag.ExpireTime, critical, data)
+    {
+        }
+
+        public SignatureExpirationTime(
+            bool    critical,
+            long       seconds)
+            : base(SignatureSubpacketTag.ExpireTime, critical, TimeToBytes(seconds))
+        {
+        }
+
+        /**
+        * return time in seconds before signature expires after creation time.
+        */
+        public long Time
+        {
+            get
+            {
+                long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
+                    | ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
+
+                return time;
+            }
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/SignerUserId.cs b/crypto/src/bcpg/sig/SignerUserId.cs
new file mode 100644
index 000000000..98cc808e7
--- /dev/null
+++ b/crypto/src/bcpg/sig/SignerUserId.cs
@@ -0,0 +1,52 @@
+using System;
+
+
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving the User ID of the signer.
+    */
+    public class SignerUserId
+        : SignatureSubpacket
+    {
+        private static byte[] UserIdToBytes(
+            string id)
+        {
+            byte[] idData = new byte[id.Length];
+
+            for (int i = 0; i != id.Length; i++)
+            {
+                idData[i] = (byte)id[i];
+            }
+
+			return idData;
+        }
+
+        public SignerUserId(
+            bool	critical,
+            byte[]	data)
+            : base(SignatureSubpacketTag.SignerUserId, critical, data)
+		{
+		}
+
+		public SignerUserId(
+            bool	critical,
+            string	userId)
+            : base(SignatureSubpacketTag.SignerUserId, critical, UserIdToBytes(userId))
+		{
+        }
+
+		public string GetId()
+        {
+            char[] chars = new char[data.Length];
+
+			for (int i = 0; i != chars.Length; i++)
+            {
+                chars[i] = (char)(data[i] & 0xff);
+            }
+
+			return new string(chars);
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/TrustSignature.cs b/crypto/src/bcpg/sig/TrustSignature.cs
new file mode 100644
index 000000000..bbadd3067
--- /dev/null
+++ b/crypto/src/bcpg/sig/TrustSignature.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving trust.
+    */
+    public class TrustSignature
+        : SignatureSubpacket
+    {
+        private static byte[] IntToByteArray(
+            int	v1,
+            int	v2)
+        {
+			return new byte[]{ (byte)v1, (byte)v2 };
+        }
+
+		public TrustSignature(
+            bool	critical,
+            byte[]	data)
+            : base(SignatureSubpacketTag.TrustSig, critical, data)
+        {
+        }
+
+        public TrustSignature(
+            bool	critical,
+            int		depth,
+            int		trustAmount)
+            : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount))
+        {
+        }
+
+        public int Depth
+        {
+			get { return data[0] & 0xff; }
+        }
+
+        public int TrustAmount
+        {
+			get { return data[1] & 0xff; }
+        }
+    }
+}
diff --git a/crypto/src/cms/BaseDigestCalculator.cs b/crypto/src/cms/BaseDigestCalculator.cs
new file mode 100644
index 000000000..3dcbca753
--- /dev/null
+++ b/crypto/src/cms/BaseDigestCalculator.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class BaseDigestCalculator
+		: IDigestCalculator
+	{
+		private readonly byte[] digest;
+
+		internal BaseDigestCalculator(
+			byte[] digest)
+		{
+			this.digest = digest;
+		}
+
+		public byte[] GetDigest()
+		{
+			return Arrays.Clone(digest);
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSAttributeTableGenerationException.cs b/crypto/src/cms/CMSAttributeTableGenerationException.cs
index 2bc8ce5d1..31b06d6dd 100644
--- a/crypto/src/cms/CMSAttributeTableGenerationException.cs
+++ b/crypto/src/cms/CMSAttributeTableGenerationException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Cms
 {
-	public class CmsAttributeTableGenerationException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CmsAttributeTableGenerationException
 		: CmsException
 	{
 		public CmsAttributeTableGenerationException()
diff --git a/crypto/src/cms/CMSAttributeTableGenerator.cs b/crypto/src/cms/CMSAttributeTableGenerator.cs
new file mode 100644
index 000000000..92c9a29d9
--- /dev/null
+++ b/crypto/src/cms/CMSAttributeTableGenerator.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Cms
+{
+	/// <remarks>
+	/// The 'Signature' parameter is only available when generating unsigned attributes.
+	/// </remarks>
+	public enum CmsAttributeTableParameter
+	{
+//		const string ContentType = "contentType";
+//		const string Digest = "digest";
+//		const string Signature = "encryptedDigest";
+//		const string DigestAlgorithmIdentifier = "digestAlgID";
+
+		ContentType, Digest, Signature, DigestAlgorithmIdentifier
+	}
+
+	public interface CmsAttributeTableGenerator
+	{
+		AttributeTable GetAttributes(IDictionary parameters);
+	}
+}
diff --git a/crypto/src/cms/CMSAuthEnvelopedData.cs b/crypto/src/cms/CMSAuthEnvelopedData.cs
new file mode 100644
index 000000000..d35e946ae
--- /dev/null
+++ b/crypto/src/cms/CMSAuthEnvelopedData.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* containing class for an CMS AuthEnveloped Data object
+	*/
+	internal class CmsAuthEnvelopedData
+	{
+		internal RecipientInformationStore recipientInfoStore;
+		internal ContentInfo contentInfo;
+
+		private OriginatorInfo      originator;
+		private AlgorithmIdentifier authEncAlg;
+		private Asn1Set             authAttrs;
+		private byte[]              mac;
+		private Asn1Set             unauthAttrs;
+	
+		public CmsAuthEnvelopedData(
+			byte[] authEnvData)
+			: this(CmsUtilities.ReadContentInfo(authEnvData))
+		{
+		}
+
+		public CmsAuthEnvelopedData(
+			Stream authEnvData)
+			: this(CmsUtilities.ReadContentInfo(authEnvData))
+		{
+		}
+
+		public CmsAuthEnvelopedData(
+			ContentInfo contentInfo)
+		{
+			this.contentInfo = contentInfo;
+
+			AuthEnvelopedData authEnvData = AuthEnvelopedData.GetInstance(contentInfo.Content);
+
+			this.originator = authEnvData.OriginatorInfo;
+
+			//
+	        // read the recipients
+	        //
+	        Asn1Set recipientInfos = authEnvData.RecipientInfos;
+
+			//
+			// read the auth-encrypted content info
+			//
+			EncryptedContentInfo authEncInfo = authEnvData.AuthEncryptedContentInfo;
+			this.authEncAlg = authEncInfo.ContentEncryptionAlgorithm;
+			CmsSecureReadable secureReadable = new AuthEnvelopedSecureReadable(this);
+
+			//
+			// build the RecipientInformationStore
+			//
+			this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+				recipientInfos, secureReadable);
+
+			// FIXME These need to be passed to the AEAD cipher as AAD (Additional Authenticated Data)
+			this.authAttrs = authEnvData.AuthAttrs;
+			this.mac = authEnvData.Mac.GetOctets();
+			this.unauthAttrs = authEnvData.UnauthAttrs;
+		}
+
+		private class AuthEnvelopedSecureReadable : CmsSecureReadable
+		{
+			private readonly CmsAuthEnvelopedData parent;
+
+			internal AuthEnvelopedSecureReadable(CmsAuthEnvelopedData parent)
+			{
+				this.parent = parent;
+			}
+
+			public AlgorithmIdentifier Algorithm
+			{
+				get { return parent.authEncAlg; }
+			}
+
+			public object CryptoObject
+			{
+				get { return null; }
+			}
+
+			public CmsReadable GetReadable(KeyParameter key)
+			{
+				// TODO Create AEAD cipher instance to decrypt and calculate tag ( MAC)
+				throw new CmsException("AuthEnveloped data decryption not yet implemented");
+
+//				RFC 5084 ASN.1 Module
+//				-- Parameters for AlgorithmIdentifier
+//				
+//				CCMParameters ::= SEQUENCE {
+//				  aes-nonce         OCTET STRING (SIZE(7..13)),
+//				  aes-ICVlen        AES-CCM-ICVlen DEFAULT 12 }
+//				
+//				AES-CCM-ICVlen ::= INTEGER (4 | 6 | 8 | 10 | 12 | 14 | 16)
+//				
+//				GCMParameters ::= SEQUENCE {
+//				  aes-nonce        OCTET STRING, -- recommended size is 12 octets
+//				  aes-ICVlen       AES-GCM-ICVlen DEFAULT 12 }
+//				
+//				AES-GCM-ICVlen ::= INTEGER (12 | 13 | 14 | 15 | 16)
+			}            
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSAuthEnvelopedGenerator.cs b/crypto/src/cms/CMSAuthEnvelopedGenerator.cs
new file mode 100644
index 000000000..4273cff29
--- /dev/null
+++ b/crypto/src/cms/CMSAuthEnvelopedGenerator.cs
@@ -0,0 +1,16 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Nist;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class CmsAuthEnvelopedGenerator
+	{
+		public static readonly string Aes128Ccm = NistObjectIdentifiers.IdAes128Ccm.Id;
+		public static readonly string Aes192Ccm = NistObjectIdentifiers.IdAes192Ccm.Id;
+		public static readonly string Aes256Ccm = NistObjectIdentifiers.IdAes256Ccm.Id;
+		public static readonly string Aes128Gcm = NistObjectIdentifiers.IdAes128Gcm.Id;
+		public static readonly string Aes192Gcm = NistObjectIdentifiers.IdAes192Gcm.Id;
+		public static readonly string Aes256Gcm = NistObjectIdentifiers.IdAes256Gcm.Id;
+	}
+}
diff --git a/crypto/src/cms/CMSAuthenticatedData.cs b/crypto/src/cms/CMSAuthenticatedData.cs
new file mode 100644
index 000000000..5e234da2b
--- /dev/null
+++ b/crypto/src/cms/CMSAuthenticatedData.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* containing class for an CMS Authenticated Data object
+	*/
+	public class CmsAuthenticatedData
+	{
+		internal RecipientInformationStore recipientInfoStore;
+		internal ContentInfo contentInfo;
+
+		private AlgorithmIdentifier macAlg;
+		private Asn1Set authAttrs;
+		private Asn1Set unauthAttrs;
+		private byte[] mac;
+
+		public CmsAuthenticatedData(
+			byte[] authData)
+			: this(CmsUtilities.ReadContentInfo(authData))
+		{
+		}
+
+		public CmsAuthenticatedData(
+			Stream authData)
+			: this(CmsUtilities.ReadContentInfo(authData))
+		{
+		}
+
+		public CmsAuthenticatedData(
+			ContentInfo contentInfo)
+		{
+			this.contentInfo = contentInfo;
+
+			AuthenticatedData authData = AuthenticatedData.GetInstance(contentInfo.Content);
+
+			//
+			// read the recipients
+			//
+			Asn1Set recipientInfos = authData.RecipientInfos;
+
+			this.macAlg = authData.MacAlgorithm;
+
+			//
+			// read the authenticated content info
+			//
+			ContentInfo encInfo = authData.EncapsulatedContentInfo;
+			CmsReadable readable = new CmsProcessableByteArray(
+				Asn1OctetString.GetInstance(encInfo.Content).GetOctets());
+			CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsAuthenticatedSecureReadable(
+				this.macAlg, readable);
+
+			//
+			// build the RecipientInformationStore
+			//
+			this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+				recipientInfos, secureReadable);
+
+			this.authAttrs = authData.AuthAttrs;
+			this.mac = authData.Mac.GetOctets();
+			this.unauthAttrs = authData.UnauthAttrs;
+		}
+
+		public byte[] GetMac()
+		{
+			return Arrays.Clone(mac);
+		}
+
+		public AlgorithmIdentifier MacAlgorithmID
+		{
+			get { return macAlg; }
+		}
+
+		/**
+		* return the object identifier for the content MAC algorithm.
+		*/
+		public string MacAlgOid
+		{
+			get { return macAlg.ObjectID.Id; }
+		}
+
+		/**
+		* return a store of the intended recipients for this message
+		*/
+		public RecipientInformationStore GetRecipientInfos()
+		{
+			return recipientInfoStore;
+		}
+
+		/**
+		 * return the ContentInfo 
+		 */
+		public ContentInfo ContentInfo
+		{
+			get { return contentInfo; }
+		}
+
+		/**
+		* return a table of the digested attributes indexed by
+		* the OID of the attribute.
+		*/
+		public Asn1.Cms.AttributeTable GetAuthAttrs()
+		{
+			if (authAttrs == null)
+				return null;
+
+			return new Asn1.Cms.AttributeTable(authAttrs);
+		}
+
+		/**
+		* return a table of the undigested attributes indexed by
+		* the OID of the attribute.
+		*/
+		public Asn1.Cms.AttributeTable GetUnauthAttrs()
+		{
+			if (unauthAttrs == null)
+				return null;
+
+			return new Asn1.Cms.AttributeTable(unauthAttrs);
+		}
+
+		/**
+		* return the ASN.1 encoded representation of this object.
+		*/
+		public byte[] GetEncoded()
+		{
+			return contentInfo.GetEncoded();
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSAuthenticatedDataGenerator.cs b/crypto/src/cms/CMSAuthenticatedDataGenerator.cs
index 0a37ca4f5..846c19a24 100644
--- a/crypto/src/cms/CMSAuthenticatedDataGenerator.cs
+++ b/crypto/src/cms/CMSAuthenticatedDataGenerator.cs
@@ -83,8 +83,8 @@ namespace Org.BouncyCastle.Cms
 
 				content.Write(mOut);
 
-                mOut.Dispose();
-                bOut.Dispose();
+				mOut.Close();
+				bOut.Close();
 
 				encContent = new BerOctetString(bOut.ToArray());
 
diff --git a/crypto/src/cms/CMSAuthenticatedDataParser.cs b/crypto/src/cms/CMSAuthenticatedDataParser.cs
new file mode 100644
index 000000000..c99aac61c
--- /dev/null
+++ b/crypto/src/cms/CMSAuthenticatedDataParser.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* Parsing class for an CMS Authenticated Data object from an input stream.
+	* <p>
+	* Note: that because we are in a streaming mode only one recipient can be tried and it is important
+	* that the methods on the parser are called in the appropriate order.
+	* </p>
+	* <p>
+	* Example of use - assuming the first recipient matches the private key we have.
+	* <pre>
+	*      CMSAuthenticatedDataParser     ad = new CMSAuthenticatedDataParser(inputStream);
+	*
+	*      RecipientInformationStore  recipients = ad.getRecipientInfos();
+	*
+	*      Collection  c = recipients.getRecipients();
+	*      Iterator    it = c.iterator();
+	*
+	*      if (it.hasNext())
+	*      {
+	*          RecipientInformation   recipient = (RecipientInformation)it.next();
+	*
+	*          CMSTypedStream recData = recipient.getContentStream(privateKey, "BC");
+	*
+	*          processDataStream(recData.getContentStream());
+	*
+	*          if (!Arrays.equals(ad.getMac(), recipient.getMac())
+	*          {
+	*              System.err.println("Data corrupted!!!!");
+	*          }
+	*      }
+	*  </pre>
+	*  Note: this class does not introduce buffering - if you are processing large files you should create
+	*  the parser with:
+	*  <pre>
+	*          CMSAuthenticatedDataParser     ep = new CMSAuthenticatedDataParser(new BufferedInputStream(inputStream, bufSize));
+	*  </pre>
+	*  where bufSize is a suitably large buffer size.
+	* </p>
+	*/
+	public class CmsAuthenticatedDataParser
+		: CmsContentInfoParser
+	{
+		internal RecipientInformationStore	_recipientInfoStore;
+		internal AuthenticatedDataParser	authData;
+
+		private AlgorithmIdentifier			macAlg;
+		private byte[]						mac;
+		private Asn1.Cms.AttributeTable		authAttrs;
+		private Asn1.Cms.AttributeTable		unauthAttrs;
+
+		private bool authAttrNotRead;
+		private bool unauthAttrNotRead;
+
+		public CmsAuthenticatedDataParser(
+			byte[] envelopedData)
+			: this(new MemoryStream(envelopedData, false))
+		{
+		}
+
+		public CmsAuthenticatedDataParser(
+			Stream envelopedData)
+			: base(envelopedData)
+		{
+			this.authAttrNotRead = true;
+			this.authData = new AuthenticatedDataParser(
+				(Asn1SequenceParser)contentInfo.GetContent(Asn1Tags.Sequence));
+
+			// TODO Validate version?
+			//DerInteger version = this.authData.getVersion();
+
+			//
+			// read the recipients
+			//
+			Asn1Set recipientInfos = Asn1Set.GetInstance(authData.GetRecipientInfos().ToAsn1Object());
+
+			this.macAlg = authData.GetMacAlgorithm();
+
+			//
+			// read the authenticated content info
+			//
+			ContentInfoParser data = authData.GetEnapsulatedContentInfo();
+			CmsReadable readable = new CmsProcessableInputStream(
+				((Asn1OctetStringParser)data.GetContent(Asn1Tags.OctetString)).GetOctetStream());
+			CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsAuthenticatedSecureReadable(
+				this.macAlg, readable);
+
+			//
+			// build the RecipientInformationStore
+			//
+			this._recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+				recipientInfos, secureReadable);
+		}
+
+		public AlgorithmIdentifier MacAlgorithmID
+		{
+			get { return macAlg; }
+		}
+
+		/**
+		* return the object identifier for the mac algorithm.
+		*/
+		public string MacAlgOid
+		{
+			get { return macAlg.ObjectID.Id; }
+		}
+
+
+		/**
+		 * return the ASN.1 encoded encryption algorithm parameters, or null if
+		 * there aren't any.
+		 */
+		public Asn1Object MacAlgParams
+		{
+			get
+			{
+				Asn1Encodable ae = macAlg.Parameters;
+
+				return ae == null ? null : ae.ToAsn1Object();
+			}
+		}
+
+		/**
+		* return a store of the intended recipients for this message
+		*/
+		public RecipientInformationStore GetRecipientInfos()
+		{
+			return _recipientInfoStore;
+		}
+
+		public byte[] GetMac()
+		{
+			if (mac == null)
+			{
+				GetAuthAttrs();
+				mac = authData.GetMac().GetOctets();
+			}
+			return Arrays.Clone(mac);
+		}
+
+		/**
+		* return a table of the unauthenticated attributes indexed by
+		* the OID of the attribute.
+		* @exception java.io.IOException
+		*/
+		public Asn1.Cms.AttributeTable GetAuthAttrs()
+		{
+			if (authAttrs == null && authAttrNotRead)
+			{
+				Asn1SetParser s = authData.GetAuthAttrs();
+
+				authAttrNotRead = false;
+
+				if (s != null)
+				{
+					Asn1EncodableVector v = new Asn1EncodableVector();
+
+					IAsn1Convertible o;
+					while ((o = s.ReadObject()) != null)
+					{
+						Asn1SequenceParser seq = (Asn1SequenceParser)o;
+
+						v.Add(seq.ToAsn1Object());
+					}
+
+					authAttrs = new Asn1.Cms.AttributeTable(new DerSet(v));
+				}
+			}
+
+			return authAttrs;
+		}
+
+		/**
+		* return a table of the unauthenticated attributes indexed by
+		* the OID of the attribute.
+		* @exception java.io.IOException
+		*/
+		public Asn1.Cms.AttributeTable GetUnauthAttrs()
+		{
+			if (unauthAttrs == null && unauthAttrNotRead)
+			{
+				Asn1SetParser s = authData.GetUnauthAttrs();
+
+				unauthAttrNotRead = false;
+
+				if (s != null)
+				{
+					Asn1EncodableVector v = new Asn1EncodableVector();
+
+					IAsn1Convertible o;
+					while ((o = s.ReadObject()) != null)
+					{
+						Asn1SequenceParser seq = (Asn1SequenceParser)o;
+
+						v.Add(seq.ToAsn1Object());
+					}
+
+					unauthAttrs = new Asn1.Cms.AttributeTable(new DerSet(v));
+				}
+			}
+
+			return unauthAttrs;
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
index c133ae240..2603cb380 100644
--- a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
@@ -251,25 +251,22 @@ namespace Org.BouncyCastle.Cms
 				macStream.Write(bytes, off, len);
 			}
 
-            protected override void Dispose(bool disposing)
-            {
-                if (disposing)
-                {
-                    macStream.Dispose();
+			public override void Close()
+			{
+				macStream.Close();
 
-                    // TODO Parent context(s) should really be be closed explicitly
+				// TODO Parent context(s) should really be be closed explicitly
 
-                    eiGen.Close();
+				eiGen.Close();
 
-                    // [TODO] auth attributes go here 
-                    byte[] macOctets = MacUtilities.DoFinal(mac);
-                    authGen.AddObject(new DerOctetString(macOctets));
-                    // [TODO] unauth attributes go here
+				// [TODO] auth attributes go here 
+				byte[] macOctets = MacUtilities.DoFinal(mac);
+				authGen.AddObject(new DerOctetString(macOctets));
+				// [TODO] unauth attributes go here
 
-                    authGen.Close();
-                    cGen.Close();
-                }
-            }
+				authGen.Close();
+				cGen.Close();
+			}
 		}
 	}
 }
diff --git a/crypto/src/cms/CMSAuthenticatedGenerator.cs b/crypto/src/cms/CMSAuthenticatedGenerator.cs
new file mode 100644
index 000000000..8824d1913
--- /dev/null
+++ b/crypto/src/cms/CMSAuthenticatedGenerator.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	public class CmsAuthenticatedGenerator
+		: CmsEnvelopedGenerator
+	{
+		/**
+		* base constructor
+		*/
+		public CmsAuthenticatedGenerator()
+		{
+		}
+
+		/**
+		* constructor allowing specific source of randomness
+		*
+		* @param rand instance of SecureRandom to use
+		*/
+		public CmsAuthenticatedGenerator(
+			SecureRandom rand)
+			: base(rand)
+		{
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSCompressedData.cs b/crypto/src/cms/CMSCompressedData.cs
index 55d06b5b8..2d0107e88 100644
--- a/crypto/src/cms/CMSCompressedData.cs
+++ b/crypto/src/cms/CMSCompressedData.cs
@@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Cms
 			}
 			finally
 			{
-                zIn.Dispose();
+				zIn.Close();
 			}
         }
 
diff --git a/crypto/src/cms/CMSCompressedDataGenerator.cs b/crypto/src/cms/CMSCompressedDataGenerator.cs
index a6381ced6..00e2a3df4 100644
--- a/crypto/src/cms/CMSCompressedDataGenerator.cs
+++ b/crypto/src/cms/CMSCompressedDataGenerator.cs
@@ -45,7 +45,7 @@ namespace Org.BouncyCastle.Cms
 
 				content.Write(zOut);
 
-                zOut.Dispose();
+				zOut.Close();
 
 				comAlgId = new AlgorithmIdentifier(new DerObjectIdentifier(compressionOid));
 				comOcts = new BerOctetString(bOut.ToArray());
diff --git a/crypto/src/cms/CMSCompressedDataParser.cs b/crypto/src/cms/CMSCompressedDataParser.cs
new file mode 100644
index 000000000..93dfa1286
--- /dev/null
+++ b/crypto/src/cms/CMSCompressedDataParser.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * Class for reading a CMS Compressed Data stream.
+    * <pre>
+    *     CMSCompressedDataParser cp = new CMSCompressedDataParser(inputStream);
+    *
+    *     process(cp.GetContent().GetContentStream());
+    * </pre>
+    *  Note: this class does not introduce buffering - if you are processing large files you should create
+    *  the parser with:
+    *  <pre>
+    *      CMSCompressedDataParser     ep = new CMSCompressedDataParser(new BufferedInputStream(inputStream, bufSize));
+    *  </pre>
+    *  where bufSize is a suitably large buffer size.
+    */
+    public class CmsCompressedDataParser
+        : CmsContentInfoParser
+    {
+        public CmsCompressedDataParser(
+            byte[] compressedData)
+            : this(new MemoryStream(compressedData, false))
+        {
+        }
+
+        public CmsCompressedDataParser(
+            Stream compressedData)
+            : base(compressedData)
+        {
+        }
+
+		public CmsTypedStream GetContent()
+        {
+            try
+            {
+                CompressedDataParser comData = new CompressedDataParser((Asn1SequenceParser)this.contentInfo.GetContent(Asn1Tags.Sequence));
+                ContentInfoParser content = comData.GetEncapContentInfo();
+
+                Asn1OctetStringParser bytes = (Asn1OctetStringParser)content.GetContent(Asn1Tags.OctetString);
+
+                return new CmsTypedStream(content.ContentType.ToString(), new ZInputStream(bytes.GetOctetStream()));
+            }
+            catch (IOException e)
+            {
+                throw new CmsException("IOException reading compressed content.", e);
+            }
+        }
+    }
+}
diff --git a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs
index 13006d4b0..db0d19845 100644
--- a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs
@@ -124,21 +124,17 @@ namespace Org.BouncyCastle.Cms
 				_out.Write(bytes, off, len);
 			}
 
-            protected override void Dispose(bool disposing)
-            {
-                if (disposing)
-                {
-                    _out.Dispose();
-
-                    // TODO Parent context(s) should really be be closed explicitly
-
-                    _eiGen.Close();
-                    _cGen.Close();
-                    _sGen.Close();
-                }
-
-                base.Dispose(disposing);
-            }
-        }
+			public override void Close()
+			{
+				_out.Close();
+
+				// TODO Parent context(s) should really be be closed explicitly
+
+				_eiGen.Close();
+				_cGen.Close();
+				_sGen.Close();
+				base.Close();
+			}
+		}
 	}
 }
diff --git a/crypto/src/cms/CMSContentInfoParser.cs b/crypto/src/cms/CMSContentInfoParser.cs
index 5b1606394..fde06cf4c 100644
--- a/crypto/src/cms/CMSContentInfoParser.cs
+++ b/crypto/src/cms/CMSContentInfoParser.cs
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Cms
 		*/
 		public void Close()
 		{
-            this.data.Dispose();
+			this.data.Close();
 		}
 	}
 }
diff --git a/crypto/src/cms/CMSEnvelopedData.cs b/crypto/src/cms/CMSEnvelopedData.cs
new file mode 100644
index 000000000..0731c307e
--- /dev/null
+++ b/crypto/src/cms/CMSEnvelopedData.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * containing class for an CMS Enveloped Data object
+    */
+    public class CmsEnvelopedData
+    {
+        internal RecipientInformationStore	recipientInfoStore;
+        internal ContentInfo				contentInfo;
+
+		private AlgorithmIdentifier	encAlg;
+        private Asn1Set				unprotectedAttributes;
+
+		public CmsEnvelopedData(
+            byte[] envelopedData)
+            : this(CmsUtilities.ReadContentInfo(envelopedData))
+        {
+        }
+
+        public CmsEnvelopedData(
+            Stream envelopedData)
+            : this(CmsUtilities.ReadContentInfo(envelopedData))
+        {
+        }
+
+        public CmsEnvelopedData(
+            ContentInfo contentInfo)
+        {
+            this.contentInfo = contentInfo;
+
+			EnvelopedData envData = EnvelopedData.GetInstance(contentInfo.Content);
+
+			//
+			// read the recipients
+			//
+			Asn1Set recipientInfos = envData.RecipientInfos;
+
+			//
+			// read the encrypted content info
+			//
+			EncryptedContentInfo encInfo = envData.EncryptedContentInfo;
+			this.encAlg = encInfo.ContentEncryptionAlgorithm;
+			CmsReadable readable = new CmsProcessableByteArray(encInfo.EncryptedContent.GetOctets());
+			CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsEnvelopedSecureReadable(
+				this.encAlg, readable);
+
+			//
+			// build the RecipientInformationStore
+			//
+			this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+				recipientInfos, secureReadable);
+
+			this.unprotectedAttributes = envData.UnprotectedAttrs;
+        }
+
+		public AlgorithmIdentifier EncryptionAlgorithmID
+		{
+			get { return encAlg; }
+		}
+
+		/**
+        * return the object identifier for the content encryption algorithm.
+        */
+        public string EncryptionAlgOid
+        {
+			get { return encAlg.ObjectID.Id; }
+        }
+
+		/**
+        * return a store of the intended recipients for this message
+        */
+        public RecipientInformationStore GetRecipientInfos()
+        {
+            return recipientInfoStore;
+        }
+
+		/**
+		 * return the ContentInfo 
+		 */
+		public ContentInfo ContentInfo
+		{
+			get { return contentInfo; }
+		}
+
+		/**
+        * return a table of the unprotected attributes indexed by
+        * the OID of the attribute.
+        */
+        public Asn1.Cms.AttributeTable GetUnprotectedAttributes()
+        {
+            if (unprotectedAttributes == null)
+                return null;
+
+			return new Asn1.Cms.AttributeTable(unprotectedAttributes);
+        }
+
+		/**
+        * return the ASN.1 encoded representation of this object.
+        */
+        public byte[] GetEncoded()
+        {
+			return contentInfo.GetEncoded();
+        }
+    }
+}
diff --git a/crypto/src/cms/CMSEnvelopedDataGenerator.cs b/crypto/src/cms/CMSEnvelopedDataGenerator.cs
index 5071af4ad..3b861cde5 100644
--- a/crypto/src/cms/CMSEnvelopedDataGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedDataGenerator.cs
@@ -80,7 +80,7 @@ namespace Org.BouncyCastle.Cms
 
 				content.Write(cOut);
 
-                cOut.Dispose();
+				cOut.Close();
 
 				encContent = new BerOctetString(bOut.ToArray());
 			}
diff --git a/crypto/src/cms/CMSEnvelopedDataParser.cs b/crypto/src/cms/CMSEnvelopedDataParser.cs
new file mode 100644
index 000000000..01a949d47
--- /dev/null
+++ b/crypto/src/cms/CMSEnvelopedDataParser.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* Parsing class for an CMS Enveloped Data object from an input stream.
+	* <p>
+	* Note: that because we are in a streaming mode only one recipient can be tried and it is important
+	* that the methods on the parser are called in the appropriate order.
+	* </p>
+	* <p>
+	* Example of use - assuming the first recipient matches the private key we have.
+	* <pre>
+	*      CmsEnvelopedDataParser     ep = new CmsEnvelopedDataParser(inputStream);
+	*
+	*      RecipientInformationStore  recipients = ep.GetRecipientInfos();
+	*
+	*      Collection  c = recipients.getRecipients();
+	*      Iterator    it = c.iterator();
+	*
+	*      if (it.hasNext())
+	*      {
+	*          RecipientInformation   recipient = (RecipientInformation)it.next();
+	*
+	*          CMSTypedStream recData = recipient.getContentStream(privateKey);
+	*
+	*          processDataStream(recData.getContentStream());
+	*      }
+	*  </pre>
+	*  Note: this class does not introduce buffering - if you are processing large files you should create
+	*  the parser with:
+	*  <pre>
+	*          CmsEnvelopedDataParser     ep = new CmsEnvelopedDataParser(new BufferedInputStream(inputStream, bufSize));
+	*  </pre>
+	*  where bufSize is a suitably large buffer size.
+	* </p>
+	*/
+	public class CmsEnvelopedDataParser
+		: CmsContentInfoParser
+	{
+		internal RecipientInformationStore	recipientInfoStore;
+		internal EnvelopedDataParser		envelopedData;
+
+		private AlgorithmIdentifier			_encAlg;
+		private Asn1.Cms.AttributeTable		_unprotectedAttributes;
+		private bool						_attrNotRead;
+
+		public CmsEnvelopedDataParser(
+			byte[] envelopedData)
+			: this(new MemoryStream(envelopedData, false))
+		{
+		}
+
+		public CmsEnvelopedDataParser(
+			Stream envelopedData)
+			: base(envelopedData)
+		{
+			this._attrNotRead = true;
+			this.envelopedData = new EnvelopedDataParser(
+				(Asn1SequenceParser)this.contentInfo.GetContent(Asn1Tags.Sequence));
+
+			// TODO Validate version?
+			//DerInteger version = this.envelopedData.Version;
+
+			//
+			// read the recipients
+			//
+			Asn1Set recipientInfos = Asn1Set.GetInstance(this.envelopedData.GetRecipientInfos().ToAsn1Object());
+
+			//
+			// read the encrypted content info
+			//
+			EncryptedContentInfoParser encInfo = this.envelopedData.GetEncryptedContentInfo();
+			this._encAlg = encInfo.ContentEncryptionAlgorithm;
+			CmsReadable readable = new CmsProcessableInputStream(
+				((Asn1OctetStringParser)encInfo.GetEncryptedContent(Asn1Tags.OctetString)).GetOctetStream());
+			CmsSecureReadable secureReadable = new CmsEnvelopedHelper.CmsEnvelopedSecureReadable(
+				this._encAlg, readable);
+
+			//
+			// build the RecipientInformationStore
+			//
+			this.recipientInfoStore = CmsEnvelopedHelper.BuildRecipientInformationStore(
+				recipientInfos, secureReadable);
+		}
+
+		public AlgorithmIdentifier EncryptionAlgorithmID
+		{
+			get { return _encAlg; }
+		}
+
+		/**
+		 * return the object identifier for the content encryption algorithm.
+		 */
+		public string EncryptionAlgOid
+		{
+			get { return _encAlg.ObjectID.Id; }
+		}
+
+		/**
+		 * return the ASN.1 encoded encryption algorithm parameters, or null if
+		 * there aren't any.
+		 */
+		public Asn1Object EncryptionAlgParams
+		{
+			get
+			{
+				Asn1Encodable ae = _encAlg.Parameters;
+
+				return ae == null ? null : ae.ToAsn1Object();
+			}
+		}
+
+		/**
+		 * return a store of the intended recipients for this message
+		 */
+		public RecipientInformationStore GetRecipientInfos()
+		{
+			return this.recipientInfoStore;
+		}
+
+		/**
+		 * return a table of the unprotected attributes indexed by
+		 * the OID of the attribute.
+		 * @throws IOException
+		 */
+		public Asn1.Cms.AttributeTable GetUnprotectedAttributes()
+		{
+			if (_unprotectedAttributes == null && _attrNotRead)
+			{
+				Asn1SetParser asn1Set = this.envelopedData.GetUnprotectedAttrs();
+
+				_attrNotRead = false;
+
+				if (asn1Set != null)
+				{
+					Asn1EncodableVector v = new Asn1EncodableVector();
+					IAsn1Convertible o;
+
+					while ((o = asn1Set.ReadObject()) != null)
+					{
+						Asn1SequenceParser seq = (Asn1SequenceParser)o;
+
+						v.Add(seq.ToAsn1Object());
+					}
+
+					_unprotectedAttributes = new Asn1.Cms.AttributeTable(new DerSet(v));
+				}
+			}
+
+			return _unprotectedAttributes;
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
index 820ddfe16..a63ea7b7f 100644
--- a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
@@ -255,31 +255,27 @@ namespace Org.BouncyCastle.Cms
 				_out.Write(bytes, off, len);
 			}
 
-            protected override void Dispose(bool disposing)
-            {
-                if (disposing)
-                {
-                    _out.Dispose();
-
-                    // TODO Parent context(s) should really be be closed explicitly
+			public override void Close()
+			{
+				_out.Close();
 
-                    _eiGen.Close();
+				// TODO Parent context(s) should really be be closed explicitly
 
-                    if (_outer.unprotectedAttributeGenerator != null)
-                    {
-                        Asn1.Cms.AttributeTable attrTable = _outer.unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable());
+				_eiGen.Close();
 
-                        Asn1Set unprotectedAttrs = new BerSet(attrTable.ToAsn1EncodableVector());
+                if (_outer.unprotectedAttributeGenerator != null)
+                {
+                    Asn1.Cms.AttributeTable attrTable = _outer.unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable());
 
-                        _envGen.AddObject(new DerTaggedObject(false, 1, unprotectedAttrs));
-                    }
+                    Asn1Set unprotectedAttrs = new BerSet(attrTable.ToAsn1EncodableVector());
 
-                    _envGen.Close();
-                    _cGen.Close();
+                    _envGen.AddObject(new DerTaggedObject(false, 1, unprotectedAttrs));
                 }
 
-                base.Dispose(disposing);
-            }
+				_envGen.Close();
+				_cGen.Close();
+				base.Close();
+			}
 		}
 	}
 }
diff --git a/crypto/src/cms/CMSEnvelopedGenerator.cs b/crypto/src/cms/CMSEnvelopedGenerator.cs
new file mode 100644
index 000000000..f92ae3824
--- /dev/null
+++ b/crypto/src/cms/CMSEnvelopedGenerator.cs
@@ -0,0 +1,331 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* General class for generating a CMS enveloped-data message.
+	*
+	* A simple example of usage.
+	*
+	* <pre>
+	*      CMSEnvelopedDataGenerator  fact = new CMSEnvelopedDataGenerator();
+	*
+	*      fact.addKeyTransRecipient(cert);
+	*
+	*      CMSEnvelopedData         data = fact.generate(content, algorithm, "BC");
+	* </pre>
+	*/
+	public class CmsEnvelopedGenerator
+	{
+		// Note: These tables are complementary: If rc2Table[i]==j, then rc2Ekb[j]==i
+		internal static readonly short[] rc2Table =
+		{
+			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
+		};
+
+//		internal static readonly short[] rc2Ekb =
+//		{
+//			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
+//		};
+
+
+		// TODO Create named constants for all of these
+		public static readonly string DesEde3Cbc		= PkcsObjectIdentifiers.DesEde3Cbc.Id;
+		public static readonly string RC2Cbc			= PkcsObjectIdentifiers.RC2Cbc.Id;
+		public const string IdeaCbc						= "1.3.6.1.4.1.188.7.1.1.2";
+		public const string Cast5Cbc					= "1.2.840.113533.7.66.10";
+		public static readonly string Aes128Cbc			= NistObjectIdentifiers.IdAes128Cbc.Id;
+		public static readonly string Aes192Cbc			= NistObjectIdentifiers.IdAes192Cbc.Id;
+		public static readonly string Aes256Cbc			= NistObjectIdentifiers.IdAes256Cbc.Id;
+		public static readonly string Camellia128Cbc	= NttObjectIdentifiers.IdCamellia128Cbc.Id;
+		public static readonly string Camellia192Cbc	= NttObjectIdentifiers.IdCamellia192Cbc.Id;
+		public static readonly string Camellia256Cbc	= NttObjectIdentifiers.IdCamellia256Cbc.Id;
+		public static readonly string SeedCbc			= KisaObjectIdentifiers.IdSeedCbc.Id;
+
+		public static readonly string DesEde3Wrap		= PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id;
+		public static readonly string Aes128Wrap		= NistObjectIdentifiers.IdAes128Wrap.Id;
+		public static readonly string Aes192Wrap		= NistObjectIdentifiers.IdAes192Wrap.Id;
+		public static readonly string Aes256Wrap		= NistObjectIdentifiers.IdAes256Wrap.Id;
+		public static readonly string Camellia128Wrap	= NttObjectIdentifiers.IdCamellia128Wrap.Id;
+		public static readonly string Camellia192Wrap	= NttObjectIdentifiers.IdCamellia192Wrap.Id;
+		public static readonly string Camellia256Wrap	= NttObjectIdentifiers.IdCamellia256Wrap.Id;
+		public static readonly string SeedWrap			= KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id;
+
+		public static readonly string ECDHSha1Kdf		= X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id;
+		public static readonly string ECMqvSha1Kdf		= X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id;
+
+		internal readonly IList recipientInfoGenerators = Platform.CreateArrayList();
+		internal readonly SecureRandom rand;
+
+        internal CmsAttributeTableGenerator unprotectedAttributeGenerator = null;
+
+		public CmsEnvelopedGenerator()
+			: this(new SecureRandom())
+		{
+		}
+
+		/// <summary>Constructor allowing specific source of randomness</summary>
+		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsEnvelopedGenerator(
+			SecureRandom rand)
+		{
+			this.rand = rand;
+		}
+
+        public CmsAttributeTableGenerator UnprotectedAttributeGenerator
+        {
+            get { return this.unprotectedAttributeGenerator; }
+            set { this.unprotectedAttributeGenerator = value; }
+        }
+
+		/**
+		 * add a recipient.
+		 *
+		 * @param cert recipient's public key certificate
+		 * @exception ArgumentException if there is a problem with the certificate
+		 */
+		public void AddKeyTransRecipient(
+			X509Certificate cert)
+		{
+			KeyTransRecipientInfoGenerator ktrig = new KeyTransRecipientInfoGenerator();
+			ktrig.RecipientCert = cert;
+
+			recipientInfoGenerators.Add(ktrig);
+		}
+
+		/**
+		* add a recipient
+		*
+		* @param key the public key used by the recipient
+		* @param subKeyId the identifier for the recipient's public key
+		* @exception ArgumentException if there is a problem with the key
+		*/
+		public void AddKeyTransRecipient(
+			AsymmetricKeyParameter	pubKey,
+			byte[]					subKeyId)
+		{
+			KeyTransRecipientInfoGenerator ktrig = new KeyTransRecipientInfoGenerator();
+			ktrig.RecipientPublicKey = pubKey;
+			ktrig.SubjectKeyIdentifier = new DerOctetString(subKeyId);
+
+			recipientInfoGenerators.Add(ktrig);
+		}
+
+		/**
+		 * add a KEK recipient.
+		 * @param key the secret key to use for wrapping
+		 * @param keyIdentifier the byte string that identifies the key
+		 */
+		public void AddKekRecipient(
+			string			keyAlgorithm, // TODO Remove need for this parameter
+			KeyParameter	key,
+			byte[]			keyIdentifier)
+		{
+			AddKekRecipient(keyAlgorithm, key, new KekIdentifier(keyIdentifier, null, null));
+		}
+
+		/**
+		* add a KEK recipient.
+		* @param key the secret key to use for wrapping
+		* @param keyIdentifier the byte string that identifies the key
+		*/
+		public void AddKekRecipient(
+			string			keyAlgorithm, // TODO Remove need for this parameter
+			KeyParameter	key,
+			KekIdentifier	kekIdentifier)
+		{
+			KekRecipientInfoGenerator kekrig = new KekRecipientInfoGenerator();
+			kekrig.KekIdentifier = kekIdentifier;
+			kekrig.KeyEncryptionKeyOID = keyAlgorithm;
+			kekrig.KeyEncryptionKey = key;
+
+			recipientInfoGenerators.Add(kekrig);
+		}
+
+		public void AddPasswordRecipient(
+			CmsPbeKey	pbeKey,
+			string		kekAlgorithmOid)
+		{
+			Pbkdf2Params p = new Pbkdf2Params(pbeKey.Salt, pbeKey.IterationCount);
+
+			PasswordRecipientInfoGenerator prig = new PasswordRecipientInfoGenerator();
+			prig.KeyDerivationAlgorithm = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPbkdf2, p);
+			prig.KeyEncryptionKeyOID = kekAlgorithmOid;
+			prig.KeyEncryptionKey = pbeKey.GetEncoded(kekAlgorithmOid);
+
+			recipientInfoGenerators.Add(prig);
+		}
+
+		/**
+		* Add a key agreement based recipient.
+		*
+		* @param agreementAlgorithm key agreement algorithm to use.
+		* @param senderPrivateKey private key to initialise sender side of agreement with.
+		* @param senderPublicKey sender public key to include with message.
+		* @param recipientCert recipient's public key certificate.
+		* @param cekWrapAlgorithm OID for key wrapping algorithm to use.
+		* @exception SecurityUtilityException if the algorithm requested cannot be found
+		* @exception InvalidKeyException if the keys are inappropriate for the algorithm specified
+		*/
+		public void AddKeyAgreementRecipient(
+			string					agreementAlgorithm,
+			AsymmetricKeyParameter	senderPrivateKey,
+			AsymmetricKeyParameter	senderPublicKey,
+			X509Certificate			recipientCert,
+			string					cekWrapAlgorithm)
+		{
+            IList recipientCerts = Platform.CreateArrayList(1);
+			recipientCerts.Add(recipientCert);
+
+			AddKeyAgreementRecipients(agreementAlgorithm, senderPrivateKey, senderPublicKey,
+				recipientCerts, cekWrapAlgorithm);
+		}
+
+		/**
+		 * Add multiple key agreement based recipients (sharing a single KeyAgreeRecipientInfo structure).
+		 *
+		 * @param agreementAlgorithm key agreement algorithm to use.
+		 * @param senderPrivateKey private key to initialise sender side of agreement with.
+		 * @param senderPublicKey sender public key to include with message.
+		 * @param recipientCerts recipients' public key certificates.
+		 * @param cekWrapAlgorithm OID for key wrapping algorithm to use.
+		 * @exception SecurityUtilityException if the algorithm requested cannot be found
+		 * @exception InvalidKeyException if the keys are inappropriate for the algorithm specified
+		 */
+		public void AddKeyAgreementRecipients(
+			string					agreementAlgorithm,
+			AsymmetricKeyParameter	senderPrivateKey,
+			AsymmetricKeyParameter	senderPublicKey,
+			ICollection				recipientCerts,
+			string					cekWrapAlgorithm)
+		{
+			if (!senderPrivateKey.IsPrivate)
+				throw new ArgumentException("Expected private key", "senderPrivateKey");
+			if (senderPublicKey.IsPrivate)
+				throw new ArgumentException("Expected public key", "senderPublicKey");
+
+			/* TODO
+			 * "a recipient X.509 version 3 certificate that contains a key usage extension MUST
+			 * assert the keyAgreement bit."
+			 */
+
+			KeyAgreeRecipientInfoGenerator karig = new KeyAgreeRecipientInfoGenerator();
+			karig.KeyAgreementOID = new DerObjectIdentifier(agreementAlgorithm);
+			karig.KeyEncryptionOID = new DerObjectIdentifier(cekWrapAlgorithm);
+			karig.RecipientCerts = recipientCerts;
+			karig.SenderKeyPair = new AsymmetricCipherKeyPair(senderPublicKey, senderPrivateKey);
+
+			recipientInfoGenerators.Add(karig);
+		}
+
+        protected internal virtual AlgorithmIdentifier GetAlgorithmIdentifier(
+			string					encryptionOid,
+			KeyParameter			encKey,
+			Asn1Encodable			asn1Params,
+			out ICipherParameters	cipherParameters)
+		{
+			Asn1Object asn1Object;
+			if (asn1Params != null)
+			{
+				asn1Object = asn1Params.ToAsn1Object();
+				cipherParameters = ParameterUtilities.GetCipherParameters(
+					encryptionOid, encKey, asn1Object);
+			}
+			else
+			{
+				asn1Object = DerNull.Instance;
+				cipherParameters = encKey;
+			}
+
+			return new AlgorithmIdentifier(
+				new DerObjectIdentifier(encryptionOid),
+				asn1Object);
+		}
+
+		protected internal virtual Asn1Encodable GenerateAsn1Parameters(
+			string	encryptionOid,
+			byte[]	encKeyBytes)
+		{
+			Asn1Encodable asn1Params = null;
+
+			try
+			{
+				if (encryptionOid.Equals(RC2Cbc))
+				{
+					byte[] iv = new byte[8];
+					rand.NextBytes(iv);
+
+					// TODO Is this detailed repeat of Java version really necessary?
+					int effKeyBits = encKeyBytes.Length * 8;
+					int parameterVersion;
+
+					if (effKeyBits < 256)
+					{
+						parameterVersion = rc2Table[effKeyBits];
+					}
+					else
+					{
+						parameterVersion = effKeyBits;
+					}
+
+					asn1Params = new RC2CbcParameter(parameterVersion, iv);
+				}
+				else
+				{
+					asn1Params = ParameterUtilities.GenerateParameters(encryptionOid, rand);
+				}
+			}
+			catch (SecurityUtilityException)
+			{
+				// No problem... no parameters generated
+			}
+
+			return asn1Params;
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSEnvelopedHelper.cs b/crypto/src/cms/CMSEnvelopedHelper.cs
new file mode 100644
index 000000000..fe2b14cd9
--- /dev/null
+++ b/crypto/src/cms/CMSEnvelopedHelper.cs
@@ -0,0 +1,311 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	class CmsEnvelopedHelper
+	{
+		internal static readonly CmsEnvelopedHelper Instance = new CmsEnvelopedHelper();
+
+		private static readonly IDictionary KeySizes = Platform.CreateHashtable();
+		private static readonly IDictionary BaseCipherNames = Platform.CreateHashtable();
+
+		static CmsEnvelopedHelper()
+		{
+			KeySizes.Add(CmsEnvelopedGenerator.DesEde3Cbc, 192);
+			KeySizes.Add(CmsEnvelopedGenerator.Aes128Cbc, 128);
+			KeySizes.Add(CmsEnvelopedGenerator.Aes192Cbc, 192);
+			KeySizes.Add(CmsEnvelopedGenerator.Aes256Cbc, 256);
+
+			BaseCipherNames.Add(CmsEnvelopedGenerator.DesEde3Cbc,  "DESEDE");
+			BaseCipherNames.Add(CmsEnvelopedGenerator.Aes128Cbc,  "AES");
+			BaseCipherNames.Add(CmsEnvelopedGenerator.Aes192Cbc,  "AES");
+			BaseCipherNames.Add(CmsEnvelopedGenerator.Aes256Cbc,  "AES");
+		}
+
+		private string GetAsymmetricEncryptionAlgName(
+			string encryptionAlgOid)
+		{
+			if (Asn1.Pkcs.PkcsObjectIdentifiers.RsaEncryption.Id.Equals(encryptionAlgOid))
+			{
+				return "RSA/ECB/PKCS1Padding";
+			}
+
+			return encryptionAlgOid;
+		}
+
+		internal IBufferedCipher CreateAsymmetricCipher(
+			string encryptionOid)
+		{
+			string asymName = GetAsymmetricEncryptionAlgName(encryptionOid);
+			if (!asymName.Equals(encryptionOid))
+			{
+				try
+				{
+					return CipherUtilities.GetCipher(asymName);
+				}
+				catch (SecurityUtilityException)
+				{
+					// Ignore
+				}
+			}
+			return CipherUtilities.GetCipher(encryptionOid);
+		}
+
+		internal IWrapper CreateWrapper(
+			string encryptionOid)
+		{
+			try
+			{
+				return WrapperUtilities.GetWrapper(encryptionOid);
+			}
+			catch (SecurityUtilityException)
+			{
+				return WrapperUtilities.GetWrapper(GetAsymmetricEncryptionAlgName(encryptionOid));
+			}
+		}
+
+		internal string GetRfc3211WrapperName(
+			string oid)
+		{
+			if (oid == null)
+				throw new ArgumentNullException("oid");
+
+			string alg = (string) BaseCipherNames[oid];
+
+			if (alg == null)
+				throw new ArgumentException("no name for " + oid, "oid");
+
+			return alg + "RFC3211Wrap";
+		}
+
+		internal int GetKeySize(
+			string oid)
+		{
+			if (!KeySizes.Contains(oid))
+			{
+				throw new ArgumentException("no keysize for " + oid, "oid");
+			}
+
+			return (int) KeySizes[oid];
+		}
+
+		internal static RecipientInformationStore BuildRecipientInformationStore(
+			Asn1Set recipientInfos, CmsSecureReadable secureReadable)
+		{
+			IList infos = Platform.CreateArrayList();
+			for (int i = 0; i != recipientInfos.Count; i++)
+			{
+				RecipientInfo info = RecipientInfo.GetInstance(recipientInfos[i]);
+
+				ReadRecipientInfo(infos, info, secureReadable);
+			}
+			return new RecipientInformationStore(infos);
+		}
+
+		private static void ReadRecipientInfo(
+			IList infos, RecipientInfo info, CmsSecureReadable secureReadable)
+		{
+			Asn1Encodable recipInfo = info.Info;
+			if (recipInfo is KeyTransRecipientInfo)
+			{
+				infos.Add(new KeyTransRecipientInformation((KeyTransRecipientInfo)recipInfo, secureReadable));
+			}
+			else if (recipInfo is KekRecipientInfo)
+			{
+				infos.Add(new KekRecipientInformation((KekRecipientInfo)recipInfo, secureReadable));
+			}
+			else if (recipInfo is KeyAgreeRecipientInfo)
+			{
+				KeyAgreeRecipientInformation.ReadRecipientInfo(infos, (KeyAgreeRecipientInfo)recipInfo, secureReadable);
+			}
+			else if (recipInfo is PasswordRecipientInfo)
+			{
+				infos.Add(new PasswordRecipientInformation((PasswordRecipientInfo)recipInfo, secureReadable));
+			}
+		}
+
+		internal class CmsAuthenticatedSecureReadable : CmsSecureReadable
+		{
+			private AlgorithmIdentifier algorithm;
+			private IMac mac;
+			private CmsReadable readable;
+
+			internal CmsAuthenticatedSecureReadable(AlgorithmIdentifier algorithm, CmsReadable readable)
+			{
+				this.algorithm = algorithm;
+				this.readable = readable;
+			}
+
+			public AlgorithmIdentifier Algorithm
+			{
+				get { return this.algorithm; }
+			}
+
+			public object CryptoObject
+			{
+				get { return this.mac; }
+			}
+
+			public CmsReadable GetReadable(KeyParameter sKey)
+			{
+				string macAlg = this.algorithm.ObjectID.Id;
+//				Asn1Object sParams = this.algorithm.Parameters.ToAsn1Object();
+
+				try
+				{
+					this.mac = MacUtilities.GetMac(macAlg);
+
+					// FIXME Support for MAC algorithm parameters similar to cipher parameters
+//						ASN1Object sParams = (ASN1Object)macAlg.getParameters();
+//
+//						if (sParams != null && !(sParams instanceof ASN1Null))
+//						{
+//							AlgorithmParameters params = CMSEnvelopedHelper.INSTANCE.createAlgorithmParameters(macAlg.getObjectId().getId(), provider);
+//
+//							params.init(sParams.getEncoded(), "ASN.1");
+//
+//							mac.init(sKey, params.getParameterSpec(IvParameterSpec.class));
+//						}
+//						else
+					{
+						mac.Init(sKey);
+					}
+
+//						Asn1Object asn1Params = asn1Enc == null ? null : asn1Enc.ToAsn1Object();
+//
+//						ICipherParameters cipherParameters = sKey;
+//
+//						if (asn1Params != null && !(asn1Params is Asn1Null))
+//						{
+//							cipherParameters = ParameterUtilities.GetCipherParameters(
+//							macAlg.ObjectID, cipherParameters, asn1Params);
+//						}
+//						else
+//						{
+//							string alg = macAlg.ObjectID.Id;
+//							if (alg.Equals(CmsEnvelopedDataGenerator.DesEde3Cbc)
+//								|| alg.Equals(CmsEnvelopedDataGenerator.IdeaCbc)
+//								|| alg.Equals(CmsEnvelopedDataGenerator.Cast5Cbc))
+//							{
+//								cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]);
+//							}
+//						}
+//
+//						mac.Init(cipherParameters);
+				}
+				catch (SecurityUtilityException e)
+				{
+					throw new CmsException("couldn't create cipher.", e);
+				}
+				catch (InvalidKeyException e)
+				{
+					throw new CmsException("key invalid in message.", e);
+				}
+				catch (IOException e)
+				{
+					throw new CmsException("error decoding algorithm parameters.", e);
+				}
+
+				try
+				{
+					return new CmsProcessableInputStream(
+						new TeeInputStream(
+							readable.GetInputStream(),
+							new MacOutputStream(this.mac)));
+				}
+				catch (IOException e)
+				{
+					throw new CmsException("error reading content.", e);
+				}
+			}
+		}
+
+		internal class CmsEnvelopedSecureReadable : CmsSecureReadable
+		{
+			private AlgorithmIdentifier algorithm;
+			private IBufferedCipher cipher;
+			private CmsReadable readable;
+
+			internal CmsEnvelopedSecureReadable(AlgorithmIdentifier algorithm, CmsReadable readable)
+			{
+				this.algorithm = algorithm;
+				this.readable = readable;
+			}
+
+			public AlgorithmIdentifier Algorithm
+			{
+				get { return this.algorithm; }
+			}
+
+			public object CryptoObject
+			{
+				get { return this.cipher; }
+			}
+
+			public CmsReadable GetReadable(KeyParameter sKey)
+			{
+				try
+				{
+					this.cipher =  CipherUtilities.GetCipher(this.algorithm.ObjectID);
+
+					Asn1Encodable asn1Enc = this.algorithm.Parameters;
+					Asn1Object asn1Params = asn1Enc == null ? null : asn1Enc.ToAsn1Object();
+
+					ICipherParameters cipherParameters = sKey;
+
+					if (asn1Params != null && !(asn1Params is Asn1Null))
+					{
+						cipherParameters = ParameterUtilities.GetCipherParameters(
+							this.algorithm.ObjectID, cipherParameters, asn1Params);
+					}
+					else
+					{
+						string alg = this.algorithm.ObjectID.Id;
+						if (alg.Equals(CmsEnvelopedDataGenerator.DesEde3Cbc)
+							|| alg.Equals(CmsEnvelopedDataGenerator.IdeaCbc)
+							|| alg.Equals(CmsEnvelopedDataGenerator.Cast5Cbc))
+						{
+							cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]);
+						}
+					}
+
+					cipher.Init(false, cipherParameters);
+				}
+				catch (SecurityUtilityException e)
+				{
+					throw new CmsException("couldn't create cipher.", e);
+				}
+				catch (InvalidKeyException e)
+				{
+					throw new CmsException("key invalid in message.", e);
+				}
+				catch (IOException e)
+				{
+					throw new CmsException("error decoding algorithm parameters.", e);
+				}
+
+				try
+				{
+					return new CmsProcessableInputStream(
+						new CipherStream(readable.GetInputStream(), cipher, null));
+				}
+				catch (IOException e)
+				{
+					throw new CmsException("error reading content.", e);
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/cms/CMSException.cs b/crypto/src/cms/CMSException.cs
index 1d1cd82e3..5a6e33502 100644
--- a/crypto/src/cms/CMSException.cs
+++ b/crypto/src/cms/CMSException.cs
@@ -2,9 +2,12 @@ using System;
 
 namespace Org.BouncyCastle.Cms
 {
-		public class CmsException
-			: Exception
-		{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CmsException
+		: Exception
+	{
 		public CmsException()
 		{
 		}
diff --git a/crypto/src/cms/CMSPBEKey.cs b/crypto/src/cms/CMSPBEKey.cs
new file mode 100644
index 000000000..cb1e54c36
--- /dev/null
+++ b/crypto/src/cms/CMSPBEKey.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+//import javax.crypto.interfaces.PBEKey;
+
+namespace Org.BouncyCastle.Cms
+{
+	public abstract class CmsPbeKey
+		// TODO Create an equivalent interface somewhere?
+		//	: PBEKey
+		: ICipherParameters
+	{
+		internal readonly char[]	password;
+		internal readonly byte[]	salt;
+		internal readonly int		iterationCount;
+
+		[Obsolete("Use version taking 'char[]' instead")]
+		public CmsPbeKey(
+			string	password,
+			byte[]	salt,
+			int		iterationCount)
+			: this(password.ToCharArray(), salt, iterationCount)
+		{
+		}
+
+		[Obsolete("Use version taking 'char[]' instead")]
+		public CmsPbeKey(
+			string				password,
+			AlgorithmIdentifier keyDerivationAlgorithm)
+			: this(password.ToCharArray(), keyDerivationAlgorithm)
+		{
+		}
+		
+		public CmsPbeKey(
+			char[]	password,
+			byte[]	salt,
+			int		iterationCount)
+		{
+			this.password = (char[])password.Clone();
+			this.salt = Arrays.Clone(salt);
+			this.iterationCount = iterationCount;
+		}
+
+		public CmsPbeKey(
+			char[]				password,
+			AlgorithmIdentifier keyDerivationAlgorithm)
+		{
+			if (!keyDerivationAlgorithm.ObjectID.Equals(PkcsObjectIdentifiers.IdPbkdf2))
+				throw new ArgumentException("Unsupported key derivation algorithm: "
+					+ keyDerivationAlgorithm.ObjectID);
+
+			Pbkdf2Params kdfParams = Pbkdf2Params.GetInstance(
+				keyDerivationAlgorithm.Parameters.ToAsn1Object());
+
+			this.password = (char[])password.Clone();
+			this.salt = kdfParams.GetSalt();
+			this.iterationCount = kdfParams.IterationCount.IntValue;
+		}
+
+		~CmsPbeKey()
+		{
+			Array.Clear(this.password, 0, this.password.Length);
+		}
+
+		[Obsolete("Will be removed")]
+		public string Password
+		{
+			get { return new string(password); }
+		}
+
+		public byte[] Salt
+		{
+			get { return Arrays.Clone(salt); }
+		}
+
+		[Obsolete("Use 'Salt' property instead")]
+		public byte[] GetSalt()
+		{
+			return Salt;
+		}
+
+		public int IterationCount
+		{
+			get { return iterationCount; }
+		}
+
+		public string Algorithm
+		{
+			get { return "PKCS5S2"; }
+		}
+
+		public string Format
+		{
+			get { return "RAW"; }
+		}
+
+		public byte[] GetEncoded()
+		{
+			return null;
+		}
+
+		internal abstract KeyParameter GetEncoded(string algorithmOid);
+	}
+}
diff --git a/crypto/src/cms/CMSProcessable.cs b/crypto/src/cms/CMSProcessable.cs
new file mode 100644
index 000000000..41018d12b
--- /dev/null
+++ b/crypto/src/cms/CMSProcessable.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	public interface CmsProcessable
+	{
+		/// <summary>
+		/// Generic routine to copy out the data we want processed.
+		/// </summary>
+		/// <remarks>
+		/// This routine may be called multiple times.
+		/// </remarks>
+		void Write(Stream outStream);
+
+		[Obsolete]
+		object GetContent();
+	}
+}
diff --git a/crypto/src/cms/CMSProcessableByteArray.cs b/crypto/src/cms/CMSProcessableByteArray.cs
new file mode 100644
index 000000000..4bee4f8bd
--- /dev/null
+++ b/crypto/src/cms/CMSProcessableByteArray.cs
@@ -0,0 +1,36 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* a holding class for a byte array of data to be processed.
+	*/
+	public class CmsProcessableByteArray
+		: CmsProcessable, CmsReadable
+	{
+		private readonly byte[] bytes;
+
+		public CmsProcessableByteArray(
+			byte[] bytes)
+		{
+			this.bytes = bytes;
+		}
+
+		public Stream GetInputStream()
+		{
+			return new MemoryStream(bytes, false);
+		}
+
+		public virtual void Write(Stream zOut)
+		{
+			zOut.Write(bytes, 0, bytes.Length);
+		}
+
+		/// <returns>A clone of the byte array</returns>
+		public virtual object GetContent()
+		{
+			return bytes.Clone();
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSProcessableFile.cs b/crypto/src/cms/CMSProcessableFile.cs
index 548dc8efb..cbc74f44b 100644
--- a/crypto/src/cms/CMSProcessableFile.cs
+++ b/crypto/src/cms/CMSProcessableFile.cs
@@ -1,5 +1,3 @@
-#if !PORTABLE
-
 using System;
 using System.IO;
 
@@ -54,4 +52,3 @@ namespace Org.BouncyCastle.Cms
 		}
 	}
 }
-#endif
\ No newline at end of file
diff --git a/crypto/src/cms/CMSProcessableInputStream.cs b/crypto/src/cms/CMSProcessableInputStream.cs
index d10d059c6..7fdd1dfef 100644
--- a/crypto/src/cms/CMSProcessableInputStream.cs
+++ b/crypto/src/cms/CMSProcessableInputStream.cs
@@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Cms
 			CheckSingleUsage();
 
 			Streams.PipeAll(input, output);
-			input.Dispose();
+			input.Close();
 		}
 
 		[Obsolete]
diff --git a/crypto/src/cms/CMSReadable.cs b/crypto/src/cms/CMSReadable.cs
new file mode 100644
index 000000000..9507b920c
--- /dev/null
+++ b/crypto/src/cms/CMSReadable.cs
@@ -0,0 +1,10 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal interface CmsReadable
+	{
+		Stream GetInputStream();
+	}
+}
diff --git a/crypto/src/cms/CMSSecureReadable.cs b/crypto/src/cms/CMSSecureReadable.cs
new file mode 100644
index 000000000..5ceac24fd
--- /dev/null
+++ b/crypto/src/cms/CMSSecureReadable.cs
@@ -0,0 +1,14 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal interface CmsSecureReadable
+	{
+		AlgorithmIdentifier Algorithm { get; }
+		object CryptoObject { get; }
+		CmsReadable GetReadable(KeyParameter key);
+	}
+}
diff --git a/crypto/src/cms/CMSSignedData.cs b/crypto/src/cms/CMSSignedData.cs
new file mode 100644
index 000000000..81c87a426
--- /dev/null
+++ b/crypto/src/cms/CMSSignedData.cs
@@ -0,0 +1,425 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* general class for handling a pkcs7-signature message.
+	*
+	* A simple example of usage - note, in the example below the validity of
+	* the certificate isn't verified, just the fact that one of the certs
+	* matches the given signer...
+	*
+	* <pre>
+	*  IX509Store              certs = s.GetCertificates();
+	*  SignerInformationStore  signers = s.GetSignerInfos();
+	*
+	*  foreach (SignerInformation signer in signers.GetSigners())
+	*  {
+	*      ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
+	*      X509Certificate cert = (X509Certificate) certList[0];
+	*
+	*      if (signer.Verify(cert.GetPublicKey()))
+	*      {
+	*          verified++;
+	*      }
+	*  }
+	* </pre>
+	*/
+	public class CmsSignedData
+	{
+		private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+		private readonly CmsProcessable	signedContent;
+		private SignedData				signedData;
+		private ContentInfo				contentInfo;
+		private SignerInformationStore	signerInfoStore;
+		private IX509Store				attrCertStore;
+		private IX509Store				certificateStore;
+		private IX509Store				crlStore;
+		private IDictionary				hashes;
+
+		private CmsSignedData(
+			CmsSignedData c)
+		{
+			this.signedData = c.signedData;
+			this.contentInfo = c.contentInfo;
+			this.signedContent = c.signedContent;
+			this.signerInfoStore = c.signerInfoStore;
+		}
+
+		public CmsSignedData(
+			byte[] sigBlock)
+			: this(CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false)))
+		{
+		}
+
+		public CmsSignedData(
+			CmsProcessable	signedContent,
+			byte[]			sigBlock)
+			: this(signedContent, CmsUtilities.ReadContentInfo(new MemoryStream(sigBlock, false)))
+		{
+		}
+
+		/**
+		 * Content with detached signature, digests precomputed
+		 *
+		 * @param hashes a map of precomputed digests for content indexed by name of hash.
+		 * @param sigBlock the signature object.
+		 */
+		public CmsSignedData(
+			IDictionary	hashes,
+			byte[]		sigBlock)
+			: this(hashes, CmsUtilities.ReadContentInfo(sigBlock))
+		{
+		}
+
+		/**
+		* base constructor - content with detached signature.
+		*
+		* @param signedContent the content that was signed.
+		* @param sigData the signature object.
+		*/
+		public CmsSignedData(
+			CmsProcessable	signedContent,
+			Stream			sigData)
+			: this(signedContent, CmsUtilities.ReadContentInfo(sigData))
+		{
+		}
+
+		/**
+		* base constructor - with encapsulated content
+		*/
+		public CmsSignedData(
+			Stream sigData)
+			: this(CmsUtilities.ReadContentInfo(sigData))
+		{
+		}
+
+		public CmsSignedData(
+			CmsProcessable  signedContent,
+			ContentInfo     sigData)
+		{
+			this.signedContent = signedContent;
+			this.contentInfo = sigData;
+			this.signedData = SignedData.GetInstance(contentInfo.Content);
+		}
+
+		public CmsSignedData(
+			IDictionary	hashes,
+			ContentInfo	sigData)
+		{
+			this.hashes = hashes;
+			this.contentInfo = sigData;
+			this.signedData = SignedData.GetInstance(contentInfo.Content);
+		}
+
+		public CmsSignedData(
+			ContentInfo sigData)
+		{
+			this.contentInfo = sigData;
+			this.signedData = SignedData.GetInstance(contentInfo.Content);
+
+			//
+			// this can happen if the signed message is sent simply to send a
+			// certificate chain.
+			//
+			if (signedData.EncapContentInfo.Content != null)
+			{
+				this.signedContent = new CmsProcessableByteArray(
+					((Asn1OctetString)(signedData.EncapContentInfo.Content)).GetOctets());
+			}
+//			else
+//			{
+//				this.signedContent = null;
+//			}
+		}
+
+		/// <summary>Return the version number for this object.</summary>
+		public int Version
+		{
+			get { return signedData.Version.Value.IntValue; }
+		}
+
+		/**
+		* return the collection of signers that are associated with the
+		* signatures for the message.
+		*/
+		public SignerInformationStore GetSignerInfos()
+		{
+			if (signerInfoStore == null)
+			{
+                IList signerInfos = Platform.CreateArrayList();
+				Asn1Set s = signedData.SignerInfos;
+
+				foreach (object obj in s)
+				{
+					SignerInfo info = SignerInfo.GetInstance(obj);
+					DerObjectIdentifier contentType = signedData.EncapContentInfo.ContentType;
+
+					if (hashes == null)
+					{
+						signerInfos.Add(new SignerInformation(info, contentType, signedContent, null));
+					}
+					else
+					{
+						byte[] hash = (byte[]) hashes[info.DigestAlgorithm.ObjectID.Id];
+
+						signerInfos.Add(new SignerInformation(info, contentType, null, new BaseDigestCalculator(hash)));
+					}
+				}
+
+				signerInfoStore = new SignerInformationStore(signerInfos);
+			}
+
+			return signerInfoStore;
+		}
+
+		/**
+		 * return a X509Store containing the attribute certificates, if any, contained
+		 * in this message.
+		 *
+		 * @param type type of store to create
+		 * @return a store of attribute certificates
+		 * @exception NoSuchStoreException if the store type isn't available.
+		 * @exception CmsException if a general exception prevents creation of the X509Store
+		 */
+		public IX509Store GetAttributeCertificates(
+			string type)
+		{
+			if (attrCertStore == null)
+			{
+				attrCertStore = Helper.CreateAttributeStore(type, signedData.Certificates);
+			}
+
+			return attrCertStore;
+		}
+
+		/**
+		 * return a X509Store containing the public key certificates, if any, contained
+		 * in this message.
+		 *
+		 * @param type type of store to create
+		 * @return a store of public key certificates
+		 * @exception NoSuchStoreException if the store type isn't available.
+		 * @exception CmsException if a general exception prevents creation of the X509Store
+		 */
+		public IX509Store GetCertificates(
+			string type)
+		{
+			if (certificateStore == null)
+			{
+				certificateStore = Helper.CreateCertificateStore(type, signedData.Certificates);
+			}
+
+			return certificateStore;
+		}
+
+		/**
+		* return a X509Store containing CRLs, if any, contained
+		* in this message.
+		*
+		* @param type type of store to create
+		* @return a store of CRLs
+		* @exception NoSuchStoreException if the store type isn't available.
+		* @exception CmsException if a general exception prevents creation of the X509Store
+		*/
+		public IX509Store GetCrls(
+			string type)
+		{
+			if (crlStore == null)
+			{
+				crlStore = Helper.CreateCrlStore(type, signedData.CRLs);
+			}
+
+			return crlStore;
+		}
+
+		[Obsolete("Use 'SignedContentType' property instead.")]
+		public string SignedContentTypeOid
+		{
+			get { return signedData.EncapContentInfo.ContentType.Id; }
+		}
+
+		/// <summary>
+		/// Return the <c>DerObjectIdentifier</c> associated with the encapsulated
+		/// content info structure carried in the signed data.
+		/// </summary>
+		public DerObjectIdentifier SignedContentType
+		{
+			get { return signedData.EncapContentInfo.ContentType; }
+		}
+
+		public CmsProcessable SignedContent
+		{
+			get { return signedContent; }
+		}
+
+		/**
+		 * return the ContentInfo
+		 */
+		public ContentInfo ContentInfo
+		{
+			get { return contentInfo; }
+		}
+
+		/**
+		* return the ASN.1 encoded representation of this object.
+		*/
+		public byte[] GetEncoded()
+		{
+			return contentInfo.GetEncoded();
+		}
+
+		/**
+		* Replace the signerinformation store associated with this
+		* CmsSignedData object with the new one passed in. You would
+		* probably only want to do this if you wanted to change the unsigned
+		* attributes associated with a signer, or perhaps delete one.
+		*
+		* @param signedData the signed data object to be used as a base.
+		* @param signerInformationStore the new signer information store to use.
+		* @return a new signed data object.
+		*/
+		public static CmsSignedData ReplaceSigners(
+			CmsSignedData           signedData,
+			SignerInformationStore  signerInformationStore)
+		{
+			//
+			// copy
+			//
+			CmsSignedData cms = new CmsSignedData(signedData);
+
+			//
+			// replace the store
+			//
+			cms.signerInfoStore = signerInformationStore;
+
+			//
+			// replace the signers in the SignedData object
+			//
+			Asn1EncodableVector digestAlgs = new Asn1EncodableVector();
+			Asn1EncodableVector vec = new Asn1EncodableVector();
+
+			foreach (SignerInformation signer in signerInformationStore.GetSigners())
+			{
+				digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID));
+				vec.Add(signer.ToSignerInfo());
+			}
+
+			Asn1Set digests = new DerSet(digestAlgs);
+			Asn1Set signers = new DerSet(vec);
+			Asn1Sequence sD = (Asn1Sequence)signedData.signedData.ToAsn1Object();
+
+			//
+			// signers are the last item in the sequence.
+			//
+			vec = new Asn1EncodableVector(
+				sD[0], // version
+				digests);
+
+			for (int i = 2; i != sD.Count - 1; i++)
+			{
+				vec.Add(sD[i]);
+			}
+
+			vec.Add(signers);
+
+			cms.signedData = SignedData.GetInstance(new BerSequence(vec));
+
+			//
+			// replace the contentInfo with the new one
+			//
+			cms.contentInfo = new ContentInfo(cms.contentInfo.ContentType, cms.signedData);
+
+			return cms;
+		}
+
+		/**
+		* Replace the certificate and CRL information associated with this
+		* CmsSignedData object with the new one passed in.
+		*
+		* @param signedData the signed data object to be used as a base.
+		* @param x509Certs the new certificates to be used.
+		* @param x509Crls the new CRLs to be used.
+		* @return a new signed data object.
+		* @exception CmsException if there is an error processing the stores
+		*/
+		public static CmsSignedData ReplaceCertificatesAndCrls(
+			CmsSignedData	signedData,
+			IX509Store		x509Certs,
+			IX509Store		x509Crls,
+			IX509Store		x509AttrCerts)
+		{
+			if (x509AttrCerts != null)
+				throw Platform.CreateNotImplementedException("Currently can't replace attribute certificates");
+
+			//
+			// copy
+			//
+			CmsSignedData cms = new CmsSignedData(signedData);
+
+			//
+			// replace the certs and crls in the SignedData object
+			//
+			Asn1Set certs = null;
+			try
+			{
+				Asn1Set asn1Set = CmsUtilities.CreateBerSetFromList(
+					CmsUtilities.GetCertificatesFromStore(x509Certs));
+
+				if (asn1Set.Count != 0)
+				{
+					certs = asn1Set;
+				}
+			}
+			catch (X509StoreException e)
+			{
+				throw new CmsException("error getting certificates from store", e);
+			}
+
+			Asn1Set crls = null;
+			try
+			{
+				Asn1Set asn1Set = CmsUtilities.CreateBerSetFromList(
+					CmsUtilities.GetCrlsFromStore(x509Crls));
+
+				if (asn1Set.Count != 0)
+				{
+					crls = asn1Set;
+				}
+			}
+			catch (X509StoreException e)
+			{
+				throw new CmsException("error getting CRLs from store", e);
+			}
+
+			//
+			// replace the CMS structure.
+			//
+			SignedData old = signedData.signedData;
+			cms.signedData = new SignedData(
+				old.DigestAlgorithms,
+				old.EncapContentInfo,
+				certs,
+				crls,
+				old.SignerInfos);
+
+			//
+			// replace the contentInfo with the new one
+			//
+			cms.contentInfo = new ContentInfo(cms.contentInfo.ContentType, cms.signedData);
+
+			return cms;
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSSignedDataGenerator.cs b/crypto/src/cms/CMSSignedDataGenerator.cs
index 5b68c785d..f31105c41 100644
--- a/crypto/src/cms/CMSSignedDataGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataGenerator.cs
@@ -108,8 +108,8 @@ namespace Org.BouncyCastle.Cms
 				outer._digests.Add(digestOID, hash.Clone());
 
 				sig.Init(true, new ParametersWithRandom(key, random));
-#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
-                Stream sigStr = new SigOutputStream(sig);
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
+				Stream sigStr = new SigOutputStream(sig);
 #else
 				Stream sigStr = new BufferedStream(new SigOutputStream(sig));
 #endif
@@ -145,7 +145,7 @@ namespace Org.BouncyCastle.Cms
 					content.Write(sigStr);
                 }
 
-                sigStr.Dispose();
+				sigStr.Close();
 				byte[] sigBytes = sig.GenerateSignature();
 
 				Asn1Set unsignedAttr = null;
diff --git a/crypto/src/cms/CMSSignedDataParser.cs b/crypto/src/cms/CMSSignedDataParser.cs
index dd794ee77..e5674a4cf 100644
--- a/crypto/src/cms/CMSSignedDataParser.cs
+++ b/crypto/src/cms/CMSSignedDataParser.cs
@@ -170,11 +170,6 @@ namespace Org.BouncyCastle.Cms
 			{
 				throw new CmsException("io exception: " + e.Message, e);
 			}
-
-			if (_digests.Count < 1)
-			{
-				throw new CmsException("no digests could be created for message.");
-			}
 		}
 
 		/**
@@ -389,7 +384,7 @@ namespace Org.BouncyCastle.Cms
 
 //			gen.AddSigners(parser.GetSignerInfos());
 
-            contentOut.Dispose();
+			contentOut.Close();
 
 			return outStr;
 		}
@@ -439,7 +434,7 @@ namespace Org.BouncyCastle.Cms
 
 			gen.AddSigners(parser.GetSignerInfos());
 
-            contentOut.Dispose();
+			contentOut.Close();
 
 			return outStr;
 		}
diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
index 0bed9fcad..743e9c6c1 100644
--- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
@@ -636,7 +636,7 @@ namespace Org.BouncyCastle.Cms
 			{
 				content.Write(signedOut);
 			}
-            signedOut.Dispose();
+			signedOut.Close();
 		}
 
 		// RFC3852, section 5.1:
@@ -809,100 +809,96 @@ namespace Org.BouncyCastle.Cms
                 _out.Write(bytes, off, len);
             }
 
-            protected override void Dispose(bool disposing)
+			public override void Close()
             {
-                if (disposing)
-                {
-                    _out.Dispose();
+                _out.Close();
 
-                    // TODO Parent context(s) should really be be closed explicitly
+				// TODO Parent context(s) should really be be closed explicitly
 
-                    _eiGen.Close();
+                _eiGen.Close();
 
-                    outer._digests.Clear();    // clear the current preserved digest state
+				outer._digests.Clear();    // clear the current preserved digest state
 
-                    if (outer._certs.Count > 0)
-                    {
-                        Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs);
+				if (outer._certs.Count > 0)
+				{
+					Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs);
 
-                        WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs));
-                    }
+					WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs));
+				}
 
-                    if (outer._crls.Count > 0)
-                    {
-                        Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._crls);
+				if (outer._crls.Count > 0)
+				{
+					Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._crls);
 
-                        WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, crls));
-                    }
+					WriteToGenerator(_sigGen, new BerTaggedObject(false, 1, crls));
+				}
 
-                    //
-                    // Calculate the digest hashes
-                    //
-                    foreach (DictionaryEntry de in outer._messageDigests)
-                    {
-                        outer._messageHashes.Add(de.Key, DigestUtilities.DoFinal((IDigest)de.Value));
-                    }
+				//
+				// Calculate the digest hashes
+				//
+				foreach (DictionaryEntry de in outer._messageDigests)
+				{
+					outer._messageHashes.Add(de.Key, DigestUtilities.DoFinal((IDigest)de.Value));
+				}
 
-                    // TODO If the digest OIDs for precalculated signers weren't mixed in with
-                    // the others, we could fill in outer._digests here, instead of SignerInfoGenerator.Generate
+				// TODO If the digest OIDs for precalculated signers weren't mixed in with
+				// the others, we could fill in outer._digests here, instead of SignerInfoGenerator.Generate
 
-                    //
-                    // collect all the SignerInfo objects
-                    //
-                    Asn1EncodableVector signerInfos = new Asn1EncodableVector();
+				//
+				// collect all the SignerInfo objects
+				//
+                Asn1EncodableVector signerInfos = new Asn1EncodableVector();
 
-                    //
-                    // add the generated SignerInfo objects
-                    //
-                    {
-                        foreach (DigestAndSignerInfoGeneratorHolder holder in outer._signerInfs)
-                        {
-                            AlgorithmIdentifier digestAlgorithm = holder.DigestAlgorithm;
+				//
+                // add the generated SignerInfo objects
+                //
+				{
+					foreach (DigestAndSignerInfoGeneratorHolder holder in outer._signerInfs)
+					{
+						AlgorithmIdentifier digestAlgorithm = holder.DigestAlgorithm;
 
-                            byte[] calculatedDigest = (byte[])outer._messageHashes[
-                                Helper.GetDigestAlgName(holder.digestOID)];
-                            outer._digests[holder.digestOID] = calculatedDigest.Clone();
+						byte[] calculatedDigest = (byte[])outer._messageHashes[
+							Helper.GetDigestAlgName(holder.digestOID)];
+						outer._digests[holder.digestOID] = calculatedDigest.Clone();
 
-                            signerInfos.Add(holder.signerInf.Generate(_contentOID, digestAlgorithm, calculatedDigest));
-                        }
-                    }
+						signerInfos.Add(holder.signerInf.Generate(_contentOID, digestAlgorithm, calculatedDigest));
+	                }
+				}
 
-                    //
-                    // add the precalculated SignerInfo objects.
-                    //
-                    {
-                        foreach (SignerInformation signer in outer._signers)
-                        {
-                            // TODO Verify the content type and calculated digest match the precalculated SignerInfo
-                            //						if (!signer.ContentType.Equals(_contentOID))
-                            //						{
-                            //							// TODO The precalculated content type did not match - error?
-                            //						}
-                            //
-                            //						byte[] calculatedDigest = (byte[])outer._digests[signer.DigestAlgOid];
-                            //						if (calculatedDigest == null)
-                            //						{
-                            //							// TODO We can't confirm this digest because we didn't calculate it - error?
-                            //						}
-                            //						else
-                            //						{
-                            //							if (!Arrays.AreEqual(signer.GetContentDigest(), calculatedDigest))
-                            //							{
-                            //								// TODO The precalculated digest did not match - error?
-                            //							}
-                            //						}
-
-                            signerInfos.Add(signer.ToSignerInfo());
-                        }
-                    }
+				//
+                // add the precalculated SignerInfo objects.
+                //
+				{
+					foreach (SignerInformation signer in outer._signers)
+					{
+						// TODO Verify the content type and calculated digest match the precalculated SignerInfo
+//						if (!signer.ContentType.Equals(_contentOID))
+//						{
+//							// TODO The precalculated content type did not match - error?
+//						}
+//
+//						byte[] calculatedDigest = (byte[])outer._digests[signer.DigestAlgOid];
+//						if (calculatedDigest == null)
+//						{
+//							// TODO We can't confirm this digest because we didn't calculate it - error?
+//						}
+//						else
+//						{
+//							if (!Arrays.AreEqual(signer.GetContentDigest(), calculatedDigest))
+//							{
+//								// TODO The precalculated digest did not match - error?
+//							}
+//						}
 
-                    WriteToGenerator(_sigGen, new DerSet(signerInfos));
+						signerInfos.Add(signer.ToSignerInfo());
+	                }
+				}
 
-                    _sigGen.Close();
-                    _sGen.Close();
-                }
+				WriteToGenerator(_sigGen, new DerSet(signerInfos));
 
-				base.Dispose(disposing);
+				_sigGen.Close();
+                _sGen.Close();
+				base.Close();
 			}
 
 			private static void WriteToGenerator(
diff --git a/crypto/src/cms/CMSSignedGenerator.cs b/crypto/src/cms/CMSSignedGenerator.cs
new file mode 100644
index 000000000..f272c830e
--- /dev/null
+++ b/crypto/src/cms/CMSSignedGenerator.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+    public class CmsSignedGenerator
+    {
+        /**
+        * Default type for the signed data.
+        */
+        public static readonly string Data = CmsObjectIdentifiers.Data.Id;
+
+		public static readonly string DigestSha1 = OiwObjectIdentifiers.IdSha1.Id;
+        public static readonly string DigestSha224 = NistObjectIdentifiers.IdSha224.Id;
+        public static readonly string DigestSha256 = NistObjectIdentifiers.IdSha256.Id;
+        public static readonly string DigestSha384 = NistObjectIdentifiers.IdSha384.Id;
+        public static readonly string DigestSha512 = NistObjectIdentifiers.IdSha512.Id;
+        public static readonly string DigestMD5 = PkcsObjectIdentifiers.MD5.Id;
+        public static readonly string DigestGost3411 = CryptoProObjectIdentifiers.GostR3411.Id;
+		public static readonly string DigestRipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
+		public static readonly string DigestRipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
+		public static readonly string DigestRipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
+
+		public static readonly string EncryptionRsa = PkcsObjectIdentifiers.RsaEncryption.Id;
+        public static readonly string EncryptionDsa = X9ObjectIdentifiers.IdDsaWithSha1.Id;
+        public static readonly string EncryptionECDsa = X9ObjectIdentifiers.ECDsaWithSha1.Id;
+        public static readonly string EncryptionRsaPss = PkcsObjectIdentifiers.IdRsassaPss.Id;
+        public static readonly string EncryptionGost3410 = CryptoProObjectIdentifiers.GostR3410x94.Id;
+        public static readonly string EncryptionECGost3410 = CryptoProObjectIdentifiers.GostR3410x2001.Id;
+
+		private static readonly string EncryptionECDsaWithSha1 = X9ObjectIdentifiers.ECDsaWithSha1.Id;
+		private static readonly string EncryptionECDsaWithSha224 = X9ObjectIdentifiers.ECDsaWithSha224.Id;
+		private static readonly string EncryptionECDsaWithSha256 = X9ObjectIdentifiers.ECDsaWithSha256.Id;
+		private static readonly string EncryptionECDsaWithSha384 = X9ObjectIdentifiers.ECDsaWithSha384.Id;
+		private static readonly string EncryptionECDsaWithSha512 = X9ObjectIdentifiers.ECDsaWithSha512.Id;
+
+		private static readonly ISet noParams = new HashSet();
+		private static readonly IDictionary ecAlgorithms = Platform.CreateHashtable();
+
+		static CmsSignedGenerator()
+		{
+			noParams.Add(EncryptionDsa);
+//			noParams.Add(EncryptionECDsa);
+			noParams.Add(EncryptionECDsaWithSha1);
+			noParams.Add(EncryptionECDsaWithSha224);
+			noParams.Add(EncryptionECDsaWithSha256);
+			noParams.Add(EncryptionECDsaWithSha384);
+			noParams.Add(EncryptionECDsaWithSha512);
+
+			ecAlgorithms.Add(DigestSha1, EncryptionECDsaWithSha1);
+			ecAlgorithms.Add(DigestSha224, EncryptionECDsaWithSha224);
+			ecAlgorithms.Add(DigestSha256, EncryptionECDsaWithSha256);
+			ecAlgorithms.Add(DigestSha384, EncryptionECDsaWithSha384);
+			ecAlgorithms.Add(DigestSha512, EncryptionECDsaWithSha512);
+		}
+
+		internal IList _certs = Platform.CreateArrayList();
+        internal IList _crls = Platform.CreateArrayList();
+		internal IList _signers = Platform.CreateArrayList();
+		internal IDictionary _digests = Platform.CreateHashtable();
+
+		protected readonly SecureRandom rand;
+
+		protected CmsSignedGenerator()
+			: this(new SecureRandom())
+		{
+		}
+
+		/// <summary>Constructor allowing specific source of randomness</summary>
+		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+		protected CmsSignedGenerator(
+			SecureRandom rand)
+		{
+			this.rand = rand;
+		}
+
+		protected string GetEncOid(
+            AsymmetricKeyParameter	key,
+            string					digestOID)
+        {
+            string encOID = null;
+
+			if (key is RsaKeyParameters)
+			{
+				if (!((RsaKeyParameters) key).IsPrivate)
+					throw new ArgumentException("Expected RSA private key");
+
+				encOID = EncryptionRsa;
+			}
+			else if (key is DsaPrivateKeyParameters)
+			{
+				if (!digestOID.Equals(DigestSha1))
+					throw new ArgumentException("can't mix DSA with anything but SHA1");
+
+				encOID = EncryptionDsa;
+			}
+			else if (key is ECPrivateKeyParameters)
+			{
+				ECPrivateKeyParameters ecPrivKey = (ECPrivateKeyParameters) key;
+				string algName = ecPrivKey.AlgorithmName;
+
+				if (algName == "ECGOST3410")
+				{
+					encOID = EncryptionECGost3410;
+				}
+				else
+				{
+					// TODO Should we insist on algName being one of "EC" or "ECDSA", as Java does?
+					encOID = (string) ecAlgorithms[digestOID];
+
+					if (encOID == null)
+						throw new ArgumentException("can't mix ECDSA with anything but SHA family digests");
+				}
+			}
+			else if (key is Gost3410PrivateKeyParameters)
+			{
+				encOID = EncryptionGost3410;
+			}
+			else
+			{
+				throw new ArgumentException("Unknown algorithm in CmsSignedGenerator.GetEncOid");
+			}
+
+			return encOID;
+        }
+
+		internal static AlgorithmIdentifier GetEncAlgorithmIdentifier(
+			DerObjectIdentifier	encOid,
+			Asn1Encodable		sigX509Parameters)
+		{
+			if (noParams.Contains(encOid.Id))
+			{
+				return new AlgorithmIdentifier(encOid);
+			}
+
+			return new AlgorithmIdentifier(encOid, sigX509Parameters);
+		}
+
+		internal protected virtual IDictionary GetBaseParameters(
+			DerObjectIdentifier	contentType,
+			AlgorithmIdentifier	digAlgId,
+			byte[]				hash)
+		{
+			IDictionary param = Platform.CreateHashtable();
+
+            if (contentType != null)
+            {
+                param[CmsAttributeTableParameter.ContentType] = contentType;
+            }
+
+			param[CmsAttributeTableParameter.DigestAlgorithmIdentifier] = digAlgId;
+            param[CmsAttributeTableParameter.Digest] = hash.Clone();
+
+            return param;
+		}
+
+		internal protected virtual Asn1Set GetAttributeSet(
+            Asn1.Cms.AttributeTable attr)
+        {
+			return attr == null
+				?	null
+				:	new DerSet(attr.ToAsn1EncodableVector());
+        }
+
+		public void AddCertificates(
+			IX509Store certStore)
+		{
+            CollectionUtilities.AddRange(_certs, CmsUtilities.GetCertificatesFromStore(certStore));
+        }
+
+		public void AddCrls(
+			IX509Store crlStore)
+		{
+            CollectionUtilities.AddRange(_crls, CmsUtilities.GetCrlsFromStore(crlStore));
+		}
+
+		/**
+		* Add the attribute certificates contained in the passed in store to the
+		* generator.
+		*
+		* @param store a store of Version 2 attribute certificates
+		* @throws CmsException if an error occurse processing the store.
+		*/
+		public void AddAttributeCertificates(
+			IX509Store store)
+		{
+			try
+			{
+				foreach (IX509AttributeCertificate attrCert in store.GetMatches(null))
+				{
+					_certs.Add(new DerTaggedObject(false, 2,
+						AttributeCertificate.GetInstance(Asn1Object.FromByteArray(attrCert.GetEncoded()))));
+				}
+			}
+			catch (Exception e)
+			{
+				throw new CmsException("error processing attribute certs", e);
+			}
+		}
+
+		/**
+		 * Add a store of precalculated signers to the generator.
+		 *
+		 * @param signerStore store of signers
+		 */
+		public void AddSigners(
+			SignerInformationStore signerStore)
+		{
+			foreach (SignerInformation o in signerStore.GetSigners())
+			{
+				_signers.Add(o);
+				AddSignerCallback(o);
+			}
+		}
+
+		/**
+		 * Return a map of oids and byte arrays representing the digests calculated on the content during
+		 * the last generate.
+		 *
+		 * @return a map of oids (as String objects) and byte[] representing digests.
+		 */
+		public IDictionary GetGeneratedDigests()
+		{
+			return Platform.CreateHashtable(_digests);
+		}
+
+		internal virtual void AddSignerCallback(
+			SignerInformation si)
+		{
+		}
+
+		internal static SignerIdentifier GetSignerIdentifier(X509Certificate cert)
+		{
+			return new SignerIdentifier(CmsUtilities.GetIssuerAndSerialNumber(cert));
+		}
+
+		internal static SignerIdentifier GetSignerIdentifier(byte[] subjectKeyIdentifier)
+		{
+			return new SignerIdentifier(new DerOctetString(subjectKeyIdentifier));    
+		}
+	}
+}
diff --git a/crypto/src/cms/CMSSignedHelper.cs b/crypto/src/cms/CMSSignedHelper.cs
new file mode 100644
index 000000000..b3406fc06
--- /dev/null
+++ b/crypto/src/cms/CMSSignedHelper.cs
@@ -0,0 +1,319 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Eac;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+    internal class CmsSignedHelper
+    {
+        internal static readonly CmsSignedHelper Instance = new CmsSignedHelper();
+
+		private static readonly IDictionary encryptionAlgs = Platform.CreateHashtable();
+        private static readonly IDictionary digestAlgs = Platform.CreateHashtable();
+        private static readonly IDictionary digestAliases = Platform.CreateHashtable();
+
+		private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption)
+		{
+			string alias = oid.Id;
+			digestAlgs.Add(alias, digest);
+			encryptionAlgs.Add(alias, encryption);
+		}
+
+		static CmsSignedHelper()
+		{
+			AddEntries(NistObjectIdentifiers.DsaWithSha224, "SHA224", "DSA");
+			AddEntries(NistObjectIdentifiers.DsaWithSha256, "SHA256", "DSA");
+			AddEntries(NistObjectIdentifiers.DsaWithSha384, "SHA384", "DSA");
+			AddEntries(NistObjectIdentifiers.DsaWithSha512, "SHA512", "DSA");
+			AddEntries(OiwObjectIdentifiers.DsaWithSha1, "SHA1", "DSA");
+			AddEntries(OiwObjectIdentifiers.MD4WithRsa, "MD4", "RSA");
+			AddEntries(OiwObjectIdentifiers.MD4WithRsaEncryption, "MD4", "RSA");
+			AddEntries(OiwObjectIdentifiers.MD5WithRsa, "MD5", "RSA");
+			AddEntries(OiwObjectIdentifiers.Sha1WithRsa, "SHA1", "RSA");
+			AddEntries(PkcsObjectIdentifiers.MD2WithRsaEncryption, "MD2", "RSA");
+			AddEntries(PkcsObjectIdentifiers.MD4WithRsaEncryption, "MD4", "RSA");
+			AddEntries(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5", "RSA");
+			AddEntries(PkcsObjectIdentifiers.Sha1WithRsaEncryption, "SHA1", "RSA");
+			AddEntries(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224", "RSA");
+			AddEntries(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256", "RSA");
+			AddEntries(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384", "RSA");
+			AddEntries(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512", "RSA");
+			AddEntries(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1", "ECDSA");
+			AddEntries(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224", "ECDSA");
+			AddEntries(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256", "ECDSA");
+			AddEntries(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384", "ECDSA");
+			AddEntries(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512", "ECDSA");
+			AddEntries(X9ObjectIdentifiers.IdDsaWithSha1, "SHA1", "DSA");
+			AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1", "ECDSA");
+			AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224", "ECDSA");
+			AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256", "ECDSA");
+			AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384", "ECDSA");
+			AddEntries(EacObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512", "ECDSA");
+			AddEntries(EacObjectIdentifiers.id_TA_RSA_v1_5_SHA_1, "SHA1", "RSA");
+			AddEntries(EacObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA");
+			AddEntries(EacObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1");
+			AddEntries(EacObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1");
+
+			encryptionAlgs.Add(X9ObjectIdentifiers.IdDsa.Id, "DSA");
+			encryptionAlgs.Add(PkcsObjectIdentifiers.RsaEncryption.Id, "RSA");
+			encryptionAlgs.Add(TeleTrusTObjectIdentifiers.TeleTrusTRsaSignatureAlgorithm, "RSA");
+			encryptionAlgs.Add(X509ObjectIdentifiers.IdEARsa.Id, "RSA");
+			encryptionAlgs.Add(CmsSignedGenerator.EncryptionRsaPss, "RSAandMGF1");
+			encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x94.Id, "GOST3410");
+			encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x2001.Id, "ECGOST3410");
+			encryptionAlgs.Add("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410");
+			encryptionAlgs.Add("1.3.6.1.4.1.5849.1.1.5", "GOST3410");
+
+			digestAlgs.Add(PkcsObjectIdentifiers.MD2.Id, "MD2");
+			digestAlgs.Add(PkcsObjectIdentifiers.MD4.Id, "MD4");
+			digestAlgs.Add(PkcsObjectIdentifiers.MD5.Id, "MD5");
+			digestAlgs.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1");
+			digestAlgs.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224");
+			digestAlgs.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256");
+			digestAlgs.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384");
+			digestAlgs.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512");
+			digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128");
+			digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160");
+			digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256");
+			digestAlgs.Add(CryptoProObjectIdentifiers.GostR3411.Id,  "GOST3411");
+			digestAlgs.Add("1.3.6.1.4.1.5849.1.2.1",  "GOST3411");
+
+			digestAliases.Add("SHA1", new string[] { "SHA-1" });
+			digestAliases.Add("SHA224", new string[] { "SHA-224" });
+			digestAliases.Add("SHA256", new string[] { "SHA-256" });
+			digestAliases.Add("SHA384", new string[] { "SHA-384" });
+			digestAliases.Add("SHA512", new string[] { "SHA-512" });
+		}
+
+		/**
+        * Return the digest algorithm using one of the standard JCA string
+        * representations rather than the algorithm identifier (if possible).
+        */
+        internal string GetDigestAlgName(
+            string digestAlgOid)
+        {
+			string algName = (string)digestAlgs[digestAlgOid];
+
+			if (algName != null)
+			{
+				return algName;
+			}
+
+			return digestAlgOid;
+        }
+
+		internal string[] GetDigestAliases(
+			string algName)
+		{
+			string[] aliases = (string[]) digestAliases[algName];
+
+			return aliases == null ? new String[0] : (string[]) aliases.Clone();
+		}
+
+		/**
+        * Return the digest encryption algorithm using one of the standard
+        * JCA string representations rather than the algorithm identifier (if
+        * possible).
+        */
+        internal string GetEncryptionAlgName(
+            string encryptionAlgOid)
+        {
+			string algName = (string) encryptionAlgs[encryptionAlgOid];
+
+			if (algName != null)
+			{
+				return algName;
+			}
+
+			return encryptionAlgOid;
+        }
+
+		internal IDigest GetDigestInstance(
+			string algorithm)
+		{
+			try
+			{
+				return DigestUtilities.GetDigest(algorithm);
+			}
+			catch (SecurityUtilityException e)
+			{
+				// This is probably superfluous on C#, since no provider infrastructure,
+				// assuming DigestUtilities already knows all the aliases
+				foreach (string alias in GetDigestAliases(algorithm))
+				{
+					try { return DigestUtilities.GetDigest(alias); }
+					catch (SecurityUtilityException) {}
+				}
+				throw e;
+			}
+		}
+
+		internal ISigner GetSignatureInstance(
+			string algorithm)
+		{
+			return SignerUtilities.GetSigner(algorithm);
+		}
+
+		internal IX509Store CreateAttributeStore(
+			string	type,
+			Asn1Set	certSet)
+		{
+			IList certs = Platform.CreateArrayList();
+
+			if (certSet != null)
+			{
+				foreach (Asn1Encodable ae in certSet)
+				{
+					try
+					{
+						Asn1Object obj = ae.ToAsn1Object();
+
+						if (obj is Asn1TaggedObject)
+						{
+							Asn1TaggedObject tagged = (Asn1TaggedObject)obj;
+
+							if (tagged.TagNo == 2)
+							{
+								certs.Add(
+									new X509V2AttributeCertificate(
+										Asn1Sequence.GetInstance(tagged, false).GetEncoded()));
+							}
+						}
+					}
+					catch (Exception ex)
+					{
+						throw new CmsException("can't re-encode attribute certificate!", ex);
+					}
+				}
+			}
+
+			try
+			{
+				return X509StoreFactory.Create(
+					"AttributeCertificate/" + type,
+					new X509CollectionStoreParameters(certs));
+			}
+			catch (ArgumentException e)
+			{
+				throw new CmsException("can't setup the X509Store", e);
+			}
+		}
+
+		internal IX509Store CreateCertificateStore(
+			string	type,
+			Asn1Set	certSet)
+		{
+			IList certs = Platform.CreateArrayList();
+
+			if (certSet != null)
+			{
+				AddCertsFromSet(certs, certSet);
+			}
+
+			try
+			{
+				return X509StoreFactory.Create(
+					"Certificate/" + type,
+					new X509CollectionStoreParameters(certs));
+			}
+			catch (ArgumentException e)
+			{
+				throw new CmsException("can't setup the X509Store", e);
+			}
+		}
+
+		internal IX509Store CreateCrlStore(
+			string	type,
+			Asn1Set	crlSet)
+		{
+			IList crls = Platform.CreateArrayList();
+
+			if (crlSet != null)
+			{
+				AddCrlsFromSet(crls, crlSet);
+			}
+
+			try
+			{
+				return X509StoreFactory.Create(
+					"CRL/" + type,
+					new X509CollectionStoreParameters(crls));
+			}
+			catch (ArgumentException e)
+			{
+				throw new CmsException("can't setup the X509Store", e);
+			}
+		}
+
+		private void AddCertsFromSet(
+			IList	certs,
+			Asn1Set	certSet)
+		{
+			X509CertificateParser cf = new X509CertificateParser();
+
+			foreach (Asn1Encodable ae in certSet)
+			{
+				try
+				{
+					Asn1Object obj = ae.ToAsn1Object();
+
+					if (obj is Asn1Sequence)
+					{
+						// TODO Build certificate directly from sequence?
+						certs.Add(cf.ReadCertificate(obj.GetEncoded()));
+					}
+				}
+				catch (Exception ex)
+				{
+					throw new CmsException("can't re-encode certificate!", ex);
+				}
+			}
+		}
+
+		private void AddCrlsFromSet(
+			IList	crls,
+			Asn1Set	crlSet)
+		{
+			X509CrlParser cf = new X509CrlParser();
+
+			foreach (Asn1Encodable ae in crlSet)
+			{
+				try
+				{
+					// TODO Build CRL directly from ae.ToAsn1Object()?
+					crls.Add(cf.ReadCrl(ae.GetEncoded()));
+				}
+				catch (Exception ex)
+				{
+					throw new CmsException("can't re-encode CRL!", ex);
+				}
+			}
+		}
+
+		internal AlgorithmIdentifier FixAlgID(
+			AlgorithmIdentifier algId)
+		{
+			if (algId.Parameters == null)
+				return new AlgorithmIdentifier(algId.ObjectID, DerNull.Instance);
+
+			return algId;
+		}
+    }
+}
diff --git a/crypto/src/cms/CMSStreamException.cs b/crypto/src/cms/CMSStreamException.cs
index 1626fb8b4..bf0a6adf4 100644
--- a/crypto/src/cms/CMSStreamException.cs
+++ b/crypto/src/cms/CMSStreamException.cs
@@ -3,6 +3,9 @@ using System.IO;
 
 namespace Org.BouncyCastle.Cms
 {
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
     public class CmsStreamException
         : IOException
     {
diff --git a/crypto/src/cms/CMSTypedStream.cs b/crypto/src/cms/CMSTypedStream.cs
index 576edf234..9cb314211 100644
--- a/crypto/src/cms/CMSTypedStream.cs
+++ b/crypto/src/cms/CMSTypedStream.cs
@@ -33,7 +33,7 @@ namespace Org.BouncyCastle.Cms
 			int		bufSize)
 		{
 			_oid = oid;
-#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
 			_in = new FullReaderStream(inStream);
 #else
 			_in = new FullReaderStream(new BufferedStream(inStream, bufSize));
@@ -53,7 +53,7 @@ namespace Org.BouncyCastle.Cms
 		public void Drain()
 		{
 			Streams.Drain(_in);
-            _in.Dispose();
+			_in.Close();
 		}
 
 		private class FullReaderStream : FilterStream
diff --git a/crypto/src/cms/CMSUtils.cs b/crypto/src/cms/CMSUtils.cs
new file mode 100644
index 000000000..95d710607
--- /dev/null
+++ b/crypto/src/cms/CMSUtils.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+    internal class CmsUtilities
+    {
+		// TODO Is there a .NET equivalent to this?
+//		private static readonly Runtime RUNTIME = Runtime.getRuntime();
+
+		internal static int MaximumMemory
+		{
+			get
+			{
+				// TODO Is there a .NET equivalent to this?
+				long maxMem = int.MaxValue;//RUNTIME.maxMemory();
+
+				if (maxMem > int.MaxValue)
+				{
+					return int.MaxValue;
+				}
+
+				return (int)maxMem;
+			}
+		}
+
+		internal static ContentInfo ReadContentInfo(
+			byte[] input)
+		{
+			// enforce limit checking as from a byte array
+			return ReadContentInfo(new Asn1InputStream(input));
+		}
+
+		internal static ContentInfo ReadContentInfo(
+			Stream input)
+		{
+			// enforce some limit checking
+			return ReadContentInfo(new Asn1InputStream(input, MaximumMemory));
+		}
+
+		private static ContentInfo ReadContentInfo(
+			Asn1InputStream aIn)
+		{
+			try
+			{
+				return ContentInfo.GetInstance(aIn.ReadObject());
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("IOException reading content.", e);
+			}
+			catch (InvalidCastException e)
+			{
+				throw new CmsException("Malformed content.", e);
+			}
+			catch (ArgumentException e)
+			{
+				throw new CmsException("Malformed content.", e);
+			}
+		}
+
+		public static byte[] StreamToByteArray(
+            Stream inStream)
+        {
+			return Streams.ReadAll(inStream);
+        }
+
+		public static byte[] StreamToByteArray(
+            Stream	inStream,
+			int		limit)
+        {
+			return Streams.ReadAllLimited(inStream, limit);
+        }
+
+		public static IList GetCertificatesFromStore(
+			IX509Store certStore)
+		{
+			try
+			{
+				IList certs = Platform.CreateArrayList();
+
+				if (certStore != null)
+				{
+					foreach (X509Certificate c in certStore.GetMatches(null))
+					{
+						certs.Add(
+							X509CertificateStructure.GetInstance(
+								Asn1Object.FromByteArray(c.GetEncoded())));
+					}
+				}
+
+				return certs;
+			}
+			catch (CertificateEncodingException e)
+			{
+				throw new CmsException("error encoding certs", e);
+			}
+			catch (Exception e)
+			{
+				throw new CmsException("error processing certs", e);
+			}
+		}
+
+		public static IList GetCrlsFromStore(
+			IX509Store crlStore)
+		{
+			try
+			{
+                IList crls = Platform.CreateArrayList();
+
+				if (crlStore != null)
+				{
+					foreach (X509Crl c in crlStore.GetMatches(null))
+					{
+						crls.Add(
+							CertificateList.GetInstance(
+								Asn1Object.FromByteArray(c.GetEncoded())));
+					}
+				}
+
+				return crls;
+			}
+			catch (CrlException e)
+			{
+				throw new CmsException("error encoding crls", e);
+			}
+			catch (Exception e)
+			{
+				throw new CmsException("error processing crls", e);
+			}
+		}
+
+		public static Asn1Set CreateBerSetFromList(
+			IList berObjects)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (Asn1Encodable ae in berObjects)
+			{
+				v.Add(ae);
+			}
+
+			return new BerSet(v);
+		}
+
+		public static Asn1Set CreateDerSetFromList(
+			IList derObjects)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (Asn1Encodable ae in derObjects)
+			{
+				v.Add(ae);
+			}
+
+			return new DerSet(v);
+		}
+
+		internal static Stream CreateBerOctetOutputStream(Stream s, int tagNo, bool isExplicit, int bufferSize)
+		{
+			BerOctetStringGenerator octGen = new BerOctetStringGenerator(s, tagNo, isExplicit);
+			return octGen.GetOctetOutputStream(bufferSize);
+		}
+
+		internal static TbsCertificateStructure GetTbsCertificateStructure(X509Certificate cert)
+		{
+			return TbsCertificateStructure.GetInstance(Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+		}
+
+		internal static IssuerAndSerialNumber GetIssuerAndSerialNumber(X509Certificate cert)
+		{
+			TbsCertificateStructure tbsCert = GetTbsCertificateStructure(cert);
+			return new IssuerAndSerialNumber(tbsCert.Issuer, tbsCert.SerialNumber.Value);
+		}
+	}
+}
diff --git a/crypto/src/cms/CounterSignatureDigestCalculator.cs b/crypto/src/cms/CounterSignatureDigestCalculator.cs
new file mode 100644
index 000000000..6f8bf65a2
--- /dev/null
+++ b/crypto/src/cms/CounterSignatureDigestCalculator.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class CounterSignatureDigestCalculator
+		: IDigestCalculator
+	{
+		private readonly string alg;
+		private readonly byte[] data;
+
+		internal CounterSignatureDigestCalculator(
+			string	alg,
+			byte[]	data)
+		{
+			this.alg = alg;
+			this.data = data;
+		}
+
+		public byte[] GetDigest()
+		{
+			IDigest digest = CmsSignedHelper.Instance.GetDigestInstance(alg);
+			return DigestUtilities.DoFinal(digest, data);
+		}
+	}
+}
diff --git a/crypto/src/cms/DefaultAuthenticatedAttributeTableGenerator.cs b/crypto/src/cms/DefaultAuthenticatedAttributeTableGenerator.cs
new file mode 100644
index 000000000..d49b1d9d2
--- /dev/null
+++ b/crypto/src/cms/DefaultAuthenticatedAttributeTableGenerator.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	 * Default authenticated attributes generator.
+	 */
+	public class DefaultAuthenticatedAttributeTableGenerator
+		: CmsAttributeTableGenerator
+	{
+		private readonly IDictionary table;
+
+		/**
+		 * Initialise to use all defaults
+		 */
+		public DefaultAuthenticatedAttributeTableGenerator()
+		{
+			table = Platform.CreateHashtable();
+		}
+
+		/**
+		 * Initialise with some extra attributes or overrides.
+		 *
+		 * @param attributeTable initial attribute table to use.
+		 */
+		public DefaultAuthenticatedAttributeTableGenerator(
+			AttributeTable attributeTable)
+		{
+			if (attributeTable != null)
+			{
+				table = attributeTable.ToDictionary();
+			}
+			else
+			{
+				table = Platform.CreateHashtable();
+			}
+		}
+
+		/**
+		 * Create a standard attribute table from the passed in parameters - this will
+		 * normally include contentType and messageDigest. If the constructor
+		 * using an AttributeTable was used, entries in it for contentType and
+		 * messageDigest will override the generated ones.
+		 *
+		 * @param parameters source parameters for table generation.
+		 *
+		 * @return a filled in IDictionary of attributes.
+		 */
+		protected virtual IDictionary CreateStandardAttributeTable(
+			IDictionary parameters)
+		{
+            IDictionary std = Platform.CreateHashtable(table);
+
+			if (!std.Contains(CmsAttributes.ContentType))
+            {
+                DerObjectIdentifier contentType = (DerObjectIdentifier)
+                    parameters[CmsAttributeTableParameter.ContentType];
+                Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.ContentType,
+                    new DerSet(contentType));
+                std[attr.AttrType] = attr;
+            }
+
+			if (!std.Contains(CmsAttributes.MessageDigest))
+            {
+                byte[] messageDigest = (byte[])parameters[CmsAttributeTableParameter.Digest];
+                Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.MessageDigest,
+                    new DerSet(new DerOctetString(messageDigest)));
+                std[attr.AttrType] = attr;
+            }
+
+            return std;
+		}
+
+        /**
+		 * @param parameters source parameters
+		 * @return the populated attribute table
+		 */
+		public virtual AttributeTable GetAttributes(
+			IDictionary parameters)
+		{
+            IDictionary table = CreateStandardAttributeTable(parameters);
+			return new AttributeTable(table);
+		}
+	}
+}
diff --git a/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs b/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
index 0e93392d9..055de8957 100644
--- a/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
+++ b/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
@@ -41,8 +41,8 @@ namespace Org.BouncyCastle.Cms
 			}
 		}
 
-#if (SILVERLIGHT || PORTABLE)
-        /**
+#if SILVERLIGHT
+		/**
 		 * Create a standard attribute table from the passed in parameters - this will
 		 * normally include contentType, signingTime, and messageDigest. If the constructor
 		 * using an AttributeTable was used, entries in it for contentType, signingTime, and
diff --git a/crypto/src/cms/DigOutputStream.cs b/crypto/src/cms/DigOutputStream.cs
new file mode 100644
index 000000000..103b45cac
--- /dev/null
+++ b/crypto/src/cms/DigOutputStream.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class DigOutputStream
+		: BaseOutputStream
+	{
+		private readonly IDigest dig;
+
+		internal DigOutputStream(IDigest dig)
+		{
+			this.dig = dig;
+		}
+
+		public override void WriteByte(byte b)
+		{
+			dig.Update(b);
+		}
+
+		public override void Write(byte[] b, int off, int len)
+		{
+			dig.BlockUpdate(b, off, len);
+		}
+	}
+}
diff --git a/crypto/src/cms/IDigestCalculator.cs b/crypto/src/cms/IDigestCalculator.cs
new file mode 100644
index 000000000..3661e4023
--- /dev/null
+++ b/crypto/src/cms/IDigestCalculator.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal interface IDigestCalculator
+	{
+		byte[] GetDigest();
+	}
+}
diff --git a/crypto/src/cms/KEKRecipientInfoGenerator.cs b/crypto/src/cms/KEKRecipientInfoGenerator.cs
new file mode 100644
index 000000000..a9bedade6
--- /dev/null
+++ b/crypto/src/cms/KEKRecipientInfoGenerator.cs
@@ -0,0 +1,137 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class KekRecipientInfoGenerator : RecipientInfoGenerator
+	{
+		private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+		private KeyParameter	keyEncryptionKey;
+		// TODO Can get this from keyEncryptionKey?		
+		private string			keyEncryptionKeyOID;
+		private KekIdentifier	kekIdentifier;
+
+		// Derived
+		private AlgorithmIdentifier keyEncryptionAlgorithm;
+
+		internal KekRecipientInfoGenerator()
+		{
+		}
+
+		internal KekIdentifier KekIdentifier
+		{
+			set { this.kekIdentifier = value; }
+		}
+
+		internal KeyParameter KeyEncryptionKey
+		{
+			set
+			{
+				this.keyEncryptionKey = value;
+				this.keyEncryptionAlgorithm = DetermineKeyEncAlg(keyEncryptionKeyOID, keyEncryptionKey);
+			}
+		}
+
+		internal string KeyEncryptionKeyOID
+		{
+			set { this.keyEncryptionKeyOID = value; }
+		}
+
+		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+		{
+			byte[] keyBytes = contentEncryptionKey.GetKey();
+
+			IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionAlgorithm.ObjectID.Id);
+			keyWrapper.Init(true, new ParametersWithRandom(keyEncryptionKey, random));
+        	Asn1OctetString encryptedKey = new DerOctetString(
+				keyWrapper.Wrap(keyBytes, 0, keyBytes.Length));
+
+			return new RecipientInfo(new KekRecipientInfo(kekIdentifier, keyEncryptionAlgorithm, encryptedKey));
+		}
+
+		private static AlgorithmIdentifier DetermineKeyEncAlg(
+			string algorithm, KeyParameter key)
+		{
+			if (algorithm.StartsWith("DES"))
+			{
+				return new AlgorithmIdentifier(
+					PkcsObjectIdentifiers.IdAlgCms3DesWrap,
+					DerNull.Instance);
+			}
+			else if (algorithm.StartsWith("RC2"))
+			{
+				return new AlgorithmIdentifier(
+					PkcsObjectIdentifiers.IdAlgCmsRC2Wrap,
+					new DerInteger(58));
+			}
+			else if (algorithm.StartsWith("AES"))
+			{
+				int length = key.GetKey().Length * 8;
+				DerObjectIdentifier wrapOid;
+
+				if (length == 128)
+				{
+					wrapOid = NistObjectIdentifiers.IdAes128Wrap;
+				}
+				else if (length == 192)
+				{
+					wrapOid = NistObjectIdentifiers.IdAes192Wrap;
+				}
+				else if (length == 256)
+				{
+					wrapOid = NistObjectIdentifiers.IdAes256Wrap;
+				}
+				else
+				{
+					throw new ArgumentException("illegal keysize in AES");
+				}
+
+				return new AlgorithmIdentifier(wrapOid);  // parameters absent
+			}
+			else if (algorithm.StartsWith("SEED"))
+			{
+				// parameters absent
+				return new AlgorithmIdentifier(KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap);
+			}
+			else if (algorithm.StartsWith("CAMELLIA"))
+			{
+				int length = key.GetKey().Length * 8;
+				DerObjectIdentifier wrapOid;
+
+				if (length == 128)
+				{
+					wrapOid = NttObjectIdentifiers.IdCamellia128Wrap;
+				}
+				else if (length == 192)
+				{
+					wrapOid = NttObjectIdentifiers.IdCamellia192Wrap;
+				}
+				else if (length == 256)
+				{
+					wrapOid = NttObjectIdentifiers.IdCamellia256Wrap;
+				}
+				else
+				{
+					throw new ArgumentException("illegal keysize in Camellia");
+				}
+
+				return new AlgorithmIdentifier(wrapOid); // parameters must be absent
+			}
+			else
+			{
+				throw new ArgumentException("unknown algorithm");
+			}
+		}
+	}
+}
diff --git a/crypto/src/cms/KEKRecipientInformation.cs b/crypto/src/cms/KEKRecipientInformation.cs
new file mode 100644
index 000000000..f960197d6
--- /dev/null
+++ b/crypto/src/cms/KEKRecipientInformation.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * the RecipientInfo class for a recipient who has been sent a message
+    * encrypted using a secret key known to the other side.
+    */
+    public class KekRecipientInformation
+        : RecipientInformation
+    {
+        private KekRecipientInfo info;
+
+		internal KekRecipientInformation(
+			KekRecipientInfo	info,
+			CmsSecureReadable	secureReadable)
+			: base(info.KeyEncryptionAlgorithm, secureReadable)
+		{
+            this.info = info;
+            this.rid = new RecipientID();
+
+			KekIdentifier kekId = info.KekID;
+
+			rid.KeyIdentifier = kekId.KeyIdentifier.GetOctets();
+        }
+
+		/**
+        * decrypt the content and return an input stream.
+        */
+        public override CmsTypedStream GetContentStream(
+            ICipherParameters key)
+        {
+			try
+			{
+				byte[] encryptedKey = info.EncryptedKey.GetOctets();
+				IWrapper keyWrapper = WrapperUtilities.GetWrapper(keyEncAlg.ObjectID.Id);
+
+				keyWrapper.Init(false, key);
+
+				KeyParameter sKey = ParameterUtilities.CreateKeyParameter(
+					GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+
+				return GetContentFromSessionKey(sKey);
+			}
+			catch (SecurityUtilityException e)
+			{
+				throw new CmsException("couldn't create cipher.", e);
+			}
+			catch (InvalidKeyException e)
+			{
+				throw new CmsException("key invalid in message.", e);
+			}
+        }
+    }
+}
diff --git a/crypto/src/cms/KeyAgreeRecipientInfoGenerator.cs b/crypto/src/cms/KeyAgreeRecipientInfoGenerator.cs
new file mode 100644
index 000000000..4fafb7c6e
--- /dev/null
+++ b/crypto/src/cms/KeyAgreeRecipientInfoGenerator.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Cms.Ecc;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class KeyAgreeRecipientInfoGenerator : RecipientInfoGenerator
+	{
+		private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+		private DerObjectIdentifier			keyAgreementOID;
+		private DerObjectIdentifier			keyEncryptionOID;
+		private IList					    recipientCerts;
+		private AsymmetricCipherKeyPair		senderKeyPair;
+
+		internal KeyAgreeRecipientInfoGenerator()
+		{
+		}
+
+		internal DerObjectIdentifier KeyAgreementOID
+		{
+			set { this.keyAgreementOID = value; }
+		}
+
+		internal DerObjectIdentifier KeyEncryptionOID
+		{
+			set { this.keyEncryptionOID = value; }
+		}
+
+		internal ICollection RecipientCerts
+		{
+			set { this.recipientCerts = Platform.CreateArrayList(value); }
+		}
+
+		internal AsymmetricCipherKeyPair SenderKeyPair
+		{
+			set { this.senderKeyPair = value; }
+		}
+
+		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+		{
+			byte[] keyBytes = contentEncryptionKey.GetKey();
+
+			AsymmetricKeyParameter senderPublicKey = senderKeyPair.Public;
+			ICipherParameters senderPrivateParams = senderKeyPair.Private;
+
+
+			OriginatorIdentifierOrKey originator;
+			try
+			{
+				originator = new OriginatorIdentifierOrKey(
+					CreateOriginatorPublicKey(senderPublicKey));
+			}
+			catch (IOException e)
+			{
+				throw new InvalidKeyException("cannot extract originator public key: " + e);
+			}
+
+
+			Asn1OctetString ukm = null;
+			if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
+			{
+				try
+				{
+					IAsymmetricCipherKeyPairGenerator ephemKPG =
+						GeneratorUtilities.GetKeyPairGenerator(keyAgreementOID);
+					ephemKPG.Init(
+						((ECPublicKeyParameters)senderPublicKey).CreateKeyGenerationParameters(random));
+
+					AsymmetricCipherKeyPair ephemKP = ephemKPG.GenerateKeyPair();
+
+					ukm = new DerOctetString(
+						new MQVuserKeyingMaterial(
+							CreateOriginatorPublicKey(ephemKP.Public), null));
+
+					senderPrivateParams = new MqvPrivateParameters(
+						(ECPrivateKeyParameters)senderPrivateParams,
+						(ECPrivateKeyParameters)ephemKP.Private,
+						(ECPublicKeyParameters)ephemKP.Public);
+				}
+				catch (IOException e)
+				{
+					throw new InvalidKeyException("cannot extract MQV ephemeral public key: " + e);
+				}
+				catch (SecurityUtilityException e)
+				{
+					throw new InvalidKeyException("cannot determine MQV ephemeral key pair parameters from public key: " + e);
+				}
+			}
+
+
+			DerSequence paramSeq = new DerSequence(
+				keyEncryptionOID,
+				DerNull.Instance);
+			AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyAgreementOID, paramSeq);
+
+
+			Asn1EncodableVector recipientEncryptedKeys = new Asn1EncodableVector();
+			foreach (X509Certificate recipientCert in recipientCerts)
+			{
+				TbsCertificateStructure tbsCert;
+				try
+				{
+					tbsCert = TbsCertificateStructure.GetInstance(
+						Asn1Object.FromByteArray(recipientCert.GetTbsCertificate()));
+				}
+				catch (Exception)
+				{
+					throw new ArgumentException("can't extract TBS structure from certificate");
+				}
+
+				// TODO Should there be a SubjectKeyIdentifier-based alternative?
+				IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(
+					tbsCert.Issuer, tbsCert.SerialNumber.Value);
+				KeyAgreeRecipientIdentifier karid = new KeyAgreeRecipientIdentifier(issuerSerial);
+
+				ICipherParameters recipientPublicParams = recipientCert.GetPublicKey();
+				if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
+				{
+					recipientPublicParams = new MqvPublicParameters(
+						(ECPublicKeyParameters)recipientPublicParams,
+						(ECPublicKeyParameters)recipientPublicParams);
+				}
+
+				// Use key agreement to choose a wrap key for this recipient
+				IBasicAgreement keyAgreement = AgreementUtilities.GetBasicAgreementWithKdf(
+					keyAgreementOID, keyEncryptionOID.Id);
+				keyAgreement.Init(new ParametersWithRandom(senderPrivateParams, random));
+				BigInteger agreedValue = keyAgreement.CalculateAgreement(recipientPublicParams);
+
+				int keyEncryptionKeySize = GeneratorUtilities.GetDefaultKeySize(keyEncryptionOID) / 8;
+				byte[] keyEncryptionKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, keyEncryptionKeySize);
+				KeyParameter keyEncryptionKey = ParameterUtilities.CreateKeyParameter(
+					keyEncryptionOID, keyEncryptionKeyBytes);
+
+				// Wrap the content encryption key with the agreement key
+				IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionOID.Id);
+				keyWrapper.Init(true, new ParametersWithRandom(keyEncryptionKey, random));
+				byte[] encryptedKeyBytes = keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);
+
+	        	Asn1OctetString encryptedKey = new DerOctetString(encryptedKeyBytes);
+
+				recipientEncryptedKeys.Add(new RecipientEncryptedKey(karid, encryptedKey));
+			}
+
+			return new RecipientInfo(new KeyAgreeRecipientInfo(originator, ukm, keyEncAlg,
+				new DerSequence(recipientEncryptedKeys)));
+		}
+
+		private static OriginatorPublicKey CreateOriginatorPublicKey(
+			AsymmetricKeyParameter publicKey)
+		{
+			SubjectPublicKeyInfo spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+			return new OriginatorPublicKey(
+				new AlgorithmIdentifier(spki.AlgorithmID.ObjectID, DerNull.Instance),
+				spki.PublicKeyData.GetBytes());
+		}
+	}
+}
diff --git a/crypto/src/cms/KeyAgreeRecipientInformation.cs b/crypto/src/cms/KeyAgreeRecipientInformation.cs
index 38a94b0a4..8e006e545 100644
--- a/crypto/src/cms/KeyAgreeRecipientInformation.cs
+++ b/crypto/src/cms/KeyAgreeRecipientInformation.cs
@@ -18,209 +18,209 @@ using Org.BouncyCastle.X509;
 
 namespace Org.BouncyCastle.Cms
 {
-	/**
-	* the RecipientInfo class for a recipient who has been sent a message
-	* encrypted using key agreement.
-	*/
-	public class KeyAgreeRecipientInformation
-		: RecipientInformation
-	{
-		private KeyAgreeRecipientInfo info;
-		private Asn1OctetString       encryptedKey;
-
-		internal static void ReadRecipientInfo(IList infos, KeyAgreeRecipientInfo info,
-			CmsSecureReadable secureReadable)
-		{
-			try
-			{
-				foreach (Asn1Encodable rek in info.RecipientEncryptedKeys)
-				{
-					RecipientEncryptedKey id = RecipientEncryptedKey.GetInstance(rek.ToAsn1Object());
-
-					RecipientID rid = new RecipientID();
-
-					Asn1.Cms.KeyAgreeRecipientIdentifier karid = id.Identifier;
-
-					Asn1.Cms.IssuerAndSerialNumber iAndSN = karid.IssuerAndSerialNumber;
-					if (iAndSN != null)
-					{
-						rid.Issuer = iAndSN.Name;
-						rid.SerialNumber = iAndSN.SerialNumber.Value;
-					}
-					else
-					{
-						Asn1.Cms.RecipientKeyIdentifier rKeyID = karid.RKeyID;
-
-						// Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational 
-
-						rid.SubjectKeyIdentifier = rKeyID.SubjectKeyIdentifier.GetOctets();
-					}
-
-					infos.Add(new KeyAgreeRecipientInformation(info, rid, id.EncryptedKey,
-						secureReadable));
-				}
-			}
-			catch (IOException e)
-			{
-				throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", e);
-			}
-		}
-
-		internal KeyAgreeRecipientInformation(
-			KeyAgreeRecipientInfo	info,
-			RecipientID				rid,
-			Asn1OctetString			encryptedKey,
-			CmsSecureReadable		secureReadable)
-			: base(info.KeyEncryptionAlgorithm, secureReadable)
-		{
-			this.info = info;
-			this.rid = rid;
-			this.encryptedKey = encryptedKey;
-		}
-
-		private AsymmetricKeyParameter GetSenderPublicKey(
-			AsymmetricKeyParameter		receiverPrivateKey,
-			OriginatorIdentifierOrKey	originator)
-		{
-			OriginatorPublicKey opk = originator.OriginatorPublicKey;
-			if (opk != null)
-			{
-				return GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, opk);
-			}
-			
-			OriginatorID origID = new OriginatorID();
-			
-			Asn1.Cms.IssuerAndSerialNumber iAndSN = originator.IssuerAndSerialNumber;
-			if (iAndSN != null)
-			{
-				origID.Issuer = iAndSN.Name;
-				origID.SerialNumber = iAndSN.SerialNumber.Value;
-			}
-			else
-			{
-				SubjectKeyIdentifier ski = originator.SubjectKeyIdentifier;
-
-				origID.SubjectKeyIdentifier = ski.GetKeyIdentifier();
-			}
-
-			return GetPublicKeyFromOriginatorID(origID);
-		}
-
-		private AsymmetricKeyParameter GetPublicKeyFromOriginatorPublicKey(
-			AsymmetricKeyParameter	receiverPrivateKey,
-			OriginatorPublicKey		originatorPublicKey)
-		{
-			PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(receiverPrivateKey);
-			SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
-				privInfo.AlgorithmID,
-				originatorPublicKey.PublicKey.GetBytes());
-			return PublicKeyFactory.CreateKey(pubInfo);
-		}
-
-		private AsymmetricKeyParameter GetPublicKeyFromOriginatorID(
-			OriginatorID origID)
-		{
-			// TODO Support all alternatives for OriginatorIdentifierOrKey
-			// see RFC 3852 6.2.2
-			throw new CmsException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
-		}
-
-		private KeyParameter CalculateAgreedWrapKey(
-			string					wrapAlg,
-			AsymmetricKeyParameter	senderPublicKey,
-			AsymmetricKeyParameter	receiverPrivateKey)
-		{
-			DerObjectIdentifier agreeAlgID = keyEncAlg.ObjectID;
-
-			ICipherParameters senderPublicParams = senderPublicKey;
-			ICipherParameters receiverPrivateParams = receiverPrivateKey;
-
-			if (agreeAlgID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
-			{
-				byte[] ukmEncoding = info.UserKeyingMaterial.GetOctets();
-				MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.GetInstance(
-					Asn1Object.FromByteArray(ukmEncoding));
-
-				AsymmetricKeyParameter ephemeralKey = GetPublicKeyFromOriginatorPublicKey(
-					receiverPrivateKey, ukm.EphemeralPublicKey);
-
-				senderPublicParams = new MqvPublicParameters(
-					(ECPublicKeyParameters)senderPublicParams,
-					(ECPublicKeyParameters)ephemeralKey);
-				receiverPrivateParams = new MqvPrivateParameters(
-					(ECPrivateKeyParameters)receiverPrivateParams,
-					(ECPrivateKeyParameters)receiverPrivateParams);
-			}
-
-			IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf(
-				agreeAlgID, wrapAlg);
-			agreement.Init(receiverPrivateParams);
-			BigInteger agreedValue = agreement.CalculateAgreement(senderPublicParams);
-
-			int wrapKeySize = GeneratorUtilities.GetDefaultKeySize(wrapAlg) / 8;
-			byte[] wrapKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, wrapKeySize);
-			return ParameterUtilities.CreateKeyParameter(wrapAlg, wrapKeyBytes);
-		}
-
-		private KeyParameter UnwrapSessionKey(
-			string			wrapAlg,
-			KeyParameter	agreedKey)
-		{
-			byte[] encKeyOctets = encryptedKey.GetOctets();
-
-			IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg);
-			keyCipher.Init(false, agreedKey);
-			byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
-			return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), sKeyBytes);
-		}
-
-		internal KeyParameter GetSessionKey(
-			AsymmetricKeyParameter receiverPrivateKey)
-		{
-			try
-			{
-				string wrapAlg = DerObjectIdentifier.GetInstance(
-					Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id;
-
-				AsymmetricKeyParameter senderPublicKey = GetSenderPublicKey(
-					receiverPrivateKey, info.Originator);
-
-				KeyParameter agreedWrapKey = CalculateAgreedWrapKey(wrapAlg,
-					senderPublicKey, receiverPrivateKey);
-
-				return UnwrapSessionKey(wrapAlg, agreedWrapKey);
-			}
-			catch (SecurityUtilityException e)
-			{
-				throw new CmsException("couldn't create cipher.", e);
-			}
-			catch (InvalidKeyException e)
-			{
-				throw new CmsException("key invalid in message.", e);
-			}
-			catch (Exception e)
-			{
-				throw new CmsException("originator key invalid.", e);
-			}
-		}
-
-		/**
-		* decrypt the content and return an input stream.
-		*/
-		public override CmsTypedStream GetContentStream(
-			ICipherParameters key)
-		{
-			if (!(key is AsymmetricKeyParameter))
-				throw new ArgumentException("KeyAgreement requires asymmetric key", "key");
-
-			AsymmetricKeyParameter receiverPrivateKey = (AsymmetricKeyParameter) key;
-
-			if (!receiverPrivateKey.IsPrivate)
-				throw new ArgumentException("Expected private key", "key");
-
-			KeyParameter sKey = GetSessionKey(receiverPrivateKey);
-
-			return GetContentFromSessionKey(sKey);
-		}
-	}
+    /**
+    * the RecipientInfo class for a recipient who has been sent a message
+    * encrypted using key agreement.
+    */
+    public class KeyAgreeRecipientInformation
+        : RecipientInformation
+    {
+        private KeyAgreeRecipientInfo info;
+        private Asn1OctetString       encryptedKey;
+
+        internal static void ReadRecipientInfo(IList infos, KeyAgreeRecipientInfo info,
+            CmsSecureReadable secureReadable)
+        {
+            try
+            {
+                foreach (Asn1Encodable rek in info.RecipientEncryptedKeys)
+                {
+                    RecipientEncryptedKey id = RecipientEncryptedKey.GetInstance(rek.ToAsn1Object());
+
+                    RecipientID rid = new RecipientID();
+
+                    Asn1.Cms.KeyAgreeRecipientIdentifier karid = id.Identifier;
+
+                    Asn1.Cms.IssuerAndSerialNumber iAndSN = karid.IssuerAndSerialNumber;
+                    if (iAndSN != null)
+                    {
+                        rid.Issuer = iAndSN.Name;
+                        rid.SerialNumber = iAndSN.SerialNumber.Value;
+                    }
+                    else
+                    {
+                        Asn1.Cms.RecipientKeyIdentifier rKeyID = karid.RKeyID;
+
+                        // Note: 'date' and 'other' fields of RecipientKeyIdentifier appear to be only informational 
+
+                        rid.SubjectKeyIdentifier = rKeyID.SubjectKeyIdentifier.GetOctets();
+                    }
+
+                    infos.Add(new KeyAgreeRecipientInformation(info, rid, id.EncryptedKey,
+                        secureReadable));
+                }
+            }
+            catch (IOException e)
+            {
+                throw new ArgumentException("invalid rid in KeyAgreeRecipientInformation", e);
+            }
+        }
+
+        internal KeyAgreeRecipientInformation(
+            KeyAgreeRecipientInfo	info,
+            RecipientID				rid,
+            Asn1OctetString			encryptedKey,
+            CmsSecureReadable		secureReadable)
+            : base(info.KeyEncryptionAlgorithm, secureReadable)
+        {
+            this.info = info;
+            this.rid = rid;
+            this.encryptedKey = encryptedKey;
+        }
+
+        private AsymmetricKeyParameter GetSenderPublicKey(
+            AsymmetricKeyParameter		receiverPrivateKey,
+            OriginatorIdentifierOrKey	originator)
+        {
+            OriginatorPublicKey opk = originator.OriginatorPublicKey;
+            if (opk != null)
+            {
+                return GetPublicKeyFromOriginatorPublicKey(receiverPrivateKey, opk);
+            }
+            
+            OriginatorID origID = new OriginatorID();
+            
+            Asn1.Cms.IssuerAndSerialNumber iAndSN = originator.IssuerAndSerialNumber;
+            if (iAndSN != null)
+            {
+                origID.Issuer = iAndSN.Name;
+                origID.SerialNumber = iAndSN.SerialNumber.Value;
+            }
+            else
+            {
+                SubjectKeyIdentifier ski = originator.SubjectKeyIdentifier;
+
+                origID.SubjectKeyIdentifier = ski.GetKeyIdentifier();
+            }
+
+            return GetPublicKeyFromOriginatorID(origID);
+        }
+
+        private AsymmetricKeyParameter GetPublicKeyFromOriginatorPublicKey(
+            AsymmetricKeyParameter	receiverPrivateKey,
+            OriginatorPublicKey		originatorPublicKey)
+        {
+            PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(receiverPrivateKey);
+            SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(
+                privInfo.PrivateKeyAlgorithm,
+                originatorPublicKey.PublicKey.GetBytes());
+            return PublicKeyFactory.CreateKey(pubInfo);
+        }
+
+        private AsymmetricKeyParameter GetPublicKeyFromOriginatorID(
+            OriginatorID origID)
+        {
+            // TODO Support all alternatives for OriginatorIdentifierOrKey
+            // see RFC 3852 6.2.2
+            throw new CmsException("No support for 'originator' as IssuerAndSerialNumber or SubjectKeyIdentifier");
+        }
+
+        private KeyParameter CalculateAgreedWrapKey(
+            string					wrapAlg,
+            AsymmetricKeyParameter	senderPublicKey,
+            AsymmetricKeyParameter	receiverPrivateKey)
+        {
+            DerObjectIdentifier agreeAlgID = keyEncAlg.ObjectID;
+
+            ICipherParameters senderPublicParams = senderPublicKey;
+            ICipherParameters receiverPrivateParams = receiverPrivateKey;
+
+            if (agreeAlgID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
+            {
+                byte[] ukmEncoding = info.UserKeyingMaterial.GetOctets();
+                MQVuserKeyingMaterial ukm = MQVuserKeyingMaterial.GetInstance(
+                    Asn1Object.FromByteArray(ukmEncoding));
+
+                AsymmetricKeyParameter ephemeralKey = GetPublicKeyFromOriginatorPublicKey(
+                    receiverPrivateKey, ukm.EphemeralPublicKey);
+
+                senderPublicParams = new MqvPublicParameters(
+                    (ECPublicKeyParameters)senderPublicParams,
+                    (ECPublicKeyParameters)ephemeralKey);
+                receiverPrivateParams = new MqvPrivateParameters(
+                    (ECPrivateKeyParameters)receiverPrivateParams,
+                    (ECPrivateKeyParameters)receiverPrivateParams);
+            }
+
+            IBasicAgreement agreement = AgreementUtilities.GetBasicAgreementWithKdf(
+                agreeAlgID, wrapAlg);
+            agreement.Init(receiverPrivateParams);
+            BigInteger agreedValue = agreement.CalculateAgreement(senderPublicParams);
+
+            int wrapKeySize = GeneratorUtilities.GetDefaultKeySize(wrapAlg) / 8;
+            byte[] wrapKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, wrapKeySize);
+            return ParameterUtilities.CreateKeyParameter(wrapAlg, wrapKeyBytes);
+        }
+
+        private KeyParameter UnwrapSessionKey(
+            string			wrapAlg,
+            KeyParameter	agreedKey)
+        {
+            byte[] encKeyOctets = encryptedKey.GetOctets();
+
+            IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg);
+            keyCipher.Init(false, agreedKey);
+            byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
+            return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), sKeyBytes);
+        }
+
+        internal KeyParameter GetSessionKey(
+            AsymmetricKeyParameter receiverPrivateKey)
+        {
+            try
+            {
+                string wrapAlg = DerObjectIdentifier.GetInstance(
+                    Asn1Sequence.GetInstance(keyEncAlg.Parameters)[0]).Id;
+
+                AsymmetricKeyParameter senderPublicKey = GetSenderPublicKey(
+                    receiverPrivateKey, info.Originator);
+
+                KeyParameter agreedWrapKey = CalculateAgreedWrapKey(wrapAlg,
+                    senderPublicKey, receiverPrivateKey);
+
+                return UnwrapSessionKey(wrapAlg, agreedWrapKey);
+            }
+            catch (SecurityUtilityException e)
+            {
+                throw new CmsException("couldn't create cipher.", e);
+            }
+            catch (InvalidKeyException e)
+            {
+                throw new CmsException("key invalid in message.", e);
+            }
+            catch (Exception e)
+            {
+                throw new CmsException("originator key invalid.", e);
+            }
+        }
+
+        /**
+        * decrypt the content and return an input stream.
+        */
+        public override CmsTypedStream GetContentStream(
+            ICipherParameters key)
+        {
+            if (!(key is AsymmetricKeyParameter))
+                throw new ArgumentException("KeyAgreement requires asymmetric key", "key");
+
+            AsymmetricKeyParameter receiverPrivateKey = (AsymmetricKeyParameter) key;
+
+            if (!receiverPrivateKey.IsPrivate)
+                throw new ArgumentException("Expected private key", "key");
+
+            KeyParameter sKey = GetSessionKey(receiverPrivateKey);
+
+            return GetContentFromSessionKey(sKey);
+        }
+    }
 }
diff --git a/crypto/src/cms/KeyTransRecipientInfoGenerator.cs b/crypto/src/cms/KeyTransRecipientInfoGenerator.cs
new file mode 100644
index 000000000..0992e6da6
--- /dev/null
+++ b/crypto/src/cms/KeyTransRecipientInfoGenerator.cs
@@ -0,0 +1,87 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class KeyTransRecipientInfoGenerator : RecipientInfoGenerator
+	{
+		private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+		private TbsCertificateStructure	recipientTbsCert;
+		private AsymmetricKeyParameter	recipientPublicKey;
+		private Asn1OctetString			subjectKeyIdentifier;
+
+		// Derived fields
+		private SubjectPublicKeyInfo info;
+
+		internal KeyTransRecipientInfoGenerator()
+		{
+		}
+
+		internal X509Certificate RecipientCert
+		{
+			set
+			{
+				this.recipientTbsCert = CmsUtilities.GetTbsCertificateStructure(value);
+				this.recipientPublicKey = value.GetPublicKey();
+				this.info = recipientTbsCert.SubjectPublicKeyInfo;
+			}
+		}
+		
+		internal AsymmetricKeyParameter RecipientPublicKey
+		{
+			set
+			{
+				this.recipientPublicKey = value;
+
+				try
+				{
+					info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+						recipientPublicKey);
+				}
+				catch (IOException)
+				{
+					throw new ArgumentException("can't extract key algorithm from this key");
+				}
+			}
+		}
+		
+		internal Asn1OctetString SubjectKeyIdentifier
+		{
+			set { this.subjectKeyIdentifier = value; }
+		}
+
+		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+		{
+			byte[] keyBytes = contentEncryptionKey.GetKey();
+			AlgorithmIdentifier keyEncryptionAlgorithm = info.AlgorithmID;
+
+			IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionAlgorithm.ObjectID.Id);
+			keyWrapper.Init(true, new ParametersWithRandom(recipientPublicKey, random));
+			byte[] encryptedKeyBytes = keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);
+
+			RecipientIdentifier recipId;
+			if (recipientTbsCert != null)
+			{
+				IssuerAndSerialNumber issuerAndSerial = new IssuerAndSerialNumber(
+					recipientTbsCert.Issuer, recipientTbsCert.SerialNumber.Value);
+				recipId = new RecipientIdentifier(issuerAndSerial);
+			}
+			else
+			{
+				recipId = new RecipientIdentifier(subjectKeyIdentifier);
+			}
+
+			return new RecipientInfo(new KeyTransRecipientInfo(recipId, keyEncryptionAlgorithm,
+				new DerOctetString(encryptedKeyBytes)));
+		}
+	}
+}
diff --git a/crypto/src/cms/KeyTransRecipientInformation.cs b/crypto/src/cms/KeyTransRecipientInformation.cs
new file mode 100644
index 000000000..24121cb2c
--- /dev/null
+++ b/crypto/src/cms/KeyTransRecipientInformation.cs
@@ -0,0 +1,113 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Asn1Pkcs = Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * the KeyTransRecipientInformation class for a recipient who has been sent a secret
+    * key encrypted using their public key that needs to be used to
+    * extract the message.
+    */
+    public class KeyTransRecipientInformation
+        : RecipientInformation
+    {
+        private KeyTransRecipientInfo info;
+
+		internal KeyTransRecipientInformation(
+			KeyTransRecipientInfo	info,
+			CmsSecureReadable		secureReadable)
+			: base(info.KeyEncryptionAlgorithm, secureReadable)
+		{
+            this.info = info;
+            this.rid = new RecipientID();
+
+			RecipientIdentifier r = info.RecipientIdentifier;
+
+			try
+            {
+                if (r.IsTagged)
+                {
+                    Asn1OctetString octs = Asn1OctetString.GetInstance(r.ID);
+
+					rid.SubjectKeyIdentifier = octs.GetOctets();
+                }
+                else
+                {
+                    IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.GetInstance(r.ID);
+
+					rid.Issuer = iAnds.Name;
+                    rid.SerialNumber = iAnds.SerialNumber.Value;
+                }
+            }
+            catch (IOException)
+            {
+                throw new ArgumentException("invalid rid in KeyTransRecipientInformation");
+            }
+        }
+
+		private string GetExchangeEncryptionAlgorithmName(
+			DerObjectIdentifier oid)
+		{
+			if (Asn1Pkcs.PkcsObjectIdentifiers.RsaEncryption.Equals(oid))
+			{
+				return "RSA//PKCS1Padding";
+			}
+
+			return oid.Id;
+		}
+
+		internal KeyParameter UnwrapKey(ICipherParameters key)
+		{
+			byte[] encryptedKey = info.EncryptedKey.GetOctets();
+			string keyExchangeAlgorithm = GetExchangeEncryptionAlgorithmName(keyEncAlg.ObjectID);
+
+			try
+			{
+				IWrapper keyWrapper = WrapperUtilities.GetWrapper(keyExchangeAlgorithm);
+				keyWrapper.Init(false, key);
+
+				// FIXME Support for MAC algorithm parameters similar to cipher parameters
+				return ParameterUtilities.CreateKeyParameter(
+					GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+			}
+			catch (SecurityUtilityException e)
+			{
+				throw new CmsException("couldn't create cipher.", e);
+			}
+			catch (InvalidKeyException e)
+			{
+				throw new CmsException("key invalid in message.", e);
+			}
+//			catch (IllegalBlockSizeException e)
+			catch (DataLengthException e)
+			{
+				throw new CmsException("illegal blocksize in message.", e);
+			}
+//			catch (BadPaddingException e)
+			catch (InvalidCipherTextException e)
+			{
+				throw new CmsException("bad padding in message.", e);
+			}
+		}
+		
+		/**
+        * decrypt the content and return it as a byte array.
+        */
+        public override CmsTypedStream GetContentStream(
+            ICipherParameters key)
+        {
+			KeyParameter sKey = UnwrapKey(key);
+
+			return GetContentFromSessionKey(sKey);
+		}
+    }
+}
diff --git a/crypto/src/cms/MacOutputStream.cs b/crypto/src/cms/MacOutputStream.cs
new file mode 100644
index 000000000..8891dbc2c
--- /dev/null
+++ b/crypto/src/cms/MacOutputStream.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class MacOutputStream
+		: BaseOutputStream
+	{
+		private readonly IMac mac;
+
+		internal MacOutputStream(IMac mac)
+		{
+			this.mac = mac;
+		}
+
+		public override void Write(byte[] b, int off, int len)
+		{
+			mac.BlockUpdate(b, off, len);
+		}
+
+		public override void WriteByte(byte b)
+		{
+			mac.Update(b);
+		}
+	}
+}
diff --git a/crypto/src/cms/OriginatorId.cs b/crypto/src/cms/OriginatorId.cs
new file mode 100644
index 000000000..5a3b7374d
--- /dev/null
+++ b/crypto/src/cms/OriginatorId.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * a basic index for an originator.
+    */
+    public class OriginatorID
+        : X509CertStoreSelector
+    {
+        public override int GetHashCode()
+        {
+            int code = Arrays.GetHashCode(this.SubjectKeyIdentifier);
+
+			BigInteger serialNumber = this.SerialNumber;
+			if (serialNumber != null)
+            {
+                code ^= serialNumber.GetHashCode();
+            }
+
+			X509Name issuer = this.Issuer;
+            if (issuer != null)
+            {
+                code ^= issuer.GetHashCode();
+            }
+
+			return code;
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+			if (obj == this)
+				return false;
+
+			OriginatorID id = obj as OriginatorID;
+
+			if (id == null)
+				return false;
+
+			return Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
+				&& Platform.Equals(SerialNumber, id.SerialNumber)
+				&& IssuersMatch(Issuer, id.Issuer);
+        }
+    }
+}
diff --git a/crypto/src/cms/OriginatorInfoGenerator.cs b/crypto/src/cms/OriginatorInfoGenerator.cs
new file mode 100644
index 000000000..6bf108799
--- /dev/null
+++ b/crypto/src/cms/OriginatorInfoGenerator.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+    public class OriginatorInfoGenerator
+    {
+        private readonly IList origCerts;
+        private readonly IList origCrls;
+
+        public OriginatorInfoGenerator(X509Certificate origCert)
+        {
+            this.origCerts = Platform.CreateArrayList(1);
+            this.origCrls = null;
+            origCerts.Add(origCert.CertificateStructure);
+        }
+
+        public OriginatorInfoGenerator(IX509Store origCerts)
+            : this(origCerts, null)
+        {
+        }
+
+        public OriginatorInfoGenerator(IX509Store origCerts, IX509Store origCrls)
+        {
+            this.origCerts = CmsUtilities.GetCertificatesFromStore(origCerts);
+            this.origCrls = origCrls == null ? null : CmsUtilities.GetCrlsFromStore(origCrls);
+        }
+
+        public virtual OriginatorInfo Generate()
+        {
+            Asn1Set certSet = CmsUtilities.CreateDerSetFromList(origCerts);
+            Asn1Set crlSet = origCrls == null ? null : CmsUtilities.CreateDerSetFromList(origCrls);
+            return new OriginatorInfo(certSet, crlSet);
+        }
+    }
+}
diff --git a/crypto/src/cms/OriginatorInformation.cs b/crypto/src/cms/OriginatorInformation.cs
new file mode 100644
index 000000000..618add6e0
--- /dev/null
+++ b/crypto/src/cms/OriginatorInformation.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+	public class OriginatorInformation
+	{
+		private readonly OriginatorInfo originatorInfo;
+
+		internal OriginatorInformation(OriginatorInfo originatorInfo)
+		{
+			this.originatorInfo = originatorInfo;
+		}
+
+		/**
+		* Return the certificates stored in the underlying OriginatorInfo object.
+		*
+		* @return a Store of X509CertificateHolder objects.
+		*/
+		public virtual IX509Store GetCertificates()
+		{
+			Asn1Set certSet = originatorInfo.Certificates;
+
+			if (certSet != null)
+			{
+				IList certList = Platform.CreateArrayList(certSet.Count);
+
+				foreach (Asn1Encodable enc in certSet)
+				{
+					Asn1Object obj = enc.ToAsn1Object();
+					if (obj is Asn1Sequence)
+					{
+						certList.Add(new X509Certificate(X509CertificateStructure.GetInstance(obj)));
+					}
+				}
+
+				return X509StoreFactory.Create(
+					"Certificate/Collection",
+					new X509CollectionStoreParameters(certList));
+			}
+
+			return X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(Platform.CreateArrayList()));
+		}
+
+		/**
+		* Return the CRLs stored in the underlying OriginatorInfo object.
+		*
+		* @return a Store of X509CRLHolder objects.
+		*/
+		public virtual IX509Store GetCrls()
+		{
+			Asn1Set crlSet = originatorInfo.Certificates;
+
+			if (crlSet != null)
+			{
+                IList crlList = Platform.CreateArrayList(crlSet.Count);
+
+				foreach (Asn1Encodable enc in crlSet)
+				{
+					Asn1Object obj = enc.ToAsn1Object();
+					if (obj is Asn1Sequence)
+					{
+						crlList.Add(new X509Crl(CertificateList.GetInstance(obj)));
+					}
+				}
+
+				return X509StoreFactory.Create(
+					"CRL/Collection",
+					new X509CollectionStoreParameters(crlList));
+			}
+
+			return X509StoreFactory.Create(
+				"CRL/Collection",
+                new X509CollectionStoreParameters(Platform.CreateArrayList()));
+		}
+
+		/**
+		* Return the underlying ASN.1 object defining this SignerInformation object.
+		*
+		* @return a OriginatorInfo.
+		*/
+		public virtual OriginatorInfo ToAsn1Structure()
+		{
+			return originatorInfo;
+		}
+	}
+}
diff --git a/crypto/src/cms/PKCS5Scheme2PBEKey.cs b/crypto/src/cms/PKCS5Scheme2PBEKey.cs
new file mode 100644
index 000000000..08b8518a1
--- /dev/null
+++ b/crypto/src/cms/PKCS5Scheme2PBEKey.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+	/// <summary>
+	/// PKCS5 scheme-2 - password converted to bytes assuming ASCII.
+	/// </summary>
+	public class Pkcs5Scheme2PbeKey
+		: CmsPbeKey
+	{
+		[Obsolete("Use version taking 'char[]' instead")]
+		public Pkcs5Scheme2PbeKey(
+			string	password,
+			byte[]	salt,
+			int		iterationCount)
+			: this(password.ToCharArray(), salt, iterationCount)
+		{
+		}
+
+		[Obsolete("Use version taking 'char[]' instead")]
+		public Pkcs5Scheme2PbeKey(
+			string				password,
+			AlgorithmIdentifier keyDerivationAlgorithm)
+			: this(password.ToCharArray(), keyDerivationAlgorithm)
+		{
+		}
+		
+		public Pkcs5Scheme2PbeKey(
+			char[]	password,
+			byte[]	salt,
+			int		iterationCount)
+			: base(password, salt, iterationCount)
+		{
+		}
+
+		public Pkcs5Scheme2PbeKey(
+			char[]				password,
+			AlgorithmIdentifier keyDerivationAlgorithm)
+			: base(password, keyDerivationAlgorithm)
+		{
+		}
+
+		internal override KeyParameter GetEncoded(
+			string algorithmOid)
+		{
+			Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator();
+
+			gen.Init(
+				PbeParametersGenerator.Pkcs5PasswordToBytes(password),
+				salt,
+				iterationCount);
+
+			return (KeyParameter) gen.GenerateDerivedParameters(
+				algorithmOid,
+				CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid));
+		}
+	}
+}
diff --git a/crypto/src/cms/PKCS5Scheme2UTF8PBEKey.cs b/crypto/src/cms/PKCS5Scheme2UTF8PBEKey.cs
new file mode 100644
index 000000000..7aecc2978
--- /dev/null
+++ b/crypto/src/cms/PKCS5Scheme2UTF8PBEKey.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	 * PKCS5 scheme-2 - password converted to bytes using UTF-8.
+	 */
+	public class Pkcs5Scheme2Utf8PbeKey
+		: CmsPbeKey
+	{
+		[Obsolete("Use version taking 'char[]' instead")]
+		public Pkcs5Scheme2Utf8PbeKey(
+			string	password,
+			byte[]	salt,
+			int		iterationCount)
+			: this(password.ToCharArray(), salt, iterationCount)
+		{
+		}
+
+		[Obsolete("Use version taking 'char[]' instead")]
+		public Pkcs5Scheme2Utf8PbeKey(
+			string				password,
+			AlgorithmIdentifier keyDerivationAlgorithm)
+			: this(password.ToCharArray(), keyDerivationAlgorithm)
+		{
+		}
+
+		public Pkcs5Scheme2Utf8PbeKey(
+			char[]	password,
+			byte[]	salt,
+			int		iterationCount)
+			: base(password, salt, iterationCount)
+		{
+		}
+
+		public Pkcs5Scheme2Utf8PbeKey(
+			char[]				password,
+			AlgorithmIdentifier keyDerivationAlgorithm)
+			: base(password, keyDerivationAlgorithm)
+		{
+		}
+
+		internal override KeyParameter GetEncoded(
+			string algorithmOid)
+		{
+			Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator();
+
+			gen.Init(
+				PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes(password),
+				salt,
+				iterationCount);
+
+			return (KeyParameter) gen.GenerateDerivedParameters(
+				algorithmOid,
+				CmsEnvelopedHelper.Instance.GetKeySize(algorithmOid));
+		}
+	}
+}
diff --git a/crypto/src/cms/PasswordRecipientInfoGenerator.cs b/crypto/src/cms/PasswordRecipientInfoGenerator.cs
new file mode 100644
index 000000000..0a0b27b53
--- /dev/null
+++ b/crypto/src/cms/PasswordRecipientInfoGenerator.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class PasswordRecipientInfoGenerator : RecipientInfoGenerator
+	{
+		private static readonly CmsEnvelopedHelper Helper = CmsEnvelopedHelper.Instance;
+
+		private AlgorithmIdentifier	keyDerivationAlgorithm;
+		private KeyParameter		keyEncryptionKey;
+		// TODO Can get this from keyEncryptionKey?		
+		private string				keyEncryptionKeyOID;
+
+		internal PasswordRecipientInfoGenerator()
+		{
+		}
+
+		internal AlgorithmIdentifier KeyDerivationAlgorithm
+		{
+			set { this.keyDerivationAlgorithm = value; }
+		}
+
+		internal KeyParameter KeyEncryptionKey
+		{
+			set { this.keyEncryptionKey = value; }
+		}
+
+		internal string KeyEncryptionKeyOID
+		{
+			set { this.keyEncryptionKeyOID = value; }
+		}
+
+		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
+		{
+			byte[] keyBytes = contentEncryptionKey.GetKey();
+
+			string rfc3211WrapperName = Helper.GetRfc3211WrapperName(keyEncryptionKeyOID);
+			IWrapper keyWrapper = Helper.CreateWrapper(rfc3211WrapperName);
+
+			// Note: In Java build, the IV is automatically generated in JCE layer
+			int ivLength = rfc3211WrapperName.StartsWith("DESEDE") ? 8 : 16;
+			byte[] iv = new byte[ivLength];
+			random.NextBytes(iv);
+
+			ICipherParameters parameters = new ParametersWithIV(keyEncryptionKey, iv);
+			keyWrapper.Init(true, new ParametersWithRandom(parameters, random));
+        	Asn1OctetString encryptedKey = new DerOctetString(
+				keyWrapper.Wrap(keyBytes, 0, keyBytes.Length));
+
+			DerSequence seq = new DerSequence(
+				new DerObjectIdentifier(keyEncryptionKeyOID),
+				new DerOctetString(iv));
+
+			AlgorithmIdentifier keyEncryptionAlgorithm = new AlgorithmIdentifier(
+				PkcsObjectIdentifiers.IdAlgPwriKek, seq);
+
+			return new RecipientInfo(new PasswordRecipientInfo(
+				keyDerivationAlgorithm, keyEncryptionAlgorithm, encryptedKey));
+		}
+	}
+}
diff --git a/crypto/src/cms/PasswordRecipientInformation.cs b/crypto/src/cms/PasswordRecipientInformation.cs
new file mode 100644
index 000000000..f629caba6
--- /dev/null
+++ b/crypto/src/cms/PasswordRecipientInformation.cs
@@ -0,0 +1,79 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	 * the RecipientInfo class for a recipient who has been sent a message
+	 * encrypted using a password.
+	 */
+	public class PasswordRecipientInformation
+		: RecipientInformation
+	{
+		private readonly PasswordRecipientInfo	info;
+
+		internal PasswordRecipientInformation(
+			PasswordRecipientInfo	info,
+			CmsSecureReadable		secureReadable)
+			: base(info.KeyEncryptionAlgorithm, secureReadable)
+		{
+			this.info = info;
+			this.rid = new RecipientID();
+		}
+
+		/**
+		 * return the object identifier for the key derivation algorithm, or null
+		 * if there is none present.
+		 *
+		 * @return OID for key derivation algorithm, if present.
+		 */
+		public virtual AlgorithmIdentifier KeyDerivationAlgorithm
+		{
+			get { return info.KeyDerivationAlgorithm; }
+		}
+
+		/**
+		 * decrypt the content and return an input stream.
+		 */
+		public override CmsTypedStream GetContentStream(
+			ICipherParameters key)
+		{
+			try
+			{
+				AlgorithmIdentifier kekAlg = AlgorithmIdentifier.GetInstance(info.KeyEncryptionAlgorithm);
+				Asn1Sequence        kekAlgParams = (Asn1Sequence)kekAlg.Parameters;
+				byte[]              encryptedKey = info.EncryptedKey.GetOctets();
+				string              kekAlgName = DerObjectIdentifier.GetInstance(kekAlgParams[0]).Id;
+				string				cName = CmsEnvelopedHelper.Instance.GetRfc3211WrapperName(kekAlgName);
+				IWrapper			keyWrapper = WrapperUtilities.GetWrapper(cName);
+
+				byte[] iv = Asn1OctetString.GetInstance(kekAlgParams[1]).GetOctets();
+
+				ICipherParameters parameters = ((CmsPbeKey)key).GetEncoded(kekAlgName);
+				parameters = new ParametersWithIV(parameters, iv);
+
+				keyWrapper.Init(false, parameters);
+
+				KeyParameter sKey = ParameterUtilities.CreateKeyParameter(
+					GetContentAlgorithmName(), keyWrapper.Unwrap(encryptedKey, 0, encryptedKey.Length));
+
+				return GetContentFromSessionKey(sKey);
+			}
+			catch (SecurityUtilityException e)
+			{
+				throw new CmsException("couldn't create cipher.", e);
+			}
+			catch (InvalidKeyException e)
+			{
+				throw new CmsException("key invalid in message.", e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/cms/RecipientId.cs b/crypto/src/cms/RecipientId.cs
new file mode 100644
index 000000000..9b6eb093b
--- /dev/null
+++ b/crypto/src/cms/RecipientId.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+    public class RecipientID
+        : X509CertStoreSelector
+    {
+        private byte[] keyIdentifier;
+
+		public byte[] KeyIdentifier
+		{
+			get { return Arrays.Clone(keyIdentifier); }
+			set { keyIdentifier = Arrays.Clone(value); }
+		}
+
+		public override int GetHashCode()
+        {
+            int code = Arrays.GetHashCode(keyIdentifier)
+				^ Arrays.GetHashCode(this.SubjectKeyIdentifier);
+
+			BigInteger serialNumber = this.SerialNumber;
+			if (serialNumber != null)
+            {
+                code ^= serialNumber.GetHashCode();
+            }
+
+			X509Name issuer = this.Issuer;
+            if (issuer != null)
+            {
+                code ^= issuer.GetHashCode();
+            }
+
+            return code;
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+			if (obj == this)
+				return true;
+
+			RecipientID id = obj as RecipientID;
+
+			if (id == null)
+				return false;
+
+			return Arrays.AreEqual(keyIdentifier, id.keyIdentifier)
+				&& Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
+				&& Platform.Equals(SerialNumber, id.SerialNumber)
+				&& IssuersMatch(Issuer, id.Issuer);
+        }
+    }
+}
diff --git a/crypto/src/cms/RecipientInfoGenerator.cs b/crypto/src/cms/RecipientInfoGenerator.cs
new file mode 100644
index 000000000..c41db6122
--- /dev/null
+++ b/crypto/src/cms/RecipientInfoGenerator.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+	interface RecipientInfoGenerator
+	{
+		/// <summary>
+		/// Generate a RecipientInfo object for the given key.
+		/// </summary>
+		/// <param name="contentEncryptionKey">
+		/// A <see cref="KeyParameter"/>
+		/// </param>
+		/// <param name="random">
+		/// A <see cref="SecureRandom"/>
+		/// </param>
+		/// <returns>
+		/// A <see cref="RecipientInfo"/>
+		/// </returns>
+		/// <exception cref="GeneralSecurityException"></exception>
+		RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random);
+	}
+}
diff --git a/crypto/src/cms/RecipientInformation.cs b/crypto/src/cms/RecipientInformation.cs
new file mode 100644
index 000000000..8b0316be4
--- /dev/null
+++ b/crypto/src/cms/RecipientInformation.cs
@@ -0,0 +1,126 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Cms
+{
+    public abstract class RecipientInformation
+    {
+		internal RecipientID			rid = new RecipientID();
+		internal AlgorithmIdentifier	keyEncAlg;
+		internal CmsSecureReadable		secureReadable;
+		
+		private byte[] resultMac;
+
+		internal RecipientInformation(
+			AlgorithmIdentifier	keyEncAlg,
+			CmsSecureReadable	secureReadable)
+		{
+			this.keyEncAlg = keyEncAlg;
+			this.secureReadable = secureReadable;
+		}
+
+		internal string GetContentAlgorithmName()
+		{
+			AlgorithmIdentifier algorithm = secureReadable.Algorithm;
+//			return CmsEnvelopedHelper.Instance.GetSymmetricCipherName(algorithm.ObjectID.Id);
+			return algorithm.ObjectID.Id;
+		}
+
+		public RecipientID RecipientID
+        {
+			get { return rid; }
+        }
+
+		public AlgorithmIdentifier KeyEncryptionAlgorithmID
+		{
+			get { return keyEncAlg; }
+		}
+
+		/**
+        * return the object identifier for the key encryption algorithm.
+        * 
+		* @return OID for key encryption algorithm.
+        */
+        public string KeyEncryptionAlgOid
+        {
+			get { return keyEncAlg.ObjectID.Id; }
+        }
+
+		/**
+        * return the ASN.1 encoded key encryption algorithm parameters, or null if
+        * there aren't any.
+        * 
+		* @return ASN.1 encoding of key encryption algorithm parameters.
+        */
+		public Asn1Object KeyEncryptionAlgParams
+		{
+			get
+			{
+				Asn1Encodable ae = keyEncAlg.Parameters;
+
+				return ae == null ? null : ae.ToAsn1Object();
+			}
+		}
+
+		internal CmsTypedStream GetContentFromSessionKey(
+			KeyParameter sKey)
+		{
+			CmsReadable readable = secureReadable.GetReadable(sKey); 
+
+			try
+			{
+				return new CmsTypedStream(readable.GetInputStream());
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("error getting .", e);
+			}
+		}
+
+		public byte[] GetContent(
+            ICipherParameters key)
+        {
+            try
+            {
+				return CmsUtilities.StreamToByteArray(GetContentStream(key).ContentStream);
+            }
+            catch (IOException e)
+            {
+                throw new Exception("unable to parse internal stream: " + e);
+            }
+        }
+
+		/**
+		* Return the MAC calculated for the content stream. Note: this call is only meaningful once all
+		* the content has been read.
+		*
+		* @return  byte array containing the mac.
+		*/
+		public byte[] GetMac()
+		{
+			if (resultMac == null)
+			{
+				object cryptoObject = secureReadable.CryptoObject;
+				if (cryptoObject is IMac)
+				{
+					resultMac = MacUtilities.DoFinal((IMac)cryptoObject);
+				}
+			}
+
+			return Arrays.Clone(resultMac);
+		}
+		
+		public abstract CmsTypedStream GetContentStream(ICipherParameters key);
+	}
+}
diff --git a/crypto/src/cms/RecipientInformationStore.cs b/crypto/src/cms/RecipientInformationStore.cs
new file mode 100644
index 000000000..33b472f9d
--- /dev/null
+++ b/crypto/src/cms/RecipientInformationStore.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+	public class RecipientInformationStore
+	{
+		private readonly IList all; //ArrayList[RecipientInformation]
+		private readonly IDictionary table = Platform.CreateHashtable(); // Hashtable[RecipientID, ArrayList[RecipientInformation]]
+
+		public RecipientInformationStore(
+			ICollection recipientInfos)
+		{
+			foreach (RecipientInformation recipientInformation in recipientInfos)
+			{
+				RecipientID rid = recipientInformation.RecipientID;
+                IList list = (IList)table[rid];
+
+				if (list == null)
+				{
+					table[rid] = list = Platform.CreateArrayList(1);
+				}
+
+				list.Add(recipientInformation);
+			}
+
+            this.all = Platform.CreateArrayList(recipientInfos);
+		}
+
+		public RecipientInformation this[RecipientID selector]
+		{
+			get { return GetFirstRecipient(selector); }
+		}
+
+		/**
+		* Return the first RecipientInformation object that matches the
+		* passed in selector. Null if there are no matches.
+		*
+		* @param selector to identify a recipient
+		* @return a single RecipientInformation object. Null if none matches.
+		*/
+		public RecipientInformation GetFirstRecipient(
+			RecipientID selector)
+		{
+			IList list = (IList) table[selector];
+
+			return list == null ? null : (RecipientInformation) list[0];
+		}
+
+		/**
+		* Return the number of recipients in the collection.
+		*
+		* @return number of recipients identified.
+		*/
+		public int Count
+		{
+			get { return all.Count; }
+		}
+
+		/**
+		* Return all recipients in the collection
+		*
+		* @return a collection of recipients.
+		*/
+		public ICollection GetRecipients()
+		{
+			return Platform.CreateArrayList(all);
+		}
+
+		/**
+		* Return possible empty collection with recipients matching the passed in RecipientID
+		*
+		* @param selector a recipient id to select against.
+		* @return a collection of RecipientInformation objects.
+		*/
+		public ICollection GetRecipients(
+			RecipientID selector)
+		{
+            IList list = (IList)table[selector];
+
+            return list == null ? Platform.CreateArrayList() : Platform.CreateArrayList(list);
+		}
+	}
+}
diff --git a/crypto/src/cms/SigOutputStream.cs b/crypto/src/cms/SigOutputStream.cs
new file mode 100644
index 000000000..a807fa7fc
--- /dev/null
+++ b/crypto/src/cms/SigOutputStream.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal class SigOutputStream
+		: BaseOutputStream
+	{
+		private readonly ISigner sig;
+
+		internal SigOutputStream(ISigner sig)
+		{
+			this.sig = sig;
+		}
+
+		public override void WriteByte(byte b)
+		{
+			try
+			{
+				sig.Update(b);
+			}
+			catch (SignatureException e)
+			{
+				throw new CmsStreamException("signature problem: " + e);
+			}
+		}
+
+		public override void Write(byte[] b, int off, int len)
+		{
+			try
+			{
+				sig.BlockUpdate(b, off, len);
+			}
+			catch (SignatureException e)
+			{
+				throw new CmsStreamException("signature problem: " + e);
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/cms/SignerId.cs b/crypto/src/cms/SignerId.cs
new file mode 100644
index 000000000..baac9369b
--- /dev/null
+++ b/crypto/src/cms/SignerId.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * a basic index for a signer.
+    */
+    public class SignerID
+        : X509CertStoreSelector
+    {
+        public override int GetHashCode()
+        {
+            int code = Arrays.GetHashCode(this.SubjectKeyIdentifier);
+
+			BigInteger serialNumber = this.SerialNumber;
+			if (serialNumber != null)
+            {
+                code ^= serialNumber.GetHashCode();
+            }
+
+			X509Name issuer = this.Issuer;
+            if (issuer != null)
+            {
+                code ^= issuer.GetHashCode();
+            }
+
+			return code;
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+			if (obj == this)
+				return false;
+
+			SignerID id = obj as SignerID;
+
+			if (id == null)
+				return false;
+
+			return Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
+				&& Platform.Equals(SerialNumber, id.SerialNumber)
+				&& IssuersMatch(Issuer, id.Issuer);
+        }
+    }
+}
diff --git a/crypto/src/cms/SignerInfoGenerator.cs b/crypto/src/cms/SignerInfoGenerator.cs
new file mode 100644
index 000000000..f78cf2c01
--- /dev/null
+++ b/crypto/src/cms/SignerInfoGenerator.cs
@@ -0,0 +1,14 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+	internal interface SignerInfoGenerator
+	{
+		SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
+        	byte[] calculatedDigest);
+	}
+}
diff --git a/crypto/src/cms/SignerInformation.cs b/crypto/src/cms/SignerInformation.cs
new file mode 100644
index 000000000..20af29a50
--- /dev/null
+++ b/crypto/src/cms/SignerInformation.cs
@@ -0,0 +1,758 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* an expanded SignerInfo block from a CMS Signed message
+	*/
+	public class SignerInformation
+	{
+		private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+		private SignerID			sid;
+		private SignerInfo			info;
+		private AlgorithmIdentifier	digestAlgorithm;
+		private AlgorithmIdentifier	encryptionAlgorithm;
+		private readonly Asn1Set	signedAttributeSet;
+		private readonly Asn1Set	unsignedAttributeSet;
+		private CmsProcessable		content;
+		private byte[]				signature;
+		private DerObjectIdentifier	contentType;
+		private IDigestCalculator	digestCalculator;
+		private byte[]				resultDigest;
+
+		// Derived
+		private Asn1.Cms.AttributeTable	signedAttributeTable;
+		private Asn1.Cms.AttributeTable	unsignedAttributeTable;
+		private readonly bool isCounterSignature;
+
+		internal SignerInformation(
+			SignerInfo			info,
+			DerObjectIdentifier	contentType,
+			CmsProcessable		content,
+			IDigestCalculator	digestCalculator)
+		{
+			this.info = info;
+			this.sid = new SignerID();
+			this.contentType = contentType;
+			this.isCounterSignature = contentType == null;
+
+			try
+			{
+				SignerIdentifier s = info.SignerID;
+
+				if (s.IsTagged)
+				{
+					Asn1OctetString octs = Asn1OctetString.GetInstance(s.ID);
+
+					sid.SubjectKeyIdentifier = octs.GetEncoded();
+				}
+				else
+				{
+					Asn1.Cms.IssuerAndSerialNumber iAnds =
+						Asn1.Cms.IssuerAndSerialNumber.GetInstance(s.ID);
+
+					sid.Issuer = iAnds.Name;
+					sid.SerialNumber = iAnds.SerialNumber.Value;
+				}
+			}
+			catch (IOException)
+			{
+				throw new ArgumentException("invalid sid in SignerInfo");
+			}
+
+			this.digestAlgorithm = info.DigestAlgorithm;
+			this.signedAttributeSet = info.AuthenticatedAttributes;
+			this.unsignedAttributeSet = info.UnauthenticatedAttributes;
+			this.encryptionAlgorithm = info.DigestEncryptionAlgorithm;
+			this.signature = info.EncryptedDigest.GetOctets();
+
+			this.content = content;
+			this.digestCalculator = digestCalculator;
+		}
+
+		public bool IsCounterSignature
+		{
+			get { return isCounterSignature; }
+		}
+
+		public DerObjectIdentifier ContentType
+		{
+			get { return contentType; }
+		}
+
+		public SignerID SignerID
+		{
+			get { return sid; }
+		}
+
+		/**
+		* return the version number for this objects underlying SignerInfo structure.
+		*/
+		public int Version
+		{
+			get { return info.Version.Value.IntValue; }
+		}
+
+		public AlgorithmIdentifier DigestAlgorithmID
+		{
+			get { return digestAlgorithm; }
+		}
+
+		/**
+		* return the object identifier for the signature.
+		*/
+		public string DigestAlgOid
+		{
+			get { return digestAlgorithm.ObjectID.Id; }
+		}
+
+		/**
+		* return the signature parameters, or null if there aren't any.
+		*/
+		public Asn1Object DigestAlgParams
+		{
+			get
+			{
+				Asn1Encodable ae = digestAlgorithm.Parameters;
+
+				return ae == null ? null : ae.ToAsn1Object();
+			}
+		}
+
+		/**
+		 * return the content digest that was calculated during verification.
+		 */
+		public byte[] GetContentDigest()
+		{
+			if (resultDigest == null)
+			{
+				throw new InvalidOperationException("method can only be called after verify.");
+			}
+
+			return (byte[])resultDigest.Clone();
+		}
+
+		public AlgorithmIdentifier EncryptionAlgorithmID
+		{
+			get { return encryptionAlgorithm; }
+		}
+
+		/**
+		* return the object identifier for the signature.
+		*/
+		public string EncryptionAlgOid
+		{
+			get { return encryptionAlgorithm.ObjectID.Id; }
+		}
+
+		/**
+		* return the signature/encryption algorithm parameters, or null if
+		* there aren't any.
+		*/
+		public Asn1Object EncryptionAlgParams
+		{
+			get
+			{
+				Asn1Encodable ae = encryptionAlgorithm.Parameters;
+
+				return ae == null ? null : ae.ToAsn1Object();
+			}
+		}
+
+		/**
+		* return a table of the signed attributes - indexed by
+		* the OID of the attribute.
+		*/
+		public Asn1.Cms.AttributeTable SignedAttributes
+		{
+			get
+			{
+				if (signedAttributeSet != null && signedAttributeTable == null)
+				{
+					signedAttributeTable = new Asn1.Cms.AttributeTable(signedAttributeSet);
+				}
+				return signedAttributeTable;
+			}
+		}
+
+		/**
+		* return a table of the unsigned attributes indexed by
+		* the OID of the attribute.
+		*/
+		public Asn1.Cms.AttributeTable UnsignedAttributes
+		{
+			get
+			{
+				if (unsignedAttributeSet != null && unsignedAttributeTable == null)
+				{
+					unsignedAttributeTable = new Asn1.Cms.AttributeTable(unsignedAttributeSet);
+				}
+				return unsignedAttributeTable;
+			}
+		}
+
+		/**
+		* return the encoded signature
+		*/
+		public byte[] GetSignature()
+		{
+			return (byte[]) signature.Clone();
+		}
+
+		/**
+		* Return a SignerInformationStore containing the counter signatures attached to this
+		* signer. If no counter signatures are present an empty store is returned.
+		*/
+		public SignerInformationStore GetCounterSignatures()
+		{
+			// TODO There are several checks implied by the RFC3852 comments that are missing
+
+			/*
+			The countersignature attribute MUST be an unsigned attribute; it MUST
+			NOT be a signed attribute, an authenticated attribute, an
+			unauthenticated attribute, or an unprotected attribute.
+			*/
+			Asn1.Cms.AttributeTable unsignedAttributeTable = UnsignedAttributes;
+			if (unsignedAttributeTable == null)
+			{
+                return new SignerInformationStore(Platform.CreateArrayList(0));
+			}
+
+            IList counterSignatures = Platform.CreateArrayList();
+
+			/*
+			The UnsignedAttributes syntax is defined as a SET OF Attributes.  The
+			UnsignedAttributes in a signerInfo may include multiple instances of
+			the countersignature attribute.
+			*/
+			Asn1EncodableVector allCSAttrs = unsignedAttributeTable.GetAll(CmsAttributes.CounterSignature);
+
+			foreach (Asn1.Cms.Attribute counterSignatureAttribute in allCSAttrs)
+			{
+				/*
+				A countersignature attribute can have multiple attribute values.  The
+				syntax is defined as a SET OF AttributeValue, and there MUST be one
+				or more instances of AttributeValue present.
+				*/
+				Asn1Set values = counterSignatureAttribute.AttrValues;
+				if (values.Count < 1)
+				{
+					// TODO Throw an appropriate exception?
+				}
+
+				foreach (Asn1Encodable asn1Obj in values)
+				{
+					/*
+					Countersignature values have the same meaning as SignerInfo values
+					for ordinary signatures, except that:
+
+					   1. The signedAttributes field MUST NOT contain a content-type
+					      attribute; there is no content type for countersignatures.
+
+					   2. The signedAttributes field MUST contain a message-digest
+					      attribute if it contains any other attributes.
+
+					   3. The input to the message-digesting process is the contents
+					      octets of the DER encoding of the signatureValue field of the
+					      SignerInfo value with which the attribute is associated.
+					*/
+					SignerInfo si = SignerInfo.GetInstance(asn1Obj.ToAsn1Object());
+
+					string digestName = CmsSignedHelper.Instance.GetDigestAlgName(si.DigestAlgorithm.ObjectID.Id);
+
+					counterSignatures.Add(new SignerInformation(si, null, null, new CounterSignatureDigestCalculator(digestName, GetSignature())));
+				}
+			}
+
+			return new SignerInformationStore(counterSignatures);
+		}
+
+		/**
+		* return the DER encoding of the signed attributes.
+		* @throws IOException if an encoding error occurs.
+		*/
+		public byte[] GetEncodedSignedAttributes()
+		{
+			return signedAttributeSet == null
+				?	null
+				:	signedAttributeSet.GetEncoded(Asn1Encodable.Der);
+		}
+
+		private bool DoVerify(
+			AsymmetricKeyParameter	key)
+		{
+			string digestName = Helper.GetDigestAlgName(this.DigestAlgOid);
+			IDigest digest = Helper.GetDigestInstance(digestName);
+
+			DerObjectIdentifier sigAlgOid = this.encryptionAlgorithm.ObjectID;
+			Asn1Encodable sigParams = this.encryptionAlgorithm.Parameters;
+			ISigner sig;
+
+			if (sigAlgOid.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdRsassaPss))
+			{
+				// RFC 4056 2.2
+				// When the id-RSASSA-PSS algorithm identifier is used for a signature,
+				// the AlgorithmIdentifier parameters field MUST contain RSASSA-PSS-params.
+				if (sigParams == null)
+					throw new CmsException("RSASSA-PSS signature must specify algorithm parameters");
+
+				try
+				{
+					// TODO Provide abstract configuration mechanism
+					// (via alternate SignerUtilities.GetSigner method taking ASN.1 params)
+
+					Asn1.Pkcs.RsassaPssParameters pss = Asn1.Pkcs.RsassaPssParameters.GetInstance(
+						sigParams.ToAsn1Object());
+
+					if (!pss.HashAlgorithm.ObjectID.Equals(this.digestAlgorithm.ObjectID))
+						throw new CmsException("RSASSA-PSS signature parameters specified incorrect hash algorithm");
+					if (!pss.MaskGenAlgorithm.ObjectID.Equals(Asn1.Pkcs.PkcsObjectIdentifiers.IdMgf1))
+						throw new CmsException("RSASSA-PSS signature parameters specified unknown MGF");
+
+					IDigest pssDigest = DigestUtilities.GetDigest(pss.HashAlgorithm.ObjectID);
+					int saltLength = pss.SaltLength.Value.IntValue;
+					byte trailerField = (byte) pss.TrailerField.Value.IntValue;
+
+					// RFC 4055 3.1
+					// The value MUST be 1, which represents the trailer field with hexadecimal value 0xBC
+					if (trailerField != 1)
+						throw new CmsException("RSASSA-PSS signature parameters must have trailerField of 1");
+
+					sig = new PssSigner(new RsaBlindedEngine(), pssDigest, saltLength);
+				}
+				catch (Exception e)
+				{
+					throw new CmsException("failed to set RSASSA-PSS signature parameters", e);
+				}
+			}
+			else
+			{
+				// TODO Probably too strong a check at the moment
+//				if (sigParams != null)
+//					throw new CmsException("unrecognised signature parameters provided");
+
+				string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
+
+				sig = Helper.GetSignatureInstance(signatureName);
+			}
+
+			try
+			{
+				if (digestCalculator != null)
+				{
+					resultDigest = digestCalculator.GetDigest();
+				}
+				else
+				{
+					if (content != null)
+					{
+						content.Write(new DigOutputStream(digest));
+					}
+					else if (signedAttributeSet == null)
+					{
+						// TODO Get rid of this exception and just treat content==null as empty not missing?
+						throw new CmsException("data not encapsulated in signature - use detached constructor.");
+					}
+
+					resultDigest = DigestUtilities.DoFinal(digest);
+				}
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("can't process mime object to create signature.", e);
+			}
+
+			// RFC 3852 11.1 Check the content-type attribute is correct
+			{
+				Asn1Object validContentType = GetSingleValuedSignedAttribute(
+					CmsAttributes.ContentType, "content-type");
+				if (validContentType == null)
+				{
+					if (!isCounterSignature && signedAttributeSet != null)
+						throw new CmsException("The content-type attribute type MUST be present whenever signed attributes are present in signed-data");
+				}
+				else
+				{
+					if (isCounterSignature)
+						throw new CmsException("[For counter signatures,] the signedAttributes field MUST NOT contain a content-type attribute");
+
+					if (!(validContentType is DerObjectIdentifier))
+						throw new CmsException("content-type attribute value not of ASN.1 type 'OBJECT IDENTIFIER'");
+
+					DerObjectIdentifier signedContentType = (DerObjectIdentifier)validContentType;
+
+					if (!signedContentType.Equals(contentType))
+						throw new CmsException("content-type attribute value does not match eContentType");
+				}
+			}
+
+			// RFC 3852 11.2 Check the message-digest attribute is correct
+			{
+				Asn1Object validMessageDigest = GetSingleValuedSignedAttribute(
+					CmsAttributes.MessageDigest, "message-digest");
+				if (validMessageDigest == null)
+				{
+				    if (signedAttributeSet != null)
+						throw new CmsException("the message-digest signed attribute type MUST be present when there are any signed attributes present");
+				}
+				else
+				{
+					if (!(validMessageDigest is Asn1OctetString))
+					{
+						throw new CmsException("message-digest attribute value not of ASN.1 type 'OCTET STRING'");
+					}
+
+					Asn1OctetString signedMessageDigest = (Asn1OctetString)validMessageDigest;
+
+					if (!Arrays.AreEqual(resultDigest, signedMessageDigest.GetOctets()))
+						throw new CmsException("message-digest attribute value does not match calculated value");
+				}
+			}
+
+			// RFC 3852 11.4 Validate countersignature attribute(s)
+			{
+            	Asn1.Cms.AttributeTable signedAttrTable = this.SignedAttributes;
+            	if (signedAttrTable != null
+                	&& signedAttrTable.GetAll(CmsAttributes.CounterSignature).Count > 0)
+            	{
+                	throw new CmsException("A countersignature attribute MUST NOT be a signed attribute");
+            	}
+
+            	Asn1.Cms.AttributeTable unsignedAttrTable = this.UnsignedAttributes;
+            	if (unsignedAttrTable != null)
+            	{
+					foreach (Asn1.Cms.Attribute csAttr in unsignedAttrTable.GetAll(CmsAttributes.CounterSignature))
+	                {
+                    	if (csAttr.AttrValues.Count < 1)
+	                        throw new CmsException("A countersignature attribute MUST contain at least one AttributeValue");
+
+						// Note: We don't recursively validate the countersignature value
+    	            }
+	            }
+			}
+
+			try
+			{
+				sig.Init(false, key);
+
+				if (signedAttributeSet == null)
+				{
+					if (digestCalculator != null)
+					{
+						// need to decrypt signature and check message bytes
+						return VerifyDigest(resultDigest, key, this.GetSignature());
+					}
+					else if (content != null)
+					{
+						// TODO Use raw signature of the hash value instead
+						content.Write(new SigOutputStream(sig));
+					}
+				}
+				else
+				{
+					byte[] tmp = this.GetEncodedSignedAttributes();
+					sig.BlockUpdate(tmp, 0, tmp.Length);
+				}
+
+				return sig.VerifySignature(this.GetSignature());
+			}
+			catch (InvalidKeyException e)
+			{
+				throw new CmsException("key not appropriate to signature in message.", e);
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("can't process mime object to create signature.", e);
+			}
+			catch (SignatureException e)
+			{
+				throw new CmsException("invalid signature format in message: " + e.Message, e);
+			}
+		}
+
+		private bool IsNull(
+			Asn1Encodable o)
+		{
+			return (o is Asn1Null) || (o == null);
+		}
+
+		private DigestInfo DerDecode(
+			byte[] encoding)
+		{
+			if (encoding[0] != (int)(Asn1Tags.Constructed | Asn1Tags.Sequence))
+			{
+				throw new IOException("not a digest info object");
+			}
+
+			DigestInfo digInfo = DigestInfo.GetInstance(Asn1Object.FromByteArray(encoding));
+
+			// length check to avoid Bleichenbacher vulnerability
+
+			if (digInfo.GetEncoded().Length != encoding.Length)
+			{
+				throw new CmsException("malformed RSA signature");
+			}
+
+			return digInfo;
+		}
+
+		private bool VerifyDigest(
+			byte[]					digest,
+			AsymmetricKeyParameter	key,
+			byte[]					signature)
+		{
+			string algorithm = Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
+
+			try
+			{
+				if (algorithm.Equals("RSA"))
+				{
+					IBufferedCipher c = CmsEnvelopedHelper.Instance.CreateAsymmetricCipher("RSA/ECB/PKCS1Padding");
+
+					c.Init(false, key);
+
+					byte[] decrypt = c.DoFinal(signature);
+
+					DigestInfo digInfo = DerDecode(decrypt);
+
+					if (!digInfo.AlgorithmID.ObjectID.Equals(digestAlgorithm.ObjectID))
+					{
+						return false;
+					}
+
+					if (!IsNull(digInfo.AlgorithmID.Parameters))
+					{
+						return false;
+					}
+
+					byte[] sigHash = digInfo.GetDigest();
+
+					return Arrays.ConstantTimeAreEqual(digest, sigHash);
+				}
+				else if (algorithm.Equals("DSA"))
+				{
+					ISigner sig = SignerUtilities.GetSigner("NONEwithDSA");
+
+					sig.Init(false, key);
+
+					sig.BlockUpdate(digest, 0, digest.Length);
+
+					return sig.VerifySignature(signature);
+				}
+				else
+				{
+					throw new CmsException("algorithm: " + algorithm + " not supported in base signatures.");
+				}
+			}
+			catch (SecurityUtilityException e)
+			{
+				throw e;
+			}
+			catch (GeneralSecurityException e)
+			{
+				throw new CmsException("Exception processing signature: " + e, e);
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("Exception decoding signature: " + e, e);
+			}
+		}
+
+		/**
+		* verify that the given public key successfully handles and confirms the
+		* signature associated with this signer.
+		*/
+		public bool Verify(
+			AsymmetricKeyParameter pubKey)
+		{
+			if (pubKey.IsPrivate)
+				throw new ArgumentException("Expected public key", "pubKey");
+
+			// Optional, but still need to validate if present
+			GetSigningTime();
+
+			return DoVerify(pubKey);
+		}
+
+		/**
+		* verify that the given certificate successfully handles and confirms
+		* the signature associated with this signer and, if a signingTime
+		* attribute is available, that the certificate was valid at the time the
+		* signature was generated.
+		*/
+		public bool Verify(
+			X509Certificate cert)
+		{
+			Asn1.Cms.Time signingTime = GetSigningTime();
+			if (signingTime != null)
+			{
+				cert.CheckValidity(signingTime.Date);
+			}
+
+			return DoVerify(cert.GetPublicKey());
+		}
+
+		/**
+		* Return the base ASN.1 CMS structure that this object contains.
+		*
+		* @return an object containing a CMS SignerInfo structure.
+		*/
+		public SignerInfo ToSignerInfo()
+		{
+			return info;
+		}
+
+		private Asn1Object GetSingleValuedSignedAttribute(
+			DerObjectIdentifier attrOID, string printableName)
+		{
+
+			Asn1.Cms.AttributeTable unsignedAttrTable = this.UnsignedAttributes;
+			if (unsignedAttrTable != null
+				&& unsignedAttrTable.GetAll(attrOID).Count > 0)
+			{
+				throw new CmsException("The " + printableName
+					+ " attribute MUST NOT be an unsigned attribute");
+			}
+
+			Asn1.Cms.AttributeTable signedAttrTable = this.SignedAttributes;
+			if (signedAttrTable == null)
+			{
+				return null;
+			}
+
+			Asn1EncodableVector v = signedAttrTable.GetAll(attrOID);
+			switch (v.Count)
+			{
+				case 0:
+					return null;
+				case 1:
+					Asn1.Cms.Attribute t = (Asn1.Cms.Attribute) v[0];
+					Asn1Set attrValues = t.AttrValues;
+
+					if (attrValues.Count != 1)
+						throw new CmsException("A " + printableName
+							+ " attribute MUST have a single attribute value");
+
+					return attrValues[0].ToAsn1Object();
+				default:
+					throw new CmsException("The SignedAttributes in a signerInfo MUST NOT include multiple instances of the "
+						+ printableName + " attribute");
+			}
+		}
+
+		private Asn1.Cms.Time GetSigningTime()
+		{
+			Asn1Object validSigningTime = GetSingleValuedSignedAttribute(
+				CmsAttributes.SigningTime, "signing-time");
+
+			if (validSigningTime == null)
+				return null;
+
+			try
+			{
+				return Asn1.Cms.Time.GetInstance(validSigningTime);
+			}
+			catch (ArgumentException)
+			{
+				throw new CmsException("signing-time attribute value not a valid 'Time' structure");
+			}
+		}
+
+		/**
+		* Return a signer information object with the passed in unsigned
+		* attributes replacing the ones that are current associated with
+		* the object passed in.
+		*
+		* @param signerInformation the signerInfo to be used as the basis.
+		* @param unsignedAttributes the unsigned attributes to add.
+		* @return a copy of the original SignerInformationObject with the changed attributes.
+		*/
+		public static SignerInformation ReplaceUnsignedAttributes(
+			SignerInformation		signerInformation,
+			Asn1.Cms.AttributeTable	unsignedAttributes)
+		{
+			SignerInfo sInfo = signerInformation.info;
+			Asn1Set unsignedAttr = null;
+
+			if (unsignedAttributes != null)
+			{
+				unsignedAttr = new DerSet(unsignedAttributes.ToAsn1EncodableVector());
+			}
+
+			return new SignerInformation(
+				new SignerInfo(
+					sInfo.SignerID,
+					sInfo.DigestAlgorithm,
+					sInfo.AuthenticatedAttributes,
+					sInfo.DigestEncryptionAlgorithm,
+					sInfo.EncryptedDigest,
+					unsignedAttr),
+				signerInformation.contentType,
+				signerInformation.content,
+				null);
+		}
+
+		/**
+		 * Return a signer information object with passed in SignerInformationStore representing counter
+		 * signatures attached as an unsigned attribute.
+		 *
+		 * @param signerInformation the signerInfo to be used as the basis.
+		 * @param counterSigners signer info objects carrying counter signature.
+		 * @return a copy of the original SignerInformationObject with the changed attributes.
+		 */
+		public static SignerInformation AddCounterSigners(
+			SignerInformation		signerInformation,
+			SignerInformationStore	counterSigners)
+		{
+			// TODO Perform checks from RFC 3852 11.4
+
+			SignerInfo sInfo = signerInformation.info;
+			Asn1.Cms.AttributeTable unsignedAttr = signerInformation.UnsignedAttributes;
+			Asn1EncodableVector v;
+
+			if (unsignedAttr != null)
+			{
+				v = unsignedAttr.ToAsn1EncodableVector();
+			}
+			else
+			{
+				v = new Asn1EncodableVector();
+			}
+
+			Asn1EncodableVector sigs = new Asn1EncodableVector();
+
+			foreach (SignerInformation sigInf in counterSigners.GetSigners())
+			{
+				sigs.Add(sigInf.ToSignerInfo());
+			}
+
+			v.Add(new Asn1.Cms.Attribute(CmsAttributes.CounterSignature, new DerSet(sigs)));
+
+			return new SignerInformation(
+				new SignerInfo(
+					sInfo.SignerID,
+					sInfo.DigestAlgorithm,
+					sInfo.AuthenticatedAttributes,
+					sInfo.DigestEncryptionAlgorithm,
+					sInfo.EncryptedDigest,
+					new DerSet(v)),
+				signerInformation.contentType,
+				signerInformation.content,
+				null);
+		}
+	}
+}
diff --git a/crypto/src/cms/SignerInformationStore.cs b/crypto/src/cms/SignerInformationStore.cs
new file mode 100644
index 000000000..bd613843d
--- /dev/null
+++ b/crypto/src/cms/SignerInformationStore.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+    public class SignerInformationStore
+    {
+		private readonly IList all; //ArrayList[SignerInformation]
+		private readonly IDictionary table = Platform.CreateHashtable(); // Hashtable[SignerID, ArrayList[SignerInformation]]
+
+		public SignerInformationStore(
+            ICollection signerInfos)
+        {
+            foreach (SignerInformation signer in signerInfos)
+            {
+                SignerID sid = signer.SignerID;
+                IList list = (IList)table[sid];
+
+				if (list == null)
+				{
+					table[sid] = list = Platform.CreateArrayList(1);
+				}
+
+				list.Add(signer);
+            }
+
+            this.all = Platform.CreateArrayList(signerInfos);
+        }
+
+        /**
+        * Return the first SignerInformation object that matches the
+        * passed in selector. Null if there are no matches.
+        *
+        * @param selector to identify a signer
+        * @return a single SignerInformation object. Null if none matches.
+        */
+        public SignerInformation GetFirstSigner(
+            SignerID selector)
+        {
+			IList list = (IList) table[selector];
+
+			return list == null ? null : (SignerInformation) list[0];
+        }
+
+		/// <summary>The number of signers in the collection.</summary>
+		public int Count
+        {
+			get { return all.Count; }
+        }
+
+		/// <returns>An ICollection of all signers in the collection</returns>
+        public ICollection GetSigners()
+        {
+            return Platform.CreateArrayList(all);
+        }
+
+		/**
+        * Return possible empty collection with signers matching the passed in SignerID
+        *
+        * @param selector a signer id to select against.
+        * @return a collection of SignerInformation objects.
+        */
+        public ICollection GetSigners(
+            SignerID selector)
+        {
+			IList list = (IList) table[selector];
+
+            return list == null ? Platform.CreateArrayList() : Platform.CreateArrayList(list);
+        }
+    }
+}
diff --git a/crypto/src/cms/SimpleAttributeTableGenerator.cs b/crypto/src/cms/SimpleAttributeTableGenerator.cs
new file mode 100644
index 000000000..b3df21c29
--- /dev/null
+++ b/crypto/src/cms/SimpleAttributeTableGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	 * Basic generator that just returns a preconstructed attribute table
+	 */
+	public class SimpleAttributeTableGenerator
+		: CmsAttributeTableGenerator
+	{
+		private readonly AttributeTable attributes;
+
+		public SimpleAttributeTableGenerator(
+			AttributeTable attributes)
+		{
+			this.attributes = attributes;
+		}
+
+		public virtual AttributeTable GetAttributes(
+			IDictionary parameters)
+		{
+			return attributes;
+		}
+	}
+}
diff --git a/crypto/src/crypto/AsymmetricCipherKeyPair.cs b/crypto/src/crypto/AsymmetricCipherKeyPair.cs
new file mode 100644
index 000000000..b00a3dc02
--- /dev/null
+++ b/crypto/src/crypto/AsymmetricCipherKeyPair.cs
@@ -0,0 +1,52 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * a holding class for public/private parameter pairs.
+     */
+    public class AsymmetricCipherKeyPair
+    {
+        private readonly AsymmetricKeyParameter publicParameter;
+        private readonly AsymmetricKeyParameter privateParameter;
+
+		/**
+         * basic constructor.
+         *
+         * @param publicParam a public key parameters object.
+         * @param privateParam the corresponding private key parameters.
+         */
+        public AsymmetricCipherKeyPair(
+            AsymmetricKeyParameter    publicParameter,
+            AsymmetricKeyParameter    privateParameter)
+        {
+			if (publicParameter.IsPrivate)
+				throw new ArgumentException("Expected a public key", "publicParameter");
+			if (!privateParameter.IsPrivate)
+				throw new ArgumentException("Expected a private key", "privateParameter");
+
+			this.publicParameter = publicParameter;
+            this.privateParameter = privateParameter;
+        }
+
+		/**
+         * return the public key parameters.
+         *
+         * @return the public key parameters.
+         */
+        public AsymmetricKeyParameter Public
+        {
+            get { return publicParameter; }
+        }
+
+		/**
+         * return the private key parameters.
+         *
+         * @return the private key parameters.
+         */
+        public AsymmetricKeyParameter Private
+        {
+            get { return privateParameter; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/AsymmetricKeyParameter.cs b/crypto/src/crypto/AsymmetricKeyParameter.cs
new file mode 100644
index 000000000..7502ee305
--- /dev/null
+++ b/crypto/src/crypto/AsymmetricKeyParameter.cs
@@ -0,0 +1,47 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto
+{
+    public abstract class AsymmetricKeyParameter
+		: ICipherParameters
+    {
+        private readonly bool privateKey;
+
+        protected AsymmetricKeyParameter(
+            bool privateKey)
+        {
+            this.privateKey = privateKey;
+        }
+
+		public bool IsPrivate
+        {
+            get { return privateKey; }
+        }
+
+		public override bool Equals(
+			object obj)
+		{
+			AsymmetricKeyParameter other = obj as AsymmetricKeyParameter;
+
+			if (other == null)
+			{
+				return false;
+			}
+
+			return Equals(other);
+		}
+
+		protected bool Equals(
+			AsymmetricKeyParameter other)
+		{
+			return privateKey == other.privateKey;
+		}
+
+		public override int GetHashCode()
+		{
+			return privateKey.GetHashCode();
+		}
+    }
+}
diff --git a/crypto/src/crypto/BufferedAeadBlockCipher.cs b/crypto/src/crypto/BufferedAeadBlockCipher.cs
index 87413b69d..04bcb88ed 100644
--- a/crypto/src/crypto/BufferedAeadBlockCipher.cs
+++ b/crypto/src/crypto/BufferedAeadBlockCipher.cs
@@ -174,23 +174,18 @@ namespace Org.BouncyCastle.Crypto
 
 		public override byte[] DoFinal()
 		{
-			byte[] outBytes = EmptyBuffer;
+            byte[] outBytes = new byte[GetOutputSize(0)];
 
-			int length = GetOutputSize(0);
-			if (length > 0)
+            int pos = DoFinal(outBytes, 0);
+
+            if (pos < outBytes.Length)
 			{
-				outBytes = new byte[length];
-
-				int pos = DoFinal(outBytes, 0);
-				if (pos < outBytes.Length)
-				{
-					byte[] tmp = new byte[pos];
-					Array.Copy(outBytes, 0, tmp, 0, pos);
-					outBytes = tmp;
-				}
+				byte[] tmp = new byte[pos];
+				Array.Copy(outBytes, 0, tmp, 0, pos);
+				outBytes = tmp;
 			}
 
-			return outBytes;
+            return outBytes;
 		}
 
 		public override byte[] DoFinal(
@@ -201,29 +196,22 @@ namespace Org.BouncyCastle.Crypto
 			if (input == null)
 				throw new ArgumentNullException("input");
 
-			int length = GetOutputSize(inLen);
-
-			byte[] outBytes = EmptyBuffer;
+            byte[] outBytes = new byte[GetOutputSize(inLen)];
 
-			if (length > 0)
-			{
-				outBytes = new byte[length];
+            int pos = (inLen > 0)
+				?	ProcessBytes(input, inOff, inLen, outBytes, 0)
+				:	0;
 
-				int pos = (inLen > 0)
-					?	ProcessBytes(input, inOff, inLen, outBytes, 0)
-					:	0;
+			pos += DoFinal(outBytes, pos);
 
-				pos += DoFinal(outBytes, pos);
-
-				if (pos < outBytes.Length)
-				{
-					byte[] tmp = new byte[pos];
-					Array.Copy(outBytes, 0, tmp, 0, pos);
-					outBytes = tmp;
-				}
+            if (pos < outBytes.Length)
+			{
+				byte[] tmp = new byte[pos];
+				Array.Copy(outBytes, 0, tmp, 0, pos);
+				outBytes = tmp;
 			}
 
-			return outBytes;
+            return outBytes;
 		}
 
 		/**
diff --git a/crypto/src/crypto/BufferedAsymmetricBlockCipher.cs b/crypto/src/crypto/BufferedAsymmetricBlockCipher.cs
new file mode 100644
index 000000000..09ec59f69
--- /dev/null
+++ b/crypto/src/crypto/BufferedAsymmetricBlockCipher.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Engines;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+    * a buffer wrapper for an asymmetric block cipher, allowing input
+    * to be accumulated in a piecemeal fashion until final processing.
+    */
+    public class BufferedAsymmetricBlockCipher
+		: BufferedCipherBase
+    {
+		private readonly IAsymmetricBlockCipher cipher;
+
+		private byte[] buffer;
+		private int bufOff;
+
+		/**
+        * base constructor.
+        *
+        * @param cipher the cipher this buffering object wraps.
+        */
+        public BufferedAsymmetricBlockCipher(
+            IAsymmetricBlockCipher cipher)
+        {
+            this.cipher = cipher;
+		}
+
+		/**
+        * return the amount of data sitting in the buffer.
+        *
+        * @return the amount of data sitting in the buffer.
+        */
+        internal int GetBufferPosition()
+        {
+            return bufOff;
+        }
+
+		public override string AlgorithmName
+        {
+            get { return cipher.AlgorithmName; }
+        }
+
+		public override int GetBlockSize()
+        {
+			return cipher.GetInputBlockSize();
+        }
+
+		public override int GetOutputSize(
+			int length)
+		{
+			return cipher.GetOutputBlockSize();
+		}
+
+		public override int GetUpdateOutputSize(
+			int length)
+		{
+			return 0;
+		}
+
+		/**
+        * initialise the buffer and the underlying 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 override void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+			Reset();
+
+			cipher.Init(forEncryption, parameters);
+
+			//
+			// we allow for an extra byte where people are using their own padding
+			// mechanisms on a raw cipher.
+			//
+			this.buffer = new byte[cipher.GetInputBlockSize() + (forEncryption ? 1 : 0)];
+			this.bufOff = 0;
+        }
+
+		public override byte[] ProcessByte(
+			byte input)
+		{
+			if (bufOff >= buffer.Length)
+				throw new DataLengthException("attempt to process message to long for cipher");
+
+			buffer[bufOff++] = input;
+			return null;
+		}
+
+		public override byte[] ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (length < 1)
+				return null;
+
+			if (input == null)
+				throw new ArgumentNullException("input");
+			if (bufOff + length > buffer.Length)
+				throw new DataLengthException("attempt to process message to long for cipher");
+
+			Array.Copy(input, inOff, buffer, bufOff, length);
+			bufOff += length;
+			return null;
+		}
+
+		/**
+        * process the contents of the buffer using the underlying
+        * cipher.
+        *
+        * @return the result of the encryption/decryption process on the
+        * buffer.
+        * @exception InvalidCipherTextException if we are given a garbage block.
+        */
+        public override byte[] DoFinal()
+        {
+			byte[] outBytes = bufOff > 0
+				?	cipher.ProcessBlock(buffer, 0, bufOff)
+				:	EmptyBuffer;
+
+			Reset();
+
+			return outBytes;
+        }
+
+		public override byte[] DoFinal(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			ProcessBytes(input, inOff, length);
+			return DoFinal();
+		}
+
+		/// <summary>Reset the buffer</summary>
+        public override void Reset()
+        {
+			if (buffer != null)
+			{
+				Array.Clear(buffer, 0, buffer.Length);
+				bufOff = 0;
+			}
+        }
+    }
+}
diff --git a/crypto/src/crypto/BufferedBlockCipher.cs b/crypto/src/crypto/BufferedBlockCipher.cs
index 72bdfed67..3a98798a2 100644
--- a/crypto/src/crypto/BufferedBlockCipher.cs
+++ b/crypto/src/crypto/BufferedBlockCipher.cs
@@ -67,12 +67,11 @@ namespace Org.BouncyCastle.Crypto
 		{
 			this.forEncryption = forEncryption;
 
-			if (parameters is ParametersWithRandom)
-			{
-				parameters = ((ParametersWithRandom) parameters).Parameters;
-			}
+            ParametersWithRandom pwr = parameters as ParametersWithRandom;
+            if (pwr != null)
+                parameters = pwr.Parameters;
 
-			Reset();
+            Reset();
 
 			cipher.Init(forEncryption, parameters);
 		}
diff --git a/crypto/src/crypto/BufferedCipherBase.cs b/crypto/src/crypto/BufferedCipherBase.cs
new file mode 100644
index 000000000..9d8610211
--- /dev/null
+++ b/crypto/src/crypto/BufferedCipherBase.cs
@@ -0,0 +1,113 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+	public abstract class BufferedCipherBase
+		: IBufferedCipher
+	{
+		protected static readonly byte[] EmptyBuffer = new byte[0];
+
+		public abstract string AlgorithmName { get; }
+
+		public abstract void Init(bool forEncryption, ICipherParameters parameters);
+
+		public abstract int GetBlockSize();
+
+		public abstract int GetOutputSize(int inputLen);
+		public abstract int GetUpdateOutputSize(int inputLen);
+
+		public abstract byte[] ProcessByte(byte input);
+
+		public virtual int ProcessByte(
+			byte	input,
+			byte[]	output,
+			int		outOff)
+		{
+			byte[] outBytes = ProcessByte(input);
+			if (outBytes == null)
+				return 0;
+			if (outOff + outBytes.Length > output.Length)
+				throw new DataLengthException("output buffer too short");
+			outBytes.CopyTo(output, outOff);
+			return outBytes.Length;
+		}
+
+		public virtual byte[] ProcessBytes(
+			byte[] input)
+		{
+			return ProcessBytes(input, 0, input.Length);
+		}
+
+		public abstract byte[] ProcessBytes(byte[] input, int inOff, int length);
+
+		public virtual int ProcessBytes(
+			byte[]	input,
+			byte[]	output,
+			int		outOff)
+		{
+			return ProcessBytes(input, 0, input.Length, output, outOff);
+		}
+
+		public virtual int ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length,
+			byte[]	output,
+			int		outOff)
+		{
+			byte[] outBytes = ProcessBytes(input, inOff, length);
+			if (outBytes == null)
+				return 0;
+			if (outOff + outBytes.Length > output.Length)
+				throw new DataLengthException("output buffer too short");
+			outBytes.CopyTo(output, outOff);
+			return outBytes.Length;
+		}
+
+		public abstract byte[] DoFinal();
+
+		public virtual byte[] DoFinal(
+			byte[] input)
+		{
+			return DoFinal(input, 0, input.Length);
+		}
+
+		public abstract byte[] DoFinal(
+			byte[]	input,
+			int		inOff,
+			int		length);
+
+		public virtual int DoFinal(
+			byte[]	output,
+			int		outOff)
+		{
+			byte[] outBytes = DoFinal();
+			if (outOff + outBytes.Length > output.Length)
+				throw new DataLengthException("output buffer too short");
+			outBytes.CopyTo(output, outOff);
+			return outBytes.Length;
+		}
+
+		public virtual int DoFinal(
+			byte[]	input,
+			byte[]	output,
+			int		outOff)
+		{
+			return DoFinal(input, 0, input.Length, output, outOff);
+		}
+
+		public virtual int DoFinal(
+			byte[]	input,
+			int		inOff,
+			int		length,
+			byte[]	output,
+			int		outOff)
+		{
+			int len = ProcessBytes(input, inOff, length, output, outOff);
+			len += DoFinal(output, outOff + len);
+			return len;
+		}
+
+		public abstract void Reset();
+	}
+}
diff --git a/crypto/src/crypto/BufferedIesCipher.cs b/crypto/src/crypto/BufferedIesCipher.cs
new file mode 100644
index 000000000..6dab4ae33
--- /dev/null
+++ b/crypto/src/crypto/BufferedIesCipher.cs
@@ -0,0 +1,113 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto
+{
+	public class BufferedIesCipher
+		: BufferedCipherBase
+	{
+		private readonly IesEngine engine;
+		private bool forEncryption;
+		private MemoryStream buffer = new MemoryStream();
+
+		public BufferedIesCipher(
+			IesEngine engine)
+		{
+			if (engine == null)
+				throw new ArgumentNullException("engine");
+
+			this.engine = engine;
+		}
+
+		public override string AlgorithmName
+		{
+			// TODO Create IESEngine.AlgorithmName
+			get { return "IES"; }
+		}
+
+		public override void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			this.forEncryption = forEncryption;
+
+			// TODO
+			throw Platform.CreateNotImplementedException("IES");
+		}
+
+		public override int GetBlockSize()
+		{
+			return 0;
+		}
+
+		public override int GetOutputSize(
+			int inputLen)
+		{
+			if (engine == null)
+				throw new InvalidOperationException("cipher not initialised");
+
+			int baseLen = inputLen + (int) buffer.Length;
+			return forEncryption
+				?	baseLen + 20
+				:	baseLen - 20;
+		}
+
+		public override int GetUpdateOutputSize(
+			int inputLen)
+		{
+			return 0;
+		}
+
+		public override byte[] ProcessByte(
+			byte input)
+		{
+			buffer.WriteByte(input);
+			return null;
+		}
+
+		public override byte[] ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (input == null)
+				throw new ArgumentNullException("input");
+			if (inOff < 0)
+				throw new ArgumentException("inOff");
+			if (length < 0)
+				throw new ArgumentException("length");
+			if (inOff + length > input.Length)
+				throw new ArgumentException("invalid offset/length specified for input array");
+
+			buffer.Write(input, inOff, length);
+			return null;
+		}
+
+		public override byte[] DoFinal()
+		{
+			byte[] buf = buffer.ToArray();
+
+			Reset();
+
+			return engine.ProcessBlock(buf, 0, buf.Length);
+		}
+
+		public override byte[] DoFinal(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			ProcessBytes(input, inOff, length);
+			return DoFinal();
+		}
+
+		public override void Reset()
+		{
+			buffer.SetLength(0);
+		}
+	}
+}
diff --git a/crypto/src/crypto/BufferedStreamCipher.cs b/crypto/src/crypto/BufferedStreamCipher.cs
new file mode 100644
index 000000000..2d4987bba
--- /dev/null
+++ b/crypto/src/crypto/BufferedStreamCipher.cs
@@ -0,0 +1,131 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+	public class BufferedStreamCipher
+		: BufferedCipherBase
+	{
+		private readonly IStreamCipher cipher;
+
+		public BufferedStreamCipher(
+			IStreamCipher cipher)
+		{
+			if (cipher == null)
+				throw new ArgumentNullException("cipher");
+
+			this.cipher = cipher;
+		}
+
+		public override string AlgorithmName
+		{
+			get { return cipher.AlgorithmName; }
+		}
+
+		public override void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			cipher.Init(forEncryption, parameters);
+		}
+
+		public override int GetBlockSize()
+		{
+			return 0;
+		}
+
+		public override int GetOutputSize(
+			int inputLen)
+		{
+			return inputLen;
+		}
+
+		public override int GetUpdateOutputSize(
+			int inputLen)
+		{
+			return inputLen;
+		}
+
+		public override byte[] ProcessByte(
+			byte input)
+		{
+			return new byte[]{ cipher.ReturnByte(input) };
+		}
+
+		public override int ProcessByte(
+			byte	input,
+			byte[]	output,
+			int		outOff)
+		{
+			if (outOff >= output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			output[outOff] = cipher.ReturnByte(input);
+			return 1;
+		}
+
+		public override byte[] ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (length < 1)
+				return null;
+
+			byte[] output = new byte[length];
+			cipher.ProcessBytes(input, inOff, length, output, 0);
+			return output;
+		}
+
+		public override int ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length,
+			byte[]	output,
+			int		outOff)
+		{
+			if (length < 1)
+				return 0;
+
+			if (length > 0)
+			{
+				cipher.ProcessBytes(input, inOff, length, output, outOff);
+			}
+
+			return length;
+		}
+
+		public override byte[] DoFinal()
+		{
+			Reset();
+
+			return EmptyBuffer;
+		}
+
+		public override byte[] DoFinal(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (length < 1)
+				return EmptyBuffer;
+
+			byte[] output = ProcessBytes(input, inOff, length);
+
+			Reset();
+
+			return output;
+		}
+
+		public override void Reset()
+		{
+			cipher.Reset();
+		}
+	}
+}
diff --git a/crypto/src/crypto/CipherKeyGenerator.cs b/crypto/src/crypto/CipherKeyGenerator.cs
new file mode 100644
index 000000000..5d00d34dd
--- /dev/null
+++ b/crypto/src/crypto/CipherKeyGenerator.cs
@@ -0,0 +1,83 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/**
+	 * The base class for symmetric, or secret, cipher key generators.
+	 */
+	public class CipherKeyGenerator
+	{
+		protected internal SecureRandom	random;
+		protected internal int			strength;
+		private bool uninitialised = true;
+		private int defaultStrength;
+
+		public CipherKeyGenerator()
+		{
+		}
+
+		internal CipherKeyGenerator(
+			int defaultStrength)
+		{
+			if (defaultStrength < 1)
+				throw new ArgumentException("strength must be a positive value", "defaultStrength");
+
+			this.defaultStrength = defaultStrength;
+		}
+
+		public int DefaultStrength
+		{
+			get { return defaultStrength; }
+		}
+
+		/**
+		 * initialise the key generator.
+		 *
+		 * @param param the parameters to be used for key generation
+		 */
+		public void Init(
+			KeyGenerationParameters parameters)
+		{
+			if (parameters == null)
+				throw new ArgumentNullException("parameters");
+
+			this.uninitialised = false;
+
+			engineInit(parameters);
+		}
+
+		protected virtual void engineInit(
+			KeyGenerationParameters parameters)
+		{
+			this.random = parameters.Random;
+			this.strength = (parameters.Strength + 7) / 8;
+		}
+
+		/**
+		 * Generate a secret key.
+		 *
+		 * @return a byte array containing the key value.
+		 */
+		public byte[] GenerateKey()
+		{
+			if (uninitialised)
+			{
+				if (defaultStrength < 1)
+					throw new InvalidOperationException("Generator has not been initialised");
+
+				uninitialised = false;
+
+				engineInit(new KeyGenerationParameters(new SecureRandom(), defaultStrength));
+			}
+
+			return engineGenerateKey();
+		}
+
+		protected virtual byte[] engineGenerateKey()
+		{
+			return random.GenerateSeed(strength);
+		}
+	}
+}
diff --git a/crypto/src/crypto/CryptoException.cs b/crypto/src/crypto/CryptoException.cs
index c012063bb..67f0d86f2 100644
--- a/crypto/src/crypto/CryptoException.cs
+++ b/crypto/src/crypto/CryptoException.cs
@@ -2,6 +2,9 @@ using System;
 
 namespace Org.BouncyCastle.Crypto
 {
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
     public class CryptoException
 		: Exception
     {
diff --git a/crypto/src/crypto/DataLengthException.cs b/crypto/src/crypto/DataLengthException.cs
index 8bd695bbc..e9efc0bd3 100644
--- a/crypto/src/crypto/DataLengthException.cs
+++ b/crypto/src/crypto/DataLengthException.cs
@@ -8,6 +8,9 @@ namespace Org.BouncyCastle.Crypto
      * insufficient input. In general this exception will Get thrown rather
      * than an ArrayOutOfBounds exception.
      */
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
     public class DataLengthException
 		: CryptoException
 	{
diff --git a/crypto/src/crypto/IAsymmetricBlockCipher.cs b/crypto/src/crypto/IAsymmetricBlockCipher.cs
new file mode 100644
index 000000000..455cfaa69
--- /dev/null
+++ b/crypto/src/crypto/IAsymmetricBlockCipher.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/// <remarks>Base interface for a public/private key block cipher.</remarks>
+	public interface IAsymmetricBlockCipher
+    {
+		/// <summary>The name of the algorithm this cipher implements.</summary>
+        string AlgorithmName { get; }
+
+		/// <summary>Initialise the cipher.</summary>
+		/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
+		/// <param name="parameters">The key or other data required by the cipher.</param>
+        void Init(bool forEncryption, ICipherParameters parameters);
+
+		/// <returns>The maximum size, in bytes, an input block may be.</returns>
+        int GetInputBlockSize();
+
+		/// <returns>The maximum size, in bytes, an output block will be.</returns>
+		int GetOutputBlockSize();
+
+		/// <summary>Process a block.</summary>
+		/// <param name="inBuf">The input buffer.</param>
+		/// <param name="inOff">The offset into <paramref>inBuf</paramref> that the input block begins.</param>
+		/// <param name="inLen">The length of the input block.</param>
+		/// <exception cref="InvalidCipherTextException">Input decrypts improperly.</exception>
+		/// <exception cref="DataLengthException">Input is too large for the cipher.</exception>
+        byte[] ProcessBlock(byte[] inBuf, int inOff, int inLen);
+    }
+}
diff --git a/crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs b/crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs
new file mode 100644
index 000000000..9ec5dfada
--- /dev/null
+++ b/crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * interface that a public/private key pair generator should conform to.
+     */
+    public interface IAsymmetricCipherKeyPairGenerator
+    {
+        /**
+         * intialise the key pair generator.
+         *
+         * @param the parameters the key pair is to be initialised with.
+         */
+        void Init(KeyGenerationParameters parameters);
+
+        /**
+         * return an AsymmetricCipherKeyPair containing the Generated keys.
+         *
+         * @return an AsymmetricCipherKeyPair containing the Generated keys.
+         */
+        AsymmetricCipherKeyPair GenerateKeyPair();
+    }
+}
diff --git a/crypto/src/crypto/IBasicAgreement.cs b/crypto/src/crypto/IBasicAgreement.cs
index 8bd363d4e..7dfc618d6 100644
--- a/crypto/src/crypto/IBasicAgreement.cs
+++ b/crypto/src/crypto/IBasicAgreement.cs
@@ -15,6 +15,11 @@ namespace Org.BouncyCastle.Crypto
         void Init(ICipherParameters parameters);
 
         /**
+         * return the field size for the agreement algorithm in bytes.
+         */
+        int GetFieldSize();
+
+        /**
          * given a public key from a given party calculate the next
          * message in the agreement sequence.
          */
diff --git a/crypto/src/crypto/IBlockCipher.cs b/crypto/src/crypto/IBlockCipher.cs
new file mode 100644
index 000000000..a3ad6d6e5
--- /dev/null
+++ b/crypto/src/crypto/IBlockCipher.cs
@@ -0,0 +1,36 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/// <remarks>Base interface for a symmetric key block cipher.</remarks>
+    public interface IBlockCipher
+    {
+		/// <summary>The name of the algorithm this cipher implements.</summary>
+		string AlgorithmName { get; }
+
+		/// <summary>Initialise the cipher.</summary>
+		/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
+		/// <param name="parameters">The key or other data required by the cipher.</param>
+		void Init(bool forEncryption, ICipherParameters parameters);
+
+		/// <returns>The block size for this cipher, in bytes.</returns>
+		int GetBlockSize();
+
+		/// <summary>Indicates whether this cipher can handle partial blocks.</summary>
+		bool IsPartialBlockOkay { get; }
+
+		/// <summary>Process a block.</summary>
+		/// <param name="inBuf">The input buffer.</param>
+		/// <param name="inOff">The offset into <paramref>inBuf</paramref> that the input block begins.</param>
+		/// <param name="outBuf">The output buffer.</param>
+		/// <param name="outOff">The offset into <paramref>outBuf</paramref> to write the output block.</param>
+		/// <exception cref="DataLengthException">If input block is wrong size, or outBuf too small.</exception>
+		/// <returns>The number of bytes processed and produced.</returns>
+		int ProcessBlock(byte[] inBuf, int inOff, byte[] outBuf, int outOff);
+
+		/// <summary>
+		/// Reset the cipher to the same state as it was after the last init (if there was one).
+		/// </summary>
+        void Reset();
+    }
+}
diff --git a/crypto/src/crypto/IBufferedCipher.cs b/crypto/src/crypto/IBufferedCipher.cs
new file mode 100644
index 000000000..69dec9596
--- /dev/null
+++ b/crypto/src/crypto/IBufferedCipher.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/// <remarks>Block cipher engines are expected to conform to this interface.</remarks>
+    public interface IBufferedCipher
+    {
+		/// <summary>The name of the algorithm this cipher implements.</summary>
+		string AlgorithmName { get; }
+
+		/// <summary>Initialise the cipher.</summary>
+		/// <param name="forEncryption">If true the cipher is initialised for encryption,
+		/// if false for decryption.</param>
+		/// <param name="parameters">The key and other data required by the cipher.</param>
+        void Init(bool forEncryption, ICipherParameters parameters);
+
+		int GetBlockSize();
+
+		int GetOutputSize(int inputLen);
+
+		int GetUpdateOutputSize(int inputLen);
+
+		byte[] ProcessByte(byte input);
+		int ProcessByte(byte input, byte[] output, int outOff);
+
+		byte[] ProcessBytes(byte[] input);
+		byte[] ProcessBytes(byte[] input, int inOff, int length);
+		int ProcessBytes(byte[] input, byte[] output, int outOff);
+		int ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+		byte[] DoFinal();
+		byte[] DoFinal(byte[] input);
+		byte[] DoFinal(byte[] input, int inOff, int length);
+		int DoFinal(byte[] output, int outOff);
+		int DoFinal(byte[] input, byte[] output, int outOff);
+		int DoFinal(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+		/// <summary>
+		/// Reset the cipher. After resetting the cipher is in the same state
+		/// as it was after the last init (if there was one).
+		/// </summary>
+        void Reset();
+    }
+}
diff --git a/crypto/src/crypto/ICipherParameters.cs b/crypto/src/crypto/ICipherParameters.cs
new file mode 100644
index 000000000..fff0941c7
--- /dev/null
+++ b/crypto/src/crypto/ICipherParameters.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * all parameter classes implement this.
+     */
+    public interface ICipherParameters
+    {
+    }
+}
diff --git a/crypto/src/crypto/IDSA.cs b/crypto/src/crypto/IDSA.cs
new file mode 100644
index 000000000..46056d8ca
--- /dev/null
+++ b/crypto/src/crypto/IDSA.cs
@@ -0,0 +1,40 @@
+using System;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * interface for classes implementing the Digital Signature Algorithm
+     */
+    public interface IDsa
+    {
+		string AlgorithmName { get; }
+
+		/**
+         * 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.
+         */
+        void Init(bool forSigning, ICipherParameters parameters);
+
+        /**
+         * 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.
+         */
+        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.
+         */
+        bool VerifySignature(byte[] message, BigInteger  r, BigInteger s);
+    }
+}
diff --git a/crypto/src/crypto/IDerivationFunction.cs b/crypto/src/crypto/IDerivationFunction.cs
new file mode 100644
index 000000000..7f289f790
--- /dev/null
+++ b/crypto/src/crypto/IDerivationFunction.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * base interface for general purpose byte derivation functions.
+     */
+    public interface IDerivationFunction
+    {
+        void Init(IDerivationParameters parameters);
+
+        /**
+         * return the message digest used as the basis for the function
+         */
+        IDigest Digest
+        {
+            get;
+        }
+
+        int GenerateBytes(byte[] output, int outOff, int length);
+        //throws DataLengthException, ArgumentException;
+    }
+
+}
diff --git a/crypto/src/crypto/IDerivationParameters.cs b/crypto/src/crypto/IDerivationParameters.cs
new file mode 100644
index 000000000..f1c848568
--- /dev/null
+++ b/crypto/src/crypto/IDerivationParameters.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * Parameters for key/byte stream derivation classes
+     */
+    public interface IDerivationParameters
+    {
+    }
+}
diff --git a/crypto/src/crypto/IDigest.cs b/crypto/src/crypto/IDigest.cs
new file mode 100644
index 000000000..6769dcc42
--- /dev/null
+++ b/crypto/src/crypto/IDigest.cs
@@ -0,0 +1,61 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * interface that a message digest conforms to.
+     */
+    public interface IDigest
+    {
+        /**
+         * return the algorithm name
+         *
+         * @return the algorithm name
+         */
+        string AlgorithmName { get; }
+
+		/**
+         * 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.
+         */
+		int GetDigestSize();
+
+		/**
+         * return the size, in bytes, of the internal buffer used by this digest.
+         *
+         * @return the size, in bytes, of the internal buffer used by this digest.
+         */
+		int GetByteLength();
+
+		/**
+         * update the message digest with a single byte.
+         *
+         * @param inByte the input byte to be entered.
+         */
+        void Update(byte input);
+
+        /**
+         * update the message digest with a block of bytes.
+         *
+         * @param input 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.
+         */
+        void BlockUpdate(byte[] input, int inOff, int length);
+
+        /**
+         * Close the digest, producing the final digest value. The doFinal
+         * call leaves the digest reset.
+         *
+         * @param output the array the digest is to be copied into.
+         * @param outOff the offset into the out array the digest is to start at.
+         */
+        int DoFinal(byte[] output, int outOff);
+
+        /**
+         * reset the digest back to it's initial state.
+         */
+        void Reset();
+    }
+}
diff --git a/crypto/src/crypto/IMac.cs b/crypto/src/crypto/IMac.cs
new file mode 100644
index 000000000..03a86e8b6
--- /dev/null
+++ b/crypto/src/crypto/IMac.cs
@@ -0,0 +1,69 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * The base interface for implementations of message authentication codes (MACs).
+     */
+    public interface IMac
+    {
+        /**
+         * Initialise the MAC.
+         *
+         * @param param the key and other data required by the MAC.
+         * @exception ArgumentException if the parameters argument is
+         * inappropriate.
+         */
+        void Init(ICipherParameters parameters);
+
+        /**
+         * Return the name of the algorithm the MAC implements.
+         *
+         * @return the name of the algorithm the MAC implements.
+         */
+        string AlgorithmName { get; }
+
+		/**
+		 * Return the block size for this MAC (in bytes).
+		 *
+		 * @return the block size for this MAC in bytes.
+		 */
+		int GetMacSize();
+
+        /**
+         * add a single byte to the mac for processing.
+         *
+         * @param in the byte to be processed.
+         * @exception InvalidOperationException if the MAC is not initialised.
+         */
+        void Update(byte input);
+
+		/**
+         * @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 InvalidOperationException if the MAC is not initialised.
+         * @exception DataLengthException if there isn't enough data in in.
+         */
+        void BlockUpdate(byte[] input, int inOff, int len);
+
+		/**
+         * 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.
+         * </p>
+         * @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 InvalidOperationException if the MAC is not initialised.
+         */
+        int DoFinal(byte[] output, int outOff);
+
+		/**
+         * 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).
+         */
+        void Reset();
+    }
+}
diff --git a/crypto/src/crypto/ISigner.cs b/crypto/src/crypto/ISigner.cs
new file mode 100644
index 000000000..e03bbf4d3
--- /dev/null
+++ b/crypto/src/crypto/ISigner.cs
@@ -0,0 +1,50 @@
+
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto
+{
+    public interface ISigner
+    {
+        /**
+         * Return the name of the algorithm the signer implements.
+         *
+         * @return the name of the algorithm the signer implements.
+         */
+        string AlgorithmName { get; }
+
+		/**
+         * Initialise the signer for signing or verification.
+         *
+         * @param forSigning true if for signing, false otherwise
+         * @param param necessary parameters.
+         */
+         void Init(bool forSigning, ICipherParameters parameters);
+
+        /**
+         * update the internal digest with the byte b
+         */
+        void Update(byte input);
+
+        /**
+         * update the internal digest with the byte array in
+         */
+        void BlockUpdate(byte[] input, int inOff, int length);
+
+        /**
+         * Generate a signature for the message we've been loaded with using
+         * the key we were initialised with.
+         */
+        byte[] GenerateSignature();
+        /**
+         * return true if the internal state represents the signature described
+         * in the passed in array.
+         */
+        bool VerifySignature(byte[] signature);
+
+        /**
+         * reset the internal state
+         */
+        void Reset();
+    }
+}
diff --git a/crypto/src/crypto/ISignerWithRecovery.cs b/crypto/src/crypto/ISignerWithRecovery.cs
new file mode 100644
index 000000000..024f5cef5
--- /dev/null
+++ b/crypto/src/crypto/ISignerWithRecovery.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * Signer with message recovery.
+     */
+    public interface ISignerWithRecovery
+        : ISigner
+    {
+        /**
+         * Returns true if the signer has recovered the full message as
+         * part of signature verification.
+         *
+         * @return true if full message recovered.
+         */
+        bool HasFullMessage();
+
+        /**
+         * Returns a reference to what message was recovered (if any).
+         *
+         * @return full/partial message, null if nothing.
+         */
+        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
+		 */
+		void UpdateWithRecoveredMessage(byte[] signature);
+	}
+}
diff --git a/crypto/src/crypto/IStreamCipher.cs b/crypto/src/crypto/IStreamCipher.cs
new file mode 100644
index 000000000..8e575a7e5
--- /dev/null
+++ b/crypto/src/crypto/IStreamCipher.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/// <summary>The interface stream ciphers conform to.</summary>
+    public interface IStreamCipher
+    {
+		/// <summary>The name of the algorithm this cipher implements.</summary>
+		string AlgorithmName { get; }
+
+		/// <summary>Initialise the cipher.</summary>
+		/// <param name="forEncryption">If true the cipher is initialised for encryption,
+		/// if false for decryption.</param>
+		/// <param name="parameters">The key and other data required by the cipher.</param>
+		/// <exception cref="ArgumentException">
+		/// If the parameters argument is inappropriate.
+		/// </exception>
+        void Init(bool forEncryption, ICipherParameters parameters);
+
+		/// <summary>encrypt/decrypt a single byte returning the result.</summary>
+		/// <param name="input">the byte to be processed.</param>
+		/// <returns>the result of processing the input byte.</returns>
+        byte ReturnByte(byte input);
+
+		/// <summary>
+		/// Process a block of bytes from <c>input</c> putting the result into <c>output</c>.
+		/// </summary>
+		/// <param name="input">The input byte array.</param>
+		/// <param name="inOff">
+		/// The offset into <c>input</c> where the data to be processed starts.
+		/// </param>
+		/// <param name="length">The number of bytes to be processed.</param>
+		/// <param name="output">The output buffer the processed bytes go into.</param>
+		/// <param name="outOff">
+		/// The offset into <c>output</c> the processed data starts at.
+		/// </param>
+		/// <exception cref="DataLengthException">If the output buffer is too small.</exception>
+        void ProcessBytes(byte[] input, int inOff, int length, byte[] output, int outOff);
+
+		/// <summary>
+		/// Reset the cipher to the same state as it was after the last init (if there was one).
+		/// </summary>
+		void Reset();
+    }
+}
diff --git a/crypto/src/crypto/IWrapper.cs b/crypto/src/crypto/IWrapper.cs
new file mode 100644
index 000000000..58202b302
--- /dev/null
+++ b/crypto/src/crypto/IWrapper.cs
@@ -0,0 +1,18 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+    public interface IWrapper
+    {
+		/// <summary>The name of the algorithm this cipher implements.</summary>
+		string AlgorithmName { get; }
+
+		void Init(bool forWrapping, ICipherParameters parameters);
+
+		byte[] Wrap(byte[] input, int inOff, int length);
+
+        byte[] Unwrap(byte[] input, int inOff, int length);
+    }
+}
diff --git a/crypto/src/crypto/InvalidCipherTextException.cs b/crypto/src/crypto/InvalidCipherTextException.cs
index 598ea278d..4d2252654 100644
--- a/crypto/src/crypto/InvalidCipherTextException.cs
+++ b/crypto/src/crypto/InvalidCipherTextException.cs
@@ -6,6 +6,9 @@ namespace Org.BouncyCastle.Crypto
      * this exception is thrown whenever we find something we don't expect in a
      * message.
      */
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
     public class InvalidCipherTextException
 		: CryptoException
     {
diff --git a/crypto/src/crypto/KeyGenerationParameters.cs b/crypto/src/crypto/KeyGenerationParameters.cs
new file mode 100644
index 000000000..0cb6b07c7
--- /dev/null
+++ b/crypto/src/crypto/KeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * 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)
+        {
+			if (random == null)
+				throw new ArgumentNullException("random");
+			if (strength < 1)
+				throw new ArgumentException("strength must be a positive value", "strength");
+
+			this.random = random;
+            this.strength = strength;
+        }
+
+		/**
+         * return the random source associated with this
+         * generator.
+         *
+         * @return the generators random source.
+         */
+        public SecureRandom Random
+        {
+            get { 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 Strength
+        {
+            get { return strength; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/MaxBytesExceededException.cs b/crypto/src/crypto/MaxBytesExceededException.cs
index 9fa28abb0..be078cb13 100644
--- a/crypto/src/crypto/MaxBytesExceededException.cs
+++ b/crypto/src/crypto/MaxBytesExceededException.cs
@@ -6,7 +6,10 @@ namespace Org.BouncyCastle.Crypto
 	/// This exception is thrown whenever a cipher requires a change of key, iv
 	/// or similar after x amount of bytes enciphered
 	/// </summary>
-	public class MaxBytesExceededException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class MaxBytesExceededException
 		: CryptoException
 	{
 		public MaxBytesExceededException()
diff --git a/crypto/src/crypto/PbeParametersGenerator.cs b/crypto/src/crypto/PbeParametersGenerator.cs
index 0e96abd0f..21679d45e 100644
--- a/crypto/src/crypto/PbeParametersGenerator.cs
+++ b/crypto/src/crypto/PbeParametersGenerator.cs
@@ -5,186 +5,198 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto
 {
-	/**
-	 * super class for all Password Based Encyrption (Pbe) parameter generator classes.
-	 */
-	public abstract class PbeParametersGenerator
-	{
-		protected byte[]	mPassword;
-		protected byte[]	mSalt;
-		protected int		mIterationCount;
-
-		/**
-		 * 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 virtual void Init(
-			byte[]  password,
-			byte[]  salt,
-			int     iterationCount)
-		{
-			if (password == null)
-				throw new ArgumentNullException("password");
-			if (salt == null)
-				throw new ArgumentNullException("salt");
-
-			this.mPassword = Arrays.Clone(password);
-			this.mSalt = Arrays.Clone(salt);
-			this.mIterationCount = iterationCount;
-		}
-
-		public virtual byte[] Password
-		{
-			get { return Arrays.Clone(mPassword); }
-		}
-
-		/**
-		 * return the password byte array.
-		 *
-		 * @return the password byte array.
-		 */
-		[Obsolete("Use 'Password' property")]
-		public byte[] GetPassword()
-		{
-			return Password;
-		}
-
-		public virtual byte[] Salt
-		{
-			get { return Arrays.Clone(mSalt); }
-		}
-
-		/**
-		 * return the salt byte array.
-		 *
-		 * @return the salt byte array.
-		 */
-		[Obsolete("Use 'Salt' property")]
-		public byte[] GetSalt()
-		{
-			return Salt;
-		}
-
-		/**
-		 * return the iteration count.
-		 *
-		 * @return the iteration count.
-		 */
-		public virtual int IterationCount
-		{
-			get { return mIterationCount; }
-		}
-
-		/**
-		 * 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.
-		 */
-		[Obsolete("Use version with 'algorithm' parameter")]
-		public abstract ICipherParameters GenerateDerivedParameters(int keySize);
-		public abstract ICipherParameters GenerateDerivedParameters(string algorithm, 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.
-		 */
-		[Obsolete("Use version with 'algorithm' parameter")]
-		public abstract ICipherParameters GenerateDerivedParameters(int keySize, int ivSize);
-		public abstract ICipherParameters GenerateDerivedParameters(string algorithm, 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 ICipherParameters 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)
-		{
+    /**
+     * super class for all Password Based Encyrption (Pbe) parameter generator classes.
+     */
+    public abstract class PbeParametersGenerator
+    {
+        protected byte[]	mPassword;
+        protected byte[]	mSalt;
+        protected int		mIterationCount;
+
+        /**
+         * 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 virtual void Init(
+            byte[]  password,
+            byte[]  salt,
+            int     iterationCount)
+        {
+            if (password == null)
+                throw new ArgumentNullException("password");
+            if (salt == null)
+                throw new ArgumentNullException("salt");
+
+            this.mPassword = Arrays.Clone(password);
+            this.mSalt = Arrays.Clone(salt);
+            this.mIterationCount = iterationCount;
+        }
+
+        public virtual byte[] Password
+        {
+            get { return Arrays.Clone(mPassword); }
+        }
+
+        /**
+         * return the password byte array.
+         *
+         * @return the password byte array.
+         */
+        [Obsolete("Use 'Password' property")]
+        public byte[] GetPassword()
+        {
+            return Password;
+        }
+
+        public virtual byte[] Salt
+        {
+            get { return Arrays.Clone(mSalt); }
+        }
+
+        /**
+         * return the salt byte array.
+         *
+         * @return the salt byte array.
+         */
+        [Obsolete("Use 'Salt' property")]
+        public byte[] GetSalt()
+        {
+            return Salt;
+        }
+
+        /**
+         * return the iteration count.
+         *
+         * @return the iteration count.
+         */
+        public virtual int IterationCount
+        {
+            get { return mIterationCount; }
+        }
+
+        /**
+         * 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.
+         */
+        [Obsolete("Use version with 'algorithm' parameter")]
+        public abstract ICipherParameters GenerateDerivedParameters(int keySize);
+        public abstract ICipherParameters GenerateDerivedParameters(string algorithm, 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.
+         */
+        [Obsolete("Use version with 'algorithm' parameter")]
+        public abstract ICipherParameters GenerateDerivedParameters(int keySize, int ivSize);
+        public abstract ICipherParameters GenerateDerivedParameters(string algorithm, 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 ICipherParameters 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)
+        {
+            if (password == null)
+                return new byte[0];
+
             return Strings.ToAsciiByteArray(password);
-		}
+        }
+
+        [Obsolete("Use version taking 'char[]' instead")]
+        public static byte[] Pkcs5PasswordToBytes(
+            string password)
+        {
+            if (password == null)
+                return new byte[0];
 
-		[Obsolete("Use version taking 'char[]' instead")]
-		public static byte[] Pkcs5PasswordToBytes(
-			string password)
-		{
             return Strings.ToAsciiByteArray(password);
         }
 
-		/**
-		 * 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 Encoding.UTF8.GetBytes(password);
-		}
-
-		[Obsolete("Use version taking 'char[]' instead")]
-		public static byte[] Pkcs5PasswordToUtf8Bytes(
-			string password)
-		{
-			return Encoding.UTF8.GetBytes(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)
-		{
-			return Pkcs12PasswordToBytes(password, false);
-		}
-
-		public static byte[] Pkcs12PasswordToBytes(
-			char[]	password,
-			bool	wrongPkcs12Zero)
-		{
-			if (password.Length < 1)
-			{
-				return new byte[wrongPkcs12Zero ? 2 : 0];
-			}
-
-			// +1 for extra 2 pad bytes.
-			byte[] bytes = new byte[(password.Length + 1) * 2];
-
-			Encoding.BigEndianUnicode.GetBytes(password, 0, password.Length, bytes, 0);
-
-			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)
+        {
+            if (password == null)
+                return new byte[0];
+
+            return Encoding.UTF8.GetBytes(password);
+        }
+
+        [Obsolete("Use version taking 'char[]' instead")]
+        public static byte[] Pkcs5PasswordToUtf8Bytes(
+            string password)
+        {
+            if (password == null)
+                return new byte[0];
+
+            return Encoding.UTF8.GetBytes(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)
+        {
+            return Pkcs12PasswordToBytes(password, false);
+        }
+
+        public static byte[] Pkcs12PasswordToBytes(
+            char[]	password,
+            bool	wrongPkcs12Zero)
+        {
+            if (password == null || password.Length < 1)
+            {
+                return new byte[wrongPkcs12Zero ? 2 : 0];
+            }
+
+            // +1 for extra 2 pad bytes.
+            byte[] bytes = new byte[(password.Length + 1) * 2];
+
+            Encoding.BigEndianUnicode.GetBytes(password, 0, password.Length, bytes, 0);
+
+            return bytes;
+        }
+    }
 }
diff --git a/crypto/src/crypto/StreamBlockCipher.cs b/crypto/src/crypto/StreamBlockCipher.cs
new file mode 100644
index 000000000..ef2a8b68a
--- /dev/null
+++ b/crypto/src/crypto/StreamBlockCipher.cs
@@ -0,0 +1,109 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace 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
+		: IStreamCipher
+	{
+		private readonly IBlockCipher cipher;
+		private readonly byte[] oneByte = new byte[1];
+
+		/**
+		 * basic constructor.
+		 *
+		 * @param cipher the block cipher to be wrapped.
+		 * @exception ArgumentException if the cipher has a block size other than
+		 * one.
+		 */
+		public StreamBlockCipher(
+			IBlockCipher cipher)
+		{
+			if (cipher == null)
+				throw new ArgumentNullException("cipher");
+			if (cipher.GetBlockSize() != 1)
+				throw new ArgumentException("block cipher block size != 1.", "cipher");
+
+			this.cipher = cipher;
+		}
+
+		/**
+		 * initialise the underlying cipher.
+		 *
+		 * @param forEncryption true if we are setting up for encryption, false otherwise.
+		 * @param param the necessary parameters for the underlying cipher to be initialised.
+		 */
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			cipher.Init(forEncryption, parameters);
+		}
+
+		/**
+		* return the name of the algorithm we are wrapping.
+		*
+		* @return the name of the algorithm we are wrapping.
+		*/
+		public string AlgorithmName
+		{
+			get { return cipher.AlgorithmName; }
+		}
+
+		/**
+		* 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 input)
+		{
+			oneByte[0] = input;
+
+			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[]	input,
+			int		inOff,
+			int		length,
+			byte[]	output,
+			int		outOff)
+		{
+			if (outOff + length > output.Length)
+				throw new DataLengthException("output buffer too small in ProcessBytes()");
+
+			for (int i = 0; i != length; i++)
+			{
+				cipher.ProcessBlock(input, inOff + i, output, 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/crypto/src/crypto/agreement/DHAgreement.cs b/crypto/src/crypto/agreement/DHAgreement.cs
new file mode 100644
index 000000000..d214caafe
--- /dev/null
+++ b/crypto/src/crypto/agreement/DHAgreement.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+	/**
+	 * a Diffie-Hellman key exchange engine.
+	 * <p>
+	 * note: This uses MTI/A0 key agreement in order to make the key agreement
+	 * secure against passive attacks. If you're doing Diffie-Hellman and both
+	 * parties have long term public keys you should look at using this. For
+	 * further information have a look at RFC 2631.</p>
+	 * <p>
+	 * It's possible to extend this to more than two parties as well, for the moment
+	 * that is left as an exercise for the reader.</p>
+	 */
+	public class DHAgreement
+	{
+		private DHPrivateKeyParameters  key;
+		private DHParameters			dhParams;
+		private BigInteger				privateValue;
+		private SecureRandom			random;
+
+		public void Init(
+			ICipherParameters parameters)
+		{
+			AsymmetricKeyParameter kParam;
+			if (parameters is ParametersWithRandom)
+			{
+				ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+				this.random = rParam.Random;
+				kParam = (AsymmetricKeyParameter)rParam.Parameters;
+			}
+			else
+			{
+				this.random = new SecureRandom();
+				kParam = (AsymmetricKeyParameter)parameters;
+			}
+
+			if (!(kParam is DHPrivateKeyParameters))
+			{
+				throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
+			}
+
+			this.key = (DHPrivateKeyParameters)kParam;
+			this.dhParams = key.Parameters;
+		}
+
+		/**
+		 * calculate our initial message.
+		 */
+		public BigInteger CalculateMessage()
+		{
+			DHKeyPairGenerator dhGen = new DHKeyPairGenerator();
+			dhGen.Init(new DHKeyGenerationParameters(random, dhParams));
+			AsymmetricCipherKeyPair dhPair = dhGen.GenerateKeyPair();
+
+			this.privateValue = ((DHPrivateKeyParameters)dhPair.Private).X;
+
+			return ((DHPublicKeyParameters)dhPair.Public).Y;
+		}
+
+		/**
+		 * given a message from a given party and the corresponding public key
+		 * calculate the next message in the agreement sequence. In this case
+		 * this will represent the shared secret.
+		 */
+		public BigInteger CalculateAgreement(
+			DHPublicKeyParameters	pub,
+			BigInteger				message)
+		{
+			if (pub == null)
+				throw new ArgumentNullException("pub");
+			if (message == null)
+				throw new ArgumentNullException("message");
+
+			if (!pub.Parameters.Equals(dhParams))
+			{
+				throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
+			}
+
+			BigInteger p = dhParams.P;
+
+			return message.ModPow(key.X, p).Multiply(pub.Y.ModPow(privateValue, p)).Mod(p);
+		}
+	}
+}
diff --git a/crypto/src/crypto/agreement/DHBasicAgreement.cs b/crypto/src/crypto/agreement/DHBasicAgreement.cs
index 5a5277049..75b5e9db5 100644
--- a/crypto/src/crypto/agreement/DHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/DHBasicAgreement.cs
@@ -6,55 +6,59 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Agreement
 {
-	/**
-	 * 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.</p>
-	 */
-	public class DHBasicAgreement
-		: IBasicAgreement
-	{
-		private DHPrivateKeyParameters	key;
-		private DHParameters			dhParams;
-
-		public void Init(
-			ICipherParameters parameters)
-		{
-			if (parameters is ParametersWithRandom)
-			{
-				parameters = ((ParametersWithRandom) parameters).Parameters;
-			}
-
-			if (!(parameters is DHPrivateKeyParameters))
-			{
-				throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
-			}
-
-			this.key = (DHPrivateKeyParameters) parameters;
-			this.dhParams = key.Parameters;
-		}
-
-		/**
-		 * given a short term public key from a given party calculate the next
-		 * message in the agreement sequence.
-		 */
-		public BigInteger CalculateAgreement(
-			ICipherParameters pubKey)
-		{
-			if (this.key == null)
-				throw new InvalidOperationException("Agreement algorithm not initialised");
-
-			DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey;
-
-			if (!pub.Parameters.Equals(dhParams))
-			{
-				throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
-			}
-
-			return pub.Y.ModPow(key.X, dhParams.P);
-		}
-	}
+    /**
+     * 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.</p>
+     */
+    public class DHBasicAgreement
+        : IBasicAgreement
+    {
+        private DHPrivateKeyParameters	key;
+        private DHParameters			dhParams;
 
+        public virtual void Init(
+            ICipherParameters parameters)
+        {
+            if (parameters is ParametersWithRandom)
+            {
+                parameters = ((ParametersWithRandom) parameters).Parameters;
+            }
+
+            if (!(parameters is DHPrivateKeyParameters))
+            {
+                throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
+            }
+
+            this.key = (DHPrivateKeyParameters) parameters;
+            this.dhParams = key.Parameters;
+        }
+
+        public virtual int GetFieldSize()
+        {
+            return (key.Parameters.P.BitLength + 7) / 8;
+        }
+
+        /**
+         * given a short term public key from a given party calculate the next
+         * message in the agreement sequence.
+         */
+        public virtual BigInteger CalculateAgreement(
+            ICipherParameters pubKey)
+        {
+            if (this.key == null)
+                throw new InvalidOperationException("Agreement algorithm not initialised");
+
+            DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey;
+
+            if (!pub.Parameters.Equals(dhParams))
+            {
+                throw new ArgumentException("Diffie-Hellman public key has wrong parameters.");
+            }
+
+            return pub.Y.ModPow(key.X, dhParams.P);
+        }
+    }
 }
diff --git a/crypto/src/crypto/agreement/DHStandardGroups.cs b/crypto/src/crypto/agreement/DHStandardGroups.cs
new file mode 100644
index 000000000..6c46b60de
--- /dev/null
+++ b/crypto/src/crypto/agreement/DHStandardGroups.cs
@@ -0,0 +1,206 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+    /// <summary>Standard Diffie-Hellman groups from various IETF specifications.</summary>
+    public class DHStandardGroups
+    {
+        private static DHParameters FromPG(string hexP, string hexG)
+        {
+            BigInteger p = new BigInteger(1, Hex.Decode(hexP));
+            BigInteger g = new BigInteger(1, Hex.Decode(hexG));
+            return new DHParameters(p, g);
+        }
+
+        private static DHParameters FromPGQ(string hexP, string hexG, string hexQ)
+        {
+            BigInteger p = new BigInteger(1, Hex.Decode(hexP));
+            BigInteger g = new BigInteger(1, Hex.Decode(hexG));
+            BigInteger q = new BigInteger(1, Hex.Decode(hexQ));
+            return new DHParameters(p, g, q);
+        }
+
+        /*
+         * RFC 2409
+         */
+        private static readonly string rfc2409_768_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+            + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+            + "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF";
+        private static readonly string rfc2409_768_g = "02";
+        public static readonly DHParameters rfc2409_768 = FromPG(rfc2409_768_p, rfc2409_768_g);
+
+        private static readonly string rfc2409_1024_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+            + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+            + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+            + "FFFFFFFFFFFFFFFF";
+        private static readonly string rfc2409_1024_g = "02";
+        public static readonly DHParameters rfc2409_1024 = FromPG(rfc2409_1024_p, rfc2409_1024_g);
+
+        /*
+         * RFC 3526
+         */
+        private static readonly string rfc3526_1536_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+            + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+            + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+            + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+            + "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
+        private static readonly string rfc3526_1536_g = "02";
+        public static readonly DHParameters rfc3526_1536 = FromPG(rfc3526_1536_p, rfc3526_1536_g);
+
+        private static readonly string rfc3526_2048_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+            + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+            + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+            + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+            + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+            + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AACAA68FFFFFFFFFFFFFFFF";
+        private static readonly string rfc3526_2048_g = "02";
+        public static readonly DHParameters rfc3526_2048 = FromPG(rfc3526_2048_p, rfc3526_2048_g);
+
+        private static readonly string rfc3526_3072_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+            + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+            + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+            + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+            + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+            + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+            + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+            + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+            + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
+        private static readonly string rfc3526_3072_g = "02";
+        public static readonly DHParameters rfc3526_3072 = FromPG(rfc3526_3072_p, rfc3526_3072_g);
+
+        private static readonly string rfc3526_4096_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+            + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+            + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+            + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+            + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+            + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+            + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+            + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+            + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+            + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+            + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
+            + "FFFFFFFFFFFFFFFF";
+        private static readonly string rfc3526_4096_g = "02";
+        public static readonly DHParameters rfc3526_4096 = FromPG(rfc3526_4096_p, rfc3526_4096_g);
+
+        private static readonly string rfc3526_6144_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
+            + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
+            + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
+            + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
+            + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8"
+            + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+            + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C"
+            + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718"
+            + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D"
+            + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D"
+            + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226"
+            + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+            + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC"
+            + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26"
+            + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB"
+            + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2"
+            + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127"
+            + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+            + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406"
+            + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918"
+            + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151"
+            + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03"
+            + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F"
+            + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+            + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B"
+            + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632"
+            + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E"
+            + "6DCC4024FFFFFFFFFFFFFFFF";
+        private static readonly string rfc3526_6144_g = "02";
+        public static readonly DHParameters rfc3526_6144 = FromPG(rfc3526_6144_p, rfc3526_6144_g);
+
+        private static readonly string rfc3526_8192_p = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+            + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+            + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+            + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+            + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+            + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+            + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+            + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+            + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+            + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+            + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+            + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" + "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+            + "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" + "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+            + "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" + "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+            + "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+            + "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" + "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+            + "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" + "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
+            + "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" + "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+            + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" + "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
+            + "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" + "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
+            + "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" + "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
+            + "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF";
+        private static readonly string rfc3526_8192_g = "02";
+        public static readonly DHParameters rfc3526_8192 = FromPG(rfc3526_8192_p, rfc3526_8192_g);
+
+        /*
+         * RFC 4306
+         */
+        public static readonly DHParameters rfc4306_768 = rfc2409_768;
+        public static readonly DHParameters rfc4306_1024 = rfc2409_1024;
+
+        /*
+         * RFC 5114
+         */
+        private static readonly string rfc5114_1024_160_p = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6"
+            + "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0" + "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70"
+            + "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0" + "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708"
+            + "DF1FB2BC2E4A4371";
+        private static readonly string rfc5114_1024_160_g = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F"
+            + "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213" + "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1"
+            + "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" + "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
+            + "855E6EEB22B3B2E5";
+        private static readonly string rfc5114_1024_160_q = "F518AA8781A8DF278ABA4E7D64B7CB9D49462353";
+        public static readonly DHParameters rfc5114_1024_160 = FromPGQ(rfc5114_1024_160_p, rfc5114_1024_160_g,
+            rfc5114_1024_160_q);
+
+        private static readonly string rfc5114_2048_224_p = "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1"
+            + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212"
+            + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708"
+            + "B3BF8A317091883681286130BC8985DB1602E714415D9330" + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D"
+            + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763"
+            + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" + "CF9DE5384E71B81C0AC4DFFE0C10E64F";
+        private static readonly string rfc5114_2048_224_g = "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"
+            + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA" + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"
+            + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A" + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"
+            + "F180EB34118E98D119529A45D6F834566E3025E316A330EF" + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"
+            + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381" + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"
+            + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179" + "81BC087F2A7065B384B890D3191F2BFA";
+        private static readonly string rfc5114_2048_224_q = "801C0D34C58D93FE997177101F80535A4738CEBCBF389A99B36371EB";
+        public static readonly DHParameters rfc5114_2048_224 = FromPGQ(rfc5114_2048_224_p, rfc5114_2048_224_g,
+            rfc5114_2048_224_q);
+
+        private static readonly string rfc5114_2048_256_p = "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F2"
+            + "5D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA30" + "16C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD"
+            + "5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B" + "6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C"
+            + "4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0E" + "F13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D9"
+            + "67E144E5140564251CCACB83E6B486F6B3CA3F7971506026" + "C0B857F689962856DED4010ABD0BE621C3A3960A54E710C3"
+            + "75F26375D7014103A4B54330C198AF126116D2276E11715F" + "693877FAD7EF09CADB094AE91E1A1597";
+        private static readonly string rfc5114_2048_256_g = "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF2054"
+            + "07F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555" + "BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18"
+            + "A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B" + "777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC83"
+            + "1D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55" + "A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14"
+            + "C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915" + "B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6"
+            + "184B523D1DB246C32F63078490F00EF8D647D148D4795451" + "5E2327CFEF98C582664B4C0F6CC41659";
+        private static readonly string rfc5114_2048_256_q = "8CF83642A709A097B447997640129DA299B1A47D1EB3750B"
+            + "A308B0FE64F5FBD3";
+        public static readonly DHParameters rfc5114_2048_256 = FromPGQ(rfc5114_2048_256_p, rfc5114_2048_256_g,
+            rfc5114_2048_256_q);
+
+        /*
+         * RFC 5996
+         */
+        public static readonly DHParameters rfc5996_768 = rfc4306_768;
+        public static readonly DHParameters rfc5996_1024 = rfc4306_1024;
+    }
+}
diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
index f272e4969..c33f16f78 100644
--- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -1,3 +1,5 @@
+using System;
+
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Crypto;
@@ -20,31 +22,36 @@ namespace Org.BouncyCastle.Crypto.Agreement
      * Section 7.2.2).
      */
     public class ECDHBasicAgreement
-		: IBasicAgreement
+        : IBasicAgreement
     {
         protected internal ECPrivateKeyParameters privKey;
 
-        public void Init(
-			ICipherParameters parameters)
+        public virtual void Init(
+            ICipherParameters parameters)
         {
-			if (parameters is ParametersWithRandom)
-			{
-				parameters = ((ParametersWithRandom)parameters).Parameters;
-			}
+            if (parameters is ParametersWithRandom)
+            {
+                parameters = ((ParametersWithRandom)parameters).Parameters;
+            }
 
-			this.privKey = (ECPrivateKeyParameters)parameters;
+            this.privKey = (ECPrivateKeyParameters)parameters;
+        }
+
+        public virtual int GetFieldSize()
+        {
+            return (privKey.Parameters.Curve.FieldSize + 7) / 8;
         }
 
         public virtual BigInteger CalculateAgreement(
             ICipherParameters pubKey)
         {
             ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
-            ECPoint P = pub.Q.Multiply(privKey.D);
+            ECPoint P = pub.Q.Multiply(privKey.D).Normalize();
 
-            // if ( p.IsInfinity ) throw new Exception("d*Q == infinity");
+            if (P.IsInfinity)
+                throw new InvalidOperationException("Infinity is not a valid agreement value for ECDH");
 
-            return P.X.ToBigInteger();
+            return P.AffineXCoord.ToBigInteger();
         }
     }
-
 }
diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
index 905d241fc..89be7061e 100644
--- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -27,32 +27,40 @@ namespace Org.BouncyCastle.Crypto.Agreement
      * BasicAgreement!).</p>
      */
     public class ECDHCBasicAgreement
-		: IBasicAgreement
+        : IBasicAgreement
     {
         private ECPrivateKeyParameters key;
 
-        public void Init(
+        public virtual void Init(
             ICipherParameters parameters)
         {
-			if (parameters is ParametersWithRandom)
-			{
-				parameters = ((ParametersWithRandom) parameters).Parameters;
-			}
+            if (parameters is ParametersWithRandom)
+            {
+                parameters = ((ParametersWithRandom) parameters).Parameters;
+            }
 
-			this.key = (ECPrivateKeyParameters)parameters;
+            this.key = (ECPrivateKeyParameters)parameters;
         }
 
-        public BigInteger CalculateAgreement(
+        public virtual int GetFieldSize()
+        {
+            return (key.Parameters.Curve.FieldSize + 7) / 8;
+        }
+
+        public virtual BigInteger CalculateAgreement(
             ICipherParameters pubKey)
         {
             ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
             ECDomainParameters parameters = pub.Parameters;
-            ECPoint P = pub.Q.Multiply(parameters.H.Multiply(key.D));
 
-            // if ( p.IsInfinity ) throw new Exception("Invalid public key");
+            BigInteger hd = parameters.H.Multiply(key.D).Mod(parameters.N);
 
-            return P.X.ToBigInteger();
+            ECPoint P = pub.Q.Multiply(hd).Normalize();
+
+            if (P.IsInfinity)
+                throw new InvalidOperationException("Infinity is not a valid agreement value for ECDHC");
+
+            return P.AffineXCoord.ToBigInteger();
         }
     }
-
 }
diff --git a/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
index 28437a268..1de80d1e5 100644
--- a/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Crypto.Agreement
 			DHKdfParameters dhKdfParams = new DHKdfParameters(
 				new DerObjectIdentifier(algorithm),
 				keySize,
-				bigIntToBytes(result));
+				BigIntToBytes(result));
 
 			kdf.Init(dhKdfParams);
 
@@ -54,10 +54,9 @@ namespace Org.BouncyCastle.Crypto.Agreement
 			return new BigInteger(1, keyBytes);
 		}
 
-		private byte[] bigIntToBytes(
-			BigInteger r)
+		private byte[] BigIntToBytes(BigInteger r)
 		{
-			int byteLength = X9IntegerConverter.GetByteLength(privKey.Parameters.G.X);
+			int byteLength = X9IntegerConverter.GetByteLength(privKey.Parameters.Curve);
 			return X9IntegerConverter.IntegerToBytes(r, byteLength);
 		}
 	}
diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
index 51faa8e49..f55ae46af 100644
--- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -7,79 +7,83 @@ using Org.BouncyCastle.Math.EC;
 
 namespace Org.BouncyCastle.Crypto.Agreement
 {
-	public class ECMqvBasicAgreement
-		: IBasicAgreement
-	{
-		protected internal MqvPrivateParameters privParams;
-
-		public void Init(
-			ICipherParameters parameters)
-		{
-			if (parameters is ParametersWithRandom)
-			{
-				parameters = ((ParametersWithRandom)parameters).Parameters;
-			}
-
-			this.privParams = (MqvPrivateParameters)parameters;
-		}
-
-		public virtual BigInteger CalculateAgreement(
-			ICipherParameters pubKey)
-		{
-			MqvPublicParameters pubParams = (MqvPublicParameters)pubKey;
-
-			ECPrivateKeyParameters staticPrivateKey = privParams.StaticPrivateKey;
-
-			ECPoint agreement = calculateMqvAgreement(staticPrivateKey.Parameters, staticPrivateKey,
-				privParams.EphemeralPrivateKey, privParams.EphemeralPublicKey,
-				pubParams.StaticPublicKey, pubParams.EphemeralPublicKey);
-
-			return agreement.X.ToBigInteger();
-		}
-		
-		// The ECMQV Primitive as described in SEC-1, 3.4
-		private static ECPoint calculateMqvAgreement(
-			ECDomainParameters		parameters,
-			ECPrivateKeyParameters	d1U,
-			ECPrivateKeyParameters	d2U,
-			ECPublicKeyParameters	Q2U,
-			ECPublicKeyParameters	Q1V,
-			ECPublicKeyParameters	Q2V)
-		{
-			BigInteger n = parameters.N;
-			int e = (n.BitLength + 1) / 2;
-			BigInteger powE = BigInteger.One.ShiftLeft(e);
-
-			// The Q2U public key is optional
-			ECPoint q;
-			if (Q2U == null)
-			{
-				q = parameters.G.Multiply(d2U.D);
-			}
-			else
-			{
-				q = Q2U.Q;
-			}
-
-			BigInteger x = q.X.ToBigInteger();
-			BigInteger xBar = x.Mod(powE);
-			BigInteger Q2UBar = xBar.SetBit(e);
-			BigInteger s = d1U.D.Multiply(Q2UBar).Mod(n).Add(d2U.D).Mod(n);
-
-			BigInteger xPrime = Q2V.Q.X.ToBigInteger();
-			BigInteger xPrimeBar = xPrime.Mod(powE);
-			BigInteger Q2VBar = xPrimeBar.SetBit(e);
-
-			BigInteger hs = parameters.H.Multiply(s).Mod(n);
-
-			//ECPoint p = Q1V.Q.Multiply(Q2VBar).Add(Q2V.Q).Multiply(hs);
-			ECPoint p = ECAlgorithms.SumOfTwoMultiplies(
-				Q1V.Q, Q2VBar.Multiply(hs).Mod(n), Q2V.Q, hs);
-
-			if (p.IsInfinity)
-				throw new InvalidOperationException("Infinity is not a valid agreement value for MQV");
-
-			return p;
-		}
-	}
+    public class ECMqvBasicAgreement
+        : IBasicAgreement
+    {
+        protected internal MqvPrivateParameters privParams;
+
+        public virtual void Init(
+            ICipherParameters parameters)
+        {
+            if (parameters is ParametersWithRandom)
+            {
+                parameters = ((ParametersWithRandom)parameters).Parameters;
+            }
+
+            this.privParams = (MqvPrivateParameters)parameters;
+        }
+
+        public virtual int GetFieldSize()
+        {
+            return (privParams.StaticPrivateKey.Parameters.Curve.FieldSize + 7) / 8;
+        }
+
+        public virtual BigInteger CalculateAgreement(
+            ICipherParameters pubKey)
+        {
+            MqvPublicParameters pubParams = (MqvPublicParameters)pubKey;
+
+            ECPrivateKeyParameters staticPrivateKey = privParams.StaticPrivateKey;
+
+            ECPoint agreement = CalculateMqvAgreement(staticPrivateKey.Parameters, staticPrivateKey,
+                privParams.EphemeralPrivateKey, privParams.EphemeralPublicKey,
+                pubParams.StaticPublicKey, pubParams.EphemeralPublicKey).Normalize();
+
+            if (agreement.IsInfinity)
+                throw new InvalidOperationException("Infinity is not a valid agreement value for MQV");
+
+            return agreement.AffineXCoord.ToBigInteger();
+        }
+
+        // The ECMQV Primitive as described in SEC-1, 3.4
+        private static ECPoint CalculateMqvAgreement(
+            ECDomainParameters		parameters,
+            ECPrivateKeyParameters	d1U,
+            ECPrivateKeyParameters	d2U,
+            ECPublicKeyParameters	Q2U,
+            ECPublicKeyParameters	Q1V,
+            ECPublicKeyParameters	Q2V)
+        {
+            BigInteger n = parameters.N;
+            int e = (n.BitLength + 1) / 2;
+            BigInteger powE = BigInteger.One.ShiftLeft(e);
+
+            ECCurve curve = parameters.Curve;
+
+            ECPoint[] points = new ECPoint[]{
+                // The Q2U public key is optional
+                ECAlgorithms.ImportPoint(curve, Q2U == null ? parameters.G.Multiply(d2U.D) : Q2U.Q),
+                ECAlgorithms.ImportPoint(curve, Q1V.Q),
+                ECAlgorithms.ImportPoint(curve, Q2V.Q)
+            };
+
+            curve.NormalizeAll(points);
+
+            ECPoint q2u = points[0], q1v = points[1], q2v = points[2];
+
+            BigInteger x = q2u.AffineXCoord.ToBigInteger();
+            BigInteger xBar = x.Mod(powE);
+            BigInteger Q2UBar = xBar.SetBit(e);
+            BigInteger s = d1U.D.Multiply(Q2UBar).Add(d2U.D).Mod(n);
+
+            BigInteger xPrime = q2v.AffineXCoord.ToBigInteger();
+            BigInteger xPrimeBar = xPrime.Mod(powE);
+            BigInteger Q2VBar = xPrimeBar.SetBit(e);
+
+            BigInteger hs = parameters.H.Multiply(s).Mod(n);
+
+            return ECAlgorithms.SumOfTwoMultiplies(
+                q1v, Q2VBar.Multiply(hs).Mod(n), q2v, hs);
+        }
+    }
 }
diff --git a/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
index 093ce4056..7d79fc468 100644
--- a/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Crypto.Agreement
 			DHKdfParameters dhKdfParams = new DHKdfParameters(
 				new DerObjectIdentifier(algorithm),
 				keySize,
-				bigIntToBytes(result));
+				BigIntToBytes(result));
 
 			kdf.Init(dhKdfParams);
 
@@ -54,10 +54,9 @@ namespace Org.BouncyCastle.Crypto.Agreement
 			return new BigInteger(1, keyBytes);
 		}
 
-		private byte[] bigIntToBytes(
-			BigInteger r)
+		private byte[] BigIntToBytes(BigInteger r)
 		{
-			int byteLength = X9IntegerConverter.GetByteLength(privParams.StaticPrivateKey.Parameters.G.X);
+			int byteLength = X9IntegerConverter.GetByteLength(privParams.StaticPrivateKey.Parameters.Curve);
 			return X9IntegerConverter.IntegerToBytes(r, byteLength);
 		}
 	}
diff --git a/crypto/src/crypto/agreement/kdf/DHKdfParameters.cs b/crypto/src/crypto/agreement/kdf/DHKdfParameters.cs
new file mode 100644
index 000000000..f6c9e6079
--- /dev/null
+++ b/crypto/src/crypto/agreement/kdf/DHKdfParameters.cs
@@ -0,0 +1,57 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Kdf
+{
+	public class DHKdfParameters
+		: IDerivationParameters
+	{
+		private readonly DerObjectIdentifier algorithm;
+		private readonly int keySize;
+		private readonly byte[] z;
+		private readonly byte[] extraInfo;
+
+		public DHKdfParameters(
+			DerObjectIdentifier	algorithm,
+			int					keySize,
+			byte[]				z)
+			: this(algorithm, keySize, z, null)
+		{
+		}
+
+		public DHKdfParameters(
+			DerObjectIdentifier algorithm,
+			int keySize,
+			byte[] z,
+			byte[] extraInfo)
+		{
+			this.algorithm = algorithm;
+			this.keySize = keySize;
+			this.z = z; // TODO Clone?
+			this.extraInfo = extraInfo;
+		}
+
+		public DerObjectIdentifier Algorithm
+		{
+			get { return algorithm; }
+		}
+
+		public int KeySize
+		{
+			get { return keySize; }
+		}
+
+		public byte[] GetZ()
+		{
+			// TODO Clone?
+			return z;
+		}
+
+		public byte[] GetExtraInfo()
+		{
+			// TODO Clone?
+			return extraInfo;
+		}
+	}
+}
diff --git a/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs b/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
index fa2921539..259e21e69 100644
--- a/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
+++ b/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
@@ -1,129 +1,112 @@
 using System;
 
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Agreement.Kdf
 {
-	/**
-	* RFC 2631 Diffie-hellman KEK derivation function.
-	*/
-	public class DHKekGenerator
-		: IDerivationFunction
-	{
-		private readonly IDigest digest;
-
-		private DerObjectIdentifier	algorithm;
-		private int					keySize;
-		private byte[]				z;
-		private byte[]				partyAInfo;
-
-		public DHKekGenerator(
-			IDigest digest)
-		{
-			this.digest = digest;
-		}
-
-		public void Init(
-			IDerivationParameters param)
-		{
-			DHKdfParameters parameters = (DHKdfParameters)param;
-
-			this.algorithm = parameters.Algorithm;
-			this.keySize = parameters.KeySize;
-			this.z = parameters.GetZ(); // TODO Clone?
-			this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone?
-		}
-
-		public IDigest Digest
-		{
-			get { return digest; }
-		}
-
-		public int GenerateBytes(
-			byte[]	outBytes,
-			int		outOff,
-			int		len)
-		{
-			if ((outBytes.Length - len) < outOff)
-			{
-				throw new DataLengthException("output buffer too small");
-			}
-
-			long oBytes = len;
-			int outLen = digest.GetDigestSize();
-
-			//
-			// this is at odds with the standard implementation, the
-			// maximum value should be hBits * (2^32 - 1) where hBits
-			// is the digest output size in bits. We can't have an
-			// array with a long index at the moment...
-			//
-			if (oBytes > ((2L << 32) - 1))
-			{
-				throw new ArgumentException("Output length too large");
-			}
-
-			int cThreshold = (int)((oBytes + outLen - 1) / outLen);
-
-			byte[] dig = new byte[digest.GetDigestSize()];
-
-			int counter = 1;
-
-			for (int i = 0; i < cThreshold; i++)
-			{
-				digest.BlockUpdate(z, 0, z.Length);
-
-				// KeySpecificInfo
-				DerSequence keyInfo = new DerSequence(
-					algorithm,
-					new DerOctetString(integerToBytes(counter)));
-
-				// OtherInfo
-				Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
-
-				if (partyAInfo != null)
-				{
-					v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
-				}
-
-				v1.Add(new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize))));
-
-				byte[] other = new DerSequence(v1).GetDerEncoded();
-
-				digest.BlockUpdate(other, 0, other.Length);
-
-				digest.DoFinal(dig, 0);
-
-				if (len > outLen)
-				{
-					Array.Copy(dig, 0, outBytes, outOff, outLen);
-					outOff += outLen;
-					len -= outLen;
-				}
-				else
-				{
-					Array.Copy(dig, 0, outBytes, outOff, len);
-				}
-
-				counter++;
-			}
-
-			digest.Reset();
-
-			return len;
-		}
-
-		private byte[] integerToBytes(
-			int keySize)
-		{
-			byte[] val = new byte[4];
-
-			val[0] = (byte)(keySize >> 24);
-			val[1] = (byte)(keySize >> 16);
-			val[2] = (byte)(keySize >> 8);
-			val[3] = (byte)keySize;
-
-			return val;
-		}
-	}
+    /**
+    * RFC 2631 Diffie-hellman KEK derivation function.
+    */
+    public class DHKekGenerator
+        : IDerivationFunction
+    {
+        private readonly IDigest digest;
+
+        private DerObjectIdentifier	algorithm;
+        private int					keySize;
+        private byte[]				z;
+        private byte[]				partyAInfo;
+
+        public DHKekGenerator(IDigest digest)
+        {
+            this.digest = digest;
+        }
+
+        public virtual void Init(IDerivationParameters param)
+        {
+            DHKdfParameters parameters = (DHKdfParameters)param;
+
+            this.algorithm = parameters.Algorithm;
+            this.keySize = parameters.KeySize;
+            this.z = parameters.GetZ(); // TODO Clone?
+            this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone?
+        }
+
+        public virtual IDigest Digest
+        {
+            get { return digest; }
+        }
+
+        public virtual int GenerateBytes(byte[]	outBytes, int outOff, int len)
+        {
+            if ((outBytes.Length - len) < outOff)
+            {
+                throw new DataLengthException("output buffer too small");
+            }
+
+            long oBytes = len;
+            int outLen = digest.GetDigestSize();
+
+            //
+            // this is at odds with the standard implementation, the
+            // maximum value should be hBits * (2^32 - 1) where hBits
+            // is the digest output size in bits. We can't have an
+            // array with a long index at the moment...
+            //
+            if (oBytes > ((2L << 32) - 1))
+            {
+                throw new ArgumentException("Output length too large");
+            }
+
+            int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+            byte[] dig = new byte[digest.GetDigestSize()];
+
+            uint counter = 1;
+
+            for (int i = 0; i < cThreshold; i++)
+            {
+                digest.BlockUpdate(z, 0, z.Length);
+
+                // KeySpecificInfo
+                DerSequence keyInfo = new DerSequence(
+                    algorithm,
+                    new DerOctetString(Pack.UInt32_To_BE(counter)));
+
+                // OtherInfo
+                Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo);
+
+                if (partyAInfo != null)
+                {
+                    v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo)));
+                }
+
+                v1.Add(new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));
+
+                byte[] other = new DerSequence(v1).GetDerEncoded();
+
+                digest.BlockUpdate(other, 0, other.Length);
+
+                digest.DoFinal(dig, 0);
+
+                if (len > outLen)
+                {
+                    Array.Copy(dig, 0, outBytes, outOff, outLen);
+                    outOff += outLen;
+                    len -= outLen;
+                }
+                else
+                {
+                    Array.Copy(dig, 0, outBytes, outOff, len);
+                }
+
+                counter++;
+            }
+
+            digest.Reset();
+
+            return (int)oBytes;
+        }
+    }
 }
diff --git a/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs b/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs
index 7d55aa485..74464574c 100644
--- a/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs
+++ b/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs
@@ -4,68 +4,52 @@ using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Agreement.Kdf
 {
-	/**
-	* X9.63 based key derivation function for ECDH CMS.
-	*/
-	public class ECDHKekGenerator
-		: IDerivationFunction
-	{
-		private readonly IDerivationFunction kdf;
-
-		private DerObjectIdentifier	algorithm;
-		private int					keySize;
-		private byte[]				z;
-
-		public ECDHKekGenerator(
-			IDigest digest)
-		{
-			this.kdf = new Kdf2BytesGenerator(digest);
-		}
-
-		public void Init(
-			IDerivationParameters param)
-		{
-			DHKdfParameters parameters = (DHKdfParameters)param;
-
-			this.algorithm = parameters.Algorithm;
-			this.keySize = parameters.KeySize;
-			this.z = parameters.GetZ(); // TODO Clone?
-		}
-
-		public IDigest Digest
-		{
-			get { return kdf.Digest; }
-		}
-
-		public int GenerateBytes(
-			byte[]	outBytes,
-			int		outOff,
-			int		len)
-		{
-			// TODO Create an ASN.1 class for this (RFC3278)
-			// ECC-CMS-SharedInfo
-			DerSequence s = new DerSequence(
-				new AlgorithmIdentifier(algorithm, DerNull.Instance),
-				new DerTaggedObject(true, 2, new DerOctetString(integerToBytes(keySize))));
-
-			kdf.Init(new KdfParameters(z, s.GetDerEncoded()));
-
-			return kdf.GenerateBytes(outBytes, outOff, len);
-		}
-
-		private byte[] integerToBytes(int keySize)
-		{
-			byte[] val = new byte[4];
-
-			val[0] = (byte)(keySize >> 24);
-			val[1] = (byte)(keySize >> 16);
-			val[2] = (byte)(keySize >> 8);
-			val[3] = (byte)keySize;
-
-			return val;
-		}
-	}
+    /**
+    * X9.63 based key derivation function for ECDH CMS.
+    */
+    public class ECDHKekGenerator
+        : IDerivationFunction
+    {
+        private readonly IDerivationFunction kdf;
+
+        private DerObjectIdentifier	algorithm;
+        private int					keySize;
+        private byte[]				z;
+
+        public ECDHKekGenerator(IDigest digest)
+        {
+            this.kdf = new Kdf2BytesGenerator(digest);
+        }
+
+        public virtual void Init(IDerivationParameters param)
+        {
+            DHKdfParameters parameters = (DHKdfParameters)param;
+
+            this.algorithm = parameters.Algorithm;
+            this.keySize = parameters.KeySize;
+            this.z = parameters.GetZ(); // TODO Clone?
+        }
+
+        public virtual IDigest Digest
+        {
+            get { return kdf.Digest; }
+        }
+
+        public virtual int GenerateBytes(byte[]	outBytes, int outOff, int len)
+        {
+            // TODO Create an ASN.1 class for this (RFC3278)
+            // ECC-CMS-SharedInfo
+            DerSequence s = new DerSequence(
+                new AlgorithmIdentifier(algorithm, DerNull.Instance),
+                new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize))));
+
+            kdf.Init(new KdfParameters(z, s.GetDerEncoded()));
+
+            return kdf.GenerateBytes(outBytes, outOff, len);
+        }
+    }
 }
diff --git a/crypto/src/crypto/agreement/srp/SRP6Client.cs b/crypto/src/crypto/agreement/srp/SRP6Client.cs
new file mode 100644
index 000000000..309736564
--- /dev/null
+++ b/crypto/src/crypto/agreement/srp/SRP6Client.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+	/**
+	 * Implements the client side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe.
+	 * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper
+	 * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002"
+	 */
+	public class Srp6Client
+	{
+	    protected BigInteger N;
+	    protected BigInteger g;
+
+	    protected BigInteger privA;
+	    protected BigInteger pubA;
+
+	    protected BigInteger B;
+
+	    protected BigInteger x;
+	    protected BigInteger u;
+	    protected BigInteger S;
+
+	    protected IDigest digest;
+	    protected SecureRandom random;
+
+	    public Srp6Client()
+	    {
+	    }
+
+	    /**
+	     * Initialises the client to begin new authentication attempt
+	     * @param N The safe prime associated with the client's verifier
+	     * @param g The group parameter associated with the client's verifier
+	     * @param digest The digest algorithm associated with the client's verifier
+	     * @param random For key generation
+	     */
+	    public virtual void Init(BigInteger N, BigInteger g, IDigest digest, SecureRandom random)
+	    {
+	        this.N = N;
+	        this.g = g;
+	        this.digest = digest;
+	        this.random = random;
+	    }
+
+	    /**
+	     * Generates client's credentials given the client's salt, identity and password
+	     * @param salt The salt used in the client's verifier.
+	     * @param identity The user's identity (eg. username)
+	     * @param password The user's password
+	     * @return Client's public value to send to server
+	     */
+	    public virtual BigInteger GenerateClientCredentials(byte[] salt, byte[] identity, byte[] password)
+	    {
+	        this.x = Srp6Utilities.CalculateX(digest, N, salt, identity, password);
+	        this.privA = SelectPrivateValue();
+	        this.pubA = g.ModPow(privA, N);
+
+	        return pubA;
+	    }
+
+	    /**
+	     * Generates client's verification message given the server's credentials
+	     * @param serverB The server's credentials
+	     * @return Client's verification message for the server
+	     * @throws CryptoException If server's credentials are invalid
+	     */
+	    public virtual BigInteger CalculateSecret(BigInteger serverB)
+	    {
+	        this.B = Srp6Utilities.ValidatePublicValue(N, serverB);
+	        this.u = Srp6Utilities.CalculateU(digest, N, pubA, B);
+	        this.S = CalculateS();
+
+	        return S;
+	    }
+
+	    protected virtual BigInteger SelectPrivateValue()
+	    {
+	    	return Srp6Utilities.GeneratePrivateValue(digest, N, g, random);    	
+	    }
+
+	    private BigInteger CalculateS()
+	    {
+	        BigInteger k = Srp6Utilities.CalculateK(digest, N, g);
+	        BigInteger exp = u.Multiply(x).Add(privA);
+	        BigInteger tmp = g.ModPow(x, N).Multiply(k).Mod(N);
+	        return B.Subtract(tmp).Mod(N).ModPow(exp, N);
+	    }
+	}
+}
diff --git a/crypto/src/crypto/agreement/srp/SRP6Server.cs b/crypto/src/crypto/agreement/srp/SRP6Server.cs
new file mode 100644
index 000000000..35b96d488
--- /dev/null
+++ b/crypto/src/crypto/agreement/srp/SRP6Server.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+	/**
+	 * Implements the server side SRP-6a protocol. Note that this class is stateful, and therefore NOT threadsafe.
+	 * This implementation of SRP is based on the optimized message sequence put forth by Thomas Wu in the paper
+	 * "SRP-6: Improvements and Refinements to the Secure Remote Password Protocol, 2002"
+	 */
+	public class Srp6Server
+	{
+	    protected BigInteger N;
+	    protected BigInteger g;
+	    protected BigInteger v;
+
+	    protected SecureRandom random;
+	    protected IDigest digest;
+
+	    protected BigInteger A;
+
+	    protected BigInteger privB;
+	    protected BigInteger pubB;
+
+	    protected BigInteger u;
+	    protected BigInteger S;
+
+	    public Srp6Server()
+	    {
+	    }
+
+	    /**
+	     * Initialises the server to accept a new client authentication attempt
+	     * @param N The safe prime associated with the client's verifier
+	     * @param g The group parameter associated with the client's verifier
+	     * @param v The client's verifier
+	     * @param digest The digest algorithm associated with the client's verifier
+	     * @param random For key generation
+	     */
+	    public virtual void Init(BigInteger N, BigInteger g, BigInteger v, IDigest digest, SecureRandom random)
+	    {
+	        this.N = N;
+	        this.g = g;
+	        this.v = v;
+
+	        this.random = random;
+	        this.digest = digest;
+	    }
+
+	    /**
+	     * Generates the server's credentials that are to be sent to the client.
+	     * @return The server's public value to the client
+	     */
+	    public virtual BigInteger GenerateServerCredentials()
+	    {
+	        BigInteger k = Srp6Utilities.CalculateK(digest, N, g);
+	        this.privB = SelectPrivateValue();
+	    	this.pubB = k.Multiply(v).Mod(N).Add(g.ModPow(privB, N)).Mod(N);
+
+	        return pubB;
+	    }
+
+	    /**
+	     * Processes the client's credentials. If valid the shared secret is generated and returned.
+	     * @param clientA The client's credentials
+	     * @return A shared secret BigInteger
+	     * @throws CryptoException If client's credentials are invalid
+	     */
+	    public virtual BigInteger CalculateSecret(BigInteger clientA)
+	    {
+	        this.A = Srp6Utilities.ValidatePublicValue(N, clientA);
+	        this.u = Srp6Utilities.CalculateU(digest, N, A, pubB);
+	        this.S = CalculateS();
+
+	        return S;
+	    }
+
+	    protected virtual BigInteger SelectPrivateValue()
+	    {
+	    	return Srp6Utilities.GeneratePrivateValue(digest, N, g, random);    	
+	    }
+
+		private BigInteger CalculateS()
+	    {
+			return v.ModPow(u, N).Multiply(A).Mod(N).ModPow(privB, N);
+	    }
+	}
+}
diff --git a/crypto/src/crypto/agreement/srp/SRP6Utilities.cs b/crypto/src/crypto/agreement/srp/SRP6Utilities.cs
new file mode 100644
index 000000000..4e790f572
--- /dev/null
+++ b/crypto/src/crypto/agreement/srp/SRP6Utilities.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+	public class Srp6Utilities
+	{
+		public static BigInteger CalculateK(IDigest digest, BigInteger N, BigInteger g)
+		{
+			return HashPaddedPair(digest, N, N, g);
+		}
+
+	    public static BigInteger CalculateU(IDigest digest, BigInteger N, BigInteger A, BigInteger B)
+	    {
+	    	return HashPaddedPair(digest, N, A, B);
+	    }
+
+		public static BigInteger CalculateX(IDigest digest, BigInteger N, byte[] salt, byte[] identity, byte[] password)
+	    {
+	        byte[] output = new byte[digest.GetDigestSize()];
+
+	        digest.BlockUpdate(identity, 0, identity.Length);
+	        digest.Update((byte)':');
+	        digest.BlockUpdate(password, 0, password.Length);
+	        digest.DoFinal(output, 0);
+
+	        digest.BlockUpdate(salt, 0, salt.Length);
+	        digest.BlockUpdate(output, 0, output.Length);
+	        digest.DoFinal(output, 0);
+
+	        return new BigInteger(1, output);
+	    }
+
+		public static BigInteger GeneratePrivateValue(IDigest digest, BigInteger N, BigInteger g, SecureRandom random)
+	    {
+			int minBits = System.Math.Min(256, N.BitLength / 2);
+	        BigInteger min = BigInteger.One.ShiftLeft(minBits - 1);
+	        BigInteger max = N.Subtract(BigInteger.One);
+
+	        return BigIntegers.CreateRandomInRange(min, max, random);
+	    }
+
+		public static BigInteger ValidatePublicValue(BigInteger N, BigInteger val)
+		{
+		    val = val.Mod(N);
+
+	        // Check that val % N != 0
+	        if (val.Equals(BigInteger.Zero))
+	            throw new CryptoException("Invalid public value: 0");
+
+		    return val;
+		}
+
+		private static BigInteger HashPaddedPair(IDigest digest, BigInteger N, BigInteger n1, BigInteger n2)
+		{
+	    	int padLength = (N.BitLength + 7) / 8;
+
+	    	byte[] n1_bytes = GetPadded(n1, padLength);
+	    	byte[] n2_bytes = GetPadded(n2, padLength);
+
+	        digest.BlockUpdate(n1_bytes, 0, n1_bytes.Length);
+	        digest.BlockUpdate(n2_bytes, 0, n2_bytes.Length);
+
+	        byte[] output = new byte[digest.GetDigestSize()];
+	        digest.DoFinal(output, 0);
+
+	        return new BigInteger(1, output);
+		}
+
+		private static byte[] GetPadded(BigInteger n, int length)
+		{
+			byte[] bs = BigIntegers.AsUnsignedByteArray(n);
+			if (bs.Length < length)
+			{
+				byte[] tmp = new byte[length];
+				Array.Copy(bs, 0, tmp, length - bs.Length, bs.Length);
+				bs = tmp;
+			}
+			return bs;
+		}
+	}
+}
diff --git a/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs b/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs
new file mode 100644
index 000000000..264833b4d
--- /dev/null
+++ b/crypto/src/crypto/agreement/srp/SRP6VerifierGenerator.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Agreement.Srp
+{
+	/**
+	 * Generates new SRP verifier for user
+	 */
+	public class Srp6VerifierGenerator
+	{
+	    protected BigInteger N;
+	    protected BigInteger g;
+	    protected IDigest digest;
+
+	    public Srp6VerifierGenerator()
+	    {
+	    }
+
+	    /**
+	     * Initialises generator to create new verifiers
+	     * @param N The safe prime to use (see DHParametersGenerator)
+	     * @param g The group parameter to use (see DHParametersGenerator)
+	     * @param digest The digest to use. The same digest type will need to be used later for the actual authentication
+	     * attempt. Also note that the final session key size is dependent on the chosen digest.
+	     */
+	    public virtual void Init(BigInteger N, BigInteger g, IDigest digest)
+	    {
+	        this.N = N;
+	        this.g = g;
+	        this.digest = digest;
+	    }
+
+	    /**
+	     * Creates a new SRP verifier
+	     * @param salt The salt to use, generally should be large and random
+	     * @param identity The user's identifying information (eg. username)
+	     * @param password The user's password
+	     * @return A new verifier for use in future SRP authentication
+	     */
+	    public virtual BigInteger GenerateVerifier(byte[] salt, byte[] identity, byte[] password)
+	    {
+	    	BigInteger x = Srp6Utilities.CalculateX(digest, N, salt, identity, password);
+
+	        return g.ModPow(x, N);
+	    }
+	}
+}
+
diff --git a/crypto/src/crypto/digests/GOST3411Digest.cs b/crypto/src/crypto/digests/GOST3411Digest.cs
index 9f0bec9e6..218adf68c 100644
--- a/crypto/src/crypto/digests/GOST3411Digest.cs
+++ b/crypto/src/crypto/digests/GOST3411Digest.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 	* implementation of GOST R 34.11-94
 	*/
 	public class Gost3411Digest
-		: IDigest
+		: IDigest, IMemoable
 	{
 		private const int DIGEST_LENGTH = 32;
 
@@ -24,7 +24,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 		private ulong	byteCount;
 
 		private readonly IBlockCipher cipher = new Gost28147Engine();
-		private readonly byte[] sBox;
+		private byte[] sBox;
 
 		private static byte[][] MakeC()
 		{
@@ -65,22 +65,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 		 */
 		public Gost3411Digest(Gost3411Digest t)
 		{
-			this.sBox = t.sBox;
-			cipher.Init(true, new ParametersWithSBox(null, sBox));
-
-			Reset();
-
-			Array.Copy(t.H, 0, this.H, 0, t.H.Length);
-			Array.Copy(t.L, 0, this.L, 0, t.L.Length);
-			Array.Copy(t.M, 0, this.M, 0, t.M.Length);
-			Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length);
-			Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length);
-			Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length);
-			Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length);
-			Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length);
-
-			this.xBufOff = t.xBufOff;
-			this.byteCount = t.byteCount;
+			Reset(t);
 		}
 
 		public string AlgorithmName
@@ -339,5 +324,33 @@ namespace Org.BouncyCastle.Crypto.Digests
 		{
 			return 32;
 		}
+
+		public IMemoable Copy()
+		{
+			return new Gost3411Digest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			Gost3411Digest t = (Gost3411Digest)other;
+
+			this.sBox = t.sBox;
+			cipher.Init(true, new ParametersWithSBox(null, sBox));
+
+			Reset();
+
+			Array.Copy(t.H, 0, this.H, 0, t.H.Length);
+			Array.Copy(t.L, 0, this.L, 0, t.L.Length);
+			Array.Copy(t.M, 0, this.M, 0, t.M.Length);
+			Array.Copy(t.Sum, 0, this.Sum, 0, t.Sum.Length);
+			Array.Copy(t.C[1], 0, this.C[1], 0, t.C[1].Length);
+			Array.Copy(t.C[2], 0, this.C[2], 0, t.C[2].Length);
+			Array.Copy(t.C[3], 0, this.C[3], 0, t.C[3].Length);
+			Array.Copy(t.xBuf, 0, this.xBuf, 0, t.xBuf.Length);
+
+			this.xBufOff = t.xBufOff;
+			this.byteCount = t.byteCount;
+		}
 	}
+
 }
diff --git a/crypto/src/crypto/digests/GeneralDigest.cs b/crypto/src/crypto/digests/GeneralDigest.cs
index 77c17ed58..54a09ae05 100644
--- a/crypto/src/crypto/digests/GeneralDigest.cs
+++ b/crypto/src/crypto/digests/GeneralDigest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -7,7 +9,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     * "Handbook of Applied Cryptography", pages 344 - 347.
     */
     public abstract class GeneralDigest
-		: IDigest
+		: IDigest, IMemoable
     {
         private const int BYTE_LENGTH = 64;
 
@@ -22,8 +24,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         }
 
         internal GeneralDigest(GeneralDigest t)
-        {
-            xBuf = new byte[t.xBuf.Length];
+		{
+			xBuf = new byte[t.xBuf.Length];
+			CopyIn(t);
+		}
+
+		protected void CopyIn(GeneralDigest t)
+		{
             Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
 
             xBufOff = t.xBufOff;
@@ -114,5 +121,7 @@ namespace Org.BouncyCastle.Crypto.Digests
         public abstract string AlgorithmName { get; }
 		public abstract int GetDigestSize();
         public abstract int DoFinal(byte[] output, int outOff);
+		public abstract IMemoable Copy();
+		public abstract void Reset(IMemoable t);
     }
 }
diff --git a/crypto/src/crypto/digests/LongDigest.cs b/crypto/src/crypto/digests/LongDigest.cs
index 702753b2b..9ee9bcd57 100644
--- a/crypto/src/crypto/digests/LongDigest.cs
+++ b/crypto/src/crypto/digests/LongDigest.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +10,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     * Base class for SHA-384 and SHA-512.
     */
     public abstract class LongDigest
-		: IDigest
+		: IDigest, IMemoable
     {
         private int     MyByteLength = 128;
 
@@ -41,8 +42,14 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         internal LongDigest(
 			LongDigest t)
-        {
-            xBuf = new byte[t.xBuf.Length];
+		{
+			xBuf = new byte[t.xBuf.Length];
+
+			CopyIn(t);
+		}
+
+		protected void CopyIn(LongDigest t)
+		{
             Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
 
             xBufOff = t.xBufOff;
@@ -342,5 +349,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 		public abstract string AlgorithmName { get; }
 		public abstract int GetDigestSize();
         public abstract int DoFinal(byte[] output, int outOff);
+		public abstract IMemoable Copy();
+		public abstract void Reset(IMemoable t);
     }
 }
diff --git a/crypto/src/crypto/digests/MD2Digest.cs b/crypto/src/crypto/digests/MD2Digest.cs
index 78c696f33..6d90f3f9d 100644
--- a/crypto/src/crypto/digests/MD2Digest.cs
+++ b/crypto/src/crypto/digests/MD2Digest.cs
@@ -1,5 +1,7 @@
 using System;
+
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
     */
     public class MD2Digest
-		: IDigest
+		: IDigest, IMemoable
     {
         private const int DigestLength = 16;
         private const int BYTE_LENGTH = 16;
@@ -32,8 +34,14 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             Reset();
         }
+
         public MD2Digest(MD2Digest t)
-        {
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(MD2Digest t)
+		{
             Array.Copy(t.X, 0, X, 0, t.X.Length);
             xOff = t.xOff;
             Array.Copy(t.M, 0, M, 0, t.M.Length);
@@ -41,6 +49,7 @@ namespace Org.BouncyCastle.Crypto.Digests
             Array.Copy(t.C, 0, C, 0, t.C.Length);
             COff = t.COff;
         }
+
         /**
         * return the algorithm name
         *
@@ -242,6 +251,19 @@ namespace Org.BouncyCastle.Crypto.Digests
         (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51,
         (byte)159,(byte)17,(byte)131,(byte)20
         };
+
+		public IMemoable Copy()
+		{
+			return new MD2Digest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			MD2Digest d = (MD2Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/MD4Digest.cs b/crypto/src/crypto/digests/MD4Digest.cs
index bc4eae0fd..8743f7dad 100644
--- a/crypto/src/crypto/digests/MD4Digest.cs
+++ b/crypto/src/crypto/digests/MD4Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -32,7 +34,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         * message digest.
         */
         public MD4Digest(MD4Digest t) : base(t)
-        {
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(MD4Digest t)
+		{
+			base.CopyIn(t);
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -266,6 +274,19 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+
+		public override IMemoable Copy()
+		{
+			return new MD4Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			MD4Digest d = (MD4Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/MD5Digest.cs b/crypto/src/crypto/digests/MD5Digest.cs
index 50d93e4f8..c60ac92a3 100644
--- a/crypto/src/crypto/digests/MD5Digest.cs
+++ b/crypto/src/crypto/digests/MD5Digest.cs
@@ -1,19 +1,22 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
     * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
     */
     public class MD5Digest
-		: GeneralDigest
+        : GeneralDigest
     {
         private const int DigestLength = 16;
 
-        private int H1, H2, H3, H4;         // IV's
+        private uint H1, H2, H3, H4;         // IV's
 
-        private int[]	X = new int[16];
-        private int		xOff;
+        private uint[] X = new uint[16];
+        private int xOff;
 
         public MD5Digest()
         {
@@ -25,8 +28,14 @@ namespace Org.BouncyCastle.Crypto.Digests
         * message digest.
         */
         public MD5Digest(MD5Digest t)
-			: base(t)
-        {
+            : base(t)
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(MD5Digest t)
+		{
+			base.CopyIn(t);
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -36,62 +45,58 @@ namespace Org.BouncyCastle.Crypto.Digests
             xOff = t.xOff;
         }
 
-		public override string AlgorithmName
-		{
-			get { return "MD5"; }
-		}
+        public override string AlgorithmName
+        {
+            get { return "MD5"; }
+        }
 
-		public override int GetDigestSize()
-		{
-			return DigestLength;
-		}
+        public override int GetDigestSize()
+        {
+            return DigestLength;
+        }
 
-		internal override void ProcessWord(
-            byte[]  input,
-            int     inOff)
+        internal override void ProcessWord(
+            byte[] input,
+            int inOff)
         {
-            X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
-                | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+            X[xOff] = Pack.LE_To_UInt32(input, inOff);
 
-            if (xOff == 16)
+            if (++xOff == 16)
             {
                 ProcessBlock();
             }
         }
 
         internal override void ProcessLength(
-            long    bitLength)
+            long bitLength)
         {
             if (xOff > 14)
             {
+                if (xOff == 15)
+                    X[15] = 0;
+
                 ProcessBlock();
             }
 
-            X[14] = (int)(bitLength & 0xffffffff);
-            X[15] = (int)((ulong) bitLength >> 32);
-        }
+            for (int i = xOff; i < 14; ++i)
+            {
+                X[i] = 0;
+            }
 
-        private void UnpackWord(
-            int     word,
-            byte[]  outBytes,
-            int     outOff)
-        {
-            outBytes[outOff]     = (byte)word;
-            outBytes[outOff + 1] = (byte)((uint) word >> 8);
-            outBytes[outOff + 2] = (byte)((uint) word >> 16);
-            outBytes[outOff + 3] = (byte)((uint) word >> 24);
+            X[14] = (uint)((ulong)bitLength);
+            X[15] = (uint)((ulong)bitLength >> 32);
         }
 
         public override int DoFinal(
-            byte[]  output,
-            int     outOff)
+            byte[] output,
+            int outOff)
         {
             Finish();
 
-            UnpackWord(H1, output, outOff);
-            UnpackWord(H2, output, outOff + 4);
-            UnpackWord(H3, output, outOff + 8);
-            UnpackWord(H4, output, outOff + 12);
+            Pack.UInt32_To_LE(H1, output, outOff);
+            Pack.UInt32_To_LE(H2, output, outOff + 4);
+            Pack.UInt32_To_LE(H3, output, outOff + 8);
+            Pack.UInt32_To_LE(H4, output, outOff + 12);
 
             Reset();
 
@@ -105,10 +110,10 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             base.Reset();
 
-            H1 = unchecked((int) 0x67452301);
-            H2 = unchecked((int) 0xefcdab89);
-            H3 = unchecked((int) 0x98badcfe);
-            H4 = unchecked((int) 0x10325476);
+            H1 = 0x67452301;
+            H2 = 0xefcdab89;
+            H3 = 0x98badcfe;
+            H4 = 0x10325476;
 
             xOff = 0;
 
@@ -153,149 +158,156 @@ namespace Org.BouncyCastle.Crypto.Digests
         /*
         * rotate int x left n bits.
         */
-        private int RotateLeft(
-            int x,
+        private static uint RotateLeft(
+            uint x,
             int n)
         {
-            return (x << n) | (int) ((uint) x >> (32 - 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)
+        private static uint F(
+            uint u,
+            uint v,
+            uint w)
         {
             return (u & v) | (~u & w);
         }
 
-        private int G(
-            int u,
-            int v,
-            int w)
+        private static uint G(
+            uint u,
+            uint v,
+            uint w)
         {
             return (u & w) | (v & ~w);
         }
 
-        private int H(
-            int u,
-            int v,
-            int w)
+        private static uint H(
+            uint u,
+            uint v,
+            uint w)
         {
             return u ^ v ^ w;
         }
 
-        private int K(
-            int u,
-            int v,
-            int w)
+        private static uint K(
+            uint u,
+            uint v,
+            uint w)
         {
             return v ^ (u | ~w);
         }
 
         internal override void ProcessBlock()
         {
-            int a = H1;
-            int b = H2;
-            int c = H3;
-            int d = H4;
+            uint a = H1;
+            uint b = H2;
+            uint c = H3;
+            uint d = H4;
 
             //
             // Round 1 - F cycle, 16 times.
             //
-            a = RotateLeft((a + F(b, c, d) + X[ 0] + unchecked((int) 0xd76aa478)), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[ 1] + unchecked((int) 0xe8c7b756)), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[ 2] + unchecked((int) 0x242070db)), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[ 3] + unchecked((int) 0xc1bdceee)), S14) + c;
-            a = RotateLeft((a + F(b, c, d) + X[ 4] + unchecked((int) 0xf57c0faf)), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[ 5] + unchecked((int) 0x4787c62a)), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[ 6] + unchecked((int) 0xa8304613)), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[ 7] + unchecked((int) 0xfd469501)), S14) + c;
-            a = RotateLeft((a + F(b, c, d) + X[ 8] + unchecked((int) 0x698098d8)), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[ 9] + unchecked((int) 0x8b44f7af)), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[10] + unchecked((int) 0xffff5bb1)), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[11] + unchecked((int) 0x895cd7be)), S14) + c;
-            a = RotateLeft((a + F(b, c, d) + X[12] + unchecked((int) 0x6b901122)), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[13] + unchecked((int) 0xfd987193)), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[14] + unchecked((int) 0xa679438e)), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[15] + unchecked((int) 0x49b40821)), S14) + c;
+            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] + unchecked((int) 0xf61e2562)), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[ 6] + unchecked((int) 0xc040b340)), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[11] + unchecked((int) 0x265e5a51)), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[ 0] + unchecked((int) 0xe9b6c7aa)), S24) + c;
-            a = RotateLeft((a + G(b, c, d) + X[ 5] + unchecked((int) 0xd62f105d)), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[10] + unchecked((int) 0x02441453)), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[15] + unchecked((int) 0xd8a1e681)), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[ 4] + unchecked((int) 0xe7d3fbc8)), S24) + c;
-            a = RotateLeft((a + G(b, c, d) + X[ 9] + unchecked((int) 0x21e1cde6)), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[14] + unchecked((int) 0xc33707d6)), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[ 3] + unchecked((int) 0xf4d50d87)), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[ 8] + unchecked((int) 0x455a14ed)), S24) + c;
-            a = RotateLeft((a + G(b, c, d) + X[13] + unchecked((int) 0xa9e3e905)), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[ 2] + unchecked((int) 0xfcefa3f8)), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[ 7] + unchecked((int) 0x676f02d9)), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[12] + unchecked((int) 0x8d2a4c8a)), S24) + c;
+            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] + unchecked((int) 0xfffa3942)), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[ 8] + unchecked((int) 0x8771f681)), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[11] + unchecked((int) 0x6d9d6122)), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[14] + unchecked((int) 0xfde5380c)), S34) + c;
-            a = RotateLeft((a + H(b, c, d) + X[ 1] + unchecked((int) 0xa4beea44)), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[ 4] + unchecked((int) 0x4bdecfa9)), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[ 7] + unchecked((int) 0xf6bb4b60)), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[10] + unchecked((int) 0xbebfbc70)), S34) + c;
-            a = RotateLeft((a + H(b, c, d) + X[13] + unchecked((int) 0x289b7ec6)), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[ 0] + unchecked((int) 0xeaa127fa)), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[ 3] + unchecked((int) 0xd4ef3085)), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[ 6] + unchecked((int) 0x04881d05)), S34) + c;
-            a = RotateLeft((a + H(b, c, d) + X[ 9] + unchecked((int) 0xd9d4d039)), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[12] + unchecked((int) 0xe6db99e5)), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[15] + unchecked((int) 0x1fa27cf8)), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[ 2] + unchecked((int) 0xc4ac5665)), S34) + c;
+            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] + unchecked((int) 0xf4292244)), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[ 7] + unchecked((int) 0x432aff97)), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[14] + unchecked((int) 0xab9423a7)), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[ 5] + unchecked((int) 0xfc93a039)), S44) + c;
-            a = RotateLeft((a + K(b, c, d) + X[12] + unchecked((int) 0x655b59c3)), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[ 3] + unchecked((int) 0x8f0ccc92)), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[10] + unchecked((int) 0xffeff47d)), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[ 1] + unchecked((int) 0x85845dd1)), S44) + c;
-            a = RotateLeft((a + K(b, c, d) + X[ 8] + unchecked((int) 0x6fa87e4f)), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[15] + unchecked((int) 0xfe2ce6e0)), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[ 6] + unchecked((int) 0xa3014314)), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[13] + unchecked((int) 0x4e0811a1)), S44) + c;
-            a = RotateLeft((a + K(b, c, d) + X[ 4] + unchecked((int) 0xf7537e82)), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[11] + unchecked((int) 0xbd3af235)), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[ 2] + unchecked((int) 0x2ad7d2bb)), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[ 9] + unchecked((int) 0xeb86d391)), S44) + c;
+            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;
-            }
         }
-    }
+
+		public override IMemoable Copy()
+		{
+			return new MD5Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			MD5Digest d = (MD5Digest)other;
+
+			CopyIn(d);
+		}
+
+	}
 
 }
+
diff --git a/crypto/src/crypto/digests/NullDigest.cs b/crypto/src/crypto/digests/NullDigest.cs
new file mode 100644
index 000000000..e598cb145
--- /dev/null
+++ b/crypto/src/crypto/digests/NullDigest.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+	public class NullDigest : IDigest
+	{
+		private readonly MemoryStream bOut = new MemoryStream();
+
+		public string AlgorithmName
+		{
+			get { return "NULL"; }
+		}
+
+		public int GetByteLength()
+		{
+			// TODO Is this okay?
+			return 0;
+		}
+
+		public int GetDigestSize()
+		{
+			return (int) bOut.Length;
+		}
+
+		public void Update(byte b)
+		{
+			bOut.WriteByte(b);
+		}
+
+		public void BlockUpdate(byte[] inBytes, int inOff, int len)
+		{
+			bOut.Write(inBytes, inOff, len);
+		}
+
+		public int DoFinal(byte[] outBytes, int outOff)
+		{
+			byte[] res = bOut.ToArray();
+			res.CopyTo(outBytes, outOff);
+			Reset();
+			return res.Length;
+		}
+
+		public void Reset()
+		{
+			bOut.SetLength(0);
+		}
+	}
+}
diff --git a/crypto/src/crypto/digests/RipeMD128Digest.cs b/crypto/src/crypto/digests/RipeMD128Digest.cs
index 8977583a4..e8a0331ca 100644
--- a/crypto/src/crypto/digests/RipeMD128Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD128Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -28,8 +30,15 @@ namespace Org.BouncyCastle.Crypto.Digests
         * message digest.
         */
         public RipeMD128Digest(RipeMD128Digest t) : base(t)
-        {
-            H0 = t.H0;
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD128Digest t)
+		{
+			base.CopyIn(t);
+
+			H0 = t.H0;
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -457,6 +466,19 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD128Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD128Digest d = (RipeMD128Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/RipeMD160Digest.cs b/crypto/src/crypto/digests/RipeMD160Digest.cs
index 8ce52ae58..af4aa44bb 100644
--- a/crypto/src/crypto/digests/RipeMD160Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD160Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /**
@@ -30,6 +32,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         public RipeMD160Digest(RipeMD160Digest t) : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD160Digest t)
+		{
+			base.CopyIn(t);
+
             H0 = t.H0;
             H1 = t.H1;
             H2 = t.H2;
@@ -418,6 +427,19 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD160Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD160Digest d = (RipeMD160Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 
 }
diff --git a/crypto/src/crypto/digests/RipeMD256Digest.cs b/crypto/src/crypto/digests/RipeMD256Digest.cs
index 950e94f80..306275767 100644
--- a/crypto/src/crypto/digests/RipeMD256Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD256Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
     /// <remarks>
@@ -37,6 +39,12 @@ namespace Org.BouncyCastle.Crypto.Digests
         /// </summary>
         public RipeMD256Digest(RipeMD256Digest t):base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD256Digest t)
+		{
+			base.CopyIn(t);
 
             H0 = t.H0;
             H1 = t.H1;
@@ -405,5 +413,18 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD256Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD256Digest d = (RipeMD256Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/RipeMD320Digest.cs b/crypto/src/crypto/digests/RipeMD320Digest.cs
index 25c74baef..767d74dba 100644
--- a/crypto/src/crypto/digests/RipeMD320Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD320Digest.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Digests
 {
 	/// <remarks>
@@ -38,6 +40,12 @@ namespace Org.BouncyCastle.Crypto.Digests
         public RipeMD320Digest(RipeMD320Digest t)
 			: base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(RipeMD320Digest t)
+		{
+			base.CopyIn(t);
 
             H0 = t.H0;
             H1 = t.H1;
@@ -434,5 +442,18 @@ namespace Org.BouncyCastle.Crypto.Digests
                 X[i] = 0;
             }
         }
+		
+		public override IMemoable Copy()
+		{
+			return new RipeMD320Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			RipeMD320Digest d = (RipeMD320Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs
new file mode 100644
index 000000000..2c6837b3c
--- /dev/null
+++ b/crypto/src/crypto/digests/SHA3Digest.cs
@@ -0,0 +1,560 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /// <summary>
+    /// Implementation of SHA-3 based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+    /// </summary>
+    /// <remarks>
+    /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+    /// </remarks>
+    public class Sha3Digest
+        : IDigest, IMemoable
+    {
+        private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
+
+        private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
+
+        private static ulong[] KeccakInitializeRoundConstants()
+        {
+            ulong[] keccakRoundConstants = new ulong[24];
+            byte LFSRState = 0x01;
+
+            for (int i = 0; i < 24; i++)
+            {
+                keccakRoundConstants[i] = 0;
+                for (int j = 0; j < 7; j++)
+                {
+                    int bitPosition = (1 << j) - 1;
+
+                    // LFSR86540
+
+                    bool loBit = (LFSRState & 0x01) != 0;
+                    if (loBit)
+                    {
+                        keccakRoundConstants[i] ^= 1UL << bitPosition;
+                    }
+
+                    bool hiBit = (LFSRState & 0x80) != 0;
+                    LFSRState <<= 1;
+                    if (hiBit)
+                    {
+                        LFSRState ^= 0x71;
+                    }
+
+                }
+            }
+
+            return keccakRoundConstants;
+        }
+
+        private static int[] KeccakInitializeRhoOffsets()
+        {
+            int[] keccakRhoOffsets = new int[25];
+            int x, y, t, newX, newY;
+
+            int rhoOffset = 0;
+            keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
+            x = 1;
+            y = 0;
+            for (t = 1; t < 25; t++)
+            {
+                //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
+                rhoOffset = (rhoOffset + t) & 63;
+                keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
+                newX = (0 * x + 1 * y) % 5;
+                newY = (2 * x + 3 * y) % 5;
+                x = newX;
+                y = newY;
+            }
+
+            return keccakRhoOffsets;
+        }
+
+        private byte[] state = new byte[(1600 / 8)];
+        private byte[] dataQueue = new byte[(1536 / 8)];
+        private int rate;
+        private int bitsInQueue;
+        private int fixedOutputLength;
+        private bool squeezing;
+        private int bitsAvailableForSqueezing;
+        private byte[] chunk;
+        private byte[] oneByte;
+
+        private void ClearDataQueueSection(int off, int len)
+        {
+            for (int i = off; i != off + len; i++)
+            {
+                dataQueue[i] = 0;
+            }
+        }
+
+        public Sha3Digest()
+        {
+            Init(0);
+        }
+
+        public Sha3Digest(int bitLength)
+        {
+            Init(bitLength);
+        }
+
+        public Sha3Digest(Sha3Digest source)
+        {
+			CopyIn(source);
+		}
+
+		private void CopyIn(Sha3Digest source)
+		{
+            Array.Copy(source.state, 0, this.state, 0, source.state.Length);
+            Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
+            this.rate = source.rate;
+            this.bitsInQueue = source.bitsInQueue;
+            this.fixedOutputLength = source.fixedOutputLength;
+            this.squeezing = source.squeezing;
+            this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
+            this.chunk = Arrays.Clone(source.chunk);
+            this.oneByte = Arrays.Clone(source.oneByte);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "SHA3-" + fixedOutputLength; }
+        }
+
+        public virtual int GetDigestSize()
+        {
+            return fixedOutputLength / 8;
+        }
+
+        public virtual void Update(byte input)
+        {
+            oneByte[0] = input;
+
+            DoUpdate(oneByte, 0, 8L);
+        }
+
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            DoUpdate(input, inOff, len * 8L);
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            Squeeze(output, outOff, fixedOutputLength);
+
+            Reset();
+
+            return GetDigestSize();
+        }
+
+        public virtual void Reset()
+        {
+            Init(fixedOutputLength);
+        }
+
+        /**
+         * Return the size of block that the compression function is applied to in bytes.
+         *
+         * @return internal byte length of a block.
+         */
+        public virtual int GetByteLength()
+        {
+            return rate / 8;
+        }
+
+        private void Init(int bitLength)
+        {
+            switch (bitLength)
+            {
+            case 0:
+            case 288:
+                InitSponge(1024, 576);
+                break;
+            case 224:
+                InitSponge(1152, 448);
+                break;
+            case 256:
+                InitSponge(1088, 512);
+                break;
+            case 384:
+                InitSponge(832, 768);
+                break;
+            case 512:
+                InitSponge(576, 1024);
+                break;
+            default:
+                throw new ArgumentException("must be one of 224, 256, 384, or 512.", "bitLength");
+            }
+        }
+
+        private void DoUpdate(byte[] data, int off, long databitlen)
+        {
+            if ((databitlen % 8) == 0)
+            {
+                Absorb(data, off, databitlen);
+            }
+            else
+            {
+                Absorb(data, off, databitlen - (databitlen % 8));
+
+                byte[] lastByte = new byte[1];
+
+                lastByte[0] = (byte)(data[off + (int)(databitlen / 8)] >> (int)(8 - (databitlen % 8)));
+                Absorb(lastByte, off, databitlen % 8);
+            }
+        }
+
+        private void InitSponge(int rate, int capacity)
+        {
+            if (rate + capacity != 1600)
+            {
+                throw new InvalidOperationException("rate + capacity != 1600");
+            }
+            if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
+            {
+                throw new InvalidOperationException("invalid rate value");
+            }
+
+            this.rate = rate;
+            // this is never read, need to check to see why we want to save it
+            //  this.capacity = capacity;
+            this.fixedOutputLength = 0;
+            Arrays.Fill(this.state, (byte)0);
+            Arrays.Fill(this.dataQueue, (byte)0);
+            this.bitsInQueue = 0;
+            this.squeezing = false;
+            this.bitsAvailableForSqueezing = 0;
+            this.fixedOutputLength = capacity / 2;
+            this.chunk = new byte[rate / 8];
+            this.oneByte = new byte[1];
+        }
+
+        private void AbsorbQueue()
+        {
+            KeccakAbsorb(state, dataQueue, rate / 8);
+
+            bitsInQueue = 0;
+        }
+
+        private void Absorb(byte[] data, int off, long databitlen)
+        {
+            long i, j, wholeBlocks;
+
+            if ((bitsInQueue % 8) != 0)
+            {
+                throw new InvalidOperationException("attempt to absorb with odd length queue.");
+            }
+            if (squeezing)
+            {
+                throw new InvalidOperationException("attempt to absorb while squeezing.");
+            }
+
+            i = 0;
+            while (i < databitlen)
+            {
+                if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
+                {
+                    wholeBlocks = (databitlen - i) / rate;
+
+                    for (j = 0; j < wholeBlocks; j++)
+                    {
+                        Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
+
+                        //displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8);
+
+                        KeccakAbsorb(state, chunk, chunk.Length);
+                    }
+
+                    i += wholeBlocks * rate;
+                }
+                else
+                {
+                    int partialBlock = (int)(databitlen - i);
+                    if (partialBlock + bitsInQueue > rate)
+                    {
+                        partialBlock = rate - bitsInQueue;
+                    }
+                    int partialByte = partialBlock % 8;
+                    partialBlock -= partialByte;
+                    Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
+
+                    bitsInQueue += partialBlock;
+                    i += partialBlock;
+                    if (bitsInQueue == rate)
+                    {
+                        AbsorbQueue();
+                    }
+                    if (partialByte > 0)
+                    {
+                        int mask = (1 << partialByte) - 1;
+                        dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
+                        bitsInQueue += partialByte;
+                        i += partialByte;
+                    }
+                }
+            }
+        }
+
+        private void PadAndSwitchToSqueezingPhase()
+        {
+            if (bitsInQueue + 1 == rate)
+            {
+                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+                AbsorbQueue();
+                ClearDataQueueSection(0, rate / 8);
+            }
+            else
+            {
+                ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
+                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+            }
+            dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
+            AbsorbQueue();
+
+            //displayIntermediateValues.displayText(1, "--- Switching to squeezing phase ---");
+
+            if (rate == 1024)
+            {
+                KeccakExtract1024bits(state, dataQueue);
+                bitsAvailableForSqueezing = 1024;
+            }
+            else
+            {
+                KeccakExtract(state, dataQueue, rate / 64);
+                bitsAvailableForSqueezing = rate;
+            }
+
+            //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
+
+            squeezing = true;
+        }
+
+        private void Squeeze(byte[] output, int offset, long outputLength)
+        {
+            long i;
+            int partialBlock;
+
+            if (!squeezing)
+            {
+                PadAndSwitchToSqueezingPhase();
+            }
+            if ((outputLength % 8) != 0)
+            {
+                throw new InvalidOperationException("outputLength not a multiple of 8");
+            }
+
+            i = 0;
+            while (i < outputLength)
+            {
+                if (bitsAvailableForSqueezing == 0)
+                {
+                    KeccakPermutation(state);
+
+                    if (rate == 1024)
+                    {
+                        KeccakExtract1024bits(state, dataQueue);
+                        bitsAvailableForSqueezing = 1024;
+                    }
+                    else
+
+                    {
+                        KeccakExtract(state, dataQueue, rate / 64);
+                        bitsAvailableForSqueezing = rate;
+                    }
+
+                    //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
+
+                }
+                partialBlock = bitsAvailableForSqueezing;
+                if ((long)partialBlock > outputLength - i)
+                {
+                    partialBlock = (int)(outputLength - i);
+                }
+
+                Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
+                bitsAvailableForSqueezing -= partialBlock;
+                i += partialBlock;
+            }
+        }
+
+        private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
+        {
+            for (int i = 0; i < (1600 / 64); i++)
+            {
+                stateAsWords[i] = 0;
+                int index = i * (64 / 8);
+                for (int j = 0; j < (64 / 8); j++)
+                {
+                    stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
+                }
+            }
+        }
+
+        private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+        {
+            for (int i = 0; i < (1600 / 64); i++)
+            {
+                int index = i * (64 / 8);
+                for (int j = 0; j < (64 / 8); j++)
+                {
+                    state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
+                }
+            }
+        }
+
+        private void KeccakPermutation(byte[] state)
+        {
+            ulong[] longState = new ulong[state.Length / 8];
+
+            FromBytesToWords(longState, state);
+
+            //displayIntermediateValues.displayStateAsBytes(1, "Input of permutation", longState);
+
+            KeccakPermutationOnWords(longState);
+
+            //displayIntermediateValues.displayStateAsBytes(1, "State after permutation", longState);
+
+            FromWordsToBytes(state, longState);
+        }
+
+        private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+        {
+            for (int i = 0; i < dataLengthInBytes; i++)
+            {
+                state[i] ^= data[i];
+            }
+
+            KeccakPermutation(state);
+        }
+
+        private void KeccakPermutationOnWords(ulong[] state)
+        {
+            int i;
+
+            //displayIntermediateValues.displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state);
+
+            for (i = 0; i < 24; i++)
+            {
+                //displayIntermediateValues.displayRoundNumber(3, i);
+
+                Theta(state);
+                //displayIntermediateValues.displayStateAs64bitWords(3, "After theta", state);
+
+                Rho(state);
+                //displayIntermediateValues.displayStateAs64bitWords(3, "After rho", state);
+
+                Pi(state);
+                //displayIntermediateValues.displayStateAs64bitWords(3, "After pi", state);
+
+                Chi(state);
+                //displayIntermediateValues.displayStateAs64bitWords(3, "After chi", state);
+
+                Iota(state, i);
+                //displayIntermediateValues.displayStateAs64bitWords(3, "After iota", state);
+            }
+        }
+
+        ulong[] C = new ulong[5];
+
+        private void Theta(ulong[] A)
+        {
+            for (int x = 0; x < 5; x++)
+            {
+                C[x] = 0;
+                for (int y = 0; y < 5; y++)
+                {
+                    C[x] ^= A[x + 5 * y];
+                }
+            }
+            for (int x = 0; x < 5; x++)
+            {
+                ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
+                for (int y = 0; y < 5; y++)
+                {
+                    A[x + 5 * y] ^= dX;
+                }
+            }
+        }
+
+        private void Rho(ulong[] A)
+        {
+            for (int x = 0; x < 5; x++)
+            {
+                for (int y = 0; y < 5; y++)
+                {
+                    int index = x + 5 * y;
+                    A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
+                }
+            }
+        }
+
+        ulong[] tempA = new ulong[25];
+
+        private void Pi(ulong[] A)
+        {
+            Array.Copy(A, 0, tempA, 0, tempA.Length);
+
+            for (int x = 0; x < 5; x++)
+            {
+                for (int y = 0; y < 5; y++)
+                {
+                    A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
+                }
+            }
+        }
+
+        ulong[] chiC = new ulong[5];
+
+        private void Chi(ulong[] A)
+        {
+            for (int y = 0; y < 5; y++)
+            {
+                for (int x = 0; x < 5; x++)
+                {
+                    chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
+                }
+                for (int x = 0; x < 5; x++)
+                {
+                    A[x + 5 * y] = chiC[x];
+                }
+            }
+        }
+
+        private static void Iota(ulong[] A, int indexRound)
+        {
+            A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
+        }
+
+        private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
+        {
+            KeccakPermutationAfterXor(byteState, data, dataInBytes);
+        }
+
+        private void KeccakExtract1024bits(byte[] byteState, byte[] data)
+        {
+            Array.Copy(byteState, 0, data, 0, 128);
+        }
+
+        private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
+        {
+            Array.Copy(byteState, 0, data, 0, laneCount * 8);
+        }
+
+		public IMemoable Copy()
+		{
+			return new Sha3Digest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			Sha3Digest d = (Sha3Digest)other;
+
+			CopyIn(d);
+		}
+
+
+    }
+}
diff --git a/crypto/src/crypto/digests/SM3Digest.cs b/crypto/src/crypto/digests/SM3Digest.cs
new file mode 100644
index 000000000..d81b2ddbf
--- /dev/null
+++ b/crypto/src/crypto/digests/SM3Digest.cs
@@ -0,0 +1,328 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+	/// <summary>
+	/// Implementation of Chinese SM3 digest as described at
+	/// http://tools.ietf.org/html/draft-shen-sm3-hash-00
+	/// and at .... ( Chinese PDF )
+	/// </summary>
+	/// <remarks>
+	/// The specification says "process a bit stream",
+	/// but this is written to process bytes in blocks of 4,
+	/// meaning this will process 32-bit word groups.
+	/// But so do also most other digest specifications,
+	/// including the SHA-256 which was a origin for
+	/// this specification.
+	/// </remarks>
+	public class SM3Digest
+		: GeneralDigest
+	{
+		private const int DIGEST_LENGTH = 32;   // bytes
+		private const int BLOCK_SIZE = 64 / 4; // of 32 bit ints (16 ints)
+
+		private uint[] V = new uint[DIGEST_LENGTH / 4]; // in 32 bit ints (8 ints)
+		private uint[] inwords = new uint[BLOCK_SIZE];
+		private int xOff;
+
+		// Work-bufs used within processBlock()
+		private uint[] W = new uint[68];
+		private uint[] W1 = new uint[64];
+
+		// Round constant T for processBlock() which is 32 bit integer rolled left up to (63 MOD 32) bit positions.
+		private static readonly uint[] T = new uint[64];
+
+		static SM3Digest()
+		{
+			for (int i = 0; i < 16; ++i)
+			{
+				uint t = 0x79CC4519;
+				T[i] = (t << i) | (t >> (32 - i));
+			}
+			for (int i = 16; i < 64; ++i)
+			{
+				int n = i % 32;
+				uint t = 0x7A879D8A;
+				T[i] = (t << n) | (t >> (32 - n));
+			}
+		}
+
+
+		/// <summary>
+		/// Standard constructor
+		/// </summary>
+		public SM3Digest()
+		{
+			Reset();
+		}
+
+		/// <summary>
+		/// Copy constructor.  This will copy the state of the provided
+		/// message digest.
+		/// </summary>
+		public SM3Digest(SM3Digest t)
+			: base(t)
+		{
+			CopyIn(t);
+		}
+
+		private void CopyIn(SM3Digest t)
+		{
+			Array.Copy(t.V, 0, this.V, 0, this.V.Length);
+			Array.Copy(t.inwords, 0, this.inwords, 0, this.inwords.Length);
+			xOff = t.xOff;
+		}
+
+		public override string AlgorithmName
+		{
+			get { return "SM3"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DIGEST_LENGTH;
+		}
+
+		public override IMemoable Copy()
+		{
+			return new SM3Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			SM3Digest d = (SM3Digest)other;
+
+			base.CopyIn(d);
+			CopyIn(d);
+		}
+
+		/// <summary>
+		/// reset the chaining variables
+		/// </summary>
+		public override void Reset()
+		{
+			base.Reset();
+
+			this.V[0] = 0x7380166F;
+			this.V[1] = 0x4914B2B9;
+			this.V[2] = 0x172442D7;
+			this.V[3] = 0xDA8A0600;
+			this.V[4] = 0xA96F30BC;
+			this.V[5] = 0x163138AA;
+			this.V[6] = 0xE38DEE4D;
+			this.V[7] = 0xB0FB0E4E;
+
+			this.xOff = 0;
+		}
+
+
+		public override int DoFinal(byte[] output, int outOff)
+		{
+			Finish();
+
+			Pack.UInt32_To_BE(this.V[0], output, outOff + 0);
+			Pack.UInt32_To_BE(this.V[1], output, outOff + 4);
+			Pack.UInt32_To_BE(this.V[2], output, outOff + 8);
+			Pack.UInt32_To_BE(this.V[3], output, outOff + 12);
+			Pack.UInt32_To_BE(this.V[4], output, outOff + 16);
+			Pack.UInt32_To_BE(this.V[5], output, outOff + 20);
+			Pack.UInt32_To_BE(this.V[6], output, outOff + 24);
+			Pack.UInt32_To_BE(this.V[7], output, outOff + 28);
+
+			Reset();
+
+			return DIGEST_LENGTH;
+		}
+
+
+		internal override void ProcessWord(byte[] input,
+		                                   int inOff)
+		{
+			uint n = Pack.BE_To_UInt32(input, inOff);
+			this.inwords[this.xOff] = n;
+			++this.xOff;
+
+			if (this.xOff >= 16)
+			{
+				ProcessBlock();
+			}
+		}
+
+		internal override void ProcessLength(long bitLength)
+		{
+			if (this.xOff > (BLOCK_SIZE - 2))
+			{
+				// xOff == 15  --> can't fit the 64 bit length field at tail..
+				this.inwords[this.xOff] = 0; // fill with zero
+				++this.xOff;
+
+				ProcessBlock();
+			}
+			// Fill with zero words, until reach 2nd to last slot
+			while (this.xOff < (BLOCK_SIZE - 2))
+			{
+				this.inwords[this.xOff] = 0;
+				++this.xOff;
+			}
+
+			// Store input data length in BITS
+			this.inwords[this.xOff++] = (uint)(bitLength >> 32);
+			this.inwords[this.xOff++] = (uint)(bitLength);
+		}
+
+		/*
+
+	3.4.2.  Constants
+
+
+	   Tj = 79cc4519        when 0  < = j < = 15
+	   Tj = 7a879d8a        when 16 < = j < = 63
+
+	3.4.3.  Boolean function
+
+
+	   FFj(X;Y;Z) = X XOR Y XOR Z                       when 0  < = j < = 15
+	              = (X AND Y) OR (X AND Z) OR (Y AND Z) when 16 < = j < = 63
+
+	   GGj(X;Y;Z) = X XOR Y XOR Z                       when 0  < = j < = 15
+	              = (X AND Y) OR (NOT X AND Z)          when 16 < = j < = 63
+
+	   The X, Y, Z in the fomular are words!GBP
+
+	3.4.4.  Permutation function
+
+
+	   P0(X) = X XOR (X <<<  9) XOR (X <<< 17)   ## ROLL, not SHIFT
+	   P1(X) = X XOR (X <<< 15) XOR (X <<< 23)   ## ROLL, not SHIFT
+
+	   The X in the fomular are a word.
+
+	----------
+
+	Each ROLL converted to Java expression:
+
+	ROLL 9  :  ((x <<  9) | (x >> (32-9))))
+	ROLL 17 :  ((x << 17) | (x >> (32-17)))
+	ROLL 15 :  ((x << 15) | (x >> (32-15)))
+	ROLL 23 :  ((x << 23) | (x >> (32-23)))
+
+	 */
+
+		private uint P0(uint x)
+		{
+			uint r9 = ((x << 9) | (x >> (32 - 9)));
+			uint r17 = ((x << 17) | (x >> (32 - 17)));
+			return (x ^ r9 ^ r17);
+		}
+
+		private uint P1(uint x)
+		{
+			uint r15 = ((x << 15) | (x >> (32 - 15)));
+			uint r23 = ((x << 23) | (x >> (32 - 23)));
+			return (x ^ r15 ^ r23);
+		}
+
+		private uint FF0(uint x, uint y, uint z)
+		{
+			return (x ^ y ^ z);
+		}
+
+		private uint FF1(uint x, uint y, uint z)
+		{
+			return ((x & y) | (x & z) | (y & z));
+		}
+
+		private uint GG0(uint x, uint y, uint z)
+		{
+			return (x ^ y ^ z);
+		}
+
+		private uint GG1(uint x, uint y, uint z)
+		{
+			return ((x & y) | ((~x) & z));
+		}
+
+
+		internal override void ProcessBlock()
+		{
+			for (int j = 0; j < 16; ++j)
+			{
+				this.W[j] = this.inwords[j];
+			}
+			for (int j = 16; j < 68; ++j)
+			{
+				uint wj3 = this.W[j - 3];
+				uint r15 = ((wj3 << 15) | (wj3 >> (32 - 15)));
+				uint wj13 = this.W[j - 13];
+				uint r7 = ((wj13 << 7) | (wj13 >> (32 - 7)));
+				this.W[j] = P1(this.W[j - 16] ^ this.W[j - 9] ^ r15) ^ r7 ^ this.W[j - 6];
+			}
+			for (int j = 0; j < 64; ++j)
+			{
+				this.W1[j] = this.W[j] ^ this.W[j + 4];
+			}
+
+			uint A = this.V[0];
+			uint B = this.V[1];
+			uint C = this.V[2];
+			uint D = this.V[3];
+			uint E = this.V[4];
+			uint F = this.V[5];
+			uint G = this.V[6];
+			uint H = this.V[7];
+
+
+			for (int j = 0; j < 16; ++j)
+			{
+				uint a12 = ((A << 12) | (A >> (32 - 12)));
+				uint s1_ = a12 + E + T[j];
+				uint SS1 = ((s1_ << 7) | (s1_ >> (32 - 7)));
+				uint SS2 = SS1 ^ a12;
+				uint TT1 = FF0(A, B, C) + D + SS2 + this.W1[j];
+				uint TT2 = GG0(E, F, G) + H + SS1 + this.W[j];
+				D = C;
+				C = ((B << 9) | (B >> (32 - 9)));
+				B = A;
+				A = TT1;
+				H = G;
+				G = ((F << 19) | (F >> (32 - 19)));
+				F = E;
+				E = P0(TT2);
+			}
+
+			// Different FF,GG functions on rounds 16..63
+			for (int j = 16; j < 64; ++j)
+			{
+				uint a12 = ((A << 12) | (A >> (32 - 12)));
+				uint s1_ = a12 + E + T[j];
+				uint SS1 = ((s1_ << 7) | (s1_ >> (32 - 7)));
+				uint SS2 = SS1 ^ a12;
+				uint TT1 = FF1(A, B, C) + D + SS2 + this.W1[j];
+				uint TT2 = GG1(E, F, G) + H + SS1 + this.W[j];
+				D = C;
+				C = ((B << 9) | (B >> (32 - 9)));
+				B = A;
+				A = TT1;
+				H = G;
+				G = ((F << 19) | (F >> (32 - 19)));
+				F = E;
+				E = P0(TT2);
+			}
+
+			this.V[0] ^= A;
+			this.V[1] ^= B;
+			this.V[2] ^= C;
+			this.V[3] ^= D;
+			this.V[4] ^= E;
+			this.V[5] ^= F;
+			this.V[6] ^= G;
+			this.V[7] ^= H;
+
+			this.xOff = 0;
+		}
+	}
+}
diff --git a/crypto/src/crypto/digests/Sha1Digest.cs b/crypto/src/crypto/digests/Sha1Digest.cs
index 9d8c1a4cf..60ec651d5 100644
--- a/crypto/src/crypto/digests/Sha1Digest.cs
+++ b/crypto/src/crypto/digests/Sha1Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,10 +10,10 @@ namespace Org.BouncyCastle.Crypto.Digests
      * 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!
+     * is the "endianness" of the word processing!
      */
     public class Sha1Digest
-		: GeneralDigest
+        : GeneralDigest
     {
         private const int DigestLength = 20;
 
@@ -21,7 +22,7 @@ namespace Org.BouncyCastle.Crypto.Digests
         private uint[] X = new uint[80];
         private int xOff;
 
-		public Sha1Digest()
+        public Sha1Digest()
         {
             Reset();
         }
@@ -31,8 +32,15 @@ namespace Org.BouncyCastle.Crypto.Digests
          * message digest.
          */
         public Sha1Digest(Sha1Digest t)
-			: base(t)
+            : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(Sha1Digest t)
+		{
+			base.CopyIn(t);
+
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -43,34 +51,34 @@ namespace Org.BouncyCastle.Crypto.Digests
             xOff = t.xOff;
         }
 
-		public override string AlgorithmName
-		{
-			get { return "SHA-1"; }
-		}
+        public override string AlgorithmName
+        {
+            get { return "SHA-1"; }
+        }
 
-		public override int GetDigestSize()
-		{
-			return DigestLength;
-		}
+        public override int GetDigestSize()
+        {
+            return DigestLength;
+        }
 
-		internal override void ProcessWord(
+        internal override void ProcessWord(
             byte[]  input,
             int     inOff)
         {
-			X[xOff] = Pack.BE_To_UInt32(input, inOff);
+            X[xOff] = Pack.BE_To_UInt32(input, inOff);
 
-			if (++xOff == 16)
-			{
-				ProcessBlock();
-			}
+            if (++xOff == 16)
+            {
+                ProcessBlock();
+            }
         }
 
-		internal override void ProcessLength(long    bitLength)
+        internal override void ProcessLength(long    bitLength)
         {
-			if (xOff > 14)
-			{
-				ProcessBlock();
-			}
+            if (xOff > 14)
+            {
+                ProcessBlock();
+            }
 
             X[14] = (uint)((ulong)bitLength >> 32);
             X[15] = (uint)((ulong)bitLength);
@@ -107,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.Digests
             H5 = 0xc3d2e1f0;
 
             xOff = 0;
-			Array.Clear(X, 0, X.Length);
+            Array.Clear(X, 0, X.Length);
         }
 
         //
@@ -118,31 +126,31 @@ namespace Org.BouncyCastle.Crypto.Digests
         private const uint Y3 = 0x8f1bbcdc;
         private const uint Y4 = 0xca62c1d6;
 
-		private static uint F(uint u, uint v, uint w)
-		{
-			return (u & v) | (~u & w);
-		}
+        private static uint F(uint u, uint v, uint w)
+        {
+            return (u & v) | (~u & w);
+        }
 
-		private static uint H(uint u, uint v, uint w)
-		{
-			return u ^ v ^ w;
-		}
+        private static uint H(uint u, uint v, uint w)
+        {
+            return u ^ v ^ w;
+        }
 
-		private static uint G(uint u, uint v, uint w)
-		{
-			return (u & v) | (u & w) | (v & w);
-		}
+        private static uint G(uint u, uint v, uint w)
+        {
+            return (u & v) | (u & w) | (v & w);
+        }
 
-		internal override void ProcessBlock()
+        internal override void ProcessBlock()
         {
             //
             // expand 16 word block into 80 word block.
             //
-			for (int i = 16; i < 80; i++)
-			{
-				uint t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
-				X[i] = t << 1 | t >> 31;
-			}
+            for (int i = 16; i < 80; i++)
+            {
+                uint t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
+                X[i] = t << 1 | t >> 31;
+            }
 
             //
             // set up working variables.
@@ -156,108 +164,121 @@ namespace Org.BouncyCastle.Crypto.Digests
             //
             // round 1
             //
-			int idx = 0;
+            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);
+            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);
+                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);
+                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);
+                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);
-			}
+                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);
+            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);
+                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);
+                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);
+                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);
-			}
+                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);
+            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);
+                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);
+                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);
+                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);
-			}
+                A += (B << 5 | (B >> 27)) + G(C, D, E) + X[idx++] + Y3;
+                C = C << 30 | (C >> 2);
+            }
 
-			//
+            //
             // round 4
             //
-			for (int j = 0; j < 4; 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;
-			Array.Clear(X, 0, 16);
+            for (int j = 0; j < 4; 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;
+            Array.Clear(X, 0, 16);
+        }
+		
+		public override IMemoable Copy()
+		{
+			return new Sha1Digest(this);
 		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha1Digest d = (Sha1Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha224Digest.cs b/crypto/src/crypto/digests/Sha224Digest.cs
index 66ecd4ecd..b4e853745 100644
--- a/crypto/src/crypto/digests/Sha224Digest.cs
+++ b/crypto/src/crypto/digests/Sha224Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -41,6 +42,13 @@ namespace Org.BouncyCastle.Crypto.Digests
 			 Sha224Digest t)
 			 : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(Sha224Digest t)
+		{
+			base.CopyIn(t);
+
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -264,5 +272,18 @@ namespace Org.BouncyCastle.Crypto.Digests
 			0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
             0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
         };
+		
+		public override IMemoable Copy()
+		{
+			return new Sha224Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha224Digest d = (Sha224Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha256Digest.cs b/crypto/src/crypto/digests/Sha256Digest.cs
index 1c00ab71f..98e10a34d 100644
--- a/crypto/src/crypto/digests/Sha256Digest.cs
+++ b/crypto/src/crypto/digests/Sha256Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -36,6 +37,13 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         public Sha256Digest(Sha256Digest t) : base(t)
         {
+			CopyIn(t);
+		}
+
+		private void CopyIn(Sha256Digest t)
+		{
+			base.CopyIn(t);
+
             H1 = t.H1;
             H2 = t.H2;
             H3 = t.H3;
@@ -305,5 +313,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
             0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
         };
+		
+		public override IMemoable Copy()
+		{
+			return new Sha256Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha256Digest d = (Sha256Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha384Digest.cs b/crypto/src/crypto/digests/Sha384Digest.cs
index f1372d0a9..e6c9a9aa9 100644
--- a/crypto/src/crypto/digests/Sha384Digest.cs
+++ b/crypto/src/crypto/digests/Sha384Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -83,5 +84,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             H7 = 0xdb0c2e0d64f98fa7;
             H8 = 0x47b5481dbefa4fa4;
         }
+		
+		public override IMemoable Copy()
+		{
+			return new Sha384Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha384Digest d = (Sha384Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha512Digest.cs b/crypto/src/crypto/digests/Sha512Digest.cs
index ed1a50819..2a0964fd3 100644
--- a/crypto/src/crypto/digests/Sha512Digest.cs
+++ b/crypto/src/crypto/digests/Sha512Digest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -17,35 +18,35 @@ namespace Org.BouncyCastle.Crypto.Digests
      * </pre>
      */
     public class Sha512Digest
-		: LongDigest
+        : LongDigest
     {
         private const int DigestLength = 64;
 
-		public Sha512Digest()
+        public Sha512Digest()
         {
         }
 
-		/**
+        /**
          * Copy constructor.  This will copy the state of the provided
          * message digest.
          */
         public Sha512Digest(
-			Sha512Digest t)
-			: base(t)
-		{
-		}
+            Sha512Digest t)
+            : base(t)
+        {
+        }
 
-		public override string AlgorithmName
-		{
-			get { return "SHA-512"; }
-		}
+        public override string AlgorithmName
+        {
+            get { return "SHA-512"; }
+        }
 
-		public override int GetDigestSize()
-		{
-			return DigestLength;
-		}
+        public override int GetDigestSize()
+        {
+            return DigestLength;
+        }
 
-		public override int DoFinal(
+        public override int DoFinal(
             byte[]  output,
             int     outOff)
         {
@@ -86,5 +87,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             H7 = 0x1f83d9abfb41bd6b;
             H8 = 0x5be0cd19137e2179;
         }
+		
+		public override IMemoable Copy()
+		{
+			return new Sha512Digest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha512Digest d = (Sha512Digest)other;
+
+			CopyIn(d);
+		}
+
     }
 }
diff --git a/crypto/src/crypto/digests/Sha512tDigest.cs b/crypto/src/crypto/digests/Sha512tDigest.cs
new file mode 100644
index 000000000..2caefa763
--- /dev/null
+++ b/crypto/src/crypto/digests/Sha512tDigest.cs
@@ -0,0 +1,200 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+     * FIPS 180-4 implementation of SHA-512/t
+     */
+    public class Sha512tDigest
+        : LongDigest
+    {
+        private const ulong A5 = 0xa5a5a5a5a5a5a5a5UL;
+
+        private readonly int digestLength;
+
+        private ulong H1t, H2t, H3t, H4t, H5t, H6t, H7t, H8t;
+
+        /**
+         * Standard constructor
+         */
+        public Sha512tDigest(int bitLength)
+        {
+            if (bitLength >= 512)
+                throw new ArgumentException("cannot be >= 512", "bitLength");
+            if (bitLength % 8 != 0)
+                throw new ArgumentException("needs to be a multiple of 8", "bitLength");
+            if (bitLength == 384)
+                throw new ArgumentException("cannot be 384 use SHA384 instead", "bitLength");
+
+            this.digestLength = bitLength / 8;
+
+            tIvGenerate(digestLength * 8);
+
+            Reset();
+        }
+
+        /**
+         * Copy constructor.  This will copy the state of the provided
+         * message digest.
+         */
+        public Sha512tDigest(Sha512tDigest t)
+            : base(t)
+        {
+            this.digestLength = t.digestLength;
+
+			Reset(t);
+        }
+
+        public override string AlgorithmName
+        {
+            get { return "SHA-512/" + (digestLength * 8); }
+        }
+
+        public override int GetDigestSize()
+        {
+            return digestLength;
+        }
+
+        public override int DoFinal(byte[] output, int outOff)
+        {
+            Finish();
+
+            UInt64_To_BE(H1, output, outOff, digestLength);
+            UInt64_To_BE(H2, output, outOff + 8, digestLength - 8);
+            UInt64_To_BE(H3, output, outOff + 16, digestLength - 16);
+            UInt64_To_BE(H4, output, outOff + 24, digestLength - 24);
+            UInt64_To_BE(H5, output, outOff + 32, digestLength - 32);
+            UInt64_To_BE(H6, output, outOff + 40, digestLength - 40);
+            UInt64_To_BE(H7, output, outOff + 48, digestLength - 48);
+            UInt64_To_BE(H8, output, outOff + 56, digestLength - 56);
+
+            Reset();
+
+            return digestLength;
+        }
+
+        /**
+         * reset the chaining variables
+         */
+        public override void Reset()
+        {
+            base.Reset();
+
+            /*
+             * initial hash values use the iv generation algorithm for t.
+             */
+            H1 = H1t;
+            H2 = H2t;
+            H3 = H3t;
+            H4 = H4t;
+            H5 = H5t;
+            H6 = H6t;
+            H7 = H7t;
+            H8 = H8t;
+        }
+
+        private void tIvGenerate(int bitLength)
+        {
+            H1 = 0x6a09e667f3bcc908UL ^ A5;
+            H2 = 0xbb67ae8584caa73bUL ^ A5;
+            H3 = 0x3c6ef372fe94f82bUL ^ A5;
+            H4 = 0xa54ff53a5f1d36f1UL ^ A5;
+            H5 = 0x510e527fade682d1UL ^ A5;
+            H6 = 0x9b05688c2b3e6c1fUL ^ A5;
+            H7 = 0x1f83d9abfb41bd6bUL ^ A5;
+            H8 = 0x5be0cd19137e2179UL ^ A5;
+
+            Update(0x53);
+            Update(0x48);
+            Update(0x41);
+            Update(0x2D);
+            Update(0x35);
+            Update(0x31);
+            Update(0x32);
+            Update(0x2F);
+
+            if (bitLength > 100)
+            {
+                Update((byte)(bitLength / 100 + 0x30));
+                bitLength = bitLength % 100;
+                Update((byte)(bitLength / 10 + 0x30));
+                bitLength = bitLength % 10;
+                Update((byte)(bitLength + 0x30));
+            }
+            else if (bitLength > 10)
+            {
+                Update((byte)(bitLength / 10 + 0x30));
+                bitLength = bitLength % 10;
+                Update((byte)(bitLength + 0x30));
+            }
+            else
+            {
+                Update((byte)(bitLength + 0x30));
+            }
+
+            Finish();
+
+            H1t = H1;
+            H2t = H2;
+            H3t = H3;
+            H4t = H4;
+            H5t = H5;
+            H6t = H6;
+            H7t = H7;
+            H8t = H8;
+        }
+
+        private static void UInt64_To_BE(ulong n, byte[] bs, int off, int max)
+        {
+            if (max > 0)
+            {
+                UInt32_To_BE((uint)(n >> 32), bs, off, max);
+
+                if (max > 4)
+                {
+                    UInt32_To_BE((uint)n, bs, off + 4, max - 4);
+                }
+            }
+        }
+
+        private static void UInt32_To_BE(uint n, byte[] bs, int off, int max)
+        {
+            int num = System.Math.Min(4, max);
+            while (--num >= 0)
+            {
+                int shift = 8 * (3 - num);
+                bs[off + num] = (byte)(n >> shift);
+            }
+        }
+
+		public override IMemoable Copy()
+		{
+			return new Sha512tDigest(this);
+		}
+
+		public override void Reset(IMemoable other)
+		{
+			Sha512tDigest t = (Sha512tDigest)other;
+
+			if (this.digestLength != t.digestLength)
+			{
+				throw new MemoableResetException("digestLength inappropriate in other");
+			}
+
+			base.CopyIn(t);
+
+			this.H1t = t.H1t;
+			this.H2t = t.H2t;
+			this.H3t = t.H3t;
+			this.H4t = t.H4t;
+			this.H5t = t.H5t;
+			this.H6t = t.H6t;
+			this.H7t = t.H7t;
+			this.H8t = t.H8t;
+		}
+
+	}
+}
diff --git a/crypto/src/crypto/digests/ShortenedDigest.cs b/crypto/src/crypto/digests/ShortenedDigest.cs
new file mode 100644
index 000000000..9e4d99e7b
--- /dev/null
+++ b/crypto/src/crypto/digests/ShortenedDigest.cs
@@ -0,0 +1,82 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+	/**
+	* Wrapper class that reduces the output length of a particular digest to
+	* only the first n bytes of the digest function.
+	*/
+	public class ShortenedDigest
+		: IDigest
+	{
+		private IDigest	baseDigest;
+		private int		length;
+
+		/**
+		* Base constructor.
+		*
+		* @param baseDigest underlying digest to use.
+		* @param length length in bytes of the output of doFinal.
+		* @exception ArgumentException if baseDigest is null, or length is greater than baseDigest.GetDigestSize().
+		*/
+		public ShortenedDigest(
+			IDigest	baseDigest,
+			int		length)
+		{
+			if (baseDigest == null)
+			{
+				throw new ArgumentNullException("baseDigest");
+			}
+
+			if (length > baseDigest.GetDigestSize())
+			{
+				throw new ArgumentException("baseDigest output not large enough to support length");
+			}
+
+			this.baseDigest = baseDigest;
+			this.length = length;
+		}
+
+		public string AlgorithmName
+		{
+			get { return baseDigest.AlgorithmName + "(" + length * 8 + ")"; }
+		}
+
+		public int GetDigestSize()
+		{
+			return length;
+		}
+
+		public void Update(byte input)
+		{
+			baseDigest.Update(input);
+		}
+
+		public void BlockUpdate(byte[] input, int inOff, int length)
+		{
+			baseDigest.BlockUpdate(input, inOff, length);
+		}
+
+		public int DoFinal(byte[] output, int outOff)
+		{
+			byte[] tmp = new byte[baseDigest.GetDigestSize()];
+
+			baseDigest.DoFinal(tmp, 0);
+
+	        Array.Copy(tmp, 0, output, outOff, length);
+
+			return length;
+		}
+
+		public void Reset()
+		{
+			baseDigest.Reset();
+		}
+
+		public int GetByteLength()
+		{
+			return baseDigest.GetByteLength();
+		}
+	}
+}
diff --git a/crypto/src/crypto/digests/SkeinDigest.cs b/crypto/src/crypto/digests/SkeinDigest.cs
new file mode 100644
index 000000000..f826ce503
--- /dev/null
+++ b/crypto/src/crypto/digests/SkeinDigest.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+	/// <summary>
+	/// Implementation of the Skein parameterised hash function in 256, 512 and 1024 bit block sizes,
+	/// based on the <see cref="Org.BouncyCastle.Crypto.Engines.ThreefishEngine">Threefish</see> tweakable block cipher.
+	/// </summary>
+	/// <remarks>
+	/// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+	/// competition in October 2010.
+	/// <p/>
+	/// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+	/// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+	/// </remarks>
+	/// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinEngine"/>
+	/// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
+	public class SkeinDigest
+		: IDigest, IMemoable
+	{
+		/// <summary>
+		/// 256 bit block size - Skein-256
+		/// </summary>
+		public const int SKEIN_256 = SkeinEngine.SKEIN_256;
+		/// <summary>
+		/// 512 bit block size - Skein-512
+		/// </summary>
+		public const int SKEIN_512 = SkeinEngine.SKEIN_512;
+		/// <summary>
+		/// 1024 bit block size - Skein-1024
+		/// </summary>
+		public const int SKEIN_1024 = SkeinEngine.SKEIN_1024;
+
+		private readonly SkeinEngine engine;
+
+		/// <summary>
+		/// Constructs a Skein digest with an internal state size and output size.
+		/// </summary>
+		/// <param name="stateSizeBits">the internal state size in bits - one of <see cref="SKEIN_256"/> <see cref="SKEIN_512"/> or
+		///                       <see cref="SKEIN_1024"/>.</param>
+		/// <param name="digestSizeBits">the output/digest size to produce in bits, which must be an integral number of
+		///                      bytes.</param>
+		public SkeinDigest(int stateSizeBits, int digestSizeBits)
+		{
+			this.engine = new SkeinEngine(stateSizeBits, digestSizeBits);
+			Init(null);
+		}
+
+		public SkeinDigest(SkeinDigest digest)
+		{
+			this.engine = new SkeinEngine(digest.engine);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			SkeinDigest d = (SkeinDigest)other;
+			engine.Reset(d.engine);
+		}
+
+		public IMemoable Copy()
+		{
+			return new SkeinDigest(this);
+		}
+
+		public String AlgorithmName
+		{
+			get { return "Skein-" + (engine.BlockSize * 8) + "-" + (engine.OutputSize * 8); }
+		}
+
+		public int GetDigestSize()
+		{
+			return engine.OutputSize;
+		}
+
+		public int GetByteLength()
+		{
+			return engine.BlockSize;
+		}
+
+		/// <summary>
+		/// Optionally initialises the Skein digest with the provided parameters.
+		/// </summary>
+		/// See <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"></see> for details on the parameterisation of the Skein hash function.
+		/// <param name="parameters">the parameters to apply to this engine, or <code>null</code> to use no parameters.</param>
+		public void Init(SkeinParameters parameters)
+		{
+			engine.Init(parameters);
+		}
+
+		public void Reset()
+		{
+			engine.Reset();
+		}
+
+		public void Update(byte inByte)
+		{
+			engine.Update(inByte);
+		}
+
+		public void BlockUpdate(byte[] inBytes, int inOff, int len)
+		{
+			engine.Update(inBytes, inOff, len);
+		}
+
+		public int DoFinal(byte[] outBytes, int outOff)
+		{
+			return engine.DoFinal(outBytes, outOff);
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs
new file mode 100644
index 000000000..7e93138ac
--- /dev/null
+++ b/crypto/src/crypto/digests/SkeinEngine.cs
@@ -0,0 +1,804 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+    /// <summary>
+    /// Implementation of the Skein family of parameterised hash functions in 256, 512 and 1024 bit block
+    /// sizes, based on the <see cref="Org.BouncyCastle.Crypto.Engines.ThreefishEngine">Threefish</see> tweakable block cipher.
+    /// </summary>
+    /// <remarks>
+    /// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+    /// competition in October 2010.
+    /// <p/>
+    /// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+    /// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+    /// <p/>
+    /// This implementation is the basis for <see cref="Org.BouncyCastle.Crypto.Digests.SkeinDigest"/> and <see cref="Org.BouncyCastle.Crypto.Macs.SkeinMac"/>, implementing the
+    /// parameter based configuration system that allows Skein to be adapted to multiple applications. <br/>
+    /// Initialising the engine with <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/> allows standard and arbitrary parameters to
+    /// be applied during the Skein hash function.
+    /// <p/>
+    /// Implemented:
+    /// <ul>
+    /// <li>256, 512 and 1024 bit internal states.</li>
+    /// <li>Full 96 bit input length.</li>
+    /// <li>Parameters defined in the Skein specification, and arbitrary other pre and post message
+    /// parameters.</li>
+    /// <li>Arbitrary output size in 1 byte intervals.</li>
+    /// </ul>
+    /// <p/>
+    /// Not implemented:
+    /// <ul>
+    /// <li>Sub-byte length input (bit padding).</li>
+    /// <li>Tree hashing.</li>
+    /// </ul>
+    /// </remarks>
+    /// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
+    public class SkeinEngine
+        : IMemoable
+    {
+        /// <summary>
+        /// 256 bit block size - Skein-256
+        /// </summary>
+        public const int SKEIN_256 = ThreefishEngine.BLOCKSIZE_256;
+        /// <summary>
+        /// 512 bit block size - Skein-512
+        /// </summary>
+        public const int SKEIN_512 = ThreefishEngine.BLOCKSIZE_512;
+        /// <summary>
+        /// 1024 bit block size - Skein-1024
+        /// </summary>
+        public const int SKEIN_1024 = ThreefishEngine.BLOCKSIZE_1024;
+
+        // Minimal at present, but more complex when tree hashing is implemented
+        private class Configuration
+        {
+            private byte[] bytes = new byte[32];
+
+            public Configuration(long outputSizeBits)
+            {
+                // 0..3 = ASCII SHA3
+                bytes[0] = (byte)'S';
+                bytes[1] = (byte)'H';
+                bytes[2] = (byte)'A';
+                bytes[3] = (byte)'3';
+
+                // 4..5 = version number in LSB order
+                bytes[4] = 1;
+                bytes[5] = 0;
+
+                // 8..15 = output length
+                ThreefishEngine.WordToBytes((ulong)outputSizeBits, bytes, 8);
+            }
+
+            public byte[] Bytes
+            {
+                get { return bytes; }
+            }
+
+        }
+
+        public class Parameter
+        {
+            private int type;
+            private byte[] value;
+
+            public Parameter(int type, byte[] value)
+            {
+                this.type = type;
+                this.value = value;
+            }
+
+            public int Type
+            {
+                get { return type; }
+            }
+
+            public byte[] Value
+            {
+                get { return value; }
+            }
+
+        }
+
+        /**
+         * The parameter type for the Skein key.
+         */
+        private const int PARAM_TYPE_KEY = 0;
+
+        /**
+         * The parameter type for the Skein configuration block.
+         */
+        private const int PARAM_TYPE_CONFIG = 4;
+
+        /**
+         * The parameter type for the message.
+         */
+        private const int PARAM_TYPE_MESSAGE = 48;
+
+        /**
+         * The parameter type for the output transformation.
+         */
+        private const int PARAM_TYPE_OUTPUT = 63;
+
+        /**
+         * Precalculated UBI(CFG) states for common state/output combinations without key or other
+         * pre-message params.
+         */
+        private static readonly IDictionary INITIAL_STATES = Platform.CreateHashtable();
+
+        static SkeinEngine()
+        {
+            // From Appendix C of the Skein 1.3 NIST submission
+            InitialState(SKEIN_256, 128, new ulong[]{
+                0xe1111906964d7260UL,
+                0x883daaa77c8d811cUL,
+                0x10080df491960f7aUL,
+                0xccf7dde5b45bc1c2UL});
+
+            InitialState(SKEIN_256, 160, new ulong[]{
+                0x1420231472825e98UL,
+                0x2ac4e9a25a77e590UL,
+                0xd47a58568838d63eUL,
+                0x2dd2e4968586ab7dUL});
+
+            InitialState(SKEIN_256, 224, new ulong[]{
+                0xc6098a8c9ae5ea0bUL,
+                0x876d568608c5191cUL,
+                0x99cb88d7d7f53884UL,
+                0x384bddb1aeddb5deUL});
+
+            InitialState(SKEIN_256, 256, new ulong[]{
+                0xfc9da860d048b449UL,
+                0x2fca66479fa7d833UL,
+                0xb33bc3896656840fUL,
+                0x6a54e920fde8da69UL});
+
+            InitialState(SKEIN_512, 128, new ulong[]{
+                0xa8bc7bf36fbf9f52UL,
+                0x1e9872cebd1af0aaUL,
+                0x309b1790b32190d3UL,
+                0xbcfbb8543f94805cUL,
+                0x0da61bcd6e31b11bUL,
+                0x1a18ebead46a32e3UL,
+                0xa2cc5b18ce84aa82UL,
+                0x6982ab289d46982dUL});
+
+            InitialState(SKEIN_512, 160, new ulong[]{
+                0x28b81a2ae013bd91UL,
+                0xc2f11668b5bdf78fUL,
+                0x1760d8f3f6a56f12UL,
+                0x4fb747588239904fUL,
+                0x21ede07f7eaf5056UL,
+                0xd908922e63ed70b8UL,
+                0xb8ec76ffeccb52faUL,
+                0x01a47bb8a3f27a6eUL});
+
+            InitialState(SKEIN_512, 224, new ulong[]{
+                0xccd0616248677224UL,
+                0xcba65cf3a92339efUL,
+                0x8ccd69d652ff4b64UL,
+                0x398aed7b3ab890b4UL,
+                0x0f59d1b1457d2bd0UL,
+                0x6776fe6575d4eb3dUL,
+                0x99fbc70e997413e9UL,
+                0x9e2cfccfe1c41ef7UL});
+
+            InitialState(SKEIN_512, 384, new ulong[]{
+                0xa3f6c6bf3a75ef5fUL,
+                0xb0fef9ccfd84faa4UL,
+                0x9d77dd663d770cfeUL,
+                0xd798cbf3b468fddaUL,
+                0x1bc4a6668a0e4465UL,
+                0x7ed7d434e5807407UL,
+                0x548fc1acd4ec44d6UL,
+                0x266e17546aa18ff8UL});
+
+            InitialState(SKEIN_512, 512, new ulong[]{
+                0x4903adff749c51ceUL,
+                0x0d95de399746df03UL,
+                0x8fd1934127c79bceUL,
+                0x9a255629ff352cb1UL,
+                0x5db62599df6ca7b0UL,
+                0xeabe394ca9d5c3f4UL,
+                0x991112c71a75b523UL,
+                0xae18a40b660fcc33UL});
+        }
+
+        private static void InitialState(int blockSize, int outputSize, ulong[] state)
+        {
+            INITIAL_STATES.Add(VariantIdentifier(blockSize / 8, outputSize / 8), state);
+        }
+
+        private static int VariantIdentifier(int blockSizeBytes, int outputSizeBytes)
+        {
+            return (outputSizeBytes << 16) | blockSizeBytes;
+        }
+
+        private class UbiTweak
+        {
+            /**
+             * Point at which position might overflow long, so switch to add with carry logic
+             */
+            private const ulong LOW_RANGE = UInt64.MaxValue - UInt32.MaxValue;
+
+            /**
+             * Bit 127 = final
+             */
+            private const ulong T1_FINAL = 1UL << 63;
+
+            /**
+             * Bit 126 = first
+             */
+            private const ulong T1_FIRST = 1UL << 62;
+
+            /**
+             * UBI uses a 128 bit tweak
+             */
+            private ulong[] tweak = new ulong[2];
+
+            /**
+             * Whether 64 bit position exceeded
+             */
+            private bool extendedPosition;
+
+            public UbiTweak()
+            {
+                Reset();
+            }
+
+            public void Reset(UbiTweak tweak)
+            {
+                this.tweak = Arrays.Clone(tweak.tweak, this.tweak);
+                this.extendedPosition = tweak.extendedPosition;
+            }
+
+            public void Reset()
+            {
+                tweak[0] = 0;
+                tweak[1] = 0;
+                extendedPosition = false;
+                First = true;
+            }
+
+            public uint Type 
+            {
+                get 
+                {
+                    return (uint)((tweak[1] >> 56) & 0x3FUL);
+                }
+
+                set 
+                {
+                    // Bits 120..125 = type
+                    tweak[1] = (tweak[1] & 0xFFFFFFC000000000UL) | ((value & 0x3FUL) << 56);
+                }
+            }
+
+            public bool First
+            {
+                get
+                {
+                    return ((tweak[1] & T1_FIRST) != 0);
+                }
+                set
+                {
+                    if (value)
+                    {
+                        tweak[1] |= T1_FIRST;
+                    }
+                    else
+                    {
+                        tweak[1] &= ~T1_FIRST;
+                    }
+                }
+            }
+
+            public bool Final
+            {
+                get
+                {
+                    return ((tweak[1] & T1_FINAL) != 0);
+                }
+                set
+                {
+                    if (value)
+                    {
+                        tweak[1] |= T1_FINAL;
+                    }
+                    else
+                    {
+                        tweak[1] &= ~T1_FINAL;
+                    }
+                }
+            }
+
+            /**
+             * Advances the position in the tweak by the specified value.
+             */
+            public void AdvancePosition(int advance)
+            {
+                // Bits 0..95 = position
+                if (extendedPosition)
+                {
+                    ulong[] parts = new ulong[3];
+                    parts[0] = tweak[0] & 0xFFFFFFFFUL;
+                    parts[1] = (tweak[0] >> 32) & 0xFFFFFFFFUL;
+                    parts[2] = tweak[1] & 0xFFFFFFFFUL;
+
+                    ulong carry = (ulong)advance;
+                    for (int i = 0; i < parts.Length; i++)
+                    {
+                        carry += parts[i];
+                        parts[i] = carry;
+                        carry >>= 32;
+                    }
+                    tweak[0] = ((parts[1] & 0xFFFFFFFFUL) << 32) | (parts[0] & 0xFFFFFFFFUL);
+                    tweak[1] = (tweak[1] & 0xFFFFFFFF00000000UL) | (parts[2] & 0xFFFFFFFFUL);
+                }
+                else
+                {
+                    ulong position = tweak[0];
+                    position += (uint)advance;
+                    tweak[0] = position;
+                    if (position > LOW_RANGE)
+                    {
+                        extendedPosition = true;
+                    }
+                }
+            }
+
+            public ulong[] GetWords()
+            {
+                return tweak;
+            }
+
+            public override string ToString()
+            {
+                return Type + " first: " + First + ", final: " + Final;
+            }
+
+        }
+
+        /**
+         * The Unique Block Iteration chaining mode.
+         */
+        // TODO: This might be better as methods...
+        private class UBI
+        {
+            private readonly UbiTweak tweak = new UbiTweak();
+
+            private readonly SkeinEngine engine;
+
+            /**
+             * Buffer for the current block of message data
+             */
+            private byte[] currentBlock;
+
+            /**
+             * Offset into the current message block
+             */
+            private int currentOffset;
+
+            /**
+             * Buffer for message words for feedback into encrypted block
+             */
+            private ulong[] message;
+
+            public UBI(SkeinEngine engine, int blockSize)
+            {
+                this.engine = engine;
+                currentBlock = new byte[blockSize];
+                message = new ulong[currentBlock.Length / 8];
+            }
+
+            public void Reset(UBI ubi)
+            {
+                currentBlock = Arrays.Clone(ubi.currentBlock, currentBlock);
+                currentOffset = ubi.currentOffset;
+                message = Arrays.Clone(ubi.message, this.message);
+                tweak.Reset(ubi.tweak);
+            }
+
+            public void Reset(int type)
+            {
+                tweak.Reset();
+                tweak.Type = (uint)type;
+                currentOffset = 0;
+            }
+
+            public void Update(byte[] value, int offset, int len, ulong[] output)
+            {
+                /*
+                 * Buffer complete blocks for the underlying Threefish cipher, only flushing when there
+                 * are subsequent bytes (last block must be processed in doFinal() with final=true set).
+                 */
+                int copied = 0;
+                while (len > copied)
+                {
+                    if (currentOffset == currentBlock.Length)
+                    {
+                        ProcessBlock(output);
+                        tweak.First = false;
+                        currentOffset = 0;
+                    }
+
+                    int toCopy = System.Math.Min((len - copied), currentBlock.Length - currentOffset);
+                    Array.Copy(value, offset + copied, currentBlock, currentOffset, toCopy);
+                    copied += toCopy;
+                    currentOffset += toCopy;
+                    tweak.AdvancePosition(toCopy);
+                }
+            }
+
+            private void ProcessBlock(ulong[] output)
+            {
+                engine.threefish.Init(true, engine.chain, tweak.GetWords());
+                for (int i = 0; i < message.Length; i++)
+                {
+                    message[i] = ThreefishEngine.BytesToWord(currentBlock, i * 8);
+                }
+
+                engine.threefish.ProcessBlock(message, output);
+
+                for (int i = 0; i < output.Length; i++)
+                {
+                    output[i] ^= message[i];
+                }
+            }
+
+            public void DoFinal(ulong[] output)
+            {
+                // Pad remainder of current block with zeroes
+                for (int i = currentOffset; i < currentBlock.Length; i++)
+                {
+                    currentBlock[i] = 0;
+                }
+
+                tweak.Final = true;
+                ProcessBlock(output);
+            }
+
+        }
+
+        /**
+         * Underlying Threefish tweakable block cipher
+         */
+        private readonly ThreefishEngine threefish;
+
+        /**
+         * Size of the digest output, in bytes
+         */
+        private readonly int outputSizeBytes;
+
+        /**
+         * The current chaining/state value
+         */
+        private ulong[] chain;
+
+        /**
+         * The initial state value
+         */
+        private ulong[] initialState;
+
+        /**
+         * The (optional) key parameter
+         */
+        private byte[] key;
+
+        /**
+         * Parameters to apply prior to the message
+         */
+        private Parameter[] preMessageParameters;
+
+        /**
+         * Parameters to apply after the message, but prior to output
+         */
+        private Parameter[] postMessageParameters;
+
+        /**
+         * The current UBI operation
+         */
+        private readonly UBI ubi;
+
+        /**
+         * Buffer for single byte update method
+         */
+        private readonly byte[] singleByte = new byte[1];
+
+        /// <summary>
+        /// Constructs a Skein digest with an internal state size and output size.
+        /// </summary>
+        /// <param name="blockSizeBits">the internal state size in bits - one of <see cref="SKEIN_256"/> <see cref="SKEIN_512"/> or
+        ///                       <see cref="SKEIN_1024"/>.</param>
+        /// <param name="outputSizeBits">the output/digest size to produce in bits, which must be an integral number of
+        ///                      bytes.</param>
+        public SkeinEngine(int blockSizeBits, int outputSizeBits)
+        {
+            if (outputSizeBits % 8 != 0)
+            {
+                throw new ArgumentException("Output size must be a multiple of 8 bits. :" + outputSizeBits);
+            }
+            // TODO: Prevent digest sizes > block size?
+            this.outputSizeBytes = outputSizeBits / 8;
+
+            this.threefish = new ThreefishEngine(blockSizeBits);
+            this.ubi = new UBI(this,threefish.GetBlockSize());
+        }
+
+        /// <summary>
+        /// Creates a SkeinEngine as an exact copy of an existing instance.
+        /// </summary>
+        public SkeinEngine(SkeinEngine engine)
+            : this(engine.BlockSize * 8, engine.OutputSize * 8)
+        {
+            CopyIn(engine);
+        }
+
+        private void CopyIn(SkeinEngine engine)
+        {
+            this.ubi.Reset(engine.ubi);
+            this.chain = Arrays.Clone(engine.chain, this.chain);
+            this.initialState = Arrays.Clone(engine.initialState, this.initialState);
+            this.key = Arrays.Clone(engine.key, this.key);
+            this.preMessageParameters = Clone(engine.preMessageParameters, this.preMessageParameters);
+            this.postMessageParameters = Clone(engine.postMessageParameters, this.postMessageParameters);
+        }
+
+        private static Parameter[] Clone(Parameter[] data, Parameter[] existing)
+        {
+            if (data == null)
+            {
+                return null;
+            }
+            if ((existing == null) || (existing.Length != data.Length))
+            {
+                existing = new Parameter[data.Length];
+            }
+            Array.Copy(data, 0, existing, 0, existing.Length);
+            return existing;
+        }
+
+        public IMemoable Copy()
+        {
+            return new SkeinEngine(this);
+        }
+
+        public void Reset(IMemoable other)
+        {
+            SkeinEngine s = (SkeinEngine)other;
+            if ((BlockSize != s.BlockSize) || (outputSizeBytes != s.outputSizeBytes))
+            {
+                throw new MemoableResetException("Incompatible parameters in provided SkeinEngine.");
+            }
+            CopyIn(s);
+        }
+
+        public int OutputSize
+        {
+            get { return outputSizeBytes; }
+        }
+
+        public int BlockSize
+        {
+            get { return threefish.GetBlockSize (); }
+        }
+
+        /// <summary>
+        /// Initialises the Skein engine with the provided parameters. See <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/> for
+        /// details on the parameterisation of the Skein hash function.
+        /// </summary>
+        /// <param name="parameters">the parameters to apply to this engine, or <code>null</code> to use no parameters.</param>
+        public void Init(SkeinParameters parameters)
+        {
+            this.chain = null;
+            this.key = null;
+            this.preMessageParameters = null;
+            this.postMessageParameters = null;
+
+            if (parameters != null)
+            {
+                byte[] key = parameters.GetKey();
+                if (key.Length < 16)
+                {
+                    throw new ArgumentException("Skein key must be at least 128 bits.");
+                }
+                InitParams(parameters.GetParameters());
+            }
+            CreateInitialState();
+
+            // Initialise message block
+            UbiInit(PARAM_TYPE_MESSAGE);
+        }
+
+        private void InitParams(IDictionary parameters)
+        {
+            IEnumerator keys = parameters.Keys.GetEnumerator();
+            IList pre = Platform.CreateArrayList();
+            IList post = Platform.CreateArrayList();
+
+            while (keys.MoveNext())
+            {
+                int type = (int)keys.Current;
+                byte[] value = (byte[])parameters[type];
+
+                if (type == PARAM_TYPE_KEY)
+                {
+                    this.key = value;
+                }
+                else if (type < PARAM_TYPE_MESSAGE)
+                {
+                    pre.Add(new Parameter(type, value));
+                }
+                else
+                {
+                    post.Add(new Parameter(type, value));
+                }
+            }
+            preMessageParameters = new Parameter[pre.Count];
+            pre.CopyTo(preMessageParameters, 0);
+            Array.Sort(preMessageParameters);
+
+            postMessageParameters = new Parameter[post.Count];
+            post.CopyTo(postMessageParameters, 0);
+            Array.Sort(postMessageParameters);
+        }
+
+        /**
+         * Calculate the initial (pre message block) chaining state.
+         */
+        private void CreateInitialState()
+        {
+            ulong[] precalc = (ulong[])INITIAL_STATES[VariantIdentifier(BlockSize, OutputSize)];
+            if ((key == null) && (precalc != null))
+            {
+                // Precalculated UBI(CFG)
+                chain = Arrays.Clone(precalc);
+            }
+            else
+            {
+                // Blank initial state
+                chain = new ulong[BlockSize / 8];
+
+                // Process key block
+                if (key != null)
+                {
+                    UbiComplete(SkeinParameters.PARAM_TYPE_KEY, key);
+                }
+
+                // Process configuration block
+                UbiComplete(PARAM_TYPE_CONFIG, new Configuration(outputSizeBytes * 8).Bytes);
+            }
+
+            // Process additional pre-message parameters
+            if (preMessageParameters != null)
+            {
+                for (int i = 0; i < preMessageParameters.Length; i++)
+                {
+                    Parameter param = preMessageParameters[i];
+                    UbiComplete(param.Type, param.Value);
+                }
+            }
+            initialState = Arrays.Clone(chain);
+        }
+
+        /// <summary>
+        /// Reset the engine to the initial state (with the key and any pre-message parameters , ready to
+        /// accept message input.
+        /// </summary>
+        public void Reset()
+        {
+            Array.Copy(initialState, 0, chain, 0, chain.Length);
+
+            UbiInit(PARAM_TYPE_MESSAGE);
+        }
+
+        private void UbiComplete(int type, byte[] value)
+        {
+            UbiInit(type);
+            this.ubi.Update(value, 0, value.Length, chain);
+            UbiFinal();
+        }
+
+        private void UbiInit(int type)
+        {
+            this.ubi.Reset(type);
+        }
+
+        private void UbiFinal()
+        {
+            ubi.DoFinal(chain);
+        }
+
+        private void CheckInitialised()
+        {
+            if (this.ubi == null)
+            {
+                throw new ArgumentException("Skein engine is not initialised.");
+            }
+        }
+
+        public void Update(byte inByte)
+        {
+            singleByte[0] = inByte;
+            Update(singleByte, 0, 1);
+        }
+
+        public void Update(byte[] inBytes, int inOff, int len)
+        {
+            CheckInitialised();
+            ubi.Update(inBytes, inOff, len, chain);
+        }
+
+        public int DoFinal(byte[] outBytes, int outOff)
+        {
+            CheckInitialised();
+            if (outBytes.Length < (outOff + outputSizeBytes))
+            {
+                throw new DataLengthException("Output buffer is too short to hold output of " + outputSizeBytes + " bytes");
+            }
+
+            // Finalise message block
+            UbiFinal();
+
+            // Process additional post-message parameters
+            if (postMessageParameters != null)
+            {
+                for (int i = 0; i < postMessageParameters.Length; i++)
+                {
+                    Parameter param = postMessageParameters[i];
+                    UbiComplete(param.Type, param.Value);
+                }
+            }
+
+            // Perform the output transform
+            int blockSize = BlockSize;
+            int blocksRequired = ((outputSizeBytes + blockSize - 1) / blockSize);
+            for (int i = 0; i < blocksRequired; i++)
+            {
+                int toWrite = System.Math.Min(blockSize, outputSizeBytes - (i * blockSize));
+                Output((ulong)i, outBytes, outOff + (i * blockSize), toWrite);
+            }
+
+            Reset();
+
+            return outputSizeBytes;
+        }
+
+        private void Output(ulong outputSequence, byte[] outBytes, int outOff, int outputBytes)
+        {
+            byte[] currentBytes = new byte[8];
+            ThreefishEngine.WordToBytes(outputSequence, currentBytes, 0);
+
+            // Output is a sequence of UBI invocations all of which use and preserve the pre-output
+            // state
+            ulong[] outputWords = new ulong[chain.Length];
+            UbiInit(PARAM_TYPE_OUTPUT);
+            this.ubi.Update(currentBytes, 0, currentBytes.Length, outputWords);
+            ubi.DoFinal(outputWords);
+
+            int wordsRequired = ((outputBytes + 8 - 1) / 8);
+            for (int i = 0; i < wordsRequired; i++)
+            {
+                int toWrite = System.Math.Min(8, outputBytes - (i * 8));
+                if (toWrite == 8)
+                {
+                    ThreefishEngine.WordToBytes(outputWords[i], outBytes, outOff + (i * 8));
+                }
+                else
+                {
+                    ThreefishEngine.WordToBytes(outputWords[i], currentBytes, 0);
+                    Array.Copy(currentBytes, 0, outBytes, outOff + (i * 8), toWrite);
+                }
+            }
+        }
+
+    }
+}
+
diff --git a/crypto/src/crypto/digests/TigerDigest.cs b/crypto/src/crypto/digests/TigerDigest.cs
index b8c9a7664..059232de0 100644
--- a/crypto/src/crypto/digests/TigerDigest.cs
+++ b/crypto/src/crypto/digests/TigerDigest.cs
@@ -1,5 +1,7 @@
 using System;
+
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     *  http://www.cs.technion.ac.il/~biham/Reports/Tiger</a>
     */
     public class TigerDigest
-		: IDigest
+		: IDigest, IMemoable
     {
         private const int MyByteLength = 64;
 
@@ -571,17 +573,7 @@ namespace Org.BouncyCastle.Crypto.Digests
         */
         public TigerDigest(TigerDigest t)
         {
-            a = t.a;
-            b = t.b;
-            c = t.c;
-
-            Array.Copy(t.x, 0, x, 0, t.x.Length);
-            xOff = t.xOff;
-
-            Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length);
-            bOff = t.bOff;
-
-            byteCount = t.byteCount;
+			Reset(t);
         }
 
 		public string AlgorithmName
@@ -864,5 +856,28 @@ namespace Org.BouncyCastle.Crypto.Digests
 
             byteCount = 0;
         }
-    }
+
+		public IMemoable Copy()
+		{
+			return new TigerDigest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			TigerDigest t = (TigerDigest)other;
+
+			a = t.a;
+			b = t.b;
+			c = t.c;
+
+			Array.Copy(t.x, 0, x, 0, t.x.Length);
+			xOff = t.xOff;
+
+			Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length);
+			bOff = t.bOff;
+
+			byteCount = t.byteCount;
+		}    
+
+	}
 }
diff --git a/crypto/src/crypto/digests/WhirlpoolDigest.cs b/crypto/src/crypto/digests/WhirlpoolDigest.cs
index df83f4508..55b71205e 100644
--- a/crypto/src/crypto/digests/WhirlpoolDigest.cs
+++ b/crypto/src/crypto/digests/WhirlpoolDigest.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
 {
@@ -9,7 +10,8 @@ namespace Org.BouncyCastle.Crypto.Digests
 	* and Rijmen.
 	*
 	*/
-	public sealed class WhirlpoolDigest : IDigest
+	public sealed class WhirlpoolDigest
+		: IDigest, IMemoable
 	{
 		private const int BYTE_LENGTH = 64;
 
@@ -149,19 +151,7 @@ namespace Org.BouncyCastle.Crypto.Digests
 			*/
 		public WhirlpoolDigest(WhirlpoolDigest originalDigest)
 		{
-			Array.Copy(originalDigest._rc, 0, _rc, 0, _rc.Length);
-
-			Array.Copy(originalDigest._buffer, 0, _buffer, 0, _buffer.Length);
-
-			this._bufferPos = originalDigest._bufferPos;
-			Array.Copy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.Length);
-
-			// -- internal hash state --
-			Array.Copy(originalDigest._hash, 0, _hash, 0, _hash.Length);
-			Array.Copy(originalDigest._K, 0, _K, 0, _K.Length);
-			Array.Copy(originalDigest._L, 0, _L, 0, _L.Length);
-			Array.Copy(originalDigest._block, 0, _block, 0, _block.Length);
-			Array.Copy(originalDigest._state, 0, _state, 0, _state.Length);
+			Reset(originalDigest);
 		}
 
 		public string AlgorithmName
@@ -393,5 +383,31 @@ namespace Org.BouncyCastle.Crypto.Digests
 		{
 			return BYTE_LENGTH;
 		}
+
+		public IMemoable Copy()
+		{
+			return new WhirlpoolDigest(this);
+		}
+
+		public void Reset(IMemoable other)
+		{
+			WhirlpoolDigest originalDigest = (WhirlpoolDigest)other;
+
+			Array.Copy(originalDigest._rc, 0, _rc, 0, _rc.Length);
+
+			Array.Copy(originalDigest._buffer, 0, _buffer, 0, _buffer.Length);
+
+			this._bufferPos = originalDigest._bufferPos;
+			Array.Copy(originalDigest._bitCount, 0, _bitCount, 0, _bitCount.Length);
+
+			// -- internal hash state --
+			Array.Copy(originalDigest._hash, 0, _hash, 0, _hash.Length);
+			Array.Copy(originalDigest._K, 0, _K, 0, _K.Length);
+			Array.Copy(originalDigest._L, 0, _L, 0, _L.Length);
+			Array.Copy(originalDigest._block, 0, _block, 0, _block.Length);
+			Array.Copy(originalDigest._state, 0, _state, 0, _state.Length);
+		}
+
+
 	}
 }
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
new file mode 100644
index 000000000..8ff1d24c7
--- /dev/null
+++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -0,0 +1,366 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Custom.Djb;
+using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.EC
+{
+    public sealed class CustomNamedCurves
+    {
+        private CustomNamedCurves()
+        {
+        }
+
+        private static BigInteger FromHex(string hex)
+        {
+            return new BigInteger(1, Hex.Decode(hex));
+        }
+
+        private static ECCurve ConfigureCurve(ECCurve curve)
+        {
+            return curve;
+        }
+
+        private static ECCurve ConfigureCurveGlv(ECCurve c, GlvTypeBParameters p)
+        {
+            return c.Configure().SetEndomorphism(new GlvTypeBEndomorphism(c, p)).Create();
+        }
+
+        /*
+         * curve25519
+         */
+        internal class Curve25519Holder
+            : X9ECParametersHolder
+        {
+            private Curve25519Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new Curve25519Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                ECCurve curve = ConfigureCurve(new Curve25519());
+
+                /*
+                 * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form
+                 * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3).
+                 * 
+                 * The Curve25519 paper doesn't say which of the two possible y values the base
+                 * point has. The choice here is guided by language in the Ed25519 paper.
+                 * 
+                 * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14) 
+                 */
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A"
+                    + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"));
+
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp192k1
+         */
+        internal class Secp192k1Holder
+            : X9ECParametersHolder
+        {
+            private Secp192k1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new Secp192k1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16),
+                    new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16),
+                    new BigInteger[]{
+                        new BigInteger("71169be7330b3038edb025f1", 16),
+                        new BigInteger("-b3fb3400dec5c4adceb8655c", 16) },
+                    new BigInteger[]{
+                        new BigInteger("12511cfe811d0f4e6bc688b4d", 16),
+                        new BigInteger("71169be7330b3038edb025f1", 16) },
+                    new BigInteger("71169be7330b3038edb025f1d0f9", 16),
+                    new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
+                    208);
+                ECCurve curve = ConfigureCurveGlv(new SecP192K1Curve(), glv);
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+                    + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp192r1
+         */
+        internal class Secp192r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp192r1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new Secp192r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+                ECCurve curve = ConfigureCurve(new SecP192R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+                    + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp224k1
+         */
+        internal class Secp224k1Holder
+            : X9ECParametersHolder
+        {
+            private Secp224k1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new Secp224k1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16),
+                    new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16),
+                    new BigInteger[]{
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16),
+                        new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) },
+                    new BigInteger[]{
+                        new BigInteger("1243ae1b4d71613bc9f780a03690e", 16),
+                        new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) },
+                    new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16),
+                    new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
+                    240);
+                ECCurve curve = ConfigureCurveGlv(new SecP224K1Curve(), glv);
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+                    + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp224r1
+         */
+        internal class Secp224r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp224r1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new Secp224r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+                ECCurve curve = ConfigureCurve(new SecP224R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+                    + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp256k1
+         */
+        internal class Secp256k1Holder
+            : X9ECParametersHolder
+        {
+            private Secp256k1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp256k1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = null;
+                GlvTypeBParameters glv = new GlvTypeBParameters(
+                    new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16),
+                    new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16),
+                    new BigInteger[]{
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16),
+                        new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) },
+                    new BigInteger[]{
+                        new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16),
+                        new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) },
+                    new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16),
+                    new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
+                    272);
+                ECCurve curve = ConfigureCurveGlv(new SecP256K1Curve(), glv);
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+                    + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp256r1
+         */
+        internal class Secp256r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp256r1Holder() {}
+
+            internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90");
+                ECCurve curve = ConfigureCurve(new SecP256R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+                    + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp384r1
+         */
+        internal class Secp384r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp384r1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+                ECCurve curve = ConfigureCurve(new SecP384R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+                    + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        /*
+         * secp521r1
+         */
+        internal class Secp521r1Holder
+            : X9ECParametersHolder
+        {
+            private Secp521r1Holder() { }
+
+            internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder();
+
+            protected override X9ECParameters CreateParameters()
+            {
+                byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+                ECCurve curve = ConfigureCurve(new SecP521R1Curve());
+                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                    + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+                    + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+                return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
+            }
+        }
+
+        private static readonly IDictionary nameToCurve = Platform.CreateHashtable();
+        private static readonly IDictionary nameToOid = Platform.CreateHashtable();
+        private static readonly IDictionary oidToCurve = Platform.CreateHashtable();
+        private static readonly IDictionary oidToName = Platform.CreateHashtable();
+
+        private static void DefineCurve(string name, X9ECParametersHolder holder)
+        {
+            nameToCurve.Add(name, holder);
+        }
+
+        private static void DefineCurve(string name, DerObjectIdentifier oid, X9ECParametersHolder holder)
+        {
+            nameToCurve.Add(name, holder);
+            nameToOid.Add(name, oid);
+            oidToName.Add(oid, name);
+            oidToCurve.Add(oid, holder);
+        }
+
+        private static void DefineCurveAlias(string alias, DerObjectIdentifier oid)
+        {
+            alias = Platform.ToLowerInvariant(alias);
+            nameToOid.Add(alias, oid);
+            nameToCurve.Add(alias, oidToCurve[oid]);
+        }
+
+        static CustomNamedCurves()
+        {
+            DefineCurve("curve25519", Curve25519Holder.Instance);
+
+            DefineCurve("secp192k1", SecObjectIdentifiers.SecP192k1, Secp192k1Holder.Instance);
+            DefineCurve("secp192r1", SecObjectIdentifiers.SecP192r1, Secp192r1Holder.Instance);
+            DefineCurve("secp224k1", SecObjectIdentifiers.SecP224k1, Secp224k1Holder.Instance);
+            DefineCurve("secp224r1", SecObjectIdentifiers.SecP224r1, Secp224r1Holder.Instance);
+            DefineCurve("secp256k1", SecObjectIdentifiers.SecP256k1, Secp256k1Holder.Instance);
+            DefineCurve("secp256r1", SecObjectIdentifiers.SecP256r1, Secp256r1Holder.Instance);
+            DefineCurve("secp384r1", SecObjectIdentifiers.SecP384r1, Secp384r1Holder.Instance);
+            DefineCurve("secp521r1", SecObjectIdentifiers.SecP521r1, Secp521r1Holder.Instance);
+
+            DefineCurveAlias("P-192", SecObjectIdentifiers.SecP192r1);
+            DefineCurveAlias("P-224", SecObjectIdentifiers.SecP224r1);
+            DefineCurveAlias("P-256", SecObjectIdentifiers.SecP256r1);
+            DefineCurveAlias("P-384", SecObjectIdentifiers.SecP384r1);
+            DefineCurveAlias("P-521", SecObjectIdentifiers.SecP521r1);
+        }
+
+        public static X9ECParameters GetByName(string name)
+        {
+            X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve[Platform.ToLowerInvariant(name)];
+            return holder == null ? null : holder.Parameters;
+        }
+
+        /**
+         * 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(DerObjectIdentifier oid)
+        {
+            X9ECParametersHolder holder = (X9ECParametersHolder)oidToCurve[oid];
+            return holder == null ? null : holder.Parameters;
+        }
+
+        /**
+         * 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 DerObjectIdentifier GetOid(string name)
+        {
+            return (DerObjectIdentifier)nameToOid[Platform.ToLowerInvariant(name)];
+        }
+
+        /**
+         * return the named curve name represented by the given object identifier.
+         */
+        public static string GetName(DerObjectIdentifier oid)
+        {
+            return (string)oidToName[oid];
+        }
+
+        /**
+         * returns an enumeration containing the name strings for curves
+         * contained in this structure.
+         */
+        public static IEnumerable Names
+        {
+            get { return new EnumerableProxy(nameToCurve.Keys); }
+        }
+    }
+}
diff --git a/crypto/src/crypto/encodings/ISO9796d1Encoding.cs b/crypto/src/crypto/encodings/ISO9796d1Encoding.cs
new file mode 100644
index 000000000..30e988356
--- /dev/null
+++ b/crypto/src/crypto/encodings/ISO9796d1Encoding.cs
@@ -0,0 +1,273 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Encodings
+{
+	/**
+	* ISO 9796-1 padding. Note in the light of recent results you should
+	* only use this with RSA (rather than the "simpler" Rabin keys) and you
+	* should never use it with anything other than a hash (ie. even if the
+	* message is small don't sign the message, sign it's hash) or some "random"
+	* value. See your favorite search engine for details.
+	*/
+	public class ISO9796d1Encoding
+		: IAsymmetricBlockCipher
+	{
+		private static readonly BigInteger Sixteen = BigInteger.ValueOf(16);
+		private static readonly BigInteger Six = BigInteger.ValueOf(6);
+
+		private static readonly byte[] shadows = { 0xe, 0x3, 0x5, 0x8, 0x9, 0x4, 0x2, 0xf,
+			0x0, 0xd, 0xb, 0x6, 0x7, 0xa, 0xc, 0x1 };
+		private static readonly byte[] inverse = { 0x8, 0xf, 0x6, 0x1, 0x5, 0x2, 0xb, 0xc,
+			0x3, 0x4, 0xd, 0xa, 0xe, 0x9, 0x0, 0x7 };
+
+		private readonly IAsymmetricBlockCipher engine;
+		private bool forEncryption;
+		private int bitSize;
+		private int padBits = 0;
+		private BigInteger modulus;
+
+		public ISO9796d1Encoding(
+			IAsymmetricBlockCipher   cipher)
+		{
+			this.engine = cipher;
+		}
+
+		public string AlgorithmName
+		{
+			get { return engine.AlgorithmName + "/ISO9796-1Padding"; }
+		}
+
+		public IAsymmetricBlockCipher GetUnderlyingCipher()
+		{
+			return engine;
+		}
+
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			RsaKeyParameters kParam;
+			if (parameters is ParametersWithRandom)
+			{
+				ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+				kParam = (RsaKeyParameters)rParam.Parameters;
+			}
+			else
+			{
+				kParam = (RsaKeyParameters)parameters;
+			}
+
+			engine.Init(forEncryption, parameters);
+
+			modulus = kParam.Modulus;
+			bitSize = modulus.BitLength;
+
+			this.forEncryption = forEncryption;
+		}
+
+		/**
+		* return the input block size. The largest message we can process
+		* is (key_size_in_bits + 3)/16, which in our world comes to
+		* key_size_in_bytes / 2.
+		*/
+		public int GetInputBlockSize()
+		{
+			int baseBlockSize = engine.GetInputBlockSize();
+
+			if (forEncryption)
+			{
+				return (baseBlockSize + 1) / 2;
+			}
+			else
+			{
+				return baseBlockSize;
+			}
+		}
+
+		/**
+		* return the maximum possible size for the output.
+		*/
+		public int GetOutputBlockSize()
+		{
+			int baseBlockSize = engine.GetOutputBlockSize();
+
+			if (forEncryption)
+			{
+				return baseBlockSize;
+			}
+			else
+			{
+				return (baseBlockSize + 1) / 2;
+			}
+		}
+
+		/**
+		* set the number of bits in the next message to be treated as
+		* pad bits.
+		*/
+		public void SetPadBits(
+			int     padBits)
+		{
+			if (padBits > 7)
+			{
+				throw new ArgumentException("padBits > 7");
+			}
+
+			this.padBits = padBits;
+		}
+
+		/**
+		* retrieve the number of pad bits in the last decoded message.
+		*/
+		public int GetPadBits()
+		{
+			return padBits;
+		}
+
+		public byte[] ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (forEncryption)
+			{
+				return EncodeBlock(input, inOff, length);
+			}
+			else
+			{
+				return DecodeBlock(input, inOff, length);
+			}
+		}
+
+		private byte[] EncodeBlock(
+			byte[]	input,
+			int		inOff,
+			int		inLen)
+		{
+			byte[]  block = new byte[(bitSize + 7) / 8];
+			int     r = padBits + 1;
+			int     z = inLen;
+			int     t = (bitSize + 13) / 16;
+
+			for (int i = 0; i < t; i += z)
+			{
+				if (i > t - z)
+				{
+					Array.Copy(input, inOff + inLen - (t - i),
+						block, block.Length - t, t - i);
+				}
+				else
+				{
+					Array.Copy(input, inOff, block, block.Length - (i + z), z);
+				}
+			}
+
+			for (int i = block.Length - 2 * t; i != block.Length; i += 2)
+			{
+				byte val = block[block.Length - t + i / 2];
+
+				block[i] = (byte)((shadows[(uint) (val & 0xff) >> 4] << 4)
+					| shadows[val & 0x0f]);
+				block[i + 1] = val;
+			}
+
+			block[block.Length - 2 * z] ^= (byte) r;
+			block[block.Length - 1] = (byte)((block[block.Length - 1] << 4) | 0x06);
+
+			int maxBit = (8 - (bitSize - 1) % 8);
+			int offSet = 0;
+
+			if (maxBit != 8)
+			{
+				block[0] &= (byte) ((ushort) 0xff >> maxBit);
+				block[0] |= (byte) ((ushort) 0x80 >> maxBit);
+			}
+			else
+			{
+				block[0] = 0x00;
+				block[1] |= 0x80;
+				offSet = 1;
+			}
+
+			return engine.ProcessBlock(block, offSet, block.Length - offSet);
+		}
+
+		/**
+		* @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
+		*/
+		private byte[] DecodeBlock(
+			byte[]	input,
+			int		inOff,
+			int		inLen)
+		{
+			byte[]  block = engine.ProcessBlock(input, inOff, inLen);
+			int     r = 1;
+			int     t = (bitSize + 13) / 16;
+
+			BigInteger iS = new BigInteger(1, block);
+			BigInteger iR;
+			if (iS.Mod(Sixteen).Equals(Six))
+			{
+				iR = iS;
+			}
+			else
+			{
+				iR = modulus.Subtract(iS);
+
+				if (!iR.Mod(Sixteen).Equals(Six))
+					throw new InvalidCipherTextException("resulting integer iS or (modulus - iS) is not congruent to 6 mod 16");
+			}
+
+			block = iR.ToByteArrayUnsigned();
+
+			if ((block[block.Length - 1] & 0x0f) != 0x6)
+				throw new InvalidCipherTextException("invalid forcing byte in block");
+
+			block[block.Length - 1] =
+				(byte)(((ushort)(block[block.Length - 1] & 0xff) >> 4)
+				| ((inverse[(block[block.Length - 2] & 0xff) >> 4]) << 4));
+
+			block[0] = (byte)((shadows[(uint) (block[1] & 0xff) >> 4] << 4)
+				| shadows[block[1] & 0x0f]);
+
+			bool boundaryFound = false;
+			int boundary = 0;
+
+			for (int i = block.Length - 1; i >= block.Length - 2 * t; i -= 2)
+			{
+				int val = ((shadows[(uint) (block[i] & 0xff) >> 4] << 4)
+					| shadows[block[i] & 0x0f]);
+
+				if (((block[i - 1] ^ val) & 0xff) != 0)
+				{
+					if (!boundaryFound)
+					{
+						boundaryFound = true;
+						r = (block[i - 1] ^ val) & 0xff;
+						boundary = i - 1;
+					}
+					else
+					{
+						throw new InvalidCipherTextException("invalid tsums in block");
+					}
+				}
+			}
+
+			block[boundary] = 0;
+
+			byte[] nblock = new byte[(block.Length - boundary) / 2];
+
+			for (int i = 0; i < nblock.Length; i++)
+			{
+				nblock[i] = block[2 * i + boundary + 1];
+			}
+
+			padBits = r - 1;
+
+			return nblock;
+		}
+	}
+}
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index 81561e7f5..a4d2f0e36 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -6,340 +6,344 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Encodings
 {
-	/**
-	* Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
-	*/
-	public class OaepEncoding
-		: IAsymmetricBlockCipher
-	{
-		private byte[] defHash;
-		private IDigest hash;
-		private IDigest mgf1Hash;
-
-		private IAsymmetricBlockCipher engine;
-		private SecureRandom random;
-		private bool forEncryption;
-
-		public OaepEncoding(
-			IAsymmetricBlockCipher cipher)
-			: this(cipher, new Sha1Digest(), null)
-		{
-		}
-
-		public OaepEncoding(
-			IAsymmetricBlockCipher	cipher,
-			IDigest					hash)
-			: this(cipher, hash, null)
-		{
-		}
-
-		public OaepEncoding(
-			IAsymmetricBlockCipher	cipher,
-			IDigest					hash,
-			byte[]					encodingParams)
-			: this(cipher, hash, hash, encodingParams)
-		{
-		}
-
-		public OaepEncoding(
-			IAsymmetricBlockCipher	cipher,
-			IDigest					hash,
-			IDigest					mgf1Hash,
-			byte[]					encodingParams)
-		{
-			this.engine = cipher;
-			this.hash = hash;
-			this.mgf1Hash = mgf1Hash;
-			this.defHash = new byte[hash.GetDigestSize()];
-
-			if (encodingParams != null)
-			{
-				hash.BlockUpdate(encodingParams, 0, encodingParams.Length);
-			}
-
-			hash.DoFinal(defHash, 0);
-		}
-
-		public IAsymmetricBlockCipher GetUnderlyingCipher()
-		{
-			return engine;
-		}
-
-		public string AlgorithmName
-		{
-			get { return engine.AlgorithmName + "/OAEPPadding"; }
-		}
-
-		public void Init(
-			bool				forEncryption,
-			ICipherParameters	param)
-		{
-			if (param is ParametersWithRandom)
-			{
-				ParametersWithRandom rParam = (ParametersWithRandom)param;
-				this.random = rParam.Random;
-			}
-			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[]	inBytes,
-			int		inOff,
-			int		inLen)
-		{
-			if (forEncryption)
-			{
-				return encodeBlock(inBytes, inOff, inLen);
-			}
-			else
-			{
-				return decodeBlock(inBytes, inOff, inLen);
-			}
-		}
-
-		private byte[] encodeBlock(
-			byte[]	inBytes,
-			int		inOff,
-			int		inLen)
-		{
-			byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length];
-
-			//
-			// copy in the message
-			//
-			Array.Copy(inBytes, 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.
-			//
-			Array.Copy(defHash, 0, block, defHash.Length, defHash.Length);
-
-			//
-			// generate the seed.
-			//
-			byte[] seed = random.GenerateSeed(defHash.Length);
-
-			//
-			// 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
-			//
-			Array.Copy(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.
-		*/
-		private byte[] decodeBlock(
-			byte[]	inBytes,
-			int		inOff,
-			int		inLen)
-		{
-			byte[] data = engine.ProcessBlock(inBytes, 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()];
-
-				Array.Copy(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];
-
-			Array.Copy(block, start, output, 0, output.Length);
-
-			return output;
-		}
-
-		/**
-		* int to octet string.
-		*/
-		private void ItoOSP(
-			int		i,
-			byte[]	sp)
-		{
-			sp[0] = (byte)((uint)i >> 24);
-			sp[1] = (byte)((uint)i >> 16);
-			sp[2] = (byte)((uint)i >> 8);
-			sp[3] = (byte)((uint)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.BlockUpdate(Z, zOff, zLen);
-				mgf1Hash.BlockUpdate(C, 0, C.Length);
-				mgf1Hash.DoFinal(hashBuf, 0);
-
-				Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length);
-			}
-			while (++counter < (length / hashBuf.Length));
-
-			if ((counter * hashBuf.Length) < length)
-			{
-				ItoOSP(counter, C);
-
-				mgf1Hash.BlockUpdate(Z, zOff, zLen);
-				mgf1Hash.BlockUpdate(C, 0, C.Length);
-				mgf1Hash.DoFinal(hashBuf, 0);
-
-				Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, mask.Length - (counter * hashBuf.Length));
-			}
-
-			return mask;
-		}
-	}
+    /**
+    * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+    */
+    public class OaepEncoding
+        : IAsymmetricBlockCipher
+    {
+        private byte[] defHash;
+        private IDigest hash;
+        private IDigest mgf1Hash;
+
+        private IAsymmetricBlockCipher engine;
+        private SecureRandom random;
+        private bool forEncryption;
+
+        public OaepEncoding(
+            IAsymmetricBlockCipher cipher)
+            : this(cipher, new Sha1Digest(), null)
+        {
+        }
+
+        public OaepEncoding(
+            IAsymmetricBlockCipher	cipher,
+            IDigest					hash)
+            : this(cipher, hash, null)
+        {
+        }
+
+        public OaepEncoding(
+            IAsymmetricBlockCipher	cipher,
+            IDigest					hash,
+            byte[]					encodingParams)
+            : this(cipher, hash, hash, encodingParams)
+        {
+        }
+
+        public OaepEncoding(
+            IAsymmetricBlockCipher	cipher,
+            IDigest					hash,
+            IDigest					mgf1Hash,
+            byte[]					encodingParams)
+        {
+            this.engine = cipher;
+            this.hash = hash;
+            this.mgf1Hash = mgf1Hash;
+            this.defHash = new byte[hash.GetDigestSize()];
+
+            if (encodingParams != null)
+            {
+                hash.BlockUpdate(encodingParams, 0, encodingParams.Length);
+            }
+
+            hash.DoFinal(defHash, 0);
+        }
+
+        public IAsymmetricBlockCipher GetUnderlyingCipher()
+        {
+            return engine;
+        }
+
+        public string AlgorithmName
+        {
+            get { return engine.AlgorithmName + "/OAEPPadding"; }
+        }
+
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	param)
+        {
+            if (param is ParametersWithRandom)
+            {
+                ParametersWithRandom rParam = (ParametersWithRandom)param;
+                this.random = rParam.Random;
+            }
+            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[]	inBytes,
+            int		inOff,
+            int		inLen)
+        {
+            if (forEncryption)
+            {
+                return EncodeBlock(inBytes, inOff, inLen);
+            }
+            else
+            {
+                return DecodeBlock(inBytes, inOff, inLen);
+            }
+        }
+
+        private byte[] EncodeBlock(
+            byte[]	inBytes,
+            int		inOff,
+            int		inLen)
+        {
+            byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length];
+
+            //
+            // copy in the message
+            //
+            Array.Copy(inBytes, 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.
+            //
+            Array.Copy(defHash, 0, block, defHash.Length, defHash.Length);
+
+            //
+            // generate the seed.
+            //
+            byte[] seed = random.GenerateSeed(defHash.Length);
+
+            //
+            // 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
+            //
+            Array.Copy(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.
+        */
+        private byte[] DecodeBlock(
+            byte[]	inBytes,
+            int		inOff,
+            int		inLen)
+        {
+            byte[] data = engine.ProcessBlock(inBytes, 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()];
+
+                Array.Copy(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.
+            // long check to try to avoid this been a source of a timing attack.
+            //
+            {
+                int diff = 0;
+                for (int i = 0; i < defHash.Length; ++i)
+                {
+                    diff |= (byte)(defHash[i] ^ block[defHash.Length + i]);
+                }
+ 
+                if (diff != 0)
+                    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];
+
+            Array.Copy(block, start, output, 0, output.Length);
+
+            return output;
+        }
+
+        /**
+        * int to octet string.
+        */
+        private void ItoOSP(
+            int		i,
+            byte[]	sp)
+        {
+            sp[0] = (byte)((uint)i >> 24);
+            sp[1] = (byte)((uint)i >> 16);
+            sp[2] = (byte)((uint)i >> 8);
+            sp[3] = (byte)((uint)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.BlockUpdate(Z, zOff, zLen);
+                mgf1Hash.BlockUpdate(C, 0, C.Length);
+                mgf1Hash.DoFinal(hashBuf, 0);
+
+                Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length);
+            }
+            while (++counter < (length / hashBuf.Length));
+
+            if ((counter * hashBuf.Length) < length)
+            {
+                ItoOSP(counter, C);
+
+                mgf1Hash.BlockUpdate(Z, zOff, zLen);
+                mgf1Hash.BlockUpdate(C, 0, C.Length);
+                mgf1Hash.DoFinal(hashBuf, 0);
+
+                Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, mask.Length - (counter * hashBuf.Length));
+            }
+
+            return mask;
+        }
+    }
 }
 
diff --git a/crypto/src/crypto/encodings/Pkcs1Encoding.cs b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
index d2225a7d4..35fd96abe 100644
--- a/crypto/src/crypto/encodings/Pkcs1Encoding.cs
+++ b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -7,226 +7,376 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Encodings
 {
-	/**
-	* 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
-		: IAsymmetricBlockCipher
-	{
-		/**
-		 * 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.
-		 */
-		public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict";
-
-		private const int HeaderLength = 10;
-
-		/**
-		 * The same effect can be achieved by setting the static property directly
-		 * <p>
-		 * The static property is checked during construction of the encoding object, it is set to
-		 * true by default.
-		 * </p>
-		 */
-		public static bool StrictLengthEnabled
-		{
-			get { return strictLengthEnabled[0]; }
-			set { strictLengthEnabled[0] = value; }
-		}
-
-		private static readonly bool[] strictLengthEnabled;
-
-		static Pkcs1Encoding()
-		{
-			string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty);
-
-			strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")};
-		}
-
-
-		private SecureRandom			random;
-		private IAsymmetricBlockCipher	engine;
-		private bool					forEncryption;
-		private bool					forPrivateKey;
-		private bool					useStrictLength;
-
-		/**
-		 * Basic constructor.
-		 * @param cipher
-		 */
-		public Pkcs1Encoding(
-			IAsymmetricBlockCipher cipher)
-		{
-			this.engine = cipher;
-			this.useStrictLength = StrictLengthEnabled;
-		}
-
-		public IAsymmetricBlockCipher GetUnderlyingCipher()
-		{
-			return engine;
-		}
-
-		public string AlgorithmName
-		{
-			get { return engine.AlgorithmName + "/PKCS1Padding"; }
-		}
-
-		public void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			AsymmetricKeyParameter kParam;
-			if (parameters is ParametersWithRandom)
-			{
-				ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
-				this.random = rParam.Random;
-				kParam = (AsymmetricKeyParameter)rParam.Parameters;
-			}
-			else
-			{
-				this.random = new SecureRandom();
-				kParam = (AsymmetricKeyParameter)parameters;
-			}
-
-			engine.Init(forEncryption, parameters);
-
-			this.forPrivateKey = kParam.IsPrivate;
-			this.forEncryption = forEncryption;
-		}
-
-		public int GetInputBlockSize()
-		{
-			int baseBlockSize = engine.GetInputBlockSize();
-
-			return forEncryption
-				?	baseBlockSize - HeaderLength
-				:	baseBlockSize;
-		}
-
-		public int GetOutputBlockSize()
-		{
-			int baseBlockSize = engine.GetOutputBlockSize();
-
-			return forEncryption
-				?	baseBlockSize
-				:	baseBlockSize - HeaderLength;
-		}
-
-		public byte[] ProcessBlock(
-			byte[]	input,
-			int		inOff,
-			int		length)
-		{
-			return forEncryption
-				?	EncodeBlock(input, inOff, length)
-				:	DecodeBlock(input, inOff, length);
-		}
-
-		private byte[] EncodeBlock(
-			byte[]	input,
-			int		inOff,
-			int		inLen)
-		{
-	        if (inLen > GetInputBlockSize())
-	            throw new ArgumentException("input data too large", "inLen");
-
-	        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
-			Array.Copy(input, 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[]	input,
-			int		inOff,
-			int		inLen)
-		{
-			byte[] block = engine.ProcessBlock(input, 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");
-			}
-
-			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 < HeaderLength)
-			{
-				throw new InvalidCipherTextException("no data in block");
-			}
-
-			byte[] result = new byte[block.Length - start];
-
-			Array.Copy(block, start, result, 0, result.Length);
-
-			return result;
-		}
-	}
+    /**
+    * 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
+        : IAsymmetricBlockCipher
+    {
+        /**
+         * 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.
+         */
+        public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict";
+
+        private const int HeaderLength = 10;
+
+        /**
+         * The same effect can be achieved by setting the static property directly
+         * <p>
+         * The static property is checked during construction of the encoding object, it is set to
+         * true by default.
+         * </p>
+         */
+        public static bool StrictLengthEnabled
+        {
+            get { return strictLengthEnabled[0]; }
+            set { strictLengthEnabled[0] = value; }
+        }
+
+        private static readonly bool[] strictLengthEnabled;
+
+        static Pkcs1Encoding()
+        {
+            string strictProperty = Platform.GetEnvironmentVariable(StrictLengthEnabledProperty);
+
+            strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")};
+        }
+
+
+        private SecureRandom			random;
+        private IAsymmetricBlockCipher	engine;
+        private bool					forEncryption;
+        private bool					forPrivateKey;
+        private bool					useStrictLength;
+        private int                     pLen = -1;
+        private byte[]                  fallback = null;
+
+        /**
+         * Basic constructor.
+         * @param cipher
+         */
+        public Pkcs1Encoding(
+            IAsymmetricBlockCipher cipher)
+        {
+            this.engine = cipher;
+            this.useStrictLength = StrictLengthEnabled;
+        }
+
+        /**
+         * Constructor for decryption with a fixed plaintext length.
+         * 
+         * @param cipher The cipher to use for cryptographic operation.
+         * @param pLen Length of the expected plaintext.
+         */
+        public Pkcs1Encoding(IAsymmetricBlockCipher cipher, int pLen)
+        {
+            this.engine = cipher;
+            this.useStrictLength = StrictLengthEnabled;
+            this.pLen = pLen;
+        }
+
+        /**
+         * Constructor for decryption with a fixed plaintext length and a fallback
+         * value that is returned, if the padding is incorrect.
+         * 
+         * @param cipher
+         *            The cipher to use for cryptographic operation.
+         * @param fallback
+         *            The fallback value, we don't to a arraycopy here.
+         */
+        public Pkcs1Encoding(IAsymmetricBlockCipher cipher, byte[] fallback)
+        {
+            this.engine = cipher;
+            this.useStrictLength = StrictLengthEnabled;
+            this.fallback = fallback;
+            this.pLen = fallback.Length;
+        }
+
+        public IAsymmetricBlockCipher GetUnderlyingCipher()
+        {
+            return engine;
+        }
+
+        public string AlgorithmName
+        {
+            get { return engine.AlgorithmName + "/PKCS1Padding"; }
+        }
+
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            AsymmetricKeyParameter kParam;
+            if (parameters is ParametersWithRandom)
+            {
+                ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+                this.random = rParam.Random;
+                kParam = (AsymmetricKeyParameter)rParam.Parameters;
+            }
+            else
+            {
+                this.random = new SecureRandom();
+                kParam = (AsymmetricKeyParameter)parameters;
+            }
+
+            engine.Init(forEncryption, parameters);
+
+            this.forPrivateKey = kParam.IsPrivate;
+            this.forEncryption = forEncryption;
+        }
+
+        public int GetInputBlockSize()
+        {
+            int baseBlockSize = engine.GetInputBlockSize();
+
+            return forEncryption
+                ?	baseBlockSize - HeaderLength
+                :	baseBlockSize;
+        }
+
+        public int GetOutputBlockSize()
+        {
+            int baseBlockSize = engine.GetOutputBlockSize();
+
+            return forEncryption
+                ?	baseBlockSize
+                :	baseBlockSize - HeaderLength;
+        }
+
+        public byte[] ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            int		length)
+        {
+            return forEncryption
+                ?	EncodeBlock(input, inOff, length)
+                :	DecodeBlock(input, inOff, length);
+        }
+
+        private byte[] EncodeBlock(
+            byte[]	input,
+            int		inOff,
+            int		inLen)
+        {
+            if (inLen > GetInputBlockSize())
+                throw new ArgumentException("input data too large", "inLen");
+
+            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
+            Array.Copy(input, inOff, block, block.Length - inLen, inLen);
+
+            return engine.ProcessBlock(block, 0, block.Length);
+        }
+
+        /**
+         * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext
+         * for encryption.
+         * 
+         * @param encoded The Plaintext.
+         * @param pLen Expected length of the plaintext.
+         * @return Either 0, if the encoding is correct, or -1, if it is incorrect.
+         */
+        private static int CheckPkcs1Encoding(byte[] encoded, int pLen)
+        {
+            int correct = 0;
+            /*
+             * Check if the first two bytes are 0 2
+             */
+            correct |= (encoded[0] ^ 2);
+
+            /*
+             * Now the padding check, check for no 0 byte in the padding
+             */
+            int plen = encoded.Length - (
+                      pLen /* Lenght of the PMS */
+                    +  1 /* Final 0-byte before PMS */
+            );
+
+            for (int i = 1; i < plen; i++)
+            {
+                int tmp = encoded[i];
+                tmp |= tmp >> 1;
+                tmp |= tmp >> 2;
+                tmp |= tmp >> 4;
+                correct |= (tmp & 1) - 1;
+            }
+
+            /*
+             * Make sure the padding ends with a 0 byte.
+             */
+            correct |= encoded[encoded.Length - (pLen + 1)];
+
+            /*
+             * Return 0 or 1, depending on the result.
+             */
+            correct |= correct >> 1;
+            correct |= correct >> 2;
+            correct |= correct >> 4;
+            return ~((correct & 1) - 1);
+        }
+
+        /**
+         * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct.
+         * 
+         * @param in The encrypted block.
+         * @param inOff Offset in the encrypted block.
+         * @param inLen Length of the encrypted block.
+         * @param pLen Length of the desired output.
+         * @return The plaintext without padding, or a random value if the padding was incorrect.
+         * 
+         * @throws InvalidCipherTextException
+         */
+        private byte[] DecodeBlockOrRandom(byte[] input, int inOff, int inLen)
+        {
+            if (!forPrivateKey)
+                throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
+
+            byte[] block = engine.ProcessBlock(input, inOff, inLen);
+            byte[] random = null;
+            if (this.fallback == null)
+            {
+                random = new byte[this.pLen];
+                this.random.NextBytes(random);
+            }
+            else
+            {
+                random = fallback;
+            }
+
+            /*
+             * TODO: This is a potential dangerous side channel. However, you can
+             * fix this by changing the RSA engine in a way, that it will always
+             * return blocks of the same length and prepend them with 0 bytes if
+             * needed.
+             */
+            if (block.Length < GetOutputBlockSize())
+                throw new InvalidCipherTextException("block truncated");
+
+            /*
+             * TODO: Potential side channel. Fix it by making the engine always
+             * return blocks of the correct length.
+             */
+            if (useStrictLength && block.Length != engine.GetOutputBlockSize())
+                throw new InvalidCipherTextException("block incorrect size");
+
+            /*
+             * Check the padding.
+             */
+            int correct = Pkcs1Encoding.CheckPkcs1Encoding(block, this.pLen);
+
+            /*
+             * Now, to a constant time constant memory copy of the decrypted value
+             * or the random value, depending on the validity of the padding.
+             */
+            byte[] result = new byte[this.pLen];
+            for (int i = 0; i < this.pLen; i++)
+            {
+                result[i] = (byte)((block[i+(block.Length-pLen)]&(~correct)) | (random[i]&correct));
+            }
+
+            return result;
+        }
+
+        /**
+        * @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format.
+        */
+        private byte[] DecodeBlock(
+            byte[]	input,
+            int		inOff,
+            int		inLen)
+        {
+            /*
+             * If the length of the expected plaintext is known, we use a constant-time decryption.
+             * If the decryption fails, we return a random value.
+             */
+            if (this.pLen != -1)
+            {
+                return this.DecodeBlockOrRandom(input, inOff, inLen);
+            }
+
+            byte[] block = engine.ProcessBlock(input, 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");
+            }
+
+            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 < HeaderLength)
+            {
+                throw new InvalidCipherTextException("no data in block");
+            }
+
+            byte[] result = new byte[block.Length - start];
+
+            Array.Copy(block, start, result, 0, result.Length);
+
+            return result;
+        }
+    }
 
 }
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 4211a9559..0cdd868fa 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -1,525 +1,532 @@
 using System;
+using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	/**
-	* 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>
-	* <p>
-	* This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
-	* </p>
-	*/
-	public class AesEngine
-		: IBlockCipher
-	{
-		// The S box
-		private static readonly byte[] S =
-		{
-			99,	124, 119, 123, 242, 107, 111, 197,
-			48, 1, 103, 43, 254, 215, 171, 118,
-			202, 130, 201, 125, 250, 89, 71, 240,
-			173, 212, 162, 175, 156, 164, 114, 192,
-			183, 253, 147, 38, 54, 63, 247, 204,
-			52, 165, 229, 241, 113, 216, 49, 21,
-			4, 199, 35, 195, 24, 150, 5, 154,
-			7, 18, 128, 226, 235, 39, 178, 117,
-			9, 131, 44, 26, 27, 110, 90, 160,
-			82, 59, 214, 179, 41, 227, 47, 132,
-			83, 209, 0, 237, 32, 252, 177, 91,
-			106, 203, 190, 57, 74, 76, 88, 207,
-			208, 239, 170, 251, 67, 77, 51, 133,
-			69, 249, 2, 127, 80, 60, 159, 168,
-			81, 163, 64, 143, 146, 157, 56, 245,
-			188, 182, 218, 33, 16, 255, 243, 210,
-			205, 12, 19, 236, 95, 151, 68, 23,
-			196, 167, 126, 61, 100, 93, 25, 115,
-			96, 129, 79, 220, 34, 42, 144, 136,
-			70, 238, 184, 20, 222, 94, 11, 219,
-			224, 50, 58, 10, 73, 6, 36, 92,
-			194, 211, 172, 98, 145, 149, 228, 121,
-			231, 200, 55, 109, 141, 213, 78, 169,
-			108, 86, 244, 234, 101, 122, 174, 8,
-			186, 120, 37, 46, 28, 166, 180, 198,
-			232, 221, 116, 31, 75, 189, 139, 138,
-			112, 62, 181, 102, 72, 3, 246, 14,
-			97, 53, 87, 185, 134, 193, 29, 158,
-			225, 248, 152, 17, 105, 217, 142, 148,
-			155, 30, 135, 233, 206, 85, 40, 223,
-			140, 161, 137, 13, 191, 230, 66, 104,
-			65, 153, 45, 15, 176, 84, 187, 22,
-		};
-
-		// The inverse S-box
-		private static readonly byte[] Si =
-		{
-			82, 9, 106, 213, 48, 54, 165, 56,
-			191, 64, 163, 158, 129, 243, 215, 251,
-			124, 227, 57, 130, 155, 47, 255, 135,
-			52, 142, 67, 68, 196, 222, 233, 203,
-			84, 123, 148, 50, 166, 194, 35, 61,
-			238, 76, 149, 11, 66, 250, 195, 78,
-			8, 46, 161, 102, 40, 217, 36, 178,
-			118, 91, 162, 73, 109, 139, 209, 37,
-			114, 248, 246, 100, 134, 104, 152, 22,
-			212, 164, 92, 204, 93, 101, 182, 146,
-			108, 112, 72, 80, 253, 237, 185, 218,
-			94, 21, 70, 87, 167, 141, 157, 132,
-			144, 216, 171, 0, 140, 188, 211, 10,
-			247, 228, 88, 5, 184, 179, 69, 6,
-			208, 44, 30, 143, 202, 63, 15, 2,
-			193, 175, 189, 3, 1, 19, 138, 107,
-			58, 145, 17, 65, 79, 103, 220, 234,
-			151, 242, 207, 206, 240, 180, 230, 115,
-			150, 172, 116, 34, 231, 173, 53, 133,
-			226, 249, 55, 232, 28, 117, 223, 110,
-			71, 241, 26, 113, 29, 41, 197, 137,
-			111, 183, 98, 14, 170, 24, 190, 27,
-			252, 86, 62, 75, 198, 210, 121, 32,
-			154, 219, 192, 254, 120, 205, 90, 244,
-			31, 221, 168, 51, 136, 7, 199, 49,
-			177, 18, 16, 89, 39, 128, 236, 95,
-			96, 81, 127, 169, 25, 181, 74, 13,
-			45, 229, 122, 159, 147, 201, 156, 239,
-			160, 224, 59, 77, 174, 42, 245, 176,
-			200, 235, 187, 60, 131, 83, 153, 97,
-			23, 43, 4, 126, 186, 119, 214, 38,
-			225, 105, 20, 99, 85, 33, 12, 125,
-		};
-
-		// vector used in calculating key schedule (powers of x in GF(256))
-		private static readonly byte[] 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 readonly uint[] 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 readonly uint[] 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 uint Shift(
-			uint	r,
-			int		shift)
-		{
-			return (r >> shift) | (r << (32 - shift));
-		}
-
-		/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
-
-		private const uint m1 = 0x80808080;
-		private const uint m2 = 0x7f7f7f7f;
-		private const uint m3 = 0x0000001b;
-
-		private uint FFmulX(
-			uint 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 uint Inv_Mcol(
-			uint x)
-		{
-			uint f2 = FFmulX(x);
-			uint f4 = FFmulX(f2);
-			uint f8 = FFmulX(f4);
-			uint f9 = x ^ f8;
-
-			return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
-		}
-
-		private uint SubWord(
-			uint x)
-		{
-			return (uint)S[x&255]
-				| (((uint)S[(x>>8)&255]) << 8)
-				| (((uint)S[(x>>16)&255]) << 16)
-				| (((uint)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 uint[,] GenerateWorkingKey(
-			byte[]	key,
-			bool	forEncryption)
-		{
-			int KC = key.Length / 4;  // key length in words
-			int t;
-
-			if ((KC != 4) && (KC != 6) && (KC != 8)) 
-				throw new ArgumentException("Key length not 128/192/256 bits.");
-
-			ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
-			uint[,] W = new uint[ROUNDS+1, 4];   // 4 words in a block
-
-			//
-			// copy the key into the round key array
-			//
-
-			t = 0;
-			for (int i = 0; i < key.Length; t++)
-			{
-				W[t >> 2, t & 3] = Pack.LE_To_UInt32(key, i);
-				i+=4;
-			}
-
-			//
-			// while not enough round key material calculated
-			// calculate new values
-			//
-			int k = (ROUNDS + 1) << 2;
-			for (int i = KC; (i < k); i++)
-			{
-				uint 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 (int i = 0; i < 4; i++)
-					{
-						W[j, i] = Inv_Mcol(W[j, i]);
-					}
-				}
-			}
-
-			return W;
-		}
-
-		private int		ROUNDS;
-		private uint[,]	WorkingKey;
-		private uint	C0, C1, C2, C3;
-		private bool	forEncryption;
-
-		private const 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 parameters the parameters required to set up the cipher.
-		* @exception ArgumentException if the parameters argument is
-		* inappropriate.
-		*/
-		public void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			KeyParameter keyParameter = parameters as KeyParameter;
-
-			if (keyParameter == null)
-				throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
-
-			WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
-
-			this.forEncryption = forEncryption;
-		}
-
-		public string AlgorithmName
-		{
-			get { return "AES"; }
-		}
-
-		public bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
-		public int GetBlockSize()
-		{
-			return BLOCK_SIZE;
-		}
-
-		public int ProcessBlock(
-			byte[]	input,
-			int		inOff,
-			byte[]	output,
-			int		outOff)
-		{
-			if (WorkingKey == null)
-			{
-				throw new InvalidOperationException("AES engine not initialised");
-			}
-
-			if ((inOff + (32 / 2)) > input.Length)
-			{
-				throw new DataLengthException("input buffer too short");
-			}
-
-			if ((outOff + (32 / 2)) > output.Length)
-			{
-				throw new DataLengthException("output buffer too short");
-			}
-
-			UnPackBlock(input, inOff);
-
-			if (forEncryption)
-			{
-				EncryptBlock(WorkingKey);
-			}
-			else
-			{
-				DecryptBlock(WorkingKey);
-			}
-
-			PackBlock(output, outOff);
-
-			return BLOCK_SIZE;
-		}
-
-		public void Reset()
-		{
-		}
-
-		private void UnPackBlock(
-			byte[]	bytes,
-			int		off)
-		{
-			C0 = Pack.LE_To_UInt32(bytes, off);
-			C1 = Pack.LE_To_UInt32(bytes, off + 4);
-			C2 = Pack.LE_To_UInt32(bytes, off + 8);
-			C3 = Pack.LE_To_UInt32(bytes, off + 12);
-		}
-
-		private void PackBlock(
-			byte[]	bytes,
-			int		off)
-		{
-			Pack.UInt32_To_LE(C0, bytes, off);
-			Pack.UInt32_To_LE(C1, bytes, off + 4);
-			Pack.UInt32_To_LE(C2, bytes, off + 8);
-			Pack.UInt32_To_LE(C3, bytes, off + 12);
-		}
-
-		private void EncryptBlock(
-			uint[,] KW)
-		{
-			uint r, r0, r1, r2, r3;
-
-			C0 ^= KW[0, 0];
-			C1 ^= KW[0, 1];
-			C2 ^= KW[0, 2];
-			C3 ^= KW[0, 3];
-
-			for (r = 1; 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 = (uint)S[r0&255] ^ (((uint)S[(r1>>8)&255])<<8) ^ (((uint)S[(r2>>16)&255])<<16) ^ (((uint)S[(r3>>24)&255])<<24) ^ KW[r,0];
-			C1 = (uint)S[r1&255] ^ (((uint)S[(r2>>8)&255])<<8) ^ (((uint)S[(r3>>16)&255])<<16) ^ (((uint)S[(r0>>24)&255])<<24) ^ KW[r,1];
-			C2 = (uint)S[r2&255] ^ (((uint)S[(r3>>8)&255])<<8) ^ (((uint)S[(r0>>16)&255])<<16) ^ (((uint)S[(r1>>24)&255])<<24) ^ KW[r,2];
-			C3 = (uint)S[r3&255] ^ (((uint)S[(r0>>8)&255])<<8) ^ (((uint)S[(r1>>16)&255])<<16) ^ (((uint)S[(r2>>24)&255])<<24) ^ KW[r,3];
-		}
-
-		private void DecryptBlock(
-			uint[,] KW)
-		{
-			int r;
-			uint r0, r1, r2, r3;
-
-			C0 ^= KW[ROUNDS,0];
-			C1 ^= KW[ROUNDS,1];
-			C2 ^= KW[ROUNDS,2];
-			C3 ^= KW[ROUNDS,3];
-
-			for (r = ROUNDS-1; 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 = (uint)Si[r0&255] ^ (((uint)Si[(r3>>8)&255])<<8) ^ (((uint)Si[(r2>>16)&255])<<16) ^ (((uint)Si[(r1>>24)&255])<<24) ^ KW[0,0];
-			C1 = (uint)Si[r1&255] ^ (((uint)Si[(r0>>8)&255])<<8) ^ (((uint)Si[(r3>>16)&255])<<16) ^ (((uint)Si[(r2>>24)&255])<<24) ^ KW[0,1];
-			C2 = (uint)Si[r2&255] ^ (((uint)Si[(r1>>8)&255])<<8) ^ (((uint)Si[(r0>>16)&255])<<16) ^ (((uint)Si[(r3>>24)&255])<<24) ^ KW[0,2];
-			C3 = (uint)Si[r3&255] ^ (((uint)Si[(r2>>8)&255])<<8) ^ (((uint)Si[(r1>>16)&255])<<16) ^ (((uint)Si[(r0>>24)&255])<<24) ^ KW[0,3];
-		}
-	}
+    /**
+    * 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>
+    * <p>
+    * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
+    * </p>
+    */
+    public class AesEngine
+        : IBlockCipher
+    {
+        // The S box
+        private static readonly byte[] S =
+        {
+            99,	124, 119, 123, 242, 107, 111, 197,
+            48, 1, 103, 43, 254, 215, 171, 118,
+            202, 130, 201, 125, 250, 89, 71, 240,
+            173, 212, 162, 175, 156, 164, 114, 192,
+            183, 253, 147, 38, 54, 63, 247, 204,
+            52, 165, 229, 241, 113, 216, 49, 21,
+            4, 199, 35, 195, 24, 150, 5, 154,
+            7, 18, 128, 226, 235, 39, 178, 117,
+            9, 131, 44, 26, 27, 110, 90, 160,
+            82, 59, 214, 179, 41, 227, 47, 132,
+            83, 209, 0, 237, 32, 252, 177, 91,
+            106, 203, 190, 57, 74, 76, 88, 207,
+            208, 239, 170, 251, 67, 77, 51, 133,
+            69, 249, 2, 127, 80, 60, 159, 168,
+            81, 163, 64, 143, 146, 157, 56, 245,
+            188, 182, 218, 33, 16, 255, 243, 210,
+            205, 12, 19, 236, 95, 151, 68, 23,
+            196, 167, 126, 61, 100, 93, 25, 115,
+            96, 129, 79, 220, 34, 42, 144, 136,
+            70, 238, 184, 20, 222, 94, 11, 219,
+            224, 50, 58, 10, 73, 6, 36, 92,
+            194, 211, 172, 98, 145, 149, 228, 121,
+            231, 200, 55, 109, 141, 213, 78, 169,
+            108, 86, 244, 234, 101, 122, 174, 8,
+            186, 120, 37, 46, 28, 166, 180, 198,
+            232, 221, 116, 31, 75, 189, 139, 138,
+            112, 62, 181, 102, 72, 3, 246, 14,
+            97, 53, 87, 185, 134, 193, 29, 158,
+            225, 248, 152, 17, 105, 217, 142, 148,
+            155, 30, 135, 233, 206, 85, 40, 223,
+            140, 161, 137, 13, 191, 230, 66, 104,
+            65, 153, 45, 15, 176, 84, 187, 22,
+        };
+
+        // The inverse S-box
+        private static readonly byte[] Si =
+        {
+            82, 9, 106, 213, 48, 54, 165, 56,
+            191, 64, 163, 158, 129, 243, 215, 251,
+            124, 227, 57, 130, 155, 47, 255, 135,
+            52, 142, 67, 68, 196, 222, 233, 203,
+            84, 123, 148, 50, 166, 194, 35, 61,
+            238, 76, 149, 11, 66, 250, 195, 78,
+            8, 46, 161, 102, 40, 217, 36, 178,
+            118, 91, 162, 73, 109, 139, 209, 37,
+            114, 248, 246, 100, 134, 104, 152, 22,
+            212, 164, 92, 204, 93, 101, 182, 146,
+            108, 112, 72, 80, 253, 237, 185, 218,
+            94, 21, 70, 87, 167, 141, 157, 132,
+            144, 216, 171, 0, 140, 188, 211, 10,
+            247, 228, 88, 5, 184, 179, 69, 6,
+            208, 44, 30, 143, 202, 63, 15, 2,
+            193, 175, 189, 3, 1, 19, 138, 107,
+            58, 145, 17, 65, 79, 103, 220, 234,
+            151, 242, 207, 206, 240, 180, 230, 115,
+            150, 172, 116, 34, 231, 173, 53, 133,
+            226, 249, 55, 232, 28, 117, 223, 110,
+            71, 241, 26, 113, 29, 41, 197, 137,
+            111, 183, 98, 14, 170, 24, 190, 27,
+            252, 86, 62, 75, 198, 210, 121, 32,
+            154, 219, 192, 254, 120, 205, 90, 244,
+            31, 221, 168, 51, 136, 7, 199, 49,
+            177, 18, 16, 89, 39, 128, 236, 95,
+            96, 81, 127, 169, 25, 181, 74, 13,
+            45, 229, 122, 159, 147, 201, 156, 239,
+            160, 224, 59, 77, 174, 42, 245, 176,
+            200, 235, 187, 60, 131, 83, 153, 97,
+            23, 43, 4, 126, 186, 119, 214, 38,
+            225, 105, 20, 99, 85, 33, 12, 125,
+        };
+
+        // vector used in calculating key schedule (powers of x in GF(256))
+        private static readonly byte[] 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 readonly uint[] 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 readonly uint[] 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 uint Shift(uint r, int shift)
+        {
+            return (r >> shift) | (r << (32 - shift));
+        }
+
+        /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+        private const uint m1 = 0x80808080;
+        private const uint m2 = 0x7f7f7f7f;
+        private const uint m3 = 0x0000001b;
+
+        private static uint FFmulX(uint 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 static uint Inv_Mcol(uint x)
+        {
+            uint f2 = FFmulX(x);
+            uint f4 = FFmulX(f2);
+            uint f8 = FFmulX(f4);
+            uint f9 = x ^ f8;
+
+            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+        }
+
+        private static uint SubWord(uint x)
+        {
+            return (uint)S[x&255]
+                | (((uint)S[(x>>8)&255]) << 8)
+                | (((uint)S[(x>>16)&255]) << 16)
+                | (((uint)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 uint[][] GenerateWorkingKey(
+            byte[]	key,
+            bool	forEncryption)
+        {
+            int KC = key.Length / 4;  // key length in words
+            int t;
+
+            if ((KC != 4) && (KC != 6) && (KC != 8)) 
+                throw new ArgumentException("Key length not 128/192/256 bits.");
+
+            ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+
+            uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
+            for (int i = 0; i <= ROUNDS; ++i)
+            {
+                W[i] = new uint[4];
+            }
+
+            //
+            // copy the key into the round key array
+            //
+
+            t = 0;
+            for (int i = 0; i < key.Length; t++)
+            {
+                W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
+                i+=4;
+            }
+
+            //
+            // while not enough round key material calculated
+            // calculate new values
+            //
+            int k = (ROUNDS + 1) << 2;
+            for (int i = KC; (i < k); i++)
+            {
+                uint 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++)
+                {
+                    uint[] w = W[j];
+                    for (int i = 0; i < 4; i++)
+                    {
+                        w[i] = Inv_Mcol(w[i]);
+                    }
+                }
+            }
+
+            return W;
+        }
+
+        private int ROUNDS;
+        private uint[][] WorkingKey;
+        private uint C0, C1, C2, C3;
+        private bool forEncryption;
+
+        private const 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 parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            KeyParameter keyParameter = parameters as KeyParameter;
+
+            if (keyParameter == null)
+                throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+
+            WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+            this.forEncryption = forEncryption;
+        }
+
+        public string AlgorithmName
+        {
+            get { return "AES"; }
+        }
+
+        public bool IsPartialBlockOkay
+        {
+            get { return false; }
+        }
+
+        public int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (WorkingKey == null)
+            {
+                throw new InvalidOperationException("AES engine not initialised");
+            }
+
+            if ((inOff + (32 / 2)) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + (32 / 2)) > output.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            UnPackBlock(input, inOff);
+
+            if (forEncryption)
+            {
+                EncryptBlock(WorkingKey);
+            }
+            else
+            {
+                DecryptBlock(WorkingKey);
+            }
+
+            PackBlock(output, outOff);
+
+            return BLOCK_SIZE;
+        }
+
+        public void Reset()
+        {
+        }
+
+        private void UnPackBlock(
+            byte[]	bytes,
+            int		off)
+        {
+            C0 = Pack.LE_To_UInt32(bytes, off);
+            C1 = Pack.LE_To_UInt32(bytes, off + 4);
+            C2 = Pack.LE_To_UInt32(bytes, off + 8);
+            C3 = Pack.LE_To_UInt32(bytes, off + 12);
+        }
+
+        private void PackBlock(
+            byte[]	bytes,
+            int		off)
+        {
+            Pack.UInt32_To_LE(C0, bytes, off);
+            Pack.UInt32_To_LE(C1, bytes, off + 4);
+            Pack.UInt32_To_LE(C2, bytes, off + 8);
+            Pack.UInt32_To_LE(C3, bytes, off + 12);
+        }
+
+        private void EncryptBlock(uint[][] KW)
+        {
+            uint[] kw = KW[0];
+            uint t0 = this.C0 ^ kw[0];
+            uint t1 = this.C1 ^ kw[1];
+            uint t2 = this.C2 ^ kw[2];
+
+            uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+            int r = 1;
+            while (r < ROUNDS - 1)
+            {
+                kw = KW[r++];
+                r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+                r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
+                r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
+                r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
+                kw = KW[r++];
+                t0 = T0[r0 & 255] ^ Shift(T0[(r1 >> 8) & 255], 24) ^ Shift(T0[(r2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+                t1 = T0[r1 & 255] ^ Shift(T0[(r2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(r0 >> 24) & 255], 8) ^ kw[1];
+                t2 = T0[r2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(r0 >> 16) & 255], 16) ^ Shift(T0[(r1 >> 24) & 255], 8) ^ kw[2];
+                r3 = T0[r3 & 255] ^ Shift(T0[(r0 >> 8) & 255], 24) ^ Shift(T0[(r1 >> 16) & 255], 16) ^ Shift(T0[(r2 >> 24) & 255], 8) ^ kw[3];
+            }
+
+            kw = KW[r++];
+            r0 = T0[t0 & 255] ^ Shift(T0[(t1 >> 8) & 255], 24) ^ Shift(T0[(t2 >> 16) & 255], 16) ^ Shift(T0[(r3 >> 24) & 255], 8) ^ kw[0];
+            r1 = T0[t1 & 255] ^ Shift(T0[(t2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ Shift(T0[(t0 >> 24) & 255], 8) ^ kw[1];
+            r2 = T0[t2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(t0 >> 16) & 255], 16) ^ Shift(T0[(t1 >> 24) & 255], 8) ^ kw[2];
+            r3 = T0[r3 & 255] ^ Shift(T0[(t0 >> 8) & 255], 24) ^ Shift(T0[(t1 >> 16) & 255], 16) ^ Shift(T0[(t2 >> 24) & 255], 8) ^ kw[3];
+
+            // the final round's table is a simple function of S so we don't use a whole other four tables for it
+
+            kw = KW[r];
+            this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
+            this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
+            this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
+            this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
+        }
+
+        private void DecryptBlock(uint[][] KW)
+        {
+            uint[] kw = KW[ROUNDS];
+            uint t0 = this.C0 ^ kw[0];
+            uint t1 = this.C1 ^ kw[1];
+            uint t2 = this.C2 ^ kw[2];
+
+            uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+            int r = ROUNDS - 1;
+            while (r > 1)
+            {
+                kw = KW[r--];
+                r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
+                r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
+                r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+                r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
+                kw = KW[r--];
+                t0 = Tinv0[r0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(r2 >> 16) & 255], 16) ^ Shift(Tinv0[(r1 >> 24) & 255], 8) ^ kw[0];
+                t1 = Tinv0[r1 & 255] ^ Shift(Tinv0[(r0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(r2 >> 24) & 255], 8) ^ kw[1];
+                t2 = Tinv0[r2 & 255] ^ Shift(Tinv0[(r1 >> 8) & 255], 24) ^ Shift(Tinv0[(r0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+                r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(r2 >> 8) & 255], 24) ^ Shift(Tinv0[(r1 >> 16) & 255], 16) ^ Shift(Tinv0[(r0 >> 24) & 255], 8) ^ kw[3];
+            }
+
+            kw = KW[1];
+            r0 = Tinv0[t0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(t2 >> 16) & 255], 16) ^ Shift(Tinv0[(t1 >> 24) & 255], 8) ^ kw[0];
+            r1 = Tinv0[t1 & 255] ^ Shift(Tinv0[(t0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ Shift(Tinv0[(t2 >> 24) & 255], 8) ^ kw[1];
+            r2 = Tinv0[t2 & 255] ^ Shift(Tinv0[(t1 >> 8) & 255], 24) ^ Shift(Tinv0[(t0 >> 16) & 255], 16) ^ Shift(Tinv0[(r3 >> 24) & 255], 8) ^ kw[2];
+            r3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(t2 >> 8) & 255], 24) ^ Shift(Tinv0[(t1 >> 16) & 255], 16) ^ Shift(Tinv0[(t0 >> 24) & 255], 8) ^ kw[3];
+
+            // the final round's table is a simple function of Si so we don't use a whole other four tables for it
+
+            kw = KW[0];
+            this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
+            this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
+            this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
+            this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
+        }
+    }
 }
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index 603b5ce4d..38d3a5841 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
@@ -30,11 +31,11 @@ namespace Org.BouncyCastle.Crypto.Engines
     * </p>
     */
     public class AesFastEngine
-		: IBlockCipher
+        : IBlockCipher
     {
         // The S box
         private static readonly byte[] S =
-		{
+        {
             99, 124, 119, 123, 242, 107, 111, 197,
             48,   1, 103,  43, 254, 215, 171, 118,
             202, 130, 201, 125, 250,  89,  71, 240,
@@ -71,503 +72,501 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         // The inverse S-box
         private static readonly byte[] Si =
-		{
-			82,   9, 106, 213,  48,  54, 165,  56,
-			191,  64, 163, 158, 129, 243, 215, 251,
-			124, 227,  57, 130, 155,  47, 255, 135,
-			52, 142,  67,  68, 196, 222, 233, 203,
-			84, 123, 148,  50, 166, 194,  35,  61,
-			238,  76, 149,  11,  66, 250, 195,  78,
-			8,  46, 161, 102,  40, 217,  36, 178,
-			118,  91, 162,  73, 109, 139, 209,  37,
-			114, 248, 246, 100, 134, 104, 152,  22,
-			212, 164,  92, 204,  93, 101, 182, 146,
-			108, 112,  72,  80, 253, 237, 185, 218,
-			94,  21,  70,  87, 167, 141, 157, 132,
-			144, 216, 171,   0, 140, 188, 211,  10,
-			247, 228,  88,   5, 184, 179,  69,   6,
-			208,  44,  30, 143, 202,  63,  15,   2,
-			193, 175, 189,   3,   1,  19, 138, 107,
-			58, 145,  17,  65,  79, 103, 220, 234,
-			151, 242, 207, 206, 240, 180, 230, 115,
-			150, 172, 116,  34, 231, 173,  53, 133,
-			226, 249,  55, 232,  28, 117, 223, 110,
-			71, 241,  26, 113,  29,  41, 197, 137,
-			111, 183,  98,  14, 170,  24, 190,  27,
-			252,  86,  62,  75, 198, 210, 121,  32,
-			154, 219, 192, 254, 120, 205,  90, 244,
-			31, 221, 168,  51, 136,   7, 199,  49,
-			177,  18,  16,  89,  39, 128, 236,  95,
-			96,  81, 127, 169,  25, 181,  74,  13,
-			45, 229, 122, 159, 147, 201, 156, 239,
-			160, 224,  59,  77, 174,  42, 245, 176,
-			200, 235, 187,  60, 131,  83, 153,  97,
-			23,  43,   4, 126, 186, 119, 214,  38,
-			225, 105,  20,  99,  85,  33,  12, 125,
-		};
-
-		// vector used in calculating key schedule (powers of x in GF(256))
+        {
+            82,   9, 106, 213,  48,  54, 165,  56,
+            191,  64, 163, 158, 129, 243, 215, 251,
+            124, 227,  57, 130, 155,  47, 255, 135,
+            52, 142,  67,  68, 196, 222, 233, 203,
+            84, 123, 148,  50, 166, 194,  35,  61,
+            238,  76, 149,  11,  66, 250, 195,  78,
+            8,  46, 161, 102,  40, 217,  36, 178,
+            118,  91, 162,  73, 109, 139, 209,  37,
+            114, 248, 246, 100, 134, 104, 152,  22,
+            212, 164,  92, 204,  93, 101, 182, 146,
+            108, 112,  72,  80, 253, 237, 185, 218,
+            94,  21,  70,  87, 167, 141, 157, 132,
+            144, 216, 171,   0, 140, 188, 211,  10,
+            247, 228,  88,   5, 184, 179,  69,   6,
+            208,  44,  30, 143, 202,  63,  15,   2,
+            193, 175, 189,   3,   1,  19, 138, 107,
+            58, 145,  17,  65,  79, 103, 220, 234,
+            151, 242, 207, 206, 240, 180, 230, 115,
+            150, 172, 116,  34, 231, 173,  53, 133,
+            226, 249,  55, 232,  28, 117, 223, 110,
+            71, 241,  26, 113,  29,  41, 197, 137,
+            111, 183,  98,  14, 170,  24, 190,  27,
+            252,  86,  62,  75, 198, 210, 121,  32,
+            154, 219, 192, 254, 120, 205,  90, 244,
+            31, 221, 168,  51, 136,   7, 199,  49,
+            177,  18,  16,  89,  39, 128, 236,  95,
+            96,  81, 127, 169,  25, 181,  74,  13,
+            45, 229, 122, 159, 147, 201, 156, 239,
+            160, 224,  59,  77, 174,  42, 245, 176,
+            200, 235, 187,  60, 131,  83, 153,  97,
+            23,  43,   4, 126, 186, 119, 214,  38,
+            225, 105,  20,  99,  85,  33,  12, 125,
+        };
+
+        // vector used in calculating key schedule (powers of x in GF(256))
         private static readonly byte[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 uint Shift(
-            uint	r,
-            int		shift)
-		{
-			return (r >> shift) | (r << (32 - shift));
-		}
+        {
+            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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 static uint Shift(uint r, int shift)
+        {
+            return (r >> shift) | (r << (32 - shift));
+        }
 
         /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
 
@@ -575,10 +574,9 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const uint m2 = 0x7f7f7f7f;
         private const uint m3 = 0x0000001b;
 
-		private uint FFmulX(
-			uint x)
-		{
-			return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
+        private static uint FFmulX(uint x)
+        {
+            return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
         }
 
         /*
@@ -591,8 +589,8 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         */
 
-        private uint Inv_Mcol(
-			uint x) {
+        private static uint Inv_Mcol(uint x)
+        {
             uint f2 = FFmulX(x);
             uint f4 = FFmulX(f2);
             uint f8 = FFmulX(f4);
@@ -601,13 +599,12 @@ namespace Org.BouncyCastle.Crypto.Engines
             return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
         }
 
-		private uint SubWord(
-			uint x)
-		{
-			return (uint)S[x&255]
-				| (((uint)S[(x>>8)&255]) << 8)
-				| (((uint)S[(x>>16)&255]) << 16)
-				| (((uint)S[(x>>24)&255]) << 24);
+        private static uint SubWord(uint x)
+        {
+            return (uint)S[x&255]
+                | (((uint)S[(x>>8)&255]) << 8)
+                | (((uint)S[(x>>16)&255]) << 16)
+                | (((uint)S[(x>>24)&255]) << 24);
         }
 
         /**
@@ -616,7 +613,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * 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 uint[,] GenerateWorkingKey(
+        private uint[][] GenerateWorkingKey(
             byte[]	key,
             bool	forEncryption)
         {
@@ -625,8 +622,13 @@ namespace Org.BouncyCastle.Crypto.Engines
             if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length))
                 throw new ArgumentException("Key length not 128/192/256 bits.");
 
-			ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
-            uint[,] W = new uint[ROUNDS+1,4];   // 4 words in a block
+            ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+
+            uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
+            for (int i = 0; i <= ROUNDS; ++i)
+            {
+                W[i] = new uint[4];
+            }
 
             //
             // copy the key into the round key array
@@ -634,10 +636,10 @@ namespace Org.BouncyCastle.Crypto.Engines
 
             int t = 0;
             for (int i = 0; i < key.Length; t++)
-			{
-				W[t >> 2,t & 3] = Pack.LE_To_UInt32(key, i);
-				i+=4;
-			}
+            {
+                W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
+                i+=4;
+            }
 
             //
             // while not enough round key material calculated
@@ -646,23 +648,24 @@ namespace Org.BouncyCastle.Crypto.Engines
             int k = (ROUNDS + 1) << 2;
             for (int i = KC; (i < k); i++)
             {
-                uint temp = W[(i-1)>>2,(i-1)&3];
+                uint 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;
+                W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
             }
 
             if (!forEncryption)
-			{
+            {
                 for (int j = 1; j < ROUNDS; j++)
-				{
+                {
+                    uint[] w = W[j];
                     for (int i = 0; i < 4; i++)
-					{
-                        W[j,i] = Inv_Mcol(W[j,i]);
+                    {
+                        w[i] = Inv_Mcol(w[i]);
                     }
                 }
             }
@@ -670,10 +673,10 @@ namespace Org.BouncyCastle.Crypto.Engines
             return W;
         }
 
-        private int		ROUNDS;
-        private uint[,]	WorkingKey;
-        private uint	C0, C1, C2, C3;
-        private bool	forEncryption;
+        private int ROUNDS;
+        private uint[][] WorkingKey;
+        private uint C0, C1, C2, C3;
+        private bool forEncryption;
 
         private const int BLOCK_SIZE = 16;
 
@@ -696,24 +699,27 @@ namespace Org.BouncyCastle.Crypto.Engines
             bool				forEncryption,
             ICipherParameters	parameters)
         {
-            if (!(parameters is KeyParameter))
-				throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString());
+            KeyParameter keyParameter = parameters as KeyParameter;
 
-			WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption);
-			this.forEncryption = forEncryption;
+            if (keyParameter == null)
+                throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+
+            WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+            this.forEncryption = forEncryption;
         }
 
-		public string AlgorithmName
+        public string AlgorithmName
         {
             get { return "AES"; }
         }
 
-		public bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
+        public bool IsPartialBlockOkay
+        {
+            get { return false; }
+        }
 
-		public int GetBlockSize()
+        public int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
@@ -752,7 +758,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
             PackBlock(output, outOff);
 
-			return BLOCK_SIZE;
+            return BLOCK_SIZE;
         }
 
         public void Reset()
@@ -763,91 +769,96 @@ namespace Org.BouncyCastle.Crypto.Engines
             byte[]	bytes,
             int		off)
         {
-			C0 = Pack.LE_To_UInt32(bytes, off);
-			C1 = Pack.LE_To_UInt32(bytes, off + 4);
-			C2 = Pack.LE_To_UInt32(bytes, off + 8);
-			C3 = Pack.LE_To_UInt32(bytes, off + 12);
+            C0 = Pack.LE_To_UInt32(bytes, off);
+            C1 = Pack.LE_To_UInt32(bytes, off + 4);
+            C2 = Pack.LE_To_UInt32(bytes, off + 8);
+            C3 = Pack.LE_To_UInt32(bytes, off + 12);
         }
 
-		private void PackBlock(
+        private void PackBlock(
             byte[]	bytes,
             int		off)
         {
-			Pack.UInt32_To_LE(C0, bytes, off);
-			Pack.UInt32_To_LE(C1, bytes, off + 4);
-			Pack.UInt32_To_LE(C2, bytes, off + 8);
-			Pack.UInt32_To_LE(C3, bytes, off + 12);
+            Pack.UInt32_To_LE(C0, bytes, off);
+            Pack.UInt32_To_LE(C1, bytes, off + 4);
+            Pack.UInt32_To_LE(C2, bytes, off + 8);
+            Pack.UInt32_To_LE(C3, bytes, off + 12);
         }
 
-		private void EncryptBlock(
-			uint[,] KW)
+        private void EncryptBlock(uint[][] KW)
         {
-            int r;
-			uint r0, r1, r2, r3;
-
-            C0 ^= KW[0,0];
-            C1 ^= KW[0,1];
-            C2 ^= KW[0,2];
-            C3 ^= KW[0,3];
-
-            for (r = 1; r < ROUNDS - 1;)
-			{
-                r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[C3>>24] ^ KW[r,0];
-                r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[C0>>24] ^ KW[r,1];
-                r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[C1>>24] ^ KW[r,2];
-                r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[C2>>24] ^ KW[r++,3];
-                C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[r3>>24] ^ KW[r,0];
-                C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[r0>>24] ^ KW[r,1];
-                C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[r1>>24] ^ KW[r,2];
-                C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[r2>>24] ^ KW[r++,3];
+            uint[] kw = KW[0];
+            uint t0 = this.C0 ^ kw[0];
+            uint t1 = this.C1 ^ kw[1];
+            uint t2 = this.C2 ^ kw[2];
+
+            uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+            int r = 1;
+            while (r < ROUNDS - 1)
+            {
+                kw = KW[r++];
+                r0 = T0[t0 & 255] ^ T1[(t1 >> 8) & 255] ^ T2[(t2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+                r1 = T0[t1 & 255] ^ T1[(t2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[t0 >> 24] ^ kw[1];
+                r2 = T0[t2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(t0 >> 16) & 255] ^ T3[t1 >> 24] ^ kw[2];
+                r3 = T0[r3 & 255] ^ T1[(t0 >> 8) & 255] ^ T2[(t1 >> 16) & 255] ^ T3[t2 >> 24] ^ kw[3];
+                kw = KW[r++];
+                t0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+                t1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ kw[1];
+                t2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ kw[2];
+                r3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ kw[3];
             }
 
-            r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[C3>>24] ^ KW[r,0];
-            r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[C0>>24] ^ KW[r,1];
-            r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[C1>>24] ^ KW[r,2];
-            r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[C2>>24] ^ KW[r++,3];
+            kw = KW[r++];
+            r0 = T0[t0 & 255] ^ T1[(t1 >> 8) & 255] ^ T2[(t2 >> 16) & 255] ^ T3[r3 >> 24] ^ kw[0];
+            r1 = T0[t1 & 255] ^ T1[(t2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[t0 >> 24] ^ kw[1];
+            r2 = T0[t2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(t0 >> 16) & 255] ^ T3[t1 >> 24] ^ kw[2];
+            r3 = T0[r3 & 255] ^ T1[(t0 >> 8) & 255] ^ T2[(t1 >> 16) & 255] ^ T3[t2 >> 24] ^ kw[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 = (uint)S[r0&255] ^ (((uint)S[(r1>>8)&255])<<8) ^ (((uint)S[(r2>>16)&255])<<16) ^ (((uint)S[r3>>24])<<24) ^ KW[r,0];
-			C1 = (uint)S[r1&255] ^ (((uint)S[(r2>>8)&255])<<8) ^ (((uint)S[(r3>>16)&255])<<16) ^ (((uint)S[r0>>24])<<24) ^ KW[r,1];
-			C2 = (uint)S[r2&255] ^ (((uint)S[(r3>>8)&255])<<8) ^ (((uint)S[(r0>>16)&255])<<16) ^ (((uint)S[r1>>24])<<24) ^ KW[r,2];
-			C3 = (uint)S[r3&255] ^ (((uint)S[(r0>>8)&255])<<8) ^ (((uint)S[(r1>>16)&255])<<16) ^ (((uint)S[r2>>24])<<24) ^ KW[r,3];
-		}
+            kw = KW[r];
+            this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ kw[0];
+            this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ kw[1];
+            this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ kw[2];
+            this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ kw[3];
+        }
 
-        private  void DecryptBlock(
-			uint[,] KW)
+        private void DecryptBlock(uint[][] KW)
         {
-            int r;
-			uint r0, r1, r2, r3;
-
-            C0 ^= KW[ROUNDS,0];
-            C1 ^= KW[ROUNDS,1];
-            C2 ^= KW[ROUNDS,2];
-            C3 ^= KW[ROUNDS,3];
-
-            for (r = ROUNDS-1; r>1;) {
-                r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[C1>>24] ^ KW[r,0];
-                r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[C2>>24] ^ KW[r,1];
-                r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[C3>>24] ^ KW[r,2];
-                r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[C0>>24] ^ KW[r--,3];
-                C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[r1>>24] ^ KW[r,0];
-                C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[r2>>24] ^ KW[r,1];
-                C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[r3>>24] ^ KW[r,2];
-                C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[r0>>24] ^ KW[r--,3];
+            uint[] kw = KW[ROUNDS];
+            uint t0 = this.C0 ^ kw[0];
+            uint t1 = this.C1 ^ kw[1];
+            uint t2 = this.C2 ^ kw[2];
+
+            uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+            int r = ROUNDS - 1;
+            while (r > 1)
+            {
+                kw = KW[r--];
+                r0 = Tinv0[t0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(t2 >> 16) & 255] ^ Tinv3[t1 >> 24] ^ kw[0];
+                r1 = Tinv0[t1 & 255] ^ Tinv1[(t0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[t2 >> 24] ^ kw[1];
+                r2 = Tinv0[t2 & 255] ^ Tinv1[(t1 >> 8) & 255] ^ Tinv2[(t0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+                r3 = Tinv0[r3 & 255] ^ Tinv1[(t2 >> 8) & 255] ^ Tinv2[(t1 >> 16) & 255] ^ Tinv3[t0 >> 24] ^ kw[3];
+                kw = KW[r--];
+                t0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ kw[0];
+                t1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ kw[1];
+                t2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+                r3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ kw[3];
             }
 
-            r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[C1>>24] ^ KW[r,0];
-            r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[C2>>24] ^ KW[r,1];
-            r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[C3>>24] ^ KW[r,2];
-            r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[C0>>24] ^ KW[r,3];
+            kw = KW[1];
+            r0 = Tinv0[t0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(t2 >> 16) & 255] ^ Tinv3[t1 >> 24] ^ kw[0];
+            r1 = Tinv0[t1 & 255] ^ Tinv1[(t0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[t2 >> 24] ^ kw[1];
+            r2 = Tinv0[t2 & 255] ^ Tinv1[(t1 >> 8) & 255] ^ Tinv2[(t0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ kw[2];
+            r3 = Tinv0[r3 & 255] ^ Tinv1[(t2 >> 8) & 255] ^ Tinv2[(t1 >> 16) & 255] ^ Tinv3[t0 >> 24] ^ kw[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 = (uint)Si[r0&255] ^ (((uint)Si[(r3>>8)&255])<<8) ^ (((uint)Si[(r2>>16)&255])<<16) ^ (((uint)Si[r1>>24])<<24) ^ KW[0,0];
-			C1 = (uint)Si[r1&255] ^ (((uint)Si[(r0>>8)&255])<<8) ^ (((uint)Si[(r3>>16)&255])<<16) ^ (((uint)Si[r2>>24])<<24) ^ KW[0,1];
-			C2 = (uint)Si[r2&255] ^ (((uint)Si[(r1>>8)&255])<<8) ^ (((uint)Si[(r0>>16)&255])<<16) ^ (((uint)Si[r3>>24])<<24) ^ KW[0,2];
-			C3 = (uint)Si[r3&255] ^ (((uint)Si[(r2>>8)&255])<<8) ^ (((uint)Si[(r1>>16)&255])<<16) ^ (((uint)Si[r0>>24])<<24) ^ KW[0,3];
-		}
+            kw = KW[0];
+            this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ kw[0];
+            this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ kw[1];
+            this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ kw[2];
+            this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ kw[3];
+        }
     }
 }
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index 2c495578d..54f2d2e88 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -1,419 +1,427 @@
 using System;
+using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	/**
-	* 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>
-	* <p>
-	* This file contains the slowest performance version with no static tables
-	* for round precomputation, but it has the smallest foot print.
-	* </p>
-	*/
-	public class AesLightEngine
-		: IBlockCipher
-	{
-		// The S box
-		private static readonly byte[] S =
-		{
-			99, 124, 119, 123, 242, 107, 111, 197,
-			48,   1, 103,  43, 254, 215, 171, 118,
-			202, 130, 201, 125, 250,  89,  71, 240,
-			173, 212, 162, 175, 156, 164, 114, 192,
-			183, 253, 147,  38,  54,  63, 247, 204,
-			52, 165, 229, 241, 113, 216,  49,  21,
-			4, 199,  35, 195,  24, 150,   5, 154,
-			7,  18, 128, 226, 235,  39, 178, 117,
-			9, 131,  44,  26,  27, 110,  90, 160,
-			82,  59, 214, 179,  41, 227,  47, 132,
-			83, 209,   0, 237,  32, 252, 177,  91,
-			106, 203, 190,  57,  74,  76,  88, 207,
-			208, 239, 170, 251,  67,  77,  51, 133,
-			69, 249,   2, 127,  80,  60, 159, 168,
-			81, 163,  64, 143, 146, 157,  56, 245,
-			188, 182, 218,  33,  16, 255, 243, 210,
-			205,  12,  19, 236,  95, 151,  68,  23,
-			196, 167, 126,  61, 100,  93,  25, 115,
-			96, 129,  79, 220,  34,  42, 144, 136,
-			70, 238, 184,  20, 222,  94,  11, 219,
-			224,  50,  58,  10,  73,   6,  36,  92,
-			194, 211, 172,  98, 145, 149, 228, 121,
-			231, 200,  55, 109, 141, 213,  78, 169,
-			108,  86, 244, 234, 101, 122, 174,   8,
-			186, 120,  37,  46,  28, 166, 180, 198,
-			232, 221, 116,  31,  75, 189, 139, 138,
-			112,  62, 181, 102,  72,   3, 246,  14,
-			97,  53,  87, 185, 134, 193,  29, 158,
-			225, 248, 152,  17, 105, 217, 142, 148,
-			155,  30, 135, 233, 206,  85,  40, 223,
-			140, 161, 137,  13, 191, 230,  66, 104,
-			65, 153,  45,  15, 176,  84, 187,  22,
-		};
-
-		// The inverse S-box
-		private static readonly byte[] Si =
-		{
-			82,   9, 106, 213,  48,  54, 165,  56,
-			191,  64, 163, 158, 129, 243, 215, 251,
-			124, 227,  57, 130, 155,  47, 255, 135,
-			52, 142,  67,  68, 196, 222, 233, 203,
-			84, 123, 148,  50, 166, 194,  35,  61,
-			238,  76, 149,  11,  66, 250, 195,  78,
-			8,  46, 161, 102,  40, 217,  36, 178,
-			118,  91, 162,  73, 109, 139, 209,  37,
-			114, 248, 246, 100, 134, 104, 152,  22,
-			212, 164,  92, 204,  93, 101, 182, 146,
-			108, 112,  72,  80, 253, 237, 185, 218,
-			94,  21,  70,  87, 167, 141, 157, 132,
-			144, 216, 171,   0, 140, 188, 211,  10,
-			247, 228,  88,   5, 184, 179,  69,   6,
-			208,  44,  30, 143, 202,  63,  15,   2,
-			193, 175, 189,   3,   1,  19, 138, 107,
-			58, 145,  17,  65,  79, 103, 220, 234,
-			151, 242, 207, 206, 240, 180, 230, 115,
-			150, 172, 116,  34, 231, 173,  53, 133,
-			226, 249,  55, 232,  28, 117, 223, 110,
-			71, 241,  26, 113,  29,  41, 197, 137,
-			111, 183,  98,  14, 170,  24, 190,  27,
-			252,  86,  62,  75, 198, 210, 121,  32,
-			154, 219, 192, 254, 120, 205,  90, 244,
-			31, 221, 168,  51, 136,   7, 199,  49,
-			177,  18,  16,  89,  39, 128, 236,  95,
-			96,  81, 127, 169,  25, 181,  74,  13,
-			45, 229, 122, 159, 147, 201, 156, 239,
-			160, 224,  59,  77, 174,  42, 245, 176,
-			200, 235, 187,  60, 131,  83, 153,  97,
-			23,  43,   4, 126, 186, 119, 214,  38,
-			225, 105,  20,  99,  85,  33,  12, 125,
-		};
-
-		// vector used in calculating key schedule (powers of x in GF(256))
-		private static readonly byte[] 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
-		};
-
-		private uint Shift(
-			uint	r,
-			int		shift)
-		{
-			return (r >> shift) | (r << (32 - shift));
-		}
-
-		/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
-
-		private const uint m1 = 0x80808080;
-		private const uint m2 = 0x7f7f7f7f;
-		private const uint m3 = 0x0000001b;
-
-		private uint FFmulX(
-			uint 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 uint Mcol(
-			uint x)
-		{
-			uint f2 = FFmulX(x);
-			return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24);
-		}
-
-		private uint Inv_Mcol(
-			uint x)
-		{
-			uint f2 = FFmulX(x);
-			uint f4 = FFmulX(f2);
-			uint f8 = FFmulX(f4);
-			uint f9 = x ^ f8;
-
-			return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
-		}
-
-		private uint SubWord(
-			uint x)
-		{
-			return (uint)S[x&255]
-				| (((uint)S[(x>>8)&255]) << 8)
-				| (((uint)S[(x>>16)&255]) << 16)
-				| (((uint)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 uint[,] GenerateWorkingKey(
-			byte[]	key,
-			bool	forEncryption)
-		{
-			int KC = key.Length / 4;  // key length in words
-			int t;
-
-			if ((KC != 4) && (KC != 6) && (KC != 8))
-				throw new ArgumentException("Key length not 128/192/256 bits.");
-
-			ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
-			uint[,] W = new uint[ROUNDS+1,4];   // 4 words in a block
-
-			//
-			// copy the key into the round key array
-			//
-
-			t = 0;
-			for (int i = 0; i < key.Length; t++)
-			{
-				W[t >> 2, t & 3] = Pack.LE_To_UInt32(key, i);
-				i+=4;
-			}
-
-			//
-			// while not enough round key material calculated
-			// calculate new values
-			//
-			int k = (ROUNDS + 1) << 2;
-			for (int i = KC; (i < k); i++)
-			{
-				uint 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 (int i = 0; i < 4; i++)
-					{
-						W[j,i] = Inv_Mcol(W[j,i]);
-					}
-				}
-			}
-
-			return W;
-		}
-
-		private int		ROUNDS;
-		private uint[,]	WorkingKey;
-		private uint	C0, C1, C2, C3;
-		private bool	forEncryption;
-
-		private const int BLOCK_SIZE = 16;
-
-		/**
-		* default constructor - 128 bit block size.
-		*/
-		public AesLightEngine()
-		{
-		}
-
-		/**
-		* initialise an AES cipher.
-		*
-		* @param forEncryption whether or not we are for encryption.
-		* @param parameters the parameters required to set up the cipher.
-		* @exception ArgumentException if the parameters argument is
-		* inappropriate.
-		*/
-		public void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			if (!(parameters is KeyParameter))
-				throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().ToString());
-
-			WorkingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey(), forEncryption);
-			this.forEncryption = forEncryption;
-		}
-
-		public string AlgorithmName
-		{
-			get { return "AES"; }
-		}
-
-		public bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
-
-		public int GetBlockSize()
-		{
-			return BLOCK_SIZE;
-		}
-
-		public int ProcessBlock(
-			byte[]	input,
-			int		inOff,
-			byte[]	output,
-			int		outOff)
-		{
-			if (WorkingKey == null)
-			{
-				throw new InvalidOperationException("AES engine not initialised");
-			}
-
-			if ((inOff + (32 / 2)) > input.Length)
-			{
-				throw new DataLengthException("input buffer too short");
-			}
-
-			if ((outOff + (32 / 2)) > output.Length)
-			{
-				throw new DataLengthException("output buffer too short");
-			}
-
-			if (forEncryption)
-			{
-				UnPackBlock(input, inOff);
-				EncryptBlock(WorkingKey);
-				PackBlock(output, outOff);
-			}
-			else
-			{
-				UnPackBlock(input, inOff);
-				DecryptBlock(WorkingKey);
-				PackBlock(output, outOff);
-			}
-
-			return BLOCK_SIZE;
-		}
-
-		public void Reset()
-		{
-		}
-
-		private void UnPackBlock(
-			byte[]	bytes,
-			int		off)
-		{
-			C0 = Pack.LE_To_UInt32(bytes, off);
-			C1 = Pack.LE_To_UInt32(bytes, off + 4);
-			C2 = Pack.LE_To_UInt32(bytes, off + 8);
-			C3 = Pack.LE_To_UInt32(bytes, off + 12);
-		}
-
-		private void PackBlock(
-			byte[]	bytes,
-			int		off)
-		{
-			Pack.UInt32_To_LE(C0, bytes, off);
-			Pack.UInt32_To_LE(C1, bytes, off + 4);
-			Pack.UInt32_To_LE(C2, bytes, off + 8);
-			Pack.UInt32_To_LE(C3, bytes, off + 12);
-		}
-
-		private void EncryptBlock(
-			uint[,] KW)
-		{
-			int r;
-			uint r0, r1, r2, r3;
-
-			C0 ^= KW[0,0];
-			C1 ^= KW[0,1];
-			C2 ^= KW[0,2];
-			C3 ^= KW[0,3];
-
-			for (r = 1; r < ROUNDS - 1;) 
-			{
-				r0 = Mcol((uint)S[C0&255] ^ (((uint)S[(C1>>8)&255])<<8) ^ (((uint)S[(C2>>16)&255])<<16) ^ (((uint)S[(C3>>24)&255])<<24)) ^ KW[r,0];
-				r1 = Mcol((uint)S[C1&255] ^ (((uint)S[(C2>>8)&255])<<8) ^ (((uint)S[(C3>>16)&255])<<16) ^ (((uint)S[(C0>>24)&255])<<24)) ^ KW[r,1];
-				r2 = Mcol((uint)S[C2&255] ^ (((uint)S[(C3>>8)&255])<<8) ^ (((uint)S[(C0>>16)&255])<<16) ^ (((uint)S[(C1>>24)&255])<<24)) ^ KW[r,2];
-				r3 = Mcol((uint)S[C3&255] ^ (((uint)S[(C0>>8)&255])<<8) ^ (((uint)S[(C1>>16)&255])<<16) ^ (((uint)S[(C2>>24)&255])<<24)) ^ KW[r++,3];
-				C0 = Mcol((uint)S[r0&255] ^ (((uint)S[(r1>>8)&255])<<8) ^ (((uint)S[(r2>>16)&255])<<16) ^ (((uint)S[(r3>>24)&255])<<24)) ^ KW[r,0];
-				C1 = Mcol((uint)S[r1&255] ^ (((uint)S[(r2>>8)&255])<<8) ^ (((uint)S[(r3>>16)&255])<<16) ^ (((uint)S[(r0>>24)&255])<<24)) ^ KW[r,1];
-				C2 = Mcol((uint)S[r2&255] ^ (((uint)S[(r3>>8)&255])<<8) ^ (((uint)S[(r0>>16)&255])<<16) ^ (((uint)S[(r1>>24)&255])<<24)) ^ KW[r,2];
-				C3 = Mcol((uint)S[r3&255] ^ (((uint)S[(r0>>8)&255])<<8) ^ (((uint)S[(r1>>16)&255])<<16) ^ (((uint)S[(r2>>24)&255])<<24)) ^ KW[r++,3];
-			}
-
-			r0 = Mcol((uint)S[C0&255] ^ (((uint)S[(C1>>8)&255])<<8) ^ (((uint)S[(C2>>16)&255])<<16) ^ (((uint)S[(C3>>24)&255])<<24)) ^ KW[r,0];
-			r1 = Mcol((uint)S[C1&255] ^ (((uint)S[(C2>>8)&255])<<8) ^ (((uint)S[(C3>>16)&255])<<16) ^ (((uint)S[(C0>>24)&255])<<24)) ^ KW[r,1];
-			r2 = Mcol((uint)S[C2&255] ^ (((uint)S[(C3>>8)&255])<<8) ^ (((uint)S[(C0>>16)&255])<<16) ^ (((uint)S[(C1>>24)&255])<<24)) ^ KW[r,2];
-			r3 = Mcol((uint)S[C3&255] ^ (((uint)S[(C0>>8)&255])<<8) ^ (((uint)S[(C1>>16)&255])<<16) ^ (((uint)S[(C2>>24)&255])<<24)) ^ KW[r++,3];
-
-			// the final round is a simple function of S
-
-			C0 = (uint)S[r0&255] ^ (((uint)S[(r1>>8)&255])<<8) ^ (((uint)S[(r2>>16)&255])<<16) ^ (((uint)S[(r3>>24)&255])<<24) ^ KW[r,0];
-			C1 = (uint)S[r1&255] ^ (((uint)S[(r2>>8)&255])<<8) ^ (((uint)S[(r3>>16)&255])<<16) ^ (((uint)S[(r0>>24)&255])<<24) ^ KW[r,1];
-			C2 = (uint)S[r2&255] ^ (((uint)S[(r3>>8)&255])<<8) ^ (((uint)S[(r0>>16)&255])<<16) ^ (((uint)S[(r1>>24)&255])<<24) ^ KW[r,2];
-			C3 = (uint)S[r3&255] ^ (((uint)S[(r0>>8)&255])<<8) ^ (((uint)S[(r1>>16)&255])<<16) ^ (((uint)S[(r2>>24)&255])<<24) ^ KW[r,3];
-		}
-
-		private void DecryptBlock(
-			uint[,] KW)
-		{
-			int r;
-			uint r0, r1, r2, r3;
-
-			C0 ^= KW[ROUNDS,0];
-			C1 ^= KW[ROUNDS,1];
-			C2 ^= KW[ROUNDS,2];
-			C3 ^= KW[ROUNDS,3];
-
-			for (r = ROUNDS-1; r>1;) 
-			{
-				r0 = Inv_Mcol((uint)Si[C0&255] ^ (((uint)Si[(C3>>8)&255])<<8) ^ (((uint)Si[(C2>>16)&255])<<16) ^ ((uint)Si[(C1>>24)&255]<<24)) ^ KW[r,0];
-				r1 = Inv_Mcol((uint)Si[C1&255] ^ (((uint)Si[(C0>>8)&255])<<8) ^ (((uint)Si[(C3>>16)&255])<<16) ^ ((uint)Si[(C2>>24)&255]<<24)) ^ KW[r,1];
-				r2 = Inv_Mcol((uint)Si[C2&255] ^ (((uint)Si[(C1>>8)&255])<<8) ^ (((uint)Si[(C0>>16)&255])<<16) ^ ((uint)Si[(C3>>24)&255]<<24)) ^ KW[r,2];
-				r3 = Inv_Mcol((uint)Si[C3&255] ^ (((uint)Si[(C2>>8)&255])<<8) ^ (((uint)Si[(C1>>16)&255])<<16) ^ ((uint)Si[(C0>>24)&255]<<24)) ^ KW[r--,3];
-				C0 = Inv_Mcol((uint)Si[r0&255] ^ (((uint)Si[(r3>>8)&255])<<8) ^ (((uint)Si[(r2>>16)&255])<<16) ^ ((uint)Si[(r1>>24)&255]<<24)) ^ KW[r,0];
-				C1 = Inv_Mcol((uint)Si[r1&255] ^ (((uint)Si[(r0>>8)&255])<<8) ^ (((uint)Si[(r3>>16)&255])<<16) ^ ((uint)Si[(r2>>24)&255]<<24)) ^ KW[r,1];
-				C2 = Inv_Mcol((uint)Si[r2&255] ^ (((uint)Si[(r1>>8)&255])<<8) ^ (((uint)Si[(r0>>16)&255])<<16) ^ ((uint)Si[(r3>>24)&255]<<24)) ^ KW[r,2];
-				C3 = Inv_Mcol((uint)Si[r3&255] ^ (((uint)Si[(r2>>8)&255])<<8) ^ (((uint)Si[(r1>>16)&255])<<16) ^ ((uint)Si[(r0>>24)&255]<<24)) ^ KW[r--,3];
-			}
-
-			r0 = Inv_Mcol((uint)Si[C0&255] ^ (((uint)Si[(C3>>8)&255])<<8) ^ (((uint)Si[(C2>>16)&255])<<16) ^ ((uint)Si[(C1>>24)&255]<<24)) ^ KW[r,0];
-			r1 = Inv_Mcol((uint)Si[C1&255] ^ (((uint)Si[(C0>>8)&255])<<8) ^ (((uint)Si[(C3>>16)&255])<<16) ^ ((uint)Si[(C2>>24)&255]<<24)) ^ KW[r,1];
-			r2 = Inv_Mcol((uint)Si[C2&255] ^ (((uint)Si[(C1>>8)&255])<<8) ^ (((uint)Si[(C0>>16)&255])<<16) ^ ((uint)Si[(C3>>24)&255]<<24)) ^ KW[r,2];
-			r3 = Inv_Mcol((uint)Si[C3&255] ^ (((uint)Si[(C2>>8)&255])<<8) ^ (((uint)Si[(C1>>16)&255])<<16) ^ ((uint)Si[(C0>>24)&255]<<24)) ^ KW[r,3];
-
-			// the final round's table is a simple function of Si
-
-			C0 = (uint)Si[r0&255] ^ (((uint)Si[(r3>>8)&255])<<8) ^ (((uint)Si[(r2>>16)&255])<<16) ^ (((uint)Si[(r1>>24)&255])<<24) ^ KW[0,0];
-			C1 = (uint)Si[r1&255] ^ (((uint)Si[(r0>>8)&255])<<8) ^ (((uint)Si[(r3>>16)&255])<<16) ^ (((uint)Si[(r2>>24)&255])<<24) ^ KW[0,1];
-			C2 = (uint)Si[r2&255] ^ (((uint)Si[(r1>>8)&255])<<8) ^ (((uint)Si[(r0>>16)&255])<<16) ^ (((uint)Si[(r3>>24)&255])<<24) ^ KW[0,2];
-			C3 = (uint)Si[r3&255] ^ (((uint)Si[(r2>>8)&255])<<8) ^ (((uint)Si[(r1>>16)&255])<<16) ^ (((uint)Si[(r0>>24)&255])<<24) ^ KW[0,3];
-		}
-	}
+    /**
+    * 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>
+    * <p>
+    * This file contains the slowest performance version with no static tables
+    * for round precomputation, but it has the smallest foot print.
+    * </p>
+    */
+    public class AesLightEngine
+        : IBlockCipher
+    {
+        // The S box
+        private static readonly byte[] S =
+        {
+            99, 124, 119, 123, 242, 107, 111, 197,
+            48,   1, 103,  43, 254, 215, 171, 118,
+            202, 130, 201, 125, 250,  89,  71, 240,
+            173, 212, 162, 175, 156, 164, 114, 192,
+            183, 253, 147,  38,  54,  63, 247, 204,
+            52, 165, 229, 241, 113, 216,  49,  21,
+            4, 199,  35, 195,  24, 150,   5, 154,
+            7,  18, 128, 226, 235,  39, 178, 117,
+            9, 131,  44,  26,  27, 110,  90, 160,
+            82,  59, 214, 179,  41, 227,  47, 132,
+            83, 209,   0, 237,  32, 252, 177,  91,
+            106, 203, 190,  57,  74,  76,  88, 207,
+            208, 239, 170, 251,  67,  77,  51, 133,
+            69, 249,   2, 127,  80,  60, 159, 168,
+            81, 163,  64, 143, 146, 157,  56, 245,
+            188, 182, 218,  33,  16, 255, 243, 210,
+            205,  12,  19, 236,  95, 151,  68,  23,
+            196, 167, 126,  61, 100,  93,  25, 115,
+            96, 129,  79, 220,  34,  42, 144, 136,
+            70, 238, 184,  20, 222,  94,  11, 219,
+            224,  50,  58,  10,  73,   6,  36,  92,
+            194, 211, 172,  98, 145, 149, 228, 121,
+            231, 200,  55, 109, 141, 213,  78, 169,
+            108,  86, 244, 234, 101, 122, 174,   8,
+            186, 120,  37,  46,  28, 166, 180, 198,
+            232, 221, 116,  31,  75, 189, 139, 138,
+            112,  62, 181, 102,  72,   3, 246,  14,
+            97,  53,  87, 185, 134, 193,  29, 158,
+            225, 248, 152,  17, 105, 217, 142, 148,
+            155,  30, 135, 233, 206,  85,  40, 223,
+            140, 161, 137,  13, 191, 230,  66, 104,
+            65, 153,  45,  15, 176,  84, 187,  22,
+        };
+
+        // The inverse S-box
+        private static readonly byte[] Si =
+        {
+            82,   9, 106, 213,  48,  54, 165,  56,
+            191,  64, 163, 158, 129, 243, 215, 251,
+            124, 227,  57, 130, 155,  47, 255, 135,
+            52, 142,  67,  68, 196, 222, 233, 203,
+            84, 123, 148,  50, 166, 194,  35,  61,
+            238,  76, 149,  11,  66, 250, 195,  78,
+            8,  46, 161, 102,  40, 217,  36, 178,
+            118,  91, 162,  73, 109, 139, 209,  37,
+            114, 248, 246, 100, 134, 104, 152,  22,
+            212, 164,  92, 204,  93, 101, 182, 146,
+            108, 112,  72,  80, 253, 237, 185, 218,
+            94,  21,  70,  87, 167, 141, 157, 132,
+            144, 216, 171,   0, 140, 188, 211,  10,
+            247, 228,  88,   5, 184, 179,  69,   6,
+            208,  44,  30, 143, 202,  63,  15,   2,
+            193, 175, 189,   3,   1,  19, 138, 107,
+            58, 145,  17,  65,  79, 103, 220, 234,
+            151, 242, 207, 206, 240, 180, 230, 115,
+            150, 172, 116,  34, 231, 173,  53, 133,
+            226, 249,  55, 232,  28, 117, 223, 110,
+            71, 241,  26, 113,  29,  41, 197, 137,
+            111, 183,  98,  14, 170,  24, 190,  27,
+            252,  86,  62,  75, 198, 210, 121,  32,
+            154, 219, 192, 254, 120, 205,  90, 244,
+            31, 221, 168,  51, 136,   7, 199,  49,
+            177,  18,  16,  89,  39, 128, 236,  95,
+            96,  81, 127, 169,  25, 181,  74,  13,
+            45, 229, 122, 159, 147, 201, 156, 239,
+            160, 224,  59,  77, 174,  42, 245, 176,
+            200, 235, 187,  60, 131,  83, 153,  97,
+            23,  43,   4, 126, 186, 119, 214,  38,
+            225, 105,  20,  99,  85,  33,  12, 125,
+        };
+
+        // vector used in calculating key schedule (powers of x in GF(256))
+        private static readonly byte[] 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
+        };
+
+        private static uint Shift(uint r, int shift)
+        {
+            return (r >> shift) | (r << (32 - shift));
+        }
+
+        /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+        private const uint m1 = 0x80808080;
+        private const uint m2 = 0x7f7f7f7f;
+        private const uint m3 = 0x0000001b;
+
+        private static uint FFmulX(uint 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 static uint Mcol(uint x)
+        {
+            uint f2 = FFmulX(x);
+            return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24);
+        }
+
+        private static uint Inv_Mcol(uint x)
+        {
+            uint f2 = FFmulX(x);
+            uint f4 = FFmulX(f2);
+            uint f8 = FFmulX(f4);
+            uint f9 = x ^ f8;
+
+            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+        }
+
+        private static uint SubWord(uint x)
+        {
+            return (uint)S[x&255]
+                | (((uint)S[(x>>8)&255]) << 8)
+                | (((uint)S[(x>>16)&255]) << 16)
+                | (((uint)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 uint[][] GenerateWorkingKey(
+            byte[]	key,
+            bool	forEncryption)
+        {
+            int KC = key.Length / 4;  // key length in words
+            int t;
+
+            if ((KC != 4) && (KC != 6) && (KC != 8))
+                throw new ArgumentException("Key length not 128/192/256 bits.");
+
+            ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
+
+            uint[][] W = new uint[ROUNDS + 1][]; // 4 words in a block
+            for (int i = 0; i <= ROUNDS; ++i)
+            {
+                W[i] = new uint[4];
+            }
+
+            //
+            // copy the key into the round key array
+            //
+
+            t = 0;
+            for (int i = 0; i < key.Length; t++)
+            {
+                W[t >> 2][t & 3] = Pack.LE_To_UInt32(key, i);
+                i+=4;
+            }
+
+            //
+            // while not enough round key material calculated
+            // calculate new values
+            //
+            int k = (ROUNDS + 1) << 2;
+            for (int i = KC; (i < k); i++)
+            {
+                uint 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++) 
+                {
+                    uint[] w = W[j];
+                    for (int i = 0; i < 4; i++)
+                    {
+                        w[i] = Inv_Mcol(w[i]);
+                    }
+                }
+            }
+
+            return W;
+        }
+
+        private int ROUNDS;
+        private uint[][] WorkingKey;
+        private uint C0, C1, C2, C3;
+        private bool forEncryption;
+
+        private const int BLOCK_SIZE = 16;
+
+        /**
+        * default constructor - 128 bit block size.
+        */
+        public AesLightEngine()
+        {
+        }
+
+        /**
+        * initialise an AES cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            KeyParameter keyParameter = parameters as KeyParameter;
+
+            if (keyParameter == null)
+                throw new ArgumentException("invalid parameter passed to AES init - " + parameters.GetType().Name);
+
+            WorkingKey = GenerateWorkingKey(keyParameter.GetKey(), forEncryption);
+
+            this.forEncryption = forEncryption;
+        }
+
+        public string AlgorithmName
+        {
+            get { return "AES"; }
+        }
+
+        public bool IsPartialBlockOkay
+        {
+            get { return false; }
+        }
+
+        public int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (WorkingKey == null)
+            {
+                throw new InvalidOperationException("AES engine not initialised");
+            }
+
+            if ((inOff + (32 / 2)) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + (32 / 2)) > output.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            UnPackBlock(input, inOff);
+
+            if (forEncryption)
+            {
+                EncryptBlock(WorkingKey);
+            }
+            else
+            {
+                DecryptBlock(WorkingKey);
+            }
+
+            PackBlock(output, outOff);
+
+            return BLOCK_SIZE;
+        }
+
+        public void Reset()
+        {
+        }
+
+        private void UnPackBlock(
+            byte[]	bytes,
+            int		off)
+        {
+            C0 = Pack.LE_To_UInt32(bytes, off);
+            C1 = Pack.LE_To_UInt32(bytes, off + 4);
+            C2 = Pack.LE_To_UInt32(bytes, off + 8);
+            C3 = Pack.LE_To_UInt32(bytes, off + 12);
+        }
+
+        private void PackBlock(
+            byte[]	bytes,
+            int		off)
+        {
+            Pack.UInt32_To_LE(C0, bytes, off);
+            Pack.UInt32_To_LE(C1, bytes, off + 4);
+            Pack.UInt32_To_LE(C2, bytes, off + 8);
+            Pack.UInt32_To_LE(C3, bytes, off + 12);
+        }
+
+        private void EncryptBlock(uint[][] KW)
+        {
+            uint[] kw = KW[0];
+            uint t0 = this.C0 ^ kw[0];
+            uint t1 = this.C1 ^ kw[1];
+            uint t2 = this.C2 ^ kw[2];
+
+            uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+            int r = 1;
+            while (r < ROUNDS - 1)
+            {
+                kw = KW[r++];
+                r0 = Mcol((uint)S[t0 & 255] ^ (((uint)S[(t1 >> 8) & 255]) << 8) ^ (((uint)S[(t2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+                r1 = Mcol((uint)S[t1 & 255] ^ (((uint)S[(t2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(t0 >> 24) & 255]) << 24)) ^ kw[1];
+                r2 = Mcol((uint)S[t2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(t0 >> 16) & 255]) << 16) ^ (((uint)S[(t1 >> 24) & 255]) << 24)) ^ kw[2];
+                r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(t0 >> 8) & 255]) << 8) ^ (((uint)S[(t1 >> 16) & 255]) << 16) ^ (((uint)S[(t2 >> 24) & 255]) << 24)) ^ kw[3];
+                kw = KW[r++];
+                t0 = Mcol((uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+                t1 = Mcol((uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24)) ^ kw[1];
+                t2 = Mcol((uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24)) ^ kw[2];
+                r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24)) ^ kw[3];
+            }
+
+            kw = KW[r++];
+            r0 = Mcol((uint)S[t0 & 255] ^ (((uint)S[(t1 >> 8) & 255]) << 8) ^ (((uint)S[(t2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24)) ^ kw[0];
+            r1 = Mcol((uint)S[t1 & 255] ^ (((uint)S[(t2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(t0 >> 24) & 255]) << 24)) ^ kw[1];
+            r2 = Mcol((uint)S[t2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(t0 >> 16) & 255]) << 16) ^ (((uint)S[(t1 >> 24) & 255]) << 24)) ^ kw[2];
+            r3 = Mcol((uint)S[r3 & 255] ^ (((uint)S[(t0 >> 8) & 255]) << 8) ^ (((uint)S[(t1 >> 16) & 255]) << 16) ^ (((uint)S[(t2 >> 24) & 255]) << 24)) ^ kw[3];
+
+            // the final round is a simple function of S
+
+            kw = KW[r];
+            this.C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[(r3 >> 24) & 255]) << 24) ^ kw[0];
+            this.C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[(r0 >> 24) & 255]) << 24) ^ kw[1];
+            this.C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[(r1 >> 24) & 255]) << 24) ^ kw[2];
+            this.C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[(r2 >> 24) & 255]) << 24) ^ kw[3];
+        }
+
+        private void DecryptBlock(uint[][] KW)
+        {
+            uint[] kw = KW[ROUNDS];
+            uint t0 = this.C0 ^ kw[0];
+            uint t1 = this.C1 ^ kw[1];
+            uint t2 = this.C2 ^ kw[2];
+
+            uint r0, r1, r2, r3 = this.C3 ^ kw[3];
+            int r = ROUNDS - 1;
+            while (r > 1)
+            {
+                kw = KW[r--];
+                r0 = Inv_Mcol((uint)Si[t0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(t2 >> 16) & 255]) << 16) ^ ((uint)Si[(t1 >> 24) & 255] << 24)) ^ kw[0];
+                r1 = Inv_Mcol((uint)Si[t1 & 255] ^ (((uint)Si[(t0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(t2 >> 24) & 255] << 24)) ^ kw[1];
+                r2 = Inv_Mcol((uint)Si[t2 & 255] ^ (((uint)Si[(t1 >> 8) & 255]) << 8) ^ (((uint)Si[(t0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+                r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(t2 >> 8) & 255]) << 8) ^ (((uint)Si[(t1 >> 16) & 255]) << 16) ^ ((uint)Si[(t0 >> 24) & 255] << 24)) ^ kw[3];
+                kw = KW[r--];
+                t0 = Inv_Mcol((uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ ((uint)Si[(r1 >> 24) & 255] << 24)) ^ kw[0];
+                t1 = Inv_Mcol((uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(r2 >> 24) & 255] << 24)) ^ kw[1];
+                t2 = Inv_Mcol((uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+                r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ ((uint)Si[(r0 >> 24) & 255] << 24)) ^ kw[3];
+            }
+
+            kw = KW[1];
+            r0 = Inv_Mcol((uint)Si[t0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(t2 >> 16) & 255]) << 16) ^ ((uint)Si[(t1 >> 24) & 255] << 24)) ^ kw[0];
+            r1 = Inv_Mcol((uint)Si[t1 & 255] ^ (((uint)Si[(t0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ ((uint)Si[(t2 >> 24) & 255] << 24)) ^ kw[1];
+            r2 = Inv_Mcol((uint)Si[t2 & 255] ^ (((uint)Si[(t1 >> 8) & 255]) << 8) ^ (((uint)Si[(t0 >> 16) & 255]) << 16) ^ ((uint)Si[(r3 >> 24) & 255] << 24)) ^ kw[2];
+            r3 = Inv_Mcol((uint)Si[r3 & 255] ^ (((uint)Si[(t2 >> 8) & 255]) << 8) ^ (((uint)Si[(t1 >> 16) & 255]) << 16) ^ ((uint)Si[(t0 >> 24) & 255] << 24)) ^ kw[3];
+
+            // the final round's table is a simple function of Si
+
+            kw = KW[0];
+            this.C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[(r1 >> 24) & 255]) << 24) ^ kw[0];
+            this.C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[(r2 >> 24) & 255]) << 24) ^ kw[1];
+            this.C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[(r3 >> 24) & 255]) << 24) ^ kw[2];
+            this.C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[(r0 >> 24) & 255]) << 24) ^ kw[3];
+        }
+    }
 }
diff --git a/crypto/src/crypto/engines/AesWrapEngine.cs b/crypto/src/crypto/engines/AesWrapEngine.cs
new file mode 100644
index 000000000..1ce01542b
--- /dev/null
+++ b/crypto/src/crypto/engines/AesWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <remarks>
+	/// 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>.
+	/// </remarks>
+	public class AesWrapEngine
+		: Rfc3394WrapEngine
+	{
+		public AesWrapEngine()
+			: base(new AesEngine())
+		{
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/BlowfishEngine.cs b/crypto/src/crypto/engines/BlowfishEngine.cs
new file mode 100644
index 000000000..8f80f712e
--- /dev/null
+++ b/crypto/src/crypto/engines/BlowfishEngine.cs
@@ -0,0 +1,561 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * 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 sealed class BlowfishEngine
+		: IBlockCipher
+    {
+        private readonly static uint[] 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 readonly int    ROUNDS = 16;
+        private const int    BLOCK_SIZE = 8;  // bytes = 64 bits
+        private static readonly int    SBOX_SK = 256;
+        private static readonly int    P_SZ = ROUNDS+2;
+
+        private readonly uint[] S0, S1, S2, S3;     // the s-boxes
+        private readonly uint[] P;                  // the p-array
+
+        private bool encrypting;
+
+        private byte[] workingKey;
+
+        public BlowfishEngine()
+        {
+            S0 = new uint[SBOX_SK];
+            S1 = new uint[SBOX_SK];
+            S2 = new uint[SBOX_SK];
+            S3 = new uint[SBOX_SK];
+            P = new uint[P_SZ];
+        }
+
+        /**
+        * initialise a Blowfish cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool               forEncryption,
+            ICipherParameters  parameters)
+        {
+            if (!(parameters is KeyParameter))
+				throw new ArgumentException("invalid parameter passed to Blowfish init - " + parameters.GetType().ToString());
+
+			this.encrypting = forEncryption;
+			this.workingKey = ((KeyParameter)parameters).GetKey();
+			SetKey(this.workingKey);
+        }
+
+		public string AlgorithmName
+        {
+            get { return "Blowfish"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public  int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (workingKey == null)
+            {
+                throw new InvalidOperationException("Blowfish not initialised");
+            }
+
+            if ((inOff + BLOCK_SIZE) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + BLOCK_SIZE) > output.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            if (encrypting)
+            {
+                EncryptBlock(input, inOff, output, outOff);
+            }
+            else
+            {
+                DecryptBlock(input, inOff, output, outOff);
+            }
+
+            return BLOCK_SIZE;
+        }
+
+        public void Reset()
+        {
+        }
+
+        public int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        //==================================
+        // Private Implementation
+        //==================================
+
+        private uint F(uint 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(
+            uint	xl,
+            uint	xr,
+            uint[]	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...)
+            */
+            Array.Copy(KS0, 0, S0, 0, SBOX_SK);
+            Array.Copy(KS1, 0, S1, 0, SBOX_SK);
+            Array.Copy(KS2, 0, S2, 0, SBOX_SK);
+            Array.Copy(KS3, 0, S3, 0, SBOX_SK);
+
+            Array.Copy(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
+                uint data = 0x0000000;
+                for (int j=0; j < 4; j++)
+                {
+                    // create a 32 bit block
+                    data = (data << 8) | (uint)key[keyIndex++];
+
+                    // 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)
+        {
+            uint xl = Pack.BE_To_UInt32(src, srcIndex);
+            uint xr = Pack.BE_To_UInt32(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];
+
+            Pack.UInt32_To_BE(xr, dst, dstIndex);
+            Pack.UInt32_To_BE(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)
+        {
+            uint xl = Pack.BE_To_UInt32(src, srcIndex);
+            uint xr = Pack.BE_To_UInt32(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];
+
+            Pack.UInt32_To_BE(xr, dst, dstIndex);
+            Pack.UInt32_To_BE(xl, dst, dstIndex + 4);
+        }
+    }
+}
diff --git a/crypto/src/crypto/engines/CamelliaEngine.cs b/crypto/src/crypto/engines/CamelliaEngine.cs
new file mode 100644
index 000000000..8f4a442e9
--- /dev/null
+++ b/crypto/src/crypto/engines/CamelliaEngine.cs
@@ -0,0 +1,669 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* Camellia - based on RFC 3713.
+	*/
+	public class CamelliaEngine
+		: IBlockCipher
+	{
+		private bool initialised = false;
+		private bool _keyIs128;
+
+		private const int BLOCK_SIZE = 16;
+
+		private uint[] subkey = new uint[24 * 4];
+		private uint[] kw = new uint[4 * 2]; // for whitening
+		private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1)
+		private uint[] state = new uint[4]; // for encryption and decryption
+
+		private static readonly uint[] SIGMA = new uint[]{
+			0xa09e667f, 0x3bcc908b,
+			0xb67ae858, 0x4caa73b2,
+			0xc6ef372f, 0xe94f82be,
+			0x54ff53a5, 0xf1d36f1c,
+			0x10e527fa, 0xde682d1d,
+			0xb05688c2, 0xb3e6c1fd
+		};
+
+		/*
+		*
+		* S-box data
+		*
+		*/
+		private static readonly uint[] SBOX1_1110 = new uint[]{
+			0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00, 0xb3b3b300, 0x27272700,
+			0xc0c0c000, 0xe5e5e500, 0xe4e4e400, 0x85858500, 0x57575700, 0x35353500,
+			0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100, 0x23232300, 0xefefef00,
+			0x6b6b6b00, 0x93939300, 0x45454500, 0x19191900, 0xa5a5a500, 0x21212100,
+			0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00, 0x1d1d1d00, 0x65656500,
+			0x92929200, 0xbdbdbd00, 0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00,
+			0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00, 0x3e3e3e00, 0x30303000,
+			0xdcdcdc00, 0x5f5f5f00, 0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00,
+			0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00, 0xd5d5d500, 0x47474700,
+			0x5d5d5d00, 0x3d3d3d00, 0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600,
+			0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00, 0x8b8b8b00, 0x0d0d0d00,
+			0x9a9a9a00, 0x66666600, 0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00,
+			0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000, 0xf0f0f000, 0xb1b1b100,
+			0x84848400, 0x99999900, 0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200,
+			0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500, 0x6d6d6d00, 0xb7b7b700,
+			0xa9a9a900, 0x31313100, 0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700,
+			0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100, 0xdedede00, 0x1b1b1b00,
+			0x11111100, 0x1c1c1c00, 0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600,
+			0x53535300, 0x18181800, 0xf2f2f200, 0x22222200, 0xfefefe00, 0x44444400,
+			0xcfcfcf00, 0xb2b2b200, 0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100,
+			0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800, 0x60606000, 0xfcfcfc00,
+			0x69696900, 0x50505000, 0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00,
+			0xa1a1a100, 0x89898900, 0x62626200, 0x97979700, 0x54545400, 0x5b5b5b00,
+			0x1e1e1e00, 0x95959500, 0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200,
+			0x10101000, 0xc4c4c400, 0x00000000, 0x48484800, 0xa3a3a300, 0xf7f7f700,
+			0x75757500, 0xdbdbdb00, 0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00,
+			0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400, 0x87878700, 0x5c5c5c00,
+			0x83838300, 0x02020200, 0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300,
+			0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300, 0x9d9d9d00, 0x7f7f7f00,
+			0xbfbfbf00, 0xe2e2e200, 0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600,
+			0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00, 0x81818100, 0x96969600,
+			0x6f6f6f00, 0x4b4b4b00, 0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00,
+			0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00, 0x9f9f9f00, 0x6e6e6e00,
+			0xbcbcbc00, 0x8e8e8e00, 0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600,
+			0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900, 0x78787800, 0x98989800,
+			0x06060600, 0x6a6a6a00, 0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00,
+			0xd4d4d400, 0x25252500, 0xababab00, 0x42424200, 0x88888800, 0xa2a2a200,
+			0x8d8d8d00, 0xfafafa00, 0x72727200, 0x07070700, 0xb9b9b900, 0x55555500,
+			0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00, 0x36363600, 0x49494900,
+			0x2a2a2a00, 0x68686800, 0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400,
+			0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00, 0xbbbbbb00, 0xc9c9c900,
+			0x43434300, 0xc1c1c100, 0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400,
+			0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00
+		};
+
+		private static readonly uint[] SBOX4_4404 = new uint[]{
+			0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0, 0xe4e400e4, 0x57570057,
+			0xeaea00ea, 0xaeae00ae, 0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5,
+			0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092, 0x86860086, 0xafaf00af,
+			0x7c7c007c, 0x1f1f001f, 0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b,
+			0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d, 0xd9d900d9, 0x5a5a005a,
+			0x51510051, 0x6c6c006c, 0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0,
+			0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084, 0xdfdf00df, 0xcbcb00cb,
+			0x34340034, 0x76760076, 0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004,
+			0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011, 0x32320032, 0x9c9c009c,
+			0x53530053, 0xf2f200f2, 0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a,
+			0x24240024, 0xe8e800e8, 0x60600060, 0x69690069, 0xaaaa00aa, 0xa0a000a0,
+			0xa1a100a1, 0x62620062, 0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064,
+			0x10100010, 0x00000000, 0xa3a300a3, 0x75750075, 0x8a8a008a, 0xe6e600e6,
+			0x09090009, 0xdddd00dd, 0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090,
+			0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf, 0x52520052, 0xd8d800d8,
+			0xc8c800c8, 0xc6c600c6, 0x81810081, 0x6f6f006f, 0x13130013, 0x63630063,
+			0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc, 0x29290029, 0xf9f900f9,
+			0x2f2f002f, 0xb4b400b4, 0x78780078, 0x06060006, 0xe7e700e7, 0x71710071,
+			0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d, 0x72720072, 0xb9b900b9,
+			0xf8f800f8, 0xacac00ac, 0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1,
+			0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043, 0x15150015, 0xadad00ad,
+			0x77770077, 0x80800080, 0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5,
+			0x85850085, 0x35350035, 0x0c0c000c, 0x41410041, 0xefef00ef, 0x93930093,
+			0x19190019, 0x21210021, 0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd,
+			0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce, 0x30300030, 0x5f5f005f,
+			0xc5c500c5, 0x1a1a001a, 0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d,
+			0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d, 0x0d0d000d, 0x66660066,
+			0xcccc00cc, 0x2d2d002d, 0x12120012, 0x20200020, 0xb1b100b1, 0x99990099,
+			0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005, 0xb7b700b7, 0x31310031,
+			0x17170017, 0xd7d700d7, 0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c,
+			0x0f0f000f, 0x16160016, 0x18180018, 0x22220022, 0x44440044, 0xb2b200b2,
+			0xb5b500b5, 0x91910091, 0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050,
+			0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097, 0x5b5b005b, 0x95950095,
+			0xffff00ff, 0xd2d200d2, 0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db,
+			0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094, 0x5c5c005c, 0x02020002,
+			0x4a4a004a, 0x33330033, 0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2,
+			0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b, 0x96960096, 0x4b4b004b,
+			0xbebe00be, 0x2e2e002e, 0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e,
+			0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059, 0x98980098, 0x6a6a006a,
+			0x46460046, 0xbaba00ba, 0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa,
+			0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a, 0x49490049, 0x68680068,
+			0x38380038, 0xa4a400a4, 0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1,
+			0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e
+		};
+
+		private static readonly uint[] SBOX2_0222 = new uint[]{
+			0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9, 0x00676767, 0x004e4e4e,
+			0x00818181, 0x00cbcbcb, 0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a,
+			0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282, 0x00464646, 0x00dfdfdf,
+			0x00d6d6d6, 0x00272727, 0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242,
+			0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c, 0x003a3a3a, 0x00cacaca,
+			0x00252525, 0x007b7b7b, 0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f,
+			0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d, 0x007c7c7c, 0x00606060,
+			0x00b9b9b9, 0x00bebebe, 0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434,
+			0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595, 0x00ababab, 0x008e8e8e,
+			0x00bababa, 0x007a7a7a, 0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad,
+			0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a, 0x00171717, 0x001a1a1a,
+			0x00353535, 0x00cccccc, 0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a,
+			0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040, 0x00e1e1e1, 0x00636363,
+			0x00090909, 0x00333333, 0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585,
+			0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a, 0x00dadada, 0x006f6f6f,
+			0x00535353, 0x00626262, 0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf,
+			0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2, 0x00bdbdbd, 0x00363636,
+			0x00222222, 0x00383838, 0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c,
+			0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444, 0x00fdfdfd, 0x00888888,
+			0x009f9f9f, 0x00656565, 0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323,
+			0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151, 0x00c0c0c0, 0x00f9f9f9,
+			0x00d2d2d2, 0x00a0a0a0, 0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa,
+			0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f, 0x00a8a8a8, 0x00b6b6b6,
+			0x003c3c3c, 0x002b2b2b, 0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5,
+			0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00efefef,
+			0x00eaeaea, 0x00b7b7b7, 0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5,
+			0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929, 0x000f0f0f, 0x00b8b8b8,
+			0x00070707, 0x00040404, 0x009b9b9b, 0x00949494, 0x00212121, 0x00666666,
+			0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7, 0x003b3b3b, 0x00fefefe,
+			0x007f7f7f, 0x00c5c5c5, 0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c,
+			0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676, 0x00030303, 0x002d2d2d,
+			0x00dedede, 0x00969696, 0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c,
+			0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919, 0x003f3f3f, 0x00dcdcdc,
+			0x00797979, 0x001d1d1d, 0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d,
+			0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2, 0x00f0f0f0, 0x00313131,
+			0x000c0c0c, 0x00d4d4d4, 0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575,
+			0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484, 0x00111111, 0x00454545,
+			0x001b1b1b, 0x00f5f5f5, 0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa,
+			0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414, 0x006c6c6c, 0x00929292,
+			0x00545454, 0x00d0d0d0, 0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949,
+			0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6, 0x00777777, 0x00939393,
+			0x00868686, 0x00838383, 0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9,
+			0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d
+		};
+
+		private static readonly uint[] SBOX3_3033 = new uint[]{
+			0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xd900d9d9, 0x93009393,
+			0x60006060, 0xf200f2f2, 0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a,
+			0x75007575, 0x06000606, 0x57005757, 0xa000a0a0, 0x91009191, 0xf700f7f7,
+			0xb500b5b5, 0xc900c9c9, 0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090,
+			0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727, 0x8e008e8e, 0xb200b2b2,
+			0x49004949, 0xde00dede, 0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7,
+			0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767, 0x1f001f1f, 0x18001818,
+			0x6e006e6e, 0xaf00afaf, 0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d,
+			0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565, 0xea00eaea, 0xa300a3a3,
+			0xae00aeae, 0x9e009e9e, 0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b,
+			0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6, 0xc500c5c5, 0x86008686,
+			0x4d004d4d, 0x33003333, 0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696,
+			0x3a003a3a, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xd800d8d8,
+			0x42004242, 0xcc00cccc, 0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161,
+			0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282, 0xb600b6b6, 0xdb00dbdb,
+			0xd400d4d4, 0x98009898, 0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb,
+			0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0, 0x6f006f6f, 0x8d008d8d,
+			0x88008888, 0x0e000e0e, 0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b,
+			0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111, 0x7f007f7f, 0x22002222,
+			0xe700e7e7, 0x59005959, 0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8,
+			0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7e007e7e,
+			0xb400b4b4, 0x28002828, 0x55005555, 0x68006868, 0x50005050, 0xbe00bebe,
+			0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb, 0x2a002a2a, 0xad00adad,
+			0x0f000f0f, 0xca00caca, 0x70007070, 0xff00ffff, 0x32003232, 0x69006969,
+			0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xd100d1d1, 0xfb00fbfb,
+			0xba00baba, 0xed00eded, 0x45004545, 0x81008181, 0x73007373, 0x6d006d6d,
+			0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a, 0xc300c3c3, 0x2e002e2e,
+			0xc100c1c1, 0x01000101, 0xe600e6e6, 0x25002525, 0x48004848, 0x99009999,
+			0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9, 0xce00cece, 0xbf00bfbf,
+			0xdf00dfdf, 0x71007171, 0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313,
+			0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d, 0xc000c0c0, 0x4b004b4b,
+			0xb700b7b7, 0xa500a5a5, 0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717,
+			0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646, 0xcf00cfcf, 0x37003737,
+			0x5e005e5e, 0x47004747, 0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b,
+			0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac, 0x3c003c3c, 0x4c004c4c,
+			0x03000303, 0x35003535, 0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d,
+			0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121, 0x44004444, 0x51005151,
+			0xc600c6c6, 0x7d007d7d, 0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa,
+			0x7c007c7c, 0x77007777, 0x56005656, 0x05000505, 0x1b001b1b, 0xa400a4a4,
+			0x15001515, 0x34003434, 0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252,
+			0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd, 0xdd00dddd, 0xe400e4e4,
+			0xa100a1a1, 0xe000e0e0, 0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a,
+			0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f
+		};
+
+		private static uint rightRotate(uint x, int s)
+		{
+			return ((x >> s) + (x << (32 - s)));
+		}
+
+		private static uint leftRotate(uint x, int s)
+		{
+			return (x << s) + (x >> (32 - s));
+		}
+
+		private static void roldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[0 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+			ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+			ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+			ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+			ki[0 + ioff] = ko[0 + ooff];
+			ki[1 + ioff] = ko[1 + ooff];
+			ki[2 + ioff] = ko[2 + ooff];
+			ki[3 + ioff] = ko[3 + ooff];
+		}
+
+		private static void decroldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[2 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+			ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+			ko[0 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+			ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+			ki[0 + ioff] = ko[2 + ooff];
+			ki[1 + ioff] = ko[3 + ooff];
+			ki[2 + ioff] = ko[0 + ooff];
+			ki[3 + ioff] = ko[1 + ooff];
+		}
+
+		private static void roldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[0 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+			ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+			ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+			ko[3 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+			ki[0 + ioff] = ko[0 + ooff];
+			ki[1 + ioff] = ko[1 + ooff];
+			ki[2 + ioff] = ko[2 + ooff];
+			ki[3 + ioff] = ko[3 + ooff];
+		}
+
+		private static void decroldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+			ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+			ko[0 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+			ko[1 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+			ki[0 + ioff] = ko[2 + ooff];
+			ki[1 + ioff] = ko[3 + ooff];
+			ki[2 + ioff] = ko[0 + ooff];
+			ki[3 + ioff] = ko[1 + ooff];
+		}
+
+		private static uint bytes2uint(byte[] src, int offset)
+		{
+			uint word = 0;
+			for (int i = 0; i < 4; i++)
+			{
+				word = (word << 8) + (uint)src[i + offset];
+			}
+			return word;
+		}
+
+		private static void uint2bytes(uint word, byte[] dst, int offset)
+		{
+			for (int i = 0; i < 4; i++)
+			{
+				dst[(3 - i) + offset] = (byte)word;
+				word >>= 8;
+			}
+		}
+
+		private static void camelliaF2(uint[] s, uint[] skey, int keyoff)
+		{
+			uint t1, t2, u, v;
+
+			t1 = s[0] ^ skey[0 + keyoff];
+			u = SBOX4_4404[(byte)t1];
+			u ^= SBOX3_3033[(byte)(t1 >> 8)];
+			u ^= SBOX2_0222[(byte)(t1 >> 16)];
+			u ^= SBOX1_1110[(byte)(t1 >> 24)];
+			t2 = s[1] ^ skey[1 + keyoff];
+			v = SBOX1_1110[(byte)t2];
+			v ^= SBOX4_4404[(byte)(t2 >> 8)];
+			v ^= SBOX3_3033[(byte)(t2 >> 16)];
+			v ^= SBOX2_0222[(byte)(t2 >> 24)];
+
+			s[2] ^= u ^ v;
+			s[3] ^= u ^ v ^ rightRotate(u, 8);
+
+			t1 = s[2] ^ skey[2 + keyoff];
+			u = SBOX4_4404[(byte)t1];
+			u ^= SBOX3_3033[(byte)(t1 >> 8)];
+			u ^= SBOX2_0222[(byte)(t1 >> 16)];
+			u ^= SBOX1_1110[(byte)(t1 >> 24)];
+			t2 = s[3] ^ skey[3 + keyoff];
+			v = SBOX1_1110[(byte)t2];
+			v ^= SBOX4_4404[(byte)(t2 >> 8)];
+			v ^= SBOX3_3033[(byte)(t2 >> 16)];
+			v ^= SBOX2_0222[(byte)(t2 >> 24)];
+
+			s[0] ^= u ^ v;
+			s[1] ^= u ^ v ^ rightRotate(u, 8);
+		}
+
+		private static void camelliaFLs(uint[] s, uint[] fkey, int keyoff)
+		{
+
+			s[1] ^= leftRotate(s[0] & fkey[0 + keyoff], 1);
+			s[0] ^= fkey[1 + keyoff] | s[1];
+
+			s[2] ^= fkey[3 + keyoff] | s[3];
+			s[3] ^= leftRotate(fkey[2 + keyoff] & s[2], 1);
+		}
+
+		private void setKey(bool forEncryption, byte[] key)
+		{
+			uint[] k = new uint[8];
+			uint[] ka = new uint[4];
+			uint[] kb = new uint[4];
+			uint[] t = new uint[4];
+
+			switch (key.Length)
+			{
+				case 16:
+					_keyIs128 = true;
+					k[0] = bytes2uint(key, 0);
+					k[1] = bytes2uint(key, 4);
+					k[2] = bytes2uint(key, 8);
+					k[3] = bytes2uint(key, 12);
+					k[4] = k[5] = k[6] = k[7] = 0;
+					break;
+				case 24:
+					k[0] = bytes2uint(key, 0);
+					k[1] = bytes2uint(key, 4);
+					k[2] = bytes2uint(key, 8);
+					k[3] = bytes2uint(key, 12);
+					k[4] = bytes2uint(key, 16);
+					k[5] = bytes2uint(key, 20);
+					k[6] = ~k[4];
+					k[7] = ~k[5];
+					_keyIs128 = false;
+					break;
+				case 32:
+					k[0] = bytes2uint(key, 0);
+					k[1] = bytes2uint(key, 4);
+					k[2] = bytes2uint(key, 8);
+					k[3] = bytes2uint(key, 12);
+					k[4] = bytes2uint(key, 16);
+					k[5] = bytes2uint(key, 20);
+					k[6] = bytes2uint(key, 24);
+					k[7] = bytes2uint(key, 28);
+					_keyIs128 = false;
+					break;
+				default:
+					throw new ArgumentException("key sizes are only 16/24/32 bytes.");
+			}
+
+			for (int i = 0; i < 4; i++)
+			{
+				ka[i] = k[i] ^ k[i + 4];
+			}
+			/* compute KA */
+			camelliaF2(ka, SIGMA, 0);
+			for (int i = 0; i < 4; i++)
+			{
+				ka[i] ^= k[i];
+			}
+			camelliaF2(ka, SIGMA, 4);
+
+			if (_keyIs128)
+			{
+				if (forEncryption)
+				{
+					/* KL dependant keys */
+					kw[0] = k[0];
+					kw[1] = k[1];
+					kw[2] = k[2];
+					kw[3] = k[3];
+					roldq(15, k, 0, subkey, 4);
+					roldq(30, k, 0, subkey, 12);
+					roldq(15, k, 0, t, 0);
+					subkey[18] = t[2];
+					subkey[19] = t[3];
+					roldq(17, k, 0, ke, 4);
+					roldq(17, k, 0, subkey, 24);
+					roldq(17, k, 0, subkey, 32);
+					/* KA dependant keys */
+					subkey[0] = ka[0];
+					subkey[1] = ka[1];
+					subkey[2] = ka[2];
+					subkey[3] = ka[3];
+					roldq(15, ka, 0, subkey, 8);
+					roldq(15, ka, 0, ke, 0);
+					roldq(15, ka, 0, t, 0);
+					subkey[16] = t[0];
+					subkey[17] = t[1];
+					roldq(15, ka, 0, subkey, 20);
+					roldqo32(34, ka, 0, subkey, 28);
+					roldq(17, ka, 0, kw, 4);
+
+				}
+				else
+				{ // decryption
+					/* KL dependant keys */
+					kw[4] = k[0];
+					kw[5] = k[1];
+					kw[6] = k[2];
+					kw[7] = k[3];
+					decroldq(15, k, 0, subkey, 28);
+					decroldq(30, k, 0, subkey, 20);
+					decroldq(15, k, 0, t, 0);
+					subkey[16] = t[0];
+					subkey[17] = t[1];
+					decroldq(17, k, 0, ke, 0);
+					decroldq(17, k, 0, subkey, 8);
+					decroldq(17, k, 0, subkey, 0);
+					/* KA dependant keys */
+					subkey[34] = ka[0];
+					subkey[35] = ka[1];
+					subkey[32] = ka[2];
+					subkey[33] = ka[3];
+					decroldq(15, ka, 0, subkey, 24);
+					decroldq(15, ka, 0, ke, 4);
+					decroldq(15, ka, 0, t, 0);
+					subkey[18] = t[2];
+					subkey[19] = t[3];
+					decroldq(15, ka, 0, subkey, 12);
+					decroldqo32(34, ka, 0, subkey, 4);
+					roldq(17, ka, 0, kw, 0);
+				}
+			}
+			else
+			{ // 192bit or 256bit
+				/* compute KB */
+				for (int i = 0; i < 4; i++)
+				{
+					kb[i] = ka[i] ^ k[i + 4];
+				}
+				camelliaF2(kb, SIGMA, 8);
+
+				if (forEncryption)
+				{
+					/* KL dependant keys */
+					kw[0] = k[0];
+					kw[1] = k[1];
+					kw[2] = k[2];
+					kw[3] = k[3];
+					roldqo32(45, k, 0, subkey, 16);
+					roldq(15, k, 0, ke, 4);
+					roldq(17, k, 0, subkey, 32);
+					roldqo32(34, k, 0, subkey, 44);
+					/* KR dependant keys */
+					roldq(15, k, 4, subkey, 4);
+					roldq(15, k, 4, ke, 0);
+					roldq(30, k, 4, subkey, 24);
+					roldqo32(34, k, 4, subkey, 36);
+					/* KA dependant keys */
+					roldq(15, ka, 0, subkey, 8);
+					roldq(30, ka, 0, subkey, 20);
+					/* 32bit rotation */
+					ke[8] = ka[1];
+					ke[9] = ka[2];
+					ke[10] = ka[3];
+					ke[11] = ka[0];
+					roldqo32(49, ka, 0, subkey, 40);
+
+					/* KB dependant keys */
+					subkey[0] = kb[0];
+					subkey[1] = kb[1];
+					subkey[2] = kb[2];
+					subkey[3] = kb[3];
+					roldq(30, kb, 0, subkey, 12);
+					roldq(30, kb, 0, subkey, 28);
+					roldqo32(51, kb, 0, kw, 4);
+
+				}
+				else
+				{ // decryption
+					/* KL dependant keys */
+					kw[4] = k[0];
+					kw[5] = k[1];
+					kw[6] = k[2];
+					kw[7] = k[3];
+					decroldqo32(45, k, 0, subkey, 28);
+					decroldq(15, k, 0, ke, 4);
+					decroldq(17, k, 0, subkey, 12);
+					decroldqo32(34, k, 0, subkey, 0);
+					/* KR dependant keys */
+					decroldq(15, k, 4, subkey, 40);
+					decroldq(15, k, 4, ke, 8);
+					decroldq(30, k, 4, subkey, 20);
+					decroldqo32(34, k, 4, subkey, 8);
+					/* KA dependant keys */
+					decroldq(15, ka, 0, subkey, 36);
+					decroldq(30, ka, 0, subkey, 24);
+					/* 32bit rotation */
+					ke[2] = ka[1];
+					ke[3] = ka[2];
+					ke[0] = ka[3];
+					ke[1] = ka[0];
+					decroldqo32(49, ka, 0, subkey, 4);
+
+					/* KB dependant keys */
+					subkey[46] = kb[0];
+					subkey[47] = kb[1];
+					subkey[44] = kb[2];
+					subkey[45] = kb[3];
+					decroldq(30, kb, 0, subkey, 32);
+					decroldq(30, kb, 0, subkey, 16);
+					roldqo32(51, kb, 0, kw, 0);
+				}
+			}
+		}
+
+		private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
+		{
+			for (int i = 0; i < 4; i++)
+			{
+				state[i] = bytes2uint(input, inOff + (i * 4));
+				state[i] ^= kw[i];
+			}
+
+			camelliaF2(state, subkey, 0);
+			camelliaF2(state, subkey, 4);
+			camelliaF2(state, subkey, 8);
+			camelliaFLs(state, ke, 0);
+			camelliaF2(state, subkey, 12);
+			camelliaF2(state, subkey, 16);
+			camelliaF2(state, subkey, 20);
+			camelliaFLs(state, ke, 4);
+			camelliaF2(state, subkey, 24);
+			camelliaF2(state, subkey, 28);
+			camelliaF2(state, subkey, 32);
+
+			state[2] ^= kw[4];
+			state[3] ^= kw[5];
+			state[0] ^= kw[6];
+			state[1] ^= kw[7];
+
+			uint2bytes(state[2], output, outOff);
+			uint2bytes(state[3], output, outOff + 4);
+			uint2bytes(state[0], output, outOff + 8);
+			uint2bytes(state[1], output, outOff + 12);
+
+			return BLOCK_SIZE;
+		}
+
+		private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
+		{
+			for (int i = 0; i < 4; i++)
+			{
+				state[i] = bytes2uint(input, inOff + (i * 4));
+				state[i] ^= kw[i];
+			}
+
+			camelliaF2(state, subkey, 0);
+			camelliaF2(state, subkey, 4);
+			camelliaF2(state, subkey, 8);
+			camelliaFLs(state, ke, 0);
+			camelliaF2(state, subkey, 12);
+			camelliaF2(state, subkey, 16);
+			camelliaF2(state, subkey, 20);
+			camelliaFLs(state, ke, 4);
+			camelliaF2(state, subkey, 24);
+			camelliaF2(state, subkey, 28);
+			camelliaF2(state, subkey, 32);
+			camelliaFLs(state, ke, 8);
+			camelliaF2(state, subkey, 36);
+			camelliaF2(state, subkey, 40);
+			camelliaF2(state, subkey, 44);
+
+			state[2] ^= kw[4];
+			state[3] ^= kw[5];
+			state[0] ^= kw[6];
+			state[1] ^= kw[7];
+
+			uint2bytes(state[2], output, outOff);
+			uint2bytes(state[3], output, outOff + 4);
+			uint2bytes(state[0], output, outOff + 8);
+			uint2bytes(state[1], output, outOff + 12);
+			return BLOCK_SIZE;
+		}
+
+		public CamelliaEngine()
+		{
+		}
+
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (!(parameters is KeyParameter))
+				throw new ArgumentException("only simple KeyParameter expected.");
+
+			setKey(forEncryption, ((KeyParameter)parameters).GetKey());
+
+			initialised = true;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Camellia"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return BLOCK_SIZE;
+		}
+
+		public int ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			if (!initialised)
+				throw new InvalidOperationException("Camellia engine not initialised");
+			if ((inOff + BLOCK_SIZE) > input.Length)
+				throw new DataLengthException("input buffer too short");
+			if ((outOff + BLOCK_SIZE) > output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			if (_keyIs128)
+			{
+				return processBlock128(input, inOff, output, outOff);
+			}
+			else
+			{
+				return processBlock192or256(input, inOff, output, outOff);
+			}
+		}
+
+		public void Reset()
+		{
+			// nothing
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/CamelliaLightEngine.cs b/crypto/src/crypto/engines/CamelliaLightEngine.cs
new file mode 100644
index 000000000..a301eb55e
--- /dev/null
+++ b/crypto/src/crypto/engines/CamelliaLightEngine.cs
@@ -0,0 +1,581 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* Camellia - based on RFC 3713, smaller implementation, about half the size of CamelliaEngine.
+	*/
+	public class CamelliaLightEngine
+		: IBlockCipher
+	{
+		private const int BLOCK_SIZE = 16;
+//		private const int MASK8 = 0xff;
+		private bool initialised;
+		private bool _keyis128;
+
+		private uint[] subkey = new uint[24 * 4];
+		private uint[] kw = new uint[4 * 2]; // for whitening
+		private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1)
+		private uint[] state = new uint[4]; // for encryption and decryption
+
+		private static readonly uint[] SIGMA = {
+			0xa09e667f, 0x3bcc908b,
+			0xb67ae858, 0x4caa73b2,
+			0xc6ef372f, 0xe94f82be,
+			0x54ff53a5, 0xf1d36f1c,
+			0x10e527fa, 0xde682d1d,
+			0xb05688c2, 0xb3e6c1fd
+		};
+
+		/*
+		*
+		* S-box data
+		*
+		*/
+		private static readonly byte[] SBOX1 = {
+			(byte)112, (byte)130, (byte)44, (byte)236,
+			(byte)179, (byte)39, (byte)192, (byte)229,
+			(byte)228, (byte)133, (byte)87, (byte)53,
+			(byte)234, (byte)12, (byte)174, (byte)65,
+			(byte)35, (byte)239, (byte)107, (byte)147,
+			(byte)69, (byte)25, (byte)165, (byte)33,
+			(byte)237, (byte)14, (byte)79, (byte)78,
+			(byte)29, (byte)101, (byte)146, (byte)189,
+			(byte)134, (byte)184, (byte)175, (byte)143,
+			(byte)124, (byte)235, (byte)31, (byte)206,
+			(byte)62, (byte)48, (byte)220, (byte)95,
+			(byte)94, (byte)197, (byte)11, (byte)26,
+			(byte)166, (byte)225, (byte)57, (byte)202,
+			(byte)213, (byte)71, (byte)93, (byte)61,
+			(byte)217, (byte)1, (byte)90, (byte)214,
+			(byte)81, (byte)86, (byte)108, (byte)77,
+			(byte)139, (byte)13, (byte)154, (byte)102,
+			(byte)251, (byte)204, (byte)176, (byte)45,
+			(byte)116, (byte)18, (byte)43, (byte)32,
+			(byte)240, (byte)177, (byte)132, (byte)153,
+			(byte)223, (byte)76, (byte)203, (byte)194,
+			(byte)52, (byte)126, (byte)118, (byte)5,
+			(byte)109, (byte)183, (byte)169, (byte)49,
+			(byte)209, (byte)23, (byte)4, (byte)215,
+			(byte)20, (byte)88, (byte)58, (byte)97,
+			(byte)222, (byte)27, (byte)17, (byte)28,
+			(byte)50, (byte)15, (byte)156, (byte)22,
+			(byte)83, (byte)24, (byte)242, (byte)34,
+			(byte)254, (byte)68, (byte)207, (byte)178,
+			(byte)195, (byte)181, (byte)122, (byte)145,
+			(byte)36, (byte)8, (byte)232, (byte)168,
+			(byte)96, (byte)252, (byte)105, (byte)80,
+			(byte)170, (byte)208, (byte)160, (byte)125,
+			(byte)161, (byte)137, (byte)98, (byte)151,
+			(byte)84, (byte)91, (byte)30, (byte)149,
+			(byte)224, (byte)255, (byte)100, (byte)210,
+			(byte)16, (byte)196, (byte)0, (byte)72,
+			(byte)163, (byte)247, (byte)117, (byte)219,
+			(byte)138, (byte)3, (byte)230, (byte)218,
+			(byte)9, (byte)63, (byte)221, (byte)148,
+			(byte)135, (byte)92, (byte)131, (byte)2,
+			(byte)205, (byte)74, (byte)144, (byte)51,
+			(byte)115, (byte)103, (byte)246, (byte)243,
+			(byte)157, (byte)127, (byte)191, (byte)226,
+			(byte)82, (byte)155, (byte)216, (byte)38,
+			(byte)200, (byte)55, (byte)198, (byte)59,
+			(byte)129, (byte)150, (byte)111, (byte)75,
+			(byte)19, (byte)190, (byte)99, (byte)46,
+			(byte)233, (byte)121, (byte)167, (byte)140,
+			(byte)159, (byte)110, (byte)188, (byte)142,
+			(byte)41, (byte)245, (byte)249, (byte)182,
+			(byte)47, (byte)253, (byte)180, (byte)89,
+			(byte)120, (byte)152, (byte)6, (byte)106,
+			(byte)231, (byte)70, (byte)113, (byte)186,
+			(byte)212, (byte)37, (byte)171, (byte)66,
+			(byte)136, (byte)162, (byte)141, (byte)250,
+			(byte)114, (byte)7, (byte)185, (byte)85,
+			(byte)248, (byte)238, (byte)172, (byte)10,
+			(byte)54, (byte)73, (byte)42, (byte)104,
+			(byte)60, (byte)56, (byte)241, (byte)164,
+			(byte)64, (byte)40, (byte)211, (byte)123,
+			(byte)187, (byte)201, (byte)67, (byte)193,
+			(byte)21, (byte)227, (byte)173, (byte)244,
+			(byte)119, (byte)199, (byte)128, (byte)158
+		};
+
+		private static uint rightRotate(uint x, int s)
+		{
+			return ((x >> s) + (x << (32 - s)));
+		}
+
+		private static uint leftRotate(uint x, int s)
+		{
+			return (x << s) + (x >> (32 - s));
+		}
+
+		private static void roldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[0 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+			ko[1 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+			ko[2 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+			ko[3 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+			ki[0 + ioff] = ko[0 + ooff];
+			ki[1 + ioff] = ko[1 + ooff];
+			ki[2 + ioff] = ko[2 + ooff];
+			ki[3 + ioff] = ko[3 + ooff];
+		}
+
+		private static void decroldq(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[2 + ooff] = (ki[0 + ioff] << rot) | (ki[1 + ioff] >> (32 - rot));
+			ko[3 + ooff] = (ki[1 + ioff] << rot) | (ki[2 + ioff] >> (32 - rot));
+			ko[0 + ooff] = (ki[2 + ioff] << rot) | (ki[3 + ioff] >> (32 - rot));
+			ko[1 + ooff] = (ki[3 + ioff] << rot) | (ki[0 + ioff] >> (32 - rot));
+			ki[0 + ioff] = ko[2 + ooff];
+			ki[1 + ioff] = ko[3 + ooff];
+			ki[2 + ioff] = ko[0 + ooff];
+			ki[3 + ioff] = ko[1 + ooff];
+		}
+
+		private static void roldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[0 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+			ko[1 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+			ko[2 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+			ko[3 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+			ki[0 + ioff] = ko[0 + ooff];
+			ki[1 + ioff] = ko[1 + ooff];
+			ki[2 + ioff] = ko[2 + ooff];
+			ki[3 + ioff] = ko[3 + ooff];
+		}
+
+		private static void decroldqo32(int rot, uint[] ki, int ioff, uint[] ko, int ooff)
+		{
+			ko[2 + ooff] = (ki[1 + ioff] << (rot - 32)) | (ki[2 + ioff] >> (64 - rot));
+			ko[3 + ooff] = (ki[2 + ioff] << (rot - 32)) | (ki[3 + ioff] >> (64 - rot));
+			ko[0 + ooff] = (ki[3 + ioff] << (rot - 32)) | (ki[0 + ioff] >> (64 - rot));
+			ko[1 + ooff] = (ki[0 + ioff] << (rot - 32)) | (ki[1 + ioff] >> (64 - rot));
+			ki[0 + ioff] = ko[2 + ooff];
+			ki[1 + ioff] = ko[3 + ooff];
+			ki[2 + ioff] = ko[0 + ooff];
+			ki[3 + ioff] = ko[1 + ooff];
+		}
+
+		private static uint bytes2uint(byte[] src, int offset)
+		{
+			uint word = 0;
+			for (int i = 0; i < 4; i++)
+			{
+				word = (word << 8) + (uint)src[i + offset];
+			}
+			return word;
+		}
+
+		private static void uint2bytes(uint word, byte[] dst, int offset)
+		{
+			for (int i = 0; i < 4; i++)
+			{
+				dst[(3 - i) + offset] = (byte)word;
+				word >>= 8;
+			}
+		}
+
+		private byte lRot8(byte v, int rot)
+		{
+			return (byte)(((uint)v << rot) | ((uint)v >> (8 - rot)));
+		}
+
+		private uint sbox2(int x)
+		{
+			return (uint)lRot8(SBOX1[x], 1);
+		}
+
+		private uint sbox3(int x)
+		{
+			return (uint)lRot8(SBOX1[x], 7);
+		}
+
+		private uint sbox4(int x)
+		{
+			return (uint)SBOX1[lRot8((byte)x, 1)];
+		}
+
+		private void camelliaF2(uint[] s, uint[] skey, int keyoff)
+		{
+			uint t1, t2, u, v;
+
+			t1 = s[0] ^ skey[0 + keyoff];
+			u = sbox4((byte)t1);
+			u |= (sbox3((byte)(t1 >> 8)) << 8);
+			u |= (sbox2((byte)(t1 >> 16)) << 16);
+			u |= ((uint)(SBOX1[(byte)(t1 >> 24)]) << 24);
+
+			t2 = s[1] ^ skey[1 + keyoff];
+			v = (uint)SBOX1[(byte)t2];
+			v |= (sbox4((byte)(t2 >> 8)) << 8);
+			v |= (sbox3((byte)(t2 >> 16)) << 16);
+			v |= (sbox2((byte)(t2 >> 24)) << 24);
+
+			v = leftRotate(v, 8);
+			u ^= v;
+			v = leftRotate(v, 8) ^ u;
+			u = rightRotate(u, 8) ^ v;
+			s[2] ^= leftRotate(v, 16) ^ u;
+			s[3] ^= leftRotate(u, 8);
+
+			t1 = s[2] ^ skey[2 + keyoff];
+			u = sbox4((byte)t1);
+			u |= sbox3((byte)(t1 >> 8)) << 8;
+			u |= sbox2((byte)(t1 >> 16)) << 16;
+			u |= ((uint)SBOX1[(byte)(t1 >> 24)]) << 24;
+
+			t2 = s[3] ^ skey[3 + keyoff];
+			v = (uint)SBOX1[(byte)t2];
+			v |= sbox4((byte)(t2 >> 8)) << 8;
+			v |= sbox3((byte)(t2 >> 16)) << 16;
+			v |= sbox2((byte)(t2 >> 24)) << 24;
+
+			v = leftRotate(v, 8);
+			u ^= v;
+			v = leftRotate(v, 8) ^ u;
+			u = rightRotate(u, 8) ^ v;
+			s[0] ^= leftRotate(v, 16) ^ u;
+			s[1] ^= leftRotate(u, 8);
+		}
+
+		private void camelliaFLs(uint[] s, uint[] fkey, int keyoff)
+		{
+			s[1] ^= leftRotate(s[0] & fkey[0 + keyoff], 1);
+			s[0] ^= fkey[1 + keyoff] | s[1];
+
+			s[2] ^= fkey[3 + keyoff] | s[3];
+			s[3] ^= leftRotate(fkey[2 + keyoff] & s[2], 1);
+		}
+
+		private void setKey(bool forEncryption, byte[] key)
+		{
+			uint[] k = new uint[8];
+			uint[] ka = new uint[4];
+			uint[] kb = new uint[4];
+			uint[] t = new uint[4];
+
+			switch (key.Length)
+			{
+				case 16:
+					_keyis128 = true;
+					k[0] = bytes2uint(key, 0);
+					k[1] = bytes2uint(key, 4);
+					k[2] = bytes2uint(key, 8);
+					k[3] = bytes2uint(key, 12);
+					k[4] = k[5] = k[6] = k[7] = 0;
+					break;
+				case 24:
+					k[0] = bytes2uint(key, 0);
+					k[1] = bytes2uint(key, 4);
+					k[2] = bytes2uint(key, 8);
+					k[3] = bytes2uint(key, 12);
+					k[4] = bytes2uint(key, 16);
+					k[5] = bytes2uint(key, 20);
+					k[6] = ~k[4];
+					k[7] = ~k[5];
+					_keyis128 = false;
+					break;
+				case 32:
+					k[0] = bytes2uint(key, 0);
+					k[1] = bytes2uint(key, 4);
+					k[2] = bytes2uint(key, 8);
+					k[3] = bytes2uint(key, 12);
+					k[4] = bytes2uint(key, 16);
+					k[5] = bytes2uint(key, 20);
+					k[6] = bytes2uint(key, 24);
+					k[7] = bytes2uint(key, 28);
+					_keyis128 = false;
+					break;
+				default:
+					throw new ArgumentException("key sizes are only 16/24/32 bytes.");
+			}
+
+			for (int i = 0; i < 4; i++)
+			{
+				ka[i] = k[i] ^ k[i + 4];
+			}
+			/* compute KA */
+			camelliaF2(ka, SIGMA, 0);
+			for (int i = 0; i < 4; i++)
+			{
+				ka[i] ^= k[i];
+			}
+			camelliaF2(ka, SIGMA, 4);
+
+			if (_keyis128)
+			{
+				if (forEncryption)
+				{
+					/* KL dependant keys */
+					kw[0] = k[0];
+					kw[1] = k[1];
+					kw[2] = k[2];
+					kw[3] = k[3];
+					roldq(15, k, 0, subkey, 4);
+					roldq(30, k, 0, subkey, 12);
+					roldq(15, k, 0, t, 0);
+					subkey[18] = t[2];
+					subkey[19] = t[3];
+					roldq(17, k, 0, ke, 4);
+					roldq(17, k, 0, subkey, 24);
+					roldq(17, k, 0, subkey, 32);
+					/* KA dependant keys */
+					subkey[0] = ka[0];
+					subkey[1] = ka[1];
+					subkey[2] = ka[2];
+					subkey[3] = ka[3];
+					roldq(15, ka, 0, subkey, 8);
+					roldq(15, ka, 0, ke, 0);
+					roldq(15, ka, 0, t, 0);
+					subkey[16] = t[0];
+					subkey[17] = t[1];
+					roldq(15, ka, 0, subkey, 20);
+					roldqo32(34, ka, 0, subkey, 28);
+					roldq(17, ka, 0, kw, 4);
+
+				}
+				else
+				{ // decryption
+					/* KL dependant keys */
+					kw[4] = k[0];
+					kw[5] = k[1];
+					kw[6] = k[2];
+					kw[7] = k[3];
+					decroldq(15, k, 0, subkey, 28);
+					decroldq(30, k, 0, subkey, 20);
+					decroldq(15, k, 0, t, 0);
+					subkey[16] = t[0];
+					subkey[17] = t[1];
+					decroldq(17, k, 0, ke, 0);
+					decroldq(17, k, 0, subkey, 8);
+					decroldq(17, k, 0, subkey, 0);
+					/* KA dependant keys */
+					subkey[34] = ka[0];
+					subkey[35] = ka[1];
+					subkey[32] = ka[2];
+					subkey[33] = ka[3];
+					decroldq(15, ka, 0, subkey, 24);
+					decroldq(15, ka, 0, ke, 4);
+					decroldq(15, ka, 0, t, 0);
+					subkey[18] = t[2];
+					subkey[19] = t[3];
+					decroldq(15, ka, 0, subkey, 12);
+					decroldqo32(34, ka, 0, subkey, 4);
+					roldq(17, ka, 0, kw, 0);
+				}
+			}
+			else
+			{ // 192bit or 256bit
+				/* compute KB */
+				for (int i = 0; i < 4; i++)
+				{
+					kb[i] = ka[i] ^ k[i + 4];
+				}
+				camelliaF2(kb, SIGMA, 8);
+
+				if (forEncryption)
+				{
+					/* KL dependant keys */
+					kw[0] = k[0];
+					kw[1] = k[1];
+					kw[2] = k[2];
+					kw[3] = k[3];
+					roldqo32(45, k, 0, subkey, 16);
+					roldq(15, k, 0, ke, 4);
+					roldq(17, k, 0, subkey, 32);
+					roldqo32(34, k, 0, subkey, 44);
+					/* KR dependant keys */
+					roldq(15, k, 4, subkey, 4);
+					roldq(15, k, 4, ke, 0);
+					roldq(30, k, 4, subkey, 24);
+					roldqo32(34, k, 4, subkey, 36);
+					/* KA dependant keys */
+					roldq(15, ka, 0, subkey, 8);
+					roldq(30, ka, 0, subkey, 20);
+					/* 32bit rotation */
+					ke[8] = ka[1];
+					ke[9] = ka[2];
+					ke[10] = ka[3];
+					ke[11] = ka[0];
+					roldqo32(49, ka, 0, subkey, 40);
+
+					/* KB dependant keys */
+					subkey[0] = kb[0];
+					subkey[1] = kb[1];
+					subkey[2] = kb[2];
+					subkey[3] = kb[3];
+					roldq(30, kb, 0, subkey, 12);
+					roldq(30, kb, 0, subkey, 28);
+					roldqo32(51, kb, 0, kw, 4);
+
+				}
+				else
+				{ // decryption
+					/* KL dependant keys */
+					kw[4] = k[0];
+					kw[5] = k[1];
+					kw[6] = k[2];
+					kw[7] = k[3];
+					decroldqo32(45, k, 0, subkey, 28);
+					decroldq(15, k, 0, ke, 4);
+					decroldq(17, k, 0, subkey, 12);
+					decroldqo32(34, k, 0, subkey, 0);
+					/* KR dependant keys */
+					decroldq(15, k, 4, subkey, 40);
+					decroldq(15, k, 4, ke, 8);
+					decroldq(30, k, 4, subkey, 20);
+					decroldqo32(34, k, 4, subkey, 8);
+					/* KA dependant keys */
+					decroldq(15, ka, 0, subkey, 36);
+					decroldq(30, ka, 0, subkey, 24);
+					/* 32bit rotation */
+					ke[2] = ka[1];
+					ke[3] = ka[2];
+					ke[0] = ka[3];
+					ke[1] = ka[0];
+					decroldqo32(49, ka, 0, subkey, 4);
+
+					/* KB dependant keys */
+					subkey[46] = kb[0];
+					subkey[47] = kb[1];
+					subkey[44] = kb[2];
+					subkey[45] = kb[3];
+					decroldq(30, kb, 0, subkey, 32);
+					decroldq(30, kb, 0, subkey, 16);
+					roldqo32(51, kb, 0, kw, 0);
+				}
+			}
+		}
+
+		private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
+		{
+			for (int i = 0; i < 4; i++)
+			{
+				state[i] = bytes2uint(input, inOff + (i * 4));
+				state[i] ^= kw[i];
+			}
+
+			camelliaF2(state, subkey, 0);
+			camelliaF2(state, subkey, 4);
+			camelliaF2(state, subkey, 8);
+			camelliaFLs(state, ke, 0);
+			camelliaF2(state, subkey, 12);
+			camelliaF2(state, subkey, 16);
+			camelliaF2(state, subkey, 20);
+			camelliaFLs(state, ke, 4);
+			camelliaF2(state, subkey, 24);
+			camelliaF2(state, subkey, 28);
+			camelliaF2(state, subkey, 32);
+
+			state[2] ^= kw[4];
+			state[3] ^= kw[5];
+			state[0] ^= kw[6];
+			state[1] ^= kw[7];
+
+			uint2bytes(state[2], output, outOff);
+			uint2bytes(state[3], output, outOff + 4);
+			uint2bytes(state[0], output, outOff + 8);
+			uint2bytes(state[1], output, outOff + 12);
+
+			return BLOCK_SIZE;
+		}
+
+		private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
+		{
+			for (int i = 0; i < 4; i++)
+			{
+				state[i] = bytes2uint(input, inOff + (i * 4));
+				state[i] ^= kw[i];
+			}
+
+			camelliaF2(state, subkey, 0);
+			camelliaF2(state, subkey, 4);
+			camelliaF2(state, subkey, 8);
+			camelliaFLs(state, ke, 0);
+			camelliaF2(state, subkey, 12);
+			camelliaF2(state, subkey, 16);
+			camelliaF2(state, subkey, 20);
+			camelliaFLs(state, ke, 4);
+			camelliaF2(state, subkey, 24);
+			camelliaF2(state, subkey, 28);
+			camelliaF2(state, subkey, 32);
+			camelliaFLs(state, ke, 8);
+			camelliaF2(state, subkey, 36);
+			camelliaF2(state, subkey, 40);
+			camelliaF2(state, subkey, 44);
+
+			state[2] ^= kw[4];
+			state[3] ^= kw[5];
+			state[0] ^= kw[6];
+			state[1] ^= kw[7];
+
+			uint2bytes(state[2], output, outOff);
+			uint2bytes(state[3], output, outOff + 4);
+			uint2bytes(state[0], output, outOff + 8);
+			uint2bytes(state[1], output, outOff + 12);
+			return BLOCK_SIZE;
+		}
+
+		public CamelliaLightEngine()
+		{
+			initialised = false;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Camellia"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return BLOCK_SIZE;
+		}
+
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (!(parameters is KeyParameter))
+				throw new ArgumentException("only simple KeyParameter expected.");
+
+			setKey(forEncryption, ((KeyParameter)parameters).GetKey());
+
+			initialised = true;
+		}
+
+		public int ProcessBlock(
+			byte[]	input,
+			int		inOff,
+            byte[]	output,
+			int		outOff)
+		{
+			if (!initialised)
+				throw new InvalidOperationException("Camellia engine not initialised");
+			if ((inOff + BLOCK_SIZE) > input.Length)
+				throw new DataLengthException("input buffer too short");
+			if ((outOff + BLOCK_SIZE) > output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			if (_keyis128)
+			{
+				return processBlock128(input, inOff, output, outOff);
+			}
+			else
+			{
+				return processBlock192or256(input, inOff, output, outOff);
+			}
+		}
+
+		public void Reset()
+		{
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/CamelliaWrapEngine.cs b/crypto/src/crypto/engines/CamelliaWrapEngine.cs
new file mode 100644
index 000000000..49dc833e6
--- /dev/null
+++ b/crypto/src/crypto/engines/CamelliaWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <remarks>
+	/// An implementation of the Camellia key wrapper based on RFC 3657/RFC 3394.
+	/// <p/>
+	/// For further details see: <a href="http://www.ietf.org/rfc/rfc3657.txt">http://www.ietf.org/rfc/rfc3657.txt</a>.
+	/// </remarks>
+	public class CamelliaWrapEngine
+		: Rfc3394WrapEngine
+	{
+		public CamelliaWrapEngine()
+			: base(new CamelliaEngine())
+		{
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/Cast5Engine.cs b/crypto/src/crypto/engines/Cast5Engine.cs
new file mode 100644
index 000000000..4c3f84a55
--- /dev/null
+++ b/crypto/src/crypto/engines/Cast5Engine.cs
@@ -0,0 +1,802 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * A class that provides CAST key encryption operations,
+    * such as encoding data and generating keys.
+    *
+    * All the algorithms herein are from the Internet RFC's
+    *
+    * RFC2144 - Cast5 (64bit block, 40-128bit key)
+    * RFC2612 - CAST6 (128bit block, 128-256bit key)
+    *
+    * and implement a simplified cryptography interface.
+    */
+    public class Cast5Engine
+		: IBlockCipher
+    {
+		internal static readonly uint[] S1 =
+		{
+			0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+			0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+			0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+			0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+			0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+			0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+			0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+			0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+			0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+			0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+			0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+			0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+			0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+			0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+			0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+			0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+			0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+			0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+			0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+			0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+			0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+			0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+			0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+			0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+			0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+			0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+			0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+			0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+			0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+			0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+			0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+			0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
+		},
+		S2 =
+		{
+			0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+			0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+			0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+			0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+			0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+			0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+			0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+			0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+			0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+			0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+			0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+			0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+			0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+			0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+			0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+			0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+			0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+			0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+			0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+			0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+			0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+			0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+			0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+			0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+			0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+			0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+			0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+			0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+			0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+			0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+			0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+			0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
+		},
+		S3 =
+		{
+			0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+			0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+			0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+			0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+			0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+			0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+			0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+			0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+			0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+			0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+			0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+			0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+			0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+			0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+			0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+			0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+			0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+			0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+			0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+			0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+			0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+			0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+			0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+			0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+			0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+			0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+			0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+			0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+			0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+			0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+			0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+			0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
+		},
+		S4 =
+		{
+			0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+			0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+			0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+			0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+			0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+			0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+			0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+			0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+			0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+			0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+			0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+			0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+			0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+			0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+			0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+			0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+			0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+			0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+			0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+			0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+			0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+			0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+			0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+			0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+			0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+			0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+			0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+			0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+			0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+			0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+			0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+			0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
+		},
+		S5 =
+		{
+			0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+			0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+			0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+			0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+			0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+			0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+			0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+			0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+			0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+			0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+			0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+			0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+			0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+			0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+			0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+			0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+			0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+			0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+			0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+			0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+			0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+			0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+			0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+			0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+			0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+			0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+			0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+			0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+			0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+			0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+			0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+			0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
+		},
+		S6 =
+		{
+			0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+			0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+			0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+			0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+			0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+			0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+			0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+			0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+			0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+			0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+			0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+			0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+			0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+			0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+			0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+			0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+			0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+			0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+			0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+			0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+			0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+			0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+			0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+			0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+			0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+			0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+			0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+			0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+			0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+			0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+			0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+			0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
+		},
+		S7 =
+		{
+			0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+			0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+			0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+			0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+			0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+			0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+			0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+			0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+			0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+			0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+			0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+			0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+			0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+			0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+			0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+			0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+			0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+			0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+			0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+			0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+			0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+			0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+			0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+			0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+			0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+			0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+			0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+			0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+			0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+			0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+			0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+			0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
+		},
+		S8 =
+		{
+			0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+			0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+			0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+			0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+			0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+			0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+			0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+			0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+			0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+			0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+			0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+			0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+			0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+			0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+			0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+			0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+			0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+			0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+			0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+			0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+			0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+			0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+			0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+			0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+			0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+			0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+			0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+			0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+			0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+			0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+			0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+			0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
+		};
+
+        //====================================
+        // Useful constants
+        //====================================
+
+        internal static readonly int MAX_ROUNDS = 16;
+        internal static readonly int RED_ROUNDS = 12;
+
+        private const int BLOCK_SIZE = 8;  // bytes = 64 bits
+
+        private int[] _Kr = new int[17];        // the rotating round key
+        private uint[] _Km = new uint[17];        // the masking round key
+
+        private bool _encrypting;
+
+        private byte[] _workingKey;
+        private int _rounds = MAX_ROUNDS;
+
+        public Cast5Engine()
+        {
+        }
+
+        /**
+        * initialise a CAST cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is KeyParameter))
+				throw new ArgumentException("Invalid parameter passed to "+ AlgorithmName +" init - " + parameters.GetType().ToString());
+
+			_encrypting = forEncryption;
+			_workingKey = ((KeyParameter)parameters).GetKey();
+			SetKey(_workingKey);
+        }
+
+		public virtual string AlgorithmName
+        {
+            get { return "CAST5"; }
+        }
+
+		public virtual bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public virtual int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+			int blockSize = GetBlockSize();
+            if (_workingKey == null)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+            if ((inOff + blockSize) > input.Length)
+                throw new DataLengthException("Input buffer too short");
+            if ((outOff + blockSize) > output.Length)
+                throw new DataLengthException("Output buffer too short");
+
+			if (_encrypting)
+            {
+                return EncryptBlock(input, inOff, output, outOff);
+            }
+            else
+            {
+                return DecryptBlock(input, inOff, output, outOff);
+            }
+        }
+
+        public virtual void Reset()
+        {
+        }
+
+        public virtual int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        //==================================
+        // Private Implementation
+        //==================================
+
+        /*
+        * Creates the subkeys using the same nomenclature
+        * as described in RFC2144.
+        *
+        * See section 2.4
+        */
+        internal virtual void SetKey(byte[] key)
+        {
+            /*
+            * Determine the key size here, if required
+            *
+            * if keysize <= 80bits, use 12 rounds instead of 16
+            * if keysize < 128bits, pad with 0
+            *
+            * Typical key sizes => 40, 64, 80, 128
+            */
+
+            if (key.Length < 11)
+            {
+                _rounds = RED_ROUNDS;
+            }
+
+            int [] z = new int[16];
+            int [] x = new int[16];
+
+            uint z03, z47, z8B, zCF;
+            uint x03, x47, x8B, xCF;
+
+            /* copy the key into x */
+            for (int i=0; i< key.Length; i++)
+            {
+                x[i] = (int)(key[i] & 0xff);
+            }
+
+            /*
+            * This will look different because the selection of
+            * bytes from the input key I've already chosen the
+            * correct int.
+            */
+            x03 = IntsTo32bits(x, 0x0);
+            x47 = IntsTo32bits(x, 0x4);
+            x8B = IntsTo32bits(x, 0x8);
+            xCF = IntsTo32bits(x, 0xC);
+
+            z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+
+            Bits32ToInts(z03, z, 0x0);
+            z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+            Bits32ToInts(z47, z, 0x4);
+            z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+            Bits32ToInts(z8B, z, 0x8);
+            zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+            Bits32ToInts(zCF, z, 0xC);
+            _Km[ 1]= S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]];
+            _Km[ 2]= S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]];
+            _Km[ 3]= S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]];
+            _Km[ 4]= S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]];
+
+            z03 = IntsTo32bits(z, 0x0);
+            z47 = IntsTo32bits(z, 0x4);
+            z8B = IntsTo32bits(z, 0x8);
+            zCF = IntsTo32bits(z, 0xC);
+            x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+            Bits32ToInts(x03, x, 0x0);
+            x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+            Bits32ToInts(x47, x, 0x4);
+            x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+            Bits32ToInts(x8B, x, 0x8);
+            xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+            Bits32ToInts(xCF, x, 0xC);
+            _Km[ 5]= S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]];
+            _Km[ 6]= S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]];
+            _Km[ 7]= S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]];
+            _Km[ 8]= S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]];
+
+            x03 = IntsTo32bits(x, 0x0);
+            x47 = IntsTo32bits(x, 0x4);
+            x8B = IntsTo32bits(x, 0x8);
+            xCF = IntsTo32bits(x, 0xC);
+            z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+            Bits32ToInts(z03, z, 0x0);
+            z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+            Bits32ToInts(z47, z, 0x4);
+            z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+            Bits32ToInts(z8B, z, 0x8);
+            zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+            Bits32ToInts(zCF, z, 0xC);
+            _Km[ 9]= S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]];
+            _Km[10]= S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]];
+            _Km[11]= S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]];
+            _Km[12]= S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]];
+
+            z03 = IntsTo32bits(z, 0x0);
+            z47 = IntsTo32bits(z, 0x4);
+            z8B = IntsTo32bits(z, 0x8);
+            zCF = IntsTo32bits(z, 0xC);
+            x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+            Bits32ToInts(x03, x, 0x0);
+            x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+            Bits32ToInts(x47, x, 0x4);
+            x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+            Bits32ToInts(x8B, x, 0x8);
+            xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+            Bits32ToInts(xCF, x, 0xC);
+            _Km[13]= S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]];
+            _Km[14]= S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]];
+            _Km[15]= S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]];
+            _Km[16]= S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]];
+
+            x03 = IntsTo32bits(x, 0x0);
+            x47 = IntsTo32bits(x, 0x4);
+            x8B = IntsTo32bits(x, 0x8);
+            xCF = IntsTo32bits(x, 0xC);
+            z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+            Bits32ToInts(z03, z, 0x0);
+            z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+            Bits32ToInts(z47, z, 0x4);
+            z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+            Bits32ToInts(z8B, z, 0x8);
+            zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+            Bits32ToInts(zCF, z, 0xC);
+            _Kr[ 1]=(int)((S5[z[0x8]]^S6[z[0x9]]^S7[z[0x7]]^S8[z[0x6]] ^ S5[z[0x2]])&0x1f);
+            _Kr[ 2]=(int)((S5[z[0xA]]^S6[z[0xB]]^S7[z[0x5]]^S8[z[0x4]] ^ S6[z[0x6]])&0x1f);
+            _Kr[ 3]=(int)((S5[z[0xC]]^S6[z[0xD]]^S7[z[0x3]]^S8[z[0x2]] ^ S7[z[0x9]])&0x1f);
+            _Kr[ 4]=(int)((S5[z[0xE]]^S6[z[0xF]]^S7[z[0x1]]^S8[z[0x0]] ^ S8[z[0xC]])&0x1f);
+
+            z03 = IntsTo32bits(z, 0x0);
+            z47 = IntsTo32bits(z, 0x4);
+            z8B = IntsTo32bits(z, 0x8);
+            zCF = IntsTo32bits(z, 0xC);
+            x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+            Bits32ToInts(x03, x, 0x0);
+            x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+            Bits32ToInts(x47, x, 0x4);
+            x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+            Bits32ToInts(x8B, x, 0x8);
+            xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+            Bits32ToInts(xCF, x, 0xC);
+            _Kr[ 5]=(int)((S5[x[0x3]]^S6[x[0x2]]^S7[x[0xC]]^S8[x[0xD]]^S5[x[0x8]])&0x1f);
+            _Kr[ 6]=(int)((S5[x[0x1]]^S6[x[0x0]]^S7[x[0xE]]^S8[x[0xF]]^S6[x[0xD]])&0x1f);
+            _Kr[ 7]=(int)((S5[x[0x7]]^S6[x[0x6]]^S7[x[0x8]]^S8[x[0x9]]^S7[x[0x3]])&0x1f);
+            _Kr[ 8]=(int)((S5[x[0x5]]^S6[x[0x4]]^S7[x[0xA]]^S8[x[0xB]]^S8[x[0x7]])&0x1f);
+
+            x03 = IntsTo32bits(x, 0x0);
+            x47 = IntsTo32bits(x, 0x4);
+            x8B = IntsTo32bits(x, 0x8);
+            xCF = IntsTo32bits(x, 0xC);
+            z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
+            Bits32ToInts(z03, z, 0x0);
+            z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
+            Bits32ToInts(z47, z, 0x4);
+            z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
+            Bits32ToInts(z8B, z, 0x8);
+            zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
+            Bits32ToInts(zCF, z, 0xC);
+            _Kr[ 9]=(int)((S5[z[0x3]]^S6[z[0x2]]^S7[z[0xC]]^S8[z[0xD]]^S5[z[0x9]])&0x1f);
+            _Kr[10]=(int)((S5[z[0x1]]^S6[z[0x0]]^S7[z[0xE]]^S8[z[0xF]]^S6[z[0xc]])&0x1f);
+            _Kr[11]=(int)((S5[z[0x7]]^S6[z[0x6]]^S7[z[0x8]]^S8[z[0x9]]^S7[z[0x2]])&0x1f);
+            _Kr[12]=(int)((S5[z[0x5]]^S6[z[0x4]]^S7[z[0xA]]^S8[z[0xB]]^S8[z[0x6]])&0x1f);
+
+            z03 = IntsTo32bits(z, 0x0);
+            z47 = IntsTo32bits(z, 0x4);
+            z8B = IntsTo32bits(z, 0x8);
+            zCF = IntsTo32bits(z, 0xC);
+            x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
+            Bits32ToInts(x03, x, 0x0);
+            x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
+            Bits32ToInts(x47, x, 0x4);
+            x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
+            Bits32ToInts(x8B, x, 0x8);
+            xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
+            Bits32ToInts(xCF, x, 0xC);
+            _Kr[13]=(int)((S5[x[0x8]]^S6[x[0x9]]^S7[x[0x7]]^S8[x[0x6]]^S5[x[0x3]])&0x1f);
+            _Kr[14]=(int)((S5[x[0xA]]^S6[x[0xB]]^S7[x[0x5]]^S8[x[0x4]]^S6[x[0x7]])&0x1f);
+            _Kr[15]=(int)((S5[x[0xC]]^S6[x[0xD]]^S7[x[0x3]]^S8[x[0x2]]^S7[x[0x8]])&0x1f);
+            _Kr[16]=(int)((S5[x[0xE]]^S6[x[0xF]]^S7[x[0x1]]^S8[x[0x0]]^S8[x[0xD]])&0x1f);
+        }
+
+        /**
+        * Encrypt the given input starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param src        The plaintext buffer
+        * @param srcIndex    An offset into src
+        * @param dst        The ciphertext buffer
+        * @param dstIndex    An offset into dst
+        */
+        internal virtual int EncryptBlock(
+            byte[] src,
+            int srcIndex,
+            byte[] dst,
+            int dstIndex)
+        {
+            // process the input block
+            // batch the units up into a 32 bit chunk and go for it
+            // the array is in bytes, the increment is 8x8 bits = 64
+
+            uint L0 = Pack.BE_To_UInt32(src, srcIndex);
+            uint R0 = Pack.BE_To_UInt32(src, srcIndex + 4);
+
+            uint[] result = new uint[2];
+            CAST_Encipher(L0, R0, result);
+
+            // now stuff them into the destination block
+            Pack.UInt32_To_BE(result[0], dst, dstIndex);
+            Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+
+            return BLOCK_SIZE;
+        }
+
+        /**
+        * Decrypt the given input starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param src        The plaintext buffer
+        * @param srcIndex    An offset into src
+        * @param dst        The ciphertext buffer
+        * @param dstIndex    An offset into dst
+        */
+        internal virtual int DecryptBlock(
+            byte[] src,
+            int srcIndex,
+            byte[] dst,
+            int dstIndex)
+        {
+            // process the input block
+            // batch the units up into a 32 bit chunk and go for it
+            // the array is in bytes, the increment is 8x8 bits = 64
+            uint L16 = Pack.BE_To_UInt32(src, srcIndex);
+            uint R16 = Pack.BE_To_UInt32(src, srcIndex + 4);
+
+            uint[] result = new uint[2];
+            CAST_Decipher(L16, R16, result);
+
+            // now stuff them into the destination block
+            Pack.UInt32_To_BE(result[0], dst, dstIndex);
+            Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+
+            return BLOCK_SIZE;
+        }
+
+        /**
+        * The first of the three processing functions for the
+        * encryption and decryption.
+        *
+        * @param D            the input to be processed
+        * @param Kmi        the mask to be used from Km[n]
+        * @param Kri        the rotation value to be used
+        *
+        */
+        internal static uint F1(uint D, uint Kmi, int Kri)
+        {
+            uint I = Kmi + D;
+            I = I << Kri | (I >> (32-Kri));
+            return ((S1[(I>>24)&0xff]^S2[(I>>16)&0xff])-S3[(I>>8)&0xff])+S4[I&0xff];
+        }
+
+        /**
+        * The second of the three processing functions for the
+        * encryption and decryption.
+        *
+        * @param D            the input to be processed
+        * @param Kmi        the mask to be used from Km[n]
+        * @param Kri        the rotation value to be used
+        *
+        */
+        internal static uint F2(uint D, uint Kmi, int Kri)
+        {
+            uint I = Kmi ^ D;
+            I = I << Kri | (I >> (32-Kri));
+            return ((S1[(I>>24)&0xff]-S2[(I>>16)&0xff])+S3[(I>>8)&0xff])^S4[I&0xff];
+        }
+
+        /**
+        * The third of the three processing functions for the
+        * encryption and decryption.
+        *
+        * @param D            the input to be processed
+        * @param Kmi        the mask to be used from Km[n]
+        * @param Kri        the rotation value to be used
+        *
+        */
+        internal static uint F3(uint D, uint Kmi, int Kri)
+        {
+            uint I = Kmi - D;
+            I = I << Kri | (I >> (32-Kri));
+            return ((S1[(I>>24)&0xff]+S2[(I>>16)&0xff])^S3[(I>>8)&0xff])-S4[I&0xff];
+        }
+
+        /**
+        * Does the 16 rounds to encrypt the block.
+        *
+        * @param L0    the LH-32bits of the plaintext block
+        * @param R0    the RH-32bits of the plaintext block
+        */
+        internal void CAST_Encipher(uint L0, uint R0, uint[] result)
+        {
+            uint Lp = L0;        // the previous value, equiv to L[i-1]
+            uint Rp = R0;        // equivalent to R[i-1]
+
+            /*
+            * numbering consistent with paper to make
+            * checking and validating easier
+            */
+            uint Li = L0, Ri = R0;
+
+            for (int i = 1; i<=_rounds ; i++)
+            {
+                Lp = Li;
+                Rp = Ri;
+
+                Li = Rp;
+                switch (i)
+                {
+                    case  1:
+                    case  4:
+                    case  7:
+                    case 10:
+                    case 13:
+                    case 16:
+                        Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
+                        break;
+                    case  2:
+                    case  5:
+                    case  8:
+                    case 11:
+                    case 14:
+                        Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
+                        break;
+                    case  3:
+                    case  6:
+                    case  9:
+                    case 12:
+                    case 15:
+                        Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
+                        break;
+                }
+            }
+
+            result[0] = Ri;
+            result[1] = Li;
+
+            return;
+        }
+
+        internal void CAST_Decipher(uint L16, uint R16, uint[] result)
+        {
+            uint Lp = L16;        // the previous value, equiv to L[i-1]
+            uint Rp = R16;        // equivalent to R[i-1]
+
+            /*
+            * numbering consistent with paper to make
+            * checking and validating easier
+            */
+            uint Li = L16, Ri = R16;
+
+            for (int i = _rounds; i > 0; i--)
+            {
+                Lp = Li;
+                Rp = Ri;
+
+                Li = Rp;
+                switch (i)
+                {
+                    case  1:
+                    case  4:
+                    case  7:
+                    case 10:
+                    case 13:
+                    case 16:
+                        Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
+                        break;
+                    case  2:
+                    case  5:
+                    case  8:
+                    case 11:
+                    case 14:
+                        Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
+                        break;
+                    case  3:
+                    case  6:
+                    case  9:
+                    case 12:
+                    case 15:
+                        Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
+                        break;
+                }
+            }
+
+            result[0] = Ri;
+            result[1] = Li;
+
+            return;
+        }
+
+        internal static void Bits32ToInts(uint inData, int[] b, int offset)
+        {
+            b[offset + 3] = (int) (inData & 0xff);
+            b[offset + 2] = (int) ((inData >> 8) & 0xff);
+            b[offset + 1] = (int) ((inData >> 16) & 0xff);
+            b[offset]     = (int) ((inData >> 24) & 0xff);
+        }
+
+        internal static uint IntsTo32bits(int[] b, int i)
+        {
+            return (uint)(((b[i]   & 0xff) << 24) |
+                ((b[i+1] & 0xff) << 16) |
+                ((b[i+2] & 0xff) << 8) |
+                ((b[i+3] & 0xff)));
+        }
+    }
+}
diff --git a/crypto/src/crypto/engines/Cast6Engine.cs b/crypto/src/crypto/engines/Cast6Engine.cs
new file mode 100644
index 000000000..c5c419b78
--- /dev/null
+++ b/crypto/src/crypto/engines/Cast6Engine.cs
@@ -0,0 +1,279 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+     * A class that provides CAST6 key encryption operations,
+     * such as encoding data and generating keys.
+     *
+     * All the algorithms herein are from the Internet RFC
+     *
+     * RFC2612 - CAST6 (128bit block, 128-256bit key)
+     *
+     * and implement a simplified cryptography interface.
+     */
+    public sealed class Cast6Engine
+		: Cast5Engine
+    {
+        //====================================
+        // Useful constants
+        //====================================
+        private const int ROUNDS = 12;
+        private const int BLOCK_SIZE = 16;  // bytes = 128 bits
+
+		/*
+        * Put the round and mask keys into an array.
+        * Kr0[i] => _Kr[i*4 + 0]
+        */
+        private int []_Kr = new int[ROUNDS*4]; // the rotating round key(s)
+        private uint []_Km = new uint[ROUNDS*4]; // the masking round key(s)
+
+		/*
+        * Key setup
+        */
+        private int []_Tr = new int[24 * 8];
+        private uint []_Tm = new uint[24 * 8];
+        private uint[] _workingKey = new uint[8];
+
+		public Cast6Engine()
+        {
+        }
+
+		public override string AlgorithmName
+        {
+            get { return "CAST6"; }
+        }
+
+		public override void Reset()
+        {
+        }
+
+		public override int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+		//==================================
+        // Private Implementation
+        //==================================
+        /*
+        * Creates the subkeys using the same nomenclature
+        * as described in RFC2612.
+        *
+        * See section 2.4
+        */
+        internal override void SetKey(
+			byte[] key)
+        {
+            uint Cm = 0x5a827999;
+            uint Mm = 0x6ed9eba1;
+            int Cr = 19;
+            int Mr = 17;
+            /*
+            * Determine the key size here, if required
+            *
+            * if keysize < 256 bytes, pad with 0
+            *
+            * Typical key sizes => 128, 160, 192, 224, 256
+            */
+            for (int i=0; i< 24; i++)
+            {
+                for (int j=0; j< 8; j++)
+                {
+                    _Tm[i*8 + j] = Cm;
+                    Cm += Mm; //mod 2^32;
+                    _Tr[i*8 + j] = Cr;
+                    Cr = (Cr + Mr) & 0x1f;            // mod 32
+                }
+            }
+
+			byte[] tmpKey = new byte[64];
+			key.CopyTo(tmpKey, 0);
+
+			// now create ABCDEFGH
+            for (int i = 0; i < 8; i++)
+            {
+                _workingKey[i] = Pack.BE_To_UInt32(tmpKey, i*4);
+            }
+
+			// Generate the key schedule
+            for (int i = 0; i < 12; i++)
+            {
+                // KAPPA <- W2i(KAPPA)
+                int i2 = i*2 *8;
+                _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+                _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+                _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+                _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+                _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+                _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+                _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+                _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+                // KAPPA <- W2i+1(KAPPA)
+                i2 = (i*2 + 1)*8;
+                _workingKey[6] ^= F1(_workingKey[7], _Tm[i2], _Tr[i2]);
+                _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]);
+                _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]);
+                _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]);
+                _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]);
+                _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]);
+                _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]);
+                _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]);
+                // Kr_(i) <- KAPPA
+                _Kr[i*4] = (int)(_workingKey[0] & 0x1f);
+                _Kr[i*4 + 1] = (int)(_workingKey[2] & 0x1f);
+                _Kr[i*4 + 2] = (int)(_workingKey[4] & 0x1f);
+                _Kr[i*4 + 3] = (int)(_workingKey[6] & 0x1f);
+                // Km_(i) <- KAPPA
+                _Km[i*4] = _workingKey[7];
+                _Km[i*4 + 1] = _workingKey[5];
+                _Km[i*4 + 2] = _workingKey[3];
+                _Km[i*4 + 3] = _workingKey[1];
+            }
+        }
+
+		/**
+        * Encrypt the given input starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param src        The plaintext buffer
+        * @param srcIndex    An offset into src
+        * @param dst        The ciphertext buffer
+        * @param dstIndex    An offset into dst
+        */
+        internal override int EncryptBlock(
+            byte[]	src,
+            int		srcIndex,
+            byte[]	dst,
+            int		dstIndex)
+        {
+            // process the input block
+            // batch the units up into 4x32 bit chunks and go for it
+            uint A = Pack.BE_To_UInt32(src, srcIndex);
+            uint B = Pack.BE_To_UInt32(src, srcIndex + 4);
+            uint C = Pack.BE_To_UInt32(src, srcIndex + 8);
+            uint D = Pack.BE_To_UInt32(src, srcIndex + 12);
+            uint[] result = new uint[4];
+            CAST_Encipher(A, B, C, D, result);
+            // now stuff them into the destination block
+            Pack.UInt32_To_BE(result[0], dst, dstIndex);
+            Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+            Pack.UInt32_To_BE(result[2], dst, dstIndex + 8);
+            Pack.UInt32_To_BE(result[3], dst, dstIndex + 12);
+            return BLOCK_SIZE;
+        }
+
+		/**
+        * Decrypt the given input starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param src        The plaintext buffer
+        * @param srcIndex    An offset into src
+        * @param dst        The ciphertext buffer
+        * @param dstIndex    An offset into dst
+        */
+        internal override int DecryptBlock(
+            byte[]	src,
+            int		srcIndex,
+            byte[]	dst,
+            int		dstIndex)
+        {
+            // process the input block
+            // batch the units up into 4x32 bit chunks and go for it
+            uint A = Pack.BE_To_UInt32(src, srcIndex);
+            uint B = Pack.BE_To_UInt32(src, srcIndex + 4);
+            uint C = Pack.BE_To_UInt32(src, srcIndex + 8);
+            uint D = Pack.BE_To_UInt32(src, srcIndex + 12);
+            uint[] result = new uint[4];
+            CAST_Decipher(A, B, C, D, result);
+            // now stuff them into the destination block
+            Pack.UInt32_To_BE(result[0], dst, dstIndex);
+            Pack.UInt32_To_BE(result[1], dst, dstIndex + 4);
+            Pack.UInt32_To_BE(result[2], dst, dstIndex + 8);
+            Pack.UInt32_To_BE(result[3], dst, dstIndex + 12);
+            return BLOCK_SIZE;
+        }
+
+		/**
+        * Does the 12 quad rounds rounds to encrypt the block.
+        *
+        * @param A    the 00-31  bits of the plaintext block
+        * @param B    the 32-63  bits of the plaintext block
+        * @param C    the 64-95  bits of the plaintext block
+        * @param D    the 96-127 bits of the plaintext block
+        * @param result the resulting ciphertext
+        */
+        private void CAST_Encipher(
+			uint	A,
+			uint	B,
+			uint	C,
+			uint	D,
+			uint[]	result)
+        {
+            for (int i = 0; i < 6; i++)
+            {
+                int x = i*4;
+                // BETA <- Qi(BETA)
+                C ^= F1(D, _Km[x], _Kr[x]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+            }
+            for (int i = 6; i < 12; i++)
+            {
+                int x = i*4;
+                // BETA <- QBARi(BETA)
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                C ^= F1(D, _Km[x], _Kr[x]);
+            }
+            result[0] = A;
+            result[1] = B;
+            result[2] = C;
+            result[3] = D;
+        }
+
+		/**
+        * Does the 12 quad rounds rounds to decrypt the block.
+        *
+        * @param A    the 00-31  bits of the ciphertext block
+        * @param B    the 32-63  bits of the ciphertext block
+        * @param C    the 64-95  bits of the ciphertext block
+        * @param D    the 96-127 bits of the ciphertext block
+        * @param result the resulting plaintext
+        */
+        private void CAST_Decipher(
+			uint	A,
+			uint	B,
+			uint	C,
+			uint	D,
+			uint[]	result)
+        {
+            for (int i = 0; i < 6; i++)
+            {
+                int x = (11-i)*4;
+                // BETA <- Qi(BETA)
+                C ^= F1(D, _Km[x], _Kr[x]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+            }
+            for (int i=6; i<12; i++)
+            {
+                int x = (11-i)*4;
+                // BETA <- QBARi(BETA)
+                D ^= F1(A, _Km[x + 3], _Kr[x + 3]);
+                A ^= F3(B, _Km[x + 2], _Kr[x + 2]);
+                B ^= F2(C, _Km[x + 1], _Kr[x + 1]);
+                C ^= F1(D, _Km[x], _Kr[x]);
+            }
+            result[0] = A;
+            result[1] = B;
+            result[2] = C;
+            result[3] = D;
+        }
+    }
+}
diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs
new file mode 100644
index 000000000..f4a7b8fe1
--- /dev/null
+++ b/crypto/src/crypto/engines/ChaChaEngine.cs
@@ -0,0 +1,189 @@
+using System;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <summary>
+	/// Implementation of Daniel J. Bernstein's ChaCha stream cipher.
+	/// </summary>
+	public class ChaChaEngine
+		: Salsa20Engine
+	{
+
+		/// <summary>
+		/// Creates a 20 rounds ChaCha engine.
+		/// </summary>
+		public ChaChaEngine()
+		{
+		}
+
+		/// <summary>
+		/// Creates a ChaCha engine with a specific number of rounds.
+		/// </summary>
+		/// <param name="rounds">the number of rounds (must be an even number).</param>
+		public ChaChaEngine(int rounds)
+			: base(rounds)
+		{
+		}
+
+		public override string AlgorithmName
+		{
+			get { return "ChaCha" + rounds; }
+		}
+
+		protected override void AdvanceCounter()
+		{
+			if (++engineState[12] == 0)
+			{
+				++engineState[13];
+			}
+		}
+
+		protected override void ResetCounter()
+		{
+			engineState[12] = engineState[13] = 0;
+		}
+
+		protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
+		{
+			if ((keyBytes.Length != 16) && (keyBytes.Length != 32))
+			{
+				throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
+			}
+
+			int offset = 0;
+			byte[] constants;
+
+			// Key
+			engineState[4] = Pack.LE_To_UInt32(keyBytes, 0);
+			engineState[5] = Pack.LE_To_UInt32(keyBytes, 4);
+			engineState[6] = Pack.LE_To_UInt32(keyBytes, 8);
+			engineState[7] = Pack.LE_To_UInt32(keyBytes, 12);
+
+			if (keyBytes.Length == 32)
+			{
+				constants = sigma;
+				offset = 16;
+			} else
+			{
+				constants = tau;
+			}
+
+			engineState[8] = Pack.LE_To_UInt32(keyBytes, offset);
+			engineState[9] = Pack.LE_To_UInt32(keyBytes, offset + 4);
+			engineState[10] = Pack.LE_To_UInt32(keyBytes, offset + 8);
+			engineState[11] = Pack.LE_To_UInt32(keyBytes, offset + 12);
+
+			engineState[0] = Pack.LE_To_UInt32(constants, 0);
+			engineState[1] = Pack.LE_To_UInt32(constants, 4);
+			engineState[2] = Pack.LE_To_UInt32(constants, 8);
+			engineState[3] = Pack.LE_To_UInt32(constants, 12);
+
+			// Counter
+			engineState[12] = engineState[13] = 0;
+
+			// IV
+			engineState[14] = Pack.LE_To_UInt32(ivBytes, 0);
+			engineState[15] = Pack.LE_To_UInt32(ivBytes, 4);
+		}
+
+		protected override void GenerateKeyStream(byte[] output)
+		{
+			ChachaCore(rounds, engineState, x);
+			Pack.UInt32_To_LE(x, output, 0);
+		}
+
+		/// <summary>
+		/// ChacCha function.
+		/// </summary>
+		/// <param name="rounds">The number of ChaCha rounds to execute</param>
+		/// <param name="input">The input words.</param>
+		/// <param name="x">The ChaCha state to modify.</param>
+		internal static void ChachaCore(int rounds, uint[] input, uint[] x)
+		{
+			if (input.Length != 16) {
+				throw new ArgumentException();
+			}
+			if (x.Length != 16) {
+				throw new ArgumentException();
+			}
+			if (rounds % 2 != 0) {
+				throw new ArgumentException("Number of rounds must be even");
+			}
+
+			uint x00 = input[ 0];
+			uint x01 = input[ 1];
+			uint x02 = input[ 2];
+			uint x03 = input[ 3];
+			uint x04 = input[ 4];
+			uint x05 = input[ 5];
+			uint x06 = input[ 6];
+			uint x07 = input[ 7];
+			uint x08 = input[ 8];
+			uint x09 = input[ 9];
+			uint x10 = input[10];
+			uint x11 = input[11];
+			uint x12 = input[12];
+			uint x13 = input[13];
+			uint x14 = input[14];
+			uint x15 = input[15];
+
+			for (int i = rounds; i > 0; i -= 2)
+			{
+				x00 += x04; x12 = R(x12 ^ x00, 16);
+				x08 += x12; x04 = R(x04 ^ x08, 12);
+				x00 += x04; x12 = R(x12 ^ x00, 8);
+				x08 += x12; x04 = R(x04 ^ x08, 7);
+				x01 += x05; x13 = R(x13 ^ x01, 16);
+				x09 += x13; x05 = R(x05 ^ x09, 12);
+				x01 += x05; x13 = R(x13 ^ x01, 8);
+				x09 += x13; x05 = R(x05 ^ x09, 7);
+				x02 += x06; x14 = R(x14 ^ x02, 16);
+				x10 += x14; x06 = R(x06 ^ x10, 12);
+				x02 += x06; x14 = R(x14 ^ x02, 8);
+				x10 += x14; x06 = R(x06 ^ x10, 7);
+				x03 += x07; x15 = R(x15 ^ x03, 16);
+				x11 += x15; x07 = R(x07 ^ x11, 12);
+				x03 += x07; x15 = R(x15 ^ x03, 8);
+				x11 += x15; x07 = R(x07 ^ x11, 7);
+				x00 += x05; x15 = R(x15 ^ x00, 16);
+				x10 += x15; x05 = R(x05 ^ x10, 12);
+				x00 += x05; x15 = R(x15 ^ x00, 8);
+				x10 += x15; x05 = R(x05 ^ x10, 7);
+				x01 += x06; x12 = R(x12 ^ x01, 16);
+				x11 += x12; x06 = R(x06 ^ x11, 12);
+				x01 += x06; x12 = R(x12 ^ x01, 8);
+				x11 += x12; x06 = R(x06 ^ x11, 7);
+				x02 += x07; x13 = R(x13 ^ x02, 16);
+				x08 += x13; x07 = R(x07 ^ x08, 12);
+				x02 += x07; x13 = R(x13 ^ x02, 8);
+				x08 += x13; x07 = R(x07 ^ x08, 7);
+				x03 += x04; x14 = R(x14 ^ x03, 16);
+				x09 += x14; x04 = R(x04 ^ x09, 12);
+				x03 += x04; x14 = R(x14 ^ x03, 8);
+				x09 += x14; x04 = R(x04 ^ x09, 7);
+
+			}
+
+			x[ 0] = x00 + input[ 0];
+			x[ 1] = x01 + input[ 1];
+			x[ 2] = x02 + input[ 2];
+			x[ 3] = x03 + input[ 3];
+			x[ 4] = x04 + input[ 4];
+			x[ 5] = x05 + input[ 5];
+			x[ 6] = x06 + input[ 6];
+			x[ 7] = x07 + input[ 7];
+			x[ 8] = x08 + input[ 8];
+			x[ 9] = x09 + input[ 9];
+			x[10] = x10 + input[10];
+			x[11] = x11 + input[11];
+			x[12] = x12 + input[12];
+			x[13] = x13 + input[13];
+			x[14] = x14 + input[14];
+			x[15] = x15 + input[15];
+		}
+
+	}
+
+}
+
diff --git a/crypto/src/crypto/engines/DesEdeEngine.cs b/crypto/src/crypto/engines/DesEdeEngine.cs
index b319888e3..eec4ec59d 100644
--- a/crypto/src/crypto/engines/DesEdeEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeEngine.cs
@@ -4,65 +4,65 @@ using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	/// <remarks>A class that provides a basic DESede (or Triple DES) engine.</remarks>
+    /// <remarks>A class that provides a basic DESede (or Triple DES) engine.</remarks>
     public class DesEdeEngine
-		: DesEngine
+        : DesEngine
     {
         private int[] workingKey1, workingKey2, workingKey3;
         private bool forEncryption;
 
-		/**
-		* initialise a DESede cipher.
-		*
-		* @param forEncryption whether or not we are for encryption.
-		* @param parameters the parameters required to set up the cipher.
-		* @exception ArgumentException if the parameters argument is
-		* inappropriate.
-		*/
-		public override void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			if (!(parameters is KeyParameter))
-			{
-				throw new ArgumentException("invalid parameter passed to DESede init - " + parameters.GetType().ToString());
-			}
+        /**
+        * initialise a DESede cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public override void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is KeyParameter))
+                throw new ArgumentException("invalid parameter passed to DESede init - " + parameters.GetType().ToString());
 
-			byte[] keyMaster = ((KeyParameter)parameters).GetKey();
+            byte[] keyMaster = ((KeyParameter)parameters).GetKey();
+            if (keyMaster.Length != 24 && keyMaster.Length != 16)
+                throw new ArgumentException("key size must be 16 or 24 bytes.");
 
-			this.forEncryption = forEncryption;
+            this.forEncryption = forEncryption;
 
-			byte[] key1 = new byte[8];
-			Array.Copy(keyMaster, 0, key1, 0, key1.Length);
-			workingKey1 = GenerateWorkingKey(forEncryption, key1);
+            byte[] key1 = new byte[8];
+            Array.Copy(keyMaster, 0, key1, 0, key1.Length);
+            workingKey1 = GenerateWorkingKey(forEncryption, key1);
 
-			byte[] key2 = new byte[8];
-			Array.Copy(keyMaster, 8, key2, 0, key2.Length);
-			workingKey2 = GenerateWorkingKey(!forEncryption, key2);
+            byte[] key2 = new byte[8];
+            Array.Copy(keyMaster, 8, key2, 0, key2.Length);
+            workingKey2 = GenerateWorkingKey(!forEncryption, key2);
 
-			if (keyMaster.Length == 24)
-			{
-				byte[] key3 = new byte[8];
-				Array.Copy(keyMaster, 16, key3, 0, key3.Length);
-				workingKey3 = GenerateWorkingKey(forEncryption, key3);
-			}
-			else        // 16 byte key
-			{
-				workingKey3 = workingKey1;
-			}
-		}
+            if (keyMaster.Length == 24)
+            {
+                byte[] key3 = new byte[8];
+                Array.Copy(keyMaster, 16, key3, 0, key3.Length);
+                workingKey3 = GenerateWorkingKey(forEncryption, key3);
+            }
+            else        // 16 byte key
+            {
+                workingKey3 = workingKey1;
+            }
+        }
 
-		public override string AlgorithmName
+        public override string AlgorithmName
         {
             get { return "DESede"; }
         }
 
-		public override int GetBlockSize()
+        public override int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-		public override int ProcessBlock(
+        public override int ProcessBlock(
             byte[]	input,
             int		inOff,
             byte[]	output,
@@ -75,9 +75,9 @@ namespace Org.BouncyCastle.Crypto.Engines
             if ((outOff + BLOCK_SIZE) > output.Length)
                 throw new DataLengthException("output buffer too short");
 
-			byte[] temp = new byte[BLOCK_SIZE];
+            byte[] temp = new byte[BLOCK_SIZE];
 
-			if (forEncryption)
+            if (forEncryption)
             {
                 DesFunc(workingKey1, input, inOff, temp, 0);
                 DesFunc(workingKey2, temp, 0, temp, 0);
@@ -90,10 +90,10 @@ namespace Org.BouncyCastle.Crypto.Engines
                 DesFunc(workingKey1, temp, 0, output, outOff);
             }
 
-			return BLOCK_SIZE;
+            return BLOCK_SIZE;
         }
 
-		public override void Reset()
+        public override void Reset()
         {
         }
     }
diff --git a/crypto/src/crypto/engines/DesEdeWrapEngine.cs b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
new file mode 100644
index 000000000..fdc71687f
--- /dev/null
+++ b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
@@ -0,0 +1,322 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * 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>
+    * <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.</li>
+    * </ul>
+	* </p>
+    */
+    public class DesEdeWrapEngine
+		: IWrapper
+    {
+        /** Field engine */
+        private CbcBlockCipher engine;
+        /** Field param */
+        private KeyParameter param;
+        /** Field paramPlusIV */
+        private ParametersWithIV paramPlusIV;
+        /** Field iv */
+        private byte[] iv;
+        /** Field forWrapping */
+        private bool forWrapping;
+        /** Field IV2           */
+        private static readonly byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+                                            (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+                                            (byte) 0x21, (byte) 0x05 };
+
+		//
+        // checksum digest
+        //
+        private readonly IDigest sha1 = new Sha1Digest();
+        private readonly byte[] digest = new byte[20];
+
+		/**
+        * Method init
+        *
+        * @param forWrapping
+        * @param param
+        */
+        public void Init(
+			bool				forWrapping,
+			ICipherParameters	parameters)
+        {
+            this.forWrapping = forWrapping;
+            this.engine = new CbcBlockCipher(new DesEdeEngine());
+
+			SecureRandom sr;
+			if (parameters is ParametersWithRandom)
+			{
+				ParametersWithRandom pr = (ParametersWithRandom) parameters;
+				parameters = pr.Parameters;
+				sr = pr.Random;
+			}
+			else
+			{
+				sr = new SecureRandom();
+			}
+
+			if (parameters is KeyParameter)
+            {
+                this.param = (KeyParameter) parameters;
+                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 (parameters is ParametersWithIV)
+            {
+				if (!forWrapping)
+					throw new ArgumentException("You should not supply an IV for unwrapping");
+
+				this.paramPlusIV = (ParametersWithIV) parameters;
+                this.iv = this.paramPlusIV.GetIV();
+                this.param = (KeyParameter) this.paramPlusIV.Parameters;
+
+				if (this.iv.Length != 8)
+					throw new ArgumentException("IV is not 8 octets", "parameters");
+            }
+        }
+
+		/**
+        * Method GetAlgorithmName
+        *
+        * @return
+        */
+        public string AlgorithmName
+        {
+            get { return "DESede"; }
+        }
+
+		/**
+        * Method wrap
+        *
+        * @param in
+        * @param inOff
+        * @param inLen
+        * @return
+        */
+        public byte[] Wrap(
+			byte[]	input,
+			int		inOff,
+			int		length)
+        {
+            if (!forWrapping)
+            {
+                throw new InvalidOperationException("Not initialized for wrapping");
+            }
+
+			byte[] keyToBeWrapped = new byte[length];
+            Array.Copy(input, inOff, keyToBeWrapped, 0, length);
+
+            // 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];
+            Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
+            Array.Copy(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 InvalidOperationException("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];
+            Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
+            Array.Copy(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
+        * @throws InvalidCipherTextException
+        */
+        public byte[] Unwrap(
+			byte[]	input,
+			int		inOff,
+			int		length)
+        {
+            if (forWrapping)
+            {
+                throw new InvalidOperationException("Not set for unwrapping");
+            }
+            if (input == null)
+            {
+                throw new InvalidCipherTextException("Null pointer as ciphertext");
+            }
+
+			int blockSize = engine.GetBlockSize();
+			
+            if (length % 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[length];
+
+			for (int currentBytePos = 0; currentBytePos != TEMP3.Length; currentBytePos += blockSize)
+			{
+				engine.ProcessBlock(input, 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];
+            Array.Copy(TEMP2, 0, this.iv, 0, 8);
+            Array.Copy(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];
+            Array.Copy(WKCKS, 0, result, 0, WKCKS.Length - 8);
+            Array.Copy(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
+        * @throws Exception
+        * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+        */
+        private byte[] CalculateCmsKeyChecksum(
+            byte[] key)
+        {
+			sha1.BlockUpdate(key, 0, key.Length);
+            sha1.DoFinal(digest, 0);
+
+            byte[] result = new byte[8];
+			Array.Copy(digest, 0, result, 0, 8);
+			return result;
+        }
+
+		/**
+        * @param key
+        * @param checksum
+        * @return
+        * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+        */
+        private bool 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/crypto/src/crypto/engines/DesEngine.cs b/crypto/src/crypto/engines/DesEngine.cs
new file mode 100644
index 000000000..067cf45e3
--- /dev/null
+++ b/crypto/src/crypto/engines/DesEngine.cs
@@ -0,0 +1,475 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <remarks>A class that provides a basic DES engine.</remarks>
+    public class DesEngine
+		: IBlockCipher
+    {
+        internal const int BLOCK_SIZE = 8;
+
+		private int[] workingKey;
+
+        public virtual int[] GetWorkingKey()
+		{
+			return workingKey;
+		}
+
+		/**
+        * initialise a DES cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public virtual void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is KeyParameter))
+				throw new ArgumentException("invalid parameter passed to DES init - " + parameters.GetType().ToString());
+
+			workingKey = GenerateWorkingKey(forEncryption, ((KeyParameter)parameters).GetKey());
+        }
+
+		public virtual string AlgorithmName
+        {
+            get { return "DES"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public virtual int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        public virtual int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (workingKey == null)
+                throw new InvalidOperationException("DES engine not initialised");
+			if ((inOff + BLOCK_SIZE) > input.Length)
+                throw new DataLengthException("input buffer too short");
+            if ((outOff + BLOCK_SIZE) > output.Length)
+                throw new DataLengthException("output buffer too short");
+
+			DesFunc(workingKey, input, inOff, output, outOff);
+
+			return BLOCK_SIZE;
+        }
+
+        public virtual 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 readonly 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 readonly short[] bytebit =
+        {
+            128, 64, 32, 16, 8, 4, 2, 1
+        };
+
+		private static readonly 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 readonly 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 readonly byte[] totrot =
+        {
+            1, 2, 4, 6, 8, 10, 12, 14,
+            15, 17, 19, 21, 23, 25, 27, 28
+        };
+
+		private static readonly 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 readonly uint[] 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 and Phil Karn.
+        *         (whoever, and wherever they are!).
+        */
+        protected static int[] GenerateWorkingKey(
+            bool	encrypting,
+            byte[]	key)
+        {
+            int[] newKey = new int[32];
+            bool[] pc1m = new bool[56];
+			bool[] pcr = new bool[56];
+
+			for (int j = 0; j < 56; j++ )
+            {
+                int l = pc1[j];
+
+				pc1m[j] = ((key[(uint) 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] = (int) ( (uint) ((i1 & 0x00fc0000) << 6)  |
+                                    (uint) ((i1 & 0x00000fc0) << 10) |
+                                    ((uint) (i2 & 0x00fc0000) >> 10) |
+                                    ((uint) (i2 & 0x00000fc0) >> 6));
+
+                newKey[i + 1] = (int) ( (uint) ((i1 & 0x0003f000) << 12) |
+                                        (uint) ((i1 & 0x0000003f) << 16) |
+                                        ((uint) (i2 & 0x0003f000) >> 4) |
+                                        (uint) (i2 & 0x0000003f));
+            }
+
+            return newKey;
+        }
+
+        /**
+        * the DES engine.
+        */
+        internal static void DesFunc(
+            int[]	wKey,
+            byte[]	input,
+            int		inOff,
+            byte[]	outBytes,
+            int		outOff)
+        {
+			uint left = Pack.BE_To_UInt32(input, inOff);
+			uint right = Pack.BE_To_UInt32(input, inOff + 4);
+			uint work;
+
+            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);
+            work = (left ^ right) & 0xaaaaaaaa;
+            left ^= work;
+            right ^= work;
+            left = (left << 1) | (left >> 31);
+
+            for (int round = 0; round < 8; round++)
+            {
+                uint fval;
+
+                work  = (right << 28) | (right >> 4);
+                work ^= (uint)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 ^ (uint)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 ^= (uint)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 ^ (uint)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);
+
+			Pack.UInt32_To_BE(right, outBytes, outOff);
+			Pack.UInt32_To_BE(left, outBytes, outOff + 4);
+        }
+    }
+}
diff --git a/crypto/src/crypto/engines/ElGamalEngine.cs b/crypto/src/crypto/engines/ElGamalEngine.cs
new file mode 100644
index 000000000..3d256a087
--- /dev/null
+++ b/crypto/src/crypto/engines/ElGamalEngine.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* this does your basic ElGamal algorithm.
+	*/
+	public class ElGamalEngine
+		: IAsymmetricBlockCipher
+	{
+		private ElGamalKeyParameters key;
+		private SecureRandom random;
+		private bool forEncryption;
+		private int bitSize;
+
+		public string AlgorithmName
+		{
+			get { return "ElGamal"; }
+		}
+
+		/**
+		* initialise the ElGamal engine.
+		*
+		* @param forEncryption true if we are encrypting, false otherwise.
+		* @param param the necessary ElGamal key parameters.
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (parameters is ParametersWithRandom)
+			{
+				ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+				this.key = (ElGamalKeyParameters) p.Parameters;
+				this.random = p.Random;
+			}
+			else
+			{
+				this.key = (ElGamalKeyParameters) parameters;
+				this.random = new SecureRandom();
+			}
+
+			this.forEncryption = forEncryption;
+			this.bitSize = key.Parameters.P.BitLength;
+
+			if (forEncryption)
+			{
+				if (!(key is ElGamalPublicKeyParameters))
+				{
+					throw new ArgumentException("ElGamalPublicKeyParameters are required for encryption.");
+				}
+			}
+			else
+			{
+				if (!(key is ElGamalPrivateKeyParameters))
+				{
+					throw new ArgumentException("ElGamalPrivateKeyParameters are required for decryption.");
+				}
+			}
+		}
+
+		/**
+		* Return the maximum size for an input block to this engine.
+		* For ElGamal this is always one byte less than the size of P on
+		* encryption, and twice the length as the size of P on decryption.
+		*
+		* @return maximum size for an input block.
+		*/
+		public int GetInputBlockSize()
+		{
+			if (forEncryption)
+			{
+				return (bitSize - 1) / 8;
+			}
+
+			return 2 * ((bitSize + 7) / 8);
+		}
+
+		/**
+		* Return the maximum size for an output block to this engine.
+		* For ElGamal this is always one byte less than the size of P on
+		* decryption, and twice the length as the size of P on encryption.
+		*
+		* @return maximum size for an output block.
+		*/
+		public int GetOutputBlockSize()
+		{
+			if (forEncryption)
+			{
+				return 2 * ((bitSize + 7) / 8);
+			}
+
+			return (bitSize - 1) / 8;
+		}
+
+		/**
+		* Process a single block using the basic ElGamal algorithm.
+		*
+		* @param in the input array.
+		* @param inOff the offset into the input buffer where the data starts.
+		* @param length the length of the data to be processed.
+		* @return the result of the ElGamal process.
+		* @exception DataLengthException the input block is too large.
+		*/
+		public byte[] ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (key == null)
+				throw new InvalidOperationException("ElGamal engine not initialised");
+
+			int maxLength = forEncryption
+				?	(bitSize - 1 + 7) / 8
+				:	GetInputBlockSize();
+
+			if (length > maxLength)
+				throw new DataLengthException("input too large for ElGamal cipher.\n");
+
+			BigInteger p = key.Parameters.P;
+
+			byte[] output;
+			if (key is ElGamalPrivateKeyParameters) // decryption
+			{
+				int halfLength = length / 2;
+				BigInteger gamma = new BigInteger(1, input, inOff, halfLength);
+				BigInteger phi = new BigInteger(1, input, inOff + halfLength, halfLength);
+
+				ElGamalPrivateKeyParameters priv = (ElGamalPrivateKeyParameters) key;
+
+				// a shortcut, which generally relies on p being prime amongst other things.
+				// if a problem with this shows up, check the p and g values!
+				BigInteger m = gamma.ModPow(p.Subtract(BigInteger.One).Subtract(priv.X), p).Multiply(phi).Mod(p);
+
+				output = m.ToByteArrayUnsigned();
+			}
+			else // encryption
+			{
+				BigInteger tmp = new BigInteger(1, input, inOff, length);
+
+				if (tmp.BitLength >= p.BitLength)
+					throw new DataLengthException("input too large for ElGamal cipher.\n");
+
+
+				ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters) key;
+
+				BigInteger pSub2 = p.Subtract(BigInteger.Two);
+
+				// TODO In theory, a series of 'k', 'g.ModPow(k, p)' and 'y.ModPow(k, p)' can be pre-calculated
+				BigInteger k;
+				do
+				{
+					k = new BigInteger(p.BitLength, random);
+				}
+				while (k.SignValue == 0 || k.CompareTo(pSub2) > 0);
+
+				BigInteger g = key.Parameters.G;
+				BigInteger gamma = g.ModPow(k, p);
+				BigInteger phi = tmp.Multiply(pub.Y.ModPow(k, p)).Mod(p);
+
+				output = new byte[this.GetOutputBlockSize()];
+
+				// TODO Add methods to allow writing BigInteger to existing byte array?
+				byte[] out1 = gamma.ToByteArrayUnsigned();
+				byte[] out2 = phi.ToByteArrayUnsigned();
+				out1.CopyTo(output, output.Length / 2 - out1.Length);
+				out2.CopyTo(output, output.Length - out2.Length);
+			}
+
+			return output;
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/GOST28147Engine.cs b/crypto/src/crypto/engines/GOST28147Engine.cs
index 17593d2c0..8eb6f36b5 100644
--- a/crypto/src/crypto/engines/GOST28147Engine.cs
+++ b/crypto/src/crypto/engines/GOST28147Engine.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Utilities;
@@ -134,7 +133,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 		private static void AddSBox(string sBoxName, byte[] sBox)
 		{
-			sBoxes.Add(sBoxName.ToUpperInvariant(), sBox);        
+			sBoxes.Add(Platform.ToUpperInvariant(sBoxName), sBox);        
 		}
 
 		/**
@@ -363,9 +362,9 @@ namespace Org.BouncyCastle.Crypto.Engines
 		public static byte[] GetSBox(
 			string sBoxName)
 		{
-			byte[] sBox = (byte[])sBoxes[sBoxName.ToUpperInvariant()];
+			byte[] sBox = (byte[])sBoxes[Platform.ToUpperInvariant(sBoxName)];
 
-			if (sBox == null)
+            if (sBox == null)
 			{
 				throw new ArgumentException("Unknown S-Box - possible types: "
 					+ "\"Default\", \"E-Test\", \"E-A\", \"E-B\", \"E-C\", \"E-D\", \"D-Test\", \"D-A\".");
diff --git a/crypto/src/crypto/engines/HC128Engine.cs b/crypto/src/crypto/engines/HC128Engine.cs
new file mode 100644
index 000000000..a2d099f87
--- /dev/null
+++ b/crypto/src/crypto/engines/HC128Engine.cs
@@ -0,0 +1,235 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* HC-128 is a software-efficient stream cipher created by Hongjun Wu. It
+	* generates keystream from a 128-bit secret key and a 128-bit initialization
+	* vector.
+	* <p>
+	* http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf
+	* </p><p>
+	* It is a third phase candidate in the eStream contest, and is patent-free.
+	* No attacks are known as of today (April 2007). See
+	*
+	* http://www.ecrypt.eu.org/stream/hcp3.html
+	* </p>
+	*/
+	public class HC128Engine
+		: IStreamCipher
+	{
+		private uint[] p = new uint[512];
+		private uint[] q = new uint[512];
+		private uint cnt = 0;
+
+		private static uint F1(uint x)
+		{
+			return RotateRight(x, 7) ^ RotateRight(x, 18) ^ (x >> 3);
+		}
+
+		private static uint F2(uint x)
+		{
+			return RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10);
+		}
+
+		private uint G1(uint x, uint y, uint z)
+		{
+			return (RotateRight(x, 10) ^ RotateRight(z, 23)) + RotateRight(y, 8);
+		}
+
+		private uint G2(uint x, uint y, uint z)
+		{
+			return (RotateLeft(x, 10) ^ RotateLeft(z, 23)) + RotateLeft(y, 8);
+		}
+
+		private static uint RotateLeft(uint	x, int bits)
+		{
+			return (x << bits) | (x >> -bits);
+		}
+
+		private static uint RotateRight(uint x, int bits)
+		{
+			return (x >> bits) | (x << -bits);
+		}
+
+		private uint H1(uint x)
+		{
+			return q[x & 0xFF] + q[((x >> 16) & 0xFF) + 256];
+		}
+
+		private uint H2(uint x)
+		{
+			return p[x & 0xFF] + p[((x >> 16) & 0xFF) + 256];
+		}
+
+		private static uint Mod1024(uint x)
+		{
+			return x & 0x3FF;
+		}
+
+		private static uint Mod512(uint x)
+		{
+			return x & 0x1FF;
+		}
+
+		private static uint Dim(uint x, uint y)
+		{
+			return Mod512(x - y);
+		}
+
+		private uint Step()
+		{
+			uint j = Mod512(cnt);
+			uint ret;
+			if (cnt < 512)
+			{
+				p[j] += G1(p[Dim(j, 3)], p[Dim(j, 10)], p[Dim(j, 511)]);
+				ret = H1(p[Dim(j, 12)]) ^ p[j];
+			}
+			else
+			{
+				q[j] += G2(q[Dim(j, 3)], q[Dim(j, 10)], q[Dim(j, 511)]);
+				ret = H2(q[Dim(j, 12)]) ^ q[j];
+			}
+			cnt = Mod1024(cnt + 1);
+			return ret;
+		}
+
+		private byte[] key, iv;
+		private bool initialised;
+
+		private void Init()
+		{
+			if (key.Length != 16)
+				throw new ArgumentException("The key must be 128 bits long");
+
+			cnt = 0;
+
+			uint[] w = new uint[1280];
+
+			for (int i = 0; i < 16; i++)
+			{
+				w[i >> 2] |= ((uint)key[i] << (8 * (i & 0x3)));
+			}
+			Array.Copy(w, 0, w, 4, 4);
+
+			for (int i = 0; i < iv.Length && i < 16; i++)
+			{
+				w[(i >> 2) + 8] |= ((uint)iv[i] << (8 * (i & 0x3)));
+			}
+			Array.Copy(w, 8, w, 12, 4);
+
+			for (uint i = 16; i < 1280; i++)
+			{
+				w[i] = F2(w[i - 2]) + w[i - 7] + F1(w[i - 15]) + w[i - 16] + i;
+			}
+
+			Array.Copy(w, 256, p, 0, 512);
+			Array.Copy(w, 768, q, 0, 512);
+
+			for (int i = 0; i < 512; i++)
+			{
+				p[i] = Step();
+			}
+			for (int i = 0; i < 512; i++)
+			{
+				q[i] = Step();
+			}
+
+			cnt = 0;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "HC-128"; }
+		}
+
+		/**
+		* Initialise a HC-128 cipher.
+		*
+		* @param forEncryption whether or not we are for encryption. Irrelevant, as
+		*                      encryption and decryption are the same.
+		* @param params        the parameters required to set up the cipher.
+		* @throws ArgumentException if the params argument is
+		*                                  inappropriate (ie. the key is not 128 bit long).
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			ICipherParameters keyParam = parameters;
+
+			if (parameters is ParametersWithIV)
+			{
+				iv = ((ParametersWithIV)parameters).GetIV();
+				keyParam = ((ParametersWithIV)parameters).Parameters;
+			}
+			else
+			{
+				iv = new byte[0];
+			}
+
+			if (keyParam is KeyParameter)
+			{
+				key = ((KeyParameter)keyParam).GetKey();
+				Init();
+			}
+			else
+			{
+				throw new ArgumentException(
+					"Invalid parameter passed to HC128 init - " + parameters.GetType().Name,
+					"parameters");
+			}
+
+			initialised = true;
+		}
+
+		private byte[] buf = new byte[4];
+		private int idx = 0;
+
+		private byte GetByte()
+		{
+			if (idx == 0)
+			{
+				Pack.UInt32_To_LE(Step(), buf);				
+			}
+			byte ret = buf[idx];
+			idx = idx + 1 & 0x3;
+			return ret;
+		}
+
+		public void ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		len,
+			byte[]	output,
+			int		outOff)
+		{
+			if (!initialised)
+				throw new InvalidOperationException(AlgorithmName + " not initialised");
+			if ((inOff + len) > input.Length)
+				throw new DataLengthException("input buffer too short");
+			if ((outOff + len) > output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			for (int i = 0; i < len; i++)
+			{
+				output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
+			}
+		}
+
+		public void Reset()
+		{
+			idx = 0;
+			Init();
+		}
+
+		public byte ReturnByte(byte input)
+		{
+			return (byte)(input ^ GetByte());
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/HC256Engine.cs b/crypto/src/crypto/engines/HC256Engine.cs
new file mode 100644
index 000000000..da717dab7
--- /dev/null
+++ b/crypto/src/crypto/engines/HC256Engine.cs
@@ -0,0 +1,224 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* HC-256 is a software-efficient stream cipher created by Hongjun Wu. It 
+	* generates keystream from a 256-bit secret key and a 256-bit initialization 
+	* vector.
+	* <p>
+	* http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
+	* </p><p>
+	* Its brother, HC-128, is a third phase candidate in the eStream contest.
+	* The algorithm is patent-free. No attacks are known as of today (April 2007). 
+	* See
+	* 
+	* http://www.ecrypt.eu.org/stream/hcp3.html
+	* </p>
+	*/
+	public class HC256Engine
+		: IStreamCipher
+	{
+		private uint[] p = new uint[1024];
+		private uint[] q = new uint[1024];
+		private uint cnt = 0;
+
+		private uint Step()
+		{
+			uint j = cnt & 0x3FF;
+			uint ret;
+			if (cnt < 1024)
+			{
+				uint x = p[(j - 3 & 0x3FF)];
+				uint y = p[(j - 1023 & 0x3FF)];
+				p[j] += p[(j - 10 & 0x3FF)]
+					+ (RotateRight(x, 10) ^ RotateRight(y, 23))
+					+ q[((x ^ y) & 0x3FF)];
+
+				x = p[(j - 12 & 0x3FF)];
+				ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256]
+					+ q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768])
+					^ p[j];
+			}
+			else
+			{
+				uint x = q[(j - 3 & 0x3FF)];
+				uint y = q[(j - 1023 & 0x3FF)];
+				q[j] += q[(j - 10 & 0x3FF)]
+					+ (RotateRight(x, 10) ^ RotateRight(y, 23))
+					+ p[((x ^ y) & 0x3FF)];
+
+				x = q[(j - 12 & 0x3FF)];
+				ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256]
+					+ p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768])
+					^ q[j];
+			}
+			cnt = cnt + 1 & 0x7FF;
+			return ret;
+		}
+
+		private byte[] key, iv;
+		private bool initialised;
+
+		private void Init()
+		{
+			if (key.Length != 32 && key.Length != 16)
+				throw new ArgumentException("The key must be 128/256 bits long");
+
+			if (iv.Length < 16)
+				throw new ArgumentException("The IV must be at least 128 bits long");
+
+			if (key.Length != 32)
+	        {
+				byte[] k = new byte[32];
+
+				Array.Copy(key, 0, k, 0, key.Length);
+				Array.Copy(key, 0, k, 16, key.Length);
+
+				key = k;
+			}
+
+			if (iv.Length < 32)
+			{
+				byte[] newIV = new byte[32];
+
+				Array.Copy(iv, 0, newIV, 0, iv.Length);
+				Array.Copy(iv, 0, newIV, iv.Length, newIV.Length - iv.Length);
+
+				iv = newIV;
+			}
+
+			cnt = 0;
+
+			uint[] w = new uint[2560];
+
+			for (int i = 0; i < 32; i++)
+			{
+				w[i >> 2] |= ((uint)key[i] << (8 * (i & 0x3)));
+			}
+
+			for (int i = 0; i < 32; i++)
+			{
+				w[(i >> 2) + 8] |= ((uint)iv[i] << (8 * (i & 0x3)));
+			}
+
+			for (uint i = 16; i < 2560; i++)
+			{
+				uint x = w[i - 2];
+				uint y = w[i - 15];
+				w[i] = (RotateRight(x, 17) ^ RotateRight(x, 19) ^ (x >> 10))
+					+ w[i - 7]
+					+ (RotateRight(y, 7) ^ RotateRight(y, 18) ^ (y >> 3))
+					+ w[i - 16] + i;
+			}
+
+			Array.Copy(w, 512, p, 0, 1024);
+			Array.Copy(w, 1536, q, 0, 1024);
+
+			for (int i = 0; i < 4096; i++)
+			{
+				Step();
+			}
+
+			cnt = 0;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "HC-256"; }
+		}
+
+		/**
+		* Initialise a HC-256 cipher.
+		*
+		* @param forEncryption whether or not we are for encryption. Irrelevant, as
+		*                      encryption and decryption are the same.
+		* @param params        the parameters required to set up the cipher.
+		* @throws ArgumentException if the params argument is
+		*                                  inappropriate (ie. the key is not 256 bit long).
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			ICipherParameters keyParam = parameters;
+
+			if (parameters is ParametersWithIV)
+			{
+				iv = ((ParametersWithIV)parameters).GetIV();
+				keyParam = ((ParametersWithIV)parameters).Parameters;
+			}
+			else
+			{
+				iv = new byte[0];
+			}
+
+			if (keyParam is KeyParameter)
+			{
+				key = ((KeyParameter)keyParam).GetKey();
+				Init();
+			}
+			else
+			{
+				throw new ArgumentException(
+					"Invalid parameter passed to HC256 init - " + parameters.GetType().Name,
+					"parameters");
+			}
+
+			initialised = true;
+		}
+
+		private byte[] buf = new byte[4];
+		private int idx = 0;
+
+		private byte GetByte()
+		{
+			if (idx == 0)
+			{
+				Pack.UInt32_To_LE(Step(), buf);
+			}
+			byte ret = buf[idx];
+			idx = idx + 1 & 0x3;
+			return ret;
+		}
+
+		public void ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		len,
+			byte[]	output,
+			int		outOff)
+		{
+			if (!initialised)
+				throw new InvalidOperationException(AlgorithmName + " not initialised");
+			if ((inOff + len) > input.Length)
+				throw new DataLengthException("input buffer too short");
+			if ((outOff + len) > output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			for (int i = 0; i < len; i++)
+			{
+				output[outOff + i] = (byte)(input[inOff + i] ^ GetByte());
+			}
+		}
+
+		public void Reset()
+		{
+			idx = 0;
+			Init();
+		}
+
+		public byte ReturnByte(byte input)
+		{
+			return (byte)(input ^ GetByte());
+		}
+
+		private static uint RotateRight(uint x, int bits)
+		{
+			return (x >> bits) | (x << -bits);
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/ISAACEngine.cs b/crypto/src/crypto/engines/ISAACEngine.cs
index 1120a4104..9c58678a0 100644
--- a/crypto/src/crypto/engines/ISAACEngine.cs
+++ b/crypto/src/crypto/engines/ISAACEngine.cs
@@ -1,252 +1,212 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	/**
-	* Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
-	* see: http://www.burtleburtle.net/bob/rand/isaacafa.html
-	*/
-	public class IsaacEngine
-		: IStreamCipher
-	{
-		// Constants
-		private static readonly int sizeL          = 8,
-									stateArraySize = sizeL<<5; // 256
-
-		// Cipher's internal state
-		private uint[]   engineState   = null, // mm                
-						results       = null; // randrsl
-		private uint     a = 0, b = 0, c = 0;
-
-		// Engine state
-		private int     index         = 0;
-		private byte[]  keyStream     = new byte[stateArraySize<<2], // results expanded into bytes
-						workingKey    = null;
-		private bool	initialised   = false;
-
-		/**
-		* initialise an ISAAC cipher.
-		*
-		* @param forEncryption whether or not we are for encryption.
-		* @param params the parameters required to set up the cipher.
-		* @exception ArgumentException if the params argument is
-		* inappropriate.
-		*/
-		public void Init(
-			bool				forEncryption, 
-			ICipherParameters	parameters)
-		{
-			if (!(parameters is KeyParameter))
-				throw new ArgumentException(
-					"invalid parameter passed to ISAAC Init - " + parameters.GetType().Name,
-					"parameters");
-
-			/* 
-			* ISAAC encryption and decryption is completely
-			* symmetrical, so the 'forEncryption' is 
-			* irrelevant.
-			*/
-			KeyParameter p = (KeyParameter) parameters;
-			setKey(p.GetKey());
-		}
-
-		public byte ReturnByte(
-			byte input)
-		{
-			if (index == 0) 
-			{
-				isaac();
-				keyStream = intToByteLittle(results);
-			}
-
-			byte output = (byte)(keyStream[index]^input);
-			index = (index + 1) & 1023;
-
-			return output;
-		}
-
-		public void ProcessBytes(
-			byte[]	input, 
-			int		inOff, 
-			int		len, 
-			byte[]	output, 
-			int		outOff)
-		{
-			if (!initialised)
-				throw new InvalidOperationException(AlgorithmName + " not initialised");
-			if ((inOff + len) > input.Length)
-				throw new DataLengthException("input buffer too short");
-			if ((outOff + len) > output.Length)
-				throw new DataLengthException("output buffer too short");
-
-			for (int i = 0; i < len; i++)
-			{
-				if (index == 0) 
-				{
-					isaac();
-					keyStream = intToByteLittle(results);
-				}
-				output[i+outOff] = (byte)(keyStream[index]^input[i+inOff]);
-				index = (index + 1) & 1023;
-			}
-		}
-
-		public string AlgorithmName
-		{
-			get { return "ISAAC"; }
-		}
-
-		public void Reset()
-		{
-			setKey(workingKey);
-		}
-
-		// Private implementation
-		private void setKey(
-			byte[] keyBytes)
-		{
-			workingKey = keyBytes;
-
-			if (engineState == null)
-			{
-				engineState = new uint[stateArraySize];
-			}
-
-			if (results == null)
-			{
-				results = new uint[stateArraySize];
-			}
-
-			int i, j, k;
-
-			// Reset state
-			for (i = 0; i < stateArraySize; i++)
-			{
-				engineState[i] = results[i] = 0;
-			}
-			a = b = c = 0;
-
-			// Reset index counter for output
-			index = 0;
-
-			// Convert the key bytes to ints and put them into results[] for initialization
-			byte[] t = new byte[keyBytes.Length + (keyBytes.Length & 3)];
-			Array.Copy(keyBytes, 0, t, 0, keyBytes.Length);
-			for (i = 0; i < t.Length; i+=4)
-			{
-				results[i>>2] = byteToIntLittle(t, i);
-			}
-
-			// It has begun?
-			uint[] abcdefgh = new uint[sizeL];
-
-			for (i = 0; i < sizeL; i++)
-			{
-				abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio)
-			}
-
-			for (i = 0; i < 4; i++)
-			{
-				mix(abcdefgh);
-			}
-
-			for (i = 0; i < 2; i++)
-			{
-				for (j = 0; j < stateArraySize; j+=sizeL)
-				{
-					for (k = 0; k < sizeL; k++)
-					{
-						abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k];
-					}
-
-					mix(abcdefgh);
-
-					for (k = 0; k < sizeL; k++)
-					{
-						engineState[j+k] = abcdefgh[k];
-					}
-				}
-			}
-
-			isaac();
-
-			initialised = true;
-		}    
-
-		private void isaac()
-		{
-			uint x, y;
-
-			b += ++c;
-			for (int i = 0; i < stateArraySize; i++)
-			{
-				x = engineState[i];
-				switch (i & 3)
-				{
-					case 0: a ^= (a << 13); break;
-					case 1: a ^= (a >>  6); break;
-					case 2: a ^= (a <<  2); break;
-					case 3: a ^= (a >> 16); break;
-				}
-				a += engineState[(i+128) & 0xFF];
-				engineState[i] = y = engineState[(int)((uint)x >> 2) & 0xFF] + a + b;
-				results[i] = b = engineState[(int)((uint)y >> 10) & 0xFF] + x;
-			}
-		}
-
-		private void mix(uint[] x)
-		{
-//			x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
-//			x[1]^=x[2]>>> 2; x[4]+=x[1]; x[2]+=x[3];
-//			x[2]^=x[3]<<  8; x[5]+=x[2]; x[3]+=x[4];
-//			x[3]^=x[4]>>>16; x[6]+=x[3]; x[4]+=x[5];
-//			x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
-//			x[5]^=x[6]>>> 4; x[0]+=x[5]; x[6]+=x[7];
-//			x[6]^=x[7]<<  8; x[1]+=x[6]; x[7]+=x[0];
-//			x[7]^=x[0]>>> 9; x[2]+=x[7]; x[0]+=x[1];
-			x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
-			x[1]^=x[2]>>  2; x[4]+=x[1]; x[2]+=x[3];
-			x[2]^=x[3]<<  8; x[5]+=x[2]; x[3]+=x[4];
-			x[3]^=x[4]>> 16; x[6]+=x[3]; x[4]+=x[5];
-			x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
-			x[5]^=x[6]>>  4; x[0]+=x[5]; x[6]+=x[7];
-			x[6]^=x[7]<<  8; x[1]+=x[6]; x[7]+=x[0];
-			x[7]^=x[0]>>  9; x[2]+=x[7]; x[0]+=x[1];
-		}
-
-		private uint byteToIntLittle(
-			byte[]	x,
-			int		offset)
-		{
-			uint result = (byte) x[offset + 3];
-			result = (result << 8) | x[offset + 2];
-			result = (result << 8) | x[offset + 1];
-			result = (result << 8) | x[offset + 0];
-			return result;
-		}
-
-		private byte[] intToByteLittle(
-			uint x)
-		{
-			byte[] output = new byte[4];
-			output[3] = (byte)x;
-			output[2] = (byte)(x >> 8);
-			output[1] = (byte)(x >> 16);
-			output[0] = (byte)(x >> 24);
-			return output;
-		} 
-
-		private byte[] intToByteLittle(
-			uint[] x)
-		{
-			byte[] output = new byte[4*x.Length];
-			for (int i = 0, j = 0; i < x.Length; i++,j+=4)
-			{
-				Array.Copy(intToByteLittle(x[i]), 0, output, j, 4);
-			}
-			return output;
-		}
-	}
+    /**
+    * Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
+    * see: http://www.burtleburtle.net/bob/rand/isaacafa.html
+    */
+    public class IsaacEngine
+        : IStreamCipher
+    {
+        // Constants
+        private static readonly int sizeL          = 8,
+                                    stateArraySize = sizeL<<5; // 256
+
+        // Cipher's internal state
+        private uint[]   engineState   = null, // mm                
+                        results       = null; // randrsl
+        private uint     a = 0, b = 0, c = 0;
+
+        // Engine state
+        private int     index         = 0;
+        private byte[]  keyStream     = new byte[stateArraySize<<2], // results expanded into bytes
+                        workingKey    = null;
+        private bool	initialised   = false;
+
+        /**
+        * initialise an ISAAC cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param params the parameters required to set up the cipher.
+        * @exception ArgumentException if the params argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption, 
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is KeyParameter))
+                throw new ArgumentException(
+                    "invalid parameter passed to ISAAC Init - " + parameters.GetType().Name,
+                    "parameters");
+
+            /* 
+            * ISAAC encryption and decryption is completely
+            * symmetrical, so the 'forEncryption' is 
+            * irrelevant.
+            */
+            KeyParameter p = (KeyParameter) parameters;
+            setKey(p.GetKey());
+        }
+
+        public byte ReturnByte(
+            byte input)
+        {
+            if (index == 0) 
+            {
+                isaac();
+                keyStream = Pack.UInt32_To_BE(results);
+            }
+
+            byte output = (byte)(keyStream[index]^input);
+            index = (index + 1) & 1023;
+
+            return output;
+        }
+
+        public void ProcessBytes(
+            byte[]	input, 
+            int		inOff, 
+            int		len, 
+            byte[]	output, 
+            int		outOff)
+        {
+            if (!initialised)
+                throw new InvalidOperationException(AlgorithmName + " not initialised");
+            if ((inOff + len) > input.Length)
+                throw new DataLengthException("input buffer too short");
+            if ((outOff + len) > output.Length)
+                throw new DataLengthException("output buffer too short");
+
+            for (int i = 0; i < len; i++)
+            {
+                if (index == 0) 
+                {
+                    isaac();
+                    keyStream = Pack.UInt32_To_BE(results);
+                }
+                output[i+outOff] = (byte)(keyStream[index]^input[i+inOff]);
+                index = (index + 1) & 1023;
+            }
+        }
+
+        public string AlgorithmName
+        {
+            get { return "ISAAC"; }
+        }
+
+        public void Reset()
+        {
+            setKey(workingKey);
+        }
+
+        // Private implementation
+        private void setKey(
+            byte[] keyBytes)
+        {
+            workingKey = keyBytes;
+
+            if (engineState == null)
+            {
+                engineState = new uint[stateArraySize];
+            }
+
+            if (results == null)
+            {
+                results = new uint[stateArraySize];
+            }
+
+            int i, j, k;
+
+            // Reset state
+            for (i = 0; i < stateArraySize; i++)
+            {
+                engineState[i] = results[i] = 0;
+            }
+            a = b = c = 0;
+
+            // Reset index counter for output
+            index = 0;
+
+            // Convert the key bytes to ints and put them into results[] for initialization
+            byte[] t = new byte[keyBytes.Length + (keyBytes.Length & 3)];
+            Array.Copy(keyBytes, 0, t, 0, keyBytes.Length);
+            for (i = 0; i < t.Length; i+=4)
+            {
+                results[i >> 2] = Pack.LE_To_UInt32(t, i);
+            }
+
+            // It has begun?
+            uint[] abcdefgh = new uint[sizeL];
+
+            for (i = 0; i < sizeL; i++)
+            {
+                abcdefgh[i] = 0x9e3779b9; // Phi (golden ratio)
+            }
+
+            for (i = 0; i < 4; i++)
+            {
+                mix(abcdefgh);
+            }
+
+            for (i = 0; i < 2; i++)
+            {
+                for (j = 0; j < stateArraySize; j+=sizeL)
+                {
+                    for (k = 0; k < sizeL; k++)
+                    {
+                        abcdefgh[k] += (i<1) ? results[j+k] : engineState[j+k];
+                    }
+
+                    mix(abcdefgh);
+
+                    for (k = 0; k < sizeL; k++)
+                    {
+                        engineState[j+k] = abcdefgh[k];
+                    }
+                }
+            }
+
+            isaac();
+
+            initialised = true;
+        }    
+
+        private void isaac()
+        {
+            uint x, y;
+
+            b += ++c;
+            for (int i = 0; i < stateArraySize; i++)
+            {
+                x = engineState[i];
+                switch (i & 3)
+                {
+                    case 0: a ^= (a << 13); break;
+                    case 1: a ^= (a >>  6); break;
+                    case 2: a ^= (a <<  2); break;
+                    case 3: a ^= (a >> 16); break;
+                }
+                a += engineState[(i+128) & 0xFF];
+                engineState[i] = y = engineState[(int)((uint)x >> 2) & 0xFF] + a + b;
+                results[i] = b = engineState[(int)((uint)y >> 10) & 0xFF] + x;
+            }
+        }
+
+        private void mix(uint[] x)
+        {
+            x[0]^=x[1]<< 11; x[3]+=x[0]; x[1]+=x[2];
+            x[1]^=x[2]>>  2; x[4]+=x[1]; x[2]+=x[3];
+            x[2]^=x[3]<<  8; x[5]+=x[2]; x[3]+=x[4];
+            x[3]^=x[4]>> 16; x[6]+=x[3]; x[4]+=x[5];
+            x[4]^=x[5]<< 10; x[7]+=x[4]; x[5]+=x[6];
+            x[5]^=x[6]>>  4; x[0]+=x[5]; x[6]+=x[7];
+            x[6]^=x[7]<<  8; x[1]+=x[6]; x[7]+=x[0];
+            x[7]^=x[0]>>  9; x[2]+=x[7]; x[0]+=x[1];
+        }
+    }
 }
diff --git a/crypto/src/crypto/engines/IdeaEngine.cs b/crypto/src/crypto/engines/IdeaEngine.cs
index f763c5939..46b5a787c 100644
--- a/crypto/src/crypto/engines/IdeaEngine.cs
+++ b/crypto/src/crypto/engines/IdeaEngine.cs
@@ -1,5 +1,3 @@
-#if INCLUDE_IDEA
-
 using System;
 
 using Org.BouncyCastle.Crypto.Parameters;
@@ -12,26 +10,26 @@ namespace Org.BouncyCastle.Crypto.Engines
     * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM"
     * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the
     * end of the mulinv function!).
-	* </p>
+    * </p>
     * <p>
     * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/
-	* </p>
+    * </p>
     * <p>
-	* Note 1: This algorithm is patented in the USA, Japan, and Europe including
+    * Note 1: This algorithm is patented in the USA, Japan, and Europe including
     * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland
     * and the United Kingdom. Non-commercial use is free, however any commercial
     * products are liable for royalties. Please see
     * <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for
     * further details. This announcement has been included at the request of
     * the patent holders.
-	* </p>
-	* <p>
-	* Note 2: Due to the requests concerning the above, this algorithm is now only
-	* included in the extended assembly. It is not included in the default distributions.
-	* </p>
+    * </p>
+    * <p>
+    * Note 2: Due to the requests concerning the above, this algorithm is now only
+    * included in the extended assembly. It is not included in the default distributions.
+    * </p>
     */
     public class IdeaEngine
-		: IBlockCipher
+        : IBlockCipher
     {
         private const int  BLOCK_SIZE = 8;
         private int[] workingKey;
@@ -54,28 +52,28 @@ namespace Org.BouncyCastle.Crypto.Engines
             ICipherParameters	parameters)
         {
             if (!(parameters is KeyParameter))
-				throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString());
+                throw new ArgumentException("invalid parameter passed to IDEA init - " + parameters.GetType().ToString());
 
-			workingKey = GenerateWorkingKey(forEncryption,
-				((KeyParameter)parameters).GetKey());
+            workingKey = GenerateWorkingKey(forEncryption,
+                ((KeyParameter)parameters).GetKey());
         }
 
-		public string AlgorithmName
+        public string AlgorithmName
         {
             get { return "IDEA"; }
         }
 
-		public bool IsPartialBlockOkay
-		{
-			get { return false; }
-		}
+        public bool IsPartialBlockOkay
+        {
+            get { return false; }
+        }
 
-		public int GetBlockSize()
+        public int GetBlockSize()
         {
             return BLOCK_SIZE;
         }
 
-		public int ProcessBlock(
+        public int ProcessBlock(
             byte[] input,
             int inOff,
             byte[] output,
@@ -228,7 +226,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * Common Divisor algorithm. Zero and one are self inverse.
         * <p>
         * i.e. x * MulInv(x) == 1 (modulo BASE)
-		* </p>
+        * </p>
         */
         private int MulInv(
             int x)
@@ -261,7 +259,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         * Return the additive inverse of x.
         * <p>
         * i.e. x + AddInv(x) == 0
-		* </p>
+        * </p>
         */
         int AddInv(
             int x)
@@ -337,5 +335,3 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
     }
 }
-
-#endif
diff --git a/crypto/src/crypto/engines/IesEngine.cs b/crypto/src/crypto/engines/IesEngine.cs
index c49b2a9ee..70df3077c 100644
--- a/crypto/src/crypto/engines/IesEngine.cs
+++ b/crypto/src/crypto/engines/IesEngine.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
@@ -15,9 +16,9 @@ namespace Org.BouncyCastle.Crypto.Engines
         private readonly IDerivationFunction kdf;
         private readonly IMac                mac;
         private readonly BufferedBlockCipher cipher;
-		private readonly byte[]              macBuf;
+        private readonly byte[]              macBuf;
 
-		private bool				forEncryption;
+        private bool				forEncryption;
         private ICipherParameters	privParam, pubParam;
         private IesParameters		param;
 
@@ -100,7 +101,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
             if (cipher == null)     // stream mode
             {
-				byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+                byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
 
                 M = new byte[inLen];
 
@@ -114,13 +115,13 @@ namespace Org.BouncyCastle.Crypto.Engines
             else
             {
                 int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
-				byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
+                byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
 
                 cipher.Init(false, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
 
-				M = cipher.DoFinal(in_enc, inOff, inLen);
+                M = cipher.DoFinal(in_enc, inOff, inLen);
 
-				macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+                macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
             }
 
             byte[] macIV = param.GetEncodingV();
@@ -130,15 +131,12 @@ namespace Org.BouncyCastle.Crypto.Engines
             mac.BlockUpdate(macIV, 0, macIV.Length);
             mac.DoFinal(macBuf, 0);
 
-			inOff += inLen;
+            inOff += inLen;
 
-			for (int t = 0; t < macBuf.Length; t++)
-            {
-                if (macBuf[t] != in_enc[inOff + t])
-                {
-                    throw (new InvalidCipherTextException("IMac codes failed to equal."));
-                }
-            }
+            byte[] T1 = Arrays.CopyOfRange(in_enc, inOff, inOff + macBuf.Length);
+
+            if (!Arrays.ConstantTimeAreEqual(T1, macBuf))
+                throw (new InvalidCipherTextException("Invalid MAC."));
 
             return M;
         }
@@ -157,12 +155,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 
             if (cipher == null)     // stream mode
             {
-				byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+                byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
 
                 C = new byte[inLen + mac.GetMacSize()];
                 c_text_length = inLen;
 
-				for (int i = 0; i != inLen; i++)
+                for (int i = 0; i != inLen; i++)
                 {
                     C[i] = (byte)(input[inOff + i] ^ Buffer[i]);
                 }
@@ -172,22 +170,22 @@ namespace Org.BouncyCastle.Crypto.Engines
             else
             {
                 int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
-				byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
+                byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
 
                 cipher.Init(true, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
 
                 c_text_length = cipher.GetOutputSize(inLen);
-				byte[] tmp = new byte[c_text_length];
+                byte[] tmp = new byte[c_text_length];
 
-				int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0);
-				len += cipher.DoFinal(tmp, len);
+                int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0);
+                len += cipher.DoFinal(tmp, len);
 
-				C = new byte[len + mac.GetMacSize()];
-				c_text_length = len;
+                C = new byte[len + mac.GetMacSize()];
+                c_text_length = len;
 
-				Array.Copy(tmp, 0, C, 0, len);
+                Array.Copy(tmp, 0, C, 0, len);
 
-				macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+                macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
             }
 
             byte[] macIV = param.GetEncodingV();
@@ -202,33 +200,32 @@ namespace Org.BouncyCastle.Crypto.Engines
             return C;
         }
 
-		private byte[] GenerateKdfBytes(
-			KdfParameters	kParam,
-			int				length)
-		{
-			byte[] buf = new byte[length];
+        private byte[] GenerateKdfBytes(
+            KdfParameters	kParam,
+            int				length)
+        {
+            byte[] buf = new byte[length];
 
-			kdf.Init(kParam);
+            kdf.Init(kParam);
 
-			kdf.GenerateBytes(buf, 0, buf.Length);
+            kdf.GenerateBytes(buf, 0, buf.Length);
 
-			return buf;
-		}
+            return buf;
+        }
 
-		public byte[] ProcessBlock(
+        public byte[] ProcessBlock(
             byte[]  input,
             int     inOff,
             int     inLen)
         {
             agree.Init(privParam);
 
-			BigInteger z = agree.CalculateAgreement(pubParam);
+            BigInteger z = agree.CalculateAgreement(pubParam);
 
-			// TODO Is a fixed length result expected?
-			byte[] zBytes = z.ToByteArrayUnsigned();
+            byte[] zBytes = BigIntegers.AsUnsignedByteArray(agree.GetFieldSize(), z);
 
             return forEncryption
-				?	EncryptBlock(input, inOff, inLen, zBytes)
+                ?	EncryptBlock(input, inOff, inLen, zBytes)
                 :	DecryptBlock(input, inOff, inLen, zBytes);
         }
     }
diff --git a/crypto/src/crypto/engines/NaccacheSternEngine.cs b/crypto/src/crypto/engines/NaccacheSternEngine.cs
index 9a0d1e0fe..9ca092351 100644
--- a/crypto/src/crypto/engines/NaccacheSternEngine.cs
+++ b/crypto/src/crypto/engines/NaccacheSternEngine.cs
@@ -51,7 +51,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			{
 				if (debug)
 				{
-					System.Diagnostics.Debug.WriteLine("Constructing lookup Array");
+					Console.WriteLine("Constructing lookup Array");
 				}
 				NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
 				IList primes = priv.SmallPrimesList;
@@ -66,7 +66,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("Constructing lookup ArrayList for " + actualPrimeValue);
+						Console.WriteLine("Constructing lookup ArrayList for " + actualPrimeValue);
 					}
 
 					BigInteger accJ = BigInteger.Zero;
@@ -158,7 +158,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("input as BigInteger: " + input);
+				Console.WriteLine("input as BigInteger: " + input);
 			}
 
 			byte[] output;
@@ -180,7 +180,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 					{
 						if (debug)
 						{
-                            System.Diagnostics.Debug.WriteLine("Prime is " + primes[i] + ", lookup table has size " + al.Count);
+							Console.WriteLine("Prime is " + primes[i] + ", lookup table has size " + al.Count);
 						}
 						throw new InvalidCipherTextException("Error in lookup Array for "
 										+ ((BigInteger)primes[i]).IntValue
@@ -194,14 +194,14 @@ namespace Org.BouncyCastle.Crypto.Engines
 					{
 						if (debug)
 						{
-                            System.Diagnostics.Debug.WriteLine("Actual prime is " + primes[i]);
-                            System.Diagnostics.Debug.WriteLine("Decrypted value is " + exp);
+							Console.WriteLine("Actual prime is " + primes[i]);
+							Console.WriteLine("Decrypted value is " + exp);
 
-                            System.Diagnostics.Debug.WriteLine("LookupList for " + primes[i] + " with size " + lookup[i].Count
+							Console.WriteLine("LookupList for " + primes[i] + " with size " + lookup[i].Count
 											+ " is: ");
 							for (int j = 0; j < lookup[i].Count; j++)
 							{
-                                System.Diagnostics.Debug.WriteLine(lookup[i][j]);
+								Console.WriteLine(lookup[i][j]);
 							}
 						}
 						throw new InvalidCipherTextException("Lookup failed");
@@ -258,7 +258,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			Array.Copy(tmp, 0, output, output.Length - tmp.Length, tmp.Length);
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("Encrypted value is:  " + new BigInteger(output));
+				Console.WriteLine("Encrypted value is:  " + new BigInteger(output));
 			}
 			return output;
 		}
@@ -304,9 +304,9 @@ namespace Org.BouncyCastle.Crypto.Engines
 			m1m2Crypt = m1m2Crypt.Mod(key.Modulus);
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("c(m1) as BigInteger:....... " + m1Crypt);
-                System.Diagnostics.Debug.WriteLine("c(m2) as BigInteger:....... " + m2Crypt);
-                System.Diagnostics.Debug.WriteLine("c(m1)*c(m2)%n = c(m1+m2)%n: " + m1m2Crypt);
+				Console.WriteLine("c(m1) as BigInteger:....... " + m1Crypt);
+				Console.WriteLine("c(m2) as BigInteger:....... " + m2Crypt);
+				Console.WriteLine("c(m1)*c(m2)%n = c(m1+m2)%n: " + m1m2Crypt);
 			}
 
 			//byte[] output = key.Modulus.ToByteArray();
@@ -334,7 +334,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("");
+				Console.WriteLine();
 			}
 			if (data.Length > GetInputBlockSize())
 			{
@@ -342,9 +342,9 @@ namespace Org.BouncyCastle.Crypto.Engines
 				int outBlocksize = GetOutputBlockSize();
 				if (debug)
 				{
-                    System.Diagnostics.Debug.WriteLine("Input blocksize is:  " + inBlocksize + " bytes");
-                    System.Diagnostics.Debug.WriteLine("Output blocksize is: " + outBlocksize + " bytes");
-                    System.Diagnostics.Debug.WriteLine("Data has length:.... " + data.Length + " bytes");
+					Console.WriteLine("Input blocksize is:  " + inBlocksize + " bytes");
+					Console.WriteLine("Output blocksize is: " + outBlocksize + " bytes");
+					Console.WriteLine("Data has length:.... " + data.Length + " bytes");
 				}
 				int datapos = 0;
 				int retpos = 0;
@@ -364,7 +364,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 					}
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("new datapos is " + datapos);
+						Console.WriteLine("new datapos is " + datapos);
 					}
 					if (tmp != null)
 					{
@@ -375,7 +375,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 					{
 						if (debug)
 						{
-                            System.Diagnostics.Debug.WriteLine("cipher returned null");
+							Console.WriteLine("cipher returned null");
 						}
 						throw new InvalidCipherTextException("cipher returned null");
 					}
@@ -384,7 +384,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 				Array.Copy(retval, 0, ret, 0, retpos);
 				if (debug)
 				{
-                    System.Diagnostics.Debug.WriteLine("returning " + ret.Length + " bytes");
+					Console.WriteLine("returning " + ret.Length + " bytes");
 				}
 				return ret;
 			}
@@ -392,7 +392,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			{
 				if (debug)
 				{
-                    System.Diagnostics.Debug.WriteLine("data size is less then input block size, processing directly");
+					Console.WriteLine("data size is less then input block size, processing directly");
 				}
 				return ProcessBlock(data, 0, data.Length);
 			}
diff --git a/crypto/src/crypto/engines/NoekeonEngine.cs b/crypto/src/crypto/engines/NoekeonEngine.cs
new file mode 100644
index 000000000..b73e696a9
--- /dev/null
+++ b/crypto/src/crypto/engines/NoekeonEngine.cs
@@ -0,0 +1,240 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* A Noekeon engine, using direct-key mode.
+	*/
+	public class NoekeonEngine
+		: IBlockCipher
+	{
+		private const int GenericSize = 16; // Block and key size, as well as the amount of rounds.
+
+		private static readonly uint[] nullVector = 
+		{
+			0x00, 0x00, 0x00, 0x00 // Used in decryption
+		};
+
+		private static readonly uint[] roundConstants = 
+		{
+			0x80, 0x1b, 0x36, 0x6c,
+			0xd8, 0xab, 0x4d, 0x9a,
+			0x2f, 0x5e, 0xbc, 0x63,
+			0xc6, 0x97, 0x35, 0x6a,
+			0xd4
+		};
+
+		private uint[]	state = new uint[4], // a
+						subKeys = new uint[4], // k
+						decryptKeys = new uint[4];
+
+		private bool _initialised, _forEncryption;
+
+		/**
+		* Create an instance of the Noekeon encryption algorithm
+		* and set some defaults
+		*/
+		public NoekeonEngine()
+		{
+			_initialised = false;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Noekeon"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return GenericSize;
+		}
+
+		/**
+		* initialise
+		*
+		* @param forEncryption whether or not we are for encryption.
+		* @param params the parameters required to set up the cipher.
+		* @exception ArgumentException if the params argument is
+		* inappropriate.
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (!(parameters is KeyParameter))
+				throw new ArgumentException("Invalid parameters passed to Noekeon init - " + parameters.GetType().Name, "parameters");
+
+			_forEncryption = forEncryption;
+			_initialised = true;
+
+			KeyParameter p = (KeyParameter) parameters;
+
+			setKey(p.GetKey());
+		}
+
+		public int ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			if (!_initialised)
+				throw new InvalidOperationException(AlgorithmName + " not initialised");
+			if ((inOff + GenericSize) > input.Length)
+				throw new DataLengthException("input buffer too short");
+			if ((outOff + GenericSize) > output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			return _forEncryption
+				?	encryptBlock(input, inOff, output, outOff)
+				:	decryptBlock(input, inOff, output, outOff);
+		}
+
+		public void Reset()
+		{
+			// TODO This should do something in case the encryption is aborted
+		}
+
+		/**
+		* Re-key the cipher.
+		*
+		* @param  key  the key to be used
+		*/
+		private void setKey(byte[] key)
+		{
+			subKeys[0] = Pack.BE_To_UInt32(key, 0);
+			subKeys[1] = Pack.BE_To_UInt32(key, 4);
+			subKeys[2] = Pack.BE_To_UInt32(key, 8);
+			subKeys[3] = Pack.BE_To_UInt32(key, 12);
+		}
+
+		private int encryptBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			state[0] = Pack.BE_To_UInt32(input, inOff);
+			state[1] = Pack.BE_To_UInt32(input, inOff+4);
+			state[2] = Pack.BE_To_UInt32(input, inOff+8);
+			state[3] = Pack.BE_To_UInt32(input, inOff+12);
+
+			int i;
+			for (i = 0; i < GenericSize; i++)
+			{
+				state[0] ^= roundConstants[i];
+				theta(state, subKeys);
+				pi1(state);
+				gamma(state);
+				pi2(state);            
+			}
+
+			state[0] ^= roundConstants[i];
+			theta(state, subKeys);
+
+			Pack.UInt32_To_BE(state[0], output, outOff);
+			Pack.UInt32_To_BE(state[1], output, outOff+4);
+			Pack.UInt32_To_BE(state[2], output, outOff+8);
+			Pack.UInt32_To_BE(state[3], output, outOff+12);
+
+			return GenericSize;
+		}
+
+		private int decryptBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			state[0] = Pack.BE_To_UInt32(input, inOff);
+			state[1] = Pack.BE_To_UInt32(input, inOff+4);
+			state[2] = Pack.BE_To_UInt32(input, inOff+8);
+			state[3] = Pack.BE_To_UInt32(input, inOff+12);
+
+			Array.Copy(subKeys, 0, decryptKeys, 0, subKeys.Length);
+			theta(decryptKeys, nullVector);
+
+			int i;
+			for (i = GenericSize; i > 0; i--)
+			{
+				theta(state, decryptKeys);
+				state[0] ^= roundConstants[i];
+				pi1(state);
+				gamma(state);
+				pi2(state);
+			}
+
+			theta(state, decryptKeys);
+			state[0] ^= roundConstants[i];
+
+			Pack.UInt32_To_BE(state[0], output, outOff);
+			Pack.UInt32_To_BE(state[1], output, outOff+4);
+			Pack.UInt32_To_BE(state[2], output, outOff+8);
+			Pack.UInt32_To_BE(state[3], output, outOff+12);
+
+			return GenericSize;
+		}
+
+		private void gamma(uint[] a)
+		{
+			a[1] ^= ~a[3] & ~a[2];
+			a[0] ^= a[2] & a[1];
+
+			uint tmp = a[3];
+			a[3]  = a[0];
+			a[0]  = tmp;
+			a[2] ^= a[0]^a[1]^a[3];
+
+			a[1] ^= ~a[3] & ~a[2];
+			a[0] ^= a[2] & a[1];
+		}
+
+		private void theta(uint[] a, uint[] k)
+		{
+			uint tmp;
+			tmp   = a[0]^a[2]; 
+			tmp  ^= rotl(tmp,8)^rotl(tmp,24); 
+			a[1] ^= tmp; 
+			a[3] ^= tmp; 
+
+			for (int i = 0; i < 4; i++)
+			{
+				a[i] ^= k[i];
+			}
+
+			tmp   = a[1]^a[3]; 
+			tmp  ^= rotl(tmp,8)^rotl(tmp,24); 
+			a[0] ^= tmp; 
+			a[2] ^= tmp;
+		}
+
+		private void pi1(uint[] a)
+		{
+			a[1] = rotl(a[1], 1);
+			a[2] = rotl(a[2], 5);
+			a[3] = rotl(a[3], 2);
+		}
+
+		private void pi2(uint[] a)
+		{
+			a[1] = rotl(a[1], 31);
+			a[2] = rotl(a[2], 27);
+			a[3] = rotl(a[3], 30);
+		}
+
+		// Helpers
+
+		private uint rotl(uint x, int y)
+		{
+			return (x << y) | (x >> (32-y));
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/NullEngine.cs b/crypto/src/crypto/engines/NullEngine.cs
new file mode 100644
index 000000000..407b8ccc6
--- /dev/null
+++ b/crypto/src/crypto/engines/NullEngine.cs
@@ -0,0 +1,70 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+	* Provided for the sake of completeness.
+	*/
+	public class NullEngine
+		: IBlockCipher
+	{
+		private bool initialised;
+		private const int BlockSize = 1;
+
+		public NullEngine()
+		{
+		}
+
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			// we don't mind any parameters that may come in
+			initialised = true;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Null"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return true; }
+		}
+
+		public int GetBlockSize()
+		{
+			return BlockSize;
+		}
+
+		public int ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			if (!initialised)
+				throw new InvalidOperationException("Null engine not initialised");
+			if ((inOff + BlockSize) > input.Length)
+				throw new DataLengthException("input buffer too short");
+			if ((outOff + BlockSize) > output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			for (int i = 0; i < BlockSize; ++i)
+			{
+				output[outOff + i] = input[inOff + i];
+			}
+
+			return BlockSize;
+		}
+
+		public void Reset()
+		{
+			// nothing needs to be done
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/RC2Engine.cs b/crypto/src/crypto/engines/RC2Engine.cs
new file mode 100644
index 000000000..aaf8c714c
--- /dev/null
+++ b/crypto/src/crypto/engines/RC2Engine.cs
@@ -0,0 +1,312 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * an implementation of RC2 as described in RFC 2268
+    *      "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+    */
+    public class RC2Engine
+		: IBlockCipher
+    {
+        //
+        // the values we use for key expansion (based on the digits of PI)
+        //
+        private static readonly 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 const int BLOCK_SIZE = 8;
+
+        private int[]   workingKey;
+        private bool 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 forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            this.encrypting = forEncryption;
+
+			if (parameters is RC2Parameters)
+            {
+                RC2Parameters param = (RC2Parameters) parameters;
+
+				workingKey = GenerateWorkingKey(param.GetKey(), param.EffectiveKeyBits);
+            }
+            else if (parameters is KeyParameter)
+            {
+				KeyParameter param = (KeyParameter) parameters;
+				byte[] key = param.GetKey();
+
+				workingKey = GenerateWorkingKey(key, key.Length * 8);
+            }
+            else
+            {
+                throw new ArgumentException("invalid parameter passed to RC2 init - " + parameters.GetType().Name);
+            }
+        }
+
+		public void Reset()
+        {
+        }
+
+		public string AlgorithmName
+        {
+            get { return "RC2"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        public  int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (workingKey == null)
+                throw new InvalidOperationException("RC2 engine not initialised");
+            if ((inOff + BLOCK_SIZE) > input.Length)
+                throw new DataLengthException("input buffer too short");
+            if ((outOff + BLOCK_SIZE) > output.Length)
+                throw new DataLengthException("output buffer too short");
+
+			if (encrypting)
+            {
+                EncryptBlock(input, inOff, output, outOff);
+            }
+            else
+            {
+                DecryptBlock(input, inOff, output, 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[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            int x76, x54, x32, x10;
+
+            x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
+            x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
+            x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
+            x10 = ((input[inOff + 1] & 0xff) << 8) + (input[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);
+            }
+
+            outBytes[outOff + 0] = (byte)x10;
+            outBytes[outOff + 1] = (byte)(x10 >> 8);
+            outBytes[outOff + 2] = (byte)x32;
+            outBytes[outOff + 3] = (byte)(x32 >> 8);
+            outBytes[outOff + 4] = (byte)x54;
+            outBytes[outOff + 5] = (byte)(x54 >> 8);
+            outBytes[outOff + 6] = (byte)x76;
+            outBytes[outOff + 7] = (byte)(x76 >> 8);
+        }
+
+        private void DecryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            int x76, x54, x32, x10;
+
+            x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff);
+            x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff);
+            x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff);
+            x10 = ((input[inOff + 1] & 0xff) << 8) + (input[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  ]);
+            }
+
+            outBytes[outOff + 0] = (byte)x10;
+            outBytes[outOff + 1] = (byte)(x10 >> 8);
+            outBytes[outOff + 2] = (byte)x32;
+            outBytes[outOff + 3] = (byte)(x32 >> 8);
+            outBytes[outOff + 4] = (byte)x54;
+            outBytes[outOff + 5] = (byte)(x54 >> 8);
+            outBytes[outOff + 6] = (byte)x76;
+            outBytes[outOff + 7] = (byte)(x76 >> 8);
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/engines/RC2WrapEngine.cs b/crypto/src/crypto/engines/RC2WrapEngine.cs
new file mode 100644
index 000000000..238c9f76a
--- /dev/null
+++ b/crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -0,0 +1,370 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	 * Wrap keys according to RFC 3217 - RC2 mechanism
+	 */
+	public class RC2WrapEngine
+		: IWrapper
+	{
+		/** Field engine */
+		private CbcBlockCipher engine;
+
+		/** Field param */
+		private ICipherParameters parameters;
+
+		/** Field paramPlusIV */
+		private ParametersWithIV paramPlusIV;
+
+		/** Field iv */
+		private byte[] iv;
+
+		/** Field forWrapping */
+		private bool forWrapping;
+
+		private SecureRandom sr;
+
+		/** Field IV2           */
+		private static readonly byte[] IV2 =
+		{
+			(byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+			(byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+			(byte) 0x21, (byte) 0x05
+		};
+
+		//
+		// checksum digest
+		//
+		IDigest sha1 = new Sha1Digest();
+		byte[] digest = new byte[20];
+
+		/**
+			* Method init
+			*
+			* @param forWrapping
+			* @param param
+			*/
+		public void Init(
+			bool				forWrapping,
+			ICipherParameters	parameters)
+		{
+			this.forWrapping = forWrapping;
+			this.engine = new CbcBlockCipher(new RC2Engine());
+
+			if (parameters is ParametersWithRandom)
+			{
+				ParametersWithRandom pWithR = (ParametersWithRandom)parameters;
+				sr = pWithR.Random;
+				parameters = pWithR.Parameters;
+			}
+			else
+			{
+				sr = new SecureRandom();
+			}
+
+			if (parameters is ParametersWithIV)
+			{
+				if (!forWrapping)
+					throw new ArgumentException("You should not supply an IV for unwrapping");
+
+				this.paramPlusIV = (ParametersWithIV)parameters;
+				this.iv = this.paramPlusIV.GetIV();
+				this.parameters = this.paramPlusIV.Parameters;
+
+				if (this.iv.Length != 8)
+					throw new ArgumentException("IV is not 8 octets");
+			}
+			else
+			{
+				this.parameters = parameters;
+
+				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.parameters, this.iv);
+				}
+			}
+		}
+
+		/**
+		* Method GetAlgorithmName
+		*
+		* @return
+		*/
+		public string AlgorithmName
+		{
+			get { return "RC2"; }
+		}
+
+		/**
+		* Method wrap
+		*
+		* @param in
+		* @param inOff
+		* @param inLen
+		* @return
+		*/
+		public byte[] Wrap(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (!forWrapping)
+			{
+				throw new InvalidOperationException("Not initialized for wrapping");
+			}
+
+			int len = length + 1;
+			if ((len % 8) != 0)
+			{
+				len += 8 - (len % 8);
+			}
+
+			byte [] keyToBeWrapped = new byte[len];
+
+			keyToBeWrapped[0] = (byte)length;
+			Array.Copy(input, inOff, keyToBeWrapped, 1, length);
+
+			byte[] pad = new byte[keyToBeWrapped.Length - length - 1];
+
+			if (pad.Length > 0)
+			{
+				sr.NextBytes(pad);
+				Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length);
+			}
+
+			// 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];
+
+			Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
+			Array.Copy(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.
+			byte [] TEMP1 = new byte[WKCKS.Length];
+
+			Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
+
+			int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
+			int extraBytes = WKCKS.Length % engine.GetBlockSize();
+
+			if (extraBytes != 0)
+			{
+				throw new InvalidOperationException("Not multiple of block length");
+			}
+
+			engine.Init(true, paramPlusIV);
+
+			for (int i = 0; i < noOfBlocks; i++)
+			{
+				int currentBytePos = i * engine.GetBlockSize();
+
+				engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+			}
+
+			// Left TEMP2 = IV || TEMP1.
+			byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
+
+			Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
+			Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
+
+			// Reverse the order of the octets in TEMP2 and call the result TEMP3.
+			byte[] TEMP3 = new byte[TEMP2.Length];
+
+			for (int i = 0; i < TEMP2.Length; i++)
+			{
+				TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
+			}
+
+			// 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.parameters, IV2);
+
+			this.engine.Init(true, param2);
+
+			for (int i = 0; i < noOfBlocks + 1; i++)
+			{
+				int currentBytePos = i * engine.GetBlockSize();
+
+				engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+			}
+
+			return TEMP3;
+		}
+
+		/**
+		* Method unwrap
+		*
+		* @param in
+		* @param inOff
+		* @param inLen
+		* @return
+		* @throws InvalidCipherTextException
+		*/
+		public byte[] Unwrap(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (forWrapping)
+			{
+				throw new InvalidOperationException("Not set for unwrapping");
+			}
+
+			if (input == null)
+			{
+				throw new InvalidCipherTextException("Null pointer as ciphertext");
+			}
+
+			if (length % engine.GetBlockSize() != 0)
+			{
+				throw new InvalidCipherTextException("Ciphertext not multiple of "
+					+ engine.GetBlockSize());
+			}
+
+			/*
+			// 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.parameters, IV2);
+
+			this.engine.Init(false, param2);
+
+			byte [] TEMP3 = new byte[length];
+
+			Array.Copy(input, inOff, TEMP3, 0, length);
+
+			for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++)
+			{
+				int currentBytePos = i * engine.GetBlockSize();
+
+				engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+			}
+
+			// Reverse the order of the octets in TEMP3 and call the result TEMP2.
+			byte[] TEMP2 = new byte[TEMP3.Length];
+
+			for (int i = 0; i < TEMP3.Length; i++)
+			{
+				TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
+			}
+
+			// 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];
+
+			Array.Copy(TEMP2, 0, this.iv, 0, 8);
+			Array.Copy(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.parameters, this.iv);
+
+			this.engine.Init(false, this.paramPlusIV);
+
+			byte[] LCEKPADICV = new byte[TEMP1.Length];
+
+			Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length);
+
+			for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++)
+			{
+				int currentBytePos = i * engine.GetBlockSize();
+
+				engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos);
+			}
+
+			// Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
+			// those octets before the CKS.
+			byte[] result = new byte[LCEKPADICV.Length - 8];
+			byte[] CKStoBeVerified = new byte[8];
+
+			Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8);
+			Array.Copy(LCEKPADICV, LCEKPADICV.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");
+			}
+
+			if ((result.Length - ((result[0] & 0xff) + 1)) > 7)
+			{
+				throw new InvalidCipherTextException(
+					"too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")");
+			}
+
+			// CEK is the wrapped key, now extracted for use in data decryption.
+			byte[] CEK = new byte[result[0]];
+			Array.Copy(result, 1, CEK, 0, CEK.Length);
+			return CEK;
+		}
+
+		/**
+		* 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
+		* @throws Exception
+		* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+		*/
+		private byte[] CalculateCmsKeyChecksum(
+			byte[] key)
+		{
+			sha1.BlockUpdate(key, 0, key.Length);
+			sha1.DoFinal(digest, 0);
+
+			byte[] result = new byte[8];
+			Array.Copy(digest, 0, result, 0, 8);
+			return result;
+		}
+
+		/**
+		* @param key
+		* @param checksum
+		* @return
+		* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+		*/
+		private bool CheckCmsKeyChecksum(
+			byte[]	key,
+			byte[]	checksum)
+		{
+			return Arrays.ConstantTimeAreEqual(CalculateCmsKeyChecksum(key), checksum);
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/RC4Engine.cs b/crypto/src/crypto/engines/RC4Engine.cs
new file mode 100644
index 000000000..c65468d93
--- /dev/null
+++ b/crypto/src/crypto/engines/RC4Engine.cs
@@ -0,0 +1,147 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    public class RC4Engine
+		: IStreamCipher
+    {
+        private readonly static int STATE_LENGTH = 256;
+
+        /*
+        * variables to hold the state of the RC4 engine
+        * during encryption and decryption
+        */
+
+        private byte[]	engineState;
+        private int		x;
+        private int		y;
+        private byte[]	workingKey;
+
+        /**
+        * initialise a RC4 cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (parameters is KeyParameter)
+            {
+                /*
+                * RC4 encryption and decryption is completely
+                * symmetrical, so the 'forEncryption' is
+                * irrelevant.
+                */
+                workingKey = ((KeyParameter)parameters).GetKey();
+                SetKey(workingKey);
+
+                return;
+            }
+
+            throw new ArgumentException("invalid parameter passed to RC4 init - " + parameters.GetType().ToString());
+        }
+
+		public string AlgorithmName
+        {
+            get { return "RC4"; }
+        }
+
+		public byte ReturnByte(
+			byte input)
+        {
+            x = (x + 1) & 0xff;
+            y = (engineState[x] + y) & 0xff;
+
+            // swap
+            byte tmp = engineState[x];
+            engineState[x] = engineState[y];
+            engineState[y] = tmp;
+
+            // xor
+            return (byte)(input ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+        }
+
+        public void ProcessBytes(
+            byte[]	input,
+            int		inOff,
+            int		length,
+            byte[]	output,
+            int		outOff
+        )
+        {
+            if ((inOff + length) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + length) > output.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            for (int i = 0; i < length ; i++)
+            {
+                x = (x + 1) & 0xff;
+                y = (engineState[x] + y) & 0xff;
+
+                // swap
+                byte tmp = engineState[x];
+                engineState[x] = engineState[y];
+                engineState[y] = tmp;
+
+                // xor
+                output[i+outOff] = (byte)(input[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/crypto/src/crypto/engines/RC532Engine.cs b/crypto/src/crypto/engines/RC532Engine.cs
new file mode 100644
index 000000000..1661707ef
--- /dev/null
+++ b/crypto/src/crypto/engines/RC532Engine.cs
@@ -0,0 +1,294 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * The specification for RC5 came from the <code>RC5 Encryption Algorithm</code>
+    * publication in RSA CryptoBytes, Spring of 1995.
+    * <em>http://www.rsasecurity.com/rsalabs/cryptobytes</em>.
+    * <p>
+    * This implementation has a word size of 32 bits.</p>
+    */
+    public class RC532Engine
+		: IBlockCipher
+    {
+        /*
+        * the number of rounds to perform
+        */
+        private int _noRounds;
+
+        /*
+        * the expanded key array of size 2*(rounds + 1)
+        */
+        private int [] _S;
+
+        /*
+        * our "magic constants" for 32 32
+        *
+        * Pw = Odd((e-2) * 2^wordsize)
+        * Qw = Odd((o-2) * 2^wordsize)
+        *
+        * where e is the base of natural logarithms (2.718281828...)
+        * and o is the golden ratio (1.61803398...)
+        */
+        private static readonly int P32 = unchecked((int) 0xb7e15163);
+        private static readonly int Q32 = unchecked((int) 0x9e3779b9);
+
+        private bool forEncryption;
+
+        /**
+        * Create an instance of the RC5 encryption algorithm
+        * and set some defaults
+        */
+        public RC532Engine()
+        {
+            _noRounds     = 12;         // the default
+//            _S            = null;
+        }
+
+        public string AlgorithmName
+        {
+            get { return "RC5-32"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+        {
+            return 2 * 4;
+        }
+
+		/**
+        * initialise a RC5-32 cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (typeof(RC5Parameters).IsInstanceOfType(parameters))
+            {
+                RC5Parameters p = (RC5Parameters)parameters;
+
+                _noRounds = p.Rounds;
+
+                SetKey(p.GetKey());
+            }
+            else if (typeof(KeyParameter).IsInstanceOfType(parameters))
+            {
+                KeyParameter p = (KeyParameter)parameters;
+
+                SetKey(p.GetKey());
+            }
+            else
+            {
+                throw new ArgumentException("invalid parameter passed to RC532 init - " + parameters.GetType().ToString());
+            }
+
+            this.forEncryption = forEncryption;
+        }
+
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            return (forEncryption)
+				?	EncryptBlock(input, inOff, output, outOff)
+				:	DecryptBlock(input, inOff, output, outOff);
+        }
+
+		public void Reset()
+        {
+        }
+
+        /**
+        * Re-key the cipher.
+        *
+        * @param  key  the key to be used
+        */
+        private void SetKey(
+            byte[] key)
+        {
+            //
+            // KEY EXPANSION:
+            //
+            // There are 3 phases to the key expansion.
+            //
+            // Phase 1:
+            //   Copy the secret key K[0...b-1] into an array L[0..c-1] of
+            //   c = ceil(b/u), where u = 32/8 in little-endian order.
+            //   In other words, we fill up L using u consecutive key bytes
+            //   of K. Any unfilled byte positions in L are zeroed. In the
+            //   case that b = c = 0, set c = 1 and L[0] = 0.
+            //
+            int[]   L = new int[(key.Length + (4 - 1)) / 4];
+
+            for (int i = 0; i != key.Length; i++)
+            {
+                L[i / 4] += (key[i] & 0xff) << (8 * (i % 4));
+            }
+
+            //
+            // Phase 2:
+            //   Initialize S to a particular fixed pseudo-random bit pattern
+            //   using an arithmetic progression modulo 2^wordsize determined
+            //   by the magic numbers, Pw & Qw.
+            //
+            _S            = new int[2*(_noRounds + 1)];
+
+            _S[0] = P32;
+            for (int i=1; i < _S.Length; i++)
+            {
+                _S[i] = (_S[i-1] + Q32);
+            }
+
+            //
+            // Phase 3:
+            //   Mix in the user's secret key in 3 passes over the arrays S & L.
+            //   The max of the arrays sizes is used as the loop control
+            //
+            int iter;
+
+            if (L.Length > _S.Length)
+            {
+                iter = 3 * L.Length;
+            }
+            else
+            {
+                iter = 3 * _S.Length;
+            }
+
+            int A = 0, B = 0;
+            int ii = 0, jj = 0;
+
+            for (int k = 0; k < iter; k++)
+            {
+                A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
+                B =  L[jj] = RotateLeft( L[jj] + A + B, A+B);
+                ii = (ii+1) % _S.Length;
+                jj = (jj+1) %  L.Length;
+            }
+        }
+
+        /**
+        * Encrypt the given block starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param  in     in byte buffer containing data to encrypt
+        * @param  inOff  offset into src buffer
+        * @param  out     out buffer where encrypted data is written
+        * @param  outOff  offset into out buffer
+        */
+        private int EncryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            int A = BytesToWord(input, inOff) + _S[0];
+            int B = BytesToWord(input, inOff + 4) + _S[1];
+
+            for (int i = 1; i <= _noRounds; i++)
+            {
+                A = RotateLeft(A ^ B, B) + _S[2*i];
+                B = RotateLeft(B ^ A, A) + _S[2*i+1];
+            }
+
+            WordToBytes(A, outBytes, outOff);
+            WordToBytes(B, outBytes, outOff + 4);
+
+            return 2 * 4;
+        }
+
+        private int DecryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            int A = BytesToWord(input, inOff);
+            int B = BytesToWord(input, inOff + 4);
+
+            for (int i = _noRounds; i >= 1; i--)
+            {
+                B = RotateRight(B - _S[2*i+1], A) ^ A;
+                A = RotateRight(A - _S[2*i],   B) ^ B;
+            }
+
+            WordToBytes(A - _S[0], outBytes, outOff);
+            WordToBytes(B - _S[1], outBytes, outOff + 4);
+
+            return 2 * 4;
+        }
+
+
+        //////////////////////////////////////////////////////////////
+        //
+        // PRIVATE Helper Methods
+        //
+        //////////////////////////////////////////////////////////////
+
+        /**
+        * Perform a left "spin" of the word. The rotation of the given
+        * word <em>x</em> is rotated left by <em>y</em> bits.
+        * Only the <em>lg(32)</em> low-order bits of <em>y</em>
+        * are used to determine the rotation amount. Here it is
+        * assumed that the wordsize used is a power of 2.
+        *
+        * @param  x  word to rotate
+        * @param  y    number of bits to rotate % 32
+        */
+        private int RotateLeft(int x, int y) {
+            return ((int)  (  (uint) (x << (y & (32-1))) |
+                              ((uint) x >> (32 - (y & (32-1)))) )
+                   );
+        }
+
+        /**
+        * Perform a right "spin" of the word. The rotation of the given
+        * word <em>x</em> is rotated left by <em>y</em> bits.
+        * Only the <em>lg(32)</em> low-order bits of <em>y</em>
+        * are used to determine the rotation amount. Here it is
+        * assumed that the wordsize used is a power of 2.
+        *
+        * @param  x  word to rotate
+        * @param  y    number of bits to rotate % 32
+        */
+        private int RotateRight(int x, int y) {
+            return ((int) (     ((uint) x >> (y & (32-1))) |
+                                (uint) (x << (32 - (y & (32-1))))   )
+                   );
+        }
+
+        private int BytesToWord(
+            byte[]  src,
+            int     srcOff)
+        {
+            return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8)
+                | ((src[srcOff + 2] & 0xff) << 16) | ((src[srcOff + 3] & 0xff) << 24);
+        }
+
+        private void WordToBytes(
+            int    word,
+            byte[]  dst,
+            int     dstOff)
+        {
+            dst[dstOff] = (byte)word;
+            dst[dstOff + 1] = (byte)(word >> 8);
+            dst[dstOff + 2] = (byte)(word >> 16);
+            dst[dstOff + 3] = (byte)(word >> 24);
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/engines/RC564Engine.cs b/crypto/src/crypto/engines/RC564Engine.cs
new file mode 100644
index 000000000..5c69d40ff
--- /dev/null
+++ b/crypto/src/crypto/engines/RC564Engine.cs
@@ -0,0 +1,295 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * The specification for RC5 came from the <code>RC5 Encryption Algorithm</code>
+    * publication in RSA CryptoBytes, Spring of 1995.
+    * <em>http://www.rsasecurity.com/rsalabs/cryptobytes</em>.
+    * <p>
+    * This implementation is set to work with a 64 bit word size.</p>
+    */
+    public class RC564Engine
+		: IBlockCipher
+    {
+        private static readonly int wordSize = 64;
+        private static readonly int bytesPerWord = wordSize / 8;
+
+        /*
+        * the number of rounds to perform
+        */
+        private int _noRounds;
+
+        /*
+        * the expanded key array of size 2*(rounds + 1)
+        */
+        private long [] _S;
+
+        /*
+        * our "magic constants" for wordSize 62
+        *
+        * Pw = Odd((e-2) * 2^wordsize)
+        * Qw = Odd((o-2) * 2^wordsize)
+        *
+        * where e is the base of natural logarithms (2.718281828...)
+        * and o is the golden ratio (1.61803398...)
+        */
+        private static readonly long P64 = unchecked( (long) 0xb7e151628aed2a6bL);
+        private static readonly long Q64 = unchecked( (long) 0x9e3779b97f4a7c15L);
+
+        private bool forEncryption;
+
+        /**
+        * Create an instance of the RC5 encryption algorithm
+        * and set some defaults
+        */
+        public RC564Engine()
+        {
+            _noRounds     = 12;
+//            _S            = null;
+        }
+
+        public string AlgorithmName
+        {
+            get { return "RC5-64"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+        {
+            return 2 * bytesPerWord;
+        }
+
+        /**
+        * initialise a RC5-64 cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool             forEncryption,
+            ICipherParameters    parameters)
+        {
+            if (!(typeof(RC5Parameters).IsInstanceOfType(parameters)))
+            {
+                throw new ArgumentException("invalid parameter passed to RC564 init - " + parameters.GetType().ToString());
+            }
+
+            RC5Parameters       p = (RC5Parameters)parameters;
+
+            this.forEncryption = forEncryption;
+
+            _noRounds     = p.Rounds;
+
+            SetKey(p.GetKey());
+        }
+
+        public int ProcessBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  output,
+            int     outOff)
+        {
+            return (forEncryption) ? EncryptBlock(input, inOff, output, outOff)
+                                        : DecryptBlock(input, inOff, output, outOff);
+        }
+
+        public void Reset()
+        {
+        }
+
+        /**
+        * Re-key the cipher.
+        *
+        * @param  key  the key to be used
+        */
+        private void SetKey(
+            byte[]      key)
+        {
+            //
+            // KEY EXPANSION:
+            //
+            // There are 3 phases to the key expansion.
+            //
+            // Phase 1:
+            //   Copy the secret key K[0...b-1] into an array L[0..c-1] of
+            //   c = ceil(b/u), where u = wordSize/8 in little-endian order.
+            //   In other words, we fill up L using u consecutive key bytes
+            //   of K. Any unfilled byte positions in L are zeroed. In the
+            //   case that b = c = 0, set c = 1 and L[0] = 0.
+            //
+            long[]   L = new long[(key.Length + (bytesPerWord - 1)) / bytesPerWord];
+
+            for (int i = 0; i != key.Length; i++)
+            {
+                L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord));
+            }
+
+            //
+            // Phase 2:
+            //   Initialize S to a particular fixed pseudo-random bit pattern
+            //   using an arithmetic progression modulo 2^wordsize determined
+            //   by the magic numbers, Pw & Qw.
+            //
+            _S            = new long[2*(_noRounds + 1)];
+
+            _S[0] = P64;
+            for (int i=1; i < _S.Length; i++)
+            {
+                _S[i] = (_S[i-1] + Q64);
+            }
+
+            //
+            // Phase 3:
+            //   Mix in the user's secret key in 3 passes over the arrays S & L.
+            //   The max of the arrays sizes is used as the loop control
+            //
+            int iter;
+
+            if (L.Length > _S.Length)
+            {
+                iter = 3 * L.Length;
+            }
+            else
+            {
+                iter = 3 * _S.Length;
+            }
+
+            long A = 0, B = 0;
+            int ii = 0, jj = 0;
+
+            for (int k = 0; k < iter; k++)
+            {
+                A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
+                B =  L[jj] = RotateLeft( L[jj] + A + B, A+B);
+                ii = (ii+1) % _S.Length;
+                jj = (jj+1) %  L.Length;
+            }
+        }
+
+        /**
+        * Encrypt the given block starting at the given offset and place
+        * the result in the provided buffer starting at the given offset.
+        *
+        * @param  in      in byte buffer containing data to encrypt
+        * @param  inOff   offset into src buffer
+        * @param  out     out buffer where encrypted data is written
+        * @param  outOff  offset into out buffer
+        */
+        private int EncryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            long A = BytesToWord(input, inOff) + _S[0];
+            long B = BytesToWord(input, inOff + bytesPerWord) + _S[1];
+
+            for (int i = 1; i <= _noRounds; i++)
+            {
+                A = RotateLeft(A ^ B, B) + _S[2*i];
+                B = RotateLeft(B ^ A, A) + _S[2*i+1];
+            }
+
+            WordToBytes(A, outBytes, outOff);
+            WordToBytes(B, outBytes, outOff + bytesPerWord);
+
+            return 2 * bytesPerWord;
+        }
+
+        private int DecryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            long A = BytesToWord(input, inOff);
+            long B = BytesToWord(input, inOff + bytesPerWord);
+
+            for (int i = _noRounds; i >= 1; i--)
+            {
+                B = RotateRight(B - _S[2*i+1], A) ^ A;
+                A = RotateRight(A - _S[2*i],   B) ^ B;
+            }
+
+            WordToBytes(A - _S[0], outBytes, outOff);
+            WordToBytes(B - _S[1], outBytes, outOff + bytesPerWord);
+
+            return 2 * bytesPerWord;
+        }
+
+
+        //////////////////////////////////////////////////////////////
+        //
+        // PRIVATE Helper Methods
+        //
+        //////////////////////////////////////////////////////////////
+
+        /**
+        * Perform a left "spin" of the word. The rotation of the given
+        * word <em>x</em> is rotated left by <em>y</em> bits.
+        * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
+        * are used to determine the rotation amount. Here it is
+        * assumed that the wordsize used is a power of 2.
+        *
+        * @param  x  word to rotate
+        * @param  y    number of bits to rotate % wordSize
+        */
+        private long RotateLeft(long x, long y) {
+            return ((long) (    (ulong) (x << (int) (y & (wordSize-1))) |
+                                ((ulong) x >> (int) (wordSize - (y & (wordSize-1)))))
+                   );
+        }
+
+        /**
+        * Perform a right "spin" of the word. The rotation of the given
+        * word <em>x</em> is rotated left by <em>y</em> bits.
+        * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
+        * are used to determine the rotation amount. Here it is
+        * assumed that the wordsize used is a power of 2.
+        *
+        * @param x word to rotate
+        * @param y number of bits to rotate % wordSize
+        */
+        private long RotateRight(long x, long y) {
+            return ((long) (    ((ulong) x >> (int) (y & (wordSize-1))) |
+                                (ulong) (x << (int) (wordSize - (y & (wordSize-1)))))
+                   );
+        }
+
+        private long BytesToWord(
+            byte[]  src,
+            int     srcOff)
+        {
+            long    word = 0;
+
+            for (int i = bytesPerWord - 1; i >= 0; i--)
+            {
+                word = (word << 8) + (src[i + srcOff] & 0xff);
+            }
+
+            return word;
+        }
+
+        private void WordToBytes(
+            long    word,
+            byte[]  dst,
+            int     dstOff)
+        {
+            for (int i = 0; i < bytesPerWord; i++)
+            {
+                dst[i + dstOff] = (byte)word;
+                word = (long) ((ulong) word >> 8);
+            }
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/engines/RC6Engine.cs b/crypto/src/crypto/engines/RC6Engine.cs
new file mode 100644
index 000000000..d72cc2f7b
--- /dev/null
+++ b/crypto/src/crypto/engines/RC6Engine.cs
@@ -0,0 +1,362 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * An RC6 engine.
+    */
+    public class RC6Engine
+		: IBlockCipher
+    {
+        private static readonly int wordSize = 32;
+        private static readonly int bytesPerWord = wordSize / 8;
+
+        /*
+        * the number of rounds to perform
+        */
+        private static readonly int _noRounds = 20;
+
+        /*
+        * the expanded key array of size 2*(rounds + 1)
+        */
+        private int [] _S;
+
+        /*
+        * our "magic constants" for wordSize 32
+        *
+        * Pw = Odd((e-2) * 2^wordsize)
+        * Qw = Odd((o-2) * 2^wordsize)
+        *
+        * where e is the base of natural logarithms (2.718281828...)
+        * and o is the golden ratio (1.61803398...)
+        */
+        private static readonly int    P32 = unchecked((int) 0xb7e15163);
+        private static readonly int    Q32 = unchecked((int) 0x9e3779b9);
+
+        private static readonly int    LGW = 5;        // log2(32)
+
+        private bool forEncryption;
+
+        /**
+        * Create an instance of the RC6 encryption algorithm
+        * and set some defaults
+        */
+        public RC6Engine()
+        {
+//            _S            = null;
+        }
+
+        public string AlgorithmName
+        {
+            get { return "RC6"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+        {
+            return 4 * bytesPerWord;
+        }
+
+        /**
+        * initialise a RC5-32 cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is KeyParameter))
+                throw new ArgumentException("invalid parameter passed to RC6 init - " + parameters.GetType().ToString());
+
+            this.forEncryption = forEncryption;
+
+			KeyParameter p = (KeyParameter)parameters;
+			SetKey(p.GetKey());
+        }
+
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+			int blockSize = GetBlockSize();
+			if (_S == null)
+				throw new InvalidOperationException("RC6 engine not initialised");
+			if ((inOff + blockSize) > input.Length)
+				throw new DataLengthException("input buffer too short");
+			if ((outOff + blockSize) > output.Length)
+				throw new DataLengthException("output buffer too short");
+
+			return (forEncryption)
+				?	EncryptBlock(input, inOff, output, outOff)
+				:	DecryptBlock(input, inOff, output, outOff);
+        }
+
+		public void Reset()
+        {
+        }
+
+        /**
+        * Re-key the cipher.
+        *
+        * @param inKey the key to be used
+        */
+        private void SetKey(
+            byte[] key)
+        {
+            //
+            // KEY EXPANSION:
+            //
+            // There are 3 phases to the key expansion.
+            //
+            // Phase 1:
+            //   Copy the secret key K[0...b-1] into an array L[0..c-1] of
+            //   c = ceil(b/u), where u = wordSize/8 in little-endian order.
+            //   In other words, we fill up L using u consecutive key bytes
+            //   of K. Any unfilled byte positions in L are zeroed. In the
+            //   case that b = c = 0, set c = 1 and L[0] = 0.
+            //
+            // compute number of dwords
+            int c = (key.Length + (bytesPerWord - 1)) / bytesPerWord;
+            if (c == 0)
+            {
+                c = 1;
+            }
+            int[]   L = new int[(key.Length + bytesPerWord - 1) / bytesPerWord];
+
+            // load all key bytes into array of key dwords
+            for (int i = key.Length - 1; i >= 0; i--)
+            {
+                L[i / bytesPerWord] = (L[i / bytesPerWord] << 8) + (key[i] & 0xff);
+            }
+
+            //
+            // Phase 2:
+            //   Key schedule is placed in a array of 2+2*ROUNDS+2 = 44 dwords.
+            //   Initialize S to a particular fixed pseudo-random bit pattern
+            //   using an arithmetic progression modulo 2^wordsize determined
+            //   by the magic numbers, Pw & Qw.
+            //
+            _S            = new int[2+2*_noRounds+2];
+
+            _S[0] = P32;
+            for (int i=1; i < _S.Length; i++)
+            {
+                _S[i] = (_S[i-1] + Q32);
+            }
+
+            //
+            // Phase 3:
+            //   Mix in the user's secret key in 3 passes over the arrays S & L.
+            //   The max of the arrays sizes is used as the loop control
+            //
+            int iter;
+
+            if (L.Length > _S.Length)
+            {
+                iter = 3 * L.Length;
+            }
+            else
+            {
+                iter = 3 * _S.Length;
+            }
+
+            int A = 0;
+            int B = 0;
+            int ii = 0, jj = 0;
+
+            for (int k = 0; k < iter; k++)
+            {
+                A = _S[ii] = RotateLeft(_S[ii] + A + B, 3);
+                B =  L[jj] = RotateLeft( L[jj] + A + B, A+B);
+                ii = (ii+1) % _S.Length;
+                jj = (jj+1) %  L.Length;
+            }
+        }
+
+        private int EncryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            // load A,B,C and D registers from in.
+            int A = BytesToWord(input, inOff);
+            int B = BytesToWord(input, inOff + bytesPerWord);
+            int C = BytesToWord(input, inOff + bytesPerWord*2);
+            int D = BytesToWord(input, inOff + bytesPerWord*3);
+
+            // Do pseudo-round #0: pre-whitening of B and D
+            B += _S[0];
+            D += _S[1];
+
+            // perform round #1,#2 ... #ROUNDS of encryption
+            for (int i = 1; i <= _noRounds; i++)
+            {
+                int t = 0,u = 0;
+
+                t = B*(2*B+1);
+                t = RotateLeft(t,5);
+
+                u = D*(2*D+1);
+                u = RotateLeft(u,5);
+
+                A ^= t;
+                A = RotateLeft(A,u);
+                A += _S[2*i];
+
+                C ^= u;
+                C = RotateLeft(C,t);
+                C += _S[2*i+1];
+
+                int temp = A;
+                A = B;
+                B = C;
+                C = D;
+                D = temp;
+            }
+            // do pseudo-round #(ROUNDS+1) : post-whitening of A and C
+            A += _S[2*_noRounds+2];
+            C += _S[2*_noRounds+3];
+
+            // store A, B, C and D registers to out
+            WordToBytes(A, outBytes, outOff);
+            WordToBytes(B, outBytes, outOff + bytesPerWord);
+            WordToBytes(C, outBytes, outOff + bytesPerWord*2);
+            WordToBytes(D, outBytes, outOff + bytesPerWord*3);
+
+            return 4 * bytesPerWord;
+        }
+
+        private int DecryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            // load A,B,C and D registers from out.
+            int A = BytesToWord(input, inOff);
+            int B = BytesToWord(input, inOff + bytesPerWord);
+            int C = BytesToWord(input, inOff + bytesPerWord*2);
+            int D = BytesToWord(input, inOff + bytesPerWord*3);
+
+            // Undo pseudo-round #(ROUNDS+1) : post whitening of A and C
+            C -= _S[2*_noRounds+3];
+            A -= _S[2*_noRounds+2];
+
+            // Undo round #ROUNDS, .., #2,#1 of encryption
+            for (int i = _noRounds; i >= 1; i--)
+            {
+                int t=0,u = 0;
+
+                int temp = D;
+                D = C;
+                C = B;
+                B = A;
+                A = temp;
+
+                t = B*(2*B+1);
+                t = RotateLeft(t, LGW);
+
+                u = D*(2*D+1);
+                u = RotateLeft(u, LGW);
+
+                C -= _S[2*i+1];
+                C = RotateRight(C,t);
+                C ^= u;
+
+                A -= _S[2*i];
+                A = RotateRight(A,u);
+                A ^= t;
+
+            }
+            // Undo pseudo-round #0: pre-whitening of B and D
+            D -= _S[1];
+            B -= _S[0];
+
+            WordToBytes(A, outBytes, outOff);
+            WordToBytes(B, outBytes, outOff + bytesPerWord);
+            WordToBytes(C, outBytes, outOff + bytesPerWord*2);
+            WordToBytes(D, outBytes, outOff + bytesPerWord*3);
+
+            return 4 * bytesPerWord;
+        }
+
+
+        //////////////////////////////////////////////////////////////
+        //
+        // PRIVATE Helper Methods
+        //
+        //////////////////////////////////////////////////////////////
+
+        /**
+        * Perform a left "spin" of the word. The rotation of the given
+        * word <em>x</em> is rotated left by <em>y</em> bits.
+        * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
+        * are used to determine the rotation amount. Here it is
+        * assumed that the wordsize used is a power of 2.
+        *
+        * @param x word to rotate
+        * @param y number of bits to rotate % wordSize
+        */
+        private int RotateLeft(int x, int y)
+        {
+            return ((int)((uint)(x << (y & (wordSize-1)))
+				| ((uint) x >> (wordSize - (y & (wordSize-1))))));
+        }
+
+        /**
+        * Perform a right "spin" of the word. The rotation of the given
+        * word <em>x</em> is rotated left by <em>y</em> bits.
+        * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em>
+        * are used to determine the rotation amount. Here it is
+        * assumed that the wordsize used is a power of 2.
+        *
+        * @param x word to rotate
+        * @param y number of bits to rotate % wordSize
+        */
+        private int RotateRight(int x, int y) 
+		{
+            return ((int)(((uint) x >> (y & (wordSize-1)))
+				| (uint)(x << (wordSize - (y & (wordSize-1))))));
+        }
+
+        private int BytesToWord(
+            byte[]	src,
+            int		srcOff)
+        {
+            int word = 0;
+
+            for (int i = bytesPerWord - 1; i >= 0; i--)
+            {
+                word = (word << 8) + (src[i + srcOff] & 0xff);
+            }
+
+            return word;
+        }
+
+        private void WordToBytes(
+            int		word,
+            byte[]	dst,
+            int		dstOff)
+        {
+            for (int i = 0; i < bytesPerWord; i++)
+            {
+                dst[i + dstOff] = (byte)word;
+                word = (int) ((uint) word >> 8);
+            }
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
new file mode 100644
index 000000000..e520075f9
--- /dev/null
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -0,0 +1,168 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	 * an implementation of the RFC 3211 Key Wrap
+	 * Specification.
+	 */
+	public class Rfc3211WrapEngine
+		: IWrapper
+	{
+		private CbcBlockCipher		engine;
+		private ParametersWithIV	param;
+		private bool				forWrapping;
+		private SecureRandom		rand;
+
+		public Rfc3211WrapEngine(
+			IBlockCipher engine)
+		{
+			this.engine = new CbcBlockCipher(engine);
+		}
+
+		public void Init(
+			bool				forWrapping,
+			ICipherParameters	param)
+		{
+			this.forWrapping = forWrapping;
+
+			if (param is ParametersWithRandom)
+			{
+				ParametersWithRandom p = (ParametersWithRandom) param;
+
+				this.rand = p.Random;
+				this.param = (ParametersWithIV) p.Parameters;
+			}
+			else
+			{
+				if (forWrapping)
+				{
+					rand = new SecureRandom();
+				}
+
+				this.param = (ParametersWithIV) param;
+			}
+		}
+
+		public string AlgorithmName
+		{
+			get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
+		}
+
+		public byte[] Wrap(
+			byte[]	inBytes,
+			int		inOff,
+			int		inLen)
+		{
+			if (!forWrapping)
+			{
+				throw new InvalidOperationException("not set for wrapping");
+			}
+
+			engine.Init(true, param);
+
+			int blockSize = engine.GetBlockSize();
+			byte[] cekBlock;
+
+			if (inLen + 4 < blockSize * 2)
+			{
+				cekBlock = new byte[blockSize * 2];
+			}
+			else
+			{
+				cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize];
+			}
+
+			cekBlock[0] = (byte)inLen;
+			cekBlock[1] = (byte)~inBytes[inOff];
+			cekBlock[2] = (byte)~inBytes[inOff + 1];
+			cekBlock[3] = (byte)~inBytes[inOff + 2];
+
+			Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
+
+			rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
+
+			for (int i = 0; i < cekBlock.Length; i += blockSize)
+			{
+				engine.ProcessBlock(cekBlock, i, cekBlock, i);
+			}
+
+			for (int i = 0; i < cekBlock.Length; i += blockSize)
+			{
+				engine.ProcessBlock(cekBlock, i, cekBlock, i);
+			}
+
+			return cekBlock;
+		}
+
+		public byte[] Unwrap(
+			byte[]	inBytes,
+			int		inOff,
+			int		inLen)
+		{
+			if (forWrapping)
+			{
+				throw new InvalidOperationException("not set for unwrapping");
+			}
+
+			int blockSize = engine.GetBlockSize();
+
+			if (inLen < 2 * blockSize)
+			{
+				throw new InvalidCipherTextException("input too short");
+			}
+
+			byte[] cekBlock = new byte[inLen];
+			byte[] iv = new byte[blockSize];
+
+			Array.Copy(inBytes, inOff, cekBlock, 0, inLen);
+			Array.Copy(inBytes, inOff, iv, 0, iv.Length);
+
+			engine.Init(false, new ParametersWithIV(param.Parameters, iv));
+
+			for (int i = blockSize; i < cekBlock.Length; i += blockSize)
+			{
+				engine.ProcessBlock(cekBlock, i, cekBlock, i);    
+			}
+
+			Array.Copy(cekBlock, cekBlock.Length - iv.Length, iv, 0, iv.Length);
+
+			engine.Init(false, new ParametersWithIV(param.Parameters, iv));
+
+			engine.ProcessBlock(cekBlock, 0, cekBlock, 0);
+
+			engine.Init(false, param);
+
+			for (int i = 0; i < cekBlock.Length; i += blockSize)
+			{
+				engine.ProcessBlock(cekBlock, i, cekBlock, i);
+			}
+
+			if ((cekBlock[0] & 0xff) > cekBlock.Length - 4)
+			{
+				throw new InvalidCipherTextException("wrapped key corrupted");
+			}
+
+			byte[] key = new byte[cekBlock[0] & 0xff];
+
+			Array.Copy(cekBlock, 4, key, 0, cekBlock[0]);
+
+			// Note: Using constant time comparison
+			int nonEqual = 0;
+			for (int i = 0; i != 3; i++)
+			{
+				byte check = (byte)~cekBlock[1 + i];
+				nonEqual |= (check ^ key[i]);
+			}
+
+			if (nonEqual != 0)
+				throw new InvalidCipherTextException("wrapped key fails checksum");
+
+			return key;
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/RFC3394WrapEngine.cs b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
index 7596e7218..5615a63e5 100644
--- a/crypto/src/crypto/engines/RFC3394WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
@@ -90,7 +90,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			byte[] buf = new byte[8 + iv.Length];
 
 			Array.Copy(iv, 0, block, 0, iv.Length);
-			Array.Copy(input, 0, block, iv.Length, inLen);
+			Array.Copy(input, inOff, block, iv.Length, inLen);
 
 			engine.Init(true, param);
 
@@ -140,8 +140,8 @@ namespace Org.BouncyCastle.Crypto.Engines
 			byte[]  a = new byte[iv.Length];
 			byte[]  buf = new byte[8 + iv.Length];
 
-			Array.Copy(input, 0, a, 0, iv.Length);
-			Array.Copy(input, iv.Length, block, 0, inLen - iv.Length);
+			Array.Copy(input, inOff, a, 0, iv.Length);
+            Array.Copy(input, inOff + iv.Length, block, 0, inLen - iv.Length);
 
 			engine.Init(false, param);
 
diff --git a/crypto/src/crypto/engines/RSABlindedEngine.cs b/crypto/src/crypto/engines/RSABlindedEngine.cs
new file mode 100644
index 000000000..cdf69ddda
--- /dev/null
+++ b/crypto/src/crypto/engines/RSABlindedEngine.cs
@@ -0,0 +1,124 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	 * this does your basic RSA algorithm with blinding
+	 */
+	public class RsaBlindedEngine
+		: IAsymmetricBlockCipher
+	{
+		private readonly RsaCoreEngine core = new RsaCoreEngine();
+		private RsaKeyParameters key;
+		private SecureRandom random;
+
+		public string AlgorithmName
+		{
+			get { return "RSA"; }
+		}
+
+		/**
+		 * initialise the RSA engine.
+		 *
+		 * @param forEncryption true if we are encrypting, false otherwise.
+		 * @param param the necessary RSA key parameters.
+		 */
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	param)
+		{
+			core.Init(forEncryption, param);
+
+			if (param is ParametersWithRandom)
+			{
+				ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+				key = (RsaKeyParameters)rParam.Parameters;
+				random = rParam.Random;
+			}
+			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 inBuf 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[]	inBuf,
+			int		inOff,
+			int		inLen)
+		{
+			if (key == null)
+				throw new InvalidOperationException("RSA engine not initialised");
+
+			BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
+
+			BigInteger result;
+			if (key is RsaPrivateCrtKeyParameters)
+			{
+				RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
+				BigInteger e = k.PublicExponent;
+				if (e != null)   // can't do blinding without a public exponent
+				{
+					BigInteger m = k.Modulus;
+					BigInteger r = BigIntegers.CreateRandomInRange(
+						BigInteger.One, m.Subtract(BigInteger.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/crypto/src/crypto/engines/RSABlindingEngine.cs b/crypto/src/crypto/engines/RSABlindingEngine.cs
new file mode 100644
index 000000000..76b57a3f7
--- /dev/null
+++ b/crypto/src/crypto/engines/RSABlindingEngine.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* This does your basic RSA Chaum's blinding and unblinding as outlined in
+	* "Handbook of Applied Cryptography", page 475. You need to use this if you are
+	* trying to get another party to generate signatures without them being aware
+	* of the message they are signing.
+	*/
+	public class RsaBlindingEngine
+		: IAsymmetricBlockCipher
+	{
+		private readonly RsaCoreEngine core = new RsaCoreEngine();
+
+		private RsaKeyParameters key;
+		private BigInteger blindingFactor;
+
+		private bool forEncryption;
+
+		public string AlgorithmName
+		{
+			get { return "RSA"; }
+		}
+
+		/**
+		* Initialise the blinding engine.
+		*
+		* @param forEncryption true if we are encrypting (blinding), false otherwise.
+		* @param param         the necessary RSA key parameters.
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	param)
+		{
+			RsaBlindingParameters p;
+
+			if (param is ParametersWithRandom)
+			{
+				ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+				p = (RsaBlindingParameters)rParam.Parameters;
+			}
+			else
+			{
+				p = (RsaBlindingParameters)param;
+			}
+
+			core.Init(forEncryption, p.PublicKey);
+
+			this.forEncryption = forEncryption;
+			this.key = p.PublicKey;
+			this.blindingFactor = p.BlindingFactor;
+		}
+
+		/**
+		* 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 RSA blinding 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.
+		* @throws DataLengthException the input block is too large.
+		*/
+		public byte[] ProcessBlock(
+			byte[]	inBuf,
+			int		inOff,
+			int		inLen)
+		{
+			BigInteger msg = core.ConvertInput(inBuf, inOff, inLen);
+
+			if (forEncryption)
+			{
+				msg = BlindMessage(msg);
+			}
+			else
+			{
+				msg = UnblindMessage(msg);
+			}
+
+			return core.ConvertOutput(msg);
+		}
+
+		/*
+		* Blind message with the blind factor.
+		*/
+		private BigInteger BlindMessage(
+			BigInteger msg)
+		{
+			BigInteger blindMsg = blindingFactor;
+			blindMsg = msg.Multiply(blindMsg.ModPow(key.Exponent, key.Modulus));
+			blindMsg = blindMsg.Mod(key.Modulus);
+
+			return blindMsg;
+		}
+
+		/*
+		* Unblind the message blinded with the blind factor.
+		*/
+		private BigInteger UnblindMessage(
+			BigInteger blindedMsg)
+		{
+			BigInteger m = key.Modulus;
+			BigInteger msg = blindedMsg;
+			BigInteger blindFactorInverse = blindingFactor.ModInverse(m);
+			msg = msg.Multiply(blindFactorInverse);
+			msg = msg.Mod(m);
+
+			return msg;
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/RSACoreEngine.cs b/crypto/src/crypto/engines/RSACoreEngine.cs
new file mode 100644
index 000000000..4e64d25d6
--- /dev/null
+++ b/crypto/src/crypto/engines/RSACoreEngine.cs
@@ -0,0 +1,156 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* this does your basic RSA algorithm.
+	*/
+	class RsaCoreEngine
+	{
+		private RsaKeyParameters	key;
+		private bool				forEncryption;
+		private int					bitSize;
+
+		/**
+		* initialise the RSA engine.
+		*
+		* @param forEncryption true if we are encrypting, false otherwise.
+		* @param param the necessary RSA key parameters.
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			if (!(parameters is RsaKeyParameters))
+				throw new InvalidKeyException("Not an RSA key");
+
+			this.key = (RsaKeyParameters) parameters;
+			this.forEncryption = forEncryption;
+			this.bitSize = key.Modulus.BitLength;
+		}
+
+		/**
+		* 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()
+		{
+			if (forEncryption)
+			{
+				return (bitSize - 1) / 8;
+			}
+
+			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()
+		{
+			if (forEncryption)
+			{
+				return (bitSize + 7) / 8;
+			}
+
+			return (bitSize - 1) / 8;
+		}
+
+		public BigInteger ConvertInput(
+			byte[]	inBuf,
+			int		inOff,
+			int		inLen)
+		{
+			int maxLength = (bitSize + 7) / 8;
+
+			if (inLen > maxLength)
+				throw new DataLengthException("input too large for RSA cipher.");
+
+			BigInteger input = new BigInteger(1, inBuf, inOff, inLen);
+
+			if (input.CompareTo(key.Modulus) >= 0)
+				throw new DataLengthException("input too large for RSA cipher.");
+
+			return input;
+		}
+
+		public byte[] ConvertOutput(
+			BigInteger result)
+		{
+			byte[] output = result.ToByteArrayUnsigned();
+
+			if (forEncryption)
+			{
+				int outSize = GetOutputBlockSize();
+
+				// TODO To avoid this, create version of BigInteger.ToByteArray that
+				// writes to an existing array
+				if (output.Length < outSize) // have ended up with less bytes than normal, lengthen
+				{
+					byte[] tmp = new byte[outSize];
+					output.CopyTo(tmp, tmp.Length - output.Length);
+					output = tmp;
+				}
+			}
+
+			return output;
+		}
+
+		public BigInteger ProcessBlock(
+			BigInteger input)
+		{
+			if (key is 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.P;;
+				BigInteger q = crtKey.Q;
+				BigInteger dP = crtKey.DP;
+				BigInteger dQ = crtKey.DQ;
+				BigInteger qInv = crtKey.QInv;
+
+				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;
+			}
+
+			return input.ModPow(key.Exponent, key.Modulus);
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/RijndaelEngine.cs b/crypto/src/crypto/engines/RijndaelEngine.cs
new file mode 100644
index 000000000..df2e5baea
--- /dev/null
+++ b/crypto/src/crypto/engines/RijndaelEngine.cs
@@ -0,0 +1,747 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* an implementation of Rijndael, based on the documentation and reference implementation
+	* by Paulo Barreto, Vincent Rijmen, for v2.0 August '99.
+	* <p>
+	* Note: this implementation is based on information prior to readonly NIST publication.
+	* </p>
+	*/
+	public class RijndaelEngine
+		: IBlockCipher
+	{
+		private static readonly int MAXROUNDS = 14;
+
+		private static readonly int MAXKC = (256/4);
+
+		private static readonly byte[] Logtable =
+		{
+			0,    0,    25,   1,    50,   2,    26,   198,
+			75,   199,  27,   104,  51,   238,  223,  3,
+			100,  4,    224,  14,   52,   141,  129,  239,
+			76,   113,  8,    200,  248,  105,  28,   193,
+			125,  194,  29,   181,  249,  185,  39,   106,
+			77,   228,  166,  114,  154,  201,  9,    120,
+			101,  47,   138,  5,    33,   15,   225,  36,
+			18,   240,  130,  69,   53,   147,  218,  142,
+			150,  143,  219,  189,  54,   208,  206,  148,
+			19,   92,   210,  241,  64,   70,   131,  56,
+			102,  221,  253,  48,   191,  6,    139,  98,
+			179,  37,   226,  152,  34,   136,  145,  16,
+			126,  110,  72,   195,  163,  182,  30,   66,
+			58,   107,  40,   84,   250,  133,  61,   186,
+			43,   121,  10,   21,   155,  159,  94,   202,
+			78,   212,  172,  229,  243,  115,  167,  87,
+			175,  88,   168,  80,   244,  234,  214,  116,
+			79,   174,  233,  213,  231,  230,  173,  232,
+			44,   215,  117,  122,  235,  22,   11,   245,
+			89,   203,  95,   176,  156,  169,  81,   160,
+			127,  12,   246,  111,  23,   196,  73,   236,
+			216,  67,   31,   45,   164,  118,  123,  183,
+			204,  187,  62,   90,   251,  96,   177,  134,
+			59,   82,   161,  108,  170,  85,   41,   157,
+			151,  178,  135,  144,  97,   190,  220,  252,
+			188,  149,  207,  205,  55,   63,   91,   209,
+			83,   57,   132,  60,   65,   162,  109,  71,
+			20,   42,   158,  93,   86,   242,  211,  171,
+			68,   17,   146,  217,  35,   32,   46,   137,
+			180,  124,  184,  38,   119,  153,  227,  165,
+			103,  74,   237,  222,  197,  49,   254,  24,
+			13,   99,   140,  128,  192,  247,  112,  7
+		};
+
+		private static readonly byte[] Alogtable =
+		{
+			0,   3,   5,  15,  17,  51,  85, 255,  26,  46, 114, 150, 161, 248,  19,  53,
+			95, 225,  56,  72, 216, 115, 149, 164, 247,   2,   6,  10,  30,  34, 102, 170,
+			229,  52,  92, 228,  55,  89, 235,  38, 106, 190, 217, 112, 144, 171, 230,  49,
+			83, 245,   4,  12,  20,  60,  68, 204,  79, 209, 104, 184, 211, 110, 178, 205,
+			76, 212, 103, 169, 224,  59,  77, 215,  98, 166, 241,   8,  24,  40, 120, 136,
+			131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206,  73, 219, 118, 154,
+			181, 196,  87, 249,  16,  48,  80, 240,  11,  29,  39, 105, 187, 214,  97, 163,
+			254,  25,  43, 125, 135, 146, 173, 236,  47, 113, 147, 174, 233,  32,  96, 160,
+			251,  22,  58,  78, 210, 109, 183, 194,  93, 231,  50,  86, 250,  21,  63,  65,
+			195,  94, 226,  61,  71, 201,  64, 192,  91, 237,  44, 116, 156, 191, 218, 117,
+			159, 186, 213, 100, 172, 239,  42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
+			155, 182, 193,  88, 232,  35, 101, 175, 234,  37, 111, 177, 200,  67, 197,  84,
+			252,  31,  33,  99, 165, 244,   7,   9,  27,  45, 119, 153, 176, 203,  70, 202,
+			69, 207,  74, 222, 121, 139, 134, 145, 168, 227,  62,  66, 198,  81, 243,  14,
+			18,  54,  90, 238,  41, 123, 141, 140, 143, 138, 133, 148, 167, 242,  13,  23,
+			57,  75, 221, 124, 132, 151, 162, 253,  28,  36, 108, 180, 199,  82, 246,   1,
+			3,   5,  15,  17,  51,  85, 255,  26,  46, 114, 150, 161, 248,  19,  53,
+			95, 225,  56,  72, 216, 115, 149, 164, 247,   2,   6,  10,  30,  34, 102, 170,
+			229,  52,  92, 228,  55,  89, 235,  38, 106, 190, 217, 112, 144, 171, 230,  49,
+			83, 245,   4,  12,  20,  60,  68, 204,  79, 209, 104, 184, 211, 110, 178, 205,
+			76, 212, 103, 169, 224,  59,  77, 215,  98, 166, 241,   8,  24,  40, 120, 136,
+			131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206,  73, 219, 118, 154,
+			181, 196,  87, 249,  16,  48,  80, 240,  11,  29,  39, 105, 187, 214,  97, 163,
+			254,  25,  43, 125, 135, 146, 173, 236,  47, 113, 147, 174, 233,  32,  96, 160,
+			251,  22,  58,  78, 210, 109, 183, 194,  93, 231,  50,  86, 250,  21,  63,  65,
+			195,  94, 226,  61,  71, 201,  64, 192,  91, 237,  44, 116, 156, 191, 218, 117,
+			159, 186, 213, 100, 172, 239,  42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
+			155, 182, 193,  88, 232,  35, 101, 175, 234,  37, 111, 177, 200,  67, 197,  84,
+			252,  31,  33,  99, 165, 244,   7,   9,  27,  45, 119, 153, 176, 203,  70, 202,
+			69, 207,  74, 222, 121, 139, 134, 145, 168, 227,  62,  66, 198,  81, 243,  14,
+			18,  54,  90, 238,  41, 123, 141, 140, 143, 138, 133, 148, 167, 242,  13,  23,
+			57,  75, 221, 124, 132, 151, 162, 253,  28,  36, 108, 180, 199,  82, 246,   1,
+		};
+
+		private static readonly byte[] S =
+		{
+			99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 118,
+			202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
+			183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 216,  49,  21,
+			4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 235,  39, 178, 117,
+			9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 179,  41, 227,  47, 132,
+			83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 190,  57,  74,  76,  88, 207,
+			208, 239, 170, 251,  67,  77,  51, 133,  69, 249,   2, 127,  80,  60, 159, 168,
+			81, 163,  64, 143, 146, 157,  56, 245, 188, 182, 218,  33,  16, 255, 243, 210,
+			205,  12,  19, 236,  95, 151,  68,  23, 196, 167, 126,  61, 100,  93,  25, 115,
+			96, 129,  79, 220,  34,  42, 144, 136,  70, 238, 184,  20, 222,  94,  11, 219,
+			224,  50,  58,  10,  73,   6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121,
+			231, 200,  55, 109, 141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8,
+			186, 120,  37,  46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138,
+			112,  62, 181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158,
+			225, 248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
+			140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  22,
+		};
+
+		private static readonly byte[] Si =
+		{
+			82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 251,
+			124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 233, 203,
+			84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 250, 195,  78,
+			8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 109, 139, 209,  37,
+			114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 204,  93, 101, 182, 146,
+			108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  70,  87, 167, 141, 157, 132,
+			144, 216, 171,   0, 140, 188, 211,  10, 247, 228,  88,   5, 184, 179,  69,   6,
+			208,  44,  30, 143, 202,  63,  15,   2, 193, 175, 189,   3,   1,  19, 138, 107,
+			58, 145,  17,  65,  79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115,
+			150, 172, 116,  34, 231, 173,  53, 133, 226, 249,  55, 232,  28, 117, 223, 110,
+			71, 241,  26, 113,  29,  41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27,
+			252,  86,  62,  75, 198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,
+			31, 221, 168,  51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,
+			96,  81, 127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239,
+			160, 224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97,
+			23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12, 125,
+		};
+
+		private static readonly byte[] 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
+		};
+
+		static readonly byte[][] shifts0 = new byte [][]
+		{
+			new byte[]{ 0, 8, 16, 24 },
+			new byte[]{ 0, 8, 16, 24 },
+			new byte[]{ 0, 8, 16, 24 },
+			new byte[]{ 0, 8, 16, 32 },
+			new byte[]{ 0, 8, 24, 32 }
+		};
+
+		static readonly byte[][] shifts1 =
+		{
+			new byte[]{ 0, 24, 16, 8 },
+			new byte[]{ 0, 32, 24, 16 },
+			new byte[]{ 0, 40, 32, 24 },
+			new byte[]{ 0, 48, 40, 24 },
+			new byte[]{ 0, 56, 40, 32 }
+		};
+
+		/**
+		* multiply two elements of GF(2^m)
+		* needed for MixColumn and InvMixColumn
+		*/
+		private byte Mul0x2(
+			int b)
+		{
+			if (b != 0)
+			{
+				return Alogtable[25 + (Logtable[b] & 0xff)];
+			}
+			else
+			{
+				return 0;
+			}
+		}
+
+		private byte Mul0x3(
+			int b)
+		{
+			if (b != 0)
+			{
+				return Alogtable[1 + (Logtable[b] & 0xff)];
+			}
+			else
+			{
+				return 0;
+			}
+		}
+
+		private byte Mul0x9(
+			int b)
+		{
+			if (b >= 0)
+			{
+				return Alogtable[199 + b];
+			}
+			else
+			{
+				return 0;
+			}
+		}
+
+		private byte Mul0xb(
+			int b)
+		{
+			if (b >= 0)
+			{
+				return Alogtable[104 + b];
+			}
+			else
+			{
+				return 0;
+			}
+		}
+
+		private byte Mul0xd(
+			int b)
+		{
+			if (b >= 0)
+			{
+				return Alogtable[238 + b];
+			}
+			else
+			{
+				return 0;
+			}
+		}
+
+		private byte Mul0xe(
+			int b)
+		{
+			if (b >= 0)
+			{
+				return Alogtable[223 + b];
+			}
+			else
+			{
+				return 0;
+			}
+		}
+
+		/**
+		* xor corresponding text input and round key input bytes
+		*/
+		private void KeyAddition(
+			long[] rk)
+		{
+			A0 ^= rk[0];
+			A1 ^= rk[1];
+			A2 ^= rk[2];
+			A3 ^= rk[3];
+		}
+
+		private long Shift(
+			long	r,
+			int	shift)
+		{
+			//return (((long)((ulong) r >> shift) | (r << (BC - shift)))) & BC_MASK;
+
+			ulong temp = (ulong) r >> shift;
+
+			// NB: This corrects for Mono Bug #79087 (fixed in 1.1.17)
+			if (shift > 31)
+			{
+				temp &= 0xFFFFFFFFUL;
+			}
+
+			return ((long) temp | (r << (BC - shift))) & BC_MASK;
+		}
+
+		/**
+		* Row 0 remains unchanged
+		* The other three rows are shifted a variable amount
+		*/
+		private void ShiftRow(
+			byte[]      shiftsSC)
+		{
+			A1 = Shift(A1, shiftsSC[1]);
+			A2 = Shift(A2, shiftsSC[2]);
+			A3 = Shift(A3, shiftsSC[3]);
+		}
+
+		private long ApplyS(
+			long    r,
+			byte[]  box)
+		{
+			long    res = 0;
+
+			for (int j = 0; j < BC; j += 8)
+			{
+				res |= (long)(box[(int)((r >> j) & 0xff)] & 0xff) << j;
+			}
+
+			return res;
+		}
+
+		/**
+		* Replace every byte of the input by the byte at that place
+		* in the nonlinear S-box
+		*/
+		private void Substitution(
+			byte[]      box)
+		{
+			A0 = ApplyS(A0, box);
+			A1 = ApplyS(A1, box);
+			A2 = ApplyS(A2, box);
+			A3 = ApplyS(A3, box);
+		}
+
+		/**
+		* Mix the bytes of every column in a linear way
+		*/
+		private void MixColumn()
+		{
+			long r0, r1, r2, r3;
+
+			r0 = r1 = r2 = r3 = 0;
+
+			for (int j = 0; j < BC; j += 8)
+			{
+				int a0 = (int)((A0 >> j) & 0xff);
+				int a1 = (int)((A1 >> j) & 0xff);
+				int a2 = (int)((A2 >> j) & 0xff);
+				int a3 = (int)((A3 >> j) & 0xff);
+
+				r0 |= (long)((Mul0x2(a0) ^ Mul0x3(a1) ^ a2 ^ a3) & 0xff) << j;
+
+				r1 |= (long)((Mul0x2(a1) ^ Mul0x3(a2) ^ a3 ^ a0) & 0xff) << j;
+
+				r2 |= (long)((Mul0x2(a2) ^ Mul0x3(a3) ^ a0 ^ a1) & 0xff) << j;
+
+				r3 |= (long)((Mul0x2(a3) ^ Mul0x3(a0) ^ a1 ^ a2) & 0xff) << j;
+			}
+
+			A0 = r0;
+			A1 = r1;
+			A2 = r2;
+			A3 = r3;
+		}
+
+		/**
+		* Mix the bytes of every column in a linear way
+		* This is the opposite operation of Mixcolumn
+		*/
+		private void InvMixColumn()
+		{
+			long r0, r1, r2, r3;
+
+			r0 = r1 = r2 = r3 = 0;
+			for (int j = 0; j < BC; j += 8)
+			{
+				int a0 = (int)((A0 >> j) & 0xff);
+				int a1 = (int)((A1 >> j) & 0xff);
+				int a2 = (int)((A2 >> j) & 0xff);
+				int a3 = (int)((A3 >> j) & 0xff);
+
+				//
+				// pre-lookup the log table
+				//
+				a0 = (a0 != 0) ? (Logtable[a0 & 0xff] & 0xff) : -1;
+				a1 = (a1 != 0) ? (Logtable[a1 & 0xff] & 0xff) : -1;
+				a2 = (a2 != 0) ? (Logtable[a2 & 0xff] & 0xff) : -1;
+				a3 = (a3 != 0) ? (Logtable[a3 & 0xff] & 0xff) : -1;
+
+				r0 |= (long)((Mul0xe(a0) ^ Mul0xb(a1) ^ Mul0xd(a2) ^ Mul0x9(a3)) & 0xff) << j;
+
+				r1 |= (long)((Mul0xe(a1) ^ Mul0xb(a2) ^ Mul0xd(a3) ^ Mul0x9(a0)) & 0xff) << j;
+
+				r2 |= (long)((Mul0xe(a2) ^ Mul0xb(a3) ^ Mul0xd(a0) ^ Mul0x9(a1)) & 0xff) << j;
+
+				r3 |= (long)((Mul0xe(a3) ^ Mul0xb(a0) ^ Mul0xd(a1) ^ Mul0x9(a2)) & 0xff) << j;
+			}
+
+			A0 = r0;
+			A1 = r1;
+			A2 = r2;
+			A3 = r3;
+		}
+
+		/**
+		* Calculate the necessary round keys
+		* The number of calculations depends on keyBits and blockBits
+		*/
+		private long[][] GenerateWorkingKey(
+			byte[]      key)
+		{
+			int         KC;
+			int         t, rconpointer = 0;
+			int         keyBits = key.Length * 8;
+			byte[,]    tk = new byte[4,MAXKC];
+			//long[,]    W = new long[MAXROUNDS+1,4];
+			long[][]    W = new long[MAXROUNDS+1][];
+
+			for (int i = 0; i < MAXROUNDS+1; i++) W[i] = new long[4];
+
+			switch (keyBits)
+			{
+				case 128:
+					KC = 4;
+					break;
+				case 160:
+					KC = 5;
+					break;
+				case 192:
+					KC = 6;
+					break;
+				case 224:
+					KC = 7;
+					break;
+				case 256:
+					KC = 8;
+					break;
+				default :
+					throw new ArgumentException("Key length not 128/160/192/224/256 bits.");
+			}
+
+			if (keyBits >= blockBits)
+			{
+				ROUNDS = KC + 6;
+			}
+			else
+			{
+				ROUNDS = (BC / 8) + 6;
+			}
+
+			//
+			// copy the key into the processing area
+			//
+			int index = 0;
+
+			for (int i = 0; i < key.Length; i++)
+			{
+				tk[i % 4,i / 4] = key[index++];
+			}
+
+			t = 0;
+
+			//
+			// copy values into round key array
+			//
+			for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++)
+			{
+				for (int i = 0; i < 4; i++)
+				{
+					W[t / (BC / 8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % BC);
+				}
+			}
+
+			//
+			// while not enough round key material calculated
+			// calculate new values
+			//
+			while (t < (ROUNDS+1)*(BC/8))
+			{
+				for (int i = 0; i < 4; i++)
+				{
+					tk[i,0] ^= S[tk[(i+1)%4,KC-1] & 0xff];
+				}
+				tk[0,0] ^= (byte) rcon[rconpointer++];
+
+				if (KC <= 6)
+				{
+					for (int j = 1; j < KC; j++)
+					{
+						for (int i = 0; i < 4; i++)
+						{
+							tk[i,j] ^= tk[i,j-1];
+						}
+					}
+				}
+				else
+				{
+					for (int j = 1; j < 4; j++)
+					{
+						for (int i = 0; i < 4; i++)
+						{
+							tk[i,j] ^= tk[i,j-1];
+						}
+					}
+					for (int i = 0; i < 4; i++)
+					{
+						tk[i,4] ^= S[tk[i,3] & 0xff];
+					}
+					for (int j = 5; j < KC; j++)
+					{
+						for (int i = 0; i < 4; i++)
+						{
+							tk[i,j] ^= tk[i,j-1];
+						}
+					}
+				}
+
+				//
+				// copy values into round key array
+				//
+				for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++)
+				{
+					for (int i = 0; i < 4; i++)
+					{
+						W[t / (BC/8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % (BC));
+					}
+				}
+			}
+			return W;
+		}
+
+		private int         BC;
+		private long        BC_MASK;
+		private int         ROUNDS;
+		private int         blockBits;
+		private long[][]    workingKey;
+		private long        A0, A1, A2, A3;
+		private bool     forEncryption;
+		private byte[]      shifts0SC;
+		private byte[]      shifts1SC;
+
+		/**
+		* default constructor - 128 bit block size.
+		*/
+		public RijndaelEngine() : this(128) {}
+
+		/**
+		* basic constructor - set the cipher up for a given blocksize
+		*
+		* @param blocksize the blocksize in bits, must be 128, 192, or 256.
+		*/
+		public RijndaelEngine(
+			int blockBits)
+		{
+			switch (blockBits)
+			{
+				case 128:
+					BC = 32;
+					BC_MASK = 0xffffffffL;
+					shifts0SC = shifts0[0];
+					shifts1SC = shifts1[0];
+					break;
+				case 160:
+					BC = 40;
+					BC_MASK = 0xffffffffffL;
+					shifts0SC = shifts0[1];
+					shifts1SC = shifts1[1];
+					break;
+				case 192:
+					BC = 48;
+					BC_MASK = 0xffffffffffffL;
+					shifts0SC = shifts0[2];
+					shifts1SC = shifts1[2];
+					break;
+				case 224:
+					BC = 56;
+					BC_MASK = 0xffffffffffffffL;
+					shifts0SC = shifts0[3];
+					shifts1SC = shifts1[3];
+					break;
+				case 256:
+					BC = 64;
+					BC_MASK = unchecked( (long)0xffffffffffffffffL);
+					shifts0SC = shifts0[4];
+					shifts1SC = shifts1[4];
+					break;
+				default:
+					throw new ArgumentException("unknown blocksize to Rijndael");
+			}
+
+			this.blockBits = blockBits;
+		}
+
+		/**
+		* initialise a Rijndael cipher.
+		*
+		* @param forEncryption whether or not we are for encryption.
+		* @param parameters the parameters required to set up the cipher.
+		* @exception ArgumentException if the parameters argument is
+		* inappropriate.
+		*/
+		public void Init(
+			bool           forEncryption,
+			ICipherParameters  parameters)
+		{
+			if (typeof(KeyParameter).IsInstanceOfType(parameters))
+			{
+				workingKey = GenerateWorkingKey(((KeyParameter)parameters).GetKey());
+				this.forEncryption = forEncryption;
+				return;
+			}
+
+			throw new ArgumentException("invalid parameter passed to Rijndael init - " + parameters.GetType().ToString());
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Rijndael"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return BC / 2;
+		}
+
+		public int ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			if (workingKey == null)
+			{
+				throw new InvalidOperationException("Rijndael engine not initialised");
+			}
+
+			if ((inOff + (BC / 2)) > input.Length)
+			{
+				throw new DataLengthException("input buffer too short");
+			}
+
+			if ((outOff + (BC / 2)) > output.Length)
+			{
+				throw new DataLengthException("output buffer too short");
+			}
+
+			UnPackBlock(input, inOff);
+
+			if (forEncryption)
+			{
+				EncryptBlock(workingKey);
+			}
+			else
+			{
+				DecryptBlock(workingKey);
+			}
+
+			PackBlock(output, outOff);
+
+			return BC / 2;
+		}
+
+		public void Reset()
+		{
+		}
+
+		private  void UnPackBlock(
+			byte[]      bytes,
+			int         off)
+		{
+			int     index = off;
+
+			A0 = (long)(bytes[index++] & 0xff);
+			A1 = (long)(bytes[index++] & 0xff);
+			A2 = (long)(bytes[index++] & 0xff);
+			A3 = (long)(bytes[index++] & 0xff);
+
+			for (int j = 8; j != BC; j += 8)
+			{
+				A0 |= (long)(bytes[index++] & 0xff) << j;
+				A1 |= (long)(bytes[index++] & 0xff) << j;
+				A2 |= (long)(bytes[index++] & 0xff) << j;
+				A3 |= (long)(bytes[index++] & 0xff) << j;
+			}
+		}
+
+		private  void PackBlock(
+			byte[]      bytes,
+			int         off)
+		{
+			int     index = off;
+
+			for (int j = 0; j != BC; j += 8)
+			{
+				bytes[index++] = (byte)(A0 >> j);
+				bytes[index++] = (byte)(A1 >> j);
+				bytes[index++] = (byte)(A2 >> j);
+				bytes[index++] = (byte)(A3 >> j);
+			}
+		}
+
+		private  void EncryptBlock(
+			long[][] rk)
+		{
+			int r;
+
+			//
+			// begin with a key addition
+			//
+			KeyAddition(rk[0]);
+
+			//
+			// ROUNDS-1 ordinary rounds
+			//
+			for (r = 1; r < ROUNDS; r++)
+			{
+				Substitution(S);
+				ShiftRow(shifts0SC);
+				MixColumn();
+				KeyAddition(rk[r]);
+			}
+
+			//
+			// Last round is special: there is no MixColumn
+			//
+			Substitution(S);
+			ShiftRow(shifts0SC);
+			KeyAddition(rk[ROUNDS]);
+		}
+
+		private void DecryptBlock(
+			long[][] rk)
+		{
+			int r;
+
+			// To decrypt: apply the inverse operations of the encrypt routine,
+			//             in opposite order
+			//
+			// (KeyAddition is an involution: it 's equal to its inverse)
+			// (the inverse of Substitution with table S is Substitution with the inverse table of S)
+			// (the inverse of Shiftrow is Shiftrow over a suitable distance)
+			//
+
+			// First the special round:
+			//   without InvMixColumn
+			//   with extra KeyAddition
+			//
+			KeyAddition(rk[ROUNDS]);
+			Substitution(Si);
+			ShiftRow(shifts1SC);
+
+			//
+			// ROUNDS-1 ordinary rounds
+			//
+			for (r = ROUNDS-1; r > 0; r--)
+			{
+				KeyAddition(rk[r]);
+				InvMixColumn();
+				Substitution(Si);
+				ShiftRow(shifts1SC);
+			}
+
+			//
+			// End with the extra key addition
+			//
+			KeyAddition(rk[0]);
+		}
+	}
+
+}
diff --git a/crypto/src/crypto/engines/RsaEngine.cs b/crypto/src/crypto/engines/RsaEngine.cs
new file mode 100644
index 000000000..7e6dfb163
--- /dev/null
+++ b/crypto/src/crypto/engines/RsaEngine.cs
@@ -0,0 +1,78 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * this does your basic RSA algorithm.
+    */
+    public class RsaEngine
+		: IAsymmetricBlockCipher
+    {
+		private RsaCoreEngine core;
+
+        public string AlgorithmName
+        {
+            get { return "RSA"; }
+        }
+
+		/**
+        * initialise the RSA engine.
+        *
+        * @param forEncryption true if we are encrypting, false otherwise.
+        * @param param the necessary RSA key parameters.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+			if (core == null)
+				core = new RsaCoreEngine();
+
+			core.Init(forEncryption, parameters);
+		}
+
+		/**
+        * 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 inBuf 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[]	inBuf,
+            int		inOff,
+            int		inLen)
+        {
+			if (core == null)
+				throw new InvalidOperationException("RSA engine not initialised");
+
+			return core.ConvertOutput(core.ProcessBlock(core.ConvertInput(inBuf, inOff, inLen)));
+        }
+    }
+}
diff --git a/crypto/src/crypto/engines/SEEDEngine.cs b/crypto/src/crypto/engines/SEEDEngine.cs
new file mode 100644
index 000000000..efea0f1fe
--- /dev/null
+++ b/crypto/src/crypto/engines/SEEDEngine.cs
@@ -0,0 +1,361 @@
+using System;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* Implementation of the SEED algorithm as described in RFC 4009
+	*/
+	public class SeedEngine
+		: IBlockCipher
+	{
+		private const int BlockSize = 16;
+
+		private static readonly uint[] SS0 =
+		{
+			0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
+			0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
+			0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
+			0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec,
+			0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074,
+			0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
+			0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8,
+			0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8,
+			0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
+			0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4,
+			0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008,
+			0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
+			0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8,
+			0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208,
+			0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
+			0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264,
+			0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0,
+			0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
+			0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114, 0x22022220, 0x38083038,
+			0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394,
+			0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
+			0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4,
+			0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8,
+			0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
+			0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040,
+			0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154,
+			0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
+			0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8,
+			0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0,
+			0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
+			0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128, 0x07070304, 0x33033330,
+			0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298
+		};
+
+		private static readonly uint[] SS1 =
+		{
+			0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0,
+			0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53,
+			0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
+			0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43,
+			0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0,
+			0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
+			0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3,
+			0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272,
+			0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
+			0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430,
+			0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0,
+			0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
+			0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1,
+			0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171,
+			0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
+			0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0,
+			0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3,
+			0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
+			0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62,
+			0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0,
+			0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
+			0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901,
+			0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501,
+			0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
+			0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971,
+			0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53,
+			0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
+			0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1,
+			0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70,
+			0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393,
+			0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783,
+			0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3
+		};
+
+		private static readonly uint[] SS2 =
+		{
+
+			0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505,
+			0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343,
+			0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
+			0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece,
+			0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444,
+			0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
+			0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9,
+			0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9,
+			0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
+			0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5,
+			0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808,
+			0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
+			0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b,
+			0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a,
+			0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
+			0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101, 0x63682b4b, 0x62642646,
+			0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0,
+			0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
+			0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505, 0x22202202, 0x30383808,
+			0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787,
+			0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
+			0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4,
+			0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888,
+			0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
+			0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040,
+			0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545,
+			0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
+			0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca,
+			0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282,
+			0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
+			0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909, 0x03040707, 0x33303303,
+			0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a
+		};
+
+		private static readonly uint[] SS3 =
+		{
+
+			0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838,
+			0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b,
+			0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
+			0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b,
+			0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434,
+			0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
+			0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f,
+			0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032,
+			0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
+			0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434,
+			0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838,
+			0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
+			0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031,
+			0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031,
+			0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
+			0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010,
+			0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f,
+			0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
+			0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e,
+			0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c,
+			0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
+			0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809,
+			0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405,
+			0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
+			0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839,
+			0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f,
+			0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
+			0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d,
+			0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c,
+			0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013,
+			0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407,
+			0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437
+		};
+
+		private static readonly uint[] KC =
+		{
+			0x9e3779b9, 0x3c6ef373, 0x78dde6e6, 0xf1bbcdcc,
+			0xe3779b99, 0xc6ef3733, 0x8dde6e67, 0x1bbcdccf,
+			0x3779b99e, 0x6ef3733c, 0xdde6e678, 0xbbcdccf1,
+			0x779b99e3, 0xef3733c6, 0xde6e678d, 0xbcdccf1b
+		};
+
+		private int[] wKey;
+		private bool forEncryption;
+
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			this.forEncryption = forEncryption;
+			wKey = createWorkingKey(((KeyParameter)parameters).GetKey());
+		}
+
+		public string AlgorithmName
+		{
+			get { return "SEED"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return BlockSize;
+		}
+
+		public int ProcessBlock(
+			byte[]	inBuf,
+			int		inOff,
+			byte[]	outBuf,
+			int		outOff)
+		{
+			if (wKey == null)
+				throw new InvalidOperationException("SEED engine not initialised");
+			if (inOff + BlockSize > inBuf.Length)
+				throw new DataLengthException("input buffer too short");
+			if (outOff + BlockSize > outBuf.Length)
+				throw new DataLengthException("output buffer too short");
+
+			long l = bytesToLong(inBuf, inOff + 0);
+			long r = bytesToLong(inBuf, inOff + 8);
+
+			if (forEncryption)
+			{
+				for (int i = 0; i < 16; i++)
+				{
+					long nl = r;
+
+					r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
+					l = nl;
+				}
+			}
+			else
+			{
+				for (int i = 15; i >= 0; i--)
+				{
+					long nl = r;
+
+					r = l ^ F(wKey[2 * i], wKey[(2 * i) + 1], r);
+					l = nl;
+				}
+			}
+
+			longToBytes(outBuf, outOff + 0, r);
+			longToBytes(outBuf, outOff + 8, l);
+
+			return BlockSize;
+		}
+
+		public void Reset()
+		{
+		}
+
+		private int[] createWorkingKey(
+			byte[] inKey)
+		{
+			int[] key = new int[32];
+			long lower = bytesToLong(inKey, 0);
+			long upper = bytesToLong(inKey, 8);
+
+			int key0 = extractW0(lower);
+			int key1 = extractW1(lower);
+			int key2 = extractW0(upper);
+			int key3 = extractW1(upper);
+
+			for (int i = 0; i < 16; i++)
+			{
+				key[2 * i] = G(key0 + key2 - (int)KC[i]);
+				key[2 * i + 1] = G(key1 - key3 + (int)KC[i]);
+
+				if (i % 2 == 0)
+				{
+					lower = rotateRight8(lower);
+					key0 = extractW0(lower);
+					key1 = extractW1(lower);
+				}
+				else
+				{
+					upper = rotateLeft8(upper);
+					key2 = extractW0(upper);
+					key3 = extractW1(upper);
+				}
+			}
+
+			return key;
+		}
+
+		private int extractW1(
+			long lVal)
+		{
+			return (int)lVal;
+		}
+
+		private int extractW0(
+			long lVal)
+		{
+			return (int)(lVal >> 32);
+		}
+
+		private long rotateLeft8(
+			long x)
+		{
+			return (x << 8) | ((long)((ulong) x >> 56));
+		}
+
+		private long rotateRight8(
+			long x)
+		{
+			return ((long)((ulong) x >> 8)) | (x << 56);
+		}
+
+		private long bytesToLong(
+			byte[]	src,
+			int		srcOff)
+		{
+			long word = 0;
+
+			for (int i = 0; i <= 7; i++)
+			{
+				word = (word << 8) + (src[i + srcOff] & 0xff);
+			}
+
+			return word;
+		}
+
+		private void longToBytes(
+			byte[]	dest,
+			int		destOff,
+			long	value)
+		{
+			for (int i = 0; i < 8; i++)
+			{
+				dest[i + destOff] = (byte)(value >> ((7 - i) * 8));
+			}
+		}
+
+		private int G(
+			int x)
+		{
+			return (int)(SS0[x & 0xff] ^ SS1[(x >> 8) & 0xff] ^ SS2[(x >> 16) & 0xff] ^ SS3[(x >> 24) & 0xff]);
+		}
+
+		private long F(
+			int		ki0,
+			int		ki1,
+			long	r)
+		{
+			int r0 = (int)(r >> 32);
+			int r1 = (int)r;
+			int rd1 = phaseCalc2(r0, ki0, r1, ki1);
+			int rd0 = rd1 + phaseCalc1(r0, ki0, r1, ki1);
+
+			return ((long)rd0 << 32) | (rd1 & 0xffffffffL);
+		}
+
+		private int phaseCalc1(
+			int	r0,
+			int	ki0,
+			int	r1,
+			int	ki1)
+		{
+			return G(G((r0 ^ ki0) ^ (r1 ^ ki1)) + (r0 ^ ki0));
+		}
+
+		private int phaseCalc2(
+			int	r0,
+			int	ki0,
+			int	r1,
+			int	ki1)
+		{
+			return G(phaseCalc1(r0, ki0, r1, ki1) + G((r0 ^ ki0) ^ (r1 ^ ki1)));
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/SEEDWrapEngine.cs b/crypto/src/crypto/engines/SEEDWrapEngine.cs
new file mode 100644
index 000000000..6b71f940b
--- /dev/null
+++ b/crypto/src/crypto/engines/SEEDWrapEngine.cs
@@ -0,0 +1,16 @@
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <remarks>
+	/// An implementation of the SEED key wrapper based on RFC 4010/RFC 3394.
+	/// <p/>
+	/// For further details see: <a href="http://www.ietf.org/rfc/rfc4010.txt">http://www.ietf.org/rfc/rfc4010.txt</a>.
+	/// </remarks>
+	public class SeedWrapEngine
+		: Rfc3394WrapEngine
+	{
+		public SeedWrapEngine()
+			: base(new SeedEngine())
+		{
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 7d68deab1..81884d603 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -7,44 +7,60 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	/**
-	 * Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
-	 */
+	/// <summary>
+	/// Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
+	/// </summary>
 	public class Salsa20Engine
 		: IStreamCipher
 	{
+		public static readonly int DEFAULT_ROUNDS = 20;
+
 		/** Constants */
 		private const int StateSize = 16; // 16, 32 bit ints = 64 bytes
 
-		private readonly static byte[]
+		protected readonly static byte[]
 			sigma = Strings.ToAsciiByteArray("expand 32-byte k"),
 			tau = Strings.ToAsciiByteArray("expand 16-byte k");
 
+		protected int rounds;
+
 		/*
 		 * variables to hold the state of the engine
 		 * during encryption and decryption
 		 */
-		private int		index = 0;
-		private uint[]  engineState = new uint[StateSize]; // state
-		private uint[]  x = new uint[StateSize]; // internal buffer
-		private byte[]  keyStream = new byte[StateSize * 4], // expanded state, 64 bytes
-						workingKey  = null,
-						workingIV   = null;
-		private bool	initialised = false;
+		private int		 index = 0;
+		internal uint[] engineState = new uint[StateSize]; // state
+		internal uint[] x = new uint[StateSize]; // internal buffer
+		private byte[]	 keyStream = new byte[StateSize * 4]; // expanded state, 64 bytes
+		private bool	 initialised = false;
 
 		/*
 		 * internal counter
 		 */
 		private uint cW0, cW1, cW2;
 
-		/**
-		 * initialise a Salsa20 cipher.
-		 *
-		 * @param forEncryption whether or not we are for encryption.
-		 * @param params the parameters required to set up the cipher.
-		 * @exception ArgumentException if the params argument is
-		 * inappropriate.
-		 */
+		/// <summary>
+		/// Creates a 20 round Salsa20 engine.
+		/// </summary>
+		public Salsa20Engine()
+			: this(DEFAULT_ROUNDS)
+		{
+		}
+
+		/// <summary>
+		/// Creates a Salsa20 engine with a specific number of rounds.
+		/// </summary>
+		/// <param name="rounds">the number of rounds (must be an even number).</param>
+		public Salsa20Engine(int rounds)
+		{
+			if (rounds <= 0 || (rounds & 1) != 0)
+			{
+				throw new ArgumentException("'rounds' must be a positive, even number");
+			}
+
+			this.rounds = rounds;
+		}
+
 		public void Init(
 			bool				forEncryption, 
 			ICipherParameters	parameters)
@@ -58,27 +74,38 @@ namespace Org.BouncyCastle.Crypto.Engines
 			ParametersWithIV ivParams = parameters as ParametersWithIV;
 
 			if (ivParams == null)
-				throw new ArgumentException("Salsa20 Init requires an IV", "parameters");
+				throw new ArgumentException(AlgorithmName + " Init requires an IV", "parameters");
 
 			byte[] iv = ivParams.GetIV();
 
-			if (iv == null || iv.Length != 8)
-				throw new ArgumentException("Salsa20 requires exactly 8 bytes of IV");
+			if (iv == null || iv.Length != NonceSize)
+				throw new ArgumentException(AlgorithmName + " requires exactly " + NonceSize + " bytes of IV");
 
 			KeyParameter key = ivParams.Parameters as KeyParameter;
 
 			if (key == null)
-				throw new ArgumentException("Salsa20 Init requires a key", "parameters");
+				throw new ArgumentException(AlgorithmName + " Init requires a key", "parameters");
 
-			workingKey = key.GetKey();
-			workingIV = iv;
+			SetKey(key.GetKey(), iv);
+			Reset();
+			initialised = true;
+		}
 
-			SetKey(workingKey, workingIV);
+		protected virtual int NonceSize
+		{
+			get { return 8; }
 		}
 
-		public string AlgorithmName
+		public virtual string AlgorithmName
 		{
-			get { return "Salsa20"; }
+			get { 
+				string name = "Salsa20";
+				if (rounds != DEFAULT_ROUNDS)
+				{
+					name += "/" + rounds;
+				}
+				return name;
+			}
 		}
 
 		public byte ReturnByte(
@@ -92,11 +119,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			if (index == 0)
 			{
 				GenerateKeyStream(keyStream);
-
-				if (++engineState[8] == 0)
-				{
-					++engineState[9];
-				}
+				AdvanceCounter();
 			}
 
 			byte output = (byte)(keyStream[index] ^ input);
@@ -105,6 +128,14 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return output;
 		}
 
+		protected virtual void AdvanceCounter()
+		{
+			if (++engineState[8] == 0)
+			{
+				++engineState[9];
+			}
+		}
+
 		public void ProcessBytes(
 			byte[]	inBytes, 
 			int		inOff, 
@@ -137,11 +168,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 				if (index == 0)
 				{
 					GenerateKeyStream(keyStream);
-
-					if (++engineState[8] == 0)
-					{
-						++engineState[9];
-					}
+					AdvanceCounter();
 				}
 				outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]);
 				index = (index + 1) & 63;
@@ -150,28 +177,32 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 		public void Reset()
 		{
-			SetKey(workingKey, workingIV);
+			index = 0;
+			ResetLimitCounter();
+			ResetCounter();
 		}
 
-		// Private implementation
+		protected virtual void ResetCounter()
+		{
+			engineState[8] = engineState[9] = 0;
+		}
 
-		private void SetKey(byte[] keyBytes, byte[] ivBytes)
+		protected virtual void SetKey(byte[] keyBytes, byte[] ivBytes)
 		{
-			workingKey = keyBytes;
-			workingIV  = ivBytes;
+			if ((keyBytes.Length != 16) && (keyBytes.Length != 32)) {
+				throw new ArgumentException(AlgorithmName + " requires 128 bit or 256 bit key");
+			}
 
-			index = 0;
-			ResetCounter();
 			int offset = 0;
 			byte[] constants;
 
 			// Key
-			engineState[1] = Pack.LE_To_UInt32(workingKey, 0);
-			engineState[2] = Pack.LE_To_UInt32(workingKey, 4);
-			engineState[3] = Pack.LE_To_UInt32(workingKey, 8);
-			engineState[4] = Pack.LE_To_UInt32(workingKey, 12);
+			engineState[1] = Pack.LE_To_UInt32(keyBytes, 0);
+			engineState[2] = Pack.LE_To_UInt32(keyBytes, 4);
+			engineState[3] = Pack.LE_To_UInt32(keyBytes, 8);
+			engineState[4] = Pack.LE_To_UInt32(keyBytes, 12);
 
-			if (workingKey.Length == 32)
+			if (keyBytes.Length == 32)
 			{
 				constants = sigma;
 				offset = 16;
@@ -181,83 +212,125 @@ namespace Org.BouncyCastle.Crypto.Engines
 				constants = tau;
 			}
 
-			engineState[11] = Pack.LE_To_UInt32(workingKey, offset);
-			engineState[12] = Pack.LE_To_UInt32(workingKey, offset + 4);
-			engineState[13] = Pack.LE_To_UInt32(workingKey, offset + 8);
-			engineState[14] = Pack.LE_To_UInt32(workingKey, offset + 12);
+			engineState[11] = Pack.LE_To_UInt32(keyBytes, offset);
+			engineState[12] = Pack.LE_To_UInt32(keyBytes, offset + 4);
+			engineState[13] = Pack.LE_To_UInt32(keyBytes, offset + 8);
+			engineState[14] = Pack.LE_To_UInt32(keyBytes, offset + 12);
 			engineState[0] = Pack.LE_To_UInt32(constants, 0);
 			engineState[5] = Pack.LE_To_UInt32(constants, 4);
 			engineState[10] = Pack.LE_To_UInt32(constants, 8);
 			engineState[15] = Pack.LE_To_UInt32(constants, 12);
 
 			// IV
-			engineState[6] = Pack.LE_To_UInt32(workingIV, 0);
-			engineState[7] = Pack.LE_To_UInt32(workingIV, 4);
-			engineState[8] = engineState[9] = 0;
-
-			initialised = true;
+			engineState[6] = Pack.LE_To_UInt32(ivBytes, 0);
+			engineState[7] = Pack.LE_To_UInt32(ivBytes, 4);
+			ResetCounter();
 		}
 
-		private void GenerateKeyStream(byte[] output)
+		protected virtual void GenerateKeyStream(byte[] output)
 		{
-			SalsaCore(20, engineState, x);
+			SalsaCore(rounds, engineState, x);
 			Pack.UInt32_To_LE(x, output, 0);
 		}
 
-		internal static void SalsaCore(int rounds, uint[] state, uint[] x)
+		internal static void SalsaCore(int rounds, uint[] input, uint[] x)
 		{
-            // TODO Exception if rounds odd?
+			if (input.Length != 16) {
+				throw new ArgumentException();
+			}
+			if (x.Length != 16) {
+				throw new ArgumentException();
+			}
+			if (rounds % 2 != 0) {
+				throw new ArgumentException("Number of rounds must be even");
+			}
 
-            Array.Copy(state, 0, x, 0, state.Length);
+			uint x00 = input[ 0];
+			uint x01 = input[ 1];
+			uint x02 = input[ 2];
+			uint x03 = input[ 3];
+			uint x04 = input[ 4];
+			uint x05 = input[ 5];
+			uint x06 = input[ 6];
+			uint x07 = input[ 7];
+			uint x08 = input[ 8];
+			uint x09 = input[ 9];
+			uint x10 = input[10];
+			uint x11 = input[11];
+			uint x12 = input[12];
+			uint x13 = input[13];
+			uint x14 = input[14];
+			uint x15 = input[15];
 
 			for (int i = rounds; i > 0; i -= 2)
 			{
-				x[ 4] ^= R((x[ 0]+x[12]), 7);
-				x[ 8] ^= R((x[ 4]+x[ 0]), 9);
-				x[12] ^= R((x[ 8]+x[ 4]),13);
-				x[ 0] ^= R((x[12]+x[ 8]),18);
-				x[ 9] ^= R((x[ 5]+x[ 1]), 7);
-				x[13] ^= R((x[ 9]+x[ 5]), 9);
-				x[ 1] ^= R((x[13]+x[ 9]),13);
-				x[ 5] ^= R((x[ 1]+x[13]),18);
-				x[14] ^= R((x[10]+x[ 6]), 7);
-				x[ 2] ^= R((x[14]+x[10]), 9);
-				x[ 6] ^= R((x[ 2]+x[14]),13);
-				x[10] ^= R((x[ 6]+x[ 2]),18);
-				x[ 3] ^= R((x[15]+x[11]), 7);
-				x[ 7] ^= R((x[ 3]+x[15]), 9);
-				x[11] ^= R((x[ 7]+x[ 3]),13);
-				x[15] ^= R((x[11]+x[ 7]),18);
-				x[ 1] ^= R((x[ 0]+x[ 3]), 7);
-				x[ 2] ^= R((x[ 1]+x[ 0]), 9);
-				x[ 3] ^= R((x[ 2]+x[ 1]),13);
-				x[ 0] ^= R((x[ 3]+x[ 2]),18);
-				x[ 6] ^= R((x[ 5]+x[ 4]), 7);
-				x[ 7] ^= R((x[ 6]+x[ 5]), 9);
-				x[ 4] ^= R((x[ 7]+x[ 6]),13);
-				x[ 5] ^= R((x[ 4]+x[ 7]),18);
-				x[11] ^= R((x[10]+x[ 9]), 7);
-				x[ 8] ^= R((x[11]+x[10]), 9);
-				x[ 9] ^= R((x[ 8]+x[11]),13);
-				x[10] ^= R((x[ 9]+x[ 8]),18);
-				x[12] ^= R((x[15]+x[14]), 7);
-				x[13] ^= R((x[12]+x[15]), 9);
-				x[14] ^= R((x[13]+x[12]),13);
-				x[15] ^= R((x[14]+x[13]),18);
+				x04 ^= R((x00+x12), 7);
+				x08 ^= R((x04+x00), 9);
+				x12 ^= R((x08+x04),13);
+				x00 ^= R((x12+x08),18);
+				x09 ^= R((x05+x01), 7);
+				x13 ^= R((x09+x05), 9);
+				x01 ^= R((x13+x09),13);
+				x05 ^= R((x01+x13),18);
+				x14 ^= R((x10+x06), 7);
+				x02 ^= R((x14+x10), 9);
+				x06 ^= R((x02+x14),13);
+				x10 ^= R((x06+x02),18);
+				x03 ^= R((x15+x11), 7);
+				x07 ^= R((x03+x15), 9);
+				x11 ^= R((x07+x03),13);
+				x15 ^= R((x11+x07),18);
+
+				x01 ^= R((x00+x03), 7);
+				x02 ^= R((x01+x00), 9);
+				x03 ^= R((x02+x01),13);
+				x00 ^= R((x03+x02),18);
+				x06 ^= R((x05+x04), 7);
+				x07 ^= R((x06+x05), 9);
+				x04 ^= R((x07+x06),13);
+				x05 ^= R((x04+x07),18);
+				x11 ^= R((x10+x09), 7);
+				x08 ^= R((x11+x10), 9);
+				x09 ^= R((x08+x11),13);
+				x10 ^= R((x09+x08),18);
+				x12 ^= R((x15+x14), 7);
+				x13 ^= R((x12+x15), 9);
+				x14 ^= R((x13+x12),13);
+				x15 ^= R((x14+x13),18);
 			}
 
-			for (int i = 0; i < StateSize; ++i)
-			{
-				x[i] += state[i];
-			}
+			x[ 0] = x00 + input[ 0];
+			x[ 1] = x01 + input[ 1];
+			x[ 2] = x02 + input[ 2];
+			x[ 3] = x03 + input[ 3];
+			x[ 4] = x04 + input[ 4];
+			x[ 5] = x05 + input[ 5];
+			x[ 6] = x06 + input[ 6];
+			x[ 7] = x07 + input[ 7];
+			x[ 8] = x08 + input[ 8];
+			x[ 9] = x09 + input[ 9];
+			x[10] = x10 + input[10];
+			x[11] = x11 + input[11];
+			x[12] = x12 + input[12];
+			x[13] = x13 + input[13];
+			x[14] = x14 + input[14];
+			x[15] = x15 + input[15];
 		}
 
-		private static uint R(uint x, int y)
+		/**
+		 * Rotate left
+		 *
+		 * @param   x   value to rotate
+		 * @param   y   amount to rotate x
+		 *
+		 * @return  rotated x
+		 */
+		internal static uint R(uint x, int y)
 		{
 			return (x << y) | (x >> (32 - y));
 		}
 
-		private void ResetCounter()
+		private void ResetLimitCounter()
 		{
 			cW0 = 0;
 			cW1 = 0;
diff --git a/crypto/src/crypto/engines/SerpentEngine.cs b/crypto/src/crypto/engines/SerpentEngine.cs
new file mode 100644
index 000000000..92b25acc6
--- /dev/null
+++ b/crypto/src/crypto/engines/SerpentEngine.cs
@@ -0,0 +1,779 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * Serpent is a 128-bit 32-round block cipher with variable key lengths,
+    * including 128, 192 and 256 bit keys conjectured to be at least as
+    * secure as three-key triple-DES.
+    * <p>
+    * Serpent was designed by Ross Anderson, Eli Biham and Lars Knudsen as a
+    * candidate algorithm for the NIST AES Quest.>
+	* </p>
+    * <p>
+    * For full details see the <a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">The Serpent home page</a>
+	* </p>
+    */
+    public class SerpentEngine
+		: IBlockCipher
+    {
+        private const int    BLOCK_SIZE = 16;
+
+        static readonly int ROUNDS = 32;
+        static readonly int PHI    = unchecked((int)0x9E3779B9);       // (Sqrt(5) - 1) * 2**31
+
+        private bool        encrypting;
+        private int[]          wKey;
+
+        private int           X0, X1, X2, X3;    // registers
+
+        /**
+        * initialise a Serpent cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is KeyParameter))
+				throw new ArgumentException("invalid parameter passed to Serpent init - " + parameters.GetType().ToString());
+
+			this.encrypting = forEncryption;
+            this.wKey = MakeWorkingKey(((KeyParameter)parameters).GetKey());
+        }
+
+		public string AlgorithmName
+		{
+			get { return "Serpent"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        /**
+        * 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 InvalidOperationException if the cipher isn't initialised.
+        * @return the number of bytes processed and produced.
+        */
+        public  int ProcessBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  output,
+            int     outOff)
+        {
+            if (wKey == null)
+                throw new InvalidOperationException("Serpent not initialised");
+            if ((inOff + BLOCK_SIZE) > input.Length)
+                throw new DataLengthException("input buffer too short");
+            if ((outOff + BLOCK_SIZE) > output.Length)
+                throw new DataLengthException("output buffer too short");
+
+			if (encrypting)
+            {
+                EncryptBlock(input, inOff, output, outOff);
+            }
+            else
+            {
+                DecryptBlock(input, inOff, output, outOff);
+            }
+
+            return BLOCK_SIZE;
+        }
+
+        public void Reset()
+        {
+        }
+
+        /**
+        * Expand a user-supplied key material into a session key.
+        *
+        * @param key  The user-key bytes (multiples of 4) to use.
+        * @exception ArgumentException
+        */
+        private int[] MakeWorkingKey(
+            byte[] key)
+        {
+            //
+            // pad key to 256 bits
+            //
+            int[]   kPad = new int[16];
+            int     off = 0;
+            int     length = 0;
+
+            for (off = key.Length - 4; off > 0; off -= 4)
+            {
+                kPad[length++] = BytesToWord(key, off);
+            }
+
+            if (off == 0)
+            {
+                kPad[length++] = BytesToWord(key, 0);
+                if (length < 8)
+                {
+                    kPad[length] = 1;
+                }
+            }
+            else
+            {
+                throw new ArgumentException("key must be a multiple of 4 bytes");
+            }
+
+            //
+            // expand the padded key up to 33 x 128 bits of key material
+            //
+            int amount = (ROUNDS + 1) * 4;
+            int[] w = new int[amount];
+
+            //
+            // compute w0 to w7 from w-8 to w-1
+            //
+            for (int i = 8; i < 16; i++)
+            {
+                kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ PHI ^ (i - 8), 11);
+            }
+
+            Array.Copy(kPad, 8, w, 0, 8);
+
+            //
+            // compute w8 to w136
+            //
+            for (int i = 8; i < amount; i++)
+            {
+                w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ PHI ^ i, 11);
+            }
+
+            //
+            // create the working keys by processing w with the Sbox and IP
+            //
+            Sb3(w[0], w[1], w[2], w[3]);
+            w[0] = X0; w[1] = X1; w[2] = X2; w[3] = X3;
+            Sb2(w[4], w[5], w[6], w[7]);
+            w[4] = X0; w[5] = X1; w[6] = X2; w[7] = X3;
+            Sb1(w[8], w[9], w[10], w[11]);
+            w[8] = X0; w[9] = X1; w[10] = X2; w[11] = X3;
+            Sb0(w[12], w[13], w[14], w[15]);
+            w[12] = X0; w[13] = X1; w[14] = X2; w[15] = X3;
+            Sb7(w[16], w[17], w[18], w[19]);
+            w[16] = X0; w[17] = X1; w[18] = X2; w[19] = X3;
+            Sb6(w[20], w[21], w[22], w[23]);
+            w[20] = X0; w[21] = X1; w[22] = X2; w[23] = X3;
+            Sb5(w[24], w[25], w[26], w[27]);
+            w[24] = X0; w[25] = X1; w[26] = X2; w[27] = X3;
+            Sb4(w[28], w[29], w[30], w[31]);
+            w[28] = X0; w[29] = X1; w[30] = X2; w[31] = X3;
+            Sb3(w[32], w[33], w[34], w[35]);
+            w[32] = X0; w[33] = X1; w[34] = X2; w[35] = X3;
+            Sb2(w[36], w[37], w[38], w[39]);
+            w[36] = X0; w[37] = X1; w[38] = X2; w[39] = X3;
+            Sb1(w[40], w[41], w[42], w[43]);
+            w[40] = X0; w[41] = X1; w[42] = X2; w[43] = X3;
+            Sb0(w[44], w[45], w[46], w[47]);
+            w[44] = X0; w[45] = X1; w[46] = X2; w[47] = X3;
+            Sb7(w[48], w[49], w[50], w[51]);
+            w[48] = X0; w[49] = X1; w[50] = X2; w[51] = X3;
+            Sb6(w[52], w[53], w[54], w[55]);
+            w[52] = X0; w[53] = X1; w[54] = X2; w[55] = X3;
+            Sb5(w[56], w[57], w[58], w[59]);
+            w[56] = X0; w[57] = X1; w[58] = X2; w[59] = X3;
+            Sb4(w[60], w[61], w[62], w[63]);
+            w[60] = X0; w[61] = X1; w[62] = X2; w[63] = X3;
+            Sb3(w[64], w[65], w[66], w[67]);
+            w[64] = X0; w[65] = X1; w[66] = X2; w[67] = X3;
+            Sb2(w[68], w[69], w[70], w[71]);
+            w[68] = X0; w[69] = X1; w[70] = X2; w[71] = X3;
+            Sb1(w[72], w[73], w[74], w[75]);
+            w[72] = X0; w[73] = X1; w[74] = X2; w[75] = X3;
+            Sb0(w[76], w[77], w[78], w[79]);
+            w[76] = X0; w[77] = X1; w[78] = X2; w[79] = X3;
+            Sb7(w[80], w[81], w[82], w[83]);
+            w[80] = X0; w[81] = X1; w[82] = X2; w[83] = X3;
+            Sb6(w[84], w[85], w[86], w[87]);
+            w[84] = X0; w[85] = X1; w[86] = X2; w[87] = X3;
+            Sb5(w[88], w[89], w[90], w[91]);
+            w[88] = X0; w[89] = X1; w[90] = X2; w[91] = X3;
+            Sb4(w[92], w[93], w[94], w[95]);
+            w[92] = X0; w[93] = X1; w[94] = X2; w[95] = X3;
+            Sb3(w[96], w[97], w[98], w[99]);
+            w[96] = X0; w[97] = X1; w[98] = X2; w[99] = X3;
+            Sb2(w[100], w[101], w[102], w[103]);
+            w[100] = X0; w[101] = X1; w[102] = X2; w[103] = X3;
+            Sb1(w[104], w[105], w[106], w[107]);
+            w[104] = X0; w[105] = X1; w[106] = X2; w[107] = X3;
+            Sb0(w[108], w[109], w[110], w[111]);
+            w[108] = X0; w[109] = X1; w[110] = X2; w[111] = X3;
+            Sb7(w[112], w[113], w[114], w[115]);
+            w[112] = X0; w[113] = X1; w[114] = X2; w[115] = X3;
+            Sb6(w[116], w[117], w[118], w[119]);
+            w[116] = X0; w[117] = X1; w[118] = X2; w[119] = X3;
+            Sb5(w[120], w[121], w[122], w[123]);
+            w[120] = X0; w[121] = X1; w[122] = X2; w[123] = X3;
+            Sb4(w[124], w[125], w[126], w[127]);
+            w[124] = X0; w[125] = X1; w[126] = X2; w[127] = X3;
+            Sb3(w[128], w[129], w[130], w[131]);
+            w[128] = X0; w[129] = X1; w[130] = X2; w[131] = X3;
+
+            return w;
+        }
+
+        private int RotateLeft(
+            int     x,
+            int     bits)
+        {
+            return ((x << bits) | (int) ((uint)x >> (32 - bits)));
+        }
+
+        private int RotateRight(
+            int     x,
+            int     bits)
+        {
+            return ( (int)((uint)x >> bits) | (x << (32 - bits)));
+        }
+
+        private int BytesToWord(
+            byte[]  src,
+            int     srcOff)
+        {
+            return (((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) <<  16) |
+            ((src[srcOff + 2] & 0xff) << 8) | ((src[srcOff + 3] & 0xff)));
+        }
+
+        private void WordToBytes(
+            int     word,
+            byte[]  dst,
+            int     dstOff)
+        {
+            dst[dstOff + 3] = (byte)(word);
+            dst[dstOff + 2] = (byte)((uint)word >> 8);
+            dst[dstOff + 1] = (byte)((uint)word >> 16);
+            dst[dstOff]     = (byte)((uint)word >> 24);
+        }
+
+        /**
+        * Encrypt one block of plaintext.
+        *
+        * @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.
+        */
+        private void EncryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            X3 = BytesToWord(input, inOff);
+            X2 = BytesToWord(input, inOff + 4);
+            X1 = BytesToWord(input, inOff + 8);
+            X0 = BytesToWord(input, inOff + 12);
+
+            Sb0(wKey[0] ^ X0, wKey[1] ^ X1, wKey[2] ^ X2, wKey[3] ^ X3); LT();
+            Sb1(wKey[4] ^ X0, wKey[5] ^ X1, wKey[6] ^ X2, wKey[7] ^ X3); LT();
+            Sb2(wKey[8] ^ X0, wKey[9] ^ X1, wKey[10] ^ X2, wKey[11] ^ X3); LT();
+            Sb3(wKey[12] ^ X0, wKey[13] ^ X1, wKey[14] ^ X2, wKey[15] ^ X3); LT();
+            Sb4(wKey[16] ^ X0, wKey[17] ^ X1, wKey[18] ^ X2, wKey[19] ^ X3); LT();
+            Sb5(wKey[20] ^ X0, wKey[21] ^ X1, wKey[22] ^ X2, wKey[23] ^ X3); LT();
+            Sb6(wKey[24] ^ X0, wKey[25] ^ X1, wKey[26] ^ X2, wKey[27] ^ X3); LT();
+            Sb7(wKey[28] ^ X0, wKey[29] ^ X1, wKey[30] ^ X2, wKey[31] ^ X3); LT();
+            Sb0(wKey[32] ^ X0, wKey[33] ^ X1, wKey[34] ^ X2, wKey[35] ^ X3); LT();
+            Sb1(wKey[36] ^ X0, wKey[37] ^ X1, wKey[38] ^ X2, wKey[39] ^ X3); LT();
+            Sb2(wKey[40] ^ X0, wKey[41] ^ X1, wKey[42] ^ X2, wKey[43] ^ X3); LT();
+            Sb3(wKey[44] ^ X0, wKey[45] ^ X1, wKey[46] ^ X2, wKey[47] ^ X3); LT();
+            Sb4(wKey[48] ^ X0, wKey[49] ^ X1, wKey[50] ^ X2, wKey[51] ^ X3); LT();
+            Sb5(wKey[52] ^ X0, wKey[53] ^ X1, wKey[54] ^ X2, wKey[55] ^ X3); LT();
+            Sb6(wKey[56] ^ X0, wKey[57] ^ X1, wKey[58] ^ X2, wKey[59] ^ X3); LT();
+            Sb7(wKey[60] ^ X0, wKey[61] ^ X1, wKey[62] ^ X2, wKey[63] ^ X3); LT();
+            Sb0(wKey[64] ^ X0, wKey[65] ^ X1, wKey[66] ^ X2, wKey[67] ^ X3); LT();
+            Sb1(wKey[68] ^ X0, wKey[69] ^ X1, wKey[70] ^ X2, wKey[71] ^ X3); LT();
+            Sb2(wKey[72] ^ X0, wKey[73] ^ X1, wKey[74] ^ X2, wKey[75] ^ X3); LT();
+            Sb3(wKey[76] ^ X0, wKey[77] ^ X1, wKey[78] ^ X2, wKey[79] ^ X3); LT();
+            Sb4(wKey[80] ^ X0, wKey[81] ^ X1, wKey[82] ^ X2, wKey[83] ^ X3); LT();
+            Sb5(wKey[84] ^ X0, wKey[85] ^ X1, wKey[86] ^ X2, wKey[87] ^ X3); LT();
+            Sb6(wKey[88] ^ X0, wKey[89] ^ X1, wKey[90] ^ X2, wKey[91] ^ X3); LT();
+            Sb7(wKey[92] ^ X0, wKey[93] ^ X1, wKey[94] ^ X2, wKey[95] ^ X3); LT();
+            Sb0(wKey[96] ^ X0, wKey[97] ^ X1, wKey[98] ^ X2, wKey[99] ^ X3); LT();
+            Sb1(wKey[100] ^ X0, wKey[101] ^ X1, wKey[102] ^ X2, wKey[103] ^ X3); LT();
+            Sb2(wKey[104] ^ X0, wKey[105] ^ X1, wKey[106] ^ X2, wKey[107] ^ X3); LT();
+            Sb3(wKey[108] ^ X0, wKey[109] ^ X1, wKey[110] ^ X2, wKey[111] ^ X3); LT();
+            Sb4(wKey[112] ^ X0, wKey[113] ^ X1, wKey[114] ^ X2, wKey[115] ^ X3); LT();
+            Sb5(wKey[116] ^ X0, wKey[117] ^ X1, wKey[118] ^ X2, wKey[119] ^ X3); LT();
+            Sb6(wKey[120] ^ X0, wKey[121] ^ X1, wKey[122] ^ X2, wKey[123] ^ X3); LT();
+            Sb7(wKey[124] ^ X0, wKey[125] ^ X1, wKey[126] ^ X2, wKey[127] ^ X3);
+
+            WordToBytes(wKey[131] ^ X3, outBytes, outOff);
+            WordToBytes(wKey[130] ^ X2, outBytes, outOff + 4);
+            WordToBytes(wKey[129] ^ X1, outBytes, outOff + 8);
+            WordToBytes(wKey[128] ^ X0, outBytes, outOff + 12);
+        }
+
+        /**
+        * Decrypt one block of ciphertext.
+        *
+        * @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.
+        */
+        private void DecryptBlock(
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            X3 = wKey[131] ^ BytesToWord(input, inOff);
+            X2 = wKey[130] ^ BytesToWord(input, inOff + 4);
+            X1 = wKey[129] ^ BytesToWord(input, inOff + 8);
+            X0 = wKey[128] ^ BytesToWord(input, inOff + 12);
+
+            Ib7(X0, X1, X2, X3);
+            X0 ^= wKey[124]; X1 ^= wKey[125]; X2 ^= wKey[126]; X3 ^= wKey[127];
+            InverseLT(); Ib6(X0, X1, X2, X3);
+            X0 ^= wKey[120]; X1 ^= wKey[121]; X2 ^= wKey[122]; X3 ^= wKey[123];
+            InverseLT(); Ib5(X0, X1, X2, X3);
+            X0 ^= wKey[116]; X1 ^= wKey[117]; X2 ^= wKey[118]; X3 ^= wKey[119];
+            InverseLT(); Ib4(X0, X1, X2, X3);
+            X0 ^= wKey[112]; X1 ^= wKey[113]; X2 ^= wKey[114]; X3 ^= wKey[115];
+            InverseLT(); Ib3(X0, X1, X2, X3);
+            X0 ^= wKey[108]; X1 ^= wKey[109]; X2 ^= wKey[110]; X3 ^= wKey[111];
+            InverseLT(); Ib2(X0, X1, X2, X3);
+            X0 ^= wKey[104]; X1 ^= wKey[105]; X2 ^= wKey[106]; X3 ^= wKey[107];
+            InverseLT(); Ib1(X0, X1, X2, X3);
+            X0 ^= wKey[100]; X1 ^= wKey[101]; X2 ^= wKey[102]; X3 ^= wKey[103];
+            InverseLT(); Ib0(X0, X1, X2, X3);
+            X0 ^= wKey[96]; X1 ^= wKey[97]; X2 ^= wKey[98]; X3 ^= wKey[99];
+            InverseLT(); Ib7(X0, X1, X2, X3);
+            X0 ^= wKey[92]; X1 ^= wKey[93]; X2 ^= wKey[94]; X3 ^= wKey[95];
+            InverseLT(); Ib6(X0, X1, X2, X3);
+            X0 ^= wKey[88]; X1 ^= wKey[89]; X2 ^= wKey[90]; X3 ^= wKey[91];
+            InverseLT(); Ib5(X0, X1, X2, X3);
+            X0 ^= wKey[84]; X1 ^= wKey[85]; X2 ^= wKey[86]; X3 ^= wKey[87];
+            InverseLT(); Ib4(X0, X1, X2, X3);
+            X0 ^= wKey[80]; X1 ^= wKey[81]; X2 ^= wKey[82]; X3 ^= wKey[83];
+            InverseLT(); Ib3(X0, X1, X2, X3);
+            X0 ^= wKey[76]; X1 ^= wKey[77]; X2 ^= wKey[78]; X3 ^= wKey[79];
+            InverseLT(); Ib2(X0, X1, X2, X3);
+            X0 ^= wKey[72]; X1 ^= wKey[73]; X2 ^= wKey[74]; X3 ^= wKey[75];
+            InverseLT(); Ib1(X0, X1, X2, X3);
+            X0 ^= wKey[68]; X1 ^= wKey[69]; X2 ^= wKey[70]; X3 ^= wKey[71];
+            InverseLT(); Ib0(X0, X1, X2, X3);
+            X0 ^= wKey[64]; X1 ^= wKey[65]; X2 ^= wKey[66]; X3 ^= wKey[67];
+            InverseLT(); Ib7(X0, X1, X2, X3);
+            X0 ^= wKey[60]; X1 ^= wKey[61]; X2 ^= wKey[62]; X3 ^= wKey[63];
+            InverseLT(); Ib6(X0, X1, X2, X3);
+            X0 ^= wKey[56]; X1 ^= wKey[57]; X2 ^= wKey[58]; X3 ^= wKey[59];
+            InverseLT(); Ib5(X0, X1, X2, X3);
+            X0 ^= wKey[52]; X1 ^= wKey[53]; X2 ^= wKey[54]; X3 ^= wKey[55];
+            InverseLT(); Ib4(X0, X1, X2, X3);
+            X0 ^= wKey[48]; X1 ^= wKey[49]; X2 ^= wKey[50]; X3 ^= wKey[51];
+            InverseLT(); Ib3(X0, X1, X2, X3);
+            X0 ^= wKey[44]; X1 ^= wKey[45]; X2 ^= wKey[46]; X3 ^= wKey[47];
+            InverseLT(); Ib2(X0, X1, X2, X3);
+            X0 ^= wKey[40]; X1 ^= wKey[41]; X2 ^= wKey[42]; X3 ^= wKey[43];
+            InverseLT(); Ib1(X0, X1, X2, X3);
+            X0 ^= wKey[36]; X1 ^= wKey[37]; X2 ^= wKey[38]; X3 ^= wKey[39];
+            InverseLT(); Ib0(X0, X1, X2, X3);
+            X0 ^= wKey[32]; X1 ^= wKey[33]; X2 ^= wKey[34]; X3 ^= wKey[35];
+            InverseLT(); Ib7(X0, X1, X2, X3);
+            X0 ^= wKey[28]; X1 ^= wKey[29]; X2 ^= wKey[30]; X3 ^= wKey[31];
+            InverseLT(); Ib6(X0, X1, X2, X3);
+            X0 ^= wKey[24]; X1 ^= wKey[25]; X2 ^= wKey[26]; X3 ^= wKey[27];
+            InverseLT(); Ib5(X0, X1, X2, X3);
+            X0 ^= wKey[20]; X1 ^= wKey[21]; X2 ^= wKey[22]; X3 ^= wKey[23];
+            InverseLT(); Ib4(X0, X1, X2, X3);
+            X0 ^= wKey[16]; X1 ^= wKey[17]; X2 ^= wKey[18]; X3 ^= wKey[19];
+            InverseLT(); Ib3(X0, X1, X2, X3);
+            X0 ^= wKey[12]; X1 ^= wKey[13]; X2 ^= wKey[14]; X3 ^= wKey[15];
+            InverseLT(); Ib2(X0, X1, X2, X3);
+            X0 ^= wKey[8]; X1 ^= wKey[9]; X2 ^= wKey[10]; X3 ^= wKey[11];
+            InverseLT(); Ib1(X0, X1, X2, X3);
+            X0 ^= wKey[4]; X1 ^= wKey[5]; X2 ^= wKey[6]; X3 ^= wKey[7];
+            InverseLT(); Ib0(X0, X1, X2, X3);
+
+            WordToBytes(X3 ^ wKey[3], outBytes, outOff);
+            WordToBytes(X2 ^ wKey[2], outBytes, outOff + 4);
+            WordToBytes(X1 ^ wKey[1], outBytes, outOff + 8);
+            WordToBytes(X0 ^ wKey[0], outBytes, outOff + 12);
+        }
+
+        /*
+        * The sboxes below are based on the work of Brian Gladman and
+        * Sam Simpson, whose original notice appears below.
+        * <p>
+        * For further details see:
+        *      http://fp.gladman.plus.com/cryptography_technology/serpent/
+		* </p>
+        */
+
+        /* Partially optimised Serpent S Box bool functions derived  */
+        /* using a recursive descent analyser but without a full search */
+        /* of all subtrees. This set of S boxes is the result of work    */
+        /* by Sam Simpson and Brian Gladman using the spare time on a    */
+        /* cluster of high capacity servers to search for S boxes with    */
+        /* this customised search engine. There are now an average of    */
+        /* 15.375 terms    per S box.                                        */
+        /*                                                              */
+        /* Copyright:   Dr B. R Gladman (gladman@seven77.demon.co.uk)   */
+        /*                and Sam Simpson (s.simpson@mia.co.uk)            */
+        /*              17th December 1998                                */
+        /*                                                              */
+        /* We hereby give permission for information in this file to be */
+        /* used freely subject only to acknowledgement of its origin.    */
+
+        /**
+        * S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
+        */
+        private void Sb0(int a, int b, int c, int d)
+        {
+            int    t1 = a ^ d;
+            int    t3 = c ^ t1;
+            int    t4 = b ^ t3;
+            X3 = (a & d) ^ t4;
+            int    t7 = a ^ (b & t1);
+            X2 = t4 ^ (c | t7);
+            int    t12 = X3 & (t3 ^ t7);
+            X1 = (~t3) ^ t12;
+            X0 = t12 ^ (~t7);
+        }
+
+        /**
+        * InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
+        */
+        private void Ib0(int a, int b, int c, int d)
+        {
+            int    t1 = ~a;
+            int    t2 = a ^ b;
+            int    t4 = d ^ (t1 | t2);
+            int    t5 = c ^ t4;
+            X2 = t2 ^ t5;
+            int    t8 = t1 ^ (d & t2);
+            X1 = t4 ^ (X2 & t8);
+            X3 = (a & t4) ^ (t5 | X1);
+            X0 = X3 ^ (t5 ^ t8);
+        }
+
+        /**
+        * S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
+        */
+        private void Sb1(int a, int b, int c, int d)
+        {
+            int    t2 = b ^ (~a);
+            int    t5 = c ^ (a | t2);
+            X2 = d ^ t5;
+            int    t7 = b ^ (d | t2);
+            int    t8 = t2 ^ X2;
+            X3 = t8 ^ (t5 & t7);
+            int    t11 = t5 ^ t7;
+            X1 = X3 ^ t11;
+            X0 = t5 ^ (t8 & t11);
+        }
+
+        /**
+        * InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
+        */
+        private void Ib1(int a, int b, int c, int d)
+        {
+            int    t1 = b ^ d;
+            int    t3 = a ^ (b & t1);
+            int    t4 = t1 ^ t3;
+            X3 = c ^ t4;
+            int    t7 = b ^ (t1 & t3);
+            int    t8 = X3 | t7;
+            X1 = t3 ^ t8;
+            int    t10 = ~X1;
+            int    t11 = X3 ^ t7;
+            X0 = t10 ^ t11;
+            X2 = t4 ^ (t10 | t11);
+        }
+
+        /**
+        * S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
+        */
+        private void Sb2(int a, int b, int c, int d)
+        {
+            int    t1 = ~a;
+            int    t2 = b ^ d;
+            int    t3 = c & t1;
+            X0 = t2 ^ t3;
+            int    t5 = c ^ t1;
+            int    t6 = c ^ X0;
+            int    t7 = b & t6;
+            X3 = t5 ^ t7;
+            X2 = a ^ ((d | t7) & (X0 | t5));
+            X1 = (t2 ^ X3) ^ (X2 ^ (d | t1));
+        }
+
+        /**
+        * InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
+        */
+        private void Ib2(int a, int b, int c, int d)
+        {
+            int    t1 = b ^ d;
+            int    t2 = ~t1;
+            int    t3 = a ^ c;
+            int    t4 = c ^ t1;
+            int    t5 = b & t4;
+            X0 = t3 ^ t5;
+            int    t7 = a | t2;
+            int    t8 = d ^ t7;
+            int    t9 = t3 | t8;
+            X3 = t1 ^ t9;
+            int    t11 = ~t4;
+            int    t12 = X0 | X3;
+            X1 = t11 ^ t12;
+            X2 = (d & t11) ^ (t3 ^ t12);
+        }
+
+        /**
+        * S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
+        */
+        private void Sb3(int a, int b, int c, int d)
+        {
+            int    t1 = a ^ b;
+            int    t2 = a & c;
+            int    t3 = a | d;
+            int    t4 = c ^ d;
+            int    t5 = t1 & t3;
+            int    t6 = t2 | t5;
+            X2 = t4 ^ t6;
+            int    t8 = b ^ t3;
+            int    t9 = t6 ^ t8;
+            int    t10 = t4 & t9;
+            X0 = t1 ^ t10;
+            int    t12 = X2 & X0;
+            X1 = t9 ^ t12;
+            X3 = (b | d) ^ (t4 ^ t12);
+        }
+
+        /**
+        * InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
+        */
+        private void Ib3(int a, int b, int c, int d)
+        {
+            int    t1 = a | b;
+            int    t2 = b ^ c;
+            int    t3 = b & t2;
+            int    t4 = a ^ t3;
+            int    t5 = c ^ t4;
+            int    t6 = d | t4;
+            X0 = t2 ^ t6;
+            int    t8 = t2 | t6;
+            int    t9 = d ^ t8;
+            X2 = t5 ^ t9;
+            int    t11 = t1 ^ t9;
+            int    t12 = X0 & t11;
+            X3 = t4 ^ t12;
+            X1 = X3 ^ (X0 ^ t11);
+        }
+
+        /**
+        * S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
+        */
+        private void Sb4(int a, int b, int c, int d)
+        {
+            int    t1 = a ^ d;
+            int    t2 = d & t1;
+            int    t3 = c ^ t2;
+            int    t4 = b | t3;
+            X3 = t1 ^ t4;
+            int    t6 = ~b;
+            int    t7 = t1 | t6;
+            X0 = t3 ^ t7;
+            int    t9 = a & X0;
+            int    t10 = t1 ^ t6;
+            int    t11 = t4 & t10;
+            X2 = t9 ^ t11;
+            X1 = (a ^ t3) ^ (t10 & X2);
+        }
+
+        /**
+        * InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
+        */
+        private void Ib4(int a, int b, int c, int d)
+        {
+            int    t1 = c | d;
+            int    t2 = a & t1;
+            int    t3 = b ^ t2;
+            int    t4 = a & t3;
+            int    t5 = c ^ t4;
+            X1 = d ^ t5;
+            int    t7 = ~a;
+            int    t8 = t5 & X1;
+            X3 = t3 ^ t8;
+            int    t10 = X1 | t7;
+            int    t11 = d ^ t10;
+            X0 = X3 ^ t11;
+            X2 = (t3 & t11) ^ (X1 ^ t7);
+        }
+
+        /**
+        * S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
+        */
+        private void Sb5(int a, int b, int c, int d)
+        {
+            int    t1 = ~a;
+            int    t2 = a ^ b;
+            int    t3 = a ^ d;
+            int    t4 = c ^ t1;
+            int    t5 = t2 | t3;
+            X0 = t4 ^ t5;
+            int    t7 = d & X0;
+            int    t8 = t2 ^ X0;
+            X1 = t7 ^ t8;
+            int    t10 = t1 | X0;
+            int    t11 = t2 | t7;
+            int    t12 = t3 ^ t10;
+            X2 = t11 ^ t12;
+            X3 = (b ^ t7) ^ (X1 & t12);
+        }
+
+        /**
+        * InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
+        */
+        private void Ib5(int a, int b, int c, int d)
+        {
+            int    t1 = ~c;
+            int    t2 = b & t1;
+            int    t3 = d ^ t2;
+            int    t4 = a & t3;
+            int    t5 = b ^ t1;
+            X3 = t4 ^ t5;
+            int    t7 = b | X3;
+            int    t8 = a & t7;
+            X1 = t3 ^ t8;
+            int    t10 = a | d;
+            int    t11 = t1 ^ t7;
+            X0 = t10 ^ t11;
+            X2 = (b & t10) ^ (t4 | (a ^ c));
+        }
+
+        /**
+        * S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
+        */
+        private void Sb6(int a, int b, int c, int d)
+        {
+            int    t1 = ~a;
+            int    t2 = a ^ d;
+            int    t3 = b ^ t2;
+            int    t4 = t1 | t2;
+            int    t5 = c ^ t4;
+            X1 = b ^ t5;
+            int    t7 = t2 | X1;
+            int    t8 = d ^ t7;
+            int    t9 = t5 & t8;
+            X2 = t3 ^ t9;
+            int    t11 = t5 ^ t8;
+            X0 = X2 ^ t11;
+            X3 = (~t5) ^ (t3 & t11);
+        }
+
+        /**
+        * InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
+        */
+        private void Ib6(int a, int b, int c, int d)
+        {
+            int    t1 = ~a;
+            int    t2 = a ^ b;
+            int    t3 = c ^ t2;
+            int    t4 = c | t1;
+            int    t5 = d ^ t4;
+            X1 = t3 ^ t5;
+            int    t7 = t3 & t5;
+            int    t8 = t2 ^ t7;
+            int    t9 = b | t8;
+            X3 = t5 ^ t9;
+            int    t11 = b | X3;
+            X0 = t8 ^ t11;
+            X2 = (d & t1) ^ (t3 ^ t11);
+        }
+
+        /**
+        * S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
+        */
+        private void Sb7(int a, int b, int c, int d)
+        {
+            int    t1 = b ^ c;
+            int    t2 = c & t1;
+            int    t3 = d ^ t2;
+            int    t4 = a ^ t3;
+            int    t5 = d | t1;
+            int    t6 = t4 & t5;
+            X1 = b ^ t6;
+            int    t8 = t3 | X1;
+            int    t9 = a & t4;
+            X3 = t1 ^ t9;
+            int    t11 = t4 ^ t8;
+            int    t12 = X3 & t11;
+            X2 = t3 ^ t12;
+            X0 = (~t11) ^ (X3 & X2);
+        }
+
+        /**
+        * InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
+        */
+        private void Ib7(int a, int b, int c, int d)
+        {
+            int t3 = c | (a & b);
+            int    t4 = d & (a | b);
+            X3 = t3 ^ t4;
+            int    t6 = ~d;
+            int    t7 = b ^ t4;
+            int    t9 = t7 | (X3 ^ t6);
+            X1 = a ^ t9;
+            X0 = (c ^ t7) ^ (d | X1);
+            X2 = (t3 ^ X1) ^ (X0 ^ (a & X3));
+        }
+
+        /**
+        * Apply the linear transformation to the register set.
+        */
+        private void LT()
+        {
+            int x0  = RotateLeft(X0, 13);
+            int x2  = RotateLeft(X2, 3);
+            int x1  = X1 ^ x0 ^ x2 ;
+            int x3  = X3 ^ x2 ^ x0 << 3;
+
+            X1  = RotateLeft(x1, 1);
+            X3  = RotateLeft(x3, 7);
+            X0  = RotateLeft(x0 ^ X1 ^ X3, 5);
+            X2  = RotateLeft(x2 ^ X3 ^ (X1 << 7), 22);
+        }
+
+        /**
+        * Apply the inverse of the linear transformation to the register set.
+        */
+        private void InverseLT()
+        {
+            int x2 = RotateRight(X2, 22) ^ X3 ^ (X1 << 7);
+            int x0 = RotateRight(X0, 5) ^ X1 ^ X3;
+            int x3 = RotateRight(X3, 7);
+            int x1 = RotateRight(X1, 1);
+            X3 = x3 ^ x2 ^ x0 << 3;
+            X1 = x1 ^ x0 ^ x2;
+            X2 = RotateRight(x2, 3);
+            X0 = RotateRight(x0, 13);
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/engines/SkipjackEngine.cs b/crypto/src/crypto/engines/SkipjackEngine.cs
new file mode 100644
index 000000000..3d2a781e6
--- /dev/null
+++ b/crypto/src/crypto/engines/SkipjackEngine.cs
@@ -0,0 +1,255 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * a class that provides a basic SKIPJACK engine.
+    */
+    public class SkipjackEngine
+		: IBlockCipher
+    {
+        const int BLOCK_SIZE = 8;
+
+        static readonly short [] ftable =
+        {
+            0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
+            0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
+            0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
+            0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
+            0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
+            0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
+            0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
+            0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
+            0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
+            0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
+            0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
+            0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
+            0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
+            0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
+            0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
+            0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46
+        };
+
+        private int[] key0, key1, key2, key3;
+        private bool encrypting;
+
+        /**
+        * initialise a SKIPJACK cipher.
+        *
+        * @param forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is KeyParameter))
+	            throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + parameters.GetType().ToString());
+
+			byte[] keyBytes = ((KeyParameter)parameters).GetKey();
+
+            this.encrypting = forEncryption;
+            this.key0 = new int[32];
+            this.key1 = new int[32];
+            this.key2 = new int[32];
+            this.key3 = new int[32];
+
+            //
+            // expand the key to 128 bytes in 4 parts (saving us a modulo, multiply
+            // and an addition).
+            //
+            for (int i = 0; i < 32; i ++)
+            {
+                key0[i] = keyBytes[(i * 4) % 10] & 0xff;
+                key1[i] = keyBytes[(i * 4 + 1) % 10] & 0xff;
+                key2[i] = keyBytes[(i * 4 + 2) % 10] & 0xff;
+                key3[i] = keyBytes[(i * 4 + 3) % 10] & 0xff;
+            }
+        }
+
+        public string AlgorithmName
+        {
+            get { return "SKIPJACK"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (key1 == null)
+                throw new InvalidOperationException("SKIPJACK engine not initialised");
+            if ((inOff + BLOCK_SIZE) > input.Length)
+                throw new DataLengthException("input buffer too short");
+            if ((outOff + BLOCK_SIZE) > output.Length)
+                throw new DataLengthException("output buffer too short");
+
+			if (encrypting)
+            {
+                EncryptBlock(input, inOff, output, outOff);
+            }
+            else
+            {
+                DecryptBlock(input, inOff, output, outOff);
+            }
+
+			return BLOCK_SIZE;
+        }
+
+		public void Reset()
+        {
+        }
+
+        /**
+        * The G permutation
+        */
+        private int G(
+            int     k,
+            int     w)
+        {
+            int g1, g2, g3, g4, g5, g6;
+
+            g1 = (w >> 8) & 0xff;
+            g2 = w & 0xff;
+
+            g3 = ftable[g2 ^ key0[k]] ^ g1;
+            g4 = ftable[g3 ^ key1[k]] ^ g2;
+            g5 = ftable[g4 ^ key2[k]] ^ g3;
+            g6 = ftable[g5 ^ key3[k]] ^ g4;
+
+            return ((g5 << 8) + g6);
+        }
+
+        public int EncryptBlock(
+            byte[]      input,
+            int         inOff,
+            byte[]      outBytes,
+            int         outOff)
+        {
+            int w1 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
+            int w2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
+            int w3 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
+            int w4 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff);
+
+            int k = 0;
+
+            for (int t = 0; t < 2; t++)
+            {
+                for(int i = 0; i < 8; i++)
+                {
+                    int tmp = w4;
+                    w4 = w3;
+                    w3 = w2;
+                    w2 = G(k, w1);
+                    w1 = w2 ^ tmp ^ (k + 1);
+                    k++;
+                }
+
+                for(int i = 0; i < 8; i++)
+                {
+                    int tmp = w4;
+                    w4 = w3;
+                    w3 = w1 ^ w2 ^ (k + 1);
+                    w2 = G(k, w1);
+                    w1 = tmp;
+                    k++;
+                }
+            }
+
+            outBytes[outOff + 0] = (byte)((w1 >> 8));
+            outBytes[outOff + 1] = (byte)(w1);
+            outBytes[outOff + 2] = (byte)((w2 >> 8));
+            outBytes[outOff + 3] = (byte)(w2);
+            outBytes[outOff + 4] = (byte)((w3 >> 8));
+            outBytes[outOff + 5] = (byte)(w3);
+            outBytes[outOff + 6] = (byte)((w4 >> 8));
+            outBytes[outOff + 7] = (byte)(w4);
+
+            return BLOCK_SIZE;
+        }
+
+        /**
+        * the inverse of the G permutation.
+        */
+        private int H(
+            int     k,
+            int     w)
+        {
+            int h1, h2, h3, h4, h5, h6;
+
+            h1 = w & 0xff;
+            h2 = (w >> 8) & 0xff;
+
+            h3 = ftable[h2 ^ key3[k]] ^ h1;
+            h4 = ftable[h3 ^ key2[k]] ^ h2;
+            h5 = ftable[h4 ^ key1[k]] ^ h3;
+            h6 = ftable[h5 ^ key0[k]] ^ h4;
+
+            return ((h6 << 8) + h5);
+        }
+
+        public int DecryptBlock(
+            byte[]      input,
+            int         inOff,
+            byte[]      outBytes,
+            int         outOff)
+        {
+            int w2 = (input[inOff + 0] << 8) + (input[inOff + 1] & 0xff);
+            int w1 = (input[inOff + 2] << 8) + (input[inOff + 3] & 0xff);
+            int w4 = (input[inOff + 4] << 8) + (input[inOff + 5] & 0xff);
+            int w3 = (input[inOff + 6] << 8) + (input[inOff + 7] & 0xff);
+
+            int k = 31;
+
+            for (int t = 0; t < 2; t++)
+            {
+                for(int i = 0; i < 8; i++)
+                {
+                    int tmp = w4;
+                    w4 = w3;
+                    w3 = w2;
+                    w2 = H(k, w1);
+                    w1 = w2 ^ tmp ^ (k + 1);
+                    k--;
+                }
+
+                for(int i = 0; i < 8; i++)
+                {
+                    int tmp = w4;
+                    w4 = w3;
+                    w3 = w1 ^ w2 ^ (k + 1);
+                    w2 = H(k, w1);
+                    w1 = tmp;
+                    k--;
+                }
+            }
+
+            outBytes[outOff + 0] = (byte)((w2 >> 8));
+            outBytes[outOff + 1] = (byte)(w2);
+            outBytes[outOff + 2] = (byte)((w1 >> 8));
+            outBytes[outOff + 3] = (byte)(w1);
+            outBytes[outOff + 4] = (byte)((w4 >> 8));
+            outBytes[outOff + 5] = (byte)(w4);
+            outBytes[outOff + 6] = (byte)((w3 >> 8));
+            outBytes[outOff + 7] = (byte)(w3);
+
+            return BLOCK_SIZE;
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/engines/TEAEngine.cs b/crypto/src/crypto/engines/TEAEngine.cs
new file mode 100644
index 000000000..582dd0f73
--- /dev/null
+++ b/crypto/src/crypto/engines/TEAEngine.cs
@@ -0,0 +1,168 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* An TEA engine.
+	*/
+	public class TeaEngine
+		: IBlockCipher
+	{
+		private const int
+			rounds		= 32,
+			block_size	= 8;
+//			key_size	= 16,
+
+		private const uint 
+			delta		= 0x9E3779B9,
+			d_sum		= 0xC6EF3720; // sum on decrypt
+
+		/*
+		* the expanded key array of 4 subkeys
+		*/
+		private uint _a, _b, _c, _d;
+		private bool _initialised;
+		private bool _forEncryption;
+
+		/**
+		* Create an instance of the TEA encryption algorithm
+		* and set some defaults
+		*/
+		public TeaEngine()
+		{
+			_initialised = false;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "TEA"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return block_size;
+		}
+
+		/**
+		* initialise
+		*
+		* @param forEncryption whether or not we are for encryption.
+		* @param params the parameters required to set up the cipher.
+		* @exception ArgumentException if the params argument is
+		* inappropriate.
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (!(parameters is KeyParameter))
+			{
+				throw new ArgumentException("invalid parameter passed to TEA init - "
+					+ parameters.GetType().FullName);
+			}
+
+			_forEncryption = forEncryption;
+			_initialised = true;
+
+			KeyParameter p = (KeyParameter) parameters;
+
+			setKey(p.GetKey());
+		}
+
+		public int ProcessBlock(
+			byte[]  inBytes,
+			int     inOff,
+			byte[]  outBytes,
+			int     outOff)
+		{
+			if (!_initialised)
+				throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+			if ((inOff + block_size) > inBytes.Length)
+				throw new DataLengthException("input buffer too short");
+
+			if ((outOff + block_size) > outBytes.Length)
+				throw new DataLengthException("output buffer too short");
+
+			return _forEncryption
+				?	encryptBlock(inBytes, inOff, outBytes, outOff)
+				:	decryptBlock(inBytes, inOff, outBytes, outOff);
+		}
+
+		public void Reset()
+		{
+		}
+
+		/**
+		* Re-key the cipher.
+		*
+		* @param  key  the key to be used
+		*/
+		private void setKey(
+			byte[] key)
+		{
+			_a = Pack.BE_To_UInt32(key, 0);
+			_b = Pack.BE_To_UInt32(key, 4);
+			_c = Pack.BE_To_UInt32(key, 8);
+			_d = Pack.BE_To_UInt32(key, 12);
+		}
+
+		private int encryptBlock(
+			byte[]	inBytes,
+			int		inOff,
+			byte[]	outBytes,
+			int		outOff)
+		{
+			// Pack bytes into integers
+			uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
+			uint v1 = Pack.BE_To_UInt32(inBytes, inOff + 4);
+	        
+			uint sum = 0;
+	        
+			for (int i = 0; i != rounds; i++)
+			{
+				sum += delta;
+				v0  += ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >> 5) + _b);
+				v1  += ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >> 5) + _d);
+			}
+
+			Pack.UInt32_To_BE(v0, outBytes, outOff);
+			Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+			return block_size;
+		}
+
+		private int decryptBlock(
+			byte[]	inBytes,
+			int		inOff,
+			byte[]	outBytes,
+			int		outOff)
+		{
+			// Pack bytes into integers
+			uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
+			uint v1 = Pack.BE_To_UInt32(inBytes, inOff + 4);
+
+			uint sum = d_sum;
+
+			for (int i = 0; i != rounds; i++)
+			{
+				v1  -= ((v0 << 4) + _c) ^ (v0 + sum) ^ ((v0 >> 5) + _d);
+				v0  -= ((v1 << 4) + _a) ^ (v1 + sum) ^ ((v1 >> 5) + _b);
+				sum -= delta;
+			}
+
+			Pack.UInt32_To_BE(v0, outBytes, outOff);
+			Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+			return block_size;
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/ThreefishEngine.cs b/crypto/src/crypto/engines/ThreefishEngine.cs
new file mode 100644
index 000000000..954470345
--- /dev/null
+++ b/crypto/src/crypto/engines/ThreefishEngine.cs
@@ -0,0 +1,1490 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <summary>
+	/// Implementation of the Threefish tweakable large block cipher in 256, 512 and 1024 bit block
+	/// sizes.
+	/// </summary>
+	/// <remarks>
+	/// This is the 1.3 version of Threefish defined in the Skein hash function submission to the NIST
+	/// SHA-3 competition in October 2010.
+	/// <p/>
+	/// Threefish was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+	/// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+	/// <p/>
+	/// This implementation inlines all round functions, unrolls 8 rounds, and uses 1.2k of static tables
+	/// to speed up key schedule injection. <br/>
+	/// 2 x block size state is retained by each cipher instance.
+	/// </remarks>
+	public class ThreefishEngine
+		: IBlockCipher
+	{
+		/// <summary>
+		/// 256 bit block size - Threefish-256
+		/// </summary>
+		public const int BLOCKSIZE_256 = 256;
+		/// <summary>
+		/// 512 bit block size - Threefish-512
+		/// </summary>
+		public const int BLOCKSIZE_512 = 512;
+		/// <summary>
+		/// 1024 bit block size - Threefish-1024
+		/// </summary>
+		public const int BLOCKSIZE_1024 = 1024;
+
+		/**
+	     * Size of the tweak in bytes (always 128 bit/16 bytes)
+	     */
+		private const int TWEAK_SIZE_BYTES = 16;
+		private const int TWEAK_SIZE_WORDS = TWEAK_SIZE_BYTES / 8;
+
+		/**
+	     * Rounds in Threefish-256
+	     */
+		private const int ROUNDS_256 = 72;
+		/**
+	     * Rounds in Threefish-512
+	     */
+		private const int ROUNDS_512 = 72;
+		/**
+	     * Rounds in Threefish-1024
+	     */
+		private const int ROUNDS_1024 = 80;
+
+		/**
+	     * Max rounds of any of the variants
+	     */
+		private const int MAX_ROUNDS = ROUNDS_1024;
+
+		/**
+	     * Key schedule parity constant
+	     */
+		private const ulong C_240 = 0x1BD11BDAA9FC1A22L;
+
+		/* Pre-calculated modulo arithmetic tables for key schedule lookups */
+		private static readonly int[] MOD9 = new int[MAX_ROUNDS];
+		private static readonly int[] MOD17 = new int[MOD9.Length];
+		private static readonly int[] MOD5 = new int[MOD9.Length];
+		private static readonly int[] MOD3 = new int[MOD9.Length];
+
+		static ThreefishEngine()
+		{
+			for (int i = 0; i < MOD9.Length; i++)
+			{
+				MOD17[i] = i % 17;
+				MOD9[i] = i % 9;
+				MOD5[i] = i % 5;
+				MOD3[i] = i % 3;
+			}
+		}
+
+		/**
+	     * Block size in bytes
+	     */
+		private readonly int blocksizeBytes;
+
+		/**
+	     * Block size in 64 bit words
+	     */
+		private readonly int blocksizeWords;
+
+		/**
+	     * Buffer for byte oriented processBytes to call internal word API
+	     */
+		private readonly ulong[] currentBlock;
+
+		/**
+	     * Tweak bytes (2 byte t1,t2, calculated t3 and repeat of t1,t2 for modulo free lookup
+	     */
+		private readonly ulong[] t = new ulong[5];
+
+		/**
+	     * Key schedule words
+	     */
+		private readonly ulong[] kw;
+
+		/**
+	     * The internal cipher implementation (varies by blocksize)
+	     */
+		private readonly ThreefishCipher cipher;
+
+		private bool forEncryption;
+
+		/// <summary>
+		/// Constructs a new Threefish cipher, with a specified block size.
+		/// </summary>
+		/// <param name="blocksizeBits">the block size in bits, one of <see cref="BLOCKSIZE_256"/>, <see cref="BLOCKSIZE_512"/>,
+		///                      <see cref="BLOCKSIZE_1024"/> .</param>
+		public ThreefishEngine(int blocksizeBits)
+		{
+			this.blocksizeBytes = (blocksizeBits / 8);
+			this.blocksizeWords = (this.blocksizeBytes / 8);
+			this.currentBlock = new ulong[blocksizeWords];
+
+			/*
+	         * Provide room for original key words, extended key word and repeat of key words for modulo
+	         * free lookup of key schedule words.
+	         */
+			this.kw = new ulong[2 * blocksizeWords + 1];
+
+			switch (blocksizeBits)
+			{
+				case BLOCKSIZE_256:
+				cipher = new Threefish256Cipher(kw, t);
+				break;
+				case BLOCKSIZE_512:
+				cipher = new Threefish512Cipher(kw, t);
+				break;
+				case BLOCKSIZE_1024:
+				cipher = new Threefish1024Cipher(kw, t);
+				break;
+				default:
+				throw new ArgumentException(
+					"Invalid blocksize - Threefish is defined with block size of 256, 512, or 1024 bits");
+			}
+		}
+
+		/// <summary>
+		/// Initialise the engine.
+		/// </summary>
+		/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
+		/// <param name="parameters">an instance of <see cref="TweakableBlockCipherParameters"/> or <see cref="KeyParameter"/> (to
+		///               use a 0 tweak)</param>
+		public void Init(bool forEncryption, ICipherParameters parameters)
+		{
+			byte[] keyBytes;
+			byte[] tweakBytes;
+
+			if (parameters is TweakableBlockCipherParameters)
+			{
+				TweakableBlockCipherParameters tParams = (TweakableBlockCipherParameters)parameters;
+				keyBytes = tParams.Key.GetKey();
+				tweakBytes = tParams.Tweak;
+			}
+			else if (parameters is KeyParameter)
+			{
+				keyBytes = ((KeyParameter)parameters).GetKey();
+				tweakBytes = null;
+			}
+			else
+			{
+				throw new ArgumentException("Invalid parameter passed to Threefish init - "
+				                            + parameters.GetType().Name);
+			}
+
+			ulong[] keyWords = null;
+			ulong[] tweakWords = null;
+
+			if (keyBytes != null)
+			{
+				if (keyBytes.Length != this.blocksizeBytes)
+				{
+					throw new ArgumentException("Threefish key must be same size as block (" + blocksizeBytes
+					                            + " bytes)");
+				}
+				keyWords = new ulong[blocksizeWords];
+				for (int i = 0; i < keyWords.Length; i++)
+				{
+					keyWords[i] = BytesToWord(keyBytes, i * 8);
+				}
+			}
+			if (tweakBytes != null)
+			{
+				if (tweakBytes.Length != TWEAK_SIZE_BYTES)
+				{
+					throw new ArgumentException("Threefish tweak must be " + TWEAK_SIZE_BYTES + " bytes");
+				}
+				tweakWords = new ulong[]{BytesToWord(tweakBytes, 0), BytesToWord(tweakBytes, 8)};
+			}
+			Init(forEncryption, keyWords, tweakWords);
+		}
+
+		/// <summary>
+		/// Initialise the engine, specifying the key and tweak directly.
+		/// </summary>
+		/// <param name="forEncryption">the cipher mode.</param>
+		/// <param name="key">the words of the key, or <code>null</code> to use the current key.</param>
+		/// <param name="tweak">the 2 word (128 bit) tweak, or <code>null</code> to use the current tweak.</param>
+		internal void Init(bool forEncryption, ulong[] key, ulong[] tweak)
+		{
+			this.forEncryption = forEncryption;
+			if (key != null)
+			{
+				SetKey(key);
+			}
+			if (tweak != null)
+			{
+				SetTweak(tweak);
+			}
+		}
+
+		private void SetKey(ulong[] key)
+		{
+			if (key.Length != this.blocksizeWords)
+			{
+				throw new ArgumentException("Threefish key must be same size as block (" + blocksizeWords
+				                            + " words)");
+			}
+
+			/*
+	         * Full subkey schedule is deferred to execution to avoid per cipher overhead (10k for 512,
+	         * 20k for 1024).
+	         * 
+	         * Key and tweak word sequences are repeated, and static MOD17/MOD9/MOD5/MOD3 calculations
+	         * used, to avoid expensive mod computations during cipher operation.
+	         */
+
+			ulong knw = C_240;
+			for (int i = 0; i < blocksizeWords; i++)
+			{
+				kw[i] = key[i];
+				knw = knw ^ kw[i];
+			}
+			kw[blocksizeWords] = knw;
+			Array.Copy(kw, 0, kw, blocksizeWords + 1, blocksizeWords);
+		}
+
+		private void SetTweak(ulong[] tweak)
+		{
+			if (tweak.Length != TWEAK_SIZE_WORDS)
+			{
+				throw new ArgumentException("Tweak must be " + TWEAK_SIZE_WORDS + " words.");
+			}
+
+			/*
+	         * Tweak schedule partially repeated to avoid mod computations during cipher operation
+	         */
+			t[0] = tweak[0];
+			t[1] = tweak[1];
+			t[2] = t[0] ^ t[1];
+			t[3] = t[0];
+			t[4] = t[1];
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Threefish-" + (blocksizeBytes * 8); }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return blocksizeBytes;
+		}
+
+		public void Reset()
+		{
+		}
+
+		public int ProcessBlock(byte[] inBytes, int inOff, byte[] outBytes, int outOff)
+		{
+			if ((outOff + blocksizeBytes) > outBytes.Length)
+			{
+				throw new DataLengthException("Output buffer too short");
+			}
+
+			if ((inOff + blocksizeBytes) > inBytes.Length)
+			{
+				throw new DataLengthException("Input buffer too short");
+			}
+
+			for (int i = 0; i < blocksizeBytes; i += 8)
+			{
+				currentBlock[i >> 3] = BytesToWord(inBytes, inOff + i);
+			}
+			ProcessBlock(this.currentBlock, this.currentBlock);
+			for (int i = 0; i < blocksizeBytes; i += 8)
+			{
+				WordToBytes(this.currentBlock[i >> 3], outBytes, outOff + i);
+			}
+
+			return blocksizeBytes;
+		}
+
+		/// <summary>
+		/// Process a block of data represented as 64 bit words.
+		/// </summary>
+		/// <returns>the number of 8 byte words processed (which will be the same as the block size).</returns>
+		/// <param name="inWords">a block sized buffer of words to process.</param>
+		/// <param name="outWords">a block sized buffer of words to receive the output of the operation.</param>
+		/// <exception cref="DataLengthException">if either the input or output is not block sized</exception>
+		/// <exception cref="InvalidOperationException">if this engine is not initialised</exception>
+		internal int ProcessBlock(ulong[] inWords, ulong[] outWords)
+		{
+			if (kw[blocksizeWords] == 0)
+			{
+				throw new InvalidOperationException("Threefish engine not initialised");
+			}
+
+			if (inWords.Length != blocksizeWords)
+			{
+				throw new DataLengthException("Input buffer too short");
+			}
+			if (outWords.Length != blocksizeWords)
+			{
+				throw new DataLengthException("Output buffer too short");
+			}
+
+			if (forEncryption)
+			{
+				cipher.EncryptBlock(inWords, outWords);
+			}
+			else
+			{
+				cipher.DecryptBlock(inWords, outWords);
+			}
+
+			return blocksizeWords;
+		}
+
+		/// <summary>
+		/// Read a single 64 bit word from input in LSB first order.
+		/// </summary>
+		internal static ulong BytesToWord(byte[] bytes, int off)
+		{
+			if ((off + 8) > bytes.Length)
+			{
+				// Help the JIT avoid index checks
+				throw new ArgumentException();
+			}
+
+			ulong word = 0;
+			int index = off;
+
+			word = (bytes[index++] & 0xffUL);
+			word |= (bytes[index++] & 0xffUL) << 8;
+			word |= (bytes[index++] & 0xffUL) << 16;
+			word |= (bytes[index++] & 0xffUL) << 24;
+			word |= (bytes[index++] & 0xffUL) << 32;
+			word |= (bytes[index++] & 0xffUL) << 40;
+			word |= (bytes[index++] & 0xffUL) << 48;
+			word |= (bytes[index++] & 0xffUL) << 56;
+
+			return word;
+		}
+
+		/// <summary>
+		/// Write a 64 bit word to output in LSB first order.
+		/// </summary>
+		internal static void WordToBytes(ulong word, byte[] bytes, int off)
+		{
+			if ((off + 8) > bytes.Length)
+			{
+				// Help the JIT avoid index checks
+				throw new ArgumentException();
+			}
+			int index = off;
+
+			bytes[index++] = (byte)word;
+			bytes[index++] = (byte)(word >> 8);
+			bytes[index++] = (byte)(word >> 16);
+			bytes[index++] = (byte)(word >> 24);
+			bytes[index++] = (byte)(word >> 32);
+			bytes[index++] = (byte)(word >> 40);
+			bytes[index++] = (byte)(word >> 48);
+			bytes[index++] = (byte)(word >> 56);
+		}
+
+		/**
+	     * Rotate left + xor part of the mix operation.
+	     */
+		private static ulong RotlXor(ulong x, int n, ulong xor)
+		{
+			return ((x << n) | (x >> (64 - n))) ^ xor;
+		}
+
+		/**
+	     * Rotate xor + rotate right part of the unmix operation.
+	     */
+		private static ulong XorRotr(ulong x, int n, ulong xor)
+		{
+			ulong xored = x ^ xor;
+			return (xored >> n) | (xored << (64 - n));
+		}
+
+		private abstract class ThreefishCipher
+		{
+			/**
+	         * The extended + repeated tweak words
+	         */
+			protected readonly ulong[] t;
+			/**
+	         * The extended + repeated key words
+	         */
+			protected readonly ulong[] kw;
+
+			protected ThreefishCipher(ulong[] kw, ulong[] t)
+			{
+				this.kw = kw;
+				this.t = t;
+			}
+
+			internal abstract void EncryptBlock(ulong[] block, ulong[] outWords);
+
+			internal abstract void DecryptBlock(ulong[] block, ulong[] outWords);
+
+		}
+
+		private sealed class Threefish256Cipher
+			: ThreefishCipher
+		{
+			/**
+	         * Mix rotation constants defined in Skein 1.3 specification
+	         */
+			private const int ROTATION_0_0 = 14, ROTATION_0_1 = 16;
+			private const int ROTATION_1_0 = 52, ROTATION_1_1 = 57;
+			private const int ROTATION_2_0 = 23, ROTATION_2_1 = 40;
+			private const int ROTATION_3_0 = 5, ROTATION_3_1 = 37;
+
+			private const int ROTATION_4_0 = 25, ROTATION_4_1 = 33;
+			private const int ROTATION_5_0 = 46, ROTATION_5_1 = 12;
+			private const int ROTATION_6_0 = 58, ROTATION_6_1 = 22;
+			private const int ROTATION_7_0 = 32, ROTATION_7_1 = 32;
+
+			public Threefish256Cipher(ulong[] kw, ulong[] t)
+				: base(kw, t)
+			{
+			}
+
+			internal override void EncryptBlock(ulong[] block, ulong[] outWords)
+			{
+				ulong[] kw = this.kw;
+				ulong[] t = this.t;
+				int[] mod5 = MOD5;
+				int[] mod3 = MOD3;
+
+				/* Help the JIT avoid index bounds checks */
+				if (kw.Length != 9)
+				{
+					throw new ArgumentException();
+				}
+				if (t.Length != 5)
+				{
+					throw new ArgumentException();
+				}
+
+				/*
+	             * Read 4 words of plaintext data, not using arrays for cipher state
+	             */
+				ulong b0 = block[0];
+				ulong b1 = block[1];
+				ulong b2 = block[2];
+				ulong b3 = block[3];
+
+				/*
+	             * First subkey injection.
+	             */
+				b0 += kw[0];
+				b1 += kw[1] + t[0];
+				b2 += kw[2] + t[1];
+				b3 += kw[3];
+
+				/*
+	             * Rounds loop, unrolled to 8 rounds per iteration.
+	             * 
+	             * Unrolling to multiples of 4 avoids the mod 4 check for key injection, and allows
+	             * inlining of the permutations, which cycle every of 2 rounds (avoiding array
+	             * index/lookup).
+	             * 
+	             * Unrolling to multiples of 8 avoids the mod 8 rotation constant lookup, and allows
+	             * inlining constant rotation values (avoiding array index/lookup).
+	             */
+
+				for (int d = 1; d < (ROUNDS_256 / 4); d += 2)
+				{
+					int dm5 = mod5[d];
+					int dm3 = mod3[d];
+
+					/*
+	                 * 4 rounds of mix and permute.
+	                 * 
+	                 * Permute schedule has a 2 round cycle, so permutes are inlined in the mix
+	                 * operations in each 4 round block.
+	                 */
+					b1 = RotlXor(b1, ROTATION_0_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_0_1, b2 += b3);
+
+					b3 = RotlXor(b3, ROTATION_1_0, b0 += b3);
+					b1 = RotlXor(b1, ROTATION_1_1, b2 += b1);
+
+					b1 = RotlXor(b1, ROTATION_2_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_2_1, b2 += b3);
+
+					b3 = RotlXor(b3, ROTATION_3_0, b0 += b3);
+					b1 = RotlXor(b1, ROTATION_3_1, b2 += b1);
+
+					/*
+	                 * Subkey injection for first 4 rounds.
+	                 */
+					b0 += kw[dm5];
+					b1 += kw[dm5 + 1] + t[dm3];
+					b2 += kw[dm5 + 2] + t[dm3 + 1];
+					b3 += kw[dm5 + 3] + (uint)d;
+
+					/*
+	                 * 4 more rounds of mix/permute
+	                 */
+					b1 = RotlXor(b1, ROTATION_4_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_4_1, b2 += b3);
+
+					b3 = RotlXor(b3, ROTATION_5_0, b0 += b3);
+					b1 = RotlXor(b1, ROTATION_5_1, b2 += b1);
+
+					b1 = RotlXor(b1, ROTATION_6_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_6_1, b2 += b3);
+
+					b3 = RotlXor(b3, ROTATION_7_0, b0 += b3);
+					b1 = RotlXor(b1, ROTATION_7_1, b2 += b1);
+
+					/*
+	                 * Subkey injection for next 4 rounds.
+	                 */
+					b0 += kw[dm5 + 1];
+					b1 += kw[dm5 + 2] + t[dm3 + 1];
+					b2 += kw[dm5 + 3] + t[dm3 + 2];
+					b3 += kw[dm5 + 4] + (uint)d + 1;
+				}
+
+				/*
+	             * Output cipher state.
+	             */
+				outWords[0] = b0;
+				outWords[1] = b1;
+				outWords[2] = b2;
+				outWords[3] = b3;
+			}
+
+			internal override void DecryptBlock(ulong[] block, ulong[] state)
+			{
+				ulong[] kw = this.kw;
+				ulong[] t = this.t;
+				int[] mod5 = MOD5;
+				int[] mod3 = MOD3;
+
+				/* Help the JIT avoid index bounds checks */
+				if (kw.Length != 9)
+				{
+					throw new ArgumentException();
+				}
+				if (t.Length != 5)
+				{
+					throw new ArgumentException();
+				}
+
+				ulong b0 = block[0];
+				ulong b1 = block[1];
+				ulong b2 = block[2];
+				ulong b3 = block[3];
+
+				for (int d = (ROUNDS_256 / 4) - 1; d >= 1; d -= 2)
+				{
+					int dm5 = mod5[d];
+					int dm3 = mod3[d];
+
+					/* Reverse key injection for second 4 rounds */
+					b0 -= kw[dm5 + 1];
+					b1 -= kw[dm5 + 2] + t[dm3 + 1];
+					b2 -= kw[dm5 + 3] + t[dm3 + 2];
+					b3 -= kw[dm5 + 4] + (uint)d + 1;
+
+					/* Reverse second 4 mix/permute rounds */
+
+					b3 = XorRotr(b3, ROTATION_7_0, b0);
+					b0 -= b3;
+					b1 = XorRotr(b1, ROTATION_7_1, b2);
+					b2 -= b1;
+
+					b1 = XorRotr(b1, ROTATION_6_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_6_1, b2);
+					b2 -= b3;
+
+					b3 = XorRotr(b3, ROTATION_5_0, b0);
+					b0 -= b3;
+					b1 = XorRotr(b1, ROTATION_5_1, b2);
+					b2 -= b1;
+
+					b1 = XorRotr(b1, ROTATION_4_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_4_1, b2);
+					b2 -= b3;
+
+					/* Reverse key injection for first 4 rounds */
+					b0 -= kw[dm5];
+					b1 -= kw[dm5 + 1] + t[dm3];
+					b2 -= kw[dm5 + 2] + t[dm3 + 1];
+					b3 -= kw[dm5 + 3] + (uint)d;
+
+					/* Reverse first 4 mix/permute rounds */
+					b3 = XorRotr(b3, ROTATION_3_0, b0);
+					b0 -= b3;
+					b1 = XorRotr(b1, ROTATION_3_1, b2);
+					b2 -= b1;
+
+					b1 = XorRotr(b1, ROTATION_2_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_2_1, b2);
+					b2 -= b3;
+
+					b3 = XorRotr(b3, ROTATION_1_0, b0);
+					b0 -= b3;
+					b1 = XorRotr(b1, ROTATION_1_1, b2);
+					b2 -= b1;
+
+					b1 = XorRotr(b1, ROTATION_0_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_0_1, b2);
+					b2 -= b3;
+				}
+
+				/*
+	             * First subkey uninjection.
+	             */
+				b0 -= kw[0];
+				b1 -= kw[1] + t[0];
+				b2 -= kw[2] + t[1];
+				b3 -= kw[3];
+
+				/*
+	             * Output cipher state.
+	             */
+				state[0] = b0;
+				state[1] = b1;
+				state[2] = b2;
+				state[3] = b3;
+			}
+
+		}
+
+		private sealed class Threefish512Cipher
+			: ThreefishCipher
+		{
+			/**
+	         * Mix rotation constants defined in Skein 1.3 specification
+	         */
+			private const int ROTATION_0_0 = 46, ROTATION_0_1 = 36, ROTATION_0_2 = 19, ROTATION_0_3 = 37;
+			private const int ROTATION_1_0 = 33, ROTATION_1_1 = 27, ROTATION_1_2 = 14, ROTATION_1_3 = 42;
+			private const int ROTATION_2_0 = 17, ROTATION_2_1 = 49, ROTATION_2_2 = 36, ROTATION_2_3 = 39;
+			private const int ROTATION_3_0 = 44, ROTATION_3_1 = 9, ROTATION_3_2 = 54, ROTATION_3_3 = 56;
+
+			private const int ROTATION_4_0 = 39, ROTATION_4_1 = 30, ROTATION_4_2 = 34, ROTATION_4_3 = 24;
+			private const int ROTATION_5_0 = 13, ROTATION_5_1 = 50, ROTATION_5_2 = 10, ROTATION_5_3 = 17;
+			private const int ROTATION_6_0 = 25, ROTATION_6_1 = 29, ROTATION_6_2 = 39, ROTATION_6_3 = 43;
+			private const int ROTATION_7_0 = 8, ROTATION_7_1 = 35, ROTATION_7_2 = 56, ROTATION_7_3 = 22;
+
+			internal Threefish512Cipher(ulong[] kw, ulong[] t)
+				: base(kw, t)
+			{
+			}
+
+			internal override void EncryptBlock(ulong[] block, ulong[] outWords)
+			{
+				ulong[] kw = this.kw;
+				ulong[] t = this.t;
+				int[] mod9 = MOD9;
+				int[] mod3 = MOD3;
+
+				/* Help the JIT avoid index bounds checks */
+				if (kw.Length != 17)
+				{
+					throw new ArgumentException();
+				}
+				if (t.Length != 5)
+				{
+					throw new ArgumentException();
+				}
+
+				/*
+	             * Read 8 words of plaintext data, not using arrays for cipher state
+	             */
+				ulong b0 = block[0];
+				ulong b1 = block[1];
+				ulong b2 = block[2];
+				ulong b3 = block[3];
+				ulong b4 = block[4];
+				ulong b5 = block[5];
+				ulong b6 = block[6];
+				ulong b7 = block[7];
+
+				/*
+	             * First subkey injection.
+	             */
+				b0 += kw[0];
+				b1 += kw[1];
+				b2 += kw[2];
+				b3 += kw[3];
+				b4 += kw[4];
+				b5 += kw[5] + t[0];
+				b6 += kw[6] + t[1];
+				b7 += kw[7];
+
+				/*
+	             * Rounds loop, unrolled to 8 rounds per iteration.
+	             * 
+	             * Unrolling to multiples of 4 avoids the mod 4 check for key injection, and allows
+	             * inlining of the permutations, which cycle every of 4 rounds (avoiding array
+	             * index/lookup).
+	             * 
+	             * Unrolling to multiples of 8 avoids the mod 8 rotation constant lookup, and allows
+	             * inlining constant rotation values (avoiding array index/lookup).
+	             */
+
+				for (int d = 1; d < (ROUNDS_512 / 4); d += 2)
+				{
+					int dm9 = mod9[d];
+					int dm3 = mod3[d];
+
+					/*
+	                 * 4 rounds of mix and permute.
+	                 * 
+	                 * Permute schedule has a 4 round cycle, so permutes are inlined in the mix
+	                 * operations in each 4 round block.
+	                 */
+					b1 = RotlXor(b1, ROTATION_0_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_0_1, b2 += b3);
+					b5 = RotlXor(b5, ROTATION_0_2, b4 += b5);
+					b7 = RotlXor(b7, ROTATION_0_3, b6 += b7);
+
+					b1 = RotlXor(b1, ROTATION_1_0, b2 += b1);
+					b7 = RotlXor(b7, ROTATION_1_1, b4 += b7);
+					b5 = RotlXor(b5, ROTATION_1_2, b6 += b5);
+					b3 = RotlXor(b3, ROTATION_1_3, b0 += b3);
+
+					b1 = RotlXor(b1, ROTATION_2_0, b4 += b1);
+					b3 = RotlXor(b3, ROTATION_2_1, b6 += b3);
+					b5 = RotlXor(b5, ROTATION_2_2, b0 += b5);
+					b7 = RotlXor(b7, ROTATION_2_3, b2 += b7);
+
+					b1 = RotlXor(b1, ROTATION_3_0, b6 += b1);
+					b7 = RotlXor(b7, ROTATION_3_1, b0 += b7);
+					b5 = RotlXor(b5, ROTATION_3_2, b2 += b5);
+					b3 = RotlXor(b3, ROTATION_3_3, b4 += b3);
+
+					/*
+	                 * Subkey injection for first 4 rounds.
+	                 */
+					b0 += kw[dm9];
+					b1 += kw[dm9 + 1];
+					b2 += kw[dm9 + 2];
+					b3 += kw[dm9 + 3];
+					b4 += kw[dm9 + 4];
+					b5 += kw[dm9 + 5] + t[dm3];
+					b6 += kw[dm9 + 6] + t[dm3 + 1];
+					b7 += kw[dm9 + 7] + (uint)d;
+
+					/*
+	                 * 4 more rounds of mix/permute
+	                 */
+					b1 = RotlXor(b1, ROTATION_4_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_4_1, b2 += b3);
+					b5 = RotlXor(b5, ROTATION_4_2, b4 += b5);
+					b7 = RotlXor(b7, ROTATION_4_3, b6 += b7);
+
+					b1 = RotlXor(b1, ROTATION_5_0, b2 += b1);
+					b7 = RotlXor(b7, ROTATION_5_1, b4 += b7);
+					b5 = RotlXor(b5, ROTATION_5_2, b6 += b5);
+					b3 = RotlXor(b3, ROTATION_5_3, b0 += b3);
+
+					b1 = RotlXor(b1, ROTATION_6_0, b4 += b1);
+					b3 = RotlXor(b3, ROTATION_6_1, b6 += b3);
+					b5 = RotlXor(b5, ROTATION_6_2, b0 += b5);
+					b7 = RotlXor(b7, ROTATION_6_3, b2 += b7);
+
+					b1 = RotlXor(b1, ROTATION_7_0, b6 += b1);
+					b7 = RotlXor(b7, ROTATION_7_1, b0 += b7);
+					b5 = RotlXor(b5, ROTATION_7_2, b2 += b5);
+					b3 = RotlXor(b3, ROTATION_7_3, b4 += b3);
+
+					/*
+	                 * Subkey injection for next 4 rounds.
+	                 */
+					b0 += kw[dm9 + 1];
+					b1 += kw[dm9 + 2];
+					b2 += kw[dm9 + 3];
+					b3 += kw[dm9 + 4];
+					b4 += kw[dm9 + 5];
+					b5 += kw[dm9 + 6] + t[dm3 + 1];
+					b6 += kw[dm9 + 7] + t[dm3 + 2];
+					b7 += kw[dm9 + 8] + (uint)d + 1;
+				}
+
+				/*
+	             * Output cipher state.
+	             */
+				outWords[0] = b0;
+				outWords[1] = b1;
+				outWords[2] = b2;
+				outWords[3] = b3;
+				outWords[4] = b4;
+				outWords[5] = b5;
+				outWords[6] = b6;
+				outWords[7] = b7;
+			}
+
+			internal override void DecryptBlock(ulong[] block, ulong[] state)
+			{
+				ulong[] kw = this.kw;
+				ulong[] t = this.t;
+				int[] mod9 = MOD9;
+				int[] mod3 = MOD3;
+
+				/* Help the JIT avoid index bounds checks */
+				if (kw.Length != 17)
+				{
+					throw new ArgumentException();
+				}
+				if (t.Length != 5)
+				{
+					throw new ArgumentException();
+				}
+
+				ulong b0 = block[0];
+				ulong b1 = block[1];
+				ulong b2 = block[2];
+				ulong b3 = block[3];
+				ulong b4 = block[4];
+				ulong b5 = block[5];
+				ulong b6 = block[6];
+				ulong b7 = block[7];
+
+				for (int d = (ROUNDS_512 / 4) - 1; d >= 1; d -= 2)
+				{
+					int dm9 = mod9[d];
+					int dm3 = mod3[d];
+
+					/* Reverse key injection for second 4 rounds */
+					b0 -= kw[dm9 + 1];
+					b1 -= kw[dm9 + 2];
+					b2 -= kw[dm9 + 3];
+					b3 -= kw[dm9 + 4];
+					b4 -= kw[dm9 + 5];
+					b5 -= kw[dm9 + 6] + t[dm3 + 1];
+					b6 -= kw[dm9 + 7] + t[dm3 + 2];
+					b7 -= kw[dm9 + 8] + (uint)d + 1;
+
+					/* Reverse second 4 mix/permute rounds */
+
+					b1 = XorRotr(b1, ROTATION_7_0, b6);
+					b6 -= b1;
+					b7 = XorRotr(b7, ROTATION_7_1, b0);
+					b0 -= b7;
+					b5 = XorRotr(b5, ROTATION_7_2, b2);
+					b2 -= b5;
+					b3 = XorRotr(b3, ROTATION_7_3, b4);
+					b4 -= b3;
+
+					b1 = XorRotr(b1, ROTATION_6_0, b4);
+					b4 -= b1;
+					b3 = XorRotr(b3, ROTATION_6_1, b6);
+					b6 -= b3;
+					b5 = XorRotr(b5, ROTATION_6_2, b0);
+					b0 -= b5;
+					b7 = XorRotr(b7, ROTATION_6_3, b2);
+					b2 -= b7;
+
+					b1 = XorRotr(b1, ROTATION_5_0, b2);
+					b2 -= b1;
+					b7 = XorRotr(b7, ROTATION_5_1, b4);
+					b4 -= b7;
+					b5 = XorRotr(b5, ROTATION_5_2, b6);
+					b6 -= b5;
+					b3 = XorRotr(b3, ROTATION_5_3, b0);
+					b0 -= b3;
+
+					b1 = XorRotr(b1, ROTATION_4_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_4_1, b2);
+					b2 -= b3;
+					b5 = XorRotr(b5, ROTATION_4_2, b4);
+					b4 -= b5;
+					b7 = XorRotr(b7, ROTATION_4_3, b6);
+					b6 -= b7;
+
+					/* Reverse key injection for first 4 rounds */
+					b0 -= kw[dm9];
+					b1 -= kw[dm9 + 1];
+					b2 -= kw[dm9 + 2];
+					b3 -= kw[dm9 + 3];
+					b4 -= kw[dm9 + 4];
+					b5 -= kw[dm9 + 5] + t[dm3];
+					b6 -= kw[dm9 + 6] + t[dm3 + 1];
+					b7 -= kw[dm9 + 7] + (uint)d;
+
+					/* Reverse first 4 mix/permute rounds */
+					b1 = XorRotr(b1, ROTATION_3_0, b6);
+					b6 -= b1;
+					b7 = XorRotr(b7, ROTATION_3_1, b0);
+					b0 -= b7;
+					b5 = XorRotr(b5, ROTATION_3_2, b2);
+					b2 -= b5;
+					b3 = XorRotr(b3, ROTATION_3_3, b4);
+					b4 -= b3;
+
+					b1 = XorRotr(b1, ROTATION_2_0, b4);
+					b4 -= b1;
+					b3 = XorRotr(b3, ROTATION_2_1, b6);
+					b6 -= b3;
+					b5 = XorRotr(b5, ROTATION_2_2, b0);
+					b0 -= b5;
+					b7 = XorRotr(b7, ROTATION_2_3, b2);
+					b2 -= b7;
+
+					b1 = XorRotr(b1, ROTATION_1_0, b2);
+					b2 -= b1;
+					b7 = XorRotr(b7, ROTATION_1_1, b4);
+					b4 -= b7;
+					b5 = XorRotr(b5, ROTATION_1_2, b6);
+					b6 -= b5;
+					b3 = XorRotr(b3, ROTATION_1_3, b0);
+					b0 -= b3;
+
+					b1 = XorRotr(b1, ROTATION_0_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_0_1, b2);
+					b2 -= b3;
+					b5 = XorRotr(b5, ROTATION_0_2, b4);
+					b4 -= b5;
+					b7 = XorRotr(b7, ROTATION_0_3, b6);
+					b6 -= b7;
+				}
+
+				/*
+	             * First subkey uninjection.
+	             */
+				b0 -= kw[0];
+				b1 -= kw[1];
+				b2 -= kw[2];
+				b3 -= kw[3];
+				b4 -= kw[4];
+				b5 -= kw[5] + t[0];
+				b6 -= kw[6] + t[1];
+				b7 -= kw[7];
+
+				/*
+	             * Output cipher state.
+	             */
+				state[0] = b0;
+				state[1] = b1;
+				state[2] = b2;
+				state[3] = b3;
+				state[4] = b4;
+				state[5] = b5;
+				state[6] = b6;
+				state[7] = b7;
+			}
+		}
+
+		private sealed class Threefish1024Cipher
+			: ThreefishCipher
+		{
+			/**
+	         * Mix rotation constants defined in Skein 1.3 specification
+	         */
+			private const int ROTATION_0_0 = 24, ROTATION_0_1 = 13, ROTATION_0_2 = 8, ROTATION_0_3 = 47;
+			private const int ROTATION_0_4 = 8, ROTATION_0_5 = 17, ROTATION_0_6 = 22, ROTATION_0_7 = 37;
+			private const int ROTATION_1_0 = 38, ROTATION_1_1 = 19, ROTATION_1_2 = 10, ROTATION_1_3 = 55;
+			private const int ROTATION_1_4 = 49, ROTATION_1_5 = 18, ROTATION_1_6 = 23, ROTATION_1_7 = 52;
+			private const int ROTATION_2_0 = 33, ROTATION_2_1 = 4, ROTATION_2_2 = 51, ROTATION_2_3 = 13;
+			private const int ROTATION_2_4 = 34, ROTATION_2_5 = 41, ROTATION_2_6 = 59, ROTATION_2_7 = 17;
+			private const int ROTATION_3_0 = 5, ROTATION_3_1 = 20, ROTATION_3_2 = 48, ROTATION_3_3 = 41;
+			private const int ROTATION_3_4 = 47, ROTATION_3_5 = 28, ROTATION_3_6 = 16, ROTATION_3_7 = 25;
+
+			private const int ROTATION_4_0 = 41, ROTATION_4_1 = 9, ROTATION_4_2 = 37, ROTATION_4_3 = 31;
+			private const int ROTATION_4_4 = 12, ROTATION_4_5 = 47, ROTATION_4_6 = 44, ROTATION_4_7 = 30;
+			private const int ROTATION_5_0 = 16, ROTATION_5_1 = 34, ROTATION_5_2 = 56, ROTATION_5_3 = 51;
+			private const int ROTATION_5_4 = 4, ROTATION_5_5 = 53, ROTATION_5_6 = 42, ROTATION_5_7 = 41;
+			private const int ROTATION_6_0 = 31, ROTATION_6_1 = 44, ROTATION_6_2 = 47, ROTATION_6_3 = 46;
+			private const int ROTATION_6_4 = 19, ROTATION_6_5 = 42, ROTATION_6_6 = 44, ROTATION_6_7 = 25;
+			private const int ROTATION_7_0 = 9, ROTATION_7_1 = 48, ROTATION_7_2 = 35, ROTATION_7_3 = 52;
+			private const int ROTATION_7_4 = 23, ROTATION_7_5 = 31, ROTATION_7_6 = 37, ROTATION_7_7 = 20;
+
+			public Threefish1024Cipher(ulong[] kw, ulong[] t)
+				: base(kw, t)
+			{
+			}
+
+			internal override void EncryptBlock(ulong[] block, ulong[] outWords)
+			{
+				ulong[] kw = this.kw;
+				ulong[] t = this.t;
+				int[] mod17 = MOD17;
+				int[] mod3 = MOD3;
+
+				/* Help the JIT avoid index bounds checks */
+				if (kw.Length != 33)
+				{
+					throw new ArgumentException();
+				}
+				if (t.Length != 5)
+				{
+					throw new ArgumentException();
+				}
+
+				/*
+	             * Read 16 words of plaintext data, not using arrays for cipher state
+	             */
+				ulong b0 = block[0];
+				ulong b1 = block[1];
+				ulong b2 = block[2];
+				ulong b3 = block[3];
+				ulong b4 = block[4];
+				ulong b5 = block[5];
+				ulong b6 = block[6];
+				ulong b7 = block[7];
+				ulong b8 = block[8];
+				ulong b9 = block[9];
+				ulong b10 = block[10];
+				ulong b11 = block[11];
+				ulong b12 = block[12];
+				ulong b13 = block[13];
+				ulong b14 = block[14];
+				ulong b15 = block[15];
+
+				/*
+	             * First subkey injection.
+	             */
+				b0 += kw[0];
+				b1 += kw[1];
+				b2 += kw[2];
+				b3 += kw[3];
+				b4 += kw[4];
+				b5 += kw[5];
+				b6 += kw[6];
+				b7 += kw[7];
+				b8 += kw[8];
+				b9 += kw[9];
+				b10 += kw[10];
+				b11 += kw[11];
+				b12 += kw[12];
+				b13 += kw[13] + t[0];
+				b14 += kw[14] + t[1];
+				b15 += kw[15];
+
+				/*
+	             * Rounds loop, unrolled to 8 rounds per iteration.
+	             * 
+	             * Unrolling to multiples of 4 avoids the mod 4 check for key injection, and allows
+	             * inlining of the permutations, which cycle every of 4 rounds (avoiding array
+	             * index/lookup).
+	             * 
+	             * Unrolling to multiples of 8 avoids the mod 8 rotation constant lookup, and allows
+	             * inlining constant rotation values (avoiding array index/lookup).
+	             */
+
+				for (int d = 1; d < (ROUNDS_1024 / 4); d += 2)
+				{
+					int dm17 = mod17[d];
+					int dm3 = mod3[d];
+
+					/*
+	                 * 4 rounds of mix and permute.
+	                 * 
+	                 * Permute schedule has a 4 round cycle, so permutes are inlined in the mix
+	                 * operations in each 4 round block.
+	                 */
+					b1 = RotlXor(b1, ROTATION_0_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_0_1, b2 += b3);
+					b5 = RotlXor(b5, ROTATION_0_2, b4 += b5);
+					b7 = RotlXor(b7, ROTATION_0_3, b6 += b7);
+					b9 = RotlXor(b9, ROTATION_0_4, b8 += b9);
+					b11 = RotlXor(b11, ROTATION_0_5, b10 += b11);
+					b13 = RotlXor(b13, ROTATION_0_6, b12 += b13);
+					b15 = RotlXor(b15, ROTATION_0_7, b14 += b15);
+
+					b9 = RotlXor(b9, ROTATION_1_0, b0 += b9);
+					b13 = RotlXor(b13, ROTATION_1_1, b2 += b13);
+					b11 = RotlXor(b11, ROTATION_1_2, b6 += b11);
+					b15 = RotlXor(b15, ROTATION_1_3, b4 += b15);
+					b7 = RotlXor(b7, ROTATION_1_4, b10 += b7);
+					b3 = RotlXor(b3, ROTATION_1_5, b12 += b3);
+					b5 = RotlXor(b5, ROTATION_1_6, b14 += b5);
+					b1 = RotlXor(b1, ROTATION_1_7, b8 += b1);
+
+					b7 = RotlXor(b7, ROTATION_2_0, b0 += b7);
+					b5 = RotlXor(b5, ROTATION_2_1, b2 += b5);
+					b3 = RotlXor(b3, ROTATION_2_2, b4 += b3);
+					b1 = RotlXor(b1, ROTATION_2_3, b6 += b1);
+					b15 = RotlXor(b15, ROTATION_2_4, b12 += b15);
+					b13 = RotlXor(b13, ROTATION_2_5, b14 += b13);
+					b11 = RotlXor(b11, ROTATION_2_6, b8 += b11);
+					b9 = RotlXor(b9, ROTATION_2_7, b10 += b9);
+
+					b15 = RotlXor(b15, ROTATION_3_0, b0 += b15);
+					b11 = RotlXor(b11, ROTATION_3_1, b2 += b11);
+					b13 = RotlXor(b13, ROTATION_3_2, b6 += b13);
+					b9 = RotlXor(b9, ROTATION_3_3, b4 += b9);
+					b1 = RotlXor(b1, ROTATION_3_4, b14 += b1);
+					b5 = RotlXor(b5, ROTATION_3_5, b8 += b5);
+					b3 = RotlXor(b3, ROTATION_3_6, b10 += b3);
+					b7 = RotlXor(b7, ROTATION_3_7, b12 += b7);
+
+					/*
+	                 * Subkey injection for first 4 rounds.
+	                 */
+					b0 += kw[dm17];
+					b1 += kw[dm17 + 1];
+					b2 += kw[dm17 + 2];
+					b3 += kw[dm17 + 3];
+					b4 += kw[dm17 + 4];
+					b5 += kw[dm17 + 5];
+					b6 += kw[dm17 + 6];
+					b7 += kw[dm17 + 7];
+					b8 += kw[dm17 + 8];
+					b9 += kw[dm17 + 9];
+					b10 += kw[dm17 + 10];
+					b11 += kw[dm17 + 11];
+					b12 += kw[dm17 + 12];
+					b13 += kw[dm17 + 13] + t[dm3];
+					b14 += kw[dm17 + 14] + t[dm3 + 1];
+					b15 += kw[dm17 + 15] + (uint)d;
+
+					/*
+	                 * 4 more rounds of mix/permute
+	                 */
+					b1 = RotlXor(b1, ROTATION_4_0, b0 += b1);
+					b3 = RotlXor(b3, ROTATION_4_1, b2 += b3);
+					b5 = RotlXor(b5, ROTATION_4_2, b4 += b5);
+					b7 = RotlXor(b7, ROTATION_4_3, b6 += b7);
+					b9 = RotlXor(b9, ROTATION_4_4, b8 += b9);
+					b11 = RotlXor(b11, ROTATION_4_5, b10 += b11);
+					b13 = RotlXor(b13, ROTATION_4_6, b12 += b13);
+					b15 = RotlXor(b15, ROTATION_4_7, b14 += b15);
+
+					b9 = RotlXor(b9, ROTATION_5_0, b0 += b9);
+					b13 = RotlXor(b13, ROTATION_5_1, b2 += b13);
+					b11 = RotlXor(b11, ROTATION_5_2, b6 += b11);
+					b15 = RotlXor(b15, ROTATION_5_3, b4 += b15);
+					b7 = RotlXor(b7, ROTATION_5_4, b10 += b7);
+					b3 = RotlXor(b3, ROTATION_5_5, b12 += b3);
+					b5 = RotlXor(b5, ROTATION_5_6, b14 += b5);
+					b1 = RotlXor(b1, ROTATION_5_7, b8 += b1);
+
+					b7 = RotlXor(b7, ROTATION_6_0, b0 += b7);
+					b5 = RotlXor(b5, ROTATION_6_1, b2 += b5);
+					b3 = RotlXor(b3, ROTATION_6_2, b4 += b3);
+					b1 = RotlXor(b1, ROTATION_6_3, b6 += b1);
+					b15 = RotlXor(b15, ROTATION_6_4, b12 += b15);
+					b13 = RotlXor(b13, ROTATION_6_5, b14 += b13);
+					b11 = RotlXor(b11, ROTATION_6_6, b8 += b11);
+					b9 = RotlXor(b9, ROTATION_6_7, b10 += b9);
+
+					b15 = RotlXor(b15, ROTATION_7_0, b0 += b15);
+					b11 = RotlXor(b11, ROTATION_7_1, b2 += b11);
+					b13 = RotlXor(b13, ROTATION_7_2, b6 += b13);
+					b9 = RotlXor(b9, ROTATION_7_3, b4 += b9);
+					b1 = RotlXor(b1, ROTATION_7_4, b14 += b1);
+					b5 = RotlXor(b5, ROTATION_7_5, b8 += b5);
+					b3 = RotlXor(b3, ROTATION_7_6, b10 += b3);
+					b7 = RotlXor(b7, ROTATION_7_7, b12 += b7);
+
+					/*
+	                 * Subkey injection for next 4 rounds.
+	                 */
+					b0 += kw[dm17 + 1];
+					b1 += kw[dm17 + 2];
+					b2 += kw[dm17 + 3];
+					b3 += kw[dm17 + 4];
+					b4 += kw[dm17 + 5];
+					b5 += kw[dm17 + 6];
+					b6 += kw[dm17 + 7];
+					b7 += kw[dm17 + 8];
+					b8 += kw[dm17 + 9];
+					b9 += kw[dm17 + 10];
+					b10 += kw[dm17 + 11];
+					b11 += kw[dm17 + 12];
+					b12 += kw[dm17 + 13];
+					b13 += kw[dm17 + 14] + t[dm3 + 1];
+					b14 += kw[dm17 + 15] + t[dm3 + 2];
+					b15 += kw[dm17 + 16] + (uint)d + 1;
+
+				}
+
+				/*
+	             * Output cipher state.
+	             */
+				outWords[0] = b0;
+				outWords[1] = b1;
+				outWords[2] = b2;
+				outWords[3] = b3;
+				outWords[4] = b4;
+				outWords[5] = b5;
+				outWords[6] = b6;
+				outWords[7] = b7;
+				outWords[8] = b8;
+				outWords[9] = b9;
+				outWords[10] = b10;
+				outWords[11] = b11;
+				outWords[12] = b12;
+				outWords[13] = b13;
+				outWords[14] = b14;
+				outWords[15] = b15;
+			}
+
+			internal override void DecryptBlock(ulong[] block, ulong[] state)
+			{
+				ulong[] kw = this.kw;
+				ulong[] t = this.t;
+				int[] mod17 = MOD17;
+				int[] mod3 = MOD3;
+
+				/* Help the JIT avoid index bounds checks */
+				if (kw.Length != 33)
+				{
+					throw new ArgumentException();
+				}
+				if (t.Length != 5)
+				{
+					throw new ArgumentException();
+				}
+
+				ulong b0 = block[0];
+				ulong b1 = block[1];
+				ulong b2 = block[2];
+				ulong b3 = block[3];
+				ulong b4 = block[4];
+				ulong b5 = block[5];
+				ulong b6 = block[6];
+				ulong b7 = block[7];
+				ulong b8 = block[8];
+				ulong b9 = block[9];
+				ulong b10 = block[10];
+				ulong b11 = block[11];
+				ulong b12 = block[12];
+				ulong b13 = block[13];
+				ulong b14 = block[14];
+				ulong b15 = block[15];
+
+				for (int d = (ROUNDS_1024 / 4) - 1; d >= 1; d -= 2)
+				{
+					int dm17 = mod17[d];
+					int dm3 = mod3[d];
+
+					/* Reverse key injection for second 4 rounds */
+					b0 -= kw[dm17 + 1];
+					b1 -= kw[dm17 + 2];
+					b2 -= kw[dm17 + 3];
+					b3 -= kw[dm17 + 4];
+					b4 -= kw[dm17 + 5];
+					b5 -= kw[dm17 + 6];
+					b6 -= kw[dm17 + 7];
+					b7 -= kw[dm17 + 8];
+					b8 -= kw[dm17 + 9];
+					b9 -= kw[dm17 + 10];
+					b10 -= kw[dm17 + 11];
+					b11 -= kw[dm17 + 12];
+					b12 -= kw[dm17 + 13];
+					b13 -= kw[dm17 + 14] + t[dm3 + 1];
+					b14 -= kw[dm17 + 15] + t[dm3 + 2];
+					b15 -= kw[dm17 + 16] + (uint)d + 1;
+
+					/* Reverse second 4 mix/permute rounds */
+					b15 = XorRotr(b15, ROTATION_7_0, b0);
+					b0 -= b15;
+					b11 = XorRotr(b11, ROTATION_7_1, b2);
+					b2 -= b11;
+					b13 = XorRotr(b13, ROTATION_7_2, b6);
+					b6 -= b13;
+					b9 = XorRotr(b9, ROTATION_7_3, b4);
+					b4 -= b9;
+					b1 = XorRotr(b1, ROTATION_7_4, b14);
+					b14 -= b1;
+					b5 = XorRotr(b5, ROTATION_7_5, b8);
+					b8 -= b5;
+					b3 = XorRotr(b3, ROTATION_7_6, b10);
+					b10 -= b3;
+					b7 = XorRotr(b7, ROTATION_7_7, b12);
+					b12 -= b7;
+
+					b7 = XorRotr(b7, ROTATION_6_0, b0);
+					b0 -= b7;
+					b5 = XorRotr(b5, ROTATION_6_1, b2);
+					b2 -= b5;
+					b3 = XorRotr(b3, ROTATION_6_2, b4);
+					b4 -= b3;
+					b1 = XorRotr(b1, ROTATION_6_3, b6);
+					b6 -= b1;
+					b15 = XorRotr(b15, ROTATION_6_4, b12);
+					b12 -= b15;
+					b13 = XorRotr(b13, ROTATION_6_5, b14);
+					b14 -= b13;
+					b11 = XorRotr(b11, ROTATION_6_6, b8);
+					b8 -= b11;
+					b9 = XorRotr(b9, ROTATION_6_7, b10);
+					b10 -= b9;
+
+					b9 = XorRotr(b9, ROTATION_5_0, b0);
+					b0 -= b9;
+					b13 = XorRotr(b13, ROTATION_5_1, b2);
+					b2 -= b13;
+					b11 = XorRotr(b11, ROTATION_5_2, b6);
+					b6 -= b11;
+					b15 = XorRotr(b15, ROTATION_5_3, b4);
+					b4 -= b15;
+					b7 = XorRotr(b7, ROTATION_5_4, b10);
+					b10 -= b7;
+					b3 = XorRotr(b3, ROTATION_5_5, b12);
+					b12 -= b3;
+					b5 = XorRotr(b5, ROTATION_5_6, b14);
+					b14 -= b5;
+					b1 = XorRotr(b1, ROTATION_5_7, b8);
+					b8 -= b1;
+
+					b1 = XorRotr(b1, ROTATION_4_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_4_1, b2);
+					b2 -= b3;
+					b5 = XorRotr(b5, ROTATION_4_2, b4);
+					b4 -= b5;
+					b7 = XorRotr(b7, ROTATION_4_3, b6);
+					b6 -= b7;
+					b9 = XorRotr(b9, ROTATION_4_4, b8);
+					b8 -= b9;
+					b11 = XorRotr(b11, ROTATION_4_5, b10);
+					b10 -= b11;
+					b13 = XorRotr(b13, ROTATION_4_6, b12);
+					b12 -= b13;
+					b15 = XorRotr(b15, ROTATION_4_7, b14);
+					b14 -= b15;
+
+					/* Reverse key injection for first 4 rounds */
+					b0 -= kw[dm17];
+					b1 -= kw[dm17 + 1];
+					b2 -= kw[dm17 + 2];
+					b3 -= kw[dm17 + 3];
+					b4 -= kw[dm17 + 4];
+					b5 -= kw[dm17 + 5];
+					b6 -= kw[dm17 + 6];
+					b7 -= kw[dm17 + 7];
+					b8 -= kw[dm17 + 8];
+					b9 -= kw[dm17 + 9];
+					b10 -= kw[dm17 + 10];
+					b11 -= kw[dm17 + 11];
+					b12 -= kw[dm17 + 12];
+					b13 -= kw[dm17 + 13] + t[dm3];
+					b14 -= kw[dm17 + 14] + t[dm3 + 1];
+					b15 -= kw[dm17 + 15] + (uint)d;
+
+					/* Reverse first 4 mix/permute rounds */
+					b15 = XorRotr(b15, ROTATION_3_0, b0);
+					b0 -= b15;
+					b11 = XorRotr(b11, ROTATION_3_1, b2);
+					b2 -= b11;
+					b13 = XorRotr(b13, ROTATION_3_2, b6);
+					b6 -= b13;
+					b9 = XorRotr(b9, ROTATION_3_3, b4);
+					b4 -= b9;
+					b1 = XorRotr(b1, ROTATION_3_4, b14);
+					b14 -= b1;
+					b5 = XorRotr(b5, ROTATION_3_5, b8);
+					b8 -= b5;
+					b3 = XorRotr(b3, ROTATION_3_6, b10);
+					b10 -= b3;
+					b7 = XorRotr(b7, ROTATION_3_7, b12);
+					b12 -= b7;
+
+					b7 = XorRotr(b7, ROTATION_2_0, b0);
+					b0 -= b7;
+					b5 = XorRotr(b5, ROTATION_2_1, b2);
+					b2 -= b5;
+					b3 = XorRotr(b3, ROTATION_2_2, b4);
+					b4 -= b3;
+					b1 = XorRotr(b1, ROTATION_2_3, b6);
+					b6 -= b1;
+					b15 = XorRotr(b15, ROTATION_2_4, b12);
+					b12 -= b15;
+					b13 = XorRotr(b13, ROTATION_2_5, b14);
+					b14 -= b13;
+					b11 = XorRotr(b11, ROTATION_2_6, b8);
+					b8 -= b11;
+					b9 = XorRotr(b9, ROTATION_2_7, b10);
+					b10 -= b9;
+
+					b9 = XorRotr(b9, ROTATION_1_0, b0);
+					b0 -= b9;
+					b13 = XorRotr(b13, ROTATION_1_1, b2);
+					b2 -= b13;
+					b11 = XorRotr(b11, ROTATION_1_2, b6);
+					b6 -= b11;
+					b15 = XorRotr(b15, ROTATION_1_3, b4);
+					b4 -= b15;
+					b7 = XorRotr(b7, ROTATION_1_4, b10);
+					b10 -= b7;
+					b3 = XorRotr(b3, ROTATION_1_5, b12);
+					b12 -= b3;
+					b5 = XorRotr(b5, ROTATION_1_6, b14);
+					b14 -= b5;
+					b1 = XorRotr(b1, ROTATION_1_7, b8);
+					b8 -= b1;
+
+					b1 = XorRotr(b1, ROTATION_0_0, b0);
+					b0 -= b1;
+					b3 = XorRotr(b3, ROTATION_0_1, b2);
+					b2 -= b3;
+					b5 = XorRotr(b5, ROTATION_0_2, b4);
+					b4 -= b5;
+					b7 = XorRotr(b7, ROTATION_0_3, b6);
+					b6 -= b7;
+					b9 = XorRotr(b9, ROTATION_0_4, b8);
+					b8 -= b9;
+					b11 = XorRotr(b11, ROTATION_0_5, b10);
+					b10 -= b11;
+					b13 = XorRotr(b13, ROTATION_0_6, b12);
+					b12 -= b13;
+					b15 = XorRotr(b15, ROTATION_0_7, b14);
+					b14 -= b15;
+				}
+
+				/*
+	             * First subkey uninjection.
+	             */
+				b0 -= kw[0];
+				b1 -= kw[1];
+				b2 -= kw[2];
+				b3 -= kw[3];
+				b4 -= kw[4];
+				b5 -= kw[5];
+				b6 -= kw[6];
+				b7 -= kw[7];
+				b8 -= kw[8];
+				b9 -= kw[9];
+				b10 -= kw[10];
+				b11 -= kw[11];
+				b12 -= kw[12];
+				b13 -= kw[13] + t[0];
+				b14 -= kw[14] + t[1];
+				b15 -= kw[15];
+
+				/*
+	             * Output cipher state.
+	             */
+				state[0] = b0;
+				state[1] = b1;
+				state[2] = b2;
+				state[3] = b3;
+				state[4] = b4;
+				state[5] = b5;
+				state[6] = b6;
+				state[7] = b7;
+				state[8] = b8;
+				state[9] = b9;
+				state[10] = b10;
+				state[11] = b11;
+				state[12] = b12;
+				state[13] = b13;
+				state[14] = b14;
+				state[15] = b15;
+			}
+
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/engines/TwofishEngine.cs b/crypto/src/crypto/engines/TwofishEngine.cs
new file mode 100644
index 000000000..b983d9d31
--- /dev/null
+++ b/crypto/src/crypto/engines/TwofishEngine.cs
@@ -0,0 +1,675 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * 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 sealed class TwofishEngine
+		: IBlockCipher
+    {
+        private static readonly 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 const int P_00 = 1;
+        private const int P_01 = 0;
+        private const int P_02 = 0;
+        private const int P_03 = P_01 ^ 1;
+        private const int P_04 = 1;
+
+        private const int P_10 = 0;
+        private const int P_11 = 0;
+        private const int P_12 = 1;
+        private const int P_13 = P_11 ^ 1;
+        private const int P_14 = 0;
+
+        private const int P_20 = 1;
+        private const int P_21 = 1;
+        private const int P_22 = 0;
+        private const int P_23 = P_21 ^ 1;
+        private const int P_24 = 0;
+
+        private const int P_30 = 0;
+        private const int P_31 = 1;
+        private const int P_32 = 1;
+        private const int P_33 = P_31 ^ 1;
+        private const int P_34 = 1;
+
+        /* Primitive polynomial for GF(256) */
+        private const int GF256_FDBK = 0x169;
+        private const int GF256_FDBK_2 = GF256_FDBK / 2;
+        private const int GF256_FDBK_4 = GF256_FDBK / 4;
+
+        private const int RS_GF_FDBK = 0x14D; // field generator
+
+        //====================================
+        // Useful constants
+        //====================================
+
+        private const int    ROUNDS = 16;
+        private const int    MAX_ROUNDS = 16;  // bytes = 128 bits
+        private const int    BLOCK_SIZE = 16;  // bytes = 128 bits
+        private const int    MAX_KEY_BITS = 256;
+
+        private const int    INPUT_WHITEN=0;
+        private const int    OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
+        private const int    ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
+
+        private const int    TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
+
+        private const int    SK_STEP = 0x02020202;
+        private const int    SK_BUMP = 0x01010101;
+        private const int    SK_ROTL = 9;
+
+        private bool encrypting;
+
+        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;
+
+        private byte[] workingKey;
+
+        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 forEncryption whether or not we are for encryption.
+        * @param parameters the parameters required to set up the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool              forEncryption,
+            ICipherParameters parameters)
+        {
+            if (!(parameters is KeyParameter))
+				throw new ArgumentException("invalid parameter passed to Twofish init - " + parameters.GetType().ToString());
+
+			this.encrypting = forEncryption;
+			this.workingKey = ((KeyParameter)parameters).GetKey();
+			this.k64Cnt = (this.workingKey.Length / 8); // pre-padded ?
+			SetKey(this.workingKey);
+        }
+
+		public string AlgorithmName
+        {
+            get { return "Twofish"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (workingKey == null)
+                throw new InvalidOperationException("Twofish not initialised");
+            if ((inOff + BLOCK_SIZE) > input.Length)
+                throw new DataLengthException("input buffer too short");
+            if ((outOff + BLOCK_SIZE) > output.Length)
+                throw new DataLengthException("output buffer too short");
+
+			if (encrypting)
+            {
+                EncryptBlock(input, inOff, output, outOff);
+            }
+            else
+            {
+                DecryptBlock(input, inOff, output, 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 ArgumentException("Key size less than 64 bits");
+            }
+
+            if (k64Cnt > 4)
+            {
+                throw new ArgumentException("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,p=0; i<k64Cnt ; i++)
+            {
+                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 | (int)((uint)B >> 24);
+                A += B;
+                gSubKeys[i*2] = A;
+                A += B;
+                gSubKeys[i*2 + 1] = A << SK_ROTL | (int)((uint)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) ^ M_b0(k0)];
+                        gSBox[i*2+1]     = gMDS1[(P[P_11,b1] & 0xff) ^ M_b1(k0)];
+                        gSBox[i*2+0x200] = gMDS2[(P[P_21,b2] & 0xff) ^ M_b2(k0)];
+                        gSBox[i*2+0x201] = gMDS3[(P[P_31,b3] & 0xff) ^ M_b3(k0)];
+                    break;
+                    case 0: // 256 bits of key
+                        b0 = (P[P_04,b0] & 0xff) ^ M_b0(k3);
+                        b1 = (P[P_14,b1] & 0xff) ^ M_b1(k3);
+                        b2 = (P[P_24,b2] & 0xff) ^ M_b2(k3);
+                        b3 = (P[P_34,b3] & 0xff) ^ M_b3(k3);
+                        // fall through, having pre-processed b[0]..b[3] with k32[3]
+                        goto case 3;
+                    case 3: // 192 bits of key
+                        b0 = (P[P_03,b0] & 0xff) ^ M_b0(k2);
+                        b1 = (P[P_13,b1] & 0xff) ^ M_b1(k2);
+                        b2 = (P[P_23,b2] & 0xff) ^ M_b2(k2);
+                        b3 = (P[P_33,b3] & 0xff) ^ M_b3(k2);
+                        // fall through, having pre-processed b[0]..b[3] with k32[2]
+                        goto case 2;
+                    case 2: // 128 bits of key
+                        gSBox[i * 2] = gMDS0[(P[P_01, (P[P_02, b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)];
+                        gSBox[i*2+1] = gMDS1[(P[P_11,(P[P_12,b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)];
+                        gSBox[i*2+0x200] = gMDS2[(P[P_21,(P[P_22,b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)];
+                        gSBox[i * 2 + 0x201] = gMDS3[(P[P_31, (P[P_32, b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_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 = (int)((uint)x2 >>1) | x2 << 31;
+                x3 = (x3 << 1 | (int) ((uint)x3 >> 31)) ^ (t0 + 2*t1 + gSubKeys[k++]);
+
+                t0 = Fe32_0(x2);
+                t1 = Fe32_3(x3);
+                x0 ^= t0 + t1 + gSubKeys[k++];
+                x0 = (int) ((uint)x0 >>1) | x0 << 31;
+                x1 = (x1 << 1 | (int)((uint)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 | (int)((uint) x0 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
+                x1 = (int) ((uint)x1 >>1) | x1 << 31;
+
+                t0 = Fe32_0(x0);
+                t1 = Fe32_3(x1);
+                x3 ^= t0 + 2*t1 + gSubKeys[k--];
+                x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + gSubKeys[k--]);
+                x3 = (int)((uint)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 = M_b0(x);
+            int b1 = M_b1(x);
+            int b2 = M_b2(x);
+            int b3 = M_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) ^ M_b0(k0)] ^
+                            gMDS1[(P[P_11,b1] & 0xff) ^ M_b1(k0)] ^
+                            gMDS2[(P[P_21,b2] & 0xff) ^ M_b2(k0)] ^
+                            gMDS3[(P[P_31,b3] & 0xff) ^ M_b3(k0)];
+                    break;
+                case 0: /* 256 bits of key */
+                    b0 = (P[P_04,b0] & 0xff) ^ M_b0(k3);
+                    b1 = (P[P_14,b1] & 0xff) ^ M_b1(k3);
+                    b2 = (P[P_24,b2] & 0xff) ^ M_b2(k3);
+                    b3 = (P[P_34,b3] & 0xff) ^ M_b3(k3);
+                    goto case 3;
+                case 3:
+                    b0 = (P[P_03,b0] & 0xff) ^ M_b0(k2);
+                    b1 = (P[P_13,b1] & 0xff) ^ M_b1(k2);
+                    b2 = (P[P_23,b2] & 0xff) ^ M_b2(k2);
+                    b3 = (P[P_33,b3] & 0xff) ^ M_b3(k2);
+                    goto case 2;
+                case 2:
+                    result =
+                    gMDS0[(P[P_01,(P[P_02,b0]&0xff)^M_b0(k1)]&0xff)^M_b0(k0)] ^
+                    gMDS1[(P[P_11,(P[P_12,b1]&0xff)^M_b1(k1)]&0xff)^M_b1(k0)] ^
+                    gMDS2[(P[P_21,(P[P_22,b2]&0xff)^M_b2(k1)]&0xff)^M_b2(k0)] ^
+                    gMDS3[(P[P_31,(P[P_32,b3]&0xff)^M_b3(k1)]&0xff)^M_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
+		* </p>
+        */
+        private  int RS_rem(int x)
+        {
+            int b = (int) (((uint)x >> 24) & 0xff);
+            int g2 = ((b << 1) ^
+                    ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
+            int g3 = ( (int)((uint)b >> 1) ^
+                    ((b & 0x01) != 0 ? (int)((uint)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 M_b0(int x)
+        {
+            return x & 0xff;
+        }
+
+        private  int M_b1(int x)
+        {
+            return (int)((uint)x >> 8) & 0xff;
+        }
+
+        private  int M_b2(int x)
+        {
+            return (int)((uint)x >> 16) & 0xff;
+        }
+
+        private  int M_b3(int x)
+        {
+            return (int)((uint)x >> 24) & 0xff;
+        }
+
+        private  int Fe32_0(int x)
+        {
+            return gSBox[ 0x000 + 2*(x & 0xff) ] ^
+                gSBox[ 0x001 + 2*((int)((uint)x >> 8) & 0xff) ] ^
+                gSBox[ 0x200 + 2*((int)((uint)x >> 16) & 0xff) ] ^
+                gSBox[ 0x201 + 2*((int)((uint)x >> 24) & 0xff) ];
+        }
+
+        private  int Fe32_3(int x)
+        {
+            return gSBox[ 0x000 + 2*((int)((uint)x >> 24) & 0xff) ] ^
+                gSBox[ 0x001 + 2*(x & 0xff) ] ^
+                gSBox[ 0x200 + 2*((int)((uint)x >> 8) & 0xff) ] ^
+                gSBox[ 0x201 + 2*((int)((uint)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 inData,  byte[] b, int offset)
+        {
+            b[offset] = (byte)inData;
+            b[offset + 1] = (byte)(inData >> 8);
+            b[offset + 2] = (byte)(inData >> 16);
+            b[offset + 3] = (byte)(inData >> 24);
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/engines/VMPCEngine.cs b/crypto/src/crypto/engines/VMPCEngine.cs
index d467fbba5..1c2802a80 100644
--- a/crypto/src/crypto/engines/VMPCEngine.cs
+++ b/crypto/src/crypto/engines/VMPCEngine.cs
@@ -4,136 +4,137 @@ using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	public class VmpcEngine
-		: IStreamCipher
-	{
-		/*
-		* variables to hold the state of the VMPC engine during encryption and
-		* decryption
-		*/
-		protected byte n = 0;
-		protected byte[] P = null;
-		protected byte s = 0;
-
-		protected byte[] workingIV;
-		protected byte[] workingKey;
-
-		public virtual string AlgorithmName
-		{
-			get { return "VMPC"; }
-		}
-
-		/**
-		* initialise a VMPC cipher.
-		* 
-		* @param forEncryption
-		*    whether or not we are for encryption.
-		* @param params
-		*    the parameters required to set up the cipher.
-		* @exception ArgumentException
-		*    if the params argument is inappropriate.
-		*/
-		public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			if (!(parameters is ParametersWithIV))
-				throw new ArgumentException("VMPC Init parameters must include an IV");
-
-			ParametersWithIV ivParams = (ParametersWithIV) parameters;
-			KeyParameter key = (KeyParameter) ivParams.Parameters;
-
-			if (!(ivParams.Parameters is KeyParameter))
-				throw new ArgumentException("VMPC Init parameters must include a key");
-
-			this.workingIV = ivParams.GetIV();
-
-			if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
-				throw new ArgumentException("VMPC requires 1 to 768 bytes of IV");
-
-			this.workingKey = key.GetKey();
-
-			InitKey(this.workingKey, this.workingIV);
-		}
-
-		protected virtual void InitKey(
-			byte[]	keyBytes,
-			byte[]	ivBytes)
-		{
-			s = 0;
-			P = new byte[256];
-			for (int i = 0; i < 256; i++)
-			{
-				P[i] = (byte) i;
-			}
-
-			for (int m = 0; m < 768; m++)
-			{
-				s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-			}
-			for (int m = 0; m < 768; m++)
-			{
-				s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
-				byte temp = P[m & 0xff];
-				P[m & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-			}
-			n = 0;
-		}
-
-		public virtual void ProcessBytes(
-			byte[]	input,
-			int		inOff,
-			int		len,
-			byte[]	output,
-			int		outOff)
-		{
-			if ((inOff + len) > input.Length)
-			{
-				throw new DataLengthException("input buffer too short");
-			}
-
-			if ((outOff + len) > output.Length)
-			{
-				throw new DataLengthException("output buffer too short");
-			}
-
-			for (int i = 0; i < len; i++)
-			{
-				s = P[(s + P[n & 0xff]) & 0xff];
-				byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
-				// encryption
-				byte temp = P[n & 0xff];
-				P[n & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-				n = (byte) ((n + 1) & 0xff);
-
-				// xor
-				output[i + outOff] = (byte) (input[i + inOff] ^ z);
-			}
-		}
-
-		public virtual void Reset()
-		{
-			InitKey(this.workingKey, this.workingIV);
-		}
-
-		public virtual byte ReturnByte(
-			byte input)
-		{
-			s = P[(s + P[n & 0xff]) & 0xff];
-			byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
-			// encryption
-			byte temp = P[n & 0xff];
-			P[n & 0xff] = P[s & 0xff];
-			P[s & 0xff] = temp;
-			n = (byte) ((n + 1) & 0xff);
-
-			// xor
-			return (byte) (input ^ z);
-		}
-	}
+    public class VmpcEngine
+        : IStreamCipher
+    {
+        /*
+        * variables to hold the state of the VMPC engine during encryption and
+        * decryption
+        */
+        protected byte n = 0;
+        protected byte[] P = null;
+        protected byte s = 0;
+
+        protected byte[] workingIV;
+        protected byte[] workingKey;
+
+        public virtual string AlgorithmName
+        {
+            get { return "VMPC"; }
+        }
+
+        /**
+        * initialise a VMPC cipher.
+        * 
+        * @param forEncryption
+        *    whether or not we are for encryption.
+        * @param params
+        *    the parameters required to set up the cipher.
+        * @exception ArgumentException
+        *    if the params argument is inappropriate.
+        */
+        public virtual void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            if (!(parameters is ParametersWithIV))
+                throw new ArgumentException("VMPC Init parameters must include an IV");
+
+            ParametersWithIV ivParams = (ParametersWithIV) parameters;
+
+            if (!(ivParams.Parameters is KeyParameter))
+                throw new ArgumentException("VMPC Init parameters must include a key");
+
+            KeyParameter key = (KeyParameter)ivParams.Parameters;
+
+            this.workingIV = ivParams.GetIV();
+
+            if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
+                throw new ArgumentException("VMPC requires 1 to 768 bytes of IV");
+
+            this.workingKey = key.GetKey();
+
+            InitKey(this.workingKey, this.workingIV);
+        }
+
+        protected virtual void InitKey(
+            byte[]	keyBytes,
+            byte[]	ivBytes)
+        {
+            s = 0;
+            P = new byte[256];
+            for (int i = 0; i < 256; i++)
+            {
+                P[i] = (byte) i;
+            }
+
+            for (int m = 0; m < 768; m++)
+            {
+                s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+                byte temp = P[m & 0xff];
+                P[m & 0xff] = P[s & 0xff];
+                P[s & 0xff] = temp;
+            }
+            for (int m = 0; m < 768; m++)
+            {
+                s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+                byte temp = P[m & 0xff];
+                P[m & 0xff] = P[s & 0xff];
+                P[s & 0xff] = temp;
+            }
+            n = 0;
+        }
+
+        public virtual void ProcessBytes(
+            byte[]	input,
+            int		inOff,
+            int		len,
+            byte[]	output,
+            int		outOff)
+        {
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + len) > output.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            for (int i = 0; i < len; i++)
+            {
+                s = P[(s + P[n & 0xff]) & 0xff];
+                byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+                // encryption
+                byte temp = P[n & 0xff];
+                P[n & 0xff] = P[s & 0xff];
+                P[s & 0xff] = temp;
+                n = (byte) ((n + 1) & 0xff);
+
+                // xor
+                output[i + outOff] = (byte) (input[i + inOff] ^ z);
+            }
+        }
+
+        public virtual void Reset()
+        {
+            InitKey(this.workingKey, this.workingIV);
+        }
+
+        public virtual byte ReturnByte(
+            byte input)
+        {
+            s = P[(s + P[n & 0xff]) & 0xff];
+            byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+            // encryption
+            byte temp = P[n & 0xff];
+            P[n & 0xff] = P[s & 0xff];
+            P[s & 0xff] = temp;
+            n = (byte) ((n + 1) & 0xff);
+
+            // xor
+            return (byte) (input ^ z);
+        }
+    }
 }
diff --git a/crypto/src/crypto/engines/VMPCKSA3Engine.cs b/crypto/src/crypto/engines/VMPCKSA3Engine.cs
new file mode 100644
index 000000000..95b6813b7
--- /dev/null
+++ b/crypto/src/crypto/engines/VMPCKSA3Engine.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	public class VmpcKsa3Engine
+		: VmpcEngine
+	{
+		public override string AlgorithmName
+		{
+			get { return "VMPC-KSA3"; }
+		}
+
+		protected override void InitKey(
+			byte[]	keyBytes,
+			byte[]	ivBytes)
+		{
+			s = 0;
+			P = new byte[256];
+			for (int i = 0; i < 256; i++)
+			{
+				P[i] = (byte) i;
+			}
+
+			for (int m = 0; m < 768; m++)
+			{
+				s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+				byte temp = P[m & 0xff];
+				P[m & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+
+			for (int m = 0; m < 768; m++)
+			{
+				s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+				byte temp = P[m & 0xff];
+				P[m & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+
+			for (int m = 0; m < 768; m++)
+			{
+				s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+				byte temp = P[m & 0xff];
+				P[m & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+
+			n = 0;
+		}
+	}
+}
diff --git a/crypto/src/crypto/engines/XSalsa20Engine.cs b/crypto/src/crypto/engines/XSalsa20Engine.cs
new file mode 100644
index 000000000..fc6630905
--- /dev/null
+++ b/crypto/src/crypto/engines/XSalsa20Engine.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <summary>
+	/// Implementation of Daniel J. Bernstein's XSalsa20 stream cipher - Salsa20 with an extended nonce.
+	/// </summary>
+	/// <remarks>
+	/// XSalsa20 requires a 256 bit key, and a 192 bit nonce.
+	/// </remarks>
+	public class XSalsa20Engine 
+		: Salsa20Engine
+	{
+
+		public override string AlgorithmName
+		{
+			get { return "XSalsa20"; }
+		}
+
+		protected override int NonceSize
+		{
+			get { return 24; }
+		}
+
+		/// <summary>
+		/// XSalsa20 key generation: process 256 bit input key and 128 bits of the input nonce
+		/// using a core Salsa20 function without input addition to produce 256 bit working key
+		/// and use that with the remaining 64 bits of nonce to initialize a standard Salsa20 engine state.
+		/// </summary>
+		protected override void SetKey(byte[] keyBytes, byte[] ivBytes)
+		{
+			if (keyBytes.Length != 32)
+			{
+				throw new ArgumentException(AlgorithmName + " requires a 256 bit key");
+			}
+
+			// Set key for HSalsa20
+			base.SetKey(keyBytes, ivBytes);
+
+			// Pack next 64 bits of IV into engine state instead of counter
+			engineState[8] = Pack.LE_To_UInt32(ivBytes, 8);
+			engineState[9] = Pack.LE_To_UInt32(ivBytes, 12);
+
+			// Process engine state to generate Salsa20 key
+			uint[] hsalsa20Out = new uint[engineState.Length];
+			SalsaCore(20, engineState, hsalsa20Out);
+
+			// Set new key, removing addition in last round of salsaCore
+			engineState[1] = hsalsa20Out[0] - engineState[0];
+			engineState[2] = hsalsa20Out[5] - engineState[5];
+			engineState[3] = hsalsa20Out[10] - engineState[10];
+			engineState[4] = hsalsa20Out[15] - engineState[15];
+
+			engineState[11] = hsalsa20Out[6] - engineState[6];
+			engineState[12] = hsalsa20Out[7] - engineState[7];
+			engineState[13] = hsalsa20Out[8] - engineState[8];
+			engineState[14] = hsalsa20Out[9] - engineState[9];
+
+			// Last 64 bits of input IV
+			engineState[6] = Pack.LE_To_UInt32(ivBytes, 16);
+			engineState[7] = Pack.LE_To_UInt32(ivBytes, 20);
+
+			// Counter reset
+			ResetCounter();
+		}
+
+	}
+}
+
diff --git a/crypto/src/crypto/engines/XTEAEngine.cs b/crypto/src/crypto/engines/XTEAEngine.cs
new file mode 100644
index 000000000..eb9291775
--- /dev/null
+++ b/crypto/src/crypto/engines/XTEAEngine.cs
@@ -0,0 +1,168 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* An XTEA engine.
+	*/
+	public class XteaEngine
+		: IBlockCipher
+	{
+		private const int
+			rounds		= 32,
+			block_size	= 8,
+//			key_size	= 16,
+			delta		= unchecked((int) 0x9E3779B9);
+
+		/*
+		* the expanded key array of 4 subkeys
+		*/
+		private uint[] _S = new uint[4],
+			_sum0 = new uint[32],
+			_sum1 = new uint[32];
+		private bool _initialised, _forEncryption;
+
+		/**
+		* Create an instance of the TEA encryption algorithm
+		* and set some defaults
+		*/
+		public XteaEngine()
+		{
+			_initialised = false;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "XTEA"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return block_size;
+		}
+
+		/**
+		* initialise
+		*
+		* @param forEncryption whether or not we are for encryption.
+		* @param params the parameters required to set up the cipher.
+		* @exception ArgumentException if the params argument is
+		* inappropriate.
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			if (!(parameters is KeyParameter))
+			{
+				throw new ArgumentException("invalid parameter passed to TEA init - "
+					+ parameters.GetType().FullName);
+			}
+
+			_forEncryption = forEncryption;
+			_initialised = true;
+
+			KeyParameter p = (KeyParameter) parameters;
+
+			setKey(p.GetKey());
+		}
+
+		public int ProcessBlock(
+			byte[]	inBytes,
+			int		inOff,
+			byte[]	outBytes,
+			int		outOff)
+		{
+			if (!_initialised)
+				throw new InvalidOperationException(AlgorithmName + " not initialised");
+
+			if ((inOff + block_size) > inBytes.Length)
+				throw new DataLengthException("input buffer too short");
+
+			if ((outOff + block_size) > outBytes.Length)
+				throw new DataLengthException("output buffer too short");
+
+			return _forEncryption
+				?	encryptBlock(inBytes, inOff, outBytes, outOff)
+				:	decryptBlock(inBytes, inOff, outBytes, outOff);
+		}
+
+		public void Reset()
+		{
+		}
+
+		/**
+		* Re-key the cipher.
+		*
+		* @param  key  the key to be used
+		*/
+		private void setKey(
+			byte[] key)
+		{
+			int i, j;
+			for (i = j = 0; i < 4; i++,j+=4)
+			{
+				_S[i] = Pack.BE_To_UInt32(key, j);
+			}
+
+			for (i = j = 0; i < rounds; i++)
+			{
+				_sum0[i] = ((uint)j + _S[j & 3]);
+				j += delta;
+				_sum1[i] = ((uint)j + _S[j >> 11 & 3]);
+			}
+		}
+
+		private int encryptBlock(
+			byte[]  inBytes,
+			int     inOff,
+			byte[]  outBytes,
+			int     outOff)
+		{
+			// Pack bytes into integers
+			uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
+			uint v1 = Pack.BE_To_UInt32(inBytes, inOff + 4);
+
+			for (int i = 0; i < rounds; i++)
+			{
+				v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ _sum0[i];
+				v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ _sum1[i];
+			}
+
+			Pack.UInt32_To_BE(v0, outBytes, outOff);
+			Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+			return block_size;
+		}
+
+		private int decryptBlock(
+			byte[]	inBytes,
+			int		inOff,
+			byte[]	outBytes,
+			int		outOff)
+		{
+			// Pack bytes into integers
+			uint v0 = Pack.BE_To_UInt32(inBytes, inOff);
+			uint v1 = Pack.BE_To_UInt32(inBytes, inOff + 4);
+
+			for (int i = rounds-1; i >= 0; i--)
+			{
+				v1  -= ((v0 << 4 ^ v0 >> 5) + v0) ^ _sum1[i];
+				v0  -= ((v1 << 4 ^ v1 >> 5) + v1) ^ _sum0[i];
+			}
+
+			Pack.UInt32_To_BE(v0, outBytes, outOff);
+			Pack.UInt32_To_BE(v1, outBytes, outOff + 4);
+
+			return block_size;
+		}
+	}
+}
diff --git a/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs b/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
index 0366401d1..bca420711 100644
--- a/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
+++ b/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
@@ -2,140 +2,131 @@ using System;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	/**
-	* Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
-	* <br/>
-	* This implementation is based on ISO 18033/P1363a.
-	*/
-	public class BaseKdfBytesGenerator
-		: IDerivationFunction
-	{
-		private int     counterStart;
-		private IDigest  digest;
-		private byte[]  shared;
-		private byte[]  iv;
-
-		/**
-		* Construct a KDF Parameters generator.
-		*
-		* @param counterStart value of counter.
-		* @param digest the digest to be used as the source of derived keys.
-		*/
-		protected BaseKdfBytesGenerator(
-			int     counterStart,
-			IDigest  digest)
-		{
-			this.counterStart = counterStart;
-			this.digest = digest;
-		}
-
-		public void Init(
-			IDerivationParameters    parameters)
-		{
-			if (parameters is KdfParameters)
-			{
-				KdfParameters   p = (KdfParameters)parameters;
-
-				shared = p.GetSharedSecret();
-				iv = p.GetIV();
-			}
-			else if (parameters is Iso18033KdfParameters)
-			{
-				Iso18033KdfParameters p = (Iso18033KdfParameters)parameters;
-
-				shared = p.GetSeed();
-				iv = null;
-			}
-			else
-			{
-				throw new ArgumentException("KDF parameters required for KDF Generator");
-			}
-		}
-
-		/**
-		* return the underlying digest.
-		*/
-		public IDigest Digest
-		{
-			get
-			{
-				return digest;
-			}
-		}
-
-		/**
-		* fill len bytes of the output buffer with bytes generated from
-		* the derivation function.
-		*
-		* @throws ArgumentException if the size of the request will cause an overflow.
-		* @throws DataLengthException if the out buffer is too small.
-		*/
-		public int GenerateBytes(
-			byte[]  output,
-			int     outOff,
-			int     length)
-		{
-			if ((output.Length - length) < outOff)
-			{
-				throw new DataLengthException("output buffer too small");
-			}
-
-			long    oBytes = length;
-			int     outLen = digest.GetDigestSize();
-
-			//
-			// this is at odds with the standard implementation, the
-			// maximum value should be hBits * (2^32 - 1) where hBits
-			// is the digest output size in bits. We can't have an
-			// array with a long index at the moment...
-			//
-			if (oBytes > ((2L << 32) - 1))
-			{
-				throw new ArgumentException("Output length too large");
-			}
-
-			int cThreshold = (int)((oBytes + outLen - 1) / outLen);
-
-			byte[] dig = new byte[digest.GetDigestSize()];
-
-			int counter = counterStart;
-
-			for (int i = 0; i < cThreshold; i++)
-			{
-				digest.BlockUpdate(shared, 0, shared.Length);
-
-				digest.Update((byte)(counter >> 24));
-				digest.Update((byte)(counter >> 16));
-				digest.Update((byte)(counter >> 8));
-				digest.Update((byte)counter);
-
-				if (iv != null)
-				{
-					digest.BlockUpdate(iv, 0, iv.Length);
-				}
-
-				digest.DoFinal(dig, 0);
-
-				if (length > outLen)
-				{
-					Array.Copy(dig, 0, output, outOff, outLen);
-					outOff += outLen;
-					length -= outLen;
-				}
-				else
-				{
-					Array.Copy(dig, 0, output, outOff, length);
-				}
-
-				counter++;
-			}
-
-			digest.Reset();
-
-			return (int)oBytes;
-		}
-	}
+    /**
+    * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+    * <br/>
+    * This implementation is based on ISO 18033/P1363a.
+    */
+    public class BaseKdfBytesGenerator
+        : IDerivationFunction
+    {
+        private int     counterStart;
+        private IDigest  digest;
+        private byte[]  shared;
+        private byte[]  iv;
+
+        /**
+        * Construct a KDF Parameters generator.
+        *
+        * @param counterStart value of counter.
+        * @param digest the digest to be used as the source of derived keys.
+        */
+        public BaseKdfBytesGenerator(int counterStart, IDigest digest)
+        {
+            this.counterStart = counterStart;
+            this.digest = digest;
+        }
+
+        public virtual void Init(IDerivationParameters parameters)
+        {
+            if (parameters is KdfParameters)
+            {
+                KdfParameters   p = (KdfParameters)parameters;
+
+                shared = p.GetSharedSecret();
+                iv = p.GetIV();
+            }
+            else if (parameters is Iso18033KdfParameters)
+            {
+                Iso18033KdfParameters p = (Iso18033KdfParameters)parameters;
+
+                shared = p.GetSeed();
+                iv = null;
+            }
+            else
+            {
+                throw new ArgumentException("KDF parameters required for KDF Generator");
+            }
+        }
+
+        /**
+        * return the underlying digest.
+        */
+        public virtual IDigest Digest
+        {
+            get { return digest; }
+        }
+
+        /**
+        * fill len bytes of the output buffer with bytes generated from
+        * the derivation function.
+        *
+        * @throws ArgumentException if the size of the request will cause an overflow.
+        * @throws DataLengthException if the out buffer is too small.
+        */
+        public virtual int GenerateBytes(byte[] output, int outOff, int length)
+        {
+            if ((output.Length - length) < outOff)
+                throw new DataLengthException("output buffer too small");
+
+            long oBytes = length;
+            int outLen = digest.GetDigestSize();
+
+            //
+            // this is at odds with the standard implementation, the
+            // maximum value should be hBits * (2^32 - 1) where hBits
+            // is the digest output size in bits. We can't have an
+            // array with a long index at the moment...
+            //
+            if (oBytes > ((2L << 32) - 1))
+                throw new ArgumentException("Output length too large");
+
+            int cThreshold = (int)((oBytes + outLen - 1) / outLen);
+
+            byte[] dig = new byte[digest.GetDigestSize()];
+
+            byte[] C = new byte[4];
+            Pack.UInt32_To_BE((uint)counterStart, C, 0);
+
+            uint counterBase = (uint)(counterStart & ~0xFF);
+
+            for (int i = 0; i < cThreshold; i++)
+            {
+                digest.BlockUpdate(shared, 0, shared.Length);
+                digest.BlockUpdate(C, 0, 4);
+
+                if (iv != null)
+                {
+                    digest.BlockUpdate(iv, 0, iv.Length);
+                }
+
+                digest.DoFinal(dig, 0);
+
+                if (length > outLen)
+                {
+                    Array.Copy(dig, 0, output, outOff, outLen);
+                    outOff += outLen;
+                    length -= outLen;
+                }
+                else
+                {
+                    Array.Copy(dig, 0, output, outOff, length);
+                }
+
+                if (++C[3] == 0)
+                {
+                    counterBase += 0x100;
+                    Pack.UInt32_To_BE(counterBase, C, 0);
+                }
+            }
+
+            digest.Reset();
+
+            return (int)oBytes;
+        }
+    }
 }
\ No newline at end of file
diff --git a/crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs b/crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs
new file mode 100644
index 000000000..51b3af687
--- /dev/null
+++ b/crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs
@@ -0,0 +1,38 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    /**
+     * a basic Diffie-Hellman key pair generator.
+     *
+     * This generates keys consistent for use with the basic algorithm for
+     * Diffie-Hellman.
+     */
+    public class DHBasicKeyPairGenerator
+		: IAsymmetricCipherKeyPairGenerator
+    {
+        private DHKeyGenerationParameters param;
+
+        public virtual void Init(
+			KeyGenerationParameters parameters)
+        {
+            this.param = (DHKeyGenerationParameters)parameters;
+        }
+
+        public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+			DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+			DHParameters dhp = param.Parameters;
+
+			BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+			BigInteger y = helper.CalculatePublic(dhp, x);
+
+			return new AsymmetricCipherKeyPair(
+                new DHPublicKeyParameters(y, dhp),
+                new DHPrivateKeyParameters(x, dhp));
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs b/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
index 756e8482a..68aba64f7 100644
--- a/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
+++ b/crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
@@ -2,52 +2,71 @@ using System;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	class DHKeyGeneratorHelper
-	{
-		internal static readonly DHKeyGeneratorHelper Instance = new DHKeyGeneratorHelper();
-
-		private DHKeyGeneratorHelper()
-		{
-		}
-
-		internal BigInteger CalculatePrivate(
-			DHParameters	dhParams,
-			SecureRandom	random)
-		{
-			int limit = dhParams.L;
-
-			if (limit != 0)
-			{
-				return new BigInteger(limit, random).SetBit(limit - 1);
-			}
-
-			BigInteger min = BigInteger.Two;
-			int m = dhParams.M;
-			if (m != 0)
-			{
-				min = BigInteger.One.ShiftLeft(m - 1);
-			}
-
-			BigInteger max = dhParams.P.Subtract(BigInteger.Two);
-			BigInteger q = dhParams.Q;
-			if (q != null)
-			{
-				max = q.Subtract(BigInteger.Two);
-			}
-
-			return BigIntegers.CreateRandomInRange(min, max, random);
-		}
-
-		internal BigInteger CalculatePublic(
-			DHParameters	dhParams,
-			BigInteger		x)
-		{
-			return dhParams.G.ModPow(x, dhParams.P);
-		}
-	}
+    class DHKeyGeneratorHelper
+    {
+        internal static readonly DHKeyGeneratorHelper Instance = new DHKeyGeneratorHelper();
+
+        private DHKeyGeneratorHelper()
+        {
+        }
+
+        internal BigInteger CalculatePrivate(
+            DHParameters	dhParams,
+            SecureRandom	random)
+        {
+            int limit = dhParams.L;
+
+            if (limit != 0)
+            {
+                int minWeight = limit >> 2;
+                for (;;)
+                {
+                    BigInteger x = new BigInteger(limit, random).SetBit(limit - 1);
+                    if (WNafUtilities.GetNafWeight(x) >= minWeight)
+                    {
+                        return x;
+                    }
+                }
+            }
+
+            BigInteger min = BigInteger.Two;
+            int m = dhParams.M;
+            if (m != 0)
+            {
+                min = BigInteger.One.ShiftLeft(m - 1);
+            }
+
+            BigInteger q = dhParams.Q;
+            if (q == null)
+            {
+                q = dhParams.P;
+            }
+            BigInteger max = q.Subtract(BigInteger.Two);
+
+            {
+                int minWeight = max.BitLength >> 2;
+                for (;;)
+                {
+                    BigInteger x = BigIntegers.CreateRandomInRange(min, max, random);
+                    if (WNafUtilities.GetNafWeight(x) >= minWeight)
+                    {
+                        return x;
+                    }
+                }
+            }
+        }
+
+        internal BigInteger CalculatePublic(
+            DHParameters	dhParams,
+            BigInteger		x)
+        {
+            return dhParams.G.ModPow(x, dhParams.P);
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/DHKeyPairGenerator.cs b/crypto/src/crypto/generators/DHKeyPairGenerator.cs
new file mode 100644
index 000000000..3bf58ba1b
--- /dev/null
+++ b/crypto/src/crypto/generators/DHKeyPairGenerator.cs
@@ -0,0 +1,38 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    /**
+     * a Diffie-Hellman key pair generator.
+     *
+     * This generates keys consistent for use in the MTI/A0 key agreement protocol
+     * as described in "Handbook of Applied Cryptography", Pages 516-519.
+     */
+    public class DHKeyPairGenerator
+		: IAsymmetricCipherKeyPairGenerator
+    {
+		private DHKeyGenerationParameters param;
+
+		public virtual void Init(
+			KeyGenerationParameters parameters)
+        {
+            this.param = (DHKeyGenerationParameters)parameters;
+        }
+
+		public virtual AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+			DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+			DHParameters dhp = param.Parameters;
+
+			BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+			BigInteger y = helper.CalculatePublic(dhp, x);
+
+			return new AsymmetricCipherKeyPair(
+                new DHPublicKeyParameters(y, dhp),
+                new DHPrivateKeyParameters(x, dhp));
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/DHParametersGenerator.cs b/crypto/src/crypto/generators/DHParametersGenerator.cs
new file mode 100644
index 000000000..e752c8456
--- /dev/null
+++ b/crypto/src/crypto/generators/DHParametersGenerator.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class DHParametersGenerator
+    {
+        private int				size;
+        private int				certainty;
+        private SecureRandom	random;
+
+        public virtual 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...</p>
+         */
+        public virtual 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, BigInteger.Two, null);
+		}
+	}
+}
diff --git a/crypto/src/crypto/generators/DHParametersHelper.cs b/crypto/src/crypto/generators/DHParametersHelper.cs
index 7860cbe33..bf2de2add 100644
--- a/crypto/src/crypto/generators/DHParametersHelper.cs
+++ b/crypto/src/crypto/generators/DHParametersHelper.cs
@@ -1,215 +1,137 @@
 using System;
 
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	internal class DHParametersHelper
-	{
-		// The primes b/w 2 and ~2^10
-		/*
-				3   5   7   11  13  17  19  23  29
-			31  37  41  43  47  53  59  61  67  71
-			73  79  83  89  97  101 103 107 109 113
-			127 131 137 139 149 151 157 163 167 173
-			179 181 191 193 197 199 211 223 227 229
-			233 239 241 251 257 263 269 271 277 281
-			283 293 307 311 313 317 331 337 347 349
-			353 359 367 373 379 383 389 397 401 409
-			419 421 431 433 439 443 449 457 461 463
-			467 479 487 491 499 503 509 521 523 541
-			547 557 563 569 571 577 587 593 599 601
-			607 613 617 619 631 641 643 647 653 659
-			661 673 677 683 691 701 709 719 727 733
-			739 743 751 757 761 769 773 787 797 809
-			811 821 823 827 829 839 853 857 859 863
-			877 881 883 887 907 911 919 929 937 941
-			947 953 967 971 977 983 991 997
-			1009 1013 1019 1021 1031
-		*/
-
-		// Each list has a product < 2^31
-		private static readonly int[][] primeLists = new int[][]
-		{
-			new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
-			new int[]{ 29, 31, 37, 41, 43 },
-			new int[]{ 47, 53, 59, 61, 67 },
-			new int[]{ 71, 73, 79, 83 },
-			new int[]{ 89, 97, 101, 103 },
-
-			new int[]{ 107, 109, 113, 127 },
-			new int[]{ 131, 137, 139, 149 },
-			new int[]{ 151, 157, 163, 167 },
-			new int[]{ 173, 179, 181, 191 },
-			new int[]{ 193, 197, 199, 211 },
-
-			new int[]{ 223, 227, 229 },
-			new int[]{ 233, 239, 241 },
-			new int[]{ 251, 257, 263 },
-			new int[]{ 269, 271, 277 },
-			new int[]{ 281, 283, 293 },
-
-			new int[]{ 307, 311, 313 },
-			new int[]{ 317, 331, 337 },
-			new int[]{ 347, 349, 353 },
-			new int[]{ 359, 367, 373 },
-			new int[]{ 379, 383, 389 },
-
-			new int[]{ 397, 401, 409 },
-			new int[]{ 419, 421, 431 },
-			new int[]{ 433, 439, 443 },
-			new int[]{ 449, 457, 461 },
-			new int[]{ 463, 467, 479 },
-
-			new int[]{ 487, 491, 499 },
-			new int[]{ 503, 509, 521 },
-			new int[]{ 523, 541, 547 },
-			new int[]{ 557, 563, 569 },
-			new int[]{ 571, 577, 587 },
-
-			new int[]{ 593, 599, 601 },
-			new int[]{ 607, 613, 617 },
-			new int[]{ 619, 631, 641 },
-			new int[]{ 643, 647, 653 },
-			new int[]{ 659, 661, 673 },
-
-			new int[]{ 677, 683, 691 },
-			new int[]{ 701, 709, 719 },
-			new int[]{ 727, 733, 739 },
-			new int[]{ 743, 751, 757 },
-			new int[]{ 761, 769, 773 },
-
-			new int[]{ 787, 797, 809 },
-			new int[]{ 811, 821, 823 },
-			new int[]{ 827, 829, 839 },
-			new int[]{ 853, 857, 859 },
-			new int[]{ 863, 877, 881 },
-
-			new int[]{ 883, 887, 907 },
-			new int[]{ 911, 919, 929 },
-			new int[]{ 937, 941, 947 },
-			new int[]{ 953, 967, 971 },
-			new int[]{ 977, 983, 991 },
-
-			new int[]{ 997, 1009, 1013 },
-			new int[]{ 1019, 1021, 1031 },
-		};
-
-		private static readonly BigInteger Six = BigInteger.ValueOf(6);
-
-		private static readonly int[] primeProducts;
-		private static readonly BigInteger[] PrimeProducts;
-
-		static DHParametersHelper()
-		{
-			primeProducts = new int[primeLists.Length];
-			PrimeProducts = new BigInteger[primeLists.Length];
-
-			for (int i = 0; i < primeLists.Length; ++i)
-			{
-				int[] primeList = primeLists[i];
-				int product = 1;
-				for (int j = 0; j < primeList.Length; ++j)
-				{
-					product *= primeList[j];
-				}
-				primeProducts[i] = product;
-				PrimeProducts[i] = BigInteger.ValueOf(product);
-			}
-		}
-
-		/*
-		 * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
-		 * 
-		 * (see: Handbook of Applied Cryptography 4.86)
-		 */
-		internal static BigInteger[] GenerateSafePrimes(int size, int certainty, SecureRandom random)
-		{
-			BigInteger p, q;
-			int qLength = size - 1;
-
-			if (size <= 32)
-			{
-				for (;;)
-				{
-					q = new BigInteger(qLength, 2, random);
-
-					p = q.ShiftLeft(1).Add(BigInteger.One);
-
-					if (p.IsProbablePrime(certainty)
-						&& (certainty <= 2 || q.IsProbablePrime(certainty)))
-							break;
-				}
-			}
-			else
-			{
-				// Note: Modified from Java version for speed
-				for (;;)
-				{
-					q = new BigInteger(qLength, 0, random);
-
-				retry:
-					for (int i = 0; i < primeLists.Length; ++i)
-					{
-						int test = q.Remainder(PrimeProducts[i]).IntValue;
-
-						if (i == 0)
-						{
-							int rem3 = test % 3;
-							if (rem3 != 2)
-							{
-								int diff = 2 * rem3 + 2;
-								q = q.Add(BigInteger.ValueOf(diff));
-								test = (test + diff) % primeProducts[i];
-							}
-						}
-
-						int[] primeList = primeLists[i];
-						for (int j = 0; j < primeList.Length; ++j)
-						{
-							int prime = primeList[j];
-							int qRem = test % prime;
-							if (qRem == 0 || qRem == (prime >> 1))
-							{
-								q = q.Add(Six);
-								goto retry;
-							}
-						}
-					}
-
-
-					if (q.BitLength != qLength)
-						continue;
-
-					if (!q.RabinMillerTest(2, random))
-						continue;
-
-					p = q.ShiftLeft(1).Add(BigInteger.One);
-
-					if (p.RabinMillerTest(certainty, random)
-						&& (certainty <= 2 || q.RabinMillerTest(certainty - 2, random)))
-						break;
-				}
-			}
-
-			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)
-		 */
-		internal static BigInteger SelectGenerator(BigInteger p, BigInteger q, SecureRandom random)
-		{
-			BigInteger pMinusTwo = p.Subtract(BigInteger.Two);
-			BigInteger g;
-
-			/*
-			 * (see: Handbook of Applied Cryptography 4.80)
-			 */
+    internal class DHParametersHelper
+    {
+        private static readonly BigInteger Six = BigInteger.ValueOf(6);
+
+        private static readonly int[][] primeLists = BigInteger.primeLists;
+        private static readonly int[] primeProducts = BigInteger.primeProducts;
+        private static readonly BigInteger[] BigPrimeProducts = ConstructBigPrimeProducts(primeProducts);
+
+        private static BigInteger[] ConstructBigPrimeProducts(int[] primeProducts)
+        {
+            BigInteger[] bpp = new BigInteger[primeProducts.Length];
+            for (int i = 0; i < bpp.Length; ++i)
+            {
+                bpp[i] = BigInteger.ValueOf(primeProducts[i]);
+            }
+            return bpp;
+        }
+
+        /*
+         * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
+         * 
+         * (see: Handbook of Applied Cryptography 4.86)
+         */
+        internal static BigInteger[] GenerateSafePrimes(int size, int certainty, SecureRandom random)
+        {
+            BigInteger p, q;
+            int qLength = size - 1;
+            int minWeight = size >> 2;
+
+            if (size <= 32)
+            {
+                for (;;)
+                {
+                    q = new BigInteger(qLength, 2, random);
+
+                    p = q.ShiftLeft(1).Add(BigInteger.One);
+
+                    if (!p.IsProbablePrime(certainty))
+                        continue;
+
+                    if (certainty > 2 && !q.IsProbablePrime(certainty - 2))
+                        continue;
+
+                    break;
+                }
+            }
+            else
+            {
+                // Note: Modified from Java version for speed
+                for (;;)
+                {
+                    q = new BigInteger(qLength, 0, random);
+
+                retry:
+                    for (int i = 0; i < primeLists.Length; ++i)
+                    {
+                        int test = q.Remainder(BigPrimeProducts[i]).IntValue;
+
+                        if (i == 0)
+                        {
+                            int rem3 = test % 3;
+                            if (rem3 != 2)
+                            {
+                                int diff = 2 * rem3 + 2;
+                                q = q.Add(BigInteger.ValueOf(diff));
+                                test = (test + diff) % primeProducts[i];
+                            }
+                        }
+
+                        int[] primeList = primeLists[i];
+                        for (int j = 0; j < primeList.Length; ++j)
+                        {
+                            int prime = primeList[j];
+                            int qRem = test % prime;
+                            if (qRem == 0 || qRem == (prime >> 1))
+                            {
+                                q = q.Add(Six);
+                                goto retry;
+                            }
+                        }
+                    }
+
+                    if (q.BitLength != qLength)
+                        continue;
+
+                    if (!q.RabinMillerTest(2, random))
+                        continue;
+
+                    p = q.ShiftLeft(1).Add(BigInteger.One);
+
+                    if (!p.RabinMillerTest(certainty, random))
+                        continue;
+
+                    if (certainty > 2 && !q.RabinMillerTest(certainty - 2, random))
+                        continue;
+
+                    /*
+                     * Require a minimum weight of the NAF representation, since low-weight primes may be
+                     * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+                     * 
+                     * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+                     */
+                    if (WNafUtilities.GetNafWeight(p) < minWeight)
+                        continue;
+
+                    break;
+                }
+            }
+
+            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)
+         */
+        internal static BigInteger SelectGenerator(BigInteger p, BigInteger q, SecureRandom random)
+        {
+            BigInteger pMinusTwo = p.Subtract(BigInteger.Two);
+            BigInteger g;
+
+            /*
+             * (see: Handbook of Applied Cryptography 4.80)
+             */
 //			do
 //			{
 //				g = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
@@ -217,18 +139,18 @@ namespace Org.BouncyCastle.Crypto.Generators
 //			while (g.ModPow(BigInteger.Two, p).Equals(BigInteger.One)
 //				|| g.ModPow(q, p).Equals(BigInteger.One));
 
-			/*
-	         * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
-	         */
-			do
-			{
-				BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
+            /*
+             * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
+             */
+            do
+            {
+                BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
 
-				g = h.ModPow(BigInteger.Two, p);
-			}
-			while (g.Equals(BigInteger.One));
+                g = h.ModPow(BigInteger.Two, p);
+            }
+            while (g.Equals(BigInteger.One));
 
-			return g;
-		}
-	}
+            return g;
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/DesEdeKeyGenerator.cs b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
new file mode 100644
index 000000000..5902643fd
--- /dev/null
+++ b/crypto/src/crypto/generators/DesEdeKeyGenerator.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class DesEdeKeyGenerator
+		: DesKeyGenerator
+    {
+		public DesEdeKeyGenerator()
+		{
+		}
+
+		internal DesEdeKeyGenerator(
+			int defaultStrength)
+			: base(defaultStrength)
+		{
+		}
+
+		/**
+        * 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
+        */
+        protected override void engineInit(
+			KeyGenerationParameters parameters)
+        {
+			this.random = parameters.Random;
+			this.strength = (parameters.Strength + 7) / 8;
+
+			if (strength == 0 || strength == (168 / 8))
+            {
+                strength = DesEdeParameters.DesEdeKeyLength;
+            }
+            else if (strength == (112 / 8))
+            {
+                strength = 2 * DesEdeParameters.DesKeyLength;
+            }
+            else if (strength != DesEdeParameters.DesEdeKeyLength
+                && strength != (2 * DesEdeParameters.DesKeyLength))
+            {
+                throw new ArgumentException("DESede key must be "
+                    + (DesEdeParameters.DesEdeKeyLength * 8) + " or "
+                    + (2 * 8 * DesEdeParameters.DesKeyLength)
+                    + " bits long.");
+            }
+        }
+
+        protected override byte[] engineGenerateKey()
+        {
+            byte[] newKey;
+
+			do
+            {
+                newKey = random.GenerateSeed(strength);
+                DesEdeParameters.SetOddParity(newKey);
+            }
+            while (DesEdeParameters.IsWeakKey(newKey, 0, newKey.Length));
+
+            return newKey;
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/DesKeyGenerator.cs b/crypto/src/crypto/generators/DesKeyGenerator.cs
new file mode 100644
index 000000000..154e3471a
--- /dev/null
+++ b/crypto/src/crypto/generators/DesKeyGenerator.cs
@@ -0,0 +1,57 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class DesKeyGenerator
+		: CipherKeyGenerator
+    {
+		public DesKeyGenerator()
+		{
+		}
+
+		internal DesKeyGenerator(
+			int defaultStrength)
+			: base(defaultStrength)
+		{
+		}
+
+		/**
+		* 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
+		*/
+		protected override void engineInit(
+			KeyGenerationParameters parameters)
+		{
+			base.engineInit(parameters);
+
+			if (strength == 0 || strength == (56 / 8))
+			{
+				strength = DesParameters.DesKeyLength;
+			}
+			else if (strength != DesParameters.DesKeyLength)
+			{
+				throw new ArgumentException(
+					"DES key must be " + (DesParameters.DesKeyLength * 8) + " bits long.");
+			}
+		}
+
+		protected override byte[] engineGenerateKey()
+        {
+            byte[] newKey;
+
+			do
+            {
+				newKey = random.GenerateSeed(DesParameters.DesKeyLength);
+				DesParameters.SetOddParity(newKey);
+            }
+            while (DesParameters.IsWeakKey(newKey, 0));
+
+			return newKey;
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/DsaKeyPairGenerator.cs b/crypto/src/crypto/generators/DsaKeyPairGenerator.cs
index bb8ec591b..1c9ce5a16 100644
--- a/crypto/src/crypto/generators/DsaKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/DsaKeyPairGenerator.cs
@@ -1,8 +1,10 @@
 using System;
-using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Security;
+
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
@@ -11,51 +13,60 @@ namespace Org.BouncyCastle.Crypto.Generators
      * 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>.
+     * in <i>FIPS 186-3 B.1 FFC Key Pair Generation</i>.
      */
     public class DsaKeyPairGenerator
-		: IAsymmetricCipherKeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
     {
+        private static readonly BigInteger One = BigInteger.One;
+
         private DsaKeyGenerationParameters param;
 
-		public void Init(
-			KeyGenerationParameters parameters)
+        public void Init(
+            KeyGenerationParameters parameters)
         {
-			if (parameters == null)
-				throw new ArgumentNullException("parameters");
+            if (parameters == null)
+                throw new ArgumentNullException("parameters");
 
-			// Note: If we start accepting instances of KeyGenerationParameters,
-			// must apply constraint checking on strength (see DsaParametersGenerator.Init)
+            // Note: If we start accepting instances of KeyGenerationParameters,
+            // must apply constraint checking on strength (see DsaParametersGenerator.Init)
 
-			this.param = (DsaKeyGenerationParameters) parameters;
+            this.param = (DsaKeyGenerationParameters) parameters;
         }
 
-		public AsymmetricCipherKeyPair GenerateKeyPair()
+        public AsymmetricCipherKeyPair GenerateKeyPair()
         {
-			DsaParameters dsaParams = param.Parameters;
+            DsaParameters dsaParams = param.Parameters;
 
-			BigInteger x = GeneratePrivateKey(dsaParams.Q, param.Random);
-			BigInteger y = CalculatePublicKey(dsaParams.P, dsaParams.G, x);
+            BigInteger x = GeneratePrivateKey(dsaParams.Q, param.Random);
+            BigInteger y = CalculatePublicKey(dsaParams.P, dsaParams.G, x);
 
-			return new AsymmetricCipherKeyPair(
-				new DsaPublicKeyParameters(y, dsaParams),
-				new DsaPrivateKeyParameters(x, dsaParams));
+            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(BigInteger.One)).Add(BigInteger.One);
-
-			// B.1.2 Key Pair Generation by Testing Candidates
-			return BigIntegers.CreateRandomInRange(BigInteger.One, q.Subtract(BigInteger.One), random);
-		}
-
-		private static BigInteger CalculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
-		{
-			return g.ModPow(x, p);
-		}
-	}
+        private static BigInteger GeneratePrivateKey(BigInteger q, SecureRandom random)
+        {
+            // B.1.2 Key Pair Generation by Testing Candidates
+            int minWeight = q.BitLength >> 2;
+            for (;;)
+            {
+                // TODO Prefer this method? (change test cases that used fixed random)
+                // B.1.1 Key Pair Generation Using Extra Random Bits
+                //BigInteger x = new BigInteger(q.BitLength + 64, random).Mod(q.Subtract(One)).Add(One);
+
+                BigInteger x = BigIntegers.CreateRandomInRange(One, q.Subtract(One), random);
+                if (WNafUtilities.GetNafWeight(x) >= minWeight)
+                {
+                    return x;
+                }
+            }
+        }
+
+        private static BigInteger CalculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
+        {
+            return g.ModPow(x, p);
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/DsaParametersGenerator.cs b/crypto/src/crypto/generators/DsaParametersGenerator.cs
index 3e9d4f021..cf6343a16 100644
--- a/crypto/src/crypto/generators/DsaParametersGenerator.cs
+++ b/crypto/src/crypto/generators/DsaParametersGenerator.cs
@@ -9,15 +9,27 @@ using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	// TODO Update docs to mention FIPS 186-3 when done
     /**
-     * Generate suitable parameters for DSA, in line with FIPS 186-2.
+     * Generate suitable parameters for DSA, in line with FIPS 186-2, or FIPS 186-3.
      */
     public class DsaParametersGenerator
     {
-		private int				L, N;
+        private IDigest         digest;
+        private int				L, N;
         private int				certainty;
         private SecureRandom	random;
+        private bool            use186_3;
+        private int             usageIndex;
+
+        public DsaParametersGenerator()
+            : this(new Sha1Digest())
+        {
+        }
+
+        public DsaParametersGenerator(IDigest digest)
+        {
+            this.digest = digest;
+        }
 
         /**
          * initialise the key generator.
@@ -26,32 +38,51 @@ namespace Org.BouncyCastle.Crypto.Generators
          * @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(
+        public virtual void Init(
             int             size,
             int             certainty,
             SecureRandom    random)
         {
-			if (!IsValidDsaStrength(size))
-				throw new ArgumentException("size must be from 512 - 1024 and a multiple of 64", "size");
-
-			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;
-		}
+            if (!IsValidDsaStrength(size))
+                throw new ArgumentException("size must be from 512 - 1024 and a multiple of 64", "size");
+
+            this.use186_3 = false;
+            this.L = size;
+            this.N = GetDefaultN(size);
+            this.certainty = certainty;
+            this.random = random;
+        }
+
+        /**
+         * Initialise the key generator for DSA 2.
+         * <p>
+         *     Use this init method if you need to generate parameters for DSA 2 keys.
+         * </p>
+         *
+         * @param params  DSA 2 key generation parameters.
+         */
+        public virtual void Init(DsaParameterGenerationParameters parameters)
+        {
+            // TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
+            this.use186_3 = true;
+            this.L = parameters.L;
+            this.N = parameters.N;
+            this.certainty = parameters.Certainty;
+            this.random = parameters.Random;
+            this.usageIndex = parameters.UsageIndex;
+
+            if ((L < 1024 || L > 3072) || L % 1024 != 0)
+                throw new ArgumentException("Values must be between 1024 and 3072 and a multiple of 1024", "L");
+            if (L == 1024 && N != 160)
+                throw new ArgumentException("N must be 160 for L = 1024");
+            if (L == 2048 && (N != 224 && N != 256))
+                throw new ArgumentException("N must be 224 or 256 for L = 2048");
+            if (L == 3072 && N != 256)
+                throw new ArgumentException("N must be 256 for L = 3072");
+
+            if (digest.GetDigestSize() * 8 < N)
+                throw new InvalidOperationException("Digest output size too small for value of N");
+        }
 
 //        /**
 //         * add value to b, returning the result in a. The a value is treated
@@ -76,280 +107,284 @@ namespace Org.BouncyCastle.Crypto.Generators
 //            }
 //        }
 
-		/**
-		 * which Generates the p and g values from the given parameters,
-		 * returning the DsaParameters object.
-		 * <p>
-		 * Note: can take a while...</p>
-		 */
-		public DsaParameters GenerateParameters()
-		{
-			return L > 1024
-				?	GenerateParameters_FIPS186_3()
-				:	GenerateParameters_FIPS186_2();
-		}
-
-		private DsaParameters GenerateParameters_FIPS186_2()
-		{
+        /**
+         * which Generates the p and g values from the given parameters,
+         * returning the DsaParameters object.
+         * <p>
+         * Note: can take a while...</p>
+         */
+        public virtual DsaParameters GenerateParameters()
+        {
+            return use186_3
+                ?	GenerateParameters_FIPS186_3()
+                :	GenerateParameters_FIPS186_2();
+        }
+
+        protected virtual DsaParameters GenerateParameters_FIPS186_2()
+        {
             byte[] seed = new byte[20];
             byte[] part1 = new byte[20];
             byte[] part2 = new byte[20];
             byte[] u = new byte[20];
-            Sha1Digest sha1 = new Sha1Digest();
-			int n = (L - 1) / 160;
-			byte[] w = new byte[L / 8];
-
-			for (;;)
-			{
-				random.NextBytes(seed);
-
-				Hash(sha1, seed, part1);
-				Array.Copy(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);
-						Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length);
-					}
-
-					Inc(offset);
-					Hash(sha1, offset, part1);
-					Array.Copy(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(BigInteger.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(BigInteger.One).Divide(q);
-			BigInteger pSub2 = p.Subtract(BigInteger.Two);
-
-			for (;;)
-			{
-				BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.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()
-		{
+            int n = (L - 1) / 160;
+            byte[] w = new byte[L / 8];
+
+            if (!(digest is Sha1Digest))
+                throw new InvalidOperationException("can only use SHA-1 for generating FIPS 186-2 parameters");
+
+            for (;;)
+            {
+                random.NextBytes(seed);
+
+                Hash(digest, seed, part1);
+                Array.Copy(seed, 0, part2, 0, seed.Length);
+                Inc(part2);
+                Hash(digest, 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(digest, offset, part1);
+                        Array.Copy(part1, 0, w, w.Length - (k + 1) * part1.Length, part1.Length);
+                    }
+
+                    Inc(offset);
+                    Hash(digest, offset, part1);
+                    Array.Copy(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(BigInteger.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));
+                    }
+                }
+            }
+        }
+
+        protected virtual BigInteger CalculateGenerator_FIPS186_2(BigInteger p, BigInteger q, SecureRandom r)
+        {
+            BigInteger e = p.Subtract(BigInteger.One).Divide(q);
+            BigInteger pSub2 = p.Subtract(BigInteger.Two);
+
+            for (;;)
+            {
+                BigInteger h = BigIntegers.CreateRandomInRange(BigInteger.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>.
+         */
+        protected virtual 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)
-			IDigest d = new Sha256Digest();
-			int outlen = d.GetDigestSize() * 8;
+            IDigest d = digest;
+            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
-			
+            // 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];
+            // 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;
+            int n = (L - 1) / outlen;
 
 // 4. b = L – 1 – (n ∗ outlen).
-			int b = (L - 1) % outlen;
+            int b = (L - 1) % outlen;
 
-			byte[] output = new byte[d.GetDigestSize()];
-			for (;;)
-			{
+            byte[] output = new byte[d.GetDigestSize()];
+            for (;;)
+            {
 // 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
-				random.NextBytes(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(BigInteger.One.ShiftLeft(N - 1));
+                Hash(d, seed, output);
+                BigInteger U = new BigInteger(1, output).Mod(BigInteger.One.ShiftLeft(N - 1));
 
 // 7. q = 2^(N–1) + U + 1 – ( U mod 2).
-				BigInteger q = BigInteger.One.ShiftLeft(N - 1).Add(U).Add(BigInteger.One).Subtract(
-					U.Mod(BigInteger.Two));
+                BigInteger q = BigInteger.One.ShiftLeft(N - 1).Add(U).Add(BigInteger.One).Subtract(
+                    U.Mod(BigInteger.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))
-				{
+                // TODO Review C.3 for primality checking
+                if (!q.IsProbablePrime(certainty))
+                {
 // 9. If q is not a prime, then go to step 5.
-					continue;
-				}
+                    continue;
+                }
 
 // 10. offset = 1.
-				// Note: 'offset' value managed incrementally
-				byte[] offset = Arrays.Clone(seed);
+                // 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)
-				{
+                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 = BigInteger.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(BigInteger.One.ShiftLeft(b));
-						}
-
-						W = W.Add(Vj.ShiftLeft(exp));
-					}
+                    // TODO Assemble w as a byte array
+                    BigInteger W = BigInteger.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(BigInteger.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(BigInteger.One.ShiftLeft(L - 1));
+                    BigInteger X = W.Add(BigInteger.One.ShiftLeft(L - 1));
 
 // 11.4 c = X mod 2q.
-					BigInteger c = X.Mod(q.ShiftLeft(1));
+                    BigInteger c = X.Mod(q.ShiftLeft(1));
 
 // 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q).
-					BigInteger p = X.Subtract(c.Subtract(BigInteger.One));
+                    BigInteger p = X.Subtract(c.Subtract(BigInteger.One));
 
-					// 11.6 If (p < 2^(L - 1)), then go to step 11.9
-					if (p.BitLength != L)
-						continue;
+                    // 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))
-					{
+                    // 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));
-					}
+                        // TODO Make configurable (8-bit unsigned)?
+
+                        if (usageIndex >= 0)
+                        {
+                            BigInteger g = CalculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, usageIndex);
+                            if (g != null)
+                                return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter, usageIndex));
+                        }
+
+                        {
+                            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
-				}
+                    // 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(IDigest d, BigInteger p, BigInteger q,
-			byte[] seed, int index)
-		{
-			// A.2.3 Verifiable Canonical Generation of the Generator g
-			BigInteger e = p.Subtract(BigInteger.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];
-			Array.Copy(seed, 0, U, 0, seed.Length);
-			Array.Copy(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(BigInteger.Two) >= 0)
-					return g;
-			}
-
-			return null;
-		}
-		
-		private static bool IsValidDsaStrength(
-			int strength)
-		{
-			return strength >= 512 && strength <= 1024 && strength % 64 == 0;
-		}
-
-		private static void Hash(IDigest d, byte[] input, byte[] output)
-		{
-			d.BlockUpdate(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);
-				buf[i] = b;
-
-				if (b != 0)
-					break;
-			}
-		}
-	}
+            }
+        }
+
+        protected virtual BigInteger CalculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q,
+            SecureRandom r)
+        {
+            return CalculateGenerator_FIPS186_2(p, q, r);
+        }
+
+        protected virtual BigInteger CalculateGenerator_FIPS186_3_Verifiable(IDigest d, BigInteger p, BigInteger q,
+            byte[] seed, int index)
+        {
+            // A.2.3 Verifiable Canonical Generation of the Generator g
+            BigInteger e = p.Subtract(BigInteger.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];
+            Array.Copy(seed, 0, U, 0, seed.Length);
+            Array.Copy(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(BigInteger.Two) >= 0)
+                    return g;
+            }
+
+            return null;
+        }
+        
+        private static bool IsValidDsaStrength(
+            int strength)
+        {
+            return strength >= 512 && strength <= 1024 && strength % 64 == 0;
+        }
+
+        protected static void Hash(IDigest d, byte[] input, byte[] output)
+        {
+            d.BlockUpdate(input, 0, input.Length);
+            d.DoFinal(output, 0);
+        }
+
+        private static int GetDefaultN(int L)
+        {
+            return L > 1024 ? 256 : 160;
+        }
+
+        protected static void Inc(byte[] buf)
+        {
+            for (int i = buf.Length - 1; i >= 0; --i)
+            {
+                byte b = (byte)(buf[i] + 1);
+                buf[i] = b;
+
+                if (b != 0)
+                    break;
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index d1e4b7cf6..6e777c74c 100644
--- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Nist;
@@ -7,168 +6,162 @@ using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.TeleTrust;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.EC;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Multiplier;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
     public class ECKeyPairGenerator
-		: IAsymmetricCipherKeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
     {
-		private readonly string algorithm;
+        private readonly string algorithm;
 
-		private ECDomainParameters parameters;
-		private DerObjectIdentifier publicKeyParamSet;
+        private ECDomainParameters parameters;
+        private DerObjectIdentifier publicKeyParamSet;
         private SecureRandom random;
 
-		public ECKeyPairGenerator()
-			: this("EC")
-		{
-		}
+        public ECKeyPairGenerator()
+            : this("EC")
+        {
+        }
 
-		public ECKeyPairGenerator(
-			string algorithm)
-		{
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
+        public ECKeyPairGenerator(
+            string algorithm)
+        {
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
 
-			this.algorithm = VerifyAlgorithmName(algorithm);
-		}
+            this.algorithm = ECKeyParameters.VerifyAlgorithmName(algorithm);
+        }
 
-		public void Init(
+        public void Init(
             KeyGenerationParameters parameters)
         {
-			if (parameters is ECKeyGenerationParameters)
-			{
-				ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters;
-
-				this.publicKeyParamSet = ecP.PublicKeyParamSet;
-				this.parameters = ecP.DomainParameters;
-			}
-			else
-			{
-				DerObjectIdentifier oid;
-				switch (parameters.Strength)
-				{
-					case 192:
-						oid = X9ObjectIdentifiers.Prime192v1;
-						break;
-					case 224:
-						oid = SecObjectIdentifiers.SecP224r1;
-						break;
-					case 239:
-						oid = X9ObjectIdentifiers.Prime239v1;
-						break;
-					case 256:
-						oid = X9ObjectIdentifiers.Prime256v1;
-						break;
-					case 384:
-						oid = SecObjectIdentifiers.SecP384r1;
-						break;
-					case 521:
-						oid = SecObjectIdentifiers.SecP521r1;
-						break;
-					default:
-						throw new InvalidParameterException("unknown key size.");
-				}
-
-				X9ECParameters ecps = FindECCurveByOid(oid);
-
-				this.parameters = new ECDomainParameters(
-					ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
-			}
-
-			this.random = parameters.Random;
-		}
-
-		/**
-         * Given the domain parameters this routine Generates an EC key
+            if (parameters is ECKeyGenerationParameters)
+            {
+                ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters;
+
+                this.publicKeyParamSet = ecP.PublicKeyParamSet;
+                this.parameters = ecP.DomainParameters;
+            }
+            else
+            {
+                DerObjectIdentifier oid;
+                switch (parameters.Strength)
+                {
+                    case 192:
+                        oid = X9ObjectIdentifiers.Prime192v1;
+                        break;
+                    case 224:
+                        oid = SecObjectIdentifiers.SecP224r1;
+                        break;
+                    case 239:
+                        oid = X9ObjectIdentifiers.Prime239v1;
+                        break;
+                    case 256:
+                        oid = X9ObjectIdentifiers.Prime256v1;
+                        break;
+                    case 384:
+                        oid = SecObjectIdentifiers.SecP384r1;
+                        break;
+                    case 521:
+                        oid = SecObjectIdentifiers.SecP521r1;
+                        break;
+                    default:
+                        throw new InvalidParameterException("unknown key size.");
+                }
+
+                X9ECParameters ecps = FindECCurveByOid(oid);
+
+                this.parameters = new ECDomainParameters(
+                    ecps.Curve, ecps.G, ecps.N, ecps.H, ecps.GetSeed());
+            }
+
+            this.random = parameters.Random;
+
+            if (this.random == null)
+            {
+                this.random = new SecureRandom();
+            }
+        }
+
+        /**
+         * 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 = parameters.N;
             BigInteger d;
+            int minWeight = n.BitLength >> 2;
 
-            do
+            for (;;)
             {
                 d = new BigInteger(n.BitLength, random);
+
+                if (d.CompareTo(BigInteger.Two) < 0 || d.CompareTo(n) >= 0)
+                    continue;
+
+                /*
+                 * Require a minimum weight of the NAF representation, since low-weight primes may be
+                 * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+                 * 
+                 * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+                 */
+                if (WNafUtilities.GetNafWeight(d) < minWeight)
+                    continue;
+
+                break;
             }
-            while (d.SignValue == 0 || (d.CompareTo(n) >= 0));
-
-            ECPoint q = parameters.G.Multiply(d);
-
-			if (publicKeyParamSet != null)
-			{
-				return new AsymmetricCipherKeyPair(
-					new ECPublicKeyParameters(algorithm, q, publicKeyParamSet),
-					new ECPrivateKeyParameters(algorithm, d, publicKeyParamSet));
-			}
-
-			return new AsymmetricCipherKeyPair(
-				new ECPublicKeyParameters(algorithm, q, parameters),
-				new ECPrivateKeyParameters(algorithm, d, parameters));
-		}
-
-		private string VerifyAlgorithmName(
-			string algorithm)
-		{
-			string upper = algorithm.ToUpperInvariant();
-
-			switch (upper)
-			{
-				case "EC":
-				case "ECDSA":
-				case "ECDH":
-				case "ECDHC":
-				case "ECGOST3410":
-				case "ECMQV":
-					break;
-				default:
-					throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
-			}
-
-			return upper;
-		}
-
-		internal static X9ECParameters FindECCurveByOid(DerObjectIdentifier oid)
-		{
-			// TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
-
-			X9ECParameters ecP = X962NamedCurves.GetByOid(oid);
-
-			if (ecP == null)
-			{
-				ecP = SecNamedCurves.GetByOid(oid);
-
-				if (ecP == null)
-				{
-					ecP = NistNamedCurves.GetByOid(oid);
-
-					if (ecP == null)
-					{
-						ecP = TeleTrusTNamedCurves.GetByOid(oid);
-					}
-				}
-			}
-
-			return ecP;
-		}
-
-		internal static ECPublicKeyParameters GetCorrespondingPublicKey(
-			ECPrivateKeyParameters privKey)
-		{
-			ECDomainParameters parameters = privKey.Parameters;
-			ECPoint q = parameters.G.Multiply(privKey.D);
-
-			if (privKey.PublicKeyParamSet != null)
-			{
-				return new ECPublicKeyParameters(privKey.AlgorithmName, q, privKey.PublicKeyParamSet);
-			}
-
-			return new ECPublicKeyParameters(privKey.AlgorithmName, q, parameters);
-		}
-	}
+
+            ECPoint q = CreateBasePointMultiplier().Multiply(parameters.G, d);
+
+            if (publicKeyParamSet != null)
+            {
+                return new AsymmetricCipherKeyPair(
+                    new ECPublicKeyParameters(algorithm, q, publicKeyParamSet),
+                    new ECPrivateKeyParameters(algorithm, d, publicKeyParamSet));
+            }
+
+            return new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(algorithm, q, parameters),
+                new ECPrivateKeyParameters(algorithm, d, parameters));
+        }
+
+        protected virtual ECMultiplier CreateBasePointMultiplier()
+        {
+            return new FixedPointCombMultiplier();
+        }
+
+        internal static X9ECParameters FindECCurveByOid(DerObjectIdentifier oid)
+        {
+            // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+
+            X9ECParameters ecP = CustomNamedCurves.GetByOid(oid);
+            if (ecP == null)
+            {
+                ecP = ECNamedCurveTable.GetByOid(oid);
+            }
+            return ecP;
+        }
+
+        internal static ECPublicKeyParameters GetCorrespondingPublicKey(
+            ECPrivateKeyParameters privKey)
+        {
+            ECDomainParameters ec = privKey.Parameters;
+            ECPoint q = new FixedPointCombMultiplier().Multiply(ec.G, privKey.D);
+
+            if (privKey.PublicKeyParamSet != null)
+            {
+                return new ECPublicKeyParameters(privKey.AlgorithmName, q, privKey.PublicKeyParamSet);
+            }
+
+            return new ECPublicKeyParameters(privKey.AlgorithmName, q, ec);
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs b/crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs
new file mode 100644
index 000000000..227e7fe94
--- /dev/null
+++ b/crypto/src/crypto/generators/ElGamalKeyPairGenerator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    /**
+     * a ElGamal key pair generator.
+     * <p>
+     * This Generates keys consistent for use with ElGamal as described in
+     * page 164 of "Handbook of Applied Cryptography".</p>
+     */
+    public class ElGamalKeyPairGenerator
+		: IAsymmetricCipherKeyPairGenerator
+    {
+        private ElGamalKeyGenerationParameters param;
+
+        public void Init(
+			KeyGenerationParameters parameters)
+        {
+            this.param = (ElGamalKeyGenerationParameters) parameters;
+        }
+
+        public AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+			DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.Instance;
+			ElGamalParameters egp = param.Parameters;
+			DHParameters dhp = new DHParameters(egp.P, egp.G, null, 0, egp.L);
+
+			BigInteger x = helper.CalculatePrivate(dhp, param.Random);
+			BigInteger y = helper.CalculatePublic(dhp, x);
+
+			return new AsymmetricCipherKeyPair(
+                new ElGamalPublicKeyParameters(y, egp),
+                new ElGamalPrivateKeyParameters(x, egp));
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/generators/ElGamalParametersGenerator.cs b/crypto/src/crypto/generators/ElGamalParametersGenerator.cs
new file mode 100644
index 000000000..8443bb00e
--- /dev/null
+++ b/crypto/src/crypto/generators/ElGamalParametersGenerator.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class ElGamalParametersGenerator
+    {
+		private int				size;
+        private int				certainty;
+        private SecureRandom	random;
+
+		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 ElGamalParameters object.
+         * <p>
+         * Note: can take a while...
+		 * </p>
+         */
+        public ElGamalParameters 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 ElGamalParameters(p, g);
+        }
+    }
+}
diff --git a/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs b/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
index 5878da64b..013b81810 100644
--- a/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
@@ -3,71 +3,86 @@ using System;
 using Org.BouncyCastle.Asn1.CryptoPro;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
 using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	/**
-	 * a GOST3410 key pair generator.
-	 * This generates GOST3410 keys in line with the method described
-	 * in GOST R 34.10-94.
-	 */
-	public class Gost3410KeyPairGenerator
-		: IAsymmetricCipherKeyPairGenerator
-	{
-		private Gost3410KeyGenerationParameters param;
+    /**
+     * a GOST3410 key pair generator.
+     * This generates GOST3410 keys in line with the method described
+     * in GOST R 34.10-94.
+     */
+    public class Gost3410KeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
+    {
+        private Gost3410KeyGenerationParameters param;
 
-		public void Init(
-			KeyGenerationParameters parameters)
-		{
-			if (parameters is Gost3410KeyGenerationParameters)
-			{
-				this.param = (Gost3410KeyGenerationParameters) parameters;
-			}
-			else
-			{
-				Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
-					parameters.Random,
-					CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
+        public void Init(
+            KeyGenerationParameters parameters)
+        {
+            if (parameters is Gost3410KeyGenerationParameters)
+            {
+                this.param = (Gost3410KeyGenerationParameters) parameters;
+            }
+            else
+            {
+                Gost3410KeyGenerationParameters kgp = new Gost3410KeyGenerationParameters(
+                    parameters.Random,
+                    CryptoProObjectIdentifiers.GostR3410x94CryptoProA);
 
-				if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
-				{
-					// TODO Should we complain?
-				}
+                if (parameters.Strength != kgp.Parameters.P.BitLength - 1)
+                {
+                    // TODO Should we complain?
+                }
 
-				this.param = kgp;
-			}
-		}
+                this.param = kgp;
+            }
+        }
 
-		public AsymmetricCipherKeyPair GenerateKeyPair()
-		{
-			SecureRandom random = param.Random;
-			Gost3410Parameters gost3410Params = param.Parameters;
+        public AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            SecureRandom random = param.Random;
+            Gost3410Parameters gost3410Params = param.Parameters;
 
-			BigInteger q = gost3410Params.Q;
-			BigInteger x;
-			do
-			{
-				x = new BigInteger(256, random);
-			}
-			while (x.SignValue < 1 || x.CompareTo(q) >= 0);
+            BigInteger q = gost3410Params.Q, x;
 
-			BigInteger p = gost3410Params.P;
-			BigInteger a = gost3410Params.A;
+            int minWeight = 64;
+            for (;;)
+            {
+                x = new BigInteger(256, random);
 
-			// calculate the public key.
-			BigInteger y = a.ModPow(x, p);
+                if (x.SignValue < 1 || x.CompareTo(q) >= 0)
+                    continue;
 
-			if (param.PublicKeyParamSet != null)
-			{
-				return new AsymmetricCipherKeyPair(
-					new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
-					new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
-			}
+                /*
+                 * Require a minimum weight of the NAF representation, since low-weight primes may be
+                 * weak against a version of the number-field-sieve for the discrete-logarithm-problem.
+                 * 
+                 * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+                 */
+                if (WNafUtilities.GetNafWeight(x) < minWeight)
+                    continue;
 
-			return new AsymmetricCipherKeyPair(
-				new Gost3410PublicKeyParameters(y, gost3410Params),
-				new Gost3410PrivateKeyParameters(x, gost3410Params));
-		}
-	}
+                break;
+            }
+
+            BigInteger p = gost3410Params.P;
+            BigInteger a = gost3410Params.A;
+
+            // calculate the public key.
+            BigInteger y = a.ModPow(x, p);
+
+            if (param.PublicKeyParamSet != null)
+            {
+                return new AsymmetricCipherKeyPair(
+                    new Gost3410PublicKeyParameters(y, param.PublicKeyParamSet),
+                    new Gost3410PrivateKeyParameters(x, param.PublicKeyParamSet));
+            }
+
+            return new AsymmetricCipherKeyPair(
+                new Gost3410PublicKeyParameters(y, gost3410Params),
+                new Gost3410PrivateKeyParameters(x, gost3410Params));
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/GOST3410ParametersGenerator.cs b/crypto/src/crypto/generators/GOST3410ParametersGenerator.cs
new file mode 100644
index 000000000..52a9f5a82
--- /dev/null
+++ b/crypto/src/crypto/generators/GOST3410ParametersGenerator.cs
@@ -0,0 +1,530 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/**
+	 * generate suitable parameters for GOST3410.
+	 */
+	public class Gost3410ParametersGenerator
+	{
+		private int             size;
+		private int             typeproc;
+		private SecureRandom    init_random;
+
+		/**
+		 * initialise the key generator.
+		 *
+		 * @param size size of the key
+		 * @param typeProcedure type procedure A,B = 1;  A',B' - else
+		 * @param random random byte source.
+		 */
+		public void Init(
+			int             size,
+			int             typeProcedure,
+			SecureRandom    random)
+		{
+			this.size = size;
+			this.typeproc = typeProcedure;
+			this.init_random = random;
+		}
+
+		//Procedure A
+		private int procedure_A(int x0, int c,  BigInteger[] pq, int size)
+		{
+			//Verify and perform condition: 0<x<2^16; 0<c<2^16; c - odd.
+			while(x0<0 || x0>65536)
+			{
+				x0 = init_random.NextInt()/32768;
+			}
+
+			while((c<0 || c>65536) || (c/2==0))
+			{
+				c = init_random.NextInt()/32768 + 1;
+			}
+
+			BigInteger C = BigInteger.ValueOf(c);
+			BigInteger constA16 = BigInteger.ValueOf(19381);
+
+			//step1
+			BigInteger[] y = new BigInteger[1]; // begin length = 1
+			y[0] = BigInteger.ValueOf(x0);
+
+			//step 2
+			int[] t = new int[1]; // t - orders; begin length = 1
+			t[0] = size;
+			int s = 0;
+			for (int i=0; t[i]>=17; i++)
+			{
+				// extension array t
+				int[] tmp_t = new int[t.Length + 1];             ///////////////
+					Array.Copy(t,0,tmp_t,0,t.Length);          //  extension
+				t = new int[tmp_t.Length];                       //  array t
+				Array.Copy(tmp_t, 0, t, 0, tmp_t.Length);  ///////////////
+
+				t[i+1] = t[i]/2;
+				s = i+1;
+			}
+
+			//step3
+			BigInteger[] p = new BigInteger[s+1];
+			p[s] = new BigInteger("8003",16); //set min prime number length 16 bit
+
+			int m = s-1;  //step4
+
+			for (int i=0; i<s; i++)
+			{
+				int rm = t[m]/16;  //step5
+
+			step6: for(;;)
+				   {
+					   //step 6
+					   BigInteger[] tmp_y = new BigInteger[y.Length];  ////////////////
+					   Array.Copy(y,0,tmp_y,0,y.Length);         //  extension
+					   y = new BigInteger[rm+1];                       //  array y
+					   Array.Copy(tmp_y,0,y,0,tmp_y.Length);     ////////////////
+
+					   for (int j=0; j<rm; j++)
+					   {
+						   y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
+					   }
+
+					   //step 7
+					   BigInteger Ym = BigInteger.Zero;
+					   for (int j=0; j<rm; j++)
+					   {
+						   Ym = Ym.Add(y[j].ShiftLeft(16*j));
+					   }
+
+					   y[0] = y[rm]; //step 8
+
+					   //step 9
+					   BigInteger N = BigInteger.One.ShiftLeft(t[m]-1).Divide(p[m+1]).Add(
+						   Ym.ShiftLeft(t[m]-1).Divide(p[m+1].ShiftLeft(16*rm)));
+
+					   if (N.TestBit(0))
+					   {
+						   N = N.Add(BigInteger.One);
+					   }
+
+					   //step 10
+
+						for(;;)
+						{
+							//step 11
+							BigInteger NByLastP = N.Multiply(p[m+1]);
+
+							if (NByLastP.BitLength > t[m])
+							{
+								goto step6; //step 12
+							}
+
+							p[m] = NByLastP.Add(BigInteger.One);
+
+							//step13
+							if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+								&& BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+							{
+								break;
+							}
+
+							N = N.Add(BigInteger.Two);
+						}
+
+					   if (--m < 0)
+					   {
+						   pq[0] = p[0];
+						   pq[1] = p[1];
+						   return y[0].IntValue; //return for procedure B step 2
+					   }
+
+					   break; //step 14
+				   }
+			}
+			return y[0].IntValue;
+		}
+
+		//Procedure A'
+		private long procedure_Aa(long x0, long c, BigInteger[] pq, int size)
+		{
+			//Verify and perform condition: 0<x<2^32; 0<c<2^32; c - odd.
+			while(x0<0 || x0>4294967296L)
+			{
+				x0 = init_random.NextInt()*2;
+			}
+
+			while((c<0 || c>4294967296L) || (c/2==0))
+			{
+				c = init_random.NextInt()*2+1;
+			}
+
+			BigInteger C = BigInteger.ValueOf(c);
+			BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+			//step1
+			BigInteger[] y = new BigInteger[1]; // begin length = 1
+			y[0] = BigInteger.ValueOf(x0);
+
+			//step 2
+			int[] t = new int[1]; // t - orders; begin length = 1
+			t[0] = size;
+			int s = 0;
+			for (int i=0; t[i]>=33; i++)
+			{
+				// extension array t
+				int[] tmp_t = new int[t.Length + 1];             ///////////////
+					Array.Copy(t,0,tmp_t,0,t.Length);          //  extension
+				t = new int[tmp_t.Length];                       //  array t
+				Array.Copy(tmp_t, 0, t, 0, tmp_t.Length);  ///////////////
+
+				t[i+1] = t[i]/2;
+				s = i+1;
+			}
+
+			//step3
+			BigInteger[] p = new BigInteger[s+1];
+			p[s] = new BigInteger("8000000B",16); //set min prime number length 32 bit
+
+			int m = s-1;  //step4
+
+			for (int i=0; i<s; i++)
+			{
+				int rm = t[m]/32;  //step5
+
+			step6: for(;;)
+				   {
+					   //step 6
+					   BigInteger[] tmp_y = new BigInteger[y.Length];  ////////////////
+						   Array.Copy(y,0,tmp_y,0,y.Length);         //  extension
+					   y = new BigInteger[rm+1];                       //  array y
+					   Array.Copy(tmp_y,0,y,0,tmp_y.Length);     ////////////////
+
+					   for (int j=0; j<rm; j++)
+					   {
+						   y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
+					   }
+
+					   //step 7
+					   BigInteger Ym = BigInteger.Zero;
+					   for (int j=0; j<rm; j++)
+					   {
+						   Ym = Ym.Add(y[j].ShiftLeft(32*j));
+					   }
+
+					   y[0] = y[rm]; //step 8
+
+					   //step 9
+					   BigInteger N = BigInteger.One.ShiftLeft(t[m]-1).Divide(p[m+1]).Add(
+						   Ym.ShiftLeft(t[m]-1).Divide(p[m+1].ShiftLeft(32*rm)));
+
+					   if (N.TestBit(0))
+					   {
+						   N = N.Add(BigInteger.One);
+					   }
+
+					   //step 10
+
+						for(;;)
+						{
+							//step 11
+							BigInteger NByLastP = N.Multiply(p[m+1]);
+
+							if (NByLastP.BitLength > t[m])
+							{
+								goto step6; //step 12
+							}
+
+							p[m] = NByLastP.Add(BigInteger.One);
+
+							//step13
+							if (BigInteger.Two.ModPow(NByLastP, p[m]).CompareTo(BigInteger.One) == 0
+								&& BigInteger.Two.ModPow(N, p[m]).CompareTo(BigInteger.One) != 0)
+							{
+								break;
+							}
+
+							N = N.Add(BigInteger.Two);
+						}
+
+					   if (--m < 0)
+					   {
+						   pq[0] = p[0];
+						   pq[1] = p[1];
+						   return y[0].LongValue; //return for procedure B' step 2
+					   }
+
+					   break; //step 14
+				   }
+			}
+			return y[0].LongValue;
+		}
+
+		//Procedure B
+		private void procedure_B(int x0, int c, BigInteger[] pq)
+		{
+			//Verify and perform condition: 0<x<2^16; 0<c<2^16; c - odd.
+			while(x0<0 || x0>65536)
+			{
+				x0 = init_random.NextInt()/32768;
+			}
+
+			while((c<0 || c>65536) || (c/2==0))
+			{
+				c = init_random.NextInt()/32768 + 1;
+			}
+
+			BigInteger [] qp = new BigInteger[2];
+			BigInteger q = null, Q = null, p = null;
+			BigInteger C = BigInteger.ValueOf(c);
+			BigInteger constA16 = BigInteger.ValueOf(19381);
+
+			//step1
+			x0 = procedure_A(x0, c, qp, 256);
+			q = qp[0];
+
+			//step2
+			x0 = procedure_A(x0, c, qp, 512);
+			Q = qp[0];
+
+			BigInteger[] y = new BigInteger[65];
+			y[0] = BigInteger.ValueOf(x0);
+
+			const int tp = 1024;
+
+			BigInteger qQ = q.Multiply(Q);
+
+step3:
+			for(;;)
+			{
+				//step 3
+				for (int j=0; j<64; j++)
+				{
+					y[j+1] = (y[j].Multiply(constA16).Add(C)).Mod(BigInteger.Two.Pow(16));
+				}
+
+				//step 4
+				BigInteger Y = BigInteger.Zero;
+
+				for (int j=0; j<64; j++)
+				{
+					Y = Y.Add(y[j].ShiftLeft(16*j));
+				}
+
+				y[0] = y[64]; //step 5
+
+				//step 6
+				BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+					Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+				if (N.TestBit(0))
+				{
+					N = N.Add(BigInteger.One);
+				}
+
+				//step 7
+
+				for(;;)
+				{
+					//step 11
+					BigInteger qQN = qQ.Multiply(N);
+
+					if (qQN.BitLength > tp)
+					{
+						goto step3; //step 9
+					}
+
+					p = qQN.Add(BigInteger.One);
+
+					//step10
+					if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+						&& BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+					{
+						pq[0] = p;
+						pq[1] = q;
+						return;
+					}
+
+					N = N.Add(BigInteger.Two);
+				}
+			}
+		}
+
+		//Procedure B'
+		private void procedure_Bb(long x0, long c, BigInteger[] pq)
+		{
+			//Verify and perform condition: 0<x<2^32; 0<c<2^32; c - odd.
+			while(x0<0 || x0>4294967296L)
+			{
+				x0 = init_random.NextInt()*2;
+			}
+
+			while((c<0 || c>4294967296L) || (c/2==0))
+			{
+				c = init_random.NextInt()*2+1;
+			}
+
+			BigInteger [] qp = new BigInteger[2];
+			BigInteger q = null, Q = null, p = null;
+			BigInteger C = BigInteger.ValueOf(c);
+			BigInteger constA32 = BigInteger.ValueOf(97781173);
+
+			//step1
+			x0 = procedure_Aa(x0, c, qp, 256);
+			q = qp[0];
+
+			//step2
+			x0 = procedure_Aa(x0, c, qp, 512);
+			Q = qp[0];
+
+			BigInteger[] y = new BigInteger[33];
+			y[0] = BigInteger.ValueOf(x0);
+
+			const int tp = 1024;
+
+			BigInteger qQ = q.Multiply(Q);
+
+step3:
+			for(;;)
+			{
+				//step 3
+				for (int j=0; j<32; j++)
+				{
+					y[j+1] = (y[j].Multiply(constA32).Add(C)).Mod(BigInteger.Two.Pow(32));
+				}
+
+				//step 4
+				BigInteger Y = BigInteger.Zero;
+				for (int j=0; j<32; j++)
+				{
+					Y = Y.Add(y[j].ShiftLeft(32*j));
+				}
+
+				y[0] = y[32]; //step 5
+
+				//step 6
+				BigInteger N = BigInteger.One.ShiftLeft(tp-1).Divide(qQ).Add(
+					Y.ShiftLeft(tp-1).Divide(qQ.ShiftLeft(1024)));
+
+				if (N.TestBit(0))
+				{
+					N = N.Add(BigInteger.One);
+				}
+
+				//step 7
+
+				for(;;)
+				{
+					//step 11
+					BigInteger qQN = qQ.Multiply(N);
+
+					if (qQN.BitLength > tp)
+					{
+						goto step3; //step 9
+					}
+
+					p = qQN.Add(BigInteger.One);
+
+					//step10
+					if (BigInteger.Two.ModPow(qQN, p).CompareTo(BigInteger.One) == 0
+						&& BigInteger.Two.ModPow(q.Multiply(N), p).CompareTo(BigInteger.One) != 0)
+					{
+						pq[0] = p;
+						pq[1] = q;
+						return;
+					}
+
+					N = N.Add(BigInteger.Two);
+				}
+			}
+		}
+
+
+		/**
+		 * Procedure C
+		 * procedure generates the a value from the given p,q,
+		 * returning the a value.
+		 */
+		private BigInteger procedure_C(BigInteger p, BigInteger q)
+		{
+			BigInteger pSub1 = p.Subtract(BigInteger.One);
+			BigInteger pSub1Divq = pSub1.Divide(q);
+
+			for(;;)
+			{
+				BigInteger d = new BigInteger(p.BitLength, init_random);
+
+				// 1 < d < p-1
+				if (d.CompareTo(BigInteger.One) > 0 && d.CompareTo(pSub1) < 0)
+				{
+					BigInteger a = d.ModPow(pSub1Divq, p);
+
+					if (a.CompareTo(BigInteger.One) != 0)
+					{
+						return a;
+					}
+				}
+			}
+		}
+
+		/**
+		 * which generates the p , q and a values from the given parameters,
+		 * returning the Gost3410Parameters object.
+		 */
+		public Gost3410Parameters GenerateParameters()
+		{
+			BigInteger [] pq = new BigInteger[2];
+			BigInteger    q = null, p = null, a = null;
+
+			int  x0, c;
+			long  x0L, cL;
+
+			if (typeproc==1)
+			{
+				x0 = init_random.NextInt();
+				c  = init_random.NextInt();
+
+				switch(size)
+				{
+					case 512:
+						procedure_A(x0, c, pq, 512);
+						break;
+					case 1024:
+						procedure_B(x0, c, pq);
+						break;
+					default:
+						throw new ArgumentException("Ooops! key size 512 or 1024 bit.");
+				}
+				p = pq[0];  q = pq[1];
+				a = procedure_C(p, q);
+				//System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+				//System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+				return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0, c));
+			}
+			else
+			{
+				x0L = init_random.NextLong();
+				cL  = init_random.NextLong();
+
+				switch(size)
+				{
+					case 512:
+						procedure_Aa(x0L, cL, pq, 512);
+						break;
+					case 1024:
+						procedure_Bb(x0L, cL, pq);
+						break;
+					default:
+						throw new InvalidOperationException("Ooops! key size 512 or 1024 bit.");
+				}
+				p = pq[0];  q = pq[1];
+				a = procedure_C(p, q);
+				//System.out.println("p:"+p.toString(16)+"\n"+"q:"+q.toString(16)+"\n"+"a:"+a.toString(16));
+				//System.out.println("p:"+p+"\n"+"q:"+q+"\n"+"a:"+a);
+				return new Gost3410Parameters(p, q, a, new Gost3410ValidationParameters(x0L, cL));
+			}
+		}
+	}
+}
diff --git a/crypto/src/crypto/generators/Kdf1BytesGenerator.cs b/crypto/src/crypto/generators/Kdf1BytesGenerator.cs
index 2b4fb7efd..0ddf6c166 100644
--- a/crypto/src/crypto/generators/Kdf1BytesGenerator.cs
+++ b/crypto/src/crypto/generators/Kdf1BytesGenerator.cs
@@ -18,8 +18,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 		 *
 		 * @param digest the digest to be used as the source of derived keys.
 		 */
-		public Kdf1BytesGenerator(
-			IDigest  digest)
+		public Kdf1BytesGenerator(IDigest digest)
 			: base(0, digest)
 		{
 		}
diff --git a/crypto/src/crypto/generators/Kdf2BytesGenerator.cs b/crypto/src/crypto/generators/Kdf2BytesGenerator.cs
index be1cd158e..8a6821980 100644
--- a/crypto/src/crypto/generators/Kdf2BytesGenerator.cs
+++ b/crypto/src/crypto/generators/Kdf2BytesGenerator.cs
@@ -19,8 +19,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 		*
 		* @param digest the digest to be used as the source of derived keys.
 		*/
-		public Kdf2BytesGenerator(
-			IDigest  digest)
+		public Kdf2BytesGenerator(IDigest digest)
 			: base(1, digest)
 		{
 		}
diff --git a/crypto/src/crypto/generators/Mgf1BytesGenerator.cs b/crypto/src/crypto/generators/Mgf1BytesGenerator.cs
new file mode 100644
index 000000000..23a3aca25
--- /dev/null
+++ b/crypto/src/crypto/generators/Mgf1BytesGenerator.cs
@@ -0,0 +1,117 @@
+using System;
+//using Org.BouncyCastle.Math;
+//using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    /**
+    * Generator for MGF1 as defined in Pkcs 1v2
+    */
+    public class Mgf1BytesGenerator : IDerivationFunction
+    {
+        private IDigest digest;
+        private byte[]  seed;
+        private int     hLen;
+
+        /**
+        * @param digest the digest to be used as the source of Generated bytes
+        */
+        public Mgf1BytesGenerator(
+            IDigest  digest)
+        {
+            this.digest = digest;
+            this.hLen = digest.GetDigestSize();
+        }
+
+        public void Init(
+            IDerivationParameters    parameters)
+        {
+            if (!(typeof(MgfParameters).IsInstanceOfType(parameters)))
+            {
+                throw new ArgumentException("MGF parameters required for MGF1Generator");
+            }
+
+            MgfParameters   p = (MgfParameters)parameters;
+
+            seed = p.GetSeed();
+        }
+
+        /**
+        * return the underlying digest.
+        */
+        public IDigest Digest
+        {
+            get
+            {
+                return digest;
+            }
+        }
+
+        /**
+        * int to octet string.
+        */
+        private void ItoOSP(
+            int     i,
+            byte[]  sp)
+        {
+            sp[0] = (byte)((uint) i >> 24);
+            sp[1] = (byte)((uint) i >> 16);
+            sp[2] = (byte)((uint) i >> 8);
+            sp[3] = (byte)((uint) i >> 0);
+        }
+
+        /**
+        * fill len bytes of the output buffer with bytes Generated from
+        * the derivation function.
+        *
+        * @throws DataLengthException if the out buffer is too small.
+        */
+        public int GenerateBytes(
+            byte[]  output,
+            int     outOff,
+            int     length)
+        {
+			if ((output.Length - length) < outOff)
+			{
+				throw new DataLengthException("output buffer too small");
+			}
+
+			byte[]  hashBuf = new byte[hLen];
+            byte[]  C = new byte[4];
+            int     counter = 0;
+
+            digest.Reset();
+
+			if (length > hLen)
+			{
+				do
+				{
+					ItoOSP(counter, C);
+
+					digest.BlockUpdate(seed, 0, seed.Length);
+					digest.BlockUpdate(C, 0, C.Length);
+					digest.DoFinal(hashBuf, 0);
+
+					Array.Copy(hashBuf, 0, output, outOff + counter * hLen, hLen);
+				}
+				while (++counter < (length / hLen));
+			}
+
+            if ((counter * hLen) < length)
+            {
+                ItoOSP(counter, C);
+
+                digest.BlockUpdate(seed, 0, seed.Length);
+                digest.BlockUpdate(C, 0, C.Length);
+                digest.DoFinal(hashBuf, 0);
+
+                Array.Copy(hashBuf, 0, output, outOff + counter * hLen, length - (counter * hLen));
+            }
+
+            return length;
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs b/crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
index a00a6c8a6..7011cf253 100644
--- a/crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
@@ -55,7 +55,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("Fetching first " + param.CountSmallPrimes + " primes.");
+				Console.WriteLine("Fetching first " + param.CountSmallPrimes + " primes.");
 			}
 
 			IList smallPrimes = findFirstPrimes(param.CountSmallPrimes);
@@ -94,7 +94,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 			long tries = 0;
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("generating p and q");
+				Console.WriteLine("generating p and q");
 			}
 
 			BigInteger _2au = a.Multiply(u).ShiftLeft(1);
@@ -126,7 +126,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 
 				if (!sigma.Gcd(_p.Multiply(_q)).Equals(BigInteger.One))
 				{
-                    System.Diagnostics.Debug.WriteLine("sigma.gcd(_p.mult(_q)) != 1!\n _p: " + _p + "\n _q: " + _q);
+					Console.WriteLine("sigma.gcd(_p.mult(_q)) != 1!\n _p: " + _p +"\n _q: "+ _q );
 					continue;
 				}
 
@@ -134,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 				{
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("key size too small. Should be " + strength + " but is actually "
+						Console.WriteLine("key size too small. Should be " + strength + " but is actually "
 							+ p.Multiply(q).BitLength);
 					}
 					continue;
@@ -144,7 +144,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("needed " + tries + " tries to generate p and q.");
+				Console.WriteLine("needed " + tries + " tries to generate p and q.");
 			}
 
 			BigInteger n = p.Multiply(q);
@@ -153,7 +153,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 			tries = 0;
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("generating g");
+				Console.WriteLine("generating g");
 			}
 			for (;;)
 			{
@@ -193,7 +193,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 					{
 						if (debug)
 						{
-                            System.Diagnostics.Debug.WriteLine("g has order phi(n)/" + smallPrimes[i] + "\n g: " + g);
+							Console.WriteLine("g has order phi(n)/" + smallPrimes[i] + "\n g: " + g);
 						}
 						divisible = true;
 						break;
@@ -212,7 +212,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 				{
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/4\n g:" + g);
+						Console.WriteLine("g has order phi(n)/4\n g:" + g);
 					}
 					continue;
 				}
@@ -221,7 +221,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 				{
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/p'\n g: " + g);
+						Console.WriteLine("g has order phi(n)/p'\n g: " + g);
 					}
 					continue;
 				}
@@ -229,7 +229,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 				{
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/q'\n g: " + g);
+						Console.WriteLine("g has order phi(n)/q'\n g: " + g);
 					}
 					continue;
 				}
@@ -237,7 +237,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 				{
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/a\n g: " + g);
+						Console.WriteLine("g has order phi(n)/a\n g: " + g);
 					}
 					continue;
 				}
@@ -245,7 +245,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 				{
 					if (debug)
 					{
-                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/b\n g: " + g);
+						Console.WriteLine("g has order phi(n)/b\n g: " + g);
 					}
 					continue;
 				}
@@ -253,21 +253,21 @@ namespace Org.BouncyCastle.Crypto.Generators
 			}
 			if (debug)
 			{
-                System.Diagnostics.Debug.WriteLine("needed " + tries + " tries to generate g");
-                System.Diagnostics.Debug.WriteLine("");
-                System.Diagnostics.Debug.WriteLine("found new NaccacheStern cipher variables:");
-                System.Diagnostics.Debug.WriteLine("smallPrimes: " + CollectionUtilities.ToString(smallPrimes));
-                System.Diagnostics.Debug.WriteLine("sigma:...... " + sigma + " (" + sigma.BitLength + " bits)");
-                System.Diagnostics.Debug.WriteLine("a:.......... " + a);
-                System.Diagnostics.Debug.WriteLine("b:.......... " + b);
-                System.Diagnostics.Debug.WriteLine("p':......... " + _p);
-                System.Diagnostics.Debug.WriteLine("q':......... " + _q);
-                System.Diagnostics.Debug.WriteLine("p:.......... " + p);
-                System.Diagnostics.Debug.WriteLine("q:.......... " + q);
-                System.Diagnostics.Debug.WriteLine("n:.......... " + n);
-                System.Diagnostics.Debug.WriteLine("phi(n):..... " + phi_n);
-                System.Diagnostics.Debug.WriteLine("g:.......... " + g);
-                System.Diagnostics.Debug.WriteLine("");
+				Console.WriteLine("needed " + tries + " tries to generate g");
+				Console.WriteLine();
+				Console.WriteLine("found new NaccacheStern cipher variables:");
+				Console.WriteLine("smallPrimes: " + CollectionUtilities.ToString(smallPrimes));
+				Console.WriteLine("sigma:...... " + sigma + " (" + sigma.BitLength + " bits)");
+				Console.WriteLine("a:.......... " + a);
+				Console.WriteLine("b:.......... " + b);
+				Console.WriteLine("p':......... " + _p);
+				Console.WriteLine("q':......... " + _q);
+				Console.WriteLine("p:.......... " + p);
+				Console.WriteLine("q:.......... " + q);
+				Console.WriteLine("n:.......... " + n);
+				Console.WriteLine("phi(n):..... " + phi_n);
+				Console.WriteLine("g:.......... " + g);
+				Console.WriteLine();
 			}
 
 			return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.BitLength),
@@ -290,7 +290,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 		 *            the ArrayList to be permuted
 		 * @param rand
 		 *            the source of Randomness for permutation
-		 * @return a new ArrayList with the permuted elements.
+		 * @return a new IList with the permuted elements.
 		 */
 		private static IList permuteList(
 			IList           arr,
diff --git a/crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs b/crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs
new file mode 100644
index 000000000..8da5d3ad1
--- /dev/null
+++ b/crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs
@@ -0,0 +1,167 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/**
+	 * 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
+		: PbeParametersGenerator
+	{
+		private readonly IDigest digest = new MD5Digest();
+
+		/**
+		 * Construct a OpenSSL Parameters generator. 
+		 */
+		public OpenSslPbeParametersGenerator()
+		{
+		}
+
+		public override void Init(
+			byte[]	password,
+			byte[]	salt,
+			int		iterationCount)
+		{
+			// Ignore the provided iterationCount
+			base.Init(password, salt, 1);
+		}
+
+		/**
+		 * Initialise - note the iteration count for this algorithm is fixed at 1.
+		 * 
+		 * @param password password to use.
+		 * @param salt salt to use.
+		 */
+		public virtual void Init(
+			byte[] password,
+			byte[] salt)
+		{
+			base.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.BlockUpdate(mPassword, 0, mPassword.Length);
+				digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+				digest.DoFinal(buf, 0);
+
+				int len = (bytesNeeded > buf.Length) ? buf.Length : bytesNeeded;
+				Array.Copy(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.BlockUpdate(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 ArgumentException if the key length larger than the base hash size.
+		 */
+		[Obsolete("Use version with 'algorithm' parameter")]
+		public override ICipherParameters GenerateDerivedParameters(
+			int keySize)
+		{
+			return GenerateDerivedMacParameters(keySize);
+		}
+
+		public override ICipherParameters GenerateDerivedParameters(
+			string	algorithm,
+			int		keySize)
+		{
+			keySize /= 8;
+
+			byte[] dKey = GenerateDerivedKey(keySize);
+
+			return ParameterUtilities.CreateKeyParameter(algorithm, 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 ArgumentException if keySize + ivSize is larger than the base hash size.
+		 */
+		[Obsolete("Use version with 'algorithm' parameter")]
+		public override ICipherParameters 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);
+		}
+
+		public override ICipherParameters GenerateDerivedParameters(
+			string	algorithm,
+			int		keySize,
+			int     ivSize)
+		{
+			keySize /= 8;
+			ivSize /= 8;
+
+			byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+			KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+			return new ParametersWithIV(key, 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 ArgumentException if the key length larger than the base hash size.
+		 */
+		public override ICipherParameters GenerateDerivedMacParameters(
+			int keySize)
+		{
+			keySize = keySize / 8;
+
+			byte[] dKey = GenerateDerivedKey(keySize);
+
+			return new KeyParameter(dKey, 0, keySize);
+		}
+	}
+}
diff --git a/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
index d2da3f6fc..cbbfd1b3b 100644
--- a/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
+++ b/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
@@ -7,239 +7,239 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	/**
-	 * 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>
-	 * </p>
-	 */
-	public class Pkcs12ParametersGenerator
-		: PbeParametersGenerator
-	{
-		public const int KeyMaterial = 1;
-		public const int IVMaterial  = 2;
-		public const int MacMaterial = 3;
-
-		private readonly IDigest digest;
-
-		private readonly int u;
-		private readonly int v;
-
-		/**
-		 * Construct a Pkcs 12 Parameters generator.
-		 *
-		 * @param digest the digest to be used as the source of derived keys.
-		 * @exception ArgumentException if an unknown digest is passed in.
-		 */
-		public Pkcs12ParametersGenerator(
-			IDigest digest)
-		{
-			this.digest = digest;
-
-			u = digest.GetDigestSize();
-			v = digest.GetByteLength();
-		}
-
-		/**
-		 * 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 = (int) ((uint) 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 = (int) ((uint) 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 ((mSalt != null) && (mSalt.Length != 0))
-			{
-				S = new byte[v * ((mSalt.Length + v - 1) / v)];
-
-				for (int i = 0; i != S.Length; i++)
-				{
-					S[i] = mSalt[i % mSalt.Length];
-				}
-			}
-			else
-			{
-				S = new byte[0];
-			}
-
-			byte[] P;
-
-			if ((mPassword != null) && (mPassword.Length != 0))
-			{
-				P = new byte[v * ((mPassword.Length + v - 1) / v)];
-
-				for (int i = 0; i != P.Length; i++)
-				{
-					P[i] = mPassword[i % mPassword.Length];
-				}
-			}
-			else
-			{
-				P = new byte[0];
-			}
-
-			byte[]  I = new byte[S.Length + P.Length];
-
-			Array.Copy(S, 0, I, 0, S.Length);
-			Array.Copy(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.BlockUpdate(D, 0, D.Length);
-				digest.BlockUpdate(I, 0, I.Length);
-				digest.DoFinal(A, 0);
-				for (int j = 1; j != mIterationCount; j++)
-				{
-					digest.BlockUpdate(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)
-				{
-					Array.Copy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
-				}
-				else
-				{
-					Array.Copy(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.
-		 */
-		[Obsolete("Use version with 'algorithm' parameter")]
-		public override ICipherParameters GenerateDerivedParameters(
-			int keySize)
-		{
-			keySize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
-
-			return new KeyParameter(dKey, 0, keySize);
-		}
-
-		public override ICipherParameters GenerateDerivedParameters(
-			string	algorithm,
-			int		keySize)
-		{
-			keySize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
-
-			return ParameterUtilities.CreateKeyParameter(algorithm, 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.
-		 */
-		[Obsolete("Use version with 'algorithm' parameter")]
-		public override ICipherParameters GenerateDerivedParameters(
-			int	keySize,
-			int	ivSize)
-		{
-			keySize /= 8;
-			ivSize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
-
-			byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
-
-			return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
-		}
-
-		public override ICipherParameters GenerateDerivedParameters(
-			string	algorithm,
-			int		keySize,
-			int		ivSize)
-		{
-			keySize /= 8;
-			ivSize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
-			KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
-
-			byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
-
-			return new ParametersWithIV(key, 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 override ICipherParameters GenerateDerivedMacParameters(
-			int keySize)
-		{
-			keySize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(MacMaterial, keySize);
-
-			return new KeyParameter(dKey, 0, keySize);
-		}
-	}
+    /**
+     * 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>
+     * </p>
+     */
+    public class Pkcs12ParametersGenerator
+        : PbeParametersGenerator
+    {
+        public const int KeyMaterial = 1;
+        public const int IVMaterial  = 2;
+        public const int MacMaterial = 3;
+
+        private readonly IDigest digest;
+
+        private readonly int u;
+        private readonly int v;
+
+        /**
+         * Construct a Pkcs 12 Parameters generator.
+         *
+         * @param digest the digest to be used as the source of derived keys.
+         * @exception ArgumentException if an unknown digest is passed in.
+         */
+        public Pkcs12ParametersGenerator(
+            IDigest digest)
+        {
+            this.digest = digest;
+
+            u = digest.GetDigestSize();
+            v = digest.GetByteLength();
+        }
+
+        /**
+         * 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 = (int) ((uint) 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 = (int) ((uint) 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 ((mSalt != null) && (mSalt.Length != 0))
+            {
+                S = new byte[v * ((mSalt.Length + v - 1) / v)];
+
+                for (int i = 0; i != S.Length; i++)
+                {
+                    S[i] = mSalt[i % mSalt.Length];
+                }
+            }
+            else
+            {
+                S = new byte[0];
+            }
+
+            byte[] P;
+
+            if ((mPassword != null) && (mPassword.Length != 0))
+            {
+                P = new byte[v * ((mPassword.Length + v - 1) / v)];
+
+                for (int i = 0; i != P.Length; i++)
+                {
+                    P[i] = mPassword[i % mPassword.Length];
+                }
+            }
+            else
+            {
+                P = new byte[0];
+            }
+
+            byte[]  I = new byte[S.Length + P.Length];
+
+            Array.Copy(S, 0, I, 0, S.Length);
+            Array.Copy(P, 0, I, S.Length, P.Length);
+
+            byte[]  B = new byte[v];
+            int     c = (n + u - 1) / u;
+            byte[]  A = new byte[u];
+
+            for (int i = 1; i <= c; i++)
+            {
+                digest.BlockUpdate(D, 0, D.Length);
+                digest.BlockUpdate(I, 0, I.Length);
+                digest.DoFinal(A, 0);
+
+                for (int j = 1; j != mIterationCount; j++)
+                {
+                    digest.BlockUpdate(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)
+                {
+                    Array.Copy(A, 0, dKey, (i - 1) * u, dKey.Length - ((i - 1) * u));
+                }
+                else
+                {
+                    Array.Copy(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.
+         */
+        [Obsolete("Use version with 'algorithm' parameter")]
+        public override ICipherParameters GenerateDerivedParameters(
+            int keySize)
+        {
+            keySize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+            return new KeyParameter(dKey, 0, keySize);
+        }
+
+        public override ICipherParameters GenerateDerivedParameters(
+            string	algorithm,
+            int		keySize)
+        {
+            keySize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+            return ParameterUtilities.CreateKeyParameter(algorithm, 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.
+         */
+        [Obsolete("Use version with 'algorithm' parameter")]
+        public override ICipherParameters GenerateDerivedParameters(
+            int	keySize,
+            int	ivSize)
+        {
+            keySize /= 8;
+            ivSize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+
+            byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+            return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+        }
+
+        public override ICipherParameters GenerateDerivedParameters(
+            string	algorithm,
+            int		keySize,
+            int		ivSize)
+        {
+            keySize /= 8;
+            ivSize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(KeyMaterial, keySize);
+            KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+            byte[] iv = GenerateDerivedKey(IVMaterial, ivSize);
+
+            return new ParametersWithIV(key, 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 override ICipherParameters GenerateDerivedMacParameters(
+            int keySize)
+        {
+            keySize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(MacMaterial, keySize);
+
+            return new KeyParameter(dKey, 0, keySize);
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
new file mode 100644
index 000000000..8586e1ca9
--- /dev/null
+++ b/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs
@@ -0,0 +1,162 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/**
+	* 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>
+	* </p>
+	*/
+	public class Pkcs5S1ParametersGenerator
+		: PbeParametersGenerator
+	{
+		private readonly IDigest digest;
+
+		/**
+		* Construct a Pkcs 5 Scheme 1 Parameters generator.
+		*
+		* @param digest the digest to be used as the source of derived keys.
+		*/
+		public Pkcs5S1ParametersGenerator(
+			IDigest digest)
+		{
+			this.digest = digest;
+		}
+
+		/**
+		* the derived key function, the ith hash of the mPassword and the mSalt.
+		*/
+		private byte[] GenerateDerivedKey()
+		{
+			byte[] digestBytes = new byte[digest.GetDigestSize()];
+
+			digest.BlockUpdate(mPassword, 0, mPassword.Length);
+			digest.BlockUpdate(mSalt, 0, mSalt.Length);
+
+			digest.DoFinal(digestBytes, 0);
+			for (int i = 1; i < mIterationCount; i++)
+			{
+				digest.BlockUpdate(digestBytes, 0, digestBytes.Length);
+				digest.DoFinal(digestBytes, 0);
+			}
+
+			return digestBytes;
+		}
+
+		/**
+		* Generate a key parameter derived from the mPassword, mSalt, and iteration
+		* count we are currently initialised with.
+		*
+		* @param keySize the size of the key we want (in bits)
+		* @return a KeyParameter object.
+		* @exception ArgumentException if the key length larger than the base hash size.
+		*/
+		[Obsolete("Use version with 'algorithm' parameter")]
+		public override ICipherParameters GenerateDerivedParameters(
+			int keySize)
+		{
+			return GenerateDerivedMacParameters(keySize);
+		}
+
+		public override ICipherParameters GenerateDerivedParameters(
+			string	algorithm,
+			int		keySize)
+		{
+			keySize /= 8;
+
+			if (keySize > digest.GetDigestSize())
+			{
+				throw new ArgumentException(
+					"Can't Generate a derived key " + keySize + " bytes long.");
+			}
+
+			byte[] dKey = GenerateDerivedKey();
+
+			return ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+		}
+
+		/**
+		* Generate a key with initialisation vector parameter derived from
+		* the mPassword, mSalt, 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 ArgumentException if keySize + ivSize is larger than the base hash size.
+		*/
+		[Obsolete("Use version with 'algorithm' parameter")]
+		public override ICipherParameters GenerateDerivedParameters(
+			int	keySize,
+			int	ivSize)
+		{
+			keySize /= 8;
+			ivSize /= 8;
+
+			if ((keySize + ivSize) > digest.GetDigestSize())
+			{
+				throw new ArgumentException(
+					"Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+			}
+
+			byte[] dKey = GenerateDerivedKey();
+
+			return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+		}
+
+		public override ICipherParameters GenerateDerivedParameters(
+			string	algorithm,
+			int		keySize,
+			int		ivSize)
+		{
+			keySize /= 8;
+			ivSize /= 8;
+
+			if ((keySize + ivSize) > digest.GetDigestSize())
+			{
+				throw new ArgumentException(
+					"Can't Generate a derived key " + (keySize + ivSize) + " bytes long.");
+			}
+
+			byte[] dKey = GenerateDerivedKey();
+			KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+			return new ParametersWithIV(key, dKey, keySize, ivSize);
+		}
+
+		/**
+		* Generate a key parameter for use with a MAC derived from the mPassword,
+		* mSalt, and iteration count we are currently initialised with.
+		*
+		* @param keySize the size of the key we want (in bits)
+		* @return a KeyParameter object.
+		* @exception ArgumentException if the key length larger than the base hash size.
+		*/
+		public override ICipherParameters GenerateDerivedMacParameters(
+			int keySize)
+		{
+			keySize /= 8;
+
+			if (keySize > digest.GetDigestSize())
+			{
+				throw new ArgumentException(
+					"Can't Generate a derived key " + keySize + " bytes long.");
+			}
+
+			byte[] dKey = GenerateDerivedKey();
+
+			return new KeyParameter(dKey, 0, keySize);
+		}
+	}
+}
diff --git a/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
index 58d7b5c37..10352abbc 100644
--- a/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
+++ b/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
@@ -10,163 +10,171 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	/**
-	* 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></p>
-	*/
-	public class Pkcs5S2ParametersGenerator
-		: PbeParametersGenerator
-	{
-		private readonly IMac hMac;
-
-		/**
-		* construct a Pkcs5 Scheme 2 Parameters generator.
-		*/
-		public Pkcs5S2ParametersGenerator()
-			: this(new Sha1Digest())
-		{
-		}
-
-		public Pkcs5S2ParametersGenerator(IDigest digest)
-		{
-			hMac = new HMac(digest);
-		}
-
-		private void F(
-			byte[]  P,
-			byte[]  S,
-			int     c,
-			byte[]  iBuf,
-			byte[]  outBytes,
-			int     outOff)
-		{
-			byte[]              state = new byte[hMac.GetMacSize()];
-			ICipherParameters    param = new KeyParameter(P);
-
-			hMac.Init(param);
-
-			if (S != null)
-			{
-				hMac.BlockUpdate(S, 0, S.Length);
-			}
-
-			hMac.BlockUpdate(iBuf, 0, iBuf.Length);
-
-			hMac.DoFinal(state, 0);
-
-			Array.Copy(state, 0, outBytes, outOff, state.Length);
-
-			for (int count = 1; count != c; count++)
-			{
-				hMac.Init(param);
-				hMac.BlockUpdate(state, 0, state.Length);
-				hMac.DoFinal(state, 0);
-
-				for (int j = 0; j != state.Length; j++)
-				{
-					outBytes[outOff + j] ^= state[j];
-				}
-			}
-		}
-
-		private byte[] GenerateDerivedKey(
-			int dkLen)
-		{
-			int     hLen = hMac.GetMacSize();
-			int     l = (dkLen + hLen - 1) / hLen;
-			byte[]  iBuf = new byte[4];
-			byte[]  outBytes = new byte[l * hLen];
-
-			for (int i = 1; i <= l; i++)
-			{
-				Pack.UInt32_To_BE((uint)i, iBuf);
-
-				F(mPassword, mSalt, mIterationCount, iBuf, outBytes, (i - 1) * hLen);
-			}
-
-			return outBytes;
-		}
-
-		/**
-		* 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.
-		*/
-		[Obsolete("Use version with 'algorithm' parameter")]
-		public override ICipherParameters GenerateDerivedParameters(
-			int keySize)
-		{
-			return GenerateDerivedMacParameters(keySize);
-		}
-
-		public override ICipherParameters GenerateDerivedParameters(
-			string	algorithm,
-			int		keySize)
-		{
-			keySize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(keySize);
-
-			return ParameterUtilities.CreateKeyParameter(algorithm, 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.
-		*/
-		[Obsolete("Use version with 'algorithm' parameter")]
-		public override ICipherParameters GenerateDerivedParameters(
-			int	keySize,
-			int	ivSize)
-		{
-			keySize /= 8;
-			ivSize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(keySize + ivSize);
-
-			return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
-		}
-
-		public override ICipherParameters GenerateDerivedParameters(
-			string	algorithm,
-			int		keySize,
-			int		ivSize)
-		{
-			keySize /= 8;
-			ivSize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(keySize + ivSize);
-			KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
-
-			return new ParametersWithIV(key, 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 override ICipherParameters GenerateDerivedMacParameters(
-			int keySize)
-		{
-			keySize /= 8;
-
-			byte[] dKey = GenerateDerivedKey(keySize);
-
-			return new KeyParameter(dKey, 0, keySize);
-		}
-	}
+    /**
+    * 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></p>
+    */
+    public class Pkcs5S2ParametersGenerator
+        : PbeParametersGenerator
+    {
+        private readonly IMac hMac;
+        private readonly byte[] state;
+
+        /**
+        * construct a Pkcs5 Scheme 2 Parameters generator.
+        */
+        public Pkcs5S2ParametersGenerator()
+            : this(new Sha1Digest())
+        {
+        }
+
+        public Pkcs5S2ParametersGenerator(IDigest digest)
+        {
+            this.hMac = new HMac(digest);
+            this.state = new byte[hMac.GetMacSize()];
+        }
+
+        private void F(
+            byte[]  S,
+            int     c,
+            byte[]  iBuf,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            if (c == 0)
+                throw new ArgumentException("iteration count must be at least 1.");
+
+            if (S != null)
+            {
+                hMac.BlockUpdate(S, 0, S.Length);
+            }
+
+            hMac.BlockUpdate(iBuf, 0, iBuf.Length);
+            hMac.DoFinal(state, 0);
+
+            Array.Copy(state, 0, outBytes, outOff, state.Length);
+
+            for (int count = 1; count < c; ++count)
+            {
+                hMac.BlockUpdate(state, 0, state.Length);
+                hMac.DoFinal(state, 0);
+
+                for (int j = 0; j < state.Length; ++j)
+                {
+                    outBytes[outOff + j] ^= state[j];
+                }
+            }
+        }
+
+        private byte[] GenerateDerivedKey(
+            int dkLen)
+        {
+            int     hLen = hMac.GetMacSize();
+            int     l = (dkLen + hLen - 1) / hLen;
+            byte[]  iBuf = new byte[4];
+            byte[]  outBytes = new byte[l * hLen];
+            int     outPos = 0;
+
+            ICipherParameters param = new KeyParameter(mPassword);
+
+            hMac.Init(param);
+
+            for (int i = 1; i <= l; i++)
+            {
+                // Increment the value in 'iBuf'
+                int pos = 3;
+                while (++iBuf[pos] == 0)
+                {
+                    --pos;
+                }
+
+                F(mSalt, mIterationCount, iBuf, outBytes, outPos);
+                outPos += hLen;
+            }
+
+            return outBytes;
+        }
+
+        /**
+        * 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.
+        */
+        [Obsolete("Use version with 'algorithm' parameter")]
+        public override ICipherParameters GenerateDerivedParameters(
+            int keySize)
+        {
+            return GenerateDerivedMacParameters(keySize);
+        }
+
+        public override ICipherParameters GenerateDerivedParameters(
+            string	algorithm,
+            int		keySize)
+        {
+            keySize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(keySize);
+
+            return ParameterUtilities.CreateKeyParameter(algorithm, 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.
+        */
+        [Obsolete("Use version with 'algorithm' parameter")]
+        public override ICipherParameters GenerateDerivedParameters(
+            int	keySize,
+            int	ivSize)
+        {
+            keySize /= 8;
+            ivSize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+
+            return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+        }
+
+        public override ICipherParameters GenerateDerivedParameters(
+            string	algorithm,
+            int		keySize,
+            int		ivSize)
+        {
+            keySize /= 8;
+            ivSize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(keySize + ivSize);
+            KeyParameter key = ParameterUtilities.CreateKeyParameter(algorithm, dKey, 0, keySize);
+
+            return new ParametersWithIV(key, 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 override ICipherParameters GenerateDerivedMacParameters(
+            int keySize)
+        {
+            keySize /= 8;
+
+            byte[] dKey = GenerateDerivedKey(keySize);
+
+            return new KeyParameter(dKey, 0, keySize);
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
new file mode 100644
index 000000000..5deb50f07
--- /dev/null
+++ b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/// <summary>
+	/// Generates keys for the Poly1305 MAC.
+	/// </summary>
+	/// <remarks>
+	/// Poly1305 keys are 256 bit keys consisting of a 128 bit secret key used for the underlying block
+	/// cipher followed by a 128 bit {@code r} value used for the polynomial portion of the Mac. <br/>
+	/// The {@code r} value has a specific format with some bits required to be cleared, resulting in an
+	/// effective 106 bit key. <br/>
+	/// A separately generated 256 bit key can be modified to fit the Poly1305 key format by using the
+	/// {@link #clamp(byte[])} method to clear the required bits.
+	/// </remarks>
+	/// <seealso cref="Poly1305"/>
+	public class Poly1305KeyGenerator
+		: CipherKeyGenerator
+	{
+		private const byte R_MASK_LOW_2 = (byte)0xFC;
+		private const byte R_MASK_HIGH_4 = (byte)0x0F;
+
+		/// <summary>
+		/// Initialises the key generator.
+		/// </summary>
+		/// <remarks>
+		/// Poly1305 keys are always 256 bits, so the key length in the provided parameters is ignored.
+		/// </remarks>
+		protected override void engineInit(KeyGenerationParameters param)
+		{
+			// Poly1305 keys are always 256 bits
+			this.random = param.Random;
+			this.strength = 32;
+		}
+
+		/// <summary>
+		/// Generates a 256 bit key in the format required for Poly1305 - e.g.
+		/// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared
+		/// as per <see cref="Clamp(byte[])"/>.
+		/// </summary>
+		protected override byte[] engineGenerateKey()
+		{
+			byte[] key = base.engineGenerateKey();
+			Clamp(key);
+			return key;
+		}
+
+		/// <summary>
+		/// Modifies an existing 32 byte key value to comply with the requirements of the Poly1305 key by
+		/// clearing required bits in the <code>r</code> (second 16 bytes) portion of the key.<br/>
+		/// Specifically:
+		/// <ul>
+		/// <li>r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})</li>
+		/// <li>r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252})</li>
+		/// </ul>
+		/// </summary>
+		/// <param name="key">a 32 byte key value <code>k[0] ... k[15], r[0] ... r[15]</code></param>
+		public static void Clamp(byte[] key)
+		{
+			/*
+	         * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl.
+	         */
+			if (key.Length != 32)
+			{
+				throw new ArgumentException("Poly1305 key must be 256 bits.");
+			}
+
+			/*
+	         * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15})
+	         */
+			key[19] &= R_MASK_HIGH_4;
+			key[23] &= R_MASK_HIGH_4;
+			key[27] &= R_MASK_HIGH_4;
+			key[31] &= R_MASK_HIGH_4;
+
+			/*
+	         * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}).
+	         */
+			key[20] &= R_MASK_LOW_2;
+			key[24] &= R_MASK_LOW_2;
+			key[28] &= R_MASK_LOW_2;
+		}
+
+		/// <summary>
+		/// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g.
+		/// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared
+		/// as per <see cref="Clamp(byte[])"/>.
+		/// </summary>
+		/// <param name="key">Key.</param>
+		/// <exception cref="System.ArgumentException">if the key is of the wrong length, or has invalid bits set
+		///           in the <code>r</code> portion of the key.</exception>
+		public static void CheckKey(byte[] key)
+		{
+			if (key.Length != 32)
+			{
+				throw new ArgumentException("Poly1305 key must be 256 bits.");
+			}
+
+			checkMask(key[19], R_MASK_HIGH_4);
+			checkMask(key[23], R_MASK_HIGH_4);
+			checkMask(key[27], R_MASK_HIGH_4);
+			checkMask(key[31], R_MASK_HIGH_4);
+
+			checkMask(key[20], R_MASK_LOW_2);
+			checkMask(key[24], R_MASK_LOW_2);
+			checkMask(key[28], R_MASK_LOW_2);
+		}
+
+		private static void checkMask(byte b, byte mask)
+		{
+			if ((b & (~mask)) != 0)
+			{
+				throw new ArgumentException("Invalid format for r portion of Poly1305 key.");
+			}
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/generators/RSABlindingFactorGenerator.cs b/crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
new file mode 100644
index 000000000..e2f63face
--- /dev/null
+++ b/crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/**
+	* Generate a random factor suitable for use with RSA blind signatures
+	* as outlined in Chaum's blinding and unblinding as outlined in
+	* "Handbook of Applied Cryptography", page 475.
+	*/
+	public class RsaBlindingFactorGenerator
+	{
+		private RsaKeyParameters key;
+		private SecureRandom random;
+
+		/**
+		* Initialise the factor generator
+		*
+		* @param param the necessary RSA key parameters.
+		*/
+		public void Init(
+			ICipherParameters param)
+		{
+			if (param is ParametersWithRandom)
+			{
+				ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+				key = (RsaKeyParameters)rParam.Parameters;
+				random = rParam.Random;
+			}
+			else
+			{
+				key = (RsaKeyParameters)param;
+				random = new SecureRandom();
+			}
+
+			if (key.IsPrivate)
+				throw new ArgumentException("generator requires RSA public key");
+		}
+
+		/**
+		* Generate a suitable blind factor for the public key the generator was initialised with.
+		*
+		* @return a random blind factor
+		*/
+		public BigInteger GenerateBlindingFactor()
+		{
+			if (key == null)
+				throw new InvalidOperationException("generator not initialised");
+
+			BigInteger m = key.Modulus;
+			int length = m.BitLength - 1; // must be less than m.BitLength
+			BigInteger factor;
+			BigInteger gcd;
+
+			do
+			{
+				factor = new BigInteger(length, random);
+				gcd = factor.Gcd(m);
+			}
+			while (factor.SignValue == 0 || factor.Equals(BigInteger.One) || !gcd.Equals(BigInteger.One));
+
+			return factor;
+		}
+	}
+}
diff --git a/crypto/src/crypto/generators/RsaKeyPairGenerator.cs b/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
index 3074aed04..e870f1c08 100644
--- a/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/RsaKeyPairGenerator.cs
@@ -3,6 +3,7 @@ using System;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Multiplier;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
@@ -10,107 +11,95 @@ namespace Org.BouncyCastle.Crypto.Generators
      * an RSA key pair generator.
      */
     public class RsaKeyPairGenerator
-		: IAsymmetricCipherKeyPairGenerator
+        : IAsymmetricCipherKeyPairGenerator
     {
-		private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
-		private const int DefaultTests = 12;
+        private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
+        private const int DefaultTests = 12;
 
-		private RsaKeyGenerationParameters param;
+        private RsaKeyGenerationParameters param;
 
-		public void Init(
+        public void Init(
             KeyGenerationParameters parameters)
         {
-			if (parameters is RsaKeyGenerationParameters)
-			{
-				this.param = (RsaKeyGenerationParameters)parameters;
-			}
-			else
-			{
-				this.param = new RsaKeyGenerationParameters(
-					DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
-			}
+            if (parameters is RsaKeyGenerationParameters)
+            {
+                this.param = (RsaKeyGenerationParameters)parameters;
+            }
+            else
+            {
+                this.param = new RsaKeyGenerationParameters(
+                    DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
+            }
         }
 
-		public AsymmetricCipherKeyPair GenerateKeyPair()
+        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.Strength;
-            int pbitlength = (strength + 1) / 2;
-            int qbitlength = (strength - pbitlength);
-			int mindiffbits = strength / 3;
-
-			e = param.PublicExponent;
-
-			// 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.Random);
+            int strength = param.Strength;
+            int qBitlength = strength >> 1;
+            int pBitlength = strength - qBitlength;
+            int mindiffbits = strength / 3;
+            int minWeight = strength >> 2;
 
-				if (p.Mod(e).Equals(BigInteger.One))
-					continue;
+            e = param.PublicExponent;
 
-				if (!p.IsProbablePrime(param.Certainty))
-					continue;
+            // 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")
 
-				if (e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One)) 
-					break;
-			}
+            p = ChooseRandomPrime(pBitlength, e);
 
             //
             // 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.Random);
+                q = ChooseRandomPrime(qBitlength, e);
 
-					if (q.Subtract(p).Abs().BitLength < mindiffbits)
-						continue;
-
-					if (q.Mod(e).Equals(BigInteger.One))
-						continue;
-
-					if (!q.IsProbablePrime(param.Certainty))
-						continue;
-
-					if (e.Gcd(q.Subtract(BigInteger.One)).Equals(BigInteger.One)) 
-						break;
-				}
+                // p and q should not be too close together (or equal!)
+                BigInteger diff = q.Subtract(p).Abs();
+                if (diff.BitLength < mindiffbits)
+                    continue;
 
                 //
                 // calculate the modulus
                 //
                 n = p.Multiply(q);
 
-                if (n.BitLength == param.Strength)
-					break;
+                if (n.BitLength != strength)
+                {
+                    //
+                    // if we get here our primes aren't big enough, make the largest
+                    // of the two p and try again
+                    //
+                    p = p.Max(q);
+                    continue;
+                }
+
+                /*
+                 * Require a minimum weight of the NAF representation, since low-weight composites may
+                 * be weak against a version of the number-field-sieve for factoring.
+                 * 
+                 * See "The number field sieve for integers of low weight", Oliver Schirokauer.
+                 */
+                if (WNafUtilities.GetNafWeight(n) < minWeight)
+                {
+                    p = ChooseRandomPrime(pBitlength, e);
+                    continue;
+                }
 
-                //
-                // if we Get here our primes aren't big enough, make the largest
-                // of the two p and try again
-                //
-                p = p.Max(q);
+                break;
             }
 
-			if (p.CompareTo(q) < 0)
-			{
-				phi = p;
-				p = q;
-				q = phi;
-			}
+            if (p.CompareTo(q) < 0)
+            {
+                phi = p;
+                p = q;
+                q = phi;
+            }
 
             pSub1 = p.Subtract(BigInteger.One);
             qSub1 = q.Subtract(BigInteger.One);
@@ -134,6 +123,28 @@ namespace Org.BouncyCastle.Crypto.Generators
                 new RsaKeyParameters(false, n, e),
                 new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
         }
-    }
 
+        /// <summary>Choose a random prime value for use with RSA</summary>
+        /// <param name="bitlength">the bit-length of the returned prime</param>
+        /// <param name="e">the RSA public exponent</param>
+        /// <returns>a prime p, with (p-1) relatively prime to e</returns>
+        protected virtual BigInteger ChooseRandomPrime(int bitlength, BigInteger e)
+        {
+            for (;;)
+            {
+                BigInteger p = new BigInteger(bitlength, 1, param.Random);
+
+                if (p.Mod(e).Equals(BigInteger.One))
+                    continue;
+
+                if (!p.IsProbablePrime(param.Certainty))
+                    continue;
+
+                if (!e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One))
+                    continue;
+
+                return p;
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs
new file mode 100644
index 000000000..efa74d735
--- /dev/null
+++ b/crypto/src/crypto/generators/SCrypt.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Threading;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	public class SCrypt
+	{
+		// TODO Validate arguments
+		public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+		{
+			return MFcrypt(P, S, N, r, p, dkLen);
+		}
+
+		private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+		{
+			int MFLenBytes = r * 128;
+			byte[] bytes = SingleIterationPBKDF2(P, S, p * MFLenBytes);
+
+			uint[] B = null;
+
+			try
+			{
+				int BLen = bytes.Length >> 2;
+				B = new uint[BLen];
+
+				Pack.LE_To_UInt32(bytes, 0, B);
+
+				int MFLenWords = MFLenBytes >> 2;
+				for (int BOff = 0; BOff < BLen; BOff += MFLenWords)
+				{
+					// TODO These can be done in parallel threads
+					SMix(B, BOff, N, r);
+				}
+
+				Pack.UInt32_To_LE(B, bytes, 0);
+
+				return SingleIterationPBKDF2(P, bytes, dkLen);
+			}
+			finally
+			{
+				ClearAll(bytes, B);
+			}
+		}
+
+		private static byte[] SingleIterationPBKDF2(byte[] P, byte[] S, int dkLen)
+		{
+			PbeParametersGenerator pGen = new Pkcs5S2ParametersGenerator(new Sha256Digest());
+			pGen.Init(P, S, 1);
+			KeyParameter key = (KeyParameter)pGen.GenerateDerivedMacParameters(dkLen * 8);
+			return key.GetKey();
+		}
+
+		private static void SMix(uint[] B, int BOff, int N, int r)
+		{
+			int BCount = r * 32;
+
+			uint[] blockX1 = new uint[16];
+			uint[] blockX2 = new uint[16];
+			uint[] blockY = new uint[BCount];
+
+			uint[] X = new uint[BCount];
+			uint[][] V = new uint[N][];
+
+			try
+			{
+				Array.Copy(B, BOff, X, 0, BCount);
+
+				for (int i = 0; i < N; ++i)
+				{
+					V[i] = (uint[])X.Clone();
+					BlockMix(X, blockX1, blockX2, blockY, r);
+				}
+
+				uint mask = (uint)N - 1;
+				for (int i = 0; i < N; ++i)
+				{
+					uint j = X[BCount - 16] & mask;
+					Xor(X, V[j], 0, X);
+					BlockMix(X, blockX1, blockX2, blockY, r);
+				}
+
+				Array.Copy(X, 0, B, BOff, BCount);
+			}
+			finally
+			{
+				ClearAll(V);
+				ClearAll(X, blockX1, blockX2, blockY);
+			}
+		}
+
+		private static void BlockMix(uint[] B, uint[] X1, uint[] X2, uint[] Y, int r)
+		{
+			Array.Copy(B, B.Length - 16, X1, 0, 16);
+
+			int BOff = 0, YOff = 0, halfLen = B.Length >> 1;
+
+			for (int i = 2 * r; i > 0; --i)
+			{
+				Xor(X1, B, BOff, X2);
+
+				Salsa20Engine.SalsaCore(8, X2, X1);
+				Array.Copy(X1, 0, Y, YOff, 16);
+
+				YOff = halfLen + BOff - YOff;
+				BOff += 16;
+			}
+
+			Array.Copy(Y, 0, B, 0, Y.Length);
+		}
+
+		private static void Xor(uint[] a, uint[] b, int bOff, uint[] output)
+		{
+			for (int i = output.Length - 1; i >= 0; --i)
+			{
+				output[i] = a[i] ^ b[bOff + i];
+			}
+		}
+
+		private static void Clear(Array array)
+		{
+			if (array != null)
+			{
+				Array.Clear(array, 0, array.Length);
+			}
+		}
+
+		private static void ClearAll(params Array[] arrays)
+		{
+			foreach (Array array in arrays)
+			{
+				Clear(array);
+			}
+		}
+	}
+}
diff --git a/crypto/src/crypto/io/CipherStream.cs b/crypto/src/crypto/io/CipherStream.cs
index bf7effb0a..b6920854d 100644
--- a/crypto/src/crypto/io/CipherStream.cs
+++ b/crypto/src/crypto/io/CipherStream.cs
@@ -201,18 +201,15 @@ namespace Org.BouncyCastle.Crypto.IO
             set { throw new NotSupportedException(); }
         }
 
-        protected override void Dispose(bool disposing)
+		public override void Close()
         {
-            if (disposing)
-            {
-                if (outCipher != null)
-                {
-                    byte[] data = outCipher.DoFinal();
-                    stream.Write(data, 0, data.Length);
-                    stream.Flush();
-                }
-                stream.Dispose();
-            }
+			if (outCipher != null)
+			{
+				byte[] data = outCipher.DoFinal();
+				stream.Write(data, 0, data.Length);
+				stream.Flush();
+			}
+			stream.Close();
         }
 
 		public override void Flush()
diff --git a/crypto/src/crypto/io/DigestStream.cs b/crypto/src/crypto/io/DigestStream.cs
index a5b31f95c..c819a409a 100644
--- a/crypto/src/crypto/io/DigestStream.cs
+++ b/crypto/src/crypto/io/DigestStream.cs
@@ -110,13 +110,10 @@ namespace Org.BouncyCastle.Crypto.IO
 			set { stream.Position = value; }
 		}
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                stream.Dispose();
-            }
-        }
+		public override void Close()
+		{
+			stream.Close();
+		}
 
 		public override  void Flush()
 		{
diff --git a/crypto/src/crypto/io/MacStream.cs b/crypto/src/crypto/io/MacStream.cs
index 419eafb77..51cf1832e 100644
--- a/crypto/src/crypto/io/MacStream.cs
+++ b/crypto/src/crypto/io/MacStream.cs
@@ -109,13 +109,10 @@ namespace Org.BouncyCastle.Crypto.IO
 			set { stream.Position = value; }
 		}
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                stream.Dispose();
-            }
-        }
+		public override void Close()
+		{
+			stream.Close();
+		}
 
 		public override void Flush()
 		{
diff --git a/crypto/src/crypto/io/SignerStream.cs b/crypto/src/crypto/io/SignerStream.cs
index 8be8ca84a..49dfb38c6 100644
--- a/crypto/src/crypto/io/SignerStream.cs
+++ b/crypto/src/crypto/io/SignerStream.cs
@@ -110,13 +110,10 @@ namespace Org.BouncyCastle.Crypto.IO
 			set { stream.Position = value; }
 		}
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                stream.Dispose();
-            }
-        }
+		public override void Close()
+		{
+			stream.Close();
+		}
 
 		public override  void Flush()
 		{
diff --git a/crypto/src/crypto/macs/CMac.cs b/crypto/src/crypto/macs/CMac.cs
index ea1ce88f5..682c12bac 100644
--- a/crypto/src/crypto/macs/CMac.cs
+++ b/crypto/src/crypto/macs/CMac.cs
@@ -2,239 +2,256 @@ using System;
 
 using Org.BouncyCastle.Crypto.Modes;
 using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Macs
 {
-	/**
-	* CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
-	* <p>
-	* CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC
-	* </p><p>
-	* CMAC is a NIST recomendation - see 
-	* csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
-	* </p><p>
-	* CMAC/OMAC1 is a blockcipher-based message authentication code designed and
-	* analyzed by Tetsu Iwata and Kaoru Kurosawa.
-	* </p><p>
-	* CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message 
-	* Authentication Code). OMAC stands for One-Key CBC MAC.
-	* </p><p>
-	* It supports 128- or 64-bits block ciphers, with any key size, and returns
-	* a MAC with dimension less or equal to the block size of the underlying 
-	* cipher.
-	* </p>
-	*/
-	public class CMac
-		: IMac
-	{
-		private const byte CONSTANT_128 = (byte)0x87;
-		private const byte CONSTANT_64 = (byte)0x1b;
-
-		private byte[] ZEROES;
-
-		private byte[] mac;
-
-		private byte[] buf;
-		private int bufOff;
-		private IBlockCipher cipher;
-
-		private int macSize;
-
-		private byte[] L, Lu, Lu2;
-
-		/**
-		* create a standard MAC based on a CBC block cipher (64 or 128 bit block).
-		* This will produce an authentication code the length of the block size
-		* of the cipher.
-		*
-		* @param cipher the cipher to be used as the basis of the MAC generation.
-		*/
-		public CMac(
-			IBlockCipher cipher)
-			: this(cipher, cipher.GetBlockSize() * 8)
-		{
-		}
-
-		/**
-		* create a standard MAC based on a block cipher with the size of the
-		* MAC been given in bits.
-		* <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 and @lt;= 128.
-		*/
-		public CMac(
-			IBlockCipher	cipher,
-			int				macSizeInBits)
-		{
-			if ((macSizeInBits % 8) != 0)
-				throw new ArgumentException("MAC size must be multiple of 8");
-
-			if (macSizeInBits > (cipher.GetBlockSize() * 8))
-			{
-				throw new ArgumentException(
-					"MAC size must be less or equal to "
-						+ (cipher.GetBlockSize() * 8));
-			}
-
-			if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16)
-			{
-				throw new ArgumentException(
-					"Block size must be either 64 or 128 bits");
-			}
-
-			this.cipher = new CbcBlockCipher(cipher);
-			this.macSize = macSizeInBits / 8;
-
-			mac = new byte[cipher.GetBlockSize()];
-
-			buf = new byte[cipher.GetBlockSize()];
-
-			ZEROES = new byte[cipher.GetBlockSize()];
-
-			bufOff = 0;
-		}
-
-		public string AlgorithmName
-		{
-			get { return cipher.AlgorithmName; }
-		}
-
-		private byte[] doubleLu(
-			byte[] inBytes)
-		{
-			int FirstBit = (inBytes[0] & 0xFF) >> 7;
-			byte[] ret = new byte[inBytes.Length];
-			for (int i = 0; i < inBytes.Length - 1; i++)
-			{
-				ret[i] = (byte)((inBytes[i] << 1) + ((inBytes[i + 1] & 0xFF) >> 7));
-			}
-			ret[inBytes.Length - 1] = (byte)(inBytes[inBytes.Length - 1] << 1);
-			if (FirstBit == 1)
-			{
-				ret[inBytes.Length - 1] ^= inBytes.Length == 16 ? CONSTANT_128 : CONSTANT_64;
-			}
-			return ret;
-		}
-
-		public void Init(
-			ICipherParameters parameters)
-		{
-			Reset();
-
-			cipher.Init(true, parameters);
-
-			//initializes the L, Lu, Lu2 numbers
-			L = new byte[ZEROES.Length];
-			cipher.ProcessBlock(ZEROES, 0, L, 0);
-			Lu = doubleLu(L);
-			Lu2 = doubleLu(Lu);
-
-			cipher.Init(true, parameters);
-		}
-
-		public int GetMacSize()
-		{
-			return macSize;
-		}
-
-		public void Update(
-			byte input)
-		{
-			if (bufOff == buf.Length)
-			{
-				cipher.ProcessBlock(buf, 0, mac, 0);
-				bufOff = 0;
-			}
-
-			buf[bufOff++] = input;
-		}
-
-		public void BlockUpdate(
-			byte[]	inBytes,
-			int		inOff,
-			int		len)
-		{
-			if (len < 0)
-				throw new ArgumentException("Can't have a negative input length!");
-
-			int blockSize = cipher.GetBlockSize();
-			int gapLen = blockSize - bufOff;
-
-			if (len > gapLen)
-			{
-				Array.Copy(inBytes, inOff, buf, bufOff, gapLen);
-
-				cipher.ProcessBlock(buf, 0, mac, 0);
-
-				bufOff = 0;
-				len -= gapLen;
-				inOff += gapLen;
-
-				while (len > blockSize)
-				{
-					cipher.ProcessBlock(inBytes, inOff, mac, 0);
-
-					len -= blockSize;
-					inOff += blockSize;
-				}
-			}
-
-			Array.Copy(inBytes, inOff, buf, bufOff, len);
-
-			bufOff += len;
-		}
-
-		public int DoFinal(
-			byte[]	outBytes,
-			int		outOff)
-		{
-			int blockSize = cipher.GetBlockSize();
-
-			byte[] lu;
-			if (bufOff == blockSize)
-			{
-				lu = Lu;
-			}
-			else
-			{
-				new ISO7816d4Padding().AddPadding(buf, bufOff);
-				lu = Lu2;
-			}
-
-			for (int i = 0; i < mac.Length; i++)
-			{
-				buf[i] ^= lu[i];
-			}
-
-			cipher.ProcessBlock(buf, 0, mac, 0);
-
-			Array.Copy(mac, 0, outBytes, outOff, macSize);
-
-			Reset();
-
-			return macSize;
-		}
-
-		/**
-		* Reset the mac generator.
-		*/
-		public void Reset()
-		{
-			/*
-			* clean the buffer.
-			*/
-			Array.Clear(buf, 0, buf.Length);
-			bufOff = 0;
-
-			/*
-			* Reset the underlying cipher.
-			*/
-			cipher.Reset();
-		}
-	}
+    /**
+    * CMAC - as specified at www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/omac.html
+    * <p>
+    * CMAC is analogous to OMAC1 - see also en.wikipedia.org/wiki/CMAC
+    * </p><p>
+    * CMAC is a NIST recomendation - see 
+    * csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+    * </p><p>
+    * CMAC/OMAC1 is a blockcipher-based message authentication code designed and
+    * analyzed by Tetsu Iwata and Kaoru Kurosawa.
+    * </p><p>
+    * CMAC/OMAC1 is a simple variant of the CBC MAC (Cipher Block Chaining Message 
+    * Authentication Code). OMAC stands for One-Key CBC MAC.
+    * </p><p>
+    * It supports 128- or 64-bits block ciphers, with any key size, and returns
+    * a MAC with dimension less or equal to the block size of the underlying 
+    * cipher.
+    * </p>
+    */
+    public class CMac
+        : IMac
+    {
+        private const byte CONSTANT_128 = (byte)0x87;
+        private const byte CONSTANT_64 = (byte)0x1b;
+
+        private byte[] ZEROES;
+
+        private byte[] mac;
+
+        private byte[] buf;
+        private int bufOff;
+        private IBlockCipher cipher;
+
+        private int macSize;
+
+        private byte[] L, Lu, Lu2;
+
+        /**
+        * create a standard MAC based on a CBC block cipher (64 or 128 bit block).
+        * This will produce an authentication code the length of the block size
+        * of the cipher.
+        *
+        * @param cipher the cipher to be used as the basis of the MAC generation.
+        */
+        public CMac(
+            IBlockCipher cipher)
+            : this(cipher, cipher.GetBlockSize() * 8)
+        {
+        }
+
+        /**
+        * create a standard MAC based on a block cipher with the size of the
+        * MAC been given in bits.
+        * <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 and @lt;= 128.
+        */
+        public CMac(
+            IBlockCipher	cipher,
+            int				macSizeInBits)
+        {
+            if ((macSizeInBits % 8) != 0)
+                throw new ArgumentException("MAC size must be multiple of 8");
+
+            if (macSizeInBits > (cipher.GetBlockSize() * 8))
+            {
+                throw new ArgumentException(
+                    "MAC size must be less or equal to "
+                        + (cipher.GetBlockSize() * 8));
+            }
+
+            if (cipher.GetBlockSize() != 8 && cipher.GetBlockSize() != 16)
+            {
+                throw new ArgumentException(
+                    "Block size must be either 64 or 128 bits");
+            }
+
+            this.cipher = new CbcBlockCipher(cipher);
+            this.macSize = macSizeInBits / 8;
+
+            mac = new byte[cipher.GetBlockSize()];
+
+            buf = new byte[cipher.GetBlockSize()];
+
+            ZEROES = new byte[cipher.GetBlockSize()];
+
+            bufOff = 0;
+        }
+
+        public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName; }
+        }
+
+        private static int ShiftLeft(byte[] block, byte[] output)
+        {
+            int i = block.Length;
+            uint bit = 0;
+            while (--i >= 0)
+            {
+                uint b = block[i];
+                output[i] = (byte)((b << 1) | bit);
+                bit = (b >> 7) & 1;
+            }
+            return (int)bit;
+        }
+
+        private static byte[] DoubleLu(byte[] input)
+        {
+            byte[] ret = new byte[input.Length];
+            int carry = ShiftLeft(input, ret);
+            int xor = input.Length == 16 ? CONSTANT_128 : CONSTANT_64;
+
+            /*
+             * NOTE: This construction is an attempt at a constant-time implementation.
+             */
+            ret[input.Length - 1] ^= (byte)(xor >> ((1 - carry) << 3));
+
+            return ret;
+        }
+
+        public void Init(
+            ICipherParameters parameters)
+        {
+            if (parameters is KeyParameter)
+            {
+                cipher.Init(true, parameters);
+
+                //initializes the L, Lu, Lu2 numbers
+                L = new byte[ZEROES.Length];
+                cipher.ProcessBlock(ZEROES, 0, L, 0);
+                Lu = DoubleLu(L);
+                Lu2 = DoubleLu(Lu);
+            }
+            else if (parameters != null)
+            {
+                // CMAC mode does not permit IV to underlying CBC mode
+                throw new ArgumentException("CMac mode only permits key to be set.", "parameters");
+            }
+
+            Reset();
+        }
+
+        public int GetMacSize()
+        {
+            return macSize;
+        }
+
+        public void Update(
+            byte input)
+        {
+            if (bufOff == buf.Length)
+            {
+                cipher.ProcessBlock(buf, 0, mac, 0);
+                bufOff = 0;
+            }
+
+            buf[bufOff++] = input;
+        }
+
+        public void BlockUpdate(
+            byte[]	inBytes,
+            int		inOff,
+            int		len)
+        {
+            if (len < 0)
+                throw new ArgumentException("Can't have a negative input length!");
+
+            int blockSize = cipher.GetBlockSize();
+            int gapLen = blockSize - bufOff;
+
+            if (len > gapLen)
+            {
+                Array.Copy(inBytes, inOff, buf, bufOff, gapLen);
+
+                cipher.ProcessBlock(buf, 0, mac, 0);
+
+                bufOff = 0;
+                len -= gapLen;
+                inOff += gapLen;
+
+                while (len > blockSize)
+                {
+                    cipher.ProcessBlock(inBytes, inOff, mac, 0);
+
+                    len -= blockSize;
+                    inOff += blockSize;
+                }
+            }
+
+            Array.Copy(inBytes, inOff, buf, bufOff, len);
+
+            bufOff += len;
+        }
+
+        public int DoFinal(
+            byte[]	outBytes,
+            int		outOff)
+        {
+            int blockSize = cipher.GetBlockSize();
+
+            byte[] lu;
+            if (bufOff == blockSize)
+            {
+                lu = Lu;
+            }
+            else
+            {
+                new ISO7816d4Padding().AddPadding(buf, bufOff);
+                lu = Lu2;
+            }
+
+            for (int i = 0; i < mac.Length; i++)
+            {
+                buf[i] ^= lu[i];
+            }
+
+            cipher.ProcessBlock(buf, 0, mac, 0);
+
+            Array.Copy(mac, 0, outBytes, outOff, macSize);
+
+            Reset();
+
+            return macSize;
+        }
+
+        /**
+        * Reset the mac generator.
+        */
+        public void Reset()
+        {
+            /*
+            * clean the buffer.
+            */
+            Array.Clear(buf, 0, buf.Length);
+            bufOff = 0;
+
+            /*
+            * Reset the underlying cipher.
+            */
+            cipher.Reset();
+        }
+    }
 }
diff --git a/crypto/src/crypto/macs/CbcBlockCipherMac.cs b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
new file mode 100644
index 000000000..146e16aa8
--- /dev/null
+++ b/crypto/src/crypto/macs/CbcBlockCipherMac.cs
@@ -0,0 +1,209 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+    /**
+    * standard CBC Block Cipher MAC - if no padding is specified the default of
+    * pad of zeroes is used.
+    */
+    public class CbcBlockCipherMac
+		: IMac
+    {
+        private byte[] buf;
+        private int bufOff;
+        private IBlockCipher cipher;
+        private IBlockCipherPadding 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(
+			IBlockCipher 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(
+            IBlockCipher		cipher,
+            IBlockCipherPadding	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).
+        * </p>
+        * @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(
+            IBlockCipher	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).
+        * </p>
+        * @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(
+            IBlockCipher		cipher,
+            int					macSizeInBits,
+            IBlockCipherPadding	padding)
+        {
+            if ((macSizeInBits % 8) != 0)
+                throw new ArgumentException("MAC size must be multiple of 8");
+
+			this.cipher = new CbcBlockCipher(cipher);
+            this.padding = padding;
+            this.macSize = macSizeInBits / 8;
+
+			buf = new byte[cipher.GetBlockSize()];
+            bufOff = 0;
+        }
+
+		public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName; }
+        }
+
+		public void Init(
+            ICipherParameters parameters)
+        {
+            Reset();
+
+			cipher.Init(true, parameters);
+        }
+
+		public int GetMacSize()
+        {
+            return macSize;
+        }
+
+		public void Update(
+            byte input)
+        {
+			if (bufOff == buf.Length)
+            {
+				cipher.ProcessBlock(buf, 0, buf, 0);
+                bufOff = 0;
+            }
+
+			buf[bufOff++] = input;
+        }
+
+        public void BlockUpdate(
+            byte[]	input,
+            int		inOff,
+            int		len)
+        {
+            if (len < 0)
+                throw new ArgumentException("Can't have a negative input length!");
+
+			int blockSize = cipher.GetBlockSize();
+            int gapLen = blockSize - bufOff;
+
+            if (len > gapLen)
+            {
+                Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+                cipher.ProcessBlock(buf, 0, buf, 0);
+
+                bufOff = 0;
+                len -= gapLen;
+                inOff += gapLen;
+
+                while (len > blockSize)
+                {
+                    cipher.ProcessBlock(input, inOff, buf, 0);
+
+                    len -= blockSize;
+                    inOff += blockSize;
+                }
+            }
+
+            Array.Copy(input, inOff, buf, bufOff, len);
+
+            bufOff += len;
+        }
+
+        public int DoFinal(
+            byte[]	output,
+            int		outOff)
+        {
+            int blockSize = cipher.GetBlockSize();
+
+            if (padding == null)
+            {
+                // pad with zeroes
+                while (bufOff < blockSize)
+                {
+                    buf[bufOff++] = 0;
+                }
+            }
+            else
+            {
+                if (bufOff == blockSize)
+                {
+                    cipher.ProcessBlock(buf, 0, buf, 0);
+                    bufOff = 0;
+                }
+
+				padding.AddPadding(buf, bufOff);
+            }
+
+			cipher.ProcessBlock(buf, 0, buf, 0);
+
+			Array.Copy(buf, 0, output, outOff, macSize);
+
+			Reset();
+
+			return macSize;
+        }
+
+		/**
+        * Reset the mac generator.
+        */
+        public void Reset()
+        {
+            // Clear the buffer.
+			Array.Clear(buf, 0, buf.Length);
+			bufOff = 0;
+
+			// Reset the underlying cipher.
+            cipher.Reset();
+        }
+    }
+}
diff --git a/crypto/src/crypto/macs/CfbBlockCipherMac.cs b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
new file mode 100644
index 000000000..364cf8499
--- /dev/null
+++ b/crypto/src/crypto/macs/CfbBlockCipherMac.cs
@@ -0,0 +1,368 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+    /**
+    * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+    */
+    class MacCFBBlockCipher
+		: IBlockCipher
+    {
+        private byte[] IV;
+        private byte[] cfbV;
+        private byte[] cfbOutV;
+
+		private readonly int blockSize;
+        private readonly IBlockCipher 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 MacCFBBlockCipher(
+            IBlockCipher	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()];
+        }
+
+		/**
+        * 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 param the key and other data required by the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+		public void Init(
+			bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+			if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParam = (ParametersWithIV)parameters;
+                byte[] iv = ivParam.GetIV();
+
+                if (iv.Length < IV.Length)
+                {
+                    Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+                }
+                else
+                {
+                    Array.Copy(iv, 0, IV, 0, IV.Length);
+                }
+
+				parameters = ivParam.Parameters;
+            }
+
+			Reset();
+
+			cipher.Init(true, parameters);
+        }
+
+        /**
+        * return the algorithm name and mode.
+        *
+        * @return the name of the underlying algorithm followed by "/CFB"
+        * and the block size in bits.
+        */
+        public string AlgorithmName
+        {
+			get { return cipher.AlgorithmName + "/CFB" + (blockSize * 8); }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return true; }
+		}
+
+		/**
+        * 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 InvalidOperationException if the cipher isn't initialised.
+        * @return the number of bytes processed and produced.
+        */
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	outBytes,
+            int		outOff)
+        {
+            if ((inOff + blockSize) > input.Length)
+                throw new DataLengthException("input buffer too short");
+
+			if ((outOff + blockSize) > outBytes.Length)
+                throw new DataLengthException("output buffer too short");
+
+			cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+
+            //
+            // XOR the cfbV with the plaintext producing the cipher text
+            //
+            for (int i = 0; i < blockSize; i++)
+            {
+                outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+            }
+
+			//
+            // change over the input block.
+            //
+            Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+            Array.Copy(outBytes, outOff, cfbV, cfbV.Length - blockSize, blockSize);
+
+			return blockSize;
+        }
+
+		/**
+        * reset the chaining vector back to the IV and reset the underlying
+        * cipher.
+        */
+        public void Reset()
+        {
+			IV.CopyTo(cfbV, 0);
+
+			cipher.Reset();
+        }
+
+		public void GetMacBlock(
+            byte[] mac)
+        {
+            cipher.ProcessBlock(cfbV, 0, mac, 0);
+        }
+    }
+
+	public class CfbBlockCipherMac
+		: IMac
+    {
+        private byte[] mac;
+        private byte[] Buffer;
+        private int bufOff;
+        private MacCFBBlockCipher cipher;
+        private IBlockCipherPadding padding;
+        private int macSize;
+
+		/**
+        * create a standard MAC based on a CFB block cipher. This will produce an
+        * authentication code half the length of the block size of the cipher, with
+        * the CFB mode set to 8 bits.
+        *
+        * @param cipher the cipher to be used as the basis of the MAC generation.
+        */
+        public CfbBlockCipherMac(
+            IBlockCipher cipher)
+			: this(cipher, 8, (cipher.GetBlockSize() * 8) / 2, null)
+		{
+		}
+
+		/**
+        * create a standard MAC based on a CFB block cipher. This will produce an
+        * authentication code half the length of the block size of the cipher, with
+        * the CFB mode set to 8 bits.
+        *
+        * @param cipher the cipher to be used as the basis of the MAC generation.
+        * @param padding the padding to be used.
+        */
+        public CfbBlockCipherMac(
+            IBlockCipher		cipher,
+            IBlockCipherPadding	padding)
+			: this(cipher, 8, (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 CFB 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).
+        * </p>
+        * @param cipher the cipher to be used as the basis of the MAC generation.
+        * @param cfbBitSize the size of an output block produced by the CFB mode.
+        * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+        */
+        public CfbBlockCipherMac(
+            IBlockCipher	cipher,
+            int				cfbBitSize,
+            int				macSizeInBits)
+			: this(cipher, cfbBitSize, macSizeInBits, null)
+		{
+		}
+
+		/**
+        * create a standard MAC based on a block cipher with the size of the
+        * MAC been given in bits. This class uses CFB 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).
+        * </p>
+        * @param cipher the cipher to be used as the basis of the MAC generation.
+        * @param cfbBitSize the size of an output block produced by the CFB mode.
+        * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+        * @param padding a padding to be used.
+        */
+        public CfbBlockCipherMac(
+            IBlockCipher		cipher,
+            int					cfbBitSize,
+            int					macSizeInBits,
+            IBlockCipherPadding	padding)
+        {
+            if ((macSizeInBits % 8) != 0)
+                throw new ArgumentException("MAC size must be multiple of 8");
+
+			mac = new byte[cipher.GetBlockSize()];
+
+			this.cipher = new MacCFBBlockCipher(cipher, cfbBitSize);
+            this.padding = padding;
+            this.macSize = macSizeInBits / 8;
+
+			Buffer = new byte[this.cipher.GetBlockSize()];
+            bufOff = 0;
+        }
+
+		public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName; }
+        }
+
+		public void Init(
+            ICipherParameters parameters)
+        {
+            Reset();
+
+			cipher.Init(true, parameters);
+        }
+
+		public int GetMacSize()
+        {
+            return macSize;
+        }
+
+		public void Update(
+            byte input)
+        {
+            if (bufOff == Buffer.Length)
+            {
+				cipher.ProcessBlock(Buffer, 0, mac, 0);
+                bufOff = 0;
+            }
+
+			Buffer[bufOff++] = input;
+        }
+
+		public void BlockUpdate(
+            byte[]	input,
+            int		inOff,
+            int		len)
+        {
+            if (len < 0)
+                throw new ArgumentException("Can't have a negative input length!");
+
+			int blockSize = cipher.GetBlockSize();
+            int resultLen = 0;
+            int gapLen = blockSize - bufOff;
+
+			if (len > gapLen)
+            {
+                Array.Copy(input, inOff, Buffer, bufOff, gapLen);
+
+				resultLen += cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+				bufOff = 0;
+                len -= gapLen;
+                inOff += gapLen;
+
+				while (len > blockSize)
+                {
+                    resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
+
+					len -= blockSize;
+                    inOff += blockSize;
+                }
+            }
+
+			Array.Copy(input, inOff, Buffer, bufOff, len);
+
+			bufOff += len;
+        }
+
+		public int DoFinal(
+            byte[]	output,
+            int		outOff)
+        {
+            int blockSize = cipher.GetBlockSize();
+
+            // pad with zeroes
+            if (this.padding == null)
+            {
+                while (bufOff < blockSize)
+                {
+                    Buffer[bufOff++] = 0;
+                }
+            }
+            else
+            {
+                padding.AddPadding(Buffer, bufOff);
+            }
+
+			cipher.ProcessBlock(Buffer, 0, mac, 0);
+
+			cipher.GetMacBlock(mac);
+
+			Array.Copy(mac, 0, output, outOff, macSize);
+
+			Reset();
+
+			return macSize;
+        }
+
+        /**
+        * Reset the mac generator.
+        */
+        public void Reset()
+        {
+            // Clear the buffer.
+			Array.Clear(Buffer, 0, Buffer.Length);
+            bufOff = 0;
+
+			// Reset the underlying cipher.
+            cipher.Reset();
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/macs/GMac.cs b/crypto/src/crypto/macs/GMac.cs
new file mode 100644
index 000000000..f2c3990c6
--- /dev/null
+++ b/crypto/src/crypto/macs/GMac.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+    /// <summary>
+    /// The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
+    /// 800-38D.
+    /// </summary>
+    /// <remarks>
+    /// GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
+    /// is processed as additional authenticated data with the underlying GCM block cipher).
+    /// </remarks>
+    public class GMac 
+        : IMac
+    {
+        private readonly GcmBlockCipher cipher;
+        private readonly int macSizeBits;
+
+        /// <summary>
+        /// Creates a GMAC based on the operation of a block cipher in GCM mode.
+        /// </summary>
+        /// <remarks>
+        /// This will produce an authentication code the length of the block size of the cipher.
+        /// </remarks>
+        /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
+        public GMac(GcmBlockCipher cipher)
+            : this(cipher, 128)
+        {
+        }
+
+        /// <summary>
+        /// Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
+        /// </summary>
+        /// <remarks>
+        /// This will produce an authentication code the length of the block size of the cipher.
+        /// </remarks>
+        /// <param name="cipher">the cipher to be used in GCM mode to generate the MAC.</param>
+        /// <param name="macSizeBits">the mac size to generate, in bits. Must be a multiple of 8, between 32 and 128 (inclusive).
+        /// Sizes less than 96 are not recommended, but are supported for specialized applications.</param>
+        public GMac(GcmBlockCipher cipher, int macSizeBits)
+        {
+            this.cipher = cipher;
+            this.macSizeBits = macSizeBits;
+        }
+
+        /// <summary>
+        /// Initialises the GMAC - requires a <see cref="Org.BouncyCastle.Crypto.Parameters.ParametersWithIV"/> 
+        /// providing a <see cref="Org.BouncyCastle.Crypto.Parameters.KeyParameter"/> and a nonce.
+        /// </summary>
+        public void Init(ICipherParameters parameters)
+        {
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV param = (ParametersWithIV)parameters;
+
+                byte[] iv = param.GetIV();
+                KeyParameter keyParam = (KeyParameter)param.Parameters;
+
+                // GCM is always operated in encrypt mode to calculate MAC
+                cipher.Init(true, new AeadParameters(keyParam, macSizeBits, iv));
+            }
+            else
+            {
+                throw new ArgumentException("GMAC requires ParametersWithIV");
+            }
+        }
+
+        public string AlgorithmName
+        {
+            get { return cipher.GetUnderlyingCipher().AlgorithmName + "-GMAC"; }
+        }
+
+        public int GetMacSize()
+        {
+            return macSizeBits / 8;
+        }
+
+        public void Update(byte input) 
+        {
+            cipher.ProcessAadByte(input);
+        }
+
+        public void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            cipher.ProcessAadBytes(input, inOff, len);
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            try
+            {
+                return cipher.DoFinal(output, outOff);
+            }
+            catch (InvalidCipherTextException e)
+            {
+                // Impossible in encrypt mode
+                throw new InvalidOperationException(e.ToString());
+            }
+        }
+
+        public void Reset()
+        {
+            cipher.Reset();
+        }
+    }
+}
diff --git a/crypto/src/crypto/macs/GOST28147Mac.cs b/crypto/src/crypto/macs/GOST28147Mac.cs
new file mode 100644
index 000000000..9a8f1b730
--- /dev/null
+++ b/crypto/src/crypto/macs/GOST28147Mac.cs
@@ -0,0 +1,296 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+	/**
+	* implementation of GOST 28147-89 MAC
+	*/
+	public class Gost28147Mac : IMac
+	{
+		private const int			blockSize = 8;
+		private const int			macSize = 4;
+		private int					bufOff;
+		private byte[]				buf;
+		private byte[]				mac;
+		private bool				firstStep = true;
+		private int[]				workingKey;
+
+		//
+		// This is default S-box - E_A.
+		private byte[] S =
+		{
+			0x9,0x6,0x3,0x2,0x8,0xB,0x1,0x7,0xA,0x4,0xE,0xF,0xC,0x0,0xD,0x5,
+			0x3,0x7,0xE,0x9,0x8,0xA,0xF,0x0,0x5,0x2,0x6,0xC,0xB,0x4,0xD,0x1,
+			0xE,0x4,0x6,0x2,0xB,0x3,0xD,0x8,0xC,0xF,0x5,0xA,0x0,0x7,0x1,0x9,
+			0xE,0x7,0xA,0xC,0xD,0x1,0x3,0x9,0x0,0x2,0xB,0x4,0xF,0x8,0x5,0x6,
+			0xB,0x5,0x1,0x9,0x8,0xD,0xF,0x0,0xE,0x4,0x2,0x3,0xC,0x7,0xA,0x6,
+			0x3,0xA,0xD,0xC,0x1,0x2,0x0,0xB,0x7,0x5,0x9,0x4,0x8,0xF,0xE,0x6,
+			0x1,0xD,0x2,0x9,0x7,0xA,0x6,0x0,0x8,0xC,0x4,0x5,0xF,0x3,0xB,0xE,
+			0xB,0xA,0xF,0x5,0x0,0xC,0xE,0x8,0x6,0x2,0x3,0x9,0x1,0x7,0xD,0x4
+		};
+
+		public Gost28147Mac()
+		{
+			mac = new byte[blockSize];
+			buf = new byte[blockSize];
+			bufOff = 0;
+		}
+
+		private static int[] generateWorkingKey(
+			byte[] userKey)
+		{
+			if (userKey.Length != 32)
+				throw new ArgumentException("Key length invalid. Key needs to be 32 byte - 256 bit!!!");
+
+			int[] key = new int[8];
+			for(int i=0; i!=8; i++)
+			{
+				key[i] = bytesToint(userKey,i*4);
+			}
+
+			return key;
+		}
+
+		public void Init(
+			ICipherParameters parameters)
+		{
+			Reset();
+			buf = new byte[blockSize];
+			if (parameters is ParametersWithSBox)
+			{
+				ParametersWithSBox param = (ParametersWithSBox)parameters;
+
+				//
+				// Set the S-Box
+				//
+				param.GetSBox().CopyTo(this.S, 0);
+
+				//
+				// set key if there is one
+				//
+				if (param.Parameters != null)
+				{
+					workingKey = generateWorkingKey(((KeyParameter)param.Parameters).GetKey());
+				}
+			}
+			else if (parameters is KeyParameter)
+			{
+				workingKey = generateWorkingKey(((KeyParameter)parameters).GetKey());
+			}
+			else
+			{
+				throw new ArgumentException("invalid parameter passed to Gost28147 init - "
+					+ parameters.GetType().Name);
+			}
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Gost28147Mac"; }
+		}
+
+		public int GetMacSize()
+		{
+			return macSize;
+		}
+
+		private int gost28147_mainStep(int n1, int key)
+		{
+			int cm = (key + n1); // CM1
+
+			// S-box replacing
+
+			int om = S[  0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4);
+			om += S[ 16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4);
+			om += S[ 32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4);
+			om += S[ 48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4);
+			om += S[ 64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4);
+			om += S[ 80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4);
+			om += S[ 96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4);
+			om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4);
+
+//			return om << 11 | om >>> (32-11); // 11-leftshift
+			int omLeft = om << 11;
+			int omRight = (int)(((uint) om) >> (32 - 11)); // Note: Casts required to get unsigned bit rotation
+
+			return omLeft | omRight;
+		}
+
+		private void gost28147MacFunc(
+			int[]	workingKey,
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			int N1, N2, tmp;  //tmp -> for saving N1
+			N1 = bytesToint(input, inOff);
+			N2 = bytesToint(input, inOff + 4);
+
+			for (int k = 0; k < 2; k++)  // 1-16 steps
+			{
+				for (int j = 0; j < 8; j++)
+				{
+					tmp = N1;
+					N1 = N2 ^ gost28147_mainStep(N1, workingKey[j]); // CM2
+					N2 = tmp;
+				}
+			}
+
+			intTobytes(N1, output, outOff);
+			intTobytes(N2, output, outOff + 4);
+		}
+
+		//array of bytes to type int
+		private static int bytesToint(
+			byte[]	input,
+			int		inOff)
+		{
+			return (int)((input[inOff + 3] << 24) & 0xff000000) + ((input[inOff + 2] << 16) & 0xff0000)
+				+ ((input[inOff + 1] << 8) & 0xff00) + (input[inOff] & 0xff);
+		}
+
+		//int to array of bytes
+		private static void intTobytes(
+			int		num,
+			byte[]	output,
+			int		outOff)
+		{
+			output[outOff + 3] = (byte)(num >> 24);
+			output[outOff + 2] = (byte)(num >> 16);
+			output[outOff + 1] = (byte)(num >> 8);
+			output[outOff] =     (byte)num;
+		}
+
+		private static byte[] CM5func(
+			byte[]	buf,
+			int		bufOff,
+			byte[]	mac)
+		{
+			byte[] sum = new byte[buf.Length - bufOff];
+
+			Array.Copy(buf, bufOff, sum, 0, mac.Length);
+
+			for (int i = 0; i != mac.Length; i++)
+			{
+				sum[i] = (byte)(sum[i] ^ mac[i]);
+			}
+
+			return sum;
+		}
+
+		public void Update(
+			byte input)
+		{
+			if (bufOff == buf.Length)
+			{
+				byte[] sumbuf = new byte[buf.Length];
+				Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+				if (firstStep)
+				{
+					firstStep = false;
+				}
+				else
+				{
+					sumbuf = CM5func(buf, 0, mac);
+				}
+
+				gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+				bufOff = 0;
+			}
+
+			buf[bufOff++] = input;
+		}
+
+		public void BlockUpdate(
+			byte[]	input,
+			int		inOff,
+			int		len)
+		{
+			if (len < 0)
+				throw new ArgumentException("Can't have a negative input length!");
+
+			int gapLen = blockSize - bufOff;
+
+			if (len > gapLen)
+			{
+				Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+				byte[] sumbuf = new byte[buf.Length];
+				Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+				if (firstStep)
+				{
+					firstStep = false;
+				}
+				else
+				{
+					sumbuf = CM5func(buf, 0, mac);
+				}
+
+				gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+				bufOff = 0;
+				len -= gapLen;
+				inOff += gapLen;
+
+				while (len > blockSize)
+				{
+					sumbuf = CM5func(input, inOff, mac);
+					gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+					len -= blockSize;
+					inOff += blockSize;
+				}
+			}
+
+			Array.Copy(input, inOff, buf, bufOff, len);
+
+			bufOff += len;
+		}
+
+		public int DoFinal(
+			byte[]	output,
+			int		outOff)
+		{
+			//padding with zero
+			while (bufOff < blockSize)
+			{
+				buf[bufOff++] = 0;
+			}
+
+			byte[] sumbuf = new byte[buf.Length];
+			Array.Copy(buf, 0, sumbuf, 0, mac.Length);
+
+			if (firstStep)
+			{
+				firstStep = false;
+			}
+			else
+			{
+				sumbuf = CM5func(buf, 0, mac);
+			}
+
+			gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
+
+			Array.Copy(mac, (mac.Length/2)-macSize, output, outOff, macSize);
+
+			Reset();
+
+			return macSize;
+		}
+
+		public void Reset()
+		{
+			// Clear the buffer.
+			Array.Clear(buf, 0, buf.Length);
+			bufOff = 0;
+
+			firstStep = true;
+		}
+	}
+}
diff --git a/crypto/src/crypto/macs/HMac.cs b/crypto/src/crypto/macs/HMac.cs
index 3f9b0cef0..460f3c5a0 100644
--- a/crypto/src/crypto/macs/HMac.cs
+++ b/crypto/src/crypto/macs/HMac.cs
@@ -3,6 +3,7 @@ using System.Collections;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Macs
 {
@@ -20,32 +21,32 @@ namespace Org.BouncyCastle.Crypto.Macs
         private readonly IDigest digest;
         private readonly int digestSize;
         private readonly int blockLength;
+		private IMemoable ipadState;
+		private IMemoable opadState;
 
 		private readonly byte[] inputPad;
-        private readonly byte[] outputPad;
+        private readonly byte[] outputBuf;
 
-        public HMac(
-            IDigest digest)
+        public HMac(IDigest digest)
         {
             this.digest = digest;
             this.digestSize = digest.GetDigestSize();
             this.blockLength = digest.GetByteLength();
             this.inputPad = new byte[blockLength];
-            this.outputPad = new byte[blockLength];
+            this.outputBuf = new byte[blockLength + digestSize];
         }
 
-        public string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return digest.AlgorithmName + "/HMAC"; }
         }
 
-		public IDigest GetUnderlyingDigest()
+		public virtual IDigest GetUnderlyingDigest()
         {
             return digest;
         }
 
-        public void Init(
-            ICipherParameters parameters)
+        public virtual void Init(ICipherParameters parameters)
         {
             digest.Reset();
 
@@ -54,7 +55,7 @@ namespace Org.BouncyCastle.Crypto.Macs
 
             if (keyLength > blockLength)
             {
-                digest.BlockUpdate(key, 0, key.Length);
+                digest.BlockUpdate(key, 0, keyLength);
                 digest.DoFinal(inputPad, 0);
 
 				keyLength = digestSize;
@@ -65,48 +66,67 @@ namespace Org.BouncyCastle.Crypto.Macs
             }
 
 			Array.Clear(inputPad, keyLength, blockLength - keyLength);
-            Array.Copy(inputPad, 0, outputPad, 0, blockLength);
+            Array.Copy(inputPad, 0, outputBuf, 0, blockLength);
 
-			xor(inputPad, IPAD);
-			xor(outputPad, OPAD);
+			XorPad(inputPad, blockLength, IPAD);
+            XorPad(outputBuf, blockLength, OPAD);
+
+			if (digest is IMemoable)
+			{
+				opadState = ((IMemoable)digest).Copy();
+
+				((IDigest)opadState).BlockUpdate(outputBuf, 0, blockLength);
+			}
 
-			// Initialise the digest
 			digest.BlockUpdate(inputPad, 0, inputPad.Length);
+
+			if (digest is IMemoable)
+			{
+				ipadState = ((IMemoable)digest).Copy();
+			}
         }
 
-        public int GetMacSize()
+        public virtual int GetMacSize()
         {
             return digestSize;
         }
 
-        public void Update(
-            byte input)
+        public virtual void Update(byte input)
         {
             digest.Update(input);
         }
 
-        public void BlockUpdate(
-            byte[] input,
-            int inOff,
-            int len)
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
         {
             digest.BlockUpdate(input, inOff, len);
         }
 
-        public int DoFinal(
-            byte[] output,
-            int outOff)
+        public virtual int DoFinal(byte[] output, int outOff)
         {
-            byte[] tmp = new byte[digestSize];
-            digest.DoFinal(tmp, 0);
-
-            digest.BlockUpdate(outputPad, 0, outputPad.Length);
-            digest.BlockUpdate(tmp, 0, tmp.Length);
-
-            int len = digest.DoFinal(output, outOff);
-
-			// Initialise the digest
-            digest.BlockUpdate(inputPad, 0, inputPad.Length);
+            digest.DoFinal(outputBuf, blockLength);
+
+			if (opadState != null)
+			{
+				((IMemoable)digest).Reset(opadState);
+				digest.BlockUpdate(outputBuf, blockLength, digest.GetDigestSize());
+			}
+			else
+			{
+				digest.BlockUpdate(outputBuf, 0, outputBuf.Length);
+			}
+
+			int len = digest.DoFinal(output, outOff);
+
+			Array.Clear(outputBuf, blockLength, digestSize);
+
+			if (ipadState != null)
+			{
+				((IMemoable)digest).Reset(ipadState);
+			}
+			else
+			{
+				digest.BlockUpdate(inputPad, 0, inputPad.Length);
+			}
 
             return len;
         }
@@ -114,7 +134,7 @@ namespace Org.BouncyCastle.Crypto.Macs
         /**
         * Reset the mac generator.
         */
-        public void Reset()
+        public virtual void Reset()
         {
 			// Reset underlying digest
             digest.Reset();
@@ -123,11 +143,11 @@ namespace Org.BouncyCastle.Crypto.Macs
             digest.BlockUpdate(inputPad, 0, inputPad.Length);
         }
 
-		private static void xor(byte[] a, byte n)
+        private static void XorPad(byte[] pad, int len, byte n)
 		{
-			for (int i = 0; i < a.Length; ++i)
+			for (int i = 0; i < len; ++i)
             {
-                a[i] ^= n;
+                pad[i] ^= n;
             }
 		}
     }
diff --git a/crypto/src/crypto/macs/ISO9797Alg3Mac.cs b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
new file mode 100644
index 000000000..6fee619c1
--- /dev/null
+++ b/crypto/src/crypto/macs/ISO9797Alg3Mac.cs
@@ -0,0 +1,275 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+	/**
+	* DES based CBC Block Cipher MAC according to ISO9797, algorithm 3 (ANSI X9.19 Retail MAC)
+	*
+	* This could as well be derived from CBCBlockCipherMac, but then the property mac in the base
+	* class must be changed to protected
+	*/
+	public class ISO9797Alg3Mac : IMac
+	{
+		private byte[] mac;
+		private byte[] buf;
+		private int bufOff;
+		private IBlockCipher cipher;
+		private IBlockCipherPadding padding;
+		private int macSize;
+		private KeyParameter lastKey2;
+		private KeyParameter lastKey3;
+
+		/**
+		* create a Retail-MAC based on a CBC block cipher. This will produce an
+		* authentication code of the length of the block size of the cipher.
+		*
+		* @param cipher the cipher to be used as the basis of the MAC generation. This must
+		* be DESEngine.
+		*/
+		public ISO9797Alg3Mac(
+			IBlockCipher cipher)
+			: this(cipher, cipher.GetBlockSize() * 8, null)
+		{
+		}
+
+		/**
+		* create a Retail-MAC based on a CBC block cipher. This will produce an
+		* authentication code of 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 ISO9797Alg3Mac(
+			IBlockCipher		cipher,
+			IBlockCipherPadding	padding)
+			: this(cipher, cipher.GetBlockSize() * 8, padding)
+		{
+		}
+
+		/**
+		* create a Retail-MAC based on a block cipher with the size of the
+		* MAC been given in bits. This class uses single DES 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).
+		* </p>
+		* @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 ISO9797Alg3Mac(
+			IBlockCipher	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 single DES CBC mode as the basis for the
+		* MAC generation. The final block is decrypted and then encrypted using the
+		* middle and right part of the key.
+		* <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).
+		* </p>
+		* @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 ISO9797Alg3Mac(
+			IBlockCipher		cipher,
+			int					macSizeInBits,
+			IBlockCipherPadding	padding)
+		{
+			if ((macSizeInBits % 8) != 0)
+				throw new ArgumentException("MAC size must be multiple of 8");
+
+			if (!(cipher is DesEngine))
+				throw new ArgumentException("cipher must be instance of DesEngine");
+
+			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 AlgorithmName
+		{
+			get { return "ISO9797Alg3"; }
+		}
+
+		public void Init(
+			ICipherParameters parameters)
+		{
+			Reset();
+
+			if (!(parameters is KeyParameter || parameters is ParametersWithIV))
+				throw new ArgumentException("parameters must be an instance of KeyParameter or ParametersWithIV");
+
+			// KeyParameter must contain a double or triple length DES key,
+			// however the underlying cipher is a single DES. The middle and
+			// right key are used only in the final step.
+
+			KeyParameter kp;
+			if (parameters is KeyParameter)
+			{
+				kp = (KeyParameter)parameters;
+			}
+			else
+			{
+				kp = (KeyParameter)((ParametersWithIV)parameters).Parameters;
+			}
+
+			KeyParameter key1;
+			byte[] keyvalue = kp.GetKey();
+
+			if (keyvalue.Length == 16)
+			{ // Double length DES key
+				key1 = new KeyParameter(keyvalue, 0, 8);
+				this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+				this.lastKey3 = key1;
+			}
+			else if (keyvalue.Length == 24)
+			{ // Triple length DES key
+				key1 = new KeyParameter(keyvalue, 0, 8);
+				this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
+				this.lastKey3 = new KeyParameter(keyvalue, 16, 8);
+			}
+			else
+			{
+				throw new ArgumentException("Key must be either 112 or 168 bit long");
+			}
+
+			if (parameters is ParametersWithIV)
+			{
+				cipher.Init(true, new ParametersWithIV(key1, ((ParametersWithIV)parameters).GetIV()));
+			}
+			else
+			{
+				cipher.Init(true, key1);
+			}
+		}
+
+		public int GetMacSize()
+		{
+			return macSize;
+		}
+
+		public void Update(
+			byte input)
+		{
+			if (bufOff == buf.Length)
+			{
+				cipher.ProcessBlock(buf, 0, mac, 0);
+				bufOff = 0;
+			}
+
+			buf[bufOff++] = input;
+		}
+
+		public void BlockUpdate(
+			byte[]	input,
+			int		inOff,
+			int		len)
+		{
+			if (len < 0)
+				throw new ArgumentException("Can't have a negative input length!");
+
+			int blockSize = cipher.GetBlockSize();
+			int resultLen = 0;
+			int gapLen = blockSize - bufOff;
+
+			if (len > gapLen)
+			{
+				Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+				resultLen += cipher.ProcessBlock(buf, 0, mac, 0);
+
+				bufOff = 0;
+				len -= gapLen;
+				inOff += gapLen;
+
+				while (len > blockSize)
+				{
+					resultLen += cipher.ProcessBlock(input, inOff, mac, 0);
+
+					len -= blockSize;
+					inOff += blockSize;
+				}
+			}
+
+			Array.Copy(input, inOff, buf, bufOff, len);
+
+			bufOff += len;
+		}
+
+		public int DoFinal(
+			byte[]	output,
+			int		outOff)
+		{
+			int blockSize = cipher.GetBlockSize();
+
+			if (padding == null)
+			{
+				// pad with zeroes
+				while (bufOff < blockSize)
+				{
+					buf[bufOff++] = 0;
+				}
+			}
+			else
+			{
+				if (bufOff == blockSize)
+				{
+					cipher.ProcessBlock(buf, 0, mac, 0);
+					bufOff = 0;
+				}
+
+				padding.AddPadding(buf, bufOff);
+			}
+
+			cipher.ProcessBlock(buf, 0, mac, 0);
+
+			// Added to code from base class
+			DesEngine deseng = new DesEngine();
+
+			deseng.Init(false, this.lastKey2);
+			deseng.ProcessBlock(mac, 0, mac, 0);
+
+			deseng.Init(true, this.lastKey3);
+			deseng.ProcessBlock(mac, 0, mac, 0);
+			// ****
+
+			Array.Copy(mac, 0, output, outOff, macSize);
+
+			Reset();
+
+			return macSize;
+		}
+
+		/**
+		* Reset the mac generator.
+		*/
+		public void Reset()
+		{
+			Array.Clear(buf, 0, buf.Length);
+			bufOff = 0;
+
+			// reset the underlying cipher.
+			cipher.Reset();
+		}
+	}
+}
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
new file mode 100644
index 000000000..1a951ca04
--- /dev/null
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -0,0 +1,291 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+
+    /// <summary>
+    /// Poly1305 message authentication code, designed by D. J. Bernstein.
+    /// </summary>
+    /// <remarks>
+    /// Poly1305 computes a 128-bit (16 bytes) authenticator, using a 128 bit nonce and a 256 bit key
+    /// consisting of a 128 bit key applied to an underlying cipher, and a 128 bit key (with 106
+    /// effective key bits) used in the authenticator.
+    /// 
+    /// The polynomial calculation in this implementation is adapted from the public domain <a
+    /// href="https://github.com/floodyberry/poly1305-donna">poly1305-donna-unrolled</a> C implementation
+    /// by Andrew M (@floodyberry).
+    /// </remarks>
+    /// <seealso cref="Org.BouncyCastle.Crypto.Generators.Poly1305KeyGenerator"/>
+    public class Poly1305
+        : IMac
+    {
+        private const int BLOCK_SIZE = 16;
+
+        private readonly IBlockCipher cipher;
+
+        private readonly byte[] singleByte = new byte[1];
+
+        // Initialised state
+
+        /** Polynomial key */
+        private uint r0, r1, r2, r3, r4;
+
+        /** Precomputed 5 * r[1..4] */
+        private uint s1, s2, s3, s4;
+
+        /** Encrypted nonce */
+        private uint k0, k1, k2, k3;
+
+        // Accumulating state
+
+        /** Current block of buffered input */
+        private byte[] currentBlock = new byte[BLOCK_SIZE];
+
+        /** Current offset in input buffer */
+        private int currentBlockOffset = 0;
+
+        /** Polynomial accumulator */
+        private uint h0, h1, h2, h3, h4;
+
+        /**
+         * Constructs a Poly1305 MAC, where the key passed to init() will be used directly.
+         */
+        public Poly1305()
+        {
+            this.cipher = null;
+        }
+
+        /**
+         * Constructs a Poly1305 MAC, using a 128 bit block cipher.
+         */
+        public Poly1305(IBlockCipher cipher)
+        {
+            if (cipher.GetBlockSize() != BLOCK_SIZE)
+            {
+                throw new ArgumentException("Poly1305 requires a 128 bit block cipher.");
+            }
+            this.cipher = cipher;
+        }
+
+        /// <summary>
+        /// Initialises the Poly1305 MAC.
+        /// </summary>
+        /// <param name="parameters">a {@link ParametersWithIV} containing a 128 bit nonce and a {@link KeyParameter} with
+        ///          a 256 bit key complying to the {@link Poly1305KeyGenerator Poly1305 key format}.</param>
+        public void Init(ICipherParameters parameters)
+        {
+            byte[] nonce = null;
+
+            if (cipher != null)
+            {
+                if (!(parameters is ParametersWithIV))
+                    throw new ArgumentException("Poly1305 requires an IV when used with a block cipher.", "parameters");
+
+                ParametersWithIV ivParams = (ParametersWithIV)parameters;
+                nonce = ivParams.GetIV();
+                parameters = ivParams.Parameters;
+            }
+
+            if (!(parameters is KeyParameter))
+                throw new ArgumentException("Poly1305 requires a key.");
+
+            KeyParameter keyParams = (KeyParameter)parameters;
+
+            SetKey(keyParams.GetKey(), nonce);
+
+            Reset();
+        }
+
+        private void SetKey(byte[] key, byte[] nonce)
+        {
+            if (cipher != null && (nonce == null || nonce.Length != BLOCK_SIZE))
+                throw new ArgumentException("Poly1305 requires a 128 bit IV.");
+
+            Poly1305KeyGenerator.CheckKey(key);
+
+            // Extract r portion of key
+            uint t0 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 0);
+            uint t1 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 4);
+            uint t2 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 8);
+            uint t3 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 12);
+
+            r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6;
+            r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12;
+            r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18;
+            r3 = t2 & 0x3f03fff; t3 >>= 8;
+            r4 = t3 & 0x00fffff;
+
+            // Precompute multipliers
+            s1 = r1 * 5;
+            s2 = r2 * 5;
+            s3 = r3 * 5;
+            s4 = r4 * 5;
+
+            byte[] kBytes;
+            if (cipher == null)
+            {
+                kBytes = key;
+            }
+            else
+            {
+                // Compute encrypted nonce
+                kBytes = new byte[BLOCK_SIZE];
+                cipher.Init(true, new KeyParameter(key, 0, BLOCK_SIZE));
+                cipher.ProcessBlock(nonce, 0, kBytes, 0);
+            }
+
+            k0 = Pack.LE_To_UInt32(kBytes, 0);
+            k1 = Pack.LE_To_UInt32(kBytes, 4);
+            k2 = Pack.LE_To_UInt32(kBytes, 8);
+            k3 = Pack.LE_To_UInt32(kBytes, 12);
+        }
+
+        public string AlgorithmName
+        {
+            get { return cipher == null ? "Poly1305" : "Poly1305-" + cipher.AlgorithmName; }
+        }
+
+        public int GetMacSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        public void Update(byte input)
+        {
+            singleByte[0] = input;
+            BlockUpdate(singleByte, 0, 1);
+        }
+
+        public void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            int copied = 0;
+            while (len > copied)
+            {
+                if (currentBlockOffset == BLOCK_SIZE)
+                {
+                    processBlock();
+                    currentBlockOffset = 0;
+                }
+
+                int toCopy = System.Math.Min((len - copied), BLOCK_SIZE - currentBlockOffset);
+                Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy);
+                copied += toCopy;
+                currentBlockOffset += toCopy;
+            }
+
+        }
+
+        private void processBlock()
+        {
+            if (currentBlockOffset < BLOCK_SIZE)
+            {
+                currentBlock[currentBlockOffset] = 1;
+                for (int i = currentBlockOffset + 1; i < BLOCK_SIZE; i++)
+                {
+                    currentBlock[i] = 0;
+                }
+            }
+
+            ulong t0 = Pack.LE_To_UInt32(currentBlock, 0);
+            ulong t1 = Pack.LE_To_UInt32(currentBlock, 4);
+            ulong t2 = Pack.LE_To_UInt32(currentBlock, 8);
+            ulong t3 = Pack.LE_To_UInt32(currentBlock, 12);
+
+            h0 += (uint)(t0 & 0x3ffffffU);
+            h1 += (uint)((((t1 << 32) | t0) >> 26) & 0x3ffffff);
+            h2 += (uint)((((t2 << 32) | t1) >> 20) & 0x3ffffff);
+            h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff);
+            h4 += (uint)(t3 >> 8);
+
+            if (currentBlockOffset == BLOCK_SIZE)
+            {
+                h4 += (1 << 24);
+            }
+
+            ulong tp0 = mul32x32_64(h0,r0) + mul32x32_64(h1,s4) + mul32x32_64(h2,s3) + mul32x32_64(h3,s2) + mul32x32_64(h4,s1);
+            ulong tp1 = mul32x32_64(h0,r1) + mul32x32_64(h1,r0) + mul32x32_64(h2,s4) + mul32x32_64(h3,s3) + mul32x32_64(h4,s2);
+            ulong tp2 = mul32x32_64(h0,r2) + mul32x32_64(h1,r1) + mul32x32_64(h2,r0) + mul32x32_64(h3,s4) + mul32x32_64(h4,s3);
+            ulong tp3 = mul32x32_64(h0,r3) + mul32x32_64(h1,r2) + mul32x32_64(h2,r1) + mul32x32_64(h3,r0) + mul32x32_64(h4,s4);
+            ulong tp4 = mul32x32_64(h0,r4) + mul32x32_64(h1,r3) + mul32x32_64(h2,r2) + mul32x32_64(h3,r1) + mul32x32_64(h4,r0);
+
+            ulong b;
+            h0 = (uint)tp0 & 0x3ffffff; b = (tp0 >> 26);
+            tp1 += b; h1 = (uint)tp1 & 0x3ffffff; b = (tp1 >> 26);
+            tp2 += b; h2 = (uint)tp2 & 0x3ffffff; b = (tp2 >> 26);
+            tp3 += b; h3 = (uint)tp3 & 0x3ffffff; b = (tp3 >> 26);
+            tp4 += b; h4 = (uint)tp4 & 0x3ffffff; b = (tp4 >> 26);
+            h0 += (uint)(b * 5);
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (outOff + BLOCK_SIZE > output.Length)
+            {
+                throw new DataLengthException("Output buffer is too short.");
+            }
+
+            if (currentBlockOffset > 0)
+            {
+                // Process padded block
+                processBlock();
+            }
+
+            ulong f0, f1, f2, f3;
+
+            uint b = h0 >> 26;
+            h0 = h0 & 0x3ffffff;
+            h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff;
+            h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff;
+            h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff;
+            h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff;
+            h0 += b * 5;
+
+            uint g0, g1, g2, g3, g4;
+            g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff;
+            g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff;
+            g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff;
+            g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff;
+            g4 = h4 + b - (1 << 26);
+
+            b = (g4 >> 31) - 1;
+            uint nb = ~b;
+            h0 = (h0 & nb) | (g0 & b);
+            h1 = (h1 & nb) | (g1 & b);
+            h2 = (h2 & nb) | (g2 & b);
+            h3 = (h3 & nb) | (g3 & b);
+            h4 = (h4 & nb) | (g4 & b);
+
+            f0 = ((h0      ) | (h1 << 26)) + (ulong)k0;
+            f1 = ((h1 >> 6 ) | (h2 << 20)) + (ulong)k1;
+            f2 = ((h2 >> 12) | (h3 << 14)) + (ulong)k2;
+            f3 = ((h3 >> 18) | (h4 << 8 )) + (ulong)k3;
+
+            Pack.UInt32_To_LE((uint)f0, output, outOff);
+            f1 += (f0 >> 32);
+            Pack.UInt32_To_LE((uint)f1, output, outOff + 4);
+            f2 += (f1 >> 32);
+            Pack.UInt32_To_LE((uint)f2, output, outOff + 8);
+            f3 += (f2 >> 32);
+            Pack.UInt32_To_LE((uint)f3, output, outOff + 12);
+
+            Reset();
+            return BLOCK_SIZE;
+        }
+
+        public void Reset()
+        {
+            currentBlockOffset = 0;
+
+            h0 = h1 = h2 = h3 = h4 = 0;
+        }
+
+        private static ulong mul32x32_64(uint i1, uint i2)
+        {
+            return ((ulong)i1) * i2;
+        }
+    }
+}
diff --git a/crypto/src/crypto/macs/SipHash.cs b/crypto/src/crypto/macs/SipHash.cs
new file mode 100644
index 000000000..e1a19fa5b
--- /dev/null
+++ b/crypto/src/crypto/macs/SipHash.cs
@@ -0,0 +1,199 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+    /// <summary>
+    /// Implementation of SipHash as specified in "SipHash: a fast short-input PRF", by Jean-Philippe
+    /// Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf).
+    /// </summary>
+    /// <remarks>
+    /// "SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d are the number of
+    /// compression rounds and the number of finalization rounds. A compression round is identical to a
+    /// finalization round and this round function is called SipRound. Given a 128-bit key k and a
+    /// (possibly empty) byte string m, SipHash-c-d returns a 64-bit value..."
+    /// </remarks>
+    public class SipHash
+        : IMac
+    {
+        protected readonly int c, d;
+
+        protected long k0, k1;
+        protected long v0, v1, v2, v3;
+
+        protected long m = 0;
+        protected int wordPos = 0;
+        protected int wordCount = 0;
+
+        /// <summary>SipHash-2-4</summary>
+        public SipHash()
+            : this(2, 4)
+        {
+        }
+
+        /// <summary>SipHash-c-d</summary>
+        /// <param name="c">the number of compression rounds</param>
+        /// <param name="d">the number of finalization rounds</param>
+        public SipHash(int c, int d)
+        {
+            this.c = c;
+            this.d = d;
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "SipHash-" + c + "-" + d; }
+        }
+
+        public virtual int GetMacSize()
+        {
+            return 8;
+        }
+
+        public virtual void Init(ICipherParameters parameters)
+        {
+            KeyParameter keyParameter = parameters as KeyParameter;
+            if (keyParameter == null)
+                throw new ArgumentException("must be an instance of KeyParameter", "parameters");
+            byte[] key = keyParameter.GetKey();
+            if (key.Length != 16)
+                throw new ArgumentException("must be a 128-bit key", "parameters");
+
+            this.k0 = (long)Pack.LE_To_UInt64(key, 0);
+            this.k1 = (long)Pack.LE_To_UInt64(key, 8);
+
+            Reset();
+        }
+
+        public virtual void Update(byte input)
+        {
+            m = (long)(((ulong)m >> 8) | ((ulong)input << 56));
+
+            if (++wordPos == 8)
+            {
+                ProcessMessageWord();
+                wordPos = 0;
+            }
+        }
+
+        public virtual void BlockUpdate(byte[] input, int offset, int length)
+        {
+            int i = 0, fullWords = length & ~7;
+            if (wordPos == 0)
+            {
+                for (; i < fullWords; i += 8)
+                {
+                    m = (long)Pack.LE_To_UInt64(input, offset + i);
+                    ProcessMessageWord();
+                }
+                for (; i < length; ++i)
+                {
+                    m = (long)(((ulong)m >> 8) | ((ulong)input[offset + i] << 56));
+                }
+                wordPos = length - fullWords;
+            }
+            else
+            {
+                int bits = wordPos << 3;
+                for (; i < fullWords; i += 8)
+                {
+                    ulong n = Pack.LE_To_UInt64(input, offset + i);
+                    m = (long)((n << bits) | ((ulong)m >> -bits));
+                    ProcessMessageWord();
+                    m = (long)n;
+                }
+                for (; i < length; ++i)
+                {
+                    m = (long)(((ulong)m >> 8) | ((ulong)input[offset + i] << 56));
+
+                    if (++wordPos == 8)
+                    {
+                        ProcessMessageWord();
+                        wordPos = 0;
+                    }
+                }
+            }
+        }
+
+        public virtual long DoFinal()
+        {
+            // NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0
+            m = (long)((ulong)m >> ((7 - wordPos) << 3));
+            m = (long)((ulong)m >> 8);
+            m = (long)((ulong)m | ((ulong)((wordCount << 3) + wordPos) << 56));
+
+            ProcessMessageWord();
+
+            v2 ^= 0xffL;
+
+            ApplySipRounds(d);
+
+            long result = v0 ^ v1 ^ v2 ^ v3;
+
+            Reset();
+
+            return result;
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            long result = DoFinal();
+            Pack.UInt64_To_LE((ulong)result, output, outOff);
+            return 8;
+        }
+
+        public virtual void Reset()
+        {
+            v0 = k0 ^ 0x736f6d6570736575L;
+            v1 = k1 ^ 0x646f72616e646f6dL;
+            v2 = k0 ^ 0x6c7967656e657261L;
+            v3 = k1 ^ 0x7465646279746573L;
+
+            m = 0;
+            wordPos = 0;
+            wordCount = 0;
+        }
+
+        protected virtual void ProcessMessageWord()
+        {
+            ++wordCount;
+            v3 ^= m;
+            ApplySipRounds(c);
+            v0 ^= m;
+        }
+
+        protected virtual void ApplySipRounds(int n)
+        {
+            long r0 = v0, r1 = v1, r2 = v2, r3 = v3;
+
+            for (int r = 0; r < n; ++r)
+            {
+                r0 += r1;
+                r2 += r3;
+                r1 = RotateLeft(r1, 13);
+                r3 = RotateLeft(r3, 16);
+                r1 ^= r0;
+                r3 ^= r2;
+                r0 = RotateLeft(r0, 32);
+                r2 += r1;
+                r0 += r3;
+                r1 = RotateLeft(r1, 17);
+                r3 = RotateLeft(r3, 21);
+                r1 ^= r2;
+                r3 ^= r0;
+                r2 = RotateLeft(r2, 32);
+            }
+
+            v0 = r0; v1 = r1; v2 = r2; v3 = r3;
+        }
+
+        protected static long RotateLeft(long x, int n)
+        {
+            ulong ux = (ulong)x;
+            ux = (ux << n) | (ux >> -n);
+            return (long)ux;
+        }
+    }
+}
diff --git a/crypto/src/crypto/macs/SkeinMac.cs b/crypto/src/crypto/macs/SkeinMac.cs
new file mode 100644
index 000000000..1d61a41ca
--- /dev/null
+++ b/crypto/src/crypto/macs/SkeinMac.cs
@@ -0,0 +1,117 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+
+	/// <summary>
+	/// Implementation of the Skein parameterised MAC function in 256, 512 and 1024 bit block sizes,
+	/// based on the <see cref="Org.BouncyCastle.Crypto.Engines.ThreefishEngine">Threefish</see> tweakable block cipher.
+	/// </summary>
+	/// <remarks>
+	/// This is the 1.3 version of Skein defined in the Skein hash function submission to the NIST SHA-3
+	/// competition in October 2010.
+	/// <p/>
+	/// Skein was designed by Niels Ferguson - Stefan Lucks - Bruce Schneier - Doug Whiting - Mihir
+	/// Bellare - Tadayoshi Kohno - Jon Callas - Jesse Walker.
+	/// </remarks>
+	/// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinEngine"/>
+	/// <seealso cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"/>
+	public class SkeinMac
+		: IMac
+	{
+		/// <summary>
+		/// 256 bit block size - Skein-256
+		/// </summary>
+		public const int SKEIN_256 = SkeinEngine.SKEIN_256;
+		/// <summary>
+		/// 512 bit block size - Skein-512
+		/// </summary>
+		public const int SKEIN_512 = SkeinEngine.SKEIN_512;
+		/// <summary>
+		/// 1024 bit block size - Skein-1024
+		/// </summary>
+		public const int SKEIN_1024 = SkeinEngine.SKEIN_1024;
+
+		private readonly SkeinEngine engine;
+
+		/// <summary>
+		/// Constructs a Skein MAC with an internal state size and output size.
+		/// </summary>
+		/// <param name="stateSizeBits">the internal state size in bits - one of <see cref="SKEIN_256"/> <see cref="SKEIN_512"/> or
+		///                       <see cref="SKEIN_1024"/>.</param>
+		/// <param name="digestSizeBits">the output/MAC size to produce in bits, which must be an integral number of
+		///                      bytes.</param>
+		public SkeinMac(int stateSizeBits, int digestSizeBits)
+		{
+			this.engine = new SkeinEngine(stateSizeBits, digestSizeBits);
+		}
+
+		public SkeinMac(SkeinMac mac)
+		{
+			this.engine = new SkeinEngine(mac.engine);
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Skein-MAC-" + (engine.BlockSize * 8) + "-" + (engine.OutputSize * 8); }
+		}
+
+		/// <summary>
+		/// Optionally initialises the Skein digest with the provided parameters.
+		/// </summary>
+		/// See <see cref="Org.BouncyCastle.Crypto.Parameters.SkeinParameters"></see> for details on the parameterisation of the Skein hash function.
+		/// <param name="parameters">the parameters to apply to this engine, or <code>null</code> to use no parameters.</param>
+		public void Init(ICipherParameters parameters)
+		{
+			SkeinParameters skeinParameters;
+			if (parameters is SkeinParameters)
+			{
+				skeinParameters = (SkeinParameters)parameters;
+			}
+			else if (parameters is KeyParameter)
+			{
+				skeinParameters = new SkeinParameters.Builder().SetKey(((KeyParameter)parameters).GetKey()).Build();
+			}
+			else
+			{
+				throw new ArgumentException("Invalid parameter passed to Skein MAC init - "
+				                            + parameters.GetType().Name);
+			}
+			if (skeinParameters.GetKey() == null)
+			{
+				throw new ArgumentException("Skein MAC requires a key parameter.");
+			}
+			engine.Init(skeinParameters);
+		}
+
+		public int GetMacSize()
+		{
+			return engine.OutputSize;
+		}
+
+		public void Reset()
+		{
+			engine.Reset();
+		}
+
+		public void Update(byte inByte)
+		{
+			engine.Update(inByte);
+		}
+
+		public void BlockUpdate(byte[] input, int inOff, int len)
+		{
+			engine.Update(input, inOff, len);
+		}
+
+		public int DoFinal(byte[] output, int outOff)
+		{
+			return engine.DoFinal(output, outOff);
+		}
+
+	}
+}
diff --git a/crypto/src/crypto/macs/VMPCMac.cs b/crypto/src/crypto/macs/VMPCMac.cs
new file mode 100644
index 000000000..89916355c
--- /dev/null
+++ b/crypto/src/crypto/macs/VMPCMac.cs
@@ -0,0 +1,173 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+	public class VmpcMac
+		: IMac
+	{
+		private byte g;
+
+		private byte n = 0;
+		private byte[] P = null;
+		private byte s = 0;
+
+		private byte[] T;
+		private byte[] workingIV;
+
+		private byte[] workingKey;
+
+		private byte x1, x2, x3, x4;
+
+		public virtual int DoFinal(byte[] output, int outOff)
+		{
+			// Execute the Post-Processing Phase
+			for (int r = 1; r < 25; r++)
+			{
+				s = P[(s + P[n & 0xff]) & 0xff];
+
+				x4 = P[(x4 + x3 + r) & 0xff];
+				x3 = P[(x3 + x2 + r) & 0xff];
+				x2 = P[(x2 + x1 + r) & 0xff];
+				x1 = P[(x1 + s + r) & 0xff];
+				T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+				T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+				T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+				T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+				g = (byte) ((g + 4) & 0x1f);
+
+				byte temp = P[n & 0xff];
+				P[n & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+				n = (byte) ((n + 1) & 0xff);
+			}
+
+			// Input T to the IV-phase of the VMPC KSA
+			for (int m = 0; m < 768; m++)
+			{
+				s = P[(s + P[m & 0xff] + T[m & 0x1f]) & 0xff];
+				byte temp = P[m & 0xff];
+				P[m & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+
+			// Store 20 new outputs of the VMPC Stream Cipher input table M
+			byte[] M = new byte[20];
+			for (int i = 0; i < 20; i++)
+			{
+				s = P[(s + P[i & 0xff]) & 0xff];
+				M[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+
+				byte temp = P[i & 0xff];
+				P[i & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+
+			Array.Copy(M, 0, output, outOff, M.Length);
+			Reset();
+
+			return M.Length;
+		}
+
+		public virtual string AlgorithmName
+		{
+			get { return "VMPC-MAC"; }
+		}
+
+		public virtual int GetMacSize()
+		{
+			return 20;
+		}
+
+		public virtual void Init(ICipherParameters parameters)
+		{
+			if (!(parameters is ParametersWithIV))
+				throw new ArgumentException("VMPC-MAC Init parameters must include an IV", "parameters");
+
+			ParametersWithIV ivParams = (ParametersWithIV) parameters;
+			KeyParameter key = (KeyParameter) ivParams.Parameters;
+
+			if (!(ivParams.Parameters is KeyParameter))
+				throw new ArgumentException("VMPC-MAC Init parameters must include a key", "parameters");
+
+			this.workingIV = ivParams.GetIV();
+
+			if (workingIV == null || workingIV.Length < 1 || workingIV.Length > 768)
+				throw new ArgumentException("VMPC-MAC requires 1 to 768 bytes of IV", "parameters");
+
+			this.workingKey = key.GetKey();
+
+			Reset();
+
+		}
+
+		private void initKey(byte[] keyBytes, byte[] ivBytes)
+		{
+			s = 0;
+			P = new byte[256];
+			for (int i = 0; i < 256; i++)
+			{
+				P[i] = (byte) i;
+			}
+			for (int m = 0; m < 768; m++)
+			{
+				s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.Length]) & 0xff];
+				byte temp = P[m & 0xff];
+				P[m & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+			for (int m = 0; m < 768; m++)
+			{
+				s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.Length]) & 0xff];
+				byte temp = P[m & 0xff];
+				P[m & 0xff] = P[s & 0xff];
+				P[s & 0xff] = temp;
+			}
+			n = 0;
+		}
+
+		public virtual void Reset()
+		{
+			initKey(this.workingKey, this.workingIV);
+			g = x1 = x2 = x3 = x4 = n = 0;
+			T = new byte[32];
+			for (int i = 0; i < 32; i++)
+			{
+				T[i] = 0;
+			}
+		}
+
+		public virtual void Update(byte input)
+		{
+			s = P[(s + P[n & 0xff]) & 0xff];
+			byte c = (byte) (input ^ P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff]);
+
+			x4 = P[(x4 + x3) & 0xff];
+			x3 = P[(x3 + x2) & 0xff];
+			x2 = P[(x2 + x1) & 0xff];
+			x1 = P[(x1 + s + c) & 0xff];
+			T[g & 0x1f] = (byte) (T[g & 0x1f] ^ x1);
+			T[(g + 1) & 0x1f] = (byte) (T[(g + 1) & 0x1f] ^ x2);
+			T[(g + 2) & 0x1f] = (byte) (T[(g + 2) & 0x1f] ^ x3);
+			T[(g + 3) & 0x1f] = (byte) (T[(g + 3) & 0x1f] ^ x4);
+			g = (byte) ((g + 4) & 0x1f);
+
+			byte temp = P[n & 0xff];
+			P[n & 0xff] = P[s & 0xff];
+			P[s & 0xff] = temp;
+			n = (byte) ((n + 1) & 0xff);
+		}
+
+		public virtual void BlockUpdate(byte[] input, int inOff, int len)
+		{
+			if ((inOff + len) > input.Length)
+				throw new DataLengthException("input buffer too short");
+
+			for (int i = 0; i < len; i++)
+			{
+				Update(input[i]);
+			}
+		}
+	}
+}
diff --git a/crypto/src/crypto/modes/CbcBlockCipher.cs b/crypto/src/crypto/modes/CbcBlockCipher.cs
index 0bbc0cb24..9345fd8c2 100644
--- a/crypto/src/crypto/modes/CbcBlockCipher.cs
+++ b/crypto/src/crypto/modes/CbcBlockCipher.cs
@@ -55,6 +55,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             bool forEncryption,
             ICipherParameters parameters)
         {
+            bool oldEncrypting = this.encrypting;
+
             this.encrypting = forEncryption;
 
             if (parameters is ParametersWithIV)
@@ -74,7 +76,15 @@ namespace Org.BouncyCastle.Crypto.Modes
 
 			Reset();
 
-			cipher.Init(encrypting, parameters);
+            // if null it's an IV changed only.
+            if (parameters != null)
+            {
+                cipher.Init(encrypting, parameters);
+            }
+            else if (oldEncrypting != encrypting)
+            {
+                throw new ArgumentException("cannot change encrypting state without providing key.");
+            }
         }
 
 		/**
diff --git a/crypto/src/crypto/modes/CcmBlockCipher.cs b/crypto/src/crypto/modes/CcmBlockCipher.cs
index abfde237e..653d75cb9 100644
--- a/crypto/src/crypto/modes/CcmBlockCipher.cs
+++ b/crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -13,21 +13,22 @@ namespace Org.BouncyCastle.Crypto.Modes
     * NIST Special Publication 800-38C.
     * <p>
     * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
-	* </p>
+    * </p>
     */
     public class CcmBlockCipher
-		: IAeadBlockCipher
+        : IAeadBlockCipher
     {
-		private static readonly int BlockSize = 16;
+        private static readonly int BlockSize = 16;
 
-		private readonly IBlockCipher	cipher;
+        private readonly IBlockCipher	cipher;
         private readonly byte[]			macBlock;
         private bool					forEncryption;
-		private byte[]					nonce;
-		private byte[]					associatedText;
-		private int						macSize;
-		private ICipherParameters		keyParam;
-		private readonly MemoryStream	data = new MemoryStream();
+        private byte[]					nonce;
+        private byte[]					initialAssociatedText;
+        private int						macSize;
+        private ICipherParameters		keyParam;
+        private readonly MemoryStream   associatedText = new MemoryStream();
+        private readonly MemoryStream   data = new MemoryStream();
 
         /**
         * Basic constructor.
@@ -35,7 +36,7 @@ namespace Org.BouncyCastle.Crypto.Modes
         * @param cipher the block cipher to be used.
         */
         public CcmBlockCipher(
-			IBlockCipher cipher)
+            IBlockCipher cipher)
         {
             this.cipher = cipher;
             this.macBlock = new byte[BlockSize];
@@ -55,88 +56,104 @@ namespace Org.BouncyCastle.Crypto.Modes
         }
 
         public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
+            bool				forEncryption,
+            ICipherParameters	parameters)
         {
-			this.forEncryption = forEncryption;
-
-			if (parameters is AeadParameters)
-			{
-				AeadParameters param = (AeadParameters) parameters;
-
-				nonce = param.GetNonce();
-				associatedText = param.GetAssociatedText();
-				macSize = param.MacSize / 8;
-				keyParam = param.Key;
-			}
-			else if (parameters is ParametersWithIV)
-			{
-				ParametersWithIV param = (ParametersWithIV) parameters;
-
-				nonce = param.GetIV();
-				associatedText = null;
-				macSize = macBlock.Length / 2;
-				keyParam = param.Parameters;
-			}
-			else
-			{
-				throw new ArgumentException("invalid parameters passed to CCM");
-			}
+            this.forEncryption = forEncryption;
+
+            if (parameters is AeadParameters)
+            {
+                AeadParameters param = (AeadParameters) parameters;
+
+                nonce = param.GetNonce();
+                initialAssociatedText = param.GetAssociatedText();
+                macSize = param.MacSize / 8;
+                keyParam = param.Key;
+            }
+            else if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV param = (ParametersWithIV) parameters;
+
+                nonce = param.GetIV();
+                initialAssociatedText = null;
+                macSize = macBlock.Length / 2;
+                keyParam = param.Parameters;
+            }
+            else
+            {
+                throw new ArgumentException("invalid parameters passed to CCM");
+            }
+
+            if (nonce == null || nonce.Length < 7 || nonce.Length > 13)
+            {
+                throw new ArgumentException("nonce must have length from 7 to 13 octets");
+            }
         }
 
-		public virtual string AlgorithmName
+        public virtual string AlgorithmName
         {
             get { return cipher.AlgorithmName + "/CCM"; }
         }
 
-		public virtual int GetBlockSize()
-		{
-			return cipher.GetBlockSize();
-		}
-
-		public virtual int ProcessByte(
-			byte	input,
-			byte[]	outBytes,
-			int		outOff)
-		{
-			data.WriteByte(input);
-
-			return 0;
-		}
-
-		public virtual int ProcessBytes(
-			byte[]	inBytes,
-			int		inOff,
-			int		inLen,
-			byte[]	outBytes,
-			int		outOff)
-		{
-			data.Write(inBytes, inOff, inLen);
-
-			return 0;
-		}
-
-		public virtual int DoFinal(
-			byte[]	outBytes,
-			int		outOff)
-		{
-			byte[] text = data.ToArray();
-			byte[] enc = ProcessPacket(text, 0, text.Length);
-
-			Array.Copy(enc, 0, outBytes, outOff, enc.Length);
-
-			Reset();
-
-			return enc.Length;
-		}
-
-		public virtual void Reset()
-		{
-			cipher.Reset();
-			data.SetLength(0);
-		}
-
-		/**
+        public virtual int GetBlockSize()
+        {
+            return cipher.GetBlockSize();
+        }
+
+        public virtual void ProcessAadByte(byte input)
+        {
+            associatedText.WriteByte(input);
+        }
+
+        public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+        {
+            // TODO: Process AAD online
+            associatedText.Write(inBytes, inOff, len);
+        }
+
+        public virtual int ProcessByte(
+            byte	input,
+            byte[]	outBytes,
+            int		outOff)
+        {
+            data.WriteByte(input);
+
+            return 0;
+        }
+
+        public virtual int ProcessBytes(
+            byte[]	inBytes,
+            int		inOff,
+            int		inLen,
+            byte[]	outBytes,
+            int		outOff)
+        {
+            data.Write(inBytes, inOff, inLen);
+
+            return 0;
+        }
+
+        public virtual int DoFinal(
+            byte[]	outBytes,
+            int		outOff)
+        {
+            byte[] enc = ProcessPacket(data.GetBuffer(), 0, (int)data.Position);
+
+            Array.Copy(enc, 0, outBytes, outOff, enc.Length);
+
+            Reset();
+
+            return enc.Length;
+        }
+
+        public virtual void Reset()
+        {
+            cipher.Reset();
+            associatedText.SetLength(0);
+            data.SetLength(0);
+        }
+
+        /**
         * Returns a byte array containing the mac calculated as part of the
         * last encrypt or decrypt operation.
         *
@@ -144,53 +161,64 @@ namespace Org.BouncyCastle.Crypto.Modes
         */
         public virtual byte[] GetMac()
         {
-			byte[] mac = new byte[macSize];
+            byte[] mac = new byte[macSize];
+
+            Array.Copy(macBlock, 0, mac, 0, mac.Length);
 
-			Array.Copy(macBlock, 0, mac, 0, mac.Length);
+            return mac;
+        }
 
-			return mac;
+        public virtual int GetUpdateOutputSize(
+            int len)
+        {
+            return 0;
         }
 
-		public virtual int GetUpdateOutputSize(
-			int len)
-		{
-			return 0;
-		}
-
-		public int GetOutputSize(
-			int len)
-		{
-			if (forEncryption)
-			{
-				return (int) data.Length + len + macSize;
-			}
-
-			return (int) data.Length + len - macSize;
-		}
-
-		public byte[] ProcessPacket(
-			byte[]	input,
-			int		inOff,
-			int		inLen)
+        public int GetOutputSize(
+            int len)
         {
+            int totalData = (int)data.Length + len;
+
+            if (forEncryption)
+            {
+                return totalData + macSize;
+            }
+
+            return totalData < macSize ? 0 : totalData - macSize;
+        }
+
+        public byte[] ProcessPacket(
+            byte[]	input,
+            int		inOff,
+            int		inLen)
+        {
+            // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
+            // Need to keep the CTR and CBC Mac parts around and reset
             if (keyParam == null)
                 throw new InvalidOperationException("CCM cipher unitialized.");
 
-			IBlockCipher ctrCipher = new SicBlockCipher(cipher);
-            byte[] iv = new byte[BlockSize];
-            byte[] output;
+            int n = nonce.Length;
+            int q = 15 - n;
+            if (q < 4)
+            {
+                int limitLen = 1 << (8 * q);
+                if (inLen >= limitLen)
+                    throw new InvalidOperationException("CCM packet too large for choice of q.");
+            }
 
-            iv[0] = (byte)(((15 - nonce.Length) - 1) & 0x7);
+            byte[] iv = new byte[BlockSize];
+            iv[0] = (byte)((q - 1) & 0x7);
+            nonce.CopyTo(iv, 1);
 
-            Array.Copy(nonce, 0, iv, 1, nonce.Length);
+            IBlockCipher ctrCipher = new SicBlockCipher(cipher);
+            ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
 
-			ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
+            int index = inOff;
+            int outOff = 0;
+            byte[] output;
 
-			if (forEncryption)
+            if (forEncryption)
             {
-                int index = inOff;
-                int outOff = 0;
-
                 output = new byte[inLen + macSize];
 
                 calculateMac(input, inOff, inLen, macBlock);
@@ -218,9 +246,6 @@ namespace Org.BouncyCastle.Crypto.Modes
             }
             else
             {
-                int index = inOff;
-                int outOff = 0;
-
                 output = new byte[inLen - macSize];
 
                 Array.Copy(input, inOff + inLen - macSize, macBlock, 0, macSize);
@@ -251,25 +276,25 @@ namespace Org.BouncyCastle.Crypto.Modes
 
                 calculateMac(output, 0, output.Length, calculatedMacBlock);
 
-				if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
+                if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
                     throw new InvalidCipherTextException("mac check in CCM failed");
             }
 
-			return output;
+            return output;
         }
 
-		private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+        private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
         {
-			IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
+            IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
 
-			cMac.Init(keyParam);
+            cMac.Init(keyParam);
 
-			//
+            //
             // build b0
             //
             byte[] b0 = new byte[16];
 
-			if (hasAssociatedText())
+            if (HasAssociatedText())
             {
                 b0[0] |= 0x40;
             }
@@ -294,14 +319,15 @@ namespace Org.BouncyCastle.Crypto.Modes
             //
             // process associated text
             //
-			if (hasAssociatedText())
+            if (HasAssociatedText())
             {
                 int extra;
 
-                if (associatedText.Length < ((1 << 16) - (1 << 8)))
+                int textLength = GetAssociatedTextLength();
+                if (textLength < ((1 << 16) - (1 << 8)))
                 {
-                    cMac.Update((byte)(associatedText.Length >> 8));
-                    cMac.Update((byte)associatedText.Length);
+                    cMac.Update((byte)(textLength >> 8));
+                    cMac.Update((byte)textLength);
 
                     extra = 2;
                 }
@@ -309,20 +335,27 @@ namespace Org.BouncyCastle.Crypto.Modes
                 {
                     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);
+                    cMac.Update((byte)(textLength >> 24));
+                    cMac.Update((byte)(textLength >> 16));
+                    cMac.Update((byte)(textLength >> 8));
+                    cMac.Update((byte)textLength);
 
                     extra = 6;
                 }
 
-                cMac.BlockUpdate(associatedText, 0, associatedText.Length);
+                if (initialAssociatedText != null)
+                {
+                    cMac.BlockUpdate(initialAssociatedText, 0, initialAssociatedText.Length);
+                }
+                if (associatedText.Position > 0)
+                {
+                    cMac.BlockUpdate(associatedText.GetBuffer(), 0, (int)associatedText.Position);
+                }
 
-                extra = (extra + associatedText.Length) % 16;
+                extra = (extra + textLength) % 16;
                 if (extra != 0)
                 {
-                    for (int i = 0; i != 16 - extra; i++)
+                    for (int i = extra; i < 16; ++i)
                     {
                         cMac.Update((byte)0x00);
                     }
@@ -337,9 +370,14 @@ namespace Org.BouncyCastle.Crypto.Modes
             return cMac.DoFinal(macBlock, 0);
         }
 
-		private bool hasAssociatedText()
-		{
-			return associatedText != null && associatedText.Length != 0;
-		}
+        private int GetAssociatedTextLength()
+        {
+            return (int)associatedText.Length + ((initialAssociatedText == null) ? 0 : initialAssociatedText.Length);
+        }
+
+        private bool HasAssociatedText()
+        {
+            return GetAssociatedTextLength() > 0;
+        }
     }
 }
diff --git a/crypto/src/crypto/modes/CfbBlockCipher.cs b/crypto/src/crypto/modes/CfbBlockCipher.cs
index b400a72f4..433716535 100644
--- a/crypto/src/crypto/modes/CfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/CfbBlockCipher.cs
@@ -71,8 +71,14 @@ namespace Org.BouncyCastle.Crypto.Modes
                 parameters = ivParam.Parameters;
             }
             Reset();
-            cipher.Init(true, parameters);
+
+            // if it's null, key is to be reused.
+            if (parameters != null)
+            {
+                cipher.Init(true, parameters);
+            }
         }
+
         /**
         * return the algorithm name and mode.
         *
diff --git a/crypto/src/crypto/modes/CtsBlockCipher.cs b/crypto/src/crypto/modes/CtsBlockCipher.cs
new file mode 100644
index 000000000..a32b49675
--- /dev/null
+++ b/crypto/src/crypto/modes/CtsBlockCipher.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+    * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
+    * be used to produce cipher text which is the same outLength as the plain text.
+    */
+    public class CtsBlockCipher
+		: BufferedBlockCipher
+    {
+        private readonly int blockSize;
+
+        /**
+        * Create a buffered block cipher that uses Cipher Text Stealing
+        *
+        * @param cipher the underlying block cipher this buffering object wraps.
+        */
+        public CtsBlockCipher(
+            IBlockCipher cipher)
+        {
+			// TODO Should this test for acceptable ones instead?
+			if (cipher is OfbBlockCipher || cipher is CfbBlockCipher)
+                throw new ArgumentException("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 of 'length' bytes.
+        *
+        * @param length the outLength of the input.
+        * @return the space required to accommodate a call to update
+        * with length bytes of input.
+        */
+        public override int GetUpdateOutputSize(
+            int length)
+        {
+            int total = length + 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 length bytes.
+        *
+        * @param length the outLength of the input.
+        * @return the space required to accommodate a call to update and doFinal
+        * with length bytes of input.
+        */
+        public override int GetOutputSize(
+            int length)
+        {
+            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 InvalidOperationException if the cipher isn't initialised.
+        */
+        public override int ProcessByte(
+            byte	input,
+            byte[]	output,
+            int		outOff)
+        {
+            int resultLen = 0;
+
+            if (bufOff == buf.Length)
+            {
+                resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+				Debug.Assert(resultLen == blockSize);
+
+				Array.Copy(buf, blockSize, buf, 0, blockSize);
+                bufOff = blockSize;
+            }
+
+            buf[bufOff++] = input;
+
+            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 length 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 InvalidOperationException if the cipher isn't initialised.
+        */
+        public override int ProcessBytes(
+            byte[]	input,
+            int		inOff,
+            int		length,
+            byte[]	output,
+            int		outOff)
+        {
+            if (length < 0)
+            {
+                throw new ArgumentException("Can't have a negative input outLength!");
+            }
+
+            int blockSize = GetBlockSize();
+            int outLength = GetUpdateOutputSize(length);
+
+            if (outLength > 0)
+            {
+                if ((outOff + outLength) > output.Length)
+                {
+                    throw new DataLengthException("output buffer too short");
+                }
+            }
+
+            int resultLen = 0;
+            int gapLen = buf.Length - bufOff;
+
+            if (length > gapLen)
+            {
+                Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+                resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+                Array.Copy(buf, blockSize, buf, 0, blockSize);
+
+                bufOff = blockSize;
+
+                length -= gapLen;
+                inOff += gapLen;
+
+                while (length > blockSize)
+                {
+                    Array.Copy(input, inOff, buf, bufOff, blockSize);
+                    resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+                    Array.Copy(buf, blockSize, buf, 0, blockSize);
+
+                    length -= blockSize;
+                    inOff += blockSize;
+                }
+            }
+
+            Array.Copy(input, inOff, buf, bufOff, length);
+
+            bufOff += length;
+
+            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 InvalidOperationException if the underlying cipher is not
+        * initialised.
+        * @exception InvalidCipherTextException if cipher text decrypts wrongly (in
+        * case the exception will never Get thrown).
+        */
+        public override int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            if (bufOff + outOff > output.Length)
+            {
+                throw new DataLengthException("output buffer too small in doFinal");
+            }
+
+            int blockSize = cipher.GetBlockSize();
+            int length = 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];
+                }
+
+				IBlockCipher c = (cipher is CbcBlockCipher)
+					?	((CbcBlockCipher)cipher).GetUnderlyingCipher()
+					:	cipher;
+
+				c.ProcessBlock(buf, blockSize, output, outOff);
+
+				Array.Copy(block, 0, output, outOff + blockSize, length);
+            }
+            else
+            {
+                byte[] lastBlock = new byte[blockSize];
+
+				IBlockCipher c = (cipher is CbcBlockCipher)
+					?	((CbcBlockCipher)cipher).GetUnderlyingCipher()
+					:	cipher;
+
+				c.ProcessBlock(buf, 0, block, 0);
+
+				for (int i = blockSize; i != bufOff; i++)
+                {
+                    lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+                }
+
+                Array.Copy(buf, blockSize, block, 0, length);
+
+                cipher.ProcessBlock(block, 0, output, outOff);
+                Array.Copy(lastBlock, 0, output, outOff + blockSize, length);
+            }
+
+            int offset = bufOff;
+
+            Reset();
+
+            return offset;
+        }
+    }
+}
diff --git a/crypto/src/crypto/modes/EAXBlockCipher.cs b/crypto/src/crypto/modes/EAXBlockCipher.cs
index b3016d79c..5ccc69b66 100644
--- a/crypto/src/crypto/modes/EAXBlockCipher.cs
+++ b/crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -40,6 +40,9 @@ namespace Org.BouncyCastle.Crypto.Modes
 		private byte[] bufBlock;
 		private int bufOff;
 
+        private bool cipherInitialized;
+        private byte[] initialAssociatedText;
+
 		/**
 		* Constructor that accepts an instance of a block cipher engine.
 		*
@@ -62,6 +65,11 @@ namespace Org.BouncyCastle.Crypto.Modes
 			get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
 		}
 
+		public IBlockCipher GetUnderlyingCipher()
+		{
+			return cipher;
+		}
+
 		public virtual int GetBlockSize()
 		{
 			return cipher.GetBlockSize();
@@ -73,7 +81,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 		{
 			this.forEncryption = forEncryption;
 
-			byte[] nonce, associatedText;
+			byte[] nonce;
 			ICipherParameters keyParam;
 
 			if (parameters is AeadParameters)
@@ -81,7 +89,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 				AeadParameters param = (AeadParameters) parameters;
 
 				nonce = param.GetNonce();
-				associatedText = param.GetAssociatedText();
+                initialAssociatedText = param.GetAssociatedText();
 				macSize = param.MacSize / 8;
 				keyParam = param.Key;
 			}
@@ -90,7 +98,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 				ParametersWithIV param = (ParametersWithIV) parameters;
 
 				nonce = param.GetIV();
-				associatedText = new byte[0];
+                initialAssociatedText = null;
 				macSize = mac.GetMacSize() / 2;
 				keyParam = param.Parameters;
 			}
@@ -99,26 +107,45 @@ namespace Org.BouncyCastle.Crypto.Modes
 				throw new ArgumentException("invalid parameters passed to EAX");
 			}
 
-			byte[] tag = new byte[blockSize];
+            byte[] tag = new byte[blockSize];
 
-			mac.Init(keyParam);
-			tag[blockSize - 1] = (byte) Tag.H;
-			mac.BlockUpdate(tag, 0, blockSize);
-			mac.BlockUpdate(associatedText, 0, associatedText.Length);
-			mac.DoFinal(associatedTextMac, 0);
+            // Key reuse implemented in CBC mode of underlying CMac
+            mac.Init(keyParam);
 
-			tag[blockSize - 1] = (byte) Tag.N;
-			mac.BlockUpdate(tag, 0, blockSize);
-			mac.BlockUpdate(nonce, 0, nonce.Length);
-			mac.DoFinal(nonceMac, 0);
+            tag[blockSize - 1] = (byte)Tag.N;
+            mac.BlockUpdate(tag, 0, blockSize);
+            mac.BlockUpdate(nonce, 0, nonce.Length);
+            mac.DoFinal(nonceMac, 0);
 
-			tag[blockSize - 1] = (byte) Tag.C;
-			mac.BlockUpdate(tag, 0, blockSize);
+            tag[blockSize - 1] = (byte)Tag.H;
+            mac.BlockUpdate(tag, 0, blockSize);
 
-			cipher.Init(true, new ParametersWithIV(keyParam, nonceMac));
+            if (initialAssociatedText != null)
+            {
+                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+            }
+
+            // Same BlockCipher underlies this and the mac, so reuse last key on cipher 
+            cipher.Init(true, new ParametersWithIV(null, nonceMac));
 		}
 
-		private void calculateMac()
+        private void InitCipher()
+        {
+            if (cipherInitialized)
+            {
+                return;
+            }
+
+            cipherInitialized = true;
+
+            mac.DoFinal(associatedTextMac, 0);
+
+            byte[] tag = new byte[blockSize];
+            tag[blockSize - 1] = (byte)Tag.C;
+            mac.BlockUpdate(tag, 0, blockSize);
+        }
+
+        private void CalculateMac()
 		{
 			byte[] outC = new byte[blockSize];
 			mac.DoFinal(outC, 0);
@@ -137,7 +164,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 		private void Reset(
 			bool clearMac)
 		{
-			cipher.Reset();
+            cipher.Reset(); // TODO Redundant since the mac will reset it?
 			mac.Reset();
 
 			bufOff = 0;
@@ -148,44 +175,75 @@ namespace Org.BouncyCastle.Crypto.Modes
 				Array.Clear(macBlock, 0, macBlock.Length);
 			}
 
-			byte[] tag = new byte[blockSize];
-			tag[blockSize - 1] = (byte) Tag.C;
-			mac.BlockUpdate(tag, 0, blockSize);
-		}
-
-		public virtual int ProcessByte(
+            byte[] tag = new byte[blockSize];
+            tag[blockSize - 1] = (byte)Tag.H;
+            mac.BlockUpdate(tag, 0, blockSize);
+
+            cipherInitialized = false;
+
+            if (initialAssociatedText != null)
+            {
+                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+            }
+        }
+        
+        public virtual void ProcessAadByte(byte input)
+        {
+            if (cipherInitialized)
+            {
+                throw new InvalidOperationException("AAD data cannot be added after encryption/decription processing has begun.");
+            }
+            mac.Update(input);
+        }
+
+        public void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+        {
+            if (cipherInitialized)
+            {
+                throw new InvalidOperationException("AAD data cannot be added after encryption/decription processing has begun.");
+            }
+            mac.BlockUpdate(inBytes, inOff, len);
+        }
+
+        public virtual int ProcessByte(
 			byte	input,
 			byte[]	outBytes,
 			int		outOff)
 		{
-			return process(input, outBytes, outOff);
+            InitCipher();
+
+            return Process(input, outBytes, outOff);
 		}
 
-		public virtual int ProcessBytes(
+        public virtual int ProcessBytes(
 			byte[]	inBytes,
 			int		inOff,
 			int		len,
 			byte[]	outBytes,
 			int		outOff)
 		{
-			int resultLen = 0;
+            InitCipher();
+
+            int resultLen = 0;
 
 			for (int i = 0; i != len; i++)
 			{
-				resultLen += process(inBytes[inOff + i], outBytes, outOff + resultLen);
+				resultLen += Process(inBytes[inOff + i], outBytes, outOff + resultLen);
 			}
 
-			return resultLen;
+            return resultLen;
 		}
 
 		public virtual int DoFinal(
 			byte[]	outBytes,
 			int		outOff)
 		{
-			int extra = bufOff;
+            InitCipher();
+
+            int extra = bufOff;
 			byte[] tmp = new byte[bufBlock.Length];
 
-			bufOff = 0;
+            bufOff = 0;
 
 			if (forEncryption)
 			{
@@ -196,7 +254,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
 				mac.BlockUpdate(tmp, 0, extra);
 
-				calculateMac();
+				CalculateMac();
 
 				Array.Copy(macBlock, 0, outBytes, outOff + extra, macSize);
 
@@ -216,9 +274,9 @@ namespace Org.BouncyCastle.Crypto.Modes
 					Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
 				}
 
-				calculateMac();
+				CalculateMac();
 
-				if (!verifyMac(bufBlock, extra - macSize))
+				if (!VerifyMac(bufBlock, extra - macSize))
 					throw new InvalidCipherTextException("mac check in EAX failed");
 
 				Reset(false);
@@ -236,24 +294,35 @@ namespace Org.BouncyCastle.Crypto.Modes
 			return mac;
 		}
 
-		public virtual int GetUpdateOutputSize(
+        public virtual int GetUpdateOutputSize(
 			int len)
 		{
-			return ((len + bufOff) / blockSize) * blockSize;
-		}
+            int totalData = len + bufOff;
+            if (!forEncryption)
+            {
+                if (totalData < macSize)
+                {
+                    return 0;
+                }
+                totalData -= macSize;
+            }
+            return totalData - totalData % blockSize;
+        }
 
 		public virtual int GetOutputSize(
 			int len)
 		{
-			if (forEncryption)
-			{
-				return len + bufOff + macSize;
-			}
+            int totalData = len + bufOff;
 
-			return len + bufOff - macSize;
-		}
+            if (forEncryption)
+            {
+                return totalData + macSize;
+            }
 
-		private int process(
+            return totalData < macSize ? 0 : totalData - macSize;
+        }
+
+		private int Process(
 			byte	b,
 			byte[]	outBytes,
 			int		outOff)
@@ -286,17 +355,16 @@ namespace Org.BouncyCastle.Crypto.Modes
 			return 0;
 		}
 
-		private bool verifyMac(byte[] mac, int off)
+		private bool VerifyMac(byte[] mac, int off)
 		{
-			for (int i = 0; i < macSize; i++)
-			{
-				if (macBlock[i] != mac[off + i])
-				{
-					return false;
-				}
-			}
+            int nonEqual = 0;
+
+            for (int i = 0; i < macSize; i++)
+            {
+                nonEqual |= (macBlock[i] ^ mac[off + i]);
+            }
 
-			return true;
+            return nonEqual == 0;
 		}
 	}
 }
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 6a3a4463d..2e2ac2eca 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -4,397 +4,513 @@ using Org.BouncyCastle.Crypto.Macs;
 using Org.BouncyCastle.Crypto.Modes.Gcm;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
-using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Modes
 {
-	/// <summary>
-	/// Implements the Galois/Counter mode (GCM) detailed in
-	/// NIST Special Publication 800-38D.
-	/// </summary>
-	public class GcmBlockCipher
-		: IAeadBlockCipher
-	{
-		private const int					BlockSize = 16;
-		private static readonly byte[]		Zeroes = new byte[BlockSize];
-
-		private readonly IBlockCipher	cipher;
-		private readonly IGcmMultiplier	multiplier;
-
-		// These fields are set by Init and not modified by processing
-		private bool				forEncryption;
-		private int                 macSize;
-		private byte[]              nonce;
-		private byte[]              A;
-		private KeyParameter        keyParam;
-		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 ulong		totalLength;
-
-		public GcmBlockCipher(
-			IBlockCipher c)
-			: this(c, null)
-		{
-	    }
-
-	    public GcmBlockCipher(
-			IBlockCipher	c,
-			IGcmMultiplier	m)
-	    {
-			if (c.GetBlockSize() != BlockSize)
-				throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
-
-	        if (m == null)
-	        {
-	            // TODO Consider a static property specifying default multiplier
-	            m = new Tables8kGcmMultiplier();
-	        }
-
-			this.cipher = c;
-			this.multiplier = m;
-		}
-
-		public virtual string AlgorithmName
-		{
-			get { return cipher.AlgorithmName + "/GCM"; }
-		}
-
-		public virtual int GetBlockSize()
-		{
-			return BlockSize;
-		}
-
-		public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
-		{
-			this.forEncryption = forEncryption;
-			this.macBlock = null;
-
-			if (parameters is AeadParameters)
-			{
-				AeadParameters param = (AeadParameters)parameters;
-
-				nonce = param.GetNonce();
-				A = param.GetAssociatedText();
-
-				int macSizeBits = param.MacSize;
-	            if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0)
-	            {
-	                throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
-	            }
-
-	            macSize = macSizeBits / 8; 
-				keyParam = param.Key;
-			}
-			else if (parameters is ParametersWithIV)
-			{
-				ParametersWithIV param = (ParametersWithIV)parameters;
-
-				nonce = param.GetIV();
-				A = null;
-	            macSize = 16; 
-				keyParam = (KeyParameter)param.Parameters;
-			}
-			else
-			{
-				throw new ArgumentException("invalid parameters passed to GCM");
-			}
-
-			int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
-			this.bufBlock = new byte[bufLength];
-
-			if (nonce == null || nonce.Length < 1)
-			{
-				throw new ArgumentException("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
-			cipher.Init(true, keyParam);
-
-			// TODO This should be configurable by Init parameters
-			// (but must be 16 if nonce length not 12) (BlockSize?)
-//			this.tagLength = 16;
-
-			this.H = new byte[BlockSize];
-			cipher.ProcessBlock(H, 0, H, 0);
-			multiplier.Init(H);
-
-			this.initS = gHASH(A);
-
-			if (nonce.Length == 12)
-			{
-				this.J0 = new byte[16];
-				Array.Copy(nonce, 0, J0, 0, nonce.Length);
-				this.J0[15] = 0x01;
-			}
-			else
-			{
-				this.J0 = gHASH(nonce);
-				byte[] X = new byte[16];
-				packLength((ulong)nonce.Length * 8UL, X, 8);
-				GcmUtilities.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 virtual byte[] GetMac()
-		{
-			return Arrays.Clone(macBlock);
-		}
-
-		public virtual int GetOutputSize(
-			int len)
-		{
-			if (forEncryption)
-			{
-				return len + bufOff + macSize;
-			}
-
-			return len + bufOff - macSize;
-		}
-
-		public virtual int GetUpdateOutputSize(
-			int len)
-		{
-			return ((len + bufOff) / BlockSize) * BlockSize;
-		}
-
-		public virtual int ProcessByte(
-			byte	input,
-			byte[]	output,
-			int		outOff)
-		{
-			return Process(input, output, outOff);
-		}
-
-		public virtual int ProcessBytes(
-			byte[]	input,
-			int		inOff,
-			int		len,
-			byte[]	output,
-			int		outOff)
-		{
-			int resultLen = 0;
-
-			for (int i = 0; i != len; i++)
-			{
-//				resultLen += Process(input[inOff + i], output, outOff + resultLen);
-				bufBlock[bufOff++] = input[inOff + i];
-
-				if (bufOff == bufBlock.Length)
-				{
-					gCTRBlock(bufBlock, BlockSize, output, outOff + resultLen);
-					if (!forEncryption)
-					{
-						Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
-					}
-//		            bufOff = 0;
-					bufOff = bufBlock.Length - BlockSize;
-//		            return bufBlock.Length;
-					resultLen += BlockSize;
-				}
-			}
-
-			return resultLen;
-		}
-
-		private int Process(
-			byte	input,
-			byte[]	output,
-			int		outOff)
-		{
-			bufBlock[bufOff++] = input;
-
-			if (bufOff == bufBlock.Length)
-			{
-				gCTRBlock(bufBlock, BlockSize, output, outOff);
-				if (!forEncryption)
-				{
-					Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
-				}
-	//            bufOff = 0;
-				bufOff = bufBlock.Length - BlockSize;
-	//            return bufBlock.Length;
-				return BlockSize;
-			}
-
-			return 0;
-		}
-
-		public int DoFinal(byte[] output, int outOff)
-		{
-			int extra = bufOff;
-			if (!forEncryption)
-			{
-				if (extra < macSize)
-					throw new InvalidCipherTextException("data too short");
-
-				extra -= macSize;
-			}
-
-			if (extra > 0)
-			{
-				byte[] tmp = new byte[BlockSize];
-				Array.Copy(bufBlock, 0, tmp, 0, extra);
-				gCTRBlock(tmp, extra, output, outOff);
-			}
-
-			// Final gHASH
-			byte[] X = new byte[16];
-			packLength((ulong)A.Length * 8UL, X, 0);
-			packLength(totalLength * 8UL, X, 8);
-
-			GcmUtilities.Xor(S, X);
-			multiplier.MultiplyH(S);
-
-			// TODO Fix this if tagLength becomes configurable
-			// T = MSBt(GCTRk(J0,S))
-			byte[] tag = new byte[BlockSize];
-			cipher.ProcessBlock(J0, 0, tag, 0);
-			GcmUtilities.Xor(tag, S);
-
-			int resultLen = extra;
-
-			// We place into macBlock our calculated value for T
-			this.macBlock = new byte[macSize];
-			Array.Copy(tag, 0, macBlock, 0, macSize);
-
-			if (forEncryption)
-			{
-				// Append T to the message
-				Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
-				resultLen += macSize;
-			}
-			else
-			{
-				// Retrieve the T value from the message and compare to calculated one
-				byte[] msgMac = new byte[macSize];
-				Array.Copy(bufBlock, extra, msgMac, 0, macSize);
-				if (!Arrays.ConstantTimeAreEqual(this.macBlock, msgMac))
-					throw new InvalidCipherTextException("mac check in GCM failed");
-			}
-
-			Reset(false);
-
-			return resultLen;
-		}
-
-		public virtual void Reset()
-		{
-			Reset(true);
-		}
-
-		private void Reset(
-			bool clearMac)
-		{
-			S = Arrays.Clone(initS);
-			counter = Arrays.Clone(J0);
-			bufOff = 0;
-			totalLength = 0;
-
-			if (bufBlock != null)
-			{
-				Array.Clear(bufBlock, 0, bufBlock.Length);
-			}
-
-			if (clearMac)
-			{
-				macBlock = null;
-			}
-
-			cipher.Reset();
-		}
-
-		private void gCTRBlock(byte[] buf, int bufCount, byte[] output, int outOff)
-		{
-//			inc(counter);
-			for (int i = 15; i >= 12; --i)
-			{
-				if (++counter[i] != 0) break;
-			}
-
-			byte[] tmp = new byte[BlockSize];
-			cipher.ProcessBlock(counter, 0, tmp, 0);
-
-			byte[] hashBytes;
-			if (forEncryption)
-			{
-				Array.Copy(Zeroes, bufCount, tmp, bufCount, BlockSize - bufCount);
-				hashBytes = tmp;
-			}
-			else
-			{
-				hashBytes = buf;
-			}
-
-			for (int i = bufCount - 1; i >= 0; --i)
-			{
-				tmp[i] ^= buf[i];
-				output[outOff + i] = tmp[i];
-			}
-
-//			gHASHBlock(hashBytes);
-			GcmUtilities.Xor(S, hashBytes);
-			multiplier.MultiplyH(S);
-
-			totalLength += (ulong)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 = System.Math.Min(b.Length - pos, 16);
-				Array.Copy(b, pos, X, 0, num);
-				GcmUtilities.Xor(Y, X);
-				multiplier.MultiplyH(Y);
-			}
-
-			return Y;
-		}
-
-//		private void gHASHBlock(byte[] block)
-//		{
-//			GcmUtilities.Xor(S, block);
-//			multiplier.MultiplyH(S);
-//		}
-
-//		private static void inc(byte[] block)
-//		{
-//			for (int i = 15; i >= 12; --i)
-//			{
-//				if (++block[i] != 0) break;
-//			}
-//		}
-
-		private static void packLength(ulong len, byte[] bs, int off)
-		{
-			Pack.UInt32_To_BE((uint)(len >> 32), bs, off); 
-			Pack.UInt32_To_BE((uint)len, bs, off + 4);
-		}
-	}
-}
\ No newline at end of file
+    /// <summary>
+    /// Implements the Galois/Counter mode (GCM) detailed in
+    /// NIST Special Publication 800-38D.
+    /// </summary>
+    public class GcmBlockCipher
+        : IAeadBlockCipher
+    {
+        private const int BlockSize = 16;
+
+        private readonly IBlockCipher	cipher;
+        private readonly IGcmMultiplier	multiplier;
+        private IGcmExponentiator exp;
+
+        // These fields are set by Init and not modified by processing
+        private bool        forEncryption;
+        private int         macSize;
+        private byte[]      nonce;
+        private byte[]      initialAssociatedText;
+        private byte[]      H;
+        private byte[]      J0;
+
+        // These fields are modified during processing
+        private byte[]		bufBlock;
+        private byte[]		macBlock;
+        private byte[]      S, S_at, S_atPre;
+        private byte[]      counter;
+        private int         bufOff;
+        private ulong		totalLength;
+        private byte[]      atBlock;
+        private int         atBlockPos;
+        private ulong       atLength;
+        private ulong       atLengthPre;
+
+        public GcmBlockCipher(
+            IBlockCipher c)
+            : this(c, null)
+        {
+        }
+
+        public GcmBlockCipher(
+            IBlockCipher	c,
+            IGcmMultiplier	m)
+        {
+            if (c.GetBlockSize() != BlockSize)
+                throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
+
+            if (m == null)
+            {
+                // TODO Consider a static property specifying default multiplier
+                m = new Tables8kGcmMultiplier();
+            }
+
+            this.cipher = c;
+            this.multiplier = m;
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return cipher.AlgorithmName + "/GCM"; }
+        }
+
+        public IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
+
+        public virtual int GetBlockSize()
+        {
+            return BlockSize;
+        }
+
+        /// <remarks>
+        /// MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits.
+        /// Sizes less than 96 are not recommended, but are supported for specialized applications.
+        /// </remarks>
+        public virtual void Init(
+            bool				forEncryption,
+            ICipherParameters	parameters)
+        {
+            this.forEncryption = forEncryption;
+            this.macBlock = null;
+
+            KeyParameter keyParam;
+
+            if (parameters is AeadParameters)
+            {
+                AeadParameters param = (AeadParameters)parameters;
+
+                nonce = param.GetNonce();
+                initialAssociatedText = param.GetAssociatedText();
+
+                int macSizeBits = param.MacSize;
+                if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
+                {
+                    throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
+                }
+
+                macSize = macSizeBits / 8; 
+                keyParam = param.Key;
+            }
+            else if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV param = (ParametersWithIV)parameters;
+
+                nonce = param.GetIV();
+                initialAssociatedText = null;
+                macSize = 16; 
+                keyParam = (KeyParameter)param.Parameters;
+            }
+            else
+            {
+                throw new ArgumentException("invalid parameters passed to GCM");
+            }
+
+            int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
+            this.bufBlock = new byte[bufLength];
+
+            if (nonce == null || nonce.Length < 1)
+            {
+                throw new ArgumentException("IV must be at least 1 byte");
+            }
+
+            // TODO Restrict macSize to 16 if nonce length not 12?
+
+            // Cipher always used in forward mode
+            // if keyParam is null we're reusing the last key.
+            if (keyParam != null)
+            {
+                cipher.Init(true, keyParam);
+
+                this.H = new byte[BlockSize];
+                cipher.ProcessBlock(H, 0, H, 0);
+
+                // if keyParam is null we're reusing the last key and the multiplier doesn't need re-init
+                multiplier.Init(H);
+                exp = null;
+            }
+            else if (this.H == null)
+            {
+                throw new ArgumentException("Key must be specified in initial init");
+            }
+
+            this.J0 = new byte[BlockSize];
+
+            if (nonce.Length == 12)
+            {
+                Array.Copy(nonce, 0, J0, 0, nonce.Length);
+                this.J0[BlockSize - 1] = 0x01;
+            }
+            else
+            {
+                gHASH(J0, nonce, nonce.Length);
+                byte[] X = new byte[BlockSize];
+                Pack.UInt64_To_BE((ulong)nonce.Length * 8UL, X, 8);
+                gHASHBlock(J0, X);
+            }
+
+            this.S = new byte[BlockSize];
+            this.S_at = new byte[BlockSize];
+            this.S_atPre = new byte[BlockSize];
+            this.atBlock = new byte[BlockSize];
+            this.atBlockPos = 0;
+            this.atLength = 0;
+            this.atLengthPre = 0;
+            this.counter = Arrays.Clone(J0);
+            this.bufOff = 0;
+            this.totalLength = 0;
+
+            if (initialAssociatedText != null)
+            {
+                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+            }
+        }
+
+        public virtual byte[] GetMac()
+        {
+            return Arrays.Clone(macBlock);
+        }
+
+        public virtual int GetOutputSize(
+            int len)
+        {
+            int totalData = len + bufOff;
+
+            if (forEncryption)
+            {
+                return totalData + macSize;
+            }
+
+            return totalData < macSize ? 0 : totalData - macSize;
+        }
+
+        public virtual int GetUpdateOutputSize(
+            int len)
+        {
+            int totalData = len + bufOff;
+            if (!forEncryption)
+            {
+                if (totalData < macSize)
+                {
+                    return 0;
+                }
+                totalData -= macSize;
+            }
+            return totalData - totalData % BlockSize;
+        }
+
+        public virtual void ProcessAadByte(byte input)
+        {
+            atBlock[atBlockPos] = input;
+            if (++atBlockPos == BlockSize)
+            {
+                // Hash each block as it fills
+                gHASHBlock(S_at, atBlock);
+                atBlockPos = 0;
+                atLength += BlockSize;
+            }
+        }
+
+        public virtual void ProcessAadBytes(byte[] inBytes, int inOff, int len)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                atBlock[atBlockPos] = inBytes[inOff + i];
+                if (++atBlockPos == BlockSize)
+                {
+                    // Hash each block as it fills
+                    gHASHBlock(S_at, atBlock);
+                    atBlockPos = 0;
+                    atLength += BlockSize;
+                }
+            }
+        }
+
+        private void InitCipher()
+        {
+            if (atLength > 0)
+            {
+                Array.Copy(S_at, 0, S_atPre, 0, BlockSize);
+                atLengthPre = atLength;
+            }
+
+            // Finish hash for partial AAD block
+            if (atBlockPos > 0)
+            {
+                gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
+                atLengthPre += (uint)atBlockPos;
+            }
+
+            if (atLengthPre > 0)
+            {
+                Array.Copy(S_atPre, 0, S, 0, BlockSize);
+            }
+        }
+
+        public virtual int ProcessByte(
+            byte	input,
+            byte[]	output,
+            int		outOff)
+        {
+            bufBlock[bufOff] = input;
+            if (++bufOff == bufBlock.Length)
+            {
+                OutputBlock(output, outOff);
+                return BlockSize;
+            }
+            return 0;
+        }
+
+        public virtual int ProcessBytes(
+            byte[]	input,
+            int		inOff,
+            int		len,
+            byte[]	output,
+            int		outOff)
+        {
+            int resultLen = 0;
+
+            for (int i = 0; i < len; ++i)
+            {
+                bufBlock[bufOff] = input[inOff + i];
+                if (++bufOff == bufBlock.Length)
+                {
+                    OutputBlock(output, outOff + resultLen);
+                    resultLen += BlockSize;
+                }
+            }
+
+            return resultLen;
+        }
+
+        private void OutputBlock(byte[] output, int offset)
+        {
+            if (totalLength == 0)
+            {
+                InitCipher();
+            }
+            gCTRBlock(bufBlock, output, offset);
+            if (forEncryption)
+            {
+                bufOff = 0;
+            }
+            else
+            {
+                Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
+                bufOff = macSize;
+            }
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (totalLength == 0)
+            {
+                InitCipher();
+            }
+
+            int extra = bufOff;
+            if (!forEncryption)
+            {
+                if (extra < macSize)
+                    throw new InvalidCipherTextException("data too short");
+
+                extra -= macSize;
+            }
+
+            if (extra > 0)
+            {
+                gCTRPartial(bufBlock, 0, extra, output, outOff);
+            }
+
+            atLength += (uint)atBlockPos;
+
+            if (atLength > atLengthPre)
+            {
+                /*
+                 *  Some AAD was sent after the cipher started. We determine the difference b/w the hash value
+                 *  we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at).
+                 *  Then we carry this difference forward by multiplying by H^c, where c is the number of (full or
+                 *  partial) cipher-text blocks produced, and adjust the current hash.
+                 */
+
+                // Finish hash for partial AAD block
+                if (atBlockPos > 0)
+                {
+                    gHASHPartial(S_at, atBlock, 0, atBlockPos);
+                }
+
+                // Find the difference between the AAD hashes
+                if (atLengthPre > 0)
+                {
+                    GcmUtilities.Xor(S_at, S_atPre);
+                }
+
+                // Number of cipher-text blocks produced
+                long c = (long)(((totalLength * 8) + 127) >> 7);
+
+                // Calculate the adjustment factor
+                byte[] H_c = new byte[16];
+                if (exp == null)
+                {
+                    exp = new Tables1kGcmExponentiator();
+                    exp.Init(H);
+                }
+                exp.ExponentiateX(c, H_c);
+
+                // Carry the difference forward
+                GcmUtilities.Multiply(S_at, H_c);
+
+                // Adjust the current hash
+                GcmUtilities.Xor(S, S_at);
+            }
+
+            // Final gHASH
+            byte[] X = new byte[BlockSize];
+            Pack.UInt64_To_BE(atLength * 8UL, X, 0);
+            Pack.UInt64_To_BE(totalLength * 8UL, X, 8);
+
+            gHASHBlock(S, X);
+
+            // T = MSBt(GCTRk(J0,S))
+            byte[] tag = new byte[BlockSize];
+            cipher.ProcessBlock(J0, 0, tag, 0);
+            GcmUtilities.Xor(tag, S);
+
+            int resultLen = extra;
+
+            // We place into macBlock our calculated value for T
+            this.macBlock = new byte[macSize];
+            Array.Copy(tag, 0, macBlock, 0, macSize);
+
+            if (forEncryption)
+            {
+                // Append T to the message
+                Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
+                resultLen += macSize;
+            }
+            else
+            {
+                // Retrieve the T value from the message and compare to calculated one
+                byte[] msgMac = new byte[macSize];
+                Array.Copy(bufBlock, extra, msgMac, 0, macSize);
+                if (!Arrays.ConstantTimeAreEqual(this.macBlock, msgMac))
+                    throw new InvalidCipherTextException("mac check in GCM failed");
+            }
+
+            Reset(false);
+
+            return resultLen;
+        }
+
+        public virtual void Reset()
+        {
+            Reset(true);
+        }
+
+        private void Reset(
+            bool clearMac)
+        {
+            cipher.Reset();
+
+            S = new byte[BlockSize];
+            S_at = new byte[BlockSize];
+            S_atPre = new byte[BlockSize];
+            atBlock = new byte[BlockSize];
+            atBlockPos = 0;
+            atLength = 0;
+            atLengthPre = 0;
+            counter = Arrays.Clone(J0);
+            bufOff = 0;
+            totalLength = 0;
+
+            if (bufBlock != null)
+            {
+                Arrays.Fill(bufBlock, 0);
+            }
+
+            if (clearMac)
+            {
+                macBlock = null;
+            }
+
+            if (initialAssociatedText != null)
+            {
+                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+            }
+        }
+
+        private void gCTRBlock(byte[] block, byte[] output, int outOff)
+        {
+            byte[] tmp = GetNextCounterBlock();
+
+            GcmUtilities.Xor(tmp, block);
+            Array.Copy(tmp, 0, output, outOff, BlockSize);
+
+            gHASHBlock(S, forEncryption ? tmp : block);
+
+            totalLength += BlockSize;
+        }
+
+        private void gCTRPartial(byte[] buf, int off, int len, byte[] output, int outOff)
+        {
+            byte[] tmp = GetNextCounterBlock();
+
+            GcmUtilities.Xor(tmp, buf, off, len);
+            Array.Copy(tmp, 0, output, outOff, len);
+
+            gHASHPartial(S, forEncryption ? tmp : buf, 0, len);
+
+            totalLength += (uint)len;
+        }
+
+        private void gHASH(byte[] Y, byte[] b, int len)
+        {
+            for (int pos = 0; pos < len; pos += BlockSize)
+            {
+                int num = System.Math.Min(len - pos, BlockSize);
+                gHASHPartial(Y, b, pos, num);
+            }
+        }
+
+        private void gHASHBlock(byte[] Y, byte[] b)
+        {
+            GcmUtilities.Xor(Y, b);
+            multiplier.MultiplyH(Y);
+        }
+
+        private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
+        {
+            GcmUtilities.Xor(Y, b, off, len);
+            multiplier.MultiplyH(Y);
+        }
+
+        private byte[] GetNextCounterBlock()
+        {
+            for (int i = 15; i >= 12; --i)
+            {
+                if (++counter[i] != 0) break;
+            }
+
+            byte[] tmp = new byte[BlockSize];
+            // TODO Sure would be nice if ciphers could operate on int[]
+            cipher.ProcessBlock(counter, 0, tmp, 0);
+            return tmp;
+        }
+    }
+}
diff --git a/crypto/src/crypto/modes/GOFBBlockCipher.cs b/crypto/src/crypto/modes/GOFBBlockCipher.cs
index 7db843115..a91562549 100644
--- a/crypto/src/crypto/modes/GOFBBlockCipher.cs
+++ b/crypto/src/crypto/modes/GOFBBlockCipher.cs
@@ -98,7 +98,11 @@ namespace Org.BouncyCastle.Crypto.Modes
 
 			Reset();
 
-			cipher.Init(true, parameters);
+            // if it's null, key is to be reused.
+            if (parameters != null)
+            {
+                cipher.Init(true, parameters);
+            }
 		}
 
 		/**
diff --git a/crypto/src/crypto/modes/IAeadBlockCipher.cs b/crypto/src/crypto/modes/IAeadBlockCipher.cs
index ca7dab44c..52c4ff428 100644
--- a/crypto/src/crypto/modes/IAeadBlockCipher.cs
+++ b/crypto/src/crypto/modes/IAeadBlockCipher.cs
@@ -11,6 +11,9 @@ namespace Org.BouncyCastle.Crypto.Modes
 		/// <summary>The name of the algorithm this cipher implements.</summary>
 		string AlgorithmName { get; }
 
+		/// <summary>The block cipher underlying this algorithm.</summary>
+		IBlockCipher GetUnderlyingCipher();
+
 		/// <summary>Initialise the cipher.</summary>
 		/// <remarks>Parameter can either be an AeadParameters or a ParametersWithIV object.</remarks>
 		/// <param name="forEncryption">Initialise for encryption if true, for decryption if false.</param>
@@ -20,7 +23,19 @@ namespace Org.BouncyCastle.Crypto.Modes
 		/// <returns>The block size for this cipher, in bytes.</returns>
 		int GetBlockSize();
 
-		/**
+        /// <summary>Add a single byte to the associated data check.</summary>
+		/// <remarks>If the implementation supports it, this will be an online operation and will not retain the associated data.</remarks>
+        /// <param name="input">The byte to be processed.</param>
+        void ProcessAadByte(byte input);
+
+        /// <summary>Add a sequence of bytes to the associated data check.</summary>
+		/// <remarks>If the implementation supports it, this will be an online operation and will not retain the associated data.</remarks>
+        /// <param name="inBytes">The input byte array.</param>
+        /// <param name="inOff">The offset into the input array where the data to be processed starts.</param>
+        /// <param name="len">The number of bytes to be processed.</param>
+        void ProcessAadBytes(byte[] inBytes, int inOff, int len);
+
+        /**
 		* Encrypt/decrypt a single byte.
 		*
 		* @param input the byte to be processed.
diff --git a/crypto/src/crypto/modes/OCBBlockCipher.cs b/crypto/src/crypto/modes/OCBBlockCipher.cs
new file mode 100644
index 000000000..54359dfe8
--- /dev/null
+++ b/crypto/src/crypto/modes/OCBBlockCipher.cs
@@ -0,0 +1,558 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+     * An implementation of <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB
+     * Authenticated-Encryption Algorithm</a>, licensed per:
+     * 
+     * <blockquote><p><a href="http://www.cs.ucdavis.edu/~rogaway/ocb/license1.pdf">License for
+     * Open-Source Software Implementations of OCB</a> (Jan 9, 2013) - 'License 1'<br/>
+     * Under this license, you are authorized to make, use, and distribute open-source software
+     * implementations of OCB. This license terminates for you if you sue someone over their open-source
+     * software implementation of OCB claiming that you have a patent covering their implementation.
+     * </p><p>
+     * This is a non-binding summary of a legal document (the link above). The parameters of the license
+     * are specified in the license document and that document is controlling.</p></blockquote>
+     */
+    public class OcbBlockCipher
+        : IAeadBlockCipher
+    {
+        private const int BLOCK_SIZE = 16;
+
+        private readonly IBlockCipher hashCipher;
+        private readonly IBlockCipher mainCipher;
+
+        /*
+         * CONFIGURATION
+         */
+        private bool forEncryption;
+        private int macSize;
+        private byte[] initialAssociatedText;
+
+        /*
+         * KEY-DEPENDENT
+         */
+        // NOTE: elements are lazily calculated
+        private IList L;
+        private byte[] L_Asterisk, L_Dollar;
+
+        /*
+         * NONCE-DEPENDENT
+         */
+        private byte[] KtopInput = null;
+        private byte[] Stretch = new byte[24];
+        private byte[] OffsetMAIN_0 = new byte[16];
+
+        /*
+         * PER-ENCRYPTION/DECRYPTION
+         */
+        private byte[] hashBlock, mainBlock;
+        private int hashBlockPos, mainBlockPos;
+        private long hashBlockCount, mainBlockCount;
+        private byte[] OffsetHASH;
+        private byte[] Sum;
+        private byte[] OffsetMAIN = new byte[16];
+        private byte[] Checksum;
+
+        // NOTE: The MAC value is preserved after doFinal
+        private byte[] macBlock;
+
+        public OcbBlockCipher(IBlockCipher hashCipher, IBlockCipher mainCipher)
+        {
+            if (hashCipher == null)
+                throw new ArgumentNullException("hashCipher");
+            if (hashCipher.GetBlockSize() != BLOCK_SIZE)
+                throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "hashCipher");
+            if (mainCipher == null)
+                throw new ArgumentNullException("mainCipher");
+            if (mainCipher.GetBlockSize() != BLOCK_SIZE)
+                throw new ArgumentException("must have a block size of " + BLOCK_SIZE, "mainCipher");
+
+            if (!hashCipher.AlgorithmName.Equals(mainCipher.AlgorithmName))
+                throw new ArgumentException("'hashCipher' and 'mainCipher' must be the same algorithm");
+
+            this.hashCipher = hashCipher;
+            this.mainCipher = mainCipher;
+        }
+
+        public virtual IBlockCipher GetUnderlyingCipher()
+        {
+            return mainCipher;
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return mainCipher.AlgorithmName + "/OCB"; }
+        }
+
+        public virtual void Init(bool forEncryption, ICipherParameters parameters)
+        {
+            bool oldForEncryption = this.forEncryption;
+            this.forEncryption = forEncryption;
+            this.macBlock = null;
+
+            KeyParameter keyParameter;
+
+            byte[] N;
+            if (parameters is AeadParameters)
+            {
+                AeadParameters aeadParameters = (AeadParameters) parameters;
+
+                N = aeadParameters.GetNonce();
+                initialAssociatedText = aeadParameters.GetAssociatedText();
+
+                int macSizeBits = aeadParameters.MacSize;
+                if (macSizeBits < 64 || macSizeBits > 128 || macSizeBits % 8 != 0)
+                    throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
+
+                macSize = macSizeBits / 8;
+                keyParameter = aeadParameters.Key;
+            }
+            else if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV parametersWithIV = (ParametersWithIV) parameters;
+
+                N = parametersWithIV.GetIV();
+                initialAssociatedText = null;
+                macSize = 16;
+                keyParameter = (KeyParameter) parametersWithIV.Parameters;
+            }
+            else
+            {
+                throw new ArgumentException("invalid parameters passed to OCB");
+            }
+
+            this.hashBlock = new byte[16];
+            this.mainBlock = new byte[forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize)];
+
+            if (N == null)
+            {
+                N = new byte[0];
+            }
+
+            if (N.Length > 15)
+            {
+                throw new ArgumentException("IV must be no more than 15 bytes");
+            }
+
+            /*
+             * KEY-DEPENDENT INITIALISATION
+             */
+
+            if (keyParameter != null)
+            {
+                // hashCipher always used in forward mode
+                hashCipher.Init(true, keyParameter);
+                mainCipher.Init(forEncryption, keyParameter);
+                KtopInput = null;
+            }
+            else if (oldForEncryption != forEncryption)
+            {
+                throw new ArgumentException("cannot change encrypting state without providing key.");
+            }
+
+            this.L_Asterisk = new byte[16];
+            hashCipher.ProcessBlock(L_Asterisk, 0, L_Asterisk, 0);
+
+            this.L_Dollar = OCB_double(L_Asterisk);
+
+            this.L = Platform.CreateArrayList();
+            this.L.Add(OCB_double(L_Dollar));
+
+            /*
+             * NONCE-DEPENDENT AND PER-ENCRYPTION/DECRYPTION INITIALISATION
+             */
+
+            int bottom = ProcessNonce(N);
+
+            int bits = bottom % 8, bytes = bottom / 8;
+            if (bits == 0)
+            {
+                Array.Copy(Stretch, bytes, OffsetMAIN_0, 0, 16);
+            }
+            else
+            {
+                for (int i = 0; i < 16; ++i)
+                {
+                    uint b1 = Stretch[bytes];
+                    uint b2 = Stretch[++bytes];
+                    this.OffsetMAIN_0[i] = (byte) ((b1 << bits) | (b2 >> (8 - bits)));
+                }
+            }
+
+            this.hashBlockPos = 0;
+            this.mainBlockPos = 0;
+
+            this.hashBlockCount = 0;
+            this.mainBlockCount = 0;
+
+            this.OffsetHASH = new byte[16];
+            this.Sum = new byte[16];
+            Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
+            this.Checksum = new byte[16];
+
+            if (initialAssociatedText != null)
+            {
+                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+            }
+        }
+
+        protected virtual int ProcessNonce(byte[] N)
+        {
+            byte[] nonce = new byte[16];
+            Array.Copy(N, 0, nonce, nonce.Length - N.Length, N.Length);
+            nonce[0] = (byte)(macSize << 4);
+            nonce[15 - N.Length] |= 1;
+
+            int bottom = nonce[15] & 0x3F;
+            nonce[15] &= 0xC0;
+
+            /*
+             * When used with incrementing nonces, the cipher is only applied once every 64 inits.
+             */
+            if (KtopInput == null || !Arrays.AreEqual(nonce, KtopInput))
+            {
+                byte[] Ktop = new byte[16];
+                KtopInput = nonce;
+                hashCipher.ProcessBlock(KtopInput, 0, Ktop, 0);
+                Array.Copy(Ktop, 0, Stretch, 0, 16);
+                for (int i = 0; i < 8; ++i)
+                {
+                    Stretch[16 + i] = (byte)(Ktop[i] ^ Ktop[i + 1]);
+                }
+            }
+
+            return bottom;
+        }
+
+        public virtual int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+        public virtual byte[] GetMac()
+        {
+            return Arrays.Clone(macBlock);
+        }
+
+        public virtual int GetOutputSize(int len)
+        {
+            int totalData = len + mainBlockPos;
+            if (forEncryption)
+            {
+                return totalData + macSize;
+            }
+            return totalData < macSize ? 0 : totalData - macSize;
+        }
+
+        public virtual int GetUpdateOutputSize(int len)
+        {
+            int totalData = len + mainBlockPos;
+            if (!forEncryption)
+            {
+                if (totalData < macSize)
+                {
+                    return 0;
+                }
+                totalData -= macSize;
+            }
+            return totalData - totalData % BLOCK_SIZE;
+        }
+
+        public virtual void ProcessAadByte(byte input)
+        {
+            hashBlock[hashBlockPos] = input;
+            if (++hashBlockPos == hashBlock.Length)
+            {
+                ProcessHashBlock();
+            }
+        }
+
+        public virtual void ProcessAadBytes(byte[] input, int off, int len)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                hashBlock[hashBlockPos] = input[off + i];
+                if (++hashBlockPos == hashBlock.Length)
+                {
+                    ProcessHashBlock();
+                }
+            }
+        }
+
+        public virtual int ProcessByte(byte input, byte[] output, int outOff)
+        {
+            mainBlock[mainBlockPos] = input;
+            if (++mainBlockPos == mainBlock.Length)
+            {
+                ProcessMainBlock(output, outOff);
+                return BLOCK_SIZE;
+            }
+            return 0;
+        }
+
+        public virtual int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            int resultLen = 0;
+
+            for (int i = 0; i < len; ++i)
+            {
+                mainBlock[mainBlockPos] = input[inOff + i];
+                if (++mainBlockPos == mainBlock.Length)
+                {
+                    ProcessMainBlock(output, outOff + resultLen);
+                    resultLen += BLOCK_SIZE;
+                }
+            }
+
+            return resultLen;
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            /*
+             * For decryption, get the tag from the end of the message
+             */
+            byte[] tag = null;
+            if (!forEncryption) {
+                if (mainBlockPos < macSize)
+                    throw new InvalidCipherTextException("data too short");
+
+                mainBlockPos -= macSize;
+                tag = new byte[macSize];
+                Array.Copy(mainBlock, mainBlockPos, tag, 0, macSize);
+            }
+
+            /*
+             * HASH: Process any final partial block; compute final hash value
+             */
+            if (hashBlockPos > 0)
+            {
+                OCB_extend(hashBlock, hashBlockPos);
+                UpdateHASH(L_Asterisk);
+            }
+
+            /*
+             * OCB-ENCRYPT/OCB-DECRYPT: Process any final partial block
+             */
+            if (mainBlockPos > 0)
+            {
+                if (forEncryption)
+                {
+                    OCB_extend(mainBlock, mainBlockPos);
+                    Xor(Checksum, mainBlock);
+                }
+
+                Xor(OffsetMAIN, L_Asterisk);
+
+                byte[] Pad = new byte[16];
+                hashCipher.ProcessBlock(OffsetMAIN, 0, Pad, 0);
+
+                Xor(mainBlock, Pad);
+
+                Array.Copy(mainBlock, 0, output, outOff, mainBlockPos);
+
+                if (!forEncryption)
+                {
+                    OCB_extend(mainBlock, mainBlockPos);
+                    Xor(Checksum, mainBlock);
+                }
+            }
+
+            /*
+             * OCB-ENCRYPT/OCB-DECRYPT: Compute raw tag
+             */
+            Xor(Checksum, OffsetMAIN);
+            Xor(Checksum, L_Dollar);
+            hashCipher.ProcessBlock(Checksum, 0, Checksum, 0);
+            Xor(Checksum, Sum);
+
+            this.macBlock = new byte[macSize];
+            Array.Copy(Checksum, 0, macBlock, 0, macSize);
+
+            /*
+             * Validate or append tag and reset this cipher for the next run
+             */
+            int resultLen = mainBlockPos;
+
+            if (forEncryption)
+            {
+                // Append tag to the message
+                Array.Copy(macBlock, 0, output, outOff + resultLen, macSize);
+                resultLen += macSize;
+            }
+            else
+            {
+                // Compare the tag from the message with the calculated one
+                if (!Arrays.ConstantTimeAreEqual(macBlock, tag))
+                    throw new InvalidCipherTextException("mac check in OCB failed");
+            }
+
+            Reset(false);
+
+            return resultLen;
+        }
+
+        public virtual void Reset()
+        {
+            Reset(true);
+        }
+
+        protected virtual void Clear(byte[] bs)
+        {
+            if (bs != null)
+            {
+                Array.Clear(bs, 0, bs.Length);
+            }
+        }
+
+        protected virtual byte[] GetLSub(int n)
+        {
+            while (n >= L.Count)
+            {
+                L.Add(OCB_double((byte[]) L[L.Count - 1]));
+            }
+            return (byte[])L[n];
+        }
+
+        protected virtual void ProcessHashBlock()
+        {
+            /*
+             * HASH: Process any whole blocks
+             */
+            UpdateHASH(GetLSub(OCB_ntz(++hashBlockCount)));
+            hashBlockPos = 0;
+        }
+
+        protected virtual void ProcessMainBlock(byte[] output, int outOff)
+        {
+            /*
+             * OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks
+             */
+
+            if (forEncryption)
+            {
+                Xor(Checksum, mainBlock);
+                mainBlockPos = 0;
+            }
+
+            Xor(OffsetMAIN, GetLSub(OCB_ntz(++mainBlockCount)));
+
+            Xor(mainBlock, OffsetMAIN);
+            mainCipher.ProcessBlock(mainBlock, 0, mainBlock, 0);
+            Xor(mainBlock, OffsetMAIN);
+
+            Array.Copy(mainBlock, 0, output, outOff, 16);
+
+            if (!forEncryption)
+            {
+                Xor(Checksum, mainBlock);
+                Array.Copy(mainBlock, BLOCK_SIZE, mainBlock, 0, macSize);
+                mainBlockPos = macSize;
+            }
+        }
+
+        protected virtual void Reset(bool clearMac)
+        {
+            hashCipher.Reset();
+            mainCipher.Reset();
+
+            Clear(hashBlock);
+            Clear(mainBlock);
+
+            hashBlockPos = 0;
+            mainBlockPos = 0;
+
+            hashBlockCount = 0;
+            mainBlockCount = 0;
+
+            Clear(OffsetHASH);
+            Clear(Sum);
+            Array.Copy(OffsetMAIN_0, 0, OffsetMAIN, 0, 16);
+            Clear(Checksum);
+
+            if (clearMac)
+            {
+                macBlock = null;
+            }
+
+            if (initialAssociatedText != null)
+            {
+                ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
+            }
+        }
+
+        protected virtual void UpdateHASH(byte[] LSub)
+        {
+            Xor(OffsetHASH, LSub);
+            Xor(hashBlock, OffsetHASH);
+            hashCipher.ProcessBlock(hashBlock, 0, hashBlock, 0);
+            Xor(Sum, hashBlock);
+        }
+
+        protected static byte[] OCB_double(byte[] block)
+        {
+            byte[] result = new byte[16];
+            int carry = ShiftLeft(block, result);
+
+            /*
+             * NOTE: This construction is an attempt at a constant-time implementation.
+             */
+            result[15] ^= (byte)(0x87 >> ((1 - carry) << 3));
+
+            return result;
+        }
+
+        protected static void OCB_extend(byte[] block, int pos)
+        {
+            block[pos] = (byte) 0x80;
+            while (++pos < 16)
+            {
+                block[pos] = 0;
+            }
+        }
+
+        protected static int OCB_ntz(long x)
+        {
+            if (x == 0)
+            {
+                return 64;
+            }
+
+            int n = 0;
+            ulong ux = (ulong)x;
+            while ((ux & 1UL) == 0UL)
+            {
+                ++n;
+                ux >>= 1;
+            }
+            return n;
+        }
+
+        protected static int ShiftLeft(byte[] block, byte[] output)
+        {
+            int i = 16;
+            uint bit = 0;
+            while (--i >= 0)
+            {
+                uint b = block[i];
+                output[i] = (byte) ((b << 1) | bit);
+                bit = (b >> 7) & 1;
+            }
+            return (int)bit;
+        }
+
+        protected static void Xor(byte[] block, byte[] val)
+        {
+            for (int i = 15; i >= 0; --i)
+            {
+                block[i] ^= val[i];
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/modes/OfbBlockCipher.cs b/crypto/src/crypto/modes/OfbBlockCipher.cs
index 9408a74d4..a99f8c5d7 100644
--- a/crypto/src/crypto/modes/OfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/OfbBlockCipher.cs
@@ -85,10 +85,14 @@ namespace Org.BouncyCastle.Crypto.Modes
 
 			Reset();
 
-			cipher.Init(true, parameters);
+            // if it's null, key is to be reused.
+            if (parameters != null)
+            {
+                cipher.Init(true, parameters);
+            }
         }
 
-		/**
+        /**
         * return the algorithm name and mode.
         *
         * @return the name of the underlying algorithm followed by "/OFB"
diff --git a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
new file mode 100644
index 000000000..038ca783d
--- /dev/null
+++ b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
@@ -0,0 +1,337 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+    * Implements OpenPGP's rather strange version of Cipher-FeedBack (CFB) mode
+    * on top of a simple cipher. This class assumes the IV has been prepended
+    * to the data stream already, and just accomodates the reset after
+    * (blockSize + 2) bytes have been read.
+    * <p>
+    * For further info see <a href="http://www.ietf.org/rfc/rfc2440.html">RFC 2440</a>.
+	* </p>
+    */
+    public class OpenPgpCfbBlockCipher
+        : IBlockCipher
+    {
+        private byte[] IV;
+        private byte[] FR;
+        private byte[] FRE;
+
+		private readonly IBlockCipher cipher;
+		private readonly int blockSize;
+
+		private int count;
+        private bool forEncryption;
+
+		/**
+        * Basic constructor.
+        *
+        * @param cipher the block cipher to be used as the basis of the
+        * feedback mode.
+        */
+        public OpenPgpCfbBlockCipher(
+            IBlockCipher cipher)
+        {
+            this.cipher = cipher;
+
+            this.blockSize = cipher.GetBlockSize();
+            this.IV = new byte[blockSize];
+            this.FR = new byte[blockSize];
+            this.FRE = new byte[blockSize];
+        }
+
+		/**
+        * return the underlying block cipher that we are wrapping.
+        *
+        * @return the underlying block cipher that we are wrapping.
+        */
+        public IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
+
+		/**
+        * return the algorithm name and mode.
+        *
+        * @return the name of the underlying algorithm followed by "/PGPCFB"
+        * and the block size in bits.
+        */
+        public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName + "/OpenPGPCFB"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return true; }
+		}
+
+		/**
+        * return the block size we are operating at.
+        *
+        * @return the block size we are operating at (in bytes).
+        */
+        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 InvalidOperationException if the cipher isn't initialised.
+        * @return the number of bytes processed and produced.
+        */
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            return (forEncryption) ? EncryptBlock(input, inOff, output, outOff) : DecryptBlock(input, inOff, output, outOff);
+        }
+
+		/**
+        * reset the chaining vector back to the IV and reset the underlying
+        * cipher.
+        */
+        public void Reset()
+        {
+            count = 0;
+
+			Array.Copy(IV, 0, FR, 0, FR.Length);
+
+			cipher.Reset();
+        }
+
+        /**
+        * 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 forEncryption if true the cipher is initialised for
+        *  encryption, if false for decryption.
+        * @param parameters the key and other data required by the cipher.
+        * @exception ArgumentException if the parameters argument is
+        * inappropriate.
+        */
+        public void Init(
+            bool forEncryption,
+            ICipherParameters parameters)
+        {
+            this.forEncryption = forEncryption;
+
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParam = (ParametersWithIV)parameters;
+                byte[] iv = ivParam.GetIV();
+
+                if (iv.Length < IV.Length)
+                {
+                    // prepend the supplied IV with zeros (per FIPS PUB 81)
+                    Array.Copy(iv, 0, IV, IV.Length - iv.Length, iv.Length);
+                    for (int i = 0; i < IV.Length - iv.Length; i++)
+                    {
+                        IV[i] = 0;
+                    }
+                }
+                else
+                {
+                    Array.Copy(iv, 0, IV, 0, IV.Length);
+                }
+
+                parameters = ivParam.Parameters;
+            }
+
+            Reset();
+
+            cipher.Init(true, parameters);
+        }
+
+		/**
+        * Encrypt one byte of data according to CFB mode.
+        * @param data the byte to encrypt
+        * @param blockOff offset in the current block
+        * @returns the encrypted byte
+        */
+        private byte EncryptByte(byte data, int blockOff)
+        {
+            return (byte)(FRE[blockOff] ^ data);
+        }
+
+		/**
+        * Do the appropriate processing for CFB IV 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 InvalidOperationException if the cipher isn't initialised.
+        * @return the number of bytes processed and produced.
+        */
+        private int EncryptBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	outBytes,
+            int		outOff)
+        {
+            if ((inOff + blockSize) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + blockSize) > outBytes.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            if (count > blockSize)
+            {
+                FR[blockSize - 2] = outBytes[outOff] = EncryptByte(input[inOff], blockSize - 2);
+                FR[blockSize - 1] = outBytes[outOff + 1] = EncryptByte(input[inOff + 1], blockSize - 1);
+
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+                for (int n = 2; n < blockSize; n++)
+                {
+					FR[n - 2] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
+                }
+            }
+            else if (count == 0)
+            {
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+				for (int n = 0; n < blockSize; n++)
+                {
+					FR[n] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n);
+                }
+
+				count += blockSize;
+            }
+            else if (count == blockSize)
+            {
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+                outBytes[outOff] = EncryptByte(input[inOff], 0);
+                outBytes[outOff + 1] = EncryptByte(input[inOff + 1], 1);
+
+                //
+                // do reset
+                //
+                Array.Copy(FR, 2, FR, 0, blockSize - 2);
+                Array.Copy(outBytes, outOff, FR, blockSize - 2, 2);
+
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+                for (int n = 2; n < blockSize; n++)
+                {
+					FR[n - 2] = outBytes[outOff + n] = EncryptByte(input[inOff + n], n - 2);
+                }
+
+				count += blockSize;
+            }
+
+            return blockSize;
+        }
+
+        /**
+        * Do the appropriate processing for CFB IV 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 InvalidOperationException if the cipher isn't initialised.
+        * @return the number of bytes processed and produced.
+        */
+        private int DecryptBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	outBytes,
+            int		outOff)
+        {
+            if ((inOff + blockSize) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + blockSize) > outBytes.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            if (count > blockSize)
+            {
+				byte inVal = input[inOff];
+				FR[blockSize - 2] = inVal;
+				outBytes[outOff] = EncryptByte(inVal, blockSize - 2);
+
+				inVal = input[inOff + 1];
+				FR[blockSize - 1] = inVal;
+				outBytes[outOff + 1] = EncryptByte(inVal, blockSize - 1);
+
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+                for (int n = 2; n < blockSize; n++)
+                {
+					inVal = input[inOff + n];
+					FR[n - 2] = inVal;
+					outBytes[outOff + n] = EncryptByte(inVal, n - 2);
+				}
+            }
+            else if (count == 0)
+            {
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+                for (int n = 0; n < blockSize; n++)
+                {
+                    FR[n] = input[inOff + n];
+                    outBytes[n] = EncryptByte(input[inOff + n], n);
+                }
+
+                count += blockSize;
+            }
+            else if (count == blockSize)
+            {
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+				byte inVal1 = input[inOff];
+				byte inVal2 = input[inOff + 1];
+				outBytes[outOff    ] = EncryptByte(inVal1, 0);
+				outBytes[outOff + 1] = EncryptByte(inVal2, 1);
+
+                Array.Copy(FR, 2, FR, 0, blockSize - 2);
+
+				FR[blockSize - 2] = inVal1;
+				FR[blockSize - 1] = inVal2;
+
+                cipher.ProcessBlock(FR, 0, FRE, 0);
+
+                for (int n = 2; n < blockSize; n++)
+                {
+					byte inVal = input[inOff + n];
+					FR[n - 2] = inVal;
+					outBytes[outOff + n] = EncryptByte(inVal, n - 2);
+                }
+
+                count += blockSize;
+            }
+
+            return blockSize;
+        }
+    }
+}
diff --git a/crypto/src/crypto/modes/SicBlockCipher.cs b/crypto/src/crypto/modes/SicBlockCipher.cs
index c45026e82..da7ed7859 100644
--- a/crypto/src/crypto/modes/SicBlockCipher.cs
+++ b/crypto/src/crypto/modes/SicBlockCipher.cs
@@ -5,106 +5,111 @@ using Org.BouncyCastle.Math;
 
 namespace Org.BouncyCastle.Crypto.Modes
 {
-	/**
-	* Implements the Segmented Integer Counter (SIC) mode on top of a simple
-	* block cipher.
-	*/
-	public class SicBlockCipher
-		: IBlockCipher
-	{
-		private readonly IBlockCipher cipher;
-		private readonly int blockSize;
-		private readonly byte[] IV;
-		private readonly byte[] counter;
-		private readonly byte[] counterOut;
+    /**
+    * Implements the Segmented Integer Counter (SIC) mode on top of a simple
+    * block cipher.
+    */
+    public class SicBlockCipher
+        : IBlockCipher
+    {
+        private readonly IBlockCipher cipher;
+        private readonly int blockSize;
+        private readonly byte[] IV;
+        private readonly byte[] counter;
+        private readonly byte[] counterOut;
 
-		/**
-		* Basic constructor.
-		*
-		* @param c the block cipher to be used.
-		*/
-		public SicBlockCipher(IBlockCipher cipher)
-		{
-			this.cipher = cipher;
-			this.blockSize = cipher.GetBlockSize();
-			this.IV = new byte[blockSize];
-			this.counter = new byte[blockSize];
-			this.counterOut = new byte[blockSize];
-		}
+        /**
+        * Basic constructor.
+        *
+        * @param c the block cipher to be used.
+        */
+        public SicBlockCipher(IBlockCipher cipher)
+        {
+            this.cipher = cipher;
+            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 IBlockCipher GetUnderlyingCipher()
-		{
-			return cipher;
-		}
+        /**
+        * return the underlying block cipher that we are wrapping.
+        *
+        * @return the underlying block cipher that we are wrapping.
+        */
+        public IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
 
-		public void Init(
-			bool				forEncryption, //ignored by this CTR mode
-			ICipherParameters	parameters)
-		{
-			if (parameters is ParametersWithIV)
-			{
-				ParametersWithIV ivParam = (ParametersWithIV) parameters;
-				byte[] iv = ivParam.GetIV();
-				Array.Copy(iv, 0, IV, 0, IV.Length);
+        public void Init(
+            bool				forEncryption, //ignored by this CTR mode
+            ICipherParameters	parameters)
+        {
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParam = (ParametersWithIV) parameters;
+                byte[] iv = ivParam.GetIV();
+                Array.Copy(iv, 0, IV, 0, IV.Length);
 
-				Reset();
-				cipher.Init(true, ivParam.Parameters);
-			}
-	        else
-	        {
-	            throw new ArgumentException("SIC mode requires ParametersWithIV", "parameters");
-	        }
-		}
+                Reset();
 
-		public string AlgorithmName
-		{
-			get { return cipher.AlgorithmName + "/SIC"; }
-		}
+                // if null it's an IV changed only.
+                if (ivParam.Parameters != null)
+                {
+                    cipher.Init(true, ivParam.Parameters);
+                }
+            }
+            else
+            {
+                throw new ArgumentException("SIC mode requires ParametersWithIV", "parameters");
+            }
+        }
 
-		public bool IsPartialBlockOkay
-		{
-			get { return true; }
-		}
+        public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName + "/SIC"; }
+        }
 
-		public int GetBlockSize()
-		{
-			return cipher.GetBlockSize();
-		}
+        public bool IsPartialBlockOkay
+        {
+            get { return true; }
+        }
 
-		public int ProcessBlock(
-			byte[]	input,
-			int		inOff,
-			byte[]	output,
-			int		outOff)
-		{
-			cipher.ProcessBlock(counter, 0, counterOut, 0);
+        public int GetBlockSize()
+        {
+            return cipher.GetBlockSize();
+        }
 
-			//
-			// XOR the counterOut with the plaintext producing the cipher text
-			//
-			for (int i = 0; i < counterOut.Length; i++)
-			{
-				output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
-			}
+        public int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            cipher.ProcessBlock(counter, 0, counterOut, 0);
 
-			// Increment the counter
-			int j = counter.Length;
-			while (--j >= 0 && ++counter[j] == 0)
-			{
-			}
+            //
+            // XOR the counterOut with the plaintext producing the cipher text
+            //
+            for (int i = 0; i < counterOut.Length; i++)
+            {
+                output[outOff + i] = (byte)(counterOut[i] ^ input[inOff + i]);
+            }
 
-			return counter.Length;
-		}
+            // Increment the counter
+            int j = counter.Length;
+            while (--j >= 0 && ++counter[j] == 0)
+            {
+            }
 
-		public void Reset()
-		{
-			Array.Copy(IV, 0, counter, 0, counter.Length);
-			cipher.Reset();
-		}
-	}
+            return counter.Length;
+        }
+
+        public void Reset()
+        {
+            Array.Copy(IV, 0, counter, 0, counter.Length);
+            cipher.Reset();
+        }
+    }
 }
diff --git a/crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs b/crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
new file mode 100644
index 000000000..98049e1db
--- /dev/null
+++ b/crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+	public class BasicGcmExponentiator
+		: IGcmExponentiator
+	{
+		private byte[] x;
+
+		public void Init(byte[] x)
+		{
+			this.x = Arrays.Clone(x);
+		}
+
+		public void ExponentiateX(long pow, byte[] output)
+		{
+			// Initial value is little-endian 1
+			byte[] y = GcmUtilities.OneAsBytes();
+
+			if (pow > 0)
+			{
+				byte[] powX = Arrays.Clone(x);
+				do
+				{
+					if ((pow & 1L) != 0)
+					{
+						GcmUtilities.Multiply(y, powX);
+					}
+					GcmUtilities.Multiply(powX, powX);
+					pow >>= 1;
+				}
+				while (pow > 0);
+			}
+
+			Array.Copy(y, 0, output, 0, 16);
+		}
+	}
+}
diff --git a/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs b/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
index 4076de990..85e3ac9b1 100644
--- a/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
+++ b/crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
@@ -1,5 +1,7 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Modes.Gcm
 {
 	public class BasicGcmMultiplier
@@ -9,10 +11,10 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
 
 		public void Init(byte[] H)
 		{
-			this.H = (byte[])H.Clone();
+            this.H = Arrays.Clone(H);
 		}
 
-		public void MultiplyH(byte[] x)
+        public void MultiplyH(byte[] x)
 		{
 			GcmUtilities.Multiply(x, H);
 		}
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 8da125641..71e63c8fd 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -5,145 +5,233 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Modes.Gcm
 {
-	internal abstract class GcmUtilities
-	{
-		internal static byte[] OneAsBytes()
-		{
-			byte[] tmp = new byte[16];
-			tmp[0] = 0x80;
-			return tmp;
-		}
-
-		internal static uint[] OneAsUints()
-		{
-			uint[] tmp = new uint[4];
-			tmp[0] = 0x80000000;
-			return tmp;
-		}
-
-		internal static uint[] AsUints(byte[] bs)
-		{
-			uint[] us = new uint[4];
-			us[0] = Pack.BE_To_UInt32(bs, 0);
-			us[1] = Pack.BE_To_UInt32(bs, 4);
-			us[2] = Pack.BE_To_UInt32(bs, 8);
-			us[3] = Pack.BE_To_UInt32(bs, 12);
-			return us;
-		}
-
-		internal 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);
-					}
-
-					bool lsb = (tmp[15] & 1) != 0;
-					ShiftRight(tmp);
-					if (lsb)
-					{
-						// R = new byte[]{ 0xe1, ... };
-						//GCMUtilities.Xor(tmp, R);
-						tmp[0] ^= (byte)0xe1;
-					}
-				}
-			}
-
-			Array.Copy(c, 0, block, 0, 16);
-		}
-
-		// P is the value with only bit i=1 set
-		internal static void MultiplyP(uint[] x)
-		{
-			bool lsb = (x[3] & 1) != 0;
-			ShiftRight(x);
-			if (lsb)
-			{
-				// R = new uint[]{ 0xe1000000, 0, 0, 0 };
-				//Xor(v, R);
-				x[0] ^= 0xe1000000;
-			}
-		}
-
-		internal static void MultiplyP8(uint[] x)
-		{
+    internal abstract class GcmUtilities
+    {
+        internal static byte[] OneAsBytes()
+        {
+            byte[] tmp = new byte[16];
+            tmp[0] = 0x80;
+            return tmp;
+        }
+
+        internal static uint[] OneAsUints()
+        {
+            uint[] tmp = new uint[4];
+            tmp[0] = 0x80000000;
+            return tmp;
+        }
+
+        internal static uint[] AsUints(byte[] bs)
+        {
+            uint[] output = new uint[4];
+            Pack.BE_To_UInt32(bs, 0, output);
+            return output;
+        }
+
+        internal static void AsUints(byte[] bs, uint[] output)
+        {
+            Pack.BE_To_UInt32(bs, 0, output);
+        }
+
+        internal 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);
+                    }
+
+                    bool lsb = (tmp[15] & 1) != 0;
+                    ShiftRight(tmp);
+                    if (lsb)
+                    {
+                        // R = new byte[]{ 0xe1, ... };
+                        //GCMUtilities.Xor(tmp, R);
+                        tmp[0] ^= (byte)0xe1;
+                    }
+                }
+            }
+
+            Array.Copy(c, 0, block, 0, 16);
+        }
+
+        // P is the value with only bit i=1 set
+        internal static void MultiplyP(uint[] x)
+        {
+            bool lsb = (x[3] & 1) != 0;
+            ShiftRight(x);
+            if (lsb)
+            {
+                // R = new uint[]{ 0xe1000000, 0, 0, 0 };
+                //Xor(v, R);
+                x[0] ^= 0xe1000000;
+            }
+        }
+
+        internal static void MultiplyP(uint[] x, uint[] output)
+        {
+            bool lsb = (x[3] & 1) != 0;
+            ShiftRight(x, output);
+            if (lsb)
+            {
+                output[0] ^= 0xe1000000;
+            }
+        }
+
+        internal static void MultiplyP8(uint[] x)
+        {
 //			for (int i = 8; i != 0; --i)
 //			{
 //				MultiplyP(x);
 //			}
 
-			uint lsw = x[3];
-			ShiftRightN(x, 8);
-			for (int i = 7; i >= 0; --i)
-			{
-				if ((lsw & (1 << i)) != 0)
-				{
-					x[0] ^= (0xe1000000 >> (7 - i));
-				}
-			}
-		}
-
-		internal static void ShiftRight(byte[] block)
-		{
-			int i = 0;
-			byte bit = 0;
-			for (;;)
-			{
-				byte b = block[i];
-				block[i] = (byte)((b >> 1) | bit);
-				if (++i == 16) break;
-				bit = (byte)(b << 7);
-			}
-		}
-
-		internal static void ShiftRight(uint[] block)
-		{
-			int i = 0;
-			uint bit = 0;
-			for (;;)
-			{
-				uint b = block[i];
-				block[i] = (b >> 1) | bit;
-				if (++i == 4) break;
-				bit = b << 31;
-			}
-		}
-
-		internal static void ShiftRightN(uint[] block, int n)
-		{
-			int i = 0;
-			uint bit = 0;
-			for (;;)
-			{
-				uint b = block[i];
-				block[i] = (b >> n) | bit;
-				if (++i == 4) break;
-				bit = b << (32 - n);
-			}
-		}
-
-		internal static void Xor(byte[] block, byte[] val)
-		{
-			for (int i = 15; i >= 0; --i)
-			{
-				block[i] ^= val[i];
-			}
-		}
-
-		internal static void Xor(uint[] block, uint[] val)
-		{
-			for (int i = 3; i >= 0; --i)
-			{
-				block[i] ^= val[i];
-			}
-		}
-	}
+            uint lsw = x[3];
+            ShiftRightN(x, 8);
+            for (int i = 7; i >= 0; --i)
+            {
+                if ((lsw & (1 << i)) != 0)
+                {
+                    x[0] ^= (0xe1000000 >> (7 - i));
+                }
+            }
+        }
+
+        internal static void MultiplyP8(uint[] x, uint[] output)
+        {
+            uint lsw = x[3];
+            ShiftRightN(x, 8, output);
+            for (int i = 7; i >= 0; --i)
+            {
+                if ((lsw & (1 << i)) != 0)
+                {
+                    output[0] ^= (0xe1000000 >> (7 - i));
+                }
+            }
+        }
+
+        internal static void ShiftRight(byte[] block)
+        {
+            int i = 0;
+            byte bit = 0;
+            for (; ; )
+            {
+                byte b = block[i];
+                block[i] = (byte)((b >> 1) | bit);
+                if (++i == 16) break;
+                bit = (byte)(b << 7);
+            }
+        }
+
+        static void ShiftRight(byte[] block, byte[] output)
+        {
+            int i = 0;
+            byte bit = 0;
+            for (;;)
+            {
+                byte b = block[i];
+                output[i] = (byte)((b >> 1) | bit);
+                if (++i == 16) break;
+                bit = (byte)(b << 7);
+            }
+        }
+
+        internal static void ShiftRight(uint[] block)
+        {
+            int i = 0;
+            uint bit = 0;
+            for (; ; )
+            {
+                uint b = block[i];
+                block[i] = (b >> 1) | bit;
+                if (++i == 4) break;
+                bit = b << 31;
+            }
+        }
+
+        internal static void ShiftRight(uint[] block, uint[] output)
+        {
+            int i = 0;
+            uint bit = 0;
+            for (; ; )
+            {
+                uint b = block[i];
+                output[i] = (b >> 1) | bit;
+                if (++i == 4) break;
+                bit = b << 31;
+            }
+        }
+
+        internal static void ShiftRightN(uint[] block, int n)
+        {
+            int i = 0;
+            uint bit = 0;
+            for (; ; )
+            {
+                uint b = block[i];
+                block[i] = (b >> n) | bit;
+                if (++i == 4) break;
+                bit = b << (32 - n);
+            }
+        }
+
+        internal static void ShiftRightN(uint[] block, int n, uint[] output)
+        {
+            int i = 0;
+            uint bit = 0;
+            for (; ; )
+            {
+                uint b = block[i];
+                output[i] = (b >> n) | bit;
+                if (++i == 4) break;
+                bit = b << (32 - n);
+            }
+        }
+
+        internal static void Xor(byte[] block, byte[] val)
+        {
+            for (int i = 15; i >= 0; --i)
+            {
+                block[i] ^= val[i];
+            }
+        }
+
+        internal static void Xor(byte[] block, byte[] val, int off, int len)
+        {
+            while (--len >= 0)
+            {
+                block[len] ^= val[off + len];
+            }
+        }
+
+        internal static void Xor(byte[] block, byte[] val, byte[] output)
+        {
+            for (int i = 15; i >= 0; --i)
+            {
+                output[i] = (byte)(block[i] ^ val[i]);
+            }
+        }
+
+        internal static void Xor(uint[] block, uint[] val)
+        {
+            for (int i = 3; i >= 0; --i)
+            {
+                block[i] ^= val[i];
+            }
+        }
+
+        internal static void Xor(uint[] block, uint[] val, uint[] output)
+        {
+            for (int i = 3; i >= 0; --i)
+            {
+                output[i] = block[i] ^ val[i];
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/modes/gcm/IGcmExponentiator.cs b/crypto/src/crypto/modes/gcm/IGcmExponentiator.cs
new file mode 100644
index 000000000..5b4ce9d7a
--- /dev/null
+++ b/crypto/src/crypto/modes/gcm/IGcmExponentiator.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+	public interface IGcmExponentiator
+	{
+		void Init(byte[] x);
+		void ExponentiateX(long pow, byte[] output);
+	}
+}
diff --git a/crypto/src/crypto/modes/gcm/IGcmMultiplier.cs b/crypto/src/crypto/modes/gcm/IGcmMultiplier.cs
new file mode 100644
index 000000000..ec7b906ee
--- /dev/null
+++ b/crypto/src/crypto/modes/gcm/IGcmMultiplier.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+	public interface IGcmMultiplier
+	{
+		void Init(byte[] H);
+		void MultiplyH(byte[] x);
+	}
+}
diff --git a/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs b/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
index 9425a3d9d..44933bba7 100644
--- a/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
+++ b/crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 
 using Org.BouncyCastle.Utilities;
 
@@ -7,38 +8,53 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
 	public class Tables1kGcmExponentiator
 		: IGcmExponentiator
 	{
-	    // A lookup table of the power-of-two powers of 'x'
-	    private byte[][] lookupPowX2 = new byte[64][];
+        // A lookup table of the power-of-two powers of 'x'
+        // - lookupPowX2[i] = x^(2^i)
+        private IList lookupPowX2;
 
-		public void Init(byte[] x)
+        public void Init(byte[] x)
 		{
-			lookupPowX2[0] = GcmUtilities.OneAsBytes();
-			lookupPowX2[1] = Arrays.Clone(x); 
+            if (lookupPowX2 != null && Arrays.AreEqual(x, (byte[])lookupPowX2[0]))
+            {
+                return;
+            }
 
-			for (int i = 2; i != 64; ++i)
-			{
-				byte[] tmp = Arrays.Clone(lookupPowX2[i - 1]);
-				GcmUtilities.Multiply(tmp, tmp);
-				lookupPowX2[i] = tmp;
-			}
+            lookupPowX2 = Platform.CreateArrayList(8);
+            lookupPowX2.Add(Arrays.Clone(x));
 		}
 
 		public void ExponentiateX(long pow, byte[] output)
 		{
 			byte[] y = GcmUtilities.OneAsBytes();
-			int powX2 = 1;
-
-			while (pow > 0)
-			{
-				if ((pow & 1L) != 0)
-				{
-					GcmUtilities.Multiply(y, lookupPowX2[powX2]);
-				}
-				++powX2;
-				pow >>= 1;
-			}
+            int bit = 0;
+            while (pow > 0)
+            {
+                if ((pow & 1L) != 0)
+                {
+                    EnsureAvailable(bit);
+                    GcmUtilities.Multiply(y, (byte[])lookupPowX2[bit]);
+                }
+                ++bit;
+                pow >>= 1;
+            }
 
 			Array.Copy(y, 0, output, 0, 16);
 		}
-	}
+
+        private void EnsureAvailable(int bit)
+        {
+            int count = lookupPowX2.Count;
+            if (count <= bit)
+            {
+                byte[] tmp = (byte[])lookupPowX2[count - 1];
+                do
+                {
+                    tmp = Arrays.Clone(tmp);
+                    GcmUtilities.Multiply(tmp, tmp);
+                    lookupPowX2.Add(tmp);
+                }
+                while (++count <= bit);
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs b/crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
index f089dfe8d..707b0be2e 100644
--- a/crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
+++ b/crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
@@ -1,64 +1,77 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Modes.Gcm
 {
-	public class Tables64kGcmMultiplier
-		: IGcmMultiplier
-	{
-		private readonly uint[][][] M = new uint[16][][];
+    public class Tables64kGcmMultiplier
+        : IGcmMultiplier
+    {
+        private byte[] H;
+        private uint[][][] M;
 
-		public void Init(byte[] H)
-		{
-			M[0] = new uint[256][];
-			M[0][0] = new uint[4];
-			M[0][128] = GcmUtilities.AsUints(H);
-			for (int j = 64; j >= 1; j >>= 1)
-			{
-				uint[] tmp = (uint[])M[0][j + j].Clone();
-				GcmUtilities.MultiplyP(tmp);
-				M[0][j] = tmp;
-			}
-			for (int i = 0;;)
-			{
-				for (int j = 2; j < 256; j += j)
-				{
-					for (int k = 1; k < j; ++k)
-					{
-						uint[] tmp = (uint[])M[i][j].Clone();
-						GcmUtilities.Xor(tmp, M[i][k]);
-						M[i][j + k] = tmp;
-					}
-				}
+        public void Init(byte[] H)
+        {
+            if (M == null)
+            {
+                M = new uint[16][][];
+            }
+            else if (Arrays.AreEqual(this.H, H))
+            {
+                return;
+            }
 
-				if (++i == 16) return;
+            this.H = Arrays.Clone(H);
 
-				M[i] = new uint[256][];
-				M[i][0] = new uint[4];
-				for (int j = 128; j > 0; j >>= 1)
-				{
-					uint[] tmp = (uint[])M[i - 1][j].Clone();
-					GcmUtilities.MultiplyP8(tmp);
-					M[i][j] = tmp;
-				}
-			}
-		}
+            M[0] = new uint[256][];
+            M[0][0] = new uint[4];
+            M[0][128] = GcmUtilities.AsUints(H);
+            for (int j = 64; j >= 1; j >>= 1)
+            {
+                uint[] tmp = (uint[])M[0][j + j].Clone();
+                GcmUtilities.MultiplyP(tmp);
+                M[0][j] = tmp;
+            }
+            for (int i = 0; ; )
+            {
+                for (int j = 2; j < 256; j += j)
+                {
+                    for (int k = 1; k < j; ++k)
+                    {
+                        uint[] tmp = (uint[])M[i][j].Clone();
+                        GcmUtilities.Xor(tmp, M[i][k]);
+                        M[i][j + k] = tmp;
+                    }
+                }
 
-		public void MultiplyH(byte[] x)
-		{
-			uint[] z = new uint[4];
-			for (int i = 0; i != 16; ++i)
-			{
-				//GcmUtilities.Xor(z, M[i][x[i]]);
-				uint[] m = M[i][x[i]];
-				z[0] ^= m[0];
-				z[1] ^= m[1];
-				z[2] ^= m[2];
-				z[3] ^= m[3];
-			}
+                if (++i == 16) return;
 
-			Pack.UInt32_To_BE(z, x, 0);
-		}
-	}
+                M[i] = new uint[256][];
+                M[i][0] = new uint[4];
+                for (int j = 128; j > 0; j >>= 1)
+                {
+                    uint[] tmp = (uint[])M[i - 1][j].Clone();
+                    GcmUtilities.MultiplyP8(tmp);
+                    M[i][j] = tmp;
+                }
+            }
+        }
+
+        public void MultiplyH(byte[] x)
+        {
+            uint[] z = new uint[4];
+            for (int i = 0; i != 16; ++i)
+            {
+                //GcmUtilities.Xor(z, M[i][x[i]]);
+                uint[] m = M[i][x[i]];
+                z[0] ^= m[0];
+                z[1] ^= m[1];
+                z[2] ^= m[2];
+                z[3] ^= m[3];
+            }
+
+            Pack.UInt32_To_BE(z, x, 0);
+        }
+    }
 }
diff --git a/crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs b/crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
index 91d58fab8..5f3d6c86c 100644
--- a/crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
+++ b/crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
@@ -1,90 +1,103 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Modes.Gcm
 {
-	public class Tables8kGcmMultiplier
-		: IGcmMultiplier
-	{
-		private readonly uint[][][] M = new uint[32][][];
-		
-		public void Init(byte[] H)
-		{
-			M[0] = new uint[16][];
-			M[1] = new uint[16][];
-			M[0][0] = new uint[4];
-			M[1][0] = new uint[4];
-			M[1][8] = GcmUtilities.AsUints(H);
+    public class Tables8kGcmMultiplier
+        : IGcmMultiplier
+    {
+        private byte[] H;
+        private uint[][][] M;
 
-			for (int j = 4; j >= 1; j >>= 1)
-			{
-				uint[] tmp = (uint[])M[1][j + j].Clone();
-				GcmUtilities.MultiplyP(tmp);
-				M[1][j] = tmp;
-			}
+        public void Init(byte[] H)
+        {
+            if (M == null)
+            {
+                M = new uint[32][][];
+            }
+            else if (Arrays.AreEqual(this.H, H))
+            {
+                return;
+            }
 
-			{
-				uint[] tmp = (uint[])M[1][1].Clone();
-				GcmUtilities.MultiplyP(tmp);
-				M[0][8] = tmp;
-			}
+            this.H = Arrays.Clone(H);
 
-			for (int j = 4; j >= 1; j >>= 1)
-			{
-				uint[] tmp = (uint[])M[0][j + j].Clone();
-				GcmUtilities.MultiplyP(tmp);
-				M[0][j] = tmp;
-			}
+            M[0] = new uint[16][];
+            M[1] = new uint[16][];
+            M[0][0] = new uint[4];
+            M[1][0] = new uint[4];
+            M[1][8] = GcmUtilities.AsUints(H);
 
-			for (int i = 0;;)
-			{
-				for (int j = 2; j < 16; j += j)
-				{
-					for (int k = 1; k < j; ++k)
-					{
-						uint[] tmp = (uint[])M[i][j].Clone();
-						GcmUtilities.Xor(tmp, M[i][k]);
-						M[i][j + k] = tmp;
-					}
-				}
+            for (int j = 4; j >= 1; j >>= 1)
+            {
+                uint[] tmp = (uint[])M[1][j + j].Clone();
+                GcmUtilities.MultiplyP(tmp);
+                M[1][j] = tmp;
+            }
 
-				if (++i == 32) return;
+            {
+                uint[] tmp = (uint[])M[1][1].Clone();
+                GcmUtilities.MultiplyP(tmp);
+                M[0][8] = tmp;
+            }
 
-				if (i > 1)
-				{
-					M[i] = new uint[16][];
-					M[i][0] = new uint[4];
-					for(int j = 8; j > 0; j >>= 1)
-					{
-						uint[] tmp = (uint[])M[i - 2][j].Clone();
-						GcmUtilities.MultiplyP8(tmp);
-						M[i][j] = tmp;
-					}
-				}
-			}
-		}
+            for (int j = 4; j >= 1; j >>= 1)
+            {
+                uint[] tmp = (uint[])M[0][j + j].Clone();
+                GcmUtilities.MultiplyP(tmp);
+                M[0][j] = tmp;
+            }
 
-		public void MultiplyH(byte[] x)
-		{
-			uint[] z = new uint[4];
-			for (int i = 15; i >= 0; --i)
-			{
-				//GcmUtilities.Xor(z, M[i + i][x[i] & 0x0f]);
-				uint[] m = M[i + i][x[i] & 0x0f];
-				z[0] ^= m[0];
-				z[1] ^= m[1];
-				z[2] ^= m[2];
-				z[3] ^= m[3];
-				//GcmUtilities.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];
-			}
+            for (int i = 0; ; )
+            {
+                for (int j = 2; j < 16; j += j)
+                {
+                    for (int k = 1; k < j; ++k)
+                    {
+                        uint[] tmp = (uint[])M[i][j].Clone();
+                        GcmUtilities.Xor(tmp, M[i][k]);
+                        M[i][j + k] = tmp;
+                    }
+                }
 
-			Pack.UInt32_To_BE(z, x, 0);
-		}
-	}
+                if (++i == 32) return;
+
+                if (i > 1)
+                {
+                    M[i] = new uint[16][];
+                    M[i][0] = new uint[4];
+                    for (int j = 8; j > 0; j >>= 1)
+                    {
+                        uint[] tmp = (uint[])M[i - 2][j].Clone();
+                        GcmUtilities.MultiplyP8(tmp);
+                        M[i][j] = tmp;
+                    }
+                }
+            }
+        }
+
+        public void MultiplyH(byte[] x)
+        {
+            uint[] z = new uint[4];
+            for (int i = 15; i >= 0; --i)
+            {
+                //GcmUtilities.Xor(z, M[i + i][x[i] & 0x0f]);
+                uint[] m = M[i + i][x[i] & 0x0f];
+                z[0] ^= m[0];
+                z[1] ^= m[1];
+                z[2] ^= m[2];
+                z[3] ^= m[3];
+                //GcmUtilities.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.UInt32_To_BE(z, x, 0);
+        }
+    }
 }
diff --git a/crypto/src/crypto/paddings/BlockCipherPadding.cs b/crypto/src/crypto/paddings/BlockCipherPadding.cs
new file mode 100644
index 000000000..33a5f9f0f
--- /dev/null
+++ b/crypto/src/crypto/paddings/BlockCipherPadding.cs
@@ -0,0 +1,43 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+    /**
+     * Block cipher padders are expected to conform to this interface
+     */
+    public interface IBlockCipherPadding
+    {
+        /**
+         * Initialise the padder.
+         *
+         * @param param parameters, if any required.
+         */
+        void Init(SecureRandom random);
+            //throws ArgumentException;
+
+        /**
+         * Return the name of the algorithm the cipher implements.
+         *
+         * @return the name of the algorithm the cipher implements.
+         */
+        string PaddingName { get; }
+
+		/**
+         * add the pad bytes to the passed in block, returning the
+         * number of bytes added.
+         */
+        int AddPadding(byte[] input, int inOff);
+
+        /**
+         * return the number of pad bytes present in the block.
+         * @exception InvalidCipherTextException if the padding is badly formed
+         * or invalid.
+         */
+        int PadCount(byte[] input);
+        //throws InvalidCipherTextException;
+    }
+
+}
diff --git a/crypto/src/crypto/paddings/ISO10126d2Padding.cs b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
new file mode 100644
index 000000000..e132a62dd
--- /dev/null
+++ b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
@@ -0,0 +1,76 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+    /**
+    * A padder that adds ISO10126-2 padding to a block.
+    */
+    public class ISO10126d2Padding: IBlockCipherPadding
+    {
+        private SecureRandom random;
+
+        /**
+        * Initialise the padder.
+        *
+        * @param random a SecureRandom if available.
+        */
+        public void Init(
+			SecureRandom random)
+            //throws ArgumentException
+        {
+			this.random = (random != null) ? random : new SecureRandom();
+        }
+
+		/**
+        * Return the name of the algorithm the cipher implements.
+        *
+        * @return the name of the algorithm the cipher implements.
+        */
+        public string PaddingName
+        {
+            get { return "ISO10126-2"; }
+        }
+
+		/**
+        * add the pad bytes to the passed in block, returning the
+        * number of bytes added.
+        */
+        public int AddPadding(
+            byte[]	input,
+            int		inOff)
+        {
+            byte code = (byte)(input.Length - inOff);
+
+            while (inOff < (input.Length - 1))
+            {
+                input[inOff] = (byte)random.NextInt();
+                inOff++;
+            }
+
+            input[inOff] = code;
+
+            return code;
+        }
+
+        /**
+        * return the number of pad bytes present in the block.
+        */
+        public int PadCount(byte[] input)
+            //throws InvalidCipherTextException
+        {
+            int count = input[input.Length - 1] & 0xff;
+
+            if (count > input.Length)
+            {
+                throw new InvalidCipherTextException("pad block corrupted");
+            }
+
+            return count;
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/paddings/ISO7816d4Padding.cs b/crypto/src/crypto/paddings/ISO7816d4Padding.cs
new file mode 100644
index 000000000..016b25a81
--- /dev/null
+++ b/crypto/src/crypto/paddings/ISO7816d4Padding.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+	/**
+	 * 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
+		: IBlockCipherPadding
+	{
+		/**
+		 * Initialise the padder.
+		 *
+		 * @param random - a SecureRandom if available.
+		 */
+		public void Init(
+			SecureRandom random)
+		{
+			// nothing to do.
+		}
+
+		/**
+		 * Return the name of the algorithm the padder implements.
+		 *
+		 * @return the name of the algorithm the padder implements.
+		 */
+		public string PaddingName
+		{
+			get { return "ISO7816-4"; }
+		}
+
+		/**
+		 * add the pad bytes to the passed in block, returning the
+		 * number of bytes added.
+		 */
+		public int AddPadding(
+			byte[]	input,
+			int		inOff)
+		{
+			int added = (input.Length - inOff);
+
+			input[inOff]= (byte) 0x80;
+			inOff ++;
+
+			while (inOff < input.Length)
+			{
+				input[inOff] = (byte) 0;
+				inOff++;
+			}
+
+			return added;
+		}
+
+		/**
+		 * return the number of pad bytes present in the block.
+		 */
+		public int PadCount(
+			byte[] input)
+		{
+			int count = input.Length - 1;
+
+			while (count > 0 && input[count] == 0)
+			{
+				count--;
+			}
+
+			if (input[count] != (byte)0x80)
+			{
+				throw new InvalidCipherTextException("pad block corrupted");
+			}
+
+			return input.Length - count;
+		}
+	}
+}
diff --git a/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
new file mode 100644
index 000000000..fb8a92ba3
--- /dev/null
+++ b/crypto/src/crypto/paddings/PaddedBufferedBlockCipher.cs
@@ -0,0 +1,288 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+	/**
+	* 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
+		: BufferedBlockCipher
+	{
+		private readonly IBlockCipherPadding 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(
+			IBlockCipher		cipher,
+			IBlockCipherPadding	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(
+			IBlockCipher cipher)
+			: this(cipher, new Pkcs7Padding())    { }
+
+		/**
+		* 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.
+		* @exception ArgumentException if the parameters argument is
+		* inappropriate.
+		*/
+		public override void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			this.forEncryption = forEncryption;
+
+			SecureRandom initRandom = null;
+			if (parameters is ParametersWithRandom)
+			{
+				ParametersWithRandom p = (ParametersWithRandom)parameters;
+				initRandom = p.Random;
+				parameters = p.Parameters;
+			}
+
+			Reset();
+			padding.Init(initRandom);
+			cipher.Init(forEncryption, parameters);
+		}
+
+		/**
+		* 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 override int GetOutputSize(
+			int length)
+		{
+			int total = length + 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 override int GetUpdateOutputSize(
+			int length)
+		{
+			int total       = length + 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 InvalidOperationException if the cipher isn't initialised.
+		*/
+		public override int ProcessByte(
+			byte	input,
+			byte[]	output,
+			int		outOff)
+		{
+			int resultLen = 0;
+
+			if (bufOff == buf.Length)
+			{
+				resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+				bufOff = 0;
+			}
+
+			buf[bufOff++] = input;
+
+			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 InvalidOperationException if the cipher isn't initialised.
+		*/
+		public override int ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length,
+			byte[]	output,
+			int		outOff)
+		{
+			if (length < 0)
+			{
+				throw new ArgumentException("Can't have a negative input length!");
+			}
+
+			int blockSize = GetBlockSize();
+			int outLength = GetUpdateOutputSize(length);
+
+			if (outLength > 0)
+			{
+				if ((outOff + outLength) > output.Length)
+				{
+					throw new DataLengthException("output buffer too short");
+				}
+			}
+
+			int resultLen = 0;
+			int gapLen = buf.Length - bufOff;
+
+			if (length > gapLen)
+			{
+				Array.Copy(input, inOff, buf, bufOff, gapLen);
+
+				resultLen += cipher.ProcessBlock(buf, 0, output, outOff);
+
+				bufOff = 0;
+				length -= gapLen;
+				inOff += gapLen;
+
+				while (length > buf.Length)
+				{
+					resultLen += cipher.ProcessBlock(input, inOff, output, outOff + resultLen);
+
+					length -= blockSize;
+					inOff += blockSize;
+				}
+			}
+
+			Array.Copy(input, inOff, buf, bufOff, length);
+
+			bufOff += length;
+
+			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 InvalidOperationException if the underlying cipher is not
+		* initialised.
+		* @exception InvalidCipherTextException if padding is expected and not found.
+		*/
+		public override int DoFinal(
+			byte[]  output,
+			int     outOff)
+		{
+			int blockSize = cipher.GetBlockSize();
+			int resultLen = 0;
+
+			if (forEncryption)
+			{
+				if (bufOff == blockSize)
+				{
+					if ((outOff + 2 * blockSize) > output.Length)
+					{
+						Reset();
+
+						throw new DataLengthException("output buffer too short");
+					}
+
+					resultLen = cipher.ProcessBlock(buf, 0, output, outOff);
+					bufOff = 0;
+				}
+
+				padding.AddPadding(buf, bufOff);
+
+				resultLen += cipher.ProcessBlock(buf, 0, output, 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);
+
+					Array.Copy(buf, 0, output, outOff, resultLen);
+				}
+				finally
+				{
+					Reset();
+				}
+			}
+
+			return resultLen;
+		}
+	}
+
+}
diff --git a/crypto/src/crypto/paddings/Pkcs7Padding.cs b/crypto/src/crypto/paddings/Pkcs7Padding.cs
new file mode 100644
index 000000000..f3166fd96
--- /dev/null
+++ b/crypto/src/crypto/paddings/Pkcs7Padding.cs
@@ -0,0 +1,79 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+    /**
+    * A padder that adds Pkcs7/Pkcs5 padding to a block.
+    */
+    public class Pkcs7Padding
+		: IBlockCipherPadding
+    {
+        /**
+        * Initialise the padder.
+        *
+        * @param random - a SecureRandom if available.
+        */
+        public void Init(
+			SecureRandom random)
+        {
+            // nothing to do.
+        }
+
+        /**
+        * Return the name of the algorithm the cipher implements.
+        *
+        * @return the name of the algorithm the cipher implements.
+        */
+        public string PaddingName
+        {
+            get { return "PKCS7"; }
+        }
+
+		/**
+        * add the pad bytes to the passed in block, returning the
+        * number of bytes added.
+        */
+        public int AddPadding(
+            byte[]  input,
+            int     inOff)
+        {
+            byte code = (byte)(input.Length - inOff);
+
+            while (inOff < input.Length)
+            {
+                input[inOff] = code;
+                inOff++;
+            }
+
+            return code;
+        }
+
+        /**
+        * return the number of pad bytes present in the block.
+        */
+        public int PadCount(
+			byte[] input)
+        {
+            int count = (int) input[input.Length - 1];
+
+			if (count < 1 || count > input.Length)
+            {
+                throw new InvalidCipherTextException("pad block corrupted");
+            }
+
+			for (int i = 1; i <= count; i++)
+            {
+                if (input[input.Length - i] != count)
+                {
+                    throw new InvalidCipherTextException("pad block corrupted");
+                }
+            }
+
+            return count;
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/paddings/TbcPadding.cs b/crypto/src/crypto/paddings/TbcPadding.cs
new file mode 100644
index 000000000..74b64e8e1
--- /dev/null
+++ b/crypto/src/crypto/paddings/TbcPadding.cs
@@ -0,0 +1,79 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+    /// <summary> A padder that adds Trailing-Bit-Compliment padding to a block.
+    /// <p>
+    /// This padding pads the block out compliment of the last bit
+    /// of the plain text.
+    /// </p>
+    /// </summary>
+    public class TbcPadding
+		: IBlockCipherPadding
+    {
+        /// <summary> Return the name of the algorithm the cipher implements.</summary>
+        /// <returns> the name of the algorithm the cipher implements.
+        /// </returns>
+        public string PaddingName
+        {
+            get { return "TBC"; }
+        }
+
+		/// <summary> Initialise the padder.</summary>
+        /// <param name="random">- a SecureRandom if available.
+        /// </param>
+        public virtual void Init(SecureRandom random)
+        {
+            // nothing to do.
+        }
+
+        /// <summary> 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>
+        /// </summary>
+        public virtual int AddPadding(byte[] input, int inOff)
+        {
+            int count = input.Length - inOff;
+            byte code;
+
+            if (inOff > 0)
+            {
+                code = (byte)((input[inOff - 1] & 0x01) == 0?0xff:0x00);
+            }
+            else
+            {
+                code = (byte)((input[input.Length - 1] & 0x01) == 0?0xff:0x00);
+            }
+
+            while (inOff < input.Length)
+            {
+                input[inOff] = code;
+                inOff++;
+            }
+
+            return count;
+        }
+
+        /// <summary> return the number of pad bytes present in the block.</summary>
+        public virtual int PadCount(byte[] input)
+        {
+            byte code = input[input.Length - 1];
+
+            int index = input.Length - 1;
+            while (index > 0 && input[index - 1] == code)
+            {
+                index--;
+            }
+
+            return input.Length - index;
+        }
+    }
+}
diff --git a/crypto/src/crypto/paddings/X923Padding.cs b/crypto/src/crypto/paddings/X923Padding.cs
new file mode 100644
index 000000000..cc1b52b3e
--- /dev/null
+++ b/crypto/src/crypto/paddings/X923Padding.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+    /**
+    * 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
+		: IBlockCipherPadding
+    {
+        private SecureRandom random;
+
+		/**
+        * Initialise the padder.
+        *
+        * @param random a SecureRandom if one is available.
+        */
+        public void Init(
+			SecureRandom random)
+        {
+            this.random = random;
+        }
+
+		/**
+        * Return the name of the algorithm the cipher implements.
+        *
+        * @return the name of the algorithm the cipher implements.
+        */
+        public string PaddingName
+        {
+            get { return "X9.23"; }
+        }
+
+		/**
+        * add the pad bytes to the passed in block, returning the
+        * number of bytes added.
+        */
+        public int AddPadding(
+            byte[]  input,
+            int     inOff)
+        {
+            byte code = (byte)(input.Length - inOff);
+
+            while (inOff < input.Length - 1)
+            {
+                if (random == null)
+                {
+                    input[inOff] = 0;
+                }
+                else
+                {
+                    input[inOff] = (byte)random.NextInt();
+                }
+                inOff++;
+            }
+
+            input[inOff] = code;
+
+            return code;
+        }
+
+        /**
+        * return the number of pad bytes present in the block.
+        */
+        public int PadCount(
+			byte[] input)
+        {
+            int count = input[input.Length - 1] & 0xff;
+
+            if (count > input.Length)
+            {
+                throw new InvalidCipherTextException("pad block corrupted");
+            }
+
+            return count;
+        }
+    }
+}
diff --git a/crypto/src/crypto/paddings/ZeroBytePadding.cs b/crypto/src/crypto/paddings/ZeroBytePadding.cs
new file mode 100644
index 000000000..0d55ca4c2
--- /dev/null
+++ b/crypto/src/crypto/paddings/ZeroBytePadding.cs
@@ -0,0 +1,68 @@
+using System;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Paddings
+{
+
+    /// <summary> A padder that adds Null byte padding to a block.</summary>
+    public class ZeroBytePadding : IBlockCipherPadding
+    {
+        /// <summary> Return the name of the algorithm the cipher implements.
+        ///
+        /// </summary>
+        /// <returns> the name of the algorithm the cipher implements.
+        /// </returns>
+        public string PaddingName
+        {
+            get { return "ZeroBytePadding"; }
+        }
+
+		/// <summary> Initialise the padder.
+        ///
+        /// </summary>
+        /// <param name="random">- a SecureRandom if available.
+        /// </param>
+        public void Init(SecureRandom random)
+        {
+            // nothing to do.
+        }
+
+        /// <summary> add the pad bytes to the passed in block, returning the
+        /// number of bytes added.
+        /// </summary>
+        public int AddPadding(
+			byte[]	input,
+			int		inOff)
+        {
+            int added = (input.Length - inOff);
+
+            while (inOff < input.Length)
+            {
+                input[inOff] = (byte) 0;
+                inOff++;
+            }
+
+            return added;
+        }
+
+		/// <summary> return the number of pad bytes present in the block.</summary>
+        public int PadCount(
+			byte[] input)
+        {
+            int count = input.Length;
+
+            while (count > 0)
+            {
+                if (input[count - 1] != 0)
+                {
+                    break;
+                }
+
+                count--;
+            }
+
+            return input.Length - count;
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/AEADParameters.cs b/crypto/src/crypto/parameters/AEADParameters.cs
index 06b2f5c38..825d6b7f2 100644
--- a/crypto/src/crypto/parameters/AEADParameters.cs
+++ b/crypto/src/crypto/parameters/AEADParameters.cs
@@ -10,7 +10,19 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		private readonly KeyParameter key;
 		private readonly int macSize;
 
-		/**
+        /**
+         * Base constructor.
+         *
+         * @param key key to be used by underlying cipher
+         * @param macSize macSize in bits
+         * @param nonce nonce to be used
+         */
+        public AeadParameters(KeyParameter key, int macSize, byte[] nonce)
+           : this(key, macSize, nonce, null)
+        {
+        }
+
+        /**
 		 * Base constructor.
 		 *
 		 * @param key key to be used by underlying cipher
diff --git a/crypto/src/crypto/parameters/CcmParameters.cs b/crypto/src/crypto/parameters/CcmParameters.cs
index 8dc981e1f..d4459081c 100644
--- a/crypto/src/crypto/parameters/CcmParameters.cs
+++ b/crypto/src/crypto/parameters/CcmParameters.cs
@@ -2,6 +2,7 @@ using System;
 
 namespace Org.BouncyCastle.Crypto.Parameters
 {
+    [Obsolete("Use AeadParameters")]
     public class CcmParameters
         : AeadParameters 
     {
diff --git a/crypto/src/crypto/parameters/DHKeyGenerationParameters.cs b/crypto/src/crypto/parameters/DHKeyGenerationParameters.cs
new file mode 100644
index 000000000..ab3e18f09
--- /dev/null
+++ b/crypto/src/crypto/parameters/DHKeyGenerationParameters.cs
@@ -0,0 +1,31 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DHKeyGenerationParameters
+		: KeyGenerationParameters
+    {
+        private readonly DHParameters parameters;
+
+		public DHKeyGenerationParameters(
+            SecureRandom	random,
+            DHParameters	parameters)
+			: base(random, GetStrength(parameters))
+        {
+            this.parameters = parameters;
+        }
+
+		public DHParameters Parameters
+        {
+            get { return parameters; }
+        }
+
+		internal static int GetStrength(
+			DHParameters parameters)
+		{
+			return parameters.L != 0 ? parameters.L : parameters.P.BitLength;
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/DHKeyParameters.cs b/crypto/src/crypto/parameters/DHKeyParameters.cs
new file mode 100644
index 000000000..1a5c1386f
--- /dev/null
+++ b/crypto/src/crypto/parameters/DHKeyParameters.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DHKeyParameters
+		: AsymmetricKeyParameter
+    {
+        private readonly DHParameters parameters;
+		private readonly DerObjectIdentifier algorithmOid;
+
+		protected DHKeyParameters(
+            bool			isPrivate,
+            DHParameters	parameters)
+			: this(isPrivate, parameters, PkcsObjectIdentifiers.DhKeyAgreement)
+        {
+        }
+
+		protected DHKeyParameters(
+            bool				isPrivate,
+            DHParameters		parameters,
+			DerObjectIdentifier	algorithmOid)
+			: base(isPrivate)
+        {
+			// TODO Should we allow parameters to be null?
+            this.parameters = parameters;
+			this.algorithmOid = algorithmOid;
+        }
+
+		public DHParameters Parameters
+        {
+            get { return parameters; }
+        }
+
+		public DerObjectIdentifier AlgorithmOid
+		{
+			get { return algorithmOid; }
+		}
+
+		public override bool Equals(
+			object obj)
+        {
+			if (obj == this)
+				return true;
+
+			DHKeyParameters other = obj as DHKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			DHKeyParameters other)
+		{
+			return Platform.Equals(parameters, other.parameters)
+				&& base.Equals(other);
+		}
+
+		public override int GetHashCode()
+        {
+			int hc = base.GetHashCode();
+
+			if (parameters != null)
+			{
+				hc ^= parameters.GetHashCode();
+			}
+
+			return hc;
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs
new file mode 100644
index 000000000..a0544e73b
--- /dev/null
+++ b/crypto/src/crypto/parameters/DHParameters.cs
@@ -0,0 +1,184 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DHParameters
+		: ICipherParameters
+    {
+		private const int DefaultMinimumLength = 160;
+
+		private readonly BigInteger p, g, q, j;
+		private readonly int m, l;
+		private readonly DHValidationParameters validation;
+
+		private static int GetDefaultMParam(
+			int lParam)
+		{
+			if (lParam == 0)
+				return DefaultMinimumLength;
+
+			return System.Math.Min(lParam, DefaultMinimumLength);
+		}
+
+		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,  DefaultMinimumLength, 0, j, validation)
+		{
+		}
+
+		public DHParameters(
+			BigInteger				p,
+			BigInteger				g,
+			BigInteger				q,
+			int						m,
+			int						l,
+			BigInteger				j,
+			DHValidationParameters	validation)
+		{
+			if (p == null)
+				throw new ArgumentNullException("p");
+			if (g == null)
+				throw new ArgumentNullException("g");
+			if (!p.TestBit(0))
+				throw new ArgumentException("field must be an odd prime", "p");
+			if (g.CompareTo(BigInteger.Two) < 0
+				|| g.CompareTo(p.Subtract(BigInteger.Two)) > 0)
+				throw new ArgumentException("generator must in the range [2, p - 2]", "g");
+			if (q != null && q.BitLength >= p.BitLength)
+				throw new ArgumentException("q too big to be a factor of (p-1)", "q");
+			if (m >= p.BitLength)
+				throw new ArgumentException("m value must be < bitlength of p", "m");
+			if (l != 0)
+			{ 
+	            if (l >= p.BitLength)
+                	throw new ArgumentException("when l value specified, it must be less than bitlength(p)", "l");
+				if (l < m)
+					throw new ArgumentException("when l value specified, it may not be less than m value", "l");
+			}
+			if (j != null && j.CompareTo(BigInteger.Two) < 0)
+				throw new ArgumentException("subgroup factor must be >= 2", "j");
+
+			// TODO If q, j both provided, validate p = jq + 1 ?
+
+			this.p = p;
+			this.g = g;
+			this.q = q;
+			this.m = m;
+			this.l = l;
+			this.j = j;
+			this.validation = validation;
+        }
+
+		public BigInteger P
+        {
+            get { return p; }
+        }
+
+		public BigInteger G
+        {
+            get { return g; }
+        }
+
+		public BigInteger Q
+        {
+            get { return q; }
+        }
+
+		public BigInteger J
+        {
+            get { return j; }
+        }
+
+		/// <summary>The minimum bitlength of the private value.</summary>
+		public int M
+		{
+			get { return m; }
+		}
+
+		/// <summary>The bitlength of the private value.</summary>
+		public int L
+		{
+			get { return l; }
+		}
+
+		public DHValidationParameters ValidationParameters
+        {
+			get { return validation; }
+        }
+
+		public override bool Equals(
+			object obj)
+        {
+			if (obj == this)
+				return true;
+
+			DHParameters other = obj as DHParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+		}
+
+		protected bool Equals(
+			DHParameters other)
+		{
+			return p.Equals(other.p)
+				&& g.Equals(other.g)
+				&& Platform.Equals(q, other.q);
+		}
+
+		public override int GetHashCode()
+        {
+			int hc = p.GetHashCode() ^ g.GetHashCode();
+
+			if (q != null)
+			{
+				hc ^= q.GetHashCode();
+			}
+
+			return hc;
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DHPrivateKeyParameters.cs b/crypto/src/crypto/parameters/DHPrivateKeyParameters.cs
new file mode 100644
index 000000000..fc724df81
--- /dev/null
+++ b/crypto/src/crypto/parameters/DHPrivateKeyParameters.cs
@@ -0,0 +1,60 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DHPrivateKeyParameters
+		: DHKeyParameters
+    {
+        private readonly BigInteger x;
+
+		public DHPrivateKeyParameters(
+            BigInteger		x,
+            DHParameters	parameters)
+			: base(true, parameters)
+        {
+            this.x = x;
+        }
+
+		public DHPrivateKeyParameters(
+            BigInteger			x,
+            DHParameters		parameters,
+		    DerObjectIdentifier	algorithmOid)
+			: base(true, parameters, algorithmOid)
+        {
+            this.x = x;
+        }
+
+		public BigInteger X
+        {
+            get { return x; }
+        }
+
+		public override bool Equals(
+			object obj)
+        {
+			if (obj == this)
+				return true;
+
+			DHPrivateKeyParameters other = obj as DHPrivateKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			DHPrivateKeyParameters other)
+		{
+			return x.Equals(other.x) && base.Equals(other);
+		}
+
+		public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ base.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DHPublicKeyParameters.cs b/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
new file mode 100644
index 000000000..e79375f71
--- /dev/null
+++ b/crypto/src/crypto/parameters/DHPublicKeyParameters.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DHPublicKeyParameters
+		: DHKeyParameters
+    {
+        private readonly BigInteger y;
+
+		public DHPublicKeyParameters(
+            BigInteger		y,
+            DHParameters	parameters)
+			: base(false, parameters)
+        {
+			if (y == null)
+				throw new ArgumentNullException("y");
+
+			this.y = y;
+        }
+
+		public DHPublicKeyParameters(
+            BigInteger			y,
+            DHParameters		parameters,
+		    DerObjectIdentifier	algorithmOid)
+			: base(false, parameters, algorithmOid)
+        {
+			if (y == null)
+				throw new ArgumentNullException("y");
+
+			this.y = y;
+        }
+
+        public BigInteger Y
+        {
+            get { return y; }
+        }
+
+		public override bool Equals(
+			object  obj)
+        {
+			if (obj == this)
+				return true;
+
+			DHPublicKeyParameters other = obj as DHPublicKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			DHPublicKeyParameters other)
+		{
+			return y.Equals(other.y) && base.Equals(other);
+		}
+
+		public override int GetHashCode()
+        {
+            return y.GetHashCode() ^ base.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DHValidationParameters.cs b/crypto/src/crypto/parameters/DHValidationParameters.cs
new file mode 100644
index 000000000..50c0739fa
--- /dev/null
+++ b/crypto/src/crypto/parameters/DHValidationParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DHValidationParameters
+    {
+        private readonly byte[] seed;
+        private readonly int counter;
+
+		public DHValidationParameters(
+            byte[]	seed,
+            int		counter)
+        {
+			if (seed == null)
+				throw new ArgumentNullException("seed");
+
+			this.seed = (byte[]) seed.Clone();
+            this.counter = counter;
+        }
+
+		public byte[] GetSeed()
+        {
+            return (byte[]) seed.Clone();
+        }
+
+		public int Counter
+        {
+            get { return counter; }
+        }
+
+		public override bool Equals(
+            object obj)
+        {
+			if (obj == this)
+				return true;
+
+			DHValidationParameters other = obj as DHValidationParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+		}
+
+		protected bool Equals(
+			DHValidationParameters other)
+		{
+			return counter == other.counter
+				&& Arrays.AreEqual(this.seed, other.seed);
+		}
+
+		public override int GetHashCode()
+        {
+			return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/DSAParameterGenerationParameters.cs b/crypto/src/crypto/parameters/DSAParameterGenerationParameters.cs
new file mode 100644
index 000000000..7427574c8
--- /dev/null
+++ b/crypto/src/crypto/parameters/DSAParameterGenerationParameters.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DsaParameterGenerationParameters
+    {
+        public const int DigitalSignatureUsage = 1;
+        public const int KeyEstablishmentUsage = 2;
+
+        private readonly int l;
+        private readonly int n;
+        private readonly int certainty;
+        private readonly SecureRandom random;
+        private readonly int usageIndex;
+
+        /**
+         * Construct without a usage index, this will do a random construction of G.
+         *
+         * @param L desired length of prime P in bits (the effective key size).
+         * @param N desired length of prime Q in bits.
+         * @param certainty certainty level for prime number generation.
+         * @param random the source of randomness to use.
+         */
+        public DsaParameterGenerationParameters(int L, int N, int certainty, SecureRandom random)
+            : this(L, N, certainty, random, -1)
+        {
+        }
+
+        /**
+         * Construct for a specific usage index - this has the effect of using verifiable canonical generation of G.
+         *
+         * @param L desired length of prime P in bits (the effective key size).
+         * @param N desired length of prime Q in bits.
+         * @param certainty certainty level for prime number generation.
+         * @param random the source of randomness to use.
+         * @param usageIndex a valid usage index.
+         */
+        public DsaParameterGenerationParameters(int L, int N, int certainty, SecureRandom random, int usageIndex)
+        {
+            this.l = L;
+            this.n = N;
+            this.certainty = certainty;
+            this.random = random;
+            this.usageIndex = usageIndex;
+        }
+
+        public virtual int L
+        {
+            get { return l; }
+        }
+
+        public virtual int N
+        {
+            get { return n; }
+        }
+
+        public virtual int UsageIndex
+        {
+            get { return usageIndex; }
+        }
+
+        public virtual int Certainty
+        {
+            get { return certainty; }
+        }
+
+        public virtual SecureRandom Random
+        {
+            get { return random; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DesEdeParameters.cs b/crypto/src/crypto/parameters/DesEdeParameters.cs
new file mode 100644
index 000000000..420aaecea
--- /dev/null
+++ b/crypto/src/crypto/parameters/DesEdeParameters.cs
@@ -0,0 +1,95 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DesEdeParameters
+		: DesParameters
+    {
+        /*
+        * DES-EDE Key length in bytes.
+        */
+		public const int DesEdeKeyLength = 24;
+
+		private static byte[] FixKey(
+			byte[]	key,
+			int		keyOff,
+			int		keyLen)
+		{
+			byte[] tmp = new byte[24];
+
+			switch (keyLen)
+			{
+				case 16:
+					Array.Copy(key, keyOff, tmp, 0, 16);
+					Array.Copy(key, keyOff, tmp, 16, 8);
+					break;
+				case 24:
+					Array.Copy(key, keyOff, tmp, 0, 24);
+					break;
+				default:
+					throw new ArgumentException("Bad length for DESede key: " + keyLen, "keyLen");
+			}
+
+			if (IsWeakKey(tmp))
+				throw new ArgumentException("attempt to create weak DESede key");
+
+			return tmp;
+		}
+
+		public DesEdeParameters(
+            byte[] key)
+			: base(FixKey(key, 0, key.Length))
+        {
+        }
+
+		public DesEdeParameters(
+			byte[]	key,
+			int		keyOff,
+			int		keyLen)
+			: base(FixKey(key, keyOff, keyLen))
+		{
+		}
+
+		/**
+         * 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 bool IsWeakKey(
+            byte[]  key,
+            int     offset,
+            int     length)
+        {
+            for (int i = offset; i < length; i += DesKeyLength)
+            {
+                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 new bool IsWeakKey(
+            byte[]	key,
+            int		offset)
+        {
+            return IsWeakKey(key, offset, key.Length - offset);
+        }
+
+		public static new bool IsWeakKey(
+			byte[] key)
+		{
+			return IsWeakKey(key, 0, key.Length);
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/DesParameters.cs b/crypto/src/crypto/parameters/DesParameters.cs
new file mode 100644
index 000000000..ee37cd861
--- /dev/null
+++ b/crypto/src/crypto/parameters/DesParameters.cs
@@ -0,0 +1,130 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DesParameters
+		: KeyParameter
+    {
+        public DesParameters(
+            byte[] key)
+			: base(key)
+        {
+            if (IsWeakKey(key))
+				throw new ArgumentException("attempt to create weak DES key");
+        }
+
+		public DesParameters(
+			byte[]	key,
+			int		keyOff,
+			int		keyLen)
+			: base(key, keyOff, keyLen)
+		{
+			if (IsWeakKey(key, keyOff))
+				throw new ArgumentException("attempt to create weak DES key");
+		}
+
+		/*
+        * DES Key Length in bytes.
+        */
+        public const int DesKeyLength = 8;
+
+        /*
+        * Table of weak and semi-weak keys taken from Schneier pp281
+        */
+        private const int N_DES_WEAK_KEYS = 16;
+
+        private static readonly 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.
+        * </p>
+        * @return true if the given DES key material is weak or semi-weak,
+        *     false otherwise.
+        */
+        public static bool IsWeakKey(
+            byte[]	key,
+            int		offset)
+        {
+            if (key.Length - offset < DesKeyLength)
+                throw new ArgumentException("key material too short.");
+
+			//nextkey:
+            for (int i = 0; i < N_DES_WEAK_KEYS; i++)
+            {
+                bool unmatch = false;
+                for (int j = 0; j < DesKeyLength; j++)
+                {
+                    if (key[j + offset] != DES_weak_keys[i * DesKeyLength + j])
+                    {
+                        //continue nextkey;
+                        unmatch = true;
+						break;
+                    }
+                }
+
+				if (!unmatch)
+				{
+					return true;
+				}
+            }
+
+			return false;
+        }
+
+		public static bool IsWeakKey(
+			byte[] key)
+		{
+			return IsWeakKey(key, 0);
+		}
+
+		/**
+        * 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/crypto/src/crypto/parameters/DsaKeyGenerationParameters.cs b/crypto/src/crypto/parameters/DsaKeyGenerationParameters.cs
new file mode 100644
index 000000000..86d6f5bd4
--- /dev/null
+++ b/crypto/src/crypto/parameters/DsaKeyGenerationParameters.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DsaKeyGenerationParameters
+		: KeyGenerationParameters
+    {
+        private readonly DsaParameters parameters;
+
+        public DsaKeyGenerationParameters(
+            SecureRandom	random,
+            DsaParameters	parameters)
+			: base(random, parameters.P.BitLength - 1)
+        {
+            this.parameters = parameters;
+        }
+
+		public DsaParameters Parameters
+        {
+            get { return parameters; }
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/parameters/DsaKeyParameters.cs b/crypto/src/crypto/parameters/DsaKeyParameters.cs
new file mode 100644
index 000000000..5fe6d7ab4
--- /dev/null
+++ b/crypto/src/crypto/parameters/DsaKeyParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public abstract class DsaKeyParameters
+		: AsymmetricKeyParameter
+    {
+		private readonly DsaParameters parameters;
+
+		protected DsaKeyParameters(
+            bool			isPrivate,
+            DsaParameters	parameters)
+			: base(isPrivate)
+        {
+			// Note: parameters may be null
+            this.parameters = parameters;
+        }
+
+		public DsaParameters Parameters
+        {
+            get { return parameters; }
+        }
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			DsaKeyParameters other = obj as DsaKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+		}
+
+		protected bool Equals(
+			DsaKeyParameters other)
+		{
+			return Platform.Equals(parameters, other.parameters)
+				&& base.Equals(other);
+		}
+
+		public override int GetHashCode()
+		{
+			int hc = base.GetHashCode();
+
+			if (parameters != null)
+			{
+				hc ^= parameters.GetHashCode();
+			}
+
+			return hc;
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/DsaParameters.cs b/crypto/src/crypto/parameters/DsaParameters.cs
new file mode 100644
index 000000000..50d080ee2
--- /dev/null
+++ b/crypto/src/crypto/parameters/DsaParameters.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DsaParameters
+		: ICipherParameters
+    {
+        private readonly BigInteger p, q , g;
+        private readonly DsaValidationParameters validation;
+
+		public DsaParameters(
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	g)
+			: this(p, q, g, null)
+        {
+        }
+
+		public DsaParameters(
+            BigInteger				p,
+            BigInteger				q,
+            BigInteger				g,
+            DsaValidationParameters	parameters)
+        {
+			if (p == null)
+				throw new ArgumentNullException("p");
+			if (q == null)
+				throw new ArgumentNullException("q");
+			if (g == null)
+				throw new ArgumentNullException("g");
+
+			this.p = p;
+            this.q = q;
+			this.g = g;
+			this.validation = parameters;
+        }
+
+        public BigInteger P
+        {
+            get { return p; }
+        }
+
+		public BigInteger Q
+        {
+            get { return q; }
+        }
+
+		public BigInteger G
+        {
+            get { return g; }
+        }
+
+		public DsaValidationParameters ValidationParameters
+        {
+			get { return validation; }
+        }
+
+		public override bool Equals(
+			object obj)
+        {
+			if (obj == this)
+				return true;
+
+			DsaParameters other = obj as DsaParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			DsaParameters other)
+		{
+			return p.Equals(other.p) && q.Equals(other.q) && g.Equals(other.g);
+		}
+
+		public override int GetHashCode()
+        {
+			return p.GetHashCode() ^ q.GetHashCode() ^ g.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DsaPrivateKeyParameters.cs b/crypto/src/crypto/parameters/DsaPrivateKeyParameters.cs
new file mode 100644
index 000000000..2abdd0e4f
--- /dev/null
+++ b/crypto/src/crypto/parameters/DsaPrivateKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DsaPrivateKeyParameters
+		: DsaKeyParameters
+    {
+        private readonly BigInteger x;
+
+		public DsaPrivateKeyParameters(
+            BigInteger		x,
+            DsaParameters	parameters)
+			: base(true, parameters)
+        {
+			if (x == null)
+				throw new ArgumentNullException("x");
+
+			this.x = x;
+        }
+
+		public BigInteger X
+        {
+            get { return x; }
+        }
+
+		public override bool Equals(
+			object obj)
+        {
+			if (obj == this)
+				return true;
+
+			DsaPrivateKeyParameters other = obj as DsaPrivateKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			DsaPrivateKeyParameters other)
+		{
+			return x.Equals(other.x) && base.Equals(other);
+		}
+
+		public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ base.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DsaPublicKeyParameters.cs b/crypto/src/crypto/parameters/DsaPublicKeyParameters.cs
new file mode 100644
index 000000000..f11f858f3
--- /dev/null
+++ b/crypto/src/crypto/parameters/DsaPublicKeyParameters.cs
@@ -0,0 +1,52 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DsaPublicKeyParameters
+		: DsaKeyParameters
+    {
+        private readonly BigInteger y;
+
+		public DsaPublicKeyParameters(
+            BigInteger		y,
+            DsaParameters	parameters)
+			: base(false, parameters)
+        {
+			if (y == null)
+				throw new ArgumentNullException("y");
+
+			this.y = y;
+        }
+
+		public BigInteger Y
+        {
+            get { return y; }
+        }
+
+		public override bool Equals(object obj)
+        {
+			if (obj == this)
+				return true;
+
+			DsaPublicKeyParameters other = obj as DsaPublicKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			DsaPublicKeyParameters other)
+		{
+			return y.Equals(other.y) && base.Equals(other);
+		}
+
+		public override int GetHashCode()
+        {
+			return y.GetHashCode() ^ base.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/DsaValidationParameters.cs b/crypto/src/crypto/parameters/DsaValidationParameters.cs
index b9cdc4a79..c2f84c785 100644
--- a/crypto/src/crypto/parameters/DsaValidationParameters.cs
+++ b/crypto/src/crypto/parameters/DsaValidationParameters.cs
@@ -8,52 +8,65 @@ namespace Org.BouncyCastle.Crypto.Parameters
     {
         private readonly byte[] seed;
         private readonly int counter;
+        private readonly int usageIndex;
 
-		public DsaValidationParameters(
+        public DsaValidationParameters(byte[] seed, int counter)
+            : this(seed, counter, -1)
+        {
+        }
+
+        public DsaValidationParameters(
             byte[]	seed,
-            int		counter)
+            int		counter,
+            int     usageIndex)
         {
-			if (seed == null)
-				throw new ArgumentNullException("seed");
+            if (seed == null)
+                throw new ArgumentNullException("seed");
 
-			this.seed = (byte[]) seed.Clone();
+            this.seed = (byte[]) seed.Clone();
             this.counter = counter;
+            this.usageIndex = usageIndex;
+        }
+
+        public virtual byte[] GetSeed()
+        {
+            return (byte[]) seed.Clone();
         }
 
-		public byte[] GetSeed()
+        public virtual int Counter
         {
-			return (byte[]) seed.Clone();
+            get { return counter; }
         }
 
-		public int Counter
-		{
-			get { return counter; }
-		}
+        public virtual int UsageIndex
+        {
+            get { return usageIndex; }
+        }
 
-		public override bool Equals(
+        public override bool Equals(
             object obj)
         {
-			if (obj == this)
-				return true;
+            if (obj == this)
+                return true;
 
-			DsaValidationParameters other = obj as DsaValidationParameters;
+            DsaValidationParameters other = obj as DsaValidationParameters;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			return Equals(other);
-		}
+            return Equals(other);
+        }
 
-		protected bool Equals(
-			DsaValidationParameters other)
-		{
-			return counter == other.counter
-				&& Arrays.AreEqual(seed, other.seed);
-		}
+        protected virtual bool Equals(
+            DsaValidationParameters other)
+        {
+            return counter == other.counter
+                && Arrays.AreEqual(seed, other.seed);
+        }
 
-		public override int GetHashCode()
+        public override int GetHashCode()
         {
-			return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
-		}
+            return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
+        }
     }
 }
diff --git a/crypto/src/crypto/parameters/ECDomainParameters.cs b/crypto/src/crypto/parameters/ECDomainParameters.cs
index c6a3e4e72..619971a6c 100644
--- a/crypto/src/crypto/parameters/ECDomainParameters.cs
+++ b/crypto/src/crypto/parameters/ECDomainParameters.cs
@@ -14,11 +14,11 @@ namespace Org.BouncyCastle.Crypto.Parameters
         internal BigInteger  n;
         internal BigInteger  h;
 
-		public ECDomainParameters(
+        public ECDomainParameters(
             ECCurve     curve,
             ECPoint     g,
             BigInteger  n)
-			: this(curve, g, n, BigInteger.One)
+            : this(curve, g, n, BigInteger.One)
         {
         }
 
@@ -27,34 +27,34 @@ namespace Org.BouncyCastle.Crypto.Parameters
             ECPoint     g,
             BigInteger  n,
             BigInteger  h)
-			: this(curve, g, n, h, null)
-		{
+            : this(curve, g, n, h, null)
+        {
         }
 
-		public ECDomainParameters(
+        public ECDomainParameters(
             ECCurve     curve,
             ECPoint     g,
             BigInteger  n,
             BigInteger  h,
             byte[]      seed)
         {
-			if (curve == null)
-				throw new ArgumentNullException("curve");
-			if (g == null)
-				throw new ArgumentNullException("g");
-			if (n == null)
-				throw new ArgumentNullException("n");
-			if (h == null)
-				throw new ArgumentNullException("h");
-
-			this.curve = curve;
-            this.g = g;
+            if (curve == null)
+                throw new ArgumentNullException("curve");
+            if (g == null)
+                throw new ArgumentNullException("g");
+            if (n == null)
+                throw new ArgumentNullException("n");
+            if (h == null)
+                throw new ArgumentNullException("h");
+
+            this.curve = curve;
+            this.g = g.Normalize();
             this.n = n;
             this.h = h;
             this.seed = Arrays.Clone(seed);
         }
 
-		public ECCurve Curve
+        public ECCurve Curve
         {
             get { return curve; }
         }
@@ -76,40 +76,40 @@ namespace Org.BouncyCastle.Crypto.Parameters
 
         public byte[] GetSeed()
         {
-			return Arrays.Clone(seed);
+            return Arrays.Clone(seed);
         }
 
-		public override bool Equals(
-			object obj)
+        public override bool Equals(
+            object obj)
         {
-			if (obj == this)
-				return true;
+            if (obj == this)
+                return true;
 
-			ECDomainParameters other = obj as ECDomainParameters;
+            ECDomainParameters other = obj as ECDomainParameters;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			return Equals(other);
+            return Equals(other);
+        }
+
+        protected bool Equals(
+            ECDomainParameters other)
+        {
+            return curve.Equals(other.curve)
+                &&	g.Equals(other.g)
+                &&	n.Equals(other.n)
+                &&	h.Equals(other.h)
+                &&	Arrays.AreEqual(seed, other.seed);
         }
 
-		protected bool Equals(
-			ECDomainParameters other)
-		{
-			return curve.Equals(other.curve)
-				&&	g.Equals(other.g)
-				&&	n.Equals(other.n)
-				&&	h.Equals(other.h)
-				&&	Arrays.AreEqual(seed, other.seed);
-		}
-
-		public override int GetHashCode()
+        public override int GetHashCode()
         {
             return curve.GetHashCode()
-				^	g.GetHashCode()
-				^	n.GetHashCode()
-				^	h.GetHashCode()
-				^	Arrays.GetHashCode(seed);
+                ^	g.GetHashCode()
+                ^	n.GetHashCode()
+                ^	h.GetHashCode()
+                ^	Arrays.GetHashCode(seed);
         }
     }
 
diff --git a/crypto/src/crypto/parameters/ECKeyGenerationParameters.cs b/crypto/src/crypto/parameters/ECKeyGenerationParameters.cs
new file mode 100644
index 000000000..9b2b98845
--- /dev/null
+++ b/crypto/src/crypto/parameters/ECKeyGenerationParameters.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ECKeyGenerationParameters
+		: KeyGenerationParameters
+    {
+        private readonly ECDomainParameters domainParams;
+		private readonly DerObjectIdentifier publicKeyParamSet;
+
+		public ECKeyGenerationParameters(
+			ECDomainParameters	domainParameters,
+			SecureRandom		random)
+			: base(random, domainParameters.N.BitLength)
+        {
+            this.domainParams = domainParameters;
+        }
+
+		public ECKeyGenerationParameters(
+			DerObjectIdentifier	publicKeyParamSet,
+			SecureRandom		random)
+			: this(ECKeyParameters.LookupParameters(publicKeyParamSet), random)
+		{
+			this.publicKeyParamSet = publicKeyParamSet;
+		}
+
+		public ECDomainParameters DomainParameters
+        {
+			get { return domainParams; }
+        }
+
+		public DerObjectIdentifier PublicKeyParamSet
+		{
+			get { return publicKeyParamSet; }
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/ECKeyParameters.cs b/crypto/src/crypto/parameters/ECKeyParameters.cs
index 4d4622ced..70b3543da 100644
--- a/crypto/src/crypto/parameters/ECKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ECKeyParameters.cs
@@ -1,145 +1,136 @@
 using System;
-using System.Globalization;
+using System.Collections;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Crypto.Parameters
 {
     public abstract class ECKeyParameters
-		: AsymmetricKeyParameter
+        : AsymmetricKeyParameter
     {
-		private readonly string algorithm;
-		private readonly ECDomainParameters parameters;
-		private readonly DerObjectIdentifier publicKeyParamSet;
+        private static readonly string[] algorithms = { "EC", "ECDSA", "ECDH", "ECDHC", "ECGOST3410", "ECMQV" };
 
-		protected ECKeyParameters(
-			string				algorithm,
+        private readonly string algorithm;
+        private readonly ECDomainParameters parameters;
+        private readonly DerObjectIdentifier publicKeyParamSet;
+
+        protected ECKeyParameters(
+            string				algorithm,
             bool				isPrivate,
             ECDomainParameters	parameters)
-			: base(isPrivate)
+            : base(isPrivate)
+        {
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+            if (parameters == null)
+                throw new ArgumentNullException("parameters");
+
+            this.algorithm = VerifyAlgorithmName(algorithm);
+            this.parameters = parameters;
+        }
+
+        protected ECKeyParameters(
+            string				algorithm,
+            bool				isPrivate,
+            DerObjectIdentifier	publicKeyParamSet)
+            : base(isPrivate)
         {
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-			if (parameters == null)
-				throw new ArgumentNullException("parameters");
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+            if (publicKeyParamSet == null)
+                throw new ArgumentNullException("publicKeyParamSet");
+
+            this.algorithm = VerifyAlgorithmName(algorithm);
+            this.parameters = LookupParameters(publicKeyParamSet);
+            this.publicKeyParamSet = publicKeyParamSet;
+        }
 
-			this.algorithm = VerifyAlgorithmName(algorithm);
-			this.parameters = parameters;
+        public string AlgorithmName
+        {
+            get { return algorithm; }
         }
 
-		protected ECKeyParameters(
-			string				algorithm,
-			bool				isPrivate,
-			DerObjectIdentifier	publicKeyParamSet)
-			: base(isPrivate)
-		{
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-			if (publicKeyParamSet == null)
-				throw new ArgumentNullException("publicKeyParamSet");
-
-			this.algorithm = VerifyAlgorithmName(algorithm);
-			this.parameters = LookupParameters(publicKeyParamSet);
-			this.publicKeyParamSet = publicKeyParamSet;
-		}
-
-		public string AlgorithmName
-		{
-			get { return algorithm; }
-		}
-
-		public ECDomainParameters Parameters
+        public ECDomainParameters Parameters
         {
-			get { return parameters; }
+            get { return parameters; }
         }
 
-		public DerObjectIdentifier PublicKeyParamSet
-		{
-			get { return publicKeyParamSet; }
-		}
-
-		public override bool Equals(
-			object obj)
-		{
-			if (obj == this)
-				return true;
-
-			ECDomainParameters other = obj as ECDomainParameters;
-
-			if (other == null)
-				return false;
-
-			return Equals(other);
-		}
-
-		protected bool Equals(
-			ECKeyParameters other)
-		{
-			return parameters.Equals(other.parameters) && base.Equals(other);
-		}
-
-		public override int GetHashCode()
-		{
-			return parameters.GetHashCode() ^ base.GetHashCode();
-		}
-
-		internal ECKeyGenerationParameters CreateKeyGenerationParameters(
-			SecureRandom random)
-		{
-			if (publicKeyParamSet != null)
-			{
-				return new ECKeyGenerationParameters(publicKeyParamSet, random);
-			}
-
-			return new ECKeyGenerationParameters(parameters, random);
-		}
-
-		private string VerifyAlgorithmName(
-			string algorithm)
-		{
-			string upper = algorithm.ToUpperInvariant();
-
-			switch (upper)
-			{
-				case "EC":
-				case "ECDSA":
-				case "ECDH":
-				case "ECDHC":
-				case "ECGOST3410":
-				case "ECMQV":
-					break;
-				default:
-					throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
-			}
-
-			return upper;
-		}
-
-		internal static ECDomainParameters LookupParameters(
-			DerObjectIdentifier publicKeyParamSet)
-		{
-			if (publicKeyParamSet == null)
-				throw new ArgumentNullException("publicKeyParamSet");
-
-			ECDomainParameters p = ECGost3410NamedCurves.GetByOid(publicKeyParamSet);
-
-			if (p == null)
-			{
-				X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(publicKeyParamSet);
-
-				if (x9 == null)
-				{
-					throw new ArgumentException("OID is not a valid public key parameter set", "publicKeyParamSet");
-				}
-
-				p = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
-			}
-
-			return p;
-		}
-	}
+        public DerObjectIdentifier PublicKeyParamSet
+        {
+            get { return publicKeyParamSet; }
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+            ECDomainParameters other = obj as ECDomainParameters;
+
+            if (other == null)
+                return false;
+
+            return Equals(other);
+        }
+
+        protected bool Equals(
+            ECKeyParameters other)
+        {
+            return parameters.Equals(other.parameters) && base.Equals(other);
+        }
+
+        public override int GetHashCode()
+        {
+            return parameters.GetHashCode() ^ base.GetHashCode();
+        }
+
+        internal ECKeyGenerationParameters CreateKeyGenerationParameters(
+            SecureRandom random)
+        {
+            if (publicKeyParamSet != null)
+            {
+                return new ECKeyGenerationParameters(publicKeyParamSet, random);
+            }
+
+            return new ECKeyGenerationParameters(parameters, random);
+        }
+
+        internal static string VerifyAlgorithmName(string algorithm)
+        {
+            string upper = Platform.ToUpperInvariant(algorithm);
+            if (Array.IndexOf(algorithms, algorithm, 0, algorithms.Length) < 0)
+                throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm");
+            return upper;
+        }
+
+        internal static ECDomainParameters LookupParameters(
+            DerObjectIdentifier publicKeyParamSet)
+        {
+            if (publicKeyParamSet == null)
+                throw new ArgumentNullException("publicKeyParamSet");
+
+            ECDomainParameters p = ECGost3410NamedCurves.GetByOid(publicKeyParamSet);
+
+            if (p == null)
+            {
+                X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(publicKeyParamSet);
+
+                if (x9 == null)
+                {
+                    throw new ArgumentException("OID is not a valid public key parameter set", "publicKeyParamSet");
+                }
+
+                p = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+            }
+
+            return p;
+        }
+    }
 }
diff --git a/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs b/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
index e6352d5d1..4d0fa1fc6 100644
--- a/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
@@ -7,81 +7,81 @@ using Org.BouncyCastle.Math;
 namespace Org.BouncyCastle.Crypto.Parameters
 {
     public class ECPrivateKeyParameters
-		: ECKeyParameters
+        : ECKeyParameters
     {
-		private readonly BigInteger d;
-
-		public ECPrivateKeyParameters(
-			BigInteger			d,
-			ECDomainParameters	parameters)
-			: this("EC", d, parameters)
-		{
-		}
-
-		[Obsolete("Use version with explicit 'algorithm' parameter")]
-		public ECPrivateKeyParameters(
-			BigInteger			d,
-			DerObjectIdentifier publicKeyParamSet)
-			: base("ECGOST3410", true, publicKeyParamSet)
-		{
-			if (d == null)
-				throw new ArgumentNullException("d");
-
-			this.d = d;
-		}
-
-		public ECPrivateKeyParameters(
-			string				algorithm,
-			BigInteger			d,
-			ECDomainParameters	parameters)
-			: base(algorithm, true, parameters)
-		{
-			if (d == null)
-				throw new ArgumentNullException("d");
-
-			this.d = d;
-		}
-
-		public ECPrivateKeyParameters(
-			string				algorithm,
-			BigInteger			d,
-			DerObjectIdentifier publicKeyParamSet)
-			: base(algorithm, true, publicKeyParamSet)
-		{
-			if (d == null)
-				throw new ArgumentNullException("d");
-
-			this.d = d;
-		}
-
-		public BigInteger D
-		{
-			get { return d; }
-		}
-
-		public override bool Equals(
-			object obj)
+        private readonly BigInteger d;
+
+        public ECPrivateKeyParameters(
+            BigInteger			d,
+            ECDomainParameters	parameters)
+            : this("EC", d, parameters)
+        {
+        }
+
+        [Obsolete("Use version with explicit 'algorithm' parameter")]
+        public ECPrivateKeyParameters(
+            BigInteger			d,
+            DerObjectIdentifier publicKeyParamSet)
+            : base("ECGOST3410", true, publicKeyParamSet)
         {
-			if (obj == this)
-				return true;
+            if (d == null)
+                throw new ArgumentNullException("d");
 
-			ECPrivateKeyParameters other = obj as ECPrivateKeyParameters;
+            this.d = d;
+        }
 
-			if (other == null)
-				return false;
+        public ECPrivateKeyParameters(
+            string				algorithm,
+            BigInteger			d,
+            ECDomainParameters	parameters)
+            : base(algorithm, true, parameters)
+        {
+            if (d == null)
+                throw new ArgumentNullException("d");
 
-			return Equals(other);
+            this.d = d;
         }
 
-		protected bool Equals(
-			ECPrivateKeyParameters other)
-		{
-			return d.Equals(other.d) && base.Equals(other);
-		}
+        public ECPrivateKeyParameters(
+            string				algorithm,
+            BigInteger			d,
+            DerObjectIdentifier publicKeyParamSet)
+            : base(algorithm, true, publicKeyParamSet)
+        {
+            if (d == null)
+                throw new ArgumentNullException("d");
+
+            this.d = d;
+        }
+
+        public BigInteger D
+        {
+            get { return d; }
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+            ECPrivateKeyParameters other = obj as ECPrivateKeyParameters;
+
+            if (other == null)
+                return false;
+
+            return Equals(other);
+        }
+
+        protected bool Equals(
+            ECPrivateKeyParameters other)
+        {
+            return d.Equals(other.d) && base.Equals(other);
+        }
 
-		public override int GetHashCode()
+        public override int GetHashCode()
         {
             return d.GetHashCode() ^ base.GetHashCode();
         }
-	}
+    }
 }
diff --git a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
index 9e71c2a25..1eb665da9 100644
--- a/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ECPublicKeyParameters.cs
@@ -7,78 +7,78 @@ using Org.BouncyCastle.Math.EC;
 namespace Org.BouncyCastle.Crypto.Parameters
 {
     public class ECPublicKeyParameters
-		: ECKeyParameters
+        : ECKeyParameters
     {
         private readonly ECPoint q;
 
-		public ECPublicKeyParameters(
-			ECPoint				q,
-			ECDomainParameters	parameters)
-			: this("EC", q, parameters)
-		{
-		}
-
-		[Obsolete("Use version with explicit 'algorithm' parameter")]
-		public ECPublicKeyParameters(
-			ECPoint				q,
-			DerObjectIdentifier publicKeyParamSet)
-			: base("ECGOST3410", false, publicKeyParamSet)
-		{
-			if (q == null)
-				throw new ArgumentNullException("q");
-
-			this.q = q;
-		}
-
-		public ECPublicKeyParameters(
-			string				algorithm,
-			ECPoint				q,
-			ECDomainParameters	parameters)
-			: base(algorithm, false, parameters)
+        public ECPublicKeyParameters(
+            ECPoint				q,
+            ECDomainParameters	parameters)
+            : this("EC", q, parameters)
         {
-			if (q == null)
-				throw new ArgumentNullException("q");
+        }
+
+        [Obsolete("Use version with explicit 'algorithm' parameter")]
+        public ECPublicKeyParameters(
+            ECPoint				q,
+            DerObjectIdentifier publicKeyParamSet)
+            : base("ECGOST3410", false, publicKeyParamSet)
+        {
+            if (q == null)
+                throw new ArgumentNullException("q");
 
-			this.q = q;
-		}
+            this.q = q.Normalize();
+        }
 
-		public ECPublicKeyParameters(
-			string				algorithm,
-			ECPoint				q,
-			DerObjectIdentifier publicKeyParamSet)
-			: base(algorithm, false, publicKeyParamSet)
+        public ECPublicKeyParameters(
+            string				algorithm,
+            ECPoint				q,
+            ECDomainParameters	parameters)
+            : base(algorithm, false, parameters)
         {
-			if (q == null)
-				throw new ArgumentNullException("q");
+            if (q == null)
+                throw new ArgumentNullException("q");
 
-			this.q = q;
-		}
+            this.q = q.Normalize();
+        }
 
-		public ECPoint Q
+        public ECPublicKeyParameters(
+            string				algorithm,
+            ECPoint				q,
+            DerObjectIdentifier publicKeyParamSet)
+            : base(algorithm, false, publicKeyParamSet)
         {
-			get { return q; }
+            if (q == null)
+                throw new ArgumentNullException("q");
+
+            this.q = q.Normalize();
         }
 
-		public override bool Equals(object obj)
+        public ECPoint Q
         {
-			if (obj == this)
-				return true;
+            get { return q; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (obj == this)
+                return true;
 
-			ECPublicKeyParameters other = obj as ECPublicKeyParameters;
+            ECPublicKeyParameters other = obj as ECPublicKeyParameters;
 
-			if (other == null)
-				return false;
+            if (other == null)
+                return false;
 
-			return Equals(other);
+            return Equals(other);
         }
 
-		protected bool Equals(
-			ECPublicKeyParameters other)
-		{
-			return q.Equals(other.q) && base.Equals(other);
-		}
+        protected bool Equals(
+            ECPublicKeyParameters other)
+        {
+            return q.Equals(other.q) && base.Equals(other);
+        }
 
-		public override int GetHashCode()
+        public override int GetHashCode()
         {
             return q.GetHashCode() ^ base.GetHashCode();
         }
diff --git a/crypto/src/crypto/parameters/ElGamalKeyGenerationParameters.cs b/crypto/src/crypto/parameters/ElGamalKeyGenerationParameters.cs
new file mode 100644
index 000000000..40ca70df4
--- /dev/null
+++ b/crypto/src/crypto/parameters/ElGamalKeyGenerationParameters.cs
@@ -0,0 +1,31 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ElGamalKeyGenerationParameters
+		: KeyGenerationParameters
+    {
+        private readonly ElGamalParameters parameters;
+
+		public ElGamalKeyGenerationParameters(
+            SecureRandom		random,
+            ElGamalParameters	parameters)
+			: base(random, GetStrength(parameters))
+        {
+            this.parameters = parameters;
+        }
+
+		public ElGamalParameters Parameters
+        {
+            get { return parameters; }
+        }
+
+		internal static int GetStrength(
+			ElGamalParameters parameters)
+		{
+			return parameters.L != 0 ? parameters.L : parameters.P.BitLength;
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/ElGamalKeyParameters.cs b/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
new file mode 100644
index 000000000..8b6e27957
--- /dev/null
+++ b/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ElGamalKeyParameters
+		: AsymmetricKeyParameter
+    {
+        private readonly ElGamalParameters parameters;
+
+		protected ElGamalKeyParameters(
+            bool				isPrivate,
+            ElGamalParameters	parameters)
+			: base(isPrivate)
+        {
+			// TODO Should we allow 'parameters' to be null?
+            this.parameters = parameters;
+        }
+
+		public ElGamalParameters Parameters
+        {
+            get { return parameters; }
+        }
+
+		public override bool Equals(
+            object obj)
+        {
+			if (obj == this)
+				return true;
+
+			ElGamalKeyParameters other = obj as ElGamalKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			ElGamalKeyParameters other)
+		{
+			return Platform.Equals(parameters, other.parameters)
+				&& base.Equals(other);
+		}
+
+		public override int GetHashCode()
+        {
+			int hc = base.GetHashCode();
+
+			if (parameters != null)
+			{
+				hc ^= parameters.GetHashCode();
+			}
+
+			return hc;
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/ElGamalParameters.cs b/crypto/src/crypto/parameters/ElGamalParameters.cs
new file mode 100644
index 000000000..ab6d3e710
--- /dev/null
+++ b/crypto/src/crypto/parameters/ElGamalParameters.cs
@@ -0,0 +1,81 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ElGamalParameters
+		: ICipherParameters
+    {
+        private readonly BigInteger p, g;
+		private readonly int l;
+
+		public ElGamalParameters(
+            BigInteger	p,
+            BigInteger	g)
+			: this(p, g, 0)
+        {
+        }
+
+		public ElGamalParameters(
+			BigInteger	p,
+			BigInteger	g,
+			int			l)
+		{
+			if (p == null)
+				throw new ArgumentNullException("p");
+			if (g == null)
+				throw new ArgumentNullException("g");
+
+			this.p = p;
+			this.g = g;
+			this.l = l;
+		}
+
+		public BigInteger P
+        {
+            get { return p; }
+        }
+
+		/**
+        * return the generator - g
+        */
+        public BigInteger G
+        {
+            get { return g; }
+        }
+
+		/**
+		 * return private value limit - l
+		 */
+		public int L
+		{
+			get { return l; }
+		}
+
+		public override bool Equals(
+            object obj)
+        {
+			if (obj == this)
+				return true;
+
+			ElGamalParameters other = obj as ElGamalParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			ElGamalParameters other)
+		{
+			return p.Equals(other.p) && g.Equals(other.g) && l == other.l;
+		}
+
+		public override int GetHashCode()
+        {
+            return p.GetHashCode() ^ g.GetHashCode() ^ l;
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/ElGamalPrivateKeyParameters.cs b/crypto/src/crypto/parameters/ElGamalPrivateKeyParameters.cs
new file mode 100644
index 000000000..6363f2bbb
--- /dev/null
+++ b/crypto/src/crypto/parameters/ElGamalPrivateKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ElGamalPrivateKeyParameters
+		: ElGamalKeyParameters
+    {
+        private readonly BigInteger x;
+
+		public ElGamalPrivateKeyParameters(
+            BigInteger			x,
+            ElGamalParameters	parameters)
+			: base(true, parameters)
+        {
+			if (x == null)
+				throw new ArgumentNullException("x");
+
+			this.x = x;
+        }
+
+		public BigInteger X
+        {
+            get { return x; }
+        }
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			ElGamalPrivateKeyParameters other = obj as ElGamalPrivateKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+		}
+
+		protected bool Equals(
+			ElGamalPrivateKeyParameters other)
+		{
+			return other.x.Equals(x) && base.Equals(other);
+		}
+
+		public override int GetHashCode()
+		{
+			return x.GetHashCode() ^ base.GetHashCode();
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/ElGamalPublicKeyParameters.cs b/crypto/src/crypto/parameters/ElGamalPublicKeyParameters.cs
new file mode 100644
index 000000000..25ac625d5
--- /dev/null
+++ b/crypto/src/crypto/parameters/ElGamalPublicKeyParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ElGamalPublicKeyParameters
+		: ElGamalKeyParameters
+    {
+        private readonly BigInteger y;
+
+		public ElGamalPublicKeyParameters(
+            BigInteger			y,
+            ElGamalParameters	parameters)
+			: base(false, parameters)
+        {
+			if (y == null)
+				throw new ArgumentNullException("y");
+
+			this.y = y;
+        }
+
+		public BigInteger Y
+        {
+            get { return y; }
+        }
+
+		public override bool Equals(
+            object obj)
+        {
+			if (obj == this)
+				return true;
+
+			ElGamalPublicKeyParameters other = obj as ElGamalPublicKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			ElGamalPublicKeyParameters other)
+		{
+			return y.Equals(other.y) && base.Equals(other);
+		}
+
+		public override int GetHashCode()
+        {
+			return y.GetHashCode() ^ base.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/GOST3410KeyGenerationParameters.cs b/crypto/src/crypto/parameters/GOST3410KeyGenerationParameters.cs
new file mode 100644
index 000000000..b06a5d896
--- /dev/null
+++ b/crypto/src/crypto/parameters/GOST3410KeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class Gost3410KeyGenerationParameters
+		: KeyGenerationParameters
+	{
+		private readonly Gost3410Parameters parameters;
+		private readonly DerObjectIdentifier publicKeyParamSet;
+
+		public Gost3410KeyGenerationParameters(
+			SecureRandom random,
+			Gost3410Parameters parameters)
+			: base(random, parameters.P.BitLength - 1)
+		{
+			this.parameters = parameters;
+		}
+
+		public Gost3410KeyGenerationParameters(
+			SecureRandom		random,
+			DerObjectIdentifier	publicKeyParamSet)
+			: this(random, LookupParameters(publicKeyParamSet))
+		{
+			this.publicKeyParamSet = publicKeyParamSet;
+		}
+
+		public Gost3410Parameters Parameters
+		{
+			get { return parameters; }
+		}
+
+		public DerObjectIdentifier PublicKeyParamSet
+		{
+			get { return publicKeyParamSet; }
+		}
+
+		private static Gost3410Parameters LookupParameters(
+			DerObjectIdentifier publicKeyParamSet)
+		{
+			if (publicKeyParamSet == null)
+				throw new ArgumentNullException("publicKeyParamSet");
+
+			Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet);
+
+			if (p == null)
+				throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+			return new Gost3410Parameters(p.P, p.Q, p.A);
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/GOST3410KeyParameters.cs b/crypto/src/crypto/parameters/GOST3410KeyParameters.cs
new file mode 100644
index 000000000..f771c4d97
--- /dev/null
+++ b/crypto/src/crypto/parameters/GOST3410KeyParameters.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public abstract class Gost3410KeyParameters
+		: AsymmetricKeyParameter
+	{
+		private readonly Gost3410Parameters parameters;
+		private readonly DerObjectIdentifier publicKeyParamSet;
+
+		protected Gost3410KeyParameters(
+			bool				isPrivate,
+			Gost3410Parameters	parameters)
+			: base(isPrivate)
+		{
+			this.parameters = parameters;
+		}
+
+		protected Gost3410KeyParameters(
+			bool				isPrivate,
+			DerObjectIdentifier	publicKeyParamSet)
+			: base(isPrivate)
+		{
+			this.parameters = LookupParameters(publicKeyParamSet);
+			this.publicKeyParamSet = publicKeyParamSet;
+		}
+
+		public Gost3410Parameters Parameters
+		{
+			get { return parameters; }
+		}
+
+		public DerObjectIdentifier PublicKeyParamSet
+		{
+			get { return publicKeyParamSet; }
+		}
+
+		// TODO Implement Equals/GetHashCode
+
+		private static Gost3410Parameters LookupParameters(
+			DerObjectIdentifier publicKeyParamSet)
+		{
+			if (publicKeyParamSet == null)
+				throw new ArgumentNullException("publicKeyParamSet");
+
+			Gost3410ParamSetParameters p = Gost3410NamedParameters.GetByOid(publicKeyParamSet);
+
+			if (p == null)
+				throw new ArgumentException("OID is not a valid CryptoPro public key parameter set", "publicKeyParamSet");
+
+			return new Gost3410Parameters(p.P, p.Q, p.A);
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/GOST3410Parameters.cs b/crypto/src/crypto/parameters/GOST3410Parameters.cs
new file mode 100644
index 000000000..2ec167ef0
--- /dev/null
+++ b/crypto/src/crypto/parameters/GOST3410Parameters.cs
@@ -0,0 +1,86 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class Gost3410Parameters
+		: ICipherParameters
+	{
+		private readonly BigInteger p, q, a;
+		private readonly Gost3410ValidationParameters validation;
+
+		public Gost3410Parameters(
+			BigInteger	p,
+			BigInteger	q,
+			BigInteger	a)
+			: this(p, q, a, null)
+		{
+		}
+
+		public Gost3410Parameters(
+			BigInteger						p,
+			BigInteger						q,
+			BigInteger						a,
+			Gost3410ValidationParameters	validation)
+		{
+			if (p == null)
+				throw new ArgumentNullException("p");
+			if (q == null)
+				throw new ArgumentNullException("q");
+			if (a == null)
+				throw new ArgumentNullException("a");
+
+			this.p = p;
+			this.q = q;
+			this.a = a;
+			this.validation = validation;
+		}
+
+		public BigInteger P
+		{
+			get { return p; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q; }
+		}
+
+		public BigInteger A
+		{
+			get { return a; }
+		}
+
+		public Gost3410ValidationParameters ValidationParameters
+		{
+			get { return validation; }
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			Gost3410Parameters other = obj as Gost3410Parameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+		}
+
+		protected bool Equals(
+			Gost3410Parameters other)
+		{
+			return p.Equals(other.p) && q.Equals(other.q) && a.Equals(other.a);
+		}
+
+		public override int GetHashCode()
+		{
+			return p.GetHashCode() ^ q.GetHashCode() ^ a.GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/GOST3410PrivateKeyParameters.cs b/crypto/src/crypto/parameters/GOST3410PrivateKeyParameters.cs
new file mode 100644
index 000000000..e3a613de6
--- /dev/null
+++ b/crypto/src/crypto/parameters/GOST3410PrivateKeyParameters.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class Gost3410PrivateKeyParameters
+		: Gost3410KeyParameters
+	{
+		private readonly BigInteger x;
+
+		public Gost3410PrivateKeyParameters(
+			BigInteger			x,
+			Gost3410Parameters	parameters)
+			: base(true, parameters)
+		{
+			if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0)
+				throw new ArgumentException("Invalid x for GOST3410 private key", "x");
+
+			this.x = x;
+		}
+
+		public Gost3410PrivateKeyParameters(
+			BigInteger			x,
+			DerObjectIdentifier	publicKeyParamSet)
+			: base(true, publicKeyParamSet)
+		{
+			if (x.SignValue < 1 || x.BitLength > 256 || x.CompareTo(Parameters.Q) >= 0)
+				throw new ArgumentException("Invalid x for GOST3410 private key", "x");
+
+			this.x = x;
+		}
+
+		public BigInteger X
+		{
+			get { return x; }
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/GOST3410PublicKeyParameters.cs b/crypto/src/crypto/parameters/GOST3410PublicKeyParameters.cs
new file mode 100644
index 000000000..96b7e91ea
--- /dev/null
+++ b/crypto/src/crypto/parameters/GOST3410PublicKeyParameters.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class Gost3410PublicKeyParameters
+		: Gost3410KeyParameters
+	{
+		private readonly BigInteger y;
+
+		public Gost3410PublicKeyParameters(
+			BigInteger y,
+			Gost3410Parameters parameters)
+			: base(false, parameters)
+		{
+			if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0)
+				throw new ArgumentException("Invalid y for GOST3410 public key", "y");
+
+			this.y = y;
+		}
+
+		public Gost3410PublicKeyParameters(
+			BigInteger			y,
+			DerObjectIdentifier publicKeyParamSet)
+			: base(false, publicKeyParamSet)
+		{
+			if (y.SignValue < 1 || y.CompareTo(Parameters.P) >= 0)
+				throw new ArgumentException("Invalid y for GOST3410 public key", "y");
+
+			this.y = y;
+		}
+
+		public BigInteger Y
+		{
+			get { return y; }
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/GOST3410ValidationParameters.cs b/crypto/src/crypto/parameters/GOST3410ValidationParameters.cs
new file mode 100644
index 000000000..21e5af823
--- /dev/null
+++ b/crypto/src/crypto/parameters/GOST3410ValidationParameters.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class Gost3410ValidationParameters
+	{
+		private int x0;
+		private int c;
+		private long x0L;
+		private long cL;
+
+		public Gost3410ValidationParameters(
+			int x0,
+			int c)
+		{
+			this.x0 = x0;
+			this.c = c;
+		}
+
+		public Gost3410ValidationParameters(
+			long x0L,
+			long cL)
+		{
+			this.x0L = x0L;
+			this.cL = cL;
+		}
+
+		public int C { get { return c; } }
+		public int X0 { get { return x0; } }
+		public long CL { get { return cL; } }
+		public long X0L { get { return x0L; } }
+
+		public override bool Equals(
+			object obj)
+		{
+			Gost3410ValidationParameters other = obj as Gost3410ValidationParameters;
+
+			return other != null
+				&& other.c == this.c
+				&& other.x0 == this.x0
+				&& other.cL == this.cL
+				&& other.x0L == this.x0L;
+		}
+
+		public override int GetHashCode()
+		{
+			return c.GetHashCode() ^ x0.GetHashCode() ^ cL.GetHashCode() ^ x0L.GetHashCode();
+		}
+
+	}
+}
diff --git a/crypto/src/crypto/parameters/ISO18033KDFParameters.cs b/crypto/src/crypto/parameters/ISO18033KDFParameters.cs
new file mode 100644
index 000000000..2d8fff8e3
--- /dev/null
+++ b/crypto/src/crypto/parameters/ISO18033KDFParameters.cs
@@ -0,0 +1,25 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	/**
+	* parameters for Key derivation functions for ISO-18033
+	*/
+	public class Iso18033KdfParameters
+		: IDerivationParameters
+	{
+		byte[]  seed;
+
+		public Iso18033KdfParameters(
+			byte[]  seed)
+		{
+			this.seed = seed;
+		}
+
+		public byte[] GetSeed()
+		{
+			return seed;
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/IesParameters.cs b/crypto/src/crypto/parameters/IesParameters.cs
new file mode 100644
index 000000000..d306b2c33
--- /dev/null
+++ b/crypto/src/crypto/parameters/IesParameters.cs
@@ -0,0 +1,49 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    /**
+     * parameters for using an integrated cipher in stream mode.
+     */
+    public class IesParameters : ICipherParameters
+    {
+        private byte[]  derivation;
+        private byte[]  encoding;
+        private int     macKeySize;
+
+        /**
+         * @param derivation the derivation parameter for the KDF function.
+         * @param encoding the encoding parameter for the KDF function.
+         * @param macKeySize the size of the MAC key (in bits).
+         */
+        public IesParameters(
+            byte[]  derivation,
+            byte[]  encoding,
+            int     macKeySize)
+        {
+            this.derivation = derivation;
+            this.encoding = encoding;
+            this.macKeySize = macKeySize;
+        }
+
+        public byte[] GetDerivationV()
+        {
+            return derivation;
+        }
+
+        public byte[] GetEncodingV()
+        {
+            return encoding;
+        }
+
+        public int MacKeySize
+        {
+			get
+			{
+				return macKeySize;
+			}
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/parameters/IesWithCipherParameters.cs b/crypto/src/crypto/parameters/IesWithCipherParameters.cs
new file mode 100644
index 000000000..70ef55d54
--- /dev/null
+++ b/crypto/src/crypto/parameters/IesWithCipherParameters.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class IesWithCipherParameters : IesParameters
+    {
+        private int cipherKeySize;
+
+        /**
+         * @param derivation the derivation parameter for the KDF function.
+         * @param encoding the encoding parameter for the KDF function.
+         * @param macKeySize the size of the MAC key (in bits).
+         * @param cipherKeySize the size of the associated Cipher key (in bits).
+         */
+        public IesWithCipherParameters(
+            byte[]  derivation,
+            byte[]  encoding,
+            int     macKeySize,
+            int     cipherKeySize) : base(derivation, encoding, macKeySize)
+        {
+            this.cipherKeySize = cipherKeySize;
+        }
+
+        public int CipherKeySize
+        {
+            get
+            {
+                return cipherKeySize;
+            }
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/parameters/KdfParameters.cs b/crypto/src/crypto/parameters/KdfParameters.cs
new file mode 100644
index 000000000..bc5c905d0
--- /dev/null
+++ b/crypto/src/crypto/parameters/KdfParameters.cs
@@ -0,0 +1,33 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    /**
+     * parameters for Key derivation functions for IEEE P1363a
+     */
+    public class KdfParameters : IDerivationParameters
+    {
+        byte[]  iv;
+        byte[]  shared;
+
+        public KdfParameters(
+            byte[]  shared,
+            byte[]  iv)
+        {
+            this.shared = shared;
+            this.iv = iv;
+        }
+
+        public byte[] GetSharedSecret()
+        {
+            return shared;
+        }
+
+        public byte[] GetIV()
+        {
+            return iv;
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/parameters/KeyParameter.cs b/crypto/src/crypto/parameters/KeyParameter.cs
new file mode 100644
index 000000000..33dff96d7
--- /dev/null
+++ b/crypto/src/crypto/parameters/KeyParameter.cs
@@ -0,0 +1,43 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class KeyParameter
+		: ICipherParameters
+    {
+        private readonly byte[] key;
+
+		public KeyParameter(
+			byte[] key)
+		{
+			if (key == null)
+				throw new ArgumentNullException("key");
+
+			this.key = (byte[]) key.Clone();
+		}
+
+		public KeyParameter(
+            byte[]	key,
+            int		keyOff,
+            int		keyLen)
+        {
+			if (key == null)
+				throw new ArgumentNullException("key");
+			if (keyOff < 0 || keyOff > key.Length)
+				throw new ArgumentOutOfRangeException("keyOff");
+			if (keyLen < 0 || (keyOff + keyLen) > key.Length)
+				throw new ArgumentOutOfRangeException("keyLen");
+
+			this.key = new byte[keyLen];
+            Array.Copy(key, keyOff, this.key, 0, keyLen);
+        }
+
+		public byte[] GetKey()
+        {
+			return (byte[]) key.Clone();
+        }
+    }
+
+}
diff --git a/crypto/src/crypto/parameters/MgfParameters.cs b/crypto/src/crypto/parameters/MgfParameters.cs
new file mode 100644
index 000000000..11983b877
--- /dev/null
+++ b/crypto/src/crypto/parameters/MgfParameters.cs
@@ -0,0 +1,31 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	/// <remarks>Parameters for mask derivation functions.</remarks>
+    public class MgfParameters
+		: IDerivationParameters
+    {
+        private readonly byte[] seed;
+
+		public MgfParameters(
+            byte[] seed)
+			: this(seed, 0, seed.Length)
+        {
+        }
+
+		public MgfParameters(
+            byte[]  seed,
+            int     off,
+            int     len)
+        {
+            this.seed = new byte[len];
+            Array.Copy(seed, off, this.seed, 0, len);
+        }
+
+		public byte[] GetSeed()
+        {
+            return (byte[]) seed.Clone();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/MqvPrivateParameters.cs b/crypto/src/crypto/parameters/MqvPrivateParameters.cs
new file mode 100644
index 000000000..4bf33e347
--- /dev/null
+++ b/crypto/src/crypto/parameters/MqvPrivateParameters.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class MqvPrivateParameters
+		: ICipherParameters
+	{
+		private readonly ECPrivateKeyParameters staticPrivateKey;
+		private readonly ECPrivateKeyParameters ephemeralPrivateKey;
+		private readonly ECPublicKeyParameters ephemeralPublicKey;
+		
+		public MqvPrivateParameters(
+			ECPrivateKeyParameters	staticPrivateKey,
+			ECPrivateKeyParameters	ephemeralPrivateKey)
+			: this(staticPrivateKey, ephemeralPrivateKey, null)
+		{
+		}
+
+		public MqvPrivateParameters(
+			ECPrivateKeyParameters	staticPrivateKey,
+			ECPrivateKeyParameters	ephemeralPrivateKey,
+			ECPublicKeyParameters	ephemeralPublicKey)
+		{
+			this.staticPrivateKey = staticPrivateKey;
+			this.ephemeralPrivateKey = ephemeralPrivateKey;
+			this.ephemeralPublicKey = ephemeralPublicKey;
+		}
+
+		public ECPrivateKeyParameters StaticPrivateKey
+		{
+			get { return staticPrivateKey; }
+		}
+
+		public ECPrivateKeyParameters EphemeralPrivateKey
+		{
+			get { return ephemeralPrivateKey; }
+		}
+
+		public ECPublicKeyParameters EphemeralPublicKey
+		{
+			get { return ephemeralPublicKey; }
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/MqvPublicParameters.cs b/crypto/src/crypto/parameters/MqvPublicParameters.cs
new file mode 100644
index 000000000..a0e273ac4
--- /dev/null
+++ b/crypto/src/crypto/parameters/MqvPublicParameters.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class MqvPublicParameters
+		: ICipherParameters
+	{
+		private readonly ECPublicKeyParameters staticPublicKey;
+		private readonly ECPublicKeyParameters ephemeralPublicKey;
+
+		public MqvPublicParameters(
+			ECPublicKeyParameters	staticPublicKey,
+			ECPublicKeyParameters	ephemeralPublicKey)
+		{
+			this.staticPublicKey = staticPublicKey;
+			this.ephemeralPublicKey = ephemeralPublicKey;
+		}
+
+		public ECPublicKeyParameters StaticPublicKey
+		{
+			get { return staticPublicKey; }
+		}
+
+		public ECPublicKeyParameters EphemeralPublicKey
+		{
+			get { return ephemeralPublicKey; }
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/NaccacheSternKeyGenerationParameters.cs b/crypto/src/crypto/parameters/NaccacheSternKeyGenerationParameters.cs
new file mode 100644
index 000000000..5b4052505
--- /dev/null
+++ b/crypto/src/crypto/parameters/NaccacheSternKeyGenerationParameters.cs
@@ -0,0 +1,101 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	/**
+	 * Parameters for NaccacheStern public private key generation. For details on
+	 * this cipher, please see
+	 *
+	 * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+	 */
+	public class NaccacheSternKeyGenerationParameters : KeyGenerationParameters
+	{
+		// private BigInteger publicExponent;
+		private readonly int certainty;
+		private readonly int countSmallPrimes;
+		private bool debug;
+
+		/**
+		 * Parameters for generating a NaccacheStern KeyPair.
+		 *
+		 * @param random
+		 *            The source of randomness
+		 * @param strength
+		 *            The desired strength of the Key in Bits
+		 * @param certainty
+		 *            the probability that the generated primes are not really prime
+		 *            as integer: 2^(-certainty) is then the probability
+		 * @param countSmallPrimes
+		 *            How many small key factors are desired
+		 */
+		public NaccacheSternKeyGenerationParameters(
+			SecureRandom	random,
+			int				strength,
+			int				certainty,
+			int				countSmallPrimes)
+			: this(random, strength, certainty, countSmallPrimes, false)
+		{
+		}
+
+		/**
+		 * Parameters for a NaccacheStern KeyPair.
+		 *
+		 * @param random
+		 *            The source of randomness
+		 * @param strength
+		 *            The desired strength of the Key in Bits
+		 * @param certainty
+		 *            the probability that the generated primes are not really prime
+		 *            as integer: 2^(-certainty) is then the probability
+		 * @param cntSmallPrimes
+		 *            How many small key factors are desired
+		 * @param debug
+		 *            Turn debugging on or off (reveals secret information, use with
+		 *            caution)
+		 */
+		public NaccacheSternKeyGenerationParameters(SecureRandom random,
+			int		strength,
+			int		certainty,
+			int		countSmallPrimes,
+			bool	debug)
+			: base(random, strength)
+		{
+			if (countSmallPrimes % 2 == 1)
+			{
+				throw new ArgumentException("countSmallPrimes must be a multiple of 2");
+			}
+			if (countSmallPrimes < 30)
+			{
+				throw new ArgumentException("countSmallPrimes must be >= 30 for security reasons");
+			}
+			this.certainty = certainty;
+			this.countSmallPrimes = countSmallPrimes;
+			this.debug = debug;
+		}
+
+		/**
+		 * @return Returns the certainty.
+		 */
+		public int Certainty
+		{
+			get { return certainty; }
+		}
+
+		/**
+		 * @return Returns the countSmallPrimes.
+		 */
+		public int CountSmallPrimes
+		{
+			get { return countSmallPrimes; }
+		}
+
+		public bool IsDebug
+		{
+			get { return debug; }
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/NaccacheSternKeyParameters.cs b/crypto/src/crypto/parameters/NaccacheSternKeyParameters.cs
new file mode 100644
index 000000000..8be7ad835
--- /dev/null
+++ b/crypto/src/crypto/parameters/NaccacheSternKeyParameters.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	/**
+	 * Public key parameters for NaccacheStern cipher. For details on this cipher,
+	 * please see
+	 *
+	 * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+	 */
+	public class NaccacheSternKeyParameters : AsymmetricKeyParameter
+	{
+		private readonly BigInteger g, n;
+		private readonly int lowerSigmaBound;
+
+		/**
+		 * @param privateKey
+		 */
+		public NaccacheSternKeyParameters(bool privateKey, BigInteger g, BigInteger n, int lowerSigmaBound)
+			: base(privateKey)
+		{
+			this.g = g;
+			this.n = n;
+			this.lowerSigmaBound = lowerSigmaBound;
+		}
+
+		/**
+		 * @return Returns the g.
+		 */
+		public BigInteger G { get  { return g; } }
+
+		/**
+		 * @return Returns the lowerSigmaBound.
+		 */
+		public int LowerSigmaBound { get { return lowerSigmaBound; } }
+
+		/**
+		 * @return Returns the n.
+		 */
+		public BigInteger Modulus { get { return n; } }
+	}
+}
diff --git a/crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs b/crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
index 42a0454a1..0e1fe14b7 100644
--- a/crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
+++ b/crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
@@ -16,7 +16,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		private readonly BigInteger phiN;
 		private readonly IList smallPrimes;
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete]
         public NaccacheSternPrivateKeyParameters(
             BigInteger g,
@@ -63,7 +63,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 			get { return phiN; }
 		}
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete("Use 'SmallPrimesList' instead")]
         public ArrayList SmallPrimes
 		{
diff --git a/crypto/src/crypto/parameters/ParametersWithIV.cs b/crypto/src/crypto/parameters/ParametersWithIV.cs
index e00abce58..11a8b77a0 100644
--- a/crypto/src/crypto/parameters/ParametersWithIV.cs
+++ b/crypto/src/crypto/parameters/ParametersWithIV.cs
@@ -21,8 +21,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
             int					ivOff,
             int					ivLen)
         {
-			if (parameters == null)
-				throw new ArgumentNullException("parameters");
+            // NOTE: 'parameters' may be null to imply key re-use
 			if (iv == null)
 				throw new ArgumentNullException("iv");
 
diff --git a/crypto/src/crypto/parameters/ParametersWithRandom.cs b/crypto/src/crypto/parameters/ParametersWithRandom.cs
new file mode 100644
index 000000000..a05e77409
--- /dev/null
+++ b/crypto/src/crypto/parameters/ParametersWithRandom.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ParametersWithRandom
+		: ICipherParameters
+    {
+        private readonly ICipherParameters	parameters;
+		private readonly SecureRandom		random;
+
+		public ParametersWithRandom(
+            ICipherParameters	parameters,
+            SecureRandom		random)
+        {
+			if (parameters == null)
+				throw new ArgumentNullException("random");
+			if (random == null)
+				throw new ArgumentNullException("random");
+
+			this.parameters = parameters;
+			this.random = random;
+		}
+
+		public ParametersWithRandom(
+            ICipherParameters parameters)
+			: this(parameters, new SecureRandom())
+        {
+		}
+
+		[Obsolete("Use Random property instead")]
+		public SecureRandom GetRandom()
+		{
+			return Random;
+		}
+
+		public SecureRandom Random
+        {
+			get { return random; }
+        }
+
+		public ICipherParameters Parameters
+        {
+            get { return parameters; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/ParametersWithSBox.cs b/crypto/src/crypto/parameters/ParametersWithSBox.cs
new file mode 100644
index 000000000..6473796e3
--- /dev/null
+++ b/crypto/src/crypto/parameters/ParametersWithSBox.cs
@@ -0,0 +1,24 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class ParametersWithSBox : ICipherParameters
+	{
+		private ICipherParameters  parameters;
+		private byte[] sBox;
+
+		public ParametersWithSBox(
+			ICipherParameters parameters,
+			byte[] sBox)
+		{
+			this.parameters = parameters;
+			this.sBox = sBox;
+		}
+
+		public byte[] GetSBox() { return sBox; }
+
+		public ICipherParameters Parameters { get { return parameters; } }
+	}
+}
diff --git a/crypto/src/crypto/parameters/ParametersWithSalt.cs b/crypto/src/crypto/parameters/ParametersWithSalt.cs
new file mode 100644
index 000000000..7f4cd6cd1
--- /dev/null
+++ b/crypto/src/crypto/parameters/ParametersWithSalt.cs
@@ -0,0 +1,39 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+    /// <summary> Cipher parameters with a fixed salt value associated with them.</summary>
+    public class ParametersWithSalt : ICipherParameters
+    {
+        private byte[] salt;
+        private ICipherParameters parameters;
+
+        public ParametersWithSalt(ICipherParameters parameters, byte[] salt):this(parameters, salt, 0, salt.Length)
+        {
+        }
+
+        public ParametersWithSalt(ICipherParameters parameters, byte[] salt, int saltOff, int saltLen)
+        {
+            this.salt = new byte[saltLen];
+            this.parameters = parameters;
+
+            Array.Copy(salt, saltOff, this.salt, 0, saltLen);
+        }
+
+        public byte[] GetSalt()
+        {
+            return salt;
+        }
+
+        public ICipherParameters Parameters
+        {
+            get
+            {
+                return parameters;
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/RC2Parameters.cs b/crypto/src/crypto/parameters/RC2Parameters.cs
new file mode 100644
index 000000000..7a6d5bb6e
--- /dev/null
+++ b/crypto/src/crypto/parameters/RC2Parameters.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class RC2Parameters
+		: KeyParameter
+	{
+		private readonly int bits;
+
+		public RC2Parameters(
+			byte[] key)
+			: this(key, (key.Length > 128) ? 1024 : (key.Length * 8))
+		{
+		}
+
+		public RC2Parameters(
+			byte[]	key,
+			int		keyOff,
+			int		keyLen)
+			: this(key, keyOff, keyLen, (keyLen > 128) ? 1024 : (keyLen * 8))
+		{
+		}
+
+		public RC2Parameters(
+			byte[]	key,
+			int		bits)
+			: base(key)
+		{
+			this.bits = bits;
+		}
+
+		public RC2Parameters(
+			byte[]	key,
+			int		keyOff,
+			int		keyLen,
+			int		bits)
+			: base(key, keyOff, keyLen)
+		{
+			this.bits = bits;
+		}
+
+		public int EffectiveKeyBits
+		{
+			get { return bits; }
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/RC5Parameters.cs b/crypto/src/crypto/parameters/RC5Parameters.cs
new file mode 100644
index 000000000..88a59e197
--- /dev/null
+++ b/crypto/src/crypto/parameters/RC5Parameters.cs
@@ -0,0 +1,27 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class RC5Parameters
+		: KeyParameter
+    {
+        private readonly int rounds;
+
+		public RC5Parameters(
+            byte[]	key,
+            int		rounds)
+			: base(key)
+        {
+            if (key.Length > 255)
+                throw new ArgumentException("RC5 key length can be no greater than 255");
+
+			this.rounds = rounds;
+        }
+
+		public int Rounds
+        {
+			get { return rounds; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/RSABlindingParameters.cs b/crypto/src/crypto/parameters/RSABlindingParameters.cs
new file mode 100644
index 000000000..49c7bcce6
--- /dev/null
+++ b/crypto/src/crypto/parameters/RSABlindingParameters.cs
@@ -0,0 +1,34 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class RsaBlindingParameters
+		: ICipherParameters
+	{
+		private readonly RsaKeyParameters	publicKey;
+		private readonly BigInteger			blindingFactor;
+
+		public RsaBlindingParameters(
+			RsaKeyParameters	publicKey,
+			BigInteger			blindingFactor)
+		{
+			if (publicKey.IsPrivate)
+				throw new ArgumentException("RSA parameters should be for a public key");
+
+			this.publicKey = publicKey;
+			this.blindingFactor = blindingFactor;
+		}
+
+		public RsaKeyParameters PublicKey
+		{
+			get { return publicKey; }
+		}
+
+		public BigInteger BlindingFactor
+		{
+			get { return blindingFactor; }
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/RsaKeyGenerationParameters.cs b/crypto/src/crypto/parameters/RsaKeyGenerationParameters.cs
new file mode 100644
index 000000000..619ab65b4
--- /dev/null
+++ b/crypto/src/crypto/parameters/RsaKeyGenerationParameters.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class RsaKeyGenerationParameters
+		: KeyGenerationParameters
+    {
+        private readonly BigInteger publicExponent;
+        private readonly int certainty;
+
+		public RsaKeyGenerationParameters(
+            BigInteger		publicExponent,
+            SecureRandom	random,
+            int				strength,
+            int				certainty)
+			: base(random, strength)
+        {
+            this.publicExponent = publicExponent;
+            this.certainty = certainty;
+        }
+
+		public BigInteger PublicExponent
+        {
+			get { return publicExponent; }
+        }
+
+		public int Certainty
+        {
+			get { return certainty; }
+        }
+
+		public override bool Equals(
+			object obj)
+		{
+			RsaKeyGenerationParameters other = obj as RsaKeyGenerationParameters;
+
+			if (other == null)
+			{
+				return false;
+			}
+
+			return certainty == other.certainty
+				&& publicExponent.Equals(other.publicExponent);
+		}
+
+		public override int GetHashCode()
+		{
+			return certainty.GetHashCode() ^ publicExponent.GetHashCode();
+		}
+    }
+}
diff --git a/crypto/src/crypto/parameters/RsaKeyParameters.cs b/crypto/src/crypto/parameters/RsaKeyParameters.cs
new file mode 100644
index 000000000..72c0d806f
--- /dev/null
+++ b/crypto/src/crypto/parameters/RsaKeyParameters.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class RsaKeyParameters
+		: AsymmetricKeyParameter
+    {
+        private readonly BigInteger modulus;
+        private readonly BigInteger exponent;
+
+		public RsaKeyParameters(
+            bool		isPrivate,
+            BigInteger	modulus,
+            BigInteger	exponent)
+			: base(isPrivate)
+        {
+			if (modulus == null)
+				throw new ArgumentNullException("modulus");
+			if (exponent == null)
+				throw new ArgumentNullException("exponent");
+			if (modulus.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA modulus", "modulus");
+			if (exponent.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA exponent", "exponent");
+
+			this.modulus = modulus;
+			this.exponent = exponent;
+        }
+
+		public BigInteger Modulus
+        {
+            get { return modulus; }
+        }
+
+		public BigInteger Exponent
+        {
+            get { return exponent; }
+        }
+
+		public override bool Equals(
+			object obj)
+        {
+            RsaKeyParameters kp = obj as RsaKeyParameters;
+
+			if (kp == null)
+			{
+				return false;
+			}
+
+			return kp.IsPrivate == this.IsPrivate
+				&& kp.Modulus.Equals(this.modulus)
+				&& kp.Exponent.Equals(this.exponent);
+        }
+
+		public override int GetHashCode()
+        {
+            return modulus.GetHashCode() ^ exponent.GetHashCode() ^ IsPrivate.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs b/crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs
new file mode 100644
index 000000000..7bd8abd76
--- /dev/null
+++ b/crypto/src/crypto/parameters/RsaPrivateCrtKeyParameters.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class RsaPrivateCrtKeyParameters
+		: RsaKeyParameters
+    {
+        private readonly BigInteger e, p, q, dP, dQ, qInv;
+
+		public RsaPrivateCrtKeyParameters(
+            BigInteger	modulus,
+            BigInteger	publicExponent,
+            BigInteger	privateExponent,
+            BigInteger	p,
+            BigInteger	q,
+            BigInteger	dP,
+            BigInteger	dQ,
+            BigInteger	qInv)
+			: base(true, modulus, privateExponent)
+        {
+			ValidateValue(publicExponent, "publicExponent", "exponent");
+			ValidateValue(p, "p", "P value");
+			ValidateValue(q, "q", "Q value");
+			ValidateValue(dP, "dP", "DP value");
+			ValidateValue(dQ, "dQ", "DQ value");
+			ValidateValue(qInv, "qInv", "InverseQ value");
+
+			this.e = publicExponent;
+            this.p = p;
+            this.q = q;
+            this.dP = dP;
+            this.dQ = dQ;
+            this.qInv = qInv;
+        }
+
+		public BigInteger PublicExponent
+        {
+            get { return e; }
+		}
+
+		public BigInteger P
+		{
+			get { return p; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q; }
+		}
+
+		public BigInteger DP
+		{
+			get { return dP; }
+		}
+
+		public BigInteger DQ
+		{
+			get { return dQ; }
+		}
+
+		public BigInteger QInv
+		{
+			get { return qInv; }
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			RsaPrivateCrtKeyParameters kp = obj as RsaPrivateCrtKeyParameters;
+
+			if (kp == null)
+				return false;
+
+			return kp.DP.Equals(dP)
+				&& kp.DQ.Equals(dQ)
+				&& kp.Exponent.Equals(this.Exponent)
+				&& kp.Modulus.Equals(this.Modulus)
+				&& kp.P.Equals(p)
+				&& kp.Q.Equals(q)
+				&& kp.PublicExponent.Equals(e)
+				&& kp.QInv.Equals(qInv);
+		}
+
+		public override int GetHashCode()
+		{
+			return DP.GetHashCode() ^ DQ.GetHashCode() ^ Exponent.GetHashCode() ^ Modulus.GetHashCode()
+				^ P.GetHashCode() ^ Q.GetHashCode() ^ PublicExponent.GetHashCode() ^ QInv.GetHashCode();
+		}
+
+		private static void ValidateValue(BigInteger x, string name, string desc)
+		{
+			if (x == null)
+				throw new ArgumentNullException(name);
+			if (x.SignValue <= 0)
+				throw new ArgumentException("Not a valid RSA " + desc, name);
+		}
+	}
+}
diff --git a/crypto/src/crypto/parameters/SkeinParameters.cs b/crypto/src/crypto/parameters/SkeinParameters.cs
new file mode 100644
index 000000000..a4e3e8e2a
--- /dev/null
+++ b/crypto/src/crypto/parameters/SkeinParameters.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+	/// <summary>
+	/// Parameters for the Skein hash function - a series of byte[] strings identified by integer tags.
+	/// </summary>
+	/// <remarks>
+	/// Parameterised Skein can be used for:
+	/// <ul> 
+	/// <li>MAC generation, by providing a <see cref="SkeinParameters.Builder.SetKey(byte[])">key</see>.</li>
+	/// <li>Randomised hashing, by providing a <see cref="SkeinParameters.Builder.SetNonce(byte[])">nonce</see>.</li>
+	/// <li>A hash function for digital signatures, associating a
+	/// <see cref="SkeinParameters.Builder.SetPublicKey(byte[])">public key</see> with the message digest.</li>
+	/// <li>A key derivation function, by providing a
+	/// <see cref="SkeinParameters.Builder.SetKeyIdentifier(byte[])">key identifier</see>.</li>
+	/// <li>Personalised hashing, by providing a
+	/// <see cref="SkeinParameters.Builder.SetPersonalisation(DateTime,string,string)">recommended format</see> or
+	/// <see cref="SkeinParameters.Builder.SetPersonalisation(byte[])">arbitrary</see> personalisation string.</li>
+	/// </ul>
+	/// </remarks>
+	/// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinEngine"/>
+	/// <seealso cref="Org.BouncyCastle.Crypto.Digests.SkeinDigest"/>
+	/// <seealso cref="Org.BouncyCastle.Crypto.Macs.SkeinMac"/>
+	public class SkeinParameters
+		: ICipherParameters
+	{
+		/// <summary>
+		/// The parameter type for a secret key, supporting MAC or KDF functions: 0
+		/// </summary>
+		public const int PARAM_TYPE_KEY = 0;
+
+		/// <summary>
+		/// The parameter type for the Skein configuration block: 4
+		/// </summary>
+		public const int PARAM_TYPE_CONFIG = 4;
+
+		/// <summary>
+		/// The parameter type for a personalisation string: 8
+		/// </summary>
+		public const int PARAM_TYPE_PERSONALISATION = 8;
+
+		/// <summary>
+		/// The parameter type for a public key: 12
+		/// </summary>
+		public const int PARAM_TYPE_PUBLIC_KEY = 12;
+
+		/// <summary>
+		/// The parameter type for a key identifier string: 16
+		/// </summary>
+		public const int PARAM_TYPE_KEY_IDENTIFIER = 16;
+
+		/// <summary>
+		/// The parameter type for a nonce: 20
+		/// </summary>
+		public const int PARAM_TYPE_NONCE = 20;
+
+		/// <summary>
+		/// The parameter type for the message: 48
+		/// </summary>
+		public const int PARAM_TYPE_MESSAGE = 48;
+
+		/// <summary>
+		/// The parameter type for the output transformation: 63
+		/// </summary>
+		public const int PARAM_TYPE_OUTPUT = 63;
+
+		private IDictionary parameters;
+
+		public SkeinParameters()
+			: this(Platform.CreateHashtable())
+
+		{
+		}
+
+		private SkeinParameters(IDictionary parameters)
+		{
+			this.parameters = parameters;
+		}
+
+		/// <summary>
+		/// Obtains a map of type (int) to value (byte[]) for the parameters tracked in this object.
+		/// </summary>
+		public IDictionary GetParameters()
+		{
+			return parameters;
+		}
+
+		/// <summary>
+		/// Obtains the value of the <see cref="PARAM_TYPE_KEY">key parameter</see>, or <code>null</code> if not
+		/// set.
+		/// </summary>
+		/// <returns>The key.</returns>
+		public byte[] GetKey()
+		{
+			return (byte[])parameters[PARAM_TYPE_KEY];
+		}
+
+		/// <summary>
+		/// Obtains the value of the <see cref="PARAM_TYPE_PERSONALISATION">personalisation parameter</see>, or
+		/// <code>null</code> if not set.
+		/// </summary>
+		public byte[] GetPersonalisation()
+		{
+			return (byte[])parameters[PARAM_TYPE_PERSONALISATION];
+		}
+
+		/// <summary>
+		/// Obtains the value of the <see cref="PARAM_TYPE_PUBLIC_KEY">public key parameter</see>, or
+		/// <code>null</code> if not set.
+		/// </summary>
+		public byte[] GetPublicKey()
+		{
+			return (byte[])parameters[PARAM_TYPE_PUBLIC_KEY];
+		}
+
+		/// <summary>
+		/// Obtains the value of the <see cref="PARAM_TYPE_KEY_IDENTIFIER">key identifier parameter</see>, or
+		/// <code>null</code> if not set.
+		/// </summary>
+		public byte[] GetKeyIdentifier()
+		{
+			return (byte[])parameters[PARAM_TYPE_KEY_IDENTIFIER];
+		}
+
+		/// <summary>
+		/// Obtains the value of the <see cref="PARAM_TYPE_NONCE">nonce parameter</see>, or <code>null</code> if
+		/// not set.
+		/// </summary>
+		public byte[] GetNonce()
+		{
+			return (byte[])parameters[PARAM_TYPE_NONCE];
+		}
+
+		/// <summary>
+		/// A builder for <see cref="SkeinParameters"/>.
+		/// </summary>
+		public class Builder
+		{
+			private IDictionary parameters = Platform.CreateHashtable();
+
+			public Builder()
+			{
+			}
+
+			public Builder(IDictionary paramsMap)
+			{
+				IEnumerator keys = paramsMap.Keys.GetEnumerator();
+				while (keys.MoveNext())
+				{
+					int key = (int)keys.Current;
+					parameters.Add(key, paramsMap[key]);
+				}
+			}
+
+			public Builder(SkeinParameters parameters)
+			{
+				IEnumerator keys = parameters.parameters.Keys.GetEnumerator();
+				while (keys.MoveNext())
+				{
+					int key = (int)keys.Current;
+					this.parameters.Add(key, parameters.parameters[key]);
+				}
+			}
+
+			/// <summary>
+			/// Sets a parameters to apply to the Skein hash function.
+			/// </summary>
+			/// <remarks>
+			/// Parameter types must be in the range 0,5..62, and cannot use the value 48
+			/// (reserved for message body).
+			/// <p/>
+			/// Parameters with type &lt; 48 are processed before
+			/// the message content, parameters with type &gt; 48
+			/// are processed after the message and prior to output.
+			/// </remarks>
+			/// <param name="type">the type of the parameter, in the range 5..62.</param>
+			/// <param name="value">the byte sequence of the parameter.</param>
+			public Builder Set(int type, byte[] value)
+			{
+				if (value == null)
+				{
+					throw new ArgumentException("Parameter value must not be null.");
+				}
+				if ((type != PARAM_TYPE_KEY)
+				    && (type <= PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE))
+				{
+					throw new ArgumentException("Parameter types must be in the range 0,5..47,49..62.");
+				}
+				if (type == PARAM_TYPE_CONFIG)
+				{
+					throw new ArgumentException("Parameter type " + PARAM_TYPE_CONFIG
+					                            + " is reserved for internal use.");
+				}
+				this.parameters.Add(type, value);
+				return this;
+			}
+
+			/// <summary>
+			/// Sets the <see cref="SkeinParameters.PARAM_TYPE_KEY"/> parameter.
+			/// </summary>
+			public Builder SetKey(byte[] key)
+			{
+				return Set(PARAM_TYPE_KEY, key);
+			}
+
+			/// <summary>
+			/// Sets the <see cref="SkeinParameters.PARAM_TYPE_PERSONALISATION"/> parameter.
+			/// </summary>
+			public Builder SetPersonalisation(byte[] personalisation)
+			{
+				return Set(PARAM_TYPE_PERSONALISATION, personalisation);
+			}
+
+			/// <summary>
+			/// Implements the recommended personalisation format for Skein defined in Section 4.11 of
+			/// the Skein 1.3 specification.
+			/// </summary>
+			/// <remarks>
+			/// The format is <code>YYYYMMDD email@address distinguisher</code>, encoded to a byte
+			/// sequence using UTF-8 encoding.
+			/// </remarks>
+			/// <param name="date">the date the personalised application of the Skein was defined.</param>
+			/// <param name="emailAddress">the email address of the creation of the personalised application.</param>
+			/// <param name="distinguisher">an arbitrary personalisation string distinguishing the application.</param>
+			public Builder SetPersonalisation(DateTime date, string emailAddress, string distinguisher)
+			{
+				try
+				{
+					MemoryStream bout = new MemoryStream();
+					StreamWriter outBytes = new StreamWriter(bout, System.Text.Encoding.UTF8);
+					outBytes.Write(date.ToString("YYYYMMDD"));
+					outBytes.Write(" ");
+					outBytes.Write(emailAddress);
+					outBytes.Write(" ");
+					outBytes.Write(distinguisher);
+					outBytes.Close();
+					return Set(PARAM_TYPE_PERSONALISATION, bout.ToArray());
+				}
+				catch (IOException e)
+				{
+					throw new InvalidOperationException("Byte I/O failed.", e);
+				}
+			}
+
+			/// <summary>
+			/// Sets the <see cref="SkeinParameters.PARAM_TYPE_KEY_IDENTIFIER"/> parameter.
+			/// </summary>
+			public Builder SetPublicKey(byte[] publicKey)
+			{
+				return Set(PARAM_TYPE_PUBLIC_KEY, publicKey);
+			}
+
+			/// <summary>
+			/// Sets the <see cref="SkeinParameters.PARAM_TYPE_KEY_IDENTIFIER"/> parameter.
+			/// </summary>
+			public Builder SetKeyIdentifier(byte[] keyIdentifier)
+			{
+				return Set(PARAM_TYPE_KEY_IDENTIFIER, keyIdentifier);
+			}
+
+			/// <summary>
+			/// Sets the <see cref="SkeinParameters.PARAM_TYPE_NONCE"/> parameter.
+			/// </summary>
+			public Builder SetNonce(byte[] nonce)
+			{
+				return Set(PARAM_TYPE_NONCE, nonce);
+			}
+
+			/// <summary>
+			/// Constructs a new <see cref="SkeinParameters"/> instance with the parameters provided to this
+			/// builder.
+			/// </summary>
+			public SkeinParameters Build()
+			{
+				return new SkeinParameters(parameters);
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/parameters/TweakableBlockCipherParameters.cs b/crypto/src/crypto/parameters/TweakableBlockCipherParameters.cs
new file mode 100644
index 000000000..f75726600
--- /dev/null
+++ b/crypto/src/crypto/parameters/TweakableBlockCipherParameters.cs
@@ -0,0 +1,40 @@
+using System;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+
+	/// <summary>
+	/// Parameters for tweakable block ciphers.
+	/// </summary>
+	public class TweakableBlockCipherParameters
+		: ICipherParameters
+	{
+		private readonly byte[] tweak;
+		private readonly KeyParameter key;
+
+		public TweakableBlockCipherParameters(KeyParameter key, byte[] tweak)
+		{
+			this.key = key;
+			this.tweak = Arrays.Clone(tweak);
+		}
+
+		/// <summary>
+		/// Gets the key.
+		/// </summary>
+		/// <value>the key to use, or <code>null</code> to use the current key.</value>
+		public KeyParameter Key
+		{
+			get { return key; }
+		}
+
+		/// <summary>
+		/// Gets the tweak value.
+		/// </summary>
+		/// <value>The tweak to use, or <code>null</code> to use the current tweak.</value>
+		public byte[] Tweak
+		{
+			get { return tweak; }
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
index 9e9e29cf1..e1a0d4012 100644
--- a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
+++ b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
@@ -1,4 +1,4 @@
-#if !(NETCF_1_0 || PORTABLE)
+#if !NETCF_1_0
 
 using System;
 using System.Security.Cryptography;
diff --git a/crypto/src/crypto/prng/DigestRandomGenerator.cs b/crypto/src/crypto/prng/DigestRandomGenerator.cs
new file mode 100644
index 000000000..cbd2ef060
--- /dev/null
+++ b/crypto/src/crypto/prng/DigestRandomGenerator.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+	/**
+	 * Random generation based on the digest with counter. Calling AddSeedMaterial will
+	 * always increase the entropy of the hash.
+	 * <p>
+	 * Internal access to the digest is synchronized so a single one of these can be shared.
+	 * </p>
+	 */
+	public class DigestRandomGenerator
+		: IRandomGenerator
+	{
+		private const long CYCLE_COUNT = 10;
+
+		private long	stateCounter;
+		private long	seedCounter;
+		private IDigest	digest;
+		private byte[]	state;
+		private byte[]	seed;
+
+		public DigestRandomGenerator(
+			IDigest digest)
+		{
+			this.digest = digest;
+
+			this.seed = new byte[digest.GetDigestSize()];
+			this.seedCounter = 1;
+
+			this.state = new byte[digest.GetDigestSize()];
+			this.stateCounter = 1;
+		}
+
+		public void AddSeedMaterial(
+			byte[] inSeed)
+		{
+			lock (this)
+			{
+				DigestUpdate(inSeed);
+				DigestUpdate(seed);
+				DigestDoFinal(seed);
+			}
+		}
+
+		public void AddSeedMaterial(
+			long rSeed)
+		{
+			lock (this)
+			{
+				DigestAddCounter(rSeed);
+				DigestUpdate(seed);
+				DigestDoFinal(seed);
+			}
+		}
+
+		public void NextBytes(
+			byte[] bytes)
+		{
+			NextBytes(bytes, 0, bytes.Length);
+		}
+
+		public void NextBytes(
+			byte[]	bytes,
+			int		start,
+			int		len)
+		{
+			lock (this)
+			{
+				int stateOff = 0;
+
+				GenerateState();
+
+				int end = start + len;
+				for (int i = start; i < end; ++i)
+				{
+					if (stateOff == state.Length)
+					{
+						GenerateState();
+						stateOff = 0;
+					}
+					bytes[i] = state[stateOff++];
+				}
+			}
+		}
+
+		private void CycleSeed()
+		{
+			DigestUpdate(seed);
+			DigestAddCounter(seedCounter++);
+			DigestDoFinal(seed);
+		}
+
+		private void GenerateState()
+		{
+			DigestAddCounter(stateCounter++);
+			DigestUpdate(state);
+			DigestUpdate(seed);
+			DigestDoFinal(state);
+
+			if ((stateCounter % CYCLE_COUNT) == 0)
+			{
+				CycleSeed();
+			}
+		}
+
+		private void DigestAddCounter(long seedVal)
+		{
+			ulong seed = (ulong)seedVal;
+			for (int i = 0; i != 8; i++)
+			{
+				digest.Update((byte)seed);
+				seed >>= 8;
+			}
+		}
+
+		private void DigestUpdate(byte[] inSeed)
+		{
+			digest.BlockUpdate(inSeed, 0, inSeed.Length);
+		}
+
+		private void DigestDoFinal(byte[] result)
+		{
+			digest.DoFinal(result, 0);
+		}
+	}
+}
diff --git a/crypto/src/crypto/prng/IRandomGenerator.cs b/crypto/src/crypto/prng/IRandomGenerator.cs
new file mode 100644
index 000000000..8dbe4068f
--- /dev/null
+++ b/crypto/src/crypto/prng/IRandomGenerator.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+	/// <remarks>Generic interface for objects generating random bytes.</remarks>
+	public interface IRandomGenerator
+	{
+		/// <summary>Add more seed material to the generator.</summary>
+		/// <param name="seed">A byte array to be mixed into the generator's state.</param>
+		void AddSeedMaterial(byte[] seed);
+
+		/// <summary>Add more seed material to the generator.</summary>
+		/// <param name="seed">A long value to be mixed into the generator's state.</param>
+		void AddSeedMaterial(long seed);
+
+		/// <summary>Fill byte array with random values.</summary>
+		/// <param name="bytes">Array to be filled.</param>
+		void NextBytes(byte[] bytes);
+
+		/// <summary>Fill byte array with random values.</summary>
+		/// <param name="bytes">Array to receive bytes.</param>
+		/// <param name="start">Index to start filling at.</param>
+		/// <param name="len">Length of segment to fill.</param>
+		void NextBytes(byte[] bytes, int start, int len);
+	}
+}
diff --git a/crypto/src/crypto/prng/ReversedWindowGenerator.cs b/crypto/src/crypto/prng/ReversedWindowGenerator.cs
new file mode 100644
index 000000000..dd28c525a
--- /dev/null
+++ b/crypto/src/crypto/prng/ReversedWindowGenerator.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+	/// <remarks>
+	/// Takes bytes generated by an underling RandomGenerator and reverses the order in
+	/// each small window (of configurable size).
+	/// <p>
+	/// Access to internals is synchronized so a single one of these can be shared.
+	/// </p>
+	/// </remarks>
+	public class ReversedWindowGenerator
+		: IRandomGenerator
+	{
+		private readonly IRandomGenerator generator;
+
+		private byte[] window;
+		private int windowCount;
+
+		public ReversedWindowGenerator(
+			IRandomGenerator	generator,
+			int					windowSize)
+		{
+			if (generator == null)
+				throw new ArgumentNullException("generator");
+			if (windowSize < 2)
+				throw new ArgumentException("Window size must be at least 2", "windowSize");
+
+			this.generator = generator;
+			this.window = new byte[windowSize];
+		}
+
+		/// <summary>Add more seed material to the generator.</summary>
+		/// <param name="seed">A byte array to be mixed into the generator's state.</param>
+		public virtual void AddSeedMaterial(
+			byte[] seed)
+		{
+			lock (this)
+			{
+				windowCount = 0;
+				generator.AddSeedMaterial(seed);
+			}
+		}
+
+		/// <summary>Add more seed material to the generator.</summary>
+		/// <param name="seed">A long value to be mixed into the generator's state.</param>
+		public virtual void AddSeedMaterial(
+			long seed)
+		{
+			lock (this)
+			{
+				windowCount = 0;
+				generator.AddSeedMaterial(seed);
+			}
+		}
+
+		/// <summary>Fill byte array with random values.</summary>
+		/// <param name="bytes">Array to be filled.</param>
+		public virtual void NextBytes(
+			byte[] bytes)
+		{
+			doNextBytes(bytes, 0, bytes.Length);
+		}
+
+		/// <summary>Fill byte array with random values.</summary>
+		/// <param name="bytes">Array to receive bytes.</param>
+		/// <param name="start">Index to start filling at.</param>
+		/// <param name="len">Length of segment to fill.</param>
+		public virtual void NextBytes(
+			byte[]	bytes,
+			int		start,
+			int		len)
+		{
+			doNextBytes(bytes, start, len);
+		}
+
+		private void doNextBytes(
+			byte[]	bytes,
+			int		start,
+			int		len)
+		{
+			lock (this)
+			{
+				int done = 0;
+				while (done < len)
+				{
+					if (windowCount < 1)
+					{
+						generator.NextBytes(window, 0, window.Length);
+						windowCount = window.Length;
+					}
+
+					bytes[start + done++] = window[--windowCount];
+				}
+			}
+		}
+	}
+}
diff --git a/crypto/src/crypto/prng/ThreadedSeedGenerator.cs b/crypto/src/crypto/prng/ThreadedSeedGenerator.cs
index 9f918ea6e..c29ad2c9a 100644
--- a/crypto/src/crypto/prng/ThreadedSeedGenerator.cs
+++ b/crypto/src/crypto/prng/ThreadedSeedGenerator.cs
@@ -34,7 +34,27 @@ namespace Org.BouncyCastle.Crypto.Prng
 				int		numBytes,
 				bool	fast)
 			{
-				this.counter = 0;
+#if SILVERLIGHT
+                return DoGenerateSeed(numBytes, fast);
+#else
+                ThreadPriority originalPriority = Thread.CurrentThread.Priority;
+                try
+                {
+                    Thread.CurrentThread.Priority = ThreadPriority.Normal;
+                    return DoGenerateSeed(numBytes, fast);
+                }
+                finally
+                {
+                    Thread.CurrentThread.Priority = originalPriority;
+                }
+#endif
+            }
+
+            private byte[] DoGenerateSeed(
+				int		numBytes,
+				bool	fast)
+            {
+                this.counter = 0;
 				this.stop = false;
 
 				byte[] result = new byte[numBytes];
@@ -45,13 +65,11 @@ namespace Org.BouncyCastle.Crypto.Prng
 
 				for (int i = 0; i < end; i++)
 				{
-                    var waitEvent = new ManualResetEvent(false);
-
 					while (this.counter == last)
 					{
 						try
 						{
-                            waitEvent.WaitOne(1);
+							Thread.Sleep(1);
 						}
 						catch (Exception)
 						{
diff --git a/crypto/src/crypto/prng/VMPCRandomGenerator.cs b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
index 2ab079999..64f287d13 100644
--- a/crypto/src/crypto/prng/VMPCRandomGenerator.cs
+++ b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
@@ -1,115 +1,114 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Prng
 {
-	public class VmpcRandomGenerator
-		: IRandomGenerator 
-	{
-		private byte n = 0;
+    public class VmpcRandomGenerator
+        : IRandomGenerator 
+    {
+        private byte n = 0;
 
-		/// <remarks>
-		/// Permutation generated by code:
-		/// <code>
-		/// // First 1850 fractional digit of Pi number. 
-		/// byte[] key = new BigInteger("14159265358979323846...5068006422512520511").ToByteArray();
-		/// s = 0;
-		/// P = new byte[256];
-		/// for (int i = 0; i &lt; 256; i++) 
-		/// {
-		///     P[i] = (byte) i;
-		/// }
-		/// for (int m = 0; m &lt; 768; m++) 
-		/// {
-		///     s = P[(s + P[m &amp; 0xff] + key[m % key.length]) &amp; 0xff];
-		///     byte temp = P[m &amp; 0xff];
-		///     P[m &amp; 0xff] = P[s &amp; 0xff];
-		///     P[s &amp; 0xff] = temp;
-		/// } </code>
-		/// </remarks>
-		private byte[] P =
-		{
-			(byte) 0xbb, (byte) 0x2c, (byte) 0x62, (byte) 0x7f, (byte) 0xb5, (byte) 0xaa, (byte) 0xd4,
-			(byte) 0x0d, (byte) 0x81, (byte) 0xfe, (byte) 0xb2, (byte) 0x82, (byte) 0xcb, (byte) 0xa0, (byte) 0xa1,
-			(byte) 0x08, (byte) 0x18, (byte) 0x71, (byte) 0x56, (byte) 0xe8, (byte) 0x49, (byte) 0x02, (byte) 0x10,
-			(byte) 0xc4, (byte) 0xde, (byte) 0x35, (byte) 0xa5, (byte) 0xec, (byte) 0x80, (byte) 0x12, (byte) 0xb8,
-			(byte) 0x69, (byte) 0xda, (byte) 0x2f, (byte) 0x75, (byte) 0xcc, (byte) 0xa2, (byte) 0x09, (byte) 0x36,
-			(byte) 0x03, (byte) 0x61, (byte) 0x2d, (byte) 0xfd, (byte) 0xe0, (byte) 0xdd, (byte) 0x05, (byte) 0x43,
-			(byte) 0x90, (byte) 0xad, (byte) 0xc8, (byte) 0xe1, (byte) 0xaf, (byte) 0x57, (byte) 0x9b, (byte) 0x4c,
-			(byte) 0xd8, (byte) 0x51, (byte) 0xae, (byte) 0x50, (byte) 0x85, (byte) 0x3c, (byte) 0x0a, (byte) 0xe4,
-			(byte) 0xf3, (byte) 0x9c, (byte) 0x26, (byte) 0x23, (byte) 0x53, (byte) 0xc9, (byte) 0x83, (byte) 0x97,
-			(byte) 0x46, (byte) 0xb1, (byte) 0x99, (byte) 0x64, (byte) 0x31, (byte) 0x77, (byte) 0xd5, (byte) 0x1d,
-			(byte) 0xd6, (byte) 0x78, (byte) 0xbd, (byte) 0x5e, (byte) 0xb0, (byte) 0x8a, (byte) 0x22, (byte) 0x38,
-			(byte) 0xf8, (byte) 0x68, (byte) 0x2b, (byte) 0x2a, (byte) 0xc5, (byte) 0xd3, (byte) 0xf7, (byte) 0xbc,
-			(byte) 0x6f, (byte) 0xdf, (byte) 0x04, (byte) 0xe5, (byte) 0x95, (byte) 0x3e, (byte) 0x25, (byte) 0x86,
-			(byte) 0xa6, (byte) 0x0b, (byte) 0x8f, (byte) 0xf1, (byte) 0x24, (byte) 0x0e, (byte) 0xd7, (byte) 0x40,
-			(byte) 0xb3, (byte) 0xcf, (byte) 0x7e, (byte) 0x06, (byte) 0x15, (byte) 0x9a, (byte) 0x4d, (byte) 0x1c,
-			(byte) 0xa3, (byte) 0xdb, (byte) 0x32, (byte) 0x92, (byte) 0x58, (byte) 0x11, (byte) 0x27, (byte) 0xf4,
-			(byte) 0x59, (byte) 0xd0, (byte) 0x4e, (byte) 0x6a, (byte) 0x17, (byte) 0x5b, (byte) 0xac, (byte) 0xff,
-			(byte) 0x07, (byte) 0xc0, (byte) 0x65, (byte) 0x79, (byte) 0xfc, (byte) 0xc7, (byte) 0xcd, (byte) 0x76,
-			(byte) 0x42, (byte) 0x5d, (byte) 0xe7, (byte) 0x3a, (byte) 0x34, (byte) 0x7a, (byte) 0x30, (byte) 0x28,
-			(byte) 0x0f, (byte) 0x73, (byte) 0x01, (byte) 0xf9, (byte) 0xd1, (byte) 0xd2, (byte) 0x19, (byte) 0xe9,
-			(byte) 0x91, (byte) 0xb9, (byte) 0x5a, (byte) 0xed, (byte) 0x41, (byte) 0x6d, (byte) 0xb4, (byte) 0xc3,
-			(byte) 0x9e, (byte) 0xbf, (byte) 0x63, (byte) 0xfa, (byte) 0x1f, (byte) 0x33, (byte) 0x60, (byte) 0x47,
-			(byte) 0x89, (byte) 0xf0, (byte) 0x96, (byte) 0x1a, (byte) 0x5f, (byte) 0x93, (byte) 0x3d, (byte) 0x37,
-			(byte) 0x4b, (byte) 0xd9, (byte) 0xa8, (byte) 0xc1, (byte) 0x1b, (byte) 0xf6, (byte) 0x39, (byte) 0x8b,
-			(byte) 0xb7, (byte) 0x0c, (byte) 0x20, (byte) 0xce, (byte) 0x88, (byte) 0x6e, (byte) 0xb6, (byte) 0x74,
-			(byte) 0x8e, (byte) 0x8d, (byte) 0x16, (byte) 0x29, (byte) 0xf2, (byte) 0x87, (byte) 0xf5, (byte) 0xeb,
-			(byte) 0x70, (byte) 0xe3, (byte) 0xfb, (byte) 0x55, (byte) 0x9f, (byte) 0xc6, (byte) 0x44, (byte) 0x4a,
-			(byte) 0x45, (byte) 0x7d, (byte) 0xe2, (byte) 0x6b, (byte) 0x5c, (byte) 0x6c, (byte) 0x66, (byte) 0xa9,
-			(byte) 0x8c, (byte) 0xee, (byte) 0x84, (byte) 0x13, (byte) 0xa7, (byte) 0x1e, (byte) 0x9d, (byte) 0xdc,
-			(byte) 0x67, (byte) 0x48, (byte) 0xba, (byte) 0x2e, (byte) 0xe6, (byte) 0xa4, (byte) 0xab, (byte) 0x7c,
-			(byte) 0x94, (byte) 0x00, (byte) 0x21, (byte) 0xef, (byte) 0xea, (byte) 0xbe, (byte) 0xca, (byte) 0x72,
-			(byte) 0x4f, (byte) 0x52, (byte) 0x98, (byte) 0x3f, (byte) 0xc2, (byte) 0x14, (byte) 0x7b, (byte) 0x3b,
-			(byte) 0x54
-		};
+        /// <remarks>
+        /// Permutation generated by code:
+        /// <code>
+        /// // First 1850 fractional digit of Pi number. 
+        /// byte[] key = new BigInteger("14159265358979323846...5068006422512520511").ToByteArray();
+        /// s = 0;
+        /// P = new byte[256];
+        /// for (int i = 0; i &lt; 256; i++) 
+        /// {
+        ///     P[i] = (byte) i;
+        /// }
+        /// for (int m = 0; m &lt; 768; m++) 
+        /// {
+        ///     s = P[(s + P[m &amp; 0xff] + key[m % key.length]) &amp; 0xff];
+        ///     byte temp = P[m &amp; 0xff];
+        ///     P[m &amp; 0xff] = P[s &amp; 0xff];
+        ///     P[s &amp; 0xff] = temp;
+        /// } </code>
+        /// </remarks>
+        private byte[] P =
+        {
+            (byte) 0xbb, (byte) 0x2c, (byte) 0x62, (byte) 0x7f, (byte) 0xb5, (byte) 0xaa, (byte) 0xd4,
+            (byte) 0x0d, (byte) 0x81, (byte) 0xfe, (byte) 0xb2, (byte) 0x82, (byte) 0xcb, (byte) 0xa0, (byte) 0xa1,
+            (byte) 0x08, (byte) 0x18, (byte) 0x71, (byte) 0x56, (byte) 0xe8, (byte) 0x49, (byte) 0x02, (byte) 0x10,
+            (byte) 0xc4, (byte) 0xde, (byte) 0x35, (byte) 0xa5, (byte) 0xec, (byte) 0x80, (byte) 0x12, (byte) 0xb8,
+            (byte) 0x69, (byte) 0xda, (byte) 0x2f, (byte) 0x75, (byte) 0xcc, (byte) 0xa2, (byte) 0x09, (byte) 0x36,
+            (byte) 0x03, (byte) 0x61, (byte) 0x2d, (byte) 0xfd, (byte) 0xe0, (byte) 0xdd, (byte) 0x05, (byte) 0x43,
+            (byte) 0x90, (byte) 0xad, (byte) 0xc8, (byte) 0xe1, (byte) 0xaf, (byte) 0x57, (byte) 0x9b, (byte) 0x4c,
+            (byte) 0xd8, (byte) 0x51, (byte) 0xae, (byte) 0x50, (byte) 0x85, (byte) 0x3c, (byte) 0x0a, (byte) 0xe4,
+            (byte) 0xf3, (byte) 0x9c, (byte) 0x26, (byte) 0x23, (byte) 0x53, (byte) 0xc9, (byte) 0x83, (byte) 0x97,
+            (byte) 0x46, (byte) 0xb1, (byte) 0x99, (byte) 0x64, (byte) 0x31, (byte) 0x77, (byte) 0xd5, (byte) 0x1d,
+            (byte) 0xd6, (byte) 0x78, (byte) 0xbd, (byte) 0x5e, (byte) 0xb0, (byte) 0x8a, (byte) 0x22, (byte) 0x38,
+            (byte) 0xf8, (byte) 0x68, (byte) 0x2b, (byte) 0x2a, (byte) 0xc5, (byte) 0xd3, (byte) 0xf7, (byte) 0xbc,
+            (byte) 0x6f, (byte) 0xdf, (byte) 0x04, (byte) 0xe5, (byte) 0x95, (byte) 0x3e, (byte) 0x25, (byte) 0x86,
+            (byte) 0xa6, (byte) 0x0b, (byte) 0x8f, (byte) 0xf1, (byte) 0x24, (byte) 0x0e, (byte) 0xd7, (byte) 0x40,
+            (byte) 0xb3, (byte) 0xcf, (byte) 0x7e, (byte) 0x06, (byte) 0x15, (byte) 0x9a, (byte) 0x4d, (byte) 0x1c,
+            (byte) 0xa3, (byte) 0xdb, (byte) 0x32, (byte) 0x92, (byte) 0x58, (byte) 0x11, (byte) 0x27, (byte) 0xf4,
+            (byte) 0x59, (byte) 0xd0, (byte) 0x4e, (byte) 0x6a, (byte) 0x17, (byte) 0x5b, (byte) 0xac, (byte) 0xff,
+            (byte) 0x07, (byte) 0xc0, (byte) 0x65, (byte) 0x79, (byte) 0xfc, (byte) 0xc7, (byte) 0xcd, (byte) 0x76,
+            (byte) 0x42, (byte) 0x5d, (byte) 0xe7, (byte) 0x3a, (byte) 0x34, (byte) 0x7a, (byte) 0x30, (byte) 0x28,
+            (byte) 0x0f, (byte) 0x73, (byte) 0x01, (byte) 0xf9, (byte) 0xd1, (byte) 0xd2, (byte) 0x19, (byte) 0xe9,
+            (byte) 0x91, (byte) 0xb9, (byte) 0x5a, (byte) 0xed, (byte) 0x41, (byte) 0x6d, (byte) 0xb4, (byte) 0xc3,
+            (byte) 0x9e, (byte) 0xbf, (byte) 0x63, (byte) 0xfa, (byte) 0x1f, (byte) 0x33, (byte) 0x60, (byte) 0x47,
+            (byte) 0x89, (byte) 0xf0, (byte) 0x96, (byte) 0x1a, (byte) 0x5f, (byte) 0x93, (byte) 0x3d, (byte) 0x37,
+            (byte) 0x4b, (byte) 0xd9, (byte) 0xa8, (byte) 0xc1, (byte) 0x1b, (byte) 0xf6, (byte) 0x39, (byte) 0x8b,
+            (byte) 0xb7, (byte) 0x0c, (byte) 0x20, (byte) 0xce, (byte) 0x88, (byte) 0x6e, (byte) 0xb6, (byte) 0x74,
+            (byte) 0x8e, (byte) 0x8d, (byte) 0x16, (byte) 0x29, (byte) 0xf2, (byte) 0x87, (byte) 0xf5, (byte) 0xeb,
+            (byte) 0x70, (byte) 0xe3, (byte) 0xfb, (byte) 0x55, (byte) 0x9f, (byte) 0xc6, (byte) 0x44, (byte) 0x4a,
+            (byte) 0x45, (byte) 0x7d, (byte) 0xe2, (byte) 0x6b, (byte) 0x5c, (byte) 0x6c, (byte) 0x66, (byte) 0xa9,
+            (byte) 0x8c, (byte) 0xee, (byte) 0x84, (byte) 0x13, (byte) 0xa7, (byte) 0x1e, (byte) 0x9d, (byte) 0xdc,
+            (byte) 0x67, (byte) 0x48, (byte) 0xba, (byte) 0x2e, (byte) 0xe6, (byte) 0xa4, (byte) 0xab, (byte) 0x7c,
+            (byte) 0x94, (byte) 0x00, (byte) 0x21, (byte) 0xef, (byte) 0xea, (byte) 0xbe, (byte) 0xca, (byte) 0x72,
+            (byte) 0x4f, (byte) 0x52, (byte) 0x98, (byte) 0x3f, (byte) 0xc2, (byte) 0x14, (byte) 0x7b, (byte) 0x3b,
+            (byte) 0x54
+        };
 
-		/// <remarks>Value generated in the same way as <c>P</c>.</remarks>
-		private byte s = (byte) 0xbe;
+        /// <remarks>Value generated in the same way as <c>P</c>.</remarks>
+        private byte s = (byte) 0xbe;
 
-		public VmpcRandomGenerator()
-		{
-		}
+        public VmpcRandomGenerator()
+        {
+        }
 
-		public virtual void AddSeedMaterial(byte[] seed) 
-		{
-			for (int m = 0; m < seed.Length; m++) 
-			{
-				s = P[(s + P[n & 0xff] + seed[m]) & 0xff];
-				byte temp = P[n & 0xff];
-				P[n & 0xff] = P[s & 0xff];
-				P[s & 0xff] = temp;
-				n = (byte) ((n + 1) & 0xff);
-			}
-		}
+        public virtual void AddSeedMaterial(byte[] seed) 
+        {
+            for (int m = 0; m < seed.Length; m++) 
+            {
+                s = P[(s + P[n & 0xff] + seed[m]) & 0xff];
+                byte temp = P[n & 0xff];
+                P[n & 0xff] = P[s & 0xff];
+                P[s & 0xff] = temp;
+                n = (byte) ((n + 1) & 0xff);
+            }
+        }
 
-		public virtual void AddSeedMaterial(long seed) 
-		{
-			byte[] s = new byte[4];
-			s[3] = (byte) (seed & 0x000000ff);
-			s[2] = (byte) ((seed & 0x0000ff00) >> 8);
-			s[1] = (byte) ((seed & 0x00ff0000) >> 16);
-			s[0] = (byte) ((seed & 0xff000000) >> 24);
-			AddSeedMaterial(s);
-		}
+        public virtual void AddSeedMaterial(long seed) 
+        {
+            AddSeedMaterial(Pack.UInt64_To_BE((ulong)seed));
+        }
 
-		public virtual void NextBytes(byte[] bytes) 
-		{
-			NextBytes(bytes, 0, bytes.Length);
-		}
+        public virtual void NextBytes(byte[] bytes) 
+        {
+            NextBytes(bytes, 0, bytes.Length);
+        }
 
-		public virtual void NextBytes(byte[] bytes, int start, int len) 
-		{
-			lock (P) 
-			{
-				int end = start + len;
-				for (int i = start; i != end; i++) 
-				{
-					s = P[(s + P[n & 0xff]) & 0xff];
-					bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
-					byte temp = P[n & 0xff];
-					P[n & 0xff] = P[s & 0xff];
-					P[s & 0xff] = temp;
-					n = (byte) ((n + 1) & 0xff);
-				}
-			}
-		}
-	}
+        public virtual void NextBytes(byte[] bytes, int start, int len) 
+        {
+            lock (P) 
+            {
+                int end = start + len;
+                for (int i = start; i != end; i++) 
+                {
+                    s = P[(s + P[n & 0xff]) & 0xff];
+                    bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+                    byte temp = P[n & 0xff];
+                    P[n & 0xff] = P[s & 0xff];
+                    P[s & 0xff] = temp;
+                    n = (byte) ((n + 1) & 0xff);
+                }
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/signers/DsaDigestSigner.cs b/crypto/src/crypto/signers/DsaDigestSigner.cs
new file mode 100644
index 000000000..aee713450
--- /dev/null
+++ b/crypto/src/crypto/signers/DsaDigestSigner.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+	public class DsaDigestSigner
+		: ISigner
+	{
+		private readonly IDigest digest;
+		private readonly IDsa dsaSigner;
+		private bool forSigning;
+
+		public DsaDigestSigner(
+			IDsa	signer,
+			IDigest	digest)
+		{
+			this.digest = digest;
+			this.dsaSigner = signer;
+		}
+
+		public string AlgorithmName
+		{
+			get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+		}
+
+		public void Init(
+			bool							forSigning,
+			ICipherParameters	parameters)
+		{
+			this.forSigning = forSigning;
+
+			AsymmetricKeyParameter k;
+
+			if (parameters is ParametersWithRandom)
+			{
+				k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+			}
+			else
+			{
+				k = (AsymmetricKeyParameter)parameters;
+			}
+
+			if (forSigning && !k.IsPrivate)
+				throw new InvalidKeyException("Signing Requires Private Key.");
+
+			if (!forSigning && k.IsPrivate)
+				throw new InvalidKeyException("Verification Requires Public Key.");
+
+			Reset();
+
+			dsaSigner.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 BlockUpdate(
+			byte[]	input,
+			int			inOff,
+			int			length)
+		{
+			digest.BlockUpdate(input, inOff, length);
+		}
+
+		/**
+		 * Generate a signature for the message we've been loaded with using
+		 * the key we were initialised with.
+     */
+		public byte[] GenerateSignature()
+		{
+			if (!forSigning)
+				throw new InvalidOperationException("DSADigestSigner not initialised for signature generation.");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+
+			return DerEncode(sig[0], sig[1]);
+		}
+
+		/// <returns>true if the internal state represents the signature described in the passed in array.</returns>
+		public bool VerifySignature(
+			byte[] signature)
+		{
+			if (forSigning)
+				throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			try
+			{
+				BigInteger[] sig = DerDecode(signature);
+				return dsaSigner.VerifySignature(hash, sig[0], sig[1]);
+			}
+			catch (IOException)
+			{
+				return false;
+			}
+		}
+
+		/// <summary>Reset the internal state</summary>
+		public void Reset()
+		{
+			digest.Reset();
+		}
+
+		private byte[] DerEncode(
+			BigInteger	r,
+			BigInteger	s)
+		{
+			return new DerSequence(new DerInteger(r), new DerInteger(s)).GetDerEncoded();
+		}
+
+		private BigInteger[] DerDecode(
+			byte[] encoding)
+		{
+			Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+			return new BigInteger[]
+			{
+				((DerInteger) s[0]).Value,
+				((DerInteger) s[1]).Value
+			};
+		}
+	}
+}
diff --git a/crypto/src/crypto/signers/DsaSigner.cs b/crypto/src/crypto/signers/DsaSigner.cs
index 419b1972e..bb28addfc 100644
--- a/crypto/src/crypto/signers/DsaSigner.cs
+++ b/crypto/src/crypto/signers/DsaSigner.cs
@@ -1,136 +1,156 @@
 using System;
-using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Math.EC;
-using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Crypto;
+
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
-	/**
-	 * The Digital Signature Algorithm - as described in "Handbook of Applied
-	 * Cryptography", pages 452 - 453.
-	 */
-	public class DsaSigner
-		: IDsa
-	{
-		private DsaKeyParameters key;
-		private SecureRandom random;
-
-		public string AlgorithmName
-		{
-			get { return "DSA"; }
-		}
-
-		public void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
-		{
-			if (forSigning)
-			{
-				if (parameters is ParametersWithRandom)
-				{
-					ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
-					this.random = rParam.Random;
-					parameters = rParam.Parameters;
-				}
-				else
-				{
-					this.random = new SecureRandom();
-				}
-
-				if (!(parameters is DsaPrivateKeyParameters))
-					throw new InvalidKeyException("DSA private key required for signing");
-
-				this.key = (DsaPrivateKeyParameters) parameters;
-			}
-			else
-			{
-				if (!(parameters is DsaPublicKeyParameters))
-					throw new InvalidKeyException("DSA public key required for verification");
-
-				this.key = (DsaPublicKeyParameters) parameters;
-			}
-		}
-
-		/**
-		 * 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 parameters = key.Parameters;
-			BigInteger q = parameters.Q;
-			BigInteger m = calculateE(q, message);
-			BigInteger k;
-
-			do
-			{
-				k = new BigInteger(q.BitLength, random);
-			}
-			while (k.CompareTo(q) >= 0);
-
-			BigInteger r = parameters.G.ModPow(k, parameters.P).Mod(q);
-
-			k = k.ModInverse(q).Multiply(
-				m.Add(((DsaPrivateKeyParameters)key).X.Multiply(r)));
-
-			BigInteger s = k.Mod(q);
-
-			return new BigInteger[]{ r, s };
-		}
-
-		/**
-		 * 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 bool VerifySignature(
-			byte[]		message,
-			BigInteger	r,
-			BigInteger	s)
-		{
-			DsaParameters parameters = key.Parameters;
-			BigInteger q = parameters.Q;
-			BigInteger m = calculateE(q, message);
-
-			if (r.SignValue <= 0 || q.CompareTo(r) <= 0)
-			{
-				return false;
-			}
-
-			if (s.SignValue <= 0 || q.CompareTo(s) <= 0)
-			{
-				return false;
-			}
-
-			BigInteger w = s.ModInverse(q);
-
-			BigInteger u1 = m.Multiply(w).Mod(q);
-			BigInteger u2 = r.Multiply(w).Mod(q);
-
-			BigInteger p = parameters.P;
-			u1 = parameters.G.ModPow(u1, p);
-			u2 = ((DsaPublicKeyParameters)key).Y.ModPow(u2, p);
-
-			BigInteger v = u1.Multiply(u2).Mod(p).Mod(q);
-
-			return v.Equals(r);
-		}
-
-		private BigInteger calculateE(
-			BigInteger	n,
-			byte[]		message)
-		{
-			int length = System.Math.Min(message.Length, n.BitLength / 8);
-
-			return new BigInteger(1, message, 0, length);
-		}
-	}
+    /**
+     * The Digital Signature Algorithm - as described in "Handbook of Applied
+     * Cryptography", pages 452 - 453.
+     */
+    public class DsaSigner
+        : IDsa
+    {
+        protected readonly IDsaKCalculator kCalculator;
+
+        protected DsaKeyParameters key = null;
+        protected SecureRandom random = null;
+
+        /**
+         * Default configuration, random K values.
+         */
+        public DsaSigner()
+        {
+            this.kCalculator = new RandomDsaKCalculator();
+        }
+
+        /**
+         * Configuration with an alternate, possibly deterministic calculator of K.
+         *
+         * @param kCalculator a K value calculator.
+         */
+        public DsaSigner(IDsaKCalculator kCalculator)
+        {
+            this.kCalculator = kCalculator;
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "DSA"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters	parameters)
+        {
+            SecureRandom providedRandom = null;
+
+            if (forSigning)
+            {
+                if (parameters is ParametersWithRandom)
+                {
+                    ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+                    providedRandom = rParam.Random;
+                    parameters = rParam.Parameters;
+                }
+
+                if (!(parameters is DsaPrivateKeyParameters))
+                    throw new InvalidKeyException("DSA private key required for signing");
+
+                this.key = (DsaPrivateKeyParameters)parameters;
+            }
+            else
+            {
+                if (!(parameters is DsaPublicKeyParameters))
+                    throw new InvalidKeyException("DSA public key required for verification");
+
+                this.key = (DsaPublicKeyParameters)parameters;
+            }
+
+            this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
+        }
+
+        /**
+         * 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 virtual BigInteger[] GenerateSignature(byte[] message)
+        {
+            DsaParameters parameters = key.Parameters;
+            BigInteger q = parameters.Q;
+            BigInteger m = CalculateE(q, message);
+            BigInteger x = ((DsaPrivateKeyParameters)key).X;
+
+            if (kCalculator.IsDeterministic)
+            {
+                kCalculator.Init(q, x, message);
+            }
+            else
+            {
+                kCalculator.Init(q, random);
+            }
+
+            BigInteger k = kCalculator.NextK();
+
+            BigInteger r = parameters.G.ModPow(k, parameters.P).Mod(q);
+
+            k = k.ModInverse(q).Multiply(m.Add(x.Multiply(r)));
+
+            BigInteger s = k.Mod(q);
+
+            return new BigInteger[]{ r, s };
+        }
+
+        /**
+         * 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 virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
+        {
+            DsaParameters parameters = key.Parameters;
+            BigInteger q = parameters.Q;
+            BigInteger m = CalculateE(q, message);
+
+            if (r.SignValue <= 0 || q.CompareTo(r) <= 0)
+            {
+                return false;
+            }
+
+            if (s.SignValue <= 0 || q.CompareTo(s) <= 0)
+            {
+                return false;
+            }
+
+            BigInteger w = s.ModInverse(q);
+
+            BigInteger u1 = m.Multiply(w).Mod(q);
+            BigInteger u2 = r.Multiply(w).Mod(q);
+
+            BigInteger p = parameters.P;
+            u1 = parameters.G.ModPow(u1, p);
+            u2 = ((DsaPublicKeyParameters)key).Y.ModPow(u2, p);
+
+            BigInteger v = u1.Multiply(u2).Mod(p).Mod(q);
+
+            return v.Equals(r);
+        }
+
+        protected virtual BigInteger CalculateE(BigInteger n, byte[] message)
+        {
+            int length = System.Math.Min(message.Length, n.BitLength / 8);
+
+            return new BigInteger(1, message, 0, length);
+        }
+
+        protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
+        {
+            return !needed ? null : (provided != null) ? provided : new SecureRandom();
+        }
+    }
 }
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index 4254e5590..9821732c2 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -1,156 +1,185 @@
 using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Multiplier;
 using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
-	/**
-	 * EC-DSA as described in X9.62
-	 */
-	public class ECDsaSigner
-		: IDsa
-	{
-		private ECKeyParameters key;
-		private SecureRandom random;
-
-		public string AlgorithmName
-		{
-			get { return "ECDSA"; }
-		}
-
-		public void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
-		{
-			if (forSigning)
-			{
-				if (parameters is ParametersWithRandom)
-				{
-					ParametersWithRandom rParam = (ParametersWithRandom) parameters;
-
-					this.random = rParam.Random;
-					parameters = rParam.Parameters;
-				}
-				else
-				{
-					this.random = new SecureRandom();
-				}
-
-				if (!(parameters is ECPrivateKeyParameters))
-					throw new InvalidKeyException("EC private key required for signing");
-
-				this.key = (ECPrivateKeyParameters) parameters;
-			}
-			else
-			{
-				if (!(parameters is ECPublicKeyParameters))
-					throw new InvalidKeyException("EC public key required for verification");
-
-				this.key = (ECPublicKeyParameters) parameters;
-			}
-		}
-
-		// 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.Parameters.N;
-			BigInteger e = calculateE(n, message);
-
-			BigInteger r = null;
-			BigInteger s = null;
-
-			// 5.3.2
-			do // Generate s
-			{
-				BigInteger k = null;
-
-				do // Generate r
-				{
-					do
-					{
-						k = new BigInteger(n.BitLength, random);
-					}
-					while (k.SignValue == 0 || k.CompareTo(n) >= 0);
-
-					ECPoint p = key.Parameters.G.Multiply(k);
-
-					// 5.3.3
-					BigInteger x = p.X.ToBigInteger();
-
-					r = x.Mod(n);
-				}
-				while (r.SignValue == 0);
-
-				BigInteger d = ((ECPrivateKeyParameters)key).D;
-
-				s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r).Mod(n))).Mod(n);
-			}
-			while (s.SignValue == 0);
-
-			return new BigInteger[]{ r, s };
-		}
-
-		// 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 bool VerifySignature(
-			byte[]		message,
-			BigInteger	r,
-			BigInteger	s)
-		{
-			BigInteger n = key.Parameters.N;
-
-			// r and s should both in the range [1,n-1]
-			if (r.SignValue < 1 || s.SignValue < 1
-				|| r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0)
-			{
-				return false;
-			}
-
-			BigInteger e = calculateE(n, message);
-			BigInteger c = s.ModInverse(n);
-
-			BigInteger u1 = e.Multiply(c).Mod(n);
-			BigInteger u2 = r.Multiply(c).Mod(n);
-
-			ECPoint G = key.Parameters.G;
-			ECPoint Q = ((ECPublicKeyParameters) key).Q;
-
-			ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2);
-
-			BigInteger v = point.X.ToBigInteger().Mod(n);
-
-			return v.Equals(r);
-		}
-
-		private BigInteger calculateE(
-			BigInteger	n,
-			byte[]		message)
-		{
-			int messageBitLength = message.Length * 8;
-			BigInteger trunc = new BigInteger(1, message);
-
-			if (n.BitLength < messageBitLength)
-			{
-				trunc = trunc.ShiftRight(messageBitLength - n.BitLength);
-			}
-
-			return trunc;
-		}
-	}
+    /**
+     * EC-DSA as described in X9.62
+     */
+    public class ECDsaSigner
+        : IDsa
+    {
+        protected readonly IDsaKCalculator kCalculator;
+
+        protected ECKeyParameters key = null;
+        protected SecureRandom random = null;
+
+        /**
+         * Default configuration, random K values.
+         */
+        public ECDsaSigner()
+        {
+            this.kCalculator = new RandomDsaKCalculator();
+        }
+
+        /**
+         * Configuration with an alternate, possibly deterministic calculator of K.
+         *
+         * @param kCalculator a K value calculator.
+         */
+        public ECDsaSigner(IDsaKCalculator kCalculator)
+        {
+            this.kCalculator = kCalculator;
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "ECDSA"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            SecureRandom providedRandom = null;
+
+            if (forSigning)
+            {
+                if (parameters is ParametersWithRandom)
+                {
+                    ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+                    providedRandom = rParam.Random;
+                    parameters = rParam.Parameters;
+                }
+
+                if (!(parameters is ECPrivateKeyParameters))
+                    throw new InvalidKeyException("EC private key required for signing");
+
+                this.key = (ECPrivateKeyParameters)parameters;
+            }
+            else
+            {
+                if (!(parameters is ECPublicKeyParameters))
+                    throw new InvalidKeyException("EC public key required for verification");
+
+                this.key = (ECPublicKeyParameters)parameters;
+            }
+
+            this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
+        }
+
+        // 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 virtual BigInteger[] GenerateSignature(byte[] message)
+        {
+            ECDomainParameters ec = key.Parameters;
+            BigInteger n = ec.N;
+            BigInteger e = CalculateE(n, message);
+            BigInteger d = ((ECPrivateKeyParameters)key).D;
+
+            if (kCalculator.IsDeterministic)
+            {
+                kCalculator.Init(n, d, message);
+            }
+            else
+            {
+                kCalculator.Init(n, random);
+            }
+
+            BigInteger r, s;
+
+            ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
+
+            // 5.3.2
+            do // Generate s
+            {
+                BigInteger k;
+                do // Generate r
+                {
+                    k = kCalculator.NextK();
+
+                    ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
+
+                    // 5.3.3
+                    r = p.AffineXCoord.ToBigInteger().Mod(n);
+                }
+                while (r.SignValue == 0);
+
+                s = k.ModInverse(n).Multiply(e.Add(d.Multiply(r))).Mod(n);
+            }
+            while (s.SignValue == 0);
+
+            return new BigInteger[]{ r, s };
+        }
+
+        // 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 virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
+        {
+            BigInteger n = key.Parameters.N;
+
+            // r and s should both in the range [1,n-1]
+            if (r.SignValue < 1 || s.SignValue < 1
+                || r.CompareTo(n) >= 0 || s.CompareTo(n) >= 0)
+            {
+                return false;
+            }
+
+            BigInteger e = CalculateE(n, message);
+            BigInteger c = s.ModInverse(n);
+
+            BigInteger u1 = e.Multiply(c).Mod(n);
+            BigInteger u2 = r.Multiply(c).Mod(n);
+
+            ECPoint G = key.Parameters.G;
+            ECPoint Q = ((ECPublicKeyParameters) key).Q;
+
+            ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, u1, Q, u2).Normalize();
+
+            if (point.IsInfinity)
+                return false;
+
+            BigInteger v = point.AffineXCoord.ToBigInteger().Mod(n);
+
+            return v.Equals(r);
+        }
+
+        protected virtual BigInteger CalculateE(BigInteger n, byte[] message)
+        {
+            int messageBitLength = message.Length * 8;
+            BigInteger trunc = new BigInteger(1, message);
+
+            if (n.BitLength < messageBitLength)
+            {
+                trunc = trunc.ShiftRight(messageBitLength - n.BitLength);
+            }
+
+            return trunc;
+        }
+
+        protected virtual ECMultiplier CreateBasePointMultiplier()
+        {
+            return new FixedPointCombMultiplier();
+        }
+
+        protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
+        {
+            return !needed ? null : (provided != null) ? provided : new SecureRandom();
+        }
+    }
 }
diff --git a/crypto/src/crypto/signers/ECGOST3410Signer.cs b/crypto/src/crypto/signers/ECGOST3410Signer.cs
index d68b83f67..6027aa9b9 100644
--- a/crypto/src/crypto/signers/ECGOST3410Signer.cs
+++ b/crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -4,151 +4,159 @@ using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.EC.Multiplier;
 using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
-	/**
-	 * GOST R 34.10-2001 Signature Algorithm
-	 */
-	public class ECGost3410Signer
-		: IDsa
-	{
-		private ECKeyParameters key;
-		private SecureRandom random;
-
-		public string AlgorithmName
-		{
-			get { return "ECGOST3410"; }
-		}
-
-		public void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
-		{
-			if (forSigning)
-			{
-				if (parameters is ParametersWithRandom)
-				{
-					ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
-					this.random = rParam.Random;
-					parameters = rParam.Parameters;
-				}
-				else
-				{
-					this.random = new SecureRandom();
-				}
-
-				if (!(parameters is ECPrivateKeyParameters))
-					throw new InvalidKeyException("EC private key required for signing");
-
-				this.key = (ECPrivateKeyParameters) parameters;
-			}
-			else
-			{
-				if (!(parameters is ECPublicKeyParameters))
-					throw new InvalidKeyException("EC public key required for verification");
-
-				this.key = (ECPublicKeyParameters)parameters;
-			}
-		}
-
-		/**
-		 * generate a signature for the given message using the key we were
-		 * initialised with. For conventional GOST3410 the message should be a GOST3411
-		 * hash of the message of interest.
-		 *
-		 * @param message the message that will be verified later.
-		 */
-		public BigInteger[] GenerateSignature(
-			byte[] message)
-		{
-			byte[] mRev = new byte[message.Length]; // conversion is little-endian
-			for (int i = 0; i != mRev.Length; i++)
-			{
-				mRev[i] = message[mRev.Length - 1 - i];
-			}
-
-			BigInteger e = new BigInteger(1, mRev);
-			BigInteger n = key.Parameters.N;
-
-			BigInteger r = null;
-			BigInteger s = null;
-
-			do // generate s
-			{
-				BigInteger k = null;
-
-				do // generate r
-				{
-					do
-					{
-						k = new BigInteger(n.BitLength, random);
-					}
-					while (k.SignValue == 0);
-
-					ECPoint p = key.Parameters.G.Multiply(k);
-
-					BigInteger x = p.X.ToBigInteger();
-
-					r = x.Mod(n);
-				}
-				while (r.SignValue == 0);
-
-				BigInteger d = ((ECPrivateKeyParameters)key).D;
-
-				s = (k.Multiply(e)).Add(d.Multiply(r)).Mod(n);
-			}
-			while (s.SignValue == 0);
-
-			return new BigInteger[]{ r, s };
-		}
-
-		/**
-		 * return true if the value r and s represent a GOST3410 signature for
-		 * the passed in message (for standard GOST3410 the message should be
-		 * a GOST3411 hash of the real message to be verified).
-		 */
-		public bool VerifySignature(
-			byte[]		message,
-			BigInteger	r,
-			BigInteger	s)
-		{
-			byte[] mRev = new byte[message.Length]; // conversion is little-endian
-			for (int i = 0; i != mRev.Length; i++)
-			{
-				mRev[i] = message[mRev.Length - 1 - i];
-			}
-
-			BigInteger e = new BigInteger(1, mRev);
-			BigInteger n = key.Parameters.N;
-
-			// r in the range [1,n-1]
-			if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
-			{
-				return false;
-			}
-
-			// s in the range [1,n-1]
-			if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
-			{
-				return false;
-			}
-
-			BigInteger v = e.ModInverse(n);
-
-			BigInteger z1 = s.Multiply(v).Mod(n);
-			BigInteger z2 = (n.Subtract(r)).Multiply(v).Mod(n);
-
-			ECPoint G = key.Parameters.G; // P
-			ECPoint Q = ((ECPublicKeyParameters)key).Q;
-
-			ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2);
-
-			BigInteger R = point.X.ToBigInteger().Mod(n);
-
-			return R.Equals(r);
-		}
-	}
+    /**
+     * GOST R 34.10-2001 Signature Algorithm
+     */
+    public class ECGost3410Signer
+        : IDsa
+    {
+        private ECKeyParameters key;
+        private SecureRandom random;
+
+        public string AlgorithmName
+        {
+            get { return "ECGOST3410"; }
+        }
+
+        public void Init(
+            bool				forSigning,
+            ICipherParameters	parameters)
+        {
+            if (forSigning)
+            {
+                if (parameters is ParametersWithRandom)
+                {
+                    ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+                    this.random = rParam.Random;
+                    parameters = rParam.Parameters;
+                }
+                else
+                {
+                    this.random = new SecureRandom();
+                }
+
+                if (!(parameters is ECPrivateKeyParameters))
+                    throw new InvalidKeyException("EC private key required for signing");
+
+                this.key = (ECPrivateKeyParameters) parameters;
+            }
+            else
+            {
+                if (!(parameters is ECPublicKeyParameters))
+                    throw new InvalidKeyException("EC public key required for verification");
+
+                this.key = (ECPublicKeyParameters)parameters;
+            }
+        }
+
+        /**
+         * generate a signature for the given message using the key we were
+         * initialised with. For conventional GOST3410 the message should be a GOST3411
+         * hash of the message of interest.
+         *
+         * @param message the message that will be verified later.
+         */
+        public BigInteger[] GenerateSignature(
+            byte[] message)
+        {
+            byte[] mRev = new byte[message.Length]; // conversion is little-endian
+            for (int i = 0; i != mRev.Length; i++)
+            {
+                mRev[i] = message[mRev.Length - 1 - i];
+            }
+
+            BigInteger e = new BigInteger(1, mRev);
+
+            ECDomainParameters ec = key.Parameters;
+            BigInteger n = ec.N;
+            BigInteger d = ((ECPrivateKeyParameters)key).D;
+
+            BigInteger r, s = null;
+
+            ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
+
+            do // generate s
+            {
+                BigInteger k;
+                do // generate r
+                {
+                    do
+                    {
+                        k = new BigInteger(n.BitLength, random);
+                    }
+                    while (k.SignValue == 0);
+
+                    ECPoint p = basePointMultiplier.Multiply(ec.G, k).Normalize();
+
+                    r = p.AffineXCoord.ToBigInteger().Mod(n);
+                }
+                while (r.SignValue == 0);
+
+                s = (k.Multiply(e)).Add(d.Multiply(r)).Mod(n);
+            }
+            while (s.SignValue == 0);
+
+            return new BigInteger[]{ r, s };
+        }
+
+        /**
+         * return true if the value r and s represent a GOST3410 signature for
+         * the passed in message (for standard GOST3410 the message should be
+         * a GOST3411 hash of the real message to be verified).
+         */
+        public bool VerifySignature(
+            byte[]		message,
+            BigInteger	r,
+            BigInteger	s)
+        {
+            byte[] mRev = new byte[message.Length]; // conversion is little-endian
+            for (int i = 0; i != mRev.Length; i++)
+            {
+                mRev[i] = message[mRev.Length - 1 - i];
+            }
+
+            BigInteger e = new BigInteger(1, mRev);
+            BigInteger n = key.Parameters.N;
+
+            // r in the range [1,n-1]
+            if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+            {
+                return false;
+            }
+
+            // s in the range [1,n-1]
+            if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
+            {
+                return false;
+            }
+
+            BigInteger v = e.ModInverse(n);
+
+            BigInteger z1 = s.Multiply(v).Mod(n);
+            BigInteger z2 = (n.Subtract(r)).Multiply(v).Mod(n);
+
+            ECPoint G = key.Parameters.G; // P
+            ECPoint Q = ((ECPublicKeyParameters)key).Q;
+
+            ECPoint point = ECAlgorithms.SumOfTwoMultiplies(G, z1, Q, z2).Normalize();
+
+            if (point.IsInfinity)
+                return false;
+
+            BigInteger R = point.AffineXCoord.ToBigInteger().Mod(n);
+
+            return R.Equals(r);
+        }
+
+        protected virtual ECMultiplier CreateBasePointMultiplier()
+        {
+            return new FixedPointCombMultiplier();
+        }
+    }
 }
diff --git a/crypto/src/crypto/signers/ECNRSigner.cs b/crypto/src/crypto/signers/ECNRSigner.cs
index 63865d731..cae15bdbf 100644
--- a/crypto/src/crypto/signers/ECNRSigner.cs
+++ b/crypto/src/crypto/signers/ECNRSigner.cs
@@ -9,178 +9,180 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
-	/**
-	 * EC-NR as described in IEEE 1363-2000
-	 */
-	public class ECNRSigner
-		: IDsa
-	{
-		private bool			forSigning;
-		private ECKeyParameters	key;
-		private SecureRandom	random;
-
-		public string AlgorithmName
-		{
-			get { return "ECNR"; }
-		}
-
-		public void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
-		{
-			this.forSigning = forSigning;
-
-			if (forSigning)
-			{
-				if (parameters is ParametersWithRandom)
-				{
-					ParametersWithRandom rParam = (ParametersWithRandom) parameters;
-
-					this.random = rParam.Random;
-					parameters = rParam.Parameters;
-				}
-				else
-				{
-					this.random = new SecureRandom();
-				}
-
-				if (!(parameters is ECPrivateKeyParameters))
-					throw new InvalidKeyException("EC private key required for signing");
-
-				this.key = (ECPrivateKeyParameters) parameters;
-			}
-			else
-			{
-				if (!(parameters is ECPublicKeyParameters))
-					throw new InvalidKeyException("EC public key required for verification");
-
-				this.key = (ECPublicKeyParameters) parameters;
-			}
-		}
-
-		// Section 7.2.5 ECSP-NR, pg 34
-		/**
-		 * generate a signature for the given message using the key we were
-		 * initialised with.  Generally, the order of the curve should be at
-		 * least as long as the hash of the message of interest, and with
-		 * ECNR it *must* be at least as long.
-		 *
-		 * @param digest  the digest to be signed.
-		 * @exception DataLengthException if the digest is longer than the key allows
-		 */
-		public BigInteger[] GenerateSignature(
-			byte[] message)
-		{
-			if (!this.forSigning)
-			{
-				// not properly initilaized... deal with it
-				throw new InvalidOperationException("not initialised for signing");
-			}
-
-			BigInteger n = ((ECPrivateKeyParameters) this.key).Parameters.N;
-			int nBitLength = n.BitLength;
-
-			BigInteger e = new BigInteger(1, message);
-			int eBitLength = e.BitLength;
-
-			ECPrivateKeyParameters  privKey = (ECPrivateKeyParameters)key;
-
-			if (eBitLength > nBitLength)
-			{
-				throw new DataLengthException("input too large for ECNR key.");
-			}
-
-			BigInteger r = null;
-			BigInteger s = null;
-
-			AsymmetricCipherKeyPair tempPair;
-			do // generate r
-			{
-				// generate another, but very temporary, key pair using
-				// the same EC parameters
-				ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
-
-				keyGen.Init(new ECKeyGenerationParameters(privKey.Parameters, this.random));
-
-				tempPair = keyGen.GenerateKeyPair();
-
-				//    BigInteger Vx = tempPair.getPublic().getW().getAffineX();
-				ECPublicKeyParameters V = (ECPublicKeyParameters) tempPair.Public; // get temp's public key
-				BigInteger Vx = V.Q.X.ToBigInteger(); // get the point's x coordinate
-
-				r = Vx.Add(e).Mod(n);
-			}
-			while (r.SignValue == 0);
-
-			// generate s
-			BigInteger x = privKey.D;                // private key value
-			BigInteger u = ((ECPrivateKeyParameters) tempPair.Private).D; // temp's private key value
-			s = u.Subtract(r.Multiply(x)).Mod(n);
-
-			return new BigInteger[]{ r, s };
-		}
-
-		// Section 7.2.6 ECVP-NR, pg 35
-		/**
-		 * return true if the value r and s represent a signature for the
-		 * message passed in. Generally, the order of the curve should be at
-		 * least as long as the hash of the message of interest, and with
-		 * ECNR, it *must* be at least as long.  But just in case the signer
-		 * applied mod(n) to the longer digest, this implementation will
-		 * apply mod(n) during verification.
-		 *
-		 * @param digest  the digest to be verified.
-		 * @param r       the r value of the signature.
-		 * @param s       the s value of the signature.
-		 * @exception DataLengthException if the digest is longer than the key allows
-		 */
-		public bool VerifySignature(
-			byte[]		message,
-			BigInteger	r,
-			BigInteger	s)
-		{
-			if (this.forSigning)
-			{
-				// not properly initilaized... deal with it
-				throw new InvalidOperationException("not initialised for verifying");
-			}
-
-			ECPublicKeyParameters pubKey = (ECPublicKeyParameters)key;
-			BigInteger n = pubKey.Parameters.N;
-			int nBitLength = n.BitLength;
-
-			BigInteger e = new BigInteger(1, message);
-			int eBitLength = e.BitLength;
-
-			if (eBitLength > nBitLength)
-			{
-				throw new DataLengthException("input too large for ECNR key.");
-			}
-
-			// r in the range [1,n-1]
-			if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
-			{
-				return false;
-			}
-
-			// TODO So why is this different from the spec?
-			// s in the range [0,n-1]           NB: ECNR spec says 0
-			if (s.CompareTo(BigInteger.Zero) < 0 || s.CompareTo(n) >= 0)
-			{
-				return false;
-			}
-
-			// compute P = sG + rW
-
-			ECPoint G = pubKey.Parameters.G;
-			ECPoint W = pubKey.Q;
-			// calculate P using Bouncy math
-			ECPoint P = ECAlgorithms.SumOfTwoMultiplies(G, s, W, r);
-
-			BigInteger x = P.X.ToBigInteger();
-			BigInteger t = r.Subtract(x).Mod(n);
-
-			return t.Equals(e);
-		}
-	}
+    /**
+     * EC-NR as described in IEEE 1363-2000
+     */
+    public class ECNRSigner
+        : IDsa
+    {
+        private bool			forSigning;
+        private ECKeyParameters	key;
+        private SecureRandom	random;
+
+        public string AlgorithmName
+        {
+            get { return "ECNR"; }
+        }
+
+        public void Init(
+            bool				forSigning,
+            ICipherParameters	parameters)
+        {
+            this.forSigning = forSigning;
+
+            if (forSigning)
+            {
+                if (parameters is ParametersWithRandom)
+                {
+                    ParametersWithRandom rParam = (ParametersWithRandom) parameters;
+
+                    this.random = rParam.Random;
+                    parameters = rParam.Parameters;
+                }
+                else
+                {
+                    this.random = new SecureRandom();
+                }
+
+                if (!(parameters is ECPrivateKeyParameters))
+                    throw new InvalidKeyException("EC private key required for signing");
+
+                this.key = (ECPrivateKeyParameters) parameters;
+            }
+            else
+            {
+                if (!(parameters is ECPublicKeyParameters))
+                    throw new InvalidKeyException("EC public key required for verification");
+
+                this.key = (ECPublicKeyParameters) parameters;
+            }
+        }
+
+        // Section 7.2.5 ECSP-NR, pg 34
+        /**
+         * generate a signature for the given message using the key we were
+         * initialised with.  Generally, the order of the curve should be at
+         * least as long as the hash of the message of interest, and with
+         * ECNR it *must* be at least as long.
+         *
+         * @param digest  the digest to be signed.
+         * @exception DataLengthException if the digest is longer than the key allows
+         */
+        public BigInteger[] GenerateSignature(
+            byte[] message)
+        {
+            if (!this.forSigning)
+            {
+                // not properly initilaized... deal with it
+                throw new InvalidOperationException("not initialised for signing");
+            }
+
+            BigInteger n = ((ECPrivateKeyParameters) this.key).Parameters.N;
+            int nBitLength = n.BitLength;
+
+            BigInteger e = new BigInteger(1, message);
+            int eBitLength = e.BitLength;
+
+            ECPrivateKeyParameters  privKey = (ECPrivateKeyParameters)key;
+
+            if (eBitLength > nBitLength)
+            {
+                throw new DataLengthException("input too large for ECNR key.");
+            }
+
+            BigInteger r = null;
+            BigInteger s = null;
+
+            AsymmetricCipherKeyPair tempPair;
+            do // generate r
+            {
+                // generate another, but very temporary, key pair using
+                // the same EC parameters
+                ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
+
+                keyGen.Init(new ECKeyGenerationParameters(privKey.Parameters, this.random));
+
+                tempPair = keyGen.GenerateKeyPair();
+
+                //    BigInteger Vx = tempPair.getPublic().getW().getAffineX();
+                ECPublicKeyParameters V = (ECPublicKeyParameters) tempPair.Public; // get temp's public key
+                BigInteger Vx = V.Q.AffineXCoord.ToBigInteger(); // get the point's x coordinate
+
+                r = Vx.Add(e).Mod(n);
+            }
+            while (r.SignValue == 0);
+
+            // generate s
+            BigInteger x = privKey.D;                // private key value
+            BigInteger u = ((ECPrivateKeyParameters) tempPair.Private).D; // temp's private key value
+            s = u.Subtract(r.Multiply(x)).Mod(n);
+
+            return new BigInteger[]{ r, s };
+        }
+
+        // Section 7.2.6 ECVP-NR, pg 35
+        /**
+         * return true if the value r and s represent a signature for the
+         * message passed in. Generally, the order of the curve should be at
+         * least as long as the hash of the message of interest, and with
+         * ECNR, it *must* be at least as long.  But just in case the signer
+         * applied mod(n) to the longer digest, this implementation will
+         * apply mod(n) during verification.
+         *
+         * @param digest  the digest to be verified.
+         * @param r       the r value of the signature.
+         * @param s       the s value of the signature.
+         * @exception DataLengthException if the digest is longer than the key allows
+         */
+        public bool VerifySignature(
+            byte[]		message,
+            BigInteger	r,
+            BigInteger	s)
+        {
+            if (this.forSigning)
+            {
+                // not properly initilaized... deal with it
+                throw new InvalidOperationException("not initialised for verifying");
+            }
+
+            ECPublicKeyParameters pubKey = (ECPublicKeyParameters)key;
+            BigInteger n = pubKey.Parameters.N;
+            int nBitLength = n.BitLength;
+
+            BigInteger e = new BigInteger(1, message);
+            int eBitLength = e.BitLength;
+
+            if (eBitLength > nBitLength)
+            {
+                throw new DataLengthException("input too large for ECNR key.");
+            }
+
+            // r in the range [1,n-1]
+            if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
+            {
+                return false;
+            }
+
+            // s in the range [0,n-1]           NB: ECNR spec says 0
+            if (s.CompareTo(BigInteger.Zero) < 0 || s.CompareTo(n) >= 0)
+            {
+                return false;
+            }
+
+            // compute P = sG + rW
+
+            ECPoint G = pubKey.Parameters.G;
+            ECPoint W = pubKey.Q;
+            // calculate P using Bouncy math
+            ECPoint P = ECAlgorithms.SumOfTwoMultiplies(G, s, W, r).Normalize();
+
+            if (P.IsInfinity)
+                return false;
+
+            BigInteger x = P.AffineXCoord.ToBigInteger();
+            BigInteger t = r.Subtract(x).Mod(n);
+
+            return t.Equals(e);
+        }
+    }
 }
diff --git a/crypto/src/crypto/signers/GOST3410DigestSigner.cs b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
new file mode 100644
index 000000000..58aefa368
--- /dev/null
+++ b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+	public class Gost3410DigestSigner
+		: ISigner
+	{
+		private readonly IDigest digest;
+		private readonly IDsa dsaSigner;
+		private bool forSigning;
+
+		public Gost3410DigestSigner(
+			IDsa	signer,
+			IDigest	digest)
+		{
+			this.dsaSigner = signer;
+			this.digest = digest;
+		}
+
+		public string AlgorithmName
+		{
+			get { return digest.AlgorithmName + "with" + dsaSigner.AlgorithmName; }
+		}
+
+		public void Init(
+			bool				forSigning,
+			ICipherParameters	parameters)
+		{
+			this.forSigning = forSigning;
+
+			AsymmetricKeyParameter k;
+			if (parameters is ParametersWithRandom)
+			{
+				k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+			}
+			else
+			{
+				k = (AsymmetricKeyParameter)parameters;
+			}
+
+			if (forSigning && !k.IsPrivate)
+			{
+				throw new InvalidKeyException("Signing Requires Private Key.");
+			}
+
+			if (!forSigning && k.IsPrivate)
+			{
+				throw new InvalidKeyException("Verification Requires Public Key.");
+			}
+
+			Reset();
+
+			dsaSigner.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 BlockUpdate(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			digest.BlockUpdate(input, inOff, length);
+		}
+
+		/**
+		 * Generate a signature for the message we've been loaded with using
+		 * the key we were initialised with.
+		 */
+		public byte[] GenerateSignature()
+		{
+			if (!forSigning)
+				throw new InvalidOperationException("GOST3410DigestSigner not initialised for signature generation.");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			try
+			{
+				BigInteger[] sig = dsaSigner.GenerateSignature(hash);
+				byte[] sigBytes = new byte[64];
+
+				// TODO Add methods to allow writing BigInteger to existing byte array?
+				byte[] r = sig[0].ToByteArrayUnsigned();
+				byte[] s = sig[1].ToByteArrayUnsigned();
+				s.CopyTo(sigBytes, 32 - s.Length);
+				r.CopyTo(sigBytes, 64 - r.Length);
+				return sigBytes;
+			}
+			catch (Exception e)
+			{
+				throw new SignatureException(e.Message, e);
+			}
+		}
+
+		/// <returns>true if the internal state represents the signature described in the passed in array.</returns>
+		public bool VerifySignature(
+			byte[] signature)
+		{
+			if (forSigning)
+				throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			BigInteger R, S;
+			try
+			{
+				R = new BigInteger(1, signature, 32, 32);
+				S = new BigInteger(1, signature, 0, 32);
+			}
+			catch (Exception e)
+			{
+				throw new SignatureException("error decoding signature bytes.", e);
+			}
+
+			return dsaSigner.VerifySignature(hash, R, S);
+		}
+
+		/// <summary>Reset the internal state</summary>
+		public void Reset()
+		{
+			digest.Reset();
+		}
+	}
+}
diff --git a/crypto/src/crypto/signers/GOST3410Signer.cs b/crypto/src/crypto/signers/GOST3410Signer.cs
new file mode 100644
index 000000000..375eeb5cc
--- /dev/null
+++ b/crypto/src/crypto/signers/GOST3410Signer.cs
@@ -0,0 +1,132 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+	/**
+	 * Gost R 34.10-94 Signature Algorithm
+	 */
+	public class Gost3410Signer
+		: IDsa
+	{
+		private Gost3410KeyParameters key;
+		private SecureRandom random;
+
+		public string AlgorithmName
+		{
+			get { return "GOST3410"; }
+		}
+
+		public void Init(
+			bool				forSigning,
+			ICipherParameters	parameters)
+		{
+			if (forSigning)
+			{
+				if (parameters is ParametersWithRandom)
+				{
+					ParametersWithRandom rParam = (ParametersWithRandom)parameters;
+
+					this.random = rParam.Random;
+					parameters = rParam.Parameters;
+				}
+				else
+				{
+					this.random = new SecureRandom();
+				}
+
+				if (!(parameters is Gost3410PrivateKeyParameters))
+					throw new InvalidKeyException("GOST3410 private key required for signing");
+
+				this.key = (Gost3410PrivateKeyParameters) parameters;
+			}
+			else
+			{
+				if (!(parameters is Gost3410PublicKeyParameters))
+					throw new InvalidKeyException("GOST3410 public key required for signing");
+
+				this.key = (Gost3410PublicKeyParameters) parameters;
+			}
+		}
+
+		/**
+		 * generate a signature for the given message using the key we were
+		 * initialised with. For conventional Gost3410 the message should be a Gost3411
+		 * hash of the message of interest.
+		 *
+		 * @param message the message that will be verified later.
+		 */
+		public BigInteger[] GenerateSignature(
+			byte[] message)
+		{
+			byte[] mRev = new byte[message.Length]; // conversion is little-endian
+			for (int i = 0; i != mRev.Length; i++)
+			{
+				mRev[i] = message[mRev.Length - 1 - i];
+			}
+
+			BigInteger m = new BigInteger(1, mRev);
+			Gost3410Parameters parameters = key.Parameters;
+			BigInteger k;
+
+			do
+			{
+				k = new BigInteger(parameters.Q.BitLength, random);
+			}
+			while (k.CompareTo(parameters.Q) >= 0);
+
+			BigInteger r = parameters.A.ModPow(k, parameters.P).Mod(parameters.Q);
+
+			BigInteger s = k.Multiply(m).
+				Add(((Gost3410PrivateKeyParameters)key).X.Multiply(r)).
+				Mod(parameters.Q);
+
+			return new BigInteger[]{ r, s };
+		}
+
+		/**
+		 * return true if the value r and s represent a Gost3410 signature for
+		 * the passed in message for standard Gost3410 the message should be a
+		 * Gost3411 hash of the real message to be verified.
+		 */
+		public bool VerifySignature(
+			byte[]		message,
+			BigInteger	r,
+			BigInteger	s)
+		{
+			byte[] mRev = new byte[message.Length]; // conversion is little-endian
+			for (int i = 0; i != mRev.Length; i++)
+			{
+				mRev[i] = message[mRev.Length - 1 - i];
+			}
+
+			BigInteger m = new BigInteger(1, mRev);
+			Gost3410Parameters parameters = key.Parameters;
+
+			if (r.SignValue < 0 || parameters.Q.CompareTo(r) <= 0)
+			{
+				return false;
+			}
+
+			if (s.SignValue < 0 || parameters.Q.CompareTo(s) <= 0)
+			{
+				return false;
+			}
+
+			BigInteger v = m.ModPow(parameters.Q.Subtract(BigInteger.Two), parameters.Q);
+
+			BigInteger z1 = s.Multiply(v).Mod(parameters.Q);
+			BigInteger z2 = (parameters.Q.Subtract(r)).Multiply(v).Mod(parameters.Q);
+
+			z1 = parameters.A.ModPow(z1, parameters.P);
+			z2 = ((Gost3410PublicKeyParameters)key).Y.ModPow(z2, parameters.P);
+
+			BigInteger u = z1.Multiply(z2).Mod(parameters.P).Mod(parameters.Q);
+
+			return u.Equals(r);
+		}
+	}
+}
diff --git a/crypto/src/crypto/signers/GenericSigner.cs b/crypto/src/crypto/signers/GenericSigner.cs
new file mode 100644
index 000000000..1a53eee2b
--- /dev/null
+++ b/crypto/src/crypto/signers/GenericSigner.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+	public class GenericSigner
+		: ISigner
+	{
+		private readonly IAsymmetricBlockCipher engine;
+		private readonly IDigest digest;
+		private bool forSigning;
+
+		public GenericSigner(
+			IAsymmetricBlockCipher	engine,
+			IDigest					digest)
+		{
+			this.engine = engine;
+			this.digest = digest;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Generic(" + engine.AlgorithmName + "/" + digest.AlgorithmName + ")"; }
+		}
+
+		/**
+		* initialise the signer for signing or verification.
+		*
+		* @param forSigning
+		*            true if for signing, false otherwise
+		* @param parameters
+		*            necessary parameters.
+		*/
+		public void Init(
+			bool				forSigning,
+			ICipherParameters	parameters)
+		{
+			this.forSigning = forSigning;
+			AsymmetricKeyParameter k;
+
+			if (parameters is ParametersWithRandom)
+			{
+				k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+			}
+			else
+			{
+				k = (AsymmetricKeyParameter)parameters;
+			}
+
+            if (forSigning && !k.IsPrivate)
+                throw new InvalidKeyException("Signing requires private key.");
+
+			if (!forSigning && k.IsPrivate)
+                throw new InvalidKeyException("Verification requires public key.");
+
+			Reset();
+
+			engine.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 BlockUpdate(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			digest.BlockUpdate(input, inOff, length);
+		}
+
+		/**
+		* Generate a signature for the message we've been loaded with using the key
+		* we were initialised with.
+		*/
+		public byte[] GenerateSignature()
+		{
+			if (!forSigning)
+				throw new InvalidOperationException("GenericSigner not initialised for signature generation.");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			return engine.ProcessBlock(hash, 0, hash.Length);
+		}
+
+		/**
+		* return true if the internal state represents the signature described in
+		* the passed in array.
+		*/
+		public bool VerifySignature(
+			byte[] signature)
+		{
+			if (forSigning)
+				throw new InvalidOperationException("GenericSigner not initialised for verification");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+			digest.DoFinal(hash, 0);
+
+			try
+			{
+				byte[] sig = engine.ProcessBlock(signature, 0, signature.Length);
+
+				return Arrays.ConstantTimeAreEqual(sig, hash);
+			}
+			catch (Exception)
+			{
+				return false;
+			}
+		}
+
+		public void Reset()
+		{
+			digest.Reset();
+		}
+	}
+}
diff --git a/crypto/src/crypto/signers/HMacDsaKCalculator.cs b/crypto/src/crypto/signers/HMacDsaKCalculator.cs
new file mode 100644
index 000000000..8231197b9
--- /dev/null
+++ b/crypto/src/crypto/signers/HMacDsaKCalculator.cs
@@ -0,0 +1,150 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    /**
+     * A deterministic K calculator based on the algorithm in section 3.2 of RFC 6979.
+     */
+    public class HMacDsaKCalculator
+        :   IDsaKCalculator
+    {
+        private readonly HMac hMac;
+        private readonly byte[] K;
+        private readonly byte[] V;
+
+        private BigInteger n;
+
+        /**
+         * Base constructor.
+         *
+         * @param digest digest to build the HMAC on.
+         */
+        public HMacDsaKCalculator(IDigest digest)
+        {
+            this.hMac = new HMac(digest);
+            this.V = new byte[hMac.GetMacSize()];
+            this.K = new byte[hMac.GetMacSize()];
+        }
+
+        public virtual bool IsDeterministic
+        {
+            get { return true; }
+        }
+
+        public virtual void Init(BigInteger n, SecureRandom random)
+        {
+            throw new InvalidOperationException("Operation not supported");
+        }
+
+        public void Init(BigInteger n, BigInteger d, byte[] message)
+        {
+            this.n = n;
+
+            Arrays.Fill(V, (byte)0x01);
+            Arrays.Fill(K, (byte)0);
+
+            byte[] x = new byte[(n.BitLength + 7) / 8];
+            byte[] dVal = BigIntegers.AsUnsignedByteArray(d);
+
+            Array.Copy(dVal, 0, x, x.Length - dVal.Length, dVal.Length);
+
+            byte[] m = new byte[(n.BitLength + 7) / 8];
+
+            BigInteger mInt = BitsToInt(message);
+
+            if (mInt.CompareTo(n) >= 0)
+            {
+                mInt = mInt.Subtract(n);
+            }
+
+            byte[] mVal = BigIntegers.AsUnsignedByteArray(mInt);
+
+            Array.Copy(mVal, 0, m, m.Length - mVal.Length, mVal.Length);
+
+            hMac.Init(new KeyParameter(K));
+
+            hMac.BlockUpdate(V, 0, V.Length);
+            hMac.Update((byte)0x00);
+            hMac.BlockUpdate(x, 0, x.Length);
+            hMac.BlockUpdate(m, 0, m.Length);
+
+            hMac.DoFinal(K, 0);
+
+            hMac.Init(new KeyParameter(K));
+
+            hMac.BlockUpdate(V, 0, V.Length);
+
+            hMac.DoFinal(V, 0);
+
+            hMac.BlockUpdate(V, 0, V.Length);
+            hMac.Update((byte)0x01);
+            hMac.BlockUpdate(x, 0, x.Length);
+            hMac.BlockUpdate(m, 0, m.Length);
+
+            hMac.DoFinal(K, 0);
+
+            hMac.Init(new KeyParameter(K));
+
+            hMac.BlockUpdate(V, 0, V.Length);
+
+            hMac.DoFinal(V, 0);
+        }
+
+        public virtual BigInteger NextK()
+        {
+            byte[] t = new byte[((n.BitLength + 7) / 8)];
+
+            for (;;)
+            {
+                int tOff = 0;
+
+                while (tOff < t.Length)
+                {
+                    hMac.BlockUpdate(V, 0, V.Length);
+
+                    hMac.DoFinal(V, 0);
+
+                    int len = System.Math.Min(t.Length - tOff, V.Length);
+                    Array.Copy(V, 0, t, tOff, len);
+                    tOff += len;
+                }
+
+                BigInteger k = BitsToInt(t);
+
+                if (k.SignValue > 0 && k.CompareTo(n) < 0)
+                {
+                    return k;
+                }
+
+                hMac.BlockUpdate(V, 0, V.Length);
+                hMac.Update((byte)0x00);
+
+                hMac.DoFinal(K, 0);
+
+                hMac.Init(new KeyParameter(K));
+
+                hMac.BlockUpdate(V, 0, V.Length);
+
+                hMac.DoFinal(V, 0);
+            }
+        }
+
+        private BigInteger BitsToInt(byte[] t)
+        {
+            BigInteger v = new BigInteger(1, t);
+
+            if (t.Length * 8 > n.BitLength)
+            {
+                v = v.ShiftRight(t.Length * 8 - n.BitLength);
+            }
+
+            return v;
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/IDsaKCalculator.cs b/crypto/src/crypto/signers/IDsaKCalculator.cs
new file mode 100644
index 000000000..645186d41
--- /dev/null
+++ b/crypto/src/crypto/signers/IDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    /**
+     * Interface define calculators of K values for DSA/ECDSA.
+     */
+    public interface IDsaKCalculator
+    {
+        /**
+         * Return true if this calculator is deterministic, false otherwise.
+         *
+         * @return true if deterministic, otherwise false.
+         */
+        bool IsDeterministic { get; }
+
+        /**
+         * Non-deterministic initialiser.
+         *
+         * @param n the order of the DSA group.
+         * @param random a source of randomness.
+         */
+        void Init(BigInteger n, SecureRandom random);
+
+        /**
+         * Deterministic initialiser.
+         *
+         * @param n the order of the DSA group.
+         * @param d the DSA private value.
+         * @param message the message being signed.
+         */
+        void Init(BigInteger n, BigInteger d, byte[] message);
+
+        /**
+         * Return the next valid value of K.
+         *
+         * @return a K value.
+         */
+        BigInteger NextK();
+    }
+}
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index 48cd719e9..d4f6c5522 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections;
 
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Parameters;
@@ -7,570 +8,610 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
-	/// <summary> ISO9796-2 - mechanism using a hash function with recovery (scheme 2 and 3).
-	/// <p>
-	/// Note: the usual length for the salt is the length of the hash
-	/// function used in bytes.</p>
-	/// </summary>
-	public class Iso9796d2PssSigner
-		: ISignerWithRecovery
-	{
-		/// <summary>
-		/// Return a reference to the recoveredMessage message.
-		/// </summary>
-		/// <returns>The full/partial recoveredMessage message.</returns>
-		/// <seealso cref="ISignerWithRecovery.GetRecoveredMessage"/>
-		public byte[] GetRecoveredMessage()
-		{
-			return recoveredMessage;
-		}
-
-		public const int TrailerImplicit = 0xBC;
-		public const int TrailerRipeMD160 = 0x31CC;
-		public const int TrailerRipeMD128 = 0x32CC;
-		public const int TrailerSha1 = 0x33CC;
-
-		private IDigest digest;
-		private IAsymmetricBlockCipher cipher;
-
-		private SecureRandom random;
-		private byte[] standardSalt;
-
-		private int hLen;
-		private int trailer;
-		private int keyBits;
-		private byte[] block;
-		private byte[] mBuf;
-		private int messageLength;
-		private readonly int saltLength;
-		private bool fullMessage;
-		private byte[] recoveredMessage;
-
-		/// <summary>
-		/// Generate a signer for the with either implicit or explicit trailers
-		/// for ISO9796-2, scheme 2 or 3.
-		/// </summary>
-		/// <param name="cipher">base cipher to use for signature creation/verification</param>
-		/// <param name="digest">digest to use.</param>
-		/// <param name="saltLength">length of salt in bytes.</param>
-		/// <param name="isImplicit">whether or not the trailer is implicit or gives the hash.</param>
-		public Iso9796d2PssSigner(
-			IAsymmetricBlockCipher	cipher,
-			IDigest					digest,
-			int						saltLength,
-			bool					isImplicit)
-		{
-			this.cipher = cipher;
-			this.digest = digest;
-			this.hLen = digest.GetDigestSize();
-			this.saltLength = saltLength;
-
-			if (isImplicit)
-			{
-				trailer = TrailerImplicit;
-			}
-			else
-			{
-				if (digest is Sha1Digest)
-				{
-					trailer = TrailerSha1;
-				}
-				else if (digest is RipeMD160Digest)
-				{
-					trailer = TrailerRipeMD160;
-				}
-				else if (digest is RipeMD128Digest)
-				{
-					trailer = TrailerRipeMD128;
-				}
-				else
-				{
-					throw new ArgumentException("no valid trailer for digest");
-				}
-			}
-		}
-
-		/// <summary> Constructor for a signer with an explicit digest trailer.
-		///
-		/// </summary>
-		/// <param name="cipher">cipher to use.
-		/// </param>
-		/// <param name="digest">digest to sign with.
-		/// </param>
-		/// <param name="saltLength">length of salt in bytes.
-		/// </param>
-		public Iso9796d2PssSigner(
-			IAsymmetricBlockCipher	cipher,
-			IDigest					digest,
-			int						saltLength)
-			: this(cipher, digest, saltLength, false)
-		{
-		}
-
-		public string AlgorithmName
-		{
-			get { return digest.AlgorithmName + "with" + "ISO9796-2S2"; }
-		}
-
-		/// <summary>Initialise the signer.</summary>
-		/// <param name="forSigning">true if for signing, false if for verification.</param>
-		/// <param name="parameters">parameters for signature generation/verification. If the
-		/// parameters are for generation they should be a ParametersWithRandom,
-		/// a ParametersWithSalt, or just an RsaKeyParameters object. If RsaKeyParameters
-		/// are passed in a SecureRandom will be created.
-		/// </param>
-		/// <exception cref="ArgumentException">if wrong parameter type or a fixed
-		/// salt is passed in which is the wrong length.
-		/// </exception>
-		public virtual void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
-		{
-			RsaKeyParameters kParam;
-			if (parameters is ParametersWithRandom)
-			{
-				ParametersWithRandom p = (ParametersWithRandom) parameters;
-
-				kParam = (RsaKeyParameters) p.Parameters;
-
-				if (forSigning)
-				{
-					random = p.Random;
-				}
-			}
-			else if (parameters is ParametersWithSalt)
-			{
-				if (!forSigning)
-					throw new ArgumentException("ParametersWithSalt only valid for signing", "parameters");
-
-				ParametersWithSalt p = (ParametersWithSalt) parameters;
-
-				kParam = (RsaKeyParameters) p.Parameters;
-				standardSalt = p.GetSalt();
-
-				if (standardSalt.Length != saltLength)
-					throw new ArgumentException("Fixed salt is of wrong length");
-			}
-			else
-			{
-				kParam = (RsaKeyParameters) parameters;
-
-				if (forSigning)
-				{
-					random = new SecureRandom();
-				}
-			}
-
-			cipher.Init(forSigning, kParam);
-
-			keyBits = kParam.Modulus.BitLength;
-
-			block = new byte[(keyBits + 7) / 8];
-
-			if (trailer == TrailerImplicit)
-			{
-				mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1];
-			}
-			else
-			{
-				mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 2];
-			}
-
-			Reset();
-		}
-
-		/// <summary> compare two byte arrays - constant time.</summary>
-		private bool IsSameAs(byte[] a, byte[] b)
-		{
-			if (messageLength != b.Length)
-			{
-				return false;
-			}
-
-			bool isOkay = true;
-
-			for (int i = 0; i != b.Length; i++)
-			{
-				if (a[i] != b[i])
-				{
-					isOkay = false;
-				}
-			}
-
-			return isOkay;
-		}
-
-		/// <summary> clear possible sensitive data</summary>
-		private void  ClearBlock(
-			byte[] block)
-		{
-			Array.Clear(block, 0, block.Length);
-		}
-
-		public virtual void UpdateWithRecoveredMessage(
-			byte[] signature)
-		{
-			// TODO
-			throw Platform.CreateNotImplementedException("UpdateWithRecoveredMessage");
-		}
-
-		/// <summary> update the internal digest with the byte b</summary>
-		public virtual void Update(
-			byte input)
-		{
-			if (messageLength < mBuf.Length)
-			{
-				mBuf[messageLength++] = input;
-			}
-			else
-			{
-				digest.Update(input);
-			}
-		}
-
-		/// <summary> update the internal digest with the byte array in</summary>
-		public virtual void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		length)
-		{
-			while (length > 0 && messageLength < mBuf.Length)
-			{
-				this.Update(input[inOff]);
-				inOff++;
-				length--;
-			}
-
-			if (length > 0)
-			{
-				digest.BlockUpdate(input, inOff, length);
-			}
-		}
-
-		/// <summary> reset the internal state</summary>
-		public virtual void Reset()
-		{
-			digest.Reset();
-			messageLength = 0;
-			if (mBuf != null)
-			{
-				ClearBlock(mBuf);
-			}
-			if (recoveredMessage != null)
-			{
-				ClearBlock(recoveredMessage);
-				recoveredMessage = null;
-			}
-			fullMessage = false;
-		}
-
-		/// <summary> Generate a signature for the loaded message using the key we were
-		/// initialised with.
-		/// </summary>
-		public byte[] GenerateSignature()
-		{
-			int digSize = digest.GetDigestSize();
-			byte[] m2Hash = new byte[digSize];
-			digest.DoFinal(m2Hash, 0);
-
-			byte[] C = new byte[8];
-			LtoOSP(messageLength * 8, C);
-
-			digest.BlockUpdate(C, 0, C.Length);
-			digest.BlockUpdate(mBuf, 0, messageLength);
-			digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
-
-			byte[] salt;
-			if (standardSalt != null)
-			{
-				salt = standardSalt;
-			}
-			else
-			{
-				salt = new byte[saltLength];
-				random.NextBytes(salt);
-			}
-
-			digest.BlockUpdate(salt, 0, salt.Length);
-
-			byte[] hash = new byte[digest.GetDigestSize()];
-			digest.DoFinal(hash, 0);
-
-			int tLength = 2;
-			if (trailer == TrailerImplicit)
-			{
-				tLength = 1;
-			}
-
-			int off = block.Length - messageLength - salt.Length - hLen - tLength - 1;
-
-			block[off] = (byte) (0x01);
-
-			Array.Copy(mBuf, 0, block, off + 1, messageLength);
-			Array.Copy(salt, 0, block, off + 1 + messageLength, salt.Length);
-
-			byte[] dbMask = MaskGeneratorFunction1(hash, 0, hash.Length, block.Length - hLen - tLength);
-			for (int i = 0; i != dbMask.Length; i++)
-			{
-				block[i] ^= dbMask[i];
-			}
-
-			Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen);
-
-			if (trailer == TrailerImplicit)
-			{
-				block[block.Length - 1] = (byte)TrailerImplicit;
-			}
-			else
-			{
-				block[block.Length - 2] = (byte) ((uint)trailer >> 8);
-				block[block.Length - 1] = (byte) trailer;
-			}
-
-			block[0] &= (byte) (0x7f);
-
-			byte[] b = cipher.ProcessBlock(block, 0, block.Length);
-
-			ClearBlock(mBuf);
-			ClearBlock(block);
-			messageLength = 0;
-
-			return b;
-		}
-
-		/// <summary> return true if the signature represents a ISO9796-2 signature
-		/// for the passed in message.
-		/// </summary>
-		public virtual bool VerifySignature(
-			byte[] signature)
-		{
-			byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
-
-			//
-			// adjust block size for leading zeroes if necessary
-			//
-			int expectedSize = (keyBits + 7) / 8;
-			if (block.Length < expectedSize)
-			{
-				byte[] tmp = new byte[expectedSize];
-				block.CopyTo(tmp, tmp.Length - block.Length);
-				ClearBlock(block);
-				block = tmp;
-			}
-
-			int tLength;
-
-			if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
-			{
-				tLength = 1;
-			}
-			else
-			{
-				int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
-
-				switch (sigTrail)
-				{
-					case TrailerRipeMD160:
-						if (!(digest is RipeMD160Digest))
-						{
-							throw new ArgumentException("signer should be initialised with RipeMD160");
-						}
-						break;
-					case TrailerSha1:
-						if (!(digest is Sha1Digest))
-						{
-							throw new ArgumentException("signer should be initialised with SHA1");
-						}
-						break;
-					case TrailerRipeMD128:
-						if (!(digest is RipeMD128Digest))
-						{
-							throw new ArgumentException("signer should be initialised with RipeMD128");
-						}
-						break;
-					default:
-						throw new ArgumentException("unrecognised hash in signature");
-				}
-
-				tLength = 2;
-			}
-
-			//
-			// calculate H(m2)
-			//
-			byte[] m2Hash = new byte[hLen];
-			digest.DoFinal(m2Hash, 0);
-
-			//
-			// remove the mask
-			//
-			byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - tLength, hLen, block.Length - hLen - tLength);
-			for (int i = 0; i != dbMask.Length; i++)
-			{
-				block[i] ^= dbMask[i];
-			}
-
-			block[0] &= 0x7f;
-
-			//
-			// find out how much padding we've got
-			//
-			int mStart = 0;
-			while (mStart < block.Length)
-			{
-				if (block[mStart++] == 0x01)
-					break;
-			}
-
-			if (mStart >= block.Length)
-			{
-				ClearBlock(block);
-				return false;
-			}
-
-			fullMessage = (mStart > 1);
-
-			// TODO Should we check if a standardSalt was set and, if so, use its length instead?
-			recoveredMessage = new byte[dbMask.Length - mStart - saltLength];
-
-			Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
-
-			//
-			// check the hashes
-			//
-			byte[] C = new byte[8];
-			LtoOSP(recoveredMessage.Length * 8, C);
-
-			digest.BlockUpdate(C, 0, C.Length);
-
-			if (recoveredMessage.Length != 0)
-			{
-				digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
-			}
-
-			digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
-
-			// Update for the salt
-			digest.BlockUpdate(block, mStart + recoveredMessage.Length, saltLength);
-
-			byte[] hash = new byte[digest.GetDigestSize()];
-			digest.DoFinal(hash, 0);
-
-			int off = block.Length - tLength - hash.Length;
-
-			// TODO ConstantTimeAreEqual with offset for one array
-
-			bool isOkay = true;
-			for (int i = 0; i != hash.Length; i++)
-			{
-				if (hash[i] != block[off + i])
-				{
-					isOkay = false;
-				}
-			}
-
-			ClearBlock(block);
-			ClearBlock(hash);
-
-			if (!isOkay)
-			{
-				fullMessage = false;
-				ClearBlock(recoveredMessage);
-				return false;
-			}
-
-			//
-			// if they've input a message check what we've recovered against
-			// what was input.
-			//
-			if (messageLength != 0)
-			{
-				if (!IsSameAs(mBuf, recoveredMessage))
-				{
-					ClearBlock(mBuf);
-					return false;
-				}
-
-				messageLength = 0;
-			}
-
-			ClearBlock(mBuf);
-			return true;
-		}
-
-		/// <summary>
-		/// Return true if the full message was recoveredMessage.
-		/// </summary>
-		/// <returns>true on full message recovery, false otherwise, or if not sure.</returns>
-		/// <seealso cref="ISignerWithRecovery.HasFullMessage"/>
-		public virtual bool HasFullMessage()
-		{
-			return fullMessage;
-		}
-
-		/// <summary> int to octet string.</summary>
-		/// <summary> int to octet string.</summary>
-		private void ItoOSP(
-			int		i,
-			byte[]	sp)
-		{
-			sp[0] = (byte)((uint)i >> 24);
-			sp[1] = (byte)((uint)i >> 16);
-			sp[2] = (byte)((uint)i >> 8);
-			sp[3] = (byte)((uint)i >> 0);
-		}
-
-		/// <summary> long to octet string.</summary>
-		private void  LtoOSP(long l, byte[] sp)
-		{
-			sp[0] = (byte)((ulong)l >> 56);
-			sp[1] = (byte)((ulong)l >> 48);
-			sp[2] = (byte)((ulong)l >> 40);
-			sp[3] = (byte)((ulong)l >> 32);
-			sp[4] = (byte)((ulong)l >> 24);
-			sp[5] = (byte)((ulong)l >> 16);
-			sp[6] = (byte)((ulong)l >> 8);
-			sp[7] = (byte)((ulong)l >> 0);
-		}
-
-		/// <summary> mask generator function, as described in Pkcs1v2.</summary>
-		private byte[] MaskGeneratorFunction1(
-			byte[]	Z,
-			int		zOff,
-			int		zLen,
-			int		length)
-		{
-			byte[] mask = new byte[length];
-			byte[] hashBuf = new byte[hLen];
-			byte[] C = new byte[4];
-			int counter = 0;
-
-			digest.Reset();
-
-			do
-			{
-				ItoOSP(counter, C);
-
-				digest.BlockUpdate(Z, zOff, zLen);
-				digest.BlockUpdate(C, 0, C.Length);
-				digest.DoFinal(hashBuf, 0);
-
-				Array.Copy(hashBuf, 0, mask, counter * hLen, hLen);
-			}
-			while (++counter < (length / hLen));
-
-			if ((counter * hLen) < length)
-			{
-				ItoOSP(counter, C);
-
-				digest.BlockUpdate(Z, zOff, zLen);
-				digest.BlockUpdate(C, 0, C.Length);
-				digest.DoFinal(hashBuf, 0);
-
-				Array.Copy(hashBuf, 0, mask, counter * hLen, mask.Length - (counter * hLen));
-			}
-
-			return mask;
-		}
-	}
+    /// <summary> ISO9796-2 - mechanism using a hash function with recovery (scheme 2 and 3).
+    /// <p>
+    /// Note: the usual length for the salt is the length of the hash
+    /// function used in bytes.</p>
+    /// </summary>
+    public class Iso9796d2PssSigner
+        : ISignerWithRecovery
+    {
+        /// <summary>
+        /// Return a reference to the recoveredMessage message.
+        /// </summary>
+        /// <returns>The full/partial recoveredMessage message.</returns>
+        /// <seealso cref="ISignerWithRecovery.GetRecoveredMessage"/>
+        public byte[] GetRecoveredMessage()
+        {
+            return recoveredMessage;
+        }
+
+        public const int TrailerImplicit = 0xBC;
+        public const int TrailerRipeMD160 = 0x31CC;
+        public const int TrailerRipeMD128 = 0x32CC;
+        public const int TrailerSha1 = 0x33CC;
+        public const int TrailerSha256 = 0x34CC;
+        public const int TrailerSha512 = 0x35CC;
+        public const int TrailerSha384 = 0x36CC;
+        public const int TrailerWhirlpool = 0x37CC;
+
+        private static readonly IDictionary trailerMap = Platform.CreateHashtable();
+
+        static Iso9796d2PssSigner()
+        {
+            trailerMap.Add("RIPEMD128", TrailerRipeMD128);
+            trailerMap.Add("RIPEMD160", TrailerRipeMD160);
+            trailerMap.Add("SHA-1", TrailerSha1);
+            trailerMap.Add("SHA-256", TrailerSha256);
+            trailerMap.Add("SHA-384", TrailerSha384);
+            trailerMap.Add("SHA-512", TrailerSha512);
+
+            trailerMap.Add("Whirlpool", TrailerWhirlpool);
+        }
+
+        private IDigest digest;
+        private IAsymmetricBlockCipher cipher;
+
+        private SecureRandom random;
+        private byte[] standardSalt;
+
+        private int hLen;
+        private int trailer;
+        private int keyBits;
+        private byte[] block;
+        private byte[] mBuf;
+        private int messageLength;
+        private readonly int saltLength;
+        private bool fullMessage;
+        private byte[] recoveredMessage;
+
+        private byte[] preSig;
+        private byte[] preBlock;
+        private int preMStart;
+        private int preTLength;
+
+        /// <summary>
+        /// Generate a signer for the with either implicit or explicit trailers
+        /// for ISO9796-2, scheme 2 or 3.
+        /// </summary>
+        /// <param name="cipher">base cipher to use for signature creation/verification</param>
+        /// <param name="digest">digest to use.</param>
+        /// <param name="saltLength">length of salt in bytes.</param>
+        /// <param name="isImplicit">whether or not the trailer is implicit or gives the hash.</param>
+        public Iso9796d2PssSigner(
+            IAsymmetricBlockCipher	cipher,
+            IDigest					digest,
+            int						saltLength,
+            bool					isImplicit)
+        {
+            this.cipher = cipher;
+            this.digest = digest;
+            this.hLen = digest.GetDigestSize();
+            this.saltLength = saltLength;
+
+            if (isImplicit)
+            {
+                trailer = TrailerImplicit;
+            }
+            else
+            {
+                string digestAlg = digest.AlgorithmName;
+                if (!trailerMap.Contains(digestAlg))
+                    throw new ArgumentException("no valid trailer for digest");
+
+                trailer = (int)trailerMap[digestAlg];
+            }
+        }
+
+        /// <summary> Constructor for a signer with an explicit digest trailer.
+        ///
+        /// </summary>
+        /// <param name="cipher">cipher to use.
+        /// </param>
+        /// <param name="digest">digest to sign with.
+        /// </param>
+        /// <param name="saltLength">length of salt in bytes.
+        /// </param>
+        public Iso9796d2PssSigner(
+            IAsymmetricBlockCipher	cipher,
+            IDigest					digest,
+            int						saltLength)
+            : this(cipher, digest, saltLength, false)
+        {
+        }
+
+        public string AlgorithmName
+        {
+            get { return digest.AlgorithmName + "with" + "ISO9796-2S2"; }
+        }
+
+        /// <summary>Initialise the signer.</summary>
+        /// <param name="forSigning">true if for signing, false if for verification.</param>
+        /// <param name="parameters">parameters for signature generation/verification. If the
+        /// parameters are for generation they should be a ParametersWithRandom,
+        /// a ParametersWithSalt, or just an RsaKeyParameters object. If RsaKeyParameters
+        /// are passed in a SecureRandom will be created.
+        /// </param>
+        /// <exception cref="ArgumentException">if wrong parameter type or a fixed
+        /// salt is passed in which is the wrong length.
+        /// </exception>
+        public virtual void Init(
+            bool				forSigning,
+            ICipherParameters	parameters)
+        {
+            RsaKeyParameters kParam;
+            if (parameters is ParametersWithRandom)
+            {
+                ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+                kParam = (RsaKeyParameters) p.Parameters;
+
+                if (forSigning)
+                {
+                    random = p.Random;
+                }
+            }
+            else if (parameters is ParametersWithSalt)
+            {
+                if (!forSigning)
+                    throw new ArgumentException("ParametersWithSalt only valid for signing", "parameters");
+
+                ParametersWithSalt p = (ParametersWithSalt) parameters;
+
+                kParam = (RsaKeyParameters) p.Parameters;
+                standardSalt = p.GetSalt();
+
+                if (standardSalt.Length != saltLength)
+                    throw new ArgumentException("Fixed salt is of wrong length");
+            }
+            else
+            {
+                kParam = (RsaKeyParameters) parameters;
+
+                if (forSigning)
+                {
+                    random = new SecureRandom();
+                }
+            }
+
+            cipher.Init(forSigning, kParam);
+
+            keyBits = kParam.Modulus.BitLength;
+
+            block = new byte[(keyBits + 7) / 8];
+
+            if (trailer == TrailerImplicit)
+            {
+                mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1];
+            }
+            else
+            {
+                mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 2];
+            }
+
+            Reset();
+        }
+
+        /// <summary> compare two byte arrays - constant time.</summary>
+        private bool IsSameAs(byte[] a, byte[] b)
+        {
+            if (messageLength != b.Length)
+            {
+                return false;
+            }
+
+            bool isOkay = true;
+
+            for (int i = 0; i != b.Length; i++)
+            {
+                if (a[i] != b[i])
+                {
+                    isOkay = false;
+                }
+            }
+
+            return isOkay;
+        }
+
+        /// <summary> clear possible sensitive data</summary>
+        private void  ClearBlock(
+            byte[] block)
+        {
+            Array.Clear(block, 0, block.Length);
+        }
+
+        public virtual void UpdateWithRecoveredMessage(
+            byte[] signature)
+        {
+            byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
+
+            //
+            // adjust block size for leading zeroes if necessary
+            //
+            if (block.Length < (keyBits + 7) / 8)
+            {
+                byte[] tmp = new byte[(keyBits + 7) / 8];
+
+                Array.Copy(block, 0, tmp, tmp.Length - block.Length, block.Length);
+                ClearBlock(block);
+                block = tmp;
+            }
+
+            int tLength;
+
+            if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+            {
+                tLength = 1;
+            }
+            else
+            {
+                int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+                string digestAlg = digest.AlgorithmName;
+                if (!trailerMap.Contains(digestAlg))
+                    throw new ArgumentException("unrecognised hash in signature");
+
+                if (sigTrail != (int)trailerMap[digestAlg])
+                    throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
+
+                tLength = 2;
+            }
+
+            //
+            // calculate H(m2)
+            //
+            byte[] m2Hash = new byte[hLen];
+            digest.DoFinal(m2Hash, 0);
+
+            //
+            // remove the mask
+            //
+            byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - tLength, hLen, block.Length - hLen - tLength);
+            for (int i = 0; i != dbMask.Length; i++)
+            {
+                block[i] ^= dbMask[i];
+            }
+
+            block[0] &= 0x7f;
+
+            //
+            // find out how much padding we've got
+            //
+            int mStart = 0;
+
+            while (mStart < block.Length)
+            {
+                if (block[mStart++] == 0x01)
+                    break;
+            }
+
+            if (mStart >= block.Length)
+            {
+                ClearBlock(block);
+            }
+
+            fullMessage = (mStart > 1);
+
+            recoveredMessage = new byte[dbMask.Length - mStart - saltLength];
+
+            Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+            recoveredMessage.CopyTo(mBuf, 0);
+
+            preSig = signature;
+            preBlock = block;
+            preMStart = mStart;
+            preTLength = tLength;
+        }
+
+        /// <summary> update the internal digest with the byte b</summary>
+        public virtual void Update(
+            byte input)
+        {
+            if (preSig == null && messageLength < mBuf.Length)
+            {
+                mBuf[messageLength++] = input;
+            }
+            else
+            {
+                digest.Update(input);
+            }
+        }
+
+        /// <summary> update the internal digest with the byte array in</summary>
+        public virtual void BlockUpdate(
+            byte[]	input,
+            int		inOff,
+            int		length)
+        {
+            if (preSig == null)
+            {
+                while (length > 0 && messageLength < mBuf.Length)
+                {
+                    this.Update(input[inOff]);
+                    inOff++;
+                    length--;
+                }
+            }
+
+            if (length > 0)
+            {
+                digest.BlockUpdate(input, inOff, length);
+            }
+        }
+
+        /// <summary> reset the internal state</summary>
+        public virtual void Reset()
+        {
+            digest.Reset();
+            messageLength = 0;
+            if (mBuf != null)
+            {
+                ClearBlock(mBuf);
+            }
+            if (recoveredMessage != null)
+            {
+                ClearBlock(recoveredMessage);
+                recoveredMessage = null;
+            }
+            fullMessage = false;
+            if (preSig != null)
+            {
+                preSig = null;
+                ClearBlock(preBlock);
+                preBlock = null;
+            }
+        }
+
+        /// <summary> Generate a signature for the loaded message using the key we were
+        /// initialised with.
+        /// </summary>
+        public byte[] GenerateSignature()
+        {
+            int digSize = digest.GetDigestSize();
+            byte[] m2Hash = new byte[digSize];
+            digest.DoFinal(m2Hash, 0);
+
+            byte[] C = new byte[8];
+            LtoOSP(messageLength * 8, C);
+
+            digest.BlockUpdate(C, 0, C.Length);
+            digest.BlockUpdate(mBuf, 0, messageLength);
+            digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
+
+            byte[] salt;
+            if (standardSalt != null)
+            {
+                salt = standardSalt;
+            }
+            else
+            {
+                salt = new byte[saltLength];
+                random.NextBytes(salt);
+            }
+
+            digest.BlockUpdate(salt, 0, salt.Length);
+
+            byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+            int tLength = 2;
+            if (trailer == TrailerImplicit)
+            {
+                tLength = 1;
+            }
+
+            int off = block.Length - messageLength - salt.Length - hLen - tLength - 1;
+
+            block[off] = (byte) (0x01);
+
+            Array.Copy(mBuf, 0, block, off + 1, messageLength);
+            Array.Copy(salt, 0, block, off + 1 + messageLength, salt.Length);
+
+            byte[] dbMask = MaskGeneratorFunction1(hash, 0, hash.Length, block.Length - hLen - tLength);
+            for (int i = 0; i != dbMask.Length; i++)
+            {
+                block[i] ^= dbMask[i];
+            }
+
+            Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen);
+
+            if (trailer == TrailerImplicit)
+            {
+                block[block.Length - 1] = (byte)TrailerImplicit;
+            }
+            else
+            {
+                block[block.Length - 2] = (byte) ((uint)trailer >> 8);
+                block[block.Length - 1] = (byte) trailer;
+            }
+
+            block[0] &= (byte) (0x7f);
+
+            byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+            ClearBlock(mBuf);
+            ClearBlock(block);
+            messageLength = 0;
+
+            return b;
+        }
+
+        /// <summary> return true if the signature represents a ISO9796-2 signature
+        /// for the passed in message.
+        /// </summary>
+        public virtual bool VerifySignature(
+            byte[] signature)
+        {
+            //
+            // calculate H(m2)
+            //
+            byte[] m2Hash = new byte[hLen];
+            digest.DoFinal(m2Hash, 0);
+
+            byte[] block;
+            int tLength;
+            int mStart = 0;
+
+            if (preSig == null)
+            {
+                try
+                {
+                    UpdateWithRecoveredMessage(signature);
+                }
+                catch (Exception)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if (!Arrays.AreEqual(preSig, signature))
+                {
+                    throw new InvalidOperationException("UpdateWithRecoveredMessage called on different signature");
+                }
+            }
+
+            block = preBlock;
+            mStart = preMStart;
+            tLength = preTLength;
+
+            preSig = null;
+            preBlock = null;
+
+            //
+            // check the hashes
+            //
+            byte[] C = new byte[8];
+            LtoOSP(recoveredMessage.Length * 8, C);
+
+            digest.BlockUpdate(C, 0, C.Length);
+
+            if (recoveredMessage.Length != 0)
+            {
+                digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
+            }
+
+            digest.BlockUpdate(m2Hash, 0, m2Hash.Length);
+
+            // Update for the salt
+            digest.BlockUpdate(block, mStart + recoveredMessage.Length, saltLength);
+
+            byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+            int off = block.Length - tLength - hash.Length;
+
+            bool isOkay = true;
+
+            for (int i = 0; i != hash.Length; i++)
+            {
+                if (hash[i] != block[off + i])
+                {
+                    isOkay = false;
+                }
+            }
+
+            ClearBlock(block);
+            ClearBlock(hash);
+
+            if (!isOkay)
+            {
+                fullMessage = false;
+                ClearBlock(recoveredMessage);
+                return false;
+            }
+
+            //
+            // if they've input a message check what we've recovered against
+            // what was input.
+            //
+            if (messageLength != 0)
+            {
+                if (!IsSameAs(mBuf, recoveredMessage))
+                {
+                    ClearBlock(mBuf);
+                    return false;
+                }
+                messageLength = 0;
+            }
+
+            ClearBlock(mBuf);
+            return true;
+        }
+
+        /// <summary>
+        /// Return true if the full message was recoveredMessage.
+        /// </summary>
+        /// <returns>true on full message recovery, false otherwise, or if not sure.</returns>
+        /// <seealso cref="ISignerWithRecovery.HasFullMessage"/>
+        public virtual bool HasFullMessage()
+        {
+            return fullMessage;
+        }
+
+        /// <summary> int to octet string.</summary>
+        /// <summary> int to octet string.</summary>
+        private void ItoOSP(
+            int		i,
+            byte[]	sp)
+        {
+            sp[0] = (byte)((uint)i >> 24);
+            sp[1] = (byte)((uint)i >> 16);
+            sp[2] = (byte)((uint)i >> 8);
+            sp[3] = (byte)((uint)i >> 0);
+        }
+
+        /// <summary> long to octet string.</summary>
+        private void  LtoOSP(long l, byte[] sp)
+        {
+            sp[0] = (byte)((ulong)l >> 56);
+            sp[1] = (byte)((ulong)l >> 48);
+            sp[2] = (byte)((ulong)l >> 40);
+            sp[3] = (byte)((ulong)l >> 32);
+            sp[4] = (byte)((ulong)l >> 24);
+            sp[5] = (byte)((ulong)l >> 16);
+            sp[6] = (byte)((ulong)l >> 8);
+            sp[7] = (byte)((ulong)l >> 0);
+        }
+
+        /// <summary> mask generator function, as described in Pkcs1v2.</summary>
+        private byte[] MaskGeneratorFunction1(
+            byte[]	Z,
+            int		zOff,
+            int		zLen,
+            int		length)
+        {
+            byte[] mask = new byte[length];
+            byte[] hashBuf = new byte[hLen];
+            byte[] C = new byte[4];
+            int counter = 0;
+
+            digest.Reset();
+
+            do
+            {
+                ItoOSP(counter, C);
+
+                digest.BlockUpdate(Z, zOff, zLen);
+                digest.BlockUpdate(C, 0, C.Length);
+                digest.DoFinal(hashBuf, 0);
+
+                Array.Copy(hashBuf, 0, mask, counter * hLen, hLen);
+            }
+            while (++counter < (length / hLen));
+
+            if ((counter * hLen) < length)
+            {
+                ItoOSP(counter, C);
+
+                digest.BlockUpdate(Z, zOff, zLen);
+                digest.BlockUpdate(C, 0, C.Length);
+                digest.DoFinal(hashBuf, 0);
+
+                Array.Copy(hashBuf, 0, mask, counter * hLen, mask.Length - (counter * hLen));
+            }
+
+            return mask;
+        }
+    }
 }
diff --git a/crypto/src/crypto/signers/Iso9796d2Signer.cs b/crypto/src/crypto/signers/Iso9796d2Signer.cs
index 8ff87e8ee..cfb8942e6 100644
--- a/crypto/src/crypto/signers/Iso9796d2Signer.cs
+++ b/crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -8,550 +8,556 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
-	/// <summary> ISO9796-2 - mechanism using a hash function with recovery (scheme 1)</summary>
-	public class Iso9796d2Signer : ISignerWithRecovery
-	{
-		/// <summary>
-		/// Return a reference to the recoveredMessage message.
-		/// </summary>
-		/// <returns>The full/partial recoveredMessage message.</returns>
-		/// <seealso cref="ISignerWithRecovery.GetRecoveredMessage"/>
-		public byte[] GetRecoveredMessage()
-		{
-			return recoveredMessage;
-		}
-
-		public const int TrailerImplicit = 0xBC;
-		public const int TrailerRipeMD160 = 0x31CC;
-		public const int TrailerRipeMD128 = 0x32CC;
-		public const int TrailerSha1 = 0x33CC;
-		public const int TrailerSha256 = 0x34CC;
-		public const int TrailerSha512 = 0x35CC;
-		public const int TrailerSha384 = 0x36CC;
-		public const int TrailerWhirlpool = 0x37CC;
-
-		private static IDictionary trailerMap = Platform.CreateHashtable();
-
-		static Iso9796d2Signer()
-		{
-			trailerMap.Add("RIPEMD128", TrailerRipeMD128);
-			trailerMap.Add("RIPEMD160", TrailerRipeMD160);
-
-			trailerMap.Add("SHA-1", TrailerSha1);
-			trailerMap.Add("SHA-256", TrailerSha256);
-			trailerMap.Add("SHA-384", TrailerSha384);
-			trailerMap.Add("SHA-512", TrailerSha512);
-
-			trailerMap.Add("Whirlpool", TrailerWhirlpool);
-		}
-
-		private IDigest digest;
-		private IAsymmetricBlockCipher cipher;
-
-		private int trailer;
-		private int keyBits;
-		private byte[] block;
-		private byte[] mBuf;
-		private int messageLength;
-		private bool fullMessage;
-		private byte[] recoveredMessage;
-
-		private byte[] preSig;
-		private byte[] preBlock;
-
-		/// <summary>
-		/// Generate a signer for the with either implicit or explicit trailers
-		/// for ISO9796-2.
-		/// </summary>
-		/// <param name="cipher">base cipher to use for signature creation/verification</param>
-		/// <param name="digest">digest to use.</param>
-		/// <param name="isImplicit">whether or not the trailer is implicit or gives the hash.</param>
-		public Iso9796d2Signer(
-			IAsymmetricBlockCipher	cipher,
-			IDigest					digest,
-			bool					isImplicit)
-		{
-			this.cipher = cipher;
-			this.digest = digest;
-
-			if (isImplicit)
-			{
-				trailer = TrailerImplicit;
-			}
-			else
-			{
-				string digestName = digest.AlgorithmName;
-
-				if (trailerMap.Contains(digestName))
-				{
-					trailer = (int)trailerMap[digest.AlgorithmName];
-				}
-				else
-				{
-					throw new System.ArgumentException("no valid trailer for digest");
-				}
-			}
-		}
-
-		/// <summary> Constructor for a signer with an explicit digest trailer.
-		///
-		/// </summary>
-		/// <param name="cipher">cipher to use.
-		/// </param>
-		/// <param name="digest">digest to sign with.
-		/// </param>
-		public Iso9796d2Signer(IAsymmetricBlockCipher cipher, IDigest digest)
-			: this(cipher, digest, false)
-		{
-		}
-
-		public string AlgorithmName
-		{
-			get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; }
-		}
-
-		public virtual void Init(bool forSigning, ICipherParameters parameters)
-		{
-			RsaKeyParameters kParam = (RsaKeyParameters) parameters;
-
-			cipher.Init(forSigning, kParam);
-
-			keyBits = kParam.Modulus.BitLength;
-
-			block = new byte[(keyBits + 7) / 8];
-			if (trailer == TrailerImplicit)
-			{
-				mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
-			}
-			else
-			{
-				mBuf = new byte[block.Length - digest.GetDigestSize() - 3];
-			}
-
-			Reset();
-		}
-
-		/// <summary> compare two byte arrays - constant time.</summary>
-		private bool IsSameAs(byte[] a, byte[] b)
-		{
-			int checkLen;
-			if (messageLength > mBuf.Length)
-			{
-				if (mBuf.Length > b.Length)
-				{
-					return false;
-				}
-
-				checkLen = mBuf.Length;
-			}
-			else
-			{
-				if (messageLength != b.Length)
-				{
-					return false;
-				}
-
-				checkLen = b.Length;
-			}
-
-			bool isOkay = true;
-
-			for (int i = 0; i != checkLen; i++)
-			{
-				if (a[i] != b[i])
-				{
-					isOkay = false;
-				}
-			}
-
-			return isOkay;
-		}
-
-		/// <summary> clear possible sensitive data</summary>
-		private void  ClearBlock(
-			byte[] block)
-		{
-			Array.Clear(block, 0, block.Length);
-		}
-
-		public virtual void UpdateWithRecoveredMessage(
-			byte[] signature)
-		{
-			byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
-
-			if (((block[0] & 0xC0) ^ 0x40) != 0)
-				throw new InvalidCipherTextException("malformed signature");
-
-			if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
-				throw new InvalidCipherTextException("malformed signature");
-
-			int delta = 0;
-
-			if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
-			{
-				delta = 1;
-			}
-			else
-			{
-				int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
-
-				string digestName = digest.AlgorithmName;
-				if (!trailerMap.Contains(digestName))
-					throw new ArgumentException("unrecognised hash in signature");
-				if (sigTrail != (int)trailerMap[digestName])
-					throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
-
-				delta = 2;
-			}
-
-			//
-			// find out how much padding we've got
-			//
-			int mStart = 0;
-
-			for (mStart = 0; mStart != block.Length; mStart++)
-			{
-				if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
-					break;
-			}
-
-			mStart++;
-
-			int off = block.Length - delta - digest.GetDigestSize();
-
-			//
-			// there must be at least one byte of message string
-			//
-			if ((off - mStart) <= 0)
-				throw new InvalidCipherTextException("malformed block");
-
-			//
-			// if we contain the whole message as well, check the hash of that.
-			//
-			if ((block[0] & 0x20) == 0)
-			{
-				fullMessage = true;
-
-				recoveredMessage = new byte[off - mStart];
-				Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
-			}
-			else
-			{
-				fullMessage = false;
-
-				recoveredMessage = new byte[off - mStart];
-				Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
-			}
-
-			preSig = signature;
-			preBlock = block;
-
-			digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
-			messageLength = recoveredMessage.Length;
-		}
-
-		/// <summary> update the internal digest with the byte b</summary>
-		public void Update(
-			byte input)
-		{
-			digest.Update(input);
-
-			if (preSig == null && messageLength < mBuf.Length)
-			{
-				mBuf[messageLength] = input;
-			}
-
-			messageLength++;
-		}
-
-		/// <summary> update the internal digest with the byte array in</summary>
-		public void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		length)
-		{
-			digest.BlockUpdate(input, inOff, length);
-
-			if (preSig == null && messageLength < mBuf.Length)
-			{
-				for (int i = 0; i < length && (i + messageLength) < mBuf.Length; i++)
-				{
-					mBuf[messageLength + i] = input[inOff + i];
-				}
-			}
-
-			messageLength += length;
-		}
-
-		/// <summary> reset the internal state</summary>
-		public virtual void Reset()
-		{
-			digest.Reset();
-			messageLength = 0;
-			ClearBlock(mBuf);
-
-			if (recoveredMessage != null)
-			{
-				ClearBlock(recoveredMessage);
-			}
-
-			recoveredMessage = null;
-			fullMessage = false;
-		}
-
-		/// <summary> Generate a signature for the loaded message using the key we were
-		/// initialised with.
-		/// </summary>
-		public virtual byte[] GenerateSignature()
-		{
-			int digSize = digest.GetDigestSize();
-
-			int t = 0;
-			int delta = 0;
-
-			if (trailer == TrailerImplicit)
-			{
-				t = 8;
-				delta = block.Length - digSize - 1;
-				digest.DoFinal(block, delta);
-				block[block.Length - 1] = (byte) TrailerImplicit;
-			}
-			else
-			{
-				t = 16;
-				delta = block.Length - digSize - 2;
-				digest.DoFinal(block, delta);
-				block[block.Length - 2] = (byte) ((uint)trailer >> 8);
-				block[block.Length - 1] = (byte) trailer;
-			}
-
-			byte header = 0;
-			int x = (digSize + messageLength) * 8 + t + 4 - keyBits;
-
-			if (x > 0)
-			{
-				int mR = messageLength - ((x + 7) / 8);
-				header = (byte) (0x60);
-
-				delta -= mR;
-
-				Array.Copy(mBuf, 0, block, delta, mR);
-			}
-			else
-			{
-				header = (byte) (0x40);
-				delta -= messageLength;
-
-				Array.Copy(mBuf, 0, block, delta, messageLength);
-			}
-
-			if ((delta - 1) > 0)
-			{
-				for (int i = delta - 1; i != 0; i--)
-				{
-					block[i] = (byte) 0xbb;
-				}
-				block[delta - 1] ^= (byte) 0x01;
-				block[0] = (byte) 0x0b;
-				block[0] |= header;
-			}
-			else
-			{
-				block[0] = (byte) 0x0a;
-				block[0] |= header;
-			}
-
-			byte[] b = cipher.ProcessBlock(block, 0, block.Length);
-
-			ClearBlock(mBuf);
-			ClearBlock(block);
-
-			return b;
-		}
-
-		/// <summary> return true if the signature represents a ISO9796-2 signature
-		/// for the passed in message.
-		/// </summary>
-		public virtual bool VerifySignature(byte[] signature)
-		{
-			byte[] block;
-			bool updateWithRecoveredCalled;
-
-			if (preSig == null)
-			{
-				updateWithRecoveredCalled = false;
-				try
-				{
-					block = cipher.ProcessBlock(signature, 0, signature.Length);
-				}
-				catch (Exception)
-				{
-					return false;
-				}
-			}
-			else
-			{
-				if (!Arrays.AreEqual(preSig, signature))
-					throw new InvalidOperationException("updateWithRecoveredMessage called on different signature");
-
-				updateWithRecoveredCalled = true;
-				block = preBlock;
-
-				preSig = null;
-				preBlock = null;
-			}
-
-			if (((block[0] & 0xC0) ^ 0x40) != 0)
-				return ReturnFalse(block);
-
-			if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
-				return ReturnFalse(block);
-
-			int delta = 0;
-
-			if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
-			{
-				delta = 1;
-			}
-			else
-			{
-				int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
-
-				string digestName = digest.AlgorithmName;
-				if (!trailerMap.Contains(digestName))
-					throw new ArgumentException("unrecognised hash in signature");
-				if (sigTrail != (int)trailerMap[digestName])
-					throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
-
-				delta = 2;
-			}
-
-			//
-			// find out how much padding we've got
-			//
-			int mStart = 0;
-			for (; mStart != block.Length; mStart++)
-			{
-				if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
-				{
-					break;
-				}
-			}
-
-			mStart++;
-
-			//
-			// check the hashes
-			//
-			byte[] hash = new byte[digest.GetDigestSize()];
-
-			int off = block.Length - delta - hash.Length;
-
-			//
-			// there must be at least one byte of message string
-			//
-			if ((off - mStart) <= 0)
-			{
-				return ReturnFalse(block);
-			}
-
-			//
-			// if we contain the whole message as well, check the hash of that.
-			//
-			if ((block[0] & 0x20) == 0)
-			{
-				fullMessage = true;
-
-				// check right number of bytes passed in.
-				if (messageLength > off - mStart)
-				{
-					return ReturnFalse(block);
-				}
-
-				digest.Reset();
-				digest.BlockUpdate(block, mStart, off - mStart);
-				digest.DoFinal(hash, 0);
-
-				bool isOkay = true;
-				
-				for (int i = 0; i != hash.Length; i++)
-				{
-					block[off + i] ^= hash[i];
-					if (block[off + i] != 0)
-					{
-						isOkay = false;
-					}
-				}
-
-				if (!isOkay)
-				{
-					return ReturnFalse(block);
-				}
-
-				recoveredMessage = new byte[off - mStart];
-				Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
-			}
-			else
-			{
-				fullMessage = false;
-
-				digest.DoFinal(hash, 0);
-
-				bool isOkay = true;
-
-				for (int i = 0; i != hash.Length; i++)
-				{
-					block[off + i] ^= hash[i];
-					if (block[off + i] != 0)
-					{
-						isOkay = false;
-					}
-				}
-
-				if (!isOkay)
-				{
-					return ReturnFalse(block);
-				}
-
-				recoveredMessage = new byte[off - mStart];
-				Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
-			}
-
-			//
-			// if they've input a message check what we've recovered against
-			// what was input.
-			//
-			if (messageLength != 0 && !updateWithRecoveredCalled)
-			{
-				if (!IsSameAs(mBuf, recoveredMessage))
-				{
-//					ClearBlock(recoveredMessage);
-					return ReturnFalse(block);
-				}
-			}
-
-			ClearBlock(mBuf);
-			ClearBlock(block);
-
-			return true;
-		}
-
-		private bool ReturnFalse(byte[] block)
-		{
-			ClearBlock(mBuf);
-			ClearBlock(block);
-
-			return false;
-		}
-
-		/// <summary>
-		/// Return true if the full message was recoveredMessage.
-		/// </summary>
-		/// <returns> true on full message recovery, false otherwise.</returns>
-		/// <seealso cref="ISignerWithRecovery.HasFullMessage"/>
-		public virtual bool HasFullMessage()
-		{
-			return fullMessage;
-		}
-	}
+    /// <summary> ISO9796-2 - mechanism using a hash function with recovery (scheme 1)</summary>
+    public class Iso9796d2Signer : ISignerWithRecovery
+    {
+        /// <summary>
+        /// Return a reference to the recoveredMessage message.
+        /// </summary>
+        /// <returns>The full/partial recoveredMessage message.</returns>
+        /// <seealso cref="ISignerWithRecovery.GetRecoveredMessage"/>
+        public byte[] GetRecoveredMessage()
+        {
+            return recoveredMessage;
+        }
+
+        public const int TrailerImplicit = 0xBC;
+        public const int TrailerRipeMD160 = 0x31CC;
+        public const int TrailerRipeMD128 = 0x32CC;
+        public const int TrailerSha1 = 0x33CC;
+        public const int TrailerSha256 = 0x34CC;
+        public const int TrailerSha512 = 0x35CC;
+        public const int TrailerSha384 = 0x36CC;
+        public const int TrailerWhirlpool = 0x37CC;
+
+        private static IDictionary trailerMap = Platform.CreateHashtable();
+
+        static Iso9796d2Signer()
+        {
+            trailerMap.Add("RIPEMD128", TrailerRipeMD128);
+            trailerMap.Add("RIPEMD160", TrailerRipeMD160);
+
+            trailerMap.Add("SHA-1", TrailerSha1);
+            trailerMap.Add("SHA-256", TrailerSha256);
+            trailerMap.Add("SHA-384", TrailerSha384);
+            trailerMap.Add("SHA-512", TrailerSha512);
+
+            trailerMap.Add("Whirlpool", TrailerWhirlpool);
+        }
+
+        private IDigest digest;
+        private IAsymmetricBlockCipher cipher;
+
+        private int trailer;
+        private int keyBits;
+        private byte[] block;
+        private byte[] mBuf;
+        private int messageLength;
+        private bool fullMessage;
+        private byte[] recoveredMessage;
+
+        private byte[] preSig;
+        private byte[] preBlock;
+
+        /// <summary>
+        /// Generate a signer for the with either implicit or explicit trailers
+        /// for ISO9796-2.
+        /// </summary>
+        /// <param name="cipher">base cipher to use for signature creation/verification</param>
+        /// <param name="digest">digest to use.</param>
+        /// <param name="isImplicit">whether or not the trailer is implicit or gives the hash.</param>
+        public Iso9796d2Signer(
+            IAsymmetricBlockCipher	cipher,
+            IDigest					digest,
+            bool					isImplicit)
+        {
+            this.cipher = cipher;
+            this.digest = digest;
+
+            if (isImplicit)
+            {
+                trailer = TrailerImplicit;
+            }
+            else
+            {
+                string digestName = digest.AlgorithmName;
+
+                if (trailerMap.Contains(digestName))
+                {
+                    trailer = (int)trailerMap[digest.AlgorithmName];
+                }
+                else
+                {
+                    throw new System.ArgumentException("no valid trailer for digest");
+                }
+            }
+        }
+
+        /// <summary> Constructor for a signer with an explicit digest trailer.
+        ///
+        /// </summary>
+        /// <param name="cipher">cipher to use.
+        /// </param>
+        /// <param name="digest">digest to sign with.
+        /// </param>
+        public Iso9796d2Signer(IAsymmetricBlockCipher cipher, IDigest digest)
+            : this(cipher, digest, false)
+        {
+        }
+
+        public string AlgorithmName
+        {
+            get { return digest.AlgorithmName + "with" + "ISO9796-2S1"; }
+        }
+
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
+        {
+            RsaKeyParameters kParam = (RsaKeyParameters) parameters;
+
+            cipher.Init(forSigning, kParam);
+
+            keyBits = kParam.Modulus.BitLength;
+
+            block = new byte[(keyBits + 7) / 8];
+            if (trailer == TrailerImplicit)
+            {
+                mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
+            }
+            else
+            {
+                mBuf = new byte[block.Length - digest.GetDigestSize() - 3];
+            }
+
+            Reset();
+        }
+
+        /// <summary> compare two byte arrays - constant time.</summary>
+        private bool IsSameAs(byte[] a, byte[] b)
+        {
+            int checkLen;
+            if (messageLength > mBuf.Length)
+            {
+                if (mBuf.Length > b.Length)
+                {
+                    return false;
+                }
+
+                checkLen = mBuf.Length;
+            }
+            else
+            {
+                if (messageLength != b.Length)
+                {
+                    return false;
+                }
+
+                checkLen = b.Length;
+            }
+
+            bool isOkay = true;
+
+            for (int i = 0; i != checkLen; i++)
+            {
+                if (a[i] != b[i])
+                {
+                    isOkay = false;
+                }
+            }
+
+            return isOkay;
+        }
+
+        /// <summary> clear possible sensitive data</summary>
+        private void  ClearBlock(
+            byte[] block)
+        {
+            Array.Clear(block, 0, block.Length);
+        }
+
+        public virtual void UpdateWithRecoveredMessage(
+            byte[] signature)
+        {
+            byte[] block = cipher.ProcessBlock(signature, 0, signature.Length);
+
+            if (((block[0] & 0xC0) ^ 0x40) != 0)
+                throw new InvalidCipherTextException("malformed signature");
+
+            if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
+                throw new InvalidCipherTextException("malformed signature");
+
+            int delta = 0;
+
+            if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+            {
+                delta = 1;
+            }
+            else
+            {
+                int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+                string digestName = digest.AlgorithmName;
+                if (!trailerMap.Contains(digestName))
+                    throw new ArgumentException("unrecognised hash in signature");
+                if (sigTrail != (int)trailerMap[digestName])
+                    throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
+
+                delta = 2;
+            }
+
+            //
+            // find out how much padding we've got
+            //
+            int mStart = 0;
+
+            for (mStart = 0; mStart != block.Length; mStart++)
+            {
+                if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+                    break;
+            }
+
+            mStart++;
+
+            int off = block.Length - delta - digest.GetDigestSize();
+
+            //
+            // there must be at least one byte of message string
+            //
+            if ((off - mStart) <= 0)
+                throw new InvalidCipherTextException("malformed block");
+
+            //
+            // if we contain the whole message as well, check the hash of that.
+            //
+            if ((block[0] & 0x20) == 0)
+            {
+                fullMessage = true;
+
+                recoveredMessage = new byte[off - mStart];
+                Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+            }
+            else
+            {
+                fullMessage = false;
+
+                recoveredMessage = new byte[off - mStart];
+                Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+            }
+
+            preSig = signature;
+            preBlock = block;
+
+            digest.BlockUpdate(recoveredMessage, 0, recoveredMessage.Length);
+            messageLength = recoveredMessage.Length;
+            recoveredMessage.CopyTo(mBuf, 0);
+        }
+
+        /// <summary> update the internal digest with the byte b</summary>
+        public void Update(
+            byte input)
+        {
+            digest.Update(input);
+
+            if (messageLength < mBuf.Length)
+            {
+                mBuf[messageLength] = input;
+            }
+
+            messageLength++;
+        }
+
+        /// <summary> update the internal digest with the byte array in</summary>
+        public void BlockUpdate(
+            byte[]	input,
+            int		inOff,
+            int		length)
+        {
+            while (length > 0 && messageLength < mBuf.Length)
+            {
+                //for (int i = 0; i < length && (i + messageLength) < mBuf.Length; i++)
+                //{
+                //    mBuf[messageLength + i] = input[inOff + i];
+                //}
+                this.Update(input[inOff]);
+                inOff++;
+                length--;
+            }
+
+            digest.BlockUpdate(input, inOff, length);
+            messageLength += length;
+        }
+
+        /// <summary> reset the internal state</summary>
+        public virtual void Reset()
+        {
+            digest.Reset();
+            messageLength = 0;
+            ClearBlock(mBuf);
+
+            if (recoveredMessage != null)
+            {
+                ClearBlock(recoveredMessage);
+            }
+
+            recoveredMessage = null;
+            fullMessage = false;
+
+            if (preSig != null)
+            {
+                preSig = null;
+                ClearBlock(preBlock);
+                preBlock = null;
+            }
+        }
+
+        /// <summary> Generate a signature for the loaded message using the key we were
+        /// initialised with.
+        /// </summary>
+        public virtual byte[] GenerateSignature()
+        {
+            int digSize = digest.GetDigestSize();
+
+            int t = 0;
+            int delta = 0;
+
+            if (trailer == TrailerImplicit)
+            {
+                t = 8;
+                delta = block.Length - digSize - 1;
+                digest.DoFinal(block, delta);
+                block[block.Length - 1] = (byte) TrailerImplicit;
+            }
+            else
+            {
+                t = 16;
+                delta = block.Length - digSize - 2;
+                digest.DoFinal(block, delta);
+                block[block.Length - 2] = (byte) ((uint)trailer >> 8);
+                block[block.Length - 1] = (byte) trailer;
+            }
+
+            byte header = 0;
+            int x = (digSize + messageLength) * 8 + t + 4 - keyBits;
+
+            if (x > 0)
+            {
+                int mR = messageLength - ((x + 7) / 8);
+                header = (byte) (0x60);
+
+                delta -= mR;
+
+                Array.Copy(mBuf, 0, block, delta, mR);
+            }
+            else
+            {
+                header = (byte) (0x40);
+                delta -= messageLength;
+
+                Array.Copy(mBuf, 0, block, delta, messageLength);
+            }
+
+            if ((delta - 1) > 0)
+            {
+                for (int i = delta - 1; i != 0; i--)
+                {
+                    block[i] = (byte) 0xbb;
+                }
+                block[delta - 1] ^= (byte) 0x01;
+                block[0] = (byte) 0x0b;
+                block[0] |= header;
+            }
+            else
+            {
+                block[0] = (byte) 0x0a;
+                block[0] |= header;
+            }
+
+            byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+            ClearBlock(mBuf);
+            ClearBlock(block);
+
+            return b;
+        }
+
+        /// <summary> return true if the signature represents a ISO9796-2 signature
+        /// for the passed in message.
+        /// </summary>
+        public virtual bool VerifySignature(byte[] signature)
+        {
+            byte[] block;
+
+            if (preSig == null)
+            {
+                try
+                {
+                    block = cipher.ProcessBlock(signature, 0, signature.Length);
+                }
+                catch (Exception)
+                {
+                    return false;
+                }
+            }
+            else
+            {
+                if (!Arrays.AreEqual(preSig, signature))
+                    throw new InvalidOperationException("updateWithRecoveredMessage called on different signature");
+
+                block = preBlock;
+
+                preSig = null;
+                preBlock = null;
+            }
+
+            if (((block[0] & 0xC0) ^ 0x40) != 0)
+                return ReturnFalse(block);
+
+            if (((block[block.Length - 1] & 0xF) ^ 0xC) != 0)
+                return ReturnFalse(block);
+
+            int delta = 0;
+
+            if (((block[block.Length - 1] & 0xFF) ^ 0xBC) == 0)
+            {
+                delta = 1;
+            }
+            else
+            {
+                int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
+
+                string digestName = digest.AlgorithmName;
+                if (!trailerMap.Contains(digestName))
+                    throw new ArgumentException("unrecognised hash in signature");
+                if (sigTrail != (int)trailerMap[digestName])
+                    throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
+
+                delta = 2;
+            }
+
+            //
+            // find out how much padding we've got
+            //
+            int mStart = 0;
+            for (; mStart != block.Length; mStart++)
+            {
+                if (((block[mStart] & 0x0f) ^ 0x0a) == 0)
+                {
+                    break;
+                }
+            }
+
+            mStart++;
+
+            //
+            // check the hashes
+            //
+            byte[] hash = new byte[digest.GetDigestSize()];
+
+            int off = block.Length - delta - hash.Length;
+
+            //
+            // there must be at least one byte of message string
+            //
+            if ((off - mStart) <= 0)
+            {
+                return ReturnFalse(block);
+            }
+
+            //
+            // if we contain the whole message as well, check the hash of that.
+            //
+            if ((block[0] & 0x20) == 0)
+            {
+                fullMessage = true;
+
+                // check right number of bytes passed in.
+                if (messageLength > off - mStart)
+                {
+                    return ReturnFalse(block);
+                }
+
+                digest.Reset();
+                digest.BlockUpdate(block, mStart, off - mStart);
+                digest.DoFinal(hash, 0);
+
+                bool isOkay = true;
+                
+                for (int i = 0; i != hash.Length; i++)
+                {
+                    block[off + i] ^= hash[i];
+                    if (block[off + i] != 0)
+                    {
+                        isOkay = false;
+                    }
+                }
+
+                if (!isOkay)
+                {
+                    return ReturnFalse(block);
+                }
+
+                recoveredMessage = new byte[off - mStart];
+                Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+            }
+            else
+            {
+                fullMessage = false;
+
+                digest.DoFinal(hash, 0);
+
+                bool isOkay = true;
+
+                for (int i = 0; i != hash.Length; i++)
+                {
+                    block[off + i] ^= hash[i];
+                    if (block[off + i] != 0)
+                    {
+                        isOkay = false;
+                    }
+                }
+
+                if (!isOkay)
+                {
+                    return ReturnFalse(block);
+                }
+
+                recoveredMessage = new byte[off - mStart];
+                Array.Copy(block, mStart, recoveredMessage, 0, recoveredMessage.Length);
+            }
+
+            //
+            // if they've input a message check what we've recovered against
+            // what was input.
+            //
+            if (messageLength != 0)
+            {
+                if (!IsSameAs(mBuf, recoveredMessage))
+                {
+                    return ReturnFalse(block);
+                }
+            }
+
+            ClearBlock(mBuf);
+            ClearBlock(block);
+
+            return true;
+        }
+
+        private bool ReturnFalse(byte[] block)
+        {
+            ClearBlock(mBuf);
+            ClearBlock(block);
+
+            return false;
+        }
+
+        /// <summary>
+        /// Return true if the full message was recoveredMessage.
+        /// </summary>
+        /// <returns> true on full message recovery, false otherwise.</returns>
+        /// <seealso cref="ISignerWithRecovery.HasFullMessage"/>
+        public virtual bool HasFullMessage()
+        {
+            return fullMessage;
+        }
+    }
 }
diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
new file mode 100644
index 000000000..6900224f3
--- /dev/null
+++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -0,0 +1,345 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+	/// <summary> RSA-PSS as described in Pkcs# 1 v 2.1.
+	/// <p>
+	/// Note: the usual value for the salt length is the number of
+	/// bytes in the hash function.</p>
+	/// </summary>
+	public class PssSigner
+		: ISigner
+	{
+		public const byte TrailerImplicit = (byte)0xBC;
+
+		private readonly IDigest contentDigest1, contentDigest2;
+		private readonly IDigest mgfDigest;
+		private readonly IAsymmetricBlockCipher cipher;
+
+		private SecureRandom random;
+
+		private int hLen;
+		private int mgfhLen;
+		private int sLen;
+		private int emBits;
+		private byte[] salt;
+		private byte[] mDash;
+		private byte[] block;
+		private byte trailer;
+
+		public static PssSigner CreateRawSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					digest)
+		{
+			return new PssSigner(cipher, new NullDigest(), digest, digest, digest.GetDigestSize(), TrailerImplicit);
+		}
+
+		public static PssSigner CreateRawSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					contentDigest,
+			IDigest					mgfDigest,
+			int						saltLen,
+			byte					trailer)
+		{
+			return new PssSigner(cipher, new NullDigest(), contentDigest, mgfDigest, saltLen, trailer);
+		}
+
+		public PssSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					digest)
+			: this(cipher, digest, digest.GetDigestSize())
+		{
+		}
+
+		/// <summary>Basic constructor</summary>
+		/// <param name="cipher">the asymmetric cipher to use.</param>
+		/// <param name="digest">the digest to use.</param>
+		/// <param name="saltLen">the length of the salt to use (in bytes).</param>
+		public PssSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					digest,
+			int						saltLen)
+			: this(cipher, digest, saltLen, TrailerImplicit)
+		{
+		}
+
+		public PssSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					contentDigest,
+			IDigest					mgfDigest,
+			int						saltLen)
+			: this(cipher, contentDigest, mgfDigest, saltLen, TrailerImplicit)
+		{
+		}
+
+		public PssSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					digest,
+			int						saltLen,
+			byte					trailer)
+			: this(cipher, digest, digest, saltLen, TrailerImplicit)
+		{
+		}
+
+		public PssSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					contentDigest,
+			IDigest					mgfDigest,
+			int						saltLen,
+			byte					trailer)
+			: this(cipher, contentDigest, contentDigest, mgfDigest, saltLen, trailer)
+		{
+		}
+
+		private PssSigner(
+			IAsymmetricBlockCipher	cipher,
+			IDigest					contentDigest1,
+			IDigest					contentDigest2,
+			IDigest					mgfDigest,
+			int						saltLen,
+			byte					trailer)
+		{
+			this.cipher = cipher;
+			this.contentDigest1 = contentDigest1;
+			this.contentDigest2 = contentDigest2;
+			this.mgfDigest = mgfDigest;
+			this.hLen = contentDigest2.GetDigestSize();
+			this.mgfhLen = mgfDigest.GetDigestSize();
+			this.sLen = saltLen;
+			this.salt = new byte[saltLen];
+			this.mDash = new byte[8 + saltLen + hLen];
+			this.trailer = trailer;
+		}
+
+		public string AlgorithmName
+		{
+			get { return mgfDigest.AlgorithmName + "withRSAandMGF1"; }
+		}
+
+		public virtual void Init(
+			bool				forSigning,
+			ICipherParameters	parameters)
+		{
+			if (parameters is ParametersWithRandom)
+			{
+				ParametersWithRandom p = (ParametersWithRandom) parameters;
+
+				parameters = p.Parameters;
+				random = p.Random;
+			}
+			else
+			{
+				if (forSigning)
+				{
+					random = new SecureRandom();
+				}
+			}
+
+			cipher.Init(forSigning, parameters);
+
+			RsaKeyParameters kParam;
+			if (parameters is RsaBlindingParameters)
+			{
+				kParam = ((RsaBlindingParameters) parameters).PublicKey;
+			}
+			else
+			{
+				kParam = (RsaKeyParameters) parameters;
+			}
+
+			emBits = kParam.Modulus.BitLength - 1;
+
+			if (emBits < (8 * hLen + 8 * sLen + 9))
+				throw new ArgumentException("key too small for specified hash and salt lengths");
+
+			block = new byte[(emBits + 7) / 8];
+		}
+
+		/// <summary> clear possible sensitive data</summary>
+		private void ClearBlock(
+			byte[] block)
+		{
+			Array.Clear(block, 0, block.Length);
+		}
+
+		/// <summary> update the internal digest with the byte b</summary>
+		public virtual void Update(
+			byte input)
+		{
+			contentDigest1.Update(input);
+		}
+
+		/// <summary> update the internal digest with the byte array in</summary>
+		public virtual void BlockUpdate(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			contentDigest1.BlockUpdate(input, inOff, length);
+		}
+
+		/// <summary> reset the internal state</summary>
+		public virtual void Reset()
+		{
+			contentDigest1.Reset();
+		}
+
+		/// <summary> Generate a signature for the message we've been loaded with using
+		/// the key we were initialised with.
+		/// </summary>
+		public virtual byte[] GenerateSignature()
+		{
+			contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen);
+
+			if (sLen != 0)
+			{
+				random.NextBytes(salt);
+				salt.CopyTo(mDash, mDash.Length - sLen);
+			}
+
+			byte[] h = new byte[hLen];
+
+			contentDigest2.BlockUpdate(mDash, 0, mDash.Length);
+
+			contentDigest2.DoFinal(h, 0);
+
+			block[block.Length - sLen - 1 - hLen - 1] = (byte) (0x01);
+			salt.CopyTo(block, block.Length - sLen - hLen - 1);
+
+			byte[] dbMask = MaskGeneratorFunction1(h, 0, h.Length, block.Length - hLen - 1);
+			for (int i = 0; i != dbMask.Length; i++)
+			{
+				block[i] ^= dbMask[i];
+			}
+
+			block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits)));
+
+			h.CopyTo(block, block.Length - hLen - 1);
+
+			block[block.Length - 1] = trailer;
+
+			byte[] b = cipher.ProcessBlock(block, 0, block.Length);
+
+			ClearBlock(block);
+
+			return b;
+		}
+
+		/// <summary> return true if the internal state represents the signature described
+		/// in the passed in array.
+		/// </summary>
+		public virtual bool VerifySignature(
+			byte[] signature)
+		{
+			contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen);
+
+			byte[] b = cipher.ProcessBlock(signature, 0, signature.Length);
+			b.CopyTo(block, block.Length - b.Length);
+
+			if (block[block.Length - 1] != trailer)
+			{
+				ClearBlock(block);
+				return false;
+			}
+
+			byte[] dbMask = MaskGeneratorFunction1(block, block.Length - hLen - 1, hLen, block.Length - hLen - 1);
+
+			for (int i = 0; i != dbMask.Length; i++)
+			{
+				block[i] ^= dbMask[i];
+			}
+
+			block[0] &= (byte) ((0xff >> ((block.Length * 8) - emBits)));
+
+			for (int i = 0; i != block.Length - hLen - sLen - 2; i++)
+			{
+				if (block[i] != 0)
+				{
+					ClearBlock(block);
+					return false;
+				}
+			}
+
+			if (block[block.Length - hLen - sLen - 2] != 0x01)
+			{
+				ClearBlock(block);
+				return false;
+			}
+
+			Array.Copy(block, block.Length - sLen - hLen - 1, mDash, mDash.Length - sLen, sLen);
+
+			contentDigest2.BlockUpdate(mDash, 0, mDash.Length);
+			contentDigest2.DoFinal(mDash, mDash.Length - hLen);
+
+			for (int i = block.Length - hLen - 1, j = mDash.Length - hLen; j != mDash.Length; i++, j++)
+			{
+				if ((block[i] ^ mDash[j]) != 0)
+				{
+					ClearBlock(mDash);
+					ClearBlock(block);
+					return false;
+				}
+			}
+
+			ClearBlock(mDash);
+			ClearBlock(block);
+
+			return true;
+		}
+
+		/// <summary> int to octet string.</summary>
+		private void ItoOSP(
+			int		i,
+			byte[]	sp)
+		{
+			sp[0] = (byte)((uint) i >> 24);
+			sp[1] = (byte)((uint) i >> 16);
+			sp[2] = (byte)((uint) i >> 8);
+			sp[3] = (byte)((uint) i >> 0);
+		}
+
+		/// <summary> mask generator function, as described in Pkcs1v2.</summary>
+		private byte[] MaskGeneratorFunction1(
+			byte[]	Z,
+			int		zOff,
+			int		zLen,
+			int		length)
+		{
+			byte[] mask = new byte[length];
+			byte[] hashBuf = new byte[mgfhLen];
+			byte[] C = new byte[4];
+			int counter = 0;
+
+			mgfDigest.Reset();
+
+			while (counter < (length / mgfhLen))
+			{
+				ItoOSP(counter, C);
+
+				mgfDigest.BlockUpdate(Z, zOff, zLen);
+				mgfDigest.BlockUpdate(C, 0, C.Length);
+				mgfDigest.DoFinal(hashBuf, 0);
+
+				hashBuf.CopyTo(mask, counter * mgfhLen);
+				++counter;
+			}
+
+			if ((counter * mgfhLen) < length)
+			{
+				ItoOSP(counter, C);
+
+				mgfDigest.BlockUpdate(Z, zOff, zLen);
+				mgfDigest.BlockUpdate(C, 0, C.Length);
+				mgfDigest.DoFinal(hashBuf, 0);
+
+				Array.Copy(hashBuf, 0, mask, counter * mgfhLen, mask.Length - (counter * mgfhLen));
+			}
+
+			return mask;
+		}
+	}
+}
diff --git a/crypto/src/crypto/signers/RandomDsaKCalculator.cs b/crypto/src/crypto/signers/RandomDsaKCalculator.cs
new file mode 100644
index 000000000..022cc268d
--- /dev/null
+++ b/crypto/src/crypto/signers/RandomDsaKCalculator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class RandomDsaKCalculator
+        :   IDsaKCalculator
+    {
+        private BigInteger q;
+        private SecureRandom random;
+
+        public virtual bool IsDeterministic
+        {
+            get { return false; }
+        }
+
+        public virtual void Init(BigInteger n, SecureRandom random)
+        {
+            this.q = n;
+            this.random = random;
+        }
+
+        public virtual void Init(BigInteger n, BigInteger d, byte[] message)
+        {
+            throw new InvalidOperationException("Operation not supported");
+        }
+
+        public virtual BigInteger NextK()
+        {
+            int qBitLength = q.BitLength;
+
+            BigInteger k;
+            do
+            {
+                k = new BigInteger(qBitLength, random);
+            }
+            while (k.SignValue < 1 || k.CompareTo(q) >= 0);
+
+            return k;
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/RsaDigestSigner.cs b/crypto/src/crypto/signers/RsaDigestSigner.cs
index f57bfc83d..9af4e7145 100644
--- a/crypto/src/crypto/signers/RsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -19,16 +19,16 @@ using Org.BouncyCastle.Utilities;
 namespace Org.BouncyCastle.Crypto.Signers
 {
     public class RsaDigestSigner
-		: ISigner
+        : ISigner
     {
         private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine());
         private readonly AlgorithmIdentifier algId;
-		private readonly IDigest digest;
-		private bool forSigning;
+        private readonly IDigest digest;
+        private bool forSigning;
 
-		private static readonly IDictionary oidMap = Platform.CreateHashtable();
+        private static readonly IDictionary oidMap = Platform.CreateHashtable();
 
-		/// <summary>
+        /// <summary>
         /// Load oid table.
         /// </summary>
         static RsaDigestSigner()
@@ -48,37 +48,37 @@ namespace Org.BouncyCastle.Crypto.Signers
             oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
         }
 
-		public RsaDigestSigner(
-			IDigest digest)
+        public RsaDigestSigner(IDigest digest)
+            :   this(digest, (DerObjectIdentifier)oidMap[digest.AlgorithmName])
         {
-            this.digest = digest;
+        }
 
-			string algName = digest.AlgorithmName;
-			if (algName.Equals("NULL"))
-			{
-				this.algId = null;
-			}
-			else
-			{
-				this.algId = new AlgorithmIdentifier(
-					(DerObjectIdentifier)oidMap[digest.AlgorithmName], DerNull.Instance);
-			}
+        public RsaDigestSigner(IDigest digest, DerObjectIdentifier digestOid)
+            :   this(digest, new AlgorithmIdentifier(digestOid, DerNull.Instance))
+        {
         }
 
-		public string AlgorithmName
+        public RsaDigestSigner(IDigest digest, AlgorithmIdentifier algId)
+        {
+            this.digest = digest;
+            this.algId = algId;
+        }
+
+        [Obsolete]
+        public string AlgorithmName
         {
             get { return digest.AlgorithmName + "withRSA"; }
         }
 
-		/**
+        /**
          * Initialise the signer for signing or verification.
          *
          * @param forSigning true if for signing, false otherwise
          * @param param necessary parameters.
          */
         public void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
+            bool				forSigning,
+            ICipherParameters	parameters)
         {
             this.forSigning = forSigning;
             AsymmetricKeyParameter k;
@@ -95,10 +95,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             if (forSigning && !k.IsPrivate)
                 throw new InvalidKeyException("Signing requires private key.");
 
-			if (!forSigning && k.IsPrivate)
+            if (!forSigning && k.IsPrivate)
                 throw new InvalidKeyException("Verification requires public key.");
 
-			Reset();
+            Reset();
 
             rsaEngine.Init(forSigning, parameters);
         }
@@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Signers
          * update the internal digest with the byte b
          */
         public void Update(
-			byte input)
+            byte input)
         {
             digest.Update(input);
         }
@@ -116,9 +116,9 @@ namespace Org.BouncyCastle.Crypto.Signers
          * update the internal digest with the byte array in
          */
         public void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		length)
+            byte[]	input,
+            int		inOff,
+            int		length)
         {
             digest.BlockUpdate(input, inOff, length);
         }
@@ -132,79 +132,69 @@ namespace Org.BouncyCastle.Crypto.Signers
             if (!forSigning)
                 throw new InvalidOperationException("RsaDigestSigner not initialised for signature generation.");
 
-			byte[] hash = new byte[digest.GetDigestSize()];
+            byte[] hash = new byte[digest.GetDigestSize()];
             digest.DoFinal(hash, 0);
 
-			byte[] data = DerEncode(hash);
+            byte[] data = DerEncode(hash);
             return rsaEngine.ProcessBlock(data, 0, data.Length);
         }
 
-		/**
+        /**
          * return true if the internal state represents the signature described
          * in the passed in array.
          */
         public bool VerifySignature(
-			byte[] signature)
+            byte[] signature)
         {
-			if (forSigning)
-				throw new InvalidOperationException("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)
-			{
-				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;
+            if (forSigning)
+                throw new InvalidOperationException("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)
+            {
+                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()
@@ -212,17 +202,17 @@ namespace Org.BouncyCastle.Crypto.Signers
             digest.Reset();
         }
 
-		private byte[] DerEncode(byte[] hash)
-		{
-			if (algId == null)
-			{
-				// For raw RSA, the DigestInfo must be prepared externally
-				return hash;
-			}
+        private byte[] DerEncode(byte[] hash)
+        {
+            if (algId == null)
+            {
+                // For raw RSA, the DigestInfo must be prepared externally
+                return hash;
+            }
 
-			DigestInfo dInfo = new DigestInfo(algId, hash);
+            DigestInfo dInfo = new DigestInfo(algId, hash);
 
-			return dInfo.GetDerEncoded();
-		}
+            return dInfo.GetDerEncoded();
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs b/crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs
new file mode 100644
index 000000000..2d7af80e8
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsAgreementCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsAgreementCredentials
+        :   AbstractTlsCredentials, TlsAgreementCredentials
+    {
+        /// <exception cref="IOException"></exception>
+        public abstract byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey);
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsCipherFactory.cs b/crypto/src/crypto/tls/AbstractTlsCipherFactory.cs
new file mode 100644
index 000000000..141ee6507
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsCipherFactory.cs
@@ -0,0 +1,15 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class AbstractTlsCipherFactory
+        :   TlsCipherFactory
+    {
+        /// <exception cref="IOException"></exception>
+        public virtual TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm)
+        {
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsClient.cs b/crypto/src/crypto/tls/AbstractTlsClient.cs
new file mode 100644
index 000000000..9484afa7d
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsClient.cs
@@ -0,0 +1,232 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsClient
+        :   AbstractTlsPeer, TlsClient
+    {
+        protected TlsCipherFactory mCipherFactory;
+
+        protected TlsClientContext mContext;
+
+        protected IList mSupportedSignatureAlgorithms;
+        protected int[] mNamedCurves;
+        protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+        protected int mSelectedCipherSuite;
+        protected short mSelectedCompressionMethod;
+
+        public AbstractTlsClient()
+            :   this(new DefaultTlsCipherFactory())
+        {
+        }
+
+        public AbstractTlsClient(TlsCipherFactory cipherFactory)
+        {
+            this.mCipherFactory = cipherFactory;
+        }
+
+        public virtual void Init(TlsClientContext context)
+        {
+            this.mContext = context;
+        }
+
+        public virtual TlsSession GetSessionToResume()
+        {
+            return null;
+        }
+
+        /**
+         * RFC 5246 E.1. "TLS clients that wish to negotiate with older servers MAY send any value
+         * {03,XX} as the record layer version number. Typical values would be {03,00}, the lowest
+         * version number supported by the client, and the value of ClientHello.client_version. No
+         * single value will guarantee interoperability with all old servers, but this is a complex
+         * topic beyond the scope of this document."
+         */
+        public virtual ProtocolVersion ClientHelloRecordLayerVersion
+        {
+            get
+            {
+                // "{03,00}"
+                // return ProtocolVersion.SSLv3;
+
+                // "the lowest version number supported by the client"
+                // return getMinimumVersion();
+
+                // "the value of ClientHello.client_version"
+                return ClientVersion;
+            }
+        }
+
+        public virtual ProtocolVersion ClientVersion
+        {
+            get { return ProtocolVersion.TLSv12; }
+        }
+
+        public virtual IDictionary GetClientExtensions()
+        {
+            IDictionary clientExtensions = null;
+
+            ProtocolVersion clientVersion = mContext.ClientVersion;
+
+            /*
+             * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior to 1.2.
+             * Clients MUST NOT offer it if they are offering prior versions.
+             */
+            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
+            {
+                // TODO Provide a way for the user to specify the acceptable hash/signature algorithms.
+
+                byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha512, HashAlgorithm.sha384, HashAlgorithm.sha256,
+                    HashAlgorithm.sha224, HashAlgorithm.sha1 };
+
+                // TODO Sort out ECDSA signatures and add them as the preferred option here
+                byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa };
+
+                this.mSupportedSignatureAlgorithms = Platform.CreateArrayList();
+                for (int i = 0; i < hashAlgorithms.Length; ++i)
+                {
+                    for (int j = 0; j < signatureAlgorithms.Length; ++j)
+                    {
+                        this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(hashAlgorithms[i],
+                            signatureAlgorithms[j]));
+                    }
+                }
+
+                /*
+                 * RFC 5264 7.4.3. Currently, DSA [DSS] may only be used with SHA-1.
+                 */
+                this.mSupportedSignatureAlgorithms.Add(new SignatureAndHashAlgorithm(HashAlgorithm.sha1,
+                    SignatureAlgorithm.dsa));
+
+                clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);
+
+                TlsUtilities.AddSignatureAlgorithmsExtension(clientExtensions, mSupportedSignatureAlgorithms);
+            }
+
+            if (TlsEccUtilities.ContainsEccCipherSuites(GetCipherSuites()))
+            {
+                /*
+                 * RFC 4492 5.1. A client that proposes ECC cipher suites in its ClientHello message
+                 * appends these extensions (along with any others), enumerating the curves it supports
+                 * and the point formats it can parse. Clients SHOULD send both the Supported Elliptic
+                 * Curves Extension and the Supported Point Formats Extension.
+                 */
+                /*
+                 * TODO Could just add all the curves since we support them all, but users may not want
+                 * to use unnecessarily large fields. Need configuration options.
+                 */
+                this.mNamedCurves = new int[]{ NamedCurve.secp256r1, NamedCurve.secp384r1 };
+                this.mClientECPointFormats = new byte[]{ ECPointFormat.uncompressed,
+                    ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };
+
+                clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);
+
+                TlsEccUtilities.AddSupportedEllipticCurvesExtension(clientExtensions, mNamedCurves);
+                TlsEccUtilities.AddSupportedPointFormatsExtension(clientExtensions, mClientECPointFormats);
+            }
+
+            return clientExtensions;
+        }
+
+        public virtual ProtocolVersion MinimumVersion
+        {
+            get { return ProtocolVersion.TLSv10; }
+        }
+
+        public virtual void NotifyServerVersion(ProtocolVersion serverVersion)
+        {
+            if (!MinimumVersion.IsEqualOrEarlierVersionOf(serverVersion))
+                throw new TlsFatalAlert(AlertDescription.protocol_version);
+        }
+
+        public abstract int[] GetCipherSuites();
+
+        public virtual byte[] GetCompressionMethods()
+        {
+            return new byte[]{ CompressionMethod.cls_null };
+        }
+
+        public virtual void NotifySessionID(byte[] sessionID)
+        {
+            // Currently ignored
+        }
+
+        public virtual void NotifySelectedCipherSuite(int selectedCipherSuite)
+        {
+            this.mSelectedCipherSuite = selectedCipherSuite;
+        }
+
+        public virtual void NotifySelectedCompressionMethod(byte selectedCompressionMethod)
+        {
+            this.mSelectedCompressionMethod = selectedCompressionMethod;
+        }
+
+        public virtual void ProcessServerExtensions(IDictionary serverExtensions)
+        {
+            /*
+             * TlsProtocol implementation validates that any server extensions received correspond to
+             * client extensions sent. By default, we don't send any, and this method is not called.
+             */
+            if (serverExtensions != null)
+            {
+                /*
+                 * RFC 5246 7.4.1.4.1. Servers MUST NOT send this extension.
+                 */
+                if (serverExtensions.Contains(ExtensionType.signature_algorithms))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+                int[] namedCurves = TlsEccUtilities.GetSupportedEllipticCurvesExtension(serverExtensions);
+                if (namedCurves != null)
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+                this.mServerECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(serverExtensions);
+                if (this.mServerECPointFormats != null && !TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+        }
+
+        public virtual void ProcessServerSupplementalData(IList serverSupplementalData)
+        {
+            if (serverSupplementalData != null)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public abstract TlsKeyExchange GetKeyExchange();
+
+        public abstract TlsAuthentication GetAuthentication();
+
+        public virtual IList GetClientSupplementalData()
+        {
+            return null;
+        }
+
+        public override TlsCompression GetCompression()
+        {
+            switch (mSelectedCompressionMethod)
+            {
+            case CompressionMethod.cls_null:
+                return new TlsNullCompression();
+
+            case CompressionMethod.DEFLATE:
+                return new TlsDeflateCompression();
+
+            default:
+                /*
+                 * Note: internal error here; the TlsProtocol implementation verifies that the
+                 * server-selected compression method was in the list of client-offered compression
+                 * methods, so if we now can't produce an implementation, we shouldn't have offered it!
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public virtual void NotifyNewSessionTicket(NewSessionTicket newSessionTicket)
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsContext.cs b/crypto/src/crypto/tls/AbstractTlsContext.cs
new file mode 100644
index 000000000..83150d37e
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsContext.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Threading;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    internal abstract class AbstractTlsContext
+        : TlsContext
+    {
+        private static long counter = Times.NanoTime();
+
+        private static long NextCounterValue()
+        {
+            return Interlocked.Increment(ref counter);
+        }
+
+        private readonly IRandomGenerator mNonceRandom;
+        private readonly SecureRandom mSecureRandom;
+        private readonly SecurityParameters mSecurityParameters;
+
+        private ProtocolVersion mClientVersion = null;
+        private ProtocolVersion mServerVersion = null;
+        private TlsSession mSession = null;
+        private object mUserObject = null;
+
+       internal AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters)
+        {
+            IDigest d = TlsUtilities.CreateHash(HashAlgorithm.sha256);
+            byte[] seed = new byte[d.GetDigestSize()];
+            secureRandom.NextBytes(seed);
+
+            this.mNonceRandom = new DigestRandomGenerator(d);
+            mNonceRandom.AddSeedMaterial(NextCounterValue());
+            mNonceRandom.AddSeedMaterial(Times.NanoTime());
+            mNonceRandom.AddSeedMaterial(seed);
+
+            this.mSecureRandom = secureRandom;
+            this.mSecurityParameters = securityParameters;
+        }
+
+        public virtual IRandomGenerator NonceRandomGenerator
+        {
+            get { return mNonceRandom; }
+        }
+
+        public virtual SecureRandom SecureRandom
+        {
+            get { return mSecureRandom; }
+        }
+
+        public virtual SecurityParameters SecurityParameters
+        {
+            get { return mSecurityParameters; }
+        }
+
+        public abstract bool IsServer { get; }
+
+        public virtual ProtocolVersion ClientVersion
+        {
+            get { return mClientVersion; }
+        }
+
+        internal virtual void SetClientVersion(ProtocolVersion clientVersion)
+        {
+            this.mClientVersion = clientVersion;
+        }
+
+        public virtual ProtocolVersion ServerVersion
+        {
+            get { return mServerVersion; }
+        }
+
+        internal virtual void SetServerVersion(ProtocolVersion serverVersion)
+        {
+            this.mServerVersion = serverVersion;
+        }
+
+        public virtual TlsSession ResumableSession
+        {
+            get { return mSession; }
+        }
+
+        internal virtual void SetResumableSession(TlsSession session)
+        {
+            this.mSession = session;
+        }
+
+        public virtual object UserObject
+        {
+            get { return mUserObject; }
+            set { this.mUserObject = value; }
+        }
+
+        public virtual byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length)
+        {
+            if (context_value != null && !TlsUtilities.IsValidUint16(context_value.Length))
+                throw new ArgumentException("must have length less than 2^16 (or be null)", "context_value");
+
+            SecurityParameters sp = SecurityParameters;
+            byte[] cr = sp.ClientRandom, sr = sp.ServerRandom;
+
+            int seedLength = cr.Length + sr.Length;
+            if (context_value != null)
+            {
+                seedLength += (2 + context_value.Length);
+            }
+
+            byte[] seed = new byte[seedLength];
+            int seedPos = 0;
+
+            Array.Copy(cr, 0, seed, seedPos, cr.Length);
+            seedPos += cr.Length;
+            Array.Copy(sr, 0, seed, seedPos, sr.Length);
+            seedPos += sr.Length;
+            if (context_value != null)
+            {
+                TlsUtilities.WriteUint16(context_value.Length, seed, seedPos);
+                seedPos += 2;
+                Array.Copy(context_value, 0, seed, seedPos, context_value.Length);
+                seedPos += context_value.Length;
+            }
+
+            if (seedPos != seedLength)
+                throw new InvalidOperationException("error in calculation of seed for export");
+
+            return TlsUtilities.PRF(this, sp.MasterSecret, asciiLabel, seed, length);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsCredentials.cs b/crypto/src/crypto/tls/AbstractTlsCredentials.cs
new file mode 100644
index 000000000..6411b811c
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsCredentials.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsCredentials
+        :   TlsCredentials
+    {
+        public abstract Certificate Certificate { get; }
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs b/crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs
new file mode 100644
index 000000000..05b129c60
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsEncryptionCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsEncryptionCredentials
+        : AbstractTlsCredentials, TlsEncryptionCredentials
+    {
+        /// <exception cref="IOException"></exception>
+        public abstract byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret);
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
new file mode 100644
index 000000000..155ac94d8
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsKeyExchange.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsKeyExchange
+        :   TlsKeyExchange
+    {
+        protected readonly int mKeyExchange;
+        protected IList mSupportedSignatureAlgorithms;
+
+        protected TlsContext context;
+
+        protected AbstractTlsKeyExchange(int keyExchange, IList supportedSignatureAlgorithms)
+        {
+            this.mKeyExchange = keyExchange;
+            this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms;
+        }
+
+        public virtual void Init(TlsContext context)
+        {
+            this.context = context;
+
+            ProtocolVersion clientVersion = context.ClientVersion;
+
+            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
+            {
+                /*
+                 * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension,
+                 * the server MUST do the following:
+                 * 
+                 * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK,
+                 * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}.
+                 * 
+                 * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if
+                 * the client had sent the value {sha1,dsa}.
+                 * 
+                 * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA),
+                 * behave as if the client had sent value {sha1,ecdsa}.
+                 */
+                if (this.mSupportedSignatureAlgorithms == null)
+                {
+                    switch (mKeyExchange)
+                    {
+                    case KeyExchangeAlgorithm.DH_DSS:
+                    case KeyExchangeAlgorithm.DHE_DSS:
+                    case KeyExchangeAlgorithm.SRP_DSS:
+                    {
+                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultDssSignatureAlgorithms();
+                        break;
+                    }
+
+                    case KeyExchangeAlgorithm.ECDH_ECDSA:
+                    case KeyExchangeAlgorithm.ECDHE_ECDSA:
+                    {
+                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+                        break;
+                    }
+
+                    case KeyExchangeAlgorithm.DH_RSA:
+                    case KeyExchangeAlgorithm.DHE_RSA:
+                    case KeyExchangeAlgorithm.ECDH_RSA:
+                    case KeyExchangeAlgorithm.ECDHE_RSA:
+                    case KeyExchangeAlgorithm.RSA:
+                    case KeyExchangeAlgorithm.RSA_PSK:
+                    case KeyExchangeAlgorithm.SRP_RSA:
+                    {
+                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
+                        break;
+                    }
+
+                    case KeyExchangeAlgorithm.DHE_PSK:
+                    case KeyExchangeAlgorithm.ECDHE_PSK:
+                    case KeyExchangeAlgorithm.PSK:
+                    case KeyExchangeAlgorithm.SRP:
+                        break;
+
+                    default:
+                        throw new InvalidOperationException("unsupported key exchange algorithm");
+                    }
+                }
+
+            }
+            else if (this.mSupportedSignatureAlgorithms != null)
+            {
+                throw new InvalidOperationException("supported_signature_algorithms not allowed for " + clientVersion);
+            }
+        }
+
+        public abstract void SkipServerCredentials();
+
+        public virtual void ProcessServerCertificate(Certificate serverCertificate)
+        {
+            if (mSupportedSignatureAlgorithms == null)
+            {
+                /*
+                 * TODO RFC 2264 7.4.2. Unless otherwise specified, the signing algorithm for the
+                 * certificate must be the same as the algorithm for the certificate key.
+                 */
+            }
+            else
+            {
+                /*
+                 * TODO RFC 5264 7.4.2. If the client provided a "signature_algorithms" extension, then
+                 * all certificates provided by the server MUST be signed by a hash/signature algorithm
+                 * pair that appears in that extension.
+                 */
+            }
+        }
+
+        public virtual void ProcessServerCredentials(TlsCredentials serverCredentials)
+        {
+            ProcessServerCertificate(serverCredentials.Certificate);
+        }
+
+        public virtual bool RequiresServerKeyExchange
+        {
+            get { return false; }
+        }
+
+        public virtual byte[] GenerateServerKeyExchange()
+        {
+            if (RequiresServerKeyExchange)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            return null;
+        }
+
+        public virtual void SkipServerKeyExchange()
+        {
+            if (RequiresServerKeyExchange)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public virtual void ProcessServerKeyExchange(Stream input)
+        {
+            if (!RequiresServerKeyExchange)
+            {
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            }
+        }
+
+        public abstract void ValidateCertificateRequest(CertificateRequest certificateRequest);
+
+        public virtual void SkipClientCredentials()
+        {
+        }
+
+        public abstract void ProcessClientCredentials(TlsCredentials clientCredentials);
+
+        public virtual void ProcessClientCertificate(Certificate clientCertificate)
+        {
+        }
+
+        public abstract void GenerateClientKeyExchange(Stream output);
+
+        public virtual void ProcessClientKeyExchange(Stream input)
+        {
+            // Key exchange implementation MUST support client key exchange
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public abstract byte[] GeneratePremasterSecret();
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsPeer.cs b/crypto/src/crypto/tls/AbstractTlsPeer.cs
new file mode 100644
index 000000000..81a53386c
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsPeer.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsPeer
+        :   TlsPeer
+    {
+        public virtual bool ShouldUseGmtUnixTime()
+        {
+            /*
+             * draft-mathewson-no-gmtunixtime-00 2. For the reasons we discuss above, we recommend that
+             * TLS implementors MUST by default set the entire value the ClientHello.Random and
+             * ServerHello.Random fields, including gmt_unix_time, to a cryptographically random
+             * sequence.
+             */
+            return false;
+        }
+
+        public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
+        {
+            if (!secureRenegotiation)
+            {
+                /*
+                 * RFC 5746 3.4/3.6. In this case, some clients/servers may want to terminate the handshake instead
+                 * of continuing; see Section 4.1/4.3 for discussion.
+                 */
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+            }
+        }
+
+        public abstract TlsCompression GetCompression();
+
+        public abstract TlsCipher GetCipher();
+
+        public virtual void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+        }
+
+        public virtual void NotifyAlertReceived(byte alertLevel, byte alertDescription)
+        {
+        }
+
+        public virtual void NotifyHandshakeComplete()
+        {
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsServer.cs b/crypto/src/crypto/tls/AbstractTlsServer.cs
new file mode 100644
index 000000000..47542c796
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsServer.cs
@@ -0,0 +1,318 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsServer
+        :   AbstractTlsPeer, TlsServer
+    {
+        protected TlsCipherFactory mCipherFactory;
+
+        protected TlsServerContext mContext;
+
+        protected ProtocolVersion mClientVersion;
+        protected int[] mOfferedCipherSuites;
+        protected byte[] mOfferedCompressionMethods;
+        protected IDictionary mClientExtensions;
+
+        protected bool mEncryptThenMacOffered;
+        protected short mMaxFragmentLengthOffered;
+        protected bool mTruncatedHMacOffered;
+        protected IList mSupportedSignatureAlgorithms;
+        protected bool mEccCipherSuitesOffered;
+        protected int[] mNamedCurves;
+        protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+        protected ProtocolVersion mServerVersion;
+        protected int mSelectedCipherSuite;
+        protected byte mSelectedCompressionMethod;
+        protected IDictionary mServerExtensions;
+
+        public AbstractTlsServer()
+            :   this(new DefaultTlsCipherFactory())
+        {
+        }
+
+        public AbstractTlsServer(TlsCipherFactory cipherFactory)
+        {
+            this.mCipherFactory = cipherFactory;
+        }
+
+        protected virtual bool AllowEncryptThenMac
+        {
+            get { return true; }
+        }
+
+        protected virtual bool AllowTruncatedHMac
+        {
+            get { return false; }
+        }
+
+        protected virtual IDictionary CheckServerExtensions()
+        {
+            return this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mServerExtensions);
+        }
+
+        protected abstract int[] GetCipherSuites();
+
+        protected byte[] GetCompressionMethods()
+        {
+            return new byte[] { CompressionMethod.cls_null };
+        }
+
+        protected virtual ProtocolVersion MaximumVersion
+        {
+            get { return ProtocolVersion.TLSv11; }
+        }
+
+        protected virtual ProtocolVersion MinimumVersion
+        {
+            get { return ProtocolVersion.TLSv10; }
+        }
+
+        protected virtual bool SupportsClientEccCapabilities(int[] namedCurves, byte[] ecPointFormats)
+        {
+            // NOTE: BC supports all the current set of point formats so we don't check them here
+
+            if (namedCurves == null)
+            {
+                /*
+                 * RFC 4492 4. A client that proposes ECC cipher suites may choose not to include these
+                 * extensions. In this case, the server is free to choose any one of the elliptic curves
+                 * or point formats [...].
+                 */
+                return TlsEccUtilities.HasAnySupportedNamedCurves();
+            }
+
+            for (int i = 0; i < namedCurves.Length; ++i)
+            {
+                int namedCurve = namedCurves[i];
+                if (NamedCurve.IsValid(namedCurve)
+                    && (!NamedCurve.RefersToASpecificNamedCurve(namedCurve) || TlsEccUtilities.IsSupportedNamedCurve(namedCurve)))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        public virtual void Init(TlsServerContext context)
+        {
+            this.mContext = context;
+        }
+
+        public virtual void NotifyClientVersion(ProtocolVersion clientVersion)
+        {
+            this.mClientVersion = clientVersion;
+        }
+
+        public virtual void NotifyOfferedCipherSuites(int[] offeredCipherSuites)
+        {
+            this.mOfferedCipherSuites = offeredCipherSuites;
+            this.mEccCipherSuitesOffered = TlsEccUtilities.ContainsEccCipherSuites(this.mOfferedCipherSuites);
+        }
+
+        public virtual void NotifyOfferedCompressionMethods(byte[] offeredCompressionMethods)
+        {
+            this.mOfferedCompressionMethods = offeredCompressionMethods;
+        }
+
+        public virtual void ProcessClientExtensions(IDictionary clientExtensions)
+        {
+            this.mClientExtensions = clientExtensions;
+
+            if (clientExtensions != null)
+            {
+                this.mEncryptThenMacOffered = TlsExtensionsUtilities.HasEncryptThenMacExtension(clientExtensions);
+                this.mMaxFragmentLengthOffered = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions);
+                this.mTruncatedHMacOffered = TlsExtensionsUtilities.HasTruncatedHMacExtension(clientExtensions);
+
+                this.mSupportedSignatureAlgorithms = TlsUtilities.GetSignatureAlgorithmsExtension(clientExtensions);
+                if (this.mSupportedSignatureAlgorithms != null)
+                {
+                    /*
+                     * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior
+                     * to 1.2. Clients MUST NOT offer it if they are offering prior versions.
+                     */
+                    if (!TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mClientVersion))
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+
+                this.mNamedCurves = TlsEccUtilities.GetSupportedEllipticCurvesExtension(clientExtensions);
+                this.mClientECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(clientExtensions);
+            }
+
+            /*
+             * RFC 4429 4. The client MUST NOT include these extensions in the ClientHello message if it
+             * does not propose any ECC cipher suites.
+             */
+            if (!this.mEccCipherSuitesOffered && (this.mNamedCurves != null || this.mClientECPointFormats != null))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+        }
+
+        public virtual ProtocolVersion GetServerVersion()
+        {
+            if (MinimumVersion.IsEqualOrEarlierVersionOf(mClientVersion))
+            {
+                ProtocolVersion maximumVersion = MaximumVersion;
+                if (mClientVersion.IsEqualOrEarlierVersionOf(maximumVersion))
+                {
+                    return mServerVersion = mClientVersion;
+                }
+                if (mClientVersion.IsLaterVersionOf(maximumVersion))
+                {
+                    return mServerVersion = maximumVersion;
+                }
+            }
+            throw new TlsFatalAlert(AlertDescription.protocol_version);
+        }
+
+        public virtual int GetSelectedCipherSuite()
+        {
+            /*
+             * TODO RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate
+             * cipher suites against the "signature_algorithms" extension before selecting them. This is
+             * somewhat inelegant but is a compromise designed to minimize changes to the original
+             * cipher suite design.
+             */
+
+            /*
+             * RFC 4429 5.1. A server that receives a ClientHello containing one or both of these
+             * extensions MUST use the client's enumerated capabilities to guide its selection of an
+             * appropriate cipher suite. One of the proposed ECC cipher suites must be negotiated only
+             * if the server can successfully complete the handshake while using the curves and point
+             * formats supported by the client [...].
+             */
+            bool eccCipherSuitesEnabled = SupportsClientEccCapabilities(this.mNamedCurves, this.mClientECPointFormats);
+
+            int[] cipherSuites = GetCipherSuites();
+            for (int i = 0; i < cipherSuites.Length; ++i)
+            {
+                int cipherSuite = cipherSuites[i];
+
+                if (Arrays.Contains(this.mOfferedCipherSuites, cipherSuite)
+                    && (eccCipherSuitesEnabled || !TlsEccUtilities.IsEccCipherSuite(cipherSuite))
+                    && TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion))
+                {
+                    return this.mSelectedCipherSuite = cipherSuite;
+                }
+            }
+            throw new TlsFatalAlert(AlertDescription.handshake_failure);
+        }
+
+        public virtual byte GetSelectedCompressionMethod()
+        {
+            byte[] compressionMethods = GetCompressionMethods();
+            for (int i = 0; i < compressionMethods.Length; ++i)
+            {
+                if (Arrays.Contains(mOfferedCompressionMethods, compressionMethods[i]))
+                {
+                    return this.mSelectedCompressionMethod = compressionMethods[i];
+                }
+            }
+            throw new TlsFatalAlert(AlertDescription.handshake_failure);
+        }
+
+        // IDictionary is (Int32 -> byte[])
+        public virtual IDictionary GetServerExtensions()
+        {
+            if (this.mEncryptThenMacOffered && AllowEncryptThenMac)
+            {
+                /*
+                 * draft-ietf-tls-encrypt-then-mac-03 3. If a server receives an encrypt-then-MAC
+                 * request extension from a client and then selects a stream or AEAD cipher suite, it
+                 * MUST NOT send an encrypt-then-MAC response extension back to the client.
+                 */
+                if (TlsUtilities.IsBlockCipherSuite(this.mSelectedCipherSuite))
+                {
+                    TlsExtensionsUtilities.AddEncryptThenMacExtension(CheckServerExtensions());
+                }
+            }
+
+            if (this.mMaxFragmentLengthOffered >= 0)
+            {
+                TlsExtensionsUtilities.AddMaxFragmentLengthExtension(CheckServerExtensions(), (byte)this.mMaxFragmentLengthOffered);
+            }
+
+            if (this.mTruncatedHMacOffered && AllowTruncatedHMac)
+            {
+                TlsExtensionsUtilities.AddTruncatedHMacExtension(CheckServerExtensions());
+            }
+
+            if (this.mClientECPointFormats != null && TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
+            {
+                /*
+                 * RFC 4492 5.2. A server that selects an ECC cipher suite in response to a ClientHello
+                 * message including a Supported Point Formats Extension appends this extension (along
+                 * with others) to its ServerHello message, enumerating the point formats it can parse.
+                 */
+                this.mServerECPointFormats = new byte[]{ ECPointFormat.uncompressed,
+                    ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };
+
+                TlsEccUtilities.AddSupportedPointFormatsExtension(CheckServerExtensions(), mServerECPointFormats);
+            }
+
+            return mServerExtensions;
+        }
+
+        public virtual IList GetServerSupplementalData()
+        {
+            return null;
+        }
+
+        public abstract TlsCredentials GetCredentials();
+
+        public virtual CertificateStatus GetCertificateStatus()
+        {
+            return null;
+        }
+
+        public abstract TlsKeyExchange GetKeyExchange();
+
+        public virtual CertificateRequest GetCertificateRequest()
+        {
+            return null;
+        }
+
+        public virtual void ProcessClientSupplementalData(IList clientSupplementalData)
+        {
+            if (clientSupplementalData != null)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public virtual void NotifyClientCertificate(Certificate clientCertificate)
+        {
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public override TlsCompression GetCompression()
+        {
+            switch (mSelectedCompressionMethod)
+            {
+            case CompressionMethod.cls_null:
+                return new TlsNullCompression();
+
+            default:
+                /*
+                 * Note: internal error here; we selected the compression method, so if we now can't
+                 * produce an implementation, we shouldn't have chosen it!
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public virtual NewSessionTicket GetNewSessionTicket()
+        {
+            /*
+             * RFC 5077 3.3. If the server determines that it does not want to include a ticket after it
+             * has included the SessionTicket extension in the ServerHello, then it sends a zero-length
+             * ticket in the NewSessionTicket handshake message.
+             */
+            return new NewSessionTicket(0L, TlsUtilities.EmptyBytes);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsSigner.cs b/crypto/src/crypto/tls/AbstractTlsSigner.cs
new file mode 100644
index 000000000..1f4aabf74
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsSigner.cs
@@ -0,0 +1,50 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsSigner
+        :   TlsSigner
+    {
+        protected TlsContext mContext;
+
+        public virtual void Init(TlsContext context)
+        {
+            this.mContext = context;
+        }
+
+        public virtual byte[] GenerateRawSignature(AsymmetricKeyParameter privateKey, byte[] md5AndSha1)
+        {
+            return GenerateRawSignature(null, privateKey, md5AndSha1);
+        }
+
+        public abstract byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+            AsymmetricKeyParameter privateKey, byte[] hash);
+
+        public virtual bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5AndSha1)
+        {
+            return VerifyRawSignature(null, sigBytes, publicKey, md5AndSha1);
+        }
+
+        public abstract bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+            AsymmetricKeyParameter publicKey, byte[] hash);
+
+        public virtual ISigner CreateSigner(AsymmetricKeyParameter privateKey)
+        {
+            return CreateSigner(null, privateKey);
+        }
+
+        public abstract ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey);
+
+        public virtual ISigner CreateVerifyer(AsymmetricKeyParameter publicKey)
+        {
+            return CreateVerifyer(null, publicKey);
+        }
+
+        public abstract ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey);
+
+        public abstract bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
+    }
+}
diff --git a/crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs b/crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs
new file mode 100644
index 000000000..886c46c6e
--- /dev/null
+++ b/crypto/src/crypto/tls/AbstractTlsSignerCredentials.cs
@@ -0,0 +1,20 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class AbstractTlsSignerCredentials
+        : AbstractTlsCredentials, TlsSignerCredentials
+    {
+        /// <exception cref="IOException"></exception>
+        public abstract byte[] GenerateCertificateSignature(byte[] hash);
+
+        public virtual SignatureAndHashAlgorithm SignatureAndHashAlgorithm
+        {
+            get
+            {
+                throw new InvalidOperationException("TlsSignerCredentials implementation does not support (D)TLS 1.2+");
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/AlertDescription.cs b/crypto/src/crypto/tls/AlertDescription.cs
index e1229a4a3..e09da6cab 100644
--- a/crypto/src/crypto/tls/AlertDescription.cs
+++ b/crypto/src/crypto/tls/AlertDescription.cs
@@ -1,47 +1,217 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 7.2
-	/// </summary>
-	public enum AlertDescription : byte
-	{
-		close_notify = 0,
-		unexpected_message = 10,
-		bad_record_mac = 20,
-		decryption_failed = 21,
-		record_overflow = 22,
-		decompression_failure = 30,
-		handshake_failure = 40,
-		/* 41 is not defined, for historical reasons */
-		bad_certificate = 42,
-		unsupported_certificate = 43,
-		certificate_revoked = 44,
-		certificate_expired = 45,
-		certificate_unknown = 46,
-		illegal_parameter = 47,
-		unknown_ca = 48,
-		access_denied = 49,
-		decode_error = 50,
-		decrypt_error = 51,
-		export_restriction = 60,
-		protocol_version = 70,
-		insufficient_security = 71,
-		internal_error = 80,
-		user_canceled = 90,
-		no_renegotiation = 100,
-
-		/*
-		 *  RFC 3546
-		 */
-		unsupported_extension = 110,
-		certificate_unobtainable = 111,
-		unrecognized_name = 112,
-		bad_certificate_status_response = 113,
-		bad_certificate_hash_value = 114,
-
-		/*
-		 *  RFC 4279
-		 */
-		unknown_psk_identity = 115,
-	}
+    /// <summary>
+    /// RFC 5246 7.2
+    /// </summary>
+    public abstract class AlertDescription
+    {
+        /**
+         * This message notifies the recipient that the sender will not send any more messages on this
+         * connection. Note that as of TLS 1.1, failure to properly close a connection no longer
+         * requires that a session not be resumed. This is a change from TLS 1.0 ("The session becomes
+         * unresumable if any connection is terminated without proper close_notify messages with level
+         * equal to warning.") to conform with widespread implementation practice.
+         */
+        public const byte close_notify = 0;
+
+        /**
+         * An inappropriate message was received. This alert is always fatal and should never be
+         * observed in communication between proper implementations.
+         */
+        public const byte unexpected_message = 10;
+
+        /**
+         * This alert is returned if a record is received with an incorrect MAC. This alert also MUST be
+         * returned if an alert is sent because a TLSCiphertext decrypted in an invalid way: either it
+         * wasn't an even multiple of the block length, or its padding values, when checked, weren't
+         * correct. This message is always fatal and should never be observed in communication between
+         * proper implementations (except when messages were corrupted in the network).
+         */
+        public const byte bad_record_mac = 20;
+
+        /**
+         * This alert was used in some earlier versions of TLS, and may have permitted certain attacks
+         * against the CBC mode [CBCATT]. It MUST NOT be sent by compliant implementations.
+         */
+        public const byte decryption_failed = 21;
+
+        /**
+         * A TLSCiphertext record was received that had a length more than 2^14+2048 bytes, or a record
+         * decrypted to a TLSCompressed record with more than 2^14+1024 bytes. This message is always
+         * fatal and should never be observed in communication between proper implementations (except
+         * when messages were corrupted in the network).
+         */
+        public const byte record_overflow = 22;
+
+        /**
+         * The decompression function received improper input (e.g., data that would expand to excessive
+         * length). This message is always fatal and should never be observed in communication between
+         * proper implementations.
+         */
+        public const byte decompression_failure = 30;
+
+        /**
+         * Reception of a handshake_failure alert message indicates that the sender was unable to
+         * negotiate an acceptable set of security parameters given the options available. This is a
+         * fatal error.
+         */
+        public const byte handshake_failure = 40;
+
+        /**
+         * This alert was used in SSLv3 but not any version of TLS. It MUST NOT be sent by compliant
+         * implementations.
+         */
+        public const byte no_certificate = 41;
+
+        /**
+         * A certificate was corrupt, contained signatures that did not verify correctly, etc.
+         */
+        public const byte bad_certificate = 42;
+
+        /**
+         * A certificate was of an unsupported type.
+         */
+        public const byte unsupported_certificate = 43;
+
+        /**
+         * A certificate was revoked by its signer.
+         */
+        public const byte certificate_revoked = 44;
+
+        /**
+         * A certificate has expired or is not currently valid.
+         */
+        public const byte certificate_expired = 45;
+
+        /**
+         * Some other (unspecified) issue arose in processing the certificate, rendering it
+         * unacceptable.
+         */
+        public const byte certificate_unknown = 46;
+
+        /**
+         * A field in the handshake was out of range or inconsistent with other fields. This message is
+         * always fatal.
+         */
+        public const byte illegal_parameter = 47;
+
+        /**
+         * A valid certificate chain or partial chain was received, but the certificate was not accepted
+         * because the CA certificate could not be located or couldn't be matched with a known, trusted
+         * CA. This message is always fatal.
+         */
+        public const byte unknown_ca = 48;
+
+        /**
+         * A valid certificate was received, but when access control was applied, the sender decided not
+         * to proceed with negotiation. This message is always fatal.
+         */
+        public const byte access_denied = 49;
+
+        /**
+         * A message could not be decoded because some field was out of the specified range or the
+         * length of the message was incorrect. This message is always fatal and should never be
+         * observed in communication between proper implementations (except when messages were corrupted
+         * in the network).
+         */
+        public const byte decode_error = 50;
+
+        /**
+         * A handshake cryptographic operation failed, including being unable to correctly verify a
+         * signature or validate a Finished message. This message is always fatal.
+         */
+        public const byte decrypt_error = 51;
+
+        /**
+         * This alert was used in some earlier versions of TLS. It MUST NOT be sent by compliant
+         * implementations.
+         */
+        public const byte export_restriction = 60;
+
+        /**
+         * The protocol version the client has attempted to negotiate is recognized but not supported.
+         * (For example, old protocol versions might be avoided for security reasons.) This message is
+         * always fatal.
+         */
+        public const byte protocol_version = 70;
+
+        /**
+         * Returned instead of handshake_failure when a negotiation has failed specifically because the
+         * server requires ciphers more secure than those supported by the client. This message is
+         * always fatal.
+         */
+        public const byte insufficient_security = 71;
+
+        /**
+         * An internal error unrelated to the peer or the correctness of the protocol (such as a memory
+         * allocation failure) makes it impossible to continue. This message is always fatal.
+         */
+        public const byte internal_error = 80;
+
+        /**
+         * This handshake is being canceled for some reason unrelated to a protocol failure. If the user
+         * cancels an operation after the handshake is complete, just closing the connection by sending
+         * a close_notify is more appropriate. This alert should be followed by a close_notify. This
+         * message is generally a warning.
+         */
+        public const byte user_canceled = 90;
+
+        /**
+         * Sent by the client in response to a hello request or by the server in response to a client
+         * hello after initial handshaking. Either of these would normally lead to renegotiation; when
+         * that is not appropriate, the recipient should respond with this alert. At that point, the
+         * original requester can decide whether to proceed with the connection. One case where this
+         * would be appropriate is where a server has spawned a process to satisfy a request; the
+         * process might receive security parameters (key length, authentication, etc.) at startup, and
+         * it might be difficult to communicate changes to these parameters after that point. This
+         * message is always a warning.
+         */
+        public const byte no_renegotiation = 100;
+
+        /**
+         * Sent by clients that receive an extended server hello containing an extension that they did
+         * not put in the corresponding client hello. This message is always fatal.
+         */
+        public const byte unsupported_extension = 110;
+
+        /*
+         * RFC 3546
+         */
+
+        /**
+         * This alert is sent by servers who are unable to retrieve a certificate chain from the URL
+         * supplied by the client (see Section 3.3). This message MAY be fatal - for example if client
+         * authentication is required by the server for the handshake to continue and the server is
+         * unable to retrieve the certificate chain, it may send a fatal alert.
+         */
+        public const byte certificate_unobtainable = 111;
+
+        /**
+         * This alert is sent by servers that receive a server_name extension request, but do not
+         * recognize the server name. This message MAY be fatal.
+         */
+        public const byte unrecognized_name = 112;
+
+        /**
+         * This alert is sent by clients that receive an invalid certificate status response (see
+         * Section 3.6). This message is always fatal.
+         */
+        public const byte bad_certificate_status_response = 113;
+
+        /**
+         * This alert is sent by servers when a certificate hash does not match a client provided
+         * certificate_hash. This message is always fatal.
+         */
+        public const byte bad_certificate_hash_value = 114;
+
+        /*
+         * RFC 4279
+         */
+
+        /**
+         * If the server does not recognize the PSK identity, it MAY respond with an
+         * "unknown_psk_identity" alert message.
+         */
+        public const byte unknown_psk_identity = 115;
+    }
 }
diff --git a/crypto/src/crypto/tls/AlertLevel.cs b/crypto/src/crypto/tls/AlertLevel.cs
index afb04308b..d77251dfb 100644
--- a/crypto/src/crypto/tls/AlertLevel.cs
+++ b/crypto/src/crypto/tls/AlertLevel.cs
@@ -1,11 +1,11 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 7.2
-	/// </summary>
-    public enum AlertLevel : byte
-	{
-	    warning = 1,
-	    fatal = 2,
-	}
+    /// <summary>
+    /// RFC 5246 7.2
+    /// </summary>
+    public abstract class AlertLevel
+    {
+        public const byte warning = 1;
+        public const byte fatal = 2;
+    }
 }
diff --git a/crypto/src/crypto/tls/BulkCipherAlgorithm.cs b/crypto/src/crypto/tls/BulkCipherAlgorithm.cs
new file mode 100644
index 000000000..07ff8dc07
--- /dev/null
+++ b/crypto/src/crypto/tls/BulkCipherAlgorithm.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 2246</summary>
+    /// <remarks>
+    /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+    /// depend on the particular values (e.g. serialization).
+    /// </remarks>
+    public abstract class BulkCipherAlgorithm
+    {
+        public const int cls_null = 0;
+        public const int rc4 = 1;
+        public const int rc2 = 2;
+        public const int des = 3;
+        public const int cls_3des = 4;
+        public const int des40 = 5;
+
+        /*
+         * RFC 4346
+         */
+        public const int aes = 6;
+        public const int idea = 7;
+    }
+}
diff --git a/crypto/src/crypto/tls/ByteQueue.cs b/crypto/src/crypto/tls/ByteQueue.cs
index 96062402b..f9398bbaf 100644
--- a/crypto/src/crypto/tls/ByteQueue.cs
+++ b/crypto/src/crypto/tls/ByteQueue.cs
@@ -2,124 +2,146 @@ using System;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <remarks>
-	/// A queue for bytes.
-	/// <p>
-	/// This file could be more optimized.
-	/// </p>
-	/// </remarks>
-	public class ByteQueue
-	{
-		/// <returns>The smallest number which can be written as 2^x which is bigger than i.</returns>
-		public static int NextTwoPow(
-			int i)
-		{
-			/*
-			* This code is based of a lot of code I found on the Internet
-			* which mostly referenced a book called "Hacking delight".
-			*
-			*/
-			i |= (i >> 1);
-			i |= (i >> 2);
-			i |= (i >> 4);
-			i |= (i >> 8);
-			i |= (i >> 16);
-			return i + 1;
-		}
+    /// <remarks>
+    /// A queue for bytes.
+    /// <p>
+    /// This file could be more optimized.
+    /// </p>
+    /// </remarks>
+    public class ByteQueue
+    {
+        /// <returns>The smallest number which can be written as 2^x which is bigger than i.</returns>
+        public static int NextTwoPow(
+            int i)
+        {
+            /*
+            * This code is based of a lot of code I found on the Internet
+            * which mostly referenced a book called "Hacking delight".
+            *
+            */
+            i |= (i >> 1);
+            i |= (i >> 2);
+            i |= (i >> 4);
+            i |= (i >> 8);
+            i |= (i >> 16);
+            return i + 1;
+        }
 
-		/**
-		 * The initial size for our buffer.
-		 */
-		private const int InitBufSize = 1024;
+        /**
+         * The initial size for our buffer.
+         */
+        private const int DefaultCapacity = 1024;
 
-		/**
-		 * The buffer where we store our data.
-		 */
-		private byte[] databuf = new byte[ByteQueue.InitBufSize];
+        /**
+         * The buffer where we store our data.
+         */
+        private byte[] databuf;
 
-		/**
-		 * How many bytes at the beginning of the buffer are skipped.
-		 */
-		private int skipped = 0;
+        /**
+         * How many bytes at the beginning of the buffer are skipped.
+         */
+        private int skipped = 0;
 
-		/**
-		 * How many bytes in the buffer are valid data.
-		 */
-		private int available = 0;
+        /**
+         * How many bytes in the buffer are valid data.
+         */
+        private int available = 0;
 
-		/// <summary>Read data from the buffer.</summary>
-		/// <param name="buf">The buffer where the read data will be copied to.</param>
-		/// <param name="offset">How many bytes to skip at the beginning of buf.</param>
-		/// <param name="len">How many bytes to read at all.</param>
-		/// <param name="skip">How many bytes from our data to skip.</param>
-		public void Read(
-			byte[]	buf,
-			int		offset,
-			int		len,
-			int		skip)
-		{
-			if ((available - skip) < len)
-			{
-				throw new TlsException("Not enough data to read");
-			}
-			if ((buf.Length - offset) < len)
-			{
-				throw new TlsException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
-			}
-			Array.Copy(databuf, skipped + skip, buf, offset, len);
-		}
+        public ByteQueue()
+            : this(DefaultCapacity)
+        {
+        }
 
-		/// <summary>Add some data to our buffer.</summary>
-		/// <param name="data">A byte-array to read data from.</param>
-		/// <param name="offset">How many bytes to skip at the beginning of the array.</param>
-		/// <param name="len">How many bytes to read from the array.</param>
-		public void AddData(
-			byte[]	data,
-			int		offset,
-			int		len)
-		{
-			if ((skipped + available + len) > databuf.Length)
-			{
-				byte[] tmp = new byte[ByteQueue.NextTwoPow(data.Length)];
-				Array.Copy(databuf, skipped, tmp, 0, available);
-				skipped = 0;
-				databuf = tmp;
-			}
-			Array.Copy(data, offset, databuf, skipped + available, len);
-			available += len;
-		}
+        public ByteQueue(int capacity)
+        {
+            this.databuf = new byte[capacity];
+        }
 
-		/// <summary>Remove some bytes from our data from the beginning.</summary>
-		/// <param name="i">How many bytes to remove.</param>
-		public void RemoveData(
-			int i)
-		{
-			if (i > available)
-			{
-				throw new TlsException("Cannot remove " + i + " bytes, only got " + available);
-			}
+        /// <summary>Read data from the buffer.</summary>
+        /// <param name="buf">The buffer where the read data will be copied to.</param>
+        /// <param name="offset">How many bytes to skip at the beginning of buf.</param>
+        /// <param name="len">How many bytes to read at all.</param>
+        /// <param name="skip">How many bytes from our data to skip.</param>
+        public void Read(
+            byte[]	buf,
+            int		offset,
+            int		len,
+            int		skip)
+        {
+            if ((buf.Length - offset) < len)
+            {
+                throw new ArgumentException("Buffer size of " + buf.Length + " is too small for a read of " + len + " bytes");
+            }
+            if ((available - skip) < len)
+            {
+                throw new InvalidOperationException("Not enough data to read");
+            }
+            Array.Copy(databuf, skipped + skip, buf, offset, len);
+        }
 
-			/*
-			* Skip the data.
-			*/
-			available -= i;
-			skipped += i;
+        /// <summary>Add some data to our buffer.</summary>
+        /// <param name="data">A byte-array to read data from.</param>
+        /// <param name="offset">How many bytes to skip at the beginning of the array.</param>
+        /// <param name="len">How many bytes to read from the array.</param>
+        public void AddData(
+            byte[]	data,
+            int		offset,
+            int		len)
+        {
+            if ((skipped + available + len) > databuf.Length)
+            {
+                int desiredSize = ByteQueue.NextTwoPow(available + len);
+                if (desiredSize > databuf.Length)
+                {
+                    byte[] tmp = new byte[desiredSize];
+                    Array.Copy(databuf, skipped, tmp, 0, available);
+                    databuf = tmp;
+                }
+                else
+                {
+                    Array.Copy(databuf, skipped, databuf, 0, available);
+                }
+                skipped = 0;
+            }
 
-			/*
-			* If more than half of our data is skipped, we will move the data
-			* in the buffer.
-			*/
-			if (skipped > (databuf.Length / 2))
-			{
-				Array.Copy(databuf, skipped, databuf, 0, available);
-				skipped = 0;
-			}
-		}
+            Array.Copy(data, offset, databuf, skipped + available, len);
+            available += len;
+        }
 
-		/// <summary>The number of bytes which are available in this buffer.</summary>
-		public int Available
-		{
-			get { return available; }
-		}
-	}
+        /// <summary>Remove some bytes from our data from the beginning.</summary>
+        /// <param name="i">How many bytes to remove.</param>
+        public void RemoveData(
+            int i)
+        {
+            if (i > available)
+            {
+                throw new InvalidOperationException("Cannot remove " + i + " bytes, only got " + available);
+            }
+
+            /*
+            * Skip the data.
+            */
+            available -= i;
+            skipped += i;
+        }
+
+        public void RemoveData(byte[] buf, int off, int len, int skip)
+        {
+            Read(buf, off, len, skip);
+            RemoveData(skip + len);
+        }
+
+        public byte[] RemoveData(int len, int skip)
+        {
+            byte[] buf = new byte[len];
+            RemoveData(buf, 0, len, skip);
+            return buf;
+        }
+
+        /// <summary>The number of bytes which are available in this buffer.</summary>
+        public int Available
+        {
+            get { return available; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/CertChainType.cs b/crypto/src/crypto/tls/CertChainType.cs
new file mode 100644
index 000000000..cbb183441
--- /dev/null
+++ b/crypto/src/crypto/tls/CertChainType.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /*
+     * RFC 3546 3.3.
+     */
+    public abstract class CertChainType
+    {
+        public const byte individual_certs = 0;
+        public const byte pkipath = 1;
+
+        public static bool IsValid(byte certChainType)
+        {
+            return certChainType >= individual_certs && certChainType <= pkipath;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/Certificate.cs b/crypto/src/crypto/tls/Certificate.cs
index e4df041e2..c59616c95 100644
--- a/crypto/src/crypto/tls/Certificate.cs
+++ b/crypto/src/crypto/tls/Certificate.cs
@@ -8,104 +8,129 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/**
-	* A representation for a certificate chain.
-	*/
-	public class Certificate
-	{
-		public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]);
-
-		/**
-		* The certificates.
-		*/
-		internal X509CertificateStructure[] certs;
-
-		/**
-		* Parse the ServerCertificate message.
-		*
-		* @param inStr The stream where to parse from.
-		* @return A Certificate object with the certs, the server has sended.
-		* @throws IOException If something goes wrong during parsing.
-		*/
-		internal static Certificate Parse(
-			Stream inStr)
-		{
-			int left = TlsUtilities.ReadUint24(inStr);
-			if (left == 0)
-			{
-				return EmptyChain;
-			}
-			IList tmp = Platform.CreateArrayList();
-			while (left > 0)
-			{
-				int size = TlsUtilities.ReadUint24(inStr);
-				left -= 3 + size;
-				byte[] buf = new byte[size];
-				TlsUtilities.ReadFully(buf, inStr);
-				MemoryStream bis = new MemoryStream(buf, false);
-				Asn1Object o = Asn1Object.FromStream(bis);
-				tmp.Add(X509CertificateStructure.GetInstance(o));
-				if (bis.Position < bis.Length)
-				{
-					throw new ArgumentException("Sorry, there is garbage data left after the certificate");
-				}
-			}
-            X509CertificateStructure[] certs = new X509CertificateStructure[tmp.Count];
-            for (int i = 0; i < tmp.Count; ++i)
+    /**
+     * Parsing and encoding of a <i>Certificate</i> struct from RFC 4346.
+     * <p/>
+     * <pre>
+     * opaque ASN.1Cert&lt;2^24-1&gt;;
+     *
+     * struct {
+     *     ASN.1Cert certificate_list&lt;0..2^24-1&gt;;
+     * } Certificate;
+     * </pre>
+     *
+     * @see Org.BouncyCastle.Asn1.X509.X509CertificateStructure
+     */
+    public class Certificate
+    {
+        public static readonly Certificate EmptyChain = new Certificate(new X509CertificateStructure[0]);
+
+        /**
+        * The certificates.
+        */
+        protected readonly X509CertificateStructure[] mCertificateList;
+
+        public Certificate(X509CertificateStructure[] certificateList)
+        {
+            if (certificateList == null)
+                throw new ArgumentNullException("certificateList");
+
+            this.mCertificateList = certificateList;
+        }
+
+        /**
+         * @return an array of {@link org.bouncycastle.asn1.x509.Certificate} representing a certificate
+         *         chain.
+         */
+        public virtual X509CertificateStructure[] GetCertificateList()
+        {
+            return CloneCertificateList();
+        }
+
+        public virtual X509CertificateStructure GetCertificateAt(int index)
+        {
+            return mCertificateList[index];
+        }
+
+        public virtual int Length
+        {
+            get { return mCertificateList.Length; }
+        }
+
+        /**
+         * @return <code>true</code> if this certificate chain contains no certificates, or
+         *         <code>false</code> otherwise.
+         */
+        public virtual bool IsEmpty
+        {
+            get { return mCertificateList.Length == 0; }
+        }
+
+        /**
+         * Encode this {@link Certificate} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            IList derEncodings = Platform.CreateArrayList(mCertificateList.Length);
+
+            int totalLength = 0;
+            foreach (Asn1Encodable asn1Cert in mCertificateList)
+            {
+                byte[] derEncoding = asn1Cert.GetEncoded(Asn1Encodable.Der);
+                derEncodings.Add(derEncoding);
+                totalLength += derEncoding.Length + 3;
+            }
+
+            TlsUtilities.CheckUint24(totalLength);
+            TlsUtilities.WriteUint24(totalLength, output);
+
+            foreach (byte[] derEncoding in derEncodings)
             {
-                certs[i] = (X509CertificateStructure)tmp[i];
+                TlsUtilities.WriteOpaque24(derEncoding, output);
             }
-			return new Certificate(certs);
-		}
-
-		/**
-		 * Encodes version of the ClientCertificate message
-		 *
-		 * @param outStr stream to write the message to
-		 * @throws IOException If something goes wrong
-		 */
-		internal void Encode(
-			Stream outStr)
-		{
-			IList encCerts = Platform.CreateArrayList();
-			int totalSize = 0;
-			foreach (X509CertificateStructure cert in certs)
-			{
-				byte[] encCert = cert.GetEncoded(Asn1Encodable.Der);
-				encCerts.Add(encCert);
-				totalSize += encCert.Length + 3;
-			}
-
-			TlsUtilities.WriteUint24(totalSize, outStr);
-
-			foreach (byte[] encCert in encCerts)
-			{
-				TlsUtilities.WriteOpaque24(encCert, outStr);
-			}
-		}
-
-		/**
-		* Private constructor from a cert array.
-		*
-		* @param certs The certs the chain should contain.
-		*/
-		public Certificate(X509CertificateStructure[] certs)
-		{
-			if (certs == null)
-				throw new ArgumentNullException("certs");
-
-			this.certs = certs;
-		}
-
-		/// <returns>An array which contains the certs, this chain contains.</returns>
-		public X509CertificateStructure[] GetCerts()
-		{
-			return (X509CertificateStructure[]) certs.Clone();
-		}
-
-		public bool IsEmpty
-		{
-			get { return certs.Length == 0; }
-		}
-	}
+        }
+
+        /**
+         * Parse a {@link Certificate} from a {@link Stream}.
+         *
+         * @param input the {@link Stream} to parse from.
+         * @return a {@link Certificate} object.
+         * @throws IOException
+         */
+        public static Certificate Parse(Stream input)
+        {
+            int totalLength = TlsUtilities.ReadUint24(input);
+            if (totalLength == 0)
+            {
+                return EmptyChain;
+            }
+
+            byte[] certListData = TlsUtilities.ReadFully(totalLength, input);
+
+            MemoryStream buf = new MemoryStream(certListData, false);
+
+            IList certificate_list = Platform.CreateArrayList();
+            while (buf.Position < buf.Length)
+            {
+                byte[] derEncoding = TlsUtilities.ReadOpaque24(buf);
+                Asn1Object asn1Cert = TlsUtilities.ReadDerObject(derEncoding);
+                certificate_list.Add(X509CertificateStructure.GetInstance(asn1Cert));
+            }
+
+            X509CertificateStructure[] certificateList = new X509CertificateStructure[certificate_list.Count];
+            for (int i = 0; i < certificate_list.Count; ++i)
+            {
+                certificateList[i] = (X509CertificateStructure)certificate_list[i];
+            }
+            return new Certificate(certificateList);
+        }
+
+        protected virtual X509CertificateStructure[] CloneCertificateList()
+        {
+            return (X509CertificateStructure[])mCertificateList.Clone();
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/CertificateRequest.cs b/crypto/src/crypto/tls/CertificateRequest.cs
index 49d8ba6fb..f3dcb3bbd 100644
--- a/crypto/src/crypto/tls/CertificateRequest.cs
+++ b/crypto/src/crypto/tls/CertificateRequest.cs
@@ -1,28 +1,156 @@
 using System;
 using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class CertificateRequest
-	{
-		private ClientCertificateType[] certificateTypes;
-		private IList certificateAuthorities;
-
-		public CertificateRequest(ClientCertificateType[] certificateTypes, IList certificateAuthorities)
-		{
-			this.certificateTypes = certificateTypes;
-			this.certificateAuthorities = certificateAuthorities;
-		}
-
-		public ClientCertificateType[] CertificateTypes
-		{
-			get { return certificateTypes; }
-		}
-
-		/// <returns>A <see cref="IList"/> of X509Name</returns>
-		public IList CertificateAuthorities
-		{
-			get { return certificateAuthorities; }
-		}
-	}
-}
\ No newline at end of file
+    /**
+     * Parsing and encoding of a <i>CertificateRequest</i> struct from RFC 4346.
+     * <p/>
+     * <pre>
+     * struct {
+     *     ClientCertificateType certificate_types&lt;1..2^8-1&gt;;
+     *     DistinguishedName certificate_authorities&lt;3..2^16-1&gt;
+     * } CertificateRequest;
+     * </pre>
+     *
+     * @see ClientCertificateType
+     * @see X509Name
+     */
+    public class CertificateRequest
+    {
+        protected readonly byte[] mCertificateTypes;
+        protected readonly IList mSupportedSignatureAlgorithms;
+        protected readonly IList mCertificateAuthorities;
+
+        /**
+         * @param certificateTypes       see {@link ClientCertificateType} for valid constants.
+         * @param certificateAuthorities an {@link IList} of {@link X509Name}.
+         */
+        public CertificateRequest(byte[] certificateTypes, IList supportedSignatureAlgorithms,
+            IList certificateAuthorities)
+        {
+            this.mCertificateTypes = certificateTypes;
+            this.mSupportedSignatureAlgorithms = supportedSignatureAlgorithms;
+            this.mCertificateAuthorities = certificateAuthorities;
+        }
+
+        /**
+         * @return an array of certificate types
+         * @see {@link ClientCertificateType}
+         */
+        public virtual byte[] CertificateTypes
+        {
+            get { return mCertificateTypes; }
+        }
+
+        /**
+         * @return an {@link IList} of {@link SignatureAndHashAlgorithm} (or null before TLS 1.2).
+         */
+        public virtual IList SupportedSignatureAlgorithms
+        {
+            get { return mSupportedSignatureAlgorithms; }
+        }
+
+        /**
+         * @return an {@link IList} of {@link X509Name}
+         */
+        public virtual IList CertificateAuthorities
+        {
+            get { return mCertificateAuthorities; }
+        }
+
+        /**
+         * Encode this {@link CertificateRequest} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            if (mCertificateTypes == null || mCertificateTypes.Length == 0)
+            {
+                TlsUtilities.WriteUint8(0, output);
+            }
+            else
+            {
+                TlsUtilities.WriteUint8ArrayWithUint8Length(mCertificateTypes, output);
+            }
+
+            if (mSupportedSignatureAlgorithms != null)
+            {
+                // TODO Check whether SignatureAlgorithm.anonymous is allowed here
+                TlsUtilities.EncodeSupportedSignatureAlgorithms(mSupportedSignatureAlgorithms, false, output);
+            }
+
+            if (mCertificateAuthorities == null || mCertificateAuthorities.Count < 1)
+            {
+                TlsUtilities.WriteUint16(0, output);
+            }
+            else
+            {
+                IList derEncodings = Platform.CreateArrayList(mCertificateAuthorities.Count);
+
+                int totalLength = 0;
+                foreach (Asn1Encodable certificateAuthority in mCertificateAuthorities)
+                {
+                    byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der);
+                    derEncodings.Add(derEncoding);
+                    totalLength += derEncoding.Length + 2;
+                }
+
+                TlsUtilities.CheckUint16(totalLength);
+                TlsUtilities.WriteUint16(totalLength, output);
+
+                foreach (byte[] derEncoding in derEncodings)
+                {
+                    TlsUtilities.WriteOpaque16(derEncoding, output);
+                }
+            }
+        }
+
+        /**
+         * Parse a {@link CertificateRequest} from a {@link Stream}.
+         * 
+         * @param context
+         *            the {@link TlsContext} of the current connection.
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link CertificateRequest} object.
+         * @throws IOException
+         */
+        public static CertificateRequest Parse(TlsContext context, Stream input)
+        {
+            int numTypes = TlsUtilities.ReadUint8(input);
+            byte[] certificateTypes = new byte[numTypes];
+            for (int i = 0; i < numTypes; ++i)
+            {
+                certificateTypes[i] = TlsUtilities.ReadUint8(input);
+            }
+
+            IList supportedSignatureAlgorithms = null;
+            if (TlsUtilities.IsTlsV12(context))
+            {
+                // TODO Check whether SignatureAlgorithm.anonymous is allowed here
+                supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(false, input);
+            }
+
+            IList certificateAuthorities = Platform.CreateArrayList();
+            byte[] certAuthData = TlsUtilities.ReadOpaque16(input);
+            MemoryStream bis = new MemoryStream(certAuthData, false);
+            while (bis.Position < bis.Length)
+            {
+                byte[] derEncoding = TlsUtilities.ReadOpaque16(bis);
+                Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding);
+                // TODO Switch to X500Name when available
+                certificateAuthorities.Add(X509Name.GetInstance(asn1));
+            }
+
+            return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/CertificateStatus.cs b/crypto/src/crypto/tls/CertificateStatus.cs
new file mode 100644
index 000000000..0f95475b9
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateStatus.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class CertificateStatus
+    {
+        protected readonly byte mStatusType;
+        protected readonly object mResponse;
+
+        public CertificateStatus(byte statusType, object response)
+        {
+            if (!IsCorrectType(statusType, response))
+                throw new ArgumentException("not an instance of the correct type", "response");
+
+            this.mStatusType = statusType;
+            this.mResponse = response;
+        }
+
+        public virtual byte StatusType
+        {
+            get { return mStatusType; }
+        }
+
+        public virtual object Response
+        {
+            get { return mResponse; }
+        }
+
+        public virtual OcspResponse GetOcspResponse()
+        {
+            if (!IsCorrectType(CertificateStatusType.ocsp, mResponse))
+                throw new InvalidOperationException("'response' is not an OcspResponse");
+
+            return (OcspResponse)mResponse;
+        }
+
+        /**
+         * Encode this {@link CertificateStatus} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint8(mStatusType, output);
+
+            switch (mStatusType)
+            {
+            case CertificateStatusType.ocsp:
+                byte[] derEncoding = ((OcspResponse)mResponse).GetEncoded(Asn1Encodable.Der);
+                TlsUtilities.WriteOpaque24(derEncoding, output);
+                break;
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        /**
+         * Parse a {@link CertificateStatus} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link CertificateStatus} object.
+         * @throws IOException
+         */
+        public static CertificateStatus Parse(Stream input)
+        {
+            byte status_type = TlsUtilities.ReadUint8(input);
+            object response;
+
+            switch (status_type)
+            {
+            case CertificateStatusType.ocsp:
+            {
+                byte[] derEncoding = TlsUtilities.ReadOpaque24(input);
+                response = OcspResponse.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+                break;
+            }
+            default:
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            }
+
+            return new CertificateStatus(status_type, response);
+        }
+
+        protected static bool IsCorrectType(byte statusType, object response)
+        {
+            switch (statusType)
+            {
+            case CertificateStatusType.ocsp:
+                return response is OcspResponse;
+            default:
+                throw new ArgumentException("unsupported value", "statusType");
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/CertificateStatusRequest.cs b/crypto/src/crypto/tls/CertificateStatusRequest.cs
new file mode 100644
index 000000000..9587d7df8
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateStatusRequest.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class CertificateStatusRequest
+    {
+        protected readonly byte mStatusType;
+        protected readonly object mRequest;
+
+        public CertificateStatusRequest(byte statusType, Object request)
+        {
+            if (!IsCorrectType(statusType, request))
+                throw new ArgumentException("not an instance of the correct type", "request");
+
+            this.mStatusType = statusType;
+            this.mRequest = request;
+        }
+
+        public virtual byte StatusType
+        {
+            get { return mStatusType; }
+        }
+
+        public virtual object Request
+        {
+            get { return mRequest; }
+        }
+
+        public virtual OcspStatusRequest GetOcspStatusRequest()
+        {
+            if (!IsCorrectType(CertificateStatusType.ocsp, mRequest))
+                throw new InvalidOperationException("'request' is not an OCSPStatusRequest");
+
+            return (OcspStatusRequest)mRequest;
+        }
+
+        /**
+         * Encode this {@link CertificateStatusRequest} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint8(mStatusType, output);
+
+            switch (mStatusType)
+            {
+            case CertificateStatusType.ocsp:
+                ((OcspStatusRequest)mRequest).Encode(output);
+                break;
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        /**
+         * Parse a {@link CertificateStatusRequest} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link CertificateStatusRequest} object.
+         * @throws IOException
+         */
+        public static CertificateStatusRequest Parse(Stream input)
+        {
+            byte status_type = TlsUtilities.ReadUint8(input);
+            object result;
+
+            switch (status_type)
+            {
+            case CertificateStatusType.ocsp:
+                result = OcspStatusRequest.Parse(input);
+                break;
+            default:
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            }
+
+            return new CertificateStatusRequest(status_type, result);
+        }
+
+        protected static bool IsCorrectType(byte statusType, object request)
+        {
+            switch (statusType)
+            {
+            case CertificateStatusType.ocsp:
+                return request is OcspStatusRequest;
+            default:
+                throw new ArgumentException("unsupported value", "statusType");
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/CertificateStatusType.cs b/crypto/src/crypto/tls/CertificateStatusType.cs
new file mode 100644
index 000000000..54b741b42
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateStatusType.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class CertificateStatusType
+    {
+        /*
+         *  RFC 3546 3.6
+         */
+        public const byte ocsp = 1;
+    }
+}
diff --git a/crypto/src/crypto/tls/CertificateUrl.cs b/crypto/src/crypto/tls/CertificateUrl.cs
new file mode 100644
index 000000000..a951b8063
--- /dev/null
+++ b/crypto/src/crypto/tls/CertificateUrl.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /*
+     * RFC 3546 3.3
+     */
+    public class CertificateUrl
+    {
+        protected readonly byte mType;
+        protected readonly IList mUrlAndHashList;
+
+        /**
+         * @param type
+         *            see {@link CertChainType} for valid constants.
+         * @param urlAndHashList
+         *            a {@link IList} of {@link UrlAndHash}.
+         */
+        public CertificateUrl(byte type, IList urlAndHashList)
+        {
+            if (!CertChainType.IsValid(type))
+                throw new ArgumentException("not a valid CertChainType value", "type");
+            if (urlAndHashList == null || urlAndHashList.Count < 1)
+                throw new ArgumentException("must have length > 0", "urlAndHashList");
+
+            this.mType = type;
+            this.mUrlAndHashList = urlAndHashList;
+        }
+
+        /**
+         * @return {@link CertChainType}
+         */
+        public virtual byte Type
+        {
+            get { return mType; }
+        }
+
+        /**
+         * @return an {@link IList} of {@link UrlAndHash} 
+         */
+        public virtual IList UrlAndHashList
+        {
+            get { return mUrlAndHashList; }
+        }
+
+        /**
+         * Encode this {@link CertificateUrl} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint8(this.mType, output);
+
+            ListBuffer16 buf = new ListBuffer16();
+            foreach (UrlAndHash urlAndHash in this.mUrlAndHashList)
+            {
+                urlAndHash.Encode(buf);
+            }
+            buf.EncodeTo(output);
+        }
+
+        /**
+         * Parse a {@link CertificateUrl} from a {@link Stream}.
+         * 
+         * @param context
+         *            the {@link TlsContext} of the current connection.
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link CertificateUrl} object.
+         * @throws IOException
+         */
+        public static CertificateUrl parse(TlsContext context, Stream input)
+        {
+            byte type = TlsUtilities.ReadUint8(input);
+            if (!CertChainType.IsValid(type))
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int totalLength = TlsUtilities.ReadUint16(input);
+            if (totalLength < 1)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            byte[] urlAndHashListData = TlsUtilities.ReadFully(totalLength, input);
+
+            MemoryStream buf = new MemoryStream(urlAndHashListData, false);
+
+            IList url_and_hash_list = Platform.CreateArrayList();
+            while (buf.Position < buf.Length)
+            {
+                UrlAndHash url_and_hash = UrlAndHash.Parse(context, buf);
+                url_and_hash_list.Add(url_and_hash);
+            }
+
+            return new CertificateUrl(type, url_and_hash_list);
+        }
+
+        // TODO Could be more generally useful
+        internal class ListBuffer16
+            : MemoryStream
+        {
+            internal ListBuffer16()
+            {
+                // Reserve space for length
+                TlsUtilities.WriteUint16(0,  this);
+            }
+
+            internal void EncodeTo(Stream output)
+            {
+                // Patch actual length back in
+                long length = Length - 2;
+                TlsUtilities.CheckUint16(length);
+                this.Position = 0;
+                TlsUtilities.WriteUint16((int)length, this);
+                this.WriteTo(output);
+                this.Close();
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/Chacha20Poly1305.cs b/crypto/src/crypto/tls/Chacha20Poly1305.cs
new file mode 100644
index 000000000..e4e4c7ee2
--- /dev/null
+++ b/crypto/src/crypto/tls/Chacha20Poly1305.cs
@@ -0,0 +1,153 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class Chacha20Poly1305
+        :   TlsCipher
+    {
+        protected readonly TlsContext context;
+
+        protected readonly ChaChaEngine encryptCipher;
+        protected readonly ChaChaEngine decryptCipher;
+
+        /// <exception cref="IOException"></exception>
+        public Chacha20Poly1305(TlsContext context)
+        {
+            if (!TlsUtilities.IsTlsV12(context))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            this.context = context;
+
+            byte[] key_block = TlsUtilities.CalculateKeyBlock(context, 64);
+
+            KeyParameter client_write_key = new KeyParameter(key_block, 0, 32);
+            KeyParameter server_write_key = new KeyParameter(key_block, 32, 32);
+
+            this.encryptCipher = new ChaChaEngine(20);
+            this.decryptCipher = new ChaChaEngine(20);
+
+            KeyParameter encryptKey, decryptKey;
+            if (context.IsServer)
+            {
+                encryptKey = server_write_key;
+                decryptKey = client_write_key;
+            }
+            else
+            {
+                encryptKey = client_write_key;
+                decryptKey = server_write_key;
+            }
+
+            byte[] dummyNonce = new byte[8];
+
+            this.encryptCipher.Init(true, new ParametersWithIV(encryptKey, dummyNonce));
+            this.decryptCipher.Init(false, new ParametersWithIV(decryptKey, dummyNonce));
+        }
+
+        public virtual int GetPlaintextLimit(int ciphertextLimit)
+        {
+            return ciphertextLimit - 16;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+        {
+            int ciphertextLength = len + 16;
+
+            KeyParameter macKey = InitRecordMac(encryptCipher, true, seqNo);
+
+            byte[] output = new byte[ciphertextLength];
+            encryptCipher.ProcessBytes(plaintext, offset, len, output, 0);
+
+            byte[] additionalData = GetAdditionalData(seqNo, type, len);
+            byte[] mac = CalculateRecordMac(macKey, additionalData, output, 0, len);
+            Array.Copy(mac, 0, output, len, mac.Length);
+
+            return output;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+        {
+            if (GetPlaintextLimit(len) < 0)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int plaintextLength = len - 16;
+
+            byte[] receivedMAC = Arrays.CopyOfRange(ciphertext, offset + plaintextLength, offset + len);
+
+            KeyParameter macKey = InitRecordMac(decryptCipher, false, seqNo);
+
+            byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+            byte[] calculatedMAC = CalculateRecordMac(macKey, additionalData, ciphertext, offset, plaintextLength);
+
+            if (!Arrays.ConstantTimeAreEqual(calculatedMAC, receivedMAC))
+                throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+
+            byte[] output = new byte[plaintextLength];
+            decryptCipher.ProcessBytes(ciphertext, offset, plaintextLength, output, 0);
+
+            return output;
+        }
+
+        protected virtual KeyParameter InitRecordMac(ChaChaEngine cipher, bool forEncryption, long seqNo)
+        {
+            byte[] nonce = new byte[8];
+            TlsUtilities.WriteUint64(seqNo, nonce, 0);
+
+            cipher.Init(forEncryption, new ParametersWithIV(null, nonce));
+
+            byte[] firstBlock = new byte[64];
+            cipher.ProcessBytes(firstBlock, 0, firstBlock.Length, firstBlock, 0);
+
+            // NOTE: The BC implementation puts 'r' after 'k'
+            Array.Copy(firstBlock, 0, firstBlock, 32, 16);
+            KeyParameter macKey = new KeyParameter(firstBlock, 16, 32);
+            Poly1305KeyGenerator.Clamp(macKey.GetKey());
+            return macKey;
+        }
+
+        protected virtual byte[] CalculateRecordMac(KeyParameter macKey, byte[] additionalData, byte[] buf, int off, int len)
+        {
+            IMac mac = new Poly1305();
+            mac.Init(macKey);
+
+            UpdateRecordMac(mac, additionalData, 0, additionalData.Length);
+            UpdateRecordMac(mac, buf, off, len);
+            return MacUtilities.DoFinal(mac);
+        }
+
+        protected virtual void UpdateRecordMac(IMac mac, byte[] buf, int off, int len)
+        {
+            mac.BlockUpdate(buf, off, len);
+
+            byte[] longLen = Pack.UInt64_To_LE((ulong)len);
+            mac.BlockUpdate(longLen, 0, longLen.Length);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual byte[] GetAdditionalData(long seqNo, byte type, int len)
+        {
+            /*
+             * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version +
+             * TLSCompressed.length
+             */
+            byte[] additional_data = new byte[13];
+            TlsUtilities.WriteUint64(seqNo, additional_data, 0);
+            TlsUtilities.WriteUint8(type, additional_data, 8);
+            TlsUtilities.WriteVersion(context.ServerVersion, additional_data, 9);
+            TlsUtilities.WriteUint16(len, additional_data, 11);
+
+            return additional_data;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ChangeCipherSpec.cs b/crypto/src/crypto/tls/ChangeCipherSpec.cs
new file mode 100644
index 000000000..323de9162
--- /dev/null
+++ b/crypto/src/crypto/tls/ChangeCipherSpec.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class ChangeCipherSpec
+    {
+        public const byte change_cipher_spec = 1;
+    }
+}
diff --git a/crypto/src/crypto/tls/CipherSuite.cs b/crypto/src/crypto/tls/CipherSuite.cs
index 6e1f7a545..f034ab802 100644
--- a/crypto/src/crypto/tls/CipherSuite.cs
+++ b/crypto/src/crypto/tls/CipherSuite.cs
@@ -1,136 +1,352 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 A.5
-	/// </summary>
-	public enum CipherSuite : int
-	{
-		TLS_NULL_WITH_NULL_NULL = 0x0000,
-		TLS_RSA_WITH_NULL_MD5 = 0x0001,
-		TLS_RSA_WITH_NULL_SHA = 0x0002,
-		TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003,
-		TLS_RSA_WITH_RC4_128_MD5 = 0x0004,
-		TLS_RSA_WITH_RC4_128_SHA = 0x0005,
-		TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006,
-		TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007,
-		TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008,
-		TLS_RSA_WITH_DES_CBC_SHA = 0x0009,
-		TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A,
-		TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B,
-		TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C,
-		TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D,
-		TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E,
-		TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F,
-		TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010,
-		TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011,
-		TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012,
-		TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013,
-		TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014,
-		TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015,
-		TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016,
-		TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017,
-		TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018,
-		TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019,
-		TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A,
-		TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B,
-
-		/*
-		 * RFC 3268
-		 */
-		TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F,
-		TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030,
-		TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031,
-		TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032,
-		TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
-		TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034,
-		TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035,
-		TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036,
-		TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037,
-		TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038,
-		TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039,
-		TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A,
-
-		/*
-		 * RFC 4279
-		 */
-		TLS_PSK_WITH_RC4_128_SHA = 0x008A,
-		TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B,
-		TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
-		TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D,
-		TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E,
-		TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F,
-		TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090,
-		TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091,
-		TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092,
-		TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093,
-		TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094,
-		TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095,
-
-		/*
-		 * RFC 4492
-		 */
-		TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001,
-		TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002,
-		TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003,
-		TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004,
-		TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005,
-		TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006,
-		TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007,
-		TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008,
-		TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009,
-		TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A,
-		TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B,
-		TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C,
-		TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D,
-		TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E,
-		TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F,
-		TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010,
-		TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011,
-		TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012,
-		TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013,
-		TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014,
-		TLS_ECDH_anon_WITH_NULL_SHA = 0xC015,
-		TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016,
-		TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017,
-		TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018,
-		TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019,
-
-		/*
-		 * RFC 5054
-		 */
-		TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A,
-		TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B,
-		TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C,
-		TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D,
-		TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E,
-		TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F,
-		TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020,
-		TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021,
-		TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022,
-
-		/*
-		 * RFC 5289
-		 */
-		TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023,
-		TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024,
-		TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025,
-		TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026,
-		TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
-		TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028,
-		TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029,
-		TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A,
-		TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B,
-		TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C,
-		TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D,
-		TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E,
-		TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F,
-		TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030,
-		TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031,
-		TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032,
-
-		/*
-		 * RFC 5746
-		 */
-		TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF,
-	}
+    /// <summary>
+    /// RFC 2246 A.5
+    /// </summary>
+    public abstract class CipherSuite
+    {
+        public const int TLS_NULL_WITH_NULL_NULL = 0x0000;
+        public const int TLS_RSA_WITH_NULL_MD5 = 0x0001;
+        public const int TLS_RSA_WITH_NULL_SHA = 0x0002;
+        public const int TLS_RSA_EXPORT_WITH_RC4_40_MD5 = 0x0003;
+        public const int TLS_RSA_WITH_RC4_128_MD5 = 0x0004;
+        public const int TLS_RSA_WITH_RC4_128_SHA = 0x0005;
+        public const int TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = 0x0006;
+        public const int TLS_RSA_WITH_IDEA_CBC_SHA = 0x0007;
+        public const int TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0008;
+        public const int TLS_RSA_WITH_DES_CBC_SHA = 0x0009;
+        public const int TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A;
+        public const int TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x000B;
+        public const int TLS_DH_DSS_WITH_DES_CBC_SHA = 0x000C;
+        public const int TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D;
+        public const int TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x000E;
+        public const int TLS_DH_RSA_WITH_DES_CBC_SHA = 0x000F;
+        public const int TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010;
+        public const int TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = 0x0011;
+        public const int TLS_DHE_DSS_WITH_DES_CBC_SHA = 0x0012;
+        public const int TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013;
+        public const int TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = 0x0014;
+        public const int TLS_DHE_RSA_WITH_DES_CBC_SHA = 0x0015;
+        public const int TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016;
+        public const int TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 = 0x0017;
+        public const int TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018;
+        public const int TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA = 0x0019;
+        public const int TLS_DH_anon_WITH_DES_CBC_SHA = 0x001A;
+        public const int TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B;
+
+        /*
+         * Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are reserved to avoid
+         * collision with Fortezza-based cipher suites in SSL 3.
+         */
+
+        /*
+         * RFC 3268
+         */
+        public const int TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F;
+        public const int TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x0030;
+        public const int TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x0031;
+        public const int TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032;
+        public const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033;
+        public const int TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x0034;
+        public const int TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035;
+        public const int TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x0036;
+        public const int TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x0037;
+        public const int TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038;
+        public const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039;
+        public const int TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x003A;
+
+        /*
+         * RFC 5932
+         */
+        public const int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0041;
+        public const int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0042;
+        public const int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0043;
+        public const int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = 0x0044;
+        public const int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = 0x0045;
+        public const int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = 0x0046;
+
+        public const int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0084;
+        public const int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0085;
+        public const int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0086;
+        public const int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = 0x0087;
+        public const int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = 0x0088;
+        public const int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = 0x0089;
+
+        public const int TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BA;
+        public const int TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BB;
+        public const int TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BC;
+        public const int TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BD;
+        public const int TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BE;
+        public const int TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = 0x00BF;
+
+        public const int TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C0;
+        public const int TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C1;
+        public const int TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C2;
+        public const int TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C3;
+        public const int TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C4;
+        public const int TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = 0x00C5;
+
+        /*
+         * RFC 4162
+         */
+        public const int TLS_RSA_WITH_SEED_CBC_SHA = 0x0096;
+        public const int TLS_DH_DSS_WITH_SEED_CBC_SHA = 0x0097;
+        public const int TLS_DH_RSA_WITH_SEED_CBC_SHA = 0x0098;
+        public const int TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099;
+        public const int TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A;
+        public const int TLS_DH_anon_WITH_SEED_CBC_SHA = 0x009B;
+
+        /*
+         * RFC 4279
+         */
+        public const int TLS_PSK_WITH_RC4_128_SHA = 0x008A;
+        public const int TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B;
+        public const int TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C;
+        public const int TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D;
+        public const int TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E;
+        public const int TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F;
+        public const int TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090;
+        public const int TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091;
+        public const int TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092;
+        public const int TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093;
+        public const int TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094;
+        public const int TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095;
+
+        /*
+         * RFC 4492
+         */
+        public const int TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001;
+        public const int TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002;
+        public const int TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003;
+        public const int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004;
+        public const int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005;
+        public const int TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006;
+        public const int TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007;
+        public const int TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008;
+        public const int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009;
+        public const int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A;
+        public const int TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B;
+        public const int TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C;
+        public const int TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D;
+        public const int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E;
+        public const int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F;
+        public const int TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010;
+        public const int TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011;
+        public const int TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012;
+        public const int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013;
+        public const int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014;
+        public const int TLS_ECDH_anon_WITH_NULL_SHA = 0xC015;
+        public const int TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016;
+        public const int TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017;
+        public const int TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018;
+        public const int TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019;
+
+        /*
+         * RFC 4785
+         */
+        public const int TLS_PSK_WITH_NULL_SHA = 0x002C;
+        public const int TLS_DHE_PSK_WITH_NULL_SHA = 0x002D;
+        public const int TLS_RSA_PSK_WITH_NULL_SHA = 0x002E;
+
+        /*
+         * RFC 5054
+         */
+        public const int TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = 0xC01A;
+        public const int TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = 0xC01B;
+        public const int TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = 0xC01C;
+        public const int TLS_SRP_SHA_WITH_AES_128_CBC_SHA = 0xC01D;
+        public const int TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = 0xC01E;
+        public const int TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = 0xC01F;
+        public const int TLS_SRP_SHA_WITH_AES_256_CBC_SHA = 0xC020;
+        public const int TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = 0xC021;
+        public const int TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = 0xC022;
+
+        /*
+         * RFC 5246
+         */
+        public const int TLS_RSA_WITH_NULL_SHA256 = 0x003B;
+        public const int TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C;
+        public const int TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D;
+        public const int TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E;
+        public const int TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F;
+        public const int TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040;
+        public const int TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067;
+        public const int TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068;
+        public const int TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069;
+        public const int TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A;
+        public const int TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B;
+        public const int TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C;
+        public const int TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D;
+
+        /*
+         * RFC 5288
+         */
+        public const int TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C;
+        public const int TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D;
+        public const int TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E;
+        public const int TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F;
+        public const int TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0;
+        public const int TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1;
+        public const int TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2;
+        public const int TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3;
+        public const int TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4;
+        public const int TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5;
+        public const int TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6;
+        public const int TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7;
+
+        /*
+         * RFC 5289
+         */
+        public const int TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023;
+        public const int TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024;
+        public const int TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025;
+        public const int TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026;
+        public const int TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027;
+        public const int TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028;
+        public const int TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029;
+        public const int TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A;
+        public const int TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B;
+        public const int TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C;
+        public const int TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D;
+        public const int TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E;
+        public const int TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F;
+        public const int TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030;
+        public const int TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031;
+        public const int TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032;
+
+        /*
+         * RFC 5487
+         */
+        public const int TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8;
+        public const int TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9;
+        public const int TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA;
+        public const int TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB;
+        public const int TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00AC;
+        public const int TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00AD;
+        public const int TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE;
+        public const int TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF;
+        public const int TLS_PSK_WITH_NULL_SHA256 = 0x00B0;
+        public const int TLS_PSK_WITH_NULL_SHA384 = 0x00B1;
+        public const int TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2;
+        public const int TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3;
+        public const int TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4;
+        public const int TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5;
+        public const int TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6;
+        public const int TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7;
+        public const int TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8;
+        public const int TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9;
+
+        /*
+         * RFC 5489
+         */
+        public const int TLS_ECDHE_PSK_WITH_RC4_128_SHA = 0xC033;
+        public const int TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = 0xC034;
+        public const int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA = 0xC035;
+        public const int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA = 0xC036;
+        public const int TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037;
+        public const int TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = 0xC038;
+        public const int TLS_ECDHE_PSK_WITH_NULL_SHA = 0xC039;
+        public const int TLS_ECDHE_PSK_WITH_NULL_SHA256 = 0xC03A;
+        public const int TLS_ECDHE_PSK_WITH_NULL_SHA384 = 0xC03B;
+
+        /*
+         * RFC 5746
+         */
+        public const int TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF;
+
+        /*
+         * RFC 6367
+         */
+        public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC072;
+        public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC073;
+        public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC074;
+        public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC075;
+        public const int TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC076;
+        public const int TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC077;
+        public const int TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = 0xC078;
+        public const int TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = 0xC079;
+
+        public const int TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07A;
+        public const int TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07B;
+        public const int TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07C;
+        public const int TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07D;
+        public const int TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07E;
+        public const int TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07F;
+        public const int TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC080;
+        public const int TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC081;
+        public const int TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC082;
+        public const int TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC083;
+        public const int TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = 0xC084;
+        public const int TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = 0xC085;
+        public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC086;
+        public const int TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC087;
+        public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC088;
+        public const int TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC089;
+        public const int TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08A;
+        public const int TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08B;
+        public const int TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08C;
+        public const int TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08D;
+
+        public const int TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08E;
+        public const int TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08F;
+        public const int TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC090;
+        public const int TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC091;
+        public const int TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC092;
+        public const int TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC093;
+        public const int TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC094;
+        public const int TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC095;
+        public const int TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC096;
+        public const int TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC097;
+        public const int TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC098;
+        public const int TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC099;
+        public const int TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = 0xC09A;
+        public const int TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = 0xC09B;
+
+        /*
+         * RFC 6655
+         */
+        public const int TLS_RSA_WITH_AES_128_CCM = 0xC09C;
+        public const int TLS_RSA_WITH_AES_256_CCM = 0xC09D;
+        public const int TLS_DHE_RSA_WITH_AES_128_CCM = 0xC09E;
+        public const int TLS_DHE_RSA_WITH_AES_256_CCM = 0xC09F;
+        public const int TLS_RSA_WITH_AES_128_CCM_8 = 0xC0A0;
+        public const int TLS_RSA_WITH_AES_256_CCM_8 = 0xC0A1;
+        public const int TLS_DHE_RSA_WITH_AES_128_CCM_8 = 0xC0A2;
+        public const int TLS_DHE_RSA_WITH_AES_256_CCM_8 = 0xC0A3;
+        public const int TLS_PSK_WITH_AES_128_CCM = 0xC0A4;
+        public const int TLS_PSK_WITH_AES_256_CCM = 0xC0A5;
+        public const int TLS_DHE_PSK_WITH_AES_128_CCM = 0xC0A6;
+        public const int TLS_DHE_PSK_WITH_AES_256_CCM = 0xC0A7;
+        public const int TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8;
+        public const int TLS_PSK_WITH_AES_256_CCM_8 = 0xC0A9;
+        public const int TLS_PSK_DHE_WITH_AES_128_CCM_8 = 0xC0AA;
+        public const int TLS_PSK_DHE_WITH_AES_256_CCM_8 = 0xC0AB;
+
+        /*
+         * draft-agl-tls-chacha20poly1305-04
+         */
+        public const int TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC13;
+        public const int TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC14;
+        public const int TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCC15;
+
+        /*
+         * draft-josefsson-salsa20-tls-04
+         */
+        public const int TLS_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE410;
+        public const int TLS_RSA_WITH_SALSA20_SHA1 = 0xE411;
+        public const int TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE412;
+        public const int TLS_ECDHE_RSA_WITH_SALSA20_SHA1 = 0xE413;
+        public const int TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE414;
+        public const int TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1 = 0xE415;
+        public const int TLS_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE416;
+        public const int TLS_PSK_WITH_SALSA20_SHA1 = 0xE417;
+        public const int TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE418;
+        public const int TLS_ECDHE_PSK_WITH_SALSA20_SHA1 = 0xE419;
+        public const int TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE41A;
+        public const int TLS_RSA_PSK_WITH_SALSA20_SHA1 = 0xE41B;
+        public const int TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1 = 0xE41C;
+        public const int TLS_DHE_PSK_WITH_SALSA20_SHA1 = 0xE41D;
+        public const int TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1 = 0xE41E;
+        public const int TLS_DHE_RSA_WITH_SALSA20_SHA1 = 0xE41F;
+    }
 }
diff --git a/crypto/src/crypto/tls/CipherType.cs b/crypto/src/crypto/tls/CipherType.cs
new file mode 100644
index 000000000..b2ad7d8e1
--- /dev/null
+++ b/crypto/src/crypto/tls/CipherType.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 2246</summary>
+    /// <remarks>
+    /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+    /// depend on the particular values (e.g. serialization).
+    /// </remarks>
+    public abstract class CipherType
+    {
+        public const int stream = 0;
+        public const int block = 1;
+
+        /*
+         * RFC 5246
+         */
+        public const int aead = 2;
+    }
+}
diff --git a/crypto/src/crypto/tls/ClientAuthenticationType.cs b/crypto/src/crypto/tls/ClientAuthenticationType.cs
new file mode 100644
index 000000000..dd248f3df
--- /dev/null
+++ b/crypto/src/crypto/tls/ClientAuthenticationType.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class ClientAuthenticationType
+    {
+        /*
+         * RFC 5077 4
+         */
+        public const byte anonymous = 0;
+        public const byte certificate_based = 1;
+        public const byte psk = 2;
+    }
+}
diff --git a/crypto/src/crypto/tls/ClientCertificateType.cs b/crypto/src/crypto/tls/ClientCertificateType.cs
index 58f5d4276..a291a46e6 100644
--- a/crypto/src/crypto/tls/ClientCertificateType.cs
+++ b/crypto/src/crypto/tls/ClientCertificateType.cs
@@ -1,20 +1,23 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 7.4.4
-	/// </summary>
-    public enum ClientCertificateType : byte
-	{
-		rsa_sign = 1,
-		dss_sign = 2,
-		rsa_fixed_dh = 3,
-		dss_fixed_dh = 4,
+    public abstract class ClientCertificateType
+    {
+        /*
+         *  RFC 4346 7.4.4
+         */
+        public const byte rsa_sign = 1;
+        public const byte dss_sign = 2;
+        public const byte rsa_fixed_dh = 3;
+        public const byte dss_fixed_dh = 4;
+        public const byte rsa_ephemeral_dh_RESERVED = 5;
+        public const byte dss_ephemeral_dh_RESERVED = 6;
+        public const byte fortezza_dms_RESERVED = 20;
 
-		/*
-		 * RFC 4492 5.5
-		 */
-		ecdsa_sign = 64,
-		rsa_fixed_ecdh = 65,
-		ecdsa_fixed_ecdh = 66,
-	}
-}
\ No newline at end of file
+        /*
+        * RFC 4492 5.5
+        */
+        public const byte ecdsa_sign = 64;
+        public const byte rsa_fixed_ecdh = 65;
+        public const byte ecdsa_fixed_ecdh = 66;
+    }
+}
diff --git a/crypto/src/crypto/tls/CombinedHash.cs b/crypto/src/crypto/tls/CombinedHash.cs
index 59ad87a7b..74a52d598 100644
--- a/crypto/src/crypto/tls/CombinedHash.cs
+++ b/crypto/src/crypto/tls/CombinedHash.cs
@@ -1,82 +1,133 @@
 using System;
 
-using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <remarks>A combined hash, which implements md5(m) || sha1(m).</remarks>
-	internal class CombinedHash
-		: IDigest
-	{
-		private readonly MD5Digest md5;
-		private readonly Sha1Digest sha1;
-
-		internal CombinedHash()
-		{
-			this.md5 = new MD5Digest();
-			this.sha1 = new Sha1Digest();
-		}
-
-		internal CombinedHash(CombinedHash t)
-		{
-			this.md5 = new MD5Digest(t.md5);
-			this.sha1 = new Sha1Digest(t.sha1);
-		}
-
-		/// <seealso cref="IDigest.AlgorithmName"/>
-		public string AlgorithmName
-		{
-			get
-			{
-				return md5.AlgorithmName + " and " + sha1.AlgorithmName + " for TLS 1.0";
-			}
-		}
-
-		/// <seealso cref="IDigest.GetByteLength"/>
-		public int GetByteLength()
-		{
-			return System.Math.Max(md5.GetByteLength(), sha1.GetByteLength());
-		}
-
-		/// <seealso cref="IDigest.GetDigestSize"/>
-		public int GetDigestSize()
-		{
-			return md5.GetDigestSize() + sha1.GetDigestSize();
-		}
-
-		/// <seealso cref="IDigest.Update"/>
-		public void Update(
-			byte input)
-		{
-			md5.Update(input);
-			sha1.Update(input);
-		}
-
-		/// <seealso cref="IDigest.BlockUpdate"/>
-		public void BlockUpdate(
-			byte[]	input,
-			int		inOff,
-			int		len)
-		{
-			md5.BlockUpdate(input, inOff, len);
-			sha1.BlockUpdate(input, inOff, len);
-		}
-
-		/// <seealso cref="IDigest.DoFinal"/>
-		public int DoFinal(
-			byte[]	output,
-			int		outOff)
-		{
-			int i1 = md5.DoFinal(output, outOff);
-			int i2 = sha1.DoFinal(output, outOff + i1);
-			return i1 + i2;
-		}
-
-		/// <seealso cref="IDigest.Reset"/>
-		public void Reset()
-		{
-			md5.Reset();
-			sha1.Reset();
-		}
-	}
+    /**
+     * A combined hash, which implements md5(m) || sha1(m).
+     */
+    internal class CombinedHash
+        :   TlsHandshakeHash
+    {
+        protected TlsContext mContext;
+        protected IDigest mMd5;
+        protected IDigest mSha1;
+
+        internal CombinedHash()
+        {
+            this.mMd5 = TlsUtilities.CreateHash(HashAlgorithm.md5);
+            this.mSha1 = TlsUtilities.CreateHash(HashAlgorithm.sha1);
+        }
+
+        internal CombinedHash(CombinedHash t)
+        {
+            this.mContext = t.mContext;
+            this.mMd5 = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5);
+            this.mSha1 = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1);
+        }
+
+        public virtual void Init(TlsContext context)
+        {
+            this.mContext = context;
+        }
+
+        public virtual TlsHandshakeHash NotifyPrfDetermined()
+        {
+            return this;
+        }
+
+        public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+        {
+            throw new InvalidOperationException("CombinedHash only supports calculating the legacy PRF for handshake hash");
+        }
+
+        public virtual void SealHashAlgorithms()
+        {
+        }
+
+        public virtual TlsHandshakeHash StopTracking()
+        {
+            return new CombinedHash(this);
+        }
+
+        public virtual IDigest ForkPrfHash()
+        {
+            return new CombinedHash(this);
+        }
+
+        public virtual byte[] GetFinalHash(byte hashAlgorithm)
+        {
+            throw new InvalidOperationException("CombinedHash doesn't support multiple hashes");
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return mMd5.AlgorithmName + " and " + mSha1.AlgorithmName; }
+        }
+
+        public virtual int GetByteLength()
+        {
+            return System.Math.Max(mMd5.GetByteLength(), mSha1.GetByteLength());
+        }
+
+        public virtual int GetDigestSize()
+        {
+            return mMd5.GetDigestSize() + mSha1.GetDigestSize();
+        }
+
+        public virtual void Update(byte input)
+        {
+            mMd5.Update(input);
+            mSha1.Update(input);
+        }
+
+        /**
+         * @see org.bouncycastle.crypto.Digest#update(byte[], int, int)
+         */
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            mMd5.BlockUpdate(input, inOff, len);
+            mSha1.BlockUpdate(input, inOff, len);
+        }
+
+        /**
+         * @see org.bouncycastle.crypto.Digest#doFinal(byte[], int)
+         */
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            if (mContext != null && TlsUtilities.IsSsl(mContext))
+            {
+                Ssl3Complete(mMd5, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 48);
+                Ssl3Complete(mSha1, Ssl3Mac.IPAD, Ssl3Mac.OPAD, 40);
+            }
+
+            int i1 = mMd5.DoFinal(output, outOff);
+            int i2 = mSha1.DoFinal(output, outOff + i1);
+            return i1 + i2;
+        }
+
+        /**
+         * @see org.bouncycastle.crypto.Digest#reset()
+         */
+        public virtual void Reset()
+        {
+            mMd5.Reset();
+            mSha1.Reset();
+        }
+
+        protected virtual void Ssl3Complete(IDigest d, byte[] ipad, byte[] opad, int padLength)
+        {
+            byte[] master_secret = mContext.SecurityParameters.masterSecret;
+
+            d.BlockUpdate(master_secret, 0, master_secret.Length);
+            d.BlockUpdate(ipad, 0, padLength);
+
+            byte[] tmp = DigestUtilities.DoFinal(d);
+
+            d.BlockUpdate(master_secret, 0, master_secret.Length);
+            d.BlockUpdate(opad, 0, padLength);
+            d.BlockUpdate(tmp, 0, tmp.Length);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/CompressionMethod.cs b/crypto/src/crypto/tls/CompressionMethod.cs
index 4a127a63e..89c1f5ff4 100644
--- a/crypto/src/crypto/tls/CompressionMethod.cs
+++ b/crypto/src/crypto/tls/CompressionMethod.cs
@@ -1,20 +1,22 @@
+using System;
+
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 6.1
-	/// </summary>
-    public enum CompressionMethod : byte
-	{
-		NULL = 0,
+    /// <summary>
+    /// RFC 2246 6.1
+    /// </summary>
+    public abstract class CompressionMethod
+    {
+        public const byte cls_null = 0;
 
-		/*
-		 * RFC 3749 2
-		 */
-		DEFLATE = 1
+        /*
+         * RFC 3749 2
+         */
+        public const byte DEFLATE = 1;
 
-		/*
-		 * Values from 224 decimal (0xE0) through 255 decimal (0xFF)
-		 * inclusive are reserved for private use.
-		 */
-	}
+        /*
+         * Values from 224 decimal (0xE0) through 255 decimal (0xFF)
+         * inclusive are reserved for private use.
+         */
+    }
 }
diff --git a/crypto/src/crypto/tls/ConnectionEnd.cs b/crypto/src/crypto/tls/ConnectionEnd.cs
new file mode 100644
index 000000000..afc9460f2
--- /dev/null
+++ b/crypto/src/crypto/tls/ConnectionEnd.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 2246</summary>
+    /// <remarks>
+    /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+    /// depend on the particular values (e.g. serialization).
+    /// </remarks>
+    public abstract class ConnectionEnd
+    {
+        public const int server = 0;
+        public const int client = 1;
+    }
+}
diff --git a/crypto/src/crypto/tls/ContentType.cs b/crypto/src/crypto/tls/ContentType.cs
index a664e3a38..d6ab43857 100644
--- a/crypto/src/crypto/tls/ContentType.cs
+++ b/crypto/src/crypto/tls/ContentType.cs
@@ -1,13 +1,14 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 6.2.1
-	/// </summary>
-    public enum ContentType : byte
-	{
-		change_cipher_spec = 20,
-		alert = 21,
-		handshake = 22,
-		application_data = 23,
-	}
+    /**
+     * RFC 2246 6.2.1
+     */
+    public abstract class ContentType
+    {
+        public const byte change_cipher_spec = 20;
+        public const byte alert = 21;
+        public const byte handshake = 22;
+        public const byte application_data = 23;
+        public const byte heartbeat = 24;
+    }
 }
diff --git a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
index 2dfe526d1..5147a1990 100644
--- a/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
@@ -1,4 +1,5 @@
 using System;
+using System.IO;
 
 using Org.BouncyCastle.Crypto.Agreement;
 using Org.BouncyCastle.Crypto.Parameters;
@@ -7,61 +8,62 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class DefaultTlsAgreementCredentials
-		: TlsAgreementCredentials
-	{
-		protected Certificate clientCert;
-		protected AsymmetricKeyParameter clientPrivateKey;
+    public class DefaultTlsAgreementCredentials
+        : AbstractTlsAgreementCredentials
+    {
+        protected readonly Certificate mCertificate;
+        protected readonly AsymmetricKeyParameter mPrivateKey;
 
-		protected IBasicAgreement basicAgreement;
+        protected readonly IBasicAgreement mBasicAgreement;
+        protected readonly bool mTruncateAgreement;
 
-		public DefaultTlsAgreementCredentials(Certificate clientCertificate, AsymmetricKeyParameter clientPrivateKey)
-		{
-			if (clientCertificate == null)
-			{
-				throw new ArgumentNullException("clientCertificate");
-			}
-			if (clientCertificate.certs.Length == 0)
-			{
-				throw new ArgumentException("cannot be empty", "clientCertificate");
-			}
-			if (clientPrivateKey == null)
-			{
-				throw new ArgumentNullException("clientPrivateKey");
-			}
-			if (!clientPrivateKey.IsPrivate)
-			{
-				throw new ArgumentException("must be private", "clientPrivateKey");
-			}
+        public DefaultTlsAgreementCredentials(Certificate certificate, AsymmetricKeyParameter privateKey)
+        {
+            if (certificate == null)
+                throw new ArgumentNullException("certificate");
+            if (certificate.IsEmpty)
+                throw new ArgumentException("cannot be empty", "certificate");
+            if (privateKey == null)
+                throw new ArgumentNullException("privateKey");
+            if (!privateKey.IsPrivate)
+                throw new ArgumentException("must be private", "privateKey");
 
-			if (clientPrivateKey is DHPrivateKeyParameters)
-			{
-				basicAgreement = new DHBasicAgreement();
-			}
-			else if (clientPrivateKey is ECPrivateKeyParameters)
-			{
-				basicAgreement = new ECDHBasicAgreement();
-			}
-			else
-			{
-				throw new ArgumentException("type not supported: "
-					+ clientPrivateKey.GetType().FullName, "clientPrivateKey");
-			}
+            if (privateKey is DHPrivateKeyParameters)
+            {
+                mBasicAgreement = new DHBasicAgreement();
+                mTruncateAgreement = true;
+            }
+            else if (privateKey is ECPrivateKeyParameters)
+            {
+                mBasicAgreement = new ECDHBasicAgreement();
+                mTruncateAgreement = false;
+            }
+            else
+            {
+                throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
+            }
 
-			this.clientCert = clientCertificate;
-			this.clientPrivateKey = clientPrivateKey;
-		}
+            this.mCertificate = certificate;
+            this.mPrivateKey = privateKey;
+        }
 
-		public virtual Certificate Certificate
-		{
-			get { return clientCert; }
-		}
+        public override Certificate Certificate
+        {
+            get { return mCertificate; }
+        }
 
-		public virtual byte[] GenerateAgreement(AsymmetricKeyParameter serverPublicKey)
-		{
-			basicAgreement.Init(clientPrivateKey);
-			BigInteger agreementValue = basicAgreement.CalculateAgreement(serverPublicKey);
-			return BigIntegers.AsUnsignedByteArray(agreementValue);
-		}
-	}
+        /// <exception cref="IOException"></exception>
+        public override byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey)
+        {
+            mBasicAgreement.Init(mPrivateKey);
+            BigInteger agreementValue = mBasicAgreement.CalculateAgreement(peerPublicKey);
+
+            if (mTruncateAgreement)
+            {
+                return BigIntegers.AsUnsignedByteArray(agreementValue);
+            }
+
+            return BigIntegers.AsUnsignedByteArray(mBasicAgreement.GetFieldSize(), agreementValue);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
index 53e3438d9..7c4213c25 100644
--- a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
+++ b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
@@ -1,73 +1,225 @@
 using System;
 using System.IO;
 
-using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Modes;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class DefaultTlsCipherFactory
-		: TlsCipherFactory
-	{
-		public virtual TlsCipher CreateCipher(TlsClientContext context,
-			EncryptionAlgorithm encryptionAlgorithm, DigestAlgorithm digestAlgorithm)
-		{
-			switch (encryptionAlgorithm)
-			{
-				case EncryptionAlgorithm.cls_3DES_EDE_CBC:
-					return CreateDesEdeCipher(context, 24, digestAlgorithm);
-				case EncryptionAlgorithm.AES_128_CBC:
-					return CreateAesCipher(context, 16, digestAlgorithm);
-				case EncryptionAlgorithm.AES_256_CBC:
-					return CreateAesCipher(context, 32, digestAlgorithm);
-				default:
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		/// <exception cref="IOException"></exception>
-		protected virtual TlsCipher CreateAesCipher(TlsClientContext context, int cipherKeySize,
-			DigestAlgorithm digestAlgorithm)
-		{
-			return new TlsBlockCipher(context, CreateAesBlockCipher(), CreateAesBlockCipher(),
-				CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize);
-		}
-
-		/// <exception cref="IOException"></exception>
-		protected virtual TlsCipher CreateDesEdeCipher(TlsClientContext context, int cipherKeySize,
-			DigestAlgorithm digestAlgorithm)
-		{
-			return new TlsBlockCipher(context, CreateDesEdeBlockCipher(), CreateDesEdeBlockCipher(),
-				CreateDigest(digestAlgorithm), CreateDigest(digestAlgorithm), cipherKeySize);
-		}
-
-		protected virtual IBlockCipher CreateAesBlockCipher()
-		{
-			return new CbcBlockCipher(new AesFastEngine());
-		}
-
-		protected virtual IBlockCipher CreateDesEdeBlockCipher()
-		{
-			return new CbcBlockCipher(new DesEdeEngine());
-		}
-
-		/// <exception cref="IOException"></exception>
-		protected virtual IDigest CreateDigest(DigestAlgorithm digestAlgorithm)
-		{
-			switch (digestAlgorithm)
-			{
-				case DigestAlgorithm.MD5:
-					return new MD5Digest();
-				case DigestAlgorithm.SHA:
-					return new Sha1Digest();
-				case DigestAlgorithm.SHA256:
-					return new Sha256Digest();
-				case DigestAlgorithm.SHA384:
-					return new Sha384Digest();
-				default:
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-	}
+    public class DefaultTlsCipherFactory
+        :   AbstractTlsCipherFactory
+    {
+        /// <exception cref="IOException"></exception>
+        public override TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm)
+        {
+            switch (encryptionAlgorithm)
+            {
+            case EncryptionAlgorithm.cls_3DES_EDE_CBC:
+                return CreateDesEdeCipher(context, macAlgorithm);
+            case EncryptionAlgorithm.AEAD_CHACHA20_POLY1305:
+                // NOTE: Ignores macAlgorithm
+                return CreateChaCha20Poly1305(context);
+            case EncryptionAlgorithm.AES_128_CBC:
+                return CreateAESCipher(context, 16, macAlgorithm);
+            case EncryptionAlgorithm.AES_128_CCM:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Aes_Ccm(context, 16, 16);
+            case EncryptionAlgorithm.AES_128_CCM_8:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Aes_Ccm(context, 16, 8);
+            case EncryptionAlgorithm.AES_256_CCM:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Aes_Ccm(context, 32, 16);
+            case EncryptionAlgorithm.AES_256_CCM_8:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Aes_Ccm(context, 32, 8);
+            case EncryptionAlgorithm.AES_128_GCM:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Aes_Gcm(context, 16, 16);
+            case EncryptionAlgorithm.AES_256_CBC:
+                return CreateAESCipher(context, 32, macAlgorithm);
+            case EncryptionAlgorithm.AES_256_GCM:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Aes_Gcm(context, 32, 16);
+            case EncryptionAlgorithm.CAMELLIA_128_CBC:
+                return CreateCamelliaCipher(context, 16, macAlgorithm);
+            case EncryptionAlgorithm.CAMELLIA_128_GCM:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Camellia_Gcm(context, 16, 16);
+            case EncryptionAlgorithm.CAMELLIA_256_CBC:
+                return CreateCamelliaCipher(context, 32, macAlgorithm);
+            case EncryptionAlgorithm.CAMELLIA_256_GCM:
+                // NOTE: Ignores macAlgorithm
+                return CreateCipher_Camellia_Gcm(context, 32, 16);
+            case EncryptionAlgorithm.ESTREAM_SALSA20:
+                return CreateSalsa20Cipher(context, 12, 32, macAlgorithm);
+            case EncryptionAlgorithm.NULL:
+                return CreateNullCipher(context, macAlgorithm);
+            case EncryptionAlgorithm.RC4_128:
+                return CreateRC4Cipher(context, 16, macAlgorithm);
+            case EncryptionAlgorithm.SALSA20:
+                return CreateSalsa20Cipher(context, 20, 32, macAlgorithm);
+            case EncryptionAlgorithm.SEED_CBC:
+                return CreateSeedCipher(context, macAlgorithm);
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsBlockCipher CreateAESCipher(TlsContext context, int cipherKeySize, int macAlgorithm)
+        {
+            return new TlsBlockCipher(context, CreateAesBlockCipher(), CreateAesBlockCipher(),
+                CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsBlockCipher CreateCamelliaCipher(TlsContext context, int cipherKeySize, int macAlgorithm)
+        {
+            return new TlsBlockCipher(context, CreateCamelliaBlockCipher(),
+                CreateCamelliaBlockCipher(), CreateHMacDigest(macAlgorithm),
+                CreateHMacDigest(macAlgorithm), cipherKeySize);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsCipher CreateChaCha20Poly1305(TlsContext context)
+        {
+            return new Chacha20Poly1305(context);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsAeadCipher CreateCipher_Aes_Ccm(TlsContext context, int cipherKeySize, int macSize)
+        {
+            return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Ccm(),
+                CreateAeadBlockCipher_Aes_Ccm(), cipherKeySize, macSize);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsAeadCipher CreateCipher_Aes_Gcm(TlsContext context, int cipherKeySize, int macSize)
+        {
+            return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Gcm(),
+                CreateAeadBlockCipher_Aes_Gcm(), cipherKeySize, macSize);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsAeadCipher CreateCipher_Camellia_Gcm(TlsContext context, int cipherKeySize, int macSize)
+        {
+            return new TlsAeadCipher(context, CreateAeadBlockCipher_Camellia_Gcm(),
+                CreateAeadBlockCipher_Camellia_Gcm(), cipherKeySize, macSize);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsBlockCipher CreateDesEdeCipher(TlsContext context, int macAlgorithm)
+        {
+            return new TlsBlockCipher(context, CreateDesEdeBlockCipher(), CreateDesEdeBlockCipher(),
+                CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), 24);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsNullCipher CreateNullCipher(TlsContext context, int macAlgorithm)
+        {
+            return new TlsNullCipher(context, CreateHMacDigest(macAlgorithm),
+                CreateHMacDigest(macAlgorithm));
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsStreamCipher CreateRC4Cipher(TlsContext context, int cipherKeySize, int macAlgorithm)
+        {
+            return new TlsStreamCipher(context, CreateRC4StreamCipher(), CreateRC4StreamCipher(),
+                CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize, false);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsStreamCipher CreateSalsa20Cipher(TlsContext context, int rounds, int cipherKeySize, int macAlgorithm)
+        {
+            return new TlsStreamCipher(context, CreateSalsa20StreamCipher(rounds), CreateSalsa20StreamCipher(rounds),
+                CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), cipherKeySize, true);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual TlsBlockCipher CreateSeedCipher(TlsContext context, int macAlgorithm)
+        {
+            return new TlsBlockCipher(context, CreateSeedBlockCipher(), CreateSeedBlockCipher(),
+                CreateHMacDigest(macAlgorithm), CreateHMacDigest(macAlgorithm), 16);
+        }
+
+        protected virtual IBlockCipher CreateAesEngine()
+        {
+            return new AesEngine();
+        }
+
+        protected virtual IBlockCipher CreateCamelliaEngine()
+        {
+            return new CamelliaEngine();
+        }
+
+        protected virtual IBlockCipher CreateAesBlockCipher()
+        {
+            return new CbcBlockCipher(CreateAesEngine());
+        }
+
+        protected virtual IAeadBlockCipher CreateAeadBlockCipher_Aes_Ccm()
+        {
+            return new CcmBlockCipher(CreateAesEngine());
+        }
+
+        protected virtual IAeadBlockCipher CreateAeadBlockCipher_Aes_Gcm()
+        {
+            // TODO Consider allowing custom configuration of multiplier
+            return new GcmBlockCipher(CreateAesEngine());
+        }
+
+        protected virtual IAeadBlockCipher CreateAeadBlockCipher_Camellia_Gcm()
+        {
+            // TODO Consider allowing custom configuration of multiplier
+            return new GcmBlockCipher(CreateCamelliaEngine());
+        }
+
+        protected virtual IBlockCipher CreateCamelliaBlockCipher()
+        {
+            return new CbcBlockCipher(CreateCamelliaEngine());
+        }
+
+        protected virtual IBlockCipher CreateDesEdeBlockCipher()
+        {
+            return new CbcBlockCipher(new DesEdeEngine());
+        }
+
+        protected virtual IStreamCipher CreateRC4StreamCipher()
+        {
+            return new RC4Engine();
+        }
+
+        protected virtual IStreamCipher CreateSalsa20StreamCipher(int rounds)
+        {
+            return new Salsa20Engine(rounds);
+        }
+
+        protected virtual IBlockCipher CreateSeedBlockCipher()
+        {
+            return new CbcBlockCipher(new SeedEngine());
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual IDigest CreateHMacDigest(int macAlgorithm)
+        {
+            switch (macAlgorithm)
+            {
+            case MacAlgorithm.cls_null:
+                return null;
+            case MacAlgorithm.hmac_md5:
+                return TlsUtilities.CreateHash(HashAlgorithm.md5);
+            case MacAlgorithm.hmac_sha1:
+                return TlsUtilities.CreateHash(HashAlgorithm.sha1);
+            case MacAlgorithm.hmac_sha256:
+                return TlsUtilities.CreateHash(HashAlgorithm.sha256);
+            case MacAlgorithm.hmac_sha384:
+                return TlsUtilities.CreateHash(HashAlgorithm.sha384);
+            case MacAlgorithm.hmac_sha512:
+                return TlsUtilities.CreateHash(HashAlgorithm.sha512);
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/DefaultTlsClient.cs b/crypto/src/crypto/tls/DefaultTlsClient.cs
index c5b59a06b..a2a04a33c 100644
--- a/crypto/src/crypto/tls/DefaultTlsClient.cs
+++ b/crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -11,249 +11,451 @@ using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public abstract class DefaultTlsClient
-		: TlsClient
-	{
-		protected TlsCipherFactory cipherFactory;
-
-		protected TlsClientContext context;
-
-        protected CompressionMethod selectedCompressionMethod;
-        protected CipherSuite selectedCipherSuite;
-
-		public DefaultTlsClient()
-			: this(new DefaultTlsCipherFactory())
-		{
-		}
-
-		public DefaultTlsClient(TlsCipherFactory cipherFactory)
-		{
-			this.cipherFactory = cipherFactory;
-		}
-
-		public virtual void Init(TlsClientContext context)
-		{
-			this.context = context;
-		}
-
-        public virtual CipherSuite[] GetCipherSuites()
-		{
-			return new CipherSuite[] {
-				CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-			};
-		}
-
-		public virtual CompressionMethod[] GetCompressionMethods()
+    public abstract class DefaultTlsClient
+        :   AbstractTlsClient
+    {
+        public DefaultTlsClient()
+            :   base()
         {
-			/*
-			 * To offer DEFLATE compression, override this method:
-			 *     return new CompressionMethod[] { CompressionMethod.DEFLATE, CompressionMethod.NULL };
-			 */
+        }
 
-            return new CompressionMethod[] { CompressionMethod.NULL };
+        public DefaultTlsClient(TlsCipherFactory cipherFactory)
+            :   base(cipherFactory)
+        {
         }
 
-        public virtual IDictionary GetClientExtensions()
-		{
-			return null;
-		}
+        public override int[] GetCipherSuites()
+        {
+            return new int[]
+            {
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
+                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+            };
+        }
 
-        public virtual void NotifySessionID(byte[] sessionID)
-		{
-			// Currently ignored
-		}
+        public override TlsKeyExchange GetKeyExchange()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+                return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS);
+
+            case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+                return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA);
+
+            case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+                return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+                return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+                return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_ECDSA);
+
+            case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+                return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_RSA);
+
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+                return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_ECDSA);
+
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+                return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
+
+            case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+                return CreateRsaKeyExchange();
+
+            default:
+                /*
+                    * Note: internal error here; the TlsProtocol implementation verifies that the
+                    * server-selected cipher suite was in the list of client-offered cipher suites, so if
+                    * we now can't produce an implementation, we shouldn't have offered it!
+                    */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
 
-        public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite)
-		{
-			this.selectedCipherSuite = selectedCipherSuite;
-		}
+        public override TlsCipher GetCipher()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AEAD_CHACHA20_POLY1305, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM_8, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha384);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM_8, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha384);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.ESTREAM_SALSA20, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_md5);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_md5);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SALSA20, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SEED_CBC, MacAlgorithm.hmac_sha1);
+
+            default:
+                /*
+                    * Note: internal error here; the TlsProtocol implementation verifies that the
+                    * server-selected cipher suite was in the list of client-offered cipher suites, so if
+                    * we now can't produce an implementation, we shouldn't have offered it!
+                    */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange)
+        {
+            return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null);
+        }
 
-        public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod)
+        protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange)
         {
-            this.selectedCompressionMethod = selectedCompressionMethod;
+            return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, null);
         }
 
-        public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
-		{
-			if (!secureRenegotiation)
-			{
-				/*
-				 * RFC 5746 3.4.
-				 * If the extension is not present, the server does not support
-				 * secure renegotiation; set secure_renegotiation flag to FALSE.
-				 * In this case, some clients may want to terminate the handshake
-				 * instead of continuing; see Section 4.1 for discussion.
-				 */
-//				throw new TlsFatalAlert(AlertDescription.handshake_failure);
-			}
-		}
-
-        public virtual void ProcessServerExtensions(IDictionary serverExtensions)
-		{
-		}
-
-        public virtual TlsKeyExchange GetKeyExchange()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
-					return CreateRsaKeyExchange();
-
-				case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
-					return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS);
-
-				case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
-					return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA);
-
-				case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
-					return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
-
-				case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
-					return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
-
-                case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
-                    return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_ECDSA);
-
-                case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
-                    return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_ECDSA);
-
-                case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
-                    return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_RSA);
-
-                case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
-                    return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
-
-				default:
-					/*
-					* Note: internal error here; the TlsProtocolHandler verifies that the
-					* server-selected cipher suite was in the list of client-offered cipher
-					* suites, so if we now can't produce an implementation, we shouldn't have
-					* offered it!
-					*/
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public abstract TlsAuthentication GetAuthentication();
-
-		public virtual TlsCompression GetCompression()
-		{
-			switch (selectedCompressionMethod)
-			{
-				case CompressionMethod.NULL:
-					return new TlsNullCompression();
-
-				case CompressionMethod.DEFLATE:
-					return new TlsDeflateCompression();
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected compression method was in the list of client-offered compression
-					 * methods, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual TlsCipher GetCipher()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
-
-				case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
-
-				case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
-                case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
-                case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
-                case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
-
-				default:
-					/*
-					* Note: internal error here; the TlsProtocolHandler verifies that the
-					* server-selected cipher suite was in the list of client-offered cipher
-					* suites, so if we now can't produce an implementation, we shouldn't have
-					* offered it!
-					*/
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		protected virtual TlsKeyExchange CreateDHKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsDHKeyExchange(context, keyExchange);
-		}
-
-        protected virtual TlsKeyExchange CreateDheKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsDheKeyExchange(context, keyExchange);
-		}
-
-        protected virtual TlsKeyExchange CreateECDHKeyExchange(KeyExchangeAlgorithm keyExchange)
+        protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange)
         {
-            return new TlsECDHKeyExchange(context, keyExchange);
+            return new TlsECDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+                mServerECPointFormats);
         }
 
-        protected virtual TlsKeyExchange CreateECDheKeyExchange(KeyExchangeAlgorithm keyExchange)
+        protected virtual TlsKeyExchange CreateECDheKeyExchange(int keyExchange)
         {
-            return new TlsECDheKeyExchange(context, keyExchange);
+            return new TlsECDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+                mServerECPointFormats);
         }
 
         protected virtual TlsKeyExchange CreateRsaKeyExchange()
-		{
-			return new TlsRsaKeyExchange(context);
-		}
+        {
+            return new TlsRsaKeyExchange(mSupportedSignatureAlgorithms);
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs b/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
new file mode 100644
index 000000000..34d15d146
--- /dev/null
+++ b/crypto/src/crypto/tls/DefaultTlsEncryptionCredentials.cs
@@ -0,0 +1,51 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class DefaultTlsEncryptionCredentials
+        :   AbstractTlsEncryptionCredentials
+    {
+        protected readonly TlsContext mContext;
+        protected readonly Certificate mCertificate;
+        protected readonly AsymmetricKeyParameter mPrivateKey;
+
+        public DefaultTlsEncryptionCredentials(TlsContext context, Certificate certificate,
+            AsymmetricKeyParameter privateKey)
+        {
+            if (certificate == null)
+                throw new ArgumentNullException("certificate");
+            if (certificate.IsEmpty)
+                throw new ArgumentException("cannot be empty", "certificate");
+            if (privateKey == null)
+                throw new ArgumentNullException("'privateKey' cannot be null");
+            if (!privateKey.IsPrivate)
+                throw new ArgumentException("must be private", "privateKey");
+
+            if (privateKey is RsaKeyParameters)
+            {
+            }
+            else
+            {
+                throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
+            }
+
+            this.mContext = context;
+            this.mCertificate = certificate;
+            this.mPrivateKey = privateKey;
+        }
+
+        public override Certificate Certificate
+        {
+            get { return mCertificate; }
+        }
+
+        /// <exception cref="IOException"></exception>
+        public override byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret)
+        {
+            return TlsRsaUtilities.SafeDecryptPreMasterSecret(mContext, (RsaKeyParameters)mPrivateKey, encryptedPreMasterSecret);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/DefaultTlsServer.cs b/crypto/src/crypto/tls/DefaultTlsServer.cs
new file mode 100644
index 000000000..017ed0d85
--- /dev/null
+++ b/crypto/src/crypto/tls/DefaultTlsServer.cs
@@ -0,0 +1,548 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class DefaultTlsServer
+        :   AbstractTlsServer
+    {
+        public DefaultTlsServer()
+            :   base()
+        {
+        }
+
+        public DefaultTlsServer(TlsCipherFactory cipherFactory)
+            :   base(cipherFactory)
+        {
+        }
+
+        protected virtual TlsEncryptionCredentials GetRsaEncryptionCredentials()
+        {
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        protected virtual TlsSignerCredentials GetRsaSignerCredentials()
+        {
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        protected virtual DHParameters GetDHParameters()
+        {
+            return DHStandardGroups.rfc5114_1024_160;
+        }
+
+        protected override int[] GetCipherSuites()
+        {
+            return new int[]
+            {
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
+                CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+                CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256,
+                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
+                CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+            };
+        }
+
+        public override TlsCredentials GetCredentials()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+                return GetRsaEncryptionCredentials();
+
+            case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+                return GetRsaSignerCredentials();
+
+            default:
+                /*
+                 * Note: internal error here; selected a key exchange we don't implement!
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public override TlsKeyExchange GetKeyExchange()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+                return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_DSS);
+
+            case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+                return CreateDHKeyExchange(KeyExchangeAlgorithm.DH_RSA);
+
+            case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+                return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_DSS);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+                return CreateDheKeyExchange(KeyExchangeAlgorithm.DHE_RSA);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+                return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_ECDSA);
+
+            case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+                return CreateECDHKeyExchange(KeyExchangeAlgorithm.ECDH_RSA);
+
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+                return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_ECDSA);
+
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+                return CreateECDheKeyExchange(KeyExchangeAlgorithm.ECDHE_RSA);
+
+            case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+                return createRSAKeyExchange();
+
+            default:
+                /*
+                 * Note: internal error here; selected a key exchange we don't implement!
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public override TlsCipher GetCipher()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AEAD_CHACHA20_POLY1305, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM_8, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha384);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM_8, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha384);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.ESTREAM_SALSA20, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_md5);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_md5);
+
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SALSA20, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SEED_CBC, MacAlgorithm.hmac_sha1);
+
+            default:
+                /*
+                 * Note: internal error here; selected a cipher suite we don't implement!
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        protected virtual TlsKeyExchange CreateDHKeyExchange(int keyExchange)
+        {
+            return new TlsDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters());
+        }
+
+        protected virtual TlsKeyExchange CreateDheKeyExchange(int keyExchange)
+        {
+            return new TlsDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, GetDHParameters());
+        }
+
+        protected virtual TlsKeyExchange CreateECDHKeyExchange(int keyExchange)
+        {
+            return new TlsECDHKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+                mServerECPointFormats);
+        }
+
+        protected virtual TlsKeyExchange CreateECDheKeyExchange(int keyExchange)
+        {
+            return new TlsECDheKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mNamedCurves, mClientECPointFormats,
+                mServerECPointFormats);
+        }
+
+        protected virtual TlsKeyExchange createRSAKeyExchange()
+        {
+            return new TlsRsaKeyExchange(mSupportedSignatureAlgorithms);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
index 23d607d85..c7a136573 100644
--- a/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
+++ b/crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
@@ -1,76 +1,92 @@
 using System;
+using System.IO;
 
 using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class DefaultTlsSignerCredentials
-		: TlsSignerCredentials
-	{
-		protected TlsClientContext context;
-		protected Certificate clientCert;
-		protected AsymmetricKeyParameter clientPrivateKey;
+    public class DefaultTlsSignerCredentials
+        :   AbstractTlsSignerCredentials
+    {
+        protected readonly TlsContext mContext;
+        protected readonly Certificate mCertificate;
+        protected readonly AsymmetricKeyParameter mPrivateKey;
+        protected readonly SignatureAndHashAlgorithm mSignatureAndHashAlgorithm;
 
-		protected TlsSigner clientSigner;
+        protected readonly TlsSigner mSigner;
 
-		public DefaultTlsSignerCredentials(TlsClientContext context,
-			Certificate clientCertificate, AsymmetricKeyParameter clientPrivateKey)
-		{
-			if (clientCertificate == null)
-			{
-				throw new ArgumentNullException("clientCertificate");
-			}
-			if (clientCertificate.certs.Length == 0)
-			{
-				throw new ArgumentException("cannot be empty", "clientCertificate");
-			}
-			if (clientPrivateKey == null)
-			{
-				throw new ArgumentNullException("clientPrivateKey");
-			}
-			if (!clientPrivateKey.IsPrivate)
-			{
-				throw new ArgumentException("must be private", "clientPrivateKey");
-			}
+        public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey)
+            :   this(context, certificate, privateKey, null)
+        {
+        }
 
-			if (clientPrivateKey is RsaKeyParameters)
-			{
-				clientSigner = new TlsRsaSigner();
-			}
-			else if (clientPrivateKey is DsaPrivateKeyParameters)
-			{
-				clientSigner = new TlsDssSigner();
-			}
-			else if (clientPrivateKey is ECPrivateKeyParameters)
-			{
-				clientSigner = new TlsECDsaSigner();
-			}
-			else
-			{
-				throw new ArgumentException("type not supported: "
-					+ clientPrivateKey.GetType().FullName, "clientPrivateKey");
-			}
+        public DefaultTlsSignerCredentials(TlsContext context, Certificate certificate, AsymmetricKeyParameter privateKey,
+            SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+        {
+            if (certificate == null)
+                throw new ArgumentNullException("certificate");
+            if (certificate.IsEmpty)
+                throw new ArgumentException("cannot be empty", "clientCertificate");
+            if (privateKey == null)
+                throw new ArgumentNullException("privateKey");
+            if (!privateKey.IsPrivate)
+                throw new ArgumentException("must be private", "privateKey");
+            if (TlsUtilities.IsTlsV12(context) && signatureAndHashAlgorithm == null)
+                throw new ArgumentException("cannot be null for (D)TLS 1.2+", "signatureAndHashAlgorithm");
 
-			this.context = context;
-			this.clientCert = clientCertificate;
-			this.clientPrivateKey = clientPrivateKey;
-		}
+            if (privateKey is RsaKeyParameters)
+            {
+                mSigner = new TlsRsaSigner();
+            }
+            else if (privateKey is DsaPrivateKeyParameters)
+            {
+                mSigner = new TlsDssSigner();
+            }
+            else if (privateKey is ECPrivateKeyParameters)
+            {
+                mSigner = new TlsECDsaSigner();
+            }
+            else
+            {
+                throw new ArgumentException("type not supported: " + privateKey.GetType().FullName, "privateKey");
+            }
 
-		public virtual Certificate Certificate
-		{
-			get { return clientCert; }
-		}
+            this.mSigner.Init(context);
 
-		public virtual byte[] GenerateCertificateSignature(byte[] md5andsha1)
-		{
-			try
-			{
-				return clientSigner.CalculateRawSignature(context.SecureRandom, clientPrivateKey, md5andsha1);
-			}
-			catch (CryptoException)
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-	}
+            this.mContext = context;
+            this.mCertificate = certificate;
+            this.mPrivateKey = privateKey;
+            this.mSignatureAndHashAlgorithm = signatureAndHashAlgorithm;
+        }
+
+        public override Certificate Certificate
+        {
+            get { return mCertificate; }
+        }
+
+        /// <exception cref="IOException"></exception>
+        public override byte[] GenerateCertificateSignature(byte[] hash)
+        {
+            try
+            {
+                if (TlsUtilities.IsTlsV12(mContext))
+                {
+                    return mSigner.GenerateRawSignature(mSignatureAndHashAlgorithm, mPrivateKey, hash);
+                }
+                else
+                {
+                    return mSigner.GenerateRawSignature(mPrivateKey, hash);
+                }
+            }
+            catch (CryptoException e)
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error, e);
+            }
+        }
+
+        public override SignatureAndHashAlgorithm SignatureAndHashAlgorithm
+        {
+            get { return mSignatureAndHashAlgorithm; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/DeferredHash.cs b/crypto/src/crypto/tls/DeferredHash.cs
new file mode 100644
index 000000000..1112d4a3c
--- /dev/null
+++ b/crypto/src/crypto/tls/DeferredHash.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * Buffers input until the hash algorithm is determined.
+     */
+    internal class DeferredHash
+        :   TlsHandshakeHash
+    {
+        protected const int BUFFERING_HASH_LIMIT = 4;
+
+        protected TlsContext mContext;
+
+        private DigestInputBuffer mBuf;
+        private IDictionary mHashes;
+        private int mPrfHashAlgorithm;
+
+        internal DeferredHash()
+        {
+            this.mBuf = new DigestInputBuffer();
+            this.mHashes = Platform.CreateHashtable();
+            this.mPrfHashAlgorithm = -1;
+        }
+
+        private DeferredHash(byte prfHashAlgorithm, IDigest prfHash)
+        {
+            this.mBuf = null;
+            this.mHashes = Platform.CreateHashtable();
+            this.mPrfHashAlgorithm = prfHashAlgorithm;
+            mHashes[prfHashAlgorithm] = prfHash;
+        }
+
+        public virtual void Init(TlsContext context)
+        {
+            this.mContext = context;
+        }
+
+        public virtual TlsHandshakeHash NotifyPrfDetermined()
+        {
+            int prfAlgorithm = mContext.SecurityParameters.PrfAlgorithm;
+            if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
+            {
+                CombinedHash legacyHash = new CombinedHash();
+                legacyHash.Init(mContext);
+                mBuf.UpdateDigest(legacyHash);
+                return legacyHash.NotifyPrfDetermined();
+            }
+
+            this.mPrfHashAlgorithm = TlsUtilities.GetHashAlgorithmForPrfAlgorithm(prfAlgorithm);
+
+            CheckTrackingHash((byte)mPrfHashAlgorithm);
+
+            return this;
+        }
+
+        public virtual void TrackHashAlgorithm(byte hashAlgorithm)
+        {
+            if (mBuf == null)
+                throw new InvalidOperationException("Too late to track more hash algorithms");
+
+            CheckTrackingHash(hashAlgorithm);
+        }
+
+        public virtual void SealHashAlgorithms()
+        {
+            CheckStopBuffering();
+        }
+
+        public virtual TlsHandshakeHash StopTracking()
+        {
+            byte prfHashAlgorithm = (byte)mPrfHashAlgorithm;
+            IDigest prfHash = TlsUtilities.CloneHash(prfHashAlgorithm, (IDigest)mHashes[prfHashAlgorithm]);
+            if (mBuf != null)
+            {
+                mBuf.UpdateDigest(prfHash);
+            }
+            DeferredHash result = new DeferredHash(prfHashAlgorithm, prfHash);
+            result.Init(mContext);
+            return result;
+        }
+
+        public virtual IDigest ForkPrfHash()
+        {
+            CheckStopBuffering();
+
+            byte prfHashAlgorithm = (byte)mPrfHashAlgorithm;
+            if (mBuf != null)
+            {
+                IDigest prfHash = TlsUtilities.CreateHash(prfHashAlgorithm);
+                mBuf.UpdateDigest(prfHash);
+                return prfHash;
+            }
+
+            return TlsUtilities.CloneHash(prfHashAlgorithm, (IDigest)mHashes[prfHashAlgorithm]);
+        }
+
+        public virtual byte[] GetFinalHash(byte hashAlgorithm)
+        {
+            IDigest d = (IDigest)mHashes[hashAlgorithm];
+            if (d == null)
+                throw new InvalidOperationException("HashAlgorithm " + hashAlgorithm + " is not being tracked");
+
+            d = TlsUtilities.CloneHash(hashAlgorithm, d);
+            if (mBuf != null)
+            {
+                mBuf.UpdateDigest(d);
+            }
+
+            return DigestUtilities.DoFinal(d);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { throw new InvalidOperationException("Use Fork() to get a definite IDigest"); }
+        }
+
+        public virtual int GetByteLength()
+        {
+            throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+        }
+
+        public virtual int GetDigestSize()
+        {
+            throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+        }
+
+        public virtual void Update(byte input)
+        {
+            if (mBuf != null)
+            {
+                mBuf.WriteByte(input);
+                return;
+            }
+
+            foreach (IDigest hash in mHashes.Values)
+            {
+                hash.Update(input);
+            }
+        }
+
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            if (mBuf != null)
+            {
+                mBuf.Write(input, inOff, len);
+                return;
+            }
+
+            foreach (IDigest hash in mHashes.Values)
+            {
+                hash.BlockUpdate(input, inOff, len);
+            }
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            throw new InvalidOperationException("Use Fork() to get a definite IDigest");
+        }
+
+        public virtual void Reset()
+        {
+            if (mBuf != null)
+            {
+                mBuf.SetLength(0);
+                return;
+            }
+
+            foreach (IDigest hash in mHashes.Values)
+            {
+                hash.Reset();
+            }
+        }
+
+        protected virtual void CheckStopBuffering()
+        {
+            if (mBuf != null && mHashes.Count <= BUFFERING_HASH_LIMIT)
+            {
+                foreach (IDigest hash in mHashes.Values)
+                {
+                    mBuf.UpdateDigest(hash);
+                }
+
+                this.mBuf = null;
+            }
+        }
+
+        protected virtual void CheckTrackingHash(byte hashAlgorithm)
+        {
+            if (!mHashes.Contains(hashAlgorithm))
+            {
+                IDigest hash = TlsUtilities.CreateHash(hashAlgorithm);
+                mHashes[hashAlgorithm] = hash;
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/DigestInputBuffer.cs b/crypto/src/crypto/tls/DigestInputBuffer.cs
new file mode 100644
index 000000000..547bcab54
--- /dev/null
+++ b/crypto/src/crypto/tls/DigestInputBuffer.cs
@@ -0,0 +1,39 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    internal class DigestInputBuffer
+        :   MemoryStream
+    {
+        internal void UpdateDigest(IDigest d)
+        {
+            WriteTo(new DigStream(d));
+        }
+
+        private class DigStream
+            :   BaseOutputStream
+        {
+            private readonly IDigest d;
+
+            internal DigStream(IDigest d)
+            {
+                this.d = d;
+            }
+
+            public override void WriteByte(byte b)
+            {
+                d.Update(b);
+            }
+
+            public override void Write(byte[] buf, int off, int len)
+            {
+                d.BlockUpdate(buf, off, len);
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/DigitallySigned.cs b/crypto/src/crypto/tls/DigitallySigned.cs
new file mode 100644
index 000000000..8b7344fd9
--- /dev/null
+++ b/crypto/src/crypto/tls/DigitallySigned.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class DigitallySigned
+    {
+        protected readonly SignatureAndHashAlgorithm mAlgorithm;
+        protected readonly byte[] mSignature;
+
+        public DigitallySigned(SignatureAndHashAlgorithm algorithm, byte[] signature)
+        {
+            if (signature == null)
+                throw new ArgumentNullException("signature");
+
+            this.mAlgorithm = algorithm;
+            this.mSignature = signature;
+        }
+
+        /**
+         * @return a {@link SignatureAndHashAlgorithm} (or null before TLS 1.2).
+         */
+        public virtual SignatureAndHashAlgorithm Algorithm
+        {
+            get { return mAlgorithm; }
+        }
+
+        public virtual byte[] Signature
+        {
+            get { return mSignature; }
+        }
+
+        /**
+         * Encode this {@link DigitallySigned} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            if (mAlgorithm != null)
+            {
+                mAlgorithm.Encode(output);
+            }
+            TlsUtilities.WriteOpaque16(mSignature, output);
+        }
+
+        /**
+         * Parse a {@link DigitallySigned} from a {@link Stream}.
+         * 
+         * @param context
+         *            the {@link TlsContext} of the current connection.
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link DigitallySigned} object.
+         * @throws IOException
+         */
+        public static DigitallySigned Parse(TlsContext context, Stream input)
+        {
+            SignatureAndHashAlgorithm algorithm = null;
+            if (TlsUtilities.IsTlsV12(context))
+            {
+                algorithm = SignatureAndHashAlgorithm.Parse(input);
+            }
+            byte[] signature = TlsUtilities.ReadOpaque16(input);
+            return new DigitallySigned(algorithm, signature);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ECBasisType.cs b/crypto/src/crypto/tls/ECBasisType.cs
new file mode 100644
index 000000000..5416e17c0
--- /dev/null
+++ b/crypto/src/crypto/tls/ECBasisType.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 4492 5.4. (Errata ID: 2389)</summary>
+    public abstract class ECBasisType
+    {
+        public const byte ec_basis_trinomial = 1;
+        public const byte ec_basis_pentanomial = 2;
+
+        public static bool IsValid(byte ecBasisType)
+        {
+            return ecBasisType >= ec_basis_trinomial && ecBasisType <= ec_basis_pentanomial;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ECCurveType.cs b/crypto/src/crypto/tls/ECCurveType.cs
index 15d5d7b42..1b352e9c4 100644
--- a/crypto/src/crypto/tls/ECCurveType.cs
+++ b/crypto/src/crypto/tls/ECCurveType.cs
@@ -1,29 +1,29 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 4492 5.4
-	/// </summary>
-    public enum ECCurveType : byte
-	{
-		/**
-		 * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
-		 * underlying finite field is a prime field.
-		 */
-		explicit_prime = 1,
+    /// <summary>
+    /// RFC 4492 5.4
+    /// </summary>
+    public abstract class ECCurveType
+    {
+        /**
+         * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+         * underlying finite field is a prime field.
+         */
+        public const byte explicit_prime = 1;
 
-		/**
-		 * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
-		 * underlying finite field is a characteristic-2 field.
-		 */
-		explicit_char2 = 2,
+        /**
+         * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+         * underlying finite field is a characteristic-2 field.
+         */
+        public const byte explicit_char2 = 2;
 
-		/**
-		 * Indicates that a named curve is used. This option SHOULD be used when applicable.
-		 */
-		named_curve = 3,
+        /**
+         * Indicates that a named curve is used. This option SHOULD be used when applicable.
+         */
+        public const byte named_curve = 3;
 
-		/*
-		 * Values 248 through 255 are reserved for private use.
-		 */
-	}
+        /*
+         * Values 248 through 255 are reserved for private use.
+         */
+    }
 }
diff --git a/crypto/src/crypto/tls/ECPointFormat.cs b/crypto/src/crypto/tls/ECPointFormat.cs
index 4e0dd0067..21b0fdd97 100644
--- a/crypto/src/crypto/tls/ECPointFormat.cs
+++ b/crypto/src/crypto/tls/ECPointFormat.cs
@@ -1,16 +1,16 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 4492 5.1.2
-	/// </summary>
-    public enum ECPointFormat : byte
-	{
-		uncompressed = 0,
-		ansiX962_compressed_prime = 1,
-		ansiX962_compressed_char2 = 2,
+    /// <summary>
+    /// RFC 4492 5.1.2
+    /// </summary>
+    public abstract class ECPointFormat
+    {
+        public const byte uncompressed = 0;
+        public const byte ansiX962_compressed_prime = 1;
+        public const byte ansiX962_compressed_char2 = 2;
 
-		/*
-		 * reserved (248..255)
-		 */
-	}
+        /*
+         * reserved (248..255)
+         */
+    }
 }
diff --git a/crypto/src/crypto/tls/EncryptionAlgorithm.cs b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
index 79d3b63b5..05d1c5d7a 100644
--- a/crypto/src/crypto/tls/EncryptionAlgorithm.cs
+++ b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -2,31 +2,68 @@ using System;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public enum EncryptionAlgorithm
-	{
-		/*
-		 * Note that the values here are implementation-specific and arbitrary.
-		 * It is recommended not to depend on the particular values (e.g. serialization).
-		 */
-		NULL,
-		RC4_40,
-		RC4_128,
-		RC2_CBC_40,
-		IDEA_CBC,
-		DES40_CBC,
-		DES_CBC,
-		cls_3DES_EDE_CBC,
-
-		/*
-		 * RFC 3268
-		 */
-		AES_128_CBC,
-		AES_256_CBC,
-
-		/*
-		 * RFC 5289
-		 */
-		AES_128_GCM,
-		AES_256_GCM,
-	}
+    /// <summary>RFC 2246</summary>
+    /// <remarks>
+    /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+    /// depend on the particular values (e.g. serialization).
+    /// </remarks>
+    public abstract class EncryptionAlgorithm
+    {
+        public const int NULL = 0;
+        public const int RC4_40 = 1;
+        public const int RC4_128 = 2;
+        public const int RC2_CBC_40 = 3;
+        public const int IDEA_CBC = 4;
+        public const int DES40_CBC = 5;
+        public const int DES_CBC = 6;
+        public const int cls_3DES_EDE_CBC = 7;
+
+        /*
+         * RFC 3268
+         */
+        public const int AES_128_CBC = 8;
+        public const int AES_256_CBC = 9;
+
+        /*
+         * RFC 5289
+         */
+        public const int AES_128_GCM = 10;
+        public const int AES_256_GCM = 11;
+
+        /*
+         * RFC 4132
+         */
+        public const int CAMELLIA_128_CBC = 12;
+        public const int CAMELLIA_256_CBC = 13;
+
+        /*
+         * RFC 4162
+         */
+        public const int SEED_CBC = 14;
+
+        /*
+         * RFC 6655
+         */
+        public const int AES_128_CCM = 15;
+        public const int AES_128_CCM_8 = 16;
+        public const int AES_256_CCM = 17;
+        public const int AES_256_CCM_8 = 18;
+
+        /*
+         * RFC 6367
+         */
+        public const int CAMELLIA_128_GCM = 19;
+        public const int CAMELLIA_256_GCM = 20;
+
+        /*
+         * draft-josefsson-salsa20-tls-04 
+         */
+        public const int ESTREAM_SALSA20 = 100;
+        public const int SALSA20 = 101;
+
+        /*
+         * draft-agl-tls-chacha20poly1305-04
+         */
+        public const int AEAD_CHACHA20_POLY1305 = 102;
+    }
 }
diff --git a/crypto/src/crypto/tls/ExporterLabel.cs b/crypto/src/crypto/tls/ExporterLabel.cs
new file mode 100644
index 000000000..f301ea3c0
--- /dev/null
+++ b/crypto/src/crypto/tls/ExporterLabel.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 5705</summary>
+    public abstract class ExporterLabel
+    {
+        /*
+         * RFC 5246
+         */
+        public const string client_finished = "client finished";
+        public const string server_finished = "server finished";
+        public const string master_secret = "master secret";
+        public const string key_expansion = "key expansion";
+
+        /*
+         * RFC 5216
+         */
+        public const string client_EAP_encryption = "client EAP encryption";
+
+        /*
+         * RFC 5281
+         */
+        public const string ttls_keying_material = "ttls keying material";
+        public const string ttls_challenge = "ttls challenge";
+
+        /*
+         * RFC 5764
+         */
+        public const string dtls_srtp = "EXTRACTOR-dtls_srtp";
+    }
+}
diff --git a/crypto/src/crypto/tls/ExtensionType.cs b/crypto/src/crypto/tls/ExtensionType.cs
index f00e34e3f..929c134d5 100644
--- a/crypto/src/crypto/tls/ExtensionType.cs
+++ b/crypto/src/crypto/tls/ExtensionType.cs
@@ -1,31 +1,61 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 4366 2.3
-	/// </summary>
-	public enum ExtensionType : int
-	{
-		server_name = 0,
-		max_fragment_length = 1,
-		client_certificate_url = 2,
-		trusted_ca_keys = 3,
-		truncated_hmac = 4,
-		status_request = 5,
-
-		/*
-		 * RFC 4492
-		 */
-		elliptic_curves = 10,
-		ec_point_formats = 11,
-
-		/*
-		 * RFC 5054 2.8.1
-		 */
-		srp = 12,
-
-		/*
-		 * RFC 5746 6
-		 */
-		renegotiation_info = 0xff01,
-	}
+    public abstract class ExtensionType
+    {
+        /*
+         * RFC 2546 2.3.
+         */
+        public const int server_name = 0;
+        public const int max_fragment_length = 1;
+        public const int client_certificate_url = 2;
+        public const int trusted_ca_keys = 3;
+        public const int truncated_hmac = 4;
+        public const int status_request = 5;
+
+        /*
+         * RFC 4681
+         */
+        public const int user_mapping = 6;
+
+        /*
+         * RFC 4492 5.1.
+         */
+        public const int elliptic_curves = 10;
+        public const int ec_point_formats = 11;
+
+        /*
+         * RFC 5054 2.8.1.
+         */
+        public const int srp = 12;
+
+        /*
+         * RFC 5246 7.4.1.4.
+         */
+        public const int signature_algorithms = 13;
+
+        /*
+         * RFC 5764 9.
+         */
+        public const int use_srtp = 14;
+
+        /*
+         * RFC 6520 6.
+         */
+        public const int heartbeat = 15;
+
+        /*
+         * RFC 5077 7.
+         */
+        public const int session_ticket = 35;
+
+        /*
+         * draft-ietf-tls-encrypt-then-mac-03
+         */
+        public const int encrypt_then_mac = 22;
+
+        /*
+         * RFC 5746 3.2.
+         */
+        public const int renegotiation_info = 0xff01;
+    }
 }
diff --git a/crypto/src/crypto/tls/HandshakeType.cs b/crypto/src/crypto/tls/HandshakeType.cs
index deedb1f84..e63042ac3 100644
--- a/crypto/src/crypto/tls/HandshakeType.cs
+++ b/crypto/src/crypto/tls/HandshakeType.cs
@@ -1,19 +1,40 @@
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 2246 7.4
-	/// </summary>
-    public enum HandshakeType : byte
-	{
-		hello_request = 0,
-		client_hello = 1,
-		server_hello = 2,
-		certificate = 11,
-		server_key_exchange = 12,
-		certificate_request = 13,
-		server_hello_done = 14,
-		certificate_verify = 15,
-		client_key_exchange = 16,
-		finished = 20,
-	}
+    public abstract class HandshakeType
+    {
+        /*
+         * RFC 2246 7.4
+         */
+        public const byte hello_request = 0;
+        public const byte client_hello = 1;
+        public const byte server_hello = 2;
+        public const byte certificate = 11;
+        public const byte server_key_exchange = 12;
+        public const byte certificate_request = 13;
+        public const byte server_hello_done = 14;
+        public const byte certificate_verify = 15;
+        public const byte client_key_exchange = 16;
+        public const byte finished = 20;
+
+        /*
+         * RFC 3546 2.4
+         */
+        public const byte certificate_url = 21;
+        public const byte certificate_status = 22;
+
+        /*
+         *  (DTLS) RFC 4347 4.3.2
+         */
+        public const byte hello_verify_request = 3;
+
+        /*
+         * RFC 4680 
+         */
+        public const byte supplemental_data = 23;
+
+        /*
+         * RFC 5077 
+         */
+        public const byte session_ticket = 4;
+    }
 }
diff --git a/crypto/src/crypto/tls/HashAlgorithm.cs b/crypto/src/crypto/tls/HashAlgorithm.cs
new file mode 100644
index 000000000..ac6def26f
--- /dev/null
+++ b/crypto/src/crypto/tls/HashAlgorithm.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 5246 7.4.1.4.1</summary>
+    public abstract class HashAlgorithm
+    {
+        public const byte none = 0;
+        public const byte md5 = 1;
+        public const byte sha1 = 2;
+        public const byte sha224 = 3;
+        public const byte sha256 = 4;
+        public const byte sha384 = 5;
+        public const byte sha512 = 6;
+    }
+}
diff --git a/crypto/src/crypto/tls/HeartbeatExtension.cs b/crypto/src/crypto/tls/HeartbeatExtension.cs
new file mode 100644
index 000000000..049837266
--- /dev/null
+++ b/crypto/src/crypto/tls/HeartbeatExtension.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class HeartbeatExtension
+    {
+        protected readonly byte mMode;
+
+        public HeartbeatExtension(byte mode)
+        {
+            if (!HeartbeatMode.IsValid(mode))
+                throw new ArgumentException("not a valid HeartbeatMode value", "mode");
+
+            this.mMode = mode;
+        }
+
+        public virtual byte Mode
+        {
+            get { return mMode; }
+        }
+
+        /**
+         * Encode this {@link HeartbeatExtension} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint8(mMode, output);
+        }
+
+        /**
+         * Parse a {@link HeartbeatExtension} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link HeartbeatExtension} object.
+         * @throws IOException
+         */
+        public static HeartbeatExtension Parse(Stream input)
+        {
+            byte mode = TlsUtilities.ReadUint8(input);
+            if (!HeartbeatMode.IsValid(mode))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            return new HeartbeatExtension(mode);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/HeartbeatMessage.cs b/crypto/src/crypto/tls/HeartbeatMessage.cs
new file mode 100644
index 000000000..f64a7baa4
--- /dev/null
+++ b/crypto/src/crypto/tls/HeartbeatMessage.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class HeartbeatMessage
+    {
+        protected readonly byte mType;
+        protected readonly byte[] mPayload;
+        protected readonly int mPaddingLength;
+
+        public HeartbeatMessage(byte type, byte[] payload, int paddingLength)
+        {
+            if (!HeartbeatMessageType.IsValid(type))
+                throw new ArgumentException("not a valid HeartbeatMessageType value", "type");
+            if (payload == null || payload.Length >= (1 << 16))
+                throw new ArgumentException("must have length < 2^16", "payload");
+            if (paddingLength < 16)
+                throw new ArgumentException("must be at least 16", "paddingLength");
+
+            this.mType = type;
+            this.mPayload = payload;
+            this.mPaddingLength = paddingLength;
+        }
+
+        /**
+         * Encode this {@link HeartbeatMessage} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(TlsContext context, Stream output)
+        {
+            TlsUtilities.WriteUint8(mType, output);
+
+            TlsUtilities.CheckUint16(mPayload.Length);
+            TlsUtilities.WriteUint16(mPayload.Length, output);
+            output.Write(mPayload, 0, mPayload.Length);
+
+            byte[] padding = new byte[mPaddingLength];
+            context.NonceRandomGenerator.NextBytes(padding);
+            output.Write(padding, 0, padding.Length);
+        }
+
+        /**
+         * Parse a {@link HeartbeatMessage} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link HeartbeatMessage} object.
+         * @throws IOException
+         */
+        public static HeartbeatMessage Parse(Stream input)
+        {
+            byte type = TlsUtilities.ReadUint8(input);
+            if (!HeartbeatMessageType.IsValid(type))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            int payload_length = TlsUtilities.ReadUint16(input);
+
+            PayloadBuffer buf = new PayloadBuffer();
+            Streams.PipeAll(input, buf);
+
+            byte[] payload = buf.ToTruncatedByteArray(payload_length);
+            if (payload == null)
+            {
+                /*
+                 * RFC 6520 4. If the payload_length of a received HeartbeatMessage is too large, the
+                 * received HeartbeatMessage MUST be discarded silently.
+                 */
+                return null;
+            }
+
+            TlsUtilities.CheckUint16(buf.Length);
+            int padding_length = (int)buf.Length - payload.Length;
+
+            /*
+             * RFC 6520 4. The padding of a received HeartbeatMessage message MUST be ignored
+             */
+            return new HeartbeatMessage(type, payload, padding_length);
+        }
+
+        internal class PayloadBuffer
+            :   MemoryStream
+        {
+            internal byte[] ToTruncatedByteArray(int payloadLength)
+            {
+                /*
+                 * RFC 6520 4. The padding_length MUST be at least 16.
+                 */
+                int minimumCount = payloadLength + 16;
+                if (Length < minimumCount)
+                    return null;
+                return Arrays.CopyOf(GetBuffer(), payloadLength);
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/HeartbeatMessageType.cs b/crypto/src/crypto/tls/HeartbeatMessageType.cs
new file mode 100644
index 000000000..57a4b86be
--- /dev/null
+++ b/crypto/src/crypto/tls/HeartbeatMessageType.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /*
+     * RFC 6520 3.
+     */
+    public abstract class HeartbeatMessageType
+    {
+        public const byte heartbeat_request = 1;
+        public const byte heartbeat_response = 2;
+
+        public static bool IsValid(byte heartbeatMessageType)
+        {
+            return heartbeatMessageType >= heartbeat_request && heartbeatMessageType <= heartbeat_response;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/HeartbeatMode.cs b/crypto/src/crypto/tls/HeartbeatMode.cs
new file mode 100644
index 000000000..f1570a84d
--- /dev/null
+++ b/crypto/src/crypto/tls/HeartbeatMode.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /*
+     * RFC 6520
+     */
+    public abstract class HeartbeatMode
+    {
+        public const byte peer_allowed_to_send = 1;
+        public const byte peer_not_allowed_to_send = 2;
+
+        public static bool IsValid(byte heartbeatMode)
+        {
+            return heartbeatMode >= peer_allowed_to_send && heartbeatMode <= peer_not_allowed_to_send;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs b/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
index 3fdbeb2a6..9b1b3ba5e 100644
--- a/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
+++ b/crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
@@ -2,35 +2,53 @@ using System;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public enum KeyExchangeAlgorithm
-	{
-		/*
-		 * Note that the values here are implementation-specific and arbitrary.
-		 * It is recommended not to depend on the particular values (e.g. serialization).
-		 */
-		NULL,
-		RSA,
-		RSA_EXPORT,
-		DHE_DSS,
-		DHE_DSS_EXPORT,
-		DHE_RSA,
-		DHE_RSA_EXPORT,
-		DH_DSS,
-		DH_DSS_EXPORT,
-		DH_RSA,
-		DH_RSA_EXPORT,
-		DH_anon,
-		DH_anon_export,
-		PSK,
-		DHE_PSK,
-		RSA_PSK,
-		ECDH_ECDSA,
-		ECDHE_ECDSA,
-		ECDH_RSA,
-		ECDHE_RSA,
-		ECDH_anon,
-		SRP,
-		SRP_DSS,
-		SRP_RSA,
-	}
+    /// <summary>RFC 2246</summary>
+    /// <remarks>
+    /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+    /// depend on the particular values (e.g. serialization).
+    /// </remarks>
+    public abstract class KeyExchangeAlgorithm
+    {
+        public const int NULL = 0;
+        public const int RSA = 1;
+        public const int RSA_EXPORT = 2;
+        public const int DHE_DSS = 3;
+        public const int DHE_DSS_EXPORT = 4;
+        public const int DHE_RSA = 5;
+        public const int DHE_RSA_EXPORT = 6;
+        public const int DH_DSS = 7;
+        public const int DH_DSS_EXPORT = 8;
+        public const int DH_RSA = 9;
+        public const int DH_RSA_EXPORT = 10;
+        public const int DH_anon = 11;
+        public const int DH_anon_EXPORT = 12;
+
+        /*
+         * RFC 4279
+         */
+        public const int PSK = 13;
+        public const int DHE_PSK = 14;
+        public const int RSA_PSK = 15;
+
+        /*
+         * RFC 4429
+         */
+        public const int ECDH_ECDSA = 16;
+        public const int ECDHE_ECDSA = 17;
+        public const int ECDH_RSA = 18;
+        public const int ECDHE_RSA = 19;
+        public const int ECDH_anon = 20;
+
+        /*
+         * RFC 5054
+         */
+        public const int SRP = 21;
+        public const int SRP_DSS = 22;
+        public const int SRP_RSA = 23;
+    
+        /*
+         * RFC 5489
+         */
+        public const int ECDHE_PSK = 24;
+    }
 }
diff --git a/crypto/src/crypto/tls/MacAlgorithm.cs b/crypto/src/crypto/tls/MacAlgorithm.cs
new file mode 100644
index 000000000..e4aa88de6
--- /dev/null
+++ b/crypto/src/crypto/tls/MacAlgorithm.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 2246</summary>
+    /// <remarks>
+    /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+    /// depend on the particular values (e.g. serialization).
+    /// </remarks>
+    public abstract class MacAlgorithm
+    {
+        public const int cls_null = 0;
+        public const int md5 = 1;
+        public const int sha = 2;
+
+        /*
+         * RFC 5246
+         */
+        public const int hmac_md5 = md5;
+        public const int hmac_sha1 = sha;
+        public const int hmac_sha256 = 3;
+        public const int hmac_sha384 = 4;
+        public const int hmac_sha512 = 5;
+    }
+}
diff --git a/crypto/src/crypto/tls/MaxFragmentLength.cs b/crypto/src/crypto/tls/MaxFragmentLength.cs
new file mode 100644
index 000000000..5b10b35dd
--- /dev/null
+++ b/crypto/src/crypto/tls/MaxFragmentLength.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class MaxFragmentLength
+    {
+        /*
+         * RFC 3546 3.2.
+         */
+        public const byte pow2_9 = 1;
+        public const byte pow2_10 = 2;
+        public const byte pow2_11 = 3;
+        public const byte pow2_12 = 4;
+
+        public static bool IsValid(byte maxFragmentLength)
+        {
+            return maxFragmentLength >= pow2_9 && maxFragmentLength <= pow2_12;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/NameType.cs b/crypto/src/crypto/tls/NameType.cs
new file mode 100644
index 000000000..25f6046fc
--- /dev/null
+++ b/crypto/src/crypto/tls/NameType.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class NameType
+    {
+        /*
+         * RFC 3546 3.1.
+         */
+        public const byte host_name = 0;
+    }
+}
diff --git a/crypto/src/crypto/tls/NamedCurve.cs b/crypto/src/crypto/tls/NamedCurve.cs
index c8ee189aa..b8aa0ecde 100644
--- a/crypto/src/crypto/tls/NamedCurve.cs
+++ b/crypto/src/crypto/tls/NamedCurve.cs
@@ -6,67 +6,72 @@ using Org.BouncyCastle.Crypto.Parameters;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// RFC 4492 5.1.1
-	/// The named curves defined here are those specified in SEC 2 [13]. Note that many of
- 	/// these curves are also recommended in ANSI X9.62 [7] and FIPS 186-2 [11]. Values 0xFE00
-	/// through 0xFEFF are reserved for private use. Values 0xFF01 and 0xFF02 indicate that the
-	/// client supports arbitrary prime and characteristic-2 curves, respectively (the curve
-	/// parameters must be encoded explicitly in ECParameters).
-	/// </summary>
-	public enum NamedCurve : int
-	{
-		sect163k1 = 1,
-		sect163r1 = 2,
-		sect163r2 = 3,
-		sect193r1 = 4,
-		sect193r2 = 5,
-		sect233k1 = 6,
-		sect233r1 = 7,
-		sect239k1 = 8,
-		sect283k1 = 9,
-		sect283r1 = 10,
-		sect409k1 = 11,
-		sect409r1 = 12,
-		sect571k1 = 13,
-		sect571r1 = 14,
-		secp160k1 = 15,
-		secp160r1 = 16,
-		secp160r2 = 17,
-		secp192k1 = 18,
-		secp192r1 = 19,
-		secp224k1 = 20,
-		secp224r1 = 21,
-		secp256k1 = 22,
-		secp256r1 = 23,
-		secp384r1 = 24,
-		secp521r1 = 25,
+    /// <summary>
+    /// RFC 4492 5.1.1
+    /// The named curves defined here are those specified in SEC 2 [13]. Note that many of
+    /// these curves are also recommended in ANSI X9.62 [7] and FIPS 186-2 [11]. Values 0xFE00
+    /// through 0xFEFF are reserved for private use. Values 0xFF01 and 0xFF02 indicate that the
+    /// client supports arbitrary prime and characteristic-2 curves, respectively (the curve
+    /// parameters must be encoded explicitly in ECParameters).
+    /// </summary>
+    public abstract class NamedCurve
+    {
+        public const int sect163k1 = 1;
+        public const int sect163r1 = 2;
+        public const int sect163r2 = 3;
+        public const int sect193r1 = 4;
+        public const int sect193r2 = 5;
+        public const int sect233k1 = 6;
+        public const int sect233r1 = 7;
+        public const int sect239k1 = 8;
+        public const int sect283k1 = 9;
+        public const int sect283r1 = 10;
+        public const int sect409k1 = 11;
+        public const int sect409r1 = 12;
+        public const int sect571k1 = 13;
+        public const int sect571r1 = 14;
+        public const int secp160k1 = 15;
+        public const int secp160r1 = 16;
+        public const int secp160r2 = 17;
+        public const int secp192k1 = 18;
+        public const int secp192r1 = 19;
+        public const int secp224k1 = 20;
+        public const int secp224r1 = 21;
+        public const int secp256k1 = 22;
+        public const int secp256r1 = 23;
+        public const int secp384r1 = 24;
+        public const int secp521r1 = 25;
+    
+        /*
+         * RFC 7027
+         */
+        public const int brainpoolP256r1 = 26;
+        public const int brainpoolP384r1 = 27;
+        public const int brainpoolP512r1 = 28;
 
-		/*
-		 * reserved (0xFE00..0xFEFF)
-		 */
+        /*
+         * reserved (0xFE00..0xFEFF)
+         */
 
-		arbitrary_explicit_prime_curves = 0xFF01,
-		arbitrary_explicit_char2_curves = 0xFF02,
-	}
+        public const int arbitrary_explicit_prime_curves = 0xFF01;
+        public const int arbitrary_explicit_char2_curves = 0xFF02;
 
-	internal class NamedCurveHelper
-	{
-	    internal static ECDomainParameters GetECParameters(NamedCurve namedCurve)
-	    {
-            if (!Enum.IsDefined(typeof(NamedCurve), namedCurve))
-                return null;
+        public static bool IsValid(int namedCurve)
+        {
+            return (namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1)
+                || (namedCurve >= arbitrary_explicit_prime_curves && namedCurve <= arbitrary_explicit_char2_curves);
+        }
 
-            string curveName = namedCurve.ToString();
-
-            // Lazily created the first time a particular curve is accessed
-	        X9ECParameters ecP = SecNamedCurves.GetByName(curveName);
-
-            if (ecP == null)
-                return null;
-
-	        // It's a bit inefficient to do this conversion every time
-	        return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
-	    }
-	}
+        public static bool RefersToASpecificNamedCurve(int namedCurve)
+        {
+            switch (namedCurve)
+            {
+            case arbitrary_explicit_prime_curves:
+            case arbitrary_explicit_char2_curves:
+                return false;
+            default:
+                return true;
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/NewSessionTicket.cs b/crypto/src/crypto/tls/NewSessionTicket.cs
new file mode 100644
index 000000000..a84026b8c
--- /dev/null
+++ b/crypto/src/crypto/tls/NewSessionTicket.cs
@@ -0,0 +1,53 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class NewSessionTicket
+    {
+        protected readonly long mTicketLifetimeHint;
+        protected readonly byte[] mTicket;
+
+        public NewSessionTicket(long ticketLifetimeHint, byte[] ticket)
+        {
+            this.mTicketLifetimeHint = ticketLifetimeHint;
+            this.mTicket = ticket;
+        }
+
+        public virtual long TicketLifetimeHint
+        {
+            get { return mTicketLifetimeHint; }
+        }
+
+        public virtual byte[] Ticket
+        {
+            get { return mTicket; }
+        }
+
+        /**
+         * Encode this {@link NewSessionTicket} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint32(mTicketLifetimeHint, output);
+            TlsUtilities.WriteOpaque16(mTicket, output);
+        }
+
+        /**
+         * Parse a {@link NewSessionTicket} from a {@link Stream}.
+         *
+         * @param input the {@link Stream} to parse from.
+         * @return a {@link NewSessionTicket} object.
+         * @throws IOException
+         */
+        public static NewSessionTicket Parse(Stream input)
+        {
+            long ticketLifetimeHint = TlsUtilities.ReadUint32(input);
+            byte[] ticket = TlsUtilities.ReadOpaque16(input);
+            return new NewSessionTicket(ticketLifetimeHint, ticket);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/OcspStatusRequest.cs b/crypto/src/crypto/tls/OcspStatusRequest.cs
new file mode 100644
index 000000000..2dd8371e5
--- /dev/null
+++ b/crypto/src/crypto/tls/OcspStatusRequest.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 3546 3.6
+     */
+    public class OcspStatusRequest
+    {
+        protected readonly IList mResponderIDList;
+        protected readonly X509Extensions mRequestExtensions;
+
+        /**
+         * @param responderIDList
+         *            an {@link IList} of {@link ResponderID}, specifying the list of trusted OCSP
+         *            responders. An empty list has the special meaning that the responders are
+         *            implicitly known to the server - e.g., by prior arrangement.
+         * @param requestExtensions
+         *            OCSP request extensions. A null value means that there are no extensions.
+         */
+        public OcspStatusRequest(IList responderIDList, X509Extensions requestExtensions)
+        {
+            this.mResponderIDList = responderIDList;
+            this.mRequestExtensions = requestExtensions;
+        }
+
+        /**
+         * @return an {@link IList} of {@link ResponderID}
+         */
+        public virtual IList ResponderIDList
+        {
+            get { return mResponderIDList; }
+        }
+
+        /**
+         * @return OCSP request extensions
+         */
+        public virtual X509Extensions RequestExtensions
+        {
+            get { return mRequestExtensions; }
+        }
+
+        /**
+         * Encode this {@link OcspStatusRequest} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            if (mResponderIDList == null || mResponderIDList.Count < 1)
+            {
+                TlsUtilities.WriteUint16(0, output);
+            }
+            else
+            {
+                MemoryStream buf = new MemoryStream();
+                for (int i = 0; i < mResponderIDList.Count; ++i)
+                {
+                    ResponderID responderID = (ResponderID)mResponderIDList[i];
+                    byte[] derEncoding = responderID.GetEncoded(Asn1Encodable.Der);
+                    TlsUtilities.WriteOpaque16(derEncoding, buf);
+                }
+                TlsUtilities.CheckUint16(buf.Length);
+                TlsUtilities.WriteUint16((int)buf.Length, output);
+                buf.WriteTo(output);
+            }
+
+            if (mRequestExtensions == null)
+            {
+                TlsUtilities.WriteUint16(0, output);
+            }
+            else
+            {
+                byte[] derEncoding = mRequestExtensions.GetEncoded(Asn1Encodable.Der);
+                TlsUtilities.CheckUint16(derEncoding.Length);
+                TlsUtilities.WriteUint16(derEncoding.Length, output);
+                output.Write(derEncoding, 0, derEncoding.Length);
+            }
+        }
+
+        /**
+         * Parse a {@link OcspStatusRequest} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return an {@link OcspStatusRequest} object.
+         * @throws IOException
+         */
+        public static OcspStatusRequest Parse(Stream input)
+        {
+            IList responderIDList = Platform.CreateArrayList();
+            {
+                int length = TlsUtilities.ReadUint16(input);
+                if (length > 0)
+                {
+                    byte[] data = TlsUtilities.ReadFully(length, input);
+                    MemoryStream buf = new MemoryStream(data, false);
+                    do
+                    {
+                        byte[] derEncoding = TlsUtilities.ReadOpaque16(buf);
+                        ResponderID responderID = ResponderID.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+                        responderIDList.Add(responderID);
+                    }
+                    while (buf.Position < buf.Length);
+                }
+            }
+
+            X509Extensions requestExtensions = null;
+            {
+                int length = TlsUtilities.ReadUint16(input);
+                if (length > 0)
+                {
+                    byte[] derEncoding = TlsUtilities.ReadFully(length, input);
+                    requestExtensions = X509Extensions.GetInstance(TlsUtilities.ReadDerObject(derEncoding));
+                }
+            }
+
+            return new OcspStatusRequest(responderIDList, requestExtensions);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/PrfAlgorithm.cs b/crypto/src/crypto/tls/PrfAlgorithm.cs
new file mode 100644
index 000000000..871241bd2
--- /dev/null
+++ b/crypto/src/crypto/tls/PrfAlgorithm.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 5246</summary>
+    /// <remarks>
+    /// Note that the values here are implementation-specific and arbitrary. It is recommended not to
+    /// depend on the particular values (e.g. serialization).
+    /// </remarks>
+    public abstract class PrfAlgorithm
+    {
+        /*
+         * Placeholder to refer to the legacy TLS algorithm
+         */
+        public const int tls_prf_legacy = 0;
+
+        public const int tls_prf_sha256 = 1;
+
+        /*
+         * Implied by RFC 5288
+         */
+        public const int tls_prf_sha384 = 2;
+    }
+}
diff --git a/crypto/src/crypto/tls/ProtocolVersion.cs b/crypto/src/crypto/tls/ProtocolVersion.cs
new file mode 100644
index 000000000..b0d55183a
--- /dev/null
+++ b/crypto/src/crypto/tls/ProtocolVersion.cs
@@ -0,0 +1,159 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public sealed class ProtocolVersion
+    {
+        public static readonly ProtocolVersion SSLv3 = new ProtocolVersion(0x0300, "SSL 3.0");
+        public static readonly ProtocolVersion TLSv10 = new ProtocolVersion(0x0301, "TLS 1.0");
+        public static readonly ProtocolVersion TLSv11 = new ProtocolVersion(0x0302, "TLS 1.1");
+        public static readonly ProtocolVersion TLSv12 = new ProtocolVersion(0x0303, "TLS 1.2");
+        public static readonly ProtocolVersion DTLSv10 = new ProtocolVersion(0xFEFF, "DTLS 1.0");
+        public static readonly ProtocolVersion DTLSv12 = new ProtocolVersion(0xFEFD, "DTLS 1.2");
+
+        private readonly int version;
+        private readonly String name;
+
+        private ProtocolVersion(int v, String name)
+        {
+            this.version = v & 0xffff;
+            this.name = name;
+        }
+
+        public int FullVersion
+        {
+            get { return version; }
+        }
+
+        public int MajorVersion
+        {
+            get { return version >> 8; }
+        }
+
+        public int MinorVersion
+        {
+            get { return version & 0xff; }
+        }
+
+        public bool IsDtls
+        {
+            get { return MajorVersion == 0xFE; }
+        }
+
+        public bool IsSsl
+        {
+            get { return this == SSLv3; }
+        }
+
+        public bool IsTls
+        {
+            get { return MajorVersion == 0x03; }
+        }
+
+        public ProtocolVersion GetEquivalentTLSVersion()
+        {
+            if (!IsDtls)
+            {
+                return this;
+            }
+            if (this == DTLSv10)
+            {
+                return TLSv11;
+            }
+            return TLSv12;
+        }
+
+        public bool IsEqualOrEarlierVersionOf(ProtocolVersion version)
+        {
+            if (MajorVersion != version.MajorVersion)
+            {
+                return false;
+            }
+            int diffMinorVersion = version.MinorVersion - MinorVersion;
+            return IsDtls ? diffMinorVersion <= 0 : diffMinorVersion >= 0;
+        }
+
+        public bool IsLaterVersionOf(ProtocolVersion version)
+        {
+            if (MajorVersion != version.MajorVersion)
+            {
+                return false;
+            }
+            int diffMinorVersion = version.MinorVersion - MinorVersion;
+            return IsDtls ? diffMinorVersion > 0 : diffMinorVersion < 0;
+        }
+
+        public override bool Equals(object other)
+        {
+            return this == other || (other is ProtocolVersion && Equals((ProtocolVersion)other));
+        }
+
+        public bool Equals(ProtocolVersion other)
+        {
+            return other != null && this.version == other.version;
+        }
+
+        public override int GetHashCode()
+        {
+            return version;
+        }
+
+        /// <exception cref="IOException"/>
+        public static ProtocolVersion Get(int major, int minor)
+        {
+            switch (major)
+            {
+                case 0x03:
+                {
+                    switch (minor)
+                    {
+                        case 0x00:
+                            return SSLv3;
+                        case 0x01:
+                            return TLSv10;
+                        case 0x02:
+                            return TLSv11;
+                        case 0x03:
+                            return TLSv12;
+                    }
+                    return GetUnknownVersion(major, minor, "TLS");
+                }
+                case 0xFE:
+                {
+                    switch (minor)
+                    {
+                        case 0xFF:
+                            return DTLSv10;
+                        case 0xFE:
+                            throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                        case 0xFD:
+                            return DTLSv12;
+                    }
+                    return GetUnknownVersion(major, minor, "DTLS");
+                }
+                default:
+                {
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+        }
+
+        public override string ToString()
+        {
+            return name;
+        }
+
+        private static ProtocolVersion GetUnknownVersion(int major, int minor, string prefix)
+        {
+            TlsUtilities.CheckUint8(major);
+            TlsUtilities.CheckUint8(minor);
+
+            int v = (major << 8) | minor;
+            String hex = Platform.ToUpperInvariant(Convert.ToString(0x10000 | v, 16).Substring(1));
+            return new ProtocolVersion(v, prefix + " 0x" + hex);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/PskTlsClient.cs b/crypto/src/crypto/tls/PskTlsClient.cs
index 16975e713..6063572a0 100644
--- a/crypto/src/crypto/tls/PskTlsClient.cs
+++ b/crypto/src/crypto/tls/PskTlsClient.cs
@@ -3,180 +3,259 @@ using System.Collections;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class PskTlsClient
-		:TlsClient
-	{
-		protected TlsCipherFactory cipherFactory;
-		protected TlsPskIdentity pskIdentity;
-
-		protected TlsClientContext context;
-
-		protected CompressionMethod selectedCompressionMethod;
-		protected CipherSuite selectedCipherSuite;
-
-		public PskTlsClient(TlsPskIdentity pskIdentity)
-			: this(new DefaultTlsCipherFactory(), pskIdentity)
-		{
-		}
-
-		public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity)
-		{
-			this.cipherFactory = cipherFactory;
-			this.pskIdentity = pskIdentity;
-		}
-
-		public virtual void Init(TlsClientContext context)
-		{
-			this.context = context;
-		}
-
-		public virtual CipherSuite[] GetCipherSuites()
-		{
-			return new CipherSuite[] {
-				CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA,
-			};
-		}
-
-		public virtual IDictionary GetClientExtensions()
-		{
-			return null;
-		}
-
-		public virtual CompressionMethod[] GetCompressionMethods()
-		{
-			return new CompressionMethod[] { CompressionMethod.NULL };
-		}
-
-		public virtual void NotifySessionID(byte[] sessionID)
-		{
-			// Currently ignored 
-		}
-
-		public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite)
-		{
-			this.selectedCipherSuite = selectedCipherSuite;
-		}
-
-		public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod)
-		{
-			this.selectedCompressionMethod = selectedCompressionMethod;
-		}
-
-		public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
-		{
-			if (!secureRenegotiation)
-			{
-				/*
-				 * RFC 5746 3.4. If the extension is not present, the server does not support
-				 * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
-				 * some clients may want to terminate the handshake instead of continuing; see
-				 * Section 4.1 for discussion.
-				 */
-//				throw new TlsFatalAlert(AlertDescription.handshake_failure);
-			}
-		}
-
-		public virtual void ProcessServerExtensions(IDictionary serverExtensions)
-		{
-		}
-
-		public virtual TlsKeyExchange GetKeyExchange()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
-					return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK);
-
-				case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
-					return CreatePskKeyExchange(KeyExchangeAlgorithm.RSA_PSK);
-
-				case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
-					return CreatePskKeyExchange(KeyExchangeAlgorithm.DHE_PSK);
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual TlsAuthentication GetAuthentication()
-		{
-			return null;
-		}
-
-		public virtual TlsCompression GetCompression()
-		{
-			switch (selectedCompressionMethod)
-			{
-				case CompressionMethod.NULL:
-					return new TlsNullCompression();
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected compression method was in the list of client-offered compression
-					 * methods, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual TlsCipher GetCipher()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC,
-						DigestAlgorithm.SHA);
-				
-				case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC,
-						DigestAlgorithm.SHA);
-
-				case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC,
-						DigestAlgorithm.SHA);
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		protected virtual TlsKeyExchange CreatePskKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsPskKeyExchange(context, keyExchange, pskIdentity);
-		}
-	}
+    public abstract class PskTlsClient
+        :   AbstractTlsClient
+    {
+        protected TlsPskIdentity mPskIdentity;
+
+        public PskTlsClient(TlsPskIdentity pskIdentity)
+            :   this(new DefaultTlsCipherFactory(), pskIdentity)
+        {
+        }
+
+        public PskTlsClient(TlsCipherFactory cipherFactory, TlsPskIdentity pskIdentity)
+            :   base(cipherFactory)
+        {
+            this.mPskIdentity = pskIdentity;
+        }
+
+        public override int[] GetCipherSuites()
+        {
+            return new int[]
+            {
+                CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
+                CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
+                CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+                CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA
+            };
+        }
+
+        public override TlsKeyExchange GetKeyExchange()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+                return CreatePskKeyExchange(KeyExchangeAlgorithm.DHE_PSK);
+
+            case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+                return CreatePskKeyExchange(KeyExchangeAlgorithm.ECDHE_PSK);
+
+            case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
+                return CreatePskKeyExchange(KeyExchangeAlgorithm.PSK);
+
+            case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
+                return CreatePskKeyExchange(KeyExchangeAlgorithm.RSA_PSK);
+
+            default:
+                /*
+                    * Note: internal error here; the TlsProtocol implementation verifies that the
+                    * server-selected cipher suite was in the list of client-offered cipher suites, so if
+                    * we now can't produce an implementation, we shouldn't have offered it!
+                    */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public override TlsCipher GetCipher()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CCM_8, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha384);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CCM_8, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_CBC, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_128_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_CBC, MacAlgorithm.hmac_sha384);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.CAMELLIA_256_GCM, MacAlgorithm.cls_null);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.ESTREAM_SALSA20, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha256);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.NULL, MacAlgorithm.hmac_sha384);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.RC4_128, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.SALSA20, MacAlgorithm.hmac_sha1);
+
+            default:
+                /*
+                    * Note: internal error here; the TlsProtocol implementation verifies that the
+                    * server-selected cipher suite was in the list of client-offered cipher suites, so if
+                    * we now can't produce an implementation, we shouldn't have offered it!
+                    */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        protected virtual TlsKeyExchange CreatePskKeyExchange(int keyExchange)
+        {
+            return new TlsPskKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mPskIdentity, null, mNamedCurves,
+                mClientECPointFormats, mServerECPointFormats);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs
index e18894b4e..db5b158bc 100644
--- a/crypto/src/crypto/tls/RecordStream.cs
+++ b/crypto/src/crypto/tls/RecordStream.cs
@@ -3,164 +3,331 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <remarks>An implementation of the TLS 1.0 record layer.</remarks>
-	internal class RecordStream
-	{
-		private TlsProtocolHandler handler;
-		private Stream inStr;
-		private Stream outStr;
-		private CombinedHash hash;
-		private TlsCompression readCompression = null;
-		private TlsCompression writeCompression = null;
-		private TlsCipher readCipher = null;
-		private TlsCipher writeCipher = null;
-		private MemoryStream buffer = new MemoryStream();
-
-		internal RecordStream(
-			TlsProtocolHandler	handler,
-			Stream				inStr,
-			Stream				outStr)
-		{
-			this.handler = handler;
-			this.inStr = inStr;
-			this.outStr = outStr;
-			this.hash = new CombinedHash();
-			this.readCompression = new TlsNullCompression();
-			this.writeCompression = this.readCompression;
-			this.readCipher = new TlsNullCipher();
-			this.writeCipher = this.readCipher;
-		}
-
-		internal void ClientCipherSpecDecided(TlsCompression tlsCompression, TlsCipher tlsCipher)
-		{
-			this.writeCompression = tlsCompression;
-			this.writeCipher = tlsCipher;
-		}
-
-		internal void ServerClientSpecReceived()
-		{
-			this.readCompression = this.writeCompression;
-			this.readCipher = this.writeCipher;
-		}
-
-		public void ReadData()
-		{
-			ContentType type = (ContentType)TlsUtilities.ReadUint8(inStr);
-			TlsUtilities.CheckVersion(inStr);
-			int size = TlsUtilities.ReadUint16(inStr);
-			byte[] buf = DecodeAndVerify(type, inStr, size);
-			handler.ProcessData(type, buf, 0, buf.Length);
-		}
-
-		internal byte[] DecodeAndVerify(
-			ContentType	type,
-			Stream		inStr,
-			int			len)
-		{
-			byte[] buf = new byte[len];
-			TlsUtilities.ReadFully(buf, inStr);
-			byte[] decoded = readCipher.DecodeCiphertext(type, buf, 0, buf.Length);
-
-			Stream cOut = readCompression.Decompress(buffer);
-
-			if (cOut == buffer)
-			{
-				return decoded;
-			}
-
-			cOut.Write(decoded, 0, decoded.Length);
-			cOut.Flush();
-			byte[] contents = buffer.ToArray();
-			buffer.SetLength(0);
-			return contents;
-		}
-
-		internal void WriteMessage(
-			ContentType	type,
-			byte[]		message,
-			int			offset,
-			int			len)
-		{
-			if (type == ContentType.handshake)
-			{
-				UpdateHandshakeData(message, offset, len);
-			}
-
-			Stream cOut = writeCompression.Compress(buffer);
-
-			byte[] ciphertext;
-			if (cOut == buffer)
-			{
-				ciphertext = writeCipher.EncodePlaintext(type, message, offset, len);
-			}
-			else
-			{
-				cOut.Write(message, offset, len);
-				cOut.Flush();
-				ciphertext = writeCipher.EncodePlaintext(type, buffer.ToArray(), 0, (int)buffer.Position);
-				buffer.SetLength(0);
-			}
-
-			byte[] writeMessage = new byte[ciphertext.Length + 5];
-            TlsUtilities.WriteUint8((byte)type, writeMessage, 0);
-			TlsUtilities.WriteVersion(writeMessage, 1);
-			TlsUtilities.WriteUint16(ciphertext.Length, writeMessage, 3);
-			Array.Copy(ciphertext, 0, writeMessage, 5, ciphertext.Length);
-			outStr.Write(writeMessage, 0, writeMessage.Length);
-			outStr.Flush();
-		}
-
-		internal void UpdateHandshakeData(
-			byte[]	message,
-			int		offset,
-			int		len)
-		{
-			hash.BlockUpdate(message, offset, len);
-		}
-
-		internal byte[] GetCurrentHash()
-		{
-			return DoFinal(new CombinedHash(hash));
-		}
-
-		internal void Close()
-		{
-			IOException e = null;
-			try
-			{
-                inStr.Dispose();
-			}
-			catch (IOException ex)
-			{
-				e = ex;
-			}
-
-			try
-			{
-				// NB: This is harmless if outStr == inStr
-                outStr.Dispose();
-			}
-			catch (IOException ex)
-			{
-				e = ex;
-			}
-
-			if (e != null)
-			{
-				throw e;
-			}
-		}
-
-		internal void Flush()
-		{
-			outStr.Flush();
-		}
-
-		private static byte[] DoFinal(CombinedHash ch)
-		{
-			byte[] bs = new byte[ch.GetDigestSize()];
-			ch.DoFinal(bs, 0);
-			return bs;
-		}
-	}
+    /// <summary>An implementation of the TLS 1.0/1.1/1.2 record layer, allowing downgrade to SSLv3.</summary>
+    internal class RecordStream
+    {
+        private const int DEFAULT_PLAINTEXT_LIMIT = (1 << 14);
+
+        private TlsProtocol mHandler;
+        private Stream mInput;
+        private Stream mOutput;
+        private TlsCompression mPendingCompression = null, mReadCompression = null, mWriteCompression = null;
+        private TlsCipher mPendingCipher = null, mReadCipher = null, mWriteCipher = null;
+        private long mReadSeqNo = 0, mWriteSeqNo = 0;
+        private MemoryStream mBuffer = new MemoryStream();
+
+        private TlsHandshakeHash mHandshakeHash = null;
+
+        private ProtocolVersion mReadVersion = null, mWriteVersion = null;
+        private bool mRestrictReadVersion = true;
+
+        private int mPlaintextLimit, mCompressedLimit, mCiphertextLimit;
+
+        internal RecordStream(TlsProtocol handler, Stream input, Stream output)
+        {
+            this.mHandler = handler;
+            this.mInput = input;
+            this.mOutput = output;
+            this.mReadCompression = new TlsNullCompression();
+            this.mWriteCompression = this.mReadCompression;
+        }
+
+        internal virtual void Init(TlsContext context)
+        {
+            this.mReadCipher = new TlsNullCipher(context);
+            this.mWriteCipher = this.mReadCipher;
+            this.mHandshakeHash = new DeferredHash();
+            this.mHandshakeHash.Init(context);
+
+            SetPlaintextLimit(DEFAULT_PLAINTEXT_LIMIT);
+        }
+
+        internal virtual int GetPlaintextLimit()
+        {
+            return mPlaintextLimit;
+        }
+
+        internal virtual void SetPlaintextLimit(int plaintextLimit)
+        {
+            this.mPlaintextLimit = plaintextLimit;
+            this.mCompressedLimit = this.mPlaintextLimit + 1024;
+            this.mCiphertextLimit = this.mCompressedLimit + 1024;
+        }
+
+        internal virtual ProtocolVersion ReadVersion
+        {
+            get { return mReadVersion; }
+            set { this.mReadVersion = value; }
+        }
+
+        internal virtual void SetWriteVersion(ProtocolVersion writeVersion)
+        {
+            this.mWriteVersion = writeVersion;
+        }
+
+        /**
+         * RFC 5246 E.1. "Earlier versions of the TLS specification were not fully clear on what the
+         * record layer version number (TLSPlaintext.version) should contain when sending ClientHello
+         * (i.e., before it is known which version of the protocol will be employed). Thus, TLS servers
+         * compliant with this specification MUST accept any value {03,XX} as the record layer version
+         * number for ClientHello."
+         */
+        internal virtual void SetRestrictReadVersion(bool enabled)
+        {
+            this.mRestrictReadVersion = enabled;
+        }
+
+        internal virtual void SetPendingConnectionState(TlsCompression tlsCompression, TlsCipher tlsCipher)
+        {
+            this.mPendingCompression = tlsCompression;
+            this.mPendingCipher = tlsCipher;
+        }
+
+        internal virtual void SentWriteCipherSpec()
+        {
+            if (mPendingCompression == null || mPendingCipher == null)
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+            this.mWriteCompression = this.mPendingCompression;
+            this.mWriteCipher = this.mPendingCipher;
+            this.mWriteSeqNo = 0;
+        }
+
+        internal virtual void ReceivedReadCipherSpec()
+        {
+            if (mPendingCompression == null || mPendingCipher == null)
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+            this.mReadCompression = this.mPendingCompression;
+            this.mReadCipher = this.mPendingCipher;
+            this.mReadSeqNo = 0;
+        }
+
+        internal virtual void FinaliseHandshake()
+        {
+            if (mReadCompression != mPendingCompression || mWriteCompression != mPendingCompression
+                || mReadCipher != mPendingCipher || mWriteCipher != mPendingCipher)
+            {
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+            }
+            this.mPendingCompression = null;
+            this.mPendingCipher = null;
+        }
+
+        internal virtual bool ReadRecord()
+        {
+            byte[] recordHeader = TlsUtilities.ReadAllOrNothing(5, mInput);
+            if (recordHeader == null)
+                return false;
+
+            byte type = TlsUtilities.ReadUint8(recordHeader, 0);
+
+            /*
+             * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
+             * unexpected_message alert.
+             */
+            CheckType(type, AlertDescription.unexpected_message);
+
+            if (!mRestrictReadVersion)
+            {
+                int version = TlsUtilities.ReadVersionRaw(recordHeader, 1);
+                if ((version & 0xffffff00) != 0x0300)
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+            else
+            {
+                ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, 1);
+                if (mReadVersion == null)
+                {
+                    mReadVersion = version;
+                }
+                else if (!version.Equals(mReadVersion))
+                {
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+
+            int length = TlsUtilities.ReadUint16(recordHeader, 3);
+            byte[] plaintext = DecodeAndVerify(type, mInput, length);
+            mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length);
+            return true;
+        }
+
+        internal virtual byte[] DecodeAndVerify(byte type, Stream input, int len)
+        {
+            CheckLength(len, mCiphertextLimit, AlertDescription.record_overflow);
+
+            byte[] buf = TlsUtilities.ReadFully(len, input);
+            byte[] decoded = mReadCipher.DecodeCiphertext(mReadSeqNo++, type, buf, 0, buf.Length);
+
+            CheckLength(decoded.Length, mCompressedLimit, AlertDescription.record_overflow);
+
+            /*
+             * TODO RFC5264 6.2.2. Implementation note: Decompression functions are responsible for
+             * ensuring that messages cannot cause internal buffer overflows.
+             */
+            Stream cOut = mReadCompression.Decompress(mBuffer);
+            if (cOut != mBuffer)
+            {
+                cOut.Write(decoded, 0, decoded.Length);
+                cOut.Flush();
+                decoded = GetBufferContents();
+            }
+
+            /*
+             * RFC 5264 6.2.2. If the decompression function encounters a TLSCompressed.fragment that
+             * would decompress to a length in excess of 2^14 bytes, it should report a fatal
+             * decompression failure error.
+             */
+            CheckLength(decoded.Length, mPlaintextLimit, AlertDescription.decompression_failure);
+
+            /*
+             * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+             * or ChangeCipherSpec content types.
+             */
+            if (decoded.Length < 1 && type != ContentType.application_data)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            return decoded;
+        }
+
+        internal virtual void WriteRecord(byte type, byte[] plaintext, int plaintextOffset, int plaintextLength)
+        {
+            // Never send anything until a valid ClientHello has been received
+            if (mWriteVersion == null)
+                return;
+
+            /*
+             * RFC 5264 6. Implementations MUST NOT send record types not defined in this document
+             * unless negotiated by some extension.
+             */
+            CheckType(type, AlertDescription.internal_error);
+
+            /*
+             * RFC 5264 6.2.1 The length should not exceed 2^14.
+             */
+            CheckLength(plaintextLength, mPlaintextLimit, AlertDescription.internal_error);
+
+            /*
+             * RFC 5264 6.2.1 Implementations MUST NOT send zero-length fragments of Handshake, Alert,
+             * or ChangeCipherSpec content types.
+             */
+            if (plaintextLength < 1 && type != ContentType.application_data)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            if (type == ContentType.handshake)
+            {
+                UpdateHandshakeData(plaintext, plaintextOffset, plaintextLength);
+            }
+
+            Stream cOut = mWriteCompression.Compress(mBuffer);
+
+            byte[] ciphertext;
+            if (cOut == mBuffer)
+            {
+                ciphertext = mWriteCipher.EncodePlaintext(mWriteSeqNo++, type, plaintext, plaintextOffset, plaintextLength);
+            }
+            else
+            {
+                cOut.Write(plaintext, plaintextOffset, plaintextLength);
+                cOut.Flush();
+                byte[] compressed = GetBufferContents();
+
+                /*
+                 * RFC5264 6.2.2. Compression must be lossless and may not increase the content length
+                 * by more than 1024 bytes.
+                 */
+                CheckLength(compressed.Length, plaintextLength + 1024, AlertDescription.internal_error);
+
+                ciphertext = mWriteCipher.EncodePlaintext(mWriteSeqNo++, type, compressed, 0, compressed.Length);
+            }
+
+            /*
+             * RFC 5264 6.2.3. The length may not exceed 2^14 + 2048.
+             */
+            CheckLength(ciphertext.Length, mCiphertextLimit, AlertDescription.internal_error);
+
+            byte[] record = new byte[ciphertext.Length + 5];
+            TlsUtilities.WriteUint8(type, record, 0);
+            TlsUtilities.WriteVersion(mWriteVersion, record, 1);
+            TlsUtilities.WriteUint16(ciphertext.Length, record, 3);
+            Array.Copy(ciphertext, 0, record, 5, ciphertext.Length);
+            mOutput.Write(record, 0, record.Length);
+            mOutput.Flush();
+        }
+
+        internal virtual void NotifyHelloComplete()
+        {
+            this.mHandshakeHash = mHandshakeHash.NotifyPrfDetermined();
+        }
+
+        internal virtual TlsHandshakeHash HandshakeHash
+        {
+            get { return mHandshakeHash; }
+        }
+
+        internal virtual TlsHandshakeHash PrepareToFinish()
+        {
+            TlsHandshakeHash result = mHandshakeHash;
+            this.mHandshakeHash = mHandshakeHash.StopTracking();
+            return result;
+        }
+
+        internal virtual void UpdateHandshakeData(byte[] message, int offset, int len)
+        {
+            mHandshakeHash.BlockUpdate(message, offset, len);
+        }
+
+        internal virtual void SafeClose()
+        {
+            try
+            {
+                mInput.Close();
+            }
+            catch (IOException)
+            {
+            }
+
+            try
+            {
+                mOutput.Close();
+            }
+            catch (IOException)
+            {
+            }
+        }
+
+        internal virtual void Flush()
+        {
+            mOutput.Flush();
+        }
+
+        private byte[] GetBufferContents()
+        {
+            byte[] contents = mBuffer.ToArray();
+            mBuffer.SetLength(0);
+            return contents;
+        }
+
+        private static void CheckType(byte type, byte alertDescription)
+        {
+            switch (type)
+            {
+            case ContentType.application_data:
+            case ContentType.alert:
+            case ContentType.change_cipher_spec:
+            case ContentType.handshake:
+            case ContentType.heartbeat:
+                break;
+            default:
+                throw new TlsFatalAlert(alertDescription);
+            }
+        }
+
+        private static void CheckLength(int length, int limit, byte alertDescription)
+        {
+            if (length > limit)
+                throw new TlsFatalAlert(alertDescription);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/SecurityParameters.cs b/crypto/src/crypto/tls/SecurityParameters.cs
index 9ed3969eb..6a115a911 100644
--- a/crypto/src/crypto/tls/SecurityParameters.cs
+++ b/crypto/src/crypto/tls/SecurityParameters.cs
@@ -1,26 +1,94 @@
 using System;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class SecurityParameters
-	{
-		internal byte[] clientRandom = null;
-		internal byte[] serverRandom = null;
-		internal byte[] masterSecret = null;
-
-		public byte[] ClientRandom
-		{
-			get { return clientRandom; }
-		}
-
-		public byte[] ServerRandom
-		{
-			get { return serverRandom; }
-		}
-
-		public byte[] MasterSecret
-		{
-			get { return masterSecret; }
-		}
-	}
+    public class SecurityParameters
+    {
+        internal int entity = -1;
+        internal int cipherSuite = -1;
+        internal byte compressionAlgorithm = CompressionMethod.cls_null;
+        internal int prfAlgorithm = -1;
+        internal int verifyDataLength = -1;
+        internal byte[] masterSecret = null;
+        internal byte[] clientRandom = null;
+        internal byte[] serverRandom = null;
+
+        // TODO Keep these internal, since it's maybe not the ideal place for them
+        internal short maxFragmentLength = -1;
+        internal bool truncatedHMac = false;
+        internal bool encryptThenMac = false;
+
+        internal void CopySessionParametersFrom(SecurityParameters other)
+        {
+            this.entity = other.entity;
+            this.cipherSuite = other.cipherSuite;
+            this.compressionAlgorithm = other.compressionAlgorithm;
+            this.prfAlgorithm = other.prfAlgorithm;
+            this.verifyDataLength = other.verifyDataLength;
+            this.masterSecret = Arrays.Clone(other.masterSecret);
+        }
+
+        internal virtual void Clear()
+        {
+            if (this.masterSecret != null)
+            {
+                Arrays.Fill(this.masterSecret, (byte)0);
+                this.masterSecret = null;
+            }
+        }
+
+        /**
+         * @return {@link ConnectionEnd}
+         */
+        public virtual int Entity
+        {
+            get { return entity; }
+        }
+
+        /**
+         * @return {@link CipherSuite}
+         */
+        public virtual int CipherSuite
+        {
+            get { return cipherSuite; }
+        }
+
+        /**
+         * @return {@link CompressionMethod}
+         */
+        public byte CompressionAlgorithm
+        {
+            get { return compressionAlgorithm; }
+        }
+
+        /**
+         * @return {@link PRFAlgorithm}
+         */
+        public virtual int PrfAlgorithm
+        {
+            get { return prfAlgorithm; }
+        }
+
+        public virtual int VerifyDataLength
+        {
+            get { return verifyDataLength; }
+        }
+
+        public virtual byte[] MasterSecret
+        {
+            get { return masterSecret; }
+        }
+
+        public virtual byte[] ClientRandom
+        {
+            get { return clientRandom; }
+        }
+
+        public virtual byte[] ServerRandom
+        {
+            get { return serverRandom; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/ServerDHParams.cs b/crypto/src/crypto/tls/ServerDHParams.cs
new file mode 100644
index 000000000..381858854
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerDHParams.cs
@@ -0,0 +1,60 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class ServerDHParams
+    {
+        protected readonly DHPublicKeyParameters mPublicKey;
+
+        public ServerDHParams(DHPublicKeyParameters publicKey)
+        {
+            if (publicKey == null)
+                throw new ArgumentNullException("publicKey");
+
+            this.mPublicKey = publicKey;
+        }
+
+        public virtual DHPublicKeyParameters PublicKey
+        {
+            get { return mPublicKey; }
+        }
+
+        /**
+         * Encode this {@link ServerDHParams} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            DHParameters dhParameters = mPublicKey.Parameters;
+            BigInteger Ys = mPublicKey.Y;
+
+            TlsDHUtilities.WriteDHParameter(dhParameters.P, output);
+            TlsDHUtilities.WriteDHParameter(dhParameters.G, output);
+            TlsDHUtilities.WriteDHParameter(Ys, output);
+        }
+
+        /**
+         * Parse a {@link ServerDHParams} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link ServerDHParams} object.
+         * @throws IOException
+         */
+        public static ServerDHParams Parse(Stream input)
+        {
+            BigInteger p = TlsDHUtilities.ReadDHParameter(input);
+            BigInteger g = TlsDHUtilities.ReadDHParameter(input);
+            BigInteger Ys = TlsDHUtilities.ReadDHParameter(input);
+
+            return new ServerDHParams(new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ServerName.cs b/crypto/src/crypto/tls/ServerName.cs
new file mode 100644
index 000000000..3d1e8f844
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerName.cs
@@ -0,0 +1,105 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class ServerName
+    {
+        protected readonly byte mNameType;
+        protected readonly object mName;
+
+        public ServerName(byte nameType, object name)
+        {
+            if (!IsCorrectType(nameType, name))
+                throw new ArgumentException("not an instance of the correct type", "name");
+
+            this.mNameType = nameType;
+            this.mName = name;
+        }
+
+        public virtual byte NameType
+        {
+            get { return mNameType; }
+        }
+
+        public virtual object Name
+        {
+            get { return mName; }
+        }
+
+        public virtual string GetHostName()
+        {
+            if (!IsCorrectType(Tls.NameType.host_name, mName))
+                throw new InvalidOperationException("'name' is not a HostName string");
+
+            return (string)mName;
+        }
+
+        /**
+         * Encode this {@link ServerName} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint8(mNameType, output);
+
+            switch (mNameType)
+            {
+            case Tls.NameType.host_name:
+                byte[] utf8Encoding = Strings.ToUtf8ByteArray((string)mName);
+                if (utf8Encoding.Length < 1)
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+                TlsUtilities.WriteOpaque16(utf8Encoding, output);
+                break;
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        /**
+         * Parse a {@link ServerName} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link ServerName} object.
+         * @throws IOException
+         */
+        public static ServerName Parse(Stream input)
+        {
+            byte name_type = TlsUtilities.ReadUint8(input);
+            object name;
+
+            switch (name_type)
+            {
+            case Tls.NameType.host_name:
+            {
+                byte[] utf8Encoding = TlsUtilities.ReadOpaque16(input);
+                if (utf8Encoding.Length < 1)
+                    throw new TlsFatalAlert(AlertDescription.decode_error);
+                name = Strings.FromUtf8ByteArray(utf8Encoding);
+                break;
+            }
+            default:
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            }
+
+            return new ServerName(name_type, name);
+        }
+
+        protected static bool IsCorrectType(byte nameType, object name)
+        {
+            switch (nameType)
+            {
+            case Tls.NameType.host_name:
+                return name is string;
+            default:
+                throw new ArgumentException("unsupported value", "name");
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ServerNameList.cs b/crypto/src/crypto/tls/ServerNameList.cs
new file mode 100644
index 000000000..13da79bf6
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerNameList.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class ServerNameList
+    {
+        protected readonly IList mServerNameList;
+
+        /**
+         * @param serverNameList an {@link IList} of {@link ServerName}.
+         */
+        public ServerNameList(IList serverNameList)
+        {
+            if (serverNameList == null || serverNameList.Count < 1)
+                throw new ArgumentException("must not be null or empty", "serverNameList");
+
+            this.mServerNameList = serverNameList;
+        }
+
+        /**
+         * @return an {@link IList} of {@link ServerName}.
+         */
+        public virtual IList ServerNames
+        {
+            get { return mServerNameList; }
+        }
+
+        /**
+         * Encode this {@link ServerNameList} to a {@link Stream}.
+         * 
+         * @param output
+         *            the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            MemoryStream buf = new MemoryStream();
+
+            foreach (ServerName entry in ServerNames)
+            {
+                entry.Encode(buf);
+            }
+
+            TlsUtilities.CheckUint16(buf.Length);
+            TlsUtilities.WriteUint16((int)buf.Length, output);
+            buf.WriteTo(output);
+        }
+
+        /**
+         * Parse a {@link ServerNameList} from a {@link Stream}.
+         * 
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link ServerNameList} object.
+         * @throws IOException
+         */
+        public static ServerNameList Parse(Stream input)
+        {
+            int length = TlsUtilities.ReadUint16(input);
+            if (length < 1)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            byte[] data = TlsUtilities.ReadFully(length, input);
+
+            MemoryStream buf = new MemoryStream(data, false);
+
+            IList server_name_list = Platform.CreateArrayList();
+            while (buf.Position < buf.Length)
+            {
+                ServerName entry = ServerName.Parse(buf);
+                server_name_list.Add(entry);
+            }
+
+            return new ServerNameList(server_name_list);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs b/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
new file mode 100644
index 000000000..485889709
--- /dev/null
+++ b/crypto/src/crypto/tls/ServerOnlyTlsAuthentication.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class ServerOnlyTlsAuthentication
+        :   TlsAuthentication
+    {
+        public abstract void NotifyServerCertificate(Certificate serverCertificate);
+
+        public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+        {
+            return null;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/SessionParameters.cs b/crypto/src/crypto/tls/SessionParameters.cs
new file mode 100644
index 000000000..c4616ac71
--- /dev/null
+++ b/crypto/src/crypto/tls/SessionParameters.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public sealed class SessionParameters
+    {
+        public sealed class Builder
+        {
+            private int mCipherSuite = -1;
+            private short mCompressionAlgorithm = -1;
+            private byte[] mMasterSecret = null;
+            private Certificate mPeerCertificate = null;
+            private byte[] mEncodedServerExtensions = null;
+
+            public Builder()
+            {
+            }
+
+            public SessionParameters Build()
+            {
+                Validate(this.mCipherSuite >= 0, "cipherSuite");
+                Validate(this.mCompressionAlgorithm >= 0, "compressionAlgorithm");
+                Validate(this.mMasterSecret != null, "masterSecret");
+                return new SessionParameters(mCipherSuite, (byte)mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
+                    mEncodedServerExtensions);
+            }
+
+            public Builder SetCipherSuite(int cipherSuite)
+            {
+                this.mCipherSuite = cipherSuite;
+                return this;
+            }
+
+            public Builder SetCompressionAlgorithm(byte compressionAlgorithm)
+            {
+                this.mCompressionAlgorithm = compressionAlgorithm;
+                return this;
+            }
+
+            public Builder SetMasterSecret(byte[] masterSecret)
+            {
+                this.mMasterSecret = masterSecret;
+                return this;
+            }
+
+            public Builder SetPeerCertificate(Certificate peerCertificate)
+            {
+                this.mPeerCertificate = peerCertificate;
+                return this;
+            }
+
+            public Builder SetServerExtensions(IDictionary serverExtensions)
+            {
+                if (serverExtensions == null)
+                {
+                    mEncodedServerExtensions = null;
+                }
+                else
+                {
+                    MemoryStream buf = new MemoryStream();
+                    TlsProtocol.WriteExtensions(buf, serverExtensions);
+                    mEncodedServerExtensions = buf.ToArray();
+                }
+                return this;
+            }
+
+            private void Validate(bool condition, string parameter)
+            {
+                if (!condition)
+                    throw new InvalidOperationException("Required session parameter '" + parameter + "' not configured");
+            }
+        }
+
+        private int mCipherSuite;
+        private byte mCompressionAlgorithm;
+        private byte[] mMasterSecret;
+        private Certificate mPeerCertificate;
+        private byte[] mEncodedServerExtensions;
+
+        private SessionParameters(int cipherSuite, byte compressionAlgorithm, byte[] masterSecret,
+            Certificate peerCertificate, byte[] encodedServerExtensions)
+        {
+            this.mCipherSuite = cipherSuite;
+            this.mCompressionAlgorithm = compressionAlgorithm;
+            this.mMasterSecret = Arrays.Clone(masterSecret);
+            this.mPeerCertificate = peerCertificate;
+            this.mEncodedServerExtensions = encodedServerExtensions;
+        }
+
+        public void Clear()
+        {
+            if (this.mMasterSecret != null)
+            {
+                Arrays.Fill(this.mMasterSecret, (byte)0);
+            }
+        }
+
+        public SessionParameters Copy()
+        {
+            return new SessionParameters(mCipherSuite, mCompressionAlgorithm, mMasterSecret, mPeerCertificate,
+                mEncodedServerExtensions);
+        }
+
+        public int CipherSuite
+        {
+            get { return mCipherSuite; }
+        }
+
+        public byte CompressionAlgorithm
+        {
+            get { return mCompressionAlgorithm; }
+        }
+
+        public byte[] MasterSecret
+        {
+            get { return mMasterSecret; }
+        }
+
+        public Certificate PeerCertificate
+        {
+            get { return mPeerCertificate; }
+        }
+
+        public IDictionary ReadServerExtensions()
+        {
+            if (mEncodedServerExtensions == null)
+                return null;
+
+            MemoryStream buf = new MemoryStream(mEncodedServerExtensions, false);
+            return TlsProtocol.ReadExtensions(buf);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/SignatureAlgorithm.cs b/crypto/src/crypto/tls/SignatureAlgorithm.cs
new file mode 100644
index 000000000..35b961762
--- /dev/null
+++ b/crypto/src/crypto/tls/SignatureAlgorithm.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5246 7.4.1.4.1 (in RFC 2246, there were no specific values assigned)
+     */
+    public abstract class SignatureAlgorithm
+    {
+        public const byte anonymous = 0;
+        public const byte rsa = 1;
+        public const byte dsa = 2;
+        public const byte ecdsa = 3;
+    }
+}
diff --git a/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs
new file mode 100644
index 000000000..f74205b62
--- /dev/null
+++ b/crypto/src/crypto/tls/SignatureAndHashAlgorithm.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5246 7.4.1.4.1
+     */
+    public class SignatureAndHashAlgorithm
+    {
+        protected readonly byte mHash;
+        protected readonly byte mSignature;
+
+        /**
+         * @param hash      {@link HashAlgorithm}
+         * @param signature {@link SignatureAlgorithm}
+         */
+        public SignatureAndHashAlgorithm(byte hash, byte signature)
+        {
+            if (!TlsUtilities.IsValidUint8(hash))
+            {
+                throw new ArgumentException("should be a uint8", "hash");
+            }
+            if (!TlsUtilities.IsValidUint8(signature))
+            {
+                throw new ArgumentException("should be a uint8", "signature");
+            }
+            if (signature == SignatureAlgorithm.anonymous)
+            {
+                throw new ArgumentException("MUST NOT be \"anonymous\"", "signature");
+            }
+
+            this.mHash = hash;
+            this.mSignature = signature;
+        }
+
+        /**
+         * @return {@link HashAlgorithm}
+         */
+        public virtual byte Hash
+        {
+            get { return mHash; }
+        }
+
+        /**
+         * @return {@link SignatureAlgorithm}
+         */
+        public virtual byte Signature
+        {
+            get { return mSignature; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is SignatureAndHashAlgorithm))
+            {
+                return false;
+            }
+            SignatureAndHashAlgorithm other = (SignatureAndHashAlgorithm)obj;
+            return other.Hash == Hash && other.Signature == Signature;
+        }
+
+        public override int GetHashCode()
+        {
+            return ((int)Hash << 16) | (int)Signature;
+        }
+
+        /**
+         * Encode this {@link SignatureAndHashAlgorithm} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint8(Hash, output);
+            TlsUtilities.WriteUint8(Signature, output);
+        }
+
+        /**
+         * Parse a {@link SignatureAndHashAlgorithm} from a {@link Stream}.
+         *
+         * @param input the {@link Stream} to parse from.
+         * @return a {@link SignatureAndHashAlgorithm} object.
+         * @throws IOException
+         */
+        public static SignatureAndHashAlgorithm Parse(Stream input)
+        {
+            byte hash = TlsUtilities.ReadUint8(input);
+            byte signature = TlsUtilities.ReadUint8(input);
+            return new SignatureAndHashAlgorithm(hash, signature);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/SignerInputBuffer.cs b/crypto/src/crypto/tls/SignerInputBuffer.cs
new file mode 100644
index 000000000..ef2827c4d
--- /dev/null
+++ b/crypto/src/crypto/tls/SignerInputBuffer.cs
@@ -0,0 +1,39 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    internal class SignerInputBuffer
+        : MemoryStream
+    {
+        internal void UpdateSigner(ISigner s)
+        {
+            WriteTo(new SigStream(s));
+        }
+
+        private class SigStream
+            : BaseOutputStream
+        {
+            private readonly ISigner s;
+
+            internal SigStream(ISigner s)
+            {
+                this.s = s;
+            }
+
+            public override void WriteByte(byte b)
+            {
+                s.Update(b);
+            }
+
+            public override void Write(byte[] buf, int off, int len)
+            {
+                s.BlockUpdate(buf, off, len);
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/SrpTlsClient.cs b/crypto/src/crypto/tls/SrpTlsClient.cs
index 6c2638bb3..5d82ed470 100644
--- a/crypto/src/crypto/tls/SrpTlsClient.cs
+++ b/crypto/src/crypto/tls/SrpTlsClient.cs
@@ -6,183 +6,118 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public abstract class SrpTlsClient
-		: TlsClient
-	{
-		protected TlsCipherFactory cipherFactory;
-		protected byte[] identity;
-		protected byte[] password;
-
-		protected TlsClientContext context;
-
-        protected CompressionMethod selectedCompressionMethod;
-        protected CipherSuite selectedCipherSuite;
-
-		public SrpTlsClient(byte[] identity, byte[] password)
-			: this(new DefaultTlsCipherFactory(), identity, password)
-		{
-		}
-
-		public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password)
-		{
-			this.cipherFactory = cipherFactory;
-			this.identity = Arrays.Clone(identity);
-			this.password = Arrays.Clone(password);
-		}
-
-		public virtual void Init(TlsClientContext context)
-		{
-			this.context = context;
-		}
-
-		public virtual CipherSuite[] GetCipherSuites()
-		{
-			return new CipherSuite[] {
-				CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
-				CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
-			};
-		}
-
-		public virtual IDictionary GetClientExtensions()
-		{
-			IDictionary clientExtensions = Platform.CreateHashtable();
-
-			MemoryStream srpData = new MemoryStream();
-			TlsUtilities.WriteOpaque8(this.identity, srpData);
-			clientExtensions[ExtensionType.srp] = srpData.ToArray();
-
-			return clientExtensions;
-		}
-
-		public virtual CompressionMethod[] GetCompressionMethods()
-		{
-			return new CompressionMethod[] { CompressionMethod.NULL };
-		}
-
-		public virtual void NotifySessionID(byte[] sessionID)
-		{
-			// Currently ignored 
-		}
-
-		public virtual void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite)
-		{
-			this.selectedCipherSuite = selectedCipherSuite;
-		}
-
-		public virtual void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod)
-		{
-            this.selectedCompressionMethod = selectedCompressionMethod;
+    public abstract class SrpTlsClient
+        :   AbstractTlsClient
+    {
+        protected byte[] mIdentity;
+        protected byte[] mPassword;
+
+        public SrpTlsClient(byte[] identity, byte[] password)
+            : this(new DefaultTlsCipherFactory(), identity, password)
+        {
         }
 
-		public virtual void NotifySecureRenegotiation(bool secureRenegotiation)
-		{
-			if (!secureRenegotiation)
-			{
-				/*
-				 * RFC 5746 3.4. If the extension is not present, the server does not support
-				 * secure renegotiation; set secure_renegotiation flag to FALSE. In this case,
-				 * some clients may want to terminate the handshake instead of continuing; see
-				 * Section 4.1 for discussion.
-				 */
-//				throw new TlsFatalAlert(AlertDescription.handshake_failure);
-			}
-		}
-
-		public virtual void ProcessServerExtensions(IDictionary serverExtensions)
-		{
-			// There is no server response for the SRP extension
-		}
-
-		public virtual TlsKeyExchange GetKeyExchange()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
-					return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP);
-
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
-					return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA);
-
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
-					return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS);
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-		
-		public abstract TlsAuthentication GetAuthentication();
-
-		public virtual TlsCompression GetCompression()
-		{
-			switch (selectedCompressionMethod)
-			{
-				case CompressionMethod.NULL:
-					return new TlsNullCompression();
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected compression method was in the list of client-offered compression
-					 * methods, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual TlsCipher GetCipher()
-		{
-			switch (selectedCipherSuite)
-			{
-				case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.cls_3DES_EDE_CBC, DigestAlgorithm.SHA);
-
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_128_CBC, DigestAlgorithm.SHA);
-
-				case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
-				case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
-					return cipherFactory.CreateCipher(context, EncryptionAlgorithm.AES_256_CBC, DigestAlgorithm.SHA);
-
-				default:
-					/*
-					 * Note: internal error here; the TlsProtocolHandler verifies that the
-					 * server-selected cipher suite was in the list of client-offered cipher
-					 * suites, so if we now can't produce an implementation, we shouldn't have
-					 * offered it!
-					 */
-					throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		protected virtual TlsKeyExchange CreateSrpKeyExchange(KeyExchangeAlgorithm keyExchange)
-		{
-			return new TlsSrpKeyExchange(context, keyExchange, identity, password);
-		}
-	}
+        public SrpTlsClient(TlsCipherFactory cipherFactory, byte[] identity, byte[] password)
+            :   base(cipherFactory)
+        {
+            this.mIdentity = Arrays.Clone(identity);
+            this.mPassword = Arrays.Clone(password);
+        }
+
+        protected virtual bool RequireSrpServerExtension
+        {
+            // No explicit guidance in RFC 5054; by default an (empty) extension from server is optional
+            get { return false; }
+        }
+
+        public override int[] GetCipherSuites()
+        {
+            return new int[]
+            {
+                CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA
+            };
+        }
+
+        public override IDictionary GetClientExtensions()
+        {
+            IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions());
+            TlsSrpUtilities.AddSrpExtension(clientExtensions, this.mIdentity);
+            return clientExtensions;
+        }
+
+        public override void ProcessServerExtensions(IDictionary serverExtensions)
+        {
+            if (!TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions, ExtensionType.srp,
+                AlertDescription.illegal_parameter))
+            {
+                if (RequireSrpServerExtension)
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            base.ProcessServerExtensions(serverExtensions);
+        }
+
+        public override TlsKeyExchange GetKeyExchange()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+                return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP);
+
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+                return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_RSA);
+
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+                return CreateSrpKeyExchange(KeyExchangeAlgorithm.SRP_DSS);
+
+            default:
+                /*
+                 * Note: internal error here; the TlsProtocol implementation verifies that the
+                 * server-selected cipher suite was in the list of client-offered cipher suites, so if
+                 * we now can't produce an implementation, we shouldn't have offered it!
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public override TlsCipher GetCipher()
+        {
+            switch (mSelectedCipherSuite)
+            {
+            case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.cls_3DES_EDE_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_128_CBC, MacAlgorithm.hmac_sha1);
+
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+                return mCipherFactory.CreateCipher(mContext, EncryptionAlgorithm.AES_256_CBC, MacAlgorithm.hmac_sha1);
+
+            default:
+                /*
+                 * Note: internal error here; the TlsProtocol implementation verifies that the
+                 * server-selected cipher suite was in the list of client-offered cipher suites, so if
+                 * we now can't produce an implementation, we shouldn't have offered it!
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        protected virtual TlsKeyExchange CreateSrpKeyExchange(int keyExchange)
+        {
+            return new TlsSrpKeyExchange(keyExchange, mSupportedSignatureAlgorithms, mIdentity, mPassword);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/SrtpProtectionProfile.cs b/crypto/src/crypto/tls/SrtpProtectionProfile.cs
new file mode 100644
index 000000000..1ce89f85e
--- /dev/null
+++ b/crypto/src/crypto/tls/SrtpProtectionProfile.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class SrtpProtectionProfile
+    {
+        /*
+         * RFC 5764 4.1.2.
+         */
+        public const int SRTP_AES128_CM_HMAC_SHA1_80 = 0x0001;
+        public const int SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002;
+        public const int SRTP_NULL_HMAC_SHA1_80 = 0x0005;
+        public const int SRTP_NULL_HMAC_SHA1_32 = 0x0006;
+    }
+}
diff --git a/crypto/src/crypto/tls/Ssl3Mac.cs b/crypto/src/crypto/tls/Ssl3Mac.cs
index b2f3f309e..8bdb342dc 100644
--- a/crypto/src/crypto/tls/Ssl3Mac.cs
+++ b/crypto/src/crypto/tls/Ssl3Mac.cs
@@ -6,109 +6,105 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/**
-	 * HMAC implementation based on original internet draft for HMAC (RFC 2104)
-	 * 
-	 * The difference is that padding is concatentated versus XORed with the key
-	 * 
-	 * H(K + opad, H(K + ipad, text))
-	 */
-	public class Ssl3Mac
-		: IMac
-	{
-		private const byte IPAD = 0x36;
-		private const byte OPAD = 0x5C;
-
-		internal static readonly byte[] MD5_IPAD = GenPad(IPAD, 48);
-		internal static readonly byte[] MD5_OPAD = GenPad(OPAD, 48);
-		internal static readonly byte[] SHA1_IPAD = GenPad(IPAD, 40);
-		internal static readonly byte[] SHA1_OPAD = GenPad(OPAD, 40);
-
-		private IDigest digest;
-
-		private byte[] secret;
-		private byte[] ipad, opad;
-
-		/**
-		 * Base constructor for one of the standard digest algorithms that the byteLength of
-		 * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1.
-		 * 
-		 * @param digest the digest.
-		 */
-		public Ssl3Mac(IDigest digest)
-		{
-			this.digest = digest;
-
-	        if (digest.GetDigestSize() == 20)
-	        {
-	            this.ipad = SHA1_IPAD;
-	            this.opad = SHA1_OPAD;
-	        }
-	        else
-	        {
-	            this.ipad = MD5_IPAD;
-	            this.opad = MD5_OPAD;
-	        }
-		}
-
-		public virtual string AlgorithmName
-		{
-			get { return digest.AlgorithmName + "/SSL3MAC"; }
-		}
-
-		public virtual void Init(ICipherParameters parameters)
-		{
-			secret = Arrays.Clone(((KeyParameter)parameters).GetKey());
-
-			Reset();
-		}
-
-		public virtual int GetMacSize()
-		{
-			return digest.GetDigestSize();
-		}
-
-		public virtual void Update(byte input)
-		{
-			digest.Update(input);
-		}
-
-		public virtual void BlockUpdate(byte[] input, int inOff, int len)
-		{
-			digest.BlockUpdate(input, inOff, len);
-		}
-
-		public virtual int DoFinal(byte[] output, int outOff)
-		{
-			byte[] tmp = new byte[digest.GetDigestSize()];
-			digest.DoFinal(tmp, 0);
-
-			digest.BlockUpdate(secret, 0, secret.Length);
-			digest.BlockUpdate(opad, 0, opad.Length);
-			digest.BlockUpdate(tmp, 0, tmp.Length);
-
-			int len = digest.DoFinal(output, outOff);
-
-			Reset();
-
-			return len;
-		}
-
-		/**
-		 * Reset the mac generator.
-		 */
-		public virtual void Reset()
-		{
-			digest.Reset();
-			digest.BlockUpdate(secret, 0, secret.Length);
-			digest.BlockUpdate(ipad, 0, ipad.Length);
-		}
-
-		private static byte[] GenPad(byte b, int count)
-		{
-			byte[] padding = new byte[count];
-			Arrays.Fill(padding, b);
-			return padding;
-		}
-	}
+    /**
+     * HMAC implementation based on original internet draft for HMAC (RFC 2104)
+     * 
+     * The difference is that padding is concatentated versus XORed with the key
+     * 
+     * H(K + opad, H(K + ipad, text))
+     */
+    public class Ssl3Mac
+        : IMac
+    {
+        private const byte IPAD_BYTE = 0x36;
+        private const byte OPAD_BYTE = 0x5C;
+
+        internal static readonly byte[] IPAD = GenPad(IPAD_BYTE, 48);
+        internal static readonly byte[] OPAD = GenPad(OPAD_BYTE, 48);
+
+        private readonly IDigest digest;
+        private readonly int padLength;
+
+        private byte[] secret;
+
+        /**
+         * Base constructor for one of the standard digest algorithms that the byteLength of
+         * the algorithm is know for. Behaviour is undefined for digests other than MD5 or SHA1.
+         * 
+         * @param digest the digest.
+         */
+        public Ssl3Mac(IDigest digest)
+        {
+            this.digest = digest;
+
+            if (digest.GetDigestSize() == 20)
+            {
+                this.padLength = 40;
+            }
+            else
+            {
+                this.padLength = 48;
+            }
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return digest.AlgorithmName + "/SSL3MAC"; }
+        }
+
+        public virtual void Init(ICipherParameters parameters)
+        {
+            secret = Arrays.Clone(((KeyParameter)parameters).GetKey());
+
+            Reset();
+        }
+
+        public virtual int GetMacSize()
+        {
+            return digest.GetDigestSize();
+        }
+
+        public virtual void Update(byte input)
+        {
+            digest.Update(input);
+        }
+
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            digest.BlockUpdate(input, inOff, len);
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            byte[] tmp = new byte[digest.GetDigestSize()];
+            digest.DoFinal(tmp, 0);
+
+            digest.BlockUpdate(secret, 0, secret.Length);
+            digest.BlockUpdate(OPAD, 0, padLength);
+            digest.BlockUpdate(tmp, 0, tmp.Length);
+
+            int len = digest.DoFinal(output, outOff);
+
+            Reset();
+
+            return len;
+        }
+
+        /**
+         * Reset the mac generator.
+         */
+        public virtual void Reset()
+        {
+            digest.Reset();
+            digest.BlockUpdate(secret, 0, secret.Length);
+            digest.BlockUpdate(IPAD, 0, padLength);
+        }
+
+        private static byte[] GenPad(byte b, int count)
+        {
+            byte[] padding = new byte[count];
+            Arrays.Fill(padding, b);
+            return padding;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/SupplementalDataEntry.cs b/crypto/src/crypto/tls/SupplementalDataEntry.cs
new file mode 100644
index 000000000..5adc4fa52
--- /dev/null
+++ b/crypto/src/crypto/tls/SupplementalDataEntry.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class SupplementalDataEntry
+    {
+        protected readonly int mDataType;
+        protected readonly byte[] mData;
+
+        public SupplementalDataEntry(int dataType, byte[] data)
+        {
+            this.mDataType = dataType;
+            this.mData = data;
+        }
+
+        public virtual int DataType
+        {
+            get { return mDataType; }
+        }
+
+        public virtual byte[] Data
+        {
+            get { return mData; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/SupplementalDataType.cs b/crypto/src/crypto/tls/SupplementalDataType.cs
new file mode 100644
index 000000000..79511c50a
--- /dev/null
+++ b/crypto/src/crypto/tls/SupplementalDataType.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <summary>RFC 4680</summary>
+    public abstract class SupplementalDataType
+    {
+        /*
+         * RFC 4681
+         */
+        public const int user_mapping_data = 0;
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsAeadCipher.cs b/crypto/src/crypto/tls/TlsAeadCipher.cs
new file mode 100644
index 000000000..951e8663b
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsAeadCipher.cs
@@ -0,0 +1,189 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class TlsAeadCipher
+        :   TlsCipher
+    {
+        protected readonly TlsContext context;
+        protected readonly int macSize;
+        protected readonly int nonce_explicit_length;
+
+        protected readonly IAeadBlockCipher encryptCipher;
+        protected readonly IAeadBlockCipher decryptCipher;
+
+        protected readonly byte[] encryptImplicitNonce, decryptImplicitNonce;
+
+        /// <exception cref="IOException"></exception>
+        public TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher,
+            int cipherKeySize, int macSize)
+        {
+            if (!TlsUtilities.IsTlsV12(context))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            this.context = context;
+            this.macSize = macSize;
+
+            // NOTE: Valid for RFC 5288/6655 ciphers but may need review for other AEAD ciphers
+            this.nonce_explicit_length = 8;
+
+            // TODO SecurityParameters.fixed_iv_length
+            int fixed_iv_length = 4;
+
+            int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);
+
+            byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+            int offset = 0;
+
+            KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+            offset += cipherKeySize;
+            KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+            offset += cipherKeySize;
+            byte[] client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+            offset += fixed_iv_length;
+            byte[] server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
+            offset += fixed_iv_length;
+
+            if (offset != key_block_size)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            KeyParameter encryptKey, decryptKey;
+            if (context.IsServer)
+            {
+                this.encryptCipher = serverWriteCipher;
+                this.decryptCipher = clientWriteCipher;
+                this.encryptImplicitNonce = server_write_IV;
+                this.decryptImplicitNonce = client_write_IV;
+                encryptKey = server_write_key;
+                decryptKey = client_write_key;
+            }
+            else
+            {
+                this.encryptCipher = clientWriteCipher;
+                this.decryptCipher = serverWriteCipher;
+                this.encryptImplicitNonce = client_write_IV;
+                this.decryptImplicitNonce = server_write_IV;
+                encryptKey = client_write_key;
+                decryptKey = server_write_key;
+            }
+
+            byte[] dummyNonce = new byte[fixed_iv_length + nonce_explicit_length];
+
+            this.encryptCipher.Init(true, new AeadParameters(encryptKey, 8 * macSize, dummyNonce));
+            this.decryptCipher.Init(false, new AeadParameters(decryptKey, 8 * macSize, dummyNonce));
+        }
+
+        public virtual int GetPlaintextLimit(int ciphertextLimit)
+        {
+            // TODO We ought to be able to ask the decryptCipher (independently of it's current state!)
+            return ciphertextLimit - macSize - nonce_explicit_length;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+        {
+            byte[] nonce = new byte[this.encryptImplicitNonce.Length + nonce_explicit_length];
+            Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length);
+
+            /*
+             * RFC 5288/6655 The nonce_explicit MAY be the 64-bit sequence number.
+             * 
+             * (May need review for other AEAD ciphers).
+             */
+            TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length);
+
+            int plaintextOffset = offset;
+            int plaintextLength = len;
+            int ciphertextLength = encryptCipher.GetOutputSize(plaintextLength);
+
+            byte[] output = new byte[nonce_explicit_length + ciphertextLength];
+            Array.Copy(nonce, encryptImplicitNonce.Length, output, 0, nonce_explicit_length);
+            int outputPos = nonce_explicit_length;
+
+            byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+            AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
+
+            try
+            {
+                encryptCipher.Init(true, parameters);
+                outputPos += encryptCipher.ProcessBytes(plaintext, plaintextOffset, plaintextLength, output, outputPos);
+                outputPos += encryptCipher.DoFinal(output, outputPos);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error, e);
+            }
+
+            if (outputPos != output.Length)
+            {
+                // NOTE: Existing AEAD cipher implementations all give exact output lengths
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            return output;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+        {
+            if (GetPlaintextLimit(len) < 0)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            byte[] nonce = new byte[this.decryptImplicitNonce.Length + nonce_explicit_length];
+            Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length);
+            Array.Copy(ciphertext, offset, nonce, decryptImplicitNonce.Length, nonce_explicit_length);
+
+            int ciphertextOffset = offset + nonce_explicit_length;
+            int ciphertextLength = len - nonce_explicit_length;
+            int plaintextLength = decryptCipher.GetOutputSize(ciphertextLength);
+
+            byte[] output = new byte[plaintextLength];
+            int outputPos = 0;
+
+            byte[] additionalData = GetAdditionalData(seqNo, type, plaintextLength);
+            AeadParameters parameters = new AeadParameters(null, 8 * macSize, nonce, additionalData);
+
+            try
+            {
+                decryptCipher.Init(false, parameters);
+                outputPos += decryptCipher.ProcessBytes(ciphertext, ciphertextOffset, ciphertextLength, output, outputPos);
+                outputPos += decryptCipher.DoFinal(output, outputPos);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.bad_record_mac, e);
+            }
+
+            if (outputPos != output.Length)
+            {
+                // NOTE: Existing AEAD cipher implementations all give exact output lengths
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            return output;
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual byte[] GetAdditionalData(long seqNo, byte type, int len)
+        {
+            /*
+             * additional_data = seq_num + TLSCompressed.type + TLSCompressed.version +
+             * TLSCompressed.length
+             */
+
+            byte[] additional_data = new byte[13];
+            TlsUtilities.WriteUint64(seqNo, additional_data, 0);
+            TlsUtilities.WriteUint8(type, additional_data, 8);
+            TlsUtilities.WriteVersion(context.ServerVersion, additional_data, 9);
+            TlsUtilities.WriteUint16(len, additional_data, 11);
+
+            return additional_data;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsAgreementCredentials.cs b/crypto/src/crypto/tls/TlsAgreementCredentials.cs
index 46ee4f90e..7c64072e8 100644
--- a/crypto/src/crypto/tls/TlsAgreementCredentials.cs
+++ b/crypto/src/crypto/tls/TlsAgreementCredentials.cs
@@ -3,9 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public interface TlsAgreementCredentials : TlsCredentials
-	{
-		/// <exception cref="IOException"></exception>
-		byte[] GenerateAgreement(AsymmetricKeyParameter serverPublicKey);
-	}
+    public interface TlsAgreementCredentials
+        :   TlsCredentials
+    {
+        /// <exception cref="IOException"></exception>
+        byte[] GenerateAgreement(AsymmetricKeyParameter peerPublicKey);
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsAuthentication.cs b/crypto/src/crypto/tls/TlsAuthentication.cs
new file mode 100644
index 000000000..9aea5e449
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsAuthentication.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsAuthentication
+	{
+		/// <summary>
+		/// Called by the protocol handler to report the server certificate.
+		/// </summary>
+		/// <remarks>
+		/// This method is responsible for certificate verification and validation
+		/// </remarks>
+		/// <param name="serverCertificate">The server <see cref="Certificate"/> received</param>
+		/// <exception cref="IOException"></exception>
+		void NotifyServerCertificate(Certificate serverCertificate);
+
+		/// <summary>
+		/// Return client credentials in response to server's certificate request
+		/// </summary>
+		/// <param name="certificateRequest">
+		/// A <see cref="CertificateRequest"/> containing server certificate request details
+		/// </param>
+		/// <returns>
+		/// A <see cref="TlsCredentials"/> to be used for client authentication
+		/// (or <c>null</c> for no client authentication)
+		/// </returns>
+		/// <exception cref="IOException"></exception>
+		TlsCredentials GetClientCredentials(CertificateRequest certificateRequest);
+	}
+}
diff --git a/crypto/src/crypto/tls/TlsBlockCipher.cs b/crypto/src/crypto/tls/TlsBlockCipher.cs
index ef7be1913..82c0318b2 100644
--- a/crypto/src/crypto/tls/TlsBlockCipher.cs
+++ b/crypto/src/crypto/tls/TlsBlockCipher.cs
@@ -1,248 +1,378 @@
 using System;
 using System.IO;
 
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// A generic TLS 1.0 block cipher. This can be used for AES or 3DES for example.
-	/// </summary>
-	public class TlsBlockCipher
-        : TlsCipher
-	{
-		protected TlsClientContext context;
-
-        protected IBlockCipher encryptCipher;
-        protected IBlockCipher decryptCipher;
-
-        protected TlsMac wMac;
-        protected TlsMac rMac;
-
-		public virtual TlsMac WriteMac
-		{
-            get { return wMac; }
-		}
-
-		public virtual TlsMac ReadMac
-		{
-            get { return rMac; }
-		}
-
-		public TlsBlockCipher(TlsClientContext context, IBlockCipher encryptCipher,
-			IBlockCipher decryptCipher, IDigest writeDigest, IDigest readDigest, int cipherKeySize)
-		{
-			this.context = context;
-			this.encryptCipher = encryptCipher;
-			this.decryptCipher = decryptCipher;
-
-			int prfSize = (2 * cipherKeySize) + writeDigest.GetDigestSize()
-				+ readDigest.GetDigestSize() + encryptCipher.GetBlockSize()
-				+ decryptCipher.GetBlockSize();
-
-			SecurityParameters securityParameters = context.SecurityParameters;
-
-			byte[] keyBlock = TlsUtilities.PRF(securityParameters.masterSecret, "key expansion",
-				TlsUtilities.Concat(securityParameters.serverRandom, securityParameters.clientRandom),
-				prfSize);
-
-			int offset = 0;
-
-			// Init MACs
-			wMac = CreateTlsMac(writeDigest, keyBlock, ref offset);
-            rMac = CreateTlsMac(readDigest, keyBlock, ref offset);
-
-			// Build keys
-			KeyParameter encryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize);
-			KeyParameter decryptKey = CreateKeyParameter(keyBlock, ref offset, cipherKeySize);
-
-			// Add IVs
-			ParametersWithIV encryptParams = CreateParametersWithIV(encryptKey,
-				keyBlock, ref offset, encryptCipher.GetBlockSize());
-			ParametersWithIV decryptParams = CreateParametersWithIV(decryptKey,
-				keyBlock, ref offset, decryptCipher.GetBlockSize());
-
-			if (offset != prfSize)
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-
-			// Init Ciphers
-			encryptCipher.Init(true, encryptParams);
-			decryptCipher.Init(false, decryptParams);
-		}
-
-        protected virtual TlsMac CreateTlsMac(IDigest digest, byte[] buf, ref int off)
-		{
-			int len = digest.GetDigestSize();
-			TlsMac mac = new TlsMac(digest, buf, off, len);
-			off += len;
-			return mac;
-		}
-
-        protected virtual KeyParameter CreateKeyParameter(byte[] buf, ref int off, int len)
-		{
-			KeyParameter key = new KeyParameter(buf, off, len);
-			off += len;
-			return key;
-		}
-
-        protected virtual ParametersWithIV CreateParametersWithIV(KeyParameter key,
-			byte[] buf, ref int off, int len)
-		{
-			ParametersWithIV ivParams = new ParametersWithIV(key, buf, off, len);
-			off += len;
-			return ivParams;
-		}
-
-		public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len)
-		{
-			int blocksize = encryptCipher.GetBlockSize();
-
-			// Add a random number of extra blocks worth of padding
-            int minPaddingSize = blocksize - ((len + wMac.Size + 1) % blocksize);
-			int maxExtraPadBlocks = (255 - minPaddingSize) / blocksize;
-			int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks);
-			int paddingsize = minPaddingSize + (actualExtraPadBlocks * blocksize);
-
-            int totalsize = len + wMac.Size + paddingsize + 1;
-			byte[] outbuf = new byte[totalsize];
-			Array.Copy(plaintext, offset, outbuf, 0, len);
-            byte[] mac = wMac.CalculateMac(type, plaintext, offset, len);
-			Array.Copy(mac, 0, outbuf, len, mac.Length);
-			int paddoffset = len + mac.Length;
-			for (int i = 0; i <= paddingsize; i++)
-			{
-				outbuf[i + paddoffset] = (byte)paddingsize;
-			}
-			for (int i = 0; i < totalsize; i += blocksize)
-			{
-				encryptCipher.ProcessBlock(outbuf, i, outbuf, i);
-			}
-			return outbuf;
-		}
-
-        public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len)
-		{
-			// TODO TLS 1.1 (RFC 4346) introduces an explicit IV
-
-            int minLength = rMac.Size + 1;
-			int blocksize = decryptCipher.GetBlockSize();
-			bool decrypterror = false;
-
-			/*
-			* ciphertext must be at least (macsize + 1) bytes long
-			*/
-			if (len < minLength)
-			{
-				throw new TlsFatalAlert(AlertDescription.decode_error);
-			}
-
-			/*
-			* ciphertext must be a multiple of blocksize
-			*/
-			if (len % blocksize != 0)
-			{
-				throw new TlsFatalAlert(AlertDescription.decryption_failed);
-			}
-
-			/*
-			* Decrypt all the ciphertext using the blockcipher
-			*/
-			for (int i = 0; i < len; i += blocksize)
-			{
-				decryptCipher.ProcessBlock(ciphertext, i + offset, ciphertext, i + offset);
-			}
-
-			/*
-			* Check if padding is correct
-			*/
-			int lastByteOffset = offset + len - 1;
-
-			byte paddingsizebyte = ciphertext[lastByteOffset];
-
-			int paddingsize = paddingsizebyte;
-
-			int maxPaddingSize = len - minLength;
-			if (paddingsize > maxPaddingSize)
-			{
-				decrypterror = true;
-				paddingsize = 0;
-			}
-			else
-			{
-				/*
-				* Now, check all the padding-bytes (constant-time comparison).
-				*/
-				byte diff = 0;
-				for (int i = lastByteOffset - paddingsize; i < lastByteOffset; ++i)
-				{
-					diff |= (byte)(ciphertext[i] ^ paddingsizebyte);
-				}
-				if (diff != 0)
-				{
-					/* Wrong padding */
-					decrypterror = true;
-					paddingsize = 0;
-				}
-			}
-
-			/*
-			* We now don't care if padding verification has failed or not, we will calculate
-			* the mac to give an attacker no kind of timing profile he can use to find out if
-			* mac verification failed or padding verification failed.
-			*/
-			int plaintextlength = len - minLength - paddingsize;
-            byte[] calculatedMac = rMac.CalculateMac(type, ciphertext, offset, plaintextlength);
-
-			/*
-			* Check all bytes in the mac (constant-time comparison).
-			*/
-			byte[] decryptedMac = new byte[calculatedMac.Length];
-			Array.Copy(ciphertext, offset + plaintextlength, decryptedMac, 0, calculatedMac.Length);
-
-			if (!Arrays.ConstantTimeAreEqual(calculatedMac, decryptedMac))
-			{
-				decrypterror = true;
-			}
-
-			/*
-			* Now, it is safe to fail.
-			*/
-			if (decrypterror)
-			{
-				throw new TlsFatalAlert(AlertDescription.bad_record_mac);
-			}
-
-			byte[] plaintext = new byte[plaintextlength];
-			Array.Copy(ciphertext, offset, plaintext, 0, plaintextlength);
-			return plaintext;
-		}
-
-		protected virtual int ChooseExtraPadBlocks(SecureRandom r, int max)
-		{
-//			return r.NextInt(max + 1);
-
-			uint x = (uint)r.NextInt();
-			int n = LowestBitSet(x);
-			return System.Math.Min(n, max);
-		}
-
-        private int LowestBitSet(uint x)
-		{
-			if (x == 0)
-			{
-				return 32;
-			}
-
-			int n = 0;
-			while ((x & 1) == 0)
-			{
-				++n;
-				x >>= 1;
-			}
-			return n;
-		}
-	}
+    /// <summary>
+    /// A generic TLS 1.0-1.2 / SSLv3 block cipher. This can be used for AES or 3DES for example.
+    /// </summary>
+    public class TlsBlockCipher
+        :   TlsCipher
+    {
+        protected readonly TlsContext context;
+        protected readonly byte[] randomData;
+        protected readonly bool useExplicitIV;
+        protected readonly bool encryptThenMac;
+
+        protected readonly IBlockCipher encryptCipher;
+        protected readonly IBlockCipher decryptCipher;
+
+        protected readonly TlsMac mWriteMac;
+        protected readonly TlsMac mReadMac;
+
+        public virtual TlsMac WriteMac
+        {
+            get { return mWriteMac; }
+        }
+
+        public virtual TlsMac ReadMac
+        {
+            get { return mReadMac; }
+        }
+
+        /// <exception cref="IOException"></exception>
+        public TlsBlockCipher(TlsContext context, IBlockCipher clientWriteCipher, IBlockCipher serverWriteCipher,
+            IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize)
+        {
+            this.context = context;
+
+            this.randomData = new byte[256];
+            context.NonceRandomGenerator.NextBytes(randomData);
+
+            this.useExplicitIV = TlsUtilities.IsTlsV11(context);
+            this.encryptThenMac = context.SecurityParameters.encryptThenMac;
+
+            int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize()
+                + serverWriteDigest.GetDigestSize();
+
+            // From TLS 1.1 onwards, block ciphers don't need client_write_IV
+            if (!useExplicitIV)
+            {
+                key_block_size += clientWriteCipher.GetBlockSize() + serverWriteCipher.GetBlockSize();
+            }
+
+            byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+            int offset = 0;
+
+            TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+                clientWriteDigest.GetDigestSize());
+            offset += clientWriteDigest.GetDigestSize();
+            TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+                serverWriteDigest.GetDigestSize());
+            offset += serverWriteDigest.GetDigestSize();
+
+            KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+            offset += cipherKeySize;
+            KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);
+            offset += cipherKeySize;
+
+            byte[] client_write_IV, server_write_IV;
+            if (useExplicitIV)
+            {
+                client_write_IV = new byte[clientWriteCipher.GetBlockSize()];
+                server_write_IV = new byte[serverWriteCipher.GetBlockSize()];
+            }
+            else
+            {
+                client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + clientWriteCipher.GetBlockSize());
+                offset += clientWriteCipher.GetBlockSize();
+                server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + serverWriteCipher.GetBlockSize());
+                offset += serverWriteCipher.GetBlockSize();
+            }
+
+            if (offset != key_block_size)
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            ICipherParameters encryptParams, decryptParams;
+            if (context.IsServer)
+            {
+                this.mWriteMac = serverWriteMac;
+                this.mReadMac = clientWriteMac;
+                this.encryptCipher = serverWriteCipher;
+                this.decryptCipher = clientWriteCipher;
+                encryptParams = new ParametersWithIV(server_write_key, server_write_IV);
+                decryptParams = new ParametersWithIV(client_write_key, client_write_IV);
+            }
+            else
+            {
+                this.mWriteMac = clientWriteMac;
+                this.mReadMac = serverWriteMac;
+                this.encryptCipher = clientWriteCipher;
+                this.decryptCipher = serverWriteCipher;
+                encryptParams = new ParametersWithIV(client_write_key, client_write_IV);
+                decryptParams = new ParametersWithIV(server_write_key, server_write_IV);
+            }
+
+            this.encryptCipher.Init(true, encryptParams);
+            this.decryptCipher.Init(false, decryptParams);
+        }
+
+        public virtual int GetPlaintextLimit(int ciphertextLimit)
+        {
+            int blockSize = encryptCipher.GetBlockSize();
+            int macSize = mWriteMac.Size;
+
+            int plaintextLimit = ciphertextLimit;
+
+            // An explicit IV consumes 1 block
+            if (useExplicitIV)
+            {
+                plaintextLimit -= blockSize;
+            }
+
+            // Leave room for the MAC, and require block-alignment
+            if (encryptThenMac)
+            {
+                plaintextLimit -= macSize;
+                plaintextLimit -= plaintextLimit % blockSize;
+            }
+            else
+            {
+                plaintextLimit -= plaintextLimit % blockSize;
+                plaintextLimit -= macSize;
+            }
+
+            // Minimum 1 byte of padding
+            --plaintextLimit;
+
+            return plaintextLimit;
+        }
+
+        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+        {
+            int blockSize = encryptCipher.GetBlockSize();
+            int macSize = mWriteMac.Size;
+
+            ProtocolVersion version = context.ServerVersion;
+
+            int enc_input_length = len;
+            if (!encryptThenMac)
+            {
+                enc_input_length += macSize;
+            }
+
+            int padding_length = blockSize - 1 - (enc_input_length % blockSize);
+
+            // TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though)
+            if (!version.IsDtls && !version.IsSsl)
+            {
+                // Add a random number of extra blocks worth of padding
+                int maxExtraPadBlocks = (255 - padding_length) / blockSize;
+                int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks);
+                padding_length += actualExtraPadBlocks * blockSize;
+            }
+
+            int totalSize = len + macSize + padding_length + 1;
+            if (useExplicitIV)
+            {
+                totalSize += blockSize;
+            }
+
+            byte[] outBuf = new byte[totalSize];
+            int outOff = 0;
+
+            if (useExplicitIV)
+            {
+                byte[] explicitIV = new byte[blockSize];
+                context.NonceRandomGenerator.NextBytes(explicitIV);
+
+                encryptCipher.Init(true, new ParametersWithIV(null, explicitIV));
+
+                Array.Copy(explicitIV, 0, outBuf, outOff, blockSize);
+                outOff += blockSize;
+            }
+
+            int blocks_start = outOff;
+
+            Array.Copy(plaintext, offset, outBuf, outOff, len);
+            outOff += len;
+
+            if (!encryptThenMac)
+            {
+                byte[] mac = mWriteMac.CalculateMac(seqNo, type, plaintext, offset, len);
+                Array.Copy(mac, 0, outBuf, outOff, mac.Length);
+                outOff += mac.Length;
+            }
+
+            for (int i = 0; i <= padding_length; i++)
+            {
+                outBuf[outOff++] = (byte)padding_length;
+            }
+
+            for (int i = blocks_start; i < outOff; i += blockSize)
+            {
+                encryptCipher.ProcessBlock(outBuf, i, outBuf, i);
+            }
+
+            if (encryptThenMac)
+            {
+                byte[] mac = mWriteMac.CalculateMac(seqNo, type, outBuf, 0, outOff);
+                Array.Copy(mac, 0, outBuf, outOff, mac.Length);
+                outOff += mac.Length;
+            }
+
+    //        assert outBuf.length == outOff;
+
+            return outBuf;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+        {
+            int blockSize = decryptCipher.GetBlockSize();
+            int macSize = mReadMac.Size;
+
+            int minLen = blockSize;
+            if (encryptThenMac)
+            {
+                minLen += macSize;
+            }
+            else
+            {
+                minLen = System.Math.Max(minLen, macSize + 1);
+            }
+
+            if (useExplicitIV)
+            {
+                minLen += blockSize;
+            }
+
+            if (len < minLen)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int blocks_length = len;
+            if (encryptThenMac)
+            {
+                blocks_length -= macSize;
+            }
+
+            if (blocks_length % blockSize != 0)
+                throw new TlsFatalAlert(AlertDescription.decryption_failed);
+
+            if (encryptThenMac)
+            {
+                int end = offset + len;
+                byte[] receivedMac = Arrays.CopyOfRange(ciphertext, end - macSize, end);
+                byte[] calculatedMac = mReadMac.CalculateMac(seqNo, type, ciphertext, offset, len - macSize);
+
+                bool badMac = !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac);
+
+                if (badMac)
+                    throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+            }
+
+            if (useExplicitIV)
+            {
+                decryptCipher.Init(false, new ParametersWithIV(null, ciphertext, offset, blockSize));
+
+                offset += blockSize;
+                blocks_length -= blockSize;
+            }
+
+            for (int i = 0; i < blocks_length; i += blockSize)
+            {
+                decryptCipher.ProcessBlock(ciphertext, offset + i, ciphertext, offset + i);
+            }
+
+            // If there's anything wrong with the padding, this will return zero
+            int totalPad = CheckPaddingConstantTime(ciphertext, offset, blocks_length, blockSize, encryptThenMac ? 0 : macSize);
+
+            int dec_output_length = blocks_length - totalPad;
+
+            if (!encryptThenMac)
+            {
+                dec_output_length -= macSize;
+                int macInputLen = dec_output_length;
+                int macOff = offset + macInputLen;
+                byte[] receivedMac = Arrays.CopyOfRange(ciphertext, macOff, macOff + macSize);
+                byte[] calculatedMac = mReadMac.CalculateMacConstantTime(seqNo, type, ciphertext, offset, macInputLen,
+                    blocks_length - macSize, randomData);
+
+                bool badMac = !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac);
+
+                if (badMac || totalPad == 0)
+                {
+                    throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+                }
+            }
+
+            return Arrays.CopyOfRange(ciphertext, offset, offset + dec_output_length);
+        }
+
+        protected virtual int CheckPaddingConstantTime(byte[] buf, int off, int len, int blockSize, int macSize)
+        {
+            int end = off + len;
+            byte lastByte = buf[end - 1];
+            int padlen = lastByte & 0xff;
+            int totalPad = padlen + 1;
+
+            int dummyIndex = 0;
+            byte padDiff = 0;
+
+            if ((TlsUtilities.IsSsl(context) && totalPad > blockSize) || (macSize + totalPad > len))
+            {
+                totalPad = 0;
+            }
+            else
+            {
+                int padPos = end - totalPad;
+                do
+                {
+                    padDiff |= (byte)(buf[padPos++] ^ lastByte);
+                }
+                while (padPos < end);
+
+                dummyIndex = totalPad;
+
+                if (padDiff != 0)
+                {
+                    totalPad = 0;
+                }
+            }
+
+            // Run some extra dummy checks so the number of checks is always constant
+            {
+                byte[] dummyPad = randomData;
+                while (dummyIndex < 256)
+                {
+                    padDiff |= (byte)(dummyPad[dummyIndex++] ^ lastByte);
+                }
+                // Ensure the above loop is not eliminated
+                dummyPad[0] ^= padDiff;
+            }
+
+            return totalPad;
+        }
+
+        protected virtual int ChooseExtraPadBlocks(SecureRandom r, int max)
+        {
+            // return r.NextInt(max + 1);
+
+            int x = r.NextInt();
+            int n = LowestBitSet(x);
+            return System.Math.Min(n, max);
+        }
+
+        protected virtual int LowestBitSet(int x)
+        {
+            if (x == 0)
+                return 32;
+
+            uint ux = (uint)x;
+            int n = 0;
+            while ((ux & 1U) == 0)
+            {
+                ++n;
+                ux >>= 1;
+            }
+            return n;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsCipher.cs b/crypto/src/crypto/tls/TlsCipher.cs
index 22c769d82..7bd8573ac 100644
--- a/crypto/src/crypto/tls/TlsCipher.cs
+++ b/crypto/src/crypto/tls/TlsCipher.cs
@@ -3,12 +3,14 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public interface TlsCipher
-	{
-		/// <exception cref="IOException"></exception>
-		byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len);
+    public interface TlsCipher
+    {
+        int GetPlaintextLimit(int ciphertextLimit);
 
-		/// <exception cref="IOException"></exception>
-		byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len);
-	}
+        /// <exception cref="IOException"></exception>
+        byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len);
+
+        /// <exception cref="IOException"></exception>
+        byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len);
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsCipherFactory.cs b/crypto/src/crypto/tls/TlsCipherFactory.cs
index 0756603f4..4e1fe0eb9 100644
--- a/crypto/src/crypto/tls/TlsCipherFactory.cs
+++ b/crypto/src/crypto/tls/TlsCipherFactory.cs
@@ -3,10 +3,9 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public interface TlsCipherFactory
-	{
-		/// <exception cref="IOException"></exception>
-		TlsCipher CreateCipher(TlsClientContext context, EncryptionAlgorithm encryptionAlgorithm,
-			DigestAlgorithm digestAlgorithm);
-	}
+    public interface TlsCipherFactory
+    {
+        /// <exception cref="IOException"></exception>
+        TlsCipher CreateCipher(TlsContext context, int encryptionAlgorithm, int macAlgorithm);
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsClient.cs b/crypto/src/crypto/tls/TlsClient.cs
index eceaa3cd3..cd5dfad13 100644
--- a/crypto/src/crypto/tls/TlsClient.cs
+++ b/crypto/src/crypto/tls/TlsClient.cs
@@ -4,60 +4,74 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public interface TlsClient
-	{
-		/// <summary>
-		/// Called at the start of a new TLS session, before any other methods.
-		/// </summary>
-		/// <param name="context">
-		/// A <see cref="TlsProtocolHandler"/>
-		/// </param>
-		void Init(TlsClientContext context);
-
-		/// <summary>
-		/// Get the list of cipher suites that this client supports.
-		/// </summary>
-		/// <returns>
-        /// An array of <see cref="CipherSuite"/>, each specifying a supported cipher suite.
-		/// </returns>
-		CipherSuite[] GetCipherSuites();
+    public interface TlsClient
+        :   TlsPeer
+    {
+        /// <summary>
+        /// Called at the start of a new TLS session, before any other methods.
+        /// </summary>
+        /// <param name="context">
+        /// A <see cref="TlsProtocolHandler"/>
+        /// </param>
+        void Init(TlsClientContext context);
+
+        /// <summary>Return the session this client wants to resume, if any.</summary>
+        /// <remarks>Note that the peer's certificate chain for the session (if any) may need to be periodically revalidated.</remarks>
+        /// <returns>
+        /// A <see cref="TlsSession"/> representing the resumable session to be used for this connection,
+        /// or null to use a new session.
+        /// </returns>
+        TlsSession GetSessionToResume();
+
+        ProtocolVersion ClientHelloRecordLayerVersion { get; }
+
+        ProtocolVersion ClientVersion { get; }
+
+        /// <summary>
+        /// Get the list of cipher suites that this client supports.
+        /// </summary>
+        /// <returns>
+        /// An array of <see cref="CipherSuite"/> values, each specifying a supported cipher suite.
+        /// </returns>
+        int[] GetCipherSuites();
 
         /// <summary>
         /// Get the list of compression methods that this client supports.
         /// </summary>
         /// <returns>
-        /// An array of <see cref="CompressionMethod"/>, each specifying a supported compression method.
+        /// An array of <see cref="CompressionMethod"/> values, each specifying a supported compression method.
+        /// </returns>
+        byte[] GetCompressionMethods();
+
+        /// <summary>
+        /// Get the (optional) table of client extensions to be included in (extended) client hello.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="IDictionary"/> (Int32 -> byte[]). May be null.
         /// </returns>
-        CompressionMethod[] GetCompressionMethods();
-
-		/// <summary>
-		/// Get the (optional) table of client extensions to be included in (extended) client hello.
-		/// </summary>
-		/// <returns>
-        /// A <see cref="IDictionary"/> (<see cref="ExtensionType"/> -> byte[]). May be null.
-		/// </returns>
-		/// <exception cref="IOException"></exception>
-		IDictionary GetClientExtensions();
-
-		/// <summary>
-		/// Reports the session ID once it has been determined.
-		/// </summary>
-		/// <param name="sessionID">
-		/// A <see cref="System.Byte"/>
-		/// </param>
-		void NotifySessionID(byte[] sessionID);
-
-		/// <summary>
-		/// Report the cipher suite that was selected by the server.
-		/// </summary>
-		/// <remarks>
-		/// The protocol handler validates this value against the offered cipher suites
-		/// <seealso cref="GetCipherSuites"/>
-		/// </remarks>
-		/// <param name="selectedCipherSuite">
-		/// A <see cref="CipherSuite"/>
-		/// </param>
-		void NotifySelectedCipherSuite(CipherSuite selectedCipherSuite);
+        /// <exception cref="IOException"></exception>
+        IDictionary GetClientExtensions();
+
+        /// <exception cref="IOException"></exception>
+        void NotifyServerVersion(ProtocolVersion selectedVersion);
+
+        /// <summary>
+        /// Notifies the client of the session_id sent in the ServerHello.
+        /// </summary>
+        /// <param name="sessionID">An array of <see cref="System.Byte"/></param>
+        void NotifySessionID(byte[] sessionID);
+
+        /// <summary>
+        /// Report the cipher suite that was selected by the server.
+        /// </summary>
+        /// <remarks>
+        /// The protocol handler validates this value against the offered cipher suites
+        /// <seealso cref="GetCipherSuites"/>
+        /// </remarks>
+        /// <param name="selectedCipherSuite">
+        /// A <see cref="CipherSuite"/>
+        /// </param>
+        void NotifySelectedCipherSuite(int selectedCipherSuite);
 
         /// <summary>
         /// Report the compression method that was selected by the server.
@@ -69,61 +83,52 @@ namespace Org.BouncyCastle.Crypto.Tls
         /// <param name="selectedCompressionMethod">
         /// A <see cref="CompressionMethod"/>
         /// </param>
-        void NotifySelectedCompressionMethod(CompressionMethod selectedCompressionMethod);
-
-		/// <summary>
-		/// Report whether the server supports secure renegotiation
-		/// </summary>
-		/// <remarks>
-		/// The protocol handler automatically processes the relevant extensions
-		/// </remarks>
-		/// <param name="secureRenegotiation">
-		/// A <see cref="System.Boolean"/>, true if the server supports secure renegotiation
-		/// </param>
-		/// <exception cref="IOException"></exception>
-		void NotifySecureRenegotiation(bool secureRenegotiation);
-
-		/// <summary>
-		/// Report the extensions from an extended server hello.
-		/// </summary>
-		/// <remarks>
-		/// Will only be called if we returned a non-null result from <see cref="GetClientExtensions"/>.
-		/// </remarks>
-		/// <param name="serverExtensions">
-        /// A <see cref="IDictionary"/>  (<see cref="ExtensionType"/> -> byte[])
-		/// </param>
-		void ProcessServerExtensions(IDictionary serverExtensions);
-
-		/// <summary>
-		/// Return an implementation of <see cref="TlsKeyExchange"/> to negotiate the key exchange
-		/// part of the protocol.
-		/// </summary>
-		/// <returns>
-		/// A <see cref="TlsKeyExchange"/>
-		/// </returns>
-		/// <exception cref="IOException"/>
-		TlsKeyExchange GetKeyExchange();
-
-		/// <summary>
-		/// Return an implementation of <see cref="TlsAuthentication"/> to handle authentication
-		/// part of the protocol.
-		/// </summary>
-		/// <exception cref="IOException"/>
-		TlsAuthentication GetAuthentication();
-
-		/// <summary>
-		/// Return an implementation of <see cref="TlsCompression"/> to handle record compression.
-		/// </summary>
-		/// <exception cref="IOException"/>
-		TlsCompression GetCompression();
-
-		/// <summary>
-		/// Return an implementation of <see cref="TlsCipher"/> to use for encryption/decryption.
-		/// </summary>
-		/// <returns>
-		/// A <see cref="TlsCipher"/>
-		/// </returns>
-		/// <exception cref="IOException"/>
-		TlsCipher GetCipher();
-	}
+        void NotifySelectedCompressionMethod(byte selectedCompressionMethod);
+
+        /// <summary>
+        /// Report the extensions from an extended server hello.
+        /// </summary>
+        /// <remarks>
+        /// Will only be called if we returned a non-null result from <see cref="GetClientExtensions"/>.
+        /// </remarks>
+        /// <param name="serverExtensions">
+        /// A <see cref="IDictionary"/>  (Int32 -> byte[])
+        /// </param>
+        void ProcessServerExtensions(IDictionary serverExtensions);
+
+        /// <param name="serverSupplementalData">A <see cref="IList">list</see> of <see cref="SupplementalDataEntry"/></param>
+        /// <exception cref="IOException"/>
+        void ProcessServerSupplementalData(IList serverSupplementalData);
+
+        /// <summary>
+        /// Return an implementation of <see cref="TlsKeyExchange"/> to negotiate the key exchange
+        /// part of the protocol.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="TlsKeyExchange"/>
+        /// </returns>
+        /// <exception cref="IOException"/>
+        TlsKeyExchange GetKeyExchange();
+
+        /// <summary>
+        /// Return an implementation of <see cref="TlsAuthentication"/> to handle authentication
+        /// part of the protocol.
+        /// </summary>
+        /// <exception cref="IOException"/>
+        TlsAuthentication GetAuthentication();
+
+        /// <returns>A <see cref="IList">list</see> of <see cref="SupplementalDataEntry"/></returns>
+        /// <exception cref="IOException"/>
+        IList GetClientSupplementalData();
+
+        /// <summary>RFC 5077 3.3. NewSessionTicket Handshake Message</summary>
+        /// <remarks>
+        /// This method will be called (only) when a NewSessionTicket handshake message is received. The
+        /// ticket is opaque to the client and clients MUST NOT examine the ticket under the assumption
+        /// that it complies with e.g. <i>RFC 5077 4. Recommended Ticket Construction</i>.
+        /// </remarks>
+        /// <param name="newSessionTicket">The <see cref="NewSessionTicket">ticket</see></param>
+        /// <exception cref="IOException"/>
+        void NotifyNewSessionTicket(NewSessionTicket newSessionTicket);
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsClientContext.cs b/crypto/src/crypto/tls/TlsClientContext.cs
index dbb10aa76..b077d0aaf 100644
--- a/crypto/src/crypto/tls/TlsClientContext.cs
+++ b/crypto/src/crypto/tls/TlsClientContext.cs
@@ -4,12 +4,8 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public interface TlsClientContext
-	{
-		SecureRandom SecureRandom { get; }
-
-		SecurityParameters SecurityParameters { get; }
-
-		object UserObject { get; set; }
-	}
+    public interface TlsClientContext
+        :   TlsContext
+    {
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsClientContextImpl.cs b/crypto/src/crypto/tls/TlsClientContextImpl.cs
index 9d5dee232..674d68937 100644
--- a/crypto/src/crypto/tls/TlsClientContextImpl.cs
+++ b/crypto/src/crypto/tls/TlsClientContextImpl.cs
@@ -4,34 +4,17 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsClientContextImpl
-		: TlsClientContext
-	{
-		private readonly SecureRandom secureRandom;
-		private readonly SecurityParameters securityParameters;
+    internal class TlsClientContextImpl
+        :   AbstractTlsContext, TlsClientContext
+    {
+        internal TlsClientContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
+            :   base(secureRandom, securityParameters)
+        {
+        }
 
-		private object userObject = null;
-
-		internal TlsClientContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
-		{
-			this.secureRandom = secureRandom;
-			this.securityParameters = securityParameters;
-		}
-
-		public virtual SecureRandom SecureRandom
-		{
-			get { return secureRandom; }
-		}
-
-		public virtual SecurityParameters SecurityParameters
-		{
-			get { return securityParameters; }
-		}
-
-		public virtual object UserObject
-		{
-			get { return userObject; }
-			set { this.userObject = value; }
-		}
-	}
+        public override bool IsServer
+        {
+            get { return false; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
new file mode 100644
index 000000000..e48c92d30
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -0,0 +1,861 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class TlsClientProtocol
+        :   TlsProtocol
+    {
+        protected TlsClient mTlsClient = null;
+        internal TlsClientContextImpl mTlsClientContext = null;
+
+        protected byte[] mSelectedSessionID = null;
+
+        protected TlsKeyExchange mKeyExchange = null;
+        protected TlsAuthentication mAuthentication = null;
+
+        protected CertificateStatus mCertificateStatus = null;
+        protected CertificateRequest mCertificateRequest = null;
+
+        public TlsClientProtocol(Stream stream, SecureRandom secureRandom)
+            :   base(stream, secureRandom)
+        {
+        }
+
+        public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom)
+            :   base(input, output, secureRandom)
+        {
+        }
+
+        /**
+         * Initiates a TLS handshake in the role of client
+         *
+         * @param tlsClient The {@link TlsClient} to use for the handshake.
+         * @throws IOException If handshake was not successful.
+         */
+        public virtual void Connect(TlsClient tlsClient)
+        {
+            if (tlsClient == null)
+                throw new ArgumentNullException("tlsClient");
+            if (this.mTlsClient != null)
+                throw new InvalidOperationException("'Connect' can only be called once");
+
+            this.mTlsClient = tlsClient;
+
+            this.mSecurityParameters = new SecurityParameters();
+            this.mSecurityParameters.entity = ConnectionEnd.client;
+
+            this.mTlsClientContext = new TlsClientContextImpl(mSecureRandom, mSecurityParameters);
+
+            this.mSecurityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(),
+                mTlsClientContext.NonceRandomGenerator);
+
+            this.mTlsClient.Init(mTlsClientContext);
+            this.mRecordStream.Init(mTlsClientContext);
+
+            TlsSession sessionToResume = tlsClient.GetSessionToResume();
+            if (sessionToResume != null)
+            {
+                SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
+                if (sessionParameters != null)
+                {
+                    this.mTlsSession = sessionToResume;
+                    this.mSessionParameters = sessionParameters;
+                }
+            }
+
+            SendClientHelloMessage();
+            this.mConnectionState = CS_CLIENT_HELLO;
+
+            CompleteHandshake();
+        }
+
+        protected override void CleanupHandshake()
+        {
+            base.CleanupHandshake();
+
+            this.mSelectedSessionID = null;
+            this.mKeyExchange = null;
+            this.mAuthentication = null;
+            this.mCertificateStatus = null;
+            this.mCertificateRequest = null;
+        }
+
+        protected override TlsContext Context
+        {
+            get { return mTlsClientContext; }
+        }
+
+        internal override AbstractTlsContext ContextAdmin
+        {
+            get { return mTlsClientContext; }
+        }
+
+        protected override TlsPeer Peer
+        {
+            get { return mTlsClient; }
+        }
+
+        protected override void HandleHandshakeMessage(byte type, byte[] data)
+        {
+            MemoryStream buf = new MemoryStream(data, false);
+
+            if (this.mResumedSession)
+            {
+                if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+                ProcessFinishedMessage(buf);
+                this.mConnectionState = CS_SERVER_FINISHED;
+
+                SendFinishedMessage();
+                this.mConnectionState = CS_CLIENT_FINISHED;
+                this.mConnectionState = CS_END;
+
+                return;
+            }
+
+            switch (type)
+            {
+            case HandshakeType.certificate:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_HELLO:
+                case CS_SERVER_SUPPLEMENTAL_DATA:
+                {
+                    if (this.mConnectionState == CS_SERVER_HELLO)
+                    {
+                        HandleSupplementalData(null);
+                    }
+
+                    // Parse the Certificate message and Send to cipher suite
+
+                    this.mPeerCertificate = Certificate.Parse(buf);
+
+                    AssertEmpty(buf);
+
+                    // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+                    if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty)
+                    {
+                        this.mAllowCertificateStatus = false;
+                    }
+
+                    this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate);
+
+                    this.mAuthentication = mTlsClient.GetAuthentication();
+                    this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate);
+
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+
+                this.mConnectionState = CS_SERVER_CERTIFICATE;
+                break;
+            }
+            case HandshakeType.certificate_status:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_CERTIFICATE:
+                {
+                    if (!this.mAllowCertificateStatus)
+                    {
+                        /*
+                         * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
+                         * server MUST have included an extension of type "status_request" with empty
+                         * "extension_data" in the extended server hello..
+                         */
+                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                    }
+
+                    this.mCertificateStatus = CertificateStatus.Parse(buf);
+
+                    AssertEmpty(buf);
+
+                    // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
+
+                    this.mConnectionState = CS_CERTIFICATE_STATUS;
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.finished:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_CLIENT_FINISHED:
+                case CS_SERVER_SESSION_TICKET:
+                {
+                    if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket)
+                    {
+                        /*
+                         * RFC 5077 3.3. This message MUST be sent if the server included a
+                         * SessionTicket extension in the ServerHello.
+                         */
+                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                    }
+
+                    ProcessFinishedMessage(buf);
+                    this.mConnectionState = CS_SERVER_FINISHED;
+                    this.mConnectionState = CS_END;
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.server_hello:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_CLIENT_HELLO:
+                {
+                    ReceiveServerHelloMessage(buf);
+                    this.mConnectionState = CS_SERVER_HELLO;
+
+                    if (this.mSecurityParameters.maxFragmentLength >= 0)
+                    {
+                        int plainTextLimit = 1 << (8 + this.mSecurityParameters.maxFragmentLength);
+                        mRecordStream.SetPlaintextLimit(plainTextLimit);
+                    }
+
+                    this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context,
+                        this.mSecurityParameters.CipherSuite);
+
+                    /*
+                     * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
+                     * verify_data_length has a verify_data_length equal to 12. This includes all
+                     * existing cipher suites.
+                     */
+                    this.mSecurityParameters.verifyDataLength = 12;
+
+                    this.mRecordStream.NotifyHelloComplete();
+
+                    if (this.mResumedSession)
+                    {
+                        this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
+                        this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+                        SendChangeCipherSpecMessage();
+                    }
+                    else
+                    {
+                        InvalidateSession();
+
+                        if (this.mSelectedSessionID.Length > 0)
+                        {
+                            this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
+                        }
+                    }
+
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.supplemental_data:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_HELLO:
+                {
+                    HandleSupplementalData(ReadSupplementalDataMessage(buf));
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.server_hello_done:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_HELLO:
+                case CS_SERVER_SUPPLEMENTAL_DATA:
+                case CS_SERVER_CERTIFICATE:
+                case CS_CERTIFICATE_STATUS:
+                case CS_SERVER_KEY_EXCHANGE:
+                case CS_CERTIFICATE_REQUEST:
+                {
+                    if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
+                    {
+                        HandleSupplementalData(null);
+                    }
+
+                    if (mConnectionState < CS_SERVER_CERTIFICATE)
+                    {
+                        // There was no server certificate message; check it's OK
+                        this.mKeyExchange.SkipServerCredentials();
+                        this.mAuthentication = null;
+                    }
+
+                    if (mConnectionState < CS_SERVER_KEY_EXCHANGE)
+                    {
+                        // There was no server key exchange message; check it's OK
+                        this.mKeyExchange.SkipServerKeyExchange();
+                    }
+
+                    AssertEmpty(buf);
+
+                    this.mConnectionState = CS_SERVER_HELLO_DONE;
+
+                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();
+
+                    IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
+                    if (clientSupplementalData != null)
+                    {
+                        SendSupplementalDataMessage(clientSupplementalData);
+                    }
+                    this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
+
+                    TlsCredentials clientCreds = null;
+                    if (mCertificateRequest == null)
+                    {
+                        this.mKeyExchange.SkipClientCredentials();
+                    }
+                    else
+                    {
+                        clientCreds = this.mAuthentication.GetClientCredentials(mCertificateRequest);
+
+                        if (clientCreds == null)
+                        {
+                            this.mKeyExchange.SkipClientCredentials();
+
+                            /*
+                             * RFC 5246 If no suitable certificate is available, the client MUST Send a
+                             * certificate message containing no certificates.
+                             * 
+                             * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+                             */
+                            SendCertificateMessage(Certificate.EmptyChain);
+                        }
+                        else
+                        {
+                            this.mKeyExchange.ProcessClientCredentials(clientCreds);
+
+                            SendCertificateMessage(clientCreds.Certificate);
+                        }
+                    }
+
+                    this.mConnectionState = CS_CLIENT_CERTIFICATE;
+
+                    /*
+                     * Send the client key exchange message, depending on the key exchange we are using
+                     * in our CipherSuite.
+                     */
+                    SendClientKeyExchangeMessage();
+                    this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
+
+                    EstablishMasterSecret(Context, mKeyExchange);
+                    mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+                    TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
+
+                    if (clientCreds != null && clientCreds is TlsSignerCredentials)
+                    {
+                        TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds;
+
+                        /*
+                         * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+                         */
+                        SignatureAndHashAlgorithm signatureAndHashAlgorithm;
+                        byte[] hash;
+
+                        if (TlsUtilities.IsTlsV12(Context))
+                        {
+                            signatureAndHashAlgorithm = signerCredentials.SignatureAndHashAlgorithm;
+                            if (signatureAndHashAlgorithm == null)
+                                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+                            hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
+                        }
+                        else
+                        {
+                            signatureAndHashAlgorithm = null;
+                            hash = GetCurrentPrfHash(Context, prepareFinishHash, null);
+                        }
+
+                        byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
+                        DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
+                        SendCertificateVerifyMessage(certificateVerify);
+
+                        this.mConnectionState = CS_CERTIFICATE_VERIFY;
+                    }
+
+                    SendChangeCipherSpecMessage();
+                    SendFinishedMessage();
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                }
+
+                this.mConnectionState = CS_CLIENT_FINISHED;
+                break;
+            }
+            case HandshakeType.server_key_exchange:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_HELLO:
+                case CS_SERVER_SUPPLEMENTAL_DATA:
+                case CS_SERVER_CERTIFICATE:
+                case CS_CERTIFICATE_STATUS:
+                {
+                    if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
+                    {
+                        HandleSupplementalData(null);
+                    }
+
+                    if (mConnectionState < CS_SERVER_CERTIFICATE)
+                    {
+                        // There was no server certificate message; check it's OK
+                        this.mKeyExchange.SkipServerCredentials();
+                        this.mAuthentication = null;
+                    }
+
+                    this.mKeyExchange.ProcessServerKeyExchange(buf);
+
+                    AssertEmpty(buf);
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+
+                this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
+                break;
+            }
+            case HandshakeType.certificate_request:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_CERTIFICATE:
+                case CS_CERTIFICATE_STATUS:
+                case CS_SERVER_KEY_EXCHANGE:
+                {
+                    if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE)
+                    {
+                        // There was no server key exchange message; check it's OK
+                        this.mKeyExchange.SkipServerKeyExchange();
+                    }
+
+                    if (this.mAuthentication == null)
+                    {
+                        /*
+                         * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server
+                         * to request client identification.
+                         */
+                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                    }
+
+                    this.mCertificateRequest = CertificateRequest.Parse(Context, buf);
+
+                    AssertEmpty(buf);
+
+                    this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);
+
+                    /*
+                     * TODO Give the client a chance to immediately select the CertificateVerify hash
+                     * algorithm here to avoid tracking the other hash algorithms unnecessarily?
+                     */
+                    TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
+                        this.mCertificateRequest.SupportedSignatureAlgorithms);
+
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+
+                this.mConnectionState = CS_CERTIFICATE_REQUEST;
+                break;
+            }
+            case HandshakeType.session_ticket:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_CLIENT_FINISHED:
+                {
+                    if (!this.mExpectSessionTicket)
+                    {
+                        /*
+                         * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a
+                         * SessionTicket extension in the ServerHello.
+                         */
+                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                    }
+
+                    /*
+                     * RFC 5077 3.4. If the client receives a session ticket from the server, then it
+                     * discards any Session ID that was sent in the ServerHello.
+                     */
+                    InvalidateSession();
+
+                    ReceiveNewSessionTicketMessage(buf);
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+
+                this.mConnectionState = CS_SERVER_SESSION_TICKET;
+                break;
+            }
+            case HandshakeType.hello_request:
+            {
+                AssertEmpty(buf);
+
+                /*
+                 * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the
+                 * client is currently negotiating a session. This message may be ignored by the client
+                 * if it does not wish to renegotiate a session, or the client may, if it wishes,
+                 * respond with a no_renegotiation alert.
+                 */
+                if (this.mConnectionState == CS_END)
+                {
+                    /*
+                     * RFC 5746 4.5 SSLv3 clients that refuse renegotiation SHOULD use a fatal
+                     * handshake_failure alert.
+                     */
+                    if (TlsUtilities.IsSsl(Context))
+                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
+
+                    string message = "Renegotiation not supported";
+                    RaiseWarning(AlertDescription.no_renegotiation, message);
+                }
+                break;
+            }
+            case HandshakeType.client_hello:
+            case HandshakeType.client_key_exchange:
+            case HandshakeType.certificate_verify:
+            case HandshakeType.hello_verify_request:
+            default:
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            }
+        }
+
+        protected virtual void HandleSupplementalData(IList serverSupplementalData)
+        {
+            this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
+            this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
+
+            this.mKeyExchange = mTlsClient.GetKeyExchange();
+            this.mKeyExchange.Init(Context);
+        }
+
+        protected virtual void ReceiveNewSessionTicketMessage(MemoryStream buf)
+        {
+            NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            mTlsClient.NotifyNewSessionTicket(newSessionTicket);
+        }
+
+        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
+        {
+            ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
+            if (server_version.IsDtls)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            // Check that this matches what the server is Sending in the record layer
+            if (!server_version.Equals(this.mRecordStream.ReadVersion))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            ProtocolVersion client_version = Context.ClientVersion;
+            if (!server_version.IsEqualOrEarlierVersionOf(client_version))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            this.mRecordStream.SetWriteVersion(server_version);
+            ContextAdmin.SetServerVersion(server_version);
+            this.mTlsClient.NotifyServerVersion(server_version);
+
+            /*
+             * Read the server random
+             */
+            this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
+
+            this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
+            if (this.mSelectedSessionID.Length > 32)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
+
+            this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null
+                && Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);
+
+            /*
+             * Find out which CipherSuite the server has chosen and check that it was one of the offered
+             * ones, and is a valid selection for the negotiated version.
+             */
+            int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
+            if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
+                || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+                || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
+
+            /*
+             * Find out which CompressionMethod the server has chosen and check that it was one of the
+             * offered ones.
+             */
+            byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
+            if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
+
+            /*
+             * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
+             * hello message when the client has requested extended functionality via the extended
+             * client hello message specified in Section 2.1. ... Note that the extended server hello
+             * message is only sent in response to an extended client hello message. This prevents the
+             * possibility that the extended server hello message could "break" existing TLS 1.0
+             * clients.
+             */
+            this.mServerExtensions = ReadExtensions(buf);
+
+            /*
+             * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
+             * extended client hello message.
+             * 
+             * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server
+             * Hello is always allowed.
+             */
+            if (this.mServerExtensions != null)
+            {
+                foreach (int extType in this.mServerExtensions.Keys)
+                {
+                    /*
+                     * RFC 5746 3.6. Note that Sending a "renegotiation_info" extension in response to a
+                     * ClientHello containing only the SCSV is an explicit exception to the prohibition
+                     * in RFC 5246, Section 7.4.1.4, on the server Sending unsolicited extensions and is
+                     * only allowed because the client is signaling its willingness to receive the
+                     * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+                     */
+                    if (extType == ExtensionType.renegotiation_info)
+                        continue;
+
+                    /*
+                     * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
+                     * extensions appearing in the client hello, and Send a server hello containing no
+                     * extensions[.]
+                     */
+                    if (this.mResumedSession)
+                    {
+                        // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats
+                        // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats
+                        // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats
+    //                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                    }
+
+                    /*
+                     * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
+                     * same extension type appeared in the corresponding ClientHello. If a client
+                     * receives an extension type in ServerHello that it did not request in the
+                     * associated ClientHello, it MUST abort the handshake with an unsupported_extension
+                     * fatal alert.
+                     */
+                    if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType))
+                        throw new TlsFatalAlert(AlertDescription.unsupported_extension);
+                }
+            }
+
+            /*
+             * RFC 5746 3.4. Client Behavior: Initial Handshake
+             */
+            {
+                /*
+                 * When a ServerHello is received, the client MUST check if it includes the
+                 * "renegotiation_info" extension:
+                 */
+                byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
+                if (renegExtData != null)
+                {
+                    /*
+                     * If the extension is present, set the secure_renegotiation flag to TRUE. The
+                     * client MUST then verify that the length of the "renegotiated_connection"
+                     * field is zero, and if it is not, MUST abort the handshake (by Sending a fatal
+                     * handshake_failure alert).
+                     */
+                    this.mSecureRenegotiation = true;
+
+                    if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                }
+            }
+
+            // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
+            this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);
+
+            IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;
+            if (this.mResumedSession)
+            {
+                if (selectedCipherSuite != this.mSessionParameters.CipherSuite
+                    || selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
+                {
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+
+                sessionClientExtensions = null;
+                sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
+            }
+
+            this.mSecurityParameters.cipherSuite = selectedCipherSuite;
+            this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+            if (sessionServerExtensions != null)
+            {
+                /*
+                 * draft-ietf-tls-encrypt-then-mac-03 3. If a server receives an encrypt-then-MAC
+                 * request extension from a client and then selects a stream or AEAD cipher suite, it
+                 * MUST NOT Send an encrypt-then-MAC response extension back to the client.
+                 */
+                bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
+                if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+                this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
+
+                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
+                    sessionServerExtensions, AlertDescription.illegal_parameter);
+
+                this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
+
+                /*
+                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+                 * a session resumption handshake.
+                 */
+                this.mAllowCertificateStatus = !this.mResumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
+                        AlertDescription.illegal_parameter);
+
+                this.mExpectSessionTicket = !this.mResumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
+                        AlertDescription.illegal_parameter);
+            }
+
+            if (sessionClientExtensions != null)
+            {
+                this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
+            }
+        }
+
+        protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
+        {
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify);
+
+            certificateVerify.Encode(message);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual void SendClientHelloMessage()
+        {
+            this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);
+
+            ProtocolVersion client_version = this.mTlsClient.ClientVersion;
+            if (client_version.IsDtls)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            ContextAdmin.SetClientVersion(client_version);
+
+            /*
+             * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
+             * Session ID in the TLS ClientHello.
+             */
+            byte[] session_id = TlsUtilities.EmptyBytes;
+            if (this.mTlsSession != null)
+            {
+                session_id = this.mTlsSession.SessionID;
+                if (session_id == null || session_id.Length > 32)
+                {
+                    session_id = TlsUtilities.EmptyBytes;
+                }
+            }
+
+            this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();
+
+            this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();
+
+            if (session_id.Length > 0 && this.mSessionParameters != null)
+            {
+                if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite)
+                    || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
+                {
+                    session_id = TlsUtilities.EmptyBytes;
+                }
+            }
+
+            this.mClientExtensions = this.mTlsClient.GetClientExtensions();
+
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
+
+            TlsUtilities.WriteVersion(client_version, message);
+
+            message.Write(this.mSecurityParameters.ClientRandom);
+
+            TlsUtilities.WriteOpaque8(session_id, message);
+
+            // Cipher Suites (and SCSV)
+            {
+                /*
+                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+                 * ClientHello. Including both is NOT RECOMMENDED.
+                 */
+                byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
+                bool noRenegExt = (null == renegExtData);
+
+                bool noSCSV = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+
+                if (noRenegExt && noSCSV)
+                {
+                    // TODO Consider whether to default to a client extension instead
+    //                this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
+    //                this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
+                }
+
+                TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
+            }
+
+            TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);
+
+            if (mClientExtensions != null)
+            {
+                WriteExtensions(message, mClientExtensions);
+            }
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual void SendClientKeyExchangeMessage()
+        {
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange);
+
+            this.mKeyExchange.GenerateClientKeyExchange(message);
+
+            message.WriteToRecordStream(this);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsCompression.cs b/crypto/src/crypto/tls/TlsCompression.cs
new file mode 100644
index 000000000..177d64b7e
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsCompression.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsCompression
+	{
+		Stream Compress(Stream output);
+
+		Stream Decompress(Stream output);
+	}
+}
diff --git a/crypto/src/crypto/tls/TlsContext.cs b/crypto/src/crypto/tls/TlsContext.cs
new file mode 100644
index 000000000..d066723fc
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsContext.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public interface TlsContext
+    {
+        IRandomGenerator NonceRandomGenerator { get; }
+
+        SecureRandom SecureRandom { get; }
+
+        SecurityParameters SecurityParameters { get; }
+
+        bool IsServer { get; }
+
+        ProtocolVersion ClientVersion { get; }
+
+        ProtocolVersion ServerVersion { get; }
+
+        /**
+         * Used to get the resumable session, if any, used by this connection. Only available after the
+         * handshake has successfully completed.
+         * 
+         * @return A {@link TlsSession} representing the resumable session used by this connection, or
+         *         null if no resumable session available.
+         * @see TlsPeer#NotifyHandshakeComplete()
+         */
+        TlsSession ResumableSession { get; }
+
+        object UserObject { get; set; }
+
+        /**
+         * Export keying material according to RFC 5705: "Keying Material Exporters for TLS".
+         *
+         * @param asciiLabel    indicates which application will use the exported keys.
+         * @param context_value allows the application using the exporter to mix its own data with the TLS PRF for
+         *                      the exporter output.
+         * @param length        the number of bytes to generate
+         * @return a pseudorandom bit string of 'length' bytes generated from the master_secret.
+         */
+        byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length);
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsCredentials.cs b/crypto/src/crypto/tls/TlsCredentials.cs
new file mode 100644
index 000000000..5c5f1c02e
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsCredentials.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsCredentials
+	{
+		Certificate Certificate { get; }
+	}
+}
diff --git a/crypto/src/crypto/tls/TlsDHKeyExchange.cs b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
index 40ac416e0..b831249a6 100644
--- a/crypto/src/crypto/tls/TlsDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -1,201 +1,193 @@
 using System;
+using System.Collections;
 using System.IO;
 
-using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// TLS 1.0 DH key exchange.
-	/// </summary>
-	internal class TlsDHKeyExchange
-		: TlsKeyExchange
-	{
-		protected TlsClientContext context;
-		protected KeyExchangeAlgorithm keyExchange;
-		protected TlsSigner tlsSigner;
-
-		protected AsymmetricKeyParameter serverPublicKey = null;
-		protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
-		protected TlsAgreementCredentials agreementCredentials;
-		protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
-
-		internal TlsDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange)
-		{
-			switch (keyExchange)
-			{
-				case KeyExchangeAlgorithm.DH_RSA:
-				case KeyExchangeAlgorithm.DH_DSS:
-					this.tlsSigner = null;
-					break;
-				case KeyExchangeAlgorithm.DHE_RSA:
-					this.tlsSigner = new TlsRsaSigner();
-					break;
-				case KeyExchangeAlgorithm.DHE_DSS:
-					this.tlsSigner = new TlsDssSigner();
-					break;
-				default:
-					throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
-			}
-
-			this.context = context;
-			this.keyExchange = keyExchange;
-		}
-
-		public virtual void SkipServerCertificate()
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ProcessServerCertificate(Certificate serverCertificate)
-		{
-			X509CertificateStructure x509Cert = serverCertificate.certs[0];
-			SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
-
-			try
-			{
-				this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
-			}
-			catch (Exception)
-			{
-				throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
-			}
-
-			if (tlsSigner == null)
-			{
-				try
-				{
-					this.dhAgreeServerPublicKey = ValidateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey);
-				}
-				catch (InvalidCastException)
-				{
-					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-				}
-
-				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
-			}
-			else
-			{
-				if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
-				{
-					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-				}
-
-				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
-			}
-
-			// TODO
-			/*
-			* Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
-			* signing algorithm for the certificate must be the same as the algorithm for the
-			* certificate key."
-			*/
-		}
-
-		public virtual void SkipServerKeyExchange()
-		{
-			// OK
-		}
-
-		public virtual void ProcessServerKeyExchange(Stream input)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			ClientCertificateType[] types = certificateRequest.CertificateTypes;
-			foreach (ClientCertificateType type in types)
-			{
-				switch (type)
-				{
-					case ClientCertificateType.rsa_sign:
-					case ClientCertificateType.dss_sign:
-					case ClientCertificateType.rsa_fixed_dh:
-					case ClientCertificateType.dss_fixed_dh:
-					case ClientCertificateType.ecdsa_sign:
-						break;
-					default:
-						throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-				}
-			}
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			this.agreementCredentials = null;
-		}
-
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			if (clientCredentials is TlsAgreementCredentials)
-			{
-				// TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
-
-				this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
-			}
-			else if (clientCredentials is TlsSignerCredentials)
-			{
-				// OK
-			}
-			else
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual void GenerateClientKeyExchange(Stream output)
-		{
-			/*
-			 * RFC 2246 7.4.7.2 If the client certificate already contains a suitable
-			 * Diffie-Hellman key, then Yc is implicit and does not need to be sent again. In
-			 * this case, the Client Key Exchange message will be sent, but will be empty.
-			 */
-			if (agreementCredentials == null)
-			{
-				GenerateEphemeralClientKeyExchange(dhAgreeServerPublicKey.Parameters, output);
-			}
-		}
-
-        public virtual byte[] GeneratePremasterSecret()
-		{
-			if (agreementCredentials != null)
-			{
-				return agreementCredentials.GenerateAgreement(dhAgreeServerPublicKey);
-			}
-
-			return CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
-		}
-		
-		protected virtual bool AreCompatibleParameters(DHParameters a, DHParameters b)
-		{
-			return a.P.Equals(b.P) && a.G.Equals(b.G);
-		}
-
-		protected virtual byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
-			DHPrivateKeyParameters privateKey)
-		{
-			return TlsDHUtilities.CalculateDHBasicAgreement(publicKey, privateKey);
-		}
-
-		protected virtual AsymmetricCipherKeyPair GenerateDHKeyPair(DHParameters dhParams)
-		{
-			return TlsDHUtilities.GenerateDHKeyPair(context.SecureRandom, dhParams);
-		}
-
-		protected virtual void GenerateEphemeralClientKeyExchange(DHParameters dhParams, Stream output)
-		{
-			this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
-				context.SecureRandom, dhParams, output);
-		}
-
-		protected virtual DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
-		{
-			return TlsDHUtilities.ValidateDHPublicKey(key);
-		}
-	}
+    /// <summary>(D)TLS DH key exchange.</summary>
+    public class TlsDHKeyExchange
+        :   AbstractTlsKeyExchange
+    {
+        protected TlsSigner mTlsSigner;
+        protected DHParameters mDHParameters;
+
+        protected AsymmetricKeyParameter mServerPublicKey;
+        protected DHPublicKeyParameters mDHAgreeServerPublicKey;
+        protected TlsAgreementCredentials mAgreementCredentials;
+        protected DHPrivateKeyParameters mDHAgreeClientPrivateKey;
+
+        protected DHPrivateKeyParameters mDHAgreeServerPrivateKey;
+        protected DHPublicKeyParameters mDHAgreeClientPublicKey;
+
+        public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
+            :   base(keyExchange, supportedSignatureAlgorithms)
+        {
+            switch (keyExchange)
+            {
+            case KeyExchangeAlgorithm.DH_RSA:
+            case KeyExchangeAlgorithm.DH_DSS:
+                this.mTlsSigner = null;
+                break;
+            case KeyExchangeAlgorithm.DHE_RSA:
+                this.mTlsSigner = new TlsRsaSigner();
+                break;
+            case KeyExchangeAlgorithm.DHE_DSS:
+                this.mTlsSigner = new TlsDssSigner();
+                break;
+            default:
+                throw new InvalidOperationException("unsupported key exchange algorithm");
+            }
+
+            this.mDHParameters = dhParameters;
+        }
+
+        public override void Init(TlsContext context)
+        {
+            base.Init(context);
+
+            if (this.mTlsSigner != null)
+            {
+                this.mTlsSigner.Init(context);
+            }
+        }
+
+        public override void SkipServerCredentials()
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public override void ProcessServerCertificate(Certificate serverCertificate)
+        {
+            if (serverCertificate.IsEmpty)
+                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+            try
+            {
+                this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+            }
+
+            if (mTlsSigner == null)
+            {
+                try
+                {
+                    this.mDHAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey((DHPublicKeyParameters)this.mServerPublicKey);
+                }
+                catch (InvalidCastException e)
+                {
+                    throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+                }
+
+                TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
+            }
+            else
+            {
+                if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
+                {
+                    throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+                }
+
+                TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+            }
+
+            base.ProcessServerCertificate(serverCertificate);
+        }
+
+        public override bool RequiresServerKeyExchange
+        {
+            get
+            {
+                switch (mKeyExchange)
+                {
+                case KeyExchangeAlgorithm.DHE_DSS:
+                case KeyExchangeAlgorithm.DHE_RSA:
+                case KeyExchangeAlgorithm.DH_anon:
+                    return true;
+                default:
+                    return false;
+                }
+            }
+        }
+
+        public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            byte[] types = certificateRequest.CertificateTypes;
+            for (int i = 0; i < types.Length; ++i)
+            {
+                switch (types[i])
+                {
+                case ClientCertificateType.rsa_sign:
+                case ClientCertificateType.dss_sign:
+                case ClientCertificateType.rsa_fixed_dh:
+                case ClientCertificateType.dss_fixed_dh:
+                case ClientCertificateType.ecdsa_sign:
+                    break;
+                default:
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+        }
+
+        public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            if (clientCredentials is TlsAgreementCredentials)
+            {
+                // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
+
+                this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
+            }
+            else if (clientCredentials is TlsSignerCredentials)
+            {
+                // OK
+            }
+            else
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public override void GenerateClientKeyExchange(Stream output)
+        {
+            /*
+             * RFC 2246 7.4.7.2 If the client certificate already contains a suitable Diffie-Hellman
+             * key, then Yc is implicit and does not need to be sent again. In this case, the Client Key
+             * Exchange message will be sent, but will be empty.
+             */
+            if (mAgreementCredentials == null)
+            {
+                this.mDHAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom,
+                    mDHAgreeServerPublicKey.Parameters, output);
+            }
+        }
+
+        public override byte[] GeneratePremasterSecret()
+        {
+            if (mAgreementCredentials != null)
+            {
+                return mAgreementCredentials.GenerateAgreement(mDHAgreeServerPublicKey);
+            }
+
+            if (mDHAgreeServerPrivateKey != null)
+            {
+                return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreeClientPublicKey, mDHAgreeServerPrivateKey);
+            }
+
+            if (mDHAgreeClientPrivateKey != null)
+            {
+                return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreeServerPublicKey, mDHAgreeClientPrivateKey);
+            }
+
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsDHUtilities.cs b/crypto/src/crypto/tls/TlsDHUtilities.cs
index 733749ea1..477c3ebac 100644
--- a/crypto/src/crypto/tls/TlsDHUtilities.cs
+++ b/crypto/src/crypto/tls/TlsDHUtilities.cs
@@ -10,61 +10,92 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public abstract class TlsDHUtilities
-	{
-		public static byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
-			DHPrivateKeyParameters privateKey)
-		{
-			DHBasicAgreement dhAgree = new DHBasicAgreement();
-			dhAgree.Init(privateKey);
-			BigInteger agreement = dhAgree.CalculateAgreement(publicKey);
-			return BigIntegers.AsUnsignedByteArray(agreement);
-		}
-
-		public static AsymmetricCipherKeyPair GenerateDHKeyPair(SecureRandom random, DHParameters dhParams)
-		{
-			DHBasicKeyPairGenerator dhGen = new DHBasicKeyPairGenerator();
-			dhGen.Init(new DHKeyGenerationParameters(random, dhParams));
-			return dhGen.GenerateKeyPair();
-		}
-
-		public static DHPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random,
-			DHParameters dhParams, Stream output)
-		{
-			AsymmetricCipherKeyPair dhAgreeClientKeyPair = GenerateDHKeyPair(random, dhParams);
-			DHPrivateKeyParameters dhAgreeClientPrivateKey =
-				(DHPrivateKeyParameters)dhAgreeClientKeyPair.Private;
-
-			BigInteger Yc = ((DHPublicKeyParameters)dhAgreeClientKeyPair.Public).Y;
-			byte[] keData = BigIntegers.AsUnsignedByteArray(Yc);
-			TlsUtilities.WriteOpaque16(keData, output);
-
-			return dhAgreeClientPrivateKey;
-		}
-		
-		public static DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
-		{
-			BigInteger Y = key.Y;
-			DHParameters parameters = key.Parameters;
-			BigInteger p = parameters.P;
-			BigInteger g = parameters.G;
-
-			if (!p.IsProbablePrime(2))
-			{
-				throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-			}
-			if (g.CompareTo(BigInteger.Two) < 0 || g.CompareTo(p.Subtract(BigInteger.Two)) > 0)
-			{
-				throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-			}
-			if (Y.CompareTo(BigInteger.Two) < 0 || Y.CompareTo(p.Subtract(BigInteger.One)) > 0)
-			{
-				throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-			}
-
-			// TODO See RFC 2631 for more discussion of Diffie-Hellman validation
-
-			return key;
-		}
-	}
-}
\ No newline at end of file
+    public abstract class TlsDHUtilities
+    {
+        internal static readonly BigInteger One = BigInteger.One;
+        internal static readonly BigInteger Two = BigInteger.Two;
+
+        public static bool AreCompatibleParameters(DHParameters a, DHParameters b)
+        {
+            return a.P.Equals(b.P) && a.G.Equals(b.G);
+        }
+
+        public static byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey,
+            DHPrivateKeyParameters privateKey)
+        {
+            DHBasicAgreement basicAgreement = new DHBasicAgreement();
+            basicAgreement.Init(privateKey);
+            BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
+
+            /*
+             * RFC 5246 8.1.2. Leading bytes of Z that contain all zero bits are stripped before it is
+             * used as the pre_master_secret.
+             */
+            return BigIntegers.AsUnsignedByteArray(agreementValue);
+        }
+
+        public static AsymmetricCipherKeyPair GenerateDHKeyPair(SecureRandom random, DHParameters dhParams)
+        {
+            DHBasicKeyPairGenerator dhGen = new DHBasicKeyPairGenerator();
+            dhGen.Init(new DHKeyGenerationParameters(random, dhParams));
+            return dhGen.GenerateKeyPair();
+        }
+
+        public static DHPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random,
+            DHParameters dhParams, Stream output)
+        {
+            AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
+
+            DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+            WriteDHParameter(dhPublic.Y, output);
+
+            return (DHPrivateKeyParameters)kp.Private;
+        }
+
+        public static DHPrivateKeyParameters GenerateEphemeralServerKeyExchange(SecureRandom random,
+            DHParameters dhParams, Stream output)
+        {
+            AsymmetricCipherKeyPair kp = GenerateDHKeyPair(random, dhParams);
+
+            DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.Public;
+            new ServerDHParams(dhPublic).Encode(output);
+
+            return (DHPrivateKeyParameters)kp.Private;
+        }
+        
+        public static DHPublicKeyParameters ValidateDHPublicKey(DHPublicKeyParameters key)
+        {
+            BigInteger Y = key.Y;
+            DHParameters parameters = key.Parameters;
+            BigInteger p = parameters.P;
+            BigInteger g = parameters.G;
+
+            if (!p.IsProbablePrime(2))
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+            if (g.CompareTo(Two) < 0 || g.CompareTo(p.Subtract(Two)) > 0)
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+            if (Y.CompareTo(Two) < 0 || Y.CompareTo(p.Subtract(One)) > 0)
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            // TODO See RFC 2631 for more discussion of Diffie-Hellman validation
+
+            return key;
+        }
+
+        public static BigInteger ReadDHParameter(Stream input)
+        {
+            return new BigInteger(1, TlsUtilities.ReadOpaque16(input));
+        }
+
+        public static void WriteDHParameter(BigInteger x, Stream output)
+        {
+            TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsDeflateCompression.cs b/crypto/src/crypto/tls/TlsDeflateCompression.cs
index 146c961c7..9e1152908 100644
--- a/crypto/src/crypto/tls/TlsDeflateCompression.cs
+++ b/crypto/src/crypto/tls/TlsDeflateCompression.cs
@@ -5,41 +5,64 @@ using Org.BouncyCastle.Utilities.Zlib;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class TlsDeflateCompression
-		: TlsCompression
-	{
-		protected ZStream zIn, zOut;
-
-		public TlsDeflateCompression()
-		{
-			this.zIn = new ZStream();
-			this.zIn.inflateInit();
-
-			this.zOut = new ZStream();
-			// TODO Allow custom setting
-			this.zOut.deflateInit(JZlib.Z_DEFAULT_COMPRESSION);
-		}
-
-		public virtual Stream Compress(Stream output)
-		{
-			return new DeflateOutputStream(output, zOut, true);
-		}
-
-		public virtual Stream Decompress(Stream output)
-		{
-			return new DeflateOutputStream(output, zIn, false);
-		}
-
-		protected class DeflateOutputStream : ZOutputStream
-		{
-			public DeflateOutputStream(Stream output, ZStream z, bool compress)
-				: base(output)
-			{
-				this.z = z;
-				this.compress = compress;
-                // TODO http://www.bolet.org/~pornin/deflate-flush.html says we should use Z_SYNC_FLUSH
-				this.FlushMode = JZlib.Z_PARTIAL_FLUSH;
-			}
-		}
-	}
+    public class TlsDeflateCompression : TlsCompression
+    {
+        public const int LEVEL_NONE = JZlib.Z_NO_COMPRESSION;
+        public const int LEVEL_FASTEST = JZlib.Z_BEST_SPEED;
+        public const int LEVEL_SMALLEST = JZlib.Z_BEST_COMPRESSION;
+        public const int LEVEL_DEFAULT = JZlib.Z_DEFAULT_COMPRESSION;
+
+        protected readonly ZStream zIn, zOut;
+
+        public TlsDeflateCompression()
+            : this(LEVEL_DEFAULT)
+        {
+        }
+
+        public TlsDeflateCompression(int level)
+        {
+            this.zIn = new ZStream();
+            this.zIn.inflateInit();
+
+            this.zOut = new ZStream();
+            this.zOut.deflateInit(level);
+        }
+
+        public virtual Stream Compress(Stream output)
+        {
+            return new DeflateOutputStream(output, zOut, true);
+        }
+
+        public virtual Stream Decompress(Stream output)
+        {
+            return new DeflateOutputStream(output, zIn, false);
+        }
+
+        protected class DeflateOutputStream : ZOutputStream
+        {
+            public DeflateOutputStream(Stream output, ZStream z, bool compress)
+                : base(output, z)
+            {
+                this.compress = compress;
+
+                /*
+                 * See discussion at http://www.bolet.org/~pornin/deflate-flush.html .
+                 */
+                this.FlushMode = JZlib.Z_SYNC_FLUSH;
+            }
+
+            public override void Flush()
+            {
+                /*
+                 * TODO The inflateSyncPoint doesn't appear to work the way I hoped at the moment.
+                 * In any case, we may like to accept PARTIAL_FLUSH input, not just SYNC_FLUSH.
+                 * It's not clear how to check this in the Inflater.
+                 */
+                //if (!this.compress && (z == null || z.istate == null || z.istate.inflateSyncPoint(z) <= 0))
+                //{
+                //    throw new TlsFatalAlert(AlertDescription.decompression_failure);
+                //}
+            }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsDheKeyExchange.cs b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
index edadaeb38..3c05bb6f0 100644
--- a/crypto/src/crypto/tls/TlsDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsDheKeyExchange.cs
@@ -1,56 +1,105 @@
 using System;
+using System.Collections;
 using System.IO;
 
-using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsDheKeyExchange
-		: TlsDHKeyExchange
-	{
-		internal TlsDheKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange)
-			: base(context, keyExchange)
-		{
-		}
-
-		public override void SkipServerKeyExchange()
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public override void ProcessServerKeyExchange(Stream input)
-		{
-			SecurityParameters securityParameters = context.SecurityParameters;
-
-			ISigner signer = InitSigner(tlsSigner, securityParameters);
-			Stream sigIn = new SignerStream(input, signer, null);
-
-			byte[] pBytes = TlsUtilities.ReadOpaque16(sigIn);
-			byte[] gBytes = TlsUtilities.ReadOpaque16(sigIn);
-			byte[] YsBytes = TlsUtilities.ReadOpaque16(sigIn);
-
-			byte[] sigByte = TlsUtilities.ReadOpaque16(input);
-			if (!signer.VerifySignature(sigByte))
-			{
-				throw new TlsFatalAlert(AlertDescription.bad_certificate);
-			}
-
-			BigInteger p = new BigInteger(1, pBytes);
-			BigInteger g = new BigInteger(1, gBytes);
-			BigInteger Ys = new BigInteger(1, YsBytes);
-
-			this.dhAgreeServerPublicKey = ValidateDHPublicKey(
-				new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
-		}
-
-		protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
-		{
-			ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
-			signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
-			signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
-			return signer;
-		}
-	}
+    public class TlsDheKeyExchange
+        :   TlsDHKeyExchange
+    {
+        protected TlsSignerCredentials mServerCredentials = null;
+
+        public TlsDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
+            :   base(keyExchange, supportedSignatureAlgorithms, dhParameters)
+        {
+        }
+
+        public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+        {
+            if (!(serverCredentials is TlsSignerCredentials))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            ProcessServerCertificate(serverCredentials.Certificate);
+
+            this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
+        }
+
+        public override byte[] GenerateServerKeyExchange()
+        {
+            if (this.mDHParameters == null)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            DigestInputBuffer buf = new DigestInputBuffer();
+
+            this.mDHAgreeServerPrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom,
+                this.mDHParameters, buf);
+
+            /*
+             * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+             */
+            SignatureAndHashAlgorithm signatureAndHashAlgorithm;
+            IDigest d;
+
+            if (TlsUtilities.IsTlsV12(context))
+            {
+                signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
+                if (signatureAndHashAlgorithm == null)
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+
+                d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
+            }
+            else
+            {
+                signatureAndHashAlgorithm = null;
+                d = new CombinedHash();
+            }
+
+            SecurityParameters securityParameters = context.SecurityParameters;
+            d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+            d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+            buf.UpdateDigest(d);
+
+            byte[] hash = DigestUtilities.DoFinal(d);
+
+            byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
+
+            DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+            signed_params.Encode(buf);
+
+            return buf.ToArray();
+        }
+
+        public override void ProcessServerKeyExchange(Stream input)
+        {
+            SecurityParameters securityParameters = context.SecurityParameters;
+
+            SignerInputBuffer buf = new SignerInputBuffer();
+            Stream teeIn = new TeeInputStream(input, buf);
+
+            ServerDHParams dhParams = ServerDHParams.Parse(teeIn);
+
+            DigitallySigned signed_params = DigitallySigned.Parse(context, input);
+
+            ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+            buf.UpdateSigner(signer);
+            if (!signer.VerifySignature(signed_params.Signature))
+                throw new TlsFatalAlert(AlertDescription.decrypt_error);
+
+            this.mDHAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey(dhParams.PublicKey);
+        }
+
+        protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+            SecurityParameters securityParameters)
+        {
+            ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
+            signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+            signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+            return signer;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsDsaSigner.cs b/crypto/src/crypto/tls/TlsDsaSigner.cs
index 27d7b1f91..a5ac55974 100644
--- a/crypto/src/crypto/tls/TlsDsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsDsaSigner.cs
@@ -7,45 +7,77 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal abstract class TlsDsaSigner
-		:	TlsSigner
-	{
-		public virtual byte[] CalculateRawSignature(SecureRandom random,
-			AsymmetricKeyParameter privateKey, byte[] md5andsha1)
-		{
-			ISigner s = MakeSigner(new NullDigest(), true, new ParametersWithRandom(privateKey, random));
-			// Note: Only use the SHA1 part of the hash
-			s.BlockUpdate(md5andsha1, 16, 20);
-			return s.GenerateSignature();
-		}
-
-		public bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5andsha1)
-		{
-			ISigner s = MakeSigner(new NullDigest(), false, publicKey);
-			// Note: Only use the SHA1 part of the hash
-			s.BlockUpdate(md5andsha1, 16, 20);
-			return s.VerifySignature(sigBytes);
-		}
-
-		public virtual ISigner CreateSigner(SecureRandom random, AsymmetricKeyParameter privateKey)
-		{
-			return MakeSigner(new Sha1Digest(), true, new ParametersWithRandom(privateKey, random));
-		}
-
-		public virtual ISigner CreateVerifyer(AsymmetricKeyParameter publicKey)
-		{
-			return MakeSigner(new Sha1Digest(), false, publicKey);
-		}
-
-		public abstract bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
-
-		protected virtual ISigner MakeSigner(IDigest d, bool forSigning, ICipherParameters cp)
-		{
-			ISigner s = new DsaDigestSigner(CreateDsaImpl(), d);
-			s.Init(forSigning, cp);
-			return s;
-		}
-
-		protected abstract IDsa CreateDsaImpl();
-	}
+    public abstract class TlsDsaSigner
+        :	AbstractTlsSigner
+    {
+        public override byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+            AsymmetricKeyParameter privateKey, byte[] hash)
+        {
+            ISigner signer = MakeSigner(algorithm, true, true,
+                new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+            if (algorithm == null)
+            {
+                // Note: Only use the SHA1 part of the (MD5/SHA1) hash
+                signer.BlockUpdate(hash, 16, 20);
+            }
+            else
+            {
+                signer.BlockUpdate(hash, 0, hash.Length);
+            }
+            return signer.GenerateSignature();
+        }
+
+        public override bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+            AsymmetricKeyParameter publicKey, byte[] hash)
+        {
+            ISigner signer = MakeSigner(algorithm, true, false, publicKey);
+            if (algorithm == null)
+            {
+                // Note: Only use the SHA1 part of the (MD5/SHA1) hash
+                signer.BlockUpdate(hash, 16, 20);
+            }
+            else
+            {
+                signer.BlockUpdate(hash, 0, hash.Length);
+            }
+            return signer.VerifySignature(sigBytes);
+        }
+
+        public override ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey)
+        {
+            return MakeSigner(algorithm, false, true, privateKey);
+        }
+
+        public override ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey)
+        {
+            return MakeSigner(algorithm, false, false, publicKey);
+        }
+
+        protected virtual ICipherParameters MakeInitParameters(bool forSigning, ICipherParameters cp)
+        {
+            return cp;
+        }
+
+        protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
+            ICipherParameters cp)
+        {
+            if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
+                throw new InvalidOperationException();
+
+            // TODO For TLS 1.2+, lift the SHA-1 restriction here
+            if (algorithm != null && (algorithm.Hash != HashAlgorithm.sha1 || algorithm.Signature != SignatureAlgorithm))
+                throw new InvalidOperationException();
+
+            byte hashAlgorithm = algorithm == null ? HashAlgorithm.sha1 : algorithm.Hash;
+            IDigest d = raw ? new NullDigest() : TlsUtilities.CreateHash(hashAlgorithm);
+
+            ISigner s = new DsaDigestSigner(CreateDsaImpl(hashAlgorithm), d);
+            s.Init(forSigning, MakeInitParameters(forSigning, cp));
+            return s;
+        }
+
+        protected abstract byte SignatureAlgorithm { get; }
+
+        protected abstract IDsa CreateDsaImpl(byte hashAlgorithm);
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsDssSigner.cs b/crypto/src/crypto/tls/TlsDssSigner.cs
index c6f1abcec..707ef3853 100644
--- a/crypto/src/crypto/tls/TlsDssSigner.cs
+++ b/crypto/src/crypto/tls/TlsDssSigner.cs
@@ -5,17 +5,22 @@ using Org.BouncyCastle.Crypto.Signers;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsDssSigner
-		: TlsDsaSigner
-	{
-		public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
-		{
-			return publicKey is DsaPublicKeyParameters;
-		}
+    public class TlsDssSigner
+        :   TlsDsaSigner
+    {
+        public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+        {
+            return publicKey is DsaPublicKeyParameters;
+        }
 
-	    protected override IDsa CreateDsaImpl()
-	    {
-			return new DsaSigner();
-	    }
-	}
+        protected override IDsa CreateDsaImpl(byte hashAlgorithm)
+        {
+            return new DsaSigner(new HMacDsaKCalculator(TlsUtilities.CreateHash(hashAlgorithm)));
+        }
+
+        protected override byte SignatureAlgorithm
+        {
+            get { return Tls.SignatureAlgorithm.dsa; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
index 83983ba47..42dc2f2ef 100644
--- a/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -3,228 +3,209 @@ using System.Collections;
 using System.IO;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto.Agreement;
-using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-    /**
-    * ECDH key exchange (see RFC 4492)
-    */
-    internal class TlsECDHKeyExchange
-		: TlsKeyExchange
+    /// <summary>(D)TLS ECDH key exchange (see RFC 4492).</summary>
+    public class TlsECDHKeyExchange
+        :   AbstractTlsKeyExchange
     {
-		protected TlsClientContext context;
-		protected KeyExchangeAlgorithm keyExchange;
-		protected TlsSigner tlsSigner;
+        protected TlsSigner mTlsSigner;
+        protected int[] mNamedCurves;
+        protected byte[] mClientECPointFormats, mServerECPointFormats;
 
-		protected AsymmetricKeyParameter serverPublicKey;
-		protected ECPublicKeyParameters ecAgreeServerPublicKey;
-		protected TlsAgreementCredentials agreementCredentials;
-		protected ECPrivateKeyParameters ecAgreeClientPrivateKey = null;
+        protected AsymmetricKeyParameter mServerPublicKey;
+        protected TlsAgreementCredentials mAgreementCredentials;
 
-		internal TlsECDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange)
+        protected ECPrivateKeyParameters mECAgreePrivateKey;
+        protected ECPublicKeyParameters mECAgreePublicKey;
+
+        public TlsECDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
+            byte[] clientECPointFormats, byte[] serverECPointFormats)
+            :   base(keyExchange, supportedSignatureAlgorithms)
         {
-			switch (keyExchange)
-			{
-				case KeyExchangeAlgorithm.ECDHE_RSA:
-					this.tlsSigner = new TlsRsaSigner();
-					break;
-				case KeyExchangeAlgorithm.ECDHE_ECDSA:
-					this.tlsSigner = new TlsECDsaSigner();
-					break;
-				case KeyExchangeAlgorithm.ECDH_RSA:
-				case KeyExchangeAlgorithm.ECDH_ECDSA:
-					this.tlsSigner = null;
-					break;
-				default:
-                    throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
-			}
-
-			this.context = context;
-			this.keyExchange = keyExchange;
+            switch (keyExchange)
+            {
+            case KeyExchangeAlgorithm.ECDHE_RSA:
+                this.mTlsSigner = new TlsRsaSigner();
+                break;
+            case KeyExchangeAlgorithm.ECDHE_ECDSA:
+                this.mTlsSigner = new TlsECDsaSigner();
+                break;
+            case KeyExchangeAlgorithm.ECDH_RSA:
+            case KeyExchangeAlgorithm.ECDH_ECDSA:
+                this.mTlsSigner = null;
+                break;
+            default:
+                throw new InvalidOperationException("unsupported key exchange algorithm");
+            }
+
+            this.mNamedCurves = namedCurves;
+            this.mClientECPointFormats = clientECPointFormats;
+            this.mServerECPointFormats = serverECPointFormats;
         }
 
-        public virtual void SkipServerCertificate()
+        public override void Init(TlsContext context)
+        {
+            base.Init(context);
+
+            if (this.mTlsSigner != null)
+            {
+                this.mTlsSigner.Init(context);
+            }
+        }
+
+        public override void SkipServerCredentials()
         {
             throw new TlsFatalAlert(AlertDescription.unexpected_message);
         }
 
-        public virtual void ProcessServerCertificate(Certificate serverCertificate)
+        public override void ProcessServerCertificate(Certificate serverCertificate)
         {
-            X509CertificateStructure x509Cert = serverCertificate.certs[0];
-            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+            if (serverCertificate.IsEmpty)
+                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
 
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
             try
             {
-                this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+                this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
             }
-            catch (Exception)
+            catch (Exception e)
             {
-                throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
             }
 
-			if (tlsSigner == null)
-			{
-				try
-				{
-					this.ecAgreeServerPublicKey = ValidateECPublicKey((ECPublicKeyParameters)this.serverPublicKey);
-				}
-				catch (InvalidCastException)
-				{
-					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-				}
-
-				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
-			}
-			else
-			{
-				if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
-				{
-					throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-				}
-
-				TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
-			}
-			
-			// TODO
+            if (mTlsSigner == null)
+            {
+                try
+                {
+                    this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey((ECPublicKeyParameters) this.mServerPublicKey);
+                }
+                catch (InvalidCastException e)
+                {
+                    throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+                }
+
+                TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
+            }
+            else
+            {
+                if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
+                    throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+
+                TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+            }
+
+            base.ProcessServerCertificate(serverCertificate);
+        }
+
+        public override bool RequiresServerKeyExchange
+        {
+            get
+            {
+                switch (mKeyExchange)
+                {
+                case KeyExchangeAlgorithm.ECDHE_ECDSA:
+                case KeyExchangeAlgorithm.ECDHE_RSA:
+                case KeyExchangeAlgorithm.ECDH_anon:
+                    return true;
+                default:
+                    return false;
+                }
+            }
+        }
+
+        public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
             /*
-            * Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
-            * signing algorithm for the certificate must be the same as the algorithm for the
-            * certificate key."
-            */
+             * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
+             * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
+             * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
+             * these algorithms.
+             */
+            byte[] types = certificateRequest.CertificateTypes;
+            for (int i = 0; i < types.Length; ++i)
+            {
+                switch (types[i])
+                {
+                case ClientCertificateType.rsa_sign:
+                case ClientCertificateType.dss_sign:
+                case ClientCertificateType.ecdsa_sign:
+                case ClientCertificateType.rsa_fixed_ecdh:
+                case ClientCertificateType.ecdsa_fixed_ecdh:
+                    break;
+                default:
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
         }
-		
-        public virtual void SkipServerKeyExchange()
+
+        public override void ProcessClientCredentials(TlsCredentials clientCredentials)
         {
-            // do nothing
+            if (clientCredentials is TlsAgreementCredentials)
+            {
+                // TODO Validate client cert has matching parameters (see 'TlsEccUtilities.AreOnSameCurve')?
+
+                this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
+            }
+            else if (clientCredentials is TlsSignerCredentials)
+            {
+                // OK
+            }
+            else
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
         }
 
-        public virtual void ProcessServerKeyExchange(Stream input)
+        public override void GenerateClientKeyExchange(Stream output)
         {
-            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            if (mAgreementCredentials == null)
+            {
+                this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom,
+                    mServerECPointFormats, mECAgreePublicKey.Parameters, output);
+            }
         }
 
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			/*
-			 * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable
-			 * with ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is
-			 * prohibited because the use of a long-term ECDH client key would jeopardize the
-			 * forward secrecy property of these algorithms.
-			 */
-			ClientCertificateType[] types = certificateRequest.CertificateTypes;
-			foreach (ClientCertificateType type in types)
-			{
-				switch (type)
-				{
-					case ClientCertificateType.rsa_sign:
-					case ClientCertificateType.dss_sign:
-					case ClientCertificateType.ecdsa_sign:
-					case ClientCertificateType.rsa_fixed_ecdh:
-					case ClientCertificateType.ecdsa_fixed_ecdh:
-						break;
-					default:
-						throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-				}
-			}
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			this.agreementCredentials = null;
-		}
-
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			if (clientCredentials is TlsAgreementCredentials)
-			{
-				// TODO Validate client cert has matching parameters (see 'AreOnSameCurve')?
-
-				this.agreementCredentials = (TlsAgreementCredentials)clientCredentials;
-			}
-			else if (clientCredentials is TlsSignerCredentials)
-			{
-				// OK
-			}
-			else
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		public virtual void GenerateClientKeyExchange(Stream output)
+        public override void ProcessClientCertificate(Certificate clientCertificate)
         {
-			if (agreementCredentials == null)
-			{
-				GenerateEphemeralClientKeyExchange(ecAgreeServerPublicKey.Parameters, output);
-			}
+            // TODO Extract the public key
+            // TODO If the certificate is 'fixed', take the public key as mECAgreeClientPublicKey
         }
 
-        public virtual byte[] GeneratePremasterSecret()
+        public override void ProcessClientKeyExchange(Stream input)
         {
-			if (agreementCredentials != null)
-			{
-				return agreementCredentials.GenerateAgreement(ecAgreeServerPublicKey);
-			}
+            if (mECAgreePublicKey != null)
+            {
+                // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate
+                return;
+            }
+
+            byte[] point = TlsUtilities.ReadOpaque8(input);
 
-			return CalculateECDHBasicAgreement(ecAgreeServerPublicKey, ecAgreeClientPrivateKey);
+            ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
+
+            this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+                mServerECPointFormats, curve_params, point));
         }
 
-		protected virtual bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
-		{
-			// TODO Move to ECDomainParameters.Equals() or other utility method?
-			return a.Curve.Equals(b.Curve) && a.G.Equals(b.G) && a.N.Equals(b.N) && a.H.Equals(b.H);
-		}
-
-		protected virtual byte[] ExternalizeKey(ECPublicKeyParameters keyParameters)
-		{
-			// TODO Add support for compressed encoding and SPF extension
-
-			/*
-			 * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format.
-			 * Here, the format MUST conform to what the server has requested through a
-			 * Supported Point Formats Extension if this extension was used, and MUST be
-			 * uncompressed if this extension was not used.
-			 */
-			return keyParameters.Q.GetEncoded();
-		}
-
-		protected virtual AsymmetricCipherKeyPair GenerateECKeyPair(ECDomainParameters ecParams)
-		{
-			ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
-			ECKeyGenerationParameters keyGenerationParameters = new ECKeyGenerationParameters(ecParams,
-				context.SecureRandom);
-			keyPairGenerator.Init(keyGenerationParameters);
-			return keyPairGenerator.GenerateKeyPair();
-		}
-
-		protected virtual void GenerateEphemeralClientKeyExchange(ECDomainParameters ecParams, Stream output)
-		{
-			AsymmetricCipherKeyPair ecAgreeClientKeyPair = GenerateECKeyPair(ecParams);
-			this.ecAgreeClientPrivateKey = (ECPrivateKeyParameters)ecAgreeClientKeyPair.Private;
-
-			byte[] keData = ExternalizeKey((ECPublicKeyParameters)ecAgreeClientKeyPair.Public);
-			TlsUtilities.WriteOpaque8(keData, output);
-		}
-
-		protected virtual byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey,
-			ECPrivateKeyParameters privateKey)
-		{
-			ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
-			basicAgreement.Init(privateKey);
-			BigInteger agreement = basicAgreement.CalculateAgreement(publicKey);
-			return BigIntegers.AsUnsignedByteArray(agreement);
-		}
-
-		protected virtual ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
-		{
-			// TODO Check RFC 4492 for validation
-			return key;
-		}
+        public override byte[] GeneratePremasterSecret()
+        {
+            if (mAgreementCredentials != null)
+            {
+                return mAgreementCredentials.GenerateAgreement(mECAgreePublicKey);
+            }
+
+            if (mECAgreePrivateKey != null)
+            {
+                return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
+            }
+
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
     }
 }
diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
index 5516154ce..0644bd44d 100644
--- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -2,106 +2,202 @@ using System;
 using System.Collections;
 using System.IO;
 
-using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-    /**
-    * ECDHE key exchange (see RFC 4492)
-    */
-    internal class TlsECDheKeyExchange : TlsECDHKeyExchange
+    /// <summary>(D)TLS ECDHE key exchange (see RFC 4492).</summary>
+    public class TlsECDheKeyExchange
+        :   TlsECDHKeyExchange
     {
-        internal TlsECDheKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange)
-            : base(context, keyExchange)
+        protected TlsSignerCredentials mServerCredentials = null;
+
+        public TlsECDheKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
+            byte[] clientECPointFormats, byte[] serverECPointFormats)
+            :   base(keyExchange, supportedSignatureAlgorithms, namedCurves, clientECPointFormats, serverECPointFormats)
         {
         }
 
-		public override void SkipServerKeyExchange()
+        public override void ProcessServerCredentials(TlsCredentials serverCredentials)
         {
-            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            if (!(serverCredentials is TlsSignerCredentials))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            ProcessServerCertificate(serverCredentials.Certificate);
+
+            this.mServerCredentials = (TlsSignerCredentials)serverCredentials;
         }
 
-        public override void ProcessServerKeyExchange(Stream input)
+        public override byte[] GenerateServerKeyExchange()
         {
-			SecurityParameters securityParameters = context.SecurityParameters;
-
-            ISigner signer = InitSigner(tlsSigner, securityParameters);
-            Stream sigIn = new SignerStream(input, signer, null);
+            /*
+             * First we try to find a supported named curve from the client's list.
+             */
+            int namedCurve = -1;
+            if (mNamedCurves == null)
+            {
+                // TODO Let the peer choose the default named curve
+                namedCurve = NamedCurve.secp256r1;
+            }
+            else
+            {
+                for (int i = 0; i < mNamedCurves.Length; ++i)
+                {
+                    int entry = mNamedCurves[i];
+                    if (NamedCurve.IsValid(entry) && TlsEccUtilities.IsSupportedNamedCurve(entry))
+                    {
+                        namedCurve = entry;
+                        break;
+                    }
+                }
+            }
 
-            ECCurveType curveType = (ECCurveType)TlsUtilities.ReadUint8(sigIn);
-            ECDomainParameters curve_params;
+            ECDomainParameters curve_params = null;
+            if (namedCurve >= 0)
+            {
+                curve_params = TlsEccUtilities.GetParametersForNamedCurve(namedCurve);
+            }
+            else
+            {
+                /*
+                 * If no named curves are suitable, check if the client supports explicit curves.
+                 */
+                if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_prime_curves))
+                {
+                    curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.secp256r1);
+                }
+                else if (Arrays.Contains(mNamedCurves, NamedCurve.arbitrary_explicit_char2_curves))
+                {
+                    curve_params = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.sect283r1);
+                }
+            }
 
-            //  Currently, we only support named curves
-            if (curveType == ECCurveType.named_curve)
+            if (curve_params == null)
             {
-                NamedCurve namedCurve = (NamedCurve)TlsUtilities.ReadUint16(sigIn);
+                /*
+                 * NOTE: We shouldn't have negotiated ECDHE key exchange since we apparently can't find
+                 * a suitable curve.
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
 
-                // TODO Check namedCurve is one we offered?
+            AsymmetricCipherKeyPair kp = TlsEccUtilities.GenerateECKeyPair(context.SecureRandom, curve_params);
+            this.mECAgreePrivateKey = (ECPrivateKeyParameters)kp.Private;
 
-                curve_params = NamedCurveHelper.GetECParameters(namedCurve);
+            DigestInputBuffer buf = new DigestInputBuffer();
+
+            if (namedCurve < 0)
+            {
+                TlsEccUtilities.WriteExplicitECParameters(mClientECPointFormats, curve_params, buf);
             }
             else
             {
-                // TODO Add support for explicit curve parameters (read from sigIn)
-
-                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                TlsEccUtilities.WriteNamedECParameters(namedCurve, buf);
             }
 
-            byte[] publicBytes = TlsUtilities.ReadOpaque8(sigIn);
+            ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
+            TlsEccUtilities.WriteECPoint(mClientECPointFormats, ecPublicKey.Q, buf);
 
-            byte[] sigByte = TlsUtilities.ReadOpaque16(input);
-            if (!signer.VerifySignature(sigByte))
+            /*
+             * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
+             */
+            SignatureAndHashAlgorithm signatureAndHashAlgorithm;
+            IDigest d;
+
+            if (TlsUtilities.IsTlsV12(context))
+            {
+                signatureAndHashAlgorithm = mServerCredentials.SignatureAndHashAlgorithm;
+                if (signatureAndHashAlgorithm == null)
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+
+                d = TlsUtilities.CreateHash(signatureAndHashAlgorithm.Hash);
+            }
+            else
             {
-                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+                signatureAndHashAlgorithm = null;
+                d = new CombinedHash();
             }
 
-            // TODO Check curve_params not null
+            SecurityParameters securityParameters = context.SecurityParameters;
+            d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+            d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+            buf.UpdateDigest(d);
+
+            byte[] hash = DigestUtilities.DoFinal(d);
 
-            ECPoint Q = curve_params.Curve.DecodePoint(publicBytes);
+            byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);
 
-			this.ecAgreeServerPublicKey = ValidateECPublicKey(new ECPublicKeyParameters(Q, curve_params));
+            DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);
+            signed_params.Encode(buf);
+
+            return buf.ToArray();
         }
-		
-		public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			/*
-			 * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable
-			 * with ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is
-			 * prohibited because the use of a long-term ECDH client key would jeopardize the
-			 * forward secrecy property of these algorithms.
-			 */
-			ClientCertificateType[] types = certificateRequest.CertificateTypes;
-			foreach (ClientCertificateType type in types)
-			{
-				switch (type)
-				{
-					case ClientCertificateType.rsa_sign:
-					case ClientCertificateType.dss_sign:
-					case ClientCertificateType.ecdsa_sign:
-						break;
-					default:
-						throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-				}
-			}
-		}
-		
-		public override void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			if (clientCredentials is TlsSignerCredentials)
-			{
-				// OK
-			}
-			else
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-
-		protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
+
+        public override void ProcessServerKeyExchange(Stream input)
+        {
+            SecurityParameters securityParameters = context.SecurityParameters;
+
+            SignerInputBuffer buf = new SignerInputBuffer();
+            Stream teeIn = new TeeInputStream(input, buf);
+
+            ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, teeIn);
+
+            byte[] point = TlsUtilities.ReadOpaque8(teeIn);
+
+            DigitallySigned signed_params = DigitallySigned.Parse(context, input);
+
+            ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+            buf.UpdateSigner(signer);
+            if (!signer.VerifySignature(signed_params.Signature))
+                throw new TlsFatalAlert(AlertDescription.decrypt_error);
+
+            this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
+                mClientECPointFormats, curve_params, point));
+        }
+
+        public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            /*
+             * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
+             * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
+             * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
+             * these algorithms.
+             */
+            byte[] types = certificateRequest.CertificateTypes;
+            for (int i = 0; i < types.Length; ++i)
+            {
+                switch (types[i])
+                {
+                case ClientCertificateType.rsa_sign:
+                case ClientCertificateType.dss_sign:
+                case ClientCertificateType.ecdsa_sign:
+                    break;
+                default:
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+        }
+
+        public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            if (clientCredentials is TlsSignerCredentials)
+            {
+                // OK
+            }
+            else
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+            SecurityParameters securityParameters)
         {
-            ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
+            ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
             signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
             signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
             return signer;
diff --git a/crypto/src/crypto/tls/TlsECDsaSigner.cs b/crypto/src/crypto/tls/TlsECDsaSigner.cs
index 3c30fdc0c..fa9d0b714 100644
--- a/crypto/src/crypto/tls/TlsECDsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsECDsaSigner.cs
@@ -5,17 +5,22 @@ using Org.BouncyCastle.Crypto.Signers;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsECDsaSigner
-		: TlsDsaSigner
-	{
-		public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
-		{
-			return publicKey is ECPublicKeyParameters;
-		}
+    public class TlsECDsaSigner
+        :   TlsDsaSigner
+    {
+        public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+        {
+            return publicKey is ECPublicKeyParameters;
+        }
 
-		protected override IDsa CreateDsaImpl()
-		{
-			return new ECDsaSigner();
-		}
-	}
+        protected override IDsa CreateDsaImpl(byte hashAlgorithm)
+        {
+            return new ECDsaSigner(new HMacDsaKCalculator(TlsUtilities.CreateHash(hashAlgorithm)));
+        }
+
+        protected override byte SignatureAlgorithm
+        {
+            get { return Tls.SignatureAlgorithm.ecdsa; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsEccUtilities.cs b/crypto/src/crypto/tls/TlsEccUtilities.cs
new file mode 100644
index 000000000..64c3c1593
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsEccUtilities.cs
@@ -0,0 +1,647 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class TlsEccUtilities
+    {
+        private static readonly string[] CurveNames = new string[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
+            "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
+            "sect571k1", "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1",
+            "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1",
+            "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"};
+
+        public static void AddSupportedEllipticCurvesExtension(IDictionary extensions, int[] namedCurves)
+        {
+            extensions[ExtensionType.elliptic_curves] = CreateSupportedEllipticCurvesExtension(namedCurves);
+        }
+
+        public static void AddSupportedPointFormatsExtension(IDictionary extensions, byte[] ecPointFormats)
+        {
+            extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats);
+        }
+
+        public static int[] GetSupportedEllipticCurvesExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.elliptic_curves);
+            return extensionData == null ? null : ReadSupportedEllipticCurvesExtension(extensionData);
+        }
+
+        public static byte[] GetSupportedPointFormatsExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats);
+            return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData);
+        }
+
+        public static byte[] CreateSupportedEllipticCurvesExtension(int[] namedCurves)
+        {
+            if (namedCurves == null || namedCurves.Length < 1)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            return TlsUtilities.EncodeUint16ArrayWithUint16Length(namedCurves);
+        }
+
+        public static byte[] CreateSupportedPointFormatsExtension(byte[] ecPointFormats)
+        {
+            if (ecPointFormats == null || !Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+            {
+                /*
+                 * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+                 * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+                 */
+
+                // NOTE: We add it at the end (lowest preference)
+                ecPointFormats = Arrays.Append(ecPointFormats, ECPointFormat.uncompressed);
+            }
+
+            return TlsUtilities.EncodeUint8ArrayWithUint8Length(ecPointFormats);
+        }
+
+        public static int[] ReadSupportedEllipticCurvesExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, false);
+
+            int length = TlsUtilities.ReadUint16(buf);
+            if (length < 2 || (length & 1) != 0)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int[] namedCurves = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return namedCurves;
+        }
+
+        public static byte[] ReadSupportedPointFormatsExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, false);
+
+            byte length = TlsUtilities.ReadUint8(buf);
+            if (length < 1)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            byte[] ecPointFormats = TlsUtilities.ReadUint8Array(length, buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            if (!Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+            {
+                /*
+                 * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+                 * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+                 */
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            return ecPointFormats;
+        }
+
+        public static string GetNameOfNamedCurve(int namedCurve)
+        {
+            return IsSupportedNamedCurve(namedCurve) ? CurveNames[namedCurve - 1] : null;
+        }
+
+        public static ECDomainParameters GetParametersForNamedCurve(int namedCurve)
+        {
+            string curveName = GetNameOfNamedCurve(namedCurve);
+            if (curveName == null)
+                return null;
+
+            // Parameters are lazily created the first time a particular curve is accessed
+
+            X9ECParameters ecP = CustomNamedCurves.GetByName(curveName);
+            if (ecP == null)
+            {
+                ecP = ECNamedCurveTable.GetByName(curveName);
+                if (ecP == null)
+                    return null;
+            }
+
+            // It's a bit inefficient to do this conversion every time
+            return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+        }
+
+        public static bool HasAnySupportedNamedCurves()
+        {
+            return CurveNames.Length > 0;
+        }
+
+        public static bool ContainsEccCipherSuites(int[] cipherSuites)
+        {
+            for (int i = 0; i < cipherSuites.Length; ++i)
+            {
+                if (IsEccCipherSuite(cipherSuites[i]))
+                    return true;
+            }
+            return false;
+        }
+
+        public static bool IsEccCipherSuite(int cipherSuite)
+        {
+            switch (cipherSuite)
+            {
+            /*
+             * RFC 4492
+             */
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+
+            /*
+             * RFC 5289
+             */
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+
+            /*
+             * RFC 5489
+             */
+            case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+
+            /*
+             * RFC 6367
+             */
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+
+            /*
+             * draft-agl-tls-chacha20poly1305-04
+             */
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+
+            /*
+             * draft-josefsson-salsa20-tls-04 
+             */
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+
+                return true;
+
+            default:
+                return false;
+            }
+        }
+
+        public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
+        {
+            // TODO Move to ECDomainParameters.Equals() or other utility method?
+            return a.Curve.Equals(b.Curve) && a.G.Equals(b.G) && a.N.Equals(b.N) && a.H.Equals(b.H);
+        }
+
+        public static bool IsSupportedNamedCurve(int namedCurve)
+        {
+            return (namedCurve > 0 && namedCurve <= CurveNames.Length);
+        }
+
+        public static bool IsCompressionPreferred(byte[] ecPointFormats, byte compressionFormat)
+        {
+            if (ecPointFormats == null)
+                return false;
+
+            for (int i = 0; i < ecPointFormats.Length; ++i)
+            {
+                byte ecPointFormat = ecPointFormats[i];
+                if (ecPointFormat == ECPointFormat.uncompressed)
+                    return false;
+                if (ecPointFormat == compressionFormat)
+                    return true;
+            }
+            return false;
+        }
+
+        public static byte[] SerializeECFieldElement(int fieldSize, BigInteger x)
+        {
+            return BigIntegers.AsUnsignedByteArray((fieldSize + 7) / 8, x);
+        }
+
+        public static byte[] SerializeECPoint(byte[] ecPointFormats, ECPoint point)
+        {
+            ECCurve curve = point.Curve;
+
+            /*
+             * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format. Here, the
+             * format MUST conform to what the server has requested through a Supported Point Formats
+             * Extension if this extension was used, and MUST be uncompressed if this extension was not
+             * used.
+             */
+            bool compressed = false;
+            if (ECAlgorithms.IsFpCurve(curve))
+            {
+                compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_prime);
+            }
+            else if (ECAlgorithms.IsF2mCurve(curve))
+            {
+                compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_char2);
+            }
+            return point.GetEncoded(compressed);
+        }
+
+        public static byte[] SerializeECPublicKey(byte[] ecPointFormats, ECPublicKeyParameters keyParameters)
+        {
+            return SerializeECPoint(ecPointFormats, keyParameters.Q);
+        }
+
+        public static BigInteger DeserializeECFieldElement(int fieldSize, byte[] encoding)
+        {
+            int requiredLength = (fieldSize + 7) / 8;
+            if (encoding.Length != requiredLength)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            return new BigInteger(1, encoding);
+        }
+
+        public static ECPoint DeserializeECPoint(byte[] ecPointFormats, ECCurve curve, byte[] encoding)
+        {
+            if (encoding == null || encoding.Length < 1)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            byte actualFormat;
+            switch (encoding[0])
+            {
+            case 0x02: // compressed
+            case 0x03: // compressed
+            {
+                if (ECAlgorithms.IsF2mCurve(curve))
+                {
+                    actualFormat = ECPointFormat.ansiX962_compressed_char2;
+                }
+                else if (ECAlgorithms.IsFpCurve(curve))
+                {
+                    actualFormat = ECPointFormat.ansiX962_compressed_prime;
+                }
+                else
+                {
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+                break;
+            }
+            case 0x04: // uncompressed
+            {
+                actualFormat = ECPointFormat.uncompressed;
+                break;
+            }
+            case 0x00: // infinity
+            case 0x06: // hybrid
+            case 0x07: // hybrid
+            default:
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            if (actualFormat != ECPointFormat.uncompressed
+                && (ecPointFormats == null || !Arrays.Contains(ecPointFormats, actualFormat)))
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            return curve.DecodePoint(encoding);
+        }
+
+        public static ECPublicKeyParameters DeserializeECPublicKey(byte[] ecPointFormats, ECDomainParameters curve_params,
+            byte[] encoding)
+        {
+            try
+            {
+                ECPoint Y = DeserializeECPoint(ecPointFormats, curve_params.Curve, encoding);
+                return new ECPublicKeyParameters(Y, curve_params);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+            }
+        }
+
+        public static byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey, ECPrivateKeyParameters privateKey)
+        {
+            ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
+            basicAgreement.Init(privateKey);
+            BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
+
+            /*
+             * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
+             * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
+             * any given field; leading zeros found in this octet string MUST NOT be truncated.
+             */
+            return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
+        }
+
+        public static AsymmetricCipherKeyPair GenerateECKeyPair(SecureRandom random, ECDomainParameters ecParams)
+        {
+            ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
+            keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random));
+            return keyPairGenerator.GenerateKeyPair();
+        }
+
+        public static ECPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random, byte[] ecPointFormats,
+            ECDomainParameters ecParams, Stream output)
+        {
+            AsymmetricCipherKeyPair kp = TlsEccUtilities.GenerateECKeyPair(random, ecParams);
+
+            ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
+            WriteECPoint(ecPointFormats, ecPublicKey.Q, output);
+
+            return (ECPrivateKeyParameters)kp.Private;
+        }
+
+        public static ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
+        {
+            // TODO Check RFC 4492 for validation
+            return key;
+        }
+
+        public static int ReadECExponent(int fieldSize, Stream input)
+        {
+            BigInteger K = ReadECParameter(input);
+            if (K.BitLength < 32)
+            {
+                int k = K.IntValue;
+                if (k > 0 && k < fieldSize)
+                {
+                    return k;
+                }
+            }
+            throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+        }
+
+        public static BigInteger ReadECFieldElement(int fieldSize, Stream input)
+        {
+            return DeserializeECFieldElement(fieldSize, TlsUtilities.ReadOpaque8(input));
+        }
+
+        public static BigInteger ReadECParameter(Stream input)
+        {
+            // TODO Are leading zeroes okay here?
+            return new BigInteger(1, TlsUtilities.ReadOpaque8(input));
+        }
+
+        public static ECDomainParameters ReadECParameters(int[] namedCurves, byte[] ecPointFormats, Stream input)
+        {
+            try
+            {
+                byte curveType = TlsUtilities.ReadUint8(input);
+
+                switch (curveType)
+                {
+                case ECCurveType.explicit_prime:
+                {
+                    CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_prime_curves);
+
+                    BigInteger prime_p = ReadECParameter(input);
+                    BigInteger a = ReadECFieldElement(prime_p.BitLength, input);
+                    BigInteger b = ReadECFieldElement(prime_p.BitLength, input);
+                    byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+                    BigInteger order = ReadECParameter(input);
+                    BigInteger cofactor = ReadECParameter(input);
+                    ECCurve curve = new FpCurve(prime_p, a, b, order, cofactor);
+                    ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+                    return new ECDomainParameters(curve, basePoint, order, cofactor);
+                }
+                case ECCurveType.explicit_char2:
+                {
+                    CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_char2_curves);
+
+                    int m = TlsUtilities.ReadUint16(input);
+                    byte basis = TlsUtilities.ReadUint8(input);
+                    if (!ECBasisType.IsValid(basis))
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+                    int k1 = ReadECExponent(m, input), k2 = -1, k3 = -1;
+                    if (basis == ECBasisType.ec_basis_pentanomial)
+                    {
+                        k2 = ReadECExponent(m, input);
+                        k3 = ReadECExponent(m, input);
+                    }
+
+                    BigInteger a = ReadECFieldElement(m, input);
+                    BigInteger b = ReadECFieldElement(m, input);
+                    byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+                    BigInteger order = ReadECParameter(input);
+                    BigInteger cofactor = ReadECParameter(input);
+
+                    ECCurve curve = (basis == ECBasisType.ec_basis_pentanomial)
+                        ? new F2mCurve(m, k1, k2, k3, a, b, order, cofactor)
+                        : new F2mCurve(m, k1, a, b, order, cofactor);
+
+                    ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+
+                    return new ECDomainParameters(curve, basePoint, order, cofactor);
+                }
+                case ECCurveType.named_curve:
+                {
+                    int namedCurve = TlsUtilities.ReadUint16(input);
+                    if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+                    {
+                        /*
+                         * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a
+                         * specific curve. Values of NamedCurve that indicate support for a class of
+                         * explicitly defined curves are not allowed here [...].
+                         */
+                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                    }
+
+                    CheckNamedCurve(namedCurves, namedCurve);
+
+                    return GetParametersForNamedCurve(namedCurve);
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+            }
+        }
+
+        private static void CheckNamedCurve(int[] namedCurves, int namedCurve)
+        {
+            if (namedCurves != null && !Arrays.Contains(namedCurves, namedCurve))
+            {
+                /*
+                 * RFC 4492 4. [...] servers MUST NOT negotiate the use of an ECC cipher suite
+                 * unless they can complete the handshake while respecting the choice of curves
+                 * and compression techniques specified by the client.
+                 */
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+        }
+
+        public static void WriteECExponent(int k, Stream output)
+        {
+            BigInteger K = BigInteger.ValueOf(k);
+            WriteECParameter(K, output);
+        }
+
+        public static void WriteECFieldElement(ECFieldElement x, Stream output)
+        {
+            TlsUtilities.WriteOpaque8(x.GetEncoded(), output);
+        }
+
+        public static void WriteECFieldElement(int fieldSize, BigInteger x, Stream output)
+        {
+            TlsUtilities.WriteOpaque8(SerializeECFieldElement(fieldSize, x), output);
+        }
+
+        public static void WriteECParameter(BigInteger x, Stream output)
+        {
+            TlsUtilities.WriteOpaque8(BigIntegers.AsUnsignedByteArray(x), output);
+        }
+
+        public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters,
+            Stream output)
+        {
+            ECCurve curve = ecParameters.Curve;
+
+            if (ECAlgorithms.IsFpCurve(curve))
+            {
+                TlsUtilities.WriteUint8(ECCurveType.explicit_prime, output);
+
+                WriteECParameter(curve.Field.Characteristic, output);
+            }
+            else if (ECAlgorithms.IsF2mCurve(curve))
+            {
+                IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
+                int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
+
+                TlsUtilities.WriteUint8(ECCurveType.explicit_char2, output);
+
+                int m = exponents[exponents.Length - 1];
+                TlsUtilities.CheckUint16(m);
+                TlsUtilities.WriteUint16(m, output);
+
+                if (exponents.Length == 3)
+                {
+                    TlsUtilities.WriteUint8(ECBasisType.ec_basis_trinomial, output);
+                    WriteECExponent(exponents[1], output);
+                }
+                else if (exponents.Length == 5)
+                {
+                    TlsUtilities.WriteUint8(ECBasisType.ec_basis_pentanomial, output);
+                    WriteECExponent(exponents[1], output);
+                    WriteECExponent(exponents[2], output);
+                    WriteECExponent(exponents[3], output);
+                }
+                else
+                {
+                    throw new ArgumentException("Only trinomial and pentomial curves are supported");
+                }
+            }
+            else
+            {
+                throw new ArgumentException("'ecParameters' not a known curve type");
+            }
+
+            WriteECFieldElement(curve.A, output);
+            WriteECFieldElement(curve.B, output);
+            TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
+            WriteECParameter(ecParameters.N, output);
+            WriteECParameter(ecParameters.H, output);
+        }
+
+        public static void WriteECPoint(byte[] ecPointFormats, ECPoint point, Stream output)
+        {
+            TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, point), output);
+        }
+
+        public static void WriteNamedECParameters(int namedCurve, Stream output)
+        {
+            if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+            {
+                /*
+                 * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a specific
+                 * curve. Values of NamedCurve that indicate support for a class of explicitly defined
+                 * curves are not allowed here [...].
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            TlsUtilities.WriteUint8(ECCurveType.named_curve, output);
+            TlsUtilities.CheckUint16(namedCurve);
+            TlsUtilities.WriteUint16(namedCurve, output);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsEncryptionCredentials.cs b/crypto/src/crypto/tls/TlsEncryptionCredentials.cs
new file mode 100644
index 000000000..52f007006
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsEncryptionCredentials.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public interface TlsEncryptionCredentials
+        :   TlsCredentials
+    {
+        /// <exception cref="IOException"></exception>
+        byte[] DecryptPreMasterSecret(byte[] encryptedPreMasterSecret);
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsExtensionsUtilities.cs b/crypto/src/crypto/tls/TlsExtensionsUtilities.cs
new file mode 100644
index 000000000..8876911e6
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsExtensionsUtilities.cs
@@ -0,0 +1,243 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class TlsExtensionsUtilities
+    {
+        public static IDictionary EnsureExtensionsInitialised(IDictionary extensions)
+        {
+            return extensions == null ? Platform.CreateHashtable() : extensions;
+        }
+
+        public static void AddEncryptThenMacExtension(IDictionary extensions)
+        {
+            extensions[ExtensionType.encrypt_then_mac] = CreateEncryptThenMacExtension();
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static void AddHeartbeatExtension(IDictionary extensions, HeartbeatExtension heartbeatExtension)
+        {
+            extensions[ExtensionType.heartbeat] = CreateHeartbeatExtension(heartbeatExtension);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static void AddMaxFragmentLengthExtension(IDictionary extensions, byte maxFragmentLength)
+        {
+            extensions[ExtensionType.max_fragment_length] = CreateMaxFragmentLengthExtension(maxFragmentLength);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static void AddServerNameExtension(IDictionary extensions, ServerNameList serverNameList)
+        {
+            extensions[ExtensionType.server_name] = CreateServerNameExtension(serverNameList);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static void AddStatusRequestExtension(IDictionary extensions, CertificateStatusRequest statusRequest)
+        {
+            extensions[ExtensionType.status_request] = CreateStatusRequestExtension(statusRequest);
+        }
+
+        public static void AddTruncatedHMacExtension(IDictionary extensions)
+        {
+            extensions[ExtensionType.truncated_hmac] = CreateTruncatedHMacExtension();
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static HeartbeatExtension GetHeartbeatExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.heartbeat);
+            return extensionData == null ? null : ReadHeartbeatExtension(extensionData);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static short GetMaxFragmentLengthExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.max_fragment_length);
+            return extensionData == null ? (short)-1 : (short)ReadMaxFragmentLengthExtension(extensionData);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static ServerNameList GetServerNameExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name);
+            return extensionData == null ? null : ReadServerNameExtension(extensionData);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static CertificateStatusRequest GetStatusRequestExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request);
+            return extensionData == null ? null : ReadStatusRequestExtension(extensionData);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static bool HasEncryptThenMacExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.encrypt_then_mac);
+            return extensionData == null ? false : ReadEncryptThenMacExtension(extensionData);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static bool HasTruncatedHMacExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.truncated_hmac);
+            return extensionData == null ? false : ReadTruncatedHMacExtension(extensionData);
+        }
+
+        public static byte[] CreateEmptyExtensionData()
+        {
+            return TlsUtilities.EmptyBytes;
+        }
+
+        public static byte[] CreateEncryptThenMacExtension()
+        {
+            return CreateEmptyExtensionData();
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static byte[] CreateHeartbeatExtension(HeartbeatExtension heartbeatExtension)
+        {
+            if (heartbeatExtension == null)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            MemoryStream buf = new MemoryStream();
+
+            heartbeatExtension.Encode(buf);
+
+            return buf.ToArray();
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static byte[] CreateMaxFragmentLengthExtension(byte maxFragmentLength)
+        {
+            if (!MaxFragmentLength.IsValid(maxFragmentLength))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            return new byte[]{ maxFragmentLength };
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static byte[] CreateServerNameExtension(ServerNameList serverNameList)
+        {
+            if (serverNameList == null)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            MemoryStream buf = new MemoryStream();
+        
+            serverNameList.Encode(buf);
+
+            return buf.ToArray();
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static byte[] CreateStatusRequestExtension(CertificateStatusRequest statusRequest)
+        {
+            if (statusRequest == null)
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            MemoryStream buf = new MemoryStream();
+
+            statusRequest.Encode(buf);
+
+            return buf.ToArray();
+        }
+
+        public static byte[] CreateTruncatedHMacExtension()
+        {
+            return CreateEmptyExtensionData();
+        }
+
+        /// <exception cref="IOException"></exception>
+        private static bool ReadEmptyExtensionData(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            if (extensionData.Length != 0)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            return true;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static bool ReadEncryptThenMacExtension(byte[] extensionData)
+        {
+            return ReadEmptyExtensionData(extensionData);
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static HeartbeatExtension ReadHeartbeatExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, false);
+
+            HeartbeatExtension heartbeatExtension = HeartbeatExtension.Parse(buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return heartbeatExtension;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static short ReadMaxFragmentLengthExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            if (extensionData.Length != 1)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            byte maxFragmentLength = extensionData[0];
+
+            if (!MaxFragmentLength.IsValid(maxFragmentLength))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            return maxFragmentLength;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static ServerNameList ReadServerNameExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, false);
+
+            ServerNameList serverNameList = ServerNameList.Parse(buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return serverNameList;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static CertificateStatusRequest ReadStatusRequestExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, false);
+
+            CertificateStatusRequest statusRequest = CertificateStatusRequest.Parse(buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return statusRequest;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public static bool ReadTruncatedHMacExtension(byte[] extensionData)
+        {
+            return ReadEmptyExtensionData(extensionData);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsFatalAlert.cs b/crypto/src/crypto/tls/TlsFatalAlert.cs
index 0a9cc6f3a..0c7ed88d9 100644
--- a/crypto/src/crypto/tls/TlsFatalAlert.cs
+++ b/crypto/src/crypto/tls/TlsFatalAlert.cs
@@ -3,19 +3,25 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public class TlsFatalAlert
-		: IOException
-	{
-		private readonly AlertDescription alertDescription;
+    public class TlsFatalAlert
+        : IOException
+    {
+        private readonly byte alertDescription;
 
-		public TlsFatalAlert(AlertDescription alertDescription)
-		{
-			this.alertDescription = alertDescription;
-		}
+        public TlsFatalAlert(byte alertDescription)
+            : this(alertDescription, null)
+        {
+        }
 
-		public AlertDescription AlertDescription
-		{
-			get { return alertDescription; }
-		}
-	}
+        public TlsFatalAlert(byte alertDescription, Exception alertCause)
+            :   base("Fatal alert: " + alertDescription, alertCause)
+        {
+            this.alertDescription = alertDescription;
+        }
+
+        public virtual byte AlertDescription
+        {
+            get { return alertDescription; }
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsHandshakeHash.cs b/crypto/src/crypto/tls/TlsHandshakeHash.cs
new file mode 100644
index 000000000..7118d9769
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsHandshakeHash.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public interface TlsHandshakeHash
+        :   IDigest
+    {
+        void Init(TlsContext context);
+
+        TlsHandshakeHash NotifyPrfDetermined();
+
+        void TrackHashAlgorithm(byte hashAlgorithm);
+
+        void SealHashAlgorithms();
+
+        TlsHandshakeHash StopTracking();
+
+        IDigest ForkPrfHash();
+
+        byte[] GetFinalHash(byte hashAlgorithm);
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsKeyExchange.cs b/crypto/src/crypto/tls/TlsKeyExchange.cs
index 5102edbec..6731f6f63 100644
--- a/crypto/src/crypto/tls/TlsKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsKeyExchange.cs
@@ -3,36 +3,52 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// A generic interface for key exchange implementations in TLS 1.0.
-	/// </summary>
-	public interface TlsKeyExchange
-	{
-		/// <exception cref="IOException"/>
-		void SkipServerCertificate();
-
-		/// <exception cref="IOException"/>
-		void ProcessServerCertificate(Certificate serverCertificate);
-
-		/// <exception cref="IOException"/>
-		void SkipServerKeyExchange();
-
-		/// <exception cref="IOException"/>
-		void ProcessServerKeyExchange(Stream input);
-
-		/// <exception cref="IOException"/>
-		void ValidateCertificateRequest(CertificateRequest certificateRequest);
-
-		/// <exception cref="IOException"/>
-		void SkipClientCredentials();
-
-		/// <exception cref="IOException"/>
-		void ProcessClientCredentials(TlsCredentials clientCredentials);
-		
-		/// <exception cref="IOException"/>
-		void GenerateClientKeyExchange(Stream output);
-
-		/// <exception cref="IOException"/>
-		byte[] GeneratePremasterSecret();
-	}
+    /// <summary>
+    /// A generic interface for key exchange implementations in (D)TLS.
+    /// </summary>
+    public interface TlsKeyExchange
+    {
+        void Init(TlsContext context);
+
+        /// <exception cref="IOException"/>
+        void SkipServerCredentials();
+
+        /// <exception cref="IOException"/>
+        void ProcessServerCredentials(TlsCredentials serverCredentials);
+
+        /// <exception cref="IOException"/>
+        void ProcessServerCertificate(Certificate serverCertificate);
+
+        bool RequiresServerKeyExchange { get; }
+
+        /// <exception cref="IOException"/>
+        byte[] GenerateServerKeyExchange();
+
+        /// <exception cref="IOException"/>
+        void SkipServerKeyExchange();
+
+        /// <exception cref="IOException"/>
+        void ProcessServerKeyExchange(Stream input);
+
+        /// <exception cref="IOException"/>
+        void ValidateCertificateRequest(CertificateRequest certificateRequest);
+
+        /// <exception cref="IOException"/>
+        void SkipClientCredentials();
+
+        /// <exception cref="IOException"/>
+        void ProcessClientCredentials(TlsCredentials clientCredentials);
+
+        /// <exception cref="IOException"/>
+        void ProcessClientCertificate(Certificate clientCertificate);
+
+        /// <exception cref="IOException"/>
+        void GenerateClientKeyExchange(Stream output);
+
+        /// <exception cref="IOException"/>
+        void ProcessClientKeyExchange(Stream input);
+
+        /// <exception cref="IOException"/>
+        byte[] GeneratePremasterSecret();
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsMac.cs b/crypto/src/crypto/tls/TlsMac.cs
index 0e58b89dc..a80319a17 100644
--- a/crypto/src/crypto/tls/TlsMac.cs
+++ b/crypto/src/crypto/tls/TlsMac.cs
@@ -9,98 +9,165 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <remarks>
-	/// A generic TLS MAC implementation, which can be used with any kind of
-	/// IDigest to act as an HMAC.
-	/// </remarks>
-	public class TlsMac
-	{
-		protected long seqNo;
-		protected byte[] secret;
-		protected HMac mac;
-
-		/**
-		* Generate a new instance of an TlsMac.
-		*
-		* @param digest    The digest to use.
-		* @param key_block A byte-array where the key for this mac is located.
-		* @param offset    The number of bytes to skip, before the key starts in the buffer.
-		* @param len       The length of the key.
-		*/
-		public TlsMac(
-			IDigest	digest,
-			byte[]	key_block,
-			int		offset,
-			int		len)
-		{
-			this.seqNo = 0;
-
-			KeyParameter param = new KeyParameter(key_block, offset, len);
-
-			this.secret = Arrays.Clone(param.GetKey());
-
-			this.mac = new HMac(digest);
-			this.mac.Init(param);
-		}
-
-		/**
-		 * @return the MAC write secret
-		 */
-		public virtual byte[] GetMacSecret()
-		{
-			return this.secret;
-		}
-
-		/**
-		 * @return the current write sequence number
-		 */
-		public virtual long SequenceNumber
-		{
-			get { return this.seqNo; }
-		}
-
-		/**
-		 * Increment the current write sequence number
-		 */
-		public virtual void IncSequenceNumber()
-		{
-			this.seqNo++;
-		}
-
-		/**
-		* @return The Keysize of the mac.
-		*/
-		public virtual int Size
-		{
-			get { return mac.GetMacSize(); }
-		}
-
-		/**
-		* Calculate the mac for some given data.
-		* <p/>
-		* TlsMac will keep track of the sequence number internally.
-		*
-		* @param type    The message type of the message.
-		* @param message A byte-buffer containing the message.
-		* @param offset  The number of bytes to skip, before the message starts.
-		* @param len     The length of the message.
-		* @return A new byte-buffer containing the mac value.
-		*/
-		public virtual byte[] CalculateMac(
-			ContentType	type,
-			byte[]		message,
-			int			offset,
-			int			len)
-		{
-			byte[] macHeader = new byte[13];
-			TlsUtilities.WriteUint64(seqNo++, macHeader, 0);
-			TlsUtilities.WriteUint8((byte)type, macHeader, 8);
-			TlsUtilities.WriteVersion(macHeader, 9);
-			TlsUtilities.WriteUint16(len, macHeader, 11);
-
-			mac.BlockUpdate(macHeader, 0, macHeader.Length);
-			mac.BlockUpdate(message, offset, len);
-			return MacUtilities.DoFinal(mac);
-		}
-	}
+    /// <summary>
+    /// A generic TLS MAC implementation, acting as an HMAC based on some underlying Digest.
+    /// </summary>
+    public class TlsMac
+    {
+        protected readonly TlsContext context;
+        protected readonly byte[] secret;
+        protected readonly IMac mac;
+        protected readonly int digestBlockSize;
+        protected readonly int digestOverhead;
+        protected readonly int macLength;
+
+        /**
+         * Generate a new instance of an TlsMac.
+         *
+         * @param context the TLS client context
+         * @param digest  The digest to use.
+         * @param key     A byte-array where the key for this MAC is located.
+         * @param keyOff  The number of bytes to skip, before the key starts in the buffer.
+         * @param keyLen  The length of the key.
+         */
+        public TlsMac(TlsContext context, IDigest digest, byte[] key, int keyOff, int keyLen)
+        {
+            this.context = context;
+
+            KeyParameter keyParameter = new KeyParameter(key, keyOff, keyLen);
+
+            this.secret = Arrays.Clone(keyParameter.GetKey());
+
+            // TODO This should check the actual algorithm, not rely on the engine type
+            if (digest is LongDigest)
+            {
+                this.digestBlockSize = 128;
+                this.digestOverhead = 16;
+            }
+            else
+            {
+                this.digestBlockSize = 64;
+                this.digestOverhead = 8;
+            }
+
+            if (TlsUtilities.IsSsl(context))
+            {
+                this.mac = new Ssl3Mac(digest);
+
+                // TODO This should check the actual algorithm, not assume based on the digest size
+                if (digest.GetDigestSize() == 20)
+                {
+                    /*
+                     * NOTE: When SHA-1 is used with the SSL 3.0 MAC, the secret + input pad is not
+                     * digest block-aligned.
+                     */
+                    this.digestOverhead = 4;
+                }
+            }
+            else
+            {
+                this.mac = new HMac(digest);
+
+                // NOTE: The input pad for HMAC is always a full digest block
+            }
+
+            this.mac.Init(keyParameter);
+
+            this.macLength = mac.GetMacSize();
+            if (context.SecurityParameters.truncatedHMac)
+            {
+                this.macLength = System.Math.Min(this.macLength, 10);
+            }
+        }
+
+        /**
+         * @return the MAC write secret
+         */
+        public virtual byte[] MacSecret
+        {
+            get { return this.secret; }
+        }
+
+        /**
+         * @return The output length of this MAC.
+         */
+        public virtual int Size
+        {
+            get { return macLength; }
+        }
+
+        /**
+         * Calculate the MAC for some given data.
+         *
+         * @param type    The message type of the message.
+         * @param message A byte-buffer containing the message.
+         * @param offset  The number of bytes to skip, before the message starts.
+         * @param length  The length of the message.
+         * @return A new byte-buffer containing the MAC value.
+         */
+        public virtual byte[] CalculateMac(long seqNo, byte type, byte[] message, int offset, int length)
+        {
+            ProtocolVersion serverVersion = context.ServerVersion;
+            bool isSsl = serverVersion.IsSsl;
+
+            byte[] macHeader = new byte[isSsl ? 11 : 13];
+            TlsUtilities.WriteUint64(seqNo, macHeader, 0);
+            TlsUtilities.WriteUint8(type, macHeader, 8);
+            if (!isSsl)
+            {
+                TlsUtilities.WriteVersion(serverVersion, macHeader, 9);
+            }
+            TlsUtilities.WriteUint16(length, macHeader, macHeader.Length - 2);
+
+            mac.BlockUpdate(macHeader, 0, macHeader.Length);
+            mac.BlockUpdate(message, offset, length);
+
+            return Truncate(MacUtilities.DoFinal(mac));
+        }
+
+        public virtual byte[] CalculateMacConstantTime(long seqNo, byte type, byte[] message, int offset, int length,
+            int fullLength, byte[] dummyData)
+        {
+            /*
+             * Actual MAC only calculated on 'length' bytes...
+             */
+            byte[] result = CalculateMac(seqNo, type, message, offset, length);
+
+            /*
+             * ...but ensure a constant number of complete digest blocks are processed (as many as would
+             * be needed for 'fullLength' bytes of input).
+             */
+            int headerLength = TlsUtilities.IsSsl(context) ? 11 : 13;
+
+            // How many extra full blocks do we need to calculate?
+            int extra = GetDigestBlockCount(headerLength + fullLength) - GetDigestBlockCount(headerLength + length);
+
+            while (--extra >= 0)
+            {
+                mac.BlockUpdate(dummyData, 0, digestBlockSize);
+            }
+
+            // One more byte in case the implementation is "lazy" about processing blocks
+            mac.Update(dummyData[0]);
+            mac.Reset();
+
+            return result;
+        }
+
+        protected virtual int GetDigestBlockCount(int inputLength)
+        {
+            // NOTE: This calculation assumes a minimum of 1 pad byte
+            return (inputLength + digestOverhead) / digestBlockSize;
+        }
+
+        protected virtual byte[] Truncate(byte[] bs)
+        {
+            if (bs.Length <= macLength)
+            {
+                return bs;
+            }
+
+            return Arrays.CopyOf(bs, macLength);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsNullCipher.cs b/crypto/src/crypto/tls/TlsNullCipher.cs
index b76f76d9c..f30ace24f 100644
--- a/crypto/src/crypto/tls/TlsNullCipher.cs
+++ b/crypto/src/crypto/tls/TlsNullCipher.cs
@@ -1,28 +1,118 @@
 using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// A NULL cipher suite, for use during handshake.
-	/// </summary>
-	public class TlsNullCipher
-		: TlsCipher
-	{
-		public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len)
-		{
-			return CopyData(plaintext, offset, len);
-		}
-
-        public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len)
-		{
-			return CopyData(ciphertext, offset, len);
-		}
-
-		protected virtual byte[] CopyData(byte[] text, int offset, int len)
-		{
-			byte[] result = new byte[len];
-			Array.Copy(text, offset, result, 0, len);
-			return result;
-		}
-	}
+    /// <summary>
+    /// A NULL CipherSuite, with optional MAC.
+    /// </summary>
+    public class TlsNullCipher
+        :   TlsCipher
+    {
+        protected readonly TlsContext context;
+
+        protected readonly TlsMac writeMac;
+        protected readonly TlsMac readMac;
+
+        public TlsNullCipher(TlsContext context)
+        {
+            this.context = context;
+            this.writeMac = null;
+            this.readMac = null;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public TlsNullCipher(TlsContext context, IDigest clientWriteDigest, IDigest serverWriteDigest)
+        {
+            if ((clientWriteDigest == null) != (serverWriteDigest == null))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            this.context = context;
+
+            TlsMac clientWriteMac = null, serverWriteMac = null;
+
+            if (clientWriteDigest != null)
+            {
+                int key_block_size = clientWriteDigest.GetDigestSize()
+                    + serverWriteDigest.GetDigestSize();
+                byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+                int offset = 0;
+
+                clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+                    clientWriteDigest.GetDigestSize());
+                offset += clientWriteDigest.GetDigestSize();
+
+                serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+                    serverWriteDigest.GetDigestSize());
+                offset += serverWriteDigest.GetDigestSize();
+
+                if (offset != key_block_size)
+                {
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+                }
+            }
+
+            if (context.IsServer)
+            {
+                writeMac = serverWriteMac;
+                readMac = clientWriteMac;
+            }
+            else
+            {
+                writeMac = clientWriteMac;
+                readMac = serverWriteMac;
+            }
+        }
+
+        public virtual int GetPlaintextLimit(int ciphertextLimit)
+        {
+            int result = ciphertextLimit;
+            if (writeMac != null)
+            {
+                result -= writeMac.Size;
+            }
+            return result;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+        {
+            if (writeMac == null)
+            {
+                return Arrays.CopyOfRange(plaintext, offset, offset + len);
+            }
+
+            byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len);
+            byte[] ciphertext = new byte[len + mac.Length];
+            Array.Copy(plaintext, offset, ciphertext, 0, len);
+            Array.Copy(mac, 0, ciphertext, len, mac.Length);
+            return ciphertext;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+        {
+            if (readMac == null)
+            {
+                return Arrays.CopyOfRange(ciphertext, offset, offset + len);
+            }
+
+            int macSize = readMac.Size;
+            if (len < macSize)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int macInputLen = len - macSize;
+
+            byte[] receivedMac = Arrays.CopyOfRange(ciphertext, offset + macInputLen, offset + len);
+            byte[] computedMac = readMac.CalculateMac(seqNo, type, ciphertext, offset, macInputLen);
+
+            if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac))
+                throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+
+            return Arrays.CopyOfRange(ciphertext, offset, offset + macInputLen);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsNullCompression.cs b/crypto/src/crypto/tls/TlsNullCompression.cs
new file mode 100644
index 000000000..45f8fc708
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsNullCompression.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public class TlsNullCompression
+		: TlsCompression
+	{
+		public virtual Stream Compress(Stream output)
+		{
+			return output;
+		}
+
+		public virtual Stream Decompress(Stream output)
+		{
+			return output;
+		}
+	}
+}
diff --git a/crypto/src/crypto/tls/TlsPeer.cs b/crypto/src/crypto/tls/TlsPeer.cs
new file mode 100644
index 000000000..1ae41a41a
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsPeer.cs
@@ -0,0 +1,62 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public interface TlsPeer
+    {
+        /// <summary>
+        /// draft-mathewson-no-gmtunixtime-00 2. "If existing users of a TLS implementation may rely on
+        /// gmt_unix_time containing the current time, we recommend that implementors MAY provide the
+        /// ability to set gmt_unix_time as an option only, off by default."
+        /// </summary>
+        /// <returns>
+        /// <code>true</code> if the current time should be used in the gmt_unix_time field of
+        /// Random, or <code>false</code> if gmt_unix_time should contain a cryptographically
+        /// random value.
+        /// </returns>
+        bool ShouldUseGmtUnixTime();
+
+        /// <summary>
+        /// Report whether the server supports secure renegotiation
+        /// </summary>
+        /// <remarks>
+        /// The protocol handler automatically processes the relevant extensions
+        /// </remarks>
+        /// <param name="secureRenegotiation">
+        /// A <see cref="System.Boolean"/>, true if the server supports secure renegotiation
+        /// </param>
+        /// <exception cref="IOException"></exception>
+        void NotifySecureRenegotiation(bool secureRenegotiation);
+
+        /// <summary>
+        /// Return an implementation of <see cref="TlsCompression"/> to handle record compression.
+        /// </summary>
+        /// <returns>A <see cref="TlsCompression"/></returns>
+        /// <exception cref="IOException"/>
+        TlsCompression GetCompression();
+
+        /// <summary>
+        /// Return an implementation of <see cref="TlsCipher"/> to use for encryption/decryption.
+        /// </summary>
+        /// <returns>A <see cref="TlsCipher"/></returns>
+        /// <exception cref="IOException"/>
+        TlsCipher GetCipher();
+
+        /// <summary>This method will be called when an alert is raised by the protocol.</summary>
+        /// <param name="alertLevel"><see cref="AlertLevel"/></param>
+        /// <param name="alertDescription"><see cref="AlertDescription"/></param>
+        /// <param name="message">A human-readable message explaining what caused this alert. May be null.</param>
+        /// <param name="cause">The <c>Exception</c> that caused this alert to be raised. May be null.</param>
+        void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause);
+
+        /// <summary>This method will be called when an alert is received from the remote peer.</summary>
+        /// <param name="alertLevel"><see cref="AlertLevel"/></param>
+        /// <param name="alertDescription"><see cref="AlertDescription"/></param>
+        void NotifyAlertReceived(byte alertLevel, byte alertDescription);
+
+        /// <summary>Notifies the peer that the handshake has been successfully completed.</summary>
+        /// <exception cref="IOException"></exception>
+        void NotifyHandshakeComplete();
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
new file mode 100644
index 000000000..8ba156952
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -0,0 +1,1102 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class TlsProtocol
+    {
+        private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
+
+        /*
+         * Our Connection states
+         */
+        protected const short CS_START = 0;
+        protected const short CS_CLIENT_HELLO = 1;
+        protected const short CS_SERVER_HELLO = 2;
+        protected const short CS_SERVER_SUPPLEMENTAL_DATA = 3;
+        protected const short CS_SERVER_CERTIFICATE = 4;
+        protected const short CS_CERTIFICATE_STATUS = 5;
+        protected const short CS_SERVER_KEY_EXCHANGE = 6;
+        protected const short CS_CERTIFICATE_REQUEST = 7;
+        protected const short CS_SERVER_HELLO_DONE = 8;
+        protected const short CS_CLIENT_SUPPLEMENTAL_DATA = 9;
+        protected const short CS_CLIENT_CERTIFICATE = 10;
+        protected const short CS_CLIENT_KEY_EXCHANGE = 11;
+        protected const short CS_CERTIFICATE_VERIFY = 12;
+        protected const short CS_CLIENT_FINISHED = 13;
+        protected const short CS_SERVER_SESSION_TICKET = 14;
+        protected const short CS_SERVER_FINISHED = 15;
+        protected const short CS_END = 16;
+
+        /*
+         * Queues for data from some protocols.
+         */
+        private ByteQueue mApplicationDataQueue = new ByteQueue();
+        private ByteQueue mAlertQueue = new ByteQueue(2);
+        private ByteQueue mHandshakeQueue = new ByteQueue();
+    //    private ByteQueue mHeartbeatQueue = new ByteQueue();
+
+        /*
+         * The Record Stream we use
+         */
+        internal RecordStream mRecordStream;
+        protected SecureRandom mSecureRandom;
+
+        private TlsStream mTlsStream = null;
+
+        private volatile bool mClosed = false;
+        private volatile bool mFailedWithError = false;
+        private volatile bool mAppDataReady = false;
+        private volatile bool mSplitApplicationDataRecords = true;
+        private byte[] mExpectedVerifyData = null;
+
+        protected TlsSession mTlsSession = null;
+        protected SessionParameters mSessionParameters = null;
+        protected SecurityParameters mSecurityParameters = null;
+        protected Certificate mPeerCertificate = null;
+
+        protected int[] mOfferedCipherSuites = null;
+        protected byte[] mOfferedCompressionMethods = null;
+        protected IDictionary mClientExtensions = null;
+        protected IDictionary mServerExtensions = null;
+
+        protected short mConnectionState = CS_START;
+        protected bool mResumedSession = false;
+        protected bool mReceivedChangeCipherSpec = false;
+        protected bool mSecureRenegotiation = false;
+        protected bool mAllowCertificateStatus = false;
+        protected bool mExpectSessionTicket = false;
+
+        public TlsProtocol(Stream stream, SecureRandom secureRandom)
+            :   this(stream, stream, secureRandom)
+        {
+        }
+
+        public TlsProtocol(Stream input, Stream output, SecureRandom secureRandom)
+        {
+            this.mRecordStream = new RecordStream(this, input, output);
+            this.mSecureRandom = secureRandom;
+        }
+
+        protected abstract TlsContext Context { get; }
+
+        internal abstract AbstractTlsContext ContextAdmin { get; }
+
+        protected abstract TlsPeer Peer { get; }
+
+        protected virtual void HandleChangeCipherSpecMessage()
+        {
+        }
+
+        protected abstract void HandleHandshakeMessage(byte type, byte[] buf);
+
+        protected virtual void HandleWarningMessage(byte description)
+        {
+        }
+
+        protected virtual void CleanupHandshake()
+        {
+            if (this.mExpectedVerifyData != null)
+            {
+                Arrays.Fill(this.mExpectedVerifyData, (byte)0);
+                this.mExpectedVerifyData = null;
+            }
+
+            this.mSecurityParameters.Clear();
+            this.mPeerCertificate = null;
+
+            this.mOfferedCipherSuites = null;
+            this.mOfferedCompressionMethods = null;
+            this.mClientExtensions = null;
+            this.mServerExtensions = null;
+
+            this.mResumedSession = false;
+            this.mReceivedChangeCipherSpec = false;
+            this.mSecureRenegotiation = false;
+            this.mAllowCertificateStatus = false;
+            this.mExpectSessionTicket = false;
+        }
+
+        protected virtual void CompleteHandshake()
+        {
+            try
+            {
+                /*
+                 * We will now read data, until we have completed the handshake.
+                 */
+                while (this.mConnectionState != CS_END)
+                {
+                    if (this.mClosed)
+                    {
+                        // TODO What kind of exception/alert?
+                    }
+
+                    SafeReadRecord();
+                }
+
+                this.mRecordStream.FinaliseHandshake();
+
+                this.mSplitApplicationDataRecords = !TlsUtilities.IsTlsV11(Context);
+
+                /*
+                 * If this was an initial handshake, we are now ready to send and receive application data.
+                 */
+                if (!mAppDataReady)
+                {
+                    this.mAppDataReady = true;
+
+                    this.mTlsStream = new TlsStream(this);
+                }
+
+                if (this.mTlsSession != null)
+                {
+                    if (this.mSessionParameters == null)
+                    {
+                        this.mSessionParameters = new SessionParameters.Builder()
+                            .SetCipherSuite(this.mSecurityParameters.cipherSuite)
+                            .SetCompressionAlgorithm(this.mSecurityParameters.compressionAlgorithm)
+                            .SetMasterSecret(this.mSecurityParameters.masterSecret)
+                            .SetPeerCertificate(this.mPeerCertificate)
+                            // TODO Consider filtering extensions that aren't relevant to resumed sessions
+                            .SetServerExtensions(this.mServerExtensions)
+                            .Build();
+
+                        this.mTlsSession = new TlsSessionImpl(this.mTlsSession.SessionID, this.mSessionParameters);
+                    }
+
+                    ContextAdmin.SetResumableSession(this.mTlsSession);
+                }
+
+                Peer.NotifyHandshakeComplete();
+            }
+            finally
+            {
+                CleanupHandshake();
+            }
+        }
+
+        protected internal void ProcessRecord(byte protocol, byte[] buf, int offset, int len)
+        {
+            /*
+             * Have a look at the protocol type, and add it to the correct queue.
+             */
+            switch (protocol)
+            {
+            case ContentType.alert:
+            {
+                mAlertQueue.AddData(buf, offset, len);
+                ProcessAlert();
+                break;
+            }
+            case ContentType.application_data:
+            {
+                if (!mAppDataReady)
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+                mApplicationDataQueue.AddData(buf, offset, len);
+                ProcessApplicationData();
+                break;
+            }
+            case ContentType.change_cipher_spec:
+            {
+                ProcessChangeCipherSpec(buf, offset, len);
+                break;
+            }
+            case ContentType.handshake:
+            {
+                mHandshakeQueue.AddData(buf, offset, len);
+                ProcessHandshake();
+                break;
+            }
+            case ContentType.heartbeat:
+            {
+                if (!mAppDataReady)
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+                // TODO[RFC 6520]
+    //            mHeartbeatQueue.AddData(buf, offset, len);
+    //            ProcessHeartbeat();
+                break;
+            }
+            default:
+                /*
+                 * Uh, we don't know this protocol.
+                 * 
+                 * RFC2246 defines on page 13, that we should ignore this.
+                 */
+                break;
+            }
+        }
+
+        private void ProcessHandshake()
+        {
+            bool read;
+            do
+            {
+                read = false;
+                /*
+                 * We need the first 4 bytes, they contain type and length of the message.
+                 */
+                if (mHandshakeQueue.Available >= 4)
+                {
+                    byte[] beginning = new byte[4];
+                    mHandshakeQueue.Read(beginning, 0, 4, 0);
+                    byte type = TlsUtilities.ReadUint8(beginning, 0);
+                    int len = TlsUtilities.ReadUint24(beginning, 1);
+
+                    /*
+                     * Check if we have enough bytes in the buffer to read the full message.
+                     */
+                    if (mHandshakeQueue.Available >= (len + 4))
+                    {
+                        /*
+                         * Read the message.
+                         */
+                        byte[] buf = mHandshakeQueue.RemoveData(len, 4);
+
+                        /*
+                         * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
+                         * starting at client hello up to, but not including, this finished message.
+                         * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
+                         */
+                        switch (type)
+                        {
+                        case HandshakeType.hello_request:
+                            break;
+                        case HandshakeType.finished:
+                        default:
+                            if (type == HandshakeType.finished && this.mExpectedVerifyData == null)
+                            {
+                                this.mExpectedVerifyData = CreateVerifyData(!Context.IsServer);
+                            }
+
+                            mRecordStream.UpdateHandshakeData(beginning, 0, 4);
+                            mRecordStream.UpdateHandshakeData(buf, 0, len);
+                            break;
+                        }
+
+                        /*
+                         * Now, parse the message.
+                         */
+                        HandleHandshakeMessage(type, buf);
+                        read = true;
+                    }
+                }
+            }
+            while (read);
+        }
+
+        private void ProcessApplicationData()
+        {
+            /*
+             * There is nothing we need to do here.
+             * 
+             * This function could be used for callbacks when application data arrives in the future.
+             */
+        }
+
+        private void ProcessAlert()
+        {
+            while (mAlertQueue.Available >= 2)
+            {
+                /*
+                 * An alert is always 2 bytes. Read the alert.
+                 */
+                byte[] tmp = mAlertQueue.RemoveData(2, 0);
+                byte level = tmp[0];
+                byte description = tmp[1];
+
+                Peer.NotifyAlertReceived(level, description);
+
+                if (level == AlertLevel.fatal)
+                {
+                    /*
+                     * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
+                     * without proper close_notify messages with level equal to warning.
+                     */
+                    InvalidateSession();
+
+                    this.mFailedWithError = true;
+                    this.mClosed = true;
+
+                    mRecordStream.SafeClose();
+
+                    throw new IOException(TLS_ERROR_MESSAGE);
+                }
+                else
+                {
+
+                    /*
+                     * RFC 5246 7.2.1. The other party MUST respond with a close_notify alert of its own
+                     * and close down the connection immediately, discarding any pending writes.
+                     */
+                    // TODO Can close_notify be a fatal alert?
+                    if (description == AlertDescription.close_notify)
+                    {
+                        HandleClose(false);
+                    }
+
+                    /*
+                     * If it is just a warning, we continue.
+                     */
+                    HandleWarningMessage(description);
+                }
+            }
+        }
+
+        /**
+         * This method is called, when a change cipher spec message is received.
+         *
+         * @throws IOException If the message has an invalid content or the handshake is not in the correct
+         * state.
+         */
+        private void ProcessChangeCipherSpec(byte[] buf, int off, int len)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                byte message = TlsUtilities.ReadUint8(buf, off + i);
+
+                if (message != ChangeCipherSpec.change_cipher_spec)
+                    throw new TlsFatalAlert(AlertDescription.decode_error);
+
+                if (this.mReceivedChangeCipherSpec
+                    || mAlertQueue.Available > 0
+                    || mHandshakeQueue.Available > 0)
+                {
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+
+                mRecordStream.ReceivedReadCipherSpec();
+
+                this.mReceivedChangeCipherSpec = true;
+
+                HandleChangeCipherSpecMessage();
+            }
+        }
+
+        protected internal virtual int ApplicationDataAvailable()
+        {
+            return mApplicationDataQueue.Available;
+        }
+
+        /**
+         * Read data from the network. The method will return immediately, if there is still some data
+         * left in the buffer, or block until some application data has been read from the network.
+         *
+         * @param buf    The buffer where the data will be copied to.
+         * @param offset The position where the data will be placed in the buffer.
+         * @param len    The maximum number of bytes to read.
+         * @return The number of bytes read.
+         * @throws IOException If something goes wrong during reading data.
+         */
+        protected internal virtual int ReadApplicationData(byte[] buf, int offset, int len)
+        {
+            if (len < 1)
+                return 0;
+
+            while (mApplicationDataQueue.Available == 0)
+            {
+                /*
+                 * We need to read some data.
+                 */
+                if (this.mClosed)
+                {
+                    if (this.mFailedWithError)
+                    {
+                        /*
+                         * Something went terribly wrong, we should throw an IOException
+                         */
+                        throw new IOException(TLS_ERROR_MESSAGE);
+                    }
+
+                    /*
+                     * Connection has been closed, there is no more data to read.
+                     */
+                    return 0;
+                }
+
+                SafeReadRecord();
+            }
+
+            len = System.Math.Min(len, mApplicationDataQueue.Available);
+            mApplicationDataQueue.RemoveData(buf, offset, len, 0);
+            return len;
+        }
+
+        protected virtual void SafeReadRecord()
+        {
+            try
+            {
+                if (!mRecordStream.ReadRecord())
+                {
+                    // TODO It would be nicer to allow graceful connection close if between records
+    //                this.FailWithError(AlertLevel.warning, AlertDescription.close_notify);
+                    throw new EndOfStreamException();
+                }
+            }
+            catch (TlsFatalAlert e)
+            {
+                if (!mClosed)
+                {
+                    this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to read record", e);
+                }
+                throw e;
+            }
+            catch (Exception e)
+            {
+                if (!mClosed)
+                {
+                    this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to read record", e);
+                }
+                throw e;
+            }
+        }
+
+        protected virtual void SafeWriteRecord(byte type, byte[] buf, int offset, int len)
+        {
+            try
+            {
+                mRecordStream.WriteRecord(type, buf, offset, len);
+            }
+            catch (TlsFatalAlert e)
+            {
+                if (!mClosed)
+                {
+                    this.FailWithError(AlertLevel.fatal, e.AlertDescription, "Failed to write record", e);
+                }
+                throw e;
+            }
+            catch (Exception e)
+            {
+                if (!mClosed)
+                {
+                    this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error, "Failed to write record", e);
+                }
+                throw e;
+            }
+        }
+
+        /**
+         * Send some application data to the remote system.
+         * <p/>
+         * The method will handle fragmentation internally.
+         *
+         * @param buf    The buffer with the data.
+         * @param offset The position in the buffer where the data is placed.
+         * @param len    The length of the data.
+         * @throws IOException If something goes wrong during sending.
+         */
+        protected internal virtual void WriteData(byte[] buf, int offset, int len)
+        {
+            if (this.mClosed)
+            {
+                if (this.mFailedWithError)
+                    throw new IOException(TLS_ERROR_MESSAGE);
+
+                throw new IOException("Sorry, connection has been closed, you cannot write more data");
+            }
+
+            while (len > 0)
+            {
+                /*
+                 * RFC 5246 6.2.1. Zero-length fragments of Application data MAY be sent as they are
+                 * potentially useful as a traffic analysis countermeasure.
+                 * 
+                 * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting.
+                 */
+
+                if (this.mSplitApplicationDataRecords)
+                {
+                    /*
+                     * Protect against known IV attack!
+                     * 
+                     * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE.
+                     */
+                    SafeWriteRecord(ContentType.application_data, buf, offset, 1);
+                    ++offset;
+                    --len;
+                }
+
+                if (len > 0)
+                {
+                    // Fragment data according to the current fragment limit.
+                    int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
+                    SafeWriteRecord(ContentType.application_data, buf, offset, toWrite);
+                    offset += toWrite;
+                    len -= toWrite;
+                }
+            }
+        }
+
+        protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len)
+        {
+            while (len > 0)
+            {
+                // Fragment data according to the current fragment limit.
+                int toWrite = System.Math.Min(len, mRecordStream.GetPlaintextLimit());
+                SafeWriteRecord(ContentType.handshake, buf, off, toWrite);
+                off += toWrite;
+                len -= toWrite;
+            }
+        }
+
+        /// <summary>The secure bidirectional stream for this connection</summary>
+        public virtual Stream Stream
+        {
+            get { return this.mTlsStream; }
+        }
+
+        /**
+         * Terminate this connection with an alert. Can be used for normal closure too.
+         * 
+         * @param alertLevel
+         *            See {@link AlertLevel} for values.
+         * @param alertDescription
+         *            See {@link AlertDescription} for values.
+         * @throws IOException
+         *             If alert was fatal.
+         */
+        protected virtual void FailWithError(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            /*
+             * Check if the connection is still open.
+             */
+            if (!mClosed)
+            {
+                /*
+                 * Prepare the message
+                 */
+                this.mClosed = true;
+
+                if (alertLevel == AlertLevel.fatal)
+                {
+                    /*
+                     * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated
+                     * without proper close_notify messages with level equal to warning.
+                     */
+                    // TODO This isn't quite in the right place. Also, as of TLS 1.1 the above is obsolete.
+                    InvalidateSession();
+
+                    this.mFailedWithError = true;
+                }
+                RaiseAlert(alertLevel, alertDescription, message, cause);
+                mRecordStream.SafeClose();
+                if (alertLevel != AlertLevel.fatal)
+                {
+                    return;
+                }
+            }
+
+            throw new IOException(TLS_ERROR_MESSAGE);
+        }
+
+        protected virtual void InvalidateSession()
+        {
+            if (this.mSessionParameters != null)
+            {
+                this.mSessionParameters.Clear();
+                this.mSessionParameters = null;
+            }
+
+            if (this.mTlsSession != null)
+            {
+                this.mTlsSession.Invalidate();
+                this.mTlsSession = null;
+            }
+        }
+
+        protected virtual void ProcessFinishedMessage(MemoryStream buf)
+        {
+            byte[] verify_data = TlsUtilities.ReadFully(mExpectedVerifyData.Length, buf);
+
+            AssertEmpty(buf);
+
+            /*
+             * Compare both checksums.
+             */
+            if (!Arrays.ConstantTimeAreEqual(mExpectedVerifyData, verify_data))
+            {
+                /*
+                 * Wrong checksum in the finished message.
+                 */
+                throw new TlsFatalAlert(AlertDescription.decrypt_error);
+            }
+        }
+
+        protected virtual void RaiseAlert(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            Peer.NotifyAlertRaised(alertLevel, alertDescription, message, cause);
+
+            byte[] error = new byte[]{ alertLevel, alertDescription };
+
+            SafeWriteRecord(ContentType.alert, error, 0, 2);
+        }
+
+        protected virtual void RaiseWarning(byte alertDescription, string message)
+        {
+            RaiseAlert(AlertLevel.warning, alertDescription, message, null);
+        }
+
+        protected virtual void SendCertificateMessage(Certificate certificate)
+        {
+            if (certificate == null)
+            {
+                certificate = Certificate.EmptyChain;
+            }
+
+            if (certificate.IsEmpty)
+            {
+                TlsContext context = Context;
+                if (!context.IsServer)
+                {
+                    ProtocolVersion serverVersion = Context.ServerVersion;
+                    if (serverVersion.IsSsl)
+                    {
+                        string errorMessage = serverVersion.ToString() + " client didn't provide credentials";
+                        RaiseWarning(AlertDescription.no_certificate, errorMessage);
+                        return;
+                    }
+                }
+            }
+
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate);
+
+            certificate.Encode(message);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual void SendChangeCipherSpecMessage()
+        {
+            byte[] message = new byte[]{ 1 };
+            SafeWriteRecord(ContentType.change_cipher_spec, message, 0, message.Length);
+            mRecordStream.SentWriteCipherSpec();
+        }
+
+        protected virtual void SendFinishedMessage()
+        {
+            byte[] verify_data = CreateVerifyData(Context.IsServer);
+
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.finished, verify_data.Length);
+
+            message.Write(verify_data, 0, verify_data.Length);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual void SendSupplementalDataMessage(IList supplementalData)
+        {
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.supplemental_data);
+
+            WriteSupplementalData(message, supplementalData);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual byte[] CreateVerifyData(bool isServer)
+        {
+            TlsContext context = Context;
+            string asciiLabel = isServer ? ExporterLabel.server_finished : ExporterLabel.client_finished;
+            byte[] sslSender = isServer ? TlsUtilities.SSL_SERVER : TlsUtilities.SSL_CLIENT;
+            byte[] hash = GetCurrentPrfHash(context, mRecordStream.HandshakeHash, sslSender);
+            return TlsUtilities.CalculateVerifyData(context, asciiLabel, hash);
+        }
+
+        /**
+         * Closes this connection.
+         *
+         * @throws IOException If something goes wrong during closing.
+         */
+        public virtual void Close()
+        {
+            HandleClose(true);
+        }
+
+        protected virtual void HandleClose(bool user_canceled)
+        {
+            if (!mClosed)
+            {
+                if (user_canceled && !mAppDataReady)
+                {
+                    RaiseWarning(AlertDescription.user_canceled, "User canceled handshake");
+                }
+                this.FailWithError(AlertLevel.warning, AlertDescription.close_notify, "Connection closed", null);
+            }
+        }
+
+        protected internal virtual void Flush()
+        {
+            mRecordStream.Flush();
+        }
+
+        protected internal virtual bool IsClosed
+        {
+            get { return mClosed; }
+        }
+
+        protected virtual short ProcessMaxFragmentLengthExtension(IDictionary clientExtensions, IDictionary serverExtensions,
+            byte alertDescription)
+        {
+            short maxFragmentLength = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(serverExtensions);
+            if (maxFragmentLength >= 0 && !this.mResumedSession)
+            {
+                if (maxFragmentLength != TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions))
+                    throw new TlsFatalAlert(alertDescription);
+            }
+            return maxFragmentLength;
+        }
+
+        /**
+         * Make sure the InputStream 'buf' now empty. Fail otherwise.
+         *
+         * @param buf The InputStream to check.
+         * @throws IOException If 'buf' is not empty.
+         */
+        protected internal static void AssertEmpty(MemoryStream buf)
+        {
+            if (buf.Position < buf.Length)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+        }
+
+        protected internal static byte[] CreateRandomBlock(bool useGmtUnixTime, IRandomGenerator randomGenerator)
+        {
+            byte[] result = new byte[32];
+            randomGenerator.NextBytes(result);
+
+            if (useGmtUnixTime)
+            {
+                TlsUtilities.WriteGmtUnixTime(result, 0);
+            }
+
+            return result;
+        }
+
+        protected internal static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection)
+        {
+            return TlsUtilities.EncodeOpaque8(renegotiated_connection);
+        }
+
+        protected internal static void EstablishMasterSecret(TlsContext context, TlsKeyExchange keyExchange)
+        {
+            byte[] pre_master_secret = keyExchange.GeneratePremasterSecret();
+
+            try
+            {
+                context.SecurityParameters.masterSecret = TlsUtilities.CalculateMasterSecret(context, pre_master_secret);
+            }
+            finally
+            {
+                // TODO Is there a way to ensure the data is really overwritten?
+                /*
+                 * RFC 2246 8.1. The pre_master_secret should be deleted from memory once the
+                 * master_secret has been computed.
+                 */
+                if (pre_master_secret != null)
+                {
+                    Arrays.Fill(pre_master_secret, (byte)0);
+                }
+            }
+        }
+
+        /**
+         * 'sender' only relevant to SSLv3
+         */
+        protected internal static byte[] GetCurrentPrfHash(TlsContext context, TlsHandshakeHash handshakeHash, byte[] sslSender)
+        {
+            IDigest d = handshakeHash.ForkPrfHash();
+
+            if (sslSender != null && TlsUtilities.IsSsl(context))
+            {
+                d.BlockUpdate(sslSender, 0, sslSender.Length);
+            }
+
+            return DigestUtilities.DoFinal(d);
+        }
+
+        protected internal static IDictionary ReadExtensions(MemoryStream input)
+        {
+            if (input.Position >= input.Length)
+                return null;
+
+            byte[] extBytes = TlsUtilities.ReadOpaque16(input);
+
+            AssertEmpty(input);
+
+            MemoryStream buf = new MemoryStream(extBytes, false);
+
+            // Integer -> byte[]
+            IDictionary extensions = Platform.CreateHashtable();
+
+            while (buf.Position < buf.Length)
+            {
+                int extension_type = TlsUtilities.ReadUint16(buf);
+                byte[] extension_data = TlsUtilities.ReadOpaque16(buf);
+
+                /*
+                 * RFC 3546 2.3 There MUST NOT be more than one extension of the same type.
+                 */
+                if (extensions.Contains(extension_type))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+                extensions.Add(extension_type, extension_data);
+            }
+
+            return extensions;
+        }
+
+        protected internal static IList ReadSupplementalDataMessage(MemoryStream input)
+        {
+            byte[] supp_data = TlsUtilities.ReadOpaque24(input);
+
+            AssertEmpty(input);
+
+            MemoryStream buf = new MemoryStream(supp_data, false);
+
+            IList supplementalData = Platform.CreateArrayList();
+
+            while (buf.Position < buf.Length)
+            {
+                int supp_data_type = TlsUtilities.ReadUint16(buf);
+                byte[] data = TlsUtilities.ReadOpaque16(buf);
+
+                supplementalData.Add(new SupplementalDataEntry(supp_data_type, data));
+            }
+
+            return supplementalData;
+        }
+
+        protected internal static void WriteExtensions(Stream output, IDictionary extensions)
+        {
+            MemoryStream buf = new MemoryStream();
+
+            foreach (int extension_type in extensions.Keys)
+            {
+                byte[] extension_data = (byte[])extensions[extension_type];
+
+                TlsUtilities.CheckUint16(extension_type);
+                TlsUtilities.WriteUint16(extension_type, buf);
+                TlsUtilities.WriteOpaque16(extension_data, buf);
+            }
+
+            byte[] extBytes = buf.ToArray();
+
+            TlsUtilities.WriteOpaque16(extBytes, output);
+        }
+
+        protected internal static void WriteSupplementalData(Stream output, IList supplementalData)
+        {
+            MemoryStream buf = new MemoryStream();
+
+            foreach (SupplementalDataEntry entry in supplementalData)
+            {
+                int supp_data_type = entry.DataType;
+                TlsUtilities.CheckUint16(supp_data_type);
+                TlsUtilities.WriteUint16(supp_data_type, buf);
+                TlsUtilities.WriteOpaque16(entry.Data, buf);
+            }
+
+            byte[] supp_data = buf.ToArray();
+
+            TlsUtilities.WriteOpaque24(supp_data, output);
+        }
+
+        protected internal static int GetPrfAlgorithm(TlsContext context, int ciphersuite)
+        {
+            bool isTLSv12 = TlsUtilities.IsTlsV12(context);
+
+            switch (ciphersuite)
+            {
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+            {
+                if (isTLSv12)
+                {
+                    return PrfAlgorithm.tls_prf_sha256;
+                }
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            {
+                if (isTLSv12)
+                {
+                    return PrfAlgorithm.tls_prf_sha384;
+                }
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+            {
+                if (isTLSv12)
+                {
+                    return PrfAlgorithm.tls_prf_sha384;
+                }
+                return PrfAlgorithm.tls_prf_legacy;
+            }
+
+            default:
+            {
+                if (isTLSv12)
+                {
+                    return PrfAlgorithm.tls_prf_sha256;
+                }
+                return PrfAlgorithm.tls_prf_legacy;
+            }
+            }
+        }
+
+        internal class HandshakeMessage
+            :   MemoryStream
+        {
+            internal HandshakeMessage(byte handshakeType)
+                :   this(handshakeType, 60)
+            {
+            }
+
+            internal HandshakeMessage(byte handshakeType, int length)
+                :   base(length + 4)
+            {
+                TlsUtilities.WriteUint8(handshakeType, this);
+                // Reserve space for length
+                TlsUtilities.WriteUint24(0, this);
+            }
+
+            internal void Write(byte[] data)
+            {
+                Write(data, 0, data.Length);
+            }
+
+            internal void WriteToRecordStream(TlsProtocol protocol)
+            {
+                // Patch actual length back in
+                long length = Length - 4;
+                TlsUtilities.CheckUint24(length);
+                this.Position = 1;
+                TlsUtilities.WriteUint24((int)length, this);
+                protocol.WriteHandshakeMessage(GetBuffer(), 0, (int)Length);
+                this.Close();
+            }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsProtocolHandler.cs b/crypto/src/crypto/tls/TlsProtocolHandler.cs
index 6d2b0b144..6f223467f 100644
--- a/crypto/src/crypto/tls/TlsProtocolHandler.cs
+++ b/crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -21,1239 +21,19 @@ using Org.BouncyCastle.Utilities.Date;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <remarks>An implementation of all high level protocols in TLS 1.0.</remarks>
-	public class TlsProtocolHandler
-	{
-		/*
-		* Our Connection states
-		*/
-		private const short CS_CLIENT_HELLO_SEND = 1;
-		private const short CS_SERVER_HELLO_RECEIVED = 2;
-		private const short CS_SERVER_CERTIFICATE_RECEIVED = 3;
-		private const short CS_SERVER_KEY_EXCHANGE_RECEIVED = 4;
-		private const short CS_CERTIFICATE_REQUEST_RECEIVED = 5;
-		private const short CS_SERVER_HELLO_DONE_RECEIVED = 6;
-		private const short CS_CLIENT_KEY_EXCHANGE_SEND = 7;
-		private const short CS_CERTIFICATE_VERIFY_SEND = 8;
-		private const short CS_CLIENT_CHANGE_CIPHER_SPEC_SEND = 9;
-		private const short CS_CLIENT_FINISHED_SEND = 10;
-		private const short CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED = 11;
-		private const short CS_DONE = 12;
-
-		private static readonly byte[] emptybuf = new byte[0];
-
-		private static readonly string TLS_ERROR_MESSAGE = "Internal TLS error, this could be an attack";
-
-		/*
-		* Queues for data from some protocols.
-		*/
-
-		private ByteQueue applicationDataQueue = new ByteQueue();
-		private ByteQueue changeCipherSpecQueue = new ByteQueue();
-		private ByteQueue alertQueue = new ByteQueue();
-		private ByteQueue handshakeQueue = new ByteQueue();
-
-		/*
-		* The Record Stream we use
-		*/
-		private RecordStream rs;
-		private SecureRandom random;
-
-		private TlsStream tlsStream = null;
-
-		private bool closed = false;
-		private bool failedWithError = false;
-		private bool appDataReady = false;
-		private IDictionary clientExtensions;
-
-		private SecurityParameters securityParameters = null;
-
-		private TlsClientContextImpl tlsClientContext = null;
-		private TlsClient tlsClient = null;
-		private CipherSuite[] offeredCipherSuites = null;
-		private CompressionMethod[] offeredCompressionMethods = null;
-        private TlsKeyExchange keyExchange = null;
-		private TlsAuthentication authentication = null;
-		private CertificateRequest certificateRequest = null;
-
-		private short connection_state = 0;
-
-		private static SecureRandom CreateSecureRandom()
-		{
-			/*
-			 * We use our threaded seed generator to generate a good random seed. If the user
-			 * has a better random seed, he should use the constructor with a SecureRandom.
-			 *
-			 * Hopefully, 20 bytes in fast mode are good enough.
-			 */
-			byte[] seed = new ThreadedSeedGenerator().GenerateSeed(20, true);
-
-			return new SecureRandom(seed);
-		}
-
-		public TlsProtocolHandler(
-			Stream s)
-			: this(s, s)
-		{
-		}
-
-		public TlsProtocolHandler(
-			Stream			s,
-			SecureRandom	sr)
-			: this(s, s, sr)
-		{
-		}
-
-		/// <remarks>Both streams can be the same object</remarks>
-		public TlsProtocolHandler(
-			Stream	inStr,
-			Stream	outStr)
-			: this(inStr, outStr, CreateSecureRandom())
-		{
-		}
-
-		/// <remarks>Both streams can be the same object</remarks>
-		public TlsProtocolHandler(
-			Stream			inStr,
-			Stream			outStr,
-			SecureRandom	sr)
-		{
-			this.rs = new RecordStream(this, inStr, outStr);
-			this.random = sr;
-		}
-
-		internal void ProcessData(
-			ContentType	protocol,
-			byte[]		buf,
-			int			offset,
-			int			len)
-		{
-			/*
-			* Have a look at the protocol type, and add it to the correct queue.
-			*/
-			switch (protocol)
-			{
-				case ContentType.change_cipher_spec:
-					changeCipherSpecQueue.AddData(buf, offset, len);
-					ProcessChangeCipherSpec();
-					break;
-				case ContentType.alert:
-					alertQueue.AddData(buf, offset, len);
-					ProcessAlert();
-					break;
-				case ContentType.handshake:
-					handshakeQueue.AddData(buf, offset, len);
-					ProcessHandshake();
-					break;
-				case ContentType.application_data:
-					if (!appDataReady)
-					{
-						this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-					}
-					applicationDataQueue.AddData(buf, offset, len);
-					ProcessApplicationData();
-					break;
-				default:
-					/*
-					* Uh, we don't know this protocol.
-					*
-					* RFC2246 defines on page 13, that we should ignore this.
-					*/
-					break;
-			}
-		}
-
-		private void ProcessHandshake()
-		{
-			bool read;
-			do
-			{
-				read = false;
-
-				/*
-				* We need the first 4 bytes, they contain type and length of
-				* the message.
-				*/
-				if (handshakeQueue.Available >= 4)
-				{
-					byte[] beginning = new byte[4];
-					handshakeQueue.Read(beginning, 0, 4, 0);
-					MemoryStream bis = new MemoryStream(beginning, false);
-					HandshakeType type = (HandshakeType)TlsUtilities.ReadUint8(bis);
-					int len = TlsUtilities.ReadUint24(bis);
-
-					/*
-					* Check if we have enough bytes in the buffer to read
-					* the full message.
-					*/
-					if (handshakeQueue.Available >= (len + 4))
-					{
-						/*
-						* Read the message.
-						*/
-						byte[] buf = new byte[len];
-						handshakeQueue.Read(buf, 0, len, 4);
-						handshakeQueue.RemoveData(len + 4);
-
-						/*
-						 * RFC 2246 7.4.9. The value handshake_messages includes all
-						 * handshake messages starting at client hello up to, but not
-						 * including, this finished message. [..] Note: [Also,] Hello Request
-						 * messages are omitted from handshake hashes.
-						 */
-						switch (type)
-						{
-							case HandshakeType.hello_request:
-							case HandshakeType.finished:
-								break;
-							default:
-								rs.UpdateHandshakeData(beginning, 0, 4);
-								rs.UpdateHandshakeData(buf, 0, len);
-								break;
-						}
-
-						/*
-						* Now, parse the message.
-						*/
-						ProcessHandshakeMessage(type, buf);
-						read = true;
-					}
-				}
-			}
-			while (read);
-		}
-
-		private void ProcessHandshakeMessage(HandshakeType type, byte[] buf)
-		{
-			MemoryStream inStr = new MemoryStream(buf, false);
-
-			/*
-			* Check the type.
-			*/
-			switch (type)
-			{
-				case HandshakeType.certificate:
-				{
-					switch (connection_state)
-					{
-						case CS_SERVER_HELLO_RECEIVED:
-						{
-							// Parse the Certificate message and send to cipher suite
-
-							Certificate serverCertificate = Certificate.Parse(inStr);
-
-							AssertEmpty(inStr);
-
-							this.keyExchange.ProcessServerCertificate(serverCertificate);
-
-							this.authentication = tlsClient.GetAuthentication();
-							this.authentication.NotifyServerCertificate(serverCertificate);
-
-							break;
-						}
-						default:
-							this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-							break;
-					}
-
-					connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
-					break;
-				}
-				case HandshakeType.finished:
-					switch (connection_state)
-					{
-						case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
-							/*
-							 * Read the checksum from the finished message, it has always 12 bytes.
-							 */
-							byte[] serverVerifyData = new byte[12];
-							TlsUtilities.ReadFully(serverVerifyData, inStr);
-
-							AssertEmpty(inStr);
-
-							/*
-							 * Calculate our own checksum.
-							 */
-							byte[] expectedServerVerifyData = TlsUtilities.PRF(
-								securityParameters.masterSecret, "server finished",
-								rs.GetCurrentHash(), 12);
-
-							/*
-							 * Compare both checksums.
-							 */
-							if (!Arrays.ConstantTimeAreEqual(expectedServerVerifyData, serverVerifyData))
-							{
-								/*
-								 * Wrong checksum in the finished message.
-								 */
-								this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
-							}
-
-							connection_state = CS_DONE;
-
-							/*
-							* We are now ready to receive application data.
-							*/
-							this.appDataReady = true;
-							break;
-						default:
-							this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-							break;
-					}
-					break;
-				case HandshakeType.server_hello:
-					switch (connection_state)
-					{
-						case CS_CLIENT_HELLO_SEND:
-							/*
-							 * Read the server hello message
-							 */
-							TlsUtilities.CheckVersion(inStr);
-
-							/*
-							 * Read the server random
-							 */
-							securityParameters.serverRandom = new byte[32];
-							TlsUtilities.ReadFully(securityParameters.serverRandom, inStr);
-
-							byte[] sessionID = TlsUtilities.ReadOpaque8(inStr);
-							if (sessionID.Length > 32)
-							{
-								this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
-							}
-
-							this.tlsClient.NotifySessionID(sessionID);
-
-							/*
-							 * Find out which CipherSuite the server has chosen and check that
-							 * it was one of the offered ones.
-							 */
-							CipherSuite selectedCipherSuite = (CipherSuite)TlsUtilities.ReadUint16(inStr);
-							if (!ArrayContains(offeredCipherSuites, selectedCipherSuite)
-								|| selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
-							{
-								this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
-							}
-
-							this.tlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
-
-                            /*
-                             * Find out which CompressionMethod the server has chosen and check that
-                             * it was one of the offered ones.
-                             */
-                            CompressionMethod selectedCompressionMethod = (CompressionMethod)TlsUtilities.ReadUint8(inStr);
-							if (!ArrayContains(offeredCompressionMethods, selectedCompressionMethod))
-							{
-								this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
-							}
-
-                            this.tlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
-
-	                        /*
-	                         * RFC3546 2.2 The extended server hello message format MAY be
-	                         * sent in place of the server hello message when the client has
-	                         * requested extended functionality via the extended client hello
-	                         * message specified in Section 2.1.
-							 * ...
-							 * Note that the extended server hello message is only sent in response
-							 * to an extended client hello message.  This prevents the possibility
-							 * that the extended server hello message could "break" existing TLS 1.0
-							 * clients.
-	                         */
-
-							/*
-							 * TODO RFC 3546 2.3
-							 * If [...] the older session is resumed, then the server MUST ignore
-							 * extensions appearing in the client hello, and send a server hello
-							 * containing no extensions.
-							 */
-
-							// ExtensionType -> byte[]
-							IDictionary serverExtensions = Platform.CreateHashtable();
-
-							if (inStr.Position < inStr.Length)
-							{
-								// Process extensions from extended server hello
-                                byte[] extBytes = TlsUtilities.ReadOpaque16(inStr);
-
-                                MemoryStream ext = new MemoryStream(extBytes, false);
-                                while (ext.Position < ext.Length)
-								{
-                                    ExtensionType extType = (ExtensionType)TlsUtilities.ReadUint16(ext);
-                                    byte[] extValue = TlsUtilities.ReadOpaque16(ext);
-
-									// Note: RFC 5746 makes a special case for EXT_RenegotiationInfo
-                                    if (extType != ExtensionType.renegotiation_info
-										&& !clientExtensions.Contains(extType))
-									{
-										/*
-										 * RFC 3546 2.3
-										 * Note that for all extension types (including those defined in
-										 * future), the extension type MUST NOT appear in the extended server
-										 * hello unless the same extension type appeared in the corresponding
-										 * client hello.  Thus clients MUST abort the handshake if they receive
-										 * an extension type in the extended server hello that they did not
-										 * request in the associated (extended) client hello.
-										 */
-										this.FailWithError(AlertLevel.fatal, AlertDescription.unsupported_extension);
-									}
-
-									if (serverExtensions.Contains(extType))
-									{
-										/*
-										 * RFC 3546 2.3
-										 * Also note that when multiple extensions of different types are
-										 * present in the extended client hello or the extended server hello,
-										 * the extensions may appear in any order. There MUST NOT be more than
-										 * one extension of the same type.
-										 */
-										this.FailWithError(AlertLevel.fatal, AlertDescription.illegal_parameter);
-									}
-
-									serverExtensions.Add(extType, extValue);
-								}
-							}
-
-							AssertEmpty(inStr);
-
-							/*
-							 * RFC 5746 3.4. When a ServerHello is received, the client MUST check if it
-							 * includes the "renegotiation_info" extension:
-							 */
-							{
-								bool secure_negotiation = serverExtensions.Contains(ExtensionType.renegotiation_info);
-
-								/*
-								 * If the extension is present, set the secure_renegotiation flag
-								 * to TRUE.  The client MUST then verify that the length of the
-								 * "renegotiated_connection" field is zero, and if it is not, MUST
-								 * abort the handshake (by sending a fatal handshake_failure
-								 * alert).
-								 */
-								if (secure_negotiation)
-								{
-                                    byte[] renegExtValue = (byte[])serverExtensions[ExtensionType.renegotiation_info];
-
-                                    if (!Arrays.ConstantTimeAreEqual(renegExtValue,
-                                        CreateRenegotiationInfo(emptybuf)))
-									{
-										this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
-									}
-								}
-
-								tlsClient.NotifySecureRenegotiation(secure_negotiation);
-							}
-
-							if (clientExtensions != null)
-							{
-								tlsClient.ProcessServerExtensions(serverExtensions);
-							}
-
-							this.keyExchange = tlsClient.GetKeyExchange();
-
-	                        connection_state = CS_SERVER_HELLO_RECEIVED;
-	                        break;
-						default:
-							this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-							break;
-					}
-					break;
-				case HandshakeType.server_hello_done:
-					switch (connection_state)
-					{
-						case CS_SERVER_HELLO_RECEIVED:
-						case CS_SERVER_CERTIFICATE_RECEIVED:
-						case CS_SERVER_KEY_EXCHANGE_RECEIVED:
-						case CS_CERTIFICATE_REQUEST_RECEIVED:
-
-							// NB: Original code used case label fall-through
-
-							if (connection_state == CS_SERVER_HELLO_RECEIVED)
-							{
-								// There was no server certificate message; check it's OK
-								this.keyExchange.SkipServerCertificate();
-								this.authentication = null;
-
-								// There was no server key exchange message; check it's OK
-								this.keyExchange.SkipServerKeyExchange();
-							}
-							else if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
-							{
-								// There was no server key exchange message; check it's OK
-								this.keyExchange.SkipServerKeyExchange();
-							}
-
-							AssertEmpty(inStr);
-
-							connection_state = CS_SERVER_HELLO_DONE_RECEIVED;
-
-							TlsCredentials clientCreds = null;
-							if (certificateRequest == null)
-							{
-								this.keyExchange.SkipClientCredentials();
-							}
-							else
-							{
-								clientCreds = this.authentication.GetClientCredentials(certificateRequest);
-
-								Certificate clientCert;
-								if (clientCreds == null)
-								{
-									this.keyExchange.SkipClientCredentials();
-									clientCert = Certificate.EmptyChain;
-								}
-								else
-								{
-									this.keyExchange.ProcessClientCredentials(clientCreds);
-									clientCert = clientCreds.Certificate;
-								}
-
-								SendClientCertificate(clientCert);
-							}
-
-							/*
-							 * Send the client key exchange message, depending on the key
-							 * exchange we are using in our CipherSuite.
-							 */
-							SendClientKeyExchange();
-
-							connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;
-
-							if (clientCreds != null && clientCreds is TlsSignerCredentials)
-							{
-								TlsSignerCredentials signerCreds = (TlsSignerCredentials)clientCreds;
-								byte[] md5andsha1 = rs.GetCurrentHash();
-								byte[] clientCertificateSignature = signerCreds.GenerateCertificateSignature(
-									md5andsha1);
-								SendCertificateVerify(clientCertificateSignature);
-
-								connection_state = CS_CERTIFICATE_VERIFY_SEND;
-							}
-					
-							/*
-							* Now, we send change cipher state
-							*/
-							byte[] cmessage = new byte[1];
-							cmessage[0] = 1;
-							rs.WriteMessage(ContentType.change_cipher_spec, cmessage, 0, cmessage.Length);
-
-							connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;
-
-							/*
-							 * Calculate the master_secret
-							 */
-							byte[] pms = this.keyExchange.GeneratePremasterSecret();
-
-							securityParameters.masterSecret = TlsUtilities.PRF(pms, "master secret",
-								TlsUtilities.Concat(securityParameters.clientRandom, securityParameters.serverRandom),
-								48);
-
-							// TODO Is there a way to ensure the data is really overwritten?
-							/*
-							 * RFC 2246 8.1. The pre_master_secret should be deleted from
-							 * memory once the master_secret has been computed.
-							 */
-							Array.Clear(pms, 0, pms.Length);
-
-							/*
-							 * Initialize our cipher suite
-							 */
-	                        rs.ClientCipherSpecDecided(tlsClient.GetCompression(), tlsClient.GetCipher());
-
-							/*
-							 * Send our finished message.
-							 */
-							byte[] clientVerifyData = TlsUtilities.PRF(securityParameters.masterSecret,
-								"client finished", rs.GetCurrentHash(), 12);
-
-							MemoryStream bos = new MemoryStream();
-							TlsUtilities.WriteUint8((byte)HandshakeType.finished, bos);
-							TlsUtilities.WriteOpaque24(clientVerifyData, bos);
-							byte[] message = bos.ToArray();
-
-							rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
-
-							this.connection_state = CS_CLIENT_FINISHED_SEND;
-							break;
-						default:
-							this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
-							break;
-					}
-					break;
-				case HandshakeType.server_key_exchange:
-				{
-					switch (connection_state)
-					{
-						case CS_SERVER_HELLO_RECEIVED:
-						case CS_SERVER_CERTIFICATE_RECEIVED:
-						{
-							// NB: Original code used case label fall-through
-							if (connection_state == CS_SERVER_HELLO_RECEIVED)
-							{
-								// There was no server certificate message; check it's OK
-								this.keyExchange.SkipServerCertificate();
-								this.authentication = null;
-							}
-
-    	                    this.keyExchange.ProcessServerKeyExchange(inStr);
-
-	                        AssertEmpty(inStr);
-							break;
-						}
-						default:
-							this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-							break;
-					}
-
-					this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
-					break;
-				}
-				case HandshakeType.certificate_request:
-					switch (connection_state)
-					{
-						case CS_SERVER_CERTIFICATE_RECEIVED:
-						case CS_SERVER_KEY_EXCHANGE_RECEIVED:
-						{
-							// NB: Original code used case label fall-through
-							if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
-							{
-								// There was no server key exchange message; check it's OK
-								this.keyExchange.SkipServerKeyExchange();
-							}
-
-							if (this.authentication == null)
-							{
-								/*
-								 * RFC 2246 7.4.4. It is a fatal handshake_failure alert
-								 * for an anonymous server to request client identification.
-								 */
-								this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
-							}
-
-                            int numTypes = TlsUtilities.ReadUint8(inStr);
-                            ClientCertificateType[] certificateTypes = new ClientCertificateType[numTypes];
-                            for (int i = 0; i < numTypes; ++i)
-                            {
-                                certificateTypes[i] = (ClientCertificateType)TlsUtilities.ReadUint8(inStr);
-                            }
-
-                            byte[] authorities = TlsUtilities.ReadOpaque16(inStr);
-
-							AssertEmpty(inStr);
-
-                            IList authorityDNs = Platform.CreateArrayList();
-
-							MemoryStream bis = new MemoryStream(authorities, false);
-							while (bis.Position < bis.Length)
-							{
-								byte[] dnBytes = TlsUtilities.ReadOpaque16(bis);
-								// TODO Switch to X500Name when available
-								authorityDNs.Add(X509Name.GetInstance(Asn1Object.FromByteArray(dnBytes)));
-							}
-
-							this.certificateRequest = new CertificateRequest(certificateTypes,
-								authorityDNs);
-							this.keyExchange.ValidateCertificateRequest(this.certificateRequest);
-
-							break;
-						}
-						default:
-							this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-							break;
-					}
-
-					this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
-					break;
-				case HandshakeType.hello_request:
-					/*
-					 * RFC 2246 7.4.1.1 Hello request
-					 * This message will be ignored by the client if the client is currently
-					 * negotiating a session. This message may be ignored by the client if it
-					 * does not wish to renegotiate a session, or the client may, if it wishes,
-					 * respond with a no_renegotiation alert.
-					 */
-					if (connection_state == CS_DONE)
-					{
-						// Renegotiation not supported yet
-						SendAlert(AlertLevel.warning, AlertDescription.no_renegotiation);
-					}
-					break;
-				case HandshakeType.client_key_exchange:
-				case HandshakeType.certificate_verify:
-				case HandshakeType.client_hello:
-				default:
-					// We do not support this!
-					this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-					break;
-			}
-		}
-
-		private void ProcessApplicationData()
-		{
-			/*
-			* There is nothing we need to do here.
-			*
-			* This function could be used for callbacks when application
-			* data arrives in the future.
-			*/
-		}
-
-		private void ProcessAlert()
-		{
-			while (alertQueue.Available >= 2)
-			{
-				/*
-				* An alert is always 2 bytes. Read the alert.
-				*/
-				byte[] tmp = new byte[2];
-				alertQueue.Read(tmp, 0, 2, 0);
-				alertQueue.RemoveData(2);
-				byte level = tmp[0];
-				byte description = tmp[1];
-				if (level == (byte)AlertLevel.fatal)
-				{
-					/*
-					* This is a fatal error.
-					*/
-					this.failedWithError = true;
-					this.closed = true;
-					/*
-					* Now try to Close the stream, ignore errors.
-					*/
-					try
-					{
-						rs.Close();
-					}
-					catch (Exception)
-					{
-					}
-					throw new IOException(TLS_ERROR_MESSAGE);
-				}
-				else
-				{
-					/*
-					* This is just a warning.
-					*/
-					if (description == (byte)AlertDescription.close_notify)
-					{
-						/*
-						* Close notify
-						*/
-						this.FailWithError(AlertLevel.warning, AlertDescription.close_notify);
-					}
-					/*
-					* If it is just a warning, we continue.
-					*/
-				}
-			}
-		}
-
-		/**
-		* This method is called, when a change cipher spec message is received.
-		*
-		* @throws IOException If the message has an invalid content or the
-		*                     handshake is not in the correct state.
-		*/
-		private void ProcessChangeCipherSpec()
-		{
-			while (changeCipherSpecQueue.Available > 0)
-			{
-				/*
-				 * A change cipher spec message is only one byte with the value 1.
-				 */
-				byte[] b = new byte[1];
-				changeCipherSpecQueue.Read(b, 0, 1, 0);
-				changeCipherSpecQueue.RemoveData(1);
-				if (b[0] != 1)
-				{
-					/*
-					* This should never happen.
-					*/
-					this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message);
-				}
-
-				/*
-				 * Check if we are in the correct connection state.
-				 */
-				if (this.connection_state != CS_CLIENT_FINISHED_SEND)
-				{
-                	this.FailWithError(AlertLevel.fatal, AlertDescription.handshake_failure);
-				}
-
-				rs.ServerClientSpecReceived();
-
-            	this.connection_state = CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED;
-			}
-		}
-
-		private void SendClientCertificate(Certificate clientCert)
-		{
-			MemoryStream bos = new MemoryStream();
-			TlsUtilities.WriteUint8((byte)HandshakeType.certificate, bos);
-
-			// Reserve space for length
-			TlsUtilities.WriteUint24(0, bos);
-
-			clientCert.Encode(bos);
-			byte[] message = bos.ToArray();
-
-			// Patch actual length back in
-			TlsUtilities.WriteUint24(message.Length - 4, message, 1);
-
-			rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
-		}
-
-		private void SendClientKeyExchange()
-		{
-			MemoryStream bos = new MemoryStream();
-            TlsUtilities.WriteUint8((byte)HandshakeType.client_key_exchange, bos);
-
-			// Reserve space for length
-			TlsUtilities.WriteUint24(0, bos);
-
-			this.keyExchange.GenerateClientKeyExchange(bos);
-			byte[] message = bos.ToArray();
-
-			// Patch actual length back in
-			TlsUtilities.WriteUint24(message.Length - 4, message, 1);
-
-			rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
-		}
-
-		private void SendCertificateVerify(byte[] data)
-		{
-			/*
-			 * Send signature of handshake messages so far to prove we are the owner of
-			 * the cert See RFC 2246 sections 4.7, 7.4.3 and 7.4.8
-			 */
-			MemoryStream bos = new MemoryStream();
-            TlsUtilities.WriteUint8((byte)HandshakeType.certificate_verify, bos);
-			TlsUtilities.WriteUint24(data.Length + 2, bos);
-			TlsUtilities.WriteOpaque16(data, bos);
-			byte[] message = bos.ToArray();
-
-			rs.WriteMessage(ContentType.handshake, message, 0, message.Length);
-		}
-
-		/// <summary>Connects to the remote system.</summary>
-		/// <param name="verifyer">Will be used when a certificate is received to verify
-		/// that this certificate is accepted by the client.</param>
-		/// <exception cref="IOException">If handshake was not successful</exception>
-		[Obsolete("Use version taking TlsClient")]
-		public virtual void Connect(
-			ICertificateVerifyer verifyer)
-		{
-	        this.Connect(new LegacyTlsClient(verifyer));
-	    }
-
-		public virtual void Connect(TlsClient tlsClient)
+    [Obsolete("Use 'TlsClientProtocol' instead")]
+    public class TlsProtocolHandler
+        :   TlsClientProtocol
+    {
+        public TlsProtocolHandler(Stream stream, SecureRandom secureRandom)
+            :   base(stream, stream, secureRandom)
         {
-            if (tlsClient == null)
-                throw new ArgumentNullException("tlsClient");
-            if (this.tlsClient != null)
-                throw new InvalidOperationException("Connect can only be called once");
-
-			/*
-             * Send Client hello
-             *
-             * First, generate some random data.
-             */
-            this.securityParameters = new SecurityParameters();
-            this.securityParameters.clientRandom = new byte[32];
-            random.NextBytes(securityParameters.clientRandom, 4, 28);
-            TlsUtilities.WriteGmtUnixTime(securityParameters.clientRandom, 0);
-
-			this.tlsClientContext = new TlsClientContextImpl(random, securityParameters);
-			this.tlsClient = tlsClient;
-			this.tlsClient.Init(tlsClientContext);
-
-            MemoryStream outStr = new MemoryStream();
-            TlsUtilities.WriteVersion(outStr);
-            outStr.Write(securityParameters.clientRandom, 0, 32);
-
-            /*
-            * Length of Session id
-            */
-            TlsUtilities.WriteUint8(0, outStr);
-
-            this.offeredCipherSuites = this.tlsClient.GetCipherSuites();
-
-            // ExtensionType -> byte[]
-            this.clientExtensions = this.tlsClient.GetClientExtensions();
-
-            // Cipher Suites (and SCSV)
-            {
-                /*
-                 * RFC 5746 3.4.
-                 * The client MUST include either an empty "renegotiation_info"
-                 * extension, or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling
-                 * cipher suite value in the ClientHello.  Including both is NOT
-                 * RECOMMENDED.
-                 */
-                bool noRenegExt = clientExtensions == null
-                    || !clientExtensions.Contains(ExtensionType.renegotiation_info);
-
-                int count = offeredCipherSuites.Length;
-                if (noRenegExt)
-                {
-                    // Note: 1 extra slot for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
-                    ++count;
-                }
-
-                TlsUtilities.WriteUint16(2 * count, outStr);
-
-                for (int i = 0; i < offeredCipherSuites.Length; ++i)
-                {
-                    TlsUtilities.WriteUint16((int)offeredCipherSuites[i], outStr);
-                }
-
-                if (noRenegExt)
-                {
-                    TlsUtilities.WriteUint16((int)CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV, outStr);
-                }
-            }
-
-            /*
-             * Compression methods, just the null method.
-             */
-            this.offeredCompressionMethods = tlsClient.GetCompressionMethods();
-
-            {
-                TlsUtilities.WriteUint8((byte)offeredCompressionMethods.Length, outStr);
-                for (int i = 0; i < offeredCompressionMethods.Length; ++i)
-                {
-                    TlsUtilities.WriteUint8((byte)offeredCompressionMethods[i], outStr);
-                }
-            }
-
-            // Extensions
-            if (clientExtensions != null)
-            {
-                MemoryStream ext = new MemoryStream();
-
-                foreach (ExtensionType extType in clientExtensions.Keys)
-                {
-                    WriteExtension(ext, extType, (byte[])clientExtensions[extType]);
-                }
-
-                TlsUtilities.WriteOpaque16(ext.ToArray(), outStr);
-            }
-
-            MemoryStream bos = new MemoryStream();
-            TlsUtilities.WriteUint8((byte)HandshakeType.client_hello, bos);
-            TlsUtilities.WriteUint24((int)outStr.Length, bos);
-            byte[] outBytes = outStr.ToArray();
-            bos.Write(outBytes, 0, outBytes.Length);
-            byte[] message = bos.ToArray();
-            SafeWriteMessage(ContentType.handshake, message, 0, message.Length);
-            connection_state = CS_CLIENT_HELLO_SEND;
-
-            /*
-            * We will now read data, until we have completed the handshake.
-            */
-            while (connection_state != CS_DONE)
-            {
-				SafeReadData();
-            }
-
-            this.tlsStream = new TlsStream(this);
-        }
-
-		/**
-		* Read data from the network. The method will return immediately, if there is
-		* still some data left in the buffer, or block until some application
-		* data has been read from the network.
-		*
-		* @param buf    The buffer where the data will be copied to.
-		* @param offset The position where the data will be placed in the buffer.
-		* @param len    The maximum number of bytes to read.
-		* @return The number of bytes read.
-		* @throws IOException If something goes wrong during reading data.
-		*/
-		internal int ReadApplicationData(byte[] buf, int offset, int len)
-		{
-			while (applicationDataQueue.Available == 0)
-			{
-				if (this.closed)
-				{
-					/*
-					* We need to read some data.
-					*/
-					if (this.failedWithError)
-					{
-						/*
-						* Something went terribly wrong, we should throw an IOException
-						*/
-						throw new IOException(TLS_ERROR_MESSAGE);
-					}
-
-					/*
-					* Connection has been closed, there is no more data to read.
-					*/
-					return 0;
-				}
-
-				SafeReadData();
-			}
-			len = System.Math.Min(len, applicationDataQueue.Available);
-			applicationDataQueue.Read(buf, offset, len, 0);
-			applicationDataQueue.RemoveData(len);
-			return len;
-		}
-
-		private void SafeReadData()
-		{
-			try
-			{
-				rs.ReadData();
-			}
-			catch (TlsFatalAlert e)
-			{
-				if (!this.closed)
-				{
-					this.FailWithError(e.AlertDescription, e);
-				}
-				throw e;
-			}
-			catch (IOException e)
-			{
-				if (!this.closed)
-				{
-					this.FailWithError(AlertDescription.internal_error, e);
-				}
-				throw e;
-			}
-			catch (Exception e)
-			{
-				if (!this.closed)
-				{
-					this.FailWithError(AlertDescription.internal_error, e);
-				}
-				throw e;
-			}
-		}
-
-		private void SafeWriteMessage(ContentType type, byte[] buf, int offset, int len)
-		{
-			try
-			{
-				rs.WriteMessage(type, buf, offset, len);
-			}
-			catch (TlsFatalAlert e)
-			{
-				if (!this.closed)
-				{
-					this.FailWithError(e.AlertDescription, e);
-				}
-				throw e;
-			}
-			catch (IOException e)
-			{
-				if (!closed)
-				{
-					this.FailWithError(AlertDescription.internal_error, e);
-				}
-				throw e;
-			}
-			catch (Exception e)
-			{
-				if (!closed)
-				{
-					this.FailWithError(AlertDescription.internal_error, e);
-				}
-				throw e;
-			}
-		}
-
-		/**
-		* Send some application data to the remote system.
-		* <p/>
-		* The method will handle fragmentation internally.
-		*
-		* @param buf    The buffer with the data.
-		* @param offset The position in the buffer where the data is placed.
-		* @param len    The length of the data.
-		* @throws IOException If something goes wrong during sending.
-		*/
-		internal void WriteData(byte[] buf, int offset, int len)
-		{
-			if (this.closed)
-			{
-				if (this.failedWithError)
-					throw new IOException(TLS_ERROR_MESSAGE);
-
-				throw new IOException("Sorry, connection has been closed, you cannot write more data");
-			}
-
-			/*
-			* Protect against known IV attack!
-			*
-			* DO NOT REMOVE THIS LINE, EXCEPT YOU KNOW EXACTLY WHAT
-			* YOU ARE DOING HERE.
-			*/
-			SafeWriteMessage(ContentType.application_data, emptybuf, 0, 0);
-
-			do
-			{
-				/*
-				* We are only allowed to write fragments up to 2^14 bytes.
-				*/
-				int toWrite = System.Math.Min(len, 1 << 14);
-
-				SafeWriteMessage(ContentType.application_data, buf, offset, toWrite);
-
-				offset += toWrite;
-				len -= toWrite;
-			}
-			while (len > 0);
-		}
-
-		/// <summary>A Stream which can be used to send data.</summary>
-		[Obsolete("Use 'Stream' property instead")]
-		public virtual Stream OutputStream
-		{
-			get { return this.tlsStream; }
-		}
-
-		/// <summary>A Stream which can be used to read data.</summary>
-		[Obsolete("Use 'Stream' property instead")]
-		public virtual Stream InputStream
-		{
-			get { return this.tlsStream; }
-		}
-
-		/// <summary>The secure bidirectional stream for this connection</summary>
-		public virtual Stream Stream
-		{
-			get { return this.tlsStream; }
-		}
-
-		/**
-		* Terminate this connection with an alert.
-		* <p/>
-		* Can be used for normal closure too.
-		*
-		* @param alertLevel       The level of the alert, an be AlertLevel.fatal or AL_warning.
-		* @param alertDescription The exact alert message.
-		* @throws IOException If alert was fatal.
-		*/
-        private void FailWithError(AlertLevel alertLevel, AlertDescription alertDescription)
-        {
-            this.FailWithError(alertLevel, alertDescription, null);
         }
 
-        private void FailWithError(AlertDescription alertDescription, Exception ex)
-        {
-            this.FailWithError(AlertLevel.fatal, alertDescription, ex);
-        }
-
-        private void FailWithError(AlertLevel alertLevel, AlertDescription alertDescription, Exception ex)
-        {
-			/*
-			* Check if the connection is still open.
-			*/
-			if (!closed)
-			{
-				/*
-				* Prepare the message
-				*/
-				this.closed = true;
-
-				if (alertLevel == AlertLevel.fatal)
-				{
-					/*
-					* This is a fatal message.
-					*/
-					this.failedWithError = true;
-				}
-				SendAlert(alertLevel, alertDescription);
-				rs.Close();
-				if (alertLevel == AlertLevel.fatal)
-				{
-					throw new IOException(TLS_ERROR_MESSAGE, ex);
-				}
-			}
-			else
-			{
-				throw new IOException(TLS_ERROR_MESSAGE, ex);
-			}
-		}
-
-		internal void SendAlert(AlertLevel alertLevel, AlertDescription alertDescription)
-		{
-			byte[] error = new byte[2];
-			error[0] = (byte)alertLevel;
-			error[1] = (byte)alertDescription;
-
-			rs.WriteMessage(ContentType.alert, error, 0, 2);
-		}
-
-		/// <summary>Closes this connection</summary>
-		/// <exception cref="IOException">If something goes wrong during closing.</exception>
-		public virtual void Close()
-		{
-			if (!closed)
-			{
-				this.FailWithError(AlertLevel.warning, AlertDescription.close_notify);
-			}
-		}
-
-		/**
-		* Make sure the Stream is now empty. Fail otherwise.
-		*
-		* @param is The Stream to check.
-		* @throws IOException If is is not empty.
-		*/
-		internal void AssertEmpty(
-			MemoryStream inStr)
-		{
-			if (inStr.Position < inStr.Length)
-			{
-				throw new TlsFatalAlert(AlertDescription.decode_error);
-			}
-		}
-
-		internal void Flush()
-		{
-			rs.Flush();
-		}
-
-		internal bool IsClosed
-		{
-			get { return closed; }
-		}
-
-		private static bool ArrayContains(CipherSuite[] a, CipherSuite n)
-		{
-			for (int i = 0; i < a.Length; ++i)
-			{
-				if (a[i] == n)
-					return true;
-			}
-			return false;
-		}
-
-        private static bool ArrayContains(CompressionMethod[] a, CompressionMethod n)
+        /// <remarks>Both streams can be the same object</remarks>
+        public TlsProtocolHandler(Stream input, Stream output, SecureRandom	secureRandom)
+            :   base(input, output, secureRandom)
         {
-            for (int i = 0; i < a.Length; ++i)
-            {
-                if (a[i] == n)
-                    return true;
-            }
-            return false;
         }
-
-		private static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection)
-		{
-			MemoryStream buf = new MemoryStream();
-			TlsUtilities.WriteOpaque8(renegotiated_connection, buf);
-			return buf.ToArray();
-		}
-
-		private static void WriteExtension(Stream output, ExtensionType extType, byte[] extValue)
-		{
-			TlsUtilities.WriteUint16((int)extType, output);
-			TlsUtilities.WriteOpaque16(extValue, output);
-		}
-	}
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsPskIdentity.cs b/crypto/src/crypto/tls/TlsPskIdentity.cs
new file mode 100644
index 000000000..119064ee7
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsPskIdentity.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsPskIdentity
+	{
+		void SkipIdentityHint();
+
+		void NotifyIdentityHint(byte[] psk_identity_hint);
+
+		byte[] GetPskIdentity();
+
+		byte[] GetPsk();
+	}
+}
diff --git a/crypto/src/crypto/tls/TlsPskKeyExchange.cs b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
index 226153a97..cd13e3438 100644
--- a/crypto/src/crypto/tls/TlsPskKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsPskKeyExchange.cs
@@ -1,149 +1,254 @@
 using System;
+using System.Collections;
 using System.IO;
 
+using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsPskKeyExchange
-		: TlsKeyExchange
-	{
-		protected TlsClientContext context;
-		protected KeyExchangeAlgorithm keyExchange;
-		protected TlsPskIdentity pskIdentity;
-
-		protected byte[] psk_identity_hint = null;
-
-		protected DHPublicKeyParameters dhAgreeServerPublicKey = null;
-		protected DHPrivateKeyParameters dhAgreeClientPrivateKey = null;
-
-		protected RsaKeyParameters rsaServerPublicKey = null;
-		protected byte[] premasterSecret;
-
-		internal TlsPskKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange,
-			TlsPskIdentity pskIdentity)
-		{
-			switch (keyExchange)
-			{
-				case KeyExchangeAlgorithm.PSK:
-				case KeyExchangeAlgorithm.RSA_PSK:
-				case KeyExchangeAlgorithm.DHE_PSK:
-					break;
-				default:
-					throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
-			}
-
-			this.context = context;
-			this.keyExchange = keyExchange;
-			this.pskIdentity = pskIdentity;
-		}
-
-		public virtual void SkipServerCertificate()
-		{
-			// OK
-		}
-
-		public virtual void ProcessServerCertificate(Certificate serverCertificate)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void SkipServerKeyExchange()
-		{
-			this.psk_identity_hint = new byte[0];
-		}
-
-		public virtual void ProcessServerKeyExchange(Stream input)
-		{
-			this.psk_identity_hint = TlsUtilities.ReadOpaque16(input);
-
-			if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
-			{
-				byte[] pBytes = TlsUtilities.ReadOpaque16(input);
-				byte[] gBytes = TlsUtilities.ReadOpaque16(input);
-				byte[] YsBytes = TlsUtilities.ReadOpaque16(input);
-
-				BigInteger p = new BigInteger(1, pBytes);
-				BigInteger g = new BigInteger(1, gBytes);
-				BigInteger Ys = new BigInteger(1, YsBytes);
-				
-				this.dhAgreeServerPublicKey = TlsDHUtilities.ValidateDHPublicKey(
-					new DHPublicKeyParameters(Ys, new DHParameters(p, g)));
-			}
-			else if (this.psk_identity_hint.Length == 0)
-			{
-				// TODO Should we enforce that this message should have been skipped if hint is empty?
-				//throw new TlsFatalAlert(AlertDescription.unexpected_message);
-			}
-		}
-
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			// OK
-		}
-
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			throw new TlsFatalAlert(AlertDescription.internal_error);
-		}
-
-		public virtual void GenerateClientKeyExchange(Stream output)
-		{
-			if (psk_identity_hint == null || psk_identity_hint.Length == 0)
-			{
-				pskIdentity.SkipIdentityHint();
-			}
-			else
-			{
-				pskIdentity.NotifyIdentityHint(psk_identity_hint);
-			}
-
-			byte[] psk_identity = pskIdentity.GetPskIdentity();
-
-			TlsUtilities.WriteOpaque16(psk_identity, output);
-
-			if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
-			{
-				this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
-					context.SecureRandom, this.rsaServerPublicKey, output);
-			}
-			else if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
-			{
-				this.dhAgreeClientPrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(
-					context.SecureRandom, this.dhAgreeServerPublicKey.Parameters, output);
-			}
-		}
-
-		public virtual byte[] GeneratePremasterSecret()
-		{
-			byte[] psk = pskIdentity.GetPsk();
-			byte[] other_secret = GenerateOtherSecret(psk.Length);
-
-			MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length);
-			TlsUtilities.WriteOpaque16(other_secret, buf);
-			TlsUtilities.WriteOpaque16(psk, buf);
-			return buf.ToArray();
-		}
-
-		protected virtual byte[] GenerateOtherSecret(int pskLength)
-		{
-			if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK)
-			{
-				return TlsDHUtilities.CalculateDHBasicAgreement(dhAgreeServerPublicKey, dhAgreeClientPrivateKey);
-			}
-
-			if (this.keyExchange == KeyExchangeAlgorithm.RSA_PSK)
-			{
-				return this.premasterSecret;
-			}
-
-			return new byte[pskLength];
-		}
-	}
+    /// <summary>(D)TLS PSK key exchange (RFC 4279).</summary>
+    public class TlsPskKeyExchange
+        :   AbstractTlsKeyExchange
+    {
+        protected TlsPskIdentity mPskIdentity;
+        protected DHParameters mDHParameters;
+        protected int[] mNamedCurves;
+        protected byte[] mClientECPointFormats, mServerECPointFormats;
+
+        protected byte[] mPskIdentityHint = null;
+
+        protected DHPrivateKeyParameters mDHAgreePrivateKey = null;
+        protected DHPublicKeyParameters mDHAgreePublicKey = null;
+
+        protected AsymmetricKeyParameter mServerPublicKey = null;
+        protected RsaKeyParameters mRsaServerPublicKey = null;
+        protected TlsEncryptionCredentials mServerCredentials = null;
+        protected byte[] mPremasterSecret;
+
+        public TlsPskKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsPskIdentity pskIdentity,
+            DHParameters dhParameters, int[] namedCurves, byte[] clientECPointFormats, byte[] serverECPointFormats)
+            :   base(keyExchange, supportedSignatureAlgorithms)
+        {
+            switch (keyExchange)
+            {
+            case KeyExchangeAlgorithm.DHE_PSK:
+            case KeyExchangeAlgorithm.ECDHE_PSK:
+            case KeyExchangeAlgorithm.PSK:
+            case KeyExchangeAlgorithm.RSA_PSK:
+                break;
+            default:
+                throw new InvalidOperationException("unsupported key exchange algorithm");
+            }
+
+            this.mPskIdentity = pskIdentity;
+            this.mDHParameters = dhParameters;
+            this.mNamedCurves = namedCurves;
+            this.mClientECPointFormats = clientECPointFormats;
+            this.mServerECPointFormats = serverECPointFormats;
+        }
+
+        public override void SkipServerCredentials()
+        {
+            if (mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+        {
+            if (!(serverCredentials is TlsEncryptionCredentials))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            ProcessServerCertificate(serverCredentials.Certificate);
+
+            this.mServerCredentials = (TlsEncryptionCredentials)serverCredentials;
+        }
+
+        public override byte[] GenerateServerKeyExchange()
+        {
+            // TODO[RFC 4279] Need a server-side PSK API to determine hint and resolve identities to keys
+            this.mPskIdentityHint = null;
+
+            if (this.mPskIdentityHint == null && !RequiresServerKeyExchange)
+                return null;
+
+            MemoryStream buf = new MemoryStream();
+
+            if (this.mPskIdentityHint == null)
+            {
+                TlsUtilities.WriteOpaque16(TlsUtilities.EmptyBytes, buf);
+            }
+            else
+            {
+                TlsUtilities.WriteOpaque16(this.mPskIdentityHint, buf);
+            }
+
+            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+            {
+                if (this.mDHParameters == null)
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+
+                this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(context.SecureRandom,
+                    this.mDHParameters, buf);
+            }
+            else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+            {
+                // TODO[RFC 5489]
+            }
+
+            return buf.ToArray();
+        }
+
+        public override void ProcessServerCertificate(Certificate serverCertificate)
+        {
+            if (mKeyExchange != KeyExchangeAlgorithm.RSA_PSK)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            if (serverCertificate.IsEmpty)
+                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+            try
+            {
+                this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+            }
+
+            // Sanity check the PublicKeyFactory
+            if (this.mServerPublicKey.IsPrivate)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            this.mRsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.mServerPublicKey);
+
+            TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
+
+            base.ProcessServerCertificate(serverCertificate);
+        }
+
+        public override bool RequiresServerKeyExchange
+        {
+            get
+            {
+                switch (mKeyExchange)
+                {
+                case KeyExchangeAlgorithm.DHE_PSK:
+                case KeyExchangeAlgorithm.ECDHE_PSK:
+                    return true;
+                default:
+                    return false;
+                }
+            }
+        }
+
+        public override void ProcessServerKeyExchange(Stream input)
+        {
+            this.mPskIdentityHint = TlsUtilities.ReadOpaque16(input);
+
+            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+            {
+                ServerDHParams serverDHParams = ServerDHParams.Parse(input);
+
+                this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(serverDHParams.PublicKey);
+            }
+            else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+            {
+                // TODO[RFC 5489]
+            }
+        }
+
+        public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public override void GenerateClientKeyExchange(Stream output)
+        {
+            if (mPskIdentityHint == null)
+            {
+                mPskIdentity.SkipIdentityHint();
+            }
+            else
+            {
+                mPskIdentity.NotifyIdentityHint(mPskIdentityHint);
+            }
+
+            byte[] psk_identity = mPskIdentity.GetPskIdentity();
+
+            TlsUtilities.WriteOpaque16(psk_identity, output);
+
+            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+            {
+                this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(context.SecureRandom,
+                    mDHAgreePublicKey.Parameters, output);
+            }
+            else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+            {
+                // TODO[RFC 5489]
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+            else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+            {
+                this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(context,
+                    this.mRsaServerPublicKey, output);
+            }
+        }
+
+        public override byte[] GeneratePremasterSecret()
+        {
+            byte[] psk = mPskIdentity.GetPsk();
+            byte[] other_secret = GenerateOtherSecret(psk.Length);
+
+            MemoryStream buf = new MemoryStream(4 + other_secret.Length + psk.Length);
+            TlsUtilities.WriteOpaque16(other_secret, buf);
+            TlsUtilities.WriteOpaque16(psk, buf);
+            return buf.ToArray();
+        }
+
+        protected virtual byte[] GenerateOtherSecret(int pskLength)
+        {
+            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
+            {
+                if (mDHAgreePrivateKey != null)
+                {
+                    return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
+                }
+
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
+            {
+                // TODO[RFC 5489]
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
+            {
+                return this.mPremasterSecret;
+            }
+
+            return new byte[pskLength];
+        }
+
+        protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
+        {
+            // TODO What is the minimum bit length required?
+            // key.Modulus.BitLength;
+
+            if (!key.Exponent.IsProbablePrime(2))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            return key;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
index 4538a2a81..3a0a49154 100644
--- a/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsRsaKeyExchange.cs
@@ -1,165 +1,140 @@
 using System;
+using System.Collections;
 using System.IO;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Encodings;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// TLS 1.0 RSA key exchange.
-	/// </summary>
-	internal class TlsRsaKeyExchange
-		: TlsKeyExchange
-	{
-		protected TlsClientContext context;
-
-		protected AsymmetricKeyParameter serverPublicKey = null;
+    /// <summary>(D)TLS and SSLv3 RSA key exchange.</summary>
+    public class TlsRsaKeyExchange
+        :   AbstractTlsKeyExchange
+    {
+        protected AsymmetricKeyParameter serverPublicKey = null;
 
         protected RsaKeyParameters rsaServerPublicKey = null;
 
+        protected TlsEncryptionCredentials serverCredentials = null;
+
         protected byte[] premasterSecret;
 
-		internal TlsRsaKeyExchange(TlsClientContext context)
-		{
-			this.context = context;
-		}
-
-		public virtual void SkipServerCertificate()
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ProcessServerCertificate(Certificate serverCertificate)
-		{
-			X509CertificateStructure x509Cert = serverCertificate.certs[0];
-			SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
-
-			try
-			{
-				this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
-			}
-//			catch (RuntimeException)
-			catch (Exception)
-			{
-				throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
-			}
-
-			// Sanity check the PublicKeyFactory
-			if (this.serverPublicKey.IsPrivate)
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-
-			this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey);
-
-			TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
-
-			// TODO
-			/*
-			* Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
-			* signing algorithm for the certificate must be the same as the algorithm for the
-			* certificate key."
-			*/
-		}
-
-		public virtual void SkipServerKeyExchange()
-		{
-			// OK
-		}
-
-		public virtual void ProcessServerKeyExchange(Stream input)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			ClientCertificateType[] types = certificateRequest.CertificateTypes;
-			foreach (ClientCertificateType type in types)
-			{
-				switch (type)
-				{
-					case ClientCertificateType.rsa_sign:
-					case ClientCertificateType.dss_sign:
-					case ClientCertificateType.ecdsa_sign:
-						break;
-					default:
-						throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-				}
-			}
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			// OK
-		}
-
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			if (!(clientCredentials is TlsSignerCredentials))
-			{
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-		}
-		
-        public virtual void GenerateClientKeyExchange(Stream output)
-		{
-			this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(
-				context.SecureRandom, this.rsaServerPublicKey, output);
-		}
-
-		public virtual byte[] GeneratePremasterSecret()
-		{
-			byte[] tmp = this.premasterSecret;
-			this.premasterSecret = null;
-			return tmp;
-		}
-
-    	// Would be needed to process RSA_EXPORT server key exchange
-//	    protected virtual void ProcessRsaServerKeyExchange(Stream input, ISigner signer)
-//	    {
-//	        Stream sigIn = input;
-//	        if (signer != null)
-//	        {
-//	            sigIn = new SignerStream(input, signer, null);
-//	        }
-//
-//	        byte[] modulusBytes = TlsUtilities.ReadOpaque16(sigIn);
-//	        byte[] exponentBytes = TlsUtilities.ReadOpaque16(sigIn);
-//
-//	        if (signer != null)
-//	        {
-//	            byte[] sigByte = TlsUtilities.ReadOpaque16(input);
-//
-//	            if (!signer.VerifySignature(sigByte))
-//	            {
-//	                handler.FailWithError(AlertLevel.fatal, AlertDescription.bad_certificate);
-//	            }
-//	        }
-//
-//	        BigInteger modulus = new BigInteger(1, modulusBytes);
-//	        BigInteger exponent = new BigInteger(1, exponentBytes);
-//
-//	        this.rsaServerPublicKey = ValidateRSAPublicKey(new RsaKeyParameters(false, modulus, exponent));
-//	    }
+        public TlsRsaKeyExchange(IList supportedSignatureAlgorithms)
+            :   base(KeyExchangeAlgorithm.RSA, supportedSignatureAlgorithms)
+        {
+        }
+
+        public override void SkipServerCredentials()
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public override void ProcessServerCredentials(TlsCredentials serverCredentials)
+        {
+            if (!(serverCredentials is TlsEncryptionCredentials))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            ProcessServerCertificate(serverCredentials.Certificate);
+
+            this.serverCredentials = (TlsEncryptionCredentials)serverCredentials;
+        }
+
+        public override void ProcessServerCertificate(Certificate serverCertificate)
+        {
+            if (serverCertificate.IsEmpty)
+                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+            try
+            {
+                this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+            }
+
+            // Sanity check the PublicKeyFactory
+            if (this.serverPublicKey.IsPrivate)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            this.rsaServerPublicKey = ValidateRsaPublicKey((RsaKeyParameters)this.serverPublicKey);
+
+            TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
+
+            base.ProcessServerCertificate(serverCertificate);
+        }
+
+        public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            byte[] types = certificateRequest.CertificateTypes;
+            for (int i = 0; i < types.Length; ++i)
+            {
+                switch (types[i])
+                {
+                case ClientCertificateType.rsa_sign:
+                case ClientCertificateType.dss_sign:
+                case ClientCertificateType.ecdsa_sign:
+                    break;
+                default:
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+            }
+        }
+
+        public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            if (!(clientCredentials is TlsSignerCredentials))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public override void GenerateClientKeyExchange(Stream output)
+        {
+            this.premasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(context, rsaServerPublicKey, output);
+        }
+
+        public override void ProcessClientKeyExchange(Stream input)
+        {
+            byte[] encryptedPreMasterSecret;
+            if (TlsUtilities.IsSsl(context))
+            {
+                // TODO Do any SSLv3 clients actually include the length?
+                encryptedPreMasterSecret = Streams.ReadAll(input);
+            }
+            else
+            {
+                encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input);
+            }
+
+            this.premasterSecret = serverCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
+        }
+
+        public override byte[] GeneratePremasterSecret()
+        {
+            if (this.premasterSecret == null)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            byte[] tmp = this.premasterSecret;
+            this.premasterSecret = null;
+            return tmp;
+        }
 
         protected virtual RsaKeyParameters ValidateRsaPublicKey(RsaKeyParameters key)
-		{
-			// TODO What is the minimum bit length required?
-//			key.Modulus.BitLength;
-
-			if (!key.Exponent.IsProbablePrime(2))
-			{
-				throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-			}
-
-			return key;
-		}
-	}
+        {
+            // TODO What is the minimum bit length required?
+            // key.Modulus.BitLength;
+
+            if (!key.Exponent.IsProbablePrime(2))
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            return key;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsRsaSigner.cs b/crypto/src/crypto/tls/TlsRsaSigner.cs
index a50ff9558..6da1c5e9b 100644
--- a/crypto/src/crypto/tls/TlsRsaSigner.cs
+++ b/crypto/src/crypto/tls/TlsRsaSigner.cs
@@ -6,48 +6,97 @@ using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Signers;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsRsaSigner
-    	: TlsSigner
-	{
-		public virtual byte[] CalculateRawSignature(SecureRandom random,
-			AsymmetricKeyParameter privateKey, byte[] md5andsha1)
-		{
-			ISigner s = MakeSigner(new NullDigest(), true, new ParametersWithRandom(privateKey, random));
-			s.BlockUpdate(md5andsha1, 0, md5andsha1.Length);
-			return s.GenerateSignature();
-		}
-
-		public virtual bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey,
-			byte[] md5andsha1)
-		{
-			ISigner s = MakeSigner(new NullDigest(), false, publicKey);
-			s.BlockUpdate(md5andsha1, 0, md5andsha1.Length);
-			return s.VerifySignature(sigBytes);
-		}
-
-		public virtual ISigner CreateSigner(SecureRandom random, AsymmetricKeyParameter privateKey)
-		{
-			return MakeSigner(new CombinedHash(), true, new ParametersWithRandom(privateKey, random));
-		}
-
-        public virtual ISigner CreateVerifyer(AsymmetricKeyParameter publicKey)
-		{
-			return MakeSigner(new CombinedHash(), false, publicKey);
-		}
-
-		public virtual bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
-		{
-			return publicKey is RsaKeyParameters && !publicKey.IsPrivate;
-		}
-
-		protected virtual ISigner MakeSigner(IDigest d, bool forSigning, ICipherParameters cp)
-		{
-			ISigner s = new GenericSigner(new Pkcs1Encoding(new RsaBlindedEngine()), d);
-			s.Init(forSigning, cp);
-			return s;
-		}
-	}
+    public class TlsRsaSigner
+        :   AbstractTlsSigner
+    {
+        public override byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+            AsymmetricKeyParameter privateKey, byte[] hash)
+        {
+            ISigner signer = MakeSigner(algorithm, true, true,
+                new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+            signer.BlockUpdate(hash, 0, hash.Length);
+            return signer.GenerateSignature();
+        }
+
+        public override bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+            AsymmetricKeyParameter publicKey, byte[] hash)
+        {
+            ISigner signer = MakeSigner(algorithm, true, false, publicKey);
+            signer.BlockUpdate(hash, 0, hash.Length);
+            return signer.VerifySignature(sigBytes);
+        }
+
+        public override ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey)
+        {
+            return MakeSigner(algorithm, false, true, new ParametersWithRandom(privateKey, this.mContext.SecureRandom));
+        }
+
+        public override ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey)
+        {
+            return MakeSigner(algorithm, false, false, publicKey);
+        }
+
+        public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+        {
+            return publicKey is RsaKeyParameters && !publicKey.IsPrivate;
+        }
+
+        protected virtual ISigner MakeSigner(SignatureAndHashAlgorithm algorithm, bool raw, bool forSigning,
+            ICipherParameters cp)
+        {
+            if ((algorithm != null) != TlsUtilities.IsTlsV12(mContext))
+                throw new InvalidOperationException();
+            if (algorithm != null && algorithm.Signature != SignatureAlgorithm.rsa)
+                throw new InvalidOperationException();
+
+            IDigest d;
+            if (raw)
+            {
+                d = new NullDigest();
+            }
+            else if (algorithm == null)
+            {
+                d = new CombinedHash();
+            }
+            else
+            {
+                d = TlsUtilities.CreateHash(algorithm.Hash);
+            }
+
+            ISigner s;
+            if (algorithm != null)
+            {
+                /*
+                 * RFC 5246 4.7. In RSA signing, the opaque vector contains the signature generated
+                 * using the RSASSA-PKCS1-v1_5 signature scheme defined in [PKCS1].
+                 */
+                s = new RsaDigestSigner(d, TlsUtilities.GetOidForHashAlgorithm(algorithm.Hash));
+            }
+            else
+            {
+                /*
+                 * RFC 5246 4.7. Note that earlier versions of TLS used a different RSA signature scheme
+                 * that did not include a DigestInfo encoding.
+                 */
+                s = new GenericSigner(CreateRsaImpl(), d);
+            }
+            s.Init(forSigning, cp);
+            return s;
+        }
+
+        protected virtual IAsymmetricBlockCipher CreateRsaImpl()
+        {
+            /*
+             * RFC 5264 7.4.7.1. Implementation note: It is now known that remote timing-based attacks
+             * on TLS are possible, at least when the client and server are on the same LAN.
+             * Accordingly, implementations that use static RSA keys MUST use RSA blinding or some other
+             * anti-timing technique, as described in [TIMING].
+             */
+            return new Pkcs1Encoding(new RsaBlindedEngine());
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsRsaUtilities.cs b/crypto/src/crypto/tls/TlsRsaUtilities.cs
index 4450ba452..0e42c1733 100644
--- a/crypto/src/crypto/tls/TlsRsaUtilities.cs
+++ b/crypto/src/crypto/tls/TlsRsaUtilities.cs
@@ -5,38 +5,128 @@ using Org.BouncyCastle.Crypto.Encodings;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public abstract class TlsRsaUtilities
-	{
-		public static byte[] GenerateEncryptedPreMasterSecret(SecureRandom random,
-			RsaKeyParameters rsaServerPublicKey, Stream output)
-		{
-			/*
-			 * Choose a PremasterSecret and send it encrypted to the server
-			 */
-			byte[] premasterSecret = new byte[48];
-			random.NextBytes(premasterSecret);
-			TlsUtilities.WriteVersion(premasterSecret, 0);
-
-			Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine());
-			encoding.Init(true, new ParametersWithRandom(rsaServerPublicKey, random));
-
-			try
-			{
-				byte[] keData = encoding.ProcessBlock(premasterSecret, 0, premasterSecret.Length);
-                TlsUtilities.WriteOpaque16(keData, output);
-			}
-			catch (InvalidCipherTextException)
-			{
-				/*
-				* This should never happen, only during decryption.
-				*/
-				throw new TlsFatalAlert(AlertDescription.internal_error);
-			}
-
-			return premasterSecret;
-		}
-	}
+    public abstract class TlsRsaUtilities
+    {
+        /// <exception cref="IOException"></exception>
+        public static byte[] GenerateEncryptedPreMasterSecret(TlsContext context, RsaKeyParameters rsaServerPublicKey,
+            Stream output)
+        {
+            /*
+             * Choose a PremasterSecret and send it encrypted to the server
+             */
+            byte[] premasterSecret = new byte[48];
+            context.SecureRandom.NextBytes(premasterSecret);
+            TlsUtilities.WriteVersion(context.ClientVersion, premasterSecret, 0);
+
+            Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine());
+            encoding.Init(true, new ParametersWithRandom(rsaServerPublicKey, context.SecureRandom));
+
+            try
+            {
+                byte[] encryptedPreMasterSecret = encoding.ProcessBlock(premasterSecret, 0, premasterSecret.Length);
+
+                if (TlsUtilities.IsSsl(context))
+                {
+                    // TODO Do any SSLv3 servers actually expect the length?
+                    output.Write(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length);
+                }
+                else
+                {
+                    TlsUtilities.WriteOpaque16(encryptedPreMasterSecret, output);
+                }
+            }
+            catch (InvalidCipherTextException e)
+            {
+                /*
+                 * This should never happen, only during decryption.
+                 */
+                throw new TlsFatalAlert(AlertDescription.internal_error, e);
+            }
+
+            return premasterSecret;
+        }
+
+        public static byte[] SafeDecryptPreMasterSecret(TlsContext context, RsaKeyParameters rsaServerPrivateKey,
+            byte[] encryptedPreMasterSecret)
+        {
+            /*
+             * RFC 5246 7.4.7.1.
+             */
+            ProtocolVersion clientVersion = context.ClientVersion;
+
+            // TODO Provide as configuration option?
+            bool versionNumberCheckDisabled = false;
+
+            /*
+             * Generate 48 random bytes we can use as a Pre-Master-Secret, if the
+             * PKCS1 padding check should fail.
+             */
+            byte[] fallback = new byte[48];
+            context.SecureRandom.NextBytes(fallback);
+
+            byte[] M = Arrays.Clone(fallback);
+            try
+            {
+                Pkcs1Encoding encoding = new Pkcs1Encoding(new RsaBlindedEngine(), fallback);
+                encoding.Init(false,
+                    new ParametersWithRandom(rsaServerPrivateKey, context.SecureRandom));
+
+                M = encoding.ProcessBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.Length);
+            }
+            catch (Exception)
+            {
+                /*
+                 * This should never happen since the decryption should never throw an exception
+                 * and return a random value instead.
+                 *
+                 * In any case, a TLS server MUST NOT generate an alert if processing an
+                 * RSA-encrypted premaster secret message fails, or the version number is not as
+                 * expected. Instead, it MUST continue the handshake with a randomly generated
+                 * premaster secret.
+                 */
+            }
+
+            /*
+             * If ClientHello.client_version is TLS 1.1 or higher, server implementations MUST
+             * check the version number [..].
+             */
+            if (versionNumberCheckDisabled && clientVersion.IsEqualOrEarlierVersionOf(ProtocolVersion.TLSv10))
+            {
+                /*
+                 * If the version number is TLS 1.0 or earlier, server
+                 * implementations SHOULD check the version number, but MAY have a
+                 * configuration option to disable the check.
+                 *
+                 * So there is nothing to do here.
+                 */
+            }
+            else
+            {
+                /*
+                 * OK, we need to compare the version number in the decrypted Pre-Master-Secret with the
+                 * clientVersion received during the handshake. If they don't match, we replace the
+                 * decrypted Pre-Master-Secret with a random one.
+                 */
+                int correct = (clientVersion.MajorVersion ^ (M[0] & 0xff))
+                    | (clientVersion.MinorVersion ^ (M[1] & 0xff));
+                correct |= correct >> 1;
+                correct |= correct >> 2;
+                correct |= correct >> 4;
+                int mask = ~((correct & 1) - 1);
+
+                /*
+                 * mask will be all bits set to 0xff if the version number differed.
+                 */
+                for (int i = 0; i < 48; i++)
+                {
+                    M[i] = (byte)((M[i] & (~mask)) | (fallback[i] & mask));
+                }
+            }
+            return M;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsServer.cs b/crypto/src/crypto/tls/TlsServer.cs
new file mode 100644
index 000000000..93e62b9ac
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServer.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public interface TlsServer
+        :   TlsPeer
+    {
+        void Init(TlsServerContext context);
+
+        /// <exception cref="IOException"></exception>
+        void NotifyClientVersion(ProtocolVersion clientVersion);
+
+        /// <exception cref="IOException"></exception>
+        void NotifyOfferedCipherSuites(int[] offeredCipherSuites);
+
+        /// <exception cref="IOException"></exception>
+        void NotifyOfferedCompressionMethods(byte[] offeredCompressionMethods);
+
+        /// <param name="clientExtensions">A <see cref="IDictionary"/> (Int32 -> byte[]). Will never be null.</param>
+        /// <exception cref="IOException"></exception>
+        void ProcessClientExtensions(IDictionary clientExtensions);
+
+        /// <exception cref="IOException"></exception>
+        ProtocolVersion GetServerVersion();
+
+        /// <exception cref="IOException"></exception>
+        int GetSelectedCipherSuite();
+
+        /// <exception cref="IOException"></exception>
+        byte GetSelectedCompressionMethod();
+
+        /// <summary>
+        /// Get the (optional) table of server extensions to be included in (extended) server hello.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="IDictionary"/> (Int32 -> byte[]). May be null.
+        /// </returns>
+        /// <exception cref="IOException"></exception>
+        IDictionary GetServerExtensions();
+
+        /// <returns>
+        /// A <see cref="IList"/> (<see cref="SupplementalDataEntry"/>). May be null.
+        /// </returns>
+        /// <exception cref="IOException"></exception>
+        IList GetServerSupplementalData();
+
+        /// <exception cref="IOException"></exception>
+        TlsCredentials GetCredentials();
+
+        /// <remarks>
+        /// This method will be called (only) if the server included an extension of type
+        /// "status_request" with empty "extension_data" in the extended server hello. See <i>RFC 3546
+        /// 3.6. Certificate Status Request</i>. If a non-null <see cref="CertificateStatus"/> is returned, it
+        /// is sent to the client as a handshake message of type "certificate_status".
+        /// </remarks>
+        /// <returns>A <see cref="CertificateStatus"/> to be sent to the client (or null for none).</returns>
+        /// <exception cref="IOException"></exception>
+        CertificateStatus GetCertificateStatus();
+
+        /// <exception cref="IOException"></exception>
+        TlsKeyExchange GetKeyExchange();
+
+        /// <exception cref="IOException"></exception>
+        CertificateRequest GetCertificateRequest();
+
+        /// <param name="clientSupplementalData"><see cref="IList"/> (<see cref="SupplementalDataEntry"/>)</param>
+        /// <exception cref="IOException"></exception>
+        void ProcessClientSupplementalData(IList clientSupplementalData);
+
+        /// <summary>
+        /// Called by the protocol handler to report the client certificate, only if <c>GetCertificateRequest</c>
+        /// returned non-null.
+        /// </summary>
+        /// <remarks>Note: this method is responsible for certificate verification and validation.</remarks>
+        /// <param name="clientCertificate">the effective client certificate (may be an empty chain).</param>
+        /// <exception cref="IOException"></exception>
+        void NotifyClientCertificate(Certificate clientCertificate);
+
+        /// <summary>RFC 5077 3.3. NewSessionTicket Handshake Message.</summary>
+        /// <remarks>
+        /// This method will be called (only) if a NewSessionTicket extension was sent by the server. See
+        /// <i>RFC 5077 4. Recommended Ticket Construction</i> for recommended format and protection.
+        /// </remarks>
+        /// <returns>The <see cref="NewSessionTicket">ticket</see>)</returns>
+        /// <exception cref="IOException"></exception>
+        NewSessionTicket GetNewSessionTicket();
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsServerContext.cs b/crypto/src/crypto/tls/TlsServerContext.cs
new file mode 100644
index 000000000..4021571aa
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServerContext.cs
@@ -0,0 +1,11 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public interface TlsServerContext
+        : TlsContext
+    {
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsServerContextImpl.cs b/crypto/src/crypto/tls/TlsServerContextImpl.cs
new file mode 100644
index 000000000..d56566ffc
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServerContextImpl.cs
@@ -0,0 +1,20 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    internal class TlsServerContextImpl
+        : AbstractTlsContext, TlsServerContext
+    {
+        internal TlsServerContextImpl(SecureRandom secureRandom, SecurityParameters securityParameters)
+            : base(secureRandom, securityParameters)
+        {
+        }
+
+        public override bool IsServer
+        {
+            get { return true; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
new file mode 100644
index 000000000..589ede802
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -0,0 +1,744 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class TlsServerProtocol
+        :   TlsProtocol
+    {
+        protected TlsServer mTlsServer = null;
+        internal TlsServerContextImpl mTlsServerContext = null;
+
+        protected TlsKeyExchange mKeyExchange = null;
+        protected TlsCredentials mServerCredentials = null;
+        protected CertificateRequest mCertificateRequest = null;
+
+        protected short mClientCertificateType = -1;
+        protected TlsHandshakeHash mPrepareFinishHash = null;
+
+        public TlsServerProtocol(Stream stream, SecureRandom secureRandom)
+            :   base(stream, secureRandom)
+        {
+        }
+
+        public TlsServerProtocol(Stream input, Stream output, SecureRandom secureRandom)
+            :   base(input, output, secureRandom)
+        {
+        }
+
+        /**
+         * Receives a TLS handshake in the role of server
+         *
+         * @param mTlsServer
+         * @throws IOException If handshake was not successful.
+         */
+        public virtual void Accept(TlsServer tlsServer)
+        {
+            if (tlsServer == null)
+                throw new ArgumentNullException("tlsServer");
+            if (this.mTlsServer != null)
+                throw new InvalidOperationException("'Accept' can only be called once");
+
+            this.mTlsServer = tlsServer;
+
+            this.mSecurityParameters = new SecurityParameters();
+            this.mSecurityParameters.entity = ConnectionEnd.server;
+
+            this.mTlsServerContext = new TlsServerContextImpl(mSecureRandom, mSecurityParameters);
+
+            this.mSecurityParameters.serverRandom = CreateRandomBlock(tlsServer.ShouldUseGmtUnixTime(),
+                mTlsServerContext.NonceRandomGenerator);
+
+            this.mTlsServer.Init(mTlsServerContext);
+            this.mRecordStream.Init(mTlsServerContext);
+
+            this.mRecordStream.SetRestrictReadVersion(false);
+
+            CompleteHandshake();
+        }
+
+        protected override void CleanupHandshake()
+        {
+            base.CleanupHandshake();
+        
+            this.mKeyExchange = null;
+            this.mServerCredentials = null;
+            this.mCertificateRequest = null;
+            this.mPrepareFinishHash = null;
+        }
+
+        protected override TlsContext Context
+        {
+            get { return mTlsServerContext; }
+        }
+
+        internal override AbstractTlsContext ContextAdmin
+        {
+            get { return mTlsServerContext; }
+        }
+
+        protected override TlsPeer Peer
+        {
+            get { return mTlsServer; }
+        }
+
+        protected override void HandleHandshakeMessage(byte type, byte[] data)
+        {
+            MemoryStream buf = new MemoryStream(data);
+
+            switch (type)
+            {
+            case HandshakeType.client_hello:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_START:
+                {
+                    ReceiveClientHelloMessage(buf);
+                    this.mConnectionState = CS_CLIENT_HELLO;
+
+                    SendServerHelloMessage();
+                    this.mConnectionState = CS_SERVER_HELLO;
+
+                    IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
+                    if (serverSupplementalData != null)
+                    {
+                        SendSupplementalDataMessage(serverSupplementalData);
+                    }
+                    this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
+
+                    this.mKeyExchange = mTlsServer.GetKeyExchange();
+                    this.mKeyExchange.Init(Context);
+
+                    this.mServerCredentials = mTlsServer.GetCredentials();
+
+                    Certificate serverCertificate = null;
+
+                    if (this.mServerCredentials == null)
+                    {
+                        this.mKeyExchange.SkipServerCredentials();
+                    }
+                    else
+                    {
+                        this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);
+
+                        serverCertificate = this.mServerCredentials.Certificate;
+                        SendCertificateMessage(serverCertificate);
+                    }
+                    this.mConnectionState = CS_SERVER_CERTIFICATE;
+
+                    // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
+                    if (serverCertificate == null || serverCertificate.IsEmpty)
+                    {
+                        this.mAllowCertificateStatus = false;
+                    }
+
+                    if (this.mAllowCertificateStatus)
+                    {
+                        CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
+                        if (certificateStatus != null)
+                        {
+                            SendCertificateStatusMessage(certificateStatus);
+                        }
+                    }
+
+                    this.mConnectionState = CS_CERTIFICATE_STATUS;
+
+                    byte[] serverKeyExchange = this.mKeyExchange.GenerateServerKeyExchange();
+                    if (serverKeyExchange != null)
+                    {
+                        SendServerKeyExchangeMessage(serverKeyExchange);
+                    }
+                    this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
+
+                    if (this.mServerCredentials != null)
+                    {
+                        this.mCertificateRequest = mTlsServer.GetCertificateRequest();
+                        if (this.mCertificateRequest != null)
+                        {
+                            this.mKeyExchange.ValidateCertificateRequest(mCertificateRequest);
+
+                            SendCertificateRequestMessage(mCertificateRequest);
+
+                            TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
+                                this.mCertificateRequest.SupportedSignatureAlgorithms);
+                        }
+                    }
+                    this.mConnectionState = CS_CERTIFICATE_REQUEST;
+
+                    SendServerHelloDoneMessage();
+                    this.mConnectionState = CS_SERVER_HELLO_DONE;
+
+                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();
+
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.supplemental_data:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_HELLO_DONE:
+                {
+                    mTlsServer.ProcessClientSupplementalData(ReadSupplementalDataMessage(buf));
+                    this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.certificate:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_HELLO_DONE:
+                case CS_CLIENT_SUPPLEMENTAL_DATA:
+                {
+                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+                    {
+                        mTlsServer.ProcessClientSupplementalData(null);
+                    }
+
+                    if (this.mCertificateRequest == null)
+                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+                    ReceiveCertificateMessage(buf);
+                    this.mConnectionState = CS_CLIENT_CERTIFICATE;
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.client_key_exchange:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_SERVER_HELLO_DONE:
+                case CS_CLIENT_SUPPLEMENTAL_DATA:
+                case CS_CLIENT_CERTIFICATE:
+                {
+                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
+                    {
+                        mTlsServer.ProcessClientSupplementalData(null);
+                    }
+
+                    if (mConnectionState < CS_CLIENT_CERTIFICATE)
+                    {
+                        if (this.mCertificateRequest == null)
+                        {
+                            this.mKeyExchange.SkipClientCredentials();
+                        }
+                        else
+                        {
+                            if (TlsUtilities.IsTlsV12(Context))
+                            {
+                                /*
+                                 * RFC 5246 If no suitable certificate is available, the client MUST Send a
+                                 * certificate message containing no certificates.
+                                 * 
+                                 * NOTE: In previous RFCs, this was SHOULD instead of MUST.
+                                 */
+                                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                            }
+                            else if (TlsUtilities.IsSsl(Context))
+                            {
+                                if (this.mPeerCertificate == null)
+                                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                            }
+                            else
+                            {
+                                NotifyClientCertificate(Certificate.EmptyChain);
+                            }
+                        }
+                    }
+
+                    ReceiveClientKeyExchangeMessage(buf);
+                    this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.certificate_verify:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_CLIENT_KEY_EXCHANGE:
+                {
+                    /*
+                     * RFC 5246 7.4.8 This message is only sent following a client certificate that has
+                     * signing capability (i.e., all certificates except those containing fixed
+                     * Diffie-Hellman parameters).
+                     */
+                    if (!ExpectCertificateVerifyMessage())
+                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+                    ReceiveCertificateVerifyMessage(buf);
+                    this.mConnectionState = CS_CERTIFICATE_VERIFY;
+
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.finished:
+            {
+                switch (this.mConnectionState)
+                {
+                case CS_CLIENT_KEY_EXCHANGE:
+                case CS_CERTIFICATE_VERIFY:
+                {
+                    if (mConnectionState < CS_CERTIFICATE_VERIFY && ExpectCertificateVerifyMessage())
+                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+                    ProcessFinishedMessage(buf);
+                    this.mConnectionState = CS_CLIENT_FINISHED;
+
+                    if (this.mExpectSessionTicket)
+                    {
+                        SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
+                        SendChangeCipherSpecMessage();
+                    }
+                    this.mConnectionState = CS_SERVER_SESSION_TICKET;
+
+                    SendFinishedMessage();
+                    this.mConnectionState = CS_SERVER_FINISHED;
+                    this.mConnectionState = CS_END;
+                    break;
+                }
+                default:
+                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
+                }
+                break;
+            }
+            case HandshakeType.hello_request:
+            case HandshakeType.hello_verify_request:
+            case HandshakeType.server_hello:
+            case HandshakeType.server_key_exchange:
+            case HandshakeType.certificate_request:
+            case HandshakeType.server_hello_done:
+            case HandshakeType.session_ticket:
+            default:
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            }
+        }
+
+        protected override void HandleWarningMessage(byte description)
+        {
+            switch (description)
+            {
+            case AlertDescription.no_certificate:
+            {
+                /*
+                 * SSL 3.0 If the server has sent a certificate request Message, the client must Send
+                 * either the certificate message or a no_certificate alert.
+                 */
+                if (TlsUtilities.IsSsl(Context) && mCertificateRequest != null)
+                {
+                    NotifyClientCertificate(Certificate.EmptyChain);
+                }
+                break;
+            }
+            default:
+            {
+                base.HandleWarningMessage(description);
+                break;
+            }
+            }
+        }
+
+        protected virtual void NotifyClientCertificate(Certificate clientCertificate)
+        {
+            if (mCertificateRequest == null)
+                throw new InvalidOperationException();
+            if (mPeerCertificate != null)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+
+            this.mPeerCertificate = clientCertificate;
+
+            if (clientCertificate.IsEmpty)
+            {
+                this.mKeyExchange.SkipClientCredentials();
+            }
+            else
+            {
+
+                /*
+                 * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request
+                 * message was non-empty, one of the certificates in the certificate chain SHOULD be
+                 * issued by one of the listed CAs.
+                 */
+
+                this.mClientCertificateType = TlsUtilities.GetClientCertificateType(clientCertificate,
+                    this.mServerCredentials.Certificate);
+
+                this.mKeyExchange.ProcessClientCertificate(clientCertificate);
+            }
+
+            /*
+             * RFC 5246 7.4.6. If the client does not Send any certificates, the server MAY at its
+             * discretion either continue the handshake without client authentication, or respond with a
+             * fatal handshake_failure alert. Also, if some aspect of the certificate chain was
+             * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its
+             * discretion either continue the handshake (considering the client unauthenticated) or Send
+             * a fatal alert.
+             */
+            this.mTlsServer.NotifyClientCertificate(clientCertificate);
+        }
+
+        protected virtual void ReceiveCertificateMessage(MemoryStream buf)
+        {
+            Certificate clientCertificate = Certificate.Parse(buf);
+
+            AssertEmpty(buf);
+
+            NotifyClientCertificate(clientCertificate);
+        }
+
+        protected virtual void ReceiveCertificateVerifyMessage(MemoryStream buf)
+        {
+            DigitallySigned clientCertificateVerify = DigitallySigned.Parse(Context, buf);
+
+            AssertEmpty(buf);
+
+            // Verify the CertificateVerify message contains a correct signature.
+            try
+            {
+                byte[] certificateVerifyHash;
+                if (TlsUtilities.IsTlsV12(Context))
+                {
+                    certificateVerifyHash = mPrepareFinishHash.GetFinalHash(clientCertificateVerify.Algorithm.Hash);
+                }
+                else
+                {
+                    certificateVerifyHash = TlsProtocol.GetCurrentPrfHash(Context, mPrepareFinishHash, null);
+                }
+
+                X509CertificateStructure x509Cert = mPeerCertificate.GetCertificateAt(0);
+                SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+                AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+
+                TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)mClientCertificateType);
+                tlsSigner.Init(Context);
+                if (!tlsSigner.VerifyRawSignature(clientCertificateVerify.Algorithm,
+                    clientCertificateVerify.Signature, publicKey, certificateVerifyHash))
+                {
+                    throw new TlsFatalAlert(AlertDescription.decrypt_error);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.decrypt_error, e);
+            }
+        }
+
+        protected virtual void ReceiveClientHelloMessage(MemoryStream buf)
+        {
+            ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);
+            if (client_version.IsDtls)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            byte[] client_random = TlsUtilities.ReadFully(32, buf);
+
+            /*
+             * TODO RFC 5077 3.4. If a ticket is presented by the client, the server MUST NOT attempt to
+             * use the Session ID in the ClientHello for stateful session resumption.
+             */
+            byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
+            if (sessionID.Length > 32)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            /*
+             * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
+             * resumption request), this vector MUST include at least the cipher_suite from that
+             * session.
+             */
+            int cipher_suites_length = TlsUtilities.ReadUint16(buf);
+            if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            this.mOfferedCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);
+
+            /*
+             * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
+             * resumption request), it MUST include the compression_method from that session.
+             */
+            int compression_methods_length = TlsUtilities.ReadUint8(buf);
+            if (compression_methods_length < 1)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+            this.mOfferedCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);
+
+            /*
+             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+             * extensions appearing in the client hello, and Send a server hello containing no
+             * extensions.
+             */
+            this.mClientExtensions = ReadExtensions(buf);
+
+            ContextAdmin.SetClientVersion(client_version);
+
+            mTlsServer.NotifyClientVersion(client_version);
+
+            mSecurityParameters.clientRandom = client_random;
+
+            mTlsServer.NotifyOfferedCipherSuites(mOfferedCipherSuites);
+            mTlsServer.NotifyOfferedCompressionMethods(mOfferedCompressionMethods);
+
+            /*
+             * RFC 5746 3.6. Server Behavior: Initial Handshake
+             */
+            {
+                /*
+                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
+                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
+                 * ClientHello. Including both is NOT RECOMMENDED.
+                 */
+
+                /*
+                 * When a ClientHello is received, the server MUST check if it includes the
+                 * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
+                 * to TRUE.
+                 */
+                if (Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
+                {
+                    this.mSecureRenegotiation = true;
+                }
+
+                /*
+                 * The server MUST check if the "renegotiation_info" extension is included in the
+                 * ClientHello.
+                 */
+                byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
+                if (renegExtData != null)
+                {
+                    /*
+                     * If the extension is present, set secure_renegotiation flag to TRUE. The
+                     * server MUST then verify that the length of the "renegotiated_connection"
+                     * field is zero, and if it is not, MUST abort the handshake.
+                     */
+                    this.mSecureRenegotiation = true;
+
+                    if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
+                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
+                }
+            }
+
+            mTlsServer.NotifySecureRenegotiation(this.mSecureRenegotiation);
+
+            if (mClientExtensions != null)
+            {
+                mTlsServer.ProcessClientExtensions(mClientExtensions);
+            }
+        }
+
+        protected virtual void ReceiveClientKeyExchangeMessage(MemoryStream buf)
+        {
+            mKeyExchange.ProcessClientKeyExchange(buf);
+
+            AssertEmpty(buf);
+
+            EstablishMasterSecret(Context, mKeyExchange);
+            mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
+
+            this.mPrepareFinishHash = mRecordStream.PrepareToFinish();
+
+            if (!mExpectSessionTicket)
+            {
+                SendChangeCipherSpecMessage();
+            }
+        }
+
+        protected virtual void SendCertificateRequestMessage(CertificateRequest certificateRequest)
+        {
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_request);
+
+            certificateRequest.Encode(message);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual void SendCertificateStatusMessage(CertificateStatus certificateStatus)
+        {
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_status);
+
+            certificateStatus.Encode(message);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual void SendNewSessionTicketMessage(NewSessionTicket newSessionTicket)
+        {
+            if (newSessionTicket == null)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.session_ticket);
+
+            newSessionTicket.Encode(message);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual void SendServerHelloMessage()
+        {
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);
+
+            ProtocolVersion server_version = mTlsServer.GetServerVersion();
+            if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            mRecordStream.ReadVersion = server_version;
+            mRecordStream.SetWriteVersion(server_version);
+            mRecordStream.SetRestrictReadVersion(true);
+            ContextAdmin.SetServerVersion(server_version);
+
+            TlsUtilities.WriteVersion(server_version, message);
+
+            message.Write(this.mSecurityParameters.serverRandom);
+
+            /*
+             * The server may return an empty session_id to indicate that the session will not be cached
+             * and therefore cannot be resumed.
+             */
+            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message);
+
+            int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();
+            if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite)
+                || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
+                || selectedCipherSuite == CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+                || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, server_version))
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+            mSecurityParameters.cipherSuite = selectedCipherSuite;
+
+            byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();
+            if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+            mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
+
+            TlsUtilities.WriteUint16(selectedCipherSuite, message);
+            TlsUtilities.WriteUint8(selectedCompressionMethod, message);
+
+            this.mServerExtensions = mTlsServer.GetServerExtensions();
+
+            /*
+             * RFC 5746 3.6. Server Behavior: Initial Handshake
+             */
+            if (this.mSecureRenegotiation)
+            {
+                byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
+                bool noRenegExt = (null == renegExtData);
+
+                if (noRenegExt)
+                {
+                    /*
+                     * Note that Sending a "renegotiation_info" extension in response to a ClientHello
+                     * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
+                     * Section 7.4.1.4, on the server Sending unsolicited extensions and is only allowed
+                     * because the client is signaling its willingness to receive the extension via the
+                     * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
+                     */
+
+                    /*
+                     * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
+                     * "renegotiation_info" extension in the ServerHello message.
+                     */
+                    this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mServerExtensions);
+                    this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
+                }
+            }
+
+            /*
+             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
+             * extensions appearing in the client hello, and Send a server hello containing no
+             * extensions.
+             */
+
+            if (this.mServerExtensions != null)
+            {
+                this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
+
+                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions,
+                    mServerExtensions, AlertDescription.internal_error);
+
+                this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);
+
+                /*
+                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
+                 * a session resumption handshake.
+                 */
+                this.mAllowCertificateStatus = !mResumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request,
+                        AlertDescription.internal_error);
+
+                this.mExpectSessionTicket = !mResumedSession
+                    && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket,
+                        AlertDescription.internal_error);
+
+                WriteExtensions(message, this.mServerExtensions);
+            }
+
+            if (mSecurityParameters.maxFragmentLength >= 0)
+            {
+                int plainTextLimit = 1 << (8 + mSecurityParameters.maxFragmentLength);
+                mRecordStream.SetPlaintextLimit(plainTextLimit);
+            }
+
+            mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
+
+            /*
+             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
+             * a verify_data_length equal to 12. This includes all existing cipher suites.
+             */
+            mSecurityParameters.verifyDataLength = 12;
+
+            message.WriteToRecordStream(this);
+
+            this.mRecordStream.NotifyHelloComplete();
+        }
+
+        protected virtual void SendServerHelloDoneMessage()
+        {
+            byte[] message = new byte[4];
+            TlsUtilities.WriteUint8(HandshakeType.server_hello_done, message, 0);
+            TlsUtilities.WriteUint24(0, message, 1);
+
+            WriteHandshakeMessage(message, 0, message.Length);
+        }
+
+        protected virtual void SendServerKeyExchangeMessage(byte[] serverKeyExchange)
+        {
+            HandshakeMessage message = new HandshakeMessage(HandshakeType.server_key_exchange, serverKeyExchange.Length);
+
+            message.Write(serverKeyExchange);
+
+            message.WriteToRecordStream(this);
+        }
+
+        protected virtual bool ExpectCertificateVerifyMessage()
+        {
+            return mClientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)mClientCertificateType);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsSession.cs b/crypto/src/crypto/tls/TlsSession.cs
new file mode 100644
index 000000000..6c229913b
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSession.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public interface TlsSession
+    {
+        SessionParameters ExportSessionParameters();
+
+        byte[] SessionID { get; }
+
+        void Invalidate();
+
+        bool IsResumable { get; }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsSessionImpl.cs b/crypto/src/crypto/tls/TlsSessionImpl.cs
new file mode 100644
index 000000000..866392623
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSessionImpl.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    internal class TlsSessionImpl
+        :   TlsSession
+    {
+        internal readonly byte[] mSessionID;
+        internal SessionParameters mSessionParameters;
+
+        internal TlsSessionImpl(byte[] sessionID, SessionParameters sessionParameters)
+        {
+            if (sessionID == null)
+                throw new ArgumentNullException("sessionID");
+            if (sessionID.Length < 1 || sessionID.Length > 32)
+                throw new ArgumentException("must have length between 1 and 32 bytes, inclusive", "sessionID");
+
+            this.mSessionID = Arrays.Clone(sessionID);
+            this.mSessionParameters = sessionParameters;
+        }
+
+        public virtual SessionParameters ExportSessionParameters()
+        {
+            lock (this)
+            {
+                return this.mSessionParameters == null ? null : this.mSessionParameters.Copy();
+            }
+        }
+
+        public virtual byte[] SessionID
+        {
+            get { lock (this) return mSessionID; }
+        }
+
+        public virtual void Invalidate()
+        {
+            lock (this)
+            {
+                if (this.mSessionParameters != null)
+                {
+                    this.mSessionParameters.Clear();
+                    this.mSessionParameters = null;
+                }
+            }
+        }
+
+        public virtual bool IsResumable
+        {
+            get { lock (this) return this.mSessionParameters != null; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsSigner.cs b/crypto/src/crypto/tls/TlsSigner.cs
index e59b90705..ffdd4c9a1 100644
--- a/crypto/src/crypto/tls/TlsSigner.cs
+++ b/crypto/src/crypto/tls/TlsSigner.cs
@@ -1,18 +1,29 @@
 using System;
 
-using Org.BouncyCastle.Security;
-
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public interface TlsSigner
-	{
-    	byte[] CalculateRawSignature(SecureRandom random, AsymmetricKeyParameter privateKey,
-			byte[] md5andsha1);
-		bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5andsha1);
+    public interface TlsSigner
+    {
+        void Init(TlsContext context);
+
+        byte[] GenerateRawSignature(AsymmetricKeyParameter privateKey, byte[] md5AndSha1);
+
+        byte[] GenerateRawSignature(SignatureAndHashAlgorithm algorithm,
+            AsymmetricKeyParameter privateKey, byte[] hash);
+
+        bool VerifyRawSignature(byte[] sigBytes, AsymmetricKeyParameter publicKey, byte[] md5AndSha1);
+
+        bool VerifyRawSignature(SignatureAndHashAlgorithm algorithm, byte[] sigBytes,
+            AsymmetricKeyParameter publicKey, byte[] hash);
+
+        ISigner CreateSigner(AsymmetricKeyParameter privateKey);
+
+        ISigner CreateSigner(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter privateKey);
+
+        ISigner CreateVerifyer(AsymmetricKeyParameter publicKey);
 
-		ISigner CreateSigner(SecureRandom random, AsymmetricKeyParameter privateKey);
-		ISigner CreateVerifyer(AsymmetricKeyParameter publicKey);
+        ISigner CreateVerifyer(SignatureAndHashAlgorithm algorithm, AsymmetricKeyParameter publicKey);
 
-		bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
-	}
+        bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsSignerCredentials.cs b/crypto/src/crypto/tls/TlsSignerCredentials.cs
index 2adb06c26..92ed7cc19 100644
--- a/crypto/src/crypto/tls/TlsSignerCredentials.cs
+++ b/crypto/src/crypto/tls/TlsSignerCredentials.cs
@@ -3,9 +3,12 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	public interface TlsSignerCredentials : TlsCredentials
-	{
-		/// <exception cref="IOException"></exception>
-		byte[] GenerateCertificateSignature(byte[] md5andsha1);
-	}
+    public interface TlsSignerCredentials
+        :   TlsCredentials
+    {
+        /// <exception cref="IOException"></exception>
+        byte[] GenerateCertificateSignature(byte[] hash);
+
+        SignatureAndHashAlgorithm SignatureAndHashAlgorithm { get; }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
index 852aace41..f42f7456d 100644
--- a/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsSrpKeyExchange.cs
@@ -1,203 +1,189 @@
 using System;
+using System.Collections;
 using System.IO;
 
-using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Crypto.Agreement;
 using Org.BouncyCastle.Crypto.Agreement.Srp;
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <summary>
-	/// TLS 1.1 SRP key exchange.
-	/// </summary>
-	internal class TlsSrpKeyExchange
-		: TlsKeyExchange
-	{
-		protected TlsClientContext context;
-        protected KeyExchangeAlgorithm keyExchange;
-        protected TlsSigner tlsSigner;
-		protected byte[] identity;
-		protected byte[] password;
-
-        protected AsymmetricKeyParameter serverPublicKey = null;
-
-		protected byte[] s = null;
-        protected BigInteger B = null;
-        protected Srp6Client srpClient = new Srp6Client();
-
-		internal TlsSrpKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange,
-			byte[] identity, byte[] password)
-		{
-			switch (keyExchange)
-			{
-				case KeyExchangeAlgorithm.SRP:
-					this.tlsSigner = null;
-					break;
-				case KeyExchangeAlgorithm.SRP_RSA:
-					this.tlsSigner = new TlsRsaSigner();
-					break;
-				case KeyExchangeAlgorithm.SRP_DSS:
-					this.tlsSigner = new TlsDssSigner();
-					break;
-				default:
-					throw new ArgumentException("unsupported key exchange algorithm", "keyExchange");
-			}
-
-			this.context = context;
-			this.keyExchange = keyExchange;
-			this.identity = identity;
-			this.password = password;
-		}
-
-		public virtual void SkipServerCertificate()
-		{
-			if (tlsSigner != null)
-			{
-				throw new TlsFatalAlert(AlertDescription.unexpected_message);
-			}
-		}
-
-		public virtual void ProcessServerCertificate(Certificate serverCertificate)
-		{
-			if (tlsSigner == null)
-			{
-				throw new TlsFatalAlert(AlertDescription.unexpected_message);
-			}
-
-			X509CertificateStructure x509Cert = serverCertificate.certs[0];
-			SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
-
-			try
-			{
-				this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
-			}
-//			catch (RuntimeException)
-			catch (Exception)
-			{
-				throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
-			}
-
-	        if (!tlsSigner.IsValidPublicKey(this.serverPublicKey))
-	        {
-	            throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-	        }
-
-			TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
-
-			// TODO
-			/*
-			* Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
-			* signing algorithm for the certificate must be the same as the algorithm for the
-			* certificate key."
-			*/
-		}
-
-		public virtual void SkipServerKeyExchange()
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void ProcessServerKeyExchange(Stream input)
-		{
-			SecurityParameters securityParameters = context.SecurityParameters;
-
-			Stream sigIn = input;
-			ISigner signer = null;
-
-			if (tlsSigner != null)
-			{
-				signer = InitSigner(tlsSigner, securityParameters);
-				sigIn = new SignerStream(input, signer, null);
-			}
-
-			byte[] NBytes = TlsUtilities.ReadOpaque16(sigIn);
-			byte[] gBytes = TlsUtilities.ReadOpaque16(sigIn);
-			byte[] sBytes = TlsUtilities.ReadOpaque8(sigIn);
-			byte[] BBytes = TlsUtilities.ReadOpaque16(sigIn);
-
-			if (signer != null)
-			{
-				byte[] sigByte = TlsUtilities.ReadOpaque16(input);
-
-				if (!signer.VerifySignature(sigByte))
-				{
-					throw new TlsFatalAlert(AlertDescription.bad_certificate);
-				}
-			}
-
-			BigInteger N = new BigInteger(1, NBytes);
-			BigInteger g = new BigInteger(1, gBytes);
-
-			// TODO Validate group parameters (see RFC 5054)
-			//throw new TlsFatalAlert(AlertDescription.insufficient_security);
-
-			this.s = sBytes;
-
-			/*
-			* RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter"
-			* alert if B % N = 0.
-			*/
-			try
-			{
-				this.B = Srp6Utilities.ValidatePublicValue(N, new BigInteger(1, BBytes));
-			}
-			catch (CryptoException)
-			{
-				throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-			}
-
-			this.srpClient.Init(N, g, new Sha1Digest(), context.SecureRandom);
-		}
-
-		public virtual void ValidateCertificateRequest(CertificateRequest certificateRequest)
-		{
-			throw new TlsFatalAlert(AlertDescription.unexpected_message);
-		}
-
-		public virtual void SkipClientCredentials()
-		{
-			// OK
-		}
-		
-		public virtual void ProcessClientCredentials(TlsCredentials clientCredentials)
-		{
-			throw new TlsFatalAlert(AlertDescription.internal_error);
-		}
-
-        public virtual void GenerateClientKeyExchange(Stream output)
-		{
-			byte[] keData = BigIntegers.AsUnsignedByteArray(srpClient.GenerateClientCredentials(s,
-				this.identity, this.password));
-            TlsUtilities.WriteOpaque16(keData, output);
-		}
-
-		public virtual byte[] GeneratePremasterSecret()
-		{
-			try
-			{
-				// TODO Check if this needs to be a fixed size
-				return BigIntegers.AsUnsignedByteArray(srpClient.CalculateSecret(B));
-			}
-			catch (CryptoException)
-			{
-				throw new TlsFatalAlert(AlertDescription.illegal_parameter);
-			}
-		}
-
-		protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
-		{
-			ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
-			signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
-			signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
-			return signer;
-		}
-	}
+    /// <summary>(D)TLS SRP key exchange (RFC 5054).</summary>
+    public class TlsSrpKeyExchange
+        :   AbstractTlsKeyExchange
+    {
+        protected TlsSigner mTlsSigner;
+        protected byte[] mIdentity;
+        protected byte[] mPassword;
+
+        protected AsymmetricKeyParameter mServerPublicKey = null;
+
+        protected byte[] mS = null;
+        protected BigInteger mB = null;
+        protected Srp6Client mSrpClient = new Srp6Client();
+
+        public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity, byte[] password)
+            :   base(keyExchange, supportedSignatureAlgorithms)
+        {
+            switch (keyExchange)
+            {
+            case KeyExchangeAlgorithm.SRP:
+                this.mTlsSigner = null;
+                break;
+            case KeyExchangeAlgorithm.SRP_RSA:
+                this.mTlsSigner = new TlsRsaSigner();
+                break;
+            case KeyExchangeAlgorithm.SRP_DSS:
+                this.mTlsSigner = new TlsDssSigner();
+                break;
+            default:
+                throw new InvalidOperationException("unsupported key exchange algorithm");
+            }
+
+            this.mIdentity = identity;
+            this.mPassword = password;
+        }
+
+        public override void Init(TlsContext context)
+        {
+            base.Init(context);
+
+            if (this.mTlsSigner != null)
+            {
+                this.mTlsSigner.Init(context);
+            }
+        }
+
+        public override void SkipServerCredentials()
+        {
+            if (mTlsSigner != null)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public override void ProcessServerCertificate(Certificate serverCertificate)
+        {
+            if (mTlsSigner == null)
+                throw new TlsFatalAlert(AlertDescription.unexpected_message);
+            if (serverCertificate.IsEmpty)
+                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+
+            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
+
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+            try
+            {
+                this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+            }
+
+            if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
+                throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+
+            TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+
+            base.ProcessServerCertificate(serverCertificate);
+        }
+
+        public override bool RequiresServerKeyExchange
+        {
+            get { return true; }
+        }
+
+        public override void ProcessServerKeyExchange(Stream input)
+        {
+            SecurityParameters securityParameters = context.SecurityParameters;
+
+            SignerInputBuffer buf = null;
+            Stream teeIn = input;
+
+            if (mTlsSigner != null)
+            {
+                buf = new SignerInputBuffer();
+                teeIn = new TeeInputStream(input, buf);
+            }
+
+            byte[] NBytes = TlsUtilities.ReadOpaque16(teeIn);
+            byte[] gBytes = TlsUtilities.ReadOpaque16(teeIn);
+            byte[] sBytes = TlsUtilities.ReadOpaque8(teeIn);
+            byte[] BBytes = TlsUtilities.ReadOpaque16(teeIn);
+
+            if (buf != null)
+            {
+                DigitallySigned signed_params = DigitallySigned.Parse(context, input);
+
+                ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);
+                buf.UpdateSigner(signer);
+                if (!signer.VerifySignature(signed_params.Signature))
+                    throw new TlsFatalAlert(AlertDescription.decrypt_error);
+            }
+
+            BigInteger N = new BigInteger(1, NBytes);
+            BigInteger g = new BigInteger(1, gBytes);
+
+            // TODO Validate group parameters (see RFC 5054)
+    //        throw new TlsFatalAlert(AlertDescription.insufficient_security);
+
+            this.mS = sBytes;
+
+            /*
+             * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if
+             * B % N = 0.
+             */
+            try
+            {
+                this.mB = Srp6Utilities.ValidatePublicValue(N, new BigInteger(1, BBytes));
+            }
+            catch (CryptoException e)
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+            }
+
+            this.mSrpClient.Init(N, g, TlsUtilities.CreateHash(HashAlgorithm.sha1), context.SecureRandom);
+        }
+
+        public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+        public override void ProcessClientCredentials(TlsCredentials clientCredentials)
+        {
+            throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public override void GenerateClientKeyExchange(Stream output)
+        {
+            BigInteger A = mSrpClient.GenerateClientCredentials(mS, this.mIdentity, this.mPassword);
+            TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(A), output);
+        }
+
+        public override byte[] GeneratePremasterSecret()
+        {
+            try
+            {
+                // TODO Check if this needs to be a fixed size
+                return BigIntegers.AsUnsignedByteArray(mSrpClient.CalculateSecret(mB));
+            }
+            catch (CryptoException e)
+            {
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
+            }
+        }
+
+        protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm,
+            SecurityParameters securityParameters)
+        {
+            ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey);
+            signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
+            signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
+            return signer;
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsSrpUtilities.cs b/crypto/src/crypto/tls/TlsSrpUtilities.cs
new file mode 100644
index 000000000..bbb6ac280
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrpUtilities.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public abstract class TlsSrpUtilities
+    {
+        public static void AddSrpExtension(IDictionary extensions, byte[] identity)
+        {
+            extensions[ExtensionType.srp] = CreateSrpExtension(identity);
+        }
+
+        public static byte[] GetSrpExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.srp);
+            return extensionData == null ? null : ReadSrpExtension(extensionData);
+        }
+
+        public static byte[] CreateSrpExtension(byte[] identity)
+        {
+            if (identity == null)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            return TlsUtilities.EncodeOpaque8(identity);
+        }
+
+        public static byte[] ReadSrpExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, false);
+            byte[] identity = TlsUtilities.ReadOpaque8(buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return identity;
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsSrtpUtilities.cs b/crypto/src/crypto/tls/TlsSrtpUtilities.cs
new file mode 100644
index 000000000..626c0e3a4
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsSrtpUtilities.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5764 DTLS Extension to Establish Keys for SRTP.
+     */
+    public abstract class TlsSRTPUtils
+    {
+        public static void AddUseSrtpExtension(IDictionary extensions, UseSrtpData useSRTPData)
+        {
+            extensions[ExtensionType.use_srtp] = CreateUseSrtpExtension(useSRTPData);
+        }
+
+        public static UseSrtpData GetUseSrtpExtension(IDictionary extensions)
+        {
+            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.use_srtp);
+            return extensionData == null ? null : ReadUseSrtpExtension(extensionData);
+        }
+
+        public static byte[] CreateUseSrtpExtension(UseSrtpData useSrtpData)
+        {
+            if (useSrtpData == null)
+                throw new ArgumentNullException("useSrtpData");
+
+            MemoryStream buf = new MemoryStream();
+
+            // SRTPProtectionProfiles
+            TlsUtilities.WriteUint16ArrayWithUint16Length(useSrtpData.ProtectionProfiles, buf);
+
+            // srtp_mki
+            TlsUtilities.WriteOpaque8(useSrtpData.Mki, buf);
+
+            return buf.ToArray();
+        }
+
+        public static UseSrtpData ReadUseSrtpExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, true);
+
+            // SRTPProtectionProfiles
+            int length = TlsUtilities.ReadUint16(buf);
+            if (length < 2 || (length & 1) != 0)
+            {
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            }
+            int[] protectionProfiles = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+            // srtp_mki
+            byte[] mki = TlsUtilities.ReadOpaque8(buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return new UseSrtpData(protectionProfiles, mki);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsStream.cs b/crypto/src/crypto/tls/TlsStream.cs
index e3d05686b..7ff7184e3 100644
--- a/crypto/src/crypto/tls/TlsStream.cs
+++ b/crypto/src/crypto/tls/TlsStream.cs
@@ -3,87 +3,83 @@ using System.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	internal class TlsStream
-		: Stream
-	{
-		private readonly TlsProtocolHandler handler;
+    internal class TlsStream
+        : Stream
+    {
+        private readonly TlsProtocol handler;
 
-		internal TlsStream(
-			TlsProtocolHandler handler)
-		{
-			this.handler = handler;
-		}
+        internal TlsStream(TlsProtocol handler)
+        {
+            this.handler = handler;
+        }
 
-		public override bool CanRead
-		{
-			get { return !handler.IsClosed; }
-		}
+        public override bool CanRead
+        {
+            get { return !handler.IsClosed; }
+        }
 
-		public override bool CanSeek
-		{
-			get { return false; }
-		}
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
 
-		public override bool CanWrite
-		{
-			get { return !handler.IsClosed; }
-		}
+        public override bool CanWrite
+        {
+            get { return !handler.IsClosed; }
+        }
 
-        protected override void Dispose(bool disposing)
+        public override void Close()
         {
-            if (disposing)
-            {
-                handler.Close();
-            }
+            handler.Close();
         }
 
-		public override void Flush()
-		{
-			handler.Flush();
-		}
+        public override void Flush()
+        {
+            handler.Flush();
+        }
 
         public override long Length
-		{
-			get { throw new NotSupportedException(); }
-		}
+        {
+            get { throw new NotSupportedException(); }
+        }
 
-		public override long Position
+        public override long Position
         {
             get { throw new NotSupportedException(); }
             set { throw new NotSupportedException(); }
         }
 
-		public override int Read(byte[]	buf, int off, int len)
-		{
-			return this.handler.ReadApplicationData(buf, off, len);
-		}
+        public override int Read(byte[]	buf, int off, int len)
+        {
+            return this.handler.ReadApplicationData(buf, off, len);
+        }
 
-		public override int ReadByte()
-		{
-			byte[] buf = new byte[1];
-			if (this.Read(buf, 0, 1) <= 0)
-				return -1;
-			return buf[0];
-		}
+        public override int ReadByte()
+        {
+            byte[] buf = new byte[1];
+            if (this.Read(buf, 0, 1) <= 0)
+                return -1;
+            return buf[0];
+        }
 
-		public override long Seek(long offset, SeekOrigin origin)
-		{
-			throw new NotSupportedException();
-		}
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
 
         public override void SetLength(long value)
-		{
-			throw new NotSupportedException();
-		}
+        {
+            throw new NotSupportedException();
+        }
 
-		public override void Write(byte[] buf, int off, int len)
-		{
-			this.handler.WriteData(buf, off, len);
-		}
+        public override void Write(byte[] buf, int off, int len)
+        {
+            this.handler.WriteData(buf, off, len);
+        }
 
-		public override void WriteByte(byte b)
-		{
-			this.handler.WriteData(new byte[] { b }, 0, 1);
-		}
-	}
+        public override void WriteByte(byte b)
+        {
+            this.handler.WriteData(new byte[] { b }, 0, 1);
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/TlsStreamCipher.cs b/crypto/src/crypto/tls/TlsStreamCipher.cs
new file mode 100644
index 000000000..45f2a9a70
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsStreamCipher.cs
@@ -0,0 +1,164 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Tls;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class TlsStreamCipher
+        :   TlsCipher
+    {
+        protected readonly TlsContext context;
+
+        protected readonly IStreamCipher encryptCipher;
+        protected readonly IStreamCipher decryptCipher;
+
+        protected readonly TlsMac writeMac;
+        protected readonly TlsMac readMac;
+
+        protected readonly bool usesNonce;
+
+        /// <exception cref="IOException"></exception>
+        public TlsStreamCipher(TlsContext context, IStreamCipher clientWriteCipher,
+            IStreamCipher serverWriteCipher, IDigest clientWriteDigest, IDigest serverWriteDigest,
+            int cipherKeySize, bool usesNonce)
+        {
+            bool isServer = context.IsServer;
+
+            this.context = context;
+            this.usesNonce = usesNonce;
+
+            this.encryptCipher = clientWriteCipher;
+            this.decryptCipher = serverWriteCipher;
+
+            int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize()
+                + serverWriteDigest.GetDigestSize();
+
+            byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);
+
+            int offset = 0;
+
+            // Init MACs
+            TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
+                clientWriteDigest.GetDigestSize());
+            offset += clientWriteDigest.GetDigestSize();
+            TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
+                serverWriteDigest.GetDigestSize());
+            offset += serverWriteDigest.GetDigestSize();
+
+            // Build keys
+            KeyParameter clientWriteKey = new KeyParameter(key_block, offset, cipherKeySize);
+            offset += cipherKeySize;
+            KeyParameter serverWriteKey = new KeyParameter(key_block, offset, cipherKeySize);
+            offset += cipherKeySize;
+
+            if (offset != key_block_size)
+            {
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+
+            ICipherParameters encryptParams, decryptParams;
+            if (isServer)
+            {
+                this.writeMac = serverWriteMac;
+                this.readMac = clientWriteMac;
+                this.encryptCipher = serverWriteCipher;
+                this.decryptCipher = clientWriteCipher;
+                encryptParams = serverWriteKey;
+                decryptParams = clientWriteKey;
+            }
+            else
+            {
+                this.writeMac = clientWriteMac;
+                this.readMac = serverWriteMac;
+                this.encryptCipher = clientWriteCipher;
+                this.decryptCipher = serverWriteCipher;
+                encryptParams = clientWriteKey;
+                decryptParams = serverWriteKey;
+            }
+
+            if (usesNonce)
+            {
+                byte[] dummyNonce = new byte[8];
+                encryptParams = new ParametersWithIV(encryptParams, dummyNonce);
+                decryptParams = new ParametersWithIV(decryptParams, dummyNonce);
+            }
+
+            this.encryptCipher.Init(true, encryptParams);
+            this.decryptCipher.Init(false, decryptParams);
+        }
+
+        public virtual int GetPlaintextLimit(int ciphertextLimit)
+        {
+            return ciphertextLimit - writeMac.Size;
+        }
+
+        public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len)
+        {
+            /*
+             * draft-josefsson-salsa20-tls-04 2.1 Note that Salsa20 requires a 64-bit nonce. That
+             * nonce is updated on the encryption of every TLS record, and is set to be the 64-bit TLS
+             * record sequence number. In case of DTLS the 64-bit nonce is formed as the concatenation
+             * of the 16-bit epoch with the 48-bit sequence number.
+             */
+            if (usesNonce)
+            {
+                UpdateIV(encryptCipher, true, seqNo);
+            }
+
+            byte[] outBuf = new byte[len + writeMac.Size];
+
+            encryptCipher.ProcessBytes(plaintext, offset, len, outBuf, 0);
+
+            byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len);
+            encryptCipher.ProcessBytes(mac, 0, mac.Length, outBuf, len);
+
+            return outBuf;
+        }
+
+        /// <exception cref="IOException"></exception>
+        public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len)
+        {
+            /*
+             * draft-josefsson-salsa20-tls-04 2.1 Note that Salsa20 requires a 64-bit nonce. That
+             * nonce is updated on the encryption of every TLS record, and is set to be the 64-bit TLS
+             * record sequence number. In case of DTLS the 64-bit nonce is formed as the concatenation
+             * of the 16-bit epoch with the 48-bit sequence number.
+             */
+            if (usesNonce)
+            {
+                UpdateIV(decryptCipher, false, seqNo);
+            }
+
+            int macSize = readMac.Size;
+            if (len < macSize)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+
+            int plaintextLength = len - macSize;
+
+            byte[] deciphered = new byte[len];
+            decryptCipher.ProcessBytes(ciphertext, offset, len, deciphered, 0);
+            CheckMac(seqNo, type, deciphered, plaintextLength, len, deciphered, 0, plaintextLength);
+            return Arrays.CopyOfRange(deciphered, 0, plaintextLength);
+        }
+
+        /// <exception cref="IOException"></exception>
+        protected virtual void CheckMac(long seqNo, byte type, byte[] recBuf, int recStart, int recEnd, byte[] calcBuf, int calcOff, int calcLen)
+        {
+            byte[] receivedMac = Arrays.CopyOfRange(recBuf, recStart, recEnd);
+            byte[] computedMac = readMac.CalculateMac(seqNo, type, calcBuf, calcOff, calcLen);
+
+            if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac))
+                throw new TlsFatalAlert(AlertDescription.bad_record_mac);
+        }
+
+        protected virtual void UpdateIV(IStreamCipher cipher, bool forEncryption, long seqNo)
+        {
+            byte[] nonce = new byte[8];
+            TlsUtilities.WriteUint64(seqNo, nonce, 0);
+            cipher.Init(forEncryption, new ParametersWithIV(null, nonce));
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 0e2452689..f1ea0996d 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -1,286 +1,1631 @@
 using System;
+using System.Collections;
 using System.IO;
 using System.Text;
 
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Macs;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Date;
 using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Crypto.Tls
 {
-	/// <remarks>Some helper fuctions for MicroTLS.</remarks>
-	public class TlsUtilities
-	{
-		internal static void WriteUint8(byte i, Stream os)
-		{
-			os.WriteByte(i);
-		}
-
-		internal static void WriteUint8(byte i, byte[] buf, int offset)
-		{
-			buf[offset] = i;
-		}
-
-		internal static void WriteUint16(int i, Stream os)
-		{
-			os.WriteByte((byte)(i >> 8));
-			os.WriteByte((byte)i);
-		}
-
-		internal static void WriteUint16(int i, byte[] buf, int offset)
-		{
-			buf[offset] = (byte)(i >> 8);
-			buf[offset + 1] = (byte)i;
-		}
-
-		internal static void WriteUint24(int i, Stream os)
-		{
-			os.WriteByte((byte)(i >> 16));
-			os.WriteByte((byte)(i >> 8));
-			os.WriteByte((byte)i);
-		}
-
-		internal static void WriteUint24(int i, byte[] buf, int offset)
-		{
-			buf[offset] = (byte)(i >> 16);
-			buf[offset + 1] = (byte)(i >> 8);
-			buf[offset + 2] = (byte)(i);
-		}
-
-		internal static void WriteUint64(long i, Stream os)
-		{
-			os.WriteByte((byte)(i >> 56));
-			os.WriteByte((byte)(i >> 48));
-			os.WriteByte((byte)(i >> 40));
-			os.WriteByte((byte)(i >> 32));
-			os.WriteByte((byte)(i >> 24));
-			os.WriteByte((byte)(i >> 16));
-			os.WriteByte((byte)(i >> 8));
-			os.WriteByte((byte)i);
-		}
-
-		internal static void WriteUint64(long i, byte[] buf, int offset)
-		{
-			buf[offset] = (byte)(i >> 56);
-			buf[offset + 1] = (byte)(i >> 48);
-			buf[offset + 2] = (byte)(i >> 40);
-			buf[offset + 3] = (byte)(i >> 32);
-			buf[offset + 4] = (byte)(i >> 24);
-			buf[offset + 5] = (byte)(i >> 16);
-			buf[offset + 6] = (byte)(i >> 8);
-			buf[offset + 7] = (byte)(i);
-		}
-
-		internal static void WriteOpaque8(byte[] buf, Stream os)
-		{
-			WriteUint8((byte)buf.Length, os);
-			os.Write(buf, 0, buf.Length);
-		}
-
-		internal static void WriteOpaque16(byte[] buf, Stream os)
-		{
-			WriteUint16(buf.Length, os);
-			os.Write(buf, 0, buf.Length);
-		}
-
-		internal static void WriteOpaque24(byte[] buf, Stream os)
-		{
-			WriteUint24(buf.Length, os);
-			os.Write(buf, 0, buf.Length);
-		}
-
-		internal static void WriteUint8Array(byte[] uints, Stream os)
-		{
-            os.Write(uints, 0, uints.Length);
-		}
-
-		internal static void WriteUint16Array(int[] uints, Stream os)
-		{
-			for (int i = 0; i < uints.Length; ++i)
-			{
-				WriteUint16(uints[i], os);
-			}
-		}
-
-		internal static byte ReadUint8(Stream inStr)
-		{
-			int i = inStr.ReadByte();
-			if (i < 0)
-			{
-				throw new EndOfStreamException();
-			}
-			return (byte)i;
-		}
-
-		internal static int ReadUint16(Stream inStr)
-		{
-			int i1 = inStr.ReadByte();
-			int i2 = inStr.ReadByte();
-			if ((i1 | i2) < 0)
-			{
-				throw new EndOfStreamException();
-			}
-			return i1 << 8 | i2;
-		}
-
-		internal static int ReadUint24(Stream inStr)
-		{
-			int i1 = inStr.ReadByte();
-			int i2 = inStr.ReadByte();
-			int i3 = inStr.ReadByte();
-			if ((i1 | i2 | i3) < 0)
-			{
-				throw new EndOfStreamException();
-			}
-			return (i1 << 16) | (i2 << 8) | i3;
-		}
-
-		internal static void ReadFully(byte[] buf, Stream inStr)
-		{
-			if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length)
-				throw new EndOfStreamException();
-		}
-
-		internal static byte[] ReadOpaque8(Stream inStr)
-		{
-			byte length = ReadUint8(inStr);
-			byte[] bytes = new byte[length];
-			ReadFully(bytes, inStr);
-			return bytes;
-		}
-
-		internal static byte[] ReadOpaque16(Stream inStr)
-		{
-			int length = ReadUint16(inStr);
-			byte[] bytes = new byte[length];
-			ReadFully(bytes, inStr);
-			return bytes;
-		}
-
-		internal static void CheckVersion(byte[] readVersion)
-		{
-			if ((readVersion[0] != 3) || (readVersion[1] != 1))
-			{
-				throw new TlsFatalAlert(AlertDescription.protocol_version);
-			}
-		}
-
-		internal static void CheckVersion(Stream inStr)
-		{
-			int i1 = inStr.ReadByte();
-			int i2 = inStr.ReadByte();
-			if ((i1 != 3) || (i2 != 1))
-			{
-				throw new TlsFatalAlert(AlertDescription.protocol_version);
-			}
-		}
-
-		internal static void WriteGmtUnixTime(byte[] buf, int offset)
-	    {
-			int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);
-			buf[offset] = (byte)(t >> 24);
-			buf[offset + 1] = (byte)(t >> 16);
-			buf[offset + 2] = (byte)(t >> 8);
-			buf[offset + 3] = (byte)t;
-	    }
-
-		internal static void WriteVersion(Stream os)
-		{
-			os.WriteByte(3);
-			os.WriteByte(1);
-		}
-
-		internal static void WriteVersion(byte[] buf, int offset)
-		{
-			buf[offset] = 3;
-			buf[offset + 1] = 1;
-		}
-
-		private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
-		{
-			HMac mac = new HMac(digest);
-			KeyParameter param = new KeyParameter(secret);
-			byte[] a = seed;
-			int size = digest.GetDigestSize();
-			int iterations = (output.Length + size - 1) / size;
-			byte[] buf = new byte[mac.GetMacSize()];
-			byte[] buf2 = new byte[mac.GetMacSize()];
-			for (int i = 0; i < iterations; i++)
-			{
-				mac.Init(param);
-				mac.BlockUpdate(a, 0, a.Length);
-				mac.DoFinal(buf, 0);
-				a = buf;
-				mac.Init(param);
-				mac.BlockUpdate(a, 0, a.Length);
-				mac.BlockUpdate(seed, 0, seed.Length);
-				mac.DoFinal(buf2, 0);
-				Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
-			}
-		}
-
-		internal static byte[] PRF(byte[] secret, string asciiLabel, byte[] seed, int size)
-		{
-            byte[] label = Strings.ToAsciiByteArray(asciiLabel);
-
-			int s_half = (secret.Length + 1) / 2;
-			byte[] s1 = new byte[s_half];
-			byte[] s2 = new byte[s_half];
-			Array.Copy(secret, 0, s1, 0, s_half);
-			Array.Copy(secret, secret.Length - s_half, s2, 0, s_half);
-
-			byte[] ls = Concat(label, seed);
-
-			byte[] buf = new byte[size];
-			byte[] prf = new byte[size];
-			hmac_hash(new MD5Digest(), s1, ls, prf);
-			hmac_hash(new Sha1Digest(), s2, ls, buf);
-			for (int i = 0; i < size; i++)
-			{
-				buf[i] ^= prf[i];
-			}
-			return buf;
-		}
-
-		internal static byte[] PRF_1_2(IDigest digest, byte[] secret, string asciiLabel, byte[] seed, int size)
-		{
-            byte[] label = Strings.ToAsciiByteArray(asciiLabel);
-			byte[] labelSeed = Concat(label, seed);
-
-			byte[] buf = new byte[size];
-			hmac_hash(digest, secret, labelSeed, buf);
-			return buf;
-		}
-
-		internal static byte[] Concat(byte[] a, byte[] b)
-		{
-			byte[] c = new byte[a.Length + b.Length];
-			Array.Copy(a, 0, c, 0, a.Length);
-			Array.Copy(b, 0, c, a.Length, b.Length);
-			return c;
-		}
-
-		internal static void ValidateKeyUsage(X509CertificateStructure c, int keyUsageBits)
-		{
-			X509Extensions exts = c.TbsCertificate.Extensions;
-			if (exts != null)
-			{
-				X509Extension ext = exts.GetExtension(X509Extensions.KeyUsage);
-				if (ext != null)
-				{
-					DerBitString ku = KeyUsage.GetInstance(ext);
-                    //int bits = ku.GetBytes()[0];
-                    //if ((bits & keyUsageBits) != keyUsageBits)
-                    //{
-                    //    throw new TlsFatalAlert(AlertDescription.certificate_unknown);
-                    //}
-				}
-			}
-		}
-	}
+    /// <remarks>Some helper functions for MicroTLS.</remarks>
+    public abstract class TlsUtilities
+    {
+        public static readonly byte[] EmptyBytes = new byte[0];
+
+        public static void CheckUint8(int i)
+        {
+            if (!IsValidUint8(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint8(long i)
+        {
+            if (!IsValidUint8(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint16(int i)
+        {
+            if (!IsValidUint16(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint16(long i)
+        {
+            if (!IsValidUint16(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint24(int i)
+        {
+            if (!IsValidUint24(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint24(long i)
+        {
+            if (!IsValidUint24(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint32(long i)
+        {
+            if (!IsValidUint32(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint48(long i)
+        {
+            if (!IsValidUint48(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint64(long i)
+        {
+            if (!IsValidUint64(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static bool IsValidUint8(int i)
+        {
+            return (i & 0xFF) == i;
+        }
+
+        public static bool IsValidUint8(long i)
+        {
+            return (i & 0xFFL) == i;
+        }
+
+        public static bool IsValidUint16(int i)
+        {
+            return (i & 0xFFFF) == i;
+        }
+
+        public static bool IsValidUint16(long i)
+        {
+            return (i & 0xFFFFL) == i;
+        }
+
+        public static bool IsValidUint24(int i)
+        {
+            return (i & 0xFFFFFF) == i;
+        }
+
+        public static bool IsValidUint24(long i)
+        {
+            return (i & 0xFFFFFFL) == i;
+        }
+
+        public static bool IsValidUint32(long i)
+        {
+            return (i & 0xFFFFFFFFL) == i;
+        }
+
+        public static bool IsValidUint48(long i)
+        {
+            return (i & 0xFFFFFFFFFFFFL) == i;
+        }
+
+        public static bool IsValidUint64(long i)
+        {
+            return true;
+        }
+
+        public static bool IsSsl(TlsContext context)
+        {
+            return context.ServerVersion.IsSsl;
+        }
+
+        public static bool IsTlsV11(TlsContext context)
+        {
+            return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
+        }
+
+        public static bool IsTlsV12(TlsContext context)
+        {
+            return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
+        }
+
+        public static void WriteUint8(byte i, Stream output)
+        {
+            output.WriteByte(i);
+        }
+
+        public static void WriteUint8(byte i, byte[] buf, int offset)
+        {
+            buf[offset] = i;
+        }
+
+        public static void WriteUint16(int i, Stream output)
+        {
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
+        }
+
+        public static void WriteUint16(int i, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)(i >> 8);
+            buf[offset + 1] = (byte)i;
+        }
+
+        public static void WriteUint24(int i, Stream output)
+        {
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
+        }
+
+        public static void WriteUint24(int i, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)(i >> 16);
+            buf[offset + 1] = (byte)(i >> 8);
+            buf[offset + 2] = (byte)i;
+        }
+
+        public static void WriteUint32(long i, Stream output)
+        {
+            output.WriteByte((byte)(i >> 24));
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
+        }
+
+        public static void WriteUint32(long i, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)(i >> 24);
+            buf[offset + 1] = (byte)(i >> 16);
+            buf[offset + 2] = (byte)(i >> 8);
+            buf[offset + 3] = (byte)i;
+        }
+
+        public static void WriteUint48(long i, Stream output)
+        {
+            output.WriteByte((byte)(i >> 40));
+            output.WriteByte((byte)(i >> 32));
+            output.WriteByte((byte)(i >> 24));
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
+        }
+
+        public static void WriteUint48(long i, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)(i >> 40);
+            buf[offset + 1] = (byte)(i >> 32);
+            buf[offset + 2] = (byte)(i >> 24);
+            buf[offset + 3] = (byte)(i >> 16);
+            buf[offset + 4] = (byte)(i >> 8);
+            buf[offset + 5] = (byte)i;
+        }
+
+        public static void WriteUint64(long i, Stream output)
+        {
+            output.WriteByte((byte)(i >> 56));
+            output.WriteByte((byte)(i >> 48));
+            output.WriteByte((byte)(i >> 40));
+            output.WriteByte((byte)(i >> 32));
+            output.WriteByte((byte)(i >> 24));
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
+        }
+
+        public static void WriteUint64(long i, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)(i >> 56);
+            buf[offset + 1] = (byte)(i >> 48);
+            buf[offset + 2] = (byte)(i >> 40);
+            buf[offset + 3] = (byte)(i >> 32);
+            buf[offset + 4] = (byte)(i >> 24);
+            buf[offset + 5] = (byte)(i >> 16);
+            buf[offset + 6] = (byte)(i >> 8);
+            buf[offset + 7] = (byte)i;
+        }
+
+        public static void WriteOpaque8(byte[] buf, Stream output)
+        {
+            WriteUint8((byte)buf.Length, output);
+            output.Write(buf, 0, buf.Length);
+        }
+
+        public static void WriteOpaque16(byte[] buf, Stream output)
+        {
+            WriteUint16(buf.Length, output);
+            output.Write(buf, 0, buf.Length);
+        }
+
+        public static void WriteOpaque24(byte[] buf, Stream output)
+        {
+            WriteUint24(buf.Length, output);
+            output.Write(buf, 0, buf.Length);
+        }
+
+        public static void WriteUint8Array(byte[] uints, Stream output)
+        {
+            output.Write(uints, 0, uints.Length);
+        }
+
+        public static void WriteUint8Array(byte[] uints, byte[] buf, int offset)
+        {
+            for (int i = 0; i < uints.Length; ++i)
+            {
+                WriteUint8(uints[i], buf, offset);
+                ++offset;
+            }
+        }
+
+        public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output)
+        {
+            CheckUint8(uints.Length);
+            WriteUint8((byte)uints.Length, output);
+            WriteUint8Array(uints, output);
+        }
+
+        public static void WriteUint8ArrayWithUint8Length(byte[] uints, byte[] buf, int offset)
+        {
+            CheckUint8(uints.Length);
+            WriteUint8((byte)uints.Length, buf, offset);
+            WriteUint8Array(uints, buf, offset + 1);
+        }
+
+        public static void WriteUint16Array(int[] uints, Stream output)
+        {
+            for (int i = 0; i < uints.Length; ++i)
+            {
+                WriteUint16(uints[i], output);
+            }
+        }
+
+        public static void WriteUint16Array(int[] uints, byte[] buf, int offset)
+        {
+            for (int i = 0; i < uints.Length; ++i)
+            {
+                WriteUint16(uints[i], buf, offset);
+                offset += 2;
+            }
+        }
+
+        public static void WriteUint16ArrayWithUint16Length(int[] uints, Stream output)
+        {
+            int length = 2 * uints.Length;
+            CheckUint16(length);
+            WriteUint16(length, output);
+            WriteUint16Array(uints, output);
+        }
+
+        public static void WriteUint16ArrayWithUint16Length(int[] uints, byte[] buf, int offset)
+        {
+            int length = 2 * uints.Length;
+            CheckUint16(length);
+            WriteUint16(length, buf, offset);
+            WriteUint16Array(uints, buf, offset + 2);
+        }
+
+        public static byte[] EncodeOpaque8(byte[] buf)
+        {
+            CheckUint8(buf.Length);
+            return Arrays.Prepend(buf, (byte)buf.Length);
+        }
+
+        public static byte[] EncodeUint8ArrayWithUint8Length(byte[] uints)
+        {
+            byte[] result = new byte[1 + uints.Length];
+            WriteUint8ArrayWithUint8Length(uints, result, 0);
+            return result;
+        }
+
+        public static byte[] EncodeUint16ArrayWithUint16Length(int[] uints)
+        {
+            int length = 2 * uints.Length;
+            byte[] result = new byte[2 + length];
+            WriteUint16ArrayWithUint16Length(uints, result, 0);
+            return result;
+        }
+
+        public static byte ReadUint8(Stream input)
+        {
+            int i = input.ReadByte();
+            if (i < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return (byte)i;
+        }
+
+        public static byte ReadUint8(byte[] buf, int offset)
+        {
+            return buf[offset];
+        }
+
+        public static int ReadUint16(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            if ((i1 | i2) < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return i1 << 8 | i2;
+        }
+
+        public static int ReadUint16(byte[] buf, int offset)
+        {
+            uint n = (uint)buf[offset] << 8;
+            n |= (uint)buf[++offset];
+            return (int)n;
+        }
+
+        public static int ReadUint24(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            int i3 = input.ReadByte();
+            if ((i1 | i2 | i3) < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return (i1 << 16) | (i2 << 8) | i3;
+        }
+
+        public static int ReadUint24(byte[] buf, int offset)
+        {
+            uint n = (uint)buf[offset] << 16;
+            n |= (uint)buf[++offset] << 8;
+            n |= (uint)buf[++offset];
+            return (int)n;
+        }
+
+        public static long ReadUint32(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            int i3 = input.ReadByte();
+            int i4 = input.ReadByte();
+            if (i4 < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return (long)(uint)((i1 << 24) | (i2 << 16) | (i3 << 8) | i4);
+        }
+
+        public static long ReadUint32(byte[] buf, int offset)
+        {
+            uint n = (uint)buf[offset] << 24;
+            n |= (uint)buf[++offset] << 16;
+            n |= (uint)buf[++offset] << 8;
+            n |= (uint)buf[++offset];
+            return (long)n;
+        }
+
+        public static long ReadUint48(Stream input)
+        {
+            int hi = ReadUint24(input);
+            int lo = ReadUint24(input);
+            return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+        }
+
+        public static long ReadUint48(byte[] buf, int offset)
+        {
+            int hi = ReadUint24(buf, offset);
+            int lo = ReadUint24(buf, offset + 3);
+            return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+        }
+
+        public static byte[] ReadAllOrNothing(int length, Stream input)
+        {
+            if (length < 1)
+                return EmptyBytes;
+            byte[] buf = new byte[length];
+            int read = Streams.ReadFully(input, buf);
+            if (read == 0)
+                return null;
+            if (read != length)
+                throw new EndOfStreamException();
+            return buf;
+        }
+
+        public static byte[] ReadFully(int length, Stream input)
+        {
+            if (length < 1)
+                return EmptyBytes;
+            byte[] buf = new byte[length];
+            if (length != Streams.ReadFully(input, buf))
+                throw new EndOfStreamException();
+            return buf;
+        }
+
+        public static void ReadFully(byte[] buf, Stream input)
+        {
+            if (Streams.ReadFully(input, buf, 0, buf.Length) < buf.Length)
+                throw new EndOfStreamException();
+        }
+
+        public static byte[] ReadOpaque8(Stream input)
+        {
+            byte length = ReadUint8(input);
+            byte[] bytes = new byte[length];
+            ReadFully(bytes, input);
+            return bytes;
+        }
+
+        public static byte[] ReadOpaque16(Stream input)
+        {
+            int length = ReadUint16(input);
+            byte[] bytes = new byte[length];
+            ReadFully(bytes, input);
+            return bytes;
+        }
+
+        public static byte[] ReadOpaque24(Stream input)
+        {
+            int length = ReadUint24(input);
+            return ReadFully(length, input);
+        }
+
+        public static byte[] ReadUint8Array(int count, Stream input)
+        {
+            byte[] uints = new byte[count];
+            for (int i = 0; i < count; ++i)
+            {
+                uints[i] = ReadUint8(input);
+            }
+            return uints;
+        }
+
+        public static int[] ReadUint16Array(int count, Stream input)
+        {
+            int[] uints = new int[count];
+            for (int i = 0; i < count; ++i)
+            {
+                uints[i] = ReadUint16(input);
+            }
+            return uints;
+        }
+
+        public static ProtocolVersion ReadVersion(byte[] buf, int offset)
+        {
+            return ProtocolVersion.Get(buf[offset], buf[offset + 1]);
+        }
+
+        public static ProtocolVersion ReadVersion(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            if (i2 < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return ProtocolVersion.Get(i1, i2);
+        }
+
+        public static int ReadVersionRaw(byte[] buf, int offset)
+        {
+            return (buf[offset] << 8) | buf[offset + 1];
+        }
+
+        public static int ReadVersionRaw(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            if (i2 < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return (i1 << 8) | i2;
+        }
+
+        public static Asn1Object ReadAsn1Object(byte[] encoding)
+        {
+            Asn1InputStream asn1 = new Asn1InputStream(encoding);
+            Asn1Object result = asn1.ReadObject();
+            if (null == result)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            if (null != asn1.ReadObject())
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            return result;
+        }
+
+        public static Asn1Object ReadDerObject(byte[] encoding)
+        {
+            /*
+             * NOTE: The current ASN.1 parsing code can't enforce DER-only parsing, but since DER is
+             * canonical, we can check it by re-encoding the result and comparing to the original.
+             */
+            Asn1Object result = ReadAsn1Object(encoding);
+            byte[] check = result.GetEncoded(Asn1Encodable.Der);
+            if (!Arrays.AreEqual(check, encoding))
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            return result;
+        }
+
+        public static void WriteGmtUnixTime(byte[] buf, int offset)
+        {
+            int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);
+            buf[offset] = (byte)(t >> 24);
+            buf[offset + 1] = (byte)(t >> 16);
+            buf[offset + 2] = (byte)(t >> 8);
+            buf[offset + 3] = (byte)t;
+        }
+
+        public static void WriteVersion(ProtocolVersion version, Stream output)
+        {
+            output.WriteByte((byte)version.MajorVersion);
+            output.WriteByte((byte)version.MinorVersion);
+        }
+
+        public static void WriteVersion(ProtocolVersion version, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)version.MajorVersion;
+            buf[offset + 1] = (byte)version.MinorVersion;
+        }
+
+        public static IList GetDefaultDssSignatureAlgorithms()
+        {
+            return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.dsa));
+        }
+
+        public static IList GetDefaultECDsaSignatureAlgorithms()
+        {
+            return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa));
+        }
+
+        public static IList GetDefaultRsaSignatureAlgorithms()
+        {
+            return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa));
+        }
+
+        public static byte[] GetExtensionData(IDictionary extensions, int extensionType)
+        {
+            return extensions == null ? null : (byte[])extensions[extensionType];
+        }
+
+        public static bool HasExpectedEmptyExtensionData(IDictionary extensions, int extensionType,
+            byte alertDescription)
+        {
+            byte[] extension_data = GetExtensionData(extensions, extensionType);
+            if (extension_data == null)
+                return false;
+            if (extension_data.Length != 0)
+                throw new TlsFatalAlert(alertDescription);
+            return true;
+        }
+
+        public static TlsSession ImportSession(byte[] sessionID, SessionParameters sessionParameters)
+        {
+            return new TlsSessionImpl(sessionID, sessionParameters);
+        }
+
+        public static bool IsSignatureAlgorithmsExtensionAllowed(ProtocolVersion clientVersion)
+        {
+            return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(clientVersion.GetEquivalentTLSVersion());
+        }
+
+        /**
+         * Add a 'signature_algorithms' extension to existing extensions.
+         *
+         * @param extensions                   A {@link Hashtable} to add the extension to.
+         * @param supportedSignatureAlgorithms {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+         * @throws IOException
+         */
+        public static void AddSignatureAlgorithmsExtension(IDictionary extensions, IList supportedSignatureAlgorithms)
+        {
+            extensions[ExtensionType.signature_algorithms] = CreateSignatureAlgorithmsExtension(supportedSignatureAlgorithms);
+        }
+
+        /**
+         * Get a 'signature_algorithms' extension from extensions.
+         *
+         * @param extensions A {@link Hashtable} to get the extension from, if it is present.
+         * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}, or null.
+         * @throws IOException
+         */
+        public static IList GetSignatureAlgorithmsExtension(IDictionary extensions)
+        {
+            byte[] extensionData = GetExtensionData(extensions, ExtensionType.signature_algorithms);
+            return extensionData == null ? null : ReadSignatureAlgorithmsExtension(extensionData);
+        }
+
+        /**
+         * Create a 'signature_algorithms' extension value.
+         *
+         * @param supportedSignatureAlgorithms A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+         * @return A byte array suitable for use as an extension value.
+         * @throws IOException
+         */
+        public static byte[] CreateSignatureAlgorithmsExtension(IList supportedSignatureAlgorithms)
+        {
+            MemoryStream buf = new MemoryStream();
+
+            // supported_signature_algorithms
+            EncodeSupportedSignatureAlgorithms(supportedSignatureAlgorithms, false, buf);
+
+            return buf.ToArray();
+        }
+
+        /**
+         * Read 'signature_algorithms' extension data.
+         *
+         * @param extensionData The extension data.
+         * @return A {@link Vector} containing at least 1 {@link SignatureAndHashAlgorithm}.
+         * @throws IOException
+         */
+        public static IList ReadSignatureAlgorithmsExtension(byte[] extensionData)
+        {
+            if (extensionData == null)
+                throw new ArgumentNullException("extensionData");
+
+            MemoryStream buf = new MemoryStream(extensionData, false);
+
+            // supported_signature_algorithms
+            IList supported_signature_algorithms = ParseSupportedSignatureAlgorithms(false, buf);
+
+            TlsProtocol.AssertEmpty(buf);
+
+            return supported_signature_algorithms;
+        }
+
+        public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous,
+            Stream output)
+        {
+            if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1
+                || supportedSignatureAlgorithms.Count >= (1 << 15))
+            {
+                throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
+            }
+
+            // supported_signature_algorithms
+            int length = 2 * supportedSignatureAlgorithms.Count;
+            CheckUint16(length);
+            WriteUint16(length, output);
+
+            foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms)
+            {
+                if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous)
+                {
+                    /*
+                     * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used
+                     * in Section 7.4.3. It MUST NOT appear in this extension.
+                     */
+                    throw new ArgumentException(
+                        "SignatureAlgorithm.anonymous MUST NOT appear in the signature_algorithms extension");
+                }
+                entry.Encode(output);
+            }
+        }
+
+        public static IList ParseSupportedSignatureAlgorithms(bool allowAnonymous, Stream input)
+        {
+            // supported_signature_algorithms
+            int length = ReadUint16(input);
+            if (length < 2 || (length & 1) != 0)
+                throw new TlsFatalAlert(AlertDescription.decode_error);
+            int count = length / 2;
+            IList supportedSignatureAlgorithms = Platform.CreateArrayList(count);
+            for (int i = 0; i < count; ++i)
+            {
+                SignatureAndHashAlgorithm entry = SignatureAndHashAlgorithm.Parse(input);
+                if (!allowAnonymous && entry.Signature == SignatureAlgorithm.anonymous)
+                {
+                    /*
+                     * RFC 5246 7.4.1.4.1 The "anonymous" value is meaningless in this context but used
+                     * in Section 7.4.3. It MUST NOT appear in this extension.
+                     */
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                }
+                supportedSignatureAlgorithms.Add(entry);
+            }
+            return supportedSignatureAlgorithms;
+        }
+
+        public static byte[] PRF(TlsContext context, byte[] secret, string asciiLabel, byte[] seed, int size)
+        {
+            ProtocolVersion version = context.ServerVersion;
+
+            if (version.IsSsl)
+                throw new InvalidOperationException("No PRF available for SSLv3 session");
+
+            byte[] label = Strings.ToByteArray(asciiLabel);
+            byte[] labelSeed = Concat(label, seed);
+
+            int prfAlgorithm = context.SecurityParameters.PrfAlgorithm;
+
+            if (prfAlgorithm == PrfAlgorithm.tls_prf_legacy)
+            {
+                return PRF_legacy(secret, label, labelSeed, size);
+            }
+
+            IDigest prfDigest = CreatePrfHash(prfAlgorithm);
+            byte[] buf = new byte[size];
+            HMacHash(prfDigest, secret, labelSeed, buf);
+            return buf;
+        }
+
+        public static byte[] PRF_legacy(byte[] secret, string asciiLabel, byte[] seed, int size)
+        {
+            byte[] label = Strings.ToByteArray(asciiLabel);
+            byte[] labelSeed = Concat(label, seed);
+
+            return PRF_legacy(secret, label, labelSeed, size);
+        }
+
+        internal static byte[] PRF_legacy(byte[] secret, byte[] label, byte[] labelSeed, int size)
+        {
+            int s_half = (secret.Length + 1) / 2;
+            byte[] s1 = new byte[s_half];
+            byte[] s2 = new byte[s_half];
+            Array.Copy(secret, 0, s1, 0, s_half);
+            Array.Copy(secret, secret.Length - s_half, s2, 0, s_half);
+
+            byte[] b1 = new byte[size];
+            byte[] b2 = new byte[size];
+            HMacHash(CreateHash(HashAlgorithm.md5), s1, labelSeed, b1);
+            HMacHash(CreateHash(HashAlgorithm.sha1), s2, labelSeed, b2);
+            for (int i = 0; i < size; i++)
+            {
+                b1[i] ^= b2[i];
+            }
+            return b1;
+        }
+
+        internal static byte[] Concat(byte[] a, byte[] b)
+        {
+            byte[] c = new byte[a.Length + b.Length];
+            Array.Copy(a, 0, c, 0, a.Length);
+            Array.Copy(b, 0, c, a.Length, b.Length);
+            return c;
+        }
+
+        internal static void HMacHash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
+        {
+            HMac mac = new HMac(digest);
+            mac.Init(new KeyParameter(secret));
+            byte[] a = seed;
+            int size = digest.GetDigestSize();
+            int iterations = (output.Length + size - 1) / size;
+            byte[] buf = new byte[mac.GetMacSize()];
+            byte[] buf2 = new byte[mac.GetMacSize()];
+            for (int i = 0; i < iterations; i++)
+            {
+                mac.BlockUpdate(a, 0, a.Length);
+                mac.DoFinal(buf, 0);
+                a = buf;
+                mac.BlockUpdate(a, 0, a.Length);
+                mac.BlockUpdate(seed, 0, seed.Length);
+                mac.DoFinal(buf2, 0);
+                Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
+            }
+        }
+
+        internal static void ValidateKeyUsage(X509CertificateStructure c, int keyUsageBits)
+        {
+            X509Extensions exts = c.TbsCertificate.Extensions;
+            if (exts != null)
+            {
+                X509Extension ext = exts.GetExtension(X509Extensions.KeyUsage);
+                if (ext != null)
+                {
+                    DerBitString ku = KeyUsage.GetInstance(ext);
+                    int bits = ku.GetBytes()[0];
+                    if ((bits & keyUsageBits) != keyUsageBits)
+                    {
+                        throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+                    }
+                }
+            }
+        }
+
+        internal static byte[] CalculateKeyBlock(TlsContext context, int size)
+        {
+            SecurityParameters securityParameters = context.SecurityParameters;
+            byte[] master_secret = securityParameters.MasterSecret;
+            byte[] seed = Concat(securityParameters.ServerRandom, securityParameters.ClientRandom);
+
+            if (IsSsl(context))
+            {
+                return CalculateKeyBlock_Ssl(master_secret, seed, size);
+            }
+
+            return PRF(context, master_secret, ExporterLabel.key_expansion, seed, size);
+        }
+
+        internal static byte[] CalculateKeyBlock_Ssl(byte[] master_secret, byte[] random, int size)
+        {
+            IDigest md5 = CreateHash(HashAlgorithm.md5);
+            IDigest sha1 = CreateHash(HashAlgorithm.sha1);
+            int md5Size = md5.GetDigestSize();
+            byte[] shatmp = new byte[sha1.GetDigestSize()];
+            byte[] tmp = new byte[size + md5Size];
+
+            int i = 0, pos = 0;
+            while (pos < size)
+            {
+                byte[] ssl3Const = SSL3_CONST[i];
+
+                sha1.BlockUpdate(ssl3Const, 0, ssl3Const.Length);
+                sha1.BlockUpdate(master_secret, 0, master_secret.Length);
+                sha1.BlockUpdate(random, 0, random.Length);
+                sha1.DoFinal(shatmp, 0);
+
+                md5.BlockUpdate(master_secret, 0, master_secret.Length);
+                md5.BlockUpdate(shatmp, 0, shatmp.Length);
+                md5.DoFinal(tmp, pos);
+
+                pos += md5Size;
+                ++i;
+            }
+
+            return Arrays.CopyOfRange(tmp, 0, size);
+        }
+
+        internal static byte[] CalculateMasterSecret(TlsContext context, byte[] pre_master_secret)
+        {
+            SecurityParameters securityParameters = context.SecurityParameters;
+            byte[] seed = Concat(securityParameters.ClientRandom, securityParameters.ServerRandom);
+
+            if (IsSsl(context))
+            {
+                return CalculateMasterSecret_Ssl(pre_master_secret, seed);
+            }
+
+            return PRF(context, pre_master_secret, ExporterLabel.master_secret, seed, 48);
+        }
+
+        internal static byte[] CalculateMasterSecret_Ssl(byte[] pre_master_secret, byte[] random)
+        {
+            IDigest md5 = CreateHash(HashAlgorithm.md5);
+            IDigest sha1 = CreateHash(HashAlgorithm.sha1);
+            int md5Size = md5.GetDigestSize();
+            byte[] shatmp = new byte[sha1.GetDigestSize()];
+
+            byte[] rval = new byte[md5Size * 3];
+            int pos = 0;
+
+            for (int i = 0; i < 3; ++i)
+            {
+                byte[] ssl3Const = SSL3_CONST[i];
+
+                sha1.BlockUpdate(ssl3Const, 0, ssl3Const.Length);
+                sha1.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length);
+                sha1.BlockUpdate(random, 0, random.Length);
+                sha1.DoFinal(shatmp, 0);
+
+                md5.BlockUpdate(pre_master_secret, 0, pre_master_secret.Length);
+                md5.BlockUpdate(shatmp, 0, shatmp.Length);
+                md5.DoFinal(rval, pos);
+
+                pos += md5Size;
+            }
+
+            return rval;
+        }
+
+        internal static byte[] CalculateVerifyData(TlsContext context, string asciiLabel, byte[] handshakeHash)
+        {
+            if (IsSsl(context))
+            {
+                return handshakeHash;
+            }
+
+            SecurityParameters securityParameters = context.SecurityParameters;
+            byte[] master_secret = securityParameters.MasterSecret;
+            int verify_data_length = securityParameters.VerifyDataLength;
+
+            return PRF(context, master_secret, asciiLabel, handshakeHash, verify_data_length);
+        }
+
+        public static IDigest CreateHash(byte hashAlgorithm)
+        {
+            switch (hashAlgorithm)
+            {
+            case HashAlgorithm.md5:
+                return new MD5Digest();
+            case HashAlgorithm.sha1:
+                return new Sha1Digest();
+            case HashAlgorithm.sha224:
+                return new Sha224Digest();
+            case HashAlgorithm.sha256:
+                return new Sha256Digest();
+            case HashAlgorithm.sha384:
+                return new Sha384Digest();
+            case HashAlgorithm.sha512:
+                return new Sha512Digest();
+            default:
+                throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+            }
+        }
+
+        public static IDigest CloneHash(byte hashAlgorithm, IDigest hash)
+        {
+            switch (hashAlgorithm)
+            {
+            case HashAlgorithm.md5:
+                return new MD5Digest((MD5Digest)hash);
+            case HashAlgorithm.sha1:
+                return new Sha1Digest((Sha1Digest)hash);
+            case HashAlgorithm.sha224:
+                return new Sha224Digest((Sha224Digest)hash);
+            case HashAlgorithm.sha256:
+                return new Sha256Digest((Sha256Digest)hash);
+            case HashAlgorithm.sha384:
+                return new Sha384Digest((Sha384Digest)hash);
+            case HashAlgorithm.sha512:
+                return new Sha512Digest((Sha512Digest)hash);
+            default:
+                throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+            }
+        }
+
+        public static IDigest CreatePrfHash(int prfAlgorithm)
+        {
+            switch (prfAlgorithm)
+            {
+                case PrfAlgorithm.tls_prf_legacy:
+                    return new CombinedHash();
+                default:
+                    return CreateHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm));
+            }
+        }
+
+        public static IDigest ClonePrfHash(int prfAlgorithm, IDigest hash)
+        {
+            switch (prfAlgorithm)
+            {
+                case PrfAlgorithm.tls_prf_legacy:
+                    return new CombinedHash((CombinedHash)hash);
+                default:
+                    return CloneHash(GetHashAlgorithmForPrfAlgorithm(prfAlgorithm), hash);
+            }
+        }
+
+        public static byte GetHashAlgorithmForPrfAlgorithm(int prfAlgorithm)
+        {
+            switch (prfAlgorithm)
+            {
+                case PrfAlgorithm.tls_prf_legacy:
+                    throw new ArgumentException("legacy PRF not a valid algorithm", "prfAlgorithm");
+                case PrfAlgorithm.tls_prf_sha256:
+                    return HashAlgorithm.sha256;
+                case PrfAlgorithm.tls_prf_sha384:
+                    return HashAlgorithm.sha384;
+                default:
+                    throw new ArgumentException("unknown PrfAlgorithm", "prfAlgorithm");
+            }
+        }
+
+        public static DerObjectIdentifier GetOidForHashAlgorithm(byte hashAlgorithm)
+        {
+            switch (hashAlgorithm)
+            {
+                case HashAlgorithm.md5:
+                    return PkcsObjectIdentifiers.MD5;
+                case HashAlgorithm.sha1:
+                    return X509ObjectIdentifiers.IdSha1;
+                case HashAlgorithm.sha224:
+                    return NistObjectIdentifiers.IdSha224;
+                case HashAlgorithm.sha256:
+                    return NistObjectIdentifiers.IdSha256;
+                case HashAlgorithm.sha384:
+                    return NistObjectIdentifiers.IdSha384;
+                case HashAlgorithm.sha512:
+                    return NistObjectIdentifiers.IdSha512;
+                default:
+                    throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+            }
+        }
+
+        internal static short GetClientCertificateType(Certificate clientCertificate, Certificate serverCertificate)
+        {
+            if (clientCertificate.IsEmpty)
+                return -1;
+
+            X509CertificateStructure x509Cert = clientCertificate.GetCertificateAt(0);
+            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
+            try
+            {
+                AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
+                if (publicKey.IsPrivate)
+                    throw new TlsFatalAlert(AlertDescription.internal_error);
+
+                /*
+                 * TODO RFC 5246 7.4.6. The certificates MUST be signed using an acceptable hash/
+                 * signature algorithm pair, as described in Section 7.4.4. Note that this relaxes the
+                 * constraints on certificate-signing algorithms found in prior versions of TLS.
+                 */
+
+                /*
+                 * RFC 5246 7.4.6. Client Certificate
+                 */
+
+                /*
+                 * RSA public key; the certificate MUST allow the key to be used for signing with the
+                 * signature scheme and hash algorithm that will be employed in the certificate verify
+                 * message.
+                 */
+                if (publicKey is RsaKeyParameters)
+                {
+                    ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+                    return ClientCertificateType.rsa_sign;
+                }
+
+                /*
+                 * DSA public key; the certificate MUST allow the key to be used for signing with the
+                 * hash algorithm that will be employed in the certificate verify message.
+                 */
+                if (publicKey is DsaPublicKeyParameters)
+                {
+                    ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+                    return ClientCertificateType.dss_sign;
+                }
+
+                /*
+                 * ECDSA-capable public key; the certificate MUST allow the key to be used for signing
+                 * with the hash algorithm that will be employed in the certificate verify message; the
+                 * public key MUST use a curve and point format supported by the server.
+                 */
+                if (publicKey is ECPublicKeyParameters)
+                {
+                    ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
+                    // TODO Check the curve and point format
+                    return ClientCertificateType.ecdsa_sign;
+                }
+
+                // TODO Add support for ClientCertificateType.*_fixed_*
+
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate);
+            }
+            catch (Exception e)
+            {
+                throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
+            }
+        }
+
+        internal static void TrackHashAlgorithms(TlsHandshakeHash handshakeHash, IList supportedSignatureAlgorithms)
+        {
+            if (supportedSignatureAlgorithms != null)
+            {
+                foreach (SignatureAndHashAlgorithm signatureAndHashAlgorithm in supportedSignatureAlgorithms)
+                {
+                    byte hashAlgorithm = signatureAndHashAlgorithm.Hash;
+                    handshakeHash.TrackHashAlgorithm(hashAlgorithm);
+                }
+            }
+        }
+
+        public static bool HasSigningCapability(byte clientCertificateType)
+        {
+            switch (clientCertificateType)
+            {
+            case ClientCertificateType.dss_sign:
+            case ClientCertificateType.ecdsa_sign:
+            case ClientCertificateType.rsa_sign:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public static TlsSigner CreateTlsSigner(byte clientCertificateType)
+        {
+            switch (clientCertificateType)
+            {
+            case ClientCertificateType.dss_sign:
+                return new TlsDssSigner();
+            case ClientCertificateType.ecdsa_sign:
+                return new TlsECDsaSigner();
+            case ClientCertificateType.rsa_sign:
+                return new TlsRsaSigner();
+            default:
+                throw new ArgumentException("not a type with signing capability", "clientCertificateType");
+            }
+        }
+
+        internal static readonly byte[] SSL_CLIENT = {0x43, 0x4C, 0x4E, 0x54};
+        internal static readonly byte[] SSL_SERVER = {0x53, 0x52, 0x56, 0x52};
+
+        // SSL3 magic mix constants ("A", "BB", "CCC", ...)
+        internal static readonly byte[][] SSL3_CONST = GenSsl3Const();
+
+        private static byte[][] GenSsl3Const()
+        {
+            int n = 10;
+            byte[][] arr = new byte[n][];
+            for (int i = 0; i < n; i++)
+            {
+                byte[] b = new byte[i + 1];
+                Arrays.Fill(b, (byte)('A' + i));
+                arr[i] = b;
+            }
+            return arr;
+        }
+
+        private static IList VectorOfOne(object obj)
+        {
+            IList v = Platform.CreateArrayList(1);
+            v.Add(obj);
+            return v;
+        }
+
+        public static int GetCipherType(int ciphersuite)
+        {
+            switch (GetEncryptionAlgorithm(ciphersuite))
+            {
+            case EncryptionAlgorithm.AES_128_GCM:
+            case EncryptionAlgorithm.AES_256_GCM:
+            case EncryptionAlgorithm.AES_128_CCM:
+            case EncryptionAlgorithm.AES_128_CCM_8:
+            case EncryptionAlgorithm.AES_256_CCM:
+            case EncryptionAlgorithm.AES_256_CCM_8:
+            case EncryptionAlgorithm.CAMELLIA_128_GCM:
+            case EncryptionAlgorithm.CAMELLIA_256_GCM:
+            case EncryptionAlgorithm.AEAD_CHACHA20_POLY1305:
+                return CipherType.aead;
+
+            case EncryptionAlgorithm.RC2_CBC_40:
+            case EncryptionAlgorithm.IDEA_CBC:
+            case EncryptionAlgorithm.DES40_CBC:
+            case EncryptionAlgorithm.DES_CBC:
+            case EncryptionAlgorithm.cls_3DES_EDE_CBC:
+            case EncryptionAlgorithm.AES_128_CBC:
+            case EncryptionAlgorithm.AES_256_CBC:
+            case EncryptionAlgorithm.CAMELLIA_128_CBC:
+            case EncryptionAlgorithm.CAMELLIA_256_CBC:
+            case EncryptionAlgorithm.SEED_CBC:
+                return CipherType.block;
+
+            case EncryptionAlgorithm.RC4_40:
+            case EncryptionAlgorithm.RC4_128:
+            case EncryptionAlgorithm.ESTREAM_SALSA20:
+            case EncryptionAlgorithm.SALSA20:
+                return CipherType.stream;
+
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public static int GetEncryptionAlgorithm(int ciphersuite)
+        {
+            switch (ciphersuite)
+            {
+            case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+                return EncryptionAlgorithm.cls_3DES_EDE_CBC;
+
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+                return EncryptionAlgorithm.AEAD_CHACHA20_POLY1305;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+                return EncryptionAlgorithm.AES_128_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+                return EncryptionAlgorithm.AES_128_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+                return EncryptionAlgorithm.AES_128_CCM;
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+                return EncryptionAlgorithm.AES_128_CCM_8;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+                return EncryptionAlgorithm.AES_128_GCM;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+                return EncryptionAlgorithm.AES_256_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+                return EncryptionAlgorithm.AES_256_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+                return EncryptionAlgorithm.AES_256_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+                return EncryptionAlgorithm.AES_256_CCM;
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+                return EncryptionAlgorithm.AES_256_CCM_8;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+                return EncryptionAlgorithm.AES_256_GCM;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+                return EncryptionAlgorithm.CAMELLIA_128_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+                return EncryptionAlgorithm.CAMELLIA_128_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+                return EncryptionAlgorithm.CAMELLIA_128_GCM;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+                return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+                return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+                return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+                return EncryptionAlgorithm.CAMELLIA_256_GCM;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+                return EncryptionAlgorithm.ESTREAM_SALSA20;
+
+            case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+                return EncryptionAlgorithm.RC4_128;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+                return EncryptionAlgorithm.RC4_128;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+                return EncryptionAlgorithm.SALSA20;
+
+            case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+                return EncryptionAlgorithm.SEED_CBC;
+
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public static ProtocolVersion GetMinimumVersion(int ciphersuite)
+        {
+            switch (ciphersuite)
+            {
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+                return ProtocolVersion.TLSv12;
+
+            default:
+                return ProtocolVersion.SSLv3;
+            }
+        }
+
+        public static bool IsAeadCipherSuite(int ciphersuite)
+        {
+            return CipherType.aead == GetCipherType(ciphersuite);
+        }
+
+        public static bool IsBlockCipherSuite(int ciphersuite)
+        {
+            return CipherType.block == GetCipherType(ciphersuite);
+        }
+
+        public static bool IsStreamCipherSuite(int ciphersuite)
+        {
+            return CipherType.stream == GetCipherType(ciphersuite);
+        }
+
+        public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion)
+        {
+            return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion());
+        }
+    }
 }
diff --git a/crypto/src/crypto/tls/UrlAndHash.cs b/crypto/src/crypto/tls/UrlAndHash.cs
new file mode 100644
index 000000000..9ffd2cbf8
--- /dev/null
+++ b/crypto/src/crypto/tls/UrlAndHash.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 6066 5.
+     */
+    public class UrlAndHash
+    {
+        protected readonly string mUrl;
+        protected readonly byte[] mSha1Hash;
+
+        public UrlAndHash(string url, byte[] sha1Hash)
+        {
+            if (url == null || url.Length < 1 || url.Length >= (1 << 16))
+                throw new ArgumentException("must have length from 1 to (2^16 - 1)", "url");
+            if (sha1Hash != null && sha1Hash.Length != 20)
+                throw new ArgumentException("must have length == 20, if present", "sha1Hash");
+
+            this.mUrl = url;
+            this.mSha1Hash = sha1Hash;
+        }
+
+        public virtual string Url
+        {
+            get { return mUrl; }
+        }
+
+        public virtual byte[] Sha1Hash
+        {
+            get { return mSha1Hash; }
+        }
+
+        /**
+         * Encode this {@link UrlAndHash} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            byte[] urlEncoding = Strings.ToByteArray(this.mUrl);
+            TlsUtilities.WriteOpaque16(urlEncoding, output);
+
+            if (this.mSha1Hash == null)
+            {
+                TlsUtilities.WriteUint8(0, output);
+            }
+            else
+            {
+                TlsUtilities.WriteUint8(1, output);
+                output.Write(this.mSha1Hash, 0, this.mSha1Hash.Length);
+            }
+        }
+
+        /**
+         * Parse a {@link UrlAndHash} from a {@link Stream}.
+         * 
+         * @param context
+         *            the {@link TlsContext} of the current connection.
+         * @param input
+         *            the {@link Stream} to parse from.
+         * @return a {@link UrlAndHash} object.
+         * @throws IOException
+         */
+        public static UrlAndHash Parse(TlsContext context, Stream input)
+        {
+            byte[] urlEncoding = TlsUtilities.ReadOpaque16(input);
+            if (urlEncoding.Length < 1)
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            string url = Strings.FromByteArray(urlEncoding);
+
+            byte[] sha1Hash = null;
+            byte padding = TlsUtilities.ReadUint8(input);
+            switch (padding)
+            {
+            case 0:
+                if (TlsUtilities.IsTlsV12(context))
+                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+                break;
+            case 1:
+                sha1Hash = TlsUtilities.ReadFully(20, input);
+                break;
+            default:
+                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+            }
+
+            return new UrlAndHash(url, sha1Hash);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/UseSrtpData.cs b/crypto/src/crypto/tls/UseSrtpData.cs
new file mode 100644
index 000000000..fe8f8accb
--- /dev/null
+++ b/crypto/src/crypto/tls/UseSrtpData.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+     * RFC 5764 4.1.1
+     */
+    public class UseSrtpData
+    {
+        protected readonly int[] mProtectionProfiles;
+        protected readonly byte[] mMki;
+
+        /**
+         * @param protectionProfiles see {@link SrtpProtectionProfile} for valid constants.
+         * @param mki                valid lengths from 0 to 255.
+         */
+        public UseSrtpData(int[] protectionProfiles, byte[] mki)
+        {
+            if (protectionProfiles == null || protectionProfiles.Length < 1
+                || protectionProfiles.Length >= (1 << 15))
+            {
+                throw new ArgumentException("must have length from 1 to (2^15 - 1)", "protectionProfiles");
+            }
+
+            if (mki == null)
+            {
+                mki = TlsUtilities.EmptyBytes;
+            }
+            else if (mki.Length > 255)
+            {
+                throw new ArgumentException("cannot be longer than 255 bytes", "mki");
+            }
+
+            this.mProtectionProfiles = protectionProfiles;
+            this.mMki = mki;
+        }
+
+        /**
+         * @return see {@link SrtpProtectionProfile} for valid constants.
+         */
+        public virtual int[] ProtectionProfiles
+        {
+            get { return mProtectionProfiles; }
+        }
+
+        /**
+         * @return valid lengths from 0 to 255.
+         */
+        public virtual byte[] Mki
+        {
+            get { return mMki; }
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/UserMappingType.cs b/crypto/src/crypto/tls/UserMappingType.cs
new file mode 100644
index 000000000..6cff51736
--- /dev/null
+++ b/crypto/src/crypto/tls/UserMappingType.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /// <remarks>RFC 4681</remarks>
+    public abstract class UserMappingType
+    {
+        /*
+         * RFC 4681
+         */
+        public const byte upn_domain_hint = 64;
+    }
+}
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 67c939ad5..087cb7cea 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -2,218 +2,265 @@ using System;
 
 namespace Org.BouncyCastle.Crypto.Utilities
 {
-	internal sealed class Pack
-	{
-		private Pack()
-		{
-		}
-		
-		internal static void UInt16_To_BE(ushort n, byte[] bs)
-		{
-			bs[0] = (byte)(n >>  8);
-			bs[1] = (byte)(n      );
-		}
-
-		internal static void UInt16_To_BE(ushort n, byte[] bs, int off)
-		{
-			bs[  off] = (byte)(n >>  8);
-			bs[++off] = (byte)(n      );
-		}
-
-		internal static ushort BE_To_UInt16(byte[] bs)
-		{
-			uint n = (uint)bs[0] << 8;
-			n |= (uint)bs[1];
-			return (ushort)n;
-		}
-
-		internal static ushort BE_To_UInt16(byte[] bs, int off)
-		{
-			uint n = (uint)bs[off] << 8;
-			n |= (uint)bs[++off];
-			return (ushort)n;
-		}
-
-		internal static void UInt32_To_BE(uint n, byte[] bs)
-		{
-			bs[0] = (byte)(n >> 24);
-			bs[1] = (byte)(n >> 16);
-			bs[2] = (byte)(n >>  8);
-			bs[3] = (byte)(n      );
-		}
-
-		internal static void UInt32_To_BE(uint n, byte[] bs, int off)
-		{
-			bs[  off] = (byte)(n >> 24);
-			bs[++off] = (byte)(n >> 16);
-			bs[++off] = (byte)(n >>  8);
-			bs[++off] = (byte)(n      );
-		}
-
-		internal static void UInt32_To_BE(uint[] ns, byte[] bs, int off)
-		{
-			for (int i = 0; i < ns.Length; ++i)
-			{
-				UInt32_To_BE(ns[i], bs, off);
-				off += 4;
-			}
-		}
-
-		internal static uint BE_To_UInt32(byte[] bs)
-		{
-			uint n = (uint)bs[0] << 24;
-			n |= (uint)bs[1] << 16;
-			n |= (uint)bs[2] << 8;
-			n |= (uint)bs[3];
-			return n;
-		}
-
-		internal static uint BE_To_UInt32(byte[] bs, int off)
-		{
-			uint n = (uint)bs[off] << 24;
-			n |= (uint)bs[++off] << 16;
-			n |= (uint)bs[++off] << 8;
-			n |= (uint)bs[++off];
-			return n;
-		}
-
-		internal static void BE_To_UInt32(byte[] bs, int off, uint[] ns)
-		{
-			for (int i = 0; i < ns.Length; ++i)
-			{
-				ns[i] = BE_To_UInt32(bs, off);
-				off += 4;
-			}
-		}
-
-		internal static ulong BE_To_UInt64(byte[] bs)
-	    {
-	        uint hi = BE_To_UInt32(bs);
-	        uint lo = BE_To_UInt32(bs, 4);
-	        return ((ulong)hi << 32) | (ulong)lo;
-	    }
-
-		internal static ulong BE_To_UInt64(byte[] bs, int off)
-	    {
-	        uint hi = BE_To_UInt32(bs, off);
-	        uint lo = BE_To_UInt32(bs, off + 4);
-	        return ((ulong)hi << 32) | (ulong)lo;
-	    }
-
-	    internal static void UInt64_To_BE(ulong n, byte[] bs)
-	    {
-	        UInt32_To_BE((uint)(n >> 32), bs);
-	        UInt32_To_BE((uint)(n      ), bs, 4);
-	    }
-
-	    internal static void UInt64_To_BE(ulong n, byte[] bs, int off)
-	    {
-	        UInt32_To_BE((uint)(n >> 32), bs, off);
-	        UInt32_To_BE((uint)(n      ), bs, off + 4);
-	    }
-
-		internal static void UInt16_To_LE(ushort n, byte[] bs)
-		{
-			bs[0] = (byte)(n      );
-			bs[1] = (byte)(n >>  8);
-		}
-
-		internal static void UInt16_To_LE(ushort n, byte[] bs, int off)
-		{
-			bs[  off] = (byte)(n      );
-			bs[++off] = (byte)(n >>  8);
-		}
-
-		internal static ushort LE_To_UInt16(byte[] bs)
-		{
-			uint n = (uint)bs[0];
-			n |= (uint)bs[1] << 8;
-			return (ushort)n;
-		}
-
-		internal static ushort LE_To_UInt16(byte[] bs, int off)
-		{
-			uint n = (uint)bs[off];
-			n |= (uint)bs[++off] << 8;
-			return (ushort)n;
-		}
-
-		internal static void UInt32_To_LE(uint n, byte[] bs)
-		{
-			bs[0] = (byte)(n      );
-			bs[1] = (byte)(n >>  8);
-			bs[2] = (byte)(n >> 16);
-			bs[3] = (byte)(n >> 24);
-		}
-
-		internal static void UInt32_To_LE(uint n, byte[] bs, int off)
-		{
-			bs[  off] = (byte)(n      );
-			bs[++off] = (byte)(n >>  8);
-			bs[++off] = (byte)(n >> 16);
-			bs[++off] = (byte)(n >> 24);
-		}
-
-		internal static void UInt32_To_LE(uint[] ns, byte[] bs, int off)
-		{
-			for (int i = 0; i < ns.Length; ++i)
-			{
-				UInt32_To_LE(ns[i], bs, off);
-				off += 4;
-			}
-		}
-
-		internal static uint LE_To_UInt32(byte[] bs)
-		{
-			uint n = (uint)bs[0];
-			n |= (uint)bs[1] << 8;
-			n |= (uint)bs[2] << 16;
-			n |= (uint)bs[3] << 24;
-			return n;
-		}
-
-		internal static uint LE_To_UInt32(byte[] bs, int off)
-		{
-			uint n = (uint)bs[off];
-			n |= (uint)bs[++off] << 8;
-			n |= (uint)bs[++off] << 16;
-			n |= (uint)bs[++off] << 24;
-			return n;
-		}
-
-		internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns)
-		{
-			for (int i = 0; i < ns.Length; ++i)
-			{
-				ns[i] = LE_To_UInt32(bs, off);
-				off += 4;
-			}
-		}
-
-		internal static ulong LE_To_UInt64(byte[] bs)
-	    {
-	        uint lo = LE_To_UInt32(bs);
-	        uint hi = LE_To_UInt32(bs, 4);
-	        return ((ulong)hi << 32) | (ulong)lo;
-	    }
-
-		internal static ulong LE_To_UInt64(byte[] bs, int off)
-	    {
-	        uint lo = LE_To_UInt32(bs, off);
-	        uint hi = LE_To_UInt32(bs, off + 4);
-	        return ((ulong)hi << 32) | (ulong)lo;
-	    }
-
-	    internal static void UInt64_To_LE(ulong n, byte[] bs)
-	    {
-	        UInt32_To_LE((uint)(n      ), bs);
-	        UInt32_To_LE((uint)(n >> 32), bs, 4);
-	    }
-
-	    internal static void UInt64_To_LE(ulong n, byte[] bs, int off)
-	    {
-	        UInt32_To_LE((uint)(n      ), bs, off);
-	        UInt32_To_LE((uint)(n >> 32), bs, off + 4);
-	    }
-	}
+    internal sealed class Pack
+    {
+        private Pack()
+        {
+        }
+
+        internal static void UInt16_To_BE(ushort n, byte[] bs)
+        {
+            bs[0] = (byte)(n >> 8);
+            bs[1] = (byte)(n);
+        }
+
+        internal static void UInt16_To_BE(ushort n, byte[] bs, int off)
+        {
+            bs[off] = (byte)(n >> 8);
+            bs[off + 1] = (byte)(n);
+        }
+
+        internal static ushort BE_To_UInt16(byte[] bs)
+        {
+            uint n = (uint)bs[0] << 8
+                | (uint)bs[1];
+            return (ushort)n;
+        }
+
+        internal static ushort BE_To_UInt16(byte[] bs, int off)
+        {
+            uint n = (uint)bs[off] << 8
+                | (uint)bs[off + 1];
+            return (ushort)n;
+        }
+
+        internal static byte[] UInt32_To_BE(uint n)
+        {
+            byte[] bs = new byte[4];
+            UInt32_To_BE(n, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt32_To_BE(uint n, byte[] bs)
+        {
+            bs[0] = (byte)(n >> 24);
+            bs[1] = (byte)(n >> 16);
+            bs[2] = (byte)(n >> 8);
+            bs[3] = (byte)(n);
+        }
+
+        internal static void UInt32_To_BE(uint n, byte[] bs, int off)
+        {
+            bs[off] = (byte)(n >> 24);
+            bs[off + 1] = (byte)(n >> 16);
+            bs[off + 2] = (byte)(n >> 8);
+            bs[off + 3] = (byte)(n);
+        }
+
+        internal static byte[] UInt32_To_BE(uint[] ns)
+        {
+            byte[] bs = new byte[4 * ns.Length];
+            UInt32_To_BE(ns, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt32_To_BE(uint[] ns, byte[] bs, int off)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                UInt32_To_BE(ns[i], bs, off);
+                off += 4;
+            }
+        }
+
+        internal static uint BE_To_UInt32(byte[] bs)
+        {
+            return (uint)bs[0] << 24
+                | (uint)bs[1] << 16
+                | (uint)bs[2] << 8
+                | (uint)bs[3];
+        }
+
+        internal static uint BE_To_UInt32(byte[] bs, int off)
+        {
+            return (uint)bs[off] << 24
+                | (uint)bs[off + 1] << 16
+                | (uint)bs[off + 2] << 8
+                | (uint)bs[off + 3];
+        }
+
+        internal static void BE_To_UInt32(byte[] bs, int off, uint[] ns)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                ns[i] = BE_To_UInt32(bs, off);
+                off += 4;
+            }
+        }
+
+        internal static byte[] UInt64_To_BE(ulong n)
+        {
+            byte[] bs = new byte[8];
+            UInt64_To_BE(n, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt64_To_BE(ulong n, byte[] bs)
+        {
+            UInt32_To_BE((uint)(n >> 32), bs);
+            UInt32_To_BE((uint)(n), bs, 4);
+        }
+
+        internal static void UInt64_To_BE(ulong n, byte[] bs, int off)
+        {
+            UInt32_To_BE((uint)(n >> 32), bs, off);
+            UInt32_To_BE((uint)(n), bs, off + 4);
+        }
+
+        internal static ulong BE_To_UInt64(byte[] bs)
+        {
+            uint hi = BE_To_UInt32(bs);
+            uint lo = BE_To_UInt32(bs, 4);
+            return ((ulong)hi << 32) | (ulong)lo;
+        }
+
+        internal static ulong BE_To_UInt64(byte[] bs, int off)
+        {
+            uint hi = BE_To_UInt32(bs, off);
+            uint lo = BE_To_UInt32(bs, off + 4);
+            return ((ulong)hi << 32) | (ulong)lo;
+        }
+
+        internal static void UInt16_To_LE(ushort n, byte[] bs)
+        {
+            bs[0] = (byte)(n);
+            bs[1] = (byte)(n >> 8);
+        }
+
+        internal static void UInt16_To_LE(ushort n, byte[] bs, int off)
+        {
+            bs[off] = (byte)(n);
+            bs[off + 1] = (byte)(n >> 8);
+        }
+
+        internal static ushort LE_To_UInt16(byte[] bs)
+        {
+            uint n = (uint)bs[0]
+                | (uint)bs[1] << 8;
+            return (ushort)n;
+        }
+
+        internal static ushort LE_To_UInt16(byte[] bs, int off)
+        {
+            uint n = (uint)bs[off]
+                | (uint)bs[off + 1] << 8;
+            return (ushort)n;
+        }
+
+        internal static byte[] UInt32_To_LE(uint n)
+        {
+            byte[] bs = new byte[4];
+            UInt32_To_LE(n, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt32_To_LE(uint n, byte[] bs)
+        {
+            bs[0] = (byte)(n);
+            bs[1] = (byte)(n >> 8);
+            bs[2] = (byte)(n >> 16);
+            bs[3] = (byte)(n >> 24);
+        }
+
+        internal static void UInt32_To_LE(uint n, byte[] bs, int off)
+        {
+            bs[off] = (byte)(n);
+            bs[off + 1] = (byte)(n >> 8);
+            bs[off + 2] = (byte)(n >> 16);
+            bs[off + 3] = (byte)(n >> 24);
+        }
+
+        internal static byte[] UInt32_To_LE(uint[] ns)
+        {
+            byte[] bs = new byte[4 * ns.Length];
+            UInt32_To_LE(ns, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt32_To_LE(uint[] ns, byte[] bs, int off)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                UInt32_To_LE(ns[i], bs, off);
+                off += 4;
+            }
+        }
+
+        internal static uint LE_To_UInt32(byte[] bs)
+        {
+            return (uint)bs[0]
+                | (uint)bs[1] << 8
+                | (uint)bs[2] << 16
+                | (uint)bs[3] << 24;
+        }
+
+        internal static uint LE_To_UInt32(byte[] bs, int off)
+        {
+            return (uint)bs[off]
+                | (uint)bs[off + 1] << 8
+                | (uint)bs[off + 2] << 16
+                | (uint)bs[off + 3] << 24;
+        }
+
+        internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                ns[i] = LE_To_UInt32(bs, off);
+                off += 4;
+            }
+        }
+
+        internal static void LE_To_UInt32(byte[] bs, int bOff, uint[] ns, int nOff, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                ns[nOff + i] = LE_To_UInt32(bs, bOff);
+                bOff += 4;
+            }
+        }
+
+        internal static byte[] UInt64_To_LE(ulong n)
+        {
+            byte[] bs = new byte[8];
+            UInt64_To_LE(n, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt64_To_LE(ulong n, byte[] bs)
+        {
+            UInt32_To_LE((uint)(n), bs);
+            UInt32_To_LE((uint)(n >> 32), bs, 4);
+        }
+
+        internal static void UInt64_To_LE(ulong n, byte[] bs, int off)
+        {
+            UInt32_To_LE((uint)(n), bs, off);
+            UInt32_To_LE((uint)(n >> 32), bs, off + 4);
+        }
+
+        internal static ulong LE_To_UInt64(byte[] bs)
+        {
+            uint lo = LE_To_UInt32(bs);
+            uint hi = LE_To_UInt32(bs, 4);
+            return ((ulong)hi << 32) | (ulong)lo;
+        }
+
+        internal static ulong LE_To_UInt64(byte[] bs, int off)
+        {
+            uint lo = LE_To_UInt32(bs, off);
+            uint hi = LE_To_UInt32(bs, off + 4);
+            return ((ulong)hi << 32) | (ulong)lo;
+        }
+    }
 }
diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs
index d52c0f83c..f302f077e 100644
--- a/crypto/src/math/BigInteger.cs
+++ b/crypto/src/math/BigInteger.cs
@@ -8,1300 +8,1388 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math
 {
-#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
-	[Serializable]
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
 #endif
     public class BigInteger
-	{
-		// The primes b/w 2 and ~2^10
-		/*
-				3   5   7   11  13  17  19  23  29
-			31  37  41  43  47  53  59  61  67  71
-			73  79  83  89  97  101 103 107 109 113
-			127 131 137 139 149 151 157 163 167 173
-			179 181 191 193 197 199 211 223 227 229
-			233 239 241 251 257 263 269 271 277 281
-			283 293 307 311 313 317 331 337 347 349
-			353 359 367 373 379 383 389 397 401 409
-			419 421 431 433 439 443 449 457 461 463
-			467 479 487 491 499 503 509 521 523 541
-			547 557 563 569 571 577 587 593 599 601
-			607 613 617 619 631 641 643 647 653 659
-			661 673 677 683 691 701 709 719 727 733
-			739 743 751 757 761 769 773 787 797 809
-			811 821 823 827 829 839 853 857 859 863
-			877 881 883 887 907 911 919 929 937 941
-			947 953 967 971 977 983 991 997
-			1009 1013 1019 1021 1031
-		*/
-
-		// Each list has a product < 2^31
-		private static readonly int[][] primeLists = new int[][]
-		{
-			new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
-			new int[]{ 29, 31, 37, 41, 43 },
-			new int[]{ 47, 53, 59, 61, 67 },
-			new int[]{ 71, 73, 79, 83 },
-			new int[]{ 89, 97, 101, 103 },
-
-			new int[]{ 107, 109, 113, 127 },
-			new int[]{ 131, 137, 139, 149 },
-			new int[]{ 151, 157, 163, 167 },
-			new int[]{ 173, 179, 181, 191 },
-			new int[]{ 193, 197, 199, 211 },
-
-			new int[]{ 223, 227, 229 },
-			new int[]{ 233, 239, 241 },
-			new int[]{ 251, 257, 263 },
-			new int[]{ 269, 271, 277 },
-			new int[]{ 281, 283, 293 },
-
-			new int[]{ 307, 311, 313 },
-			new int[]{ 317, 331, 337 },
-			new int[]{ 347, 349, 353 },
-			new int[]{ 359, 367, 373 },
-			new int[]{ 379, 383, 389 },
-
-			new int[]{ 397, 401, 409 },
-			new int[]{ 419, 421, 431 },
-			new int[]{ 433, 439, 443 },
-			new int[]{ 449, 457, 461 },
-			new int[]{ 463, 467, 479 },
-
-			new int[]{ 487, 491, 499 },
-			new int[]{ 503, 509, 521 },
-			new int[]{ 523, 541, 547 },
-			new int[]{ 557, 563, 569 },
-			new int[]{ 571, 577, 587 },
-
-			new int[]{ 593, 599, 601 },
-			new int[]{ 607, 613, 617 },
-			new int[]{ 619, 631, 641 },
-			new int[]{ 643, 647, 653 },
-			new int[]{ 659, 661, 673 },
-
-			new int[]{ 677, 683, 691 },
-			new int[]{ 701, 709, 719 },
-			new int[]{ 727, 733, 739 },
-			new int[]{ 743, 751, 757 },
-			new int[]{ 761, 769, 773 },
-
-			new int[]{ 787, 797, 809 },
-			new int[]{ 811, 821, 823 },
-			new int[]{ 827, 829, 839 },
-			new int[]{ 853, 857, 859 },
-			new int[]{ 863, 877, 881 },
-
-			new int[]{ 883, 887, 907 },
-			new int[]{ 911, 919, 929 },
-			new int[]{ 937, 941, 947 },
-			new int[]{ 953, 967, 971 },
-			new int[]{ 977, 983, 991 },
-
-			new int[]{ 997, 1009, 1013 },
-			new int[]{ 1019, 1021, 1031 },
-		};
-
-		private static readonly int[] primeProducts;
-
-		private const long IMASK = 0xffffffffL;
-		private static readonly ulong UIMASK = (ulong)IMASK;
-
-		private static readonly int[] ZeroMagnitude = new int[0];
-		private static readonly byte[] ZeroEncoding = new byte[0];
-
-		public static readonly BigInteger Zero = new BigInteger(0, ZeroMagnitude, false);
-		public static readonly BigInteger One = createUValueOf(1);
-		public static readonly BigInteger Two = createUValueOf(2);
-		public static readonly BigInteger Three = createUValueOf(3);
-		public static readonly BigInteger Ten = createUValueOf(10);
-
-		private static readonly int chunk2 = 1; // TODO Parse 64 bits at a time
-		private static readonly BigInteger radix2 = ValueOf(2);
-		private static readonly BigInteger radix2E = radix2.Pow(chunk2);
-
-		private static readonly int chunk10 = 19;
-		private static readonly BigInteger radix10 = ValueOf(10);
-		private static readonly BigInteger radix10E = radix10.Pow(chunk10);
-
-		private static readonly int chunk16 = 16;
-		private static readonly BigInteger radix16 = ValueOf(16);
-		private static readonly BigInteger radix16E = radix16.Pow(chunk16);
-
-		private static readonly Random RandomSource = new Random();
-
-		private const int BitsPerByte = 8;
-		private const int BitsPerInt = 32;
-		private const int BytesPerInt = 4;
-
-		static BigInteger()
-		{
-			primeProducts = new int[primeLists.Length];
-
-			for (int i = 0; i < primeLists.Length; ++i)
-			{
-				int[] primeList = primeLists[i];
-				int product = primeList[0];
-				for (int j = 1; j < primeList.Length; ++j)
-				{
-					product *= primeList[j];
-				}
-				primeProducts[i] = product;
-			}
-		}
-
-		private int sign; // -1 means -ve; +1 means +ve; 0 means 0;
-		private int[] magnitude; // array of ints with [0] being the most significant
-		private int nBits = -1; // cache BitCount() value
-		private int nBitLength = -1; // cache calcBitLength() value
-		private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.)
-
-		private static int GetByteLength(
-			int nBits)
-		{
-			return (nBits + BitsPerByte - 1) / BitsPerByte;
-		}
-
-		private BigInteger(
-			int		signum,
-			int[]	mag,
-			bool	checkMag)
-		{
-			if (checkMag)
-			{
-				int i = 0;
-				while (i < mag.Length && mag[i] == 0)
-				{
-					++i;
-				}
-
-				if (i == mag.Length)
-				{
-					this.sign = 0;
-					this.magnitude = ZeroMagnitude;
-				}
-				else
-				{
-					this.sign = signum;
-
-					if (i == 0)
-					{
-						this.magnitude = mag;
-					}
-					else
-					{
-						// strip leading 0 words
-						this.magnitude = new int[mag.Length - i];
-						Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length);
-					}
-				}
-			}
-			else
-			{
-				this.sign = signum;
-				this.magnitude = mag;
-			}
-		}
-
-		public BigInteger(
-			string value)
-			: this(value, 10)
-		{
-		}
-
-		public BigInteger(
-			string	str,
-			int		radix)
-		{
-			if (str.Length == 0)
-				throw new FormatException("Zero length BigInteger");
-
-			NumberStyles style;
-			int chunk;
-			BigInteger r;
-			BigInteger rE;
-
-			switch (radix)
-			{
-				case 2:
-					// Is there anyway to restrict to binary digits?
-					style = NumberStyles.Integer;
-					chunk = chunk2;
-					r = radix2;
-					rE = radix2E;
-					break;
-				case 10:
-					// This style seems to handle spaces and minus sign already (our processing redundant?)
-					style = NumberStyles.Integer;
-					chunk = chunk10;
-					r = radix10;
-					rE = radix10E;
-					break;
-				case 16:
-					// TODO Should this be HexNumber?
-					style = NumberStyles.AllowHexSpecifier;
-					chunk = chunk16;
-					r = radix16;
-					rE = radix16E;
-					break;
-				default:
-					throw new FormatException("Only bases 2, 10, or 16 allowed");
-			}
-
-
-			int index = 0;
-			sign = 1;
-
-			if (str[0] == '-')
-			{
-				if (str.Length == 1)
-					throw new FormatException("Zero length BigInteger");
-
-				sign = -1;
-				index = 1;
-			}
-
-			// strip leading zeros from the string str
-			while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0)
-			{
-				index++;
-			}
-
-			if (index >= str.Length)
-			{
-				// zero value - we're done
-				sign = 0;
-				magnitude = ZeroMagnitude;
-				return;
-			}
-
-			//////
-			// could we work out the max number of ints required to store
-			// str.Length digits in the given base, then allocate that
-			// storage in one hit?, then Generate the magnitude in one hit too?
-			//////
-
-			BigInteger b = Zero;
-
-
-			int next = index + chunk;
-
-			if (next <= str.Length)
-			{
-				do
-				{
-					string s = str.Substring(index, chunk);
-					ulong i = ulong.Parse(s, style);
-					BigInteger bi = createUValueOf(i);
-
-					switch (radix)
-					{
-						case 2:
-							// TODO Need this because we are parsing in radix 10 above
-							if (i > 1)
-								throw new FormatException("Bad character in radix 2 string: " + s);
-
-							// TODO Parse 64 bits at a time
-							b = b.ShiftLeft(1);
-							break;
-						case 16:
-							b = b.ShiftLeft(64);
-							break;
-						default:
-							b = b.Multiply(rE);
-							break;
-					}
-
-					b = b.Add(bi);
-
-					index = next;
-					next += chunk;
-				}
-				while (next <= str.Length);
-			}
-
-			if (index < str.Length)
-			{
-				string s = str.Substring(index);
-				ulong i = ulong.Parse(s, style);
-				BigInteger bi = createUValueOf(i);
-
-				if (b.sign > 0)
-				{
-					if (radix == 2)
-					{
-						// NB: Can't reach here since we are parsing one char at a time
-						Debug.Assert(false);
-
-						// TODO Parse all bits at once
+    {
+        // The first few odd primes
+        /*
+                3   5   7   11  13  17  19  23  29
+            31  37  41  43  47  53  59  61  67  71
+            73  79  83  89  97  101 103 107 109 113
+            127 131 137 139 149 151 157 163 167 173
+            179 181 191 193 197 199 211 223 227 229
+            233 239 241 251 257 263 269 271 277 281
+            283 293 307 311 313 317 331 337 347 349
+            353 359 367 373 379 383 389 397 401 409
+            419 421 431 433 439 443 449 457 461 463
+            467 479 487 491 499 503 509 521 523 541
+            547 557 563 569 571 577 587 593 599 601
+            607 613 617 619 631 641 643 647 653 659
+            661 673 677 683 691 701 709 719 727 733
+            739 743 751 757 761 769 773 787 797 809
+            811 821 823 827 829 839 853 857 859 863
+            877 881 883 887 907 911 919 929 937 941
+            947 953 967 971 977 983 991 997 1009
+            1013 1019 1021 1031 1033 1039 1049 1051
+            1061 1063 1069 1087 1091 1093 1097 1103
+            1109 1117 1123 1129 1151 1153 1163 1171
+            1181 1187 1193 1201 1213 1217 1223 1229
+            1231 1237 1249 1259 1277 1279 1283 1289
+        */
+
+        // Each list has a product < 2^31
+        internal static readonly int[][] primeLists = new int[][]
+        {
+            new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 },
+            new int[]{ 29, 31, 37, 41, 43 },
+            new int[]{ 47, 53, 59, 61, 67 },
+            new int[]{ 71, 73, 79, 83 },
+            new int[]{ 89, 97, 101, 103 },
+
+            new int[]{ 107, 109, 113, 127 },
+            new int[]{ 131, 137, 139, 149 },
+            new int[]{ 151, 157, 163, 167 },
+            new int[]{ 173, 179, 181, 191 },
+            new int[]{ 193, 197, 199, 211 },
+
+            new int[]{ 223, 227, 229 },
+            new int[]{ 233, 239, 241 },
+            new int[]{ 251, 257, 263 },
+            new int[]{ 269, 271, 277 },
+            new int[]{ 281, 283, 293 },
+
+            new int[]{ 307, 311, 313 },
+            new int[]{ 317, 331, 337 },
+            new int[]{ 347, 349, 353 },
+            new int[]{ 359, 367, 373 },
+            new int[]{ 379, 383, 389 },
+
+            new int[]{ 397, 401, 409 },
+            new int[]{ 419, 421, 431 },
+            new int[]{ 433, 439, 443 },
+            new int[]{ 449, 457, 461 },
+            new int[]{ 463, 467, 479 },
+
+            new int[]{ 487, 491, 499 },
+            new int[]{ 503, 509, 521 },
+            new int[]{ 523, 541, 547 },
+            new int[]{ 557, 563, 569 },
+            new int[]{ 571, 577, 587 },
+
+            new int[]{ 593, 599, 601 },
+            new int[]{ 607, 613, 617 },
+            new int[]{ 619, 631, 641 },
+            new int[]{ 643, 647, 653 },
+            new int[]{ 659, 661, 673 },
+
+            new int[]{ 677, 683, 691 },
+            new int[]{ 701, 709, 719 },
+            new int[]{ 727, 733, 739 },
+            new int[]{ 743, 751, 757 },
+            new int[]{ 761, 769, 773 },
+
+            new int[]{ 787, 797, 809 },
+            new int[]{ 811, 821, 823 },
+            new int[]{ 827, 829, 839 },
+            new int[]{ 853, 857, 859 },
+            new int[]{ 863, 877, 881 },
+
+            new int[]{ 883, 887, 907 },
+            new int[]{ 911, 919, 929 },
+            new int[]{ 937, 941, 947 },
+            new int[]{ 953, 967, 971 },
+            new int[]{ 977, 983, 991 },
+
+            new int[]{ 997, 1009, 1013 },
+            new int[]{ 1019, 1021, 1031 },
+            new int[]{ 1033, 1039, 1049 },
+            new int[]{ 1051, 1061, 1063 },
+            new int[]{ 1069, 1087, 1091 },
+
+            new int[]{ 1093, 1097, 1103 },
+            new int[]{ 1109, 1117, 1123 },
+            new int[]{ 1129, 1151, 1153 },
+            new int[]{ 1163, 1171, 1181 },
+            new int[]{ 1187, 1193, 1201 },
+
+            new int[]{ 1213, 1217, 1223 },
+            new int[]{ 1229, 1231, 1237 },
+            new int[]{ 1249, 1259, 1277 },
+            new int[]{ 1279, 1283, 1289 },
+        };
+
+        internal static readonly int[] primeProducts;
+
+        private const long IMASK = 0xFFFFFFFFL;
+        private const ulong UIMASK = 0xFFFFFFFFUL;
+
+        private static readonly int[] ZeroMagnitude = new int[0];
+        private static readonly byte[] ZeroEncoding = new byte[0];
+
+        private static readonly BigInteger[] SMALL_CONSTANTS = new BigInteger[17];
+        public static readonly BigInteger Zero;
+        public static readonly BigInteger One;
+        public static readonly BigInteger Two;
+        public static readonly BigInteger Three;
+        public static readonly BigInteger Ten;
+
+        //private readonly static byte[] BitCountTable =
+        //{
+        //    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+        //    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        //    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        //    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        //    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        //    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        //    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        //    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        //    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+        //    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        //    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        //    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        //    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+        //    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        //    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+        //    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+        //};
+
+        private readonly static byte[] BitLengthTable =
+        {
+            0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+            6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+            6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+        };
+
+        // TODO Parse radix-2 64 bits at a time and radix-8 63 bits at a time
+        private const int chunk2 = 1, chunk8 = 1, chunk10 = 19, chunk16 = 16;
+        private static readonly BigInteger radix2, radix2E, radix8, radix8E, radix10, radix10E, radix16, radix16E;
+
+        private static readonly Random RandomSource = new Random();
+
+        /*
+         * These are the threshold bit-lengths (of an exponent) where we increase the window size.
+         * They are calculated according to the expected savings in multiplications.
+         * Some squares will also be saved on average, but we offset these against the extra storage costs.
+         */
+        private static readonly int[] ExpWindowThresholds = { 7, 25, 81, 241, 673, 1793, 4609, Int32.MaxValue };
+
+        private const int BitsPerByte = 8;
+        private const int BitsPerInt = 32;
+        private const int BytesPerInt = 4;
+
+        static BigInteger()
+        {
+            Zero = new BigInteger(0, ZeroMagnitude, false);
+            Zero.nBits = 0; Zero.nBitLength = 0;
+
+            SMALL_CONSTANTS[0] = Zero;
+            for (uint i = 1; i < SMALL_CONSTANTS.Length; ++i)
+            {
+                SMALL_CONSTANTS[i] = CreateUValueOf(i);
+            }
+
+            One = SMALL_CONSTANTS[1];
+            Two = SMALL_CONSTANTS[2];
+            Three = SMALL_CONSTANTS[3];
+            Ten = SMALL_CONSTANTS[10];
+
+            radix2 = ValueOf(2);
+            radix2E = radix2.Pow(chunk2);
+
+            radix8 = ValueOf(8);
+            radix8E = radix8.Pow(chunk8);
+
+            radix10 = ValueOf(10);
+            radix10E = radix10.Pow(chunk10);
+
+            radix16 = ValueOf(16);
+            radix16E = radix16.Pow(chunk16);
+
+            primeProducts = new int[primeLists.Length];
+
+            for (int i = 0; i < primeLists.Length; ++i)
+            {
+                int[] primeList = primeLists[i];
+                int product = primeList[0];
+                for (int j = 1; j < primeList.Length; ++j)
+                {
+                    product *= primeList[j];
+                }
+                primeProducts[i] = product;
+            }
+        }
+
+        private int[] magnitude; // array of ints with [0] being the most significant
+        private int sign; // -1 means -ve; +1 means +ve; 0 means 0;
+        private int nBits = -1; // cache BitCount() value
+        private int nBitLength = -1; // cache BitLength() value
+        private int mQuote = 0; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.), 0 when uninitialised
+
+        private static int GetByteLength(
+            int nBits)
+        {
+            return (nBits + BitsPerByte - 1) / BitsPerByte;
+        }
+
+        private BigInteger(
+            int		signum,
+            int[]	mag,
+            bool	checkMag)
+        {
+            if (checkMag)
+            {
+                int i = 0;
+                while (i < mag.Length && mag[i] == 0)
+                {
+                    ++i;
+                }
+
+                if (i == mag.Length)
+                {
+                    this.sign = 0;
+                    this.magnitude = ZeroMagnitude;
+                }
+                else
+                {
+                    this.sign = signum;
+
+                    if (i == 0)
+                    {
+                        this.magnitude = mag;
+                    }
+                    else
+                    {
+                        // strip leading 0 words
+                        this.magnitude = new int[mag.Length - i];
+                        Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length);
+                    }
+                }
+            }
+            else
+            {
+                this.sign = signum;
+                this.magnitude = mag;
+            }
+        }
+
+        public BigInteger(
+            string value)
+            : this(value, 10)
+        {
+        }
+
+        public BigInteger(
+            string	str,
+            int		radix)
+        {
+            if (str.Length == 0)
+                throw new FormatException("Zero length BigInteger");
+
+            NumberStyles style;
+            int chunk;
+            BigInteger r;
+            BigInteger rE;
+
+            switch (radix)
+            {
+                case 2:
+                    // Is there anyway to restrict to binary digits?
+                    style = NumberStyles.Integer;
+                    chunk = chunk2;
+                    r = radix2;
+                    rE = radix2E;
+                    break;
+                case 8:
+                    // Is there anyway to restrict to octal digits?
+                    style = NumberStyles.Integer;
+                    chunk = chunk8;
+                    r = radix8;
+                    rE = radix8E;
+                    break;
+                case 10:
+                    // This style seems to handle spaces and minus sign already (our processing redundant?)
+                    style = NumberStyles.Integer;
+                    chunk = chunk10;
+                    r = radix10;
+                    rE = radix10E;
+                    break;
+                case 16:
+                    // TODO Should this be HexNumber?
+                    style = NumberStyles.AllowHexSpecifier;
+                    chunk = chunk16;
+                    r = radix16;
+                    rE = radix16E;
+                    break;
+                default:
+                    throw new FormatException("Only bases 2, 8, 10, or 16 allowed");
+            }
+
+
+            int index = 0;
+            sign = 1;
+
+            if (str[0] == '-')
+            {
+                if (str.Length == 1)
+                    throw new FormatException("Zero length BigInteger");
+
+                sign = -1;
+                index = 1;
+            }
+
+            // strip leading zeros from the string str
+            while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0)
+            {
+                index++;
+            }
+
+            if (index >= str.Length)
+            {
+                // zero value - we're done
+                sign = 0;
+                magnitude = ZeroMagnitude;
+                return;
+            }
+
+            //////
+            // could we work out the max number of ints required to store
+            // str.Length digits in the given base, then allocate that
+            // storage in one hit?, then Generate the magnitude in one hit too?
+            //////
+
+            BigInteger b = Zero;
+
+
+            int next = index + chunk;
+
+            if (next <= str.Length)
+            {
+                do
+                {
+                    string s = str.Substring(index, chunk);
+                    ulong i = ulong.Parse(s, style);
+                    BigInteger bi = CreateUValueOf(i);
+
+                    switch (radix)
+                    {
+                        case 2:
+                            // TODO Need this because we are parsing in radix 10 above
+                            if (i >= 2)
+                                throw new FormatException("Bad character in radix 2 string: " + s);
+
+                            // TODO Parse 64 bits at a time
+                            b = b.ShiftLeft(1);
+                            break;
+                        case 8:
+                            // TODO Need this because we are parsing in radix 10 above
+                            if (i >= 8)
+                                throw new FormatException("Bad character in radix 8 string: " + s);
+
+                            // TODO Parse 63 bits at a time
+                            b = b.ShiftLeft(3);
+                            break;
+                        case 16:
+                            b = b.ShiftLeft(64);
+                            break;
+                        default:
+                            b = b.Multiply(rE);
+                            break;
+                    }
+
+                    b = b.Add(bi);
+
+                    index = next;
+                    next += chunk;
+                }
+                while (next <= str.Length);
+            }
+
+            if (index < str.Length)
+            {
+                string s = str.Substring(index);
+                ulong i = ulong.Parse(s, style);
+                BigInteger bi = CreateUValueOf(i);
+
+                if (b.sign > 0)
+                {
+                    if (radix == 2)
+                    {
+                        // NB: Can't reach here since we are parsing one char at a time
+                        Debug.Assert(false);
+
+                        // TODO Parse all bits at once
 //						b = b.ShiftLeft(s.Length);
-					}
-					else if (radix == 16)
-					{
-						b = b.ShiftLeft(s.Length << 2);
-					}
-					else
-					{
-						b = b.Multiply(r.Pow(s.Length));
-					}
-
-					b = b.Add(bi);
-				}
-				else
-				{
-					b = bi;
-				}
-			}
-
-			// Note: This is the previous (slower) algorithm
-			//			while (index < value.Length)
-			//            {
-			//				char c = value[index];
-			//				string s = c.ToString();
-			//				int i = Int32.Parse(s, style);
-			//
-			//                b = b.Multiply(r).Add(ValueOf(i));
-			//                index++;
-			//            }
-
-			magnitude = b.magnitude;
-		}
-
-		public BigInteger(
-			byte[] bytes)
-			: this(bytes, 0, bytes.Length)
-		{
-		}
-
-		public BigInteger(
-			byte[]	bytes,
-			int		offset,
-			int		length)
-		{
-			if (length == 0)
-				throw new FormatException("Zero length BigInteger");
-
-			// TODO Move this processing into MakeMagnitude (provide sign argument)
-			if ((sbyte)bytes[offset] < 0)
-			{
-				this.sign = -1;
-
-				int end = offset + length;
-
-				int iBval;
-				// strip leading sign bytes
-				for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++)
-				{
-				}
-
-				if (iBval >= end)
-				{
-					this.magnitude = One.magnitude;
-				}
-				else
-				{
-					int numBytes = end - iBval;
-					byte[] inverse = new byte[numBytes];
-
-					int index = 0;
-					while (index < numBytes)
-					{
-						inverse[index++] = (byte)~bytes[iBval++];
-					}
-
-					Debug.Assert(iBval == end);
-
-					while (inverse[--index] == byte.MaxValue)
-					{
-						inverse[index] = byte.MinValue;
-					}
-
-					inverse[index]++;
-
-					this.magnitude = MakeMagnitude(inverse, 0, inverse.Length);
-				}
-			}
-			else
-			{
-				// strip leading zero bytes and return magnitude bytes
-				this.magnitude = MakeMagnitude(bytes, offset, length);
-				this.sign = this.magnitude.Length > 0 ? 1 : 0;
-			}
-		}
-
-		private static int[] MakeMagnitude(
-			byte[]	bytes,
-			int		offset,
-			int		length)
-		{
-			int end = offset + length;
-
-			// strip leading zeros
-			int firstSignificant;
-			for (firstSignificant = offset; firstSignificant < end
-				&& bytes[firstSignificant] == 0; firstSignificant++)
-			{
-			}
-
-			if (firstSignificant >= end)
-			{
-				return ZeroMagnitude;
-			}
-
-			int nInts = (end - firstSignificant + 3) / BytesPerInt;
-			int bCount = (end - firstSignificant) % BytesPerInt;
-			if (bCount == 0)
-			{
-				bCount = BytesPerInt;
-			}
-
-			if (nInts < 1)
-			{
-				return ZeroMagnitude;
-			}
-
-			int[] mag = new int[nInts];
-
-			int v = 0;
-			int magnitudeIndex = 0;
-			for (int i = firstSignificant; i < end; ++i)
-			{
-				v <<= 8;
-				v |= bytes[i] & 0xff;
-				bCount--;
-				if (bCount <= 0)
-				{
-					mag[magnitudeIndex] = v;
-					magnitudeIndex++;
-					bCount = BytesPerInt;
-					v = 0;
-				}
-			}
-
-			if (magnitudeIndex < mag.Length)
-			{
-				mag[magnitudeIndex] = v;
-			}
-
-			return mag;
-		}
-
-		public BigInteger(
-			int		sign,
-			byte[]	bytes)
-			: this(sign, bytes, 0, bytes.Length)
-		{
-		}
-
-		public BigInteger(
-			int		sign,
-			byte[]	bytes,
-			int		offset,
-			int		length)
-		{
-			if (sign < -1 || sign > 1)
-				throw new FormatException("Invalid sign value");
-
-			if (sign == 0)
-			{
-				this.sign = 0;
-				this.magnitude = ZeroMagnitude;
-			}
-			else
-			{
-				// copy bytes
-				this.magnitude = MakeMagnitude(bytes, offset, length);
-				this.sign = this.magnitude.Length < 1 ? 0 : sign;
-			}
-		}
-
-		public BigInteger(
-			int		sizeInBits,
-			Random	random)
-		{
-			if (sizeInBits < 0)
-				throw new ArgumentException("sizeInBits must be non-negative");
-
-			this.nBits = -1;
-			this.nBitLength = -1;
-
-			if (sizeInBits == 0)
-			{
-				this.sign = 0;
-				this.magnitude = ZeroMagnitude;
-				return;
-			}
-
-			int nBytes = GetByteLength(sizeInBits);
-			byte[] b = new byte[nBytes];
-			random.NextBytes(b);
-
-			// strip off any excess bits in the MSB
-			b[0] &= rndMask[BitsPerByte * nBytes - sizeInBits];
-
-			this.magnitude = MakeMagnitude(b, 0, b.Length);
-			this.sign = this.magnitude.Length < 1 ? 0 : 1;
-		}
-
-		private static readonly byte[] rndMask = { 255, 127, 63, 31, 15, 7, 3, 1 };
-
-		public BigInteger(
-			int		bitLength,
-			int		certainty,
-			Random	random)
-		{
-			if (bitLength < 2)
-				throw new ArithmeticException("bitLength < 2");
-
-			this.sign = 1;
-			this.nBitLength = bitLength;
-
-			if (bitLength == 2)
-			{
-				this.magnitude = random.Next(2) == 0
-					?	Two.magnitude
-					:	Three.magnitude;
-				return;
-			}
-
-			int nBytes = GetByteLength(bitLength);
-			byte[] b = new byte[nBytes];
-
-			int xBits = BitsPerByte * nBytes - bitLength;
-			byte mask = rndMask[xBits];
-
-			for (;;)
-			{
-				random.NextBytes(b);
-
-				// strip off any excess bits in the MSB
-				b[0] &= mask;
-
-				// ensure the leading bit is 1 (to meet the strength requirement)
-				b[0] |= (byte)(1 << (7 - xBits));
-
-				// ensure the trailing bit is 1 (i.e. must be odd)
-				b[nBytes - 1] |= 1;
-
-				this.magnitude = MakeMagnitude(b, 0, b.Length);
-				this.nBits = -1;
-				this.mQuote = -1L;
-
-				if (certainty < 1)
-					break;
-
-				if (CheckProbablePrime(certainty, random))
-					break;
-
-				if (bitLength > 32)
-				{
-					for (int rep = 0; rep < 10000; ++rep)
-					{
-						int n = 33 + random.Next(bitLength - 2);
-						this.magnitude[this.magnitude.Length - (n >> 5)] ^= (1 << (n & 31));
-						this.magnitude[this.magnitude.Length - 1] ^= ((random.Next() + 1) << 1);
-						this.mQuote = -1L;
-
-						if (CheckProbablePrime(certainty, random))
-							return;
-					}
-				}
-			}
-		}
-
-		public BigInteger Abs()
-		{
-			return sign >= 0 ? this : Negate();
-		}
-
-		/**
-		 * return a = a + b - b preserved.
-		 */
-		private static int[] AddMagnitudes(
-			int[] a,
-			int[] b)
-		{
-			int tI = a.Length - 1;
-			int vI = b.Length - 1;
-			long m = 0;
-
-			while (vI >= 0)
-			{
-				m += ((long)(uint)a[tI] + (long)(uint)b[vI--]);
-				a[tI--] = (int)m;
-				m = (long)((ulong)m >> 32);
-			}
-
-			if (m != 0)
-			{
-				while (tI >= 0 && ++a[tI--] == 0)
-				{
-				}
-			}
-
-			return a;
-		}
-
-		public BigInteger Add(
-			BigInteger value)
-		{
-			if (this.sign == 0)
-				return value;
-
-			if (this.sign != value.sign)
-			{
-				if (value.sign == 0)
-					return this;
-
-				if (value.sign < 0)
-					return Subtract(value.Negate());
-
-				return value.Subtract(Negate());
-			}
-
-			return AddToMagnitude(value.magnitude);
-		}
-
-		private BigInteger AddToMagnitude(
-			int[] magToAdd)
-		{
-			int[] big, small;
-			if (this.magnitude.Length < magToAdd.Length)
-			{
-				big = magToAdd;
-				small = this.magnitude;
-			}
-			else
-			{
-				big = this.magnitude;
-				small = magToAdd;
-			}
-
-			// Conservatively avoid over-allocation when no overflow possible
-			uint limit = uint.MaxValue;
-			if (big.Length == small.Length)
-				limit -= (uint) small[0];
-
-			bool possibleOverflow = (uint) big[0] >= limit;
-
-			int[] bigCopy;
-			if (possibleOverflow)
-			{
-				bigCopy = new int[big.Length + 1];
-				big.CopyTo(bigCopy, 1);
-			}
-			else
-			{
-				bigCopy = (int[]) big.Clone();
-			}
-
-			bigCopy = AddMagnitudes(bigCopy, small);
-
-			return new BigInteger(this.sign, bigCopy, possibleOverflow);
-		}
-
-		public BigInteger And(
-			BigInteger value)
-		{
-			if (this.sign == 0 || value.sign == 0)
-			{
-				return Zero;
-			}
-
-			int[] aMag = this.sign > 0
-				? this.magnitude
-				: Add(One).magnitude;
-
-			int[] bMag = value.sign > 0
-				? value.magnitude
-				: value.Add(One).magnitude;
-
-			bool resultNeg = sign < 0 && value.sign < 0;
-			int resultLength = System.Math.Max(aMag.Length, bMag.Length);
-			int[] resultMag = new int[resultLength];
-
-			int aStart = resultMag.Length - aMag.Length;
-			int bStart = resultMag.Length - bMag.Length;
-
-			for (int i = 0; i < resultMag.Length; ++i)
-			{
-				int aWord = i >= aStart ? aMag[i - aStart] : 0;
-				int bWord = i >= bStart ? bMag[i - bStart] : 0;
-
-				if (this.sign < 0)
-				{
-					aWord = ~aWord;
-				}
-
-				if (value.sign < 0)
-				{
-					bWord = ~bWord;
-				}
-
-				resultMag[i] = aWord & bWord;
-
-				if (resultNeg)
-				{
-					resultMag[i] = ~resultMag[i];
-				}
-			}
-
-			BigInteger result = new BigInteger(1, resultMag, true);
-
-			// TODO Optimise this case
-			if (resultNeg)
-			{
-				result = result.Not();
-			}
-
-			return result;
-		}
-
-		public BigInteger AndNot(
-			BigInteger val)
-		{
-			return And(val.Not());
-		}
-
-		public int BitCount
-		{
-			get
-			{
-				if (nBits == -1)
-				{
-					if (sign < 0)
-					{
-						// TODO Optimise this case
-						nBits = Not().BitCount;
-					}
-					else
-					{
-						int sum = 0;
-						for (int i = 0; i < magnitude.Length; i++)
-						{
-							sum += bitCounts[(byte) magnitude[i]];
-							sum += bitCounts[(byte)(magnitude[i] >> 8)];
-							sum += bitCounts[(byte)(magnitude[i] >> 16)];
-							sum += bitCounts[(byte)(magnitude[i] >> 24)];
-						}
-						nBits = sum;
-					}
-				}
-
-				return nBits;
-			}
-		}
-
-		private readonly static byte[] bitCounts =
-		{
-			0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1,
-			2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4,
-			4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3,
-			4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5,
-			3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2,
-			3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3,
-			3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6,
-			7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,
-			5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5,
-			6, 6, 7, 6, 7, 7, 8
-		};
-
-		private int calcBitLength(
-			int		indx,
-			int[]	mag)
-		{
-			for (;;)
-			{
-				if (indx >= mag.Length)
-					return 0;
-
-				if (mag[indx] != 0)
-					break;
-
-				++indx;
-			}
-
-			// bit length for everything after the first int
-			int bitLength = 32 * ((mag.Length - indx) - 1);
-
-			// and determine bitlength of first int
-			int firstMag = mag[indx];
-			bitLength += BitLen(firstMag);
-
-			// Check for negative powers of two
-			if (sign < 0 && ((firstMag & -firstMag) == firstMag))
-			{
-				do
-				{
-					if (++indx >= mag.Length)
-					{
-						--bitLength;
-						break;
-					}
-				}
-				while (mag[indx] == 0);
-			}
-
-			return bitLength;
-		}
-
-		public int BitLength
-		{
-			get
-			{
-				if (nBitLength == -1)
-				{
-					nBitLength = sign == 0
-						? 0
-						: calcBitLength(0, magnitude);
-				}
-
-				return nBitLength;
-			}
-		}
-
-		//
-		// BitLen(value) is the number of bits in value.
-		//
-		private static int BitLen(
-			int w)
-		{
-			// Binary search - decision tree (5 tests, rarely 6)
-			return (w < 1 << 15 ? (w < 1 << 7
-				? (w < 1 << 3 ? (w < 1 << 1
-				? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1)
-				: (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5
-				? (w < 1 << 4 ? 4 : 5)
-				: (w < 1 << 6 ? 6 : 7)))
-				: (w < 1 << 11
-				? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11))
-				: (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19
-				? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19))
-				: (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27
-				? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27))
-				: (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31)))));
-		}
-
-//		private readonly static byte[] bitLengths =
-//		{
-//			0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
-//			5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-//			6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-//			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-//			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
-//			8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-//			8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-//			8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-//			8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
-//			8, 8, 8, 8, 8, 8, 8, 8
-//		};
-
-		private bool QuickPow2Check()
-		{
-			return sign > 0 && nBits == 1;
-		}
-
-		public int CompareTo(
-			object obj)
-		{
-			return CompareTo((BigInteger)obj);
-		}
-
-		/**
-		 * unsigned comparison on two arrays - note the arrays may
-		 * start with leading zeros.
-		 */
-		private static int CompareTo(
-			int		xIndx,
-			int[]	x,
-			int		yIndx,
-			int[]	y)
-		{
-			while (xIndx != x.Length && x[xIndx] == 0)
-			{
-				xIndx++;
-			}
-
-			while (yIndx != y.Length && y[yIndx] == 0)
-			{
-				yIndx++;
-			}
-
-			return CompareNoLeadingZeroes(xIndx, x, yIndx, y);
-		}
-
-		private static int CompareNoLeadingZeroes(
-			int		xIndx,
-			int[]	x,
-			int		yIndx,
-			int[]	y)
-		{
-			int diff = (x.Length - y.Length) - (xIndx - yIndx);
-
-			if (diff != 0)
-			{
-				return diff < 0 ? -1 : 1;
-			}
-
-			// lengths of magnitudes the same, test the magnitude values
-
-			while (xIndx < x.Length)
-			{
-				uint v1 = (uint)x[xIndx++];
-				uint v2 = (uint)y[yIndx++];
-
-				if (v1 != v2)
-					return v1 < v2 ? -1 : 1;
-			}
-
-			return 0;
-		}
-
-		public int CompareTo(
-			BigInteger value)
-		{
-			return sign < value.sign ? -1
-				: sign > value.sign ? 1
-				: sign == 0 ? 0
-				: sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude);
-		}
-
-		/**
-		 * return z = x / y - done in place (z value preserved, x contains the
-		 * remainder)
-		 */
-		private int[] Divide(
-			int[]	x,
-			int[]	y)
-		{
-			int xStart = 0;
-			while (xStart < x.Length && x[xStart] == 0)
-			{
-				++xStart;
-			}
-
-			int yStart = 0;
-			while (yStart < y.Length && y[yStart] == 0)
-			{
-				++yStart;
-			}
-
-			Debug.Assert(yStart < y.Length);
-
-			int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
-			int[] count;
-
-			if (xyCmp > 0)
-			{
-				int yBitLength = calcBitLength(yStart, y);
-				int xBitLength = calcBitLength(xStart, x);
-				int shift = xBitLength - yBitLength;
-
-				int[] iCount;
-				int iCountStart = 0;
-
-				int[] c;
-				int cStart = 0;
-				int cBitLength = yBitLength;
-				if (shift > 0)
-				{
+                    }
+                    else if (radix == 8)
+                    {
+                        // NB: Can't reach here since we are parsing one char at a time
+                        Debug.Assert(false);
+
+                        // TODO Parse all bits at once
+//						b = b.ShiftLeft(s.Length * 3);
+                    }
+                    else if (radix == 16)
+                    {
+                        b = b.ShiftLeft(s.Length << 2);
+                    }
+                    else
+                    {
+                        b = b.Multiply(r.Pow(s.Length));
+                    }
+
+                    b = b.Add(bi);
+                }
+                else
+                {
+                    b = bi;
+                }
+            }
+
+            // Note: This is the previous (slower) algorithm
+//			while (index < value.Length)
+//            {
+//				char c = value[index];
+//				string s = c.ToString();
+//				int i = Int32.Parse(s, style);
+//
+//                b = b.Multiply(r).Add(ValueOf(i));
+//                index++;
+//            }
+
+            magnitude = b.magnitude;
+        }
+
+        public BigInteger(
+            byte[] bytes)
+            : this(bytes, 0, bytes.Length)
+        {
+        }
+
+        public BigInteger(
+            byte[]	bytes,
+            int		offset,
+            int		length)
+        {
+            if (length == 0)
+                throw new FormatException("Zero length BigInteger");
+
+            // TODO Move this processing into MakeMagnitude (provide sign argument)
+            if ((sbyte)bytes[offset] < 0)
+            {
+                this.sign = -1;
+
+                int end = offset + length;
+
+                int iBval;
+                // strip leading sign bytes
+                for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++)
+                {
+                }
+
+                if (iBval >= end)
+                {
+                    this.magnitude = One.magnitude;
+                }
+                else
+                {
+                    int numBytes = end - iBval;
+                    byte[] inverse = new byte[numBytes];
+
+                    int index = 0;
+                    while (index < numBytes)
+                    {
+                        inverse[index++] = (byte)~bytes[iBval++];
+                    }
+
+                    Debug.Assert(iBval == end);
+
+                    while (inverse[--index] == byte.MaxValue)
+                    {
+                        inverse[index] = byte.MinValue;
+                    }
+
+                    inverse[index]++;
+
+                    this.magnitude = MakeMagnitude(inverse, 0, inverse.Length);
+                }
+            }
+            else
+            {
+                // strip leading zero bytes and return magnitude bytes
+                this.magnitude = MakeMagnitude(bytes, offset, length);
+                this.sign = this.magnitude.Length > 0 ? 1 : 0;
+            }
+        }
+
+        private static int[] MakeMagnitude(
+            byte[]	bytes,
+            int		offset,
+            int		length)
+        {
+            int end = offset + length;
+
+            // strip leading zeros
+            int firstSignificant;
+            for (firstSignificant = offset; firstSignificant < end
+                && bytes[firstSignificant] == 0; firstSignificant++)
+            {
+            }
+
+            if (firstSignificant >= end)
+            {
+                return ZeroMagnitude;
+            }
+
+            int nInts = (end - firstSignificant + 3) / BytesPerInt;
+            int bCount = (end - firstSignificant) % BytesPerInt;
+            if (bCount == 0)
+            {
+                bCount = BytesPerInt;
+            }
+
+            if (nInts < 1)
+            {
+                return ZeroMagnitude;
+            }
+
+            int[] mag = new int[nInts];
+
+            int v = 0;
+            int magnitudeIndex = 0;
+            for (int i = firstSignificant; i < end; ++i)
+            {
+                v <<= 8;
+                v |= bytes[i] & 0xff;
+                bCount--;
+                if (bCount <= 0)
+                {
+                    mag[magnitudeIndex] = v;
+                    magnitudeIndex++;
+                    bCount = BytesPerInt;
+                    v = 0;
+                }
+            }
+
+            if (magnitudeIndex < mag.Length)
+            {
+                mag[magnitudeIndex] = v;
+            }
+
+            return mag;
+        }
+
+        public BigInteger(
+            int		sign,
+            byte[]	bytes)
+            : this(sign, bytes, 0, bytes.Length)
+        {
+        }
+
+        public BigInteger(
+            int		sign,
+            byte[]	bytes,
+            int		offset,
+            int		length)
+        {
+            if (sign < -1 || sign > 1)
+                throw new FormatException("Invalid sign value");
+
+            if (sign == 0)
+            {
+                this.sign = 0;
+                this.magnitude = ZeroMagnitude;
+            }
+            else
+            {
+                // copy bytes
+                this.magnitude = MakeMagnitude(bytes, offset, length);
+                this.sign = this.magnitude.Length < 1 ? 0 : sign;
+            }
+        }
+
+        public BigInteger(
+            int		sizeInBits,
+            Random	random)
+        {
+            if (sizeInBits < 0)
+                throw new ArgumentException("sizeInBits must be non-negative");
+
+            this.nBits = -1;
+            this.nBitLength = -1;
+
+            if (sizeInBits == 0)
+            {
+                this.sign = 0;
+                this.magnitude = ZeroMagnitude;
+                return;
+            }
+
+            int nBytes = GetByteLength(sizeInBits);
+            byte[] b = new byte[nBytes];
+            random.NextBytes(b);
+
+            // strip off any excess bits in the MSB
+            int xBits = BitsPerByte * nBytes - sizeInBits;
+            b[0] &= (byte)(255U >> xBits);
+
+            this.magnitude = MakeMagnitude(b, 0, b.Length);
+            this.sign = this.magnitude.Length < 1 ? 0 : 1;
+        }
+
+        public BigInteger(
+            int		bitLength,
+            int		certainty,
+            Random	random)
+        {
+            if (bitLength < 2)
+                throw new ArithmeticException("bitLength < 2");
+
+            this.sign = 1;
+            this.nBitLength = bitLength;
+
+            if (bitLength == 2)
+            {
+                this.magnitude = random.Next(2) == 0
+                    ?	Two.magnitude
+                    :	Three.magnitude;
+                return;
+            }
+             
+            int nBytes = GetByteLength(bitLength);
+            byte[] b = new byte[nBytes];
+
+            int xBits = BitsPerByte * nBytes - bitLength;
+            byte mask = (byte)(255U >> xBits);
+
+            for (;;)
+            {
+                random.NextBytes(b);
+
+                // strip off any excess bits in the MSB
+                b[0] &= mask;
+
+                // ensure the leading bit is 1 (to meet the strength requirement)
+                b[0] |= (byte)(1 << (7 - xBits));
+
+                // ensure the trailing bit is 1 (i.e. must be odd)
+                b[nBytes - 1] |= 1;
+
+                this.magnitude = MakeMagnitude(b, 0, b.Length);
+                this.nBits = -1;
+                this.mQuote = 0;
+
+                if (certainty < 1)
+                    break;
+
+                if (CheckProbablePrime(certainty, random))
+                    break;
+
+                if (bitLength > 32)
+                {
+                    for (int rep = 0; rep < 10000; ++rep)
+                    {
+                        int n = 33 + random.Next(bitLength - 2);
+                        this.magnitude[this.magnitude.Length - (n >> 5)] ^= (1 << (n & 31));
+                        this.magnitude[this.magnitude.Length - 1] ^= ((random.Next() + 1) << 1);
+                        this.mQuote = 0;
+
+                        if (CheckProbablePrime(certainty, random))
+                            return;
+                    }
+                }
+            }
+        }
+
+        public BigInteger Abs()
+        {
+            return sign >= 0 ? this : Negate();
+        }
+
+        /**
+         * return a = a + b - b preserved.
+         */
+        private static int[] AddMagnitudes(
+            int[] a,
+            int[] b)
+        {
+            int tI = a.Length - 1;
+            int vI = b.Length - 1;
+            long m = 0;
+
+            while (vI >= 0)
+            {
+                m += ((long)(uint)a[tI] + (long)(uint)b[vI--]);
+                a[tI--] = (int)m;
+                m = (long)((ulong)m >> 32);
+            }
+
+            if (m != 0)
+            {
+                while (tI >= 0 && ++a[tI--] == 0)
+                {
+                }
+            }
+
+            return a;
+        }
+
+        public BigInteger Add(
+            BigInteger value)
+        {
+            if (this.sign == 0)
+                return value;
+
+            if (this.sign != value.sign)
+            {
+                if (value.sign == 0)
+                    return this;
+
+                if (value.sign < 0)
+                    return Subtract(value.Negate());
+
+                return value.Subtract(Negate());
+            }
+
+            return AddToMagnitude(value.magnitude);
+        }
+
+        private BigInteger AddToMagnitude(
+            int[] magToAdd)
+        {
+            int[] big, small;
+            if (this.magnitude.Length < magToAdd.Length)
+            {
+                big = magToAdd;
+                small = this.magnitude;
+            }
+            else
+            {
+                big = this.magnitude;
+                small = magToAdd;
+            }
+
+            // Conservatively avoid over-allocation when no overflow possible
+            uint limit = uint.MaxValue;
+            if (big.Length == small.Length)
+                limit -= (uint) small[0];
+
+            bool possibleOverflow = (uint) big[0] >= limit;
+
+            int[] bigCopy;
+            if (possibleOverflow)
+            {
+                bigCopy = new int[big.Length + 1];
+                big.CopyTo(bigCopy, 1);
+            }
+            else
+            {
+                bigCopy = (int[]) big.Clone();
+            }
+
+            bigCopy = AddMagnitudes(bigCopy, small);
+
+            return new BigInteger(this.sign, bigCopy, possibleOverflow);
+        }
+
+        public BigInteger And(
+            BigInteger value)
+        {
+            if (this.sign == 0 || value.sign == 0)
+            {
+                return Zero;
+            }
+
+            int[] aMag = this.sign > 0
+                ? this.magnitude
+                : Add(One).magnitude;
+
+            int[] bMag = value.sign > 0
+                ? value.magnitude
+                : value.Add(One).magnitude;
+
+            bool resultNeg = sign < 0 && value.sign < 0;
+            int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+            int[] resultMag = new int[resultLength];
+
+            int aStart = resultMag.Length - aMag.Length;
+            int bStart = resultMag.Length - bMag.Length;
+
+            for (int i = 0; i < resultMag.Length; ++i)
+            {
+                int aWord = i >= aStart ? aMag[i - aStart] : 0;
+                int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+                if (this.sign < 0)
+                {
+                    aWord = ~aWord;
+                }
+
+                if (value.sign < 0)
+                {
+                    bWord = ~bWord;
+                }
+
+                resultMag[i] = aWord & bWord;
+
+                if (resultNeg)
+                {
+                    resultMag[i] = ~resultMag[i];
+                }
+            }
+
+            BigInteger result = new BigInteger(1, resultMag, true);
+
+            // TODO Optimise this case
+            if (resultNeg)
+            {
+                result = result.Not();
+            }
+
+            return result;
+        }
+
+        public BigInteger AndNot(
+            BigInteger val)
+        {
+            return And(val.Not());
+        }
+
+        public int BitCount
+        {
+            get
+            {
+                if (nBits == -1)
+                {
+                    if (sign < 0)
+                    {
+                        // TODO Optimise this case
+                        nBits = Not().BitCount;
+                    }
+                    else
+                    {
+                        int sum = 0;
+                        for (int i = 0; i < magnitude.Length; ++i)
+                        {
+                            sum += BitCnt(magnitude[i]);
+                        }
+                        nBits = sum;
+                    }
+                }
+
+                return nBits;
+            }
+        }
+
+        public static int BitCnt(int i)
+        {
+            uint u = (uint)i;
+            u = u - ((u >> 1) & 0x55555555);
+            u = (u & 0x33333333) + ((u >> 2) & 0x33333333);
+            u = (u + (u >> 4)) & 0x0f0f0f0f;
+            u += (u >> 8);
+            u += (u >> 16);
+            u &= 0x3f;
+            return (int)u;
+        }
+
+        private static int CalcBitLength(int sign, int indx, int[]	mag)
+        {
+            for (;;)
+            {
+                if (indx >= mag.Length)
+                    return 0;
+
+                if (mag[indx] != 0)
+                    break;
+
+                ++indx;
+            }
+
+            // bit length for everything after the first int
+            int bitLength = 32 * ((mag.Length - indx) - 1);
+
+            // and determine bitlength of first int
+            int firstMag = mag[indx];
+            bitLength += BitLen(firstMag);
+
+            // Check for negative powers of two
+            if (sign < 0 && ((firstMag & -firstMag) == firstMag))
+            {
+                do
+                {
+                    if (++indx >= mag.Length)
+                    {
+                        --bitLength;
+                        break;
+                    }
+                }
+                while (mag[indx] == 0);
+            }
+
+            return bitLength;
+        }
+
+        public int BitLength
+        {
+            get
+            {
+                if (nBitLength == -1)
+                {
+                    nBitLength = sign == 0
+                        ? 0
+                        : CalcBitLength(sign, 0, magnitude);
+                }
+
+                return nBitLength;
+            }
+        }
+
+        //
+        // BitLen(value) is the number of bits in value.
+        //
+        private static int BitLen(int w)
+        {
+            uint v = (uint)w;
+            uint t = v >> 24;
+            if (t != 0)
+                return 24 + BitLengthTable[t];
+            t = v >> 16;
+            if (t != 0)
+                return 16 + BitLengthTable[t];
+            t = v >> 8;
+            if (t != 0)
+                return 8 + BitLengthTable[t];
+            return BitLengthTable[v];
+        }
+
+        private bool QuickPow2Check()
+        {
+            return sign > 0 && nBits == 1;
+        }
+
+        public int CompareTo(
+            object obj)
+        {
+            return CompareTo((BigInteger)obj);
+        }
+
+        /**
+         * unsigned comparison on two arrays - note the arrays may
+         * start with leading zeros.
+         */
+        private static int CompareTo(
+            int		xIndx,
+            int[]	x,
+            int		yIndx,
+            int[]	y)
+        {
+            while (xIndx != x.Length && x[xIndx] == 0)
+            {
+                xIndx++;
+            }
+
+            while (yIndx != y.Length && y[yIndx] == 0)
+            {
+                yIndx++;
+            }
+
+            return CompareNoLeadingZeroes(xIndx, x, yIndx, y);
+        }
+
+        private static int CompareNoLeadingZeroes(
+            int		xIndx,
+            int[]	x,
+            int		yIndx,
+            int[]	y)
+        {
+            int diff = (x.Length - y.Length) - (xIndx - yIndx);
+
+            if (diff != 0)
+            {
+                return diff < 0 ? -1 : 1;
+            }
+
+            // lengths of magnitudes the same, test the magnitude values
+
+            while (xIndx < x.Length)
+            {
+                uint v1 = (uint)x[xIndx++];
+                uint v2 = (uint)y[yIndx++];
+
+                if (v1 != v2)
+                    return v1 < v2 ? -1 : 1;
+            }
+
+            return 0;
+        }
+
+        public int CompareTo(
+            BigInteger value)
+        {
+            return sign < value.sign ? -1
+                : sign > value.sign ? 1
+                : sign == 0 ? 0
+                : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude);
+        }
+
+        /**
+         * return z = x / y - done in place (z value preserved, x contains the
+         * remainder)
+         */
+        private int[] Divide(
+            int[]	x,
+            int[]	y)
+        {
+            int xStart = 0;
+            while (xStart < x.Length && x[xStart] == 0)
+            {
+                ++xStart;
+            }
+
+            int yStart = 0;
+            while (yStart < y.Length && y[yStart] == 0)
+            {
+                ++yStart;
+            }
+
+            Debug.Assert(yStart < y.Length);
+
+            int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+            int[] count;
+
+            if (xyCmp > 0)
+            {
+                int yBitLength = CalcBitLength(1, yStart, y);
+                int xBitLength = CalcBitLength(1, xStart, x);
+                int shift = xBitLength - yBitLength;
+
+                int[] iCount;
+                int iCountStart = 0;
+
+                int[] c;
+                int cStart = 0;
+                int cBitLength = yBitLength;
+                if (shift > 0)
+                {
 //					iCount = ShiftLeft(One.magnitude, shift);
-					iCount = new int[(shift >> 5) + 1];
-					iCount[0] = 1 << (shift % 32);
-
-					c = ShiftLeft(y, shift);
-					cBitLength += shift;
-				}
-				else
-				{
-					iCount = new int[] { 1 };
-
-					int len = y.Length - yStart;
-					c = new int[len];
-					Array.Copy(y, yStart, c, 0, len);
-				}
-
-				count = new int[iCount.Length];
-
-				for (;;)
-				{
-					if (cBitLength < xBitLength
-						|| CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
-					{
-						Subtract(xStart, x, cStart, c);
-						AddMagnitudes(count, iCount);
-
-						while (x[xStart] == 0)
-						{
-							if (++xStart == x.Length)
-								return count;
-						}
-
-						//xBitLength = calcBitLength(xStart, x);
-						xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
-
-						if (xBitLength <= yBitLength)
-						{
-							if (xBitLength < yBitLength)
-								return count;
-
-							xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
-
-							if (xyCmp <= 0)
-								break;
-						}
-					}
-
-					shift = cBitLength - xBitLength;
-
-					// NB: The case where c[cStart] is 1-bit is harmless
-					if (shift == 1)
-					{
-						uint firstC = (uint) c[cStart] >> 1;
-						uint firstX = (uint) x[xStart];
-						if (firstC > firstX)
-							++shift;
-					}
-
-					if (shift < 2)
-					{
-						ShiftRightOneInPlace(cStart, c);
-						--cBitLength;
-						ShiftRightOneInPlace(iCountStart, iCount);
-					}
-					else
-					{
-						ShiftRightInPlace(cStart, c, shift);
-						cBitLength -= shift;
-						ShiftRightInPlace(iCountStart, iCount, shift);
-					}
-
-					//cStart = c.Length - ((cBitLength + 31) / 32);
-					while (c[cStart] == 0)
-					{
-						++cStart;
-					}
-
-					while (iCount[iCountStart] == 0)
-					{
-						++iCountStart;
-					}
-				}
-			}
-			else
-			{
-				count = new int[1];
-			}
-
-			if (xyCmp == 0)
-			{
-				AddMagnitudes(count, One.magnitude);
-				Array.Clear(x, xStart, x.Length - xStart);
-			}
-
-			return count;
-		}
-
-		public BigInteger Divide(
-			BigInteger val)
-		{
-			if (val.sign == 0)
-				throw new ArithmeticException("Division by zero error");
-
-			if (sign == 0)
-				return Zero;
-
-			if (val.QuickPow2Check()) // val is power of two
-			{
-				BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1);
-				return val.sign == this.sign ? result : result.Negate();
-			}
-
-			int[] mag = (int[]) this.magnitude.Clone();
-
-			return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true);
-		}
-
-		public BigInteger[] DivideAndRemainder(
-			BigInteger val)
-		{
-			if (val.sign == 0)
-				throw new ArithmeticException("Division by zero error");
-
-			BigInteger[] biggies = new BigInteger[2];
-
-			if (sign == 0)
-			{
-				biggies[0] = Zero;
-				biggies[1] = Zero;
-			}
-			else if (val.QuickPow2Check()) // val is power of two
-			{
-				int e = val.Abs().BitLength - 1;
-				BigInteger quotient = this.Abs().ShiftRight(e);
-				int[] remainder = this.LastNBits(e);
-
-				biggies[0] = val.sign == this.sign ? quotient : quotient.Negate();
-				biggies[1] = new BigInteger(this.sign, remainder, true);
-			}
-			else
-			{
-				int[] remainder = (int[]) this.magnitude.Clone();
-				int[] quotient = Divide(remainder, val.magnitude);
-
-				biggies[0] = new BigInteger(this.sign * val.sign, quotient, true);
-				biggies[1] = new BigInteger(this.sign, remainder, true);
-			}
-
-			return biggies;
-		}
-
-		public override bool Equals(
-			object obj)
-		{
-			if (obj == this)
-				return true;
-
-			BigInteger biggie = obj as BigInteger;
-			if (biggie == null)
-				return false;
-
-			if (biggie.sign != sign || biggie.magnitude.Length != magnitude.Length)
-				return false;
-
-			for (int i = 0; i < magnitude.Length; i++)
-			{
-				if (biggie.magnitude[i] != magnitude[i])
-				{
-					return false;
-				}
-			}
-
-			return true;
-		}
-
-		public BigInteger Gcd(
-			BigInteger value)
-		{
-			if (value.sign == 0)
-				return Abs();
-
-			if (sign == 0)
-				return value.Abs();
-
-			BigInteger r;
-			BigInteger u = this;
-			BigInteger v = value;
-
-			while (v.sign != 0)
-			{
-				r = u.Mod(v);
-				u = v;
-				v = r;
-			}
-
-			return u;
-		}
-
-		public override int GetHashCode()
-		{
-			int hc = magnitude.Length;
-			if (magnitude.Length > 0)
-			{
-				hc ^= magnitude[0];
-
-				if (magnitude.Length > 1)
-				{
-					hc ^= magnitude[magnitude.Length - 1];
-				}
-			}
-
-			return sign < 0 ? ~hc : hc;
-		}
-
-		// TODO Make public?
-		private BigInteger Inc()
-		{
-			if (this.sign == 0)
-				return One;
-
-			if (this.sign < 0)
-				return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true);
-
-			return AddToMagnitude(One.magnitude);
-		}
-
-		public int IntValue
-		{
-			get
-			{
-				return sign == 0 ? 0
-					: sign > 0 ? magnitude[magnitude.Length - 1]
-					: -magnitude[magnitude.Length - 1];
-			}
-		}
-
-		/**
-		 * return whether or not a BigInteger is probably prime with a
-		 * probability of 1 - (1/2)**certainty.
-		 * <p>From Knuth Vol 2, pg 395.</p>
-		 */
-		public bool IsProbablePrime(
-			int certainty)
-		{
-			if (certainty <= 0)
-				return true;
-
-			BigInteger n = Abs();
-
-			if (!n.TestBit(0))
-				return n.Equals(Two);
-
-			if (n.Equals(One))
-				return false;
-
-			return n.CheckProbablePrime(certainty, RandomSource);
-		}
-
-		private bool CheckProbablePrime(
-			int		certainty,
-			Random	random)
-		{
-			Debug.Assert(certainty > 0);
-			Debug.Assert(CompareTo(Two) > 0);
-			Debug.Assert(TestBit(0));
-
-
-			// Try to reduce the penalty for really small numbers
-			int numLists = System.Math.Min(BitLength - 1, primeLists.Length);
-
-			for (int i = 0; i < numLists; ++i)
-			{
-				int test = Remainder(primeProducts[i]);
-
-				int[] primeList = primeLists[i];
-				for (int j = 0; j < primeList.Length; ++j)
-				{
-					int prime = primeList[j];
-					int qRem = test % prime;
-					if (qRem == 0)
-					{
-						// We may find small numbers in the list
-						return BitLength < 16 && IntValue == prime;
-					}
-				}
-			}
-
-
-			// TODO Special case for < 10^16 (RabinMiller fixed list)
+                    iCount = new int[(shift >> 5) + 1];
+                    iCount[0] = 1 << (shift % 32);
+
+                    c = ShiftLeft(y, shift);
+                    cBitLength += shift;
+                }
+                else
+                {
+                    iCount = new int[] { 1 };
+
+                    int len = y.Length - yStart;
+                    c = new int[len];
+                    Array.Copy(y, yStart, c, 0, len);
+                }
+
+                count = new int[iCount.Length];
+
+                for (;;)
+                {
+                    if (cBitLength < xBitLength
+                        || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
+                    {
+                        Subtract(xStart, x, cStart, c);
+                        AddMagnitudes(count, iCount);
+
+                        while (x[xStart] == 0)
+                        {
+                            if (++xStart == x.Length)
+                                return count;
+                        }
+
+                        //xBitLength = CalcBitLength(xStart, x);
+                        xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
+
+                        if (xBitLength <= yBitLength)
+                        {
+                            if (xBitLength < yBitLength)
+                                return count;
+
+                            xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+                            if (xyCmp <= 0)
+                                break;
+                        }
+                    }
+
+                    shift = cBitLength - xBitLength;
+
+                    // NB: The case where c[cStart] is 1-bit is harmless
+                    if (shift == 1)
+                    {
+                        uint firstC = (uint) c[cStart] >> 1;
+                        uint firstX = (uint) x[xStart];
+                        if (firstC > firstX)
+                            ++shift;
+                    }
+
+                    if (shift < 2)
+                    {
+                        ShiftRightOneInPlace(cStart, c);
+                        --cBitLength;
+                        ShiftRightOneInPlace(iCountStart, iCount);
+                    }
+                    else
+                    {
+                        ShiftRightInPlace(cStart, c, shift);
+                        cBitLength -= shift;
+                        ShiftRightInPlace(iCountStart, iCount, shift);
+                    }
+
+                    //cStart = c.Length - ((cBitLength + 31) / 32);
+                    while (c[cStart] == 0)
+                    {
+                        ++cStart;
+                    }
+
+                    while (iCount[iCountStart] == 0)
+                    {
+                        ++iCountStart;
+                    }
+                }
+            }
+            else
+            {
+                count = new int[1];
+            }
+
+            if (xyCmp == 0)
+            {
+                AddMagnitudes(count, One.magnitude);
+                Array.Clear(x, xStart, x.Length - xStart);
+            }
+
+            return count;
+        }
+
+        public BigInteger Divide(
+            BigInteger val)
+        {
+            if (val.sign == 0)
+                throw new ArithmeticException("Division by zero error");
+
+            if (sign == 0)
+                return Zero;
+
+            if (val.QuickPow2Check()) // val is power of two
+            {
+                BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1);
+                return val.sign == this.sign ? result : result.Negate();
+            }
+
+            int[] mag = (int[]) this.magnitude.Clone();
+
+            return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true);
+        }
+
+        public BigInteger[] DivideAndRemainder(
+            BigInteger val)
+        {
+            if (val.sign == 0)
+                throw new ArithmeticException("Division by zero error");
+
+            BigInteger[] biggies = new BigInteger[2];
+
+            if (sign == 0)
+            {
+                biggies[0] = Zero;
+                biggies[1] = Zero;
+            }
+            else if (val.QuickPow2Check()) // val is power of two
+            {
+                int e = val.Abs().BitLength - 1;
+                BigInteger quotient = this.Abs().ShiftRight(e);
+                int[] remainder = this.LastNBits(e);
+
+                biggies[0] = val.sign == this.sign ? quotient : quotient.Negate();
+                biggies[1] = new BigInteger(this.sign, remainder, true);
+            }
+            else
+            {
+                int[] remainder = (int[]) this.magnitude.Clone();
+                int[] quotient = Divide(remainder, val.magnitude);
+
+                biggies[0] = new BigInteger(this.sign * val.sign, quotient, true);
+                biggies[1] = new BigInteger(this.sign, remainder, true);
+            }
+
+            return biggies;
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+            BigInteger biggie = obj as BigInteger;
+            if (biggie == null)
+                return false;
+
+            return sign == biggie.sign && IsEqualMagnitude(biggie);
+        }
+
+        private bool IsEqualMagnitude(BigInteger x)
+        {
+            int[] xMag = x.magnitude;
+            if (magnitude.Length != x.magnitude.Length)
+                return false;
+            for (int i = 0; i < magnitude.Length; i++)
+            {
+                if (magnitude[i] != x.magnitude[i])
+                    return false;
+            }
+            return true;
+        }
+
+        public BigInteger Gcd(
+            BigInteger value)
+        {
+            if (value.sign == 0)
+                return Abs();
+
+            if (sign == 0)
+                return value.Abs();
+
+            BigInteger r;
+            BigInteger u = this;
+            BigInteger v = value;
+
+            while (v.sign != 0)
+            {
+                r = u.Mod(v);
+                u = v;
+                v = r;
+            }
+
+            return u;
+        }
+
+        public override int GetHashCode()
+        {
+            int hc = magnitude.Length;
+            if (magnitude.Length > 0)
+            {
+                hc ^= magnitude[0];
+
+                if (magnitude.Length > 1)
+                {
+                    hc ^= magnitude[magnitude.Length - 1];
+                }
+            }
+
+            return sign < 0 ? ~hc : hc;
+        }
+
+        // TODO Make public?
+        private BigInteger Inc()
+        {
+            if (this.sign == 0)
+                return One;
+
+            if (this.sign < 0)
+                return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true);
+
+            return AddToMagnitude(One.magnitude);
+        }
+
+        public int IntValue
+        {
+            get
+            {
+                if (sign == 0)
+                    return 0;
+
+                int n = magnitude.Length;
+
+                int v = magnitude[n - 1];
+
+                return sign < 0 ? -v : v;
+            }
+        }
+
+        /**
+         * return whether or not a BigInteger is probably prime with a
+         * probability of 1 - (1/2)**certainty.
+         * <p>From Knuth Vol 2, pg 395.</p>
+         */
+        public bool IsProbablePrime(
+            int certainty)
+        {
+            if (certainty <= 0)
+                return true;
+
+            BigInteger n = Abs();
+
+            if (!n.TestBit(0))
+                return n.Equals(Two);
+
+            if (n.Equals(One))
+                return false;
+
+            return n.CheckProbablePrime(certainty, RandomSource);
+        }
+
+        private bool CheckProbablePrime(
+            int		certainty,
+            Random	random)
+        {
+            Debug.Assert(certainty > 0);
+            Debug.Assert(CompareTo(Two) > 0);
+            Debug.Assert(TestBit(0));
+
+
+            // Try to reduce the penalty for really small numbers
+            int numLists = System.Math.Min(BitLength - 1, primeLists.Length);
+
+            for (int i = 0; i < numLists; ++i)
+            {
+                int test = Remainder(primeProducts[i]);
+
+                int[] primeList = primeLists[i];
+                for (int j = 0; j < primeList.Length; ++j)
+                {
+                    int prime = primeList[j];
+                    int qRem = test % prime;
+                    if (qRem == 0)
+                    {
+                        // We may find small numbers in the list
+                        return BitLength < 16 && IntValue == prime;
+                    }
+                }
+            }
+
+
+            // TODO Special case for < 10^16 (RabinMiller fixed list)
 //			if (BitLength < 30)
 //			{
 //				RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient
 //			}
 
 
-			// TODO Is it worth trying to create a hybrid of these two?
-			return RabinMillerTest(certainty, random);
+            // TODO Is it worth trying to create a hybrid of these two?
+            return RabinMillerTest(certainty, random);
 //			return SolovayStrassenTest(certainty, random);
 
 //			bool rbTest = RabinMillerTest(certainty, random);
@@ -1310,58 +1398,58 @@ namespace Org.BouncyCastle.Math
 //			Debug.Assert(rbTest == ssTest);
 //
 //			return rbTest;
-		}
-
-		internal bool RabinMillerTest(
-			int		certainty,
-			Random	random)
-		{
-			Debug.Assert(certainty > 0);
-			Debug.Assert(BitLength > 2);
-			Debug.Assert(TestBit(0));
-
-			// let n = 1 + d . 2^s
-			BigInteger n = this;
-			BigInteger nMinusOne = n.Subtract(One);
-			int s = nMinusOne.GetLowestSetBit();
-			BigInteger r = nMinusOne.ShiftRight(s);
-
-			Debug.Assert(s >= 1);
-
-			do
-			{
-				// TODO Make a method for random BigIntegers in range 0 < x < n)
-				// - Method can be optimized by only replacing examined bits at each trial
-				BigInteger a;
-				do
-				{
-					a = new BigInteger(n.BitLength, random);
-				}
-				while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0);
-
-				BigInteger y = a.ModPow(r, n);
-
-				if (!y.Equals(One))
-				{
-					int j = 0;
-					while (!y.Equals(nMinusOne))
-					{
-						if (++j == s)
-							return false;
-
-						y = y.ModPow(Two, n);
-
-						if (y.Equals(One))
-							return false;
-					}
-				}
-
-				certainty -= 2; // composites pass for only 1/4 possible 'a'
-			}
-			while (certainty > 0);
-
-			return true;
-		}
+        }
+
+        public bool RabinMillerTest(int certainty, Random random)
+        {
+            Debug.Assert(certainty > 0);
+            Debug.Assert(BitLength > 2);
+            Debug.Assert(TestBit(0));
+
+            // let n = 1 + d . 2^s
+            BigInteger n = this;
+            int s = n.GetLowestSetBitMaskFirst(-1 << 1);
+            Debug.Assert(s >= 1);
+            BigInteger r = n.ShiftRight(s);
+
+            // NOTE: Avoid conversion to/from Montgomery form and check for R/-R as result instead
+
+            BigInteger montRadix = One.ShiftLeft(32 * n.magnitude.Length).Remainder(n);
+            BigInteger minusMontRadix = n.Subtract(montRadix);
+
+            do
+            {
+                BigInteger a;
+                do
+                {
+                    a = new BigInteger(n.BitLength, random);
+                }
+                while (a.sign == 0 || a.CompareTo(n) >= 0
+                    || a.IsEqualMagnitude(montRadix) || a.IsEqualMagnitude(minusMontRadix));
+
+                BigInteger y = ModPowMonty(a, r, n, false);
+
+                if (!y.Equals(montRadix))
+                {
+                    int j = 0;
+                    while (!y.Equals(minusMontRadix))
+                    {
+                        if (++j == s)
+                            return false;
+
+                        y = ModPowMonty(y, Two, n, false);
+
+                        if (y.Equals(montRadix))
+                            return false;
+                    }
+                }
+
+                certainty -= 2; // composites pass for only 1/4 possible 'a'
+            }
+            while (certainty > 0);
+
+            return true;
+        }
 
 //		private bool SolovayStrassenTest(
 //			int		certainty,
@@ -1452,58 +1540,55 @@ namespace Org.BouncyCastle.Math
 //			return totalS;
 //		}
 
-		public long LongValue
-		{
-			get
-			{
-				if (sign == 0)
-					return 0;
-
-				long v;
-				if (magnitude.Length > 1)
-				{
-					v = ((long)magnitude[magnitude.Length - 2] << 32)
-						| (magnitude[magnitude.Length - 1] & IMASK);
-				}
-				else
-				{
-					v = (magnitude[magnitude.Length - 1] & IMASK);
-				}
-
-				return sign < 0 ? -v : v;
-			}
-		}
-
-		public BigInteger Max(
-			BigInteger value)
-		{
-			return CompareTo(value) > 0 ? this : value;
-		}
-
-		public BigInteger Min(
-			BigInteger value)
-		{
-			return CompareTo(value) < 0 ? this : value;
-		}
-
-		public BigInteger Mod(
-			BigInteger m)
-		{
-			if (m.sign < 1)
-				throw new ArithmeticException("Modulus must be positive");
-
-			BigInteger biggie = Remainder(m);
-
-			return (biggie.sign >= 0 ? biggie : biggie.Add(m));
-		}
-
-		public BigInteger ModInverse(
-			BigInteger m)
-		{
-			if (m.sign < 1)
-				throw new ArithmeticException("Modulus must be positive");
-
-			// TODO Too slow at the moment
+        public long LongValue
+        {
+            get
+            {
+                if (sign == 0)
+                    return 0;
+
+                int n = magnitude.Length;
+
+                long v = magnitude[n - 1] & IMASK;
+                if (n > 1)
+                {
+                    v |= (magnitude[n - 2] & IMASK) << 32;
+                }
+
+                return sign < 0 ? -v : v;
+            }
+        }
+
+        public BigInteger Max(
+            BigInteger value)
+        {
+            return CompareTo(value) > 0 ? this : value;
+        }
+
+        public BigInteger Min(
+            BigInteger value)
+        {
+            return CompareTo(value) < 0 ? this : value;
+        }
+
+        public BigInteger Mod(
+            BigInteger m)
+        {
+            if (m.sign < 1)
+                throw new ArithmeticException("Modulus must be positive");
+
+            BigInteger biggie = Remainder(m);
+
+            return (biggie.sign >= 0 ? biggie : biggie.Add(m));
+        }
+
+        public BigInteger ModInverse(
+            BigInteger m)
+        {
+            if (m.sign < 1)
+                throw new ArithmeticException("Modulus must be positive");
+
+            // TODO Too slow at the moment
 //			// "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel
 //			if (m.TestBit(0))
 //			{
@@ -1541,992 +1626,1309 @@ namespace Org.BouncyCastle.Math
 //				}
 //			}
 
+            if (m.QuickPow2Check())
+            {
+                return ModInversePow2(m);
+            }
+
+            BigInteger d = this.Remainder(m);
             BigInteger x;
-            BigInteger gcd = ExtEuclid(this.Mod(m), m, out x);
+            BigInteger gcd = ExtEuclid(d, m, out x);
+
+            if (!gcd.Equals(One))
+                throw new ArithmeticException("Numbers not relatively prime.");
 
-			if (!gcd.Equals(One))
-				throw new ArithmeticException("Numbers not relatively prime.");
+            if (x.sign < 0)
+            {
+                x = x.Add(m);
+            }
+
+            return x;
+        }
+
+        private BigInteger ModInversePow2(BigInteger m)
+        {
+            Debug.Assert(m.SignValue > 0);
+            Debug.Assert(m.BitCount == 1);
+
+            if (!TestBit(0))
+            {
+                throw new ArithmeticException("Numbers not relatively prime.");
+            }
+
+            int pow = m.BitLength - 1;
+
+            long inv64 = ModInverse64(LongValue);
+            if (pow < 64)
+            {
+                inv64 &= ((1L << pow) - 1);
+            }
 
-			if (x.sign < 0)
-			{
+            BigInteger x = BigInteger.ValueOf(inv64);
+
+            if (pow > 64)
+            {
+                BigInteger d = this.Remainder(m);
+                int bitsCorrect = 64;
+
+                do
+                {
+                    BigInteger t = x.Multiply(d).Remainder(m);
+                    x = x.Multiply(Two.Subtract(t)).Remainder(m);
+                    bitsCorrect <<= 1;
+                }
+                while (bitsCorrect < pow);
+            }
+
+            if (x.sign < 0)
+            {
                 x = x.Add(m);
-			}
-
-			return x;
-		}
-
-		/**
-		 * Calculate the numbers u1, u2, and u3 such that:
-		 *
-		 * u1 * a + u2 * b = u3
-		 *
-		 * where u3 is the greatest common divider of a and b.
-		 * a and b using the extended Euclid algorithm (refer p. 323
-		 * of The Art of Computer Programming vol 2, 2nd ed).
-		 * This also seems to have the side effect of calculating
-		 * some form of multiplicative inverse.
-		 *
-		 * @param a    First number to calculate gcd for
-		 * @param b    Second number to calculate gcd for
-		 * @param u1Out      the return object for the u1 value
-		 * @param u2Out      the return object for the u2 value
-		 * @return     The greatest common divisor of a and b
-		 */
-		private static BigInteger ExtEuclid(
-			BigInteger	    a,
-			BigInteger	    b,
-			out BigInteger  u1Out)
-            //BigInteger	    u2Out)
-		{
-			BigInteger u1 = One;
-			BigInteger u3 = a;
-			BigInteger v1 = Zero;
-			BigInteger v3 = b;
-
-			while (v3.sign > 0)
-			{
-				BigInteger[] q = u3.DivideAndRemainder(v3);
-
-				BigInteger tmp = v1.Multiply(q[0]);
-				BigInteger tn = u1.Subtract(tmp);
-				u1 = v1;
-				v1 = tn;
-
-				u3 = v3;
-				v3 = q[1];
-			}
-
-            //if (u1Out != null)
-            //{
-            //    u1Out.sign = u1.sign;
-            //    u1Out.magnitude = u1.magnitude;
-            //}
+            }
+
+            return x;
+        }
+
+        private static int ModInverse32(int d)
+        {
+            // Newton's method with initial estimate "correct to 4 bits"
+            Debug.Assert((d & 1) != 0);
+            int x = d + (((d + 1) & 4) << 1);   // d.x == 1 mod 2**4
+            Debug.Assert(((d * x) & 15) == 1);
+            x *= 2 - d * x;                     // d.x == 1 mod 2**8
+            x *= 2 - d * x;                     // d.x == 1 mod 2**16
+            x *= 2 - d * x;                     // d.x == 1 mod 2**32
+            Debug.Assert(d * x == 1);
+            return x;
+        }
+
+        private static long ModInverse64(long d)
+        {
+            // Newton's method with initial estimate "correct to 4 bits"
+            Debug.Assert((d & 1L) != 0);
+            long x = d + (((d + 1L) & 4L) << 1);    // d.x == 1 mod 2**4
+            Debug.Assert(((d * x) & 15L) == 1L);
+            x *= 2 - d * x;                         // d.x == 1 mod 2**8
+            x *= 2 - d * x;                         // d.x == 1 mod 2**16
+            x *= 2 - d * x;                         // d.x == 1 mod 2**32
+            x *= 2 - d * x;                         // d.x == 1 mod 2**64
+            Debug.Assert(d * x == 1L);
+            return x;
+        }
+
+        /**
+         * Calculate the numbers u1, u2, and u3 such that:
+         *
+         * u1 * a + u2 * b = u3
+         *
+         * where u3 is the greatest common divider of a and b.
+         * a and b using the extended Euclid algorithm (refer p. 323
+         * of The Art of Computer Programming vol 2, 2nd ed).
+         * This also seems to have the side effect of calculating
+         * some form of multiplicative inverse.
+         *
+         * @param a    First number to calculate gcd for
+         * @param b    Second number to calculate gcd for
+         * @param u1Out      the return object for the u1 value
+         * @return     The greatest common divisor of a and b
+         */
+        private static BigInteger ExtEuclid(BigInteger a, BigInteger b, out BigInteger u1Out)
+        {
+            BigInteger u1 = One, v1 = Zero;
+            BigInteger u3 = a, v3 = b;
+
+            if (v3.sign > 0)
+            {
+                for (;;)
+                {
+                    BigInteger[] q = u3.DivideAndRemainder(v3);
+                    u3 = v3;
+                    v3 = q[1];
+
+                    BigInteger oldU1 = u1;
+                    u1 = v1;
+
+                    if (v3.sign <= 0)
+                        break;
+
+                    v1 = oldU1.Subtract(v1.Multiply(q[0]));
+                }
+            }
+
             u1Out = u1;
 
-            //if (u2Out != null)
-            //{
-            //    BigInteger tmp = u1.Multiply(a);
-            //    tmp = u3.Subtract(tmp);
-            //    BigInteger res = tmp.Divide(b);
-            //    u2Out.sign = res.sign;
-            //    u2Out.magnitude = res.magnitude;
-            //}
-
-			return u3;
-		}
-
-		private static void ZeroOut(
-			int[] x)
-		{
-			Array.Clear(x, 0, x.Length);
-		}
-
-		public BigInteger ModPow(
-			BigInteger exponent,
-			BigInteger m)
-		{
-			if (m.sign < 1)
-				throw new ArithmeticException("Modulus must be positive");
-
-			if (m.Equals(One))
-				return Zero;
-
-			if (exponent.sign == 0)
-				return One;
-
-			if (sign == 0)
-				return Zero;
-
-			int[] zVal = null;
-			int[] yAccum = null;
-			int[] yVal;
-
-			// Montgomery exponentiation is only possible if the modulus is odd,
-			// but AFAIK, this is always the case for crypto algo's
-			bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1);
-			long mQ = 0;
-			if (useMonty)
-			{
-				mQ = m.GetMQuote();
-
-				// tmp = this * R mod m
-				BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m);
-				zVal = tmp.magnitude;
-
-				useMonty = (zVal.Length <= m.magnitude.Length);
-
-				if (useMonty)
-				{
-					yAccum = new int[m.magnitude.Length + 1];
-					if (zVal.Length < m.magnitude.Length)
-					{
-						int[] longZ = new int[m.magnitude.Length];
-						zVal.CopyTo(longZ, longZ.Length - zVal.Length);
-						zVal = longZ;
-					}
-				}
-			}
-
-			if (!useMonty)
-			{
-				if (magnitude.Length <= m.magnitude.Length)
-				{
-					//zAccum = new int[m.magnitude.Length * 2];
-					zVal = new int[m.magnitude.Length];
-					magnitude.CopyTo(zVal, zVal.Length - magnitude.Length);
-				}
-				else
-				{
-					//
-					// in normal practice we'll never see this...
-					//
-					BigInteger tmp = Remainder(m);
-
-					//zAccum = new int[m.magnitude.Length * 2];
-					zVal = new int[m.magnitude.Length];
-					tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length);
-				}
-
-				yAccum = new int[m.magnitude.Length * 2];
-			}
-
-			yVal = new int[m.magnitude.Length];
-
-			//
-			// from LSW to MSW
-			//
-			for (int i = 0; i < exponent.magnitude.Length; i++)
-			{
-				int v = exponent.magnitude[i];
-				int bits = 0;
-
-				if (i == 0)
-				{
-					while (v > 0)
-					{
-						v <<= 1;
-						bits++;
-					}
-
-					//
-					// first time in initialise y
-					//
-					zVal.CopyTo(yVal, 0);
-
-					v <<= 1;
-					bits++;
-				}
-
-				while (v != 0)
-				{
-					if (useMonty)
-					{
-						// Montgomery square algo doesn't exist, and a normal
-						// square followed by a Montgomery reduction proved to
-						// be almost as heavy as a Montgomery mulitply.
-						MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
-					}
-					else
-					{
-						Square(yAccum, yVal);
-						Remainder(yAccum, m.magnitude);
-						Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
-						ZeroOut(yAccum);
-					}
-					bits++;
-
-					if (v < 0)
-					{
-						if (useMonty)
-						{
-							MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
-						}
-						else
-						{
-							Multiply(yAccum, yVal, zVal);
-							Remainder(yAccum, m.magnitude);
-							Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0,
-								yVal.Length);
-							ZeroOut(yAccum);
-						}
-					}
-
-					v <<= 1;
-				}
-
-				while (bits < 32)
-				{
-					if (useMonty)
-					{
-						MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ);
-					}
-					else
-					{
-						Square(yAccum, yVal);
-						Remainder(yAccum, m.magnitude);
-						Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length);
-						ZeroOut(yAccum);
-					}
-					bits++;
-				}
-			}
-
-			if (useMonty)
-			{
-				// Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m
-				ZeroOut(zVal);
-				zVal[zVal.Length - 1] = 1;
-				MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ);
-			}
-
-			BigInteger result = new BigInteger(1, yVal, true);
-
-			return exponent.sign > 0
-				?	result
-				:	result.ModInverse(m);
-		}
-
-		/**
-		 * return w with w = x * x - w is assumed to have enough space.
-		 */
-		private static int[] Square(
-			int[]	w,
-			int[]	x)
-		{
-			// Note: this method allows w to be only (2 * x.Length - 1) words if result will fit
+            return u3;
+        }
+
+        private static void ZeroOut(
+            int[] x)
+        {
+            Array.Clear(x, 0, x.Length);
+        }
+
+        public BigInteger ModPow(BigInteger e, BigInteger m)
+        {
+            if (m.sign < 1)
+                throw new ArithmeticException("Modulus must be positive");
+
+            if (m.Equals(One))
+                return Zero;
+
+            if (e.sign == 0)
+                return One;
+
+            if (sign == 0)
+                return Zero;
+
+            bool negExp = e.sign < 0;
+            if (negExp)
+                e = e.Negate();
+
+            BigInteger result = this.Mod(m);
+            if (!e.Equals(One))
+            {
+                if ((m.magnitude[m.magnitude.Length - 1] & 1) == 0)
+                {
+                    result = ModPowBarrett(result, e, m);
+                }
+                else
+                {
+                    result = ModPowMonty(result, e, m, true);
+                }
+            }
+
+            if (negExp)
+                result = result.ModInverse(m);
+
+            return result;
+        }
+
+        private static BigInteger ModPowBarrett(BigInteger b, BigInteger e, BigInteger m)
+        {
+            int k = m.magnitude.Length;
+            BigInteger mr = One.ShiftLeft((k + 1) << 5);
+            BigInteger yu = One.ShiftLeft(k << 6).Divide(m);
+
+            // Sliding window from MSW to LSW
+            int extraBits = 0, expLength = e.BitLength;
+            while (expLength > ExpWindowThresholds[extraBits])
+            {
+                ++extraBits;
+            }
+
+            int numPowers = 1 << extraBits;
+            BigInteger[] oddPowers = new BigInteger[numPowers];
+            oddPowers[0] = b;
+
+            BigInteger b2 = ReduceBarrett(b.Square(), m, mr, yu);
+
+            for (int i = 1; i < numPowers; ++i)
+            {
+                oddPowers[i] = ReduceBarrett(oddPowers[i - 1].Multiply(b2), m, mr, yu);
+            }
+
+            int[] windowList = GetWindowList(e.magnitude, extraBits);
+            Debug.Assert(windowList.Length > 0);
+
+            int window = windowList[0];
+            int mult = window & 0xFF, lastZeroes = window >> 8;
+
+            BigInteger y;
+            if (mult == 1)
+            {
+                y = b2;
+                --lastZeroes;
+            }
+            else
+            {
+                y = oddPowers[mult >> 1];
+            }
+
+            int windowPos = 1;
+            while ((window = windowList[windowPos++]) != -1)
+            {
+                mult = window & 0xFF;
+
+                int bits = lastZeroes + BitLengthTable[mult];
+                for (int j = 0; j < bits; ++j)
+                {
+                    y = ReduceBarrett(y.Square(), m, mr, yu);
+                }
+
+                y = ReduceBarrett(y.Multiply(oddPowers[mult >> 1]), m, mr, yu);
+
+                lastZeroes = window >> 8;
+            }
+
+            for (int i = 0; i < lastZeroes; ++i)
+            {
+                y = ReduceBarrett(y.Square(), m, mr, yu);
+            }
+
+            return y;
+        }
+
+        private static BigInteger ReduceBarrett(BigInteger x, BigInteger m, BigInteger mr, BigInteger yu)
+        {
+            int xLen = x.BitLength, mLen = m.BitLength;
+            if (xLen < mLen)
+                return x;
+
+            if (xLen - mLen > 1)
+            {
+                int k = m.magnitude.Length;
+
+                BigInteger q1 = x.DivideWords(k - 1);
+                BigInteger q2 = q1.Multiply(yu); // TODO Only need partial multiplication here
+                BigInteger q3 = q2.DivideWords(k + 1);
+
+                BigInteger r1 = x.RemainderWords(k + 1);
+                BigInteger r2 = q3.Multiply(m); // TODO Only need partial multiplication here
+                BigInteger r3 = r2.RemainderWords(k + 1);
+
+                x = r1.Subtract(r3);
+                if (x.sign < 0)
+                {
+                    x = x.Add(mr);
+                }
+            }
+
+            while (x.CompareTo(m) >= 0)
+            {
+                x = x.Subtract(m);
+            }
+
+            return x;
+        }
+
+        private static BigInteger ModPowMonty(BigInteger b, BigInteger e, BigInteger m, bool convert)
+        {
+            int n = m.magnitude.Length;
+            int powR = 32 * n;
+            bool smallMontyModulus = m.BitLength + 2 <= powR;
+            uint mDash = (uint)m.GetMQuote();
+
+            // tmp = this * R mod m
+            if (convert)
+            {
+                b = b.ShiftLeft(powR).Remainder(m);
+            }
+
+            int[] yAccum = new int[n + 1];
+
+            int[] zVal = b.magnitude;
+            Debug.Assert(zVal.Length <= n);
+            if (zVal.Length < n)
+            {
+                int[] tmp = new int[n];
+                zVal.CopyTo(tmp, n - zVal.Length);
+                zVal = tmp;
+            }
+
+            // Sliding window from MSW to LSW
+
+            int extraBits = 0;
+
+            // Filter the common case of small RSA exponents with few bits set
+            if (e.magnitude.Length > 1 || e.BitCount > 2)
+            {
+                int expLength = e.BitLength;
+                while (expLength > ExpWindowThresholds[extraBits])
+                {
+                    ++extraBits;
+                }
+            }
+
+            int numPowers = 1 << extraBits;
+            int[][] oddPowers = new int[numPowers][];
+            oddPowers[0] = zVal;
+
+            int[] zSquared = Arrays.Clone(zVal);
+            SquareMonty(yAccum, zSquared, m.magnitude, mDash, smallMontyModulus);
+
+            for (int i = 1; i < numPowers; ++i)
+            {
+                oddPowers[i] = Arrays.Clone(oddPowers[i - 1]);
+                MultiplyMonty(yAccum, oddPowers[i], zSquared, m.magnitude, mDash, smallMontyModulus);
+            }
+
+            int[] windowList = GetWindowList(e.magnitude, extraBits);
+            Debug.Assert(windowList.Length > 1);
+
+            int window = windowList[0];
+            int mult = window & 0xFF, lastZeroes = window >> 8;
+
+            int[] yVal;
+            if (mult == 1)
+            {
+                yVal = zSquared;
+                --lastZeroes;
+            }
+            else
+            {
+                yVal = Arrays.Clone(oddPowers[mult >> 1]);
+            }
+
+            int windowPos = 1;
+            while ((window = windowList[windowPos++]) != -1)
+            {
+                mult = window & 0xFF;
+
+                int bits = lastZeroes + BitLengthTable[mult];
+                for (int j = 0; j < bits; ++j)
+                {
+                    SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus);
+                }
+
+                MultiplyMonty(yAccum, yVal, oddPowers[mult >> 1], m.magnitude, mDash, smallMontyModulus);
+
+                lastZeroes = window >> 8;
+            }
+
+            for (int i = 0; i < lastZeroes; ++i)
+            {
+                SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus);
+            }
+
+            if (convert)
+            {
+                // Return y * R^(-1) mod m
+                MontgomeryReduce(yVal, m.magnitude, mDash);
+            }
+            else if (smallMontyModulus && CompareTo(0, yVal, 0, m.magnitude) >= 0)
+            {
+                Subtract(0, yVal, 0, m.magnitude);
+            }
+
+            return new BigInteger(1, yVal, true);
+        }
+
+        private static int[] GetWindowList(int[] mag, int extraBits)
+        {
+            int v = mag[0];
+            Debug.Assert(v != 0);
+
+            int leadingBits = BitLen(v);
+
+            int resultSize = (((mag.Length - 1) << 5) + leadingBits) / (1 + extraBits) + 2;
+            int[] result = new int[resultSize];
+            int resultPos = 0;
+
+            int bitPos = 33 - leadingBits;
+            v <<= bitPos;
+
+            int mult = 1, multLimit = 1 << extraBits;
+            int zeroes = 0;
+
+            int i = 0;
+            for (; ; )
+            {
+                for (; bitPos < 32; ++bitPos)
+                {
+                    if (mult < multLimit)
+                    {
+                        mult = (mult << 1) | (int)((uint)v >> 31);
+                    }
+                    else if (v < 0)
+                    {
+                        result[resultPos++] = CreateWindowEntry(mult, zeroes);
+                        mult = 1;
+                        zeroes = 0;
+                    }
+                    else
+                    {
+                        ++zeroes;
+                    }
+
+                    v <<= 1;
+                }
+
+                if (++i == mag.Length)
+                {
+                    result[resultPos++] = CreateWindowEntry(mult, zeroes);
+                    break;
+                }
+
+                v = mag[i];
+                bitPos = 0;
+            }
+
+            result[resultPos] = -1;
+            return result;
+        }
+
+        private static int CreateWindowEntry(int mult, int zeroes)
+        {
+            while ((mult & 1) == 0)
+            {
+                mult >>= 1;
+                ++zeroes;
+            }
+
+            return mult | (zeroes << 8);
+        }
+
+        /**
+         * return w with w = x * x - w is assumed to have enough space.
+         */
+        private static int[] Square(
+            int[]	w,
+            int[]	x)
+        {
+            // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit
 //			if (w.Length != 2 * x.Length)
 //				throw new ArgumentException("no I don't think so...");
 
-			ulong u1, u2, c;
-
-			int wBase = w.Length - 1;
-
-			for (int i = x.Length - 1; i != 0; i--)
-			{
-				ulong v = (ulong)(uint) x[i];
-
-				u1 = v * v;
-				u2 = u1 >> 32;
-				u1 = (uint) u1;
-
-				u1 += (ulong)(uint) w[wBase];
-
-				w[wBase] = (int)(uint) u1;
-				c = u2 + (u1 >> 32);
-
-				for (int j = i - 1; j >= 0; j--)
-				{
-					--wBase;
-					u1 = v * (ulong)(uint) x[j];
-					u2 = u1 >> 31; // multiply by 2!
-					u1 = (uint)(u1 << 1); // multiply by 2!
-					u1 += c + (ulong)(uint) w[wBase];
-
-					w[wBase] = (int)(uint) u1;
-					c = u2 + (u1 >> 32);
-				}
-
-				c += (ulong)(uint) w[--wBase];
-				w[wBase] = (int)(uint) c;
-
-				if (--wBase >= 0)
-				{
-					w[wBase] = (int)(uint)(c >> 32);
-				}
-				else
-				{
-					Debug.Assert((uint)(c >> 32) == 0);
-				}
-				wBase += i;
-			}
-
-			u1 = (ulong)(uint) x[0];
-			u1 = u1 * u1;
-			u2 = u1 >> 32;
-			u1 = u1 & IMASK;
-
-			u1 += (ulong)(uint) w[wBase];
-
-			w[wBase] = (int)(uint) u1;
-			if (--wBase >= 0)
-			{
-				w[wBase] = (int)(uint)(u2 + (u1 >> 32) + (ulong)(uint) w[wBase]);
-			}
-			else
-			{
-				Debug.Assert((uint)(u2 + (u1 >> 32)) == 0);
-			}
-
-			return w;
-		}
-
-		/**
-		 * return x with x = y * z - x is assumed to have enough space.
-		 */
-		private static int[] Multiply(
-			int[]	x,
-			int[]	y,
-			int[]	z)
-		{
-			int i = z.Length;
-
-			if (i < 1)
-				return x;
-
-			int xBase = x.Length - y.Length;
-
-			do
-			{
-				long a = z[--i] & IMASK;
-				long val = 0;
-
-				if (a != 0)
-				{
-					for (int j = y.Length - 1; j >= 0; j--)
-					{
-						val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK);
-	
-						x[xBase + j] = (int)val;
-	
-						val = (long)((ulong)val >> 32);
-					}
-				}
-
-				--xBase;
-
-				if (xBase >= 0)
-				{
-					x[xBase] = (int)val;
-				}
-				else
-				{
-					Debug.Assert(val == 0);
-				}
-			}
-			while (i > 0);
-
-			return x;
-		}
-
-		private static long FastExtEuclid(
-			long	a,
-			long	b,
-			long[]	uOut)
-		{
-			long u1 = 1;
-			long u3 = a;
-			long v1 = 0;
-			long v3 = b;
-
-			while (v3 > 0)
-			{
-				long q, tn;
-
-				q = u3 / v3;
-
-				tn = u1 - (v1 * q);
-				u1 = v1;
-				v1 = tn;
-
-				tn = u3 - (v3 * q);
-				u3 = v3;
-				v3 = tn;
-			}
-
-			uOut[0] = u1;
-			uOut[1] = (u3 - (u1 * a)) / b;
-
-			return u3;
-		}
-
-		private static long FastModInverse(
-			long	v,
-			long	m)
-		{
-			if (m < 1)
-				throw new ArithmeticException("Modulus must be positive");
-
-			long[] x = new long[2];
-			long gcd = FastExtEuclid(v, m, x);
-
-			if (gcd != 1)
-				throw new ArithmeticException("Numbers not relatively prime.");
-
-			if (x[0] < 0)
-			{
-				x[0] += m;
-			}
-
-			return x[0];
-		}
-
-//		private static BigInteger MQuoteB = One.ShiftLeft(32);
-//		private static BigInteger MQuoteBSub1 = MQuoteB.Subtract(One);
-
-		/**
-		 * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
-		 */
-		private long GetMQuote()
-		{
-			Debug.Assert(this.sign > 0);
-
-			if (mQuote != -1)
-			{
-				return mQuote; // already calculated
-			}
-
-			if (magnitude.Length == 0 || (magnitude[magnitude.Length - 1] & 1) == 0)
-			{
-				return -1; // not for even numbers
-			}
-
-			long v = (((~this.magnitude[this.magnitude.Length - 1]) | 1) & 0xffffffffL);
-			mQuote = FastModInverse(v, 0x100000000L);
-
-			return mQuote;
-		}
-
-		/**
-		 * Montgomery multiplication: a = x * y * R^(-1) mod m
-		 * <br/>
-		 * Based algorithm 14.36 of Handbook of Applied Cryptography.
-		 * <br/>
-		 * <li> m, x, y should have length n </li>
-		 * <li> a should have length (n + 1) </li>
-		 * <li> b = 2^32, R = b^n </li>
-		 * <br/>
-		 * The result is put in x
-		 * <br/>
-		 * NOTE: the indices of x, y, m, a different in HAC and in Java
-		 */
-		private static void MultiplyMonty(
-			int[]	a,
-			int[]	x,
-			int[]	y,
-			int[]	m,
-			long	mQuote)
-			// mQuote = -m^(-1) mod b
-		{
-			if (m.Length == 1)
-			{
-				x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], (ulong)mQuote);
-				return;
-			}
-
-			int n = m.Length;
-			int nMinus1 = n - 1;
-			long y_0 = y[nMinus1] & IMASK;
-
-			// 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} )
-			Array.Clear(a, 0, n + 1);
-
-			// 2. for i from 0 to (n - 1) do the following:
-			for (int i = n; i > 0; i--)
-			{
-				long x_i = x[i - 1] & IMASK;
-
-				// 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b
-				long u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK;
-
-				// 2.2 a = (a + x_i * y + u * m) / b
-				long prod1 = x_i * y_0;
-				long prod2 = u * (m[nMinus1] & IMASK);
-				long tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK);
-				long carry = (long)((ulong)prod1 >> 32) + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32);
-				for (int j = nMinus1; j > 0; j--)
-				{
-					prod1 = x_i * (y[j - 1] & IMASK);
-					prod2 = u * (m[j - 1] & IMASK);
-					tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK);
-					carry = (long)((ulong)carry >> 32) + (long)((ulong)prod1 >> 32) +
-						(long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32);
-					a[j + 1] = (int)tmp; // division by b
-				}
-				carry += (a[0] & IMASK);
-				a[1] = (int)carry;
-				a[0] = (int)((ulong)carry >> 32); // OJO!!!!!
-			}
-
-			// 3. if x >= m the x = x - m
-			if (CompareTo(0, a, 0, m) >= 0)
-			{
-				Subtract(0, a, 0, m);
-			}
-
-			// put the result in x
-			Array.Copy(a, 1, x, 0, n);
-		}
-
-		private static uint MultiplyMontyNIsOne(
-			uint	x,
-			uint	y,
-			uint	m,
-			ulong	mQuote)
-		{
-			ulong um = m;
-			ulong prod1 = (ulong)x * (ulong)y;
-			ulong u = (prod1 * mQuote) & UIMASK;
-			ulong prod2 = u * um;
-			ulong tmp = (prod1 & UIMASK) + (prod2 & UIMASK);
-			ulong carry = (prod1 >> 32) + (prod2 >> 32) + (tmp >> 32);
-
-			if (carry > um)
-			{
-				carry -= um;
-			}
-
-			return (uint)(carry & UIMASK);
-		}
-
-		public BigInteger Multiply(
-			BigInteger val)
-		{
-			if (sign == 0 || val.sign == 0)
-				return Zero;
-
-			if (val.QuickPow2Check()) // val is power of two
-			{
-				BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1);
-				return val.sign > 0 ? result : result.Negate();
-			}
-
-			if (this.QuickPow2Check()) // this is power of two
-			{
-				BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1);
-				return this.sign > 0 ? result : result.Negate();
-			}
-
-			int resLength = (this.BitLength + val.BitLength) / BitsPerInt + 1;
-			int[] res = new int[resLength];
-
-			if (val == this)
-			{
-				Square(res, this.magnitude);
-			}
-			else
-			{
-				Multiply(res, this.magnitude, val.magnitude);
-			}
-
-			return new BigInteger(sign * val.sign, res, true);
-		}
-
-		public BigInteger Negate()
-		{
-			if (sign == 0)
-				return this;
-
-			return new BigInteger(-sign, magnitude, false);
-		}
-
-		public BigInteger NextProbablePrime()
-		{
-			if (sign < 0)
-				throw new ArithmeticException("Cannot be called on value < 0");
-
-			if (CompareTo(Two) < 0)
-				return Two;
-
-			BigInteger n = Inc().SetBit(0);
-
-			while (!n.CheckProbablePrime(100, RandomSource))
-			{
-				n = n.Add(Two);
-			}
-
-			return n;
-		}
-
-		public BigInteger Not()
-		{
-			return Inc().Negate();
-		}
-
-		public BigInteger Pow(int exp)
-		{
-			if (exp < 0)
-			{
-				throw new ArithmeticException("Negative exponent");
-			}
-
-			if (exp == 0)
-			{
-				return One;
-			}
-
-			if (sign == 0 || Equals(One))
-			{
-				return this;
-			}
-
-			BigInteger y = One;
-			BigInteger z = this;
-
-			for (;;)
-			{
-				if ((exp & 0x1) == 1)
-				{
-					y = y.Multiply(z);
-				}
-				exp >>= 1;
-				if (exp == 0) break;
-				z = z.Multiply(z);
-			}
-
-			return y;
-		}
-
-		public static BigInteger ProbablePrime(
-			int bitLength,
-			Random random)
-		{
-			return new BigInteger(bitLength, 100, random);
-		}
-
-		private int Remainder(
-			int m)
-		{
-			Debug.Assert(m > 0);
-
-			long acc = 0;
-			for (int pos = 0; pos < magnitude.Length; ++pos)
-			{
-				long posVal = (uint) magnitude[pos];
-				acc = (acc << 32 | posVal) % m;
-			}
-
-			return (int) acc;
-		}
-
-		/**
-		 * return x = x % y - done in place (y value preserved)
-		 */
-		private int[] Remainder(
-			int[] x,
-			int[] y)
-		{
-			int xStart = 0;
-			while (xStart < x.Length && x[xStart] == 0)
-			{
-				++xStart;
-			}
-
-			int yStart = 0;
-			while (yStart < y.Length && y[yStart] == 0)
-			{
-				++yStart;
-			}
-
-			Debug.Assert(yStart < y.Length);
-
-			int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
-
-			if (xyCmp > 0)
-			{
-				int yBitLength = calcBitLength(yStart, y);
-				int xBitLength = calcBitLength(xStart, x);
-				int shift = xBitLength - yBitLength;
-
-				int[] c;
-				int cStart = 0;
-				int cBitLength = yBitLength;
-				if (shift > 0)
-				{
-					c = ShiftLeft(y, shift);
-					cBitLength += shift;
-					Debug.Assert(c[0] != 0);
-				}
-				else
-				{
-					int len = y.Length - yStart;
-					c = new int[len];
-					Array.Copy(y, yStart, c, 0, len);
-				}
-
-				for (;;)
-				{
-					if (cBitLength < xBitLength
-						|| CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
-					{
-						Subtract(xStart, x, cStart, c);
-
-						while (x[xStart] == 0)
-						{
-							if (++xStart == x.Length)
-								return x;
-						}
-
-						//xBitLength = calcBitLength(xStart, x);
-						xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
-
-						if (xBitLength <= yBitLength)
-						{
-							if (xBitLength < yBitLength)
-								return x;
-
-							xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
-
-							if (xyCmp <= 0)
-								break;
-						}
-					}
-
-					shift = cBitLength - xBitLength;
-
-					// NB: The case where c[cStart] is 1-bit is harmless
-					if (shift == 1)
-					{
-						uint firstC = (uint) c[cStart] >> 1;
-						uint firstX = (uint) x[xStart];
-						if (firstC > firstX)
-							++shift;
-					}
-
-					if (shift < 2)
-					{
-						ShiftRightOneInPlace(cStart, c);
-						--cBitLength;
-					}
-					else
-					{
-						ShiftRightInPlace(cStart, c, shift);
-						cBitLength -= shift;
-					}
-
-					//cStart = c.Length - ((cBitLength + 31) / 32);
-					while (c[cStart] == 0)
-					{
-						++cStart;
-					}
-				}
-			}
-
-			if (xyCmp == 0)
-			{
-				Array.Clear(x, xStart, x.Length - xStart);
-			}
-
-			return x;
-		}
-
-		public BigInteger Remainder(
-			BigInteger n)
-		{
-			if (n.sign == 0)
-				throw new ArithmeticException("Division by zero error");
-
-			if (this.sign == 0)
-				return Zero;
-
-			// For small values, use fast remainder method
-			if (n.magnitude.Length == 1)
-			{
-				int val = n.magnitude[0];
-
-				if (val > 0)
-				{
-					if (val == 1)
-						return Zero;
-
-					// TODO Make this func work on uint, and handle val == 1?
-					int rem = Remainder(val);
-
-					return rem == 0
-						?	Zero
-						:	new BigInteger(sign, new int[]{ rem }, false);
-				}
-			}
-
-			if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0)
-				return this;
-
-			int[] result;
-			if (n.QuickPow2Check())  // n is power of two
-			{
-				// TODO Move before small values branch above?
-				result = LastNBits(n.Abs().BitLength - 1);
-			}
-			else
-			{
-				result = (int[]) this.magnitude.Clone();
-				result = Remainder(result, n.magnitude);
-			}
-
-			return new BigInteger(sign, result, true);
-		}
-
-		private int[] LastNBits(
-			int n)
-		{
-			if (n < 1)
-				return ZeroMagnitude;
-
-			int numWords = (n + BitsPerInt - 1) / BitsPerInt;
-			numWords = System.Math.Min(numWords, this.magnitude.Length);
-			int[] result = new int[numWords];
-
-			Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords);
-
-			int hiBits = n % 32;
-			if (hiBits != 0)
-			{
-				result[0] &= ~(-1 << hiBits);
-			}
-
-			return result;
-		}
-
-		/**
-		 * do a left shift - this returns a new array.
-		 */
-		private static int[] ShiftLeft(
-			int[]	mag,
-			int		n)
-		{
-			int nInts = (int)((uint)n >> 5);
-			int nBits = n & 0x1f;
-			int magLen = mag.Length;
-			int[] newMag;
-
-			if (nBits == 0)
-			{
-				newMag = new int[magLen + nInts];
-				mag.CopyTo(newMag, 0);
-			}
-			else
-			{
-				int i = 0;
-				int nBits2 = 32 - nBits;
-				int highBits = (int)((uint)mag[0] >> nBits2);
-
-				if (highBits != 0)
-				{
-					newMag = new int[magLen + nInts + 1];
-					newMag[i++] = highBits;
-				}
-				else
-				{
-					newMag = new int[magLen + nInts];
-				}
-
-				int m = mag[0];
-				for (int j = 0; j < magLen - 1; j++)
-				{
-					int next = mag[j + 1];
-
-					newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2);
-					m = next;
-				}
-
-				newMag[i] = mag[magLen - 1] << nBits;
-			}
-
-			return newMag;
-		}
-
-		public BigInteger ShiftLeft(
-			int n)
-		{
-			if (sign == 0 || magnitude.Length == 0)
-				return Zero;
-
-			if (n == 0)
-				return this;
-
-			if (n < 0)
-				return ShiftRight(-n);
-
-			BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true);
-
-			if (this.nBits != -1)
-			{
-				result.nBits = sign > 0
-					?	this.nBits
-					:	this.nBits + n;
-			}
-
-			if (this.nBitLength != -1)
-			{
-				result.nBitLength = this.nBitLength + n;
-			}
-
-			return result;
-		}
-
-		/**
-		 * do a right shift - this does it in place.
-		 */
-		private static void ShiftRightInPlace(
-			int		start,
-			int[]	mag,
-			int		n)
-		{
-			int nInts = (int)((uint)n >> 5) + start;
-			int nBits = n & 0x1f;
-			int magEnd = mag.Length - 1;
-
-			if (nInts != start)
-			{
-				int delta = (nInts - start);
-
-				for (int i = magEnd; i >= nInts; i--)
-				{
-					mag[i] = mag[i - delta];
-				}
-				for (int i = nInts - 1; i >= start; i--)
-				{
-					mag[i] = 0;
-				}
-			}
-
-			if (nBits != 0)
-			{
-				int nBits2 = 32 - nBits;
-				int m = mag[magEnd];
-
-				for (int i = magEnd; i > nInts; --i)
-				{
-					int next = mag[i - 1];
-
-					mag[i] = (int)((uint)m >> nBits) | (next << nBits2);
-					m = next;
-				}
-
-				mag[nInts] = (int)((uint)mag[nInts] >> nBits);
-			}
-		}
-
-		/**
-		 * do a right shift by one - this does it in place.
-		 */
-		private static void ShiftRightOneInPlace(
-			int		start,
-			int[]	mag)
-		{
-			int i = mag.Length;
-			int m = mag[i - 1];
-
-			while (--i > start)
-			{
-				int next = mag[i - 1];
-				mag[i] = ((int)((uint)m >> 1)) | (next << 31);
-				m = next;
-			}
-
-			mag[start] = (int)((uint)mag[start] >> 1);
-		}
+            ulong c;
+
+            int wBase = w.Length - 1;
+
+            for (int i = x.Length - 1; i > 0; --i)
+            {
+                ulong v = (uint)x[i];
+
+                c = v * v + (uint)w[wBase];
+                w[wBase] = (int)c;
+                c >>= 32;
+
+                for (int j = i - 1; j >= 0; --j)
+                {
+                    ulong prod = v * (uint)x[j];
+
+                    c += ((uint)w[--wBase] & UIMASK) + ((uint)prod << 1);
+                    w[wBase] = (int)c;
+                    c = (c >> 32) + (prod >> 31);
+                }
+
+                c += (uint)w[--wBase];
+                w[wBase] = (int)c;
+
+                if (--wBase >= 0)
+                {
+                    w[wBase] = (int)(c >> 32);
+                }
+                else
+                {
+                    Debug.Assert((c >> 32) == 0);
+                }
+
+                wBase += i;
+            }
+
+            c = (uint)x[0];
+
+            c = c * c + (uint)w[wBase];
+            w[wBase] = (int)c;
+
+            if (--wBase >= 0)
+            {
+                w[wBase] += (int)(c >> 32);
+            }
+            else
+            {
+                Debug.Assert((c >> 32) == 0);
+            }
+
+            return w;
+        }
+
+        /**
+         * return x with x = y * z - x is assumed to have enough space.
+         */
+        private static int[] Multiply(int[]	x, int[] y, int[] z)
+        {
+            int i = z.Length;
+
+            if (i < 1)
+                return x;
+
+            int xBase = x.Length - y.Length;
+
+            do
+            {
+                long a = z[--i] & IMASK;
+                long val = 0;
+
+                if (a != 0)
+                {
+                    for (int j = y.Length - 1; j >= 0; j--)
+                    {
+                        val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK);
+    
+                        x[xBase + j] = (int)val;
+    
+                        val = (long)((ulong)val >> 32);
+                    }
+                }
+
+                --xBase;
+
+                if (xBase >= 0)
+                {
+                    x[xBase] = (int)val;
+                }
+                else
+                {
+                    Debug.Assert(val == 0);
+                }
+            }
+            while (i > 0);
+
+            return x;
+        }
+
+        /**
+         * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
+         */
+        private int GetMQuote()
+        {
+            if (mQuote != 0)
+            {
+                return mQuote; // already calculated
+            }
+
+            Debug.Assert(this.sign > 0);
+
+            int d = -magnitude[magnitude.Length - 1];
+
+            Debug.Assert((d & 1) != 0);
+
+            return mQuote = ModInverse32(d);
+        }
+
+        private static void MontgomeryReduce(int[] x, int[] m, uint mDash) // mDash = -m^(-1) mod b
+        {
+            // NOTE: Not a general purpose reduction (which would allow x up to twice the bitlength of m)
+            Debug.Assert(x.Length == m.Length);
+
+            int n = m.Length;
+
+            for (int i = n - 1; i >= 0; --i)
+            {
+                uint x0 = (uint)x[n - 1];
+                ulong t = x0 * mDash;
+
+                ulong carry = t * (uint)m[n - 1] + x0;
+                Debug.Assert((uint)carry == 0);
+                carry >>= 32;
+
+                for (int j = n - 2; j >= 0; --j)
+                {
+                    carry += t * (uint)m[j] + (uint)x[j];
+                    x[j + 1] = (int)carry;
+                    carry >>= 32;
+                }
+
+                x[0] = (int)carry;
+                Debug.Assert(carry >> 32 == 0);
+            }
+
+            if (CompareTo(0, x, 0, m) >= 0)
+            {
+                Subtract(0, x, 0, m);
+            }
+        }
+
+        /**
+         * Montgomery multiplication: a = x * y * R^(-1) mod m
+         * <br/>
+         * Based algorithm 14.36 of Handbook of Applied Cryptography.
+         * <br/>
+         * <li> m, x, y should have length n </li>
+         * <li> a should have length (n + 1) </li>
+         * <li> b = 2^32, R = b^n </li>
+         * <br/>
+         * The result is put in x
+         * <br/>
+         * NOTE: the indices of x, y, m, a different in HAC and in Java
+         */
+        private static void MultiplyMonty(int[]	a, int[] x, int[] y, int[] m, uint mDash, bool smallMontyModulus)
+            // mDash = -m^(-1) mod b
+        {
+            int n = m.Length;
+
+            if (n == 1)
+            {
+                x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], mDash);
+                return;
+            }
+
+            uint y0 = (uint)y[n - 1];
+            int aMax;
+
+            {
+                ulong xi = (uint)x[n - 1];
+
+                ulong carry = xi * y0;
+                ulong t = (uint)carry * mDash;
+
+                ulong prod2 = t * (uint)m[n - 1];
+                carry += (uint)prod2;
+                Debug.Assert((uint)carry == 0);
+                carry = (carry >> 32) + (prod2 >> 32);
+
+                for (int j = n - 2; j >= 0; --j)
+                {
+                    ulong prod1 = xi * (uint)y[j];
+                    prod2 = t * (uint)m[j];
+
+                    carry += (prod1 & UIMASK) + (uint)prod2;
+                    a[j + 2] = (int)carry;
+                    carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+                }
+
+                a[1] = (int)carry;
+                aMax = (int)(carry >> 32);
+            }
+
+            for (int i = n - 2; i >= 0; --i)
+            {
+                uint a0 = (uint)a[n];
+                ulong xi = (uint)x[i];
+
+                ulong prod1 = xi * y0;
+                ulong carry = (prod1 & UIMASK) + a0;
+                ulong t = (uint)carry * mDash;
+
+                ulong prod2 = t * (uint)m[n - 1];
+                carry += (uint)prod2;
+                Debug.Assert((uint)carry == 0);
+                carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+
+                for (int j = n - 2; j >= 0; --j)
+                {
+                    prod1 = xi * (uint)y[j];
+                    prod2 = t * (uint)m[j];
+
+                    carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[j + 1];
+                    a[j + 2] = (int)carry;
+                    carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+                }
+
+                carry += (uint)aMax;
+                a[1] = (int)carry;
+                aMax = (int)(carry >> 32);
+            }
+
+            a[0] = aMax;
+
+            if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0)
+            {
+                Subtract(0, a, 0, m);
+            }
+
+            Array.Copy(a, 1, x, 0, n);
+        }
+
+        private static void SquareMonty(int[] a, int[] x, int[] m, uint mDash, bool smallMontyModulus)
+            // mDash = -m^(-1) mod b
+        {
+            int n = m.Length;
+
+            if (n == 1)
+            {
+                uint xVal = (uint)x[0];
+                x[0] = (int)MultiplyMontyNIsOne(xVal, xVal, (uint)m[0], mDash);
+                return;
+            }
+
+            ulong x0 = (uint)x[n - 1];
+            int aMax;
+
+            {
+                ulong carry = x0 * x0;
+                ulong t = (uint)carry * mDash;
+
+                ulong prod2 = t * (uint)m[n - 1];
+                carry += (uint)prod2;
+                Debug.Assert((uint)carry == 0);
+                carry = (carry >> 32) + (prod2 >> 32);
+
+                for (int j = n - 2; j >= 0; --j)
+                {
+                    ulong prod1 = x0 * (uint)x[j];
+                    prod2 = t * (uint)m[j];
+
+                    carry += (prod2 & UIMASK) + ((uint)prod1 << 1);
+                    a[j + 2] = (int)carry;
+                    carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32);
+                }
+
+                a[1] = (int)carry;
+                aMax = (int)(carry >> 32);
+            }
+
+            for (int i = n - 2; i >= 0; --i)
+            {
+                uint a0 = (uint)a[n];
+                ulong t = a0 * mDash;
+
+                ulong carry = t * (uint)m[n - 1] + a0;
+                Debug.Assert((uint)carry == 0);
+                carry >>= 32;
+
+                for (int j = n - 2; j > i; --j)
+                {
+                    carry += t * (uint)m[j] + (uint)a[j + 1];
+                    a[j + 2] = (int)carry;
+                    carry >>= 32;
+                }
+
+                ulong xi = (uint)x[i];
+
+                {
+                    ulong prod1 = xi * xi;
+                    ulong prod2 = t * (uint)m[i];
+
+                    carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[i + 1];
+                    a[i + 2] = (int)carry;
+                    carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32);
+                }
+
+                for (int j = i - 1; j >= 0; --j)
+                {
+                    ulong prod1 = xi * (uint)x[j];
+                    ulong prod2 = t * (uint)m[j];
+
+                    carry += (prod2 & UIMASK) + ((uint)prod1 << 1) + (uint)a[j + 1];
+                    a[j + 2] = (int)carry;
+                    carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32);
+                }
+
+                carry += (uint)aMax;
+                a[1] = (int)carry;
+                aMax = (int)(carry >> 32);
+            }
+
+            a[0] = aMax;
+
+            if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0)
+            {
+                Subtract(0, a, 0, m);
+            }
+
+            Array.Copy(a, 1, x, 0, n);
+        }
+
+        private static uint MultiplyMontyNIsOne(uint x, uint y, uint m, uint mDash)
+        {
+            ulong carry = (ulong)x * y;
+            uint t = (uint)carry * mDash;
+            ulong um = m;
+            ulong prod2 = um * t;
+            carry += (uint)prod2;
+            Debug.Assert((uint)carry == 0);
+            carry = (carry >> 32) + (prod2 >> 32);
+            if (carry > um)
+            {
+                carry -= um;
+            }
+            Debug.Assert(carry < um);
+            return (uint)carry;
+        }
+
+        public BigInteger Multiply(
+            BigInteger val)
+        {
+            if (val == this)
+                return Square();
+
+            if ((sign & val.sign) == 0)
+                return Zero;
+
+            if (val.QuickPow2Check()) // val is power of two
+            {
+                BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1);
+                return val.sign > 0 ? result : result.Negate();
+            }
+
+            if (this.QuickPow2Check()) // this is power of two
+            {
+                BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1);
+                return this.sign > 0 ? result : result.Negate();
+            }
+
+            int resLength = magnitude.Length + val.magnitude.Length;
+            int[] res = new int[resLength];
+
+            Multiply(res, this.magnitude, val.magnitude);
+
+            int resSign = sign ^ val.sign ^ 1;
+            return new BigInteger(resSign, res, true);
+        }
+
+        public BigInteger Square()
+        {
+            if (sign == 0)
+                return Zero;
+            if (this.QuickPow2Check())
+                return ShiftLeft(Abs().BitLength - 1);
+            int resLength = magnitude.Length << 1;
+            if ((uint)magnitude[0] >> 16 == 0)
+                --resLength;
+            int[] res = new int[resLength];
+            Square(res, magnitude);
+            return new BigInteger(1, res, false);
+        }
+
+        public BigInteger Negate()
+        {
+            if (sign == 0)
+                return this;
+
+            return new BigInteger(-sign, magnitude, false);
+        }
+
+        public BigInteger NextProbablePrime()
+        {
+            if (sign < 0)
+                throw new ArithmeticException("Cannot be called on value < 0");
+
+            if (CompareTo(Two) < 0)
+                return Two;
+
+            BigInteger n = Inc().SetBit(0);
+
+            while (!n.CheckProbablePrime(100, RandomSource))
+            {
+                n = n.Add(Two);
+            }
+
+            return n;
+        }
+
+        public BigInteger Not()
+        {
+            return Inc().Negate();
+        }
+
+        public BigInteger Pow(int exp)
+        {
+            if (exp <= 0)
+            {
+                if (exp < 0)
+                    throw new ArithmeticException("Negative exponent");
+
+                return One;
+            }
+
+            if (sign == 0)
+            {
+                return this;
+            }
+
+            if (QuickPow2Check())
+            {
+                long powOf2 = (long)exp * (BitLength - 1);
+                if (powOf2 > Int32.MaxValue)
+                {
+                    throw new ArithmeticException("Result too large");
+                }
+                return One.ShiftLeft((int)powOf2); 
+            }
+
+            BigInteger y = One;
+            BigInteger z = this;
+
+            for (;;)
+            {
+                if ((exp & 0x1) == 1)
+                {
+                    y = y.Multiply(z);
+                }
+                exp >>= 1;
+                if (exp == 0) break;
+                z = z.Multiply(z);
+            }
+
+            return y;
+        }
+
+        public static BigInteger ProbablePrime(
+            int bitLength,
+            Random random)
+        {
+            return new BigInteger(bitLength, 100, random);
+        }
+
+        private int Remainder(
+            int m)
+        {
+            Debug.Assert(m > 0);
+
+            long acc = 0;
+            for (int pos = 0; pos < magnitude.Length; ++pos)
+            {
+                long posVal = (uint) magnitude[pos];
+                acc = (acc << 32 | posVal) % m;
+            }
+
+            return (int) acc;
+        }
+
+        /**
+         * return x = x % y - done in place (y value preserved)
+         */
+        private static int[] Remainder(
+            int[] x,
+            int[] y)
+        {
+            int xStart = 0;
+            while (xStart < x.Length && x[xStart] == 0)
+            {
+                ++xStart;
+            }
+
+            int yStart = 0;
+            while (yStart < y.Length && y[yStart] == 0)
+            {
+                ++yStart;
+            }
+
+            Debug.Assert(yStart < y.Length);
+
+            int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+            if (xyCmp > 0)
+            {
+                int yBitLength = CalcBitLength(1, yStart, y);
+                int xBitLength = CalcBitLength(1, xStart, x);
+                int shift = xBitLength - yBitLength;
+
+                int[] c;
+                int cStart = 0;
+                int cBitLength = yBitLength;
+                if (shift > 0)
+                {
+                    c = ShiftLeft(y, shift);
+                    cBitLength += shift;
+                    Debug.Assert(c[0] != 0);
+                }
+                else
+                {
+                    int len = y.Length - yStart;
+                    c = new int[len];
+                    Array.Copy(y, yStart, c, 0, len);
+                }
+
+                for (;;)
+                {
+                    if (cBitLength < xBitLength
+                        || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0)
+                    {
+                        Subtract(xStart, x, cStart, c);
+
+                        while (x[xStart] == 0)
+                        {
+                            if (++xStart == x.Length)
+                                return x;
+                        }
+
+                        //xBitLength = CalcBitLength(xStart, x);
+                        xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]);
+
+                        if (xBitLength <= yBitLength)
+                        {
+                            if (xBitLength < yBitLength)
+                                return x;
+
+                            xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y);
+
+                            if (xyCmp <= 0)
+                                break;
+                        }
+                    }
+
+                    shift = cBitLength - xBitLength;
+
+                    // NB: The case where c[cStart] is 1-bit is harmless
+                    if (shift == 1)
+                    {
+                        uint firstC = (uint) c[cStart] >> 1;
+                        uint firstX = (uint) x[xStart];
+                        if (firstC > firstX)
+                            ++shift;
+                    }
+
+                    if (shift < 2)
+                    {
+                        ShiftRightOneInPlace(cStart, c);
+                        --cBitLength;
+                    }
+                    else
+                    {
+                        ShiftRightInPlace(cStart, c, shift);
+                        cBitLength -= shift;
+                    }
+
+                    //cStart = c.Length - ((cBitLength + 31) / 32);
+                    while (c[cStart] == 0)
+                    {
+                        ++cStart;
+                    }
+                }
+            }
+
+            if (xyCmp == 0)
+            {
+                Array.Clear(x, xStart, x.Length - xStart);
+            }
+
+            return x;
+        }
+
+        public BigInteger Remainder(
+            BigInteger n)
+        {
+            if (n.sign == 0)
+                throw new ArithmeticException("Division by zero error");
+
+            if (this.sign == 0)
+                return Zero;
+
+            // For small values, use fast remainder method
+            if (n.magnitude.Length == 1)
+            {
+                int val = n.magnitude[0];
+
+                if (val > 0)
+                {
+                    if (val == 1)
+                        return Zero;
+
+                    // TODO Make this func work on uint, and handle val == 1?
+                    int rem = Remainder(val);
+
+                    return rem == 0
+                        ?	Zero
+                        :	new BigInteger(sign, new int[]{ rem }, false);
+                }
+            }
+
+            if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0)
+                return this;
+
+            int[] result;
+            if (n.QuickPow2Check())  // n is power of two
+            {
+                // TODO Move before small values branch above?
+                result = LastNBits(n.Abs().BitLength - 1);
+            }
+            else
+            {
+                result = (int[]) this.magnitude.Clone();
+                result = Remainder(result, n.magnitude);
+            }
+
+            return new BigInteger(sign, result, true);
+        }
+
+        private int[] LastNBits(
+            int n)
+        {
+            if (n < 1)
+                return ZeroMagnitude;
+
+            int numWords = (n + BitsPerInt - 1) / BitsPerInt;
+            numWords = System.Math.Min(numWords, this.magnitude.Length);
+            int[] result = new int[numWords];
+
+            Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords);
+
+            int excessBits = (numWords << 5) - n;
+            if (excessBits > 0)
+            {
+                result[0] &= (int)(UInt32.MaxValue >> excessBits);
+            }
+
+            return result;
+        }
+
+        private BigInteger DivideWords(int w)
+        {
+            Debug.Assert(w >= 0);
+            int n = magnitude.Length;
+            if (w >= n)
+                return Zero;
+            int[] mag = new int[n - w];
+            Array.Copy(magnitude, 0, mag, 0, n - w);
+            return new BigInteger(sign, mag, false);
+        }
+
+        private BigInteger RemainderWords(int w)
+        {
+            Debug.Assert(w >= 0);
+            int n = magnitude.Length;
+            if (w >= n)
+                return this;
+            int[] mag = new int[w];
+            Array.Copy(magnitude, n - w, mag, 0, w);
+            return new BigInteger(sign, mag, false);
+        }
+
+        /**
+         * do a left shift - this returns a new array.
+         */
+        private static int[] ShiftLeft(
+            int[]	mag,
+            int		n)
+        {
+            int nInts = (int)((uint)n >> 5);
+            int nBits = n & 0x1f;
+            int magLen = mag.Length;
+            int[] newMag;
+
+            if (nBits == 0)
+            {
+                newMag = new int[magLen + nInts];
+                mag.CopyTo(newMag, 0);
+            }
+            else
+            {
+                int i = 0;
+                int nBits2 = 32 - nBits;
+                int highBits = (int)((uint)mag[0] >> nBits2);
+
+                if (highBits != 0)
+                {
+                    newMag = new int[magLen + nInts + 1];
+                    newMag[i++] = highBits;
+                }
+                else
+                {
+                    newMag = new int[magLen + nInts];
+                }
+
+                int m = mag[0];
+                for (int j = 0; j < magLen - 1; j++)
+                {
+                    int next = mag[j + 1];
+
+                    newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2);
+                    m = next;
+                }
+
+                newMag[i] = mag[magLen - 1] << nBits;
+            }
+
+            return newMag;
+        }
+
+        private static int ShiftLeftOneInPlace(int[] x, int carry)
+        {
+            Debug.Assert(carry == 0 || carry == 1);
+            int pos = x.Length;
+            while (--pos >= 0)
+            {
+                uint val = (uint)x[pos];
+                x[pos] = (int)(val << 1) | carry;
+                carry = (int)(val >> 31);
+            }
+            return carry;
+        }
+
+        public BigInteger ShiftLeft(
+            int n)
+        {
+            if (sign == 0 || magnitude.Length == 0)
+                return Zero;
+
+            if (n == 0)
+                return this;
+
+            if (n < 0)
+                return ShiftRight(-n);
+
+            BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true);
+
+            if (this.nBits != -1)
+            {
+                result.nBits = sign > 0
+                    ?	this.nBits
+                    :	this.nBits + n;
+            }
+
+            if (this.nBitLength != -1)
+            {
+                result.nBitLength = this.nBitLength + n;
+            }
+
+            return result;
+        }
+
+        /**
+         * do a right shift - this does it in place.
+         */
+        private static void ShiftRightInPlace(
+            int		start,
+            int[]	mag,
+            int		n)
+        {
+            int nInts = (int)((uint)n >> 5) + start;
+            int nBits = n & 0x1f;
+            int magEnd = mag.Length - 1;
+
+            if (nInts != start)
+            {
+                int delta = (nInts - start);
+
+                for (int i = magEnd; i >= nInts; i--)
+                {
+                    mag[i] = mag[i - delta];
+                }
+                for (int i = nInts - 1; i >= start; i--)
+                {
+                    mag[i] = 0;
+                }
+            }
+
+            if (nBits != 0)
+            {
+                int nBits2 = 32 - nBits;
+                int m = mag[magEnd];
+
+                for (int i = magEnd; i > nInts; --i)
+                {
+                    int next = mag[i - 1];
+
+                    mag[i] = (int)((uint)m >> nBits) | (next << nBits2);
+                    m = next;
+                }
+
+                mag[nInts] = (int)((uint)mag[nInts] >> nBits);
+            }
+        }
+
+        /**
+         * do a right shift by one - this does it in place.
+         */
+        private static void ShiftRightOneInPlace(
+            int		start,
+            int[]	mag)
+        {
+            int i = mag.Length;
+            int m = mag[i - 1];
+
+            while (--i > start)
+            {
+                int next = mag[i - 1];
+                mag[i] = ((int)((uint)m >> 1)) | (next << 31);
+                m = next;
+            }
+
+            mag[start] = (int)((uint)mag[start] >> 1);
+        }
 
         public BigInteger ShiftRight(
-			int n)
-		{
-			if (n == 0)
-				return this;
+            int n)
+        {
+            if (n == 0)
+                return this;
 
-			if (n < 0)
-				return ShiftLeft(-n);
+            if (n < 0)
+                return ShiftLeft(-n);
 
-			if (n >= BitLength)
-				return (this.sign < 0 ? One.Negate() : Zero);
+            if (n >= BitLength)
+                return (this.sign < 0 ? One.Negate() : Zero);
 
 //			int[] res = (int[]) this.magnitude.Clone();
 //
@@ -2534,608 +2936,630 @@ namespace Org.BouncyCastle.Math
 //
 //			return new BigInteger(this.sign, res, true);
 
-			int resultLength = (BitLength - n + 31) >> 5;
-			int[] res = new int[resultLength];
-
-			int numInts = n >> 5;
-			int numBits = n & 31;
-
-			if (numBits == 0)
-			{
-				Array.Copy(this.magnitude, 0, res, 0, res.Length);
-			}
-			else
-			{
-				int numBits2 = 32 - numBits;
-
-				int magPos = this.magnitude.Length - 1 - numInts;
-				for (int i = resultLength - 1; i >= 0; --i)
-				{
-					res[i] = (int)((uint) this.magnitude[magPos--] >> numBits);
-
-					if (magPos >= 0)
-					{
-						res[i] |= this.magnitude[magPos] << numBits2;
-					}
-				}
-			}
-
-			Debug.Assert(res[0] != 0);
-
-			return new BigInteger(this.sign, res, false);
-		}
-
-		public int SignValue
-		{
-			get { return sign; }
-		}
-
-		/**
-		 * returns x = x - y - we assume x is >= y
-		 */
-		private static int[] Subtract(
-			int		xStart,
-			int[]	x,
-			int		yStart,
-			int[]	y)
-		{
-			Debug.Assert(yStart < y.Length);
-			Debug.Assert(x.Length - xStart >= y.Length - yStart);
-
-			int iT = x.Length;
-			int iV = y.Length;
-			long m;
-			int borrow = 0;
-
-			do
-			{
-				m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow;
-				x[iT] = (int) m;
+            int resultLength = (BitLength - n + 31) >> 5;
+            int[] res = new int[resultLength];
+
+            int numInts = n >> 5;
+            int numBits = n & 31;
+
+            if (numBits == 0)
+            {
+                Array.Copy(this.magnitude, 0, res, 0, res.Length);
+            }
+            else
+            {
+                int numBits2 = 32 - numBits;
+
+                int magPos = this.magnitude.Length - 1 - numInts;
+                for (int i = resultLength - 1; i >= 0; --i)
+                {
+                    res[i] = (int)((uint) this.magnitude[magPos--] >> numBits);
+
+                    if (magPos >= 0)
+                    {
+                        res[i] |= this.magnitude[magPos] << numBits2;
+                    }
+                }
+            }
+
+            Debug.Assert(res[0] != 0);
+
+            return new BigInteger(this.sign, res, false);
+        }
+
+        public int SignValue
+        {
+            get { return sign; }
+        }
+
+        /**
+         * returns x = x - y - we assume x is >= y
+         */
+        private static int[] Subtract(
+            int		xStart,
+            int[]	x,
+            int		yStart,
+            int[]	y)
+        {
+            Debug.Assert(yStart < y.Length);
+            Debug.Assert(x.Length - xStart >= y.Length - yStart);
+
+            int iT = x.Length;
+            int iV = y.Length;
+            long m;
+            int borrow = 0;
+
+            do
+            {
+                m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow;
+                x[iT] = (int) m;
 
 //				borrow = (m < 0) ? -1 : 0;
-				borrow = (int)(m >> 63);
-			}
-			while (iV > yStart);
-
-			if (borrow != 0)
-			{
-				while (--x[--iT] == -1)
-				{
-				}
-			}
-
-			return x;
-		}
-
-		public BigInteger Subtract(
-			BigInteger n)
-		{
-			if (n.sign == 0)
-				return this;
-
-			if (this.sign == 0)
-				return n.Negate();
-
-			if (this.sign != n.sign)
-				return Add(n.Negate());
-
-			int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude);
-			if (compare == 0)
-				return Zero;
-
-			BigInteger bigun, lilun;
-			if (compare < 0)
-			{
-				bigun = n;
-				lilun = this;
-			}
-			else
-			{
-				bigun = this;
-				lilun = n;
-			}
-
-			return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true);
-		}
-
-		private static int[] doSubBigLil(
-			int[]	bigMag,
-			int[]	lilMag)
-		{
-			int[] res = (int[]) bigMag.Clone();
-
-			return Subtract(0, res, 0, lilMag);
-		}
-
-		public byte[] ToByteArray()
-		{
-			return ToByteArray(false);
-		}
-
-		public byte[] ToByteArrayUnsigned()
-		{
-			return ToByteArray(true);
-		}
-
-		private byte[] ToByteArray(
-			bool unsigned)
-		{
-			if (sign == 0)
-				return unsigned ? ZeroEncoding : new byte[1];
-
-			int nBits = (unsigned && sign > 0)
-				?	BitLength
-				:	BitLength + 1;
-
-			int nBytes = GetByteLength(nBits);
-			byte[] bytes = new byte[nBytes];
-
-			int magIndex = magnitude.Length;
-			int bytesIndex = bytes.Length;
-
-			if (sign > 0)
-			{
-				while (magIndex > 1)
-				{
-					uint mag = (uint) magnitude[--magIndex];
-					bytes[--bytesIndex] = (byte) mag;
-					bytes[--bytesIndex] = (byte)(mag >> 8);
-					bytes[--bytesIndex] = (byte)(mag >> 16);
-					bytes[--bytesIndex] = (byte)(mag >> 24);
-				}
-
-				uint lastMag = (uint) magnitude[0];
-				while (lastMag > byte.MaxValue)
-				{
-					bytes[--bytesIndex] = (byte) lastMag;
-					lastMag >>= 8;
-				}
-
-				bytes[--bytesIndex] = (byte) lastMag;
-			}
-			else // sign < 0
-			{
-				bool carry = true;
-
-				while (magIndex > 1)
-				{
-					uint mag = ~((uint) magnitude[--magIndex]);
-
-					if (carry)
-					{
-						carry = (++mag == uint.MinValue);
-					}
-
-					bytes[--bytesIndex] = (byte) mag;
-					bytes[--bytesIndex] = (byte)(mag >> 8);
-					bytes[--bytesIndex] = (byte)(mag >> 16);
-					bytes[--bytesIndex] = (byte)(mag >> 24);
-				}
-
-				uint lastMag = (uint) magnitude[0];
-
-				if (carry)
-				{
-					// Never wraps because magnitude[0] != 0
-					--lastMag;
-				}
-
-				while (lastMag > byte.MaxValue)
-				{
-					bytes[--bytesIndex] = (byte) ~lastMag;
-					lastMag >>= 8;
-				}
-
-				bytes[--bytesIndex] = (byte) ~lastMag;
-
-				if (bytesIndex > 0)
-				{
-					bytes[--bytesIndex] = byte.MaxValue;
-				}
-			}
-
-			return bytes;
-		}
-
-		public override string ToString()
-		{
-			return ToString(10);
-		}
-
-		public string ToString(
-			int radix)
-		{
-			// TODO Make this method work for other radices (ideally 2 <= radix <= 16)
-
-			switch (radix)
-			{
-				case 2:
-				case 10:
-				case 16:
-					break;
-				default:
-					throw new FormatException("Only bases 2, 10, 16 are allowed");
-			}
-
-			// NB: Can only happen to internally managed instances
-			if (magnitude == null)
-				return "null";
-
-			if (sign == 0)
-				return "0";
-
-			Debug.Assert(magnitude.Length > 0);
-
-			StringBuilder sb = new StringBuilder();
-
-			if (radix == 16)
-			{
-				sb.Append(magnitude[0].ToString("x"));
-
-				for (int i = 1; i < magnitude.Length; i++)
-				{
-					sb.Append(magnitude[i].ToString("x8"));
-				}
-			}
-			else if (radix == 2)
-			{
-				sb.Append('1');
-
-				for (int i = BitLength - 2; i >= 0; --i)
-				{
-					sb.Append(TestBit(i) ? '1' : '0');
-				}
-			}
-			else
-			{
-				// This is algorithm 1a from chapter 4.4 in Seminumerical Algorithms, slow but it works
-				IList S = Platform.CreateArrayList();
-				BigInteger bs = ValueOf(radix);
-
-				// The sign is handled separatly.
-				// Notice however that for this to work, radix 16 _MUST_ be a special case,
-				// unless we want to enter a recursion well. In their infinite wisdom, why did not
-				// the Sun engineers made a c'tor for BigIntegers taking a BigInteger as parameter?
-				// (Answer: Becuase Sun's BigIntger is clonable, something bouncycastle's isn't.)
-//				BigInteger u = new BigInteger(Abs().ToString(16), 16);
-				BigInteger u = this.Abs();
-				BigInteger b;
-
-				while (u.sign != 0)
-				{
-					b = u.Mod(bs);
-					if (b.sign == 0)
-					{
-						S.Add("0");
-					}
-					else
-					{
-						// see how to interact with different bases
-						S.Add(b.magnitude[0].ToString("d"));
-					}
-					u = u.Divide(bs);
-				}
-
-				// Then pop the stack
+                borrow = (int)(m >> 63);
+            }
+            while (iV > yStart);
+
+            if (borrow != 0)
+            {
+                while (--x[--iT] == -1)
+                {
+                }
+            }
+
+            return x;
+        }
+
+        public BigInteger Subtract(
+            BigInteger n)
+        {
+            if (n.sign == 0)
+                return this;
+
+            if (this.sign == 0)
+                return n.Negate();
+
+            if (this.sign != n.sign)
+                return Add(n.Negate());
+
+            int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude);
+            if (compare == 0)
+                return Zero;
+
+            BigInteger bigun, lilun;
+            if (compare < 0)
+            {
+                bigun = n;
+                lilun = this;
+            }
+            else
+            {
+                bigun = this;
+                lilun = n;
+            }
+
+            return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true);
+        }
+
+        private static int[] doSubBigLil(
+            int[]	bigMag,
+            int[]	lilMag)
+        {
+            int[] res = (int[]) bigMag.Clone();
+
+            return Subtract(0, res, 0, lilMag);
+        }
+
+        public byte[] ToByteArray()
+        {
+            return ToByteArray(false);
+        }
+
+        public byte[] ToByteArrayUnsigned()
+        {
+            return ToByteArray(true);
+        }
+
+        private byte[] ToByteArray(
+            bool unsigned)
+        {
+            if (sign == 0)
+                return unsigned ? ZeroEncoding : new byte[1];
+
+            int nBits = (unsigned && sign > 0)
+                ?	BitLength
+                :	BitLength + 1;
+
+            int nBytes = GetByteLength(nBits);
+            byte[] bytes = new byte[nBytes];
+
+            int magIndex = magnitude.Length;
+            int bytesIndex = bytes.Length;
+
+            if (sign > 0)
+            {
+                while (magIndex > 1)
+                {
+                    uint mag = (uint) magnitude[--magIndex];
+                    bytes[--bytesIndex] = (byte) mag;
+                    bytes[--bytesIndex] = (byte)(mag >> 8);
+                    bytes[--bytesIndex] = (byte)(mag >> 16);
+                    bytes[--bytesIndex] = (byte)(mag >> 24);
+                }
+
+                uint lastMag = (uint) magnitude[0];
+                while (lastMag > byte.MaxValue)
+                {
+                    bytes[--bytesIndex] = (byte) lastMag;
+                    lastMag >>= 8;
+                }
+
+                bytes[--bytesIndex] = (byte) lastMag;
+            }
+            else // sign < 0
+            {
+                bool carry = true;
+
+                while (magIndex > 1)
+                {
+                    uint mag = ~((uint) magnitude[--magIndex]);
+
+                    if (carry)
+                    {
+                        carry = (++mag == uint.MinValue);
+                    }
+
+                    bytes[--bytesIndex] = (byte) mag;
+                    bytes[--bytesIndex] = (byte)(mag >> 8);
+                    bytes[--bytesIndex] = (byte)(mag >> 16);
+                    bytes[--bytesIndex] = (byte)(mag >> 24);
+                }
+
+                uint lastMag = (uint) magnitude[0];
+
+                if (carry)
+                {
+                    // Never wraps because magnitude[0] != 0
+                    --lastMag;
+                }
+
+                while (lastMag > byte.MaxValue)
+                {
+                    bytes[--bytesIndex] = (byte) ~lastMag;
+                    lastMag >>= 8;
+                }
+
+                bytes[--bytesIndex] = (byte) ~lastMag;
+
+                if (bytesIndex > 0)
+                {
+                    bytes[--bytesIndex] = byte.MaxValue;
+                }
+            }
+
+            return bytes;
+        }
+
+        public override string ToString()
+        {
+            return ToString(10);
+        }
+
+        public string ToString(int radix)
+        {
+            // TODO Make this method work for other radices (ideally 2 <= radix <= 36 as in Java)
+
+            switch (radix)
+            {
+                case 2:
+                case 8:
+                case 10:
+                case 16:
+                    break;
+                default:
+                    throw new FormatException("Only bases 2, 8, 10, 16 are allowed");
+            }
+
+            // NB: Can only happen to internally managed instances
+            if (magnitude == null)
+                return "null";
+
+            if (sign == 0)
+                return "0";
+
+
+            // NOTE: This *should* be unnecessary, since the magnitude *should* never have leading zero digits
+            int firstNonZero = 0;
+            while (firstNonZero < magnitude.Length)
+            {
+                if (magnitude[firstNonZero] != 0)
+                {
+                    break;
+                }
+                ++firstNonZero;
+            }
+
+            if (firstNonZero == magnitude.Length)
+            {
+                return "0";
+            }
+
+
+            StringBuilder sb = new StringBuilder();
+            if (sign == -1)
+            {
+                sb.Append('-');
+            }
+
+            switch (radix)
+            {
+            case 2:
+            {
+                int pos = firstNonZero;
+                sb.Append(Convert.ToString(magnitude[pos], 2));
+                while (++pos < magnitude.Length)
+                {
+                    AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 2), 32);
+                }
+                break;
+            }
+            case 8:
+            {
+                int mask = (1 << 30) - 1;
+                BigInteger u = this.Abs();
+                int bits = u.BitLength;
+                IList S = Platform.CreateArrayList();
+                while (bits > 30)
+                {
+                    S.Add(Convert.ToString(u.IntValue & mask, 8));
+                    u = u.ShiftRight(30);
+                    bits -= 30;
+                }
+                sb.Append(Convert.ToString(u.IntValue, 8));
                 for (int i = S.Count - 1; i >= 0; --i)
                 {
-                    sb.Append((string)S[i]);
+                    AppendZeroExtendedString(sb, (string)S[i], 10);
+                }
+                break;
+            }
+            case 16:
+            {
+                int pos = firstNonZero;
+                sb.Append(Convert.ToString(magnitude[pos], 16));
+                while (++pos < magnitude.Length)
+                {
+                    AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 16), 8);
+                }
+                break;
+            }
+            // TODO This could work for other radices if there is an alternative to Convert.ToString method
+            //default:
+            case 10:
+            {
+                BigInteger q = this.Abs();
+                if (q.BitLength < 64)
+                {
+                    sb.Append(Convert.ToString(q.LongValue, radix));
+                    break;
                 }
-			}
 
-			string s = sb.ToString();
+                // Based on algorithm 1a from chapter 4.4 in Seminumerical Algorithms (Knuth)
 
-			Debug.Assert(s.Length > 0);
+                // Work out the largest power of 'rdx' that is a positive 64-bit integer
+                // TODO possibly cache power/exponent against radix?
+                long limit = Int64.MaxValue / radix;
+                long power = radix;
+                int exponent = 1;
+                while (power <= limit)
+                {
+                    power *= radix;
+                    ++exponent;
+                }
 
-			// Strip leading zeros. (We know this number is not all zeroes though)
-			if (s[0] == '0')
-			{
-				int nonZeroPos = 0;
-				while (s[++nonZeroPos] == '0') {}
+                BigInteger bigPower = BigInteger.ValueOf(power);
 
-				s = s.Substring(nonZeroPos);
-			}
+                IList S = Platform.CreateArrayList();
+                while (q.CompareTo(bigPower) >= 0)
+                {
+                    BigInteger[] qr = q.DivideAndRemainder(bigPower);
+                    S.Add(Convert.ToString(qr[1].LongValue, radix));
+                    q = qr[0];
+                }
 
-			if (sign == -1)
-			{
-				s = "-" + s;
-			}
+                sb.Append(Convert.ToString(q.LongValue, radix));
+                for (int i = S.Count - 1; i >= 0; --i)
+                {
+                    AppendZeroExtendedString(sb, (string)S[i], exponent);
+                }
+                break;
+            }
+            }
+
+            return sb.ToString();
+        }
+
+        private static void AppendZeroExtendedString(StringBuilder sb, string s, int minLength)
+        {
+            for (int len = s.Length; len < minLength; ++len)
+            {
+                sb.Append('0');
+            }
+            sb.Append(s);
+        }
+
+        private static BigInteger CreateUValueOf(
+            ulong value)
+        {
+            int msw = (int)(value >> 32);
+            int lsw = (int)value;
+
+            if (msw != 0)
+                return new BigInteger(1, new int[] { msw, lsw }, false);
+
+            if (lsw != 0)
+            {
+                BigInteger n = new BigInteger(1, new int[] { lsw }, false);
+                // Check for a power of two
+                if ((lsw & -lsw) == lsw)
+                {
+                    n.nBits = 1;
+                }
+                return n;
+            }
+
+            return Zero;
+        }
+
+        private static BigInteger CreateValueOf(
+            long value)
+        {
+            if (value < 0)
+            {
+                if (value == long.MinValue)
+                    return CreateValueOf(~value).Not();
+
+                return CreateValueOf(-value).Negate();
+            }
+
+            return CreateUValueOf((ulong)value);
+        }
+
+        public static BigInteger ValueOf(
+            long value)
+        {
+            if (value >= 0 && value < SMALL_CONSTANTS.Length)
+            {
+                return SMALL_CONSTANTS[value];
+            }
+
+            return CreateValueOf(value);
+        }
+
+        public int GetLowestSetBit()
+        {
+            if (this.sign == 0)
+                return -1;
+
+            return GetLowestSetBitMaskFirst(-1);
+        }
+
+        private int GetLowestSetBitMaskFirst(int firstWordMask)
+        {
+            int w = magnitude.Length, offset = 0;
+
+            uint word = (uint)(magnitude[--w] & firstWordMask);
+            Debug.Assert(magnitude[0] != 0);
+
+            while (word == 0)
+            {
+                word = (uint)magnitude[--w];
+                offset += 32;
+            }
+
+            while ((word & 0xFF) == 0)
+            {
+                word >>= 8;
+                offset += 8;
+            }
+
+            while ((word & 1) == 0)
+            {
+                word >>= 1;
+                ++offset;
+            }
+
+            return offset;
+        }
+
+        public bool TestBit(
+            int n)
+        {
+            if (n < 0)
+                throw new ArithmeticException("Bit position must not be negative");
+
+            if (sign < 0)
+                return !Not().TestBit(n);
+
+            int wordNum = n / 32;
+            if (wordNum >= magnitude.Length)
+                return false;
+
+            int word = magnitude[magnitude.Length - 1 - wordNum];
+            return ((word >> (n % 32)) & 1) > 0;
+        }
+
+        public BigInteger Or(
+            BigInteger value)
+        {
+            if (this.sign == 0)
+                return value;
+
+            if (value.sign == 0)
+                return this;
+
+            int[] aMag = this.sign > 0
+                ? this.magnitude
+                : Add(One).magnitude;
+
+            int[] bMag = value.sign > 0
+                ? value.magnitude
+                : value.Add(One).magnitude;
+
+            bool resultNeg = sign < 0 || value.sign < 0;
+            int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+            int[] resultMag = new int[resultLength];
+
+            int aStart = resultMag.Length - aMag.Length;
+            int bStart = resultMag.Length - bMag.Length;
+
+            for (int i = 0; i < resultMag.Length; ++i)
+            {
+                int aWord = i >= aStart ? aMag[i - aStart] : 0;
+                int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+                if (this.sign < 0)
+                {
+                    aWord = ~aWord;
+                }
+
+                if (value.sign < 0)
+                {
+                    bWord = ~bWord;
+                }
+
+                resultMag[i] = aWord | bWord;
 
-			return s;
-		}
+                if (resultNeg)
+                {
+                    resultMag[i] = ~resultMag[i];
+                }
+            }
 
-		private static BigInteger createUValueOf(
-			ulong value)
-		{
-			int msw = (int)(value >> 32);
-			int lsw = (int)value;
+            BigInteger result = new BigInteger(1, resultMag, true);
 
-			if (msw != 0)
-				return new BigInteger(1, new int[] { msw, lsw }, false);
+            // TODO Optimise this case
+            if (resultNeg)
+            {
+                result = result.Not();
+            }
 
-			if (lsw != 0)
-			{
-				BigInteger n = new BigInteger(1, new int[] { lsw }, false);
-				// Check for a power of two
-				if ((lsw & -lsw) == lsw)
-				{
-					n.nBits = 1;
-				}
-				return n;
-			}
+            return result;
+        }
 
-			return Zero;
-		}
+        public BigInteger Xor(
+            BigInteger value)
+        {
+            if (this.sign == 0)
+                return value;
 
-		private static BigInteger createValueOf(
-			long value)
-		{
-			if (value < 0)
-			{
-				if (value == long.MinValue)
-					return createValueOf(~value).Not();
+            if (value.sign == 0)
+                return this;
 
-				return createValueOf(-value).Negate();
-			}
+            int[] aMag = this.sign > 0
+                ? this.magnitude
+                : Add(One).magnitude;
 
-			return createUValueOf((ulong)value);
+            int[] bMag = value.sign > 0
+                ? value.magnitude
+                : value.Add(One).magnitude;
 
-//			// store value into a byte array
-//			byte[] b = new byte[8];
-//			for (int i = 0; i < 8; i++)
-//			{
-//				b[7 - i] = (byte)value;
-//				value >>= 8;
-//			}
-//
-//			return new BigInteger(b);
-		}
-
-		public static BigInteger ValueOf(
-			long value)
-		{
-			switch (value)
-			{
-				case 0:
-					return Zero;
-				case 1:
-					return One;
-				case 2:
-					return Two;
-				case 3:
-					return Three;
-				case 10:
-					return Ten;
-			}
-
-			return createValueOf(value);
-		}
-
-		public int GetLowestSetBit()
-		{
-			if (this.sign == 0)
-				return -1;
-
-			int w = magnitude.Length;
-
-			while (--w > 0)
-			{
-				if (magnitude[w] != 0)
-					break;
-			}
-
-			int word = (int) magnitude[w];
-			Debug.Assert(word != 0);
-
-			int b = (word & 0x0000FFFF) == 0
-				?	(word & 0x00FF0000) == 0
-					?	7
-					:	15
-				:	(word & 0x000000FF) == 0
-					?	23
-					:	31;
-
-			while (b > 0)
-			{
-				if ((word << b) == int.MinValue)
-					break;
-
-				b--;
-			}
-
-			return ((magnitude.Length - w) * 32 - (b + 1));
-		}
-
-		public bool TestBit(
-			int n)
-		{
-			if (n < 0)
-				throw new ArithmeticException("Bit position must not be negative");
-
-			if (sign < 0)
-				return !Not().TestBit(n);
-
-			int wordNum = n / 32;
-			if (wordNum >= magnitude.Length)
-				return false;
-
-			int word = magnitude[magnitude.Length - 1 - wordNum];
-			return ((word >> (n % 32)) & 1) > 0;
-		}
-
-		public BigInteger Or(
-			BigInteger value)
-		{
-			if (this.sign == 0)
-				return value;
-
-			if (value.sign == 0)
-				return this;
-
-			int[] aMag = this.sign > 0
-				? this.magnitude
-				: Add(One).magnitude;
-
-			int[] bMag = value.sign > 0
-				? value.magnitude
-				: value.Add(One).magnitude;
-
-			bool resultNeg = sign < 0 || value.sign < 0;
-			int resultLength = System.Math.Max(aMag.Length, bMag.Length);
-			int[] resultMag = new int[resultLength];
-
-			int aStart = resultMag.Length - aMag.Length;
-			int bStart = resultMag.Length - bMag.Length;
-
-			for (int i = 0; i < resultMag.Length; ++i)
-			{
-				int aWord = i >= aStart ? aMag[i - aStart] : 0;
-				int bWord = i >= bStart ? bMag[i - bStart] : 0;
-
-				if (this.sign < 0)
-				{
-					aWord = ~aWord;
-				}
-
-				if (value.sign < 0)
-				{
-					bWord = ~bWord;
-				}
-
-				resultMag[i] = aWord | bWord;
-
-				if (resultNeg)
-				{
-					resultMag[i] = ~resultMag[i];
-				}
-			}
-
-			BigInteger result = new BigInteger(1, resultMag, true);
-
-			// TODO Optimise this case
-			if (resultNeg)
-			{
-				result = result.Not();
-			}
-
-			return result;
-		}
-
-		public BigInteger Xor(
-			BigInteger value)
-		{
-			if (this.sign == 0)
-				return value;
-
-			if (value.sign == 0)
-				return this;
-
-			int[] aMag = this.sign > 0
-				? this.magnitude
-				: Add(One).magnitude;
-
-			int[] bMag = value.sign > 0
-				? value.magnitude
-				: value.Add(One).magnitude;
-
-			// TODO Can just replace with sign != value.sign?
-			bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0);
-			int resultLength = System.Math.Max(aMag.Length, bMag.Length);
-			int[] resultMag = new int[resultLength];
-
-			int aStart = resultMag.Length - aMag.Length;
-			int bStart = resultMag.Length - bMag.Length;
-
-			for (int i = 0; i < resultMag.Length; ++i)
-			{
-				int aWord = i >= aStart ? aMag[i - aStart] : 0;
-				int bWord = i >= bStart ? bMag[i - bStart] : 0;
-
-				if (this.sign < 0)
-				{
-					aWord = ~aWord;
-				}
-
-				if (value.sign < 0)
-				{
-					bWord = ~bWord;
-				}
-
-				resultMag[i] = aWord ^ bWord;
-
-				if (resultNeg)
-				{
-					resultMag[i] = ~resultMag[i];
-				}
-			}
-
-			BigInteger result = new BigInteger(1, resultMag, true);
-
-			// TODO Optimise this case
-			if (resultNeg)
-			{
-				result = result.Not();
-			}
-
-			return result;
-		}
-
-		public BigInteger SetBit(
-			int n)
-		{
-			if (n < 0)
-				throw new ArithmeticException("Bit address less than zero");
-
-			if (TestBit(n))
-				return this;
-
-			// TODO Handle negative values and zero
-			if (sign > 0 && n < (BitLength - 1))
-				return FlipExistingBit(n);
-
-			return Or(One.ShiftLeft(n));
-		}
-
-		public BigInteger ClearBit(
-			int n)
-		{
-			if (n < 0)
-				throw new ArithmeticException("Bit address less than zero");
-
-			if (!TestBit(n))
-				return this;
-
-			// TODO Handle negative values
-			if (sign > 0 && n < (BitLength - 1))
-				return FlipExistingBit(n);
-
-			return AndNot(One.ShiftLeft(n));
-		}
-
-		public BigInteger FlipBit(
-			int n)
-		{
-			if (n < 0)
-				throw new ArithmeticException("Bit address less than zero");
-
-			// TODO Handle negative values and zero
-			if (sign > 0 && n < (BitLength - 1))
-				return FlipExistingBit(n);
-
-			return Xor(One.ShiftLeft(n));
-		}
-
-		private BigInteger FlipExistingBit(
-			int n)
-		{
-			Debug.Assert(sign > 0);
-			Debug.Assert(n >= 0);
-			Debug.Assert(n < BitLength - 1);
-
-			int[] mag = (int[]) this.magnitude.Clone();
-			mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit
-			//mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32));
-			return new BigInteger(this.sign, mag, false);
-		}
-	}
+            // TODO Can just replace with sign != value.sign?
+            bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0);
+            int resultLength = System.Math.Max(aMag.Length, bMag.Length);
+            int[] resultMag = new int[resultLength];
+
+            int aStart = resultMag.Length - aMag.Length;
+            int bStart = resultMag.Length - bMag.Length;
+
+            for (int i = 0; i < resultMag.Length; ++i)
+            {
+                int aWord = i >= aStart ? aMag[i - aStart] : 0;
+                int bWord = i >= bStart ? bMag[i - bStart] : 0;
+
+                if (this.sign < 0)
+                {
+                    aWord = ~aWord;
+                }
+
+                if (value.sign < 0)
+                {
+                    bWord = ~bWord;
+                }
+
+                resultMag[i] = aWord ^ bWord;
+
+                if (resultNeg)
+                {
+                    resultMag[i] = ~resultMag[i];
+                }
+            }
+
+            BigInteger result = new BigInteger(1, resultMag, true);
+
+            // TODO Optimise this case
+            if (resultNeg)
+            {
+                result = result.Not();
+            }
+
+            return result;
+        }
+
+        public BigInteger SetBit(
+            int n)
+        {
+            if (n < 0)
+                throw new ArithmeticException("Bit address less than zero");
+
+            if (TestBit(n))
+                return this;
+
+            // TODO Handle negative values and zero
+            if (sign > 0 && n < (BitLength - 1))
+                return FlipExistingBit(n);
+
+            return Or(One.ShiftLeft(n));
+        }
+
+        public BigInteger ClearBit(
+            int n)
+        {
+            if (n < 0)
+                throw new ArithmeticException("Bit address less than zero");
+
+            if (!TestBit(n))
+                return this;
+
+            // TODO Handle negative values
+            if (sign > 0 && n < (BitLength - 1))
+                return FlipExistingBit(n);
+
+            return AndNot(One.ShiftLeft(n));
+        }
+
+        public BigInteger FlipBit(
+            int n)
+        {
+            if (n < 0)
+                throw new ArithmeticException("Bit address less than zero");
+
+            // TODO Handle negative values and zero
+            if (sign > 0 && n < (BitLength - 1))
+                return FlipExistingBit(n);
+
+            return Xor(One.ShiftLeft(n));
+        }
+
+        private BigInteger FlipExistingBit(
+            int n)
+        {
+            Debug.Assert(sign > 0);
+            Debug.Assert(n >= 0);
+            Debug.Assert(n < BitLength - 1);
+
+            int[] mag = (int[]) this.magnitude.Clone();
+            mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit
+            //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32));
+            return new BigInteger(this.sign, mag, false);
+        }
+    }
 }
diff --git a/crypto/src/math/ec/ECAlgorithms.cs b/crypto/src/math/ec/ECAlgorithms.cs
index be4fd1b14..3c911b173 100644
--- a/crypto/src/math/ec/ECAlgorithms.cs
+++ b/crypto/src/math/ec/ECAlgorithms.cs
@@ -1,93 +1,459 @@
 using System;
 
-using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Math.Field;
 
 namespace Org.BouncyCastle.Math.EC
 {
-	public class ECAlgorithms
-	{
-		public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a,
-			ECPoint Q, BigInteger b)
-		{
-			ECCurve c = P.Curve;
-			if (!c.Equals(Q.Curve))
-				throw new ArgumentException("P and Q must be on same curve");
-
-			// Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
-			if (c is F2mCurve)
-			{
-				F2mCurve f2mCurve = (F2mCurve) 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)
-		*  
-		* 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
-		*/
-		public static ECPoint ShamirsTrick(
-			ECPoint		P,
-			BigInteger	k,
-			ECPoint		Q,
-			BigInteger	l)
-		{
-			if (!P.Curve.Equals(Q.Curve))
-				throw new ArgumentException("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 = System.Math.Max(k.BitLength, l.BitLength);
-			ECPoint Z = P.Add(Q);
-			ECPoint R = P.Curve.Infinity;
-
-			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;
-		}
-	}
+    public class ECAlgorithms
+    {
+        public static bool IsF2mCurve(ECCurve c)
+        {
+            IFiniteField field = c.Field;
+            return field.Dimension > 1 && field.Characteristic.Equals(BigInteger.Two)
+                && field is IPolynomialExtensionField;
+        }
+
+        public static bool IsFpCurve(ECCurve c)
+        {
+            return c.Field.Dimension == 1;
+        }
+
+        public static ECPoint SumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
+        {
+            if (ps == null || ks == null || ps.Length != ks.Length || ps.Length < 1)
+                throw new ArgumentException("point and scalar arrays should be non-null, and of equal, non-zero, length");
+
+            int count = ps.Length;
+            switch (count)
+            {
+                case 1:
+                    return ps[0].Multiply(ks[0]);
+                case 2:
+                    return SumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]);
+                default:
+                    break;
+            }
+
+            ECPoint p = ps[0];
+            ECCurve c = p.Curve;
+
+            ECPoint[] imported = new ECPoint[count];
+            imported[0] = p;
+            for (int i = 1; i < count; ++i)
+            {
+                imported[i] = ImportPoint(c, ps[i]);
+            }
+
+            GlvEndomorphism glvEndomorphism = c.GetEndomorphism() as GlvEndomorphism;
+            if (glvEndomorphism != null)
+            {
+                return ValidatePoint(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism));
+            }
+
+            return ValidatePoint(ImplSumOfMultiplies(imported, ks));
+        }
+
+        public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b)
+        {
+            ECCurve cp = P.Curve;
+            Q = ImportPoint(cp, Q);
+
+            // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+            if (cp is F2mCurve)
+            {
+                F2mCurve f2mCurve = (F2mCurve) cp;
+                if (f2mCurve.IsKoblitz)
+                {
+                    return ValidatePoint(P.Multiply(a).Add(Q.Multiply(b)));
+                }
+            }
+
+            GlvEndomorphism glvEndomorphism = cp.GetEndomorphism() as GlvEndomorphism;
+            if (glvEndomorphism != null)
+            {
+                return ValidatePoint(
+                    ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism));
+            }
+
+            return ValidatePoint(ImplShamirsTrickWNaf(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)
+        *  
+        * 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
+        */
+        public static ECPoint ShamirsTrick(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
+        {
+            ECCurve cp = P.Curve;
+            Q = ImportPoint(cp, Q);
+
+            return ValidatePoint(ImplShamirsTrickJsf(P, k, Q, l));
+        }
+
+        public static ECPoint ImportPoint(ECCurve c, ECPoint p)
+        {
+            ECCurve cp = p.Curve;
+            if (!c.Equals(cp))
+                throw new ArgumentException("Point must be on the same curve");
+
+            return c.ImportPoint(p);
+        }
+
+        public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len)
+        {
+            /*
+             * Uses the "Montgomery Trick" to invert many field elements, with only a single actual
+             * field inversion. See e.g. the paper:
+             * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick"
+             * by Katsuyuki Okeya, Kouichi Sakurai.
+             */
+
+            ECFieldElement[] c = new ECFieldElement[len];
+            c[0] = zs[off];
+
+            int i = 0;
+            while (++i < len)
+            {
+                c[i] = c[i - 1].Multiply(zs[off + i]);
+            }
+
+            ECFieldElement u = c[--i].Invert();
+
+            while (i > 0)
+            {
+                int j = off + i--;
+                ECFieldElement tmp = zs[j];
+                zs[j] = c[i].Multiply(u);
+                u = u.Multiply(tmp);
+            }
+
+            zs[off] = u;
+        }
+
+        /**
+         * Simple shift-and-add multiplication. Serves as reference implementation
+         * to verify (possibly faster) implementations, and for very small scalars.
+         * 
+         * @param p
+         *            The point to multiply.
+         * @param k
+         *            The multiplier.
+         * @return The result of the point multiplication <code>kP</code>.
+         */
+        public static ECPoint ReferenceMultiply(ECPoint p, BigInteger k)
+        {
+            BigInteger x = k.Abs();
+            ECPoint q = p.Curve.Infinity;
+            int t = x.BitLength;
+            if (t > 0)
+            {
+                if (x.TestBit(0))
+                {
+                    q = p;
+                }
+                for (int i = 1; i < t; i++)
+                {
+                    p = p.Twice();
+                    if (x.TestBit(i))
+                    {
+                        q = q.Add(p);
+                    }
+                }
+            }
+            return k.SignValue < 0 ? q.Negate() : q;
+        }
+
+        public static ECPoint ValidatePoint(ECPoint p)
+        {
+            if (!p.IsValid())
+                throw new ArgumentException("Invalid point", "p");
+
+            return p;
+        }
+
+        internal static ECPoint ImplShamirsTrickJsf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l)
+        {
+            ECCurve curve = P.Curve;
+            ECPoint infinity = curve.Infinity;
+
+            // TODO conjugate co-Z addition (ZADDC) can return both of these
+            ECPoint PaddQ = P.Add(Q);
+            ECPoint PsubQ = P.Subtract(Q);
+
+            ECPoint[] points = new ECPoint[] { Q, PsubQ, P, PaddQ };
+            curve.NormalizeAll(points);
+
+            ECPoint[] table = new ECPoint[] {
+            points[3].Negate(), points[2].Negate(), points[1].Negate(),
+            points[0].Negate(), infinity, points[0],
+            points[1], points[2], points[3] };
+
+            byte[] jsf = WNafUtilities.GenerateJsf(k, l);
+
+            ECPoint R = infinity;
+
+            int i = jsf.Length;
+            while (--i >= 0)
+            {
+                int jsfi = jsf[i];
+
+                // NOTE: The shifting ensures the sign is extended correctly
+                int kDigit = ((jsfi << 24) >> 28), lDigit = ((jsfi << 28) >> 28);
+
+                int index = 4 + (kDigit * 3) + lDigit;
+                R = R.TwicePlus(table[index]);
+            }
+
+            return R;
+        }
+
+        internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k,
+            ECPoint Q, BigInteger l)
+        {
+            bool negK = k.SignValue < 0, negL = l.SignValue < 0;
+
+            k = k.Abs();
+            l = l.Abs();
+
+            int widthP = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(k.BitLength)));
+            int widthQ = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(l.BitLength)));
+
+            WNafPreCompInfo infoP = WNafUtilities.Precompute(P, widthP, true);
+            WNafPreCompInfo infoQ = WNafUtilities.Precompute(Q, widthQ, true);
+
+            ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
+            ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
+            ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
+            ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
+
+            byte[] wnafP = WNafUtilities.GenerateWindowNaf(widthP, k);
+            byte[] wnafQ = WNafUtilities.GenerateWindowNaf(widthQ, l);
+
+            return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+        }
+
+        internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l)
+        {
+            bool negK = k.SignValue < 0, negL = l.SignValue < 0;
+
+            k = k.Abs();
+            l = l.Abs();
+
+            int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(k.BitLength, l.BitLength))));
+
+            ECPoint Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMapQ);
+            WNafPreCompInfo infoP = WNafUtilities.GetWNafPreCompInfo(P);
+            WNafPreCompInfo infoQ = WNafUtilities.GetWNafPreCompInfo(Q);
+
+            ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp;
+            ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp;
+            ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg;
+            ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg;
+
+            byte[] wnafP = WNafUtilities.GenerateWindowNaf(width, k);
+            byte[] wnafQ = WNafUtilities.GenerateWindowNaf(width, l);
+
+            return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ);
+        }
+
+        private static ECPoint ImplShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP,
+            ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ)
+        {
+            int len = System.Math.Max(wnafP.Length, wnafQ.Length);
+
+            ECCurve curve = preCompP[0].Curve;
+            ECPoint infinity = curve.Infinity;
+
+            ECPoint R = infinity;
+            int zeroes = 0;
+
+            for (int i = len - 1; i >= 0; --i)
+            {
+                int wiP = i < wnafP.Length ? (int)(sbyte)wnafP[i] : 0;
+                int wiQ = i < wnafQ.Length ? (int)(sbyte)wnafQ[i] : 0;
+
+                if ((wiP | wiQ) == 0)
+                {
+                    ++zeroes;
+                    continue;
+                }
+
+                ECPoint r = infinity;
+                if (wiP != 0)
+                {
+                    int nP = System.Math.Abs(wiP);
+                    ECPoint[] tableP = wiP < 0 ? preCompNegP : preCompP;
+                    r = r.Add(tableP[nP >> 1]);
+                }
+                if (wiQ != 0)
+                {
+                    int nQ = System.Math.Abs(wiQ);
+                    ECPoint[] tableQ = wiQ < 0 ? preCompNegQ : preCompQ;
+                    r = r.Add(tableQ[nQ >> 1]);
+                }
+
+                if (zeroes > 0)
+                {
+                    R = R.TimesPow2(zeroes);
+                    zeroes = 0;
+                }
+
+                R = R.TwicePlus(r);
+            }
+
+            if (zeroes > 0)
+            {
+                R = R.TimesPow2(zeroes);
+            }
+
+            return R;
+        }
+
+        internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, BigInteger[] ks)
+        {
+            int count = ps.Length;
+            bool[] negs = new bool[count];
+            WNafPreCompInfo[] infos = new WNafPreCompInfo[count];
+            byte[][] wnafs = new byte[count][];
+
+            for (int i = 0; i < count; ++i)
+            {
+                BigInteger ki = ks[i]; negs[i] = ki.SignValue < 0; ki = ki.Abs();
+
+                int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(ki.BitLength)));
+                infos[i] = WNafUtilities.Precompute(ps[i], width, true);
+                wnafs[i] = WNafUtilities.GenerateWindowNaf(width, ki);
+            }
+
+            return ImplSumOfMultiplies(negs, infos, wnafs);
+        }
+
+        internal static ECPoint ImplSumOfMultipliesGlv(ECPoint[] ps, BigInteger[] ks, GlvEndomorphism glvEndomorphism)
+        {
+            BigInteger n = ps[0].Curve.Order;
+
+            int len = ps.Length;
+
+            BigInteger[] abs = new BigInteger[len << 1];
+            for (int i = 0, j = 0; i < len; ++i)
+            {
+                BigInteger[] ab = glvEndomorphism.DecomposeScalar(ks[i].Mod(n));
+                abs[j++] = ab[0];
+                abs[j++] = ab[1];
+            }
+
+            ECPointMap pointMap = glvEndomorphism.PointMap;
+            if (glvEndomorphism.HasEfficientPointMap)
+            {
+                return ECAlgorithms.ImplSumOfMultiplies(ps, pointMap, abs);
+            }
+
+            ECPoint[] pqs = new ECPoint[len << 1];
+            for (int i = 0, j = 0; i < len; ++i)
+            {
+                ECPoint p = ps[i], q = pointMap.Map(p);
+                pqs[j++] = p;
+                pqs[j++] = q;
+            }
+
+            return ECAlgorithms.ImplSumOfMultiplies(pqs, abs);
+        }
+
+        internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks)
+        {
+            int halfCount = ps.Length, fullCount = halfCount << 1;
+
+            bool[] negs = new bool[fullCount];
+            WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount];
+            byte[][] wnafs = new byte[fullCount][];
+
+            for (int i = 0; i < halfCount; ++i)
+            {
+                int j0 = i << 1, j1 = j0 + 1;
+
+                BigInteger kj0 = ks[j0]; negs[j0] = kj0.SignValue < 0; kj0 = kj0.Abs();
+                BigInteger kj1 = ks[j1]; negs[j1] = kj1.SignValue < 0; kj1 = kj1.Abs();
+
+                int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(kj0.BitLength, kj1.BitLength))));
+
+                ECPoint P = ps[i], Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMap);
+                infos[j0] = WNafUtilities.GetWNafPreCompInfo(P);
+                infos[j1] = WNafUtilities.GetWNafPreCompInfo(Q);
+                wnafs[j0] = WNafUtilities.GenerateWindowNaf(width, kj0);
+                wnafs[j1] = WNafUtilities.GenerateWindowNaf(width, kj1);
+            }
+
+            return ImplSumOfMultiplies(negs, infos, wnafs);
+        }
+
+        private static ECPoint ImplSumOfMultiplies(bool[] negs, WNafPreCompInfo[] infos, byte[][] wnafs)
+        {
+            int len = 0, count = wnafs.Length;
+            for (int i = 0; i < count; ++i)
+            {
+                len = System.Math.Max(len, wnafs[i].Length);
+            }
+
+            ECCurve curve = infos[0].PreComp[0].Curve;
+            ECPoint infinity = curve.Infinity;
+
+            ECPoint R = infinity;
+            int zeroes = 0;
+
+            for (int i = len - 1; i >= 0; --i)
+            {
+                ECPoint r = infinity;
+
+                for (int j = 0; j < count; ++j)
+                {
+                    byte[] wnaf = wnafs[j];
+                    int wi = i < wnaf.Length ? (int)(sbyte)wnaf[i] : 0;
+                    if (wi != 0)
+                    {
+                        int n = System.Math.Abs(wi);
+                        WNafPreCompInfo info = infos[j];
+                        ECPoint[] table = (wi < 0 == negs[j]) ? info.PreComp : info.PreCompNeg;
+                        r = r.Add(table[n >> 1]);
+                    }
+                }
+
+                if (r == infinity)
+                {
+                    ++zeroes;
+                    continue;
+                }
+
+                if (zeroes > 0)
+                {
+                    R = R.TimesPow2(zeroes);
+                    zeroes = 0;
+                }
+
+                R = R.TwicePlus(r);
+            }
+
+            if (zeroes > 0)
+            {
+                R = R.TimesPow2(zeroes);
+            }
+
+            return R;
+        }
+    }
 }
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 4dd5e74e2..eaa3e0c3d 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -2,230 +2,635 @@ using System;
 using System.Collections;
 
 using Org.BouncyCastle.Math.EC.Abc;
+using Org.BouncyCastle.Math.EC.Endo;
+using Org.BouncyCastle.Math.EC.Multiplier;
+using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC
 {
-	/// <remarks>Base class for an elliptic curve.</remarks>
-	public abstract class ECCurve
-	{
-		internal ECFieldElement a, b;
-
-		public abstract int FieldSize { get; }
-		public abstract ECFieldElement FromBigInteger(BigInteger x);
-		public abstract ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression);
-		public abstract ECPoint DecodePoint(byte[] encoded);
-		public abstract ECPoint Infinity { get; }
-
-		public ECFieldElement A
-		{
-			get { return a; }
-		}
-
-		public ECFieldElement B
-		{
-			get { return b; }
-		}
-
-		public override bool Equals(
-			object obj)
-		{
-			if (obj == this)
-				return true;
-
-			ECCurve other = obj as ECCurve;
-
-			if (other == null)
-				return false;
-
-			return Equals(other);
-		}
-
-		protected bool Equals(
-			ECCurve other)
-		{
-			return a.Equals(other.a) && b.Equals(other.b);
-		}
-
-		public override int GetHashCode()
-		{
-			return a.GetHashCode() ^ b.GetHashCode();
-		}
-	}
-
-	public abstract class ECCurveBase : ECCurve
-	{
-		protected internal ECCurveBase()
-		{
-		}
-
-		protected internal abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
-
-		/**
-		 * 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 override ECPoint DecodePoint(
-			byte[] encoded)
-		{
-			ECPoint p = null;
-			int expectedLength = (FieldSize + 7) / 8;
-
-			switch (encoded[0])
-			{
-				case 0x00: // infinity
-				{
-					if (encoded.Length != 1)
-						throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
-
-					p = Infinity;
-					break;
-				}
-
-				case 0x02: // compressed
-				case 0x03: // compressed
-				{
-					if (encoded.Length != (expectedLength + 1))
-						throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
-
-					int yTilde = encoded[0] & 1;
-					BigInteger X1 = new BigInteger(1, encoded, 1, encoded.Length - 1);
-
-					p = DecompressPoint(yTilde, X1);
-					break;
-				}
-
-				case 0x04: // uncompressed
-				case 0x06: // hybrid
-				case 0x07: // hybrid
-				{
-					if (encoded.Length != (2 * expectedLength + 1))
-						throw new ArgumentException("Incorrect length for uncompressed/hybrid encoding", "encoded");
-
-					BigInteger X1 = new BigInteger(1, encoded, 1, expectedLength);
-					BigInteger Y1 = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
-
-					p = CreatePoint(X1, Y1, false);
-					break;
-				}
-
-				default:
-					throw new FormatException("Invalid point encoding " + encoded[0]);
-			}
-
-			return p;
-		}
-	}
-
-	/**
-     * Elliptic curve over Fp
-     */
-    public class FpCurve : ECCurveBase
+    /// <remarks>Base class for an elliptic curve.</remarks>
+    public abstract class ECCurve
     {
-        private readonly BigInteger q;
-		private readonly FpPoint infinity;
+        public const int COORD_AFFINE = 0;
+        public const int COORD_HOMOGENEOUS = 1;
+        public const int COORD_JACOBIAN = 2;
+        public const int COORD_JACOBIAN_CHUDNOVSKY = 3;
+        public const int COORD_JACOBIAN_MODIFIED = 4;
+        public const int COORD_LAMBDA_AFFINE = 5;
+        public const int COORD_LAMBDA_PROJECTIVE = 6;
+        public const int COORD_SKEWED = 7;
+
+        public static int[] GetAllCoordinateSystems()
+        {
+            return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY,
+                COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED };
+        }
 
-		public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+        public class Config
         {
-            this.q = q;
-            this.a = FromBigInteger(a);
-            this.b = FromBigInteger(b);
-			this.infinity = new FpPoint(this, null, null);
+            protected ECCurve outer;
+            protected int coord;
+            protected ECEndomorphism endomorphism;
+            protected ECMultiplier multiplier;
+
+            internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier)
+            {
+                this.outer = outer;
+                this.coord = coord;
+                this.endomorphism = endomorphism;
+                this.multiplier = multiplier;
+            }
+
+            public Config SetCoordinateSystem(int coord)
+            {
+                this.coord = coord;
+                return this;
+            }
+
+            public Config SetEndomorphism(ECEndomorphism endomorphism)
+            {
+                this.endomorphism = endomorphism;
+                return this;
+            }
+
+            public Config SetMultiplier(ECMultiplier multiplier)
+            {
+                this.multiplier = multiplier;
+                return this;
+            }
+
+            public ECCurve Create()
+            {
+                if (!outer.SupportsCoordinateSystem(coord))
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+
+                ECCurve c = outer.CloneCurve();
+                if (c == outer)
+                {
+                    throw new InvalidOperationException("implementation returned current curve");
+                }
+
+                c.m_coord = coord;
+                c.m_endomorphism = endomorphism;
+                c.m_multiplier = multiplier;
+
+                return c;
+            }
+        }
+
+        protected readonly IFiniteField m_field;
+        protected ECFieldElement m_a, m_b;
+        protected BigInteger m_order, m_cofactor;
+
+        protected int m_coord = COORD_AFFINE;
+        protected ECEndomorphism m_endomorphism = null;
+        protected ECMultiplier m_multiplier = null;
+
+        protected ECCurve(IFiniteField field)
+        {
+            this.m_field = field;
         }
 
-		public BigInteger Q
+        public abstract int FieldSize { get; }
+        public abstract ECFieldElement FromBigInteger(BigInteger x);
+
+        public virtual Config Configure()
         {
-			get { return q; }
+            return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier);
         }
 
-		public override ECPoint Infinity
-		{
-			get { return infinity; }
-		}
+        public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y)
+        {
+            ECPoint p = CreatePoint(x, y);
+            if (!p.IsValid())
+            {
+                throw new ArgumentException("Invalid point coordinates");
+            }
+            return p;
+        }
 
-		public override int FieldSize
-		{
-			get { return q.BitLength; }
-		}
+        [Obsolete("Per-point compression property will be removed")]
+        public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            ECPoint p = CreatePoint(x, y, withCompression);
+            if (!p.IsValid())
+            {
+                throw new ArgumentException("Invalid point coordinates");
+            }
+            return p;
+        }
 
-		public override ECFieldElement FromBigInteger(BigInteger x)
+        public virtual ECPoint CreatePoint(BigInteger x, BigInteger y)
         {
-            return new FpFieldElement(this.q, x);
+            return CreatePoint(x, y, false);
         }
 
-		public override ECPoint CreatePoint(
-			BigInteger	X1,
-			BigInteger	Y1,
-			bool		withCompression)
-		{
-			// TODO Validation of X1, Y1?
-			return new FpPoint(
-				this,
-				FromBigInteger(X1),
-				FromBigInteger(Y1),
-				withCompression);
-		}
+        [Obsolete("Per-point compression property will be removed")]
+        public virtual ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            return CreateRawPoint(FromBigInteger(x), FromBigInteger(y), withCompression);
+        }
 
-		protected internal override ECPoint DecompressPoint(
-			int			yTilde,
-			BigInteger	X1)
-		{
-			ECFieldElement x = FromBigInteger(X1);
-			ECFieldElement alpha = x.Multiply(x.Square().Add(a)).Add(b);
-			ECFieldElement beta = alpha.Sqrt();
+        protected abstract ECCurve CloneCurve();
 
-			//
-			// if we can't find a sqrt we haven't got a point on the
-			// curve - run!
-			//
-			if (beta == null)
-				throw new ArithmeticException("Invalid point compression");
+        protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression);
 
-			BigInteger betaValue = beta.ToBigInteger();
-			int bit0 = betaValue.TestBit(0) ? 1 : 0;
+        protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression);
 
-			if (bit0 != yTilde)
-			{
-				// Use the other root
-				beta = FromBigInteger(q.Subtract(betaValue));
-			}
+        protected virtual ECMultiplier CreateDefaultMultiplier()
+        {
+            GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism;
+            if (glvEndomorphism != null)
+            {
+                return new GlvMultiplier(this, glvEndomorphism);
+            }
 
-			return new FpPoint(this, x, beta, true);
-		}
+            return new WNafL2RMultiplier();
+        }
 
-		public override bool Equals(
-            object obj)
+        public virtual bool SupportsCoordinateSystem(int coord)
         {
-            if (obj == this)
-                return true;
+            return coord == COORD_AFFINE;
+        }
 
-			FpCurve other = obj as FpCurve;
+        public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name)
+        {
+            CheckPoint(point);
+            lock (point)
+            {
+                IDictionary table = point.m_preCompTable;
+                return table == null ? null : (PreCompInfo)table[name];
+            }
+        }
+
+        /**
+         * Adds <code>PreCompInfo</code> for a point on this curve, under a given name. Used by
+         * <code>ECMultiplier</code>s to save the precomputation for this <code>ECPoint</code> for use
+         * by subsequent multiplication.
+         * 
+         * @param point
+         *            The <code>ECPoint</code> to store precomputations for.
+         * @param name
+         *            A <code>String</code> used to index precomputations of different types.
+         * @param preCompInfo
+         *            The values precomputed by the <code>ECMultiplier</code>.
+         */
+        public virtual void SetPreCompInfo(ECPoint point, string name, PreCompInfo preCompInfo)
+        {
+            CheckPoint(point);
+            lock (point)
+            {
+                IDictionary table = point.m_preCompTable;
+                if (null == table)
+                {
+                    point.m_preCompTable = table = Platform.CreateHashtable(4);
+                }
+                table[name] = preCompInfo;
+            }
+        }
+
+        public virtual ECPoint ImportPoint(ECPoint p)
+        {
+            if (this == p.Curve)
+            {
+                return p;
+            }
+            if (p.IsInfinity)
+            {
+                return Infinity;
+            }
+
+            // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates.
+            p = p.Normalize();
+
+            return ValidatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed);
+        }
+
+        /**
+         * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+         * coordinates reflect those of the equivalent point in an affine coordinate system. Where more
+         * than one point is to be normalized, this method will generally be more efficient than
+         * normalizing each point separately.
+         * 
+         * @param points
+         *            An array of points that will be updated in place with their normalized versions,
+         *            where necessary
+         */
+        public virtual void NormalizeAll(ECPoint[] points)
+        {
+            CheckPoints(points);
+
+            if (this.CoordinateSystem == ECCurve.COORD_AFFINE)
+            {
+                return;
+            }
+
+            /*
+             * Figure out which of the points actually need to be normalized
+             */
+            ECFieldElement[] zs = new ECFieldElement[points.Length];
+            int[] indices = new int[points.Length];
+            int count = 0;
+            for (int i = 0; i < points.Length; ++i)
+            {
+                ECPoint p = points[i];
+                if (null != p && !p.IsNormalized())
+                {
+                    zs[count] = p.GetZCoord(0);
+                    indices[count++] = i;
+                }
+            }
+
+            if (count == 0)
+            {
+                return;
+            }
+
+            ECAlgorithms.MontgomeryTrick(zs, 0, count);
+
+            for (int j = 0; j < count; ++j)
+            {
+                int index = indices[j];
+                points[index] = points[index].Normalize(zs[j]);
+            }
+        }
+
+        public abstract ECPoint Infinity { get; }
+
+        public virtual IFiniteField Field
+        {
+            get { return m_field; }
+        }
+
+        public virtual ECFieldElement A
+        {
+            get { return m_a; }
+        }
 
-			if (other == null)
+        public virtual ECFieldElement B
+        {
+            get { return m_b; }
+        }
+
+        public virtual BigInteger Order
+        {
+            get { return m_order; }
+        }
+
+        public virtual BigInteger Cofactor
+        {
+            get { return m_cofactor; }
+        }
+
+        public virtual int CoordinateSystem
+        {
+            get { return m_coord; }
+        }
+
+        protected virtual void CheckPoint(ECPoint point)
+        {
+            if (null == point || (this != point.Curve))
+                throw new ArgumentException("must be non-null and on this curve", "point");
+        }
+
+        protected virtual void CheckPoints(ECPoint[] points)
+        {
+            if (points == null)
+                throw new ArgumentNullException("points");
+
+            for (int i = 0; i < points.Length; ++i)
+            {
+                ECPoint point = points[i];
+                if (null != point && this != point.Curve)
+                    throw new ArgumentException("entries must be null or on this curve", "points");
+            }
+        }
+
+        public virtual bool Equals(ECCurve other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
                 return false;
+            return Field.Equals(other.Field)
+                && A.ToBigInteger().Equals(other.A.ToBigInteger())
+                && B.ToBigInteger().Equals(other.B.ToBigInteger());
+        }
+
+        public override bool Equals(object obj) 
+        {
+            return Equals(obj as ECCurve);
+        }
+
+        public override int GetHashCode()
+        {
+            return Field.GetHashCode()
+                ^ Integers.RotateLeft(A.ToBigInteger().GetHashCode(), 8)
+                ^ Integers.RotateLeft(B.ToBigInteger().GetHashCode(), 16);
+        }
+
+        protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1);
+
+        public virtual ECEndomorphism GetEndomorphism()
+        {
+            return m_endomorphism;
+        }
+
+        /**
+         * Sets the default <code>ECMultiplier</code>, unless already set. 
+         */
+        public virtual ECMultiplier GetMultiplier()
+        {
+            lock (this)
+            {
+                if (this.m_multiplier == null)
+                {
+                    this.m_multiplier = CreateDefaultMultiplier();
+                }
+                return this.m_multiplier;
+            }
+        }
+
+        /**
+         * 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 virtual ECPoint DecodePoint(byte[] encoded)
+        {
+            ECPoint p = null;
+            int expectedLength = (FieldSize + 7) / 8;
+
+            byte type = encoded[0];
+            switch (type)
+            {
+                case 0x00: // infinity
+                {
+                    if (encoded.Length != 1)
+                        throw new ArgumentException("Incorrect length for infinity encoding", "encoded");
+
+                    p = Infinity;
+                    break;
+                }
+
+                case 0x02: // compressed
+                case 0x03: // compressed
+                {
+                    if (encoded.Length != (expectedLength + 1))
+                        throw new ArgumentException("Incorrect length for compressed encoding", "encoded");
+
+                    int yTilde = type & 1;
+                    BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+
+                    p = DecompressPoint(yTilde, X);
+                    if (!p.SatisfiesCofactor())
+                        throw new ArgumentException("Invalid point");
+
+                    break;
+                }
+
+                case 0x04: // uncompressed
+                {
+                    if (encoded.Length != (2 * expectedLength + 1))
+                        throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded");
+
+                    BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+                    BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+                    p = ValidatePoint(X, Y);
+                    break;
+                }
+
+                case 0x06: // hybrid
+                case 0x07: // hybrid
+                {
+                    if (encoded.Length != (2 * expectedLength + 1))
+                        throw new ArgumentException("Incorrect length for hybrid encoding", "encoded");
+
+                    BigInteger X = new BigInteger(1, encoded, 1, expectedLength);
+                    BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength);
+
+                    if (Y.TestBit(0) != (type == 0x07))
+                        throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded");
+
+                    p = ValidatePoint(X, Y);
+                    break;
+                }
+
+                default:
+                    throw new FormatException("Invalid point encoding " + type);
+            }
+
+            if (type != 0x00 && p.IsInfinity)
+                throw new ArgumentException("Invalid infinity encoding", "encoded");
 
-			return Equals(other);
+            return p;
         }
+    }
 
-		protected bool Equals(
-			FpCurve other)
-		{
-			return base.Equals(other) && q.Equals(other.q);
-		}
+    public abstract class AbstractFpCurve
+        : ECCurve
+    {
+        protected AbstractFpCurve(BigInteger q)
+            : base(FiniteFields.GetPrimeField(q))
+        {
+        }
 
-		public override int GetHashCode()
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
         {
-            return base.GetHashCode() ^ q.GetHashCode();
+            ECFieldElement x = FromBigInteger(X1);
+            ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B);
+            ECFieldElement y = rhs.Sqrt();
+
+            /*
+             * If y is not a square, then we haven't got a point on the curve
+             */
+            if (y == null)
+                throw new ArgumentException("Invalid point compression");
+
+            if (y.TestBitZero() != (yTilde == 1))
+            {
+                // Use the other root
+                y = y.Negate();
+            }
+
+            return CreateRawPoint(x, y, true);
         }
     }
 
-	/**
+    /**
+     * Elliptic curve over Fp
+     */
+    public class FpCurve
+        : AbstractFpCurve
+    {
+        private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+        protected readonly BigInteger m_q, m_r;
+        protected readonly FpPoint m_infinity;
+
+        public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+            : this(q, a, b, null, null)
+        {
+        }
+
+        public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor)
+            : base(q)
+        {
+            this.m_q = q;
+            this.m_r = FpFieldElement.CalculateResidue(q);
+            this.m_infinity = new FpPoint(this, null, null);
+
+            this.m_a = FromBigInteger(a);
+            this.m_b = FromBigInteger(b);
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+            this.m_coord = FP_DEFAULT_COORDS;
+        }
+
+        protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b)
+            : this(q, r, a, b, null, null)
+        {
+        }
+
+        protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+            : base(q)
+        {
+            this.m_q = q;
+            this.m_r = r;
+            this.m_infinity = new FpPoint(this, null, null);
+
+            this.m_a = a;
+            this.m_b = b;
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+            this.m_coord = FP_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor);
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_AFFINE:
+                case COORD_HOMOGENEOUS:
+                case COORD_JACOBIAN:
+                case COORD_JACOBIAN_MODIFIED:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return m_q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return m_q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new FpFieldElement(this.m_q, this.m_r, x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new FpPoint(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new FpPoint(this, x, y, zs, withCompression);
+        }
+
+        public override ECPoint ImportPoint(ECPoint p)
+        {
+            if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity)
+            {
+                switch (p.Curve.CoordinateSystem)
+                {
+                    case COORD_JACOBIAN:
+                    case COORD_JACOBIAN_CHUDNOVSKY:
+                    case COORD_JACOBIAN_MODIFIED:
+                        return new FpPoint(this,
+                            FromBigInteger(p.RawXCoord.ToBigInteger()),
+                            FromBigInteger(p.RawYCoord.ToBigInteger()),
+                            new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) },
+                            p.IsCompressed);
+                    default:
+                        break;
+                }
+            }
+
+            return base.ImportPoint(p);
+        }
+    }
+
+    public abstract class AbstractF2mCurve
+        : ECCurve
+    {
+        private static IFiniteField BuildField(int m, int k1, int k2, int k3)
+        {
+            if (k1 == 0)
+            {
+                throw new ArgumentException("k1 must be > 0");
+            }
+
+            if (k2 == 0)
+            {
+                if (k3 != 0)
+                {
+                    throw new ArgumentException("k3 must be 0 if k2 == 0");
+                }
+
+                return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m });
+            }
+
+            if (k2 <= k1)
+            {
+                throw new ArgumentException("k2 must be > k1");
+            }
+
+            if (k3 <= k2)
+            {
+                throw new ArgumentException("k3 must be > k2");
+            }
+
+            return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m });
+        }
+
+        protected AbstractF2mCurve(int m, int k1, int k2, int k3)
+            : base(BuildField(m, k1, k2, k3))
+        {
+        }
+    }
+
+    /**
      * 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 class F2mCurve : ECCurveBase
+    public class F2mCurve
+        : AbstractF2mCurve
     {
+        private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE;
+
         /**
          * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
          */
@@ -257,161 +662,152 @@ namespace Org.BouncyCastle.Math.EC
          */
         private readonly int k3;
 
-		/**
-		 * The order of the base point of the curve.
-		 */
-		private readonly BigInteger n;
-
-		/**
-		 * The cofactor of the curve.
-		 */
-		private readonly BigInteger h;
-
-		/**
-		 * The point at infinity on this curve.
-		 */
-		private readonly F2mPoint infinity;
-
-		/**
-		 * The parameter <code>&#956;</code> of the elliptic curve if this is
-		 * a Koblitz curve.
-		 */
-		private sbyte 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 F2mCurve(
-			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 F2mCurve(
-			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 F2mCurve(
-			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 F2mCurve(
-			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;
-			this.infinity = new F2mPoint(this, null, null);
-
-			if (k1 == 0)
+        /**
+         * The point at infinity on this curve.
+         */
+        protected readonly F2mPoint m_infinity;
+
+        /**
+         * The parameter <code>&#956;</code> of the elliptic curve if this is
+         * a Koblitz curve.
+         */
+        private sbyte 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 F2mCurve(
+            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 order The order of the main subgroup of the elliptic curve.
+         * @param cofactor The cofactor of the elliptic curve, i.e.
+         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+         */
+        public F2mCurve(
+            int			m, 
+            int			k, 
+            BigInteger	a, 
+            BigInteger	b,
+            BigInteger	order,
+            BigInteger	cofactor)
+            : this(m, k, 0, 0, a, b, order, cofactor)
+        {
+        }
+
+        /**
+         * 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 F2mCurve(
+            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 order The order of the main subgroup of the elliptic curve.
+         * @param cofactor The cofactor of the elliptic curve, i.e.
+         * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+         */
+        public F2mCurve(
+            int			m, 
+            int			k1, 
+            int			k2, 
+            int			k3,
+            BigInteger	a, 
+            BigInteger	b,
+            BigInteger	order,
+            BigInteger	cofactor)
+            : base(m, k1, k2, k3)
+        {
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+            this.m_infinity = new F2mPoint(this, null, null);
+
+            if (k1 == 0)
                 throw new ArgumentException("k1 must be > 0");
 
-			if (k2 == 0)
+            if (k2 == 0)
             {
                 if (k3 != 0)
                     throw new ArgumentException("k3 must be 0 if k2 == 0");
@@ -421,135 +817,212 @@ namespace Org.BouncyCastle.Math.EC
                 if (k2 <= k1)
                     throw new ArgumentException("k2 must be > k1");
 
-				if (k3 <= k2)
+                if (k3 <= k2)
                     throw new ArgumentException("k3 must be > k2");
             }
 
-			this.a = FromBigInteger(a);
-            this.b = FromBigInteger(b);
+            this.m_a = FromBigInteger(a);
+            this.m_b = FromBigInteger(b);
+            this.m_coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor)
+            : base(m, k1, k2, k3)
+        {
+            this.m = m;
+            this.k1 = k1;
+            this.k2 = k2;
+            this.k3 = k3;
+            this.m_order = order;
+            this.m_cofactor = cofactor;
+
+            this.m_infinity = new F2mPoint(this, null, null);
+            this.m_a = a;
+            this.m_b = b;
+            this.m_coord = F2M_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor);
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_AFFINE:
+                case COORD_HOMOGENEOUS:
+                case COORD_LAMBDA_PROJECTIVE:
+                    return true;
+                default:
+                    return false;
+            }
         }
 
-		public override ECPoint Infinity
-		{
-			get { return infinity; }
-		}
+        protected override ECMultiplier CreateDefaultMultiplier()
+        {
+            if (IsKoblitz)
+            {
+                return new WTauNafMultiplier();
+            }
 
-		public override int FieldSize
-		{
-			get { return m; }
-		}
+            return base.CreateDefaultMultiplier();
+        }
+
+        public override int FieldSize
+        {
+            get { return m; }
+        }
 
-		public override ECFieldElement FromBigInteger(BigInteger x)
+        public override ECFieldElement FromBigInteger(BigInteger x)
         {
             return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x);
         }
 
-		/**
-		 * Returns true if this is a Koblitz curve (ABC curve).
-		 * @return true if this is a Koblitz curve (ABC curve), false otherwise
-		 */
-		public bool IsKoblitz
-		{
-			get
-			{
-				return n != null && h != null
-					&& (a.ToBigInteger().Equals(BigInteger.Zero)
-						|| a.ToBigInteger().Equals(BigInteger.One))
-					&& b.ToBigInteger().Equals(BigInteger.One);
-			}
-		}
-
-		/**
-		 * Returns the parameter <code>&#956;</code> of the elliptic curve.
-		 * @return <code>&#956;</code> of the elliptic curve.
-		 * @throws ArgumentException if the given ECCurve is not a
-		 * Koblitz curve.
-		 */
-		internal sbyte GetMu()
-		{
-			if (mu == 0)
-			{
-				lock (this)
-				{
-					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.
-		 */
-		internal BigInteger[] GetSi()
-		{
-			if (si == null)
-			{
-				lock (this)
-				{
-					if (si == null)
-					{
-						si = Tnaf.GetSi(this);
-					}
-				}
-			}
-			return si;
-		}
-
-		public override ECPoint CreatePoint(
-			BigInteger	X1,
-			BigInteger	Y1,
-			bool		withCompression)
-		{
-			// TODO Validation of X1, Y1?
-			return new F2mPoint(
-				this,
-				FromBigInteger(X1),
-				FromBigInteger(Y1),
-				withCompression);
-		}
-
-		protected internal override ECPoint DecompressPoint(
-			int			yTilde,
-			BigInteger	X1)
-		{
-			ECFieldElement xp = FromBigInteger(X1);
-			ECFieldElement yp = null;
-			if (xp.ToBigInteger().SignValue == 0)
-			{
-				yp = (F2mFieldElement)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 ArithmeticException("Invalid point compression");
-
-				int zBit = z.ToBigInteger().TestBit(0) ? 1 : 0;
-				if (zBit != yTilde)
-				{
-					z = z.Add(FromBigInteger(BigInteger.One));
-				}
-
-				yp = xp.Multiply(z);
-			}
-
-			return new F2mPoint(this, xp, yp, true);
-		}
-
-		/**
+        [Obsolete("Per-point compression property will be removed")]
+        public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression)
+        {
+            ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y);
+
+            switch (this.CoordinateSystem)
+            {
+                case COORD_LAMBDA_AFFINE:
+                case COORD_LAMBDA_PROJECTIVE:
+                    {
+                        if (X.IsZero)
+                        {
+                            if (!Y.Square().Equals(B))
+                                throw new ArgumentException();
+                        }
+                        else
+                        {
+                            // Y becomes Lambda (X + Y/X) here
+                            Y = Y.Divide(X).Add(X);
+                        }
+                        break;
+                    }
+                default:
+                    {
+                        break;
+                    }
+            }
+
+            return CreateRawPoint(X, Y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new F2mPoint(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new F2mPoint(this, x, y, zs, withCompression);
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        /**
+         * Returns true if this is a Koblitz curve (ABC curve).
+         * @return true if this is a Koblitz curve (ABC curve), false otherwise
+         */
+        public virtual bool IsKoblitz
+        {
+            get
+            {
+                return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne);
+            }
+        }
+
+        /**
+         * Returns the parameter <code>&#956;</code> of the elliptic curve.
+         * @return <code>&#956;</code> of the elliptic curve.
+         * @throws ArgumentException if the given ECCurve is not a
+         * Koblitz curve.
+         */
+        internal virtual sbyte GetMu()
+        {
+            if (mu == 0)
+            {
+                lock (this)
+                {
+                    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.
+         */
+        internal virtual BigInteger[] GetSi()
+        {
+            if (si == null)
+            {
+                lock (this)
+                {
+                    if (si == null)
+                    {
+                        si = Tnaf.GetSi(this);
+                    }
+                }
+            }
+            return si;
+        }
+
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement xp = FromBigInteger(X1), yp = null;
+            if (xp.IsZero)
+            {
+                yp = m_b.Sqrt();
+            }
+            else
+            {
+                ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
+                ECFieldElement z = SolveQuadradicEquation(beta);
+
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                        case COORD_LAMBDA_AFFINE:
+                        case COORD_LAMBDA_PROJECTIVE:
+                        {
+                            yp = z.Add(xp);
+                            break;
+                        }
+                        default:
+                        {
+                            yp = z.Multiply(xp);
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if (yp == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return CreateRawPoint(xp, yp, true);
+        }
+
+        /**
          * 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>.
          *
@@ -558,72 +1031,47 @@ namespace Org.BouncyCastle.Math.EC
          * @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)
+        private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
         {
-            if (beta.ToBigInteger().SignValue == 0)
+            if (beta.IsZero)
             {
-                return FromBigInteger(BigInteger.Zero);
+                return beta;
             }
 
-			ECFieldElement z = null;
-            ECFieldElement gamma = FromBigInteger(BigInteger.Zero);
+            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
 
-			while (gamma.ToBigInteger().SignValue == 0)
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(m, new Random()));
-				z = FromBigInteger(BigInteger.Zero);
+            ECFieldElement z = null;
+            ECFieldElement gamma = null;
 
-				ECFieldElement w = beta;
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(m, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
                 for (int i = 1; i <= m - 1; i++)
                 {
-					ECFieldElement w2 = w.Square();
+                    ECFieldElement w2 = w.Square();
                     z = z.Square().Add(w2.Multiply(t));
                     w = w2.Add(beta);
                 }
-                if (w.ToBigInteger().SignValue != 0)
+                if (!w.IsZero)
                 {
                     return null;
                 }
                 gamma = z.Square().Add(z);
             }
-            return z;
-        }
-
-		public override bool Equals(
-            object obj)
-        {
-            if (obj == this)
-                return true;
-
-			F2mCurve other = obj as F2mCurve;
-
-			if (other == null)
-                return false;
-
-			return Equals(other);
-        }
+            while (gamma.IsZero);
 
-		protected bool Equals(
-			F2mCurve other)
-		{
-			return m == other.m
-				&& k1 == other.k1
-				&& k2 == other.k2
-				&& k3 == other.k3
-				&& base.Equals(other);
-		}
-
-		public override int GetHashCode()
-        {
-            return base.GetHashCode() ^ m ^ k1 ^ k2 ^ k3;
+            return z;
         }
 
-		public int M
+        public int M
         {
-			get { return m; }
+            get { return m; }
         }
 
-		/**
+        /**
          * Return true if curve uses a Trinomial basis.
          *
          * @return true if curve Trinomial, false otherwise.
@@ -633,29 +1081,31 @@ namespace Org.BouncyCastle.Math.EC
             return k2 == 0 && k3 == 0;
         }
 
-		public int K1
+        public int K1
         {
-			get { return k1; }
+            get { return k1; }
         }
 
-		public int K2
+        public int K2
         {
-			get { return k2; }
+            get { return k2; }
         }
 
-		public int K3
+        public int K3
         {
-			get { return k3; }
+            get { return k3; }
         }
 
-		public BigInteger N
-		{
-			get { return n; }
-		}
+        [Obsolete("Use 'Order' property instead")]
+        public BigInteger N
+        {
+            get { return m_order; }
+        }
 
-		public BigInteger H
-		{
-			get { return h; }
-		}
-	}
+        [Obsolete("Use 'Cofactor' property instead")]
+        public BigInteger H
+        {
+            get { return m_cofactor; }
+        }
+    }
 }
diff --git a/crypto/src/math/ec/ECFieldElement.cs b/crypto/src/math/ec/ECFieldElement.cs
index 5235c6c0e..e589fc737 100644
--- a/crypto/src/math/ec/ECFieldElement.cs
+++ b/crypto/src/math/ec/ECFieldElement.cs
@@ -5,1249 +5,913 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math.EC
 {
-	public abstract class ECFieldElement
-	{
-		public abstract BigInteger ToBigInteger();
-		public abstract string FieldName { get; }
-		public abstract int FieldSize { get; }
-		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 override bool Equals(
-			object obj)
-		{
-			if (obj == this)
-				return true;
-
-			ECFieldElement other = obj as ECFieldElement;
-
-			if (other == null)
-				return false;
-
-			return Equals(other);
-		}
-
-		protected bool Equals(
-			ECFieldElement other)
-		{
-			return ToBigInteger().Equals(other.ToBigInteger());
-		}
-
-		public override int GetHashCode()
-		{
-			return ToBigInteger().GetHashCode();
-		}
-
-		public override string ToString()
-		{
-			return this.ToBigInteger().ToString(2);
-		}
-	}
-
-	public class FpFieldElement
-		: ECFieldElement
-	{
-		private readonly BigInteger q, x;
-
-		public FpFieldElement(
-			BigInteger	q,
-			BigInteger	x)
-		{
-			if (x.CompareTo(q) >= 0)
-				throw new ArgumentException("x value too large in field element");
-
-			this.q = q;
-			this.x = x;
-		}
-
-		public override BigInteger ToBigInteger()
-		{
-			return x;
-		}
-
-		/**
-		 * return the field name for this field.
-		 *
-		 * @return the string "Fp".
-		 */
-		public override string FieldName
-		{
-			get { return "Fp"; }
-		}
-
-		public override int FieldSize
-		{
-			get { return q.BitLength; }
-		}
-
-		public BigInteger Q
-		{
-			get { return q; }
-		}
-
-		public override ECFieldElement Add(
-			ECFieldElement b)
-		{
-			return new FpFieldElement(q, x.Add(b.ToBigInteger()).Mod(q));
-		}
-
-		public override ECFieldElement Subtract(
-			ECFieldElement b)
-		{
-			return new FpFieldElement(q, x.Subtract(b.ToBigInteger()).Mod(q));
-		}
-
-		public override ECFieldElement Multiply(
-			ECFieldElement b)
-		{
-			return new FpFieldElement(q, x.Multiply(b.ToBigInteger()).Mod(q));
-		}
-
-		public override ECFieldElement Divide(
-			ECFieldElement b)
-		{
-			return new FpFieldElement(q, x.Multiply(b.ToBigInteger().ModInverse(q)).Mod(q));
-		}
-
-		public override ECFieldElement Negate()
-		{
-			return new FpFieldElement(q, x.Negate().Mod(q));
-		}
-
-		public override ECFieldElement Square()
-		{
-			return new FpFieldElement(q, x.Multiply(x).Mod(q));
-		}
-
-		public override ECFieldElement Invert()
-		{
-			return new FpFieldElement(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 override ECFieldElement Sqrt()
-		{
-			if (!q.TestBit(0))
-				throw Platform.CreateNotImplementedException("even value of q");
-
-			// p mod 4 == 3
-			if (q.TestBit(1))
-			{
-				// TODO Can this be optimised (inline the Square?)
-				// z = g^(u+1) + p, p = 4u + 3
-				ECFieldElement z = new FpFieldElement(q, x.ModPow(q.ShiftRight(2).Add(BigInteger.One), q));
-
-                return this.Equals(z.Square()) ? z : null;
-			}
-
-			// p mod 4 == 1
-			BigInteger qMinusOne = q.Subtract(BigInteger.One);
-
-			BigInteger legendreExponent = qMinusOne.ShiftRight(1);
-			if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One)))
-				return null;
-
-			BigInteger u = qMinusOne.ShiftRight(2);
-			BigInteger k = u.ShiftLeft(1).Add(BigInteger.One);
-
-			BigInteger Q = this.x;
-			BigInteger fourQ = Q.ShiftLeft(2).Mod(q);
-
-			BigInteger U, V;
-			do
-			{
-				Random rand = new Random();
-				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 = fastLucasSequence(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);
-
-					Debug.Assert(V.Multiply(V).Mod(q).Equals(x));
-
-					return new FpFieldElement(q, V);
-				}
-			}
-			while (U.Equals(BigInteger.One) || U.Equals(qMinusOne));
-
-			return null;
-
-
-//			BigInteger qMinusOne = q.Subtract(BigInteger.One);
-//
-//			BigInteger legendreExponent = qMinusOne.ShiftRight(1);
-//			if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.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);
-//			BigInteger n2 = n1.Add(BigInteger.One);
-//
-//			BigInteger wOne = WOne(r, x, q);
-//			BigInteger wSum = W(n1, wOne, q).Add(W(n2, wOne, q)).Mod(q);
-//			BigInteger twoR = r.ShiftLeft(1);
-//
-//			BigInteger root = twoR.ModPow(q.Subtract(BigInteger.Two), q)
-//				.Multiply(x).Mod(q)
-//				.Multiply(wSum).Mod(q);
-//
-//			return new FpFieldElement(q, root);
-		}
-
-//		private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p)
-//		{
-//			if (n.Equals(BigInteger.One))
-//				return wOne;
-//
-//			bool isEven = !n.TestBit(0);
-//			n = n.ShiftRight(1);
-//			if (isEven)
-//			{
-//				BigInteger w = W(n, wOne, p);
-//				return w.Multiply(w).Subtract(BigInteger.Two).Mod(p);
-//			}
-//			BigInteger w1 = W(n.Add(BigInteger.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(BigInteger.Two), q)).Subtract(BigInteger.Two).Mod(p);
-//		}
-
-		private static BigInteger[] fastLucasSequence(
-			BigInteger	p,
-			BigInteger	P,
-			BigInteger	Q,
-			BigInteger	k)
-		{
-			// TODO Research and apply "common-multiplicand multiplication here"
-
-			int n = k.BitLength;
-			int s = k.GetLowestSetBit();
-
-			Debug.Assert(k.TestBit(s));
-
-			BigInteger Uh = BigInteger.One;
-			BigInteger Vl = BigInteger.Two;
-			BigInteger Vh = P;
-			BigInteger Ql = BigInteger.One;
-			BigInteger Qh = BigInteger.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 };
-		}
-
-//		private static BigInteger[] verifyLucasSequence(
-//			BigInteger	p,
-//			BigInteger	P,
-//			BigInteger	Q,
-//			BigInteger	k)
-//		{
-//			BigInteger[] actual = fastLucasSequence(p, P, Q, k);
-//			BigInteger[] plus1 = fastLucasSequence(p, P, Q, k.Add(BigInteger.One));
-//			BigInteger[] plus2 = fastLucasSequence(p, P, Q, k.Add(BigInteger.Two));
-//
-//			BigInteger[] check = stepLucasSequence(p, P, Q, actual, plus1);
-//
-//			Debug.Assert(check[0].Equals(plus2[0]));
-//			Debug.Assert(check[1].Equals(plus2[1]));
-//
-//			return actual;
-//		}
-//
-//		private static BigInteger[] stepLucasSequence(
-//			BigInteger		p,
-//			BigInteger		P,
-//			BigInteger		Q,
-//			BigInteger[]	backTwo,
-//			BigInteger[]	backOne)
-//		{
-//			return new BigInteger[]
-//			{
-//				P.Multiply(backOne[0]).Subtract(Q.Multiply(backTwo[0])).Mod(p),
-//				P.Multiply(backOne[1]).Subtract(Q.Multiply(backTwo[1])).Mod(p)
-//			};
-//		}
-
-		public override bool Equals(
-			object obj)
-		{
-			if (obj == this)
-				return true;
-
-			FpFieldElement other = obj as FpFieldElement;
-
-			if (other == null)
-				return false;
-
-			return Equals(other);
-		}
-
-		protected bool Equals(
-			FpFieldElement other)
-		{
-			return q.Equals(other.q) && base.Equals(other);
-		}
-
-		public override int GetHashCode()
-		{
-			return q.GetHashCode() ^ base.GetHashCode();
-		}
-	}
-
-//	/**
-//	 * 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 class F2mFieldElement
-//		: ECFieldElement
-//	{
-//		/**
-//		 * Indicates gaussian normal basis representation (GNB). Number chosen
-//		 * according to X9.62. GNB is not implemented at present.
-//		 */
-//		public const int Gnb = 1;
-//
-//		/**
-//		 * Indicates trinomial basis representation (Tpb). Number chosen
-//		 * according to X9.62.
-//		 */
-//		public const int Tpb = 2;
-//
-//		/**
-//		 * Indicates pentanomial basis representation (Ppb). Number chosen
-//		 * according to X9.62.
-//		 */
-//		public const 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 F2mFieldElement(
-//			int			m,
-//			int			k1,
-//			int			k2,
-//			int			k3,
-//			BigInteger	x)
-//			: base(x)
-//		{
-//			if ((k2 == 0) && (k3 == 0))
-//			{
-//				this.representation = Tpb;
-//			}
-//			else
-//			{
-//				if (k2 >= k3)
-//					throw new ArgumentException("k2 must be smaller than k3");
-//				if (k2 <= 0)
-//					throw new ArgumentException("k2 must be larger than 0");
-//
-//				this.representation = Ppb;
-//			}
-//
-//			if (x.SignValue < 0)
-//				throw new ArgumentException("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 F2mFieldElement(
-//			int			m,
-//			int			k,
-//			BigInteger	x)
-//			: this(m, k, 0, 0, x)
-//		{
-//			// Set k1 to k, and set k2 and k3 to 0
-//		}
-//
-//		public override string FieldName
-//		{
-//			get { return "F2m"; }
-//		}
-//
-//		/**
-//		* 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 ArgumentException 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 is F2mFieldElement) || !(b is F2mFieldElement))
-//			{
-//				throw new ArgumentException("Field elements are not "
-//					+ "both instances of F2mFieldElement");
-//			}
-//
-//			if ((a.x.SignValue < 0) || (b.x.SignValue < 0))
-//			{
-//				throw new ArgumentException(
-//					"x value may not be negative");
-//			}
-//
-//			F2mFieldElement aF2m = (F2mFieldElement)a;
-//			F2mFieldElement bF2m = (F2mFieldElement)b;
-//
-//			if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
-//				|| (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
-//			{
-//				throw new ArgumentException("Field elements are not "
-//					+ "elements of the same field F2m");
-//			}
-//
-//			if (aF2m.representation != bF2m.representation)
-//			{
-//				// Should never occur
-//				throw new ArgumentException(
-//					"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(
-//			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 override ECFieldElement Add(
-//			ECFieldElement b)
-//		{
-//			// No check performed here for performance reasons. Instead the
-//			// elements involved are checked in ECPoint.F2m
-//			// checkFieldElements(this, b);
-//			if (b.x.SignValue == 0)
-//				return this;
-//
-//			return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, this.x.Xor(b.x));
-//		}
-//
-//		public override ECFieldElement Subtract(
-//			ECFieldElement b)
-//		{
-//			// Addition and subtraction are the same in F2m
-//			return Add(b);
-//		}
-//
-//		public override ECFieldElement Multiply(
-//			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);
-//			BigInteger az = this.x;
-//			BigInteger bz = b.x;
-//			BigInteger cz;
-//
-//			// Compute c(z) = a(z) * b(z) mod f(z)
-//			if (az.TestBit(0))
-//			{
-//				cz = bz;
-//			}
-//			else
-//			{
-//				cz = BigInteger.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 F2mFieldElement(m, this.k1, this.k2, this.k3, cz);
-//		}
-//
-//
-//		public override ECFieldElement Divide(
-//			ECFieldElement b)
-//		{
-//			// There may be more efficient implementations
-//			ECFieldElement bInv = b.Invert();
-//			return Multiply(bInv);
-//		}
-//
-//		public override ECFieldElement Negate()
-//		{
-//			// -x == x holds for all x in F2m
-//			return this;
-//		}
-//
-//		public override ECFieldElement Square()
-//		{
-//			// Naive implementation, can probably be speeded up using modular
-//			// reduction
-//			return Multiply(this);
-//		}
-//
-//		public override 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.SignValue <= 0)
-//			{
-//				throw new ArithmeticException("x is zero or negative, " +
-//					"inversion is impossible");
-//			}
-//
-//			// v(z) := f(z)
-//			BigInteger vz = BigInteger.One.ShiftLeft(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 = BigInteger.One;
-//			BigInteger g2z = BigInteger.Zero;
-//
-//			// while u != 1
-//			while (uz.SignValue != 0)
-//			{
-//				// 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)
-//				{
-//					BigInteger uzCopy = uz;
-//					uz = vz;
-//					vz = uzCopy;
-//
-//					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 F2mFieldElement(this.m, this.k1, this.k2, this.k3, g2z);
-//		}
-//
-//		public override ECFieldElement Sqrt()
-//		{
-//			throw new ArithmeticException("Not implemented");
-//		}
-//
-//		/**
-//			* @return the representation of the field
-//			* <code>F<sub>2<sup>m</sup></sub></code>, either of
-//			* {@link F2mFieldElement.Tpb} (trinomial
-//			* basis representation) or
-//			* {@link F2mFieldElement.Ppb} (pentanomial
-//			* basis representation).
-//			*/
-//		public int Representation
-//		{
-//			get { return this.representation; }
-//		}
-//
-//		/**
-//			* @return the degree <code>m</code> of the reduction polynomial
-//			* <code>f(z)</code>.
-//			*/
-//		public int M
-//		{
-//			get { 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 K1
-//		{
-//			get { 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 K2
-//		{
-//			get { 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 K3
-//		{
-//			get { return this.k3; }
-//		}
-//
-//		public override bool Equals(
-//			object obj)
-//		{
-//			if (obj == this)
-//				return true;
-//
-//			F2mFieldElement other = obj as F2mFieldElement;
-//
-//			if (other == null)
-//				return false;
-//
-//			return Equals(other);
-//		}
-//
-//		protected bool Equals(
-//			F2mFieldElement other)
-//		{
-//			return m == other.m
-//				&& k1 == other.k1
-//				&& k2 == other.k2
-//				&& k3 == other.k3
-//				&& representation == other.representation
-//				&& base.Equals(other);
-//		}
-//
-//		public override int GetHashCode()
-//		{
-//			return base.GetHashCode() ^ 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 class F2mFieldElement
-		: ECFieldElement
-	{
-		/**
-		 * Indicates gaussian normal basis representation (GNB). Number chosen
-		 * according to X9.62. GNB is not implemented at present.
-		 */
-		public const int Gnb = 1;
-
-		/**
-		 * Indicates trinomial basis representation (Tpb). Number chosen
-		 * according to X9.62.
-		 */
-		public const int Tpb = 2;
-
-		/**
-		 * Indicates pentanomial basis representation (Ppb). Number chosen
-		 * according to X9.62.
-		 */
-		public const 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 readonly 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 F2mFieldElement(
-			int			m,
-			int			k1,
-			int			k2,
-			int			k3,
-			BigInteger	x)
-		{
-			// t = m / 32 rounded up to the next integer
-			this.t = (m + 31) >> 5;
-			this.x = new IntArray(x, t);
-
-			if ((k2 == 0) && (k3 == 0))
-			{
-				this.representation = Tpb;
-			}
-			else
-			{
-				if (k2 >= k3)
-					throw new ArgumentException("k2 must be smaller than k3");
-				if (k2 <= 0)
-					throw new ArgumentException("k2 must be larger than 0");
-
-				this.representation = Ppb;
-			}
-
-			if (x.SignValue < 0)
-				throw new ArgumentException("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 F2mFieldElement(
-			int			m,
-			int			k,
-			BigInteger	x)
-			: this(m, k, 0, 0, x)
-		{
-			// Set k1 to k, and set k2 and k3 to 0
-		}
-
-		private F2mFieldElement(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 override BigInteger ToBigInteger()
-		{
-			return x.ToBigInteger();
-		}
-
-		public override string FieldName
-		{
-			get { return "F2m"; }
-		}
-
-		public override int FieldSize
-		{
-			get { 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 ArgumentException 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 is F2mFieldElement) || !(b is F2mFieldElement))
-			{
-				throw new ArgumentException("Field elements are not "
-					+ "both instances of F2mFieldElement");
-			}
-
-			F2mFieldElement aF2m = (F2mFieldElement)a;
-			F2mFieldElement bF2m = (F2mFieldElement)b;
-
-			if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1)
-				|| (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3))
-			{
-				throw new ArgumentException("Field elements are not "
-					+ "elements of the same field F2m");
-			}
-
-			if (aF2m.representation != bF2m.representation)
-			{
-				// Should never occur
-				throw new ArgumentException(
-					"One of the field "
-					+ "elements are not elements has incorrect representation");
-			}
-		}
-
-		public override ECFieldElement Add(
-			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.Copy();
-			F2mFieldElement bF2m = (F2mFieldElement) b;
-			iarrClone.AddShifted(bF2m.x, 0);
-			return new F2mFieldElement(m, k1, k2, k3, iarrClone);
-		}
-
-		public override ECFieldElement Subtract(
-			ECFieldElement b)
-		{
-			// Addition and subtraction are the same in F2m
-			return Add(b);
-		}
-
-		public override ECFieldElement Multiply(
-			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);
-			F2mFieldElement bF2m = (F2mFieldElement) b;
-			IntArray mult = x.Multiply(bF2m.x, m);
-			mult.Reduce(m, new int[]{k1, k2, k3});
-			return new F2mFieldElement(m, k1, k2, k3, mult);
-		}
-
-		public override ECFieldElement Divide(
-			ECFieldElement b)
-		{
-			// There may be more efficient implementations
-			ECFieldElement bInv = b.Invert();
-			return Multiply(bInv);
-		}
-
-		public override ECFieldElement Negate()
-		{
-			// -x == x holds for all x in F2m
-			return this;
-		}
-
-		public override ECFieldElement Square()
-		{
-			IntArray squared = x.Square(m);
-			squared.Reduce(m, new int[]{k1, k2, k3});
-			return new F2mFieldElement(m, k1, k2, k3, squared);
-		}
-
-		public override 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.Copy();
-
-			// 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.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)
-				{
-                    IntArray uzCopy = uz;
-					uz = vz;
-					vz = uzCopy;
-
-                    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 F2mFieldElement(this.m, this.k1, this.k2, this.k3, g2z);
-		}
-
-		public override ECFieldElement Sqrt()
-		{
-			throw new ArithmeticException("Not implemented");
-		}
-
-		/**
-			* @return the representation of the field
-			* <code>F<sub>2<sup>m</sup></sub></code>, either of
-			* {@link F2mFieldElement.Tpb} (trinomial
-			* basis representation) or
-			* {@link F2mFieldElement.Ppb} (pentanomial
-			* basis representation).
-			*/
-		public int Representation
-		{
-			get { return this.representation; }
-		}
-
-		/**
-			* @return the degree <code>m</code> of the reduction polynomial
-			* <code>f(z)</code>.
-			*/
-		public int M
-		{
-			get { 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 K1
-		{
-			get { 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 K2
-		{
-			get { 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 K3
-		{
-			get { return this.k3; }
-		}
-
-		public override bool Equals(
-			object obj)
-		{
-			if (obj == this)
-				return true;
-
-			F2mFieldElement other = obj as F2mFieldElement;
-
-			if (other == null)
-				return false;
-
-			return Equals(other);
-		}
-
-		protected bool Equals(
-			F2mFieldElement other)
-		{
-			return m == other.m
-				&& k1 == other.k1
-				&& k2 == other.k2
-				&& k3 == other.k3
-				&& representation == other.representation
-				&& base.Equals(other);
-		}
-
-		public override int GetHashCode()
-		{
-			return m.GetHashCode()
-				^	k1.GetHashCode()
-				^	k2.GetHashCode()
-				^	k3.GetHashCode()
-				^	representation.GetHashCode()
-				^	base.GetHashCode();
-		}
-	}
+    public abstract class ECFieldElement
+    {
+        public abstract BigInteger ToBigInteger();
+        public abstract string FieldName { get; }
+        public abstract int FieldSize { get; }
+        public abstract ECFieldElement Add(ECFieldElement b);
+        public abstract ECFieldElement AddOne();
+        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 virtual int BitLength
+        {
+            get { return ToBigInteger().BitLength; }
+        }
+
+        public virtual bool IsOne
+        {
+            get { return BitLength == 1; }
+        }
+
+        public virtual bool IsZero
+        {
+            get { return 0 == ToBigInteger().SignValue; }
+        }
+
+        public virtual ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return Multiply(b).Subtract(x.Multiply(y));
+        }
+
+        public virtual ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return Multiply(b).Add(x.Multiply(y));
+        }
+
+        public virtual ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return Square().Subtract(x.Multiply(y));
+        }
+
+        public virtual ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return Square().Add(x.Multiply(y));
+        }
+
+        public virtual bool TestBitZero()
+        {
+            return ToBigInteger().TestBit(0);
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as ECFieldElement);
+        }
+
+        public virtual bool Equals(ECFieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return ToBigInteger().Equals(other.ToBigInteger());
+        }
+
+        public override int GetHashCode()
+        {
+            return ToBigInteger().GetHashCode();
+        }
+
+        public override string ToString()
+        {
+            return this.ToBigInteger().ToString(16);
+        }
+
+        public virtual byte[] GetEncoded()
+        {
+            return BigIntegers.AsUnsignedByteArray((FieldSize + 7) / 8, ToBigInteger());
+        }
+    }
+
+    public class FpFieldElement
+        : ECFieldElement
+    {
+        private readonly BigInteger q, r, x;
+
+        internal static BigInteger CalculateResidue(BigInteger p)
+        {
+            int bitLength = p.BitLength;
+            if (bitLength >= 96)
+            {
+                BigInteger firstWord = p.ShiftRight(bitLength - 64);
+                if (firstWord.LongValue == -1L)
+                {
+                    return BigInteger.One.ShiftLeft(bitLength).Subtract(p);
+                }
+                if ((bitLength & 7) == 0)
+                {
+                    return BigInteger.One.ShiftLeft(bitLength << 1).Divide(p).Negate();
+                }
+            }
+            return null;
+        }
+
+        [Obsolete("Use ECCurve.FromBigInteger to construct field elements")]
+        public FpFieldElement(BigInteger q, BigInteger x)
+            : this(q, CalculateResidue(q), x)
+        {
+        }
+
+        internal FpFieldElement(BigInteger q, BigInteger r, BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(q) >= 0)
+                throw new ArgumentException("value invalid in Fp field element", "x");
+
+            this.q = q;
+            this.r = r;
+            this.x = x;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return x;
+        }
+
+        /**
+         * return the field name for this field.
+         *
+         * @return the string "Fp".
+         */
+        public override string FieldName
+        {
+            get { return "Fp"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECFieldElement Add(
+            ECFieldElement b)
+        {
+            return new FpFieldElement(q, r, ModAdd(x, b.ToBigInteger()));
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            BigInteger x2 = x.Add(BigInteger.One);
+            if (x2.CompareTo(q) == 0)
+            {
+                x2 = BigInteger.Zero;
+            }
+            return new FpFieldElement(q, r, x2);
+        }
+
+        public override ECFieldElement Subtract(
+            ECFieldElement b)
+        {
+            return new FpFieldElement(q, r, ModSubtract(x, b.ToBigInteger()));
+        }
+
+        public override ECFieldElement Multiply(
+            ECFieldElement b)
+        {
+            return new FpFieldElement(q, r, ModMult(x, b.ToBigInteger()));
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger();
+            BigInteger ab = ax.Multiply(bx);
+            BigInteger xy = xx.Multiply(yx);
+            return new FpFieldElement(q, r, ModReduce(ab.Subtract(xy)));
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger();
+            BigInteger ab = ax.Multiply(bx);
+            BigInteger xy = xx.Multiply(yx);
+            BigInteger sum = ab.Add(xy);
+            if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1))
+            {
+                sum = sum.Subtract(q.ShiftLeft(q.BitLength));
+            }
+            return new FpFieldElement(q, r, ModReduce(sum));
+        }
+
+        public override ECFieldElement Divide(
+            ECFieldElement b)
+        {
+            return new FpFieldElement(q, r, ModMult(x, ModInverse(b.ToBigInteger())));
+        }
+
+        public override ECFieldElement Negate()
+        {
+            return x.SignValue == 0 ? this : new FpFieldElement(q, r, q.Subtract(x));
+        }
+
+        public override ECFieldElement Square()
+        {
+            return new FpFieldElement(q, r, ModMult(x, x));
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger();
+            BigInteger aa = ax.Multiply(ax);
+            BigInteger xy = xx.Multiply(yx);
+            return new FpFieldElement(q, r, ModReduce(aa.Subtract(xy)));
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger();
+            BigInteger aa = ax.Multiply(ax);
+            BigInteger xy = xx.Multiply(yx);
+            BigInteger sum = aa.Add(xy);
+            if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1))
+            {
+                sum = sum.Subtract(q.ShiftLeft(q.BitLength));
+            }
+            return new FpFieldElement(q, r, ModReduce(sum));
+        }
+
+        public override ECFieldElement Invert()
+        {
+            // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime.
+            return new FpFieldElement(q, r, ModInverse(x));
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation
+         * returns the right value - if none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            if (IsZero || IsOne)
+                return this;
+
+            if (!q.TestBit(0))
+                throw Platform.CreateNotImplementedException("even value of q");
+
+            if (q.TestBit(1)) // q == 4m + 3
+            {
+                BigInteger e = q.ShiftRight(2).Add(BigInteger.One);
+                return CheckSqrt(new FpFieldElement(q, r, x.ModPow(e, q)));
+            }
+
+            if (q.TestBit(2)) // q == 8m + 5
+            {
+                BigInteger t1 = x.ModPow(q.ShiftRight(3), q);
+                BigInteger t2 = ModMult(t1, x);
+                BigInteger t3 = ModMult(t2, t1);
+
+                if (t3.Equals(BigInteger.One))
+                {
+                    return CheckSqrt(new FpFieldElement(q, r, t2));
+                }
+
+                // TODO This is constant and could be precomputed
+                BigInteger t4 = BigInteger.Two.ModPow(q.ShiftRight(2), q);
+
+                BigInteger y = ModMult(t2, t4);
+
+                return CheckSqrt(new FpFieldElement(q, r, y));
+            }
+
+            // q == 8m + 1
+
+            BigInteger legendreExponent = q.ShiftRight(1);
+            if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One)))
+                return null;
+
+            BigInteger X = this.x;
+            BigInteger fourX = ModDouble(ModDouble(X)); ;
+
+            BigInteger k = legendreExponent.Add(BigInteger.One), qMinusOne = q.Subtract(BigInteger.One);
+
+            BigInteger U, V;
+            Random rand = new Random();
+            do
+            {
+                BigInteger P;
+                do
+                {
+                    P = new BigInteger(q.BitLength, rand);
+                }
+                while (P.CompareTo(q) >= 0
+                    || !ModReduce(P.Multiply(P).Subtract(fourX)).ModPow(legendreExponent, q).Equals(qMinusOne));
+
+                BigInteger[] result = LucasSequence(P, X, k);
+                U = result[0];
+                V = result[1];
+
+                if (ModMult(V, V).Equals(fourX))
+                {
+                    return new FpFieldElement(q, r, ModHalfAbs(V));
+                }
+            }
+            while (U.Equals(BigInteger.One) || U.Equals(qMinusOne));
+
+            return null;
+        }
+
+        private ECFieldElement CheckSqrt(ECFieldElement z)
+        {
+            return z.Square().Equals(this) ? z : null;
+        }
+
+        private BigInteger[] LucasSequence(
+            BigInteger	P,
+            BigInteger	Q,
+            BigInteger	k)
+        {
+            // TODO Research and apply "common-multiplicand multiplication here"
+
+            int n = k.BitLength;
+            int s = k.GetLowestSetBit();
+
+            Debug.Assert(k.TestBit(s));
+
+            BigInteger Uh = BigInteger.One;
+            BigInteger Vl = BigInteger.Two;
+            BigInteger Vh = P;
+            BigInteger Ql = BigInteger.One;
+            BigInteger Qh = BigInteger.One;
+
+            for (int j = n - 1; j >= s + 1; --j)
+            {
+                Ql = ModMult(Ql, Qh);
+
+                if (k.TestBit(j))
+                {
+                    Qh = ModMult(Ql, Q);
+                    Uh = ModMult(Uh, Vh);
+                    Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
+                    Vh = ModReduce(Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1)));
+                }
+                else
+                {
+                    Qh = Ql;
+                    Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql));
+                    Vh = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
+                    Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
+                }
+            }
+
+            Ql = ModMult(Ql, Qh);
+            Qh = ModMult(Ql, Q);
+            Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql));
+            Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql)));
+            Ql = ModMult(Ql, Qh);
+
+            for (int j = 1; j <= s; ++j)
+            {
+                Uh = ModMult(Uh, Vl);
+                Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1)));
+                Ql = ModMult(Ql, Ql);
+            }
+
+            return new BigInteger[] { Uh, Vl };
+        }
+
+        protected virtual BigInteger ModAdd(BigInteger x1, BigInteger x2)
+        {
+            BigInteger x3 = x1.Add(x2);
+            if (x3.CompareTo(q) >= 0)
+            {
+                x3 = x3.Subtract(q);
+            }
+            return x3;
+        }
+
+        protected virtual BigInteger ModDouble(BigInteger x)
+        {
+            BigInteger _2x = x.ShiftLeft(1);
+            if (_2x.CompareTo(q) >= 0)
+            {
+                _2x = _2x.Subtract(q);
+            }
+            return _2x;
+        }
+
+        protected virtual BigInteger ModHalf(BigInteger x)
+        {
+            if (x.TestBit(0))
+            {
+                x = q.Add(x);
+            }
+            return x.ShiftRight(1);
+        }
+
+        protected virtual BigInteger ModHalfAbs(BigInteger x)
+        {
+            if (x.TestBit(0))
+            {
+                x = q.Subtract(x);
+            }
+            return x.ShiftRight(1);
+        }
+
+        protected virtual BigInteger ModInverse(BigInteger x)
+        {
+            int bits = FieldSize;
+            int len = (bits + 31) >> 5;
+            uint[] p = Nat.FromBigInteger(bits, q);
+            uint[] n = Nat.FromBigInteger(bits, x);
+            uint[] z = Nat.Create(len);
+            Mod.Invert(p, n, z);
+            return Nat.ToBigInteger(len, z);
+        }
+
+        protected virtual BigInteger ModMult(BigInteger x1, BigInteger x2)
+        {
+            return ModReduce(x1.Multiply(x2));
+        }
+
+        protected virtual BigInteger ModReduce(BigInteger x)
+        {
+            if (r == null)
+            {
+                x = x.Mod(q);
+            }
+            else
+            {
+                bool negative = x.SignValue < 0;
+                if (negative)
+                {
+                    x = x.Abs();
+                }
+                int qLen = q.BitLength;
+                if (r.SignValue > 0)
+                {
+                    BigInteger qMod = BigInteger.One.ShiftLeft(qLen);
+                    bool rIsOne = r.Equals(BigInteger.One);
+                    while (x.BitLength > (qLen + 1))
+                    {
+                        BigInteger u = x.ShiftRight(qLen);
+                        BigInteger v = x.Remainder(qMod);
+                        if (!rIsOne)
+                        {
+                            u = u.Multiply(r);
+                        }
+                        x = u.Add(v);
+                    }
+                }
+                else
+                {
+                    int d = ((qLen - 1) & 31) + 1;
+                    BigInteger mu = r.Negate();
+                    BigInteger u = mu.Multiply(x.ShiftRight(qLen - d));
+                    BigInteger quot = u.ShiftRight(qLen + d);
+                    BigInteger v = quot.Multiply(q);
+                    BigInteger bk1 = BigInteger.One.ShiftLeft(qLen + d);
+                    v = v.Remainder(bk1);
+                    x = x.Remainder(bk1);
+                    x = x.Subtract(v);
+                    if (x.SignValue < 0)
+                    {
+                        x = x.Add(bk1);
+                    }
+                }
+                while (x.CompareTo(q) >= 0)
+                {
+                    x = x.Subtract(q);
+                }
+                if (negative && x.SignValue != 0)
+                {
+                    x = q.Subtract(x);
+                }
+            }
+            return x;
+        }
+
+        protected virtual BigInteger ModSubtract(BigInteger x1, BigInteger x2)
+        {
+            BigInteger x3 = x1.Subtract(x2);
+            if (x3.SignValue < 0)
+            {
+                x3 = x3.Add(q);
+            }
+            return x3;
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+            FpFieldElement other = obj as FpFieldElement;
+
+            if (other == null)
+                return false;
+
+            return Equals(other);
+        }
+
+        public virtual bool Equals(
+            FpFieldElement other)
+        {
+            return q.Equals(other.q) && base.Equals(other);
+        }
+
+        public override int GetHashCode()
+        {
+            return q.GetHashCode() ^ base.GetHashCode();
+        }
+    }
+
+    /**
+     * 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 class F2mFieldElement
+        : ECFieldElement
+    {
+        /**
+         * Indicates gaussian normal basis representation (GNB). Number chosen
+         * according to X9.62. GNB is not implemented at present.
+         */
+        public const int Gnb = 1;
+
+        /**
+         * Indicates trinomial basis representation (Tpb). Number chosen
+         * according to X9.62.
+         */
+        public const int Tpb = 2;
+
+        /**
+         * Indicates pentanomial basis representation (Ppb). Number chosen
+         * according to X9.62.
+         */
+        public const 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;
+
+        private int[] ks;
+
+        /**
+         * The <code>LongArray</code> holding the bits.
+         */
+        private LongArray x;
+
+        /**
+            * 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 F2mFieldElement(
+            int			m,
+            int			k1,
+            int			k2,
+            int			k3,
+            BigInteger	x)
+        {
+            if ((k2 == 0) && (k3 == 0))
+            {
+                this.representation = Tpb;
+                this.ks = new int[] { k1 };
+            }
+            else
+            {
+                if (k2 >= k3)
+                    throw new ArgumentException("k2 must be smaller than k3");
+                if (k2 <= 0)
+                    throw new ArgumentException("k2 must be larger than 0");
+
+                this.representation = Ppb;
+                this.ks = new int[] { k1, k2, k3 };
+            }
+
+            this.m = m;
+            this.x = new LongArray(x);
+        }
+
+        /**
+            * 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 F2mFieldElement(
+            int			m,
+            int			k,
+            BigInteger	x)
+            : this(m, k, 0, 0, x)
+        {
+            // Set k1 to k, and set k2 and k3 to 0
+        }
+
+        private F2mFieldElement(int m, int[] ks, LongArray x)
+        {
+            this.m = m;
+            this.representation = (ks.Length == 1) ? Tpb : Ppb;
+            this.ks = ks;
+            this.x = x;
+        }
+
+        public override int BitLength
+        {
+            get { return x.Degree(); }
+        }
+
+        public override bool IsOne
+        {
+            get { return x.IsOne(); }
+        }
+
+        public override bool IsZero
+        {
+            get { return x.IsZero(); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return x.TestBitZero();
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return x.ToBigInteger();
+        }
+
+        public override string FieldName
+        {
+            get { return "F2m"; }
+        }
+
+        public override int FieldSize
+        {
+            get { 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 ArgumentException 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 is F2mFieldElement) || !(b is F2mFieldElement))
+            {
+                throw new ArgumentException("Field elements are not "
+                    + "both instances of F2mFieldElement");
+            }
+
+            F2mFieldElement aF2m = (F2mFieldElement)a;
+            F2mFieldElement bF2m = (F2mFieldElement)b;
+
+            if (aF2m.representation != bF2m.representation)
+            {
+                // Should never occur
+                throw new ArgumentException("One of the F2m field elements has incorrect representation");
+            }
+
+            if ((aF2m.m != bF2m.m) || !Arrays.AreEqual(aF2m.ks, bF2m.ks))
+            {
+                throw new ArgumentException("Field elements are not elements of the same field F2m");
+            }
+        }
+
+        public override ECFieldElement Add(
+            ECFieldElement b)
+        {
+            // No check performed here for performance reasons. Instead the
+            // elements involved are checked in ECPoint.F2m
+            // checkFieldElements(this, b);
+            LongArray iarrClone = this.x.Copy();
+            F2mFieldElement bF2m = (F2mFieldElement)b;
+            iarrClone.AddShiftedByWords(bF2m.x, 0);
+            return new F2mFieldElement(m, ks, iarrClone);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            return new F2mFieldElement(m, ks, x.AddOne());
+        }
+
+        public override ECFieldElement Subtract(
+            ECFieldElement b)
+        {
+            // Addition and subtraction are the same in F2m
+            return Add(b);
+        }
+
+        public override ECFieldElement Multiply(
+            ECFieldElement b)
+        {
+            // Right-to-left comb multiplication in the LongArray
+            // 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);
+            return new F2mFieldElement(m, ks, x.ModMultiply(((F2mFieldElement)b).x, m, ks));
+        }
+
+        public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            return MultiplyPlusProduct(b, x, y);
+        }
+
+        public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y)
+        {
+            LongArray ax = this.x, bx = ((F2mFieldElement)b).x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x;
+
+            LongArray ab = ax.Multiply(bx, m, ks);
+            LongArray xy = xx.Multiply(yx, m, ks);
+
+            if (ab == ax || ab == bx)
+            {
+                ab = (LongArray)ab.Copy();
+            }
+
+            ab.AddShiftedByWords(xy, 0);
+            ab.Reduce(m, ks);
+
+            return new F2mFieldElement(m, ks, ab);
+        }
+
+        public override ECFieldElement Divide(
+            ECFieldElement b)
+        {
+            // There may be more efficient implementations
+            ECFieldElement bInv = b.Invert();
+            return Multiply(bInv);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            // -x == x holds for all x in F2m
+            return this;
+        }
+
+        public override ECFieldElement Square()
+        {
+            return new F2mFieldElement(m, ks, x.ModSquare(m, ks));
+        }
+
+        public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            return SquarePlusProduct(x, y);
+        }
+
+        public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y)
+        {
+            LongArray ax = this.x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x;
+
+            LongArray aa = ax.Square(m, ks);
+            LongArray xy = xx.Multiply(yx, m, ks);
+
+            if (aa == ax)
+            {
+                aa = (LongArray)aa.Copy();
+            }
+
+            aa.AddShiftedByWords(xy, 0);
+            aa.Reduce(m, ks);
+
+            return new F2mFieldElement(m, ks, aa);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            return new F2mFieldElement(this.m, this.ks, this.x.ModInverse(m, ks));
+        }
+
+        public override ECFieldElement Sqrt()
+        {
+            LongArray x1 = this.x;
+            if (x1.IsOne() || x1.IsZero())
+            {
+                return this;
+            }
+
+            LongArray x2 = x1.ModSquareN(m - 1, m, ks);
+            return new F2mFieldElement(m, ks, x2);
+        }
+
+        /**
+            * @return the representation of the field
+            * <code>F<sub>2<sup>m</sup></sub></code>, either of
+            * {@link F2mFieldElement.Tpb} (trinomial
+            * basis representation) or
+            * {@link F2mFieldElement.Ppb} (pentanomial
+            * basis representation).
+            */
+        public int Representation
+        {
+            get { return this.representation; }
+        }
+
+        /**
+            * @return the degree <code>m</code> of the reduction polynomial
+            * <code>f(z)</code>.
+            */
+        public int M
+        {
+            get { 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 K1
+        {
+            get { return this.ks[0]; }
+        }
+
+        /**
+            * @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 K2
+        {
+            get { return this.ks.Length >= 2 ? this.ks[1] : 0; }
+        }
+
+        /**
+            * @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 K3
+        {
+            get { return this.ks.Length >= 3 ? this.ks[2] : 0; }
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+            F2mFieldElement other = obj as F2mFieldElement;
+
+            if (other == null)
+                return false;
+
+            return Equals(other);
+        }
+
+        public virtual bool Equals(
+            F2mFieldElement other)
+        {
+            return ((this.m == other.m)
+                && (this.representation == other.representation)
+                && Arrays.AreEqual(this.ks, other.ks)
+                && (this.x.Equals(other.x)));
+        }
+
+        public override int GetHashCode()
+        {
+            return x.GetHashCode() ^ m ^ Arrays.GetHashCode(ks);
+        }
+    }
 }
diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs
index f95f09974..3e206e65f 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -1,567 +1,2089 @@
 using System;
 using System.Collections;
 using System.Diagnostics;
-
-using Org.BouncyCastle.Asn1.X9;
+using System.Text;
 
 using Org.BouncyCastle.Math.EC.Multiplier;
 
 namespace Org.BouncyCastle.Math.EC
 {
-	/**
-	 * base class for points on elliptic curves.
-	 */
-	public abstract class ECPoint
-	{
-		internal readonly ECCurve			curve;
-		internal readonly ECFieldElement	x, y;
-		internal readonly bool				withCompression;
-		internal ECMultiplier				multiplier = null;
-		internal PreCompInfo				preCompInfo = null;
-
-		protected internal ECPoint(
-			ECCurve			curve,
-			ECFieldElement	x,
-			ECFieldElement	y,
-			bool			withCompression)
-		{
-			if (curve == null)
-				throw new ArgumentNullException("curve");
-
-			this.curve = curve;
-			this.x = x;
-			this.y = y;
-			this.withCompression = withCompression;
-		}
-
-		public ECCurve Curve
-		{
-			get { return curve; }
-		}
-
-		public ECFieldElement X
-		{
-			get { return x; }
-		}
-
-		public ECFieldElement Y
-		{
-			get { return y; }
-		}
-
-		public bool IsInfinity
-		{
-			get { return x == null && y == null; }
-		}
-
-		public bool IsCompressed
-		{
-			get { return withCompression; }
-		}
-
-		public override bool Equals(
-			object obj)
-		{
-			if (obj == this)
-				return true;
-
-			ECPoint o = obj as ECPoint;
-
-			if (o == null)
-				return false;
-
-			if (this.IsInfinity)
-				return o.IsInfinity;
-
-			return x.Equals(o.x) && y.Equals(o.y);
-		}
-
-		public override int GetHashCode()
-		{
-			if (this.IsInfinity)
-				return 0;
-
-			return x.GetHashCode() ^ y.GetHashCode();
-		}
-
-//		/**
-//		 * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
-//		 * @param multiplier The <code>ECMultiplier</code> to be used to multiply
-//		 * this <code>ECPoint</code>.
-//		 */
-//		internal 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>.
-		 */
-		internal 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();
-		public abstract ECPoint Multiply(BigInteger b);
-
-		/**
-		* Sets the appropriate <code>ECMultiplier</code>, unless already set. 
-		*/
-		internal virtual void AssertECMultiplier()
-		{
-			if (this.multiplier == null)
-			{
-				lock (this)
-				{
-					if (this.multiplier == null)
-					{
-						this.multiplier = new FpNafMultiplier();
-					}
-				}
-			}
-		}
-	}
-
-	public abstract class ECPointBase
-		: ECPoint
-	{
-		protected internal ECPointBase(
-			ECCurve			curve,
-			ECFieldElement	x,
-			ECFieldElement	y,
-			bool			withCompression)
-			: base(curve, x, y, withCompression)
-		{
-		}
-
-		protected internal abstract bool YTilde { get; }
-
-		/**
-		 * return the field element encoded with point compression. (S 4.3.6)
-		 */
-		public override byte[] GetEncoded()
-		{
-			if (this.IsInfinity)
-				return new byte[1];
-
-			// Note: some of the tests rely on calculating byte length from the field element
-			// (since the test cases use mismatching fields for curve/elements)
-			int byteLength = X9IntegerConverter.GetByteLength(x);
-			byte[] X = X9IntegerConverter.IntegerToBytes(this.X.ToBigInteger(), byteLength);
-			byte[] PO;
-
-			if (withCompression)
-			{
-				PO = new byte[1 + X.Length];
-
-				PO[0] = (byte)(YTilde ? 0x03 : 0x02);
-			}
-			else
-			{
-				byte[] Y = X9IntegerConverter.IntegerToBytes(this.Y.ToBigInteger(), byteLength);
-				PO = new byte[1 + X.Length + Y.Length];
-
-				PO[0] = 0x04;
-
-				Y.CopyTo(PO, 1 + X.Length);
-			}
-
-			X.CopyTo(PO, 1);
-
-			return PO;
-		}
-
-		/**
-		 * Multiplies this <code>ECPoint</code> by the given number.
-		 * @param k The multiplicator.
-		 * @return <code>k * this</code>.
-		 */
-		public override ECPoint Multiply(
-			BigInteger k)
-		{
-			if (k.SignValue < 0)
-				throw new ArgumentException("The multiplicator cannot be negative", "k");
-
-			if (this.IsInfinity)
-				return this;
-
-			if (k.SignValue == 0)
-				return this.curve.Infinity;
-
-			AssertECMultiplier();
-			return this.multiplier.Multiply(this, k, preCompInfo);
-		}
-	}
-
-	/**
-	 * Elliptic curve points over Fp
-	 */
-	public class FpPoint
-		: ECPointBase
-	{
-		/**
-		 * 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 FpPoint(
-			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 FpPoint(
-			ECCurve			curve,
-			ECFieldElement	x,
-			ECFieldElement	y,
-			bool			withCompression)
-			: base(curve, x, y, withCompression)
-		{
-			if ((x != null && y == null) || (x == null && y != null))
-				throw new ArgumentException("Exactly one of the field elements is null");
-		}
-
-		protected internal override bool YTilde
-		{
-			get
-			{
-				return this.Y.ToBigInteger().TestBit(0);
-			}
-		}
-
-		// B.3 pg 62
-		public override 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();
-				}
-
-				Debug.Assert(this.y.Equals(b.y.Negate()));
-
-				// this = -b, i.e. the result is the point at infinity
-				return this.curve.Infinity;
-			}
-
-			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 FpPoint(curve, x3, y3);
-		}
-
-		// B.3 pg 62
-		public override ECPoint Twice()
-		{
-			// Twice identity element (point at infinity) is identity
-			if (this.IsInfinity)
-				return this;
-
-			// if y1 == 0, then (x1, y1) == (x1, -y1)
-			// and hence this = -this and thus 2(x1, y1) == infinity
-			if (this.y.ToBigInteger().SignValue == 0)
-				return this.curve.Infinity;
-
-			ECFieldElement TWO = this.curve.FromBigInteger(BigInteger.Two);
-			ECFieldElement THREE = this.curve.FromBigInteger(BigInteger.Three);
-			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 FpPoint(curve, x3, y3, this.withCompression);
-		}
-
-		// D.3.2 pg 102 (see Note:)
-		public override ECPoint Subtract(
-			ECPoint b)
-		{
-			if (b.IsInfinity)
-				return this;
-
-			// Add -b
-			return Add(b.Negate());
-		}
-
-		public override ECPoint Negate()
-		{
-			return new FpPoint(this.curve, this.x, this.y.Negate(), this.withCompression);
-		}
-
-		/**
-		 * Sets the default <code>ECMultiplier</code>, unless already set. 
-		 */
-		internal override void AssertECMultiplier()
-		{
-			if (this.multiplier == null)
-			{
-				lock (this)
-				{
-					if (this.multiplier == null)
-					{
-						this.multiplier = new WNafMultiplier();
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Elliptic curve points over F2m
-	 */
-	public class F2mPoint
-		: ECPointBase
-	{
-		/**
-		 * @param curve base curve
-		 * @param x x point
-		 * @param y y point
-		 */
-		public F2mPoint(
-			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 F2mPoint(
-			ECCurve			curve,
-			ECFieldElement	x,
-			ECFieldElement	y,
-			bool			withCompression)
-			: base(curve, x, y, withCompression)
-		{
-			if ((x != null && y == null) || (x == null && y != null))
-			{
-				throw new ArgumentException("Exactly one of the field elements is null");
-			}
-
-			if (x != null)
-			{
-				// Check if x and y are elements of the same field
-				F2mFieldElement.CheckFieldElements(this.x, this.y);
-
-				// Check if x and a are elements of the same field
-				F2mFieldElement.CheckFieldElements(this.x, this.curve.A);
-			}
-		}
-
-		/**
-		 * Constructor for point at infinity
-		 */
-		[Obsolete("Use ECCurve.Infinity property")]
-		public F2mPoint(
-			ECCurve curve)
-			: this(curve, null, null)
-		{
-		}
-
-		protected internal override bool YTilde
-		{
-			get
-			{
-				// 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)
-				return this.X.ToBigInteger().SignValue != 0
-					&& this.Y.Multiply(this.X.Invert()).ToBigInteger().TestBit(0);
-			}
-		}
-
-		/**
-		 * 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 ArgumentException("Only points on the same curve can be added or subtracted");
+    /**
+     * base class for points on elliptic curves.
+     */
+    public abstract class ECPoint
+    {
+        protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
+
+        protected static ECFieldElement[] GetInitialZCoords(ECCurve curve)
+        {
+            // Cope with null curve, most commonly used by implicitlyCa
+            int coord = null == curve ? ECCurve.COORD_AFFINE : curve.CoordinateSystem;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                case ECCurve.COORD_LAMBDA_AFFINE:
+                    return EMPTY_ZS;
+                default:
+                    break;
+            }
+
+            ECFieldElement one = curve.FromBigInteger(BigInteger.One);
+
+            switch (coord)
+            {
+                case ECCurve.COORD_HOMOGENEOUS:
+                case ECCurve.COORD_JACOBIAN:
+                case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                    return new ECFieldElement[] { one };
+                case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+                    return new ECFieldElement[] { one, one, one };
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                    return new ECFieldElement[] { one, curve.A };
+                default:
+                    throw new ArgumentException("unknown coordinate system");
+            }
+        }
+
+        protected internal readonly ECCurve m_curve;
+        protected internal readonly ECFieldElement m_x, m_y;
+        protected internal readonly ECFieldElement[] m_zs;
+        protected internal readonly bool m_withCompression;
+
+        // Dictionary is (string -> PreCompInfo)
+        protected internal IDictionary m_preCompTable = null;
+
+        protected ECPoint(ECCurve curve, ECFieldElement	x, ECFieldElement y, bool withCompression)
+            : this(curve, x, y, GetInitialZCoords(curve), withCompression)
+        {
+        }
+
+        internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            this.m_curve = curve;
+            this.m_x = x;
+            this.m_y = y;
+            this.m_zs = zs;
+            this.m_withCompression = withCompression;
+        }
+
+        protected internal bool SatisfiesCofactor()
+        {
+            BigInteger h = Curve.Cofactor;
+            return h == null || h.Equals(BigInteger.One) || !ECAlgorithms.ReferenceMultiply(this, h).IsInfinity;
+        }
+
+        protected abstract bool SatisfiesCurveEquation();
+
+        public ECPoint GetDetachedPoint()
+        {
+            return Normalize().Detach();
+        }
+
+        public virtual ECCurve Curve
+        {
+            get { return m_curve; }
+        }
+
+        protected abstract ECPoint Detach();
+
+        protected virtual int CurveCoordinateSystem
+        {
+            get
+            {
+                // Cope with null curve, most commonly used by implicitlyCa
+                return null == m_curve ? ECCurve.COORD_AFFINE : m_curve.CoordinateSystem;
+            }
+        }
+
+        /**
+         * Normalizes this point, and then returns the affine x-coordinate.
+         * 
+         * Note: normalization can be expensive, this method is deprecated in favour
+         * of caller-controlled normalization.
+         */
+        [Obsolete("Use AffineXCoord, or Normalize() and XCoord, instead")]
+        public virtual ECFieldElement X
+        {
+            get { return Normalize().XCoord; }
+        }
+
+        /**
+         * Normalizes this point, and then returns the affine y-coordinate.
+         * 
+         * Note: normalization can be expensive, this method is deprecated in favour
+         * of caller-controlled normalization.
+         */
+        [Obsolete("Use AffineYCoord, or Normalize() and YCoord, instead")]
+        public virtual ECFieldElement Y
+        {
+            get { return Normalize().YCoord; }
+        }
+
+        /**
+         * Returns the affine x-coordinate after checking that this point is normalized.
+         * 
+         * @return The affine x-coordinate of this point
+         * @throws IllegalStateException if the point is not normalized
+         */
+        public virtual ECFieldElement AffineXCoord
+        {
+            get
+            {
+                CheckNormalized();
+                return XCoord;
+            }
+        }
+
+        /**
+         * Returns the affine y-coordinate after checking that this point is normalized
+         * 
+         * @return The affine y-coordinate of this point
+         * @throws IllegalStateException if the point is not normalized
+         */
+        public virtual ECFieldElement AffineYCoord
+        {
+            get
+            {
+                CheckNormalized();
+                return YCoord;
+            }
+        }
+
+        /**
+         * Returns the x-coordinate.
+         * 
+         * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+         * affine coordinate system; use Normalize() to get a point where the coordinates have their
+         * affine values, or use AffineXCoord if you expect the point to already have been normalized.
+         * 
+         * @return the x-coordinate of this point
+         */
+        public virtual ECFieldElement XCoord
+        {
+            get { return m_x; }
+        }
+
+        /**
+         * Returns the y-coordinate.
+         * 
+         * Caution: depending on the curve's coordinate system, this may not be the same value as in an
+         * affine coordinate system; use Normalize() to get a point where the coordinates have their
+         * affine values, or use AffineYCoord if you expect the point to already have been normalized.
+         * 
+         * @return the y-coordinate of this point
+         */
+        public virtual ECFieldElement YCoord
+        {
+            get { return m_y; }
+        }
+
+        public virtual ECFieldElement GetZCoord(int index)
+        {
+            return (index < 0 || index >= m_zs.Length) ? null : m_zs[index];
+        }
+
+        public virtual ECFieldElement[] GetZCoords()
+        {
+            int zsLen = m_zs.Length;
+            if (zsLen == 0)
+            {
+                return m_zs;
+            }
+            ECFieldElement[] copy = new ECFieldElement[zsLen];
+            Array.Copy(m_zs, 0, copy, 0, zsLen);
+            return copy;
+        }
+
+        protected internal ECFieldElement RawXCoord
+        {
+            get { return m_x; }
+        }
+
+        protected internal ECFieldElement RawYCoord
+        {
+            get { return m_y; }
+        }
+
+        protected internal ECFieldElement[] RawZCoords
+        {
+            get { return m_zs; }
+        }
+
+        protected virtual void CheckNormalized()
+        {
+            if (!IsNormalized())
+                throw new InvalidOperationException("point not in normal form");
+        }
+
+        public virtual bool IsNormalized()
+        {
+            int coord = this.CurveCoordinateSystem;
+
+            return coord == ECCurve.COORD_AFFINE
+                || coord == ECCurve.COORD_LAMBDA_AFFINE
+                || IsInfinity
+                || RawZCoords[0].IsOne;
+        }
+
+        /**
+         * Normalization ensures that any projective coordinate is 1, and therefore that the x, y
+         * coordinates reflect those of the equivalent point in an affine coordinate system.
+         * 
+         * @return a new ECPoint instance representing the same point, but with normalized coordinates
+         */
+        public virtual ECPoint Normalize()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            switch (this.CurveCoordinateSystem)
+            {
+                case ECCurve.COORD_AFFINE:
+                case ECCurve.COORD_LAMBDA_AFFINE:
+                {
+                    return this;
+                }
+                default:
+                {
+                    ECFieldElement Z1 = RawZCoords[0];
+                    if (Z1.IsOne)
+                    {
+                        return this;
+                    }
+
+                    return Normalize(Z1.Invert());
+                }
+            }
+        }
+
+        internal virtual ECPoint Normalize(ECFieldElement zInv)
+        {
+            switch (this.CurveCoordinateSystem)
+            {
+                case ECCurve.COORD_HOMOGENEOUS:
+                case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                {
+                    return CreateScaledPoint(zInv, zInv);
+                }
+                case ECCurve.COORD_JACOBIAN:
+                case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                {
+                    ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
+                    return CreateScaledPoint(zInv2, zInv3);
+                }
+                default:
+                {
+                    throw new InvalidOperationException("not a projective coordinate system");
+                }
+            }
+        }
+
+        protected virtual ECPoint CreateScaledPoint(ECFieldElement sx, ECFieldElement sy)
+        {
+            return Curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy), IsCompressed);
+        }
+
+        public bool IsInfinity
+        {
+            get { return m_x == null && m_y == null; }
+        }
+
+        public bool IsCompressed
+        {
+            get { return m_withCompression; }
+        }
+
+        public bool IsValid()
+        {
+            if (IsInfinity)
+                return true;
+
+            // TODO Sanity-check the field elements
+
+            ECCurve curve = Curve;
+            if (curve != null)
+            {
+                if (!SatisfiesCurveEquation())
+                    return false;
+
+                if (!SatisfiesCofactor())
+                    return false;
+            }
+
+            return true;
+        }
+
+        public virtual ECPoint ScaleX(ECFieldElement scale)
+        {
+            return IsInfinity
+                ? this
+                : Curve.CreateRawPoint(RawXCoord.Multiply(scale), RawYCoord, RawZCoords, IsCompressed);
+        }
+
+        public virtual ECPoint ScaleY(ECFieldElement scale)
+        {
+            return IsInfinity
+                ? this
+                : Curve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(scale), RawZCoords, IsCompressed);
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as ECPoint);
+        }
+
+        public virtual bool Equals(ECPoint other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+
+            ECCurve c1 = this.Curve, c2 = other.Curve;
+            bool n1 = (null == c1), n2 = (null == c2);
+            bool i1 = IsInfinity, i2 = other.IsInfinity;
+
+            if (i1 || i2)
+            {
+                return (i1 && i2) && (n1 || n2 || c1.Equals(c2));
+            }
+
+            ECPoint p1 = this, p2 = other;
+            if (n1 && n2)
+            {
+                // Points with null curve are in affine form, so already normalized
+            }
+            else if (n1)
+            {
+                p2 = p2.Normalize();
+            }
+            else if (n2)
+            {
+                p1 = p1.Normalize();
+            }
+            else if (!c1.Equals(c2))
+            {
+                return false;
+            }
+            else
+            {
+                // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+                ECPoint[] points = new ECPoint[] { this, c1.ImportPoint(p2) };
+
+                // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal
+                c1.NormalizeAll(points);
+
+                p1 = points[0];
+                p2 = points[1];
+            }
+
+            return p1.XCoord.Equals(p2.XCoord) && p1.YCoord.Equals(p2.YCoord);
+        }
+
+        public override int GetHashCode()
+        {
+            ECCurve c = this.Curve;
+            int hc = (null == c) ? 0 : ~c.GetHashCode();
+
+            if (!this.IsInfinity)
+            {
+                // TODO Consider just requiring already normalized, to avoid silent performance degradation
+
+                ECPoint p = Normalize();
+
+                hc ^= p.XCoord.GetHashCode() * 17;
+                hc ^= p.YCoord.GetHashCode() * 257;
+            }
+
+            return hc;
+        }
+
+        public override string ToString()
+        {
+            if (this.IsInfinity)
+            {
+                return "INF";
+            }
+
+            StringBuilder sb = new StringBuilder();
+            sb.Append('(');
+            sb.Append(RawXCoord);
+            sb.Append(',');
+            sb.Append(RawYCoord);
+            for (int i = 0; i < m_zs.Length; ++i)
+            {
+                sb.Append(',');
+                sb.Append(m_zs[i]);
+            }
+            sb.Append(')');
+            return sb.ToString();
+        }
+
+        public virtual byte[] GetEncoded()
+        {
+            return GetEncoded(m_withCompression);
+        }
+
+        public abstract byte[] GetEncoded(bool compressed);
+
+        protected internal abstract bool CompressionYTilde { get; }
+
+        public abstract ECPoint Add(ECPoint b);
+        public abstract ECPoint Subtract(ECPoint b);
+        public abstract ECPoint Negate();
+
+        public virtual ECPoint TimesPow2(int e)
+        {
+            if (e < 0)
+                throw new ArgumentException("cannot be negative", "e");
+
+            ECPoint p = this;
+            while (--e >= 0)
+            {
+                p = p.Twice();
+            }
+            return p;
+        }
+
+        public abstract ECPoint Twice();
+        public abstract ECPoint Multiply(BigInteger b);
+
+        public virtual ECPoint TwicePlus(ECPoint b)
+        {
+            return Twice().Add(b);
+        }
+
+        public virtual ECPoint ThreeTimes()
+        {
+            return TwicePlus(this);
+        }
+    }
+
+    public abstract class ECPointBase
+        : ECPoint
+    {
+        protected internal ECPointBase(
+            ECCurve			curve,
+            ECFieldElement	x,
+            ECFieldElement	y,
+            bool			withCompression)
+            : base(curve, x, y, withCompression)
+        {
+        }
+
+        protected internal ECPointBase(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        /**
+         * return the field element encoded with point compression. (S 4.3.6)
+         */
+        public override byte[] GetEncoded(bool compressed)
+        {
+            if (this.IsInfinity)
+            {
+                return new byte[1];
+            }
+
+            ECPoint normed = Normalize();
+
+            byte[] X = normed.XCoord.GetEncoded();
+
+            if (compressed)
+            {
+                byte[] PO = new byte[X.Length + 1];
+                PO[0] = (byte)(normed.CompressionYTilde ? 0x03 : 0x02);
+                Array.Copy(X, 0, PO, 1, X.Length);
+                return PO;
+            }
+
+            byte[] Y = normed.YCoord.GetEncoded();
+
+            {
+                byte[] PO = new byte[X.Length + Y.Length + 1];
+                PO[0] = 0x04;
+                Array.Copy(X, 0, PO, 1, X.Length);
+                Array.Copy(Y, 0, PO, X.Length + 1, Y.Length);
+                return PO;
+            }
+        }
+
+        /**
+         * Multiplies this <code>ECPoint</code> by the given number.
+         * @param k The multiplicator.
+         * @return <code>k * this</code>.
+         */
+        public override ECPoint Multiply(BigInteger k)
+        {
+            return this.Curve.GetMultiplier().Multiply(this, k);
+        }
+    }
+
+    public abstract class AbstractFpPoint
+        : ECPointBase
+    {
+        protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+        }
+
+        protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get { return this.AffineYCoord.TestBitZero(); }
+        }
+
+        protected override bool SatisfiesCurveEquation()
+        {
+            ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = Curve.A, B = Curve.B;
+            ECFieldElement lhs = Y.Square();
+
+            switch (CurveCoordinateSystem)
+            {
+            case ECCurve.COORD_AFFINE:
+                break;
+            case ECCurve.COORD_HOMOGENEOUS:
+            {
+                ECFieldElement Z = this.RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
+                    lhs = lhs.Multiply(Z);
+                    A = A.Multiply(Z2);
+                    B = B.Multiply(Z3);
+                }
+                break;
+            }
+            case ECCurve.COORD_JACOBIAN:
+            case ECCurve.COORD_JACOBIAN_CHUDNOVSKY:
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+            {
+                ECFieldElement Z = this.RawZCoords[0];
+                if (!Z.IsOne)
+                {
+                    ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square(), Z6 = Z2.Multiply(Z4);
+                    A = A.Multiply(Z4);
+                    B = B.Multiply(Z6);
+                }
+                break;
+            }
+            default:
+                throw new InvalidOperationException("unsupported coordinate system");
+            }
+
+            ECFieldElement rhs = X.Square().Add(A).Multiply(X).Add(B);
+            return lhs.Equals(rhs);
+        }
+
+        public override ECPoint Subtract(ECPoint b)
+        {
+            if (b.IsInfinity)
+                return this;
+
+            // Add -b
+            return Add(b.Negate());
+        }
+    }
+
+    /**
+     * Elliptic curve points over Fp
+     */
+    public class FpPoint
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes without point compression.
+         *
+         * @param curve the curve to use
+         * @param x affine x co-ordinate
+         * @param y affine y co-ordinate
+         */
+        public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compression.
+         *
+         * @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 FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new FpPoint(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement GetZCoord(int index)
+        {
+            if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.CurveCoordinateSystem)
+            {
+                return GetJacobianModifiedW();
+            }
+
+            return base.GetZCoord(index);
+        }
+
+        // B.3 pg 62
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord;
+            ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                {
+                    ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
+
+                    if (dx.IsZero)
+                    {
+                        if (dy.IsZero)
+                        {
+                            // this == b, i.e. this must be doubled
+                            return Twice();
+                        }
+
+                        // this == -b, i.e. the result is the point at infinity
+                        return Curve.Infinity;
+                    }
+
+                    ECFieldElement gamma = dy.Divide(dx);
+                    ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2);
+                    ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+
+                    return new FpPoint(Curve, X3, Y3, IsCompressed);
+                }
+
+                case ECCurve.COORD_HOMOGENEOUS:
+                {
+                    ECFieldElement Z1 = this.RawZCoords[0];
+                    ECFieldElement Z2 = b.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+                    bool Z2IsOne = Z2.IsOne;
+
+                    ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1);
+                    ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2);
+                    ECFieldElement u = u1.Subtract(u2);
+                    ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1);
+                    ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2);
+                    ECFieldElement v = v1.Subtract(v2);
+
+                    // Check if b == this or b == -this
+                    if (v.IsZero)
+                    {
+                        if (u.IsZero)
+                        {
+                            // this == b, i.e. this must be doubled
+                            return this.Twice();
+                        }
+
+                        // this == -b, i.e. the result is the point at infinity
+                        return curve.Infinity;
+                    }
+
+                    // TODO Optimize for when w == 1
+                    ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
+                    ECFieldElement vSquared = v.Square();
+                    ECFieldElement vCubed = vSquared.Multiply(v);
+                    ECFieldElement vSquaredV2 = vSquared.Multiply(v2);
+                    ECFieldElement A = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2));
+
+                    ECFieldElement X3 = v.Multiply(A);
+                    ECFieldElement Y3 = vSquaredV2.Subtract(A).MultiplyMinusProduct(u, u2, vCubed);
+                    ECFieldElement Z3 = vCubed.Multiply(w);
+
+                    return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+
+                case ECCurve.COORD_JACOBIAN:
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                {
+                    ECFieldElement Z1 = this.RawZCoords[0];
+                    ECFieldElement Z2 = b.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+
+                    ECFieldElement X3, Y3, Z3, Z3Squared = null;
+
+                    if (!Z1IsOne && Z1.Equals(Z2))
+                    {
+                        // TODO Make this available as public method coZAdd?
+
+                        ECFieldElement dx = X1.Subtract(X2), dy = Y1.Subtract(Y2);
+                        if (dx.IsZero)
+                        {
+                            if (dy.IsZero)
+                            {
+                                return Twice();
+                            }
+                            return curve.Infinity;
+                        }
+
+                        ECFieldElement C = dx.Square();
+                        ECFieldElement W1 = X1.Multiply(C), W2 = X2.Multiply(C);
+                        ECFieldElement A1 = W1.Subtract(W2).Multiply(Y1);
+
+                        X3 = dy.Square().Subtract(W1).Subtract(W2);
+                        Y3 = W1.Subtract(X3).Multiply(dy).Subtract(A1);
+                        Z3 = dx;
+
+                        if (Z1IsOne)
+                        {
+                            Z3Squared = C;
+                        }
+                        else
+                        {
+                            Z3 = Z3.Multiply(Z1);
+                        }
+                    }
+                    else
+                    {
+                        ECFieldElement Z1Squared, U2, S2;
+                        if (Z1IsOne)
+                        {
+                            Z1Squared = Z1; U2 = X2; S2 = Y2;
+                        }
+                        else
+                        {
+                            Z1Squared = Z1.Square();
+                            U2 = Z1Squared.Multiply(X2);
+                            ECFieldElement Z1Cubed = Z1Squared.Multiply(Z1);
+                            S2 = Z1Cubed.Multiply(Y2);
+                        }
+
+                        bool Z2IsOne = Z2.IsOne;
+                        ECFieldElement Z2Squared, U1, S1;
+                        if (Z2IsOne)
+                        {
+                            Z2Squared = Z2; U1 = X1; S1 = Y1;
+                        }
+                        else
+                        {
+                            Z2Squared = Z2.Square();
+                            U1 = Z2Squared.Multiply(X1);
+                            ECFieldElement Z2Cubed = Z2Squared.Multiply(Z2);
+                            S1 = Z2Cubed.Multiply(Y1);
+                        }
+
+                        ECFieldElement H = U1.Subtract(U2);
+                        ECFieldElement R = S1.Subtract(S2);
+
+                        // Check if b == this or b == -this
+                        if (H.IsZero)
+                        {
+                            if (R.IsZero)
+                            {
+                                // this == b, i.e. this must be doubled
+                                return this.Twice();
+                            }
+
+                            // this == -b, i.e. the result is the point at infinity
+                            return curve.Infinity;
+                        }
+
+                        ECFieldElement HSquared = H.Square();
+                        ECFieldElement G = HSquared.Multiply(H);
+                        ECFieldElement V = HSquared.Multiply(U1);
+
+                        X3 = R.Square().Add(G).Subtract(Two(V));
+                        Y3 = V.Subtract(X3).MultiplyMinusProduct(R, G, S1);
+
+                        Z3 = H;
+                        if (!Z1IsOne)
+                        {
+                            Z3 = Z3.Multiply(Z1);
+                        }
+                        if (!Z2IsOne)
+                        {
+                            Z3 = Z3.Multiply(Z2);
+                        }
+
+                        // Alternative calculation of Z3 using fast square
+                        //X3 = four(X3);
+                        //Y3 = eight(Y3);
+                        //Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).Multiply(H);
+
+                        if (Z3 == H)
+                        {
+                            Z3Squared = HSquared;
+                        }
+                    }
+
+                    ECFieldElement[] zs;
+                    if (coord == ECCurve.COORD_JACOBIAN_MODIFIED)
+                    {
+                        // TODO If the result will only be used in a subsequent addition, we don't need W3
+                        ECFieldElement W3 = CalculateJacobianModifiedW(Z3, Z3Squared);
+
+                        zs = new ECFieldElement[] { Z3, W3 };
+                    }
+                    else
+                    {
+                        zs = new ECFieldElement[] { Z3 };
+                    }
+
+                    return new FpPoint(curve, X3, Y3, zs, IsCompressed);
+                }
+
+                default:
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+            }
+        }
+
+        // B.3 pg 62
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero) 
+                return curve.Infinity;
+
+            int coord = curve.CoordinateSystem;
+
+            ECFieldElement X1 = this.RawXCoord;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                {
+                    ECFieldElement X1Squared = X1.Square();
+                    ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1));
+                    ECFieldElement X3 = gamma.Square().Subtract(Two(X1));
+                    ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1);
+
+                    return new FpPoint(Curve, X3, Y3, IsCompressed);
+                }
+
+                case ECCurve.COORD_HOMOGENEOUS:
+                {
+                    ECFieldElement Z1 = this.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+
+                    // TODO Optimize for small negative a4 and -3
+                    ECFieldElement w = curve.A;
+                    if (!w.IsZero && !Z1IsOne)
+                    {
+                        w = w.Multiply(Z1.Square());
+                    }
+                    w = w.Add(Three(X1.Square()));
+
+                    ECFieldElement s = Z1IsOne ? Y1 : Y1.Multiply(Z1);
+                    ECFieldElement t = Z1IsOne ? Y1.Square() : s.Multiply(Y1);
+                    ECFieldElement B = X1.Multiply(t);
+                    ECFieldElement _4B = Four(B);
+                    ECFieldElement h = w.Square().Subtract(Two(_4B));
+
+                    ECFieldElement _2s = Two(s);
+                    ECFieldElement X3 = h.Multiply(_2s);
+                    ECFieldElement _2t = Two(t);
+                    ECFieldElement Y3 = _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square()));
+                    ECFieldElement _4sSquared = Z1IsOne ? Two(_2t) : _2s.Square();
+                    ECFieldElement Z3 = Two(_4sSquared).Multiply(s);
+
+                    return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+
+                case ECCurve.COORD_JACOBIAN:
+                {
+                    ECFieldElement Z1 = this.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+
+                    ECFieldElement Y1Squared = Y1.Square();
+                    ECFieldElement T = Y1Squared.Square();
+
+                    ECFieldElement a4 = curve.A;
+                    ECFieldElement a4Neg = a4.Negate();
+
+                    ECFieldElement M, S;
+                    if (a4Neg.ToBigInteger().Equals(BigInteger.ValueOf(3)))
+                    {
+                        ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
+                        M = Three(X1.Add(Z1Squared).Multiply(X1.Subtract(Z1Squared)));
+                        S = Four(Y1Squared.Multiply(X1));
+                    }
+                    else
+                    {
+                        ECFieldElement X1Squared = X1.Square();
+                        M = Three(X1Squared);
+                        if (Z1IsOne)
+                        {
+                            M = M.Add(a4);
+                        }
+                        else if (!a4.IsZero)
+                        {
+                            ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square();
+                            ECFieldElement Z1Pow4 = Z1Squared.Square();
+                            if (a4Neg.BitLength < a4.BitLength)
+                            {
+                                M = M.Subtract(Z1Pow4.Multiply(a4Neg));
+                            }
+                            else
+                            {
+                                M = M.Add(Z1Pow4.Multiply(a4));
+                            }
+                        }
+                        //S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T));
+                        S = Four(X1.Multiply(Y1Squared));
+                    }
+
+                    ECFieldElement X3 = M.Square().Subtract(Two(S));
+                    ECFieldElement Y3 = S.Subtract(X3).Multiply(M).Subtract(Eight(T));
+
+                    ECFieldElement Z3 = Two(Y1);
+                    if (!Z1IsOne)
+                    {
+                        Z3 = Z3.Multiply(Z1);
+                    }
+
+                    // Alternative calculation of Z3 using fast square
+                    //ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared);
+
+                    return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                {
+                    return TwiceJacobianModified(true);
+                }
+
+                default:
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+            }
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                {
+                    ECFieldElement X1 = this.RawXCoord;
+                    ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord;
+
+                    ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1);
+
+                    if (dx.IsZero)
+                    {
+                        if (dy.IsZero)
+                        {
+                            // this == b i.e. the result is 3P
+                            return ThreeTimes();
+                        }
+
+                        // this == -b, i.e. the result is P
+                        return this;
+                    }
+
+                    /*
+                     * Optimized calculation of 2P + Q, as described in "Trading Inversions for
+                     * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery.
+                     */
+
+                    ECFieldElement X = dx.Square(), Y = dy.Square();
+                    ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y);
+                    if (d.IsZero)
+                    {
+                        return Curve.Infinity;
+                    }
+
+                    ECFieldElement D = d.Multiply(dx);
+                    ECFieldElement I = D.Invert();
+                    ECFieldElement L1 = d.Multiply(I).Multiply(dy);
+                    ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1);
+                    ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2);
+                    ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
+
+                    return new FpPoint(Curve, X4, Y4, IsCompressed);
+                }
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                {
+                    return TwiceJacobianModified(false).Add(b);
+                }
+                default:
+                {
+                    return Twice().Add(b);
+                }
+            }
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return this;
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                {
+                    ECFieldElement X1 = this.RawXCoord;
+
+                    ECFieldElement _2Y1 = Two(Y1);
+                    ECFieldElement X = _2Y1.Square();
+                    ECFieldElement Z = Three(X1.Square()).Add(Curve.A);
+                    ECFieldElement Y = Z.Square();
+
+                    ECFieldElement d = Three(X1).Multiply(X).Subtract(Y);
+                    if (d.IsZero)
+                    {
+                        return Curve.Infinity;
+                    }
+
+                    ECFieldElement D = d.Multiply(_2Y1);
+                    ECFieldElement I = D.Invert();
+                    ECFieldElement L1 = d.Multiply(I).Multiply(Z);
+                    ECFieldElement L2 = X.Square().Multiply(I).Subtract(L1);
+
+                    ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X1);
+                    ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1);
+                    return new FpPoint(Curve, X4, Y4, IsCompressed);
+                }
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                {
+                    return TwiceJacobianModified(false).Add(this);
+                }
+                default:
+                {
+                    // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+                    return Twice().Add(this);
+                }
+            }
+        }
+
+        public override ECPoint TimesPow2(int e)
+        {
+            if (e < 0)
+                throw new ArgumentException("cannot be negative", "e");
+            if (e == 0 || this.IsInfinity)
+                return this;
+            if (e == 1)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero) 
+                return curve.Infinity;
+
+            int coord = curve.CoordinateSystem;
+
+            ECFieldElement W1 = curve.A;
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement Z1 = this.RawZCoords.Length < 1 ? curve.FromBigInteger(BigInteger.One) : this.RawZCoords[0];
+
+            if (!Z1.IsOne)
+            {
+                switch (coord)
+                {
+                case ECCurve.COORD_HOMOGENEOUS:
+                    ECFieldElement Z1Sq = Z1.Square();
+                    X1 = X1.Multiply(Z1);
+                    Y1 = Y1.Multiply(Z1Sq);
+                    W1 = CalculateJacobianModifiedW(Z1, Z1Sq);
+                    break;
+                case ECCurve.COORD_JACOBIAN:
+                    W1 = CalculateJacobianModifiedW(Z1, null);
+                    break;
+                case ECCurve.COORD_JACOBIAN_MODIFIED:
+                    W1 = GetJacobianModifiedW();
+                    break;
+                }
+            }
+
+            for (int i = 0; i < e; ++i)
+            {
+                if (Y1.IsZero) 
+                    return curve.Infinity;
+
+                ECFieldElement X1Squared = X1.Square();
+                ECFieldElement M = Three(X1Squared);
+                ECFieldElement _2Y1 = Two(Y1);
+                ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
+                ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
+                ECFieldElement _4T = _2Y1Squared.Square();
+                ECFieldElement _8T = Two(_4T);
+
+                if (!W1.IsZero)
+                {
+                    M = M.Add(W1);
+                    W1 = Two(_8T.Multiply(W1));
+                }
+
+                X1 = M.Square().Subtract(Two(S));
+                Y1 = M.Multiply(S.Subtract(X1)).Subtract(_8T);
+                Z1 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
+            }
+
+            switch (coord)
+            {
+            case ECCurve.COORD_AFFINE:
+                ECFieldElement zInv = Z1.Invert(), zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv);
+                return new FpPoint(curve, X1.Multiply(zInv2), Y1.Multiply(zInv3), IsCompressed);
+            case ECCurve.COORD_HOMOGENEOUS:
+                X1 = X1.Multiply(Z1);
+                Z1 = Z1.Multiply(Z1.Square());
+                return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
+            case ECCurve.COORD_JACOBIAN:
+                return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed);
+            case ECCurve.COORD_JACOBIAN_MODIFIED:
+                return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1, W1 }, IsCompressed);
+            default:
+                throw new InvalidOperationException("unsupported coordinate system");
+            }
+        }
+
+        protected virtual ECFieldElement Two(ECFieldElement x)
+        {
+            return x.Add(x);
+        }
+
+        protected virtual ECFieldElement Three(ECFieldElement x)
+        {
+            return Two(x).Add(x);
+        }
+
+        protected virtual ECFieldElement Four(ECFieldElement x)
+        {
+            return Two(Two(x));
+        }
+
+        protected virtual ECFieldElement Eight(ECFieldElement x)
+        {
+            return Four(Two(x));
+        }
+
+        protected virtual ECFieldElement DoubleProductFromSquares(ECFieldElement a, ECFieldElement b,
+            ECFieldElement aSquared, ECFieldElement bSquared)
+        {
+            /*
+             * NOTE: If squaring in the field is faster than multiplication, then this is a quicker
+             * way to calculate 2.A.B, if A^2 and B^2 are already known.
+             */
+            return a.Add(b).Square().Subtract(aSquared).Subtract(bSquared);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            ECCurve curve = Curve;
+            int coord = curve.CoordinateSystem;
+
+            if (ECCurve.COORD_AFFINE != coord)
+            {
+                return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+            }
+
+            return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), IsCompressed);
+        }
+
+        protected virtual ECFieldElement CalculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared)
+        {
+            ECFieldElement a4 = this.Curve.A;
+            if (a4.IsZero || Z.IsOne)
+                return a4;
+
+            if (ZSquared == null)
+            {
+                ZSquared = Z.Square();
+            }
+
+            ECFieldElement W = ZSquared.Square();
+            ECFieldElement a4Neg = a4.Negate();
+            if (a4Neg.BitLength < a4.BitLength)
+            {
+                W = W.Multiply(a4Neg).Negate();
+            }
+            else
+            {
+                W = W.Multiply(a4);
+            }
+            return W;
+        }
+
+        protected virtual ECFieldElement GetJacobianModifiedW()
+        {
+            ECFieldElement[] ZZ = this.RawZCoords;
+            ECFieldElement W = ZZ[1];
+            if (W == null)
+            {
+                // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
+                ZZ[1] = W = CalculateJacobianModifiedW(ZZ[0], null);
+            }
+            return W;
+        }
+
+        protected virtual FpPoint TwiceJacobianModified(bool calculateW)
+        {
+            ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord, Z1 = this.RawZCoords[0], W1 = GetJacobianModifiedW();
+
+            ECFieldElement X1Squared = X1.Square();
+            ECFieldElement M = Three(X1Squared).Add(W1);
+            ECFieldElement _2Y1 = Two(Y1);
+            ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1);
+            ECFieldElement S = Two(X1.Multiply(_2Y1Squared));
+            ECFieldElement X3 = M.Square().Subtract(Two(S));
+            ECFieldElement _4T = _2Y1Squared.Square();
+            ECFieldElement _8T = Two(_4T);
+            ECFieldElement Y3 = M.Multiply(S.Subtract(X3)).Subtract(_8T);
+            ECFieldElement W3 = calculateW ? Two(_8T.Multiply(W1)) : null;
+            ECFieldElement Z3 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1);
+
+            return new FpPoint(this.Curve, X3, Y3, new ECFieldElement[] { Z3, W3 }, IsCompressed);
+        }
+    }
+
+    public abstract class AbstractF2mPoint 
+        : ECPointBase
+    {
+        protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+        }
+
+        protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override bool SatisfiesCurveEquation()
+        {
+            ECCurve curve = Curve;
+            ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = curve.A, B = curve.B;
+            ECFieldElement lhs, rhs;
+
+            int coord = curve.CoordinateSystem;
+            if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE)
+            {
+                ECFieldElement Z = this.RawZCoords[0];
+                bool ZIsOne = Z.IsOne;
+
+                if (X.IsZero)
+                {
+                    // NOTE: For x == 0, we expect the affine-y instead of the lambda-y 
+                    lhs = Y.Square();
+                    rhs = B;
+                    if (!ZIsOne)
+                    {
+                        ECFieldElement Z2 = Z.Square();
+                        rhs = rhs.Multiply(Z2);
+                    }
+                }
+                else
+                {
+                    ECFieldElement L = Y, X2 = X.Square();
+                    if (ZIsOne)
+                    {
+                        lhs = L.Square().Add(L).Add(A);
+                        rhs = X2.Square().Add(B);
+                    }
+                    else
+                    {
+                        ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square();
+                        lhs = L.Add(Z).MultiplyPlusProduct(L, A, Z2);
+                        // TODO If sqrt(b) is precomputed this can be simplified to a single square
+                        rhs = X2.SquarePlusProduct(B, Z4);
+                    }
+                    lhs = lhs.Multiply(X2);
+                }
+            }
+            else
+            {
+                lhs = Y.Add(X).Multiply(Y);
+
+                switch (coord)
+                {
+                    case ECCurve.COORD_AFFINE:
+                        break;
+                    case ECCurve.COORD_HOMOGENEOUS:
+                        {
+                            ECFieldElement Z = this.RawZCoords[0];
+                            if (!Z.IsOne)
+                            {
+                                ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2);
+                                lhs = lhs.Multiply(Z);
+                                A = A.Multiply(Z);
+                                B = B.Multiply(Z3);
+                            }
+                            break;
+                        }
+                    default:
+                        throw new InvalidOperationException("unsupported coordinate system");
+                }
+
+                rhs = X.Add(A).Multiply(X.Square()).Add(B);
+            }
+
+            return lhs.Equals(rhs);
+        }
+    }
+
+    /**
+     * Elliptic curve points over F2m
+     */
+    public class F2mPoint
+        : AbstractF2mPoint
+    {
+        /**
+         * @param curve base curve
+         * @param x x point
+         * @param y y point
+         */
+        public F2mPoint(
+            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 F2mPoint(
+            ECCurve			curve,
+            ECFieldElement	x,
+            ECFieldElement	y,
+            bool			withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+            {
+                throw new ArgumentException("Exactly one of the field elements is null");
+            }
+
+            if (x != null)
+            {
+                // Check if x and y are elements of the same field
+                F2mFieldElement.CheckFieldElements(x, y);
+
+                // Check if x and a are elements of the same field
+                if (curve != null)
+                {
+                    F2mFieldElement.CheckFieldElements(x, curve.A);
+                }
+            }
+        }
+
+        internal F2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        /**
+         * Constructor for point at infinity
+         */
+        [Obsolete("Use ECCurve.Infinity property")]
+        public F2mPoint(
+            ECCurve curve)
+            : this(curve, null, null)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new F2mPoint(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement YCoord
+        {
+            get
+            {
+                int coord = this.CurveCoordinateSystem;
+
+                switch (coord)
+                {
+                    case ECCurve.COORD_LAMBDA_AFFINE:
+                    case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                    {
+                        ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                        if (this.IsInfinity || X.IsZero)
+                            return L;
+
+                        // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly
+                        ECFieldElement Y = L.Add(X).Multiply(X);
+                        if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord)
+                        {
+                            ECFieldElement Z = RawZCoords[0];
+                            if (!Z.IsOne)
+                            {
+                                Y = Y.Divide(Z);
+                            }
+                        }
+                        return Y;
+                    }
+                    default:
+                    {
+                        return RawYCoord;
+                    }
+                }
+            }
+        }
+
+        public override ECPoint ScaleX(ECFieldElement scale)
+        {
+            if (this.IsInfinity)
+                return this;
+
+            switch (CurveCoordinateSystem)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                ECFieldElement X2 = X.Multiply(scale);
+                ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2);
+
+                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+            }
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0];
+
+                // We scale the Z coordinate also, to avoid an inversion
+                ECFieldElement X2 = X.Multiply(scale.Square());
+                ECFieldElement L2 = L.Add(X).Add(X2);
+                ECFieldElement Z2 = Z.Multiply(scale);
+
+                return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed);
+            }
+            default:
+            {
+                return base.ScaleX(scale);
+            }
+            }
+        }
+
+        public override ECPoint ScaleY(ECFieldElement scale)
+        {
+            if (this.IsInfinity)
+                return this;
+
+            switch (CurveCoordinateSystem)
+            {
+            case ECCurve.COORD_LAMBDA_AFFINE:
+            case ECCurve.COORD_LAMBDA_PROJECTIVE:
+            {
+                ECFieldElement X = RawXCoord, L = RawYCoord;
+
+                // Y is actually Lambda (X + Y/X) here
+                ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X);
+
+                return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed);
+            }
+            default:
+            {
+                return base.ScaleY(scale);
+            }
+            }
+        }
+
+        protected internal override bool CompressionYTilde
+        {
+            get
+            {
+                ECFieldElement X = this.RawXCoord;
+                if (X.IsZero)
+                {
+                    return false;
+                }
+
+                ECFieldElement Y = this.RawYCoord;
+
+                switch (this.CurveCoordinateSystem)
+                {
+                    case ECCurve.COORD_LAMBDA_AFFINE:
+                    case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                    {
+                        // Y is actually Lambda (X + Y/X) here
+                        return Y.TestBitZero() != X.TestBitZero();
+                    }
+                    default:
+                    {
+                        return Y.Divide(X).TestBitZero();
+                    }
+                }
+            }
+        }
+
+        /**
+         * 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 ArgumentException("Only points on the same curve can be added or subtracted");
 
 //			F2mFieldElement.CheckFieldElements(a.x, b.x);
-		}
-
-		/* (non-Javadoc)
-		 * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
-		 */
-		public override ECPoint Add(ECPoint b)
-		{
-			CheckPoints(this, b);
-			return AddSimple((F2mPoint) 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>
-		 */
-		internal F2mPoint AddSimple(F2mPoint b)
-		{
-			if (this.IsInfinity)
-				return b;
-
-			if (b.IsInfinity)
-				return this;
-
-			F2mFieldElement x2 = (F2mFieldElement) b.X;
-			F2mFieldElement y2 = (F2mFieldElement) b.Y;
-
-			// Check if b == this or b == -this
-			if (this.x.Equals(x2))
-			{
-				// this == b, i.e. this must be doubled
-				if (this.y.Equals(y2))
-					return (F2mPoint) this.Twice();
-
-				// this = -other, i.e. the result is the point at infinity
-				return (F2mPoint) this.curve.Infinity;
-			}
-
-			ECFieldElement xSum = this.x.Add(x2);
-
-			F2mFieldElement lambda
-				= (F2mFieldElement)(this.y.Add(y2)).Divide(xSum);
-
-			F2mFieldElement x3
-				= (F2mFieldElement)lambda.Square().Add(lambda).Add(xSum).Add(this.curve.A);
-
-			F2mFieldElement y3
-				= (F2mFieldElement)lambda.Multiply(this.x.Add(x3)).Add(x3).Add(this.y);
-
-			return new F2mPoint(curve, x3, y3, withCompression);
-		}
-
-		/* (non-Javadoc)
-		 * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
-		 */
-		public override ECPoint Subtract(
-			ECPoint b)
-		{
-			CheckPoints(this, b);
-			return SubtractSimple((F2mPoint) 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>
-		 */
-		internal F2mPoint SubtractSimple(
-			F2mPoint b)
-		{
-			if (b.IsInfinity)
-				return this;
-
-			// Add -b
-			return AddSimple((F2mPoint) b.Negate());
-		}
-
-		/* (non-Javadoc)
-		 * @see Org.BouncyCastle.Math.EC.ECPoint#twice()
-		 */
-		public override ECPoint Twice()
-		{
-			// Twice identity element (point at infinity) is identity
-			if (this.IsInfinity)
-				return this;
-
-			// if x1 == 0, then (x1, y1) == (x1, x1 + y1)
-			// and hence this = -this and thus 2(x1, y1) == infinity
-			if (this.x.ToBigInteger().SignValue == 0)
-				return this.curve.Infinity;
-
-			F2mFieldElement lambda = (F2mFieldElement) this.x.Add(this.y.Divide(this.x));
-			F2mFieldElement x2 = (F2mFieldElement)lambda.Square().Add(lambda).Add(this.curve.A);
-			ECFieldElement ONE = this.curve.FromBigInteger(BigInteger.One);
-			F2mFieldElement y2 = (F2mFieldElement)this.x.Square().Add(
-				x2.Multiply(lambda.Add(ONE)));
-
-			return new F2mPoint(this.curve, x2, y2, withCompression);
-		}
-
-		public override ECPoint Negate()
-		{
-			return new F2mPoint(curve, this.x, this.x.Add(this.y), withCompression);
-		}
-
-		/**
-		 * Sets the appropriate <code>ECMultiplier</code>, unless already set. 
-		 */
-		internal override void AssertECMultiplier()
-		{
-			if (this.multiplier == null)
-			{
-				lock (this)
-				{
-					if (this.multiplier == null)
-					{
-						if (((F2mCurve) this.curve).IsKoblitz)
-						{
-							this.multiplier = new WTauNafMultiplier();
-						}
-						else
-						{
-							this.multiplier = new WNafMultiplier();
-						}
-					}
-				}
-			}
-		}
-	}
+        }
+
+        /* (non-Javadoc)
+         * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
+         */
+        public override ECPoint Add(ECPoint b)
+        {
+            CheckPoints(this, b);
+            return AddSimple((F2mPoint) 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>
+         */
+        internal F2mPoint AddSimple(F2mPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            ECFieldElement X1 = this.RawXCoord;
+            ECFieldElement X2 = b.RawXCoord;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                {
+                    ECFieldElement Y1 = this.RawYCoord;
+                    ECFieldElement Y2 = b.RawYCoord;
+
+                    ECFieldElement dx = X1.Add(X2), dy = Y1.Add(Y2);
+                    if (dx.IsZero)
+                    {
+                        if (dy.IsZero)
+                        {
+                            return (F2mPoint)Twice();
+                        }
+
+                        return (F2mPoint)curve.Infinity;
+                    }
+
+                    ECFieldElement L = dy.Divide(dx);
+
+                    ECFieldElement X3 = L.Square().Add(L).Add(dx).Add(curve.A);
+                    ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+
+                    return new F2mPoint(curve, X3, Y3, IsCompressed);
+                }
+                case ECCurve.COORD_HOMOGENEOUS:
+                {
+                    ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+                    ECFieldElement Y2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+                    ECFieldElement U1 = Y2, V1 = X2;
+                    if (!Z1IsOne)
+                    {
+                        U1 = U1.Multiply(Z1);
+                        V1 = V1.Multiply(Z1);
+                    }
+
+                    bool Z2IsOne = Z2.IsOne;
+                    ECFieldElement U2 = Y1, V2 = X1;
+                    if (!Z2IsOne)
+                    {
+                        U2 = U2.Multiply(Z2);
+                        V2 = V2.Multiply(Z2);
+                    }
+
+                    ECFieldElement U = U1.Add(U2);
+                    ECFieldElement V = V1.Add(V2);
+
+                    if (V.IsZero)
+                    {
+                        if (U.IsZero)
+                        {
+                            return (F2mPoint)Twice();
+                        }
+
+                        return (F2mPoint)curve.Infinity;
+                    }
+
+                    ECFieldElement VSq = V.Square();
+                    ECFieldElement VCu = VSq.Multiply(V);
+                    ECFieldElement W = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2);
+                    ECFieldElement uv = U.Add(V);
+                    ECFieldElement A = uv.MultiplyPlusProduct(U, VSq, curve.A).Multiply(W).Add(VCu);
+
+                    ECFieldElement X3 = V.Multiply(A);
+                    ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.Multiply(Z2);
+                    ECFieldElement Y3 = U.MultiplyPlusProduct(X1, V, Y1).MultiplyPlusProduct(VSqZ2, uv, A);
+                    ECFieldElement Z3 = VCu.Multiply(W);
+
+                    return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+                case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                {
+                    if (X1.IsZero)
+                    {
+                        if (X2.IsZero)
+                            return (F2mPoint)curve.Infinity;
+
+                        return b.AddSimple(this);
+                    }
+
+                    ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+                    ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+                    ECFieldElement U2 = X2, S2 = L2;
+                    if (!Z1IsOne)
+                    {
+                        U2 = U2.Multiply(Z1);
+                        S2 = S2.Multiply(Z1);
+                    }
+
+                    bool Z2IsOne = Z2.IsOne;
+                    ECFieldElement U1 = X1, S1 = L1;
+                    if (!Z2IsOne)
+                    {
+                        U1 = U1.Multiply(Z2);
+                        S1 = S1.Multiply(Z2);
+                    }
+
+                    ECFieldElement A = S1.Add(S2);
+                    ECFieldElement B = U1.Add(U2);
+
+                    if (B.IsZero)
+                    {
+                        if (A.IsZero)
+                        {
+                            return (F2mPoint)Twice();
+                        }
+
+                        return (F2mPoint)curve.Infinity;
+                    }
+
+                    ECFieldElement X3, L3, Z3;
+                    if (X2.IsZero)
+                    {
+                        // TODO This can probably be optimized quite a bit
+                        ECPoint p = this.Normalize();
+                        X1 = p.RawXCoord;
+                        ECFieldElement Y1 = p.YCoord;
+
+                        ECFieldElement Y2 = L2;
+                        ECFieldElement L = Y1.Add(Y2).Divide(X1);
+
+                        X3 = L.Square().Add(L).Add(X1).Add(curve.A);
+                        if (X3.IsZero)
+                        {
+                            return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
+                        }
+
+                        ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1);
+                        L3 = Y3.Divide(X3).Add(X3);
+                        Z3 = curve.FromBigInteger(BigInteger.One);
+                    }
+                    else
+                    {
+                        B = B.Square();
+
+                        ECFieldElement AU1 = A.Multiply(U1);
+                        ECFieldElement AU2 = A.Multiply(U2);
+
+                        X3 = AU1.Multiply(AU2);
+                        if (X3.IsZero)
+                        {
+                            return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed);
+                        }
+
+                        ECFieldElement ABZ2 = A.Multiply(B);
+                        if (!Z2IsOne)
+                        {
+                            ABZ2 = ABZ2.Multiply(Z2);
+                        }
+
+                        L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1));
+
+                        Z3 = ABZ2;
+                        if (!Z1IsOne)
+                        {
+                            Z3 = Z3.Multiply(Z1);
+                        }
+                    }
+
+                    return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+                default:
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+            }
+        }
+
+        /* (non-Javadoc)
+         * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
+         */
+        public override ECPoint Subtract(
+            ECPoint b)
+        {
+            CheckPoints(this, b);
+            return SubtractSimple((F2mPoint) 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>
+         */
+        internal F2mPoint SubtractSimple(
+            F2mPoint b)
+        {
+            if (b.IsInfinity)
+                return this;
+
+            // Add -b
+            return AddSimple((F2mPoint) b.Negate());
+        }
+
+        public virtual F2mPoint Tau()
+        {
+            if (this.IsInfinity)
+            {
+                return this;
+            }
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            ECFieldElement X1 = this.RawXCoord;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                case ECCurve.COORD_LAMBDA_AFFINE:
+                {
+                    ECFieldElement Y1 = this.RawYCoord;
+                    return new F2mPoint(curve, X1.Square(), Y1.Square(), IsCompressed);
+                }
+                case ECCurve.COORD_HOMOGENEOUS:
+                case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                {
+                    ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+                    return new F2mPoint(curve, X1.Square(), Y1.Square(), new ECFieldElement[] { Z1.Square() }, IsCompressed);
+                }
+                default:
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+            }
+        }
+
+        /* (non-Javadoc)
+         * @see Org.BouncyCastle.Math.EC.ECPoint#twice()
+         */
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own additive inverse
+                return curve.Infinity;
+            }
+
+            int coord = curve.CoordinateSystem;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                {
+                    ECFieldElement Y1 = this.RawYCoord;
+
+                    ECFieldElement L1 = Y1.Divide(X1).Add(X1);
+
+                    ECFieldElement X3 = L1.Square().Add(L1).Add(curve.A);
+                    ECFieldElement Y3 = X1.SquarePlusProduct(X3, L1.AddOne());
+
+                    return new F2mPoint(curve, X3, Y3, IsCompressed);
+                }
+                case ECCurve.COORD_HOMOGENEOUS:
+                {
+                    ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+                    ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+                    ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.Multiply(Z1);
+
+                    ECFieldElement X1Sq = X1.Square();
+                    ECFieldElement S = X1Sq.Add(Y1Z1);
+                    ECFieldElement V = X1Z1;
+                    ECFieldElement vSquared = V.Square();
+                    ECFieldElement sv = S.Add(V);
+                    ECFieldElement h = sv.MultiplyPlusProduct(S, vSquared, curve.A);
+
+                    ECFieldElement X3 = V.Multiply(h);
+                    ECFieldElement Y3 = X1Sq.Square().MultiplyPlusProduct(V, h, sv);
+                    ECFieldElement Z3 = V.Multiply(vSquared);
+
+                    return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+                case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                {
+                    ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+
+                    bool Z1IsOne = Z1.IsOne;
+                    ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1);
+                    ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square();
+                    ECFieldElement a = curve.A;
+                    ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq);
+                    ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq);
+                    if (T.IsZero)
+                    {
+                        return new F2mPoint(curve, T, curve.B.Sqrt(), IsCompressed);
+                    }
+
+                    ECFieldElement X3 = T.Square();
+                    ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq);
+
+                    ECFieldElement b = curve.B;
+                    ECFieldElement L3;
+                    if (b.BitLength < (curve.FieldSize >> 1))
+                    {
+                        ECFieldElement t1 = L1.Add(X1).Square();
+                        ECFieldElement t2;
+                        if (b.IsOne)
+                        {
+                            t2 = aZ1Sq.Add(Z1Sq).Square();
+                        }
+                        else
+                        {
+                            // TODO Can be calculated with one square if we pre-compute sqrt(b)
+                            t2 = aZ1Sq.SquarePlusProduct(b, Z1Sq.Square());
+                        }
+                        L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3);
+                        if (a.IsZero)
+                        {
+                            L3 = L3.Add(Z3);
+                        }
+                        else if (!a.IsOne)
+                        {
+                            L3 = L3.Add(a.AddOne().Multiply(Z3));
+                        }
+                    }
+                    else
+                    {
+                        ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1);
+                        L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3);
+                    }
+
+                    return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+                default:
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+            }
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement X1 = this.RawXCoord;
+            if (X1.IsZero)
+            {
+                // A point with X == 0 is it's own additive inverse
+                return b;
+            }
+
+            int coord = curve.CoordinateSystem;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                {
+                    // NOTE: twicePlus() only optimized for lambda-affine argument
+                    ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0];
+                    if (X2.IsZero || !Z2.IsOne)
+                    {
+                        return Twice().Add(b);
+                    }
+
+                    ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0];
+                    ECFieldElement L2 = b.RawYCoord;
+
+                    ECFieldElement X1Sq = X1.Square();
+                    ECFieldElement L1Sq = L1.Square();
+                    ECFieldElement Z1Sq = Z1.Square();
+                    ECFieldElement L1Z1 = L1.Multiply(Z1);
+
+                    ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1);
+                    ECFieldElement L2plus1 = L2.AddOne();
+                    ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq);
+                    ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq);
+                    ECFieldElement B = X2Z1Sq.Add(T).Square();
+
+                    if (B.IsZero)
+                    {
+                        if (A.IsZero)
+                        {
+                            return b.Twice();
+                        }
+
+                        return curve.Infinity;
+                    }
+
+                    if (A.IsZero)
+                    {
+                        return new F2mPoint(curve, A, curve.B.Sqrt(), IsCompressed);
+                    }
+
+                    ECFieldElement X3 = A.Square().Multiply(X2Z1Sq);
+                    ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq);
+                    ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3);
+
+                    return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed);
+                }
+                default:
+                {
+                    return Twice().Add(b);
+                }
+            }
+        }
+
+        public override ECPoint Negate()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECFieldElement X = this.RawXCoord;
+            if (X.IsZero)
+                return this;
+
+            ECCurve curve = this.Curve;
+            int coord = curve.CoordinateSystem;
+
+            switch (coord)
+            {
+                case ECCurve.COORD_AFFINE:
+                {
+                    ECFieldElement Y = this.RawYCoord;
+                    return new F2mPoint(curve, X, Y.Add(X), IsCompressed);
+                }
+                case ECCurve.COORD_HOMOGENEOUS:
+                {
+                    ECFieldElement Y = this.RawYCoord, Z = this.RawZCoords[0];
+                    return new F2mPoint(curve, X, Y.Add(X), new ECFieldElement[] { Z }, IsCompressed);
+                }
+                case ECCurve.COORD_LAMBDA_AFFINE:
+                {
+                    ECFieldElement L = this.RawYCoord;
+                    return new F2mPoint(curve, X, L.AddOne(), IsCompressed);
+                }
+                case ECCurve.COORD_LAMBDA_PROJECTIVE:
+                {
+                    // L is actually Lambda (X + Y/X) here
+                    ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0];
+                    return new F2mPoint(curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed);
+                }
+                default:
+                {
+                    throw new InvalidOperationException("unsupported coordinate system");
+                }
+            }
+        }
+    }
 }
diff --git a/crypto/src/math/ec/ECPointMap.cs b/crypto/src/math/ec/ECPointMap.cs
new file mode 100644
index 000000000..e78c80065
--- /dev/null
+++ b/crypto/src/math/ec/ECPointMap.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    public interface ECPointMap
+    {
+        ECPoint Map(ECPoint p);
+    }
+}
diff --git a/crypto/src/math/ec/LongArray.cs b/crypto/src/math/ec/LongArray.cs
new file mode 100644
index 000000000..c4e3dacbc
--- /dev/null
+++ b/crypto/src/math/ec/LongArray.cs
@@ -0,0 +1,2201 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    internal class LongArray
+    {
+        //private static long DEInterleave_MASK = 0x5555555555555555L;
+
+        /*
+         * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
+         * In a binary field, this operation is the same as squaring an 8 bit number.
+         */
+        private static readonly int[] INTERLEAVE2_TABLE = new int[]
+        {
+            0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+            0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+            0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+            0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+            0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+            0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+            0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+            0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+            0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+            0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+            0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+            0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+            0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+            0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+            0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+            0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+            0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+            0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+            0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+            0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+            0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+            0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+            0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+            0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+            0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+            0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+            0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+            0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+            0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+            0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+            0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+            0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+        };
+
+        /*
+         * This expands 7 bit indices into 21 bit contents (high bit 18), by inserting 0s between bits.
+         */
+        private static readonly int[] INTERLEAVE3_TABLE = new  int[]
+        {
+            0x00000, 0x00001, 0x00008, 0x00009, 0x00040, 0x00041, 0x00048, 0x00049,
+            0x00200, 0x00201, 0x00208, 0x00209, 0x00240, 0x00241, 0x00248, 0x00249,
+            0x01000, 0x01001, 0x01008, 0x01009, 0x01040, 0x01041, 0x01048, 0x01049,
+            0x01200, 0x01201, 0x01208, 0x01209, 0x01240, 0x01241, 0x01248, 0x01249,
+            0x08000, 0x08001, 0x08008, 0x08009, 0x08040, 0x08041, 0x08048, 0x08049,
+            0x08200, 0x08201, 0x08208, 0x08209, 0x08240, 0x08241, 0x08248, 0x08249,
+            0x09000, 0x09001, 0x09008, 0x09009, 0x09040, 0x09041, 0x09048, 0x09049,
+            0x09200, 0x09201, 0x09208, 0x09209, 0x09240, 0x09241, 0x09248, 0x09249,
+            0x40000, 0x40001, 0x40008, 0x40009, 0x40040, 0x40041, 0x40048, 0x40049,
+            0x40200, 0x40201, 0x40208, 0x40209, 0x40240, 0x40241, 0x40248, 0x40249,
+            0x41000, 0x41001, 0x41008, 0x41009, 0x41040, 0x41041, 0x41048, 0x41049,
+            0x41200, 0x41201, 0x41208, 0x41209, 0x41240, 0x41241, 0x41248, 0x41249,
+            0x48000, 0x48001, 0x48008, 0x48009, 0x48040, 0x48041, 0x48048, 0x48049,
+            0x48200, 0x48201, 0x48208, 0x48209, 0x48240, 0x48241, 0x48248, 0x48249,
+            0x49000, 0x49001, 0x49008, 0x49009, 0x49040, 0x49041, 0x49048, 0x49049,
+            0x49200, 0x49201, 0x49208, 0x49209, 0x49240, 0x49241, 0x49248, 0x49249
+        };
+
+        /*
+         * This expands 8 bit indices into 32 bit contents (high bit 28), by inserting 0s between bits.
+         */
+        private static readonly int[] INTERLEAVE4_TABLE = new int[]
+        {
+            0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 0x00000101, 0x00000110, 0x00000111,
+            0x00001000, 0x00001001, 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 0x00001111,
+            0x00010000, 0x00010001, 0x00010010, 0x00010011, 0x00010100, 0x00010101, 0x00010110, 0x00010111,
+            0x00011000, 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, 0x00011110, 0x00011111,
+            0x00100000, 0x00100001, 0x00100010, 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111,
+            0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, 0x00101101, 0x00101110, 0x00101111,
+            0x00110000, 0x00110001, 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, 0x00110111,
+            0x00111000, 0x00111001, 0x00111010, 0x00111011, 0x00111100, 0x00111101, 0x00111110, 0x00111111,
+            0x01000000, 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, 0x01000110, 0x01000111,
+            0x01001000, 0x01001001, 0x01001010, 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111,
+            0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, 0x01010101, 0x01010110, 0x01010111,
+            0x01011000, 0x01011001, 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, 0x01011111,
+            0x01100000, 0x01100001, 0x01100010, 0x01100011, 0x01100100, 0x01100101, 0x01100110, 0x01100111,
+            0x01101000, 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, 0x01101110, 0x01101111,
+            0x01110000, 0x01110001, 0x01110010, 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111,
+            0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, 0x01111101, 0x01111110, 0x01111111,
+            0x10000000, 0x10000001, 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, 0x10000111,
+            0x10001000, 0x10001001, 0x10001010, 0x10001011, 0x10001100, 0x10001101, 0x10001110, 0x10001111,
+            0x10010000, 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, 0x10010110, 0x10010111,
+            0x10011000, 0x10011001, 0x10011010, 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111,
+            0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, 0x10100101, 0x10100110, 0x10100111,
+            0x10101000, 0x10101001, 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, 0x10101111,
+            0x10110000, 0x10110001, 0x10110010, 0x10110011, 0x10110100, 0x10110101, 0x10110110, 0x10110111,
+            0x10111000, 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, 0x10111110, 0x10111111,
+            0x11000000, 0x11000001, 0x11000010, 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111,
+            0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, 0x11001101, 0x11001110, 0x11001111,
+            0x11010000, 0x11010001, 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, 0x11010111,
+            0x11011000, 0x11011001, 0x11011010, 0x11011011, 0x11011100, 0x11011101, 0x11011110, 0x11011111,
+            0x11100000, 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, 0x11100110, 0x11100111,
+            0x11101000, 0x11101001, 0x11101010, 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111,
+            0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, 0x11110101, 0x11110110, 0x11110111,
+            0x11111000, 0x11111001, 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, 0x11111111
+        };
+
+        /*
+         * This expands 7 bit indices into 35 bit contents (high bit 30), by inserting 0s between bits.
+         */
+        private static readonly int[] INTERLEAVE5_TABLE = new int[] {
+            0x00000000, 0x00000001, 0x00000020, 0x00000021, 0x00000400, 0x00000401, 0x00000420, 0x00000421,
+            0x00008000, 0x00008001, 0x00008020, 0x00008021, 0x00008400, 0x00008401, 0x00008420, 0x00008421,
+            0x00100000, 0x00100001, 0x00100020, 0x00100021, 0x00100400, 0x00100401, 0x00100420, 0x00100421,
+            0x00108000, 0x00108001, 0x00108020, 0x00108021, 0x00108400, 0x00108401, 0x00108420, 0x00108421,
+            0x02000000, 0x02000001, 0x02000020, 0x02000021, 0x02000400, 0x02000401, 0x02000420, 0x02000421,
+            0x02008000, 0x02008001, 0x02008020, 0x02008021, 0x02008400, 0x02008401, 0x02008420, 0x02008421,
+            0x02100000, 0x02100001, 0x02100020, 0x02100021, 0x02100400, 0x02100401, 0x02100420, 0x02100421,
+            0x02108000, 0x02108001, 0x02108020, 0x02108021, 0x02108400, 0x02108401, 0x02108420, 0x02108421,
+            0x40000000, 0x40000001, 0x40000020, 0x40000021, 0x40000400, 0x40000401, 0x40000420, 0x40000421,
+            0x40008000, 0x40008001, 0x40008020, 0x40008021, 0x40008400, 0x40008401, 0x40008420, 0x40008421,
+            0x40100000, 0x40100001, 0x40100020, 0x40100021, 0x40100400, 0x40100401, 0x40100420, 0x40100421,
+            0x40108000, 0x40108001, 0x40108020, 0x40108021, 0x40108400, 0x40108401, 0x40108420, 0x40108421,
+            0x42000000, 0x42000001, 0x42000020, 0x42000021, 0x42000400, 0x42000401, 0x42000420, 0x42000421,
+            0x42008000, 0x42008001, 0x42008020, 0x42008021, 0x42008400, 0x42008401, 0x42008420, 0x42008421,
+            0x42100000, 0x42100001, 0x42100020, 0x42100021, 0x42100400, 0x42100401, 0x42100420, 0x42100421,
+            0x42108000, 0x42108001, 0x42108020, 0x42108021, 0x42108400, 0x42108401, 0x42108420, 0x42108421
+        };
+
+        /*
+         * This expands 9 bit indices into 63 bit (long) contents (high bit 56), by inserting 0s between bits.
+         */
+        private static readonly long[] INTERLEAVE7_TABLE = new long[]
+        {
+            0x0000000000000000L, 0x0000000000000001L, 0x0000000000000080L, 0x0000000000000081L,
+            0x0000000000004000L, 0x0000000000004001L, 0x0000000000004080L, 0x0000000000004081L,
+            0x0000000000200000L, 0x0000000000200001L, 0x0000000000200080L, 0x0000000000200081L,
+            0x0000000000204000L, 0x0000000000204001L, 0x0000000000204080L, 0x0000000000204081L,
+            0x0000000010000000L, 0x0000000010000001L, 0x0000000010000080L, 0x0000000010000081L,
+            0x0000000010004000L, 0x0000000010004001L, 0x0000000010004080L, 0x0000000010004081L,
+            0x0000000010200000L, 0x0000000010200001L, 0x0000000010200080L, 0x0000000010200081L,
+            0x0000000010204000L, 0x0000000010204001L, 0x0000000010204080L, 0x0000000010204081L,
+            0x0000000800000000L, 0x0000000800000001L, 0x0000000800000080L, 0x0000000800000081L,
+            0x0000000800004000L, 0x0000000800004001L, 0x0000000800004080L, 0x0000000800004081L,
+            0x0000000800200000L, 0x0000000800200001L, 0x0000000800200080L, 0x0000000800200081L,
+            0x0000000800204000L, 0x0000000800204001L, 0x0000000800204080L, 0x0000000800204081L,
+            0x0000000810000000L, 0x0000000810000001L, 0x0000000810000080L, 0x0000000810000081L,
+            0x0000000810004000L, 0x0000000810004001L, 0x0000000810004080L, 0x0000000810004081L,
+            0x0000000810200000L, 0x0000000810200001L, 0x0000000810200080L, 0x0000000810200081L,
+            0x0000000810204000L, 0x0000000810204001L, 0x0000000810204080L, 0x0000000810204081L,
+            0x0000040000000000L, 0x0000040000000001L, 0x0000040000000080L, 0x0000040000000081L,
+            0x0000040000004000L, 0x0000040000004001L, 0x0000040000004080L, 0x0000040000004081L,
+            0x0000040000200000L, 0x0000040000200001L, 0x0000040000200080L, 0x0000040000200081L,
+            0x0000040000204000L, 0x0000040000204001L, 0x0000040000204080L, 0x0000040000204081L,
+            0x0000040010000000L, 0x0000040010000001L, 0x0000040010000080L, 0x0000040010000081L,
+            0x0000040010004000L, 0x0000040010004001L, 0x0000040010004080L, 0x0000040010004081L,
+            0x0000040010200000L, 0x0000040010200001L, 0x0000040010200080L, 0x0000040010200081L,
+            0x0000040010204000L, 0x0000040010204001L, 0x0000040010204080L, 0x0000040010204081L,
+            0x0000040800000000L, 0x0000040800000001L, 0x0000040800000080L, 0x0000040800000081L,
+            0x0000040800004000L, 0x0000040800004001L, 0x0000040800004080L, 0x0000040800004081L,
+            0x0000040800200000L, 0x0000040800200001L, 0x0000040800200080L, 0x0000040800200081L,
+            0x0000040800204000L, 0x0000040800204001L, 0x0000040800204080L, 0x0000040800204081L,
+            0x0000040810000000L, 0x0000040810000001L, 0x0000040810000080L, 0x0000040810000081L,
+            0x0000040810004000L, 0x0000040810004001L, 0x0000040810004080L, 0x0000040810004081L,
+            0x0000040810200000L, 0x0000040810200001L, 0x0000040810200080L, 0x0000040810200081L,
+            0x0000040810204000L, 0x0000040810204001L, 0x0000040810204080L, 0x0000040810204081L,
+            0x0002000000000000L, 0x0002000000000001L, 0x0002000000000080L, 0x0002000000000081L,
+            0x0002000000004000L, 0x0002000000004001L, 0x0002000000004080L, 0x0002000000004081L,
+            0x0002000000200000L, 0x0002000000200001L, 0x0002000000200080L, 0x0002000000200081L,
+            0x0002000000204000L, 0x0002000000204001L, 0x0002000000204080L, 0x0002000000204081L,
+            0x0002000010000000L, 0x0002000010000001L, 0x0002000010000080L, 0x0002000010000081L,
+            0x0002000010004000L, 0x0002000010004001L, 0x0002000010004080L, 0x0002000010004081L,
+            0x0002000010200000L, 0x0002000010200001L, 0x0002000010200080L, 0x0002000010200081L,
+            0x0002000010204000L, 0x0002000010204001L, 0x0002000010204080L, 0x0002000010204081L,
+            0x0002000800000000L, 0x0002000800000001L, 0x0002000800000080L, 0x0002000800000081L,
+            0x0002000800004000L, 0x0002000800004001L, 0x0002000800004080L, 0x0002000800004081L,
+            0x0002000800200000L, 0x0002000800200001L, 0x0002000800200080L, 0x0002000800200081L,
+            0x0002000800204000L, 0x0002000800204001L, 0x0002000800204080L, 0x0002000800204081L,
+            0x0002000810000000L, 0x0002000810000001L, 0x0002000810000080L, 0x0002000810000081L,
+            0x0002000810004000L, 0x0002000810004001L, 0x0002000810004080L, 0x0002000810004081L,
+            0x0002000810200000L, 0x0002000810200001L, 0x0002000810200080L, 0x0002000810200081L,
+            0x0002000810204000L, 0x0002000810204001L, 0x0002000810204080L, 0x0002000810204081L,
+            0x0002040000000000L, 0x0002040000000001L, 0x0002040000000080L, 0x0002040000000081L,
+            0x0002040000004000L, 0x0002040000004001L, 0x0002040000004080L, 0x0002040000004081L,
+            0x0002040000200000L, 0x0002040000200001L, 0x0002040000200080L, 0x0002040000200081L,
+            0x0002040000204000L, 0x0002040000204001L, 0x0002040000204080L, 0x0002040000204081L,
+            0x0002040010000000L, 0x0002040010000001L, 0x0002040010000080L, 0x0002040010000081L,
+            0x0002040010004000L, 0x0002040010004001L, 0x0002040010004080L, 0x0002040010004081L,
+            0x0002040010200000L, 0x0002040010200001L, 0x0002040010200080L, 0x0002040010200081L,
+            0x0002040010204000L, 0x0002040010204001L, 0x0002040010204080L, 0x0002040010204081L,
+            0x0002040800000000L, 0x0002040800000001L, 0x0002040800000080L, 0x0002040800000081L,
+            0x0002040800004000L, 0x0002040800004001L, 0x0002040800004080L, 0x0002040800004081L,
+            0x0002040800200000L, 0x0002040800200001L, 0x0002040800200080L, 0x0002040800200081L,
+            0x0002040800204000L, 0x0002040800204001L, 0x0002040800204080L, 0x0002040800204081L,
+            0x0002040810000000L, 0x0002040810000001L, 0x0002040810000080L, 0x0002040810000081L,
+            0x0002040810004000L, 0x0002040810004001L, 0x0002040810004080L, 0x0002040810004081L,
+            0x0002040810200000L, 0x0002040810200001L, 0x0002040810200080L, 0x0002040810200081L,
+            0x0002040810204000L, 0x0002040810204001L, 0x0002040810204080L, 0x0002040810204081L,
+            0x0100000000000000L, 0x0100000000000001L, 0x0100000000000080L, 0x0100000000000081L,
+            0x0100000000004000L, 0x0100000000004001L, 0x0100000000004080L, 0x0100000000004081L,
+            0x0100000000200000L, 0x0100000000200001L, 0x0100000000200080L, 0x0100000000200081L,
+            0x0100000000204000L, 0x0100000000204001L, 0x0100000000204080L, 0x0100000000204081L,
+            0x0100000010000000L, 0x0100000010000001L, 0x0100000010000080L, 0x0100000010000081L,
+            0x0100000010004000L, 0x0100000010004001L, 0x0100000010004080L, 0x0100000010004081L,
+            0x0100000010200000L, 0x0100000010200001L, 0x0100000010200080L, 0x0100000010200081L,
+            0x0100000010204000L, 0x0100000010204001L, 0x0100000010204080L, 0x0100000010204081L,
+            0x0100000800000000L, 0x0100000800000001L, 0x0100000800000080L, 0x0100000800000081L,
+            0x0100000800004000L, 0x0100000800004001L, 0x0100000800004080L, 0x0100000800004081L,
+            0x0100000800200000L, 0x0100000800200001L, 0x0100000800200080L, 0x0100000800200081L,
+            0x0100000800204000L, 0x0100000800204001L, 0x0100000800204080L, 0x0100000800204081L,
+            0x0100000810000000L, 0x0100000810000001L, 0x0100000810000080L, 0x0100000810000081L,
+            0x0100000810004000L, 0x0100000810004001L, 0x0100000810004080L, 0x0100000810004081L,
+            0x0100000810200000L, 0x0100000810200001L, 0x0100000810200080L, 0x0100000810200081L,
+            0x0100000810204000L, 0x0100000810204001L, 0x0100000810204080L, 0x0100000810204081L,
+            0x0100040000000000L, 0x0100040000000001L, 0x0100040000000080L, 0x0100040000000081L,
+            0x0100040000004000L, 0x0100040000004001L, 0x0100040000004080L, 0x0100040000004081L,
+            0x0100040000200000L, 0x0100040000200001L, 0x0100040000200080L, 0x0100040000200081L,
+            0x0100040000204000L, 0x0100040000204001L, 0x0100040000204080L, 0x0100040000204081L,
+            0x0100040010000000L, 0x0100040010000001L, 0x0100040010000080L, 0x0100040010000081L,
+            0x0100040010004000L, 0x0100040010004001L, 0x0100040010004080L, 0x0100040010004081L,
+            0x0100040010200000L, 0x0100040010200001L, 0x0100040010200080L, 0x0100040010200081L,
+            0x0100040010204000L, 0x0100040010204001L, 0x0100040010204080L, 0x0100040010204081L,
+            0x0100040800000000L, 0x0100040800000001L, 0x0100040800000080L, 0x0100040800000081L,
+            0x0100040800004000L, 0x0100040800004001L, 0x0100040800004080L, 0x0100040800004081L,
+            0x0100040800200000L, 0x0100040800200001L, 0x0100040800200080L, 0x0100040800200081L,
+            0x0100040800204000L, 0x0100040800204001L, 0x0100040800204080L, 0x0100040800204081L,
+            0x0100040810000000L, 0x0100040810000001L, 0x0100040810000080L, 0x0100040810000081L,
+            0x0100040810004000L, 0x0100040810004001L, 0x0100040810004080L, 0x0100040810004081L,
+            0x0100040810200000L, 0x0100040810200001L, 0x0100040810200080L, 0x0100040810200081L,
+            0x0100040810204000L, 0x0100040810204001L, 0x0100040810204080L, 0x0100040810204081L,
+            0x0102000000000000L, 0x0102000000000001L, 0x0102000000000080L, 0x0102000000000081L,
+            0x0102000000004000L, 0x0102000000004001L, 0x0102000000004080L, 0x0102000000004081L,
+            0x0102000000200000L, 0x0102000000200001L, 0x0102000000200080L, 0x0102000000200081L,
+            0x0102000000204000L, 0x0102000000204001L, 0x0102000000204080L, 0x0102000000204081L,
+            0x0102000010000000L, 0x0102000010000001L, 0x0102000010000080L, 0x0102000010000081L,
+            0x0102000010004000L, 0x0102000010004001L, 0x0102000010004080L, 0x0102000010004081L,
+            0x0102000010200000L, 0x0102000010200001L, 0x0102000010200080L, 0x0102000010200081L,
+            0x0102000010204000L, 0x0102000010204001L, 0x0102000010204080L, 0x0102000010204081L,
+            0x0102000800000000L, 0x0102000800000001L, 0x0102000800000080L, 0x0102000800000081L,
+            0x0102000800004000L, 0x0102000800004001L, 0x0102000800004080L, 0x0102000800004081L,
+            0x0102000800200000L, 0x0102000800200001L, 0x0102000800200080L, 0x0102000800200081L,
+            0x0102000800204000L, 0x0102000800204001L, 0x0102000800204080L, 0x0102000800204081L,
+            0x0102000810000000L, 0x0102000810000001L, 0x0102000810000080L, 0x0102000810000081L,
+            0x0102000810004000L, 0x0102000810004001L, 0x0102000810004080L, 0x0102000810004081L,
+            0x0102000810200000L, 0x0102000810200001L, 0x0102000810200080L, 0x0102000810200081L,
+            0x0102000810204000L, 0x0102000810204001L, 0x0102000810204080L, 0x0102000810204081L,
+            0x0102040000000000L, 0x0102040000000001L, 0x0102040000000080L, 0x0102040000000081L,
+            0x0102040000004000L, 0x0102040000004001L, 0x0102040000004080L, 0x0102040000004081L,
+            0x0102040000200000L, 0x0102040000200001L, 0x0102040000200080L, 0x0102040000200081L,
+            0x0102040000204000L, 0x0102040000204001L, 0x0102040000204080L, 0x0102040000204081L,
+            0x0102040010000000L, 0x0102040010000001L, 0x0102040010000080L, 0x0102040010000081L,
+            0x0102040010004000L, 0x0102040010004001L, 0x0102040010004080L, 0x0102040010004081L,
+            0x0102040010200000L, 0x0102040010200001L, 0x0102040010200080L, 0x0102040010200081L,
+            0x0102040010204000L, 0x0102040010204001L, 0x0102040010204080L, 0x0102040010204081L,
+            0x0102040800000000L, 0x0102040800000001L, 0x0102040800000080L, 0x0102040800000081L,
+            0x0102040800004000L, 0x0102040800004001L, 0x0102040800004080L, 0x0102040800004081L,
+            0x0102040800200000L, 0x0102040800200001L, 0x0102040800200080L, 0x0102040800200081L,
+            0x0102040800204000L, 0x0102040800204001L, 0x0102040800204080L, 0x0102040800204081L,
+            0x0102040810000000L, 0x0102040810000001L, 0x0102040810000080L, 0x0102040810000081L,
+            0x0102040810004000L, 0x0102040810004001L, 0x0102040810004080L, 0x0102040810004081L,
+            0x0102040810200000L, 0x0102040810200001L, 0x0102040810200080L, 0x0102040810200081L,
+            0x0102040810204000L, 0x0102040810204001L, 0x0102040810204080L, 0x0102040810204081L
+        };
+
+        // For toString(); must have length 64
+        private const string ZEROES = "0000000000000000000000000000000000000000000000000000000000000000";
+
+        internal static readonly byte[] BitLengths =
+        {
+            0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
+            5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+            6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+            6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+            8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
+        };
+
+        // TODO make m fixed for the LongArray, and hence compute T once and for all
+
+        private long[] m_ints;
+
+        public LongArray(int intLen)
+        {
+            m_ints = new long[intLen];
+        }
+
+        public LongArray(long[] ints)
+        {
+            m_ints = ints;
+        }
+
+        public LongArray(long[] ints, int off, int len)
+        {
+            if (off == 0 && len == ints.Length)
+            {
+                m_ints = ints;
+            }
+            else
+            {
+                m_ints = new long[len];
+                Array.Copy(ints, off, m_ints, 0, len);
+            }
+        }
+
+        public LongArray(BigInteger bigInt)
+        {
+            if (bigInt == null || bigInt.SignValue < 0)
+            {
+                throw new ArgumentException("invalid F2m field value", "bigInt");
+            }
+
+            if (bigInt.SignValue == 0)
+            {
+                m_ints = new long[] { 0L };
+                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 + 7) / 8;
+            m_ints = new long[intLen];
+
+            int iarrJ = intLen - 1;
+            int rem = barrLen % 8 + barrStart;
+            long temp = 0;
+            int barrI = barrStart;
+            if (barrStart < rem)
+            {
+                for (; barrI < rem; barrI++)
+                {
+                    temp <<= 8;
+                    uint barrBarrI = barr[barrI];
+                    temp |= barrBarrI;
+                }
+                m_ints[iarrJ--] = temp;
+            }
+
+            for (; iarrJ >= 0; iarrJ--)
+            {
+                temp = 0;
+                for (int i = 0; i < 8; i++)
+                {
+                    temp <<= 8;
+                    uint barrBarrI = barr[barrI++];
+                    temp |= barrBarrI;
+                }
+                m_ints[iarrJ] = temp;
+            }
+        }
+
+        public bool IsOne()
+        {
+            long[] a = m_ints;
+            if (a[0] != 1L)
+            {
+                return false;
+            }
+            for (int i = 1; i < a.Length; ++i)
+            {
+                if (a[i] != 0L)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public bool IsZero()
+        {
+            long[] a = m_ints;
+            for (int i = 0; i < a.Length; ++i)
+            {
+                if (a[i] != 0L)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public int GetUsedLength()
+        {
+            return GetUsedLengthFrom(m_ints.Length);
+        }
+
+        public int GetUsedLengthFrom(int from)
+        {
+            long[] a = m_ints;
+            from = System.Math.Min(from, a.Length);
+
+            if (from < 1)
+            {
+                return 0;
+            }
+
+            // Check if first element will act as sentinel
+            if (a[0] != 0)
+            {
+                while (a[--from] == 0)
+                {
+                }
+                return from + 1;
+            }
+
+            do
+            {
+                if (a[--from] != 0)
+                {
+                    return from + 1;
+                }
+            }
+            while (from > 0);
+
+            return 0;
+        }
+
+        public int Degree()
+        {
+            int i = m_ints.Length;
+            long w;
+            do
+            {
+                if (i == 0)
+                {
+                    return 0;
+                }
+                w = m_ints[--i];
+            }
+            while (w == 0);
+
+            return (i << 6) + BitLength(w);
+        }
+
+        private int DegreeFrom(int limit)
+        {
+            int i = (int)(((uint)limit + 62) >> 6);
+            long w;
+            do
+            {
+                if (i == 0)
+                {
+                    return 0;
+                }
+                w = m_ints[--i];
+            }
+            while (w == 0);
+
+            return (i << 6) + BitLength(w);
+        }
+
+    //    private int lowestCoefficient()
+    //    {
+    //        for (int i = 0; i < m_ints.Length; ++i)
+    //        {
+    //            long mi = m_ints[i];
+    //            if (mi != 0)
+    //            {
+    //                int j = 0;
+    //                while ((mi & 0xFFL) == 0)
+    //                {
+    //                    j += 8;
+    //                    mi >>>= 8;
+    //                }
+    //                while ((mi & 1L) == 0)
+    //                {
+    //                    ++j;
+    //                    mi >>>= 1;
+    //                }
+    //                return (i << 6) + j;
+    //            }
+    //        }
+    //        return -1;
+    //    }
+
+        private static int BitLength(long w)
+        {
+            int u = (int)((ulong)w >> 32), b;
+            if (u == 0)
+            {
+                u = (int)w;
+                b = 0;
+            }
+            else
+            {
+                b = 32;
+            }
+
+            int t = (int)((uint)u >> 16), k;
+            if (t == 0)
+            {
+                t = (int)((uint)u >> 8);
+                k = (t == 0) ? BitLengths[u] : 8 + BitLengths[t];
+            }
+            else
+            {
+                int v = (int)((uint)t >> 8);
+                k = (v == 0) ? 16 + BitLengths[t] : 24 + BitLengths[v];
+            }
+
+            return b + k;
+        }
+
+        private long[] ResizedInts(int newLen)
+        {
+            long[] newInts = new long[newLen];
+            Array.Copy(m_ints, 0, newInts, 0, System.Math.Min(m_ints.Length, newLen));
+            return newInts;
+        }
+
+        public BigInteger ToBigInteger()
+        {
+            int usedLen = GetUsedLength();
+            if (usedLen == 0)
+            {
+                return BigInteger.Zero;
+            }
+
+            long highestInt = m_ints[usedLen - 1];
+            byte[] temp = new byte[8];
+            int barrI = 0;
+            bool trailingZeroBytesDone = false;
+            for (int j = 7; j >= 0; j--)
+            {
+                byte thisByte = (byte)((ulong)highestInt >> (8 * j));
+                if (trailingZeroBytesDone || (thisByte != 0))
+                {
+                    trailingZeroBytesDone = true;
+                    temp[barrI++] = thisByte;
+                }
+            }
+
+            int barrLen = 8 * (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--)
+            {
+                long mi = m_ints[iarrJ];
+                for (int j = 7; j >= 0; j--)
+                {
+                    barr[barrI++] = (byte)((ulong)mi >> (8 * j));
+                }
+            }
+            return new BigInteger(1, barr);
+        }
+
+    //    private static long shiftUp(long[] x, int xOff, int count)
+    //    {
+    //        long prev = 0;
+    //        for (int i = 0; i < count; ++i)
+    //        {
+    //            long next = x[xOff + i];
+    //            x[xOff + i] = (next << 1) | prev;
+    //            prev = next >>> 63;
+    //        }
+    //        return prev;
+    //    }
+
+        private static long ShiftUp(long[] x, int xOff, int count, int shift)
+        {
+            int shiftInv = 64 - shift;
+            long prev = 0;
+            for (int i = 0; i < count; ++i)
+            {
+                long next = x[xOff + i];
+                x[xOff + i] = (next << shift) | prev;
+                prev = (long)((ulong)next >> shiftInv);
+            }
+            return prev;
+        }
+
+        private static long ShiftUp(long[] x, int xOff, long[] z, int zOff, int count, int shift)
+        {
+            int shiftInv = 64 - shift;
+            long prev = 0;
+            for (int i = 0; i < count; ++i)
+            {
+                long next = x[xOff + i];
+                z[zOff + i] = (next << shift) | prev;
+                prev = (long)((ulong)next >> shiftInv);
+            }
+            return prev;
+        }
+
+        public LongArray AddOne()
+        {
+            if (m_ints.Length == 0)
+            {
+                return new LongArray(new long[]{ 1L });
+            }
+
+            int resultLen = System.Math.Max(1, GetUsedLength());
+            long[] ints = ResizedInts(resultLen);
+            ints[0] ^= 1L;
+            return new LongArray(ints);
+        }
+
+    //    private void addShiftedByBits(LongArray other, int bits)
+    //    {
+    //        int words = bits >>> 6;
+    //        int shift = bits & 0x3F;
+    //
+    //        if (shift == 0)
+    //        {
+    //            addShiftedByWords(other, words);
+    //            return;
+    //        }
+    //
+    //        int otherUsedLen = other.GetUsedLength();
+    //        if (otherUsedLen == 0)
+    //        {
+    //            return;
+    //        }
+    //
+    //        int minLen = otherUsedLen + words + 1;
+    //        if (minLen > m_ints.Length)
+    //        {
+    //            m_ints = resizedInts(minLen);
+    //        }
+    //
+    //        long carry = addShiftedByBits(m_ints, words, other.m_ints, 0, otherUsedLen, shift);
+    //        m_ints[otherUsedLen + words] ^= carry;
+    //    }
+
+        private void AddShiftedByBitsSafe(LongArray other, int otherDegree, int bits)
+        {
+            int otherLen = (int)((uint)(otherDegree + 63) >> 6);
+
+            int words = (int)((uint)bits >> 6);
+            int shift = bits & 0x3F;
+
+            if (shift == 0)
+            {
+                Add(m_ints, words, other.m_ints, 0, otherLen);
+                return;
+            }
+
+            long carry = AddShiftedUp(m_ints, words, other.m_ints, 0, otherLen, shift);
+            if (carry != 0L)
+            {
+                m_ints[otherLen + words] ^= carry;
+            }
+        }
+
+        private static long AddShiftedUp(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+        {
+            int shiftInv = 64 - shift;
+            long prev = 0;
+            for (int i = 0; i < count; ++i)
+            {
+                long next = y[yOff + i];
+                x[xOff + i] ^= (next << shift) | prev;
+                prev = (long)((ulong)next >> shiftInv);
+            }
+            return prev;
+        }
+
+        private static long AddShiftedDown(long[] x, int xOff, long[] y, int yOff, int count, int shift)
+        {
+            int shiftInv = 64 - shift;
+            long prev = 0;
+            int i = count;
+            while (--i >= 0)
+            {
+                long next = y[yOff + i];
+                x[xOff + i] ^= (long)((ulong)next >> shift) | prev;
+                prev = next << shiftInv;
+            }
+            return prev;
+        }
+
+        public void AddShiftedByWords(LongArray other, int words)
+        {
+            int otherUsedLen = other.GetUsedLength();
+            if (otherUsedLen == 0)
+            {
+                return;
+            }
+
+            int minLen = otherUsedLen + words;
+            if (minLen > m_ints.Length)
+            {
+                m_ints = ResizedInts(minLen);
+            }
+
+            Add(m_ints, words, other.m_ints, 0, otherUsedLen);
+        }
+
+        private static void Add(long[] x, int xOff, long[] y, int yOff, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                x[xOff + i] ^= y[yOff + i];
+            }
+        }
+
+        private static void Add(long[] x, int xOff, long[] y, int yOff, long[] z, int zOff, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+            }
+        }
+
+        private static void AddBoth(long[] x, int xOff, long[] y1, int y1Off, long[] y2, int y2Off, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                x[xOff + i] ^= y1[y1Off + i] ^ y2[y2Off + i];
+            }
+        }
+
+        private static void Distribute(long[] x, int src, int dst1, int dst2, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                long v = x[src + i];
+                x[dst1 + i] ^= v;
+                x[dst2 + i] ^= v;
+            }
+        }
+
+        public int Length
+        {
+            get { return m_ints.Length; }
+        }
+
+        private static void FlipWord(long[] buf, int off, int bit, long word)
+        {
+            int n = off + (int)((uint)bit >> 6);
+            int shift = bit & 0x3F;
+            if (shift == 0)
+            {
+                buf[n] ^= word;
+            }
+            else
+            {
+                buf[n] ^= word << shift;
+                word = (long)((ulong)word >> (64 - shift));
+                if (word != 0)
+                {
+                    buf[++n] ^= word;
+                }
+            }
+        }
+
+    //    private static long getWord(long[] buf, int off, int len, int bit)
+    //    {
+    //        int n = off + (bit >>> 6);
+    //        int shift = bit & 0x3F;
+    //        if (shift == 0)
+    //        {
+    //            return buf[n];
+    //        }
+    //        long result = buf[n] >>> shift;
+    //        if (++n < len)
+    //        {
+    //            result |= buf[n] << (64 - shift);
+    //        }
+    //        return result;
+    //    }
+
+        public bool TestBitZero()
+        {
+            return m_ints.Length > 0 && (m_ints[0] & 1L) != 0;
+        }
+
+        private static bool TestBit(long[] buf, int off, int n)
+        {
+            // theInt = n / 64
+            int theInt = (int)((uint)n >> 6);
+            // theBit = n % 64
+            int theBit = n & 0x3F;
+            long tester = 1L << theBit;
+            return (buf[off + theInt] & tester) != 0;
+        }
+
+        private static void FlipBit(long[] buf, int off, int n)
+        {
+            // theInt = n / 64
+            int theInt = (int)((uint)n >> 6);
+            // theBit = n % 64
+            int theBit = n & 0x3F;
+            long flipper = 1L << theBit;
+            buf[off + theInt] ^= flipper;
+        }
+
+    //    private static void SetBit(long[] buf, int off, int n)
+    //    {
+    //        // theInt = n / 64
+    //        int theInt = n >>> 6;
+    //        // theBit = n % 64
+    //        int theBit = n & 0x3F;
+    //        long setter = 1L << theBit;
+    //        buf[off + theInt] |= setter;
+    //    }
+    //
+    //    private static void ClearBit(long[] buf, int off, int n)
+    //    {
+    //        // theInt = n / 64
+    //        int theInt = n >>> 6;
+    //        // theBit = n % 64
+    //        int theBit = n & 0x3F;
+    //        long setter = 1L << theBit;
+    //        buf[off + theInt] &= ~setter;
+    //    }
+
+        private static void MultiplyWord(long a, long[] b, int bLen, long[] c, int cOff)
+        {
+            if ((a & 1L) != 0L)
+            {
+                Add(c, cOff, b, 0, bLen);
+            }
+            int k = 1;
+            while ((a = (long)((ulong)a >> 1)) != 0L)
+            {
+                if ((a & 1L) != 0L)
+                {
+                    long carry = AddShiftedUp(c, cOff, b, 0, bLen, k);
+                    if (carry != 0L)
+                    {
+                        c[cOff + bLen] ^= carry;
+                    }
+                }
+                ++k;
+            }
+        }
+
+        public LongArray ModMultiplyLD(LongArray other, int m, int[] ks)
+        {
+            /*
+             * Find out the degree of each argument and handle the zero cases
+             */
+            int aDeg = Degree();
+            if (aDeg == 0)
+            {
+                return this;
+            }
+            int bDeg = other.Degree();
+            if (bDeg == 0)
+            {
+                return other;
+            }
+
+            /*
+             * Swap if necessary so that A is the smaller argument
+             */
+            LongArray A = this, B = other;
+            if (aDeg > bDeg)
+            {
+                A = other; B = this;
+                int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+            }
+
+            /*
+             * Establish the word lengths of the arguments and result
+             */
+            int aLen = (int)((uint)(aDeg + 63) >> 6);
+            int bLen = (int)((uint)(bDeg + 63) >> 6);
+            int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+            if (aLen == 1)
+            {
+                long a0 = A.m_ints[0];
+                if (a0 == 1L)
+                {
+                    return B;
+                }
+
+                /*
+                 * Fast path for small A, with performance dependent only on the number of set bits
+                 */
+                long[] c0 = new long[cLen];
+                MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+                /*
+                 * Reduce the raw answer against the reduction coefficients
+                 */
+                return ReduceResult(c0, 0, cLen, m, ks);
+            }
+
+            /*
+             * Determine if B will get bigger during shifting
+             */
+            int bMax = (int)((uint)(bDeg + 7 + 63) >> 6);
+
+            /*
+             * Lookup table for the offset of each B in the tables
+             */
+            int[] ti = new int[16];
+
+            /*
+             * Precompute table of all 4-bit products of B
+             */
+            long[] T0 = new long[bMax << 4];
+            int tOff = bMax;
+            ti[1] = tOff;
+            Array.Copy(B.m_ints, 0, T0, tOff, bLen);
+            for (int i = 2; i < 16; ++i)
+            {
+                ti[i] = (tOff += bMax);
+                if ((i & 1) == 0)
+                {
+                    ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1);
+                }
+                else
+                {
+                    Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+                }
+            }
+
+            /*
+             * Second table with all 4-bit products of B shifted 4 bits
+             */
+            long[] T1 = new long[T0.Length];
+            ShiftUp(T0, 0, T1, 0, T0.Length, 4);
+    //        shiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+            long[] a = A.m_ints;
+            long[] c = new long[cLen];
+
+            int MASK = 0xF;
+
+            /*
+             * Lopez-Dahab algorithm
+             */
+
+            for (int k = 56; k >= 0; k -= 8)
+            {
+                for (int j = 1; j < aLen; j += 2)
+                {
+                    int aVal = (int)((ulong)a[j] >> k);
+                    int u = aVal & MASK;
+                    int v = (int)((uint)aVal >> 4) & MASK;
+                    AddBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax);
+                }
+                ShiftUp(c, 0, cLen, 8);
+            }
+
+            for (int k = 56; k >= 0; k -= 8)
+            {
+                for (int j = 0; j < aLen; j += 2)
+                {
+                    int aVal = (int)((ulong)a[j] >> k);
+                    int u = aVal & MASK;
+                    int v = (int)((uint)aVal >> 4) & MASK;
+                    AddBoth(c, j, T0, ti[u], T1, ti[v], bMax);
+                }
+                if (k > 0)
+                {
+                    ShiftUp(c, 0, cLen, 8);
+                }
+            }
+
+            /*
+             * Finally the raw answer is collected, reduce it against the reduction coefficients
+             */
+            return ReduceResult(c, 0, cLen, m, ks);
+        }
+
+        public LongArray ModMultiply(LongArray other, int m, int[] ks)
+        {
+            /*
+             * Find out the degree of each argument and handle the zero cases
+             */
+            int aDeg = Degree();
+            if (aDeg == 0)
+            {
+                return this;
+            }
+            int bDeg = other.Degree();
+            if (bDeg == 0)
+            {
+                return other;
+            }
+
+            /*
+             * Swap if necessary so that A is the smaller argument
+             */
+            LongArray A = this, B = other;
+            if (aDeg > bDeg)
+            {
+                A = other; B = this;
+                int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+            }
+
+            /*
+             * Establish the word lengths of the arguments and result
+             */
+            int aLen = (int)((uint)(aDeg + 63) >> 6);
+            int bLen = (int)((uint)(bDeg + 63) >> 6);
+            int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+            if (aLen == 1)
+            {
+                long a0 = A.m_ints[0];
+                if (a0 == 1L)
+                {
+                    return B;
+                }
+
+                /*
+                 * Fast path for small A, with performance dependent only on the number of set bits
+                 */
+                long[] c0 = new long[cLen];
+                MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+                /*
+                 * Reduce the raw answer against the reduction coefficients
+                 */
+                return ReduceResult(c0, 0, cLen, m, ks);
+            }
+
+            /*
+             * Determine if B will get bigger during shifting
+             */
+            int bMax = (int)((uint)(bDeg + 7 + 63) >> 6);
+
+            /*
+             * Lookup table for the offset of each B in the tables
+             */
+            int[] ti = new int[16];
+
+            /*
+             * Precompute table of all 4-bit products of B
+             */
+            long[] T0 = new long[bMax << 4];
+            int tOff = bMax;
+            ti[1] = tOff;
+            Array.Copy(B.m_ints, 0, T0, tOff, bLen);
+            for (int i = 2; i < 16; ++i)
+            {
+                ti[i] = (tOff += bMax);
+                if ((i & 1) == 0)
+                {
+                    ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1);
+                }
+                else
+                {
+                    Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+                }
+            }
+
+            /*
+             * Second table with all 4-bit products of B shifted 4 bits
+             */
+            long[] T1 = new long[T0.Length];
+            ShiftUp(T0, 0, T1, 0, T0.Length, 4);
+    //        ShiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+            long[] a = A.m_ints;
+            long[] c = new long[cLen << 3];
+
+            int MASK = 0xF;
+
+            /*
+             * Lopez-Dahab (Modified) algorithm
+             */
+
+            for (int aPos = 0; aPos < aLen; ++aPos)
+            {
+                long aVal = a[aPos];
+                int cOff = aPos;
+                for (;;)
+                {
+                    int u = (int)aVal & MASK;
+                    aVal = (long)((ulong)aVal >> 4);
+                    int v = (int)aVal & MASK;
+                    AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
+                    aVal = (long)((ulong)aVal >> 4);
+                    if (aVal == 0L)
+                    {
+                        break;
+                    }
+                    cOff += cLen;
+                }
+            }
+
+            {
+                int cOff = c.Length;
+                while ((cOff -= cLen) != 0)
+                {
+                    AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
+                }
+            }
+
+            /*
+             * Finally the raw answer is collected, reduce it against the reduction coefficients
+             */
+            return ReduceResult(c, 0, cLen, m, ks);
+        }
+
+        public LongArray ModMultiplyAlt(LongArray other, int m, int[] ks)
+        {
+            /*
+             * Find out the degree of each argument and handle the zero cases
+             */
+            int aDeg = Degree();
+            if (aDeg == 0)
+            {
+                return this;
+            }
+            int bDeg = other.Degree();
+            if (bDeg == 0)
+            {
+                return other;
+            }
+
+            /*
+             * Swap if necessary so that A is the smaller argument
+             */
+            LongArray A = this, B = other;
+            if (aDeg > bDeg)
+            {
+                A = other; B = this;
+                int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+            }
+
+            /*
+             * Establish the word lengths of the arguments and result
+             */
+            int aLen = (int)((uint)(aDeg + 63) >> 6);
+            int bLen = (int)((uint)(bDeg + 63) >> 6);
+            int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+            if (aLen == 1)
+            {
+                long a0 = A.m_ints[0];
+                if (a0 == 1L)
+                {
+                    return B;
+                }
+
+                /*
+                 * Fast path for small A, with performance dependent only on the number of set bits
+                 */
+                long[] c0 = new long[cLen];
+                MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+                /*
+                 * Reduce the raw answer against the reduction coefficients
+                 */
+                return ReduceResult(c0, 0, cLen, m, ks);
+            }
+
+            // NOTE: This works, but is slower than width 4 processing
+    //        if (aLen == 2)
+    //        {
+    //            /*
+    //             * Use common-multiplicand optimization to save ~1/4 of the adds
+    //             */
+    //            long a1 = A.m_ints[0], a2 = A.m_ints[1];
+    //            long aa = a1 & a2; a1 ^= aa; a2 ^= aa;
+    //
+    //            long[] b = B.m_ints;
+    //            long[] c = new long[cLen];
+    //            multiplyWord(aa, b, bLen, c, 1);
+    //            add(c, 0, c, 1, cLen - 1);
+    //            multiplyWord(a1, b, bLen, c, 0);
+    //            multiplyWord(a2, b, bLen, c, 1);
+    //
+    //            /*
+    //             * Reduce the raw answer against the reduction coefficients
+    //             */
+    //            return ReduceResult(c, 0, cLen, m, ks);
+    //        }
+
+            /*
+             * Determine the parameters of the Interleaved window algorithm: the 'width' in bits to
+             * process together, the number of evaluation 'positions' implied by that width, and the
+             * 'top' position at which the regular window algorithm stops.
+             */
+            int width, positions, top, banks;
+
+            // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto 
+    //        width = 1; positions = 64; top = 64; banks = 4;
+    //        width = 2; positions = 32; top = 64; banks = 4;
+    //        width = 3; positions = 21; top = 63; banks = 3;
+            width = 4; positions = 16; top = 64; banks = 8;
+    //        width = 5; positions = 13; top = 65; banks = 7;
+    //        width = 7; positions = 9; top = 63; banks = 9;
+    //        width = 8; positions = 8; top = 64; banks = 8;
+
+            /*
+             * Determine if B will get bigger during shifting
+             */
+            int shifts = top < 64 ? positions : positions - 1;
+            int bMax = (int)((uint)(bDeg + shifts + 63) >> 6);
+
+            int bTotal = bMax * banks, stride = width * banks;
+
+            /*
+             * Create a single temporary buffer, with an offset table to find the positions of things in it 
+             */
+            int[] ci = new int[1 << width];
+            int cTotal = aLen;
+            {
+                ci[0] = cTotal;
+                cTotal += bTotal;
+                ci[1] = cTotal;
+                for (int i = 2; i < ci.Length; ++i)
+                {
+                    cTotal += cLen;
+                    ci[i] = cTotal;
+                }
+                cTotal += cLen;
+            }
+            // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen'
+            ++cTotal;
+
+            long[] c = new long[cTotal];
+
+            // Prepare A in Interleaved form, according to the chosen width
+            Interleave(A.m_ints, 0, c, 0, aLen, width);
+
+            // Make a working copy of B, since we will be shifting it
+            {
+                int bOff = aLen;
+                Array.Copy(B.m_ints, 0, c, bOff, bLen);
+                for (int bank = 1; bank < banks; ++bank)
+                {
+                    ShiftUp(c, aLen, c, bOff += bMax, bMax, bank);
+                }
+            }
+
+            /*
+             * The main loop analyzes the Interleaved windows in A, and for each non-zero window
+             * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is
+             * breadth-first, checking the lowest window in each word, then looping again for the
+             * next higher window position.
+             */
+            int MASK = (1 << width) - 1;
+
+            int k = 0;
+            for (;;)
+            {
+                int aPos = 0;
+                do
+                {
+                    long aVal = (long)((ulong)c[aPos] >> k);
+                    int bank = 0, bOff = aLen;
+                    for (;;)
+                    {
+                        int index = (int)(aVal) & MASK;
+                        if (index != 0)
+                        {
+                            /*
+                             * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in
+                             * Interleaved form, the bits represent the current B shifted by 0, 'positions',
+                             * 'positions' * 2, ..., 'positions' * ('width' - 1)
+                             */
+                            Add(c, aPos + ci[index], c, bOff, bMax);
+                        }
+                        if (++bank == banks)
+                        {
+                            break;
+                        }
+                        bOff += bMax;
+                        aVal = (long)((ulong)aVal >> width);
+                    }
+                }
+                while (++aPos < aLen);
+
+                if ((k += stride) >= top)
+                {
+                    if (k >= 64)
+                    {
+                        break;
+                    }
+
+                    /*
+                     * Adjustment for window setups with top == 63, the final bit (if any) is processed
+                     * as the top-bit of a window
+                     */
+                    k = 64 - width;
+                    MASK &= MASK << (top - k);
+                }
+
+                /*
+                 * After each position has been checked for all words of A, B is shifted up 1 place
+                 */
+                ShiftUp(c, aLen, bTotal, banks);
+            }
+
+            int ciPos = ci.Length;
+            while (--ciPos > 1)
+            {
+                if ((ciPos & 1L) == 0L)
+                {
+                    /*
+                     * For even numbers, shift contents and add to the half-position
+                     */
+                    AddShiftedUp(c, ci[(uint)ciPos >> 1], c, ci[ciPos], cLen, positions);
+                }
+                else
+                {
+                    /*
+                     * For odd numbers, 'distribute' contents to the result and the next-lowest position
+                     */
+                    Distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen);
+                }
+            }
+
+            /*
+             * Finally the raw answer is collected, reduce it against the reduction coefficients
+             */
+            return ReduceResult(c, ci[1], cLen, m, ks);
+        }
+
+        public LongArray ModReduce(int m, int[] ks)
+        {
+            long[] buf = Arrays.Clone(m_ints);
+            int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks);
+            return new LongArray(buf, 0, rLen);
+        }
+
+        public LongArray Multiply(LongArray other, int m, int[] ks)
+        {
+            /*
+             * Find out the degree of each argument and handle the zero cases
+             */
+            int aDeg = Degree();
+            if (aDeg == 0)
+            {
+                return this;
+            }
+            int bDeg = other.Degree();
+            if (bDeg == 0)
+            {
+                return other;
+            }
+
+            /*
+             * Swap if necessary so that A is the smaller argument
+             */
+            LongArray A = this, B = other;
+            if (aDeg > bDeg)
+            {
+                A = other; B = this;
+                int tmp = aDeg; aDeg = bDeg; bDeg = tmp;
+            }
+
+            /*
+             * Establish the word lengths of the arguments and result
+             */
+            int aLen = (int)((uint)(aDeg + 63) >> 6);
+            int bLen = (int)((uint)(bDeg + 63) >> 6);
+            int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6);
+
+            if (aLen == 1)
+            {
+                long a0 = A.m_ints[0];
+                if (a0 == 1L)
+                {
+                    return B;
+                }
+
+                /*
+                 * Fast path for small A, with performance dependent only on the number of set bits
+                 */
+                long[] c0 = new long[cLen];
+                MultiplyWord(a0, B.m_ints, bLen, c0, 0);
+
+                /*
+                 * Reduce the raw answer against the reduction coefficients
+                 */
+                //return ReduceResult(c0, 0, cLen, m, ks);
+                return new LongArray(c0, 0, cLen);
+            }
+
+            /*
+             * Determine if B will get bigger during shifting
+             */
+            int bMax = (int)((uint)(bDeg + 7 + 63) >> 6);
+
+            /*
+             * Lookup table for the offset of each B in the tables
+             */
+            int[] ti = new int[16];
+
+            /*
+             * Precompute table of all 4-bit products of B
+             */
+            long[] T0 = new long[bMax << 4];
+            int tOff = bMax;
+            ti[1] = tOff;
+            Array.Copy(B.m_ints, 0, T0, tOff, bLen);
+            for (int i = 2; i < 16; ++i)
+            {
+                ti[i] = (tOff += bMax);
+                if ((i & 1) == 0)
+                {
+                    ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1);
+                }
+                else
+                {
+                    Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax);
+                }
+            }
+
+            /*
+             * Second table with all 4-bit products of B shifted 4 bits
+             */
+            long[] T1 = new long[T0.Length];
+            ShiftUp(T0, 0, T1, 0, T0.Length, 4);
+            //        ShiftUp(T0, bMax, T1, bMax, tOff, 4);
+
+            long[] a = A.m_ints;
+            long[] c = new long[cLen << 3];
+
+            int MASK = 0xF;
+
+            /*
+             * Lopez-Dahab (Modified) algorithm
+             */
+
+            for (int aPos = 0; aPos < aLen; ++aPos)
+            {
+                long aVal = a[aPos];
+                int cOff = aPos;
+                for (; ; )
+                {
+                    int u = (int)aVal & MASK;
+                    aVal = (long)((ulong)aVal >> 4);
+                    int v = (int)aVal & MASK;
+                    AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax);
+                    aVal = (long)((ulong)aVal >> 4);
+                    if (aVal == 0L)
+                    {
+                        break;
+                    }
+                    cOff += cLen;
+                }
+            }
+
+            {
+                int cOff = c.Length;
+                while ((cOff -= cLen) != 0)
+                {
+                    AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8);
+                }
+            }
+
+            /*
+             * Finally the raw answer is collected, reduce it against the reduction coefficients
+             */
+            //return ReduceResult(c, 0, cLen, m, ks);
+            return new LongArray(c, 0, cLen);
+        }
+
+        public void Reduce(int m, int[] ks)
+        {
+            long[] buf = m_ints;
+            int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks);
+            if (rLen < buf.Length)
+            {
+                m_ints = new long[rLen];
+                Array.Copy(buf, 0, m_ints, 0, rLen);
+            }
+        }
+
+        private static LongArray ReduceResult(long[] buf, int off, int len, int m, int[] ks)
+        {
+            int rLen = ReduceInPlace(buf, off, len, m, ks);
+            return new LongArray(buf, off, rLen);
+        }
+
+    //    private static void deInterleave(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+    //    {
+    //        for (int i = 0; i < count; ++i)
+    //        {
+    //            z[zOff + i] = deInterleave(x[zOff + i], rounds);
+    //        }
+    //    }
+    //
+    //    private static long deInterleave(long x, int rounds)
+    //    {
+    //        while (--rounds >= 0)
+    //        {
+    //            x = deInterleave32(x & DEInterleave_MASK) | (deInterleave32((x >>> 1) & DEInterleave_MASK) << 32);
+    //        }
+    //        return x;
+    //    }
+    //
+    //    private static long deInterleave32(long x)
+    //    {
+    //        x = (x | (x >>> 1)) & 0x3333333333333333L;
+    //        x = (x | (x >>> 2)) & 0x0F0F0F0F0F0F0F0FL;
+    //        x = (x | (x >>> 4)) & 0x00FF00FF00FF00FFL;
+    //        x = (x | (x >>> 8)) & 0x0000FFFF0000FFFFL;
+    //        x = (x | (x >>> 16)) & 0x00000000FFFFFFFFL;
+    //        return x;
+    //    }
+
+        private static int ReduceInPlace(long[] buf, int off, int len, int m, int[] ks)
+        {
+            int mLen = (m + 63) >> 6;
+            if (len < mLen)
+            {
+                return len;
+            }
+
+            int numBits = System.Math.Min(len << 6, (m << 1) - 1); // TODO use actual degree?
+            int excessBits = (len << 6) - numBits;
+            while (excessBits >= 64)
+            {
+                --len;
+                excessBits -= 64;
+            }
+
+            int kLen = ks.Length, kMax = ks[kLen - 1], kNext = kLen > 1 ? ks[kLen - 2] : 0;
+            int wordWiseLimit = System.Math.Max(m, kMax + 64);
+            int vectorableWords = (excessBits + System.Math.Min(numBits - wordWiseLimit, m - kNext)) >> 6;
+            if (vectorableWords > 1)
+            {
+                int vectorWiseWords = len - vectorableWords;
+                ReduceVectorWise(buf, off, len, vectorWiseWords, m, ks);
+                while (len > vectorWiseWords)
+                {
+                    buf[off + --len] = 0L;
+                }
+                numBits = vectorWiseWords << 6;
+            }
+
+            if (numBits > wordWiseLimit)
+            {
+                ReduceWordWise(buf, off, len, wordWiseLimit, m, ks);
+                numBits = wordWiseLimit;
+            }
+
+            if (numBits > m)
+            {
+                ReduceBitWise(buf, off, numBits, m, ks);
+            }
+
+            return mLen;
+        }
+
+        private static void ReduceBitWise(long[] buf, int off, int BitLength, int m, int[] ks)
+        {
+            while (--BitLength >= m)
+            {
+                if (TestBit(buf, off, BitLength))
+                {
+                    ReduceBit(buf, off, BitLength, m, ks);
+                }
+            }
+        }
+
+        private static void ReduceBit(long[] buf, int off, int bit, int m, int[] ks)
+        {
+            FlipBit(buf, off, bit);
+            int n = bit - m;
+            int j = ks.Length;
+            while (--j >= 0)
+            {
+                FlipBit(buf, off, ks[j] + n);
+            }
+            FlipBit(buf, off, n);
+        }
+
+        private static void ReduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks)
+        {
+            int toPos = (int)((uint)toBit >> 6);
+
+            while (--len > toPos)
+            {
+                long word = buf[off + len];
+                if (word != 0)
+                {
+                    buf[off + len] = 0;
+                    ReduceWord(buf, off, (len << 6), word, m, ks);
+                }
+            }
+
+            {
+                int partial = toBit & 0x3F;
+                long word = (long)((ulong)buf[off + toPos] >> partial);
+                if (word != 0)
+                {
+                    buf[off + toPos] ^= word << partial;
+                    ReduceWord(buf, off, toBit, word, m, ks);
+                }
+            }
+        }
+
+        private static void ReduceWord(long[] buf, int off, int bit, long word, int m, int[] ks)
+        {
+            int offset = bit - m;
+            int j = ks.Length;
+            while (--j >= 0)
+            {
+                FlipWord(buf, off, offset + ks[j], word);
+            }
+            FlipWord(buf, off, offset, word);
+        }
+
+        private static void ReduceVectorWise(long[] buf, int off, int len, int words, int m, int[] ks)
+        {
+            /*
+             * NOTE: It's important we go from highest coefficient to lowest, because for the highest
+             * one (only) we allow the ranges to partially overlap, and therefore any changes must take
+             * effect for the subsequent lower coefficients.
+             */
+            int baseBit = (words << 6) - m;
+            int j = ks.Length;
+            while (--j >= 0)
+            {
+                FlipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]);
+            }
+            FlipVector(buf, off, buf, off + words, len - words, baseBit);
+        }
+
+        private static void FlipVector(long[] x, int xOff, long[] y, int yOff, int yLen, int bits)
+        {
+            xOff += (int)((uint)bits >> 6);
+            bits &= 0x3F;
+
+            if (bits == 0)
+            {
+                Add(x, xOff, y, yOff, yLen);
+            }
+            else
+            {
+                long carry = AddShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits);
+                x[xOff] ^= carry;
+            }
+        }
+
+        public LongArray ModSquare(int m, int[] ks)
+        {
+            int len = GetUsedLength();
+            if (len == 0)
+            {
+                return this;
+            }
+
+            int _2len = len << 1;
+            long[] r = new long[_2len];
+
+            int pos = 0;
+            while (pos < _2len)
+            {
+                long mi = m_ints[(uint)pos >> 1];
+                r[pos++] = Interleave2_32to64((int)mi);
+                r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32));
+            }
+
+            return new LongArray(r, 0, ReduceInPlace(r, 0, r.Length, m, ks));
+        }
+
+        public LongArray ModSquareN(int n, int m, int[] ks)
+        {
+            int len = GetUsedLength();
+            if (len == 0)
+            {
+                return this;
+            }
+    
+            int mLen = (m + 63) >> 6;
+            long[] r = new long[mLen << 1];
+            Array.Copy(m_ints, 0, r, 0, len);
+    
+            while (--n >= 0)
+            {
+                SquareInPlace(r, len, m, ks);
+                len = ReduceInPlace(r, 0, r.Length, m, ks);
+            }
+    
+            return new LongArray(r, 0, len);
+        }
+
+        public LongArray Square(int m, int[] ks)
+        {
+            int len = GetUsedLength();
+            if (len == 0)
+            {
+                return this;
+            }
+
+            int _2len = len << 1;
+            long[] r = new long[_2len];
+
+            int pos = 0;
+            while (pos < _2len)
+            {
+                long mi = m_ints[(uint)pos >> 1];
+                r[pos++] = Interleave2_32to64((int)mi);
+                r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32));
+            }
+
+            return new LongArray(r, 0, r.Length);
+        }
+
+        private static void SquareInPlace(long[] x, int xLen, int m, int[] ks)
+        {
+            int pos = xLen << 1;
+            while (--xLen >= 0)
+            {
+                long xVal = x[xLen];
+                x[--pos] = Interleave2_32to64((int)((ulong)xVal >> 32));
+                x[--pos] = Interleave2_32to64((int)xVal);
+            }
+        }
+
+        private static void Interleave(long[] x, int xOff, long[] z, int zOff, int count, int width)
+        {
+            switch (width)
+            {
+            case 3:
+                Interleave3(x, xOff, z, zOff, count);
+                break;
+            case 5:
+                Interleave5(x, xOff, z, zOff, count);
+                break;
+            case 7:
+                Interleave7(x, xOff, z, zOff, count);
+                break;
+            default:
+                Interleave2_n(x, xOff, z, zOff, count, BitLengths[width] - 1);
+                break;
+            }
+        }
+
+        private static void Interleave3(long[] x, int xOff, long[] z, int zOff, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                z[zOff + i] = Interleave3(x[xOff + i]);
+            }
+        }
+
+        private static long Interleave3(long x)
+        {
+            long z = x & (1L << 63);
+            return z
+                | Interleave3_21to63((int)x & 0x1FFFFF)
+                | Interleave3_21to63((int)((ulong)x >> 21) & 0x1FFFFF) << 1
+                | Interleave3_21to63((int)((ulong)x >> 42) & 0x1FFFFF) << 2;
+
+    //        int zPos = 0, wPos = 0, xPos = 0;
+    //        for (;;)
+    //        {
+    //            z |= ((x >>> xPos) & 1L) << zPos;
+    //            if (++zPos == 63)
+    //            {
+    //                String sz2 = Long.toBinaryString(z);
+    //                return z;
+    //            }
+    //            if ((xPos += 21) >= 63)
+    //            {
+    //                xPos = ++wPos;
+    //            }
+    //        }
+        }
+
+        private static long Interleave3_21to63(int x)
+        {
+            int r00 = INTERLEAVE3_TABLE[x & 0x7F];
+            int r21 = INTERLEAVE3_TABLE[((uint)x >> 7) & 0x7F];
+            int r42 = INTERLEAVE3_TABLE[(uint)x >> 14];
+            return (r42 & 0xFFFFFFFFL) << 42 | (r21 & 0xFFFFFFFFL) << 21 | (r00 & 0xFFFFFFFFL);
+        }
+
+        private static void Interleave5(long[] x, int xOff, long[] z, int zOff, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                z[zOff + i] = Interleave5(x[xOff + i]);
+            }
+        }
+
+        private static long Interleave5(long x)
+        {
+            return Interleave3_13to65((int)x & 0x1FFF)
+                | Interleave3_13to65((int)((ulong)x >> 13) & 0x1FFF) << 1
+                | Interleave3_13to65((int)((ulong)x >> 26) & 0x1FFF) << 2
+                | Interleave3_13to65((int)((ulong)x >> 39) & 0x1FFF) << 3
+                | Interleave3_13to65((int)((ulong)x >> 52) & 0x1FFF) << 4;
+
+    //        long z = 0;
+    //        int zPos = 0, wPos = 0, xPos = 0;
+    //        for (;;)
+    //        {
+    //            z |= ((x >>> xPos) & 1L) << zPos;
+    //            if (++zPos == 64)
+    //            {
+    //                return z;
+    //            }
+    //            if ((xPos += 13) >= 64)
+    //            {
+    //                xPos = ++wPos;
+    //            }
+    //        }
+        }
+
+        private static long Interleave3_13to65(int x)
+        {
+            int r00 = INTERLEAVE5_TABLE[x & 0x7F];
+            int r35 = INTERLEAVE5_TABLE[(uint)x >> 7];
+            return (r35 & 0xFFFFFFFFL) << 35 | (r00 & 0xFFFFFFFFL);
+        }
+
+        private static void Interleave7(long[] x, int xOff, long[] z, int zOff, int count)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                z[zOff + i] = Interleave7(x[xOff + i]);
+            }
+        }
+
+        private static long Interleave7(long x)
+        {
+            long z = x & (1L << 63);
+            return z
+                | INTERLEAVE7_TABLE[(int)x & 0x1FF]
+                | INTERLEAVE7_TABLE[(int)((ulong)x >> 9) & 0x1FF] << 1
+                | INTERLEAVE7_TABLE[(int)((ulong)x >> 18) & 0x1FF] << 2
+                | INTERLEAVE7_TABLE[(int)((ulong)x >> 27) & 0x1FF] << 3
+                | INTERLEAVE7_TABLE[(int)((ulong)x >> 36) & 0x1FF] << 4
+                | INTERLEAVE7_TABLE[(int)((ulong)x >> 45) & 0x1FF] << 5
+                | INTERLEAVE7_TABLE[(int)((ulong)x >> 54) & 0x1FF] << 6;
+
+    //        int zPos = 0, wPos = 0, xPos = 0;
+    //        for (;;)
+    //        {
+    //            z |= ((x >>> xPos) & 1L) << zPos;
+    //            if (++zPos == 63)
+    //            {
+    //                return z;
+    //            }
+    //            if ((xPos += 9) >= 63)
+    //            {
+    //                xPos = ++wPos;
+    //            }
+    //        }
+        }
+
+        private static void Interleave2_n(long[] x, int xOff, long[] z, int zOff, int count, int rounds)
+        {
+            for (int i = 0; i < count; ++i)
+            {
+                z[zOff + i] = Interleave2_n(x[xOff + i], rounds);
+            }
+        }
+
+        private static long Interleave2_n(long x, int rounds)
+        {
+            while (rounds > 1)
+            {
+                rounds -= 2;
+                x = Interleave4_16to64((int)x & 0xFFFF)
+                    | Interleave4_16to64((int)((ulong)x >> 16) & 0xFFFF) << 1
+                    | Interleave4_16to64((int)((ulong)x >> 32) & 0xFFFF) << 2
+                    | Interleave4_16to64((int)((ulong)x >> 48) & 0xFFFF) << 3;
+            }
+            if (rounds > 0)
+            {
+                x = Interleave2_32to64((int)x) | Interleave2_32to64((int)((ulong)x >> 32)) << 1;
+            }
+            return x;
+        }
+
+        private static long Interleave4_16to64(int x)
+        {
+            int r00 = INTERLEAVE4_TABLE[x & 0xFF];
+            int r32 = INTERLEAVE4_TABLE[(uint)x >> 8];
+            return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+        }
+
+        private static long Interleave2_32to64(int x)
+        {
+            int r00 = INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[((uint)x >> 8) & 0xFF] << 16;
+            int r32 = INTERLEAVE2_TABLE[((uint)x >> 16) & 0xFF] | INTERLEAVE2_TABLE[(uint)x >> 24] << 16;
+            return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL);
+        }
+
+    //    private static LongArray ExpItohTsujii2(LongArray B, int n, int m, int[] ks)
+    //    {
+    //        LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+    //        int scale = 1;
+    //
+    //        int numTerms = n;
+    //        while (numTerms > 1)
+    //        {
+    //            if ((numTerms & 1) != 0)
+    //            {
+    //                t3 = t3.ModMultiply(t1, m, ks);
+    //                t1 = t1.modSquareN(scale, m, ks);
+    //            }
+    //
+    //            LongArray t2 = t1.modSquareN(scale, m, ks);
+    //            t1 = t1.ModMultiply(t2, m, ks);
+    //            numTerms >>>= 1; scale <<= 1;
+    //        }
+    //
+    //        return t3.ModMultiply(t1, m, ks);
+    //    }
+    //
+    //    private static LongArray ExpItohTsujii23(LongArray B, int n, int m, int[] ks)
+    //    {
+    //        LongArray t1 = B, t3 = new LongArray(new long[]{ 1L });
+    //        int scale = 1;
+    //
+    //        int numTerms = n;
+    //        while (numTerms > 1)
+    //        {
+    //            bool m03 = numTerms % 3 == 0;
+    //            bool m14 = !m03 && (numTerms & 1) != 0;
+    //
+    //            if (m14)
+    //            {
+    //                t3 = t3.ModMultiply(t1, m, ks);
+    //                t1 = t1.modSquareN(scale, m, ks);
+    //            }
+    //
+    //            LongArray t2 = t1.modSquareN(scale, m, ks);
+    //            t1 = t1.ModMultiply(t2, m, ks);
+    //
+    //            if (m03)
+    //            {
+    //                t2 = t2.modSquareN(scale, m, ks);
+    //                t1 = t1.ModMultiply(t2, m, ks);
+    //                numTerms /= 3; scale *= 3;
+    //            }
+    //            else
+    //            {
+    //                numTerms >>>= 1; scale <<= 1;
+    //            }
+    //        }
+    //
+    //        return t3.ModMultiply(t1, m, ks);
+    //    }
+    //
+    //    private static LongArray ExpItohTsujii235(LongArray B, int n, int m, int[] ks)
+    //    {
+    //        LongArray t1 = B, t4 = new LongArray(new long[]{ 1L });
+    //        int scale = 1;
+    //
+    //        int numTerms = n;
+    //        while (numTerms > 1)
+    //        {
+    //            if (numTerms % 5 == 0)
+    //            {
+    ////                t1 = ExpItohTsujii23(t1, 5, m, ks);
+    //
+    //                LongArray t3 = t1;
+    //                t1 = t1.modSquareN(scale, m, ks);
+    //
+    //                LongArray t2 = t1.modSquareN(scale, m, ks);
+    //                t1 = t1.ModMultiply(t2, m, ks);
+    //                t2 = t1.modSquareN(scale << 1, m, ks);
+    //                t1 = t1.ModMultiply(t2, m, ks);
+    //
+    //                t1 = t1.ModMultiply(t3, m, ks);
+    //
+    //                numTerms /= 5; scale *= 5;
+    //                continue;
+    //            }
+    //
+    //            bool m03 = numTerms % 3 == 0;
+    //            bool m14 = !m03 && (numTerms & 1) != 0;
+    //
+    //            if (m14)
+    //            {
+    //                t4 = t4.ModMultiply(t1, m, ks);
+    //                t1 = t1.modSquareN(scale, m, ks);
+    //            }
+    //
+    //            LongArray t2 = t1.modSquareN(scale, m, ks);
+    //            t1 = t1.ModMultiply(t2, m, ks);
+    //
+    //            if (m03)
+    //            {
+    //                t2 = t2.modSquareN(scale, m, ks);
+    //                t1 = t1.ModMultiply(t2, m, ks);
+    //                numTerms /= 3; scale *= 3;
+    //            }
+    //            else
+    //            {
+    //                numTerms >>>= 1; scale <<= 1;
+    //            }
+    //        }
+    //
+    //        return t4.ModMultiply(t1, m, ks);
+    //    }
+
+        public LongArray ModInverse(int m, int[] ks)
+        {
+            /*
+             * Fermat's Little Theorem
+             */
+    //        LongArray A = this;
+    //        LongArray B = A.modSquare(m, ks);
+    //        LongArray R0 = B, R1 = B;
+    //        for (int i = 2; i < m; ++i)
+    //        {
+    //            R1 = R1.modSquare(m, ks);
+    //            R0 = R0.ModMultiply(R1, m, ks);
+    //        }
+    //
+    //        return R0;
+
+            /*
+             * Itoh-Tsujii
+             */
+    //        LongArray B = modSquare(m, ks);
+    //        switch (m)
+    //        {
+    //        case 409:
+    //            return ExpItohTsujii23(B, m - 1, m, ks);
+    //        case 571:
+    //            return ExpItohTsujii235(B, m - 1, m, ks);
+    //        case 163:
+    //        case 233:
+    //        case 283:
+    //        default:
+    //            return ExpItohTsujii2(B, m - 1, m, ks);
+    //        }
+
+            /*
+             * Inversion in F2m using the extended Euclidean algorithm
+             * 
+             * Input: A nonzero polynomial a(z) of degree at most m-1
+             * Output: a(z)^(-1) mod f(z)
+             */
+            int uzDegree = Degree();
+            if (uzDegree == 0)
+            {
+                throw new InvalidOperationException();
+            }
+            if (uzDegree == 1)
+            {
+                return this;
+            }
+
+            // u(z) := a(z)
+            LongArray uz = (LongArray)Copy();
+
+            int t = (m + 63) >> 6;
+
+            // v(z) := f(z)
+            LongArray vz = new LongArray(t);
+            ReduceBit(vz.m_ints, 0, m, m, ks);
+
+            // g1(z) := 1, g2(z) := 0
+            LongArray g1z = new LongArray(t);
+            g1z.m_ints[0] = 1L;
+            LongArray g2z = new LongArray(t);
+
+            int[] uvDeg = new int[]{ uzDegree, m + 1 };
+            LongArray[] uv = new LongArray[]{ uz, vz };
+
+            int[] ggDeg = new int[]{ 1, 0 };
+            LongArray[] gg = new LongArray[]{ g1z, g2z };
+
+            int b = 1;
+            int duv1 = uvDeg[b];
+            int dgg1 = ggDeg[b];
+            int j = duv1 - uvDeg[1 - b];
+
+            for (;;)
+            {
+                if (j < 0)
+                {
+                    j = -j;
+                    uvDeg[b] = duv1;
+                    ggDeg[b] = dgg1;
+                    b = 1 - b;
+                    duv1 = uvDeg[b];
+                    dgg1 = ggDeg[b];
+                }
+
+                uv[b].AddShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j);
+
+                int duv2 = uv[b].DegreeFrom(duv1);
+                if (duv2 == 0)
+                {
+                    return gg[1 - b];
+                }
+
+                {
+                    int dgg2 = ggDeg[1 - b];
+                    gg[b].AddShiftedByBitsSafe(gg[1 - b], dgg2, j);
+                    dgg2 += j;
+
+                    if (dgg2 > dgg1)
+                    {
+                        dgg1 = dgg2;
+                    }
+                    else if (dgg2 == dgg1)
+                    {
+                        dgg1 = gg[b].DegreeFrom(dgg1);
+                    }
+                }
+
+                j += (duv2 - duv1);
+                duv1 = duv2;
+            }
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as LongArray);
+        }
+
+        public virtual bool Equals(LongArray other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            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 override int GetHashCode()
+        {
+            int usedLen = GetUsedLength();
+            int hash = 1;
+            for (int i = 0; i < usedLen; i++)
+            {
+                long mi = m_ints[i];
+                hash *= 31;
+                hash ^= (int)mi;
+                hash *= 31;
+                hash ^= (int)((ulong)mi >> 32);
+            }
+            return hash;
+        }
+
+        public LongArray Copy()
+        {
+            return new LongArray(Arrays.Clone(m_ints));
+        }
+
+        public override string ToString()
+        {
+            int i = GetUsedLength();
+            if (i == 0)
+            {
+                return "0";
+            }
+
+            StringBuilder sb = new StringBuilder(Convert.ToString(m_ints[--i], 2));
+            while (--i >= 0)
+            {
+                string s = Convert.ToString(m_ints[i], 2);
+
+                // Add leading zeroes, except for highest significant word
+                int len = s.Length;
+                if (len < 64)
+                {
+                    sb.Append(ZEROES.Substring(len));
+                }
+
+                sb.Append(s);
+            }
+            return sb.ToString();
+        }
+    }
+}
diff --git a/crypto/src/math/ec/Mod.cs b/crypto/src/math/ec/Mod.cs
new file mode 100644
index 000000000..80534ca9f
--- /dev/null
+++ b/crypto/src/math/ec/Mod.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    internal abstract class Mod
+    {
+        public static void Invert(uint[] p, uint[] x, uint[] z)
+        {
+            int len = p.Length;
+            if (Nat.IsZero(len, x))
+                throw new ArgumentException("cannot be 0", "x");
+            if (Nat.IsOne(len, x))
+            {
+                Array.Copy(x, 0, z, 0, len);
+                return;
+            }
+
+            uint[] u = Nat.Copy(len, x);
+            uint[] a = Nat.Create(len);
+            a[0] = 1;
+            int ac = 0;
+
+            if ((u[0] & 1) == 0)
+            {
+                InversionStep(p, u, len, a, ref ac);
+            }
+            if (Nat.IsOne(len, u))
+            {
+                InversionResult(p, ac, a, z);
+                return;
+            }
+
+            uint[] v = Nat.Copy(len, p);
+            uint[] b = Nat.Create(len);
+            int bc = 0;
+
+            int uvLen = len;
+
+            for (;;)
+            {
+                while (u[uvLen - 1] == 0 && v[uvLen - 1] == 0)
+                {
+                    --uvLen;
+                }
+
+                if (Nat.Gte(len, u, v))
+                {
+                    Nat.SubFrom(len, v, u);
+                    Debug.Assert((u[0] & 1) == 0);
+                    ac += Nat.SubFrom(len, b, a) - bc;
+                    InversionStep(p, u, uvLen, a, ref ac);
+                    if (Nat.IsOne(len, u))
+                    {
+                        InversionResult(p, ac, a, z);
+                        return;
+                    }
+                }
+                else
+                {
+                    Nat.SubFrom(len, u, v);
+                    Debug.Assert((v[0] & 1) == 0);
+                    bc += Nat.SubFrom(len, a, b) - ac;
+                    InversionStep(p, v, uvLen, b, ref bc);
+                    if (Nat.IsOne(len, v))
+                    {
+                        InversionResult(p, bc, b, z);
+                        return;
+                    }
+                }
+            }
+        }
+
+        public static uint[] Random(uint[] p)
+        {
+            int len = p.Length;
+            Random rand = new Random();
+            uint[] s = Nat.Create(len);
+
+            uint m = p[len - 1];
+            m |= m >> 1;
+            m |= m >> 2;
+            m |= m >> 4;
+            m |= m >> 8;
+            m |= m >> 16;
+
+            do
+            {
+                byte[] bytes = new byte[len << 2];
+                rand.NextBytes(bytes);
+                Pack.BE_To_UInt32(bytes, 0, s);
+                s[len - 1] &= m;
+            }
+            while (Nat.Gte(len, s, p));
+
+            return s;
+        }
+
+        public static void Add(uint[] p, uint[] x, uint[] y, uint[] z)
+        {
+            int len = p.Length;
+            uint c = Nat.Add(len, x, y, z);
+            if (c != 0)
+            {
+                Nat.SubFrom(len, p, z);
+            }
+        }
+
+        public static void Subtract(uint[] p, uint[] x, uint[] y, uint[] z)
+        {
+            int len = p.Length;
+            int c = Nat.Sub(len, x, y, z);
+            if (c != 0)
+            {
+                Nat.AddTo(len, p, z);
+            }
+        }
+
+        private static void InversionResult(uint[] p, int ac, uint[] a, uint[] z)
+        {
+            if (ac < 0)
+            {
+                Nat.Add(p.Length, a, p, z);
+            }
+            else
+            {
+                Array.Copy(a, 0, z, 0, p.Length);
+            }
+        }
+
+        private static void InversionStep(uint[] p, uint[] u, int uLen, uint[] x, ref int xc)
+        {
+            int len = p.Length;
+            int count = 0;
+            while (u[0] == 0)
+            {
+                Nat.ShiftDownWord(uLen, u, 0);
+                count += 32;
+            }
+
+            {
+                int zeroes = GetTrailingZeroes(u[0]);
+                if (zeroes > 0)
+                {
+                    Nat.ShiftDownBits(uLen, u, zeroes, 0);
+                    count += zeroes;
+                }
+            }
+
+            for (int i = 0; i < count; ++i)
+            {
+                if ((x[0] & 1) != 0)
+                {
+                    if (xc < 0)
+                    {
+                        xc += (int)Nat.AddTo(len, p, x);
+                    }
+                    else
+                    {
+                        xc += Nat.SubFrom(len, p, x);
+                    }
+                }
+
+                Debug.Assert(xc == 0 || xc == -1);
+                Nat.ShiftDownBit(len, x, (uint)xc);
+            }
+        }
+
+        private static int GetTrailingZeroes(uint x)
+        {
+            Debug.Assert(x != 0);
+            int count = 0;
+            while ((x & 1) == 0)
+            {
+                x >>= 1;
+                ++count;
+            }
+            return count;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/Nat.cs b/crypto/src/math/ec/Nat.cs
new file mode 100644
index 000000000..17b632f26
--- /dev/null
+++ b/crypto/src/math/ec/Nat.cs
@@ -0,0 +1,1013 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    internal abstract class Nat
+    {
+        private const ulong M = 0xFFFFFFFFUL;
+
+        public static uint Add(int len, uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (ulong)x[i] + y[i];
+                z[i] = (uint)c;
+                c >>= 32;
+            }
+            return (uint)c;
+        }
+
+        public static uint Add33At(int len, uint x, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            ulong c = (ulong)z[zPos + 0] + x;
+            z[zPos + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[zPos + 1] + 1;
+            z[zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zPos + 2);
+        }
+
+        public static uint Add33At(int len, uint x, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            ulong c = (ulong)z[zOff + zPos] + x;
+            z[zOff + zPos] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[zOff + zPos + 1] + 1;
+            z[zOff + zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 2);
+        }
+
+        public static uint Add33To(int len, uint x, uint[] z)
+        {
+            ulong c = (ulong)z[0] + x;
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[1] + 1;
+            z[1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, 2);
+        }
+
+        public static uint Add33To(int len, uint x, uint[] z, int zOff)
+        {
+            ulong c = (ulong)z[zOff + 0] + x;
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[zOff + 1] + 1;
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zOff, 2);
+        }
+
+        public static uint AddBothTo(int len, uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (ulong)x[i] + y[i] + z[i];
+                z[i] = (uint)c;
+                c >>= 32;
+            }
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (ulong)x[xOff + i] + y[yOff + i] + z[zOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            return (uint)c;
+        }
+
+        public static uint AddDWordAt(int len, ulong x, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            ulong c = (ulong)z[zPos + 0] + (x & M);
+            z[zPos + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[zPos + 1] + (x >> 32);
+            z[zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zPos + 2);
+        }
+
+        public static uint AddDWordAt(int len, ulong x, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            ulong c = (ulong)z[zOff + zPos] + (x & M);
+            z[zOff + zPos] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[zOff + zPos + 1] + (x >> 32);
+            z[zOff + zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 2);
+        }
+
+        public static uint AddDWordTo(int len, ulong x, uint[] z)
+        {
+            ulong c = (ulong)z[0] + (x & M);
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[1] + (x >> 32);
+            z[1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, 2);
+        }
+
+        public static uint AddDWordTo(int len, ulong x, uint[] z, int zOff)
+        {
+            ulong c = (ulong)z[zOff + 0] + (x & M);
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[zOff + 1] + (x >> 32);
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zOff, 2);
+        }
+
+        public static uint AddTo(int len, uint[] x, uint[] z)
+        {
+            ulong c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (ulong)x[i] + z[i];
+                z[i] = (uint)c;
+                c >>= 32;
+            }
+            return (uint)c;
+        }
+
+        public static uint AddTo(int len, uint[] x, int xOff, uint[] z, int zOff)
+        {
+            ulong c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (ulong)x[xOff + i] + z[zOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            return (uint)c;
+        }
+
+        public static uint AddWordAt(int len, uint x, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 1));
+            ulong c = (ulong)x + z[zPos];
+            z[zPos] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zPos + 1);
+        }
+
+        public static uint AddWordAt(int len, uint x, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 1));
+            ulong c = (ulong)x + z[zOff + zPos];
+            z[zOff + zPos] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 1);
+        }
+
+        public static uint AddWordTo(int len, uint x, uint[] z)
+        {
+            ulong c = (ulong)x + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, 1);
+        }
+
+        public static uint AddWordTo(int len, uint x, uint[] z, int zOff)
+        {
+            ulong c = (ulong)x + z[zOff];
+            z[zOff] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zOff, 1);
+        }
+
+        public static void Copy(int len, uint[] x, uint[] z)
+        {
+            Array.Copy(x, 0, z, 0, len);
+        }
+
+        public static uint[] Copy(int len, uint[] x)
+        {
+            uint[] z = new uint[len];
+            Array.Copy(x, 0, z, 0, len);
+            return z;
+        }
+
+        public static uint[] Create(int len)
+        {
+            return new uint[len];
+        }
+
+        public static int Dec(int len, uint[] z)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                if (--z[i] != uint.MaxValue)
+                {
+                    return 0;
+                }
+            }
+            return -1;
+        }
+
+        public static int Dec(int len, uint[] x, uint[] z)
+        {
+            int i = 0;
+            while (i < len)
+            {
+                uint c = x[i] - 1;
+                z[i] = c;
+                ++i;
+                if (c != uint.MaxValue)
+                {
+                    while (i < len)
+                    {
+                        z[i] = x[i];
+                        ++i;
+                    }
+                    return 0;
+                }
+            }
+            return -1;
+        }
+
+        public static int DecAt(int len, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= len);
+            for (int i = zPos; i < len; ++i)
+            {
+                if (--z[i] != uint.MaxValue)
+                {
+                    return 0;
+                }
+            }
+            return -1;
+        }
+
+        public static int DecAt(int len, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= len);
+            for (int i = zPos; i < len; ++i)
+            {
+                if (--z[zOff + i] != uint.MaxValue)
+                {
+                    return 0;
+                }
+            }
+            return -1;
+        }
+
+        public static bool Eq(int len, uint[] x, uint[] y)
+        {
+            for (int i = len - 1; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static uint[] FromBigInteger(int bits, BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > bits)
+                throw new ArgumentException();
+
+            int len = (bits + 31) >> 5;
+            uint[] z = Create(len);
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (uint)x.IntValue;
+                x = x.ShiftRight(32);
+            }
+            return z;
+        }
+
+        public static uint GetBit(uint[] x, int bit)
+        {
+            if (bit == 0)
+            {
+                return x[0] & 1;
+            }
+            int w = bit >> 5;
+            if (w < 0 || w >= x.Length)
+            {
+                return 0;
+            }
+            int b = bit & 31;
+            return (x[w] >> b) & 1;
+        }
+
+        public static bool Gte(int len, uint[] x, uint[] y)
+        {
+            for (int i = len - 1; i >= 0; --i)
+            {
+                uint x_i = x[i], y_i = y[i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static uint Inc(int len, uint[] z)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                if (++z[i] != uint.MinValue)
+                {
+                    return 0;
+                }
+            }
+            return 1;
+        }
+
+        public static uint Inc(int len, uint[] x, uint[] z)
+        {
+            int i = 0;
+            while (i < len)
+            {
+                uint c = x[i] + 1;
+                z[i] = c;
+                ++i;
+                if (c != 0)
+                {
+                    while (i < len)
+                    {
+                        z[i] = x[i];
+                        ++i;
+                    }
+                    return 0;
+                }
+            }
+            return 1;
+        }
+
+        public static uint IncAt(int len, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= len);
+            for (int i = zPos; i < len; ++i)
+            {
+                if (++z[i] != uint.MinValue)
+                {
+                    return 0;
+                }
+            }
+            return 1;
+        }
+
+        public static uint IncAt(int len, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= len);
+            for (int i = zPos; i < len; ++i)
+            {
+                if (++z[zOff + i] != uint.MinValue)
+                {
+                    return 0;
+                }
+            }
+            return 1;
+        }
+
+        public static bool IsOne(int len, uint[] x)
+        {
+            if (x[0] != 1)
+            {
+                return false;
+            }
+            for (int i = 1; i < len; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero(int len, uint[] x)
+        {
+            if (x[0] != 0)
+            {
+                return false;
+            }
+            for (int i = 1; i < len; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static void Mul(int len, uint[] x, uint[] y, uint[] zz)
+        {
+            zz[len] = (uint)MulWord(len, x[0], y, zz);
+
+            for (int i = 1; i < len; ++i)
+            {
+                zz[i + len] = (uint)MulWordAddTo(len, x[i], y, 0, zz, i);
+            }
+        }
+
+        public static void Mul(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            zz[zzOff + len] = (uint)MulWord(len, x[xOff], y, yOff, zz, zzOff);
+
+            for (int i = 1; i < len; ++i)
+            {
+                zz[zzOff + i + len] = (uint)MulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i);
+            }
+        }
+
+        public static uint Mul31BothAdd(int len, uint a, uint[] x, uint b, uint[] y, uint[] z, int zOff)
+        {
+            ulong c = 0, aVal = (ulong)a, bVal = (ulong)b;
+            int i = 0;
+            do
+            {
+                c += aVal * x[i] + bVal * y[i] + z[zOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < len);
+            return (uint)c;
+        }
+
+        public static uint MulWord(int len, uint x, uint[] y, uint[] z)
+        {
+            ulong c = 0, xVal = (ulong)x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[i];
+                z[i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < len);
+            return (uint)c;
+        }
+
+        public static uint MulWord(int len, uint x, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = (ulong)x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[yOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < len);
+            return (uint)c;
+        }
+
+        public static uint MulWordAddTo(int len, uint x, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = (ulong)x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[yOff + i] + z[zOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < len);
+            return (uint)c;
+        }
+
+        public static uint MulWordDwordAddAt(int len, uint x, ulong y, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 3));
+            ulong c = 0, xVal = (ulong)x;
+            c += xVal * (uint)y + z[zPos + 0];
+            z[zPos + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * (y >> 32) + z[zPos + 1];
+            z[zPos + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)z[zPos + 2];
+            z[zPos + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : IncAt(len, z, zPos + 3);
+        }
+
+        public static uint ShiftDownBit(int len, uint[] z, uint c)
+        {
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = z[i];
+                z[i] = (next >> 1) | (c << 31);
+                c = next;
+            }
+            return c << 31;
+        }
+
+        public static uint ShiftDownBit(int len, uint[] z, int zOff, uint c)
+        {
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = z[zOff + i];
+                z[zOff + i] = (next >> 1) | (c << 31);
+                c = next;
+            }
+            return c << 31;
+        }
+
+        public static uint ShiftDownBit(int len, uint[] x, uint c, uint[] z)
+        {
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = x[i];
+                z[i] = (next >> 1) | (c << 31);
+                c = next;
+            }
+            return c << 31;
+        }
+
+        public static uint ShiftDownBit(int len, uint[] x, int xOff, uint c, uint[] z, int zOff)
+        {
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = x[xOff + i];
+                z[zOff + i] = (next >> 1) | (c << 31);
+                c = next;
+            }
+            return c << 31;
+        }
+
+        public static uint ShiftDownBits(int len, uint[] z, int bits, uint c)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = z[i];
+                z[i] = (next >> bits) | (c << -bits);
+                c = next;
+            }
+            return c << -bits;
+        }
+
+        public static uint ShiftDownBits(int len, uint[] z, int zOff, int bits, uint c)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = z[zOff + i];
+                z[zOff + i] = (next >> bits) | (c << -bits);
+                c = next;
+            }
+            return c << -bits;
+        }
+
+        public static uint ShiftDownBits(int len, uint[] x, int bits, uint c, uint[] z)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = x[i];
+                z[i] = (next >> bits) | (c << -bits);
+                c = next;
+            }
+            return c << -bits;
+        }
+
+        public static uint ShiftDownBits(int len, uint[] x, int xOff, int bits, uint c, uint[] z, int zOff)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = x[xOff + i];
+                z[zOff + i] = (next >> bits) | (c << -bits);
+                c = next;
+            }
+            return c << -bits;
+        }
+
+        public static uint ShiftDownWord(int len, uint[] z, uint c)
+        {
+            int i = len;
+            while (--i >= 0)
+            {
+                uint next = z[i];
+                z[i] = c;
+                c = next;
+            }
+            return c;
+        }
+
+        public static uint ShiftUpBit(int len, uint[] z, uint c)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = z[i];
+                z[i] = (next << 1) | (c >> 31);
+                c = next;
+            }
+            return c >> 31;
+        }
+
+        public static uint ShiftUpBit(int len, uint[] z, int zOff, uint c)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = z[zOff + i];
+                z[zOff + i] = (next << 1) | (c >> 31);
+                c = next;
+            }
+            return c >> 31;
+        }
+
+        public static uint ShiftUpBit(int len, uint[] x, uint c, uint[] z)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = x[i];
+                z[i] = (next << 1) | (c >> 31);
+                c = next;
+            }
+            return c >> 31;
+        }
+
+        public static uint ShiftUpBit(int len, uint[] x, int xOff, uint c, uint[] z, int zOff)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = x[xOff + i];
+                z[zOff + i] = (next << 1) | (c >> 31);
+                c = next;
+            }
+            return c >> 31;
+        }
+
+        public static uint ShiftUpBits(int len, uint[] z, int bits, uint c)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = z[i];
+                z[i] = (next << bits) | (c >> -bits);
+                c = next;
+            }
+            return c >> -bits;
+        }
+
+        public static uint ShiftUpBits(int len, uint[] z, int zOff, int bits, uint c)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = z[zOff + i];
+                z[zOff + i] = (next << bits) | (c >> -bits);
+                c = next;
+            }
+            return c >> -bits;
+        }
+
+        public static uint ShiftUpBits(int len, uint[] x, int bits, uint c, uint[] z)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = x[i];
+                z[i] = (next << bits) | (c >> -bits);
+                c = next;
+            }
+            return c >> -bits;
+        }
+
+        public static uint ShiftUpBits(int len, uint[] x, int xOff, int bits, uint c, uint[] z, int zOff)
+        {
+            Debug.Assert(bits > 0 && bits < 32);
+            for (int i = 0; i < len; ++i)
+            {
+                uint next = x[xOff + i];
+                z[zOff + i] = (next << bits) | (c >> -bits);
+                c = next;
+            }
+            return c >> -bits;
+        }
+
+        public static void Square(int len, uint[] x, uint[] zz)
+        {
+            int extLen = len << 1;
+            uint c = 0;
+            int j = len, k = extLen;
+            do
+            {
+                ulong xVal = (ulong)x[--j];
+                ulong p = xVal * xVal;
+                zz[--k] = (c << 31) | (uint)(p >> 33);
+                zz[--k] = (uint)(p >> 1);
+                c = (uint)p;
+            }
+            while (j > 0);
+
+            for (int i = 1; i < len; ++i)
+            {
+                c = SquareWordAdd(x, i, zz);
+                AddWordAt(extLen, c, zz, i << 1);
+            }
+
+            ShiftUpBit(extLen, zz, x[0] << 31);
+        }
+
+        public static void Square(int len, uint[] x, int xOff, uint[] zz, int zzOff)
+        {
+            int extLen = len << 1;
+            uint c = 0;
+            int j = len, k = extLen;
+            do
+            {
+                ulong xVal = (ulong)x[xOff + --j];
+                ulong p = xVal * xVal;
+                zz[zzOff + --k] = (c << 31) | (uint)(p >> 33);
+                zz[zzOff + --k] = (uint)(p >> 1);
+                c = (uint)p;
+            }
+            while (j > 0);
+
+            for (int i = 1; i < len; ++i)
+            {
+                c = SquareWordAdd(x, xOff, i, zz, zzOff);
+                AddWordAt(extLen, c, zz, zzOff, i << 1);
+            }
+
+            ShiftUpBit(extLen, zz, zzOff, x[xOff] << 31);
+        }
+
+        public static uint SquareWordAdd(uint[] x, int xPos, uint[] z)
+        {
+            ulong c = 0, xVal = (ulong)x[xPos];
+            int i = 0;
+            do
+            {
+                c += xVal * x[i] + z[xPos + i];
+                z[xPos + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < xPos);
+            return (uint)c;
+        }
+
+        public static uint SquareWordAdd(uint[] x, int xOff, int xPos, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = (ulong)x[xOff + xPos];
+            int i = 0;
+            do
+            {
+                c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M);
+                z[xPos + zOff] = (uint)c;
+                c >>= 32;
+                ++zOff;
+            }
+            while (++i < xPos);
+            return (uint)c;
+        }
+
+        public static int Sub(int len, uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (long)x[i] - y[i];
+                z[i] = (uint)c;
+                c >>= 32;
+            }
+            return (int)c;
+        }
+
+        public static int Sub(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (long)x[xOff + i] - y[yOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            return (int)c;
+        }
+        public static int Sub33At(int len, uint x, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            long c = (long)z[zPos + 0] - x;
+            z[zPos + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zPos + 1] - 1;
+            z[zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zPos + 2);
+        }
+
+        public static int Sub33At(int len, uint x, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            long c = (long)z[zOff + zPos] - x;
+            z[zOff + zPos] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + zPos + 1] - 1;
+            z[zOff + zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 2);
+        }
+
+        public static int Sub33From(int len, uint x, uint[] z)
+        {
+            long c = (long)z[0] - x;
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - 1;
+            z[1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, 2);
+        }
+
+        public static int Sub33From(int len, uint x, uint[] z, int zOff)
+        {
+            long c = (long)z[zOff + 0] - x;
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 1] - 1;
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zOff, 2);
+        }
+
+        public static int SubBothFrom(int len, uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (long)z[i] - x[i] - y[i];
+                z[i] = (uint)c;
+                c >>= 32;
+            }
+            return (int)c;
+        }
+
+        public static int SubBothFrom(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (long)z[zOff + i] - x[xOff + i] - y[yOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            return (int)c;
+        }
+
+        public static int SubDWordAt(int len, ulong x, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            long c = (long)z[zPos + 0] - (long)(x & M);
+            z[zPos + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zPos + 1] - (long)(x >> 32);
+            z[zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zPos + 2);
+        }
+
+        public static int SubDWordAt(int len, ulong x, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 2));
+            long c = (long)z[zOff + zPos] - (long)(x & M);
+            z[zOff + zPos] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + zPos + 1] - (long)(x >> 32);
+            z[zOff + zPos + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z,  zOff, zPos + 2);
+        }
+
+        public static int SubDWordFrom(int len, ulong x, uint[] z)
+        {
+            long c = (long)z[0] - (long)(x & M);
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - (long)(x >> 32);
+            z[1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, 2);
+        }
+
+        public static int SubDWordFrom(int len, ulong x, uint[] z, int zOff)
+        {
+            long c = (long)z[zOff + 0] - (long)(x & M);
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 1] - (long)(x >> 32);
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zOff, 2);
+        }
+
+        public static int SubFrom(int len, uint[] x, uint[] z)
+        {
+            long c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (long)z[i] - x[i];
+                z[i] = (uint)c;
+                c >>= 32;
+            }
+            return (int)c;
+        }
+
+        public static int SubFrom(int len, uint[] x, int xOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            for (int i = 0; i < len; ++i)
+            {
+                c += (long)z[zOff + i] - x[xOff + i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            return (int)c;
+        }
+
+        public static int SubWordAt(int len, uint x, uint[] z, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 1));
+            long c = (long)z[zPos] - x;
+            z[zPos] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zPos + 1);
+        }
+
+        public static int SubWordAt(int len, uint x, uint[] z, int zOff, int zPos)
+        {
+            Debug.Assert(zPos <= (len - 1));
+            long c = (long)z[zOff + zPos] - x;
+            z[zOff + zPos] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 1);
+        }
+
+        public static int SubWordFrom(int len, uint x, uint[] z)
+        {
+            long c = (long)z[0] - x;
+            z[0] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, 1);
+        }
+
+        public static int SubWordFrom(int len, uint x, uint[] z, int zOff)
+        {
+            long c = (long)z[zOff + 0] - x;
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : DecAt(len, z, zOff, 1);
+        }
+
+        public static BigInteger ToBigInteger(int len, uint[] x)
+        {
+            byte[] bs = new byte[len << 2];
+            for (int i = 0; i < len; ++i)
+            {
+                uint x_i = x[i];
+                if (x_i != 0)
+                {
+                    Pack.UInt32_To_BE(x_i, bs, (len - 1 - i) << 2);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        public static void Zero(int len, uint[] z)
+        {
+            for (int i = 0; i < len; ++i)
+            {
+                z[i] = 0;
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/ScaleXPointMap.cs b/crypto/src/math/ec/ScaleXPointMap.cs
new file mode 100644
index 000000000..f8a363b24
--- /dev/null
+++ b/crypto/src/math/ec/ScaleXPointMap.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    public class ScaleXPointMap
+        : ECPointMap
+    {
+        protected readonly ECFieldElement scale;
+
+        public ScaleXPointMap(ECFieldElement scale)
+        {
+            this.scale = scale;
+        }
+
+        public virtual ECPoint Map(ECPoint p)
+        {
+            return p.ScaleX(scale);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/ScaleYPointMap.cs b/crypto/src/math/ec/ScaleYPointMap.cs
new file mode 100644
index 000000000..1c4795b70
--- /dev/null
+++ b/crypto/src/math/ec/ScaleYPointMap.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC
+{
+    public class ScaleYPointMap
+        : ECPointMap
+    {
+        protected readonly ECFieldElement scale;
+
+        public ScaleYPointMap(ECFieldElement scale)
+        {
+            this.scale = scale;
+        }
+
+        public virtual ECPoint Map(ECPoint p)
+        {
+            return p.ScaleY(scale);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/abc/SimpleBigDecimal.cs b/crypto/src/math/ec/abc/SimpleBigDecimal.cs
new file mode 100644
index 000000000..d5664dbfd
--- /dev/null
+++ b/crypto/src/math/ec/abc/SimpleBigDecimal.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+	/**
+	* 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.
+	*/
+	internal class SimpleBigDecimal
+		//	: Number
+	{
+		//	private static final long serialVersionUID = 1L;
+
+		private readonly BigInteger	bigInt;
+		private readonly 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 val, int scale)
+		{
+			return new SimpleBigDecimal(val.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 ArgumentException("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 ArgumentException("Only SimpleBigDecimal of same scale allowed in arithmetic operations");
+		}
+
+		public SimpleBigDecimal AdjustScale(int newScale)
+		{
+			if (newScale < 0)
+				throw new ArgumentException("scale may not be negative");
+
+			if (newScale == scale)
+				return 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(BigInteger.One, 1);
+			return Add(oneHalf.AdjustScale(scale)).Floor();
+		}
+
+		public int IntValue
+		{
+			get { return Floor().IntValue; }
+		}
+
+		public long LongValue
+		{
+			get { return Floor().LongValue; }
+		}
+
+//		public double doubleValue()
+//		{
+//			return new Double(ToString()).doubleValue();
+//		}
+//
+//		public float floatValue()
+//		{
+//			return new Float(ToString()).floatValue();
+//		}
+
+		public int Scale
+		{
+			get { return scale; }
+		}
+
+		public override string ToString()
+		{
+			if (scale == 0)
+				return bigInt.ToString();
+
+			BigInteger floorBigInt = Floor();
+	        
+			BigInteger fract = bigInt.Subtract(floorBigInt.ShiftLeft(scale));
+			if (bigInt.SignValue < 0)
+			{
+				fract = BigInteger.One.ShiftLeft(scale).Subtract(fract);
+			}
+
+			if ((floorBigInt.SignValue == -1) && (!(fract.Equals(BigInteger.Zero))))
+			{
+				floorBigInt = floorBigInt.Add(BigInteger.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[j];
+			}
+			string rightOfPoint = new string(fractCharArr);
+
+			StringBuilder sb = new StringBuilder(leftOfPoint);
+			sb.Append(".");
+			sb.Append(rightOfPoint);
+
+			return sb.ToString();
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (this == obj)
+				return true;
+
+			SimpleBigDecimal other = obj as SimpleBigDecimal;
+
+			if (other == null)
+				return false;
+
+			return bigInt.Equals(other.bigInt)
+				&& scale == other.scale;
+		}
+
+		public override int GetHashCode()
+		{
+			return bigInt.GetHashCode() ^ scale;
+		}
+
+	}
+}
diff --git a/crypto/src/math/ec/abc/Tnaf.cs b/crypto/src/math/ec/abc/Tnaf.cs
index 225fc3075..9f16886f5 100644
--- a/crypto/src/math/ec/abc/Tnaf.cs
+++ b/crypto/src/math/ec/abc/Tnaf.cs
@@ -2,833 +2,827 @@ using System;
 
 namespace Org.BouncyCastle.Math.EC.Abc
 {
-	/**
-	* Class holding methods for point multiplication based on the window
-	* &#964;-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.
-	*/
-	internal class Tnaf
-	{
-		private static readonly BigInteger MinusOne = BigInteger.One.Negate();
-		private static readonly BigInteger MinusTwo = BigInteger.Two.Negate();
-		private static readonly BigInteger MinusThree = BigInteger.Three.Negate();
-		private static readonly BigInteger Four = BigInteger.ValueOf(4);
-
-		/**
-		* 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>&#945;<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 const sbyte Width = 4;
-
-		/**
-		* 2<sup>4</sup>
-		*/
-		public const sbyte Pow2Width = 16;
-
-		/**
-		* The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
-		* of <code>ZTauElement</code>s.
-		*/
-		public static readonly ZTauElement[] Alpha0 =
-		{
-			null,
-			new ZTauElement(BigInteger.One, BigInteger.Zero), null,
-			new ZTauElement(MinusThree, MinusOne), null,
-			new ZTauElement(MinusOne, MinusOne), null,
-			new ZTauElement(BigInteger.One, MinusOne), null
-		};
-
-		/**
-		* The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
-		* of TNAFs.
-		*/
-		public static readonly sbyte[][] Alpha0Tnaf =
-		{
-			null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1}
-		};
-
-		/**
-		* The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
-		* of <code>ZTauElement</code>s.
-		*/
-		public static readonly ZTauElement[] Alpha1 =
-		{
-			null,
-			new ZTauElement(BigInteger.One, BigInteger.Zero), null,
-			new ZTauElement(MinusThree, BigInteger.One), null,
-			new ZTauElement(MinusOne, BigInteger.One), null,
-			new ZTauElement(BigInteger.One, BigInteger.One), null
-		};
-
-		/**
-		* The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
-		* of TNAFs.
-		*/
-		public static readonly sbyte[][] Alpha1Tnaf =
-		{
-			null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1}
-		};
-
-		/**
-		* Computes the norm of an element <code>&#955;</code> of
-		* <code><b>Z</b>[&#964;]</code>.
-		* @param mu The parameter <code>&#956;</code> of the elliptic curve.
-		* @param lambda The element <code>&#955;</code> of
-		* <code><b>Z</b>[&#964;]</code>.
-		* @return The norm of <code>&#955;</code>.
-		*/
-		public static BigInteger Norm(sbyte 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 ArgumentException("mu must be 1 or -1");
-			}
-
-			return norm;
-		}
-
-		/**
-		* Computes the norm of an element <code>&#955;</code> of
-		* <code><b>R</b>[&#964;]</code>, where <code>&#955; = u + v&#964;</code>
-		* and <code>u</code> and <code>u</code> are real numbers (elements of
-		* <code><b>R</b></code>). 
-		* @param mu The parameter <code>&#956;</code> of the elliptic curve.
-		* @param u The real part of the element <code>&#955;</code> of
-		* <code><b>R</b>[&#964;]</code>.
-		* @param v The <code>&#964;</code>-adic part of the element
-		* <code>&#955;</code> of <code><b>R</b>[&#964;]</code>.
-		* @return The norm of <code>&#955;</code>.
-		*/
-		public static SimpleBigDecimal Norm(sbyte 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 ArgumentException("mu must be 1 or -1");
-			}
-
-			return norm;
-		}
-
-		/**
-		* Rounds an element <code>&#955;</code> of <code><b>R</b>[&#964;]</code>
-		* to an element of <code><b>Z</b>[&#964;]</code>, such that their difference
-		* has minimal norm. <code>&#955;</code> is given as
-		* <code>&#955; = &#955;<sub>0</sub> + &#955;<sub>1</sub>&#964;</code>.
-		* @param lambda0 The component <code>&#955;<sub>0</sub></code>.
-		* @param lambda1 The component <code>&#955;<sub>1</sub></code>.
-		* @param mu The parameter <code>&#956;</code> of the elliptic curve. Must
-		* equal 1 or -1.
-		* @return The rounded element of <code><b>Z</b>[&#964;]</code>.
-		* @throws ArgumentException if <code>lambda0</code> and
-		* <code>lambda1</code> do not have same scale.
-		*/
-		public static ZTauElement Round(SimpleBigDecimal lambda0,
-			SimpleBigDecimal lambda1, sbyte mu)
-		{
-			int scale = lambda0.Scale;
-			if (lambda1.Scale != scale)
-				throw new ArgumentException("lambda0 and lambda1 do not have same scale");
-
-			if (!((mu == 1) || (mu == -1)))
-				throw new ArgumentException("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);
-			}
-
-			sbyte h0 = 0;
-			sbyte h1 = 0;
-
-			// if eta >= 1
-			if (eta.CompareTo(BigInteger.One) >= 0)
-			{
-				if (check1.CompareTo(MinusOne) < 0)
-				{
-					h1 = mu;
-				}
-				else
-				{
-					h0 = 1;
-				}
-			}
-			else
-			{
-				// eta < 1
-				if (check2.CompareTo(BigInteger.Two) >= 0)
-				{
-					h1 = mu;
-				}
-			}
-
-			// if eta < -1
-			if (eta.CompareTo(MinusOne) < 0)
-			{
-				if (check1.CompareTo(BigInteger.One) >= 0)
-				{
-					h1 = (sbyte)-mu;
-				}
-				else
-				{
-					h0 = -1;
-				}
-			}
-			else
-			{
-				// eta >= -1
-				if (check2.CompareTo(MinusTwo) < 0)
-				{
-					h1 = (sbyte)-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>&#955; = 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>&#955; = s k / n</code> computed to
-		* <code>c</code> bits of accuracy.
-		*/
-		public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k,
-			BigInteger s, BigInteger vm, sbyte 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(BigInteger.One);
-			}
-
-			return new SimpleBigDecimal(ls, c);
-		}
-
-		/**
-		* Computes the <code>&#964;</code>-adic NAF (non-adjacent form) of an
-		* element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>.
-		* @param mu The parameter <code>&#956;</code> of the elliptic curve.
-		* @param lambda The element <code>&#955;</code> of
-		* <code><b>Z</b>[&#964;]</code>.
-		* @return The <code>&#964;</code>-adic NAF of <code>&#955;</code>.
-		*/
-		public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda)
-		{
-			if (!((mu == 1) || (mu == -1))) 
-				throw new ArgumentException("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
-			sbyte[] u = new sbyte[maxLength];
-			int i = 0;
-
-			// The actual length of the TNAF
-			int length = 0;
-
-			BigInteger r0 = lambda.u;
-			BigInteger r1 = lambda.v;
-
-			while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero))))
-			{
-				// If r0 is odd
-				if (r0.TestBit(0)) 
-				{
-					u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue;
-
-					// r0 = r0 - u[i]
-					if (u[i] == 1)
-					{
-						r0 = r0.ClearBit(0);
-					}
-					else
-					{
-						// u[i] == -1
-						r0 = r0.Add(BigInteger.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
-			sbyte[] tnaf = new sbyte[length];
-			Array.Copy(u, 0, tnaf, 0, length);
-			return tnaf;
-		}
-
-		/**
-		* Applies the operation <code>&#964;()</code> to an
-		* <code>F2mPoint</code>. 
-		* @param p The F2mPoint to which <code>&#964;()</code> is applied.
-		* @return <code>&#964;(p)</code>
-		*/
-		public static F2mPoint Tau(F2mPoint p)
-		{
-			if (p.IsInfinity)
-				return p;
-
-			ECFieldElement x = p.X;
-			ECFieldElement y = p.Y;
-
-			return new F2mPoint(p.Curve, x.Square(), y.Square(), p.IsCompressed);
-		}
-
-		/**
-		* Returns the parameter <code>&#956;</code> of the elliptic curve.
-		* @param curve The elliptic curve from which to obtain <code>&#956;</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>&#956;</code> of the elliptic curve.
-		* @throws ArgumentException if the given ECCurve is not a Koblitz
-		* curve.
-		*/
-		public static sbyte GetMu(F2mCurve curve)
-		{
-			BigInteger a = curve.A.ToBigInteger();
-
-			sbyte mu;
-			if (a.SignValue == 0)
-			{
-				mu = -1;
-			}
-			else if (a.Equals(BigInteger.One))
-			{
-				mu = 1;
-			}
-			else
-			{
-				throw new ArgumentException("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>&#956;</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(sbyte mu, int k, bool doV)
-		{
-			if (!(mu == 1 || mu == -1)) 
-				throw new ArgumentException("mu must be 1 or -1");
-
-			BigInteger u0;
-			BigInteger u1;
-			BigInteger u2;
-
-			if (doV)
-			{
-				u0 = BigInteger.Two;
-				u1 = BigInteger.ValueOf(mu);
-			}
-			else
-			{
-				u0 = BigInteger.Zero;
-				u1 = BigInteger.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>&#956;</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(sbyte 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 = BigInteger.Zero.SetBit(w);
-				BigInteger u1invert = us[1].ModInverse(twoToW);
-				BigInteger tw;
-				tw = BigInteger.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 ArgumentException if <code>curve</code> is not a
-		* Koblitz curve (Anomalous Binary Curve, ABC).
-		*/
-		public static BigInteger[] GetSi(F2mCurve curve)
-		{
-			if (!curve.IsKoblitz)
-				throw new ArgumentException("si is defined for Koblitz curves only");
-
-			int m = curve.M;
-			int a = curve.A.ToBigInteger().IntValue;
-			sbyte mu = curve.GetMu();
-			int h = curve.H.IntValue;
-			int index = m + 3 - a;
-			BigInteger[] ui = GetLucas(mu, index, false);
-
-			BigInteger dividend0;
-			BigInteger dividend1;
-			if (mu == 1)
-			{
-				dividend0 = BigInteger.One.Subtract(ui[1]);
-				dividend1 = BigInteger.One.Subtract(ui[0]);
-			}
-			else if (mu == -1)
-			{
-				dividend0 = BigInteger.One.Add(ui[1]);
-				dividend1 = BigInteger.One.Add(ui[0]);
-			}
-			else
-			{
-				throw new ArgumentException("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 ArgumentException("h (Cofactor) must be 2 or 4");
-			}
-
-			return si;
-		}
-
-		/**
-		* Partial modular reduction modulo
-		* <code>(&#964;<sup>m</sup> - 1)/(&#964; - 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 &#956; of the elliptic curve.
-		* @param c The precision (number of bits of accuracy) of the partial
-		* modular reduction.
-		* @return <code>&#961; := k partmod (&#964;<sup>m</sup> - 1)/(&#964; - 1)</code>
-		*/
-		public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a,
-			BigInteger[] s, sbyte mu, sbyte 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.F2mPoint F2mPoint}
-		* by a <code>BigInteger</code> using the reduced <code>&#964;</code>-adic
-		* NAF (RTNAF) method.
-		* @param p The F2mPoint to Multiply.
-		* @param k The <code>BigInteger</code> by which to Multiply <code>p</code>.
-		* @return <code>k * p</code>
-		*/
-		public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k)
-		{
-			F2mCurve curve = (F2mCurve) p.Curve;
-			int m = curve.M;
-			sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
-			sbyte mu = curve.GetMu();
-			BigInteger[] s = curve.GetSi();
-			ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10);
-
-			return MultiplyTnaf(p, rho);
-		}
-
-		/**
-		* Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
-		* by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
-		* using the <code>&#964;</code>-adic NAF (TNAF) method.
-		* @param p The F2mPoint to Multiply.
-		* @param lambda The element <code>&#955;</code> of
-		* <code><b>Z</b>[&#964;]</code>.
-		* @return <code>&#955; * p</code>
-		*/
-		public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda)
-		{
-			F2mCurve curve = (F2mCurve)p.Curve;
-			sbyte mu = curve.GetMu();
-			sbyte[] u = TauAdicNaf(mu, lambda);
-
-			F2mPoint q = MultiplyFromTnaf(p, u);
-
-			return q;
-		}
-
-		/**
-		* Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
-		* by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
-		* using the <code>&#964;</code>-adic NAF (TNAF) method, given the TNAF
-		* of <code>&#955;</code>.
-		* @param p The F2mPoint to Multiply.
-		* @param u The the TNAF of <code>&#955;</code>..
-		* @return <code>&#955; * p</code>
-		*/
-		public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u)
-		{
-			F2mCurve curve = (F2mCurve)p.Curve;
-			F2mPoint q = (F2mPoint) curve.Infinity;
-			for (int i = u.Length - 1; i >= 0; i--)
-			{
-				q = Tau(q);
-				if (u[i] == 1)
-				{
-					q = (F2mPoint)q.AddSimple(p);
-				}
-				else if (u[i] == -1)
-				{
-					q = (F2mPoint)q.SubtractSimple(p);
-				}
-			}
-			return q;
-		}
-
-		/**
-		* Computes the <code>[&#964;]</code>-adic window NAF of an element
-		* <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>.
-		* @param mu The parameter &#956; of the elliptic curve.
-		* @param lambda The element <code>&#955;</code> of
-		* <code><b>Z</b>[&#964;]</code> of which to compute the
-		* <code>[&#964;]</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>&#945;<sub>u</sub></code>'s for the window width.
-		* @return The <code>[&#964;]</code>-adic window NAF of
-		* <code>&#955;</code>.
-		*/
-		public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda,
-			sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
-		{
-			if (!((mu == 1) || (mu == -1))) 
-				throw new ArgumentException("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
-			sbyte[] u = new sbyte[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(BigInteger.Zero))&&(r1.Equals(BigInteger.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);
-	                
-					sbyte uLocal;
-					// if uUnMod >= 2^(width - 1)
-					if (uUnMod.CompareTo(pow2wMin1) >= 0)
-					{
-						uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue;
-					}
-					else
-					{
-						uLocal = (sbyte) uUnMod.IntValue;
-					}
-					// uLocal is now in [-2^(width-1), 2^(width-1)-1]
-
-					u[i] = uLocal;
-					bool s = true;
-					if (uLocal < 0) 
-					{
-						s = false;
-						uLocal = (sbyte)-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 F2mPoint[] GetPreComp(F2mPoint p, sbyte a)
-		{
-			F2mPoint[] pu;
-			pu = new F2mPoint[16];
-			pu[1] = p;
-			sbyte[][] 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;
-		}
-	}
+    /**
+    * Class holding methods for point multiplication based on the window
+    * &#964;-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.
+    */
+    internal class Tnaf
+    {
+        private static readonly BigInteger MinusOne = BigInteger.One.Negate();
+        private static readonly BigInteger MinusTwo = BigInteger.Two.Negate();
+        private static readonly BigInteger MinusThree = BigInteger.Three.Negate();
+        private static readonly BigInteger Four = BigInteger.ValueOf(4);
+
+        /**
+        * 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>&#945;<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 const sbyte Width = 4;
+
+        /**
+        * 2<sup>4</sup>
+        */
+        public const sbyte Pow2Width = 16;
+
+        /**
+        * The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
+        * of <code>ZTauElement</code>s.
+        */
+        public static readonly ZTauElement[] Alpha0 =
+        {
+            null,
+            new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+            new ZTauElement(MinusThree, MinusOne), null,
+            new ZTauElement(MinusOne, MinusOne), null,
+            new ZTauElement(BigInteger.One, MinusOne), null
+        };
+
+        /**
+        * The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
+        * of TNAFs.
+        */
+        public static readonly sbyte[][] Alpha0Tnaf =
+        {
+            null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1}
+        };
+
+        /**
+        * The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
+        * of <code>ZTauElement</code>s.
+        */
+        public static readonly ZTauElement[] Alpha1 =
+        {
+            null,
+            new ZTauElement(BigInteger.One, BigInteger.Zero), null,
+            new ZTauElement(MinusThree, BigInteger.One), null,
+            new ZTauElement(MinusOne, BigInteger.One), null,
+            new ZTauElement(BigInteger.One, BigInteger.One), null
+        };
+
+        /**
+        * The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
+        * of TNAFs.
+        */
+        public static readonly sbyte[][] Alpha1Tnaf =
+        {
+            null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1}
+        };
+
+        /**
+        * Computes the norm of an element <code>&#955;</code> of
+        * <code><b>Z</b>[&#964;]</code>.
+        * @param mu The parameter <code>&#956;</code> of the elliptic curve.
+        * @param lambda The element <code>&#955;</code> of
+        * <code><b>Z</b>[&#964;]</code>.
+        * @return The norm of <code>&#955;</code>.
+        */
+        public static BigInteger Norm(sbyte 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 ArgumentException("mu must be 1 or -1");
+            }
+
+            return norm;
+        }
+
+        /**
+        * Computes the norm of an element <code>&#955;</code> of
+        * <code><b>R</b>[&#964;]</code>, where <code>&#955; = u + v&#964;</code>
+        * and <code>u</code> and <code>u</code> are real numbers (elements of
+        * <code><b>R</b></code>). 
+        * @param mu The parameter <code>&#956;</code> of the elliptic curve.
+        * @param u The real part of the element <code>&#955;</code> of
+        * <code><b>R</b>[&#964;]</code>.
+        * @param v The <code>&#964;</code>-adic part of the element
+        * <code>&#955;</code> of <code><b>R</b>[&#964;]</code>.
+        * @return The norm of <code>&#955;</code>.
+        */
+        public static SimpleBigDecimal Norm(sbyte 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 ArgumentException("mu must be 1 or -1");
+            }
+
+            return norm;
+        }
+
+        /**
+        * Rounds an element <code>&#955;</code> of <code><b>R</b>[&#964;]</code>
+        * to an element of <code><b>Z</b>[&#964;]</code>, such that their difference
+        * has minimal norm. <code>&#955;</code> is given as
+        * <code>&#955; = &#955;<sub>0</sub> + &#955;<sub>1</sub>&#964;</code>.
+        * @param lambda0 The component <code>&#955;<sub>0</sub></code>.
+        * @param lambda1 The component <code>&#955;<sub>1</sub></code>.
+        * @param mu The parameter <code>&#956;</code> of the elliptic curve. Must
+        * equal 1 or -1.
+        * @return The rounded element of <code><b>Z</b>[&#964;]</code>.
+        * @throws ArgumentException if <code>lambda0</code> and
+        * <code>lambda1</code> do not have same scale.
+        */
+        public static ZTauElement Round(SimpleBigDecimal lambda0,
+            SimpleBigDecimal lambda1, sbyte mu)
+        {
+            int scale = lambda0.Scale;
+            if (lambda1.Scale != scale)
+                throw new ArgumentException("lambda0 and lambda1 do not have same scale");
+
+            if (!((mu == 1) || (mu == -1)))
+                throw new ArgumentException("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);
+            }
+
+            sbyte h0 = 0;
+            sbyte h1 = 0;
+
+            // if eta >= 1
+            if (eta.CompareTo(BigInteger.One) >= 0)
+            {
+                if (check1.CompareTo(MinusOne) < 0)
+                {
+                    h1 = mu;
+                }
+                else
+                {
+                    h0 = 1;
+                }
+            }
+            else
+            {
+                // eta < 1
+                if (check2.CompareTo(BigInteger.Two) >= 0)
+                {
+                    h1 = mu;
+                }
+            }
+
+            // if eta < -1
+            if (eta.CompareTo(MinusOne) < 0)
+            {
+                if (check1.CompareTo(BigInteger.One) >= 0)
+                {
+                    h1 = (sbyte)-mu;
+                }
+                else
+                {
+                    h0 = -1;
+                }
+            }
+            else
+            {
+                // eta >= -1
+                if (check2.CompareTo(MinusTwo) < 0)
+                {
+                    h1 = (sbyte)-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>&#955; = 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>&#955; = s k / n</code> computed to
+        * <code>c</code> bits of accuracy.
+        */
+        public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k,
+            BigInteger s, BigInteger vm, sbyte 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(BigInteger.One);
+            }
+
+            return new SimpleBigDecimal(ls, c);
+        }
+
+        /**
+        * Computes the <code>&#964;</code>-adic NAF (non-adjacent form) of an
+        * element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>.
+        * @param mu The parameter <code>&#956;</code> of the elliptic curve.
+        * @param lambda The element <code>&#955;</code> of
+        * <code><b>Z</b>[&#964;]</code>.
+        * @return The <code>&#964;</code>-adic NAF of <code>&#955;</code>.
+        */
+        public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda)
+        {
+            if (!((mu == 1) || (mu == -1))) 
+                throw new ArgumentException("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
+            sbyte[] u = new sbyte[maxLength];
+            int i = 0;
+
+            // The actual length of the TNAF
+            int length = 0;
+
+            BigInteger r0 = lambda.u;
+            BigInteger r1 = lambda.v;
+
+            while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero))))
+            {
+                // If r0 is odd
+                if (r0.TestBit(0)) 
+                {
+                    u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue;
+
+                    // r0 = r0 - u[i]
+                    if (u[i] == 1)
+                    {
+                        r0 = r0.ClearBit(0);
+                    }
+                    else
+                    {
+                        // u[i] == -1
+                        r0 = r0.Add(BigInteger.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
+            sbyte[] tnaf = new sbyte[length];
+            Array.Copy(u, 0, tnaf, 0, length);
+            return tnaf;
+        }
+
+        /**
+        * Applies the operation <code>&#964;()</code> to an
+        * <code>F2mPoint</code>. 
+        * @param p The F2mPoint to which <code>&#964;()</code> is applied.
+        * @return <code>&#964;(p)</code>
+        */
+        public static F2mPoint Tau(F2mPoint p)
+        {
+            return p.Tau();
+        }
+
+        /**
+        * Returns the parameter <code>&#956;</code> of the elliptic curve.
+        * @param curve The elliptic curve from which to obtain <code>&#956;</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>&#956;</code> of the elliptic curve.
+        * @throws ArgumentException if the given ECCurve is not a Koblitz
+        * curve.
+        */
+        public static sbyte GetMu(F2mCurve curve)
+        {
+            BigInteger a = curve.A.ToBigInteger();
+
+            sbyte mu;
+            if (a.SignValue == 0)
+            {
+                mu = -1;
+            }
+            else if (a.Equals(BigInteger.One))
+            {
+                mu = 1;
+            }
+            else
+            {
+                throw new ArgumentException("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>&#956;</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(sbyte mu, int k, bool doV)
+        {
+            if (!(mu == 1 || mu == -1)) 
+                throw new ArgumentException("mu must be 1 or -1");
+
+            BigInteger u0;
+            BigInteger u1;
+            BigInteger u2;
+
+            if (doV)
+            {
+                u0 = BigInteger.Two;
+                u1 = BigInteger.ValueOf(mu);
+            }
+            else
+            {
+                u0 = BigInteger.Zero;
+                u1 = BigInteger.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>&#956;</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(sbyte 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 = BigInteger.Zero.SetBit(w);
+                BigInteger u1invert = us[1].ModInverse(twoToW);
+                BigInteger tw;
+                tw = BigInteger.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 ArgumentException if <code>curve</code> is not a
+        * Koblitz curve (Anomalous Binary Curve, ABC).
+        */
+        public static BigInteger[] GetSi(F2mCurve curve)
+        {
+            if (!curve.IsKoblitz)
+                throw new ArgumentException("si is defined for Koblitz curves only");
+
+            int m = curve.M;
+            int a = curve.A.ToBigInteger().IntValue;
+            sbyte mu = curve.GetMu();
+            int h = curve.Cofactor.IntValue;
+            int index = m + 3 - a;
+            BigInteger[] ui = GetLucas(mu, index, false);
+
+            BigInteger dividend0;
+            BigInteger dividend1;
+            if (mu == 1)
+            {
+                dividend0 = BigInteger.One.Subtract(ui[1]);
+                dividend1 = BigInteger.One.Subtract(ui[0]);
+            }
+            else if (mu == -1)
+            {
+                dividend0 = BigInteger.One.Add(ui[1]);
+                dividend1 = BigInteger.One.Add(ui[0]);
+            }
+            else
+            {
+                throw new ArgumentException("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 ArgumentException("h (Cofactor) must be 2 or 4");
+            }
+
+            return si;
+        }
+
+        /**
+        * Partial modular reduction modulo
+        * <code>(&#964;<sup>m</sup> - 1)/(&#964; - 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 &#956; of the elliptic curve.
+        * @param c The precision (number of bits of accuracy) of the partial
+        * modular reduction.
+        * @return <code>&#961; := k partmod (&#964;<sup>m</sup> - 1)/(&#964; - 1)</code>
+        */
+        public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a,
+            BigInteger[] s, sbyte mu, sbyte 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.F2mPoint F2mPoint}
+        * by a <code>BigInteger</code> using the reduced <code>&#964;</code>-adic
+        * NAF (RTNAF) method.
+        * @param p The F2mPoint to Multiply.
+        * @param k The <code>BigInteger</code> by which to Multiply <code>p</code>.
+        * @return <code>k * p</code>
+        */
+        public static F2mPoint MultiplyRTnaf(F2mPoint p, BigInteger k)
+        {
+            F2mCurve curve = (F2mCurve) p.Curve;
+            int m = curve.M;
+            sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
+            sbyte mu = curve.GetMu();
+            BigInteger[] s = curve.GetSi();
+            ZTauElement rho = PartModReduction(k, m, a, s, mu, (sbyte)10);
+
+            return MultiplyTnaf(p, rho);
+        }
+
+        /**
+        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
+        * using the <code>&#964;</code>-adic NAF (TNAF) method.
+        * @param p The F2mPoint to Multiply.
+        * @param lambda The element <code>&#955;</code> of
+        * <code><b>Z</b>[&#964;]</code>.
+        * @return <code>&#955; * p</code>
+        */
+        public static F2mPoint MultiplyTnaf(F2mPoint p, ZTauElement lambda)
+        {
+            F2mCurve curve = (F2mCurve)p.Curve;
+            sbyte mu = curve.GetMu();
+            sbyte[] u = TauAdicNaf(mu, lambda);
+
+            F2mPoint q = MultiplyFromTnaf(p, u);
+
+            return q;
+        }
+
+        /**
+        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
+        * using the <code>&#964;</code>-adic NAF (TNAF) method, given the TNAF
+        * of <code>&#955;</code>.
+        * @param p The F2mPoint to Multiply.
+        * @param u The the TNAF of <code>&#955;</code>..
+        * @return <code>&#955; * p</code>
+        */
+        public static F2mPoint MultiplyFromTnaf(F2mPoint p, sbyte[] u)
+        {
+            F2mCurve curve = (F2mCurve)p.Curve;
+            F2mPoint q = (F2mPoint) curve.Infinity;
+            for (int i = u.Length - 1; i >= 0; i--)
+            {
+                q = Tau(q);
+                if (u[i] == 1)
+                {
+                    q = (F2mPoint)q.AddSimple(p);
+                }
+                else if (u[i] == -1)
+                {
+                    q = (F2mPoint)q.SubtractSimple(p);
+                }
+            }
+            return q;
+        }
+
+        /**
+        * Computes the <code>[&#964;]</code>-adic window NAF of an element
+        * <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>.
+        * @param mu The parameter &#956; of the elliptic curve.
+        * @param lambda The element <code>&#955;</code> of
+        * <code><b>Z</b>[&#964;]</code> of which to compute the
+        * <code>[&#964;]</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>&#945;<sub>u</sub></code>'s for the window width.
+        * @return The <code>[&#964;]</code>-adic window NAF of
+        * <code>&#955;</code>.
+        */
+        public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda,
+            sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+        {
+            if (!((mu == 1) || (mu == -1))) 
+                throw new ArgumentException("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
+            sbyte[] u = new sbyte[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(BigInteger.Zero))&&(r1.Equals(BigInteger.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);
+                    
+                    sbyte uLocal;
+                    // if uUnMod >= 2^(width - 1)
+                    if (uUnMod.CompareTo(pow2wMin1) >= 0)
+                    {
+                        uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue;
+                    }
+                    else
+                    {
+                        uLocal = (sbyte) uUnMod.IntValue;
+                    }
+                    // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+                    u[i] = uLocal;
+                    bool s = true;
+                    if (uLocal < 0) 
+                    {
+                        s = false;
+                        uLocal = (sbyte)-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 F2mPoint[] GetPreComp(F2mPoint p, sbyte a)
+        {
+            F2mPoint[] pu;
+            pu = new F2mPoint[16];
+            pu[1] = p;
+            sbyte[][] 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/crypto/src/math/ec/abc/ZTauElement.cs b/crypto/src/math/ec/abc/ZTauElement.cs
new file mode 100644
index 000000000..4fcbf1bdf
--- /dev/null
+++ b/crypto/src/math/ec/abc/ZTauElement.cs
@@ -0,0 +1,36 @@
+namespace Org.BouncyCastle.Math.EC.Abc
+{
+	/**
+	* Class representing an element of <code><b>Z</b>[&#964;]</code>. Let
+	* <code>&#955;</code> be an element of <code><b>Z</b>[&#964;]</code>. Then
+	* <code>&#955;</code> is given as <code>&#955; = u + v&#964;</code>. The
+	* components <code>u</code> and <code>v</code> may be used directly, there
+	* are no accessor methods.
+	* Immutable class.
+	*/
+	internal class ZTauElement 
+	{
+		/**
+		* The &quot;real&quot; part of <code>&#955;</code>.
+		*/
+		public readonly BigInteger u;
+
+		/**
+		* The &quot;<code>&#964;</code>-adic&quot; part of <code>&#955;</code>.
+		*/
+		public readonly BigInteger v;
+
+		/**
+		* Constructor for an element <code>&#955;</code> of
+		* <code><b>Z</b>[&#964;]</code>.
+		* @param u The &quot;real&quot; part of <code>&#955;</code>.
+		* @param v The &quot;<code>&#964;</code>-adic&quot; part of
+		* <code>&#955;</code>.
+		*/
+		public ZTauElement(BigInteger u, BigInteger v)
+		{
+			this.u = u;
+			this.v = v;
+		}
+	}
+}
diff --git a/crypto/src/math/ec/custom/djb/Curve25519.cs b/crypto/src/math/ec/custom/djb/Curve25519.cs
new file mode 100644
index 000000000..712b68f29
--- /dev/null
+++ b/crypto/src/math/ec/custom/djb/Curve25519.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+    internal class Curve25519
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = Nat256.ToBigInteger(Curve25519Field.P);
+
+        private const int Curve25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
+
+        protected readonly Curve25519Point m_infinity;
+
+        public Curve25519()
+            : base(q)
+        {
+            this.m_infinity = new Curve25519Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864")));
+            this.m_order = new BigInteger(1, Hex.Decode("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED"));
+            this.m_cofactor = BigInteger.ValueOf(8);
+            this.m_coord = Curve25519_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new Curve25519();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN_MODIFIED:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new Curve25519FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new Curve25519Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new Curve25519Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/djb/Curve25519Field.cs b/crypto/src/math/ec/custom/djb/Curve25519Field.cs
new file mode 100644
index 000000000..809e51b80
--- /dev/null
+++ b/crypto/src/math/ec/custom/djb/Curve25519Field.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Math.EC.Custom.Sec;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+    internal class Curve25519Field
+    {
+        // 2^255 - 2^4 - 2^1 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0x7FFFFFFF };
+        private const uint P7 = 0x7FFFFFFF;
+        private static readonly uint[] PExt = new uint[]{ 0x00000169, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+            0x00000000, 0x00000000, 0x00000000, 0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0x3FFFFFFF };
+        private const uint PInv = 0x13;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            Nat256.Add(x, y, z);
+            if (Nat256.Gte(z, P))
+            {
+                SubPFrom(z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            Nat.Add(16, xx, yy, zz);
+            if (Nat.Gte(16, zz, PExt))
+            {
+                SubPExtFrom(zz);
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            Nat.Inc(8, x, z);
+            if (Nat256.Gte(z, P))
+            {
+                SubPFrom(z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat256.FromBigInteger(x);
+            while (Nat256.Gte(z, P))
+            {
+                Nat256.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(8, x, 0, z);
+            }
+            else
+            {
+                Nat256.Add(x, P, z);
+                Nat.ShiftDownBit(8, z, 0);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            Nat256.MulAddTo(x, y, zz);
+            if (Nat.Gte(16, zz, PExt))
+            {
+                SubPExtFrom(zz);
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat256.IsZero(x))
+            {
+                Nat256.Zero(z);
+            }
+            else
+            {
+                Nat256.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            Debug.Assert(xx[15] >> 30 == 0);
+
+            uint xx07 = xx[7];
+            Nat.ShiftUpBit(8, xx, 8, xx07, z, 0);
+            uint c = Nat256.MulByWordAddTo(PInv, xx, z) << 1;
+            uint z7 = z[7];
+            c += (z7 >> 31) - (xx07 >> 31);
+            z7 &= P7;
+            z7 += Nat.AddWordTo(7, c * PInv, z);
+            z[7] = z7;
+            if (z7 >= P7 && Nat256.Gte(z, P))
+            {
+                SubPFrom(z);
+            }
+        }
+
+        public static void Reduce27(uint x, uint[] z)
+        {
+            Debug.Assert(x >> 26 == 0);
+
+            uint z7 = z[7];
+            uint c = (x << 1 | z7 >> 31);
+            z7 &= P7;
+            z7 += Nat.AddWordTo(7, c * PInv, z);
+            z[7] = z7;
+            if (z7 >= P7 && Nat256.Gte(z, P))
+            {
+                SubPFrom(z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat256.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat256.Sub(x, y, z);
+            if (c != 0)
+            {
+                AddPTo(z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(16, xx, yy, zz);
+            if (c != 0)
+            {
+                AddPExtTo(zz);
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            Nat.ShiftUpBit(8, x, 0, z);
+            if (Nat256.Gte(z, P))
+            {
+                SubPFrom(z);
+            }
+        }
+
+        private static uint AddPTo(uint[] z)
+        {
+            long c = (long)z[0] - PInv;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c = Nat.DecAt(7, z, 1);
+            }
+            c += (long)z[7] + (P7 + 1);
+            z[7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        private static uint AddPExtTo(uint[] zz)
+        {
+            long c = (long)zz[0] + PExt[0];
+            zz[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c = Nat.IncAt(8, zz, 1);
+            }
+            c += (long)zz[8] - PInv;
+            zz[8] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c = Nat.DecAt(15, zz, 9);
+            }
+            c += (long)zz[15] + (PExt[15] + 1);
+            zz[15] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        private static int SubPFrom(uint[] z)
+        {
+            long c = (long)z[0] + PInv;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c = Nat.IncAt(7, z, 1);
+            }
+            c += (long)z[7] - (P7 + 1);
+            z[7] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        private static int SubPExtFrom(uint[] zz)
+        {
+            long c = (long)zz[0] - PExt[0];
+            zz[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c = Nat.DecAt(8, zz, 1);
+            }
+            c += (long)zz[8] + PInv;
+            zz[8] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c = Nat.IncAt(15, zz, 9);
+            }
+            c += (long)zz[15] - (PExt[15] + 1);
+            zz[15] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
new file mode 100644
index 000000000..8d5a80326
--- /dev/null
+++ b/crypto/src/math/ec/custom/djb/Curve25519FieldElement.cs
@@ -0,0 +1,233 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Custom.Sec;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+    internal class Curve25519FieldElement
+        :   ECFieldElement
+    {
+        public static readonly BigInteger Q = Curve25519.q;
+
+        // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q)
+        private static readonly uint[] PRECOMP_POW2 = new uint[]{ 0x4a0ea0b0, 0xc4ee1b27, 0xad2fe478, 0x2f431806,
+            0x3dfbd7a7, 0x2b4d0099, 0x4fc1df0b, 0x2b832480 };
+
+        protected internal readonly uint[] x;
+
+        public Curve25519FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for Curve25519FieldElement", "x");
+
+            this.x = Curve25519Field.FromBigInteger(x);
+        }
+
+        public Curve25519FieldElement()
+        {
+            this.x = Nat256.Create();
+        }
+
+        protected internal Curve25519FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat256.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat256.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat256.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat256.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "Curve25519Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            Curve25519Field.Add(x, ((Curve25519FieldElement)b).x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat256.Create();
+            Curve25519Field.AddOne(x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            Curve25519Field.Subtract(x, ((Curve25519FieldElement)b).x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            Curve25519Field.Multiply(x, ((Curve25519FieldElement)b).x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat256.Create();
+            Mod.Invert(Curve25519Field.P, ((Curve25519FieldElement)b).x, z);
+            Curve25519Field.Multiply(z, x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat256.Create();
+            Curve25519Field.Negate(x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat256.Create();
+            Curve25519Field.Square(x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new Curve25519FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat256.Create();
+            Mod.Invert(Curve25519Field.P, x, z);
+            return new Curve25519FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Q == 8m + 5, so we use Pocklington's method for this case.
+             *
+             * First, raise this element to the exponent 2^252 - 2^1 (i.e. m + 1)
+             * 
+             * Breaking up the exponent's binary representation into "repunits", we get:
+             * { 251 1s } { 1 0s }
+             * 
+             * Therefore we need an addition chain containing 251 (the lengths of the repunits)
+             * We use: 1, 2, 3, 4, 7, 11, 15, 30, 60, 120, 131, [251]
+             */
+
+            uint[] x1 = this.x;
+            if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+                return this;
+
+            uint[] x2 = Nat256.Create();
+            Curve25519Field.Square(x1, x2);
+            Curve25519Field.Multiply(x2, x1, x2);
+            uint[] x3 = x2;
+            Curve25519Field.Square(x2, x3);
+            Curve25519Field.Multiply(x3, x1, x3);
+            uint[] x4 = Nat256.Create();
+            Curve25519Field.Square(x3, x4);
+            Curve25519Field.Multiply(x4, x1, x4);
+            uint[] x7 = Nat256.Create();
+            Curve25519Field.SquareN(x4, 3, x7);
+            Curve25519Field.Multiply(x7, x3, x7);
+            uint[] x11 = x3;
+            Curve25519Field.SquareN(x7, 4, x11);
+            Curve25519Field.Multiply(x11, x4, x11);
+            uint[] x15 = x7;
+            Curve25519Field.SquareN(x11, 4, x15);
+            Curve25519Field.Multiply(x15, x4, x15);
+            uint[] x30 = x4;
+            Curve25519Field.SquareN(x15, 15, x30);
+            Curve25519Field.Multiply(x30, x15, x30);
+            uint[] x60 = x15;
+            Curve25519Field.SquareN(x30, 30, x60);
+            Curve25519Field.Multiply(x60, x30, x60);
+            uint[] x120 = x30;
+            Curve25519Field.SquareN(x60, 60, x120);
+            Curve25519Field.Multiply(x120, x60, x120);
+            uint[] x131 = x60;
+            Curve25519Field.SquareN(x120, 11, x131);
+            Curve25519Field.Multiply(x131, x11, x131);
+            uint[] x251 = x11;
+            Curve25519Field.SquareN(x131, 120, x251);
+            Curve25519Field.Multiply(x251, x120, x251);
+
+            uint[] t1 = x251;
+            Curve25519Field.Square(t1, t1);
+
+            uint[] t2 = x120;
+            Curve25519Field.Square(t1, t2);
+
+            if (Nat256.Eq(x1, t2))
+            {
+                return new Curve25519FieldElement(t1);
+            }
+
+            /*
+             * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
+             * which is ((4x)^(m + 1))/2 mod Q
+             */
+            Curve25519Field.Multiply(t1, PRECOMP_POW2, t1);
+
+            Curve25519Field.Square(t1, t2);
+
+            if (Nat256.Eq(x1, t2))
+            {
+                return new Curve25519FieldElement(t1);
+            }
+
+            return null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as Curve25519FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as Curve25519FieldElement);
+        }
+
+        public virtual bool Equals(Curve25519FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat256.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/djb/Curve25519Point.cs b/crypto/src/math/ec/custom/djb/Curve25519Point.cs
new file mode 100644
index 000000000..bfec1d11d
--- /dev/null
+++ b/crypto/src/math/ec/custom/djb/Curve25519Point.cs
@@ -0,0 +1,313 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Custom.Sec;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Djb
+{
+    internal class Curve25519Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve the curve to use
+         * @param x affine x co-ordinate
+         * @param y affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.CreatePoint to construct points
+         */
+        public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve the curve to use
+         * @param x affine x co-ordinate
+         * @param y affine y co-ordinate
+         * @param withCompression if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer {@link #getEncoded(bool)}
+         */
+        public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new Curve25519Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECFieldElement GetZCoord(int index)
+        {
+            if (index == 1)
+            {
+                return GetJacobianModifiedW();
+            }
+
+            return base.GetZCoord(index);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            Curve25519FieldElement X1 = (Curve25519FieldElement)this.RawXCoord, Y1 = (Curve25519FieldElement)this.RawYCoord,
+                Z1 = (Curve25519FieldElement)this.RawZCoords[0];
+            Curve25519FieldElement X2 = (Curve25519FieldElement)b.RawXCoord, Y2 = (Curve25519FieldElement)b.RawYCoord,
+                Z2 = (Curve25519FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat256.CreateExt();
+            uint[] t2 = Nat256.Create();
+            uint[] t3 = Nat256.Create();
+            uint[] t4 = Nat256.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                Curve25519Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                Curve25519Field.Multiply(S2, X2.x, U2);
+
+                Curve25519Field.Multiply(S2, Z1.x, S2);
+                Curve25519Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                Curve25519Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                Curve25519Field.Multiply(S1, X1.x, U1);
+
+                Curve25519Field.Multiply(S1, Z2.x, S1);
+                Curve25519Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat256.Create();
+            Curve25519Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            Curve25519Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat256.IsZero(H))
+            {
+                if (Nat256.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = Nat256.Create();
+            Curve25519Field.Square(H, HSquared);
+
+            uint[] G = Nat256.Create();
+            Curve25519Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            Curve25519Field.Multiply(HSquared, U1, V);
+
+            Curve25519Field.Negate(G, G);
+            Nat256.Mul(S1, G, tt1);
+
+            c = Nat256.AddBothTo(V, V, G);
+            Curve25519Field.Reduce27(c, G);
+
+            Curve25519FieldElement X3 = new Curve25519FieldElement(t4);
+            Curve25519Field.Square(R, X3.x);
+            Curve25519Field.Subtract(X3.x, G, X3.x);
+
+            Curve25519FieldElement Y3 = new Curve25519FieldElement(G);
+            Curve25519Field.Subtract(V, X3.x, Y3.x);
+            Curve25519Field.MultiplyAddToExt(Y3.x, R, tt1);
+            Curve25519Field.Reduce(tt1, Y3.x);
+
+            Curve25519FieldElement Z3 = new Curve25519FieldElement(H);
+            if (!Z1IsOne)
+            {
+                Curve25519Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                Curve25519Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            uint[] Z3Squared = (Z1IsOne && Z2IsOne) ? HSquared : null;
+
+            // TODO If the result will only be used in a subsequent addition, we don't need W3
+            Curve25519FieldElement W3 = CalculateJacobianModifiedW((Curve25519FieldElement)Z3, Z3Squared);
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3, W3 };
+
+            return new Curve25519Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            return TwiceJacobianModified(true);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return TwiceJacobianModified(false).Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            return TwiceJacobianModified(false).Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new Curve25519Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+
+        protected virtual Curve25519FieldElement CalculateJacobianModifiedW(Curve25519FieldElement Z, uint[] ZSquared)
+        {
+            Curve25519FieldElement a4 = (Curve25519FieldElement)this.Curve.A;
+            if (Z.IsOne)
+                return a4;
+
+            Curve25519FieldElement W = new Curve25519FieldElement();
+            if (ZSquared == null)
+            {
+                ZSquared = W.x;
+                Curve25519Field.Square(Z.x, ZSquared);
+            }
+            Curve25519Field.Square(ZSquared, W.x);
+            Curve25519Field.Multiply(W.x, a4.x, W.x);
+            return W;
+        }
+
+        protected virtual Curve25519FieldElement GetJacobianModifiedW()
+        {
+            ECFieldElement[] ZZ = this.RawZCoords;
+            Curve25519FieldElement W = (Curve25519FieldElement)ZZ[1];
+            if (W == null)
+            {
+                // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here
+                ZZ[1] = W = CalculateJacobianModifiedW((Curve25519FieldElement)ZZ[0], null);
+            }
+            return W;
+        }
+
+        protected virtual Curve25519Point TwiceJacobianModified(bool calculateW)
+        {
+            Curve25519FieldElement X1 = (Curve25519FieldElement)this.RawXCoord, Y1 = (Curve25519FieldElement)this.RawYCoord,
+                Z1 = (Curve25519FieldElement)this.RawZCoords[0], W1 = GetJacobianModifiedW();
+
+            uint c;
+
+            uint[] M = Nat256.Create();
+            Curve25519Field.Square(X1.x, M);
+            c = Nat256.AddBothTo(M, M, M);
+            c += Nat256.AddTo(W1.x, M);
+            Curve25519Field.Reduce27(c, M);
+
+            uint[] _2Y1 = Nat256.Create();
+            Curve25519Field.Twice(Y1.x, _2Y1);
+
+            uint[] _2Y1Squared = Nat256.Create();
+            Curve25519Field.Multiply(_2Y1, Y1.x, _2Y1Squared);
+
+            uint[] S = Nat256.Create();
+            Curve25519Field.Multiply(_2Y1Squared, X1.x, S);
+            Curve25519Field.Twice(S, S);
+
+            uint[] _8T = Nat256.Create();
+            Curve25519Field.Square(_2Y1Squared, _8T);
+            Curve25519Field.Twice(_8T, _8T);
+
+            Curve25519FieldElement X3 = new Curve25519FieldElement(_2Y1Squared);
+            Curve25519Field.Square(M, X3.x);
+            Curve25519Field.Subtract(X3.x, S, X3.x);
+            Curve25519Field.Subtract(X3.x, S, X3.x);
+
+            Curve25519FieldElement Y3 = new Curve25519FieldElement(S);
+            Curve25519Field.Subtract(S, X3.x, Y3.x);
+            Curve25519Field.Multiply(Y3.x, M, Y3.x);
+            Curve25519Field.Subtract(Y3.x, _8T, Y3.x);
+
+            Curve25519FieldElement Z3 = new Curve25519FieldElement(_2Y1);
+            if (!Nat256.IsOne(Z1.x))
+            {
+                Curve25519Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            Curve25519FieldElement W3 = null;
+            if (calculateW)
+            {
+                W3 = new Curve25519FieldElement(_8T);
+                Curve25519Field.Multiply(W3.x, W1.x, W3.x);
+                Curve25519Field.Twice(W3.x, W3.x);
+            }
+
+            return new Curve25519Point(this.Curve, X3, Y3, new ECFieldElement[] { Z3, W3 }, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat192.cs b/crypto/src/math/ec/custom/sec/Nat192.cs
new file mode 100644
index 000000000..94d7ed17c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/Nat192.cs
@@ -0,0 +1,962 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal abstract class Nat192
+    {
+        private const ulong M = 0xFFFFFFFFUL;
+
+        public static uint Add(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + y[5] + z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+        {
+            ulong c = cIn;
+            c += (ulong)x[xOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + z[zOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+        {
+            ulong c = 0;
+            c += (ulong)u[uOff + 0] + v[vOff + 0];
+            u[uOff + 0] = (uint)c;
+            v[vOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 1] + v[vOff + 1];
+            u[uOff + 1] = (uint)c;
+            v[vOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 2] + v[vOff + 2];
+            u[uOff + 2] = (uint)c;
+            v[vOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 3] + v[vOff + 3];
+            u[uOff + 3] = (uint)c;
+            v[vOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 4] + v[vOff + 4];
+            u[uOff + 4] = (uint)c;
+            v[vOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 5] + v[vOff + 5];
+            u[uOff + 5] = (uint)c;
+            v[vOff + 5] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static void Copy(uint[] x, uint[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+            z[5] = x[5];
+        }
+
+        public static uint[] Create()
+        {
+            return new uint[6];
+        }
+
+        public static uint[] CreateExt()
+        {
+            return new uint[12];
+        }
+
+        public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            bool pos = Gte(x, xOff, y, yOff);
+            if (pos)
+            {
+                Sub(x, xOff, y, yOff, z, zOff);
+            }
+            else
+            {
+                Sub(y, yOff, x, xOff, z, zOff);
+            }
+            return pos;
+        }
+
+        public static bool Eq(uint[] x, uint[] y)
+        {
+            for (int i = 5; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                    return false;
+            }
+            return true;
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 192)
+                throw new ArgumentException();
+
+            uint[] z = Create();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (uint)x.IntValue;
+                x = x.ShiftRight(32);
+            }
+            return z;
+        }
+
+        public static uint GetBit(uint[] x, int bit)
+        {
+            if (bit == 0)
+            {
+                return x[0] & 1;
+            }
+            int w = bit >> 5;
+            if (w < 0 || w >= 6)
+            {
+                return 0;
+            }
+            int b = bit & 31;
+            return (x[w] >> b) & 1;
+        }
+
+        public static bool Gte(uint[] x, uint[] y)
+        {
+            for (int i = 5; i >= 0; --i)
+            {
+                uint x_i = x[i], y_i = y[i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+        {
+            for (int i = 5; i >= 0; --i)
+            {
+                uint x_i = x[xOff + i], y_i = y[yOff + i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool IsOne(uint[] x)
+        {
+            if (x[0] != 1)
+            {
+                return false;
+            }
+            for (int i = 1; i < 6; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero(uint[] x)
+        {
+            for (int i = 0; i < 6; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static void Mul(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+            ulong y_5 = y[5];
+
+            {
+                ulong c = 0, x_0 = x[0];
+                c += x_0 * y_0;
+                zz[0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[4] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_5;
+                zz[5] = (uint)c;
+                c >>= 32;
+                zz[6] = (uint)c;
+            }
+
+            for (int i = 1; i < 6; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[i + 5];
+                zz[i + 5] = (uint)c;
+                c >>= 32;
+                zz[i + 6] = (uint)c;
+            }
+        }
+
+        public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+            ulong y_5 = y[yOff + 5];
+
+            {
+                ulong c = 0, x_0 = x[xOff + 0];
+                c += x_0 * y_0;
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_5;
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 6] = (uint)c;
+            }
+
+            for (int i = 1; i < 6; ++i)
+            {
+                ++zzOff;
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[zzOff + 5];
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 6] = (uint)c;
+            }
+        }
+
+        public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+            ulong y_5 = y[5];
+
+            ulong zc = 0;
+            for (int i = 0; i < 6; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[i + 5];
+                zz[i + 5] = (uint)c;
+                c >>= 32;
+                c += zc + zz[i + 6];
+                zz[i + 6] = (uint)c;
+                zc = c >> 32;
+            }
+            return (uint)zc;
+        }
+
+        public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+            ulong y_5 = y[yOff + 5];
+
+            ulong zc = 0;
+            for (int i = 0; i < 6; ++i)
+            {
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[zzOff + 5];
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                c += zc + zz[zzOff + 6];
+                zz[zzOff + 6] = (uint)c;
+                zc = c >> 32;
+                ++zzOff;
+            }
+            return (uint)zc;
+        }
+
+        public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            Debug.Assert(w >> 31 == 0);
+
+            ulong c = 0, wVal = w;
+            ulong x0 = x[xOff + 0];
+            c += wVal * x0 + y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong x1 = x[xOff + 1];
+            c += wVal * x1 + x0 + y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            ulong x2 = x[xOff + 2];
+            c += wVal * x2 + x1 + y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            ulong x3 = x[xOff + 3];
+            c += wVal * x3 + x2 + y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            ulong x4 = x[xOff + 4];
+            c += wVal * x4 + x3 + y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            ulong x5 = x[xOff + 5];
+            c += wVal * x5 + x4 + y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += x5;
+            return c;
+        }
+
+        public static uint MulWordAddExt(uint x, uint[] yy, int yyOff, uint[] zz, int zzOff)
+        {
+            Debug.Assert(yyOff <= 6);
+            Debug.Assert(zzOff <= 6);
+            ulong c = 0, xVal = x;
+            c += xVal * yy[yyOff + 0] + zz[zzOff + 0];
+            zz[zzOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 1] + zz[zzOff + 1];
+            zz[zzOff + 1] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 2] + zz[zzOff + 2];
+            zz[zzOff + 2] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 3] + zz[zzOff + 3];
+            zz[zzOff + 3] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 4] + zz[zzOff + 4];
+            zz[zzOff + 4] = (uint)c;
+            c >>= 32;
+            c += xVal * yy[yyOff + 5] + zz[zzOff + 5];
+            zz[zzOff + 5] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 2);
+            ulong c = 0, xVal = x;
+            ulong y00 = y & M;
+            c += xVal * y00 + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong y01 = y >> 32;
+            c += xVal * y01 + y00 + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += y01 + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(6, z, zOff, 4);
+        }
+
+        public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <=3);
+            ulong c = 0, yVal = y;
+            c += yVal * x + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += yVal + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(6, z, zOff, 3);
+        }
+
+        public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(zOff <= 3);
+            ulong c = 0, xVal = x;
+            c += xVal * y + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * (y >> 32) + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(6, z, zOff, 3);
+        }
+
+        public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < 6);
+            return (uint)c;
+        }
+
+        public static void Square(uint[] x, uint[] zz)
+        {
+            ulong x_0 = x[0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 5, j = 12;
+                do
+                {
+                    ulong xVal = x[i--];
+                    ulong p = xVal * xVal;
+                    zz[--j] = (c << 31) | (uint)(p >> 33);
+                    zz[--j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[1];
+            ulong zz_2 = zz[2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[2];
+            ulong zz_3 = zz[3];
+            ulong zz_4 = zz[4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[3];
+            ulong zz_5 = zz[5];
+            ulong zz_6 = zz[6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[4];
+            ulong zz_7 = zz[7];
+            ulong zz_8 = zz[8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_5 &= M;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_6 &= M;
+                zz_8 += zz_7 >> 32;
+                zz_7 &= M;
+            }
+
+            ulong x_5 = x[5];
+            ulong zz_9 = zz[9];
+            ulong zz_10 = zz[10];
+            {
+                zz_5 += x_5 * x_0;
+                w = (uint)zz_5;
+                zz[5] = (w << 1) | c;
+                c = w >> 31;
+                zz_6 += (zz_5 >> 32) + x_5 * x_1;
+                zz_7 += (zz_6 >> 32) + x_5 * x_2;
+                zz_8 += (zz_7 >> 32) + x_5 * x_3;
+                zz_9 += (zz_8 >> 32) + x_5 * x_4;
+                zz_10 += zz_9 >> 32;
+            }
+
+            w = (uint)zz_6;
+            zz[6] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_7;
+            zz[7] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_8;
+            zz[8] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_9;
+            zz[9] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_10;
+            zz[10] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[11] + (uint)(zz_10 >> 32);
+            zz[11] = (w << 1) | c;
+        }
+
+        public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+        {
+            ulong x_0 = x[xOff + 0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 5, j = 12;
+                do
+                {
+                    ulong xVal = x[xOff + i--];
+                    ulong p = xVal * xVal;
+                    zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+                    zz[zzOff + --j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[zzOff + 0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[xOff + 1];
+            ulong zz_2 = zz[zzOff + 2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[zzOff + 1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[xOff + 2];
+            ulong zz_3 = zz[zzOff + 3];
+            ulong zz_4 = zz[zzOff + 4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[zzOff + 2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[xOff + 3];
+            ulong zz_5 = zz[zzOff + 5];
+            ulong zz_6 = zz[zzOff + 6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[zzOff + 3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[xOff + 4];
+            ulong zz_7 = zz[zzOff + 7];
+            ulong zz_8 = zz[zzOff + 8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[zzOff + 4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_5 &= M;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_6 &= M;
+                zz_8 += zz_7 >> 32;
+                zz_7 &= M;
+            }
+
+            ulong x_5 = x[xOff + 5];
+            ulong zz_9 = zz[zzOff + 9];
+            ulong zz_10 = zz[zzOff + 10];
+            {
+                zz_5 += x_5 * x_0;
+                w = (uint)zz_5;
+                zz[zzOff + 5] = (w << 1) | c;
+                c = w >> 31;
+                zz_6 += (zz_5 >> 32) + x_5 * x_1;
+                zz_7 += (zz_6 >> 32) + x_5 * x_2;
+                zz_8 += (zz_7 >> 32) + x_5 * x_3;
+                zz_9 += (zz_8 >> 32) + x_5 * x_4;
+                zz_10 += zz_9 >> 32;
+            }
+
+            w = (uint)zz_6;
+            zz[zzOff + 6] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_7;
+            zz[zzOff + 7] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_8;
+            zz[zzOff + 8] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_9;
+            zz[zzOff + 9] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_10;
+            zz[zzOff + 10] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[zzOff + 11] + (uint)(zz_10 >> 32);
+            zz[zzOff + 11] = (w << 1) | c;
+        }
+
+        public static int Sub(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)x[5] - y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)x[xOff + 0] - y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 1] - y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 2] - y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 3] - y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 4] - y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 5] - y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)z[5] - x[5] - y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)z[5] - x[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)z[zOff + 0] - x[xOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 1] - x[xOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 2] - x[xOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 3] - x[xOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 4] - x[xOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 5] - x[xOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static BigInteger ToBigInteger(uint[] x)
+        {
+            byte[] bs = new byte[24];
+            for (int i = 0; i < 6; ++i)
+            {
+                uint x_i = x[i];
+                if (x_i != 0)
+                {
+                    Pack.UInt32_To_BE(x_i, bs, (5 - i) << 2);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        public static void Zero(uint[] z)
+        {
+            z[0] = 0;
+            z[1] = 0;
+            z[2] = 0;
+            z[3] = 0;
+            z[4] = 0;
+            z[5] = 0;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat224.cs b/crypto/src/math/ec/custom/sec/Nat224.cs
new file mode 100644
index 000000000..d5b916a54
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/Nat224.cs
@@ -0,0 +1,1176 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal abstract class Nat224
+    {
+        private const ulong M = 0xFFFFFFFFUL;
+
+        public static uint Add(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[6] + y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Add(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0;
+            c += (ulong)x[xOff + 0] + y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 6] + y[yOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + y[5] + z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[6] + y[6] + z[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0;
+            c += (ulong)x[xOff + 0] + y[yOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + y[yOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + y[yOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + y[yOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + y[yOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + y[yOff + 5] + z[zOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 6] + y[yOff + 6] + z[zOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[6] + z[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+        {
+            ulong c = cIn;
+            c += (ulong)x[xOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + z[zOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 6] + z[zOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+        {
+            ulong c = 0;
+            c += (ulong)u[uOff + 0] + v[vOff + 0];
+            u[uOff + 0] = (uint)c;
+            v[vOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 1] + v[vOff + 1];
+            u[uOff + 1] = (uint)c;
+            v[vOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 2] + v[vOff + 2];
+            u[uOff + 2] = (uint)c;
+            v[vOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 3] + v[vOff + 3];
+            u[uOff + 3] = (uint)c;
+            v[vOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 4] + v[vOff + 4];
+            u[uOff + 4] = (uint)c;
+            v[vOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 5] + v[vOff + 5];
+            u[uOff + 5] = (uint)c;
+            v[vOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 6] + v[vOff + 6];
+            u[uOff + 6] = (uint)c;
+            v[vOff + 6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static void Copy(uint[] x, uint[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+            z[5] = x[5];
+            z[6] = x[6];
+        }
+
+        public static uint[] Create()
+        {
+            return new uint[7];
+        }
+
+        public static uint[] CreateExt()
+        {
+            return new uint[14];
+        }
+
+        public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            bool pos = Gte(x, xOff, y, yOff);
+            if (pos)
+            {
+                Sub(x, xOff, y, yOff, z, zOff);
+            }
+            else
+            {
+                Sub(y, yOff, x, xOff, z, zOff);
+            }
+            return pos;
+        }
+
+        public static bool Eq(uint[] x, uint[] y)
+        {
+            for (int i = 6; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                    return false;
+            }
+            return true;
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 224)
+                throw new ArgumentException();
+
+            uint[] z = Create();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (uint)x.IntValue;
+                x = x.ShiftRight(32);
+            }
+            return z;
+        }
+
+        public static uint GetBit(uint[] x, int bit)
+        {
+            if (bit == 0)
+            {
+                return x[0] & 1;
+            }
+            int w = bit >> 5;
+            if (w < 0 || w >= 7)
+            {
+                return 0;
+            }
+            int b = bit & 31;
+            return (x[w] >> b) & 1;
+        }
+
+        public static bool Gte(uint[] x, uint[] y)
+        {
+            for (int i = 6; i >= 0; --i)
+            {
+                uint x_i = x[i], y_i = y[i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+        {
+            for (int i = 6; i >= 0; --i)
+            {
+                uint x_i = x[xOff + i], y_i = y[yOff + i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool IsOne(uint[] x)
+        {
+            if (x[0] != 1)
+            {
+                return false;
+            }
+            for (int i = 1; i < 7; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero(uint[] x)
+        {
+            for (int i = 0; i < 7; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static void Mul(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+            ulong y_5 = y[5];
+            ulong y_6 = y[6];
+
+            {
+                ulong c = 0, x_0 = x[0];
+                c += x_0 * y_0;
+                zz[0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[4] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_5;
+                zz[5] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_6;
+                zz[6] = (uint)c;
+                c >>= 32;
+                zz[7] = (uint)c;
+            }
+
+            for (int i = 1; i < 7; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[i + 5];
+                zz[i + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[i + 6];
+                zz[i + 6] = (uint)c;
+                c >>= 32;
+                zz[i + 7] = (uint)c;
+            }
+        }
+
+        public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+            ulong y_5 = y[yOff + 5];
+            ulong y_6 = y[yOff + 6];
+
+            {
+                ulong c = 0, x_0 = x[xOff + 0];
+                c += x_0 * y_0;
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_5;
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_6;
+                zz[zzOff + 6] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 7] = (uint)c;
+            }
+
+            for (int i = 1; i < 7; ++i)
+            {
+                ++zzOff;
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[zzOff + 5];
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[zzOff + 6];
+                zz[zzOff + 6] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 7] = (uint)c;
+            }
+        }
+
+        public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+            ulong y_5 = y[5];
+            ulong y_6 = y[6];
+
+            ulong zc = 0;
+            for (int i = 0; i < 7; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[i + 5];
+                zz[i + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[i + 6];
+                zz[i + 6] = (uint)c;
+                c >>= 32;
+                c += zc + zz[i + 7];
+                zz[i + 7] = (uint)c;
+                zc = c >> 32;
+            }
+            return (uint)zc;
+        }
+
+        public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+            ulong y_5 = y[yOff + 5];
+            ulong y_6 = y[yOff + 6];
+
+            ulong zc = 0;
+            for (int i = 0; i < 7; ++i)
+            {
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[zzOff + 5];
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[zzOff + 6];
+                zz[zzOff + 6] = (uint)c;
+                c >>= 32;
+                c += zc + zz[zzOff + 7];
+                zz[zzOff + 7] = (uint)c;
+                zc = c >> 32;
+                ++zzOff;
+            }
+            return (uint)zc;
+        }
+
+        public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            Debug.Assert(w >> 31 == 0);
+
+            ulong c = 0, wVal = w;
+            ulong x0 = x[xOff + 0];
+            c += wVal * x0 + y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong x1 = x[xOff + 1];
+            c += wVal * x1 + x0 + y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            ulong x2 = x[xOff + 2];
+            c += wVal * x2 + x1 + y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            ulong x3 = x[xOff + 3];
+            c += wVal * x3 + x2 + y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            ulong x4 = x[xOff + 4];
+            c += wVal * x4 + x3 + y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            ulong x5 = x[xOff + 5];
+            c += wVal * x5 + x4 + y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            ulong x6 = x[xOff + 6];
+            c += wVal * x6 + x5 + y[yOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            c += x6;
+            return c;
+        }
+
+        public static uint MulByWord(uint x, uint[] z)
+        {
+            ulong c = 0, xVal = x;
+            c += xVal * (ulong)z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint MulByWordAddTo(uint x, uint[] y, uint[] z)
+        {
+            ulong c = 0, xVal = x;
+            c += xVal * (ulong)z[0] + y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[1] + y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[2] + y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[3] + y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[4] + y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[5] + y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[6] + y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint MulWordAddTo(uint x, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = x;
+            c += xVal * y[yOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 5] + z[zOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 6] + z[zOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 3);
+            ulong c = 0, xVal = x;
+            ulong y00 = y & M;
+            c += xVal * y00 + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong y01 = y >> 32;
+            c += xVal * y01 + y00 + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += y01 + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(7, z, zOff, 4);
+        }
+
+        public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 4);
+            ulong c = 0, yVal = y;
+            c += yVal * x + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += yVal + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(7, z, zOff, 3);
+        }
+
+        public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(zOff <= 4);
+            ulong c = 0, xVal = x;
+            c += xVal * y + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * (y >> 32) + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(7, z, zOff, 3);
+        }
+
+        public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < 7);
+            return (uint)c;
+        }
+
+        public static void Square(uint[] x, uint[] zz)
+        {
+            ulong x_0 = x[0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 6, j = 14;
+                do
+                {
+                    ulong xVal = x[i--];
+                    ulong p = xVal * xVal;
+                    zz[--j] = (c << 31) | (uint)(p >> 33);
+                    zz[--j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[1];
+            ulong zz_2 = zz[2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[2];
+            ulong zz_3 = zz[3];
+            ulong zz_4 = zz[4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[3];
+            ulong zz_5 = zz[5];
+            ulong zz_6 = zz[6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[4];
+            ulong zz_7 = zz[7];
+            ulong zz_8 = zz[8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_5 &= M;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_6 &= M;
+                zz_8 += zz_7 >> 32;
+                zz_7 &= M;
+            }
+
+            ulong x_5 = x[5];
+            ulong zz_9 = zz[9];
+            ulong zz_10 = zz[10];
+            {
+                zz_5 += x_5 * x_0;
+                w = (uint)zz_5;
+                zz[5] = (w << 1) | c;
+                c = w >> 31;
+                zz_6 += (zz_5 >> 32) + x_5 * x_1;
+                zz_7 += (zz_6 >> 32) + x_5 * x_2;
+                zz_6 &= M;
+                zz_8 += (zz_7 >> 32) + x_5 * x_3;
+                zz_7 &= M;
+                zz_9 += (zz_8 >> 32) + x_5 * x_4;
+                zz_8 &= M;
+                zz_10 += zz_9 >> 32;
+                zz_9 &= M;
+            }
+
+            ulong x_6 = x[6];
+            ulong zz_11 = zz[11];
+            ulong zz_12 = zz[12];
+            {
+                zz_6 += x_6 * x_0;
+                w = (uint)zz_6;
+                zz[6] = (w << 1) | c;
+                c = w >> 31;
+                zz_7 += (zz_6 >> 32) + x_6 * x_1;
+                zz_8 += (zz_7 >> 32) + x_6 * x_2;
+                zz_9 += (zz_8 >> 32) + x_6 * x_3;
+                zz_10 += (zz_9 >> 32) + x_6 * x_4;
+                zz_11 += (zz_10 >> 32) + x_6 * x_5;
+                zz_12 += zz_11 >> 32;
+            }
+
+            w = (uint)zz_7;
+            zz[7] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_8;
+            zz[8] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_9;
+            zz[9] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_10;
+            zz[10] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_11;
+            zz[11] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_12;
+            zz[12] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[13] + (uint)(zz_12 >> 32);
+            zz[13] = (w << 1) | c;
+        }
+
+        public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+        {
+            ulong x_0 = x[xOff + 0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 6, j = 14;
+                do
+                {
+                    ulong xVal = x[xOff + i--];
+                    ulong p = xVal * xVal;
+                    zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+                    zz[zzOff + --j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[zzOff + 0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[xOff + 1];
+            ulong zz_2 = zz[zzOff + 2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[zzOff + 1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[xOff + 2];
+            ulong zz_3 = zz[zzOff + 3];
+            ulong zz_4 = zz[zzOff + 4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[zzOff + 2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[xOff + 3];
+            ulong zz_5 = zz[zzOff + 5];
+            ulong zz_6 = zz[zzOff + 6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[zzOff + 3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[xOff + 4];
+            ulong zz_7 = zz[zzOff + 7];
+            ulong zz_8 = zz[zzOff + 8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[zzOff + 4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_5 &= M;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_6 &= M;
+                zz_8 += zz_7 >> 32;
+                zz_7 &= M;
+            }
+
+            ulong x_5 = x[xOff + 5];
+            ulong zz_9 = zz[zzOff + 9];
+            ulong zz_10 = zz[zzOff + 10];
+            {
+                zz_5 += x_5 * x_0;
+                w = (uint)zz_5;
+                zz[zzOff + 5] = (w << 1) | c;
+                c = w >> 31;
+                zz_6 += (zz_5 >> 32) + x_5 * x_1;
+                zz_7 += (zz_6 >> 32) + x_5 * x_2;
+                zz_6 &= M;
+                zz_8 += (zz_7 >> 32) + x_5 * x_3;
+                zz_7 &= M;
+                zz_9 += (zz_8 >> 32) + x_5 * x_4;
+                zz_8 &= M;
+                zz_10 += zz_9 >> 32;
+                zz_9 &= M;
+            }
+
+            ulong x_6 = x[xOff + 6];
+            ulong zz_11 = zz[zzOff + 11];
+            ulong zz_12 = zz[zzOff + 12];
+            {
+                zz_6 += x_6 * x_0;
+                w = (uint)zz_6;
+                zz[zzOff + 6] = (w << 1) | c;
+                c = w >> 31;
+                zz_7 += (zz_6 >> 32) + x_6 * x_1;
+                zz_8 += (zz_7 >> 32) + x_6 * x_2;
+                zz_9 += (zz_8 >> 32) + x_6 * x_3;
+                zz_10 += (zz_9 >> 32) + x_6 * x_4;
+                zz_11 += (zz_10 >> 32) + x_6 * x_5;
+                zz_12 += zz_11 >> 32;
+            }
+
+            w = (uint)zz_7;
+            zz[zzOff + 7] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_8;
+            zz[zzOff + 8] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_9;
+            zz[zzOff + 9] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_10;
+            zz[zzOff + 10] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_11;
+            zz[zzOff + 11] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_12;
+            zz[zzOff + 12] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[zzOff + 13] + (uint)(zz_12 >> 32);
+            zz[zzOff + 13] = (w << 1) | c;
+        }
+
+        public static int Sub(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)x[5] - y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (long)x[6] - y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)x[xOff + 0] - y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 1] - y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 2] - y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 3] - y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 4] - y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 5] - y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 6] - y[yOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)z[5] - x[5] - y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (long)z[6] - x[6] - y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)z[5] - x[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (long)z[6] - x[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)z[zOff + 0] - x[xOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 1] - x[xOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 2] - x[xOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 3] - x[xOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 4] - x[xOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 5] - x[xOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 6] - x[xOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static BigInteger ToBigInteger(uint[] x)
+        {
+            byte[] bs = new byte[28];
+            for (int i = 0; i < 7; ++i)
+            {
+                uint x_i = x[i];
+                if (x_i != 0)
+                {
+                    Pack.UInt32_To_BE(x_i, bs, (6 - i) << 2);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        public static void Zero(uint[] z)
+        {
+            z[0] = 0;
+            z[1] = 0;
+            z[2] = 0;
+            z[3] = 0;
+            z[4] = 0;
+            z[5] = 0;
+            z[6] = 0;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat256.cs b/crypto/src/math/ec/custom/sec/Nat256.cs
new file mode 100644
index 000000000..bd2d6da47
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/Nat256.cs
@@ -0,0 +1,1300 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal abstract class Nat256
+    {
+        private const ulong M = 0xFFFFFFFFUL;
+
+        public static uint Add(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[6] + y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[7] + y[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Add(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0;
+            c += (ulong)x[xOff + 0] + y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 6] + y[yOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 7] + y[yOff + 7];
+            z[zOff + 7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(uint[] x, uint[] y, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + y[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + y[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + y[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + y[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + y[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + y[5] + z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[6] + y[6] + z[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[7] + y[7] + z[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddBothTo(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0;
+            c += (ulong)x[xOff + 0] + y[yOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + y[yOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + y[yOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + y[yOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + y[yOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + y[yOff + 5] + z[zOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 6] + y[yOff + 6] + z[zOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 7] + y[yOff + 7] + z[zOff + 7];
+            z[zOff + 7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, uint[] z)
+        {
+            ulong c = 0;
+            c += (ulong)x[0] + z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[1] + z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[2] + z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[3] + z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[4] + z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[5] + z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[6] + z[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[7] + z[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddTo(uint[] x, int xOff, uint[] z, int zOff, uint cIn)
+        {
+            ulong c = cIn;
+            c += (ulong)x[xOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 5] + z[zOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 6] + z[zOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            c += (ulong)x[xOff + 7] + z[zOff + 7];
+            z[zOff + 7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint AddToEachOther(uint[] u, int uOff, uint[] v, int vOff)
+        {
+            ulong c = 0;
+            c += (ulong)u[uOff + 0] + v[vOff + 0];
+            u[uOff + 0] = (uint)c;
+            v[vOff + 0] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 1] + v[vOff + 1];
+            u[uOff + 1] = (uint)c;
+            v[vOff + 1] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 2] + v[vOff + 2];
+            u[uOff + 2] = (uint)c;
+            v[vOff + 2] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 3] + v[vOff + 3];
+            u[uOff + 3] = (uint)c;
+            v[vOff + 3] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 4] + v[vOff + 4];
+            u[uOff + 4] = (uint)c;
+            v[vOff + 4] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 5] + v[vOff + 5];
+            u[uOff + 5] = (uint)c;
+            v[vOff + 5] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 6] + v[vOff + 6];
+            u[uOff + 6] = (uint)c;
+            v[vOff + 6] = (uint)c;
+            c >>= 32;
+            c += (ulong)u[uOff + 7] + v[vOff + 7];
+            u[uOff + 7] = (uint)c;
+            v[vOff + 7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static void Copy(uint[] x, uint[] z)
+        {
+            z[0] = x[0];
+            z[1] = x[1];
+            z[2] = x[2];
+            z[3] = x[3];
+            z[4] = x[4];
+            z[5] = x[5];
+            z[6] = x[6];
+            z[7] = x[7];
+        }
+
+        public static uint[] Create()
+        {
+            return new uint[8];
+        }
+
+        public static uint[] CreateExt()
+        {
+            return new uint[16];
+        }
+
+        public static bool Diff(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            bool pos = Gte(x, xOff, y, yOff);
+            if (pos)
+            {
+                Sub(x, xOff, y, yOff, z, zOff);
+            }
+            else
+            {
+                Sub(y, yOff, x, xOff, z, zOff);
+            }
+            return pos;
+        }
+
+        public static bool Eq(uint[] x, uint[] y)
+        {
+            for (int i = 7; i >= 0; --i)
+            {
+                if (x[i] != y[i])
+                    return false;
+            }
+            return true;
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            if (x.SignValue < 0 || x.BitLength > 256)
+                throw new ArgumentException();
+
+            uint[] z = Create();
+            int i = 0;
+            while (x.SignValue != 0)
+            {
+                z[i++] = (uint)x.IntValue;
+                x = x.ShiftRight(32);
+            }
+            return z;
+        }
+
+        public static uint GetBit(uint[] x, int bit)
+        {
+            if (bit == 0)
+            {
+                return x[0] & 1;
+            }
+            if ((bit & 255) != bit)
+            {
+                return 0;
+            }
+            int w = bit >> 5;
+            int b = bit & 31;
+            return (x[w] >> b) & 1;
+        }
+
+        public static bool Gte(uint[] x, uint[] y)
+        {
+            for (int i = 7; i >= 0; --i)
+            {
+                uint x_i = x[i], y_i = y[i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool Gte(uint[] x, int xOff, uint[] y, int yOff)
+        {
+            for (int i = 7; i >= 0; --i)
+            {
+                uint x_i = x[xOff + i], y_i = y[yOff + i];
+                if (x_i < y_i)
+                    return false;
+                if (x_i > y_i)
+                    return true;
+            }
+            return true;
+        }
+
+        public static bool IsOne(uint[] x)
+        {
+            if (x[0] != 1)
+            {
+                return false;
+            }
+            for (int i = 1; i < 8; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static bool IsZero(uint[] x)
+        {
+            for (int i = 0; i < 8; ++i)
+            {
+                if (x[i] != 0)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public static void Mul(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+            ulong y_5 = y[5];
+            ulong y_6 = y[6];
+            ulong y_7 = y[7];
+
+            {
+                ulong c = 0, x_0 = x[0];
+                c += x_0 * y_0;
+                zz[0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[4] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_5;
+                zz[5] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_6;
+                zz[6] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_7;
+                zz[7] = (uint)c;
+                c >>= 32;
+                zz[8] = (uint)c;
+            }
+
+            for (int i = 1; i < 8; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[i + 5];
+                zz[i + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[i + 6];
+                zz[i + 6] = (uint)c;
+                c >>= 32;
+                c += x_i * y_7 + zz[i + 7];
+                zz[i + 7] = (uint)c;
+                c >>= 32;
+                zz[i + 8] = (uint)c;
+            }
+        }
+
+        public static void Mul(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+            ulong y_5 = y[yOff + 5];
+            ulong y_6 = y[yOff + 6];
+            ulong y_7 = y[yOff + 7];
+
+            {
+                ulong c = 0, x_0 = x[xOff + 0];
+                c += x_0 * y_0;
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_1;
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_2;
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_3;
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_4;
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_5;
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_6;
+                zz[zzOff + 6] = (uint)c;
+                c >>= 32;
+                c += x_0 * y_7;
+                zz[zzOff + 7] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 8] = (uint)c;
+            }
+
+            for (int i = 1; i < 8; ++i)
+            {
+                ++zzOff;
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[zzOff + 5];
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[zzOff + 6];
+                zz[zzOff + 6] = (uint)c;
+                c >>= 32;
+                c += x_i * y_7 + zz[zzOff + 7];
+                zz[zzOff + 7] = (uint)c;
+                c >>= 32;
+                zz[zzOff + 8] = (uint)c;
+            }
+        }
+
+        public static uint MulAddTo(uint[] x, uint[] y, uint[] zz)
+        {
+            ulong y_0 = y[0];
+            ulong y_1 = y[1];
+            ulong y_2 = y[2];
+            ulong y_3 = y[3];
+            ulong y_4 = y[4];
+            ulong y_5 = y[5];
+            ulong y_6 = y[6];
+            ulong y_7 = y[7];
+
+            ulong zc = 0;
+            for (int i = 0; i < 8; ++i)
+            {
+                ulong c = 0, x_i = x[i];
+                c += x_i * y_0 + zz[i + 0];
+                zz[i + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[i + 1];
+                zz[i + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[i + 2];
+                zz[i + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[i + 3];
+                zz[i + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[i + 4];
+                zz[i + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[i + 5];
+                zz[i + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[i + 6];
+                zz[i + 6] = (uint)c;
+                c >>= 32;
+                c += x_i * y_7 + zz[i + 7];
+                zz[i + 7] = (uint)c;
+                c >>= 32;
+                c += zc + zz[i + 8];
+                zz[i + 8] = (uint)c;
+                zc = c >> 32;
+            }
+            return (uint)zc;
+        }
+
+        public static uint MulAddTo(uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff)
+        {
+            ulong y_0 = y[yOff + 0];
+            ulong y_1 = y[yOff + 1];
+            ulong y_2 = y[yOff + 2];
+            ulong y_3 = y[yOff + 3];
+            ulong y_4 = y[yOff + 4];
+            ulong y_5 = y[yOff + 5];
+            ulong y_6 = y[yOff + 6];
+            ulong y_7 = y[yOff + 7];
+
+            ulong zc = 0;
+            for (int i = 0; i < 8; ++i)
+            {
+                ulong c = 0, x_i = x[xOff + i];
+                c += x_i * y_0 + zz[zzOff + 0];
+                zz[zzOff + 0] = (uint)c;
+                c >>= 32;
+                c += x_i * y_1 + zz[zzOff + 1];
+                zz[zzOff + 1] = (uint)c;
+                c >>= 32;
+                c += x_i * y_2 + zz[zzOff + 2];
+                zz[zzOff + 2] = (uint)c;
+                c >>= 32;
+                c += x_i * y_3 + zz[zzOff + 3];
+                zz[zzOff + 3] = (uint)c;
+                c >>= 32;
+                c += x_i * y_4 + zz[zzOff + 4];
+                zz[zzOff + 4] = (uint)c;
+                c >>= 32;
+                c += x_i * y_5 + zz[zzOff + 5];
+                zz[zzOff + 5] = (uint)c;
+                c >>= 32;
+                c += x_i * y_6 + zz[zzOff + 6];
+                zz[zzOff + 6] = (uint)c;
+                c >>= 32;
+                c += x_i * y_7 + zz[zzOff + 7];
+                zz[zzOff + 7] = (uint)c;
+                c >>= 32;
+                c += zc + zz[zzOff + 8];
+                zz[zzOff + 8] = (uint)c;
+                zc = c >> 32;
+                ++zzOff;
+            }
+            return (uint)zc;
+        }
+
+        public static ulong Mul33Add(uint w, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            Debug.Assert(w >> 31 == 0);
+
+            ulong c = 0, wVal = w;
+            ulong x0 = x[xOff + 0];
+            c += wVal * x0 + y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong x1 = x[xOff + 1];
+            c += wVal * x1 + x0 + y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            ulong x2 = x[xOff + 2];
+            c += wVal * x2 + x1 + y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            ulong x3 = x[xOff + 3];
+            c += wVal * x3 + x2 + y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            ulong x4 = x[xOff + 4];
+            c += wVal * x4 + x3 + y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            ulong x5 = x[xOff + 5];
+            c += wVal * x5 + x4 + y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            ulong x6 = x[xOff + 6];
+            c += wVal * x6 + x5 + y[yOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            ulong x7 = x[xOff + 7];
+            c += wVal * x7 + x6 + y[yOff + 7];
+            z[zOff + 7] = (uint)c;
+            c >>= 32;
+            c += x7;
+            return c;
+        }
+
+        public static uint MulByWord(uint x, uint[] z)
+        {
+            ulong c = 0, xVal = x;
+            c += xVal * (ulong)z[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint MulByWordAddTo(uint x, uint[] y, uint[] z)
+        {
+            ulong c = 0, xVal = x;
+            c += xVal * (ulong)z[0] + y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[1] + y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[2] + y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[3] + y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[4] + y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[5] + y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[6] + y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += xVal * (ulong)z[7] + y[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint MulWordAddTo(uint x, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = x;
+            c += xVal * y[yOff + 0] + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 1] + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 2] + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 3] + z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 4] + z[zOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 5] + z[zOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 6] + z[zOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            c += xVal * y[yOff + 7] + z[zOff + 7];
+            z[zOff + 7] = (uint)c;
+            c >>= 32;
+            return (uint)c;
+        }
+
+        public static uint Mul33DWordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 4);
+            ulong c = 0, xVal = x;
+            ulong y00 = y & M;
+            c += xVal * y00 + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            ulong y01 = y >> 32;
+            c += xVal * y01 + y00 + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += y01 + z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(8, z, zOff, 4);
+        }
+
+        public static uint Mul33WordAdd(uint x, uint y, uint[] z, int zOff)
+        {
+            Debug.Assert(x >> 31 == 0);
+            Debug.Assert(zOff <= 5);
+            ulong c = 0, yVal = y;
+            c += yVal * x + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += yVal + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(8, z, zOff, 3);
+        }
+
+        public static uint MulWordDwordAdd(uint x, ulong y, uint[] z, int zOff)
+        {
+            Debug.Assert(zOff <= 5);
+            ulong c = 0, xVal = x;
+            c += xVal * y + z[zOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += xVal * (y >> 32) + z[zOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += z[zOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            return c == 0 ? 0 : Nat.IncAt(8, z, zOff, 3);
+        }
+
+        public static uint MulWord(uint x, uint[] y, uint[] z, int zOff)
+        {
+            ulong c = 0, xVal = x;
+            int i = 0;
+            do
+            {
+                c += xVal * y[i];
+                z[zOff + i] = (uint)c;
+                c >>= 32;
+            }
+            while (++i < 8);
+            return (uint)c;
+        }
+
+        public static void Square(uint[] x, uint[] zz)
+        {
+            ulong x_0 = x[0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 7, j = 16;
+                do
+                {
+                    ulong xVal = x[i--];
+                    ulong p = xVal * xVal;
+                    zz[--j] = (c << 31) | (uint)(p >> 33);
+                    zz[--j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[1];
+            ulong zz_2 = zz[2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[2];
+            ulong zz_3 = zz[3];
+            ulong zz_4 = zz[4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[3];
+            ulong zz_5 = zz[5];
+            ulong zz_6 = zz[6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[4];
+            ulong zz_7 = zz[7];
+            ulong zz_8 = zz[8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_5 &= M;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_6 &= M;
+                zz_8 += zz_7 >> 32;
+                zz_7 &= M;
+            }
+
+            ulong x_5 = x[5];
+            ulong zz_9 = zz[9];
+            ulong zz_10 = zz[10];
+            {
+                zz_5 += x_5 * x_0;
+                w = (uint)zz_5;
+                zz[5] = (w << 1) | c;
+                c = w >> 31;
+                zz_6 += (zz_5 >> 32) + x_5 * x_1;
+                zz_7 += (zz_6 >> 32) + x_5 * x_2;
+                zz_6 &= M;
+                zz_8 += (zz_7 >> 32) + x_5 * x_3;
+                zz_7 &= M;
+                zz_9 += (zz_8 >> 32) + x_5 * x_4;
+                zz_8 &= M;
+                zz_10 += zz_9 >> 32;
+                zz_9 &= M;
+            }
+
+            ulong x_6 = x[6];
+            ulong zz_11 = zz[11];
+            ulong zz_12 = zz[12];
+            {
+                zz_6 += x_6 * x_0;
+                w = (uint)zz_6;
+                zz[6] = (w << 1) | c;
+                c = w >> 31;
+                zz_7 += (zz_6 >> 32) + x_6 * x_1;
+                zz_8 += (zz_7 >> 32) + x_6 * x_2;
+                zz_7 &= M;
+                zz_9 += (zz_8 >> 32) + x_6 * x_3;
+                zz_8 &= M;
+                zz_10 += (zz_9 >> 32) + x_6 * x_4;
+                zz_9 &= M;
+                zz_11 += (zz_10 >> 32) + x_6 * x_5;
+                zz_10 &= M;
+                zz_12 += zz_11 >> 32;
+                zz_11 &= M;
+            }
+
+            ulong x_7 = x[7];
+            ulong zz_13 = zz[13];
+            ulong zz_14 = zz[14];
+            {
+                zz_7 += x_7 * x_0;
+                w = (uint)zz_7;
+                zz[7] = (w << 1) | c;
+                c = w >> 31;
+                zz_8 += (zz_7 >> 32) + x_7 * x_1;
+                zz_9 += (zz_8 >> 32) + x_7 * x_2;
+                zz_10 += (zz_9 >> 32) + x_7 * x_3;
+                zz_11 += (zz_10 >> 32) + x_7 * x_4;
+                zz_12 += (zz_11 >> 32) + x_7 * x_5;
+                zz_13 += (zz_12 >> 32) + x_7 * x_6;
+                zz_14 += zz_13 >> 32;
+            }
+
+            w = (uint)zz_8;
+            zz[8] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_9;
+            zz[9] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_10;
+            zz[10] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_11;
+            zz[11] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_12;
+            zz[12] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_13;
+            zz[13] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_14;
+            zz[14] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[15] + (uint)(zz_14 >> 32);
+            zz[15] = (w << 1) | c;
+        }
+
+        public static void Square(uint[] x, int xOff, uint[] zz, int zzOff)
+        {
+            ulong x_0 = x[xOff + 0];
+            ulong zz_1;
+
+            uint c = 0, w;
+            {
+                int i = 7, j = 16;
+                do
+                {
+                    ulong xVal = x[xOff + i--];
+                    ulong p = xVal * xVal;
+                    zz[zzOff + --j] = (c << 31) | (uint)(p >> 33);
+                    zz[zzOff + --j] = (uint)(p >> 1);
+                    c = (uint)p;
+                }
+                while (i > 0);
+
+                {
+                    ulong p = x_0 * x_0;
+                    zz_1 = (ulong)(c << 31) | (p >> 33);
+                    zz[zzOff + 0] = (uint)p;
+                    c = (uint)(p >> 32) & 1;
+                }
+            }
+
+            ulong x_1 = x[xOff + 1];
+            ulong zz_2 = zz[zzOff + 2];
+
+            {
+                zz_1 += x_1 * x_0;
+                w = (uint)zz_1;
+                zz[zzOff + 1] = (w << 1) | c;
+                c = w >> 31;
+                zz_2 += zz_1 >> 32;
+            }
+
+            ulong x_2 = x[xOff + 2];
+            ulong zz_3 = zz[zzOff + 3];
+            ulong zz_4 = zz[zzOff + 4];
+            {
+                zz_2 += x_2 * x_0;
+                w = (uint)zz_2;
+                zz[zzOff + 2] = (w << 1) | c;
+                c = w >> 31;
+                zz_3 += (zz_2 >> 32) + x_2 * x_1;
+                zz_4 += zz_3 >> 32;
+                zz_3 &= M;
+            }
+
+            ulong x_3 = x[xOff + 3];
+            ulong zz_5 = zz[zzOff + 5];
+            ulong zz_6 = zz[zzOff + 6];
+            {
+                zz_3 += x_3 * x_0;
+                w = (uint)zz_3;
+                zz[zzOff + 3] = (w << 1) | c;
+                c = w >> 31;
+                zz_4 += (zz_3 >> 32) + x_3 * x_1;
+                zz_5 += (zz_4 >> 32) + x_3 * x_2;
+                zz_4 &= M;
+                zz_6 += zz_5 >> 32;
+                zz_5 &= M;
+            }
+
+            ulong x_4 = x[xOff + 4];
+            ulong zz_7 = zz[zzOff + 7];
+            ulong zz_8 = zz[zzOff + 8];
+            {
+                zz_4 += x_4 * x_0;
+                w = (uint)zz_4;
+                zz[zzOff + 4] = (w << 1) | c;
+                c = w >> 31;
+                zz_5 += (zz_4 >> 32) + x_4 * x_1;
+                zz_6 += (zz_5 >> 32) + x_4 * x_2;
+                zz_5 &= M;
+                zz_7 += (zz_6 >> 32) + x_4 * x_3;
+                zz_6 &= M;
+                zz_8 += zz_7 >> 32;
+                zz_7 &= M;
+            }
+
+            ulong x_5 = x[xOff + 5];
+            ulong zz_9 = zz[zzOff + 9];
+            ulong zz_10 = zz[zzOff + 10];
+            {
+                zz_5 += x_5 * x_0;
+                w = (uint)zz_5;
+                zz[zzOff + 5] = (w << 1) | c;
+                c = w >> 31;
+                zz_6 += (zz_5 >> 32) + x_5 * x_1;
+                zz_7 += (zz_6 >> 32) + x_5 * x_2;
+                zz_6 &= M;
+                zz_8 += (zz_7 >> 32) + x_5 * x_3;
+                zz_7 &= M;
+                zz_9 += (zz_8 >> 32) + x_5 * x_4;
+                zz_8 &= M;
+                zz_10 += zz_9 >> 32;
+                zz_9 &= M;
+            }
+
+            ulong x_6 = x[xOff + 6];
+            ulong zz_11 = zz[zzOff + 11];
+            ulong zz_12 = zz[zzOff + 12];
+            {
+                zz_6 += x_6 * x_0;
+                w = (uint)zz_6;
+                zz[zzOff + 6] = (w << 1) | c;
+                c = w >> 31;
+                zz_7 += (zz_6 >> 32) + x_6 * x_1;
+                zz_8 += (zz_7 >> 32) + x_6 * x_2;
+                zz_7 &= M;
+                zz_9 += (zz_8 >> 32) + x_6 * x_3;
+                zz_8 &= M;
+                zz_10 += (zz_9 >> 32) + x_6 * x_4;
+                zz_9 &= M;
+                zz_11 += (zz_10 >> 32) + x_6 * x_5;
+                zz_10 &= M;
+                zz_12 += zz_11 >> 32;
+                zz_11 &= M;
+            }
+
+            ulong x_7 = x[xOff + 7];
+            ulong zz_13 = zz[zzOff + 13];
+            ulong zz_14 = zz[zzOff + 14];
+            {
+                zz_7 += x_7 * x_0;
+                w = (uint)zz_7;
+                zz[zzOff + 7] = (w << 1) | c;
+                c = w >> 31;
+                zz_8 += (zz_7 >> 32) + x_7 * x_1;
+                zz_9 += (zz_8 >> 32) + x_7 * x_2;
+                zz_10 += (zz_9 >> 32) + x_7 * x_3;
+                zz_11 += (zz_10 >> 32) + x_7 * x_4;
+                zz_12 += (zz_11 >> 32) + x_7 * x_5;
+                zz_13 += (zz_12 >> 32) + x_7 * x_6;
+                zz_14 += zz_13 >> 32;
+            }
+
+            w = (uint)zz_8;
+            zz[zzOff + 8] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_9;
+            zz[zzOff + 9] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_10;
+            zz[zzOff + 10] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_11;
+            zz[zzOff + 11] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_12;
+            zz[zzOff + 12] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_13;
+            zz[zzOff + 13] = (w << 1) | c;
+            c = w >> 31;
+            w = (uint)zz_14;
+            zz[zzOff + 14] = (w << 1) | c;
+            c = w >> 31;
+            w = zz[zzOff + 15] + (uint)(zz_14 >> 32);
+            zz[zzOff + 15] = (w << 1) | c;
+        }
+
+        public static int Sub(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)x[5] - y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (long)x[6] - y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (long)x[7] - y[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int Sub(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)x[xOff + 0] - y[yOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 1] - y[yOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 2] - y[yOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 3] - y[yOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 4] - y[yOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 5] - y[yOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 6] - y[yOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            c += (long)x[xOff + 7] - y[yOff + 7];
+            z[zOff + 7] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubBothFrom(uint[] x, uint[] y, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0] - y[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1] - y[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2] - y[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3] - y[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4] - y[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)z[5] - x[5] - y[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (long)z[6] - x[6] - y[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (long)z[7] - x[7] - y[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, uint[] z)
+        {
+            long c = 0;
+            c += (long)z[0] - x[0];
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - x[1];
+            z[1] = (uint)c;
+            c >>= 32;
+            c += (long)z[2] - x[2];
+            z[2] = (uint)c;
+            c >>= 32;
+            c += (long)z[3] - x[3];
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - x[4];
+            z[4] = (uint)c;
+            c >>= 32;
+            c += (long)z[5] - x[5];
+            z[5] = (uint)c;
+            c >>= 32;
+            c += (long)z[6] - x[6];
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (long)z[7] - x[7];
+            z[7] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static int SubFrom(uint[] x, int xOff, uint[] z, int zOff)
+        {
+            long c = 0;
+            c += (long)z[zOff + 0] - x[xOff + 0];
+            z[zOff + 0] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 1] - x[xOff + 1];
+            z[zOff + 1] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 2] - x[xOff + 2];
+            z[zOff + 2] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 3] - x[xOff + 3];
+            z[zOff + 3] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 4] - x[xOff + 4];
+            z[zOff + 4] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 5] - x[xOff + 5];
+            z[zOff + 5] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 6] - x[xOff + 6];
+            z[zOff + 6] = (uint)c;
+            c >>= 32;
+            c += (long)z[zOff + 7] - x[xOff + 7];
+            z[zOff + 7] = (uint)c;
+            c >>= 32;
+            return (int)c;
+        }
+
+        public static BigInteger ToBigInteger(uint[] x)
+        {
+            byte[] bs = new byte[32];
+            for (int i = 0; i < 8; ++i)
+            {
+                uint x_i = x[i];
+                if (x_i != 0)
+                {
+                    Pack.UInt32_To_BE(x_i, bs, (7 - i) << 2);
+                }
+            }
+            return new BigInteger(1, bs);
+        }
+
+        public static void Zero(uint[] z)
+        {
+            z[0] = 0;
+            z[1] = 0;
+            z[2] = 0;
+            z[3] = 0;
+            z[4] = 0;
+            z[5] = 0;
+            z[6] = 0;
+            z[7] = 0;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat384.cs b/crypto/src/math/ec/custom/sec/Nat384.cs
new file mode 100644
index 000000000..dd93e68b6
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/Nat384.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal abstract class Nat384
+    {
+        public static void Mul(uint[] x, uint[] y, uint[] zz)
+        {
+            Nat192.Mul(x, y, zz);
+            Nat192.Mul(x, 6, y, 6, zz, 12);
+
+            uint c18 = Nat192.AddToEachOther(zz, 6, zz, 12);
+            uint c12 = c18 + Nat192.AddTo(zz, 0, zz, 6, 0);
+            c18 += Nat192.AddTo(zz, 18, zz, 12, c12);
+
+            uint[] dx = Nat192.Create(), dy = Nat192.Create();
+            bool neg = Nat192.Diff(x, 6, x, 0, dx, 0) != Nat192.Diff(y, 6, y, 0, dy, 0);
+
+            uint[] tt = Nat192.CreateExt();
+            Nat192.Mul(dx, dy, tt);
+
+            c18 += neg ? Nat.AddTo(12, tt, 0, zz, 6) : (uint)Nat.SubFrom(12, tt, 0, zz, 6);
+            Nat.AddWordAt(24, c18, zz, 18);
+        }
+
+        public static void Square(uint[] x, uint[] zz)
+        {
+            Nat192.Square(x, zz);
+            Nat192.Square(x, 6, zz, 12);
+
+            uint c18 = Nat192.AddToEachOther(zz, 6, zz, 12);
+            uint c12 = c18 + Nat192.AddTo(zz, 0, zz, 6, 0);
+            c18 += Nat192.AddTo(zz, 18, zz, 12, c12);
+
+            uint[] dx = Nat192.Create();
+            Nat192.Diff(x, 6, x, 0, dx, 0);
+
+            uint[] m = Nat192.CreateExt();
+            Nat192.Square(dx, m);
+
+            c18 += (uint)Nat.SubFrom(12, m, 0, zz, 6);
+            Nat.AddWordAt(24, c18, zz, 18);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/Nat512.cs b/crypto/src/math/ec/custom/sec/Nat512.cs
new file mode 100644
index 000000000..46e10f995
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/Nat512.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal abstract class Nat512
+    {
+        public static void Mul(uint[] x, uint[] y, uint[] zz)
+        {
+            Nat256.Mul(x, y, zz);
+            Nat256.Mul(x, 8, y, 8, zz, 16);
+
+            uint c24 = Nat256.AddToEachOther(zz, 8, zz, 16);
+            uint c16 = c24 + Nat256.AddTo(zz, 0, zz, 8, 0);
+            c24 += Nat256.AddTo(zz, 24, zz, 16, c16);
+
+            uint[] dx = Nat256.Create(), dy = Nat256.Create();
+            bool neg = Nat256.Diff(x, 8, x, 0, dx, 0) != Nat256.Diff(y, 8, y, 0, dy, 0);
+
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Mul(dx, dy, tt);
+
+            c24 += neg ? Nat.AddTo(16, tt, 0, zz, 8) : (uint)Nat.SubFrom(16, tt, 0, zz, 8);
+            Nat.AddWordAt(32, c24, zz, 24); 
+        }
+
+        public static void Square(uint[] x, uint[] zz)
+        {
+            Nat256.Square(x, zz);
+            Nat256.Square(x, 8, zz, 16);
+
+            uint c24 = Nat256.AddToEachOther(zz, 8, zz, 16);
+            uint c16 = c24 + Nat256.AddTo(zz, 0, zz, 8, 0);
+            c24 += Nat256.AddTo(zz, 24, zz, 16, c16);
+
+            uint[] dx = Nat256.Create();
+            Nat256.Diff(x, 8, x, 0, dx, 0);
+
+            uint[] m = Nat256.CreateExt();
+            Nat256.Square(dx, m);
+
+            c24 += (uint)Nat.SubFrom(16, m, 0, zz, 8);
+            Nat.AddWordAt(32, c24, zz, 24); 
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
new file mode 100644
index 000000000..81f77197e
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192K1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"));
+
+        private const int SECP192K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP192K1Point m_infinity;
+
+        public SecP192K1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP192K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.ValueOf(3));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SECP192K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP192K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_JACOBIAN:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP192K1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP192K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP192K1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Field.cs b/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
new file mode 100644
index 000000000..d5ca903d1
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Field.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192K1Field
+    {
+        // 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFEE37, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000,
+            0x00000000, 0xFFFFDC6E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFEC3B02F, 0xFFFFDC6D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0x00002391, 0x00000002 };
+        private const uint P5 = 0xFFFFFFFF;
+        private const uint PExt11 = 0xFFFFFFFF;
+        private const uint PInv33 = 0x11C9;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat192.Add(x, y, z);
+            if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                Nat.Add33To(6, PInv33, z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(12, xx, yy, zz);
+            if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(12, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(6, x, z);
+            if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                Nat.Add33To(6, PInv33, z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat192.FromBigInteger(x);
+            if (z[5] == P5 && Nat192.Gte(z, P))
+            {
+                Nat192.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(6, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat192.Add(x, P, z);
+                Nat.ShiftDownBit(6, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat192.CreateExt();
+            Nat192.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat192.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(12, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat192.IsZero(x))
+            {
+                Nat192.Zero(z);
+            }
+            else
+            {
+                Nat192.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            ulong cc = Nat192.Mul33Add(PInv33, xx, 6, xx, 0, z, 0);
+            uint c = Nat192.Mul33DWordAdd(PInv33, cc, z, 0);
+
+            Debug.Assert(c == 0 || c == 1);
+
+            if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                Nat.Add33To(6, PInv33, z);
+            }
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            if ((x != 0 && Nat192.Mul33WordAdd(PInv33, x, z, 0) != 0)
+                || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                Nat.Add33To(6, PInv33, z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat192.CreateExt();
+            Nat192.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat192.CreateExt();
+            Nat192.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat192.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat192.Sub(x, y, z);
+            if (c != 0)
+            {
+                Nat.Sub33From(6, PInv33, z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(12, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(12, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(6, x, 0, z);
+            if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                Nat.Add33To(6, PInv33, z);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
new file mode 100644
index 000000000..78886dd8c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
@@ -0,0 +1,212 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192K1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP192K1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP192K1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP192K1FieldElement", "x");
+
+            this.x = SecP192K1Field.FromBigInteger(x);
+        }
+
+        public SecP192K1FieldElement()
+        {
+            this.x = Nat192.Create();
+        }
+
+        protected internal SecP192K1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat192.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat192.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat192.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat192.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP192K1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat192.Create();
+            SecP192K1Field.Add(x, ((SecP192K1FieldElement)b).x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat192.Create();
+            SecP192K1Field.AddOne(x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat192.Create();
+            SecP192K1Field.Subtract(x, ((SecP192K1FieldElement)b).x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat192.Create();
+            SecP192K1Field.Multiply(x, ((SecP192K1FieldElement)b).x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat192.Create();
+            Mod.Invert(SecP192K1Field.P, ((SecP192K1FieldElement)b).x, z);
+            SecP192K1Field.Multiply(z, x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat192.Create();
+            SecP192K1Field.Negate(x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat192.Create();
+            SecP192K1Field.Square(x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP192K1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat192.Create();
+            Mod.Invert(SecP192K1Field.P, x, z);
+            return new SecP192K1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Raise this element to the exponent 2^190 - 2^30 - 2^10 - 2^6 - 2^5 - 2^4 - 2^1
+             * 
+             * Breaking up the exponent's binary representation into "repunits", we get:
+             * { 159 1s } { 1 0s } { 19 1s } { 1 0s } { 3 1s } { 3 0s} { 3 1s } { 1 0s }
+             * 
+             * Therefore we need an addition chain containing 3, 19, 159 (the lengths of the repunits)
+             * We use: 1, 2, [3], 6, 8, 16, [19], 35, 70, 140, [159]
+             */
+
+            uint[] x1 = this.x;
+            if (Nat192.IsZero(x1) || Nat192.IsOne(x1))
+                return this;
+
+            uint[] x2 = Nat192.Create();
+            SecP192K1Field.Square(x1, x2);
+            SecP192K1Field.Multiply(x2, x1, x2);
+            uint[] x3 = Nat192.Create();
+            SecP192K1Field.Square(x2, x3);
+            SecP192K1Field.Multiply(x3, x1, x3);
+            uint[] x6 = Nat192.Create();
+            SecP192K1Field.SquareN(x3, 3, x6);
+            SecP192K1Field.Multiply(x6, x3, x6);
+            uint[] x8 = x6;
+            SecP192K1Field.SquareN(x6, 2, x8);
+            SecP192K1Field.Multiply(x8, x2, x8);
+            uint[] x16 = x2;
+            SecP192K1Field.SquareN(x8, 8, x16);
+            SecP192K1Field.Multiply(x16, x8, x16);
+            uint[] x19 = x8;
+            SecP192K1Field.SquareN(x16, 3, x19);
+            SecP192K1Field.Multiply(x19, x3, x19);
+            uint[] x35 = Nat192.Create();
+            SecP192K1Field.SquareN(x19, 16, x35);
+            SecP192K1Field.Multiply(x35, x16, x35);
+            uint[] x70 = x16;
+            SecP192K1Field.SquareN(x35, 35, x70);
+            SecP192K1Field.Multiply(x70, x35, x70);
+            uint[] x140 = x35;
+            SecP192K1Field.SquareN(x70, 70, x140);
+            SecP192K1Field.Multiply(x140, x70, x140);
+            uint[] x159 = x70;
+            SecP192K1Field.SquareN(x140, 19, x159);
+            SecP192K1Field.Multiply(x159, x19, x159);
+
+            uint[] t1 = x159;
+            SecP192K1Field.SquareN(t1, 20, t1);
+            SecP192K1Field.Multiply(t1, x19, t1);
+            SecP192K1Field.SquareN(t1, 4, t1);
+            SecP192K1Field.Multiply(t1, x3, t1);
+            SecP192K1Field.SquareN(t1, 6, t1);
+            SecP192K1Field.Multiply(t1, x3, t1);
+            SecP192K1Field.Square(t1, t1);
+
+            uint[] t2 = x3;
+            SecP192K1Field.Square(t1, t2);
+
+            return Nat192.Eq(x1, t2) ? new SecP192K1FieldElement(t1) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP192K1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP192K1FieldElement);
+        }
+
+        public virtual bool Equals(SecP192K1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat192.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 6);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Point.cs b/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
new file mode 100644
index 000000000..648aca502
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Point.cs
@@ -0,0 +1,265 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192K1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+            bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP192K1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.RawXCoord, Y1 = (SecP192K1FieldElement)this.RawYCoord;
+            SecP192K1FieldElement X2 = (SecP192K1FieldElement)b.RawXCoord, Y2 = (SecP192K1FieldElement)b.RawYCoord;
+
+            SecP192K1FieldElement Z1 = (SecP192K1FieldElement)this.RawZCoords[0];
+            SecP192K1FieldElement Z2 = (SecP192K1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat192.CreateExt();
+            uint[] t2 = Nat192.Create();
+            uint[] t3 = Nat192.Create();
+            uint[] t4 = Nat192.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP192K1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP192K1Field.Multiply(S2, X2.x, U2);
+
+                SecP192K1Field.Multiply(S2, Z1.x, S2);
+                SecP192K1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP192K1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP192K1Field.Multiply(S1, X1.x, U1);
+
+                SecP192K1Field.Multiply(S1, Z2.x, S1);
+                SecP192K1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat192.Create();
+            SecP192K1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP192K1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat192.IsZero(H))
+            {
+                if (Nat192.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP192K1Field.Square(H, HSquared);
+
+            uint[] G = Nat192.Create();
+            SecP192K1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP192K1Field.Multiply(HSquared, U1, V);
+
+            SecP192K1Field.Negate(G, G);
+            Nat192.Mul(S1, G, tt1);
+
+            c = Nat192.AddBothTo(V, V, G);
+            SecP192K1Field.Reduce32(c, G);
+
+            SecP192K1FieldElement X3 = new SecP192K1FieldElement(t4);
+            SecP192K1Field.Square(R, X3.x);
+            SecP192K1Field.Subtract(X3.x, G, X3.x);
+
+            SecP192K1FieldElement Y3 = new SecP192K1FieldElement(G);
+            SecP192K1Field.Subtract(V, X3.x, Y3.x);
+            SecP192K1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP192K1Field.Reduce(tt1, Y3.x);
+
+            SecP192K1FieldElement Z3 = new SecP192K1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP192K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP192K1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP192K1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP192K1FieldElement Y1 = (SecP192K1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.RawXCoord, Z1 = (SecP192K1FieldElement)this.RawZCoords[0];
+
+            uint c;
+
+            uint[] Y1Squared = Nat192.Create();
+            SecP192K1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat192.Create();
+            SecP192K1Field.Square(Y1Squared, T);
+
+            uint[] M = Nat192.Create();
+            SecP192K1Field.Square(X1.x, M);
+            c = Nat192.AddBothTo(M, M, M);
+            SecP192K1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP192K1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(6, S, 2, 0);
+            SecP192K1Field.Reduce32(c, S);
+
+            uint[] t1 = Nat192.Create();
+            c = Nat.ShiftUpBits(6, T, 3, 0, t1);
+            SecP192K1Field.Reduce32(c, t1);
+
+            SecP192K1FieldElement X3 = new SecP192K1FieldElement(T);
+            SecP192K1Field.Square(M, X3.x);
+            SecP192K1Field.Subtract(X3.x, S, X3.x);
+            SecP192K1Field.Subtract(X3.x, S, X3.x);
+
+            SecP192K1FieldElement Y3 = new SecP192K1FieldElement(S);
+            SecP192K1Field.Subtract(S, X3.x, Y3.x);
+            SecP192K1Field.Multiply(Y3.x, M, Y3.x);
+            SecP192K1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP192K1FieldElement Z3 = new SecP192K1FieldElement(M);
+            SecP192K1Field.Twice(Y1.x, Z3.x);
+            if (!Z1.IsOne)
+            {
+                SecP192K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP192K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP192K1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
new file mode 100644
index 000000000..cb3a981c8
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192R1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"));
+
+        private const int SecP192R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP192R1Point m_infinity;
+
+        public SecP192R1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP192R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1")));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"));
+            this.m_cofactor = BigInteger.One;
+
+            this.m_coord = SecP192R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP192R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP192R1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP192R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP192R1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Field.cs b/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
new file mode 100644
index 000000000..85e3a0394
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Field.cs
@@ -0,0 +1,281 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192R1Field
+    {
+        // 2^192 - 2^64 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001,
+            0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFE,
+            0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000002 };
+        private const uint P5 = 0xFFFFFFFF;
+        private const uint PExt11 = 0xFFFFFFFF;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat192.Add(x, y, z);
+            if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(12, xx, yy, zz);
+            if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(12, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(6, x, z);
+            if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat192.FromBigInteger(x);
+            if (z[5] == P5 && Nat192.Gte(z, P))
+            {
+                Nat192.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(6, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat192.Add(x, P, z);
+                Nat.ShiftDownBit(6, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat192.CreateExt();
+            Nat192.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat192.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[11] == PExt11 && Nat.Gte(12, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(12, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat192.IsZero(x))
+            {
+                Nat192.Zero(z);
+            }
+            else
+            {
+                Nat192.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            ulong xx06 = xx[6], xx07 = xx[7], xx08 = xx[8];
+            ulong xx09 = xx[9], xx10 = xx[10], xx11 = xx[11];
+
+            ulong t0 = xx06 + xx10;
+            ulong t1 = xx07 + xx11;
+
+            ulong cc = 0;
+            cc += (ulong)xx[0] + t0;
+            uint z0 = (uint)cc;
+            cc >>= 32;
+            cc += (ulong)xx[1] + t1;
+            z[1] = (uint)cc;
+            cc >>= 32;
+
+            t0 += xx08;
+            t1 += xx09;
+
+            cc += (ulong)xx[2] + t0;
+            ulong z2 = (uint)cc;
+            cc >>= 32;
+            cc += (ulong)xx[3] + t1;
+            z[3] = (uint)cc;
+            cc >>= 32;
+
+            t0 -= xx06;
+            t1 -= xx07;
+
+            cc += (ulong)xx[4] + t0;
+            z[4] = (uint)cc;
+            cc >>= 32;
+            cc += (ulong)xx[5] + t1;
+            z[5] = (uint)cc;
+            cc >>= 32;
+
+            z2 += cc;
+
+            cc += z0;
+            z[0] = (uint)cc;
+            cc >>= 32;
+            if (cc != 0)
+            {
+                cc += z[1];
+                z[1] = (uint)cc;
+                z2 += cc >> 32;
+            }
+            z[2] = (uint)z2;
+            cc  = z2 >> 32;
+
+            Debug.Assert(cc == 0 || cc == 1);
+
+            if ((cc != 0 && Nat.IncAt(6, z, 3) != 0)
+                || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            ulong cc = 0;
+
+            if (x != 0)
+            {
+                cc += (ulong)z[0] + x;
+                z[0] = (uint)cc;
+                cc >>= 32;
+                if (cc != 0)
+                {
+                    cc += (ulong)z[1];
+                    z[1] = (uint)cc;
+                    cc >>= 32;
+                }
+                cc += (ulong)z[2] + x;
+                z[2] = (uint)cc;
+                cc >>= 32;
+
+                Debug.Assert(cc == 0 || cc == 1);
+            }
+
+            if ((cc != 0 && Nat.IncAt(6, z, 3) != 0)
+                || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat192.CreateExt();
+            Nat192.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat192.CreateExt();
+            Nat192.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat192.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat192.Sub(x, y, z);
+            if (c != 0)
+            {
+                SubPInvFrom(z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(12, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(12, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(6, x, 0, z);
+            if (c != 0 || (z[5] == P5 && Nat192.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        private static void AddPInvTo(uint[] z)
+        {
+            long c = (long)z[0] + 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[2] + 1;
+            z[2] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                Nat.IncAt(6, z, 3);
+            }
+        }
+
+        private static void SubPInvFrom(uint[] z)
+        {
+            long c = (long)z[0] - 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[2] - 1;
+            z[2] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                Nat.DecAt(6, z, 3);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
new file mode 100644
index 000000000..020c5cdbb
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
@@ -0,0 +1,187 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192R1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP192R1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP192R1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP192R1FieldElement", "x");
+
+            this.x = SecP192R1Field.FromBigInteger(x);
+        }
+
+        public SecP192R1FieldElement()
+        {
+            this.x = Nat192.Create();
+        }
+
+        protected internal SecP192R1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat192.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat192.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat192.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat192.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP192R1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat192.Create();
+            SecP192R1Field.Add(x, ((SecP192R1FieldElement)b).x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat192.Create();
+            SecP192R1Field.AddOne(x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat192.Create();
+            SecP192R1Field.Subtract(x, ((SecP192R1FieldElement)b).x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat192.Create();
+            SecP192R1Field.Multiply(x, ((SecP192R1FieldElement)b).x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat192.Create();
+            Mod.Invert(SecP192R1Field.P, ((SecP192R1FieldElement)b).x, z);
+            SecP192R1Field.Multiply(z, x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat192.Create();
+            SecP192R1Field.Negate(x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat192.Create();
+            SecP192R1Field.Square(x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP192R1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat192.Create();
+            Mod.Invert(SecP192R1Field.P, x, z);
+            return new SecP192R1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            // Raise this element to the exponent 2^190 - 2^62
+
+            uint[] x1 = this.x;
+            if (Nat192.IsZero(x1) || Nat192.IsOne(x1))
+                return this;
+
+            uint[] t1 = Nat192.Create();
+            uint[] t2 = Nat192.Create();
+
+            SecP192R1Field.Square(x1, t1);
+            SecP192R1Field.Multiply(t1, x1, t1);
+
+            SecP192R1Field.SquareN(t1, 2, t2);
+            SecP192R1Field.Multiply(t2, t1, t2);
+
+            SecP192R1Field.SquareN(t2, 4, t1);
+            SecP192R1Field.Multiply(t1, t2, t1);
+
+            SecP192R1Field.SquareN(t1, 8, t2);
+            SecP192R1Field.Multiply(t2, t1, t2);
+
+            SecP192R1Field.SquareN(t2, 16, t1);
+            SecP192R1Field.Multiply(t1, t2, t1);
+
+            SecP192R1Field.SquareN(t1, 32, t2);
+            SecP192R1Field.Multiply(t2, t1, t2);
+
+            SecP192R1Field.SquareN(t2, 64, t1);
+            SecP192R1Field.Multiply(t1, t2, t1);
+
+            SecP192R1Field.SquareN(t1, 62, t1);
+            SecP192R1Field.Square(t1, t2);
+
+            return Nat192.Eq(x1, t2) ? new SecP192R1FieldElement(t1) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP192R1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP192R1FieldElement);
+        }
+
+        public virtual bool Equals(SecP192R1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat192.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 6);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Point.cs b/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
new file mode 100644
index 000000000..797a8de35
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Point.cs
@@ -0,0 +1,277 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP192R1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP192R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.RawXCoord, Y1 = (SecP192R1FieldElement)this.RawYCoord;
+            SecP192R1FieldElement X2 = (SecP192R1FieldElement)b.RawXCoord, Y2 = (SecP192R1FieldElement)b.RawYCoord;
+
+            SecP192R1FieldElement Z1 = (SecP192R1FieldElement)this.RawZCoords[0];
+            SecP192R1FieldElement Z2 = (SecP192R1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat192.CreateExt();
+            uint[] t2 = Nat192.Create();
+            uint[] t3 = Nat192.Create();
+            uint[] t4 = Nat192.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP192R1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP192R1Field.Multiply(S2, X2.x, U2);
+
+                SecP192R1Field.Multiply(S2, Z1.x, S2);
+                SecP192R1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP192R1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP192R1Field.Multiply(S1, X1.x, U1);
+
+                SecP192R1Field.Multiply(S1, Z2.x, S1);
+                SecP192R1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat192.Create();
+            SecP192R1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP192R1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat192.IsZero(H))
+            {
+                if (Nat192.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP192R1Field.Square(H, HSquared);
+
+            uint[] G = Nat192.Create();
+            SecP192R1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP192R1Field.Multiply(HSquared, U1, V);
+
+            SecP192R1Field.Negate(G, G);
+            Nat192.Mul(S1, G, tt1);
+
+            c = Nat192.AddBothTo(V, V, G);
+            SecP192R1Field.Reduce32(c, G);
+
+            SecP192R1FieldElement X3 = new SecP192R1FieldElement(t4);
+            SecP192R1Field.Square(R, X3.x);
+            SecP192R1Field.Subtract(X3.x, G, X3.x);
+
+            SecP192R1FieldElement Y3 = new SecP192R1FieldElement(G);
+            SecP192R1Field.Subtract(V, X3.x, Y3.x);
+            SecP192R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP192R1Field.Reduce(tt1, Y3.x);
+
+            SecP192R1FieldElement Z3 = new SecP192R1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP192R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP192R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP192R1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP192R1FieldElement Y1 = (SecP192R1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.RawXCoord, Z1 = (SecP192R1FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat192.Create();
+            uint[] t2 = Nat192.Create();
+
+            uint[] Y1Squared = Nat192.Create();
+            SecP192R1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat192.Create();
+            SecP192R1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP192R1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP192R1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP192R1Field.Add(X1.x, Z1Squared, M);
+            SecP192R1Field.Multiply(M, t1, M);
+            c = Nat192.AddBothTo(M, M, M);
+            SecP192R1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP192R1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(6, S, 2, 0);
+            SecP192R1Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(6, T, 3, 0, t1);
+            SecP192R1Field.Reduce32(c, t1);
+
+            SecP192R1FieldElement X3 = new SecP192R1FieldElement(T);
+            SecP192R1Field.Square(M, X3.x);
+            SecP192R1Field.Subtract(X3.x, S, X3.x);
+            SecP192R1Field.Subtract(X3.x, S, X3.x);
+
+            SecP192R1FieldElement Y3 = new SecP192R1FieldElement(S);
+            SecP192R1Field.Subtract(S, X3.x, Y3.x);
+            SecP192R1Field.Multiply(Y3.x, M, Y3.x);
+            SecP192R1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP192R1FieldElement Z3 = new SecP192R1FieldElement(M);
+            SecP192R1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP192R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP192R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP192R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
new file mode 100644
index 000000000..d4be7d8de
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224K1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D"));
+
+        private const int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP224K1Point m_infinity;
+
+        public SecP224K1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP224K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.ValueOf(5));
+            this.m_order = new BigInteger(1, Hex.Decode("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SECP224K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP224K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_JACOBIAN:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP224K1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP224K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP224K1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Field.cs b/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
new file mode 100644
index 000000000..a55810c6d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Field.cs
@@ -0,0 +1,177 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224K1Field
+    {
+        // 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFE56D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x02C23069, 0x00003526, 0x00000001, 0x00000000, 0x00000000,
+            0x00000000, 0x00000000, 0xFFFFCADA, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFD3DCF97, 0xFFFFCAD9, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFF, 0x00003525, 0x00000002 };
+        private const uint P6 = 0xFFFFFFFF;
+        private const uint PExt13 = 0xFFFFFFFF;
+        private const uint PInv33 = 0x1A93;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat224.Add(x, y, z);
+            if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                Nat.Add33To(7, PInv33, z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(14, xx, yy, zz);
+            if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(14, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(7, x, z);
+            if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                Nat.Add33To(7, PInv33, z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat224.FromBigInteger(x);
+            if (z[6] == P6 && Nat224.Gte(z, P))
+            {
+                Nat224.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(7, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat224.Add(x, P, z);
+                Nat.ShiftDownBit(7, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat224.CreateExt();
+            Nat224.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat224.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(14, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat224.IsZero(x))
+            {
+                Nat224.Zero(z);
+            }
+            else
+            {
+                Nat224.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            ulong cc = Nat224.Mul33Add(PInv33, xx, 7, xx, 0, z, 0);
+            uint c = Nat224.Mul33DWordAdd(PInv33, cc, z, 0);
+
+            Debug.Assert(c == 0 || c == 1);
+
+            if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                Nat.Add33To(7, PInv33, z);
+            }
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            if ((x != 0 && Nat224.Mul33WordAdd(PInv33, x, z, 0) != 0)
+                || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                Nat.Add33To(7, PInv33, z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat224.CreateExt();
+            Nat224.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat224.CreateExt();
+            Nat224.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat224.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat224.Sub(x, y, z);
+            if (c != 0)
+            {
+                Nat.Sub33From(7, PInv33, z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(14, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(14, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(7, x, 0, z);
+            if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                Nat.Add33To(7, PInv33, z);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
new file mode 100644
index 000000000..72ff4b099
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
@@ -0,0 +1,241 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224K1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP224K1Curve.q;
+
+        // Calculated as BigInteger.Two.ModPow(Q.ShiftRight(2), Q)
+        private static readonly uint[] PRECOMP_POW2 = new uint[]{ 0x33bfd202, 0xdcfad133, 0x2287624a, 0xc3811ba8,
+            0xa85558fc, 0x1eaef5d7, 0x8edf154c };
+
+        protected internal readonly uint[] x;
+
+        public SecP224K1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP224K1FieldElement", "x");
+
+            this.x = SecP224K1Field.FromBigInteger(x);
+        }
+
+        public SecP224K1FieldElement()
+        {
+            this.x = Nat224.Create();
+        }
+
+        protected internal SecP224K1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat224.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat224.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat224.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat224.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP224K1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat224.Create();
+            SecP224K1Field.Add(x, ((SecP224K1FieldElement)b).x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat224.Create();
+            SecP224K1Field.AddOne(x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat224.Create();
+            SecP224K1Field.Subtract(x, ((SecP224K1FieldElement)b).x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat224.Create();
+            SecP224K1Field.Multiply(x, ((SecP224K1FieldElement)b).x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat224.Create();
+            Mod.Invert(SecP224K1Field.P, ((SecP224K1FieldElement)b).x, z);
+            SecP224K1Field.Multiply(z, x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat224.Create();
+            SecP224K1Field.Negate(x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat224.Create();
+            SecP224K1Field.Square(x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP224K1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat224.Create();
+            Mod.Invert(SecP224K1Field.P, x, z);
+            return new SecP224K1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Q == 8m + 5, so we use Pocklington's method for this case.
+             *
+             * First, raise this element to the exponent 2^221 - 2^29 - 2^9 - 2^8 - 2^6 - 2^4 - 2^1 (i.e. m + 1)
+             * 
+             * Breaking up the exponent's binary representation into "repunits", we get:
+             * { 191 1s } { 1 0s } { 19 1s } { 2 0s } { 1 1s } { 1 0s} { 1 1s } { 1 0s} { 3 1s } { 1 0s}
+             * 
+             * Therefore we need an addition chain containing 1, 3, 19, 191 (the lengths of the repunits)
+             * We use: [1], 2, [3], 4, 8, 11, [19], 23, 42, 84, 107, [191]
+             */
+
+            uint[] x1 = this.x;
+            if (Nat224.IsZero(x1) || Nat224.IsOne(x1))
+                return this;
+
+            uint[] x2 = Nat224.Create();
+            SecP224K1Field.Square(x1, x2);
+            SecP224K1Field.Multiply(x2, x1, x2);
+            uint[] x3 = x2;
+            SecP224K1Field.Square(x2, x3);
+            SecP224K1Field.Multiply(x3, x1, x3);
+            uint[] x4 = Nat224.Create();
+            SecP224K1Field.Square(x3, x4);
+            SecP224K1Field.Multiply(x4, x1, x4);
+            uint[] x8 = Nat224.Create();
+            SecP224K1Field.SquareN(x4, 4, x8);
+            SecP224K1Field.Multiply(x8, x4, x8);
+            uint[] x11 = Nat224.Create();
+            SecP224K1Field.SquareN(x8, 3, x11);
+            SecP224K1Field.Multiply(x11, x3, x11);
+            uint[] x19 = x11;
+            SecP224K1Field.SquareN(x11, 8, x19);
+            SecP224K1Field.Multiply(x19, x8, x19);
+            uint[] x23 = x8;
+            SecP224K1Field.SquareN(x19, 4, x23);
+            SecP224K1Field.Multiply(x23, x4, x23);
+            uint[] x42 = x4;
+            SecP224K1Field.SquareN(x23, 19, x42);
+            SecP224K1Field.Multiply(x42, x19, x42);
+            uint[] x84 = Nat224.Create();
+            SecP224K1Field.SquareN(x42, 42, x84);
+            SecP224K1Field.Multiply(x84, x42, x84);
+            uint[] x107 = x42;
+            SecP224K1Field.SquareN(x84, 23, x107);
+            SecP224K1Field.Multiply(x107, x23, x107);
+            uint[] x191 = x23;
+            SecP224K1Field.SquareN(x107, 84, x191);
+            SecP224K1Field.Multiply(x191, x84, x191);
+
+            uint[] t1 = x191;
+            SecP224K1Field.SquareN(t1, 20, t1);
+            SecP224K1Field.Multiply(t1, x19, t1);
+            SecP224K1Field.SquareN(t1, 3, t1);
+            SecP224K1Field.Multiply(t1, x1, t1);
+            SecP224K1Field.SquareN(t1, 2, t1);
+            SecP224K1Field.Multiply(t1, x1, t1);
+            SecP224K1Field.SquareN(t1, 4, t1);
+            SecP224K1Field.Multiply(t1, x3, t1);
+            SecP224K1Field.Square(t1, t1);
+
+            uint[] t2 = x84;
+            SecP224K1Field.Square(t1, t2);
+
+            if (Nat224.Eq(x1, t2))
+            {
+                return new SecP224K1FieldElement(t1);
+            }
+
+            /*
+             * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess,
+             * which is ((4x)^(m + 1))/2 mod Q
+             */
+            SecP224K1Field.Multiply(t1, PRECOMP_POW2, t1);
+
+            SecP224K1Field.Square(t1, t2);
+
+            if (Nat224.Eq(x1, t2))
+            {
+                return new SecP224K1FieldElement(t1);
+            }
+
+            return null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP224K1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP224K1FieldElement);
+        }
+
+        public virtual bool Equals(SecP224K1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat224.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 7);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Point.cs b/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
new file mode 100644
index 000000000..8cbd29699
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Point.cs
@@ -0,0 +1,265 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224K1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+            bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP224K1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.RawXCoord, Y1 = (SecP224K1FieldElement)this.RawYCoord;
+            SecP224K1FieldElement X2 = (SecP224K1FieldElement)b.RawXCoord, Y2 = (SecP224K1FieldElement)b.RawYCoord;
+
+            SecP224K1FieldElement Z1 = (SecP224K1FieldElement)this.RawZCoords[0];
+            SecP224K1FieldElement Z2 = (SecP224K1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat224.CreateExt();
+            uint[] t2 = Nat224.Create();
+            uint[] t3 = Nat224.Create();
+            uint[] t4 = Nat224.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP224K1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP224K1Field.Multiply(S2, X2.x, U2);
+
+                SecP224K1Field.Multiply(S2, Z1.x, S2);
+                SecP224K1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP224K1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP224K1Field.Multiply(S1, X1.x, U1);
+
+                SecP224K1Field.Multiply(S1, Z2.x, S1);
+                SecP224K1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat224.Create();
+            SecP224K1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP224K1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat224.IsZero(H))
+            {
+                if (Nat224.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP224K1Field.Square(H, HSquared);
+
+            uint[] G = Nat224.Create();
+            SecP224K1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP224K1Field.Multiply(HSquared, U1, V);
+
+            SecP224K1Field.Negate(G, G);
+            Nat224.Mul(S1, G, tt1);
+
+            c = Nat224.AddBothTo(V, V, G);
+            SecP224K1Field.Reduce32(c, G);
+
+            SecP224K1FieldElement X3 = new SecP224K1FieldElement(t4);
+            SecP224K1Field.Square(R, X3.x);
+            SecP224K1Field.Subtract(X3.x, G, X3.x);
+
+            SecP224K1FieldElement Y3 = new SecP224K1FieldElement(G);
+            SecP224K1Field.Subtract(V, X3.x, Y3.x);
+            SecP224K1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP224K1Field.Reduce(tt1, Y3.x);
+
+            SecP224K1FieldElement Z3 = new SecP224K1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP224K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP224K1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP224K1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP224K1FieldElement Y1 = (SecP224K1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.RawXCoord, Z1 = (SecP224K1FieldElement)this.RawZCoords[0];
+
+            uint c;
+
+            uint[] Y1Squared = Nat224.Create();
+            SecP224K1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat224.Create();
+            SecP224K1Field.Square(Y1Squared, T);
+
+            uint[] M = Nat224.Create();
+            SecP224K1Field.Square(X1.x, M);
+            c = Nat224.AddBothTo(M, M, M);
+            SecP224K1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP224K1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(7, S, 2, 0);
+            SecP224K1Field.Reduce32(c, S);
+
+            uint[] t1 = Nat224.Create();
+            c = Nat.ShiftUpBits(7, T, 3, 0, t1);
+            SecP224K1Field.Reduce32(c, t1);
+
+            SecP224K1FieldElement X3 = new SecP224K1FieldElement(T);
+            SecP224K1Field.Square(M, X3.x);
+            SecP224K1Field.Subtract(X3.x, S, X3.x);
+            SecP224K1Field.Subtract(X3.x, S, X3.x);
+
+            SecP224K1FieldElement Y3 = new SecP224K1FieldElement(S);
+            SecP224K1Field.Subtract(S, X3.x, Y3.x);
+            SecP224K1Field.Multiply(Y3.x, M, Y3.x);
+            SecP224K1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP224K1FieldElement Z3 = new SecP224K1FieldElement(M);
+            SecP224K1Field.Twice(Y1.x, Z3.x);
+            if (!Z1.IsOne)
+            {
+                SecP224K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP224K1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
new file mode 100644
index 000000000..cda8781ff
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224R1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"));
+
+        private const int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP224R1Point m_infinity;
+
+        public SecP224R1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP224R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4")));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"));
+            this.m_cofactor = BigInteger.One;
+
+            this.m_coord = SecP224R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP224R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_JACOBIAN:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP224R1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP224R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP224R1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Field.cs b/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
new file mode 100644
index 000000000..559593c66
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Field.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224R1Field
+    {
+        // 2^224 - 2^96 + 1
+        internal static readonly uint[] P = new uint[] { 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+            0xFFFFFFFF, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000,
+            0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001 };
+        private const uint P6 = 0xFFFFFFFF;
+        private const uint PExt13 = 0xFFFFFFFF;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat224.Add(x, y, z);
+            if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(14, xx, yy, zz);
+            if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(14, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(7, x, z);
+            if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat224.FromBigInteger(x);
+            if (z[6] == P6 && Nat224.Gte(z, P))
+            {
+                Nat224.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(7, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat224.Add(x, P, z);
+                Nat.ShiftDownBit(7, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat224.CreateExt();
+            Nat224.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat224.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[13] == PExt13 && Nat.Gte(14, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(14, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat224.IsZero(x))
+            {
+                Nat224.Zero(z);
+            }
+            else
+            {
+                Nat224.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            long xx10 = xx[10], xx11 = xx[11], xx12 = xx[12], xx13 = xx[13];
+
+            const long n = 1;
+
+            long t0 = (long)xx[7] + xx11 - n;
+            long t1 = (long)xx[8] + xx12;
+            long t2 = (long)xx[9] + xx13;
+
+            long cc = 0;
+            cc += (long)xx[0] - t0;
+            long z0 = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[1] - t1;
+            z[1] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[2] - t2;
+            z[2] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[3] + t0 - xx10;
+            long z3 = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[4] + t1 - xx11;
+            z[4] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[5] + t2 - xx12;
+            z[5] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[6] + xx10 - xx13;
+            z[6] = (uint)cc;
+            cc >>= 32;
+            cc += n;
+
+            Debug.Assert(cc >= 0);
+
+            z3 += cc;
+
+            z0 -= cc;
+            z[0] = (uint)z0;
+            cc = z0 >> 32;
+            if (cc != 0)
+            {
+                cc += (long)z[1];
+                z[1] = (uint)cc;
+                cc >>= 32;
+                cc += (long)z[2];
+                z[2] = (uint)cc;
+                z3 += cc >> 32;
+            }
+            z[3] = (uint)z3;
+            cc = z3 >> 32;
+
+            Debug.Assert(cc == 0 || cc == 1);
+
+            if ((cc != 0 && Nat.IncAt(7, z, 4) != 0)
+                || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            long cc = 0;
+
+            if (x != 0)
+            {
+                long xx07 = x;
+
+                cc += (long)z[0] - xx07;
+                z[0] = (uint)cc;
+                cc >>= 32;
+                if (cc != 0)
+                {
+                    cc += (long)z[1];
+                    z[1] = (uint)cc;
+                    cc >>= 32;
+                    cc += (long)z[2];
+                    z[2] = (uint)cc;
+                    cc >>= 32;
+                }
+                cc += (long)z[3] + xx07;
+                z[3] = (uint)cc;
+                cc >>= 32;
+
+                Debug.Assert(cc == 0 || cc == 1);
+            }
+
+            if ((cc != 0 && Nat.IncAt(7, z, 4) != 0)
+                || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat224.CreateExt();
+            Nat224.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat224.CreateExt();
+            Nat224.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat224.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat224.Sub(x, y, z);
+            if (c != 0)
+            {
+                SubPInvFrom(z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(14, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(14, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(7, x, 0, z);
+            if (c != 0 || (z[6] == P6 && Nat224.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        private static void AddPInvTo(uint[] z)
+        {
+            long c = (long)z[0] - 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+                c += (long)z[2];
+                z[2] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[3] + 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                Nat.IncAt(7, z, 4);
+            }
+        }
+
+        private static void SubPInvFrom(uint[] z)
+        {
+            long c = (long)z[0] + 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+                c += (long)z[2];
+                z[2] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[3] - 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                Nat.DecAt(7, z, 4);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
new file mode 100644
index 000000000..06f47cded
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
@@ -0,0 +1,268 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224R1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP224R1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP224R1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP224R1FieldElement", "x");
+
+            this.x = SecP224R1Field.FromBigInteger(x);
+        }
+
+        public SecP224R1FieldElement()
+        {
+            this.x = Nat224.Create();
+        }
+
+        protected internal SecP224R1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat224.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat224.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat224.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat224.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP224R1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat224.Create();
+            SecP224R1Field.Add(x, ((SecP224R1FieldElement)b).x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat224.Create();
+            SecP224R1Field.AddOne(x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat224.Create();
+            SecP224R1Field.Subtract(x, ((SecP224R1FieldElement)b).x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat224.Create();
+            SecP224R1Field.Multiply(x, ((SecP224R1FieldElement)b).x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat224.Create();
+            Mod.Invert(SecP224R1Field.P, ((SecP224R1FieldElement)b).x, z);
+            SecP224R1Field.Multiply(z, x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat224.Create();
+            SecP224R1Field.Negate(x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat224.Create();
+            SecP224R1Field.Square(x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP224R1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat224.Create();
+            Mod.Invert(SecP224R1Field.P, x, z);
+            return new SecP224R1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            uint[] c = this.x;
+            if (Nat224.IsZero(c) || Nat224.IsOne(c))
+                return this;
+
+            uint[] nc = Nat224.Create();
+            SecP224R1Field.Negate(c, nc);
+
+            uint[] r = Mod.Random(SecP224R1Field.P);
+            uint[] t = Nat224.Create();
+
+            if (!IsSquare(c))
+                return null;
+
+            while (!TrySqrt(nc, r, t))
+            {
+                SecP224R1Field.AddOne(r, r);
+            }
+
+            SecP224R1Field.Square(t, r);
+
+            return Nat224.Eq(c, r) ? new SecP224R1FieldElement(t) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP224R1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP224R1FieldElement);
+        }
+
+        public virtual bool Equals(SecP224R1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat224.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 7);
+        }
+
+        private static bool IsSquare(uint[] x)
+        {
+            uint[] t1 = Nat224.Create();
+            uint[] t2 = Nat224.Create();
+            Nat224.Copy(x, t1);
+
+            for (int i = 0; i < 7; ++i)
+            {
+                Nat224.Copy(t1, t2);
+                SecP224R1Field.SquareN(t1, 1 << i, t1);
+                SecP224R1Field.Multiply(t1, t2, t1);
+            }
+
+            SecP224R1Field.SquareN(t1, 95, t1);
+            return Nat224.IsOne(t1);
+        }
+
+        private static void RM(uint[] nc, uint[] d0, uint[] e0, uint[] d1, uint[] e1, uint[] f1, uint[] t)
+        {
+            SecP224R1Field.Multiply(e1, e0, t);
+            SecP224R1Field.Multiply(t, nc, t);
+            SecP224R1Field.Multiply(d1, d0, f1);
+            SecP224R1Field.Add(f1, t, f1);
+            SecP224R1Field.Multiply(d1, e0, t);
+            Nat224.Copy(f1, d1);
+            SecP224R1Field.Multiply(e1, d0, e1);
+            SecP224R1Field.Add(e1, t, e1);
+            SecP224R1Field.Square(e1, f1);
+            SecP224R1Field.Multiply(f1, nc, f1);
+        }
+
+        private static void RP(uint[] nc, uint[] d1, uint[] e1, uint[] f1, uint[] t)
+        {
+            Nat224.Copy(nc, f1);
+
+            uint[] d0 = Nat224.Create();
+            uint[] e0 = Nat224.Create();
+
+            for (int i = 0; i < 7; ++i)
+            {
+                Nat224.Copy(d1, d0);
+                Nat224.Copy(e1, e0);
+
+                int j = 1 << i;
+                while (--j >= 0)
+                {
+                    RS(d1, e1, f1, t);
+                }
+
+                RM(nc, d0, e0, d1, e1, f1, t);
+            }
+        }
+
+        private static void RS(uint[] d, uint[] e, uint[] f, uint[] t)
+        {
+            SecP224R1Field.Multiply(e, d, e);
+            SecP224R1Field.Twice(e, e);
+            SecP224R1Field.Square(d, t);
+            SecP224R1Field.Add(f, t, d);
+            SecP224R1Field.Multiply(f, t, f);
+            uint c = Nat.ShiftUpBits(7, f, 2, 0);
+            SecP224R1Field.Reduce32(c, f);
+        }
+
+        private static bool TrySqrt(uint[] nc, uint[] r, uint[] t)
+        {
+            uint[] d1 = Nat224.Create();
+            Nat224.Copy(r, d1);
+            uint[] e1 = Nat224.Create();
+            e1[0] = 1;
+            uint[] f1 = Nat224.Create();
+            RP(nc, d1, e1, f1, t);
+
+            uint[] d0 = Nat224.Create();
+            uint[] e0 = Nat224.Create();
+
+            for (int k = 1; k < 96; ++k)
+            {
+                Nat224.Copy(d1, d0);
+                Nat224.Copy(e1, e0);
+
+                RS(d1, e1, f1, t);
+
+                if (Nat224.IsZero(d1))
+                {
+                    Mod.Invert(SecP224R1Field.P, e0, t);
+                    SecP224R1Field.Multiply(t, d0, t);
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Point.cs b/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
new file mode 100644
index 000000000..c3f4efb59
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Point.cs
@@ -0,0 +1,277 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP224R1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP224R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.RawXCoord, Y1 = (SecP224R1FieldElement)this.RawYCoord;
+            SecP224R1FieldElement X2 = (SecP224R1FieldElement)b.RawXCoord, Y2 = (SecP224R1FieldElement)b.RawYCoord;
+
+            SecP224R1FieldElement Z1 = (SecP224R1FieldElement)this.RawZCoords[0];
+            SecP224R1FieldElement Z2 = (SecP224R1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat224.CreateExt();
+            uint[] t2 = Nat224.Create();
+            uint[] t3 = Nat224.Create();
+            uint[] t4 = Nat224.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP224R1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP224R1Field.Multiply(S2, X2.x, U2);
+
+                SecP224R1Field.Multiply(S2, Z1.x, S2);
+                SecP224R1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP224R1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP224R1Field.Multiply(S1, X1.x, U1);
+
+                SecP224R1Field.Multiply(S1, Z2.x, S1);
+                SecP224R1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat224.Create();
+            SecP224R1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP224R1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat224.IsZero(H))
+            {
+                if (Nat224.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP224R1Field.Square(H, HSquared);
+
+            uint[] G = Nat224.Create();
+            SecP224R1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP224R1Field.Multiply(HSquared, U1, V);
+
+            SecP224R1Field.Negate(G, G);
+            Nat224.Mul(S1, G, tt1);
+
+            c = Nat224.AddBothTo(V, V, G);
+            SecP224R1Field.Reduce32(c, G);
+
+            SecP224R1FieldElement X3 = new SecP224R1FieldElement(t4);
+            SecP224R1Field.Square(R, X3.x);
+            SecP224R1Field.Subtract(X3.x, G, X3.x);
+
+            SecP224R1FieldElement Y3 = new SecP224R1FieldElement(G);
+            SecP224R1Field.Subtract(V, X3.x, Y3.x);
+            SecP224R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP224R1Field.Reduce(tt1, Y3.x);
+
+            SecP224R1FieldElement Z3 = new SecP224R1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP224R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP224R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP224R1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP224R1FieldElement Y1 = (SecP224R1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.RawXCoord, Z1 = (SecP224R1FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat224.Create();
+            uint[] t2 = Nat224.Create();
+
+            uint[] Y1Squared = Nat224.Create();
+            SecP224R1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat224.Create();
+            SecP224R1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP224R1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP224R1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP224R1Field.Add(X1.x, Z1Squared, M);
+            SecP224R1Field.Multiply(M, t1, M);
+            c = Nat224.AddBothTo(M, M, M);
+            SecP224R1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP224R1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(7, S, 2, 0);
+            SecP224R1Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(7, T, 3, 0, t1);
+            SecP224R1Field.Reduce32(c, t1);
+
+            SecP224R1FieldElement X3 = new SecP224R1FieldElement(T);
+            SecP224R1Field.Square(M, X3.x);
+            SecP224R1Field.Subtract(X3.x, S, X3.x);
+            SecP224R1Field.Subtract(X3.x, S, X3.x);
+
+            SecP224R1FieldElement Y3 = new SecP224R1FieldElement(S);
+            SecP224R1Field.Subtract(S, X3.x, Y3.x);
+            SecP224R1Field.Multiply(Y3.x, M, Y3.x);
+            SecP224R1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP224R1FieldElement Z3 = new SecP224R1FieldElement(M);
+            SecP224R1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP224R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP224R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
new file mode 100644
index 000000000..59e2cefb2
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256K1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"));
+
+        private const int SECP256K1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP256K1Point m_infinity;
+
+        public SecP256K1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP256K1Point(this, null, null);
+
+            this.m_a = FromBigInteger(BigInteger.Zero);
+            this.m_b = FromBigInteger(BigInteger.ValueOf(7));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SECP256K1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP256K1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP256K1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP256K1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP256K1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Field.cs b/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
new file mode 100644
index 000000000..ba3a070a9
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Field.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256K1Field
+    {
+        // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000,
+            0x00000000, 0x00000000, 0x00000000, 0xFFFFF85E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFFF16F5F, 0xFFFFF85D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000007A1, 0x00000002 };
+        private const uint P7 = 0xFFFFFFFF;
+        private const uint PExt15 = 0xFFFFFFFF;
+        private const uint PInv33 = 0x3D1;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat256.Add(x, y, z);
+            if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                Nat.Add33To(8, PInv33, z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(16, xx, yy, zz);
+            if (c != 0 || (zz[15] == PExt15 && Nat.Gte(16, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(16, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(8, x, z);
+            if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                Nat.Add33To(8, PInv33, z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat256.FromBigInteger(x);
+            if (z[7] == P7 && Nat256.Gte(z, P))
+            {
+                Nat256.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(8, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat256.Add(x, P, z);
+                Nat.ShiftDownBit(8, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat256.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[15] == PExt15 && Nat.Gte(16, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(16, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat256.IsZero(x))
+            {
+                Nat256.Zero(z);
+            }
+            else
+            {
+                Nat256.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            ulong cc = Nat256.Mul33Add(PInv33, xx, 8, xx, 0, z, 0);
+            uint c = Nat256.Mul33DWordAdd(PInv33, cc, z, 0);
+
+            Debug.Assert(c == 0 || c == 1);
+
+            if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                Nat.Add33To(8, PInv33, z);
+            }
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            if ((x != 0 && Nat256.Mul33WordAdd(PInv33, x, z, 0) != 0)
+                || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                Nat.Add33To(8, PInv33, z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat256.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat256.Sub(x, y, z);
+            if (c != 0)
+            {
+                Nat.Sub33From(8, PInv33, z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(16, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(16, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(8, x, 0, z);
+            if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                Nat.Add33To(8, PInv33, z);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
new file mode 100644
index 000000000..d9a039a4f
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
@@ -0,0 +1,213 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256K1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP256K1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP256K1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP256K1FieldElement", "x");
+
+            this.x = SecP256K1Field.FromBigInteger(x);
+        }
+
+        public SecP256K1FieldElement()
+        {
+            this.x = Nat256.Create();
+        }
+
+        protected internal SecP256K1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat256.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat256.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat256.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat256.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP256K1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SecP256K1Field.Add(x, ((SecP256K1FieldElement)b).x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat256.Create();
+            SecP256K1Field.AddOne(x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SecP256K1Field.Subtract(x, ((SecP256K1FieldElement)b).x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SecP256K1Field.Multiply(x, ((SecP256K1FieldElement)b).x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat256.Create();
+            Mod.Invert(SecP256K1Field.P, ((SecP256K1FieldElement)b).x, z);
+            SecP256K1Field.Multiply(z, x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat256.Create();
+            SecP256K1Field.Negate(x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat256.Create();
+            SecP256K1Field.Square(x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP256K1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat256.Create();
+            Mod.Invert(SecP256K1Field.P, x, z);
+            return new SecP256K1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            /*
+             * Raise this element to the exponent 2^254 - 2^30 - 2^7 - 2^6 - 2^5 - 2^4 - 2^2
+             * 
+             * Breaking up the exponent's binary representation into "repunits", we get:
+             * { 223 1s } { 1 0s } { 22 1s } { 4 0s } { 2 1s } { 2 0s}
+             * 
+             * Therefore we need an addition chain containing 2, 22, 223 (the lengths of the repunits)
+             * We use: 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
+             */
+
+            uint[] x1 = this.x;
+            if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+                return this;
+
+            uint[] x2 = Nat256.Create();
+            SecP256K1Field.Square(x1, x2);
+            SecP256K1Field.Multiply(x2, x1, x2);
+            uint[] x3 = Nat256.Create();
+            SecP256K1Field.Square(x2, x3);
+            SecP256K1Field.Multiply(x3, x1, x3);
+            uint[] x6 = Nat256.Create();
+            SecP256K1Field.SquareN(x3, 3, x6);
+            SecP256K1Field.Multiply(x6, x3, x6);
+            uint[] x9 = x6;
+            SecP256K1Field.SquareN(x6, 3, x9);
+            SecP256K1Field.Multiply(x9, x3, x9);
+            uint[] x11 = x9;
+            SecP256K1Field.SquareN(x9, 2, x11);
+            SecP256K1Field.Multiply(x11, x2, x11);
+            uint[] x22 = Nat256.Create();
+            SecP256K1Field.SquareN(x11, 11, x22);
+            SecP256K1Field.Multiply(x22, x11, x22);
+            uint[] x44 = x11;
+            SecP256K1Field.SquareN(x22, 22, x44);
+            SecP256K1Field.Multiply(x44, x22, x44);
+            uint[] x88 = Nat256.Create();
+            SecP256K1Field.SquareN(x44, 44, x88);
+            SecP256K1Field.Multiply(x88, x44, x88);
+            uint[] x176 = Nat256.Create();
+            SecP256K1Field.SquareN(x88, 88, x176);
+            SecP256K1Field.Multiply(x176, x88, x176);
+            uint[] x220 = x88;
+            SecP256K1Field.SquareN(x176, 44, x220);
+            SecP256K1Field.Multiply(x220, x44, x220);
+            uint[] x223 = x44;
+            SecP256K1Field.SquareN(x220, 3, x223);
+            SecP256K1Field.Multiply(x223, x3, x223);
+
+            uint[] t1 = x223;
+            SecP256K1Field.SquareN(t1, 23, t1);
+            SecP256K1Field.Multiply(t1, x22, t1);
+            SecP256K1Field.SquareN(t1, 6, t1);
+            SecP256K1Field.Multiply(t1, x2, t1);
+            SecP256K1Field.SquareN(t1, 2, t1);
+
+            uint[] t2 = x2;
+            SecP256K1Field.Square(t1, t2);
+
+            return Nat256.Eq(x1, t2) ? new SecP256K1FieldElement(t1) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP256K1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP256K1FieldElement);
+        }
+
+        public virtual bool Equals(SecP256K1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat256.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Point.cs b/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
new file mode 100644
index 000000000..3165682fa
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Point.cs
@@ -0,0 +1,265 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256K1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs,
+            bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP256K1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.RawXCoord, Y1 = (SecP256K1FieldElement)this.RawYCoord;
+            SecP256K1FieldElement X2 = (SecP256K1FieldElement)b.RawXCoord, Y2 = (SecP256K1FieldElement)b.RawYCoord;
+
+            SecP256K1FieldElement Z1 = (SecP256K1FieldElement)this.RawZCoords[0];
+            SecP256K1FieldElement Z2 = (SecP256K1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat256.CreateExt();
+            uint[] t2 = Nat256.Create();
+            uint[] t3 = Nat256.Create();
+            uint[] t4 = Nat256.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP256K1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP256K1Field.Multiply(S2, X2.x, U2);
+
+                SecP256K1Field.Multiply(S2, Z1.x, S2);
+                SecP256K1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP256K1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP256K1Field.Multiply(S1, X1.x, U1);
+
+                SecP256K1Field.Multiply(S1, Z2.x, S1);
+                SecP256K1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat256.Create();
+            SecP256K1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP256K1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat256.IsZero(H))
+            {
+                if (Nat256.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP256K1Field.Square(H, HSquared);
+
+            uint[] G = Nat256.Create();
+            SecP256K1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP256K1Field.Multiply(HSquared, U1, V);
+
+            SecP256K1Field.Negate(G, G);
+            Nat256.Mul(S1, G, tt1);
+
+            c = Nat256.AddBothTo(V, V, G);
+            SecP256K1Field.Reduce32(c, G);
+
+            SecP256K1FieldElement X3 = new SecP256K1FieldElement(t4);
+            SecP256K1Field.Square(R, X3.x);
+            SecP256K1Field.Subtract(X3.x, G, X3.x);
+
+            SecP256K1FieldElement Y3 = new SecP256K1FieldElement(G);
+            SecP256K1Field.Subtract(V, X3.x, Y3.x);
+            SecP256K1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP256K1Field.Reduce(tt1, Y3.x);
+
+            SecP256K1FieldElement Z3 = new SecP256K1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP256K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP256K1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP256K1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP256K1FieldElement Y1 = (SecP256K1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.RawXCoord, Z1 = (SecP256K1FieldElement)this.RawZCoords[0];
+
+            uint c;
+
+            uint[] Y1Squared = Nat256.Create();
+            SecP256K1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat256.Create();
+            SecP256K1Field.Square(Y1Squared, T);
+
+            uint[] M = Nat256.Create();
+            SecP256K1Field.Square(X1.x, M);
+            c = Nat256.AddBothTo(M, M, M);
+            SecP256K1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP256K1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(8, S, 2, 0);
+            SecP256K1Field.Reduce32(c, S);
+
+            uint[] t1 = Nat256.Create();
+            c = Nat.ShiftUpBits(8, T, 3, 0, t1);
+            SecP256K1Field.Reduce32(c, t1);
+
+            SecP256K1FieldElement X3 = new SecP256K1FieldElement(T);
+            SecP256K1Field.Square(M, X3.x);
+            SecP256K1Field.Subtract(X3.x, S, X3.x);
+            SecP256K1Field.Subtract(X3.x, S, X3.x);
+
+            SecP256K1FieldElement Y3 = new SecP256K1FieldElement(S);
+            SecP256K1Field.Subtract(S, X3.x, Y3.x);
+            SecP256K1Field.Multiply(Y3.x, M, Y3.x);
+            SecP256K1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP256K1FieldElement Z3 = new SecP256K1FieldElement(M);
+            SecP256K1Field.Twice(Y1.x, Z3.x);
+            if (!Z1.IsOne)
+            {
+                SecP256K1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP256K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP256K1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
new file mode 100644
index 000000000..6b3448f06
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256R1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"));
+
+        private const int SecP256R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP256R1Point m_infinity;
+
+        public SecP256R1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP256R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B")));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SecP256R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP256R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+            case COORD_JACOBIAN:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP256R1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP256R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP256R1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Field.cs b/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
new file mode 100644
index 000000000..9ed9dcd41
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Field.cs
@@ -0,0 +1,309 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256R1Field
+    {
+        // 2^256 - 2^224 + 2^192 + 2^96 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000,
+            0x00000001, 0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0x00000001, 0xFFFFFFFE,
+            0x00000002, 0xFFFFFFFE };
+        internal const uint P7 = 0xFFFFFFFF;
+        internal const uint PExt15 = 0xFFFFFFFE;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat256.Add(x, y, z);
+            if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(16, xx, yy, zz);
+            if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+            {
+                Nat.SubFrom(16, PExt, zz);
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(8, x, z);
+            if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat256.FromBigInteger(x);
+            if (z[7] == P7 && Nat256.Gte(z, P))
+            {
+                Nat256.SubFrom(P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(8, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat256.Add(x, P, z);
+                Nat.ShiftDownBit(8, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void MultiplyAddToExt(uint[] x, uint[] y, uint[] zz)
+        {
+            uint c = Nat256.MulAddTo(x, y, zz);
+            if (c != 0 || (zz[15] >= PExt15 && Nat.Gte(16, zz, PExt)))
+            {
+                Nat.SubFrom(16, PExt, zz);
+            }
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat256.IsZero(x))
+            {
+                Nat256.Zero(z);
+            }
+            else
+            {
+                Nat256.Sub(P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            long xx08 = xx[8], xx09 = xx[9], xx10 = xx[10], xx11 = xx[11];
+            long xx12 = xx[12], xx13 = xx[13], xx14 = xx[14], xx15 = xx[15];
+
+            const long n = 6;
+
+            xx08 -= n;
+
+            long t0 = xx08 + xx09;
+            long t1 = xx09 + xx10;
+            long t2 = xx10 + xx11 - xx15;
+            long t3 = xx11 + xx12;
+            long t4 = xx12 + xx13;
+            long t5 = xx13 + xx14;
+            long t6 = xx14 + xx15;
+
+            long cc = 0;
+            cc += (long)xx[0] + t0 - t3 - t5;
+            z[0] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[1] + t1 - t4 - t6;
+            z[1] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[2] + t2 - t5;
+            z[2] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[3] + (t3 << 1) + xx13 - xx15 - t0;
+            z[3] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[4] + (t4 << 1) + xx14 - t1;
+            z[4] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[5] + (t5 << 1) - t2;
+            z[5] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[6] + (t6 << 1) + t5 - t0;
+            z[6] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[7] + (xx15 << 1) + xx08 - t2 - t4;
+            z[7] = (uint)cc;
+            cc >>= 32;
+            cc += n;
+
+            Debug.Assert(cc >= 0);
+
+            Reduce32((uint)cc, z);
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            long cc = 0;
+
+            if (x != 0)
+            {
+                long xx08 = x;
+
+                cc += (long)z[0] + xx08;
+                z[0] = (uint)cc;
+                cc >>= 32;
+                if (cc != 0)
+                {
+                    cc += (long)z[1];
+                    z[1] = (uint)cc;
+                    cc >>= 32;
+                    cc += (long)z[2];
+                    z[2] = (uint)cc;
+                    cc >>= 32;
+                }
+                cc += (long)z[3] - xx08;
+                z[3] = (uint)cc;
+                cc >>= 32;
+                if (cc != 0)
+                {
+                    cc += (long)z[4];
+                    z[4] = (uint)cc;
+                    cc >>= 32;
+                    cc += (long)z[5];
+                    z[5] = (uint)cc;
+                    cc >>= 32;
+                }
+                cc += (long)z[6] - xx08;
+                z[6] = (uint)cc;
+                cc >>= 32;
+                cc += (long)z[7] + xx08;
+                z[7] = (uint)cc;
+                cc >>= 32;
+
+                Debug.Assert(cc == 0 || cc == 1);
+            }
+
+            if (cc != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat256.CreateExt();
+            Nat256.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat256.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat256.Sub(x, y, z);
+            if (c != 0)
+            {
+                SubPInvFrom(z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(16, xx, yy, zz);
+            if (c != 0)
+            {
+                Nat.AddTo(16, PExt, zz);
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(8, x, 0, z);
+            if (c != 0 || (z[7] == P7 && Nat256.Gte(z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        private static void AddPInvTo(uint[] z)
+        {
+            long c = (long)z[0] + 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+                c += (long)z[2];
+                z[2] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[3] - 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[4];
+                z[4] = (uint)c;
+                c >>= 32;
+                c += (long)z[5];
+                z[5] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[6] - 1;
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (long)z[7] + 1;
+            z[7] = (uint)c;
+            //c >>= 32;
+        }
+
+        private static void SubPInvFrom(uint[] z)
+        {
+            long c = (long)z[0] - 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[1];
+                z[1] = (uint)c;
+                c >>= 32;
+                c += (long)z[2];
+                z[2] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[3] + 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[4];
+                z[4] = (uint)c;
+                c >>= 32;
+                c += (long)z[5];
+                z[5] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[6] + 1;
+            z[6] = (uint)c;
+            c >>= 32;
+            c += (long)z[7] - 1;
+            z[7] = (uint)c;
+            //c >>= 32;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
new file mode 100644
index 000000000..b22763cfa
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
@@ -0,0 +1,187 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256R1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP256R1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP256R1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP256R1FieldElement", "x");
+
+            this.x = SecP256R1Field.FromBigInteger(x);
+        }
+
+        public SecP256R1FieldElement()
+        {
+            this.x = Nat256.Create();
+        }
+
+        protected internal SecP256R1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat256.IsZero(x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat256.IsOne(x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat256.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat256.ToBigInteger(x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP256R1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SecP256R1Field.Add(x, ((SecP256R1FieldElement)b).x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat256.Create();
+            SecP256R1Field.AddOne(x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SecP256R1Field.Subtract(x, ((SecP256R1FieldElement)b).x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat256.Create();
+            SecP256R1Field.Multiply(x, ((SecP256R1FieldElement)b).x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat256.Create();
+            Mod.Invert(SecP256R1Field.P, ((SecP256R1FieldElement)b).x, z);
+            SecP256R1Field.Multiply(z, x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat256.Create();
+            SecP256R1Field.Negate(x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat256.Create();
+            SecP256R1Field.Square(x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP256R1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat256.Create();
+            Mod.Invert(SecP256R1Field.P, x, z);
+            return new SecP256R1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            // Raise this element to the exponent 2^254 - 2^222 + 2^190 + 2^94
+
+            uint[] x1 = this.x;
+            if (Nat256.IsZero(x1) || Nat256.IsOne(x1))
+                return this;
+
+            uint[] t1 = Nat256.Create();
+            uint[] t2 = Nat256.Create();
+
+            SecP256R1Field.Square(x1, t1);
+            SecP256R1Field.Multiply(t1, x1, t1);
+
+            SecP256R1Field.SquareN(t1, 2, t2);
+            SecP256R1Field.Multiply(t2, t1, t2);
+
+            SecP256R1Field.SquareN(t2, 4, t1);
+            SecP256R1Field.Multiply(t1, t2, t1);
+
+            SecP256R1Field.SquareN(t1, 8, t2);
+            SecP256R1Field.Multiply(t2, t1, t2);
+
+            SecP256R1Field.SquareN(t2, 16, t1);
+            SecP256R1Field.Multiply(t1, t2, t1);
+
+            SecP256R1Field.SquareN(t1, 32, t1);
+            SecP256R1Field.Multiply(t1, x1, t1);
+
+            SecP256R1Field.SquareN(t1, 96, t1);
+            SecP256R1Field.Multiply(t1, x1, t1);
+
+            SecP256R1Field.SquareN(t1, 94, t1);
+            SecP256R1Field.Multiply(t1, t1, t2);
+
+            return Nat256.Eq(x1, t2) ? new SecP256R1FieldElement(t1) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP256R1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP256R1FieldElement);
+        }
+
+        public virtual bool Equals(SecP256R1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat256.Eq(x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 8);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Point.cs b/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
new file mode 100644
index 000000000..1de4a0b4a
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Point.cs
@@ -0,0 +1,277 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP256R1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP256R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.RawXCoord, Y1 = (SecP256R1FieldElement)this.RawYCoord;
+            SecP256R1FieldElement X2 = (SecP256R1FieldElement)b.RawXCoord, Y2 = (SecP256R1FieldElement)b.RawYCoord;
+
+            SecP256R1FieldElement Z1 = (SecP256R1FieldElement)this.RawZCoords[0];
+            SecP256R1FieldElement Z2 = (SecP256R1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat256.CreateExt();
+            uint[] t2 = Nat256.Create();
+            uint[] t3 = Nat256.Create();
+            uint[] t4 = Nat256.Create();
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP256R1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP256R1Field.Multiply(S2, X2.x, U2);
+
+                SecP256R1Field.Multiply(S2, Z1.x, S2);
+                SecP256R1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP256R1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP256R1Field.Multiply(S1, X1.x, U1);
+
+                SecP256R1Field.Multiply(S1, Z2.x, S1);
+                SecP256R1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat256.Create();
+            SecP256R1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP256R1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat256.IsZero(H))
+            {
+                if (Nat256.IsZero(R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP256R1Field.Square(H, HSquared);
+
+            uint[] G = Nat256.Create();
+            SecP256R1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP256R1Field.Multiply(HSquared, U1, V);
+
+            SecP256R1Field.Negate(G, G);
+            Nat256.Mul(S1, G, tt1);
+
+            c = Nat256.AddBothTo(V, V, G);
+            SecP256R1Field.Reduce32(c, G);
+
+            SecP256R1FieldElement X3 = new SecP256R1FieldElement(t4);
+            SecP256R1Field.Square(R, X3.x);
+            SecP256R1Field.Subtract(X3.x, G, X3.x);
+
+            SecP256R1FieldElement Y3 = new SecP256R1FieldElement(G);
+            SecP256R1Field.Subtract(V, X3.x, Y3.x);
+            SecP256R1Field.MultiplyAddToExt(Y3.x, R, tt1);
+            SecP256R1Field.Reduce(tt1, Y3.x);
+
+            SecP256R1FieldElement Z3 = new SecP256R1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP256R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP256R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[]{ Z3 };
+
+            return new SecP256R1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP256R1FieldElement Y1 = (SecP256R1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.RawXCoord, Z1 = (SecP256R1FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat256.Create();
+            uint[] t2 = Nat256.Create();
+
+            uint[] Y1Squared = Nat256.Create();
+            SecP256R1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat256.Create();
+            SecP256R1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP256R1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP256R1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP256R1Field.Add(X1.x, Z1Squared, M);
+            SecP256R1Field.Multiply(M, t1, M);
+            c = Nat256.AddBothTo(M, M, M);
+            SecP256R1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP256R1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(8, S, 2, 0);
+            SecP256R1Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(8, T, 3, 0, t1);
+            SecP256R1Field.Reduce32(c, t1);
+
+            SecP256R1FieldElement X3 = new SecP256R1FieldElement(T);
+            SecP256R1Field.Square(M, X3.x);
+            SecP256R1Field.Subtract(X3.x, S, X3.x);
+            SecP256R1Field.Subtract(X3.x, S, X3.x);
+
+            SecP256R1FieldElement Y3 = new SecP256R1FieldElement(S);
+            SecP256R1Field.Subtract(S, X3.x, Y3.x);
+            SecP256R1Field.Multiply(Y3.x, M, Y3.x);
+            SecP256R1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP256R1FieldElement Z3 = new SecP256R1FieldElement(M);
+            SecP256R1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP256R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP256R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP256R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
new file mode 100644
index 000000000..7fd58276a
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP384R1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"));
+
+        private const int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP384R1Point m_infinity;
+
+        public SecP384R1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP384R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF")));
+            this.m_order = new BigInteger(1, Hex.Decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SecP384R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP384R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_JACOBIAN:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP384R1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP384R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP384R1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Field.cs b/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
new file mode 100644
index 000000000..508b01e3c
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Field.cs
@@ -0,0 +1,292 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP384R1Field
+    {
+            // 2^384 - 2^128 - 2^96 + 2^32 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        internal static readonly uint[] PExt = new uint[]{ 0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE,
+            0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000000,
+            0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+        private static readonly uint[] PExtInv = new uint[]{ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0x00000001,
+            0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF,
+            0x00000001, 0x00000002 };
+        private const uint P11 = 0xFFFFFFFF;
+        private const uint PExt23 = 0xFFFFFFFF;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat.Add(12, x, y, z);
+            if (c != 0 || (z[11] == P11 && Nat.Gte(12, z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void AddExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            uint c = Nat.Add(24, xx, yy, zz);
+            if (c != 0 || (zz[23] == PExt23 && Nat.Gte(24, zz, PExt)))
+            {
+                if (Nat.AddTo(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.IncAt(24, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(12, x, z);
+            if (c != 0 || (z[11] == P11 && Nat.Gte(12, z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat.FromBigInteger(384, x);
+            if (z[11] == P11 && Nat.Gte(12, z, P))
+            {
+                Nat.SubFrom(12, P, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            if ((x[0] & 1) == 0)
+            {
+                Nat.ShiftDownBit(12, x, 0, z);
+            }
+            else
+            {
+                uint c = Nat.Add(12, x, P, z);
+                Nat.ShiftDownBit(12, z, c);
+            }
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat.Create(24);
+            Nat384.Mul(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat.IsZero(12, x))
+            {
+                Nat.Zero(12, z);
+            }
+            else
+            {
+                Nat.Sub(12, P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            long xx16 = xx[16], xx17 = xx[17], xx18 = xx[18], xx19 = xx[19];
+            long xx20 = xx[20], xx21 = xx[21], xx22 = xx[22], xx23 = xx[23];
+
+            const long n = 1;
+
+            long t0 = (long)xx[12] + xx20 - n;
+            long t1 = (long)xx[13] + xx22;
+            long t2 = (long)xx[14] + xx22 + xx23;
+            long t3 = (long)xx[15] + xx23;
+            long t4 = xx17 + xx21;
+            long t5 = xx21 - xx23;
+            long t6 = xx22 - xx23;
+
+            long cc = 0;
+            cc += (long)xx[0] + t0 + t5;
+            z[0] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[1] + xx23 - t0 + t1;
+            z[1] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[2] - xx21 - t1 + t2;
+            z[2] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[3] + t0 - t2 + t3 + t5;
+            z[3] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[4] + xx16 + xx21 + t0 + t1 - t3 + t5;
+            z[4] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[5] - xx16 + t1 + t2 + t4;
+            z[5] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[6] + xx18 - xx17 + t2 + t3;
+            z[6] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[7] + xx16 + xx19 - xx18 + t3;
+            z[7] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[8] + xx16 + xx17 + xx20 - xx19;
+            z[8] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[9] + xx18 - xx20 + t4;
+            z[9] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[10] + xx18 + xx19 - t5 + t6;
+            z[10] = (uint)cc;
+            cc >>= 32;
+            cc += (long)xx[11] + xx19 + xx20 - t6;
+            z[11] = (uint)cc;
+            cc >>= 32;
+            cc += n;
+
+            Debug.Assert(cc >= 0);
+
+            Reduce32((uint)cc, z);
+        }
+
+        public static void Reduce32(uint x, uint[] z)
+        {
+            long cc = 0;
+
+            if (x != 0)
+            {
+                long xx12 = x;
+
+                cc += (long)z[0] + xx12;
+                z[0] = (uint)cc;
+                cc >>= 32;
+                cc += (long)z[1] - xx12;
+                z[1] = (uint)cc;
+                cc >>= 32;
+                if (cc != 0)
+                {
+                    cc += (long)z[2];
+                    z[2] = (uint)cc;
+                    cc >>= 32;
+                }
+                cc += (long)z[3] + xx12;
+                z[3] = (uint)cc;
+                cc >>= 32;
+                cc += (long)z[4] + xx12;
+                z[4] = (uint)cc;
+                cc >>= 32;
+
+                Debug.Assert(cc == 0 || cc == 1);
+            }
+
+            if ((cc != 0 && Nat.IncAt(12, z, 5) != 0)
+                || (z[11] == P11 && Nat.Gte(12, z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat.Create(24);
+            Nat384.Square(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+
+            uint[] tt = Nat.Create(24);
+            Nat384.Square(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                Nat384.Square(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat.Sub(12, x, y, z);
+            if (c != 0)
+            {
+                SubPInvFrom(z);
+            }
+        }
+
+        public static void SubtractExt(uint[] xx, uint[] yy, uint[] zz)
+        {
+            int c = Nat.Sub(24, xx, yy, zz);
+            if (c != 0)
+            {
+                if (Nat.SubFrom(PExtInv.Length, PExtInv, zz) != 0)
+                {
+                    Nat.DecAt(24, zz, PExtInv.Length);
+                }
+            }
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint c = Nat.ShiftUpBit(12, x, 0, z);
+            if (c != 0 || (z[11] == P11 && Nat.Gte(12, z, P)))
+            {
+                AddPInvTo(z);
+            }
+        }
+
+        private static void AddPInvTo(uint[] z)
+        {
+            long c = (long)z[0] + 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] - 1;
+            z[1] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[2];
+                z[2] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[3] + 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] + 1;
+            z[4] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                Nat.IncAt(12, z, 5);
+            }
+        }
+
+        private static void SubPInvFrom(uint[] z)
+        {
+            long c = (long)z[0] - 1;
+            z[0] = (uint)c;
+            c >>= 32;
+            c += (long)z[1] + 1;
+            z[1] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                c += (long)z[2];
+                z[2] = (uint)c;
+                c >>= 32;
+            }
+            c += (long)z[3] - 1;
+            z[3] = (uint)c;
+            c >>= 32;
+            c += (long)z[4] - 1;
+            z[4] = (uint)c;
+            c >>= 32;
+            if (c != 0)
+            {
+                Nat.DecAt(12, z, 5);
+            }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
new file mode 100644
index 000000000..40086978d
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
@@ -0,0 +1,209 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP384R1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP384R1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP384R1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP384R1FieldElement", "x");
+
+            this.x = SecP384R1Field.FromBigInteger(x);
+        }
+
+        public SecP384R1FieldElement()
+        {
+            this.x = Nat.Create(12);
+        }
+
+        protected internal SecP384R1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat.IsZero(12, x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat.IsOne(12, x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat.ToBigInteger(12, x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP384R1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat.Create(12);
+            SecP384R1Field.Add(x, ((SecP384R1FieldElement)b).x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat.Create(12);
+            SecP384R1Field.AddOne(x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat.Create(12);
+            SecP384R1Field.Subtract(x, ((SecP384R1FieldElement)b).x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat.Create(12);
+            SecP384R1Field.Multiply(x, ((SecP384R1FieldElement)b).x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat.Create(12);
+            Mod.Invert(SecP384R1Field.P, ((SecP384R1FieldElement)b).x, z);
+            SecP384R1Field.Multiply(z, x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat.Create(12);
+            SecP384R1Field.Negate(x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat.Create(12);
+            SecP384R1Field.Square(x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP384R1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat.Create(12);
+            Mod.Invert(SecP384R1Field.P, x, z);
+            return new SecP384R1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            // Raise this element to the exponent 2^382 - 2^126 - 2^94 + 2^30
+
+            uint[] x1 = this.x;
+            if (Nat.IsZero(12, x1) || Nat.IsOne(12, x1))
+                return this;
+
+            uint[] t1 = Nat.Create(12);
+            uint[] t2 = Nat.Create(12);
+            uint[] t3 = Nat.Create(12);
+            uint[] t4 = Nat.Create(12);
+
+            SecP384R1Field.Square(x1, t1);
+            SecP384R1Field.Multiply(t1, x1, t1);
+
+            SecP384R1Field.SquareN(t1, 2, t2);
+            SecP384R1Field.Multiply(t2, t1, t2);
+
+            SecP384R1Field.Square(t2, t2);
+            SecP384R1Field.Multiply(t2, x1, t2);
+
+            SecP384R1Field.SquareN(t2, 5, t3);
+            SecP384R1Field.Multiply(t3, t2, t3);
+
+            SecP384R1Field.SquareN(t3, 5, t4);
+            SecP384R1Field.Multiply(t4, t2, t4);
+
+            SecP384R1Field.SquareN(t4, 15, t2);
+            SecP384R1Field.Multiply(t2, t4, t2);
+
+            SecP384R1Field.SquareN(t2, 2, t3);
+            SecP384R1Field.Multiply(t1, t3, t1);
+
+            SecP384R1Field.SquareN(t3, 28, t3);
+            SecP384R1Field.Multiply(t2, t3, t2);
+
+            SecP384R1Field.SquareN(t2, 60, t3);
+            SecP384R1Field.Multiply(t3, t2, t3);
+
+            uint[] r = t2;
+
+            SecP384R1Field.SquareN(t3, 120, r);
+            SecP384R1Field.Multiply(r, t3, r);
+
+            SecP384R1Field.SquareN(r, 15, r);
+            SecP384R1Field.Multiply(r, t4, r);
+
+            SecP384R1Field.SquareN(r, 33, r);
+            SecP384R1Field.Multiply(r, t1, r);
+
+            SecP384R1Field.SquareN(r, 64, r);
+            SecP384R1Field.Multiply(r, x1, r);
+
+            SecP384R1Field.SquareN(r, 30, t1);
+            SecP384R1Field.Square(t1, t2);
+
+            return Nat.Eq(12, x1, t2) ? new SecP384R1FieldElement(t1) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP384R1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP384R1FieldElement);
+        }
+
+        public virtual bool Equals(SecP384R1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat.Eq(12, x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 12);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Point.cs b/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
new file mode 100644
index 000000000..68c601611
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Point.cs
@@ -0,0 +1,278 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP384R1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP384R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.RawXCoord, Y1 = (SecP384R1FieldElement)this.RawYCoord;
+            SecP384R1FieldElement X2 = (SecP384R1FieldElement)b.RawXCoord, Y2 = (SecP384R1FieldElement)b.RawYCoord;
+
+            SecP384R1FieldElement Z1 = (SecP384R1FieldElement)this.RawZCoords[0];
+            SecP384R1FieldElement Z2 = (SecP384R1FieldElement)b.RawZCoords[0];
+
+            uint c;
+            uint[] tt1 = Nat.Create(24);
+            uint[] tt2 = Nat.Create(24);
+            uint[] t3 = Nat.Create(12);
+            uint[] t4 = Nat.Create(12);
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP384R1Field.Square(Z1.x, S2);
+
+                U2 = tt2;
+                SecP384R1Field.Multiply(S2, X2.x, U2);
+
+                SecP384R1Field.Multiply(S2, Z1.x, S2);
+                SecP384R1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP384R1Field.Square(Z2.x, S1);
+
+                U1 = tt1;
+                SecP384R1Field.Multiply(S1, X1.x, U1);
+
+                SecP384R1Field.Multiply(S1, Z2.x, S1);
+                SecP384R1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat.Create(12);
+            SecP384R1Field.Subtract(U1, U2, H);
+
+            uint[] R = Nat.Create(12);
+            SecP384R1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat.IsZero(12, H))
+            {
+                if (Nat.IsZero(12, R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP384R1Field.Square(H, HSquared);
+
+            uint[] G = Nat.Create(12);
+            SecP384R1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP384R1Field.Multiply(HSquared, U1, V);
+
+            SecP384R1Field.Negate(G, G);
+            Nat384.Mul(S1, G, tt1);
+
+            c = Nat.AddBothTo(12, V, V, G);
+            SecP384R1Field.Reduce32(c, G);
+
+            SecP384R1FieldElement X3 = new SecP384R1FieldElement(t4);
+            SecP384R1Field.Square(R, X3.x);
+            SecP384R1Field.Subtract(X3.x, G, X3.x);
+
+            SecP384R1FieldElement Y3 = new SecP384R1FieldElement(G);
+            SecP384R1Field.Subtract(V, X3.x, Y3.x);
+            Nat384.Mul(Y3.x, R, tt2);
+            SecP384R1Field.AddExt(tt1, tt2, tt1);
+            SecP384R1Field.Reduce(tt1, Y3.x);
+
+            SecP384R1FieldElement Z3 = new SecP384R1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP384R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP384R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP384R1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP384R1FieldElement Y1 = (SecP384R1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.RawXCoord, Z1 = (SecP384R1FieldElement)this.RawZCoords[0];
+
+            uint c;
+            uint[] t1 = Nat.Create(12);
+            uint[] t2 = Nat.Create(12);
+
+            uint[] Y1Squared = Nat.Create(12);
+            SecP384R1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat.Create(12);
+            SecP384R1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP384R1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP384R1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP384R1Field.Add(X1.x, Z1Squared, M);
+            SecP384R1Field.Multiply(M, t1, M);
+            c = Nat.AddBothTo(12, M, M, M);
+            SecP384R1Field.Reduce32(c, M);
+
+            uint[] S = Y1Squared;
+            SecP384R1Field.Multiply(Y1Squared, X1.x, S);
+            c = Nat.ShiftUpBits(12, S, 2, 0);
+            SecP384R1Field.Reduce32(c, S);
+
+            c = Nat.ShiftUpBits(12, T, 3, 0, t1);
+            SecP384R1Field.Reduce32(c, t1);
+
+            SecP384R1FieldElement X3 = new SecP384R1FieldElement(T);
+            SecP384R1Field.Square(M, X3.x);
+            SecP384R1Field.Subtract(X3.x, S, X3.x);
+            SecP384R1Field.Subtract(X3.x, S, X3.x);
+
+            SecP384R1FieldElement Y3 = new SecP384R1FieldElement(S);
+            SecP384R1Field.Subtract(S, X3.x, Y3.x);
+            SecP384R1Field.Multiply(Y3.x, M, Y3.x);
+            SecP384R1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP384R1FieldElement Z3 = new SecP384R1FieldElement(M);
+            SecP384R1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP384R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP384R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
new file mode 100644
index 000000000..e5083c7f0
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
@@ -0,0 +1,77 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP521R1Curve
+        : AbstractFpCurve
+    {
+        public static readonly BigInteger q = new BigInteger(1,
+            Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+        private const int SecP521R1_DEFAULT_COORDS = COORD_JACOBIAN;
+
+        protected readonly SecP521R1Point m_infinity;
+
+        public SecP521R1Curve()
+            : base(q)
+        {
+            this.m_infinity = new SecP521R1Point(this, null, null);
+
+            this.m_a = FromBigInteger(new BigInteger(1,
+                Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC")));
+            this.m_b = FromBigInteger(new BigInteger(1,
+                Hex.Decode("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00")));
+            this.m_order = new BigInteger(1, Hex.Decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"));
+            this.m_cofactor = BigInteger.One;
+            this.m_coord = SecP521R1_DEFAULT_COORDS;
+        }
+
+        protected override ECCurve CloneCurve()
+        {
+            return new SecP521R1Curve();
+        }
+
+        public override bool SupportsCoordinateSystem(int coord)
+        {
+            switch (coord)
+            {
+                case COORD_JACOBIAN:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        public virtual BigInteger Q
+        {
+            get { return q; }
+        }
+
+        public override ECPoint Infinity
+        {
+            get { return m_infinity; }
+        }
+
+        public override int FieldSize
+        {
+            get { return q.BitLength; }
+        }
+
+        public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new SecP521R1FieldElement(x);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression)
+        {
+            return new SecP521R1Point(this, x, y, withCompression);
+        }
+
+        protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+        {
+            return new SecP521R1Point(this, x, y, zs, withCompression);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Field.cs b/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
new file mode 100644
index 000000000..3568156d8
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Field.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP521R1Field
+    {
+        // 2^521 - 1
+        internal static readonly uint[] P = new uint[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+            0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x1FF };
+        private const int P16 = 0x1FF;
+
+        public static void Add(uint[] x, uint[] y, uint[] z)
+        {
+            uint c = Nat.Add(16, x, y, z) + x[16] + y[16];
+            if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+            {
+                c += Nat.Inc(16, z);
+                c &= P16;
+            }
+            z[16] = c;
+        }
+
+        public static void AddOne(uint[] x, uint[] z)
+        {
+            uint c = Nat.Inc(16, x, z) + x[16];
+            if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+            {
+                c += Nat.Inc(16, z);
+                c &= P16;
+            }
+            z[16] = c;
+        }
+
+        public static uint[] FromBigInteger(BigInteger x)
+        {
+            uint[] z = Nat.FromBigInteger(521, x);
+            if (Nat.Eq(17, z, P))
+            {
+                Nat.Zero(17, z);
+            }
+            return z;
+        }
+
+        public static void Half(uint[] x, uint[] z)
+        {
+            uint x16 = x[16];
+            uint c = Nat.ShiftDownBit(16, x, x16, z);
+            z[16] = (x16 >> 1) | (c >> 23);
+        }
+
+        public static void Multiply(uint[] x, uint[] y, uint[] z)
+        {
+            uint[] tt = Nat.Create(33);
+            ImplMultiply(x, y, tt);
+            Reduce(tt, z);
+        }
+
+        public static void Negate(uint[] x, uint[] z)
+        {
+            if (Nat.IsZero(17, x))
+            {
+                Nat.Zero(17, z);
+            }
+            else
+            {
+                Nat.Sub(17, P, x, z);
+            }
+        }
+
+        public static void Reduce(uint[] xx, uint[] z)
+        {
+            Debug.Assert(xx[32] >> 18 == 0);
+            uint xx32 = xx[32];
+            uint c = Nat.ShiftDownBits(16, xx, 16, 9, xx32, z, 0) >> 23;
+            c += xx32 >> 9;
+            c += Nat.AddTo(16, xx, z);
+            if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+            {
+                c += Nat.Inc(16, z);
+                c &= P16;
+            }
+            z[16] = c;
+        }
+
+        public static void Reduce23(uint[] z)
+        {
+            uint z16 = z[16];
+            uint c = Nat.AddWordTo(16, z16 >> 9, z) + (z16 & P16);
+            if (c > P16 || (c == P16 && Nat.Eq(16, z, P)))
+            {
+                c += Nat.Inc(16, z);
+                c &= P16;
+            }
+            z[16] = c;
+        }
+
+        public static void Square(uint[] x, uint[] z)
+        {
+            uint[] tt = Nat.Create(33);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+        }
+
+        public static void SquareN(uint[] x, int n, uint[] z)
+        {
+            Debug.Assert(n > 0);
+            uint[] tt = Nat.Create(33);
+            ImplSquare(x, tt);
+            Reduce(tt, z);
+
+            while (--n > 0)
+            {
+                ImplSquare(z, tt);
+                Reduce(tt, z);
+            }
+        }
+
+        public static void Subtract(uint[] x, uint[] y, uint[] z)
+        {
+            int c = Nat.Sub(16, x, y, z) + (int)(x[16] - y[16]);
+            if (c < 0)
+            {
+                c += Nat.Dec(16, z);
+                c &= P16;
+            }
+            z[16] = (uint)c;
+        }
+
+        public static void Twice(uint[] x, uint[] z)
+        {
+            uint x16 = x[16];
+            uint c = Nat.ShiftUpBit(16, x, x16 << 23, z) | (x16 << 1);
+            z[16] = c & P16;
+        }
+
+        protected static void ImplMultiply(uint[] x, uint[] y, uint[] zz)
+        {
+            Nat512.Mul(x, y, zz);
+
+            uint x16 = x[16], y16 = y[16];
+            zz[32] = Nat.Mul31BothAdd(16, x16, y, y16, x, zz, 16) + (x16 * y16);
+        }
+
+        protected static void ImplSquare(uint[] x, uint[] zz)
+        {
+            Nat512.Square(x, zz);
+
+            uint x16 = x[16];
+            zz[32] = Nat.MulWordAddTo(16, x16 << 1, x, 0, zz, 16) + (x16 * x16);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
new file mode 100644
index 000000000..83a615928
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
@@ -0,0 +1,166 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP521R1FieldElement
+        : ECFieldElement
+    {
+        public static readonly BigInteger Q = SecP521R1Curve.q;
+
+        protected internal readonly uint[] x;
+
+        public SecP521R1FieldElement(BigInteger x)
+        {
+            if (x == null || x.SignValue < 0 || x.CompareTo(Q) >= 0)
+                throw new ArgumentException("value invalid for SecP521R1FieldElement", "x");
+
+            this.x = SecP521R1Field.FromBigInteger(x);
+        }
+
+        public SecP521R1FieldElement()
+        {
+            this.x = Nat.Create(17);
+        }
+
+        protected internal SecP521R1FieldElement(uint[] x)
+        {
+            this.x = x;
+        }
+
+        public override bool IsZero
+        {
+            get { return Nat.IsZero(17, x); }
+        }
+
+        public override bool IsOne
+        {
+            get { return Nat.IsOne(17, x); }
+        }
+
+        public override bool TestBitZero()
+        {
+            return Nat.GetBit(x, 0) == 1;
+        }
+
+        public override BigInteger ToBigInteger()
+        {
+            return Nat.ToBigInteger(17, x);
+        }
+
+        public override string FieldName
+        {
+            get { return "SecP521R1Field"; }
+        }
+
+        public override int FieldSize
+        {
+            get { return Q.BitLength; }
+        }
+
+        public override ECFieldElement Add(ECFieldElement b)
+        {
+            uint[] z = Nat.Create(17);
+            SecP521R1Field.Add(x, ((SecP521R1FieldElement)b).x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        public override ECFieldElement AddOne()
+        {
+            uint[] z = Nat.Create(17);
+            SecP521R1Field.AddOne(x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        public override ECFieldElement Subtract(ECFieldElement b)
+        {
+            uint[] z = Nat.Create(17);
+            SecP521R1Field.Subtract(x, ((SecP521R1FieldElement)b).x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        public override ECFieldElement Multiply(ECFieldElement b)
+        {
+            uint[] z = Nat.Create(17);
+            SecP521R1Field.Multiply(x, ((SecP521R1FieldElement)b).x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        public override ECFieldElement Divide(ECFieldElement b)
+        {
+            //return Multiply(b.Invert());
+            uint[] z = Nat.Create(17);
+            Mod.Invert(SecP521R1Field.P, ((SecP521R1FieldElement)b).x, z);
+            SecP521R1Field.Multiply(z, x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        public override ECFieldElement Negate()
+        {
+            uint[] z = Nat.Create(17);
+            SecP521R1Field.Negate(x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        public override ECFieldElement Square()
+        {
+            uint[] z = Nat.Create(17);
+            SecP521R1Field.Square(x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        public override ECFieldElement Invert()
+        {
+            //return new SecP521R1FieldElement(ToBigInteger().ModInverse(Q));
+            uint[] z = Nat.Create(17);
+            Mod.Invert(SecP521R1Field.P, x, z);
+            return new SecP521R1FieldElement(z);
+        }
+
+        /**
+         * return a sqrt root - the routine verifies that the calculation returns the right value - if
+         * none exists it returns null.
+         */
+        public override ECFieldElement Sqrt()
+        {
+            // Raise this element to the exponent 2^519
+
+            uint[] x1 = this.x;
+            if (Nat.IsZero(17, x1) || Nat.IsOne(17, x1))
+                return this;
+
+            uint[] t1 = Nat.Create(17);
+            uint[] t2 = Nat.Create(17);
+
+            SecP521R1Field.SquareN(x1, 519, t1);
+            SecP521R1Field.Square(t1, t2);
+
+            return Nat.Eq(17, x1, t2) ? new SecP521R1FieldElement(t1) : null;
+        }
+
+        public override bool Equals(object obj)
+        {
+            return Equals(obj as SecP521R1FieldElement);
+        }
+
+        public override bool Equals(ECFieldElement other)
+        {
+            return Equals(other as SecP521R1FieldElement);
+        }
+
+        public virtual bool Equals(SecP521R1FieldElement other)
+        {
+            if (this == other)
+                return true;
+            if (null == other)
+                return false;
+            return Nat.Eq(17, x, other.x);
+        }
+
+        public override int GetHashCode()
+        {
+            return Q.GetHashCode() ^ Arrays.GetHashCode(x, 0, 17);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Point.cs b/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
new file mode 100644
index 000000000..fb1996cfd
--- /dev/null
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Point.cs
@@ -0,0 +1,273 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Custom.Sec
+{
+    internal class SecP521R1Point
+        : AbstractFpPoint
+    {
+        /**
+         * Create a point which encodes with point compression.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * 
+         * @deprecated Use ECCurve.createPoint to construct points
+         */
+        public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y)
+            : this(curve, x, y, false)
+        {
+        }
+
+        /**
+         * Create a point that encodes with or without point compresion.
+         * 
+         * @param curve
+         *            the curve to use
+         * @param x
+         *            affine x co-ordinate
+         * @param y
+         *            affine y co-ordinate
+         * @param withCompression
+         *            if true encode with point compression
+         * 
+         * @deprecated per-point compression property will be removed, refer
+         *             {@link #getEncoded(bool)}
+         */
+        public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression)
+            : base(curve, x, y, withCompression)
+        {
+            if ((x == null) != (y == null))
+                throw new ArgumentException("Exactly one of the field elements is null");
+        }
+
+        internal SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression)
+            : base(curve, x, y, zs, withCompression)
+        {
+        }
+
+        protected override ECPoint Detach()
+        {
+            return new SecP521R1Point(null, AffineXCoord, AffineYCoord);
+        }
+
+        public override ECPoint Add(ECPoint b)
+        {
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return this;
+            if (this == b)
+                return Twice();
+
+            ECCurve curve = this.Curve;
+
+            SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.RawXCoord, Y1 = (SecP521R1FieldElement)this.RawYCoord;
+            SecP521R1FieldElement X2 = (SecP521R1FieldElement)b.RawXCoord, Y2 = (SecP521R1FieldElement)b.RawYCoord;
+
+            SecP521R1FieldElement Z1 = (SecP521R1FieldElement)this.RawZCoords[0];
+            SecP521R1FieldElement Z2 = (SecP521R1FieldElement)b.RawZCoords[0];
+
+            uint[] t1 = Nat.Create(17);
+            uint[] t2 = Nat.Create(17);
+            uint[] t3 = Nat.Create(17);
+            uint[] t4 = Nat.Create(17);
+
+            bool Z1IsOne = Z1.IsOne;
+            uint[] U2, S2;
+            if (Z1IsOne)
+            {
+                U2 = X2.x;
+                S2 = Y2.x;
+            }
+            else
+            {
+                S2 = t3;
+                SecP521R1Field.Square(Z1.x, S2);
+
+                U2 = t2;
+                SecP521R1Field.Multiply(S2, X2.x, U2);
+
+                SecP521R1Field.Multiply(S2, Z1.x, S2);
+                SecP521R1Field.Multiply(S2, Y2.x, S2);
+            }
+
+            bool Z2IsOne = Z2.IsOne;
+            uint[] U1, S1;
+            if (Z2IsOne)
+            {
+                U1 = X1.x;
+                S1 = Y1.x;
+            }
+            else
+            {
+                S1 = t4;
+                SecP521R1Field.Square(Z2.x, S1);
+
+                U1 = t1;
+                SecP521R1Field.Multiply(S1, X1.x, U1);
+
+                SecP521R1Field.Multiply(S1, Z2.x, S1);
+                SecP521R1Field.Multiply(S1, Y1.x, S1);
+            }
+
+            uint[] H = Nat.Create(17);
+            SecP521R1Field.Subtract(U1, U2, H);
+
+            uint[] R = t2;
+            SecP521R1Field.Subtract(S1, S2, R);
+
+            // Check if b == this or b == -this
+            if (Nat.IsZero(17, H))
+            {
+                if (Nat.IsZero(17, R))
+                {
+                    // this == b, i.e. this must be doubled
+                    return this.Twice();
+                }
+
+                // this == -b, i.e. the result is the point at infinity
+                return curve.Infinity;
+            }
+
+            uint[] HSquared = t3;
+            SecP521R1Field.Square(H, HSquared);
+
+            uint[] G = Nat.Create(17);
+            SecP521R1Field.Multiply(HSquared, H, G);
+
+            uint[] V = t3;
+            SecP521R1Field.Multiply(HSquared, U1, V);
+
+            SecP521R1Field.Multiply(S1, G, t1);
+
+            SecP521R1FieldElement X3 = new SecP521R1FieldElement(t4);
+            SecP521R1Field.Square(R, X3.x);
+            SecP521R1Field.Add(X3.x, G, X3.x);
+            SecP521R1Field.Subtract(X3.x, V, X3.x);
+            SecP521R1Field.Subtract(X3.x, V, X3.x);
+
+            SecP521R1FieldElement Y3 = new SecP521R1FieldElement(G);
+            SecP521R1Field.Subtract(V, X3.x, Y3.x);
+            SecP521R1Field.Multiply(Y3.x, R, t2);
+            SecP521R1Field.Subtract(t2, t1, Y3.x);
+
+            SecP521R1FieldElement Z3 = new SecP521R1FieldElement(H);
+            if (!Z1IsOne)
+            {
+                SecP521R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+            if (!Z2IsOne)
+            {
+                SecP521R1Field.Multiply(Z3.x, Z2.x, Z3.x);
+            }
+
+            ECFieldElement[] zs = new ECFieldElement[] { Z3 };
+
+            return new SecP521R1Point(curve, X3, Y3, zs, IsCompressed);
+        }
+
+        public override ECPoint Twice()
+        {
+            if (this.IsInfinity)
+                return this;
+
+            ECCurve curve = this.Curve;
+
+            SecP521R1FieldElement Y1 = (SecP521R1FieldElement)this.RawYCoord;
+            if (Y1.IsZero)
+                return curve.Infinity;
+
+            SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.RawXCoord, Z1 = (SecP521R1FieldElement)this.RawZCoords[0];
+
+            uint[] t1 = Nat.Create(17);
+            uint[] t2 = Nat.Create(17);
+
+            uint[] Y1Squared = Nat.Create(17);
+            SecP521R1Field.Square(Y1.x, Y1Squared);
+
+            uint[] T = Nat.Create(17);
+            SecP521R1Field.Square(Y1Squared, T);
+
+            bool Z1IsOne = Z1.IsOne;
+
+            uint[] Z1Squared = Z1.x;
+            if (!Z1IsOne)
+            {
+                Z1Squared = t2;
+                SecP521R1Field.Square(Z1.x, Z1Squared);
+            }
+
+            SecP521R1Field.Subtract(X1.x, Z1Squared, t1);
+
+            uint[] M = t2;
+            SecP521R1Field.Add(X1.x, Z1Squared, M);
+            SecP521R1Field.Multiply(M, t1, M);
+            Nat.AddBothTo(17, M, M, M);
+            SecP521R1Field.Reduce23(M);
+
+            uint[] S = Y1Squared;
+            SecP521R1Field.Multiply(Y1Squared, X1.x, S);
+            Nat.ShiftUpBits(17, S, 2, 0);
+            SecP521R1Field.Reduce23(S);
+
+            Nat.ShiftUpBits(17, T, 3, 0, t1);
+            SecP521R1Field.Reduce23(t1);
+
+            SecP521R1FieldElement X3 = new SecP521R1FieldElement(T);
+            SecP521R1Field.Square(M, X3.x);
+            SecP521R1Field.Subtract(X3.x, S, X3.x);
+            SecP521R1Field.Subtract(X3.x, S, X3.x);
+
+            SecP521R1FieldElement Y3 = new SecP521R1FieldElement(S);
+            SecP521R1Field.Subtract(S, X3.x, Y3.x);
+            SecP521R1Field.Multiply(Y3.x, M, Y3.x);
+            SecP521R1Field.Subtract(Y3.x, t1, Y3.x);
+
+            SecP521R1FieldElement Z3 = new SecP521R1FieldElement(M);
+            SecP521R1Field.Twice(Y1.x, Z3.x);
+            if (!Z1IsOne)
+            {
+                SecP521R1Field.Multiply(Z3.x, Z1.x, Z3.x);
+            }
+
+            return new SecP521R1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed);
+        }
+
+        public override ECPoint TwicePlus(ECPoint b)
+        {
+            if (this == b)
+                return ThreeTimes();
+            if (this.IsInfinity)
+                return b;
+            if (b.IsInfinity)
+                return Twice();
+
+            ECFieldElement Y1 = this.RawYCoord;
+            if (Y1.IsZero)
+                return b;
+
+            return Twice().Add(b);
+        }
+
+        public override ECPoint ThreeTimes()
+        {
+            if (this.IsInfinity || this.RawYCoord.IsZero)
+                return this;
+
+            // NOTE: Be careful about recursions between TwicePlus and ThreeTimes
+            return Twice().Add(this);
+        }
+
+        public override ECPoint Negate()
+        {
+            if (IsInfinity)
+                return this;
+
+            return new SecP521R1Point(Curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/endo/ECEndomorphism.cs b/crypto/src/math/ec/endo/ECEndomorphism.cs
new file mode 100644
index 000000000..dfb321368
--- /dev/null
+++ b/crypto/src/math/ec/endo/ECEndomorphism.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public interface ECEndomorphism
+    {
+        ECPointMap PointMap { get; }
+
+        bool HasEfficientPointMap { get; }
+    }
+}
diff --git a/crypto/src/math/ec/endo/GlvEndomorphism.cs b/crypto/src/math/ec/endo/GlvEndomorphism.cs
new file mode 100644
index 000000000..f65bdd613
--- /dev/null
+++ b/crypto/src/math/ec/endo/GlvEndomorphism.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public interface GlvEndomorphism
+        :   ECEndomorphism
+    {
+        BigInteger[] DecomposeScalar(BigInteger k);
+    }
+}
diff --git a/crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs b/crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs
new file mode 100644
index 000000000..d234d88bf
--- /dev/null
+++ b/crypto/src/math/ec/endo/GlvTypeBEndomorphism.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public class GlvTypeBEndomorphism
+        :   GlvEndomorphism
+    {
+        protected readonly ECCurve m_curve;
+        protected readonly GlvTypeBParameters m_parameters;
+        protected readonly ECPointMap m_pointMap;
+
+        public GlvTypeBEndomorphism(ECCurve curve, GlvTypeBParameters parameters)
+        {
+            this.m_curve = curve;
+            this.m_parameters = parameters;
+            this.m_pointMap = new ScaleXPointMap(curve.FromBigInteger(parameters.Beta));
+        }
+
+        public virtual BigInteger[] DecomposeScalar(BigInteger k)
+        {
+            int bits = m_parameters.Bits;
+            BigInteger b1 = CalculateB(k, m_parameters.G1, bits);
+            BigInteger b2 = CalculateB(k, m_parameters.G2, bits);
+
+            BigInteger[] v1 = m_parameters.V1, v2 = m_parameters.V2;
+            BigInteger a = k.Subtract((b1.Multiply(v1[0])).Add(b2.Multiply(v2[0])));
+            BigInteger b = (b1.Multiply(v1[1])).Add(b2.Multiply(v2[1])).Negate();
+
+            return new BigInteger[]{ a, b };
+        }
+
+        public virtual ECPointMap PointMap
+        {
+            get { return m_pointMap; }
+        }
+
+        public virtual bool HasEfficientPointMap
+        {
+            get { return true; }
+        }
+
+        protected virtual BigInteger CalculateB(BigInteger k, BigInteger g, int t)
+        {
+            bool negative = (g.SignValue < 0);
+            BigInteger b = k.Multiply(g.Abs());
+            bool extra = b.TestBit(t - 1);
+            b = b.ShiftRight(t);
+            if (extra)
+            {
+                b = b.Add(BigInteger.One);
+            }
+            return negative ? b.Negate() : b;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/endo/GlvTypeBParameters.cs b/crypto/src/math/ec/endo/GlvTypeBParameters.cs
new file mode 100644
index 000000000..f93dfaf2b
--- /dev/null
+++ b/crypto/src/math/ec/endo/GlvTypeBParameters.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Endo
+{
+    public class GlvTypeBParameters
+    {
+        protected readonly BigInteger m_beta;
+        protected readonly BigInteger m_lambda;
+        protected readonly BigInteger[] m_v1, m_v2;
+        protected readonly BigInteger m_g1, m_g2;
+        protected readonly int m_bits;
+
+        public GlvTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2,
+            BigInteger g1, BigInteger g2, int bits)
+        {
+            this.m_beta = beta;
+            this.m_lambda = lambda;
+            this.m_v1 = v1;
+            this.m_v2 = v2;
+            this.m_g1 = g1;
+            this.m_g2 = g2;
+            this.m_bits = bits;
+        }
+
+        public virtual BigInteger Beta
+        {
+            get { return m_beta; }
+        }
+
+        public virtual BigInteger Lambda
+        {
+            get { return m_lambda; }
+        }
+
+        public virtual BigInteger[] V1
+        {
+            get { return m_v1; }
+        }
+
+        public virtual BigInteger[] V2
+        {
+            get { return m_v2; }
+        }
+
+        public virtual BigInteger G1
+        {
+            get { return m_g1; }
+        }
+
+        public virtual BigInteger G2
+        {
+            get { return m_g2; }
+        }
+
+        public virtual int Bits
+        {
+            get { return m_bits; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
new file mode 100644
index 000000000..517881323
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/AbstractECMultiplier.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public abstract class AbstractECMultiplier
+        : ECMultiplier
+    {
+        public virtual ECPoint Multiply(ECPoint p, BigInteger k)
+        {
+            int sign = k.SignValue;
+            if (sign == 0 || p.IsInfinity)
+                return p.Curve.Infinity;
+
+            ECPoint positive = MultiplyPositive(p, k.Abs());
+            ECPoint result = sign > 0 ? positive : positive.Negate();
+
+            /*
+             * Although the various multipliers ought not to produce invalid output under normal
+             * circumstances, a final check here is advised to guard against fault attacks.
+             */
+            return ECAlgorithms.ValidatePoint(result);
+        }
+
+        protected abstract ECPoint MultiplyPositive(ECPoint p, BigInteger k);
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/DoubleAddMultiplier.cs b/crypto/src/math/ec/multiplier/DoubleAddMultiplier.cs
new file mode 100644
index 000000000..18a72c0a2
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/DoubleAddMultiplier.cs
@@ -0,0 +1,24 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public class DoubleAddMultiplier
+        : AbstractECMultiplier
+    {
+        /**
+         * Joye's double-add algorithm.
+         */
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            ECPoint[] R = new ECPoint[]{ p.Curve.Infinity, p };
+
+            int n = k.BitLength;
+            for (int i = 0; i < n; ++i)
+            {
+                int b = k.TestBit(i) ? 1 : 0;
+                int bp = 1 - b;
+                R[bp] = R[bp].TwicePlus(R[b]);
+            }
+
+            return R[0];
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/ECMultiplier.cs b/crypto/src/math/ec/multiplier/ECMultiplier.cs
index c6d768ea8..8d6136b34 100644
--- a/crypto/src/math/ec/multiplier/ECMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/ECMultiplier.cs
@@ -1,18 +1,18 @@
 namespace Org.BouncyCastle.Math.EC.Multiplier
 {
-	/**
-	* Interface for classes encapsulating a point multiplication algorithm
-	* for <code>ECPoint</code>s.
-	*/
-	internal 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);
-	}
+    /**
+    * Interface for classes encapsulating a point multiplication algorithm
+    * for <code>ECPoint</code>s.
+    */
+    public 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> is multiplied.
+         * @return <code>p</code> multiplied by <code>k</code>.
+         */
+        ECPoint Multiply(ECPoint p, BigInteger k);
+    }
 }
diff --git a/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
new file mode 100644
index 000000000..a8ef5a77a
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/FixedPointCombMultiplier.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public class FixedPointCombMultiplier
+        : AbstractECMultiplier
+    {
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            ECCurve c = p.Curve;
+            int size = FixedPointUtilities.GetCombSize(c);
+
+            if (k.BitLength > size)
+            {
+                /*
+                 * TODO The comb works best when the scalars are less than the (possibly unknown) order.
+                 * Still, if we want to handle larger scalars, we could allow customization of the comb
+                 * size, or alternatively we could deal with the 'extra' bits either by running the comb
+                 * multiple times as necessary, or by using an alternative multiplier as prelude.
+                 */
+                throw new InvalidOperationException("fixed-point comb doesn't support scalars larger than the curve order");
+            }
+
+            int minWidth = GetWidthForCombSize(size);
+
+            FixedPointPreCompInfo info = FixedPointUtilities.Precompute(p, minWidth);
+            ECPoint[] lookupTable = info.PreComp;
+            int width = info.Width;
+
+            int d = (size + width - 1) / width;
+
+            ECPoint R = c.Infinity;
+
+            int top = d * width - 1;
+            for (int i = 0; i < d; ++i)
+            {
+                int index = 0;
+
+                for (int j = top - i; j >= 0; j -= d)
+                {
+                    index <<= 1;
+                    if (k.TestBit(j))
+                    {
+                        index |= 1;
+                    }
+                }
+
+                R = R.TwicePlus(lookupTable[index]);
+            }
+
+            return R;
+        }
+
+        protected virtual int GetWidthForCombSize(int combSize)
+        {
+            return combSize > 257 ? 6 : 5;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs
new file mode 100644
index 000000000..56a6326a1
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/FixedPointPreCompInfo.cs
@@ -0,0 +1,34 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    /**
+     * Class holding precomputation data for fixed-point multiplications.
+     */
+    public class FixedPointPreCompInfo
+        : PreCompInfo
+    {
+        /**
+         * Array holding the precomputed <code>ECPoint</code>s used for a fixed
+         * point multiplication.
+         */
+        protected ECPoint[] m_preComp = null;
+
+        /**
+         * The width used for the precomputation. If a larger width precomputation
+         * is already available this may be larger than was requested, so calling
+         * code should refer to the actual width.
+         */
+        protected int m_width = -1;
+
+        public virtual ECPoint[] PreComp
+        {
+            get { return m_preComp; }
+            set { this.m_preComp = value; }
+        }
+
+        public virtual int Width
+        {
+            get { return m_width; }
+            set { this.m_width = value; }
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/FixedPointUtilities.cs b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs
new file mode 100644
index 000000000..d927d010b
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/FixedPointUtilities.cs
@@ -0,0 +1,72 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public class FixedPointUtilities
+    {
+        public static readonly string PRECOMP_NAME = "bc_fixed_point";
+
+        public static int GetCombSize(ECCurve c)
+        {
+            BigInteger order = c.Order;
+            return order == null ? c.FieldSize + 1 : order.BitLength;
+        }
+
+        public static FixedPointPreCompInfo GetFixedPointPreCompInfo(PreCompInfo preCompInfo)
+        {
+            if ((preCompInfo != null) && (preCompInfo is FixedPointPreCompInfo))
+            {
+                return (FixedPointPreCompInfo)preCompInfo;
+            }
+
+            return new FixedPointPreCompInfo();
+        }
+
+        public static FixedPointPreCompInfo Precompute(ECPoint p, int minWidth)
+        {
+            ECCurve c = p.Curve;
+
+            int n = 1 << minWidth;
+            FixedPointPreCompInfo info = GetFixedPointPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
+            ECPoint[] lookupTable = info.PreComp;
+
+            if (lookupTable == null || lookupTable.Length < n)
+            {
+                int bits = GetCombSize(c);
+                int d = (bits + minWidth - 1) / minWidth;
+
+                ECPoint[] pow2Table = new ECPoint[minWidth];
+                pow2Table[0] = p;
+                for (int i = 1; i < minWidth; ++i)
+                {
+                    pow2Table[i] = pow2Table[i - 1].TimesPow2(d);
+                }
+    
+                c.NormalizeAll(pow2Table);
+    
+                lookupTable = new ECPoint[n];
+                lookupTable[0] = c.Infinity;
+
+                for (int bit = minWidth - 1; bit >= 0; --bit)
+                {
+                    ECPoint pow2 = pow2Table[bit];
+
+                    int step = 1 << bit;
+                    for (int i = step; i < n; i += (step << 1))
+                    {
+                        lookupTable[i] = lookupTable[i - step].Add(pow2);
+                    }
+                }
+
+                c.NormalizeAll(lookupTable);
+
+                info.PreComp = lookupTable;
+                info.Width = minWidth;
+
+                c.SetPreCompInfo(p, PRECOMP_NAME, info);
+            }
+
+            return info;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/GlvMultiplier.cs b/crypto/src/math/ec/multiplier/GlvMultiplier.cs
new file mode 100644
index 000000000..f19049474
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/GlvMultiplier.cs
@@ -0,0 +1,40 @@
+using System;
+
+using Org.BouncyCastle.Math.EC.Endo;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public class GlvMultiplier
+        :   AbstractECMultiplier
+    {
+        protected readonly ECCurve curve;
+        protected readonly GlvEndomorphism glvEndomorphism;
+
+        public GlvMultiplier(ECCurve curve, GlvEndomorphism glvEndomorphism)
+        {
+            if (curve == null || curve.Order == null)
+                throw new ArgumentException("Need curve with known group order", "curve");
+
+            this.curve = curve;
+            this.glvEndomorphism = glvEndomorphism;
+        }
+
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            if (!curve.Equals(p.Curve))
+                throw new InvalidOperationException();
+
+            BigInteger n = p.Curve.Order;
+            BigInteger[] ab = glvEndomorphism.DecomposeScalar(k.Mod(n));
+            BigInteger a = ab[0], b = ab[1];
+
+            ECPointMap pointMap = glvEndomorphism.PointMap;
+            if (glvEndomorphism.HasEfficientPointMap)
+            {
+                return ECAlgorithms.ImplShamirsTrickWNaf(p, a, pointMap, b);
+            }
+
+            return ECAlgorithms.ImplShamirsTrickWNaf(p, a, pointMap.Map(p), b);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/MixedNafR2LMultiplier.cs b/crypto/src/math/ec/multiplier/MixedNafR2LMultiplier.cs
new file mode 100644
index 000000000..a4c201832
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/MixedNafR2LMultiplier.cs
@@ -0,0 +1,75 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    /**
+     * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm (right-to-left) using
+     * mixed coordinates.
+     */
+    public class MixedNafR2LMultiplier 
+        : AbstractECMultiplier
+    {
+        protected readonly int additionCoord, doublingCoord;
+
+        /**
+         * By default, addition will be done in Jacobian coordinates, and doubling will be done in
+         * Modified Jacobian coordinates (independent of the original coordinate system of each point).
+         */
+        public MixedNafR2LMultiplier()
+            : this(ECCurve.COORD_JACOBIAN, ECCurve.COORD_JACOBIAN_MODIFIED)
+        {
+        }
+
+        public MixedNafR2LMultiplier(int additionCoord, int doublingCoord)
+        {
+            this.additionCoord = additionCoord;
+            this.doublingCoord = doublingCoord;
+        }
+
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            ECCurve curveOrig = p.Curve;
+
+            ECCurve curveAdd = ConfigureCurve(curveOrig, additionCoord);
+            ECCurve curveDouble = ConfigureCurve(curveOrig, doublingCoord);
+
+            int[] naf = WNafUtilities.GenerateCompactNaf(k);
+
+            ECPoint Ra = curveAdd.Infinity;
+            ECPoint Td = curveDouble.ImportPoint(p);
+
+            int zeroes = 0;
+            for (int i = 0; i < naf.Length; ++i)
+            {
+                int ni = naf[i];
+                int digit = ni >> 16;
+                zeroes += ni & 0xFFFF;
+
+                Td = Td.TimesPow2(zeroes);
+
+                ECPoint Tj = curveAdd.ImportPoint(Td);
+                if (digit < 0)
+                {
+                    Tj = Tj.Negate();
+                }
+
+                Ra = Ra.Add(Tj);
+
+                zeroes = 1;
+            }
+
+            return curveOrig.ImportPoint(Ra);
+        }
+
+        protected virtual ECCurve ConfigureCurve(ECCurve c, int coord)
+        {
+            if (c.CoordinateSystem == coord)
+                return c;
+
+            if (!c.SupportsCoordinateSystem(coord))
+                throw new ArgumentException("Coordinate system " + coord + " not supported by this curve", "coord");
+
+            return c.Configure().SetCoordinateSystem(coord).Create();
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/MontgomeryLadderMultiplier.cs b/crypto/src/math/ec/multiplier/MontgomeryLadderMultiplier.cs
new file mode 100644
index 000000000..e2470a383
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/MontgomeryLadderMultiplier.cs
@@ -0,0 +1,25 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public class MontgomeryLadderMultiplier 
+        : AbstractECMultiplier
+    {
+        /**
+         * Montgomery ladder.
+         */
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            ECPoint[] R = new ECPoint[]{ p.Curve.Infinity, p };
+
+            int n = k.BitLength;
+            int i = n;
+            while (--i >= 0)
+            {
+                int b = k.TestBit(i) ? 1 : 0;
+                int bp = 1 - b;
+                R[bp] = R[bp].Add(R[b]);
+                R[b] = R[b].Twice();
+            }
+            return R[0];
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/NafL2RMultiplier.cs b/crypto/src/math/ec/multiplier/NafL2RMultiplier.cs
new file mode 100644
index 000000000..ac80cf905
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/NafL2RMultiplier.cs
@@ -0,0 +1,30 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    /**
+     * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm (left-to-right).
+     */
+    public class NafL2RMultiplier
+        : AbstractECMultiplier
+    {
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            int[] naf = WNafUtilities.GenerateCompactNaf(k);
+
+            ECPoint addP = p.Normalize(), subP = addP.Negate();
+
+            ECPoint R = p.Curve.Infinity;
+
+            int i = naf.Length;
+            while (--i >= 0)
+            {
+                int ni = naf[i];
+                int digit = ni >> 16, zeroes = ni & 0xFFFF;
+
+                R = R.TwicePlus(digit < 0 ? subP : addP);
+                R = R.TimesPow2(zeroes);
+            }
+
+            return R;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/NafR2LMultiplier.cs b/crypto/src/math/ec/multiplier/NafR2LMultiplier.cs
new file mode 100644
index 000000000..1fa69fae8
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/NafR2LMultiplier.cs
@@ -0,0 +1,31 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    /**
+     * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm (right-to-left).
+     */
+    public class NafR2LMultiplier 
+        : AbstractECMultiplier
+    {
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            int[] naf = WNafUtilities.GenerateCompactNaf(k);
+
+            ECPoint R0 = p.Curve.Infinity, R1 = p;
+
+            int zeroes = 0;
+            for (int i = 0; i < naf.Length; ++i)
+            {
+                int ni = naf[i];
+                int digit = ni >> 16;
+                zeroes += ni & 0xFFFF;
+
+                R1 = R1.TimesPow2(zeroes);
+                R0 = R0.Add(digit < 0 ? R1.Negate() : R1);
+
+                zeroes = 1;
+            }
+
+            return R0;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/PreCompInfo.cs b/crypto/src/math/ec/multiplier/PreCompInfo.cs
index d379508c8..5c3289286 100644
--- a/crypto/src/math/ec/multiplier/PreCompInfo.cs
+++ b/crypto/src/math/ec/multiplier/PreCompInfo.cs
@@ -5,7 +5,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier
 	* algorithms. Used as a Memento (see GOF patterns) for
 	* <code>WNafMultiplier</code>.
 	*/
-	internal interface PreCompInfo
+	public interface PreCompInfo
 	{
 	}
 }
diff --git a/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs b/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
index cdccffc2d..4848ada39 100644
--- a/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
@@ -1,30 +1,11 @@
 namespace Org.BouncyCastle.Math.EC.Multiplier
 {
-	internal class ReferenceMultiplier
-		: ECMultiplier
-	{
-		/**
-		* Simple shift-and-add multiplication. Serves as reference implementation
-		* to verify (possibly faster) implementations in
-		* {@link org.bouncycastle.math.ec.ECPoint ECPoint}.
-		* 
-		* @param p The point to multiply.
-		* @param k The factor by which to multiply.
-		* @return The result of the point multiplication <code>k * p</code>.
-		*/
-		public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
-		{
-			ECPoint q = p.Curve.Infinity;
-			int t = k.BitLength;
-			for (int i = 0; i < t; i++)
-			{
-				if (k.TestBit(i))
-				{
-					q = q.Add(p);
-				}
-				p = p.Twice();
-			}
-			return q;
-		}
-	}
+    public class ReferenceMultiplier
+        : AbstractECMultiplier
+    {
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            return ECAlgorithms.ReferenceMultiply(p, k);
+        }
+    }
 }
diff --git a/crypto/src/math/ec/multiplier/WNafL2RMultiplier.cs b/crypto/src/math/ec/multiplier/WNafL2RMultiplier.cs
new file mode 100644
index 000000000..f671f6a5c
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/WNafL2RMultiplier.cs
@@ -0,0 +1,98 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    /**
+    * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+    * algorithm.
+    */
+    public class WNafL2RMultiplier
+        : AbstractECMultiplier
+    {
+        /**
+         * 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>.
+         */
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            // Clamp the window width in the range [2, 16]
+            int width = System.Math.Max(2, System.Math.Min(16, GetWindowSize(k.BitLength)));
+
+            WNafPreCompInfo wnafPreCompInfo = WNafUtilities.Precompute(p, width, true);
+            ECPoint[] preComp = wnafPreCompInfo.PreComp;
+            ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg;
+
+            int[] wnaf = WNafUtilities.GenerateCompactWindowNaf(width, k);
+
+            ECPoint R = p.Curve.Infinity;
+
+            int i = wnaf.Length;
+
+            /*
+             * NOTE: We try to optimize the first window using the precomputed points to substitute an
+             * addition for 2 or more doublings.
+             */
+            if (i > 1)
+            {
+                int wi = wnaf[--i];
+                int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+                int n = System.Math.Abs(digit);
+                ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+
+                // Optimization can only be used for values in the lower half of the table
+                if ((n << 2) < (1 << width))
+                {
+                    int highest = LongArray.BitLengths[n];
+
+                    // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting?
+                    int scale = width - highest;
+                    int lowBits = n ^ (1 << (highest - 1));
+
+                    int i1 = ((1 << (width - 1)) - 1);
+                    int i2 = (lowBits << scale) + 1;
+                    R = table[i1 >> 1].Add(table[i2 >> 1]);
+
+                    zeroes -= scale;
+
+                    //Console.WriteLine("Optimized: 2^" + scale + " * " + n + " = " + i1 + " + " + i2);
+                }
+                else
+                {
+                    R = table[n >> 1];
+                }
+
+                R = R.TimesPow2(zeroes);
+            }
+
+            while (i > 0)
+            {
+                int wi = wnaf[--i];
+                int digit = wi >> 16, zeroes = wi & 0xFFFF;
+
+                int n = System.Math.Abs(digit);
+                ECPoint[] table = digit < 0 ? preCompNeg : preComp;
+                ECPoint r = table[n >> 1];
+
+                R = R.TwicePlus(r);
+                R = R.TimesPow2(zeroes);
+            }
+
+            return R;
+        }
+
+        /**
+         * Determine window width to use for a scalar multiplication of the given size.
+         * 
+         * @param bits the bit-length of the scalar to multiply by
+         * @return the window size to use
+         */
+        protected virtual int GetWindowSize(int bits)
+        {
+            return WNafUtilities.GetWindowSize(bits);
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/WNafPreCompInfo.cs b/crypto/src/math/ec/multiplier/WNafPreCompInfo.cs
index d9305dace..7e0a73154 100644
--- a/crypto/src/math/ec/multiplier/WNafPreCompInfo.cs
+++ b/crypto/src/math/ec/multiplier/WNafPreCompInfo.cs
@@ -1,46 +1,46 @@
 namespace Org.BouncyCastle.Math.EC.Multiplier
 {
-	/**
-	* Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
-	* algorithm.
-	*/
-	internal class WNafPreCompInfo
-		: 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;
+    /**
+    * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+    * algorithm.
+    */
+    public class WNafPreCompInfo
+        : PreCompInfo 
+    {
+        /**
+         * Array holding the precomputed <code>ECPoint</code>s used for a Window
+         * NAF multiplication.
+         */
+        protected ECPoint[] m_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;
+        /**
+         * Array holding the negations of the precomputed <code>ECPoint</code>s used
+         * for a Window NAF multiplication.
+         */
+        protected ECPoint[] m_preCompNeg = null;
 
-		internal ECPoint[] GetPreComp()
-		{
-			return preComp;
-		}
+        /**
+         * Holds an <code>ECPoint</code> representing Twice(this). Used for the
+         * Window NAF multiplication to create or extend the precomputed values.
+         */
+        protected ECPoint m_twice = null;
 
-		internal void SetPreComp(ECPoint[] preComp)
-		{
-			this.preComp = preComp;
-		}
+        public virtual ECPoint[] PreComp
+        {
+            get { return m_preComp; }
+            set { this.m_preComp = value; }
+        }
 
-		internal ECPoint GetTwiceP()
-		{
-			return twiceP;
-		}
+        public virtual ECPoint[] PreCompNeg
+        {
+            get { return m_preCompNeg; }
+            set { this.m_preCompNeg = value; }
+        }
 
-		internal void SetTwiceP(ECPoint twiceThis)
-		{
-			this.twiceP = twiceThis;
-		}
-	}
+        public virtual ECPoint Twice
+        {
+            get { return m_twice; }
+            set { this.m_twice = value; }
+        }
+    }
 }
diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs
new file mode 100644
index 000000000..865b9073e
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs
@@ -0,0 +1,469 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public abstract class WNafUtilities
+    {
+        public static readonly string PRECOMP_NAME = "bc_wnaf";
+
+        private static readonly int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 };
+
+        private static readonly byte[] EMPTY_BYTES = new byte[0];
+        private static readonly int[] EMPTY_INTS = new int[0];
+
+        public static int[] GenerateCompactNaf(BigInteger k)
+        {
+            if ((k.BitLength >> 16) != 0)
+                throw new ArgumentException("must have bitlength < 2^16", "k");
+            if (k.SignValue == 0)
+                return EMPTY_INTS;
+
+            BigInteger _3k = k.ShiftLeft(1).Add(k);
+
+            int bits = _3k.BitLength;
+            int[] naf = new int[bits >> 1];
+
+            BigInteger diff = _3k.Xor(k);
+
+            int highBit = bits - 1, length = 0, zeroes = 0;
+            for (int i = 1; i < highBit; ++i)
+            {
+                if (!diff.TestBit(i))
+                {
+                    ++zeroes;
+                    continue;
+                }
+
+                int digit = k.TestBit(i) ? -1 : 1;
+                naf[length++] = (digit << 16) | zeroes;
+                zeroes = 1;
+                ++i;
+            }
+
+            naf[length++] = (1 << 16) | zeroes;
+
+            if (naf.Length > length)
+            {
+                naf = Trim(naf, length);
+            }
+
+            return naf;
+        }
+
+        public static int[] GenerateCompactWindowNaf(int width, BigInteger k)
+        {
+            if (width == 2)
+            {
+                return GenerateCompactNaf(k);
+            }
+
+            if (width < 2 || width > 16)
+                throw new ArgumentException("must be in the range [2, 16]", "width");
+            if ((k.BitLength >> 16) != 0)
+                throw new ArgumentException("must have bitlength < 2^16", "k");
+            if (k.SignValue == 0)
+                return EMPTY_INTS;
+
+            int[] wnaf = new int[k.BitLength / width + 1];
+
+            // 2^width and a mask and sign bit set accordingly
+            int pow2 = 1 << width;
+            int mask = pow2 - 1;
+            int sign = pow2 >> 1;
+
+            bool carry = false;
+            int length = 0, pos = 0;
+
+            while (pos <= k.BitLength)
+            {
+                if (k.TestBit(pos) == carry)
+                {
+                    ++pos;
+                    continue;
+                }
+
+                k = k.ShiftRight(pos);
+
+                int digit = k.IntValue & mask;
+                if (carry)
+                {
+                    ++digit;
+                }
+
+                carry = (digit & sign) != 0;
+                if (carry)
+                {
+                    digit -= pow2;
+                }
+
+                int zeroes = length > 0 ? pos - 1 : pos;
+                wnaf[length++] = (digit << 16) | zeroes;
+                pos = width;
+            }
+
+            // Reduce the WNAF array to its actual length
+            if (wnaf.Length > length)
+            {
+                wnaf = Trim(wnaf, length);
+            }
+
+            return wnaf;
+        }
+
+        public static byte[] GenerateJsf(BigInteger g, BigInteger h)
+        {
+            int digits = System.Math.Max(g.BitLength, h.BitLength) + 1;
+            byte[] jsf = new byte[digits];
+
+            BigInteger k0 = g, k1 = h;
+            int j = 0, d0 = 0, d1 = 0;
+
+            int offset = 0;
+            while ((d0 | d1) != 0 || k0.BitLength > offset || k1.BitLength > offset)
+            {
+                int n0 = ((int)((uint)k0.IntValue >> offset) + d0) & 7;
+                int n1 = ((int)((uint)k1.IntValue >> offset) + d1) & 7;
+
+                int u0 = n0 & 1;
+                if (u0 != 0)
+                {
+                    u0 -= (n0 & 2);
+                    if ((n0 + u0) == 4 && (n1 & 3) == 2)
+                    {
+                        u0 = -u0;
+                    }
+                }
+
+                int u1 = n1 & 1;
+                if (u1 != 0)
+                {
+                    u1 -= (n1 & 2);
+                    if ((n1 + u1) == 4 && (n0 & 3) == 2)
+                    {
+                        u1 = -u1;
+                    }
+                }
+
+                if ((d0 << 1) == 1 + u0)
+                {
+                    d0 ^= 1;
+                }
+                if ((d1 << 1) == 1 + u1)
+                {
+                    d1 ^= 1;
+                }
+
+                if (++offset == 30)
+                {
+                    offset = 0;
+                    k0 = k0.ShiftRight(30);
+                    k1 = k1.ShiftRight(30);
+                }
+
+                jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF));
+            }
+
+            // Reduce the JSF array to its actual length
+            if (jsf.Length > j)
+            {
+                jsf = Trim(jsf, j);
+            }
+
+            return jsf;
+        }
+
+        public static byte[] GenerateNaf(BigInteger k)
+        {
+            if (k.SignValue == 0)
+                return EMPTY_BYTES;
+
+            BigInteger _3k = k.ShiftLeft(1).Add(k);
+
+            int digits = _3k.BitLength - 1;
+            byte[] naf = new byte[digits];
+
+            BigInteger diff = _3k.Xor(k);
+
+            for (int i = 1; i < digits; ++i)
+            {
+                if (diff.TestBit(i))
+                {
+                    naf[i - 1] = (byte)(k.TestBit(i) ? -1 : 1);
+                    ++i;
+                }
+            }
+
+            naf[digits - 1] = 1;
+
+            return naf;
+        }
+
+        /**
+         * 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 = &amp;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 static byte[] GenerateWindowNaf(int width, BigInteger k)
+        {
+            if (width == 2)
+            {
+                return GenerateNaf(k);
+            }
+
+            if (width < 2 || width > 8)
+                throw new ArgumentException("must be in the range [2, 8]", "width");
+            if (k.SignValue == 0)
+                return EMPTY_BYTES;
+
+            byte[] wnaf = new byte[k.BitLength + 1];
+
+            // 2^width and a mask and sign bit set accordingly
+            int pow2 = 1 << width;
+            int mask = pow2 - 1;
+            int sign = pow2 >> 1;
+
+            bool carry = false;
+            int length = 0, pos = 0;
+
+            while (pos <= k.BitLength)
+            {
+                if (k.TestBit(pos) == carry)
+                {
+                    ++pos;
+                    continue;
+                }
+
+                k = k.ShiftRight(pos);
+
+                int digit = k.IntValue & mask;
+                if (carry)
+                {
+                    ++digit;
+                }
+
+                carry = (digit & sign) != 0;
+                if (carry)
+                {
+                    digit -= pow2;
+                }
+
+                length += (length > 0) ? pos - 1 : pos;
+                wnaf[length++] = (byte)digit;
+                pos = width;
+            }
+
+            // Reduce the WNAF array to its actual length
+            if (wnaf.Length > length)
+            {
+                wnaf = Trim(wnaf, length);
+            }
+        
+            return wnaf;
+        }
+
+        public static int GetNafWeight(BigInteger k)
+        {
+            if (k.SignValue == 0)
+                return 0;
+
+            BigInteger _3k = k.ShiftLeft(1).Add(k);
+            BigInteger diff = _3k.Xor(k);
+
+            return diff.BitCount;
+        }
+
+        public static WNafPreCompInfo GetWNafPreCompInfo(ECPoint p)
+        {
+            return GetWNafPreCompInfo(p.Curve.GetPreCompInfo(p, PRECOMP_NAME));
+        }
+
+        public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo)
+        {
+            if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo))
+            {
+                return (WNafPreCompInfo)preCompInfo;
+            }
+
+            return new WNafPreCompInfo();
+        }
+
+        /**
+         * Determine window width to use for a scalar multiplication of the given size.
+         * 
+         * @param bits the bit-length of the scalar to multiply by
+         * @return the window size to use
+         */
+        public static int GetWindowSize(int bits)
+        {
+            return GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS);
+        }
+
+        /**
+         * Determine window width to use for a scalar multiplication of the given size.
+         * 
+         * @param bits the bit-length of the scalar to multiply by
+         * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width
+         * @return the window size to use
+         */
+        public static int GetWindowSize(int bits, int[] windowSizeCutoffs)
+        {
+            int w = 0;
+            for (; w < windowSizeCutoffs.Length; ++w)
+            {
+                if (bits < windowSizeCutoffs[w])
+                {
+                    break;
+                }
+            }
+            return w + 2;
+        }
+
+        public static ECPoint MapPointWithPrecomp(ECPoint p, int width, bool includeNegated,
+            ECPointMap pointMap)
+        {
+            ECCurve c = p.Curve;
+            WNafPreCompInfo wnafPreCompP = Precompute(p, width, includeNegated);
+
+            ECPoint q = pointMap.Map(p);
+            WNafPreCompInfo wnafPreCompQ = GetWNafPreCompInfo(c.GetPreCompInfo(q, PRECOMP_NAME));
+
+            ECPoint twiceP = wnafPreCompP.Twice;
+            if (twiceP != null)
+            {
+                ECPoint twiceQ = pointMap.Map(twiceP);
+                wnafPreCompQ.Twice = twiceQ;
+            }
+
+            ECPoint[] preCompP = wnafPreCompP.PreComp;
+            ECPoint[] preCompQ = new ECPoint[preCompP.Length];
+            for (int i = 0; i < preCompP.Length; ++i)
+            {
+                preCompQ[i] = pointMap.Map(preCompP[i]);
+            }
+            wnafPreCompQ.PreComp = preCompQ;
+
+            if (includeNegated)
+            {
+                ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length];
+                for (int i = 0; i < preCompNegQ.Length; ++i)
+                {
+                    preCompNegQ[i] = preCompQ[i].Negate();
+                }
+                wnafPreCompQ.PreCompNeg = preCompNegQ;
+            }
+
+            c.SetPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ);
+
+            return q;
+        }
+
+        public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated)
+        {
+            ECCurve c = p.Curve;
+            WNafPreCompInfo wnafPreCompInfo = GetWNafPreCompInfo(c.GetPreCompInfo(p, PRECOMP_NAME));
+            
+            ECPoint[] preComp = wnafPreCompInfo.PreComp;
+            if (preComp == null)
+            {
+                preComp = new ECPoint[]{ p };
+            }
+
+            int preCompLen = preComp.Length;
+            int reqPreCompLen = 1 << System.Math.Max(0, width - 2);
+
+            if (preCompLen < reqPreCompLen)
+            {
+                preComp = ResizeTable(preComp, reqPreCompLen);
+                if (reqPreCompLen == 2)
+                {
+                    preComp[1] = preComp[0].ThreeTimes();
+                }
+                else
+                {
+                    ECPoint twiceP = wnafPreCompInfo.Twice;
+                    if (twiceP == null)
+                    {
+                        twiceP = preComp[0].Twice();
+                        wnafPreCompInfo.Twice = twiceP;
+                    }
+
+                    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]);
+                    }
+                }
+
+                /*
+                 * Having oft-used operands in affine form makes operations faster.
+                 */
+                c.NormalizeAll(preComp);
+            }
+
+            wnafPreCompInfo.PreComp = preComp;
+
+            if (includeNegated)
+            {
+                ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg;
+
+                int pos;
+                if (preCompNeg == null)
+                {
+                    pos = 0;
+                    preCompNeg = new ECPoint[reqPreCompLen]; 
+                }
+                else
+                {
+                    pos = preCompNeg.Length;
+                    if (pos < reqPreCompLen)
+                    {
+                        preCompNeg = ResizeTable(preCompNeg, reqPreCompLen);
+                    }
+                }
+
+                while (pos < reqPreCompLen)
+                {
+                    preCompNeg[pos] = preComp[pos].Negate();
+                    ++pos;
+                }
+
+                wnafPreCompInfo.PreCompNeg = preCompNeg;
+            }
+
+            c.SetPreCompInfo(p, PRECOMP_NAME, wnafPreCompInfo);
+
+            return wnafPreCompInfo;
+        }
+
+        private static byte[] Trim(byte[] a, int length)
+        {
+            byte[] result = new byte[length];
+            Array.Copy(a, 0, result, 0, result.Length);
+            return result;
+        }
+
+        private static int[] Trim(int[] a, int length)
+        {
+            int[] result = new int[length];
+            Array.Copy(a, 0, result, 0, result.Length);
+            return result;
+        }
+
+        private static ECPoint[] ResizeTable(ECPoint[] a, int length)
+        {
+            ECPoint[] result = new ECPoint[length];
+            Array.Copy(a, 0, result, 0, a.Length);
+            return result;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
index f1a605770..dda778eea 100644
--- a/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
+++ b/crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
@@ -4,117 +4,113 @@ using Org.BouncyCastle.Math.EC.Abc;
 
 namespace Org.BouncyCastle.Math.EC.Multiplier
 {
-	/**
-	* Class implementing the WTNAF (Window
-	* <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
-	*/
-	internal class WTauNafMultiplier
-		: ECMultiplier
-	{
-		/**
-		* Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
-		* by <code>k</code> using the reduced <code>&#964;</code>-adic NAF (RTNAF)
-		* method.
-		* @param p The F2mPoint 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 is F2mPoint))
-				throw new ArgumentException("Only F2mPoint can be used in WTauNafMultiplier");
+    /**
+    * Class implementing the WTNAF (Window
+    * <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
+    */
+    public class WTauNafMultiplier
+        : AbstractECMultiplier
+    {
+        // TODO Create WTauNafUtilities class and move various functionality into it
+        internal static readonly string PRECOMP_NAME = "bc_wtnaf";
 
-			F2mPoint p = (F2mPoint)point;
+        /**
+        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * by <code>k</code> using the reduced <code>&#964;</code>-adic NAF (RTNAF)
+        * method.
+        * @param p The F2mPoint to multiply.
+        * @param k The integer by which to multiply <code>k</code>.
+        * @return <code>p</code> multiplied by <code>k</code>.
+        */
+        protected override ECPoint MultiplyPositive(ECPoint point, BigInteger k)
+        {
+            if (!(point is F2mPoint))
+                throw new ArgumentException("Only F2mPoint can be used in WTauNafMultiplier");
 
-			F2mCurve curve = (F2mCurve) p.Curve;
-			int m = curve.M;
-			sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
-			sbyte mu = curve.GetMu();
-			BigInteger[] s = curve.GetSi();
+            F2mPoint p = (F2mPoint)point;
+            F2mCurve curve = (F2mCurve)p.Curve;
+            int m = curve.M;
+            sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
+            sbyte mu = curve.GetMu();
+            BigInteger[] s = curve.GetSi();
 
-			ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10);
+            ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10);
 
-			return MultiplyWTnaf(p, rho, preCompInfo, a, mu);
-		}
+            return MultiplyWTnaf(p, rho, curve.GetPreCompInfo(p, PRECOMP_NAME), a, mu);
+        }
 
-		/**
-		* Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
-		* by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code> using
-		* the <code>&#964;</code>-adic NAF (TNAF) method.
-		* @param p The F2mPoint to multiply.
-		* @param lambda The element <code>&#955;</code> of
-		* <code><b>Z</b>[&#964;]</code> of which to compute the
-		* <code>[&#964;]</code>-adic NAF.
-		* @return <code>p</code> multiplied by <code>&#955;</code>.
-		*/
-		private F2mPoint MultiplyWTnaf(F2mPoint p, ZTauElement lambda,
-			PreCompInfo preCompInfo, sbyte a, sbyte mu)
-		{
-			ZTauElement[] alpha;
-			if (a == 0)
-			{
-				alpha = Tnaf.Alpha0;
-			}
-			else
-			{
-				// a == 1
-				alpha = Tnaf.Alpha1;
-			}
+        /**
+        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code> using
+        * the <code>&#964;</code>-adic NAF (TNAF) method.
+        * @param p The F2mPoint to multiply.
+        * @param lambda The element <code>&#955;</code> of
+        * <code><b>Z</b>[&#964;]</code> of which to compute the
+        * <code>[&#964;]</code>-adic NAF.
+        * @return <code>p</code> multiplied by <code>&#955;</code>.
+        */
+        private F2mPoint MultiplyWTnaf(F2mPoint p, ZTauElement lambda,
+            PreCompInfo preCompInfo, sbyte a, sbyte mu)
+        {
+            ZTauElement[] alpha = (a == 0) ? Tnaf.Alpha0 : Tnaf.Alpha1;
 
-			BigInteger tw = Tnaf.GetTw(mu, Tnaf.Width);
+            BigInteger tw = Tnaf.GetTw(mu, Tnaf.Width);
 
-			sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width,
-				BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha);
+            sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width,
+                BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha);
 
-			return MultiplyFromWTnaf(p, u, preCompInfo);
-		}
-	    
-		/**
-		* Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
-		* by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
-		* using the window <code>&#964;</code>-adic NAF (TNAF) method, given the
-		* WTNAF of <code>&#955;</code>.
-		* @param p The F2mPoint to multiply.
-		* @param u The the WTNAF of <code>&#955;</code>..
-		* @return <code>&#955; * p</code>
-		*/
-		private static F2mPoint MultiplyFromWTnaf(F2mPoint p, sbyte[] u,
-			PreCompInfo preCompInfo)
-		{
-			F2mCurve curve = (F2mCurve)p.Curve;
-			sbyte a = (sbyte) curve.A.ToBigInteger().IntValue;
+            return MultiplyFromWTnaf(p, u, preCompInfo);
+        }
+        
+        /**
+        * Multiplies a {@link org.bouncycastle.math.ec.F2mPoint F2mPoint}
+        * by an element <code>&#955;</code> of <code><b>Z</b>[&#964;]</code>
+        * using the window <code>&#964;</code>-adic NAF (TNAF) method, given the
+        * WTNAF of <code>&#955;</code>.
+        * @param p The F2mPoint to multiply.
+        * @param u The the WTNAF of <code>&#955;</code>..
+        * @return <code>&#955; * p</code>
+        */
+        private static F2mPoint MultiplyFromWTnaf(F2mPoint p, sbyte[] u, PreCompInfo preCompInfo)
+        {
+            F2mCurve curve = (F2mCurve)p.Curve;
+            sbyte a = (sbyte)curve.A.ToBigInteger().IntValue;
 
-			F2mPoint[] pu;
-			if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
-			{
-				pu = Tnaf.GetPreComp(p, a);
-				p.SetPreCompInfo(new WTauNafPreCompInfo(pu));
-			}
-			else
-			{
-				pu = ((WTauNafPreCompInfo)preCompInfo).GetPreComp();
-			}
+            F2mPoint[] pu;
+            if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
+            {
+                pu = Tnaf.GetPreComp(p, a);
 
-			// q = infinity
-			F2mPoint q = (F2mPoint) p.Curve.Infinity;
-			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]]);
-					}
-				}
-			}
+                WTauNafPreCompInfo pre = new WTauNafPreCompInfo();
+                pre.PreComp = pu;
+                curve.SetPreCompInfo(p, PRECOMP_NAME, pre);
+            }
+            else
+            {
+                pu = ((WTauNafPreCompInfo)preCompInfo).PreComp;
+            }
 
-			return q;
-		}
-	}
+            // q = infinity
+            F2mPoint q = (F2mPoint)curve.Infinity;
+            for (int i = u.Length - 1; i >= 0; i--)
+            {
+                q = Tnaf.Tau(q);
+                sbyte ui = u[i];
+                if (ui != 0)
+                {
+                    if (ui > 0)
+                    {
+                        q = q.AddSimple(pu[ui]);
+                    }
+                    else
+                    {
+                        // u[i] < 0
+                        q = q.SubtractSimple(pu[-ui]);
+                    }
+                }
+            }
+
+            return q;
+        }
+    }
 }
diff --git a/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs b/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
index cede4a05d..3c18404c0 100644
--- a/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
+++ b/crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
@@ -1,41 +1,24 @@
 namespace Org.BouncyCastle.Math.EC.Multiplier
 {
-	/**
-	* Class holding precomputation data for the WTNAF (Window
-	* <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
-	*/
-	internal class WTauNafPreCompInfo
-		: PreCompInfo
-	{
-		/**
-		* Array holding the precomputed <code>F2mPoint</code>s used for the
-		* WTNAF multiplication in <code>
-		* {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
-		* WTauNafMultiplier.multiply()}</code>.
-		*/
-		private readonly F2mPoint[] preComp;
+    /**
+     * Class holding precomputation data for the WTNAF (Window
+     * <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
+     */
+    public class WTauNafPreCompInfo
+        : PreCompInfo
+    {
+        /**
+         * Array holding the precomputed <code>F2mPoint</code>s used for the
+         * WTNAF multiplication in <code>
+         * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+         * WTauNafMultiplier.multiply()}</code>.
+         */
+        protected F2mPoint[] m_preComp;
 
-		/**
-		* Constructor for <code>WTauNafPreCompInfo</code>
-		* @param preComp Array holding the precomputed <code>F2mPoint</code>s
-		* used for the WTNAF multiplication in <code>
-		* {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
-		* WTauNafMultiplier.multiply()}</code>.
-		*/
-		internal WTauNafPreCompInfo(F2mPoint[] preComp)
-		{
-			this.preComp = preComp;
-		}
-
-		/**
-		* @return the array holding the precomputed <code>F2mPoint</code>s
-		* used for the WTNAF multiplication in <code>
-		* {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
-		* WTauNafMultiplier.multiply()}</code>.
-		*/
-		internal F2mPoint[] GetPreComp()
-		{
-			return preComp;
-		}
-	}
+        public virtual F2mPoint[] PreComp
+        {
+            get { return m_preComp; }
+            set { this.m_preComp = value; }
+        }
+    }
 }
diff --git a/crypto/src/math/ec/multiplier/ZSignedDigitL2RMultiplier.cs b/crypto/src/math/ec/multiplier/ZSignedDigitL2RMultiplier.cs
new file mode 100644
index 000000000..554ac61b3
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/ZSignedDigitL2RMultiplier.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public class ZSignedDigitL2RMultiplier 
+        : AbstractECMultiplier
+    {
+        /**
+         * 'Zeroless' Signed Digit Left-to-Right.
+         */
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            ECPoint addP = p.Normalize(), subP = addP.Negate();
+
+            ECPoint R0 = addP;
+
+            int n = k.BitLength;
+            int s = k.GetLowestSetBit();
+
+            int i = n;
+            while (--i > s)
+            {
+                R0 = R0.TwicePlus(k.TestBit(i) ? addP : subP);
+            }
+
+            R0 = R0.TimesPow2(s);
+
+            return R0;
+        }
+    }
+}
diff --git a/crypto/src/math/ec/multiplier/ZSignedDigitR2LMultiplier.cs b/crypto/src/math/ec/multiplier/ZSignedDigitR2LMultiplier.cs
new file mode 100644
index 000000000..91c06cbb8
--- /dev/null
+++ b/crypto/src/math/ec/multiplier/ZSignedDigitR2LMultiplier.cs
@@ -0,0 +1,30 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+    public class ZSignedDigitR2LMultiplier 
+        : AbstractECMultiplier
+    {
+        /**
+         * 'Zeroless' Signed Digit Right-to-Left.
+         */
+        protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k)
+        {
+            ECPoint R0 = p.Curve.Infinity, R1 = p;
+
+            int n = k.BitLength;
+            int s = k.GetLowestSetBit();
+
+            R1 = R1.TimesPow2(s);
+
+            int i = s;
+            while (++i < n)
+            {
+                R0 = R0.Add(k.TestBit(i) ? R1 : R1.Negate());
+                R1 = R1.Twice();
+            }
+
+            R0 = R0.Add(R1);
+
+            return R0;
+        }
+    }
+}
diff --git a/crypto/src/math/field/FiniteFields.cs b/crypto/src/math/field/FiniteFields.cs
new file mode 100644
index 000000000..7b84569fe
--- /dev/null
+++ b/crypto/src/math/field/FiniteFields.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    public abstract class FiniteFields
+    {
+        internal static readonly IFiniteField GF_2 = new PrimeField(BigInteger.ValueOf(2));
+        internal static readonly IFiniteField GF_3 = new PrimeField(BigInteger.ValueOf(3));
+
+        public static IPolynomialExtensionField GetBinaryExtensionField(int[] exponents)
+        {
+            if (exponents[0] != 0)
+            {
+                throw new ArgumentException("Irreducible polynomials in GF(2) must have constant term", "exponents");
+            }
+            for (int i = 1; i < exponents.Length; ++i)
+            {
+                if (exponents[i] <= exponents[i - 1])
+                {
+                    throw new ArgumentException("Polynomial exponents must be montonically increasing", "exponents");
+                }
+            }
+
+            return new GenericPolynomialExtensionField(GF_2, new GF2Polynomial(exponents));
+        }
+
+    //    public static IPolynomialExtensionField GetTernaryExtensionField(Term[] terms)
+    //    {
+    //        return new GenericPolynomialExtensionField(GF_3, new GF3Polynomial(terms));
+    //    }
+
+        public static IFiniteField GetPrimeField(BigInteger characteristic)
+        {
+            int bitLength = characteristic.BitLength;
+            if (characteristic.SignValue <= 0 || bitLength < 2)
+            {
+                throw new ArgumentException("Must be >= 2", "characteristic");
+            }
+
+            if (bitLength < 3)
+            {
+                switch (characteristic.IntValue)
+                {
+                case 2:
+                    return GF_2;
+                case 3:
+                    return GF_3;
+                }
+            }
+
+            return new PrimeField(characteristic);
+        }
+    }
+}
diff --git a/crypto/src/math/field/GF2Polynomial.cs b/crypto/src/math/field/GF2Polynomial.cs
new file mode 100644
index 000000000..c062d508a
--- /dev/null
+++ b/crypto/src/math/field/GF2Polynomial.cs
@@ -0,0 +1,46 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    internal class GF2Polynomial
+        : IPolynomial
+    {
+        protected readonly int[] exponents;
+
+        internal GF2Polynomial(int[] exponents)
+        {
+            this.exponents = Arrays.Clone(exponents);
+        }
+
+        public virtual int Degree
+        {
+            get { return exponents[exponents.Length - 1]; }
+        }
+
+        public virtual int[] GetExponentsPresent()
+        {
+            return Arrays.Clone(exponents);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            GF2Polynomial other = obj as GF2Polynomial;
+            if (null == other)
+            {
+                return false;
+            }
+            return Arrays.AreEqual(exponents, other.exponents);
+        }
+
+        public override int GetHashCode()
+        {
+            return Arrays.GetHashCode(exponents);
+        }
+    }
+}
diff --git a/crypto/src/math/field/GenericPolynomialExtensionField.cs b/crypto/src/math/field/GenericPolynomialExtensionField.cs
new file mode 100644
index 000000000..13ef57165
--- /dev/null
+++ b/crypto/src/math/field/GenericPolynomialExtensionField.cs
@@ -0,0 +1,63 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    internal class GenericPolynomialExtensionField
+        : IPolynomialExtensionField
+    {
+        protected readonly IFiniteField subfield;
+        protected readonly IPolynomial minimalPolynomial;
+
+        internal GenericPolynomialExtensionField(IFiniteField subfield, IPolynomial polynomial)
+        {
+            this.subfield = subfield;
+            this.minimalPolynomial = polynomial;
+        }
+
+        public virtual BigInteger Characteristic
+        {
+            get { return subfield.Characteristic; }
+        }
+
+        public virtual int Dimension
+        {
+            get { return subfield.Dimension * minimalPolynomial.Degree; }
+        }
+
+        public virtual IFiniteField Subfield
+        {
+            get { return subfield; }
+        }
+
+        public virtual int Degree
+        {
+            get { return minimalPolynomial.Degree; }
+        }
+
+        public virtual IPolynomial MinimalPolynomial
+        {
+            get { return minimalPolynomial; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            GenericPolynomialExtensionField other = obj as GenericPolynomialExtensionField;
+            if (null == other)
+            {
+                return false;
+            }
+            return subfield.Equals(other.subfield) && minimalPolynomial.Equals(other.minimalPolynomial);
+        }
+
+        public override int GetHashCode()
+        {
+            return subfield.GetHashCode() ^ Integers.RotateLeft(minimalPolynomial.GetHashCode(), 16);
+        }
+    }
+}
diff --git a/crypto/src/math/field/IExtensionField.cs b/crypto/src/math/field/IExtensionField.cs
new file mode 100644
index 000000000..17f45c153
--- /dev/null
+++ b/crypto/src/math/field/IExtensionField.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    public interface IExtensionField
+        : IFiniteField
+    {
+        IFiniteField Subfield { get; }
+
+        int Degree { get; }
+    }
+}
diff --git a/crypto/src/math/field/IFiniteField.cs b/crypto/src/math/field/IFiniteField.cs
new file mode 100644
index 000000000..b618be74b
--- /dev/null
+++ b/crypto/src/math/field/IFiniteField.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    public interface IFiniteField
+    {
+        BigInteger Characteristic { get; }
+
+        int Dimension { get; }
+    }
+}
diff --git a/crypto/src/math/field/IPolynomial.cs b/crypto/src/math/field/IPolynomial.cs
new file mode 100644
index 000000000..ad6dfb662
--- /dev/null
+++ b/crypto/src/math/field/IPolynomial.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    public interface IPolynomial
+    {
+        int Degree { get; }
+
+        //BigInteger[] GetCoefficients();
+
+        int[] GetExponentsPresent();
+
+        //Term[] GetNonZeroTerms();
+    }
+}
diff --git a/crypto/src/math/field/IPolynomialExtensionField.cs b/crypto/src/math/field/IPolynomialExtensionField.cs
new file mode 100644
index 000000000..3818c1855
--- /dev/null
+++ b/crypto/src/math/field/IPolynomialExtensionField.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    public interface IPolynomialExtensionField
+        : IExtensionField
+    {
+        IPolynomial MinimalPolynomial { get; }
+    }
+}
diff --git a/crypto/src/math/field/PrimeField.cs b/crypto/src/math/field/PrimeField.cs
new file mode 100644
index 000000000..f6ba629d5
--- /dev/null
+++ b/crypto/src/math/field/PrimeField.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Math.Field
+{
+    internal class PrimeField
+        : IFiniteField
+    {
+        protected readonly BigInteger characteristic;
+
+        internal PrimeField(BigInteger characteristic)
+        {
+            this.characteristic = characteristic;
+        }
+
+        public virtual BigInteger Characteristic
+        {
+            get { return characteristic; }
+        }
+
+        public virtual int Dimension
+        {
+            get { return 1; }
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            PrimeField other = obj as PrimeField;
+            if (null == other)
+            {
+                return false;
+            }
+            return characteristic.Equals(other.characteristic);
+        }
+
+        public override int GetHashCode()
+        {
+            return characteristic.GetHashCode();
+        }
+    }
+}
diff --git a/crypto/src/ocsp/BasicOCSPResp.cs b/crypto/src/ocsp/BasicOCSPResp.cs
new file mode 100644
index 000000000..4253726bb
--- /dev/null
+++ b/crypto/src/ocsp/BasicOCSPResp.cs
@@ -0,0 +1,220 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	/// <remarks>
+	/// <code>
+	/// BasicOcspResponse ::= SEQUENCE {
+	///		tbsResponseData		ResponseData,
+	///		signatureAlgorithm	AlgorithmIdentifier,
+	///		signature			BIT STRING,
+	///		certs				[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
+	/// }
+	/// </code>
+	/// </remarks>
+	public class BasicOcspResp
+		: X509ExtensionBase
+	{
+		private readonly BasicOcspResponse	resp;
+		private readonly ResponseData		data;
+//		private readonly X509Certificate[]	chain;
+
+		public BasicOcspResp(
+			BasicOcspResponse resp)
+		{
+			this.resp = resp;
+			this.data = resp.TbsResponseData;
+		}
+
+		/// <returns>The DER encoding of the tbsResponseData field.</returns>
+		/// <exception cref="OcspException">In the event of an encoding error.</exception>
+		public byte[] GetTbsResponseData()
+		{
+			try
+			{
+				return data.GetDerEncoded();
+			}
+			catch (IOException e)
+			{
+				throw new OcspException("problem encoding tbsResponseData", e);
+			}
+		}
+
+		public int Version
+		{
+			get { return data.Version.Value.IntValue + 1; }
+		}
+
+		public RespID ResponderId
+		{
+			get { return new RespID(data.ResponderID); }
+		}
+
+		public DateTime ProducedAt
+		{
+			get { return data.ProducedAt.ToDateTime(); }
+		}
+
+		public SingleResp[] Responses
+		{
+			get
+			{
+				Asn1Sequence s = data.Responses;
+				SingleResp[] rs = new SingleResp[s.Count];
+
+				for (int i = 0; i != rs.Length; i++)
+				{
+					rs[i] = new SingleResp(SingleResponse.GetInstance(s[i]));
+				}
+
+				return rs;
+			}
+		}
+
+		public X509Extensions ResponseExtensions
+		{
+			get { return data.ResponseExtensions; }
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return ResponseExtensions;
+		}
+
+		public string SignatureAlgName
+		{
+			get { return OcspUtilities.GetAlgorithmName(resp.SignatureAlgorithm.ObjectID); }
+		}
+
+		public string SignatureAlgOid
+		{
+			get { return resp.SignatureAlgorithm.ObjectID.Id; }
+		}
+
+		[Obsolete("RespData class is no longer required as all functionality is available on this class")]
+		public RespData GetResponseData()
+		{
+			return new RespData(data);
+		}
+
+		public byte[] GetSignature()
+		{
+			return resp.Signature.GetBytes();
+		}
+
+		private IList GetCertList()
+		{
+			// load the certificates and revocation lists if we have any
+
+			IList certs = Platform.CreateArrayList();
+			Asn1Sequence s = resp.Certs;
+
+			if (s != null)
+			{
+				foreach (Asn1Encodable ae in s)
+				{
+					try
+					{
+						certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded()));
+					}
+					catch (IOException ex)
+					{
+						throw new OcspException("can't re-encode certificate!", ex);
+					}
+					catch (CertificateException ex)
+					{
+						throw new OcspException("can't re-encode certificate!", ex);
+					}
+				}
+			}
+
+			return certs;
+		}
+
+		public X509Certificate[] GetCerts()
+		{
+			IList certs = GetCertList();
+            X509Certificate[] result = new X509Certificate[certs.Count];
+            for (int i = 0; i < certs.Count; ++i)
+            {
+                result[i] = (X509Certificate)certs[i];
+            }
+            return result;
+		}
+
+		/// <returns>The certificates, if any, associated with the response.</returns>
+		/// <exception cref="OcspException">In the event of an encoding error.</exception>
+		public IX509Store GetCertificates(
+			string type)
+		{
+			try
+			{
+				return X509StoreFactory.Create(
+					"Certificate/" + type,
+					new X509CollectionStoreParameters(this.GetCertList()));
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("can't setup the CertStore", e);
+			}
+		}
+
+		/// <summary>
+		/// Verify the signature against the tbsResponseData object we contain.
+		/// </summary>
+		public bool Verify(
+			AsymmetricKeyParameter publicKey)
+		{
+			try
+			{
+				ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgName);
+				signature.Init(false, publicKey);
+				byte[] bs = data.GetDerEncoded();
+				signature.BlockUpdate(bs, 0, bs.Length);
+
+				return signature.VerifySignature(this.GetSignature());
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("exception processing sig: " + e, e);
+			}
+		}
+
+		/// <returns>The ASN.1 encoded representation of this object.</returns>
+		public byte[] GetEncoded()
+		{
+			return resp.GetEncoded();
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			BasicOcspResp other = obj as BasicOcspResp;
+
+			if (other == null)
+				return false;
+
+			return resp.Equals(other.resp);
+		}
+
+		public override int GetHashCode()
+		{
+			return resp.GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/ocsp/BasicOCSPRespGenerator.cs b/crypto/src/ocsp/BasicOCSPRespGenerator.cs
new file mode 100644
index 000000000..5ff4bd9cc
--- /dev/null
+++ b/crypto/src/ocsp/BasicOCSPRespGenerator.cs
@@ -0,0 +1,318 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	/**
+	 * Generator for basic OCSP response objects.
+	 */
+	public class BasicOcspRespGenerator
+	{
+		private readonly IList list = Platform.CreateArrayList();
+
+		private X509Extensions responseExtensions;
+		private RespID responderID;
+
+		private class ResponseObject
+		{
+			internal CertificateID         certId;
+			internal CertStatus            certStatus;
+			internal DerGeneralizedTime    thisUpdate;
+			internal DerGeneralizedTime    nextUpdate;
+			internal X509Extensions        extensions;
+
+			public ResponseObject(
+				CertificateID		certId,
+				CertificateStatus	certStatus,
+				DateTime			thisUpdate,
+				X509Extensions		extensions)
+				: this(certId, certStatus, new DerGeneralizedTime(thisUpdate), null, extensions)
+			{
+			}
+
+			public ResponseObject(
+				CertificateID		certId,
+				CertificateStatus	certStatus,
+				DateTime			thisUpdate,
+				DateTime			nextUpdate,
+				X509Extensions		extensions)
+				: this(certId, certStatus, new DerGeneralizedTime(thisUpdate), new DerGeneralizedTime(nextUpdate), extensions)
+			{
+			}
+
+			private ResponseObject(
+				CertificateID		certId,
+				CertificateStatus	certStatus,
+				DerGeneralizedTime	thisUpdate,
+				DerGeneralizedTime	nextUpdate,
+				X509Extensions		extensions)
+			{
+				this.certId = certId;
+
+				if (certStatus == null)
+				{
+					this.certStatus = new CertStatus();
+				}
+				else if (certStatus is UnknownStatus)
+				{
+					this.certStatus = new CertStatus(2, DerNull.Instance);
+				}
+				else
+				{
+					RevokedStatus rs = (RevokedStatus) certStatus;
+					CrlReason revocationReason = rs.HasRevocationReason
+						?	new CrlReason(rs.RevocationReason)
+						:	null;
+
+					this.certStatus = new CertStatus(
+						new RevokedInfo(new DerGeneralizedTime(rs.RevocationTime), revocationReason));
+				}
+
+				this.thisUpdate = thisUpdate;
+				this.nextUpdate = nextUpdate;
+
+				this.extensions = extensions;
+			}
+
+			public SingleResponse ToResponse()
+			{
+				return new SingleResponse(certId.ToAsn1Object(), certStatus, thisUpdate, nextUpdate, extensions);
+			}
+		}
+
+		/**
+		 * basic constructor
+		 */
+		public BasicOcspRespGenerator(
+			RespID responderID)
+		{
+			this.responderID = responderID;
+		}
+
+		/**
+		 * construct with the responderID to be the SHA-1 keyHash of the passed in public key.
+		 */
+		public BasicOcspRespGenerator(
+			AsymmetricKeyParameter publicKey)
+		{
+			this.responderID = new RespID(publicKey);
+		}
+
+		/**
+		 * Add a response for a particular Certificate ID.
+		 *
+		 * @param certID certificate ID details
+		 * @param certStatus status of the certificate - null if okay
+		 */
+		public void AddResponse(
+			CertificateID		certID,
+			CertificateStatus	certStatus)
+		{
+			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null));
+		}
+
+		/**
+		 * Add a response for a particular Certificate ID.
+		 *
+		 * @param certID certificate ID details
+		 * @param certStatus status of the certificate - null if okay
+		 * @param singleExtensions optional extensions
+		 */
+		public void AddResponse(
+			CertificateID		certID,
+			CertificateStatus	certStatus,
+			X509Extensions		singleExtensions)
+		{
+			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, singleExtensions));
+		}
+
+		/**
+		 * Add a response for a particular Certificate ID.
+		 *
+		 * @param certID certificate ID details
+		 * @param nextUpdate date when next update should be requested
+		 * @param certStatus status of the certificate - null if okay
+		 * @param singleExtensions optional extensions
+		 */
+		public void AddResponse(
+			CertificateID		certID,
+			CertificateStatus	certStatus,
+			DateTime			nextUpdate,
+			X509Extensions		singleExtensions)
+		{
+			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, nextUpdate, singleExtensions));
+		}
+
+		/**
+		 * Add a response for a particular Certificate ID.
+		 *
+		 * @param certID certificate ID details
+		 * @param thisUpdate date this response was valid on
+		 * @param nextUpdate date when next update should be requested
+		 * @param certStatus status of the certificate - null if okay
+		 * @param singleExtensions optional extensions
+		 */
+		public void AddResponse(
+			CertificateID		certID,
+			CertificateStatus	certStatus,
+			DateTime			thisUpdate,
+			DateTime			nextUpdate,
+			X509Extensions		singleExtensions)
+		{
+			list.Add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions));
+		}
+
+		/**
+		 * Set the extensions for the response.
+		 *
+		 * @param responseExtensions the extension object to carry.
+		 */
+		public void SetResponseExtensions(
+			X509Extensions responseExtensions)
+		{
+			this.responseExtensions = responseExtensions;
+		}
+
+		private BasicOcspResp GenerateResponse(
+			string					signatureName,
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate[]		chain,
+			DateTime				producedAt,
+			SecureRandom			random)
+		{
+			DerObjectIdentifier signingAlgorithm;
+			try
+			{
+				signingAlgorithm = OcspUtilities.GetAlgorithmOid(signatureName);
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("unknown signing algorithm specified", e);
+			}
+
+			Asn1EncodableVector responses = new Asn1EncodableVector();
+
+			foreach (ResponseObject respObj in list)
+			{
+				try
+				{
+					responses.Add(respObj.ToResponse());
+				}
+				catch (Exception e)
+				{
+					throw new OcspException("exception creating Request", e);
+				}
+			}
+
+			ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new DerGeneralizedTime(producedAt), new DerSequence(responses), responseExtensions);
+
+			ISigner sig = null;
+
+			try
+			{
+				sig = SignerUtilities.GetSigner(signatureName);
+
+				if (random != null)
+				{
+					sig.Init(true, new ParametersWithRandom(privateKey, random));
+				}
+				else
+				{
+					sig.Init(true, privateKey);
+				}
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("exception creating signature: " + e, e);
+			}
+
+			DerBitString bitSig = null;
+
+			try
+			{
+				byte[] encoded = tbsResp.GetDerEncoded();
+				sig.BlockUpdate(encoded, 0, encoded.Length);
+
+				bitSig = new DerBitString(sig.GenerateSignature());
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("exception processing TBSRequest: " + e, e);
+			}
+
+			AlgorithmIdentifier sigAlgId = OcspUtilities.GetSigAlgID(signingAlgorithm);
+
+			DerSequence chainSeq = null;
+			if (chain != null && chain.Length > 0)
+			{
+				Asn1EncodableVector v = new Asn1EncodableVector();
+				try
+				{
+					for (int i = 0; i != chain.Length; i++)
+					{
+						v.Add(
+							X509CertificateStructure.GetInstance(
+								Asn1Object.FromByteArray(chain[i].GetEncoded())));
+					}
+				}
+				catch (IOException e)
+				{
+					throw new OcspException("error processing certs", e);
+				}
+				catch (CertificateEncodingException e)
+				{
+					throw new OcspException("error encoding certs", e);
+				}
+
+				chainSeq = new DerSequence(v);
+			}
+
+			return new BasicOcspResp(new BasicOcspResponse(tbsResp, sigAlgId, bitSig, chainSeq));
+		}
+
+		public BasicOcspResp Generate(
+			string					signingAlgorithm,
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate[]		chain,
+			DateTime				thisUpdate)
+		{
+			return Generate(signingAlgorithm, privateKey, chain, thisUpdate, null);
+		}
+
+		public BasicOcspResp Generate(
+			string					signingAlgorithm,
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate[]		chain,
+			DateTime				producedAt,
+			SecureRandom			random)
+		{
+			if (signingAlgorithm == null)
+			{
+				throw new ArgumentException("no signing algorithm specified");
+			}
+
+			return GenerateResponse(signingAlgorithm, privateKey, chain, producedAt, random);
+		}
+
+		/**
+		 * Return an IEnumerable of the signature names supported by the generator.
+		 *
+		 * @return an IEnumerable containing recognised names.
+		 */
+		public IEnumerable SignatureAlgNames
+		{
+			get { return OcspUtilities.AlgNames; }
+		}
+	}
+}
diff --git a/crypto/src/ocsp/CertificateID.cs b/crypto/src/ocsp/CertificateID.cs
new file mode 100644
index 000000000..a8f035759
--- /dev/null
+++ b/crypto/src/ocsp/CertificateID.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public class CertificateID
+	{
+		public const string HashSha1 = "1.3.14.3.2.26";
+
+		private readonly CertID id;
+
+		public CertificateID(
+			CertID id)
+		{
+			if (id == null)
+				throw new ArgumentNullException("id");
+
+			this.id = id;
+		}
+
+		/**
+		 * create from an issuer certificate and the serial number of the
+		 * certificate it signed.
+		 * @exception OcspException if any problems occur creating the id fields.
+		 */
+		public CertificateID(
+			string			hashAlgorithm,
+			X509Certificate	issuerCert,
+			BigInteger		serialNumber)
+		{
+			AlgorithmIdentifier hashAlg = new AlgorithmIdentifier(
+				new DerObjectIdentifier(hashAlgorithm), DerNull.Instance);
+
+			this.id = CreateCertID(hashAlg, issuerCert, new DerInteger(serialNumber));
+		}
+
+		public string HashAlgOid
+		{
+			get { return id.HashAlgorithm.ObjectID.Id; }
+		}
+
+		public byte[] GetIssuerNameHash()
+		{
+			return id.IssuerNameHash.GetOctets();
+		}
+
+		public byte[] GetIssuerKeyHash()
+		{
+			return id.IssuerKeyHash.GetOctets();
+		}
+
+		/**
+		 * return the serial number for the certificate associated
+		 * with this request.
+		 */
+		public BigInteger SerialNumber
+		{
+			get { return id.SerialNumber.Value; }
+		}
+
+		public bool MatchesIssuer(
+			X509Certificate	issuerCert)
+		{
+			return CreateCertID(id.HashAlgorithm, issuerCert, id.SerialNumber).Equals(id);
+		}
+
+		public CertID ToAsn1Object()
+		{
+			return id;
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			CertificateID other = obj as CertificateID;
+
+			if (other == null)
+				return false;
+
+			return id.ToAsn1Object().Equals(other.id.ToAsn1Object());
+		}
+
+		public override int GetHashCode()
+		{
+			return id.ToAsn1Object().GetHashCode();
+		}
+
+
+		/**
+		 * Create a new CertificateID for a new serial number derived from a previous one
+		 * calculated for the same CA certificate.
+		 *
+		 * @param original the previously calculated CertificateID for the CA.
+		 * @param newSerialNumber the serial number for the new certificate of interest.
+		 *
+		 * @return a new CertificateID for newSerialNumber
+		 */
+		public static CertificateID DeriveCertificateID(CertificateID original, BigInteger newSerialNumber)
+		{
+			return new CertificateID(new CertID(original.id.HashAlgorithm, original.id.IssuerNameHash,
+				original.id.IssuerKeyHash, new DerInteger(newSerialNumber)));
+		}
+
+        private static CertID CreateCertID(
+			AlgorithmIdentifier	hashAlg,
+			X509Certificate		issuerCert,
+			DerInteger			serialNumber)
+		{
+			try
+			{
+				String hashAlgorithm = hashAlg.ObjectID.Id;
+
+				X509Name issuerName = PrincipalUtilities.GetSubjectX509Principal(issuerCert);
+				byte[] issuerNameHash = DigestUtilities.CalculateDigest(
+					hashAlgorithm, issuerName.GetEncoded());
+
+				AsymmetricKeyParameter issuerKey = issuerCert.GetPublicKey();
+				SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKey);
+				byte[] issuerKeyHash = DigestUtilities.CalculateDigest(
+					hashAlgorithm, info.PublicKeyData.GetBytes());
+
+				return new CertID(hashAlg, new DerOctetString(issuerNameHash),
+					new DerOctetString(issuerKeyHash), serialNumber);
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("problem creating ID: " + e, e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/ocsp/CertificateStatus.cs b/crypto/src/ocsp/CertificateStatus.cs
new file mode 100644
index 000000000..edfcc2582
--- /dev/null
+++ b/crypto/src/ocsp/CertificateStatus.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public abstract class CertificateStatus
+	{
+		public static readonly CertificateStatus Good = null;
+	}
+}
diff --git a/crypto/src/ocsp/OCSPException.cs b/crypto/src/ocsp/OCSPException.cs
index 44eed9f32..db53e559a 100644
--- a/crypto/src/ocsp/OCSPException.cs
+++ b/crypto/src/ocsp/OCSPException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Ocsp
 {
-	public class OcspException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class OcspException
 		: Exception
 	{
 		public OcspException()
diff --git a/crypto/src/ocsp/OCSPReq.cs b/crypto/src/ocsp/OCSPReq.cs
new file mode 100644
index 000000000..84808e50a
--- /dev/null
+++ b/crypto/src/ocsp/OCSPReq.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	/**
+	 * <pre>
+	 * OcspRequest     ::=     SEQUENCE {
+	 *       tbsRequest                  TBSRequest,
+	 *       optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+	 *
+	 *   TBSRequest      ::=     SEQUENCE {
+	 *       version             [0]     EXPLICIT Version DEFAULT v1,
+	 *       requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+	 *       requestList                 SEQUENCE OF Request,
+	 *       requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+	 *
+	 *   Signature       ::=     SEQUENCE {
+	 *       signatureAlgorithm      AlgorithmIdentifier,
+	 *       signature               BIT STRING,
+	 *       certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+	 *
+	 *   Version         ::=             INTEGER  {  v1(0) }
+	 *
+	 *   Request         ::=     SEQUENCE {
+	 *       reqCert                     CertID,
+	 *       singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+	 *
+	 *   CertID          ::=     SEQUENCE {
+	 *       hashAlgorithm       AlgorithmIdentifier,
+	 *       issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
+	 *       issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
+	 *       serialNumber        CertificateSerialNumber }
+	 * </pre>
+	 */
+	public class OcspReq
+		: X509ExtensionBase
+	{
+		private OcspRequest req;
+
+		public OcspReq(
+			OcspRequest req)
+		{
+			this.req = req;
+		}
+
+		public OcspReq(
+			byte[] req)
+			: this(new Asn1InputStream(req))
+		{
+		}
+
+		public OcspReq(
+			Stream inStr)
+			: this(new Asn1InputStream(inStr))
+		{
+		}
+
+		private OcspReq(
+			Asn1InputStream aIn)
+		{
+			try
+			{
+				this.req = OcspRequest.GetInstance(aIn.ReadObject());
+			}
+			catch (ArgumentException e)
+			{
+				throw new IOException("malformed request: " + e.Message);
+			}
+			catch (InvalidCastException e)
+			{
+				throw new IOException("malformed request: " + e.Message);
+			}
+		}
+
+		/**
+		 * Return the DER encoding of the tbsRequest field.
+		 * @return DER encoding of tbsRequest
+		 * @throws OcspException in the event of an encoding error.
+		 */
+		public byte[] GetTbsRequest()
+		{
+			try
+			{
+				return req.TbsRequest.GetEncoded();
+			}
+			catch (IOException e)
+			{
+				throw new OcspException("problem encoding tbsRequest", e);
+			}
+		}
+
+		public int Version
+		{
+			get { return req.TbsRequest.Version.Value.IntValue + 1; }
+		}
+
+		public GeneralName RequestorName
+		{
+			get { return GeneralName.GetInstance(req.TbsRequest.RequestorName); }
+		}
+
+		public Req[] GetRequestList()
+		{
+			Asn1Sequence seq = req.TbsRequest.RequestList;
+			Req[] requests = new Req[seq.Count];
+
+			for (int i = 0; i != requests.Length; i++)
+			{
+				requests[i] = new Req(Request.GetInstance(seq[i]));
+			}
+
+			return requests;
+		}
+
+		public X509Extensions RequestExtensions
+		{
+			get { return X509Extensions.GetInstance(req.TbsRequest.RequestExtensions); }
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return RequestExtensions;
+		}
+
+		/**
+		 * return the object identifier representing the signature algorithm
+		 */
+		public string SignatureAlgOid
+		{
+			get
+			{
+				if (!this.IsSigned)
+					return null;
+
+				return req.OptionalSignature.SignatureAlgorithm.ObjectID.Id;
+			}
+		}
+
+		public byte[] GetSignature()
+		{
+			if (!this.IsSigned)
+				return null;
+
+			return req.OptionalSignature.SignatureValue.GetBytes();
+		}
+
+		private IList GetCertList()
+		{
+			// load the certificates if we have any
+
+			IList certs = Platform.CreateArrayList();
+			Asn1Sequence s = req.OptionalSignature.Certs;
+
+			if (s != null)
+			{
+				foreach (Asn1Encodable ae in s)
+				{
+					try
+					{
+						certs.Add(new X509CertificateParser().ReadCertificate(ae.GetEncoded()));
+					}
+					catch (Exception e)
+					{
+						throw new OcspException("can't re-encode certificate!", e);
+					}
+				}
+			}
+
+			return certs;
+		}
+
+		public X509Certificate[] GetCerts()
+		{
+			if (!this.IsSigned)
+				return null;
+
+			IList certs = this.GetCertList();
+            X509Certificate[] result = new X509Certificate[certs.Count];
+            for (int i = 0; i < certs.Count; ++i)
+            {
+                result[i] = (X509Certificate)certs[i];
+            }
+            return result;
+		}
+
+		/**
+		 * If the request is signed return a possibly empty CertStore containing the certificates in the
+		 * request. If the request is not signed the method returns null.
+		 *
+		 * @return null if not signed, a CertStore otherwise
+		 * @throws OcspException
+		 */
+		public IX509Store GetCertificates(
+			string type)
+		{
+			if (!this.IsSigned)
+				return null;
+
+			try
+			{
+				return X509StoreFactory.Create(
+					"Certificate/" + type,
+					new X509CollectionStoreParameters(this.GetCertList()));
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("can't setup the CertStore", e);
+			}
+		}
+
+		/**
+		 * Return whether or not this request is signed.
+		 *
+		 * @return true if signed false otherwise.
+		 */
+		public bool IsSigned
+		{
+			get { return req.OptionalSignature != null; }
+		}
+
+		/**
+		 * Verify the signature against the TBSRequest object we contain.
+		 */
+		public bool Verify(
+			AsymmetricKeyParameter publicKey)
+		{
+			if (!this.IsSigned)
+				throw new OcspException("attempt to Verify signature on unsigned object");
+
+			try
+			{
+				ISigner signature = SignerUtilities.GetSigner(this.SignatureAlgOid);
+
+				signature.Init(false, publicKey);
+
+				byte[] encoded = req.TbsRequest.GetEncoded();
+
+				signature.BlockUpdate(encoded, 0, encoded.Length);
+
+				return signature.VerifySignature(this.GetSignature());
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("exception processing sig: " + e, e);
+			}
+		}
+
+		/**
+		 * return the ASN.1 encoded representation of this object.
+		 */
+		public byte[] GetEncoded()
+		{
+			return req.GetEncoded();
+		}
+	}
+}
diff --git a/crypto/src/ocsp/OCSPReqGenerator.cs b/crypto/src/ocsp/OCSPReqGenerator.cs
new file mode 100644
index 000000000..8032a4598
--- /dev/null
+++ b/crypto/src/ocsp/OCSPReqGenerator.cs
@@ -0,0 +1,243 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public class OcspReqGenerator
+	{
+		private IList			list = Platform.CreateArrayList();
+		private GeneralName		requestorName = null;
+		private X509Extensions	requestExtensions = null;
+
+		private class RequestObject
+		{
+			internal CertificateID certId;
+			internal X509Extensions extensions;
+
+			public RequestObject(
+				CertificateID	certId,
+				X509Extensions	extensions)
+			{
+				this.certId = certId;
+				this.extensions = extensions;
+			}
+
+			public Request ToRequest()
+			{
+				return new Request(certId.ToAsn1Object(), extensions);
+			}
+		}
+
+		/**
+		 * Add a request for the given CertificateID.
+		 *
+		 * @param certId certificate ID of interest
+		 */
+		public void AddRequest(
+			CertificateID certId)
+		{
+			list.Add(new RequestObject(certId, null));
+		}
+
+		/**
+		 * Add a request with extensions
+		 *
+		 * @param certId certificate ID of interest
+		 * @param singleRequestExtensions the extensions to attach to the request
+		 */
+		public void AddRequest(
+			CertificateID   certId,
+			X509Extensions  singleRequestExtensions)
+		{
+			list.Add(new RequestObject(certId, singleRequestExtensions));
+		}
+
+		/**
+		* Set the requestor name to the passed in X509Principal
+		*
+		* @param requestorName a X509Principal representing the requestor name.
+		*/
+		public void SetRequestorName(
+		    X509Name requestorName)
+		{
+		    try
+		    {
+		        this.requestorName = new GeneralName(GeneralName.DirectoryName, requestorName);
+		    }
+		    catch (Exception e)
+		    {
+		        throw new ArgumentException("cannot encode principal", e);
+		    }
+		}
+
+		public void SetRequestorName(
+			GeneralName requestorName)
+		{
+			this.requestorName = requestorName;
+		}
+
+		public void SetRequestExtensions(
+			X509Extensions requestExtensions)
+		{
+			this.requestExtensions = requestExtensions;
+		}
+
+		private OcspReq GenerateRequest(
+			DerObjectIdentifier		signingAlgorithm,
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate[]		chain,
+			SecureRandom			random)
+		{
+			Asn1EncodableVector requests = new Asn1EncodableVector();
+
+			foreach (RequestObject reqObj in list)
+			{
+				try
+				{
+					requests.Add(reqObj.ToRequest());
+				}
+				catch (Exception e)
+				{
+					throw new OcspException("exception creating Request", e);
+				}
+			}
+
+			TbsRequest tbsReq = new TbsRequest(requestorName, new DerSequence(requests), requestExtensions);
+
+			ISigner sig = null;
+			Signature signature = null;
+
+			if (signingAlgorithm != null)
+			{
+				if (requestorName == null)
+				{
+					throw new OcspException("requestorName must be specified if request is signed.");
+				}
+
+				try
+				{
+					sig = SignerUtilities.GetSigner(signingAlgorithm.Id);
+					if (random != null)
+					{
+						sig.Init(true, new ParametersWithRandom(privateKey, random));
+					}
+					else
+					{
+						sig.Init(true, privateKey);
+					}
+				}
+				catch (Exception e)
+				{
+					throw new OcspException("exception creating signature: " + e, e);
+				}
+
+				DerBitString bitSig = null;
+
+				try
+				{
+					byte[] encoded = tbsReq.GetEncoded();
+					sig.BlockUpdate(encoded, 0, encoded.Length);
+
+					bitSig = new DerBitString(sig.GenerateSignature());
+				}
+				catch (Exception e)
+				{
+					throw new OcspException("exception processing TBSRequest: " + e, e);
+				}
+
+				AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, DerNull.Instance);
+
+				if (chain != null && chain.Length > 0)
+				{
+					Asn1EncodableVector v = new Asn1EncodableVector();
+					try
+					{
+						for (int i = 0; i != chain.Length; i++)
+						{
+							v.Add(
+								X509CertificateStructure.GetInstance(
+									Asn1Object.FromByteArray(chain[i].GetEncoded())));
+						}
+					}
+					catch (IOException e)
+					{
+						throw new OcspException("error processing certs", e);
+					}
+					catch (CertificateEncodingException e)
+					{
+						throw new OcspException("error encoding certs", e);
+					}
+
+					signature = new Signature(sigAlgId, bitSig, new DerSequence(v));
+				}
+				else
+				{
+					signature = new Signature(sigAlgId, bitSig);
+				}
+			}
+
+			return new OcspReq(new OcspRequest(tbsReq, signature));
+		}
+
+		/**
+		 * Generate an unsigned request
+		 *
+		 * @return the OcspReq
+		 * @throws OcspException
+		 */
+		public OcspReq Generate()
+		{
+			return GenerateRequest(null, null, null, null);
+		}
+
+		public OcspReq Generate(
+			string					signingAlgorithm,
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate[]		chain)
+		{
+			return Generate(signingAlgorithm, privateKey, chain, null);
+		}
+
+		public OcspReq Generate(
+			string					signingAlgorithm,
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate[]		chain,
+			SecureRandom			random)
+		{
+			if (signingAlgorithm == null)
+				throw new ArgumentException("no signing algorithm specified");
+
+			try
+			{
+				DerObjectIdentifier oid = OcspUtilities.GetAlgorithmOid(signingAlgorithm);
+
+				return GenerateRequest(oid, privateKey, chain, random);
+			}
+			catch (ArgumentException)
+			{
+				throw new ArgumentException("unknown signing algorithm specified: " + signingAlgorithm);
+			}
+		}
+
+		/**
+		 * Return an IEnumerable of the signature names supported by the generator.
+		 *
+		 * @return an IEnumerable containing recognised names.
+		 */
+		public IEnumerable SignatureAlgNames
+		{
+			get { return OcspUtilities.AlgNames; }
+		}
+	}
+}
diff --git a/crypto/src/ocsp/OCSPResp.cs b/crypto/src/ocsp/OCSPResp.cs
new file mode 100644
index 000000000..dc99c6a9a
--- /dev/null
+++ b/crypto/src/ocsp/OCSPResp.cs
@@ -0,0 +1,100 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public class OcspResp
+	{
+		private OcspResponse resp;
+
+		public OcspResp(
+			OcspResponse resp)
+		{
+			this.resp = resp;
+		}
+
+		public OcspResp(
+			byte[] resp)
+			: this(new Asn1InputStream(resp))
+		{
+		}
+
+		public OcspResp(
+			Stream inStr)
+			: this(new Asn1InputStream(inStr))
+		{
+		}
+
+		private OcspResp(
+			Asn1InputStream aIn)
+		{
+			try
+			{
+				this.resp = OcspResponse.GetInstance(aIn.ReadObject());
+			}
+			catch (Exception e)
+			{
+				throw new IOException("malformed response: " + e.Message, e);
+			}
+		}
+
+		public int Status
+		{
+			get { return this.resp.ResponseStatus.Value.IntValue; }
+		}
+
+		public object GetResponseObject()
+		{
+			ResponseBytes rb = this.resp.ResponseBytes;
+
+			if (rb == null)
+				return null;
+
+			if (rb.ResponseType.Equals(OcspObjectIdentifiers.PkixOcspBasic))
+			{
+				try
+				{
+					return new BasicOcspResp(
+						BasicOcspResponse.GetInstance(
+							Asn1Object.FromByteArray(rb.Response.GetOctets())));
+				}
+				catch (Exception e)
+				{
+					throw new OcspException("problem decoding object: " + e, e);
+				}
+			}
+
+			return rb.Response;
+		}
+
+		/**
+		* return the ASN.1 encoded representation of this object.
+		*/
+		public byte[] GetEncoded()
+		{
+			return resp.GetEncoded();
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			OcspResp other = obj as OcspResp;
+
+			if (other == null)
+				return false;
+
+			return resp.Equals(other.resp);
+		}
+
+		public override int GetHashCode()
+		{
+			return resp.GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/ocsp/OCSPRespGenerator.cs b/crypto/src/ocsp/OCSPRespGenerator.cs
new file mode 100644
index 000000000..e0eb9ae90
--- /dev/null
+++ b/crypto/src/ocsp/OCSPRespGenerator.cs
@@ -0,0 +1,54 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	/**
+	 * base generator for an OCSP response - at the moment this only supports the
+	 * generation of responses containing BasicOCSP responses.
+	 */
+	public class OCSPRespGenerator
+	{
+		public const int Successful			= 0;	// Response has valid confirmations
+		public const int MalformedRequest	= 1;	// Illegal confirmation request
+		public const int InternalError		= 2;	// Internal error in issuer
+		public const int TryLater			= 3;	// Try again later
+		// (4) is not used
+		public const int SigRequired		= 5;	// Must sign the request
+		public const int Unauthorized		= 6;	// Request unauthorized
+
+		public OcspResp Generate(
+			int     status,
+			object  response)
+		{
+			if (response == null)
+			{
+				return new OcspResp(new OcspResponse(new OcspResponseStatus(status),null));
+			}
+			if (response is BasicOcspResp)
+			{
+				BasicOcspResp r = (BasicOcspResp)response;
+				Asn1OctetString octs;
+
+				try
+				{
+					octs = new DerOctetString(r.GetEncoded());
+				}
+				catch (Exception e)
+				{
+					throw new OcspException("can't encode object.", e);
+				}
+
+				ResponseBytes rb = new ResponseBytes(
+					OcspObjectIdentifiers.PkixOcspBasic, octs);
+
+				return new OcspResp(new OcspResponse(
+					new OcspResponseStatus(status), rb));
+			}
+
+			throw new OcspException("unknown response object");
+		}
+	}
+}
diff --git a/crypto/src/ocsp/OCSPRespStatus.cs b/crypto/src/ocsp/OCSPRespStatus.cs
new file mode 100644
index 000000000..9c00c7035
--- /dev/null
+++ b/crypto/src/ocsp/OCSPRespStatus.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	[Obsolete("Use version with correct spelling 'OcspRespStatus'")]
+	public abstract class OcscpRespStatus : OcspRespStatus
+	{
+	}
+
+	public abstract class OcspRespStatus
+	{
+		/**
+		 * note 4 is not used.
+		 */
+		public const int Successful = 0;		// --Response has valid confirmations
+		public const int MalformedRequest = 1;	// --Illegal confirmation request
+		public const int InternalError = 2;		// --Internal error in issuer
+		public const int TryLater = 3;			// --Try again later
+		public const int SigRequired = 5;		// --Must sign the request
+		public const int Unauthorized = 6;		//  --Request unauthorized
+	}
+}
diff --git a/crypto/src/ocsp/OCSPUtil.cs b/crypto/src/ocsp/OCSPUtil.cs
index dad56dc39..cbc1e95f5 100644
--- a/crypto/src/ocsp/OCSPUtil.cs
+++ b/crypto/src/ocsp/OCSPUtil.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
@@ -92,9 +91,9 @@ namespace Org.BouncyCastle.Ocsp
 		internal static DerObjectIdentifier GetAlgorithmOid(
 			string algorithmName)
 		{
-			algorithmName = algorithmName.ToUpperInvariant();
+			algorithmName = Platform.ToUpperInvariant(algorithmName);
 
-			if (algorithms.Contains(algorithmName))
+            if (algorithms.Contains(algorithmName))
 			{
 				return (DerObjectIdentifier)algorithms[algorithmName];
 			}
diff --git a/crypto/src/ocsp/Req.cs b/crypto/src/ocsp/Req.cs
new file mode 100644
index 000000000..68fd9f12a
--- /dev/null
+++ b/crypto/src/ocsp/Req.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public class Req
+		: X509ExtensionBase
+	{
+		private Request req;
+
+		public Req(
+			Request req)
+		{
+			this.req = req;
+		}
+
+		public CertificateID GetCertID()
+		{
+			return new CertificateID(req.ReqCert);
+		}
+
+		public X509Extensions SingleRequestExtensions
+		{
+			get { return req.SingleRequestExtensions; }
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return SingleRequestExtensions;
+		}
+	}
+}
diff --git a/crypto/src/ocsp/RespData.cs b/crypto/src/ocsp/RespData.cs
new file mode 100644
index 000000000..105726ca7
--- /dev/null
+++ b/crypto/src/ocsp/RespData.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public class RespData
+		: X509ExtensionBase
+	{
+		internal readonly ResponseData data;
+
+		public RespData(
+			ResponseData data)
+		{
+			this.data = data;
+		}
+
+		public int Version
+		{
+			get { return data.Version.Value.IntValue + 1; }
+		}
+
+		public RespID GetResponderId()
+		{
+			return new RespID(data.ResponderID);
+		}
+
+		public DateTime ProducedAt
+		{
+			get { return data.ProducedAt.ToDateTime(); }
+		}
+
+		public SingleResp[] GetResponses()
+		{
+			Asn1Sequence s = data.Responses;
+			SingleResp[] rs = new SingleResp[s.Count];
+
+			for (int i = 0; i != rs.Length; i++)
+			{
+				rs[i] = new SingleResp(SingleResponse.GetInstance(s[i]));
+			}
+
+			return rs;
+		}
+
+		public X509Extensions ResponseExtensions
+		{
+			get { return data.ResponseExtensions; }
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return ResponseExtensions;
+		}
+	}
+}
diff --git a/crypto/src/ocsp/RespID.cs b/crypto/src/ocsp/RespID.cs
new file mode 100644
index 000000000..3238b26da
--- /dev/null
+++ b/crypto/src/ocsp/RespID.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	/**
+	 * Carrier for a ResponderID.
+	 */
+	public class RespID
+	{
+		internal readonly ResponderID id;
+
+		public RespID(
+			ResponderID id)
+		{
+			this.id = id;
+		}
+
+		public RespID(
+			X509Name name)
+		{
+	        this.id = new ResponderID(name);
+		}
+
+		public RespID(
+			AsymmetricKeyParameter publicKey)
+		{
+			try
+			{
+				SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+				byte[] keyHash = DigestUtilities.CalculateDigest("SHA1", info.PublicKeyData.GetBytes());
+
+				this.id = new ResponderID(new DerOctetString(keyHash));
+			}
+			catch (Exception e)
+			{
+				throw new OcspException("problem creating ID: " + e, e);
+			}
+		}
+
+		public ResponderID ToAsn1Object()
+		{
+			return id;
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			RespID other = obj as RespID;
+
+			if (other == null)
+				return false;
+
+			return id.Equals(other.id);
+		}
+
+		public override int GetHashCode()
+		{
+			return id.GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/ocsp/RevokedStatus.cs b/crypto/src/ocsp/RevokedStatus.cs
new file mode 100644
index 000000000..6e5ad1b26
--- /dev/null
+++ b/crypto/src/ocsp/RevokedStatus.cs
@@ -0,0 +1,58 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	/**
+	 * wrapper for the RevokedInfo object
+	 */
+	public class RevokedStatus
+		: CertificateStatus
+	{
+		internal readonly RevokedInfo info;
+
+		public RevokedStatus(
+			RevokedInfo info)
+		{
+			this.info = info;
+		}
+
+		public RevokedStatus(
+			DateTime	revocationDate,
+			int			reason)
+		{
+			this.info = new RevokedInfo(new DerGeneralizedTime(revocationDate), new CrlReason(reason));
+		}
+
+		public DateTime RevocationTime
+		{
+			get { return info.RevocationTime.ToDateTime(); }
+		}
+
+		public bool HasRevocationReason
+		{
+			get { return (info.RevocationReason != null); }
+		}
+
+		/**
+		 * return the revocation reason. Note: this field is optional, test for it
+		 * with hasRevocationReason() first.
+		 * @exception InvalidOperationException if a reason is asked for and none is avaliable
+		 */
+		public int RevocationReason
+		{
+			get
+			{
+				if (info.RevocationReason == null)
+				{
+					throw new InvalidOperationException("attempt to get a reason where none is available");
+				}
+
+				return info.RevocationReason.Value.IntValue;
+			}
+		}
+	}
+}
diff --git a/crypto/src/ocsp/SingleResp.cs b/crypto/src/ocsp/SingleResp.cs
new file mode 100644
index 000000000..b8979c538
--- /dev/null
+++ b/crypto/src/ocsp/SingleResp.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public class SingleResp
+		: X509ExtensionBase
+	{
+		internal readonly SingleResponse resp;
+
+		public SingleResp(
+			SingleResponse resp)
+		{
+			this.resp = resp;
+		}
+
+		public CertificateID GetCertID()
+		{
+			return new CertificateID(resp.CertId);
+		}
+
+		/**
+		 * Return the status object for the response - null indicates good.
+		 *
+		 * @return the status object for the response, null if it is good.
+		 */
+		public object GetCertStatus()
+		{
+			CertStatus s = resp.CertStatus;
+
+			if (s.TagNo == 0)
+			{
+				return null;            // good
+			}
+
+			if (s.TagNo == 1)
+			{
+				return new RevokedStatus(RevokedInfo.GetInstance(s.Status));
+			}
+
+			return new UnknownStatus();
+		}
+
+		public DateTime ThisUpdate
+		{
+			get { return resp.ThisUpdate.ToDateTime(); }
+		}
+
+		/**
+		* return the NextUpdate value - note: this is an optional field so may
+		* be returned as null.
+		*
+		* @return nextUpdate, or null if not present.
+		*/
+		public DateTimeObject NextUpdate
+		{
+			get
+			{
+				return resp.NextUpdate == null
+					?	null
+					:	new DateTimeObject(resp.NextUpdate.ToDateTime());
+			}
+		}
+
+		public X509Extensions SingleExtensions
+		{
+			get { return resp.SingleExtensions; }
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return SingleExtensions;
+		}
+	}
+}
diff --git a/crypto/src/ocsp/UnknownStatus.cs b/crypto/src/ocsp/UnknownStatus.cs
new file mode 100644
index 000000000..c0f7a3a64
--- /dev/null
+++ b/crypto/src/ocsp/UnknownStatus.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	/**
+	 * wrapper for the UnknownInfo object
+	 */
+	public class UnknownStatus
+		: CertificateStatus
+	{
+		public UnknownStatus()
+		{
+		}
+	}
+}
diff --git a/crypto/src/openpgp/IStreamGenerator.cs b/crypto/src/openpgp/IStreamGenerator.cs
new file mode 100644
index 000000000..379213a66
--- /dev/null
+++ b/crypto/src/openpgp/IStreamGenerator.cs
@@ -0,0 +1,7 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	public interface IStreamGenerator
+	{
+		void Close();
+	}
+}
diff --git a/crypto/src/openpgp/PGPKeyRing.cs b/crypto/src/openpgp/PGPKeyRing.cs
new file mode 100644
index 000000000..6426f3f25
--- /dev/null
+++ b/crypto/src/openpgp/PGPKeyRing.cs
@@ -0,0 +1,79 @@
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	public abstract class PgpKeyRing
+		: PgpObject
+	{
+		internal PgpKeyRing()
+		{
+		}
+
+		internal static TrustPacket ReadOptionalTrustPacket(
+			BcpgInputStream bcpgInput)
+		{
+			return (bcpgInput.NextPacketTag() == PacketTag.Trust)
+				?	(TrustPacket) bcpgInput.ReadPacket()
+				:	null;
+		}
+
+		internal static IList ReadSignaturesAndTrust(
+			BcpgInputStream	bcpgInput)
+		{
+			try
+			{
+				IList sigList = Platform.CreateArrayList();
+
+				while (bcpgInput.NextPacketTag() == PacketTag.Signature)
+				{
+					SignaturePacket signaturePacket = (SignaturePacket) bcpgInput.ReadPacket();
+					TrustPacket trustPacket = ReadOptionalTrustPacket(bcpgInput);
+
+					sigList.Add(new PgpSignature(signaturePacket, trustPacket));
+				}
+
+				return sigList;
+			}
+			catch (PgpException e)
+			{
+				throw new IOException("can't create signature object: " + e.Message, e);
+			}
+		}
+
+		internal static void ReadUserIDs(
+			BcpgInputStream	bcpgInput,
+			out IList       ids,
+			out IList       idTrusts,
+			out IList       idSigs)
+		{
+			ids = Platform.CreateArrayList();
+            idTrusts = Platform.CreateArrayList();
+            idSigs = Platform.CreateArrayList();
+
+			while (bcpgInput.NextPacketTag() == PacketTag.UserId
+				|| bcpgInput.NextPacketTag() == PacketTag.UserAttribute)
+			{
+				Packet obj = bcpgInput.ReadPacket();
+				if (obj is UserIdPacket)
+				{
+					UserIdPacket id = (UserIdPacket)obj;
+					ids.Add(id.GetId());
+				}
+				else
+				{
+					UserAttributePacket user = (UserAttributePacket) obj;
+					ids.Add(new PgpUserAttributeSubpacketVector(user.GetSubpackets()));
+				}
+
+				idTrusts.Add(
+					ReadOptionalTrustPacket(bcpgInput));
+
+				idSigs.Add(
+					ReadSignaturesAndTrust(bcpgInput));
+			}
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PGPObject.cs b/crypto/src/openpgp/PGPObject.cs
new file mode 100644
index 000000000..d38276cb6
--- /dev/null
+++ b/crypto/src/openpgp/PGPObject.cs
@@ -0,0 +1,9 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	public abstract class PgpObject
+	{
+		internal PgpObject()
+		{
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs b/crypto/src/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs
new file mode 100644
index 000000000..9d56c8bc3
--- /dev/null
+++ b/crypto/src/openpgp/PGPUserAttributeSubpacketVectorGenerator.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Attr;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	public class PgpUserAttributeSubpacketVectorGenerator
+	{
+		private IList list = Platform.CreateArrayList();
+
+		public virtual void SetImageAttribute(
+			ImageAttrib.Format	imageType,
+			byte[]				imageData)
+		{
+			if (imageData == null)
+				throw new ArgumentException("attempt to set null image", "imageData");
+
+			list.Add(new ImageAttrib(imageType, imageData));
+		}
+
+        public virtual PgpUserAttributeSubpacketVector Generate()
+		{
+            UserAttributeSubpacket[] a = new UserAttributeSubpacket[list.Count];
+            for (int i = 0; i < list.Count; ++i)
+            {
+                a[i] = (UserAttributeSubpacket)list[i];
+            }
+            return new PgpUserAttributeSubpacketVector(a);
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PgpCompressedData.cs b/crypto/src/openpgp/PgpCompressedData.cs
new file mode 100644
index 000000000..e64a17c9c
--- /dev/null
+++ b/crypto/src/openpgp/PgpCompressedData.cs
@@ -0,0 +1,50 @@
+using System.IO;
+
+using Org.BouncyCastle.Apache.Bzip2;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Compressed data objects</remarks>
+    public class PgpCompressedData
+		: PgpObject
+    {
+        private readonly CompressedDataPacket data;
+
+		public PgpCompressedData(
+            BcpgInputStream bcpgInput)
+        {
+            data = (CompressedDataPacket) bcpgInput.ReadPacket();
+        }
+
+		/// <summary>The algorithm used for compression</summary>
+        public CompressionAlgorithmTag Algorithm
+        {
+			get { return data.Algorithm; }
+        }
+
+		/// <summary>Get the raw input stream contained in the object.</summary>
+        public Stream GetInputStream()
+        {
+            return data.GetInputStream();
+        }
+
+		/// <summary>Return an uncompressed input stream which allows reading of the compressed data.</summary>
+        public Stream GetDataStream()
+        {
+            switch (Algorithm)
+            {
+				case CompressionAlgorithmTag.Uncompressed:
+					return GetInputStream();
+				case CompressionAlgorithmTag.Zip:
+					return new ZInputStream(GetInputStream(), true);
+                case CompressionAlgorithmTag.ZLib:
+					return new ZInputStream(GetInputStream());
+				case CompressionAlgorithmTag.BZip2:
+					return new CBZip2InputStream(GetInputStream());
+                default:
+                    throw new PgpException("can't recognise compression algorithm: " + Algorithm);
+            }
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpCompressedDataGenerator.cs b/crypto/src/openpgp/PgpCompressedDataGenerator.cs
index c758ecb05..7f4ec8e53 100644
--- a/crypto/src/openpgp/PgpCompressedDataGenerator.cs
+++ b/crypto/src/openpgp/PgpCompressedDataGenerator.cs
@@ -155,7 +155,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			{
 				if (dOut != pkOut)
 				{
-                    dOut.Dispose();
+					dOut.Close();
 					dOut.Flush();
 				}
 
@@ -174,13 +174,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			{
 			}
 
-            protected override void Dispose(bool disposing)
-            {
-                if (disposing)
-                {
-                    Finish();
-                }
-            }
+			public override void Close()
+			{
+				Finish();
+			}
 		}
 
 		private class SafeZOutputStream : ZOutputStream
@@ -190,14 +187,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			{
 			}
 
-            protected override void Dispose(bool disposing)
-            {
-                if (disposing)
-                {
-                    Finish();
-                    End();
-                }
-            }
+			public override void Close()
+			{
+				Finish();
+				End();
+			}
 		}
 	}
 }
diff --git a/crypto/src/openpgp/PgpDataValidationException.cs b/crypto/src/openpgp/PgpDataValidationException.cs
index 74674da59..aab5165b2 100644
--- a/crypto/src/openpgp/PgpDataValidationException.cs
+++ b/crypto/src/openpgp/PgpDataValidationException.cs
@@ -5,6 +5,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 	/// <remarks>
 	/// Thrown if the IV at the start of a data stream indicates the wrong key is being used.
 	/// </remarks>
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
     public class PgpDataValidationException
         : PgpException
 	{
diff --git a/crypto/src/openpgp/PgpEncryptedData.cs b/crypto/src/openpgp/PgpEncryptedData.cs
new file mode 100644
index 000000000..0d237b56c
--- /dev/null
+++ b/crypto/src/openpgp/PgpEncryptedData.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+    public abstract class PgpEncryptedData
+    {
+		internal class TruncatedStream
+			: BaseInputStream
+		{
+			private const int LookAheadSize = 22;
+			private const int LookAheadBufSize = 512;
+			private const int LookAheadBufLimit = LookAheadBufSize - LookAheadSize;
+
+			private readonly Stream inStr;
+			private readonly byte[] lookAhead = new byte[LookAheadBufSize];
+			private int bufStart, bufEnd;
+
+			internal TruncatedStream(
+				Stream inStr)
+			{
+				int numRead = Streams.ReadFully(inStr, lookAhead, 0, lookAhead.Length);
+
+				if (numRead < LookAheadSize)
+					throw new EndOfStreamException();
+
+				this.inStr = inStr;
+				this.bufStart = 0;
+				this.bufEnd = numRead - LookAheadSize;
+			}
+
+			private int FillBuffer()
+			{
+				if (bufEnd < LookAheadBufLimit)
+					return 0;
+
+				Debug.Assert(bufStart == LookAheadBufLimit);
+				Debug.Assert(bufEnd == LookAheadBufLimit);
+
+				Array.Copy(lookAhead, LookAheadBufLimit, lookAhead, 0, LookAheadSize);
+				bufEnd = Streams.ReadFully(inStr, lookAhead, LookAheadSize, LookAheadBufLimit);
+				bufStart = 0;
+				return bufEnd;
+			}
+
+			public override int ReadByte()
+			{
+				if (bufStart < bufEnd)
+					return lookAhead[bufStart++];
+
+				if (FillBuffer() < 1)
+					return -1;
+
+				return lookAhead[bufStart++];
+			}
+
+			public override int Read(byte[] buf, int off, int len)
+			{
+				int avail = bufEnd - bufStart;
+
+				int pos = off;
+				while (len > avail)
+				{
+					Array.Copy(lookAhead, bufStart, buf, pos, avail);
+
+					bufStart += avail;
+					pos += avail;
+					len -= avail;
+
+					if ((avail = FillBuffer()) < 1)
+						return pos - off;
+				}
+
+				Array.Copy(lookAhead, bufStart, buf, pos, len);
+				bufStart += len;
+
+				return pos + len - off;;
+			}
+
+			internal byte[] GetLookAhead()
+			{
+				byte[] temp = new byte[LookAheadSize];
+				Array.Copy(lookAhead, bufStart, temp, 0, LookAheadSize);
+				return temp;
+			}
+		}
+
+		internal InputStreamPacket	encData;
+        internal Stream				encStream;
+        internal TruncatedStream	truncStream;
+
+		internal PgpEncryptedData(
+            InputStreamPacket encData)
+        {
+            this.encData = encData;
+        }
+
+		/// <summary>Return the raw input stream for the data stream.</summary>
+        public virtual Stream GetInputStream()
+        {
+            return encData.GetInputStream();
+        }
+
+		/// <summary>Return true if the message is integrity protected.</summary>
+		/// <returns>True, if there is a modification detection code namespace associated
+		/// with this stream.</returns>
+        public bool IsIntegrityProtected()
+        {
+			return encData is SymmetricEncIntegrityPacket;
+        }
+
+		/// <summary>Note: This can only be called after the message has been read.</summary>
+		/// <returns>True, if the message verifies, false otherwise</returns>
+        public bool Verify()
+        {
+            if (!IsIntegrityProtected())
+                throw new PgpException("data not integrity protected.");
+
+			DigestStream dIn = (DigestStream) encStream;
+
+			//
+            // make sure we are at the end.
+            //
+            while (encStream.ReadByte() >= 0)
+            {
+				// do nothing
+            }
+
+			//
+            // process the MDC packet
+            //
+			byte[] lookAhead = truncStream.GetLookAhead();
+
+			IDigest hash = dIn.ReadDigest();
+			hash.BlockUpdate(lookAhead, 0, 2);
+			byte[] digest = DigestUtilities.DoFinal(hash);
+
+			byte[] streamDigest = new byte[digest.Length];
+			Array.Copy(lookAhead, 2, streamDigest, 0, streamDigest.Length);
+
+			return Arrays.ConstantTimeAreEqual(digest, streamDigest);
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
new file mode 100644
index 000000000..f46f99d37
--- /dev/null
+++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
@@ -0,0 +1,506 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Generator for encrypted objects.</remarks>
+    public class PgpEncryptedDataGenerator
+		: IStreamGenerator
+    {
+		private BcpgOutputStream	pOut;
+        private CipherStream		cOut;
+        private IBufferedCipher		c;
+        private bool				withIntegrityPacket;
+        private bool				oldFormat;
+        private DigestStream		digestOut;
+
+		private abstract class EncMethod
+            : ContainedPacket
+        {
+            protected byte[]                    sessionInfo;
+            protected SymmetricKeyAlgorithmTag  encAlgorithm;
+            protected KeyParameter              key;
+
+			public abstract void AddSessionInfo(byte[] si, SecureRandom random);
+        }
+
+        private class PbeMethod
+            : EncMethod
+        {
+            private S2k s2k;
+
+            internal PbeMethod(
+                SymmetricKeyAlgorithmTag  encAlgorithm,
+                S2k                       s2k,
+                KeyParameter              key)
+            {
+                this.encAlgorithm = encAlgorithm;
+                this.s2k = s2k;
+                this.key = key;
+            }
+
+            public KeyParameter GetKey()
+            {
+                return key;
+            }
+
+			public override void AddSessionInfo(
+                byte[]			si,
+				SecureRandom	random)
+            {
+                string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+                IBufferedCipher c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+
+				byte[] iv = new byte[c.GetBlockSize()];
+                c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), random));
+
+				this.sessionInfo = c.DoFinal(si, 0, si.Length - 2);
+			}
+
+			public override void Encode(BcpgOutputStream pOut)
+            {
+                SymmetricKeyEncSessionPacket pk = new SymmetricKeyEncSessionPacket(
+                    encAlgorithm, s2k, sessionInfo);
+
+				pOut.WritePacket(pk);
+            }
+        }
+
+		private class PubMethod
+            : EncMethod
+        {
+			internal PgpPublicKey pubKey;
+            internal BigInteger[] data;
+
+			internal PubMethod(
+                PgpPublicKey pubKey)
+            {
+                this.pubKey = pubKey;
+            }
+
+			public override void AddSessionInfo(
+                byte[]			si,
+				SecureRandom	random)
+            {
+                IBufferedCipher c;
+
+				switch (pubKey.Algorithm)
+                {
+                    case PublicKeyAlgorithmTag.RsaEncrypt:
+                    case PublicKeyAlgorithmTag.RsaGeneral:
+                        c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
+                        break;
+                    case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                    case PublicKeyAlgorithmTag.ElGamalGeneral:
+                        c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+                        break;
+                    case PublicKeyAlgorithmTag.Dsa:
+                        throw new PgpException("Can't use DSA for encryption.");
+                    case PublicKeyAlgorithmTag.ECDsa:
+                        throw new PgpException("Can't use ECDSA for encryption.");
+                    default:
+                        throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+                }
+
+				AsymmetricKeyParameter akp = pubKey.GetKey();
+
+				c.Init(true, new ParametersWithRandom(akp, random));
+
+				byte[] encKey = c.DoFinal(si);
+
+				switch (pubKey.Algorithm)
+                {
+                    case PublicKeyAlgorithmTag.RsaEncrypt:
+                    case PublicKeyAlgorithmTag.RsaGeneral:
+						data = new BigInteger[]{ new BigInteger(1, encKey) };
+                        break;
+                    case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                    case PublicKeyAlgorithmTag.ElGamalGeneral:
+						int halfLength = encKey.Length / 2;
+						data = new BigInteger[]
+						{
+							new BigInteger(1, encKey, 0, halfLength),
+							new BigInteger(1, encKey, halfLength, halfLength)
+						};
+                        break;
+                    default:
+                        throw new PgpException("unknown asymmetric algorithm: " + encAlgorithm);
+                }
+            }
+
+			public override void Encode(BcpgOutputStream pOut)
+            {
+                PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(
+                    pubKey.KeyId, pubKey.Algorithm, data);
+
+				pOut.WritePacket(pk);
+            }
+        }
+
+		private readonly IList methods = Platform.CreateArrayList();
+        private readonly SymmetricKeyAlgorithmTag defAlgorithm;
+        private readonly SecureRandom rand;
+
+		public PgpEncryptedDataGenerator(
+			SymmetricKeyAlgorithmTag encAlgorithm)
+		{
+			this.defAlgorithm = encAlgorithm;
+			this.rand = new SecureRandom();
+		}
+
+		public PgpEncryptedDataGenerator(
+			SymmetricKeyAlgorithmTag	encAlgorithm,
+			bool						withIntegrityPacket)
+		{
+			this.defAlgorithm = encAlgorithm;
+			this.withIntegrityPacket = withIntegrityPacket;
+			this.rand = new SecureRandom();
+		}
+
+		/// <summary>Existing SecureRandom constructor.</summary>
+		/// <param name="encAlgorithm">The symmetric algorithm to use.</param>
+		/// <param name="rand">Source of randomness.</param>
+        public PgpEncryptedDataGenerator(
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            SecureRandom				rand)
+        {
+            this.defAlgorithm = encAlgorithm;
+            this.rand = rand;
+        }
+
+		/// <summary>Creates a cipher stream which will have an integrity packet associated with it.</summary>
+        public PgpEncryptedDataGenerator(
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            bool						withIntegrityPacket,
+            SecureRandom				rand)
+        {
+            this.defAlgorithm = encAlgorithm;
+            this.rand = rand;
+            this.withIntegrityPacket = withIntegrityPacket;
+        }
+
+		/// <summary>Base constructor.</summary>
+		/// <param name="encAlgorithm">The symmetric algorithm to use.</param>
+		/// <param name="rand">Source of randomness.</param>
+		/// <param name="oldFormat">PGP 2.6.x compatibility required.</param>
+        public PgpEncryptedDataGenerator(
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            SecureRandom				rand,
+            bool						oldFormat)
+        {
+            this.defAlgorithm = encAlgorithm;
+            this.rand = rand;
+            this.oldFormat = oldFormat;
+        }
+
+		/// <summary>
+		/// Add a PBE encryption method to the encrypted object using the default algorithm (S2K_SHA1).
+		/// </summary>
+		public void AddMethod(
+			char[] passPhrase) 
+		{
+			AddMethod(passPhrase, HashAlgorithmTag.Sha1);
+		}
+
+		/// <summary>Add a PBE encryption method to the encrypted object.</summary>
+        public void AddMethod(
+ 			char[]				passPhrase,
+			HashAlgorithmTag	s2kDigest)
+        {
+            byte[] iv = new byte[8];
+			rand.NextBytes(iv);
+
+			S2k s2k = new S2k(s2kDigest, iv, 0x60);
+
+			methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.MakeKeyFromPassPhrase(defAlgorithm, s2k, passPhrase)));
+        }
+
+		/// <summary>Add a public key encrypted session key to the encrypted object.</summary>
+        public void AddMethod(
+            PgpPublicKey key)
+        {
+			if (!key.IsEncryptionKey)
+            {
+                throw new ArgumentException("passed in key not an encryption key!");
+            }
+
+			methods.Add(new PubMethod(key));
+        }
+
+		private void AddCheckSum(
+            byte[] sessionInfo)
+        {
+			Debug.Assert(sessionInfo != null);
+			Debug.Assert(sessionInfo.Length >= 3);
+
+			int check = 0;
+
+			for (int i = 1; i < sessionInfo.Length - 2; i++)
+            {
+                check += sessionInfo[i];
+            }
+
+			sessionInfo[sessionInfo.Length - 2] = (byte)(check >> 8);
+            sessionInfo[sessionInfo.Length - 1] = (byte)(check);
+        }
+
+		private byte[] CreateSessionInfo(
+			SymmetricKeyAlgorithmTag	algorithm,
+			KeyParameter				key)
+		{
+			byte[] keyBytes = key.GetKey();
+			byte[] sessionInfo = new byte[keyBytes.Length + 3];
+			sessionInfo[0] = (byte) algorithm;
+			keyBytes.CopyTo(sessionInfo, 1);
+			AddCheckSum(sessionInfo);
+			return sessionInfo;
+		}
+
+		/// <summary>
+		/// <p>
+		/// If buffer is non null stream assumed to be partial, otherwise the length will be used
+		/// to output a fixed length packet.
+		/// </p>
+		/// <p>
+		/// The stream created can be closed off by either calling Close()
+		/// on the stream or Close() on the generator. Closing the returned
+		/// stream does not close off the Stream parameter <c>outStr</c>.
+		/// </p>
+		/// </summary>
+        private Stream Open(
+            Stream	outStr,
+            long	length,
+            byte[]	buffer)
+        {
+			if (cOut != null)
+				throw new InvalidOperationException("generator already in open state");
+			if (methods.Count == 0)
+				throw new InvalidOperationException("No encryption methods specified");
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			pOut = new BcpgOutputStream(outStr);
+
+			KeyParameter key;
+
+			if (methods.Count == 1)
+            {
+                if (methods[0] is PbeMethod)
+                {
+                    PbeMethod m = (PbeMethod)methods[0];
+
+					key = m.GetKey();
+                }
+                else
+                {
+                    key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
+
+					byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
+                    PubMethod m = (PubMethod)methods[0];
+
+                    try
+                    {
+                        m.AddSessionInfo(sessionInfo, rand);
+                    }
+                    catch (Exception e)
+                    {
+                        throw new PgpException("exception encrypting session key", e);
+                    }
+                }
+
+				pOut.WritePacket((ContainedPacket)methods[0]);
+            }
+            else // multiple methods
+            {
+                key = PgpUtilities.MakeRandomKey(defAlgorithm, rand);
+				byte[] sessionInfo = CreateSessionInfo(defAlgorithm, key);
+
+				for (int i = 0; i != methods.Count; i++)
+                {
+                    EncMethod m = (EncMethod)methods[i];
+
+                    try
+                    {
+                        m.AddSessionInfo(sessionInfo, rand);
+                    }
+                    catch (Exception e)
+                    {
+                        throw new PgpException("exception encrypting session key", e);
+                    }
+
+                    pOut.WritePacket(m);
+                }
+            }
+
+            string cName = PgpUtilities.GetSymmetricCipherName(defAlgorithm);
+			if (cName == null)
+            {
+                throw new PgpException("null cipher specified");
+            }
+
+			try
+            {
+                if (withIntegrityPacket)
+                {
+                    cName += "/CFB/NoPadding";
+                }
+                else
+                {
+                    cName += "/OpenPGPCFB/NoPadding";
+                }
+
+                c = CipherUtilities.GetCipher(cName);
+
+				// TODO Confirm the IV should be all zero bytes (not inLineIv - see below)
+				byte[] iv = new byte[c.GetBlockSize()];
+                c.Init(true, new ParametersWithRandom(new ParametersWithIV(key, iv), rand));
+
+                if (buffer == null)
+                {
+                    //
+                    // we have to Add block size + 2 for the Generated IV and + 1 + 22 if integrity protected
+                    //
+                    if (withIntegrityPacket)
+                    {
+                        pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, length + c.GetBlockSize() + 2 + 1 + 22);
+                        pOut.WriteByte(1);        // version number
+                    }
+                    else
+                    {
+                        pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, length + c.GetBlockSize() + 2, oldFormat);
+                    }
+                }
+                else
+                {
+                    if (withIntegrityPacket)
+                    {
+                        pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricEncryptedIntegrityProtected, buffer);
+                        pOut.WriteByte(1);        // version number
+                    }
+                    else
+                    {
+                        pOut = new BcpgOutputStream(outStr, PacketTag.SymmetricKeyEncrypted, buffer);
+                    }
+                }
+
+				int blockSize = c.GetBlockSize();
+				byte[] inLineIv = new byte[blockSize + 2];
+                rand.NextBytes(inLineIv, 0, blockSize);
+				Array.Copy(inLineIv, inLineIv.Length - 4, inLineIv, inLineIv.Length - 2, 2);
+
+				Stream myOut = cOut = new CipherStream(pOut, null, c);
+
+				if (withIntegrityPacket)
+                {
+					string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+					IDigest digest = DigestUtilities.GetDigest(digestName);
+					myOut = digestOut = new DigestStream(myOut, null, digest);
+                }
+
+				myOut.Write(inLineIv, 0, inLineIv.Length);
+
+				return new WrappedGeneratorStream(this, myOut);
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception creating cipher", e);
+            }
+        }
+
+		/// <summary>
+		/// <p>
+		/// Return an output stream which will encrypt the data as it is written to it.
+		/// </p>
+		/// <p>
+		/// The stream created can be closed off by either calling Close()
+		/// on the stream or Close() on the generator. Closing the returned
+		/// stream does not close off the Stream parameter <c>outStr</c>.
+		/// </p>
+		/// </summary>
+        public Stream Open(
+            Stream	outStr,
+            long	length)
+        {
+            return Open(outStr, length, null);
+        }
+
+		/// <summary>
+		/// <p>
+		/// Return an output stream which will encrypt the data as it is written to it.
+		/// The stream will be written out in chunks according to the size of the passed in buffer.
+		/// </p>
+		/// <p>
+		/// The stream created can be closed off by either calling Close()
+		/// on the stream or Close() on the generator. Closing the returned
+		/// stream does not close off the Stream parameter <c>outStr</c>.
+		/// </p>
+		/// <p>
+		/// <b>Note</b>: if the buffer is not a power of 2 in length only the largest power of 2
+		/// bytes worth of the buffer will be used.
+		/// </p>
+		/// </summary>
+        public Stream Open(
+            Stream	outStr,
+            byte[]	buffer)
+        {
+            return Open(outStr, 0, buffer);
+        }
+
+		/// <summary>
+		/// <p>
+		/// Close off the encrypted object - this is equivalent to calling Close() on the stream
+		/// returned by the Open() method.
+		/// </p>
+		/// <p>
+		/// <b>Note</b>: This does not close the underlying output stream, only the stream on top of
+		/// it created by the Open() method.
+		/// </p>
+		/// </summary>
+        public void Close()
+        {
+            if (cOut != null)
+            {
+				// TODO Should this all be under the try/catch block?
+                if (digestOut != null)
+                {
+                    //
+                    // hand code a mod detection packet
+                    //
+                    BcpgOutputStream bOut = new BcpgOutputStream(
+						digestOut, PacketTag.ModificationDetectionCode, 20);
+
+                    bOut.Flush();
+                    digestOut.Flush();
+
+					// TODO
+					byte[] dig = DigestUtilities.DoFinal(digestOut.WriteDigest());
+					cOut.Write(dig, 0, dig.Length);
+                }
+
+				cOut.Flush();
+
+				try
+                {
+					pOut.Write(c.DoFinal());
+                    pOut.Finish();
+                }
+                catch (Exception e)
+                {
+                    throw new IOException(e.Message, e);
+                }
+
+				cOut = null;
+				pOut = null;
+            }
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PgpEncryptedDataList.cs b/crypto/src/openpgp/PgpEncryptedDataList.cs
new file mode 100644
index 000000000..8dded7c05
--- /dev/null
+++ b/crypto/src/openpgp/PgpEncryptedDataList.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>A holder for a list of PGP encryption method packets.</remarks>
+    public class PgpEncryptedDataList
+		: PgpObject
+    {
+        private IList list = Platform.CreateArrayList();
+        private InputStreamPacket data;
+
+		public PgpEncryptedDataList(
+            BcpgInputStream bcpgInput)
+        {
+            while (bcpgInput.NextPacketTag() == PacketTag.PublicKeyEncryptedSession
+                || bcpgInput.NextPacketTag() == PacketTag.SymmetricKeyEncryptedSessionKey)
+            {
+                list.Add(bcpgInput.ReadPacket());
+            }
+
+			data = (InputStreamPacket)bcpgInput.ReadPacket();
+
+			for (int i = 0; i != list.Count; i++)
+            {
+                if (list[i] is SymmetricKeyEncSessionPacket)
+                {
+                    list[i] = new PgpPbeEncryptedData((SymmetricKeyEncSessionPacket) list[i], data);
+                }
+                else
+                {
+                    list[i] = new PgpPublicKeyEncryptedData((PublicKeyEncSessionPacket) list[i], data);
+                }
+            }
+        }
+
+		public PgpEncryptedData this[int index]
+		{
+			get { return (PgpEncryptedData) list[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public object Get(int index)
+        {
+            return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+        {
+			get { return list.Count; }
+        }
+
+		public int Count
+		{
+			get { return list.Count; }
+		}
+
+		public bool IsEmpty
+        {
+			get { return list.Count == 0; }
+        }
+
+		public IEnumerable GetEncryptedDataObjects()
+        {
+            return new EnumerableProxy(list);
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpException.cs b/crypto/src/openpgp/PgpException.cs
index 3048116fa..378b16a56 100644
--- a/crypto/src/openpgp/PgpException.cs
+++ b/crypto/src/openpgp/PgpException.cs
@@ -3,7 +3,10 @@ using System;
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
 	/// <remarks>Generic exception class for PGP encoding/decoding problems.</remarks>
-	public class PgpException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PgpException
 		: Exception
 	{
 		public PgpException() : base() {}
diff --git a/crypto/src/openpgp/PgpExperimental.cs b/crypto/src/openpgp/PgpExperimental.cs
new file mode 100644
index 000000000..8518335a1
--- /dev/null
+++ b/crypto/src/openpgp/PgpExperimental.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	public class PgpExperimental
+		: PgpObject
+	{
+		private readonly ExperimentalPacket p;
+
+		public PgpExperimental(
+			BcpgInputStream bcpgIn)
+		{
+			p = (ExperimentalPacket) bcpgIn.ReadPacket();
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PgpKeyFlags.cs b/crypto/src/openpgp/PgpKeyFlags.cs
new file mode 100644
index 000000000..ea1800606
--- /dev/null
+++ b/crypto/src/openpgp/PgpKeyFlags.cs
@@ -0,0 +1,13 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Key flag values for the KeyFlags subpacket.</remarks>
+    public abstract class PgpKeyFlags
+    {
+        public const int CanCertify = 0x01; // This key may be used to certify other keys.
+        public const int CanSign = 0x02; // This key may be used to sign data.
+        public const int CanEncryptCommunications = 0x04; // This key may be used to encrypt communications.
+        public const int CanEncryptStorage = 0x08; // This key may be used to encrypt storage.
+        public const int MaybeSplit = 0x10; // The private component of this key may have been split by a secret-sharing mechanism.
+        public const int MaybeShared = 0x80; // The private component of this key may be in the possession of more than one person.
+    }
+}
diff --git a/crypto/src/openpgp/PgpKeyPair.cs b/crypto/src/openpgp/PgpKeyPair.cs
new file mode 100644
index 000000000..6efb03a42
--- /dev/null
+++ b/crypto/src/openpgp/PgpKeyPair.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// General class to handle JCA key pairs and convert them into OpenPGP ones.
+	/// <p>
+	/// A word for the unwary, the KeyId for an OpenPGP public key is calculated from
+	/// a hash that includes the time of creation, if you pass a different date to the
+	/// constructor below with the same public private key pair the KeyIs will not be the
+	/// same as for previous generations of the key, so ideally you only want to do
+	/// this once.
+	/// </p>
+	/// </remarks>
+    public class PgpKeyPair
+    {
+        private readonly PgpPublicKey	pub;
+        private readonly PgpPrivateKey	priv;
+
+		public PgpKeyPair(
+            PublicKeyAlgorithmTag	algorithm,
+            AsymmetricCipherKeyPair	keyPair,
+            DateTime				time)
+			: this(algorithm, keyPair.Public, keyPair.Private, time)
+        {
+        }
+
+		public PgpKeyPair(
+            PublicKeyAlgorithmTag	algorithm,
+            AsymmetricKeyParameter	pubKey,
+            AsymmetricKeyParameter	privKey,
+            DateTime				time)
+        {
+            this.pub = new PgpPublicKey(algorithm, pubKey, time);
+			this.priv = new PgpPrivateKey(privKey, pub.KeyId);
+        }
+
+		/// <summary>Create a key pair from a PgpPrivateKey and a PgpPublicKey.</summary>
+		/// <param name="pub">The public key.</param>
+		/// <param name="priv">The private key.</param>
+        public PgpKeyPair(
+            PgpPublicKey	pub,
+            PgpPrivateKey	priv)
+        {
+            this.pub = pub;
+            this.priv = priv;
+        }
+
+		/// <summary>The keyId associated with this key pair.</summary>
+        public long KeyId
+        {
+            get { return pub.KeyId; }
+        }
+
+		public PgpPublicKey PublicKey
+        {
+			get { return pub; }
+        }
+
+		public PgpPrivateKey PrivateKey
+        {
+			get { return priv; }
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpKeyRingGenerator.cs b/crypto/src/openpgp/PgpKeyRingGenerator.cs
new file mode 100644
index 000000000..e85fc2eef
--- /dev/null
+++ b/crypto/src/openpgp/PgpKeyRingGenerator.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// Generator for a PGP master and subkey ring.
+	/// This class will generate both the secret and public key rings
+	/// </remarks>
+    public class PgpKeyRingGenerator
+    {
+        private IList					    keys = Platform.CreateArrayList();
+        private string                      id;
+        private SymmetricKeyAlgorithmTag	encAlgorithm;
+        private int                         certificationLevel;
+        private char[]                      passPhrase;
+		private bool						useSha1;
+		private PgpKeyPair                  masterKey;
+        private PgpSignatureSubpacketVector hashedPacketVector;
+        private PgpSignatureSubpacketVector unhashedPacketVector;
+        private SecureRandom				rand;
+
+		/// <summary>
+		/// Create a new key ring generator using old style checksumming. It is recommended to use
+		/// SHA1 checksumming where possible.
+		/// </summary>
+		/// <param name="certificationLevel">The certification level for keys on this ring.</param>
+		/// <param name="masterKey">The master key pair.</param>
+		/// <param name="id">The id to be associated with the ring.</param>
+		/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
+		/// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param>
+		/// <param name="hashedPackets">Packets to be included in the certification hash.</param>
+		/// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
+		/// <param name="rand">input secured random.</param>
+		public PgpKeyRingGenerator(
+			int							certificationLevel,
+			PgpKeyPair					masterKey,
+			string						id,
+			SymmetricKeyAlgorithmTag	encAlgorithm,
+			char[]						passPhrase,
+			PgpSignatureSubpacketVector	hashedPackets,
+			PgpSignatureSubpacketVector	unhashedPackets,
+			SecureRandom				rand)
+			: this(certificationLevel, masterKey, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
+		{
+		}
+
+		/// <summary>
+		/// Create a new key ring generator.
+		/// </summary>
+		/// <param name="certificationLevel">The certification level for keys on this ring.</param>
+		/// <param name="masterKey">The master key pair.</param>
+		/// <param name="id">The id to be associated with the ring.</param>
+		/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
+		/// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param>
+		/// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param>
+		/// <param name="hashedPackets">Packets to be included in the certification hash.</param>
+		/// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
+		/// <param name="rand">input secured random.</param>
+        public PgpKeyRingGenerator(
+            int							certificationLevel,
+            PgpKeyPair					masterKey,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+			bool						useSha1,
+			PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+        {
+            this.certificationLevel = certificationLevel;
+            this.masterKey = masterKey;
+            this.id = id;
+            this.encAlgorithm = encAlgorithm;
+            this.passPhrase = passPhrase;
+			this.useSha1 = useSha1;
+			this.hashedPacketVector = hashedPackets;
+            this.unhashedPacketVector = unhashedPackets;
+            this.rand = rand;
+
+			keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand));
+        }
+
+		/// <summary>Add a subkey to the key ring to be generated with default certification.</summary>
+        public void AddSubKey(
+            PgpKeyPair keyPair)
+        {
+			AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector);
+		}
+
+		/// <summary>
+		/// Add a subkey with specific hashed and unhashed packets associated with it and
+		/// default certification.
+		/// </summary>
+		/// <param name="keyPair">Public/private key pair.</param>
+		/// <param name="hashedPackets">Hashed packet values to be included in certification.</param>
+		/// <param name="unhashedPackets">Unhashed packets values to be included in certification.</param>
+		/// <exception cref="PgpException"></exception>
+		public void AddSubKey(
+			PgpKeyPair					keyPair,
+			PgpSignatureSubpacketVector	hashedPackets,
+			PgpSignatureSubpacketVector	unhashedPackets)
+		{
+			try
+            {
+                PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+					masterKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+
+				//
+                // Generate the certification
+                //
+                sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey);
+
+				sGen.SetHashedSubpackets(hashedPackets);
+                sGen.SetUnhashedSubpackets(unhashedPackets);
+
+				IList subSigs = Platform.CreateArrayList();
+
+				subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
+
+				keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm, passPhrase, useSha1, rand));
+			}
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("exception adding subkey: ", e);
+            }
+        }
+
+		/// <summary>Return the secret key ring.</summary>
+        public PgpSecretKeyRing GenerateSecretKeyRing()
+        {
+            return new PgpSecretKeyRing(keys);
+        }
+
+		/// <summary>Return the public key ring that corresponds to the secret key ring.</summary>
+        public PgpPublicKeyRing GeneratePublicKeyRing()
+        {
+            IList pubKeys = Platform.CreateArrayList();
+
+            IEnumerator enumerator = keys.GetEnumerator();
+            enumerator.MoveNext();
+
+			PgpSecretKey pgpSecretKey = (PgpSecretKey) enumerator.Current;
+			pubKeys.Add(pgpSecretKey.PublicKey);
+
+			while (enumerator.MoveNext())
+            {
+                pgpSecretKey = (PgpSecretKey) enumerator.Current;
+
+				PgpPublicKey k = new PgpPublicKey(pgpSecretKey.PublicKey);
+				k.publicPk = new PublicSubkeyPacket(
+					k.Algorithm, k.CreationTime, k.publicPk.Key);
+
+				pubKeys.Add(k);
+			}
+
+			return new PgpPublicKeyRing(pubKeys);
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpKeyValidationException.cs b/crypto/src/openpgp/PgpKeyValidationException.cs
index da07f400f..d6419b27b 100644
--- a/crypto/src/openpgp/PgpKeyValidationException.cs
+++ b/crypto/src/openpgp/PgpKeyValidationException.cs
@@ -5,7 +5,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 	/// <remarks>
 	/// Thrown if the key checksum is invalid.
 	/// </remarks>
-	public class PgpKeyValidationException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PgpKeyValidationException
 		: PgpException
 	{
 		public PgpKeyValidationException() : base() {}
diff --git a/crypto/src/openpgp/PgpLiteralData.cs b/crypto/src/openpgp/PgpLiteralData.cs
new file mode 100644
index 000000000..79bbc3984
--- /dev/null
+++ b/crypto/src/openpgp/PgpLiteralData.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <summary>Class for processing literal data objects.</summary>
+    public class PgpLiteralData
+		: PgpObject
+    {
+        public const char Binary = 'b';
+        public const char Text = 't';
+		public const char Utf8 = 'u';
+
+		/// <summary>The special name indicating a "for your eyes only" packet.</summary>
+        public const string Console = "_CONSOLE";
+
+		private LiteralDataPacket data;
+
+		public PgpLiteralData(
+            BcpgInputStream bcpgInput)
+        {
+            data = (LiteralDataPacket) bcpgInput.ReadPacket();
+        }
+
+		/// <summary>The format of the data stream - Binary or Text</summary>
+        public int Format
+        {
+            get { return data.Format; }
+        }
+
+		/// <summary>The file name that's associated with the data stream.</summary>
+        public string FileName
+        {
+			get { return data.FileName; }
+        }
+
+		/// Return the file name as an unintrepreted byte array.
+		public byte[] GetRawFileName()
+		{
+			return data.GetRawFileName();
+		}
+
+		/// <summary>The modification time for the file.</summary>
+        public DateTime ModificationTime
+        {
+			get { return DateTimeUtilities.UnixMsToDateTime(data.ModificationTime); }
+        }
+
+		/// <summary>The raw input stream for the data stream.</summary>
+        public Stream GetInputStream()
+        {
+            return data.GetInputStream();
+        }
+
+		/// <summary>The input stream representing the data stream.</summary>
+        public Stream GetDataStream()
+        {
+            return GetInputStream();
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpLiteralDataGenerator.cs b/crypto/src/openpgp/PgpLiteralDataGenerator.cs
index b0337c80d..3b1f2fe74 100644
--- a/crypto/src/openpgp/PgpLiteralDataGenerator.cs
+++ b/crypto/src/openpgp/PgpLiteralDataGenerator.cs
@@ -39,11 +39,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		private void WriteHeader(
             BcpgOutputStream	outStr,
             char				format,
-            string				name,
+            byte[]				encName,
             long				modificationTime)
         {
-			byte[] encName = Strings.ToUtf8ByteArray(name);
-
 			outStr.Write(
 				(byte) format,
 				(byte) encName.Length);
@@ -89,15 +87,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			// Do this first, since it might throw an exception
 			long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
 
-			pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData,
-				length + 2 + name.Length + 4, oldFormat);
+            byte[] encName = Strings.ToUtf8ByteArray(name);
+
+            pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData,
+				length + 2 + encName.Length + 4, oldFormat);
 
-			WriteHeader(pkOut, format, name, unixMs);
+			WriteHeader(pkOut, format, encName, unixMs);
 
 			return new WrappedGeneratorStream(this, pkOut);
         }
 
-		/// <summary>
+        /// <summary>
 		/// <p>
 		/// Open a literal data packet, returning a stream to store the data inside the packet,
 		/// as an indefinite length stream. The stream is written out as a series of partial
@@ -132,14 +132,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			// Do this first, since it might throw an exception
 			long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
 
+            byte[] encName = Strings.ToUtf8ByteArray(name);
+
 			pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer);
 
-			WriteHeader(pkOut, format, name, unixMs);
+            WriteHeader(pkOut, format, encName, unixMs);
 
 			return new WrappedGeneratorStream(this, pkOut);
 		}
 
-#if !PORTABLE
 		/// <summary>
 		/// <p>
 		/// Open a literal data packet for the passed in <c>FileInfo</c> object, returning
@@ -161,7 +162,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
 			return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
         }
-#endif
 
 		/// <summary>
 		/// Close the literal data packet - this is equivalent to calling Close()
diff --git a/crypto/src/openpgp/PgpMarker.cs b/crypto/src/openpgp/PgpMarker.cs
new file mode 100644
index 000000000..733e4e959
--- /dev/null
+++ b/crypto/src/openpgp/PgpMarker.cs
@@ -0,0 +1,18 @@
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// A PGP marker packet - in general these should be ignored other than where
+	/// the idea is to preserve the original input stream.
+	/// </remarks>
+    public class PgpMarker
+		: PgpObject
+    {
+        private readonly MarkerPacket p;
+
+		public PgpMarker(
+            BcpgInputStream bcpgIn)
+        {
+            p = (MarkerPacket) bcpgIn.ReadPacket();
+        }
+	}
+}
diff --git a/crypto/src/openpgp/PgpObjectFactory.cs b/crypto/src/openpgp/PgpObjectFactory.cs
new file mode 100644
index 000000000..c5c6fcb68
--- /dev/null
+++ b/crypto/src/openpgp/PgpObjectFactory.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+    /// General class for reading a PGP object stream.
+    /// <p>
+    /// Note: if this class finds a PgpPublicKey or a PgpSecretKey it
+    /// will create a PgpPublicKeyRing, or a PgpSecretKeyRing for each
+    /// key found. If all you are trying to do is read a key ring file use
+    /// either PgpPublicKeyRingBundle or PgpSecretKeyRingBundle.</p>
+	/// </remarks>
+	public class PgpObjectFactory
+    {
+        private readonly BcpgInputStream bcpgIn;
+
+		public PgpObjectFactory(
+            Stream inputStream)
+        {
+            this.bcpgIn = BcpgInputStream.Wrap(inputStream);
+        }
+
+        public PgpObjectFactory(
+            byte[] bytes)
+            : this(new MemoryStream(bytes, false))
+        {
+        }
+
+		/// <summary>Return the next object in the stream, or null if the end is reached.</summary>
+		/// <exception cref="IOException">On a parse error</exception>
+        public PgpObject NextPgpObject()
+        {
+            PacketTag tag = bcpgIn.NextPacketTag();
+
+            if ((int) tag == -1) return null;
+
+            switch (tag)
+            {
+                case PacketTag.Signature:
+                {
+                    IList l = Platform.CreateArrayList();
+
+                    while (bcpgIn.NextPacketTag() == PacketTag.Signature)
+                    {
+                        try
+                        {
+                            l.Add(new PgpSignature(bcpgIn));
+                        }
+                        catch (PgpException e)
+                        {
+                            throw new IOException("can't create signature object: " + e);
+                        }
+                    }
+
+                    PgpSignature[] sigs = new PgpSignature[l.Count];
+                    for (int i = 0; i < l.Count; ++i)
+                    {
+                        sigs[i] = (PgpSignature)l[i];
+                    }
+					return new PgpSignatureList(sigs);
+                }
+                case PacketTag.SecretKey:
+                    try
+                    {
+                        return new PgpSecretKeyRing(bcpgIn);
+                    }
+                    catch (PgpException e)
+                    {
+                        throw new IOException("can't create secret key object: " + e);
+                    }
+                case PacketTag.PublicKey:
+                    return new PgpPublicKeyRing(bcpgIn);
+				// TODO Make PgpPublicKey a PgpObject or return a PgpPublicKeyRing
+//				case PacketTag.PublicSubkey:
+//					return PgpPublicKeyRing.ReadSubkey(bcpgIn);
+                case PacketTag.CompressedData:
+                    return new PgpCompressedData(bcpgIn);
+                case PacketTag.LiteralData:
+                    return new PgpLiteralData(bcpgIn);
+                case PacketTag.PublicKeyEncryptedSession:
+                case PacketTag.SymmetricKeyEncryptedSessionKey:
+                    return new PgpEncryptedDataList(bcpgIn);
+                case PacketTag.OnePassSignature:
+                {
+                    IList l = Platform.CreateArrayList();
+
+                    while (bcpgIn.NextPacketTag() == PacketTag.OnePassSignature)
+                    {
+                        try
+                        {
+                            l.Add(new PgpOnePassSignature(bcpgIn));
+                        }
+                        catch (PgpException e)
+                        {
+							throw new IOException("can't create one pass signature object: " + e);
+						}
+                    }
+
+                    PgpOnePassSignature[] sigs = new PgpOnePassSignature[l.Count];
+                    for (int i = 0; i < l.Count; ++i)
+                    {
+                        sigs[i] = (PgpOnePassSignature)l[i];
+                    }
+					return new PgpOnePassSignatureList(sigs);
+                }
+                case PacketTag.Marker:
+                    return new PgpMarker(bcpgIn);
+                case PacketTag.Experimental1:
+                case PacketTag.Experimental2:
+                case PacketTag.Experimental3:
+                case PacketTag.Experimental4:
+					return new PgpExperimental(bcpgIn);
+            }
+
+            throw new IOException("unknown object in stream " + bcpgIn.NextPacketTag());
+        }
+
+		[Obsolete("Use NextPgpObject() instead")]
+		public object NextObject()
+		{
+			return NextPgpObject();
+		}
+
+		/// <summary>
+		/// Return all available objects in a list.
+		/// </summary>
+		/// <returns>An <c>IList</c> containing all objects from this factory, in order.</returns>
+		public IList AllPgpObjects()
+		{
+            IList result = Platform.CreateArrayList();
+			PgpObject pgpObject;
+			while ((pgpObject = NextPgpObject()) != null)
+			{
+				result.Add(pgpObject);
+			}
+			return result;
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PgpOnePassSignature.cs b/crypto/src/openpgp/PgpOnePassSignature.cs
new file mode 100644
index 000000000..68fc5994d
--- /dev/null
+++ b/crypto/src/openpgp/PgpOnePassSignature.cs
@@ -0,0 +1,179 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>A one pass signature object.</remarks>
+    public class PgpOnePassSignature
+    {
+        private OnePassSignaturePacket sigPack;
+        private int signatureType;
+		private ISigner sig;
+		private byte lastb;
+
+		internal PgpOnePassSignature(
+            BcpgInputStream bcpgInput)
+            : this((OnePassSignaturePacket) bcpgInput.ReadPacket())
+        {
+        }
+
+		internal PgpOnePassSignature(
+            OnePassSignaturePacket sigPack)
+        {
+            this.sigPack = sigPack;
+            this.signatureType = sigPack.SignatureType;
+        }
+
+		/// <summary>Initialise the signature object for verification.</summary>
+        public void InitVerify(
+            PgpPublicKey pubKey)
+        {
+			lastb = 0;
+
+			try
+			{
+				sig = SignerUtilities.GetSigner(
+					PgpUtilities.GetSignatureName(sigPack.KeyAlgorithm, sigPack.HashAlgorithm));
+			}
+			catch (Exception e)
+			{
+				throw new PgpException("can't set up signature object.",  e);
+			}
+
+			try
+            {
+                sig.Init(false, pubKey.GetKey());
+            }
+			catch (InvalidKeyException e)
+            {
+                throw new PgpException("invalid key.", e);
+            }
+        }
+
+		public void Update(
+            byte b)
+        {
+			if (signatureType == PgpSignature.CanonicalTextDocument)
+			{
+				doCanonicalUpdateByte(b);
+			}
+			else
+			{
+				sig.Update(b);
+			}
+        }
+
+		private void doCanonicalUpdateByte(
+			byte b)
+		{
+			if (b == '\r')
+			{
+				doUpdateCRLF();
+			}
+			else if (b == '\n')
+			{
+				if (lastb != '\r')
+				{
+					doUpdateCRLF();
+				}
+			}
+			else
+			{
+				sig.Update(b);
+			}
+
+			lastb = b;
+		}
+
+		private void doUpdateCRLF()
+		{
+			sig.Update((byte)'\r');
+			sig.Update((byte)'\n');
+		}
+
+		public void Update(
+            byte[] bytes)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+                for (int i = 0; i != bytes.Length; i++)
+                {
+                    doCanonicalUpdateByte(bytes[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(bytes, 0, bytes.Length);
+            }
+        }
+
+        public void Update(
+            byte[]  bytes,
+            int     off,
+            int     length)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+                int finish = off + length;
+
+                for (int i = off; i != finish; i++)
+                {
+                    doCanonicalUpdateByte(bytes[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(bytes, off, length);
+            }
+        }
+
+		/// <summary>Verify the calculated signature against the passed in PgpSignature.</summary>
+        public bool Verify(
+            PgpSignature pgpSig)
+        {
+            byte[] trailer = pgpSig.GetSignatureTrailer();
+
+			sig.BlockUpdate(trailer, 0, trailer.Length);
+
+			return sig.VerifySignature(pgpSig.GetSignature());
+        }
+
+        public long KeyId
+        {
+			get { return sigPack.KeyId; }
+        }
+
+		public int SignatureType
+        {
+            get { return sigPack.SignatureType; }
+        }
+
+		public HashAlgorithmTag HashAlgorithm
+		{
+			get { return sigPack.HashAlgorithm; }
+		}
+
+		public PublicKeyAlgorithmTag KeyAlgorithm
+		{
+			get { return sigPack.KeyAlgorithm; }
+		}
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+            Encode(bOut);
+
+            return bOut.ToArray();
+        }
+
+		public void Encode(
+            Stream outStr)
+        {
+            BcpgOutputStream.Wrap(outStr).WritePacket(sigPack);
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpOnePassSignatureList.cs b/crypto/src/openpgp/PgpOnePassSignatureList.cs
new file mode 100644
index 000000000..37c4288e3
--- /dev/null
+++ b/crypto/src/openpgp/PgpOnePassSignatureList.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Holder for a list of PgpOnePassSignature objects.</remarks>
+    public class PgpOnePassSignatureList
+		: PgpObject
+    {
+        private readonly PgpOnePassSignature[] sigs;
+
+		public PgpOnePassSignatureList(
+            PgpOnePassSignature[] sigs)
+        {
+			this.sigs = (PgpOnePassSignature[]) sigs.Clone();
+        }
+
+		public PgpOnePassSignatureList(
+            PgpOnePassSignature sig)
+        {
+			this.sigs = new PgpOnePassSignature[]{ sig };
+        }
+
+		public PgpOnePassSignature this[int index]
+		{
+			get { return sigs[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public PgpOnePassSignature Get(
+            int index)
+        {
+            return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+        {
+			get { return sigs.Length; }
+        }
+
+		public int Count
+		{
+			get { return sigs.Length; }
+		}
+
+		public bool IsEmpty
+        {
+			get { return (sigs.Length == 0); }
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpPbeEncryptedData.cs b/crypto/src/openpgp/PgpPbeEncryptedData.cs
new file mode 100644
index 000000000..c5fe89407
--- /dev/null
+++ b/crypto/src/openpgp/PgpPbeEncryptedData.cs
@@ -0,0 +1,135 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>A password based encryption object.</remarks>
+    public class PgpPbeEncryptedData
+        : PgpEncryptedData
+    {
+        private readonly SymmetricKeyEncSessionPacket keyData;
+
+		internal PgpPbeEncryptedData(
+			SymmetricKeyEncSessionPacket	keyData,
+			InputStreamPacket				encData)
+			: base(encData)
+		{
+			this.keyData = keyData;
+		}
+
+		/// <summary>Return the raw input stream for the data stream.</summary>
+		public override Stream GetInputStream()
+		{
+			return encData.GetInputStream();
+		}
+
+		/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
+        public Stream GetDataStream(
+            char[] passPhrase)
+        {
+			try
+			{
+				SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm;
+
+				KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(
+					keyAlgorithm, keyData.S2k, passPhrase);
+
+
+				byte[] secKeyData = keyData.GetSecKeyData();
+				if (secKeyData != null && secKeyData.Length > 0)
+				{
+					IBufferedCipher keyCipher = CipherUtilities.GetCipher(
+						PgpUtilities.GetSymmetricCipherName(keyAlgorithm) + "/CFB/NoPadding");
+
+					keyCipher.Init(false,
+						new ParametersWithIV(key, new byte[keyCipher.GetBlockSize()]));
+
+					byte[] keyBytes = keyCipher.DoFinal(secKeyData);
+
+					keyAlgorithm = (SymmetricKeyAlgorithmTag) keyBytes[0];
+
+					key = ParameterUtilities.CreateKeyParameter(
+						PgpUtilities.GetSymmetricCipherName(keyAlgorithm),
+						keyBytes, 1, keyBytes.Length - 1);
+				}
+
+
+				IBufferedCipher c = CreateStreamCipher(keyAlgorithm);
+
+				byte[] iv = new byte[c.GetBlockSize()];
+
+				c.Init(false, new ParametersWithIV(key, iv));
+
+				encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c, null));
+
+				if (encData is SymmetricEncIntegrityPacket)
+				{
+					truncStream = new TruncatedStream(encStream);
+
+					string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+					IDigest digest = DigestUtilities.GetDigest(digestName);
+
+					encStream = new DigestStream(truncStream, digest, null);
+				}
+
+				if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
+					throw new EndOfStreamException("unexpected end of stream.");
+
+				int v1 = encStream.ReadByte();
+				int v2 = encStream.ReadByte();
+
+				if (v1 < 0 || v2 < 0)
+					throw new EndOfStreamException("unexpected end of stream.");
+
+
+				// Note: the oracle attack on the "quick check" bytes is not deemed
+				// a security risk for PBE (see PgpPublicKeyEncryptedData)
+
+				bool repeatCheckPassed =
+						iv[iv.Length - 2] == (byte)v1
+					&&	iv[iv.Length - 1] == (byte)v2;
+
+				// Note: some versions of PGP appear to produce 0 for the extra
+				// bytes rather than repeating the two previous bytes
+				bool zeroesCheckPassed =
+						v1 == 0
+					&&	v2 == 0;
+
+				if (!repeatCheckPassed && !zeroesCheckPassed)
+				{
+					throw new PgpDataValidationException("quick check failed.");
+				}
+
+
+				return encStream;
+			}
+			catch (PgpException e)
+			{
+				throw e;
+			}
+			catch (Exception e)
+			{
+				throw new PgpException("Exception creating cipher", e);
+			}
+		}
+
+		private IBufferedCipher CreateStreamCipher(
+			SymmetricKeyAlgorithmTag keyAlgorithm)
+		{
+			string mode = (encData is SymmetricEncIntegrityPacket)
+				? "CFB"
+				: "OpenPGPCFB";
+
+			string cName = PgpUtilities.GetSymmetricCipherName(keyAlgorithm)
+				+ "/" + mode + "/NoPadding";
+
+			return CipherUtilities.GetCipher(cName);
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PgpPrivateKey.cs b/crypto/src/openpgp/PgpPrivateKey.cs
new file mode 100644
index 000000000..154c87cd7
--- /dev/null
+++ b/crypto/src/openpgp/PgpPrivateKey.cs
@@ -0,0 +1,42 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>General class to contain a private key for use with other OpenPGP objects.</remarks>
+    public class PgpPrivateKey
+    {
+        private readonly long keyId;
+        private readonly AsymmetricKeyParameter privateKey;
+
+		/// <summary>
+		/// Create a PgpPrivateKey from a regular private key and the ID of its
+		/// associated public key.
+		/// </summary>
+		/// <param name="privateKey">Private key to use.</param>
+		/// <param name="keyId">ID of the corresponding public key.</param>
+		public PgpPrivateKey(
+            AsymmetricKeyParameter	privateKey,
+            long					keyId)
+        {
+			if (!privateKey.IsPrivate)
+				throw new ArgumentException("Expected a private key", "privateKey");
+
+			this.privateKey = privateKey;
+            this.keyId = keyId;
+        }
+
+		/// <summary>The keyId associated with the contained private key.</summary>
+        public long KeyId
+        {
+			get { return keyId; }
+        }
+
+		/// <summary>The contained private key.</summary>
+        public AsymmetricKeyParameter Key
+        {
+			get { return privateKey; }
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs
new file mode 100644
index 000000000..b0720146c
--- /dev/null
+++ b/crypto/src/openpgp/PgpPublicKey.cs
@@ -0,0 +1,890 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>General class to handle a PGP public key object.</remarks>
+    public class PgpPublicKey
+    {
+		private static readonly int[] MasterKeyCertificationTypes = new int[]
+		{
+			PgpSignature.PositiveCertification,
+			PgpSignature.CasualCertification,
+			PgpSignature.NoCertification,
+			PgpSignature.DefaultCertification
+		};
+
+		private long				keyId;
+        private byte[]				fingerprint;
+        private int					keyStrength;
+
+		internal PublicKeyPacket	publicPk;
+        internal TrustPacket		trustPk;
+        internal IList			    keySigs = Platform.CreateArrayList();
+        internal IList			    ids = Platform.CreateArrayList();
+        internal IList              idTrusts = Platform.CreateArrayList();
+        internal IList              idSigs = Platform.CreateArrayList();
+        internal IList			    subSigs;
+
+		private void Init()
+        {
+            IBcpgKey key = publicPk.Key;
+
+			if (publicPk.Version <= 3)
+            {
+                RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key;
+
+				this.keyId = rK.Modulus.LongValue;
+
+				try
+                {
+                    IDigest digest = DigestUtilities.GetDigest("MD5");
+
+					byte[] bytes = rK.Modulus.ToByteArrayUnsigned();
+					digest.BlockUpdate(bytes, 0, bytes.Length);
+
+					bytes = rK.PublicExponent.ToByteArrayUnsigned();
+					digest.BlockUpdate(bytes, 0, bytes.Length);
+
+					this.fingerprint = DigestUtilities.DoFinal(digest);
+                }
+				//catch (NoSuchAlgorithmException)
+				catch (Exception e)
+                {
+                    throw new IOException("can't find MD5", e);
+                }
+
+				this.keyStrength = rK.Modulus.BitLength;
+            }
+            else
+            {
+                byte[] kBytes = publicPk.GetEncodedContents();
+
+				try
+                {
+                    IDigest digest = DigestUtilities.GetDigest("SHA1");
+
+					digest.Update(0x99);
+                    digest.Update((byte)(kBytes.Length >> 8));
+                    digest.Update((byte)kBytes.Length);
+                    digest.BlockUpdate(kBytes, 0, kBytes.Length);
+                    this.fingerprint = DigestUtilities.DoFinal(digest);
+                }
+                catch (Exception e)
+                {
+                    throw new IOException("can't find SHA1", e);
+                }
+
+				this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56)
+                    | ((ulong)fingerprint[fingerprint.Length - 7] << 48)
+                    | ((ulong)fingerprint[fingerprint.Length - 6] << 40)
+                    | ((ulong)fingerprint[fingerprint.Length - 5] << 32)
+                    | ((ulong)fingerprint[fingerprint.Length - 4] << 24)
+                    | ((ulong)fingerprint[fingerprint.Length - 3] << 16)
+                    | ((ulong)fingerprint[fingerprint.Length - 2] << 8)
+                    | (ulong)fingerprint[fingerprint.Length - 1]);
+
+				if (key is RsaPublicBcpgKey)
+                {
+                    this.keyStrength = ((RsaPublicBcpgKey)key).Modulus.BitLength;
+                }
+                else if (key is DsaPublicBcpgKey)
+                {
+                    this.keyStrength = ((DsaPublicBcpgKey)key).P.BitLength;
+                }
+                else if (key is ElGamalPublicBcpgKey)
+                {
+                    this.keyStrength = ((ElGamalPublicBcpgKey)key).P.BitLength;
+                }
+            }
+        }
+
+		/// <summary>
+		/// Create a PgpPublicKey from the passed in lightweight one.
+		/// </summary>
+		/// <remarks>
+		/// Note: the time passed in affects the value of the key's keyId, so you probably only want
+		/// to do this once for a lightweight key, or make sure you keep track of the time you used.
+		/// </remarks>
+		/// <param name="algorithm">Asymmetric algorithm type representing the public key.</param>
+		/// <param name="pubKey">Actual public key to associate.</param>
+		/// <param name="time">Date of creation.</param>
+		/// <exception cref="ArgumentException">If <c>pubKey</c> is not public.</exception>
+		/// <exception cref="PgpException">On key creation problem.</exception>
+        public PgpPublicKey(
+            PublicKeyAlgorithmTag	algorithm,
+            AsymmetricKeyParameter	pubKey,
+            DateTime				time)
+        {
+			if (pubKey.IsPrivate)
+				throw new ArgumentException("Expected a public key", "pubKey");
+
+			IBcpgKey bcpgKey;
+            if (pubKey is RsaKeyParameters)
+            {
+                RsaKeyParameters rK = (RsaKeyParameters) pubKey;
+
+				bcpgKey = new RsaPublicBcpgKey(rK.Modulus, rK.Exponent);
+            }
+            else if (pubKey is DsaPublicKeyParameters)
+            {
+                DsaPublicKeyParameters dK = (DsaPublicKeyParameters) pubKey;
+                DsaParameters dP = dK.Parameters;
+
+				bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y);
+            }
+            else if (pubKey is ElGamalPublicKeyParameters)
+            {
+                ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey;
+                ElGamalParameters eS = eK.Parameters;
+
+				bcpgKey = new ElGamalPublicBcpgKey(eS.P, eS.G, eK.Y);
+            }
+            else
+            {
+                throw new PgpException("unknown key class");
+            }
+
+			this.publicPk = new PublicKeyPacket(algorithm, time, bcpgKey);
+            this.ids = Platform.CreateArrayList();
+            this.idSigs = Platform.CreateArrayList();
+
+			try
+            {
+                Init();
+            }
+            catch (IOException e)
+            {
+                throw new PgpException("exception calculating keyId", e);
+            }
+        }
+
+		/// <summary>Constructor for a sub-key.</summary>
+        internal PgpPublicKey(
+            PublicKeyPacket	publicPk,
+            TrustPacket		trustPk,
+            IList           sigs)
+        {
+            this.publicPk = publicPk;
+            this.trustPk = trustPk;
+            this.subSigs = sigs;
+
+			Init();
+        }
+
+		internal PgpPublicKey(
+            PgpPublicKey	key,
+            TrustPacket		trust,
+            IList           subSigs)
+        {
+            this.publicPk = key.publicPk;
+            this.trustPk = trust;
+            this.subSigs = subSigs;
+
+			this.fingerprint = key.fingerprint;
+            this.keyId = key.keyId;
+            this.keyStrength = key.keyStrength;
+        }
+
+		/// <summary>Copy constructor.</summary>
+		/// <param name="pubKey">The public key to copy.</param>
+        internal PgpPublicKey(
+            PgpPublicKey pubKey)
+        {
+            this.publicPk = pubKey.publicPk;
+
+			this.keySigs = Platform.CreateArrayList(pubKey.keySigs);
+            this.ids = Platform.CreateArrayList(pubKey.ids);
+            this.idTrusts = Platform.CreateArrayList(pubKey.idTrusts);
+            this.idSigs = Platform.CreateArrayList(pubKey.idSigs.Count);
+            for (int i = 0; i != pubKey.idSigs.Count; i++)
+            {
+                this.idSigs.Add(Platform.CreateArrayList((IList)pubKey.idSigs[i]));
+            }
+
+			if (pubKey.subSigs != null)
+            {
+                this.subSigs = Platform.CreateArrayList(pubKey.subSigs.Count);
+                for (int i = 0; i != pubKey.subSigs.Count; i++)
+                {
+                    this.subSigs.Add(pubKey.subSigs[i]);
+                }
+            }
+
+			this.fingerprint = pubKey.fingerprint;
+            this.keyId = pubKey.keyId;
+            this.keyStrength = pubKey.keyStrength;
+        }
+
+		internal PgpPublicKey(
+            PublicKeyPacket	publicPk,
+            TrustPacket		trustPk,
+            IList		    keySigs,
+            IList		    ids,
+            IList           idTrusts,
+            IList           idSigs)
+        {
+            this.publicPk = publicPk;
+            this.trustPk = trustPk;
+            this.keySigs = keySigs;
+            this.ids = ids;
+            this.idTrusts = idTrusts;
+            this.idSigs = idSigs;
+
+			Init();
+        }
+
+		internal PgpPublicKey(
+            PublicKeyPacket	publicPk,
+            IList           ids,
+            IList           idSigs)
+        {
+            this.publicPk = publicPk;
+            this.ids = ids;
+            this.idSigs = idSigs;
+            Init();
+        }
+
+		/// <summary>The version of this key.</summary>
+        public int Version
+        {
+			get { return publicPk.Version; }
+        }
+
+		/// <summary>The creation time of this key.</summary>
+		public DateTime CreationTime
+        {
+			get { return publicPk.GetTime(); }
+        }
+
+		/// <summary>The number of valid days from creation time - zero means no expiry.</summary>
+        public int ValidDays
+        {
+			get
+			{
+				if (publicPk.Version > 3)
+				{
+					return (int)(GetValidSeconds() / (24 * 60 * 60));
+				}
+
+				return publicPk.ValidDays;
+			}
+        }
+
+		/// <summary>Return the trust data associated with the public key, if present.</summary>
+		/// <returns>A byte array with trust data, null otherwise.</returns>
+		public byte[] GetTrustData()
+		{
+			if (trustPk == null)
+			{
+				return null;
+			}
+
+			return trustPk.GetLevelAndTrustAmount();
+		}
+
+		/// <summary>The number of valid seconds from creation time - zero means no expiry.</summary>
+		public long GetValidSeconds()
+        {
+			if (publicPk.Version > 3)
+			{
+				if (IsMasterKey)
+				{
+					for (int i = 0; i != MasterKeyCertificationTypes.Length; i++)
+					{
+						long seconds = GetExpirationTimeFromSig(true, MasterKeyCertificationTypes[i]);
+
+						if (seconds >= 0)
+						{
+							return seconds;
+						}
+					}
+				}
+				else
+				{
+					long seconds = GetExpirationTimeFromSig(false, PgpSignature.SubkeyBinding);
+
+					if (seconds >= 0)
+					{
+						return seconds;
+					}
+				}
+
+				return 0;
+			}
+
+			return (long) publicPk.ValidDays * 24 * 60 * 60;
+        }
+
+		private long GetExpirationTimeFromSig(
+			bool	selfSigned,
+			int		signatureType)
+		{
+			foreach (PgpSignature sig in GetSignaturesOfType(signatureType))
+			{
+				if (!selfSigned || sig.KeyId == KeyId)
+				{
+					PgpSignatureSubpacketVector hashed = sig.GetHashedSubPackets();
+
+					if (hashed != null)
+					{
+						return hashed.GetKeyExpirationTime();
+					}
+
+					return 0;
+				}
+			}
+
+			return -1;
+		}
+
+		/// <summary>The keyId associated with the public key.</summary>
+        public long KeyId
+        {
+            get { return keyId; }
+        }
+
+		/// <summary>The fingerprint of the key</summary>
+        public byte[] GetFingerprint()
+        {
+			return (byte[]) fingerprint.Clone();
+        }
+
+		/// <summary>
+		/// Check if this key has an algorithm type that makes it suitable to use for encryption.
+		/// </summary>
+		/// <remarks>
+		/// Note: with version 4 keys KeyFlags subpackets should also be considered when present for
+		/// determining the preferred use of the key.
+		/// </remarks>
+		/// <returns>
+		/// <c>true</c> if this key algorithm is suitable for encryption.
+		/// </returns>
+		public bool IsEncryptionKey
+        {
+            get
+            {
+				switch (publicPk.Algorithm)
+				{
+					case PublicKeyAlgorithmTag.ElGamalEncrypt:
+					case PublicKeyAlgorithmTag.ElGamalGeneral:
+					case PublicKeyAlgorithmTag.RsaEncrypt:
+					case PublicKeyAlgorithmTag.RsaGeneral:
+						return true;
+					default:
+						return false;
+				}
+            }
+        }
+
+		/// <summary>True, if this is a master key.</summary>
+        public bool IsMasterKey
+        {
+            get { return subSigs == null; }
+        }
+
+		/// <summary>The algorithm code associated with the public key.</summary>
+        public PublicKeyAlgorithmTag Algorithm
+        {
+			get { return publicPk.Algorithm; }
+        }
+
+		/// <summary>The strength of the key in bits.</summary>
+        public int BitStrength
+        {
+            get { return keyStrength; }
+        }
+
+		/// <summary>The public key contained in the object.</summary>
+		/// <returns>A lightweight public key.</returns>
+		/// <exception cref="PgpException">If the key algorithm is not recognised.</exception>
+        public AsymmetricKeyParameter GetKey()
+        {
+            try
+            {
+                switch (publicPk.Algorithm)
+                {
+                    case PublicKeyAlgorithmTag.RsaEncrypt:
+                    case PublicKeyAlgorithmTag.RsaGeneral:
+                    case PublicKeyAlgorithmTag.RsaSign:
+                        RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key;
+                        return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent);
+                    case PublicKeyAlgorithmTag.Dsa:
+                        DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key;
+                        return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G));
+                    case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                    case PublicKeyAlgorithmTag.ElGamalGeneral:
+                        ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key;
+                        return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G));
+                    default:
+                        throw new PgpException("unknown public key algorithm encountered");
+                }
+            }
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("exception constructing public key", e);
+            }
+        }
+
+		/// <summary>Allows enumeration of any user IDs associated with the key.</summary>
+		/// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        public IEnumerable GetUserIds()
+        {
+            IList temp = Platform.CreateArrayList();
+
+			foreach (object o in ids)
+			{
+				if (o is string)
+				{
+					temp.Add(o);
+                }
+            }
+
+			return new EnumerableProxy(temp);
+        }
+
+		/// <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
+		/// <returns>An <c>IEnumerable</c> of <c>PgpUserAttributeSubpacketVector</c> objects.</returns>
+        public IEnumerable GetUserAttributes()
+        {
+            IList temp = Platform.CreateArrayList();
+
+			foreach (object o in ids)
+			{
+				if (o is PgpUserAttributeSubpacketVector)
+				{
+					temp.Add(o);
+				}
+			}
+
+			return new EnumerableProxy(temp);
+        }
+
+		/// <summary>Allows enumeration of any signatures associated with the passed in id.</summary>
+		/// <param name="id">The ID to be matched.</param>
+		/// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
+        public IEnumerable GetSignaturesForId(
+            string id)
+        {
+			if (id == null)
+				throw new ArgumentNullException("id");
+
+			for (int i = 0; i != ids.Count; i++)
+            {
+                if (id.Equals(ids[i]))
+                {
+                    return new EnumerableProxy((IList)idSigs[i]);
+                }
+            }
+
+			return null;
+        }
+
+		/// <summary>Allows enumeration of signatures associated with the passed in user attributes.</summary>
+		/// <param name="userAttributes">The vector of user attributes to be matched.</param>
+		/// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
+        public IEnumerable GetSignaturesForUserAttribute(
+            PgpUserAttributeSubpacketVector userAttributes)
+        {
+            for (int i = 0; i != ids.Count; i++)
+            {
+                if (userAttributes.Equals(ids[i]))
+                {
+                    return new EnumerableProxy((IList) idSigs[i]);
+                }
+            }
+
+			return null;
+        }
+
+		/// <summary>Allows enumeration of signatures of the passed in type that are on this key.</summary>
+		/// <param name="signatureType">The type of the signature to be returned.</param>
+		/// <returns>An <c>IEnumerable</c> of <c>PgpSignature</c> objects.</returns>
+        public IEnumerable GetSignaturesOfType(
+            int signatureType)
+        {
+            IList temp = Platform.CreateArrayList();
+
+			foreach (PgpSignature sig in GetSignatures())
+            {
+                if (sig.SignatureType == signatureType)
+                {
+                    temp.Add(sig);
+                }
+            }
+
+			return new EnumerableProxy(temp);
+        }
+
+		/// <summary>Allows enumeration of all signatures/certifications associated with this key.</summary>
+		/// <returns>An <c>IEnumerable</c> with all signatures/certifications.</returns>
+        public IEnumerable GetSignatures()
+        {
+			IList sigs;
+			if (subSigs != null)
+			{
+				sigs = subSigs;
+			}
+			else
+			{
+                sigs = Platform.CreateArrayList(keySigs);
+
+				foreach (ICollection extraSigs in idSigs)
+				{
+                    CollectionUtilities.AddRange(sigs, extraSigs);
+				}
+			}
+
+			return new EnumerableProxy(sigs);
+        }
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+            Encode(bOut);
+            return bOut.ToArray();
+        }
+
+		public void Encode(
+            Stream outStr)
+        {
+            BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+			bcpgOut.WritePacket(publicPk);
+            if (trustPk != null)
+            {
+                bcpgOut.WritePacket(trustPk);
+            }
+
+			if (subSigs == null)    // not a sub-key
+            {
+				foreach (PgpSignature keySig in keySigs)
+				{
+					keySig.Encode(bcpgOut);
+				}
+
+				for (int i = 0; i != ids.Count; i++)
+                {
+                    if (ids[i] is string)
+                    {
+                        string id = (string) ids[i];
+
+						bcpgOut.WritePacket(new UserIdPacket(id));
+                    }
+                    else
+                    {
+                        PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector)ids[i];
+                        bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
+                    }
+
+					if (idTrusts[i] != null)
+                    {
+                        bcpgOut.WritePacket((ContainedPacket)idTrusts[i]);
+                    }
+
+					foreach (PgpSignature sig in (IList) idSigs[i])
+					{
+						sig.Encode(bcpgOut);
+					}
+                }
+            }
+            else
+            {
+				foreach (PgpSignature subSig in subSigs)
+				{
+					subSig.Encode(bcpgOut);
+				}
+            }
+        }
+
+		/// <summary>Check whether this (sub)key has a revocation signature on it.</summary>
+		/// <returns>True, if this (sub)key has been revoked.</returns>
+        public bool IsRevoked()
+        {
+            int ns = 0;
+            bool revoked = false;
+            if (IsMasterKey)	// Master key
+            {
+                while (!revoked && (ns < keySigs.Count))
+                {
+                    if (((PgpSignature)keySigs[ns++]).SignatureType == PgpSignature.KeyRevocation)
+                    {
+                        revoked = true;
+                    }
+                }
+            }
+            else	// Sub-key
+            {
+                while (!revoked && (ns < subSigs.Count))
+                {
+                    if (((PgpSignature)subSigs[ns++]).SignatureType == PgpSignature.SubkeyRevocation)
+                    {
+                        revoked = true;
+                    }
+                }
+            }
+            return revoked;
+        }
+
+		/// <summary>Add a certification for an id to the given public key.</summary>
+		/// <param name="key">The key the certification is to be added to.</param>
+		/// <param name="id">The ID the certification is associated with.</param>
+		/// <param name="certification">The new certification.</param>
+		/// <returns>The re-certified key.</returns>
+        public static PgpPublicKey AddCertification(
+            PgpPublicKey	key,
+            string			id,
+            PgpSignature	certification)
+        {
+			return AddCert(key, id, certification);
+		}
+
+		/// <summary>Add a certification for the given UserAttributeSubpackets to the given public key.</summary>
+		/// <param name="key">The key the certification is to be added to.</param>
+		/// <param name="userAttributes">The attributes the certification is associated with.</param>
+		/// <param name="certification">The new certification.</param>
+		/// <returns>The re-certified key.</returns>
+		public static PgpPublicKey AddCertification(
+			PgpPublicKey					key,
+			PgpUserAttributeSubpacketVector	userAttributes,
+			PgpSignature					certification)
+		{
+			return AddCert(key, userAttributes, certification);
+		}
+
+		private static PgpPublicKey AddCert(
+			PgpPublicKey	key,
+			object			id,
+			PgpSignature	certification)
+		{
+			PgpPublicKey returnKey = new PgpPublicKey(key);
+			IList sigList = null;
+
+			for (int i = 0; i != returnKey.ids.Count; i++)
+			{
+				if (id.Equals(returnKey.ids[i]))
+				{
+					sigList = (IList) returnKey.idSigs[i];
+				}
+			}
+
+			if (sigList != null)
+			{
+				sigList.Add(certification);
+			}
+			else
+			{
+				sigList = Platform.CreateArrayList();
+				sigList.Add(certification);
+				returnKey.ids.Add(id);
+				returnKey.idTrusts.Add(null);
+				returnKey.idSigs.Add(sigList);
+			}
+
+			return returnKey;
+		}
+
+		/// <summary>
+		/// Remove any certifications associated with a user attribute subpacket on a key.
+		/// </summary>
+		/// <param name="key">The key the certifications are to be removed from.</param>
+		/// <param name="userAttributes">The attributes to be removed.</param>
+		/// <returns>
+		/// The re-certified key, or null if the user attribute subpacket was not found on the key.
+		/// </returns>
+		public static PgpPublicKey RemoveCertification(
+			PgpPublicKey					key,
+			PgpUserAttributeSubpacketVector	userAttributes)
+		{
+			return RemoveCert(key, userAttributes);
+		}
+
+		/// <summary>Remove any certifications associated with a given ID on a key.</summary>
+		/// <param name="key">The key the certifications are to be removed from.</param>
+		/// <param name="id">The ID that is to be removed.</param>
+		/// <returns>The re-certified key, or null if the ID was not found on the key.</returns>
+        public static PgpPublicKey RemoveCertification(
+            PgpPublicKey	key,
+            string			id)
+        {
+			return RemoveCert(key, id);
+		}
+
+		private static PgpPublicKey RemoveCert(
+			PgpPublicKey	key,
+			object			id)
+		{
+			PgpPublicKey returnKey = new PgpPublicKey(key);
+            bool found = false;
+
+			for (int i = 0; i < returnKey.ids.Count; i++)
+            {
+                if (id.Equals(returnKey.ids[i]))
+                {
+                    found = true;
+                    returnKey.ids.RemoveAt(i);
+                    returnKey.idTrusts.RemoveAt(i);
+                    returnKey.idSigs.RemoveAt(i);
+                }
+            }
+
+			return found ? returnKey : null;
+        }
+
+		/// <summary>Remove a certification associated with a given ID on a key.</summary>
+		/// <param name="key">The key the certifications are to be removed from.</param>
+		/// <param name="id">The ID that the certfication is to be removed from.</param>
+		/// <param name="certification">The certfication to be removed.</param>
+		/// <returns>The re-certified key, or null if the certification was not found.</returns>
+        public static PgpPublicKey RemoveCertification(
+            PgpPublicKey	key,
+            string			id,
+            PgpSignature	certification)
+        {
+			return RemoveCert(key, id, certification);
+		}
+
+		/// <summary>Remove a certification associated with a given user attributes on a key.</summary>
+		/// <param name="key">The key the certifications are to be removed from.</param>
+		/// <param name="userAttributes">The user attributes that the certfication is to be removed from.</param>
+		/// <param name="certification">The certification to be removed.</param>
+		/// <returns>The re-certified key, or null if the certification was not found.</returns>
+		public static PgpPublicKey RemoveCertification(
+			PgpPublicKey					key,
+			PgpUserAttributeSubpacketVector	userAttributes,
+			PgpSignature					certification)
+		{
+			return RemoveCert(key, userAttributes, certification);
+		}
+
+		private static PgpPublicKey RemoveCert(
+			PgpPublicKey	key,
+			object			id,
+			PgpSignature	certification)
+		{
+			PgpPublicKey returnKey = new PgpPublicKey(key);
+            bool found = false;
+
+			for (int i = 0; i < returnKey.ids.Count; i++)
+            {
+                if (id.Equals(returnKey.ids[i]))
+                {
+                    IList certs = (IList) returnKey.idSigs[i];
+                    found = certs.Contains(certification);
+
+					if (found)
+					{
+						certs.Remove(certification);
+					}
+                }
+            }
+
+			return found ? returnKey : null;
+        }
+
+		/// <summary>Add a revocation or some other key certification to a key.</summary>
+		/// <param name="key">The key the revocation is to be added to.</param>
+		/// <param name="certification">The key signature to be added.</param>
+		/// <returns>The new changed public key object.</returns>
+        public static PgpPublicKey AddCertification(
+            PgpPublicKey	key,
+            PgpSignature	certification)
+        {
+            if (key.IsMasterKey)
+            {
+                if (certification.SignatureType == PgpSignature.SubkeyRevocation)
+                {
+                    throw new ArgumentException("signature type incorrect for master key revocation.");
+                }
+            }
+            else
+            {
+                if (certification.SignatureType == PgpSignature.KeyRevocation)
+                {
+                    throw new ArgumentException("signature type incorrect for sub-key revocation.");
+                }
+            }
+
+			PgpPublicKey returnKey = new PgpPublicKey(key);
+
+			if (returnKey.subSigs != null)
+            {
+                returnKey.subSigs.Add(certification);
+            }
+            else
+            {
+                returnKey.keySigs.Add(certification);
+            }
+
+			return returnKey;
+        }
+
+		/// <summary>Remove a certification from the key.</summary>
+		/// <param name="key">The key the certifications are to be removed from.</param>
+		/// <param name="certification">The certfication to be removed.</param>
+		/// <returns>The modified key, null if the certification was not found.</returns>
+		public static PgpPublicKey RemoveCertification(
+			PgpPublicKey	key,
+			PgpSignature	certification)
+		{
+			PgpPublicKey returnKey = new PgpPublicKey(key);
+			IList sigs = returnKey.subSigs != null
+				?	returnKey.subSigs
+				:	returnKey.keySigs;
+
+//			bool found = sigs.Remove(certification);
+			int pos = sigs.IndexOf(certification);
+			bool found = pos >= 0;
+
+			if (found)
+			{
+				sigs.RemoveAt(pos);
+			}
+			else
+			{
+				foreach (String id in key.GetUserIds())
+				{
+					foreach (object sig in key.GetSignaturesForId(id))
+					{
+						// TODO Is this the right type of equality test?
+						if (certification == sig)
+						{
+							found = true;
+							returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
+						}
+					}
+				}
+
+				if (!found)
+				{
+					foreach (PgpUserAttributeSubpacketVector id in key.GetUserAttributes())
+					{
+						foreach (object sig in key.GetSignaturesForUserAttribute(id))
+						{
+							// TODO Is this the right type of equality test?
+							if (certification == sig)
+							{
+								found = true;
+								returnKey = PgpPublicKey.RemoveCertification(returnKey, id, certification);
+							}
+						}
+					}
+				}
+			}
+
+			return returnKey;
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
new file mode 100644
index 000000000..b6504cbcd
--- /dev/null
+++ b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
@@ -0,0 +1,252 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>A public key encrypted data object.</remarks>
+    public class PgpPublicKeyEncryptedData
+        : PgpEncryptedData
+    {
+        private PublicKeyEncSessionPacket keyData;
+
+		internal PgpPublicKeyEncryptedData(
+            PublicKeyEncSessionPacket	keyData,
+            InputStreamPacket			encData)
+            : base(encData)
+        {
+            this.keyData = keyData;
+        }
+
+		private static IBufferedCipher GetKeyCipher(
+            PublicKeyAlgorithmTag algorithm)
+        {
+            try
+            {
+                switch (algorithm)
+                {
+                    case PublicKeyAlgorithmTag.RsaEncrypt:
+                    case PublicKeyAlgorithmTag.RsaGeneral:
+                        return CipherUtilities.GetCipher("RSA//PKCS1Padding");
+                    case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                    case PublicKeyAlgorithmTag.ElGamalGeneral:
+                        return CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+                    default:
+                        throw new PgpException("unknown asymmetric algorithm: " + algorithm);
+                }
+            }
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception creating cipher", e);
+            }
+        }
+
+		private bool ConfirmCheckSum(
+            byte[] sessionInfo)
+        {
+            int check = 0;
+
+			for (int i = 1; i != sessionInfo.Length - 2; i++)
+            {
+                check += sessionInfo[i] & 0xff;
+            }
+
+			return (sessionInfo[sessionInfo.Length - 2] == (byte)(check >> 8))
+                && (sessionInfo[sessionInfo.Length - 1] == (byte)(check));
+        }
+
+		/// <summary>The key ID for the key used to encrypt the data.</summary>
+        public long KeyId
+        {
+			get { return keyData.KeyId; }
+        }
+
+		/// <summary>
+		/// Return the algorithm code for the symmetric algorithm used to encrypt the data.
+		/// </summary>
+		public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm(
+			PgpPrivateKey privKey)
+		{
+			byte[] plain = fetchSymmetricKeyData(privKey);
+
+			return (SymmetricKeyAlgorithmTag) plain[0];
+		}
+
+		/// <summary>Return the decrypted data stream for the packet.</summary>
+        public Stream GetDataStream(
+            PgpPrivateKey privKey)
+        {
+			byte[] plain = fetchSymmetricKeyData(privKey);
+
+			IBufferedCipher c2;
+			string cipherName = PgpUtilities.GetSymmetricCipherName((SymmetricKeyAlgorithmTag) plain[0]);
+			string cName = cipherName;
+
+			try
+            {
+                if (encData is SymmetricEncIntegrityPacket)
+                {
+					cName += "/CFB/NoPadding";
+                }
+                else
+                {
+					cName += "/OpenPGPCFB/NoPadding";
+                }
+
+				c2 = CipherUtilities.GetCipher(cName);
+			}
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("exception creating cipher", e);
+            }
+
+			if (c2 == null)
+				return encData.GetInputStream();
+
+			try
+            {
+				KeyParameter key = ParameterUtilities.CreateKeyParameter(
+					cipherName, plain, 1, plain.Length - 3);
+
+				byte[] iv = new byte[c2.GetBlockSize()];
+
+				c2.Init(false, new ParametersWithIV(key, iv));
+
+                encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c2, null));
+
+				if (encData is SymmetricEncIntegrityPacket)
+                {
+                    truncStream = new TruncatedStream(encStream);
+
+					string digestName = PgpUtilities.GetDigestName(HashAlgorithmTag.Sha1);
+					IDigest digest = DigestUtilities.GetDigest(digestName);
+
+					encStream = new DigestStream(truncStream, digest, null);
+                }
+
+				if (Streams.ReadFully(encStream, iv, 0, iv.Length) < iv.Length)
+					throw new EndOfStreamException("unexpected end of stream.");
+
+				int v1 = encStream.ReadByte();
+                int v2 = encStream.ReadByte();
+
+				if (v1 < 0 || v2 < 0)
+                    throw new EndOfStreamException("unexpected end of stream.");
+
+				// Note: the oracle attack on the "quick check" bytes is deemed
+				// a security risk for typical public key encryption usages,
+				// therefore we do not perform the check.
+
+//				bool repeatCheckPassed =
+//					iv[iv.Length - 2] == (byte)v1
+//					&&	iv[iv.Length - 1] == (byte)v2;
+//
+//				// Note: some versions of PGP appear to produce 0 for the extra
+//				// bytes rather than repeating the two previous bytes
+//				bool zeroesCheckPassed =
+//					v1 == 0
+//					&&	v2 == 0;
+//
+//				if (!repeatCheckPassed && !zeroesCheckPassed)
+//				{
+//					throw new PgpDataValidationException("quick check failed.");
+//				}
+
+				return encStream;
+            }
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception starting decryption", e);
+            }
+		}
+
+		private byte[] fetchSymmetricKeyData(
+			PgpPrivateKey privKey)
+		{
+			IBufferedCipher c1 = GetKeyCipher(keyData.Algorithm);
+
+			try
+			{
+				c1.Init(false, privKey.Key);
+			}
+			catch (InvalidKeyException e)
+			{
+				throw new PgpException("error setting asymmetric cipher", e);
+			}
+
+			BigInteger[] keyD = keyData.GetEncSessionKey();
+
+			if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
+				|| keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
+			{
+				c1.ProcessBytes(keyD[0].ToByteArrayUnsigned());
+			}
+			else
+			{
+				ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key;
+				int size = (k.Parameters.P.BitLength + 7) / 8;
+
+				byte[] bi = keyD[0].ToByteArray();
+
+				int diff = bi.Length - size;
+				if (diff >= 0)
+				{
+					c1.ProcessBytes(bi, diff, size);
+				}
+				else
+				{
+					byte[] zeros = new byte[-diff];
+					c1.ProcessBytes(zeros);
+					c1.ProcessBytes(bi);
+				}
+
+				bi = keyD[1].ToByteArray();
+
+				diff = bi.Length - size;
+				if (diff >= 0)
+				{
+					c1.ProcessBytes(bi, diff, size);
+				}
+				else
+				{
+					byte[] zeros = new byte[-diff];
+					c1.ProcessBytes(zeros);
+					c1.ProcessBytes(bi);
+				}
+			}
+
+			byte[] plain;
+			try
+			{
+				plain = c1.DoFinal();
+			}
+			catch (Exception e)
+			{
+				throw new PgpException("exception decrypting secret key", e);
+			}
+
+			if (!ConfirmCheckSum(plain))
+				throw new PgpKeyValidationException("key checksum failed");
+
+			return plain;
+		}
+	}
+}
diff --git a/crypto/src/openpgp/PgpPublicKeyRing.cs b/crypto/src/openpgp/PgpPublicKeyRing.cs
index ecb935e4b..7b1ac93bf 100644
--- a/crypto/src/openpgp/PgpPublicKeyRing.cs
+++ b/crypto/src/openpgp/PgpPublicKeyRing.cs
@@ -7,164 +7,164 @@ using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
-	/// <remarks>
-	/// Class to hold a single master public key and its subkeys.
-	/// <p>
-	/// Often PGP keyring files consist of multiple master keys, if you are trying to process
-	/// or construct one of these you should use the <c>PgpPublicKeyRingBundle</c> class.
-	/// </p>
-	/// </remarks>
-	public class PgpPublicKeyRing
-		: PgpKeyRing
+    /// <remarks>
+    /// Class to hold a single master public key and its subkeys.
+    /// <p>
+    /// Often PGP keyring files consist of multiple master keys, if you are trying to process
+    /// or construct one of these you should use the <c>PgpPublicKeyRingBundle</c> class.
+    /// </p>
+    /// </remarks>
+    public class PgpPublicKeyRing
+        : PgpKeyRing
     {
         private readonly IList keys;
 
-		public PgpPublicKeyRing(
+        public PgpPublicKeyRing(
             byte[] encoding)
             : this(new MemoryStream(encoding, false))
         {
         }
 
-		internal PgpPublicKeyRing(
+        internal PgpPublicKeyRing(
             IList pubKeys)
         {
             this.keys = pubKeys;
         }
 
-		public PgpPublicKeyRing(
+        public PgpPublicKeyRing(
             Stream inputStream)
         {
-			this.keys = Platform.CreateArrayList();
+            this.keys = Platform.CreateArrayList();
 
             BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
 
-			PacketTag initialTag = bcpgInput.NextPacketTag();
+            PacketTag initialTag = bcpgInput.NextPacketTag();
             if (initialTag != PacketTag.PublicKey && initialTag != PacketTag.PublicSubkey)
             {
                 throw new IOException("public key ring doesn't start with public key tag: "
-					+ "tag 0x" + ((int)initialTag).ToString("X"));
+                    + "tag 0x" + ((int)initialTag).ToString("X"));
             }
 
-			PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
-			TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
+            PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
+            TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
 
             // direct signatures and revocations
-			IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+            IList keySigs = ReadSignaturesAndTrust(bcpgInput);
 
-			IList ids, idTrusts, idSigs;
-			ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+            IList ids, idTrusts, idSigs;
+            ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
 
-			keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
+            keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
 
 
-			// Read subkeys
-			while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+            // Read subkeys
+            while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
             {
-				keys.Add(ReadSubkey(bcpgInput));
+                keys.Add(ReadSubkey(bcpgInput));
             }
         }
 
-		/// <summary>Return the first public key in the ring.</summary>
-        public PgpPublicKey GetPublicKey()
+        /// <summary>Return the first public key in the ring.</summary>
+        public virtual PgpPublicKey GetPublicKey()
         {
             return (PgpPublicKey) keys[0];
         }
 
-		/// <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
-        public PgpPublicKey GetPublicKey(
+        /// <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
+        public virtual PgpPublicKey GetPublicKey(
             long keyId)
         {
-			foreach (PgpPublicKey k in keys)
-			{
-				if (keyId == k.KeyId)
+            foreach (PgpPublicKey k in keys)
+            {
+                if (keyId == k.KeyId)
                 {
                     return k;
                 }
             }
 
-			return null;
+            return null;
         }
 
-		/// <summary>Allows enumeration of all the public keys.</summary>
-		/// <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
-        public IEnumerable GetPublicKeys()
+        /// <summary>Allows enumeration of all the public keys.</summary>
+        /// <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
+        public virtual IEnumerable GetPublicKeys()
         {
             return new EnumerableProxy(keys);
         }
 
-		public byte[] GetEncoded()
+        public virtual byte[] GetEncoded()
         {
             MemoryStream bOut = new MemoryStream();
 
-			Encode(bOut);
+            Encode(bOut);
 
-			return bOut.ToArray();
+            return bOut.ToArray();
         }
 
-		public void Encode(
+        public virtual void Encode(
             Stream outStr)
         {
-			if (outStr == null)
-				throw new ArgumentNullException("outStr");
+            if (outStr == null)
+                throw new ArgumentNullException("outStr");
 
-			foreach (PgpPublicKey k in keys)
-			{
-				k.Encode(outStr);
+            foreach (PgpPublicKey k in keys)
+            {
+                k.Encode(outStr);
             }
         }
 
-		/// <summary>
-		/// Returns a new key ring with the public key passed in either added or
-		/// replacing an existing one.
-		/// </summary>
-		/// <param name="pubRing">The public key ring to be modified.</param>
-		/// <param name="pubKey">The public key to be inserted.</param>
-		/// <returns>A new <c>PgpPublicKeyRing</c></returns>
+        /// <summary>
+        /// Returns a new key ring with the public key passed in either added or
+        /// replacing an existing one.
+        /// </summary>
+        /// <param name="pubRing">The public key ring to be modified.</param>
+        /// <param name="pubKey">The public key to be inserted.</param>
+        /// <returns>A new <c>PgpPublicKeyRing</c></returns>
         public static PgpPublicKeyRing InsertPublicKey(
             PgpPublicKeyRing	pubRing,
             PgpPublicKey		pubKey)
         {
             IList keys = Platform.CreateArrayList(pubRing.keys);
             bool found = false;
-			bool masterFound = false;
+            bool masterFound = false;
 
-			for (int i = 0; i != keys.Count; i++)
+            for (int i = 0; i != keys.Count; i++)
             {
                 PgpPublicKey key = (PgpPublicKey) keys[i];
 
-				if (key.KeyId == pubKey.KeyId)
+                if (key.KeyId == pubKey.KeyId)
                 {
                     found = true;
                     keys[i] = pubKey;
                 }
-				if (key.IsMasterKey)
-				{
-					masterFound = true;
-				}
-			}
+                if (key.IsMasterKey)
+                {
+                    masterFound = true;
+                }
+            }
 
-			if (!found)
+            if (!found)
             {
-				if (pubKey.IsMasterKey)
-				{
-					if (masterFound)
-						throw new ArgumentException("cannot add a master key to a ring that already has one");
-
-					keys.Insert(0, pubKey);
-				}
-				else
-				{
-					keys.Add(pubKey);
-				}
-			}
-
-			return new PgpPublicKeyRing(keys);
+                if (pubKey.IsMasterKey)
+                {
+                    if (masterFound)
+                        throw new ArgumentException("cannot add a master key to a ring that already has one");
+
+                    keys.Insert(0, pubKey);
+                }
+                else
+                {
+                    keys.Add(pubKey);
+                }
+            }
+
+            return new PgpPublicKeyRing(keys);
         }
 
-		/// <summary>Returns a new key ring with the public key passed in removed from the key ring.</summary>
-		/// <param name="pubRing">The public key ring to be modified.</param>
-		/// <param name="pubKey">The public key to be removed.</param>
-		/// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns>
+        /// <summary>Returns a new key ring with the public key passed in removed from the key ring.</summary>
+        /// <param name="pubRing">The public key ring to be modified.</param>
+        /// <param name="pubKey">The public key to be removed.</param>
+        /// <returns>A new <c>PgpPublicKeyRing</c>, or null if pubKey is not found.</returns>
         public static PgpPublicKeyRing RemovePublicKey(
             PgpPublicKeyRing	pubRing,
             PgpPublicKey		pubKey)
@@ -172,29 +172,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             IList keys = Platform.CreateArrayList(pubRing.keys);
             bool found = false;
 
-			for (int i = 0; i < keys.Count; i++)
+            for (int i = 0; i < keys.Count; i++)
             {
                 PgpPublicKey key = (PgpPublicKey) keys[i];
 
-				if (key.KeyId == pubKey.KeyId)
+                if (key.KeyId == pubKey.KeyId)
                 {
                     found = true;
                     keys.RemoveAt(i);
                 }
             }
 
-			return found ? new PgpPublicKeyRing(keys) : null;
+            return found ? new PgpPublicKeyRing(keys) : null;
         }
 
-		internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
-		{
+        internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
+        {
             PublicKeyPacket	pk = (PublicKeyPacket) bcpgInput.ReadPacket();
-			TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
+            TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
 
-			// PGP 8 actually leaves out the signature.
-			IList sigList = ReadSignaturesAndTrust(bcpgInput);
+            // PGP 8 actually leaves out the signature.
+            IList sigList = ReadSignaturesAndTrust(bcpgInput);
 
-			return new PgpPublicKey(pk, kTrust, sigList);
-		}
+            return new PgpPublicKey(pk, kTrust, sigList);
+        }
     }
 }
diff --git a/crypto/src/openpgp/PgpPublicKeyRingBundle.cs b/crypto/src/openpgp/PgpPublicKeyRingBundle.cs
index 77cede4a1..519a2f884 100644
--- a/crypto/src/openpgp/PgpPublicKeyRingBundle.cs
+++ b/crypto/src/openpgp/PgpPublicKeyRingBundle.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 using System.IO;
 
 using Org.BouncyCastle.Utilities;
@@ -114,7 +113,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 			if (ignoreCase)
 			{
-				userId = userId.ToLowerInvariant();
+                userId = Platform.ToLowerInvariant(userId);
 			}
 
 			foreach (PgpPublicKeyRing pubRing in GetKeyRings())
@@ -124,8 +123,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 					string next = nextUserID;
 					if (ignoreCase)
 					{
-						next = next.ToLowerInvariant();
-					}
+                        next = Platform.ToLowerInvariant(next);
+                    }
 
 					if (matchPartial)
 					{
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs
index 9d87f49c8..872316dd7 100644
--- a/crypto/src/openpgp/PgpSecretKey.cs
+++ b/crypto/src/openpgp/PgpSecretKey.cs
@@ -5,112 +5,121 @@ using System.IO;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
-	/// <remarks>General class to handle a PGP secret key object.</remarks>
+    /// <remarks>General class to handle a PGP secret key object.</remarks>
     public class PgpSecretKey
     {
         private readonly SecretKeyPacket	secret;
         private readonly PgpPublicKey		pub;
 
-		internal PgpSecretKey(
-			SecretKeyPacket	secret,
-			PgpPublicKey	pub)
-		{
-			this.secret = secret;
-			this.pub = pub;
-		}
-
-		internal PgpSecretKey(
-			PgpPrivateKey				privKey,
-			PgpPublicKey				pubKey,
-			SymmetricKeyAlgorithmTag	encAlgorithm,
-			char[]						passPhrase,
-			bool						useSha1,
-			SecureRandom				rand)
-			: this(privKey, pubKey, encAlgorithm, passPhrase, useSha1, rand, false)
-		{
-		}
-
-		internal PgpSecretKey(
-			PgpPrivateKey				privKey,
-			PgpPublicKey				pubKey,
-			SymmetricKeyAlgorithmTag	encAlgorithm,
+        internal PgpSecretKey(
+            SecretKeyPacket	secret,
+            PgpPublicKey	pub)
+        {
+            this.secret = secret;
+            this.pub = pub;
+        }
+
+        internal PgpSecretKey(
+            PgpPrivateKey				privKey,
+            PgpPublicKey				pubKey,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
             char[]						passPhrase,
-			bool						useSha1,
-			SecureRandom				rand,
-			bool						isMasterKey)
+            bool						useSha1,
+            SecureRandom				rand)
+            : this(privKey, pubKey, encAlgorithm, passPhrase, useSha1, rand, false)
         {
-			BcpgObject secKey;
+        }
 
-			this.pub = pubKey;
+        internal PgpSecretKey(
+            PgpPrivateKey				privKey,
+            PgpPublicKey				pubKey,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+            bool						useSha1,
+            SecureRandom				rand,
+            bool						isMasterKey)
+        {
+            BcpgObject secKey;
 
-			switch (pubKey.Algorithm)
+            this.pub = pubKey;
+
+            switch (pubKey.Algorithm)
             {
-				case PublicKeyAlgorithmTag.RsaEncrypt:
-				case PublicKeyAlgorithmTag.RsaSign:
-				case PublicKeyAlgorithmTag.RsaGeneral:
-					RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) privKey.Key;
-					secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q);
-					break;
-				case PublicKeyAlgorithmTag.Dsa:
-					DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) privKey.Key;
-					secKey = new DsaSecretBcpgKey(dsK.X);
-					break;
-				case PublicKeyAlgorithmTag.ElGamalEncrypt:
-				case PublicKeyAlgorithmTag.ElGamalGeneral:
-					ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key;
-					secKey = new ElGamalSecretBcpgKey(esK.X);
-					break;
-				default:
-					throw new PgpException("unknown key class");
+                case PublicKeyAlgorithmTag.RsaEncrypt:
+                case PublicKeyAlgorithmTag.RsaSign:
+                case PublicKeyAlgorithmTag.RsaGeneral:
+                    RsaPrivateCrtKeyParameters rsK = (RsaPrivateCrtKeyParameters) privKey.Key;
+                    secKey = new RsaSecretBcpgKey(rsK.Exponent, rsK.P, rsK.Q);
+                    break;
+                case PublicKeyAlgorithmTag.Dsa:
+                    DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) privKey.Key;
+                    secKey = new DsaSecretBcpgKey(dsK.X);
+                    break;
+                case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                case PublicKeyAlgorithmTag.ElGamalGeneral:
+                    ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key;
+                    secKey = new ElGamalSecretBcpgKey(esK.X);
+                    break;
+                default:
+                    throw new PgpException("unknown key class");
             }
 
-			try
+            try
             {
                 MemoryStream bOut = new MemoryStream();
                 BcpgOutputStream pOut = new BcpgOutputStream(bOut);
 
-				pOut.WriteObject(secKey);
-
-				byte[] keyData = bOut.ToArray();
-				byte[] checksumBytes = Checksum(useSha1, keyData, keyData.Length);
+                pOut.WriteObject(secKey);
 
-				pOut.Write(checksumBytes);
+                byte[] keyData = bOut.ToArray();
+                byte[] checksumData = Checksum(useSha1, keyData, keyData.Length);
 
-				byte[] bOutData = bOut.ToArray();
+                keyData = Arrays.Concatenate(keyData, checksumData);
 
-				if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
-				{
-					if (isMasterKey)
-					{
-						this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, bOutData);
-					}
-					else
-					{
-						this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, bOutData);
-					}
-				}
-				else
+                if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
                 {
-					S2k s2k;
-					byte[] iv;
-					byte[] encData = EncryptKeyData(bOutData, encAlgorithm, passPhrase, rand, out s2k, out iv);
-
-					int s2kUsage = useSha1
-						?	SecretKeyPacket.UsageSha1
-						:	SecretKeyPacket.UsageChecksum;
-
-					if (isMasterKey)
-					{
-						this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData);
-					}
-					else
-					{
-						this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData);
-					}
-				}
+                    if (isMasterKey)
+                    {
+                        this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, null, null, keyData);
+                    }
+                    else
+                    {
+                        this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, null, null, keyData);
+                    }
+                }
+                else
+                {
+                    S2k s2k;
+                    byte[] iv;
+
+                    byte[] encData;
+                    if (pub.Version >= 4)
+                    {
+                        encData = EncryptKeyData(keyData, encAlgorithm, passPhrase, rand, out s2k, out iv);
+                    }
+                    else
+                    {
+                        // TODO v3 RSA key encryption
+                        throw Platform.CreateNotImplementedException("v3 RSA");
+                    }
+
+                    int s2kUsage = useSha1
+                        ?	SecretKeyPacket.UsageSha1
+                        :	SecretKeyPacket.UsageChecksum;
+
+                    if (isMasterKey)
+                    {
+                        this.secret = new SecretKeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData);
+                    }
+                    else
+                    {
+                        this.secret = new SecretSubkeyPacket(pub.publicPk, encAlgorithm, s2kUsage, s2k, iv, encData);
+                    }
+                }
             }
             catch (PgpException e)
             {
@@ -122,7 +131,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
-		public PgpSecretKey(
+        public PgpSecretKey(
             int							certificationLevel,
             PgpKeyPair					keyPair,
             string						id,
@@ -131,61 +140,61 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             PgpSignatureSubpacketVector	hashedPackets,
             PgpSignatureSubpacketVector	unhashedPackets,
             SecureRandom				rand)
-			: this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
-		{
-		}
-
-		public PgpSecretKey(
-			int							certificationLevel,
-			PgpKeyPair					keyPair,
-			string						id,
-			SymmetricKeyAlgorithmTag	encAlgorithm,
-			char[]						passPhrase,
-			bool						useSha1,
-			PgpSignatureSubpacketVector	hashedPackets,
-			PgpSignatureSubpacketVector	unhashedPackets,
-			SecureRandom				rand)
-			: this(keyPair.PrivateKey, certifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, passPhrase, useSha1, rand, true)
-		{
-		}
-
-		private static PgpPublicKey certifiedPublicKey(
-			int							certificationLevel,
-			PgpKeyPair					keyPair,
-			string						id,
-			PgpSignatureSubpacketVector	hashedPackets,
-			PgpSignatureSubpacketVector	unhashedPackets)
-		{
-			PgpSignatureGenerator sGen;
-			try
-			{
-				sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
-			}
-			catch (Exception e)
-			{
-				throw new PgpException("Creating signature generator: " + e.Message, e);
-			}
-
-			//
-			// Generate the certification
-			//
-			sGen.InitSign(certificationLevel, keyPair.PrivateKey);
-
-			sGen.SetHashedSubpackets(hashedPackets);
-			sGen.SetUnhashedSubpackets(unhashedPackets);
-
-			try
+            : this(certificationLevel, keyPair, id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        public PgpSecretKey(
+            int							certificationLevel,
+            PgpKeyPair					keyPair,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+            bool						useSha1,
+            PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+            : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, passPhrase, useSha1, rand, true)
+        {
+        }
+
+        private static PgpPublicKey CertifiedPublicKey(
+            int							certificationLevel,
+            PgpKeyPair					keyPair,
+            string						id,
+            PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets)
+        {
+            PgpSignatureGenerator sGen;
+            try
             {
-				PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
+                sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Creating signature generator: " + e.Message, e);
+            }
+
+            //
+            // Generate the certification
+            //
+            sGen.InitSign(certificationLevel, keyPair.PrivateKey);
+
+            sGen.SetHashedSubpackets(hashedPackets);
+            sGen.SetUnhashedSubpackets(unhashedPackets);
+
+            try
+            {
+                PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey);
                 return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification);
             }
             catch (Exception e)
             {
-				throw new PgpException("Exception doing certification: " + e.Message, e);
-			}
+                throw new PgpException("Exception doing certification: " + e.Message, e);
+            }
         }
 
-		public PgpSecretKey(
+        public PgpSecretKey(
             int							certificationLevel,
             PublicKeyAlgorithmTag		algorithm,
             AsymmetricKeyParameter		pubKey,
@@ -203,181 +212,199 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
         }
 
-		public PgpSecretKey(
-			int							certificationLevel,
-			PublicKeyAlgorithmTag		algorithm,
-			AsymmetricKeyParameter		pubKey,
-			AsymmetricKeyParameter		privKey,
-			DateTime					time,
-			string						id,
-			SymmetricKeyAlgorithmTag	encAlgorithm,
-			char[]						passPhrase,
-			bool						useSha1,
-			PgpSignatureSubpacketVector	hashedPackets,
-			PgpSignatureSubpacketVector	unhashedPackets,
-			SecureRandom				rand)
-			: this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
-		{
-		}
-
-		/// <summary>
-		/// Check if this key has an algorithm type that makes it suitable to use for signing.
-		/// </summary>
-		/// <remarks>
-		/// Note: with version 4 keys KeyFlags subpackets should also be considered when present for
-		/// determining the preferred use of the key.
-		/// </remarks>
-		/// <returns>
-		/// <c>true</c> if this key algorithm is suitable for use with signing.
-		/// </returns>
-		public bool IsSigningKey
+        public PgpSecretKey(
+            int							certificationLevel,
+            PublicKeyAlgorithmTag		algorithm,
+            AsymmetricKeyParameter		pubKey,
+            AsymmetricKeyParameter		privKey,
+            DateTime					time,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+            bool						useSha1,
+            PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+            : this(certificationLevel, new PgpKeyPair(algorithm, pubKey, privKey, time), id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
         {
-			get
-			{
-				switch (pub.Algorithm)
-				{
-					case PublicKeyAlgorithmTag.RsaGeneral:
-					case PublicKeyAlgorithmTag.RsaSign:
-					case PublicKeyAlgorithmTag.Dsa:
-					case PublicKeyAlgorithmTag.ECDsa:
-					case PublicKeyAlgorithmTag.ElGamalGeneral:
-						return true;
-					default:
-						return false;
-				}
-			}
         }
 
-		/// <summary>True, if this is a master key.</summary>
+        /// <summary>
+        /// Check if this key has an algorithm type that makes it suitable to use for signing.
+        /// </summary>
+        /// <remarks>
+        /// Note: with version 4 keys KeyFlags subpackets should also be considered when present for
+        /// determining the preferred use of the key.
+        /// </remarks>
+        /// <returns>
+        /// <c>true</c> if this key algorithm is suitable for use with signing.
+        /// </returns>
+        public bool IsSigningKey
+        {
+            get
+            {
+                switch (pub.Algorithm)
+                {
+                    case PublicKeyAlgorithmTag.RsaGeneral:
+                    case PublicKeyAlgorithmTag.RsaSign:
+                    case PublicKeyAlgorithmTag.Dsa:
+                    case PublicKeyAlgorithmTag.ECDsa:
+                    case PublicKeyAlgorithmTag.ElGamalGeneral:
+                        return true;
+                    default:
+                        return false;
+                }
+            }
+        }
+
+        /// <summary>True, if this is a master key.</summary>
         public bool IsMasterKey
-		{
-			get { return pub.IsMasterKey; }
+        {
+            get { return pub.IsMasterKey; }
+        }
+
+        /// <summary>Detect if the Secret Key's Private Key is empty or not</summary>
+        public bool IsPrivateKeyEmpty
+        {
+            get
+            {
+                byte[] secKeyData = secret.GetSecretKeyData();
+
+                return secKeyData == null || secKeyData.Length < 1;
+            }
         }
 
-		/// <summary>The algorithm the key is encrypted with.</summary>
+        /// <summary>The algorithm the key is encrypted with.</summary>
         public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm
         {
-			get { return secret.EncAlgorithm; }
+            get { return secret.EncAlgorithm; }
         }
 
-		/// <summary>The key ID of the public key associated with this key.</summary>
+        /// <summary>The key ID of the public key associated with this key.</summary>
         public long KeyId
         {
             get { return pub.KeyId; }
         }
 
-		/// <summary>The public key associated with this key.</summary>
+        /// <summary>The public key associated with this key.</summary>
         public PgpPublicKey PublicKey
         {
-			get { return pub; }
+            get { return pub; }
         }
 
-		/// <summary>Allows enumeration of any user IDs associated with the key.</summary>
-		/// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        /// <summary>Allows enumeration of any user IDs associated with the key.</summary>
+        /// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
         public IEnumerable UserIds
         {
-			get { return pub.GetUserIds(); }
+            get { return pub.GetUserIds(); }
         }
 
-		/// <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
-		/// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        /// <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
+        /// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
         public IEnumerable UserAttributes
         {
-			get { return pub.GetUserAttributes(); }
+            get { return pub.GetUserAttributes(); }
         }
 
-		private byte[] ExtractKeyData(
+        private byte[] ExtractKeyData(
             char[] passPhrase)
         {
             SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm;
-			byte[] encData = secret.GetSecretKeyData();
-
-			if (alg == SymmetricKeyAlgorithmTag.Null)
-				return encData;
-
-			byte[] data;
-			IBufferedCipher c = null;
-			try
-			{
-				string cName = PgpUtilities.GetSymmetricCipherName(alg);
-				c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
-			}
-			catch (Exception e)
-			{
-				throw new PgpException("Exception creating cipher", e);
-			}
-
-			// TODO Factor this block out as 'encryptData'
-			try
+            byte[] encData = secret.GetSecretKeyData();
+
+            if (alg == SymmetricKeyAlgorithmTag.Null)
+                // TODO Check checksum here?
+                return encData;
+
+            IBufferedCipher c = null;
+            try
+            {
+                string cName = PgpUtilities.GetSymmetricCipherName(alg);
+                c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception creating cipher", e);
+            }
+
+            // TODO Factor this block out as 'decryptData'
+            try
             {
-				KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase);
-				byte[] iv = secret.GetIV();
+                KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase);
+                byte[] iv = secret.GetIV();
+                byte[] data;
 
-				if (secret.PublicKeyPacket.Version == 4)
+                if (secret.PublicKeyPacket.Version >= 4)
                 {
-					c.Init(false, new ParametersWithIV(key, iv));
+                    c.Init(false, new ParametersWithIV(key, iv));
 
-					data = c.DoFinal(encData);
+                    data = c.DoFinal(encData);
 
-					bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
-					byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2);
+                    bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
+                    byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2);
 
-					for (int i = 0; i != check.Length; i++)
-					{
-						if (check[i] != data[data.Length - check.Length + i])
-						{
-							throw new PgpException("Checksum mismatch at " + i + " of " + check.Length);
-						}
-					}
-				}
+                    for (int i = 0; i != check.Length; i++)
+                    {
+                        if (check[i] != data[data.Length - check.Length + i])
+                        {
+                            throw new PgpException("Checksum mismatch at " + i + " of " + check.Length);
+                        }
+                    }
+                }
                 else // version 2 or 3, RSA only.
                 {
-					data = new byte[encData.Length];
+                    data = new byte[encData.Length];
+
+                    iv = Arrays.Clone(iv);
 
-					//
+                    //
                     // read in the four numbers
                     //
                     int pos = 0;
 
-					for (int i = 0; i != 4; i++)
+                    for (int i = 0; i != 4; i++)
                     {
                         c.Init(false, new ParametersWithIV(key, iv));
 
-						int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
+                        int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
 
-						data[pos] = encData[pos];
-						data[pos + 1] = encData[pos + 1];
-						pos += 2;
+                        data[pos] = encData[pos];
+                        data[pos + 1] = encData[pos + 1];
+                        pos += 2;
 
-						c.DoFinal(encData, pos, encLen, data, pos);
-						pos += encLen;
+                        c.DoFinal(encData, pos, encLen, data, pos);
+                        pos += encLen;
 
-						if (i != 3)
+                        if (i != 3)
                         {
                             Array.Copy(encData, pos - iv.Length, iv, 0, iv.Length);
                         }
                     }
 
-					//
-                    // verify Checksum
                     //
-					int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
+                    // verify and copy checksum
+                    //
+
+                    data[pos] = encData[pos];
+                    data[pos + 1] = encData[pos + 1];
+
+                    int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff);
                     int calcCs = 0;
-                    for (int j=0; j < data.Length-2; j++)
+                    for (int j = 0; j < pos; j++)
                     {
                         calcCs += data[j] & 0xff;
                     }
 
-					calcCs &= 0xffff;
+                    calcCs &= 0xffff;
                     if (calcCs != cs)
                     {
                         throw new PgpException("Checksum mismatch: passphrase wrong, expected "
-							+ cs.ToString("X")
-							+ " found " + calcCs.ToString("X"));
+                            + cs.ToString("X")
+                            + " found " + calcCs.ToString("X"));
                     }
                 }
 
-				return data;
+                return data;
             }
             catch (PgpException e)
             {
@@ -389,15 +416,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
-		/// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
+        /// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
         public PgpPrivateKey ExtractPrivateKey(
             char[] passPhrase)
         {
-			byte[] secKeyData = secret.GetSecretKeyData();
-            if (secKeyData == null || secKeyData.Length < 1)
+            if (IsPrivateKeyEmpty)
                 return null;
 
-			PublicKeyPacket pubPk = secret.PublicKeyPacket;
+            PublicKeyPacket pubPk = secret.PublicKeyPacket;
             try
             {
                 byte[] data = ExtractKeyData(passPhrase);
@@ -438,7 +464,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                     throw new PgpException("unknown public key algorithm encountered");
                 }
 
-				return new PgpPrivateKey(privateKey, KeyId);
+                return new PgpPrivateKey(privateKey, KeyId);
             }
             catch (PgpException e)
             {
@@ -450,65 +476,65 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
-		private static byte[] Checksum(
-			bool	useSha1,
-			byte[]	bytes,
-			int		length)
-		{
-			if (useSha1)
-			{
-				try
-				{
-					IDigest dig = DigestUtilities.GetDigest("SHA1");
-					dig.BlockUpdate(bytes, 0, length);
-					return DigestUtilities.DoFinal(dig);
-				}
-				//catch (NoSuchAlgorithmException e)
-				catch (Exception e)
-				{
-					throw new PgpException("Can't find SHA-1", e);
-				}
-			}
-			else
-			{
-				int Checksum = 0;
-				for (int i = 0; i != length; i++)
-				{
-					Checksum += bytes[i];
-				}
-
-				return new byte[] { (byte)(Checksum >> 8), (byte)Checksum };
-			}
-		}
-
-		public byte[] GetEncoded()
+        private static byte[] Checksum(
+            bool	useSha1,
+            byte[]	bytes,
+            int		length)
+        {
+            if (useSha1)
+            {
+                try
+                {
+                    IDigest dig = DigestUtilities.GetDigest("SHA1");
+                    dig.BlockUpdate(bytes, 0, length);
+                    return DigestUtilities.DoFinal(dig);
+                }
+                //catch (NoSuchAlgorithmException e)
+                catch (Exception e)
+                {
+                    throw new PgpException("Can't find SHA-1", e);
+                }
+            }
+            else
+            {
+                int Checksum = 0;
+                for (int i = 0; i != length; i++)
+                {
+                    Checksum += bytes[i];
+                }
+
+                return new byte[] { (byte)(Checksum >> 8), (byte)Checksum };
+            }
+        }
+
+        public byte[] GetEncoded()
         {
             MemoryStream bOut = new MemoryStream();
             Encode(bOut);
             return bOut.ToArray();
         }
 
-		public void Encode(
+        public void Encode(
             Stream outStr)
         {
             BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
 
-			bcpgOut.WritePacket(secret);
+            bcpgOut.WritePacket(secret);
             if (pub.trustPk != null)
             {
                 bcpgOut.WritePacket(pub.trustPk);
             }
 
-			if (pub.subSigs == null) // is not a sub key
+            if (pub.subSigs == null) // is not a sub key
             {
-				foreach (PgpSignature keySig in pub.keySigs)
-				{
-					keySig.Encode(bcpgOut);
+                foreach (PgpSignature keySig in pub.keySigs)
+                {
+                    keySig.Encode(bcpgOut);
                 }
 
-				for (int i = 0; i != pub.ids.Count; i++)
+                for (int i = 0; i != pub.ids.Count; i++)
                 {
-					object pubID = pub.ids[i];
+                    object pubID = pub.ids[i];
                     if (pubID is string)
                     {
                         string id = (string) pubID;
@@ -520,38 +546,38 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                         bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
                     }
 
-					if (pub.idTrusts[i] != null)
+                    if (pub.idTrusts[i] != null)
                     {
                         bcpgOut.WritePacket((ContainedPacket)pub.idTrusts[i]);
                     }
 
-					foreach (PgpSignature sig in (IList) pub.idSigs[i])
-					{
-						sig.Encode(bcpgOut);
+                    foreach (PgpSignature sig in (IList) pub.idSigs[i])
+                    {
+                        sig.Encode(bcpgOut);
                     }
                 }
             }
             else
             {
-				foreach (PgpSignature subSig in pub.subSigs)
-				{
-					subSig.Encode(bcpgOut);
+                foreach (PgpSignature subSig in pub.subSigs)
+                {
+                    subSig.Encode(bcpgOut);
                 }
             }
 
-			// TODO Check that this is right/necessary
-			//bcpgOut.Finish();
+            // TODO Check that this is right/necessary
+            //bcpgOut.Finish();
         }
 
-		/// <summary>
-		/// Return a copy of the passed in secret key, encrypted using a new password
-		/// and the passed in algorithm.
-		/// </summary>
-		/// <param name="key">The PgpSecretKey to be copied.</param>
-		/// <param name="oldPassPhrase">The current password for the key.</param>
-		/// <param name="newPassPhrase">The new password for the key.</param>
-		/// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
-		/// <param name="rand">Source of randomness.</param>
+        /// <summary>
+        /// Return a copy of the passed in secret key, encrypted using a new password
+        /// and the passed in algorithm.
+        /// </summary>
+        /// <param name="key">The PgpSecretKey to be copied.</param>
+        /// <param name="oldPassPhrase">The current password for the key.</param>
+        /// <param name="newPassPhrase">The new password for the key.</param>
+        /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
+        /// <param name="rand">Source of randomness.</param>
         public static PgpSecretKey CopyWithNewPassword(
             PgpSecretKey				key,
             char[]						oldPassPhrase,
@@ -559,36 +585,48 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             SymmetricKeyAlgorithmTag	newEncAlgorithm,
             SecureRandom				rand)
         {
+            if (key.IsPrivateKeyEmpty)
+                throw new PgpException("no private key in this SecretKey - public key present only.");
+
             byte[]	rawKeyData = key.ExtractKeyData(oldPassPhrase);
-			int		s2kUsage = key.secret.S2kUsage;
-			byte[]	iv = null;
+            int		s2kUsage = key.secret.S2kUsage;
+            byte[]	iv = null;
             S2k		s2k = null;
             byte[]	keyData;
+            PublicKeyPacket pubKeyPacket = key.secret.PublicKeyPacket;
 
-			if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
+            if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null)
             {
-				s2kUsage = SecretKeyPacket.UsageNone;
-				if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1)   // SHA-1 hash, need to rewrite Checksum
-				{
-					keyData = new byte[rawKeyData.Length - 18];
-
-					Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);
-
-					byte[] check = Checksum(false, keyData, keyData.Length - 2);
-
-					keyData[keyData.Length - 2] = check[0];
-					keyData[keyData.Length - 1] = check[1];
-				}
-				else
-				{
-					keyData = rawKeyData;
-				}
-			}
+                s2kUsage = SecretKeyPacket.UsageNone;
+                if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1)   // SHA-1 hash, need to rewrite Checksum
+                {
+                    keyData = new byte[rawKeyData.Length - 18];
+
+                    Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2);
+
+                    byte[] check = Checksum(false, keyData, keyData.Length - 2);
+
+                    keyData[keyData.Length - 2] = check[0];
+                    keyData[keyData.Length - 1] = check[1];
+                }
+                else
+                {
+                    keyData = rawKeyData;
+                }
+            }
             else
             {
                 try
                 {
-					keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
+                    if (pubKeyPacket.Version >= 4)
+                    {
+                        keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
+                    }
+                    else
+                    {
+                        // TODO v3 RSA key encryption
+                        throw Platform.CreateNotImplementedException("v3 RSA");
+                    }
                 }
                 catch (PgpException e)
                 {
@@ -600,67 +638,65 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 }
             }
 
-			SecretKeyPacket secret;
+            SecretKeyPacket secret;
             if (key.secret is SecretSubkeyPacket)
             {
-                secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
-					newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+                secret = new SecretSubkeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
             }
             else
             {
-                secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
-	                newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+                secret = new SecretKeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData);
             }
 
-			return new PgpSecretKey(secret, key.pub);
+            return new PgpSecretKey(secret, key.pub);
+        }
+
+        /// <summary>Replace the passed the public key on the passed in secret key.</summary>
+        /// <param name="secretKey">Secret key to change.</param>
+        /// <param name="publicKey">New public key.</param>
+        /// <returns>A new secret key.</returns>
+        /// <exception cref="ArgumentException">If KeyId's do not match.</exception>
+        public static PgpSecretKey ReplacePublicKey(
+            PgpSecretKey	secretKey,
+            PgpPublicKey	publicKey)
+        {
+            if (publicKey.KeyId != secretKey.KeyId)
+                throw new ArgumentException("KeyId's do not match");
+
+            return new PgpSecretKey(secretKey.secret, publicKey);
         }
 
-		/// <summary>Replace the passed the public key on the passed in secret key.</summary>
-		/// <param name="secretKey">Secret key to change.</param>
-		/// <param name="publicKey">New public key.</param>
-		/// <returns>A new secret key.</returns>
-		/// <exception cref="ArgumentException">If KeyId's do not match.</exception>
-		public static PgpSecretKey ReplacePublicKey(
-			PgpSecretKey	secretKey,
-			PgpPublicKey	publicKey)
-		{
-			if (publicKey.KeyId != secretKey.KeyId)
-				throw new ArgumentException("KeyId's do not match");
-
-			return new PgpSecretKey(secretKey.secret, publicKey);
-		}
-
-		private static byte[] EncryptKeyData(
-			byte[]						rawKeyData,
-			SymmetricKeyAlgorithmTag	encAlgorithm,
-			char[]						passPhrase,
-			SecureRandom				random,
-			out S2k						s2k,
-			out byte[]					iv)
-		{
-			IBufferedCipher c;
-			try
-			{
-				string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
-				c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
-			}
-			catch (Exception e)
-			{
-				throw new PgpException("Exception creating cipher", e);
-			}
-
-			byte[] s2kIV = new byte[8];
-			random.NextBytes(s2kIV);
-			s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60);
-
-			KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase);
-
-			iv = new byte[c.GetBlockSize()];
-			random.NextBytes(iv);
-
-			c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random));
-
-			return c.DoFinal(rawKeyData);
-		}
+        private static byte[] EncryptKeyData(
+            byte[]						rawKeyData,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+            SecureRandom				random,
+            out S2k						s2k,
+            out byte[]					iv)
+        {
+            IBufferedCipher c;
+            try
+            {
+                string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+                c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception creating cipher", e);
+            }
+
+            byte[] s2kIV = new byte[8];
+            random.NextBytes(s2kIV);
+            s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60);
+
+            KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase);
+
+            iv = new byte[c.GetBlockSize()];
+            random.NextBytes(iv);
+
+            c.Init(true, new ParametersWithRandom(new ParametersWithIV(kp, iv), random));
+
+            return c.DoFinal(rawKeyData);
+        }
     }
 }
diff --git a/crypto/src/openpgp/PgpSecretKeyRing.cs b/crypto/src/openpgp/PgpSecretKeyRing.cs
index 3e646eaa1..70cd7217c 100644
--- a/crypto/src/openpgp/PgpSecretKeyRing.cs
+++ b/crypto/src/openpgp/PgpSecretKeyRing.cs
@@ -8,57 +8,57 @@ using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
-	/// <remarks>
-	/// Class to hold a single master secret key and its subkeys.
-	/// <p>
-	/// Often PGP keyring files consist of multiple master keys, if you are trying to process
-	/// or construct one of these you should use the <c>PgpSecretKeyRingBundle</c> class.
-	/// </p>
-	/// </remarks>
-	public class PgpSecretKeyRing
-		: PgpKeyRing
+    /// <remarks>
+    /// Class to hold a single master secret key and its subkeys.
+    /// <p>
+    /// Often PGP keyring files consist of multiple master keys, if you are trying to process
+    /// or construct one of these you should use the <c>PgpSecretKeyRingBundle</c> class.
+    /// </p>
+    /// </remarks>
+    public class PgpSecretKeyRing
+        : PgpKeyRing
     {
         private readonly IList keys;
-		private readonly IList extraPubKeys;
-
-		internal PgpSecretKeyRing(
-			IList keys)
-			: this(keys, Platform.CreateArrayList())
-		{
-		}
-
-		private PgpSecretKeyRing(
-			IList	keys,
-			IList	extraPubKeys)
-		{
-			this.keys = keys;
-			this.extraPubKeys = extraPubKeys;
-		}
-
-		public PgpSecretKeyRing(
+        private readonly IList extraPubKeys;
+
+        internal PgpSecretKeyRing(
+            IList keys)
+            : this(keys, Platform.CreateArrayList())
+        {
+        }
+
+        private PgpSecretKeyRing(
+            IList	keys,
+            IList	extraPubKeys)
+        {
+            this.keys = keys;
+            this.extraPubKeys = extraPubKeys;
+        }
+
+        public PgpSecretKeyRing(
             byte[] encoding)
             : this(new MemoryStream(encoding))
         {
         }
 
-		public PgpSecretKeyRing(
+        public PgpSecretKeyRing(
             Stream inputStream)
         {
-			this.keys = Platform.CreateArrayList();
+            this.keys = Platform.CreateArrayList();
             this.extraPubKeys = Platform.CreateArrayList();
 
-			BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+            BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
 
-			PacketTag initialTag = bcpgInput.NextPacketTag();
-			if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey)
+            PacketTag initialTag = bcpgInput.NextPacketTag();
+            if (initialTag != PacketTag.SecretKey && initialTag != PacketTag.SecretSubkey)
             {
                 throw new IOException("secret key ring doesn't start with secret key tag: "
-					+ "tag 0x" + ((int)initialTag).ToString("X"));
+                    + "tag 0x" + ((int)initialTag).ToString("X"));
             }
 
-			SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket();
+            SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket();
 
-			//
+            //
             // ignore GPG comment packets if found.
             //
             while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
@@ -66,65 +66,65 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 bcpgInput.ReadPacket();
             }
 
-			TrustPacket trust = ReadOptionalTrustPacket(bcpgInput);
+            TrustPacket trust = ReadOptionalTrustPacket(bcpgInput);
 
-			// revocation and direct signatures
-			IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+            // revocation and direct signatures
+            IList keySigs = ReadSignaturesAndTrust(bcpgInput);
 
-			IList ids, idTrusts, idSigs;
-			ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+            IList ids, idTrusts, idSigs;
+            ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
 
-			keys.Add(new PgpSecretKey(secret, new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs)));
+            keys.Add(new PgpSecretKey(secret, new PgpPublicKey(secret.PublicKeyPacket, trust, keySigs, ids, idTrusts, idSigs)));
 
 
-			// Read subkeys
-			while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey
-				|| bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+            // Read subkeys
+            while (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey
+                || bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
             {
-				if (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey)
-				{
-					SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket();
-
-					//
-					// ignore GPG comment packets if found.
-					//
-					while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
-					{
-						bcpgInput.ReadPacket();
-					}
-
-					TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
-					IList sigList = ReadSignaturesAndTrust(bcpgInput);
-
-					keys.Add(new PgpSecretKey(sub, new PgpPublicKey(sub.PublicKeyPacket, subTrust, sigList)));
-				}
-				else
-				{
-					PublicSubkeyPacket sub = (PublicSubkeyPacket) bcpgInput.ReadPacket();
-
-					TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
-					IList sigList = ReadSignaturesAndTrust(bcpgInput);
-
-					extraPubKeys.Add(new PgpPublicKey(sub, subTrust, sigList));
-				}
+                if (bcpgInput.NextPacketTag() == PacketTag.SecretSubkey)
+                {
+                    SecretSubkeyPacket sub = (SecretSubkeyPacket) bcpgInput.ReadPacket();
+
+                    //
+                    // ignore GPG comment packets if found.
+                    //
+                    while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
+                    {
+                        bcpgInput.ReadPacket();
+                    }
+
+                    TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
+                    IList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+                    keys.Add(new PgpSecretKey(sub, new PgpPublicKey(sub.PublicKeyPacket, subTrust, sigList)));
+                }
+                else
+                {
+                    PublicSubkeyPacket sub = (PublicSubkeyPacket) bcpgInput.ReadPacket();
+
+                    TrustPacket subTrust = ReadOptionalTrustPacket(bcpgInput);
+                    IList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+                    extraPubKeys.Add(new PgpPublicKey(sub, subTrust, sigList));
+                }
             }
         }
 
-		/// <summary>Return the public key for the master key.</summary>
+        /// <summary>Return the public key for the master key.</summary>
         public PgpPublicKey GetPublicKey()
         {
             return ((PgpSecretKey) keys[0]).PublicKey;
         }
 
-		/// <summary>Return the master private key.</summary>
+        /// <summary>Return the master private key.</summary>
         public PgpSecretKey GetSecretKey()
         {
             return (PgpSecretKey) keys[0];
         }
 
-		/// <summary>Allows enumeration of the secret keys.</summary>
-		/// <returns>An <c>IEnumerable</c> of <c>PgpSecretKey</c> objects.</returns>
-		public IEnumerable GetSecretKeys()
+        /// <summary>Allows enumeration of the secret keys.</summary>
+        /// <returns>An <c>IEnumerable</c> of <c>PgpSecretKey</c> objects.</returns>
+        public IEnumerable GetSecretKeys()
         {
             return new EnumerableProxy(keys);
         }
@@ -132,29 +132,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         public PgpSecretKey GetSecretKey(
             long keyId)
         {
-			foreach (PgpSecretKey k in keys)
-			{
-				if (keyId == k.KeyId)
-				{
-					return k;
-				}
-			}
-
-			return null;
+            foreach (PgpSecretKey k in keys)
+            {
+                if (keyId == k.KeyId)
+                {
+                    return k;
+                }
+            }
+
+            return null;
+        }
+
+        /// <summary>
+        /// Return an iterator of the public keys in the secret key ring that
+        /// have no matching private key. At the moment only personal certificate data
+        /// appears in this fashion.
+        /// </summary>
+        /// <returns>An <c>IEnumerable</c> of unattached, or extra, public keys.</returns>
+        public IEnumerable GetExtraPublicKeys()
+        {
+            return new EnumerableProxy(extraPubKeys);
         }
 
-		/// <summary>
-		/// Return an iterator of the public keys in the secret key ring that
-		/// have no matching private key. At the moment only personal certificate data
-		/// appears in this fashion.
-		/// </summary>
-		/// <returns>An <c>IEnumerable</c> of unattached, or extra, public keys.</returns>
-		public IEnumerable GetExtraPublicKeys()
-		{
-			return new EnumerableProxy(extraPubKeys);
-		}
-
-		public byte[] GetEncoded()
+        public byte[] GetEncoded()
         {
             MemoryStream bOut = new MemoryStream();
 
@@ -166,117 +166,124 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         public void Encode(
             Stream outStr)
         {
-			if (outStr == null)
-				throw new ArgumentNullException("outStr");
-
-			foreach (PgpSecretKey key in keys)
-			{
-				key.Encode(outStr);
-			}
-			foreach (PgpPublicKey extraPubKey in extraPubKeys)
-			{
-				extraPubKey.Encode(outStr);
-			}
+            if (outStr == null)
+                throw new ArgumentNullException("outStr");
+
+            foreach (PgpSecretKey key in keys)
+            {
+                key.Encode(outStr);
+            }
+            foreach (PgpPublicKey extraPubKey in extraPubKeys)
+            {
+                extraPubKey.Encode(outStr);
+            }
         }
 
-		/// <summary>
-		/// Replace the public key set on the secret ring with the corresponding key off the public ring.
-		/// </summary>
-		/// <param name="secretRing">Secret ring to be changed.</param>
-		/// <param name="publicRing">Public ring containing the new public key set.</param>
-		public static PgpSecretKeyRing ReplacePublicKeys(
-			PgpSecretKeyRing	secretRing,
-			PgpPublicKeyRing	publicRing)
-		{
+        /// <summary>
+        /// Replace the public key set on the secret ring with the corresponding key off the public ring.
+        /// </summary>
+        /// <param name="secretRing">Secret ring to be changed.</param>
+        /// <param name="publicRing">Public ring containing the new public key set.</param>
+        public static PgpSecretKeyRing ReplacePublicKeys(
+            PgpSecretKeyRing	secretRing,
+            PgpPublicKeyRing	publicRing)
+        {
             IList newList = Platform.CreateArrayList(secretRing.keys.Count);
 
-			foreach (PgpSecretKey sk in secretRing.keys)
-			{
-				PgpPublicKey pk = publicRing.GetPublicKey(sk.KeyId);
-
-				newList.Add(PgpSecretKey.ReplacePublicKey(sk, pk));
-			}
-
-			return new PgpSecretKeyRing(newList);
-		}
-
-		/// <summary>
-		/// Return a copy of the passed in secret key ring, with the master key and sub keys encrypted
-		/// using a new password and the passed in algorithm.
-		/// </summary>
-		/// <param name="ring">The <c>PgpSecretKeyRing</c> to be copied.</param>
-		/// <param name="oldPassPhrase">The current password for key.</param>
-		/// <param name="newPassPhrase">The new password for the key.</param>
-		/// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
-		/// <param name="rand">Source of randomness.</param>
-		public static PgpSecretKeyRing CopyWithNewPassword(
-			PgpSecretKeyRing			ring,
-			char[]						oldPassPhrase,
-			char[]						newPassPhrase,
-			SymmetricKeyAlgorithmTag	newEncAlgorithm,
-			SecureRandom				rand)
-		{
+            foreach (PgpSecretKey sk in secretRing.keys)
+            {
+                PgpPublicKey pk = publicRing.GetPublicKey(sk.KeyId);
+
+                newList.Add(PgpSecretKey.ReplacePublicKey(sk, pk));
+            }
+
+            return new PgpSecretKeyRing(newList);
+        }
+
+        /// <summary>
+        /// Return a copy of the passed in secret key ring, with the master key and sub keys encrypted
+        /// using a new password and the passed in algorithm.
+        /// </summary>
+        /// <param name="ring">The <c>PgpSecretKeyRing</c> to be copied.</param>
+        /// <param name="oldPassPhrase">The current password for key.</param>
+        /// <param name="newPassPhrase">The new password for the key.</param>
+        /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param>
+        /// <param name="rand">Source of randomness.</param>
+        public static PgpSecretKeyRing CopyWithNewPassword(
+            PgpSecretKeyRing			ring,
+            char[]						oldPassPhrase,
+            char[]						newPassPhrase,
+            SymmetricKeyAlgorithmTag	newEncAlgorithm,
+            SecureRandom				rand)
+        {
             IList newKeys = Platform.CreateArrayList(ring.keys.Count);
-			foreach (PgpSecretKey secretKey in ring.GetSecretKeys())
-			{
-				newKeys.Add(PgpSecretKey.CopyWithNewPassword(secretKey, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand));
-			}
-
-			return new PgpSecretKeyRing(newKeys, ring.extraPubKeys);
-		}
-
-		/// <summary>
-		/// Returns a new key ring with the secret key passed in either added or
-		/// replacing an existing one with the same key ID.
-		/// </summary>
-		/// <param name="secRing">The secret key ring to be modified.</param>
-		/// <param name="secKey">The secret key to be inserted.</param>
-		/// <returns>A new <c>PgpSecretKeyRing</c></returns>
-		public static PgpSecretKeyRing InsertSecretKey(
+            foreach (PgpSecretKey secretKey in ring.GetSecretKeys())
+            {
+                if (secretKey.IsPrivateKeyEmpty)
+                {
+                    newKeys.Add(secretKey);
+                }
+                else
+                {
+                    newKeys.Add(PgpSecretKey.CopyWithNewPassword(secretKey, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand));
+                }
+            }
+
+            return new PgpSecretKeyRing(newKeys, ring.extraPubKeys);
+        }
+
+        /// <summary>
+        /// Returns a new key ring with the secret key passed in either added or
+        /// replacing an existing one with the same key ID.
+        /// </summary>
+        /// <param name="secRing">The secret key ring to be modified.</param>
+        /// <param name="secKey">The secret key to be inserted.</param>
+        /// <returns>A new <c>PgpSecretKeyRing</c></returns>
+        public static PgpSecretKeyRing InsertSecretKey(
             PgpSecretKeyRing  secRing,
             PgpSecretKey      secKey)
         {
             IList keys = Platform.CreateArrayList(secRing.keys);
             bool found = false;
-			bool masterFound = false;
+            bool masterFound = false;
 
-			for (int i = 0; i != keys.Count; i++)
+            for (int i = 0; i != keys.Count; i++)
             {
                 PgpSecretKey key = (PgpSecretKey) keys[i];
 
-				if (key.KeyId == secKey.KeyId)
+                if (key.KeyId == secKey.KeyId)
                 {
                     found = true;
                     keys[i] = secKey;
                 }
-				if (key.IsMasterKey)
-				{
-					masterFound = true;
-				}
-			}
+                if (key.IsMasterKey)
+                {
+                    masterFound = true;
+                }
+            }
 
             if (!found)
             {
-				if (secKey.IsMasterKey)
-				{
-					if (masterFound)
-						throw new ArgumentException("cannot add a master key to a ring that already has one");
-
-					keys.Insert(0, secKey);
-				}
-				else
-				{
-					keys.Add(secKey);
-				}
+                if (secKey.IsMasterKey)
+                {
+                    if (masterFound)
+                        throw new ArgumentException("cannot add a master key to a ring that already has one");
+
+                    keys.Insert(0, secKey);
+                }
+                else
+                {
+                    keys.Add(secKey);
+                }
             }
 
-			return new PgpSecretKeyRing(keys, secRing.extraPubKeys);
-		}
+            return new PgpSecretKeyRing(keys, secRing.extraPubKeys);
+        }
 
-		/// <summary>Returns a new key ring with the secret key passed in removed from the key ring.</summary>
-		/// <param name="secRing">The secret key ring to be modified.</param>
-		/// <param name="secKey">The secret key to be removed.</param>
-		/// <returns>A new <c>PgpSecretKeyRing</c>, or null if secKey is not found.</returns>
+        /// <summary>Returns a new key ring with the secret key passed in removed from the key ring.</summary>
+        /// <param name="secRing">The secret key ring to be modified.</param>
+        /// <param name="secKey">The secret key to be removed.</param>
+        /// <returns>A new <c>PgpSecretKeyRing</c>, or null if secKey is not found.</returns>
         public static PgpSecretKeyRing RemoveSecretKey(
             PgpSecretKeyRing  secRing,
             PgpSecretKey      secKey)
@@ -284,18 +291,18 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             IList keys = Platform.CreateArrayList(secRing.keys);
             bool found = false;
 
-			for (int i = 0; i < keys.Count; i++)
+            for (int i = 0; i < keys.Count; i++)
             {
                 PgpSecretKey key = (PgpSecretKey)keys[i];
 
-				if (key.KeyId == secKey.KeyId)
+                if (key.KeyId == secKey.KeyId)
                 {
                     found = true;
                     keys.RemoveAt(i);
                 }
             }
 
-			return found ? new PgpSecretKeyRing(keys, secRing.extraPubKeys) : null;
+            return found ? new PgpSecretKeyRing(keys, secRing.extraPubKeys) : null;
         }
     }
 }
diff --git a/crypto/src/openpgp/PgpSecretKeyRingBundle.cs b/crypto/src/openpgp/PgpSecretKeyRingBundle.cs
index 18636dd65..12c7c098c 100644
--- a/crypto/src/openpgp/PgpSecretKeyRingBundle.cs
+++ b/crypto/src/openpgp/PgpSecretKeyRingBundle.cs
@@ -114,8 +114,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 			if (ignoreCase)
 			{
-				userId = userId.ToLowerInvariant();
-			}
+                userId = Platform.ToLowerInvariant(userId);
+            }
 
 			foreach (PgpSecretKeyRing secRing in GetKeyRings())
 			{
@@ -124,8 +124,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 					string next = nextUserID;
 					if (ignoreCase)
 					{
-						next = next.ToLowerInvariant();
-					}
+                        next = Platform.ToLowerInvariant(next);
+                    }
 
 					if (matchPartial)
 					{
diff --git a/crypto/src/openpgp/PgpSignature.cs b/crypto/src/openpgp/PgpSignature.cs
index cbe0d83b4..3bb6f2f0e 100644
--- a/crypto/src/openpgp/PgpSignature.cs
+++ b/crypto/src/openpgp/PgpSignature.cs
@@ -253,7 +253,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			//
             // hash in the id
             //
-			UpdateWithIdData(0xb4, Strings.ToByteArray(id));
+            UpdateWithIdData(0xb4, Strings.ToUtf8ByteArray(id));
 
 			Update(sigPck.GetSignatureTrailer());
 
diff --git a/crypto/src/openpgp/PgpSignatureGenerator.cs b/crypto/src/openpgp/PgpSignatureGenerator.cs
index 891397267..c5309689f 100644
--- a/crypto/src/openpgp/PgpSignatureGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureGenerator.cs
@@ -267,9 +267,9 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			//
             // hash in the id
             //
-			UpdateWithIdData(0xb4, Strings.ToByteArray(id));
+			UpdateWithIdData(0xb4, Strings.ToUtf8ByteArray(id));
 
-			return Generate();
+            return Generate();
         }
 
 		/// <summary>Generate a certification for the passed in userAttributes.</summary>
diff --git a/crypto/src/openpgp/PgpSignatureList.cs b/crypto/src/openpgp/PgpSignatureList.cs
new file mode 100644
index 000000000..61976fc4f
--- /dev/null
+++ b/crypto/src/openpgp/PgpSignatureList.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>A list of PGP signatures - normally in the signature block after literal data.</remarks>
+    public class PgpSignatureList
+		: PgpObject
+    {
+        private PgpSignature[] sigs;
+
+		public PgpSignatureList(
+            PgpSignature[] sigs)
+        {
+            this.sigs = (PgpSignature[]) sigs.Clone();
+        }
+
+		public PgpSignatureList(
+            PgpSignature sig)
+        {
+			this.sigs = new PgpSignature[]{ sig };
+        }
+
+		public PgpSignature this[int index]
+		{
+			get { return sigs[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public PgpSignature Get(
+            int index)
+        {
+            return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+        {
+			get { return sigs.Length; }
+        }
+
+		public int Count
+		{
+			get { return sigs.Length; }
+		}
+
+		public bool IsEmpty
+        {
+			get { return (sigs.Length == 0); }
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
new file mode 100644
index 000000000..4adf64012
--- /dev/null
+++ b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
@@ -0,0 +1,193 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Generator for signature subpackets.</remarks>
+    public class PgpSignatureSubpacketGenerator
+    {
+        private IList list = Platform.CreateArrayList();
+
+		public void SetRevocable(
+            bool	isCritical,
+            bool	isRevocable)
+        {
+            list.Add(new Revocable(isCritical, isRevocable));
+        }
+
+		public void SetExportable(
+            bool	isCritical,
+            bool	isExportable)
+        {
+            list.Add(new Exportable(isCritical, isExportable));
+        }
+
+		/// <summary>
+		/// Add a TrustSignature packet to the signature. The values for depth and trust are largely
+		/// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13.
+		/// </summary>
+		/// <param name="isCritical">true if the packet is critical.</param>
+		/// <param name="depth">depth level.</param>
+		/// <param name="trustAmount">trust amount.</param>
+		public void SetTrust(
+            bool	isCritical,
+            int		depth,
+            int		trustAmount)
+        {
+            list.Add(new TrustSignature(isCritical, depth, trustAmount));
+        }
+
+		/// <summary>
+		/// Set the number of seconds a key is valid for after the time of its creation.
+		/// A value of zero means the key never expires.
+		/// </summary>
+		/// <param name="isCritical">True, if should be treated as critical, false otherwise.</param>
+		/// <param name="seconds">The number of seconds the key is valid, or zero if no expiry.</param>
+        public void SetKeyExpirationTime(
+            bool	isCritical,
+            long	seconds)
+        {
+            list.Add(new KeyExpirationTime(isCritical, seconds));
+        }
+
+		/// <summary>
+		/// Set the number of seconds a signature is valid for after the time of its creation.
+		/// A value of zero means the signature never expires.
+		/// </summary>
+		/// <param name="isCritical">True, if should be treated as critical, false otherwise.</param>
+		/// <param name="seconds">The number of seconds the signature is valid, or zero if no expiry.</param>
+        public void SetSignatureExpirationTime(
+            bool	isCritical,
+            long	seconds)
+        {
+            list.Add(new SignatureExpirationTime(isCritical, seconds));
+        }
+
+		/// <summary>
+		/// Set the creation time for the signature.
+		/// <p>
+		/// Note: this overrides the generation of a creation time when the signature
+		/// is generated.</p>
+		/// </summary>
+		public void SetSignatureCreationTime(
+			bool		isCritical,
+			DateTime	date)
+		{
+			list.Add(new SignatureCreationTime(isCritical, date));
+		}
+
+		public void SetPreferredHashAlgorithms(
+            bool	isCritical,
+            int[]	algorithms)
+        {
+            list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredHashAlgorithms, isCritical, algorithms));
+        }
+
+		public void SetPreferredSymmetricAlgorithms(
+            bool	isCritical,
+            int[]	algorithms)
+        {
+            list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredSymmetricAlgorithms, isCritical, algorithms));
+        }
+
+		public void SetPreferredCompressionAlgorithms(
+            bool	isCritical,
+            int[]	algorithms)
+        {
+            list.Add(new PreferredAlgorithms(SignatureSubpacketTag.PreferredCompressionAlgorithms, isCritical, algorithms));
+        }
+
+		public void SetKeyFlags(
+            bool	isCritical,
+            int		flags)
+        {
+            list.Add(new KeyFlags(isCritical, flags));
+        }
+
+		public void SetSignerUserId(
+            bool	isCritical,
+            string	userId)
+        {
+            if (userId == null)
+                throw new ArgumentNullException("userId");
+
+			list.Add(new SignerUserId(isCritical, userId));
+        }
+
+		public void SetEmbeddedSignature(
+			bool			isCritical,
+			PgpSignature	pgpSignature)
+		{
+			byte[] sig = pgpSignature.GetEncoded();
+			byte[] data;
+
+			// TODO Should be >= ?
+			if (sig.Length - 1 > 256)
+			{
+				data = new byte[sig.Length - 3];
+			}
+			else
+			{
+				data = new byte[sig.Length - 2];
+			}
+
+			Array.Copy(sig, sig.Length - data.Length, data, 0, data.Length);
+
+			list.Add(new EmbeddedSignature(isCritical, data));
+		}
+
+		public void SetPrimaryUserId(
+            bool	isCritical,
+            bool	isPrimaryUserId)
+        {
+            list.Add(new PrimaryUserId(isCritical, isPrimaryUserId));
+        }
+
+		public void SetNotationData(
+			bool	isCritical,
+			bool	isHumanReadable,
+			string	notationName,
+			string	notationValue)
+		{
+			list.Add(new NotationData(isCritical, isHumanReadable, notationName, notationValue));
+		}
+
+		/// <summary>
+		/// Sets revocation reason sub packet
+		/// </summary>	    
+		public void SetRevocationReason(bool isCritical, RevocationReasonTag reason,
+			string description)
+		{
+			list.Add(new RevocationReason(isCritical, reason, description));
+		}
+
+		/// <summary>
+		/// Sets revocation key sub packet
+		/// </summary>	
+		public void SetRevocationKey(bool isCritical, PublicKeyAlgorithmTag keyAlgorithm, byte[] fingerprint)
+		{
+			list.Add(new RevocationKey(isCritical, RevocationKeyTag.ClassDefault, keyAlgorithm, fingerprint));
+		}
+
+		/// <summary>
+		/// Sets issuer key sub packet
+		/// </summary>	
+		public void SetIssuerKeyID(bool isCritical, long keyID)
+		{
+			list.Add(new IssuerKeyId(isCritical, keyID));
+		}    
+
+		public PgpSignatureSubpacketVector Generate()
+        {
+            SignatureSubpacket[] a = new SignatureSubpacket[list.Count];
+            for (int i = 0; i < list.Count; ++i)
+            {
+                a[i] = (SignatureSubpacket)list[i];
+            }
+            return new PgpSignatureSubpacketVector(a);
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
new file mode 100644
index 000000000..68fe4b594
--- /dev/null
+++ b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
@@ -0,0 +1,229 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Container for a list of signature subpackets.</remarks>
+    public class PgpSignatureSubpacketVector
+    {
+        private readonly SignatureSubpacket[] packets;
+
+		internal PgpSignatureSubpacketVector(
+            SignatureSubpacket[] packets)
+        {
+            this.packets = packets;
+        }
+
+		public SignatureSubpacket GetSubpacket(
+            SignatureSubpacketTag type)
+        {
+            for (int i = 0; i != packets.Length; i++)
+            {
+                if (packets[i].SubpacketType == type)
+                {
+                    return packets[i];
+                }
+            }
+
+			return null;
+        }
+
+		/**
+		 * Return true if a particular subpacket type exists.
+		 *
+		 * @param type type to look for.
+		 * @return true if present, false otherwise.
+		 */
+		public bool HasSubpacket(
+			SignatureSubpacketTag type)
+		{
+			return GetSubpacket(type) != null;
+		}
+
+		/**
+		 * Return all signature subpackets of the passed in type.
+		 * @param type subpacket type code
+		 * @return an array of zero or more matching subpackets.
+		 */
+		public SignatureSubpacket[] GetSubpackets(
+			SignatureSubpacketTag type)
+		{
+            int count = 0;
+            for (int i = 0; i < packets.Length; ++i)
+            {
+                if (packets[i].SubpacketType == type)
+                {
+                    ++count;
+                }
+            }
+
+            SignatureSubpacket[] result = new SignatureSubpacket[count];
+
+            int pos = 0;
+            for (int i = 0; i < packets.Length; ++i)
+            {
+                if (packets[i].SubpacketType == type)
+                {
+                    result[pos++] = packets[i];
+                }
+            }
+
+            return result;
+        }
+
+        public NotationData[] GetNotationDataOccurences()
+		{
+			SignatureSubpacket[] notations = GetSubpackets(SignatureSubpacketTag.NotationData);
+			NotationData[] vals = new NotationData[notations.Length];
+
+			for (int i = 0; i < notations.Length; i++)
+			{
+				vals[i] = (NotationData) notations[i];
+			}
+
+			return vals;
+		}
+
+		public long GetIssuerKeyId()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.IssuerKeyId);
+
+            return p == null ? 0 : ((IssuerKeyId) p).KeyId;
+        }
+
+		public bool HasSignatureCreationTime()
+		{
+			return GetSubpacket(SignatureSubpacketTag.CreationTime) != null;
+		}
+
+		public DateTime GetSignatureCreationTime()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.CreationTime);
+
+            if (p == null)
+            {
+                throw new PgpException("SignatureCreationTime not available");
+            }
+
+            return ((SignatureCreationTime)p).GetTime();
+        }
+
+		/// <summary>
+		/// Return the number of seconds a signature is valid for after its creation date.
+		/// A value of zero means the signature never expires.
+		/// </summary>
+		/// <returns>Seconds a signature is valid for.</returns>
+        public long GetSignatureExpirationTime()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.ExpireTime);
+
+			return p == null ? 0 : ((SignatureExpirationTime) p).Time;
+        }
+
+		/// <summary>
+		/// Return the number of seconds a key is valid for after its creation date.
+		/// A value of zero means the key never expires.
+		/// </summary>
+		/// <returns>Seconds a signature is valid for.</returns>
+        public long GetKeyExpirationTime()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyExpireTime);
+
+			return p == null ? 0 : ((KeyExpirationTime) p).Time;
+        }
+
+		public int[] GetPreferredHashAlgorithms()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredHashAlgorithms);
+
+			return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+        }
+
+		public int[] GetPreferredSymmetricAlgorithms()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredSymmetricAlgorithms);
+
+            return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+        }
+
+		public int[] GetPreferredCompressionAlgorithms()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.PreferredCompressionAlgorithms);
+
+            return p == null ? null : ((PreferredAlgorithms) p).GetPreferences();
+        }
+
+		public int GetKeyFlags()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.KeyFlags);
+
+            return p == null ? 0 : ((KeyFlags) p).Flags;
+        }
+
+		public string GetSignerUserId()
+        {
+            SignatureSubpacket p = GetSubpacket(SignatureSubpacketTag.SignerUserId);
+
+			return p == null ? null : ((SignerUserId) p).GetId();
+        }
+
+		public bool IsPrimaryUserId()
+		{
+			PrimaryUserId primaryId = (PrimaryUserId)
+				this.GetSubpacket(SignatureSubpacketTag.PrimaryUserId);
+
+			if (primaryId != null)
+			{
+				return primaryId.IsPrimaryUserId();
+			}
+
+			return false;
+		}
+
+		public SignatureSubpacketTag[] GetCriticalTags()
+        {
+            int count = 0;
+            for (int i = 0; i != packets.Length; i++)
+            {
+                if (packets[i].IsCritical())
+                {
+                    count++;
+                }
+            }
+
+			SignatureSubpacketTag[] list = new SignatureSubpacketTag[count];
+
+			count = 0;
+
+			for (int i = 0; i != packets.Length; i++)
+            {
+                if (packets[i].IsCritical())
+                {
+                    list[count++] = packets[i].SubpacketType;
+                }
+            }
+
+			return list;
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return packets.Length; }
+		}
+
+		/// <summary>Return the number of packets this vector contains.</summary>
+		public int Count
+		{
+			get { return packets.Length; }
+		}
+
+		internal SignatureSubpacket[] ToSubpacketArray()
+        {
+            return packets;
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpUserAttributeSubpacketVector.cs b/crypto/src/openpgp/PgpUserAttributeSubpacketVector.cs
new file mode 100644
index 000000000..4cdbeda54
--- /dev/null
+++ b/crypto/src/openpgp/PgpUserAttributeSubpacketVector.cs
@@ -0,0 +1,81 @@
+using Org.BouncyCastle.Bcpg.Attr;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Container for a list of user attribute subpackets.</remarks>
+    public class PgpUserAttributeSubpacketVector
+    {
+        private readonly UserAttributeSubpacket[] packets;
+
+		internal PgpUserAttributeSubpacketVector(
+            UserAttributeSubpacket[] packets)
+        {
+            this.packets = packets;
+        }
+
+		public UserAttributeSubpacket GetSubpacket(
+            UserAttributeSubpacketTag type)
+        {
+            for (int i = 0; i != packets.Length; i++)
+            {
+                if (packets[i].SubpacketType == type)
+                {
+                    return packets[i];
+                }
+            }
+
+			return null;
+        }
+
+		public ImageAttrib GetImageAttribute()
+        {
+            UserAttributeSubpacket p = GetSubpacket(UserAttributeSubpacketTag.ImageAttribute);
+
+            return p == null ? null : (ImageAttrib) p;
+        }
+
+		internal UserAttributeSubpacket[] ToSubpacketArray()
+        {
+            return packets;
+        }
+
+		public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+			PgpUserAttributeSubpacketVector other = obj as PgpUserAttributeSubpacketVector;
+
+			if (other == null)
+				return false;
+
+			if (other.packets.Length != packets.Length)
+            {
+                return false;
+            }
+
+			for (int i = 0; i != packets.Length; i++)
+            {
+                if (!other.packets[i].Equals(packets[i]))
+                {
+                    return false;
+                }
+            }
+
+			return true;
+        }
+
+		public override int GetHashCode()
+        {
+            int code = 0;
+
+			foreach (object o in packets)
+			{
+				code ^= o.GetHashCode();
+			}
+
+			return code;
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs
index e22381bb1..32e37b819 100644
--- a/crypto/src/openpgp/PgpUtilities.cs
+++ b/crypto/src/openpgp/PgpUtilities.cs
@@ -97,7 +97,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			return GetDigestName(hashAlgorithm) + "with" + encAlg;
         }
 
-		public static string GetSymmetricCipherName(
+	public static string GetSymmetricCipherName(
             SymmetricKeyAlgorithmTag algorithm)
         {
             switch (algorithm)
@@ -124,12 +124,18 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 					return "AES";
 				case SymmetricKeyAlgorithmTag.Twofish:
 					return "Twofish";
+				case SymmetricKeyAlgorithmTag.Camellia128:
+					return "Camellia";
+				case SymmetricKeyAlgorithmTag.Camellia192:
+					return "Camellia";
+				case SymmetricKeyAlgorithmTag.Camellia256:
+					return "Camellia";
 				default:
 					throw new PgpException("unknown symmetric algorithm: " + algorithm);
             }
         }
 
-		public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
+	public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
         {
             int keySize;
             switch (algorithm)
@@ -142,14 +148,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 case SymmetricKeyAlgorithmTag.Blowfish:
                 case SymmetricKeyAlgorithmTag.Safer:
                 case SymmetricKeyAlgorithmTag.Aes128:
+                case SymmetricKeyAlgorithmTag.Camellia128:
                     keySize = 128;
                     break;
                 case SymmetricKeyAlgorithmTag.TripleDes:
                 case SymmetricKeyAlgorithmTag.Aes192:
+                case SymmetricKeyAlgorithmTag.Camellia192:
                     keySize = 192;
                     break;
                 case SymmetricKeyAlgorithmTag.Aes256:
                 case SymmetricKeyAlgorithmTag.Twofish:
+                case SymmetricKeyAlgorithmTag.Camellia256:
                     keySize = 256;
                     break;
                 default:
@@ -298,7 +307,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			return MakeKey(algorithm, keyBytes);
         }
 
-#if !PORTABLE
 		/// <summary>Write out the passed in file as a literal data packet.</summary>
         public static void WriteFileToLiteralData(
             Stream		output,
@@ -336,7 +344,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			pOut.Close();
 			inputStream.Close();
 		}
-#endif
 
 		private const int ReadAhead = 60;
 
diff --git a/crypto/src/openpgp/PgpV3SignatureGenerator.cs b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
new file mode 100644
index 000000000..fc8b42df2
--- /dev/null
+++ b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
@@ -0,0 +1,199 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Generator for old style PGP V3 Signatures.</remarks>
+	// TODO Should be able to implement ISigner?
+	public class PgpV3SignatureGenerator
+    {
+        private PublicKeyAlgorithmTag keyAlgorithm;
+        private HashAlgorithmTag hashAlgorithm;
+        private PgpPrivateKey privKey;
+        private ISigner sig;
+        private IDigest    dig;
+        private int signatureType;
+        private byte lastb;
+
+		/// <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
+        public PgpV3SignatureGenerator(
+            PublicKeyAlgorithmTag	keyAlgorithm,
+            HashAlgorithmTag		hashAlgorithm)
+        {
+            this.keyAlgorithm = keyAlgorithm;
+            this.hashAlgorithm = hashAlgorithm;
+
+            dig = DigestUtilities.GetDigest(PgpUtilities.GetDigestName(hashAlgorithm));
+            sig = SignerUtilities.GetSigner(PgpUtilities.GetSignatureName(keyAlgorithm, hashAlgorithm));
+        }
+
+		/// <summary>Initialise the generator for signing.</summary>
+		public void InitSign(
+			int				sigType,
+			PgpPrivateKey	key)
+		{
+			InitSign(sigType, key, null);
+		}
+
+		/// <summary>Initialise the generator for signing.</summary>
+        public void InitSign(
+            int				sigType,
+            PgpPrivateKey	key,
+			SecureRandom	random)
+        {
+            this.privKey = key;
+            this.signatureType = sigType;
+
+			try
+            {
+				ICipherParameters cp = key.Key;
+				if (random != null)
+				{
+					cp = new ParametersWithRandom(key.Key, random);
+				}
+
+				sig.Init(true, cp);
+            }
+            catch (InvalidKeyException e)
+            {
+                throw new PgpException("invalid key.", e);
+            }
+
+			dig.Reset();
+            lastb = 0;
+        }
+
+		public void Update(
+            byte b)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+				doCanonicalUpdateByte(b);
+            }
+            else
+            {
+				doUpdateByte(b);
+            }
+        }
+
+		private void doCanonicalUpdateByte(
+			byte b)
+		{
+			if (b == '\r')
+			{
+				doUpdateCRLF();
+			}
+			else if (b == '\n')
+			{
+				if (lastb != '\r')
+				{
+					doUpdateCRLF();
+				}
+			}
+			else
+			{
+				doUpdateByte(b);
+			}
+
+			lastb = b;
+		}
+
+		private void doUpdateCRLF()
+		{
+			doUpdateByte((byte)'\r');
+			doUpdateByte((byte)'\n');
+		}
+
+		private void doUpdateByte(
+			byte b)
+		{
+			sig.Update(b);
+			dig.Update(b);
+		}
+
+		public void Update(
+            byte[] b)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+                for (int i = 0; i != b.Length; i++)
+                {
+                    doCanonicalUpdateByte(b[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(b, 0, b.Length);
+                dig.BlockUpdate(b, 0, b.Length);
+            }
+        }
+
+		public void Update(
+            byte[]	b,
+            int		off,
+            int		len)
+        {
+            if (signatureType == PgpSignature.CanonicalTextDocument)
+            {
+                int finish = off + len;
+
+				for (int i = off; i != finish; i++)
+                {
+                    doCanonicalUpdateByte(b[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(b, off, len);
+                dig.BlockUpdate(b, off, len);
+            }
+        }
+
+		/// <summary>Return the one pass header associated with the current signature.</summary>
+        public PgpOnePassSignature GenerateOnePassVersion(
+            bool isNested)
+        {
+            return new PgpOnePassSignature(
+				new OnePassSignaturePacket(signatureType, hashAlgorithm, keyAlgorithm, privKey.KeyId, isNested));
+        }
+
+		/// <summary>Return a V3 signature object containing the current signature state.</summary>
+        public PgpSignature Generate()
+        {
+            long creationTime = DateTimeUtilities.CurrentUnixMs() / 1000L;
+
+			byte[] hData = new byte[]
+			{
+				(byte) signatureType,
+				(byte)(creationTime >> 24),
+				(byte)(creationTime >> 16),
+				(byte)(creationTime >> 8),
+				(byte) creationTime
+			};
+
+			sig.BlockUpdate(hData, 0, hData.Length);
+            dig.BlockUpdate(hData, 0, hData.Length);
+
+			byte[] sigBytes = sig.GenerateSignature();
+			byte[] digest = DigestUtilities.DoFinal(dig);
+			byte[] fingerPrint = new byte[]{ digest[0], digest[1] };
+
+			// an RSA signature
+			bool isRsa = keyAlgorithm == PublicKeyAlgorithmTag.RsaSign
+                || keyAlgorithm == PublicKeyAlgorithmTag.RsaGeneral;
+
+			MPInteger[] sigValues = isRsa
+				?	PgpUtilities.RsaSigToMpi(sigBytes)
+				:	PgpUtilities.DsaSigToMpi(sigBytes);
+
+			return new PgpSignature(
+				new SignaturePacket(3, signatureType, privKey.KeyId, keyAlgorithm,
+					hashAlgorithm, creationTime * 1000L, fingerPrint, sigValues));
+        }
+    }
+}
diff --git a/crypto/src/openpgp/WrappedGeneratorStream.cs b/crypto/src/openpgp/WrappedGeneratorStream.cs
index baad0d429..6fc7329af 100644
--- a/crypto/src/openpgp/WrappedGeneratorStream.cs
+++ b/crypto/src/openpgp/WrappedGeneratorStream.cs
@@ -4,25 +4,22 @@ using Org.BouncyCastle.Asn1.Utilities;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
-    public class WrappedGeneratorStream
-        : FilterStream
-    {
-        private readonly IStreamGenerator gen;
+	public class WrappedGeneratorStream
+		: FilterStream
+	{
+		private readonly IStreamGenerator gen;
 
-        public WrappedGeneratorStream(
-            IStreamGenerator gen,
-            Stream str)
-            : base(str)
-        {
-            this.gen = gen;
-        }
+		public WrappedGeneratorStream(
+			IStreamGenerator	gen,
+			Stream				str)
+			: base(str)
+		{
+			this.gen = gen;
+		}
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                gen.Close();
-            }
-        }
-    }
+		public override void Close()
+		{
+			gen.Close();
+		}
+	}
 }
diff --git a/crypto/src/openssl/EncryptionException.cs b/crypto/src/openssl/EncryptionException.cs
index 043e8f899..c4a6ec02f 100644
--- a/crypto/src/openssl/EncryptionException.cs
+++ b/crypto/src/openssl/EncryptionException.cs
@@ -3,7 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.Security
 {
-	public class EncryptionException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class EncryptionException
 		: IOException
 	{
 		public EncryptionException(
diff --git a/crypto/src/openssl/IPasswordFinder.cs b/crypto/src/openssl/IPasswordFinder.cs
new file mode 100644
index 000000000..4fcef1bd7
--- /dev/null
+++ b/crypto/src/openssl/IPasswordFinder.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+	public interface IPasswordFinder
+	{
+		char[] GetPassword();
+	}
+}
diff --git a/crypto/src/openssl/MiscPemGenerator.cs b/crypto/src/openssl/MiscPemGenerator.cs
index a1f64498d..6b91e8b1c 100644
--- a/crypto/src/openssl/MiscPemGenerator.cs
+++ b/crypto/src/openssl/MiscPemGenerator.cs
@@ -1,7 +1,6 @@
 using System;
 using System.Collections;
 using System.IO;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Cms;
@@ -22,117 +21,117 @@ using Org.BouncyCastle.X509;
 
 namespace Org.BouncyCastle.OpenSsl
 {
-	/**
-	* PEM generator for the original set of PEM objects used in Open SSL.
-	*/
-	public class MiscPemGenerator
-		: PemObjectGenerator
-	{
-		private object obj;
-		private string algorithm;
-		private char[] password;
-		private SecureRandom random;
-
-		public MiscPemGenerator(object obj)
-		{
-			this.obj = obj;
-		}
-
-		public MiscPemGenerator(
-			object			obj,
-			string			algorithm,
-			char[]			password,
-			SecureRandom	random)
-		{
-			this.obj = obj;
-			this.algorithm = algorithm;
-			this.password = password;
-			this.random = random;
-		}
-
-		private static PemObject CreatePemObject(object obj)
-		{
-			if (obj == null)
-				throw new ArgumentNullException("obj");
-
-			if (obj is AsymmetricCipherKeyPair)
-			{
-				return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private);
-			}
-
-			string type;
-			byte[] encoding;
-
-			if (obj is PemObject)
-				return (PemObject)obj;
-
-			if (obj is PemObjectGenerator)
-				return ((PemObjectGenerator)obj).Generate();
-
-			if (obj is X509Certificate)
-			{
-				// TODO Should we prefer "X509 CERTIFICATE" here?
-				type = "CERTIFICATE";
-				try
-				{
-					encoding = ((X509Certificate)obj).GetEncoded();
-				}
-				catch (CertificateEncodingException e)
-				{
-					throw new IOException("Cannot Encode object: " + e.ToString());
-				}
-			}
-			else if (obj is X509Crl)
-			{
-				type = "X509 CRL";
-				try
-				{
-					encoding = ((X509Crl)obj).GetEncoded();
-				}
-				catch (CrlException e)
-				{
-					throw new IOException("Cannot Encode object: " + e.ToString());
-				}
-			}
-			else if (obj is AsymmetricKeyParameter)
-			{
-				AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
-				if (akp.IsPrivate)
-				{
-					string keyType;
-					encoding = EncodePrivateKey(akp, out keyType);
-
-					type = keyType + " PRIVATE KEY";
-				}
-				else
-				{
-					type = "PUBLIC KEY";
-
-					encoding = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(akp).GetDerEncoded();
-				}
-			}
-			else if (obj is IX509AttributeCertificate)
-			{
-				type = "ATTRIBUTE CERTIFICATE";
-				encoding = ((X509V2AttributeCertificate)obj).GetEncoded();
-			}
-			else if (obj is Pkcs10CertificationRequest)
-			{
-				type = "CERTIFICATE REQUEST";
-				encoding = ((Pkcs10CertificationRequest)obj).GetEncoded();
-			}
-			else if (obj is Asn1.Cms.ContentInfo)
-			{
-				type = "PKCS7";
-				encoding = ((Asn1.Cms.ContentInfo)obj).GetEncoded();
-			}
-			else
-			{
-				throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
-			}
-
-			return new PemObject(type, encoding);
-		}
+    /**
+    * PEM generator for the original set of PEM objects used in Open SSL.
+    */
+    public class MiscPemGenerator
+        : PemObjectGenerator
+    {
+        private object obj;
+        private string algorithm;
+        private char[] password;
+        private SecureRandom random;
+
+        public MiscPemGenerator(object obj)
+        {
+            this.obj = obj;
+        }
+
+        public MiscPemGenerator(
+            object			obj,
+            string			algorithm,
+            char[]			password,
+            SecureRandom	random)
+        {
+            this.obj = obj;
+            this.algorithm = algorithm;
+            this.password = password;
+            this.random = random;
+        }
+
+        private static PemObject CreatePemObject(object obj)
+        {
+            if (obj == null)
+                throw new ArgumentNullException("obj");
+
+            if (obj is AsymmetricCipherKeyPair)
+            {
+                return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private);
+            }
+
+            string type;
+            byte[] encoding;
+
+            if (obj is PemObject)
+                return (PemObject)obj;
+
+            if (obj is PemObjectGenerator)
+                return ((PemObjectGenerator)obj).Generate();
+
+            if (obj is X509Certificate)
+            {
+                // TODO Should we prefer "X509 CERTIFICATE" here?
+                type = "CERTIFICATE";
+                try
+                {
+                    encoding = ((X509Certificate)obj).GetEncoded();
+                }
+                catch (CertificateEncodingException e)
+                {
+                    throw new IOException("Cannot Encode object: " + e.ToString());
+                }
+            }
+            else if (obj is X509Crl)
+            {
+                type = "X509 CRL";
+                try
+                {
+                    encoding = ((X509Crl)obj).GetEncoded();
+                }
+                catch (CrlException e)
+                {
+                    throw new IOException("Cannot Encode object: " + e.ToString());
+                }
+            }
+            else if (obj is AsymmetricKeyParameter)
+            {
+                AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+                if (akp.IsPrivate)
+                {
+                    string keyType;
+                    encoding = EncodePrivateKey(akp, out keyType);
+
+                    type = keyType + " PRIVATE KEY";
+                }
+                else
+                {
+                    type = "PUBLIC KEY";
+
+                    encoding = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(akp).GetDerEncoded();
+                }
+            }
+            else if (obj is IX509AttributeCertificate)
+            {
+                type = "ATTRIBUTE CERTIFICATE";
+                encoding = ((X509V2AttributeCertificate)obj).GetEncoded();
+            }
+            else if (obj is Pkcs10CertificationRequest)
+            {
+                type = "CERTIFICATE REQUEST";
+                encoding = ((Pkcs10CertificationRequest)obj).GetEncoded();
+            }
+            else if (obj is Asn1.Cms.ContentInfo)
+            {
+                type = "PKCS7";
+                encoding = ((Asn1.Cms.ContentInfo)obj).GetEncoded();
+            }
+            else
+            {
+                throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
+            }
+
+            return new PemObject(type, encoding);
+        }
 
 //		private string GetHexEncoded(byte[] bytes)
 //		{
@@ -148,130 +147,130 @@ namespace Org.BouncyCastle.OpenSsl
 //			return new string(chars);
 //		}
 
-		private static PemObject CreatePemObject(
-			object			obj,
-			string			algorithm,
-			char[]			password,
-			SecureRandom	random)
-		{
-			if (obj == null)
-				throw new ArgumentNullException("obj");
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-			if (password == null)
-				throw new ArgumentNullException("password");
-			if (random == null)
-				throw new ArgumentNullException("random");
-
-			if (obj is AsymmetricCipherKeyPair)
-			{
-				return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private, algorithm, password, random);
-			}
-
-			string type = null;
-			byte[] keyData = null;
-
-			if (obj is AsymmetricKeyParameter)
-			{
-				AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
-				if (akp.IsPrivate)
-				{
-					string keyType;
-					keyData = EncodePrivateKey(akp, out keyType);
-
-					type = keyType + " PRIVATE KEY";
-				}
-			}
-
-			if (type == null || keyData == null)
-			{
-				// TODO Support other types?
-				throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
-			}
-
-
-			string dekAlgName = algorithm.ToUpperInvariant();
-
-			// Note: For backward compatibility
-			if (dekAlgName == "DESEDE")
-			{
-				dekAlgName = "DES-EDE3-CBC";
-			}
-
-			int ivLength = dekAlgName.StartsWith("AES-") ? 16 : 8;
-
-			byte[] iv = new byte[ivLength];
-			random.NextBytes(iv);
-
-			byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv);
-
-			IList headers = Platform.CreateArrayList(2);
-
-			headers.Add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
-			headers.Add(new PemHeader("DEK-Info", dekAlgName + "," + Hex.ToHexString(iv)));
-
-			return new PemObject(type, headers, encData);
-		}
-
-		private static byte[] EncodePrivateKey(
-			AsymmetricKeyParameter	akp,
-			out string				keyType)
-		{
-			PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);
-
-			DerObjectIdentifier oid = info.AlgorithmID.ObjectID;
-
-			if (oid.Equals(X9ObjectIdentifiers.IdDsa))
-			{
-				keyType = "DSA";
-
-				DsaParameter p = DsaParameter.GetInstance(info.AlgorithmID.Parameters);
-
-				BigInteger x = ((DsaPrivateKeyParameters) akp).X;
-				BigInteger y = p.G.ModPow(x, p.P);
-
-				// TODO Create an ASN1 object somewhere for this?
-				return new DerSequence(
-					new DerInteger(0),
-					new DerInteger(p.P),
-					new DerInteger(p.Q),
-					new DerInteger(p.G),
-					new DerInteger(y),
-					new DerInteger(x)).GetEncoded();
-			}
-
-			if (oid.Equals(PkcsObjectIdentifiers.RsaEncryption))
-			{
-				keyType = "RSA";
-			}
-			else if (oid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)
-				|| oid.Equals(X9ObjectIdentifiers.IdECPublicKey))
-			{
-				keyType = "EC";
-			}
-			else
-			{
-				throw new ArgumentException("Cannot handle private key of type: " + akp.GetType().FullName, "akp");
-			}
-
-			return info.PrivateKey.GetEncoded();
-		}
-
-		public PemObject Generate()
-		{
-			try
-			{
-				if (algorithm != null)
-				{
-					return CreatePemObject(obj, algorithm, password, random);
-				}
-
-				return CreatePemObject(obj);
-			}
-			catch (IOException e)
-			{
-				throw new PemGenerationException("encoding exception", e);
-			}
-		}
-	}
+        private static PemObject CreatePemObject(
+            object			obj,
+            string			algorithm,
+            char[]			password,
+            SecureRandom	random)
+        {
+            if (obj == null)
+                throw new ArgumentNullException("obj");
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+            if (password == null)
+                throw new ArgumentNullException("password");
+            if (random == null)
+                throw new ArgumentNullException("random");
+
+            if (obj is AsymmetricCipherKeyPair)
+            {
+                return CreatePemObject(((AsymmetricCipherKeyPair)obj).Private, algorithm, password, random);
+            }
+
+            string type = null;
+            byte[] keyData = null;
+
+            if (obj is AsymmetricKeyParameter)
+            {
+                AsymmetricKeyParameter akp = (AsymmetricKeyParameter) obj;
+                if (akp.IsPrivate)
+                {
+                    string keyType;
+                    keyData = EncodePrivateKey(akp, out keyType);
+
+                    type = keyType + " PRIVATE KEY";
+                }
+            }
+
+            if (type == null || keyData == null)
+            {
+                // TODO Support other types?
+                throw new PemGenerationException("Object type not supported: " + obj.GetType().FullName);
+            }
+
+
+            string dekAlgName = Platform.ToUpperInvariant(algorithm);
+
+            // Note: For backward compatibility
+            if (dekAlgName == "DESEDE")
+            {
+                dekAlgName = "DES-EDE3-CBC";
+            }
+
+            int ivLength = dekAlgName.StartsWith("AES-") ? 16 : 8;
+
+            byte[] iv = new byte[ivLength];
+            random.NextBytes(iv);
+
+            byte[] encData = PemUtilities.Crypt(true, keyData, password, dekAlgName, iv);
+
+            IList headers = Platform.CreateArrayList(2);
+
+            headers.Add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
+            headers.Add(new PemHeader("DEK-Info", dekAlgName + "," + Hex.ToHexString(iv)));
+
+            return new PemObject(type, headers, encData);
+        }
+
+        private static byte[] EncodePrivateKey(
+            AsymmetricKeyParameter	akp,
+            out string				keyType)
+        {
+            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(akp);
+            AlgorithmIdentifier algID = info.PrivateKeyAlgorithm;
+            DerObjectIdentifier oid = algID.ObjectID;
+
+            if (oid.Equals(X9ObjectIdentifiers.IdDsa))
+            {
+                keyType = "DSA";
+
+                DsaParameter p = DsaParameter.GetInstance(algID.Parameters);
+
+                BigInteger x = ((DsaPrivateKeyParameters) akp).X;
+                BigInteger y = p.G.ModPow(x, p.P);
+
+                // TODO Create an ASN1 object somewhere for this?
+                return new DerSequence(
+                    new DerInteger(0),
+                    new DerInteger(p.P),
+                    new DerInteger(p.Q),
+                    new DerInteger(p.G),
+                    new DerInteger(y),
+                    new DerInteger(x)).GetEncoded();
+            }
+
+            if (oid.Equals(PkcsObjectIdentifiers.RsaEncryption))
+            {
+                keyType = "RSA";
+            }
+            else if (oid.Equals(CryptoProObjectIdentifiers.GostR3410x2001)
+                || oid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+            {
+                keyType = "EC";
+            }
+            else
+            {
+                throw new ArgumentException("Cannot handle private key of type: " + akp.GetType().FullName, "akp");
+            }
+
+            return info.ParsePrivateKey().GetEncoded();
+        }
+
+        public PemObject Generate()
+        {
+            try
+            {
+                if (algorithm != null)
+                {
+                    return CreatePemObject(obj, algorithm, password, random);
+                }
+
+                return CreatePemObject(obj);
+            }
+            catch (IOException e)
+            {
+                throw new PemGenerationException("encoding exception", e);
+            }
+        }
+    }
 }
diff --git a/crypto/src/openssl/PEMException.cs b/crypto/src/openssl/PEMException.cs
index df0eebc69..4d33a2a1f 100644
--- a/crypto/src/openssl/PEMException.cs
+++ b/crypto/src/openssl/PEMException.cs
@@ -3,7 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.OpenSsl
 {
-	public class PemException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PemException
 		: IOException
 	{
 		public PemException(
diff --git a/crypto/src/openssl/PEMReader.cs b/crypto/src/openssl/PEMReader.cs
index a2fedab96..9d3560838 100644
--- a/crypto/src/openssl/PEMReader.cs
+++ b/crypto/src/openssl/PEMReader.cs
@@ -12,6 +12,7 @@ using Org.BouncyCastle.Asn1.TeleTrust;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.EC;
 using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Pkcs;
@@ -23,20 +24,20 @@ using Org.BouncyCastle.X509;
 
 namespace Org.BouncyCastle.OpenSsl
 {
-	/**
-	* Class for reading OpenSSL PEM encoded streams containing 
-	* X509 certificates, PKCS8 encoded keys and PKCS7 objects.
-	* <p>
-	* In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and
-	* Certificates will be returned using the appropriate java.security type.</p>
-	*/
-	public class PemReader
-		: Org.BouncyCastle.Utilities.IO.Pem.PemReader
-	{
+    /**
+    * Class for reading OpenSSL PEM encoded streams containing 
+    * X509 certificates, PKCS8 encoded keys and PKCS7 objects.
+    * <p>
+    * In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Keys and
+    * Certificates will be returned using the appropriate java.security type.</p>
+    */
+    public class PemReader
+        : Org.BouncyCastle.Utilities.IO.Pem.PemReader
+    {
 //		private static readonly IDictionary parsers = new Hashtable();
 
-		static PemReader()
-		{
+        static PemReader()
+        {
 //			parsers.Add("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
 //			parsers.Add("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
 //			parsers.Add("CERTIFICATE", new X509CertificateParser(provider));
@@ -52,323 +53,323 @@ namespace Org.BouncyCastle.OpenSsl
 //			parsers.Add("EC PRIVATE KEY", new ECDSAKeyPairParser(provider));
 //			parsers.Add("ENCRYPTED PRIVATE KEY", new EncryptedPrivateKeyParser(provider));
 //			parsers.Add("PRIVATE KEY", new PrivateKeyParser(provider));
-		}
-
-		private readonly IPasswordFinder pFinder;
-
-		/**
-		* Create a new PemReader
-		*
-		* @param reader the Reader
-		*/
-		public PemReader(
-			TextReader reader)
-			: this(reader, null)
-		{
-		}
-
-		/**
-		* Create a new PemReader with a password finder
-		*
-		* @param reader the Reader
-		* @param pFinder the password finder
-		*/
-		public PemReader(
-			TextReader		reader,
-			IPasswordFinder	pFinder)
-			: base(reader)
-		{
-			this.pFinder = pFinder;
-		}
-
-		public object ReadObject()
-		{
-			PemObject obj = ReadPemObject();
-
-			if (obj == null)
-				return null;
-
-			// TODO Follow Java build and map to parser objects?
+        }
+
+        private readonly IPasswordFinder pFinder;
+
+        /**
+        * Create a new PemReader
+        *
+        * @param reader the Reader
+        */
+        public PemReader(
+            TextReader reader)
+            : this(reader, null)
+        {
+        }
+
+        /**
+        * Create a new PemReader with a password finder
+        *
+        * @param reader the Reader
+        * @param pFinder the password finder
+        */
+        public PemReader(
+            TextReader		reader,
+            IPasswordFinder	pFinder)
+            : base(reader)
+        {
+            this.pFinder = pFinder;
+        }
+
+        public object ReadObject()
+        {
+            PemObject obj = ReadPemObject();
+
+            if (obj == null)
+                return null;
+
+            // TODO Follow Java build and map to parser objects?
 //			if (parsers.Contains(obj.Type))
 //				return ((PemObjectParser)parsers[obj.Type]).ParseObject(obj);
 
-			if (obj.Type.EndsWith("PRIVATE KEY"))
-				return ReadPrivateKey(obj);
-
-			switch (obj.Type)
-			{
-				case "PUBLIC KEY":
-					return ReadPublicKey(obj);
-				case "RSA PUBLIC KEY":
-					return ReadRsaPublicKey(obj);
-				case "CERTIFICATE REQUEST":
-				case "NEW CERTIFICATE REQUEST":
-					return ReadCertificateRequest(obj);
-				case "CERTIFICATE":
-				case "X509 CERTIFICATE":
-					return ReadCertificate(obj);
-				case "PKCS7":
-					return ReadPkcs7(obj);
-				case "X509 CRL":
-					return ReadCrl(obj);
-				case "ATTRIBUTE CERTIFICATE":
-					return ReadAttributeCertificate(obj);
-				// TODO Add back in when tests done, and return type issue resolved
-				//case "EC PARAMETERS":
-				//	return ReadECParameters(obj);
-				default:
-					throw new IOException("unrecognised object: " + obj.Type);
-			}
-		}
-
-		private AsymmetricKeyParameter ReadRsaPublicKey(PemObject pemObject)
-		{
-			RsaPublicKeyStructure rsaPubStructure = RsaPublicKeyStructure.GetInstance(
-				Asn1Object.FromByteArray(pemObject.Content));
-
-			return new RsaKeyParameters(
-				false, // not private
-				rsaPubStructure.Modulus, 
-				rsaPubStructure.PublicExponent);
-		}
-
-		private AsymmetricKeyParameter ReadPublicKey(PemObject pemObject)
-		{
-			return PublicKeyFactory.CreateKey(pemObject.Content);
-		}
-
-		/**
-		* Reads in a X509Certificate.
-		*
-		* @return the X509Certificate
-		* @throws IOException if an I/O error occured
-		*/
-		private X509Certificate ReadCertificate(PemObject pemObject)
-		{
-			try
-			{
-				return new X509CertificateParser().ReadCertificate(pemObject.Content);
-			}
-			catch (Exception e)
-			{
-				throw new PemException("problem parsing cert: " + e.ToString());
-			}
-		}
-
-		/**
-		* Reads in a X509CRL.
-		*
-		* @return the X509Certificate
-		* @throws IOException if an I/O error occured
-		*/
-		private X509Crl ReadCrl(PemObject pemObject)
-		{
-			try
-			{
-				return new X509CrlParser().ReadCrl(pemObject.Content);
-			}
-			catch (Exception e)
-			{
-				throw new PemException("problem parsing cert: " + e.ToString());
-			}
-		}
-
-		/**
-		* Reads in a PKCS10 certification request.
-		*
-		* @return the certificate request.
-		* @throws IOException if an I/O error occured
-		*/
-		private Pkcs10CertificationRequest ReadCertificateRequest(PemObject pemObject)
-		{
-			try
-			{
-				return new Pkcs10CertificationRequest(pemObject.Content);
-			}
-			catch (Exception e)
-			{
-				throw new PemException("problem parsing cert: " + e.ToString());
-			}
-		}
-
-		/**
-		* Reads in a X509 Attribute Certificate.
-		*
-		* @return the X509 Attribute Certificate
-		* @throws IOException if an I/O error occured
-		*/
-		private IX509AttributeCertificate ReadAttributeCertificate(PemObject pemObject)
-		{
-			return new X509V2AttributeCertificate(pemObject.Content);
-		}
-
-		/**
-		* Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
-		* API.
-		*
-		* @return the X509Certificate
-		* @throws IOException if an I/O error occured
-		*/
-		// TODO Consider returning Asn1.Pkcs.ContentInfo
-		private Asn1.Cms.ContentInfo ReadPkcs7(PemObject pemObject)
-		{
-			try
-			{
-				return Asn1.Cms.ContentInfo.GetInstance(
-					Asn1Object.FromByteArray(pemObject.Content));
-			}
-			catch (Exception e)
-			{
-				throw new PemException("problem parsing PKCS7 object: " + e.ToString());
-			}
-		}
-
-		/**
-		* Read a Key Pair
-		*/
-		private object ReadPrivateKey(PemObject pemObject)
-		{
-			//
-			// extract the key
-			//
-			Debug.Assert(pemObject.Type.EndsWith("PRIVATE KEY"));
-
-			string type = pemObject.Type.Substring(0, pemObject.Type.Length - "PRIVATE KEY".Length).Trim();
-			byte[] keyBytes = pemObject.Content;
-
-			IDictionary fields = Platform.CreateHashtable();
-			foreach (PemHeader header in pemObject.Headers)
-			{
-				fields[header.Name] = header.Value;
-			}
-
-			string procType = (string) fields["Proc-Type"];
-
-			if (procType == "4,ENCRYPTED")
-			{
-				if (pFinder == null)
-					throw new PasswordException("No password finder specified, but a password is required");
-
-				char[] password = pFinder.GetPassword();
-
-				if (password == null)
-					throw new PasswordException("Password is null, but a password is required");
-
-				string dekInfo = (string) fields["DEK-Info"];
-				string[] tknz = dekInfo.Split(',');
-
-				string dekAlgName = tknz[0].Trim();
-				byte[] iv = Hex.Decode(tknz[1].Trim());
-
-				keyBytes = PemUtilities.Crypt(false, keyBytes, password, dekAlgName, iv);
-			}
-
-			try
-			{
-				AsymmetricKeyParameter pubSpec, privSpec;
-				Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(keyBytes);
-
-				switch (type)
-				{
-					case "RSA":
-					{
-						if (seq.Count != 9)
-							throw new PemException("malformed sequence in RSA private key");
-
-						RsaPrivateKeyStructure rsa = new RsaPrivateKeyStructure(seq);
-
-						pubSpec = new RsaKeyParameters(false, rsa.Modulus, rsa.PublicExponent);
-						privSpec = new RsaPrivateCrtKeyParameters(
-							rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent,
-							rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2,
-							rsa.Coefficient);
-
-						break;
-					}
-
-					case "DSA":
-					{
-						if (seq.Count != 6)
-							throw new PemException("malformed sequence in DSA private key");
-
-						// TODO Create an ASN1 object somewhere for this?
-						//DerInteger v = (DerInteger)seq[0];
-						DerInteger p = (DerInteger)seq[1];
-						DerInteger q = (DerInteger)seq[2];
-						DerInteger g = (DerInteger)seq[3];
-						DerInteger y = (DerInteger)seq[4];
-						DerInteger x = (DerInteger)seq[5];
-
-						DsaParameters parameters = new DsaParameters(p.Value, q.Value, g.Value);
-
-						privSpec = new DsaPrivateKeyParameters(x.Value, parameters);
-						pubSpec = new DsaPublicKeyParameters(y.Value, parameters);
-
-						break;
-					}
-
-					case "EC":
-					{
-						ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq);
-						AlgorithmIdentifier algId = new AlgorithmIdentifier(
-							X9ObjectIdentifiers.IdECPublicKey, pKey.GetParameters());
-
-						PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.ToAsn1Object());
-
-						// TODO Are the keys returned here ECDSA, as Java version forces?
-						privSpec = PrivateKeyFactory.CreateKey(privInfo);
-
-						DerBitString pubKey = pKey.GetPublicKey();
-						if (pubKey != null)
-						{
-							SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pubKey.GetBytes());
-
-							// TODO Are the keys returned here ECDSA, as Java version forces?
-							pubSpec = PublicKeyFactory.CreateKey(pubInfo);
-						}
-						else
-						{
-							pubSpec = ECKeyPairGenerator.GetCorrespondingPublicKey(
-								(ECPrivateKeyParameters)privSpec);
-						}
-
-						break;
-					}
-
-					case "ENCRYPTED":
-					{
-						char[] password = pFinder.GetPassword();
-
-						if (password == null)
-							throw new PasswordException("Password is null, but a password is required");
-
-						return PrivateKeyFactory.DecryptKey(password, EncryptedPrivateKeyInfo.GetInstance(seq));
-					}
-
-					case "":
-					{
-						return PrivateKeyFactory.CreateKey(PrivateKeyInfo.GetInstance(seq));
-					}
-
-					default:
-						throw new ArgumentException("Unknown key type: " + type, "type");
-				}
-
-				return new AsymmetricCipherKeyPair(pubSpec, privSpec);
-			}
-			catch (IOException e)
-			{
-				throw e;
-			}
-			catch (Exception e)
-			{
-				throw new PemException(
-					"problem creating " + type + " private key: " + e.ToString());
-			}
-		}
-
-		// TODO Add an equivalent class for ECNamedCurveParameterSpec?
-		//private ECNamedCurveParameterSpec ReadECParameters(
+            if (obj.Type.EndsWith("PRIVATE KEY"))
+                return ReadPrivateKey(obj);
+
+            switch (obj.Type)
+            {
+                case "PUBLIC KEY":
+                    return ReadPublicKey(obj);
+                case "RSA PUBLIC KEY":
+                    return ReadRsaPublicKey(obj);
+                case "CERTIFICATE REQUEST":
+                case "NEW CERTIFICATE REQUEST":
+                    return ReadCertificateRequest(obj);
+                case "CERTIFICATE":
+                case "X509 CERTIFICATE":
+                    return ReadCertificate(obj);
+                case "PKCS7":
+                    return ReadPkcs7(obj);
+                case "X509 CRL":
+                    return ReadCrl(obj);
+                case "ATTRIBUTE CERTIFICATE":
+                    return ReadAttributeCertificate(obj);
+                // TODO Add back in when tests done, and return type issue resolved
+                //case "EC PARAMETERS":
+                //	return ReadECParameters(obj);
+                default:
+                    throw new IOException("unrecognised object: " + obj.Type);
+            }
+        }
+
+        private AsymmetricKeyParameter ReadRsaPublicKey(PemObject pemObject)
+        {
+            RsaPublicKeyStructure rsaPubStructure = RsaPublicKeyStructure.GetInstance(
+                Asn1Object.FromByteArray(pemObject.Content));
+
+            return new RsaKeyParameters(
+                false, // not private
+                rsaPubStructure.Modulus, 
+                rsaPubStructure.PublicExponent);
+        }
+
+        private AsymmetricKeyParameter ReadPublicKey(PemObject pemObject)
+        {
+            return PublicKeyFactory.CreateKey(pemObject.Content);
+        }
+
+        /**
+        * Reads in a X509Certificate.
+        *
+        * @return the X509Certificate
+        * @throws IOException if an I/O error occured
+        */
+        private X509Certificate ReadCertificate(PemObject pemObject)
+        {
+            try
+            {
+                return new X509CertificateParser().ReadCertificate(pemObject.Content);
+            }
+            catch (Exception e)
+            {
+                throw new PemException("problem parsing cert: " + e.ToString());
+            }
+        }
+
+        /**
+        * Reads in a X509CRL.
+        *
+        * @return the X509Certificate
+        * @throws IOException if an I/O error occured
+        */
+        private X509Crl ReadCrl(PemObject pemObject)
+        {
+            try
+            {
+                return new X509CrlParser().ReadCrl(pemObject.Content);
+            }
+            catch (Exception e)
+            {
+                throw new PemException("problem parsing cert: " + e.ToString());
+            }
+        }
+
+        /**
+        * Reads in a PKCS10 certification request.
+        *
+        * @return the certificate request.
+        * @throws IOException if an I/O error occured
+        */
+        private Pkcs10CertificationRequest ReadCertificateRequest(PemObject pemObject)
+        {
+            try
+            {
+                return new Pkcs10CertificationRequest(pemObject.Content);
+            }
+            catch (Exception e)
+            {
+                throw new PemException("problem parsing cert: " + e.ToString());
+            }
+        }
+
+        /**
+        * Reads in a X509 Attribute Certificate.
+        *
+        * @return the X509 Attribute Certificate
+        * @throws IOException if an I/O error occured
+        */
+        private IX509AttributeCertificate ReadAttributeCertificate(PemObject pemObject)
+        {
+            return new X509V2AttributeCertificate(pemObject.Content);
+        }
+
+        /**
+        * Reads in a PKCS7 object. This returns a ContentInfo object suitable for use with the CMS
+        * API.
+        *
+        * @return the X509Certificate
+        * @throws IOException if an I/O error occured
+        */
+        // TODO Consider returning Asn1.Pkcs.ContentInfo
+        private Asn1.Cms.ContentInfo ReadPkcs7(PemObject pemObject)
+        {
+            try
+            {
+                return Asn1.Cms.ContentInfo.GetInstance(
+                    Asn1Object.FromByteArray(pemObject.Content));
+            }
+            catch (Exception e)
+            {
+                throw new PemException("problem parsing PKCS7 object: " + e.ToString());
+            }
+        }
+
+        /**
+        * Read a Key Pair
+        */
+        private object ReadPrivateKey(PemObject pemObject)
+        {
+            //
+            // extract the key
+            //
+            Debug.Assert(pemObject.Type.EndsWith("PRIVATE KEY"));
+
+            string type = pemObject.Type.Substring(0, pemObject.Type.Length - "PRIVATE KEY".Length).Trim();
+            byte[] keyBytes = pemObject.Content;
+
+            IDictionary fields = Platform.CreateHashtable();
+            foreach (PemHeader header in pemObject.Headers)
+            {
+                fields[header.Name] = header.Value;
+            }
+
+            string procType = (string) fields["Proc-Type"];
+
+            if (procType == "4,ENCRYPTED")
+            {
+                if (pFinder == null)
+                    throw new PasswordException("No password finder specified, but a password is required");
+
+                char[] password = pFinder.GetPassword();
+
+                if (password == null)
+                    throw new PasswordException("Password is null, but a password is required");
+
+                string dekInfo = (string) fields["DEK-Info"];
+                string[] tknz = dekInfo.Split(',');
+
+                string dekAlgName = tknz[0].Trim();
+                byte[] iv = Hex.Decode(tknz[1].Trim());
+
+                keyBytes = PemUtilities.Crypt(false, keyBytes, password, dekAlgName, iv);
+            }
+
+            try
+            {
+                AsymmetricKeyParameter pubSpec, privSpec;
+                Asn1Sequence seq = Asn1Sequence.GetInstance(keyBytes);
+
+                switch (type)
+                {
+                    case "RSA":
+                    {
+                        if (seq.Count != 9)
+                            throw new PemException("malformed sequence in RSA private key");
+
+                        RsaPrivateKeyStructure rsa = new RsaPrivateKeyStructure(seq);
+
+                        pubSpec = new RsaKeyParameters(false, rsa.Modulus, rsa.PublicExponent);
+                        privSpec = new RsaPrivateCrtKeyParameters(
+                            rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent,
+                            rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2,
+                            rsa.Coefficient);
+
+                        break;
+                    }
+
+                    case "DSA":
+                    {
+                        if (seq.Count != 6)
+                            throw new PemException("malformed sequence in DSA private key");
+
+                        // TODO Create an ASN1 object somewhere for this?
+                        //DerInteger v = (DerInteger)seq[0];
+                        DerInteger p = (DerInteger)seq[1];
+                        DerInteger q = (DerInteger)seq[2];
+                        DerInteger g = (DerInteger)seq[3];
+                        DerInteger y = (DerInteger)seq[4];
+                        DerInteger x = (DerInteger)seq[5];
+
+                        DsaParameters parameters = new DsaParameters(p.Value, q.Value, g.Value);
+
+                        privSpec = new DsaPrivateKeyParameters(x.Value, parameters);
+                        pubSpec = new DsaPublicKeyParameters(y.Value, parameters);
+
+                        break;
+                    }
+
+                    case "EC":
+                    {
+                        ECPrivateKeyStructure pKey = new ECPrivateKeyStructure(seq);
+                        AlgorithmIdentifier algId = new AlgorithmIdentifier(
+                            X9ObjectIdentifiers.IdECPublicKey, pKey.GetParameters());
+
+                        PrivateKeyInfo privInfo = new PrivateKeyInfo(algId, pKey.ToAsn1Object());
+
+                        // TODO Are the keys returned here ECDSA, as Java version forces?
+                        privSpec = PrivateKeyFactory.CreateKey(privInfo);
+
+                        DerBitString pubKey = pKey.GetPublicKey();
+                        if (pubKey != null)
+                        {
+                            SubjectPublicKeyInfo pubInfo = new SubjectPublicKeyInfo(algId, pubKey.GetBytes());
+
+                            // TODO Are the keys returned here ECDSA, as Java version forces?
+                            pubSpec = PublicKeyFactory.CreateKey(pubInfo);
+                        }
+                        else
+                        {
+                            pubSpec = ECKeyPairGenerator.GetCorrespondingPublicKey(
+                                (ECPrivateKeyParameters)privSpec);
+                        }
+
+                        break;
+                    }
+
+                    case "ENCRYPTED":
+                    {
+                        char[] password = pFinder.GetPassword();
+
+                        if (password == null)
+                            throw new PasswordException("Password is null, but a password is required");
+
+                        return PrivateKeyFactory.DecryptKey(password, EncryptedPrivateKeyInfo.GetInstance(seq));
+                    }
+
+                    case "":
+                    {
+                        return PrivateKeyFactory.CreateKey(PrivateKeyInfo.GetInstance(seq));
+                    }
+
+                    default:
+                        throw new ArgumentException("Unknown key type: " + type, "type");
+                }
+
+                return new AsymmetricCipherKeyPair(pubSpec, privSpec);
+            }
+            catch (IOException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PemException(
+                    "problem creating " + type + " private key: " + e.ToString());
+            }
+        }
+
+        // TODO Add an equivalent class for ECNamedCurveParameterSpec?
+        //private ECNamedCurveParameterSpec ReadECParameters(
 //		private X9ECParameters ReadECParameters(PemObject pemObject)
 //		{
 //			DerObjectIdentifier oid = (DerObjectIdentifier)Asn1Object.FromByteArray(pemObject.Content);
@@ -377,31 +378,23 @@ namespace Org.BouncyCastle.OpenSsl
 //			return GetCurveParameters(oid.Id);
 //		}
 
-		//private static ECDomainParameters GetCurveParameters(
-		private static X9ECParameters GetCurveParameters(
-			string name)
-		{
-			// TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
-			X9ECParameters ecP = X962NamedCurves.GetByName(name);
-
-			if (ecP == null)
-			{
-				ecP = SecNamedCurves.GetByName(name);
-				if (ecP == null)
-				{
-					ecP = NistNamedCurves.GetByName(name);
-					if (ecP == null)
-					{
-						ecP = TeleTrusTNamedCurves.GetByName(name);
-
-						if (ecP == null)
-							throw new Exception("unknown curve name: " + name);
-					}
-				}
-			}
-
-			//return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
-			return ecP;
-		}
-	}
+        //private static ECDomainParameters GetCurveParameters(
+        private static X9ECParameters GetCurveParameters(
+            string name)
+        {
+            // TODO ECGost3410NamedCurves support (returns ECDomainParameters though)
+
+            X9ECParameters ecP = CustomNamedCurves.GetByName(name);
+            if (ecP == null)
+            {
+                ecP = ECNamedCurveTable.GetByName(name);
+            }
+
+            if (ecP == null)
+                throw new Exception("unknown curve name: " + name);
+
+            //return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+            return ecP;
+        }
+    }
 }
diff --git a/crypto/src/openssl/PEMUtilities.cs b/crypto/src/openssl/PEMUtilities.cs
new file mode 100644
index 000000000..b58e5e765
--- /dev/null
+++ b/crypto/src/openssl/PEMUtilities.cs
@@ -0,0 +1,158 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+	internal sealed class PemUtilities
+	{
+		private enum PemBaseAlg { AES_128, AES_192, AES_256, BF, DES, DES_EDE, DES_EDE3, RC2, RC2_40, RC2_64 };
+		private enum PemMode { CBC, CFB, ECB, OFB };
+
+		static PemUtilities()
+		{
+			// Signal to obfuscation tools not to change enum constants
+			((PemBaseAlg)Enums.GetArbitraryValue(typeof(PemBaseAlg))).ToString();
+			((PemMode)Enums.GetArbitraryValue(typeof(PemMode))).ToString();
+		}
+
+		private static void ParseDekAlgName(
+			string			dekAlgName,
+			out PemBaseAlg	baseAlg,
+			out PemMode		mode)
+		{
+			try
+			{
+				mode = PemMode.ECB;
+
+				if (dekAlgName == "DES-EDE" || dekAlgName == "DES-EDE3")
+				{
+					baseAlg = (PemBaseAlg)Enums.GetEnumValue(typeof(PemBaseAlg), dekAlgName);
+					return;
+				}
+
+				int pos = dekAlgName.LastIndexOf('-');
+				if (pos >= 0)
+				{
+					baseAlg = (PemBaseAlg)Enums.GetEnumValue(typeof(PemBaseAlg), dekAlgName.Substring(0, pos));
+					mode = (PemMode)Enums.GetEnumValue(typeof(PemMode), dekAlgName.Substring(pos + 1));
+					return;
+				}
+			}
+			catch (ArgumentException)
+			{
+			}
+
+			throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+		}
+
+		internal static byte[] Crypt(
+			bool	encrypt,
+			byte[]	bytes,
+			char[]	password,
+			string	dekAlgName,
+			byte[]	iv)
+		{
+			PemBaseAlg baseAlg;
+			PemMode mode;
+			ParseDekAlgName(dekAlgName, out baseAlg, out mode);
+
+			string padding;
+			switch (mode)
+			{
+				case PemMode.CBC:
+				case PemMode.ECB:
+					padding = "PKCS5Padding";
+					break;
+				case PemMode.CFB:
+				case PemMode.OFB:
+					padding = "NoPadding";
+					break;
+				default:
+					throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+			}
+
+			string algorithm;
+
+			byte[] salt = iv;
+			switch (baseAlg)
+			{
+				case PemBaseAlg.AES_128:
+				case PemBaseAlg.AES_192:
+				case PemBaseAlg.AES_256:
+					algorithm = "AES";
+					if (salt.Length > 8)
+					{
+						salt = new byte[8];
+						Array.Copy(iv, 0, salt, 0, salt.Length);
+					}
+					break;
+				case PemBaseAlg.BF:
+					algorithm = "BLOWFISH";
+					break;
+				case PemBaseAlg.DES:
+					algorithm = "DES";
+					break;
+				case PemBaseAlg.DES_EDE:
+				case PemBaseAlg.DES_EDE3:
+					algorithm = "DESede";
+					break;
+				case PemBaseAlg.RC2:
+				case PemBaseAlg.RC2_40:
+				case PemBaseAlg.RC2_64:
+					algorithm = "RC2";
+					break;
+				default:
+					throw new EncryptionException("Unknown DEK algorithm: " + dekAlgName);
+			}
+
+			string cipherName = algorithm + "/" + mode + "/" + padding;
+			IBufferedCipher cipher = CipherUtilities.GetCipher(cipherName);
+
+			ICipherParameters cParams = GetCipherParameters(password, baseAlg, salt);
+
+			if (mode != PemMode.ECB)
+			{
+				cParams = new ParametersWithIV(cParams, iv);
+			}
+
+			cipher.Init(encrypt, cParams);
+
+			return cipher.DoFinal(bytes);
+		}
+
+		private static ICipherParameters GetCipherParameters(
+			char[]		password,
+			PemBaseAlg	baseAlg,
+			byte[]		salt)
+		{
+			string algorithm;
+			int keyBits;
+			switch (baseAlg)
+			{
+				case PemBaseAlg.AES_128:		keyBits = 128;	algorithm = "AES128";	break;
+				case PemBaseAlg.AES_192:		keyBits = 192;	algorithm = "AES192";	break;
+				case PemBaseAlg.AES_256:		keyBits = 256;	algorithm = "AES256";	break;
+				case PemBaseAlg.BF:				keyBits = 128;	algorithm = "BLOWFISH";	break;
+				case PemBaseAlg.DES:			keyBits = 64;	algorithm = "DES";		break;
+				case PemBaseAlg.DES_EDE:		keyBits = 128;	algorithm = "DESEDE";	break;
+				case PemBaseAlg.DES_EDE3:		keyBits = 192;	algorithm = "DESEDE3";	break;
+				case PemBaseAlg.RC2:			keyBits = 128;	algorithm = "RC2";		break;
+				case PemBaseAlg.RC2_40:			keyBits = 40;	algorithm = "RC2";		break;
+				case PemBaseAlg.RC2_64:			keyBits = 64;	algorithm = "RC2";		break;
+				default:
+					return null;
+			}
+
+			OpenSslPbeParametersGenerator pGen = new OpenSslPbeParametersGenerator();
+
+			pGen.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password), salt);
+
+			return pGen.GenerateDerivedParameters(algorithm, keyBits);
+		}
+	}
+}
diff --git a/crypto/src/openssl/PEMWriter.cs b/crypto/src/openssl/PEMWriter.cs
new file mode 100644
index 000000000..aefb018f3
--- /dev/null
+++ b/crypto/src/openssl/PEMWriter.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+	/// <remarks>General purpose writer for OpenSSL PEM objects.</remarks>
+	public class PemWriter
+		: Org.BouncyCastle.Utilities.IO.Pem.PemWriter
+	{
+		/// <param name="writer">The TextWriter object to write the output to.</param>
+		public PemWriter(
+			TextWriter writer)
+			: base(writer)
+		{
+		}
+
+		public void WriteObject(
+			object obj) 
+		{
+			try
+			{
+				base.WriteObject(new MiscPemGenerator(obj));
+			}
+			catch (PemGenerationException e)
+			{
+				if (e.InnerException is IOException)
+					throw (IOException)e.InnerException;
+
+				throw e;
+			}
+		}
+
+		public void WriteObject(
+			object			obj,
+			string			algorithm,
+			char[]			password,
+			SecureRandom	random)
+		{
+			base.WriteObject(new MiscPemGenerator(obj, algorithm, password, random));
+		}
+	}
+}
diff --git a/crypto/src/openssl/PasswordException.cs b/crypto/src/openssl/PasswordException.cs
index b21dee231..fba958aa0 100644
--- a/crypto/src/openssl/PasswordException.cs
+++ b/crypto/src/openssl/PasswordException.cs
@@ -3,7 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.Security
 {
-	public class PasswordException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PasswordException
 		: IOException
 	{
 		public PasswordException(
diff --git a/crypto/src/openssl/Pkcs8Generator.cs b/crypto/src/openssl/Pkcs8Generator.cs
new file mode 100644
index 000000000..d03ea08d2
--- /dev/null
+++ b/crypto/src/openssl/Pkcs8Generator.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO.Pem;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+	public class Pkcs8Generator
+		: PemObjectGenerator
+	{
+		// FIXME See PbeUtilities static constructor
+//		public static readonly string Aes128Cbc = NistObjectIdentifiers.IdAes128Cbc.Id;
+//		public static readonly string Aes192Cbc = NistObjectIdentifiers.IdAes192Cbc.Id;
+//		public static readonly string Aes256Cbc = NistObjectIdentifiers.IdAes256Cbc.Id;
+//
+//		public static readonly string Des3Cbc = PkcsObjectIdentifiers.DesEde3Cbc.Id;
+
+		public static readonly string PbeSha1_RC4_128 = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id;
+		public static readonly string PbeSha1_RC4_40 = PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id;
+		public static readonly string PbeSha1_3DES = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id;
+		public static readonly string PbeSha1_2DES = PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id;
+		public static readonly string PbeSha1_RC2_128 = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id;
+		public static readonly string PbeSha1_RC2_40 = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id;
+
+		private char[]					password;
+		private string					algorithm;
+		private int						iterationCount;
+		private AsymmetricKeyParameter	privKey;
+		private SecureRandom			random;
+
+		/**
+		* Constructor for an unencrypted private key PEM object.
+		*
+		* @param key private key to be encoded.
+		*/
+		public Pkcs8Generator(AsymmetricKeyParameter privKey)
+		{
+			this.privKey = privKey;
+		}
+
+		/**
+		* Constructor for an encrypted private key PEM object.
+		*
+		* @param key       private key to be encoded
+		* @param algorithm encryption algorithm to use
+		* @param provider  provider to use
+		* @throws NoSuchAlgorithmException if algorithm/mode cannot be found
+		*/
+		public Pkcs8Generator(AsymmetricKeyParameter privKey, string algorithm)
+		{
+			// TODO Check privKey.IsPrivate
+			this.privKey = privKey;
+			this.algorithm = algorithm;
+			this.iterationCount = 2048;
+		}
+
+		public SecureRandom SecureRandom
+		{
+			set { this.random = value; }
+		}
+
+		public char[] Password
+		{
+			set { this.password = value; }
+		}
+
+		public int IterationCount
+		{
+			set { this.iterationCount = value; }
+		}
+
+		public PemObject Generate()
+		{
+			if (algorithm == null)
+			{
+				PrivateKeyInfo pki = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privKey);
+
+				return new PemObject("PRIVATE KEY", pki.GetEncoded());
+			}
+
+			// TODO Theoretically, the amount of salt needed depends on the algorithm
+			byte[] salt = new byte[20];
+			if (random == null)
+			{
+				random = new SecureRandom();
+			}
+			random.NextBytes(salt);
+
+			try
+			{
+				EncryptedPrivateKeyInfo epki = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+					algorithm, password, salt, iterationCount, privKey);
+	
+				return new PemObject("ENCRYPTED PRIVATE KEY", epki.GetEncoded());
+			}
+			catch (Exception e)
+			{
+				throw new PemGenerationException("Couldn't encrypt private key", e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/pkcs/AsymmetricKeyEntry.cs b/crypto/src/pkcs/AsymmetricKeyEntry.cs
index 6da3ade3e..1c37631d5 100644
--- a/crypto/src/pkcs/AsymmetricKeyEntry.cs
+++ b/crypto/src/pkcs/AsymmetricKeyEntry.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Pkcs
             this.key = key;
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete]
         public AsymmetricKeyEntry(
             AsymmetricKeyParameter key,
diff --git a/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs b/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
index b69693490..b6b7bac65 100644
--- a/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
@@ -22,54 +22,43 @@ namespace Org.BouncyCastle.Pkcs
             AsymmetricKeyParameter	key)
         {
             return CreateEncryptedPrivateKeyInfo(
-				algorithm.Id, passPhrase, salt, iterationCount,
-				PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+                algorithm.Id, passPhrase, salt, iterationCount,
+                PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
         }
 
-		public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
-			string					algorithm,
-			char[]					passPhrase,
-			byte[]					salt,
-			int						iterationCount,
-			AsymmetricKeyParameter	key)
-		{
-			return CreateEncryptedPrivateKeyInfo(
-				algorithm, passPhrase, salt, iterationCount,
-				PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
-		}
+        public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+            string					algorithm,
+            char[]					passPhrase,
+            byte[]					salt,
+            int						iterationCount,
+            AsymmetricKeyParameter	key)
+        {
+            return CreateEncryptedPrivateKeyInfo(
+                algorithm, passPhrase, salt, iterationCount,
+                PrivateKeyInfoFactory.CreatePrivateKeyInfo(key));
+        }
 
-		public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+        public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
             string			algorithm,
             char[]			passPhrase,
             byte[]			salt,
             int				iterationCount,
             PrivateKeyInfo	keyInfo)
         {
-            if (!PbeUtilities.IsPbeAlgorithm(algorithm))
-                throw new ArgumentException("attempt to use non-PBE algorithm with PBE EncryptedPrivateKeyInfo generation");
-
-			IBufferedCipher cipher = PbeUtilities.CreateEngine(algorithm) as IBufferedCipher;
-
-			if (cipher == null)
-			{
-				// TODO Throw exception?
-			}
-
-			Asn1Encodable parameters = PbeUtilities.GenerateAlgorithmParameters(
-				algorithm, salt, iterationCount);
-
-			ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters(
-				algorithm, passPhrase, parameters);
-
-			cipher.Init(true, keyParameters);
-
-			byte[] keyBytes = keyInfo.GetEncoded();
-			byte[] encoding = cipher.DoFinal(keyBytes);
+            IBufferedCipher cipher = PbeUtilities.CreateEngine(algorithm) as IBufferedCipher;
+            if (cipher == null)
+                throw new Exception("Unknown encryption algorithm: " + algorithm);
 
-			DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm);
-			AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, parameters);
+            Asn1Encodable pbeParameters = PbeUtilities.GenerateAlgorithmParameters(
+                algorithm, salt, iterationCount);
+            ICipherParameters cipherParameters = PbeUtilities.GenerateCipherParameters(
+                algorithm, passPhrase, pbeParameters);
+            cipher.Init(true, cipherParameters);
+            byte[] encoding = cipher.DoFinal(keyInfo.GetEncoded());
 
-			return new EncryptedPrivateKeyInfo(algID, encoding);
+            DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm);
+            AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, pbeParameters);
+            return new EncryptedPrivateKeyInfo(algID, encoding);
         }
     }
 }
diff --git a/crypto/src/pkcs/PKCS12StoreBuilder.cs b/crypto/src/pkcs/PKCS12StoreBuilder.cs
new file mode 100644
index 000000000..c8fa0f603
--- /dev/null
+++ b/crypto/src/pkcs/PKCS12StoreBuilder.cs
@@ -0,0 +1,41 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Pkcs
+{
+	public class Pkcs12StoreBuilder
+	{
+		private DerObjectIdentifier	keyAlgorithm = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
+		private DerObjectIdentifier	certAlgorithm = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+		private bool useDerEncoding = false;
+
+		public Pkcs12StoreBuilder()
+		{
+		}
+
+		public Pkcs12Store Build()
+		{
+			return new Pkcs12Store(keyAlgorithm, certAlgorithm, useDerEncoding);
+		}
+
+		public Pkcs12StoreBuilder SetCertAlgorithm(DerObjectIdentifier certAlgorithm)
+		{
+			this.certAlgorithm = certAlgorithm;
+			return this;
+		}
+
+		public Pkcs12StoreBuilder SetKeyAlgorithm(DerObjectIdentifier keyAlgorithm)
+		{
+			this.keyAlgorithm = keyAlgorithm;
+			return this;
+		}
+
+		public Pkcs12StoreBuilder SetUseDerEncoding(bool useDerEncoding)
+		{
+			this.useDerEncoding = useDerEncoding;
+			return this;
+		}
+	}
+}
diff --git a/crypto/src/pkcs/Pkcs10CertificationRequest.cs b/crypto/src/pkcs/Pkcs10CertificationRequest.cs
index 2c343c0b4..9f24eb18a 100644
--- a/crypto/src/pkcs/Pkcs10CertificationRequest.cs
+++ b/crypto/src/pkcs/Pkcs10CertificationRequest.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 using System.IO;
 
 using Org.BouncyCastle.Asn1;
@@ -228,7 +227,7 @@ namespace Org.BouncyCastle.Pkcs
 				throw new ArgumentException("key for signing must be private", "signingKey");
 
 //			DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
-			string algorithmName = signatureAlgorithm.ToUpperInvariant();
+			string algorithmName = Platform.ToUpperInvariant(signatureAlgorithm);
 			DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
 
 			if (sigOid == null)
diff --git a/crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs b/crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs
index f649b47a2..ecbb4ab62 100644
--- a/crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs
+++ b/crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs
@@ -104,7 +104,7 @@ namespace Org.BouncyCastle.Pkcs
 			if (publicKey.IsPrivate)
 				throw new ArgumentException("expected public key", "publicKey");
 //			DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
-			string algorithmName = signatureAlgorithm.ToUpperInvariant();
+			string algorithmName = Platform.ToUpperInvariant(signatureAlgorithm);
 			DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
 			if (sigOid == null)
 			{
diff --git a/crypto/src/pkcs/Pkcs12Entry.cs b/crypto/src/pkcs/Pkcs12Entry.cs
new file mode 100644
index 000000000..5dcc94e88
--- /dev/null
+++ b/crypto/src/pkcs/Pkcs12Entry.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    public abstract class Pkcs12Entry
+    {
+        private readonly IDictionary attributes;
+
+		protected internal Pkcs12Entry(
+            IDictionary attributes)
+        {
+            this.attributes = attributes;
+
+			foreach (DictionaryEntry entry in attributes)
+			{
+				if (!(entry.Key is string))
+					throw new ArgumentException("Attribute keys must be of type: " + typeof(string).FullName, "attributes");
+				if (!(entry.Value is Asn1Encodable))
+					throw new ArgumentException("Attribute values must be of type: " + typeof(Asn1Encodable).FullName, "attributes");
+			}
+        }
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public Asn1Encodable GetBagAttribute(
+            DerObjectIdentifier oid)
+        {
+            return (Asn1Encodable)this.attributes[oid.Id];
+        }
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public Asn1Encodable GetBagAttribute(
+            string oid)
+        {
+            return (Asn1Encodable)this.attributes[oid];
+        }
+
+		[Obsolete("Use 'BagAttributeKeys' property")]
+        public IEnumerator GetBagAttributeKeys()
+        {
+            return this.attributes.Keys.GetEnumerator();
+        }
+
+		public Asn1Encodable this[
+			DerObjectIdentifier oid]
+		{
+			get { return (Asn1Encodable) this.attributes[oid.Id]; }
+		}
+
+		public Asn1Encodable this[
+			string oid]
+		{
+			get { return (Asn1Encodable) this.attributes[oid]; }
+		}
+
+		public IEnumerable BagAttributeKeys
+		{
+			get { return new EnumerableProxy(this.attributes.Keys); }
+		}
+    }
+}
diff --git a/crypto/src/pkcs/Pkcs12Store.cs b/crypto/src/pkcs/Pkcs12Store.cs
index 2e7f2295e..40364eec7 100644
--- a/crypto/src/pkcs/Pkcs12Store.cs
+++ b/crypto/src/pkcs/Pkcs12Store.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 using System.IO;
 using System.Text;
 
@@ -18,704 +17,704 @@ using Org.BouncyCastle.X509;
 
 namespace Org.BouncyCastle.Pkcs
 {
-	public class Pkcs12Store
-	{
-		private readonly IgnoresCaseHashtable	keys = new IgnoresCaseHashtable();
-		private readonly IDictionary            localIds = Platform.CreateHashtable();
-		private readonly IgnoresCaseHashtable	certs = new IgnoresCaseHashtable();
+    public class Pkcs12Store
+    {
+        private readonly IgnoresCaseHashtable	keys = new IgnoresCaseHashtable();
+        private readonly IDictionary            localIds = Platform.CreateHashtable();
+        private readonly IgnoresCaseHashtable	certs = new IgnoresCaseHashtable();
         private readonly IDictionary            chainCerts = Platform.CreateHashtable();
         private readonly IDictionary            keyCerts = Platform.CreateHashtable();
-		private readonly DerObjectIdentifier	keyAlgorithm;
-		private readonly DerObjectIdentifier	certAlgorithm;
-		private readonly bool					useDerEncoding;
-
-		private const int MinIterations = 1024;
-		private const int SaltSize = 20;
-
-		private static SubjectKeyIdentifier CreateSubjectKeyID(
-			AsymmetricKeyParameter pubKey)
-		{
-			return new SubjectKeyIdentifier(
-				SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey));
-		}
-
-		internal class CertId
-		{
-			private readonly byte[] id;
-
-			internal CertId(
-				AsymmetricKeyParameter pubKey)
-			{
-				this.id = CreateSubjectKeyID(pubKey).GetKeyIdentifier();
-			}
-
-			internal CertId(
-				byte[] id)
-			{
-				this.id = id;
-			}
-
-			internal byte[] Id
-			{
-				get { return id; }
-			}
-
-			public override int GetHashCode()
-			{
-				return Arrays.GetHashCode(id);
-			}
-
-			public override bool Equals(
-				object obj)
-			{
-				if (obj == this)
-					return true;
-
-				CertId other = obj as CertId;
-
-				if (other == null)
-					return false;
-
-				return Arrays.AreEqual(id, other.id);
-			}
-		}
-
-		internal Pkcs12Store(
-			DerObjectIdentifier	keyAlgorithm,
-			DerObjectIdentifier	certAlgorithm,
-			bool				useDerEncoding)
-		{
-			this.keyAlgorithm = keyAlgorithm;
-			this.certAlgorithm = certAlgorithm;
-			this.useDerEncoding = useDerEncoding;
-		}
-
-		// TODO Consider making obsolete
+        private readonly DerObjectIdentifier	keyAlgorithm;
+        private readonly DerObjectIdentifier	certAlgorithm;
+        private readonly bool					useDerEncoding;
+
+        private const int MinIterations = 1024;
+        private const int SaltSize = 20;
+
+        private static SubjectKeyIdentifier CreateSubjectKeyID(
+            AsymmetricKeyParameter pubKey)
+        {
+            return new SubjectKeyIdentifier(
+                SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey));
+        }
+
+        internal class CertId
+        {
+            private readonly byte[] id;
+
+            internal CertId(
+                AsymmetricKeyParameter pubKey)
+            {
+                this.id = CreateSubjectKeyID(pubKey).GetKeyIdentifier();
+            }
+
+            internal CertId(
+                byte[] id)
+            {
+                this.id = id;
+            }
+
+            internal byte[] Id
+            {
+                get { return id; }
+            }
+
+            public override int GetHashCode()
+            {
+                return Arrays.GetHashCode(id);
+            }
+
+            public override bool Equals(
+                object obj)
+            {
+                if (obj == this)
+                    return true;
+
+                CertId other = obj as CertId;
+
+                if (other == null)
+                    return false;
+
+                return Arrays.AreEqual(id, other.id);
+            }
+        }
+
+        internal Pkcs12Store(
+            DerObjectIdentifier	keyAlgorithm,
+            DerObjectIdentifier	certAlgorithm,
+            bool				useDerEncoding)
+        {
+            this.keyAlgorithm = keyAlgorithm;
+            this.certAlgorithm = certAlgorithm;
+            this.useDerEncoding = useDerEncoding;
+        }
+
+        // TODO Consider making obsolete
 //		[Obsolete("Use 'Pkcs12StoreBuilder' instead")]
-		public Pkcs12Store()
-			: this(PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
-				PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc, false)
-		{
-		}
+        public Pkcs12Store()
+            : this(PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
+                PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc, false)
+        {
+        }
 
-		// TODO Consider making obsolete
+        // TODO Consider making obsolete
 //		[Obsolete("Use 'Pkcs12StoreBuilder' and 'Load' method instead")]
-		public Pkcs12Store(
-			Stream	input,
-			char[]	password)
-			: this()
-		{
-			Load(input, password);
-		}
-
-		public void Load(
-			Stream	input,
-			char[]	password)
-		{
-			if (input == null)
-				throw new ArgumentNullException("input");
-			if (password == null)
-				throw new ArgumentNullException("password");
-
-			Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromStream(input);
-			Pfx bag = new Pfx(obj);
-			ContentInfo info = bag.AuthSafe;
-			bool unmarkedKey = false;
-			bool wrongPkcs12Zero = false;
-
-			if (bag.MacData != null) // check the mac code
-			{
-				MacData mData = bag.MacData;
-				DigestInfo dInfo = mData.Mac;
-				AlgorithmIdentifier algId = dInfo.AlgorithmID;
-				byte[] salt = mData.GetSalt();
-				int itCount = mData.IterationCount.IntValue;
-
-				byte[] data = ((Asn1OctetString) info.Content).GetOctets();
-
-				byte[] mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, false, data);
-				byte[] dig = dInfo.GetDigest();
-
-				if (!Arrays.ConstantTimeAreEqual(mac, dig))
-				{
-					if (password.Length > 0)
-						throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
-
-					// Try with incorrect zero length password
-					mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, true, data);
-
-					if (!Arrays.ConstantTimeAreEqual(mac, dig))
-						throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
-
-					wrongPkcs12Zero = true;
-				}
-			}
-
-			keys.Clear();
-			localIds.Clear();
+        public Pkcs12Store(
+            Stream	input,
+            char[]	password)
+            : this()
+        {
+            Load(input, password);
+        }
+
+        public void Load(
+            Stream	input,
+            char[]	password)
+        {
+            if (input == null)
+                throw new ArgumentNullException("input");
+            if (password == null)
+                throw new ArgumentNullException("password");
+
+            Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromStream(input);
+            Pfx bag = new Pfx(obj);
+            ContentInfo info = bag.AuthSafe;
+            bool unmarkedKey = false;
+            bool wrongPkcs12Zero = false;
+
+            if (bag.MacData != null) // check the mac code
+            {
+                MacData mData = bag.MacData;
+                DigestInfo dInfo = mData.Mac;
+                AlgorithmIdentifier algId = dInfo.AlgorithmID;
+                byte[] salt = mData.GetSalt();
+                int itCount = mData.IterationCount.IntValue;
+
+                byte[] data = ((Asn1OctetString) info.Content).GetOctets();
+
+                byte[] mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, false, data);
+                byte[] dig = dInfo.GetDigest();
+
+                if (!Arrays.ConstantTimeAreEqual(mac, dig))
+                {
+                    if (password.Length > 0)
+                        throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
+
+                    // Try with incorrect zero length password
+                    mac = CalculatePbeMac(algId.ObjectID, salt, itCount, password, true, data);
+
+                    if (!Arrays.ConstantTimeAreEqual(mac, dig))
+                        throw new IOException("PKCS12 key store MAC invalid - wrong password or corrupted file.");
+
+                    wrongPkcs12Zero = true;
+                }
+            }
+
+            keys.Clear();
+            localIds.Clear();
 
             IList chain = Platform.CreateArrayList();
 
-			if (info.ContentType.Equals(PkcsObjectIdentifiers.Data))
-			{
-				byte[] octs = ((Asn1OctetString)info.Content).GetOctets();
-				AuthenticatedSafe authSafe = new AuthenticatedSafe(
-					(Asn1Sequence) Asn1OctetString.FromByteArray(octs));
-				ContentInfo[] cis = authSafe.GetContentInfo();
-
-				foreach (ContentInfo ci in cis)
-				{
-					DerObjectIdentifier oid = ci.ContentType;
-
-					if (oid.Equals(PkcsObjectIdentifiers.Data))
-					{
-						byte[] octets = ((Asn1OctetString)ci.Content).GetOctets();
-						Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
-
-						foreach (Asn1Sequence subSeq in seq)
-						{
-							SafeBag b = new SafeBag(subSeq);
-
-							if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
-							{
-								EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
-								PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
-									password, wrongPkcs12Zero, eIn);
-								AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
-
-								//
-								// set the attributes on the key
-								//
-								IDictionary attributes = Platform.CreateHashtable();
-								AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
-								string alias = null;
-								Asn1OctetString localId = null;
-
-								if (b.BagAttributes != null)
-								{
-									foreach (Asn1Sequence sq in b.BagAttributes)
-									{
-										DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
-										Asn1Set attrSet = (Asn1Set) sq[1];
-										Asn1Encodable attr = null;
-
-										if (attrSet.Count > 0)
-										{
-											// TODO We should be adding all attributes in the set
-											attr = attrSet[0];
-
-											// TODO We might want to "merge" attribute sets with
-											// the same OID - currently, differing values give an error
-											if (attributes.Contains(aOid.Id))
-											{
-												// OK, but the value has to be the same
-												if (!attributes[aOid.Id].Equals(attr))
-												{
-													throw new IOException("attempt to add existing attribute with different value");
-												}
-											}
-											else
-											{
-											    attributes.Add(aOid.Id, attr);
-											}
-
-											if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
-											{
-												alias = ((DerBmpString)attr).GetString();
-												// TODO Do these in a separate loop, just collect aliases here
-												keys[alias] = pkcs12Key;
-											}
-											else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
-											{
-												localId = (Asn1OctetString)attr;
-											}
-										}
-									}
-								}
-
-								if (localId != null)
-								{
-									string name = Hex.ToHexString(localId.GetOctets());
-
-									if (alias == null)
-									{
-										keys[name] = pkcs12Key;
-									}
-									else
-									{
-										// TODO There may have been more than one alias
-										localIds[alias] = name;
-									}
-								}
-								else
-								{
-									unmarkedKey = true;
-									keys["unmarked"] = pkcs12Key;
-								}
-							}
-							else if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
-							{
-								chain.Add(b);
-							}
-							else
-							{
-                                System.Diagnostics.Debug.WriteLine("extra " + b.BagID);
-                                System.Diagnostics.Debug.WriteLine("extra " + Asn1Dump.DumpAsString(b));
-							}
-						}
-					}
-					else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
-					{
-						EncryptedData d = EncryptedData.GetInstance(ci.Content);
-						byte[] octets = CryptPbeData(false, d.EncryptionAlgorithm,
-							password, wrongPkcs12Zero, d.Content.GetOctets());
-						Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
-
-						foreach (Asn1Sequence subSeq in seq)
-						{
-							SafeBag b = new SafeBag(subSeq);
-
-							if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
-							{
-								chain.Add(b);
-							}
-							else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
-							{
-								EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
-								PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
-									password, wrongPkcs12Zero, eIn);
-								AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
-
-								//
-								// set the attributes on the key
-								//
-								IDictionary attributes = Platform.CreateHashtable();
-								AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
-								string alias = null;
-								Asn1OctetString localId = null;
-
-								foreach (Asn1Sequence sq in b.BagAttributes)
-								{
-									DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
-									Asn1Set attrSet = (Asn1Set) sq[1];
-									Asn1Encodable attr = null;
-
-									if (attrSet.Count > 0)
-									{
-										// TODO We should be adding all attributes in the set
-										attr = attrSet[0];
-
-										// TODO We might want to "merge" attribute sets with
-										// the same OID - currently, differing values give an error
-										if (attributes.Contains(aOid.Id))
-										{
-											// OK, but the value has to be the same
-											if (!attributes[aOid.Id].Equals(attr))
-											{
-												throw new IOException("attempt to add existing attribute with different value");
-											}
-										}
-										else
-										{
-										    attributes.Add(aOid.Id, attr);
-										}
-
-										if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
-										{
-											alias = ((DerBmpString)attr).GetString();
-											// TODO Do these in a separate loop, just collect aliases here
-											keys[alias] = pkcs12Key;
-										}
-										else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
-										{
-											localId = (Asn1OctetString)attr;
-										}
-									}
-								}
-
-								// TODO Should we be checking localIds != null here
-								// as for PkcsObjectIdentifiers.Data version above?
-
-								string name = Hex.ToHexString(localId.GetOctets());
-
-								if (alias == null)
-								{
-									keys[name] = pkcs12Key;
-								}
-								else
-								{
-									// TODO There may have been more than one alias
-									localIds[alias] = name;
-								}
-							}
-							else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag))
-							{
-								PrivateKeyInfo privKeyInfo = PrivateKeyInfo.GetInstance(b.BagValue);
-								AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
-
-								//
-								// set the attributes on the key
-								//
-								string alias = null;
-								Asn1OctetString localId = null;
-								IDictionary attributes = Platform.CreateHashtable();
-								AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
-
-								foreach (Asn1Sequence sq in b.BagAttributes)
-								{
-									DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
-									Asn1Set attrSet = (Asn1Set) sq[1];
-									Asn1Encodable attr = null;
-
-									if (attrSet.Count > 0)
-									{
-										// TODO We should be adding all attributes in the set
-										attr = attrSet[0];
-
-										// TODO We might want to "merge" attribute sets with
-										// the same OID - currently, differing values give an error
-										if (attributes.Contains(aOid.Id))
-										{
-											// OK, but the value has to be the same
-											if (!attributes[aOid.Id].Equals(attr))
-											{
-												throw new IOException("attempt to add existing attribute with different value");
-											}
-										}
-										else
-										{
-										    attributes.Add(aOid.Id, attr);
-										}
-
-										if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
-										{
-											alias = ((DerBmpString)attr).GetString();
-											// TODO Do these in a separate loop, just collect aliases here
-											keys[alias] = pkcs12Key;
-										}
-										else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
-										{
-											localId = (Asn1OctetString)attr;
-										}
-									}
-								}
-
-								// TODO Should we be checking localIds != null here
-								// as for PkcsObjectIdentifiers.Data version above?
-
-								string name = Hex.ToHexString(localId.GetOctets());
-
-								if (alias == null)
-								{
-									keys[name] = pkcs12Key;
-								}
-								else
-								{
-									// TODO There may have been more than one alias
-									localIds[alias] = name;
-								}
-							}
-							else
-							{
-                                System.Diagnostics.Debug.WriteLine("extra " + b.BagID);
-                                System.Diagnostics.Debug.WriteLine("extra " + Asn1Dump.DumpAsString(b));
-							}
-						}
-					}
-					else
-					{
-                        System.Diagnostics.Debug.WriteLine("extra " + oid);
-                        System.Diagnostics.Debug.WriteLine("extra " + Asn1Dump.DumpAsString(ci.Content));
-					}
-				}
-			}
-
-			certs.Clear();
-			chainCerts.Clear();
-			keyCerts.Clear();
-
-			foreach (SafeBag b in chain)
-			{
-				CertBag cb = new CertBag((Asn1Sequence)b.BagValue);
-				byte[] octets = ((Asn1OctetString) cb.CertValue).GetOctets();
-				X509Certificate cert = new X509CertificateParser().ReadCertificate(octets);
-
-				//
-				// set the attributes
-				//
+            if (info.ContentType.Equals(PkcsObjectIdentifiers.Data))
+            {
+                byte[] octs = ((Asn1OctetString)info.Content).GetOctets();
+                AuthenticatedSafe authSafe = new AuthenticatedSafe(
+                    (Asn1Sequence) Asn1OctetString.FromByteArray(octs));
+                ContentInfo[] cis = authSafe.GetContentInfo();
+
+                foreach (ContentInfo ci in cis)
+                {
+                    DerObjectIdentifier oid = ci.ContentType;
+
+                    if (oid.Equals(PkcsObjectIdentifiers.Data))
+                    {
+                        byte[] octets = ((Asn1OctetString)ci.Content).GetOctets();
+                        Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
+
+                        foreach (Asn1Sequence subSeq in seq)
+                        {
+                            SafeBag b = new SafeBag(subSeq);
+
+                            if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
+                            {
+                                EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
+                                PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
+                                    password, wrongPkcs12Zero, eIn);
+                                AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
+
+                                //
+                                // set the attributes on the key
+                                //
+                                IDictionary attributes = Platform.CreateHashtable();
+                                AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
+                                string alias = null;
+                                Asn1OctetString localId = null;
+
+                                if (b.BagAttributes != null)
+                                {
+                                    foreach (Asn1Sequence sq in b.BagAttributes)
+                                    {
+                                        DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
+                                        Asn1Set attrSet = (Asn1Set) sq[1];
+                                        Asn1Encodable attr = null;
+
+                                        if (attrSet.Count > 0)
+                                        {
+                                            // TODO We should be adding all attributes in the set
+                                            attr = attrSet[0];
+
+                                            // TODO We might want to "merge" attribute sets with
+                                            // the same OID - currently, differing values give an error
+                                            if (attributes.Contains(aOid.Id))
+                                            {
+                                                // OK, but the value has to be the same
+                                                if (!attributes[aOid.Id].Equals(attr))
+                                                {
+                                                    throw new IOException("attempt to add existing attribute with different value");
+                                                }
+                                            }
+                                            else
+                                            {
+                                                attributes.Add(aOid.Id, attr);
+                                            }
+
+                                            if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+                                            {
+                                                alias = ((DerBmpString)attr).GetString();
+                                                // TODO Do these in a separate loop, just collect aliases here
+                                                keys[alias] = pkcs12Key;
+                                            }
+                                            else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+                                            {
+                                                localId = (Asn1OctetString)attr;
+                                            }
+                                        }
+                                    }
+                                }
+
+                                if (localId != null)
+                                {
+                                    string name = Hex.ToHexString(localId.GetOctets());
+
+                                    if (alias == null)
+                                    {
+                                        keys[name] = pkcs12Key;
+                                    }
+                                    else
+                                    {
+                                        // TODO There may have been more than one alias
+                                        localIds[alias] = name;
+                                    }
+                                }
+                                else
+                                {
+                                    unmarkedKey = true;
+                                    keys["unmarked"] = pkcs12Key;
+                                }
+                            }
+                            else if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
+                            {
+                                chain.Add(b);
+                            }
+                            else
+                            {
+                                Console.WriteLine("extra " + b.BagID);
+                                Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
+                            }
+                        }
+                    }
+                    else if (oid.Equals(PkcsObjectIdentifiers.EncryptedData))
+                    {
+                        EncryptedData d = EncryptedData.GetInstance(ci.Content);
+                        byte[] octets = CryptPbeData(false, d.EncryptionAlgorithm,
+                            password, wrongPkcs12Zero, d.Content.GetOctets());
+                        Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
+
+                        foreach (Asn1Sequence subSeq in seq)
+                        {
+                            SafeBag b = new SafeBag(subSeq);
+
+                            if (b.BagID.Equals(PkcsObjectIdentifiers.CertBag))
+                            {
+                                chain.Add(b);
+                            }
+                            else if (b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
+                            {
+                                EncryptedPrivateKeyInfo eIn = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
+                                PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
+                                    password, wrongPkcs12Zero, eIn);
+                                AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privInfo);
+
+                                //
+                                // set the attributes on the key
+                                //
+                                IDictionary attributes = Platform.CreateHashtable();
+                                AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
+                                string alias = null;
+                                Asn1OctetString localId = null;
+
+                                foreach (Asn1Sequence sq in b.BagAttributes)
+                                {
+                                    DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
+                                    Asn1Set attrSet = (Asn1Set) sq[1];
+                                    Asn1Encodable attr = null;
+
+                                    if (attrSet.Count > 0)
+                                    {
+                                        // TODO We should be adding all attributes in the set
+                                        attr = attrSet[0];
+
+                                        // TODO We might want to "merge" attribute sets with
+                                        // the same OID - currently, differing values give an error
+                                        if (attributes.Contains(aOid.Id))
+                                        {
+                                            // OK, but the value has to be the same
+                                            if (!attributes[aOid.Id].Equals(attr))
+                                            {
+                                                throw new IOException("attempt to add existing attribute with different value");
+                                            }
+                                        }
+                                        else
+                                        {
+                                            attributes.Add(aOid.Id, attr);
+                                        }
+
+                                        if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+                                        {
+                                            alias = ((DerBmpString)attr).GetString();
+                                            // TODO Do these in a separate loop, just collect aliases here
+                                            keys[alias] = pkcs12Key;
+                                        }
+                                        else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+                                        {
+                                            localId = (Asn1OctetString)attr;
+                                        }
+                                    }
+                                }
+
+                                // TODO Should we be checking localIds != null here
+                                // as for PkcsObjectIdentifiers.Data version above?
+
+                                string name = Hex.ToHexString(localId.GetOctets());
+
+                                if (alias == null)
+                                {
+                                    keys[name] = pkcs12Key;
+                                }
+                                else
+                                {
+                                    // TODO There may have been more than one alias
+                                    localIds[alias] = name;
+                                }
+                            }
+                            else if (b.BagID.Equals(PkcsObjectIdentifiers.KeyBag))
+                            {
+                                PrivateKeyInfo privKeyInfo = PrivateKeyInfo.GetInstance(b.BagValue);
+                                AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyInfo);
+
+                                //
+                                // set the attributes on the key
+                                //
+                                string alias = null;
+                                Asn1OctetString localId = null;
+                                IDictionary attributes = Platform.CreateHashtable();
+                                AsymmetricKeyEntry pkcs12Key = new AsymmetricKeyEntry(privKey, attributes);
+
+                                foreach (Asn1Sequence sq in b.BagAttributes)
+                                {
+                                    DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
+                                    Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
+                                    Asn1Encodable attr = null;
+
+                                    if (attrSet.Count > 0)
+                                    {
+                                        // TODO We should be adding all attributes in the set
+                                        attr = attrSet[0];
+
+                                        // TODO We might want to "merge" attribute sets with
+                                        // the same OID - currently, differing values give an error
+                                        if (attributes.Contains(aOid.Id))
+                                        {
+                                            // OK, but the value has to be the same
+                                            if (!attributes[aOid.Id].Equals(attr))
+                                            {
+                                                throw new IOException("attempt to add existing attribute with different value");
+                                            }
+                                        }
+                                        else
+                                        {
+                                            attributes.Add(aOid.Id, attr);
+                                        }
+
+                                        if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+                                        {
+                                            alias = ((DerBmpString)attr).GetString();
+                                            // TODO Do these in a separate loop, just collect aliases here
+                                            keys[alias] = pkcs12Key;
+                                        }
+                                        else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+                                        {
+                                            localId = (Asn1OctetString)attr;
+                                        }
+                                    }
+                                }
+
+                                // TODO Should we be checking localIds != null here
+                                // as for PkcsObjectIdentifiers.Data version above?
+
+                                string name = Hex.ToHexString(localId.GetOctets());
+
+                                if (alias == null)
+                                {
+                                    keys[name] = pkcs12Key;
+                                }
+                                else
+                                {
+                                    // TODO There may have been more than one alias
+                                    localIds[alias] = name;
+                                }
+                            }
+                            else
+                            {
+                                Console.WriteLine("extra " + b.BagID);
+                                Console.WriteLine("extra " + Asn1Dump.DumpAsString(b));
+                            }
+                        }
+                    }
+                    else
+                    {
+                        Console.WriteLine("extra " + oid);
+                        Console.WriteLine("extra " + Asn1Dump.DumpAsString(ci.Content));
+                    }
+                }
+            }
+
+            certs.Clear();
+            chainCerts.Clear();
+            keyCerts.Clear();
+
+            foreach (SafeBag b in chain)
+            {
+                CertBag cb = new CertBag((Asn1Sequence)b.BagValue);
+                byte[] octets = ((Asn1OctetString) cb.CertValue).GetOctets();
+                X509Certificate cert = new X509CertificateParser().ReadCertificate(octets);
+
+                //
+                // set the attributes
+                //
                 IDictionary attributes = Platform.CreateHashtable();
-				Asn1OctetString localId = null;
-				string alias = null;
-
-				if (b.BagAttributes != null)
-				{
-					foreach (Asn1Sequence sq in b.BagAttributes)
-					{
-						DerObjectIdentifier aOid = (DerObjectIdentifier) sq[0];
-						Asn1Set attrSet = (Asn1Set) sq[1];
-
-						if (attrSet.Count > 0)
-						{
-							// TODO We should be adding all attributes in the set
-							Asn1Encodable attr = attrSet[0];
-
-							// TODO We might want to "merge" attribute sets with
-							// the same OID - currently, differing values give an error
-							if (attributes.Contains(aOid.Id))
-							{
-								// OK, but the value has to be the same
-								if (!attributes[aOid.Id].Equals(attr))
-								{
-									throw new IOException("attempt to add existing attribute with different value");
-								}
-							}
-							else
-							{
-							    attributes.Add(aOid.Id, attr);
-							}
-
-							if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
-							{
-								alias = ((DerBmpString)attr).GetString();
-							}
-							else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
-							{
-								localId = (Asn1OctetString)attr;
-							}
-						}
-					}
-				}
-
-				CertId certId = new CertId(cert.GetPublicKey());
-				X509CertificateEntry pkcs12Cert = new X509CertificateEntry(cert, attributes);
-
-				chainCerts[certId] = pkcs12Cert;
-
-				if (unmarkedKey)
-				{
-					if (keyCerts.Count == 0)
-					{
-						string name = Hex.ToHexString(certId.Id);
-
-						keyCerts[name] = pkcs12Cert;
-
-						object temp = keys["unmarked"];
-						keys.Remove("unmarked");
-						keys[name] = temp;
-					}
-				}
-				else
-				{
-					if (localId != null)
-					{
-						string name = Hex.ToHexString(localId.GetOctets());
-
-						keyCerts[name] = pkcs12Cert;
-					}
-
-					if (alias != null)
-					{
-						// TODO There may have been more than one alias
-						certs[alias] = pkcs12Cert;
-					}
-				}
-			}
-		}
-
-		public AsymmetricKeyEntry GetKey(
-			string alias)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-
-			return (AsymmetricKeyEntry)keys[alias];
-		}
-
-		public bool IsCertificateEntry(
-			string alias)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-
-			return (certs[alias] != null && keys[alias] == null);
-		}
-
-		public bool IsKeyEntry(
-			string alias)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-
-			return (keys[alias] != null);
-		}
-
-		private IDictionary GetAliasesTable()
-		{
+                Asn1OctetString localId = null;
+                string alias = null;
+
+                if (b.BagAttributes != null)
+                {
+                    foreach (Asn1Sequence sq in b.BagAttributes)
+                    {
+                        DerObjectIdentifier aOid = DerObjectIdentifier.GetInstance(sq[0]);
+                        Asn1Set attrSet = Asn1Set.GetInstance(sq[1]);
+
+                        if (attrSet.Count > 0)
+                        {
+                            // TODO We should be adding all attributes in the set
+                            Asn1Encodable attr = attrSet[0];
+
+                            // TODO We might want to "merge" attribute sets with
+                            // the same OID - currently, differing values give an error
+                            if (attributes.Contains(aOid.Id))
+                            {
+                                // OK, but the value has to be the same
+                                if (!attributes[aOid.Id].Equals(attr))
+                                {
+                                    throw new IOException("attempt to add existing attribute with different value");
+                                }
+                            }
+                            else
+                            {
+                                attributes.Add(aOid.Id, attr);
+                            }
+
+                            if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName))
+                            {
+                                alias = ((DerBmpString)attr).GetString();
+                            }
+                            else if (aOid.Equals(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID))
+                            {
+                                localId = (Asn1OctetString)attr;
+                            }
+                        }
+                    }
+                }
+
+                CertId certId = new CertId(cert.GetPublicKey());
+                X509CertificateEntry pkcs12Cert = new X509CertificateEntry(cert, attributes);
+
+                chainCerts[certId] = pkcs12Cert;
+
+                if (unmarkedKey)
+                {
+                    if (keyCerts.Count == 0)
+                    {
+                        string name = Hex.ToHexString(certId.Id);
+
+                        keyCerts[name] = pkcs12Cert;
+
+                        object temp = keys["unmarked"];
+                        keys.Remove("unmarked");
+                        keys[name] = temp;
+                    }
+                }
+                else
+                {
+                    if (localId != null)
+                    {
+                        string name = Hex.ToHexString(localId.GetOctets());
+
+                        keyCerts[name] = pkcs12Cert;
+                    }
+
+                    if (alias != null)
+                    {
+                        // TODO There may have been more than one alias
+                        certs[alias] = pkcs12Cert;
+                    }
+                }
+            }
+        }
+
+        public AsymmetricKeyEntry GetKey(
+            string alias)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+
+            return (AsymmetricKeyEntry)keys[alias];
+        }
+
+        public bool IsCertificateEntry(
+            string alias)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+
+            return (certs[alias] != null && keys[alias] == null);
+        }
+
+        public bool IsKeyEntry(
+            string alias)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+
+            return (keys[alias] != null);
+        }
+
+        private IDictionary GetAliasesTable()
+        {
             IDictionary tab = Platform.CreateHashtable();
 
-			foreach (string key in certs.Keys)
-			{
-				tab[key] = "cert";
-			}
-
-			foreach (string a in keys.Keys)
-			{
-				if (tab[a] == null)
-				{
-					tab[a] = "key";
-				}
-			}
-
-			return tab;
-		}
-
-		public IEnumerable Aliases
-		{
-			get { return new EnumerableProxy(GetAliasesTable().Keys); }
-		}
-
-		public bool ContainsAlias(
-			string alias)
-		{
-			return certs[alias] != null || keys[alias] != null;
-		}
-
-		/**
-		 * simply return the cert entry for the private key
-		 */
-		public X509CertificateEntry GetCertificate(
-			string alias)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-
-			X509CertificateEntry c = (X509CertificateEntry) certs[alias];
-
-			//
-			// look up the key table - and try the local key id
-			//
-			if (c == null)
-			{
-				string id = (string)localIds[alias];
-				if (id != null)
-				{
-					c = (X509CertificateEntry)keyCerts[id];
-				}
-				else
-				{
-					c = (X509CertificateEntry)keyCerts[alias];
-				}
-			}
-
-			return c;
-		}
-
-		public string GetCertificateAlias(
-			X509Certificate cert)
-		{
-			if (cert == null)
-				throw new ArgumentNullException("cert");
-
-			foreach (DictionaryEntry entry in certs)
-			{
-				X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
-				if (entryValue.Certificate.Equals(cert))
-				{
-					return (string) entry.Key;
-				}
-			}
-
-			foreach (DictionaryEntry entry in keyCerts)
-			{
-				X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
-				if (entryValue.Certificate.Equals(cert))
-				{
-					return (string) entry.Key;
-				}
-			}
-
-			return null;
-		}
-
-		public X509CertificateEntry[] GetCertificateChain(
-			string alias)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-
-			if (!IsKeyEntry(alias))
-			{
-				return null;
-			}
-
-			X509CertificateEntry c = GetCertificate(alias);
-
-			if (c != null)
-			{
-				IList cs = Platform.CreateArrayList();
-
-				while (c != null)
-				{
-					X509Certificate x509c = c.Certificate;
-					X509CertificateEntry nextC = null;
-
-					Asn1OctetString ext = x509c.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
-					if (ext != null)
-					{
-						AuthorityKeyIdentifier id = AuthorityKeyIdentifier.GetInstance(
-							Asn1Object.FromByteArray(ext.GetOctets()));
-
-						if (id.GetKeyIdentifier() != null)
-						{
-							nextC = (X509CertificateEntry) chainCerts[new CertId(id.GetKeyIdentifier())];
-						}
-					}
-
-					if (nextC == null)
-					{
-						//
-						// no authority key id, try the Issuer DN
-						//
-						X509Name i = x509c.IssuerDN;
-						X509Name s = x509c.SubjectDN;
-
-						if (!i.Equivalent(s))
-						{
-							foreach (CertId certId in chainCerts.Keys)
-							{
-								X509CertificateEntry x509CertEntry = (X509CertificateEntry) chainCerts[certId];
-
-								X509Certificate crt = x509CertEntry.Certificate;
-
-								X509Name sub = crt.SubjectDN;
-								if (sub.Equivalent(i))
-								{
-									try
-									{
-										x509c.Verify(crt.GetPublicKey());
-
-										nextC = x509CertEntry;
-										break;
-									}
-									catch (InvalidKeyException)
-									{
-										// TODO What if it doesn't verify?
-									}
-								}
-							}
-						}
-					}
-
-					cs.Add(c);
-					if (nextC != c) // self signed - end of the chain
-					{
-						c = nextC;
-					}
-					else
-					{
-						c = null;
-					}
-				}
+            foreach (string key in certs.Keys)
+            {
+                tab[key] = "cert";
+            }
+
+            foreach (string a in keys.Keys)
+            {
+                if (tab[a] == null)
+                {
+                    tab[a] = "key";
+                }
+            }
+
+            return tab;
+        }
+
+        public IEnumerable Aliases
+        {
+            get { return new EnumerableProxy(GetAliasesTable().Keys); }
+        }
+
+        public bool ContainsAlias(
+            string alias)
+        {
+            return certs[alias] != null || keys[alias] != null;
+        }
+
+        /**
+         * simply return the cert entry for the private key
+         */
+        public X509CertificateEntry GetCertificate(
+            string alias)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+
+            X509CertificateEntry c = (X509CertificateEntry) certs[alias];
+
+            //
+            // look up the key table - and try the local key id
+            //
+            if (c == null)
+            {
+                string id = (string)localIds[alias];
+                if (id != null)
+                {
+                    c = (X509CertificateEntry)keyCerts[id];
+                }
+                else
+                {
+                    c = (X509CertificateEntry)keyCerts[alias];
+                }
+            }
+
+            return c;
+        }
+
+        public string GetCertificateAlias(
+            X509Certificate cert)
+        {
+            if (cert == null)
+                throw new ArgumentNullException("cert");
+
+            foreach (DictionaryEntry entry in certs)
+            {
+                X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
+                if (entryValue.Certificate.Equals(cert))
+                {
+                    return (string) entry.Key;
+                }
+            }
+
+            foreach (DictionaryEntry entry in keyCerts)
+            {
+                X509CertificateEntry entryValue = (X509CertificateEntry) entry.Value;
+                if (entryValue.Certificate.Equals(cert))
+                {
+                    return (string) entry.Key;
+                }
+            }
+
+            return null;
+        }
+
+        public X509CertificateEntry[] GetCertificateChain(
+            string alias)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+
+            if (!IsKeyEntry(alias))
+            {
+                return null;
+            }
+
+            X509CertificateEntry c = GetCertificate(alias);
+
+            if (c != null)
+            {
+                IList cs = Platform.CreateArrayList();
+
+                while (c != null)
+                {
+                    X509Certificate x509c = c.Certificate;
+                    X509CertificateEntry nextC = null;
+
+                    Asn1OctetString ext = x509c.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
+                    if (ext != null)
+                    {
+                        AuthorityKeyIdentifier id = AuthorityKeyIdentifier.GetInstance(
+                            Asn1Object.FromByteArray(ext.GetOctets()));
+
+                        if (id.GetKeyIdentifier() != null)
+                        {
+                            nextC = (X509CertificateEntry) chainCerts[new CertId(id.GetKeyIdentifier())];
+                        }
+                    }
+
+                    if (nextC == null)
+                    {
+                        //
+                        // no authority key id, try the Issuer DN
+                        //
+                        X509Name i = x509c.IssuerDN;
+                        X509Name s = x509c.SubjectDN;
+
+                        if (!i.Equivalent(s))
+                        {
+                            foreach (CertId certId in chainCerts.Keys)
+                            {
+                                X509CertificateEntry x509CertEntry = (X509CertificateEntry) chainCerts[certId];
+
+                                X509Certificate crt = x509CertEntry.Certificate;
+
+                                X509Name sub = crt.SubjectDN;
+                                if (sub.Equivalent(i))
+                                {
+                                    try
+                                    {
+                                        x509c.Verify(crt.GetPublicKey());
+
+                                        nextC = x509CertEntry;
+                                        break;
+                                    }
+                                    catch (InvalidKeyException)
+                                    {
+                                        // TODO What if it doesn't verify?
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    cs.Add(c);
+                    if (nextC != c) // self signed - end of the chain
+                    {
+                        c = nextC;
+                    }
+                    else
+                    {
+                        c = null;
+                    }
+                }
 
                 X509CertificateEntry[] result = new X509CertificateEntry[cs.Count];
                 for (int i = 0; i < cs.Count; ++i)
@@ -723,509 +722,506 @@ namespace Org.BouncyCastle.Pkcs
                     result[i] = (X509CertificateEntry)cs[i];
                 }
                 return result;
-			}
-
-			return null;
-		}
-
-		public void SetCertificateEntry(
-			string					alias,
-			X509CertificateEntry	certEntry)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-			if (certEntry == null)
-				throw new ArgumentNullException("certEntry");
-			if (keys[alias] != null)
-				throw new ArgumentException("There is a key entry with the name " + alias + ".");
-
-			certs[alias] = certEntry;
-			chainCerts[new CertId(certEntry.Certificate.GetPublicKey())] = certEntry;
-		}
-
-		public void SetKeyEntry(
-			string					alias,
-			AsymmetricKeyEntry		keyEntry,
-			X509CertificateEntry[]	chain)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-			if (keyEntry == null)
-				throw new ArgumentNullException("keyEntry");
-			if (keyEntry.Key.IsPrivate && (chain == null))
-				throw new ArgumentException("No certificate chain for private key");
-
-			if (keys[alias] != null)
-			{
-				DeleteEntry(alias);
-			}
-
-			keys[alias] = keyEntry;
-			certs[alias] = chain[0];
-
-			for (int i = 0; i != chain.Length; i++)
-			{
-				chainCerts[new CertId(chain[i].Certificate.GetPublicKey())] = chain[i];
-			}
-		}
-
-		public void DeleteEntry(
-			string alias)
-		{
-			if (alias == null)
-				throw new ArgumentNullException("alias");
-
-			AsymmetricKeyEntry k = (AsymmetricKeyEntry)keys[alias];
-			if (k != null)
-			{
-				keys.Remove(alias);
-			}
-
-			X509CertificateEntry c = (X509CertificateEntry)certs[alias];
-
-			if (c != null)
-			{
-				certs.Remove(alias);
-				chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
-			}
-
-			if (k != null)
-			{
-				string id = (string)localIds[alias];
-				if (id != null)
-				{
-					localIds.Remove(alias);
-					c = (X509CertificateEntry)keyCerts[id];
-				}
-				if (c != null)
-				{
-					keyCerts.Remove(id);
-					chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
-				}
-			}
-
-			if (c == null && k == null)
-			{
-				throw new ArgumentException("no such entry as " + alias);
-			}
-		}
-
-		public bool IsEntryOfType(
-			string	alias,
-			Type	entryType)
-		{
-			if (entryType == typeof(X509CertificateEntry))
-				return IsCertificateEntry(alias);
-
-			if (entryType == typeof(AsymmetricKeyEntry))
-				return IsKeyEntry(alias) && GetCertificate(alias) != null;
-
-			return false;
-		}
-
-		[Obsolete("Use 'Count' property instead")]
-		public int Size()
-		{
-			return Count;
-		}
-
-		public int Count
-		{
-			// TODO Seems a little inefficient
-			get { return GetAliasesTable().Count; }
-		}
-
-		public void Save(
-			Stream			stream,
-			char[]			password,
-			SecureRandom	random)
-		{
-			if (stream == null)
-				throw new ArgumentNullException("stream");
-			if (password == null)
-				throw new ArgumentNullException("password");
-			if (random == null)
-				throw new ArgumentNullException("random");
-
-			//
-			// handle the key
-			//
-			Asn1EncodableVector keyS = new Asn1EncodableVector();
-			foreach (string name in keys.Keys)
-			{
-				byte[] kSalt = new byte[SaltSize];
-				random.NextBytes(kSalt);
-
-				AsymmetricKeyEntry privKey = (AsymmetricKeyEntry) keys[name];
-				EncryptedPrivateKeyInfo kInfo =
-					EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
-					keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
-
-				Asn1EncodableVector kName = new Asn1EncodableVector();
-
-				foreach (string oid in privKey.BagAttributeKeys)
-				{
-					Asn1Encodable entry = privKey[oid];
-
-					// NB: Ignore any existing FriendlyName
-					if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
-						continue;
-
-					kName.Add(
-						new DerSequence(
-							new DerObjectIdentifier(oid),
-							new DerSet(entry)));
-				}
-
-				//
-				// make sure we are using the local alias on store
-				//
-				// NB: We always set the FriendlyName based on 'name'
-				//if (privKey[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
-				{
-					kName.Add(
-						new DerSequence(
-							PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
-							new DerSet(new DerBmpString(name))));
-				}
-
-				//
-				// make sure we have a local key-id
-				//
-				if (privKey[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
-				{
-					X509CertificateEntry ct = GetCertificate(name);
-					AsymmetricKeyParameter pubKey = ct.Certificate.GetPublicKey();
-					SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
-
-					kName.Add(
-						new DerSequence(
-							PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
-							new DerSet(subjectKeyID)));
-				}
-
-				SafeBag kBag = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, kInfo.ToAsn1Object(), new DerSet(kName));
-				keyS.Add(kBag);
-			}
-
-			byte[] derEncodedBytes = new DerSequence(keyS).GetDerEncoded();
-
-			BerOctetString keyString = new BerOctetString(derEncodedBytes);
-
-			//
-			// certificate processing
-			//
-			byte[] cSalt = new byte[SaltSize];
-
-			random.NextBytes(cSalt);
-
-			Asn1EncodableVector	certSeq = new Asn1EncodableVector();
-			Pkcs12PbeParams		cParams = new Pkcs12PbeParams(cSalt, MinIterations);
-			AlgorithmIdentifier	cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.ToAsn1Object());
-			ISet				doneCerts = new HashSet();
-
-			foreach (string name in keys.Keys)
-			{
-				X509CertificateEntry certEntry = GetCertificate(name);
-				CertBag cBag = new CertBag(
-					PkcsObjectIdentifiers.X509Certificate,
-					new DerOctetString(certEntry.Certificate.GetEncoded()));
-
-				Asn1EncodableVector fName = new Asn1EncodableVector();
-
-				foreach (string oid in certEntry.BagAttributeKeys)
-				{
-					Asn1Encodable entry = certEntry[oid];
-
-					// NB: Ignore any existing FriendlyName
-					if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
-						continue;
-
-					fName.Add(
-						new DerSequence(
-							new DerObjectIdentifier(oid),
-							new DerSet(entry)));
-				}
-
-				//
-				// make sure we are using the local alias on store
-				//
-				// NB: We always set the FriendlyName based on 'name'
-				//if (certEntry[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
-				{
-					fName.Add(
-						new DerSequence(
-							PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
-							new DerSet(new DerBmpString(name))));
-				}
-
-				//
-				// make sure we have a local key-id
-				//
-				if (certEntry[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
-				{
-					AsymmetricKeyParameter pubKey = certEntry.Certificate.GetPublicKey();
-					SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
-
-					fName.Add(
-						new DerSequence(
-							PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
-							new DerSet(subjectKeyID)));
-				}
-
-				SafeBag sBag = new SafeBag(
-					PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
-
-				certSeq.Add(sBag);
-
-				doneCerts.Add(certEntry.Certificate);
-			}
-
-			foreach (string certId in certs.Keys)
-			{
-				X509CertificateEntry cert = (X509CertificateEntry)certs[certId];
-
-				if (keys[certId] != null)
-					continue;
-
-				CertBag cBag = new CertBag(
-					PkcsObjectIdentifiers.X509Certificate,
-					new DerOctetString(cert.Certificate.GetEncoded()));
-
-				Asn1EncodableVector fName = new Asn1EncodableVector();
-
-				foreach (string oid in cert.BagAttributeKeys)
-				{
-					// 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.Pkcs9AtLocalKeyID.Id))
-						continue;
-
-					Asn1Encodable entry = cert[oid];
-
-					// NB: Ignore any existing FriendlyName
-					if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
-						continue;
-
-					fName.Add(
-						new DerSequence(
-							new DerObjectIdentifier(oid),
-							new DerSet(entry)));
-				}
-
-				//
-				// make sure we are using the local alias on store
-				//
-				// NB: We always set the FriendlyName based on 'certId'
-				//if (cert[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
-				{
-					fName.Add(
-						new DerSequence(
-							PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
-							new DerSet(new DerBmpString(certId))));
-				}
-
-				SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag,
-					cBag.ToAsn1Object(), new DerSet(fName));
-
-				certSeq.Add(sBag);
-
-				doneCerts.Add(cert.Certificate);
-			}
-
-			foreach (CertId certId in chainCerts.Keys)
-			{
-				X509CertificateEntry cert = (X509CertificateEntry)chainCerts[certId];
-
-				if (doneCerts.Contains(cert.Certificate))
-					continue;
-
-				CertBag cBag = new CertBag(
-					PkcsObjectIdentifiers.X509Certificate,
-					new DerOctetString(cert.Certificate.GetEncoded()));
-
-				Asn1EncodableVector fName = new Asn1EncodableVector();
-
-				foreach (string oid in cert.BagAttributeKeys)
-				{
-					// 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.Pkcs9AtLocalKeyID.Id))
-						continue;
-
-					fName.Add(
-						new DerSequence(
-							new DerObjectIdentifier(oid),
-							new DerSet(cert[oid])));
-				}
-
-				SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
-
-				certSeq.Add(sBag);
-			}
-
-			derEncodedBytes = new DerSequence(certSeq).GetDerEncoded();
-
-			byte[] certBytes = CryptPbeData(true, cAlgId, password, false, derEncodedBytes);
-
-			EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
-
-			ContentInfo[] info = new ContentInfo[]
-			{
-				new ContentInfo(PkcsObjectIdentifiers.Data, keyString),
-				new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object())
-			};
-
-			byte[] data = new AuthenticatedSafe(info).GetEncoded(
-				useDerEncoding ? Asn1Encodable.Der : Asn1Encodable.Ber);
-
-			ContentInfo mainInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(data));
-
-			//
-			// create the mac
-			//
-			byte[] mSalt = new byte[20];
-			random.NextBytes(mSalt);
-
-			byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
-				mSalt, MinIterations, password, false, data);
-
-			AlgorithmIdentifier algId = new AlgorithmIdentifier(
-				OiwObjectIdentifiers.IdSha1, DerNull.Instance);
-			DigestInfo dInfo = new DigestInfo(algId, mac);
-
-			MacData mData = new MacData(dInfo, mSalt, MinIterations);
-
-			//
-			// output the Pfx
-			//
-			Pfx pfx = new Pfx(mainInfo, mData);
-
-			DerOutputStream derOut;
-			if (useDerEncoding)
-			{
-				derOut = new DerOutputStream(stream);
-			}
-			else
-			{
-				derOut = new BerOutputStream(stream);
-			}
-
-			derOut.WriteObject(pfx);
-		}
-
-		internal static byte[] CalculatePbeMac(
-			DerObjectIdentifier	oid,
-			byte[]				salt,
-			int					itCount,
-			char[]				password,
-			bool				wrongPkcs12Zero,
-			byte[]				data)
-		{
-			Asn1Encodable asn1Params = PbeUtilities.GenerateAlgorithmParameters(
-				oid, salt, itCount);
-			ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
-				oid, password, wrongPkcs12Zero, asn1Params);
-
-			IMac mac = (IMac) PbeUtilities.CreateEngine(oid);
-			mac.Init(cipherParams);
-			mac.BlockUpdate(data, 0, data.Length);
-			return MacUtilities.DoFinal(mac);
-		}
-
-		private static byte[] CryptPbeData(
-			bool				forEncryption,
-			AlgorithmIdentifier	algId,
-			char[]				password,
-			bool				wrongPkcs12Zero,
-			byte[]				data)
-		{
-			Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(algId.Parameters);
-			ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
-				algId.ObjectID, password, wrongPkcs12Zero, pbeParams);
-
-			IBufferedCipher cipher = PbeUtilities.CreateEngine(algId.ObjectID) as IBufferedCipher;
-
-			if (cipher == null)
-				throw new Exception("Unknown encryption algorithm: " + algId.ObjectID);
-
-			cipher.Init(forEncryption, cipherParams);
-
-			return cipher.DoFinal(data);
-		}
-
-		private class IgnoresCaseHashtable
-			: IEnumerable
-		{
-			private readonly IDictionary orig = Platform.CreateHashtable();
+            }
+
+            return null;
+        }
+
+        public void SetCertificateEntry(
+            string					alias,
+            X509CertificateEntry	certEntry)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+            if (certEntry == null)
+                throw new ArgumentNullException("certEntry");
+            if (keys[alias] != null)
+                throw new ArgumentException("There is a key entry with the name " + alias + ".");
+
+            certs[alias] = certEntry;
+            chainCerts[new CertId(certEntry.Certificate.GetPublicKey())] = certEntry;
+        }
+
+        public void SetKeyEntry(
+            string					alias,
+            AsymmetricKeyEntry		keyEntry,
+            X509CertificateEntry[]	chain)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+            if (keyEntry == null)
+                throw new ArgumentNullException("keyEntry");
+            if (keyEntry.Key.IsPrivate && (chain == null))
+                throw new ArgumentException("No certificate chain for private key");
+
+            if (keys[alias] != null)
+            {
+                DeleteEntry(alias);
+            }
+
+            keys[alias] = keyEntry;
+            certs[alias] = chain[0];
+
+            for (int i = 0; i != chain.Length; i++)
+            {
+                chainCerts[new CertId(chain[i].Certificate.GetPublicKey())] = chain[i];
+            }
+        }
+
+        public void DeleteEntry(
+            string alias)
+        {
+            if (alias == null)
+                throw new ArgumentNullException("alias");
+
+            AsymmetricKeyEntry k = (AsymmetricKeyEntry)keys[alias];
+            if (k != null)
+            {
+                keys.Remove(alias);
+            }
+
+            X509CertificateEntry c = (X509CertificateEntry)certs[alias];
+
+            if (c != null)
+            {
+                certs.Remove(alias);
+                chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
+            }
+
+            if (k != null)
+            {
+                string id = (string)localIds[alias];
+                if (id != null)
+                {
+                    localIds.Remove(alias);
+                    c = (X509CertificateEntry)keyCerts[id];
+                }
+                if (c != null)
+                {
+                    keyCerts.Remove(id);
+                    chainCerts.Remove(new CertId(c.Certificate.GetPublicKey()));
+                }
+            }
+
+            if (c == null && k == null)
+            {
+                throw new ArgumentException("no such entry as " + alias);
+            }
+        }
+
+        public bool IsEntryOfType(
+            string	alias,
+            Type	entryType)
+        {
+            if (entryType == typeof(X509CertificateEntry))
+                return IsCertificateEntry(alias);
+
+            if (entryType == typeof(AsymmetricKeyEntry))
+                return IsKeyEntry(alias) && GetCertificate(alias) != null;
+
+            return false;
+        }
+
+        [Obsolete("Use 'Count' property instead")]
+        public int Size()
+        {
+            return Count;
+        }
+
+        public int Count
+        {
+            // TODO Seems a little inefficient
+            get { return GetAliasesTable().Count; }
+        }
+
+        public void Save(
+            Stream			stream,
+            char[]			password,
+            SecureRandom	random)
+        {
+            if (stream == null)
+                throw new ArgumentNullException("stream");
+            if (password == null)
+                throw new ArgumentNullException("password");
+            if (random == null)
+                throw new ArgumentNullException("random");
+
+            //
+            // handle the key
+            //
+            Asn1EncodableVector keyS = new Asn1EncodableVector();
+            foreach (string name in keys.Keys)
+            {
+                byte[] kSalt = new byte[SaltSize];
+                random.NextBytes(kSalt);
+
+                AsymmetricKeyEntry privKey = (AsymmetricKeyEntry) keys[name];
+                EncryptedPrivateKeyInfo kInfo =
+                    EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+                    keyAlgorithm, password, kSalt, MinIterations, privKey.Key);
+
+                Asn1EncodableVector kName = new Asn1EncodableVector();
+
+                foreach (string oid in privKey.BagAttributeKeys)
+                {
+                    Asn1Encodable entry = privKey[oid];
+
+                    // NB: Ignore any existing FriendlyName
+                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+                        continue;
+
+                    kName.Add(
+                        new DerSequence(
+                            new DerObjectIdentifier(oid),
+                            new DerSet(entry)));
+                }
+
+                //
+                // make sure we are using the local alias on store
+                //
+                // NB: We always set the FriendlyName based on 'name'
+                //if (privKey[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+                {
+                    kName.Add(
+                        new DerSequence(
+                            PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+                            new DerSet(new DerBmpString(name))));
+                }
+
+                //
+                // make sure we have a local key-id
+                //
+                if (privKey[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
+                {
+                    X509CertificateEntry ct = GetCertificate(name);
+                    AsymmetricKeyParameter pubKey = ct.Certificate.GetPublicKey();
+                    SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
+
+                    kName.Add(
+                        new DerSequence(
+                            PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
+                            new DerSet(subjectKeyID)));
+                }
+
+                SafeBag kBag = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, kInfo.ToAsn1Object(), new DerSet(kName));
+                keyS.Add(kBag);
+            }
+
+            byte[] derEncodedBytes = new DerSequence(keyS).GetDerEncoded();
+
+            BerOctetString keyString = new BerOctetString(derEncodedBytes);
+
+            //
+            // certificate processing
+            //
+            byte[] cSalt = new byte[SaltSize];
+
+            random.NextBytes(cSalt);
+
+            Asn1EncodableVector	certSeq = new Asn1EncodableVector();
+            Pkcs12PbeParams		cParams = new Pkcs12PbeParams(cSalt, MinIterations);
+            AlgorithmIdentifier	cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.ToAsn1Object());
+            ISet				doneCerts = new HashSet();
+
+            foreach (string name in keys.Keys)
+            {
+                X509CertificateEntry certEntry = GetCertificate(name);
+                CertBag cBag = new CertBag(
+                    PkcsObjectIdentifiers.X509Certificate,
+                    new DerOctetString(certEntry.Certificate.GetEncoded()));
+
+                Asn1EncodableVector fName = new Asn1EncodableVector();
+
+                foreach (string oid in certEntry.BagAttributeKeys)
+                {
+                    Asn1Encodable entry = certEntry[oid];
+
+                    // NB: Ignore any existing FriendlyName
+                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+                        continue;
+
+                    fName.Add(
+                        new DerSequence(
+                            new DerObjectIdentifier(oid),
+                            new DerSet(entry)));
+                }
+
+                //
+                // make sure we are using the local alias on store
+                //
+                // NB: We always set the FriendlyName based on 'name'
+                //if (certEntry[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+                {
+                    fName.Add(
+                        new DerSequence(
+                            PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+                            new DerSet(new DerBmpString(name))));
+                }
+
+                //
+                // make sure we have a local key-id
+                //
+                if (certEntry[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
+                {
+                    AsymmetricKeyParameter pubKey = certEntry.Certificate.GetPublicKey();
+                    SubjectKeyIdentifier subjectKeyID = CreateSubjectKeyID(pubKey);
+
+                    fName.Add(
+                        new DerSequence(
+                            PkcsObjectIdentifiers.Pkcs9AtLocalKeyID,
+                            new DerSet(subjectKeyID)));
+                }
+
+                SafeBag sBag = new SafeBag(
+                    PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
+
+                certSeq.Add(sBag);
+
+                doneCerts.Add(certEntry.Certificate);
+            }
+
+            foreach (string certId in certs.Keys)
+            {
+                X509CertificateEntry cert = (X509CertificateEntry)certs[certId];
+
+                if (keys[certId] != null)
+                    continue;
+
+                CertBag cBag = new CertBag(
+                    PkcsObjectIdentifiers.X509Certificate,
+                    new DerOctetString(cert.Certificate.GetEncoded()));
+
+                Asn1EncodableVector fName = new Asn1EncodableVector();
+
+                foreach (string oid in cert.BagAttributeKeys)
+                {
+                    // 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.Pkcs9AtLocalKeyID.Id))
+                        continue;
+
+                    Asn1Encodable entry = cert[oid];
+
+                    // NB: Ignore any existing FriendlyName
+                    if (oid.Equals(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id))
+                        continue;
+
+                    fName.Add(
+                        new DerSequence(
+                            new DerObjectIdentifier(oid),
+                            new DerSet(entry)));
+                }
+
+                //
+                // make sure we are using the local alias on store
+                //
+                // NB: We always set the FriendlyName based on 'certId'
+                //if (cert[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] == null)
+                {
+                    fName.Add(
+                        new DerSequence(
+                            PkcsObjectIdentifiers.Pkcs9AtFriendlyName,
+                            new DerSet(new DerBmpString(certId))));
+                }
+
+                SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag,
+                    cBag.ToAsn1Object(), new DerSet(fName));
+
+                certSeq.Add(sBag);
+
+                doneCerts.Add(cert.Certificate);
+            }
+
+            foreach (CertId certId in chainCerts.Keys)
+            {
+                X509CertificateEntry cert = (X509CertificateEntry)chainCerts[certId];
+
+                if (doneCerts.Contains(cert.Certificate))
+                    continue;
+
+                CertBag cBag = new CertBag(
+                    PkcsObjectIdentifiers.X509Certificate,
+                    new DerOctetString(cert.Certificate.GetEncoded()));
+
+                Asn1EncodableVector fName = new Asn1EncodableVector();
+
+                foreach (string oid in cert.BagAttributeKeys)
+                {
+                    // 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.Pkcs9AtLocalKeyID.Id))
+                        continue;
+
+                    fName.Add(
+                        new DerSequence(
+                            new DerObjectIdentifier(oid),
+                            new DerSet(cert[oid])));
+                }
+
+                SafeBag sBag = new SafeBag(PkcsObjectIdentifiers.CertBag, cBag.ToAsn1Object(), new DerSet(fName));
+
+                certSeq.Add(sBag);
+            }
+
+            derEncodedBytes = new DerSequence(certSeq).GetDerEncoded();
+
+            byte[] certBytes = CryptPbeData(true, cAlgId, password, false, derEncodedBytes);
+
+            EncryptedData cInfo = new EncryptedData(PkcsObjectIdentifiers.Data, cAlgId, new BerOctetString(certBytes));
+
+            ContentInfo[] info = new ContentInfo[]
+            {
+                new ContentInfo(PkcsObjectIdentifiers.Data, keyString),
+                new ContentInfo(PkcsObjectIdentifiers.EncryptedData, cInfo.ToAsn1Object())
+            };
+
+            byte[] data = new AuthenticatedSafe(info).GetEncoded(
+                useDerEncoding ? Asn1Encodable.Der : Asn1Encodable.Ber);
+
+            ContentInfo mainInfo = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(data));
+
+            //
+            // create the mac
+            //
+            byte[] mSalt = new byte[20];
+            random.NextBytes(mSalt);
+
+            byte[] mac = CalculatePbeMac(OiwObjectIdentifiers.IdSha1,
+                mSalt, MinIterations, password, false, data);
+
+            AlgorithmIdentifier algId = new AlgorithmIdentifier(
+                OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+            DigestInfo dInfo = new DigestInfo(algId, mac);
+
+            MacData mData = new MacData(dInfo, mSalt, MinIterations);
+
+            //
+            // output the Pfx
+            //
+            Pfx pfx = new Pfx(mainInfo, mData);
+
+            DerOutputStream derOut;
+            if (useDerEncoding)
+            {
+                derOut = new DerOutputStream(stream);
+            }
+            else
+            {
+                derOut = new BerOutputStream(stream);
+            }
+
+            derOut.WriteObject(pfx);
+        }
+
+        internal static byte[] CalculatePbeMac(
+            DerObjectIdentifier	oid,
+            byte[]				salt,
+            int					itCount,
+            char[]				password,
+            bool				wrongPkcs12Zero,
+            byte[]				data)
+        {
+            Asn1Encodable asn1Params = PbeUtilities.GenerateAlgorithmParameters(
+                oid, salt, itCount);
+            ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+                oid, password, wrongPkcs12Zero, asn1Params);
+
+            IMac mac = (IMac) PbeUtilities.CreateEngine(oid);
+            mac.Init(cipherParams);
+            return MacUtilities.DoFinal(mac, data);
+        }
+
+        private static byte[] CryptPbeData(
+            bool				forEncryption,
+            AlgorithmIdentifier	algId,
+            char[]				password,
+            bool				wrongPkcs12Zero,
+            byte[]				data)
+        {
+            IBufferedCipher cipher = PbeUtilities.CreateEngine(algId.ObjectID) as IBufferedCipher;
+
+            if (cipher == null)
+                throw new Exception("Unknown encryption algorithm: " + algId.ObjectID);
+
+            Pkcs12PbeParams pbeParameters = Pkcs12PbeParams.GetInstance(algId.Parameters);
+            ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+                algId.ObjectID, password, wrongPkcs12Zero, pbeParameters);
+            cipher.Init(forEncryption, cipherParams);
+            return cipher.DoFinal(data);
+        }
+
+        private class IgnoresCaseHashtable
+            : IEnumerable
+        {
+            private readonly IDictionary orig = Platform.CreateHashtable();
             private readonly IDictionary keys = Platform.CreateHashtable();
 
-			public void Clear()
-			{
-				orig.Clear();
-				keys.Clear();
-			}
-
-			public IEnumerator GetEnumerator()
-			{
-				return orig.GetEnumerator();
-			}
-
-			public ICollection Keys
-			{
-				get { return orig.Keys; }
-			}
-
-			public object Remove(
-				string alias)
-			{
-				string lower = alias.ToLowerInvariant();
-				string k = (string) keys[lower];
-
-				if (k == null)
-					return null;
-
-				keys.Remove(lower);
-
-				object o = orig[k];
-				orig.Remove(k);
-				return o;
-			}
-
-			public object this[
-				string alias]
-			{
-				get
-				{
-					string lower = alias.ToLowerInvariant();
-					string k = (string) keys[lower];
-
-					if (k == null)
-						return null;
-
-					return orig[k];
-				}
-				set
-				{
-					string lower = alias.ToLowerInvariant();
-					string k = (string) keys[lower];
-					if (k != null)
-					{
-						orig.Remove(k);
-					}
-					keys[lower] = alias;
-					orig[alias] = value;
-				}
-			}
-
-			public ICollection Values
-			{
-				get { return orig.Values; }
-			}
-		}
-	}
+            public void Clear()
+            {
+                orig.Clear();
+                keys.Clear();
+            }
+
+            public IEnumerator GetEnumerator()
+            {
+                return orig.GetEnumerator();
+            }
+
+            public ICollection Keys
+            {
+                get { return orig.Keys; }
+            }
+
+            public object Remove(
+                string alias)
+            {
+                string lower = Platform.ToLowerInvariant(alias);
+                string k = (string) keys[lower];
+
+                if (k == null)
+                    return null;
+
+                keys.Remove(lower);
+
+                object o = orig[k];
+                orig.Remove(k);
+                return o;
+            }
+
+            public object this[
+                string alias]
+            {
+                get
+                {
+                    string lower = Platform.ToLowerInvariant(alias);
+                    string k = (string)keys[lower];
+
+                    if (k == null)
+                        return null;
+
+                    return orig[k];
+                }
+                set
+                {
+                    string lower = Platform.ToLowerInvariant(alias);
+                    string k = (string)keys[lower];
+                    if (k != null)
+                    {
+                        orig.Remove(k);
+                    }
+                    keys[lower] = alias;
+                    orig[alias] = value;
+                }
+            }
+
+            public ICollection Values
+            {
+                get { return orig.Values; }
+            }
+        }
+    }
 }
diff --git a/crypto/src/pkcs/Pkcs12Utilities.cs b/crypto/src/pkcs/Pkcs12Utilities.cs
new file mode 100644
index 000000000..d35c8b6a2
--- /dev/null
+++ b/crypto/src/pkcs/Pkcs12Utilities.cs
@@ -0,0 +1,77 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+	/**
+	 * Utility class for reencoding PKCS#12 files to definite length.
+	 */
+	public class Pkcs12Utilities
+	{
+		/**
+		 * Just re-encode the outer layer of the PKCS#12 file to definite length encoding.
+		 *
+		 * @param berPKCS12File - original PKCS#12 file
+		 * @return a byte array representing the DER encoding of the PFX structure
+		 * @throws IOException
+		 */
+		public static byte[] ConvertToDefiniteLength(
+			byte[] berPkcs12File)
+		{
+			Pfx pfx = new Pfx(Asn1Sequence.GetInstance(Asn1Object.FromByteArray(berPkcs12File)));
+
+			return pfx.GetEncoded(Asn1Encodable.Der);
+		}
+
+		/**
+		* Re-encode the PKCS#12 structure to definite length encoding at the inner layer
+		* as well, recomputing the MAC accordingly.
+		*
+		* @param berPKCS12File - original PKCS12 file.
+		* @param provider - provider to use for MAC calculation.
+		* @return a byte array representing the DER encoding of the PFX structure.
+		* @throws IOException on parsing, encoding errors.
+		*/
+		public static byte[] ConvertToDefiniteLength(
+			byte[]	berPkcs12File,
+			char[]	passwd)
+		{
+			Pfx pfx = new Pfx(Asn1Sequence.GetInstance(Asn1Object.FromByteArray(berPkcs12File)));
+
+			ContentInfo info = pfx.AuthSafe;
+
+			Asn1OctetString content = Asn1OctetString.GetInstance(info.Content);
+			Asn1Object obj = Asn1Object.FromByteArray(content.GetOctets());
+
+			info = new ContentInfo(info.ContentType, new DerOctetString(obj.GetEncoded(Asn1Encodable.Der)));
+
+			MacData mData = pfx.MacData;
+
+			try
+			{
+				int itCount = mData.IterationCount.IntValue;
+				byte[] data = Asn1OctetString.GetInstance(info.Content).GetOctets();
+				byte[] res = Pkcs12Store.CalculatePbeMac(
+					mData.Mac.AlgorithmID.ObjectID, mData.GetSalt(), itCount, passwd, false, data);
+
+				AlgorithmIdentifier algId = new AlgorithmIdentifier(
+					mData.Mac.AlgorithmID.ObjectID, DerNull.Instance);
+				DigestInfo dInfo = new DigestInfo(algId, res);
+
+				mData = new MacData(dInfo, mData.GetSalt(), itCount);
+			}
+			catch (Exception e)
+			{
+				throw new IOException("error constructing MAC: " + e.ToString());
+			}
+
+			pfx = new Pfx(info, mData);
+
+			return pfx.GetEncoded(Asn1Encodable.Der);
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/pkcs/PrivateKeyInfoFactory.cs b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
index ed566cae9..723d50f08 100644
--- a/crypto/src/pkcs/PrivateKeyInfoFactory.cs
+++ b/crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -15,200 +15,194 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pkcs
 {
-	public sealed class PrivateKeyInfoFactory
-	{
-		private PrivateKeyInfoFactory()
-		{
-		}
-
-		public static PrivateKeyInfo CreatePrivateKeyInfo(
-			AsymmetricKeyParameter key)
-		{
-			if (key == null)
-				throw new ArgumentNullException("key");
-			if (!key.IsPrivate)
-				throw new ArgumentException("Public key passed - private key expected", "key");
-
-			if (key is ElGamalPrivateKeyParameters)
-			{
-				ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key;
-				return new PrivateKeyInfo(
-					new AlgorithmIdentifier(
-					OiwObjectIdentifiers.ElGamalAlgorithm,
-					new ElGamalParameter(
-					_key.Parameters.P,
-					_key.Parameters.G).ToAsn1Object()),
-					new DerInteger(_key.X));
-			}
-
-			if (key is DsaPrivateKeyParameters)
-			{
-				DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key;
-				return new PrivateKeyInfo(
-					new AlgorithmIdentifier(
-					X9ObjectIdentifiers.IdDsa,
-					new DsaParameter(
-					_key.Parameters.P,
-					_key.Parameters.Q,
-					_key.Parameters.G).ToAsn1Object()),
-					new DerInteger(_key.X));
-			}
-
-			if (key is DHPrivateKeyParameters)
-			{
-				DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key;
-
-				DHParameter p = new DHParameter(
-					_key.Parameters.P, _key.Parameters.G, _key.Parameters.L);
-
-				return new PrivateKeyInfo(
-					new AlgorithmIdentifier(_key.AlgorithmOid, p.ToAsn1Object()),
-					new DerInteger(_key.X));
-			}
-
-			if (key is RsaKeyParameters)
-			{
-				AlgorithmIdentifier algID = new AlgorithmIdentifier(
-					PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance);
-
-				RsaPrivateKeyStructure keyStruct;
-				if (key is RsaPrivateCrtKeyParameters)
-				{
-					RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key;
-
-					keyStruct = new RsaPrivateKeyStructure(
-						_key.Modulus,
-						_key.PublicExponent,
-						_key.Exponent,
-						_key.P,
-						_key.Q,
-						_key.DP,
-						_key.DQ,
-						_key.QInv);
-				}
-				else
-				{
-					RsaKeyParameters _key = (RsaKeyParameters) key;
-
-					keyStruct = new RsaPrivateKeyStructure(
-						_key.Modulus,
-						BigInteger.Zero,
-						_key.Exponent,
-						BigInteger.Zero,
-						BigInteger.Zero,
-						BigInteger.Zero,
-						BigInteger.Zero,
-						BigInteger.Zero);
-				}
-
-				return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object());
-			}
-
-			if (key is ECPrivateKeyParameters)
-			{
-				ECPrivateKeyParameters _key = (ECPrivateKeyParameters)key;
-				AlgorithmIdentifier algID;
-				ECPrivateKeyStructure ec;
-
-				if (_key.AlgorithmName == "ECGOST3410")
-				{
-					if (_key.PublicKeyParamSet == null)
-						throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
-
-					Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
-						_key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
-
-					algID = new AlgorithmIdentifier(
-						CryptoProObjectIdentifiers.GostR3410x2001,
-						gostParams.ToAsn1Object());
-
-					// TODO Do we need to pass any parameters here?
-					ec = new ECPrivateKeyStructure(_key.D);
-				}
-				else
-				{
-					X962Parameters x962;
-					if (_key.PublicKeyParamSet == null)
-					{
-						ECDomainParameters kp = _key.Parameters;
-						X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
-
-						x962 = new X962Parameters(ecP);
-					}
-					else
-					{
-						x962 = new X962Parameters(_key.PublicKeyParamSet);
-					}
-
-					Asn1Object x962Object = x962.ToAsn1Object();
-
-					// TODO Possible to pass the publicKey bitstring here?
-					ec = new ECPrivateKeyStructure(_key.D, x962Object);
-
-					algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962Object);
-				}
-
-				return new PrivateKeyInfo(algID, ec.ToAsn1Object());
-			}
-
-			if (key is Gost3410PrivateKeyParameters)
-			{
-				Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key;
-
-				if (_key.PublicKeyParamSet == null)
-					throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
-
-				byte[] keyEnc = _key.X.ToByteArrayUnsigned();
-				byte[] keyBytes = new byte[keyEnc.Length];
-
-				for (int i = 0; i != keyBytes.Length; i++)
-				{
-					keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
-				}
-
-				Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
-					_key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet, null);
-
-				AlgorithmIdentifier algID = new AlgorithmIdentifier(
-					CryptoProObjectIdentifiers.GostR3410x94,
-					algParams.ToAsn1Object());
-
-				return new PrivateKeyInfo(algID, new DerOctetString(keyBytes));
-			}
-
-			throw new ArgumentException("Class provided is not convertible: " + key.GetType().FullName);
-		}
-
-		public static PrivateKeyInfo CreatePrivateKeyInfo(
-			char[]					passPhrase,
-			EncryptedPrivateKeyInfo	encInfo)
-		{
-			return CreatePrivateKeyInfo(passPhrase, false, encInfo);
-		}
-
-		public static PrivateKeyInfo CreatePrivateKeyInfo(
-			char[]					passPhrase,
-			bool					wrongPkcs12Zero,
-			EncryptedPrivateKeyInfo	encInfo)
-		{
-			AlgorithmIdentifier algID = encInfo.EncryptionAlgorithm;
-			IBufferedCipher cipher = PbeUtilities.CreateEngine(algID) as IBufferedCipher;
-
-			if (cipher == null)
-			{
-				// TODO Throw exception?
-			}
-
-			ICipherParameters keyParameters = PbeUtilities.GenerateCipherParameters(
-				algID, passPhrase, wrongPkcs12Zero);
-
-			cipher.Init(false, keyParameters);
-
-			byte[] keyBytes = encInfo.GetEncryptedData();
-			byte[] encoding = cipher.DoFinal(keyBytes);
-			Asn1Object asn1Data = Asn1Object.FromByteArray(encoding);
-
-			return PrivateKeyInfo.GetInstance(asn1Data);
-		}
-	}
+    public sealed class PrivateKeyInfoFactory
+    {
+        private PrivateKeyInfoFactory()
+        {
+        }
+
+        public static PrivateKeyInfo CreatePrivateKeyInfo(
+            AsymmetricKeyParameter key)
+        {
+            if (key == null)
+                throw new ArgumentNullException("key");
+            if (!key.IsPrivate)
+                throw new ArgumentException("Public key passed - private key expected", "key");
+
+            if (key is ElGamalPrivateKeyParameters)
+            {
+                ElGamalPrivateKeyParameters _key = (ElGamalPrivateKeyParameters)key;
+                return new PrivateKeyInfo(
+                    new AlgorithmIdentifier(
+                    OiwObjectIdentifiers.ElGamalAlgorithm,
+                    new ElGamalParameter(
+                    _key.Parameters.P,
+                    _key.Parameters.G).ToAsn1Object()),
+                    new DerInteger(_key.X));
+            }
+
+            if (key is DsaPrivateKeyParameters)
+            {
+                DsaPrivateKeyParameters _key = (DsaPrivateKeyParameters)key;
+                return new PrivateKeyInfo(
+                    new AlgorithmIdentifier(
+                    X9ObjectIdentifiers.IdDsa,
+                    new DsaParameter(
+                    _key.Parameters.P,
+                    _key.Parameters.Q,
+                    _key.Parameters.G).ToAsn1Object()),
+                    new DerInteger(_key.X));
+            }
+
+            if (key is DHPrivateKeyParameters)
+            {
+                DHPrivateKeyParameters _key = (DHPrivateKeyParameters)key;
+
+                DHParameter p = new DHParameter(
+                    _key.Parameters.P, _key.Parameters.G, _key.Parameters.L);
+
+                return new PrivateKeyInfo(
+                    new AlgorithmIdentifier(_key.AlgorithmOid, p.ToAsn1Object()),
+                    new DerInteger(_key.X));
+            }
+
+            if (key is RsaKeyParameters)
+            {
+                AlgorithmIdentifier algID = new AlgorithmIdentifier(
+                    PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance);
+
+                RsaPrivateKeyStructure keyStruct;
+                if (key is RsaPrivateCrtKeyParameters)
+                {
+                    RsaPrivateCrtKeyParameters _key = (RsaPrivateCrtKeyParameters)key;
+
+                    keyStruct = new RsaPrivateKeyStructure(
+                        _key.Modulus,
+                        _key.PublicExponent,
+                        _key.Exponent,
+                        _key.P,
+                        _key.Q,
+                        _key.DP,
+                        _key.DQ,
+                        _key.QInv);
+                }
+                else
+                {
+                    RsaKeyParameters _key = (RsaKeyParameters) key;
+
+                    keyStruct = new RsaPrivateKeyStructure(
+                        _key.Modulus,
+                        BigInteger.Zero,
+                        _key.Exponent,
+                        BigInteger.Zero,
+                        BigInteger.Zero,
+                        BigInteger.Zero,
+                        BigInteger.Zero,
+                        BigInteger.Zero);
+                }
+
+                return new PrivateKeyInfo(algID, keyStruct.ToAsn1Object());
+            }
+
+            if (key is ECPrivateKeyParameters)
+            {
+                ECPrivateKeyParameters _key = (ECPrivateKeyParameters)key;
+                AlgorithmIdentifier algID;
+                ECPrivateKeyStructure ec;
+
+                if (_key.AlgorithmName == "ECGOST3410")
+                {
+                    if (_key.PublicKeyParamSet == null)
+                        throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+                    Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+                        _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+                    algID = new AlgorithmIdentifier(
+                        CryptoProObjectIdentifiers.GostR3410x2001,
+                        gostParams.ToAsn1Object());
+
+                    // TODO Do we need to pass any parameters here?
+                    ec = new ECPrivateKeyStructure(_key.D);
+                }
+                else
+                {
+                    X962Parameters x962;
+                    if (_key.PublicKeyParamSet == null)
+                    {
+                        ECDomainParameters kp = _key.Parameters;
+                        X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
+
+                        x962 = new X962Parameters(ecP);
+                    }
+                    else
+                    {
+                        x962 = new X962Parameters(_key.PublicKeyParamSet);
+                    }
+
+                    Asn1Object x962Object = x962.ToAsn1Object();
+
+                    // TODO Possible to pass the publicKey bitstring here?
+                    ec = new ECPrivateKeyStructure(_key.D, x962Object);
+
+                    algID = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, x962Object);
+                }
+
+                return new PrivateKeyInfo(algID, ec.ToAsn1Object());
+            }
+
+            if (key is Gost3410PrivateKeyParameters)
+            {
+                Gost3410PrivateKeyParameters _key = (Gost3410PrivateKeyParameters)key;
+
+                if (_key.PublicKeyParamSet == null)
+                    throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+                byte[] keyEnc = _key.X.ToByteArrayUnsigned();
+                byte[] keyBytes = new byte[keyEnc.Length];
+
+                for (int i = 0; i != keyBytes.Length; i++)
+                {
+                    keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+                }
+
+                Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+                    _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet, null);
+
+                AlgorithmIdentifier algID = new AlgorithmIdentifier(
+                    CryptoProObjectIdentifiers.GostR3410x94,
+                    algParams.ToAsn1Object());
+
+                return new PrivateKeyInfo(algID, new DerOctetString(keyBytes));
+            }
+
+            throw new ArgumentException("Class provided is not convertible: " + key.GetType().FullName);
+        }
+
+        public static PrivateKeyInfo CreatePrivateKeyInfo(
+            char[]					passPhrase,
+            EncryptedPrivateKeyInfo	encInfo)
+        {
+            return CreatePrivateKeyInfo(passPhrase, false, encInfo);
+        }
+
+        public static PrivateKeyInfo CreatePrivateKeyInfo(
+            char[]					passPhrase,
+            bool					wrongPkcs12Zero,
+            EncryptedPrivateKeyInfo	encInfo)
+        {
+            AlgorithmIdentifier algID = encInfo.EncryptionAlgorithm;
+
+            IBufferedCipher cipher = PbeUtilities.CreateEngine(algID) as IBufferedCipher;
+            if (cipher == null)
+                throw new Exception("Unknown encryption algorithm: " + algID.ObjectID);
+
+            ICipherParameters cipherParameters = PbeUtilities.GenerateCipherParameters(
+                algID, passPhrase, wrongPkcs12Zero);
+            cipher.Init(false, cipherParameters);
+            byte[] keyBytes = cipher.DoFinal(encInfo.GetEncryptedData());
+
+            return PrivateKeyInfo.GetInstance(keyBytes);
+        }
+    }
 }
diff --git a/crypto/src/pkcs/X509CertificateEntry.cs b/crypto/src/pkcs/X509CertificateEntry.cs
index 2f81dd87b..a621619fb 100644
--- a/crypto/src/pkcs/X509CertificateEntry.cs
+++ b/crypto/src/pkcs/X509CertificateEntry.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Pkcs
             this.cert = cert;
         }
 
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
         [Obsolete]
         public X509CertificateEntry(
             X509Certificate	cert,
diff --git a/crypto/src/pkix/CertStatus.cs b/crypto/src/pkix/CertStatus.cs
new file mode 100644
index 000000000..4f40b7bc6
--- /dev/null
+++ b/crypto/src/pkix/CertStatus.cs
@@ -0,0 +1,35 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Pkix
+{
+    public class CertStatus
+    {
+        public const int Unrevoked = 11;
+
+        public const int Undetermined = 12;
+
+        private int status = Unrevoked;
+
+        DateTimeObject revocationDate = null;
+
+        /// <summary>
+        /// Returns the revocationDate.
+        /// </summary>
+         public DateTimeObject RevocationDate
+        {
+            get { return revocationDate; }
+            set { this.revocationDate = value; }
+        }
+
+		/// <summary>
+        /// Returns the certStatus.
+        /// </summary>
+        public int Status
+        {
+            get { return status; }
+            set { this.status = value; }
+        }
+    }
+}
diff --git a/crypto/src/pkix/PkixAttrCertChecker.cs b/crypto/src/pkix/PkixAttrCertChecker.cs
new file mode 100644
index 000000000..a6eab8480
--- /dev/null
+++ b/crypto/src/pkix/PkixAttrCertChecker.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+	public abstract class PkixAttrCertChecker
+	{
+		/**
+		 * 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>
+		 * <p>
+		 * All X.509 attribute certificate extensions that a
+		 * <code>PkixAttrCertChecker</code> might possibly be able to process
+		 * should be included in the set.
+		 * </p>
+		 * 
+		 * @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 ISet 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(IX509AttributeCertificate attrCert, PkixCertPath certPath,
+			PkixCertPath holderCertPath, ICollection unresolvedCritExts);
+
+		/**
+		* Returns a clone of this object.
+		* 
+		* @return a copy of this <code>PkixAttrCertChecker</code>
+		*/
+		public abstract PkixAttrCertChecker Clone();
+	}
+}
diff --git a/crypto/src/pkix/PkixAttrCertPathBuilder.cs b/crypto/src/pkix/PkixAttrCertPathBuilder.cs
new file mode 100644
index 000000000..646cc5db5
--- /dev/null
+++ b/crypto/src/pkix/PkixAttrCertPathBuilder.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	public class PkixAttrCertPathBuilder
+	{
+		/**
+		* Build and validate a CertPath using the given parameter.
+		*
+		* @param params PKIXBuilderParameters object containing all information to
+		*            build the CertPath
+		*/
+		public virtual PkixCertPathBuilderResult Build(
+			PkixBuilderParameters pkixParams)
+		{
+			// search target certificates
+
+			IX509Selector certSelect = pkixParams.GetTargetConstraints();
+			if (!(certSelect is X509AttrCertStoreSelector))
+			{
+				throw new PkixCertPathBuilderException(
+					"TargetConstraints must be an instance of "
+					+ typeof(X509AttrCertStoreSelector).FullName
+					+ " for "
+					+ typeof(PkixAttrCertPathBuilder).FullName + " class.");
+			}
+
+			ICollection targets;
+			try
+			{
+				targets = PkixCertPathValidatorUtilities.FindCertificates(
+					(X509AttrCertStoreSelector)certSelect, pkixParams.GetStores());
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathBuilderException("Error finding target attribute certificate.", e);
+			}
+
+			if (targets.Count == 0)
+			{
+				throw new PkixCertPathBuilderException(
+					"No attribute certificate found matching targetContraints.");
+			}
+
+			PkixCertPathBuilderResult result = null;
+
+			// check all potential target certificates
+			foreach (IX509AttributeCertificate cert in targets)
+			{
+				X509CertStoreSelector selector = new X509CertStoreSelector();
+				X509Name[] principals = cert.Issuer.GetPrincipals();
+				ISet issuers = new HashSet();
+				for (int i = 0; i < principals.Length; i++)
+				{
+					try
+					{
+						selector.Subject = principals[i];
+
+						issuers.AddAll(PkixCertPathValidatorUtilities.FindCertificates(selector, pkixParams.GetStores()));
+					}
+					catch (Exception e)
+					{
+						throw new PkixCertPathBuilderException(
+							"Public key certificate for attribute certificate cannot be searched.",
+							e);
+					}
+				}
+
+				if (issuers.IsEmpty)
+					throw new PkixCertPathBuilderException("Public key certificate for attribute certificate cannot be found.");
+
+                IList certPathList = Platform.CreateArrayList();
+
+				foreach (X509Certificate issuer in issuers)
+				{
+					result = Build(cert, issuer, pkixParams, certPathList);
+
+					if (result != null)
+						break;
+				}
+
+				if (result != null)
+					break;
+			}
+
+			if (result == null && certPathException != null)
+			{
+				throw new PkixCertPathBuilderException(
+					"Possible certificate chain could not be validated.",
+					certPathException);
+			}
+
+			if (result == null && certPathException == null)
+			{
+				throw new PkixCertPathBuilderException(
+					"Unable to find certificate chain.");
+			}
+
+			return result;
+		}
+
+		private Exception certPathException;
+
+		private PkixCertPathBuilderResult Build(
+			IX509AttributeCertificate	attrCert,
+			X509Certificate				tbvCert,
+			PkixBuilderParameters		pkixParams,
+			IList						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.MaxPathLength != -1)
+			{
+				if (tbvPath.Count - 1 > pkixParams.MaxPathLength)
+					return null;
+			}
+
+			tbvPath.Add(tbvCert);
+
+			PkixCertPathBuilderResult builderResult = null;
+
+//			X509CertificateParser certParser = new X509CertificateParser();
+			PkixAttrCertPathValidator validator = new PkixAttrCertPathValidator();
+
+			try
+			{
+				// check whether the issuer of <tbvCert> is a TrustAnchor
+				if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null)
+				{
+					PkixCertPath certPath = new PkixCertPath(tbvPath);
+					PkixCertPathValidatorResult result;
+
+					try
+					{
+						result = validator.Validate(certPath, pkixParams);
+					}
+					catch (Exception e)
+					{
+						throw new Exception("Certification path could not be validated.", e);
+					}
+
+					return new PkixCertPathBuilderResult(certPath, result.TrustAnchor,
+						result.PolicyTree, result.SubjectPublicKey);
+				}
+				else
+				{
+					// add additional X.509 stores from locations in certificate
+					try
+					{
+						PkixCertPathValidatorUtilities.AddAdditionalStoresFromAltNames(tbvCert, pkixParams);
+					}
+					catch (CertificateParsingException e)
+					{
+						throw new Exception("No additional X.509 stores can be added from certificate locations.", e);
+					}
+
+					// try to get the issuer certificate from one of the stores
+					ISet issuers = new HashSet();
+					try
+					{
+						issuers.AddAll(PkixCertPathValidatorUtilities.FindIssuerCerts(tbvCert, pkixParams));
+					}
+					catch (Exception e)
+					{
+						throw new Exception("Cannot find issuer certificate for certificate in certification path.", e);
+					}
+
+					if (issuers.IsEmpty)
+						throw new Exception("No issuer certificate for certificate in certification path found.");
+
+					foreach (X509Certificate issuer in issuers)
+					{
+						// if untrusted self signed certificate continue
+						if (PkixCertPathValidatorUtilities.IsSelfIssued(issuer))
+							continue;
+
+						builderResult = Build(attrCert, issuer, pkixParams, tbvPath);
+
+						if (builderResult != null)
+							break;
+					}
+				}
+			}
+			catch (Exception e)
+			{
+				certPathException = new Exception("No valid certification path could be build.", e);
+			}
+
+			if (builderResult == null)
+			{
+				tbvPath.Remove(tbvCert);
+			}
+
+			return builderResult;
+		}
+	}
+}
diff --git a/crypto/src/pkix/PkixAttrCertPathValidator.cs b/crypto/src/pkix/PkixAttrCertPathValidator.cs
new file mode 100644
index 000000000..5f53bcde6
--- /dev/null
+++ b/crypto/src/pkix/PkixAttrCertPathValidator.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/**
+	* CertPathValidatorSpi implementation for X.509 Attribute Certificates la RFC 3281.
+	* 
+	* @see org.bouncycastle.x509.ExtendedPkixParameters
+	*/
+	public class PkixAttrCertPathValidator
+	//    extends CertPathValidatorSpi
+	{
+		/**
+		* Validates an attribute certificate with the given certificate path.
+		* 
+		* <p>
+		* <code>params</code> must be an instance of
+		* <code>ExtendedPkixParameters</code>.
+		* </p><p>
+		* The target constraints in the <code>params</code> must be an
+		* <code>X509AttrCertStoreSelector</code> with at least the attribute
+		* certificate criterion set. Obey that also target informations may be
+		* necessary to correctly validate this attribute certificate.
+		* </p><p>
+		* The attribute certificate issuer must be added to the trusted attribute
+		* issuers with {@link ExtendedPkixParameters#setTrustedACIssuers(Set)}.
+		* </p>
+		* @param certPath The certificate path which belongs to the attribute
+		*            certificate issuer public key certificate.
+		* @param params The PKIX parameters.
+		* @return A <code>PKIXCertPathValidatorResult</code> of the result of
+		*         validating the <code>certPath</code>.
+		* @throws InvalidAlgorithmParameterException if <code>params</code> is
+		*             inappropriate for this validator.
+		* @throws CertPathValidatorException if the verification fails.
+		*/
+		public virtual PkixCertPathValidatorResult Validate(
+			PkixCertPath	certPath,
+			PkixParameters	pkixParams)
+		{
+			IX509Selector certSelect = pkixParams.GetTargetConstraints();
+			if (!(certSelect is X509AttrCertStoreSelector))
+			{
+				throw new ArgumentException(
+					"TargetConstraints must be an instance of " + typeof(X509AttrCertStoreSelector).FullName,
+					"pkixParams");
+			}
+			IX509AttributeCertificate attrCert = ((X509AttrCertStoreSelector) certSelect).AttributeCert;
+
+			PkixCertPath holderCertPath = Rfc3281CertPathUtilities.ProcessAttrCert1(attrCert, pkixParams);
+			PkixCertPathValidatorResult result = Rfc3281CertPathUtilities.ProcessAttrCert2(certPath, pkixParams);
+			X509Certificate issuerCert = (X509Certificate)certPath.Certificates[0];
+			Rfc3281CertPathUtilities.ProcessAttrCert3(issuerCert, pkixParams);
+			Rfc3281CertPathUtilities.ProcessAttrCert4(issuerCert, pkixParams);
+			Rfc3281CertPathUtilities.ProcessAttrCert5(attrCert, pkixParams);
+			// 6 already done in X509AttrCertStoreSelector
+			Rfc3281CertPathUtilities.ProcessAttrCert7(attrCert, certPath, holderCertPath, pkixParams);
+			Rfc3281CertPathUtilities.AdditionalChecks(attrCert, pkixParams);
+			DateTime date;
+			try
+			{
+				date = PkixCertPathValidatorUtilities.GetValidCertDateFromValidityModel(pkixParams, null, -1);
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Could not get validity date from attribute certificate.", e);
+			}
+			Rfc3281CertPathUtilities.CheckCrls(attrCert, pkixParams, issuerCert, date, certPath.Certificates);
+			return result;
+		}
+	}
+}
diff --git a/crypto/src/pkix/PkixBuilderParameters.cs b/crypto/src/pkix/PkixBuilderParameters.cs
new file mode 100644
index 000000000..32fc04360
--- /dev/null
+++ b/crypto/src/pkix/PkixBuilderParameters.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509.Store;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+    /// Summary description for PkixBuilderParameters.
+	/// </summary>
+	public class PkixBuilderParameters
+		: PkixParameters
+	{
+		private int maxPathLength = 5;
+
+		private ISet excludedCerts = new HashSet();
+
+		/**
+		* Returns an instance of <code>PkixBuilderParameters</code>.
+		* <p>
+		* This method can be used to get a copy from other
+		* <code>PKIXBuilderParameters</code>, <code>PKIXParameters</code>,
+		* and <code>ExtendedPKIXParameters</code> instances.
+		* </p>
+		*
+		* @param pkixParams The PKIX parameters to create a copy of.
+		* @return An <code>PkixBuilderParameters</code> instance.
+		*/
+		public static PkixBuilderParameters GetInstance(
+			PkixParameters pkixParams)
+		{
+			PkixBuilderParameters parameters = new PkixBuilderParameters(
+				pkixParams.GetTrustAnchors(),
+				new X509CertStoreSelector(pkixParams.GetTargetCertConstraints()));
+			parameters.SetParams(pkixParams);
+			return parameters;
+		}
+
+		public PkixBuilderParameters(
+			ISet			trustAnchors,
+			IX509Selector	targetConstraints)
+			: base(trustAnchors)
+		{
+			SetTargetCertConstraints(targetConstraints);
+		}
+
+		public virtual int MaxPathLength
+		{
+			get { return maxPathLength; }
+			set
+			{
+				if (value < -1)
+				{
+					throw new InvalidParameterException(
+						"The maximum path length parameter can not be less than -1.");
+				}
+				this.maxPathLength = value;
+			}
+		}
+
+		/// <summary>
+		/// Excluded certificates are not used for building a certification path.
+		/// </summary>
+		/// <returns>the excluded certificates.</returns>
+		public virtual ISet GetExcludedCerts()
+		{
+			return new HashSet(excludedCerts);
+		}
+
+		/// <summary>
+		/// Sets the excluded certificates which are not used for building a
+		/// certification path. If the <code>ISet</code> is <code>null</code> an
+		/// empty set is assumed.
+		/// </summary>
+		/// <remarks>
+		/// The given set is cloned to protect it against subsequent modifications.
+		/// </remarks>
+		/// <param name="excludedCerts">The excluded certificates to set.</param>
+		public virtual void SetExcludedCerts(
+			ISet excludedCerts)
+		{
+			if (excludedCerts == null)
+			{
+				excludedCerts = new HashSet();
+			}
+			else
+			{
+				this.excludedCerts = new HashSet(excludedCerts);
+			}
+		}
+
+		/**
+		* 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 override void SetParams(
+			PkixParameters parameters)
+		{
+			base.SetParams(parameters);
+			if (parameters is PkixBuilderParameters)
+			{
+				PkixBuilderParameters _params = (PkixBuilderParameters) parameters;
+				maxPathLength = _params.maxPathLength;
+				excludedCerts = new HashSet(_params.excludedCerts);
+			}
+		}
+
+		/**
+		* 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 override object Clone()
+		{
+			PkixBuilderParameters parameters = new PkixBuilderParameters(
+				GetTrustAnchors(), GetTargetCertConstraints());
+			parameters.SetParams(this);
+			return parameters;
+		}
+
+		public override string ToString()
+		{
+			string nl = Platform.NewLine;
+			StringBuilder s = new StringBuilder();
+			s.Append("PkixBuilderParameters [" + nl);
+			s.Append(base.ToString());
+			s.Append("  Maximum Path Length: ");
+			s.Append(MaxPathLength);
+			s.Append(nl + "]" + nl);
+			return s.ToString();
+		}
+	}
+}
diff --git a/crypto/src/pkix/PkixCertPath.cs b/crypto/src/pkix/PkixCertPath.cs
index e13e50995..e3d3ea7fe 100644
--- a/crypto/src/pkix/PkixCertPath.cs
+++ b/crypto/src/pkix/PkixCertPath.cs
@@ -401,7 +401,7 @@ namespace Org.BouncyCastle.Pkix
 						pWrt.WriteObject(certificates[i]);
 					}
 
-                    pWrt.Writer.Dispose();
+					pWrt.Writer.Close();
 				}
 				catch (Exception)
 				{
diff --git a/crypto/src/pkix/PkixCertPathBuilder.cs b/crypto/src/pkix/PkixCertPathBuilder.cs
new file mode 100644
index 000000000..7082fe409
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathBuilder.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1.IsisMtt;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/**
+	* Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+	*
+	* @see CertPathBuilderSpi
+	*/
+	public class PkixCertPathBuilder
+		//		: CertPathBuilderSpi
+	{
+		/**
+		 * Build and validate a CertPath using the given parameter.
+		 *
+		 * @param params PKIXBuilderParameters object containing all information to
+		 *            build the CertPath
+		 */
+		public virtual PkixCertPathBuilderResult Build(
+			PkixBuilderParameters pkixParams)
+		{
+			// search target certificates
+
+			IX509Selector certSelect = pkixParams.GetTargetCertConstraints();
+			if (!(certSelect is X509CertStoreSelector))
+			{
+				throw new PkixCertPathBuilderException(
+					"TargetConstraints must be an instance of "
+					+ typeof(X509CertStoreSelector).FullName + " for "
+					+ this.GetType() + " class.");
+			}
+
+			ISet targets = new HashSet();
+			try
+			{
+				targets.AddAll(PkixCertPathValidatorUtilities.FindCertificates((X509CertStoreSelector)certSelect, pkixParams.GetStores()));
+				// TODO Should this include an entry for pkixParams.GetAdditionalStores() too?
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathBuilderException(
+					"Error finding target certificate.", e);
+			}
+
+			if (targets.IsEmpty)
+				throw new PkixCertPathBuilderException("No certificate found matching targetContraints.");
+
+			PkixCertPathBuilderResult result = null;
+			IList certPathList = Platform.CreateArrayList();
+
+			// check all potential target certificates
+			foreach (X509Certificate cert in targets)
+			{
+				result = Build(cert, pkixParams, certPathList);
+
+				if (result != null)
+					break;
+			}
+
+			if (result == null && certPathException != null)
+			{
+				throw new PkixCertPathBuilderException(certPathException.Message, certPathException.InnerException);
+			}
+
+			if (result == null && certPathException == null)
+			{
+				throw new PkixCertPathBuilderException("Unable to find certificate chain.");
+			}
+
+			return result;
+		}
+
+		private Exception certPathException;
+
+		protected virtual PkixCertPathBuilderResult Build(
+			X509Certificate			tbvCert,
+			PkixBuilderParameters	pkixParams,
+			IList					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.MaxPathLength != -1)
+			{
+				if (tbvPath.Count - 1 > pkixParams.MaxPathLength)
+					return null;
+			}
+
+			tbvPath.Add(tbvCert);
+
+//			X509CertificateParser certParser = new X509CertificateParser();
+			PkixCertPathBuilderResult builderResult = null;
+			PkixCertPathValidator validator = new PkixCertPathValidator();
+
+			try
+			{
+				// check whether the issuer of <tbvCert> is a TrustAnchor
+				if (PkixCertPathValidatorUtilities.FindTrustAnchor(tbvCert, pkixParams.GetTrustAnchors()) != null)
+				{
+					// exception message from possibly later tried certification
+					// chains
+					PkixCertPath certPath = null;
+					try
+					{
+						certPath = new PkixCertPath(tbvPath);
+					}
+					catch (Exception e)
+					{
+						throw new Exception(
+							"Certification path could not be constructed from certificate list.",
+							e);
+					}
+
+					PkixCertPathValidatorResult result = null;
+					try
+					{
+						result = (PkixCertPathValidatorResult)validator.Validate(
+							certPath, pkixParams);
+					}
+					catch (Exception e)
+					{
+						throw new Exception(
+							"Certification path could not be validated.", e);
+					}
+
+					return new PkixCertPathBuilderResult(certPath, result.TrustAnchor,
+						result.PolicyTree, result.SubjectPublicKey);
+				}
+				else
+				{
+					// add additional X.509 stores from locations in certificate
+					try
+					{
+						PkixCertPathValidatorUtilities.AddAdditionalStoresFromAltNames(
+							tbvCert, pkixParams);
+					}
+					catch (CertificateParsingException e)
+					{
+						throw new Exception(
+							"No additiontal X.509 stores can be added from certificate locations.",
+							e);
+					}
+
+					// try to get the issuer certificate from one of the stores
+					HashSet issuers = new HashSet();
+					try
+					{
+						issuers.AddAll(PkixCertPathValidatorUtilities.FindIssuerCerts(tbvCert, pkixParams));
+					}
+					catch (Exception e)
+					{
+						throw new Exception(
+							"Cannot find issuer certificate for certificate in certification path.",
+							e);
+					}
+
+					if (issuers.IsEmpty)
+						throw new Exception("No issuer certificate for certificate in certification path found.");
+
+					foreach (X509Certificate issuer in issuers)
+					{
+						builderResult = Build(issuer, pkixParams, tbvPath);
+
+						if (builderResult != null)
+							break;
+					}
+				}
+			}
+			catch (Exception e)
+			{
+				certPathException = e;
+			}
+
+			if (builderResult == null)
+			{
+				tbvPath.Remove(tbvCert);
+			}
+
+			return builderResult;
+		}
+	}
+}
diff --git a/crypto/src/pkix/PkixCertPathBuilderException.cs b/crypto/src/pkix/PkixCertPathBuilderException.cs
index 106075a63..5a4944dd8 100644
--- a/crypto/src/pkix/PkixCertPathBuilderException.cs
+++ b/crypto/src/pkix/PkixCertPathBuilderException.cs
@@ -7,7 +7,10 @@ namespace Org.BouncyCastle.Pkix
 	/// <summary>
 	/// Summary description for PkixCertPathBuilderException.
 	/// </summary>
-	public class PkixCertPathBuilderException : GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PkixCertPathBuilderException : GeneralSecurityException
 	{
 		public PkixCertPathBuilderException() : base() { }
 		
diff --git a/crypto/src/pkix/PkixCertPathBuilderResult.cs b/crypto/src/pkix/PkixCertPathBuilderResult.cs
new file mode 100644
index 000000000..f8003032f
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathBuilderResult.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkix;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// Summary description for PkixCertPathBuilderResult.
+	/// </summary>
+	public class PkixCertPathBuilderResult
+		: PkixCertPathValidatorResult//, ICertPathBuilderResult
+	{
+		private PkixCertPath certPath;
+		
+		public PkixCertPathBuilderResult(
+			PkixCertPath			certPath,
+			TrustAnchor				trustAnchor,
+			PkixPolicyNode			policyTree,
+			AsymmetricKeyParameter	subjectPublicKey)
+			: base(trustAnchor, policyTree, subjectPublicKey)
+		{			
+			if (certPath == null)
+				throw new ArgumentNullException("certPath");
+
+			this.certPath = certPath;
+		}
+
+		public PkixCertPath CertPath
+		{
+            get { return certPath; }
+		}
+
+		public override string ToString()
+		{
+			StringBuilder s = new StringBuilder();
+			s.Append("SimplePKIXCertPathBuilderResult: [\n");
+			s.Append("  Certification Path: ").Append(CertPath).Append('\n');
+			s.Append("  Trust Anchor: ").Append(this.TrustAnchor.TrustedCert.IssuerDN.ToString()).Append('\n');
+			s.Append("  Subject Public Key: ").Append(this.SubjectPublicKey).Append("\n]");
+			return s.ToString();
+		}
+	}
+}
diff --git a/crypto/src/pkix/PkixCertPathChecker.cs b/crypto/src/pkix/PkixCertPathChecker.cs
new file mode 100644
index 000000000..f22738d89
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathChecker.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+    public abstract class PkixCertPathChecker
+    {
+        protected PkixCertPathChecker()
+        {
+        }
+
+        /**
+         * Initializes the internal state of this <code>PKIXCertPathChecker</code>.
+         * <p>
+         * The <code>forward</code> flag specifies the order that certificates
+         * will be passed to the {@link #check check} method (forward or reverse). A
+         * <code>PKIXCertPathChecker</code> <b>must</b> support reverse checking
+         * and <b>may</b> support forward checking.
+		 * </p>
+         * 
+         * @param forward
+         *            the order that certificates are presented to the
+         *            <code>check</code> method. If <code>true</code>,
+         *            certificates are presented from target to most-trusted CA
+         *            (forward); if <code>false</code>, from most-trusted CA to
+         *            target (reverse).
+         * @exception CertPathValidatorException
+         *                if this <code>PKIXCertPathChecker</code> is unable to
+         *                check certificates in the specified order; it should never
+         *                be thrown if the forward flag is false since reverse
+         *                checking must be supported
+         */
+        public abstract void Init(bool forward);
+        //throws CertPathValidatorException;
+
+        /**
+         * Indicates if forward checking is supported. Forward checking refers to
+         * the ability of the <code>PKIXCertPathChecker</code> to perform its
+         * checks when certificates are presented to the <code>check</code> method
+         * in the forward direction (from target to most-trusted CA).
+         * 
+         * @return <code>true</code> if forward checking is supported,
+         *         <code>false</code> otherwise
+         */
+        public abstract bool IsForwardCheckingSupported();
+
+        /**
+         * Returns an immutable <code>Set</code> of X.509 certificate extensions
+         * that this <code>PKIXCertPathChecker</code> supports (i.e. recognizes,
+         * is able to process), 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. The OID
+         * is represented by a set of nonnegative integers separated by periods.
+         * </p><p>
+         * All X.509 certificate extensions that a <code>PKIXCertPathChecker</code>
+         * might possibly be able to process should be included in the set.
+		 * </p>
+         * 
+         * @return an immutable <code>Set</code> of X.509 extension OIDs (in
+         *         <code>String</code> format) supported by this
+         *         <code>PKIXCertPathChecker</code>, or <code>null</code> if no
+         *         extensions are supported
+         */
+        public abstract ISet GetSupportedExtensions();
+
+        /**
+         * Performs the check(s) on the specified certificate using its internal
+         * state and removes any critical extensions that it processes from the
+         * specified collection of OID strings that represent the unresolved
+         * critical extensions. The certificates are presented in the order
+         * specified by the <code>init</code> method.
+         * 
+         * @param cert
+         *            the <code>Certificate</code> to be checked
+         * @param unresolvedCritExts
+         *            a <code>Collection</code> of OID strings representing the
+         *            current set of unresolved critical extensions
+         * @exception CertPathValidatorException
+         *                if the specified certificate does not pass the check
+         */
+        public abstract void Check(X509Certificate cert, ICollection unresolvedCritExts);
+        //throws CertPathValidatorException;
+
+        /**
+         * Returns a clone of this object. Calls the <code>Object.clone()</code>
+         * method. All subclasses which maintain state must support and override
+         * this method, if necessary.
+         * 
+         * @return a copy of this <code>PKIXCertPathChecker</code>
+         */
+        public virtual object Clone()
+        {
+			// TODO Check this
+			return base.MemberwiseClone();
+        }
+    }
+}
diff --git a/crypto/src/pkix/PkixCertPathValidator.cs b/crypto/src/pkix/PkixCertPathValidator.cs
new file mode 100644
index 000000000..7eb838886
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathValidator.cs
@@ -0,0 +1,420 @@
+using System;
+using System.Collections;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/**
+	 * The <i>Service Provider Interface</i> (<b>SPI</b>)
+	 * for the {@link CertPathValidator CertPathValidator} class. All
+	 * <code>CertPathValidator</code> implementations must include a class (the
+	 * SPI class) that extends this class (<code>CertPathValidatorSpi</code>)
+	 * and implements all of its methods. In general, instances of this class
+	 * should only be accessed through the <code>CertPathValidator</code> class.
+	 * For details, see the Java Cryptography Architecture.<br />
+	 * <br />
+	 * <b>Concurrent Access</b><br />
+	 * <br />
+	 * Instances of this class need not be protected against concurrent
+	 * access from multiple threads. Threads that need to access a single
+	 * <code>CertPathValidatorSpi</code> instance concurrently should synchronize
+	 * amongst themselves and provide the necessary locking before calling the
+	 * wrapping <code>CertPathValidator</code> object.<br />
+	 * <br />
+	 * However, implementations of <code>CertPathValidatorSpi</code> may still
+	 * encounter concurrency issues, since multiple threads each
+	 * manipulating a different <code>CertPathValidatorSpi</code> instance need not
+	 * synchronize.
+	 */
+	/// <summary>
+    /// CertPathValidatorSpi implementation for X.509 Certificate validation a la RFC
+    /// 3280.
+    /// </summary>
+    public class PkixCertPathValidator
+    {
+        public virtual PkixCertPathValidatorResult Validate(
+			PkixCertPath	certPath,
+			PkixParameters	paramsPkix)
+        {
+			if (paramsPkix.GetTrustAnchors() == null)
+            {
+                throw new ArgumentException(
+					"trustAnchors is null, this is not allowed for certification path validation.",
+					"parameters");
+            }
+
+            //
+            // 6.1.1 - inputs
+            //
+
+            //
+            // (a)
+            //
+            IList certs = certPath.Certificates;
+            int n = certs.Count;
+
+            if (certs.Count == 0)
+                throw new PkixCertPathValidatorException("Certification path is empty.", null, certPath, 0);
+
+			//
+            // (b)
+            //
+            // DateTime validDate = PkixCertPathValidatorUtilities.GetValidDate(paramsPkix);
+
+            //
+            // (c)
+            //
+            ISet userInitialPolicySet = paramsPkix.GetInitialPolicies();
+
+            //
+            // (d)
+            //
+            TrustAnchor trust;
+            try
+            {
+                trust = PkixCertPathValidatorUtilities.FindTrustAnchor(
+					(X509Certificate)certs[certs.Count - 1],
+					paramsPkix.GetTrustAnchors());
+            }
+            catch (Exception e)
+            {
+                throw new PkixCertPathValidatorException(e.Message, e, certPath, certs.Count - 1);
+            }
+
+            if (trust == null)
+                throw new PkixCertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+
+			//
+            // (e), (f), (g) are part of the paramsPkix object.
+            //
+            IEnumerator 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)
+            //
+            IList[] policyNodes = new IList[n + 1];
+            for (int j = 0; j < policyNodes.Length; j++)
+            {
+                policyNodes[j] = Platform.CreateArrayList();
+            }
+
+            ISet policySet = new HashSet();
+
+            policySet.Add(Rfc3280CertPathUtilities.ANY_POLICY);
+
+            PkixPolicyNode validPolicyTree = new PkixPolicyNode(Platform.CreateArrayList(), 0, policySet, null, new HashSet(),
+                    Rfc3280CertPathUtilities.ANY_POLICY, false);
+
+            policyNodes[0].Add(validPolicyTree);
+
+            //
+            // (b) and (c)
+            //
+            PkixNameConstraintValidator nameConstraintValidator = new PkixNameConstraintValidator();
+
+            // (d)
+            //
+            int explicitPolicy;
+            ISet 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)
+            //
+            AsymmetricKeyParameter workingPublicKey;
+            X509Name workingIssuerName;
+
+            X509Certificate sign = trust.TrustedCert;
+            try
+            {
+                if (sign != null)
+                {
+                    workingIssuerName = sign.SubjectDN;
+                    workingPublicKey = sign.GetPublicKey();
+                }
+                else
+                {
+                    workingIssuerName = new X509Name(trust.CAName);
+                    workingPublicKey = trust.CAPublicKey;
+                }
+            }
+            catch (ArgumentException ex)
+            {
+                throw new PkixCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+                        -1);
+            }
+
+            AlgorithmIdentifier workingAlgId = null;
+            try
+            {
+                workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
+            }
+            catch (PkixCertPathValidatorException e)
+            {
+                throw new PkixCertPathValidatorException(
+                        "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+            }
+
+//			DerObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.ObjectID;
+//			Asn1Encodable workingPublicKeyParameters = workingAlgId.Parameters;
+
+            //
+            // (k)
+            //
+            int maxPathLength = n;
+
+            //
+            // 6.1.3
+            //
+
+			X509CertStoreSelector certConstraints = paramsPkix.GetTargetCertConstraints();
+            if (certConstraints != null && !certConstraints.Match((X509Certificate)certs[0]))
+            {
+                throw new PkixCertPathValidatorException(
+					"Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+            }
+
+            //
+            // initialize CertPathChecker's
+            //
+            IList pathCheckers = paramsPkix.GetCertPathCheckers();
+            certIter = pathCheckers.GetEnumerator();
+
+            while (certIter.MoveNext())
+            {
+                ((PkixCertPathChecker)certIter.Current).Init(false);
+            }
+
+            X509Certificate cert = null;
+
+            for (index = certs.Count - 1; index >= 0; index--)
+            {
+                // 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[index];
+
+                //
+                // 6.1.3
+                //
+
+                Rfc3280CertPathUtilities.ProcessCertA(certPath, paramsPkix, index, workingPublicKey,
+					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.Version == 1)
+                    {
+                        throw new PkixCertPathValidatorException(
+							"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);
+
+					ISet criticalExtensions1 = cert.GetCriticalExtensionOids();
+
+					if (criticalExtensions1 != null)
+					{
+						criticalExtensions1 = new HashSet(criticalExtensions1);
+
+						// these extensions are handled by the algorithm
+						criticalExtensions1.Remove(X509Extensions.KeyUsage.Id);
+						criticalExtensions1.Remove(X509Extensions.CertificatePolicies.Id);
+						criticalExtensions1.Remove(X509Extensions.PolicyMappings.Id);
+						criticalExtensions1.Remove(X509Extensions.InhibitAnyPolicy.Id);
+						criticalExtensions1.Remove(X509Extensions.IssuingDistributionPoint.Id);
+						criticalExtensions1.Remove(X509Extensions.DeltaCrlIndicator.Id);
+						criticalExtensions1.Remove(X509Extensions.PolicyConstraints.Id);
+						criticalExtensions1.Remove(X509Extensions.BasicConstraints.Id);
+						criticalExtensions1.Remove(X509Extensions.SubjectAlternativeName.Id);
+						criticalExtensions1.Remove(X509Extensions.NameConstraints.Id);
+					}
+					else
+					{
+						criticalExtensions1 = new HashSet();
+					}
+
+					// (o)
+					Rfc3280CertPathUtilities.PrepareNextCertO(certPath, index, criticalExtensions1, pathCheckers);
+
+					// set signing certificate for next round
+                    sign = cert;
+
+                    // (c)
+                    workingIssuerName = sign.SubjectDN;
+
+                    // (d)
+                    try
+                    {
+                        workingPublicKey = PkixCertPathValidatorUtilities.GetNextWorkingKey(certPath.Certificates, index);
+                    }
+                    catch (PkixCertPathValidatorException e)
+                    {
+                        throw new PkixCertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+                    }
+
+                    workingAlgId = PkixCertPathValidatorUtilities.GetAlgorithmIdentifier(workingPublicKey);
+                    // (f)
+//                    workingPublicKeyAlgorithm = workingAlgId.ObjectID;
+                    // (e)
+//                    workingPublicKeyParameters = workingAlgId.Parameters;
+                }
+            }
+
+            //
+            // 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)
+            //
+            ISet criticalExtensions = cert.GetCriticalExtensionOids();
+
+            if (criticalExtensions != null)
+            {
+                criticalExtensions = new HashSet(criticalExtensions);
+
+                // Requires .Id
+                // these extensions are handled by the algorithm
+                criticalExtensions.Remove(X509Extensions.KeyUsage.Id);
+                criticalExtensions.Remove(X509Extensions.CertificatePolicies.Id);
+                criticalExtensions.Remove(X509Extensions.PolicyMappings.Id);
+                criticalExtensions.Remove(X509Extensions.InhibitAnyPolicy.Id);
+                criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+                criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+                criticalExtensions.Remove(X509Extensions.PolicyConstraints.Id);
+                criticalExtensions.Remove(X509Extensions.BasicConstraints.Id);
+                criticalExtensions.Remove(X509Extensions.SubjectAlternativeName.Id);
+                criticalExtensions.Remove(X509Extensions.NameConstraints.Id);
+                criticalExtensions.Remove(X509Extensions.CrlDistributionPoints.Id);
+            }
+            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 PkixCertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+        }
+    }
+}
diff --git a/crypto/src/pkix/PkixCertPathValidatorException.cs b/crypto/src/pkix/PkixCertPathValidatorException.cs
index 504a3c646..35522c6f8 100644
--- a/crypto/src/pkix/PkixCertPathValidatorException.cs
+++ b/crypto/src/pkix/PkixCertPathValidatorException.cs
@@ -27,8 +27,11 @@ namespace Org.BouncyCastle.Pkix
 	 *
 	 * @see CertPathValidator
 	 **/
-
-	public class PkixCertPathValidatorException : GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PkixCertPathValidatorException
+        : GeneralSecurityException
 	{
 		private Exception cause;
 		private PkixCertPath certPath;
diff --git a/crypto/src/pkix/PkixCertPathValidatorResult.cs b/crypto/src/pkix/PkixCertPathValidatorResult.cs
new file mode 100644
index 000000000..c7d81c7f5
--- /dev/null
+++ b/crypto/src/pkix/PkixCertPathValidatorResult.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// Summary description for PkixCertPathValidatorResult.
+	/// </summary>
+	public class PkixCertPathValidatorResult
+		//: ICertPathValidatorResult
+	{
+		private TrustAnchor trustAnchor;
+		private PkixPolicyNode policyTree;
+		private AsymmetricKeyParameter subjectPublicKey;
+
+		public PkixPolicyNode PolicyTree
+		{
+			get { return this.policyTree; }
+		}
+
+		public TrustAnchor TrustAnchor
+		{
+			get { return this.trustAnchor; }
+		}
+
+		public AsymmetricKeyParameter SubjectPublicKey
+		{
+			get { return this.subjectPublicKey; }
+		}
+
+		public PkixCertPathValidatorResult(
+			TrustAnchor				trustAnchor,
+			PkixPolicyNode			policyTree,
+			AsymmetricKeyParameter	subjectPublicKey)
+		{
+			if (subjectPublicKey == null)
+			{
+				throw new NullReferenceException("subjectPublicKey must be non-null");
+			}
+			if (trustAnchor == null)
+			{
+				throw new NullReferenceException("trustAnchor must be non-null");
+			}
+			
+			this.trustAnchor = trustAnchor;
+			this.policyTree = policyTree;
+			this.subjectPublicKey = subjectPublicKey;
+		}
+
+		public object Clone()
+		{
+			return new PkixCertPathValidatorResult(this.TrustAnchor, this.PolicyTree, this.SubjectPublicKey);
+		}
+
+		public override String ToString() 
+		{
+			StringBuilder sB = new StringBuilder();
+			sB.Append("PKIXCertPathValidatorResult: [ \n");
+			sB.Append("  Trust Anchor: ").Append(this.TrustAnchor).Append('\n');
+			sB.Append("  Policy Tree: ").Append(this.PolicyTree).Append('\n');
+			sB.Append("  Subject Public Key: ").Append(this.SubjectPublicKey).Append("\n]");
+			return sB.ToString();
+		}
+
+	}
+}
diff --git a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
index 305b2de35..acea77856 100644
--- a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
+++ b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
@@ -528,7 +528,7 @@ namespace Org.BouncyCastle.Pkix
 					}
 					catch (Exception e)
 					{
-						new Exception(
+						throw new Exception(
 							"Reason code CRL entry extension could not be decoded.",
 							e);
 					}
@@ -683,8 +683,8 @@ namespace Org.BouncyCastle.Pkix
 		/// the certificates</param>
 		/// <param name="certStores">a List containing only X509Store objects. These
 		/// are used to search for certificates.</param>
-		/// <returns>a Collection of all found <see cref="X509Certificate "/> or
-		/// org.bouncycastle.x509.X509AttributeCertificate objects.
+		/// <returns>a Collection of all found <see cref="X509Certificate"/> or
+		/// <see cref="Org.BouncyCastle.X509.IX509AttributeCertificate"/> objects.
 		/// May be empty but never <code>null</code>.</returns>
 		/// <exception cref="Exception"></exception>
 		internal static ICollection FindCertificates(
@@ -864,7 +864,7 @@ namespace Org.BouncyCastle.Pkix
 			}
 			catch (Exception e)
 			{
-				new Exception("Could not get issuer information from distribution point.", e);
+				throw new Exception("Could not get issuer information from distribution point.", e);
 			}
 
 			if (cert is X509Certificate)
@@ -924,7 +924,7 @@ namespace Org.BouncyCastle.Pkix
 			}
 			catch (IOException e)
 			{
-				new Exception("Cannot extract issuer from CRL.", e);
+				throw new Exception("Cannot extract issuer from CRL.", e);
 			}
 
 			BigInteger completeCRLNumber = null;
diff --git a/crypto/src/pkix/PkixCrlUtilities.cs b/crypto/src/pkix/PkixCrlUtilities.cs
new file mode 100644
index 000000000..c386b8a05
--- /dev/null
+++ b/crypto/src/pkix/PkixCrlUtilities.cs
@@ -0,0 +1,114 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	public class PkixCrlUtilities
+	{
+		public virtual ISet FindCrls(X509CrlStoreSelector crlselect, PkixParameters paramsPkix, DateTime currentDate)
+		{
+			ISet initialSet = new HashSet();
+
+			// get complete CRL(s)
+			try
+			{
+				initialSet.AddAll(FindCrls(crlselect, paramsPkix.GetAdditionalStores()));
+				initialSet.AddAll(FindCrls(crlselect, paramsPkix.GetStores()));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("Exception obtaining complete CRLs.", e);
+			}
+
+			ISet finalSet = new HashSet();
+			DateTime validityDate = currentDate;
+
+			if (paramsPkix.Date != null)
+			{
+				validityDate = paramsPkix.Date.Value;
+			}
+
+			// based on RFC 5280 6.3.3
+			foreach (X509Crl crl in initialSet)
+			{
+				if (crl.NextUpdate.Value.CompareTo(validityDate) > 0)
+				{
+					X509Certificate cert = crlselect.CertificateChecking;
+
+					if (cert != null)
+					{
+						if (crl.ThisUpdate.CompareTo(cert.NotAfter) < 0)
+						{
+							finalSet.Add(crl);
+						}
+					}
+					else
+					{
+						finalSet.Add(crl);
+					}
+				}
+			}
+
+			return finalSet;
+		}
+
+		public virtual ISet FindCrls(X509CrlStoreSelector crlselect, PkixParameters paramsPkix)
+		{
+			ISet completeSet = new HashSet();
+
+			// get complete CRL(s)
+			try
+			{
+				completeSet.AddAll(FindCrls(crlselect, paramsPkix.GetStores()));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("Exception obtaining complete CRLs.", e);
+			}
+
+			return completeSet;
+		}
+
+		/// <summary>
+		/// crl checking
+		/// Return a Collection of all CRLs found in the X509Store's that are
+		/// matching the crlSelect criteriums.
+		/// </summary>
+		/// <param name="crlSelect">a {@link X509CRLStoreSelector} object that will be used
+		/// to select the CRLs</param>
+		/// <param name="crlStores">a List containing only {@link org.bouncycastle.x509.X509Store
+		/// X509Store} objects. These are used to search for CRLs</param>
+		/// <returns>a Collection of all found {@link X509CRL X509CRL} objects. May be
+		/// empty but never <code>null</code>.
+		/// </returns>
+		private ICollection FindCrls(X509CrlStoreSelector crlSelect, IList crlStores)
+		{
+			ISet crls = new HashSet();
+
+			Exception lastException = null;
+			bool foundValidStore = false;
+
+			foreach (IX509Store store in crlStores)
+			{
+				try
+				{
+					crls.AddAll(store.GetMatches(crlSelect));
+					foundValidStore = true;
+				}
+				catch (X509StoreException e)
+				{
+					lastException = new Exception("Exception searching in X.509 CRL store.", e);
+				}
+			}
+
+	        if (!foundValidStore && lastException != null)
+	            throw lastException;
+
+			return crls;
+		}
+	}
+}
diff --git a/crypto/src/pkix/PkixNameConstraintValidator.cs b/crypto/src/pkix/PkixNameConstraintValidator.cs
new file mode 100644
index 000000000..535f95174
--- /dev/null
+++ b/crypto/src/pkix/PkixNameConstraintValidator.cs
@@ -0,0 +1,1937 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+    public class PkixNameConstraintValidator
+    {
+        private ISet excludedSubtreesDN = new HashSet();
+
+        private ISet excludedSubtreesDNS = new HashSet();
+
+        private ISet excludedSubtreesEmail = new HashSet();
+
+        private ISet excludedSubtreesURI = new HashSet();
+
+        private ISet excludedSubtreesIP = new HashSet();
+
+        private ISet permittedSubtreesDN;
+
+        private ISet permittedSubtreesDNS;
+
+        private ISet permittedSubtreesEmail;
+
+        private ISet permittedSubtreesURI;
+
+        private ISet permittedSubtreesIP;
+
+        public PkixNameConstraintValidator()
+        {
+        }
+
+        private static bool WithinDNSubtree(
+            Asn1Sequence dns,
+            Asn1Sequence subtree)
+        {
+            if (subtree.Count < 1)
+            {
+                return false;
+            }
+
+            if (subtree.Count > dns.Count)
+            {
+                return false;
+            }
+
+            for (int j = subtree.Count - 1; j >= 0; j--)
+            {
+                if (!(subtree[j].Equals(dns[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(ISet permitted, Asn1Sequence dns)
+        //throws PkixNameConstraintValidatorException
+        {
+            if (permitted == null)
+            {
+                return;
+            }
+
+            if ((permitted.Count == 0) && dns.Count == 0)
+            {
+                return;
+            }
+
+            IEnumerator it = permitted.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+                if (WithinDNSubtree(dns, subtree))
+                {
+                    return;
+                }
+            }
+
+            throw new PkixNameConstraintValidatorException(
+                "Subject distinguished name is not from a permitted subtree");
+        }
+
+        private void CheckExcludedDN(ISet excluded, Asn1Sequence dns)
+        //throws PkixNameConstraintValidatorException
+        {
+            if (excluded.IsEmpty)
+            {
+                return;
+            }
+
+            IEnumerator it = excluded.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+                if (WithinDNSubtree(dns, subtree))
+                {
+                    throw new PkixNameConstraintValidatorException(
+                        "Subject distinguished name is from an excluded subtree");
+                }
+            }
+        }
+
+        private ISet IntersectDN(ISet permitted, ISet dns)
+        {
+            ISet intersect = new HashSet();
+            for (IEnumerator it = dns.GetEnumerator(); it.MoveNext(); )
+            {
+                Asn1Sequence dn = Asn1Sequence.GetInstance(((GeneralSubtree)it
+                    .Current).Base.Name.ToAsn1Object());
+                if (permitted == null)
+                {
+                    if (dn != null)
+                    {
+                        intersect.Add(dn);
+                    }
+                }
+                else
+                {
+                    IEnumerator _iter = permitted.GetEnumerator();
+                    while (_iter.MoveNext())
+                    {
+                        Asn1Sequence subtree = (Asn1Sequence)_iter.Current;
+
+                        if (WithinDNSubtree(dn, subtree))
+                        {
+                            intersect.Add(dn);
+                        }
+                        else if (WithinDNSubtree(subtree, dn))
+                        {
+                            intersect.Add(subtree);
+                        }
+                    }
+                }
+            }
+            return intersect;
+        }
+
+        private ISet UnionDN(ISet excluded, Asn1Sequence dn)
+        {
+            if (excluded.IsEmpty)
+            {
+                if (dn == null)
+                {
+                    return excluded;
+                }
+                excluded.Add(dn);
+
+                return excluded;
+            }
+            else
+            {
+                ISet intersect = new HashSet();
+
+                IEnumerator it = excluded.GetEnumerator();
+                while (it.MoveNext())
+                {
+                    Asn1Sequence subtree = (Asn1Sequence)it.Current;
+
+                    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 ISet IntersectEmail(ISet permitted, ISet emails)
+        {
+            ISet intersect = new HashSet();
+            for (IEnumerator it = emails.GetEnumerator(); it.MoveNext(); )
+            {
+                String email = ExtractNameAsString(((GeneralSubtree)it.Current)
+                    .Base);
+
+                if (permitted == null)
+                {
+                    if (email != null)
+                    {
+                        intersect.Add(email);
+                    }
+                }
+                else
+                {
+                    IEnumerator it2 = permitted.GetEnumerator();
+                    while (it2.MoveNext())
+                    {
+                        String _permitted = (String)it2.Current;
+
+                        intersectEmail(email, _permitted, intersect);
+                    }
+                }
+            }
+            return intersect;
+        }
+
+        private ISet UnionEmail(ISet excluded, String email)
+        {
+            if (excluded.IsEmpty)
+            {
+                if (email == null)
+                {
+                    return excluded;
+                }
+                excluded.Add(email);
+                return excluded;
+            }
+            else
+            {
+                ISet union = new HashSet();
+
+                IEnumerator it = excluded.GetEnumerator();
+                while (it.MoveNext())
+                {
+                    String _excluded = (String)it.Current;
+
+                    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 ISet IntersectIP(ISet permitted, ISet ips)
+        {
+            ISet intersect = new HashSet();
+            for (IEnumerator it = ips.GetEnumerator(); it.MoveNext(); )
+            {
+                byte[] ip = Asn1OctetString.GetInstance(
+                    ((GeneralSubtree)it.Current).Base.Name).GetOctets();
+                if (permitted == null)
+                {
+                    if (ip != null)
+                    {
+                        intersect.Add(ip);
+                    }
+                }
+                else
+                {
+                    IEnumerator it2 = permitted.GetEnumerator();
+                    while (it2.MoveNext())
+                    {
+                        byte[] _permitted = (byte[])it2.Current;
+                        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 ISet UnionIP(ISet excluded, byte[] ip)
+        {
+            if (excluded.IsEmpty)
+            {
+                if (ip == null)
+                {
+                    return excluded;
+                }
+                excluded.Add(ip);
+
+                return excluded;
+            }
+            else
+            {
+                ISet union = new HashSet();
+
+                IEnumerator it = excluded.GetEnumerator();
+                while (it.MoveNext())
+                {
+                    byte[] _excluded = (byte[])it.Current;
+                    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 ISet UnionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+        {
+            ISet set = new HashSet();
+
+            // difficult, adding always all IPs is not wrong
+            if (Org.BouncyCastle.Utilities.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 ISet IntersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+    {
+        if (ipWithSubmask1.Length != ipWithSubmask2.Length)
+        {
+            //Collections.EMPTY_SET;
+            return new HashSet();
+        }
+
+        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;
+            return new HashSet();
+        }
+        // OR keeps all significant bits
+        byte[] ip = Or(minMax[0], minMax[2]);
+        byte[] subnetmask = Or(subnetmask1, subnetmask2);
+
+            //return new HashSet( ICollectionsingleton(IpWithSubnetMask(ip, subnetmask));
+        ISet hs = new HashSet();
+        hs.Add(IpWithSubnetMask(ip, subnetmask));
+
+            return hs;
+    }
+
+        /**
+         * 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];
+            Array.Copy(ip, 0, temp, 0, ipLength);
+            Array.Copy(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];
+        Array.Copy(ipWithSubmask1, 0, ip1, 0, ipLength);
+        Array.Copy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
+
+        byte[] ip2 = new byte[ipLength];
+        byte[] subnetmask2 = new byte[ipLength];
+        Array.Copy(ipWithSubmask2, 0, ip2, 0, ipLength);
+        Array.Copy(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(ISet permitted, String email)
+        //throws PkixNameConstraintValidatorException
+        {
+            if (permitted == null)
+            {
+                return;
+            }
+
+            IEnumerator it = permitted.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                String str = ((String)it.Current);
+
+                if (EmailIsConstrained(email, str))
+                {
+                    return;
+                }
+            }
+
+            if (email.Length == 0 && permitted.Count == 0)
+            {
+                return;
+            }
+
+            throw new PkixNameConstraintValidatorException(
+                "Subject email address is not from a permitted subtree.");
+        }
+
+        private void CheckExcludedEmail(ISet excluded, String email)
+        //throws PkixNameConstraintValidatorException
+        {
+            if (excluded.IsEmpty)
+            {
+                return;
+            }
+
+            IEnumerator it = excluded.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                String str = (String)it.Current;
+
+                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 ISet
+         * <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(ISet permitted, byte[] ip)
+        //throws PkixNameConstraintValidatorException
+        {
+            if (permitted == null)
+            {
+                return;
+            }
+
+            IEnumerator it = permitted.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                byte[] ipWithSubnet = (byte[])it.Current;
+
+                if (IsIPConstrained(ip, ipWithSubnet))
+                {
+                    return;
+                }
+            }
+            if (ip.Length == 0 && permitted.Count == 0)
+            {
+                return;
+            }
+            throw new PkixNameConstraintValidatorException(
+                "IP is not from a permitted subtree.");
+        }
+
+        /**
+         * Checks if the IP <code>ip</code> is included in the excluded ISet
+         * <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(ISet excluded, byte[] ip)
+        //throws PkixNameConstraintValidatorException
+        {
+            if (excluded.IsEmpty)
+            {
+                return;
+            }
+
+            IEnumerator it = excluded.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                byte[] ipWithSubnet = (byte[])it.Current;
+
+                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 bool IsIPConstrained(byte[] ip, byte[] constraint)
+        {
+            int ipLength = ip.Length;
+
+            if (ipLength != (constraint.Length / 2))
+            {
+                return false;
+            }
+
+            byte[] subnetMask = new byte[ipLength];
+            Array.Copy(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 Org.BouncyCastle.Utilities.Arrays.AreEqual(permittedSubnetAddress, ipSubnetAddress);
+        }
+
+        private bool EmailIsConstrained(String email, String constraint)
+        {
+            String sub = email.Substring(email.IndexOf('@') + 1);
+            // a particular mailbox
+            if (constraint.IndexOf('@') != -1)
+            {
+                if (email.ToUpper().Equals(constraint.ToUpper()))
+                {
+                    return true;
+                }
+            }
+            // on particular host
+            else if (!(constraint[0].Equals('.')))
+            {
+                if (sub.ToUpper().Equals(constraint.ToUpper()))
+                {
+                    return true;
+                }
+            }
+            // address in sub domain
+            else if (WithinDomain(sub, constraint))
+            {
+                return true;
+            }
+            return false;
+        }
+
+        private bool WithinDomain(String testDomain, String domain)
+        {
+            String tempDomain = domain;
+            if (tempDomain.StartsWith("."))
+            {
+                tempDomain = tempDomain.Substring(1);
+            }
+            String[] domainParts = tempDomain.Split('.'); // Strings.split(tempDomain, '.');
+            String[] testDomainParts = testDomain.Split('.'); // 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 (!(Platform.CompareIgnoreCase(testDomainParts[i + d], domainParts[i]) == 0))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private void CheckPermittedDNS(ISet permitted, String dns)
+        //throws PkixNameConstraintValidatorException
+        {
+            if (permitted == null)
+            {
+                return;
+            }
+
+            IEnumerator it = permitted.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                String str = ((String)it.Current);
+
+                // is sub domain
+                if (WithinDomain(dns, str) || dns.ToUpper().Equals(str.ToUpper()))
+                {
+                    return;
+                }
+            }
+            if (dns.Length == 0 && permitted.Count == 0)
+            {
+                return;
+            }
+            throw new PkixNameConstraintValidatorException(
+                "DNS is not from a permitted subtree.");
+        }
+
+        private void checkExcludedDNS(ISet excluded, String dns)
+        //     throws PkixNameConstraintValidatorException
+        {
+            if (excluded.IsEmpty)
+            {
+                return;
+            }
+
+            IEnumerator it = excluded.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                String str = ((String)it.Current);
+
+                // is sub domain or the same
+				if (WithinDomain(dns, str) || (Platform.CompareIgnoreCase(dns, str) == 0))
+                {
+                    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, ISet 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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email2) == 0)
+                    {
+                        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) || Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email1) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        union.Add(email1);
+                    }
+                    else
+                    {
+                        union.Add(email1);
+                        union.Add(email2);
+                    }
+                }
+            }
+        }
+
+        private void unionURI(String email1, String email2, ISet 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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email2) == 0)
+                    {
+                        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) || Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email1) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        union.Add(email1);
+                    }
+                    else
+                    {
+                        union.Add(email1);
+                        union.Add(email2);
+                    }
+                }
+            }
+        }
+
+        private ISet intersectDNS(ISet permitted, ISet dnss)
+        {
+            ISet intersect = new HashSet();
+            for (IEnumerator it = dnss.GetEnumerator(); it.MoveNext(); )
+            {
+                String dns = ExtractNameAsString(((GeneralSubtree)it.Current)
+                    .Base);
+                if (permitted == null)
+                {
+                    if (dns != null)
+                    {
+                        intersect.Add(dns);
+                    }
+                }
+                else
+                {
+                    IEnumerator _iter = permitted.GetEnumerator();
+                    while (_iter.MoveNext())
+                    {
+                        String _permitted = (String)_iter.Current;
+
+                        if (WithinDomain(_permitted, dns))
+                        {
+                            intersect.Add(_permitted);
+                        }
+                        else if (WithinDomain(dns, _permitted))
+                        {
+                            intersect.Add(dns);
+                        }
+                    }
+                }
+            }
+
+            return intersect;
+        }
+
+        protected ISet unionDNS(ISet excluded, String dns)
+        {
+            if (excluded.IsEmpty)
+            {
+                if (dns == null)
+                {
+                    return excluded;
+                }
+                excluded.Add(dns);
+
+                return excluded;
+            }
+            else
+            {
+                ISet union = new HashSet();
+
+                IEnumerator _iter = excluded.GetEnumerator();
+                while (_iter.MoveNext())
+                {
+                    String _permitted = (String)_iter.Current;
+
+                    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, ISet 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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email2) == 0)
+                    {
+                        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) || (Platform.CompareIgnoreCase(email1, email2) == 0))
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email1) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        intersect.Add(email1);
+                    }
+                }
+            }
+        }
+
+        private void checkExcludedURI(ISet excluded, String uri)
+        //       throws PkixNameConstraintValidatorException
+        {
+            if (excluded.IsEmpty)
+            {
+                return;
+            }
+
+            IEnumerator it = excluded.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                String str = ((String)it.Current);
+
+                if (IsUriConstrained(uri, str))
+                {
+                    throw new PkixNameConstraintValidatorException(
+                        "URI is from an excluded subtree.");
+                }
+            }
+        }
+
+        private ISet intersectURI(ISet permitted, ISet uris)
+        {
+            ISet intersect = new HashSet();
+            for (IEnumerator it = uris.GetEnumerator(); it.MoveNext(); )
+            {
+                String uri = ExtractNameAsString(((GeneralSubtree)it.Current)
+                    .Base);
+                if (permitted == null)
+                {
+                    if (uri != null)
+                    {
+                        intersect.Add(uri);
+                    }
+                }
+                else
+                {
+                    IEnumerator _iter = permitted.GetEnumerator();
+                    while (_iter.MoveNext())
+                    {
+                        String _permitted = (String)_iter.Current;
+                        intersectURI(_permitted, uri, intersect);
+                    }
+                }
+            }
+            return intersect;
+        }
+
+        private ISet unionURI(ISet excluded, String uri)
+        {
+            if (excluded.IsEmpty)
+            {
+                if (uri == null)
+                {
+                    return excluded;
+                }
+                excluded.Add(uri);
+
+                return excluded;
+            }
+            else
+            {
+                ISet union = new HashSet();
+
+                IEnumerator _iter = excluded.GetEnumerator();
+                while (_iter.MoveNext())
+                {
+                    String _excluded = (String)_iter.Current;
+
+                    unionURI(_excluded, uri, union);
+                }
+
+                return union;
+            }
+        }
+
+        private void intersectURI(String email1, String email2, ISet 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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email2) == 0)
+                    {
+                        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) || (Platform.CompareIgnoreCase(email1, email2) == 0))
+                    {
+                        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 (Platform.CompareIgnoreCase(_sub, email1) == 0)
+                    {
+                        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 (Platform.CompareIgnoreCase(email1, email2) == 0)
+                    {
+                        intersect.Add(email1);
+                    }
+                }
+            }
+        }
+
+        private void CheckPermittedURI(ISet permitted, String uri)
+        //        throws PkixNameConstraintValidatorException
+        {
+            if (permitted == null)
+            {
+                return;
+            }
+
+            IEnumerator it = permitted.GetEnumerator();
+
+            while (it.MoveNext())
+            {
+                String str = ((String)it.Current);
+
+                if (IsUriConstrained(uri, str))
+                {
+                    return;
+                }
+            }
+            if (uri.Length == 0 && permitted.Count == 0)
+            {
+                return;
+            }
+            throw new PkixNameConstraintValidatorException(
+                "URI is not from a permitted subtree.");
+        }
+
+        private bool IsUriConstrained(String uri, String constraint)
+        {
+            String host = ExtractHostFromURL(uri);
+            // a host
+            if (!constraint.StartsWith("."))
+            {
+                if (Platform.CompareIgnoreCase(host, constraint) == 0)
+                {
+                    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 ISet.
+         *
+         * @param name The GeneralName
+         * @throws PkixNameConstraintValidatorException
+         *          If the <code>name</code>
+         */
+        public void checkPermitted(GeneralName name)
+        //        throws PkixNameConstraintValidatorException
+        {
+            switch (name.TagNo)
+            {
+                case 1:
+                    CheckPermittedEmail(permittedSubtreesEmail,
+                        ExtractNameAsString(name));
+                    break;
+                case 2:
+                    CheckPermittedDNS(permittedSubtreesDNS, DerIA5String.GetInstance(
+                        name.Name).GetString());
+                    break;
+                case 4:
+                    CheckPermittedDN(Asn1Sequence.GetInstance(name.Name.ToAsn1Object()));
+                    break;
+                case 6:
+                    CheckPermittedURI(permittedSubtreesURI, DerIA5String.GetInstance(
+                        name.Name).GetString());
+                    break;
+                case 7:
+                    byte[] ip = Asn1OctetString.GetInstance(name.Name).GetOctets();
+
+                    CheckPermittedIP(permittedSubtreesIP, ip);
+                    break;
+            }
+        }
+
+        /**
+         * Check if the given GeneralName is contained in the excluded ISet.
+         *
+         * @param name The GeneralName.
+         * @throws PkixNameConstraintValidatorException
+         *          If the <code>name</code> is
+         *          excluded.
+         */
+        public void checkExcluded(GeneralName name)
+        //        throws PkixNameConstraintValidatorException
+        {
+            switch (name.TagNo)
+            {
+                case 1:
+                    CheckExcludedEmail(excludedSubtreesEmail, ExtractNameAsString(name));
+                    break;
+                case 2:
+                    checkExcludedDNS(excludedSubtreesDNS, DerIA5String.GetInstance(
+                        name.Name).GetString());
+                    break;
+                case 4:
+                    CheckExcludedDN(Asn1Sequence.GetInstance(name.Name.ToAsn1Object()));
+                    break;
+                case 6:
+                    checkExcludedURI(excludedSubtreesURI, DerIA5String.GetInstance(
+                        name.Name).GetString());
+                    break;
+                case 7:
+                    byte[] ip = Asn1OctetString.GetInstance(name.Name).GetOctets();
+
+                    checkExcludedIP(excludedSubtreesIP, ip);
+                    break;
+            }
+        }
+
+        /**
+         * Updates the permitted ISet of these name constraints with the intersection
+         * with the given subtree.
+         *
+         * @param permitted The permitted subtrees
+         */
+
+        public void IntersectPermittedSubtree(Asn1Sequence permitted)
+        {
+            IDictionary subtreesMap = Platform.CreateHashtable();
+
+            // group in ISets in a map ordered by tag no.
+            for (IEnumerator e = permitted.GetEnumerator(); e.MoveNext(); )
+            {
+                GeneralSubtree subtree = GeneralSubtree.GetInstance(e.Current);
+
+                int tagNo = subtree.Base.TagNo;
+                if (subtreesMap[tagNo] == null)
+                {
+                    subtreesMap[tagNo] = new HashSet();
+                }
+
+                ((ISet)subtreesMap[tagNo]).Add(subtree);
+            }
+
+            for (IEnumerator it = subtreesMap.GetEnumerator(); it.MoveNext(); )
+            {
+                DictionaryEntry entry = (DictionaryEntry)it.Current;
+
+                // go through all subtree groups
+                switch ((int)entry.Key )
+                {
+                    case 1:
+                        permittedSubtreesEmail = IntersectEmail(permittedSubtreesEmail,
+                            (ISet)entry.Value);
+                        break;
+                    case 2:
+                        permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+                            (ISet)entry.Value);
+                        break;
+                    case 4:
+                        permittedSubtreesDN = IntersectDN(permittedSubtreesDN,
+                            (ISet)entry.Value);
+                        break;
+                    case 6:
+                        permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+                            (ISet)entry.Value);
+                        break;
+                    case 7:
+                        permittedSubtreesIP = IntersectIP(permittedSubtreesIP,
+                            (ISet)entry.Value);
+                        break;
+                }
+            }
+        }
+
+        private String ExtractNameAsString(GeneralName name)
+        {
+            return DerIA5String.GetInstance(name.Name).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();
+                    break;
+            }
+        }
+
+        /**
+         * Adds a subtree to the excluded ISet of these name constraints.
+         *
+         * @param subtree A subtree with an excluded GeneralName.
+         */
+        public void AddExcludedSubtree(GeneralSubtree subtree)
+        {
+            GeneralName subTreeBase = subtree.Base;
+
+            switch (subTreeBase.TagNo)
+            {
+                case 1:
+                    excludedSubtreesEmail = UnionEmail(excludedSubtreesEmail,
+                        ExtractNameAsString(subTreeBase));
+                    break;
+                case 2:
+                    excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+                        ExtractNameAsString(subTreeBase));
+                    break;
+                case 4:
+                    excludedSubtreesDN = UnionDN(excludedSubtreesDN,
+                        (Asn1Sequence)subTreeBase.Name.ToAsn1Object());
+                    break;
+                case 6:
+                    excludedSubtreesURI = unionURI(excludedSubtreesURI,
+                        ExtractNameAsString(subTreeBase));
+                    break;
+                case 7:
+                    excludedSubtreesIP = UnionIP(excludedSubtreesIP, Asn1OctetString
+                        .GetInstance(subTreeBase.Name).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 (Org.BouncyCastle.Utilities.Arrays.AreEqual(ip1, ip2))
+            {
+                return 0;
+            }
+            if (Org.BouncyCastle.Utilities.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;
+        }
+
+		[Obsolete("Use GetHashCode instead")]
+		public int HashCode()
+		{
+			return GetHashCode();
+		}
+
+		public override int GetHashCode()
+        {
+            return HashCollection(excludedSubtreesDN)
+                + HashCollection(excludedSubtreesDNS)
+                + HashCollection(excludedSubtreesEmail)
+                + HashCollection(excludedSubtreesIP)
+                + HashCollection(excludedSubtreesURI)
+                + HashCollection(permittedSubtreesDN)
+                + HashCollection(permittedSubtreesDNS)
+                + HashCollection(permittedSubtreesEmail)
+                + HashCollection(permittedSubtreesIP)
+                + HashCollection(permittedSubtreesURI);
+        }
+
+        private int HashCollection(ICollection coll)
+        {
+            if (coll == null)
+            {
+                return 0;
+            }
+            int hash = 0;
+            IEnumerator it1 = coll.GetEnumerator();
+            while (it1.MoveNext())
+            {
+                Object o = it1.Current;
+                if (o is byte[])
+                {
+                    hash += Org.BouncyCastle.Utilities.Arrays.GetHashCode((byte[])o);
+                }
+                else
+                {
+                    hash += o.GetHashCode();
+                }
+            }
+            return hash;
+        }
+
+		public override bool Equals(Object o)
+		{
+			if (!(o is 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 bool CollectionsAreEqual(ICollection coll1, ICollection coll2)
+        {
+            if (coll1 == coll2)
+            {
+                return true;
+            }
+            if (coll1 == null || coll2 == null)
+            {
+                return false;
+            }
+            if (coll1.Count != coll2.Count)
+            {
+                return false;
+            }
+            IEnumerator it1 = coll1.GetEnumerator();
+
+            while (it1.MoveNext())
+            {
+                Object a = it1.Current;
+                IEnumerator it2 = coll2.GetEnumerator();
+                bool found = false;
+                while (it2.MoveNext())
+                {
+                    Object b = it2.Current;
+                    if (SpecialEquals(a, b))
+                    {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found)
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private bool SpecialEquals(Object o1, Object o2)
+        {
+            if (o1 == o2)
+            {
+                return true;
+            }
+            if (o1 == null || o2 == null)
+            {
+                return false;
+            }
+            if ((o1 is byte[]) && (o2 is byte[]))
+            {
+                return Org.BouncyCastle.Utilities.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 += (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 += (ip[i] & 0x00FF) + ".";
+            }
+            temp = temp.Substring(0, temp.Length - 1);
+            return temp;
+        }
+
+        private String StringifyIPCollection(ISet ips)
+        {
+            String temp = "";
+            temp += "[";
+            for (IEnumerator it = ips.GetEnumerator(); it.MoveNext(); )
+            {
+                temp += StringifyIP((byte[])it.Current) + ",";
+            }
+            if (temp.Length > 1)
+            {
+                temp = temp.Substring(0, temp.Length - 1);
+            }
+            temp += "]";
+
+            return temp;
+        }
+
+        public override 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/crypto/src/pkix/PkixNameConstraintValidatorException.cs b/crypto/src/pkix/PkixNameConstraintValidatorException.cs
index 9f01e8765..432d7bd6b 100644
--- a/crypto/src/pkix/PkixNameConstraintValidatorException.cs
+++ b/crypto/src/pkix/PkixNameConstraintValidatorException.cs
@@ -2,7 +2,11 @@ using System;
 
 namespace Org.BouncyCastle.Pkix
 {
-    public class PkixNameConstraintValidatorException : Exception
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PkixNameConstraintValidatorException
+        : Exception
     {
         public PkixNameConstraintValidatorException(String msg)
             : base(msg)
diff --git a/crypto/src/pkix/PkixParameters.cs b/crypto/src/pkix/PkixParameters.cs
new file mode 100644
index 000000000..6df1b646f
--- /dev/null
+++ b/crypto/src/pkix/PkixParameters.cs
@@ -0,0 +1,893 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// Summary description for PkixParameters.
+	/// </summary>
+	public class PkixParameters
+//		: ICertPathParameters
+	{
+		/**
+		* 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 const int PkixValidityModel = 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 const int ChainValidityModel = 1;
+
+		private ISet trustAnchors;
+		private DateTimeObject date;
+		private IList certPathCheckers;
+		private bool revocationEnabled = true;
+		private ISet initialPolicies;
+		//private bool checkOnlyEECertificateCrl = false;
+		private bool explicitPolicyRequired = false;
+		private bool anyPolicyInhibited = false;
+		private bool policyMappingInhibited = false;
+		private bool policyQualifiersRejected = true;
+		private IX509Selector certSelector;
+		private IList stores;
+		private IX509Selector selector;
+		private bool additionalLocationsEnabled;
+		private IList additionalStores;
+		private ISet trustedACIssuers;
+		private ISet necessaryACAttributes;
+		private ISet prohibitedACAttributes;
+		private ISet attrCertCheckers;
+		private int validityModel = PkixValidityModel;
+		private bool useDeltas = false;
+
+		/**
+		 * Creates an instance of PKIXParameters with the specified Set of
+		 * most-trusted CAs. Each element of the set is a TrustAnchor.<br />
+		 * <br />
+		 * Note that the Set is copied to protect against subsequent modifications.
+		 *
+		 * @param trustAnchors
+		 *            a Set of TrustAnchors
+		 *
+		 * @exception InvalidAlgorithmParameterException
+		 *                if the specified Set is empty
+		 *                <code>(trustAnchors.isEmpty() == true)</code>
+		 * @exception NullPointerException
+		 *                if the specified Set is <code>null</code>
+		 * @exception ClassCastException
+		 *                if any of the elements in the Set are not of type
+		 *                <code>java.security.cert.TrustAnchor</code>
+		 */
+		public PkixParameters(
+			ISet trustAnchors)
+		{
+			SetTrustAnchors(trustAnchors);
+
+			this.initialPolicies = new HashSet();
+			this.certPathCheckers = Platform.CreateArrayList();
+            this.stores = Platform.CreateArrayList();
+			this.additionalStores = Platform.CreateArrayList();
+			this.trustedACIssuers = new HashSet();
+			this.necessaryACAttributes = new HashSet();
+			this.prohibitedACAttributes = new HashSet();
+			this.attrCertCheckers = new HashSet();
+		}
+
+//		// TODO implement for other keystores (see Java build)?
+//		/**
+//		 * Creates an instance of <code>PKIXParameters</code> that
+//		 * populates the set of most-trusted CAs from the trusted
+//		 * certificate entries contained in the specified <code>KeyStore</code>.
+//		 * Only keystore entries that contain trusted <code>X509Certificates</code>
+//		 * are considered; all other certificate types are ignored.
+//		 *
+//		 * @param keystore a <code>KeyStore</code> from which the set of
+//		 * most-trusted CAs will be populated
+//		 * @throws KeyStoreException if the keystore has not been initialized
+//		 * @throws InvalidAlgorithmParameterException if the keystore does
+//		 * not contain at least one trusted certificate entry
+//		 * @throws NullPointerException if the keystore is <code>null</code>
+//		 */
+//		public PkixParameters(
+//			Pkcs12Store keystore)
+////			throws KeyStoreException, InvalidAlgorithmParameterException
+//		{
+//			if (keystore == null)
+//				throw new ArgumentNullException("keystore");
+//			ISet trustAnchors = new HashSet();
+//			foreach (string alias in keystore.Aliases)
+//			{
+//				if (keystore.IsCertificateEntry(alias))
+//				{
+//					X509CertificateEntry x509Entry = keystore.GetCertificate(alias);
+//					trustAnchors.Add(new TrustAnchor(x509Entry.Certificate, null));
+//				}
+//			}
+//			SetTrustAnchors(trustAnchors);
+//
+//			this.initialPolicies = new HashSet();
+//			this.certPathCheckers = new ArrayList();
+//			this.stores = new ArrayList();
+//			this.additionalStores = new ArrayList();
+//			this.trustedACIssuers = new HashSet();
+//			this.necessaryACAttributes = new HashSet();
+//			this.prohibitedACAttributes = new HashSet();
+//			this.attrCertCheckers = new HashSet();
+//		}
+
+		public virtual bool IsRevocationEnabled
+		{
+			get { return revocationEnabled; }
+			set { revocationEnabled = value; }
+		}
+
+		public virtual bool IsExplicitPolicyRequired
+		{
+			get { return explicitPolicyRequired; }
+			set { this.explicitPolicyRequired = value; }
+		}
+
+		public virtual bool IsAnyPolicyInhibited
+		{
+			get { return anyPolicyInhibited; }
+			set { this.anyPolicyInhibited = value; }
+		}
+
+		public virtual bool IsPolicyMappingInhibited
+		{
+			get { return policyMappingInhibited; }
+			set { this.policyMappingInhibited = value; }
+		}
+
+		public virtual bool IsPolicyQualifiersRejected
+		{
+			get { return policyQualifiersRejected; }
+			set { this.policyQualifiersRejected = value; }
+		}
+
+		//public bool IsCheckOnlyEECertificateCrl
+		//{
+		//	get { return this.checkOnlyEECertificateCrl; }
+		//	set { this.checkOnlyEECertificateCrl = value; }
+		//}
+
+		public virtual DateTimeObject Date
+		{
+			get { return this.date; }
+			set { this.date = value; }
+		}
+
+		// Returns a Set of the most-trusted CAs.
+		public virtual ISet GetTrustAnchors()
+		{
+			return new HashSet(this.trustAnchors);
+		}
+
+		// Sets the set of most-trusted CAs.
+		// Set is copied to protect against subsequent modifications.
+		public virtual void SetTrustAnchors(
+			ISet tas)
+		{
+			if (tas == null)
+				throw new ArgumentNullException("value");
+			if (tas.IsEmpty)
+				throw new ArgumentException("non-empty set required", "value");
+
+			// Explicit copy to enforce type-safety
+			this.trustAnchors = new HashSet();
+			foreach (TrustAnchor ta in tas)
+			{
+				if (ta != null)
+				{
+					trustAnchors.Add(ta);
+				}
+			}
+		}
+
+		/**
+		* Returns the required constraints on the target certificate. The
+		* constraints are returned as an instance of CertSelector. If
+		* <code>null</code>, no constraints are defined.<br />
+		* <br />
+		* Note that the CertSelector returned is cloned to protect against
+		* subsequent modifications.
+		*
+		* @return a CertSelector specifying the constraints on the target
+		*         certificate (or <code>null</code>)
+		*
+		* @see #setTargetCertConstraints(CertSelector)
+		*/
+		public virtual X509CertStoreSelector GetTargetCertConstraints()
+		{
+			if (certSelector == null)
+			{
+				return null;
+			}
+
+			return (X509CertStoreSelector)certSelector.Clone();
+		}
+
+		/**
+		 * Sets the required constraints on the target certificate. The constraints
+		 * are specified as an instance of CertSelector. If null, no constraints are
+		 * defined.<br />
+		 * <br />
+		 * Note that the CertSelector specified is cloned to protect against
+		 * subsequent modifications.
+		 *
+		 * @param selector
+		 *            a CertSelector specifying the constraints on the target
+		 *            certificate (or <code>null</code>)
+		 *
+		 * @see #getTargetCertConstraints()
+		 */
+		public virtual void SetTargetCertConstraints(
+			IX509Selector selector)
+		{
+			if (selector == null)
+			{
+				certSelector = null;
+			}
+			else
+			{
+				certSelector = (IX509Selector)selector.Clone();
+			}
+		}
+
+		/**
+		* Returns an immutable Set of initial policy identifiers (OID strings),
+		* indicating that any one of these policies would be acceptable to the
+		* certificate user for the purposes of certification path processing. The
+		* default return value is an empty <code>Set</code>, which is
+		* interpreted as meaning that any policy would be acceptable.
+		*
+		* @return an immutable <code>Set</code> of initial policy OIDs in String
+		*         format, or an empty <code>Set</code> (implying any policy is
+		*         acceptable). Never returns <code>null</code>.
+		*
+		* @see #setInitialPolicies(java.util.Set)
+		*/
+		public virtual ISet GetInitialPolicies()
+		{
+			ISet returnSet = initialPolicies;
+
+			// TODO Can it really be null?
+			if (initialPolicies == null)
+			{
+				returnSet = new HashSet();
+			}
+
+			return new HashSet(returnSet);
+		}
+
+		/**
+		* Sets the <code>Set</code> of initial policy identifiers (OID strings),
+		* indicating that any one of these policies would be acceptable to the
+		* certificate user for the purposes of certification path processing. By
+		* default, any policy is acceptable (i.e. all policies), so a user that
+		* wants to allow any policy as acceptable does not need to call this
+		* method, or can call it with an empty <code>Set</code> (or
+		* <code>null</code>).<br />
+		* <br />
+		* Note that the Set is copied to protect against subsequent modifications.<br />
+		* <br />
+		*
+		* @param initialPolicies
+		*            a Set of initial policy OIDs in String format (or
+		*            <code>null</code>)
+		*
+		* @exception ClassCastException
+		*                if any of the elements in the set are not of type String
+		*
+		* @see #getInitialPolicies()
+		*/
+		public virtual void SetInitialPolicies(
+			ISet initialPolicies)
+		{
+			this.initialPolicies = new HashSet();
+			if (initialPolicies != null)
+			{
+				foreach (string obj in initialPolicies)
+				{
+					if (obj != null)
+					{
+						this.initialPolicies.Add(obj);
+					}
+				}
+			}
+		}
+
+		/**
+		* Sets a <code>List</code> of additional certification path checkers. If
+		* the specified List contains an object that is not a PKIXCertPathChecker,
+		* it is ignored.<br />
+		* <br />
+		* Each <code>PKIXCertPathChecker</code> specified implements additional
+		* checks on a certificate. Typically, these are checks to process and
+		* verify private extensions contained in certificates. Each
+		* <code>PKIXCertPathChecker</code> should be instantiated with any
+		* initialization parameters needed to execute the check.<br />
+		* <br />
+		* This method allows sophisticated applications to extend a PKIX
+		* <code>CertPathValidator</code> or <code>CertPathBuilder</code>. Each
+		* of the specified PKIXCertPathCheckers will be called, in turn, by a PKIX
+		* <code>CertPathValidator</code> or <code>CertPathBuilder</code> for
+		* each certificate processed or validated.<br />
+		* <br />
+		* Regardless of whether these additional PKIXCertPathCheckers are set, a
+		* PKIX <code>CertPathValidator</code> or <code>CertPathBuilder</code>
+		* must perform all of the required PKIX checks on each certificate. The one
+		* exception to this rule is if the RevocationEnabled flag is set to false
+		* (see the {@link #setRevocationEnabled(boolean) setRevocationEnabled}
+		* method).<br />
+		* <br />
+		* Note that the List supplied here is copied and each PKIXCertPathChecker
+		* in the list is cloned to protect against subsequent modifications.
+		*
+		* @param checkers
+		*            a List of PKIXCertPathCheckers. May be null, in which case no
+		*            additional checkers will be used.
+		* @exception ClassCastException
+		*                if any of the elements in the list are not of type
+		*                <code>java.security.cert.PKIXCertPathChecker</code>
+		* @see #getCertPathCheckers()
+		*/
+		public virtual void SetCertPathCheckers(IList checkers)
+		{
+            certPathCheckers = Platform.CreateArrayList();
+			if (checkers != null)
+			{
+				foreach (PkixCertPathChecker obj in checkers)
+				{
+					certPathCheckers.Add(obj.Clone());
+				}
+			}
+		}
+
+		/**
+		 * Returns the List of certification path checkers. Each PKIXCertPathChecker
+		 * in the returned IList is cloned to protect against subsequent modifications.
+		 *
+		 * @return an immutable List of PKIXCertPathCheckers (may be empty, but not
+		 *         <code>null</code>)
+		 *
+		 * @see #setCertPathCheckers(java.util.List)
+		 */
+		public virtual IList GetCertPathCheckers()
+		{
+			IList checkers = Platform.CreateArrayList();
+			foreach (PkixCertPathChecker obj in certPathCheckers)
+			{
+				checkers.Add(obj.Clone());
+			}
+			return checkers;
+		}
+
+		/**
+		 * Adds a <code>PKIXCertPathChecker</code> to the list of certification
+		 * path checkers. See the {@link #setCertPathCheckers setCertPathCheckers}
+		 * method for more details.
+		 * <p>
+		 * Note that the <code>PKIXCertPathChecker</code> is cloned to protect
+		 * against subsequent modifications.</p>
+		 *
+		 * @param checker a <code>PKIXCertPathChecker</code> to add to the list of
+		 * checks. If <code>null</code>, the checker is ignored (not added to list).
+		 */
+		public virtual void AddCertPathChecker(
+			PkixCertPathChecker checker)
+		{
+			if (checker != null)
+			{
+				certPathCheckers.Add(checker.Clone());
+			}
+		}
+
+		public virtual object Clone()
+		{
+			// FIXME Check this whole method against the Java implementation!
+
+			PkixParameters parameters = new PkixParameters(GetTrustAnchors());
+			parameters.SetParams(this);
+			return parameters;
+
+
+//			PkixParameters obj = new PkixParameters(new HashSet());
+////			(PkixParameters) this.MemberwiseClone();
+//			obj.x509Stores = new ArrayList(x509Stores);
+//			obj.certPathCheckers = new ArrayList(certPathCheckers);
+//
+//			//Iterator iter = certPathCheckers.iterator();
+//			//obj.certPathCheckers = new ArrayList();
+//			//while (iter.hasNext())
+//			//{
+//			//	obj.certPathCheckers.add(((PKIXCertPathChecker)iter.next())
+//			//		.clone());
+//			//}
+//			//if (initialPolicies != null)
+//			//{
+//			//	obj.initialPolicies = new HashSet(initialPolicies);
+//			//}
+////			if (trustAnchors != null)
+////			{
+////				obj.trustAnchors = new HashSet(trustAnchors);
+////			}
+////			if (certSelector != null)
+////			{
+////				obj.certSelector = (X509CertStoreSelector) certSelector.Clone();
+////			}
+//			return obj;
+		}
+
+		/**
+		* 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 virtual void SetParams(
+			PkixParameters parameters)
+		{
+			Date = parameters.Date;
+			SetCertPathCheckers(parameters.GetCertPathCheckers());
+			IsAnyPolicyInhibited = parameters.IsAnyPolicyInhibited;
+			IsExplicitPolicyRequired = parameters.IsExplicitPolicyRequired;
+			IsPolicyMappingInhibited = parameters.IsPolicyMappingInhibited;
+			IsRevocationEnabled = parameters.IsRevocationEnabled;
+			SetInitialPolicies(parameters.GetInitialPolicies());
+			IsPolicyQualifiersRejected = parameters.IsPolicyQualifiersRejected;
+			SetTargetCertConstraints(parameters.GetTargetCertConstraints());
+			SetTrustAnchors(parameters.GetTrustAnchors());
+
+			validityModel = parameters.validityModel;
+			useDeltas = parameters.useDeltas;
+			additionalLocationsEnabled = parameters.additionalLocationsEnabled;
+			selector = parameters.selector == null ? null
+				: (IX509Selector) parameters.selector.Clone();
+			stores = Platform.CreateArrayList(parameters.stores);
+            additionalStores = Platform.CreateArrayList(parameters.additionalStores);
+			trustedACIssuers = new HashSet(parameters.trustedACIssuers);
+			prohibitedACAttributes = new HashSet(parameters.prohibitedACAttributes);
+			necessaryACAttributes = new HashSet(parameters.necessaryACAttributes);
+			attrCertCheckers = new HashSet(parameters.attrCertCheckers);
+		}
+
+		/**
+		 * Whether delta CRLs should be used for checking the revocation status.
+		 * Defaults to <code>false</code>.
+		 */
+		public virtual bool IsUseDeltasEnabled
+		{
+			get { return useDeltas; }
+			set { useDeltas = value; }
+		}
+
+		/**
+		* The validity model.
+		* @see #CHAIN_VALIDITY_MODEL
+		* @see #PKIX_VALIDITY_MODEL
+		*/
+		public virtual int ValidityModel
+		{
+			get { return validityModel; }
+			set { validityModel = value; }
+		}
+
+		/**
+		* Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+		* certificates or cross certificates.
+		* <p>
+		* The <code>IList</code> is cloned.
+		* </p>
+		*
+		* @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 virtual void SetStores(
+			IList stores)
+		{
+			if (stores == null)
+			{
+                this.stores = Platform.CreateArrayList();
+			}
+			else
+			{
+				foreach (object obj in stores)
+				{
+					if (!(obj is IX509Store))
+					{
+						throw new InvalidCastException(
+							"All elements of list must be of type " + typeof(IX509Store).FullName);
+					}
+				}
+                this.stores = Platform.CreateArrayList(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><p>
+		* If <code>store</code> is <code>null</code> it is ignored.
+		* </p>
+		*
+		* @param store The store to add.
+		* @see #getStores
+		*/
+		public virtual void AddStore(
+			IX509Store 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><p>
+		* If <code>store</code> is <code>null</code> it is ignored.
+		* </p>
+		*
+		* @param store The store to add.
+		* @see #getStores()
+		*/
+		public virtual void AddAdditionalStore(
+			IX509Store store)
+		{
+			if (store != null)
+			{
+				additionalStores.Add(store);
+			}
+		}
+
+		/**
+		* Returns an <code>IList</code> of additional Bouncy Castle
+		* <code>Store</code>s used for finding CRLs, certificates, attribute
+		* certificates or cross certificates.
+		*
+		* @return an immutable <code>IList</code> of additional Bouncy Castle
+		*         <code>Store</code>s. Never <code>null</code>.
+		*
+		* @see #addAddionalStore(Store)
+		*/
+		public virtual IList GetAdditionalStores()
+		{
+            return Platform.CreateArrayList(additionalStores);
+		}
+
+		/**
+		* Returns an <code>IList</code> of Bouncy Castle
+		* <code>Store</code>s used for finding CRLs, certificates, attribute
+		* certificates or cross certificates.
+		*
+		* @return an immutable <code>IList</code> of Bouncy Castle
+		*         <code>Store</code>s. Never <code>null</code>.
+		*
+		* @see #setStores(IList)
+		*/
+		public virtual IList GetStores()
+		{
+            return Platform.CreateArrayList(stores);
+		}
+
+		/**
+		* 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 virtual bool IsAdditionalLocationsEnabled
+		{
+			get { 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 virtual void SetAdditionalLocationsEnabled(
+			bool enabled)
+		{
+			additionalLocationsEnabled = enabled;
+		}
+
+		/**
+		* Returns the required constraints on the target certificate or attribute
+		* certificate. The constraints are returned as an instance of
+		* <code>IX509Selector</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><p>
+		* Note that the <code>IX509Selector</code> returned is cloned to protect
+		* against subsequent modifications.
+		* </p>
+		* @return a <code>IX509Selector</code> specifying the constraints on the
+		*         target certificate or attribute certificate (or <code>null</code>)
+		* @see #setTargetConstraints
+		* @see X509CertStoreSelector
+		* @see X509AttributeCertStoreSelector
+		*/
+		public virtual IX509Selector GetTargetConstraints()
+		{
+			if (selector != null)
+			{
+				return (IX509Selector) 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>IX509Selector</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><p>
+		* Note that the <code>IX509Selector</code> specified is cloned to protect
+		* against subsequent modifications.
+		* </p>
+		*
+		* @param selector a <code>IX509Selector</code> specifying the constraints on
+		*            the target certificate or attribute certificate (or
+		*            <code>null</code>)
+		* @see #getTargetConstraints
+		* @see X509CertStoreSelector
+		* @see X509AttributeCertStoreSelector
+		*/
+		public virtual void SetTargetConstraints(IX509Selector selector)
+		{
+			if (selector != null)
+			{
+				this.selector = (IX509Selector) selector.Clone();
+			}
+			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>ISet</code> consists of <code>TrustAnchor</code>s.
+		* </p><p>
+		* The returned <code>ISet</code> is immutable. Never <code>null</code>
+		* </p>
+		*
+		* @return Returns an immutable set of the trusted AC issuers.
+		*/
+		public virtual ISet GetTrustedACIssuers()
+		{
+			return new HashSet(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>ISet</code> of
+		* <code>TrustAnchor</code>
+		* </p><p>
+		* The given set is cloned.
+		* </p>
+		*
+		* @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 virtual void SetTrustedACIssuers(
+			ISet trustedACIssuers)
+		{
+			if (trustedACIssuers == null)
+			{
+				this.trustedACIssuers = new HashSet();
+			}
+			else
+			{
+				foreach (object obj in trustedACIssuers)
+				{
+					if (!(obj is TrustAnchor))
+					{
+						throw new InvalidCastException("All elements of set must be "
+							+ "of type " + typeof(TrustAnchor).Name + ".");
+					}
+				}
+				this.trustedACIssuers = new HashSet(trustedACIssuers);
+			}
+		}
+
+		/**
+		* Returns the neccessary attributes which must be contained in an attribute
+		* certificate.
+		* <p>
+		* The returned <code>ISet</code> is immutable and contains
+		* <code>String</code>s with the OIDs.
+		* </p>
+		*
+		* @return Returns the necessary AC attributes.
+		*/
+		public virtual ISet GetNecessaryACAttributes()
+		{
+			return new HashSet(necessaryACAttributes);
+		}
+
+		/**
+		* Sets the neccessary which must be contained in an attribute certificate.
+		* <p>
+		* The <code>ISet</code> must contain <code>String</code>s with the
+		* OIDs.
+		* </p><p>
+		* The set is cloned.
+		* </p>
+		*
+		* @param necessaryACAttributes The necessary AC attributes to set.
+		* @throws ClassCastException if an element of
+		*             <code>necessaryACAttributes</code> is not a
+		*             <code>String</code>.
+		*/
+		public virtual void SetNecessaryACAttributes(
+			ISet necessaryACAttributes)
+		{
+			if (necessaryACAttributes == null)
+			{
+				this.necessaryACAttributes = new HashSet();
+			}
+			else
+			{
+				foreach (object obj in necessaryACAttributes)
+				{
+					if (!(obj is string))
+					{
+						throw new InvalidCastException("All elements of set must be "
+							+ "of type string.");
+					}
+				}
+				this.necessaryACAttributes = new HashSet(necessaryACAttributes);
+			}
+		}
+
+		/**
+		* Returns the attribute certificates which are not allowed.
+		* <p>
+		* The returned <code>ISet</code> is immutable and contains
+		* <code>String</code>s with the OIDs.
+		* </p>
+		*
+		* @return Returns the prohibited AC attributes. Is never <code>null</code>.
+		*/
+		public virtual ISet GetProhibitedACAttributes()
+		{
+			return new HashSet(prohibitedACAttributes);
+		}
+
+		/**
+		* Sets the attribute certificates which are not allowed.
+		* <p>
+		* The <code>ISet</code> must contain <code>String</code>s with the
+		* OIDs.
+		* </p><p>
+		* The set is cloned.
+		* </p>
+		*
+		* @param prohibitedACAttributes The prohibited AC attributes to set.
+		* @throws ClassCastException if an element of
+		*             <code>prohibitedACAttributes</code> is not a
+		*             <code>String</code>.
+		*/
+		public virtual void SetProhibitedACAttributes(
+			ISet prohibitedACAttributes)
+		{
+			if (prohibitedACAttributes == null)
+			{
+				this.prohibitedACAttributes = new HashSet();
+			}
+			else
+			{
+				foreach (object obj in prohibitedACAttributes)
+				{
+					if (!(obj is String))
+					{
+						throw new InvalidCastException("All elements of set must be "
+							+ "of type string.");
+					}
+				}
+				this.prohibitedACAttributes = new HashSet(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 virtual ISet GetAttrCertCheckers()
+		{
+			return new HashSet(attrCertCheckers);
+		}
+
+		/**
+		* Sets the attribute certificate checkers.
+		* <p>
+		* All elements in the <code>ISet</code> must a {@link PKIXAttrCertChecker}.
+		* </p>
+		* <p>
+		* The given set is cloned.
+		* </p>
+		*
+		* @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 virtual void SetAttrCertCheckers(
+			ISet attrCertCheckers)
+		{
+			if (attrCertCheckers == null)
+			{
+				this.attrCertCheckers = new HashSet();
+			}
+			else
+			{
+				foreach (object obj in attrCertCheckers)
+				{
+					if (!(obj is PkixAttrCertChecker))
+					{
+						throw new InvalidCastException("All elements of set must be "
+							+ "of type " + typeof(PkixAttrCertChecker).FullName + ".");
+					}
+				}
+				this.attrCertCheckers = new HashSet(attrCertCheckers);
+			}
+		}
+	}
+}
diff --git a/crypto/src/pkix/PkixPolicyNode.cs b/crypto/src/pkix/PkixPolicyNode.cs
new file mode 100644
index 000000000..fc5b82f6f
--- /dev/null
+++ b/crypto/src/pkix/PkixPolicyNode.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// Summary description for PkixPolicyNode.
+	/// </summary>
+	public class PkixPolicyNode
+//		: IPolicyNode
+	{
+		protected IList				mChildren;
+		protected int				mDepth;
+		protected ISet				mExpectedPolicies;
+		protected PkixPolicyNode	mParent;
+		protected ISet				mPolicyQualifiers;
+		protected string			mValidPolicy;
+		protected bool				mCritical;
+
+		public virtual int Depth
+		{
+			get { return this.mDepth; }
+		}
+
+		public virtual IEnumerable Children
+		{
+			get { return new EnumerableProxy(mChildren); }
+		}
+
+		public virtual bool IsCritical
+		{
+			get { return this.mCritical; }
+			set { this.mCritical = value; }
+		}
+
+		public virtual ISet PolicyQualifiers
+		{
+			get { return new HashSet(this.mPolicyQualifiers); }
+		}
+
+		public virtual string ValidPolicy
+		{
+			get { return this.mValidPolicy; }
+		}
+
+		public virtual bool HasChildren
+		{
+			get { return mChildren.Count != 0; }
+		}
+
+		public virtual ISet ExpectedPolicies
+		{
+			get { return new HashSet(this.mExpectedPolicies); }
+			set { this.mExpectedPolicies = new HashSet(value); }
+		}
+
+		public virtual PkixPolicyNode Parent
+		{
+			get { return this.mParent; }
+			set { this.mParent = value; }
+		}
+
+		/// Constructors
+		public PkixPolicyNode(
+			IList			children,
+			int				depth,
+			ISet			expectedPolicies,
+			PkixPolicyNode	parent,
+			ISet			policyQualifiers,
+			string			validPolicy,
+			bool			critical)
+		{
+            if (children == null)
+            {
+                this.mChildren = Platform.CreateArrayList();
+            }
+            else
+            {
+                this.mChildren = Platform.CreateArrayList(children);
+            }
+
+            this.mDepth = depth;
+			this.mExpectedPolicies = expectedPolicies;
+			this.mParent = parent;
+			this.mPolicyQualifiers = policyQualifiers;
+			this.mValidPolicy = validPolicy;
+			this.mCritical = critical;
+		}
+
+		public virtual void AddChild(
+			PkixPolicyNode child)
+		{
+			child.Parent = this;
+			mChildren.Add(child);
+		}
+
+		public virtual void RemoveChild(
+			PkixPolicyNode child)
+		{
+			mChildren.Remove(child);
+		}
+
+		public override string ToString()
+		{
+			return ToString("");
+		}
+
+		public virtual string ToString(
+			string indent)
+		{
+			StringBuilder buf = new StringBuilder();
+			buf.Append(indent);
+			buf.Append(mValidPolicy);
+			buf.Append(" {");
+			buf.Append(Platform.NewLine);
+
+			foreach (PkixPolicyNode child in mChildren)
+			{
+				buf.Append(child.ToString(indent + "    "));
+			}
+
+			buf.Append(indent);
+			buf.Append("}");
+			buf.Append(Platform.NewLine);
+			return buf.ToString();
+		}
+
+		public virtual object Clone()
+		{
+			return Copy();
+		}
+
+		public virtual PkixPolicyNode Copy()
+		{
+			PkixPolicyNode node = new PkixPolicyNode(
+                Platform.CreateArrayList(),
+				mDepth,
+				new HashSet(mExpectedPolicies),
+				null,
+				new HashSet(mPolicyQualifiers),
+				mValidPolicy,
+				mCritical);
+
+			foreach (PkixPolicyNode child in mChildren)
+			{
+				PkixPolicyNode copy = child.Copy();
+				copy.Parent = node;
+				node.AddChild(copy);
+			}
+
+			return node;
+		}
+	}
+}
diff --git a/crypto/src/pkix/ReasonsMask.cs b/crypto/src/pkix/ReasonsMask.cs
new file mode 100644
index 000000000..e389bfe11
--- /dev/null
+++ b/crypto/src/pkix/ReasonsMask.cs
@@ -0,0 +1,96 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// This class helps to handle CRL revocation reasons mask. Each CRL handles a
+	/// certain set of revocation reasons.
+	/// </summary>
+	internal class ReasonsMask
+	{
+		private int _reasons;
+
+		/// <summary>
+		/// Constructs are reason mask with the reasons.
+		/// </summary>
+		/// <param name="reasons">The reasons.</param>
+		internal ReasonsMask(
+			int reasons)
+		{
+			_reasons = reasons;
+		}
+
+		/// <summary>
+		/// A reason mask with no reason.
+		/// </summary>
+		internal ReasonsMask()
+			: this(0)
+		{
+		}
+
+		/// <summary>
+		/// A mask with all revocation reasons.
+		/// </summary>
+		internal static readonly 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.
+		 */
+		internal void AddReasons(
+			ReasonsMask mask)
+		{
+			_reasons = _reasons | mask.Reasons.IntValue;
+		}
+
+		/// <summary>
+		/// Returns <code>true</code> if this reasons mask contains all possible
+		/// reasons.
+		/// </summary>
+		/// <returns>true if this reasons mask contains all possible reasons.
+		/// </returns>
+		internal bool IsAllReasons
+		{
+			get { return _reasons == AllReasons._reasons; }
+		}
+
+		/// <summary>
+		/// Intersects this mask with the given reasons mask.
+		/// </summary>
+		/// <param name="mask">mask The mask to intersect with.</param>
+		/// <returns>The intersection of this and teh given mask.</returns>
+		internal ReasonsMask Intersect(
+			ReasonsMask mask)
+		{
+			ReasonsMask _mask = new ReasonsMask();
+			_mask.AddReasons(new ReasonsMask(_reasons & mask.Reasons.IntValue));
+			return _mask;
+		}
+
+		/// <summary>
+		/// Returns <c>true</c> if the passed reasons mask has new reasons.
+		/// </summary>
+		/// <param name="mask">The reasons mask which should be tested for new reasons.</param>
+		/// <returns><c>true</c> if the passed reasons mask has new reasons.</returns>
+		internal bool HasNewReasons(
+			ReasonsMask mask)
+		{
+			return ((_reasons | mask.Reasons.IntValue ^ _reasons) != 0);
+		}
+
+		/// <summary>
+		/// Returns the reasons in this mask.
+		/// </summary>
+		public ReasonFlags Reasons
+		{
+			get { return new ReasonFlags(_reasons); }
+		}
+	}
+}
diff --git a/crypto/src/pkix/Rfc3280CertPathUtilities.cs b/crypto/src/pkix/Rfc3280CertPathUtilities.cs
index bae657d90..c6f3fbff9 100644
--- a/crypto/src/pkix/Rfc3280CertPathUtilities.cs
+++ b/crypto/src/pkix/Rfc3280CertPathUtilities.cs
@@ -1197,10 +1197,10 @@ namespace Org.BouncyCastle.Pkix
 			}
 			if (certStatus.Status != CertStatus.Unrevoked)
 			{
-				// TODO This format is forced by the NistCertPath tests
-				string formattedDate = certStatus.RevocationDate.Value.ToString(
-					"G", new CultureInfo("en-us"));
-				string message = "Certificate revocation after " + formattedDate;
+				// This format is enforced by the NistCertPath tests
+                string formattedDate = certStatus.RevocationDate.Value.ToString(
+                    "ddd MMM dd HH:mm:ss K yyyy");
+                string message = "Certificate revocation after " + formattedDate;
 				message += ", reason: " + CrlReasons[certStatus.Status];
 				throw new Exception(message);
 			}
diff --git a/crypto/src/pkix/Rfc3281CertPathUtilities.cs b/crypto/src/pkix/Rfc3281CertPathUtilities.cs
index bda2aa737..101ef5e11 100644
--- a/crypto/src/pkix/Rfc3281CertPathUtilities.cs
+++ b/crypto/src/pkix/Rfc3281CertPathUtilities.cs
@@ -195,10 +195,10 @@ namespace Org.BouncyCastle.Pkix
 					}
 					if (certStatus.Status != CertStatus.Unrevoked)
 					{
-						// TODO This format is forced by the NistCertPath tests
-						string formattedDate = certStatus.RevocationDate.Value.ToString(
-                            "G", new CultureInfo("en-us"));
-						string message = "Attribute certificate revocation after "
+                        // This format is enforced by the NistCertPath tests
+                        string formattedDate = certStatus.RevocationDate.Value.ToString(
+                            "ddd MMM dd HH:mm:ss K yyyy");
+                        string message = "Attribute certificate revocation after "
 							+ formattedDate;
 						message += ", reason: "
 							+ Rfc3280CertPathUtilities.CrlReasons[certStatus.Status];
diff --git a/crypto/src/pkix/TrustAnchor.cs b/crypto/src/pkix/TrustAnchor.cs
new file mode 100644
index 000000000..22078baf2
--- /dev/null
+++ b/crypto/src/pkix/TrustAnchor.cs
@@ -0,0 +1,259 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// A trust anchor or most-trusted Certification Authority (CA).
+	/// 
+	/// This class represents a "most-trusted CA", which is used as a trust anchor
+	/// for validating X.509 certification paths. A most-trusted CA includes the
+	/// public key of the CA, the CA's name, and any constraints upon the set of
+	/// paths which may be validated using this key. These parameters can be
+	/// specified in the form of a trusted X509Certificate or as individual
+	/// parameters.
+	/// </summary>
+	public class TrustAnchor
+	{
+		private readonly AsymmetricKeyParameter pubKey;
+		private readonly string caName;
+		private readonly X509Name caPrincipal;
+		private readonly X509Certificate trustedCert;
+		private byte[] ncBytes;
+		private NameConstraints nc;
+
+		/// <summary>
+		/// Creates an instance of TrustAnchor with the specified X509Certificate and
+	    /// optional name constraints, which are intended to be used as additional
+	    /// constraints when validating an X.509 certification path.
+	    ///	The name constraints are specified as a byte array. This byte array
+	    ///	should contain the DER encoded form of the name constraints, as they
+	    ///	would appear in the NameConstraints structure defined in RFC 2459 and
+	    ///	X.509. The ASN.1 definition of this structure appears below.
+	    ///	
+	    ///	<pre>
+	    ///	NameConstraints ::= SEQUENCE {
+	    ///		permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+	    ///		excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+	    ///	   
+        /// GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+        /// 
+        ///		GeneralSubtree ::= SEQUENCE {
+        ///		base                    GeneralName,
+        ///		minimum         [0]     BaseDistance DEFAULT 0,
+        ///		maximum         [1]     BaseDistance OPTIONAL }
+        ///		
+        ///		BaseDistance ::= INTEGER (0..MAX)
+		///
+		///		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}
+		///	</pre>
+		///	
+		///	Note that the name constraints byte array supplied is cloned to protect
+		///	against subsequent modifications.
+		/// </summary>
+		/// <param name="trustedCert">a trusted X509Certificate</param>
+		/// <param name="nameConstraints">a byte array containing the ASN.1 DER encoding of a
+		/// NameConstraints extension to be used for checking name
+		/// constraints. Only the value of the extension is included, not
+		/// the OID or criticality flag. Specify null to omit the
+		/// parameter.</param>
+		/// <exception cref="ArgumentNullException">if the specified X509Certificate is null</exception>
+		public TrustAnchor(
+			X509Certificate	trustedCert,
+			byte[]			nameConstraints)
+		{
+			if (trustedCert == null)
+				throw new ArgumentNullException("trustedCert");
+
+			this.trustedCert = trustedCert;
+			this.pubKey = null;
+			this.caName = null;
+			this.caPrincipal = null;
+			setNameConstraints(nameConstraints);
+		}
+
+		/// <summary>
+		/// Creates an instance of <c>TrustAnchor</c> where the
+		/// most-trusted CA is specified as an X500Principal and public key.
+		/// </summary>
+		/// <remarks>
+		/// <p>
+		/// Name constraints are an optional parameter, and are intended to be used
+		/// as additional constraints when validating an X.509 certification path.
+		/// </p><p>
+		/// The name constraints are specified as a byte array. This byte array
+		/// contains the DER encoded form of the name constraints, as they
+		/// would appear in the NameConstraints structure defined in RFC 2459
+		/// and X.509. The ASN.1 notation for this structure is supplied in the
+		/// documentation for the other constructors.
+		/// </p><p>
+		/// Note that the name constraints byte array supplied here is cloned to
+		/// protect against subsequent modifications.
+		/// </p>
+		/// </remarks>
+		/// <param name="caPrincipal">the name of the most-trusted CA as X509Name</param>
+		/// <param name="pubKey">the public key of the most-trusted CA</param>
+		/// <param name="nameConstraints">
+		/// a byte array containing the ASN.1 DER encoding of a NameConstraints extension to
+		/// be used for checking name constraints. Only the value of the extension is included,
+		/// not the OID or criticality flag. Specify <c>null</c> to omit the parameter.
+		/// </param>
+		/// <exception cref="ArgumentNullException">
+		/// if <c>caPrincipal</c> or <c>pubKey</c> is null
+		/// </exception>
+		public TrustAnchor(
+			X509Name				caPrincipal,
+			AsymmetricKeyParameter	pubKey,
+			byte[]					nameConstraints) 
+		{
+			if (caPrincipal == null)
+				throw new ArgumentNullException("caPrincipal");
+			if (pubKey == null)
+				throw new ArgumentNullException("pubKey");
+
+			this.trustedCert = null;
+			this.caPrincipal = caPrincipal;
+			this.caName = caPrincipal.ToString();
+			this.pubKey = pubKey;
+			setNameConstraints(nameConstraints);
+		}
+
+		/// <summary>
+		/// Creates an instance of <code>TrustAnchor</code> where the most-trusted
+		/// CA is specified as a distinguished name and public key. Name constraints
+		/// are an optional parameter, and are intended to be used as additional
+		/// constraints when validating an X.509 certification path.
+		/// <br/>
+		/// The name constraints are specified as a byte array. This byte array
+		/// contains the DER encoded form of the name constraints, as they would
+		/// appear in the NameConstraints structure defined in RFC 2459 and X.509.
+		/// </summary>
+		/// <param name="caName">the X.500 distinguished name of the most-trusted CA in RFC
+		/// 2253 string format</param>
+		/// <param name="pubKey">the public key of the most-trusted CA</param>
+		/// <param name="nameConstraints">a byte array containing the ASN.1 DER encoding of a
+		/// NameConstraints extension to be used for checking name
+		/// constraints. Only the value of the extension is included, not 
+		/// the OID or criticality flag. Specify null to omit the 
+		/// parameter.</param>
+		/// throws NullPointerException, IllegalArgumentException
+		public TrustAnchor(
+			string					caName,
+			AsymmetricKeyParameter	pubKey,
+			byte[]					nameConstraints)
+		{
+			if (caName == null)
+				throw new ArgumentNullException("caName");
+			if (pubKey == null)
+				throw new ArgumentNullException("pubKey");
+			if (caName.Length == 0)
+				throw new ArgumentException("caName can not be an empty string");
+
+			this.caPrincipal = new X509Name(caName);
+			this.pubKey = pubKey;
+			this.caName = caName;
+			this.trustedCert = null;
+			setNameConstraints(nameConstraints);
+		}
+
+		/// <summary>
+		/// Returns the most-trusted CA certificate.
+		/// </summary>
+		public X509Certificate TrustedCert
+		{
+			get { return this.trustedCert; }
+		}
+
+		/// <summary>
+		/// Returns the name of the most-trusted CA as an X509Name.
+		/// </summary>
+		public X509Name CA
+		{
+			get { return this.caPrincipal; }
+		}
+
+		/// <summary>
+		/// Returns the name of the most-trusted CA in RFC 2253 string format.
+		/// </summary>
+		public string CAName
+		{
+			get { return this.caName; }
+		}
+
+		/// <summary>
+		/// Returns the public key of the most-trusted CA.
+		/// </summary>
+		public AsymmetricKeyParameter CAPublicKey
+		{
+			get { return this.pubKey; }
+		}
+
+		/// <summary>
+		/// Decode the name constraints and clone them if not null.
+		/// </summary>
+		private void setNameConstraints(
+			byte[] bytes) 
+		{
+			if (bytes == null) 
+			{
+				ncBytes = null;
+				nc = null;
+			} 
+			else 
+			{
+				ncBytes = (byte[]) bytes.Clone();
+				// validate DER encoding
+				//nc = new NameConstraintsExtension(Boolean.FALSE, bytes);
+				nc = NameConstraints.GetInstance(Asn1Object.FromByteArray(bytes));
+			}
+		}
+
+		public byte[] GetNameConstraints
+		{
+			get { return Arrays.Clone(ncBytes); }
+		}
+
+		/// <summary>
+		/// Returns a formatted string describing the <code>TrustAnchor</code>.
+		/// </summary>
+		/// <returns>a formatted string describing the <code>TrustAnchor</code></returns>
+		public override string ToString()
+		{
+			// TODO Some of the sub-objects might not implement ToString() properly
+			string nl = Platform.NewLine;
+			StringBuilder sb = new StringBuilder();
+			sb.Append("[");
+			sb.Append(nl);
+			if (this.pubKey != null)
+			{
+				sb.Append("  Trusted CA Public Key: ").Append(this.pubKey).Append(nl);
+				sb.Append("  Trusted CA Issuer Name: ").Append(this.caName).Append(nl);
+			}
+			else
+			{
+				sb.Append("  Trusted CA cert: ").Append(this.TrustedCert).Append(nl);
+			}
+			if (nc != null)
+			{
+				sb.Append("  Name Constraints: ").Append(nc).Append(nl);
+			}
+			return sb.ToString();
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs
index d74ec7368..4c61ac354 100644
--- a/crypto/src/security/AgreementUtilities.cs
+++ b/crypto/src/security/AgreementUtilities.cs
@@ -1,5 +1,4 @@
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X9;
@@ -39,7 +38,7 @@ namespace Org.BouncyCastle.Security
 		public static IBasicAgreement GetBasicAgreement(
 			string algorithm)
 		{
-			string upper = algorithm.ToUpperInvariant();
+			string upper = Platform.ToUpperInvariant(algorithm);
 			string mechanism = (string) algorithms[upper];
 
 			if (mechanism == null)
@@ -73,7 +72,7 @@ namespace Org.BouncyCastle.Security
 			string agreeAlgorithm,
 			string wrapAlgorithm)
 		{
-			string upper = agreeAlgorithm.ToUpperInvariant();
+			string upper = Platform.ToUpperInvariant(agreeAlgorithm);
 			string mechanism = (string) algorithms[upper];
 
 			if (mechanism == null)
diff --git a/crypto/src/security/CipherUtilities.cs b/crypto/src/security/CipherUtilities.cs
index ffd7d1373..cdb711f69 100644
--- a/crypto/src/security/CipherUtilities.cs
+++ b/crypto/src/security/CipherUtilities.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
@@ -22,675 +21,715 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
-	/// <remarks>
-	///  Cipher Utility class contains methods that can not be specifically grouped into other classes.
-	/// </remarks>
-	public sealed class CipherUtilities
-	{
-		internal enum CipherAlgorithm {
-			AES,
-			ARC4,
-			BLOWFISH,
-			CAMELLIA,
-			CAST5,
-			CAST6,
-			DES,
-			DESEDE,
-			ELGAMAL,
-			GOST28147,
-			HC128,
-			HC256,
-			IDEA,
-			NOEKEON,
-			PBEWITHSHAAND128BITRC4,
-			PBEWITHSHAAND40BITRC4,
-			RC2,
-			RC5,
-			RC5_64,
-			RC6,
-			RIJNDAEL,
-			RSA,
-			SALSA20,
-			SEED,
-			SERPENT,
-			SKIPJACK,
-			TEA,
-			TWOFISH,
-			VMPC,
-			VMPC_KSA3,
-			XTEA,
-		};
-		
-		internal enum CipherMode { ECB, NONE, CBC, CCM, CFB, CTR, CTS, EAX, GCM, GOFB, OFB, OPENPGPCFB, SIC };
-		internal enum CipherPadding
-		{
-			NOPADDING,
-			RAW,
-			ISO10126PADDING,
-			ISO10126D2PADDING,
-			ISO10126_2PADDING,
-			ISO7816_4PADDING,
-			ISO9797_1PADDING,
-			ISO9796_1,
-			ISO9796_1PADDING,
-			OAEP,
-			OAEPPADDING,
-			OAEPWITHMD5ANDMGF1PADDING,
-			OAEPWITHSHA1ANDMGF1PADDING,
-			OAEPWITHSHA_1ANDMGF1PADDING,
-			OAEPWITHSHA224ANDMGF1PADDING,
-			OAEPWITHSHA_224ANDMGF1PADDING,
-			OAEPWITHSHA256ANDMGF1PADDING,
-			OAEPWITHSHA_256ANDMGF1PADDING,
-			OAEPWITHSHA384ANDMGF1PADDING,
-			OAEPWITHSHA_384ANDMGF1PADDING,
-			OAEPWITHSHA512ANDMGF1PADDING,
-			OAEPWITHSHA_512ANDMGF1PADDING,
-			PKCS1,
-			PKCS1PADDING,
-			PKCS5,
-			PKCS5PADDING,
-			PKCS7,
-			PKCS7PADDING,
-			TBCPADDING,
-			WITHCTS,
-			X923PADDING,
-			ZEROBYTEPADDING,
-		};
-
-		private static readonly IDictionary algorithms = Platform.CreateHashtable();
+    /// <remarks>
+    ///  Cipher Utility class contains methods that can not be specifically grouped into other classes.
+    /// </remarks>
+    public sealed class CipherUtilities
+    {
+        private enum CipherAlgorithm {
+            AES,
+            ARC4,
+            BLOWFISH,
+            CAMELLIA,
+            CAST5,
+            CAST6,
+            DES,
+            DESEDE,
+            ELGAMAL,
+            GOST28147,
+            HC128,
+            HC256,
+            IDEA,
+            NOEKEON,
+            PBEWITHSHAAND128BITRC4,
+            PBEWITHSHAAND40BITRC4,
+            RC2,
+            RC5,
+            RC5_64,
+            RC6,
+            RIJNDAEL,
+            RSA,
+            SALSA20,
+            SEED,
+            SERPENT,
+            SKIPJACK,
+            TEA,
+            TWOFISH,
+            VMPC,
+            VMPC_KSA3,
+            XTEA,
+        };
+        
+        private enum CipherMode { ECB, NONE, CBC, CCM, CFB, CTR, CTS, EAX, GCM, GOFB, OCB, OFB, OPENPGPCFB, SIC };
+        private enum CipherPadding
+        {
+            NOPADDING,
+            RAW,
+            ISO10126PADDING,
+            ISO10126D2PADDING,
+            ISO10126_2PADDING,
+            ISO7816_4PADDING,
+            ISO9797_1PADDING,
+            ISO9796_1,
+            ISO9796_1PADDING,
+            OAEP,
+            OAEPPADDING,
+            OAEPWITHMD5ANDMGF1PADDING,
+            OAEPWITHSHA1ANDMGF1PADDING,
+            OAEPWITHSHA_1ANDMGF1PADDING,
+            OAEPWITHSHA224ANDMGF1PADDING,
+            OAEPWITHSHA_224ANDMGF1PADDING,
+            OAEPWITHSHA256ANDMGF1PADDING,
+            OAEPWITHSHA_256ANDMGF1PADDING,
+            OAEPWITHSHA384ANDMGF1PADDING,
+            OAEPWITHSHA_384ANDMGF1PADDING,
+            OAEPWITHSHA512ANDMGF1PADDING,
+            OAEPWITHSHA_512ANDMGF1PADDING,
+            PKCS1,
+            PKCS1PADDING,
+            PKCS5,
+            PKCS5PADDING,
+            PKCS7,
+            PKCS7PADDING,
+            TBCPADDING,
+            WITHCTS,
+            X923PADDING,
+            ZEROBYTEPADDING,
+        };
+
+        private static readonly IDictionary algorithms = Platform.CreateHashtable();
         private static readonly IDictionary oids = Platform.CreateHashtable();
 
-		static CipherUtilities()
-		{
-			// Signal to obfuscation tools not to change enum constants
-			((CipherAlgorithm)Enums.GetArbitraryValue(typeof(CipherAlgorithm))).ToString();
-			((CipherMode)Enums.GetArbitraryValue(typeof(CipherMode))).ToString();
-			((CipherPadding)Enums.GetArbitraryValue(typeof(CipherPadding))).ToString();
+        static CipherUtilities()
+        {
+            // Signal to obfuscation tools not to change enum constants
+            ((CipherAlgorithm)Enums.GetArbitraryValue(typeof(CipherAlgorithm))).ToString();
+            ((CipherMode)Enums.GetArbitraryValue(typeof(CipherMode))).ToString();
+            ((CipherPadding)Enums.GetArbitraryValue(typeof(CipherPadding))).ToString();
 
-			// TODO Flesh out the list of aliases
+            // TODO Flesh out the list of aliases
 
-			algorithms[NistObjectIdentifiers.IdAes128Ecb.Id] = "AES/ECB/PKCS7PADDING";
-			algorithms[NistObjectIdentifiers.IdAes192Ecb.Id] = "AES/ECB/PKCS7PADDING";
-			algorithms[NistObjectIdentifiers.IdAes256Ecb.Id] = "AES/ECB/PKCS7PADDING";
-			algorithms["AES//PKCS7"] = "AES/ECB/PKCS7PADDING";
-			algorithms["AES//PKCS7PADDING"] = "AES/ECB/PKCS7PADDING";
-			algorithms["AES//PKCS5"] = "AES/ECB/PKCS7PADDING";
-			algorithms["AES//PKCS5PADDING"] = "AES/ECB/PKCS7PADDING";
+            algorithms[NistObjectIdentifiers.IdAes128Ecb.Id] = "AES/ECB/PKCS7PADDING";
+            algorithms[NistObjectIdentifiers.IdAes192Ecb.Id] = "AES/ECB/PKCS7PADDING";
+            algorithms[NistObjectIdentifiers.IdAes256Ecb.Id] = "AES/ECB/PKCS7PADDING";
+            algorithms["AES//PKCS7"] = "AES/ECB/PKCS7PADDING";
+            algorithms["AES//PKCS7PADDING"] = "AES/ECB/PKCS7PADDING";
+            algorithms["AES//PKCS5"] = "AES/ECB/PKCS7PADDING";
+            algorithms["AES//PKCS5PADDING"] = "AES/ECB/PKCS7PADDING";
 
-			algorithms[NistObjectIdentifiers.IdAes128Cbc.Id] = "AES/CBC/PKCS7PADDING";
-			algorithms[NistObjectIdentifiers.IdAes192Cbc.Id] = "AES/CBC/PKCS7PADDING";
-			algorithms[NistObjectIdentifiers.IdAes256Cbc.Id] = "AES/CBC/PKCS7PADDING";
+            algorithms[NistObjectIdentifiers.IdAes128Cbc.Id] = "AES/CBC/PKCS7PADDING";
+            algorithms[NistObjectIdentifiers.IdAes192Cbc.Id] = "AES/CBC/PKCS7PADDING";
+            algorithms[NistObjectIdentifiers.IdAes256Cbc.Id] = "AES/CBC/PKCS7PADDING";
 
-			algorithms[NistObjectIdentifiers.IdAes128Ofb.Id] = "AES/OFB/NOPADDING";
-			algorithms[NistObjectIdentifiers.IdAes192Ofb.Id] = "AES/OFB/NOPADDING";
-			algorithms[NistObjectIdentifiers.IdAes256Ofb.Id] = "AES/OFB/NOPADDING";
+            algorithms[NistObjectIdentifiers.IdAes128Ofb.Id] = "AES/OFB/NOPADDING";
+            algorithms[NistObjectIdentifiers.IdAes192Ofb.Id] = "AES/OFB/NOPADDING";
+            algorithms[NistObjectIdentifiers.IdAes256Ofb.Id] = "AES/OFB/NOPADDING";
 
-			algorithms[NistObjectIdentifiers.IdAes128Cfb.Id] = "AES/CFB/NOPADDING";
-			algorithms[NistObjectIdentifiers.IdAes192Cfb.Id] = "AES/CFB/NOPADDING";
-			algorithms[NistObjectIdentifiers.IdAes256Cfb.Id] = "AES/CFB/NOPADDING";
+            algorithms[NistObjectIdentifiers.IdAes128Cfb.Id] = "AES/CFB/NOPADDING";
+            algorithms[NistObjectIdentifiers.IdAes192Cfb.Id] = "AES/CFB/NOPADDING";
+            algorithms[NistObjectIdentifiers.IdAes256Cfb.Id] = "AES/CFB/NOPADDING";
 
-			algorithms["RSA/ECB/PKCS1"] = "RSA//PKCS1PADDING";
-			algorithms["RSA/ECB/PKCS1PADDING"] = "RSA//PKCS1PADDING";
-			algorithms[PkcsObjectIdentifiers.RsaEncryption.Id] = "RSA//PKCS1PADDING";
-			algorithms[PkcsObjectIdentifiers.IdRsaesOaep.Id] = "RSA//OAEPPADDING";
+            algorithms["RSA/ECB/PKCS1"] = "RSA//PKCS1PADDING";
+            algorithms["RSA/ECB/PKCS1PADDING"] = "RSA//PKCS1PADDING";
+            algorithms[PkcsObjectIdentifiers.RsaEncryption.Id] = "RSA//PKCS1PADDING";
+            algorithms[PkcsObjectIdentifiers.IdRsaesOaep.Id] = "RSA//OAEPPADDING";
 
-			algorithms[OiwObjectIdentifiers.DesCbc.Id] = "DES/CBC";
-			algorithms[OiwObjectIdentifiers.DesCfb.Id] = "DES/CFB";
-			algorithms[OiwObjectIdentifiers.DesEcb.Id] = "DES/ECB";
-			algorithms[OiwObjectIdentifiers.DesOfb.Id] = "DES/OFB";
-			algorithms[OiwObjectIdentifiers.DesEde.Id] = "DESEDE";
-			algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDE/CBC";
-			algorithms[PkcsObjectIdentifiers.RC2Cbc.Id] = "RC2/CBC";
-			algorithms["1.3.6.1.4.1.188.7.1.1.2"] = "IDEA/CBC";
-			algorithms["1.2.840.113533.7.66.10"] = "CAST5/CBC";
-
-			algorithms["RC4"] = "ARC4";
-			algorithms["ARCFOUR"] = "ARC4";
-			algorithms["1.2.840.113549.3.4"] = "ARC4";
+            algorithms[OiwObjectIdentifiers.DesCbc.Id] = "DES/CBC";
+            algorithms[OiwObjectIdentifiers.DesCfb.Id] = "DES/CFB";
+            algorithms[OiwObjectIdentifiers.DesEcb.Id] = "DES/ECB";
+            algorithms[OiwObjectIdentifiers.DesOfb.Id] = "DES/OFB";
+            algorithms[OiwObjectIdentifiers.DesEde.Id] = "DESEDE";
+            algorithms["TDEA"] = "DESEDE";
+            algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDE/CBC";
+            algorithms[PkcsObjectIdentifiers.RC2Cbc.Id] = "RC2/CBC";
+            algorithms["1.3.6.1.4.1.188.7.1.1.2"] = "IDEA/CBC";
+            algorithms["1.2.840.113533.7.66.10"] = "CAST5/CBC";
+
+            algorithms["RC4"] = "ARC4";
+            algorithms["ARCFOUR"] = "ARC4";
+            algorithms["1.2.840.113549.3.4"] = "ARC4";
 
 
 
-			algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEWITHSHAAND128BITRC4";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEWITHSHAAND128BITRC4";
-			algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEWITHSHAAND40BITRC4";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEWITHSHAAND40BITRC4";
+            algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEWITHSHAAND128BITRC4";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEWITHSHAAND128BITRC4";
+            algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEWITHSHAAND40BITRC4";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEWITHSHAAND40BITRC4";
 
-			algorithms["PBEWITHSHA1ANDDES"] = "PBEWITHSHA1ANDDES-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEWITHSHA1ANDDES-CBC";
-			algorithms["PBEWITHSHA1ANDRC2"] = "PBEWITHSHA1ANDRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEWITHSHA1ANDRC2-CBC";
-
-			algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
-			algorithms["PBEWITHSHAAND3KEYTRIPLEDES"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
-			algorithms["PBEWITHSHA1ANDDESEDE"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
-
-			algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
-
-			algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEWITHSHAAND128BITRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEWITHSHAAND128BITRC2-CBC";
-
-			algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEWITHSHAAND40BITRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEWITHSHAAND40BITRC2-CBC";
-
-			algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
-			algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
-
-			algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
-			algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
-
-			algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
-			algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
-
-			algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEWITHSHA256AND128BITAES-CBC-BC";
-			algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEWITHSHA256AND192BITAES-CBC-BC";
-			algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEWITHSHA256AND256BITAES-CBC-BC";
-
-
-			algorithms["GOST"] = "GOST28147";
-			algorithms["GOST-28147"] = "GOST28147";
-			algorithms[CryptoProObjectIdentifiers.GostR28147Cbc.Id] = "GOST28147/CBC/PKCS7PADDING";
-
-			algorithms["RC5-32"] = "RC5";
-
-			algorithms[NttObjectIdentifiers.IdCamellia128Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
-			algorithms[NttObjectIdentifiers.IdCamellia192Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
-			algorithms[NttObjectIdentifiers.IdCamellia256Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
-
-			algorithms[KisaObjectIdentifiers.IdSeedCbc.Id] = "SEED/CBC/PKCS7PADDING";
-
-			algorithms["1.3.6.1.4.1.3029.1.2"] = "BLOWFISH/CBC";
-		}
-
-		private CipherUtilities()
-		{
-		}
-
-		/// <summary>
-		/// Returns a ObjectIdentifier for a give encoding.
-		/// </summary>
-		/// <param name="mechanism">A string representation of the encoding.</param>
-		/// <returns>A DerObjectIdentifier, null if the Oid is not available.</returns>
-		// TODO Don't really want to support this
-		public static DerObjectIdentifier GetObjectIdentifier(
-			string mechanism)
-		{
-			if (mechanism == null)
-				throw new ArgumentNullException("mechanism");
-
-			mechanism = mechanism.ToUpperInvariant();
-			string aliased = (string) algorithms[mechanism];
-
-			if (aliased != null)
-				mechanism = aliased;
-
-			return (DerObjectIdentifier) oids[mechanism];
-		}
-
-		public static ICollection Algorithms
-		{
-			get { return oids.Keys; }
-		}
-
-		public static IBufferedCipher GetCipher(
-			DerObjectIdentifier oid)
-		{
-			return GetCipher(oid.Id);
-		}
-
-		public static IBufferedCipher GetCipher(
-			string algorithm)
-		{
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-
-			algorithm = algorithm.ToUpperInvariant();
-
-			string aliased = (string) algorithms[algorithm];
-
-			if (aliased != null)
-				algorithm = aliased;
-
-
-
-			IBasicAgreement iesAgreement = null;
-			if (algorithm == "IES")
-			{
-				iesAgreement = new DHBasicAgreement();
-			}
-			else if (algorithm == "ECIES")
-			{
-				iesAgreement = new ECDHBasicAgreement();
-			}
-
-			if (iesAgreement != null)
-			{
-				return new BufferedIesCipher(
-					new IesEngine(
-					iesAgreement,
-					new Kdf2BytesGenerator(
-					new Sha1Digest()),
-					new HMac(
-					new Sha1Digest())));
-			}
-
-
-
-			if (algorithm.StartsWith("PBE"))
-			{
-				if (algorithm.EndsWith("-CBC"))
-				{
-					if (algorithm == "PBEWITHSHA1ANDDES-CBC")
-					{
-						return new PaddedBufferedBlockCipher(
-							new CbcBlockCipher(new DesEngine()));
-					}
-					else if (algorithm == "PBEWITHSHA1ANDRC2-CBC")
-					{
-						return new PaddedBufferedBlockCipher(
-							new CbcBlockCipher(new RC2Engine()));
-					}
-					else if (Strings.IsOneOf(algorithm,
-						"PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"))
-					{
-						return new PaddedBufferedBlockCipher(
-							new CbcBlockCipher(new DesEdeEngine()));
-					}
-					else if (Strings.IsOneOf(algorithm,
-						"PBEWITHSHAAND128BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC"))
-					{
-						return new PaddedBufferedBlockCipher(
-							new CbcBlockCipher(new RC2Engine()));
-					}
-				}
-				else if (algorithm.EndsWith("-BC") || algorithm.EndsWith("-OPENSSL"))
-				{
-					if (Strings.IsOneOf(algorithm,
-						"PBEWITHSHAAND128BITAES-CBC-BC",
-						"PBEWITHSHAAND192BITAES-CBC-BC",
-						"PBEWITHSHAAND256BITAES-CBC-BC",
-						"PBEWITHSHA256AND128BITAES-CBC-BC",
-						"PBEWITHSHA256AND192BITAES-CBC-BC",
-						"PBEWITHSHA256AND256BITAES-CBC-BC",
-						"PBEWITHMD5AND128BITAES-CBC-OPENSSL",
-						"PBEWITHMD5AND192BITAES-CBC-OPENSSL",
-						"PBEWITHMD5AND256BITAES-CBC-OPENSSL"))
-					{
-						return new PaddedBufferedBlockCipher(
-							new CbcBlockCipher(new AesFastEngine()));
-					}
-				}
-			}
-
-
-
-			string[] parts = algorithm.Split('/');
-
-			IBlockCipher blockCipher = null;
-			IAsymmetricBlockCipher asymBlockCipher = null;
-			IStreamCipher streamCipher = null;
-
-			string algorithmName = parts[0];
-			CipherAlgorithm cipherAlgorithm;
-			try
-			{
-				cipherAlgorithm = (CipherAlgorithm)Enums.GetEnumValue(typeof(CipherAlgorithm), algorithmName);
-			}
-			catch (ArgumentException)
-			{
-				throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
-			}
-
-			switch (cipherAlgorithm)
-			{
-				case CipherAlgorithm.AES:
-					blockCipher = new AesFastEngine();
-					break;
-				case CipherAlgorithm.ARC4:
-					streamCipher = new RC4Engine();
-					break;
-				case CipherAlgorithm.BLOWFISH:
-					blockCipher = new BlowfishEngine();
-					break;
-				case CipherAlgorithm.CAMELLIA:
-					blockCipher = new CamelliaEngine();
-					break;
-				case CipherAlgorithm.CAST5:
-					blockCipher = new Cast5Engine();
-					break;
-				case CipherAlgorithm.CAST6:
-					blockCipher = new Cast6Engine();
-					break;
-				case CipherAlgorithm.DES:
-					blockCipher = new DesEngine();
-					break;
-				case CipherAlgorithm.DESEDE:
-					blockCipher = new DesEdeEngine();
-					break;
-				case CipherAlgorithm.ELGAMAL:
-					asymBlockCipher = new ElGamalEngine();
-					break;
-				case CipherAlgorithm.GOST28147:
-					blockCipher = new Gost28147Engine();
-					break;
-				case CipherAlgorithm.HC128:
-					streamCipher = new HC128Engine();
-					break;
-				case CipherAlgorithm.HC256:
-					streamCipher = new HC256Engine();
-					break;
-#if INCLUDE_IDEA
-				case CipherAlgorithm.IDEA:
-					blockCipher = new IdeaEngine();
-					break;
-#endif
-				case CipherAlgorithm.NOEKEON:
-					blockCipher = new NoekeonEngine();
-					break;
-				case CipherAlgorithm.PBEWITHSHAAND128BITRC4:
-				case CipherAlgorithm.PBEWITHSHAAND40BITRC4:
-					streamCipher = new RC4Engine();
-					break;
-				case CipherAlgorithm.RC2:
-					blockCipher = new RC2Engine();
-					break;
-				case CipherAlgorithm.RC5:
-					blockCipher = new RC532Engine();
-					break;
-				case CipherAlgorithm.RC5_64:
-					blockCipher = new RC564Engine();
-					break;
-				case CipherAlgorithm.RC6:
-					blockCipher = new RC6Engine();
-					break;
-				case CipherAlgorithm.RIJNDAEL:
-					blockCipher = new RijndaelEngine();
-					break;
-				case CipherAlgorithm.RSA:
-					asymBlockCipher = new RsaBlindedEngine();
-					break;
-				case CipherAlgorithm.SALSA20:
-					streamCipher = new Salsa20Engine();
-					break;
-				case CipherAlgorithm.SEED:
-					blockCipher = new SeedEngine();
-					break;
-				case CipherAlgorithm.SERPENT:
-					blockCipher = new SerpentEngine();
-					break;
-				case CipherAlgorithm.SKIPJACK:
-					blockCipher = new SkipjackEngine();
-					break;
-				case CipherAlgorithm.TEA:
-					blockCipher = new TeaEngine();
-					break;
-				case CipherAlgorithm.TWOFISH:
-					blockCipher = new TwofishEngine();
-					break;
-				case CipherAlgorithm.VMPC:
-					streamCipher = new VmpcEngine();
-					break;
-				case CipherAlgorithm.VMPC_KSA3:
-					streamCipher = new VmpcKsa3Engine();
-					break;
-				case CipherAlgorithm.XTEA:
-					blockCipher = new XteaEngine();
-					break;
-				default:
-					throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
-			}
-
-			if (streamCipher != null)
-			{
-				if (parts.Length > 1)
-					throw new ArgumentException("Modes and paddings not used for stream ciphers");
-
-				return new BufferedStreamCipher(streamCipher);
-			}
-
-
-			bool cts = false;
-			bool padded = true;
-			IBlockCipherPadding padding = null;
-			IAeadBlockCipher aeadBlockCipher = null;
-
-			if (parts.Length > 2)
-			{
-				if (streamCipher != null)
-					throw new ArgumentException("Paddings not used for stream ciphers");
-
-				string paddingName = parts[2];
-
-				CipherPadding cipherPadding;
-				if (paddingName == "")
-				{
-					cipherPadding = CipherPadding.RAW;
-				}
-				else if (paddingName == "X9.23PADDING")
-				{
-					cipherPadding = CipherPadding.X923PADDING;
-				}
-				else
-				{
-					try
-					{
-						cipherPadding = (CipherPadding)Enums.GetEnumValue(typeof(CipherPadding), paddingName);
-					}
-					catch (ArgumentException)
-					{
-						throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
-					}
-				}
-
-				switch (cipherPadding)
-				{
-					case CipherPadding.NOPADDING:
-						padded = false;
-						break;
-					case CipherPadding.RAW:
-						break;
-					case CipherPadding.ISO10126PADDING:
-					case CipherPadding.ISO10126D2PADDING:
-					case CipherPadding.ISO10126_2PADDING:
-						padding = new ISO10126d2Padding();
-						break;
-					case CipherPadding.ISO7816_4PADDING:
-					case CipherPadding.ISO9797_1PADDING:
-						padding = new ISO7816d4Padding();
-						break;
-					case CipherPadding.ISO9796_1:
-					case CipherPadding.ISO9796_1PADDING:
-						asymBlockCipher = new ISO9796d1Encoding(asymBlockCipher);
-						break;
-					case CipherPadding.OAEP:
-					case CipherPadding.OAEPPADDING:
-						asymBlockCipher = new OaepEncoding(asymBlockCipher);
-						break;
-					case CipherPadding.OAEPWITHMD5ANDMGF1PADDING:
-						asymBlockCipher = new OaepEncoding(asymBlockCipher, new MD5Digest());
-						break;
-					case CipherPadding.OAEPWITHSHA1ANDMGF1PADDING:
-					case CipherPadding.OAEPWITHSHA_1ANDMGF1PADDING:
-						asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha1Digest());
-						break;
-					case CipherPadding.OAEPWITHSHA224ANDMGF1PADDING:
-					case CipherPadding.OAEPWITHSHA_224ANDMGF1PADDING:
-						asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha224Digest());
-						break;
-					case CipherPadding.OAEPWITHSHA256ANDMGF1PADDING:
-					case CipherPadding.OAEPWITHSHA_256ANDMGF1PADDING:
-						asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha256Digest());
-						break;
-					case CipherPadding.OAEPWITHSHA384ANDMGF1PADDING:
-					case CipherPadding.OAEPWITHSHA_384ANDMGF1PADDING:
-						asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha384Digest());
-						break;
-					case CipherPadding.OAEPWITHSHA512ANDMGF1PADDING:
-					case CipherPadding.OAEPWITHSHA_512ANDMGF1PADDING:
-						asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha512Digest());
-						break;
-					case CipherPadding.PKCS1:
-					case CipherPadding.PKCS1PADDING:
-						asymBlockCipher = new Pkcs1Encoding(asymBlockCipher);
-						break;
-					case CipherPadding.PKCS5:
-					case CipherPadding.PKCS5PADDING:
-					case CipherPadding.PKCS7:
-					case CipherPadding.PKCS7PADDING:
-						padding = new Pkcs7Padding();
-						break;
-					case CipherPadding.TBCPADDING:
-						padding = new TbcPadding();
-						break;
-					case CipherPadding.WITHCTS:
-						cts = true;
-						break;
-					case CipherPadding.X923PADDING:
-						padding = new X923Padding();
-						break;
-					case CipherPadding.ZEROBYTEPADDING:
-						padding = new ZeroBytePadding();
-						break;
-					default:
-						throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
-				}
-			}
-
-			string mode = "";
-			if (parts.Length > 1)
-			{
-				mode = parts[1];
-
-				int di = GetDigitIndex(mode);
-				string modeName = di >= 0 ? mode.Substring(0, di) : mode;
-
-				try
-				{
-					CipherMode cipherMode = modeName == ""
-						? CipherMode.NONE
-						: (CipherMode)Enums.GetEnumValue(typeof(CipherMode), modeName);
-
-					switch (cipherMode)
-					{
-						case CipherMode.ECB:
-						case CipherMode.NONE:
-							break;
-						case CipherMode.CBC:
-							blockCipher = new CbcBlockCipher(blockCipher);
-							break;
-						case CipherMode.CCM:
-							aeadBlockCipher = new CcmBlockCipher(blockCipher);
-							break;
-						case CipherMode.CFB:
-						{
-							int bits = (di < 0)
-								?	8 * blockCipher.GetBlockSize()
-								:	int.Parse(mode.Substring(di));
-	
-							blockCipher = new CfbBlockCipher(blockCipher, bits);
-							break;
-						}
-						case CipherMode.CTR:
-							blockCipher = new SicBlockCipher(blockCipher);
-							break;
-						case CipherMode.CTS:
-							cts = true;
-							blockCipher = new CbcBlockCipher(blockCipher);
-							break;
-						case CipherMode.EAX:
-							aeadBlockCipher = new EaxBlockCipher(blockCipher);
-							break;
-						case CipherMode.GCM:
-							aeadBlockCipher = new GcmBlockCipher(blockCipher);
-							break;
-						case CipherMode.GOFB:
-							blockCipher = new GOfbBlockCipher(blockCipher);
-							break;
-						case CipherMode.OFB:
-						{
-							int bits = (di < 0)
-								?	8 * blockCipher.GetBlockSize()
-								:	int.Parse(mode.Substring(di));
-	
-							blockCipher = new OfbBlockCipher(blockCipher, bits);
-							break;
-						}
-						case CipherMode.OPENPGPCFB:
-							blockCipher = new OpenPgpCfbBlockCipher(blockCipher);
-							break;
-						case CipherMode.SIC:
-							if (blockCipher.GetBlockSize() < 16)
-							{
-								throw new ArgumentException("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)");
-							}
-							blockCipher = new SicBlockCipher(blockCipher);
-							break;
-						default:
-							throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
-					}
-				}
-				catch (ArgumentException)
-				{
-					throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
-				}
-			}
-
-			if (aeadBlockCipher != null)
-			{
-				if (cts)
-					throw new SecurityUtilityException("CTS mode not valid for AEAD ciphers.");
-				if (padded && parts.Length > 2 && parts[2] != "")
-					throw new SecurityUtilityException("Bad padding specified for AEAD cipher.");
-
-				return new BufferedAeadBlockCipher(aeadBlockCipher);
-			}
-
-			if (blockCipher != null)
-			{
-				if (cts)
-				{
-					return new CtsBlockCipher(blockCipher);
-				}
-
-				if (padding != null)
-				{
-					return new PaddedBufferedBlockCipher(blockCipher, padding);
-				}
-
-				if (!padded || blockCipher.IsPartialBlockOkay)
-				{
-					return new BufferedBlockCipher(blockCipher);
-				}
-
-				return new PaddedBufferedBlockCipher(blockCipher);
-			}
-
-			if (asymBlockCipher != null)
-			{
-				return new BufferedAsymmetricBlockCipher(asymBlockCipher);
-			}
-
-			throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
-		}
-
-		public static string GetAlgorithmName(
-			DerObjectIdentifier oid)
-		{
-			return (string) algorithms[oid.Id];
-		}
-
-		private static int GetDigitIndex(
-			string s)
-		{
-			for (int i = 0; i < s.Length; ++i)
-			{
-				if (char.IsDigit(s[i]))
-					return i;
-			}
-
-			return -1;
-		}
-	}
+            algorithms["PBEWITHSHA1ANDDES"] = "PBEWITHSHA1ANDDES-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEWITHSHA1ANDDES-CBC";
+            algorithms["PBEWITHSHA1ANDRC2"] = "PBEWITHSHA1ANDRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEWITHSHA1ANDRC2-CBC";
+
+            algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+            algorithms["PBEWITHSHAAND3KEYTRIPLEDES"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+            algorithms["PBEWITHSHA1ANDDESEDE"] = "PBEWITHSHAAND3-KEYTRIPLEDES-CBC";
+
+            algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
+
+            algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEWITHSHAAND128BITRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEWITHSHAAND128BITRC2-CBC";
+
+            algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEWITHSHAAND40BITRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEWITHSHAAND40BITRC2-CBC";
+
+            algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
+            algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEWITHSHAAND128BITAES-CBC-BC";
+
+            algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
+            algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEWITHSHAAND192BITAES-CBC-BC";
+
+            algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
+            algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEWITHSHAAND256BITAES-CBC-BC";
+
+            algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEWITHSHA256AND128BITAES-CBC-BC";
+            algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEWITHSHA256AND192BITAES-CBC-BC";
+            algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEWITHSHA256AND256BITAES-CBC-BC";
+
+
+            algorithms["GOST"] = "GOST28147";
+            algorithms["GOST-28147"] = "GOST28147";
+            algorithms[CryptoProObjectIdentifiers.GostR28147Cbc.Id] = "GOST28147/CBC/PKCS7PADDING";
+
+            algorithms["RC5-32"] = "RC5";
+
+            algorithms[NttObjectIdentifiers.IdCamellia128Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+            algorithms[NttObjectIdentifiers.IdCamellia192Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+            algorithms[NttObjectIdentifiers.IdCamellia256Cbc.Id] = "CAMELLIA/CBC/PKCS7PADDING";
+
+            algorithms[KisaObjectIdentifiers.IdSeedCbc.Id] = "SEED/CBC/PKCS7PADDING";
+
+            algorithms["1.3.6.1.4.1.3029.1.2"] = "BLOWFISH/CBC";
+        }
+
+        private CipherUtilities()
+        {
+        }
+
+        /// <summary>
+        /// Returns a ObjectIdentifier for a give encoding.
+        /// </summary>
+        /// <param name="mechanism">A string representation of the encoding.</param>
+        /// <returns>A DerObjectIdentifier, null if the Oid is not available.</returns>
+        // TODO Don't really want to support this
+        public static DerObjectIdentifier GetObjectIdentifier(
+            string mechanism)
+        {
+            if (mechanism == null)
+                throw new ArgumentNullException("mechanism");
+
+            mechanism = Platform.ToUpperInvariant(mechanism);
+            string aliased = (string) algorithms[mechanism];
+
+            if (aliased != null)
+                mechanism = aliased;
+
+            return (DerObjectIdentifier) oids[mechanism];
+        }
+
+        public static ICollection Algorithms
+        {
+            get { return oids.Keys; }
+        }
+
+        public static IBufferedCipher GetCipher(
+            DerObjectIdentifier oid)
+        {
+            return GetCipher(oid.Id);
+        }
+
+        public static IBufferedCipher GetCipher(
+            string algorithm)
+        {
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+
+            algorithm = Platform.ToUpperInvariant(algorithm);
+
+            {
+                string aliased = (string) algorithms[algorithm];
+
+                if (aliased != null)
+                    algorithm = aliased;
+            }
+
+            IBasicAgreement iesAgreement = null;
+            if (algorithm == "IES")
+            {
+                iesAgreement = new DHBasicAgreement();
+            }
+            else if (algorithm == "ECIES")
+            {
+                iesAgreement = new ECDHBasicAgreement();
+            }
+
+            if (iesAgreement != null)
+            {
+                return new BufferedIesCipher(
+                    new IesEngine(
+                    iesAgreement,
+                    new Kdf2BytesGenerator(
+                    new Sha1Digest()),
+                    new HMac(
+                    new Sha1Digest())));
+            }
+
+
+
+            if (algorithm.StartsWith("PBE"))
+            {
+                if (algorithm.EndsWith("-CBC"))
+                {
+                    if (algorithm == "PBEWITHSHA1ANDDES-CBC")
+                    {
+                        return new PaddedBufferedBlockCipher(
+                            new CbcBlockCipher(new DesEngine()));
+                    }
+                    else if (algorithm == "PBEWITHSHA1ANDRC2-CBC")
+                    {
+                        return new PaddedBufferedBlockCipher(
+                            new CbcBlockCipher(new RC2Engine()));
+                    }
+                    else if (Strings.IsOneOf(algorithm,
+                        "PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"))
+                    {
+                        return new PaddedBufferedBlockCipher(
+                            new CbcBlockCipher(new DesEdeEngine()));
+                    }
+                    else if (Strings.IsOneOf(algorithm,
+                        "PBEWITHSHAAND128BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC"))
+                    {
+                        return new PaddedBufferedBlockCipher(
+                            new CbcBlockCipher(new RC2Engine()));
+                    }
+                }
+                else if (algorithm.EndsWith("-BC") || algorithm.EndsWith("-OPENSSL"))
+                {
+                    if (Strings.IsOneOf(algorithm,
+                        "PBEWITHSHAAND128BITAES-CBC-BC",
+                        "PBEWITHSHAAND192BITAES-CBC-BC",
+                        "PBEWITHSHAAND256BITAES-CBC-BC",
+                        "PBEWITHSHA256AND128BITAES-CBC-BC",
+                        "PBEWITHSHA256AND192BITAES-CBC-BC",
+                        "PBEWITHSHA256AND256BITAES-CBC-BC",
+                        "PBEWITHMD5AND128BITAES-CBC-OPENSSL",
+                        "PBEWITHMD5AND192BITAES-CBC-OPENSSL",
+                        "PBEWITHMD5AND256BITAES-CBC-OPENSSL"))
+                    {
+                        return new PaddedBufferedBlockCipher(
+                            new CbcBlockCipher(new AesFastEngine()));
+                    }
+                }
+            }
+
+
+
+            string[] parts = algorithm.Split('/');
+
+            IBlockCipher blockCipher = null;
+            IAsymmetricBlockCipher asymBlockCipher = null;
+            IStreamCipher streamCipher = null;
+
+            string algorithmName = parts[0];
+
+            {
+                string aliased = (string)algorithms[algorithmName];
+
+                if (aliased != null)
+                    algorithmName = aliased;
+            }
+
+            CipherAlgorithm cipherAlgorithm;
+            try
+            {
+                cipherAlgorithm = (CipherAlgorithm)Enums.GetEnumValue(typeof(CipherAlgorithm), algorithmName);
+            }
+            catch (ArgumentException)
+            {
+                throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+            }
+
+            switch (cipherAlgorithm)
+            {
+                case CipherAlgorithm.AES:
+                    blockCipher = new AesFastEngine();
+                    break;
+                case CipherAlgorithm.ARC4:
+                    streamCipher = new RC4Engine();
+                    break;
+                case CipherAlgorithm.BLOWFISH:
+                    blockCipher = new BlowfishEngine();
+                    break;
+                case CipherAlgorithm.CAMELLIA:
+                    blockCipher = new CamelliaEngine();
+                    break;
+                case CipherAlgorithm.CAST5:
+                    blockCipher = new Cast5Engine();
+                    break;
+                case CipherAlgorithm.CAST6:
+                    blockCipher = new Cast6Engine();
+                    break;
+                case CipherAlgorithm.DES:
+                    blockCipher = new DesEngine();
+                    break;
+                case CipherAlgorithm.DESEDE:
+                    blockCipher = new DesEdeEngine();
+                    break;
+                case CipherAlgorithm.ELGAMAL:
+                    asymBlockCipher = new ElGamalEngine();
+                    break;
+                case CipherAlgorithm.GOST28147:
+                    blockCipher = new Gost28147Engine();
+                    break;
+                case CipherAlgorithm.HC128:
+                    streamCipher = new HC128Engine();
+                    break;
+                case CipherAlgorithm.HC256:
+                    streamCipher = new HC256Engine();
+                    break;
+                case CipherAlgorithm.IDEA:
+                    blockCipher = new IdeaEngine();
+                    break;
+                case CipherAlgorithm.NOEKEON:
+                    blockCipher = new NoekeonEngine();
+                    break;
+                case CipherAlgorithm.PBEWITHSHAAND128BITRC4:
+                case CipherAlgorithm.PBEWITHSHAAND40BITRC4:
+                    streamCipher = new RC4Engine();
+                    break;
+                case CipherAlgorithm.RC2:
+                    blockCipher = new RC2Engine();
+                    break;
+                case CipherAlgorithm.RC5:
+                    blockCipher = new RC532Engine();
+                    break;
+                case CipherAlgorithm.RC5_64:
+                    blockCipher = new RC564Engine();
+                    break;
+                case CipherAlgorithm.RC6:
+                    blockCipher = new RC6Engine();
+                    break;
+                case CipherAlgorithm.RIJNDAEL:
+                    blockCipher = new RijndaelEngine();
+                    break;
+                case CipherAlgorithm.RSA:
+                    asymBlockCipher = new RsaBlindedEngine();
+                    break;
+                case CipherAlgorithm.SALSA20:
+                    streamCipher = new Salsa20Engine();
+                    break;
+                case CipherAlgorithm.SEED:
+                    blockCipher = new SeedEngine();
+                    break;
+                case CipherAlgorithm.SERPENT:
+                    blockCipher = new SerpentEngine();
+                    break;
+                case CipherAlgorithm.SKIPJACK:
+                    blockCipher = new SkipjackEngine();
+                    break;
+                case CipherAlgorithm.TEA:
+                    blockCipher = new TeaEngine();
+                    break;
+                case CipherAlgorithm.TWOFISH:
+                    blockCipher = new TwofishEngine();
+                    break;
+                case CipherAlgorithm.VMPC:
+                    streamCipher = new VmpcEngine();
+                    break;
+                case CipherAlgorithm.VMPC_KSA3:
+                    streamCipher = new VmpcKsa3Engine();
+                    break;
+                case CipherAlgorithm.XTEA:
+                    blockCipher = new XteaEngine();
+                    break;
+                default:
+                    throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+            }
+
+            if (streamCipher != null)
+            {
+                if (parts.Length > 1)
+                    throw new ArgumentException("Modes and paddings not used for stream ciphers");
+
+                return new BufferedStreamCipher(streamCipher);
+            }
+
+
+            bool cts = false;
+            bool padded = true;
+            IBlockCipherPadding padding = null;
+            IAeadBlockCipher aeadBlockCipher = null;
+
+            if (parts.Length > 2)
+            {
+                if (streamCipher != null)
+                    throw new ArgumentException("Paddings not used for stream ciphers");
+
+                string paddingName = parts[2];
+
+                CipherPadding cipherPadding;
+                if (paddingName == "")
+                {
+                    cipherPadding = CipherPadding.RAW;
+                }
+                else if (paddingName == "X9.23PADDING")
+                {
+                    cipherPadding = CipherPadding.X923PADDING;
+                }
+                else
+                {
+                    try
+                    {
+                        cipherPadding = (CipherPadding)Enums.GetEnumValue(typeof(CipherPadding), paddingName);
+                    }
+                    catch (ArgumentException)
+                    {
+                        throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+                    }
+                }
+
+                switch (cipherPadding)
+                {
+                    case CipherPadding.NOPADDING:
+                        padded = false;
+                        break;
+                    case CipherPadding.RAW:
+                        break;
+                    case CipherPadding.ISO10126PADDING:
+                    case CipherPadding.ISO10126D2PADDING:
+                    case CipherPadding.ISO10126_2PADDING:
+                        padding = new ISO10126d2Padding();
+                        break;
+                    case CipherPadding.ISO7816_4PADDING:
+                    case CipherPadding.ISO9797_1PADDING:
+                        padding = new ISO7816d4Padding();
+                        break;
+                    case CipherPadding.ISO9796_1:
+                    case CipherPadding.ISO9796_1PADDING:
+                        asymBlockCipher = new ISO9796d1Encoding(asymBlockCipher);
+                        break;
+                    case CipherPadding.OAEP:
+                    case CipherPadding.OAEPPADDING:
+                        asymBlockCipher = new OaepEncoding(asymBlockCipher);
+                        break;
+                    case CipherPadding.OAEPWITHMD5ANDMGF1PADDING:
+                        asymBlockCipher = new OaepEncoding(asymBlockCipher, new MD5Digest());
+                        break;
+                    case CipherPadding.OAEPWITHSHA1ANDMGF1PADDING:
+                    case CipherPadding.OAEPWITHSHA_1ANDMGF1PADDING:
+                        asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha1Digest());
+                        break;
+                    case CipherPadding.OAEPWITHSHA224ANDMGF1PADDING:
+                    case CipherPadding.OAEPWITHSHA_224ANDMGF1PADDING:
+                        asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha224Digest());
+                        break;
+                    case CipherPadding.OAEPWITHSHA256ANDMGF1PADDING:
+                    case CipherPadding.OAEPWITHSHA_256ANDMGF1PADDING:
+                        asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha256Digest());
+                        break;
+                    case CipherPadding.OAEPWITHSHA384ANDMGF1PADDING:
+                    case CipherPadding.OAEPWITHSHA_384ANDMGF1PADDING:
+                        asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha384Digest());
+                        break;
+                    case CipherPadding.OAEPWITHSHA512ANDMGF1PADDING:
+                    case CipherPadding.OAEPWITHSHA_512ANDMGF1PADDING:
+                        asymBlockCipher = new OaepEncoding(asymBlockCipher, new Sha512Digest());
+                        break;
+                    case CipherPadding.PKCS1:
+                    case CipherPadding.PKCS1PADDING:
+                        asymBlockCipher = new Pkcs1Encoding(asymBlockCipher);
+                        break;
+                    case CipherPadding.PKCS5:
+                    case CipherPadding.PKCS5PADDING:
+                    case CipherPadding.PKCS7:
+                    case CipherPadding.PKCS7PADDING:
+                        padding = new Pkcs7Padding();
+                        break;
+                    case CipherPadding.TBCPADDING:
+                        padding = new TbcPadding();
+                        break;
+                    case CipherPadding.WITHCTS:
+                        cts = true;
+                        break;
+                    case CipherPadding.X923PADDING:
+                        padding = new X923Padding();
+                        break;
+                    case CipherPadding.ZEROBYTEPADDING:
+                        padding = new ZeroBytePadding();
+                        break;
+                    default:
+                        throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+                }
+            }
+
+            string mode = "";
+            if (parts.Length > 1)
+            {
+                mode = parts[1];
+
+                int di = GetDigitIndex(mode);
+                string modeName = di >= 0 ? mode.Substring(0, di) : mode;
+
+                try
+                {
+                    CipherMode cipherMode = modeName == ""
+                        ? CipherMode.NONE
+                        : (CipherMode)Enums.GetEnumValue(typeof(CipherMode), modeName);
+
+                    switch (cipherMode)
+                    {
+                        case CipherMode.ECB:
+                        case CipherMode.NONE:
+                            break;
+                        case CipherMode.CBC:
+                            blockCipher = new CbcBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.CCM:
+                            aeadBlockCipher = new CcmBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.CFB:
+                        {
+                            int bits = (di < 0)
+                                ?	8 * blockCipher.GetBlockSize()
+                                :	int.Parse(mode.Substring(di));
+    
+                            blockCipher = new CfbBlockCipher(blockCipher, bits);
+                            break;
+                        }
+                        case CipherMode.CTR:
+                            blockCipher = new SicBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.CTS:
+                            cts = true;
+                            blockCipher = new CbcBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.EAX:
+                            aeadBlockCipher = new EaxBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.GCM:
+                            aeadBlockCipher = new GcmBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.GOFB:
+                            blockCipher = new GOfbBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.OCB:
+                            aeadBlockCipher = new OcbBlockCipher(blockCipher, CreateBlockCipher(cipherAlgorithm));
+                            break;
+                        case CipherMode.OFB:
+                        {
+                            int bits = (di < 0)
+                                ?	8 * blockCipher.GetBlockSize()
+                                :	int.Parse(mode.Substring(di));
+    
+                            blockCipher = new OfbBlockCipher(blockCipher, bits);
+                            break;
+                        }
+                        case CipherMode.OPENPGPCFB:
+                            blockCipher = new OpenPgpCfbBlockCipher(blockCipher);
+                            break;
+                        case CipherMode.SIC:
+                            if (blockCipher.GetBlockSize() < 16)
+                            {
+                                throw new ArgumentException("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)");
+                            }
+                            blockCipher = new SicBlockCipher(blockCipher);
+                            break;
+                        default:
+                            throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+                    }
+                }
+                catch (ArgumentException)
+                {
+                    throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+                }
+            }
+
+            if (aeadBlockCipher != null)
+            {
+                if (cts)
+                    throw new SecurityUtilityException("CTS mode not valid for AEAD ciphers.");
+                if (padded && parts.Length > 2 && parts[2] != "")
+                    throw new SecurityUtilityException("Bad padding specified for AEAD cipher.");
+
+                return new BufferedAeadBlockCipher(aeadBlockCipher);
+            }
+
+            if (blockCipher != null)
+            {
+                if (cts)
+                {
+                    return new CtsBlockCipher(blockCipher);
+                }
+
+                if (padding != null)
+                {
+                    return new PaddedBufferedBlockCipher(blockCipher, padding);
+                }
+
+                if (!padded || blockCipher.IsPartialBlockOkay)
+                {
+                    return new BufferedBlockCipher(blockCipher);
+                }
+
+                return new PaddedBufferedBlockCipher(blockCipher);
+            }
+
+            if (asymBlockCipher != null)
+            {
+                return new BufferedAsymmetricBlockCipher(asymBlockCipher);
+            }
+
+            throw new SecurityUtilityException("Cipher " + algorithm + " not recognised.");
+        }
+
+        public static string GetAlgorithmName(
+            DerObjectIdentifier oid)
+        {
+            return (string) algorithms[oid.Id];
+        }
+
+        private static int GetDigitIndex(
+            string s)
+        {
+            for (int i = 0; i < s.Length; ++i)
+            {
+                if (char.IsDigit(s[i]))
+                    return i;
+            }
+
+            return -1;
+        }
+
+        private static IBlockCipher CreateBlockCipher(CipherAlgorithm cipherAlgorithm)
+        {
+            switch (cipherAlgorithm)
+            {
+                case CipherAlgorithm.AES: return new AesFastEngine();
+                case CipherAlgorithm.BLOWFISH: return new BlowfishEngine();
+                case CipherAlgorithm.CAMELLIA: return new CamelliaEngine();
+                case CipherAlgorithm.CAST5: return new Cast5Engine();
+                case CipherAlgorithm.CAST6: return new Cast6Engine();
+                case CipherAlgorithm.DES: return new DesEngine();
+                case CipherAlgorithm.DESEDE: return new DesEdeEngine();
+                case CipherAlgorithm.GOST28147: return new Gost28147Engine();
+                case CipherAlgorithm.IDEA: return new IdeaEngine();
+                case CipherAlgorithm.NOEKEON: return new NoekeonEngine();
+                case CipherAlgorithm.RC2: return new RC2Engine();
+                case CipherAlgorithm.RC5: return new RC532Engine();
+                case CipherAlgorithm.RC5_64: return new RC564Engine();
+                case CipherAlgorithm.RC6: return new RC6Engine();
+                case CipherAlgorithm.RIJNDAEL: return new RijndaelEngine();
+                case CipherAlgorithm.SEED: return new SeedEngine();
+                case CipherAlgorithm.SERPENT: return new SerpentEngine();
+                case CipherAlgorithm.SKIPJACK: return new SkipjackEngine();
+                case CipherAlgorithm.TEA: return new TeaEngine();
+                case CipherAlgorithm.TWOFISH: return new TwofishEngine();
+                case CipherAlgorithm.XTEA: return new XteaEngine();
+                default:
+                    throw new SecurityUtilityException("Cipher " + cipherAlgorithm + " not recognised or not a block cipher");
+            }
+        }
+    }
 }
diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs
index a507b4e9b..ec3f63940 100644
--- a/crypto/src/security/DigestUtilities.cs
+++ b/crypto/src/security/DigestUtilities.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
@@ -20,27 +19,29 @@ namespace Org.BouncyCastle.Security
     /// </remarks>
     public sealed class DigestUtilities
     {
-		internal enum DigestAlgorithm {
-			GOST3411,
-			MD2, MD4, MD5,
-			RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320,
-			SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
-			TIGER,
-			WHIRLPOOL,
-		};
-
-		private DigestUtilities()
-		{
-		}
+        private enum DigestAlgorithm {
+            GOST3411,
+            MD2, MD4, MD5,
+            RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320,
+            SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
+            SHA_512_224, SHA_512_256,
+            SHA3_224, SHA3_256, SHA3_384, SHA3_512,
+            TIGER,
+            WHIRLPOOL,
+        };
+
+        private DigestUtilities()
+        {
+        }
 
         private static readonly IDictionary algorithms = Platform.CreateHashtable();
         private static readonly IDictionary oids = Platform.CreateHashtable();
 
         static DigestUtilities()
         {
-			// Signal to obfuscation tools not to change enum constants
-			((DigestAlgorithm)Enums.GetArbitraryValue(typeof(DigestAlgorithm))).ToString();
-			
+            // Signal to obfuscation tools not to change enum constants
+            ((DigestAlgorithm)Enums.GetArbitraryValue(typeof(DigestAlgorithm))).ToString();
+
             algorithms[PkcsObjectIdentifiers.MD2.Id] = "MD2";
             algorithms[PkcsObjectIdentifiers.MD4.Id] = "MD4";
             algorithms[PkcsObjectIdentifiers.MD5.Id] = "MD5";
@@ -55,6 +56,10 @@ namespace Org.BouncyCastle.Security
             algorithms[NistObjectIdentifiers.IdSha384.Id] = "SHA-384";
             algorithms["SHA512"] = "SHA-512";
             algorithms[NistObjectIdentifiers.IdSha512.Id] = "SHA-512";
+            algorithms["SHA512/224"] = "SHA-512/224";
+            algorithms[NistObjectIdentifiers.IdSha512_224.Id] = "SHA-512/224";
+            algorithms["SHA512/256"] = "SHA-512/256";
+            algorithms[NistObjectIdentifiers.IdSha512_256.Id] = "SHA-512/256";
 
             algorithms["RIPEMD-128"] = "RIPEMD128";
             algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "RIPEMD128";
@@ -62,10 +67,10 @@ namespace Org.BouncyCastle.Security
             algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "RIPEMD160";
             algorithms["RIPEMD-256"] = "RIPEMD256";
             algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "RIPEMD256";
-			algorithms["RIPEMD-320"] = "RIPEMD320";
+            algorithms["RIPEMD-320"] = "RIPEMD320";
 //			algorithms[TeleTrusTObjectIdentifiers.RipeMD320.Id] = "RIPEMD320";
 
-			algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
+            algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
 
 
 
@@ -77,113 +82,121 @@ namespace Org.BouncyCastle.Security
             oids["SHA-256"] = NistObjectIdentifiers.IdSha256;
             oids["SHA-384"] = NistObjectIdentifiers.IdSha384;
             oids["SHA-512"] = NistObjectIdentifiers.IdSha512;
+            oids["SHA-512/224"] = NistObjectIdentifiers.IdSha512_224;
+            oids["SHA-512/256"] = NistObjectIdentifiers.IdSha512_256;
             oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
             oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
             oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
-			oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411;
+            oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411;
         }
 
-		/// <summary>
+        /// <summary>
         /// Returns a ObjectIdentifier for a given digest mechanism.
         /// </summary>
         /// <param name="mechanism">A string representation of the digest meanism.</param>
         /// <returns>A DerObjectIdentifier, null if the Oid is not available.</returns>
 
         public static DerObjectIdentifier GetObjectIdentifier(
-			string mechanism)
+            string mechanism)
         {
-			if (mechanism == null)
-				throw new System.ArgumentNullException("mechanism");
+            if (mechanism == null)
+                throw new System.ArgumentNullException("mechanism");
 
-			mechanism = mechanism.ToUpperInvariant();
-			string aliased = (string) algorithms[mechanism];
+            mechanism = Platform.ToUpperInvariant(mechanism);
+            string aliased = (string) algorithms[mechanism];
 
-			if (aliased != null)
-				mechanism = aliased;
+            if (aliased != null)
+                mechanism = aliased;
 
-			return (DerObjectIdentifier) oids[mechanism];
+            return (DerObjectIdentifier) oids[mechanism];
         }
 
         public static ICollection Algorithms
         {
-			get { return oids.Keys; }
+            get { return oids.Keys; }
         }
 
         public static IDigest GetDigest(
-			DerObjectIdentifier id)
+            DerObjectIdentifier id)
         {
             return GetDigest(id.Id);
         }
 
         public static IDigest GetDigest(
-			string algorithm)
+            string algorithm)
         {
-			string upper = algorithm.ToUpperInvariant();
+            string upper = Platform.ToUpperInvariant(algorithm);
             string mechanism = (string) algorithms[upper];
 
-			if (mechanism == null)
-			{
-				mechanism = upper;
-			}
-
-			try
-			{
-				DigestAlgorithm digestAlgorithm = (DigestAlgorithm)Enums.GetEnumValue(
-					typeof(DigestAlgorithm), mechanism);
-
-				switch (digestAlgorithm)
-				{
-					case DigestAlgorithm.GOST3411:	return new Gost3411Digest();
-					case DigestAlgorithm.MD2:		return new MD2Digest();
-					case DigestAlgorithm.MD4:		return new MD4Digest();
-					case DigestAlgorithm.MD5:		return new MD5Digest();
-					case DigestAlgorithm.RIPEMD128:	return new RipeMD128Digest();
-					case DigestAlgorithm.RIPEMD160:	return new RipeMD160Digest();
-					case DigestAlgorithm.RIPEMD256:	return new RipeMD256Digest();
-					case DigestAlgorithm.RIPEMD320:	return new RipeMD320Digest();
-					case DigestAlgorithm.SHA_1:		return new Sha1Digest();
-					case DigestAlgorithm.SHA_224:	return new Sha224Digest();
-					case DigestAlgorithm.SHA_256:	return new Sha256Digest();
-					case DigestAlgorithm.SHA_384:	return new Sha384Digest();
-					case DigestAlgorithm.SHA_512:	return new Sha512Digest();
-					case DigestAlgorithm.TIGER:		return new TigerDigest();
-					case DigestAlgorithm.WHIRLPOOL:	return new WhirlpoolDigest();
-				}
-			}
-			catch (ArgumentException)
-			{
-			}
-
-			throw new SecurityUtilityException("Digest " + mechanism + " not recognised.");
+            if (mechanism == null)
+            {
+                mechanism = upper;
+            }
+
+            try
+            {
+                DigestAlgorithm digestAlgorithm = (DigestAlgorithm)Enums.GetEnumValue(
+                    typeof(DigestAlgorithm), mechanism);
+
+                switch (digestAlgorithm)
+                {
+                    case DigestAlgorithm.GOST3411:      return new Gost3411Digest();
+                    case DigestAlgorithm.MD2:		    return new MD2Digest();
+                    case DigestAlgorithm.MD4:		    return new MD4Digest();
+                    case DigestAlgorithm.MD5:		    return new MD5Digest();
+                    case DigestAlgorithm.RIPEMD128:	    return new RipeMD128Digest();
+                    case DigestAlgorithm.RIPEMD160:	    return new RipeMD160Digest();
+                    case DigestAlgorithm.RIPEMD256:	    return new RipeMD256Digest();
+                    case DigestAlgorithm.RIPEMD320:	    return new RipeMD320Digest();
+                    case DigestAlgorithm.SHA_1:		    return new Sha1Digest();
+                    case DigestAlgorithm.SHA_224:	    return new Sha224Digest();
+                    case DigestAlgorithm.SHA_256:	    return new Sha256Digest();
+                    case DigestAlgorithm.SHA_384:	    return new Sha384Digest();
+                    case DigestAlgorithm.SHA_512:	    return new Sha512Digest();
+                    case DigestAlgorithm.SHA_512_224:   return new Sha512tDigest(224);
+                    case DigestAlgorithm.SHA_512_256:   return new Sha512tDigest(256);
+                    case DigestAlgorithm.SHA3_224:      return new Sha3Digest(224);
+                    case DigestAlgorithm.SHA3_256:      return new Sha3Digest(256);
+                    case DigestAlgorithm.SHA3_384:      return new Sha3Digest(384);
+                    case DigestAlgorithm.SHA3_512:      return new Sha3Digest(512);
+                    case DigestAlgorithm.TIGER:         return new TigerDigest();
+                    case DigestAlgorithm.WHIRLPOOL:     return new WhirlpoolDigest();
+                }
+            }
+            catch (ArgumentException)
+            {
+            }
+
+            throw new SecurityUtilityException("Digest " + mechanism + " not recognised.");
         }
 
-		public static string GetAlgorithmName(
-			DerObjectIdentifier oid)
+        public static string GetAlgorithmName(
+            DerObjectIdentifier oid)
         {
             return (string) algorithms[oid.Id];
         }
 
-		public static byte[] CalculateDigest(string algorithm, byte[] input)
-		{
-			IDigest digest = GetDigest(algorithm);
-			digest.BlockUpdate(input, 0, input.Length);
-			return DoFinal(digest);
-		}
-
-		public static byte[] DoFinal(
-			IDigest digest)
-		{
-			byte[] b = new byte[digest.GetDigestSize()];
-			digest.DoFinal(b, 0);
-			return b;
-		}
-
-		public static byte[] DoFinal(
-			IDigest	digest,
-		    byte[]	input)
-		{
-			digest.BlockUpdate(input, 0, input.Length);
-			return DoFinal(digest);
-		}
+        public static byte[] CalculateDigest(string algorithm, byte[] input)
+        {
+            IDigest digest = GetDigest(algorithm);
+            digest.BlockUpdate(input, 0, input.Length);
+            return DoFinal(digest);
+        }
+
+        public static byte[] DoFinal(
+            IDigest digest)
+        {
+            byte[] b = new byte[digest.GetDigestSize()];
+            digest.DoFinal(b, 0);
+            return b;
+        }
+
+        public static byte[] DoFinal(
+            IDigest	digest,
+            byte[]	input)
+        {
+            digest.BlockUpdate(input, 0, input.Length);
+            return DoFinal(digest);
+        }
     }
 }
diff --git a/crypto/src/security/DotNetUtilities.cs b/crypto/src/security/DotNetUtilities.cs
index 4df1ae739..d50e17d39 100644
--- a/crypto/src/security/DotNetUtilities.cs
+++ b/crypto/src/security/DotNetUtilities.cs
@@ -1,9 +1,10 @@
-#if !(NETCF_1_0 || SILVERLIGHT || PORTABLE)
+#if !(NETCF_1_0 || SILVERLIGHT)
 
 using System;
 using System.Security.Cryptography;
 using SystemX509 = System.Security.Cryptography.X509Certificates;
 
+using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
@@ -161,22 +162,21 @@ namespace Org.BouncyCastle.Security
 
 		public static RSA ToRSA(RsaKeyParameters rsaKey)
 		{
-			RSAParameters rp = ToRSAParameters(rsaKey);
-			RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
-			// TODO This call appears to not work for private keys (when no CRT info)
-			rsaCsp.ImportParameters(rp);
-			return rsaCsp;
-		}
+            // TODO This appears to not work for private keys (when no CRT info)
+            return CreateRSAProvider(ToRSAParameters(rsaKey));
+        }
 
 		public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
 		{
-			RSAParameters rp = ToRSAParameters(privKey);
-			RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
-			rsaCsp.ImportParameters(rp);
-			return rsaCsp;
-		}
+            return CreateRSAProvider(ToRSAParameters(privKey));
+        }
 
-		public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey)
+        public static RSA ToRSA(RsaPrivateKeyStructure privKey)
+        {
+            return CreateRSAProvider(ToRSAParameters(privKey));
+        }
+
+        public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey)
 		{
 			RSAParameters rp = new RSAParameters();
 			rp.Modulus = rsaKey.Modulus.ToByteArrayUnsigned();
@@ -201,7 +201,21 @@ namespace Org.BouncyCastle.Security
 			return rp;
 		}
 
-		// TODO Move functionality to more general class
+        public static RSAParameters ToRSAParameters(RsaPrivateKeyStructure privKey)
+        {
+            RSAParameters rp = new RSAParameters();
+            rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
+            rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
+            rp.P = privKey.Prime1.ToByteArrayUnsigned();
+            rp.Q = privKey.Prime2.ToByteArrayUnsigned();
+            rp.D = ConvertRSAParametersField(privKey.PrivateExponent, rp.Modulus.Length);
+            rp.DP = ConvertRSAParametersField(privKey.Exponent1, rp.P.Length);
+            rp.DQ = ConvertRSAParametersField(privKey.Exponent2, rp.Q.Length);
+            rp.InverseQ = ConvertRSAParametersField(privKey.Coefficient, rp.Q.Length);
+            return rp;
+        }
+
+        // TODO Move functionality to more general class
 		private static byte[] ConvertRSAParametersField(BigInteger n, int size)
 		{
 			byte[] bs = n.ToByteArrayUnsigned();
@@ -216,6 +230,13 @@ namespace Org.BouncyCastle.Security
 			Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
 			return padded;
 		}
+
+        private static RSA CreateRSAProvider(RSAParameters rp)
+        {
+            RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
+            rsaCsp.ImportParameters(rp);
+            return rsaCsp;
+        }
 	}
 }
 
diff --git a/crypto/src/security/GeneralSecurityException.cs b/crypto/src/security/GeneralSecurityException.cs
index c0e412f98..2c3f2a555 100644
--- a/crypto/src/security/GeneralSecurityException.cs
+++ b/crypto/src/security/GeneralSecurityException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security
 {
-	public class GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class GeneralSecurityException
 		: Exception
 	{
 		public GeneralSecurityException()
diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs
index 8e9290222..45fbc9425 100644
--- a/crypto/src/security/GeneratorUtilities.cs
+++ b/crypto/src/security/GeneratorUtilities.cs
@@ -1,5 +1,4 @@
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
@@ -17,325 +16,334 @@ using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Security
 {
-	public sealed class GeneratorUtilities
-	{
-		private GeneratorUtilities()
-		{
-		}
+    public sealed class GeneratorUtilities
+    {
+        private GeneratorUtilities()
+        {
+        }
 
-		private static readonly IDictionary kgAlgorithms = Platform.CreateHashtable();
+        private static readonly IDictionary kgAlgorithms = Platform.CreateHashtable();
         private static readonly IDictionary kpgAlgorithms = Platform.CreateHashtable();
-		private static readonly IDictionary defaultKeySizes = Platform.CreateHashtable();
-
-		static GeneratorUtilities()
-		{
-			//
-			// key generators.
-			//
-			AddKgAlgorithm("AES",
-				"AESWRAP");
-			AddKgAlgorithm("AES128",
-				"2.16.840.1.101.3.4.2",
-				NistObjectIdentifiers.IdAes128Cbc,
-				NistObjectIdentifiers.IdAes128Cfb,
-				NistObjectIdentifiers.IdAes128Ecb,
-				NistObjectIdentifiers.IdAes128Ofb,
-				NistObjectIdentifiers.IdAes128Wrap);
-			AddKgAlgorithm("AES192",
-				"2.16.840.1.101.3.4.22",
-				NistObjectIdentifiers.IdAes192Cbc,
-				NistObjectIdentifiers.IdAes192Cfb,
-				NistObjectIdentifiers.IdAes192Ecb,
-				NistObjectIdentifiers.IdAes192Ofb,
-				NistObjectIdentifiers.IdAes192Wrap);
-			AddKgAlgorithm("AES256",
-				"2.16.840.1.101.3.4.42",
-				NistObjectIdentifiers.IdAes256Cbc,
-				NistObjectIdentifiers.IdAes256Cfb,
-				NistObjectIdentifiers.IdAes256Ecb,
-				NistObjectIdentifiers.IdAes256Ofb,
-				NistObjectIdentifiers.IdAes256Wrap);
-			AddKgAlgorithm("BLOWFISH",
-				"1.3.6.1.4.1.3029.1.2");
-			AddKgAlgorithm("CAMELLIA",
-				"CAMELLIAWRAP");
-			AddKgAlgorithm("CAMELLIA128",
-				NttObjectIdentifiers.IdCamellia128Cbc,
-				NttObjectIdentifiers.IdCamellia128Wrap);
-			AddKgAlgorithm("CAMELLIA192",
-				NttObjectIdentifiers.IdCamellia192Cbc,
-				NttObjectIdentifiers.IdCamellia192Wrap);
-			AddKgAlgorithm("CAMELLIA256",
-				NttObjectIdentifiers.IdCamellia256Cbc,
-				NttObjectIdentifiers.IdCamellia256Wrap);
-			AddKgAlgorithm("CAST5",
-				"1.2.840.113533.7.66.10");
-			AddKgAlgorithm("CAST6");
-			AddKgAlgorithm("DES",
-				OiwObjectIdentifiers.DesCbc,
-				OiwObjectIdentifiers.DesCfb,
-				OiwObjectIdentifiers.DesEcb,
-				OiwObjectIdentifiers.DesOfb);
-			AddKgAlgorithm("DESEDE",
-				"DESEDEWRAP",
-				OiwObjectIdentifiers.DesEde);
-			AddKgAlgorithm("DESEDE3",
-				PkcsObjectIdentifiers.DesEde3Cbc,
-				PkcsObjectIdentifiers.IdAlgCms3DesWrap);
-			AddKgAlgorithm("GOST28147",
-				"GOST",
-				"GOST-28147",
-				CryptoProObjectIdentifiers.GostR28147Cbc);
-			AddKgAlgorithm("HC128");
-			AddKgAlgorithm("HC256");
-			AddKgAlgorithm("IDEA",
-				"1.3.6.1.4.1.188.7.1.1.2");
-			AddKgAlgorithm("NOEKEON");
-			AddKgAlgorithm("RC2",
-				PkcsObjectIdentifiers.RC2Cbc,
-				PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
-			AddKgAlgorithm("RC4",
-				"ARC4",
-				"1.2.840.113549.3.4");
-			AddKgAlgorithm("RC5",
-				"RC5-32");
-			AddKgAlgorithm("RC5-64");
-			AddKgAlgorithm("RC6");
-			AddKgAlgorithm("RIJNDAEL");
-			AddKgAlgorithm("SALSA20");
-			AddKgAlgorithm("SEED",
-				KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
-				KisaObjectIdentifiers.IdSeedCbc);
-			AddKgAlgorithm("SERPENT");
-			AddKgAlgorithm("SKIPJACK");
-			AddKgAlgorithm("TEA");
-			AddKgAlgorithm("TWOFISH");
-			AddKgAlgorithm("VMPC");
-			AddKgAlgorithm("VMPC-KSA3");
-			AddKgAlgorithm("XTEA");
-
-			//
-			// HMac key generators
-			//
-			AddHMacKeyGenerator("MD2");
-			AddHMacKeyGenerator("MD4");
-			AddHMacKeyGenerator("MD5",
-				IanaObjectIdentifiers.HmacMD5);
-			AddHMacKeyGenerator("SHA1",
-				PkcsObjectIdentifiers.IdHmacWithSha1,
-				IanaObjectIdentifiers.HmacSha1);
-			AddHMacKeyGenerator("SHA224",
-				PkcsObjectIdentifiers.IdHmacWithSha224);
-			AddHMacKeyGenerator("SHA256",
-				PkcsObjectIdentifiers.IdHmacWithSha256);
-			AddHMacKeyGenerator("SHA384",
-				PkcsObjectIdentifiers.IdHmacWithSha384);
-			AddHMacKeyGenerator("SHA512",
-				PkcsObjectIdentifiers.IdHmacWithSha512);
-			AddHMacKeyGenerator("RIPEMD128");
-			AddHMacKeyGenerator("RIPEMD160",
-				IanaObjectIdentifiers.HmacRipeMD160);
-			AddHMacKeyGenerator("TIGER",
-				IanaObjectIdentifiers.HmacTiger);
-
-
-
-			//
-			// key pair generators.
-			//
-			AddKpgAlgorithm("DH",
-				"DIFFIEHELLMAN");
-			AddKpgAlgorithm("DSA");
-			AddKpgAlgorithm("EC",
-				// TODO Should this be an alias for ECDH?
-				X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme);
-			AddKpgAlgorithm("ECDH",
-				"ECIES");
-			AddKpgAlgorithm("ECDHC");
-			AddKpgAlgorithm("ECMQV",
-				X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme);
-			AddKpgAlgorithm("ECDSA");
-			AddKpgAlgorithm("ECGOST3410",
-				"ECGOST-3410",
-				"GOST-3410-2001");
-			AddKpgAlgorithm("ELGAMAL");
-			AddKpgAlgorithm("GOST3410",
+        private static readonly IDictionary defaultKeySizes = Platform.CreateHashtable();
+
+        static GeneratorUtilities()
+        {
+            //
+            // key generators.
+            //
+            AddKgAlgorithm("AES",
+                "AESWRAP");
+            AddKgAlgorithm("AES128",
+                "2.16.840.1.101.3.4.2",
+                NistObjectIdentifiers.IdAes128Cbc,
+                NistObjectIdentifiers.IdAes128Cfb,
+                NistObjectIdentifiers.IdAes128Ecb,
+                NistObjectIdentifiers.IdAes128Ofb,
+                NistObjectIdentifiers.IdAes128Wrap);
+            AddKgAlgorithm("AES192",
+                "2.16.840.1.101.3.4.22",
+                NistObjectIdentifiers.IdAes192Cbc,
+                NistObjectIdentifiers.IdAes192Cfb,
+                NistObjectIdentifiers.IdAes192Ecb,
+                NistObjectIdentifiers.IdAes192Ofb,
+                NistObjectIdentifiers.IdAes192Wrap);
+            AddKgAlgorithm("AES256",
+                "2.16.840.1.101.3.4.42",
+                NistObjectIdentifiers.IdAes256Cbc,
+                NistObjectIdentifiers.IdAes256Cfb,
+                NistObjectIdentifiers.IdAes256Ecb,
+                NistObjectIdentifiers.IdAes256Ofb,
+                NistObjectIdentifiers.IdAes256Wrap);
+            AddKgAlgorithm("BLOWFISH",
+                "1.3.6.1.4.1.3029.1.2");
+            AddKgAlgorithm("CAMELLIA",
+                "CAMELLIAWRAP");
+            AddKgAlgorithm("CAMELLIA128",
+                NttObjectIdentifiers.IdCamellia128Cbc,
+                NttObjectIdentifiers.IdCamellia128Wrap);
+            AddKgAlgorithm("CAMELLIA192",
+                NttObjectIdentifiers.IdCamellia192Cbc,
+                NttObjectIdentifiers.IdCamellia192Wrap);
+            AddKgAlgorithm("CAMELLIA256",
+                NttObjectIdentifiers.IdCamellia256Cbc,
+                NttObjectIdentifiers.IdCamellia256Wrap);
+            AddKgAlgorithm("CAST5",
+                "1.2.840.113533.7.66.10");
+            AddKgAlgorithm("CAST6");
+            AddKgAlgorithm("DES",
+                OiwObjectIdentifiers.DesCbc,
+                OiwObjectIdentifiers.DesCfb,
+                OiwObjectIdentifiers.DesEcb,
+                OiwObjectIdentifiers.DesOfb);
+            AddKgAlgorithm("DESEDE",
+                "DESEDEWRAP",
+                "TDEA",
+                OiwObjectIdentifiers.DesEde);
+            AddKgAlgorithm("DESEDE3",
+                PkcsObjectIdentifiers.DesEde3Cbc,
+                PkcsObjectIdentifiers.IdAlgCms3DesWrap);
+            AddKgAlgorithm("GOST28147",
+                "GOST",
+                "GOST-28147",
+                CryptoProObjectIdentifiers.GostR28147Cbc);
+            AddKgAlgorithm("HC128");
+            AddKgAlgorithm("HC256");
+            AddKgAlgorithm("IDEA",
+                "1.3.6.1.4.1.188.7.1.1.2");
+            AddKgAlgorithm("NOEKEON");
+            AddKgAlgorithm("RC2",
+                PkcsObjectIdentifiers.RC2Cbc,
+                PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
+            AddKgAlgorithm("RC4",
+                "ARC4",
+                "1.2.840.113549.3.4");
+            AddKgAlgorithm("RC5",
+                "RC5-32");
+            AddKgAlgorithm("RC5-64");
+            AddKgAlgorithm("RC6");
+            AddKgAlgorithm("RIJNDAEL");
+            AddKgAlgorithm("SALSA20");
+            AddKgAlgorithm("SEED",
+                KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
+                KisaObjectIdentifiers.IdSeedCbc);
+            AddKgAlgorithm("SERPENT");
+            AddKgAlgorithm("SKIPJACK");
+            AddKgAlgorithm("TEA");
+            AddKgAlgorithm("TWOFISH");
+            AddKgAlgorithm("VMPC");
+            AddKgAlgorithm("VMPC-KSA3");
+            AddKgAlgorithm("XTEA");
+
+            //
+            // HMac key generators
+            //
+            AddHMacKeyGenerator("MD2");
+            AddHMacKeyGenerator("MD4");
+            AddHMacKeyGenerator("MD5",
+                IanaObjectIdentifiers.HmacMD5);
+            AddHMacKeyGenerator("SHA1",
+                PkcsObjectIdentifiers.IdHmacWithSha1,
+                IanaObjectIdentifiers.HmacSha1);
+            AddHMacKeyGenerator("SHA224",
+                PkcsObjectIdentifiers.IdHmacWithSha224);
+            AddHMacKeyGenerator("SHA256",
+                PkcsObjectIdentifiers.IdHmacWithSha256);
+            AddHMacKeyGenerator("SHA384",
+                PkcsObjectIdentifiers.IdHmacWithSha384);
+            AddHMacKeyGenerator("SHA512",
+                PkcsObjectIdentifiers.IdHmacWithSha512);
+            AddHMacKeyGenerator("SHA512/224");
+            AddHMacKeyGenerator("SHA512/256");
+            AddHMacKeyGenerator("SHA3-224");
+            AddHMacKeyGenerator("SHA3-256");
+            AddHMacKeyGenerator("SHA3-384");
+            AddHMacKeyGenerator("SHA3-512");
+            AddHMacKeyGenerator("RIPEMD128");
+            AddHMacKeyGenerator("RIPEMD160",
+                IanaObjectIdentifiers.HmacRipeMD160);
+            AddHMacKeyGenerator("TIGER",
+                IanaObjectIdentifiers.HmacTiger);
+
+
+
+            //
+            // key pair generators.
+            //
+            AddKpgAlgorithm("DH",
+                "DIFFIEHELLMAN");
+            AddKpgAlgorithm("DSA");
+            AddKpgAlgorithm("EC",
+                // TODO Should this be an alias for ECDH?
+                X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme);
+            AddKpgAlgorithm("ECDH",
+                "ECIES");
+            AddKpgAlgorithm("ECDHC");
+            AddKpgAlgorithm("ECMQV",
+                X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme);
+            AddKpgAlgorithm("ECDSA");
+            AddKpgAlgorithm("ECGOST3410",
+                "ECGOST-3410",
+                "GOST-3410-2001");
+            AddKpgAlgorithm("ELGAMAL");
+            AddKpgAlgorithm("GOST3410",
                 "GOST-3410",
-				"GOST-3410-94");
-			AddKpgAlgorithm("RSA",
-				"1.2.840.113549.1.1.1");
-
-			AddDefaultKeySizeEntries(64, "DES");
-			AddDefaultKeySizeEntries(80, "SKIPJACK");
-			AddDefaultKeySizeEntries(128, "AES128", "BLOWFISH", "CAMELLIA128", "CAST5", "DESEDE",
-				"HC128", "HMACMD2", "HMACMD4", "HMACMD5", "HMACRIPEMD128", "IDEA", "NOEKEON",
-				"RC2", "RC4", "RC5", "SALSA20", "SEED", "TEA", "XTEA", "VMPC", "VMPC-KSA3");
-			AddDefaultKeySizeEntries(160, "HMACRIPEMD160", "HMACSHA1");
-			AddDefaultKeySizeEntries(192, "AES", "AES192", "CAMELLIA192", "DESEDE3", "HMACTIGER",
-				"RIJNDAEL", "SERPENT");
-			AddDefaultKeySizeEntries(224, "HMACSHA224");
-			AddDefaultKeySizeEntries(256, "AES256", "CAMELLIA", "CAMELLIA256", "CAST6", "GOST28147",
-				"HC256", "HMACSHA256", "RC5-64", "RC6", "TWOFISH");
-			AddDefaultKeySizeEntries(384, "HMACSHA384");
-			AddDefaultKeySizeEntries(512, "HMACSHA512");
-		}
-
-		private static void AddDefaultKeySizeEntries(int size, params string[] algorithms)
-		{
-			foreach (string algorithm in algorithms)
-			{
-				defaultKeySizes.Add(algorithm, size);
-			}
-		}
-
-		private static void AddKgAlgorithm(
-			string			canonicalName,
-			params object[] aliases)
-		{
-			kgAlgorithms[canonicalName] = canonicalName;
-
-			foreach (object alias in aliases)
-			{
-				kgAlgorithms[alias.ToString()] = canonicalName;
-			}
-		}
-
-		private static void AddKpgAlgorithm(
-			string			canonicalName,
-			params object[] aliases)
-		{
-			kpgAlgorithms[canonicalName] = canonicalName;
-
-			foreach (object alias in aliases)
-			{
-				kpgAlgorithms[alias.ToString()] = canonicalName;
-			}
-		}
-
-		private static void AddHMacKeyGenerator(
-			string			algorithm,
-			params object[]	aliases)
-		{
-			string mainName = "HMAC" + algorithm;
-
-			kgAlgorithms[mainName] = mainName;
-			kgAlgorithms["HMAC-" + algorithm] = mainName;
-			kgAlgorithms["HMAC/" + algorithm] = mainName;
-
-			foreach (object alias in aliases)
-			{
-				kgAlgorithms[alias.ToString()] = mainName;
-			}
-		}
-
-		// TODO Consider making this public
-		internal static string GetCanonicalKeyGeneratorAlgorithm(
-			string algorithm)
-		{
-			return (string) kgAlgorithms[algorithm.ToUpperInvariant()];
-		}
-
-		// TODO Consider making this public
-		internal static string GetCanonicalKeyPairGeneratorAlgorithm(
-			string algorithm)
-		{
-			return (string) kpgAlgorithms[algorithm.ToUpperInvariant()];
-		}
-
-		public static CipherKeyGenerator GetKeyGenerator(
-			DerObjectIdentifier oid)
-		{
-			return GetKeyGenerator(oid.Id);
-		}
-
-		public static CipherKeyGenerator GetKeyGenerator(
-			string algorithm)
-		{
-			string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm);
-
-			if (canonicalName == null)
-				throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
-
-			int defaultKeySize = FindDefaultKeySize(canonicalName);
-			if (defaultKeySize == -1)
-				throw new SecurityUtilityException("KeyGenerator " + algorithm
-					+ " (" + canonicalName + ") not supported.");
-
-			if (canonicalName == "DES")
-				return new DesKeyGenerator(defaultKeySize);
-
-			if (canonicalName == "DESEDE" || canonicalName == "DESEDE3")
-				return new DesEdeKeyGenerator(defaultKeySize);
-
-			return new CipherKeyGenerator(defaultKeySize);
-		}
-
-		public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
-			DerObjectIdentifier oid)
-		{
-			return GetKeyPairGenerator(oid.Id);
-		}
-
-		public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
-			string algorithm)
-		{
-			string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm);
-
-			if (canonicalName == null)
-				throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised.");
-
-			if (canonicalName == "DH")
-				return new DHKeyPairGenerator();
-
-			if (canonicalName == "DSA")
-				return new DsaKeyPairGenerator();
-
-			// "EC", "ECDH", "ECDHC", "ECDSA", "ECGOST3410", "ECMQV"
-			if (canonicalName.StartsWith("EC"))
-				return new ECKeyPairGenerator(canonicalName);
-
-			if (canonicalName == "ELGAMAL")
-				return new ElGamalKeyPairGenerator();
-
-			if (canonicalName == "GOST3410")
-				return new Gost3410KeyPairGenerator();
-
-			if (canonicalName == "RSA")
-				return new RsaKeyPairGenerator();
-
-			throw new SecurityUtilityException("KeyPairGenerator " + algorithm
-				+ " (" + canonicalName + ") not supported.");
-		}
-
-		internal static int GetDefaultKeySize(
-			DerObjectIdentifier oid)
-		{
-			return GetDefaultKeySize(oid.Id);
-		}
-
-		internal static int GetDefaultKeySize(
-			string algorithm)
-		{
-			string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm);
-
-			if (canonicalName == null)
-				throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
-
-			int defaultKeySize = FindDefaultKeySize(canonicalName);
-			if (defaultKeySize == -1)
-				throw new SecurityUtilityException("KeyGenerator " + algorithm
-					+ " (" + canonicalName + ") not supported.");
-
-			return defaultKeySize;
-		}
-
-		private static int FindDefaultKeySize(
-			string canonicalName)
-		{
-			if (!defaultKeySizes.Contains(canonicalName))
-				return -1;
-
-			return (int)defaultKeySizes[canonicalName];
-		}
-	}
+                "GOST-3410-94");
+            AddKpgAlgorithm("RSA",
+                "1.2.840.113549.1.1.1");
+
+            AddDefaultKeySizeEntries(64, "DES");
+            AddDefaultKeySizeEntries(80, "SKIPJACK");
+            AddDefaultKeySizeEntries(128, "AES128", "BLOWFISH", "CAMELLIA128", "CAST5", "DESEDE",
+                "HC128", "HMACMD2", "HMACMD4", "HMACMD5", "HMACRIPEMD128", "IDEA", "NOEKEON",
+                "RC2", "RC4", "RC5", "SALSA20", "SEED", "TEA", "XTEA", "VMPC", "VMPC-KSA3");
+            AddDefaultKeySizeEntries(160, "HMACRIPEMD160", "HMACSHA1");
+            AddDefaultKeySizeEntries(192, "AES", "AES192", "CAMELLIA192", "DESEDE3", "HMACTIGER",
+                "RIJNDAEL", "SERPENT");
+            AddDefaultKeySizeEntries(224, "HMACSHA224");
+            AddDefaultKeySizeEntries(256, "AES256", "CAMELLIA", "CAMELLIA256", "CAST6", "GOST28147",
+                "HC256", "HMACSHA256", "RC5-64", "RC6", "TWOFISH");
+            AddDefaultKeySizeEntries(384, "HMACSHA384");
+            AddDefaultKeySizeEntries(512, "HMACSHA512");
+            AddDefaultKeySizeEntries(224, "HMACSHA512/224");
+            AddDefaultKeySizeEntries(256, "HMACSHA512/256");
+        }
+
+        private static void AddDefaultKeySizeEntries(int size, params string[] algorithms)
+        {
+            foreach (string algorithm in algorithms)
+            {
+                defaultKeySizes.Add(algorithm, size);
+            }
+        }
+
+        private static void AddKgAlgorithm(
+            string			canonicalName,
+            params object[] aliases)
+        {
+            kgAlgorithms[canonicalName] = canonicalName;
+
+            foreach (object alias in aliases)
+            {
+                kgAlgorithms[alias.ToString()] = canonicalName;
+            }
+        }
+
+        private static void AddKpgAlgorithm(
+            string			canonicalName,
+            params object[] aliases)
+        {
+            kpgAlgorithms[canonicalName] = canonicalName;
+
+            foreach (object alias in aliases)
+            {
+                kpgAlgorithms[alias.ToString()] = canonicalName;
+            }
+        }
+
+        private static void AddHMacKeyGenerator(
+            string			algorithm,
+            params object[]	aliases)
+        {
+            string mainName = "HMAC" + algorithm;
+
+            kgAlgorithms[mainName] = mainName;
+            kgAlgorithms["HMAC-" + algorithm] = mainName;
+            kgAlgorithms["HMAC/" + algorithm] = mainName;
+
+            foreach (object alias in aliases)
+            {
+                kgAlgorithms[alias.ToString()] = mainName;
+            }
+        }
+
+        // TODO Consider making this public
+        internal static string GetCanonicalKeyGeneratorAlgorithm(
+            string algorithm)
+        {
+            return (string) kgAlgorithms[Platform.ToUpperInvariant(algorithm)];
+        }
+
+        // TODO Consider making this public
+        internal static string GetCanonicalKeyPairGeneratorAlgorithm(
+            string algorithm)
+        {
+            return (string)kpgAlgorithms[Platform.ToUpperInvariant(algorithm)];
+        }
+
+        public static CipherKeyGenerator GetKeyGenerator(
+            DerObjectIdentifier oid)
+        {
+            return GetKeyGenerator(oid.Id);
+        }
+
+        public static CipherKeyGenerator GetKeyGenerator(
+            string algorithm)
+        {
+            string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm);
+
+            if (canonicalName == null)
+                throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
+
+            int defaultKeySize = FindDefaultKeySize(canonicalName);
+            if (defaultKeySize == -1)
+                throw new SecurityUtilityException("KeyGenerator " + algorithm
+                    + " (" + canonicalName + ") not supported.");
+
+            if (canonicalName == "DES")
+                return new DesKeyGenerator(defaultKeySize);
+
+            if (canonicalName == "DESEDE" || canonicalName == "DESEDE3")
+                return new DesEdeKeyGenerator(defaultKeySize);
+
+            return new CipherKeyGenerator(defaultKeySize);
+        }
+
+        public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
+            DerObjectIdentifier oid)
+        {
+            return GetKeyPairGenerator(oid.Id);
+        }
+
+        public static IAsymmetricCipherKeyPairGenerator GetKeyPairGenerator(
+            string algorithm)
+        {
+            string canonicalName = GetCanonicalKeyPairGeneratorAlgorithm(algorithm);
+
+            if (canonicalName == null)
+                throw new SecurityUtilityException("KeyPairGenerator " + algorithm + " not recognised.");
+
+            if (canonicalName == "DH")
+                return new DHKeyPairGenerator();
+
+            if (canonicalName == "DSA")
+                return new DsaKeyPairGenerator();
+
+            // "EC", "ECDH", "ECDHC", "ECDSA", "ECGOST3410", "ECMQV"
+            if (canonicalName.StartsWith("EC"))
+                return new ECKeyPairGenerator(canonicalName);
+
+            if (canonicalName == "ELGAMAL")
+                return new ElGamalKeyPairGenerator();
+
+            if (canonicalName == "GOST3410")
+                return new Gost3410KeyPairGenerator();
+
+            if (canonicalName == "RSA")
+                return new RsaKeyPairGenerator();
+
+            throw new SecurityUtilityException("KeyPairGenerator " + algorithm
+                + " (" + canonicalName + ") not supported.");
+        }
+
+        internal static int GetDefaultKeySize(
+            DerObjectIdentifier oid)
+        {
+            return GetDefaultKeySize(oid.Id);
+        }
+
+        internal static int GetDefaultKeySize(
+            string algorithm)
+        {
+            string canonicalName = GetCanonicalKeyGeneratorAlgorithm(algorithm);
+
+            if (canonicalName == null)
+                throw new SecurityUtilityException("KeyGenerator " + algorithm + " not recognised.");
+
+            int defaultKeySize = FindDefaultKeySize(canonicalName);
+            if (defaultKeySize == -1)
+                throw new SecurityUtilityException("KeyGenerator " + algorithm
+                    + " (" + canonicalName + ") not supported.");
+
+            return defaultKeySize;
+        }
+
+        private static int FindDefaultKeySize(
+            string canonicalName)
+        {
+            if (!defaultKeySizes.Contains(canonicalName))
+                return -1;
+
+            return (int)defaultKeySizes[canonicalName];
+        }
+    }
 }
diff --git a/crypto/src/security/InvalidKeyException.cs b/crypto/src/security/InvalidKeyException.cs
index 97d48e091..4d4488ef2 100644
--- a/crypto/src/security/InvalidKeyException.cs
+++ b/crypto/src/security/InvalidKeyException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security
 {
-	public class InvalidKeyException : KeyException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class InvalidKeyException : KeyException
 	{
 		public InvalidKeyException() : base() { }
 		public InvalidKeyException(string message) : base(message) { }
diff --git a/crypto/src/security/InvalidParameterException.cs b/crypto/src/security/InvalidParameterException.cs
index 08ca4a076..57a912d03 100644
--- a/crypto/src/security/InvalidParameterException.cs
+++ b/crypto/src/security/InvalidParameterException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security
 {
-	public class InvalidParameterException : KeyException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class InvalidParameterException : KeyException
 	{
 		public InvalidParameterException() : base() { }
 		public InvalidParameterException(string message) : base(message) { }
diff --git a/crypto/src/security/KeyException.cs b/crypto/src/security/KeyException.cs
index f19264e5f..9304c1c4d 100644
--- a/crypto/src/security/KeyException.cs
+++ b/crypto/src/security/KeyException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security
 {
-	public class KeyException : GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class KeyException : GeneralSecurityException
 	{
 		public KeyException() : base() { }
 		public KeyException(string message) : base(message) { }
diff --git a/crypto/src/security/MacUtilities.cs b/crypto/src/security/MacUtilities.cs
index 8550d7550..d1f8c89b4 100644
--- a/crypto/src/security/MacUtilities.cs
+++ b/crypto/src/security/MacUtilities.cs
@@ -1,5 +1,4 @@
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Iana;
@@ -12,64 +11,65 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
-	/// <remarks>
-	///  Utility class for creating HMac object from their names/Oids
-	/// </remarks>
-	public sealed class MacUtilities
-	{
-		private MacUtilities()
-		{
-		}
-
-		private static readonly IDictionary algorithms = Platform.CreateHashtable();
+    /// <remarks>
+    ///  Utility class for creating HMac object from their names/Oids
+    /// </remarks>
+    public sealed class MacUtilities
+    {
+        private MacUtilities()
+        {
+        }
+
+        private static readonly IDictionary algorithms = Platform.CreateHashtable();
         //private static readonly IDictionary oids = Platform.CreateHashtable();
 
-		static MacUtilities()
-		{
-			algorithms[IanaObjectIdentifiers.HmacMD5.Id] = "HMAC-MD5";
-			algorithms[IanaObjectIdentifiers.HmacRipeMD160.Id] = "HMAC-RIPEMD160";
-			algorithms[IanaObjectIdentifiers.HmacSha1.Id] = "HMAC-SHA1";
-			algorithms[IanaObjectIdentifiers.HmacTiger.Id] = "HMAC-TIGER";
-
-			algorithms[PkcsObjectIdentifiers.IdHmacWithSha1.Id] = "HMAC-SHA1";
-			algorithms[PkcsObjectIdentifiers.IdHmacWithSha224.Id] = "HMAC-SHA224";
-			algorithms[PkcsObjectIdentifiers.IdHmacWithSha256.Id] = "HMAC-SHA256";
-			algorithms[PkcsObjectIdentifiers.IdHmacWithSha384.Id] = "HMAC-SHA384";
-			algorithms[PkcsObjectIdentifiers.IdHmacWithSha512.Id] = "HMAC-SHA512";
-
-			// TODO AESMAC?
-
-			algorithms["DES"] = "DESMAC";
-			algorithms["DES/CFB8"] = "DESMAC/CFB8";
-			algorithms["DES64"] = "DESMAC64";
-			algorithms["DESEDE"] = "DESEDEMAC";
-			algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDEMAC";
-			algorithms["DESEDE/CFB8"] = "DESEDEMAC/CFB8";
-			algorithms["DESISO9797MAC"] = "DESWITHISO9797";
-			algorithms["DESEDE64"] = "DESEDEMAC64";
-
-			algorithms["DESEDE64WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
-			algorithms["DESEDEISO9797ALG1MACWITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
-			algorithms["DESEDEISO9797ALG1WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
-
-			algorithms["ISO9797ALG3"] = "ISO9797ALG3MAC";
-			algorithms["ISO9797ALG3MACWITHISO7816-4PADDING"] = "ISO9797ALG3WITHISO7816-4PADDING";
-
-			algorithms["SKIPJACK"] = "SKIPJACKMAC";
-			algorithms["SKIPJACK/CFB8"] = "SKIPJACKMAC/CFB8";
-			algorithms["IDEA"] = "IDEAMAC";
-			algorithms["IDEA/CFB8"] = "IDEAMAC/CFB8";
-			algorithms["RC2"] = "RC2MAC";
-			algorithms["RC2/CFB8"] = "RC2MAC/CFB8";
-			algorithms["RC5"] = "RC5MAC";
-			algorithms["RC5/CFB8"] = "RC5MAC/CFB8";
-			algorithms["GOST28147"] = "GOST28147MAC";
-			algorithms["VMPC"] = "VMPCMAC";
-			algorithms["VMPC-MAC"] = "VMPCMAC";
-
-			algorithms["PBEWITHHMACSHA"] = "PBEWITHHMACSHA1";
-			algorithms["1.3.14.3.2.26"] = "PBEWITHHMACSHA1";
-		}
+        static MacUtilities()
+        {
+            algorithms[IanaObjectIdentifiers.HmacMD5.Id] = "HMAC-MD5";
+            algorithms[IanaObjectIdentifiers.HmacRipeMD160.Id] = "HMAC-RIPEMD160";
+            algorithms[IanaObjectIdentifiers.HmacSha1.Id] = "HMAC-SHA1";
+            algorithms[IanaObjectIdentifiers.HmacTiger.Id] = "HMAC-TIGER";
+
+            algorithms[PkcsObjectIdentifiers.IdHmacWithSha1.Id] = "HMAC-SHA1";
+            algorithms[PkcsObjectIdentifiers.IdHmacWithSha224.Id] = "HMAC-SHA224";
+            algorithms[PkcsObjectIdentifiers.IdHmacWithSha256.Id] = "HMAC-SHA256";
+            algorithms[PkcsObjectIdentifiers.IdHmacWithSha384.Id] = "HMAC-SHA384";
+            algorithms[PkcsObjectIdentifiers.IdHmacWithSha512.Id] = "HMAC-SHA512";
+
+            // TODO AESMAC?
+
+            algorithms["DES"] = "DESMAC";
+            algorithms["DES/CFB8"] = "DESMAC/CFB8";
+            algorithms["DES64"] = "DESMAC64";
+            algorithms["DESEDE"] = "DESEDEMAC";
+            algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "DESEDEMAC";
+            algorithms["DESEDE/CFB8"] = "DESEDEMAC/CFB8";
+            algorithms["DESISO9797MAC"] = "DESWITHISO9797";
+            algorithms["DESEDE64"] = "DESEDEMAC64";
+
+            algorithms["DESEDE64WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+            algorithms["DESEDEISO9797ALG1MACWITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+            algorithms["DESEDEISO9797ALG1WITHISO7816-4PADDING"] = "DESEDEMAC64WITHISO7816-4PADDING";
+
+            algorithms["ISO9797ALG3"] = "ISO9797ALG3MAC";
+            algorithms["ISO9797ALG3MACWITHISO7816-4PADDING"] = "ISO9797ALG3WITHISO7816-4PADDING";
+
+            algorithms["SKIPJACK"] = "SKIPJACKMAC";
+            algorithms["SKIPJACK/CFB8"] = "SKIPJACKMAC/CFB8";
+            algorithms["IDEA"] = "IDEAMAC";
+            algorithms["IDEA/CFB8"] = "IDEAMAC/CFB8";
+            algorithms["RC2"] = "RC2MAC";
+            algorithms["RC2/CFB8"] = "RC2MAC/CFB8";
+            algorithms["RC5"] = "RC5MAC";
+            algorithms["RC5/CFB8"] = "RC5MAC/CFB8";
+            algorithms["GOST28147"] = "GOST28147MAC";
+            algorithms["VMPC"] = "VMPCMAC";
+            algorithms["VMPC-MAC"] = "VMPCMAC";
+            algorithms["SIPHASH"] = "SIPHASH-2-4";
+
+            algorithms["PBEWITHHMACSHA"] = "PBEWITHHMACSHA1";
+            algorithms["1.3.14.3.2.26"] = "PBEWITHHMACSHA1";
+        }
 
 //		/// <summary>
 //		/// Returns a ObjectIdentifier for a given digest mechanism.
@@ -79,7 +79,7 @@ namespace Org.BouncyCastle.Security
 //		public static DerObjectIdentifier GetObjectIdentifier(
 //			string mechanism)
 //		{
-//			mechanism = (string) algorithms[mechanism.ToUpperInvariant()];
+//			mechanism = (string) algorithms[Platform.ToUpperInvariant(mechanism)];
 //
 //			if (mechanism != null)
 //			{
@@ -94,146 +94,153 @@ namespace Org.BouncyCastle.Security
 //			get { return oids.Keys; }
 //		}
 
-		public static IMac GetMac(
-			DerObjectIdentifier id)
-		{
-			return GetMac(id.Id);
-		}
-
-		public static IMac GetMac(
-			string algorithm)
-		{
-			string upper = algorithm.ToUpperInvariant();
-
-			string mechanism = (string) algorithms[upper];
-
-			if (mechanism == null)
-			{
-				mechanism = upper;
-			}
-
-			if (mechanism.StartsWith("PBEWITH"))
-			{
-				mechanism = mechanism.Substring("PBEWITH".Length);
-			}
-
-			if (mechanism.StartsWith("HMAC"))
-			{
-				string digestName;
-				if (mechanism.StartsWith("HMAC-") || mechanism.StartsWith("HMAC/"))
-				{
-					digestName = mechanism.Substring(5);
-				}
-				else
-				{
-					digestName = mechanism.Substring(4);
-				}
-
-				return new HMac(DigestUtilities.GetDigest(digestName));
-			}
-
-			if (mechanism == "AESCMAC")
-			{
-				return new CMac(new AesFastEngine());
-			}
-			if (mechanism == "DESMAC")
-			{
-				return new CbcBlockCipherMac(new DesEngine());
-			}
-			if (mechanism == "DESMAC/CFB8")
-			{
-				return new CfbBlockCipherMac(new DesEngine());
-			}
-			if (mechanism == "DESMAC64")
-			{
-				return new CbcBlockCipherMac(new DesEngine(), 64);
-			}
-			if (mechanism == "DESEDECMAC")
-			{
-				return new CMac(new DesEdeEngine());
-			}
-			if (mechanism == "DESEDEMAC")
-			{
-				return new CbcBlockCipherMac(new DesEdeEngine());
-			}
-			if (mechanism == "DESEDEMAC/CFB8")
-			{
-				return new CfbBlockCipherMac(new DesEdeEngine());
-			}
-			if (mechanism == "DESEDEMAC64")
-			{
-				return new CbcBlockCipherMac(new DesEdeEngine(), 64);
-			}
-			if (mechanism == "DESEDEMAC64WITHISO7816-4PADDING")
-			{
-				return new CbcBlockCipherMac(new DesEdeEngine(), 64, new ISO7816d4Padding());
-			}
-			if (mechanism == "DESWITHISO9797"
-				|| mechanism == "ISO9797ALG3MAC")
-			{
-				return new ISO9797Alg3Mac(new DesEngine());
-			}
-			if (mechanism == "ISO9797ALG3WITHISO7816-4PADDING")
-			{
-				return new ISO9797Alg3Mac(new DesEngine(), new ISO7816d4Padding());
-			}
-			if (mechanism == "SKIPJACKMAC")
-			{
-				return new CbcBlockCipherMac(new SkipjackEngine());
-			}
-			if (mechanism == "SKIPJACKMAC/CFB8")
-			{
-				return new CfbBlockCipherMac(new SkipjackEngine());
-			}
-#if INCLUDE_IDEA
-			if (mechanism == "IDEAMAC")
-			{
-				return new CbcBlockCipherMac(new IdeaEngine());
-			}
-			if (mechanism == "IDEAMAC/CFB8")
-			{
-				return new CfbBlockCipherMac(new IdeaEngine());
-			}
-#endif
-			if (mechanism == "RC2MAC")
-			{
-				return new CbcBlockCipherMac(new RC2Engine());
-			}
-			if (mechanism == "RC2MAC/CFB8")
-			{
-				return new CfbBlockCipherMac(new RC2Engine());
-			}
-			if (mechanism == "RC5MAC")
-			{
-				return new CbcBlockCipherMac(new RC532Engine());
-			}
-			if (mechanism == "RC5MAC/CFB8")
-			{
-				return new CfbBlockCipherMac(new RC532Engine());
-			}
-			if (mechanism == "GOST28147MAC")
-			{
-				return new Gost28147Mac();
-			}
-			if (mechanism == "VMPCMAC")
-			{
-				return new VmpcMac();
-			}
-			throw new SecurityUtilityException("Mac " + mechanism + " not recognised.");
-		}
-
-		public static string GetAlgorithmName(
-			DerObjectIdentifier oid)
-		{
-			return (string) algorithms[oid.Id];
-		}
-
-		public static byte[] DoFinal(
-			IMac mac)
-		{
-			byte[] b = new byte[mac.GetMacSize()];
-			mac.DoFinal(b, 0);
-			return b;
-		}
-	}
+        public static IMac GetMac(
+            DerObjectIdentifier id)
+        {
+            return GetMac(id.Id);
+        }
+
+        public static IMac GetMac(
+            string algorithm)
+        {
+            string upper = Platform.ToUpperInvariant(algorithm);
+
+            string mechanism = (string) algorithms[upper];
+
+            if (mechanism == null)
+            {
+                mechanism = upper;
+            }
+
+            if (mechanism.StartsWith("PBEWITH"))
+            {
+                mechanism = mechanism.Substring("PBEWITH".Length);
+            }
+
+            if (mechanism.StartsWith("HMAC"))
+            {
+                string digestName;
+                if (mechanism.StartsWith("HMAC-") || mechanism.StartsWith("HMAC/"))
+                {
+                    digestName = mechanism.Substring(5);
+                }
+                else
+                {
+                    digestName = mechanism.Substring(4);
+                }
+
+                return new HMac(DigestUtilities.GetDigest(digestName));
+            }
+
+            if (mechanism == "AESCMAC")
+            {
+                return new CMac(new AesFastEngine());
+            }
+            if (mechanism == "DESMAC")
+            {
+                return new CbcBlockCipherMac(new DesEngine());
+            }
+            if (mechanism == "DESMAC/CFB8")
+            {
+                return new CfbBlockCipherMac(new DesEngine());
+            }
+            if (mechanism == "DESMAC64")
+            {
+                return new CbcBlockCipherMac(new DesEngine(), 64);
+            }
+            if (mechanism == "DESEDECMAC")
+            {
+                return new CMac(new DesEdeEngine());
+            }
+            if (mechanism == "DESEDEMAC")
+            {
+                return new CbcBlockCipherMac(new DesEdeEngine());
+            }
+            if (mechanism == "DESEDEMAC/CFB8")
+            {
+                return new CfbBlockCipherMac(new DesEdeEngine());
+            }
+            if (mechanism == "DESEDEMAC64")
+            {
+                return new CbcBlockCipherMac(new DesEdeEngine(), 64);
+            }
+            if (mechanism == "DESEDEMAC64WITHISO7816-4PADDING")
+            {
+                return new CbcBlockCipherMac(new DesEdeEngine(), 64, new ISO7816d4Padding());
+            }
+            if (mechanism == "DESWITHISO9797"
+                || mechanism == "ISO9797ALG3MAC")
+            {
+                return new ISO9797Alg3Mac(new DesEngine());
+            }
+            if (mechanism == "ISO9797ALG3WITHISO7816-4PADDING")
+            {
+                return new ISO9797Alg3Mac(new DesEngine(), new ISO7816d4Padding());
+            }
+            if (mechanism == "SKIPJACKMAC")
+            {
+                return new CbcBlockCipherMac(new SkipjackEngine());
+            }
+            if (mechanism == "SKIPJACKMAC/CFB8")
+            {
+                return new CfbBlockCipherMac(new SkipjackEngine());
+            }
+            if (mechanism == "IDEAMAC")
+            {
+                return new CbcBlockCipherMac(new IdeaEngine());
+            }
+            if (mechanism == "IDEAMAC/CFB8")
+            {
+                return new CfbBlockCipherMac(new IdeaEngine());
+            }
+            if (mechanism == "RC2MAC")
+            {
+                return new CbcBlockCipherMac(new RC2Engine());
+            }
+            if (mechanism == "RC2MAC/CFB8")
+            {
+                return new CfbBlockCipherMac(new RC2Engine());
+            }
+            if (mechanism == "RC5MAC")
+            {
+                return new CbcBlockCipherMac(new RC532Engine());
+            }
+            if (mechanism == "RC5MAC/CFB8")
+            {
+                return new CfbBlockCipherMac(new RC532Engine());
+            }
+            if (mechanism == "GOST28147MAC")
+            {
+                return new Gost28147Mac();
+            }
+            if (mechanism == "VMPCMAC")
+            {
+                return new VmpcMac();
+            }
+            if (mechanism == "SIPHASH-2-4")
+            {
+                return new SipHash();
+            }
+            throw new SecurityUtilityException("Mac " + mechanism + " not recognised.");
+        }
+
+        public static string GetAlgorithmName(
+            DerObjectIdentifier oid)
+        {
+            return (string) algorithms[oid.Id];
+        }
+
+        public static byte[] DoFinal(IMac mac)
+        {
+            byte[] b = new byte[mac.GetMacSize()];
+            mac.DoFinal(b, 0);
+            return b;
+        }
+
+        public static byte[] DoFinal(IMac mac, byte[] input)
+        {
+            mac.BlockUpdate(input, 0, input.Length);
+            return DoFinal(mac);
+        }
+    }
 }
diff --git a/crypto/src/security/NoSuchAlgorithmException.cs b/crypto/src/security/NoSuchAlgorithmException.cs
index 25c0ab04f..d120c5f77 100644
--- a/crypto/src/security/NoSuchAlgorithmException.cs
+++ b/crypto/src/security/NoSuchAlgorithmException.cs
@@ -3,7 +3,10 @@ using System;
 namespace Org.BouncyCastle.Security
 {
 	[Obsolete("Never thrown")]
-	public class NoSuchAlgorithmException : GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class NoSuchAlgorithmException : GeneralSecurityException
 	{
 		public NoSuchAlgorithmException() : base() {}
 		public NoSuchAlgorithmException(string message) : base(message) {}
diff --git a/crypto/src/security/ParameterUtilities.cs b/crypto/src/security/ParameterUtilities.cs
index b44fbda73..b2d7c0dff 100644
--- a/crypto/src/security/ParameterUtilities.cs
+++ b/crypto/src/security/ParameterUtilities.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
@@ -16,312 +15,307 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
-	public sealed class ParameterUtilities
-	{
-		private ParameterUtilities()
-		{
-		}
-
-		private static readonly IDictionary algorithms = Platform.CreateHashtable();
-		private static readonly IDictionary basicIVSizes = Platform.CreateHashtable();
-
-		static ParameterUtilities()
-		{
-			AddAlgorithm("AES",
-				"AESWRAP");
-			AddAlgorithm("AES128",
-				"2.16.840.1.101.3.4.2",
-				NistObjectIdentifiers.IdAes128Cbc,
-				NistObjectIdentifiers.IdAes128Cfb,
-				NistObjectIdentifiers.IdAes128Ecb,
-				NistObjectIdentifiers.IdAes128Ofb,
-				NistObjectIdentifiers.IdAes128Wrap);
-			AddAlgorithm("AES192",
-				"2.16.840.1.101.3.4.22",
-				NistObjectIdentifiers.IdAes192Cbc,
-				NistObjectIdentifiers.IdAes192Cfb,
-				NistObjectIdentifiers.IdAes192Ecb,
-				NistObjectIdentifiers.IdAes192Ofb,
-				NistObjectIdentifiers.IdAes192Wrap);
-			AddAlgorithm("AES256",
-				"2.16.840.1.101.3.4.42",
-				NistObjectIdentifiers.IdAes256Cbc,
-				NistObjectIdentifiers.IdAes256Cfb,
-				NistObjectIdentifiers.IdAes256Ecb,
-				NistObjectIdentifiers.IdAes256Ofb,
-				NistObjectIdentifiers.IdAes256Wrap);
-			AddAlgorithm("BLOWFISH",
-				"1.3.6.1.4.1.3029.1.2");
-			AddAlgorithm("CAMELLIA",
-				"CAMELLIAWRAP");
-			AddAlgorithm("CAMELLIA128",
-				NttObjectIdentifiers.IdCamellia128Cbc,
-				NttObjectIdentifiers.IdCamellia128Wrap);
-			AddAlgorithm("CAMELLIA192",
-				NttObjectIdentifiers.IdCamellia192Cbc,
-				NttObjectIdentifiers.IdCamellia192Wrap);
-			AddAlgorithm("CAMELLIA256",
-				NttObjectIdentifiers.IdCamellia256Cbc,
-				NttObjectIdentifiers.IdCamellia256Wrap);
-			AddAlgorithm("CAST5",
-				"1.2.840.113533.7.66.10");
-			AddAlgorithm("CAST6");
-			AddAlgorithm("DES",
-				OiwObjectIdentifiers.DesCbc,
-				OiwObjectIdentifiers.DesCfb,
-				OiwObjectIdentifiers.DesEcb,
-				OiwObjectIdentifiers.DesOfb);
-			AddAlgorithm("DESEDE",
-				"DESEDEWRAP",
-				OiwObjectIdentifiers.DesEde,
-				PkcsObjectIdentifiers.IdAlgCms3DesWrap);
-			AddAlgorithm("DESEDE3",
-				PkcsObjectIdentifiers.DesEde3Cbc);
-			AddAlgorithm("GOST28147",
-				"GOST",
-				"GOST-28147",
-				CryptoProObjectIdentifiers.GostR28147Cbc);
-			AddAlgorithm("HC128");
-			AddAlgorithm("HC256");
-#if INCLUDE_IDEA
-			AddAlgorithm("IDEA",
-				"1.3.6.1.4.1.188.7.1.1.2");
-#endif
-			AddAlgorithm("NOEKEON");
-			AddAlgorithm("RC2",
-				PkcsObjectIdentifiers.RC2Cbc,
-				PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
-			AddAlgorithm("RC4",
-				"ARC4",
-				"1.2.840.113549.3.4");
-			AddAlgorithm("RC5",
-				"RC5-32");
-			AddAlgorithm("RC5-64");
-			AddAlgorithm("RC6");
-			AddAlgorithm("RIJNDAEL");
-			AddAlgorithm("SALSA20");
-			AddAlgorithm("SEED",
-				KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
-				KisaObjectIdentifiers.IdSeedCbc);
-			AddAlgorithm("SERPENT");
-			AddAlgorithm("SKIPJACK");
-			AddAlgorithm("TEA");
-			AddAlgorithm("TWOFISH");
-			AddAlgorithm("VMPC");
-			AddAlgorithm("VMPC-KSA3");
-			AddAlgorithm("XTEA");
-
-			AddBasicIVSizeEntries(8, "BLOWFISH", "DES", "DESEDE", "DESEDE3");
-			AddBasicIVSizeEntries(16, "AES", "AES128", "AES192", "AES256",
-				"CAMELLIA", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "NOEKEON", "SEED");
-
-			// TODO These algorithms support an IV
-			// but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
-			// "RIJNDAEL", "SKIPJACK", "TWOFISH"
-		}
-
-		private static void AddAlgorithm(
-			string			canonicalName,
-			params object[]	aliases)
-		{
-			algorithms[canonicalName] = canonicalName;
-
-			foreach (object alias in aliases)
-			{
-				algorithms[alias.ToString()] = canonicalName;
-			}
-		}
-
-		private static void AddBasicIVSizeEntries(int size, params string[] algorithms)
-		{
-			foreach (string algorithm in algorithms)
-			{
-				basicIVSizes.Add(algorithm, size);
-			}
-		}
-
-		public static string GetCanonicalAlgorithmName(
-			string algorithm)
-		{
-			return (string) algorithms[algorithm.ToUpperInvariant()];
-		}
-
-		public static KeyParameter CreateKeyParameter(
-			DerObjectIdentifier algOid,
-			byte[]				keyBytes)
-		{
-			return CreateKeyParameter(algOid.Id, keyBytes, 0, keyBytes.Length);
-		}
-
-		public static KeyParameter CreateKeyParameter(
-			string	algorithm,
-			byte[]	keyBytes)
-		{
-			return CreateKeyParameter(algorithm, keyBytes, 0, keyBytes.Length);
-		}
-
-		public static KeyParameter CreateKeyParameter(
-			DerObjectIdentifier algOid,
-			byte[]				keyBytes,
-			int					offset,
-			int					length)
-		{
-			return CreateKeyParameter(algOid.Id, keyBytes, offset, length);
-		}
-
-		public static KeyParameter CreateKeyParameter(
-			string	algorithm,
-			byte[]	keyBytes,
-			int		offset,
-			int		length)
-		{
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-
-			string canonical = GetCanonicalAlgorithmName(algorithm);
-
-			if (canonical == null)
-				throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
-
-			if (canonical == "DES")
-				return new DesParameters(keyBytes, offset, length);
-
-			if (canonical == "DESEDE" || canonical =="DESEDE3")
-				return new DesEdeParameters(keyBytes, offset, length);
-
-			if (canonical == "RC2")
-				return new RC2Parameters(keyBytes, offset, length);
-
-			return new KeyParameter(keyBytes, offset, length);
-		}
-
-		public static ICipherParameters GetCipherParameters(
-			DerObjectIdentifier	algOid,
-			ICipherParameters	key,
-			Asn1Object			asn1Params)
-		{
-			return GetCipherParameters(algOid.Id, key, asn1Params);
-		}
-
-		public static ICipherParameters GetCipherParameters(
-			string				algorithm,
-			ICipherParameters	key,
-			Asn1Object			asn1Params)
-		{
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-
-			string canonical = GetCanonicalAlgorithmName(algorithm);
-
-			if (canonical == null)
-				throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
-
-			byte[] iv = null;
-
-			try
-			{
-				// TODO These algorithms support an IV
-				// but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
-				// "RIJNDAEL", "SKIPJACK", "TWOFISH"
-
-				int basicIVKeySize = FindBasicIVSize(canonical);
-				if (basicIVKeySize != -1
-					|| canonical == "RIJNDAEL" || canonical == "SKIPJACK" || canonical == "TWOFISH")
-				{
-					iv = ((Asn1OctetString) asn1Params).GetOctets();
-				}
-				else if (canonical == "CAST5")
-				{
-					iv = Cast5CbcParameters.GetInstance(asn1Params).GetIV();
-				}
-#if INCLUDE_IDEA
-				else if (canonical == "IDEA")
-				{
-					iv = IdeaCbcPar.GetInstance(asn1Params).GetIV();
-				}
-#endif
-				else if (canonical == "RC2")
-				{
-					iv = RC2CbcParameter.GetInstance(asn1Params).GetIV();
-				}
-			}
-			catch (Exception e)
-			{
-				throw new ArgumentException("Could not process ASN.1 parameters", e);
-			}
-
-			if (iv != null)
-			{
-				return new ParametersWithIV(key, iv);
-			}
-
-			throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
-		}
-
-		public static Asn1Encodable GenerateParameters(
-			DerObjectIdentifier algID,
-			SecureRandom		random)
-		{
-			return GenerateParameters(algID.Id, random);
-		}
-
-		public static Asn1Encodable GenerateParameters(
-			string			algorithm,
-			SecureRandom	random)
-		{
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-
-			string canonical = GetCanonicalAlgorithmName(algorithm);
-
-			if (canonical == null)
-				throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
-
-			// TODO These algorithms support an IV
-			// but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
-			// "RIJNDAEL", "SKIPJACK", "TWOFISH"
-
-			int basicIVKeySize = FindBasicIVSize(canonical);
-			if (basicIVKeySize != -1)
-				return CreateIVOctetString(random, basicIVKeySize);
-
-			if (canonical == "CAST5")
-				return new Cast5CbcParameters(CreateIV(random, 8), 128);
-
-#if INCLUDE_IDEA
-			if (canonical == "IDEA")
-				return new IdeaCbcPar(CreateIV(random, 8));
-#endif
-
-			if (canonical == "RC2")
-				return new RC2CbcParameter(CreateIV(random, 8));
-
-			throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
-		}
-
-		private static Asn1OctetString CreateIVOctetString(
-			SecureRandom	random,
-			int				ivLength)
-		{
-			return new DerOctetString(CreateIV(random, ivLength));
-		}
-
-		private static byte[] CreateIV(
-			SecureRandom	random,
-			int				ivLength)
-		{
-			byte[] iv = new byte[ivLength];
-			random.NextBytes(iv);
-			return iv;
-		}
-
-		private static int FindBasicIVSize(
-			string canonicalName)
-		{
-			if (!basicIVSizes.Contains(canonicalName))
-				return -1;
-
-			return (int)basicIVSizes[canonicalName];
-		}
-	}
+    public sealed class ParameterUtilities
+    {
+        private ParameterUtilities()
+        {
+        }
+
+        private static readonly IDictionary algorithms = Platform.CreateHashtable();
+        private static readonly IDictionary basicIVSizes = Platform.CreateHashtable();
+
+        static ParameterUtilities()
+        {
+            AddAlgorithm("AES",
+                "AESWRAP");
+            AddAlgorithm("AES128",
+                "2.16.840.1.101.3.4.2",
+                NistObjectIdentifiers.IdAes128Cbc,
+                NistObjectIdentifiers.IdAes128Cfb,
+                NistObjectIdentifiers.IdAes128Ecb,
+                NistObjectIdentifiers.IdAes128Ofb,
+                NistObjectIdentifiers.IdAes128Wrap);
+            AddAlgorithm("AES192",
+                "2.16.840.1.101.3.4.22",
+                NistObjectIdentifiers.IdAes192Cbc,
+                NistObjectIdentifiers.IdAes192Cfb,
+                NistObjectIdentifiers.IdAes192Ecb,
+                NistObjectIdentifiers.IdAes192Ofb,
+                NistObjectIdentifiers.IdAes192Wrap);
+            AddAlgorithm("AES256",
+                "2.16.840.1.101.3.4.42",
+                NistObjectIdentifiers.IdAes256Cbc,
+                NistObjectIdentifiers.IdAes256Cfb,
+                NistObjectIdentifiers.IdAes256Ecb,
+                NistObjectIdentifiers.IdAes256Ofb,
+                NistObjectIdentifiers.IdAes256Wrap);
+            AddAlgorithm("BLOWFISH",
+                "1.3.6.1.4.1.3029.1.2");
+            AddAlgorithm("CAMELLIA",
+                "CAMELLIAWRAP");
+            AddAlgorithm("CAMELLIA128",
+                NttObjectIdentifiers.IdCamellia128Cbc,
+                NttObjectIdentifiers.IdCamellia128Wrap);
+            AddAlgorithm("CAMELLIA192",
+                NttObjectIdentifiers.IdCamellia192Cbc,
+                NttObjectIdentifiers.IdCamellia192Wrap);
+            AddAlgorithm("CAMELLIA256",
+                NttObjectIdentifiers.IdCamellia256Cbc,
+                NttObjectIdentifiers.IdCamellia256Wrap);
+            AddAlgorithm("CAST5",
+                "1.2.840.113533.7.66.10");
+            AddAlgorithm("CAST6");
+            AddAlgorithm("DES",
+                OiwObjectIdentifiers.DesCbc,
+                OiwObjectIdentifiers.DesCfb,
+                OiwObjectIdentifiers.DesEcb,
+                OiwObjectIdentifiers.DesOfb);
+            AddAlgorithm("DESEDE",
+                "DESEDEWRAP",
+                "TDEA",
+                OiwObjectIdentifiers.DesEde,
+                PkcsObjectIdentifiers.IdAlgCms3DesWrap);
+            AddAlgorithm("DESEDE3",
+                PkcsObjectIdentifiers.DesEde3Cbc);
+            AddAlgorithm("GOST28147",
+                "GOST",
+                "GOST-28147",
+                CryptoProObjectIdentifiers.GostR28147Cbc);
+            AddAlgorithm("HC128");
+            AddAlgorithm("HC256");
+            AddAlgorithm("IDEA",
+                "1.3.6.1.4.1.188.7.1.1.2");
+            AddAlgorithm("NOEKEON");
+            AddAlgorithm("RC2",
+                PkcsObjectIdentifiers.RC2Cbc,
+                PkcsObjectIdentifiers.IdAlgCmsRC2Wrap);
+            AddAlgorithm("RC4",
+                "ARC4",
+                "1.2.840.113549.3.4");
+            AddAlgorithm("RC5",
+                "RC5-32");
+            AddAlgorithm("RC5-64");
+            AddAlgorithm("RC6");
+            AddAlgorithm("RIJNDAEL");
+            AddAlgorithm("SALSA20");
+            AddAlgorithm("SEED",
+                KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap,
+                KisaObjectIdentifiers.IdSeedCbc);
+            AddAlgorithm("SERPENT");
+            AddAlgorithm("SKIPJACK");
+            AddAlgorithm("TEA");
+            AddAlgorithm("TWOFISH");
+            AddAlgorithm("VMPC");
+            AddAlgorithm("VMPC-KSA3");
+            AddAlgorithm("XTEA");
+
+            AddBasicIVSizeEntries(8, "BLOWFISH", "DES", "DESEDE", "DESEDE3");
+            AddBasicIVSizeEntries(16, "AES", "AES128", "AES192", "AES256",
+                "CAMELLIA", "CAMELLIA128", "CAMELLIA192", "CAMELLIA256", "NOEKEON", "SEED");
+
+            // TODO These algorithms support an IV
+            // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
+            // "RIJNDAEL", "SKIPJACK", "TWOFISH"
+        }
+
+        private static void AddAlgorithm(
+            string			canonicalName,
+            params object[]	aliases)
+        {
+            algorithms[canonicalName] = canonicalName;
+
+            foreach (object alias in aliases)
+            {
+                algorithms[alias.ToString()] = canonicalName;
+            }
+        }
+
+        private static void AddBasicIVSizeEntries(int size, params string[] algorithms)
+        {
+            foreach (string algorithm in algorithms)
+            {
+                basicIVSizes.Add(algorithm, size);
+            }
+        }
+
+        public static string GetCanonicalAlgorithmName(
+            string algorithm)
+        {
+            return (string) algorithms[Platform.ToUpperInvariant(algorithm)];
+        }
+
+        public static KeyParameter CreateKeyParameter(
+            DerObjectIdentifier algOid,
+            byte[]				keyBytes)
+        {
+            return CreateKeyParameter(algOid.Id, keyBytes, 0, keyBytes.Length);
+        }
+
+        public static KeyParameter CreateKeyParameter(
+            string	algorithm,
+            byte[]	keyBytes)
+        {
+            return CreateKeyParameter(algorithm, keyBytes, 0, keyBytes.Length);
+        }
+
+        public static KeyParameter CreateKeyParameter(
+            DerObjectIdentifier algOid,
+            byte[]				keyBytes,
+            int					offset,
+            int					length)
+        {
+            return CreateKeyParameter(algOid.Id, keyBytes, offset, length);
+        }
+
+        public static KeyParameter CreateKeyParameter(
+            string	algorithm,
+            byte[]	keyBytes,
+            int		offset,
+            int		length)
+        {
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+
+            string canonical = GetCanonicalAlgorithmName(algorithm);
+
+            if (canonical == null)
+                throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+            if (canonical == "DES")
+                return new DesParameters(keyBytes, offset, length);
+
+            if (canonical == "DESEDE" || canonical =="DESEDE3")
+                return new DesEdeParameters(keyBytes, offset, length);
+
+            if (canonical == "RC2")
+                return new RC2Parameters(keyBytes, offset, length);
+
+            return new KeyParameter(keyBytes, offset, length);
+        }
+
+        public static ICipherParameters GetCipherParameters(
+            DerObjectIdentifier	algOid,
+            ICipherParameters	key,
+            Asn1Object			asn1Params)
+        {
+            return GetCipherParameters(algOid.Id, key, asn1Params);
+        }
+
+        public static ICipherParameters GetCipherParameters(
+            string				algorithm,
+            ICipherParameters	key,
+            Asn1Object			asn1Params)
+        {
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+
+            string canonical = GetCanonicalAlgorithmName(algorithm);
+
+            if (canonical == null)
+                throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+            byte[] iv = null;
+
+            try
+            {
+                // TODO These algorithms support an IV
+                // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
+                // "RIJNDAEL", "SKIPJACK", "TWOFISH"
+
+                int basicIVKeySize = FindBasicIVSize(canonical);
+                if (basicIVKeySize != -1
+                    || canonical == "RIJNDAEL" || canonical == "SKIPJACK" || canonical == "TWOFISH")
+                {
+                    iv = ((Asn1OctetString) asn1Params).GetOctets();
+                }
+                else if (canonical == "CAST5")
+                {
+                    iv = Cast5CbcParameters.GetInstance(asn1Params).GetIV();
+                }
+                else if (canonical == "IDEA")
+                {
+                    iv = IdeaCbcPar.GetInstance(asn1Params).GetIV();
+                }
+                else if (canonical == "RC2")
+                {
+                    iv = RC2CbcParameter.GetInstance(asn1Params).GetIV();
+                }
+            }
+            catch (Exception e)
+            {
+                throw new ArgumentException("Could not process ASN.1 parameters", e);
+            }
+
+            if (iv != null)
+            {
+                return new ParametersWithIV(key, iv);
+            }
+
+            throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+        }
+
+        public static Asn1Encodable GenerateParameters(
+            DerObjectIdentifier algID,
+            SecureRandom		random)
+        {
+            return GenerateParameters(algID.Id, random);
+        }
+
+        public static Asn1Encodable GenerateParameters(
+            string			algorithm,
+            SecureRandom	random)
+        {
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+
+            string canonical = GetCanonicalAlgorithmName(algorithm);
+
+            if (canonical == null)
+                throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+
+            // TODO These algorithms support an IV
+            // but JCE doesn't seem to provide an AlgorithmParametersGenerator for them
+            // "RIJNDAEL", "SKIPJACK", "TWOFISH"
+
+            int basicIVKeySize = FindBasicIVSize(canonical);
+            if (basicIVKeySize != -1)
+                return CreateIVOctetString(random, basicIVKeySize);
+
+            if (canonical == "CAST5")
+                return new Cast5CbcParameters(CreateIV(random, 8), 128);
+
+            if (canonical == "IDEA")
+                return new IdeaCbcPar(CreateIV(random, 8));
+
+            if (canonical == "RC2")
+                return new RC2CbcParameter(CreateIV(random, 8));
+
+            throw new SecurityUtilityException("Algorithm " + algorithm + " not recognised.");
+        }
+
+        private static Asn1OctetString CreateIVOctetString(
+            SecureRandom	random,
+            int				ivLength)
+        {
+            return new DerOctetString(CreateIV(random, ivLength));
+        }
+
+        private static byte[] CreateIV(
+            SecureRandom	random,
+            int				ivLength)
+        {
+            byte[] iv = new byte[ivLength];
+            random.NextBytes(iv);
+            return iv;
+        }
+
+        private static int FindBasicIVSize(
+            string canonicalName)
+        {
+            if (!basicIVSizes.Contains(canonicalName))
+                return -1;
+
+            return (int)basicIVSizes[canonicalName];
+        }
+    }
 }
diff --git a/crypto/src/security/PbeUtilities.cs b/crypto/src/security/PbeUtilities.cs
index f59ab104b..56d68ba0a 100644
--- a/crypto/src/security/PbeUtilities.cs
+++ b/crypto/src/security/PbeUtilities.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.BC;
@@ -21,638 +20,644 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
-	/// <summary>
-	///
-	/// </summary>
-	public sealed class PbeUtilities
-	{
-		private PbeUtilities()
-		{
-		}
-
-		const string Pkcs5S1 = "Pkcs5S1";
-		const string Pkcs5S2 = "Pkcs5S2";
-		const string Pkcs12 = "Pkcs12";
-		const string OpenSsl = "OpenSsl";
-
-		private static readonly IDictionary algorithms = Platform.CreateHashtable();
+    /// <summary>
+    ///
+    /// </summary>
+    public sealed class PbeUtilities
+    {
+        private PbeUtilities()
+        {
+        }
+
+        const string Pkcs5S1 = "Pkcs5S1";
+        const string Pkcs5S2 = "Pkcs5S2";
+        const string Pkcs12 = "Pkcs12";
+        const string OpenSsl = "OpenSsl";
+
+        private static readonly IDictionary algorithms = Platform.CreateHashtable();
         private static readonly IDictionary algorithmType = Platform.CreateHashtable();
         private static readonly IDictionary oids = Platform.CreateHashtable();
 
-		static PbeUtilities()
-		{
-			algorithms["PKCS5SCHEME1"] = "Pkcs5scheme1";
-			algorithms["PKCS5SCHEME2"] = "Pkcs5scheme2";
-			algorithms[PkcsObjectIdentifiers.IdPbeS2.Id] = "Pkcs5scheme2";
+        static PbeUtilities()
+        {
+            algorithms["PKCS5SCHEME1"] = "Pkcs5scheme1";
+            algorithms["PKCS5SCHEME2"] = "Pkcs5scheme2";
+            algorithms[PkcsObjectIdentifiers.IdPbeS2.Id] = "Pkcs5scheme2";
 //			algorithms[PkcsObjectIdentifiers.IdPbkdf2.Id] = "Pkcs5scheme2";
 
-			// FIXME Add support for these? (see Pkcs8Generator)
+            // FIXME Add support for these? (see Pkcs8Generator)
 //			algorithms[PkcsObjectIdentifiers.DesEde3Cbc.Id] = "Pkcs5scheme2";
 //			algorithms[NistObjectIdentifiers.IdAes128Cbc.Id] = "Pkcs5scheme2";
 //			algorithms[NistObjectIdentifiers.IdAes192Cbc.Id] = "Pkcs5scheme2";
 //			algorithms[NistObjectIdentifiers.IdAes256Cbc.Id] = "Pkcs5scheme2";
 
-			algorithms["PBEWITHMD2ANDDES-CBC"] = "PBEwithMD2andDES-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithMD2AndDesCbc.Id] = "PBEwithMD2andDES-CBC";
-			algorithms["PBEWITHMD2ANDRC2-CBC"] = "PBEwithMD2andRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc.Id] = "PBEwithMD2andRC2-CBC";
-			algorithms["PBEWITHMD5ANDDES-CBC"] = "PBEwithMD5andDES-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithMD5AndDesCbc.Id] = "PBEwithMD5andDES-CBC";
-			algorithms["PBEWITHMD5ANDRC2-CBC"] = "PBEwithMD5andRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc.Id] = "PBEwithMD5andRC2-CBC";
-			algorithms["PBEWITHSHA1ANDDES"] = "PBEwithSHA-1andDES-CBC";
-			algorithms["PBEWITHSHA-1ANDDES"] = "PBEwithSHA-1andDES-CBC";
-			algorithms["PBEWITHSHA1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
-			algorithms["PBEWITHSHA-1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEwithSHA-1andDES-CBC";
-			algorithms["PBEWITHSHA1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
-			algorithms["PBEWITHSHA-1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
-			algorithms["PBEWITHSHA1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
-			algorithms["PBEWITHSHA-1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEwithSHA-1andRC2-CBC";
-			algorithms["PKCS12"] = "Pkcs12";
-			algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.Id] = "PBEWITHSHAAND128BITAES-CBC-BC";
-			algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.Id] = "PBEWITHSHAAND192BITAES-CBC-BC";
-			algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.Id] = "PBEWITHSHAAND256BITAES-CBC-BC";
-			algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.Id] = "PBEWITHSHA256AND128BITAES-CBC-BC";
-			algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.Id] = "PBEWITHSHA256AND192BITAES-CBC-BC";
-			algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.Id] = "PBEWITHSHA256AND256BITAES-CBC-BC";
-			algorithms["PBEWITHSHAAND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
-			algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
-			algorithms["PBEWITHSHA-1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEwithSHA-1and128bitRC4";
-			algorithms["PBEWITHSHAAND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
-			algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
-			algorithms["PBEWITHSHA-1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEwithSHA-1and40bitRC4";
-			algorithms["PBEWITHSHAAND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
-			algorithms["PBEWITHSHAAND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA-1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA-1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEwithSHA-1and3-keyDESEDE-CBC";
-			algorithms["PBEWITHSHAAND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
-			algorithms["PBEWITHSHAAND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA-1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
-			algorithms["PBEWITHSHA-1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEwithSHA-1and2-keyDESEDE-CBC";
-			algorithms["PBEWITHSHAAND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
-			algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
-			algorithms["PBEWITHSHA-1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEwithSHA-1and128bitRC2-CBC";
-			algorithms["PBEWITHSHAAND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
-			algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
-			algorithms["PBEWITHSHA-1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
-			algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEwithSHA-1and40bitRC2-CBC";
-			algorithms["PBEWITHSHAAND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
-			algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
-			algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
-			algorithms["PBEWITHSHAAND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
-			algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
-			algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
-			algorithms["PBEWITHSHAAND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
-			algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
-			algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
-			algorithms["PBEWITHSHA256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
-			algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
-			algorithms["PBEWITHSHA256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
-			algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
-			algorithms["PBEWITHSHA256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
-			algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
-			algorithms["PBEWITHSHAANDIDEA"] = "PBEwithSHA-1andIDEA-CBC";
-			algorithms["PBEWITHSHAANDIDEA-CBC"] = "PBEwithSHA-1andIDEA-CBC";
-			algorithms["PBEWITHSHAANDTWOFISH"] = "PBEwithSHA-1andTWOFISH-CBC";
-			algorithms["PBEWITHSHAANDTWOFISH-CBC"] = "PBEwithSHA-1andTWOFISH-CBC";
-			algorithms["PBEWITHHMACSHA1"] = "PBEwithHmacSHA-1";
-			algorithms["PBEWITHHMACSHA-1"] = "PBEwithHmacSHA-1";
-			algorithms[OiwObjectIdentifiers.IdSha1.Id] = "PBEwithHmacSHA-1";
-			algorithms["PBEWITHHMACSHA224"] = "PBEwithHmacSHA-224";
-			algorithms["PBEWITHHMACSHA-224"] = "PBEwithHmacSHA-224";
-			algorithms[NistObjectIdentifiers.IdSha224.Id] = "PBEwithHmacSHA-224";
-			algorithms["PBEWITHHMACSHA256"] = "PBEwithHmacSHA-256";
-			algorithms["PBEWITHHMACSHA-256"] = "PBEwithHmacSHA-256";
-			algorithms[NistObjectIdentifiers.IdSha256.Id] = "PBEwithHmacSHA-256";
-			algorithms["PBEWITHHMACRIPEMD128"] = "PBEwithHmacRipeMD128";
-			algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "PBEwithHmacRipeMD128";
-			algorithms["PBEWITHHMACRIPEMD160"] = "PBEwithHmacRipeMD160";
-			algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "PBEwithHmacRipeMD160";
-			algorithms["PBEWITHHMACRIPEMD256"] = "PBEwithHmacRipeMD256";
-			algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "PBEwithHmacRipeMD256";
-			algorithms["PBEWITHHMACTIGER"] = "PBEwithHmacTiger";
-
-			algorithms["PBEWITHMD5AND128BITAES-CBC-OPENSSL"] = "PBEwithMD5and128bitAES-CBC-OpenSSL";
-			algorithms["PBEWITHMD5AND192BITAES-CBC-OPENSSL"] = "PBEwithMD5and192bitAES-CBC-OpenSSL";
-			algorithms["PBEWITHMD5AND256BITAES-CBC-OPENSSL"] = "PBEwithMD5and256bitAES-CBC-OpenSSL";
-
-			algorithmType["Pkcs5scheme1"] = Pkcs5S1;
-			algorithmType["Pkcs5scheme2"] = Pkcs5S2;
-			algorithmType["PBEwithMD2andDES-CBC"] = Pkcs5S1;
-			algorithmType["PBEwithMD2andRC2-CBC"] = Pkcs5S1;
-			algorithmType["PBEwithMD5andDES-CBC"] = Pkcs5S1;
-			algorithmType["PBEwithMD5andRC2-CBC"] = Pkcs5S1;
-			algorithmType["PBEwithSHA-1andDES-CBC"] = Pkcs5S1;
-			algorithmType["PBEwithSHA-1andRC2-CBC"] = Pkcs5S1;
-			algorithmType["Pkcs12"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and128bitRC4"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and40bitRC4"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and3-keyDESEDE-CBC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and2-keyDESEDE-CBC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and128bitRC2-CBC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and40bitRC2-CBC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and128bitAES-CBC-BC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and192bitAES-CBC-BC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1and256bitAES-CBC-BC"] = Pkcs12;
-			algorithmType["PBEwithSHA-256and128bitAES-CBC-BC"] = Pkcs12;
-			algorithmType["PBEwithSHA-256and192bitAES-CBC-BC"] = Pkcs12;
-			algorithmType["PBEwithSHA-256and256bitAES-CBC-BC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1andIDEA-CBC"] = Pkcs12;
-			algorithmType["PBEwithSHA-1andTWOFISH-CBC"] = Pkcs12;
-			algorithmType["PBEwithHmacSHA-1"] = Pkcs12;
-			algorithmType["PBEwithHmacSHA-224"] = Pkcs12;
-			algorithmType["PBEwithHmacSHA-256"] = Pkcs12;
-			algorithmType["PBEwithHmacRipeMD128"] = Pkcs12;
-			algorithmType["PBEwithHmacRipeMD160"] = Pkcs12;
-			algorithmType["PBEwithHmacRipeMD256"] = Pkcs12;
-			algorithmType["PBEwithHmacTiger"] = Pkcs12;
-
-			algorithmType["PBEwithMD5and128bitAES-CBC-OpenSSL"] = OpenSsl;
-			algorithmType["PBEwithMD5and192bitAES-CBC-OpenSSL"] = OpenSsl;
-			algorithmType["PBEwithMD5and256bitAES-CBC-OpenSSL"] = OpenSsl;
-
-			oids["PBEwithMD2andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndDesCbc;
-			oids["PBEwithMD2andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc;
-			oids["PBEwithMD5andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndDesCbc;
-			oids["PBEwithMD5andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc;
-			oids["PBEwithSHA-1andDES-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndDesCbc;
-			oids["PBEwithSHA-1andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc;
-			oids["PBEwithSHA-1and128bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4;
-			oids["PBEwithSHA-1and40bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4;
-			oids["PBEwithSHA-1and3-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
-			oids["PBEwithSHA-1and2-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc;
-			oids["PBEwithSHA-1and128bitRC2-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc;
-			oids["PBEwithSHA-1and40bitRC2-CBC"] = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
-			oids["PBEwithHmacSHA-1"] = OiwObjectIdentifiers.IdSha1;
-			oids["PBEwithHmacSHA-224"] = NistObjectIdentifiers.IdSha224;
-			oids["PBEwithHmacSHA-256"] = NistObjectIdentifiers.IdSha256;
-			oids["PBEwithHmacRipeMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
-			oids["PBEwithHmacRipeMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
-			oids["PBEwithHmacRipeMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
-			oids["Pkcs5scheme2"] = PkcsObjectIdentifiers.IdPbeS2;
-		}
-
-		static PbeParametersGenerator MakePbeGenerator(
-			string	type,
-			IDigest	digest,
-			byte[]	key,
-			byte[]	salt,
-			int		iterationCount)
-		{
-			PbeParametersGenerator generator;
-
-			if (type.Equals(Pkcs5S1))
-			{
-				generator = new Pkcs5S1ParametersGenerator(digest);
-			}
-			else if (type.Equals(Pkcs5S2))
-			{
-				generator = new Pkcs5S2ParametersGenerator();
-			}
-			else if (type.Equals(Pkcs12))
-			{
-				generator = new Pkcs12ParametersGenerator(digest);
-			}
-			else if (type.Equals(OpenSsl))
-			{
-				generator = new OpenSslPbeParametersGenerator();
-			}
-			else
-			{
-				throw new ArgumentException("Unknown PBE type: " + type, "type");
-			}
-
-			generator.Init(key, salt, iterationCount);
-			return generator;
-		}
-
-		/// <summary>
-		/// Returns a ObjectIdentifier for a give encoding.
-		/// </summary>
-		/// <param name="mechanism">A string representation of the encoding.</param>
-		/// <returns>A DerObjectIdentifier, null if the Oid is not available.</returns>
-		public static DerObjectIdentifier GetObjectIdentifier(
-			string mechanism)
-		{
-			mechanism = (string) algorithms[mechanism.ToUpperInvariant()];
-			if (mechanism != null)
-			{
-				return (DerObjectIdentifier)oids[mechanism];
-			}
-			return null;
-		}
-
-		public static ICollection Algorithms
-		{
-			get { return oids.Keys; }
-		}
-
-		public static bool IsPkcs12(
-			string algorithm)
-		{
-			string mechanism = (string) algorithms[algorithm.ToUpperInvariant()];
-
-			return mechanism != null && Pkcs12.Equals(algorithmType[mechanism]);
-		}
-
-		public static bool IsPkcs5Scheme1(
-			string algorithm)
-		{
-			string mechanism = (string)algorithms[algorithm.ToUpperInvariant()];
-
-			return mechanism != null && Pkcs5S1.Equals(algorithmType[mechanism]);
-		}
-
-		public static bool IsPkcs5Scheme2(
-			string algorithm)
-		{
-			string mechanism = (string)algorithms[algorithm.ToUpperInvariant()];
-
-			return mechanism != null && Pkcs5S2.Equals(algorithmType[mechanism]);
-		}
-
-		public static bool IsOpenSsl(
-			string algorithm)
-		{
-			string mechanism = (string)algorithms[algorithm.ToUpperInvariant()];
-
-			return mechanism != null && OpenSsl.Equals(algorithmType[mechanism]);
-		}
-
-		public static bool IsPbeAlgorithm(
-			string algorithm)
-		{
-			string mechanism = (string)algorithms[algorithm.ToUpperInvariant()];
-
-			return mechanism != null && algorithmType[mechanism] != null;
-		}
-
-		public static Asn1Encodable GenerateAlgorithmParameters(
-			DerObjectIdentifier algorithmOid,
-			byte[]              salt,
-			int                 iterationCount)
-		{
-			return GenerateAlgorithmParameters(algorithmOid.Id, salt, iterationCount);
-		}
-
-		public static Asn1Encodable GenerateAlgorithmParameters(
-			string  algorithm,
-			byte[]  salt,
-			int     iterationCount)
-		{
-			if (IsPkcs12(algorithm))
-			{
-				return new Pkcs12PbeParams(salt, iterationCount);
-			}
-			else if (IsPkcs5Scheme2(algorithm))
-			{
-				return new Pbkdf2Params(salt, iterationCount);
-			}
-			else
-			{
-				return new PbeParameter(salt, iterationCount);
-			}
-		}
-
-		public static ICipherParameters GenerateCipherParameters(
-			DerObjectIdentifier algorithmOid,
-			char[]              password,
-			Asn1Encodable       pbeParameters)
-		{
-			return GenerateCipherParameters(algorithmOid.Id, password, false, pbeParameters);
-		}
-
-		public static ICipherParameters GenerateCipherParameters(
-			DerObjectIdentifier algorithmOid,
-			char[]              password,
-			bool				wrongPkcs12Zero,
-			Asn1Encodable       pbeParameters)
-		{
-			return GenerateCipherParameters(algorithmOid.Id, password, wrongPkcs12Zero, pbeParameters);
-		}
-
-		public static ICipherParameters GenerateCipherParameters(
-			AlgorithmIdentifier algID,
-			char[]              password)
-		{
-			return GenerateCipherParameters(algID.ObjectID.Id, password, false, algID.Parameters);
-		}
-
-		public static ICipherParameters GenerateCipherParameters(
-			AlgorithmIdentifier algID,
-			char[]              password,
-			bool				wrongPkcs12Zero)
-		{
-			return GenerateCipherParameters(algID.ObjectID.Id, password, wrongPkcs12Zero, algID.Parameters);
-		}
-
-		public static ICipherParameters GenerateCipherParameters(
-			string          algorithm,
-			char[]          password,
-			Asn1Encodable   pbeParameters)
-		{
-			return GenerateCipherParameters(algorithm, password, false, pbeParameters);
-		}
-
-		public static ICipherParameters GenerateCipherParameters(
-			string          algorithm,
-			char[]          password,
-			bool			wrongPkcs12Zero,
-			Asn1Encodable   pbeParameters)
-		{
-			string	mechanism = (string) algorithms[algorithm.ToUpperInvariant()];
-
-			byte[] keyBytes = null;
-			byte[] salt = null;
-			int iterationCount = 0;
-
-			if (IsPkcs12(mechanism))
-			{
-				Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(pbeParameters);
-				salt = pbeParams.GetIV();
-				iterationCount = pbeParams.Iterations.IntValue;
-				keyBytes = PbeParametersGenerator.Pkcs12PasswordToBytes(password, wrongPkcs12Zero);
-			}
-			else if (IsPkcs5Scheme2(mechanism))
-			{
-				// See below
-			}
-			else
-			{
-				PbeParameter pbeParams = PbeParameter.GetInstance(pbeParameters);
-				salt = pbeParams.GetSalt();
-				iterationCount = pbeParams.IterationCount.IntValue;
-				keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
-			}
-
-			ICipherParameters parameters = null;
-
-			if (IsPkcs5Scheme2(mechanism))
-			{
-				PbeS2Parameters s2p = PbeS2Parameters.GetInstance(pbeParameters.ToAsn1Object());
-				AlgorithmIdentifier encScheme = s2p.EncryptionScheme;
-				DerObjectIdentifier encOid = encScheme.ObjectID;
-				Asn1Object encParams = encScheme.Parameters.ToAsn1Object();
-
-				// TODO What about s2p.KeyDerivationFunc.ObjectID?
-				Pbkdf2Params pbeParams = Pbkdf2Params.GetInstance(s2p.KeyDerivationFunc.Parameters.ToAsn1Object());
-
-				byte[] iv;
-				if (encOid.Equals(PkcsObjectIdentifiers.RC2Cbc)) // PKCS5.B.2.3
-				{
-					RC2CbcParameter rc2Params = RC2CbcParameter.GetInstance(encParams);
-					iv = rc2Params.GetIV();
-				}
-				else
-				{
-					iv = Asn1OctetString.GetInstance(encParams).GetOctets();
-				}
-
-				salt = pbeParams.GetSalt();
-				iterationCount = pbeParams.IterationCount.IntValue;
-				keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
-
-				int keyLength = pbeParams.KeyLength != null
-					?	pbeParams.KeyLength.IntValue * 8
-					:	GeneratorUtilities.GetDefaultKeySize(encOid);
-
-				PbeParametersGenerator gen = MakePbeGenerator(
-					(string)algorithmType[mechanism], null, keyBytes, salt, iterationCount);
-
-				parameters = gen.GenerateDerivedParameters(encOid.Id, keyLength);
-
-				if (iv != null)
-				{
-					// FIXME? OpenSSL weirdness with IV of zeros (for ECB keys?)
-					if (Arrays.AreEqual(iv, new byte[iv.Length]))
-					{
-						//Console.Error.Write("***** IV all 0 (length " + iv.Length + ") *****");
-					}
-					else
-					{
-						parameters = new ParametersWithIV(parameters, iv);
-					}
-				}
-			}
-			else if (mechanism.StartsWith("PBEwithSHA-1"))
-			{
-				PbeParametersGenerator generator = MakePbeGenerator(
-					(string) algorithmType[mechanism], new Sha1Digest(), keyBytes, salt, iterationCount);
-
-				if (mechanism.Equals("PBEwithSHA-1and128bitRC4"))
-				{
-					parameters = generator.GenerateDerivedParameters("RC4", 128);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and40bitRC4"))
-				{
-					parameters = generator.GenerateDerivedParameters("RC4", 40);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and3-keyDESEDE-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("DESEDE", 192, 64);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and2-keyDESEDE-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("DESEDE", 128, 64);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and128bitRC2-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("RC2", 128, 64);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and40bitRC2-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("RC2", 40, 64);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1andDES-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("DES", 64, 64);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1andRC2-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and128bitAES-CBC-BC"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 128, 128);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and192bitAES-CBC-BC"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 192, 128);
-				}
-				else if (mechanism.Equals("PBEwithSHA-1and256bitAES-CBC-BC"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 256, 128);
-				}
-			}
-			else if (mechanism.StartsWith("PBEwithSHA-256"))
-			{
-				PbeParametersGenerator generator = MakePbeGenerator(
-					(string) algorithmType[mechanism], new Sha256Digest(), keyBytes, salt, iterationCount);
-
-				if (mechanism.Equals("PBEwithSHA-256and128bitAES-CBC-BC"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 128, 128);
-				}
-				else if (mechanism.Equals("PBEwithSHA-256and192bitAES-CBC-BC"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 192, 128);
-				}
-				else if (mechanism.Equals("PBEwithSHA-256and256bitAES-CBC-BC"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 256, 128);
-				}
-			}
-			else if (mechanism.StartsWith("PBEwithMD5"))
-			{
-				PbeParametersGenerator generator = MakePbeGenerator(
-					(string)algorithmType[mechanism], new MD5Digest(), keyBytes, salt, iterationCount);
-
-				if (mechanism.Equals("PBEwithMD5andDES-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("DES", 64, 64);
-				}
-				else if (mechanism.Equals("PBEwithMD5andRC2-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
-				}
-				else if (mechanism.Equals("PBEwithMD5and128bitAES-CBC-OpenSSL"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 128, 128);
-				}
-				else if (mechanism.Equals("PBEwithMD5and192bitAES-CBC-OpenSSL"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 192, 128);
-				}
-				else if (mechanism.Equals("PBEwithMD5and256bitAES-CBC-OpenSSL"))
-				{
-					parameters = generator.GenerateDerivedParameters("AES", 256, 128);
-				}
-			}
-			else if (mechanism.StartsWith("PBEwithMD2"))
-			{
-				PbeParametersGenerator generator = MakePbeGenerator(
-					(string)algorithmType[mechanism], new MD2Digest(), keyBytes, salt, iterationCount);
-				if (mechanism.Equals("PBEwithMD2andDES-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("DES", 64, 64);
-				}
-				else if (mechanism.Equals("PBEwithMD2andRC2-CBC"))
-				{
-					parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
-				}
-			}
-			else if (mechanism.StartsWith("PBEwithHmac"))
-			{
-				string digestName = mechanism.Substring("PBEwithHmac".Length);
-				IDigest digest = DigestUtilities.GetDigest(digestName);
-
-				PbeParametersGenerator generator = MakePbeGenerator(
-					(string) algorithmType[mechanism], digest, keyBytes, salt, iterationCount);
-
-				int bitLen = digest.GetDigestSize() * 8;
-				parameters = generator.GenerateDerivedMacParameters(bitLen);
-			}
-
-			Array.Clear(keyBytes, 0, keyBytes.Length);
-
-			return FixDesParity(mechanism, parameters);
-		}
-
-		public static object CreateEngine(
-			DerObjectIdentifier algorithmOid)
-		{
-			return CreateEngine(algorithmOid.Id);
-		}
-
-		public static object CreateEngine(
-			AlgorithmIdentifier algID)
-		{
-			string algorithm = algID.ObjectID.Id;
-
-			if (IsPkcs5Scheme2(algorithm))
-			{
-				PbeS2Parameters s2p = PbeS2Parameters.GetInstance(algID.Parameters.ToAsn1Object());
-				AlgorithmIdentifier encScheme = s2p.EncryptionScheme;
-				return CipherUtilities.GetCipher(encScheme.ObjectID);
-			}
-
-			return CreateEngine(algorithm);
-		}
-
-		public static object CreateEngine(
-			string algorithm)
-		{
-			string mechanism = (string)algorithms[algorithm.ToUpperInvariant()];
-
-			if (mechanism.StartsWith("PBEwithHmac"))
-			{
-				string digestName = mechanism.Substring("PBEwithHmac".Length);
-
-				return MacUtilities.GetMac("HMAC/" + digestName);
-			}
-
-			if (mechanism.StartsWith("PBEwithMD2")
-				||	mechanism.StartsWith("PBEwithMD5")
-				||	mechanism.StartsWith("PBEwithSHA-1"))
-			{
-				if (mechanism.EndsWith("RC2-CBC"))
-				{
-					return CipherUtilities.GetCipher("RC2/CBC");
-				}
-
-				if (mechanism.EndsWith("RC4"))
-				{
-					return CipherUtilities.GetCipher("RC4");
-				}
-
-				if (mechanism.EndsWith("DES-CBC"))
-				{
-					return CipherUtilities.GetCipher("DES/CBC");
-				}
-
-				if (mechanism.EndsWith("DESEDE-CBC"))
-				{
-					return CipherUtilities.GetCipher("DESEDE/CBC");
-				}
-			}
-
-			return null;
-		}
-
-		public static string GetEncodingName(
-			DerObjectIdentifier oid)
-		{
-			return (string) algorithms[oid.Id];
-		}
-
-		private static ICipherParameters FixDesParity(string mechanism, ICipherParameters parameters)
-		{
-			if (!mechanism.EndsWith("DES-CBC") & !mechanism.EndsWith("DESEDE-CBC"))
-			{
-				return parameters;
-			}
-
-			if (parameters is ParametersWithIV)
-			{
-				ParametersWithIV ivParams = (ParametersWithIV)parameters;
-				return new ParametersWithIV(FixDesParity(mechanism, ivParams.Parameters), ivParams.GetIV());
-			}
-
-			KeyParameter kParam = (KeyParameter)parameters;
-			byte[] keyBytes = kParam.GetKey();
-			DesParameters.SetOddParity(keyBytes);
-			return new KeyParameter(keyBytes);
-		}
-	}
+            algorithms["PBEWITHMD2ANDDES-CBC"] = "PBEwithMD2andDES-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithMD2AndDesCbc.Id] = "PBEwithMD2andDES-CBC";
+            algorithms["PBEWITHMD2ANDRC2-CBC"] = "PBEwithMD2andRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc.Id] = "PBEwithMD2andRC2-CBC";
+            algorithms["PBEWITHMD5ANDDES-CBC"] = "PBEwithMD5andDES-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithMD5AndDesCbc.Id] = "PBEwithMD5andDES-CBC";
+            algorithms["PBEWITHMD5ANDRC2-CBC"] = "PBEwithMD5andRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc.Id] = "PBEwithMD5andRC2-CBC";
+            algorithms["PBEWITHSHA1ANDDES"] = "PBEwithSHA-1andDES-CBC";
+            algorithms["PBEWITHSHA-1ANDDES"] = "PBEwithSHA-1andDES-CBC";
+            algorithms["PBEWITHSHA1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
+            algorithms["PBEWITHSHA-1ANDDES-CBC"] = "PBEwithSHA-1andDES-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithSha1AndDesCbc.Id] = "PBEwithSHA-1andDES-CBC";
+            algorithms["PBEWITHSHA1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
+            algorithms["PBEWITHSHA-1ANDRC2"] = "PBEwithSHA-1andRC2-CBC";
+            algorithms["PBEWITHSHA1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
+            algorithms["PBEWITHSHA-1ANDRC2-CBC"] = "PBEwithSHA-1andRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc.Id] = "PBEwithSHA-1andRC2-CBC";
+            algorithms["PKCS12"] = "Pkcs12";
+            algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.Id] = "PBEwithSHA-1and128bitAES-CBC-BC";
+            algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.Id] = "PBEwithSHA-1and192bitAES-CBC-BC";
+            algorithms[BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.Id] = "PBEwithSHA-1and256bitAES-CBC-BC";
+            algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.Id] = "PBEwithSHA-256and128bitAES-CBC-BC";
+            algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.Id] = "PBEwithSHA-256and192bitAES-CBC-BC";
+            algorithms[BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.Id] = "PBEwithSHA-256and256bitAES-CBC-BC";
+            algorithms["PBEWITHSHAAND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+            algorithms["PBEWITHSHA1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+            algorithms["PBEWITHSHA-1AND128BITRC4"] = "PBEwithSHA-1and128bitRC4";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4.Id] = "PBEwithSHA-1and128bitRC4";
+            algorithms["PBEWITHSHAAND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+            algorithms["PBEWITHSHA1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+            algorithms["PBEWITHSHA-1AND40BITRC4"] = "PBEwithSHA-1and40bitRC4";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4.Id] = "PBEwithSHA-1and40bitRC4";
+            algorithms["PBEWITHSHAAND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+            algorithms["PBEWITHSHAAND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA-1AND3-KEYDESEDE-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA-1AND3-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id] = "PBEwithSHA-1and3-keyDESEDE-CBC";
+            algorithms["PBEWITHSHAAND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+            algorithms["PBEWITHSHAAND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA-1AND2-KEYDESEDE-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+            algorithms["PBEWITHSHA-1AND2-KEYTRIPLEDES-CBC"] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc.Id] = "PBEwithSHA-1and2-keyDESEDE-CBC";
+            algorithms["PBEWITHSHAAND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+            algorithms["PBEWITHSHA1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+            algorithms["PBEWITHSHA-1AND128BITRC2-CBC"] = "PBEwithSHA-1and128bitRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc.Id] = "PBEwithSHA-1and128bitRC2-CBC";
+            algorithms["PBEWITHSHAAND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+            algorithms["PBEWITHSHA1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+            algorithms["PBEWITHSHA-1AND40BITRC2-CBC"] = "PBEwithSHA-1and40bitRC2-CBC";
+            algorithms[PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc.Id] = "PBEwithSHA-1and40bitRC2-CBC";
+            algorithms["PBEWITHSHAAND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+            algorithms["PBEWITHSHA1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+            algorithms["PBEWITHSHA-1AND128BITAES-CBC-BC"] = "PBEwithSHA-1and128bitAES-CBC-BC";
+            algorithms["PBEWITHSHAAND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+            algorithms["PBEWITHSHA1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+            algorithms["PBEWITHSHA-1AND192BITAES-CBC-BC"] = "PBEwithSHA-1and192bitAES-CBC-BC";
+            algorithms["PBEWITHSHAAND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+            algorithms["PBEWITHSHA1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+            algorithms["PBEWITHSHA-1AND256BITAES-CBC-BC"] = "PBEwithSHA-1and256bitAES-CBC-BC";
+            algorithms["PBEWITHSHA256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
+            algorithms["PBEWITHSHA-256AND128BITAES-CBC-BC"] = "PBEwithSHA-256and128bitAES-CBC-BC";
+            algorithms["PBEWITHSHA256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
+            algorithms["PBEWITHSHA-256AND192BITAES-CBC-BC"] = "PBEwithSHA-256and192bitAES-CBC-BC";
+            algorithms["PBEWITHSHA256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
+            algorithms["PBEWITHSHA-256AND256BITAES-CBC-BC"] = "PBEwithSHA-256and256bitAES-CBC-BC";
+            algorithms["PBEWITHSHAANDIDEA"] = "PBEwithSHA-1andIDEA-CBC";
+            algorithms["PBEWITHSHAANDIDEA-CBC"] = "PBEwithSHA-1andIDEA-CBC";
+            algorithms["PBEWITHSHAANDTWOFISH"] = "PBEwithSHA-1andTWOFISH-CBC";
+            algorithms["PBEWITHSHAANDTWOFISH-CBC"] = "PBEwithSHA-1andTWOFISH-CBC";
+            algorithms["PBEWITHHMACSHA1"] = "PBEwithHmacSHA-1";
+            algorithms["PBEWITHHMACSHA-1"] = "PBEwithHmacSHA-1";
+            algorithms[OiwObjectIdentifiers.IdSha1.Id] = "PBEwithHmacSHA-1";
+            algorithms["PBEWITHHMACSHA224"] = "PBEwithHmacSHA-224";
+            algorithms["PBEWITHHMACSHA-224"] = "PBEwithHmacSHA-224";
+            algorithms[NistObjectIdentifiers.IdSha224.Id] = "PBEwithHmacSHA-224";
+            algorithms["PBEWITHHMACSHA256"] = "PBEwithHmacSHA-256";
+            algorithms["PBEWITHHMACSHA-256"] = "PBEwithHmacSHA-256";
+            algorithms[NistObjectIdentifiers.IdSha256.Id] = "PBEwithHmacSHA-256";
+            algorithms["PBEWITHHMACRIPEMD128"] = "PBEwithHmacRipeMD128";
+            algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "PBEwithHmacRipeMD128";
+            algorithms["PBEWITHHMACRIPEMD160"] = "PBEwithHmacRipeMD160";
+            algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "PBEwithHmacRipeMD160";
+            algorithms["PBEWITHHMACRIPEMD256"] = "PBEwithHmacRipeMD256";
+            algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "PBEwithHmacRipeMD256";
+            algorithms["PBEWITHHMACTIGER"] = "PBEwithHmacTiger";
+
+            algorithms["PBEWITHMD5AND128BITAES-CBC-OPENSSL"] = "PBEwithMD5and128bitAES-CBC-OpenSSL";
+            algorithms["PBEWITHMD5AND192BITAES-CBC-OPENSSL"] = "PBEwithMD5and192bitAES-CBC-OpenSSL";
+            algorithms["PBEWITHMD5AND256BITAES-CBC-OPENSSL"] = "PBEwithMD5and256bitAES-CBC-OpenSSL";
+
+            algorithmType["Pkcs5scheme1"] = Pkcs5S1;
+            algorithmType["Pkcs5scheme2"] = Pkcs5S2;
+            algorithmType["PBEwithMD2andDES-CBC"] = Pkcs5S1;
+            algorithmType["PBEwithMD2andRC2-CBC"] = Pkcs5S1;
+            algorithmType["PBEwithMD5andDES-CBC"] = Pkcs5S1;
+            algorithmType["PBEwithMD5andRC2-CBC"] = Pkcs5S1;
+            algorithmType["PBEwithSHA-1andDES-CBC"] = Pkcs5S1;
+            algorithmType["PBEwithSHA-1andRC2-CBC"] = Pkcs5S1;
+            algorithmType["Pkcs12"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and128bitRC4"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and40bitRC4"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and3-keyDESEDE-CBC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and2-keyDESEDE-CBC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and128bitRC2-CBC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and40bitRC2-CBC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and128bitAES-CBC-BC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and192bitAES-CBC-BC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1and256bitAES-CBC-BC"] = Pkcs12;
+            algorithmType["PBEwithSHA-256and128bitAES-CBC-BC"] = Pkcs12;
+            algorithmType["PBEwithSHA-256and192bitAES-CBC-BC"] = Pkcs12;
+            algorithmType["PBEwithSHA-256and256bitAES-CBC-BC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1andIDEA-CBC"] = Pkcs12;
+            algorithmType["PBEwithSHA-1andTWOFISH-CBC"] = Pkcs12;
+            algorithmType["PBEwithHmacSHA-1"] = Pkcs12;
+            algorithmType["PBEwithHmacSHA-224"] = Pkcs12;
+            algorithmType["PBEwithHmacSHA-256"] = Pkcs12;
+            algorithmType["PBEwithHmacRipeMD128"] = Pkcs12;
+            algorithmType["PBEwithHmacRipeMD160"] = Pkcs12;
+            algorithmType["PBEwithHmacRipeMD256"] = Pkcs12;
+            algorithmType["PBEwithHmacTiger"] = Pkcs12;
+
+            algorithmType["PBEwithMD5and128bitAES-CBC-OpenSSL"] = OpenSsl;
+            algorithmType["PBEwithMD5and192bitAES-CBC-OpenSSL"] = OpenSsl;
+            algorithmType["PBEwithMD5and256bitAES-CBC-OpenSSL"] = OpenSsl;
+
+            oids["PBEwithMD2andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndDesCbc;
+            oids["PBEwithMD2andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD2AndRC2Cbc;
+            oids["PBEwithMD5andDES-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndDesCbc;
+            oids["PBEwithMD5andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithMD5AndRC2Cbc;
+            oids["PBEwithSHA-1andDES-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndDesCbc;
+            oids["PBEwithSHA-1andRC2-CBC"] = PkcsObjectIdentifiers.PbeWithSha1AndRC2Cbc;
+            oids["PBEwithSHA-1and128bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC4;
+            oids["PBEwithSHA-1and40bitRC4"] = PkcsObjectIdentifiers.PbeWithShaAnd40BitRC4;
+            oids["PBEwithSHA-1and3-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc;
+            oids["PBEwithSHA-1and2-keyDESEDE-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd2KeyTripleDesCbc;
+            oids["PBEwithSHA-1and128bitRC2-CBC"] = PkcsObjectIdentifiers.PbeWithShaAnd128BitRC2Cbc;
+            oids["PBEwithSHA-1and40bitRC2-CBC"] = PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc;
+            oids["PBEwithHmacSHA-1"] = OiwObjectIdentifiers.IdSha1;
+            oids["PBEwithHmacSHA-224"] = NistObjectIdentifiers.IdSha224;
+            oids["PBEwithHmacSHA-256"] = NistObjectIdentifiers.IdSha256;
+            oids["PBEwithHmacRipeMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+            oids["PBEwithHmacRipeMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+            oids["PBEwithHmacRipeMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+            oids["Pkcs5scheme2"] = PkcsObjectIdentifiers.IdPbeS2;
+        }
+
+        static PbeParametersGenerator MakePbeGenerator(
+            string	type,
+            IDigest	digest,
+            byte[]	key,
+            byte[]	salt,
+            int		iterationCount)
+        {
+            PbeParametersGenerator generator;
+
+            if (type.Equals(Pkcs5S1))
+            {
+                generator = new Pkcs5S1ParametersGenerator(digest);
+            }
+            else if (type.Equals(Pkcs5S2))
+            {
+                generator = new Pkcs5S2ParametersGenerator();
+            }
+            else if (type.Equals(Pkcs12))
+            {
+                generator = new Pkcs12ParametersGenerator(digest);
+            }
+            else if (type.Equals(OpenSsl))
+            {
+                generator = new OpenSslPbeParametersGenerator();
+            }
+            else
+            {
+                throw new ArgumentException("Unknown PBE type: " + type, "type");
+            }
+
+            generator.Init(key, salt, iterationCount);
+            return generator;
+        }
+
+        /// <summary>
+        /// Returns a ObjectIdentifier for a give encoding.
+        /// </summary>
+        /// <param name="mechanism">A string representation of the encoding.</param>
+        /// <returns>A DerObjectIdentifier, null if the Oid is not available.</returns>
+        public static DerObjectIdentifier GetObjectIdentifier(
+            string mechanism)
+        {
+            mechanism = (string) algorithms[Platform.ToUpperInvariant(mechanism)];
+            if (mechanism != null)
+            {
+                return (DerObjectIdentifier)oids[mechanism];
+            }
+            return null;
+        }
+
+        public static ICollection Algorithms
+        {
+            get { return oids.Keys; }
+        }
+
+        public static bool IsPkcs12(
+            string algorithm)
+        {
+            string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+            return mechanism != null && Pkcs12.Equals(algorithmType[mechanism]);
+        }
+
+        public static bool IsPkcs5Scheme1(
+            string algorithm)
+        {
+            string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+            return mechanism != null && Pkcs5S1.Equals(algorithmType[mechanism]);
+        }
+
+        public static bool IsPkcs5Scheme2(
+            string algorithm)
+        {
+            string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+            return mechanism != null && Pkcs5S2.Equals(algorithmType[mechanism]);
+        }
+
+        public static bool IsOpenSsl(
+            string algorithm)
+        {
+            string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+            return mechanism != null && OpenSsl.Equals(algorithmType[mechanism]);
+        }
+
+        public static bool IsPbeAlgorithm(
+            string algorithm)
+        {
+            string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+            return mechanism != null && algorithmType[mechanism] != null;
+        }
+
+        public static Asn1Encodable GenerateAlgorithmParameters(
+            DerObjectIdentifier algorithmOid,
+            byte[]              salt,
+            int                 iterationCount)
+        {
+            return GenerateAlgorithmParameters(algorithmOid.Id, salt, iterationCount);
+        }
+
+        public static Asn1Encodable GenerateAlgorithmParameters(
+            string  algorithm,
+            byte[]  salt,
+            int     iterationCount)
+        {
+            if (IsPkcs12(algorithm))
+            {
+                return new Pkcs12PbeParams(salt, iterationCount);
+            }
+            else if (IsPkcs5Scheme2(algorithm))
+            {
+                return new Pbkdf2Params(salt, iterationCount);
+            }
+            else
+            {
+                return new PbeParameter(salt, iterationCount);
+            }
+        }
+
+        public static ICipherParameters GenerateCipherParameters(
+            DerObjectIdentifier algorithmOid,
+            char[]              password,
+            Asn1Encodable       pbeParameters)
+        {
+            return GenerateCipherParameters(algorithmOid.Id, password, false, pbeParameters);
+        }
+
+        public static ICipherParameters GenerateCipherParameters(
+            DerObjectIdentifier algorithmOid,
+            char[]              password,
+            bool				wrongPkcs12Zero,
+            Asn1Encodable       pbeParameters)
+        {
+            return GenerateCipherParameters(algorithmOid.Id, password, wrongPkcs12Zero, pbeParameters);
+        }
+
+        public static ICipherParameters GenerateCipherParameters(
+            AlgorithmIdentifier algID,
+            char[]              password)
+        {
+            return GenerateCipherParameters(algID.ObjectID.Id, password, false, algID.Parameters);
+        }
+
+        public static ICipherParameters GenerateCipherParameters(
+            AlgorithmIdentifier algID,
+            char[]              password,
+            bool				wrongPkcs12Zero)
+        {
+            return GenerateCipherParameters(algID.ObjectID.Id, password, wrongPkcs12Zero, algID.Parameters);
+        }
+
+        public static ICipherParameters GenerateCipherParameters(
+            string          algorithm,
+            char[]          password,
+            Asn1Encodable   pbeParameters)
+        {
+            return GenerateCipherParameters(algorithm, password, false, pbeParameters);
+        }
+
+        public static ICipherParameters GenerateCipherParameters(
+            string          algorithm,
+            char[]          password,
+            bool			wrongPkcs12Zero,
+            Asn1Encodable   pbeParameters)
+        {
+            string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+            byte[] keyBytes = null;
+            byte[] salt = null;
+            int iterationCount = 0;
+
+            if (IsPkcs12(mechanism))
+            {
+                Pkcs12PbeParams pbeParams = Pkcs12PbeParams.GetInstance(pbeParameters);
+                salt = pbeParams.GetIV();
+                iterationCount = pbeParams.Iterations.IntValue;
+                keyBytes = PbeParametersGenerator.Pkcs12PasswordToBytes(password, wrongPkcs12Zero);
+            }
+            else if (IsPkcs5Scheme2(mechanism))
+            {
+                // See below
+            }
+            else
+            {
+                PbeParameter pbeParams = PbeParameter.GetInstance(pbeParameters);
+                salt = pbeParams.GetSalt();
+                iterationCount = pbeParams.IterationCount.IntValue;
+                keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
+            }
+
+            ICipherParameters parameters = null;
+
+            if (IsPkcs5Scheme2(mechanism))
+            {
+                PbeS2Parameters s2p = PbeS2Parameters.GetInstance(pbeParameters.ToAsn1Object());
+                AlgorithmIdentifier encScheme = s2p.EncryptionScheme;
+                DerObjectIdentifier encOid = encScheme.ObjectID;
+                Asn1Object encParams = encScheme.Parameters.ToAsn1Object();
+
+                // TODO What about s2p.KeyDerivationFunc.ObjectID?
+                Pbkdf2Params pbeParams = Pbkdf2Params.GetInstance(s2p.KeyDerivationFunc.Parameters.ToAsn1Object());
+
+                byte[] iv;
+                if (encOid.Equals(PkcsObjectIdentifiers.RC2Cbc)) // PKCS5.B.2.3
+                {
+                    RC2CbcParameter rc2Params = RC2CbcParameter.GetInstance(encParams);
+                    iv = rc2Params.GetIV();
+                }
+                else
+                {
+                    iv = Asn1OctetString.GetInstance(encParams).GetOctets();
+                }
+
+                salt = pbeParams.GetSalt();
+                iterationCount = pbeParams.IterationCount.IntValue;
+                keyBytes = PbeParametersGenerator.Pkcs5PasswordToBytes(password);
+
+                int keyLength = pbeParams.KeyLength != null
+                    ?	pbeParams.KeyLength.IntValue * 8
+                    :	GeneratorUtilities.GetDefaultKeySize(encOid);
+
+                PbeParametersGenerator gen = MakePbeGenerator(
+                    (string)algorithmType[mechanism], null, keyBytes, salt, iterationCount);
+
+                parameters = gen.GenerateDerivedParameters(encOid.Id, keyLength);
+
+                if (iv != null)
+                {
+                    // FIXME? OpenSSL weirdness with IV of zeros (for ECB keys?)
+                    if (Arrays.AreEqual(iv, new byte[iv.Length]))
+                    {
+                        //Console.Error.Write("***** IV all 0 (length " + iv.Length + ") *****");
+                    }
+                    else
+                    {
+                        parameters = new ParametersWithIV(parameters, iv);
+                    }
+                }
+            }
+            else if (mechanism.StartsWith("PBEwithSHA-1"))
+            {
+                PbeParametersGenerator generator = MakePbeGenerator(
+                    (string) algorithmType[mechanism], new Sha1Digest(), keyBytes, salt, iterationCount);
+
+                if (mechanism.Equals("PBEwithSHA-1and128bitAES-CBC-BC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and192bitAES-CBC-BC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and256bitAES-CBC-BC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and128bitRC4"))
+                {
+                    parameters = generator.GenerateDerivedParameters("RC4", 128);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and40bitRC4"))
+                {
+                    parameters = generator.GenerateDerivedParameters("RC4", 40);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and3-keyDESEDE-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("DESEDE", 192, 64);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and2-keyDESEDE-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("DESEDE", 128, 64);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and128bitRC2-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("RC2", 128, 64);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1and40bitRC2-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("RC2", 40, 64);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1andDES-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+                }
+                else if (mechanism.Equals("PBEwithSHA-1andRC2-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+                }
+            }
+            else if (mechanism.StartsWith("PBEwithSHA-256"))
+            {
+                PbeParametersGenerator generator = MakePbeGenerator(
+                    (string) algorithmType[mechanism], new Sha256Digest(), keyBytes, salt, iterationCount);
+
+                if (mechanism.Equals("PBEwithSHA-256and128bitAES-CBC-BC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+                }
+                else if (mechanism.Equals("PBEwithSHA-256and192bitAES-CBC-BC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+                }
+                else if (mechanism.Equals("PBEwithSHA-256and256bitAES-CBC-BC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+                }
+            }
+            else if (mechanism.StartsWith("PBEwithMD5"))
+            {
+                PbeParametersGenerator generator = MakePbeGenerator(
+                    (string)algorithmType[mechanism], new MD5Digest(), keyBytes, salt, iterationCount);
+
+                if (mechanism.Equals("PBEwithMD5andDES-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+                }
+                else if (mechanism.Equals("PBEwithMD5andRC2-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+                }
+                else if (mechanism.Equals("PBEwithMD5and128bitAES-CBC-OpenSSL"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 128, 128);
+                }
+                else if (mechanism.Equals("PBEwithMD5and192bitAES-CBC-OpenSSL"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 192, 128);
+                }
+                else if (mechanism.Equals("PBEwithMD5and256bitAES-CBC-OpenSSL"))
+                {
+                    parameters = generator.GenerateDerivedParameters("AES", 256, 128);
+                }
+            }
+            else if (mechanism.StartsWith("PBEwithMD2"))
+            {
+                PbeParametersGenerator generator = MakePbeGenerator(
+                    (string)algorithmType[mechanism], new MD2Digest(), keyBytes, salt, iterationCount);
+                if (mechanism.Equals("PBEwithMD2andDES-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("DES", 64, 64);
+                }
+                else if (mechanism.Equals("PBEwithMD2andRC2-CBC"))
+                {
+                    parameters = generator.GenerateDerivedParameters("RC2", 64, 64);
+                }
+            }
+            else if (mechanism.StartsWith("PBEwithHmac"))
+            {
+                string digestName = mechanism.Substring("PBEwithHmac".Length);
+                IDigest digest = DigestUtilities.GetDigest(digestName);
+
+                PbeParametersGenerator generator = MakePbeGenerator(
+                    (string) algorithmType[mechanism], digest, keyBytes, salt, iterationCount);
+
+                int bitLen = digest.GetDigestSize() * 8;
+                parameters = generator.GenerateDerivedMacParameters(bitLen);
+            }
+
+            Array.Clear(keyBytes, 0, keyBytes.Length);
+
+            return FixDesParity(mechanism, parameters);
+        }
+
+        public static object CreateEngine(
+            DerObjectIdentifier algorithmOid)
+        {
+            return CreateEngine(algorithmOid.Id);
+        }
+
+        public static object CreateEngine(
+            AlgorithmIdentifier algID)
+        {
+            string algorithm = algID.ObjectID.Id;
+
+            if (IsPkcs5Scheme2(algorithm))
+            {
+                PbeS2Parameters s2p = PbeS2Parameters.GetInstance(algID.Parameters.ToAsn1Object());
+                AlgorithmIdentifier encScheme = s2p.EncryptionScheme;
+                return CipherUtilities.GetCipher(encScheme.ObjectID);
+            }
+
+            return CreateEngine(algorithm);
+        }
+
+        public static object CreateEngine(
+            string algorithm)
+        {
+            string mechanism = (string)algorithms[Platform.ToUpperInvariant(algorithm)];
+
+            if (mechanism.StartsWith("PBEwithHmac"))
+            {
+                string digestName = mechanism.Substring("PBEwithHmac".Length);
+
+                return MacUtilities.GetMac("HMAC/" + digestName);
+            }
+
+            if (mechanism.StartsWith("PBEwithMD2")
+                ||	mechanism.StartsWith("PBEwithMD5")
+                ||	mechanism.StartsWith("PBEwithSHA-1")
+                ||	mechanism.StartsWith("PBEwithSHA-256"))
+            {
+                if (mechanism.EndsWith("AES-CBC-BC") || mechanism.EndsWith("AES-CBC-OPENSSL"))
+                {
+                    return CipherUtilities.GetCipher("AES/CBC");
+                }
+
+                if (mechanism.EndsWith("DES-CBC"))
+                {
+                    return CipherUtilities.GetCipher("DES/CBC");
+                }
+
+                if (mechanism.EndsWith("DESEDE-CBC"))
+                {
+                    return CipherUtilities.GetCipher("DESEDE/CBC");
+                }
+
+                if (mechanism.EndsWith("RC2-CBC"))
+                {
+                    return CipherUtilities.GetCipher("RC2/CBC");
+                }
+
+                if (mechanism.EndsWith("RC4"))
+                {
+                    return CipherUtilities.GetCipher("RC4");
+                }
+            }
+
+            return null;
+        }
+
+        public static string GetEncodingName(
+            DerObjectIdentifier oid)
+        {
+            return (string) algorithms[oid.Id];
+        }
+
+        private static ICipherParameters FixDesParity(string mechanism, ICipherParameters parameters)
+        {
+            if (!mechanism.EndsWith("DES-CBC") & !mechanism.EndsWith("DESEDE-CBC"))
+            {
+                return parameters;
+            }
+
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParams = (ParametersWithIV)parameters;
+                return new ParametersWithIV(FixDesParity(mechanism, ivParams.Parameters), ivParams.GetIV());
+            }
+
+            KeyParameter kParam = (KeyParameter)parameters;
+            byte[] keyBytes = kParam.GetKey();
+            DesParameters.SetOddParity(keyBytes);
+            return new KeyParameter(keyBytes);
+        }
+    }
 }
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index 5ebebd55a..1cfa37afe 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -15,6 +15,7 @@ using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
@@ -24,101 +25,101 @@ namespace Org.BouncyCastle.Security
         {
         }
 
-		public static AsymmetricKeyParameter CreateKey(
-			byte[] privateKeyInfoData)
-		{
-			return CreateKey(
-				PrivateKeyInfo.GetInstance(
-					Asn1Object.FromByteArray(privateKeyInfoData)));
-		}
-
-		public static AsymmetricKeyParameter CreateKey(
-			Stream inStr)
-		{
-			return CreateKey(
-				PrivateKeyInfo.GetInstance(
-					Asn1Object.FromStream(inStr)));
-		}
-
-		public static AsymmetricKeyParameter CreateKey(
-			PrivateKeyInfo keyInfo)
+        public static AsymmetricKeyParameter CreateKey(
+            byte[] privateKeyInfoData)
         {
-            AlgorithmIdentifier algID = keyInfo.AlgorithmID;
-			DerObjectIdentifier algOid = algID.ObjectID;
-
-			// TODO See RSAUtil.isRsaOid in Java build
-			if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)
-				|| algOid.Equals(X509ObjectIdentifiers.IdEARsa)
-				|| algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss)
-				|| algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
-			{
-				RsaPrivateKeyStructure keyStructure = new RsaPrivateKeyStructure(
-					Asn1Sequence.GetInstance(keyInfo.PrivateKey));
-
-				return new RsaPrivateCrtKeyParameters(
-					keyStructure.Modulus,
-					keyStructure.PublicExponent,
-					keyStructure.PrivateExponent,
-					keyStructure.Prime1,
-					keyStructure.Prime2,
-					keyStructure.Exponent1,
-					keyStructure.Exponent2,
-					keyStructure.Coefficient);
-			}
-			// TODO?
+            return CreateKey(
+                PrivateKeyInfo.GetInstance(
+                    Asn1Object.FromByteArray(privateKeyInfoData)));
+        }
+
+        public static AsymmetricKeyParameter CreateKey(
+            Stream inStr)
+        {
+            return CreateKey(
+                PrivateKeyInfo.GetInstance(
+                    Asn1Object.FromStream(inStr)));
+        }
+
+        public static AsymmetricKeyParameter CreateKey(
+            PrivateKeyInfo keyInfo)
+        {
+            AlgorithmIdentifier algID = keyInfo.PrivateKeyAlgorithm;
+            DerObjectIdentifier algOid = algID.ObjectID;
+
+            // TODO See RSAUtil.isRsaOid in Java build
+            if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)
+                || algOid.Equals(X509ObjectIdentifiers.IdEARsa)
+                || algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss)
+                || algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
+            {
+                RsaPrivateKeyStructure keyStructure = new RsaPrivateKeyStructure(
+                    Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey()));
+
+                return new RsaPrivateCrtKeyParameters(
+                    keyStructure.Modulus,
+                    keyStructure.PublicExponent,
+                    keyStructure.PrivateExponent,
+                    keyStructure.Prime1,
+                    keyStructure.Prime2,
+                    keyStructure.Exponent1,
+                    keyStructure.Exponent2,
+                    keyStructure.Coefficient);
+            }
+            // TODO?
 //			else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
-			else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
-			{
-				DHParameter para = new DHParameter(
-					Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
-				DerInteger derX = (DerInteger)keyInfo.PrivateKey;
-
-				BigInteger lVal = para.L;
-				int l = lVal == null ? 0 : lVal.IntValue;
-				DHParameters dhParams = new DHParameters(para.P, para.G, null, l);
-
-				return new DHPrivateKeyParameters(derX.Value, dhParams, algOid);
-			}
-			else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
-			{
-				ElGamalParameter  para = new ElGamalParameter(
-					Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
-				DerInteger derX = (DerInteger)keyInfo.PrivateKey;
-
-				return new ElGamalPrivateKeyParameters(
-					derX.Value,
-					new ElGamalParameters(para.P, para.G));
-			}
-			else if (algOid.Equals(X9ObjectIdentifiers.IdDsa))
-			{
-				DerInteger derX = (DerInteger) keyInfo.PrivateKey;
-				Asn1Encodable ae = algID.Parameters;
-
-				DsaParameters parameters = null;
-				if (ae != null)
-				{
-					DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
-					parameters = new DsaParameters(para.P, para.Q, para.G);
-				}
-
-				return new DsaPrivateKeyParameters(derX.Value, parameters);
-			}
-			else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
-			{
-				X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object());
-
-				X9ECParameters x9;
-				if (para.IsNamedCurve)
-				{
+            else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
+            {
+                DHParameter para = new DHParameter(
+                    Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+                DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
+
+                BigInteger lVal = para.L;
+                int l = lVal == null ? 0 : lVal.IntValue;
+                DHParameters dhParams = new DHParameters(para.P, para.G, null, l);
+
+                return new DHPrivateKeyParameters(derX.Value, dhParams, algOid);
+            }
+            else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
+            {
+                ElGamalParameter  para = new ElGamalParameter(
+                    Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+                DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
+
+                return new ElGamalPrivateKeyParameters(
+                    derX.Value,
+                    new ElGamalParameters(para.P, para.G));
+            }
+            else if (algOid.Equals(X9ObjectIdentifiers.IdDsa))
+            {
+                DerInteger derX = (DerInteger)keyInfo.ParsePrivateKey();
+                Asn1Encodable ae = algID.Parameters;
+
+                DsaParameters parameters = null;
+                if (ae != null)
+                {
+                    DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
+                    parameters = new DsaParameters(para.P, para.Q, para.G);
+                }
+
+                return new DsaPrivateKeyParameters(derX.Value, parameters);
+            }
+            else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+            {
+                X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object());
+
+                X9ECParameters x9;
+                if (para.IsNamedCurve)
+                {
                     x9 = ECKeyPairGenerator.FindECCurveByOid((DerObjectIdentifier)para.Parameters);
-				}
-				else
-				{
+                }
+                else
+                {
                     x9 = new X9ECParameters((Asn1Sequence)para.Parameters);
-				}
+                }
 
                 ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
-                    Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+                    Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey()));
                 BigInteger d = ec.GetKey();
 
                 if (para.IsNamedCurve)
@@ -127,74 +128,76 @@ namespace Org.BouncyCastle.Security
                 }
 
                 ECDomainParameters dParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H,  x9.GetSeed());
-				return new ECPrivateKeyParameters(d, dParams);
-			}
-			else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
-			{
-				Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
-					Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
-
-				ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
-					Asn1Sequence.GetInstance(keyInfo.PrivateKey));
-
-				ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
-
-				if (ecP == null)
-					return null;
-
-				return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet);
-			}
-			else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
-			{
-				Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
-					Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
-
-				DerOctetString derX = (DerOctetString) keyInfo.PrivateKey;
-				byte[] keyEnc = derX.GetOctets();
-				byte[] keyBytes = new byte[keyEnc.Length];
-
-				for (int i = 0; i != keyEnc.Length; i++)
-				{
-					keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
-				}
-
-				BigInteger x = new BigInteger(1, keyBytes);
-
-				return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
-			}
-			else
-			{
-				throw new SecurityUtilityException("algorithm identifier in key not recognised");
-			}
+                return new ECPrivateKeyParameters(d, dParams);
+            }
+            else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
+            {
+                Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+                    Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+
+                Asn1Object privKey = keyInfo.ParsePrivateKey();
+                ECPrivateKeyStructure ec;
+
+                if (privKey is DerInteger)
+                {
+                    // TODO Do we need to pass any parameters here?
+                    ec = new ECPrivateKeyStructure(((DerInteger)privKey).Value);
+                }
+                else
+                {
+                    ec = ECPrivateKeyStructure.GetInstance(privKey);
+                }
+
+                ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+                if (ecP == null)
+                    throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key");
+
+                return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet);
+            }
+            else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
+            {
+                Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+                    Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+
+                DerOctetString derX = (DerOctetString)keyInfo.ParsePrivateKey();
+                BigInteger x = new BigInteger(1, Arrays.Reverse(derX.GetOctets()));
+
+                return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
+            }
+            else
+            {
+                throw new SecurityUtilityException("algorithm identifier in key not recognised");
+            }
         }
 
-		public static AsymmetricKeyParameter DecryptKey(
-			char[]					passPhrase,
-			EncryptedPrivateKeyInfo	encInfo)
-		{
-			return CreateKey(PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase, encInfo));
-		}
-
-		public static AsymmetricKeyParameter DecryptKey(
-			char[]	passPhrase,
-			byte[]	encryptedPrivateKeyInfoData)
-		{
-			return DecryptKey(passPhrase, Asn1Object.FromByteArray(encryptedPrivateKeyInfoData));
-		}
-
-		public static AsymmetricKeyParameter DecryptKey(
-			char[]	passPhrase,
-			Stream	encryptedPrivateKeyInfoStream)
-		{
-			return DecryptKey(passPhrase, Asn1Object.FromStream(encryptedPrivateKeyInfoStream));
-		}
-
-		private static AsymmetricKeyParameter DecryptKey(
-			char[]		passPhrase,
-			Asn1Object	asn1Object)
-		{
-			return DecryptKey(passPhrase, EncryptedPrivateKeyInfo.GetInstance(asn1Object));
-		}
+        public static AsymmetricKeyParameter DecryptKey(
+            char[]					passPhrase,
+            EncryptedPrivateKeyInfo	encInfo)
+        {
+            return CreateKey(PrivateKeyInfoFactory.CreatePrivateKeyInfo(passPhrase, encInfo));
+        }
+
+        public static AsymmetricKeyParameter DecryptKey(
+            char[]	passPhrase,
+            byte[]	encryptedPrivateKeyInfoData)
+        {
+            return DecryptKey(passPhrase, Asn1Object.FromByteArray(encryptedPrivateKeyInfoData));
+        }
+
+        public static AsymmetricKeyParameter DecryptKey(
+            char[]	passPhrase,
+            Stream	encryptedPrivateKeyInfoStream)
+        {
+            return DecryptKey(passPhrase, Asn1Object.FromStream(encryptedPrivateKeyInfoStream));
+        }
+
+        private static AsymmetricKeyParameter DecryptKey(
+            char[]		passPhrase,
+            Asn1Object	asn1Object)
+        {
+            return DecryptKey(passPhrase, EncryptedPrivateKeyInfo.GetInstance(asn1Object));
+        }
 
         public static byte[] EncryptKey(
             DerObjectIdentifier		algorithm,
@@ -203,19 +206,19 @@ namespace Org.BouncyCastle.Security
             int						iterationCount,
             AsymmetricKeyParameter	key)
         {
-			return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
-				algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
+            return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+                algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
         }
 
-		public static byte[] EncryptKey(
-			string					algorithm,
+        public static byte[] EncryptKey(
+            string					algorithm,
             char[]					passPhrase,
             byte[]					salt,
             int						iterationCount,
             AsymmetricKeyParameter	key)
         {
-			return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
-				algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
+            return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+                algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
         }
-	}
+    }
 }
diff --git a/crypto/src/security/PublicKeyFactory.cs b/crypto/src/security/PublicKeyFactory.cs
index c15e24a41..8c0be4f70 100644
--- a/crypto/src/security/PublicKeyFactory.cs
+++ b/crypto/src/security/PublicKeyFactory.cs
@@ -24,122 +24,122 @@ namespace Org.BouncyCastle.Security
         {
         }
 
-		public static AsymmetricKeyParameter CreateKey(
-			byte[] keyInfoData)
-		{
-			return CreateKey(
-				SubjectPublicKeyInfo.GetInstance(
-					Asn1Object.FromByteArray(keyInfoData)));
-		}
-
-		public static AsymmetricKeyParameter CreateKey(
-			Stream inStr)
-		{
-			return CreateKey(
-				SubjectPublicKeyInfo.GetInstance(
-					Asn1Object.FromStream(inStr)));
-		}
-
-		public static AsymmetricKeyParameter CreateKey(
-			SubjectPublicKeyInfo keyInfo)
+        public static AsymmetricKeyParameter CreateKey(
+            byte[] keyInfoData)
+        {
+            return CreateKey(
+                SubjectPublicKeyInfo.GetInstance(
+                    Asn1Object.FromByteArray(keyInfoData)));
+        }
+
+        public static AsymmetricKeyParameter CreateKey(
+            Stream inStr)
+        {
+            return CreateKey(
+                SubjectPublicKeyInfo.GetInstance(
+                    Asn1Object.FromStream(inStr)));
+        }
+
+        public static AsymmetricKeyParameter CreateKey(
+            SubjectPublicKeyInfo keyInfo)
         {
             AlgorithmIdentifier algID = keyInfo.AlgorithmID;
-			DerObjectIdentifier algOid = algID.ObjectID;
-
-			// TODO See RSAUtil.isRsaOid in Java build
-			if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)
-				|| algOid.Equals(X509ObjectIdentifiers.IdEARsa)
-				|| algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss)
-				|| algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
-			{
-				RsaPublicKeyStructure pubKey = RsaPublicKeyStructure.GetInstance(
-					keyInfo.GetPublicKey());
-
-				return new RsaKeyParameters(false, pubKey.Modulus, pubKey.PublicExponent);
-			}
-			else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
-			{
-				Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object());
-
-				DHPublicKey dhPublicKey = DHPublicKey.GetInstance(keyInfo.GetPublicKey());
-
-				BigInteger y = dhPublicKey.Y.Value;
-
-				if (IsPkcsDHParam(seq))
-					return ReadPkcsDHParam(algOid, y, seq);
-
-				DHDomainParameters dhParams = DHDomainParameters.GetInstance(seq);
-
-				BigInteger p = dhParams.P.Value;
-				BigInteger g = dhParams.G.Value;
-				BigInteger q = dhParams.Q.Value;
-
-				BigInteger j = null;
-				if (dhParams.J != null)
-				{
-					j = dhParams.J.Value;
-				}
-
-				DHValidationParameters validation = null;
-				DHValidationParms dhValidationParms = dhParams.ValidationParms;
-				if (dhValidationParms != null)
-				{
-					byte[] seed = dhValidationParms.Seed.GetBytes();
-					BigInteger pgenCounter = dhValidationParms.PgenCounter.Value;
-
-					// TODO Check pgenCounter size?
-
-					validation = new DHValidationParameters(seed, pgenCounter.IntValue);
-				}
-
-				return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
-			}
-			else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
-			{
-				Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object());
-
-				DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
-
-				return ReadPkcsDHParam(algOid, derY.Value, seq);
-			}
-			else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
-			{
-				ElGamalParameter para = new ElGamalParameter(
-					Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
-				DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
-
-				return new ElGamalPublicKeyParameters(
-					derY.Value,
-					new ElGamalParameters(para.P, para.G));
-			}
-			else if (algOid.Equals(X9ObjectIdentifiers.IdDsa)
-				|| algOid.Equals(OiwObjectIdentifiers.DsaWithSha1))
-			{
-				DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
-				Asn1Encodable ae = algID.Parameters;
-
-				DsaParameters parameters = null;
-				if (ae != null)
-				{
-					DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
-					parameters = new DsaParameters(para.P, para.Q, para.G);
-				}
-
-				return new DsaPublicKeyParameters(derY.Value, parameters);
-			}
-			else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
-			{
-				X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object());
+            DerObjectIdentifier algOid = algID.ObjectID;
+
+            // TODO See RSAUtil.isRsaOid in Java build
+            if (algOid.Equals(PkcsObjectIdentifiers.RsaEncryption)
+                || algOid.Equals(X509ObjectIdentifiers.IdEARsa)
+                || algOid.Equals(PkcsObjectIdentifiers.IdRsassaPss)
+                || algOid.Equals(PkcsObjectIdentifiers.IdRsaesOaep))
+            {
+                RsaPublicKeyStructure pubKey = RsaPublicKeyStructure.GetInstance(
+                    keyInfo.GetPublicKey());
+
+                return new RsaKeyParameters(false, pubKey.Modulus, pubKey.PublicExponent);
+            }
+            else if (algOid.Equals(X9ObjectIdentifiers.DHPublicNumber))
+            {
+                Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object());
+
+                DHPublicKey dhPublicKey = DHPublicKey.GetInstance(keyInfo.GetPublicKey());
+
+                BigInteger y = dhPublicKey.Y.Value;
+
+                if (IsPkcsDHParam(seq))
+                    return ReadPkcsDHParam(algOid, y, seq);
+
+                DHDomainParameters dhParams = DHDomainParameters.GetInstance(seq);
+
+                BigInteger p = dhParams.P.Value;
+                BigInteger g = dhParams.G.Value;
+                BigInteger q = dhParams.Q.Value;
+
+                BigInteger j = null;
+                if (dhParams.J != null)
+                {
+                    j = dhParams.J.Value;
+                }
+
+                DHValidationParameters validation = null;
+                DHValidationParms dhValidationParms = dhParams.ValidationParms;
+                if (dhValidationParms != null)
+                {
+                    byte[] seed = dhValidationParms.Seed.GetBytes();
+                    BigInteger pgenCounter = dhValidationParms.PgenCounter.Value;
+
+                    // TODO Check pgenCounter size?
+
+                    validation = new DHValidationParameters(seed, pgenCounter.IntValue);
+                }
+
+                return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
+            }
+            else if (algOid.Equals(PkcsObjectIdentifiers.DhKeyAgreement))
+            {
+                Asn1Sequence seq = Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object());
+
+                DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+
+                return ReadPkcsDHParam(algOid, derY.Value, seq);
+            }
+            else if (algOid.Equals(OiwObjectIdentifiers.ElGamalAlgorithm))
+            {
+                ElGamalParameter para = new ElGamalParameter(
+                    Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
+                DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+
+                return new ElGamalPublicKeyParameters(
+                    derY.Value,
+                    new ElGamalParameters(para.P, para.G));
+            }
+            else if (algOid.Equals(X9ObjectIdentifiers.IdDsa)
+                || algOid.Equals(OiwObjectIdentifiers.DsaWithSha1))
+            {
+                DerInteger derY = (DerInteger) keyInfo.GetPublicKey();
+                Asn1Encodable ae = algID.Parameters;
+
+                DsaParameters parameters = null;
+                if (ae != null)
+                {
+                    DsaParameter para = DsaParameter.GetInstance(ae.ToAsn1Object());
+                    parameters = new DsaParameters(para.P, para.Q, para.G);
+                }
+
+                return new DsaPublicKeyParameters(derY.Value, parameters);
+            }
+            else if (algOid.Equals(X9ObjectIdentifiers.IdECPublicKey))
+            {
+                X962Parameters para = new X962Parameters(algID.Parameters.ToAsn1Object());
 
                 X9ECParameters x9;
-				if (para.IsNamedCurve)
-				{
-					x9 = ECKeyPairGenerator.FindECCurveByOid((DerObjectIdentifier)para.Parameters);
-				}
-				else
-				{
-					x9 = new X9ECParameters((Asn1Sequence)para.Parameters);
-				}
+                if (para.IsNamedCurve)
+                {
+                    x9 = ECKeyPairGenerator.FindECCurveByOid((DerObjectIdentifier)para.Parameters);
+                }
+                else
+                {
+                    x9 = new X9ECParameters((Asn1Sequence)para.Parameters);
+                }
 
                 Asn1OctetString key = new DerOctetString(keyInfo.PublicKeyData.GetBytes());
                 X9ECPoint derQ = new X9ECPoint(x9.Curve, key);
@@ -151,103 +151,103 @@ namespace Org.BouncyCastle.Security
                 }
 
                 ECDomainParameters dParams = new ECDomainParameters(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
-				return new ECPublicKeyParameters(q, dParams);
-			}
-			else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
-			{
-				Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
-					(Asn1Sequence) algID.Parameters);
-
-				Asn1OctetString key;
-				try
-				{
-					key = (Asn1OctetString) keyInfo.GetPublicKey();
-				}
-				catch (IOException)
-				{
-					throw new ArgumentException("invalid info structure in GOST3410 public key");
-				}
-
-				byte[] keyEnc = key.GetOctets();
-				byte[] x = new byte[32];
-				byte[] y = new byte[32];
-
-				for (int i = 0; i != y.Length; i++)
-				{
-					x[i] = keyEnc[32 - 1 - i];
-				}
-
-				for (int i = 0; i != x.Length; i++)
-				{
-					y[i] = keyEnc[64 - 1 - i];
-				}
-
-				ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
-
-				if (ecP == null)
-					return null;
-
-				ECPoint q = ecP.Curve.CreatePoint(new BigInteger(1, x), new BigInteger(1, y), false);
-
-				return new ECPublicKeyParameters("ECGOST3410", q, gostParams.PublicKeyParamSet);
-			}
-			else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
-			{
-				Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
-					(Asn1Sequence) algID.Parameters);
-
-				DerOctetString derY;
-				try
-				{
-					derY = (DerOctetString) keyInfo.GetPublicKey();
-				}
-				catch (IOException)
-				{
-					throw new ArgumentException("invalid info structure in GOST3410 public key");
-				}
-
-				byte[] keyEnc = derY.GetOctets();
-				byte[] keyBytes = new byte[keyEnc.Length];
-
-				for (int i = 0; i != keyEnc.Length; i++)
-				{
-					keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
-				}
-
-				BigInteger y = new BigInteger(1, keyBytes);
-
-				return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
-			}
+                return new ECPublicKeyParameters(q, dParams);
+            }
+            else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x2001))
+            {
+                Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+                    (Asn1Sequence) algID.Parameters);
+
+                Asn1OctetString key;
+                try
+                {
+                    key = (Asn1OctetString) keyInfo.GetPublicKey();
+                }
+                catch (IOException)
+                {
+                    throw new ArgumentException("invalid info structure in GOST3410 public key");
+                }
+
+                byte[] keyEnc = key.GetOctets();
+                byte[] x = new byte[32];
+                byte[] y = new byte[32];
+
+                for (int i = 0; i != y.Length; i++)
+                {
+                    x[i] = keyEnc[32 - 1 - i];
+                }
+
+                for (int i = 0; i != x.Length; i++)
+                {
+                    y[i] = keyEnc[64 - 1 - i];
+                }
+
+                ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
+
+                if (ecP == null)
+                    return null;
+
+                ECPoint q = ecP.Curve.CreatePoint(new BigInteger(1, x), new BigInteger(1, y));
+
+                return new ECPublicKeyParameters("ECGOST3410", q, gostParams.PublicKeyParamSet);
+            }
+            else if (algOid.Equals(CryptoProObjectIdentifiers.GostR3410x94))
+            {
+                Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+                    (Asn1Sequence) algID.Parameters);
+
+                DerOctetString derY;
+                try
+                {
+                    derY = (DerOctetString) keyInfo.GetPublicKey();
+                }
+                catch (IOException)
+                {
+                    throw new ArgumentException("invalid info structure in GOST3410 public key");
+                }
+
+                byte[] keyEnc = derY.GetOctets();
+                byte[] keyBytes = new byte[keyEnc.Length];
+
+                for (int i = 0; i != keyEnc.Length; i++)
+                {
+                    keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
+                }
+
+                BigInteger y = new BigInteger(1, keyBytes);
+
+                return new Gost3410PublicKeyParameters(y, algParams.PublicKeyParamSet);
+            }
             else
             {
                 throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid);
             }
         }
 
-		private static bool IsPkcsDHParam(Asn1Sequence seq)
-		{
-			if (seq.Count == 2)
-				return true;
+        private static bool IsPkcsDHParam(Asn1Sequence seq)
+        {
+            if (seq.Count == 2)
+                return true;
 
-			if (seq.Count > 3)
-				return false;
+            if (seq.Count > 3)
+                return false;
 
-			DerInteger l = DerInteger.GetInstance(seq[2]);
-			DerInteger p = DerInteger.GetInstance(seq[0]);
+            DerInteger l = DerInteger.GetInstance(seq[2]);
+            DerInteger p = DerInteger.GetInstance(seq[0]);
 
-			return l.Value.CompareTo(BigInteger.ValueOf(p.Value.BitLength)) <= 0;
-		}
+            return l.Value.CompareTo(BigInteger.ValueOf(p.Value.BitLength)) <= 0;
+        }
 
-		private static DHPublicKeyParameters ReadPkcsDHParam(DerObjectIdentifier algOid,
-			BigInteger y, Asn1Sequence seq)
-		{
-			DHParameter para = new DHParameter(seq);
+        private static DHPublicKeyParameters ReadPkcsDHParam(DerObjectIdentifier algOid,
+            BigInteger y, Asn1Sequence seq)
+        {
+            DHParameter para = new DHParameter(seq);
 
-			BigInteger lVal = para.L;
-			int l = lVal == null ? 0 : lVal.IntValue;
-			DHParameters dhParams = new DHParameters(para.P, para.G, null, l);
+            BigInteger lVal = para.L;
+            int l = lVal == null ? 0 : lVal.IntValue;
+            DHParameters dhParams = new DHParameters(para.P, para.G, null, l);
 
-			return new DHPublicKeyParameters(y, dhParams, algOid);
-		}
-	}
+            return new DHPublicKeyParameters(y, dhParams, algOid);
+        }
+    }
 }
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index 866a2cf0d..ac9d98158 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -1,9 +1,9 @@
 using System;
-using System.Globalization;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Security
 			// TODO Compared to JDK, we don't auto-seed if the client forgets - problem?
 
 			// TODO Support all digests more generally, by stripping PRNG and calling DigestUtilities?
-			string drgName = algorithm.ToUpperInvariant();
+			string drgName = Platform.ToUpperInvariant(algorithm);
 
 			IRandomGenerator drg = null;
 			if (drgName == "SHA1PRNG")
@@ -136,7 +136,7 @@ namespace Org.BouncyCastle.Security
 			if (maxValue < 2)
 			{
 				if (maxValue < 0)
-					throw new ArgumentOutOfRangeException("maxValue < 0");
+					throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
 
 				return 0;
 			}
diff --git a/crypto/src/security/SecurityUtilityException.cs b/crypto/src/security/SecurityUtilityException.cs
index 8a5ea68d0..02a3e806e 100644
--- a/crypto/src/security/SecurityUtilityException.cs
+++ b/crypto/src/security/SecurityUtilityException.cs
@@ -2,6 +2,9 @@ using System;
 
 namespace Org.BouncyCastle.Security
 {
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
     public class SecurityUtilityException
 		: Exception
     {
diff --git a/crypto/src/security/SignatureException.cs b/crypto/src/security/SignatureException.cs
index 5ae4cbcf4..cea3c59cd 100644
--- a/crypto/src/security/SignatureException.cs
+++ b/crypto/src/security/SignatureException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security
 {
-	public class SignatureException : GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class SignatureException : GeneralSecurityException
 	{
 		public SignatureException() : base() { }
 		public SignatureException(string message) : base(message) { }
diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs
index ab23ee5d5..0cf113f65 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 using System.IO;
 
 using Org.BouncyCastle.Asn1;
@@ -24,16 +23,16 @@ namespace Org.BouncyCastle.Security
     /// </summary>
     public sealed class SignerUtilities
     {
-		private SignerUtilities()
-		{
-		}
+        private SignerUtilities()
+        {
+        }
 
-		internal static readonly IDictionary algorithms = Platform.CreateHashtable();
+        internal static readonly IDictionary algorithms = Platform.CreateHashtable();
         internal static readonly IDictionary oids = Platform.CreateHashtable();
 
-		static SignerUtilities()
+        static SignerUtilities()
         {
-			algorithms["MD2WITHRSA"] = "MD2withRSA";
+            algorithms["MD2WITHRSA"] = "MD2withRSA";
             algorithms["MD2WITHRSAENCRYPTION"] = "MD2withRSA";
             algorithms[PkcsObjectIdentifiers.MD2WithRsaEncryption.Id] = "MD2withRSA";
 
@@ -70,41 +69,41 @@ namespace Org.BouncyCastle.Security
             algorithms[PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id] = "SHA-512withRSA";
             algorithms["SHA-512WITHRSA"] = "SHA-512withRSA";
 
-			algorithms["PSSWITHRSA"] = "PSSwithRSA";
-			algorithms["RSASSA-PSS"] = "PSSwithRSA";
-			algorithms[PkcsObjectIdentifiers.IdRsassaPss.Id] = "PSSwithRSA";
-			algorithms["RSAPSS"] = "PSSwithRSA";
+            algorithms["PSSWITHRSA"] = "PSSwithRSA";
+            algorithms["RSASSA-PSS"] = "PSSwithRSA";
+            algorithms[PkcsObjectIdentifiers.IdRsassaPss.Id] = "PSSwithRSA";
+            algorithms["RSAPSS"] = "PSSwithRSA";
 
-			algorithms["SHA1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
-			algorithms["SHA-1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
-			algorithms["SHA1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
-			algorithms["SHA-1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+            algorithms["SHA1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+            algorithms["SHA-1WITHRSAANDMGF1"] = "SHA-1withRSAandMGF1";
+            algorithms["SHA1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
+            algorithms["SHA-1WITHRSA/PSS"] = "SHA-1withRSAandMGF1";
 
-			algorithms["SHA224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
-			algorithms["SHA-224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
-			algorithms["SHA224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
-			algorithms["SHA-224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+            algorithms["SHA224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+            algorithms["SHA-224WITHRSAANDMGF1"] = "SHA-224withRSAandMGF1";
+            algorithms["SHA224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
+            algorithms["SHA-224WITHRSA/PSS"] = "SHA-224withRSAandMGF1";
 
-			algorithms["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
+            algorithms["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
             algorithms["SHA-256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
-			algorithms["SHA256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
-			algorithms["SHA-256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+            algorithms["SHA256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
+            algorithms["SHA-256WITHRSA/PSS"] = "SHA-256withRSAandMGF1";
 
             algorithms["SHA384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
             algorithms["SHA-384WITHRSAANDMGF1"] = "SHA-384withRSAandMGF1";
-			algorithms["SHA384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
-			algorithms["SHA-384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+            algorithms["SHA384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
+            algorithms["SHA-384WITHRSA/PSS"] = "SHA-384withRSAandMGF1";
 
             algorithms["SHA512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
             algorithms["SHA-512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
-			algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
-			algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+            algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+            algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
 
-			algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA";
+            algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA";
             algorithms["RIPEMD128WITHRSAENCRYPTION"] = "RIPEMD128withRSA";
             algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128.Id] = "RIPEMD128withRSA";
 
-			algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA";
+            algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA";
             algorithms["RIPEMD160WITHRSAENCRYPTION"] = "RIPEMD160withRSA";
             algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160.Id] = "RIPEMD160withRSA";
 
@@ -112,126 +111,123 @@ namespace Org.BouncyCastle.Security
             algorithms["RIPEMD256WITHRSAENCRYPTION"] = "RIPEMD256withRSA";
             algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256.Id] = "RIPEMD256withRSA";
 
-			algorithms["NONEWITHRSA"] = "RSA";
-			algorithms["RSAWITHNONE"] = "RSA";
-			algorithms["RAWRSA"] = "RSA";
-
-			algorithms["RAWRSAPSS"] = "RAWRSASSA-PSS";
-			algorithms["NONEWITHRSAPSS"] = "RAWRSASSA-PSS";
-			algorithms["NONEWITHRSASSA-PSS"] = "RAWRSASSA-PSS";
-
-			algorithms["NONEWITHDSA"] = "NONEwithDSA";
-			algorithms["DSAWITHNONE"] = "NONEwithDSA";
-			algorithms["RAWDSA"] = "NONEwithDSA";
-
-			algorithms["DSA"] = "SHA-1withDSA";
-			algorithms["DSAWITHSHA1"] = "SHA-1withDSA";
-			algorithms["DSAWITHSHA-1"] = "SHA-1withDSA";
-			algorithms["SHA/DSA"] = "SHA-1withDSA";
-			algorithms["SHA1/DSA"] = "SHA-1withDSA";
-			algorithms["SHA-1/DSA"] = "SHA-1withDSA";
-			algorithms["SHA1WITHDSA"] = "SHA-1withDSA";
+            algorithms["NONEWITHRSA"] = "RSA";
+            algorithms["RSAWITHNONE"] = "RSA";
+            algorithms["RAWRSA"] = "RSA";
+
+            algorithms["RAWRSAPSS"] = "RAWRSASSA-PSS";
+            algorithms["NONEWITHRSAPSS"] = "RAWRSASSA-PSS";
+            algorithms["NONEWITHRSASSA-PSS"] = "RAWRSASSA-PSS";
+
+            algorithms["NONEWITHDSA"] = "NONEwithDSA";
+            algorithms["DSAWITHNONE"] = "NONEwithDSA";
+            algorithms["RAWDSA"] = "NONEwithDSA";
+
+            algorithms["DSA"] = "SHA-1withDSA";
+            algorithms["DSAWITHSHA1"] = "SHA-1withDSA";
+            algorithms["DSAWITHSHA-1"] = "SHA-1withDSA";
+            algorithms["SHA/DSA"] = "SHA-1withDSA";
+            algorithms["SHA1/DSA"] = "SHA-1withDSA";
+            algorithms["SHA-1/DSA"] = "SHA-1withDSA";
+            algorithms["SHA1WITHDSA"] = "SHA-1withDSA";
             algorithms["SHA-1WITHDSA"] = "SHA-1withDSA";
             algorithms[X9ObjectIdentifiers.IdDsaWithSha1.Id] = "SHA-1withDSA";
 
-			algorithms["DSAWITHSHA224"] = "SHA-224withDSA";
-			algorithms["DSAWITHSHA-224"] = "SHA-224withDSA";
-			algorithms["SHA224/DSA"] = "SHA-224withDSA";
-			algorithms["SHA-224/DSA"] = "SHA-224withDSA";
-			algorithms["SHA224WITHDSA"] = "SHA-224withDSA";
-			algorithms["SHA-224WITHDSA"] = "SHA-224withDSA";
-			algorithms[NistObjectIdentifiers.DsaWithSha224.Id] = "SHA-224withDSA";
-
-			algorithms["DSAWITHSHA256"] = "SHA-256withDSA";
-			algorithms["DSAWITHSHA-256"] = "SHA-256withDSA";
-			algorithms["SHA256/DSA"] = "SHA-256withDSA";
-			algorithms["SHA-256/DSA"] = "SHA-256withDSA";
-			algorithms["SHA256WITHDSA"] = "SHA-256withDSA";
-			algorithms["SHA-256WITHDSA"] = "SHA-256withDSA";
-			algorithms[NistObjectIdentifiers.DsaWithSha256.Id] = "SHA-256withDSA";
-
-			algorithms["DSAWITHSHA384"] = "SHA-384withDSA";
-			algorithms["DSAWITHSHA-384"] = "SHA-384withDSA";
-			algorithms["SHA384/DSA"] = "SHA-384withDSA";
-			algorithms["SHA-384/DSA"] = "SHA-384withDSA";
-			algorithms["SHA384WITHDSA"] = "SHA-384withDSA";
-			algorithms["SHA-384WITHDSA"] = "SHA-384withDSA";
-			algorithms[NistObjectIdentifiers.DsaWithSha384.Id] = "SHA-384withDSA";
-
-			algorithms["DSAWITHSHA512"] = "SHA-512withDSA";
-			algorithms["DSAWITHSHA-512"] = "SHA-512withDSA";
-			algorithms["SHA512/DSA"] = "SHA-512withDSA";
-			algorithms["SHA-512/DSA"] = "SHA-512withDSA";
-			algorithms["SHA512WITHDSA"] = "SHA-512withDSA";
-			algorithms["SHA-512WITHDSA"] = "SHA-512withDSA";
-			algorithms[NistObjectIdentifiers.DsaWithSha512.Id] = "SHA-512withDSA";
-
-			algorithms["NONEWITHECDSA"] = "NONEwithECDSA";
-			algorithms["ECDSAWITHNONE"] = "NONEwithECDSA";
-
-			algorithms["ECDSA"] = "SHA-1withECDSA";
-			algorithms["SHA1/ECDSA"] = "SHA-1withECDSA";
-			algorithms["SHA-1/ECDSA"] = "SHA-1withECDSA";
-			algorithms["ECDSAWITHSHA1"] = "SHA-1withECDSA";
-			algorithms["ECDSAWITHSHA-1"] = "SHA-1withECDSA";
-			algorithms["SHA1WITHECDSA"] = "SHA-1withECDSA";
+            algorithms["DSAWITHSHA224"] = "SHA-224withDSA";
+            algorithms["DSAWITHSHA-224"] = "SHA-224withDSA";
+            algorithms["SHA224/DSA"] = "SHA-224withDSA";
+            algorithms["SHA-224/DSA"] = "SHA-224withDSA";
+            algorithms["SHA224WITHDSA"] = "SHA-224withDSA";
+            algorithms["SHA-224WITHDSA"] = "SHA-224withDSA";
+            algorithms[NistObjectIdentifiers.DsaWithSha224.Id] = "SHA-224withDSA";
+
+            algorithms["DSAWITHSHA256"] = "SHA-256withDSA";
+            algorithms["DSAWITHSHA-256"] = "SHA-256withDSA";
+            algorithms["SHA256/DSA"] = "SHA-256withDSA";
+            algorithms["SHA-256/DSA"] = "SHA-256withDSA";
+            algorithms["SHA256WITHDSA"] = "SHA-256withDSA";
+            algorithms["SHA-256WITHDSA"] = "SHA-256withDSA";
+            algorithms[NistObjectIdentifiers.DsaWithSha256.Id] = "SHA-256withDSA";
+
+            algorithms["DSAWITHSHA384"] = "SHA-384withDSA";
+            algorithms["DSAWITHSHA-384"] = "SHA-384withDSA";
+            algorithms["SHA384/DSA"] = "SHA-384withDSA";
+            algorithms["SHA-384/DSA"] = "SHA-384withDSA";
+            algorithms["SHA384WITHDSA"] = "SHA-384withDSA";
+            algorithms["SHA-384WITHDSA"] = "SHA-384withDSA";
+            algorithms[NistObjectIdentifiers.DsaWithSha384.Id] = "SHA-384withDSA";
+
+            algorithms["DSAWITHSHA512"] = "SHA-512withDSA";
+            algorithms["DSAWITHSHA-512"] = "SHA-512withDSA";
+            algorithms["SHA512/DSA"] = "SHA-512withDSA";
+            algorithms["SHA-512/DSA"] = "SHA-512withDSA";
+            algorithms["SHA512WITHDSA"] = "SHA-512withDSA";
+            algorithms["SHA-512WITHDSA"] = "SHA-512withDSA";
+            algorithms[NistObjectIdentifiers.DsaWithSha512.Id] = "SHA-512withDSA";
+
+            algorithms["NONEWITHECDSA"] = "NONEwithECDSA";
+            algorithms["ECDSAWITHNONE"] = "NONEwithECDSA";
+
+            algorithms["ECDSA"] = "SHA-1withECDSA";
+            algorithms["SHA1/ECDSA"] = "SHA-1withECDSA";
+            algorithms["SHA-1/ECDSA"] = "SHA-1withECDSA";
+            algorithms["ECDSAWITHSHA1"] = "SHA-1withECDSA";
+            algorithms["ECDSAWITHSHA-1"] = "SHA-1withECDSA";
+            algorithms["SHA1WITHECDSA"] = "SHA-1withECDSA";
             algorithms["SHA-1WITHECDSA"] = "SHA-1withECDSA";
-			algorithms[X9ObjectIdentifiers.ECDsaWithSha1.Id] = "SHA-1withECDSA";
-			algorithms[TeleTrusTObjectIdentifiers.ECSignWithSha1.Id] = "SHA-1withECDSA";
-
-			algorithms["SHA224/ECDSA"] = "SHA-224withECDSA";
-			algorithms["SHA-224/ECDSA"] = "SHA-224withECDSA";
-			algorithms["ECDSAWITHSHA224"] = "SHA-224withECDSA";
-			algorithms["ECDSAWITHSHA-224"] = "SHA-224withECDSA";
-			algorithms["SHA224WITHECDSA"] = "SHA-224withECDSA";
-			algorithms["SHA-224WITHECDSA"] = "SHA-224withECDSA";
-			algorithms[X9ObjectIdentifiers.ECDsaWithSha224.Id] = "SHA-224withECDSA";
-
-			algorithms["SHA256/ECDSA"] = "SHA-256withECDSA";
-			algorithms["SHA-256/ECDSA"] = "SHA-256withECDSA";
-			algorithms["ECDSAWITHSHA256"] = "SHA-256withECDSA";
-			algorithms["ECDSAWITHSHA-256"] = "SHA-256withECDSA";
-			algorithms["SHA256WITHECDSA"] = "SHA-256withECDSA";
-			algorithms["SHA-256WITHECDSA"] = "SHA-256withECDSA";
-			algorithms[X9ObjectIdentifiers.ECDsaWithSha256.Id] = "SHA-256withECDSA";
-
-			algorithms["SHA384/ECDSA"] = "SHA-384withECDSA";
-			algorithms["SHA-384/ECDSA"] = "SHA-384withECDSA";
-			algorithms["ECDSAWITHSHA384"] = "SHA-384withECDSA";
-			algorithms["ECDSAWITHSHA-384"] = "SHA-384withECDSA";
-			algorithms["SHA384WITHECDSA"] = "SHA-384withECDSA";
-			algorithms["SHA-384WITHECDSA"] = "SHA-384withECDSA";
-			algorithms[X9ObjectIdentifiers.ECDsaWithSha384.Id] = "SHA-384withECDSA";
-
-			algorithms["SHA512/ECDSA"] = "SHA-512withECDSA";
-			algorithms["SHA-512/ECDSA"] = "SHA-512withECDSA";
-			algorithms["ECDSAWITHSHA512"] = "SHA-512withECDSA";
-			algorithms["ECDSAWITHSHA-512"] = "SHA-512withECDSA";
-			algorithms["SHA512WITHECDSA"] = "SHA-512withECDSA";
-			algorithms["SHA-512WITHECDSA"] = "SHA-512withECDSA";
-			algorithms[X9ObjectIdentifiers.ECDsaWithSha512.Id] = "SHA-512withECDSA";
-
-			algorithms["RIPEMD160/ECDSA"] = "RIPEMD160withECDSA";
-			algorithms["SHA-512/ECDSA"] = "RIPEMD160withECDSA";
-			algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
-			algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
-			algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
-			algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
-			algorithms[TeleTrusTObjectIdentifiers.ECSignWithRipeMD160.Id] = "RIPEMD160withECDSA";
-
-			algorithms["GOST-3410"] = "GOST3410";
-			algorithms["GOST-3410-94"] = "GOST3410";
-			algorithms["GOST3411WITHGOST3410"] = "GOST3410";
-			algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410";
-
-			algorithms["ECGOST-3410"] = "ECGOST3410";
-			algorithms["ECGOST-3410-2001"] = "ECGOST3410";
-			algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
-			algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
-
-
-
-			oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
+            algorithms[X9ObjectIdentifiers.ECDsaWithSha1.Id] = "SHA-1withECDSA";
+            algorithms[TeleTrusTObjectIdentifiers.ECSignWithSha1.Id] = "SHA-1withECDSA";
+
+            algorithms["SHA224/ECDSA"] = "SHA-224withECDSA";
+            algorithms["SHA-224/ECDSA"] = "SHA-224withECDSA";
+            algorithms["ECDSAWITHSHA224"] = "SHA-224withECDSA";
+            algorithms["ECDSAWITHSHA-224"] = "SHA-224withECDSA";
+            algorithms["SHA224WITHECDSA"] = "SHA-224withECDSA";
+            algorithms["SHA-224WITHECDSA"] = "SHA-224withECDSA";
+            algorithms[X9ObjectIdentifiers.ECDsaWithSha224.Id] = "SHA-224withECDSA";
+
+            algorithms["SHA256/ECDSA"] = "SHA-256withECDSA";
+            algorithms["SHA-256/ECDSA"] = "SHA-256withECDSA";
+            algorithms["ECDSAWITHSHA256"] = "SHA-256withECDSA";
+            algorithms["ECDSAWITHSHA-256"] = "SHA-256withECDSA";
+            algorithms["SHA256WITHECDSA"] = "SHA-256withECDSA";
+            algorithms["SHA-256WITHECDSA"] = "SHA-256withECDSA";
+            algorithms[X9ObjectIdentifiers.ECDsaWithSha256.Id] = "SHA-256withECDSA";
+
+            algorithms["SHA384/ECDSA"] = "SHA-384withECDSA";
+            algorithms["SHA-384/ECDSA"] = "SHA-384withECDSA";
+            algorithms["ECDSAWITHSHA384"] = "SHA-384withECDSA";
+            algorithms["ECDSAWITHSHA-384"] = "SHA-384withECDSA";
+            algorithms["SHA384WITHECDSA"] = "SHA-384withECDSA";
+            algorithms["SHA-384WITHECDSA"] = "SHA-384withECDSA";
+            algorithms[X9ObjectIdentifiers.ECDsaWithSha384.Id] = "SHA-384withECDSA";
+
+            algorithms["SHA512/ECDSA"] = "SHA-512withECDSA";
+            algorithms["SHA-512/ECDSA"] = "SHA-512withECDSA";
+            algorithms["ECDSAWITHSHA512"] = "SHA-512withECDSA";
+            algorithms["ECDSAWITHSHA-512"] = "SHA-512withECDSA";
+            algorithms["SHA512WITHECDSA"] = "SHA-512withECDSA";
+            algorithms["SHA-512WITHECDSA"] = "SHA-512withECDSA";
+            algorithms[X9ObjectIdentifiers.ECDsaWithSha512.Id] = "SHA-512withECDSA";
+
+            algorithms["RIPEMD160/ECDSA"] = "RIPEMD160withECDSA";
+            algorithms["ECDSAWITHRIPEMD160"] = "RIPEMD160withECDSA";
+            algorithms["RIPEMD160WITHECDSA"] = "RIPEMD160withECDSA";
+            algorithms[TeleTrusTObjectIdentifiers.ECSignWithRipeMD160.Id] = "RIPEMD160withECDSA";
+
+            algorithms["GOST-3410"] = "GOST3410";
+            algorithms["GOST-3410-94"] = "GOST3410";
+            algorithms["GOST3411WITHGOST3410"] = "GOST3410";
+            algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410";
+
+            algorithms["ECGOST-3410"] = "ECGOST3410";
+            algorithms["ECGOST-3410-2001"] = "ECGOST3410";
+            algorithms["GOST3411WITHECGOST3410"] = "ECGOST3410";
+            algorithms[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
+
+
+
+            oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
             oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
             oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption;
 
@@ -241,129 +237,129 @@ namespace Org.BouncyCastle.Security
             oids["SHA-384withRSA"] = PkcsObjectIdentifiers.Sha384WithRsaEncryption;
             oids["SHA-512withRSA"] = PkcsObjectIdentifiers.Sha512WithRsaEncryption;
 
-			oids["PSSwithRSA"] = PkcsObjectIdentifiers.IdRsassaPss;
-			oids["SHA-1withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
-			oids["SHA-224withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
-			oids["SHA-256withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
-			oids["SHA-384withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
-			oids["SHA-512withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+            oids["PSSwithRSA"] = PkcsObjectIdentifiers.IdRsassaPss;
+            oids["SHA-1withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+            oids["SHA-224withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+            oids["SHA-256withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+            oids["SHA-384withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
+            oids["SHA-512withRSAandMGF1"] = PkcsObjectIdentifiers.IdRsassaPss;
 
-			oids["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128;
-			oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160;
-			oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256;
+            oids["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128;
+            oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160;
+            oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256;
 
-			oids["SHA-1withDSA"] = X9ObjectIdentifiers.IdDsaWithSha1;
+            oids["SHA-1withDSA"] = X9ObjectIdentifiers.IdDsaWithSha1;
 
-			oids["SHA-1withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha1;
-			oids["SHA-224withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha224;
-			oids["SHA-256withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha256;
-			oids["SHA-384withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha384;
-			oids["SHA-512withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha512;
+            oids["SHA-1withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha1;
+            oids["SHA-224withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha224;
+            oids["SHA-256withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha256;
+            oids["SHA-384withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha384;
+            oids["SHA-512withECDSA"] = X9ObjectIdentifiers.ECDsaWithSha512;
 
-			oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
-			oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
-		}
+            oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
+            oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
+        }
 
-		/// <summary>
+        /// <summary>
         /// Returns a ObjectIdentifier for a give encoding.
         /// </summary>
         /// <param name="mechanism">A string representation of the encoding.</param>
         /// <returns>A DerObjectIdentifier, null if the Oid is not available.</returns>
-		// TODO Don't really want to support this
+        // TODO Don't really want to support this
         public static DerObjectIdentifier GetObjectIdentifier(
-			string mechanism)
+            string mechanism)
         {
-			if (mechanism == null)
-				throw new ArgumentNullException("mechanism");
+            if (mechanism == null)
+                throw new ArgumentNullException("mechanism");
 
-			mechanism = mechanism.ToUpperInvariant();
-			string aliased = (string) algorithms[mechanism];
+            mechanism = Platform.ToUpperInvariant(mechanism);
+            string aliased = (string) algorithms[mechanism];
 
-			if (aliased != null)
-				mechanism = aliased;
+            if (aliased != null)
+                mechanism = aliased;
 
-			return (DerObjectIdentifier) oids[mechanism];
-		}
+            return (DerObjectIdentifier) oids[mechanism];
+        }
 
-		public static ICollection Algorithms
+        public static ICollection Algorithms
         {
             get { return oids.Keys; }
         }
 
-		public static Asn1Encodable GetDefaultX509Parameters(
-			DerObjectIdentifier id)
-		{
-			return GetDefaultX509Parameters(id.Id);
-		}
-
-		public static Asn1Encodable GetDefaultX509Parameters(
-			string algorithm)
-		{
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
-
-			algorithm = algorithm.ToUpperInvariant();
-
-			string mechanism = (string) algorithms[algorithm];
-
-			if (mechanism == null)
-				mechanism = algorithm;
-
-			if (mechanism == "PSSwithRSA")
-			{
-				// TODO The Sha1Digest here is a default. In JCE version, the actual digest
-				// to be used can be overridden by subsequent parameter settings.
-				return GetPssX509Parameters("SHA-1");
-			}
-
-			if (mechanism.EndsWith("withRSAandMGF1"))
-			{
-				string digestName = mechanism.Substring(0, mechanism.Length - "withRSAandMGF1".Length);
-				return GetPssX509Parameters(digestName);
-			}
-
-			return DerNull.Instance;
-		}
-
-		private static Asn1Encodable GetPssX509Parameters(
-			string	digestName)
-		{
-			AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
-				DigestUtilities.GetObjectIdentifier(digestName), DerNull.Instance);
-
-			// TODO Is it possible for the MGF hash alg to be different from the PSS one?
-			AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
-				PkcsObjectIdentifiers.IdMgf1, hashAlgorithm);
-
-			int saltLen = DigestUtilities.GetDigest(digestName).GetDigestSize();
-			return new RsassaPssParameters(hashAlgorithm, maskGenAlgorithm,
-				new DerInteger(saltLen), new DerInteger(1));
-		}
-
-		public static ISigner GetSigner(
-			DerObjectIdentifier id)
+        public static Asn1Encodable GetDefaultX509Parameters(
+            DerObjectIdentifier id)
+        {
+            return GetDefaultX509Parameters(id.Id);
+        }
+
+        public static Asn1Encodable GetDefaultX509Parameters(
+            string algorithm)
+        {
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
+
+            algorithm = Platform.ToUpperInvariant(algorithm);
+
+            string mechanism = (string) algorithms[algorithm];
+
+            if (mechanism == null)
+                mechanism = algorithm;
+
+            if (mechanism == "PSSwithRSA")
+            {
+                // TODO The Sha1Digest here is a default. In JCE version, the actual digest
+                // to be used can be overridden by subsequent parameter settings.
+                return GetPssX509Parameters("SHA-1");
+            }
+
+            if (mechanism.EndsWith("withRSAandMGF1"))
+            {
+                string digestName = mechanism.Substring(0, mechanism.Length - "withRSAandMGF1".Length);
+                return GetPssX509Parameters(digestName);
+            }
+
+            return DerNull.Instance;
+        }
+
+        private static Asn1Encodable GetPssX509Parameters(
+            string	digestName)
+        {
+            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+                DigestUtilities.GetObjectIdentifier(digestName), DerNull.Instance);
+
+            // TODO Is it possible for the MGF hash alg to be different from the PSS one?
+            AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+                PkcsObjectIdentifiers.IdMgf1, hashAlgorithm);
+
+            int saltLen = DigestUtilities.GetDigest(digestName).GetDigestSize();
+            return new RsassaPssParameters(hashAlgorithm, maskGenAlgorithm,
+                new DerInteger(saltLen), new DerInteger(1));
+        }
+
+        public static ISigner GetSigner(
+            DerObjectIdentifier id)
         {
             return GetSigner(id.Id);
         }
 
-		public static ISigner GetSigner(
-			string algorithm)
+        public static ISigner GetSigner(
+            string algorithm)
         {
-			if (algorithm == null)
-				throw new ArgumentNullException("algorithm");
+            if (algorithm == null)
+                throw new ArgumentNullException("algorithm");
 
-			algorithm = algorithm.ToUpperInvariant();
+            algorithm = Platform.ToUpperInvariant(algorithm);
 
-			string mechanism = (string) algorithms[algorithm];
+            string mechanism = (string) algorithms[algorithm];
 
-			if (mechanism == null)
-				mechanism = algorithm;
+            if (mechanism == null)
+                mechanism = algorithm;
 
-			if (mechanism.Equals("RSA"))
-			{
-				return (new RsaDigestSigner(new NullDigest()));
-			}
-			if (mechanism.Equals("MD2withRSA"))
+            if (mechanism.Equals("RSA"))
+            {
+                return (new RsaDigestSigner(new NullDigest(), (AlgorithmIdentifier)null));
+            }
+            if (mechanism.Equals("MD2withRSA"))
             {
                 return (new RsaDigestSigner(new MD2Digest()));
             }
@@ -395,7 +391,7 @@ namespace Org.BouncyCastle.Security
             {
                 return (new RsaDigestSigner(new Sha512Digest()));
             }
-			if (mechanism.Equals("RIPEMD128withRSA"))
+            if (mechanism.Equals("RIPEMD128withRSA"))
             {
                 return (new RsaDigestSigner(new RipeMD128Digest()));
             }
@@ -408,141 +404,141 @@ namespace Org.BouncyCastle.Security
                 return (new RsaDigestSigner(new RipeMD256Digest()));
             }
 
-			if (mechanism.Equals("RAWRSASSA-PSS"))
-			{
-				// TODO Add support for other parameter settings
-				return PssSigner.CreateRawSigner(new RsaBlindedEngine(), new Sha1Digest());
-			}
-			if (mechanism.Equals("PSSwithRSA"))
-			{
-				// TODO The Sha1Digest here is a default. In JCE version, the actual digest
-				// to be used can be overridden by subsequent parameter settings.
-				return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
-			}
-			if (mechanism.Equals("SHA-1withRSAandMGF1"))
-			{
-				return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
-			}
-			if (mechanism.Equals("SHA-224withRSAandMGF1"))
-			{
-				return (new PssSigner(new RsaBlindedEngine(), new Sha224Digest()));
-			}
-			if (mechanism.Equals("SHA-256withRSAandMGF1"))
-			{
-				return (new PssSigner(new RsaBlindedEngine(), new Sha256Digest()));
-			}
-			if (mechanism.Equals("SHA-384withRSAandMGF1"))
-			{
-				return (new PssSigner(new RsaBlindedEngine(), new Sha384Digest()));
-			}
-			if (mechanism.Equals("SHA-512withRSAandMGF1"))
-			{
-				return (new PssSigner(new RsaBlindedEngine(), new Sha512Digest()));
-			}
-
-			if (mechanism.Equals("NONEwithDSA"))
-			{
-				return (new DsaDigestSigner(new DsaSigner(), new NullDigest()));
-			}
-			if (mechanism.Equals("SHA-1withDSA"))
+            if (mechanism.Equals("RAWRSASSA-PSS"))
+            {
+                // TODO Add support for other parameter settings
+                return PssSigner.CreateRawSigner(new RsaBlindedEngine(), new Sha1Digest());
+            }
+            if (mechanism.Equals("PSSwithRSA"))
+            {
+                // TODO The Sha1Digest here is a default. In JCE version, the actual digest
+                // to be used can be overridden by subsequent parameter settings.
+                return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+            }
+            if (mechanism.Equals("SHA-1withRSAandMGF1"))
+            {
+                return (new PssSigner(new RsaBlindedEngine(), new Sha1Digest()));
+            }
+            if (mechanism.Equals("SHA-224withRSAandMGF1"))
+            {
+                return (new PssSigner(new RsaBlindedEngine(), new Sha224Digest()));
+            }
+            if (mechanism.Equals("SHA-256withRSAandMGF1"))
+            {
+                return (new PssSigner(new RsaBlindedEngine(), new Sha256Digest()));
+            }
+            if (mechanism.Equals("SHA-384withRSAandMGF1"))
+            {
+                return (new PssSigner(new RsaBlindedEngine(), new Sha384Digest()));
+            }
+            if (mechanism.Equals("SHA-512withRSAandMGF1"))
+            {
+                return (new PssSigner(new RsaBlindedEngine(), new Sha512Digest()));
+            }
+
+            if (mechanism.Equals("NONEwithDSA"))
+            {
+                return (new DsaDigestSigner(new DsaSigner(), new NullDigest()));
+            }
+            if (mechanism.Equals("SHA-1withDSA"))
             {
                 return (new DsaDigestSigner(new DsaSigner(), new Sha1Digest()));
             }
-			if (mechanism.Equals("SHA-224withDSA"))
-			{
-				return (new DsaDigestSigner(new DsaSigner(), new Sha224Digest()));
-			}
-			if (mechanism.Equals("SHA-256withDSA"))
-			{
-				return (new DsaDigestSigner(new DsaSigner(), new Sha256Digest()));
-			}
-			if (mechanism.Equals("SHA-384withDSA"))
-			{
-				return (new DsaDigestSigner(new DsaSigner(), new Sha384Digest()));
-			}
-			if (mechanism.Equals("SHA-512withDSA"))
-			{
-				return (new DsaDigestSigner(new DsaSigner(), new Sha512Digest()));
-			}
-
-			if (mechanism.Equals("NONEwithECDSA"))
-			{
-				return (new DsaDigestSigner(new ECDsaSigner(), new NullDigest()));
-			}
-			if (mechanism.Equals("SHA-1withECDSA"))
+            if (mechanism.Equals("SHA-224withDSA"))
+            {
+                return (new DsaDigestSigner(new DsaSigner(), new Sha224Digest()));
+            }
+            if (mechanism.Equals("SHA-256withDSA"))
+            {
+                return (new DsaDigestSigner(new DsaSigner(), new Sha256Digest()));
+            }
+            if (mechanism.Equals("SHA-384withDSA"))
+            {
+                return (new DsaDigestSigner(new DsaSigner(), new Sha384Digest()));
+            }
+            if (mechanism.Equals("SHA-512withDSA"))
+            {
+                return (new DsaDigestSigner(new DsaSigner(), new Sha512Digest()));
+            }
+
+            if (mechanism.Equals("NONEwithECDSA"))
+            {
+                return (new DsaDigestSigner(new ECDsaSigner(), new NullDigest()));
+            }
+            if (mechanism.Equals("SHA-1withECDSA"))
             {
                 return (new DsaDigestSigner(new ECDsaSigner(), new Sha1Digest()));
             }
-			if (mechanism.Equals("SHA-224withECDSA"))
-			{
-				return (new DsaDigestSigner(new ECDsaSigner(), new Sha224Digest()));
-			}
-			if (mechanism.Equals("SHA-256withECDSA"))
-			{
-				return (new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest()));
-			}
-			if (mechanism.Equals("SHA-384withECDSA"))
-			{
-				return (new DsaDigestSigner(new ECDsaSigner(), new Sha384Digest()));
-			}
-			if (mechanism.Equals("SHA-512withECDSA"))
-			{
-				return (new DsaDigestSigner(new ECDsaSigner(), new Sha512Digest()));
-			}
-
-			if (mechanism.Equals("RIPEMD160withECDSA"))
-			{
-				return (new DsaDigestSigner(new ECDsaSigner(), new RipeMD160Digest()));
-			}
-
-			if (mechanism.Equals("SHA1WITHECNR"))
-			{
-				return (new DsaDigestSigner(new ECNRSigner(), new Sha1Digest()));
-			}
-			if (mechanism.Equals("SHA224WITHECNR"))
-			{
-				return (new DsaDigestSigner(new ECNRSigner(), new Sha224Digest()));
-			}
-			if (mechanism.Equals("SHA256WITHECNR"))
-			{
-				return (new DsaDigestSigner(new ECNRSigner(), new Sha256Digest()));
-			}
-			if (mechanism.Equals("SHA384WITHECNR"))
-			{
-				return (new DsaDigestSigner(new ECNRSigner(), new Sha384Digest()));
-			}
-			if (mechanism.Equals("SHA512WITHECNR"))
-			{
-				return (new DsaDigestSigner(new ECNRSigner(), new Sha512Digest()));
-			}
-
-			if (mechanism.Equals("GOST3410"))
-			{
-				return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
-			}
-			if (mechanism.Equals("ECGOST3410"))
-			{
-				return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
-			}
-
-			if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
-			{
-				return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
-			}
-			if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
-			{
-				return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
-			}
-			if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
-			{
-				return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
-			}
-
-			throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+            if (mechanism.Equals("SHA-224withECDSA"))
+            {
+                return (new DsaDigestSigner(new ECDsaSigner(), new Sha224Digest()));
+            }
+            if (mechanism.Equals("SHA-256withECDSA"))
+            {
+                return (new DsaDigestSigner(new ECDsaSigner(), new Sha256Digest()));
+            }
+            if (mechanism.Equals("SHA-384withECDSA"))
+            {
+                return (new DsaDigestSigner(new ECDsaSigner(), new Sha384Digest()));
+            }
+            if (mechanism.Equals("SHA-512withECDSA"))
+            {
+                return (new DsaDigestSigner(new ECDsaSigner(), new Sha512Digest()));
+            }
+
+            if (mechanism.Equals("RIPEMD160withECDSA"))
+            {
+                return (new DsaDigestSigner(new ECDsaSigner(), new RipeMD160Digest()));
+            }
+
+            if (mechanism.Equals("SHA1WITHECNR"))
+            {
+                return (new DsaDigestSigner(new ECNRSigner(), new Sha1Digest()));
+            }
+            if (mechanism.Equals("SHA224WITHECNR"))
+            {
+                return (new DsaDigestSigner(new ECNRSigner(), new Sha224Digest()));
+            }
+            if (mechanism.Equals("SHA256WITHECNR"))
+            {
+                return (new DsaDigestSigner(new ECNRSigner(), new Sha256Digest()));
+            }
+            if (mechanism.Equals("SHA384WITHECNR"))
+            {
+                return (new DsaDigestSigner(new ECNRSigner(), new Sha384Digest()));
+            }
+            if (mechanism.Equals("SHA512WITHECNR"))
+            {
+                return (new DsaDigestSigner(new ECNRSigner(), new Sha512Digest()));
+            }
+
+            if (mechanism.Equals("GOST3410"))
+            {
+                return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
+            }
+            if (mechanism.Equals("ECGOST3410"))
+            {
+                return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
+            }
+
+            if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
+            {
+                return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
+            }
+            if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+            {
+                return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+            }
+            if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+            {
+                return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+            }
+
+            throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
         }
 
         public static string GetEncodingName(
-			DerObjectIdentifier oid)
+            DerObjectIdentifier oid)
         {
             return (string) algorithms[oid.Id];
         }
diff --git a/crypto/src/security/WrapperUtilities.cs b/crypto/src/security/WrapperUtilities.cs
index 33567c51b..ce31ea519 100644
--- a/crypto/src/security/WrapperUtilities.cs
+++ b/crypto/src/security/WrapperUtilities.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Kisa;
@@ -13,141 +12,142 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
-	/// <remarks>
-	///  Utility class for creating IWrapper objects from their names/Oids
-	/// </remarks>
-	public sealed class WrapperUtilities
-	{
-		internal enum WrapAlgorithm { AESWRAP, CAMELLIAWRAP, DESEDEWRAP, RC2WRAP, SEEDWRAP,
-			DESEDERFC3211WRAP, AESRFC3211WRAP, CAMELLIARFC3211WRAP };
-
-		private WrapperUtilities()
-		{
-		}
-
-		private static readonly IDictionary algorithms = Platform.CreateHashtable();
+    /// <remarks>
+    ///  Utility class for creating IWrapper objects from their names/Oids
+    /// </remarks>
+    public sealed class WrapperUtilities
+    {
+        private enum WrapAlgorithm { AESWRAP, CAMELLIAWRAP, DESEDEWRAP, RC2WRAP, SEEDWRAP,
+            DESEDERFC3211WRAP, AESRFC3211WRAP, CAMELLIARFC3211WRAP };
+
+        private WrapperUtilities()
+        {
+        }
+
+        private static readonly IDictionary algorithms = Platform.CreateHashtable();
         //private static readonly IDictionary oids = Platform.CreateHashtable();
 
-		static WrapperUtilities()
-		{
-			// Signal to obfuscation tools not to change enum constants
-			((WrapAlgorithm)Enums.GetArbitraryValue(typeof(WrapAlgorithm))).ToString();
-
-			algorithms[NistObjectIdentifiers.IdAes128Wrap.Id] = "AESWRAP";
-			algorithms[NistObjectIdentifiers.IdAes192Wrap.Id] = "AESWRAP";
-			algorithms[NistObjectIdentifiers.IdAes256Wrap.Id] = "AESWRAP";
-
-			algorithms[NttObjectIdentifiers.IdCamellia128Wrap.Id] = "CAMELLIAWRAP";
-			algorithms[NttObjectIdentifiers.IdCamellia192Wrap.Id] = "CAMELLIAWRAP";
-			algorithms[NttObjectIdentifiers.IdCamellia256Wrap.Id] = "CAMELLIAWRAP";
-
-			algorithms[PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id] = "DESEDEWRAP";
-
-			algorithms[PkcsObjectIdentifiers.IdAlgCmsRC2Wrap.Id] = "RC2WRAP";
-
-			algorithms[KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id] = "SEEDWRAP";
-		}
-
-		public static IWrapper GetWrapper(
-			DerObjectIdentifier oid)
-		{
-			return GetWrapper(oid.Id);
-		}
-
-		public static IWrapper GetWrapper(
-			string algorithm)
-		{
-			string upper = algorithm.ToUpperInvariant();
-			string mechanism = (string) algorithms[upper];
-
-			if (mechanism == null)
-			{
-				mechanism = upper;
-			}
-
-			try
-			{
-				WrapAlgorithm wrapAlgorithm = (WrapAlgorithm)Enums.GetEnumValue(
-					typeof(WrapAlgorithm), mechanism);
-
-				switch (wrapAlgorithm)
-				{
-					case WrapAlgorithm.AESWRAP:				return new AesWrapEngine();
-					case WrapAlgorithm.CAMELLIAWRAP:		return new CamelliaWrapEngine();
-					case WrapAlgorithm.DESEDEWRAP:			return new DesEdeWrapEngine();
-					case WrapAlgorithm.RC2WRAP:				return new RC2WrapEngine();
-					case WrapAlgorithm.SEEDWRAP:			return new SeedWrapEngine();
-					case WrapAlgorithm.DESEDERFC3211WRAP:	return new Rfc3211WrapEngine(new DesEdeEngine());
-					case WrapAlgorithm.AESRFC3211WRAP:		return new Rfc3211WrapEngine(new AesFastEngine());
-					case WrapAlgorithm.CAMELLIARFC3211WRAP:	return new Rfc3211WrapEngine(new CamelliaEngine());
-				}
-			}
-			catch (ArgumentException)
-			{
-			}
-
-			// Create an IBufferedCipher and use it as IWrapper (via BufferedCipherWrapper)
-			IBufferedCipher blockCipher = CipherUtilities.GetCipher(algorithm);
-
-			if (blockCipher != null)
-				return new BufferedCipherWrapper(blockCipher);
-
-			throw new SecurityUtilityException("Wrapper " + algorithm + " not recognised.");
-		}
-
-		public static string GetAlgorithmName(
-			DerObjectIdentifier oid)
-		{
-			return (string) algorithms[oid.Id];
-		}
-
-		private class BufferedCipherWrapper
-			: IWrapper
-		{
-			private readonly IBufferedCipher cipher;
-			private bool forWrapping;
-
-			public BufferedCipherWrapper(
-				IBufferedCipher cipher)
-			{
-				this.cipher = cipher;
-			}
-
-			public string AlgorithmName
-			{
-				get { return cipher.AlgorithmName; }
-			}
-
-			public void Init(
-				bool				forWrapping,
-				ICipherParameters	parameters)
-			{
-				this.forWrapping = forWrapping;
-
-				cipher.Init(forWrapping, parameters);
-			}
-
-			public byte[] Wrap(
-				byte[]	input,
-				int		inOff,
-				int		length)
-			{
-				if (!forWrapping)
-					throw new InvalidOperationException("Not initialised for wrapping");
-
-				return cipher.DoFinal(input, inOff, length);
-			}
-
-			public byte[] Unwrap(
-				byte[]	input,
-				int		inOff,
-				int		length)
-			{
-				if (forWrapping)
-					throw new InvalidOperationException("Not initialised for unwrapping");
-
-				return cipher.DoFinal(input, inOff, length);
-			}
-		}
-	}
+        static WrapperUtilities()
+        {
+            // Signal to obfuscation tools not to change enum constants
+            ((WrapAlgorithm)Enums.GetArbitraryValue(typeof(WrapAlgorithm))).ToString();
+
+            algorithms[NistObjectIdentifiers.IdAes128Wrap.Id] = "AESWRAP";
+            algorithms[NistObjectIdentifiers.IdAes192Wrap.Id] = "AESWRAP";
+            algorithms[NistObjectIdentifiers.IdAes256Wrap.Id] = "AESWRAP";
+
+            algorithms[NttObjectIdentifiers.IdCamellia128Wrap.Id] = "CAMELLIAWRAP";
+            algorithms[NttObjectIdentifiers.IdCamellia192Wrap.Id] = "CAMELLIAWRAP";
+            algorithms[NttObjectIdentifiers.IdCamellia256Wrap.Id] = "CAMELLIAWRAP";
+
+            algorithms[PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id] = "DESEDEWRAP";
+            algorithms["TDEAWRAP"] = "DESEDEWRAP";
+
+            algorithms[PkcsObjectIdentifiers.IdAlgCmsRC2Wrap.Id] = "RC2WRAP";
+
+            algorithms[KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id] = "SEEDWRAP";
+        }
+
+        public static IWrapper GetWrapper(
+            DerObjectIdentifier oid)
+        {
+            return GetWrapper(oid.Id);
+        }
+
+        public static IWrapper GetWrapper(
+            string algorithm)
+        {
+            string upper = Platform.ToUpperInvariant(algorithm);
+            string mechanism = (string)algorithms[upper];
+
+            if (mechanism == null)
+            {
+                mechanism = upper;
+            }
+
+            try
+            {
+                WrapAlgorithm wrapAlgorithm = (WrapAlgorithm)Enums.GetEnumValue(
+                    typeof(WrapAlgorithm), mechanism);
+
+                switch (wrapAlgorithm)
+                {
+                    case WrapAlgorithm.AESWRAP:				return new AesWrapEngine();
+                    case WrapAlgorithm.CAMELLIAWRAP:		return new CamelliaWrapEngine();
+                    case WrapAlgorithm.DESEDEWRAP:			return new DesEdeWrapEngine();
+                    case WrapAlgorithm.RC2WRAP:				return new RC2WrapEngine();
+                    case WrapAlgorithm.SEEDWRAP:			return new SeedWrapEngine();
+                    case WrapAlgorithm.DESEDERFC3211WRAP:	return new Rfc3211WrapEngine(new DesEdeEngine());
+                    case WrapAlgorithm.AESRFC3211WRAP:		return new Rfc3211WrapEngine(new AesFastEngine());
+                    case WrapAlgorithm.CAMELLIARFC3211WRAP:	return new Rfc3211WrapEngine(new CamelliaEngine());
+                }
+            }
+            catch (ArgumentException)
+            {
+            }
+
+            // Create an IBufferedCipher and use it as IWrapper (via BufferedCipherWrapper)
+            IBufferedCipher blockCipher = CipherUtilities.GetCipher(algorithm);
+
+            if (blockCipher != null)
+                return new BufferedCipherWrapper(blockCipher);
+
+            throw new SecurityUtilityException("Wrapper " + algorithm + " not recognised.");
+        }
+
+        public static string GetAlgorithmName(
+            DerObjectIdentifier oid)
+        {
+            return (string) algorithms[oid.Id];
+        }
+
+        private class BufferedCipherWrapper
+            : IWrapper
+        {
+            private readonly IBufferedCipher cipher;
+            private bool forWrapping;
+
+            public BufferedCipherWrapper(
+                IBufferedCipher cipher)
+            {
+                this.cipher = cipher;
+            }
+
+            public string AlgorithmName
+            {
+                get { return cipher.AlgorithmName; }
+            }
+
+            public void Init(
+                bool				forWrapping,
+                ICipherParameters	parameters)
+            {
+                this.forWrapping = forWrapping;
+
+                cipher.Init(forWrapping, parameters);
+            }
+
+            public byte[] Wrap(
+                byte[]	input,
+                int		inOff,
+                int		length)
+            {
+                if (!forWrapping)
+                    throw new InvalidOperationException("Not initialised for wrapping");
+
+                return cipher.DoFinal(input, inOff, length);
+            }
+
+            public byte[] Unwrap(
+                byte[]	input,
+                int		inOff,
+                int		length)
+            {
+                if (forWrapping)
+                    throw new InvalidOperationException("Not initialised for unwrapping");
+
+                return cipher.DoFinal(input, inOff, length);
+            }
+        }
+    }
 }
diff --git a/crypto/src/security/cert/CertificateEncodingException.cs b/crypto/src/security/cert/CertificateEncodingException.cs
index ae6a56653..a2909b0d5 100644
--- a/crypto/src/security/cert/CertificateEncodingException.cs
+++ b/crypto/src/security/cert/CertificateEncodingException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security.Certificates
 {
-	public class CertificateEncodingException : CertificateException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CertificateEncodingException : CertificateException
 	{
 		public CertificateEncodingException() : base() { }
 		public CertificateEncodingException(string msg) : base(msg) { }
diff --git a/crypto/src/security/cert/CertificateException.cs b/crypto/src/security/cert/CertificateException.cs
index fa403c7f5..441c598e4 100644
--- a/crypto/src/security/cert/CertificateException.cs
+++ b/crypto/src/security/cert/CertificateException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security.Certificates
 {
-	public class CertificateException : GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CertificateException : GeneralSecurityException
 	{
 		public CertificateException() : base() { }
 		public CertificateException(string message) : base(message) { }
diff --git a/crypto/src/security/cert/CertificateExpiredException.cs b/crypto/src/security/cert/CertificateExpiredException.cs
index 33a54806f..c893c07ee 100644
--- a/crypto/src/security/cert/CertificateExpiredException.cs
+++ b/crypto/src/security/cert/CertificateExpiredException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security.Certificates
 {
-	public class CertificateExpiredException : CertificateException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CertificateExpiredException : CertificateException
 	{
 		public CertificateExpiredException() : base() { }
 		public CertificateExpiredException(string message) : base(message) { }
diff --git a/crypto/src/security/cert/CertificateNotYetValidException.cs b/crypto/src/security/cert/CertificateNotYetValidException.cs
index b9210e57c..a0081ce23 100644
--- a/crypto/src/security/cert/CertificateNotYetValidException.cs
+++ b/crypto/src/security/cert/CertificateNotYetValidException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security.Certificates
 {
-	public class CertificateNotYetValidException : CertificateException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CertificateNotYetValidException : CertificateException
 	{
 		public CertificateNotYetValidException() : base() { }
 		public CertificateNotYetValidException(string message) : base(message) { }
diff --git a/crypto/src/security/cert/CertificateParsingException.cs b/crypto/src/security/cert/CertificateParsingException.cs
index 9a1d0111b..8d8ed1e92 100644
--- a/crypto/src/security/cert/CertificateParsingException.cs
+++ b/crypto/src/security/cert/CertificateParsingException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security.Certificates
 {
-	public class CertificateParsingException : CertificateException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CertificateParsingException : CertificateException
 	{
 		public CertificateParsingException() : base() { }
 		public CertificateParsingException(string message) : base(message) { }
diff --git a/crypto/src/security/cert/CrlException.cs b/crypto/src/security/cert/CrlException.cs
index 59e4f20ea..0df007b1e 100644
--- a/crypto/src/security/cert/CrlException.cs
+++ b/crypto/src/security/cert/CrlException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Security.Certificates
 {
-	public class CrlException : GeneralSecurityException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class CrlException : GeneralSecurityException
 	{
 		public CrlException() : base() { }
 		public CrlException(string msg) : base(msg) {}
diff --git a/crypto/src/tsp/GenTimeAccuracy.cs b/crypto/src/tsp/GenTimeAccuracy.cs
new file mode 100644
index 000000000..8a2f29989
--- /dev/null
+++ b/crypto/src/tsp/GenTimeAccuracy.cs
@@ -0,0 +1,33 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+
+namespace Org.BouncyCastle.Tsp
+{
+	public class GenTimeAccuracy
+	{
+		private Accuracy accuracy;
+
+		public GenTimeAccuracy(
+			Accuracy accuracy)
+		{
+			this.accuracy = accuracy;
+		}
+
+		public int Seconds { get { return GetTimeComponent(accuracy.Seconds); } }
+
+		public int Millis { get { return GetTimeComponent(accuracy.Millis); } }
+
+		public int Micros { get { return GetTimeComponent(accuracy.Micros); } }
+
+		private int GetTimeComponent(
+			DerInteger time)
+		{
+			return time == null ? 0 : time.Value.IntValue;
+		}
+
+		public override string ToString()
+		{
+			return Seconds + "." + Millis.ToString("000") + Micros.ToString("000");
+		}
+	}
+}
diff --git a/crypto/src/tsp/TSPAlgorithms.cs b/crypto/src/tsp/TSPAlgorithms.cs
new file mode 100644
index 000000000..e3dfc7916
--- /dev/null
+++ b/crypto/src/tsp/TSPAlgorithms.cs
@@ -0,0 +1,48 @@
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+	/**
+	 * Recognised hash algorithms for the time stamp protocol.
+	 */
+	public abstract class TspAlgorithms
+	{
+		public static readonly string MD5 = PkcsObjectIdentifiers.MD5.Id;
+
+		public static readonly string Sha1 = OiwObjectIdentifiers.IdSha1.Id;
+
+		public static readonly string Sha224 = NistObjectIdentifiers.IdSha224.Id;
+		public static readonly string Sha256 = NistObjectIdentifiers.IdSha256.Id;
+		public static readonly string Sha384 = NistObjectIdentifiers.IdSha384.Id;
+		public static readonly string Sha512 = NistObjectIdentifiers.IdSha512.Id;
+
+		public static readonly string RipeMD128 = TeleTrusTObjectIdentifiers.RipeMD128.Id;
+		public static readonly string RipeMD160 = TeleTrusTObjectIdentifiers.RipeMD160.Id;
+		public static readonly string RipeMD256 = TeleTrusTObjectIdentifiers.RipeMD256.Id;
+
+		public static readonly string Gost3411 = CryptoProObjectIdentifiers.GostR3411.Id;
+
+		public static readonly IList Allowed;
+
+		static TspAlgorithms()
+		{
+			string[] algs = new string[]
+			{
+				Gost3411, MD5, Sha1, Sha224, Sha256, Sha384, Sha512, RipeMD128, RipeMD160, RipeMD256
+			};
+
+			Allowed = Platform.CreateArrayList();
+			foreach (string alg in algs)
+			{
+				Allowed.Add(alg);
+			}
+		}
+	}
+}
diff --git a/crypto/src/tsp/TSPException.cs b/crypto/src/tsp/TSPException.cs
index a5e24163d..3917e96a7 100644
--- a/crypto/src/tsp/TSPException.cs
+++ b/crypto/src/tsp/TSPException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Tsp
 {
-	public class TspException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class TspException
 		: Exception
 	{
 		public TspException()
diff --git a/crypto/src/tsp/TSPUtil.cs b/crypto/src/tsp/TSPUtil.cs
new file mode 100644
index 000000000..1026914f4
--- /dev/null
+++ b/crypto/src/tsp/TSPUtil.cs
@@ -0,0 +1,202 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tsp
+{
+	public class TspUtil
+	{
+		private static ISet EmptySet = CollectionUtilities.ReadOnly(new HashSet());
+		private static IList EmptyList = CollectionUtilities.ReadOnly(Platform.CreateArrayList());
+
+		private static readonly IDictionary digestLengths = Platform.CreateHashtable();
+        private static readonly IDictionary digestNames = Platform.CreateHashtable();
+
+		static TspUtil()
+		{
+			digestLengths.Add(PkcsObjectIdentifiers.MD5.Id, 16);
+			digestLengths.Add(OiwObjectIdentifiers.IdSha1.Id, 20);
+			digestLengths.Add(NistObjectIdentifiers.IdSha224.Id, 28);
+			digestLengths.Add(NistObjectIdentifiers.IdSha256.Id, 32);
+			digestLengths.Add(NistObjectIdentifiers.IdSha384.Id, 48);
+			digestLengths.Add(NistObjectIdentifiers.IdSha512.Id, 64);
+			digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, 16);
+			digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, 20);
+			digestLengths.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, 32);
+			digestLengths.Add(CryptoProObjectIdentifiers.GostR3411.Id, 32);
+
+			digestNames.Add(PkcsObjectIdentifiers.MD5.Id, "MD5");
+			digestNames.Add(OiwObjectIdentifiers.IdSha1.Id, "SHA1");
+			digestNames.Add(NistObjectIdentifiers.IdSha224.Id, "SHA224");
+			digestNames.Add(NistObjectIdentifiers.IdSha256.Id, "SHA256");
+			digestNames.Add(NistObjectIdentifiers.IdSha384.Id, "SHA384");
+			digestNames.Add(NistObjectIdentifiers.IdSha512.Id, "SHA512");
+			digestNames.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id, "SHA1");
+			digestNames.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id, "SHA224");
+			digestNames.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, "SHA256");
+			digestNames.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id, "SHA384");
+			digestNames.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption.Id, "SHA512");
+			digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD128.Id, "RIPEMD128");
+			digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD160.Id, "RIPEMD160");
+			digestNames.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256");
+			digestNames.Add(CryptoProObjectIdentifiers.GostR3411.Id, "GOST3411");
+		}
+
+
+	    /**
+	     * Fetches the signature time-stamp attributes from a SignerInformation object.
+	     * Checks that the MessageImprint for each time-stamp matches the signature field.
+	     * (see RFC 3161 Appendix A).
+	     *
+	     * @param signerInfo a SignerInformation to search for time-stamps
+	     * @return a collection of TimeStampToken objects
+	     * @throws TSPValidationException
+	     */
+		public static ICollection GetSignatureTimestamps(
+			SignerInformation signerInfo)
+		{
+			IList timestamps = Platform.CreateArrayList();
+
+			Asn1.Cms.AttributeTable unsignedAttrs = signerInfo.UnsignedAttributes;
+			if (unsignedAttrs != null)
+			{
+				foreach (Asn1.Cms.Attribute tsAttr in unsignedAttrs.GetAll(
+					PkcsObjectIdentifiers.IdAASignatureTimeStampToken))
+				{
+					foreach (Asn1Encodable asn1 in tsAttr.AttrValues)
+					{
+						try
+						{
+							Asn1.Cms.ContentInfo contentInfo = Asn1.Cms.ContentInfo.GetInstance(
+								asn1.ToAsn1Object());
+							TimeStampToken timeStampToken = new TimeStampToken(contentInfo);
+							TimeStampTokenInfo tstInfo = timeStampToken.TimeStampInfo;
+
+							byte[] expectedDigest = DigestUtilities.CalculateDigest(
+								GetDigestAlgName(tstInfo.MessageImprintAlgOid),
+							    signerInfo.GetSignature());
+
+							if (!Arrays.ConstantTimeAreEqual(expectedDigest, tstInfo.GetMessageImprintDigest()))
+								throw new TspValidationException("Incorrect digest in message imprint");
+
+							timestamps.Add(timeStampToken);
+						}
+						catch (SecurityUtilityException)
+						{
+							throw new TspValidationException("Unknown hash algorithm specified in timestamp");
+						}
+						catch (Exception)
+						{
+							throw new TspValidationException("Timestamp could not be parsed");
+						}
+					}
+				}
+			}
+
+			return timestamps;
+		}
+
+		/**
+		 * Validate the passed in certificate as being of the correct type to be used
+		 * for time stamping. To be valid it must have an ExtendedKeyUsage extension
+		 * which has a key purpose identifier of id-kp-timeStamping.
+		 *
+		 * @param cert the certificate of interest.
+		 * @throws TspValidationException if the certicate fails on one of the check points.
+		 */
+		public static void ValidateCertificate(
+			X509Certificate cert)
+		{
+			if (cert.Version != 3)
+				throw new ArgumentException("Certificate must have an ExtendedKeyUsage extension.");
+
+			Asn1OctetString ext = cert.GetExtensionValue(X509Extensions.ExtendedKeyUsage);
+			if (ext == null)
+				throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension.");
+
+			if (!cert.GetCriticalExtensionOids().Contains(X509Extensions.ExtendedKeyUsage.Id))
+				throw new TspValidationException("Certificate must have an ExtendedKeyUsage extension marked as critical.");
+
+			try
+			{
+				ExtendedKeyUsage extKey = ExtendedKeyUsage.GetInstance(
+					Asn1Object.FromByteArray(ext.GetOctets()));
+
+				if (!extKey.HasKeyPurposeId(KeyPurposeID.IdKPTimeStamping) || extKey.Count != 1)
+					throw new TspValidationException("ExtendedKeyUsage not solely time stamping.");
+			}
+			catch (IOException)
+			{
+				throw new TspValidationException("cannot process ExtendedKeyUsage extension");
+			}
+		}
+
+		/// <summary>
+		/// Return the digest algorithm using one of the standard JCA string
+		/// representations rather than the algorithm identifier (if possible).
+		/// </summary>
+		internal static string GetDigestAlgName(
+			string digestAlgOID)
+		{
+			string digestName = (string) digestNames[digestAlgOID];
+
+			return digestName != null ? digestName : digestAlgOID;
+		}
+
+		internal static int GetDigestLength(
+			string digestAlgOID)
+		{
+			if (!digestLengths.Contains(digestAlgOID))
+				throw new TspException("digest algorithm cannot be found.");
+
+			return (int)digestLengths[digestAlgOID];
+		}
+
+		internal static IDigest CreateDigestInstance(
+			String digestAlgOID)
+		{
+	        string digestName = GetDigestAlgName(digestAlgOID);
+
+			return DigestUtilities.GetDigest(digestName);
+		}
+
+		internal static ISet GetCriticalExtensionOids(X509Extensions extensions)
+		{
+			if (extensions == null)
+				return EmptySet;
+
+			return CollectionUtilities.ReadOnly(new HashSet(extensions.GetCriticalExtensionOids()));
+		}
+
+		internal static ISet GetNonCriticalExtensionOids(X509Extensions extensions)
+		{
+			if (extensions == null)
+				return EmptySet;
+
+			// TODO: should probably produce a set that imposes correct ordering
+			return CollectionUtilities.ReadOnly(new HashSet(extensions.GetNonCriticalExtensionOids()));
+		}
+		
+		internal static IList GetExtensionOids(X509Extensions extensions)
+		{
+			if (extensions == null)
+				return EmptyList;
+
+			return CollectionUtilities.ReadOnly(Platform.CreateArrayList(extensions.GetExtensionOids()));
+		}
+	}
+}
diff --git a/crypto/src/tsp/TSPValidationException.cs b/crypto/src/tsp/TSPValidationException.cs
index d8243e65f..8ef2ec6cf 100644
--- a/crypto/src/tsp/TSPValidationException.cs
+++ b/crypto/src/tsp/TSPValidationException.cs
@@ -1,3 +1,5 @@
+using System;
+
 namespace Org.BouncyCastle.Tsp
 {
 	/**
@@ -6,7 +8,10 @@ namespace Org.BouncyCastle.Tsp
 	 * If a failure code is associated with the exception it can be retrieved using
 	 * the getFailureCode() method.</p>
 	 */
-	public class TspValidationException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class TspValidationException
 		: TspException
 	{
 		private int failureCode;
diff --git a/crypto/src/tsp/TimeStampRequest.cs b/crypto/src/tsp/TimeStampRequest.cs
new file mode 100644
index 000000000..6b9699379
--- /dev/null
+++ b/crypto/src/tsp/TimeStampRequest.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tsp
+{
+	/**
+	 * Base class for an RFC 3161 Time Stamp Request.
+	 */
+	public class TimeStampRequest
+		: X509ExtensionBase
+	{
+		private TimeStampReq req;
+		private X509Extensions extensions;
+
+		public TimeStampRequest(
+			TimeStampReq req)
+		{
+			this.req = req;
+			this.extensions = req.Extensions;
+		}
+
+		/**
+		* Create a TimeStampRequest from the past in byte array.
+		*
+		* @param req byte array containing the request.
+		* @throws IOException if the request is malformed.
+		*/
+		public TimeStampRequest(
+			byte[] req)
+			: this(new Asn1InputStream(req))
+		{
+		}
+
+		/**
+		* Create a TimeStampRequest from the past in input stream.
+		*
+		* @param in input stream containing the request.
+		* @throws IOException if the request is malformed.
+		*/
+		public TimeStampRequest(
+			Stream input)
+			: this(new Asn1InputStream(input))
+		{
+		}
+
+		private TimeStampRequest(
+			Asn1InputStream str)
+		{
+			try
+			{
+				this.req = TimeStampReq.GetInstance(str.ReadObject());
+			}
+			catch (InvalidCastException e)
+			{
+				throw new IOException("malformed request: " + e);
+			}
+			catch (ArgumentException e)
+			{
+				throw new IOException("malformed request: " + e);
+			}
+		}
+
+		public int Version
+		{
+			get { return req.Version.Value.IntValue; }
+		}
+
+		public string MessageImprintAlgOid
+		{
+			get { return req.MessageImprint.HashAlgorithm.ObjectID.Id; }
+		}
+
+		public byte[] GetMessageImprintDigest()
+		{
+			return req.MessageImprint.GetHashedMessage();
+		}
+
+		public string ReqPolicy
+		{
+			get
+			{
+				return req.ReqPolicy == null
+					?	null
+					:	req.ReqPolicy.Id;
+			}
+		}
+
+		public BigInteger Nonce
+		{
+			get
+			{
+				return req.Nonce == null
+					?	null
+					:	req.Nonce.Value;
+			}
+		}
+
+		public bool CertReq
+		{
+			get
+			{
+				return req.CertReq == null
+					?	false
+					:	req.CertReq.IsTrue;
+			}
+		}
+
+		/**
+		* Validate the timestamp request, checking the digest to see if it is of an
+		* accepted type and whether it is of the correct length for the algorithm specified.
+		*
+		* @param algorithms a set of string OIDS giving accepted algorithms.
+		* @param policies if non-null a set of policies we are willing to sign under.
+		* @param extensions if non-null a set of extensions we are willing to accept.
+		* @throws TspException if the request is invalid, or processing fails.
+		*/
+		public void Validate(
+			IList algorithms,
+			IList policies,
+			IList extensions)
+		{
+			if (!algorithms.Contains(this.MessageImprintAlgOid))
+			{
+				throw new TspValidationException("request contains unknown algorithm.", PkiFailureInfo.BadAlg);
+			}
+
+			if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy))
+			{
+				throw new TspValidationException("request contains unknown policy.", PkiFailureInfo.UnacceptedPolicy);
+			}
+
+			if (this.Extensions != null && extensions != null)
+			{
+				foreach (DerObjectIdentifier oid in this.Extensions.ExtensionOids)
+				{
+					if (!extensions.Contains(oid.Id))
+					{
+						throw new TspValidationException("request contains unknown extension.",
+							PkiFailureInfo.UnacceptedExtension);
+					}
+				}
+			}
+
+			int digestLength = TspUtil.GetDigestLength(this.MessageImprintAlgOid);
+
+			if (digestLength != this.GetMessageImprintDigest().Length)
+			{
+				throw new TspValidationException("imprint digest the wrong length.",
+					PkiFailureInfo.BadDataFormat);
+			}
+		}
+
+		/**
+		 * return the ASN.1 encoded representation of this object.
+		 */
+		public byte[] GetEncoded()
+		{
+			return req.GetEncoded();
+		}
+
+		internal X509Extensions Extensions
+		{
+			get { return req.Extensions; }
+		}
+		
+		public virtual bool HasExtensions
+		{
+			get { return extensions != null; }
+		}
+
+		public virtual X509Extension GetExtension(DerObjectIdentifier oid)
+		{
+			return extensions == null ? null : extensions.GetExtension(oid);
+		}
+
+		public virtual IList GetExtensionOids()
+		{
+			return TspUtil.GetExtensionOids(extensions);
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return Extensions;
+		}
+	}
+}
diff --git a/crypto/src/tsp/TimeStampRequestGenerator.cs b/crypto/src/tsp/TimeStampRequestGenerator.cs
new file mode 100644
index 000000000..2c698e476
--- /dev/null
+++ b/crypto/src/tsp/TimeStampRequestGenerator.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+	/**
+	 * Generator for RFC 3161 Time Stamp Request objects.
+	 */
+	public class TimeStampRequestGenerator
+	{
+		private DerObjectIdentifier reqPolicy;
+
+		private DerBoolean certReq;
+
+		private IDictionary extensions = Platform.CreateHashtable();
+        private IList       extOrdering = Platform.CreateArrayList();
+
+		public void SetReqPolicy(
+			string reqPolicy)
+		{
+			this.reqPolicy = new DerObjectIdentifier(reqPolicy);
+		}
+
+		public void SetCertReq(
+			bool certReq)
+		{
+			this.certReq = DerBoolean.GetInstance(certReq);
+		}
+
+		/**
+		 * add a given extension field for the standard extensions tag (tag 3)
+		 * @throws IOException
+		 */
+		[Obsolete("Use method taking DerObjectIdentifier")]
+		public void AddExtension(
+			string			oid,
+			bool			critical,
+			Asn1Encodable	value)
+		{
+			this.AddExtension(oid, critical, value.GetEncoded());
+		}
+
+		/**
+		* add a given extension field for the standard extensions tag
+		* The value parameter becomes the contents of the octet string associated
+		* with the extension.
+		*/
+		[Obsolete("Use method taking DerObjectIdentifier")]
+		public void AddExtension(
+			string	oid,
+			bool	critical,
+			byte[]	value)
+		{
+			DerObjectIdentifier derOid = new DerObjectIdentifier(oid);
+			extensions[derOid] = new X509Extension(critical, new DerOctetString(value));
+			extOrdering.Add(derOid);
+		}
+
+		/**
+		 * add a given extension field for the standard extensions tag (tag 3)
+		 * @throws IOException
+		 */
+		public virtual void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			Asn1Encodable 		extValue)
+		{
+			this.AddExtension(oid, critical, extValue.GetEncoded());
+		}
+
+		/**
+		 * add a given extension field for the standard extensions tag
+		 * The value parameter becomes the contents of the octet string associated
+		 * with the extension.
+		 */
+		public virtual void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			byte[]				extValue)
+		{
+			extensions.Add(oid, new X509Extension(critical, new DerOctetString(extValue)));
+			extOrdering.Add(oid);
+		}
+
+		public TimeStampRequest Generate(
+			string	digestAlgorithm,
+			byte[]	digest)
+		{
+			return this.Generate(digestAlgorithm, digest, null);
+		}
+
+		public TimeStampRequest Generate(
+			string		digestAlgorithmOid,
+			byte[]		digest,
+			BigInteger	nonce)
+		{
+			if (digestAlgorithmOid == null)
+			{
+				throw new ArgumentException("No digest algorithm specified");
+			}
+
+			DerObjectIdentifier digestAlgOid = new DerObjectIdentifier(digestAlgorithmOid);
+
+			AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOid, DerNull.Instance);
+			MessageImprint messageImprint = new MessageImprint(algID, digest);
+
+			X509Extensions  ext = null;
+
+			if (extOrdering.Count != 0)
+			{
+				ext = new X509Extensions(extOrdering, extensions);
+			}
+
+			DerInteger derNonce = nonce == null
+				?	null
+				:	new DerInteger(nonce);
+
+			return new TimeStampRequest(
+				new TimeStampReq(messageImprint, reqPolicy, derNonce, certReq, ext));
+		}
+
+		public virtual TimeStampRequest Generate(DerObjectIdentifier digestAlgorithm, byte[] digest)
+		{
+			return Generate(digestAlgorithm.Id, digest);
+		}
+
+		public virtual TimeStampRequest Generate(DerObjectIdentifier digestAlgorithm, byte[] digest, BigInteger nonce)
+		{
+			return Generate(digestAlgorithm.Id, digest, nonce);
+		}
+	}
+}
diff --git a/crypto/src/tsp/TimeStampResponse.cs b/crypto/src/tsp/TimeStampResponse.cs
new file mode 100644
index 000000000..069521111
--- /dev/null
+++ b/crypto/src/tsp/TimeStampResponse.cs
@@ -0,0 +1,184 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+	/**
+	 * Base class for an RFC 3161 Time Stamp Response object.
+	 */
+	public class TimeStampResponse
+	{
+		private TimeStampResp	resp;
+		private TimeStampToken	timeStampToken;
+
+		public TimeStampResponse(
+			TimeStampResp resp)
+		{
+			this.resp = resp;
+
+			if (resp.TimeStampToken != null)
+			{
+				timeStampToken = new TimeStampToken(resp.TimeStampToken);
+			}
+		}
+
+		/**
+		* Create a TimeStampResponse from a byte array containing an ASN.1 encoding.
+		*
+		* @param resp the byte array containing the encoded response.
+		* @throws TspException if the response is malformed.
+		* @throws IOException if the byte array doesn't represent an ASN.1 encoding.
+		*/
+		public TimeStampResponse(
+			byte[] resp)
+			: this(readTimeStampResp(new Asn1InputStream(resp)))
+		{
+		}
+
+		/**
+		 * Create a TimeStampResponse from an input stream containing an ASN.1 encoding.
+		 *
+		 * @param input the input stream containing the encoded response.
+		 * @throws TspException if the response is malformed.
+		 * @throws IOException if the stream doesn't represent an ASN.1 encoding.
+		 */
+		public TimeStampResponse(
+			Stream input)
+			: this(readTimeStampResp(new Asn1InputStream(input)))
+		{
+		}
+
+		private static TimeStampResp readTimeStampResp(
+			Asn1InputStream input)
+		{
+			try
+			{
+				return TimeStampResp.GetInstance(input.ReadObject());
+			}
+			catch (ArgumentException e)
+			{
+				throw new TspException("malformed timestamp response: " + e, e);
+			}
+			catch (InvalidCastException e)
+			{
+				throw new TspException("malformed timestamp response: " + e, e);
+			}
+		}
+
+		public int Status
+		{
+			get { return resp.Status.Status.IntValue; }
+		}
+
+		public string GetStatusString()
+		{
+			if (resp.Status.StatusString == null)
+			{
+				return null;
+			}
+
+			StringBuilder statusStringBuf = new StringBuilder();
+			PkiFreeText text = resp.Status.StatusString;
+			for (int i = 0; i != text.Count; i++)
+			{
+				statusStringBuf.Append(text[i].GetString());
+			}
+
+			return statusStringBuf.ToString();
+		}
+
+		public PkiFailureInfo GetFailInfo()
+		{
+			if (resp.Status.FailInfo == null)
+			{
+				return null;
+			}
+
+			return new PkiFailureInfo(resp.Status.FailInfo);
+		}
+
+		public TimeStampToken TimeStampToken
+		{
+			get { return timeStampToken; }
+		}
+
+		/**
+		 * Check this response against to see if it a well formed response for
+		 * the passed in request. Validation will include checking the time stamp
+		 * token if the response status is GRANTED or GRANTED_WITH_MODS.
+		 *
+		 * @param request the request to be checked against
+		 * @throws TspException if the request can not match this response.
+		 */
+		public void Validate(
+			TimeStampRequest request)
+		{
+			TimeStampToken tok = this.TimeStampToken;
+
+			if (tok != null)
+			{
+				TimeStampTokenInfo tstInfo = tok.TimeStampInfo;
+
+				if (request.Nonce != null && !request.Nonce.Equals(tstInfo.Nonce))
+				{
+					throw new TspValidationException("response contains wrong nonce value.");
+				}
+
+				if (this.Status != (int) PkiStatus.Granted && this.Status != (int) PkiStatus.GrantedWithMods)
+				{
+					throw new TspValidationException("time stamp token found in failed request.");
+				}
+
+				if (!Arrays.ConstantTimeAreEqual(request.GetMessageImprintDigest(), tstInfo.GetMessageImprintDigest()))
+				{
+					throw new TspValidationException("response for different message imprint digest.");
+				}
+
+				if (!tstInfo.MessageImprintAlgOid.Equals(request.MessageImprintAlgOid))
+				{
+					throw new TspValidationException("response for different message imprint algorithm.");
+				}
+
+				Asn1.Cms.Attribute scV1 = tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificate];
+				Asn1.Cms.Attribute scV2 = tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
+
+				if (scV1 == null && scV2 == null)
+				{
+					throw new TspValidationException("no signing certificate attribute present.");
+				}
+
+				if (scV1 != null && scV2 != null)
+				{
+					/*
+					 * RFC 5035 5.4. If both attributes exist in a single message,
+					 * they are independently evaluated. 
+					 */
+				}
+
+				if (request.ReqPolicy != null && !request.ReqPolicy.Equals(tstInfo.Policy))
+				{
+					throw new TspValidationException("TSA policy wrong for request.");
+				}
+			}
+			else if (this.Status == (int) PkiStatus.Granted || this.Status == (int) PkiStatus.GrantedWithMods)
+			{
+				throw new TspValidationException("no time stamp token found and one expected.");
+			}
+		}
+
+		/**
+		 * return the ASN.1 encoded representation of this object.
+		 */
+		public byte[] GetEncoded()
+		{
+			return resp.GetEncoded();
+		}
+	}
+}
diff --git a/crypto/src/tsp/TimeStampResponseGenerator.cs b/crypto/src/tsp/TimeStampResponseGenerator.cs
new file mode 100644
index 000000000..8d798de67
--- /dev/null
+++ b/crypto/src/tsp/TimeStampResponseGenerator.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Tsp
+{
+    /**
+     * Generator for RFC 3161 Time Stamp Responses.
+     */
+    public class TimeStampResponseGenerator
+    {
+        private PkiStatus status;
+
+        private Asn1EncodableVector statusStrings;
+
+        private int failInfo;
+        private TimeStampTokenGenerator tokenGenerator;
+        private IList acceptedAlgorithms;
+        private IList acceptedPolicies;
+        private IList acceptedExtensions;
+
+        public TimeStampResponseGenerator(
+            TimeStampTokenGenerator tokenGenerator,
+            IList acceptedAlgorithms)
+            : this(tokenGenerator, acceptedAlgorithms, null, null)
+        {
+        }
+
+        public TimeStampResponseGenerator(
+            TimeStampTokenGenerator tokenGenerator,
+            IList acceptedAlgorithms,
+            IList acceptedPolicy)
+            : this(tokenGenerator, acceptedAlgorithms, acceptedPolicy, null)
+        {
+        }
+
+        public TimeStampResponseGenerator(
+            TimeStampTokenGenerator tokenGenerator,
+            IList acceptedAlgorithms,
+            IList acceptedPolicies,
+            IList acceptedExtensions)
+        {
+            this.tokenGenerator = tokenGenerator;
+            this.acceptedAlgorithms = acceptedAlgorithms;
+            this.acceptedPolicies = acceptedPolicies;
+            this.acceptedExtensions = acceptedExtensions;
+
+            statusStrings = new Asn1EncodableVector();
+        }
+
+        private void AddStatusString(string statusString)
+        {
+            statusStrings.Add(new DerUtf8String(statusString));
+        }
+
+        private void SetFailInfoField(int field)
+        {
+            failInfo |= field;
+        }
+
+        private PkiStatusInfo GetPkiStatusInfo()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+                new DerInteger((int)status));
+
+            if (statusStrings.Count > 0)
+            {
+                v.Add(new PkiFreeText(new DerSequence(statusStrings)));
+            }
+
+            if (failInfo != 0)
+            {
+                v.Add(new FailInfo(failInfo));
+            }
+
+            return new PkiStatusInfo(new DerSequence(v));
+        }
+
+        public TimeStampResponse Generate(
+            TimeStampRequest request,
+            BigInteger serialNumber,
+            DateTime genTime)
+        {
+            return Generate(request, serialNumber, new DateTimeObject(genTime));
+        }
+
+        /**
+         * Return an appropriate TimeStampResponse.
+         * <p>
+         * If genTime is null a timeNotAvailable error response will be returned.
+         *
+         * @param request the request this response is for.
+         * @param serialNumber serial number for the response token.
+         * @param genTime generation time for the response token.
+         * @param provider provider to use for signature calculation.
+         * @return
+         * @throws NoSuchAlgorithmException
+         * @throws NoSuchProviderException
+         * @throws TSPException
+         * </p>
+         */
+        public TimeStampResponse Generate(
+            TimeStampRequest request,
+            BigInteger serialNumber,
+            DateTimeObject genTime)
+        {
+            TimeStampResp resp;
+
+            try
+            {
+                if (genTime == null)
+                    throw new TspValidationException("The time source is not available.",
+                        PkiFailureInfo.TimeNotAvailable);
+
+                request.Validate(acceptedAlgorithms, acceptedPolicies, acceptedExtensions);
+
+                this.status = PkiStatus.Granted;
+                this.AddStatusString("Operation Okay");
+
+                PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
+
+                ContentInfo tstTokenContentInfo;
+                try
+                {
+                    TimeStampToken token = tokenGenerator.Generate(request, serialNumber, genTime.Value);
+                    byte[] encoded = token.ToCmsSignedData().GetEncoded();
+
+                    tstTokenContentInfo = ContentInfo.GetInstance(Asn1Object.FromByteArray(encoded));
+                }
+                catch (IOException e)
+                {
+                    throw new TspException("Timestamp token received cannot be converted to ContentInfo", e);
+                }
+
+                resp = new TimeStampResp(pkiStatusInfo, tstTokenContentInfo);
+            }
+            catch (TspValidationException e)
+            {
+                status = PkiStatus.Rejection;
+
+                this.SetFailInfoField(e.FailureCode);
+                this.AddStatusString(e.Message);
+
+                PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
+
+                resp = new TimeStampResp(pkiStatusInfo, null);
+            }
+
+            try
+            {
+                return new TimeStampResponse(resp);
+            }
+            catch (IOException e)
+            {
+                throw new TspException("created badly formatted response!", e);
+            }
+        }
+
+        class FailInfo
+            : DerBitString
+        {
+            internal FailInfo(
+                int failInfoValue)
+                : base(GetBytes(failInfoValue), GetPadBits(failInfoValue))
+            {
+            }
+        }
+
+        /**
+         * Generate a TimeStampResponse with chosen status and FailInfoField.
+         *
+         * @param status the PKIStatus to set.
+         * @param failInfoField the FailInfoField to set.
+         * @param statusString an optional string describing the failure.
+         * @return a TimeStampResponse with a failInfoField and optional statusString
+         * @throws TSPException in case the response could not be created
+         */
+        public TimeStampResponse GenerateFailResponse(PkiStatus status, int failInfoField, string statusString)
+        {
+            this.status = status;
+
+            this.SetFailInfoField(failInfoField);
+
+            if (statusString != null)
+            {
+                this.AddStatusString(statusString);
+            }
+
+            PkiStatusInfo pkiStatusInfo = GetPkiStatusInfo();
+
+            TimeStampResp resp = new TimeStampResp(pkiStatusInfo, null);
+
+            try
+            {
+                return new TimeStampResponse(resp);
+            }
+            catch (IOException e)
+            {
+                throw new TspException("created badly formatted response!", e);
+            }
+        }
+    }
+}
diff --git a/crypto/src/tsp/TimeStampToken.cs b/crypto/src/tsp/TimeStampToken.cs
new file mode 100644
index 000000000..51a9592dc
--- /dev/null
+++ b/crypto/src/tsp/TimeStampToken.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp
+{
+	public class TimeStampToken
+	{
+		private readonly CmsSignedData		tsToken;
+		private readonly SignerInformation	tsaSignerInfo;
+//		private readonly DateTime			genTime;
+		private readonly TimeStampTokenInfo	tstInfo;
+		private readonly CertID				certID;
+
+		public TimeStampToken(
+			Asn1.Cms.ContentInfo contentInfo)
+			: this(new CmsSignedData(contentInfo))
+		{
+		}
+
+		public TimeStampToken(
+			CmsSignedData signedData)
+		{
+			this.tsToken = signedData;
+
+			if (!this.tsToken.SignedContentType.Equals(PkcsObjectIdentifiers.IdCTTstInfo))
+			{
+				throw new TspValidationException("ContentInfo object not for a time stamp.");
+			}
+
+			ICollection signers = tsToken.GetSignerInfos().GetSigners();
+
+			if (signers.Count != 1)
+			{
+				throw new ArgumentException("Time-stamp token signed by "
+					+ signers.Count
+					+ " signers, but it must contain just the TSA signature.");
+			}
+
+
+			IEnumerator signerEnum = signers.GetEnumerator();
+
+			signerEnum.MoveNext();
+			tsaSignerInfo = (SignerInformation) signerEnum.Current;
+
+			try
+			{
+				CmsProcessable content = tsToken.SignedContent;
+				MemoryStream bOut = new MemoryStream();
+
+				content.Write(bOut);
+
+				this.tstInfo = new TimeStampTokenInfo(
+					TstInfo.GetInstance(
+						Asn1Object.FromByteArray(bOut.ToArray())));
+
+				Asn1.Cms.Attribute attr = tsaSignerInfo.SignedAttributes[
+					PkcsObjectIdentifiers.IdAASigningCertificate];
+
+//				if (attr == null)
+//				{
+//					throw new TspValidationException(
+//						"no signing certificate attribute found, time stamp invalid.");
+//				}
+//
+//				SigningCertificate signCert = SigningCertificate.GetInstance(
+//					attr.AttrValues[0]);
+//
+//				this.certID = EssCertID.GetInstance(signCert.GetCerts()[0]);
+
+				if (attr != null)
+				{
+					SigningCertificate signCert = SigningCertificate.GetInstance(attr.AttrValues[0]);
+
+					this.certID = new CertID(EssCertID.GetInstance(signCert.GetCerts()[0]));
+				}
+				else
+				{
+					attr = tsaSignerInfo.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
+
+					if (attr == null)
+						throw new TspValidationException("no signing certificate attribute found, time stamp invalid.");
+
+					SigningCertificateV2 signCertV2 = SigningCertificateV2.GetInstance(attr.AttrValues[0]);
+
+					this.certID = new CertID(EssCertIDv2.GetInstance(signCertV2.GetCerts()[0]));
+				}
+			}
+			catch (CmsException e)
+			{
+				throw new TspException(e.Message, e.InnerException);
+			}
+		}
+
+		public TimeStampTokenInfo TimeStampInfo
+		{
+			get { return tstInfo; }
+		}
+
+		public SignerID SignerID
+		{
+			get { return tsaSignerInfo.SignerID; }
+		}
+
+		public Asn1.Cms.AttributeTable SignedAttributes
+		{
+			get { return tsaSignerInfo.SignedAttributes; }
+		}
+
+		public Asn1.Cms.AttributeTable UnsignedAttributes
+		{
+			get { return tsaSignerInfo.UnsignedAttributes; }
+		}
+
+		public IX509Store GetCertificates(
+			string type)
+		{
+			return tsToken.GetCertificates(type);
+		}
+
+		public IX509Store GetCrls(
+			string type)
+		{
+			return tsToken.GetCrls(type);
+		}
+
+	    public IX509Store GetAttributeCertificates(
+			string type)
+	    {
+	        return tsToken.GetAttributeCertificates(type);
+	    }
+
+		/**
+		 * Validate the time stamp token.
+		 * <p>
+		 * To be valid the token must be signed by the passed in certificate and
+		 * the certificate must be the one referred to by the SigningCertificate
+		 * attribute included in the hashed attributes of the token. The
+		 * certificate must also have the ExtendedKeyUsageExtension with only
+		 * KeyPurposeID.IdKPTimeStamping and have been valid at the time the
+		 * timestamp was created.
+		 * </p>
+		 * <p>
+		 * A successful call to validate means all the above are true.
+		 * </p>
+		 */
+		public void Validate(
+			X509Certificate cert)
+		{
+			try
+			{
+				byte[] hash = DigestUtilities.CalculateDigest(
+					certID.GetHashAlgorithmName(), cert.GetEncoded());
+
+				if (!Arrays.ConstantTimeAreEqual(certID.GetCertHash(), hash))
+				{
+					throw new TspValidationException("certificate hash does not match certID hash.");
+				}
+
+				if (certID.IssuerSerial != null)
+				{
+					if (!certID.IssuerSerial.Serial.Value.Equals(cert.SerialNumber))
+					{
+						throw new TspValidationException("certificate serial number does not match certID for signature.");
+					}
+
+					GeneralName[] names = certID.IssuerSerial.Issuer.GetNames();
+					X509Name principal = PrincipalUtilities.GetIssuerX509Principal(cert);
+					bool found = false;
+
+					for (int i = 0; i != names.Length; i++)
+					{
+						if (names[i].TagNo == 4
+							&& X509Name.GetInstance(names[i].Name).Equivalent(principal))
+						{
+							found = true;
+							break;
+						}
+					}
+
+					if (!found)
+					{
+						throw new TspValidationException("certificate name does not match certID for signature. ");
+					}
+				}
+
+				TspUtil.ValidateCertificate(cert);
+
+				cert.CheckValidity(tstInfo.GenTime);
+
+				if (!tsaSignerInfo.Verify(cert))
+				{
+					throw new TspValidationException("signature not created by certificate.");
+				}
+			}
+			catch (CmsException e)
+			{
+				if (e.InnerException != null)
+				{
+					throw new TspException(e.Message, e.InnerException);
+				}
+
+				throw new TspException("CMS exception: " + e, e);
+			}
+			catch (CertificateEncodingException e)
+			{
+				throw new TspException("problem processing certificate: " + e, e);
+			}
+			catch (SecurityUtilityException e)
+			{
+				throw new TspException("cannot find algorithm: " + e.Message, e);
+			}
+		}
+
+		/**
+		 * Return the underlying CmsSignedData object.
+		 *
+		 * @return the underlying CMS structure.
+		 */
+		public CmsSignedData ToCmsSignedData()
+		{
+			return tsToken;
+		}
+
+		/**
+		 * Return a ASN.1 encoded byte stream representing the encoded object.
+		 *
+		 * @throws IOException if encoding fails.
+		 */
+		public byte[] GetEncoded()
+		{
+			return tsToken.GetEncoded();
+		}
+
+
+		// perhaps this should be done using an interface on the ASN.1 classes...
+		private class CertID
+		{
+			private EssCertID certID;
+			private EssCertIDv2 certIDv2;
+
+			internal CertID(EssCertID certID)
+			{
+				this.certID = certID;
+				this.certIDv2 = null;
+			}
+
+			internal CertID(EssCertIDv2 certID)
+			{
+				this.certIDv2 = certID;
+				this.certID = null;
+			}
+
+			public string GetHashAlgorithmName()
+			{
+				if (certID != null)
+					return "SHA-1";
+
+				if (NistObjectIdentifiers.IdSha256.Equals(certIDv2.HashAlgorithm.ObjectID))
+					return "SHA-256";
+
+				return certIDv2.HashAlgorithm.ObjectID.Id;
+			}
+
+			public AlgorithmIdentifier GetHashAlgorithm()
+			{
+				return (certID != null)
+					?	new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1)
+					:	certIDv2.HashAlgorithm;
+			}
+
+			public byte[] GetCertHash()
+			{
+				return certID != null
+					?	certID.GetCertHash()
+					:	certIDv2.GetCertHash();
+			}
+
+			public IssuerSerial IssuerSerial
+			{
+				get
+				{
+					return certID != null
+						?	certID.IssuerSerial
+						:	certIDv2.IssuerSerial;
+				}
+			}
+		}
+	}
+}
diff --git a/crypto/src/tsp/TimeStampTokenGenerator.cs b/crypto/src/tsp/TimeStampTokenGenerator.cs
new file mode 100644
index 000000000..07eddd4b9
--- /dev/null
+++ b/crypto/src/tsp/TimeStampTokenGenerator.cs
@@ -0,0 +1,245 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp
+{
+	public class TimeStampTokenGenerator
+	{
+		private int accuracySeconds = -1;
+		private int accuracyMillis = -1;
+		private int accuracyMicros = -1;
+		private bool ordering = false;
+		private GeneralName tsa = null;
+		private string tsaPolicyOID;
+
+		private AsymmetricKeyParameter	key;
+		private X509Certificate			cert;
+		private string					digestOID;
+		private Asn1.Cms.AttributeTable	signedAttr;
+		private Asn1.Cms.AttributeTable	unsignedAttr;
+		private IX509Store				x509Certs;
+		private IX509Store				x509Crls;
+
+		/**
+		 * basic creation - only the default attributes will be included here.
+		 */
+		public TimeStampTokenGenerator(
+			AsymmetricKeyParameter	key,
+			X509Certificate			cert,
+			string					digestOID,
+			string					tsaPolicyOID)
+			: this(key, cert, digestOID, tsaPolicyOID, null, null)
+		{
+		}
+
+		/**
+		 * create with a signer with extra signed/unsigned attributes.
+		 */
+		public TimeStampTokenGenerator(
+			AsymmetricKeyParameter	key,
+			X509Certificate			cert,
+			string					digestOID,
+			string					tsaPolicyOID,
+			Asn1.Cms.AttributeTable	signedAttr,
+			Asn1.Cms.AttributeTable	unsignedAttr)
+		{
+			this.key = key;
+			this.cert = cert;
+			this.digestOID = digestOID;
+			this.tsaPolicyOID = tsaPolicyOID;
+			this.unsignedAttr = unsignedAttr;
+
+			TspUtil.ValidateCertificate(cert);
+
+			//
+			// Add the ESSCertID attribute
+			//
+			IDictionary signedAttrs;
+			if (signedAttr != null)
+			{
+				signedAttrs = signedAttr.ToDictionary();
+			}
+			else
+			{
+				signedAttrs = Platform.CreateHashtable();
+			}
+
+			try
+			{
+				byte[] hash = DigestUtilities.CalculateDigest("SHA-1", cert.GetEncoded());
+
+				EssCertID essCertid = new EssCertID(hash);
+
+				Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
+					PkcsObjectIdentifiers.IdAASigningCertificate,
+					new DerSet(new SigningCertificate(essCertid)));
+
+				signedAttrs[attr.AttrType] = attr;
+			}
+			catch (CertificateEncodingException e)
+			{
+				throw new TspException("Exception processing certificate.", e);
+			}
+			catch (SecurityUtilityException e)
+			{
+				throw new TspException("Can't find a SHA-1 implementation.", e);
+			}
+
+			this.signedAttr = new Asn1.Cms.AttributeTable(signedAttrs);
+		}
+
+		public void SetCertificates(
+			IX509Store certificates)
+		{
+			this.x509Certs = certificates;
+		}
+
+		public void SetCrls(
+			IX509Store crls)
+		{
+			this.x509Crls = crls;
+		}
+
+		public void SetAccuracySeconds(
+			int accuracySeconds)
+		{
+			this.accuracySeconds = accuracySeconds;
+		}
+
+		public void SetAccuracyMillis(
+			int accuracyMillis)
+		{
+			this.accuracyMillis = accuracyMillis;
+		}
+
+		public void SetAccuracyMicros(
+			int accuracyMicros)
+		{
+			this.accuracyMicros = accuracyMicros;
+		}
+
+		public void SetOrdering(
+			bool ordering)
+		{
+			this.ordering = ordering;
+		}
+
+		public void SetTsa(
+			GeneralName tsa)
+		{
+			this.tsa = tsa;
+		}
+
+		//------------------------------------------------------------------------------
+
+		public TimeStampToken Generate(
+			TimeStampRequest	request,
+			BigInteger			serialNumber,
+			DateTime			genTime)
+		{
+			DerObjectIdentifier digestAlgOID = new DerObjectIdentifier(request.MessageImprintAlgOid);
+
+			AlgorithmIdentifier algID = new AlgorithmIdentifier(digestAlgOID, DerNull.Instance);
+			MessageImprint messageImprint = new MessageImprint(algID, request.GetMessageImprintDigest());
+
+			Accuracy accuracy = null;
+			if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0)
+			{
+				DerInteger seconds = null;
+				if (accuracySeconds > 0)
+				{
+					seconds = new DerInteger(accuracySeconds);
+				}
+
+				DerInteger millis = null;
+				if (accuracyMillis > 0)
+				{
+					millis = new DerInteger(accuracyMillis);
+				}
+
+				DerInteger micros = null;
+				if (accuracyMicros > 0)
+				{
+					micros = new DerInteger(accuracyMicros);
+				}
+
+				accuracy = new Accuracy(seconds, millis, micros);
+			}
+
+			DerBoolean derOrdering = null;
+			if (ordering)
+			{
+				derOrdering = DerBoolean.GetInstance(ordering);
+			}
+
+			DerInteger nonce = null;
+			if (request.Nonce != null)
+			{
+				nonce = new DerInteger(request.Nonce);
+			}
+
+			DerObjectIdentifier tsaPolicy = new DerObjectIdentifier(tsaPolicyOID);
+			if (request.ReqPolicy != null)
+			{
+				tsaPolicy = new DerObjectIdentifier(request.ReqPolicy);
+			}
+
+			TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint,
+				new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy,
+				derOrdering, nonce, tsa, request.Extensions);
+
+			try
+			{
+				CmsSignedDataGenerator signedDataGenerator = new CmsSignedDataGenerator();
+
+				byte[] derEncodedTstInfo = tstInfo.GetDerEncoded();
+
+				if (request.CertReq)
+				{
+					signedDataGenerator.AddCertificates(x509Certs);
+				}
+
+				signedDataGenerator.AddCrls(x509Crls);
+				signedDataGenerator.AddSigner(key, cert, digestOID, signedAttr, unsignedAttr);
+
+				CmsSignedData signedData = signedDataGenerator.Generate(
+					PkcsObjectIdentifiers.IdCTTstInfo.Id,
+					new CmsProcessableByteArray(derEncodedTstInfo),
+					true);
+
+				return new TimeStampToken(signedData);
+			}
+			catch (CmsException cmsEx)
+			{
+				throw new TspException("Error generating time-stamp token", cmsEx);
+			}
+			catch (IOException e)
+			{
+				throw new TspException("Exception encoding info", e);
+			}
+			catch (X509StoreException e)
+			{
+				throw new TspException("Exception handling CertStore", e);
+			}
+//			catch (InvalidAlgorithmParameterException e)
+//			{
+//				throw new TspException("Exception handling CertStore CRLs", e);
+//			}
+		}
+	}
+}
diff --git a/crypto/src/tsp/TimeStampTokenInfo.cs b/crypto/src/tsp/TimeStampTokenInfo.cs
new file mode 100644
index 000000000..5027a87c4
--- /dev/null
+++ b/crypto/src/tsp/TimeStampTokenInfo.cs
@@ -0,0 +1,107 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Tsp
+{
+	public class TimeStampTokenInfo
+	{
+		private TstInfo		tstInfo;
+		private DateTime	genTime;
+
+		public TimeStampTokenInfo(
+			TstInfo tstInfo)
+		{
+			this.tstInfo = tstInfo;
+
+			try
+			{
+				this.genTime = tstInfo.GenTime.ToDateTime();
+			}
+			catch (Exception e)
+			{
+				throw new TspException("unable to parse genTime field: " + e.Message);
+			}
+		}
+
+		public bool IsOrdered
+		{
+			get { return tstInfo.Ordering.IsTrue; }
+		}
+
+		public Accuracy Accuracy
+		{
+			get { return tstInfo.Accuracy; }
+		}
+
+		public DateTime GenTime
+		{
+			get { return genTime; }
+		}
+
+		public GenTimeAccuracy GenTimeAccuracy
+		{
+			get
+			{
+				return this.Accuracy == null
+					?	null
+					:	new GenTimeAccuracy(this.Accuracy);
+			}
+		}
+
+		public string Policy
+		{
+			get { return tstInfo.Policy.Id; }
+		}
+
+		public BigInteger SerialNumber
+		{
+			get { return tstInfo.SerialNumber.Value; }
+		}
+
+		public GeneralName Tsa
+		{
+			get { return tstInfo.Tsa; }
+		}
+
+		/**
+		 * @return the nonce value, null if there isn't one.
+		 */
+		public BigInteger Nonce
+		{
+			get
+			{
+				return tstInfo.Nonce == null
+					?	null
+					:	tstInfo.Nonce.Value;
+			}
+		}
+
+		public AlgorithmIdentifier HashAlgorithm
+		{
+			get { return tstInfo.MessageImprint.HashAlgorithm; }
+		}
+
+		public string MessageImprintAlgOid
+		{
+			get { return tstInfo.MessageImprint.HashAlgorithm.ObjectID.Id; }
+		}
+
+		public byte[] GetMessageImprintDigest()
+		{
+			return tstInfo.MessageImprint.GetHashedMessage();
+		}
+
+		public byte[] GetEncoded()
+		{
+			return tstInfo.GetEncoded();
+		}
+
+		public TstInfo TstInfo
+		{
+			get { return tstInfo; }
+		}
+	}
+}
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 7fa05ebee..27fd18d6d 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -1,28 +1,25 @@
 using System;
 using System.Text;
 
+using Org.BouncyCastle.Math;
+
 namespace Org.BouncyCastle.Utilities
 {
-
     /// <summary> General array utilities.</summary>
-    public sealed class Arrays
+    public abstract class Arrays
     {
-        private Arrays()
+        public static bool AreEqual(
+            bool[]  a,
+            bool[]  b)
         {
-        }
-
-		public static bool AreEqual(
-			bool[]  a,
-			bool[]  b)
-		{
-			if (a == b)
-				return true;
+            if (a == b)
+                return true;
 
-			if (a == null || b == null)
-				return false;
+            if (a == null || b == null)
+                return false;
 
             return HaveSameContents(a, b);
-		}
+        }
 
         public static bool AreEqual(
             char[] a,
@@ -44,61 +41,73 @@ namespace Org.BouncyCastle.Utilities
         /// <param name="b">Right side.</param>
         /// <returns>True if equal.</returns>
         public static bool AreEqual(
-			byte[]	a,
-			byte[]	b)
-        {
-			if (a == b)
-				return true;
-
-			if (a == null || b == null)
-				return false;
-
-			return HaveSameContents(a, b);
-		}
-
-		[Obsolete("Use 'AreEqual' method instead")]
-		public static bool AreSame(
-			byte[]	a,
-			byte[]	b)
-		{
-			return AreEqual(a, b);
-		}
-
-		/// <summary>
-		/// A constant time equals comparison - does not terminate early if
-		/// test will fail.
-		/// </summary>
-		/// <param name="a">first array</param>
-		/// <param name="b">second array</param>
-		/// <returns>true if arrays equal, false otherwise.</returns>
-		public static bool ConstantTimeAreEqual(
-			byte[]	a,
-			byte[]	b)
-		{
-			int i = a.Length;
-			if (i != b.Length)
-				return false;
-			int cmp = 0;
-			while (i != 0)
-			{
-				--i;
-				cmp |= (a[i] ^ b[i]);
-			}
-			return cmp == 0;
-		}
-
-		public static bool AreEqual(
-			int[]	a,
-			int[]	b)
-		{
-			if (a == b)
-				return true;
-
-			if (a == null || b == null)
-				return false;
-
-			return HaveSameContents(a, b);
-		}
+            byte[]	a,
+            byte[]	b)
+        {
+            if (a == b)
+                return true;
+
+            if (a == null || b == null)
+                return false;
+
+            return HaveSameContents(a, b);
+        }
+
+        [Obsolete("Use 'AreEqual' method instead")]
+        public static bool AreSame(
+            byte[]	a,
+            byte[]	b)
+        {
+            return AreEqual(a, b);
+        }
+
+        /// <summary>
+        /// A constant time equals comparison - does not terminate early if
+        /// test will fail.
+        /// </summary>
+        /// <param name="a">first array</param>
+        /// <param name="b">second array</param>
+        /// <returns>true if arrays equal, false otherwise.</returns>
+        public static bool ConstantTimeAreEqual(
+            byte[]	a,
+            byte[]	b)
+        {
+            int i = a.Length;
+            if (i != b.Length)
+                return false;
+            int cmp = 0;
+            while (i != 0)
+            {
+                --i;
+                cmp |= (a[i] ^ b[i]);
+            }
+            return cmp == 0;
+        }
+
+        public static bool AreEqual(
+            int[]	a,
+            int[]	b)
+        {
+            if (a == b)
+                return true;
+
+            if (a == null || b == null)
+                return false;
+
+            return HaveSameContents(a, b);
+        }
+
+        [CLSCompliantAttribute(false)]
+        public static bool AreEqual(uint[] a, uint[] b)
+        {
+            if (a == b)
+                return true;
+
+            if (a == null || b == null)
+                return false;
+
+            return HaveSameContents(a, b);
+        }
 
         private static bool HaveSameContents(
             bool[] a,
@@ -133,94 +142,471 @@ namespace Org.BouncyCastle.Utilities
         }
 
         private static bool HaveSameContents(
-			byte[]	a,
-			byte[]	b)
-		{
-			int i = a.Length;
-			if (i != b.Length)
-				return false;
-			while (i != 0)
-			{
-				--i;
-				if (a[i] != b[i])
-					return false;
-			}
-			return true;
-		}
-
-		private static bool HaveSameContents(
-			int[]	a,
-			int[]	b)
-		{
-			int i = a.Length;
-			if (i != b.Length)
-				return false;
-			while (i != 0)
-			{
-				--i;
-				if (a[i] != b[i])
-					return false;
-			}
-			return true;
-		}
+            byte[]	a,
+            byte[]	b)
+        {
+            int i = a.Length;
+            if (i != b.Length)
+                return false;
+            while (i != 0)
+            {
+                --i;
+                if (a[i] != b[i])
+                    return false;
+            }
+            return true;
+        }
+
+        private static bool HaveSameContents(
+            int[]	a,
+            int[]	b)
+        {
+            int i = a.Length;
+            if (i != b.Length)
+                return false;
+            while (i != 0)
+            {
+                --i;
+                if (a[i] != b[i])
+                    return false;
+            }
+            return true;
+        }
+
+        private static bool HaveSameContents(uint[] a, uint[] b)
+        {
+            int i = a.Length;
+            if (i != b.Length)
+                return false;
+            while (i != 0)
+            {
+                --i;
+                if (a[i] != b[i])
+                    return false;
+            }
+            return true;
+        }
 
         public static string ToString(
-			object[] a)
-		{
-			StringBuilder sb = new StringBuilder('[');
-			if (a.Length > 0)
-			{
-				sb.Append(a[0]);
-				for (int index = 1; index < a.Length; ++index)
-				{
-					sb.Append(", ").Append(a[index]);
-				}
-			}
-			sb.Append(']');
-			return sb.ToString();
-		}
-
-		public static int GetHashCode(
-			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 byte[] Clone(
-			byte[] data)
-		{
-			return data == null ? null : (byte[]) data.Clone();
-		}
-
-		public static int[] Clone(
-			int[] data)
-		{
-			return data == null ? null : (int[]) data.Clone();
-		}
-
-		public static void Fill(
-			byte[]	buf,
-			byte	b)
-		{
-			int i = buf.Length;
-			while (i > 0)
-			{
-				buf[--i] = b;
-			}
-		}
-	}
+            object[] a)
+        {
+            StringBuilder sb = new StringBuilder('[');
+            if (a.Length > 0)
+            {
+                sb.Append(a[0]);
+                for (int index = 1; index < a.Length; ++index)
+                {
+                    sb.Append(", ").Append(a[index]);
+                }
+            }
+            sb.Append(']');
+            return sb.ToString();
+        }
+
+        public static int GetHashCode(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 GetHashCode(byte[] data, int off, int len)
+        {
+            if (data == null)
+            {
+                return 0;
+            }
+
+            int i = len;
+            int hc = i + 1;
+
+            while (--i >= 0)
+            {
+                hc *= 257;
+                hc ^= data[off + i];
+            }
+
+            return hc;
+        }
+
+        public static int GetHashCode(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 GetHashCode(int[] data, int off, int len)
+        {
+            if (data == null)
+                return 0;
+
+            int i = len;
+            int hc = i + 1;
+
+            while (--i >= 0)
+            {
+                hc *= 257;
+                hc ^= data[off + i];
+            }
+
+            return hc;
+        }
+
+        [CLSCompliantAttribute(false)]
+        public static int GetHashCode(uint[] data)
+        {
+            if (data == null)
+                return 0;
+
+            int i = data.Length;
+            int hc = i + 1;
+
+            while (--i >= 0)
+            {
+                hc *= 257;
+                hc ^= (int)data[i];
+            }
+
+            return hc;
+        }
+
+        [CLSCompliantAttribute(false)]
+        public static int GetHashCode(uint[] data, int off, int len)
+        {
+            if (data == null)
+                return 0;
+
+            int i = len;
+            int hc = i + 1;
+
+            while (--i >= 0)
+            {
+                hc *= 257;
+                hc ^= (int)data[off + i];
+            }
+
+            return hc;
+        }
+
+        public static byte[] Clone(
+            byte[] data)
+        {
+            return data == null ? null : (byte[])data.Clone();
+        }
+
+        public static byte[] Clone(
+            byte[] data, 
+            byte[] existing)
+        {
+            if (data == null)
+            {
+                return null;
+            }
+            if ((existing == null) || (existing.Length != data.Length))
+            {
+                return Clone(data);
+            }
+            Array.Copy(data, 0, existing, 0, existing.Length);
+            return existing;
+        }
+
+        public static int[] Clone(
+            int[] data)
+        {
+            return data == null ? null : (int[])data.Clone();
+        }
+
+        public static long[] Clone(long[] data)
+        {
+            return data == null ? null : (long[])data.Clone();
+        }
+
+        [CLSCompliantAttribute(false)]
+        public static ulong[] Clone(
+            ulong[] data)
+        {
+            return data == null ? null : (ulong[]) data.Clone();
+        }
+
+        [CLSCompliantAttribute(false)]
+        public static ulong[] Clone(
+            ulong[] data, 
+            ulong[] existing)
+        {
+            if (data == null)
+            {
+                return null;
+            }
+            if ((existing == null) || (existing.Length != data.Length))
+            {
+                return Clone(data);
+            }
+            Array.Copy(data, 0, existing, 0, existing.Length);
+            return existing;
+        }
+
+        public static bool Contains(byte[] a, byte n)
+        {
+            for (int i = 0; i < a.Length; ++i)
+            {
+                if (a[i] == n)
+                    return true;
+            }
+            return false;
+        }
+
+        public static bool Contains(short[] a, short n)
+        {
+            for (int i = 0; i < a.Length; ++i)
+            {
+                if (a[i] == n)
+                    return true;
+            }
+            return false;
+        }
+
+        public static bool Contains(int[] a, int n)
+        {
+            for (int i = 0; i < a.Length; ++i)
+            {
+                if (a[i] == n)
+                    return true;
+            }
+            return false;
+        }
+
+        public static void Fill(
+            byte[]	buf,
+            byte	b)
+        {
+            int i = buf.Length;
+            while (i > 0)
+            {
+                buf[--i] = b;
+            }
+        }
+
+        public static byte[] CopyOf(byte[] data, int newLength)
+        {
+            byte[] tmp = new byte[newLength];
+            Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+            return tmp;
+        }
+
+        public static char[] CopyOf(char[] data, int newLength)
+        {
+            char[] tmp = new char[newLength];
+            Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+            return tmp;
+        }
+
+        public static int[] CopyOf(int[] data, int newLength)
+        {
+            int[] tmp = new int[newLength];
+            Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+            return tmp;
+        }
+
+        public static long[] CopyOf(long[] data, int newLength)
+        {
+            long[] tmp = new long[newLength];
+            Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+            return tmp;
+        }
+
+        public static BigInteger[] CopyOf(BigInteger[] data, int newLength)
+        {
+            BigInteger[] tmp = new BigInteger[newLength];
+            Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length));
+            return tmp;
+        }
+
+        /**
+         * Make a copy of a range of bytes from the passed in data array. The range can
+         * extend beyond the end of the input array, in which case the return array will
+         * be padded with zeroes.
+         *
+         * @param data the array from which the data is to be copied.
+         * @param from the start index at which the copying should take place.
+         * @param to the final index of the range (exclusive).
+         *
+         * @return a new byte array containing the range given.
+         */
+        public static byte[] CopyOfRange(byte[] data, int from, int to)
+        {
+            int newLength = GetLength(from, to);
+            byte[] tmp = new byte[newLength];
+            Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+            return tmp;
+        }
+
+        public static int[] CopyOfRange(int[] data, int from, int to)
+        {
+            int newLength = GetLength(from, to);
+            int[] tmp = new int[newLength];
+            Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+            return tmp;
+        }
+
+        public static long[] CopyOfRange(long[] data, int from, int to)
+        {
+            int newLength = GetLength(from, to);
+            long[] tmp = new long[newLength];
+            Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+            return tmp;
+        }
+
+        public static BigInteger[] CopyOfRange(BigInteger[] data, int from, int to)
+        {
+            int newLength = GetLength(from, to);
+            BigInteger[] tmp = new BigInteger[newLength];
+            Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from));
+            return tmp;
+        }
+
+        private static int GetLength(int from, int to)
+        {
+            int newLength = to - from;
+            if (newLength < 0)
+                throw new ArgumentException(from + " > " + to);
+            return newLength;
+        }
+
+        public static byte[] Append(byte[] a, byte b)
+        {
+            if (a == null)
+                return new byte[] { b };
+
+            int length = a.Length;
+            byte[] result = new byte[length + 1];
+            Array.Copy(a, 0, result, 0, length);
+            result[length] = b;
+            return result;
+        }
+
+        public static short[] Append(short[] a, short b)
+        {
+            if (a == null)
+                return new short[] { b };
+
+            int length = a.Length;
+            short[] result = new short[length + 1];
+            Array.Copy(a, 0, result, 0, length);
+            result[length] = b;
+            return result;
+        }
+
+        public static int[] Append(int[] a, int b)
+        {
+            if (a == null)
+                return new int[] { b };
+
+            int length = a.Length;
+            int[] result = new int[length + 1];
+            Array.Copy(a, 0, result, 0, length);
+            result[length] = b;
+            return result;
+        }
+
+        public static byte[] Concatenate(byte[] a, byte[] b)
+        {
+            if (a == null)
+                return Clone(b);
+            if (b == null)
+                return Clone(a);
+
+            byte[] rv = new byte[a.Length + b.Length];
+            Array.Copy(a, 0, rv, 0, a.Length);
+            Array.Copy(b, 0, rv, a.Length, b.Length);
+            return rv;
+        }
+
+        public static int[] Concatenate(int[] a, int[] b)
+        {
+            if (a == null)
+                return Clone(b);
+            if (b == null)
+                return Clone(a);
+
+            int[] rv = new int[a.Length + b.Length];
+            Array.Copy(a, 0, rv, 0, a.Length);
+            Array.Copy(b, 0, rv, a.Length, b.Length);
+            return rv;
+        }
+
+        public static byte[] Prepend(byte[] a, byte b)
+        {
+            if (a == null)
+                return new byte[] { b };
+
+            int length = a.Length;
+            byte[] result = new byte[length + 1];
+            Array.Copy(a, 0, result, 1, length);
+            result[0] = b;
+            return result;
+        }
+
+        public static short[] Prepend(short[] a, short b)
+        {
+            if (a == null)
+                return new short[] { b };
+
+            int length = a.Length;
+            short[] result = new short[length + 1];
+            Array.Copy(a, 0, result, 1, length);
+            result[0] = b;
+            return result;
+        }
+
+        public static int[] Prepend(int[] a, int b)
+        {
+            if (a == null)
+                return new int[] { b };
+
+            int length = a.Length;
+            int[] result = new int[length + 1];
+            Array.Copy(a, 0, result, 1, length);
+            result[0] = b;
+            return result;
+        }
+
+        public static byte[] Reverse(byte[] a)
+        {
+            if (a == null)
+                return null;
+
+            int p1 = 0, p2 = a.Length;
+            byte[] result = new byte[p2];
+
+            while (--p2 >= 0)
+            {
+                result[p2] = a[p1++];
+            }
+
+            return result;
+        }
+    }
 }
diff --git a/crypto/src/util/BigIntegers.cs b/crypto/src/util/BigIntegers.cs
index df82e1f22..f2d0425cc 100644
--- a/crypto/src/util/BigIntegers.cs
+++ b/crypto/src/util/BigIntegers.cs
@@ -5,68 +5,86 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Utilities
 {
-	/**
-	 * BigInteger utilities.
-	 */
-	public sealed class BigIntegers
-	{
-		private const int MaxIterations = 1000;
+    /**
+     * BigInteger utilities.
+     */
+    public abstract class BigIntegers
+    {
+        private const int MaxIterations = 1000;
 
-		private BigIntegers()
-		{
-		}
+        /**
+        * 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 n)
+        {
+            return n.ToByteArrayUnsigned();
+        }
 
-		/**
-		* 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 n)
-		{
-			return n.ToByteArrayUnsigned();
-		}
+        /**
+         * Return the passed in value as an unsigned byte array of specified length, zero-extended as necessary.
+         *
+         * @param length desired length of result array.
+         * @param n value to be converted.
+         * @return a byte array of specified length, with leading zeroes as necessary given the size of n.
+         */
+        public static byte[] AsUnsignedByteArray(int length, BigInteger n)
+        {
+            byte[] bytes = n.ToByteArrayUnsigned();
 
-		/**
-		* 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,
-			// TODO Should have been just Random class
-			SecureRandom	random)
-		{
-			int cmp = min.CompareTo(max);
-			if (cmp >= 0)
-			{
-				if (cmp > 0)
-					throw new ArgumentException("'min' may not be greater than 'max'");
+            if (bytes.Length > length)
+                throw new ArgumentException("standard length exceeded", "n");
 
-				return min;
-			}
+            if (bytes.Length == length)
+                return bytes;
 
-			if (min.BitLength > max.BitLength / 2)
-			{
-				return CreateRandomInRange(BigInteger.Zero, max.Subtract(min), random).Add(min);
-			}
+            byte[] tmp = new byte[length];
+            Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length);
+            return tmp;
+        }
 
-			for (int i = 0; i < MaxIterations; ++i)
-			{
-				BigInteger x = new BigInteger(max.BitLength, random);
-				if (x.CompareTo(min) >= 0 && x.CompareTo(max) <= 0)
-				{
-					return x;
-				}
-			}
+        /**
+        * 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,
+            // TODO Should have been just Random class
+            SecureRandom	random)
+        {
+            int cmp = min.CompareTo(max);
+            if (cmp >= 0)
+            {
+                if (cmp > 0)
+                    throw new ArgumentException("'min' may not be greater than 'max'");
 
-			// fall back to a faster (restricted) method
-			return new BigInteger(max.Subtract(min).BitLength - 1, random).Add(min);
-		}
-	}
+                return min;
+            }
+
+            if (min.BitLength > max.BitLength / 2)
+            {
+                return CreateRandomInRange(BigInteger.Zero, max.Subtract(min), random).Add(min);
+            }
+
+            for (int i = 0; i < MaxIterations; ++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/crypto/src/util/Enums.cs b/crypto/src/util/Enums.cs
index abab5266b..8bd9c4053 100644
--- a/crypto/src/util/Enums.cs
+++ b/crypto/src/util/Enums.cs
@@ -1,7 +1,7 @@
 using System;
 using System.Text;
 
-#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
 using System.Collections;
 using System.Reflection;
 #endif
@@ -10,63 +10,60 @@ using Org.BouncyCastle.Utilities.Date;
 
 namespace Org.BouncyCastle.Utilities
 {
-    internal sealed class Enums
+    internal abstract class Enums
     {
-        private Enums()
+        internal static Enum GetEnumValue(System.Type enumType, string s)
         {
-        }
-
-		internal static Enum GetEnumValue(System.Type enumType, string s)
-		{
-			if (!enumType.IsEnum)
-				throw new ArgumentException("Not an enumeration type", "enumType");
+            if (!enumType.IsEnum)
+                throw new ArgumentException("Not an enumeration type", "enumType");
 
-			// We only want to parse single named constants
-			if (s.Length > 0 && char.IsLetter(s[0]) && s.IndexOf(',') < 0)
-			{
-				s = s.Replace('-', '_');
+            // We only want to parse single named constants
+            if (s.Length > 0 && char.IsLetter(s[0]) && s.IndexOf(',') < 0)
+            {
+                s = s.Replace('-', '_');
+                s = s.Replace('/', '_');
 
 #if NETCF_1_0
-				FieldInfo field = enumType.GetField(s, BindingFlags.Static | BindingFlags.Public);
-				if (field != null)
-				{
-					return (Enum)field.GetValue(null);
-				}
+                FieldInfo field = enumType.GetField(s, BindingFlags.Static | BindingFlags.Public);
+                if (field != null)
+                {
+                    return (Enum)field.GetValue(null);
+                }
 #else
-				return (Enum)Enum.Parse(enumType, s, false);
+                return (Enum)Enum.Parse(enumType, s, false);
 #endif		
-			}
+            }
 
-			throw new ArgumentException();
-		}
+            throw new ArgumentException();
+        }
 
-		internal static Array GetEnumValues(System.Type enumType)
-		{
-			if (!enumType.IsEnum)
-				throw new ArgumentException("Not an enumeration type", "enumType");
+        internal static Array GetEnumValues(System.Type enumType)
+        {
+            if (!enumType.IsEnum)
+                throw new ArgumentException("Not an enumeration type", "enumType");
 
-#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
             IList result = Platform.CreateArrayList();
-			FieldInfo[] fields = enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
-			foreach (FieldInfo field in fields)
-			{
+            FieldInfo[] fields = enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
+            foreach (FieldInfo field in fields)
+            {
                 // Note: Argument to GetValue() ignored since the fields are static,
                 //     but Silverlight for Windows Phone throws exception if we pass null
-				result.Add(field.GetValue(enumType));
-			}
+                result.Add(field.GetValue(enumType));
+            }
             object[] arr = new object[result.Count];
             result.CopyTo(arr, 0);
             return arr;
 #else
-			return Enum.GetValues(enumType);
+            return Enum.GetValues(enumType);
 #endif
-		}
+        }
 
-		internal static Enum GetArbitraryValue(System.Type enumType)
-		{
-			Array values = GetEnumValues(enumType);
-			int pos = (int)(DateTimeUtilities.CurrentUnixMs() & int.MaxValue) % values.Length;
-			return (Enum)values.GetValue(pos);
-		}
-	}
+        internal static Enum GetArbitraryValue(System.Type enumType)
+        {
+            Array values = GetEnumValues(enumType);
+            int pos = (int)(DateTimeUtilities.CurrentUnixMs() & int.MaxValue) % values.Length;
+            return (Enum)values.GetValue(pos);
+        }
+    }
 }
diff --git a/crypto/src/util/IMemoable.cs b/crypto/src/util/IMemoable.cs
new file mode 100644
index 000000000..cc8a2e55b
--- /dev/null
+++ b/crypto/src/util/IMemoable.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+	public interface IMemoable
+	{
+		/// <summary>
+		/// Produce a copy of this object with its configuration and in its current state.
+		/// </summary>
+		/// <remarks>
+		/// The returned object may be used simply to store the state, or may be used as a similar object
+		/// starting from the copied state.
+		/// </remarks>
+		IMemoable Copy();
+
+		/// <summary>
+		/// Restore a copied object state into this object.
+		/// </summary>
+		/// <remarks>
+		/// Implementations of this method <em>should</em> try to avoid or minimise memory allocation to perform the reset.
+		/// </remarks>
+		/// <param name="other">an object originally {@link #copy() copied} from an object of the same type as this instance.</param>
+		/// <exception cref="InvalidCastException">if the provided object is not of the correct type.</exception>
+		/// <exception cref="MemoableResetException">if the <b>other</b> parameter is in some other way invalid.</exception>
+		void Reset(IMemoable other);
+	}
+
+}
+
diff --git a/crypto/src/util/Integers.cs b/crypto/src/util/Integers.cs
new file mode 100644
index 000000000..ccbf872c4
--- /dev/null
+++ b/crypto/src/util/Integers.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+    public abstract class Integers
+    {
+        public static int RotateLeft(int i, int distance)
+        {
+            return (i << distance) ^ (int)((uint)i >> -distance);
+        }
+
+        public static int RotateRight(int i, int distance)
+        {
+            return (int)((uint)i >> distance) ^ (i << -distance);
+        }
+    }
+}
diff --git a/crypto/src/util/MemoableResetException.cs b/crypto/src/util/MemoableResetException.cs
new file mode 100644
index 000000000..99554f6c2
--- /dev/null
+++ b/crypto/src/util/MemoableResetException.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+    /**
+     * Exception to be thrown on a failure to reset an object implementing Memoable.
+     * <p>
+     * The exception extends InvalidCastException to enable users to have a single handling case,
+     * only introducing specific handling of this one if required.
+     * </p>
+     */
+    public class MemoableResetException
+        : InvalidCastException
+    {
+        /**
+         * Basic Constructor.
+         *
+         * @param msg message to be associated with this exception.
+         */
+        public MemoableResetException(string msg)
+            : base(msg)
+        {
+        }
+    }
+
+}
+
diff --git a/crypto/src/util/Platform.cs b/crypto/src/util/Platform.cs
index 52ace89e5..99d3982ea 100644
--- a/crypto/src/util/Platform.cs
+++ b/crypto/src/util/Platform.cs
@@ -1,8 +1,9 @@
 using System;
+using System.Globalization;
 using System.IO;
 using System.Text;
 
-#if SILVERLIGHT || PORTABLE
+#if SILVERLIGHT
 using System.Collections.Generic;
 #else
 using System.Collections;
@@ -10,22 +11,18 @@ using System.Collections;
 
 namespace Org.BouncyCastle.Utilities
 {
-	internal sealed class Platform
-	{
-		private Platform()
-		{
-		}
-
+    internal abstract class Platform
+    {
 #if NETCF_1_0 || NETCF_2_0
-		private static string GetNewLine()
-		{
-			MemoryStream buf = new MemoryStream();
-			StreamWriter w = new StreamWriter(buf, Encoding.UTF8);
-			w.WriteLine();
-			w.Close();
-			byte[] bs = buf.ToArray();
+        private static string GetNewLine()
+        {
+            MemoryStream buf = new MemoryStream();
+            StreamWriter w = new StreamWriter(buf, Encoding.UTF8);
+            w.WriteLine();
+            w.Close();
+            byte[] bs = buf.ToArray();
             return Encoding.UTF8.GetString(bs, 0, bs.Length);
-		}
+        }
 #else
         private static string GetNewLine()
         {
@@ -35,58 +32,58 @@ namespace Org.BouncyCastle.Utilities
 
         internal static int CompareIgnoreCase(string a, string b)
         {
-#if (SILVERLIGHT || PORTABLE)
-            return String.Compare(a, b, StringComparison.OrdinalIgnoreCase);
+#if SILVERLIGHT
+            return String.Compare(a, b, StringComparison.InvariantCultureIgnoreCase);
 #else
             return String.Compare(a, b, true);
 #endif
         }
 
-#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
-		internal static string GetEnvironmentVariable(
-			string variable)
-		{
-			return null;
-		}
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT
+        internal static string GetEnvironmentVariable(
+            string variable)
+        {
+            return null;
+        }
 #else
-		internal static string GetEnvironmentVariable(
-			string variable)
-		{
-			try
-			{
-				return Environment.GetEnvironmentVariable(variable);
-			}
-			catch (System.Security.SecurityException)
-			{
-				// We don't have the required permission to read this environment variable,
-				// which is fine, just act as if it's not set
-				return null;
-			}
-		}
+        internal static string GetEnvironmentVariable(
+            string variable)
+        {
+            try
+            {
+                return Environment.GetEnvironmentVariable(variable);
+            }
+            catch (System.Security.SecurityException)
+            {
+                // We don't have the required permission to read this environment variable,
+                // which is fine, just act as if it's not set
+                return null;
+            }
+        }
 #endif
 
 #if NETCF_1_0
-		internal static Exception CreateNotImplementedException(
-			string message)
-		{
-			return new Exception("Not implemented: " + message);
-		}
+        internal static Exception CreateNotImplementedException(
+            string message)
+        {
+            return new Exception("Not implemented: " + message);
+        }
 
-		internal static bool Equals(
-			object	a,
-			object	b)
-		{
-			return a == b || (a != null && b != null && a.Equals(b));
-		}
+        internal static bool Equals(
+            object	a,
+            object	b)
+        {
+            return a == b || (a != null && b != null && a.Equals(b));
+        }
 #else
-		internal static Exception CreateNotImplementedException(
-			string message)
-		{
-			return new NotImplementedException(message);
-		}
+        internal static Exception CreateNotImplementedException(
+            string message)
+        {
+            return new NotImplementedException(message);
+        }
 #endif
 
-#if SILVERLIGHT || PORTABLE
+#if SILVERLIGHT
         internal static System.Collections.IList CreateArrayList()
         {
             return new List<object>();
@@ -166,6 +163,16 @@ namespace Org.BouncyCastle.Utilities
         }
 #endif
 
+        internal static string ToLowerInvariant(string s)
+        {
+            return s.ToLower(CultureInfo.InvariantCulture);
+        }
+
+        internal static string ToUpperInvariant(string s)
+        {
+            return s.ToUpper(CultureInfo.InvariantCulture);
+        }
+
         internal static readonly string NewLine = GetNewLine();
-	}
+    }
 }
diff --git a/crypto/src/util/Strings.cs b/crypto/src/util/Strings.cs
index 1d35920c9..a6080f427 100644
--- a/crypto/src/util/Strings.cs
+++ b/crypto/src/util/Strings.cs
@@ -3,33 +3,29 @@ using System.Text;
 
 namespace Org.BouncyCastle.Utilities
 {
-	/// <summary> General string utilities.</summary>
-	public sealed class Strings
-	{
-		private Strings()
-		{
-		}
-
-		internal static bool IsOneOf(string s, params string[] candidates)
-		{
-			foreach (string candidate in candidates)
-			{
-				if (s == candidate)
-					return true;
-			}
-			return false;
-		}
+    /// <summary> General string utilities.</summary>
+    public abstract class Strings
+    {
+        internal static bool IsOneOf(string s, params string[] candidates)
+        {
+            foreach (string candidate in candidates)
+            {
+                if (s == candidate)
+                    return true;
+            }
+            return false;
+        }
 
-		public static string FromByteArray(
-			byte[] bs)
-		{
-			char[] cs = new char[bs.Length];
-			for (int i = 0; i < cs.Length; ++i)
-			{
-				cs[i] = Convert.ToChar(bs[i]);
-			}
-			return new string(cs);
-		}
+        public static string FromByteArray(
+            byte[] bs)
+        {
+            char[] cs = new char[bs.Length];
+            for (int i = 0; i < cs.Length; ++i)
+            {
+                cs[i] = Convert.ToChar(bs[i]);
+            }
+            return new string(cs);
+        }
 
         public static byte[] ToByteArray(
             char[] cs)
@@ -43,20 +39,20 @@ namespace Org.BouncyCastle.Utilities
         }
 
         public static byte[] ToByteArray(
-			string s)
-		{
-			byte[] bs = new byte[s.Length];
-			for (int i = 0; i < bs.Length; ++i)
-			{
-				bs[i] = Convert.ToByte(s[i]);
-			}
-			return bs;
-		}
+            string s)
+        {
+            byte[] bs = new byte[s.Length];
+            for (int i = 0; i < bs.Length; ++i)
+            {
+                bs[i] = Convert.ToByte(s[i]);
+            }
+            return bs;
+        }
 
         public static string FromAsciiByteArray(
             byte[] bytes)
         {
-#if (SILVERLIGHT || PORTABLE)
+#if SILVERLIGHT
             // TODO Check for non-ASCII bytes in input?
             return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
 #else
@@ -67,7 +63,7 @@ namespace Org.BouncyCastle.Utilities
         public static byte[] ToAsciiByteArray(
             char[] cs)
         {
-#if SILVERLIGHT || PORTABLE
+#if SILVERLIGHT
             // TODO Check for non-ASCII characters in input?
             return Encoding.UTF8.GetBytes(cs);
 #else
@@ -78,7 +74,7 @@ namespace Org.BouncyCastle.Utilities
         public static byte[] ToAsciiByteArray(
             string s)
         {
-#if SILVERLIGHT || PORTABLE
+#if SILVERLIGHT
             // TODO Check for non-ASCII characters in input?
             return Encoding.UTF8.GetBytes(s);
 #else
@@ -87,10 +83,10 @@ namespace Org.BouncyCastle.Utilities
         }
 
         public static string FromUtf8ByteArray(
-			byte[] bytes)
-		{
-			return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
-		}
+            byte[] bytes)
+        {
+            return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+        }
 
         public static byte[] ToUtf8ByteArray(
             char[] cs)
@@ -98,10 +94,10 @@ namespace Org.BouncyCastle.Utilities
             return Encoding.UTF8.GetBytes(cs);
         }
 
-		public static byte[] ToUtf8ByteArray(
-			string s)
-		{
-			return Encoding.UTF8.GetBytes(s);
-		}
-	}
+        public static byte[] ToUtf8ByteArray(
+            string s)
+        {
+            return Encoding.UTF8.GetBytes(s);
+        }
+    }
 }
diff --git a/crypto/src/util/Times.cs b/crypto/src/util/Times.cs
new file mode 100644
index 000000000..99a78d21a
--- /dev/null
+++ b/crypto/src/util/Times.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities
+{
+    public sealed class Times
+    {
+        private static long NanosecondsPerTick = 100L;
+
+        public static long NanoTime()
+        {
+            return DateTime.UtcNow.Ticks * NanosecondsPerTick;
+        }
+    }
+}
diff --git a/crypto/src/util/collections/CollectionUtilities.cs b/crypto/src/util/collections/CollectionUtilities.cs
index fd0bdcc7a..18fcb6774 100644
--- a/crypto/src/util/collections/CollectionUtilities.cs
+++ b/crypto/src/util/collections/CollectionUtilities.cs
@@ -4,13 +4,9 @@ using System.Text;
 
 namespace Org.BouncyCastle.Utilities.Collections
 {
-	public sealed class CollectionUtilities
-	{
-		private CollectionUtilities()
-		{
-		}
-
-        public static void AddRange(IList to, ICollection range)
+    public abstract class CollectionUtilities
+    {
+        public static void AddRange(IList to, IEnumerable range)
         {
             foreach (object o in range)
             {
@@ -18,17 +14,15 @@ namespace Org.BouncyCastle.Utilities.Collections
             }
         }
 
-        public static bool CheckElementsAreOfType(
-			IEnumerable e,
-			Type		t)
-		{
-			foreach (object o in e)
-			{
-				if (!t.IsInstanceOfType(o))
-					return false;
-			}
-			return true;
-		}
+        public static bool CheckElementsAreOfType(IEnumerable e, Type t)
+        {
+            foreach (object o in e)
+            {
+                if (!t.IsInstanceOfType(o))
+                    return false;
+            }
+            return true;
+        }
 
         public static IDictionary ReadOnly(IDictionary d)
         {
@@ -45,27 +39,26 @@ namespace Org.BouncyCastle.Utilities.Collections
             return new UnmodifiableSetProxy(s);
         }
 
-        public static string ToString(
-			IEnumerable c)
-		{
-			StringBuilder sb = new StringBuilder("[");
+        public static string ToString(IEnumerable c)
+        {
+            StringBuilder sb = new StringBuilder("[");
 
-			IEnumerator e = c.GetEnumerator();
+            IEnumerator e = c.GetEnumerator();
 
-			if (e.MoveNext())
-			{
-				sb.Append(e.Current.ToString());
+            if (e.MoveNext())
+            {
+                sb.Append(e.Current.ToString());
 
-				while (e.MoveNext())
-				{
-					sb.Append(", ");
-					sb.Append(e.Current.ToString());
-				}
-			}
+                while (e.MoveNext())
+                {
+                    sb.Append(", ");
+                    sb.Append(e.Current.ToString());
+                }
+            }
 
-			sb.Append(']');
+            sb.Append(']');
 
-			return sb.ToString();
-		}
-	}
+            return sb.ToString();
+        }
+    }
 }
diff --git a/crypto/src/util/collections/EmptyEnumerable.cs b/crypto/src/util/collections/EmptyEnumerable.cs
new file mode 100644
index 000000000..a61a0789a
--- /dev/null
+++ b/crypto/src/util/collections/EmptyEnumerable.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public sealed class EmptyEnumerable
+		: IEnumerable
+	{
+		public static readonly IEnumerable Instance = new EmptyEnumerable();
+
+		private EmptyEnumerable()
+		{
+		}
+
+		public IEnumerator GetEnumerator()
+		{
+			return EmptyEnumerator.Instance;
+		}
+	}
+
+	public sealed class EmptyEnumerator
+		: IEnumerator
+	{
+		public static readonly IEnumerator Instance = new EmptyEnumerator();
+
+		private EmptyEnumerator()
+		{
+		}
+
+		public bool MoveNext()
+		{
+			return false;
+		}
+
+		public void Reset()
+		{
+		}
+
+		public object Current
+		{
+			get { throw new InvalidOperationException("No elements"); }
+		}
+	}
+}
diff --git a/crypto/src/util/collections/EnumerableProxy.cs b/crypto/src/util/collections/EnumerableProxy.cs
new file mode 100644
index 000000000..9eec4af21
--- /dev/null
+++ b/crypto/src/util/collections/EnumerableProxy.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public sealed class EnumerableProxy
+		: IEnumerable
+	{
+		private readonly IEnumerable inner;
+
+		public EnumerableProxy(
+			IEnumerable inner)
+		{
+			if (inner == null)
+				throw new ArgumentNullException("inner");
+
+			this.inner = inner;
+		}
+
+		public IEnumerator GetEnumerator()
+		{
+			return inner.GetEnumerator();
+		}
+	}
+}
diff --git a/crypto/src/util/collections/HashSet.cs b/crypto/src/util/collections/HashSet.cs
new file mode 100644
index 000000000..1facb58e3
--- /dev/null
+++ b/crypto/src/util/collections/HashSet.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public class HashSet
+		: ISet
+	{
+		private readonly IDictionary impl = Platform.CreateHashtable();
+
+		public HashSet()
+		{
+		}
+
+		public HashSet(IEnumerable s)
+		{
+			foreach (object o in s)
+			{
+				Add(o);
+			}
+		}
+
+		public virtual void Add(object o)
+		{
+			impl[o] = null;
+		}
+
+		public virtual void AddAll(IEnumerable e)
+		{
+			foreach (object o in e)
+			{
+				Add(o);
+			}
+		}
+
+		public virtual void Clear()
+		{
+			impl.Clear();
+		}
+
+		public virtual bool Contains(object o)
+		{
+			return impl.Contains(o);
+		}
+
+		public virtual void CopyTo(Array array, int index)
+		{
+			impl.Keys.CopyTo(array, index);
+		}
+
+		public virtual int Count
+		{
+			get { return impl.Count; }
+		}
+
+		public virtual IEnumerator GetEnumerator()
+		{
+			return impl.Keys.GetEnumerator();
+		}
+
+		public virtual bool IsEmpty
+		{
+			get { return impl.Count == 0; }
+		}
+
+		public virtual bool IsFixedSize
+		{
+			get { return impl.IsFixedSize; }
+		}
+
+		public virtual bool IsReadOnly
+		{
+			get { return impl.IsReadOnly; }
+		}
+
+		public virtual bool IsSynchronized
+		{
+			get { return impl.IsSynchronized; }
+		}
+
+		public virtual void Remove(object o)
+		{
+			impl.Remove(o);
+		}
+
+		public virtual void RemoveAll(IEnumerable e)
+		{
+			foreach (object o in e)
+			{
+				Remove(o);
+			}
+		}
+
+		public virtual object SyncRoot
+		{
+			get { return impl.SyncRoot; }
+		}
+	}
+}
diff --git a/crypto/src/util/collections/ISet.cs b/crypto/src/util/collections/ISet.cs
new file mode 100644
index 000000000..1f8edba40
--- /dev/null
+++ b/crypto/src/util/collections/ISet.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public interface ISet
+		: ICollection
+	{
+		void Add(object o);
+		void AddAll(IEnumerable e);
+		void Clear();
+		bool Contains(object o);
+		bool IsEmpty { get; }
+		bool IsFixedSize { get; }
+		bool IsReadOnly { get; }
+		void Remove(object o);
+		void RemoveAll(IEnumerable e);
+	}
+}
diff --git a/crypto/src/util/collections/LinkedDictionary.cs b/crypto/src/util/collections/LinkedDictionary.cs
new file mode 100644
index 000000000..933d38ded
--- /dev/null
+++ b/crypto/src/util/collections/LinkedDictionary.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public class LinkedDictionary
+		: IDictionary
+	{
+		internal readonly IDictionary hash = Platform.CreateHashtable();
+		internal readonly IList keys = Platform.CreateArrayList();
+
+		public LinkedDictionary()
+		{
+		}
+
+		public virtual void Add(object k, object v)
+		{
+			hash.Add(k, v);
+			keys.Add(k);
+		}
+
+		public virtual void Clear()
+		{
+			hash.Clear();
+			keys.Clear();
+		}
+
+		public virtual bool Contains(object k)
+		{
+			return hash.Contains(k);
+		}
+
+		public virtual void CopyTo(Array array, int index)
+		{
+			foreach (object k in keys)
+			{
+				array.SetValue(hash[k], index++);
+			}
+		}
+
+		public virtual int Count
+		{
+			get { return hash.Count; }
+		}
+
+		IEnumerator IEnumerable.GetEnumerator()
+		{
+			return GetEnumerator();
+		}
+
+		public virtual IDictionaryEnumerator GetEnumerator()
+		{
+			return new LinkedDictionaryEnumerator(this);
+		}
+
+		public virtual void Remove(object k)
+		{
+			hash.Remove(k);
+			keys.Remove(k);
+		}
+
+		public virtual bool IsFixedSize
+		{
+			get { return false; }
+		}
+
+		public virtual bool IsReadOnly
+		{
+			get { return false; }
+		}
+
+		public virtual bool IsSynchronized
+		{
+			get { return false; }
+		}
+
+		public virtual object SyncRoot
+		{
+			get { return false; }
+		}
+
+		public virtual ICollection Keys
+		{
+            get { return Platform.CreateArrayList(keys); }
+		}
+
+		public virtual ICollection Values
+		{
+			// NB: Order has to be the same as for Keys property
+			get
+			{
+                IList values = Platform.CreateArrayList(keys.Count);
+				foreach (object k in keys)
+				{
+					values.Add(hash[k]);
+				}
+				return values;
+			}
+		}
+
+		public virtual object this[object k]
+		{
+			get
+			{
+				return hash[k];
+			}
+			set
+			{
+				if (!hash.Contains(k))
+					keys.Add(k);
+				hash[k] = value;
+			}
+		}
+	}
+
+	internal class LinkedDictionaryEnumerator : IDictionaryEnumerator
+	{
+		private readonly LinkedDictionary parent;
+		private int pos = -1;
+
+		internal LinkedDictionaryEnumerator(LinkedDictionary parent)
+		{
+			this.parent = parent;
+		}
+
+		public virtual object Current
+		{
+			get { return Entry; }
+		}
+
+		public virtual DictionaryEntry Entry
+		{
+			get
+			{
+				object k = CurrentKey;
+				return new DictionaryEntry(k, parent.hash[k]);
+			}
+		}
+
+		public virtual object Key
+		{
+			get
+			{
+				return CurrentKey;
+			}
+		}
+
+		public virtual bool MoveNext()
+		{
+			if (pos >= parent.keys.Count)
+				return false;
+			return ++pos < parent.keys.Count;
+		}
+
+		public virtual void Reset()
+		{
+			this.pos = -1;
+		}
+
+		public virtual object Value
+		{
+			get
+			{
+				return parent.hash[CurrentKey];
+			}
+		}
+
+		private object CurrentKey
+		{
+			get
+			{
+				if (pos < 0 || pos >= parent.keys.Count)
+					throw new InvalidOperationException();
+				return parent.keys[pos];
+			}
+		}
+	}
+}
diff --git a/crypto/src/util/collections/UnmodifiableDictionary.cs b/crypto/src/util/collections/UnmodifiableDictionary.cs
new file mode 100644
index 000000000..0bdf70ad7
--- /dev/null
+++ b/crypto/src/util/collections/UnmodifiableDictionary.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public abstract class UnmodifiableDictionary
+		: IDictionary
+	{
+		protected UnmodifiableDictionary()
+		{
+		}
+
+		public virtual void Add(object k, object v)
+		{
+			throw new NotSupportedException();
+		}
+
+		public virtual void Clear()
+		{
+			throw new NotSupportedException();
+		}
+
+		public abstract bool Contains(object k);
+
+		public abstract void CopyTo(Array array, int index);
+
+		public abstract int Count { get; }
+
+		IEnumerator IEnumerable.GetEnumerator()
+		{
+			return GetEnumerator();
+		}
+
+		public abstract IDictionaryEnumerator GetEnumerator();
+
+		public virtual void Remove(object k)
+		{
+			throw new NotSupportedException();
+		}
+
+		public abstract bool IsFixedSize { get; }
+
+		public virtual bool IsReadOnly
+		{
+			get { return true; }
+		}
+
+		public abstract bool IsSynchronized { get; }
+
+		public abstract object SyncRoot { get; }
+
+		public abstract ICollection Keys { get; }
+
+		public abstract ICollection Values { get; }
+
+		public virtual object this[object k]
+		{
+			get { return GetValue(k); }
+			set { throw new NotSupportedException(); }
+		}
+
+		protected abstract object GetValue(object k);
+	}
+}
diff --git a/crypto/src/util/collections/UnmodifiableDictionaryProxy.cs b/crypto/src/util/collections/UnmodifiableDictionaryProxy.cs
new file mode 100644
index 000000000..0fca909a3
--- /dev/null
+++ b/crypto/src/util/collections/UnmodifiableDictionaryProxy.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public class UnmodifiableDictionaryProxy
+		: UnmodifiableDictionary
+	{
+		private readonly IDictionary d;
+
+		public UnmodifiableDictionaryProxy(IDictionary d)
+		{
+			this.d = d;
+		}
+
+		public override bool Contains(object k)
+		{
+			return d.Contains(k);
+		}
+
+		public override void CopyTo(Array array, int index)
+		{
+			d.CopyTo(array, index);
+		}
+
+		public override int Count
+		{
+			get { return d.Count; }
+		}
+
+		public override IDictionaryEnumerator GetEnumerator()
+		{
+			return d.GetEnumerator();
+		}
+
+		public override bool IsFixedSize
+		{
+			get { return d.IsFixedSize; }
+		}
+
+		public override bool IsSynchronized
+		{
+			get { return d.IsSynchronized; }
+		}
+
+		public override object SyncRoot
+		{
+			get { return d.SyncRoot; }
+		}
+
+		public override ICollection Keys
+		{
+			get { return d.Keys; }
+		}
+
+		public override ICollection Values
+		{
+			get { return d.Values; }
+		}
+
+		protected override object GetValue(object k)
+		{
+			return d[k];
+		}
+	}
+}
diff --git a/crypto/src/util/collections/UnmodifiableList.cs b/crypto/src/util/collections/UnmodifiableList.cs
new file mode 100644
index 000000000..28e49eac3
--- /dev/null
+++ b/crypto/src/util/collections/UnmodifiableList.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public abstract class UnmodifiableList
+		: IList
+	{
+		protected UnmodifiableList()
+		{
+		}
+
+		public virtual int Add(object o)
+		{
+			throw new NotSupportedException();
+		}
+
+		public virtual void Clear()
+		{
+			throw new NotSupportedException();
+		}
+
+		public abstract bool Contains(object o);
+
+		public abstract void CopyTo(Array array, int index);
+
+		public abstract int Count { get; }
+
+		public abstract IEnumerator GetEnumerator();
+
+		public abstract int IndexOf(object o);
+
+		public virtual void Insert(int i, object o)
+		{
+			throw new NotSupportedException();
+		}
+
+		public abstract bool IsFixedSize { get; }
+
+		public virtual bool IsReadOnly
+		{
+			get { return true; }
+		}
+
+		public abstract bool IsSynchronized { get; }
+
+		public virtual void Remove(object o)
+		{
+			throw new NotSupportedException();
+		}
+
+		public virtual void RemoveAt(int i)
+		{
+			throw new NotSupportedException();
+		}
+
+		public abstract object SyncRoot { get; }
+		
+		public virtual object this[int i]
+		{
+			get { return GetValue(i); }
+			set { throw new NotSupportedException(); }
+		}
+
+		protected abstract object GetValue(int i);
+	}
+}
diff --git a/crypto/src/util/collections/UnmodifiableListProxy.cs b/crypto/src/util/collections/UnmodifiableListProxy.cs
new file mode 100644
index 000000000..9d00737ef
--- /dev/null
+++ b/crypto/src/util/collections/UnmodifiableListProxy.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public class UnmodifiableListProxy
+		: UnmodifiableList
+	{
+		private readonly IList l;
+
+		public UnmodifiableListProxy(IList l)
+		{
+			this.l = l;
+		}
+
+		public override bool Contains(object o)
+		{
+			return l.Contains(o);
+		}
+
+		public override void CopyTo(Array array, int index)
+		{
+			l.CopyTo(array, index);
+		}
+
+		public override int Count
+		{
+			get { return l.Count; }
+		}
+
+		public override IEnumerator GetEnumerator()
+		{
+			return l.GetEnumerator();
+		}
+
+		public override int IndexOf(object o)
+		{
+			return l.IndexOf(o);
+		}
+
+		public override bool IsFixedSize
+		{
+			get { return l.IsFixedSize; }
+		}
+
+		public override bool IsSynchronized
+		{
+			get { return l.IsSynchronized; }
+		}
+
+		public override object SyncRoot
+		{
+			get { return l.SyncRoot; }
+		}
+
+		protected override object GetValue(int i)
+		{
+			return l[i];
+		}
+	}
+}
diff --git a/crypto/src/util/collections/UnmodifiableSet.cs b/crypto/src/util/collections/UnmodifiableSet.cs
new file mode 100644
index 000000000..8792815ac
--- /dev/null
+++ b/crypto/src/util/collections/UnmodifiableSet.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public abstract class UnmodifiableSet
+		: ISet
+	{
+		protected UnmodifiableSet()
+		{
+		}
+
+		public virtual void Add(object o)
+		{
+			throw new NotSupportedException();
+		}
+
+		public virtual void AddAll(IEnumerable e)
+		{
+			throw new NotSupportedException();
+		}
+
+		public virtual void Clear()
+		{
+			throw new NotSupportedException();
+		}
+		
+		public abstract bool Contains(object o);
+
+		public abstract void CopyTo(Array array, int index);
+
+		public abstract int Count { get; }
+
+		public abstract IEnumerator GetEnumerator();
+
+		public abstract bool IsEmpty { get; }
+
+		public abstract bool IsFixedSize { get; }
+
+		public virtual bool IsReadOnly
+		{
+			get { return true; }
+		}
+
+		public abstract bool IsSynchronized { get; }
+
+		public abstract object SyncRoot { get; }
+
+		public virtual void Remove(object o)
+		{
+			throw new NotSupportedException();
+		}
+
+		public virtual void RemoveAll(IEnumerable e)
+		{
+			throw new NotSupportedException();
+		}
+	}
+}
diff --git a/crypto/src/util/collections/UnmodifiableSetProxy.cs b/crypto/src/util/collections/UnmodifiableSetProxy.cs
new file mode 100644
index 000000000..e119e2957
--- /dev/null
+++ b/crypto/src/util/collections/UnmodifiableSetProxy.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public class UnmodifiableSetProxy
+		: UnmodifiableSet
+	{
+		private readonly ISet s;
+
+		public UnmodifiableSetProxy (ISet s)
+		{
+			this.s = s;
+		}
+
+		public override bool Contains(object o)
+		{
+			return s.Contains(o);
+		}
+
+		public override void CopyTo(Array array, int index)
+		{
+			s.CopyTo(array, index);
+		}
+
+		public override int Count
+		{
+			get { return s.Count; }
+		}
+
+		public override IEnumerator GetEnumerator()
+		{
+			return s.GetEnumerator();
+		}
+
+		public override bool IsEmpty
+		{
+			get { return s.IsEmpty; }
+		}
+
+		public override bool IsFixedSize
+		{
+			get { return s.IsFixedSize; }
+		}
+
+		public override bool IsSynchronized
+		{
+			get { return s.IsSynchronized; }
+		}
+
+		public override object SyncRoot
+		{
+			get { return s.SyncRoot; }
+		}
+	}
+}
diff --git a/crypto/src/util/date/DateTimeObject.cs b/crypto/src/util/date/DateTimeObject.cs
new file mode 100644
index 000000000..793376b6d
--- /dev/null
+++ b/crypto/src/util/date/DateTimeObject.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Date
+{
+	public sealed class DateTimeObject
+	{
+		private readonly DateTime dt;
+
+		public DateTimeObject(
+			DateTime dt)
+		{
+			this.dt = dt;
+		}
+
+		public DateTime Value
+		{
+			get { return dt; }
+		}
+
+		public override string ToString()
+		{
+			return dt.ToString();
+		}
+	}
+}
diff --git a/crypto/src/util/date/DateTimeUtilities.cs b/crypto/src/util/date/DateTimeUtilities.cs
new file mode 100644
index 000000000..311ad5d37
--- /dev/null
+++ b/crypto/src/util/date/DateTimeUtilities.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Date
+{
+	public class DateTimeUtilities
+	{
+		public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1);
+
+		private DateTimeUtilities()
+		{
+		}
+
+		/// <summary>
+		/// Return the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC) for a given DateTime value.
+		/// </summary>
+		/// <param name="dateTime">A UTC DateTime value not before epoch.</param>
+		/// <returns>Number of whole milliseconds after epoch.</returns>
+		/// <exception cref="ArgumentException">'dateTime' is before epoch.</exception>
+		public static long DateTimeToUnixMs(
+			DateTime dateTime)
+		{
+			if (dateTime.CompareTo(UnixEpoch) < 0)
+				throw new ArgumentException("DateTime value may not be before the epoch", "dateTime");
+
+			return (dateTime.Ticks - UnixEpoch.Ticks) / TimeSpan.TicksPerMillisecond;
+		}
+
+		/// <summary>
+		/// Create a DateTime value from the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+		/// </summary>
+		/// <param name="unixMs">Number of milliseconds since the epoch.</param>
+		/// <returns>A UTC DateTime value</returns>
+		public static DateTime UnixMsToDateTime(
+			long unixMs)
+		{
+			return new DateTime(unixMs * TimeSpan.TicksPerMillisecond + UnixEpoch.Ticks);
+		}
+
+		/// <summary>
+		/// Return the current number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+		/// </summary>
+		public static long CurrentUnixMs()
+		{
+			return DateTimeToUnixMs(DateTime.UtcNow);
+		}
+	}
+}
diff --git a/crypto/src/util/encoders/Base64.cs b/crypto/src/util/encoders/Base64.cs
index 5dc9fae63..ccecd8dc2 100644
--- a/crypto/src/util/encoders/Base64.cs
+++ b/crypto/src/util/encoders/Base64.cs
@@ -4,92 +4,117 @@ using System.Text;
 
 namespace Org.BouncyCastle.Utilities.Encoders
 {
-	public sealed class Base64
-	{
-		private Base64()
-		{
-		}
+    public sealed class Base64
+    {
+        private Base64()
+        {
+        }
 
-		/**
-		 * 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)
-		{
-			string s = Convert.ToBase64String(data, 0, data.Length);
+        public static string ToBase64String(
+            byte[] data)
+        {
+            return Convert.ToBase64String(data, 0, data.Length);
+        }
+
+        public static string ToBase64String(
+            byte[] data,
+            int off,
+            int length)
+        {
+            return Convert.ToBase64String(data, off, length);
+        }
+
+        /**
+         * 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)
+        {
+            return Encode(data, 0, data.Length);
+        }
+
+        /**
+         * 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 off,
+            int length)
+        {
+            string s = Convert.ToBase64String(data, off, length);
             return Strings.ToAsciiByteArray(s);
-		}
+        }
 
-		/**
-		 * 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,
-			Stream	outStream)
-		{
-			string s = Convert.ToBase64String(data, 0, data.Length);
-            byte[] encoded = Strings.ToAsciiByteArray(s);
-			outStream.Write(encoded, 0, encoded.Length);
-			return encoded.Length;
-		}
+        /**
+         * 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,
+            Stream	outStream)
+        {
+            byte[] encoded = Encode(data);
+            outStream.Write(encoded, 0, encoded.Length);
+            return encoded.Length;
+        }
 
-		/**
-		 * 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,
-			Stream	outStream)
-		{
-			string s = Convert.ToBase64String(data, off, length);
-            byte[] encoded = Strings.ToAsciiByteArray(s);
-			outStream.Write(encoded, 0, encoded.Length);
-			return encoded.Length;
-		}
+        /**
+         * 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,
+            Stream	outStream)
+        {
+            byte[] encoded = Encode(data, off, length);
+            outStream.Write(encoded, 0, encoded.Length);
+            return encoded.Length;
+        }
 
-		/**
-		 * 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)
-		{
+        /**
+         * 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)
+        {
             string s = Strings.FromAsciiByteArray(data);
-			return Convert.FromBase64String(s);
-		}
+            return Convert.FromBase64String(s);
+        }
 
-		/**
-		 * 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)
-		{
-			return Convert.FromBase64String(data);
-		}
+        /**
+         * 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)
+        {
+            return Convert.FromBase64String(data);
+        }
 
-		/**
-		 * 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,
-			Stream	outStream)
-		{
-			byte[] decoded = Decode(data);
-			outStream.Write(decoded, 0, decoded.Length);
-			return decoded.Length;
-		}
-	}
+        /**
+         * 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,
+            Stream	outStream)
+        {
+            byte[] decoded = Decode(data);
+            outStream.Write(decoded, 0, decoded.Length);
+            return decoded.Length;
+        }
+    }
 }
diff --git a/crypto/src/util/encoders/Base64Encoder.cs b/crypto/src/util/encoders/Base64Encoder.cs
index c94ce9d3c..7b53df25a 100644
--- a/crypto/src/util/encoders/Base64Encoder.cs
+++ b/crypto/src/util/encoders/Base64Encoder.cs
@@ -3,305 +3,322 @@ using System.IO;
 
 namespace Org.BouncyCastle.Utilities.Encoders
 {
-	public class Base64Encoder
-		: IEncoder
-	{
-		protected readonly 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 readonly 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,
-			Stream	outStream)
-		{
-			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;
-
-				outStream.WriteByte(encodingTable[(int) ((uint) a1 >> 2) & 0x3f]);
-				outStream.WriteByte(encodingTable[((a1 << 4) | (int) ((uint) a2 >> 4)) & 0x3f]);
-				outStream.WriteByte(encodingTable[((a2 << 2) | (int) ((uint) a3 >> 6)) & 0x3f]);
-				outStream.WriteByte(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;
-
-					outStream.WriteByte(encodingTable[b1]);
-					outStream.WriteByte(encodingTable[b2]);
-					outStream.WriteByte(padding);
-					outStream.WriteByte(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;
-
-					outStream.WriteByte(encodingTable[b1]);
-					outStream.WriteByte(encodingTable[b2]);
-					outStream.WriteByte(encodingTable[b3]);
-					outStream.WriteByte(padding);
-					break;
-			}
-
-			return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
-		}
-
-		private bool 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,
-			Stream	outStream)
-		{
-			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++]];
-
-				outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
-				outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
-				outStream.WriteByte((byte)((b3 << 6) | b4));
-
-				outLen += 3;
-
-				i = nextI(data, i, finish);
-			}
-
-			outLen += decodeLastBlock(outStream, (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 DecodeString(
-			string	data,
-			Stream	outStream)
-		{
-			// Platform Implementation
+    public class Base64Encoder
+        : IEncoder
+    {
+        protected readonly 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 readonly byte[] decodingTable = new byte[128];
+
+        protected void InitialiseDecodingTable()
+        {
+            Arrays.Fill(decodingTable, (byte)0xff);
+
+            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,
+            Stream	outStream)
+        {
+            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;
+
+                outStream.WriteByte(encodingTable[(int) ((uint) a1 >> 2) & 0x3f]);
+                outStream.WriteByte(encodingTable[((a1 << 4) | (int) ((uint) a2 >> 4)) & 0x3f]);
+                outStream.WriteByte(encodingTable[((a2 << 2) | (int) ((uint) a3 >> 6)) & 0x3f]);
+                outStream.WriteByte(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;
+
+                    outStream.WriteByte(encodingTable[b1]);
+                    outStream.WriteByte(encodingTable[b2]);
+                    outStream.WriteByte(padding);
+                    outStream.WriteByte(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;
+
+                    outStream.WriteByte(encodingTable[b1]);
+                    outStream.WriteByte(encodingTable[b2]);
+                    outStream.WriteByte(encodingTable[b3]);
+                    outStream.WriteByte(padding);
+                    break;
+            }
+
+            return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+        }
+
+        private bool 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,
+            Stream	outStream)
+        {
+            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++]];
+
+                if ((b1 | b2 | b3 | b4) >= 0x80)
+                    throw new IOException("invalid characters encountered in base64 data");
+
+                outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+                outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+                outStream.WriteByte((byte)((b3 << 6) | b4));
+
+                outLen += 3;
+
+                i = nextI(data, i, finish);
+            }
+
+            outLen += decodeLastBlock(outStream, (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 DecodeString(
+            string	data,
+            Stream	outStream)
+        {
+            // Platform Implementation
 //			byte[] bytes = Convert.FromBase64String(data);
 //			outStream.Write(bytes, 0, bytes.Length);
 //			return bytes.Length;
 
-			byte b1, b2, b3, b4;
-			int length = 0;
+            byte b1, b2, b3, b4;
+            int length = 0;
 
-			int end = data.Length;
+            int end = data.Length;
 
-			while (end > 0)
-			{
-				if (!ignore(data[end - 1]))
-				{
-					break;
-				}
+            while (end > 0)
+            {
+                if (!ignore(data[end - 1]))
+                {
+                    break;
+                }
 
-				end--;
-			}
+                end--;
+            }
 
-			int  i = 0;
-			int  finish = end - 4;
+            int  i = 0;
+            int  finish = end - 4;
 
-			i = nextI(data, i, finish);
+            i = nextI(data, i, finish);
 
-			while (i < finish)
-			{
-				b1 = decodingTable[data[i++]];
+            while (i < finish)
+            {
+                b1 = decodingTable[data[i++]];
 
-				i = nextI(data, i, finish);
+                i = nextI(data, i, finish);
 
-				b2 = decodingTable[data[i++]];
+                b2 = decodingTable[data[i++]];
 
-				i = nextI(data, i, finish);
+                i = nextI(data, i, finish);
 
-				b3 = decodingTable[data[i++]];
+                b3 = decodingTable[data[i++]];
 
-				i = nextI(data, i, finish);
+                i = nextI(data, i, finish);
 
-				b4 = decodingTable[data[i++]];
+                b4 = decodingTable[data[i++]];
 
-				outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
-				outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
-				outStream.WriteByte((byte)((b3 << 6) | b4));
+                if ((b1 | b2 | b3 | b4) >= 0x80)
+                    throw new IOException("invalid characters encountered in base64 data");
 
-				length += 3;
+                outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+                outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+                outStream.WriteByte((byte)((b3 << 6) | b4));
 
-				i = nextI(data, i, finish);
-			}
+                length += 3;
 
-			length += decodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]);
+                i = nextI(data, i, finish);
+            }
 
-			return length;
-		}
+            length += decodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]);
 
-		private int decodeLastBlock(
-			Stream	outStream,
-			char	c1,
-			char	c2,
-			char	c3,
-			char	c4)
-		{
-			if (c3 == padding)
-			{
-				byte b1 = decodingTable[c1];
-				byte b2 = decodingTable[c2];
+            return length;
+        }
 
-				outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+        private int decodeLastBlock(
+            Stream	outStream,
+            char	c1,
+            char	c2,
+            char	c3,
+            char	c4)
+        {
+            if (c3 == padding)
+            {
+                byte b1 = decodingTable[c1];
+                byte b2 = decodingTable[c2];
 
-				return 1;
-			}
+                if ((b1 | b2) >= 0x80)
+                    throw new IOException("invalid characters encountered at end of base64 data");
 
-			if (c4 == padding)
-			{
-				byte b1 = decodingTable[c1];
-				byte b2 = decodingTable[c2];
-				byte b3 = decodingTable[c3];
+                outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
 
-				outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
-				outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+                return 1;
+            }
 
-				return 2;
-			}
+            if (c4 == padding)
+            {
+                byte b1 = decodingTable[c1];
+                byte b2 = decodingTable[c2];
+                byte b3 = decodingTable[c3];
 
-			{
-				byte b1 = decodingTable[c1];
-				byte b2 = decodingTable[c2];
-				byte b3 = decodingTable[c3];
-				byte b4 = decodingTable[c4];
+                if ((b1 | b2 | b3) >= 0x80)
+                    throw new IOException("invalid characters encountered at end of base64 data");
 
-				outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
-				outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
-				outStream.WriteByte((byte)((b3 << 6) | b4));
+                outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+                outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
 
-				return 3;
-			}
-		}
+                return 2;
+            }
 
-		private int nextI(string data, int i, int finish)
-		{
-			while ((i < finish) && ignore(data[i]))
-			{
-				i++;
-			}
-			return i;
-		}
-	}
+            {
+                byte b1 = decodingTable[c1];
+                byte b2 = decodingTable[c2];
+                byte b3 = decodingTable[c3];
+                byte b4 = decodingTable[c4];
+
+                if ((b1 | b2 | b3 | b4) >= 0x80)
+                    throw new IOException("invalid characters encountered at end of base64 data");
+
+                outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+                outStream.WriteByte((byte)((b2 << 4) | (b3 >> 2)));
+                outStream.WriteByte((byte)((b3 << 6) | b4));
+
+                return 3;
+            }
+        }
+
+        private int nextI(string data, int i, int finish)
+        {
+            while ((i < finish) && ignore(data[i]))
+            {
+                i++;
+            }
+            return i;
+        }
+    }
 }
diff --git a/crypto/src/util/encoders/BufferedDecoder.cs b/crypto/src/util/encoders/BufferedDecoder.cs
new file mode 100644
index 000000000..633cf1e97
--- /dev/null
+++ b/crypto/src/util/encoders/BufferedDecoder.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+    /// <summary>
+    ///  A buffering class to allow translation from one format to another to
+    ///     be done in discrete chunks.
+    /// </summary>
+    public class BufferedDecoder
+    {
+        internal byte[]        buffer;
+        internal int           bufOff;
+
+        internal ITranslator   translator;
+
+        /// <summary>
+        /// Create a buffered Decoder.
+        /// </summary>
+        /// <param name="translator">The translater to use.</param>
+        /// <param name="bufferSize">The size of the buffer.</param>
+        public BufferedDecoder(
+            ITranslator translator,
+            int         bufferSize)
+        {
+            this.translator = translator;
+
+            if ((bufferSize % translator.GetEncodedBlockSize()) != 0)
+            {
+                throw new ArgumentException("buffer size not multiple of input block size");
+            }
+
+            buffer = new byte[bufferSize];
+//            bufOff = 0;
+        }
+
+        /// <summary>
+        /// Process one byte of data.
+        /// </summary>
+        /// <param name="input">Data in.</param>
+        /// <param name="output">Byte array for the output.</param>
+        /// <param name="outOff">The offset in the output byte array to start writing from.</param>
+        /// <returns>The amount of output bytes.</returns>
+        public int ProcessByte(
+            byte        input,
+            byte[]      output,
+            int         outOff)
+        {
+            int         resultLen = 0;
+
+            buffer[bufOff++] = input;
+
+            if (bufOff == buffer.Length)
+            {
+                resultLen = translator.Decode(buffer, 0, buffer.Length, output, outOff);
+                bufOff = 0;
+            }
+
+            return resultLen;
+        }
+
+
+        /// <summary>
+        /// Process data from a byte array.
+        /// </summary>
+        /// <param name="input">The input data.</param>
+        /// <param name="inOff">Start position within input data array.</param>
+        /// <param name="len">Amount of data to process from input data array.</param>
+        /// <param name="outBytes">Array to store output.</param>
+        /// <param name="outOff">Position in output array to start writing from.</param>
+        /// <returns>The amount of output bytes.</returns>
+        public int ProcessBytes(
+            byte[]      input,
+            int         inOff,
+            int         len,
+            byte[]      outBytes,
+            int         outOff)
+        {
+            if (len < 0)
+            {
+            throw new ArgumentException("Can't have a negative input length!");
+            }
+
+            int resultLen = 0;
+            int gapLen = buffer.Length - bufOff;
+
+            if (len > gapLen)
+            {
+                Array.Copy(input, inOff, buffer, bufOff, gapLen);
+
+                resultLen += translator.Decode(buffer, 0, buffer.Length, outBytes, outOff);
+
+                bufOff = 0;
+
+                len -= gapLen;
+                inOff += gapLen;
+                outOff += resultLen;
+
+                int chunkSize = len - (len % buffer.Length);
+
+                resultLen += translator.Decode(input, inOff, chunkSize, outBytes, outOff);
+
+                len -= chunkSize;
+                inOff += chunkSize;
+            }
+
+            if (len != 0)
+            {
+                Array.Copy(input, inOff, buffer, bufOff, len);
+
+                bufOff += len;
+            }
+
+            return resultLen;
+        }
+    }
+
+}
diff --git a/crypto/src/util/encoders/BufferedEncoder.cs b/crypto/src/util/encoders/BufferedEncoder.cs
new file mode 100644
index 000000000..5c3b1ab46
--- /dev/null
+++ b/crypto/src/util/encoders/BufferedEncoder.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+    /// <summary>
+    /// A class that allows encoding of data using a specific encoder to be processed in chunks.
+    /// </summary>
+    public class BufferedEncoder
+    {
+        internal byte[]        Buffer;
+        internal int           bufOff;
+
+        internal ITranslator   translator;
+
+
+        /// <summary>
+        /// Create.
+        /// </summary>
+        /// <param name="translator">The translator to use.</param>
+        /// <param name="bufferSize">Size of the chunks.</param>
+        public BufferedEncoder(
+            ITranslator translator,
+            int         bufferSize)
+        {
+            this.translator = translator;
+
+            if ((bufferSize % translator.GetEncodedBlockSize()) != 0)
+            {
+                throw new ArgumentException("buffer size not multiple of input block size");
+            }
+
+            Buffer = new byte[bufferSize];
+//            bufOff = 0;
+        }
+
+
+        /// <summary>
+        /// Process one byte of data.
+        /// </summary>
+        /// <param name="input">The byte.</param>
+        /// <param name="outBytes">An array to store output in.</param>
+        /// <param name="outOff">Offset within output array to start writing from.</param>
+        /// <returns></returns>
+        public int ProcessByte(
+            byte        input,
+            byte[]      outBytes,
+            int         outOff)
+        {
+            int         resultLen = 0;
+
+            Buffer[bufOff++] = input;
+
+            if (bufOff == Buffer.Length)
+            {
+                resultLen = translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff);
+                bufOff = 0;
+            }
+
+            return resultLen;
+        }
+
+        /// <summary>
+        /// Process data from a byte array.
+        /// </summary>
+        /// <param name="input">Input data Byte array containing data to be processed.</param>
+        /// <param name="inOff">Start position within input data array.</param>
+        /// <param name="len">Amount of input data to be processed.</param>
+        /// <param name="outBytes">Output data array.</param>
+        /// <param name="outOff">Offset within output data array to start writing to.</param>
+        /// <returns>The amount of data written.</returns>
+        public int ProcessBytes(
+            byte[]      input,
+            int         inOff,
+            int         len,
+            byte[]      outBytes,
+            int         outOff)
+        {
+            if (len < 0)
+            {
+            throw new ArgumentException("Can't have a negative input length!");
+            }
+
+            int resultLen = 0;
+            int gapLen = Buffer.Length - bufOff;
+
+            if (len > gapLen)
+            {
+                Array.Copy(input, inOff, Buffer, bufOff, gapLen);
+
+                resultLen += translator.Encode(Buffer, 0, Buffer.Length, outBytes, outOff);
+
+                bufOff = 0;
+
+                len -= gapLen;
+                inOff += gapLen;
+                outOff += resultLen;
+
+                int chunkSize = len - (len % Buffer.Length);
+
+                resultLen += translator.Encode(input, inOff, chunkSize, outBytes, outOff);
+
+                len -= chunkSize;
+                inOff += chunkSize;
+            }
+
+            if (len != 0)
+            {
+                Array.Copy(input, inOff, Buffer, bufOff, len);
+
+                bufOff += len;
+            }
+
+            return resultLen;
+        }
+    }
+
+}
diff --git a/crypto/src/util/encoders/Hex.cs b/crypto/src/util/encoders/Hex.cs
index fbe475991..3540a9d1e 100644
--- a/crypto/src/util/encoders/Hex.cs
+++ b/crypto/src/util/encoders/Hex.cs
@@ -4,128 +4,127 @@ using System.Text;
 
 namespace Org.BouncyCastle.Utilities.Encoders
 {
-	/// <summary>
-	/// Class to decode and encode Hex.
-	/// </summary>
-	public sealed class Hex
-	{
-		private static readonly IEncoder encoder = new HexEncoder();
-
-		private Hex()
-		{
-		}
-
-		public static string ToHexString(
-			byte[] data)
-		{
-			byte[] hex = Encode(data, 0, data.Length);
-            return Strings.FromAsciiByteArray(hex);
-		}
-
-		public static string ToHexString(
-			byte[]	data,
-			int		off,
-			int		length)
-		{
-			byte[] hex = Encode(data, off, length);
+    /// <summary>
+    /// Class to decode and encode Hex.
+    /// </summary>
+    public sealed class Hex
+    {
+        private static readonly IEncoder encoder = new HexEncoder();
+
+        private Hex()
+        {
+        }
+
+        public static string ToHexString(
+            byte[] data)
+        {
+            return ToHexString(data, 0, data.Length);
+        }
+
+        public static string ToHexString(
+            byte[]	data,
+            int		off,
+            int		length)
+        {
+            byte[] hex = Encode(data, off, length);
             return Strings.FromAsciiByteArray(hex);
         }
 
-		/**
-		 * 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)
-		{
-			MemoryStream bOut = new MemoryStream(length * 2);
-
-			encoder.Encode(data, off, length, bOut);
-
-			return bOut.ToArray();
-		}
-
-		/**
-		 * Hex encode the byte data writing it to the given output stream.
-		 *
-		 * @return the number of bytes produced.
-		 */
-		public static int Encode(
-			byte[]	data,
-			Stream	outStream)
-		{
-			return encoder.Encode(data, 0, data.Length, outStream);
-		}
-
-		/**
-		 * 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,
-			Stream	outStream)
-		{
-			return encoder.Encode(data, off, length, outStream);
-		}
-
-		/**
-		 * 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)
-		{
-			MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
-
-			encoder.Decode(data, 0, data.Length, bOut);
-
-			return bOut.ToArray();
-		}
-
-		/**
-		 * decode the Hex encoded string data - whitespace will be ignored.
-		 *
-		 * @return a byte array representing the decoded data.
-		 */
-		public static byte[] Decode(
-			string data)
-		{
-			MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
-
-			encoder.DecodeString(data, bOut);
-
-			return bOut.ToArray();
-		}
-
-		/**
-		 * 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,
-			Stream	outStream)
-		{
-			return encoder.DecodeString(data, outStream);
-		}
-	}
+        /**
+         * 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)
+        {
+            MemoryStream bOut = new MemoryStream(length * 2);
+
+            encoder.Encode(data, off, length, bOut);
+
+            return bOut.ToArray();
+        }
+
+        /**
+         * Hex encode the byte data writing it to the given output stream.
+         *
+         * @return the number of bytes produced.
+         */
+        public static int Encode(
+            byte[]	data,
+            Stream	outStream)
+        {
+            return encoder.Encode(data, 0, data.Length, outStream);
+        }
+
+        /**
+         * 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,
+            Stream	outStream)
+        {
+            return encoder.Encode(data, off, length, outStream);
+        }
+
+        /**
+         * 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)
+        {
+            MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
+
+            encoder.Decode(data, 0, data.Length, bOut);
+
+            return bOut.ToArray();
+        }
+
+        /**
+         * decode the Hex encoded string data - whitespace will be ignored.
+         *
+         * @return a byte array representing the decoded data.
+         */
+        public static byte[] Decode(
+            string data)
+        {
+            MemoryStream bOut = new MemoryStream((data.Length + 1) / 2);
+
+            encoder.DecodeString(data, bOut);
+
+            return bOut.ToArray();
+        }
+
+        /**
+         * 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,
+            Stream	outStream)
+        {
+            return encoder.DecodeString(data, outStream);
+        }
+    }
 }
diff --git a/crypto/src/util/encoders/HexEncoder.cs b/crypto/src/util/encoders/HexEncoder.cs
index c47d6219b..af526e0da 100644
--- a/crypto/src/util/encoders/HexEncoder.cs
+++ b/crypto/src/util/encoders/HexEncoder.cs
@@ -3,162 +3,174 @@ using System.IO;
 
 namespace Org.BouncyCastle.Utilities.Encoders
 {
-	public class HexEncoder
-		: IEncoder
-	{
-		private static readonly 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.
-		*/
-		internal static readonly byte[] decodingTable = new byte[128];
-
-		static HexEncoder()
-		{
-			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'];
-		}
-
-		/**
-		* encode the input data producing a Hex output stream.
-		*
-		* @return the number of bytes produced.
-		*/
-		public int Encode(
-			byte[]	data,
-			int		off,
-			int		length,
-			Stream	outStream)
-		{
-			for (int i = off; i < (off + length); i++)
-			{
-				int v = data[i];
-
-				outStream.WriteByte(encodingTable[v >> 4]);
-				outStream.WriteByte(encodingTable[v & 0xf]);
-			}
-
-			return length * 2;
-		}
-
-		private bool 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,
-			Stream	outStream)
-		{
-			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++]];
-
-				outStream.WriteByte((byte)((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 DecodeString(
-			string	data,
-			Stream	outStream)
-		{
-			byte    b1, b2;
-			int     length = 0;
-
-			int     end = data.Length;
-
-			while (end > 0)
-			{
-				if (!ignore(data[end - 1]))
-				{
-					break;
-				}
-
-				end--;
-			}
-
-			int i = 0;
-			while (i < end)
-			{
-				while (i < end && ignore(data[i]))
-				{
-					i++;
-				}
-
-				b1 = decodingTable[data[i++]];
-
-				while (i < end && ignore(data[i]))
-				{
-					i++;
-				}
-
-				b2 = decodingTable[data[i++]];
-
-				outStream.WriteByte((byte)((b1 << 4) | b2));
-
-				length++;
-			}
-
-			return length;
-		}
-	}
+    public class HexEncoder
+        : IEncoder
+    {
+        protected readonly 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 readonly byte[] decodingTable = new byte[128];
+
+        protected void InitialiseDecodingTable()
+        {
+            Arrays.Fill(decodingTable, (byte)0xff);
+
+            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,
+            Stream	outStream)
+        {
+            for (int i = off; i < (off + length); i++)
+            {
+                int v = data[i];
+
+                outStream.WriteByte(encodingTable[v >> 4]);
+                outStream.WriteByte(encodingTable[v & 0xf]);
+            }
+
+            return length * 2;
+        }
+
+        private static bool 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,
+            Stream	outStream)
+        {
+            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++]];
+
+                if ((b1 | b2) >= 0x80)
+                    throw new IOException("invalid characters encountered in Hex data");
+
+                outStream.WriteByte((byte)((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 DecodeString(
+            string	data,
+            Stream	outStream)
+        {
+            byte    b1, b2;
+            int     length = 0;
+
+            int     end = data.Length;
+
+            while (end > 0)
+            {
+                if (!Ignore(data[end - 1]))
+                {
+                    break;
+                }
+
+                end--;
+            }
+
+            int i = 0;
+            while (i < end)
+            {
+                while (i < end && Ignore(data[i]))
+                {
+                    i++;
+                }
+
+                b1 = decodingTable[data[i++]];
+
+                while (i < end && Ignore(data[i]))
+                {
+                    i++;
+                }
+
+                b2 = decodingTable[data[i++]];
+
+                if ((b1 | b2) >= 0x80)
+                    throw new IOException("invalid characters encountered in Hex data");
+
+                outStream.WriteByte((byte)((b1 << 4) | b2));
+
+                length++;
+            }
+
+            return length;
+        }
+    }
 }
diff --git a/crypto/src/util/encoders/HexTranslator.cs b/crypto/src/util/encoders/HexTranslator.cs
new file mode 100644
index 000000000..9775b6948
--- /dev/null
+++ b/crypto/src/util/encoders/HexTranslator.cs
@@ -0,0 +1,108 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+    /// <summary>
+    /// A hex translator.
+    /// </summary>
+    public class HexTranslator : ITranslator
+    {
+        private static readonly byte[]   hexTable =
+            {
+                (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'
+            };
+
+        /// <summary>
+        /// Return encoded block size.
+        /// </summary>
+        /// <returns>2</returns>
+        public int GetEncodedBlockSize()
+        {
+            return 2;
+        }
+
+        /// <summary>
+        /// Encode some data.
+        /// </summary>
+        /// <param name="input">Input data array.</param>
+        /// <param name="inOff">Start position within input data array.</param>
+        /// <param name="length">The amount of data to process.</param>
+        /// <param name="outBytes">The output data array.</param>
+        /// <param name="outOff">The offset within the output data array to start writing from.</param>
+        /// <returns>Amount of data encoded.</returns>
+        public int Encode(
+            byte[]  input,
+            int     inOff,
+            int     length,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            for (int i = 0, j = 0; i < length; i++, j += 2)
+            {
+                outBytes[outOff + j] = hexTable[(input[inOff] >> 4) & 0x0f];
+                outBytes[outOff + j + 1] = hexTable[input[inOff] & 0x0f];
+
+                inOff++;
+            }
+
+            return length * 2;
+        }
+
+        /// <summary>
+        /// Returns the decoded block size.
+        /// </summary>
+        /// <returns>1</returns>
+        public int GetDecodedBlockSize()
+        {
+            return 1;
+        }
+
+        /// <summary>
+        /// Decode data from a byte array.
+        /// </summary>
+        /// <param name="input">The input data array.</param>
+        /// <param name="inOff">Start position within input data array.</param>
+        /// <param name="length">The amounty of data to process.</param>
+        /// <param name="outBytes">The output data array.</param>
+        /// <param name="outOff">The position within the output data array to start writing from.</param>
+        /// <returns>The amount of data written.</returns>
+        public int Decode(
+            byte[]  input,
+            int     inOff,
+            int     length,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            int halfLength = length / 2;
+            byte left, right;
+            for (int i = 0; i < halfLength; i++)
+            {
+                left  = input[inOff + i * 2];
+                right = input[inOff + i * 2 + 1];
+
+                if (left < (byte)'a')
+                {
+                    outBytes[outOff] = (byte)((left - '0') << 4);
+                }
+                else
+                {
+                    outBytes[outOff] = (byte)((left - 'a' + 10) << 4);
+                }
+                if (right < (byte)'a')
+                {
+                    outBytes[outOff] += (byte)(right - '0');
+                }
+                else
+                {
+                    outBytes[outOff] += (byte)(right - 'a' + 10);
+                }
+
+                outOff++;
+            }
+
+            return halfLength;
+        }
+    }
+
+}
diff --git a/crypto/src/util/encoders/IEncoder.cs b/crypto/src/util/encoders/IEncoder.cs
new file mode 100644
index 000000000..5887d5daa
--- /dev/null
+++ b/crypto/src/util/encoders/IEncoder.cs
@@ -0,0 +1,18 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+	/**
+	 * Encode and decode byte arrays (typically from binary to 7-bit ASCII
+	 * encodings).
+	 */
+	public interface IEncoder
+	{
+		int Encode(byte[] data, int off, int length, Stream outStream);
+
+		int Decode(byte[] data, int off, int length, Stream outStream);
+
+		int DecodeString(string data, Stream outStream);
+	}
+}
diff --git a/crypto/src/util/encoders/Translator.cs b/crypto/src/util/encoders/Translator.cs
new file mode 100644
index 000000000..10bd24b63
--- /dev/null
+++ b/crypto/src/util/encoders/Translator.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+    /// <summary>
+    /// Translator interface.
+    /// </summary>
+    public interface ITranslator
+    {
+        int GetEncodedBlockSize();
+
+        int Encode(byte[] input, int inOff, int length, byte[] outBytes, int outOff);
+
+        int GetDecodedBlockSize();
+
+        int Decode(byte[] input, int inOff, int length, byte[] outBytes, int outOff);
+    }
+
+}
diff --git a/crypto/src/util/encoders/UrlBase64.cs b/crypto/src/util/encoders/UrlBase64.cs
new file mode 100644
index 000000000..94195ef5e
--- /dev/null
+++ b/crypto/src/util/encoders/UrlBase64.cs
@@ -0,0 +1,127 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+	/**
+	* Convert binary data to and from UrlBase64 encoding.  This is identical to
+	* Base64 encoding, except that the padding character is "." and the other 
+	* non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+	* <p>
+	* The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+	* data that is safe for use as an URL parameter. Base64 encoding does not
+	* produce encoded values that are safe for use in URLs, since "/" can be 
+	* interpreted as a path delimiter; "+" is the encoded form of a space; and
+	* "=" is used to separate a name from the corresponding value in an URL 
+	* parameter.
+	* </p>
+	*/
+	public class UrlBase64
+	{
+		private static readonly IEncoder encoder = new UrlBase64Encoder();
+
+		/**
+		* Encode the input data producing a URL safe base 64 encoded byte array.
+		*
+		* @return a byte array containing the URL safe base 64 encoded data.
+		*/
+		public static byte[] Encode(
+			byte[] data)
+		{
+			MemoryStream bOut = new MemoryStream();
+
+			try
+			{
+				encoder.Encode(data, 0, data.Length, bOut);
+			}
+			catch (IOException e)
+			{
+				throw new Exception("exception encoding URL safe base64 string: " + e.Message, e);
+			}
+
+			return bOut.ToArray();
+		}
+
+		/**
+		* Encode the byte data writing it to the given output stream.
+		*
+		* @return the number of bytes produced.
+		*/
+		public static int Encode(
+			byte[]	data,
+			Stream	outStr)
+		{
+			return encoder.Encode(data, 0, data.Length, outStr);
+		}
+
+		/**
+		* Decode the URL safe base 64 encoded input data - white space will be ignored.
+		*
+		* @return a byte array representing the decoded data.
+		*/
+		public static byte[] Decode(
+			byte[] data)
+		{
+			MemoryStream bOut = new MemoryStream();
+
+			try
+			{
+				encoder.Decode(data, 0, data.Length, bOut);
+			}
+			catch (IOException e)
+			{
+				throw new Exception("exception decoding URL safe base64 string: " + e.Message, e);
+			}
+
+			return bOut.ToArray();
+		}
+
+		/**
+		* decode the URL safe base 64 encoded byte data writing it to the given output stream,
+		* whitespace characters will be ignored.
+		*
+		* @return the number of bytes produced.
+		*/
+		public static int Decode(
+			byte[]	data,
+			Stream	outStr)
+		{
+			return encoder.Decode(data, 0, data.Length, outStr);
+		}
+
+		/**
+		* decode the URL safe base 64 encoded string data - whitespace will be ignored.
+		*
+		* @return a byte array representing the decoded data.
+		*/
+		public static byte[] Decode(
+			string data)
+		{
+			MemoryStream bOut = new MemoryStream();
+
+			try
+			{
+				encoder.DecodeString(data, bOut);
+			}
+			catch (IOException e)
+			{
+				throw new Exception("exception decoding URL safe base64 string: " + e.Message, e);
+			}
+	        
+			return bOut.ToArray();
+		}
+	    
+		/**
+		* Decode the URL safe 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,
+			Stream	outStr)
+		{
+			return encoder.DecodeString(data, outStr);
+		}
+	}
+}
diff --git a/crypto/src/util/encoders/UrlBase64Encoder.cs b/crypto/src/util/encoders/UrlBase64Encoder.cs
new file mode 100644
index 000000000..5611a831c
--- /dev/null
+++ b/crypto/src/util/encoders/UrlBase64Encoder.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+	/**
+	* Convert binary data to and from UrlBase64 encoding.  This is identical to
+	* Base64 encoding, except that the padding character is "." and the other 
+	* non-alphanumeric characters are "-" and "_" instead of "+" and "/".
+	* <p>
+	* The purpose of UrlBase64 encoding is to provide a compact encoding of binary
+	* data that is safe for use as an URL parameter. Base64 encoding does not
+	* produce encoded values that are safe for use in URLs, since "/" can be 
+	* interpreted as a path delimiter; "+" is the encoded form of a space; and
+	* "=" is used to separate a name from the corresponding value in an URL 
+	* parameter.
+	* </p>
+	*/
+	public class UrlBase64Encoder
+		: Base64Encoder
+	{
+		public UrlBase64Encoder()
+		{
+			encodingTable[encodingTable.Length - 2] = (byte) '-';
+			encodingTable[encodingTable.Length - 1] = (byte) '_';
+			padding = (byte) '.';
+			// we must re-create the decoding table with the new encoded values.
+			InitialiseDecodingTable();
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/util/io/BaseInputStream.cs b/crypto/src/util/io/BaseInputStream.cs
index 08eedb160..3ff4a1957 100644
--- a/crypto/src/util/io/BaseInputStream.cs
+++ b/crypto/src/util/io/BaseInputStream.cs
@@ -11,15 +11,8 @@ namespace Org.BouncyCastle.Utilities.IO
 		public sealed override bool CanRead { get { return !closed; } }
         public sealed override bool CanSeek { get { return false; } }
         public sealed override bool CanWrite { get { return false; } }
-
-        protected override void Dispose(bool disposing)
-        {
-            base.Dispose(disposing);
-
-            closed = true;
-        }
-
-        public sealed override void Flush() {}
+		public override void Close() { closed = true; }
+		public sealed override void Flush() {}
         public sealed override long Length { get { throw new NotSupportedException(); } }
         public sealed override long Position
         {
diff --git a/crypto/src/util/io/BaseOutputStream.cs b/crypto/src/util/io/BaseOutputStream.cs
index 77233f68c..6e6c6d346 100644
--- a/crypto/src/util/io/BaseOutputStream.cs
+++ b/crypto/src/util/io/BaseOutputStream.cs
@@ -11,14 +11,7 @@ namespace Org.BouncyCastle.Utilities.IO
 		public sealed override bool CanRead { get { return false; } }
         public sealed override bool CanSeek { get { return false; } }
         public sealed override bool CanWrite { get { return !closed; } }
-		
-        protected override void Dispose(bool disposing)
-        {
-            base.Dispose(disposing);
-
-            closed = true;
-        }
-        
+		public override void Close() { closed = true; }
         public override void Flush() {}
         public sealed override long Length { get { throw new NotSupportedException(); } }
         public sealed override long Position
diff --git a/crypto/src/util/io/NullOutputStream.cs b/crypto/src/util/io/NullOutputStream.cs
new file mode 100644
index 000000000..13877fa13
--- /dev/null
+++ b/crypto/src/util/io/NullOutputStream.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+	internal class NullOutputStream
+		: BaseOutputStream
+	{
+		public override void WriteByte(byte b)
+		{
+			// do nothing
+		}
+
+		public override void Write(byte[] buffer, int offset, int count)
+		{
+			// do nothing
+		}
+	}
+}
diff --git a/crypto/src/util/io/PushbackStream.cs b/crypto/src/util/io/PushbackStream.cs
new file mode 100644
index 000000000..954694259
--- /dev/null
+++ b/crypto/src/util/io/PushbackStream.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+	public class PushbackStream
+		: FilterStream
+	{
+		private int buf = -1;
+
+		public PushbackStream(
+			Stream s)
+			: base(s)
+		{
+		}
+
+		public override int ReadByte()
+		{
+			if (buf != -1)
+			{
+				int tmp = buf;
+				buf = -1;
+				return tmp;
+			}
+
+			return base.ReadByte();
+		}
+
+		public override int Read(byte[] buffer, int offset, int count)
+		{
+			if (buf != -1 && count > 0)
+			{
+				// TODO Can this case be made more efficient?
+				buffer[offset] = (byte) buf;
+				buf = -1;
+				return 1;
+			}
+
+			return base.Read(buffer, offset, count);
+		}
+
+		public virtual void Unread(int b)
+		{
+			if (buf != -1)
+				throw new InvalidOperationException("Can only push back one byte");
+
+			buf = b & 0xFF;
+		}
+	}
+}
diff --git a/crypto/src/util/io/StreamOverflowException.cs b/crypto/src/util/io/StreamOverflowException.cs
index a8e7432fa..d8fcb558c 100644
--- a/crypto/src/util/io/StreamOverflowException.cs
+++ b/crypto/src/util/io/StreamOverflowException.cs
@@ -3,7 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.Utilities.IO
 {
-	public class StreamOverflowException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class StreamOverflowException
 		: IOException
 	{
 		public StreamOverflowException()
diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs
new file mode 100644
index 000000000..ee95d3b01
--- /dev/null
+++ b/crypto/src/util/io/Streams.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+	public sealed class Streams
+	{
+		private const int BufferSize = 512;
+
+		private Streams()
+		{
+		}
+
+		public static void Drain(Stream inStr)
+		{
+			byte[] bs = new byte[BufferSize];
+			while (inStr.Read(bs, 0, bs.Length) > 0)
+			{
+			}
+		}
+
+		public static byte[] ReadAll(Stream inStr)
+		{
+			MemoryStream buf = new MemoryStream();
+			PipeAll(inStr, buf);
+			return buf.ToArray();
+		}
+
+		public static byte[] ReadAllLimited(Stream inStr, int limit)
+		{
+			MemoryStream buf = new MemoryStream();
+			PipeAllLimited(inStr, limit, buf);
+			return buf.ToArray();
+		}
+
+		public static int ReadFully(Stream inStr, byte[] buf)
+		{
+			return ReadFully(inStr, buf, 0, buf.Length);
+		}
+
+		public static int ReadFully(Stream inStr, byte[] buf, int off, int len)
+		{
+			int totalRead = 0;
+			while (totalRead < len)
+			{
+				int numRead = inStr.Read(buf, off + totalRead, len - totalRead);
+				if (numRead < 1)
+					break;
+				totalRead += numRead;
+			}
+			return totalRead;
+		}
+
+		public static void PipeAll(Stream inStr, Stream outStr)
+		{
+			byte[] bs = new byte[BufferSize];
+			int numRead;
+			while ((numRead = inStr.Read(bs, 0, bs.Length)) > 0)
+			{
+				outStr.Write(bs, 0, numRead);
+			}
+		}
+
+		/// <summary>
+		/// Pipe all bytes from <c>inStr</c> to <c>outStr</c>, throwing <c>StreamFlowException</c> if greater
+		/// than <c>limit</c> bytes in <c>inStr</c>.
+		/// </summary>
+		/// <param name="inStr">
+		/// A <see cref="Stream"/>
+		/// </param>
+		/// <param name="limit">
+		/// A <see cref="System.Int64"/>
+		/// </param>
+		/// <param name="outStr">
+		/// A <see cref="Stream"/>
+		/// </param>
+		/// <returns>The number of bytes actually transferred, if not greater than <c>limit</c></returns>
+		/// <exception cref="IOException"></exception>
+		public static long PipeAllLimited(Stream inStr, long limit, Stream outStr)
+		{
+			byte[] bs = new byte[BufferSize];
+			long total = 0;
+			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/crypto/src/util/io/TeeInputStream.cs b/crypto/src/util/io/TeeInputStream.cs
index fed9823f0..373df4502 100644
--- a/crypto/src/util/io/TeeInputStream.cs
+++ b/crypto/src/util/io/TeeInputStream.cs
@@ -18,14 +18,11 @@ namespace Org.BouncyCastle.Utilities.IO
 			this.tee = tee;
 		}
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                input.Dispose();
-                tee.Dispose();
-            }
-        }
+		public override void Close()
+		{
+			input.Close();
+			tee.Close();
+		}
 
 		public override int Read(byte[] buf, int off, int len)
 		{
diff --git a/crypto/src/util/io/TeeOutputStream.cs b/crypto/src/util/io/TeeOutputStream.cs
index 965ef23c8..fe3a7586a 100644
--- a/crypto/src/util/io/TeeOutputStream.cs
+++ b/crypto/src/util/io/TeeOutputStream.cs
@@ -18,14 +18,11 @@ namespace Org.BouncyCastle.Utilities.IO
 			this.tee = tee;
 		}
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                output.Dispose();
-                tee.Dispose();
-            }
-        }
+		public override void Close()
+		{
+			output.Close();
+			tee.Close();
+		}
 
 		public override void Write(byte[] buffer, int offset, int count)
 		{
diff --git a/crypto/src/util/io/pem/PemGenerationException.cs b/crypto/src/util/io/pem/PemGenerationException.cs
index 22e83ac2d..b8edc622b 100644
--- a/crypto/src/util/io/pem/PemGenerationException.cs
+++ b/crypto/src/util/io/pem/PemGenerationException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.Utilities.IO.Pem
 {
-	public class PemGenerationException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class PemGenerationException
 		: Exception
 	{
 		public PemGenerationException()
diff --git a/crypto/src/util/io/pem/PemHeader.cs b/crypto/src/util/io/pem/PemHeader.cs
new file mode 100644
index 000000000..72da8a4f7
--- /dev/null
+++ b/crypto/src/util/io/pem/PemHeader.cs
@@ -0,0 +1,55 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+	public class PemHeader
+	{
+		private string name;
+		private string val;
+
+		public PemHeader(string name, string val)
+		{
+			this.name = name;
+			this.val = val;
+		}
+
+		public virtual string Name
+		{
+			get { return name; }
+		}
+
+		public virtual string Value
+		{
+			get { return val; }
+		}
+
+		public override int GetHashCode()
+		{
+			return GetHashCode(this.name) + 31 * GetHashCode(this.val);
+		}
+
+		public override bool Equals(object obj)
+		{
+			if (obj == this)
+				return true;
+
+			if (!(obj is PemHeader))
+				return false;
+
+			PemHeader other = (PemHeader)obj;
+
+			return Platform.Equals(this.name, other.name)
+				&& Platform.Equals(this.val, other.val);
+		}
+
+		private int GetHashCode(string s)
+		{
+			if (s == null)
+			{
+				return 1;
+			}
+
+			return s.GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/util/io/pem/PemObject.cs b/crypto/src/util/io/pem/PemObject.cs
new file mode 100644
index 000000000..41212f997
--- /dev/null
+++ b/crypto/src/util/io/pem/PemObject.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+	public class PemObject
+		: PemObjectGenerator
+	{
+		private string		type;
+		private IList		headers;
+		private byte[]		content;
+
+		public PemObject(string type, byte[] content)
+			: this(type, Platform.CreateArrayList(), content)
+		{
+		}
+
+		public PemObject(String type, IList headers, byte[] content)
+		{
+			this.type = type;
+            this.headers = Platform.CreateArrayList(headers);
+			this.content = content;
+		}
+
+		public string Type
+		{
+			get { return type; }
+		}
+
+		public IList Headers
+		{
+			get { return headers; }
+		}
+
+		public byte[] Content
+		{
+			get { return content; }
+		}
+
+		public PemObject Generate()
+		{
+			return this;
+		}
+	}
+}
diff --git a/crypto/src/util/io/pem/PemObjectGenerator.cs b/crypto/src/util/io/pem/PemObjectGenerator.cs
new file mode 100644
index 000000000..6f9bfc191
--- /dev/null
+++ b/crypto/src/util/io/pem/PemObjectGenerator.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+	public interface PemObjectGenerator
+	{
+		/// <returns>
+		/// A <see cref="PemObject"/>
+		/// </returns>
+		/// <exception cref="PemGenerationException"></exception>
+		PemObject Generate();
+	}
+}
diff --git a/crypto/src/util/io/pem/PemObjectParser.cs b/crypto/src/util/io/pem/PemObjectParser.cs
new file mode 100644
index 000000000..91d26dc3a
--- /dev/null
+++ b/crypto/src/util/io/pem/PemObjectParser.cs
@@ -0,0 +1,17 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+	public interface PemObjectParser
+	{
+		/// <param name="obj">
+		/// A <see cref="PemObject"/>
+		/// </param>
+		/// <returns>
+		/// A <see cref="System.Object"/>
+		/// </returns>
+		/// <exception cref="IOException"></exception>
+		object ParseObject(PemObject obj);
+	}
+}
diff --git a/crypto/src/util/io/pem/PemReader.cs b/crypto/src/util/io/pem/PemReader.cs
new file mode 100644
index 000000000..b3284705d
--- /dev/null
+++ b/crypto/src/util/io/pem/PemReader.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+	public class PemReader
+	{
+		private const string BeginString = "-----BEGIN ";
+		private const string EndString = "-----END ";
+
+		private readonly TextReader reader;
+
+		public PemReader(TextReader reader)
+		{
+			if (reader == null)
+				throw new ArgumentNullException("reader");
+
+			this.reader = reader;
+		}
+
+		public TextReader Reader
+		{
+			get { return reader; }
+		}
+
+		/// <returns>
+		/// A <see cref="PemObject"/>
+		/// </returns>
+		/// <exception cref="IOException"></exception>
+		public PemObject ReadPemObject()
+		{
+			string line = reader.ReadLine();
+
+			if (line != null && line.StartsWith(BeginString))
+			{
+				line = line.Substring(BeginString.Length);
+				int index = line.IndexOf('-');
+				string type = line.Substring(0, index);
+
+				if (index > 0)
+					return LoadObject(type);
+			}
+
+			return null;
+		}
+
+		private PemObject LoadObject(string type)
+		{
+			string endMarker = EndString + type;
+			IList headers = Platform.CreateArrayList();
+			StringBuilder buf = new StringBuilder();
+
+			string line;
+			while ((line = reader.ReadLine()) != null
+				&& line.IndexOf(endMarker) == -1)
+			{
+				int colonPos = line.IndexOf(':');
+
+				if (colonPos == -1)
+				{
+					buf.Append(line.Trim());
+				}
+				else
+				{
+					// Process field
+					string fieldName = line.Substring(0, colonPos).Trim();
+
+					if (fieldName.StartsWith("X-"))
+						fieldName = fieldName.Substring(2);
+
+					string fieldValue = line.Substring(colonPos + 1).Trim();
+
+					headers.Add(new PemHeader(fieldName, fieldValue));
+				}
+			}
+
+			if (line == null)
+			{
+				throw new IOException(endMarker + " not found");
+			}
+
+			if (buf.Length % 4 != 0)
+			{
+				throw new IOException("base64 data appears to be truncated");
+			}
+
+			return new PemObject(type, headers, Base64.Decode(buf.ToString()));
+		}
+	}
+}
diff --git a/crypto/src/util/io/pem/PemWriter.cs b/crypto/src/util/io/pem/PemWriter.cs
new file mode 100644
index 000000000..e85b31543
--- /dev/null
+++ b/crypto/src/util/io/pem/PemWriter.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+	/**
+	* A generic PEM writer, based on RFC 1421
+	*/
+	public class PemWriter
+	{
+		private const int LineLength = 64;
+
+		private readonly TextWriter	writer;
+		private readonly int		nlLength;
+		private char[]				buf = new char[LineLength];
+		
+		/**
+		 * Base constructor.
+		 *
+		 * @param out output stream to use.
+		 */
+		public PemWriter(TextWriter writer)
+		{
+			if (writer == null)
+				throw new ArgumentNullException("writer");
+
+			this.writer = writer;
+			this.nlLength = Platform.NewLine.Length;
+		}
+
+		public TextWriter Writer
+		{
+			get { return writer; }
+		}
+
+		/**
+		 * 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.Type.Length + 10 + nlLength)) + 6 + 4;
+
+			if (obj.Headers.Count > 0)
+			{
+				foreach (PemHeader header in obj.Headers)
+				{
+					size += header.Name.Length + ": ".Length + header.Value.Length + nlLength;
+				}
+
+				size += nlLength;
+			}
+
+			// base64 encoding
+			int dataLen = ((obj.Content.Length + 2) / 3) * 4;
+
+			size += dataLen + (((dataLen + LineLength - 1) / LineLength) * nlLength);
+
+			return size;
+		}
+
+		public void WriteObject(PemObjectGenerator objGen)
+		{
+			PemObject obj = objGen.Generate();
+
+			WritePreEncapsulationBoundary(obj.Type);
+
+			if (obj.Headers.Count > 0)
+			{
+				foreach (PemHeader header in obj.Headers)
+				{
+					writer.Write(header.Name);
+					writer.Write(": ");
+					writer.WriteLine(header.Value);
+				}
+
+				writer.WriteLine();
+			}
+
+			WriteEncoded(obj.Content);
+			WritePostEncapsulationBoundary(obj.Type);
+		}
+
+		private void WriteEncoded(byte[] bytes)
+		{
+			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++;
+				}
+				writer.WriteLine(buf, 0, index);
+			}
+		}
+
+		private void WritePreEncapsulationBoundary(string type)
+		{
+			writer.WriteLine("-----BEGIN " + type + "-----");
+		}
+
+		private void WritePostEncapsulationBoundary(string type)
+		{
+			writer.WriteLine("-----END " + type + "-----");
+		}
+	}
+}
diff --git a/crypto/src/util/net/IPAddress.cs b/crypto/src/util/net/IPAddress.cs
new file mode 100644
index 000000000..2a30a15f0
--- /dev/null
+++ b/crypto/src/util/net/IPAddress.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Utilities.Net
+{
+	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 bool 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 bool 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 bool IsValidIPv4(
+			string address)
+		{
+			try
+			{
+				return unsafeIsValidIPv4(address);
+			}
+			catch (FormatException) {}
+			catch (OverflowException) {}
+			return false;
+		}
+
+		private static bool unsafeIsValidIPv4(
+			string address)
+		{
+			if (address.Length == 0)
+				return false;
+
+			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;
+
+				string octetStr = temp.Substring(start, pos - start);
+				int octet = Int32.Parse(octetStr);
+
+				if (octet < 0 || octet > 255)
+					return false;
+
+				start = pos + 1;
+				octets++;
+			}
+
+			return octets == 4;
+		}
+
+		public static bool 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 bool 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 bool IsMaskValue(
+			string	component,
+			int		size)
+		{
+			int val = Int32.Parse(component);
+			try
+			{
+				return val >= 0 && val <= size;
+			}
+			catch (FormatException) {}
+			catch (OverflowException) {}
+			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 bool IsValidIPv6(
+			string address)
+		{
+			try
+			{
+				return unsafeIsValidIPv6(address);
+			}
+			catch (FormatException) {}
+			catch (OverflowException) {}
+			return false;
+		}
+
+		private static bool unsafeIsValidIPv6(
+			string address)
+		{
+			if (address.Length == 0)
+			{
+				return false;
+			}
+
+			int octets = 0;
+
+			string temp = address + ":";
+			bool 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 - start);
+
+					if (pos == (temp.Length - 1) && value.IndexOf('.') > 0)
+					{
+						if (!IsValidIPv4(value))
+						{
+							return false;
+						}
+
+						octets++; // add an extra one as address covers 2 words.
+					}
+					else
+					{
+						string octetStr = temp.Substring(start, pos - start);
+						int octet = Int32.Parse(octetStr, NumberStyles.AllowHexSpecifier);
+
+						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/crypto/src/util/zlib/Adler32.cs b/crypto/src/util/zlib/Adler32.cs
new file mode 100644
index 000000000..c38258f2a
--- /dev/null
+++ b/crypto/src/util/zlib/Adler32.cs
@@ -0,0 +1,88 @@
+using System;
+/*
+ * $Id: Adler32.cs,v 1.1 2006-07-31 13:59:25 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    internal sealed class Adler32{
+
+        // largest prime smaller than 65536
+        private const int BASE=65521; 
+        // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
+        private const int NMAX=5552;
+
+        internal long adler32(long adler, byte[] buf, int index, int len){
+            if(buf == null){ return 1L; }
+
+            long s1=adler&0xffff;
+            long s2=(adler>>16)&0xffff;
+            int k;
+
+            while(len > 0) {
+                k=len<NMAX?len:NMAX;
+                len-=k;
+                while(k>=16){
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    s1+=buf[index++]&0xff; s2+=s1;
+                    k-=16;
+                }
+                if(k!=0){
+                    do{
+                        s1+=buf[index++]&0xff; s2+=s1;
+                    }
+                    while(--k!=0);
+                }
+                s1%=BASE;
+                s2%=BASE;
+            }
+            return (s2<<16)|s1;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/Deflate.cs b/crypto/src/util/zlib/Deflate.cs
new file mode 100644
index 000000000..ca0430939
--- /dev/null
+++ b/crypto/src/util/zlib/Deflate.cs
@@ -0,0 +1,1640 @@
+using System;
+/*
+ * $Id: Deflate.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    public sealed class Deflate{
+
+        private const int MAX_MEM_LEVEL=9;
+
+        private const int Z_DEFAULT_COMPRESSION=-1;
+
+        private const int MAX_WBITS=15;            // 32K LZ77 window
+        private const int DEF_MEM_LEVEL=8;
+
+        internal class Config{
+            internal int good_length; // reduce lazy search above this match length
+            internal int max_lazy;    // do not perform lazy search above this match length
+            internal int nice_length; // quit search above this match length
+            internal int max_chain;
+            internal int func;
+            internal Config(int good_length, int max_lazy, 
+                int nice_length, int max_chain, int func){
+                this.good_length=good_length;
+                this.max_lazy=max_lazy;
+                this.nice_length=nice_length;
+                this.max_chain=max_chain;
+                this.func=func;
+            }
+        }
+  
+        private const int STORED=0;
+        private const int FAST=1;
+        private const int SLOW=2;
+        private static readonly Config[] config_table;
+
+		static Deflate(){
+            config_table=new Config[10];
+            //                         good  lazy  nice  chain
+            config_table[0]=new Config(0,    0,    0,    0, STORED);
+            config_table[1]=new Config(4,    4,    8,    4, FAST);
+            config_table[2]=new Config(4,    5,   16,    8, FAST);
+            config_table[3]=new Config(4,    6,   32,   32, FAST);
+
+            config_table[4]=new Config(4,    4,   16,   16, SLOW);
+            config_table[5]=new Config(8,   16,   32,   32, SLOW);
+            config_table[6]=new Config(8,   16,  128,  128, SLOW);
+            config_table[7]=new Config(8,   32,  128,  256, SLOW);
+            config_table[8]=new Config(32, 128,  258, 1024, SLOW);
+            config_table[9]=new Config(32, 258,  258, 4096, SLOW);
+        }
+
+        private static readonly String[] z_errmsg = {
+                                               "need dictionary",     // Z_NEED_DICT       2
+                                               "stream end",          // Z_STREAM_END      1
+                                               "",                    // Z_OK              0
+                                               "file error",          // Z_ERRNO         (-1)
+                                               "stream error",        // Z_STREAM_ERROR  (-2)
+                                               "data error",          // Z_DATA_ERROR    (-3)
+                                               "insufficient memory", // Z_MEM_ERROR     (-4)
+                                               "buffer error",        // Z_BUF_ERROR     (-5)
+                                               "incompatible version",// Z_VERSION_ERROR (-6)
+                                               ""
+                                           };
+
+        // block not completed, need more input or more output
+        private const int NeedMore=0; 
+
+        // block flush performed
+        private const int BlockDone=1; 
+
+        // finish started, need only more output at next deflate
+        private const int FinishStarted=2;
+
+        // finish done, accept no more input or output
+        private const int FinishDone=3;
+
+        // preset dictionary flag in zlib header
+        private const int PRESET_DICT=0x20;
+
+        private const int Z_FILTERED=1;
+        private const int Z_HUFFMAN_ONLY=2;
+        private const int Z_DEFAULT_STRATEGY=0;
+
+        private const int Z_NO_FLUSH=0;
+        private const int Z_PARTIAL_FLUSH=1;
+        private const int Z_SYNC_FLUSH=2;
+        private const int Z_FULL_FLUSH=3;
+        private const int Z_FINISH=4;
+
+        private const int Z_OK=0;
+        private const int Z_STREAM_END=1;
+        private const int Z_NEED_DICT=2;
+        private const int Z_ERRNO=-1;
+        private const int Z_STREAM_ERROR=-2;
+        private const int Z_DATA_ERROR=-3;
+        private const int Z_MEM_ERROR=-4;
+        private const int Z_BUF_ERROR=-5;
+        private const int Z_VERSION_ERROR=-6;
+
+        private const int INIT_STATE=42;
+        private const int BUSY_STATE=113;
+        private const int FINISH_STATE=666;
+
+        // The deflate compression method
+        private const int Z_DEFLATED=8;
+
+        private const int STORED_BLOCK=0;
+        private const int STATIC_TREES=1;
+        private const int DYN_TREES=2;
+
+        // The three kinds of block type
+        private const int Z_BINARY=0;
+        private const int Z_ASCII=1;
+        private const int Z_UNKNOWN=2;
+
+        private const int Buf_size=8*2;
+
+        // repeat previous bit length 3-6 times (2 bits of repeat count)
+        private const int REP_3_6=16; 
+
+        // repeat a zero length 3-10 times  (3 bits of repeat count)
+        private const int REPZ_3_10=17; 
+
+        // repeat a zero length 11-138 times  (7 bits of repeat count)
+        private const int REPZ_11_138=18; 
+
+        private const int MIN_MATCH=3;
+        private const int MAX_MATCH=258;
+        private const int MIN_LOOKAHEAD=(MAX_MATCH+MIN_MATCH+1);
+
+        private const int MAX_BITS=15;
+        private const int D_CODES=30;
+        private const int BL_CODES=19;
+        private const int LENGTH_CODES=29;
+        private const int LITERALS=256;
+        private const int L_CODES=(LITERALS+1+LENGTH_CODES);
+        private const int HEAP_SIZE=(2*L_CODES+1);
+
+        private const int END_BLOCK=256;
+
+        internal ZStream strm;         // pointer back to this zlib stream
+        internal int status;           // as the name implies
+        internal byte[] pending_buf;   // output still pending
+        internal int pending_buf_size; // size of pending_buf
+        internal int pending_out;      // next pending byte to output to the stream
+        internal int pending;          // nb of bytes in the pending buffer
+        internal int noheader;         // suppress zlib header and adler32
+        internal byte data_type;       // UNKNOWN, BINARY or ASCII
+        internal byte method;          // STORED (for zip only) or DEFLATED
+        internal int last_flush;       // value of flush param for previous deflate call
+
+        internal int w_size;           // LZ77 window size (32K by default)
+        internal int w_bits;           // log2(w_size)  (8..16)
+        internal int w_mask;           // w_size - 1
+
+        internal byte[] window;
+        // Sliding window. Input bytes are read into the second half of the window,
+        // and move to the first half later to keep a dictionary of at least wSize
+        // bytes. With this organization, matches are limited to a distance of
+        // wSize-MAX_MATCH bytes, but this ensures that IO is always
+        // performed with a length multiple of the block size. Also, it limits
+        // the window size to 64K, which is quite useful on MSDOS.
+        // To do: use the user input buffer as sliding window.
+
+        internal int window_size;
+        // Actual size of window: 2*wSize, except when the user input buffer
+        // is directly used as sliding window.
+
+        internal short[] prev;
+        // Link to older string with same hash index. To limit the size of this
+        // array to 64K, this link is maintained only for the last 32K strings.
+        // An index in this array is thus a window index modulo 32K.
+
+        internal short[] head; // Heads of the hash chains or NIL.
+
+        internal int ins_h;          // hash index of string to be inserted
+        internal int hash_size;      // number of elements in hash table
+        internal int hash_bits;      // log2(hash_size)
+        internal int hash_mask;      // hash_size-1
+
+        // Number of bits by which ins_h must be shifted at each input
+        // step. It must be such that after MIN_MATCH steps, the oldest
+        // byte no longer takes part in the hash key, that is:
+        // hash_shift * MIN_MATCH >= hash_bits
+        internal int hash_shift;
+
+        // Window position at the beginning of the current output block. Gets
+        // negative when the window is moved backwards.
+
+        internal int block_start;
+
+        internal int match_length;           // length of best match
+        internal int prev_match;             // previous match
+        internal int match_available;        // set if previous match exists
+        internal int strstart;               // start of string to insert
+        internal int match_start;            // start of matching string
+        internal int lookahead;              // number of valid bytes ahead in window
+
+        // Length of the best match at previous step. Matches not greater than this
+        // are discarded. This is used in the lazy match evaluation.
+        internal int prev_length;
+
+        // To speed up deflation, hash chains are never searched beyond this
+        // length.  A higher limit improves compression ratio but degrades the speed.
+        internal int max_chain_length;
+
+        // Attempt to find a better match only when the current match is strictly
+        // smaller than this value. This mechanism is used only for compression
+        // levels >= 4.
+        internal int max_lazy_match;
+
+        // Insert new strings in the hash table only if the match length is not
+        // greater than this length. This saves time but degrades compression.
+        // max_insert_length is used only for compression levels <= 3.
+
+        internal int level;    // compression level (1..9)
+        internal int strategy; // favor or force Huffman coding
+
+        // Use a faster search when the previous match is longer than this
+        internal int good_match;
+
+        // Stop searching when current match exceeds this
+        internal int nice_match;
+
+        internal short[] dyn_ltree;       // literal and length tree
+        internal short[] dyn_dtree;       // distance tree
+        internal short[] bl_tree;         // Huffman tree for bit lengths
+
+        internal Tree l_desc=new Tree();  // desc for literal tree
+        internal Tree d_desc=new Tree();  // desc for distance tree
+        internal Tree bl_desc=new Tree(); // desc for bit length tree
+
+        // number of codes at each bit length for an optimal tree
+        internal short[] bl_count=new short[MAX_BITS+1];
+
+        // heap used to build the Huffman trees
+        internal int[] heap=new int[2*L_CODES+1];
+
+        internal int heap_len;               // number of elements in the heap
+        internal int heap_max;               // element of largest frequency
+        // The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+        // The same heap array is used to build all trees.
+
+        // Depth of each subtree used as tie breaker for trees of equal frequency
+        internal byte[] depth=new byte[2*L_CODES+1];
+
+        internal int l_buf;               // index for literals or lengths */
+
+        // Size of match buffer for literals/lengths.  There are 4 reasons for
+        // limiting lit_bufsize to 64K:
+        //   - frequencies can be kept in 16 bit counters
+        //   - if compression is not successful for the first block, all input
+        //     data is still in the window so we can still emit a stored block even
+        //     when input comes from standard input.  (This can also be done for
+        //     all blocks if lit_bufsize is not greater than 32K.)
+        //   - if compression is not successful for a file smaller than 64K, we can
+        //     even emit a stored file instead of a stored block (saving 5 bytes).
+        //     This is applicable only for zip (not gzip or zlib).
+        //   - creating new Huffman trees less frequently may not provide fast
+        //     adaptation to changes in the input data statistics. (Take for
+        //     example a binary file with poorly compressible code followed by
+        //     a highly compressible string table.) Smaller buffer sizes give
+        //     fast adaptation but have of course the overhead of transmitting
+        //     trees more frequently.
+        //   - I can't count above 4
+        internal int lit_bufsize;
+
+        internal int last_lit;      // running index in l_buf
+
+        // Buffer for distances. To simplify the code, d_buf and l_buf have
+        // the same number of elements. To use different lengths, an extra flag
+        // array would be necessary.
+
+        internal int d_buf;         // index of pendig_buf
+
+        internal int opt_len;        // bit length of current block with optimal trees
+        internal int static_len;     // bit length of current block with static trees
+        internal int matches;        // number of string matches in current block
+        internal int last_eob_len;   // bit length of EOB code for last block
+
+        // Output buffer. bits are inserted starting at the bottom (least
+        // significant bits).
+        internal uint bi_buf;
+
+        // Number of valid bits in bi_buf.  All bits above the last valid bit
+        // are always zero.
+        internal int bi_valid;
+
+        internal Deflate(){
+            dyn_ltree=new short[HEAP_SIZE*2];
+            dyn_dtree=new short[(2*D_CODES+1)*2]; // distance tree
+            bl_tree=new short[(2*BL_CODES+1)*2];  // Huffman tree for bit lengths
+        }
+
+        internal void lm_init() {
+            window_size=2*w_size;
+
+            head[hash_size-1]=0;
+            for(int i=0; i<hash_size-1; i++){
+                head[i]=0;
+            }
+
+            // Set the default configuration parameters:
+            max_lazy_match   = Deflate.config_table[level].max_lazy;
+            good_match       = Deflate.config_table[level].good_length;
+            nice_match       = Deflate.config_table[level].nice_length;
+            max_chain_length = Deflate.config_table[level].max_chain;
+
+            strstart = 0;
+            block_start = 0;
+            lookahead = 0;
+            match_length = prev_length = MIN_MATCH-1;
+            match_available = 0;
+            ins_h = 0;
+        }
+
+        // Initialize the tree data structures for a new zlib stream.
+        internal void tr_init(){
+
+            l_desc.dyn_tree = dyn_ltree;
+            l_desc.stat_desc = StaticTree.static_l_desc;
+
+            d_desc.dyn_tree = dyn_dtree;
+            d_desc.stat_desc = StaticTree.static_d_desc;
+
+            bl_desc.dyn_tree = bl_tree;
+            bl_desc.stat_desc = StaticTree.static_bl_desc;
+
+            bi_buf = 0;
+            bi_valid = 0;
+            last_eob_len = 8; // enough lookahead for inflate
+
+            // Initialize the first block of the first file:
+            init_block();
+        }
+
+        internal void init_block(){
+            // Initialize the trees.
+            for(int i = 0; i < L_CODES; i++) dyn_ltree[i*2] = 0;
+            for(int i= 0; i < D_CODES; i++) dyn_dtree[i*2] = 0;
+            for(int i= 0; i < BL_CODES; i++) bl_tree[i*2] = 0;
+
+            dyn_ltree[END_BLOCK*2] = 1;
+            opt_len = static_len = 0;
+            last_lit = matches = 0;
+        }
+
+        // Restore the heap property by moving down the tree starting at node k,
+        // exchanging a node with the smallest of its two sons if necessary, stopping
+        // when the heap property is re-established (each father smaller than its
+        // two sons).
+        internal void pqdownheap(short[] tree,  // the tree to restore
+            int k          // node to move down
+            ){
+            int v = heap[k];
+            int j = k << 1;  // left son of k
+            while (j <= heap_len) {
+                // Set j to the smallest of the two sons:
+                if (j < heap_len &&
+                    smaller(tree, heap[j+1], heap[j], depth)){
+                    j++;
+                }
+                // Exit if v is smaller than both sons
+                if(smaller(tree, v, heap[j], depth)) break;
+
+                // Exchange v with the smallest son
+                heap[k]=heap[j];  k = j;
+                // And continue down the tree, setting j to the left son of k
+                j <<= 1;
+            }
+            heap[k] = v;
+        }
+
+        internal static bool smaller(short[] tree, int n, int m, byte[] depth){
+            short tn2=tree[n*2];
+            short tm2=tree[m*2];
+            return (tn2<tm2 ||
+                (tn2==tm2 && depth[n] <= depth[m]));
+        }
+
+        // Scan a literal or distance tree to determine the frequencies of the codes
+        // in the bit length tree.
+        internal void scan_tree (short[] tree,// the tree to be scanned
+            int max_code // and its largest code of non zero frequency
+            ){
+            int n;                     // iterates over all tree elements
+            int prevlen = -1;          // last emitted length
+            int curlen;                // length of current code
+            int nextlen = tree[0*2+1]; // length of next code
+            int count = 0;             // repeat count of the current code
+            int max_count = 7;         // max repeat count
+            int min_count = 4;         // min repeat count
+
+            if (nextlen == 0){ max_count = 138; min_count = 3; }
+            tree[(max_code+1)*2+1] = -1; // guard
+
+            for(n = 0; n <= max_code; n++) {
+                curlen = nextlen; nextlen = tree[(n+1)*2+1];
+                if(++count < max_count && curlen == nextlen) {
+                    continue;
+                }
+                else if(count < min_count) {
+                    bl_tree[curlen*2] += (short)count;
+                }
+                else if(curlen != 0) {
+                    if(curlen != prevlen) bl_tree[curlen*2]++;
+                    bl_tree[REP_3_6*2]++;
+                }
+                else if(count <= 10) {
+                    bl_tree[REPZ_3_10*2]++;
+                }
+                else{
+                    bl_tree[REPZ_11_138*2]++;
+                }
+                count = 0; prevlen = curlen;
+                if(nextlen == 0) {
+                    max_count = 138; min_count = 3;
+                }
+                else if(curlen == nextlen) {
+                    max_count = 6; min_count = 3;
+                }
+                else{
+                    max_count = 7; min_count = 4;
+                }
+            }
+        }
+
+        // Construct the Huffman tree for the bit lengths and return the index in
+        // bl_order of the last bit length code to send.
+        internal int build_bl_tree(){
+            int max_blindex;  // index of last bit length code of non zero freq
+
+            // Determine the bit length frequencies for literal and distance trees
+            scan_tree(dyn_ltree, l_desc.max_code);
+            scan_tree(dyn_dtree, d_desc.max_code);
+
+            // Build the bit length tree:
+            bl_desc.build_tree(this);
+            // opt_len now includes the length of the tree representations, except
+            // the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+
+            // Determine the number of bit length codes to send. The pkzip format
+            // requires that at least 4 bit length codes be sent. (appnote.txt says
+            // 3 but the actual value used is 4.)
+            for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+                if (bl_tree[Tree.bl_order[max_blindex]*2+1] != 0) break;
+            }
+            // Update opt_len to include the bit length tree and counts
+            opt_len += 3*(max_blindex+1) + 5+5+4;
+
+            return max_blindex;
+        }
+
+
+        // Send the header for a block using dynamic Huffman trees: the counts, the
+        // lengths of the bit length codes, the literal tree and the distance tree.
+        // IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+        internal void send_all_trees(int lcodes, int dcodes, int blcodes){
+            int rank;                    // index in bl_order
+
+            send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt
+            send_bits(dcodes-1,   5);
+            send_bits(blcodes-4,  4); // not -3 as stated in appnote.txt
+            for (rank = 0; rank < blcodes; rank++) {
+                send_bits(bl_tree[Tree.bl_order[rank]*2+1], 3);
+            }
+            send_tree(dyn_ltree, lcodes-1); // literal tree
+            send_tree(dyn_dtree, dcodes-1); // distance tree
+        }
+
+        // Send a literal or distance tree in compressed form, using the codes in
+        // bl_tree.
+        internal void send_tree (short[] tree,// the tree to be sent
+            int max_code // and its largest code of non zero frequency
+            ){
+            int n;                     // iterates over all tree elements
+            int prevlen = -1;          // last emitted length
+            int curlen;                // length of current code
+            int nextlen = tree[0*2+1]; // length of next code
+            int count = 0;             // repeat count of the current code
+            int max_count = 7;         // max repeat count
+            int min_count = 4;         // min repeat count
+
+            if (nextlen == 0){ max_count = 138; min_count = 3; }
+
+            for (n = 0; n <= max_code; n++) {
+                curlen = nextlen; nextlen = tree[(n+1)*2+1];
+                if(++count < max_count && curlen == nextlen) {
+                    continue;
+                }
+                else if(count < min_count) {
+                    do { send_code(curlen, bl_tree); } while (--count != 0);
+                }
+                else if(curlen != 0){
+                    if(curlen != prevlen){
+                        send_code(curlen, bl_tree); count--;
+                    }
+                    send_code(REP_3_6, bl_tree); 
+                    send_bits(count-3, 2);
+                }
+                else if(count <= 10){
+                    send_code(REPZ_3_10, bl_tree); 
+                    send_bits(count-3, 3);
+                }
+                else{
+                    send_code(REPZ_11_138, bl_tree);
+                    send_bits(count-11, 7);
+                }
+                count = 0; prevlen = curlen;
+                if(nextlen == 0){
+                    max_count = 138; min_count = 3;
+                }
+                else if(curlen == nextlen){
+                    max_count = 6; min_count = 3;
+                }
+                else{
+                    max_count = 7; min_count = 4;
+                }
+            }
+        }
+
+        // Output a byte on the stream.
+        // IN assertion: there is enough room in pending_buf.
+        internal void put_byte(byte[] p, int start, int len){
+            System.Array.Copy(p, start, pending_buf, pending, len);
+            pending+=len;
+        }
+
+        internal void put_byte(byte c){
+            pending_buf[pending++]=c;
+        }
+        internal void put_short(int w) {
+            pending_buf[pending++]=(byte)(w/*&0xff*/);
+            pending_buf[pending++]=(byte)(w>>8);
+        }
+        internal void putShortMSB(int b){
+            pending_buf[pending++]=(byte)(b>>8);
+            pending_buf[pending++]=(byte)(b/*&0xff*/);
+        }   
+
+        internal void send_code(int c, short[] tree){
+            int c2=c*2;
+            send_bits((tree[c2]&0xffff), (tree[c2+1]&0xffff));
+        }
+
+        internal void send_bits(int val, int length){
+            if (bi_valid > Buf_size - length) {
+                bi_buf |= (uint)(val << bi_valid);
+                pending_buf[pending++]=(byte)(bi_buf/*&0xff*/);
+                pending_buf[pending++]=(byte)(bi_buf>>8);
+                bi_buf = ((uint)val) >> (Buf_size - bi_valid);
+                bi_valid += length - Buf_size;
+            } else {
+                bi_buf |= (uint)(val << bi_valid);
+                bi_valid += length;
+            }
+//            int len = length;
+//            if (bi_valid > (int)Buf_size - len) {
+//                int val = value;
+//                //      bi_buf |= (val << bi_valid);
+//                bi_buf = (short)((ushort)bi_buf | (ushort)((val << bi_valid)&0xffff));
+//                put_short(bi_buf);
+//                bi_buf = (short)(((uint)val) >> (Buf_size - bi_valid));
+//                bi_valid += len - Buf_size;
+//            } else {
+//                //      bi_buf |= (value) << bi_valid;
+//                bi_buf = (short)((ushort)bi_buf | (ushort)(((value) << bi_valid)&0xffff));
+//                bi_valid += len;
+//            }
+        }
+
+        // Send one empty static block to give enough lookahead for inflate.
+        // This takes 10 bits, of which 7 may remain in the bit buffer.
+        // The current inflate code requires 9 bits of lookahead. If the
+        // last two codes for the previous block (real code plus EOB) were coded
+        // on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+        // the last real code. In this case we send two empty static blocks instead
+        // of one. (There are no problems if the previous block is stored or fixed.)
+        // To simplify the code, we assume the worst case of last real code encoded
+        // on one bit only.
+        internal void _tr_align(){
+            send_bits(STATIC_TREES<<1, 3);
+            send_code(END_BLOCK, StaticTree.static_ltree);
+
+            bi_flush();
+
+            // Of the 10 bits for the empty block, we have already sent
+            // (10 - bi_valid) bits. The lookahead for the last real code (before
+            // the EOB of the previous block) was thus at least one plus the length
+            // of the EOB plus what we have just sent of the empty static block.
+            if (1 + last_eob_len + 10 - bi_valid < 9) {
+                send_bits(STATIC_TREES<<1, 3);
+                send_code(END_BLOCK, StaticTree.static_ltree);
+                bi_flush();
+            }
+            last_eob_len = 7;
+        }
+
+
+        // Save the match info and tally the frequency counts. Return true if
+        // the current block must be flushed.
+        internal bool _tr_tally (int dist, // distance of matched string
+            int lc // match length-MIN_MATCH or unmatched char (if dist==0)
+            ){
+
+            pending_buf[d_buf+last_lit*2] = (byte)(dist>>8);
+            pending_buf[d_buf+last_lit*2+1] = (byte)dist;
+
+            pending_buf[l_buf+last_lit] = (byte)lc; last_lit++;
+
+            if (dist == 0) {
+                // lc is the unmatched char
+                dyn_ltree[lc*2]++;
+            } 
+            else {
+                matches++;
+                // Here, lc is the match length - MIN_MATCH
+                dist--;             // dist = match distance - 1
+                dyn_ltree[(Tree._length_code[lc]+LITERALS+1)*2]++;
+                dyn_dtree[Tree.d_code(dist)*2]++;
+            }
+
+            if ((last_lit & 0x1fff) == 0 && level > 2) {
+                // Compute an upper bound for the compressed length
+                int out_length = last_lit*8;
+                int in_length = strstart - block_start;
+                int dcode;
+                for (dcode = 0; dcode < D_CODES; dcode++) {
+                    out_length += (int)((int)dyn_dtree[dcode*2] *
+                        (5L+Tree.extra_dbits[dcode]));
+                }
+                out_length >>= 3;
+                if ((matches < (last_lit/2)) && out_length < in_length/2) return true;
+            }
+
+            return (last_lit == lit_bufsize-1);
+            // We avoid equality with lit_bufsize because of wraparound at 64K
+            // on 16 bit machines and because stored blocks are restricted to
+            // 64K-1 bytes.
+        }
+
+        // Send the block data compressed using the given Huffman trees
+        internal void compress_block(short[] ltree, short[] dtree){
+            int  dist;      // distance of matched string
+            int lc;         // match length or unmatched char (if dist == 0)
+            int lx = 0;     // running index in l_buf
+            int code;       // the code to send
+            int extra;      // number of extra bits to send
+
+            if (last_lit != 0){
+                do{
+                    dist=((pending_buf[d_buf+lx*2]<<8)&0xff00)|
+                        (pending_buf[d_buf+lx*2+1]&0xff);
+                    lc=(pending_buf[l_buf+lx])&0xff; lx++;
+
+                    if(dist == 0){
+                        send_code(lc, ltree); // send a literal byte
+                    } 
+                    else{
+                        // Here, lc is the match length - MIN_MATCH
+                        code = Tree._length_code[lc];
+
+                        send_code(code+LITERALS+1, ltree); // send the length code
+                        extra = Tree.extra_lbits[code];
+                        if(extra != 0){
+                            lc -= Tree.base_length[code];
+                            send_bits(lc, extra);       // send the extra length bits
+                        }
+                        dist--; // dist is now the match distance - 1
+                        code = Tree.d_code(dist);
+
+                        send_code(code, dtree);       // send the distance code
+                        extra = Tree.extra_dbits[code];
+                        if (extra != 0) {
+                            dist -= Tree.base_dist[code];
+                            send_bits(dist, extra);   // send the extra distance bits
+                        }
+                    } // literal or match pair ?
+
+                    // Check that the overlay between pending_buf and d_buf+l_buf is ok:
+                }
+                while (lx < last_lit);
+            }
+
+            send_code(END_BLOCK, ltree);
+            last_eob_len = ltree[END_BLOCK*2+1];
+        }
+
+        // Set the data type to ASCII or BINARY, using a crude approximation:
+        // binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+        // IN assertion: the fields freq of dyn_ltree are set and the total of all
+        // frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+        internal void set_data_type(){
+            int n = 0;
+            int  ascii_freq = 0;
+            int  bin_freq = 0;
+            while(n<7){ bin_freq += dyn_ltree[n*2]; n++;}
+            while(n<128){ ascii_freq += dyn_ltree[n*2]; n++;}
+            while(n<LITERALS){ bin_freq += dyn_ltree[n*2]; n++;}
+            data_type=(byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+        }
+
+        // Flush the bit buffer, keeping at most 7 bits in it.
+        internal void bi_flush(){
+            if (bi_valid == 16) {
+                pending_buf[pending++]=(byte)(bi_buf/*&0xff*/);
+                pending_buf[pending++]=(byte)(bi_buf>>8);
+                bi_buf=0;
+                bi_valid=0;
+            }
+            else if (bi_valid >= 8) {
+                pending_buf[pending++]=(byte)(bi_buf);
+                bi_buf>>=8;
+                bi_buf &= 0x00ff;
+                bi_valid-=8;
+            }
+        }
+
+        // Flush the bit buffer and align the output on a byte boundary
+        internal void bi_windup(){
+            if (bi_valid > 8) {
+                pending_buf[pending++]=(byte)(bi_buf);
+                pending_buf[pending++]=(byte)(bi_buf>>8);
+            } else if (bi_valid > 0) {
+                pending_buf[pending++]=(byte)(bi_buf);
+            }
+            bi_buf = 0;
+            bi_valid = 0;
+        }
+
+        // Copy a stored block, storing first the length and its
+        // one's complement if requested.
+        internal void copy_block(int buf,         // the input data
+            int len,         // its length
+            bool header   // true if block header must be written
+            ){
+            //int index=0;
+            bi_windup();      // align on byte boundary
+            last_eob_len = 8; // enough lookahead for inflate
+
+            if (header) {
+                put_short((short)len);   
+                put_short((short)~len);
+            }
+
+            //  while(len--!=0) {
+            //    put_byte(window[buf+index]);
+            //    index++;
+            //  }
+            put_byte(window, buf, len);
+        }
+
+        internal void flush_block_only(bool eof){
+            _tr_flush_block(block_start>=0 ? block_start : -1,
+                strstart-block_start,
+                eof);
+            block_start=strstart;
+            strm.flush_pending();
+        }
+
+        // Copy without compression as much as possible from the input stream, return
+        // the current block state.
+        // This function does not insert new strings in the dictionary since
+        // uncompressible data is probably not useful. This function is used
+        // only for the level=0 compression option.
+        // NOTE: this function should be optimized to avoid extra copying from
+        // window to pending_buf.
+        internal int deflate_stored(int flush){
+            // Stored blocks are limited to 0xffff bytes, pending_buf is limited
+            // to pending_buf_size, and each stored block has a 5 byte header:
+
+            int max_block_size = 0xffff;
+            int max_start;
+
+            if(max_block_size > pending_buf_size - 5) {
+                max_block_size = pending_buf_size - 5;
+            }
+
+            // Copy as much as possible from input to output:
+            while(true){
+                // Fill the window as much as possible:
+                if(lookahead<=1){
+                    fill_window();
+                    if(lookahead==0 && flush==Z_NO_FLUSH) return NeedMore;
+                    if(lookahead==0) break; // flush the current block
+                }
+
+                strstart+=lookahead;
+                lookahead=0;
+
+                // Emit a stored block if pending_buf will be full:
+                max_start=block_start+max_block_size;
+                if(strstart==0|| strstart>=max_start) {
+                    // strstart == 0 is possible when wraparound on 16-bit machine
+                    lookahead = (int)(strstart-max_start);
+                    strstart = (int)max_start;
+      
+                    flush_block_only(false);
+                    if(strm.avail_out==0) return NeedMore;
+
+                }
+
+                // Flush if we may have to slide, otherwise block_start may become
+                // negative and the data will be gone:
+                if(strstart-block_start >= w_size-MIN_LOOKAHEAD) {
+                    flush_block_only(false);
+                    if(strm.avail_out==0) return NeedMore;
+                }
+            }
+
+            flush_block_only(flush == Z_FINISH);
+            if(strm.avail_out==0)
+                return (flush == Z_FINISH) ? FinishStarted : NeedMore;
+
+            return flush == Z_FINISH ? FinishDone : BlockDone;
+        }
+
+        // Send a stored block
+        internal void _tr_stored_block(int buf,        // input block
+            int stored_len, // length of input block
+            bool eof     // true if this is the last block for a file
+            ){
+            send_bits((STORED_BLOCK<<1)+(eof?1:0), 3);  // send block type
+            copy_block(buf, stored_len, true);          // with header
+        }
+
+        // Determine the best encoding for the current block: dynamic trees, static
+        // trees or store, and output the encoded block to the zip file.
+        internal void _tr_flush_block(int buf,        // input block, or NULL if too old
+            int stored_len, // length of input block
+            bool eof     // true if this is the last block for a file
+            ) {
+            int opt_lenb, static_lenb;// opt_len and static_len in bytes
+            int max_blindex = 0;      // index of last bit length code of non zero freq
+
+            // Build the Huffman trees unless a stored block is forced
+            if(level > 0) {
+                // Check if the file is ascii or binary
+                if(data_type == Z_UNKNOWN) set_data_type();
+
+                // Construct the literal and distance trees
+                l_desc.build_tree(this);
+
+                d_desc.build_tree(this);
+
+                // At this point, opt_len and static_len are the total bit lengths of
+                // the compressed block data, excluding the tree representations.
+
+                // Build the bit length tree for the above two trees, and get the index
+                // in bl_order of the last bit length code to send.
+                max_blindex=build_bl_tree();
+
+                // Determine the best encoding. Compute first the block length in bytes
+                opt_lenb=(opt_len+3+7)>>3;
+                static_lenb=(static_len+3+7)>>3;
+
+                if(static_lenb<=opt_lenb) opt_lenb=static_lenb;
+            }
+            else {
+                opt_lenb=static_lenb=stored_len+5; // force a stored block
+            }
+
+            if(stored_len+4<=opt_lenb && buf != -1){
+                // 4: two words for the lengths
+                // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+                // Otherwise we can't have processed more than WSIZE input bytes since
+                // the last block flush, because compression would have been
+                // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+                // transform a block into a stored block.
+                _tr_stored_block(buf, stored_len, eof);
+            }
+            else if(static_lenb == opt_lenb){
+                send_bits((STATIC_TREES<<1)+(eof?1:0), 3);
+                compress_block(StaticTree.static_ltree, StaticTree.static_dtree);
+            }
+            else{
+                send_bits((DYN_TREES<<1)+(eof?1:0), 3);
+                send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1);
+                compress_block(dyn_ltree, dyn_dtree);
+            }
+
+            // The above check is made mod 2^32, for files larger than 512 MB
+            // and uLong implemented on 32 bits.
+
+            init_block();
+
+            if(eof){
+                bi_windup();
+            }
+        }
+
+        // Fill the window when the lookahead becomes insufficient.
+        // Updates strstart and lookahead.
+        //
+        // IN assertion: lookahead < MIN_LOOKAHEAD
+        // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+        //    At least one byte has been read, or avail_in == 0; reads are
+        //    performed for at least two bytes (required for the zip translate_eol
+        //    option -- not supported here).
+        internal void fill_window(){
+            int n, m;
+            int p;
+            int more;    // Amount of free space at the end of the window.
+
+            do{
+                more = (window_size-lookahead-strstart);
+
+                // Deal with !@#$% 64K limit:
+                if(more==0 && strstart==0 && lookahead==0){
+                    more = w_size;
+                } 
+                else if(more==-1) {
+                    // Very unlikely, but possible on 16 bit machine if strstart == 0
+                    // and lookahead == 1 (input done one byte at time)
+                    more--;
+
+                    // If the window is almost full and there is insufficient lookahead,
+                    // move the upper half to the lower one to make room in the upper half.
+                }
+                else if(strstart >= w_size+ w_size-MIN_LOOKAHEAD) {
+                    System.Array.Copy(window, w_size, window, 0, w_size);
+                    match_start-=w_size;
+                    strstart-=w_size; // we now have strstart >= MAX_DIST
+                    block_start-=w_size;
+
+                    // Slide the hash table (could be avoided with 32 bit values
+                    // at the expense of memory usage). We slide even when level == 0
+                    // to keep the hash table consistent if we switch back to level > 0
+                    // later. (Using level 0 permanently is not an optimal usage of
+                    // zlib, so we don't care about this pathological case.)
+
+                    n = hash_size;
+                    p=n;
+                    do {
+                        m = (head[--p]&0xffff);
+                        head[p]=(short)(m>=w_size ? (m-w_size) : 0);
+                    }
+                    while (--n != 0);
+
+                    n = w_size;
+                    p = n;
+                    do {
+                        m = (prev[--p]&0xffff);
+                        prev[p] = (short)(m >= w_size ? (m-w_size) : 0);
+                        // If n is not on any hash chain, prev[n] is garbage but
+                        // its value will never be used.
+                    }
+                    while (--n!=0);
+                    more += w_size;
+                }
+
+                if (strm.avail_in == 0) return;
+
+                // If there was no sliding:
+                //    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+                //    more == window_size - lookahead - strstart
+                // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+                // => more >= window_size - 2*WSIZE + 2
+                // In the BIG_MEM or MMAP case (not yet supported),
+                //   window_size == input_size + MIN_LOOKAHEAD  &&
+                //   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+                // Otherwise, window_size == 2*WSIZE so more >= 2.
+                // If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+
+                n = strm.read_buf(window, strstart + lookahead, more);
+                lookahead += n;
+
+                // Initialize the hash value now that we have some input:
+                if(lookahead >= MIN_MATCH) {
+                    ins_h = window[strstart]&0xff;
+                    ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask;
+                }
+                // If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+                // but this is not important since only literal bytes will be emitted.
+            }
+            while (lookahead < MIN_LOOKAHEAD && strm.avail_in != 0);
+        }
+
+        // Compress as much as possible from the input stream, return the current
+        // block state.
+        // This function does not perform lazy evaluation of matches and inserts
+        // new strings in the dictionary only for unmatched strings or for short
+        // matches. It is used only for the fast compression options.
+        internal int deflate_fast(int flush){
+            //    short hash_head = 0; // head of the hash chain
+            int hash_head = 0; // head of the hash chain
+            bool bflush;      // set if current block must be flushed
+
+            while(true){
+                // Make sure that we always have enough lookahead, except
+                // at the end of the input file. We need MAX_MATCH bytes
+                // for the next match, plus MIN_MATCH bytes to insert the
+                // string following the next match.
+                if(lookahead < MIN_LOOKAHEAD){
+                    fill_window();
+                    if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH){
+                        return NeedMore;
+                    }
+                    if(lookahead == 0) break; // flush the current block
+                }
+
+                // Insert the string window[strstart .. strstart+2] in the
+                // dictionary, and set hash_head to the head of the hash chain:
+                if(lookahead >= MIN_MATCH){
+                    ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
+
+                    //  prev[strstart&w_mask]=hash_head=head[ins_h];
+                    hash_head=(head[ins_h]&0xffff);
+                    prev[strstart&w_mask]=head[ins_h];
+                    head[ins_h]=(short)strstart;
+                }
+
+                // Find the longest match, discarding those <= prev_length.
+                // At this point we have always match_length < MIN_MATCH
+
+                if(hash_head!=0L && 
+                    ((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD
+                    ){
+                    // To simplify the code, we prevent matches with the string
+                    // of window index 0 (in particular we have to avoid a match
+                    // of the string with itself at the start of the input file).
+                    if(strategy != Z_HUFFMAN_ONLY){
+                        match_length=longest_match (hash_head);
+                    }
+                    // longest_match() sets match_start
+                }
+                if(match_length>=MIN_MATCH){
+                    //        check_match(strstart, match_start, match_length);
+
+                    bflush=_tr_tally(strstart-match_start, match_length-MIN_MATCH);
+
+                    lookahead -= match_length;
+
+                    // Insert new strings in the hash table only if the match length
+                    // is not too large. This saves time but degrades compression.
+                    if(match_length <= max_lazy_match &&
+                        lookahead >= MIN_MATCH) {
+                        match_length--; // string at strstart already in hash table
+                        do{
+                            strstart++;
+
+                            ins_h=((ins_h<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
+                            //      prev[strstart&w_mask]=hash_head=head[ins_h];
+                            hash_head=(head[ins_h]&0xffff);
+                            prev[strstart&w_mask]=head[ins_h];
+                            head[ins_h]=(short)strstart;
+
+                            // strstart never exceeds WSIZE-MAX_MATCH, so there are
+                            // always MIN_MATCH bytes ahead.
+                        }
+                        while (--match_length != 0);
+                        strstart++; 
+                    }
+                    else{
+                        strstart += match_length;
+                        match_length = 0;
+                        ins_h = window[strstart]&0xff;
+
+                        ins_h=(((ins_h)<<hash_shift)^(window[strstart+1]&0xff))&hash_mask;
+                        // If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                        // matter since it will be recomputed at next deflate call.
+                    }
+                }
+                else {
+                    // No match, output a literal byte
+
+                    bflush=_tr_tally(0, window[strstart]&0xff);
+                    lookahead--;
+                    strstart++; 
+                }
+                if (bflush){
+
+                    flush_block_only(false);
+                    if(strm.avail_out==0) return NeedMore;
+                }
+            }
+
+            flush_block_only(flush == Z_FINISH);
+            if(strm.avail_out==0){
+                if(flush == Z_FINISH) return FinishStarted;
+                else return NeedMore;
+            }
+            return flush==Z_FINISH ? FinishDone : BlockDone;
+        }
+
+        // Same as above, but achieves better compression. We use a lazy
+        // evaluation for matches: a match is finally adopted only if there is
+        // no better match at the next window position.
+        internal int deflate_slow(int flush){
+            //    short hash_head = 0;    // head of hash chain
+            int hash_head = 0;    // head of hash chain
+            bool bflush;         // set if current block must be flushed
+
+            // Process the input block.
+            while(true){
+                // Make sure that we always have enough lookahead, except
+                // at the end of the input file. We need MAX_MATCH bytes
+                // for the next match, plus MIN_MATCH bytes to insert the
+                // string following the next match.
+
+                if (lookahead < MIN_LOOKAHEAD) {
+                    fill_window();
+                    if(lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                        return NeedMore;
+                    }
+                    if(lookahead == 0) break; // flush the current block
+                }
+
+                // Insert the string window[strstart .. strstart+2] in the
+                // dictionary, and set hash_head to the head of the hash chain:
+
+                if(lookahead >= MIN_MATCH) {
+                    ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff)) & hash_mask;
+                    //  prev[strstart&w_mask]=hash_head=head[ins_h];
+                    hash_head=(head[ins_h]&0xffff);
+                    prev[strstart&w_mask]=head[ins_h];
+                    head[ins_h]=(short)strstart;
+                }
+
+                // Find the longest match, discarding those <= prev_length.
+                prev_length = match_length; prev_match = match_start;
+                match_length = MIN_MATCH-1;
+
+                if (hash_head != 0 && prev_length < max_lazy_match &&
+                    ((strstart-hash_head)&0xffff) <= w_size-MIN_LOOKAHEAD
+                    ){
+                    // To simplify the code, we prevent matches with the string
+                    // of window index 0 (in particular we have to avoid a match
+                    // of the string with itself at the start of the input file).
+
+                    if(strategy != Z_HUFFMAN_ONLY) {
+                        match_length = longest_match(hash_head);
+                    }
+                    // longest_match() sets match_start
+
+                    if (match_length <= 5 && (strategy == Z_FILTERED ||
+                        (match_length == MIN_MATCH &&
+                        strstart - match_start > 4096))) {
+
+                        // If prev_match is also MIN_MATCH, match_start is garbage
+                        // but we will ignore the current match anyway.
+                        match_length = MIN_MATCH-1;
+                    }
+                }
+
+                // If there was a match at the previous step and the current
+                // match is not better, output the previous match:
+                if(prev_length >= MIN_MATCH && match_length <= prev_length) {
+                    int max_insert = strstart + lookahead - MIN_MATCH;
+                    // Do not insert strings in hash table beyond this.
+
+                    //          check_match(strstart-1, prev_match, prev_length);
+
+                    bflush=_tr_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
+
+                    // Insert in hash table all strings up to the end of the match.
+                    // strstart-1 and strstart are already inserted. If there is not
+                    // enough lookahead, the last two strings are not inserted in
+                    // the hash table.
+                    lookahead -= prev_length-1;
+                    prev_length -= 2;
+                    do{
+                        if(++strstart <= max_insert) {
+                            ins_h=(((ins_h)<<hash_shift)^(window[(strstart)+(MIN_MATCH-1)]&0xff))&hash_mask;
+                            //prev[strstart&w_mask]=hash_head=head[ins_h];
+                            hash_head=(head[ins_h]&0xffff);
+                            prev[strstart&w_mask]=head[ins_h];
+                            head[ins_h]=(short)strstart;
+                        }
+                    }
+                    while(--prev_length != 0);
+                    match_available = 0;
+                    match_length = MIN_MATCH-1;
+                    strstart++;
+
+                    if (bflush){
+                        flush_block_only(false);
+                        if(strm.avail_out==0) return NeedMore;
+                    }
+                } else if (match_available!=0) {
+
+                    // If there was no match at the previous position, output a
+                    // single literal. If there was a match but the current match
+                    // is longer, truncate the previous match to a single literal.
+
+                    bflush=_tr_tally(0, window[strstart-1]&0xff);
+
+                    if (bflush) {
+                        flush_block_only(false);
+                    }
+                    strstart++;
+                    lookahead--;
+                    if(strm.avail_out == 0) return NeedMore;
+                } else {
+                    // There is no previous match to compare with, wait for
+                    // the next step to decide.
+
+                    match_available = 1;
+                    strstart++;
+                    lookahead--;
+                }
+            }
+
+            if(match_available!=0) {
+                bflush=_tr_tally(0, window[strstart-1]&0xff);
+                match_available = 0;
+            }
+            flush_block_only(flush == Z_FINISH);
+
+            if(strm.avail_out==0){
+                if(flush == Z_FINISH) return FinishStarted;
+                else return NeedMore;
+            }
+
+            return flush == Z_FINISH ? FinishDone : BlockDone;
+        }
+
+        internal int longest_match(int cur_match){
+            int chain_length = max_chain_length; // max hash chain length
+            int scan = strstart;                 // current string
+            int match;                           // matched string
+            int len;                             // length of current match
+            int best_len = prev_length;          // best match length so far
+            int limit = strstart>(w_size-MIN_LOOKAHEAD) ?
+                strstart-(w_size-MIN_LOOKAHEAD) : 0;
+            int nice_match=this.nice_match;
+
+            // Stop when cur_match becomes <= limit. To simplify the code,
+            // we prevent matches with the string of window index 0.
+
+            int wmask = w_mask;
+
+            int strend = strstart + MAX_MATCH;
+            byte scan_end1 = window[scan+best_len-1];
+            byte scan_end = window[scan+best_len];
+
+            // The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+            // It is easy to get rid of this optimization if necessary.
+
+            // Do not waste too much time if we already have a good match:
+            if (prev_length >= good_match) {
+                chain_length >>= 2;
+            }
+
+            // Do not look for matches beyond the end of the input. This is necessary
+            // to make deflate deterministic.
+            if (nice_match > lookahead) nice_match = lookahead;
+
+            do {
+                match = cur_match;
+
+                // Skip to next match if the match length cannot increase
+                // or if the match length is less than 2:
+                if (window[match+best_len]   != scan_end  ||
+                    window[match+best_len-1] != scan_end1 ||
+                    window[match]       != window[scan]     ||
+                    window[++match]     != window[scan+1])      continue;
+
+                // The check at best_len-1 can be removed because it will be made
+                // again later. (This heuristic is not always a win.)
+                // It is not necessary to compare scan[2] and match[2] since they
+                // are always equal when the other bytes match, given that
+                // the hash keys are equal and that HASH_BITS >= 8.
+                scan += 2; match++;
+
+                // We check for insufficient lookahead only every 8th comparison;
+                // the 256th check will be made at strstart+258.
+                do {
+                } while (window[++scan] == window[++match] &&
+                    window[++scan] == window[++match] &&
+                    window[++scan] == window[++match] &&
+                    window[++scan] == window[++match] &&
+                    window[++scan] == window[++match] &&
+                    window[++scan] == window[++match] &&
+                    window[++scan] == window[++match] &&
+                    window[++scan] == window[++match] &&
+                    scan < strend);
+
+                len = MAX_MATCH - (int)(strend - scan);
+                scan = strend - MAX_MATCH;
+
+                if(len>best_len) {
+                    match_start = cur_match;
+                    best_len = len;
+                    if (len >= nice_match) break;
+                    scan_end1  = window[scan+best_len-1];
+                    scan_end   = window[scan+best_len];
+                }
+
+            } while ((cur_match = (prev[cur_match & wmask]&0xffff)) > limit
+                && --chain_length != 0);
+
+            if (best_len <= lookahead) return best_len;
+            return lookahead;
+        }
+    
+        internal int deflateInit(ZStream strm, int level, int bits){
+            return deflateInit2(strm, level, Z_DEFLATED, bits, DEF_MEM_LEVEL,
+                Z_DEFAULT_STRATEGY);
+        }
+        internal int deflateInit(ZStream strm, int level){
+            return deflateInit(strm, level, MAX_WBITS);
+        }
+        internal int deflateInit2(ZStream strm, int level, int method,  int windowBits,
+            int memLevel, int strategy){
+            int noheader = 0;
+            //    byte[] my_version=ZLIB_VERSION;
+
+            //
+            //  if (version == null || version[0] != my_version[0]
+            //  || stream_size != sizeof(z_stream)) {
+            //  return Z_VERSION_ERROR;
+            //  }
+
+            strm.msg = null;
+
+            if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+            if (windowBits < 0) { // undocumented feature: suppress zlib header
+                noheader = 1;
+                windowBits = -windowBits;
+            }
+
+            if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || 
+                method != Z_DEFLATED ||
+                windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+                strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+                return Z_STREAM_ERROR;
+            }
+
+            strm.dstate = (Deflate)this;
+
+            this.noheader = noheader;
+            w_bits = windowBits;
+            w_size = 1 << w_bits;
+            w_mask = w_size - 1;
+
+            hash_bits = memLevel + 7;
+            hash_size = 1 << hash_bits;
+            hash_mask = hash_size - 1;
+            hash_shift = ((hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+            window = new byte[w_size*2];
+            prev = new short[w_size];
+            head = new short[hash_size];
+
+            lit_bufsize = 1 << (memLevel + 6); // 16K elements by default
+
+            // We overlay pending_buf and d_buf+l_buf. This works since the average
+            // output size for (length,distance) codes is <= 24 bits.
+            pending_buf = new byte[lit_bufsize*4];
+            pending_buf_size = lit_bufsize*4;
+
+            d_buf = lit_bufsize/2;
+            l_buf = (1+2)*lit_bufsize;
+
+            this.level = level;
+
+            //System.out.println("level="+level);
+
+            this.strategy = strategy;
+            this.method = (byte)method;
+
+            return deflateReset(strm);
+        }
+
+        internal int deflateReset(ZStream strm){
+            strm.total_in = strm.total_out = 0;
+            strm.msg = null; //
+            strm.data_type = Z_UNKNOWN;
+
+            pending = 0;
+            pending_out = 0;
+
+            if(noheader < 0) {
+                noheader = 0; // was set to -1 by deflate(..., Z_FINISH);
+            }
+            status = (noheader!=0) ? BUSY_STATE : INIT_STATE;
+            strm.adler=strm._adler.adler32(0, null, 0, 0);
+
+            last_flush = Z_NO_FLUSH;
+
+            tr_init();
+            lm_init();
+            return Z_OK;
+        }
+
+        internal int deflateEnd(){
+            if(status!=INIT_STATE && status!=BUSY_STATE && status!=FINISH_STATE){
+                return Z_STREAM_ERROR;
+            }
+            // Deallocate in reverse order of allocations:
+            pending_buf=null;
+            head=null;
+            prev=null;
+            window=null;
+            // free
+            // dstate=null;
+            return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+        }
+
+        internal int deflateParams(ZStream strm, int _level, int _strategy){
+            int err=Z_OK;
+
+            if(_level == Z_DEFAULT_COMPRESSION){
+                _level = 6;
+            }
+            if(_level < 0 || _level > 9 || 
+                _strategy < 0 || _strategy > Z_HUFFMAN_ONLY) {
+                return Z_STREAM_ERROR;
+            }
+
+            if(config_table[level].func!=config_table[_level].func &&
+                strm.total_in != 0) {
+                // Flush the last buffer:
+                err = strm.deflate(Z_PARTIAL_FLUSH);
+            }
+
+            if(level != _level) {
+                level = _level;
+                max_lazy_match   = config_table[level].max_lazy;
+                good_match       = config_table[level].good_length;
+                nice_match       = config_table[level].nice_length;
+                max_chain_length = config_table[level].max_chain;
+            }
+            strategy = _strategy;
+            return err;
+        }
+
+        internal int deflateSetDictionary (ZStream strm, byte[] dictionary, int dictLength){
+            int length = dictLength;
+            int index=0;
+
+            if(dictionary == null || status != INIT_STATE)
+                return Z_STREAM_ERROR;
+
+            strm.adler=strm._adler.adler32(strm.adler, dictionary, 0, dictLength);
+
+            if(length < MIN_MATCH) return Z_OK;
+            if(length > w_size-MIN_LOOKAHEAD){
+                length = w_size-MIN_LOOKAHEAD;
+                index=dictLength-length; // use the tail of the dictionary
+            }
+            System.Array.Copy(dictionary, index, window, 0, length);
+            strstart = length;
+            block_start = length;
+
+            // Insert all strings in the hash table (except for the last two bytes).
+            // s->lookahead stays null, so s->ins_h will be recomputed at the next
+            // call of fill_window.
+
+            ins_h = window[0]&0xff;
+            ins_h=(((ins_h)<<hash_shift)^(window[1]&0xff))&hash_mask;
+
+            for(int n=0; n<=length-MIN_MATCH; n++){
+                ins_h=(((ins_h)<<hash_shift)^(window[(n)+(MIN_MATCH-1)]&0xff))&hash_mask;
+                prev[n&w_mask]=head[ins_h];
+                head[ins_h]=(short)n;
+            }
+            return Z_OK;
+        }
+
+        internal int deflate(ZStream strm, int flush){
+            int old_flush;
+
+            if(flush>Z_FINISH || flush<0){
+                return Z_STREAM_ERROR;
+            }
+
+            if(strm.next_out == null ||
+                (strm.next_in == null && strm.avail_in != 0) ||
+                (status == FINISH_STATE && flush != Z_FINISH)) {
+                strm.msg=z_errmsg[Z_NEED_DICT-(Z_STREAM_ERROR)];
+                return Z_STREAM_ERROR;
+            }
+            if(strm.avail_out == 0){
+                strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+                return Z_BUF_ERROR;
+            }
+
+            this.strm = strm; // just in case
+            old_flush = last_flush;
+            last_flush = flush;
+
+            // Write the zlib header
+            if(status == INIT_STATE) {
+                int header = (Z_DEFLATED+((w_bits-8)<<4))<<8;
+                int level_flags=((level-1)&0xff)>>1;
+
+                if(level_flags>3) level_flags=3;
+                header |= (level_flags<<6);
+                if(strstart!=0) header |= PRESET_DICT;
+                header+=31-(header % 31);
+
+                status=BUSY_STATE;
+                putShortMSB(header);
+
+
+                // Save the adler32 of the preset dictionary:
+                if(strstart!=0){
+                    putShortMSB((int)(strm.adler>>16));
+                    putShortMSB((int)(strm.adler&0xffff));
+                }
+                strm.adler=strm._adler.adler32(0, null, 0, 0);
+            }
+
+            // Flush as much pending output as possible
+            if(pending != 0) {
+                strm.flush_pending();
+                if(strm.avail_out == 0) {
+                    //System.out.println("  avail_out==0");
+                    // Since avail_out is 0, deflate will be called again with
+                    // more output space, but possibly with both pending and
+                    // avail_in equal to zero. There won't be anything to do,
+                    // but this is not an error situation so make sure we
+                    // return OK instead of BUF_ERROR at next call of deflate:
+                    last_flush = -1;
+                    return Z_OK;
+                }
+
+                // Make sure there is something to do and avoid duplicate consecutive
+                // flushes. For repeated and useless calls with Z_FINISH, we keep
+                // returning Z_STREAM_END instead of Z_BUFF_ERROR.
+            }
+            else if(strm.avail_in==0 && flush <= old_flush &&
+                flush != Z_FINISH) {
+                strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+                return Z_BUF_ERROR;
+            }
+
+            // User must not provide more input after the first FINISH:
+            if(status == FINISH_STATE && strm.avail_in != 0) {
+                strm.msg=z_errmsg[Z_NEED_DICT-(Z_BUF_ERROR)];
+                return Z_BUF_ERROR;
+            }
+
+            // Start a new block or continue the current one.
+            if(strm.avail_in!=0 || lookahead!=0 ||
+                (flush != Z_NO_FLUSH && status != FINISH_STATE)) {
+                int bstate=-1;
+                switch(config_table[level].func){
+                    case STORED: 
+                        bstate = deflate_stored(flush);
+                        break;
+                    case FAST: 
+                        bstate = deflate_fast(flush);
+                        break;
+                    case SLOW: 
+                        bstate = deflate_slow(flush);
+                        break;
+                    default:
+                        break;
+                }
+
+                if (bstate==FinishStarted || bstate==FinishDone) {
+                    status = FINISH_STATE;
+                }
+                if (bstate==NeedMore || bstate==FinishStarted) {
+                    if(strm.avail_out == 0) {
+                        last_flush = -1; // avoid BUF_ERROR next call, see above
+                    }
+                    return Z_OK;
+                    // If flush != Z_NO_FLUSH && avail_out == 0, the next call
+                    // of deflate should use the same flush parameter to make sure
+                    // that the flush is complete. So we don't have to output an
+                    // empty block here, this will be done at next call. This also
+                    // ensures that for a very small output buffer, we emit at most
+                    // one empty block.
+                }
+
+                if (bstate==BlockDone) {
+                    if(flush == Z_PARTIAL_FLUSH) {
+                        _tr_align();
+                    } 
+                    else { // FULL_FLUSH or SYNC_FLUSH
+                        _tr_stored_block(0, 0, false);
+                        // For a full flush, this empty block will be recognized
+                        // as a special marker by inflate_sync().
+                        if(flush == Z_FULL_FLUSH) {
+                            //state.head[s.hash_size-1]=0;
+                            for(int i=0; i<hash_size/*-1*/; i++)  // forget history
+                                head[i]=0;
+                        }
+                    }
+                    strm.flush_pending();
+                    if(strm.avail_out == 0) {
+                        last_flush = -1; // avoid BUF_ERROR at next call, see above
+                        return Z_OK;
+                    }
+                }
+            }
+
+            if(flush!=Z_FINISH) return Z_OK;
+            if(noheader!=0) return Z_STREAM_END;
+
+            // Write the zlib trailer (adler32)
+            putShortMSB((int)(strm.adler>>16));
+            putShortMSB((int)(strm.adler&0xffff));
+            strm.flush_pending();
+
+            // If avail_out is zero, the application will call deflate again
+            // to flush the rest.
+            noheader = -1; // write the trailer only once!
+            return pending != 0 ? Z_OK : Z_STREAM_END;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/InfBlocks.cs b/crypto/src/util/zlib/InfBlocks.cs
new file mode 100644
index 000000000..479d9b5c9
--- /dev/null
+++ b/crypto/src/util/zlib/InfBlocks.cs
@@ -0,0 +1,618 @@
+using System;
+/*
+ * $Id: InfBlocks.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    internal sealed class InfBlocks{
+        private const int MANY=1440;
+
+        // And'ing with mask[n] masks the lower n bits
+        private static readonly int[] inflate_mask = {
+                                                0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+                                                0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+                                                0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+                                                0x00007fff, 0x0000ffff
+                                            };
+
+        // Table for deflate from PKZIP's appnote.txt.
+        static readonly int[] border = { // Order of the bit length code lengths
+                                  16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+                              };
+
+        private const int Z_OK=0;
+        private const int Z_STREAM_END=1;
+        private const int Z_NEED_DICT=2;
+        private const int Z_ERRNO=-1;
+        private const int Z_STREAM_ERROR=-2;
+        private const int Z_DATA_ERROR=-3;
+        private const int Z_MEM_ERROR=-4;
+        private const int Z_BUF_ERROR=-5;
+        private const int Z_VERSION_ERROR=-6;
+
+        private const int TYPE=0;  // get type bits (3, including end bit)
+        private const int LENS=1;  // get lengths for stored
+        private const int STORED=2;// processing stored block
+        private const int TABLE=3; // get table lengths
+        private const int BTREE=4; // get bit lengths tree for a dynamic block
+        private const int DTREE=5; // get length, distance trees for a dynamic block
+        private const int CODES=6; // processing fixed or dynamic block
+        private const int DRY=7;   // output remaining window bytes
+        private const int DONE=8;  // finished last block, done
+        private const int BAD=9;   // ot a data error--stuck here
+
+        internal int mode;            // current inflate_block mode 
+
+        internal int left;            // if STORED, bytes left to copy 
+
+        internal int table;           // table lengths (14 bits) 
+        internal int index;           // index into blens (or border) 
+        internal int[] blens;         // bit lengths of codes 
+        internal int[] bb=new int[1]; // bit length tree depth 
+        internal int[] tb=new int[1]; // bit length decoding tree 
+
+        internal InfCodes codes=new InfCodes();      // if CODES, current state 
+
+        int last;            // true if this block is the last block 
+
+        // mode independent information 
+        internal int bitk;            // bits in bit buffer 
+        internal int bitb;            // bit buffer 
+        internal int[] hufts;         // single malloc for tree space 
+        internal byte[] window;       // sliding window 
+        internal int end;             // one byte after sliding window 
+        internal int read;            // window read pointer 
+        internal int write;           // window write pointer 
+        internal Object checkfn;      // check function 
+        internal long check;          // check on output 
+
+        internal InfTree inftree=new InfTree();
+
+        internal InfBlocks(ZStream z, Object checkfn, int w){
+            hufts=new int[MANY*3];
+            window=new byte[w];
+            end=w;
+            this.checkfn = checkfn;
+            mode = TYPE;
+            reset(z, null);
+        }
+
+        internal void reset(ZStream z, long[] c){
+            if(c!=null) c[0]=check;
+            if(mode==BTREE || mode==DTREE){
+            }
+            if(mode==CODES){
+                codes.free(z);
+            }
+            mode=TYPE;
+            bitk=0;
+            bitb=0;
+            read=write=0;
+
+            if(checkfn != null)
+                z.adler=check=z._adler.adler32(0L, null, 0, 0);
+        }
+
+        internal int proc(ZStream z, int r){
+            int t;              // temporary storage
+            int b;              // bit buffer
+            int k;              // bits in bit buffer
+            int p;              // input data pointer
+            int n;              // bytes available there
+            int q;              // output window write pointer
+            int m; {              // bytes to end of window or read pointer
+
+            // copy input/output information to locals (UPDATE macro restores)
+     p=z.next_in_index;n=z.avail_in;b=bitb;k=bitk;} {
+     q=write;m=(int)(q<read?read-q-1:end-q);}
+
+            // process input based on current state
+            while(true){
+                switch (mode){
+                    case TYPE:
+
+                        while(k<(3)){
+                            if(n!=0){
+                                r=Z_OK;
+                            }
+                            else{
+                                bitb=b; bitk=k; 
+                                z.avail_in=n;
+                                z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                write=q;
+                                return inflate_flush(z,r);
+                            };
+                            n--;
+                            b|=(z.next_in[p++]&0xff)<<k;
+                            k+=8;
+                        }
+                        t = (int)(b & 7);
+                        last = t & 1;
+
+                    switch (t >> 1){
+                        case 0: {                         // stored 
+           b>>=(3);k-=(3);}
+                            t = k & 7; {                    // go to byte boundary
+
+           b>>=(t);k-=(t);}
+                            mode = LENS;                  // get length of stored block
+                            break;
+                        case 1: {                         // fixed
+                            int[] bl=new int[1];
+                            int[] bd=new int[1];
+                            int[][] tl=new int[1][];
+                            int[][] td=new int[1][];
+
+                            InfTree.inflate_trees_fixed(bl, bd, tl, td, z);
+                            codes.init(bl[0], bd[0], tl[0], 0, td[0], 0, z);
+                        } {
+
+           b>>=(3);k-=(3);}
+
+                            mode = CODES;
+                            break;
+                        case 2: {                         // dynamic
+
+           b>>=(3);k-=(3);}
+
+                            mode = TABLE;
+                            break;
+                        case 3: {                         // illegal
+
+           b>>=(3);k-=(3);}
+                            mode = BAD;
+                            z.msg = "invalid block type";
+                            r = Z_DATA_ERROR;
+
+                            bitb=b; bitk=k; 
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            write=q;
+                            return inflate_flush(z,r);
+                    }
+                        break;
+                    case LENS:
+
+                        while(k<(32)){
+                            if(n!=0){
+                                r=Z_OK;
+                            }
+                            else{
+                                bitb=b; bitk=k; 
+                                z.avail_in=n;
+                                z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                write=q;
+                                return inflate_flush(z,r);
+                            };
+                            n--;
+                            b|=(z.next_in[p++]&0xff)<<k;
+                            k+=8;
+                        }
+
+                        if ((((~b) >> 16) & 0xffff) != (b & 0xffff)){
+                            mode = BAD;
+                            z.msg = "invalid stored block lengths";
+                            r = Z_DATA_ERROR;
+
+                            bitb=b; bitk=k; 
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            write=q;
+                            return inflate_flush(z,r);
+                        }
+                        left = (b & 0xffff);
+                        b = k = 0;                       // dump bits
+                        mode = left!=0 ? STORED : (last!=0 ? DRY : TYPE);
+                        break;
+                    case STORED:
+                        if (n == 0){
+                            bitb=b; bitk=k; 
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            write=q;
+                            return inflate_flush(z,r);
+                        }
+
+                        if(m==0){
+                            if(q==end&&read!=0){
+                                q=0; m=(int)(q<read?read-q-1:end-q);
+                            }
+                            if(m==0){
+                                write=q; 
+                                r=inflate_flush(z,r);
+                                q=write;m=(int)(q<read?read-q-1:end-q);
+                                if(q==end&&read!=0){
+                                    q=0; m=(int)(q<read?read-q-1:end-q);
+                                }
+                                if(m==0){
+                                    bitb=b; bitk=k; 
+                                    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                    write=q;
+                                    return inflate_flush(z,r);
+                                }
+                            }
+                        }
+                        r=Z_OK;
+
+                        t = left;
+                        if(t>n) t = n;
+                        if(t>m) t = m;
+                        System.Array.Copy(z.next_in, p, window, q, t);
+                        p += t;  n -= t;
+                        q += t;  m -= t;
+                        if ((left -= t) != 0)
+                            break;
+                        mode = last!=0 ? DRY : TYPE;
+                        break;
+                    case TABLE:
+
+                        while(k<(14)){
+                            if(n!=0){
+                                r=Z_OK;
+                            }
+                            else{
+                                bitb=b; bitk=k; 
+                                z.avail_in=n;
+                                z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                write=q;
+                                return inflate_flush(z,r);
+                            };
+                            n--;
+                            b|=(z.next_in[p++]&0xff)<<k;
+                            k+=8;
+                        }
+
+                        table = t = (b & 0x3fff);
+                        if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) {
+                            mode = BAD;
+                            z.msg = "too many length or distance symbols";
+                            r = Z_DATA_ERROR;
+
+                            bitb=b; bitk=k; 
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            write=q;
+                            return inflate_flush(z,r);
+                        }
+                        t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+                        if(blens==null || blens.Length<t){
+                            blens=new int[t];
+                        }
+                        else{
+                            for(int i=0; i<t; i++){blens[i]=0;}
+                        } {
+
+	 b>>=(14);k-=(14);}
+
+                        index = 0;
+                        mode = BTREE;
+                        goto case BTREE;
+                    case BTREE:
+                        while (index < 4 + (table >> 10)){
+                            while(k<(3)){
+                                if(n!=0){
+                                    r=Z_OK;
+                                }
+                                else{
+                                    bitb=b; bitk=k; 
+                                    z.avail_in=n;
+                                    z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                    write=q;
+                                    return inflate_flush(z,r);
+                                };
+                                n--;
+                                b|=(z.next_in[p++]&0xff)<<k;
+                                k+=8;
+                            }
+
+                            blens[border[index++]] = b&7; {
+
+	   b>>=(3);k-=(3);}
+                        }
+
+                        while(index < 19){
+                            blens[border[index++]] = 0;
+                        }
+
+                        bb[0] = 7;
+                        t = inftree.inflate_trees_bits(blens, bb, tb, hufts, z);
+                        if (t != Z_OK){
+                            r = t;
+                            if (r == Z_DATA_ERROR){
+                                blens=null;
+                                mode = BAD;
+                            }
+
+                            bitb=b; bitk=k; 
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            write=q;
+                            return inflate_flush(z,r);
+                        }
+
+                        index = 0;
+                        mode = DTREE;
+                        goto case DTREE;
+                    case DTREE:
+                        while (true){
+                            t = table;
+                            if(!(index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))){
+                                break;
+                            }
+
+                            int i, j, c;
+
+                            t = bb[0];
+
+                            while(k<(t)){
+                                if(n!=0){
+                                    r=Z_OK;
+                                }
+                                else{
+                                    bitb=b; bitk=k; 
+                                    z.avail_in=n;
+                                    z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                    write=q;
+                                    return inflate_flush(z,r);
+                                };
+                                n--;
+                                b|=(z.next_in[p++]&0xff)<<k;
+                                k+=8;
+                            }
+
+                            if(tb[0]==-1){
+                                //System.err.println("null...");
+                            }
+
+                            t=hufts[(tb[0]+(b&inflate_mask[t]))*3+1];
+                            c=hufts[(tb[0]+(b&inflate_mask[t]))*3+2];
+
+                            if (c < 16){
+                                b>>=(t);k-=(t);
+                                blens[index++] = c;
+                            }
+                            else { // c == 16..18
+                                i = c == 18 ? 7 : c - 14;
+                                j = c == 18 ? 11 : 3;
+
+                                while(k<(t+i)){
+                                    if(n!=0){
+                                        r=Z_OK;
+                                    }
+                                    else{
+                                        bitb=b; bitk=k; 
+                                        z.avail_in=n;
+                                        z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                        write=q;
+                                        return inflate_flush(z,r);
+                                    };
+                                    n--;
+                                    b|=(z.next_in[p++]&0xff)<<k;
+                                    k+=8;
+                                }
+
+                                b>>=(t);k-=(t);
+
+                                j += (b & inflate_mask[i]);
+
+                                b>>=(i);k-=(i);
+
+                                i = index;
+                                t = table;
+                                if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+                                    (c == 16 && i < 1)){
+                                    blens=null;
+                                    mode = BAD;
+                                    z.msg = "invalid bit length repeat";
+                                    r = Z_DATA_ERROR;
+
+                                    bitb=b; bitk=k; 
+                                    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                    write=q;
+                                    return inflate_flush(z,r);
+                                }
+
+                                c = c == 16 ? blens[i-1] : 0;
+                                do{
+                                    blens[i++] = c;
+                                }
+                                while (--j!=0);
+                                index = i;
+                            }
+                        }
+
+                        tb[0]=-1; {
+                        int[] bl=new int[1];
+                        int[] bd=new int[1];
+                        int[] tl=new int[1];
+                        int[] td=new int[1];
+                        bl[0] = 9;         // must be <= 9 for lookahead assumptions
+                        bd[0] = 6;         // must be <= 9 for lookahead assumptions
+
+                        t = table;
+                        t = inftree.inflate_trees_dynamic(257 + (t & 0x1f), 
+                            1 + ((t >> 5) & 0x1f),
+                            blens, bl, bd, tl, td, hufts, z);
+
+                        if (t != Z_OK){
+                            if (t == Z_DATA_ERROR){
+                                blens=null;
+                                mode = BAD;
+                            }
+                            r = t;
+
+                            bitb=b; bitk=k; 
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            write=q;
+                            return inflate_flush(z,r);
+                        }
+                        codes.init(bl[0], bd[0], hufts, tl[0], hufts, td[0], z);
+                    }
+                        mode = CODES;
+                        goto case CODES;
+                    case CODES:
+                        bitb=b; bitk=k;
+                        z.avail_in=n; z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        write=q;
+
+                        if ((r = codes.proc(this, z, r)) != Z_STREAM_END){
+                            return inflate_flush(z, r);
+                        }
+                        r = Z_OK;
+                        codes.free(z);
+
+                        p=z.next_in_index; n=z.avail_in;b=bitb;k=bitk;
+                        q=write;m=(int)(q<read?read-q-1:end-q);
+
+                        if (last==0){
+                            mode = TYPE;
+                            break;
+                        }
+                        mode = DRY;
+                        goto case DRY;
+                    case DRY:
+                        write=q; 
+                        r=inflate_flush(z, r); 
+                        q=write; m=(int)(q<read?read-q-1:end-q);
+                        if (read != write){
+                            bitb=b; bitk=k; 
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            write=q;
+                            return inflate_flush(z, r);
+                        }
+                        mode = DONE;
+                        goto case DONE;
+                    case DONE:
+                        r = Z_STREAM_END;
+
+                        bitb=b; bitk=k; 
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        write=q;
+                        return inflate_flush(z, r);
+                    case BAD:
+                        r = Z_DATA_ERROR;
+
+                        bitb=b; bitk=k; 
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        write=q;
+                        return inflate_flush(z, r);
+
+                    default:
+                        r = Z_STREAM_ERROR;
+
+                        bitb=b; bitk=k; 
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        write=q;
+                        return inflate_flush(z, r);
+                }
+            }
+        }
+
+        internal void free(ZStream z){
+            reset(z, null);
+            window=null;
+            hufts=null;
+            //ZFREE(z, s);
+        }
+
+        internal void set_dictionary(byte[] d, int start, int n){
+            System.Array.Copy(d, start, window, 0, n);
+            read = write = n;
+        }
+
+        // Returns true if inflate is currently at the end of a block generated
+        // by Z_SYNC_FLUSH or Z_FULL_FLUSH. 
+        internal int sync_point(){
+            return mode == LENS ? 1 : 0;
+        }
+
+        // copy as much as possible from the sliding window to the output area
+        internal int inflate_flush(ZStream z, int r){
+            int n;
+            int p;
+            int q;
+
+            // local copies of source and destination pointers
+            p = z.next_out_index;
+            q = read;
+
+            // compute number of bytes to copy as far as end of window
+            n = (int)((q <= write ? write : end) - q);
+            if (n > z.avail_out) n = z.avail_out;
+            if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+            // update counters
+            z.avail_out -= n;
+            z.total_out += n;
+
+            // update check information
+            if(checkfn != null)
+                z.adler=check=z._adler.adler32(check, window, q, n);
+
+            // copy as far as end of window
+            System.Array.Copy(window, q, z.next_out, p, n);
+            p += n;
+            q += n;
+
+            // see if more to copy at beginning of window
+            if (q == end){
+                // wrap pointers
+                q = 0;
+                if (write == end)
+                    write = 0;
+
+                // compute bytes to copy
+                n = write - q;
+                if (n > z.avail_out) n = z.avail_out;
+                if (n!=0 && r == Z_BUF_ERROR) r = Z_OK;
+
+                // update counters
+                z.avail_out -= n;
+                z.total_out += n;
+
+                // update check information
+                if(checkfn != null)
+                    z.adler=check=z._adler.adler32(check, window, q, n);
+
+                // copy
+                System.Array.Copy(window, q, z.next_out, p, n);
+                p += n;
+                q += n;
+            }
+
+            // update pointers
+            z.next_out_index = p;
+            read = q;
+
+            // done
+            return r;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/InfCodes.cs b/crypto/src/util/zlib/InfCodes.cs
new file mode 100644
index 000000000..6fcafe458
--- /dev/null
+++ b/crypto/src/util/zlib/InfCodes.cs
@@ -0,0 +1,611 @@
+using System;
+/*
+ * $Id: InfCodes.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    internal sealed class InfCodes{
+
+        private static readonly int[] inflate_mask = {
+                                                0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+                                                0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff,
+                                                0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
+                                                0x00007fff, 0x0000ffff
+                                            };
+
+        private const int Z_OK=0;
+        private const int Z_STREAM_END=1;
+        private const int Z_NEED_DICT=2;
+        private const int Z_ERRNO=-1;
+        private const int Z_STREAM_ERROR=-2;
+        private const int Z_DATA_ERROR=-3;
+        private const int Z_MEM_ERROR=-4;
+        private const int Z_BUF_ERROR=-5;
+        private const int Z_VERSION_ERROR=-6;
+
+        // waiting for "i:"=input,
+        //             "o:"=output,
+        //             "x:"=nothing
+        private const int START=0;  // x: set up for LEN
+        private const int LEN=1;    // i: get length/literal/eob next
+        private const int LENEXT=2; // i: getting length extra (have base)
+        private const int DIST=3;   // i: get distance next
+        private const int DISTEXT=4;// i: getting distance extra
+        private const int COPY=5;   // o: copying bytes in window, waiting for space
+        private const int LIT=6;    // o: got literal, waiting for output space
+        private const int WASH=7;   // o: got eob, possibly still output waiting
+        private const int END=8;    // x: got eob and all data flushed
+        private const int BADCODE=9;// x: got error
+
+        int mode;      // current inflate_codes mode
+
+        // mode dependent information
+        int len;
+
+        int[] tree; // pointer into tree
+        int tree_index=0;
+        int need;   // bits needed
+
+        int lit;
+
+        // if EXT or COPY, where and how much
+        int get;              // bits to get for extra
+        int dist;             // distance back to copy from
+
+        byte lbits;           // ltree bits decoded per branch
+        byte dbits;           // dtree bits decoder per branch
+        int[] ltree;          // literal/length/eob tree
+        int ltree_index;      // literal/length/eob tree
+        int[] dtree;          // distance tree
+        int dtree_index;      // distance tree
+
+        internal InfCodes(){
+        }
+        internal void init(int bl, int bd,
+            int[] tl, int tl_index,
+            int[] td, int td_index, ZStream z){
+            mode=START;
+            lbits=(byte)bl;
+            dbits=(byte)bd;
+            ltree=tl;
+            ltree_index=tl_index;
+            dtree = td;
+            dtree_index=td_index;
+            tree=null;
+        }
+
+        internal int proc(InfBlocks s, ZStream z, int r){ 
+            int j;              // temporary storage
+            int tindex;         // temporary pointer
+            int e;              // extra bits or operation
+            int b=0;            // bit buffer
+            int k=0;            // bits in bit buffer
+            int p=0;            // input data pointer
+            int n;              // bytes available there
+            int q;              // output window write pointer
+            int m;              // bytes to end of window or read pointer
+            int f;              // pointer to copy strings from
+
+            // copy input/output information to locals (UPDATE macro restores)
+            p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+            q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+            // process input and output based on current state
+            while (true){
+                switch (mode){
+                        // waiting for "i:"=input, "o:"=output, "x:"=nothing
+                    case START:         // x: set up for LEN
+                        if (m >= 258 && n >= 10){
+
+                            s.bitb=b;s.bitk=k;
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            s.write=q;
+                            r = inflate_fast(lbits, dbits, 
+                                ltree, ltree_index, 
+                                dtree, dtree_index,
+                                s, z);
+
+                            p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+                            q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+                            if (r != Z_OK){
+                                mode = r == Z_STREAM_END ? WASH : BADCODE;
+                                break;
+                            }
+                        }
+                        need = lbits;
+                        tree = ltree;
+                        tree_index=ltree_index;
+
+                        mode = LEN;
+                        goto case LEN;
+                    case LEN:           // i: get length/literal/eob next
+                        j = need;
+
+                        while(k<(j)){
+                            if(n!=0)r=Z_OK;
+                            else{
+
+                                s.bitb=b;s.bitk=k;
+                                z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                s.write=q;
+                                return s.inflate_flush(z,r);
+                            }
+                            n--;
+                            b|=(z.next_in[p++]&0xff)<<k;
+                            k+=8;
+                        }
+
+                        tindex=(tree_index+(b&inflate_mask[j]))*3;
+
+                        b>>=(tree[tindex+1]);
+                        k-=(tree[tindex+1]);
+
+                        e=tree[tindex];
+
+                        if(e == 0){               // literal
+                            lit = tree[tindex+2];
+                            mode = LIT;
+                            break;
+                        }
+                        if((e & 16)!=0 ){          // length
+                            get = e & 15;
+                            len = tree[tindex+2];
+                            mode = LENEXT;
+                            break;
+                        }
+                        if ((e & 64) == 0){        // next table
+                            need = e;
+                            tree_index = tindex/3+tree[tindex+2];
+                            break;
+                        }
+                        if ((e & 32)!=0){               // end of block
+                            mode = WASH;
+                            break;
+                        }
+                        mode = BADCODE;        // invalid code
+                        z.msg = "invalid literal/length code";
+                        r = Z_DATA_ERROR;
+
+                        s.bitb=b;s.bitk=k;
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        s.write=q;
+                        return s.inflate_flush(z,r);
+
+                    case LENEXT:        // i: getting length extra (have base)
+                        j = get;
+
+                        while(k<(j)){
+                            if(n!=0)r=Z_OK;
+                            else{
+
+                                s.bitb=b;s.bitk=k;
+                                z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                s.write=q;
+                                return s.inflate_flush(z,r);
+                            }
+                            n--; b|=(z.next_in[p++]&0xff)<<k;
+                            k+=8;
+                        }
+
+                        len += (b & inflate_mask[j]);
+
+                        b>>=j;
+                        k-=j;
+
+                        need = dbits;
+                        tree = dtree;
+                        tree_index=dtree_index;
+                        mode = DIST;
+                        goto case DIST;
+                    case DIST:          // i: get distance next
+                        j = need;
+
+                        while(k<(j)){
+                            if(n!=0)r=Z_OK;
+                            else{
+
+                                s.bitb=b;s.bitk=k;
+                                z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                s.write=q;
+                                return s.inflate_flush(z,r);
+                            }
+                            n--; b|=(z.next_in[p++]&0xff)<<k;
+                            k+=8;
+                        }
+
+                        tindex=(tree_index+(b & inflate_mask[j]))*3;
+
+                        b>>=tree[tindex+1];
+                        k-=tree[tindex+1];
+
+                        e = (tree[tindex]);
+                        if((e & 16)!=0){               // distance
+                            get = e & 15;
+                            dist = tree[tindex+2];
+                            mode = DISTEXT;
+                            break;
+                        }
+                        if ((e & 64) == 0){        // next table
+                            need = e;
+                            tree_index = tindex/3 + tree[tindex+2];
+                            break;
+                        }
+                        mode = BADCODE;        // invalid code
+                        z.msg = "invalid distance code";
+                        r = Z_DATA_ERROR;
+
+                        s.bitb=b;s.bitk=k;
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        s.write=q;
+                        return s.inflate_flush(z,r);
+
+                    case DISTEXT:       // i: getting distance extra
+                        j = get;
+
+                        while(k<(j)){
+                            if(n!=0)r=Z_OK;
+                            else{
+
+                                s.bitb=b;s.bitk=k;
+                                z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                s.write=q;
+                                return s.inflate_flush(z,r);
+                            }
+                            n--; b|=(z.next_in[p++]&0xff)<<k;
+                            k+=8;
+                        }
+
+                        dist += (b & inflate_mask[j]);
+
+                        b>>=j;
+                        k-=j;
+
+                        mode = COPY;
+                        goto case COPY;
+                    case COPY:          // o: copying bytes in window, waiting for space
+                        f = q - dist;
+                        while(f < 0){     // modulo window size-"while" instead
+                            f += s.end;     // of "if" handles invalid distances
+                        }
+                        while (len!=0){
+
+                            if(m==0){
+                                if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+                                if(m==0){
+                                    s.write=q; r=s.inflate_flush(z,r);
+                                    q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+                                    if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+
+                                    if(m==0){
+                                        s.bitb=b;s.bitk=k;
+                                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                        s.write=q;
+                                        return s.inflate_flush(z,r);
+                                    }  
+                                }
+                            }
+
+                            s.window[q++]=s.window[f++]; m--;
+
+                            if (f == s.end)
+                                f = 0;
+                            len--;
+                        }
+                        mode = START;
+                        break;
+                    case LIT:           // o: got literal, waiting for output space
+                        if(m==0){
+                            if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+                            if(m==0){
+                                s.write=q; r=s.inflate_flush(z,r);
+                                q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+                                if(q==s.end&&s.read!=0){q=0;m=q<s.read?s.read-q-1:s.end-q;}
+                                if(m==0){
+                                    s.bitb=b;s.bitk=k;
+                                    z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                    s.write=q;
+                                    return s.inflate_flush(z,r);
+                                }
+                            }
+                        }
+                        r=Z_OK;
+
+                        s.window[q++]=(byte)lit; m--;
+
+                        mode = START;
+                        break;
+                    case WASH:           // o: got eob, possibly more output
+                        if (k > 7){        // return unused byte, if any
+                            k -= 8;
+                            n++;
+                            p--;             // can always return one
+                        }
+
+                        s.write=q; r=s.inflate_flush(z,r);
+                        q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+                        if (s.read != s.write){
+                            s.bitb=b;s.bitk=k;
+                            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                            s.write=q;
+                            return s.inflate_flush(z,r);
+                        }
+                        mode = END;
+                        goto case END;
+                    case END:
+                        r = Z_STREAM_END;
+                        s.bitb=b;s.bitk=k;
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        s.write=q;
+                        return s.inflate_flush(z,r);
+
+                    case BADCODE:       // x: got error
+
+                        r = Z_DATA_ERROR;
+
+                        s.bitb=b;s.bitk=k;
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        s.write=q;
+                        return s.inflate_flush(z,r);
+
+                    default:
+                        r = Z_STREAM_ERROR;
+
+                        s.bitb=b;s.bitk=k;
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        s.write=q;
+                        return s.inflate_flush(z,r);
+                }
+            }
+        }
+
+        internal void free(ZStream z){
+            //  ZFREE(z, c);
+        }
+
+        // Called with number of bytes left to write in window at least 258
+        // (the maximum string length) and number of input bytes available
+        // at least ten.  The ten bytes are six bytes for the longest length/
+        // distance pair plus four bytes for overloading the bit buffer.
+
+        internal int inflate_fast(int bl, int bd, 
+            int[] tl, int tl_index,
+            int[] td, int td_index,
+            InfBlocks s, ZStream z){
+            int t;                // temporary pointer
+            int[] tp;             // temporary pointer
+            int tp_index;         // temporary pointer
+            int e;                // extra bits or operation
+            int b;                // bit buffer
+            int k;                // bits in bit buffer
+            int p;                // input data pointer
+            int n;                // bytes available there
+            int q;                // output window write pointer
+            int m;                // bytes to end of window or read pointer
+            int ml;               // mask for literal/length tree
+            int md;               // mask for distance tree
+            int c;                // bytes to copy
+            int d;                // distance back to copy from
+            int r;                // copy source pointer
+
+            int tp_index_t_3;     // (tp_index+t)*3
+
+            // load input, output, bit values
+            p=z.next_in_index;n=z.avail_in;b=s.bitb;k=s.bitk;
+            q=s.write;m=q<s.read?s.read-q-1:s.end-q;
+
+            // initialize masks
+            ml = inflate_mask[bl];
+            md = inflate_mask[bd];
+
+            // do until not enough input or output space for fast loop
+            do {                          // assume called with m >= 258 && n >= 10
+                // get literal/length code
+            while(k<(20)){              // max bits for literal/length code
+                n--;
+                b|=(z.next_in[p++]&0xff)<<k;k+=8;
+            }
+
+                t= b&ml;
+                tp=tl; 
+                tp_index=tl_index;
+                tp_index_t_3=(tp_index+t)*3;
+                if ((e = tp[tp_index_t_3]) == 0){
+                    b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+                    s.window[q++] = (byte)tp[tp_index_t_3+2];
+                    m--;
+                    continue;
+                }
+                do {
+
+                    b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+                    if((e&16)!=0){
+                        e &= 15;
+                        c = tp[tp_index_t_3+2] + ((int)b & inflate_mask[e]);
+
+                        b>>=e; k-=e;
+
+                        // decode distance base of block to copy
+                        while(k<(15)){           // max bits for distance code
+                            n--;
+                            b|=(z.next_in[p++]&0xff)<<k;k+=8;
+                        }
+
+                        t= b&md;
+                        tp=td;
+                        tp_index=td_index;
+                        tp_index_t_3=(tp_index+t)*3;
+                        e = tp[tp_index_t_3];
+
+                        do {
+
+                            b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+                            if((e&16)!=0){
+                                // get extra bits to add to distance base
+                                e &= 15;
+                                while(k<(e)){         // get extra bits (up to 13)
+                                    n--;
+                                    b|=(z.next_in[p++]&0xff)<<k;k+=8;
+                                }
+
+                                d = tp[tp_index_t_3+2] + (b&inflate_mask[e]);
+
+                                b>>=(e); k-=(e);
+
+                                // do the copy
+                                m -= c;
+                                if (q >= d){                // offset before dest
+                                    //  just copy
+                                    r=q-d;
+                                    if(q-r>0 && 2>(q-r)){           
+                                        s.window[q++]=s.window[r++]; // minimum count is three,
+                                        s.window[q++]=s.window[r++]; // so unroll loop a little
+                                        c-=2;
+                                    }
+                                    else{
+                                        System.Array.Copy(s.window, r, s.window, q, 2);
+                                        q+=2; r+=2; c-=2;
+                                    }
+                                }
+                                else{                  // else offset after destination
+                                    r=q-d;
+                                    do{
+                                        r+=s.end;          // force pointer in window
+                                    }while(r<0);         // covers invalid distances
+                                    e=s.end-r;
+                                    if(c>e){             // if source crosses,
+                                        c-=e;              // wrapped copy
+                                        if(q-r>0 && e>(q-r)){           
+                                            do{s.window[q++] = s.window[r++];}
+                                            while(--e!=0);
+                                        }
+                                        else{
+                                            System.Array.Copy(s.window, r, s.window, q, e);
+                                            q+=e; r+=e; e=0;
+                                        }
+                                        r = 0;                  // copy rest from start of window
+                                    }
+
+                                }
+
+                                // copy all or what's left
+                                if(q-r>0 && c>(q-r)){           
+                                    do{s.window[q++] = s.window[r++];}
+                                    while(--c!=0);
+                                }
+                                else{
+                                    System.Array.Copy(s.window, r, s.window, q, c);
+                                    q+=c; r+=c; c=0;
+                                }
+                                break;
+                            }
+                            else if((e&64)==0){
+                                t+=tp[tp_index_t_3+2];
+                                t+=(b&inflate_mask[e]);
+                                tp_index_t_3=(tp_index+t)*3;
+                                e=tp[tp_index_t_3];
+                            }
+                            else{
+                                z.msg = "invalid distance code";
+
+                                c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+
+                                s.bitb=b;s.bitk=k;
+                                z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                                s.write=q;
+
+                                return Z_DATA_ERROR;
+                            }
+                        }
+                        while(true);
+                        break;
+                    }
+
+                    if((e&64)==0){
+                        t+=tp[tp_index_t_3+2];
+                        t+=(b&inflate_mask[e]);
+                        tp_index_t_3=(tp_index+t)*3;
+                        if((e=tp[tp_index_t_3])==0){
+
+                            b>>=(tp[tp_index_t_3+1]); k-=(tp[tp_index_t_3+1]);
+
+                            s.window[q++]=(byte)tp[tp_index_t_3+2];
+                            m--;
+                            break;
+                        }
+                    }
+                    else if((e&32)!=0){
+
+                        c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+ 
+                        s.bitb=b;s.bitk=k;
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        s.write=q;
+
+                        return Z_STREAM_END;
+                    }
+                    else{
+                        z.msg="invalid literal/length code";
+
+                        c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+
+                        s.bitb=b;s.bitk=k;
+                        z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+                        s.write=q;
+
+                        return Z_DATA_ERROR;
+                    }
+                } 
+                while(true);
+            } 
+            while(m>=258 && n>= 10);
+
+            // not enough input or output--restore pointers and return
+            c=z.avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;
+
+            s.bitb=b;s.bitk=k;
+            z.avail_in=n;z.total_in+=p-z.next_in_index;z.next_in_index=p;
+            s.write=q;
+
+            return Z_OK;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/InfTree.cs b/crypto/src/util/zlib/InfTree.cs
new file mode 100644
index 000000000..6ed7d1920
--- /dev/null
+++ b/crypto/src/util/zlib/InfTree.cs
@@ -0,0 +1,523 @@
+using System;
+/*
+ * $Id: InfTree.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    internal sealed class InfTree{
+
+        private const int MANY=1440;
+
+        private const int Z_OK=0;
+        private const int Z_STREAM_END=1;
+        private const int Z_NEED_DICT=2;
+        private const int Z_ERRNO=-1;
+        private const int Z_STREAM_ERROR=-2;
+        private const int Z_DATA_ERROR=-3;
+        private const int Z_MEM_ERROR=-4;
+        private const int Z_BUF_ERROR=-5;
+        private const int Z_VERSION_ERROR=-6;
+
+        private const int fixed_bl = 9;
+        private const int fixed_bd = 5;
+
+		static readonly int[] fixed_tl = {
+                                    96,7,256, 0,8,80, 0,8,16, 84,8,115,
+                                    82,7,31, 0,8,112, 0,8,48, 0,9,192,
+                                    80,7,10, 0,8,96, 0,8,32, 0,9,160,
+                                    0,8,0, 0,8,128, 0,8,64, 0,9,224,
+                                    80,7,6, 0,8,88, 0,8,24, 0,9,144,
+                                    83,7,59, 0,8,120, 0,8,56, 0,9,208,
+                                    81,7,17, 0,8,104, 0,8,40, 0,9,176,
+                                    0,8,8, 0,8,136, 0,8,72, 0,9,240,
+                                    80,7,4, 0,8,84, 0,8,20, 85,8,227,
+                                    83,7,43, 0,8,116, 0,8,52, 0,9,200,
+                                    81,7,13, 0,8,100, 0,8,36, 0,9,168,
+                                    0,8,4, 0,8,132, 0,8,68, 0,9,232,
+                                    80,7,8, 0,8,92, 0,8,28, 0,9,152,
+                                    84,7,83, 0,8,124, 0,8,60, 0,9,216,
+                                    82,7,23, 0,8,108, 0,8,44, 0,9,184,
+                                    0,8,12, 0,8,140, 0,8,76, 0,9,248,
+                                    80,7,3, 0,8,82, 0,8,18, 85,8,163,
+                                    83,7,35, 0,8,114, 0,8,50, 0,9,196,
+                                    81,7,11, 0,8,98, 0,8,34, 0,9,164,
+                                    0,8,2, 0,8,130, 0,8,66, 0,9,228,
+                                    80,7,7, 0,8,90, 0,8,26, 0,9,148,
+                                    84,7,67, 0,8,122, 0,8,58, 0,9,212,
+                                    82,7,19, 0,8,106, 0,8,42, 0,9,180,
+                                    0,8,10, 0,8,138, 0,8,74, 0,9,244,
+                                    80,7,5, 0,8,86, 0,8,22, 192,8,0,
+                                    83,7,51, 0,8,118, 0,8,54, 0,9,204,
+                                    81,7,15, 0,8,102, 0,8,38, 0,9,172,
+                                    0,8,6, 0,8,134, 0,8,70, 0,9,236,
+                                    80,7,9, 0,8,94, 0,8,30, 0,9,156,
+                                    84,7,99, 0,8,126, 0,8,62, 0,9,220,
+                                    82,7,27, 0,8,110, 0,8,46, 0,9,188,
+                                    0,8,14, 0,8,142, 0,8,78, 0,9,252,
+                                    96,7,256, 0,8,81, 0,8,17, 85,8,131,
+                                    82,7,31, 0,8,113, 0,8,49, 0,9,194,
+                                    80,7,10, 0,8,97, 0,8,33, 0,9,162,
+                                    0,8,1, 0,8,129, 0,8,65, 0,9,226,
+                                    80,7,6, 0,8,89, 0,8,25, 0,9,146,
+                                    83,7,59, 0,8,121, 0,8,57, 0,9,210,
+                                    81,7,17, 0,8,105, 0,8,41, 0,9,178,
+                                    0,8,9, 0,8,137, 0,8,73, 0,9,242,
+                                    80,7,4, 0,8,85, 0,8,21, 80,8,258,
+                                    83,7,43, 0,8,117, 0,8,53, 0,9,202,
+                                    81,7,13, 0,8,101, 0,8,37, 0,9,170,
+                                    0,8,5, 0,8,133, 0,8,69, 0,9,234,
+                                    80,7,8, 0,8,93, 0,8,29, 0,9,154,
+                                    84,7,83, 0,8,125, 0,8,61, 0,9,218,
+                                    82,7,23, 0,8,109, 0,8,45, 0,9,186,
+                                    0,8,13, 0,8,141, 0,8,77, 0,9,250,
+                                    80,7,3, 0,8,83, 0,8,19, 85,8,195,
+                                    83,7,35, 0,8,115, 0,8,51, 0,9,198,
+                                    81,7,11, 0,8,99, 0,8,35, 0,9,166,
+                                    0,8,3, 0,8,131, 0,8,67, 0,9,230,
+                                    80,7,7, 0,8,91, 0,8,27, 0,9,150,
+                                    84,7,67, 0,8,123, 0,8,59, 0,9,214,
+                                    82,7,19, 0,8,107, 0,8,43, 0,9,182,
+                                    0,8,11, 0,8,139, 0,8,75, 0,9,246,
+                                    80,7,5, 0,8,87, 0,8,23, 192,8,0,
+                                    83,7,51, 0,8,119, 0,8,55, 0,9,206,
+                                    81,7,15, 0,8,103, 0,8,39, 0,9,174,
+                                    0,8,7, 0,8,135, 0,8,71, 0,9,238,
+                                    80,7,9, 0,8,95, 0,8,31, 0,9,158,
+                                    84,7,99, 0,8,127, 0,8,63, 0,9,222,
+                                    82,7,27, 0,8,111, 0,8,47, 0,9,190,
+                                    0,8,15, 0,8,143, 0,8,79, 0,9,254,
+                                    96,7,256, 0,8,80, 0,8,16, 84,8,115,
+                                    82,7,31, 0,8,112, 0,8,48, 0,9,193,
+
+                                    80,7,10, 0,8,96, 0,8,32, 0,9,161,
+                                    0,8,0, 0,8,128, 0,8,64, 0,9,225,
+                                    80,7,6, 0,8,88, 0,8,24, 0,9,145,
+                                    83,7,59, 0,8,120, 0,8,56, 0,9,209,
+                                    81,7,17, 0,8,104, 0,8,40, 0,9,177,
+                                    0,8,8, 0,8,136, 0,8,72, 0,9,241,
+                                    80,7,4, 0,8,84, 0,8,20, 85,8,227,
+                                    83,7,43, 0,8,116, 0,8,52, 0,9,201,
+                                    81,7,13, 0,8,100, 0,8,36, 0,9,169,
+                                    0,8,4, 0,8,132, 0,8,68, 0,9,233,
+                                    80,7,8, 0,8,92, 0,8,28, 0,9,153,
+                                    84,7,83, 0,8,124, 0,8,60, 0,9,217,
+                                    82,7,23, 0,8,108, 0,8,44, 0,9,185,
+                                    0,8,12, 0,8,140, 0,8,76, 0,9,249,
+                                    80,7,3, 0,8,82, 0,8,18, 85,8,163,
+                                    83,7,35, 0,8,114, 0,8,50, 0,9,197,
+                                    81,7,11, 0,8,98, 0,8,34, 0,9,165,
+                                    0,8,2, 0,8,130, 0,8,66, 0,9,229,
+                                    80,7,7, 0,8,90, 0,8,26, 0,9,149,
+                                    84,7,67, 0,8,122, 0,8,58, 0,9,213,
+                                    82,7,19, 0,8,106, 0,8,42, 0,9,181,
+                                    0,8,10, 0,8,138, 0,8,74, 0,9,245,
+                                    80,7,5, 0,8,86, 0,8,22, 192,8,0,
+                                    83,7,51, 0,8,118, 0,8,54, 0,9,205,
+                                    81,7,15, 0,8,102, 0,8,38, 0,9,173,
+                                    0,8,6, 0,8,134, 0,8,70, 0,9,237,
+                                    80,7,9, 0,8,94, 0,8,30, 0,9,157,
+                                    84,7,99, 0,8,126, 0,8,62, 0,9,221,
+                                    82,7,27, 0,8,110, 0,8,46, 0,9,189,
+                                    0,8,14, 0,8,142, 0,8,78, 0,9,253,
+                                    96,7,256, 0,8,81, 0,8,17, 85,8,131,
+                                    82,7,31, 0,8,113, 0,8,49, 0,9,195,
+                                    80,7,10, 0,8,97, 0,8,33, 0,9,163,
+                                    0,8,1, 0,8,129, 0,8,65, 0,9,227,
+                                    80,7,6, 0,8,89, 0,8,25, 0,9,147,
+                                    83,7,59, 0,8,121, 0,8,57, 0,9,211,
+                                    81,7,17, 0,8,105, 0,8,41, 0,9,179,
+                                    0,8,9, 0,8,137, 0,8,73, 0,9,243,
+                                    80,7,4, 0,8,85, 0,8,21, 80,8,258,
+                                    83,7,43, 0,8,117, 0,8,53, 0,9,203,
+                                    81,7,13, 0,8,101, 0,8,37, 0,9,171,
+                                    0,8,5, 0,8,133, 0,8,69, 0,9,235,
+                                    80,7,8, 0,8,93, 0,8,29, 0,9,155,
+                                    84,7,83, 0,8,125, 0,8,61, 0,9,219,
+                                    82,7,23, 0,8,109, 0,8,45, 0,9,187,
+                                    0,8,13, 0,8,141, 0,8,77, 0,9,251,
+                                    80,7,3, 0,8,83, 0,8,19, 85,8,195,
+                                    83,7,35, 0,8,115, 0,8,51, 0,9,199,
+                                    81,7,11, 0,8,99, 0,8,35, 0,9,167,
+                                    0,8,3, 0,8,131, 0,8,67, 0,9,231,
+                                    80,7,7, 0,8,91, 0,8,27, 0,9,151,
+                                    84,7,67, 0,8,123, 0,8,59, 0,9,215,
+                                    82,7,19, 0,8,107, 0,8,43, 0,9,183,
+                                    0,8,11, 0,8,139, 0,8,75, 0,9,247,
+                                    80,7,5, 0,8,87, 0,8,23, 192,8,0,
+                                    83,7,51, 0,8,119, 0,8,55, 0,9,207,
+                                    81,7,15, 0,8,103, 0,8,39, 0,9,175,
+                                    0,8,7, 0,8,135, 0,8,71, 0,9,239,
+                                    80,7,9, 0,8,95, 0,8,31, 0,9,159,
+                                    84,7,99, 0,8,127, 0,8,63, 0,9,223,
+                                    82,7,27, 0,8,111, 0,8,47, 0,9,191,
+                                    0,8,15, 0,8,143, 0,8,79, 0,9,255
+                                };
+        static readonly int[] fixed_td = {
+                                    80,5,1, 87,5,257, 83,5,17, 91,5,4097,
+                                    81,5,5, 89,5,1025, 85,5,65, 93,5,16385,
+                                    80,5,3, 88,5,513, 84,5,33, 92,5,8193,
+                                    82,5,9, 90,5,2049, 86,5,129, 192,5,24577,
+                                    80,5,2, 87,5,385, 83,5,25, 91,5,6145,
+                                    81,5,7, 89,5,1537, 85,5,97, 93,5,24577,
+                                    80,5,4, 88,5,769, 84,5,49, 92,5,12289,
+                                    82,5,13, 90,5,3073, 86,5,193, 192,5,24577
+                                };
+
+        // Tables for deflate from PKZIP's appnote.txt.
+        static readonly int[] cplens = { // Copy lengths for literal codes 257..285
+                                  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+                                  35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
+                              };
+
+        // see note #13 above about 258
+        static readonly int[] cplext = { // Extra bits for literal codes 257..285
+                                  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+                                  3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112  // 112==invalid
+                              };
+
+        static readonly int[] cpdist = { // Copy offsets for distance codes 0..29
+                                  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+                                  257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+                                  8193, 12289, 16385, 24577
+                              };
+
+        static readonly int[] cpdext = { // Extra bits for distance codes
+                                  0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+                                  7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+                                  12, 12, 13, 13};
+
+        // If BMAX needs to be larger than 16, then h and x[] should be uLong.
+        const int BMAX=15;         // maximum bit length of any code
+
+        int[] hn = null;  // hufts used in space
+        int[] v = null;   // work area for huft_build 
+        int[] c = null;   // bit length count table
+        int[] r = null;   // table entry for structure assignment
+        int[] u = null;   // table stack
+        int[] x = null;   // bit offsets, then code stack
+
+        private int huft_build(int[] b, // code lengths in bits (all assumed <= BMAX)
+            int bindex, 
+            int n,   // number of codes (assumed <= 288)
+            int s,   // number of simple-valued codes (0..s-1)
+            int[] d, // list of base values for non-simple codes
+            int[] e, // list of extra bits for non-simple codes
+            int[] t, // result: starting table
+            int[] m, // maximum lookup bits, returns actual
+            int[] hp,// space for trees
+            int[] hn,// hufts used in space
+            int[] v  // working area: values in order of bit length
+            ){
+            // Given a list of code lengths and a maximum table size, make a set of
+            // tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+            // if the given code set is incomplete (the tables are still built in this
+            // case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+            // lengths), or Z_MEM_ERROR if not enough memory.
+
+            int a;                       // counter for codes of length k
+            int f;                       // i repeats in table every f entries
+            int g;                       // maximum code length
+            int h;                       // table level
+            int i;                       // counter, current code
+            int j;                       // counter
+            int k;                       // number of bits in current code
+            int l;                       // bits per table (returned in m)
+            int mask;                    // (1 << w) - 1, to avoid cc -O bug on HP
+            int p;                       // pointer into c[], b[], or v[]
+            int q;                       // points to current table
+            int w;                       // bits before this table == (l * h)
+            int xp;                      // pointer into x
+            int y;                       // number of dummy codes added
+            int z;                       // number of entries in current table
+
+            // Generate counts for each bit length
+
+            p = 0; i = n;
+            do {
+                c[b[bindex+p]]++; p++; i--;   // assume all entries <= BMAX
+            }while(i!=0);
+
+            if(c[0] == n){                // null input--all zero length codes
+                t[0] = -1;
+                m[0] = 0;
+                return Z_OK;
+            }
+
+            // Find minimum and maximum length, bound *m by those
+            l = m[0];
+            for (j = 1; j <= BMAX; j++)
+                if(c[j]!=0) break;
+            k = j;                        // minimum code length
+            if(l < j){
+                l = j;
+            }
+            for (i = BMAX; i!=0; i--){
+                if(c[i]!=0) break;
+            }
+            g = i;                        // maximum code length
+            if(l > i){
+                l = i;
+            }
+            m[0] = l;
+
+            // Adjust last length count to fill out codes, if needed
+            for (y = 1 << j; j < i; j++, y <<= 1){
+                if ((y -= c[j]) < 0){
+                    return Z_DATA_ERROR;
+                }
+            }
+            if ((y -= c[i]) < 0){
+                return Z_DATA_ERROR;
+            }
+            c[i] += y;
+
+            // Generate starting offsets into the value table for each length
+            x[1] = j = 0;
+            p = 1;  xp = 2;
+            while (--i!=0) {                 // note that i == g from above
+                x[xp] = (j += c[p]);
+                xp++;
+                p++;
+            }
+
+            // Make a table of values in order of bit lengths
+            i = 0; p = 0;
+            do {
+                if ((j = b[bindex+p]) != 0){
+                    v[x[j]++] = i;
+                }
+                p++;
+            }
+            while (++i < n);
+            n = x[g];                     // set n to length of v
+
+            // Generate the Huffman codes and for each, make the table entries
+            x[0] = i = 0;                 // first Huffman code is zero
+            p = 0;                        // grab values in bit order
+            h = -1;                       // no tables yet--level -1
+            w = -l;                       // bits decoded == (l * h)
+            u[0] = 0;                     // just to keep compilers happy
+            q = 0;                        // ditto
+            z = 0;                        // ditto
+
+            // go through the bit lengths (k already is bits in shortest code)
+            for (; k <= g; k++){
+                a = c[k];
+                while (a--!=0){
+                    // here i is the Huffman code of length k bits for value *p
+                    // make tables up to required level
+                    while (k > w + l){
+                        h++;
+                        w += l;                 // previous table always l bits
+                        // compute minimum size table less than or equal to l bits
+                        z = g - w;
+                        z = (z > l) ? l : z;        // table size upper limit
+                        if((f=1<<(j=k-w))>a+1){     // try a k-w bit table
+                            // too few codes for k-w bit table
+                            f -= a + 1;               // deduct codes from patterns left
+                            xp = k;
+                            if(j < z){
+                                while (++j < z){        // try smaller tables up to z bits
+                                    if((f <<= 1) <= c[++xp])
+                                        break;              // enough codes to use up j bits
+                                    f -= c[xp];           // else deduct codes from patterns
+                                }
+                            }
+                        }
+                        z = 1 << j;                 // table entries for j-bit table
+
+                        // allocate new table
+                        if (hn[0] + z > MANY){       // (note: doesn't matter for fixed)
+                            return Z_DATA_ERROR;       // overflow of MANY
+                        }
+                        u[h] = q = /*hp+*/ hn[0];   // DEBUG
+                        hn[0] += z;
+ 
+                        // connect to last table, if there is one
+                        if(h!=0){
+                            x[h]=i;           // save pattern for backing up
+                            r[0]=(byte)j;     // bits in this table
+                            r[1]=(byte)l;     // bits to dump before this table
+                            j=i>>(w - l);
+                            r[2] = (int)(q - u[h-1] - j);               // offset to this table
+                            System.Array.Copy(r, 0, hp, (u[h-1]+j)*3, 3); // connect to last table
+                        }
+                        else{
+                            t[0] = q;               // first table is returned result
+                        }
+                    }
+
+                    // set up table entry in r
+                    r[1] = (byte)(k - w);
+                    if (p >= n){
+                        r[0] = 128 + 64;      // out of values--invalid code
+                    }
+                    else if (v[p] < s){
+                        r[0] = (byte)(v[p] < 256 ? 0 : 32 + 64);  // 256 is end-of-block
+                        r[2] = v[p++];          // simple code is just the value
+                    }
+                    else{
+                        r[0]=(byte)(e[v[p]-s]+16+64); // non-simple--look up in lists
+                        r[2]=d[v[p++] - s];
+                    }
+
+                    // fill code-like entries with r
+                    f=1<<(k-w);
+                    for (j=i>>w;j<z;j+=f){
+                        System.Array.Copy(r, 0, hp, (q+j)*3, 3);
+                    }
+
+                    // backwards increment the k-bit code i
+                    for (j = 1 << (k - 1); (i & j)!=0; j >>= 1){
+                        i ^= j;
+                    }
+                    i ^= j;
+
+                    // backup over finished tables
+                    mask = (1 << w) - 1;      // needed on HP, cc -O bug
+                    while ((i & mask) != x[h]){
+                        h--;                    // don't need to update q
+                        w -= l;
+                        mask = (1 << w) - 1;
+                    }
+                }
+            }
+            // Return Z_BUF_ERROR if we were given an incomplete table
+            return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+        }
+
+        internal int inflate_trees_bits(int[] c,  // 19 code lengths
+            int[] bb, // bits tree desired/actual depth
+            int[] tb, // bits tree result
+            int[] hp, // space for trees
+            ZStream z // for messages
+            ){
+            int result;
+            initWorkArea(19);
+            hn[0]=0;
+            result = huft_build(c, 0, 19, 19, null, null, tb, bb, hp, hn, v);
+
+            if(result == Z_DATA_ERROR){
+                z.msg = "oversubscribed dynamic bit lengths tree";
+            }
+            else if(result == Z_BUF_ERROR || bb[0] == 0){
+                z.msg = "incomplete dynamic bit lengths tree";
+                result = Z_DATA_ERROR;
+            }
+            return result;
+        }
+
+        internal int inflate_trees_dynamic(int nl,   // number of literal/length codes
+            int nd,   // number of distance codes
+            int[] c,  // that many (total) code lengths
+            int[] bl, // literal desired/actual bit depth
+            int[] bd, // distance desired/actual bit depth 
+            int[] tl, // literal/length tree result
+            int[] td, // distance tree result
+            int[] hp, // space for trees
+            ZStream z // for messages
+            ){
+            int result;
+
+            // build literal/length tree
+            initWorkArea(288);
+            hn[0]=0;
+            result = huft_build(c, 0, nl, 257, cplens, cplext, tl, bl, hp, hn, v);
+            if (result != Z_OK || bl[0] == 0){
+                if(result == Z_DATA_ERROR){
+                    z.msg = "oversubscribed literal/length tree";
+                }
+                else if (result != Z_MEM_ERROR){
+                    z.msg = "incomplete literal/length tree";
+                    result = Z_DATA_ERROR;
+                }
+                return result;
+            }
+
+            // build distance tree
+            initWorkArea(288);
+            result = huft_build(c, nl, nd, 0, cpdist, cpdext, td, bd, hp, hn, v);
+
+            if (result != Z_OK || (bd[0] == 0 && nl > 257)){
+                if (result == Z_DATA_ERROR){
+                    z.msg = "oversubscribed distance tree";
+                }
+                else if (result == Z_BUF_ERROR) {
+                    z.msg = "incomplete distance tree";
+                    result = Z_DATA_ERROR;
+                }
+                else if (result != Z_MEM_ERROR){
+                    z.msg = "empty distance tree with lengths";
+                    result = Z_DATA_ERROR;
+                }
+                return result;
+            }
+
+            return Z_OK;
+        }
+
+        internal static int inflate_trees_fixed(int[] bl,  //literal desired/actual bit depth
+            int[] bd,  //distance desired/actual bit depth
+            int[][] tl,//literal/length tree result
+            int[][] td,//distance tree result 
+            ZStream z  //for memory allocation
+            ){
+            bl[0]=fixed_bl;
+            bd[0]=fixed_bd;
+            tl[0]=fixed_tl;
+            td[0]=fixed_td;
+            return Z_OK;
+        }
+
+        private void initWorkArea(int vsize){
+            if(hn==null){
+                hn=new int[1];
+                v=new int[vsize];
+                c=new int[BMAX+1];
+                r=new int[3];
+                u=new int[BMAX];
+                x=new int[BMAX+1];
+            }
+            if(v.Length<vsize){ v=new int[vsize]; }
+            for(int i=0; i<vsize; i++){v[i]=0;}
+            for(int i=0; i<BMAX+1; i++){c[i]=0;}
+            for(int i=0; i<3; i++){r[i]=0;}
+            //  for(int i=0; i<BMAX; i++){u[i]=0;}
+            System.Array.Copy(c, 0, u, 0, BMAX);
+            //  for(int i=0; i<BMAX+1; i++){x[i]=0;}
+            System.Array.Copy(c, 0, x, 0, BMAX+1);
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/Inflate.cs b/crypto/src/util/zlib/Inflate.cs
new file mode 100644
index 000000000..ac8789332
--- /dev/null
+++ b/crypto/src/util/zlib/Inflate.cs
@@ -0,0 +1,387 @@
+using System;
+/*
+ * $Id: Inflate.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    internal sealed class Inflate{
+  
+        private const int MAX_WBITS=15; // 32K LZ77 window
+
+        // preset dictionary flag in zlib header
+        private const int PRESET_DICT=0x20;
+
+        internal const int Z_NO_FLUSH=0;
+        internal const int Z_PARTIAL_FLUSH=1;
+        internal const int Z_SYNC_FLUSH=2;
+        internal const int Z_FULL_FLUSH=3;
+        internal const int Z_FINISH=4;
+
+        private const int Z_DEFLATED=8;
+
+        private const int Z_OK=0;
+        private const int Z_STREAM_END=1;
+        private const int Z_NEED_DICT=2;
+        private const int Z_ERRNO=-1;
+        private const int Z_STREAM_ERROR=-2;
+        private const int Z_DATA_ERROR=-3;
+        private const int Z_MEM_ERROR=-4;
+        private const int Z_BUF_ERROR=-5;
+        private const int Z_VERSION_ERROR=-6;
+
+        private const int METHOD=0;   // waiting for method byte
+        private const int FLAG=1;     // waiting for flag byte
+        private const int DICT4=2;    // four dictionary check bytes to go
+        private const int DICT3=3;    // three dictionary check bytes to go
+        private const int DICT2=4;    // two dictionary check bytes to go
+        private const int DICT1=5;    // one dictionary check byte to go
+        private const int DICT0=6;    // waiting for inflateSetDictionary
+        private const int BLOCKS=7;   // decompressing blocks
+        private const int CHECK4=8;   // four check bytes to go
+        private const int CHECK3=9;   // three check bytes to go
+        private const int CHECK2=10;  // two check bytes to go
+        private const int CHECK1=11;  // one check byte to go
+        private const int DONE=12;    // finished check, done
+        private const int BAD=13;     // got an error--stay here
+
+        internal int mode;                            // current inflate mode
+
+        // mode dependent information
+        internal int method;        // if FLAGS, method byte
+
+        // if CHECK, check values to compare
+        internal long[] was=new long[1] ; // computed check value
+        internal long need;               // stream check value
+
+        // if BAD, inflateSync's marker bytes count
+        internal int marker;
+
+        // mode independent information
+        internal int  nowrap;          // flag for no wrapper
+        internal int wbits;            // log2(window size)  (8..15, defaults to 15)
+
+        internal InfBlocks blocks;     // current inflate_blocks state
+
+        internal int inflateReset(ZStream z){
+            if(z == null || z.istate == null) return Z_STREAM_ERROR;
+    
+            z.total_in = z.total_out = 0;
+            z.msg = null;
+            z.istate.mode = z.istate.nowrap!=0 ? BLOCKS : METHOD;
+            z.istate.blocks.reset(z, null);
+            return Z_OK;
+        }
+
+        internal int inflateEnd(ZStream z){
+            if(blocks != null)
+                blocks.free(z);
+            blocks=null;
+            //    ZFREE(z, z->state);
+            return Z_OK;
+        }
+
+        internal int inflateInit(ZStream z, int w){
+            z.msg = null;
+            blocks = null;
+
+            // handle undocumented nowrap option (no zlib header or check)
+            nowrap = 0;
+            if(w < 0){
+                w = - w;
+                nowrap = 1;
+            }
+
+            // set window size
+            if(w<8 ||w>15){
+                inflateEnd(z);
+                return Z_STREAM_ERROR;
+            }
+            wbits=w;
+
+            z.istate.blocks=new InfBlocks(z, 
+                z.istate.nowrap!=0 ? null : this,
+                1<<w);
+
+            // reset state
+            inflateReset(z);
+            return Z_OK;
+        }
+
+        internal int inflate(ZStream z, int f){
+            int r;
+            int b;
+
+            if(z == null || z.istate == null || z.next_in == null)
+                return Z_STREAM_ERROR;
+            f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+            r = Z_BUF_ERROR;
+            while (true){
+                //System.out.println("mode: "+z.istate.mode);
+                switch (z.istate.mode){
+                    case METHOD:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        if(((z.istate.method = z.next_in[z.next_in_index++])&0xf)!=Z_DEFLATED){
+                            z.istate.mode = BAD;
+                            z.msg="unknown compression method";
+                            z.istate.marker = 5;       // can't try inflateSync
+                            break;
+                        }
+                        if((z.istate.method>>4)+8>z.istate.wbits){
+                            z.istate.mode = BAD;
+                            z.msg="invalid window size";
+                            z.istate.marker = 5;       // can't try inflateSync
+                            break;
+                        }
+                        z.istate.mode=FLAG;
+                        goto case FLAG;
+                    case FLAG:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        b = (z.next_in[z.next_in_index++])&0xff;
+
+                        if((((z.istate.method << 8)+b) % 31)!=0){
+                            z.istate.mode = BAD;
+                            z.msg = "incorrect header check";
+                            z.istate.marker = 5;       // can't try inflateSync
+                            break;
+                        }
+
+                        if((b&PRESET_DICT)==0){
+                            z.istate.mode = BLOCKS;
+                            break;
+                        }
+                        z.istate.mode = DICT4;
+                        goto case DICT4;
+                    case DICT4:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+                        z.istate.mode=DICT3;
+                        goto case DICT3;
+                    case DICT3:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+                        z.istate.mode=DICT2;
+                        goto case DICT2;
+                    case DICT2:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+                        z.istate.mode=DICT1;
+                        goto case DICT1;
+                    case DICT1:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need += (z.next_in[z.next_in_index++]&0xffL);
+                        z.adler = z.istate.need;
+                        z.istate.mode = DICT0;
+                        return Z_NEED_DICT;
+                    case DICT0:
+                        z.istate.mode = BAD;
+                        z.msg = "need dictionary";
+                        z.istate.marker = 0;       // can try inflateSync
+                        return Z_STREAM_ERROR;
+                    case BLOCKS:
+
+                        r = z.istate.blocks.proc(z, r);
+                        if(r == Z_DATA_ERROR){
+                            z.istate.mode = BAD;
+                            z.istate.marker = 0;     // can try inflateSync
+                            break;
+                        }
+                        if(r == Z_OK){
+                            r = f;
+                        }
+                        if(r != Z_STREAM_END){
+                            return r;
+                        }
+                        r = f;
+                        z.istate.blocks.reset(z, z.istate.was);
+                        if(z.istate.nowrap!=0){
+                            z.istate.mode=DONE;
+                            break;
+                        }
+                        z.istate.mode=CHECK4;
+                        goto case CHECK4;
+                    case CHECK4:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need=((z.next_in[z.next_in_index++]&0xff)<<24)&0xff000000L;
+                        z.istate.mode=CHECK3;
+                        goto case CHECK3;
+                    case CHECK3:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<16)&0xff0000L;
+                        z.istate.mode = CHECK2;
+                        goto case CHECK2;
+                    case CHECK2:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need+=((z.next_in[z.next_in_index++]&0xff)<<8)&0xff00L;
+                        z.istate.mode = CHECK1;
+                        goto case CHECK1;
+                    case CHECK1:
+
+                        if(z.avail_in==0)return r;r=f;
+
+                        z.avail_in--; z.total_in++;
+                        z.istate.need+=(z.next_in[z.next_in_index++]&0xffL);
+
+                        if(((int)(z.istate.was[0])) != ((int)(z.istate.need))){
+                            z.istate.mode = BAD;
+                            z.msg = "incorrect data check";
+                            z.istate.marker = 5;       // can't try inflateSync
+                            break;
+                        }
+
+                        z.istate.mode = DONE;
+                        goto case DONE;
+                    case DONE:
+                        return Z_STREAM_END;
+                    case BAD:
+                        return Z_DATA_ERROR;
+                    default:
+                        return Z_STREAM_ERROR;
+                }
+            }
+        }
+
+
+        internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength){
+            int index=0;
+            int length = dictLength;
+            if(z==null || z.istate == null|| z.istate.mode != DICT0)
+                return Z_STREAM_ERROR;
+
+            if(z._adler.adler32(1L, dictionary, 0, dictLength)!=z.adler){
+                return Z_DATA_ERROR;
+            }
+
+            z.adler = z._adler.adler32(0, null, 0, 0);
+
+            if(length >= (1<<z.istate.wbits)){
+                length = (1<<z.istate.wbits)-1;
+                index=dictLength - length;
+            }
+            z.istate.blocks.set_dictionary(dictionary, index, length);
+            z.istate.mode = BLOCKS;
+            return Z_OK;
+        }
+
+        private static readonly byte[] mark = {(byte)0, (byte)0, (byte)0xff, (byte)0xff};
+
+        internal int inflateSync(ZStream z){
+            int n;       // number of bytes to look at
+            int p;       // pointer to bytes
+            int m;       // number of marker bytes found in a row
+            long r, w;   // temporaries to save total_in and total_out
+
+            // set up
+            if(z == null || z.istate == null)
+                return Z_STREAM_ERROR;
+            if(z.istate.mode != BAD){
+                z.istate.mode = BAD;
+                z.istate.marker = 0;
+            }
+            if((n=z.avail_in)==0)
+                return Z_BUF_ERROR;
+            p=z.next_in_index;
+            m=z.istate.marker;
+
+            // search
+            while (n!=0 && m < 4){
+                if(z.next_in[p] == mark[m]){
+                    m++;
+                }
+                else if(z.next_in[p]!=0){
+                    m = 0;
+                }
+                else{
+                    m = 4 - m;
+                }
+                p++; n--;
+            }
+
+            // restore
+            z.total_in += p-z.next_in_index;
+            z.next_in_index = p;
+            z.avail_in = n;
+            z.istate.marker = m;
+
+            // return no joy or set up to restart on a new block
+            if(m != 4){
+                return Z_DATA_ERROR;
+            }
+            r=z.total_in;  w=z.total_out;
+            inflateReset(z);
+            z.total_in=r;  z.total_out = w;
+            z.istate.mode = BLOCKS;
+            return Z_OK;
+        }
+
+        // Returns true if inflate is currently at the end of a block generated
+        // by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+        // implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
+        // but removes the length bytes of the resulting empty stored block. When
+        // decompressing, PPP checks that at the end of input packet, inflate is
+        // waiting for these length bytes.
+        internal int inflateSyncPoint(ZStream z){
+            if(z == null || z.istate == null || z.istate.blocks == null)
+                return Z_STREAM_ERROR;
+            return z.istate.blocks.sync_point();
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/JZlib.cs b/crypto/src/util/zlib/JZlib.cs
new file mode 100644
index 000000000..4f2cfdaa9
--- /dev/null
+++ b/crypto/src/util/zlib/JZlib.cs
@@ -0,0 +1,73 @@
+using System;
+/*
+ * $Id: JZlib.cs,v 1.3 2011-02-15 05:46:04 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    public sealed class JZlib{
+        private const String _version="1.0.7";
+        public static String version()
+		{
+			return _version;
+		}
+
+        // compression levels
+        public const int Z_NO_COMPRESSION=0;
+        public const int Z_BEST_SPEED=1;
+        public const int Z_BEST_COMPRESSION=9;
+        public const int Z_DEFAULT_COMPRESSION=-1;
+
+        // compression strategy
+        public const int Z_FILTERED=1;
+        public const int Z_HUFFMAN_ONLY=2;
+        public const int Z_DEFAULT_STRATEGY=0;
+
+        public const int Z_NO_FLUSH=0;
+        public const int Z_PARTIAL_FLUSH=1;
+        public const int Z_SYNC_FLUSH=2;
+        public const int Z_FULL_FLUSH=3;
+        public const int Z_FINISH=4;
+
+        public const int Z_OK=0;
+        public const int Z_STREAM_END=1;
+        public const int Z_NEED_DICT=2;
+        public const int Z_ERRNO=-1;
+        public const int Z_STREAM_ERROR=-2;
+        public const int Z_DATA_ERROR=-3;
+        public const int Z_MEM_ERROR=-4;
+        public const int Z_BUF_ERROR=-5;
+        public const int Z_VERSION_ERROR=-6;
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/StaticTree.cs b/crypto/src/util/zlib/StaticTree.cs
new file mode 100644
index 000000000..097735db5
--- /dev/null
+++ b/crypto/src/util/zlib/StaticTree.cs
@@ -0,0 +1,152 @@
+using System;
+/*
+ * $Id: StaticTree.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    internal sealed class StaticTree{
+        private const int MAX_BITS=15;
+
+        private const int BL_CODES=19;
+        private const int D_CODES=30;
+        private const int LITERALS=256;
+        private const int LENGTH_CODES=29;
+        private const int L_CODES=(LITERALS+1+LENGTH_CODES);
+
+        // Bit length codes must not exceed MAX_BL_BITS bits
+        internal const int MAX_BL_BITS=7; 
+
+        internal static readonly short[] static_ltree = {
+                                                   12,  8, 140,  8,  76,  8, 204,  8,  44,  8,
+                                                   172,  8, 108,  8, 236,  8,  28,  8, 156,  8,
+                                                   92,  8, 220,  8,  60,  8, 188,  8, 124,  8,
+                                                   252,  8,   2,  8, 130,  8,  66,  8, 194,  8,
+                                                   34,  8, 162,  8,  98,  8, 226,  8,  18,  8,
+                                                   146,  8,  82,  8, 210,  8,  50,  8, 178,  8,
+                                                   114,  8, 242,  8,  10,  8, 138,  8,  74,  8,
+                                                   202,  8,  42,  8, 170,  8, 106,  8, 234,  8,
+                                                   26,  8, 154,  8,  90,  8, 218,  8,  58,  8,
+                                                   186,  8, 122,  8, 250,  8,   6,  8, 134,  8,
+                                                   70,  8, 198,  8,  38,  8, 166,  8, 102,  8,
+                                                   230,  8,  22,  8, 150,  8,  86,  8, 214,  8,
+                                                   54,  8, 182,  8, 118,  8, 246,  8,  14,  8,
+                                                   142,  8,  78,  8, 206,  8,  46,  8, 174,  8,
+                                                   110,  8, 238,  8,  30,  8, 158,  8,  94,  8,
+                                                   222,  8,  62,  8, 190,  8, 126,  8, 254,  8,
+                                                   1,  8, 129,  8,  65,  8, 193,  8,  33,  8,
+                                                   161,  8,  97,  8, 225,  8,  17,  8, 145,  8,
+                                                   81,  8, 209,  8,  49,  8, 177,  8, 113,  8,
+                                                   241,  8,   9,  8, 137,  8,  73,  8, 201,  8,
+                                                   41,  8, 169,  8, 105,  8, 233,  8,  25,  8,
+                                                   153,  8,  89,  8, 217,  8,  57,  8, 185,  8,
+                                                   121,  8, 249,  8,   5,  8, 133,  8,  69,  8,
+                                                   197,  8,  37,  8, 165,  8, 101,  8, 229,  8,
+                                                   21,  8, 149,  8,  85,  8, 213,  8,  53,  8,
+                                                   181,  8, 117,  8, 245,  8,  13,  8, 141,  8,
+                                                   77,  8, 205,  8,  45,  8, 173,  8, 109,  8,
+                                                   237,  8,  29,  8, 157,  8,  93,  8, 221,  8,
+                                                   61,  8, 189,  8, 125,  8, 253,  8,  19,  9,
+                                                   275,  9, 147,  9, 403,  9,  83,  9, 339,  9,
+                                                   211,  9, 467,  9,  51,  9, 307,  9, 179,  9,
+                                                   435,  9, 115,  9, 371,  9, 243,  9, 499,  9,
+                                                   11,  9, 267,  9, 139,  9, 395,  9,  75,  9,
+                                                   331,  9, 203,  9, 459,  9,  43,  9, 299,  9,
+                                                   171,  9, 427,  9, 107,  9, 363,  9, 235,  9,
+                                                   491,  9,  27,  9, 283,  9, 155,  9, 411,  9,
+                                                   91,  9, 347,  9, 219,  9, 475,  9,  59,  9,
+                                                   315,  9, 187,  9, 443,  9, 123,  9, 379,  9,
+                                                   251,  9, 507,  9,   7,  9, 263,  9, 135,  9,
+                                                   391,  9,  71,  9, 327,  9, 199,  9, 455,  9,
+                                                   39,  9, 295,  9, 167,  9, 423,  9, 103,  9,
+                                                   359,  9, 231,  9, 487,  9,  23,  9, 279,  9,
+                                                   151,  9, 407,  9,  87,  9, 343,  9, 215,  9,
+                                                   471,  9,  55,  9, 311,  9, 183,  9, 439,  9,
+                                                   119,  9, 375,  9, 247,  9, 503,  9,  15,  9,
+                                                   271,  9, 143,  9, 399,  9,  79,  9, 335,  9,
+                                                   207,  9, 463,  9,  47,  9, 303,  9, 175,  9,
+                                                   431,  9, 111,  9, 367,  9, 239,  9, 495,  9,
+                                                   31,  9, 287,  9, 159,  9, 415,  9,  95,  9,
+                                                   351,  9, 223,  9, 479,  9,  63,  9, 319,  9,
+                                                   191,  9, 447,  9, 127,  9, 383,  9, 255,  9,
+                                                   511,  9,   0,  7,  64,  7,  32,  7,  96,  7,
+                                                   16,  7,  80,  7,  48,  7, 112,  7,   8,  7,
+                                                   72,  7,  40,  7, 104,  7,  24,  7,  88,  7,
+                                                   56,  7, 120,  7,   4,  7,  68,  7,  36,  7,
+                                                   100,  7,  20,  7,  84,  7,  52,  7, 116,  7,
+                                                   3,  8, 131,  8,  67,  8, 195,  8,  35,  8,
+                                                   163,  8,  99,  8, 227,  8
+                                               };
+
+        internal static readonly short[] static_dtree = {
+                                                   0, 5, 16, 5,  8, 5, 24, 5,  4, 5,
+                                                   20, 5, 12, 5, 28, 5,  2, 5, 18, 5,
+                                                   10, 5, 26, 5,  6, 5, 22, 5, 14, 5,
+                                                   30, 5,  1, 5, 17, 5,  9, 5, 25, 5,
+                                                   5, 5, 21, 5, 13, 5, 29, 5,  3, 5,
+                                                   19, 5, 11, 5, 27, 5,  7, 5, 23, 5
+                                               };
+
+        internal static readonly StaticTree static_l_desc =
+            new StaticTree(static_ltree, Tree.extra_lbits,
+            LITERALS+1, L_CODES, MAX_BITS);
+
+        internal static readonly StaticTree static_d_desc =
+            new StaticTree(static_dtree, Tree.extra_dbits,
+            0,  D_CODES, MAX_BITS);
+
+        internal static readonly StaticTree static_bl_desc =
+            new StaticTree(null, Tree.extra_blbits,
+            0, BL_CODES, MAX_BL_BITS);
+
+        internal short[] static_tree;     // static tree or null
+        internal int[] extra_bits;        // extra bits for each code or null
+        internal int extra_base;          // base index for extra_bits
+        internal int elems;               // max number of elements in the tree
+        internal int max_length;          // max bit length for the codes
+
+        internal StaticTree(short[] static_tree,
+            int[] extra_bits,
+            int extra_base,
+            int elems,
+            int max_length
+            ){
+            this.static_tree=static_tree;
+            this.extra_bits=extra_bits;
+            this.extra_base=extra_base;
+            this.elems=elems;
+            this.max_length=max_length;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/Tree.cs b/crypto/src/util/zlib/Tree.cs
new file mode 100644
index 000000000..29d0a30d4
--- /dev/null
+++ b/crypto/src/util/zlib/Tree.cs
@@ -0,0 +1,367 @@
+using System;
+/*
+ * $Id: Tree.cs,v 1.2 2008-05-10 09:35:40 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    internal sealed class Tree{
+        private const int MAX_BITS=15;
+        private const int BL_CODES=19;
+        private const int D_CODES=30;
+        private const int LITERALS=256;
+        private const int LENGTH_CODES=29;
+        private const int L_CODES=(LITERALS+1+LENGTH_CODES);
+        private const int HEAP_SIZE=(2*L_CODES+1);
+
+        // Bit length codes must not exceed MAX_BL_BITS bits
+        internal const int MAX_BL_BITS=7; 
+
+        // end of block literal code
+        internal const int END_BLOCK=256; 
+
+        // repeat previous bit length 3-6 times (2 bits of repeat count)
+        internal const int REP_3_6=16; 
+
+        // repeat a zero length 3-10 times  (3 bits of repeat count)
+        internal const int REPZ_3_10=17; 
+
+        // repeat a zero length 11-138 times  (7 bits of repeat count)
+        internal const int REPZ_11_138=18; 
+
+        // extra bits for each length code
+        internal static readonly int[] extra_lbits={
+                                             0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0
+                                         };
+
+        // extra bits for each distance code
+        internal static readonly int[] extra_dbits={
+                                             0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13
+                                         };
+
+        // extra bits for each bit length code
+        internal static readonly int[] extra_blbits={
+                                              0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7
+                                          };
+
+        internal static readonly byte[] bl_order={
+                                            16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+
+
+        // The lengths of the bit length codes are sent in order of decreasing
+        // probability, to avoid transmitting the lengths for unused bit
+        // length codes.
+
+        internal const int Buf_size=8*2;
+
+        // see definition of array dist_code below
+        internal const int DIST_CODE_LEN=512;
+
+        internal static readonly byte[] _dist_code = {
+                                                0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+                                                8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+                                                10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+                                                11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+                                                12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+                                                13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+                                                13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+                                                14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+                                                14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+                                                14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+                                                15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+                                                15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+                                                15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+                                                18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+                                                23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+                                                24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+                                                26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+                                                26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+                                                27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+                                                27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+                                                28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+                                                28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+                                                28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+                                                29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+                                                29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+                                                29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+                                            };
+
+        internal static readonly byte[] _length_code={
+                                                0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+                                                13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+                                                17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+                                                19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+                                                21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+                                                22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+                                                23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+                                                24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+                                                25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+                                                25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+                                                26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+                                                26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+                                                27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+                                            };
+
+        internal static readonly int[] base_length = {
+                                               0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+                                               64, 80, 96, 112, 128, 160, 192, 224, 0
+                                           };
+
+        internal static readonly int[] base_dist = {
+                                             0,   1,      2,     3,     4,    6,     8,    12,    16,     24,
+                                             32,  48,     64,    96,   128,  192,   256,   384,   512,    768,
+                                             1024, 1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+                                         };
+
+        // Mapping from a distance to a distance code. dist is the distance - 1 and
+        // must not have side effects. _dist_code[256] and _dist_code[257] are never
+        // used.
+        internal static int d_code(int dist){
+            return ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]);
+        }
+
+        internal short[] dyn_tree;      // the dynamic tree
+        internal int     max_code;      // largest code with non zero frequency
+        internal StaticTree stat_desc;  // the corresponding static tree
+
+        // Compute the optimal bit lengths for a tree and update the total bit length
+        // for the current block.
+        // IN assertion: the fields freq and dad are set, heap[heap_max] and
+        //    above are the tree nodes sorted by increasing frequency.
+        // OUT assertions: the field len is set to the optimal bit length, the
+        //     array bl_count contains the frequencies for each bit length.
+        //     The length opt_len is updated; static_len is also updated if stree is
+        //     not null.
+        internal void gen_bitlen(Deflate s){
+            short[] tree = dyn_tree;
+            short[] stree = stat_desc.static_tree;
+            int[] extra = stat_desc.extra_bits;
+            int based = stat_desc.extra_base;
+            int max_length = stat_desc.max_length;
+            int h;              // heap index
+            int n, m;           // iterate over the tree elements
+            int bits;           // bit length
+            int xbits;          // extra bits
+            short f;            // frequency
+            int overflow = 0;   // number of elements with bit length too large
+
+            for (bits = 0; bits <= MAX_BITS; bits++) s.bl_count[bits] = 0;
+
+            // In a first pass, compute the optimal bit lengths (which may
+            // overflow in the case of the bit length tree).
+            tree[s.heap[s.heap_max]*2+1] = 0; // root of the heap
+
+            for(h=s.heap_max+1; h<HEAP_SIZE; h++){
+                n = s.heap[h];
+                bits = tree[tree[n*2+1]*2+1] + 1;
+                if (bits > max_length){ bits = max_length; overflow++; }
+                tree[n*2+1] = (short)bits;
+                // We overwrite tree[n*2+1] which is no longer needed
+
+                if (n > max_code) continue;  // not a leaf node
+
+                s.bl_count[bits]++;
+                xbits = 0;
+                if (n >= based) xbits = extra[n-based];
+                f = tree[n*2];
+                s.opt_len += f * (bits + xbits);
+                if (stree!=null) s.static_len += f * (stree[n*2+1] + xbits);
+            }
+            if (overflow == 0) return;
+
+            // This happens for example on obj2 and pic of the Calgary corpus
+            // Find the first bit length which could increase:
+            do {
+                bits = max_length-1;
+            while(s.bl_count[bits]==0) bits--;
+                s.bl_count[bits]--;      // move one leaf down the tree
+                s.bl_count[bits+1]+=2;   // move one overflow item as its brother
+                s.bl_count[max_length]--;
+                // The brother of the overflow item also moves one step up,
+                // but this does not affect bl_count[max_length]
+                overflow -= 2;
+            }
+            while (overflow > 0);
+
+            for (bits = max_length; bits != 0; bits--) {
+                n = s.bl_count[bits];
+                while (n != 0) {
+                    m = s.heap[--h];
+                    if (m > max_code) continue;
+                    if (tree[m*2+1] != bits) {
+                        s.opt_len += (int)(((long)bits - (long)tree[m*2+1])*(long)tree[m*2]);
+                        tree[m*2+1] = (short)bits;
+                    }
+                    n--;
+                }
+            }
+        }
+
+        // Construct one Huffman tree and assigns the code bit strings and lengths.
+        // Update the total bit length for the current block.
+        // IN assertion: the field freq is set for all tree elements.
+        // OUT assertions: the fields len and code are set to the optimal bit length
+        //     and corresponding code. The length opt_len is updated; static_len is
+        //     also updated if stree is not null. The field max_code is set.
+        internal void build_tree(Deflate s){
+            short[] tree=dyn_tree;
+            short[] stree=stat_desc.static_tree;
+            int elems=stat_desc.elems;
+            int n, m;          // iterate over heap elements
+            int max_code=-1;   // largest code with non zero frequency
+            int node;          // new node being created
+
+            // Construct the initial heap, with least frequent element in
+            // heap[1]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+            // heap[0] is not used.
+            s.heap_len = 0;
+            s.heap_max = HEAP_SIZE;
+
+            for(n=0; n<elems; n++) {
+                if(tree[n*2] != 0) {
+                    s.heap[++s.heap_len] = max_code = n;
+                    s.depth[n] = 0;
+                }
+                else{
+                    tree[n*2+1] = 0;
+                }
+            }
+
+            // The pkzip format requires that at least one distance code exists,
+            // and that at least one bit should be sent even if there is only one
+            // possible code. So to avoid special checks later on we force at least
+            // two codes of non zero frequency.
+            while (s.heap_len < 2) {
+                node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
+                tree[node*2] = 1;
+                s.depth[node] = 0;
+                s.opt_len--; if (stree!=null) s.static_len -= stree[node*2+1];
+                // node is 0 or 1 so it does not have extra bits
+            }
+            this.max_code = max_code;
+
+            // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+            // establish sub-heaps of increasing lengths:
+
+            for(n=s.heap_len/2;n>=1; n--)
+                s.pqdownheap(tree, n);
+
+            // Construct the Huffman tree by repeatedly combining the least two
+            // frequent nodes.
+
+            node=elems;                 // next internal node of the tree
+            do{
+                // n = node of least frequency
+                n=s.heap[1];
+                s.heap[1]=s.heap[s.heap_len--];
+                s.pqdownheap(tree, 1);
+                m=s.heap[1];                // m = node of next least frequency
+
+                s.heap[--s.heap_max] = n; // keep the nodes sorted by frequency
+                s.heap[--s.heap_max] = m;
+
+                // Create a new node father of n and m
+                tree[node*2] = (short)(tree[n*2] + tree[m*2]);
+                s.depth[node] = (byte)(System.Math.Max(s.depth[n],s.depth[m])+1);
+                tree[n*2+1] = tree[m*2+1] = (short)node;
+
+                // and insert the new node in the heap
+                s.heap[1] = node++;
+                s.pqdownheap(tree, 1);
+            }
+            while(s.heap_len>=2);
+
+            s.heap[--s.heap_max] = s.heap[1];
+
+            // At this point, the fields freq and dad are set. We can now
+            // generate the bit lengths.
+
+            gen_bitlen(s);
+
+            // The field len is now set, we can generate the bit codes
+            gen_codes(tree, max_code, s.bl_count);
+        }
+
+        // Generate the codes for a given tree and bit counts (which need not be
+        // optimal).
+        // IN assertion: the array bl_count contains the bit length statistics for
+        // the given tree and the field len is set for all tree elements.
+        // OUT assertion: the field code is set for all tree elements of non
+        //     zero code length.
+        internal static void gen_codes(short[] tree, // the tree to decorate
+            int max_code, // largest code with non zero frequency
+            short[] bl_count // number of codes at each bit length
+            ){
+            short[] next_code=new short[MAX_BITS+1]; // next code value for each bit length
+            short code = 0;            // running code value
+            int bits;                  // bit index
+            int n;                     // code index
+
+            // The distribution counts are first used to generate the code values
+            // without bit reversal.
+            for (bits = 1; bits <= MAX_BITS; bits++) {
+                next_code[bits] = code = (short)((code + bl_count[bits-1]) << 1);
+            }
+
+            // Check that the bit counts in bl_count are consistent. The last code
+            // must be all ones.
+            //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            //        "inconsistent bit counts");
+            //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+            for (n = 0;  n <= max_code; n++) {
+                int len = tree[n*2+1];
+                if (len == 0) continue;
+                // Now reverse the bits
+                tree[n*2] = (short)(bi_reverse(next_code[len]++, len));
+            }
+        }
+
+        // Reverse the first len bits of a code, using straightforward code (a faster
+        // method would use a table)
+        // IN assertion: 1 <= len <= 15
+        internal static int bi_reverse(int code, // the value to invert
+            int len   // its bit length
+            ){
+            int res = 0;
+            do{
+                res|=code&1;
+                code>>=1;
+                res<<=1;
+            } 
+            while(--len>0);
+            return res>>1;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/util/zlib/ZDeflaterOutputStream.cs b/crypto/src/util/zlib/ZDeflaterOutputStream.cs
index 6dea74223..1d88847bd 100644
--- a/crypto/src/util/zlib/ZDeflaterOutputStream.cs
+++ b/crypto/src/util/zlib/ZDeflaterOutputStream.cs
@@ -135,20 +135,16 @@ namespace Org.BouncyCastle.Utilities.Zlib {
             z.free();
             z=null;
         }
-
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                try{
-                    try { Finish(); }
-                    catch (IOException) { }
-                }
-                finally{
-                    End();
-                    outp.Dispose();
-                    outp = null;
-                }
+        
+        public override void Close() {
+            try{
+                try{Finish();}
+                catch (IOException) {}
+            }
+            finally{
+                End();
+                outp.Close();
+                outp=null;
             }
         }
     }
diff --git a/crypto/src/util/zlib/ZInflaterInputStream.cs b/crypto/src/util/zlib/ZInflaterInputStream.cs
index d2d70ebd1..5a3ff5aa6 100644
--- a/crypto/src/util/zlib/ZInflaterInputStream.cs
+++ b/crypto/src/util/zlib/ZInflaterInputStream.cs
@@ -114,12 +114,8 @@ namespace Org.BouncyCastle.Utilities.Zlib {
         public override void WriteByte(byte b) {
         }
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                inp.Dispose();
-            }
+        public override void Close() {
+            inp.Close();
         }
     
         public override int ReadByte() {
diff --git a/crypto/src/util/zlib/ZInputStream.cs b/crypto/src/util/zlib/ZInputStream.cs
index 179c133bf..d1e1ba160 100644
--- a/crypto/src/util/zlib/ZInputStream.cs
+++ b/crypto/src/util/zlib/ZInputStream.cs
@@ -93,16 +93,13 @@ namespace Org.BouncyCastle.Utilities.Zlib
 		public sealed override bool CanSeek { get { return false; } }
 		public sealed override bool CanWrite { get { return false; } }
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                if (!closed)
-                {
-                    closed = true;
-                    input.Dispose();
-                }
-            }
+		public override void Close()
+		{
+			if (!closed)
+			{
+				closed = true;
+				input.Close();
+			}
 		}
 
 		public sealed override void Flush() {}
diff --git a/crypto/src/util/zlib/ZOutputStream.cs b/crypto/src/util/zlib/ZOutputStream.cs
index 7ea7cbb33..1d2ead7b3 100644
--- a/crypto/src/util/zlib/ZOutputStream.cs
+++ b/crypto/src/util/zlib/ZOutputStream.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Utilities.Zlib
 	{
 		private const int BufferSize = 512;
 
-		protected ZStream z = new ZStream();
+		protected ZStream z;
 		protected int flushLevel = JZlib.Z_NO_FLUSH;
 		// TODO Allow custom buf
 		protected byte[] buf = new byte[BufferSize];
@@ -54,17 +54,28 @@ namespace Org.BouncyCastle.Utilities.Zlib
 		protected Stream output;
 		protected bool closed;
 
-		public ZOutputStream(Stream output)
+        public ZOutputStream(Stream output)
+			: this(output, null)
+        {
+        }
+
+        public ZOutputStream(Stream output, ZStream z)
 			: base()
 		{
 			Debug.Assert(output.CanWrite);
 
-			this.output = output;
-			this.z.inflateInit();
+            if (z == null)
+            {
+                z = new ZStream();
+                z.inflateInit();
+            }
+
+            this.output = output;
+            this.z = z;
 			this.compress = false;
 		}
 
-		public ZOutputStream(Stream output, int level)
+        public ZOutputStream(Stream output, int level)
 			: this(output, level, false)
 		{
 		}
@@ -75,6 +86,7 @@ namespace Org.BouncyCastle.Utilities.Zlib
 			Debug.Assert(output.CanWrite);
 
 			this.output = output;
+            this.z = new ZStream();
 			this.z.deflateInit(level, nowrap);
 			this.compress = true;
 		}
@@ -83,32 +95,29 @@ namespace Org.BouncyCastle.Utilities.Zlib
         public sealed override bool CanSeek { get { return false; } }
         public sealed override bool CanWrite { get { return !closed; } }
 
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                if (this.closed)
-                    return;
-
-                try
-                {
-                    try
-                    {
-                        Finish();
-                    }
-                    catch (IOException)
-                    {
-                        // Ignore
-                    }
-                }
-                finally
-                {
-                    this.closed = true;
-                    End();
-                    output.Dispose();
-                    output = null;
-                }
-            }
+		public override void Close()
+		{
+			if (this.closed)
+				return;
+
+			try
+			{
+				try
+				{
+					Finish();
+				}
+				catch (IOException)
+				{
+					// Ignore
+				}
+			}
+			finally
+			{
+				this.closed = true;
+				End();
+				output.Close();
+				output = null;
+			}
 		}
 
 		public virtual void End()
diff --git a/crypto/src/util/zlib/ZStream.cs b/crypto/src/util/zlib/ZStream.cs
new file mode 100644
index 000000000..7ff961462
--- /dev/null
+++ b/crypto/src/util/zlib/ZStream.cs
@@ -0,0 +1,214 @@
+using System;
+/*
+ * $Id: ZStream.cs,v 1.1 2006-07-31 13:59:26 bouncy Exp $
+ *
+Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  1. Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+
+  2. Redistributions in binary form must reproduce the above copyright 
+     notice, this list of conditions and the following disclaimer in 
+     the documentation and/or other materials provided with the distribution.
+
+  3. The names of the authors may not be used to endorse or promote products
+     derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
+INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * This program is based on zlib-1.1.3, so all credit should go authors
+ * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
+ * and contributors of zlib.
+ */
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+
+    public sealed class ZStream{
+
+        private const int MAX_WBITS=15;        // 32K LZ77 window
+        private const int DEF_WBITS=MAX_WBITS;
+
+        private const int Z_NO_FLUSH=0;
+        private const int Z_PARTIAL_FLUSH=1;
+        private const int Z_SYNC_FLUSH=2;
+        private const int Z_FULL_FLUSH=3;
+        private const int Z_FINISH=4;
+
+        private const int MAX_MEM_LEVEL=9;
+
+        private const int Z_OK=0;
+        private const int Z_STREAM_END=1;
+        private const int Z_NEED_DICT=2;
+        private const int Z_ERRNO=-1;
+        private const int Z_STREAM_ERROR=-2;
+        private const int Z_DATA_ERROR=-3;
+        private const int Z_MEM_ERROR=-4;
+        private const int Z_BUF_ERROR=-5;
+        private const int Z_VERSION_ERROR=-6;
+
+        public byte[] next_in;     // next input byte
+        public int next_in_index;
+        public int avail_in;       // number of bytes available at next_in
+        public long total_in;      // total nb of input bytes read so far
+
+        public byte[] next_out;    // next output byte should be put there
+        public int next_out_index;
+        public int avail_out;      // remaining free space at next_out
+        public long total_out;     // total nb of bytes output so far
+
+        public String msg;
+
+        internal Deflate dstate; 
+        internal Inflate istate; 
+
+        internal int data_type; // best guess about the data type: ascii or binary
+
+        public long adler;
+        internal Adler32 _adler=new Adler32();
+
+        public int inflateInit(){
+            return inflateInit(DEF_WBITS);
+        }
+        public int inflateInit(bool nowrap){
+            return inflateInit(DEF_WBITS, nowrap);
+        }
+        public int inflateInit(int w){
+            return inflateInit(w, false);
+        }
+
+        public int inflateInit(int w, bool nowrap){
+            istate=new Inflate();
+            return istate.inflateInit(this, nowrap?-w:w);
+        }
+
+        public int inflate(int f){
+            if(istate==null) return Z_STREAM_ERROR;
+            return istate.inflate(this, f);
+        }
+        public int inflateEnd(){
+            if(istate==null) return Z_STREAM_ERROR;
+            int ret=istate.inflateEnd(this);
+            istate = null;
+            return ret;
+        }
+        public int inflateSync(){
+            if(istate == null)
+                return Z_STREAM_ERROR;
+            return istate.inflateSync(this);
+        }
+        public int inflateSetDictionary(byte[] dictionary, int dictLength){
+            if(istate == null)
+                return Z_STREAM_ERROR;
+            return istate.inflateSetDictionary(this, dictionary, dictLength);
+        }
+
+        public int deflateInit(int level){
+            return deflateInit(level, MAX_WBITS);
+        }
+        public int deflateInit(int level, bool nowrap){
+            return deflateInit(level, MAX_WBITS, nowrap);
+        }
+        public int deflateInit(int level, int bits){
+            return deflateInit(level, bits, false);
+        }
+        public int deflateInit(int level, int bits, bool nowrap){
+            dstate=new Deflate();
+            return dstate.deflateInit(this, level, nowrap?-bits:bits);
+        }
+        public int deflate(int flush){
+            if(dstate==null){
+                return Z_STREAM_ERROR;
+            }
+            return dstate.deflate(this, flush);
+        }
+        public int deflateEnd(){
+            if(dstate==null) return Z_STREAM_ERROR;
+            int ret=dstate.deflateEnd();
+            dstate=null;
+            return ret;
+        }
+        public int deflateParams(int level, int strategy){
+            if(dstate==null) return Z_STREAM_ERROR;
+            return dstate.deflateParams(this, level, strategy);
+        }
+        public int deflateSetDictionary (byte[] dictionary, int dictLength){
+            if(dstate == null)
+                return Z_STREAM_ERROR;
+            return dstate.deflateSetDictionary(this, dictionary, dictLength);
+        }
+
+        // Flush as much pending output as possible. All deflate() output goes
+        // through this function so some applications may wish to modify it
+        // to avoid allocating a large strm->next_out buffer and copying into it.
+        // (See also read_buf()).
+        internal void flush_pending(){
+            int len=dstate.pending;
+
+            if(len>avail_out) len=avail_out;
+            if(len==0) return;
+
+            if(dstate.pending_buf.Length<=dstate.pending_out ||
+                next_out.Length<=next_out_index ||
+                dstate.pending_buf.Length<(dstate.pending_out+len) ||
+                next_out.Length<(next_out_index+len)){
+                //      System.out.println(dstate.pending_buf.length+", "+dstate.pending_out+
+                //			 ", "+next_out.length+", "+next_out_index+", "+len);
+                //      System.out.println("avail_out="+avail_out);
+            }
+
+            System.Array.Copy(dstate.pending_buf, dstate.pending_out,
+                next_out, next_out_index, len);
+
+            next_out_index+=len;
+            dstate.pending_out+=len;
+            total_out+=len;
+            avail_out-=len;
+            dstate.pending-=len;
+            if(dstate.pending==0){
+                dstate.pending_out=0;
+            }
+        }
+
+        // Read a new buffer from the current input stream, update the adler32
+        // and total number of bytes read.  All deflate() input goes through
+        // this function so some applications may wish to modify it to avoid
+        // allocating a large strm->next_in buffer and copying from it.
+        // (See also flush_pending()).
+        internal int read_buf(byte[] buf, int start, int size) {
+            int len=avail_in;
+
+            if(len>size) len=size;
+            if(len==0) return 0;
+
+            avail_in-=len;
+
+            if(dstate.noheader==0) {
+                adler=_adler.adler32(adler, next_in, next_in_index, len);
+            }
+            System.Array.Copy(next_in, next_in_index, buf, start, len);
+            next_in_index  += len;
+            total_in += len;
+            return len;
+        }
+
+        public void free(){
+            next_in=null;
+            next_out=null;
+            msg=null;
+            _adler=null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/x509/AttributeCertificateHolder.cs b/crypto/src/x509/AttributeCertificateHolder.cs
new file mode 100644
index 000000000..3a6af4c20
--- /dev/null
+++ b/crypto/src/x509/AttributeCertificateHolder.cs
@@ -0,0 +1,442 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+	/// <remarks>
+	/// 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>
+	/// </remarks>
+	public class AttributeCertificateHolder
+		//: CertSelector, Selector
+		: IX509Selector
+	{
+		internal readonly Holder holder;
+
+		internal AttributeCertificateHolder(
+			Asn1Sequence seq)
+		{
+			holder = Holder.GetInstance(seq);
+		}
+
+		public AttributeCertificateHolder(
+			X509Name	issuerName,
+			BigInteger	serialNumber)
+		{
+			holder = new Holder(
+				new IssuerSerial(
+					GenerateGeneralNames(issuerName),
+					new DerInteger(serialNumber)));
+		}
+
+		public AttributeCertificateHolder(
+			X509Certificate	cert)
+		{
+			X509Name name;
+			try
+			{
+				name = PrincipalUtilities.GetIssuerX509Principal(cert);
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException(e.Message);
+			}
+
+			holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber)));
+		}
+
+		public AttributeCertificateHolder(
+			X509Name principal)
+		{
+			holder = new Holder(GenerateGeneralNames(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>
+		 * <li>1 - publicKeyCert - A hash of the public key certificate of the
+		 * holder must be passed.</li>
+		 * <li>2 - otherObjectDigest - A hash of some other object type must be
+		 * passed. <code>otherObjectTypeID</code> must not be empty.</li>
+		 * </ul>
+		 * </p>
+		 * <p>This cannot be used if a v1 attribute certificate is used.</p>
+		 *
+		 * @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)
+		{
+			// TODO Allow 'objectDigest' to be null?
+
+			holder = new Holder(new ObjectDigestInfo(digestedObjectType, 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>
+		 * <li>1 - publicKeyCert - A hash of the public key certificate of the
+		 * holder must be passed.</li>
+		 * <li>2 - otherObjectDigest - A hash of some other object type must be
+		 * passed. <code>otherObjectTypeID</code> must not be empty.</li>
+		 * </ul>
+		 * </p>
+		 *
+		 * @return The digest object type or -1 if no object digest info is set.
+		 */
+		public int DigestedObjectType
+		{
+			get
+			{
+				ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+				return odi == null
+					?	-1
+					:	odi.DigestedObjectType.Value.IntValue;
+			}
+		}
+
+		/**
+		 * 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 DigestAlgorithm
+		{
+			get
+			{
+				ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+				return odi == null
+					?	null
+					:	odi.DigestAlgorithm.ObjectID.Id;
+			}
+		}
+
+		/**
+		 * 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()
+		{
+			ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+			return odi == null
+				?	null
+				:	odi.ObjectDigest.GetBytes();
+		}
+
+		/**
+		 * 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 OtherObjectTypeID
+		{
+			get
+			{
+				ObjectDigestInfo odi = holder.ObjectDigestInfo;
+
+				return odi == null
+					?	null
+					:	odi.OtherObjectTypeID.Id;
+			}
+		}
+
+		private GeneralNames GenerateGeneralNames(
+			X509Name principal)
+		{
+//			return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal)));
+			return new GeneralNames(new GeneralName(principal));
+		}
+
+		private bool MatchesDN(
+			X509Name		subject,
+			GeneralNames	targets)
+		{
+			GeneralName[] names = targets.GetNames();
+
+			for (int i = 0; i != names.Length; i++)
+			{
+				GeneralName gn = names[i];
+
+				if (gn.TagNo == GeneralName.DirectoryName)
+				{
+					try
+					{
+						if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+						{
+							return true;
+						}
+					}
+					catch (Exception)
+					{
+					}
+				}
+			}
+
+			return false;
+		}
+
+		private object[] GetNames(
+			GeneralName[] names)
+		{
+            int count = 0;
+            for (int i = 0; i != names.Length; i++)
+            {
+                if (names[i].TagNo == GeneralName.DirectoryName)
+                {
+                    ++count;
+                }
+            }
+
+            object[] result = new object[count];
+
+            int pos = 0;
+            for (int i = 0; i != names.Length; i++)
+            {
+                if (names[i].TagNo == GeneralName.DirectoryName)
+                {
+                    result[pos++] = X509Name.GetInstance(names[i].Name);
+                }
+            }
+
+            return result;
+        }
+
+		private X509Name[] GetPrincipals(
+			GeneralNames names)
+		{
+			object[] p = this.GetNames(names.GetNames());
+
+            int count = 0;
+
+            for (int i = 0; i != p.Length; i++)
+			{
+				if (p[i] is X509Name)
+				{
+                    ++count;
+				}
+			}
+
+            X509Name[] result = new X509Name[count];
+
+            int pos = 0;
+            for (int i = 0; i != p.Length; i++)
+            {
+                if (p[i] is X509Name)
+                {
+                    result[pos++] = (X509Name)p[i];
+                }
+            }
+
+            return result;
+        }
+
+		/**
+		 * Return any principal objects inside the attribute certificate holder entity names field.
+		 *
+		 * @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set.
+		 */
+		public X509Name[] GetEntityNames()
+		{
+			if (holder.EntityName != null)
+			{
+				return GetPrincipals(holder.EntityName);
+			}
+
+			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 X509Name[] GetIssuer()
+		{
+			if (holder.BaseCertificateID != null)
+			{
+				return GetPrincipals(holder.BaseCertificateID.Issuer);
+			}
+
+			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 SerialNumber
+		{
+			get
+			{
+				if (holder.BaseCertificateID != null)
+				{
+					return holder.BaseCertificateID.Serial.Value;
+				}
+
+				return null;
+			}
+		}
+
+		public object Clone()
+		{
+			return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object());
+		}
+
+		public bool Match(
+//			Certificate cert)
+			X509Certificate x509Cert)
+		{
+//			if (!(cert is X509Certificate))
+//			{
+//				return false;
+//			}
+//
+//			X509Certificate x509Cert = (X509Certificate)cert;
+
+			try
+			{
+				if (holder.BaseCertificateID != null)
+				{
+					return holder.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+						&& MatchesDN(PrincipalUtilities.GetIssuerX509Principal(x509Cert), holder.BaseCertificateID.Issuer);
+				}
+
+				if (holder.EntityName != null)
+				{
+					if (MatchesDN(PrincipalUtilities.GetSubjectX509Principal(x509Cert), holder.EntityName))
+					{
+						return true;
+					}
+				}
+
+				if (holder.ObjectDigestInfo != null)
+				{
+					IDigest md = null;
+					try
+					{
+						md = DigestUtilities.GetDigest(DigestAlgorithm);
+					}
+					catch (Exception)
+					{
+						return false;
+					}
+
+					switch (DigestedObjectType)
+					{
+						case ObjectDigestInfo.PublicKey:
+						{
+							// TODO: DSA Dss-parms
+
+							//byte[] b = x509Cert.GetPublicKey().getEncoded();
+							// TODO Is this the right way to encode?
+							byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+								x509Cert.GetPublicKey()).GetEncoded();
+							md.BlockUpdate(b, 0, b.Length);
+							break;
+						}
+
+						case ObjectDigestInfo.PublicKeyCert:
+						{
+							byte[] b = x509Cert.GetEncoded();
+							md.BlockUpdate(b, 0, b.Length);
+							break;
+						}
+
+						// TODO Default handler?
+					}
+
+					// TODO Shouldn't this be the other way around?
+					if (!Arrays.AreEqual(DigestUtilities.DoFinal(md), GetObjectDigest()))
+					{
+						return false;
+					}
+				}
+			}
+			catch (CertificateEncodingException)
+			{
+				return false;
+			}
+
+			return false;
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+			{
+				return true;
+			}
+
+			if (!(obj is AttributeCertificateHolder))
+			{
+				return false;
+			}
+
+			AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+			return this.holder.Equals(other.holder);
+		}
+
+		public override int GetHashCode()
+		{
+			return this.holder.GetHashCode();
+		}
+
+		public bool Match(
+			object obj)
+		{
+			if (!(obj is X509Certificate))
+			{
+				return false;
+			}
+
+//			return Match((Certificate)obj);
+			return Match((X509Certificate)obj);
+		}
+	}
+}
diff --git a/crypto/src/x509/AttributeCertificateIssuer.cs b/crypto/src/x509/AttributeCertificateIssuer.cs
new file mode 100644
index 000000000..7df1416d3
--- /dev/null
+++ b/crypto/src/x509/AttributeCertificateIssuer.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.X509
+{
+	/**
+	 * Carrying class for an attribute certificate issuer.
+	 */
+	public class AttributeCertificateIssuer
+		//: CertSelector, Selector
+		: IX509Selector
+	{
+		internal readonly Asn1Encodable form;
+
+		/**
+		 * Set the issuer directly with the ASN.1 structure.
+		 *
+		 * @param issuer The issuer
+		 */
+		public AttributeCertificateIssuer(
+			AttCertIssuer issuer)
+		{
+			form = issuer.Issuer;
+		}
+
+		public AttributeCertificateIssuer(
+			X509Name principal)
+		{
+//			form = new V2Form(GeneralNames.GetInstance(new DerSequence(new GeneralName(principal))));
+			form = new V2Form(new GeneralNames(new GeneralName(principal)));
+		}
+
+		private object[] GetNames()
+		{
+			GeneralNames name;
+			if (form is V2Form)
+			{
+				name = ((V2Form)form).IssuerName;
+			}
+			else
+			{
+				name = (GeneralNames)form;
+			}
+
+            GeneralName[] names = name.GetNames();
+
+            int count = 0;
+            for (int i = 0; i != names.Length; i++)
+            {
+                if (names[i].TagNo == GeneralName.DirectoryName)
+                {
+                    ++count;
+                }
+            }
+
+            object[] result = new object[count];
+
+            int pos = 0;
+            for (int i = 0; i != names.Length; i++)
+			{
+				if (names[i].TagNo == GeneralName.DirectoryName)
+				{
+                    result[pos++] = X509Name.GetInstance(names[i].Name);
+				}
+			}
+
+            return result;
+        }
+
+		/// <summary>Return any principal objects inside the attribute certificate issuer object.</summary>
+		/// <returns>An array of IPrincipal objects (usually X509Principal).</returns>
+		public X509Name[] GetPrincipals()
+		{
+			object[] p = this.GetNames();
+
+            int count = 0;
+            for (int i = 0; i != p.Length; i++)
+            {
+                if (p[i] is X509Name)
+                {
+                    ++count;
+                }
+            }
+
+            X509Name[] result = new X509Name[count];
+
+            int pos = 0;
+			for (int i = 0; i != p.Length; i++)
+			{
+				if (p[i] is X509Name)
+				{
+					result[pos++] = (X509Name)p[i];
+				}
+			}
+
+            return result;
+		}
+
+		private bool MatchesDN(
+			X509Name		subject,
+			GeneralNames	targets)
+		{
+			GeneralName[] names = targets.GetNames();
+
+			for (int i = 0; i != names.Length; i++)
+			{
+				GeneralName gn = names[i];
+
+				if (gn.TagNo == GeneralName.DirectoryName)
+				{
+					try
+					{
+						if (X509Name.GetInstance(gn.Name).Equivalent(subject))
+						{
+							return true;
+						}
+					}
+					catch (Exception)
+					{
+					}
+				}
+			}
+
+			return false;
+		}
+
+		public object Clone()
+		{
+			return new AttributeCertificateIssuer(AttCertIssuer.GetInstance(form));
+		}
+
+		public bool Match(
+//			Certificate cert)
+			X509Certificate x509Cert)
+		{
+//			if (!(cert is X509Certificate))
+//			{
+//				return false;
+//			}
+//
+//			X509Certificate x509Cert = (X509Certificate)cert;
+
+			if (form is V2Form)
+			{
+				V2Form issuer = (V2Form) form;
+				if (issuer.BaseCertificateID != null)
+				{
+					return issuer.BaseCertificateID.Serial.Value.Equals(x509Cert.SerialNumber)
+						&& MatchesDN(x509Cert.IssuerDN, issuer.BaseCertificateID.Issuer);
+				}
+
+				return MatchesDN(x509Cert.SubjectDN, issuer.IssuerName);
+			}
+
+			return MatchesDN(x509Cert.SubjectDN, (GeneralNames) form);
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+			{
+				return true;
+			}
+
+			if (!(obj is AttributeCertificateIssuer))
+			{
+				return false;
+			}
+
+			AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+			return this.form.Equals(other.form);
+		}
+
+		public override int GetHashCode()
+		{
+			return this.form.GetHashCode();
+		}
+
+		public bool Match(
+			object obj)
+		{
+			if (!(obj is X509Certificate))
+			{
+				return false;
+			}
+
+			//return Match((Certificate)obj);
+			return Match((X509Certificate)obj);
+		}
+	}
+}
diff --git a/crypto/src/x509/IX509AttributeCertificate.cs b/crypto/src/x509/IX509AttributeCertificate.cs
new file mode 100644
index 000000000..9a3004e01
--- /dev/null
+++ b/crypto/src/x509/IX509AttributeCertificate.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.X509
+{
+	/// <remarks>Interface for an X.509 Attribute Certificate.</remarks>
+	public interface IX509AttributeCertificate
+		: IX509Extension
+	{
+		/// <summary>The version number for the certificate.</summary>
+		int Version { get; }
+
+		/// <summary>The serial number for the certificate.</summary>
+		BigInteger SerialNumber { get; }
+
+		/// <summary>The UTC DateTime before which the certificate is not valid.</summary>
+		DateTime NotBefore { get; }
+
+		/// <summary>The UTC DateTime after which the certificate is not valid.</summary>
+		DateTime NotAfter { get; }
+
+		/// <summary>The holder of the certificate.</summary>
+		AttributeCertificateHolder Holder { get; }
+
+		/// <summary>The issuer details for the certificate.</summary>
+		AttributeCertificateIssuer Issuer { get; }
+
+		/// <summary>Return the attributes contained in the attribute block in the certificate.</summary>
+		/// <returns>An array of attributes.</returns>
+		X509Attribute[] GetAttributes();
+
+		/// <summary>Return the attributes with the same type as the passed in oid.</summary>
+		/// <param name="oid">The object identifier we wish to match.</param>
+		/// <returns>An array of matched attributes, null if there is no match.</returns>
+		X509Attribute[] GetAttributes(string oid);
+
+		bool[] GetIssuerUniqueID();
+
+		bool IsValidNow { get; }
+		bool IsValid(DateTime date);
+
+		void CheckValidity();
+		void CheckValidity(DateTime date);
+
+		byte[] GetSignature();
+
+		void Verify(AsymmetricKeyParameter publicKey);
+
+		/// <summary>Return an ASN.1 encoded byte array representing the attribute certificate.</summary>
+		/// <returns>An ASN.1 encoded byte array.</returns>
+		/// <exception cref="IOException">If the certificate cannot be encoded.</exception>
+		byte[] GetEncoded();
+	}
+}
diff --git a/crypto/src/x509/IX509Extension.cs b/crypto/src/x509/IX509Extension.cs
new file mode 100644
index 000000000..e861e8736
--- /dev/null
+++ b/crypto/src/x509/IX509Extension.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+	public interface IX509Extension
+	{
+		/// <summary>
+		/// Get all critical extension values, by oid
+		/// </summary>
+		/// <returns>IDictionary with string (OID) keys and Asn1OctetString values</returns>
+		ISet GetCriticalExtensionOids();
+
+		/// <summary>
+		/// Get all non-critical extension values, by oid
+		/// </summary>
+		/// <returns>IDictionary with string (OID) keys and Asn1OctetString values</returns>
+		ISet GetNonCriticalExtensionOids();
+
+		[Obsolete("Use version taking a DerObjectIdentifier instead")]
+		Asn1OctetString GetExtensionValue(string oid);
+
+		Asn1OctetString GetExtensionValue(DerObjectIdentifier oid);
+	}
+}
diff --git a/crypto/src/x509/PEMParser.cs b/crypto/src/x509/PEMParser.cs
new file mode 100644
index 000000000..8c117f323
--- /dev/null
+++ b/crypto/src/x509/PEMParser.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.X509
+{
+	class PemParser
+	{
+		private readonly string _header1;
+		private readonly string _header2;
+		private readonly string _footer1;
+		private readonly string _footer2;
+
+		internal PemParser(
+			string type)
+		{
+			_header1 = "-----BEGIN " + type + "-----";
+			_header2 = "-----BEGIN X509 " + type + "-----";
+			_footer1 = "-----END " + type + "-----";
+			_footer2 = "-----END X509 " + type + "-----";
+		}
+
+		private string ReadLine(
+			Stream inStream)
+		{
+			int c;
+			StringBuilder l = new StringBuilder();
+
+			do
+			{
+				while (((c = inStream.ReadByte()) != '\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();
+		}
+
+		internal Asn1Sequence ReadPemObject(
+			Stream inStream)
+		{
+			string line;
+			StringBuilder pemBuf = new StringBuilder();
+
+			while ((line = ReadLine(inStream)) != null)
+			{
+				if (line.StartsWith(_header1) || line.StartsWith(_header2))
+				{
+					break;
+				}
+			}
+
+			while ((line = ReadLine(inStream)) != null)
+			{
+				if (line.StartsWith(_footer1) || line.StartsWith(_footer2))
+				{
+					break;
+				}
+
+				pemBuf.Append(line);
+			}
+
+			if (pemBuf.Length != 0)
+			{
+				Asn1Object o = Asn1Object.FromByteArray(Base64.Decode(pemBuf.ToString()));
+
+				if (!(o is Asn1Sequence))
+				{
+					throw new IOException("malformed PEM data encountered");
+				}
+
+				return (Asn1Sequence) o;
+			}
+
+			return null;
+		}
+	}
+}
+
diff --git a/crypto/src/x509/PrincipalUtil.cs b/crypto/src/x509/PrincipalUtil.cs
new file mode 100644
index 000000000..0edc4a395
--- /dev/null
+++ b/crypto/src/x509/PrincipalUtil.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+	/// <remarks>
+	/// 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.</p>
+	/// </remarks>
+	public class PrincipalUtilities
+	{
+		/// <summary>Return the issuer of the given cert as an X509Principal.</summary>
+		public static X509Name GetIssuerX509Principal(
+			X509Certificate cert)
+		{
+			try
+			{
+				TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+					Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+				return tbsCert.Issuer;
+			}
+			catch (Exception e)
+			{
+				throw new CertificateEncodingException("Could not extract issuer", e);
+			}
+		}
+
+		/// <summary>Return the subject of the given cert as an X509Principal.</summary>
+		public static X509Name GetSubjectX509Principal(
+			X509Certificate cert)
+		{
+			try
+			{
+				TbsCertificateStructure tbsCert = TbsCertificateStructure.GetInstance(
+					Asn1Object.FromByteArray(cert.GetTbsCertificate()));
+
+				return tbsCert.Subject;
+			}
+			catch (Exception e)
+			{
+				throw new CertificateEncodingException("Could not extract subject", e);
+			}
+		}
+
+		/// <summary>Return the issuer of the given CRL as an X509Principal.</summary>
+		public static X509Name GetIssuerX509Principal(
+			X509Crl crl)
+		{
+			try
+			{
+				TbsCertificateList tbsCertList = TbsCertificateList.GetInstance(
+					Asn1Object.FromByteArray(crl.GetTbsCertList()));
+
+				return tbsCertList.Issuer;
+			}
+			catch (Exception e)
+			{
+				throw new CrlException("Could not extract issuer", e);
+			}
+		}
+	}
+}
diff --git a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
index 54ca78090..bb6f37831 100644
--- a/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -26,162 +26,162 @@ namespace Org.BouncyCastle.X509
         {
         }
 
-		/// <summary>
+        /// <summary>
         /// Create a Subject Public Key Info object for a given public key.
         /// </summary>
         /// <param name="key">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param>
         /// <returns>A subject public key info object.</returns>
         /// <exception cref="Exception">Throw exception if object provided is not one of the above.</exception>
         public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
-			AsymmetricKeyParameter key)
+            AsymmetricKeyParameter key)
         {
-			if (key == null)
-				throw new ArgumentNullException("key");
+            if (key == null)
+                throw new ArgumentNullException("key");
             if (key.IsPrivate)
                 throw new ArgumentException("Private key passed - public key expected.", "key");
 
-			if (key is ElGamalPublicKeyParameters)
+            if (key is ElGamalPublicKeyParameters)
             {
-				ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
-				ElGamalParameters kp = _key.Parameters;
+                ElGamalPublicKeyParameters _key = (ElGamalPublicKeyParameters)key;
+                ElGamalParameters kp = _key.Parameters;
 
-				SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
-					new AlgorithmIdentifier(
-						OiwObjectIdentifiers.ElGamalAlgorithm,
-						new ElGamalParameter(kp.P, kp.G).ToAsn1Object()),
-						new DerInteger(_key.Y));
+                SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                    new AlgorithmIdentifier(
+                        OiwObjectIdentifiers.ElGamalAlgorithm,
+                        new ElGamalParameter(kp.P, kp.G).ToAsn1Object()),
+                        new DerInteger(_key.Y));
 
-				return info;
+                return info;
             }
 
-			if (key is DsaPublicKeyParameters)
+            if (key is DsaPublicKeyParameters)
             {
                 DsaPublicKeyParameters _key = (DsaPublicKeyParameters) key;
-				DsaParameters kp = _key.Parameters;
-				Asn1Encodable ae = kp == null
-					?	null
-					:	new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object();
+                DsaParameters kp = _key.Parameters;
+                Asn1Encodable ae = kp == null
+                    ?	null
+                    :	new DsaParameter(kp.P, kp.Q, kp.G).ToAsn1Object();
 
-				return new SubjectPublicKeyInfo(
+                return new SubjectPublicKeyInfo(
                     new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, ae),
-					new DerInteger(_key.Y));
+                    new DerInteger(_key.Y));
             }
 
-			if (key is DHPublicKeyParameters)
+            if (key is DHPublicKeyParameters)
             {
                 DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
-				DHParameters kp = _key.Parameters;
+                DHParameters kp = _key.Parameters;
 
-				SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
                     new AlgorithmIdentifier(
-						_key.AlgorithmOid,
-						new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
-						new DerInteger(_key.Y));
+                        _key.AlgorithmOid,
+                        new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
+                        new DerInteger(_key.Y));
 
-				return info;
+                return info;
             } // End of DH
 
             if (key is RsaKeyParameters)
             {
                 RsaKeyParameters _key = (RsaKeyParameters) key;
 
-				SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
-					new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
-					new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object());
+                SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                    new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
+                    new RsaPublicKeyStructure(_key.Modulus, _key.Exponent).ToAsn1Object());
 
-				return info;
+                return info;
             } // End of RSA.
 
-			if (key is ECPublicKeyParameters)
+            if (key is ECPublicKeyParameters)
             {
                 ECPublicKeyParameters _key = (ECPublicKeyParameters) key;
 
-				if (_key.AlgorithmName == "ECGOST3410")
-				{
-					if (_key.PublicKeyParamSet == null)
-						throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
-
-					ECPoint q = _key.Q;
-					BigInteger bX = q.X.ToBigInteger();
-					BigInteger bY = q.Y.ToBigInteger();
-
-					byte[] encKey = new byte[64];
-					ExtractBytes(encKey, 0, bX);
-					ExtractBytes(encKey, 32, bY);
-
-					Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
-						_key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
-
-					AlgorithmIdentifier algID = new AlgorithmIdentifier(
-						CryptoProObjectIdentifiers.GostR3410x2001,
-						gostParams.ToAsn1Object());
-
-					return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey));
-				}
-				else
-				{
-					X962Parameters x962;
-					if (_key.PublicKeyParamSet == null)
-					{
-						ECDomainParameters kp = _key.Parameters;
-						X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
-
-						x962 = new X962Parameters(ecP);
-					}
-					else
-					{
-						x962 = new X962Parameters(_key.PublicKeyParamSet);
-					}
-
-					Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object());
-
-					AlgorithmIdentifier algID = new AlgorithmIdentifier(
-						X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
-
-					return new SubjectPublicKeyInfo(algID, p.GetOctets());
-				}
-			} // End of EC
-
-			if (key is Gost3410PublicKeyParameters)
-			{
-				Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
-
-				if (_key.PublicKeyParamSet == null)
-					throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
-
-				byte[] keyEnc = _key.Y.ToByteArrayUnsigned();
-				byte[] keyBytes = new byte[keyEnc.Length];
-
-				for (int i = 0; i != keyBytes.Length; i++)
-				{
-					keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
-				}
-
-				Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
-					_key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
-
-				AlgorithmIdentifier algID = new AlgorithmIdentifier(
-					CryptoProObjectIdentifiers.GostR3410x94,
-					algParams.ToAsn1Object());
-
-				return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
-			}
-
-			throw new ArgumentException("Class provided no convertible: " + key.GetType().FullName);
-		}
-
-		private static void ExtractBytes(
-			byte[]		encKey,
-			int			offset,
-			BigInteger	bI)
-		{
-			byte[] val = bI.ToByteArray();
-			int n = (bI.BitLength + 7) / 8;
-
-			for (int i = 0; i < n; ++i)
-			{
-				encKey[offset + i] = val[val.Length - 1 - i];
-			}
-		}
-	}
+                if (_key.AlgorithmName == "ECGOST3410")
+                {
+                    if (_key.PublicKeyParamSet == null)
+                        throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+                    ECPoint q = _key.Q.Normalize();
+                    BigInteger bX = q.AffineXCoord.ToBigInteger();
+                    BigInteger bY = q.AffineYCoord.ToBigInteger();
+
+                    byte[] encKey = new byte[64];
+                    ExtractBytes(encKey, 0, bX);
+                    ExtractBytes(encKey, 32, bY);
+
+                    Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
+                        _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+                    AlgorithmIdentifier algID = new AlgorithmIdentifier(
+                        CryptoProObjectIdentifiers.GostR3410x2001,
+                        gostParams.ToAsn1Object());
+
+                    return new SubjectPublicKeyInfo(algID, new DerOctetString(encKey));
+                }
+                else
+                {
+                    X962Parameters x962;
+                    if (_key.PublicKeyParamSet == null)
+                    {
+                        ECDomainParameters kp = _key.Parameters;
+                        X9ECParameters ecP = new X9ECParameters(kp.Curve, kp.G, kp.N, kp.H, kp.GetSeed());
+
+                        x962 = new X962Parameters(ecP);
+                    }
+                    else
+                    {
+                        x962 = new X962Parameters(_key.PublicKeyParamSet);
+                    }
+
+                    Asn1OctetString p = (Asn1OctetString)(new X9ECPoint(_key.Q).ToAsn1Object());
+
+                    AlgorithmIdentifier algID = new AlgorithmIdentifier(
+                        X9ObjectIdentifiers.IdECPublicKey, x962.ToAsn1Object());
+
+                    return new SubjectPublicKeyInfo(algID, p.GetOctets());
+                }
+            } // End of EC
+
+            if (key is Gost3410PublicKeyParameters)
+            {
+                Gost3410PublicKeyParameters _key = (Gost3410PublicKeyParameters) key;
+
+                if (_key.PublicKeyParamSet == null)
+                    throw Platform.CreateNotImplementedException("Not a CryptoPro parameter set");
+
+                byte[] keyEnc = _key.Y.ToByteArrayUnsigned();
+                byte[] keyBytes = new byte[keyEnc.Length];
+
+                for (int i = 0; i != keyBytes.Length; i++)
+                {
+                    keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // must be little endian
+                }
+
+                Gost3410PublicKeyAlgParameters algParams = new Gost3410PublicKeyAlgParameters(
+                    _key.PublicKeyParamSet, CryptoProObjectIdentifiers.GostR3411x94CryptoProParamSet);
+
+                AlgorithmIdentifier algID = new AlgorithmIdentifier(
+                    CryptoProObjectIdentifiers.GostR3410x94,
+                    algParams.ToAsn1Object());
+
+                return new SubjectPublicKeyInfo(algID, new DerOctetString(keyBytes));
+            }
+
+            throw new ArgumentException("Class provided no convertible: " + key.GetType().FullName);
+        }
+
+        private static void ExtractBytes(
+            byte[]		encKey,
+            int			offset,
+            BigInteger	bI)
+        {
+            byte[] val = bI.ToByteArray();
+            int n = (bI.BitLength + 7) / 8;
+
+            for (int i = 0; i < n; ++i)
+            {
+                encKey[offset + i] = val[val.Length - 1 - i];
+            }
+        }
+    }
 }
diff --git a/crypto/src/x509/X509AttrCertParser.cs b/crypto/src/x509/X509AttrCertParser.cs
new file mode 100644
index 000000000..a5c07362e
--- /dev/null
+++ b/crypto/src/x509/X509AttrCertParser.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+	public class X509AttrCertParser
+	{
+		private static readonly PemParser PemAttrCertParser = new PemParser("ATTRIBUTE CERTIFICATE");
+
+		private Asn1Set	sData;
+		private int		sDataObjectCount;
+		private Stream	currentStream;
+
+		private IX509AttributeCertificate ReadDerCertificate(
+			Asn1InputStream dIn)
+		{
+			Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+			if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+			{
+				if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+				{
+					sData = SignedData.GetInstance(
+						Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+					return GetCertificate();
+				}
+			}
+
+//			return new X509V2AttributeCertificate(seq.getEncoded());
+			return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+		}
+
+		private IX509AttributeCertificate GetCertificate()
+		{
+			if (sData != null)
+			{
+				while (sDataObjectCount < sData.Count)
+				{
+					object obj = sData[sDataObjectCount++];
+
+					if (obj is Asn1TaggedObject && ((Asn1TaggedObject)obj).TagNo == 2)
+					{
+						//return new X509V2AttributeCertificate(
+						//	Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false).GetEncoded());
+						return new X509V2AttributeCertificate(
+							AttributeCertificate.GetInstance(
+								Asn1Sequence.GetInstance((Asn1TaggedObject)obj, false)));
+					}
+				}
+			}
+
+			return null;
+		}
+
+		private IX509AttributeCertificate ReadPemCertificate(
+			Stream inStream)
+		{
+			Asn1Sequence seq = PemAttrCertParser.ReadPemObject(inStream);
+
+			return seq == null
+				?	null
+				//:	new X509V2AttributeCertificate(seq.getEncoded());
+				:	new X509V2AttributeCertificate(AttributeCertificate.GetInstance(seq));
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public IX509AttributeCertificate ReadAttrCert(
+			byte[] input)
+		{
+			return ReadAttrCert(new MemoryStream(input, false));
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public ICollection ReadAttrCerts(
+			byte[] input)
+		{
+			return ReadAttrCerts(new MemoryStream(input, false));
+		}
+
+		/**
+		 * Generates a certificate object and initializes it with the data
+		 * read from the input stream inStream.
+		 */
+		public IX509AttributeCertificate ReadAttrCert(
+			Stream inStream)
+		{
+			if (inStream == null)
+				throw new ArgumentNullException("inStream");
+			if (!inStream.CanRead)
+				throw new ArgumentException("inStream must be read-able", "inStream");
+
+			if (currentStream == null)
+			{
+				currentStream = inStream;
+				sData = null;
+				sDataObjectCount = 0;
+			}
+			else if (currentStream != inStream) // reset if input stream has changed
+			{
+				currentStream = inStream;
+				sData = null;
+				sDataObjectCount = 0;
+			}
+
+			try
+			{
+				if (sData != null)
+				{
+					if (sDataObjectCount != sData.Count)
+					{
+						return GetCertificate();
+					}
+
+					sData = null;
+					sDataObjectCount = 0;
+					return null;
+				}
+
+				PushbackStream pis = new PushbackStream(inStream);
+				int tag = pis.ReadByte();
+
+				if (tag < 0)
+					return null;
+
+				pis.Unread(tag);
+
+				if (tag != 0x30)  // assume ascii PEM encoded.
+				{
+					return ReadPemCertificate(pis);
+				}
+
+				return ReadDerCertificate(new Asn1InputStream(pis));
+			}
+			catch (Exception e)
+			{
+				throw new CertificateException(e.ToString());
+			}
+		}
+
+		/**
+		 * Returns a (possibly empty) collection view of the certificates
+		 * read from the given input stream inStream.
+		 */
+		public ICollection ReadAttrCerts(
+			Stream inStream)
+		{
+			IX509AttributeCertificate attrCert;
+            IList attrCerts = Platform.CreateArrayList();
+
+			while ((attrCert = ReadAttrCert(inStream)) != null)
+			{
+				attrCerts.Add(attrCert);
+			}
+
+			return attrCerts;
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/src/x509/X509Attribute.cs b/crypto/src/x509/X509Attribute.cs
new file mode 100644
index 000000000..248d66cc4
--- /dev/null
+++ b/crypto/src/x509/X509Attribute.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+	/**
+	 * Class for carrying the values in an X.509 Attribute.
+	 */
+	public class X509Attribute
+		: Asn1Encodable
+	{
+		private readonly AttributeX509 attr;
+
+		/**
+		 * @param at an object representing an attribute.
+		 */
+		internal X509Attribute(
+			Asn1Encodable at)
+		{
+			this.attr = AttributeX509.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 AttributeX509(new DerObjectIdentifier(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 AttributeX509(new DerObjectIdentifier(oid), new DerSet(value));
+		}
+
+		public string Oid
+		{
+			get { return attr.AttrType.Id; }
+		}
+
+		public Asn1Encodable[] GetValues()
+		{
+			Asn1Set s = attr.AttrValues;
+			Asn1Encodable[] values = new Asn1Encodable[s.Count];
+
+			for (int i = 0; i != s.Count; i++)
+			{
+				values[i] = (Asn1Encodable)s[i];
+			}
+
+			return values;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return attr.ToAsn1Object();
+		}
+	}
+}
diff --git a/crypto/src/x509/X509CertPairParser.cs b/crypto/src/x509/X509CertPairParser.cs
new file mode 100644
index 000000000..82612599b
--- /dev/null
+++ b/crypto/src/x509/X509CertPairParser.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+	public class X509CertPairParser
+	{
+		private Stream currentStream;
+
+		private X509CertificatePair ReadDerCrossCertificatePair(
+			Stream inStream)
+		{
+			Asn1InputStream dIn = new Asn1InputStream(inStream);//, ProviderUtil.getReadLimit(in));
+			Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+			CertificatePair pair = CertificatePair.GetInstance(seq);
+			return new X509CertificatePair(pair);
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public X509CertificatePair ReadCertPair(
+			byte[] input)
+		{
+			return ReadCertPair(new MemoryStream(input, false));
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public ICollection ReadCertPairs(
+			byte[] input)
+		{
+			return ReadCertPairs(new MemoryStream(input, false));
+		}
+
+		public X509CertificatePair ReadCertPair(
+			Stream inStream)
+		{
+			if (inStream == null)
+				throw new ArgumentNullException("inStream");
+			if (!inStream.CanRead)
+				throw new ArgumentException("inStream must be read-able", "inStream");
+
+			if (currentStream == null)
+			{
+				currentStream = inStream;
+			}
+			else if (currentStream != inStream) // reset if input stream has changed
+			{
+				currentStream = inStream;
+			}
+
+			try
+			{
+				PushbackStream pis = new PushbackStream(inStream);
+				int tag = pis.ReadByte();
+
+				if (tag < 0)
+					return null;
+
+				pis.Unread(tag);
+
+				return ReadDerCrossCertificatePair(pis);
+			}
+			catch (Exception e)
+			{
+				throw new CertificateException(e.ToString());
+			}
+		}
+
+		public ICollection ReadCertPairs(
+			Stream inStream)
+		{
+			X509CertificatePair certPair;
+			IList certPairs = Platform.CreateArrayList();
+
+			while ((certPair = ReadCertPair(inStream)) != null)
+			{
+				certPairs.Add(certPair);
+			}
+
+			return certPairs;
+		}
+	}
+}
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs
new file mode 100644
index 000000000..f156f3147
--- /dev/null
+++ b/crypto/src/x509/X509Certificate.cs
@@ -0,0 +1,595 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+    /// <summary>
+    /// An Object representing an X509 Certificate.
+    /// Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
+    /// </summary>
+    public class X509Certificate
+		:	X509ExtensionBase
+//		, PKCS12BagAttributeCarrier
+    {
+        private readonly X509CertificateStructure c;
+//        private Hashtable pkcs12Attributes = new Hashtable();
+//        private ArrayList pkcs12Ordering = new ArrayList();
+		private readonly BasicConstraints basicConstraints;
+		private readonly bool[] keyUsage;
+
+		private bool hashValueSet;
+		private int hashValue;
+
+		protected X509Certificate()
+		{
+		}
+
+		public X509Certificate(
+			X509CertificateStructure c)
+		{
+			this.c = c;
+
+			try
+			{
+				Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.19"));
+
+				if (str != null)
+				{
+					basicConstraints = BasicConstraints.GetInstance(
+						X509ExtensionUtilities.FromExtensionValue(str));
+				}
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+			}
+
+			try
+			{
+				Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.15"));
+
+				if (str != null)
+				{
+					DerBitString bits = DerBitString.GetInstance(
+						X509ExtensionUtilities.FromExtensionValue(str));
+
+					byte[] bytes = bits.GetBytes();
+					int length = (bytes.Length * 8) - bits.PadBits;
+
+					keyUsage = new bool[(length < 9) ? 9 : length];
+
+					for (int i = 0; i != length; i++)
+					{
+//						keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+						keyUsage[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+					}
+				}
+				else
+				{
+					keyUsage = null;
+				}
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+			}
+		}
+
+//		internal X509Certificate(
+//			Asn1Sequence seq)
+//        {
+//            this.c = X509CertificateStructure.GetInstance(seq);
+//        }
+
+//		/// <summary>
+//        /// Load certificate from byte array.
+//        /// </summary>
+//        /// <param name="encoded">Byte array containing encoded X509Certificate.</param>
+//        public X509Certificate(
+//            byte[] encoded)
+//			: this((Asn1Sequence) new Asn1InputStream(encoded).ReadObject())
+//		{
+//        }
+//
+//        /// <summary>
+//        /// Load certificate from Stream.
+//        /// Must be positioned at start of certificate.
+//        /// </summary>
+//        /// <param name="input"></param>
+//        public X509Certificate(
+//            Stream input)
+//			: this((Asn1Sequence) new Asn1InputStream(input).ReadObject())
+//        {
+//        }
+
+		public virtual X509CertificateStructure CertificateStructure
+		{
+			get { return c; }
+		}
+
+		/// <summary>
+        /// Return true if the current time is within the start and end times nominated on the certificate.
+        /// </summary>
+        /// <returns>true id certificate is valid for the current time.</returns>
+        public virtual bool IsValidNow
+        {
+			get { return IsValid(DateTime.UtcNow); }
+        }
+
+		/// <summary>
+        /// Return true if the nominated time is within the start and end times nominated on the certificate.
+        /// </summary>
+        /// <param name="time">The time to test validity against.</param>
+        /// <returns>True if certificate is valid for nominated time.</returns>
+        public virtual bool IsValid(
+			DateTime time)
+        {
+            return time.CompareTo(NotBefore) >= 0 && time.CompareTo(NotAfter) <= 0;
+        }
+
+		/// <summary>
+		/// Checks if the current date is within certificate's validity period.
+		/// </summary>
+		public virtual void CheckValidity()
+		{
+			this.CheckValidity(DateTime.UtcNow);
+		}
+
+		/// <summary>
+		/// Checks if the given date is within certificate's validity period.
+		/// </summary>
+		/// <exception cref="CertificateExpiredException">if the certificate is expired by given date</exception>
+		/// <exception cref="CertificateNotYetValidException">if the certificate is not yet valid on given date</exception>
+		public virtual void CheckValidity(
+			DateTime time)
+		{
+			if (time.CompareTo(NotAfter) > 0)
+				throw new CertificateExpiredException("certificate expired on " + c.EndDate.GetTime());
+			if (time.CompareTo(NotBefore) < 0)
+				throw new CertificateNotYetValidException("certificate not valid until " + c.StartDate.GetTime());
+		}
+
+		/// <summary>
+        /// Return the certificate's version.
+        /// </summary>
+        /// <returns>An integer whose value Equals the version of the cerficate.</returns>
+        public virtual int Version
+        {
+            get { return c.Version; }
+        }
+
+		/// <summary>
+        /// Return a <see cref="Org.BouncyCastle.Math.BigInteger">BigInteger</see> containing the serial number.
+        /// </summary>
+        /// <returns>The Serial number.</returns>
+        public virtual BigInteger SerialNumber
+        {
+            get { return c.SerialNumber.Value; }
+        }
+
+		/// <summary>
+        /// Get the Issuer Distinguished Name. (Who signed the certificate.)
+        /// </summary>
+        /// <returns>And X509Object containing name and value pairs.</returns>
+//        public IPrincipal IssuerDN
+		public virtual X509Name IssuerDN
+		{
+            get { return c.Issuer; }
+        }
+
+		/// <summary>
+        /// Get the subject of this certificate.
+        /// </summary>
+        /// <returns>An X509Name object containing name and value pairs.</returns>
+//        public IPrincipal SubjectDN
+		public virtual X509Name SubjectDN
+		{
+            get { return c.Subject; }
+        }
+
+		/// <summary>
+		/// The time that this certificate is valid from.
+		/// </summary>
+		/// <returns>A DateTime object representing that time in the local time zone.</returns>
+		public virtual DateTime NotBefore
+		{
+			get { return c.StartDate.ToDateTime(); }
+		}
+
+		/// <summary>
+        /// The time that this certificate is valid up to.
+        /// </summary>
+        /// <returns>A DateTime object representing that time in the local time zone.</returns>
+        public virtual DateTime NotAfter
+        {
+			get { return c.EndDate.ToDateTime(); }
+        }
+
+		/// <summary>
+		/// Return the Der encoded TbsCertificate data.
+		/// This is the certificate component less the signature.
+		/// To Get the whole certificate call the GetEncoded() member.
+		/// </summary>
+		/// <returns>A byte array containing the Der encoded Certificate component.</returns>
+		public virtual byte[] GetTbsCertificate()
+		{
+			return c.TbsCertificate.GetDerEncoded();
+		}
+
+		/// <summary>
+		/// The signature.
+		/// </summary>
+		/// <returns>A byte array containg the signature of the certificate.</returns>
+		public virtual byte[] GetSignature()
+		{
+			return c.Signature.GetBytes();
+		}
+
+		/// <summary>
+		/// A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
+		/// </summary>
+		/// <returns>A sting representing the signature algorithm.</returns>
+		public virtual string SigAlgName
+		{
+			get { return SignerUtilities.GetEncodingName(c.SignatureAlgorithm.ObjectID); }
+		}
+
+		/// <summary>
+		/// Get the Signature Algorithms Object ID.
+		/// </summary>
+		/// <returns>A string containg a '.' separated object id.</returns>
+		public virtual string SigAlgOid
+		{
+			get { return c.SignatureAlgorithm.ObjectID.Id; }
+		}
+
+		/// <summary>
+		/// Get the signature algorithms parameters. (EG DSA Parameters)
+		/// </summary>
+		/// <returns>A byte array containing the Der encoded version of the parameters or null if there are none.</returns>
+		public virtual byte[] GetSigAlgParams()
+		{
+			if (c.SignatureAlgorithm.Parameters != null)
+			{
+				return c.SignatureAlgorithm.Parameters.GetDerEncoded();
+			}
+
+			return null;
+		}
+
+		/// <summary>
+		/// Get the issuers UID.
+		/// </summary>
+		/// <returns>A DerBitString.</returns>
+		public virtual DerBitString IssuerUniqueID
+		{
+			get { return c.TbsCertificate.IssuerUniqueID; }
+		}
+
+		/// <summary>
+		/// Get the subjects UID.
+		/// </summary>
+		/// <returns>A DerBitString.</returns>
+		public virtual DerBitString SubjectUniqueID
+		{
+			get { return c.TbsCertificate.SubjectUniqueID; }
+		}
+
+		/// <summary>
+		/// Get a key usage guidlines.
+		/// </summary>
+		public virtual bool[] GetKeyUsage()
+		{
+			return keyUsage == null ? null : (bool[]) keyUsage.Clone();
+		}
+
+		// TODO Replace with something that returns a list of DerObjectIdentifier
+		public virtual IList GetExtendedKeyUsage()
+		{
+			Asn1OctetString str = this.GetExtensionValue(new DerObjectIdentifier("2.5.29.37"));
+
+			if (str == null)
+				return null;
+
+			try
+			{
+				Asn1Sequence seq = Asn1Sequence.GetInstance(
+					X509ExtensionUtilities.FromExtensionValue(str));
+
+                IList list = Platform.CreateArrayList();
+
+				foreach (DerObjectIdentifier oid in seq)
+				{
+					list.Add(oid.Id);
+				}
+
+				return list;
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("error processing extended key usage extension", e);
+			}
+		}
+
+		public virtual int GetBasicConstraints()
+		{
+			if (basicConstraints != null && basicConstraints.IsCA())
+			{
+				if (basicConstraints.PathLenConstraint == null)
+				{
+					return int.MaxValue;
+				}
+
+				return basicConstraints.PathLenConstraint.IntValue;
+			}
+
+			return -1;
+		}
+
+		public virtual ICollection GetSubjectAlternativeNames()
+		{
+			return GetAlternativeNames("2.5.29.17");
+		}
+
+		public virtual ICollection GetIssuerAlternativeNames()
+		{
+			return GetAlternativeNames("2.5.29.18");
+		}
+
+		protected virtual ICollection GetAlternativeNames(
+			string oid)
+		{
+			Asn1OctetString altNames = GetExtensionValue(new DerObjectIdentifier(oid));
+
+			if (altNames == null)
+				return null;
+
+			Asn1Object asn1Object = X509ExtensionUtilities.FromExtensionValue(altNames);
+
+			GeneralNames gns = GeneralNames.GetInstance(asn1Object);
+
+            IList result = Platform.CreateArrayList();
+			foreach (GeneralName gn in gns.GetNames())
+			{
+                IList entry = Platform.CreateArrayList();
+				entry.Add(gn.TagNo);
+				entry.Add(gn.Name.ToString());
+				result.Add(entry);
+			}
+			return result;
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return c.Version == 3
+				?	c.TbsCertificate.Extensions
+				:	null;
+		}
+
+		/// <summary>
+		/// Get the public key of the subject of the certificate.
+		/// </summary>
+		/// <returns>The public key parameters.</returns>
+		public virtual AsymmetricKeyParameter GetPublicKey()
+		{
+			return PublicKeyFactory.CreateKey(c.SubjectPublicKeyInfo);
+		}
+
+		/// <summary>
+		/// Return a Der encoded version of this certificate.
+		/// </summary>
+		/// <returns>A byte array.</returns>
+		public virtual byte[] GetEncoded()
+		{
+			return c.GetDerEncoded();
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			X509Certificate other = obj as X509Certificate;
+
+			if (other == null)
+				return false;
+
+			return c.Equals(other.c);
+
+			// NB: May prefer this implementation of Equals if more than one certificate implementation in play
+//			return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+		}
+
+		public override int GetHashCode()
+		{
+			lock (this)
+			{
+				if (!hashValueSet)
+				{
+					hashValue = c.GetHashCode();
+					hashValueSet = true;
+				}
+			}
+
+			return hashValue;
+		}
+
+//		public void setBagAttribute(
+//			DERObjectIdentifier oid,
+//			DEREncodable        attribute)
+//		{
+//			pkcs12Attributes.put(oid, attribute);
+//			pkcs12Ordering.addElement(oid);
+//		}
+//
+//		public DEREncodable getBagAttribute(
+//			DERObjectIdentifier oid)
+//		{
+//			return (DEREncodable)pkcs12Attributes.get(oid);
+//		}
+//
+//		public Enumeration getBagAttributeKeys()
+//		{
+//			return pkcs12Ordering.elements();
+//		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string nl = Platform.NewLine;
+
+			buf.Append("  [0]         Version: ").Append(this.Version).Append(nl);
+			buf.Append("         SerialNumber: ").Append(this.SerialNumber).Append(nl);
+			buf.Append("             IssuerDN: ").Append(this.IssuerDN).Append(nl);
+			buf.Append("           Start Date: ").Append(this.NotBefore).Append(nl);
+			buf.Append("           Final Date: ").Append(this.NotAfter).Append(nl);
+			buf.Append("            SubjectDN: ").Append(this.SubjectDN).Append(nl);
+			buf.Append("           Public Key: ").Append(this.GetPublicKey()).Append(nl);
+			buf.Append("  Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+			byte[] sig = this.GetSignature();
+			buf.Append("            Signature: ").Append(Hex.ToHexString(sig, 0, 20)).Append(nl);
+
+			for (int i = 20; i < sig.Length; i += 20)
+			{
+				int len = System.Math.Min(20, sig.Length - i);
+				buf.Append("                       ").Append(Hex.ToHexString(sig, i, len)).Append(nl);
+			}
+
+			X509Extensions extensions = c.TbsCertificate.Extensions;
+
+			if (extensions != null)
+			{
+				IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+				if (e.MoveNext())
+				{
+					buf.Append("       Extensions: \n");
+				}
+
+				do
+				{
+					DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+					X509Extension ext = extensions.GetExtension(oid);
+
+					if (ext.Value != null)
+					{
+						byte[] octs = ext.Value.GetOctets();
+						Asn1Object obj = Asn1Object.FromByteArray(octs);
+						buf.Append("                       critical(").Append(ext.IsCritical).Append(") ");
+						try
+						{
+							if (oid.Equals(X509Extensions.BasicConstraints))
+							{
+								buf.Append(BasicConstraints.GetInstance(obj));
+							}
+							else if (oid.Equals(X509Extensions.KeyUsage))
+							{
+								buf.Append(KeyUsage.GetInstance(obj));
+							}
+							else if (oid.Equals(MiscObjectIdentifiers.NetscapeCertType))
+							{
+								buf.Append(new NetscapeCertType((DerBitString) obj));
+							}
+							else if (oid.Equals(MiscObjectIdentifiers.NetscapeRevocationUrl))
+							{
+								buf.Append(new NetscapeRevocationUrl((DerIA5String) obj));
+							}
+							else if (oid.Equals(MiscObjectIdentifiers.VerisignCzagExtension))
+							{
+								buf.Append(new VerisignCzagExtension((DerIA5String) obj));
+							}
+							else
+							{
+								buf.Append(oid.Id);
+								buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+								//buf.Append(" value = ").Append("*****").Append(nl);
+							}
+						}
+						catch (Exception)
+						{
+							buf.Append(oid.Id);
+							//buf.Append(" value = ").Append(new string(Hex.encode(ext.getValue().getOctets()))).Append(nl);
+							buf.Append(" value = ").Append("*****");
+						}
+					}
+
+					buf.Append(nl);
+				}
+				while (e.MoveNext());
+			}
+
+			return buf.ToString();
+		}
+
+		/// <summary>
+		/// Verify the certificate's signature using the nominated public key.
+		/// </summary>
+		/// <param name="key">An appropriate public key parameter object, RsaPublicKeyParameters, DsaPublicKeyParameters or ECDsaPublicKeyParameters</param>
+		/// <returns>True if the signature is valid.</returns>
+		/// <exception cref="Exception">If key submitted is not of the above nominated types.</exception>
+		public virtual void Verify(
+			AsymmetricKeyParameter key)
+		{
+			string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+			ISigner signature = SignerUtilities.GetSigner(sigName);
+
+			CheckSignature(key, signature);
+		}
+
+		protected virtual void CheckSignature(
+			AsymmetricKeyParameter	publicKey,
+			ISigner					signature)
+		{
+			if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
+				throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+
+			Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+			X509SignatureUtilities.SetSignatureParameters(signature, parameters);
+
+			signature.Init(false, publicKey);
+
+			byte[] b = this.GetTbsCertificate();
+			signature.BlockUpdate(b, 0, b.Length);
+
+			byte[] sig = this.GetSignature();
+			if (!signature.VerifySignature(sig))
+			{
+				throw new InvalidKeyException("Public key presented not for certificate signature");
+			}
+		}
+
+		private static bool IsAlgIDEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+		{
+			if (!id1.ObjectID.Equals(id2.ObjectID))
+				return false;
+
+			Asn1Encodable p1 = id1.Parameters;
+			Asn1Encodable p2 = id2.Parameters;
+
+			if ((p1 == null) == (p2 == null))
+				return Platform.Equals(p1, p2);
+
+			// Exactly one of p1, p2 is null at this point
+			return p1 == null
+				?	p2.ToAsn1Object() is Asn1Null
+				:	p1.ToAsn1Object() is Asn1Null;
+		}
+	}
+}
diff --git a/crypto/src/x509/X509CertificatePair.cs b/crypto/src/x509/X509CertificatePair.cs
new file mode 100644
index 000000000..fbeba4dc6
--- /dev/null
+++ b/crypto/src/x509/X509CertificatePair.cs
@@ -0,0 +1,123 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+	/// <remarks>
+	/// This class contains a cross certificate pair. Cross certificates pairs may
+	/// contain two cross signed certificates from two CAs. A certificate from the
+	/// other CA to this CA is contained in the forward certificate, the certificate
+	/// from this CA to the other CA is contained in the reverse certificate.
+	/// </remarks>
+	public class X509CertificatePair
+	{
+		private readonly X509Certificate forward;
+		private readonly X509Certificate reverse;
+
+		/// <summary>Constructor</summary>
+		/// <param name="forward">Certificate from the other CA to this CA.</param>
+		/// <param name="reverse">Certificate from this CA to the other CA.</param>
+		public X509CertificatePair(
+			X509Certificate	forward,
+			X509Certificate	reverse)
+		{
+			this.forward = forward;
+			this.reverse = reverse;
+		}
+
+		/// <summary>Constructor from a ASN.1 CertificatePair structure.</summary>
+		/// <param name="pair">The <c>CertificatePair</c> ASN.1 object.</param>
+		public X509CertificatePair(
+			CertificatePair pair)
+		{
+			if (pair.Forward != null)
+			{
+				this.forward = new X509Certificate(pair.Forward);
+			}
+			if (pair.Reverse != null)
+			{
+				this.reverse = new X509Certificate(pair.Reverse);
+			}
+		}
+
+		public byte[] GetEncoded()
+		{
+			try
+			{
+				X509CertificateStructure f = null, r = null;
+
+				if (forward != null)
+				{
+					f = X509CertificateStructure.GetInstance(
+						Asn1Object.FromByteArray(forward.GetEncoded()));
+
+					if (f == null)
+						throw new CertificateEncodingException("unable to get encoding for forward");
+				}
+
+				if (reverse != null)
+				{
+					r = X509CertificateStructure.GetInstance(
+						Asn1Object.FromByteArray(reverse.GetEncoded()));
+
+					if (r == null)
+						throw new CertificateEncodingException("unable to get encoding for reverse");
+				}
+
+				return new CertificatePair(f, r).GetDerEncoded();
+			}
+			catch (Exception e)
+			{
+				// TODO
+//				throw new ExtCertificateEncodingException(e.toString(), e);
+				throw new CertificateEncodingException(e.Message, e);
+			}
+		}
+
+		/// <summary>Returns the certificate from the other CA to this CA.</summary>
+		public X509Certificate Forward
+		{
+			get { return forward; }
+		}
+
+		/// <summary>Returns the certificate from this CA to the other CA.</summary>
+		public X509Certificate Reverse
+		{
+			get { return reverse; }
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			X509CertificatePair other = obj as X509CertificatePair;
+
+			if (other == null)
+				return false;
+
+			return Platform.Equals(this.forward, other.forward)
+				&& Platform.Equals(this.reverse, other.reverse);
+		}
+
+		public override int GetHashCode()
+		{
+			int hash = -1;
+			if (forward != null)
+			{
+				hash ^= forward.GetHashCode();
+			}
+			if (reverse != null)
+			{
+				hash *= 17;
+				hash ^= reverse.GetHashCode();
+			}
+			return hash;
+		}
+	}
+}
diff --git a/crypto/src/x509/X509CertificateParser.cs b/crypto/src/x509/X509CertificateParser.cs
new file mode 100644
index 000000000..8f0e7406c
--- /dev/null
+++ b/crypto/src/x509/X509CertificateParser.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+	/**
+	 * 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.</p>
+	 */
+	public class X509CertificateParser
+	{
+		private static readonly PemParser PemCertParser = new PemParser("CERTIFICATE");
+
+		private Asn1Set	sData;
+		private int		sDataObjectCount;
+		private Stream	currentStream;
+
+		private X509Certificate ReadDerCertificate(
+			Asn1InputStream dIn)
+		{
+			Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+			if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+			{
+				if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+				{
+					sData = SignedData.GetInstance(
+						Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Certificates;
+
+					return GetCertificate();
+				}
+			}
+
+			return CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+		}
+
+		private X509Certificate GetCertificate()
+		{
+			if (sData != null)
+			{
+				while (sDataObjectCount < sData.Count)
+				{
+					object obj = sData[sDataObjectCount++];
+
+					if (obj is Asn1Sequence)
+					{
+						return CreateX509Certificate(
+							X509CertificateStructure.GetInstance(obj));
+					}
+				}
+			}
+
+			return null;
+		}
+
+		private X509Certificate ReadPemCertificate(
+			Stream inStream)
+		{
+			Asn1Sequence seq = PemCertParser.ReadPemObject(inStream);
+
+			return seq == null
+				?	null
+				:	CreateX509Certificate(X509CertificateStructure.GetInstance(seq));
+		}
+
+		protected virtual X509Certificate CreateX509Certificate(
+			X509CertificateStructure c)
+		{
+			return new X509Certificate(c);
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public X509Certificate ReadCertificate(
+			byte[] input)
+		{
+			return ReadCertificate(new MemoryStream(input, false));
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public ICollection ReadCertificates(
+			byte[] input)
+		{
+			return ReadCertificates(new MemoryStream(input, false));
+		}
+
+		/**
+		 * Generates a certificate object and initializes it with the data
+		 * read from the input stream inStream.
+		 */
+		public X509Certificate ReadCertificate(
+			Stream inStream)
+		{
+			if (inStream == null)
+				throw new ArgumentNullException("inStream");
+			if (!inStream.CanRead)
+				throw new ArgumentException("inStream must be read-able", "inStream");
+
+			if (currentStream == null)
+			{
+				currentStream = inStream;
+				sData = null;
+				sDataObjectCount = 0;
+			}
+			else if (currentStream != inStream) // reset if input stream has changed
+			{
+				currentStream = inStream;
+				sData = null;
+				sDataObjectCount = 0;
+			}
+
+			try
+			{
+				if (sData != null)
+				{
+					if (sDataObjectCount != sData.Count)
+					{
+						return GetCertificate();
+					}
+
+					sData = null;
+					sDataObjectCount = 0;
+					return null;
+				}
+
+				PushbackStream pis = new PushbackStream(inStream);
+				int tag = pis.ReadByte();
+
+				if (tag < 0)
+					return null;
+
+				pis.Unread(tag);
+
+				if (tag != 0x30)  // assume ascii PEM encoded.
+				{
+					return ReadPemCertificate(pis);
+				}
+
+				return ReadDerCertificate(new Asn1InputStream(pis));
+			}
+			catch (Exception e)
+			{
+				throw new CertificateException("Failed to read certificate", e);
+			}
+		}
+
+		/**
+		 * Returns a (possibly empty) collection view of the certificates
+		 * read from the given input stream inStream.
+		 */
+		public ICollection ReadCertificates(
+			Stream inStream)
+		{
+			X509Certificate cert;
+            IList certs = Platform.CreateArrayList();
+
+			while ((cert = ReadCertificate(inStream)) != null)
+			{
+				certs.Add(cert);
+			}
+
+			return certs;
+		}
+	}
+}
diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs
new file mode 100644
index 000000000..7d0e7aa72
--- /dev/null
+++ b/crypto/src/x509/X509Crl.cs
@@ -0,0 +1,403 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+	/**
+	 * 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 X509Crl
+		: X509ExtensionBase
+		// TODO Add interface Crl?
+	{
+		private readonly CertificateList c;
+		private readonly string sigAlgName;
+		private readonly byte[] sigAlgParams;
+		private readonly bool isIndirect;
+
+		public X509Crl(
+			CertificateList c)
+		{
+			this.c = c;
+
+			try
+			{
+				this.sigAlgName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
+
+				if (c.SignatureAlgorithm.Parameters != null)
+				{
+					this.sigAlgParams = ((Asn1Encodable)c.SignatureAlgorithm.Parameters).GetDerEncoded();
+				}
+				else
+				{
+					this.sigAlgParams = null;
+				}
+
+				this.isIndirect = IsIndirectCrl;
+			}
+			catch (Exception e)
+			{
+				throw new CrlException("CRL contents invalid: " + e);
+			}
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return Version == 2
+				?	c.TbsCertList.Extensions
+				:	null;
+		}
+
+		public virtual byte[] GetEncoded()
+		{
+			try
+			{
+				return c.GetDerEncoded();
+			}
+			catch (Exception e)
+			{
+				throw new CrlException(e.ToString());
+			}
+		}
+
+		public virtual void Verify(
+			AsymmetricKeyParameter publicKey)
+		{
+			if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
+			{
+				throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
+			}
+
+			ISigner sig = SignerUtilities.GetSigner(SigAlgName);
+			sig.Init(false, publicKey);
+
+			byte[] encoded = this.GetTbsCertList();
+			sig.BlockUpdate(encoded, 0, encoded.Length);
+
+			if (!sig.VerifySignature(this.GetSignature()))
+			{
+				throw new SignatureException("CRL does not verify with supplied public key.");
+			}
+		}
+
+		public virtual int Version
+		{
+			get { return c.Version; }
+		}
+
+		public virtual X509Name IssuerDN
+		{
+			get { return c.Issuer; }
+		}
+
+		public virtual DateTime ThisUpdate
+		{
+			get { return c.ThisUpdate.ToDateTime(); }
+		}
+
+		public virtual DateTimeObject NextUpdate
+		{
+			get
+			{
+				return c.NextUpdate == null
+					?	null
+					:	new DateTimeObject(c.NextUpdate.ToDateTime());
+			}
+		}
+
+		private ISet LoadCrlEntries()
+		{
+			ISet entrySet = new HashSet();
+			IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+			X509Name previousCertificateIssuer = IssuerDN;
+			foreach (CrlEntry entry in certs)
+			{
+				X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+				entrySet.Add(crlEntry);
+				previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+			}
+
+			return entrySet;
+		}
+
+		public virtual X509CrlEntry GetRevokedCertificate(
+			BigInteger serialNumber)
+		{
+			IEnumerable certs = c.GetRevokedCertificateEnumeration();
+
+			X509Name previousCertificateIssuer = IssuerDN;
+			foreach (CrlEntry entry in certs)
+			{
+				X509CrlEntry crlEntry = new X509CrlEntry(entry, isIndirect, previousCertificateIssuer);
+
+				if (serialNumber.Equals(entry.UserCertificate.Value))
+				{
+					return crlEntry;
+				}
+
+				previousCertificateIssuer = crlEntry.GetCertificateIssuer();
+			}
+
+			return null;
+		}
+
+		public virtual ISet GetRevokedCertificates()
+		{
+			ISet entrySet = LoadCrlEntries();
+
+			if (entrySet.Count > 0)
+			{
+				return entrySet; // TODO? Collections.unmodifiableSet(entrySet);
+			}
+
+			return null;
+		}
+
+		public virtual byte[] GetTbsCertList()
+		{
+			try
+			{
+				return c.TbsCertList.GetDerEncoded();
+			}
+			catch (Exception e)
+			{
+				throw new CrlException(e.ToString());
+			}
+		}
+
+		public virtual byte[] GetSignature()
+		{
+			return c.Signature.GetBytes();
+		}
+
+		public virtual string SigAlgName
+		{
+			get { return sigAlgName; }
+		}
+
+		public virtual string SigAlgOid
+		{
+			get { return c.SignatureAlgorithm.ObjectID.Id; }
+		}
+
+		public virtual byte[] GetSigAlgParams()
+		{
+			return Arrays.Clone(sigAlgParams);
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			X509Crl other = obj as X509Crl;
+
+			if (other == null)
+				return false;
+
+			return c.Equals(other.c);
+
+			// NB: May prefer this implementation of Equals if more than one certificate implementation in play
+			//return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+		}
+
+		public override int GetHashCode()
+		{
+			return c.GetHashCode();
+		}
+
+		/**
+		 * Returns a string representation of this CRL.
+		 *
+		 * @return a string representation of this CRL.
+		 */
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string nl = Platform.NewLine;
+
+			buf.Append("              Version: ").Append(this.Version).Append(nl);
+			buf.Append("             IssuerDN: ").Append(this.IssuerDN).Append(nl);
+			buf.Append("          This update: ").Append(this.ThisUpdate).Append(nl);
+			buf.Append("          Next update: ").Append(this.NextUpdate).Append(nl);
+			buf.Append("  Signature Algorithm: ").Append(this.SigAlgName).Append(nl);
+
+			byte[] sig = this.GetSignature();
+
+			buf.Append("            Signature: ");
+			buf.Append(Hex.ToHexString(sig, 0, 20)).Append(nl);
+
+			for (int i = 20; i < sig.Length; i += 20)
+			{
+				int count = System.Math.Min(20, sig.Length - i);
+				buf.Append("                       ");
+				buf.Append(Hex.ToHexString(sig, i, count)).Append(nl);
+			}
+
+			X509Extensions extensions = c.TbsCertList.Extensions;
+
+			if (extensions != null)
+			{
+				IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+
+				if (e.MoveNext())
+				{
+					buf.Append("           Extensions: ").Append(nl);
+				}
+
+				do
+				{
+					DerObjectIdentifier oid = (DerObjectIdentifier) e.Current;
+					X509Extension ext = extensions.GetExtension(oid);
+
+					if (ext.Value != null)
+					{
+						Asn1Object asn1Value = X509ExtensionUtilities.FromExtensionValue(ext.Value);
+
+						buf.Append("                       critical(").Append(ext.IsCritical).Append(") ");
+						try
+						{
+							if (oid.Equals(X509Extensions.CrlNumber))
+							{
+								buf.Append(new CrlNumber(DerInteger.GetInstance(asn1Value).PositiveValue)).Append(nl);
+							}
+							else if (oid.Equals(X509Extensions.DeltaCrlIndicator))
+							{
+								buf.Append(
+									"Base CRL: "
+									+ new CrlNumber(DerInteger.GetInstance(
+									asn1Value).PositiveValue))
+									.Append(nl);
+							}
+							else if (oid.Equals(X509Extensions.IssuingDistributionPoint))
+							{
+								buf.Append(IssuingDistributionPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+							}
+							else if (oid.Equals(X509Extensions.CrlDistributionPoints))
+							{
+								buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+							}
+							else if (oid.Equals(X509Extensions.FreshestCrl))
+							{
+								buf.Append(CrlDistPoint.GetInstance((Asn1Sequence) asn1Value)).Append(nl);
+							}
+							else
+							{
+								buf.Append(oid.Id);
+								buf.Append(" value = ").Append(
+									Asn1Dump.DumpAsString(asn1Value))
+									.Append(nl);
+							}
+						}
+						catch (Exception)
+						{
+							buf.Append(oid.Id);
+							buf.Append(" value = ").Append("*****").Append(nl);
+						}
+					}
+					else
+					{
+						buf.Append(nl);
+					}
+				}
+				while (e.MoveNext());
+			}
+
+			ISet certSet = GetRevokedCertificates();
+			if (certSet != null)
+			{
+				foreach (X509CrlEntry entry in certSet)
+				{
+					buf.Append(entry);
+					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 bool IsRevoked(
+//			Certificate cert)
+//		{
+//			if (!cert.getType().Equals("X.509"))
+//			{
+//				throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+//			}
+		public virtual bool IsRevoked(
+			X509Certificate cert)
+		{
+			CrlEntry[] certs = c.GetRevokedCertificates();
+
+			if (certs != null)
+			{
+//				BigInteger serial = ((X509Certificate)cert).SerialNumber;
+				BigInteger serial = cert.SerialNumber;
+
+				for (int i = 0; i < certs.Length; i++)
+				{
+					if (certs[i].UserCertificate.Value.Equals(serial))
+					{
+						return true;
+					}
+				}
+			}
+
+			return false;
+		}
+
+		protected virtual bool IsIndirectCrl
+		{
+			get
+			{
+				Asn1OctetString idp = GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+				bool isIndirect = false;
+
+				try
+				{
+					if (idp != null)
+					{
+						isIndirect = IssuingDistributionPoint.GetInstance(
+							X509ExtensionUtilities.FromExtensionValue(idp)).IsIndirectCrl;
+					}
+				}
+				catch (Exception e)
+				{
+					// TODO
+//					throw new ExtCrlException("Exception reading IssuingDistributionPoint", e);
+					throw new CrlException("Exception reading IssuingDistributionPoint" + e);
+				}
+
+				return isIndirect;
+			}
+		}
+	}
+}
diff --git a/crypto/src/x509/X509CrlEntry.cs b/crypto/src/x509/X509CrlEntry.cs
new file mode 100644
index 000000000..caca29470
--- /dev/null
+++ b/crypto/src/x509/X509CrlEntry.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+	/**
+	 * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+	 *
+	 * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+	 * (critical)
+	 */
+	public class X509CrlEntry
+		: X509ExtensionBase
+	{
+		private CrlEntry	c;
+		private bool		isIndirect;
+		private X509Name	previousCertificateIssuer;
+		private X509Name	certificateIssuer;
+
+		public X509CrlEntry(
+			CrlEntry c)
+		{
+			this.c = c;
+			this.certificateIssuer = loadCertificateIssuer();
+		}
+
+		/**
+		* 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
+		*            TbsCertificateList.CrlEntry object.
+		* @param isIndirect
+		*            <code>true</code> if the corresponding CRL is a indirect
+		*            CRL.
+		* @param previousCertificateIssuer
+		*            Certificate issuer of the previous CrlEntry.
+		*/
+		public X509CrlEntry(
+			CrlEntry		c,
+			bool			isIndirect,
+			X509Name		previousCertificateIssuer)
+		{
+			this.c = c;
+			this.isIndirect = isIndirect;
+			this.previousCertificateIssuer = previousCertificateIssuer;
+			this.certificateIssuer = loadCertificateIssuer();
+		}
+
+		private X509Name loadCertificateIssuer()
+		{
+			if (!isIndirect)
+			{
+				return null;
+			}
+
+			Asn1OctetString ext = GetExtensionValue(X509Extensions.CertificateIssuer);
+			if (ext == null)
+			{
+				return previousCertificateIssuer;
+			}
+
+			try
+			{
+				GeneralName[] names = GeneralNames.GetInstance(
+					X509ExtensionUtilities.FromExtensionValue(ext)).GetNames();
+
+				for (int i = 0; i < names.Length; i++)
+				{
+					if (names[i].TagNo == GeneralName.DirectoryName)
+					{
+						return X509Name.GetInstance(names[i].Name);
+					}
+				}
+			}
+			catch (Exception)
+			{
+			}
+
+			return null;
+		}
+
+		public X509Name GetCertificateIssuer()
+		{
+			return certificateIssuer;
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return c.Extensions;
+		}
+
+		public byte[] GetEncoded()
+		{
+			try
+			{
+				return c.GetDerEncoded();
+			}
+			catch (Exception e)
+			{
+				throw new CrlException(e.ToString());
+			}
+		}
+
+		public BigInteger SerialNumber
+		{
+			get { return c.UserCertificate.Value; }
+		}
+
+		public DateTime RevocationDate
+		{
+			get { return c.RevocationDate.ToDateTime(); }
+		}
+
+		public bool HasExtensions
+		{
+			get { return c.Extensions != null; }
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			string nl = Platform.NewLine;
+
+			buf.Append("        userCertificate: ").Append(this.SerialNumber).Append(nl);
+			buf.Append("         revocationDate: ").Append(this.RevocationDate).Append(nl);
+			buf.Append("      certificateIssuer: ").Append(this.GetCertificateIssuer()).Append(nl);
+
+			X509Extensions extensions = c.Extensions;
+
+			if (extensions != null)
+			{
+				IEnumerator e = extensions.ExtensionOids.GetEnumerator();
+				if (e.MoveNext())
+				{
+					buf.Append("   crlEntryExtensions:").Append(nl);
+
+					do
+					{
+						DerObjectIdentifier oid = (DerObjectIdentifier)e.Current;
+						X509Extension ext = extensions.GetExtension(oid);
+
+						if (ext.Value != null)
+						{
+							Asn1Object obj = Asn1Object.FromByteArray(ext.Value.GetOctets());
+
+							buf.Append("                       critical(")
+								.Append(ext.IsCritical)
+								.Append(") ");
+							try
+							{
+								if (oid.Equals(X509Extensions.ReasonCode))
+								{
+									buf.Append(new CrlReason(DerEnumerated.GetInstance(obj)));
+								}
+								else if (oid.Equals(X509Extensions.CertificateIssuer))
+								{
+									buf.Append("Certificate issuer: ").Append(
+										GeneralNames.GetInstance((Asn1Sequence)obj));
+								}
+								else 
+								{
+									buf.Append(oid.Id);
+									buf.Append(" value = ").Append(Asn1Dump.DumpAsString(obj));
+								}
+								buf.Append(nl);
+							}
+							catch (Exception)
+							{
+								buf.Append(oid.Id);
+								buf.Append(" value = ").Append("*****").Append(nl);
+							}
+						}
+						else
+						{
+							buf.Append(nl);
+						}
+					}
+					while (e.MoveNext());
+				}
+			}
+
+			return buf.ToString();
+		}
+	}
+}
diff --git a/crypto/src/x509/X509CrlParser.cs b/crypto/src/x509/X509CrlParser.cs
new file mode 100644
index 000000000..d830bb9a6
--- /dev/null
+++ b/crypto/src/x509/X509CrlParser.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.X509
+{
+	public class X509CrlParser
+	{
+		private static readonly PemParser PemCrlParser = new PemParser("CRL");
+
+		private readonly bool lazyAsn1;
+
+		private Asn1Set	sCrlData;
+		private int		sCrlDataObjectCount;
+		private Stream	currentCrlStream;
+
+		public X509CrlParser()
+			: this(false)
+		{
+		}
+
+		public X509CrlParser(
+			bool lazyAsn1)
+		{
+			this.lazyAsn1 = lazyAsn1;
+		}
+
+		private X509Crl ReadPemCrl(
+			Stream inStream)
+		{
+			Asn1Sequence seq = PemCrlParser.ReadPemObject(inStream);
+
+			return seq == null
+				?	null
+				:	CreateX509Crl(CertificateList.GetInstance(seq));
+		}
+
+		private X509Crl ReadDerCrl(
+			Asn1InputStream dIn)
+		{
+			Asn1Sequence seq = (Asn1Sequence)dIn.ReadObject();
+
+			if (seq.Count > 1 && seq[0] is DerObjectIdentifier)
+			{
+				if (seq[0].Equals(PkcsObjectIdentifiers.SignedData))
+				{
+					sCrlData = SignedData.GetInstance(
+						Asn1Sequence.GetInstance((Asn1TaggedObject) seq[1], true)).Crls;
+
+					return GetCrl();
+				}
+			}
+
+			return CreateX509Crl(CertificateList.GetInstance(seq));
+		}
+
+		private X509Crl GetCrl()
+		{
+			if (sCrlData == null || sCrlDataObjectCount >= sCrlData.Count)
+			{
+				return null;
+			}
+
+			return CreateX509Crl(
+				CertificateList.GetInstance(
+					sCrlData[sCrlDataObjectCount++]));
+		}
+
+		protected virtual X509Crl CreateX509Crl(
+			CertificateList c)
+		{
+			return new X509Crl(c);
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public X509Crl ReadCrl(
+			byte[] input)
+		{
+			return ReadCrl(new MemoryStream(input, false));
+		}
+
+		/// <summary>
+		/// Create loading data from byte array.
+		/// </summary>
+		/// <param name="input"></param>
+		public ICollection ReadCrls(
+			byte[] input)
+		{
+			return ReadCrls(new MemoryStream(input, false));
+		}
+
+		/**
+		 * Generates a certificate revocation list (CRL) object and initializes
+		 * it with the data read from the input stream inStream.
+		 */
+		public X509Crl ReadCrl(
+			Stream inStream)
+		{
+			if (inStream == null)
+				throw new ArgumentNullException("inStream");
+			if (!inStream.CanRead)
+				throw new ArgumentException("inStream must be read-able", "inStream");
+
+			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.Count)
+					{
+						return GetCrl();
+					}
+
+					sCrlData = null;
+					sCrlDataObjectCount = 0;
+					return null;
+				}
+
+				PushbackStream pis = new PushbackStream(inStream);
+				int tag = pis.ReadByte();
+
+				if (tag < 0)
+					return null;
+
+				pis.Unread(tag);
+
+				if (tag != 0x30)	// assume ascii PEM encoded.
+				{
+					return ReadPemCrl(pis);
+				}
+
+				Asn1InputStream asn1 = lazyAsn1
+					?	new LazyAsn1InputStream(pis)
+					:	new Asn1InputStream(pis);
+
+				return ReadDerCrl(asn1);
+			}
+			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 significant field being crls.  In particular the signature
+		 * and the contents are ignored.
+		 */
+		public ICollection ReadCrls(
+			Stream inStream)
+		{
+			X509Crl crl;
+			IList crls = Platform.CreateArrayList();
+
+			while ((crl = ReadCrl(inStream)) != null)
+			{
+				crls.Add(crl);
+			}
+
+			return crls;
+		}
+	}
+}
diff --git a/crypto/src/x509/X509ExtensionBase.cs b/crypto/src/x509/X509ExtensionBase.cs
new file mode 100644
index 000000000..aaf6695c0
--- /dev/null
+++ b/crypto/src/x509/X509ExtensionBase.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+	public abstract class X509ExtensionBase
+		: IX509Extension
+	{
+		protected abstract X509Extensions GetX509Extensions();
+
+		protected virtual ISet GetExtensionOids(
+			bool critical)
+		{
+			X509Extensions extensions = GetX509Extensions();
+			if (extensions != null)
+			{
+				HashSet set = new HashSet();
+				foreach (DerObjectIdentifier oid in extensions.ExtensionOids)
+				{
+					X509Extension ext = extensions.GetExtension(oid);
+					if (ext.IsCritical == critical)
+					{
+						set.Add(oid.Id);
+					}
+				}
+
+				return set;
+			}
+
+			return null;
+		}
+
+		/// <summary>
+		/// Get non critical extensions.
+		/// </summary>
+		/// <returns>A set of non critical extension oids.</returns>
+		public virtual ISet GetNonCriticalExtensionOids()
+		{
+			return GetExtensionOids(false);
+		}
+
+		/// <summary>
+		/// Get any critical extensions.
+		/// </summary>
+		/// <returns>A sorted list of critical entension.</returns>
+		public virtual ISet GetCriticalExtensionOids()
+		{
+			return GetExtensionOids(true);
+		}
+
+		/// <summary>
+		/// Get the value of a given extension.
+		/// </summary>
+		/// <param name="oid">The object ID of the extension. </param>
+		/// <returns>An Asn1OctetString object if that extension is found or null if not.</returns>
+		[Obsolete("Use version taking a DerObjectIdentifier instead")]
+		public Asn1OctetString GetExtensionValue(
+			string oid)
+		{
+			return GetExtensionValue(new DerObjectIdentifier(oid));
+		}
+
+		public virtual Asn1OctetString GetExtensionValue(
+			DerObjectIdentifier oid)
+		{
+			X509Extensions exts = GetX509Extensions();
+			if (exts != null)
+			{
+				X509Extension ext = exts.GetExtension(oid);
+				if (ext != null)
+				{
+					return ext.Value;
+				}
+			}
+
+			return null;
+		}
+	}
+}
diff --git a/crypto/src/x509/X509KeyUsage.cs b/crypto/src/x509/X509KeyUsage.cs
new file mode 100644
index 000000000..e0a7b4939
--- /dev/null
+++ b/crypto/src/x509/X509KeyUsage.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.X509
+{
+	/**
+	 * A holding class for constructing an X509 Key Usage extension.
+	 *
+	 * <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 X509KeyUsage
+		: Asn1Encodable
+	{
+		public const int DigitalSignature = 1 << 7;
+		public const int NonRepudiation   = 1 << 6;
+		public const int KeyEncipherment  = 1 << 5;
+		public const int DataEncipherment = 1 << 4;
+		public const int KeyAgreement     = 1 << 3;
+		public const int KeyCertSign      = 1 << 2;
+		public const int CrlSign          = 1 << 1;
+		public const int EncipherOnly     = 1 << 0;
+		public const int DecipherOnly     = 1 << 15;
+
+		private readonly int usage;
+
+		/**
+		 * Basic constructor.
+		 *
+		 * @param usage - the bitwise OR of the Key Usage flags giving the
+		 * allowed uses for the key.
+		 * e.g. (X509KeyUsage.keyEncipherment | X509KeyUsage.dataEncipherment)
+		 */
+		public X509KeyUsage(
+			int usage)
+		{
+			this.usage = usage;
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return new KeyUsage(usage);
+		}
+	}
+}
diff --git a/crypto/src/x509/X509SignatureUtil.cs b/crypto/src/x509/X509SignatureUtil.cs
new file mode 100644
index 000000000..7a4ab1448
--- /dev/null
+++ b/crypto/src/x509/X509SignatureUtil.cs
@@ -0,0 +1,128 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.X509
+{
+	internal class X509SignatureUtilities
+	{
+		private static readonly Asn1Null derNull = DerNull.Instance;
+
+		internal static void SetSignatureParameters(
+			ISigner			signature,
+			Asn1Encodable	parameters)
+		{
+			if (parameters != null && !derNull.Equals(parameters))
+			{
+				// TODO Put back in
+//				AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm());
+//
+//				try
+//				{
+//					sigParams.Init(parameters.ToAsn1Object().GetDerEncoded());
+//				}
+//				catch (IOException e)
+//				{
+//					throw new SignatureException("IOException decoding parameters: " + e.Message);
+//				}
+//
+//				if (signature.getAlgorithm().EndsWith("MGF1"))
+//				{
+//					try
+//					{
+//						signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+//					}
+//					catch (GeneralSecurityException e)
+//					{
+//						throw new SignatureException("Exception extracting parameters: " + e.Message);
+//					}
+//				}
+			}
+		}
+
+		internal static string GetSignatureName(
+			AlgorithmIdentifier sigAlgId)
+		{
+			Asn1Encodable parameters = sigAlgId.Parameters;
+
+			if (parameters != null && !derNull.Equals(parameters))
+			{
+				if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+				{
+					RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
+
+					return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+				}
+				if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+				{
+					Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
+
+					return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA";
+				}
+			}
+
+			return sigAlgId.ObjectID.Id;
+		}
+
+		/**
+		 * Return the digest algorithm using one of the standard JCA string
+		 * representations rather than 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";
+			}
+			else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+			{
+				return "SHA224";
+			}
+			else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+			{
+				return "SHA256";
+			}
+			else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+			{
+				return "SHA384";
+			}
+			else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+			{
+				return "SHA512";
+			}
+			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";
+			}
+			else
+			{
+				return digestAlgOID.Id;
+			}
+		}
+	}
+}
diff --git a/crypto/src/x509/X509Utilities.cs b/crypto/src/x509/X509Utilities.cs
index 000958340..52a122c21 100644
--- a/crypto/src/x509/X509Utilities.cs
+++ b/crypto/src/x509/X509Utilities.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections;
-using System.Globalization;
 using System.IO;
 
 using Org.BouncyCastle.Asn1;
@@ -124,9 +123,9 @@ namespace Org.BouncyCastle.X509
 		internal static DerObjectIdentifier GetAlgorithmOid(
 			string algorithmName)
 		{
-			algorithmName = algorithmName.ToUpperInvariant();
+			algorithmName = Platform.ToUpperInvariant(algorithmName);
 
-			if (algorithms.Contains(algorithmName))
+            if (algorithms.Contains(algorithmName))
 			{
 				return (DerObjectIdentifier) algorithms[algorithmName];
 			}
@@ -143,7 +142,7 @@ namespace Org.BouncyCastle.X509
 				return new AlgorithmIdentifier(sigOid);
 			}
 
-			algorithmName = algorithmName.ToUpperInvariant();
+            algorithmName = Platform.ToUpperInvariant(algorithmName);
 
 			if (exParams.Contains(algorithmName))
 			{
diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs
new file mode 100644
index 000000000..02b58a198
--- /dev/null
+++ b/crypto/src/x509/X509V1CertificateGenerator.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509
+{
+	/// <summary>
+	/// Class to Generate X509V1 Certificates.
+	/// </summary>
+	public class X509V1CertificateGenerator
+	{
+		private V1TbsCertificateGenerator   tbsGen;
+		private DerObjectIdentifier         sigOID;
+		private AlgorithmIdentifier         sigAlgId;
+		private string                      signatureAlgorithm;
+
+		/// <summary>
+		/// Default Constructor.
+		/// </summary>
+		public X509V1CertificateGenerator()
+		{
+			tbsGen = new V1TbsCertificateGenerator();
+		}
+
+		/// <summary>
+		/// Reset the generator.
+		/// </summary>
+		public void Reset()
+		{
+			tbsGen = new V1TbsCertificateGenerator();
+		}
+
+		/// <summary>
+		/// Set the certificate's serial number.
+		/// </summary>
+		/// <remarks>Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+		/// You will be surprised how ugly a serial number collision can get.</remarks>
+		/// <param name="serialNumber">The serial number.</param>
+		public void SetSerialNumber(
+			BigInteger serialNumber)
+		{
+			if (serialNumber.SignValue <= 0)
+			{
+				throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+			}
+
+			tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+		}
+
+		/// <summary>
+		/// Set the issuer distinguished name.
+		/// The issuer is the entity whose private key is used to sign the certificate.
+		/// </summary>
+		/// <param name="issuer">The issuers DN.</param>
+		public void SetIssuerDN(
+			X509Name issuer)
+		{
+			tbsGen.SetIssuer(issuer);
+		}
+
+		/// <summary>
+		/// Set the date that this certificate is to be valid from.
+		/// </summary>
+		/// <param name="date"/>
+		public void SetNotBefore(
+			DateTime date)
+		{
+			tbsGen.SetStartDate(new Time(date));
+		}
+
+		/// <summary>
+		/// Set the date after which this certificate will no longer be valid.
+		/// </summary>
+		/// <param name="date"/>
+		public void SetNotAfter(
+			DateTime date)
+		{
+			tbsGen.SetEndDate(new Time(date));
+		}
+
+		/// <summary>
+		/// Set the subject distinguished name.
+		/// The subject describes the entity associated with the public key.
+		/// </summary>
+		/// <param name="subject"/>
+		public void SetSubjectDN(
+			X509Name subject)
+		{
+			tbsGen.SetSubject(subject);
+		}
+
+        /// <summary>
+        /// Set the public key that this certificate identifies.
+        /// </summary>
+        /// <param name="publicKey"/>
+		public void SetPublicKey(
+			AsymmetricKeyParameter publicKey)
+		{
+			try
+			{
+				tbsGen.SetSubjectPublicKeyInfo(
+					SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("unable to process key - " + e.ToString());
+			}
+		}
+
+		/// <summary>
+		/// Set the signature algorithm that will be used to sign this certificate.
+		/// This can be either a name or an OID, names are treated as case insensitive.
+		/// </summary>
+		/// <param name="signatureAlgorithm">string representation of the algorithm name</param>
+		public void SetSignatureAlgorithm(
+			string signatureAlgorithm)
+		{
+			this.signatureAlgorithm = signatureAlgorithm;
+
+			try
+			{
+				sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+			}
+			catch (Exception)
+			{
+				throw new ArgumentException("Unknown signature type requested", "signatureAlgorithm");
+			}
+
+			sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+			tbsGen.SetSignature(sigAlgId);
+		}
+
+		/// <summary>
+		/// Generate a new X509Certificate.
+		/// </summary>
+		/// <param name="privateKey">The private key of the issuer used to sign this certificate.</param>
+		/// <returns>An X509Certificate.</returns>
+		public X509Certificate Generate(
+			AsymmetricKeyParameter privateKey)
+		{
+			return Generate(privateKey, null);
+		}
+
+        /// <summary>
+        /// Generate a new X509Certificate specifying a SecureRandom instance that you would like to use.
+        /// </summary>
+        /// <param name="privateKey">The private key of the issuer used to sign this certificate.</param>
+        /// <param name="random">The Secure Random you want to use.</param>
+        /// <returns>An X509Certificate.</returns>
+		public X509Certificate Generate(
+			AsymmetricKeyParameter	privateKey,
+			SecureRandom			random)
+		{
+			TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+			byte[] signature;
+
+			try
+			{
+				signature = X509Utilities.GetSignatureForObject(
+					sigOID, signatureAlgorithm, privateKey, random, tbsCert);
+			}
+			catch (Exception e)
+			{
+				// TODO
+//				throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+				throw new CertificateEncodingException("exception encoding TBS cert", e);
+			}
+
+			try
+			{
+				return GenerateJcaObject(tbsCert, signature);
+			}
+			catch (CertificateParsingException e)
+			{
+				// TODO
+				// throw new ExtCertificateEncodingException("exception producing certificate object", e);
+				throw new CertificateEncodingException("exception producing certificate object", e);
+			}
+		}
+
+		private X509Certificate GenerateJcaObject(
+			TbsCertificateStructure	tbsCert,
+			byte[]					signature)
+		{
+			return new X509Certificate(
+				new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+		}
+
+		/// <summary>
+		/// Allows enumeration of the signature names supported by the generator.
+		/// </summary>
+		public IEnumerable SignatureAlgNames
+		{
+			get { return X509Utilities.GetAlgNames(); }
+		}
+	}
+}
diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs
new file mode 100644
index 000000000..117ac4cc2
--- /dev/null
+++ b/crypto/src/x509/X509V2AttributeCertificate.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+	/// <summary>An implementation of a version 2 X.509 Attribute Certificate.</summary>
+	public class X509V2AttributeCertificate
+		: X509ExtensionBase, IX509AttributeCertificate
+	{
+		private readonly AttributeCertificate cert;
+		private readonly DateTime notBefore;
+		private readonly DateTime notAfter;
+
+		private static AttributeCertificate GetObject(Stream input)
+		{
+			try
+			{
+				return AttributeCertificate.GetInstance(Asn1Object.FromStream(input));
+			}
+			catch (IOException e)
+			{
+				throw e;
+			}
+			catch (Exception e)
+			{
+				throw new IOException("exception decoding certificate structure", e);
+			}
+		}
+
+		public X509V2AttributeCertificate(
+			Stream encIn)
+			: this(GetObject(encIn))
+		{
+		}
+
+		public X509V2AttributeCertificate(
+			byte[] encoded)
+			: this(new MemoryStream(encoded, false))
+		{
+		}
+
+		internal X509V2AttributeCertificate(
+			AttributeCertificate cert)
+		{
+			this.cert = cert;
+
+			try
+			{
+				this.notAfter = cert.ACInfo.AttrCertValidityPeriod.NotAfterTime.ToDateTime();
+				this.notBefore = cert.ACInfo.AttrCertValidityPeriod.NotBeforeTime.ToDateTime();
+			}
+			catch (Exception e)
+			{
+				throw new IOException("invalid data structure in certificate!", e);
+			}
+		}
+
+		public virtual int Version
+		{
+			get { return cert.ACInfo.Version.Value.IntValue + 1; }
+		}
+
+		public virtual BigInteger SerialNumber
+		{
+			get { return cert.ACInfo.SerialNumber.Value; }
+		}
+
+		public virtual AttributeCertificateHolder Holder
+		{
+			get
+			{
+				return new AttributeCertificateHolder((Asn1Sequence)cert.ACInfo.Holder.ToAsn1Object());
+			}
+		}
+
+		public virtual AttributeCertificateIssuer Issuer
+		{
+			get
+			{
+				return new AttributeCertificateIssuer(cert.ACInfo.Issuer);
+			}
+		}
+
+		public virtual DateTime NotBefore
+		{
+			get { return notBefore; }
+		}
+
+		public virtual DateTime NotAfter
+		{
+			get { return notAfter; }
+		}
+
+		public virtual bool[] GetIssuerUniqueID()
+		{
+			DerBitString id = cert.ACInfo.IssuerUniqueID;
+
+			if (id != null)
+			{
+				byte[] bytes = id.GetBytes();
+				bool[] boolId = new bool[bytes.Length * 8 - id.PadBits];
+
+				for (int i = 0; i != boolId.Length; i++)
+				{
+					//boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+					boolId[i] = (bytes[i / 8] & (0x80 >> (i % 8))) != 0;
+				}
+
+				return boolId;
+			}
+
+			return null;
+		}
+
+		public virtual bool IsValidNow
+		{
+			get { return IsValid(DateTime.UtcNow); }
+		}
+
+		public virtual bool IsValid(
+			DateTime date)
+		{
+			return date.CompareTo(NotBefore) >= 0 && date.CompareTo(NotAfter) <= 0;
+		}
+
+		public virtual void CheckValidity()
+		{
+			this.CheckValidity(DateTime.UtcNow);
+		}
+
+		public virtual void CheckValidity(
+			DateTime date)
+		{
+			if (date.CompareTo(NotAfter) > 0)
+				throw new CertificateExpiredException("certificate expired on " + NotAfter);
+			if (date.CompareTo(NotBefore) < 0)
+				throw new CertificateNotYetValidException("certificate not valid until " + NotBefore);
+		}
+
+		public virtual byte[] GetSignature()
+		{
+			return cert.SignatureValue.GetBytes();
+		}
+
+		public virtual void Verify(
+			AsymmetricKeyParameter publicKey)
+		{
+			if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
+			{
+				throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+			}
+
+			ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id);
+
+			signature.Init(false, publicKey);
+
+			try
+			{
+				byte[] b = cert.ACInfo.GetEncoded();
+				signature.BlockUpdate(b, 0, b.Length);
+			}
+			catch (IOException e)
+			{
+				throw new SignatureException("Exception encoding certificate info object", e);
+			}
+
+			if (!signature.VerifySignature(this.GetSignature()))
+			{
+				throw new InvalidKeyException("Public key presented not for certificate signature");
+			}
+		}
+
+		public virtual byte[] GetEncoded()
+		{
+			return cert.GetEncoded();
+		}
+
+		protected override X509Extensions GetX509Extensions()
+		{
+			return cert.ACInfo.Extensions;
+		}
+
+		public virtual X509Attribute[] GetAttributes()
+		{
+			Asn1Sequence seq = cert.ACInfo.Attributes;
+			X509Attribute[] attrs = new X509Attribute[seq.Count];
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				attrs[i] = new X509Attribute((Asn1Encodable)seq[i]);
+			}
+
+			return attrs;
+		}
+
+		public virtual X509Attribute[] GetAttributes(
+			string oid)
+		{
+			Asn1Sequence seq = cert.ACInfo.Attributes;
+			IList list = Platform.CreateArrayList();
+
+			for (int i = 0; i != seq.Count; i++)
+			{
+				X509Attribute attr = new X509Attribute((Asn1Encodable)seq[i]);
+				if (attr.Oid.Equals(oid))
+				{
+					list.Add(attr);
+				}
+			}
+
+			if (list.Count < 1)
+			{
+				return null;
+			}
+
+            X509Attribute[] result = new X509Attribute[list.Count];
+            for (int i = 0; i < list.Count; ++i)
+            {
+                result[i] = (X509Attribute)list[i];
+            }
+            return result;
+		}
+
+		public override bool Equals(
+			object obj)
+		{
+			if (obj == this)
+				return true;
+
+			X509V2AttributeCertificate other = obj as X509V2AttributeCertificate;
+
+			if (other == null)
+				return false;
+
+			return cert.Equals(other.cert);
+
+			// NB: May prefer this implementation of Equals if more than one certificate implementation in play
+			//return Arrays.AreEqual(this.GetEncoded(), other.GetEncoded());
+		}
+
+		public override int GetHashCode()
+		{
+			return cert.GetHashCode();
+		}
+	}
+}
diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
new file mode 100644
index 000000000..a683d5e20
--- /dev/null
+++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+	/// <remarks>Class to produce an X.509 Version 2 AttributeCertificate.</remarks>
+	public class X509V2AttributeCertificateGenerator
+	{
+		private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+		private V2AttributeCertificateInfoGenerator	acInfoGen;
+		private DerObjectIdentifier sigOID;
+		private AlgorithmIdentifier sigAlgId;
+		private string signatureAlgorithm;
+
+		public X509V2AttributeCertificateGenerator()
+		{
+			acInfoGen = new V2AttributeCertificateInfoGenerator();
+		}
+
+		/// <summary>Reset the generator</summary>
+		public void Reset()
+		{
+			acInfoGen = new V2AttributeCertificateInfoGenerator();
+			extGenerator.Reset();
+		}
+
+		/// <summary>Set the Holder of this Attribute Certificate.</summary>
+		public void SetHolder(
+			AttributeCertificateHolder holder)
+		{
+			acInfoGen.SetHolder(holder.holder);
+		}
+
+		/// <summary>Set the issuer.</summary>
+		public void SetIssuer(
+			AttributeCertificateIssuer issuer)
+		{
+			acInfoGen.SetIssuer(AttCertIssuer.GetInstance(issuer.form));
+		}
+
+		/// <summary>Set the serial number for the certificate.</summary>
+		public void SetSerialNumber(
+			BigInteger serialNumber)
+		{
+			acInfoGen.SetSerialNumber(new DerInteger(serialNumber));
+		}
+
+		public void SetNotBefore(
+			DateTime date)
+		{
+			acInfoGen.SetStartDate(new DerGeneralizedTime(date));
+		}
+
+		public void SetNotAfter(
+			DateTime date)
+		{
+			acInfoGen.SetEndDate(new DerGeneralizedTime(date));
+		}
+
+		/// <summary>
+		/// Set the signature algorithm. This can be either a name or an OID, names
+		/// are treated as case insensitive.
+		/// </summary>
+		/// <param name="signatureAlgorithm">The algorithm name.</param>
+		public void SetSignatureAlgorithm(
+			string signatureAlgorithm)
+		{
+			this.signatureAlgorithm = signatureAlgorithm;
+
+			try
+			{
+				sigOID = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+			}
+			catch (Exception)
+			{
+				throw new ArgumentException("Unknown signature type requested");
+			}
+
+			sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+			acInfoGen.SetSignature(sigAlgId);
+		}
+
+		/// <summary>Add an attribute.</summary>
+		public void AddAttribute(
+			X509Attribute attribute)
+		{
+			acInfoGen.AddAttribute(AttributeX509.GetInstance(attribute.ToAsn1Object()));
+		}
+
+		public void SetIssuerUniqueId(
+			bool[] iui)
+		{
+			// TODO convert bool array to bit string
+			//acInfoGen.SetIssuerUniqueID(iui);
+			throw Platform.CreateNotImplementedException("SetIssuerUniqueId()");
+		}
+
+		/// <summary>Add a given extension field for the standard extensions tag.</summary>
+		public void AddExtension(
+			string			oid,
+			bool			critical,
+			Asn1Encodable	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+		}
+
+		/// <summary>
+		/// Add a given extension field for the standard extensions tag.
+		/// The value parameter becomes the contents of the octet string associated
+		/// with the extension.
+		/// </summary>
+		public void AddExtension(
+			string	oid,
+			bool	critical,
+			byte[]	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+		}
+
+		/// <summary>
+		/// Generate an X509 certificate, based on the current issuer and subject.
+		/// </summary>
+		public IX509AttributeCertificate Generate(
+			AsymmetricKeyParameter publicKey)
+		{
+			return Generate(publicKey, null);
+		}
+
+		/// <summary>
+		/// Generate an X509 certificate, based on the current issuer and subject,
+		/// using the supplied source of randomness, if required.
+		/// </summary>
+		public IX509AttributeCertificate Generate(
+			AsymmetricKeyParameter	publicKey,
+			SecureRandom			random)
+		{
+			if (!extGenerator.IsEmpty)
+			{
+				acInfoGen.SetExtensions(extGenerator.Generate());
+			}
+
+			AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
+
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			v.Add(acInfo, sigAlgId);
+
+			try
+			{
+				v.Add(new DerBitString(X509Utilities.GetSignatureForObject(sigOID, signatureAlgorithm, publicKey, random, acInfo)));
+
+				return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v)));
+			}
+			catch (Exception e)
+			{
+				// TODO
+//				throw new ExtCertificateEncodingException("constructed invalid certificate", e);
+				throw new CertificateEncodingException("constructed invalid certificate", e);
+			}
+		}
+
+		/// <summary>
+		/// Allows enumeration of the signature names supported by the generator.
+		/// </summary>
+		public IEnumerable SignatureAlgNames
+		{
+			get { return X509Utilities.GetAlgNames(); }
+		}
+	}
+}
diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs
new file mode 100644
index 000000000..a2293b333
--- /dev/null
+++ b/crypto/src/x509/X509V2CRLGenerator.cs
@@ -0,0 +1,261 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+	/**
+	* class to produce an X.509 Version 2 CRL.
+	*/
+	public class X509V2CrlGenerator
+	{
+		private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+		private V2TbsCertListGenerator	tbsGen;
+		private DerObjectIdentifier		sigOID;
+		private AlgorithmIdentifier		sigAlgId;
+		private string					signatureAlgorithm;
+
+		public X509V2CrlGenerator()
+		{
+			tbsGen = new V2TbsCertListGenerator();
+		}
+
+		/**
+		* reset the generator
+		*/
+		public void Reset()
+		{
+			tbsGen = new V2TbsCertListGenerator();
+			extGenerator.Reset();
+		}
+
+		/**
+		* 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 SetThisUpdate(
+			DateTime date)
+		{
+			tbsGen.SetThisUpdate(new Time(date));
+		}
+
+		public void SetNextUpdate(
+			DateTime date)
+		{
+			tbsGen.SetNextUpdate(new Time(date));
+		}
+
+		/**
+		* Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+		* or 0 if CrlReason is not to be used
+		**/
+		public void AddCrlEntry(
+			BigInteger	userCertificate,
+			DateTime	revocationDate,
+			int			reason)
+		{
+			tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason);
+		}
+
+		/**
+		* Add a CRL entry with an Invalidity Date extension as well as a CrlReason extension.
+		* Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+		* or 0 if CrlReason is not to be used
+		**/
+		public void AddCrlEntry(
+			BigInteger	userCertificate,
+			DateTime	revocationDate,
+			int			reason,
+			DateTime	invalidityDate)
+		{
+			tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason, new DerGeneralizedTime(invalidityDate));
+		}
+
+		/**
+		* Add a CRL entry with extensions.
+		**/
+		public void AddCrlEntry(
+			BigInteger		userCertificate,
+			DateTime		revocationDate,
+			X509Extensions	extensions)
+		{
+			tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), extensions);
+		}
+
+		/**
+		* Add the CRLEntry objects contained in a previous CRL.
+		*
+		* @param other the X509Crl to source the other entries from.
+		*/
+		public void AddCrl(
+			X509Crl other)
+		{
+			if (other == null)
+				throw new ArgumentNullException("other");
+
+			ISet revocations = other.GetRevokedCertificates();
+
+			if (revocations != null)
+			{
+				foreach (X509CrlEntry entry in revocations)
+				{
+					try
+					{
+						tbsGen.AddCrlEntry(
+							Asn1Sequence.GetInstance(
+							Asn1Object.FromByteArray(entry.GetEncoded())));
+					}
+					catch (IOException e)
+					{
+						throw new CrlException("exception processing encoding of CRL", e);
+					}
+				}
+			}
+		}
+
+		/**
+		* 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 = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("Unknown signature type requested", e);
+			}
+
+			sigAlgId = X509Utilities.GetSigAlgID(sigOID, signatureAlgorithm);
+
+			tbsGen.SetSignature(sigAlgId);
+		}
+
+		/**
+		* add a given extension field for the standard extensions tag (tag 0)
+		*/
+		public void AddExtension(
+			string			oid,
+			bool			critical,
+			Asn1Encodable	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+		}
+
+		/**
+		* add a given extension field for the standard extensions tag (tag 0)
+		*/
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			Asn1Encodable		extensionValue)
+		{
+			extGenerator.AddExtension(oid, critical, extensionValue);
+		}
+
+		/**
+		* add a given extension field for the standard extensions tag (tag 0)
+		*/
+		public void AddExtension(
+			string	oid,
+			bool	critical,
+			byte[]	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+		}
+
+		/**
+		* add a given extension field for the standard extensions tag (tag 0)
+		*/
+		public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			byte[]				extensionValue)
+		{
+			extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+		}
+
+		/// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
+		/// <param name="privateKey">The key used for signing.</param>
+		public X509Crl Generate(
+			AsymmetricKeyParameter privateKey)
+		{
+			return Generate(privateKey, null);
+		}
+
+		/// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
+		/// <param name="privateKey">The key used for signing.</param>
+		/// <param name="random">A user-defined source of randomness.</param>
+		public X509Crl Generate(
+			AsymmetricKeyParameter	privateKey,
+			SecureRandom			random)
+		{
+			TbsCertificateList tbsCrl = GenerateCertList();
+			byte[] signature;
+
+			try
+			{
+				signature = X509Utilities.GetSignatureForObject(
+					sigOID, signatureAlgorithm, privateKey, random, tbsCrl);
+			}
+			catch (IOException e)
+			{
+				// TODO
+//				throw new ExtCrlException("cannot generate CRL encoding", e);
+				throw new CrlException("cannot generate CRL encoding", e);
+			}
+
+			return GenerateJcaObject(tbsCrl, signature);
+		}
+
+		private TbsCertificateList GenerateCertList()
+		{
+			if (!extGenerator.IsEmpty)
+			{
+				tbsGen.SetExtensions(extGenerator.Generate());
+			}
+
+			return tbsGen.GenerateTbsCertList();
+		}
+
+		private X509Crl GenerateJcaObject(
+			TbsCertificateList	tbsCrl,
+			byte[]				signature)
+		{
+			return new X509Crl(
+				CertificateList.GetInstance(
+					new DerSequence(tbsCrl, sigAlgId, new DerBitString(signature))));
+		}
+
+		/// <summary>
+		/// Allows enumeration of the signature names supported by the generator.
+		/// </summary>
+		public IEnumerable SignatureAlgNames
+		{
+			get { return X509Utilities.GetAlgNames(); }
+		}
+	}
+}
diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs
new file mode 100644
index 000000000..bb0dd9cbc
--- /dev/null
+++ b/crypto/src/x509/X509V3CertificateGenerator.cs
@@ -0,0 +1,346 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509
+{
+    /// <summary>
+    /// A class to Generate Version 3 X509Certificates.
+    /// </summary>
+    public class X509V3CertificateGenerator
+    {
+		private readonly X509ExtensionsGenerator extGenerator = new X509ExtensionsGenerator();
+
+		private V3TbsCertificateGenerator	tbsGen;
+        private DerObjectIdentifier			sigOid;
+        private AlgorithmIdentifier			sigAlgId;
+        private string						signatureAlgorithm;
+
+		public X509V3CertificateGenerator()
+        {
+            tbsGen = new V3TbsCertificateGenerator();
+        }
+
+		/// <summary>
+		/// Reset the Generator.
+		/// </summary>
+		public void Reset()
+		{
+			tbsGen = new V3TbsCertificateGenerator();
+			extGenerator.Reset();
+		}
+
+		/// <summary>
+        /// Set the certificate's serial number.
+        /// </summary>
+        /// <remarks>Make serial numbers long, if you have no serial number policy make sure the number is at least 16 bytes of secure random data.
+        /// You will be surprised how ugly a serial number collision can Get.</remarks>
+        /// <param name="serialNumber">The serial number.</param>
+        public void SetSerialNumber(
+			BigInteger serialNumber)
+        {
+			if (serialNumber.SignValue <= 0)
+			{
+				throw new ArgumentException("serial number must be a positive integer", "serialNumber");
+			}
+
+			tbsGen.SetSerialNumber(new DerInteger(serialNumber));
+        }
+
+		/// <summary>
+        /// Set the distinguished name of the issuer.
+        /// The issuer is the entity which is signing the certificate.
+        /// </summary>
+        /// <param name="issuer">The issuer's DN.</param>
+        public void SetIssuerDN(
+            X509Name issuer)
+        {
+            tbsGen.SetIssuer(issuer);
+        }
+
+		/// <summary>
+        /// Set the date that this certificate is to be valid from.
+        /// </summary>
+        /// <param name="date"/>
+        public void SetNotBefore(
+            DateTime date)
+        {
+            tbsGen.SetStartDate(new Time(date));
+        }
+
+        /// <summary>
+        /// Set the date after which this certificate will no longer be valid.
+        /// </summary>
+        /// <param name="date"/>
+        public void SetNotAfter(
+			DateTime date)
+        {
+            tbsGen.SetEndDate(new Time(date));
+        }
+
+		/// <summary>
+		/// Set the DN of the entity that this certificate is about.
+		/// </summary>
+		/// <param name="subject"/>
+        public void SetSubjectDN(
+			X509Name subject)
+        {
+            tbsGen.SetSubject(subject);
+        }
+
+		/// <summary>
+        /// Set the public key that this certificate identifies.
+        /// </summary>
+        /// <param name="publicKey"/>
+        public void SetPublicKey(
+			AsymmetricKeyParameter publicKey)
+        {
+            tbsGen.SetSubjectPublicKeyInfo(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey));
+        }
+
+		/// <summary>
+        /// Set the signature algorithm that will be used to sign this certificate.
+        /// </summary>
+        /// <param name="signatureAlgorithm"/>
+        public void SetSignatureAlgorithm(
+			string signatureAlgorithm)
+        {
+			this.signatureAlgorithm = signatureAlgorithm;
+
+			try
+			{
+				sigOid = X509Utilities.GetAlgorithmOid(signatureAlgorithm);
+			}
+			catch (Exception)
+			{
+				throw new ArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+			}
+
+			sigAlgId = X509Utilities.GetSigAlgID(sigOid, signatureAlgorithm);
+
+			tbsGen.SetSignature(sigAlgId);
+		}
+
+		/// <summary>
+		/// Set the subject unique ID - note: it is very rare that it is correct to do this.
+		/// </summary>
+		/// <param name="uniqueID"/>
+		public void SetSubjectUniqueID(
+			bool[] uniqueID)
+		{
+			tbsGen.SetSubjectUniqueID(booleanToBitString(uniqueID));
+		}
+
+		/// <summary>
+		/// Set the issuer unique ID - note: it is very rare that it is correct to do this.
+		/// </summary>
+		/// <param name="uniqueID"/>
+		public void SetIssuerUniqueID(
+			bool[] uniqueID)
+		{
+			tbsGen.SetIssuerUniqueID(booleanToBitString(uniqueID));
+		}
+
+		private DerBitString booleanToBitString(
+			bool[] id)
+		{
+			byte[] bytes = new byte[(id.Length + 7) / 8];
+
+			for (int i = 0; i != id.Length; i++)
+			{
+				if (id[i])
+				{
+					bytes[i / 8] |= (byte)(1 << ((7 - (i % 8))));
+				}
+			}
+
+			int pad = id.Length % 8;
+
+			if (pad == 0)
+			{
+				return new DerBitString(bytes);
+			}
+
+			return new DerBitString(bytes, 8 - pad);
+		}
+
+		/// <summary>
+		/// Add a given extension field for the standard extensions tag (tag 3).
+		/// </summary>
+		/// <param name="oid">string containing a dotted decimal Object Identifier.</param>
+		/// <param name="critical">Is it critical.</param>
+		/// <param name="extensionValue">The value.</param>
+		public void AddExtension(
+			string			oid,
+			bool			critical,
+			Asn1Encodable	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
+		}
+
+		/// <summary>
+        /// Add an extension to this certificate.
+        /// </summary>
+        /// <param name="oid">Its Object Identifier.</param>
+        /// <param name="critical">Is it critical.</param>
+        /// <param name="extensionValue">The value.</param>
+        public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			Asn1Encodable		extensionValue)
+        {
+			extGenerator.AddExtension(oid, critical, extensionValue);
+        }
+
+		/// <summary>
+		/// Add an extension using a string with a dotted decimal OID.
+		/// </summary>
+		/// <param name="oid">string containing a dotted decimal Object Identifier.</param>
+		/// <param name="critical">Is it critical.</param>
+		/// <param name="extensionValue">byte[] containing the value of this extension.</param>
+		public void AddExtension(
+			string	oid,
+			bool	critical,
+			byte[]	extensionValue)
+		{
+			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, new DerOctetString(extensionValue));
+		}
+
+		/// <summary>
+        /// Add an extension to this certificate.
+        /// </summary>
+        /// <param name="oid">Its Object Identifier.</param>
+        /// <param name="critical">Is it critical.</param>
+        /// <param name="extensionValue">byte[] containing the value of this extension.</param>
+        public void AddExtension(
+			DerObjectIdentifier	oid,
+			bool				critical,
+			byte[]				extensionValue)
+        {
+			extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
+        }
+
+		/// <summary>
+		/// Add a given extension field for the standard extensions tag (tag 3),
+		/// copying the extension value from another certificate.
+		/// </summary>
+		public void CopyAndAddExtension(
+			string			oid,
+			bool			critical,
+			X509Certificate	cert)
+		{
+			CopyAndAddExtension(new DerObjectIdentifier(oid), critical, cert);
+		}
+
+		/**
+		 * 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,
+			bool				critical,
+			X509Certificate		cert)
+		{
+			Asn1OctetString extValue = cert.GetExtensionValue(oid);
+
+			if (extValue == null)
+			{
+				throw new CertificateParsingException("extension " + oid + " not present");
+			}
+
+			try
+			{
+				Asn1Encodable value = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+				this.AddExtension(oid, critical, value);
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException(e.Message, e);
+			}
+		}
+
+		/// <summary>
+        /// Generate an X509Certificate.
+        /// </summary>
+        /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+        /// <returns>An X509Certificate.</returns>
+        public X509Certificate Generate(
+			AsymmetricKeyParameter privateKey)
+        {
+            return Generate(privateKey, null);
+        }
+
+		/// <summary>
+		/// Generate an X509Certificate using your own SecureRandom.
+		/// </summary>
+		/// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+		/// <param name="random">You Secure Random instance.</param>
+		/// <returns>An X509Certificate.</returns>
+		public X509Certificate Generate(
+			AsymmetricKeyParameter	privateKey,
+			SecureRandom			random)
+		{
+			TbsCertificateStructure tbsCert = GenerateTbsCert();
+			byte[] signature;
+
+			try
+			{
+				signature = X509Utilities.GetSignatureForObject(
+					sigOid, signatureAlgorithm, privateKey, random, tbsCert);
+			}
+			catch (Exception e)
+			{
+				// TODO
+//				throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+				throw new CertificateEncodingException("exception encoding TBS cert", e);
+			}
+
+			try
+			{
+				return GenerateJcaObject(tbsCert, signature);
+			}
+			catch (CertificateParsingException e)
+			{
+				// TODO
+				// throw new ExtCertificateEncodingException("exception producing certificate object", e);
+				throw new CertificateEncodingException("exception producing certificate object", e);
+			}
+		}
+
+		private TbsCertificateStructure GenerateTbsCert()
+		{
+			if (!extGenerator.IsEmpty)
+			{
+				tbsGen.SetExtensions(extGenerator.Generate());
+			}
+
+			return tbsGen.GenerateTbsCertificate();
+		}
+
+		private X509Certificate GenerateJcaObject(
+			TbsCertificateStructure	tbsCert,
+			byte[]					signature)
+		{
+			return new X509Certificate(
+				new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+		}
+
+		/// <summary>
+		/// Allows enumeration of the signature names supported by the generator.
+		/// </summary>
+		public IEnumerable SignatureAlgNames
+		{
+			get { return X509Utilities.GetAlgNames(); }
+		}
+	}
+}
diff --git a/crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs b/crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs
new file mode 100644
index 000000000..006dc009b
--- /dev/null
+++ b/crypto/src/x509/extension/AuthorityKeyIdentifierStructure.cs
@@ -0,0 +1,102 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+	/// <remarks>A high level authority key identifier.</remarks>
+	public class AuthorityKeyIdentifierStructure
+		: 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.
+		 */
+		// TODO Add a functional constructor from byte[]?
+		public AuthorityKeyIdentifierStructure(
+			Asn1OctetString encodedValue)
+			: base((Asn1Sequence) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+		{
+		}
+
+		private static Asn1Sequence FromCertificate(
+			X509Certificate certificate)
+		{
+			try
+			{
+				GeneralName genName = new GeneralName(
+					PrincipalUtilities.GetIssuerX509Principal(certificate));
+
+				if (certificate.Version == 3)
+				{
+					Asn1OctetString ext = certificate.GetExtensionValue(X509Extensions.SubjectKeyIdentifier);
+
+					if (ext != null)
+					{
+						Asn1OctetString str = (Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(ext);
+
+						return (Asn1Sequence) new AuthorityKeyIdentifier(
+							str.GetOctets(), new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+					}
+				}
+
+				SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+					certificate.GetPublicKey());
+
+				return (Asn1Sequence) new AuthorityKeyIdentifier(
+					info, new GeneralNames(genName), certificate.SerialNumber).ToAsn1Object();
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("Exception extracting certificate details", e);
+			}
+		}
+
+		private static Asn1Sequence FromKey(
+			AsymmetricKeyParameter pubKey)
+		{
+			try
+			{
+				SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+				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)
+			: base(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(
+			AsymmetricKeyParameter pubKey)
+			: base(FromKey(pubKey))
+		{
+		}
+	}
+}
diff --git a/crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs b/crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs
new file mode 100644
index 000000000..4c7b79ab8
--- /dev/null
+++ b/crypto/src/x509/extension/SubjectKeyIdentifierStructure.cs
@@ -0,0 +1,49 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security.Certificates;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+	/**
+	 * A high level subject key identifier.
+	 */
+	public class SubjectKeyIdentifierStructure
+		: 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(
+			Asn1OctetString encodedValue)
+			: base((Asn1OctetString) X509ExtensionUtilities.FromExtensionValue(encodedValue))
+		{
+		}
+
+		private static Asn1OctetString FromPublicKey(
+			AsymmetricKeyParameter pubKey)
+		{
+			try
+			{
+				SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pubKey);
+
+				return (Asn1OctetString) new SubjectKeyIdentifier(info).ToAsn1Object();
+			}
+			catch (Exception e)
+			{
+				throw new CertificateParsingException("Exception extracting certificate details: " + e.ToString());
+			}
+		}
+
+		public SubjectKeyIdentifierStructure(
+			AsymmetricKeyParameter pubKey)
+			: base(FromPublicKey(pubKey))
+		{
+		}
+	}
+}
diff --git a/crypto/src/x509/extension/X509ExtensionUtil.cs b/crypto/src/x509/extension/X509ExtensionUtil.cs
new file mode 100644
index 000000000..845a87bad
--- /dev/null
+++ b/crypto/src/x509/extension/X509ExtensionUtil.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Extension
+{
+	public class X509ExtensionUtilities
+	{
+		public static Asn1Object FromExtensionValue(
+			Asn1OctetString extensionValue)
+		{
+			return Asn1Object.FromByteArray(extensionValue.GetOctets());
+		}
+
+		public static ICollection GetIssuerAlternativeNames(
+			X509Certificate cert)
+		{
+			Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.IssuerAlternativeName);
+
+			return GetAlternativeName(extVal);
+		}
+
+		public static ICollection GetSubjectAlternativeNames(
+			X509Certificate cert)
+		{
+			Asn1OctetString extVal = cert.GetExtensionValue(X509Extensions.SubjectAlternativeName);
+
+			return GetAlternativeName(extVal);
+		}
+
+		private static ICollection GetAlternativeName(
+			Asn1OctetString extVal)
+		{
+			IList temp = Platform.CreateArrayList();
+
+			if (extVal != null)
+			{
+				try
+				{
+					Asn1Sequence seq = DerSequence.GetInstance(FromExtensionValue(extVal));
+
+					foreach (GeneralName genName in seq)
+					{
+                        IList list = Platform.CreateArrayList();
+						list.Add(genName.TagNo);
+
+						switch (genName.TagNo)
+						{
+							case GeneralName.EdiPartyName:
+							case GeneralName.X400Address:
+							case GeneralName.OtherName:
+								list.Add(genName.Name.ToAsn1Object());
+								break;
+							case GeneralName.DirectoryName:
+								list.Add(X509Name.GetInstance(genName.Name).ToString());
+								break;
+							case GeneralName.DnsName:
+							case GeneralName.Rfc822Name:
+							case GeneralName.UniformResourceIdentifier:
+								list.Add(((IAsn1String)genName.Name).GetString());
+								break;
+							case GeneralName.RegisteredID:
+								list.Add(DerObjectIdentifier.GetInstance(genName.Name).Id);
+								break;
+							case GeneralName.IPAddress:
+								list.Add(DerOctetString.GetInstance(genName.Name).GetOctets());
+								break;
+							default:
+								throw new IOException("Bad tag number: " + genName.TagNo);
+						}
+
+						temp.Add(list);
+					}
+				}
+				catch (Exception e)
+				{
+					throw new CertificateParsingException(e.Message);
+				}
+			}
+
+			return temp;
+		}
+	}
+}
diff --git a/crypto/src/x509/store/IX509Selector.cs b/crypto/src/x509/store/IX509Selector.cs
index 3f37fcd66..09f6f1849 100644
--- a/crypto/src/x509/store/IX509Selector.cs
+++ b/crypto/src/x509/store/IX509Selector.cs
@@ -3,11 +3,11 @@ using System;
 namespace Org.BouncyCastle.X509.Store
 {
 	public interface IX509Selector
-#if !(SILVERLIGHT || PORTABLE)
+#if !SILVERLIGHT
 		: ICloneable
 #endif
-    {
-#if SILVERLIGHT || PORTABLE
+	{
+#if SILVERLIGHT
         object Clone();
 #endif
         bool Match(object obj);
diff --git a/crypto/src/x509/store/IX509Store.cs b/crypto/src/x509/store/IX509Store.cs
new file mode 100644
index 000000000..e5c3a462a
--- /dev/null
+++ b/crypto/src/x509/store/IX509Store.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public interface IX509Store
+	{
+//		void Init(IX509StoreParameters parameters);
+		ICollection GetMatches(IX509Selector selector);
+	}
+}
diff --git a/crypto/src/x509/store/IX509StoreParameters.cs b/crypto/src/x509/store/IX509StoreParameters.cs
new file mode 100644
index 000000000..aee3036c2
--- /dev/null
+++ b/crypto/src/x509/store/IX509StoreParameters.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public interface IX509StoreParameters
+	{
+	}
+}
diff --git a/crypto/src/x509/store/NoSuchStoreException.cs b/crypto/src/x509/store/NoSuchStoreException.cs
index 3df26de79..02c593245 100644
--- a/crypto/src/x509/store/NoSuchStoreException.cs
+++ b/crypto/src/x509/store/NoSuchStoreException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.X509.Store
 {
-	public class NoSuchStoreException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class NoSuchStoreException
 		: X509StoreException
 	{
 		public NoSuchStoreException()
diff --git a/crypto/src/x509/store/X509AttrCertStoreSelector.cs b/crypto/src/x509/store/X509AttrCertStoreSelector.cs
new file mode 100644
index 000000000..9f1dc20d1
--- /dev/null
+++ b/crypto/src/x509/store/X509AttrCertStoreSelector.cs
@@ -0,0 +1,376 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	/**
+	* This class is an <code>Selector</code> like implementation to select
+	* attribute certificates from a given set of criteria.
+	*
+	* @see org.bouncycastle.x509.X509AttributeCertificate
+	* @see org.bouncycastle.x509.X509Store
+	*/
+	public class X509AttrCertStoreSelector
+		: IX509Selector
+	{
+		// TODO: name constraints???
+
+		private IX509AttributeCertificate attributeCert;
+		private DateTimeObject attributeCertificateValid;
+		private AttributeCertificateHolder holder;
+		private AttributeCertificateIssuer issuer;
+		private BigInteger serialNumber;
+		private ISet targetNames = new HashSet();
+		private ISet targetGroups = new HashSet();
+
+		public X509AttrCertStoreSelector()
+		{
+		}
+
+		private X509AttrCertStoreSelector(
+			X509AttrCertStoreSelector o)
+		{
+			this.attributeCert = o.attributeCert;
+			this.attributeCertificateValid = o.attributeCertificateValid;
+			this.holder = o.holder;
+			this.issuer = o.issuer;
+			this.serialNumber = o.serialNumber;
+			this.targetGroups = new HashSet(o.targetGroups);
+			this.targetNames = new HashSet(o.targetNames);
+		}
+
+		/// <summary>
+		/// Decides if the given attribute certificate should be selected.
+		/// </summary>
+		/// <param name="obj">The attribute certificate to be checked.</param>
+		/// <returns><code>true</code> if the object matches this selector.</returns>
+		public bool Match(
+			object obj)
+		{
+			if (obj == null)
+				throw new ArgumentNullException("obj");
+
+			IX509AttributeCertificate attrCert = obj as IX509AttributeCertificate;
+
+			if (attrCert == null)
+				return false;
+
+			if (this.attributeCert != null && !this.attributeCert.Equals(attrCert))
+				return false;
+
+			if (serialNumber != null && !attrCert.SerialNumber.Equals(serialNumber))
+				return false;
+
+			if (holder != null && !attrCert.Holder.Equals(holder))
+				return false;
+
+			if (issuer != null && !attrCert.Issuer.Equals(issuer))
+				return false;
+
+			if (attributeCertificateValid != null && !attrCert.IsValid(attributeCertificateValid.Value))
+				return false;
+
+			if (targetNames.Count > 0 || targetGroups.Count > 0)
+			{
+				Asn1OctetString targetInfoExt = attrCert.GetExtensionValue(
+					X509Extensions.TargetInformation);
+
+				if (targetInfoExt != null)
+				{
+					TargetInformation targetinfo;
+					try
+					{
+						targetinfo = TargetInformation.GetInstance(
+							X509ExtensionUtilities.FromExtensionValue(targetInfoExt));
+					}
+					catch (Exception)
+					{
+						return false;
+					}
+
+					Targets[] targetss = targetinfo.GetTargetsObjects();
+
+					if (targetNames.Count > 0)
+					{
+						bool found = false;
+
+						for (int i = 0; i < targetss.Length && !found; i++)
+						{
+							Target[] targets = targetss[i].GetTargets();
+
+							for (int j = 0; j < targets.Length; j++)
+							{
+								GeneralName targetName = targets[j].TargetName;
+
+								if (targetName != null && targetNames.Contains(targetName))
+								{
+									found = true;
+									break;
+								}
+							}
+						}
+						if (!found)
+						{
+							return false;
+						}
+					}
+
+					if (targetGroups.Count > 0)
+					{
+						bool found = false;
+
+						for (int i = 0; i < targetss.Length && !found; i++)
+						{
+							Target[] targets = targetss[i].GetTargets();
+
+							for (int j = 0; j < targets.Length; j++)
+							{
+								GeneralName targetGroup = targets[j].TargetGroup;
+
+								if (targetGroup != null && targetGroups.Contains(targetGroup))
+								{
+									found = true;
+									break;
+								}
+							}
+						}
+
+						if (!found)
+						{
+							return false;
+						}
+					}
+				}
+			}
+
+			return true;
+		}
+
+		public object Clone()
+		{
+			return new X509AttrCertStoreSelector(this);
+		}
+
+		/// <summary>The attribute certificate which must be matched.</summary>
+		/// <remarks>If <c>null</c> is given, any will do.</remarks>
+		public IX509AttributeCertificate AttributeCert
+		{
+			get { return attributeCert; }
+			set { this.attributeCert = value; }
+		}
+
+		[Obsolete("Use AttributeCertificateValid instead")]
+		public DateTimeObject AttribueCertificateValid
+		{
+			get { return attributeCertificateValid; }
+			set { this.attributeCertificateValid = value; }
+		}
+
+		/// <summary>The criteria for validity</summary>
+		/// <remarks>If <c>null</c> is given any will do.</remarks>
+		public DateTimeObject AttributeCertificateValid
+		{
+			get { return attributeCertificateValid; }
+			set { this.attributeCertificateValid = value; }
+		}
+
+		/// <summary>The holder.</summary>
+		/// <remarks>If <c>null</c> is given any will do.</remarks>
+		public AttributeCertificateHolder Holder
+		{
+			get { return holder; }
+			set { this.holder = value; }
+		}
+
+		/// <summary>The issuer.</summary>
+		/// <remarks>If <c>null</c> is given any will do.</remarks>
+		public AttributeCertificateIssuer Issuer
+		{
+			get { return issuer; }
+			set { this.issuer = value; }
+		}
+
+		/// <summary>The serial number.</summary>
+		/// <remarks>If <c>null</c> is given any will do.</remarks>
+		public BigInteger SerialNumber
+		{
+			get { return serialNumber; }
+			set { this.serialNumber = value; }
+		}
+
+		/**
+		* Adds a target name criterion for the attribute certificate to the target
+		* information extension criteria. The <code>X509AttributeCertificate</code>
+		* must contain at least one of the specified target names.
+		* <p>
+		* Each attribute certificate may contain a target information extension
+		* limiting the servers where this attribute certificate can be used. If
+		* this extension is not present, the attribute certificate is not targeted
+		* and may be accepted by any server.
+		* </p>
+		*
+		* @param name The name as a GeneralName (not <code>null</code>)
+		*/
+		public void AddTargetName(
+			GeneralName name)
+		{
+			targetNames.Add(name);
+		}
+
+		/**
+		* Adds a target name criterion for the attribute certificate to the target
+		* information extension criteria. The <code>X509AttributeCertificate</code>
+		* must contain at least one of the specified target names.
+		* <p>
+		* Each attribute certificate may contain a target information extension
+		* limiting the servers where this attribute certificate can be used. If
+		* this extension is not present, the attribute certificate is not targeted
+		* and may be accepted by any server.
+		* </p>
+		*
+		* @param name a byte array containing the name in ASN.1 DER encoded form of a GeneralName
+		* @throws IOException if a parsing error occurs.
+		*/
+		public void AddTargetName(
+			byte[] name)
+		{
+			AddTargetName(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+		}
+
+		/**
+		* Adds a collection with target names criteria. If <code>null</code> is
+		* given any will do.
+		* <p>
+		* The collection consists of either GeneralName objects or byte[] arrays representing
+		* DER encoded GeneralName structures.
+		* </p>
+		* 
+		* @param names A collection of target names.
+		* @throws IOException if a parsing error occurs.
+		* @see #AddTargetName(byte[])
+		* @see #AddTargetName(GeneralName)
+		*/
+		public void SetTargetNames(
+			IEnumerable names)
+		{
+			targetNames = ExtractGeneralNames(names);
+		}
+
+		/**
+		* Gets the target names. The collection consists of <code>List</code>s
+		* made up of an <code>Integer</code> in the first entry and a DER encoded
+		* byte array or a <code>String</code> in the second entry.
+		* <p>The returned collection is immutable.</p>
+		* 
+		* @return The collection of target names
+		* @see #setTargetNames(Collection)
+		*/
+		public IEnumerable GetTargetNames()
+		{
+			return new EnumerableProxy(targetNames);
+		}
+
+		/**
+		* Adds a target group criterion for the attribute certificate to the target
+		* information extension criteria. The <code>X509AttributeCertificate</code>
+		* must contain at least one of the specified target groups.
+		* <p>
+		* Each attribute certificate may contain a target information extension
+		* limiting the servers where this attribute certificate can be used. If
+		* this extension is not present, the attribute certificate is not targeted
+		* and may be accepted by any server.
+		* </p>
+		*
+		* @param group The group as GeneralName form (not <code>null</code>)
+		*/
+		public void AddTargetGroup(
+			GeneralName group)
+		{
+			targetGroups.Add(group);
+		}
+
+		/**
+		* Adds a target group criterion for the attribute certificate to the target
+		* information extension criteria. The <code>X509AttributeCertificate</code>
+		* must contain at least one of the specified target groups.
+		* <p>
+		* Each attribute certificate may contain a target information extension
+		* limiting the servers where this attribute certificate can be used. If
+		* this extension is not present, the attribute certificate is not targeted
+		* and may be accepted by any server.
+		* </p>
+		*
+		* @param name a byte array containing the group in ASN.1 DER encoded form of a GeneralName
+		* @throws IOException if a parsing error occurs.
+		*/
+		public void AddTargetGroup(
+			byte[] name)
+		{
+			AddTargetGroup(GeneralName.GetInstance(Asn1Object.FromByteArray(name)));
+		}
+
+		/**
+		* Adds a collection with target groups criteria. If <code>null</code> is
+		* given any will do.
+		* <p>
+		* The collection consists of <code>GeneralName</code> objects or <code>byte[]</code>
+		* representing DER encoded GeneralNames.
+		* </p>
+		*
+		* @param names A collection of target groups.
+		* @throws IOException if a parsing error occurs.
+		* @see #AddTargetGroup(byte[])
+		* @see #AddTargetGroup(GeneralName)
+		*/
+		public void SetTargetGroups(
+			IEnumerable names)
+		{
+			targetGroups = ExtractGeneralNames(names);
+		}
+
+		/**
+		* Gets the target groups. The collection consists of <code>List</code>s
+		* made up of an <code>Integer</code> in the first entry and a DER encoded
+		* byte array or a <code>String</code> in the second entry.
+		* <p>The returned collection is immutable.</p>
+		*
+		* @return The collection of target groups.
+		* @see #setTargetGroups(Collection)
+		*/
+		public IEnumerable GetTargetGroups()
+		{
+			return new EnumerableProxy(targetGroups);
+		}
+
+		private ISet ExtractGeneralNames(
+			IEnumerable names)
+		{
+			ISet result = new HashSet();
+
+			if (names != null)
+			{
+				foreach (object o in names)
+				{
+					if (o is GeneralName)
+					{
+						result.Add(o);
+					}
+					else
+					{
+						result.Add(GeneralName.GetInstance(Asn1Object.FromByteArray((byte[]) o)));
+					}
+				}
+			}
+
+			return result;
+		}
+	}
+}
diff --git a/crypto/src/x509/store/X509CertPairStoreSelector.cs b/crypto/src/x509/store/X509CertPairStoreSelector.cs
new file mode 100644
index 000000000..2796971c7
--- /dev/null
+++ b/crypto/src/x509/store/X509CertPairStoreSelector.cs
@@ -0,0 +1,92 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	/// <remarks>
+	/// This class is an <code>IX509Selector</code> implementation to select
+	/// certificate pairs, which are e.g. used for cross certificates. The set of
+	/// criteria is given from two <code>X509CertStoreSelector</code> objects,
+	/// each of which, if present, must match the respective component of a pair.
+	/// </remarks>
+	public class X509CertPairStoreSelector
+		: IX509Selector
+	{
+		private static X509CertStoreSelector CloneSelector(
+			X509CertStoreSelector s)
+		{
+			return s == null ? null : (X509CertStoreSelector) s.Clone();
+		}
+
+		private X509CertificatePair certPair;
+		private X509CertStoreSelector forwardSelector;
+		private X509CertStoreSelector reverseSelector;
+
+		public X509CertPairStoreSelector()
+		{
+		}
+
+		private X509CertPairStoreSelector(
+			X509CertPairStoreSelector o)
+		{
+			this.certPair = o.CertPair;
+			this.forwardSelector = o.ForwardSelector;
+			this.reverseSelector = o.ReverseSelector;
+		}
+
+		/// <summary>The certificate pair which is used for testing on equality.</summary>
+		public X509CertificatePair CertPair
+		{
+			get { return certPair; }
+			set { this.certPair = value; }
+		}
+
+		/// <summary>The certificate selector for the forward part.</summary>
+		public X509CertStoreSelector ForwardSelector
+		{
+			get { return CloneSelector(forwardSelector); }
+			set { this.forwardSelector = CloneSelector(value); }
+		}
+
+		/// <summary>The certificate selector for the reverse part.</summary>
+		public X509CertStoreSelector ReverseSelector
+		{
+			get { return CloneSelector(reverseSelector); }
+			set { this.reverseSelector = CloneSelector(value); }
+		}
+
+		/// <summary>
+		/// Decides if the given certificate pair should be selected. If
+		/// <c>obj</c> is not a <code>X509CertificatePair</code>, this method
+		/// returns <code>false</code>.
+		/// </summary>
+		/// <param name="obj">The <code>X509CertificatePair</code> to be tested.</param>
+		/// <returns><code>true</code> if the object matches this selector.</returns>
+		public bool Match(
+			object obj)
+		{
+			if (obj == null)
+				throw new ArgumentNullException("obj");
+
+			X509CertificatePair pair = obj as X509CertificatePair;
+
+			if (pair == null)
+				return false;
+
+			if (certPair != null && !certPair.Equals(pair))
+				return false;
+
+			if (forwardSelector != null && !forwardSelector.Match(pair.Forward))
+				return false;
+
+			if (reverseSelector != null && !reverseSelector.Match(pair.Reverse))
+				return false;
+
+			return true;
+		}
+
+		public object Clone()
+		{
+			return new X509CertPairStoreSelector(this);
+		}
+	}
+}
diff --git a/crypto/src/x509/store/X509CertStoreSelector.cs b/crypto/src/x509/store/X509CertStoreSelector.cs
new file mode 100644
index 000000000..3874edf1d
--- /dev/null
+++ b/crypto/src/x509/store/X509CertStoreSelector.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public class X509CertStoreSelector
+		: IX509Selector
+	{
+		// TODO Missing criteria?
+
+		private byte[] authorityKeyIdentifier;
+		private int basicConstraints = -1;
+		private X509Certificate certificate;
+		private DateTimeObject certificateValid;
+		private ISet extendedKeyUsage;
+		private X509Name issuer;
+		private bool[] keyUsage;
+		private ISet policy;
+		private DateTimeObject privateKeyValid;
+		private BigInteger serialNumber;
+		private X509Name subject;
+		private byte[] subjectKeyIdentifier;
+		private SubjectPublicKeyInfo subjectPublicKey;
+		private DerObjectIdentifier subjectPublicKeyAlgID;
+
+		public X509CertStoreSelector()
+		{
+		}
+
+		public X509CertStoreSelector(
+			X509CertStoreSelector o)
+		{
+			this.authorityKeyIdentifier = o.AuthorityKeyIdentifier;
+			this.basicConstraints = o.BasicConstraints;
+			this.certificate = o.Certificate;
+			this.certificateValid = o.CertificateValid;
+			this.extendedKeyUsage = o.ExtendedKeyUsage;
+			this.issuer = o.Issuer;
+			this.keyUsage = o.KeyUsage;
+			this.policy = o.Policy;
+			this.privateKeyValid = o.PrivateKeyValid;
+			this.serialNumber = o.SerialNumber;
+			this.subject = o.Subject;
+			this.subjectKeyIdentifier = o.SubjectKeyIdentifier;
+			this.subjectPublicKey = o.SubjectPublicKey;
+			this.subjectPublicKeyAlgID = o.SubjectPublicKeyAlgID;
+		}
+
+		public virtual object Clone()
+		{
+			return new X509CertStoreSelector(this);
+		}
+
+		public byte[] AuthorityKeyIdentifier
+		{
+			get { return Arrays.Clone(authorityKeyIdentifier); }
+			set { authorityKeyIdentifier = Arrays.Clone(value); }
+		}
+
+		public int BasicConstraints
+		{
+			get { return basicConstraints; }
+			set
+			{
+				if (value < -2)
+					throw new ArgumentException("value can't be less than -2", "value");
+
+				basicConstraints = value;
+			}
+		}
+
+		public X509Certificate Certificate
+		{
+			get { return certificate; }
+			set { this.certificate = value; }
+		}
+
+		public DateTimeObject CertificateValid
+		{
+			get { return certificateValid; }
+			set { certificateValid = value; }
+		}
+
+		public ISet ExtendedKeyUsage
+		{
+			get { return CopySet(extendedKeyUsage); }
+			set { extendedKeyUsage = CopySet(value); }
+		}
+
+		public X509Name Issuer
+		{
+			get { return issuer; }
+			set { issuer = value; }
+		}
+
+		[Obsolete("Avoid working with X509Name objects in string form")]
+		public string IssuerAsString
+		{
+			get { return issuer != null ? issuer.ToString() : null; }
+		}
+
+		public bool[] KeyUsage
+		{
+			get { return CopyBoolArray(keyUsage); }
+			set { keyUsage = CopyBoolArray(value); }
+		}
+
+		/// <summary>
+		/// An <code>ISet</code> of <code>DerObjectIdentifier</code> objects.
+		/// </summary>
+		public ISet Policy
+		{
+			get { return CopySet(policy); }
+			set { policy = CopySet(value); }
+		}
+
+		public DateTimeObject PrivateKeyValid
+		{
+			get { return privateKeyValid; }
+			set { privateKeyValid = value; }
+		}
+
+		public BigInteger SerialNumber
+		{
+			get { return serialNumber; }
+			set { serialNumber = value; }
+		}
+
+		public X509Name Subject
+		{
+			get { return subject; }
+			set { subject = value; }
+		}
+
+		public string SubjectAsString
+		{
+			get { return subject != null ? subject.ToString() : null; }
+		}
+
+		public byte[] SubjectKeyIdentifier
+		{
+			get { return Arrays.Clone(subjectKeyIdentifier); }
+			set { subjectKeyIdentifier = Arrays.Clone(value); }
+		}
+
+		public SubjectPublicKeyInfo SubjectPublicKey
+		{
+			get { return subjectPublicKey; }
+			set { subjectPublicKey = value; }
+		}
+
+		public DerObjectIdentifier SubjectPublicKeyAlgID
+		{
+			get { return subjectPublicKeyAlgID; }
+			set { subjectPublicKeyAlgID = value; }
+		}
+
+		public virtual bool Match(
+			object obj)
+		{
+			X509Certificate c = obj as X509Certificate;
+
+			if (c == null)
+				return false;
+
+			if (!MatchExtension(authorityKeyIdentifier, c, X509Extensions.AuthorityKeyIdentifier))
+				return false;
+
+			if (basicConstraints != -1)
+			{
+				int bc = c.GetBasicConstraints();
+
+				if (basicConstraints == -2)
+				{
+					if (bc != -1)
+						return false;
+				}
+				else
+				{
+					if (bc < basicConstraints)
+						return false;
+				}
+			}
+
+			if (certificate != null && !certificate.Equals(c))
+				return false;
+
+			if (certificateValid != null && !c.IsValid(certificateValid.Value))
+				return false;
+
+			if (extendedKeyUsage != null)
+			{
+				IList eku = c.GetExtendedKeyUsage();
+
+				// Note: if no extended key usage set, all key purposes are implicitly allowed
+
+				if (eku != null)
+				{
+					foreach (DerObjectIdentifier oid in extendedKeyUsage)
+					{
+						if (!eku.Contains(oid.Id))
+							return false;
+					}
+				}
+			}
+
+			if (issuer != null && !issuer.Equivalent(c.IssuerDN, true))
+				return false;
+
+			if (keyUsage != null)
+			{
+				bool[] ku = c.GetKeyUsage();
+
+				// Note: if no key usage set, all key purposes are implicitly allowed
+
+				if (ku != null)
+				{
+					for (int i = 0; i < 9; ++i)
+					{
+						if (keyUsage[i] && !ku[i])
+							return false;
+					}
+				}
+			}
+
+			if (policy != null)
+			{
+				Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CertificatePolicies);
+				if (extVal == null)
+					return false;
+
+				Asn1Sequence certPolicies = Asn1Sequence.GetInstance(
+					X509ExtensionUtilities.FromExtensionValue(extVal));
+
+				if (policy.Count < 1 && certPolicies.Count < 1)
+					return false;
+
+				bool found = false;
+				foreach (PolicyInformation pi in certPolicies)
+				{
+					if (policy.Contains(pi.PolicyIdentifier))
+					{
+						found = true;
+						break;
+					}
+				}
+
+				if (!found)
+					return false;
+			}
+
+			if (privateKeyValid != null)
+			{
+				Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.PrivateKeyUsagePeriod);
+				if (extVal == null)
+					return false;
+
+				PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.GetInstance(
+					X509ExtensionUtilities.FromExtensionValue(extVal));
+
+				DateTime dt = privateKeyValid.Value;
+				DateTime notAfter = pkup.NotAfter.ToDateTime();
+				DateTime notBefore = pkup.NotBefore.ToDateTime();
+
+				if (dt.CompareTo(notAfter) > 0 || dt.CompareTo(notBefore) < 0)
+					return false;
+			}
+
+			if (serialNumber != null && !serialNumber.Equals(c.SerialNumber))
+				return false;
+
+			if (subject != null && !subject.Equivalent(c.SubjectDN, true))
+				return false;
+
+			if (!MatchExtension(subjectKeyIdentifier, c, X509Extensions.SubjectKeyIdentifier))
+				return false;
+
+			if (subjectPublicKey != null && !subjectPublicKey.Equals(GetSubjectPublicKey(c)))
+				return false;
+
+			if (subjectPublicKeyAlgID != null
+				&& !subjectPublicKeyAlgID.Equals(GetSubjectPublicKey(c).AlgorithmID))
+				return false;
+
+			return true;
+		}
+
+		internal static bool IssuersMatch(
+			X509Name	a,
+			X509Name	b)
+		{
+			return a == null ? b == null : a.Equivalent(b, true);
+		}
+
+		private static bool[] CopyBoolArray(
+			bool[] b)
+		{
+			return b == null ? null : (bool[]) b.Clone();
+		}
+
+		private static ISet CopySet(
+			ISet s)
+		{
+			return s == null ? null : new HashSet(s);
+		}
+
+		private static SubjectPublicKeyInfo GetSubjectPublicKey(
+			X509Certificate c)
+		{
+			return SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(c.GetPublicKey());
+		}
+
+		private static bool MatchExtension(
+			byte[]				b,
+			X509Certificate		c,
+			DerObjectIdentifier	oid)
+		{
+			if (b == null)
+				return true;
+
+			Asn1OctetString extVal = c.GetExtensionValue(oid);
+
+			if (extVal == null)
+				return false;
+
+			return Arrays.AreEqual(b, extVal.GetOctets());
+		}
+	}
+}
diff --git a/crypto/src/x509/store/X509CollectionStore.cs b/crypto/src/x509/store/X509CollectionStore.cs
new file mode 100644
index 000000000..92173140b
--- /dev/null
+++ b/crypto/src/x509/store/X509CollectionStore.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	/**
+	 * A simple collection backed store.
+	 */
+	internal class X509CollectionStore
+		: IX509Store
+	{
+		private ICollection _local;
+
+		/**
+		 * Basic constructor.
+		 *
+		 * @param collection - initial contents for the store, this is copied.
+		 */
+		internal X509CollectionStore(
+			ICollection collection)
+		{
+			_local = Platform.CreateArrayList(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 ICollection GetMatches(
+			IX509Selector selector)
+		{
+			if (selector == null)
+			{
+                return Platform.CreateArrayList(_local);
+			}
+
+            IList result = Platform.CreateArrayList();
+			foreach (object obj in _local)
+			{
+				if (selector.Match(obj))
+					result.Add(obj);
+			}
+
+			return result;
+		}
+	}
+}
diff --git a/crypto/src/x509/store/X509CollectionStoreParameters.cs b/crypto/src/x509/store/X509CollectionStoreParameters.cs
new file mode 100644
index 000000000..7fd047a47
--- /dev/null
+++ b/crypto/src/x509/store/X509CollectionStoreParameters.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	/// <remarks>This class contains a collection for collection based <code>X509Store</code>s.</remarks>
+	public class X509CollectionStoreParameters
+		: IX509StoreParameters
+	{
+		private readonly IList collection;
+
+		/// <summary>
+		/// Constructor.
+		/// <p>
+		/// The collection is copied.
+		/// </p>
+		/// </summary>
+		/// <param name="collection">The collection containing X.509 object types.</param>
+		/// <exception cref="ArgumentNullException">If collection is null.</exception>
+		public X509CollectionStoreParameters(
+			ICollection collection)
+		{
+			if (collection == null)
+				throw new ArgumentNullException("collection");
+
+			this.collection = Platform.CreateArrayList(collection);
+		}
+
+		// TODO Do we need to be able to Clone() these, and should it really be shallow?
+//		/**
+//		* 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);
+//		}
+
+		/// <summary>Returns a copy of the <code>ICollection</code>.</summary>
+		public ICollection GetCollection()
+		{
+			return Platform.CreateArrayList(collection);
+		}
+
+		/// <summary>Returns a formatted string describing the parameters.</summary>
+		public override string ToString()
+		{
+			StringBuilder sb = new StringBuilder();
+			sb.Append("X509CollectionStoreParameters: [\n");
+			sb.Append("  collection: " + collection + "\n");
+			sb.Append("]");
+			return sb.ToString();
+		}
+	}
+}
diff --git a/crypto/src/x509/store/X509CrlStoreSelector.cs b/crypto/src/x509/store/X509CrlStoreSelector.cs
new file mode 100644
index 000000000..c4b0062c1
--- /dev/null
+++ b/crypto/src/x509/store/X509CrlStoreSelector.cs
@@ -0,0 +1,283 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public class X509CrlStoreSelector
+		: IX509Selector
+	{
+		// TODO Missing criteria?
+
+		private X509Certificate certificateChecking;
+		private DateTimeObject dateAndTime;
+		private ICollection issuers;
+		private BigInteger maxCrlNumber;
+		private BigInteger minCrlNumber;
+
+		private IX509AttributeCertificate attrCertChecking;
+		private bool completeCrlEnabled;
+		private bool deltaCrlIndicatorEnabled;
+		private byte[] issuingDistributionPoint;
+		private bool issuingDistributionPointEnabled;
+		private BigInteger maxBaseCrlNumber;
+
+		public X509CrlStoreSelector()
+		{
+		}
+
+		public X509CrlStoreSelector(
+			X509CrlStoreSelector o)
+		{
+			this.certificateChecking = o.CertificateChecking;
+			this.dateAndTime = o.DateAndTime;
+			this.issuers = o.Issuers;
+			this.maxCrlNumber = o.MaxCrlNumber;
+			this.minCrlNumber = o.MinCrlNumber;
+
+			this.deltaCrlIndicatorEnabled = o.DeltaCrlIndicatorEnabled;
+			this.completeCrlEnabled = o.CompleteCrlEnabled;
+			this.maxBaseCrlNumber = o.MaxBaseCrlNumber;
+			this.attrCertChecking = o.AttrCertChecking;
+			this.issuingDistributionPointEnabled = o.IssuingDistributionPointEnabled;
+			this.issuingDistributionPoint = o.IssuingDistributionPoint;
+		}
+
+		public virtual object Clone()
+		{
+			return new X509CrlStoreSelector(this);
+		}
+
+		public X509Certificate CertificateChecking
+		{
+			get { return certificateChecking; }
+			set { certificateChecking = value; }
+		}
+
+		public DateTimeObject DateAndTime
+		{
+			get { return dateAndTime; }
+			set { dateAndTime = value; }
+		}
+
+		/// <summary>
+		/// An <code>ICollection</code> of <code>X509Name</code> objects
+		/// </summary>
+		public ICollection Issuers
+		{
+			get { return Platform.CreateArrayList(issuers); }
+            set { issuers = Platform.CreateArrayList(value); }
+		}
+
+		public BigInteger MaxCrlNumber
+		{
+			get { return maxCrlNumber; }
+			set { maxCrlNumber = value; }
+		}
+
+		public BigInteger MinCrlNumber
+		{
+			get { return minCrlNumber; }
+			set { minCrlNumber = value; }
+		}
+
+		/**
+		 * 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>IX509AttributeCertificate</code> being checked (or
+		 *             <code>null</code>)
+		 * @see #getAttrCertificateChecking()
+		 */
+		public IX509AttributeCertificate AttrCertChecking
+		{
+			get { return attrCertChecking; }
+			set { this.attrCertChecking = value; }
+		}
+
+		/**
+		 * 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 bool CompleteCrlEnabled
+		{
+			get { return completeCrlEnabled; }
+			set { this.completeCrlEnabled = value; }
+		}
+
+		/**
+		 * 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 bool DeltaCrlIndicatorEnabled
+		{
+			get { return deltaCrlIndicatorEnabled; }
+			set { this.deltaCrlIndicatorEnabled = value; }
+		}
+
+		/**
+		 * 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>
+		 * <p>
+		 * The byte array is cloned to protect against subsequent modifications.</p>
+		 * <p>
+		 * You must also enable or disable this criteria with
+		 * {@link #setIssuingDistributionPointEnabled(bool)}.</p>
+		 *
+		 * @param issuingDistributionPoint The issuing distribution point to set.
+		 *                                 This is the DER encoded OCTET STRING extension value.
+		 * @see #getIssuingDistributionPoint()
+		 */
+		public byte[] IssuingDistributionPoint
+		{
+			get { return Arrays.Clone(issuingDistributionPoint); }
+			set { this.issuingDistributionPoint = Arrays.Clone(value); }
+		}
+
+		/**
+		 * Whether 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.</p>
+		 *
+		 * @return Returns if the issuing distribution point check is enabled.
+		 */
+		public bool IssuingDistributionPointEnabled
+		{
+			get { return issuingDistributionPointEnabled; }
+			set { this.issuingDistributionPointEnabled = value; }
+		}
+
+		/**
+		 * The maximum base CRL number. Defaults to <code>null</code>.
+		 *
+		 * @return Returns the maximum base CRL number.
+		 * @see #setMaxBaseCRLNumber(BigInteger)
+		 */
+		public BigInteger MaxBaseCrlNumber
+		{
+			get { return maxBaseCrlNumber; }
+			set { this.maxBaseCrlNumber = value; }
+		}
+
+		public virtual bool Match(
+			object obj)
+		{
+			X509Crl c = obj as X509Crl;
+
+			if (c == null)
+				return false;
+
+			if (dateAndTime != null)
+			{
+				DateTime dt = dateAndTime.Value;
+				DateTime tu = c.ThisUpdate;
+				DateTimeObject nu = c.NextUpdate;
+
+				if (dt.CompareTo(tu) < 0 || nu == null || dt.CompareTo(nu.Value) >= 0)
+					return false;
+			}
+
+			if (issuers != null)
+			{
+				X509Name i = c.IssuerDN;
+
+				bool found = false;
+
+				foreach (X509Name issuer in issuers)
+				{
+					if (issuer.Equivalent(i, true))
+					{
+						found = true;
+						break;
+					}
+				}
+
+				if (!found)
+					return false;
+			}
+
+			if (maxCrlNumber != null || minCrlNumber != null)
+			{
+				Asn1OctetString extVal = c.GetExtensionValue(X509Extensions.CrlNumber);
+				if (extVal == null)
+					return false;
+
+				BigInteger cn = CrlNumber.GetInstance(
+					X509ExtensionUtilities.FromExtensionValue(extVal)).PositiveValue;
+
+				if (maxCrlNumber != null && cn.CompareTo(maxCrlNumber) > 0)
+					return false;
+
+				if (minCrlNumber != null && cn.CompareTo(minCrlNumber) < 0)
+					return false;
+			}
+
+			DerInteger dci = null;
+			try
+			{
+				Asn1OctetString bytes = c.GetExtensionValue(X509Extensions.DeltaCrlIndicator);
+				if (bytes != null)
+				{
+					dci = DerInteger.GetInstance(X509ExtensionUtilities.FromExtensionValue(bytes));
+				}
+			}
+			catch (Exception)
+			{
+				return false;
+			}
+
+			if (dci == null)
+			{
+				if (DeltaCrlIndicatorEnabled)
+					return false;
+			}
+			else
+			{
+				if (CompleteCrlEnabled)
+					return false;
+
+				if (maxBaseCrlNumber != null && dci.PositiveValue.CompareTo(maxBaseCrlNumber) > 0)
+					return false;
+			}
+
+			if (issuingDistributionPointEnabled)
+			{
+				Asn1OctetString idp = c.GetExtensionValue(X509Extensions.IssuingDistributionPoint);
+				if (issuingDistributionPoint == null)
+				{
+					if (idp != null)
+						return false;
+				}
+				else
+				{
+					if (!Arrays.AreEqual(idp.GetOctets(), issuingDistributionPoint))
+						return false;
+				}
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/crypto/src/x509/store/X509StoreException.cs b/crypto/src/x509/store/X509StoreException.cs
index f6a5e235f..f781291e2 100644
--- a/crypto/src/x509/store/X509StoreException.cs
+++ b/crypto/src/x509/store/X509StoreException.cs
@@ -2,7 +2,10 @@ using System;
 
 namespace Org.BouncyCastle.X509.Store
 {
-	public class X509StoreException
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class X509StoreException
 		: Exception
 	{
 		public X509StoreException()
diff --git a/crypto/src/x509/store/X509StoreFactory.cs b/crypto/src/x509/store/X509StoreFactory.cs
index 322639991..96f22be3f 100644
--- a/crypto/src/x509/store/X509StoreFactory.cs
+++ b/crypto/src/x509/store/X509StoreFactory.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections;
-using System.Globalization;
+
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.X509.Store
 {
@@ -17,9 +18,9 @@ namespace Org.BouncyCastle.X509.Store
 			if (type == null)
 				throw new ArgumentNullException("type");
 
-			string[] parts = type.ToUpperInvariant().Split('/');
+			string[] parts = Platform.ToUpperInvariant(type).Split('/');
 
-			if (parts.Length < 2)
+            if (parts.Length < 2)
 				throw new ArgumentException("type");
 
 			if (parts[1] != "COLLECTION")
diff --git a/crypto/test/data/PKITS/README.txt b/crypto/test/data/PKITS/README.txt
new file mode 100644
index 000000000..00a124b65
--- /dev/null
+++ b/crypto/test/data/PKITS/README.txt
@@ -0,0 +1,3 @@
+PKITS test data from http://csrc.nist.gov/pki/testing/x509paths.html
+
+For more details please check the website above.
diff --git a/crypto/test/data/PKITS/certs/AllCertificatesNoPoliciesTest2EE.crt b/crypto/test/data/PKITS/certs/AllCertificatesNoPoliciesTest2EE.crt
new file mode 100644
index 000000000..6c40491f2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/AllCertificatesNoPoliciesTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest10EE.crt b/crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest10EE.crt
new file mode 100644
index 000000000..41b6d15b2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest13EE.crt b/crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest13EE.crt
new file mode 100644
index 000000000..9210106f5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/AllCertificatesSamePoliciesTest13EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/AllCertificatesanyPolicyTest11EE.crt b/crypto/test/data/PKITS/certs/AllCertificatesanyPolicyTest11EE.crt
new file mode 100644
index 000000000..a7f9d22b0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/AllCertificatesanyPolicyTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/AnyPolicyTest14EE.crt b/crypto/test/data/PKITS/certs/AnyPolicyTest14EE.crt
new file mode 100644
index 000000000..b5961c75f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/AnyPolicyTest14EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BadCRLIssuerNameCACert.crt b/crypto/test/data/PKITS/certs/BadCRLIssuerNameCACert.crt
new file mode 100644
index 000000000..6afe5ddd0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BadCRLIssuerNameCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BadCRLSignatureCACert.crt b/crypto/test/data/PKITS/certs/BadCRLSignatureCACert.crt
new file mode 100644
index 000000000..bfac8a406
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BadCRLSignatureCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BadSignedCACert.crt b/crypto/test/data/PKITS/certs/BadSignedCACert.crt
new file mode 100644
index 000000000..abf7f319c
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BadSignedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BadnotAfterDateCACert.crt b/crypto/test/data/PKITS/certs/BadnotAfterDateCACert.crt
new file mode 100644
index 000000000..d8babc267
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BadnotAfterDateCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BadnotBeforeDateCACert.crt b/crypto/test/data/PKITS/certs/BadnotBeforeDateCACert.crt
new file mode 100644
index 000000000..9b4cd824a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BadnotBeforeDateCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCACert.crt b/crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCACert.crt
new file mode 100644
index 000000000..41881148c
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCRLCert.crt b/crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCRLCert.crt
new file mode 100644
index 000000000..7c1b13952
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BasicSelfIssuedCRLSigningKeyCRLCert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyCACert.crt b/crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyCACert.crt
new file mode 100644
index 000000000..b4ccbe84f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyOldWithNewCACert.crt b/crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyOldWithNewCACert.crt
new file mode 100644
index 000000000..336a1caa0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BasicSelfIssuedNewKeyOldWithNewCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyCACert.crt b/crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyCACert.crt
new file mode 100644
index 000000000..78953d66f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyNewWithOldCACert.crt b/crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyNewWithOldCACert.crt
new file mode 100644
index 000000000..853dc0613
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/BasicSelfIssuedOldKeyNewWithOldCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/CPSPointerQualifierTest20EE.crt b/crypto/test/data/PKITS/certs/CPSPointerQualifierTest20EE.crt
new file mode 100644
index 000000000..8bc703698
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/CPSPointerQualifierTest20EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DSACACert.crt b/crypto/test/data/PKITS/certs/DSACACert.crt
new file mode 100644
index 000000000..a1f9e05f6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DSACACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DSAParametersInheritedCACert.crt b/crypto/test/data/PKITS/certs/DSAParametersInheritedCACert.crt
new file mode 100644
index 000000000..7eae4863e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DSAParametersInheritedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DifferentPoliciesTest12EE.crt b/crypto/test/data/PKITS/certs/DifferentPoliciesTest12EE.crt
new file mode 100644
index 000000000..6aa6ae5cd
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DifferentPoliciesTest12EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DifferentPoliciesTest3EE.crt b/crypto/test/data/PKITS/certs/DifferentPoliciesTest3EE.crt
new file mode 100644
index 000000000..8cd24ec7e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DifferentPoliciesTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DifferentPoliciesTest4EE.crt b/crypto/test/data/PKITS/certs/DifferentPoliciesTest4EE.crt
new file mode 100644
index 000000000..6af794d89
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DifferentPoliciesTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DifferentPoliciesTest5EE.crt b/crypto/test/data/PKITS/certs/DifferentPoliciesTest5EE.crt
new file mode 100644
index 000000000..43150466b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DifferentPoliciesTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DifferentPoliciesTest7EE.crt b/crypto/test/data/PKITS/certs/DifferentPoliciesTest7EE.crt
new file mode 100644
index 000000000..8caf46a33
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DifferentPoliciesTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DifferentPoliciesTest8EE.crt b/crypto/test/data/PKITS/certs/DifferentPoliciesTest8EE.crt
new file mode 100644
index 000000000..f49721d7e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DifferentPoliciesTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/DifferentPoliciesTest9EE.crt b/crypto/test/data/PKITS/certs/DifferentPoliciesTest9EE.crt
new file mode 100644
index 000000000..49a38a558
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/DifferentPoliciesTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/GeneralizedTimeCRLnextUpdateCACert.crt b/crypto/test/data/PKITS/certs/GeneralizedTimeCRLnextUpdateCACert.crt
new file mode 100644
index 000000000..c22228aa0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/GeneralizedTimeCRLnextUpdateCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/GoodCACert.crt b/crypto/test/data/PKITS/certs/GoodCACert.crt
new file mode 100644
index 000000000..5aecbc0cf
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/GoodCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/GoodsubCACert.crt b/crypto/test/data/PKITS/certs/GoodsubCACert.crt
new file mode 100644
index 000000000..09c98aad6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/GoodsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/GoodsubCAPanyPolicyMapping1to2CACert.crt b/crypto/test/data/PKITS/certs/GoodsubCAPanyPolicyMapping1to2CACert.crt
new file mode 100644
index 000000000..2540cd45d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/GoodsubCAPanyPolicyMapping1to2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidBadCRLIssuerNameTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidBadCRLIssuerNameTest5EE.crt
new file mode 100644
index 000000000..749f7cc0f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidBadCRLIssuerNameTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidBadCRLSignatureTest4EE.crt b/crypto/test/data/PKITS/certs/InvalidBadCRLSignatureTest4EE.crt
new file mode 100644
index 000000000..3c4d2cbe2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidBadCRLSignatureTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt
new file mode 100644
index 000000000..7919115d2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt
new file mode 100644
index 000000000..b242bad64
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedCRLSigningKeyTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedNewWithOldTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedNewWithOldTest5EE.crt
new file mode 100644
index 000000000..e75d97865
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedNewWithOldTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedOldWithNewTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedOldWithNewTest2EE.crt
new file mode 100644
index 000000000..ed3000124
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidBasicSelfIssuedOldWithNewTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidCASignatureTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidCASignatureTest2EE.crt
new file mode 100644
index 000000000..8d337bddf
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidCASignatureTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidCAnotAfterDateTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidCAnotAfterDateTest5EE.crt
new file mode 100644
index 000000000..6f6748d07
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidCAnotAfterDateTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidCAnotBeforeDateTest1EE.crt b/crypto/test/data/PKITS/certs/InvalidCAnotBeforeDateTest1EE.crt
new file mode 100644
index 000000000..e7b01de4d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidCAnotBeforeDateTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest31EE.crt b/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest31EE.crt
new file mode 100644
index 000000000..3f86eefe0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest31EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest33EE.crt b/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest33EE.crt
new file mode 100644
index 000000000..805205b29
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest33EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest38EE.crt b/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest38EE.crt
new file mode 100644
index 000000000..eff3779d3
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNSnameConstraintsTest38EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest28EE.crt b/crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest28EE.crt
new file mode 100644
index 000000000..7c1dd9cb2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest28EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest29EE.crt b/crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest29EE.crt
new file mode 100644
index 000000000..bdf08adcb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNandRFC822nameConstraintsTest29EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest10EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest10EE.crt
new file mode 100644
index 000000000..5ff84a45b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest12EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest12EE.crt
new file mode 100644
index 000000000..11ec10fe8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest12EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest13EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest13EE.crt
new file mode 100644
index 000000000..08c3050d1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest13EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest15EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest15EE.crt
new file mode 100644
index 000000000..28ab46587
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest15EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest16EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest16EE.crt
new file mode 100644
index 000000000..56e42d0f1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest16EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest17EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest17EE.crt
new file mode 100644
index 000000000..f9f53b932
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest17EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest20EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest20EE.crt
new file mode 100644
index 000000000..15fbe8faa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest20EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest2EE.crt
new file mode 100644
index 000000000..8daf2f2a6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest3EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest3EE.crt
new file mode 100644
index 000000000..52cd9993e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest7EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest7EE.crt
new file mode 100644
index 000000000..799760b5f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest8EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest8EE.crt
new file mode 100644
index 000000000..d874621eb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest9EE.crt b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest9EE.crt
new file mode 100644
index 000000000..18314bd01
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDNnameConstraintsTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidDSASignatureTest6EE.crt b/crypto/test/data/PKITS/certs/InvalidDSASignatureTest6EE.crt
new file mode 100644
index 000000000..bcc900cf4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidDSASignatureTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidEESignatureTest3EE.crt b/crypto/test/data/PKITS/certs/InvalidEESignatureTest3EE.crt
new file mode 100644
index 000000000..e21461e37
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidEESignatureTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidEEnotAfterDateTest6EE.crt b/crypto/test/data/PKITS/certs/InvalidEEnotAfterDateTest6EE.crt
new file mode 100644
index 000000000..46269d05e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidEEnotAfterDateTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidEEnotBeforeDateTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidEEnotBeforeDateTest2EE.crt
new file mode 100644
index 000000000..f1bf1d1a4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidEEnotBeforeDateTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest23EE.crt b/crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest23EE.crt
new file mode 100644
index 000000000..31965f628
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest23EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest26EE.crt b/crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest26EE.crt
new file mode 100644
index 000000000..b9b87a6c1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidIDPwithindirectCRLTest26EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidLongSerialNumberTest18EE.crt b/crypto/test/data/PKITS/certs/InvalidLongSerialNumberTest18EE.crt
new file mode 100644
index 000000000..1c84dce0e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidLongSerialNumberTest18EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidMappingFromanyPolicyTest7EE.crt b/crypto/test/data/PKITS/certs/InvalidMappingFromanyPolicyTest7EE.crt
new file mode 100644
index 000000000..49aab726e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidMappingFromanyPolicyTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidMappingToanyPolicyTest8EE.crt b/crypto/test/data/PKITS/certs/InvalidMappingToanyPolicyTest8EE.crt
new file mode 100644
index 000000000..0a56c5e0d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidMappingToanyPolicyTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidMissingCRLTest1EE.crt b/crypto/test/data/PKITS/certs/InvalidMissingCRLTest1EE.crt
new file mode 100644
index 000000000..7af5ce5aa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidMissingCRLTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidMissingbasicConstraintsTest1EE.crt b/crypto/test/data/PKITS/certs/InvalidMissingbasicConstraintsTest1EE.crt
new file mode 100644
index 000000000..f5d8703c3
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidMissingbasicConstraintsTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidNameChainingOrderTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidNameChainingOrderTest2EE.crt
new file mode 100644
index 000000000..9c40a3391
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidNameChainingOrderTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidNameChainingTest1EE.crt b/crypto/test/data/PKITS/certs/InvalidNameChainingTest1EE.crt
new file mode 100644
index 000000000..f7ae3b0e8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidNameChainingTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidNegativeSerialNumberTest15EE.crt b/crypto/test/data/PKITS/certs/InvalidNegativeSerialNumberTest15EE.crt
new file mode 100644
index 000000000..2d323b4df
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidNegativeSerialNumberTest15EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidOldCRLnextUpdateTest11EE.crt b/crypto/test/data/PKITS/certs/InvalidOldCRLnextUpdateTest11EE.crt
new file mode 100644
index 000000000..858db72d6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidOldCRLnextUpdateTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest10EE.crt b/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest10EE.crt
new file mode 100644
index 000000000..ef227b8ea
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest2EE.crt
new file mode 100644
index 000000000..58ace916a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest4EE.crt b/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest4EE.crt
new file mode 100644
index 000000000..c0dd555d5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidPolicyMappingTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest22EE.crt b/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest22EE.crt
new file mode 100644
index 000000000..d8134e0a6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest22EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest24EE.crt b/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest24EE.crt
new file mode 100644
index 000000000..b71c6a377
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest24EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest26EE.crt b/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest26EE.crt
new file mode 100644
index 000000000..0ffdf26fa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidRFC822nameConstraintsTest26EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidRevokedCATest2EE.crt b/crypto/test/data/PKITS/certs/InvalidRevokedCATest2EE.crt
new file mode 100644
index 000000000..65a0a1ab4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidRevokedCATest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidRevokedEETest3EE.crt b/crypto/test/data/PKITS/certs/InvalidRevokedEETest3EE.crt
new file mode 100644
index 000000000..80ea4d3f5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidRevokedEETest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest10EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest10EE.crt
new file mode 100644
index 000000000..21c32e976
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest8EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest8EE.crt
new file mode 100644
index 000000000..d57f0cb52
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitAnyPolicyTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest10EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest10EE.crt
new file mode 100644
index 000000000..577998c4f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest11EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest11EE.crt
new file mode 100644
index 000000000..621c325eb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest8EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest8EE.crt
new file mode 100644
index 000000000..98f8160cb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest9EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest9EE.crt
new file mode 100644
index 000000000..b80277286
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedinhibitPolicyMappingTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedpathLenConstraintTest16EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedpathLenConstraintTest16EE.crt
new file mode 100644
index 000000000..9fba63afb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedpathLenConstraintTest16EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest7EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest7EE.crt
new file mode 100644
index 000000000..a1b58ffaa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest8EE.crt b/crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest8EE.crt
new file mode 100644
index 000000000..108f38c5f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSelfIssuedrequireExplicitPolicyTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest20EE.crt b/crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest20EE.crt
new file mode 100644
index 000000000..8671cc6f5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest20EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest21EE.crt b/crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest21EE.crt
new file mode 100644
index 000000000..b8faa4acc
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidSeparateCertificateandCRLKeysTest21EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest35EE.crt b/crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest35EE.crt
new file mode 100644
index 000000000..5313fc96d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest35EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest37EE.crt b/crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest37EE.crt
new file mode 100644
index 000000000..81fd01db7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidURInameConstraintsTest37EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidUnknownCRLEntryExtensionTest8EE.crt b/crypto/test/data/PKITS/certs/InvalidUnknownCRLEntryExtensionTest8EE.crt
new file mode 100644
index 000000000..6170daef8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidUnknownCRLEntryExtensionTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest10EE.crt b/crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest10EE.crt
new file mode 100644
index 000000000..8c8dfc0d8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest9EE.crt b/crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest9EE.crt
new file mode 100644
index 000000000..83c1b6af4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidUnknownCRLExtensionTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidUnknownCriticalCertificateExtensionTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidUnknownCriticalCertificateExtensionTest2EE.crt
new file mode 100644
index 000000000..65c7a68ec
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidUnknownCriticalCertificateExtensionTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidWrongCRLTest6EE.crt b/crypto/test/data/PKITS/certs/InvalidWrongCRLTest6EE.crt
new file mode 100644
index 000000000..206892ceb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidWrongCRLTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidcAFalseTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidcAFalseTest2EE.crt
new file mode 100644
index 000000000..25b925a28
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidcAFalseTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidcAFalseTest3EE.crt b/crypto/test/data/PKITS/certs/InvalidcAFalseTest3EE.crt
new file mode 100644
index 000000000..5d8f86320
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidcAFalseTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest27EE.crt b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest27EE.crt
new file mode 100644
index 000000000..1cb9f595d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest27EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest31EE.crt b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest31EE.crt
new file mode 100644
index 000000000..7e08a55d3
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest31EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest32EE.crt b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest32EE.crt
new file mode 100644
index 000000000..ec020a1a4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest32EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest34EE.crt b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest34EE.crt
new file mode 100644
index 000000000..b309b809b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest34EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest35EE.crt b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest35EE.crt
new file mode 100644
index 000000000..257daab5a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidcRLIssuerTest35EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddeltaCRLIndicatorNoBaseTest1EE.crt b/crypto/test/data/PKITS/certs/InvaliddeltaCRLIndicatorNoBaseTest1EE.crt
new file mode 100644
index 000000000..30e49a4ec
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddeltaCRLIndicatorNoBaseTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest10EE.crt b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest10EE.crt
new file mode 100644
index 000000000..d60e4f698
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest3EE.crt b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest3EE.crt
new file mode 100644
index 000000000..27ce111ae
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest4EE.crt b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest4EE.crt
new file mode 100644
index 000000000..a7edcf890
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest6EE.crt b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest6EE.crt
new file mode 100644
index 000000000..0e247f2ab
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest9EE.crt b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest9EE.crt
new file mode 100644
index 000000000..e5b34e4ac
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddeltaCRLTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddistributionPointTest2EE.crt b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest2EE.crt
new file mode 100644
index 000000000..c61a6460a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddistributionPointTest3EE.crt b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest3EE.crt
new file mode 100644
index 000000000..531033234
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddistributionPointTest6EE.crt b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest6EE.crt
new file mode 100644
index 000000000..9236346ee
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddistributionPointTest8EE.crt b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest8EE.crt
new file mode 100644
index 000000000..3520f6a3f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvaliddistributionPointTest9EE.crt b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest9EE.crt
new file mode 100644
index 000000000..5982bb6a2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvaliddistributionPointTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest1EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest1EE.crt
new file mode 100644
index 000000000..b6fe66182
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest4EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest4EE.crt
new file mode 100644
index 000000000..e6a924a1a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest5EE.crt
new file mode 100644
index 000000000..20c40a497
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest6EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest6EE.crt
new file mode 100644
index 000000000..03c8a3208
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitAnyPolicyTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest1EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest1EE.crt
new file mode 100644
index 000000000..f028a76ff
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest3EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest3EE.crt
new file mode 100644
index 000000000..3393af56c
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest5EE.crt
new file mode 100644
index 000000000..374681425
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest6EE.crt b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest6EE.crt
new file mode 100644
index 000000000..9f7eafa22
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidinhibitPolicyMappingTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt b/crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt
new file mode 100644
index 000000000..888f7e2ae
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalcRLSignFalseTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt b/crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt
new file mode 100644
index 000000000..43b0d9587
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidkeyUsageCriticalkeyCertSignFalseTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt
new file mode 100644
index 000000000..fbfb4c4e4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalcRLSignFalseTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt b/crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt
new file mode 100644
index 000000000..a9da41446
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidkeyUsageNotCriticalkeyCertSignFalseTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlyContainsAttributeCertsTest14EE.crt b/crypto/test/data/PKITS/certs/InvalidonlyContainsAttributeCertsTest14EE.crt
new file mode 100644
index 000000000..60e0f7dbf
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlyContainsAttributeCertsTest14EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlyContainsCACertsTest12EE.crt b/crypto/test/data/PKITS/certs/InvalidonlyContainsCACertsTest12EE.crt
new file mode 100644
index 000000000..c0ada1281
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlyContainsCACertsTest12EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlyContainsUserCertsTest11EE.crt b/crypto/test/data/PKITS/certs/InvalidonlyContainsUserCertsTest11EE.crt
new file mode 100644
index 000000000..acf119985
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlyContainsUserCertsTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest15EE.crt b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest15EE.crt
new file mode 100644
index 000000000..45460ee00
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest15EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest16EE.crt b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest16EE.crt
new file mode 100644
index 000000000..b82e84e61
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest16EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest17EE.crt b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest17EE.crt
new file mode 100644
index 000000000..d29a9ff08
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest17EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest20EE.crt b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest20EE.crt
new file mode 100644
index 000000000..431d60071
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest20EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest21EE.crt b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest21EE.crt
new file mode 100644
index 000000000..68bf8f9ab
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidonlySomeReasonsTest21EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest10EE.crt b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest10EE.crt
new file mode 100644
index 000000000..788389d3e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest11EE.crt b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest11EE.crt
new file mode 100644
index 000000000..01ea4d0b7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest12EE.crt b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest12EE.crt
new file mode 100644
index 000000000..231641608
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest12EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest5EE.crt
new file mode 100644
index 000000000..7164f04fe
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest6EE.crt b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest6EE.crt
new file mode 100644
index 000000000..eec5f9de1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest9EE.crt b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest9EE.crt
new file mode 100644
index 000000000..6a063a61d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidpathLenConstraintTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/Invalidpre2000CRLnextUpdateTest12EE.crt b/crypto/test/data/PKITS/certs/Invalidpre2000CRLnextUpdateTest12EE.crt
new file mode 100644
index 000000000..634a08e51
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/Invalidpre2000CRLnextUpdateTest12EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crt b/crypto/test/data/PKITS/certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crt
new file mode 100644
index 000000000..88916af6f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/Invalidpre2000UTCEEnotAfterDateTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest3EE.crt b/crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest3EE.crt
new file mode 100644
index 000000000..38f98e475
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest5EE.crt b/crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest5EE.crt
new file mode 100644
index 000000000..ca3ea17b8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/InvalidrequireExplicitPolicyTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/LongSerialNumberCACert.crt b/crypto/test/data/PKITS/certs/LongSerialNumberCACert.crt
new file mode 100644
index 000000000..6aaf3d0a4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/LongSerialNumberCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/Mapping1to2CACert.crt b/crypto/test/data/PKITS/certs/Mapping1to2CACert.crt
new file mode 100644
index 000000000..a458115a3
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/Mapping1to2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/MappingFromanyPolicyCACert.crt b/crypto/test/data/PKITS/certs/MappingFromanyPolicyCACert.crt
new file mode 100644
index 000000000..812da596d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/MappingFromanyPolicyCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/MappingToanyPolicyCACert.crt b/crypto/test/data/PKITS/certs/MappingToanyPolicyCACert.crt
new file mode 100644
index 000000000..42effeb79
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/MappingToanyPolicyCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/MissingbasicConstraintsCACert.crt b/crypto/test/data/PKITS/certs/MissingbasicConstraintsCACert.crt
new file mode 100644
index 000000000..17ebf2523
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/MissingbasicConstraintsCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/NameOrderingCACert.crt b/crypto/test/data/PKITS/certs/NameOrderingCACert.crt
new file mode 100644
index 000000000..6b744db06
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/NameOrderingCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/NegativeSerialNumberCACert.crt b/crypto/test/data/PKITS/certs/NegativeSerialNumberCACert.crt
new file mode 100644
index 000000000..57fc93300
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/NegativeSerialNumberCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/NoCRLCACert.crt b/crypto/test/data/PKITS/certs/NoCRLCACert.crt
new file mode 100644
index 000000000..acd908c6f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/NoCRLCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/NoPoliciesCACert.crt b/crypto/test/data/PKITS/certs/NoPoliciesCACert.crt
new file mode 100644
index 000000000..5e2a3fc70
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/NoPoliciesCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/NoissuingDistributionPointCACert.crt b/crypto/test/data/PKITS/certs/NoissuingDistributionPointCACert.crt
new file mode 100644
index 000000000..bf4f8140f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/NoissuingDistributionPointCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/OldCRLnextUpdateCACert.crt b/crypto/test/data/PKITS/certs/OldCRLnextUpdateCACert.crt
new file mode 100644
index 000000000..c9fb043b8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/OldCRLnextUpdateCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/OverlappingPoliciesTest6EE.crt b/crypto/test/data/PKITS/certs/OverlappingPoliciesTest6EE.crt
new file mode 100644
index 000000000..56d136cfd
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/OverlappingPoliciesTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/P12Mapping1to3CACert.crt b/crypto/test/data/PKITS/certs/P12Mapping1to3CACert.crt
new file mode 100644
index 000000000..f9ed7b756
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/P12Mapping1to3CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/P12Mapping1to3subCACert.crt b/crypto/test/data/PKITS/certs/P12Mapping1to3subCACert.crt
new file mode 100644
index 000000000..2029d6ba7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/P12Mapping1to3subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/P12Mapping1to3subsubCACert.crt b/crypto/test/data/PKITS/certs/P12Mapping1to3subsubCACert.crt
new file mode 100644
index 000000000..50e7fcd26
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/P12Mapping1to3subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/P1Mapping1to234CACert.crt b/crypto/test/data/PKITS/certs/P1Mapping1to234CACert.crt
new file mode 100644
index 000000000..d7b3028d6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/P1Mapping1to234CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/P1Mapping1to234subCACert.crt b/crypto/test/data/PKITS/certs/P1Mapping1to234subCACert.crt
new file mode 100644
index 000000000..8648ddec9
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/P1Mapping1to234subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/P1anyPolicyMapping1to2CACert.crt b/crypto/test/data/PKITS/certs/P1anyPolicyMapping1to2CACert.crt
new file mode 100644
index 000000000..85e39feaa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/P1anyPolicyMapping1to2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PanyPolicyMapping1to2CACert.crt b/crypto/test/data/PKITS/certs/PanyPolicyMapping1to2CACert.crt
new file mode 100644
index 000000000..5abbb788d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PanyPolicyMapping1to2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP1234CACert.crt b/crypto/test/data/PKITS/certs/PoliciesP1234CACert.crt
new file mode 100644
index 000000000..9a5eb5b73
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP1234CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP1234subCAP123Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP1234subCAP123Cert.crt
new file mode 100644
index 000000000..9b385455d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP1234subCAP123Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP1234subsubCAP123P12Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP1234subsubCAP123P12Cert.crt
new file mode 100644
index 000000000..4990a9b9d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP1234subsubCAP123P12Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP123CACert.crt b/crypto/test/data/PKITS/certs/PoliciesP123CACert.crt
new file mode 100644
index 000000000..03509d172
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP123CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP123subCAP12Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP123subCAP12Cert.crt
new file mode 100644
index 000000000..0009819fa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP123subCAP12Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P1Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P1Cert.crt
new file mode 100644
index 000000000..669c18190
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P2Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P2Cert.crt
new file mode 100644
index 000000000..faa7516b7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP123subsubCAP12P2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP123subsubsubCAP12P2P1Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP123subsubsubCAP12P2P1Cert.crt
new file mode 100644
index 000000000..44346d5c2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP123subsubsubCAP12P2P1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP12CACert.crt b/crypto/test/data/PKITS/certs/PoliciesP12CACert.crt
new file mode 100644
index 000000000..27bf52414
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP12CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP12subCAP1Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP12subCAP1Cert.crt
new file mode 100644
index 000000000..9a24328a7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP12subCAP1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP12subsubCAP1P2Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP12subsubCAP1P2Cert.crt
new file mode 100644
index 000000000..49cc0ed6d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP12subsubCAP1P2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP2subCA2Cert.crt b/crypto/test/data/PKITS/certs/PoliciesP2subCA2Cert.crt
new file mode 100644
index 000000000..ccbedc695
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP2subCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP2subCACert.crt b/crypto/test/data/PKITS/certs/PoliciesP2subCACert.crt
new file mode 100644
index 000000000..ce66a79b5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP2subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/PoliciesP3CACert.crt b/crypto/test/data/PKITS/certs/PoliciesP3CACert.crt
new file mode 100644
index 000000000..90c4d266e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/PoliciesP3CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/RFC3280MandatoryAttributeTypesCACert.crt b/crypto/test/data/PKITS/certs/RFC3280MandatoryAttributeTypesCACert.crt
new file mode 100644
index 000000000..fa0e1c8f4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/RFC3280MandatoryAttributeTypesCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/RFC3280OptionalAttributeTypesCACert.crt b/crypto/test/data/PKITS/certs/RFC3280OptionalAttributeTypesCACert.crt
new file mode 100644
index 000000000..973373b10
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/RFC3280OptionalAttributeTypesCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/RevokedsubCACert.crt b/crypto/test/data/PKITS/certs/RevokedsubCACert.crt
new file mode 100644
index 000000000..edbd547f0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/RevokedsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/RolloverfromPrintableStringtoUTF8StringCACert.crt b/crypto/test/data/PKITS/certs/RolloverfromPrintableStringtoUTF8StringCACert.crt
new file mode 100644
index 000000000..658f20cf5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/RolloverfromPrintableStringtoUTF8StringCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CRLSigningCert.crt b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CRLSigningCert.crt
new file mode 100644
index 000000000..67135a6c0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CRLSigningCert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CertificateSigningCACert.crt b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CertificateSigningCACert.crt
new file mode 100644
index 000000000..c05f92c3b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCA2CertificateSigningCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCRLSigningCert.crt b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCRLSigningCert.crt
new file mode 100644
index 000000000..8c7200f87
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCRLSigningCert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCertificateSigningCACert.crt b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCertificateSigningCACert.crt
new file mode 100644
index 000000000..10deedd4f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/SeparateCertificateandCRLKeysCertificateSigningCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/TrustAnchorRootCertificate.crt b/crypto/test/data/PKITS/certs/TrustAnchorRootCertificate.crt
new file mode 100644
index 000000000..21f520ee5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/TrustAnchorRootCertificate.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/TwoCRLsCACert.crt b/crypto/test/data/PKITS/certs/TwoCRLsCACert.crt
new file mode 100644
index 000000000..c6389d36a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/TwoCRLsCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UIDCACert.crt b/crypto/test/data/PKITS/certs/UIDCACert.crt
new file mode 100644
index 000000000..d852bc095
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UIDCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UTF8StringCaseInsensitiveMatchCACert.crt b/crypto/test/data/PKITS/certs/UTF8StringCaseInsensitiveMatchCACert.crt
new file mode 100644
index 000000000..c59715d5e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UTF8StringCaseInsensitiveMatchCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UTF8StringEncodedNamesCACert.crt b/crypto/test/data/PKITS/certs/UTF8StringEncodedNamesCACert.crt
new file mode 100644
index 000000000..68d49e021
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UTF8StringEncodedNamesCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UnknownCRLEntryExtensionCACert.crt b/crypto/test/data/PKITS/certs/UnknownCRLEntryExtensionCACert.crt
new file mode 100644
index 000000000..8c81c3744
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UnknownCRLEntryExtensionCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UnknownCRLExtensionCACert.crt b/crypto/test/data/PKITS/certs/UnknownCRLExtensionCACert.crt
new file mode 100644
index 000000000..db7d39e59
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UnknownCRLExtensionCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UserNoticeQualifierTest15EE.crt b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest15EE.crt
new file mode 100644
index 000000000..e912cdfa9
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest15EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UserNoticeQualifierTest16EE.crt b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest16EE.crt
new file mode 100644
index 000000000..ec04e1f3d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest16EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UserNoticeQualifierTest17EE.crt b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest17EE.crt
new file mode 100644
index 000000000..f78a47d6a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest17EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UserNoticeQualifierTest18EE.crt b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest18EE.crt
new file mode 100644
index 000000000..cc5cf5a77
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest18EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/UserNoticeQualifierTest19EE.crt b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest19EE.crt
new file mode 100644
index 000000000..3df534a98
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/UserNoticeQualifierTest19EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt
new file mode 100644
index 000000000..034de7fe0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedCRLSigningKeyTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest3EE.crt b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest3EE.crt
new file mode 100644
index 000000000..199afb768
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest4EE.crt b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest4EE.crt
new file mode 100644
index 000000000..d4323162e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedNewWithOldTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedOldWithNewTest1EE.crt b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedOldWithNewTest1EE.crt
new file mode 100644
index 000000000..b54a8b0f4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidBasicSelfIssuedOldWithNewTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidCertificatePathTest1EE.crt b/crypto/test/data/PKITS/certs/ValidCertificatePathTest1EE.crt
new file mode 100644
index 000000000..26985c9f6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidCertificatePathTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest30EE.crt b/crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest30EE.crt
new file mode 100644
index 000000000..ec7d43d46
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest30EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest32EE.crt b/crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest32EE.crt
new file mode 100644
index 000000000..ed88860ba
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNSnameConstraintsTest32EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNandRFC822nameConstraintsTest27EE.crt b/crypto/test/data/PKITS/certs/ValidDNandRFC822nameConstraintsTest27EE.crt
new file mode 100644
index 000000000..73759dca2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNandRFC822nameConstraintsTest27EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest11EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest11EE.crt
new file mode 100644
index 000000000..1af47ba80
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest14EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest14EE.crt
new file mode 100644
index 000000000..ff249f051
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest14EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest18EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest18EE.crt
new file mode 100644
index 000000000..b658d671b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest18EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest19EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest19EE.crt
new file mode 100644
index 000000000..f4e2b8448
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest19EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest1EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest1EE.crt
new file mode 100644
index 000000000..4c86f9b77
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest4EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest4EE.crt
new file mode 100644
index 000000000..beb401360
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest5EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest5EE.crt
new file mode 100644
index 000000000..b68b6f7ca
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest6EE.crt b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest6EE.crt
new file mode 100644
index 000000000..9aff6e874
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDNnameConstraintsTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDSAParameterInheritanceTest5EE.crt b/crypto/test/data/PKITS/certs/ValidDSAParameterInheritanceTest5EE.crt
new file mode 100644
index 000000000..8fe2af452
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDSAParameterInheritanceTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidDSASignaturesTest4EE.crt b/crypto/test/data/PKITS/certs/ValidDSASignaturesTest4EE.crt
new file mode 100644
index 000000000..5b1cbc827
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidDSASignaturesTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidGeneralizedTimeCRLnextUpdateTest13EE.crt b/crypto/test/data/PKITS/certs/ValidGeneralizedTimeCRLnextUpdateTest13EE.crt
new file mode 100644
index 000000000..a22f2e6c1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidGeneralizedTimeCRLnextUpdateTest13EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidGeneralizedTimenotAfterDateTest8EE.crt b/crypto/test/data/PKITS/certs/ValidGeneralizedTimenotAfterDateTest8EE.crt
new file mode 100644
index 000000000..15689c18c
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidGeneralizedTimenotAfterDateTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidGeneralizedTimenotBeforeDateTest4EE.crt b/crypto/test/data/PKITS/certs/ValidGeneralizedTimenotBeforeDateTest4EE.crt
new file mode 100644
index 000000000..385bb1eaa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidGeneralizedTimenotBeforeDateTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest22EE.crt b/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest22EE.crt
new file mode 100644
index 000000000..6706cf1c3
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest22EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest24EE.crt b/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest24EE.crt
new file mode 100644
index 000000000..bea72fe2b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest24EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest25EE.crt b/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest25EE.crt
new file mode 100644
index 000000000..994c90ad6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidIDPwithindirectCRLTest25EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidLongSerialNumberTest16EE.crt b/crypto/test/data/PKITS/certs/ValidLongSerialNumberTest16EE.crt
new file mode 100644
index 000000000..11ba787ab
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidLongSerialNumberTest16EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidLongSerialNumberTest17EE.crt b/crypto/test/data/PKITS/certs/ValidLongSerialNumberTest17EE.crt
new file mode 100644
index 000000000..75504db35
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidLongSerialNumberTest17EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidNameChainingCapitalizationTest5EE.crt b/crypto/test/data/PKITS/certs/ValidNameChainingCapitalizationTest5EE.crt
new file mode 100644
index 000000000..5b633871e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidNameChainingCapitalizationTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest3EE.crt b/crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest3EE.crt
new file mode 100644
index 000000000..2aef73cfc
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest4EE.crt b/crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest4EE.crt
new file mode 100644
index 000000000..6890cdd85
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidNameChainingWhitespaceTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidNameUIDsTest6EE.crt b/crypto/test/data/PKITS/certs/ValidNameUIDsTest6EE.crt
new file mode 100644
index 000000000..3cddea4a2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidNameUIDsTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidNegativeSerialNumberTest14EE.crt b/crypto/test/data/PKITS/certs/ValidNegativeSerialNumberTest14EE.crt
new file mode 100644
index 000000000..139a086d8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidNegativeSerialNumberTest14EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidNoissuingDistributionPointTest10EE.crt b/crypto/test/data/PKITS/certs/ValidNoissuingDistributionPointTest10EE.crt
new file mode 100644
index 000000000..bd8ca38b0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidNoissuingDistributionPointTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest11EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest11EE.crt
new file mode 100644
index 000000000..9d19ad192
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest12EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest12EE.crt
new file mode 100644
index 000000000..76b9fe52c
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest12EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest13EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest13EE.crt
new file mode 100644
index 000000000..7db330523
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest13EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest14EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest14EE.crt
new file mode 100644
index 000000000..57bf42655
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest14EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest1EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest1EE.crt
new file mode 100644
index 000000000..436cb9e02
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest3EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest3EE.crt
new file mode 100644
index 000000000..c835b0b24
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest5EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest5EE.crt
new file mode 100644
index 000000000..faaeb9e46
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest6EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest6EE.crt
new file mode 100644
index 000000000..2cd443323
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidPolicyMappingTest9EE.crt b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest9EE.crt
new file mode 100644
index 000000000..4debc2942
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidPolicyMappingTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crt b/crypto/test/data/PKITS/certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crt
new file mode 100644
index 000000000..c3e977666
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidRFC3280MandatoryAttributeTypesTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidRFC3280OptionalAttributeTypesTest8EE.crt b/crypto/test/data/PKITS/certs/ValidRFC3280OptionalAttributeTypesTest8EE.crt
new file mode 100644
index 000000000..f33c9d509
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidRFC3280OptionalAttributeTypesTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest21EE.crt b/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest21EE.crt
new file mode 100644
index 000000000..743e9eb9a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest21EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest23EE.crt b/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest23EE.crt
new file mode 100644
index 000000000..f8703ed8d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest23EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest25EE.crt b/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest25EE.crt
new file mode 100644
index 000000000..e89ae7f80
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidRFC822nameConstraintsTest25EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt b/crypto/test/data/PKITS/certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt
new file mode 100644
index 000000000..924d2f60a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidRolloverfromPrintableStringtoUTF8StringTest10EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest7EE.crt b/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest7EE.crt
new file mode 100644
index 000000000..2e7e99546
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest9EE.crt b/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest9EE.crt
new file mode 100644
index 000000000..764024716
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitAnyPolicyTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitPolicyMappingTest7EE.crt b/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitPolicyMappingTest7EE.crt
new file mode 100644
index 000000000..b4b282d99
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidSelfIssuedinhibitPolicyMappingTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest15EE.crt b/crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest15EE.crt
new file mode 100644
index 000000000..0bad35f76
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest15EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest17EE.crt b/crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest17EE.crt
new file mode 100644
index 000000000..1535ef864
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidSelfIssuedpathLenConstraintTest17EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidSelfIssuedrequireExplicitPolicyTest6EE.crt b/crypto/test/data/PKITS/certs/ValidSelfIssuedrequireExplicitPolicyTest6EE.crt
new file mode 100644
index 000000000..781ce0d38
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidSelfIssuedrequireExplicitPolicyTest6EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidSeparateCertificateandCRLKeysTest19EE.crt b/crypto/test/data/PKITS/certs/ValidSeparateCertificateandCRLKeysTest19EE.crt
new file mode 100644
index 000000000..fda18197b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidSeparateCertificateandCRLKeysTest19EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidTwoCRLsTest7EE.crt b/crypto/test/data/PKITS/certs/ValidTwoCRLsTest7EE.crt
new file mode 100644
index 000000000..e04433ad2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidTwoCRLsTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidURInameConstraintsTest34EE.crt b/crypto/test/data/PKITS/certs/ValidURInameConstraintsTest34EE.crt
new file mode 100644
index 000000000..b554f91e6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidURInameConstraintsTest34EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidURInameConstraintsTest36EE.crt b/crypto/test/data/PKITS/certs/ValidURInameConstraintsTest36EE.crt
new file mode 100644
index 000000000..8b1f00f21
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidURInameConstraintsTest36EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crt b/crypto/test/data/PKITS/certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crt
new file mode 100644
index 000000000..8a9d0ca82
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidUTF8StringCaseInsensitiveMatchTest11EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidUTF8StringEncodedNamesTest9EE.crt b/crypto/test/data/PKITS/certs/ValidUTF8StringEncodedNamesTest9EE.crt
new file mode 100644
index 000000000..c901690b8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidUTF8StringEncodedNamesTest9EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidUnknownNotCriticalCertificateExtensionTest1EE.crt b/crypto/test/data/PKITS/certs/ValidUnknownNotCriticalCertificateExtensionTest1EE.crt
new file mode 100644
index 000000000..6ee8d1e3b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidUnknownNotCriticalCertificateExtensionTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidbasicConstraintsNotCriticalTest4EE.crt b/crypto/test/data/PKITS/certs/ValidbasicConstraintsNotCriticalTest4EE.crt
new file mode 100644
index 000000000..543710fda
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidbasicConstraintsNotCriticalTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidcRLIssuerTest28EE.crt b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest28EE.crt
new file mode 100644
index 000000000..1448aa4a3
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest28EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidcRLIssuerTest29EE.crt b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest29EE.crt
new file mode 100644
index 000000000..ec442e1b1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest29EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidcRLIssuerTest30EE.crt b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest30EE.crt
new file mode 100644
index 000000000..2dc236766
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest30EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidcRLIssuerTest33EE.crt b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest33EE.crt
new file mode 100644
index 000000000..65b28440d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidcRLIssuerTest33EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddeltaCRLTest2EE.crt b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest2EE.crt
new file mode 100644
index 000000000..0d24df052
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddeltaCRLTest5EE.crt b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest5EE.crt
new file mode 100644
index 000000000..2bdaaf21e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddeltaCRLTest7EE.crt b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest7EE.crt
new file mode 100644
index 000000000..3f6792194
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddeltaCRLTest8EE.crt b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest8EE.crt
new file mode 100644
index 000000000..65861281c
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddeltaCRLTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddistributionPointTest1EE.crt b/crypto/test/data/PKITS/certs/ValiddistributionPointTest1EE.crt
new file mode 100644
index 000000000..487cc2f9a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddistributionPointTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddistributionPointTest4EE.crt b/crypto/test/data/PKITS/certs/ValiddistributionPointTest4EE.crt
new file mode 100644
index 000000000..3782e79a8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddistributionPointTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddistributionPointTest5EE.crt b/crypto/test/data/PKITS/certs/ValiddistributionPointTest5EE.crt
new file mode 100644
index 000000000..07a8c494a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddistributionPointTest5EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValiddistributionPointTest7EE.crt b/crypto/test/data/PKITS/certs/ValiddistributionPointTest7EE.crt
new file mode 100644
index 000000000..948f37fb9
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValiddistributionPointTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidinhibitAnyPolicyTest2EE.crt b/crypto/test/data/PKITS/certs/ValidinhibitAnyPolicyTest2EE.crt
new file mode 100644
index 000000000..dc61d5231
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidinhibitAnyPolicyTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest2EE.crt b/crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest2EE.crt
new file mode 100644
index 000000000..fc432a1d4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest4EE.crt b/crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest4EE.crt
new file mode 100644
index 000000000..dce692769
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidinhibitPolicyMappingTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidkeyUsageNotCriticalTest3EE.crt b/crypto/test/data/PKITS/certs/ValidkeyUsageNotCriticalTest3EE.crt
new file mode 100644
index 000000000..bddbb9a26
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidkeyUsageNotCriticalTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidonlyContainsCACertsTest13EE.crt b/crypto/test/data/PKITS/certs/ValidonlyContainsCACertsTest13EE.crt
new file mode 100644
index 000000000..f35f5de2a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidonlyContainsCACertsTest13EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest18EE.crt b/crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest18EE.crt
new file mode 100644
index 000000000..7c0e1dedc
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest18EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest19EE.crt b/crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest19EE.crt
new file mode 100644
index 000000000..f3a811c1b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidonlySomeReasonsTest19EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest13EE.crt b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest13EE.crt
new file mode 100644
index 000000000..dcf88340d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest13EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest14EE.crt b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest14EE.crt
new file mode 100644
index 000000000..66fe25647
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest14EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest7EE.crt b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest7EE.crt
new file mode 100644
index 000000000..5f689eaf7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest7EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest8EE.crt b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest8EE.crt
new file mode 100644
index 000000000..2357bebf1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidpathLenConstraintTest8EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/Validpre2000UTCnotBeforeDateTest3EE.crt b/crypto/test/data/PKITS/certs/Validpre2000UTCnotBeforeDateTest3EE.crt
new file mode 100644
index 000000000..5a6149927
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/Validpre2000UTCnotBeforeDateTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest1EE.crt b/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest1EE.crt
new file mode 100644
index 000000000..10399269e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest1EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest2EE.crt b/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest2EE.crt
new file mode 100644
index 000000000..451c2d81d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest2EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest4EE.crt b/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest4EE.crt
new file mode 100644
index 000000000..a2fa2f12b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/ValidrequireExplicitPolicyTest4EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/WrongCRLCACert.crt b/crypto/test/data/PKITS/certs/WrongCRLCACert.crt
new file mode 100644
index 000000000..4cc51952a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/WrongCRLCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/anyPolicyCACert.crt b/crypto/test/data/PKITS/certs/anyPolicyCACert.crt
new file mode 100644
index 000000000..4d9fb79b2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/anyPolicyCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/basicConstraintsCriticalcAFalseCACert.crt b/crypto/test/data/PKITS/certs/basicConstraintsCriticalcAFalseCACert.crt
new file mode 100644
index 000000000..12a8b5037
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/basicConstraintsCriticalcAFalseCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/basicConstraintsNotCriticalCACert.crt b/crypto/test/data/PKITS/certs/basicConstraintsNotCriticalCACert.crt
new file mode 100644
index 000000000..8f9da1eb1
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/basicConstraintsNotCriticalCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/basicConstraintsNotCriticalcAFalseCACert.crt b/crypto/test/data/PKITS/certs/basicConstraintsNotCriticalcAFalseCACert.crt
new file mode 100644
index 000000000..ca61262ec
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/basicConstraintsNotCriticalcAFalseCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/deltaCRLCA1Cert.crt b/crypto/test/data/PKITS/certs/deltaCRLCA1Cert.crt
new file mode 100644
index 000000000..47f74eb40
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/deltaCRLCA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/deltaCRLCA2Cert.crt b/crypto/test/data/PKITS/certs/deltaCRLCA2Cert.crt
new file mode 100644
index 000000000..a99dd4030
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/deltaCRLCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/deltaCRLCA3Cert.crt b/crypto/test/data/PKITS/certs/deltaCRLCA3Cert.crt
new file mode 100644
index 000000000..eeaaa36e4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/deltaCRLCA3Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/deltaCRLIndicatorNoBaseCACert.crt b/crypto/test/data/PKITS/certs/deltaCRLIndicatorNoBaseCACert.crt
new file mode 100644
index 000000000..5ec06b3d6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/deltaCRLIndicatorNoBaseCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/distributionPoint1CACert.crt b/crypto/test/data/PKITS/certs/distributionPoint1CACert.crt
new file mode 100644
index 000000000..1e74bed04
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/distributionPoint1CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/distributionPoint2CACert.crt b/crypto/test/data/PKITS/certs/distributionPoint2CACert.crt
new file mode 100644
index 000000000..a6d37be90
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/distributionPoint2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA1Cert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA1Cert.crt
new file mode 100644
index 000000000..ef079f653
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA2Cert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA2Cert.crt
new file mode 100644
index 000000000..4bfc0b5ed
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA3Cert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA3Cert.crt
new file mode 100644
index 000000000..f0787f0c5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA3Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA3cRLIssuerCert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA3cRLIssuerCert.crt
new file mode 100644
index 000000000..f8089937b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA3cRLIssuerCert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA4Cert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA4Cert.crt
new file mode 100644
index 000000000..6ebe43ce5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA4Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA4cRLIssuerCert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA4cRLIssuerCert.crt
new file mode 100644
index 000000000..0468b0866
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA4cRLIssuerCert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA5Cert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA5Cert.crt
new file mode 100644
index 000000000..90ba7d7e5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA5Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/indirectCRLCA6Cert.crt b/crypto/test/data/PKITS/certs/indirectCRLCA6Cert.crt
new file mode 100644
index 000000000..3c5781e96
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/indirectCRLCA6Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy0CACert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy0CACert.crt
new file mode 100644
index 000000000..474968979
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy0CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy1CACert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1CACert.crt
new file mode 100644
index 000000000..8d35b0e67
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedCACert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedCACert.crt
new file mode 100644
index 000000000..0362dde87
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedsubCA2Cert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedsubCA2Cert.crt
new file mode 100644
index 000000000..1d24bc194
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1SelfIssuedsubCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA1Cert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA1Cert.crt
new file mode 100644
index 000000000..af02467cd
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA2Cert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA2Cert.crt
new file mode 100644
index 000000000..e8590f72e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCAIAP5Cert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCAIAP5Cert.crt
new file mode 100644
index 000000000..75bc59e4a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subCAIAP5Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subsubCA2Cert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subsubCA2Cert.crt
new file mode 100644
index 000000000..cbf40ff09
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy1subsubCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy5CACert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy5CACert.crt
new file mode 100644
index 000000000..3765f6e38
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy5CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy5subCACert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy5subCACert.crt
new file mode 100644
index 000000000..f75006d1e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy5subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicy5subsubCACert.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicy5subsubCACert.crt
new file mode 100644
index 000000000..f2898ea06
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicy5subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitAnyPolicyTest3EE.crt b/crypto/test/data/PKITS/certs/inhibitAnyPolicyTest3EE.crt
new file mode 100644
index 000000000..850d6499f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitAnyPolicyTest3EE.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping0CACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping0CACert.crt
new file mode 100644
index 000000000..b4934e898
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping0CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping0subCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping0subCACert.crt
new file mode 100644
index 000000000..79f45b82b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping0subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12CACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12CACert.crt
new file mode 100644
index 000000000..57dd683c6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCACert.crt
new file mode 100644
index 000000000..1e6bd7006
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCAIPM5Cert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCAIPM5Cert.crt
new file mode 100644
index 000000000..e68346842
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subCAIPM5Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCACert.crt
new file mode 100644
index 000000000..f73f4d299
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCAIPM5Cert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCAIPM5Cert.crt
new file mode 100644
index 000000000..fe32edafb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P12subsubCAIPM5Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1CACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1CACert.crt
new file mode 100644
index 000000000..b3bff4667
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedCACert.crt
new file mode 100644
index 000000000..399bd824f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedsubCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedsubCACert.crt
new file mode 100644
index 000000000..cd2ce9448
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1SelfIssuedsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subCACert.crt
new file mode 100644
index 000000000..31d9af5dd
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subsubCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subsubCACert.crt
new file mode 100644
index 000000000..13e78f0cc
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping1P1subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping5CACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5CACert.crt
new file mode 100644
index 000000000..86ea42633
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subCACert.crt
new file mode 100644
index 000000000..788622cb9
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubCACert.crt
new file mode 100644
index 000000000..d4a025e32
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubsubCACert.crt b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubsubCACert.crt
new file mode 100644
index 000000000..2c0e6e888
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/inhibitPolicyMapping5subsubsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/keyUsageCriticalcRLSignFalseCACert.crt b/crypto/test/data/PKITS/certs/keyUsageCriticalcRLSignFalseCACert.crt
new file mode 100644
index 000000000..a50545a1e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/keyUsageCriticalcRLSignFalseCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/keyUsageCriticalkeyCertSignFalseCACert.crt b/crypto/test/data/PKITS/certs/keyUsageCriticalkeyCertSignFalseCACert.crt
new file mode 100644
index 000000000..f6824d3a2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/keyUsageCriticalkeyCertSignFalseCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/keyUsageNotCriticalCACert.crt b/crypto/test/data/PKITS/certs/keyUsageNotCriticalCACert.crt
new file mode 100644
index 000000000..344f7d90a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/keyUsageNotCriticalCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/keyUsageNotCriticalcRLSignFalseCACert.crt b/crypto/test/data/PKITS/certs/keyUsageNotCriticalcRLSignFalseCACert.crt
new file mode 100644
index 000000000..c02d6f491
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/keyUsageNotCriticalcRLSignFalseCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/keyUsageNotCriticalkeyCertSignFalseCACert.crt b/crypto/test/data/PKITS/certs/keyUsageNotCriticalkeyCertSignFalseCACert.crt
new file mode 100644
index 000000000..b9c46b5b8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/keyUsageNotCriticalkeyCertSignFalseCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN1CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN1CACert.crt
new file mode 100644
index 000000000..5379f1fbb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN1CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN1SelfIssuedCACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN1SelfIssuedCACert.crt
new file mode 100644
index 000000000..75f1f7e60
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN1SelfIssuedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA1Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA1Cert.crt
new file mode 100644
index 000000000..670291b8e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA2Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA2Cert.crt
new file mode 100644
index 000000000..a010eee16
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA3Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA3Cert.crt
new file mode 100644
index 000000000..b31c28a6f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN1subCA3Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN2CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN2CACert.crt
new file mode 100644
index 000000000..3aab55b46
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN3CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN3CACert.crt
new file mode 100644
index 000000000..f1af18eac
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN3CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN3subCA1Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN3subCA1Cert.crt
new file mode 100644
index 000000000..e40c5f06b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN3subCA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN3subCA2Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN3subCA2Cert.crt
new file mode 100644
index 000000000..94247454d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN3subCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN4CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN4CACert.crt
new file mode 100644
index 000000000..141eb7264
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN4CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDN5CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDN5CACert.crt
new file mode 100644
index 000000000..a0d06284a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDN5CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDNS1CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDNS1CACert.crt
new file mode 100644
index 000000000..10f0b35d2
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDNS1CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsDNS2CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsDNS2CACert.crt
new file mode 100644
index 000000000..83fabc569
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsDNS2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA1Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA1Cert.crt
new file mode 100644
index 000000000..07fcc37a5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA2Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA2Cert.crt
new file mode 100644
index 000000000..2001bfa39
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA3Cert.crt b/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA3Cert.crt
new file mode 100644
index 000000000..e3723693b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsRFC822CA3Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsURI1CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsURI1CACert.crt
new file mode 100644
index 000000000..d0dbca5ee
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsURI1CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/nameConstraintsURI2CACert.crt b/crypto/test/data/PKITS/certs/nameConstraintsURI2CACert.crt
new file mode 100644
index 000000000..bf988e6d6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/nameConstraintsURI2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/onlyContainsAttributeCertsCACert.crt b/crypto/test/data/PKITS/certs/onlyContainsAttributeCertsCACert.crt
new file mode 100644
index 000000000..6855fbe46
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/onlyContainsAttributeCertsCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/onlyContainsCACertsCACert.crt b/crypto/test/data/PKITS/certs/onlyContainsCACertsCACert.crt
new file mode 100644
index 000000000..055d8aace
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/onlyContainsCACertsCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/onlyContainsUserCertsCACert.crt b/crypto/test/data/PKITS/certs/onlyContainsUserCertsCACert.crt
new file mode 100644
index 000000000..f8fc85e7a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/onlyContainsUserCertsCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/onlySomeReasonsCA1Cert.crt b/crypto/test/data/PKITS/certs/onlySomeReasonsCA1Cert.crt
new file mode 100644
index 000000000..26ee389ad
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/onlySomeReasonsCA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/onlySomeReasonsCA2Cert.crt b/crypto/test/data/PKITS/certs/onlySomeReasonsCA2Cert.crt
new file mode 100644
index 000000000..3c444e1e6
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/onlySomeReasonsCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/onlySomeReasonsCA3Cert.crt b/crypto/test/data/PKITS/certs/onlySomeReasonsCA3Cert.crt
new file mode 100644
index 000000000..3b0969977
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/onlySomeReasonsCA3Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/onlySomeReasonsCA4Cert.crt b/crypto/test/data/PKITS/certs/onlySomeReasonsCA4Cert.crt
new file mode 100644
index 000000000..4889d5ce8
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/onlySomeReasonsCA4Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint0CACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint0CACert.crt
new file mode 100644
index 000000000..73c9433c4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint0CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint0SelfIssuedCACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint0SelfIssuedCACert.crt
new file mode 100644
index 000000000..f66228e11
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint0SelfIssuedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint0subCA2Cert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint0subCA2Cert.crt
new file mode 100644
index 000000000..c5cdea3df
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint0subCA2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint0subCACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint0subCACert.crt
new file mode 100644
index 000000000..c51de222e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint0subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint1CACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint1CACert.crt
new file mode 100644
index 000000000..b1da15b82
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint1CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedCACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedCACert.crt
new file mode 100644
index 000000000..02aeffa91
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedsubCACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedsubCACert.crt
new file mode 100644
index 000000000..0a94f5f4f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint1SelfIssuedsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint1subCACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint1subCACert.crt
new file mode 100644
index 000000000..a84fb534a
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint1subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6CACert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6CACert.crt
new file mode 100644
index 000000000..d89052bd9
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subCA0Cert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subCA0Cert.crt
new file mode 100644
index 000000000..4b220169b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subCA0Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subCA1Cert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subCA1Cert.crt
new file mode 100644
index 000000000..b25ba34cb
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subCA1Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subCA4Cert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subCA4Cert.crt
new file mode 100644
index 000000000..ca87ee8bf
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subCA4Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA00Cert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA00Cert.crt
new file mode 100644
index 000000000..2b88eb6d7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA00Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA11Cert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA11Cert.crt
new file mode 100644
index 000000000..de511c4d9
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA11Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA41Cert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA41Cert.crt
new file mode 100644
index 000000000..c6e6096b0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubCA41Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA11XCert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA11XCert.crt
new file mode 100644
index 000000000..9c9dc4e15
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA11XCert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA41XCert.crt b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA41XCert.crt
new file mode 100644
index 000000000..2729261cc
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pathLenConstraint6subsubsubCA41XCert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/pre2000CRLnextUpdateCACert.crt b/crypto/test/data/PKITS/certs/pre2000CRLnextUpdateCACert.crt
new file mode 100644
index 000000000..1a79b8158
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/pre2000CRLnextUpdateCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy0CACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy0CACert.crt
new file mode 100644
index 000000000..0eb93be3f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy0CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy0subCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy0subCACert.crt
new file mode 100644
index 000000000..f96129ec7
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy0subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubCACert.crt
new file mode 100644
index 000000000..c0d9b49c0
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubsubCACert.crt
new file mode 100644
index 000000000..497d53a8b
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy0subsubsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy10CACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy10CACert.crt
new file mode 100644
index 000000000..b3406b122
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy10CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy10subCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy10subCACert.crt
new file mode 100644
index 000000000..1544bbb75
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy10subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubCACert.crt
new file mode 100644
index 000000000..0166d99f3
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubsubCACert.crt
new file mode 100644
index 000000000..8018f6afa
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy10subsubsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy2CACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy2CACert.crt
new file mode 100644
index 000000000..7ec4e4944
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy2CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedCACert.crt
new file mode 100644
index 000000000..285a05c72
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedsubCACert.crt
new file mode 100644
index 000000000..f29b37f27
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy2SelfIssuedsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy2subCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy2subCACert.crt
new file mode 100644
index 000000000..a1f20a3a5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy2subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy4CACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy4CACert.crt
new file mode 100644
index 000000000..c2a9c464f
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy4CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy4subCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy4subCACert.crt
new file mode 100644
index 000000000..9f9ea5bff
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy4subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubCACert.crt
new file mode 100644
index 000000000..3d0f27852
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubsubCACert.crt
new file mode 100644
index 000000000..a14f9d474
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy4subsubsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy5CACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy5CACert.crt
new file mode 100644
index 000000000..ef2010b4d
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy5CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy5subCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy5subCACert.crt
new file mode 100644
index 000000000..99d31d162
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy5subCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubCACert.crt
new file mode 100644
index 000000000..99afa4d14
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubsubCACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubsubCACert.crt
new file mode 100644
index 000000000..9abe48ddd
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy5subsubsubCACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy7CACert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy7CACert.crt
new file mode 100644
index 000000000..cac6bb62e
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy7CACert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy7subCARE2Cert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy7subCARE2Cert.crt
new file mode 100644
index 000000000..d55d884c5
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy7subCARE2Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubCARE2RE4Cert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubCARE2RE4Cert.crt
new file mode 100644
index 000000000..1c9aec850
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubCARE2RE4Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubsubCARE2RE4Cert.crt b/crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubsubCARE2RE4Cert.crt
new file mode 100644
index 000000000..ecd5f45a4
--- /dev/null
+++ b/crypto/test/data/PKITS/certs/requireExplicitPolicy7subsubsubCARE2RE4Cert.crt
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BadCRLIssuerNameCACRL.crl b/crypto/test/data/PKITS/crls/BadCRLIssuerNameCACRL.crl
new file mode 100644
index 000000000..d4871b55f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BadCRLIssuerNameCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BadCRLSignatureCACRL.crl b/crypto/test/data/PKITS/crls/BadCRLSignatureCACRL.crl
new file mode 100644
index 000000000..b1658c34f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BadCRLSignatureCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BadSignedCACRL.crl b/crypto/test/data/PKITS/crls/BadSignedCACRL.crl
new file mode 100644
index 000000000..e0ded9b4c
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BadSignedCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BadnotAfterDateCACRL.crl b/crypto/test/data/PKITS/crls/BadnotAfterDateCACRL.crl
new file mode 100644
index 000000000..1ec2a0e81
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BadnotAfterDateCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BadnotBeforeDateCACRL.crl b/crypto/test/data/PKITS/crls/BadnotBeforeDateCACRL.crl
new file mode 100644
index 000000000..1a96d0f76
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BadnotBeforeDateCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCACRL.crl b/crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCACRL.crl
new file mode 100644
index 000000000..fed48645b
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.crl b/crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.crl
new file mode 100644
index 000000000..053471f83
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BasicSelfIssuedCRLSigningKeyCRLCertCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BasicSelfIssuedNewKeyCACRL.crl b/crypto/test/data/PKITS/crls/BasicSelfIssuedNewKeyCACRL.crl
new file mode 100644
index 000000000..7370ed295
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BasicSelfIssuedNewKeyCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeyCACRL.crl b/crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeyCACRL.crl
new file mode 100644
index 000000000..dee61837e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeyCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.crl b/crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.crl
new file mode 100644
index 000000000..4e7e0145b
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/BasicSelfIssuedOldKeySelfIssuedCertCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/DSACACRL.crl b/crypto/test/data/PKITS/crls/DSACACRL.crl
new file mode 100644
index 000000000..46463c8a2
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/DSACACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/DSAParametersInheritedCACRL.crl b/crypto/test/data/PKITS/crls/DSAParametersInheritedCACRL.crl
new file mode 100644
index 000000000..5bf724527
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/DSAParametersInheritedCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/GeneralizedTimeCRLnextUpdateCACRL.crl b/crypto/test/data/PKITS/crls/GeneralizedTimeCRLnextUpdateCACRL.crl
new file mode 100644
index 000000000..40387d3cf
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/GeneralizedTimeCRLnextUpdateCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/GoodCACRL.crl b/crypto/test/data/PKITS/crls/GoodCACRL.crl
new file mode 100644
index 000000000..2fdc3cc1a
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/GoodCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/GoodsubCACRL.crl b/crypto/test/data/PKITS/crls/GoodsubCACRL.crl
new file mode 100644
index 000000000..963d7033b
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/GoodsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/GoodsubCAPanyPolicyMapping1to2CACRL.crl b/crypto/test/data/PKITS/crls/GoodsubCAPanyPolicyMapping1to2CACRL.crl
new file mode 100644
index 000000000..9c5d1b278
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/GoodsubCAPanyPolicyMapping1to2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/LongSerialNumberCACRL.crl b/crypto/test/data/PKITS/crls/LongSerialNumberCACRL.crl
new file mode 100644
index 000000000..55f39b844
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/LongSerialNumberCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/Mapping1to2CACRL.crl b/crypto/test/data/PKITS/crls/Mapping1to2CACRL.crl
new file mode 100644
index 000000000..36e07e1e3
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/Mapping1to2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/MappingFromanyPolicyCACRL.crl b/crypto/test/data/PKITS/crls/MappingFromanyPolicyCACRL.crl
new file mode 100644
index 000000000..025b6bbba
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/MappingFromanyPolicyCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/MappingToanyPolicyCACRL.crl b/crypto/test/data/PKITS/crls/MappingToanyPolicyCACRL.crl
new file mode 100644
index 000000000..99f12535d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/MappingToanyPolicyCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/MissingbasicConstraintsCACRL.crl b/crypto/test/data/PKITS/crls/MissingbasicConstraintsCACRL.crl
new file mode 100644
index 000000000..f91729cc1
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/MissingbasicConstraintsCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/NameOrderCACRL.crl b/crypto/test/data/PKITS/crls/NameOrderCACRL.crl
new file mode 100644
index 000000000..4cd201583
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/NameOrderCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/NegativeSerialNumberCACRL.crl b/crypto/test/data/PKITS/crls/NegativeSerialNumberCACRL.crl
new file mode 100644
index 000000000..99514d7a4
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/NegativeSerialNumberCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/NoPoliciesCACRL.crl b/crypto/test/data/PKITS/crls/NoPoliciesCACRL.crl
new file mode 100644
index 000000000..b77586bc6
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/NoPoliciesCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/NoissuingDistributionPointCACRL.crl b/crypto/test/data/PKITS/crls/NoissuingDistributionPointCACRL.crl
new file mode 100644
index 000000000..c7d5b1d63
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/NoissuingDistributionPointCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/OldCRLnextUpdateCACRL.crl b/crypto/test/data/PKITS/crls/OldCRLnextUpdateCACRL.crl
new file mode 100644
index 000000000..f121dff3d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/OldCRLnextUpdateCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/P12Mapping1to3CACRL.crl b/crypto/test/data/PKITS/crls/P12Mapping1to3CACRL.crl
new file mode 100644
index 000000000..451d1986e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/P12Mapping1to3CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/P12Mapping1to3subCACRL.crl b/crypto/test/data/PKITS/crls/P12Mapping1to3subCACRL.crl
new file mode 100644
index 000000000..b063e6bce
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/P12Mapping1to3subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/P12Mapping1to3subsubCACRL.crl b/crypto/test/data/PKITS/crls/P12Mapping1to3subsubCACRL.crl
new file mode 100644
index 000000000..6dcdf05d9
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/P12Mapping1to3subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/P1Mapping1to234CACRL.crl b/crypto/test/data/PKITS/crls/P1Mapping1to234CACRL.crl
new file mode 100644
index 000000000..70febec74
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/P1Mapping1to234CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/P1Mapping1to234subCACRL.crl b/crypto/test/data/PKITS/crls/P1Mapping1to234subCACRL.crl
new file mode 100644
index 000000000..8ee779929
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/P1Mapping1to234subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/P1anyPolicyMapping1to2CACRL.crl b/crypto/test/data/PKITS/crls/P1anyPolicyMapping1to2CACRL.crl
new file mode 100644
index 000000000..8cf52dc8f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/P1anyPolicyMapping1to2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PanyPolicyMapping1to2CACRL.crl b/crypto/test/data/PKITS/crls/PanyPolicyMapping1to2CACRL.crl
new file mode 100644
index 000000000..51482debf
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PanyPolicyMapping1to2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP1234CACRL.crl b/crypto/test/data/PKITS/crls/PoliciesP1234CACRL.crl
new file mode 100644
index 000000000..48c6b1a6f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP1234CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP1234subCAP123CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP1234subCAP123CRL.crl
new file mode 100644
index 000000000..aa8426312
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP1234subCAP123CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP1234subsubCAP123P12CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP1234subsubCAP123P12CRL.crl
new file mode 100644
index 000000000..ae1a01941
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP1234subsubCAP123P12CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP123CACRL.crl b/crypto/test/data/PKITS/crls/PoliciesP123CACRL.crl
new file mode 100644
index 000000000..deb37062e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP123CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP123subCAP12CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP123subCAP12CRL.crl
new file mode 100644
index 000000000..ecd65f87b
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP123subCAP12CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP123subsubCAP12P1CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP123subsubCAP12P1CRL.crl
new file mode 100644
index 000000000..51f09f6d7
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP123subsubCAP12P1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP123subsubCAP2P2CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP123subsubCAP2P2CRL.crl
new file mode 100644
index 000000000..5d6fb365d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP123subsubCAP2P2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP123subsubsubCAP12P2P1CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP123subsubsubCAP12P2P1CRL.crl
new file mode 100644
index 000000000..07908f67d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP123subsubsubCAP12P2P1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP12CACRL.crl b/crypto/test/data/PKITS/crls/PoliciesP12CACRL.crl
new file mode 100644
index 000000000..5b090b05b
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP12CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP12subCAP1CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP12subCAP1CRL.crl
new file mode 100644
index 000000000..d2f29b792
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP12subCAP1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP12subsubCAP1P2CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP12subsubCAP1P2CRL.crl
new file mode 100644
index 000000000..bd4cf7576
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP12subsubCAP1P2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP2subCA2CRL.crl b/crypto/test/data/PKITS/crls/PoliciesP2subCA2CRL.crl
new file mode 100644
index 000000000..774bc7325
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP2subCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP2subCACRL.crl b/crypto/test/data/PKITS/crls/PoliciesP2subCACRL.crl
new file mode 100644
index 000000000..7d7ba76b0
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP2subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/PoliciesP3CACRL.crl b/crypto/test/data/PKITS/crls/PoliciesP3CACRL.crl
new file mode 100644
index 000000000..9d81c6da9
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/PoliciesP3CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/RFC3280MandatoryAttributeTypesCACRL.crl b/crypto/test/data/PKITS/crls/RFC3280MandatoryAttributeTypesCACRL.crl
new file mode 100644
index 000000000..63ed6556f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/RFC3280MandatoryAttributeTypesCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/RFC3280OptionalAttributeTypesCACRL.crl b/crypto/test/data/PKITS/crls/RFC3280OptionalAttributeTypesCACRL.crl
new file mode 100644
index 000000000..e088ab148
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/RFC3280OptionalAttributeTypesCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/RevokedsubCACRL.crl b/crypto/test/data/PKITS/crls/RevokedsubCACRL.crl
new file mode 100644
index 000000000..c77ffa358
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/RevokedsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/RolloverfromPrintableStringtoUTF8StringCACRL.crl b/crypto/test/data/PKITS/crls/RolloverfromPrintableStringtoUTF8StringCACRL.crl
new file mode 100644
index 000000000..c7f5c7acd
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/RolloverfromPrintableStringtoUTF8StringCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCA2CRL.crl b/crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCA2CRL.crl
new file mode 100644
index 000000000..a85f99f7c
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCRL.crl b/crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCRL.crl
new file mode 100644
index 000000000..4d159dd45
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/SeparateCertificateandCRLKeysCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/TrustAnchorRootCRL.crl b/crypto/test/data/PKITS/crls/TrustAnchorRootCRL.crl
new file mode 100644
index 000000000..3ba3df615
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/TrustAnchorRootCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/TwoCRLsCABadCRL.crl b/crypto/test/data/PKITS/crls/TwoCRLsCABadCRL.crl
new file mode 100644
index 000000000..fba92fae4
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/TwoCRLsCABadCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/TwoCRLsCAGoodCRL.crl b/crypto/test/data/PKITS/crls/TwoCRLsCAGoodCRL.crl
new file mode 100644
index 000000000..fcb7488a6
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/TwoCRLsCAGoodCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/UIDCACRL.crl b/crypto/test/data/PKITS/crls/UIDCACRL.crl
new file mode 100644
index 000000000..0da091a66
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/UIDCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/UTF8StringCaseInsensitiveMatchCACRL.crl b/crypto/test/data/PKITS/crls/UTF8StringCaseInsensitiveMatchCACRL.crl
new file mode 100644
index 000000000..9ee2a2354
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/UTF8StringCaseInsensitiveMatchCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/UTF8StringEncodedNamesCACRL.crl b/crypto/test/data/PKITS/crls/UTF8StringEncodedNamesCACRL.crl
new file mode 100644
index 000000000..3d7de0022
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/UTF8StringEncodedNamesCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/UnknownCRLEntryExtensionCACRL.crl b/crypto/test/data/PKITS/crls/UnknownCRLEntryExtensionCACRL.crl
new file mode 100644
index 000000000..efbdae412
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/UnknownCRLEntryExtensionCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/UnknownCRLExtensionCACRL.crl b/crypto/test/data/PKITS/crls/UnknownCRLExtensionCACRL.crl
new file mode 100644
index 000000000..de7111393
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/UnknownCRLExtensionCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/WrongCRLCACRL.crl b/crypto/test/data/PKITS/crls/WrongCRLCACRL.crl
new file mode 100644
index 000000000..3ba3df615
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/WrongCRLCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/anyPolicyCACRL.crl b/crypto/test/data/PKITS/crls/anyPolicyCACRL.crl
new file mode 100644
index 000000000..8506ea112
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/anyPolicyCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/basicConstraintsCriticalcAFalseCACRL.crl b/crypto/test/data/PKITS/crls/basicConstraintsCriticalcAFalseCACRL.crl
new file mode 100644
index 000000000..15a7e3d10
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/basicConstraintsCriticalcAFalseCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/basicConstraintsNotCriticalCACRL.crl b/crypto/test/data/PKITS/crls/basicConstraintsNotCriticalCACRL.crl
new file mode 100644
index 000000000..9e5ac6215
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/basicConstraintsNotCriticalCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/basicConstraintsNotCriticalcAFalseCACRL.crl b/crypto/test/data/PKITS/crls/basicConstraintsNotCriticalcAFalseCACRL.crl
new file mode 100644
index 000000000..dfbbec9f8
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/basicConstraintsNotCriticalcAFalseCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/deltaCRLCA1CRL.crl b/crypto/test/data/PKITS/crls/deltaCRLCA1CRL.crl
new file mode 100644
index 000000000..fb562aaa6
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/deltaCRLCA1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/deltaCRLCA1deltaCRL.crl b/crypto/test/data/PKITS/crls/deltaCRLCA1deltaCRL.crl
new file mode 100644
index 000000000..9a76c5cf1
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/deltaCRLCA1deltaCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/deltaCRLCA2CRL.crl b/crypto/test/data/PKITS/crls/deltaCRLCA2CRL.crl
new file mode 100644
index 000000000..36d66fe6d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/deltaCRLCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/deltaCRLCA2deltaCRL.crl b/crypto/test/data/PKITS/crls/deltaCRLCA2deltaCRL.crl
new file mode 100644
index 000000000..713d54a4c
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/deltaCRLCA2deltaCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/deltaCRLCA3CRL.crl b/crypto/test/data/PKITS/crls/deltaCRLCA3CRL.crl
new file mode 100644
index 000000000..4527c9a8f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/deltaCRLCA3CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/deltaCRLCA3deltaCRL.crl b/crypto/test/data/PKITS/crls/deltaCRLCA3deltaCRL.crl
new file mode 100644
index 000000000..bfb3c1d63
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/deltaCRLCA3deltaCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/deltaCRLIndicatorNoBaseCACRL.crl b/crypto/test/data/PKITS/crls/deltaCRLIndicatorNoBaseCACRL.crl
new file mode 100644
index 000000000..b9a591e1a
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/deltaCRLIndicatorNoBaseCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/distributionPoint1CACRL.crl b/crypto/test/data/PKITS/crls/distributionPoint1CACRL.crl
new file mode 100644
index 000000000..1be74de20
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/distributionPoint1CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/distributionPoint2CACRL.crl b/crypto/test/data/PKITS/crls/distributionPoint2CACRL.crl
new file mode 100644
index 000000000..5bdc14914
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/distributionPoint2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/indirectCRLCA1CRL.crl b/crypto/test/data/PKITS/crls/indirectCRLCA1CRL.crl
new file mode 100644
index 000000000..6eed456cb
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/indirectCRLCA1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/indirectCRLCA3CRL.crl b/crypto/test/data/PKITS/crls/indirectCRLCA3CRL.crl
new file mode 100644
index 000000000..02be17931
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/indirectCRLCA3CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/indirectCRLCA3cRLIssuerCRL.crl b/crypto/test/data/PKITS/crls/indirectCRLCA3cRLIssuerCRL.crl
new file mode 100644
index 000000000..166a457ea
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/indirectCRLCA3cRLIssuerCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/indirectCRLCA4cRLIssuerCRL.crl b/crypto/test/data/PKITS/crls/indirectCRLCA4cRLIssuerCRL.crl
new file mode 100644
index 000000000..b870a7fa5
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/indirectCRLCA4cRLIssuerCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/indirectCRLCA5CRL.crl b/crypto/test/data/PKITS/crls/indirectCRLCA5CRL.crl
new file mode 100644
index 000000000..25c2e8145
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/indirectCRLCA5CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy0CACRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy0CACRL.crl
new file mode 100644
index 000000000..301f7456a
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy0CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy1CACRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1CACRL.crl
new file mode 100644
index 000000000..ab1364573
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA1CRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA1CRL.crl
new file mode 100644
index 000000000..46c0e0c00
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA2CRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA2CRL.crl
new file mode 100644
index 000000000..1ee4b77ea
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCAIAP5CRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCAIAP5CRL.crl
new file mode 100644
index 000000000..af4fff09e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subCAIAP5CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subsubCA2CRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subsubCA2CRL.crl
new file mode 100644
index 000000000..3b6b35c33
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy1subsubCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy5CACRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy5CACRL.crl
new file mode 100644
index 000000000..07f5e3de2
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy5CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy5subCACRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy5subCACRL.crl
new file mode 100644
index 000000000..373bdebbe
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy5subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitAnyPolicy5subsubCACRL.crl b/crypto/test/data/PKITS/crls/inhibitAnyPolicy5subsubCACRL.crl
new file mode 100644
index 000000000..e56b61c9a
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitAnyPolicy5subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping0CACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping0CACRL.crl
new file mode 100644
index 000000000..1ebad7097
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping0CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping0subCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping0subCACRL.crl
new file mode 100644
index 000000000..e3f4f9712
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping0subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12CACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12CACRL.crl
new file mode 100644
index 000000000..5291d66d1
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCACRL.crl
new file mode 100644
index 000000000..9c155a976
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCAIPM5CRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCAIPM5CRL.crl
new file mode 100644
index 000000000..dc7fe6836
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subCAIPM5CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCACRL.crl
new file mode 100644
index 000000000..9fcab42c6
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.crl
new file mode 100644
index 000000000..ebcdc5bb7
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P12subsubCAIPM5CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1CACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1CACRL.crl
new file mode 100644
index 000000000..36c2b7918
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subCACRL.crl
new file mode 100644
index 000000000..1fa7ac98f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subsubCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subsubCACRL.crl
new file mode 100644
index 000000000..3b1ac99ff
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping1P1subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping5CACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5CACRL.crl
new file mode 100644
index 000000000..a19deb75f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subCACRL.crl
new file mode 100644
index 000000000..c3ef69116
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubCACRL.crl
new file mode 100644
index 000000000..45df218ac
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubsubCACRL.crl b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubsubCACRL.crl
new file mode 100644
index 000000000..3ca93d4d0
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/inhibitPolicyMapping5subsubsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/keyUsageCriticalcRLSignFalseCACRL.crl b/crypto/test/data/PKITS/crls/keyUsageCriticalcRLSignFalseCACRL.crl
new file mode 100644
index 000000000..6f02f8089
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/keyUsageCriticalcRLSignFalseCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/keyUsageCriticalkeyCertSignFalseCACRL.crl b/crypto/test/data/PKITS/crls/keyUsageCriticalkeyCertSignFalseCACRL.crl
new file mode 100644
index 000000000..4abda7660
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/keyUsageCriticalkeyCertSignFalseCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/keyUsageNotCriticalCACRL.crl b/crypto/test/data/PKITS/crls/keyUsageNotCriticalCACRL.crl
new file mode 100644
index 000000000..358e4e6a0
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/keyUsageNotCriticalCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/keyUsageNotCriticalcRLSignFalseCACRL.crl b/crypto/test/data/PKITS/crls/keyUsageNotCriticalcRLSignFalseCACRL.crl
new file mode 100644
index 000000000..707c73c2c
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/keyUsageNotCriticalcRLSignFalseCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.crl b/crypto/test/data/PKITS/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.crl
new file mode 100644
index 000000000..5e817b640
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/keyUsageNotCriticalkeyCertSignFalseCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN1CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN1CACRL.crl
new file mode 100644
index 000000000..10c7389ed
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN1CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA1CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA1CRL.crl
new file mode 100644
index 000000000..9d33b7c9f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA2CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA2CRL.crl
new file mode 100644
index 000000000..7a3949e5a
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA3CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA3CRL.crl
new file mode 100644
index 000000000..22aa2f9b1
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN1subCA3CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN2CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN2CACRL.crl
new file mode 100644
index 000000000..da6fe6f80
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN3CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN3CACRL.crl
new file mode 100644
index 000000000..83fd3a5e1
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN3CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN3subCA1CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN3subCA1CRL.crl
new file mode 100644
index 000000000..8c6fb506d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN3subCA1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN3subCA2CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN3subCA2CRL.crl
new file mode 100644
index 000000000..1797663c3
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN3subCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN4CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN4CACRL.crl
new file mode 100644
index 000000000..ae9f73a86
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN4CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDN5CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDN5CACRL.crl
new file mode 100644
index 000000000..46dbb8812
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDN5CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDNS1CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDNS1CACRL.crl
new file mode 100644
index 000000000..94fa45e45
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDNS1CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsDNS2CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsDNS2CACRL.crl
new file mode 100644
index 000000000..214093179
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsDNS2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA1CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA1CRL.crl
new file mode 100644
index 000000000..a4b047314
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA2CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA2CRL.crl
new file mode 100644
index 000000000..2042f6fc8
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA3CRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA3CRL.crl
new file mode 100644
index 000000000..8f207e51e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsRFC822CA3CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsURI1CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsURI1CACRL.crl
new file mode 100644
index 000000000..b19c9de77
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsURI1CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/nameConstraintsURI2CACRL.crl b/crypto/test/data/PKITS/crls/nameConstraintsURI2CACRL.crl
new file mode 100644
index 000000000..3dbc011d4
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/nameConstraintsURI2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlyContainsAttributeCertsCACRL.crl b/crypto/test/data/PKITS/crls/onlyContainsAttributeCertsCACRL.crl
new file mode 100644
index 000000000..0993754a2
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlyContainsAttributeCertsCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlyContainsCACertsCACRL.crl b/crypto/test/data/PKITS/crls/onlyContainsCACertsCACRL.crl
new file mode 100644
index 000000000..621dfa9bc
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlyContainsCACertsCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlyContainsUserCertsCACRL.crl b/crypto/test/data/PKITS/crls/onlyContainsUserCertsCACRL.crl
new file mode 100644
index 000000000..1aee7c2ba
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlyContainsUserCertsCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA1compromiseCRL.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA1compromiseCRL.crl
new file mode 100644
index 000000000..3d5ff65da
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA1compromiseCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA1otherreasonsCRL.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA1otherreasonsCRL.crl
new file mode 100644
index 000000000..83cce82f0
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA1otherreasonsCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL1.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL1.crl
new file mode 100644
index 000000000..eb408f271
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL1.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL2.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL2.crl
new file mode 100644
index 000000000..e333d2650
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA2CRL2.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA3compromiseCRL.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA3compromiseCRL.crl
new file mode 100644
index 000000000..6837068b2
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA3compromiseCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA3otherreasonsCRL.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA3otherreasonsCRL.crl
new file mode 100644
index 000000000..ef4ee3e05
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA3otherreasonsCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA4compromiseCRL.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA4compromiseCRL.crl
new file mode 100644
index 000000000..45fcc0bbd
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA4compromiseCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/onlySomeReasonsCA4otherreasonsCRL.crl b/crypto/test/data/PKITS/crls/onlySomeReasonsCA4otherreasonsCRL.crl
new file mode 100644
index 000000000..0fca68195
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/onlySomeReasonsCA4otherreasonsCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint0CACRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint0CACRL.crl
new file mode 100644
index 000000000..1e52e650f
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint0CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint0subCA2CRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint0subCA2CRL.crl
new file mode 100644
index 000000000..69488c7ba
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint0subCA2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint0subCACRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint0subCACRL.crl
new file mode 100644
index 000000000..00295797c
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint0subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint1CACRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint1CACRL.crl
new file mode 100644
index 000000000..9c069801e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint1CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint1subCACRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint1subCACRL.crl
new file mode 100644
index 000000000..61d007640
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint1subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6CACRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6CACRL.crl
new file mode 100644
index 000000000..779c2b785
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subCA0CRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subCA0CRL.crl
new file mode 100644
index 000000000..30fee13e3
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subCA0CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subCA1CRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subCA1CRL.crl
new file mode 100644
index 000000000..71eafbb42
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subCA1CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subCA4CRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subCA4CRL.crl
new file mode 100644
index 000000000..8d14b0c8a
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subCA4CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA00CRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA00CRL.crl
new file mode 100644
index 000000000..24ecdde93
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA00CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA11CRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA11CRL.crl
new file mode 100644
index 000000000..51b4ab70e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA11CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA41CRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA41CRL.crl
new file mode 100644
index 000000000..9e4e18181
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubCA41CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA11XCRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA11XCRL.crl
new file mode 100644
index 000000000..5891e6308
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA11XCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA41XCRL.crl b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA41XCRL.crl
new file mode 100644
index 000000000..217e5e57e
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pathLenConstraint6subsubsubCA41XCRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/pre2000CRLnextUpdateCACRL.crl b/crypto/test/data/PKITS/crls/pre2000CRLnextUpdateCACRL.crl
new file mode 100644
index 000000000..6315186f4
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/pre2000CRLnextUpdateCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy0CACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy0CACRL.crl
new file mode 100644
index 000000000..5ac2d2764
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy0CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy0subCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy0subCACRL.crl
new file mode 100644
index 000000000..569ff3e26
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy0subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubCACRL.crl
new file mode 100644
index 000000000..c614cbb1d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubsubCACRL.crl
new file mode 100644
index 000000000..910c035ff
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy0subsubsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy10CACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy10CACRL.crl
new file mode 100644
index 000000000..7bfbf7634
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy10CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy10subCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy10subCACRL.crl
new file mode 100644
index 000000000..bc4845d41
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy10subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubCACRL.crl
new file mode 100644
index 000000000..802a6520d
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubsubCACRL.crl
new file mode 100644
index 000000000..6f84d3972
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy10subsubsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy2CACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy2CACRL.crl
new file mode 100644
index 000000000..e14cdaa0b
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy2CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy2subCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy2subCACRL.crl
new file mode 100644
index 000000000..883091750
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy2subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy4CACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy4CACRL.crl
new file mode 100644
index 000000000..c6817a34a
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy4CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy4subCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy4subCACRL.crl
new file mode 100644
index 000000000..d1f5ad1e4
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy4subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubCACRL.crl
new file mode 100644
index 000000000..7203b19af
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubsubCACRL.crl
new file mode 100644
index 000000000..467e00472
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy4subsubsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy5CACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy5CACRL.crl
new file mode 100644
index 000000000..96848db79
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy5CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy5subCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy5subCACRL.crl
new file mode 100644
index 000000000..8bb7c1dbb
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy5subCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubCACRL.crl
new file mode 100644
index 000000000..143dab515
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubsubCACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubsubCACRL.crl
new file mode 100644
index 000000000..8a9c8b363
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy5subsubsubCACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy7CACRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy7CACRL.crl
new file mode 100644
index 000000000..43870fb63
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy7CACRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy7subCARE2CRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy7subCARE2CRL.crl
new file mode 100644
index 000000000..48c70c0fa
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy7subCARE2CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubCARE2RE4CRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubCARE2RE4CRL.crl
new file mode 100644
index 000000000..3808af657
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubCARE2RE4CRL.crl
Binary files differdiff --git a/crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.crl b/crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.crl
new file mode 100644
index 000000000..4ed5b0a13
--- /dev/null
+++ b/crypto/test/data/PKITS/crls/requireExplicitPolicy7subsubsubCARE2RE4CRL.crl
Binary files differdiff --git a/crypto/test/data/asn1/masterlist-content.data b/crypto/test/data/asn1/masterlist-content.data
new file mode 100644
index 000000000..d462f0d8d
--- /dev/null
+++ b/crypto/test/data/asn1/masterlist-content.data
Binary files differdiff --git a/crypto/test/data/cms/sigs/PSSSignData.data b/crypto/test/data/cms/sigs/PSSSignData.data
new file mode 100644
index 000000000..ab51e847c
--- /dev/null
+++ b/crypto/test/data/cms/sigs/PSSSignData.data
@@ -0,0 +1 @@
+This is a test message
\ No newline at end of file
diff --git a/crypto/test/data/cms/sigs/PSSSignDataSHA1.sig b/crypto/test/data/cms/sigs/PSSSignDataSHA1.sig
new file mode 100644
index 000000000..1ecfd010c
--- /dev/null
+++ b/crypto/test/data/cms/sigs/PSSSignDataSHA1.sig
Binary files differdiff --git a/crypto/test/data/cms/sigs/PSSSignDataSHA1Enc.sig b/crypto/test/data/cms/sigs/PSSSignDataSHA1Enc.sig
new file mode 100644
index 000000000..2f7e7b677
--- /dev/null
+++ b/crypto/test/data/cms/sigs/PSSSignDataSHA1Enc.sig
Binary files differdiff --git a/crypto/test/data/cms/sigs/PSSSignDataSHA256.sig b/crypto/test/data/cms/sigs/PSSSignDataSHA256.sig
new file mode 100644
index 000000000..114c592d7
--- /dev/null
+++ b/crypto/test/data/cms/sigs/PSSSignDataSHA256.sig
Binary files differdiff --git a/crypto/test/data/cms/sigs/PSSSignDataSHA256Enc.sig b/crypto/test/data/cms/sigs/PSSSignDataSHA256Enc.sig
new file mode 100644
index 000000000..28bb81108
--- /dev/null
+++ b/crypto/test/data/cms/sigs/PSSSignDataSHA256Enc.sig
Binary files differdiff --git a/crypto/test/data/cms/sigs/PSSSignDataSHA512.sig b/crypto/test/data/cms/sigs/PSSSignDataSHA512.sig
new file mode 100644
index 000000000..eb3429ba8
--- /dev/null
+++ b/crypto/test/data/cms/sigs/PSSSignDataSHA512.sig
Binary files differdiff --git a/crypto/test/data/cms/sigs/PSSSignDataSHA512Enc.sig b/crypto/test/data/cms/sigs/PSSSignDataSHA512Enc.sig
new file mode 100644
index 000000000..91556c681
--- /dev/null
+++ b/crypto/test/data/cms/sigs/PSSSignDataSHA512Enc.sig
Binary files differdiff --git a/crypto/test/data/cms/sigs/counterSig.p7m b/crypto/test/data/cms/sigs/counterSig.p7m
new file mode 100644
index 000000000..7d82b99c6
--- /dev/null
+++ b/crypto/test/data/cms/sigs/counterSig.p7m
Binary files differdiff --git a/crypto/test/data/hc256/hc128/ecrypt_HC-128.txt b/crypto/test/data/hc256/hc128/ecrypt_HC-128.txt
new file mode 100644
index 000000000..fbc2fbd38
--- /dev/null
+++ b/crypto/test/data/hc256/hc128/ecrypt_HC-128.txt
@@ -0,0 +1,2337 @@
+********************************************************************************
+*                          ECRYPT Stream Cipher Project                        *
+********************************************************************************
+
+Primitive Name: HC-128
+======================
+Profile: S3___
+Key size: 128 bits
+IV size: 128 bits
+
+Test vectors -- set 1
+=====================
+
+(stream is generated by encrypting 512 zero bytes)
+
+Set 1, vector#  0:
+                         key = 80000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 378602B98F32A74847515654AE0DE7ED
+                               8F72BC34776A065103E51595521FFE47
+                               F9AF0A4CB47999CFA26D33BF80954598
+                               9D53DEBFE7A9EFD8B9109CA6EFADDF83
+            stream[192..255] = E7F8DCC6A1D42ECF6A49651F7C610657
+                               B1DF6E58FBEF6A246D6D4CAA83858839
+                               86325BE2B4185B4D63D4BF766C5F4B73
+                               0B89C3CD66018155DFE9D37B6F5C1251
+            stream[256..319] = 6D21763B2FEBADB212AC71388FF93586
+                               48AA1A0E874D3B6932D7F80A5657F88D
+                               A44BDC16AA21E531E3E473CFE6FCA9EE
+                               20739339CE4F2DAC793210C8CC20897F
+            stream[448..511] = 5BB39DF39C64BFA13F2AAE924D3DF4FA
+                               22899838ADB609806C022C36180A3E46
+                               A547CFF7F4DE1151A81AED3646B2D86E
+                               1F0F3C22C92D3459593ED599D1A535DF
+                  xor-digest = 1EFC3423B31F67D397923613A1169F54
+                               A35193C9A31484D48204A8380D19984A
+                               AB3C53E44D0511C1CA13A3823A0B2C24
+                               7602797C533F0D5251CD5FF60D4A4F5E
+
+Set 1, vector#  9:
+                         key = 00400000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 80978AC0647C7C5E3716B3B3DD9A3FD6
+                               EE0EC133F29A0F2F92E3F7AEFFE8CAD2
+                               789DB433255F7A9F2A9D0873B8932032
+                               A7FD7EE6D07C903738B78E88DC173674
+            stream[192..255] = E314E449A75D8CD4FB0BF8BB133915EF
+                               0471D3824CCB9CF828F2086EED1E09EF
+                               78E510E0D7362275CFECE3F2D79F5B37
+                               8C8F21D3817083098E1D3918DC49EB13
+            stream[256..319] = BD9BD906D4AC9B0A0A68C1371DDD0BAB
+                               7D36784577856634034D9A7BAF3A8B06
+                               1C29904A896A82526CCAED7899FCBCE2
+                               619E6AEDA6D79B55C6EE7C97353486F0
+            stream[448..511] = 163E7EDB8F4A866A0E1C991883B2A966
+                               0DF6C547BA4C3E2D59AC014170872C73
+                               220303B5AB4D7321CA0C25DF3E18D5D9
+                               1D6B52A5C2369F4F764B7E4649674F89
+                  xor-digest = 2F1B2356F1149C6EE7694E217332E4CA
+                               33E47D0DB237E71D542A4BFDE033137D
+                               C8085B39215AF06840E542E501FC0584
+                               257B7F6DCD6297CABF03026A95A6E27D
+
+Set 1, vector# 18:
+                         key = 00002000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 94DAB13AE0D2F9A65283C6AE98733110
+                               1C4EE45EC812AD67DDF3D1F026B51B17
+                               2D366C7E3B2D55E5AE7010A279D35B03
+                               83B77E96C6B2434C3E6DDC2401D64AEC
+            stream[192..255] = 8199B6243A278FA6C07B430B6FFAAD83
+                               C2A40A1115DEB693B446504AD35615CD
+                               C4881D06F2EC1EC5C189BC37C0F6AABC
+                               C349FD461023A1B840C40B7E96A481E4
+            stream[256..319] = A2FF8C499364E1E900EAE72A98399585
+                               6C609132B14C83B191D49BF251E73EE2
+                               0FC48469A1E72416F803CCB7C933A880
+                               F8343A8DE2AB9492190E86194680B21C
+            stream[448..511] = C442F7A0791CCC0F7E8D4CC454829E6C
+                               26811BE74AF8BC70276C4901277753CF
+                               E44FACC0ECB82E9E5803CD08A316D9EE
+                               5B0A016185BEEF9FE94A3E64C8BCB161
+                  xor-digest = 53170F85C0661EBB8E0C595C6405CE21
+                               B9F19433C791DB8A71883E4E6BA31656
+                               2268C2110CCF228AF6634A80599B6A0E
+                               24106DBA30C3098EE57A10B1604511E7
+
+Set 1, vector# 27:
+                         key = 00000010000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0D3549E38106BC69495957DE0722C36F
+                               B3362CB8BB2ECAAB49C99AA5455C4DC7
+                               363E990AE7FCAB1F4648413DDC698D79
+                               294F3FF36FD83C299AEE2772D34D057F
+            stream[192..255] = 3239C047E0DA62024EC64B1D8E8A5E0F
+                               6E89062774AB24D2B69A17FC7F4C6EA8
+                               85F71AEEF1B7A36A559EEE29D422CD4E
+                               98733C99CF47472F1E4A406EC58A80EA
+            stream[256..319] = 1B1F13FBB383683E26371ECB23F49D0D
+                               E3B0A224D96A1A87D63A6737614F0415
+                               DBAA27AE8107DA06E5BB62D96FE4502D
+                               7B92EB6B5AF180CE8C2373920C77292B
+            stream[448..511] = CDA9A705E95B0656600EE8CC654127ED
+                               0A8E362FACAC68B18C0C25CA57929F2B
+                               1761F0706FCB0E066338507BD04C7F62
+                               0FC91BB6AD77D569E30547959578216A
+                  xor-digest = 6D339778DCB212787325D09BA20110C9
+                               A9CAE09E5915DFB1F74BA59E9C610FEC
+                               7989F18AF4CE86AC3D135659F46DB2D3
+                               59C08FC80B14E10AEC6B6701F661E86B
+
+Set 1, vector# 36:
+                         key = 00000000080000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A4E7B46F89DD8205C71F6453B1ED3924
+                               5D7FBB100E7EBE4D1D27E69047AF47DB
+                               3575B3A580FB9591A5F794306CDFA3E1
+                               A0A61905827D5ED980F49932A5ABA561
+            stream[192..255] = 364556E21E20C5816ED375B9C12C0603
+                               B680F2A4972EDA77AF198A2F015ECEA4
+                               7171028016B99EEABE1DAA2131711466
+                               6D3C1558218D95A8068E1780BF738C2D
+            stream[256..319] = 84F5E62E1E8D4AD21DFE9B3537172D6E
+                               3F4539DD15B5A55B38373E9787F0A4DE
+                               5F4D90B0D56C0E1F8A5F9C282A1F5567
+                               342BF864960F27E5311A4FBE3B85CDF8
+            stream[448..511] = FB062A1FD5E64D97489F24A4F12193CA
+                               9C6F4711C993C13742EEF14D88009DCD
+                               FA40D295DB8959D1562DE734ED1AEF4C
+                               90D136852F37A4115757F21F40977025
+                  xor-digest = FB8B62297F1B5E510091057F075AD348
+                               54FD949E9E35712E2F455D25AA7EC559
+                               D55FFCC3D6832865EBDA17EEF34A2CCE
+                               C6758E6449BDE9D70B5071B2A1D5094D
+
+Set 1, vector# 45:
+                         key = 00000000000400000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DFAB6AB2296BDEB8D8B3F6A790F3885F
+                               093BAD3BE4E0BD63E43F69535F5E77CA
+                               DBA06B447471B03D6A47D6BCB5AE4D40
+                               03B8AF7738AB8EB4D5B9C6040A434A71
+            stream[192..255] = 9313979FA86022D65C61D902DC0D4F9F
+                               98C1D026B710B03123812FEABEE5C0ED
+                               8973F8B97CF7E281EEE0A5135A01F0B1
+                               4C6DC27B352CB349273EE5E34541C518
+            stream[256..319] = B53E875AA400CB453C7DBF5CEEEE4D69
+                               31763C844FEDD960E5410FC3A5E51B19
+                               7D252502EDBE71D457461A9D0033E26E
+                               C7F78BD9C39580695914941737645754
+            stream[448..511] = DED32F71701CB0AB10C3062F1A15571A
+                               E70F2E3AC7A533CF7C962B2F4C256A9E
+                               12EA7D7F7DEA955DE6C7CA512A7EB4B1
+                               80CE31FDD1F38BD486EF438D52B791A8
+                  xor-digest = B0EBC9D8BCC2DC7E20BBB7063FA84B6C
+                               109A619BE7EC9DF5C9C6182AD692DED1
+                               0F24329DA2E5C346A659F2DF60BA0F2F
+                               E0169D173C4C75D26363A0D7DB40A195
+
+Set 1, vector# 54:
+                         key = 00000000000002000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 9D5E9AA4795B8B5E97E415BD1F14E697
+                               3D5E1D148EC12743699A48DADD6EF61A
+                               4643E9A7C2D2F88D50A8B9A63E003367
+                               ADDD8DCC464EB1C0FA6C23D244E725C9
+            stream[192..255] = 8DC91C4A6B3E6B88EB7EE1E0F7345718
+                               6C80BCCEED7197FC98CB118EE13D9AE5
+                               3EC8C6917F38FEE09C5C6F08E475E058
+                               51D1E7D4EF0B24AB263F0AB5656E3E82
+            stream[256..319] = BC2875569BEA6623C7E16A6A87C972C1
+                               1EE3782148A48D51F6D9E32CFB42812A
+                               2D20A318F0D699C9E760159F591EB9DC
+                               9EF3429A2613FD30EF2C839FFFAC5D0C
+            stream[448..511] = 6733FAE7B9AE358748DCD6937D494F21
+                               46315B363CC50E362C5F585FD350C462
+                               BD99DD69F2644043100A9E690302CF26
+                               4436B96CC818B659555DE0ABCBCB911F
+                  xor-digest = ECCE54CD5721D18E47CAE60E30741660
+                               1F03D46F90A1110614728849445E66B9
+                               ADA53954F9E8DCB746CC4BCD4D82EA34
+                               30767E2CF9BE6BF81E19382DB5A7677E
+
+Set 1, vector# 63:
+                         key = 00000000000000010000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A88EADE3DE0EB0BA73CE09E995540BF3
+                               B8DF7485F028B1C3C15D1F813E2C5413
+                               5B004E1804EB6FD248505C998B5F2CCD
+                               B3EC043B40FE7A532981F932D107776F
+            stream[192..255] = D81CAE569DEC3E6D22C83F043B64FC88
+                               0B04116A646BBADC38B28848D17028D3
+                               11535C1AE172CD85A9B2D3ED4D728FCD
+                               0A5289DA14D823578E5B8984AEE42671
+            stream[256..319] = 18FF81D6F5D7678998B48A51CF0D024F
+                               5872A5C1084E20182A8C255938339D34
+                               6798356AD957663C089939F896330C12
+                               747C08E2BF752B4103661B98229FB5CF
+            stream[448..511] = 9B797430B254C3F4DDB6AA211254ED75
+                               13A7403B62D5D1E2452E43DBCC7B50C8
+                               266F82A5155D405A5B7E15E921AD8154
+                               362799FFE25F1E7ADE3434B0862E9D10
+                  xor-digest = 983E10E11689266E4569A99855A4F642
+                               9094FAEBEBCD68434BD771C8528FDC62
+                               D357A379A0D6D78B9543E9A4CCAA42CD
+                               DC719C3C880A358B409477D670F55EBF
+
+Set 1, vector# 72:
+                         key = 00000000000000000080000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 7ECBBF2FD6D7E521A15DD022D0988F7E
+                               319AC64A9ED55C72E2817AD91F778221
+                               98A55A9E9BFC9D01C0BF8BCD9828001A
+                               18AED8C48E3F6633FA541B74A1799C62
+            stream[192..255] = 1BC71E27C8EAF24C12E78A4F9FC8E000
+                               625AE2FA2AB74483C8EE3ABB69C77B13
+                               7DF6C9213A1EA8D6557F0C1688154B87
+                               BE22F1B87AEE346AF7AFDE02C4C2C776
+            stream[256..319] = D2AF220214395745FA09AF2FBBCDB112
+                               0A588713476B29479F48B92F278BF39B
+                               3048630F0EC091D1188E7CEFD4C6F8D2
+                               709187581999E5DEE22745D21C03BCA3
+            stream[448..511] = 995534950559F7F3D01A718891ABC639
+                               3D64688DE7FDA76C1DCF2B81F6934EE9
+                               4BE1DE90F720E073DB9E54DC101BF513
+                               5ED06CA4684A73A506553CB8713E4FEC
+                  xor-digest = 2E87F43F3622E1A512D0E540939727EA
+                               A035F7D7C136FFD565BF639C00165F7B
+                               6C33B969DDD106EC9D4CFAB1FA0D5618
+                               FD17C64CC68E94DAF7DB9791B7DE16A9
+
+Set 1, vector# 81:
+                         key = 00000000000000000000400000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 2AAC5C088CC1EC5D579779B7EEEB7F9D
+                               AEC2DF6224B8E39F9E74511E4E8CAD0E
+                               59E0BEFCFCFA73DA661B53350A470887
+                               11B1ADC5304481515256C94204EAD340
+            stream[192..255] = AA9240B5E98DD28D7CC6FDF07C61E536
+                               069C5D4B818A96DFF41939A57DF9FE45
+                               32F384A624B236064C1AFF1A37C8CE01
+                               23B87B7903EBB91D6D83C69C684090B5
+            stream[256..319] = FD816941100F6CCA2EFF27C275753702
+                               8B371BB985E878229621CA3D0B4E6BF9
+                               1F74BAF0C05F661C93B819092CF475E0
+                               C61EE25FC5FF6CC9BE274834E718EDC1
+            stream[448..511] = 0A2B3B21DE9AE621B9DA45091AA26213
+                               EE2E560D32FA4CB8ADC6DD1AF7EA11DE
+                               B4905EAC39580A5A89A68F85BED6CFFE
+                               820A79E20265488FBC9E266ADA0C4CFA
+                  xor-digest = 60ABAD1341AA90112B53568014827D64
+                               A4A39E7CCCD78943018C685D0CC4DEB7
+                               EE7A203B7C88ED8996EA7B2EEBBECC7D
+                               86E53A4B5E0646BA59CA88144B032C9F
+
+Set 1, vector# 90:
+                         key = 00000000000000000000002000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CB3DF6C584DC8826BAD57EC5B98D644D
+                               AFE6C749F0463744EE1CB03EC81DDEC4
+                               4B4948C634552BF4760A0976C67BB2D4
+                               C53F7A7805FDCC68C3ADB7ADBDF9B509
+            stream[192..255] = 0ABC3A02DEDCEE79E8C26D3667B085C5
+                               30FD86A2CAB845CCD323075D7D6FD7A7
+                               05E7532A5F630BDC205B1DE61DC29243
+                               A2DDC2750F9AF32EF0CD794EC074AA83
+            stream[256..319] = FC4AD0FCAB98C2F3379E3A3D1B35DEE3
+                               93B60A327A41BD5147DD17F315DBB5F6
+                               625D67ACCF9A460C2CFDAD84403D4163
+                               EFF59D1356C144E6237A09044BCFF8CB
+            stream[448..511] = EFDAD499C277519887424DBEFAD5DB2C
+                               97C97CE5E512871B5CA81D9408F59B39
+                               9E23B24AA57DC934C2F539CBCC6A9EE9
+                               750B3A5D08ACEAFDED87C325D01CE866
+                  xor-digest = 7D8E173BD06363238A383D72422F5FAB
+                               941BA41199C462C2110E29E62350C9AD
+                               15780C3BC2B9092641A4702B9A696430
+                               E38F7D0F6FFD1AE59B82787A3A69CA0E
+
+Set 1, vector# 99:
+                         key = 00000000000000000000000010000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = EBF5E178FA8E2E45F53B73AB15C2D54F
+                               A48DEAC9529BDA434E857A809CC7C0F9
+                               D8F372BAE323FBF79874EC53EAD3928E
+                               DB203A64C601A99BEE4C07473DDD3B23
+            stream[192..255] = D461188EA8C5F22E8649B6FA7B68274C
+                               D97EF513C81DA77CBAC826D9D20D9968
+                               716FBDA415BBF064DBFCB7D5AE12F72D
+                               4DD1FC3670A553EE6F23CFDA400F6D9A
+            stream[256..319] = 031589CA9A8B0C09BD0CB167D3D49C2F
+                               873AA718E0C9B3A3A515A9D196C5382F
+                               BB6CA5E3190FC20084F5A4D22DD92095
+                               8E3A1883E30F7BFB55B40747B495FD49
+            stream[448..511] = CF106A7EB0FD339B8EB67F09E2A27AFE
+                               A4117C472AA64CF1A41850062266B48F
+                               92CB46600E87E811121959B19999BFE9
+                               1C68A664A4C28ACC8AE5E6EA477D0A2F
+                  xor-digest = 2480D3C1DCD26EE2B05D964B3CD526C8
+                               4E39E6FF48EC793FB82F4AF928073D1D
+                               80887F9AED832951D4AB2FDB518B548F
+                               EB5A42FE6454C19FCC101019B598A808
+
+Set 1, vector#108:
+                         key = 00000000000000000000000000080000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 2EABC4033A51B3901B6340BE32F808EE
+                               A319582F21A7CF6633570E82AC879B60
+                               3E438847D9E3719EAB71F8E3247FEFA5
+                               C07B2282AA2FA80CEFFA8E076304FEBA
+            stream[192..255] = F178E16CCB405A8025FA50215B109BFC
+                               9CE3A655DAD91BCC64D89BE115D4BC84
+                               261DC0E440DAF6028D3AFEA13C9D53B1
+                               C38E2AA48153CCF3DD9791563E45A98C
+            stream[256..319] = 284E211A092241828DB7204310536167
+                               653D66987537E004201DFF6290CD8C37
+                               84AA31D76477908455CD4E1C51F907AC
+                               69893D7FD3D626989526F4E6891E82A0
+            stream[448..511] = 043F1740552381D9A01C882DD0D542B4
+                               8EE86ECF6B5D2A23B8EAECCA55224664
+                               5702B29F7CAB606417CDCCAFD9B63ACB
+                               CEC56E95C945B72DC457103B2C378A28
+                  xor-digest = 1A56CC2BC61F1A802CDF26A84BD37A9C
+                               86F903637E5A1BB21B5829994628B000
+                               2A356A4D150DC529907786BAABD0C733
+                               4500BE0DDC9D487EC6356B2ACD65946E
+
+Set 1, vector#117:
+                         key = 00000000000000000000000000000400
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = BA81D9884075FC9E2F9938392EB10354
+                               1AD1D4A599A6DAC3E33EEC59235C3559
+                               4448E3DAB3B5A5F56DAF7B86B63EF376
+                               3728193CCE74807DC7E26087D87BF7D8
+            stream[192..255] = 1F91ECF0B6E889D6FD6FA97510D2EE3F
+                               91552978AC896D69B10A923F6F5CCA67
+                               8320765AA5CDD2ABB4A5FB3CAF86C76E
+                               12280CABB4E74C8543C9D5B1D9B8268C
+            stream[256..319] = 31BF924BBD38F9FE050E17E50EB66C45
+                               081DC5CF49F0F02610828A91F31D0B29
+                               AAB0D6123D69347ADA5CFB37C8AE5E70
+                               38453B5194EA285F798179A875F75E70
+            stream[448..511] = 78F5C37A21EEBAB00F7A80656D72AE39
+                               5566B8114BA6EC8BCFE8C46D0CEB4C6A
+                               BDE4E4F0F131BAC671F8186821CA01E8
+                               69FAB184E938B93B56D1AA3C1D68D3AB
+                  xor-digest = EFA43D76919EF92EED6AA30B4FD2E37D
+                               461D4377618426C2912493665FBB004E
+                               0C92A654CB660FB709681F460DD61825
+                               C7A7089737F5F5DA10023049A0595DBE
+
+Set 1, vector#126:
+                         key = 00000000000000000000000000000002
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 23C1F447C5496B37512923D74B61CF71
+                               015A25988370C0F4E0E48194E4C3B72D
+                               0C9519F6A88D8AE9DD319A3C9160A6B5
+                               51FFBAF27D374B3E6F624344D06BD06B
+            stream[192..255] = 019E730A2D0DD92CB417B1FCF42D2352
+                               058F3B059E1FA4C489909E0B9B90944D
+                               9816E45E992893244CDEB5EA6AF79703
+                               F70CEC7C3E770D2A8310127B3EEA9026
+            stream[256..319] = 3BA682C375554002E718ECEAE6768648
+                               2442D9643AEB6E4D518A5146263B6BEC
+                               0577A4A0CCD7995F10B7F1312926C613
+                               B4BCFA28D37B85C7FE6CC64A26DBCD47
+            stream[448..511] = 41D18A4275E2E4DBACDD91D3F79A186F
+                               6B2F48BBB64D47186C32910E86914BB8
+                               74688AEE59998D8CF7635DDED58EA9E5
+                               C51DF64956C951C1F9123DC1C97A4027
+                  xor-digest = E7A40A98E52ACDD2CAD780E71312F128
+                               8A73CDDD2CABD28EB767A045871861B7
+                               680C64DE4986F508E8CAA04B49630B3B
+                               DF931CAF478B2C3470E483F3D2EA71A8
+
+Test vectors -- set 2
+=====================
+
+Set 2, vector#  0:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 82001573A003FD3B7FD72FFB0EAF63AA
+                               C62F12DEB629DCA72785A66268EC758B
+                               1EDB36900560898178E0AD009ABF1F49
+                               1330DC1C246E3D6CB264F6900271D59C
+            stream[192..255] = 76F5E28163A6F72F4AB72FCD90C69EED
+                               EF6D5C73539F14E7CA0BF6A9F229F12D
+                               1492EFCFDAD11EE26DE44F0E843178D2
+                               C989D4F21FE9B53C03C12874E83A7026
+            stream[256..319] = 3CDC1D88EDA836767090FB77DAE5ECC0
+                               0F5BF5CA8879733FAC19E8DE5C725636
+                               7E39E8C9C4EFCDD75DFA9660BBBEB584
+                               B5593DFF4566EAC37E857D9B9E21FF06
+            stream[448..511] = 713B389BD7E1651A450C051B77F83A96
+                               DA277A370FCEBC4303A18AB1C5FF5342
+                               B319F0593A67F2BE6DE7D256CEC89F65
+                               61FF60B8AB8621B6720206975269023F
+                  xor-digest = 4943A339E572249ED48A06F45BD60AC5
+                               26F1ED970617DC9DB29EFE99ACEC6C7B
+                               82C8F548503C3DC16E79C4D7D7B7C6C6
+                               08CE84DC170A72286CEA1148D180A7BD
+
+Set 2, vector#  9:
+                         key = 09090909090909090909090909090909
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 4C76978E4BC79261F8608B3E5327AEB4
+                               4F2F0305D5F6B6326E0127F00C50DEDB
+                               85F5915ED2D70C9BECA2866AEBE6D154
+                               A4CCD80AC88588CAF24FC805974C96A7
+            stream[192..255] = 5875CA142FA9AC13170031C71A3619EA
+                               ECC3D6E0692AC276E2CA29864643D364
+                               56DFA39E1782D487F49402AE32CB739F
+                               AE267CFC438495B292D21E6B4A21774B
+            stream[256..319] = 8CEB212AE637E8DE29AD64E7D0719338
+                               F41AFEB1F1022F30BE485B348722B7F5
+                               A57DE6F253C6B0828C6FB1EF6C59EEC5
+                               FAC3D7FCBAB8C6BDAE2310CE77ECA503
+            stream[448..511] = 4810F2AEA6804ED4820E5B9E7ADD1F44
+                               37EF320686F108947B42991ACC7C4887
+                               635E57E9AA90EF29F831D7959936DD95
+                               0F466666BB84280764F5557582FAC149
+                  xor-digest = 7EA2FDE204E339B9C85051F22A46587B
+                               3619F4F9AE11426F5470D9EAA1629476
+                               FF156BF2727CB6306E62BABB4A68E9AF
+                               610D50C8034C5D4E23BCAC487F3DCA03
+
+Set 2, vector# 18:
+                         key = 12121212121212121212121212121212
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 38F35C0172088DC537AE80089719655F
+                               E8671884235DB1F6477D776B8DD158A6
+                               F6914C168E9EDF0B1020C63EA1851D2E
+                               FE1A343C98ED4B4B23E52451B9BDC3D6
+            stream[192..255] = E88226EA0CA8B620A68402F83A1475C2
+                               54C875FD5D27C935130FDE6DCE3EA050
+                               4F121A7EBF6B572D6EB41240A65CD001
+                               5007AFF6C2A8827CC0841A6170C08467
+            stream[256..319] = 0ECB78E446AB9C763315031C95E570B5
+                               5A5D89BA13A228B80D86797BE378D766
+                               59B47D48AF0FDB4C3D439311963B0A0E
+                               1311E6FA792B089EE4797D9AD023FF5A
+            stream[448..511] = 44C71180BEDC7E3CD29F80B9922C1733
+                               5D815207E848FD528572CF61612A42E0
+                               AD4AEC01D042461A8C30ED194940F82F
+                               A442DFD9061C03A1B72592894A0C73BA
+                  xor-digest = 127E8501304A0632B8FA27A23BB97321
+                               BCD67F699D39A35A4324D5E8AD368E0D
+                               CF134D13FBBADE2FA930AFCA7D15FEC0
+                               B2682F0B09AAB3373069F6DAB9EA112C
+
+Set 2, vector# 27:
+                         key = 1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B90DA1C325244BDA08C319AA6B4ED7E8
+                               3DEF56BF03ADFB2A46E9041F4498BE2C
+                               4B9F76E7AF98697B2835F2F4D4585320
+                               36844D8FA3F34121D9BF624556A52BCB
+            stream[192..255] = ED912457955FE3EDB032F4E7C452A13D
+                               52361DAA3154A756B1C00B0079DBF782
+                               AD089F2C090691BF7B66695538402EFF
+                               893D27969913F25177C01F4CA2FF5195
+            stream[256..319] = 0127342854571D0640F2C283104FD6E4
+                               4FF9B9198492414C1803E36F01A2E79E
+                               3EF76F350542EFEA11419692B6A708F2
+                               0A6D938306E9212B8F047207E7C5782D
+            stream[448..511] = B297A467A6D2770B2609C7DC1EA505F8
+                               3A36223731550282001144B4DF3363BD
+                               49802CCDF59D22FC7C2CB7913B4FEFB9
+                               49128A2BED699B55D24E5B26C52BE674
+                  xor-digest = 711ED121D562F49A3D3F66FE95540DC1
+                               A58F5703108A7C484A53EDC9FA7455D0
+                               D356D9EA792AC30009754E94CF63493A
+                               8AA3BEADC0E7D671DAC10390C841F9EE
+
+Set 2, vector# 36:
+                         key = 24242424242424242424242424242424
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 38D294B5B1ED0A38C5430A355A5A5949
+                               0137741305AD7EB6159A1B97A956648F
+                               B27C16F507D5D5FF8E2B779BFF22CFD8
+                               DB4C7CF7FA78CBB20445D2F94518174E
+            stream[192..255] = FE70A06921BC304689079DDFB4CD4BBE
+                               FC64B0C8E014A65F6D84A804E8F8F1A1
+                               371D470977F033ADCA960346B189E848
+                               C899CD90446D5074C3C1EE48DD40F0C9
+            stream[256..319] = C9B90ED55AD83A8DE0547000ABD0A633
+                               653ED5D3B62EB16D2C3E176952786205
+                               AA702C32FC37DCDB714D8BB81E488438
+                               43B805F2FF5ECE2E6C0A4A4BA5746561
+            stream[448..511] = 396490C2E87DDA2FC2F9FD4D2E468A91
+                               A826ED3FB2AEE07DAB6E33EBB5D657B3
+                               2488B38BEE6E316DEA6439979112CC62
+                               0989E9907AD83A9479DF253A75FC6683
+                  xor-digest = 5478F54C1B95FFD16C6C873F900181F4
+                               EE33E5CB58CD28259E19645FF36B4419
+                               FF92A289E9C355E769D0CF6F004BB256
+                               E5134627E4E99459CA3916BC1216312E
+
+Set 2, vector# 45:
+                         key = 2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0188DFBDAB2AA5D4996601E8CBC5AEE1
+                               5254491641DCF5DEB7414FC751D52E56
+                               C253A98157200CE0C142C355AB961015
+                               04991380F77C287212145552C000CFA2
+            stream[192..255] = 6957E2069E8F1042C6A46AC8ECAD2439
+                               0DB5739043E911FB9BBE4A7071A88B14
+                               2867E45971D7C19BAAC4333BC176230A
+                               A67A081EA89728380B00F5173E866B89
+            stream[256..319] = B47E8222962EDF8B3CF7E4DF469C81F0
+                               40431EE27D2CCC1C5D2B048C6E986681
+                               9656F8E23714A227341795A9B881A776
+                               9434923C01D25B4B2D60D0EA89580F82
+            stream[448..511] = 89E48ABDB1A7F5BF17EC7304A951B1E5
+                               D152EA7EE181DD9866ABD782C7FCF238
+                               66871D0B1EA30527CC178D0FBB0E6D8A
+                               C5CDAFB27F01B7B6AA68413B3E7DCA6D
+                  xor-digest = DFB99C93E6B26D2F079414A370EFCA10
+                               5468E93AB8983DE0AAA1AEE3F8FCD068
+                               3C20753931A9B13F48F10C9F71F99638
+                               1AACA39469AD3EC6BC8B2ACB1DB9ECC9
+
+Set 2, vector# 54:
+                         key = 36363636363636363636363636363636
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 6EC768666ADE02892FF522A9422F5B3D
+                               D802727755D64C602C5BE156DCCC690D
+                               D0237CF95B191BD29BEE5E030E1EB4B2
+                               CA981BED69F2F4FEBA39C9658450D21A
+            stream[192..255] = D62AED496AD8BC9EAE570843460EFF9F
+                               8CAA155E3B1619341D43D416A89C85EF
+                               2186E398467C6763C6B38AE8AC642391
+                               39FC7D77C5DE1BF0304237527ECEF79E
+            stream[256..319] = FD2A2505BC2484CD26A953A460D43EB3
+                               500DB0572509C1409AFB25DAF7A08E96
+                               8C45901DD9943AC3558FE2D956045AFA
+                               EC7FE93AFA7AC461E348A6FF67DFD8B9
+            stream[448..511] = 1A9AAF97AD789E4003BF48E9B723EBCE
+                               F2DB13513398FF8161D929F64C5603BE
+                               2D0B89D1B94E2C4A91468EF743C2A745
+                               98093DC6EB5069213A1423FBD5526B80
+                  xor-digest = 93DD39B5F82C8B105C9A1D3CA17AEB09
+                               21E77AF3235E3DC1F626D690D9306698
+                               60DB7382B38C6F3EE0F250DBB67E8001
+                               078938ACC2DCDFE3DC5E2F33FB4EEE51
+
+Set 2, vector# 63:
+                         key = 3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 6D05510EF24AC345594E94F58E6F5024
+                               1B40AA1CD6A62F35BC303CACBB263253
+                               CDDF54462EC606D6969E4CC5FB719A7C
+                               107DB872A5119566BF72FE37363E60E8
+            stream[192..255] = A1626164C36C6AB010B9A2B944ED8839
+                               13A3B9522F66429A75F5E30A03961871
+                               26AF86AEF382E3944B0414B274859B4A
+                               93881386E6A3E780802B0E6894739442
+            stream[256..319] = CBC22EEB532BE4B8B80D7F10A00FFFC6
+                               22A02B7426DBF648AF398444B8F8D2FD
+                               E4265F1B50CB43B003DDB0256D9E0A10
+                               99BCDBDE162E8AA37B107B316B9673C3
+            stream[448..511] = A7F2D829EF3BEADAE6D84CA26C81E618
+                               6F70F3D9DA4E208754EFAA5A0441D87C
+                               7AE36AF993E7225A9C68764C87B5DA4C
+                               C08B54A245A296EBF399B91331A6F286
+                  xor-digest = 55A30CB34036E3A22AAE25981272C8F3
+                               6392347B5FCE8101A66023C5B324867B
+                               783EA103A714E749F14375CE64985A0B
+                               8ACECA137560D12E941228D04A968513
+
+Set 2, vector# 72:
+                         key = 48484848484848484848484848484848
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 89C61A1182BC868BEDA3FE4A76CD679D
+                               A3DF3A656AAD3AF83BB55C0F0455AFCA
+                               1B3FBAD0B91F7B1F209E5F74FDBD700D
+                               9417BF9B4A22BD3B7C94317C20ACCFE6
+            stream[192..255] = 1C312223B46A20BAB52F110E04AB324A
+                               068E6DBDB1EABEA92CDC5063E38B7EB9
+                               A7DB50FC4CC626761CC00B7D821EB0E2
+                               D40F7C8DD10F5A975A14689151B38B77
+            stream[256..319] = B38D45E3CEC551950D662FAE4241E3BC
+                               5FC8FFA67A472B1048F45D594EA0715A
+                               5B1DE277264D72251A3C5024C914A0A8
+                               14747D714F8CC583105013382518A0F5
+            stream[448..511] = 42D47BDA13625C17FC6E972E68F3AA7C
+                               F8F9F12B900AB9E474C0295B48879DCC
+                               0832FD53C3C90B641454AB4BA90DD7D4
+                               1748F4AACC9AB1E1CDA8007B3B18B1F1
+                  xor-digest = 131A1E29ACA16C3A409ED6E201559CF3
+                               3CD05312376DBF6796D39E2877D23255
+                               F3308D3419CBEA800F1F2E9DF7AA36CD
+                               03AC3D6BD228A165A885824941D764C6
+
+Set 2, vector# 81:
+                         key = 51515151515151515151515151515151
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 70977581BC650C5D03F1B3A02672C384
+                               250692C2AC94EA0F4A43723E88FE587C
+                               00B5319F87223F6817C36F21FB852995
+                               5CCCAE243D65792A55D6F047DDE1999E
+            stream[192..255] = C00B41DD0BE80054F46ECE559526ED5F
+                               A87E7196A3A20698F5048183F91ABACC
+                               9E50AB64D437F05375CE78D75469EB7D
+                               478810E1C792CE3BA0C253FB1E549A0C
+            stream[256..319] = C95C6CE222392307CABC95202CE59EEB
+                               160A25C482F4608616C80B50A9D0B771
+                               732262DA67BE8319486F73E4B1FE3DBD
+                               1B7C97516F0ED02F1F4ABE9141329925
+            stream[448..511] = 93984394395B47A34FBEDD96E50A1F67
+                               7DCFB1845CFAFEB7DD83A9A7BFA35C7E
+                               48E44C38F9D33B3CFBB763A79048F6F7
+                               B6F32386329AC979F7EDF8828734A116
+                  xor-digest = DF2A33DFE7C90E76DB4E4F2D9AE2AB69
+                               EA16664B5E0031D800913B6572E1E2C9
+                               AD4A31D6BB088AA082195F8B4DA56605
+                               D32A19916474C042F755AB11EE56F6E1
+
+Set 2, vector# 90:
+                         key = 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A266B810953284ECAD69E960C9AC8FC7
+                               0B94798E55BF7D2EF54EE50319574C28
+                               7DF798958FD653B5E5BBAC0519D3F40C
+                               4372DB7204A3FFF89F6E70BE245C30B4
+            stream[192..255] = 72979FA8747EC91B68EECED4820CE7F3
+                               8EF0F20240D8E04C5004D10880BBE17F
+                               673A427D0FD62E8331BA633890D062CD
+                               FE584ECEB2884AB4086E3AD04F9C1137
+            stream[256..319] = 77E9FD26E216E6F22D32AA89E4D02C33
+                               482570BE05C0E1FAD59DCDC5A3F1315D
+                               B2FE99C4863DE4512EDBBF45DDF51CB2
+                               EF472481D6BB7EF8C7AA09E45B03F45F
+            stream[448..511] = 0386E999B6EDB2E52F86B3792A8BD15A
+                               FBC40B44D6EAFAA0D562C6FB2BD16BAA
+                               3F77F968925DA020D36A109A67ECEFA1
+                               CC278F022B93169006D79C0F56351DEC
+                  xor-digest = 35BCB2796B3AD76E59C2BDA7EBD7B47D
+                               C99236FAF5F2186188114C1A958185C6
+                               48BA837A3B839CCCF55FBA67B21DB031
+                               D7BAB7AF52A98676CFE3EE4249A530DA
+
+Set 2, vector# 99:
+                         key = 63636363636363636363636363636363
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 14F782FCF5C88052A93AEF40492669AF
+                               7C92F72147C2AB2C18217144055C9868
+                               3E2FBB80775B54D119A9A06AE72EEFAB
+                               999E85F3AE12804FABCAE539A8585492
+            stream[192..255] = 663FFAE38877EF1898973355FA27E9E7
+                               0BC0034A88C1ABBD2847C46335C18113
+                               47F42E18C1295D07D5F75909F0B1C0AB
+                               45EEBED3356A930E018E262655074944
+            stream[256..319] = 6ECB3BB43DC1C4A3FFE0EAECE58B07B7
+                               1CB5C7763DF420859853C7973778F63B
+                               10EB1B854BB8CF1DA0D5DCE6EA0D5816
+                               BA0508E7A1694ABDE04A706A008252D8
+            stream[448..511] = A68ECAAD1CF25C78522FB75D08C8CFEE
+                               561C2CAA9E0D44EEDB121228F4809F50
+                               996B9DB89E2E2F8547578F83015C55F4
+                               ABE82F371A5E02CC97FC35FE7DA49AD3
+                  xor-digest = 83F0BDBDF9A82287A650BC70A0C8F38D
+                               92868DF38D150E4268526A0A51D3A9A6
+                               FDA27D6FDE8A1A55E856DC891B35ECA9
+                               1D583E0470419BAB5C0B9ED4886342B4
+
+Set 2, vector#108:
+                         key = 6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 359B9D751379BECE129238C22647B90F
+                               A849534C9395EDFA5F2121963D2F0B68
+                               D9C6469AC8A192FACBA7C27762B22D8E
+                               39171D3D01D6BB41CC4F2AC318407D65
+            stream[192..255] = BB4795A89BA6AC0869B2BBA5891FC1E6
+                               890F13DCDE5CBBCB22A85014E554BF10
+                               DCB0873D79A79438F39DB467E23EE1E6
+                               2D2A549DC86B89FA3DF53BA5E5195718
+            stream[256..319] = 7AD5CF48C01B51572FFE4E0D23FF158E
+                               46941F1B1BB5D7DED2BFE80BCC48A6CF
+                               3DBB186AD1D3F911ACD8426B2A1219A3
+                               032104E3EE70717FA7D547014FD334AC
+            stream[448..511] = 6320933C389A66B5BD72DD69BA492432
+                               01861F3524C529DC2869127BA41DEEEC
+                               FCA5D5BA7521DED5166E70FCEC72A564
+                               545FE45F29A2DA9DCCD5AB80DFD119D1
+                  xor-digest = 9E1E8A8A4FE661C660DA51134D1C8A65
+                               3824DC5A99715E88F17245436F07E283
+                               E481D9B0A314B2DC9821930C80F8A184
+                               2F33F4219525F3DD063CB9C32D9AAC60
+
+Set 2, vector#117:
+                         key = 75757575757575757575757575757575
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CD479075E614524CA0B4A73BA48632FB
+                               01C8E9DA532912094D14606F08B81C0A
+                               CD7556942CC4FE4900C4419E8F618AED
+                               B53261B5B97603DC21F5FC8D57887F0E
+            stream[192..255] = E69AFA41D5DCC57CEE46FFF86551AE30
+                               D7A4B7CD2082BA8B9F446BA1A8E01B55
+                               D924E0D788A01D7C75B819D8B88C4074
+                               E97E1781061DDB3AF084A45E5A2D67D7
+            stream[256..319] = 27F75AB01FE45DBF6E661D39159A8727
+                               15AB7D7CB1275A11AA3C8CD55708A67A
+                               DCBE98FD8E1DF1F787F099881C87A3C2
+                               A0135088B99B21631AD115A8247BD280
+            stream[448..511] = A75C019250930742A65637B2E60A43E4
+                               1891CE1252082CA86891A684C19304EB
+                               7D57EAA4F8DF4686D05E886C5496C37F
+                               C224455AAE45F071FA654FC88CCBE17D
+                  xor-digest = F5C14A26F22546515005E433E1F825E3
+                               6395F5B59566C11C79F0435389DD7745
+                               793F8C925E68A9836B6E7B03C0639FCC
+                               CCBB3C1758E28E9DBAB1D9F733AEE7DD
+
+Set 2, vector#126:
+                         key = 7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 1AFC41EB0B3A1AE62127B62AE3B7219F
+                               C34C0A9D904D21F071424A7D07A55E4A
+                               69AB9FB401909372445844A367C2ED44
+                               69C12FFED293DE61619AF98FC5F159AC
+            stream[192..255] = 48080F88453788279BEAAD61B24BA5EE
+                               28F0044B5AAEBA5DD6844E2F57A0F3A7
+                               AF19BE8E7F6DF5BA7D74DEEF01CD5B09
+                               C928410B02532F66C19A3E677B04AFEB
+            stream[256..319] = 5D493BE7C17B1D6075F0CFF7C738CDAE
+                               8B5BB6126A1FDD8ED2FAD3A1502BBA0E
+                               CAD26485BD94EC5FA852AC74FBABB070
+                               FBC0604F69C11F5725F644FD14E5D001
+            stream[448..511] = 7D3D74044FEC8DF49C8A505CF1E5413F
+                               A63F53ED43F4B90DB3CAB6EC08E65821
+                               F1384E84490C6E5631B021145565D234
+                               67010AD6C9A5C729C774BFCAE2D43DC0
+                  xor-digest = E2B8D71D68ABBFA49D04DFC8A3DFC390
+                               FAFFCED207BCEB9EC4B6C435A9757AF4
+                               ADAF3E0734268365C82DE978634696B8
+                               D61EF69FAF3EF62CFCE89672F1CA7497
+
+Set 2, vector#135:
+                         key = 87878787878787878787878787878787
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DFD7B8D57A6AE51A401FA8DF38395B37
+                               17507AF28A9A771149C034F3361E0203
+                               ECE88C484F44DEB8370D9E77994EBE6B
+                               E05CA8E05E3DCF545EFBA53859C2FBF3
+            stream[192..255] = 42996981385309DC8884D65CF2103D64
+                               F76567EC51266A6DE5BEBC362529B782
+                               C95D92A17CF4567454422BC72D20BA56
+                               9DBCCA81DCD694B2B3DD88A988004875
+            stream[256..319] = 43C31B1EEAA67D7506A6CAE07CF9EB0C
+                               838C72494C14012F58B80D0F4D159379
+                               68C860E32A029B3B0CA040AAEE262CE2
+                               9C50046E1CE83FF36120D3CE81EA3BB6
+            stream[448..511] = BA8D089901F2F5C83E1CD485BC178F12
+                               88D1B700A7EE749DDA9A96910529EB5F
+                               057BC8FCBCD0D542FC3781E0FA742C3E
+                               C616578C8ED918E8F104EDC142BC7B7B
+                  xor-digest = C9D6AB2D64CC7BDB01F89F08047749AC
+                               38856667B53C87F8B501CBB5F18DDB84
+                               820D409D5A44FBEF505213981D86241D
+                               279C6749D1D0B756BAE39390D754AB21
+
+Set 2, vector#144:
+                         key = 90909090909090909090909090909090
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C60205FE3662A0905EA10CE1D17527A2
+                               7565D227C895A8C9426069A9F0F48894
+                               A96AB80039477BD604762F5F2CB2903C
+                               7642EA714B27B365DFBFAF60A6E249BD
+            stream[192..255] = 88DC912DB28D5A2700EB74CE8011A307
+                               E2A0B8FA2E9B50E38899B4AF1A0F3BA1
+                               79CF4DFE87DA0BCC1E76D9A56DB789FB
+                               18E439849D6B8B6850D0CF8A17726FEF
+            stream[256..319] = 2247A96C32B9BDC5DB41E7670DEC0A51
+                               73EFD83F345DE71CE0A2192354395576
+                               4101D73BCB2051C08DA70CA5100C7194
+                               D22A6C3DADF313369CAF8E545E97E25A
+            stream[448..511] = 83089E1CCDEF294EDAC0006D6CF49475
+                               E93324D10A6EA635B2C19D285B58226F
+                               AE271B6166A5818C6C567CDDE508B9C5
+                               264C2A6D5A8A4C7D6754CD11A58A6588
+                  xor-digest = 2B89AACFAAFFFCC15076A79EA8D983CF
+                               FA2CBE2BBAB4BC70464E9801B585FA23
+                               618864E62E573F51F1119D32E509A507
+                               458DB29422896E0A29E44D2A96FC0B64
+
+Set 2, vector#153:
+                         key = 99999999999999999999999999999999
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A6A3260212BC1A9FCD7336F1DEA05D75
+                               A48B1B1662F61B1CF1589A91AA66EB82
+                               25F58E77BFE7DB10AC31F318ABBDA7B2
+                               FBA88A57CA8AAFB83A3ACD0D78AE9944
+            stream[192..255] = C960FEA579A48D263C514DC4D7173B8C
+                               A325A16B02C87086EFC38F3271087B48
+                               BC51FC4B8FE936BB87336D54D35E8B60
+                               F8300334D0A78B48D2E97751CA571ADC
+            stream[256..319] = DB1859630B7E5D59366E95EE9F680F48
+                               1EEB9B880A3E82C85046552A844E5784
+                               3D4BBBC50923E806A1E2B03499C4F869
+                               9035913D5993757A5CE2A94311A22C17
+            stream[448..511] = 792B3AFBA5A9EC89C8119FB8F1CD552D
+                               6ADFCD61B70481760EB52878CB907367
+                               B2A5082FD963F56ACCD0F5FE6B67ED48
+                               EE81ACCBF066DD4178D39E001A6A2027
+                  xor-digest = 45E67FC4B7FCCEE700CDDE0404160E21
+                               DBFA6280DCFDAD3865FEC930EFF1B3FD
+                               799161C8812EB27F6A24985298994FD6
+                               5605325D0979CD798F0ECE18886C6E8B
+
+Set 2, vector#162:
+                         key = A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 94DF00B66C81CEF99E47BCB9AA6B2E48
+                               CCB408E20D878C56A9328D2422F1436B
+                               CCB7C8B04F8AA12BCF1DEE965EF098F3
+                               F78540213E755C86FA33B6117BE9E81F
+            stream[192..255] = DB745EADFB31EAE7A699A84FCD41EF80
+                               DCDC25334225F7B3E5D49FF58503C60A
+                               2FD73212719EA17F61F60271C9347E19
+                               3A894816DBD39A313AEA33F56311309F
+            stream[256..319] = 75410B6F256D7E9D2C4DEA9F24766E0D
+                               1FC3EBC67A5EEC72BD45140C41C3ACF7
+                               C517E9D8BE1B0AA06668012FB1C388F8
+                               098FA03173EC61CCF0252F793E42B4F5
+            stream[448..511] = E41DEDE3241806F3ACE001D8ABA5C290
+                               8C8D3DCC7E33A4031571D6F5BCAEBDBD
+                               0DA77831AFE34A4300B5677EC615FC18
+                               00A2CA80FEC9CB40AA33DAA1D20D80F6
+                  xor-digest = 8A80F6234BB7430D1EA7C6A6998D03C7
+                               CBBEBEA27F9C329012E19B0B62BC5077
+                               CB64AF18099DFB4113C6430B842BF529
+                               0DDE3BC0DF45CF836D766D03B6CDD43E
+
+Set 2, vector#171:
+                         key = ABABABABABABABABABABABABABABABAB
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 77BAAA833D320DD2E8C8D36D4C1025BA
+                               07DB396F663C2E50CBC43E640EF93977
+                               97ABF342CF471B758DC6A1472C817068
+                               BC7E30B49004DED1F763DE141C33A0BE
+            stream[192..255] = 018E53C65112E8C3CD374B892B21C1EA
+                               80408F1A21AF4EF02AC7CA5A6A55D130
+                               0B947E0A93D8980BC2070B082EFC3125
+                               E37F2A7D1A5BF0A8C8D154B84D6FC933
+            stream[256..319] = 0EA8A2C53BCFCD5350B3CC2CA07C0041
+                               53B4AEC461D18419071470D8F4BC7404
+                               F34FB030DCBC4E01B98DEEFEDAC031A9
+                               41C395538E95867A13EAC71EBCDADBDB
+            stream[448..511] = 1832583CC5A02147E6CB3FC2E5157A83
+                               3BD5513D14333DE552B5E1517527E4BA
+                               7069DE68F47D7A28CD2DD2808DF110AE
+                               1F53353B654E4ADD055032D8323FE829
+                  xor-digest = 14C12CE94857C60659ACC9DB6FFA02AF
+                               11840A7E2859DB05FA6436D7B3E9779F
+                               D21CA43BBDB9F721B5164485FEBE4034
+                               7CA303DF12630D6E967C0DFD7653ABFE
+
+Set 2, vector#180:
+                         key = B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 1C1BA750879B3BC214CB843962A0006F
+                               54E3B0F682FBDD7AECC21EDC208994F7
+                               E738B69FDDE5E90964CCE34D7351188B
+                               B3D788F435747FAA13EE208030893252
+            stream[192..255] = F358238286724199C183D8C960D730C7
+                               2058248249104960DD2899886625C5AB
+                               4844D768FB2594F2CCB751280478364D
+                               C78E631B5ED11343A104338AB8E28958
+            stream[256..319] = 0AF1A0C7A000092FB1CDA9CE6D145DDF
+                               C37D1078C00008392BE73C2F34DC05B9
+                               9FC4954071AAB16AEBA5A0D8498D411B
+                               5C1DAE961DC2A74B8FC992DAEFBAD292
+            stream[448..511] = CF358444795D941D450F2A6F86811CBC
+                               2492263D5964C4A45A26AEE228739BDE
+                               3BC223FE507EB5B9AC6983E213F529D7
+                               86473A4DB0764DCA5A27AB7B011A5393
+                  xor-digest = 78714C06C8C4C206EC238D4E679D96CE
+                               4C258C46C1EAB4E23D2E55A0061CD767
+                               9AFC8C85AB4862D39768DFFB3A0FC583
+                               0BD203F66B03BE4FD491E1FE0DD83FFD
+
+Set 2, vector#189:
+                         key = BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = AA10D434183C285709EC2706371DCE5D
+                               5F8C6FF0CA2B01281550AFE875413B25
+                               14D34846E658F9F11BED0F93A427FD96
+                               8C62380A46FE8E3F7E023318E989BF31
+            stream[192..255] = 2AB885D3EA66AEDC476DC5C59C3D4888
+                               2D39907B51878917B7DCF351CDD30963
+                               6AD8614DA701B89EC9B141696F77E815
+                               F95B15AD77B96513E5ED6C7F10EDE616
+            stream[256..319] = 39270D1BAC8A3028E55097217ABAA158
+                               1C0B8874A21E42533720F0F4350CAA8F
+                               1940A83B17D328BF0FD50BF8E62EDBD9
+                               5DF959FA4CEE952B6098D48277968AB0
+            stream[448..511] = 21DD7B64EBEF256536E95403EE0CCD20
+                               B062193EBCD72EDDCB1B0DE9308D048C
+                               B3F3C653DD93D01F3B266252B11F32A1
+                               59AFE3B00369FDA024DBF392921FD1CE
+                  xor-digest = 1A748746F13675F5125F0151D0AD6349
+                               7D23517B99000CB5479645F19889E407
+                               FC770983F7537AF86564F5B323E0DFCB
+                               FAEAA53AF258F151C871C83B5BEB7AE7
+
+Set 2, vector#198:
+                         key = C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = D4CE9B9AB39183E530A347FE5B435895
+                               4899F18A43A1AD9F249522F7B8243359
+                               EB61ACCC30BB40203D3B5730736D38BE
+                               057C15D6A2DCCD005395C16CEF85FADC
+            stream[192..255] = 459CA305A8F73AA0931A56D914A51CCB
+                               3C6B22C1C35392464BD2BCDA1FB37050
+                               E2181510546024C753222E678A7CCDB0
+                               77DC88DD7C947210897021A72E437DBD
+            stream[256..319] = 8537F62AC5AD1CDC7C6C910D45111165
+                               5219E461238002391B54E7A8BD6BF323
+                               1E2CE93AA581D9A8E755B33A382FE56E
+                               9FAC3D9F3370226EFB99701B4D0668B1
+            stream[448..511] = 192691D070C8E3966467F1DAD89D5D8A
+                               E345230E9828C9BECF681DC7AC0B7AE9
+                               88656C7333BE93F103D7EE505F05C5C1
+                               FD8CEA2D27407EE265CD59F6BB5ED7F8
+                  xor-digest = 41A75368279FA64F63FC895FDC49DF18
+                               1EB48E780AAE9C2F548C825BBB276803
+                               A4479CBFF22E79E35701B24B47B45777
+                               26B5455C804E802B62704655B77D20F9
+
+Set 2, vector#207:
+                         key = CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 430EEE25DFCA972E12DF2FA3FD1F9A61
+                               CA16B3EA67C5131D701360C9BBF2ABCB
+                               F2431D01590B300CF462A68FEC3C6E9F
+                               1F6A5BBB416EE0A098D2995711C9772C
+            stream[192..255] = 97D49334BC2482B1BEF901BA4A91738C
+                               F6DD9F917862984616DA7C2FA3F9BEE5
+                               1329AAADFD5B88A224C7B4EECF1BDAD2
+                               EE33E2C7060C1EE0E8A4E21D78D08942
+            stream[256..319] = 79C06E2806BB38FE558E926E4A2C11DA
+                               903DC06D384D033984D2F7516ECB2657
+                               4D5B5629B79C8D38E71F9A01B9526EB1
+                               7E3FDB48B37B6338BCCBC914B7804935
+            stream[448..511] = DA2A78E621FE1D105DBD0F7CD45AFD51
+                               366533D03C446005EF100DFCD9789C5A
+                               06A00A7379A4D45AAEC1CC337F61C532
+                               DE26B1D028E72C399097A04FD7FF087C
+                  xor-digest = F3833AF5AD9FF9AC9B227B1C9D0EF385
+                               0B22FF5A0F307EB25654BFB63C61E802
+                               2134A69091E5C5DC1E04C56BA2009B97
+                               DC9D02339578603D8EE4F50D1320247D
+
+Set 2, vector#216:
+                         key = D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 7960EC96803829CE052CCF5B8205D09E
+                               A417C075068FE91982283DA19533A61B
+                               EAB72F7CC93AEB22AF97AA3B4A5B337D
+                               36C96BCBB23A073F57F2F378B7309758
+            stream[192..255] = CABCE57DB1AFA7127A13498FE1FF87BF
+                               DF1C40DC7F8D69D46EF62996C2AADE35
+                               526377F4A09FB10B4260EF7B5E700470
+                               1729CD1F0732748CDAFFC14AB6910617
+            stream[256..319] = 01898230BE3F6E682480C8333700A2C5
+                               1FD38AD27EBBF60CF2DF71B22C827708
+                               3A1476E7FCF3348FD5E4E9EEE6CE61EB
+                               818DED1BA0C09FB96C5B7C799C1656F7
+            stream[448..511] = E49D27417583CC79299ECD18751AA540
+                               C7831C3A0252292EEA8242590714DFF9
+                               4833393BCC56403144E68A6BB08AAF35
+                               2F71C6AEA9256EB5AB5250DED6366AA8
+                  xor-digest = E6D998D7F3BF7EEBE45844EFD7EEA371
+                               4405D07D6EBF2D5F7F5435E4F557AB4F
+                               7571015CEBDC2CE0A199D7FF8B0DCAB2
+                               B9BACAEABE852E667EFD2E82A219FFC3
+
+Set 2, vector#225:
+                         key = E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E9AB7EE17B4734823A1522F5D78EBFC7
+                               2F8112F67325BC5C12778C6F8302ED9F
+                               BB545EF47EBF2B12380935AD8048B90D
+                               4B7DBC7759E27C205C94202EB64F8E0A
+            stream[192..255] = 5B775277917681D67800B3249E7A82EF
+                               C5500F49E7507CFA0696D94FFB021CF4
+                               EC6955663CC37F9B2FF7A0345A71FEFF
+                               3712836C66A05C3C6FB9A03EC3D52260
+            stream[256..319] = 11ECB0057615CC8244B2251E87449CCF
+                               0CE7805F669C762F46EF54E8E992737A
+                               BC668204D49ADA49E51E592B79B34BEE
+                               248CE41C72E8A60366C9951B74986FA2
+            stream[448..511] = 3BD82780875577B7ED9C603A240F1944
+                               5C3090E36926793F769B11E3C6C8C993
+                               697E2A0C1793AC4F39DEC882DACE3375
+                               D17B72FE40B82FB95575F9B7A17B24A0
+                  xor-digest = 996E394453A2CDE7CF809216337D1ECA
+                               FF5FFA7414AAACEFFFFFD30CCDA5E424
+                               2223AD119B3EA56D50248E7E7C0BE002
+                               9640304D08A2B3D44386CEA0098D6738
+
+Set 2, vector#234:
+                         key = EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 79D2D1270B77A586ED9C3897C2875842
+                               16498EA183465A96FA1D783BF1B1B070
+                               B46091CC3879E9ABF97ED22A72FBFF2F
+                               F8C72DF9A3832C927FFDE6FD43D6C1BB
+            stream[192..255] = 4CB1C6953204F5F279F9F334AE8BE696
+                               26201C8EBD488E6204DCC9823E022A15
+                               23DADDA98E6A1A19BD42B37047A2906D
+                               19EF12702530DF4B7E597367B4463DA3
+            stream[256..319] = 51500A31B349274BBF9A6E324773E5A4
+                               2E91DA8482D306C7F13EE3E1975F7BC0
+                               D9006964367F4D8B28B389652455951C
+                               402AB51A4ABD06262E0E3A7A8FA3A7AE
+            stream[448..511] = 01F28C4729556AE8227B306930175707
+                               C75BF589B3711AACAD836615D666A66D
+                               255B40302E0DD5021EC4A15BCCAACA95
+                               565BF3FB68BCF02D265F911ACDF6BA0E
+                  xor-digest = 3B5FF103A75AFD640DEA7B686359CBBB
+                               A888AB60348CE2FDF301267E415129BE
+                               46D088D9222139E96DA8D804DA3691FC
+                               C546981BF65265FE04366053229BD030
+
+Set 2, vector#243:
+                         key = F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = D8AA78A091BFB8D90FCA94705DD86B4D
+                               FBB2673A5ACCBDC4F69A21C3B06A0594
+                               F470F70DCCA273A2A72C167659B7E0A2
+                               76CC3BCC20AB889E682D4E2B70BEC4A9
+            stream[192..255] = FD6974FE135C1E11DDC82F2DCF5CBB27
+                               AF0A8A55084407C3315B47FA41D2C240
+                               372C7C4B03F8F90C3201B2269D18CFF4
+                               C70A13722F46FFC34727779CEDD17FA8
+            stream[256..319] = 6433E61D5773ECF30ECF8DA06F8F11BB
+                               717B268E2C283FDC7B2F7841040EEEF8
+                               29216193392BA5D99405A744FB571B6A
+                               71A6EA188B3BF5CDF9D601ABE3312FA6
+            stream[448..511] = B238D39267ED812D37AC81E6D2B29D21
+                               45F9337A6E2CB426C8B43BC795832FA7
+                               8D94B5E1E83C19D40D3C2B4B670F3C1A
+                               D504DA82D6E83A71BC5E431152B485EC
+                  xor-digest = DE1C9B7BAE92989BCDC7AD0D527CC6D9
+                               4F138C8C2A1A06C1AE28405C867191CF
+                               444F45770CC216226ACB13D2A0A2B8DF
+                               FD81B93AAB20EE7C19E631D9635AD0B9
+
+Set 2, vector#252:
+                         key = FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F61BEE71B1353E8E198E9300CC720C88
+                               977F23274ABF7F9DEF298B97EF43FFA5
+                               CDFEB51DAC7224EE6DE64CE0966B358C
+                               9786762BE880BF00BD48FB1D3D1FCB99
+            stream[192..255] = 019B52D05CEC5CFC74F2D26ADA3D2F18
+                               B4B44D3EC9359A132AE18B33510C249E
+                               D56D0AA2BE16C6213BE2ED47514B70A4
+                               DD5FB07C317757F5981009F70EEDCF39
+            stream[256..319] = 4221E9421F2C68EC8B59660512EA0442
+                               64FF35D22DEC65E1ED18E3D8BA359A78
+                               92FB5566DA0DA25CD5A3409EF6A6F020
+                               59DD632A793886C0032864F16D827A36
+            stream[448..511] = 71330EEACEE6E27994023E212D1B8A42
+                               045C29F141E4C696F74A0E7500B45E82
+                               A0ED1F4DF8C78A93D8D6033B780BC22A
+                               F4D8029B82AB447E0D5EEE3405EB0D22
+                  xor-digest = AB84F0A0D9D1E8D810E76517E5A0B80D
+                               0B2832EE12AEC48B5DA48B78DC4D2278
+                               710DF7664ADD91B1FAF3F14F3951344F
+                               08515E7D43F8EB677B5CF18C487A697F
+
+Test vectors -- set 3
+=====================
+
+Set 3, vector#  0:
+                         key = 000102030405060708090A0B0C0D0E0F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CCF2DFC47B94B1C67DA07BE50ECBEBE5
+                               9F470BFA68058E55529EC8041EAA2107
+                               A15DBCFF20B1E54B36ADEDB49356FE2D
+                               4BA86FA2C6FE08DD1E260D7D20A3D93C
+            stream[192..255] = E5EE7048E8EC8C7904138C6E355D3956
+                               1D8A1B824D62DD5267918237E9225416
+                               2A192BD543327B9D786F973479F88DDF
+                               152974B2FCD44DF9B77E1E9D8595F29E
+            stream[256..319] = ABEDDC8F46C83EF0B3D159B3A1BC6E1A
+                               4535744E20D82A2013A3013F864D4B43
+                               01C54F2BB0F03C775738875C1116642F
+                               4E6BC1D551145D40A8F978207F44BF89
+            stream[448..511] = 804C09F0973A24FAD6B4E7398C57B11D
+                               E670AB2AEAA63822D70C7109E2E1CA58
+                               42E2251424C23525980A7E7132BA889C
+                               C2604FCD9F443A1A194646730FE349E7
+                  xor-digest = ADBA33559432364C670A33CBBDA0C0D6
+                               D75C6C986D073C473C96286F5058ECB9
+                               5B78052C26C5BCDD6138334201B05458
+                               135B363B8ADA8CDB3AE0C565C9235646
+
+Set 3, vector#  9:
+                         key = 090A0B0C0D0E0F101112131415161718
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 759D5A8381CB183CB0A01B4A85FBD793
+                               EC9580339CECC9BDF7DC52F67D8D635F
+                               1F590575EFB26F906424962D99880E45
+                               AF25D68181C9652EFA590E8B1E0FA578
+            stream[192..255] = 3FA014E6416459F15B5527380E5B513A
+                               CC38193B9A26CC24C59CD6866EFE8010
+                               30C950DC2D55B70495D4C11296D9609D
+                               670E41CCC20EA01349E28A2651318A1E
+            stream[256..319] = 675B1A11D7F20A18C137EEEB2D3593F1
+                               7D1A284A076E4E18BF8B622738962236
+                               C3F07D4AB453EB4FF0E3A0BD89E21AE5
+                               CD17432F149B386CD29011D6864B3B83
+            stream[448..511] = C2C4385B74B6A38A18590A5A596DBDA7
+                               294C4DE7B15EE36F4481E275AE2C11A8
+                               17181DA10309BE5B366852035C227BBB
+                               C61F001560F03F2B361B5B8E0FADE6F9
+                  xor-digest = 26A33A713972455A92FF0E6D65C7A7C8
+                               537BD0D9F8EEC96E03C3B39C5F9307FE
+                               F8956D1EC10BEAF467BA86A26E846ECE
+                               F4F330FBD9D6DAF5306DE538F0F76C0E
+
+Set 3, vector# 18:
+                         key = 12131415161718191A1B1C1D1E1F2021
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 27D21507A4F5E2C39050B1D752574ECD
+                               5BDC31D6E8708D1AD950E3E48C53A059
+                               9FE6F7B5CD7A6AB95AB9C3FE0EF154E9
+                               68882B10A2613A283C9310579F444F19
+            stream[192..255] = CFD6E486D72760DD5FD1D246C5C150BD
+                               622052B7F1938C3EA510F3D0EE47B494
+                               FE8854A833EBB2C7E579EE3925B19AE9
+                               EED77434CF7B7AA00833904A78AED517
+            stream[256..319] = C6FDE37C40A1FF7B4EA3A8DD64E7A1D0
+                               7C4F25C04CE05A3C09F6EE012B458A9F
+                               93FF21C9EDE67FF06918CA541DD24C87
+                               19931323F1C87EBC38F56308A2F5E076
+            stream[448..511] = 1E9D3E112C8CCCE11ABA19E941E48173
+                               EAC5840A3025A88EE79DF2514EDCFBD1
+                               3A581C507EA3769FC0498EFC7447C0D8
+                               9135E602E06512D25EC773A20C4D1F2B
+                  xor-digest = 122C8ABB06E644953AE81EF78CF4EF6C
+                               A1322AF81186B8C27EB199B5EA7814EF
+                               E6F0C6EF98781CC12FF7A988F135F3C3
+                               28BB53B6D2612B1786D4B24D63BCAD01
+
+Set 3, vector# 27:
+                         key = 1B1C1D1E1F202122232425262728292A
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B98764C4BEE54B7CE1722955D29F7265
+                               74D3B6D2A7F51847A8A5F2BD78218DD4
+                               13BAE5A9B76EB7C2140E6D728D430CE3
+                               EE77FA5446B53D887A600B8C2A954DFC
+            stream[192..255] = CA3AD141894C09B6DF333C6C42729339
+                               45AA6F7F13EA64C1E3043F2AB64FA18B
+                               A3CF16B35E853FC98A67DEB1A9A60B1F
+                               EFF93767C87E583C8B50BA0B80B69AEF
+            stream[256..319] = 0D03AEE4BC0E4260B48C43614AE1327B
+                               4FAA2F0813F188DA28C3CF15C433EE59
+                               881DD500A53768C5A1231991386E1470
+                               2295243CF3E18638B60CCC4513C83077
+            stream[448..511] = 4E190889B78B6CECDDCC675FCD336592
+                               8D01D945C8B9737CEDC144005A7E2E6C
+                               921256F89098BB560D39BEAF700CA5DA
+                               4F4535ACCE3439D9223E357DAD2983A5
+                  xor-digest = 2261129A59B37D3C9FA15E35B9DA02E8
+                               B6044084F0EEDA1A62641BD8BEAE9293
+                               A57E89120CEF2CBE5594C47F96E46C5A
+                               E6FADA330126A4EDE047E40153D5A182
+
+Set 3, vector# 36:
+                         key = 2425262728292A2B2C2D2E2F30313233
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F8088D4E53936A40E21B3AAC1E6D975F
+                               13BCA7E4D6CF7D926F6B9AAC562790D8
+                               E2B66C05A075737B75F8E171C70E1507
+                               94437B818F59052FE5ED87BBADFAD509
+            stream[192..255] = 19686CA73474C6F626390DA198824970
+                               9FE43AD003953D102437DFE11DFDBC64
+                               432929F934A0758B2964EC3B7CFB8C1A
+                               BE23C6B12132B155D3922719DF28ACC6
+            stream[256..319] = 55EA041FDC9CD8438EB7B9C2C5381785
+                               57E53ACC75CA512B88D8531E07DF4C15
+                               35F60851AC242CD46F56DD35241D51AC
+                               6DA52A3BEF555E2844DD4EAFAFE3CE63
+            stream[448..511] = FDFB1D76CEA5E3FD0C5EE1FDA1717684
+                               2120C48956F28A583B291712DEFC158E
+                               FA26FC4A833D31B0EB59F61D942E99D4
+                               AF4BB42D0C0448CF8CDDBEB336738414
+                  xor-digest = E49BAC9E963F83F3AE70026DA7DA496A
+                               0764267F7F5A8A23F7AB32EA0F54D459
+                               32367E47527DF738F7255CC890F15FF5
+                               8160EC0C1A27260856A822810AE63F2C
+
+Set 3, vector# 45:
+                         key = 2D2E2F303132333435363738393A3B3C
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 67F1B4269C402D69FFB8B84559E60033
+                               07B153631D650E01A3B265739130F184
+                               4F6126FA1F957C7FF5AAD71C2E3BDE25
+                               94DB87780773B4A4DB3E44D231D46AE2
+            stream[192..255] = 5BF80BBE842FA08B4B2EDEEE74626A19
+                               69CDEF41D1E731FDCFC906F320A2CAC2
+                               8B79B585B0F70A5AB48CBC5C9478E5EC
+                               B14A387D5DB8E60E4EFC86785274E437
+            stream[256..319] = 5DC02CB76EAE6800980E204AD9A315F7
+                               A65C57E2F38DEFCC29FB1153E7A4586B
+                               E9FB7FEA650E326A5593568957BCD278
+                               A93FEC168D48372068B9A2E41EE10C61
+            stream[448..511] = 61D55EB5278689230193C990EC5E65A1
+                               DDA93955026C14BC32E80036055A31BA
+                               118911DAFA9FA9160D4C37524F5EFFD1
+                               2D575FF005967C3EACFDCC9D8889A198
+                  xor-digest = 9B327699C5FB098D15CFF2AAE321D095
+                               A569B6D87AB1BD20FC8FD94AABFCDF2C
+                               521D3D5657857A6E197B55F371351525
+                               171D23F4DC242408730057CE67BE8E58
+
+Set 3, vector# 54:
+                         key = 363738393A3B3C3D3E3F404142434445
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = D9B96EA262807FB3F5A8675D81B1A006
+                               1D717D345EB2B91F607B853A5A38DB2B
+                               ECDD26626A33477BF07BF9C57FE95100
+                               A1F142F70DA7DC86E063A58AEB090B2A
+            stream[192..255] = 597883FB531AA34A2EDB6D83AB2A304A
+                               FE522A9EA6914C556618B3094874E021
+                               2316FA67BEAF7ECE4BCF350A817DEA50
+                               FEF5B76E72E2596A149D99B6971B069B
+            stream[256..319] = 6090A1AF397F2BC3ED551450EF28472A
+                               F60EE5F2B4BEC18A8B1ADF21A6A476F6
+                               8C11F76405ED62ABB7BC585BEA4B0A47
+                               988A09A1D93CE2CE95B82C9C1B60E650
+            stream[448..511] = 49F88E9C5E53BF43EA422682ECA42968
+                               6D794754E65DCE9306D3D9FF206BDAC6
+                               442655D27EF6166CB095DA4C301FB7EE
+                               F1F5FA0225EB84CE61BF3856062A4EF1
+                  xor-digest = A71B962E13E66A678C5B56E19099CED2
+                               A15480838832FA6361C3C0B5BF47C1C0
+                               DC954A7CA8D7484D7889FC760227B418
+                               73EB611B5AD62FB622F5FB75FE412A44
+
+Set 3, vector# 63:
+                         key = 3F404142434445464748494A4B4C4D4E
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CF11B1510C81A296CB185B1BA6436112
+                               832AD2EB68B70E52CD68F9D394F5165B
+                               94DE467FFDE4EBAB6AFB180EE7A2116A
+                               1E73AB81AE4528273D0D93DD05025D70
+            stream[192..255] = 26E9F1C007EA49793D701F21696FDE8D
+                               B72D317BB958F86A35E7BBAC80D62CE7
+                               0879213503B04FEB1FBF3987847745F9
+                               DDA9310DB36AB8F485FEBE9FA6C1C7FB
+            stream[256..319] = 25C98B6441F90615C6078D82B5D72F61
+                               828ACCFC365CD5EC17D5CEE488A51192
+                               8826B334A1D7BEFAD7528BC5CFD32B82
+                               87F4EC603E21F528B51999F222817DF0
+            stream[448..511] = E2CB68B1CFB640B76DBFC5CDFD192AD0
+                               A7E8BE14ECDF6E20F1C8FD444D073108
+                               6932BFEF0EFBCB7F64E5CE79CA4AAD15
+                               846081CB229C74013CA0D498DDC69703
+                  xor-digest = 4BB7025AEEE0FC3ADE977F13A0853FBD
+                               9F43393A6A0B7C91534F5F2A47009D63
+                               79D0B9440D5A36A82974EE70BCF3634D
+                               131E754FC6BFB8DA62A05B3F4D1E9FED
+
+Set 3, vector# 72:
+                         key = 48494A4B4C4D4E4F5051525354555657
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0CD34EBF2677F222A589B77FC7284567
+                               C3CD391D85E3CBD04F43DCCFF830F0D9
+                               5C9C97371376B180AC2235DE4EF2E377
+                               8242ECD6A257FA02F2055CC7116A006E
+            stream[192..255] = 0CEA97153979B13DFBFC3F04D311D677
+                               9380FCA517161003A82CF5E00CAD8438
+                               18341CAF98A5BB7CC4D4E487A5878A3E
+                               F0D490EFD4834ACB92EE0FBAA3144270
+            stream[256..319] = 700797B741FF36DD80F72A889696436B
+                               A900033C957BEBA6BB3EE71AE3D79A83
+                               FB4EF28F39B0B3A0E36719059774E6AB
+                               CDB4447CB3CE6CF78E30EE239F537140
+            stream[448..511] = 44EE572970D5AB8C094D434DF6489171
+                               B657A51C610D370EE9517370780D81CF
+                               47A666A1556AC7B254DBFCB2D1352365
+                               F62B950D9457E4E364EA980C3832AF75
+                  xor-digest = C794C46A6A1C155D6922A7CCF4327038
+                               B48618EE29326A7555AC2A00122D4E83
+                               A4F17AB72F9A133F48750BF43344D561
+                               E71C69844840FE83889B542FC83D5132
+
+Set 3, vector# 81:
+                         key = 5152535455565758595A5B5C5D5E5F60
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = AA9A1800F63A3D6EE6FAAE48B615175F
+                               F4EC441EFAADB6273B38087417E9528E
+                               BB3E9A8D9E81C6B7863D26C24CACF50D
+                               BAE956DD15EE335C99CDC981B4182545
+            stream[192..255] = 6F8CB1506073F5BF7E656C25BB46A689
+                               73EFED2E87229204BDB09910180C279F
+                               23341A1FBB0C40705C1EDCDE8E1BD8D5
+                               AF9F503901071A857F8315ED2F963114
+            stream[256..319] = 3EB29DC8A63E3B61A6EB1062F189BD53
+                               54A7DDBB22A6C3B7857D80E5A761836C
+                               4A91EC1C994FBAF781AC65B1840DD892
+                               2A82AF4D6DCE1004B3FDCDE790018C31
+            stream[448..511] = 00A6E02F4DCAEEE2FC77318AB9619246
+                               64E1DF835DD62629D035C44A1E147D6B
+                               809D6C60983B9767B92A10E35A651786
+                               B0B0E1B8FE8BCBBEF4D02BC625E5B402
+                  xor-digest = CBF02F452CCC84F5D8D3556876B7902F
+                               324BB22F3C676D3D5C5FEA182A4582EC
+                               57BB18419D8F82CC8C43737F3B356C73
+                               CC9452557FDE07F9CB3BCC06041C4279
+
+Set 3, vector# 90:
+                         key = 5A5B5C5D5E5F60616263646566676869
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E5605A67C46B013408F53D1D8A583699
+                               389267A63163901506FDB6150CAB719E
+                               D591787D8CEEBF1EB13E73F6A5D3DBCA
+                               CC916D41738008C5453132A472931D9D
+            stream[192..255] = 0D04AC34DE63ACD3D554E568B4E423D9
+                               76B22FD4C32464BBA143163B225AE996
+                               4658EF46C19E5C95CA14D9677098C303
+                               7C37E77446E8878A5F8794E00FD2E0F8
+            stream[256..319] = 1915755636B9E8CFDF50F532F6FD6C66
+                               60CA7E53C6037A532A39E56E61C6067F
+                               99C864B32049F95CC142B019BAA37720
+                               1A0C28D747CAAB42E81073F14818EF1E
+            stream[448..511] = 820E743AC49AF76E030EACE4D0BD568E
+                               781B2AB82257DF8C407C159CFFC13D12
+                               7B869E6E48C5A6BE72A5F1A9877564E3
+                               CE22D770D9FFE839BA4BFB8D297D3795
+                  xor-digest = F98873945A95030C43B22CE430D520EE
+                               F6E4F2FF30F2545693C7765D5EB19AC7
+                               A096799EDB90D661B1379264D5B42729
+                               E2CB5479FE63BA9B8D409AB98696248C
+
+Set 3, vector# 99:
+                         key = 636465666768696A6B6C6D6E6F707172
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 2ACCA4B94538608F318E142FA9DA9DAE
+                               F2DA0FE10DC27C804C0DCEA927CBFBFC
+                               4F9AF87F67D962130A2DE073D4CBD1C2
+                               70A836BE81FF2EFA6CF910E6F558485A
+            stream[192..255] = 586AC09D4C7285B3CC8A49BBF978D086
+                               C628229659DA298476EBED38C7FCD86B
+                               59FEE45D41F480258A44C0615DBA2DA5
+                               E64B178A2E7EE3B02A316245152F72CE
+            stream[256..319] = 1988E499CFD61EC2699181A520C1C829
+                               3F0AE76B30C4BD0279C937D53054F646
+                               B318B13703EA193F63BC83BCD501C083
+                               D31B8E2DCBCAA5CB4B9ACF15EE740010
+            stream[448..511] = 797DB54E1E718B6ECAB6F928C3CF507A
+                               A8E58832933F404CE1331FD469643E78
+                               3F8BC3004AC7AFC5EF036F8B5D4DB5EE
+                               16BA7F94C39A39237EF93BAE10E427D1
+                  xor-digest = 75197D3AF308890C381051938649CF93
+                               157F5E1200E87F7A0CCE920B1A378415
+                               F1DBF671C49324EF517ACDE52BDDA9DB
+                               BACFB24EB2DDA3582DFF0F0DA9A7CC8D
+
+Set 3, vector#108:
+                         key = 6C6D6E6F707172737475767778797A7B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 5B1C1C98D5EC2E066FE163A010AB06CB
+                               D81E8E237F4486C3C57C7DDFE9CC4E2B
+                               6C0C016EB38630B09823CFE1804D969B
+                               3CF93666F785BF5EED450D6CCAA1ECAC
+            stream[192..255] = 5519D71CA1AD10191586664DDFF26BCA
+                               7CEE6FA4C728BC0487FFF71236DD947C
+                               C7F84A9ADE9ACBDDB04CA4576AA11CD1
+                               19F676BC908335BE454957280423AB9C
+            stream[256..319] = BCBAFB8D31351D748DAEB21A4927FCC0
+                               D206C0DFD1EF6CE6425808BCBEAEE26D
+                               DF29CD37EF61A6C186E33E432298CB7E
+                               94A598588A7649C3639D3EEA43A4EFD9
+            stream[448..511] = 6FED1CDB9C109AC353D8F0A92B8DE388
+                               EF089BB8805D6622CBF93F4E70939039
+                               536C12BB7952550B4A9F62B8F99A3522
+                               FE12D79D52456E5E2B58D899CCC0A683
+                  xor-digest = 9A528A131B2DC7999743397DD1191EF6
+                               306AC8B7D333276AA11FC5F952DA12C4
+                               890509B6B3324B57117736A2FE462B97
+                               3676D4AB0F9EC5F40389BD1631DA30C2
+
+Set 3, vector#117:
+                         key = 75767778797A7B7C7D7E7F8081828384
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 19DD8D2D6FED84E4C8983761323019B5
+                               6EFBFDDE9D0DD65ACF8EA7064D876159
+                               34CA7A8690CD9B688A3A7E2739C0DD40
+                               87E931669B47FAE65582F217B703F744
+            stream[192..255] = 118247263D78B35C87001EE80D0855A5
+                               4BB82A2538BDC4CE4E0508BA9C1AFF2D
+                               F6E3BD124EE8EBBE9C5F8CFF809B22C7
+                               EC14FADC932266458D049847E4BBDA57
+            stream[256..319] = 3ED5D1F9FC223FAF7C35165CB00DC41A
+                               948089FE364B824970DB5C8EEB277D5F
+                               E1D7EBE4133BC0B5C9AA277360AB3D59
+                               D990F5F7F8FB2D4839F8DF8F91BC8CD5
+            stream[448..511] = CA652B9B5179E5FD45CDD84F778BCA9F
+                               A5E029B0D5F8F8DC9F6848EC6FB90CB8
+                               B5D6D1F65BAF94B02FAD8F432901B2C8
+                               1DF0A7BE680810CBAC3FAEA492EB49C7
+                  xor-digest = 1D54E85686E20E556FF40B2C310505C8
+                               B3E341EE7DB6BEE6761CF0FF87D56DE0
+                               3C08007AC388112D542875E0F56BC435
+                               EF698DE5F550B2E6DADB7CF899C670C7
+
+Set 3, vector#126:
+                         key = 7E7F808182838485868788898A8B8C8D
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A865C1EC58AEB098342D771FD9DC8CC6
+                               257144135060E17F794154163B5B50E0
+                               C175DADFE996D8D9EDC24F528B403EBD
+                               31B181DA7621E80465F5609656D2F6BE
+            stream[192..255] = 6E369A08D533239B1813FB1E64FE4016
+                               D5A168E7B082AC17782FD536B1614EEF
+                               9B96114431A8A20901442B17D359AA8A
+                               616CDFF610EB376A01A5424443724BC5
+            stream[256..319] = A6A4AAC9510367507B3ACD133FF4621F
+                               EF8117A2F74CE892273D852801F6B788
+                               3B4CFA27124C42D424131AFFF2890AF9
+                               B7EB6F70917407991169997C9014C6B8
+            stream[448..511] = 54DA1A3C64310F07888F043684AC5081
+                               B35962F34CF46D8B1BF8CB9079A0CB7C
+                               3AE2998F6A247D758D7C435F2A509E9A
+                               164A0CB7F1D9FCF1DFF99D2C7074198C
+                  xor-digest = 44F37D188FB59A4BB0BBD69BE1592797
+                               65135A26C7EC258CB2FFCA9BCCFDC005
+                               E9971F4128215E73D9EAD8C6B0465C98
+                               DFB9065DCD07E83DEC0001A737CF8DFD
+
+Set 3, vector#135:
+                         key = 8788898A8B8C8D8E8F90919293949596
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0707B0C6C7CFDB502FBA27A9179AC77A
+                               8EC79404E4DF30E46B0512EAE40876BA
+                               A0129C7C6A7D61A264654AD3C7822B68
+                               80AAEF7CEAB7CDC898F11F217BF705BE
+            stream[192..255] = FE4ED3B451213FDF4847305FEB8E9FE1
+                               2C359E24DC7AC0957DF2558D300FB0CE
+                               D38A9983F6CA936514983BD48F80A596
+                               A2CE35993ACA48ABC500BE4E766699FD
+            stream[256..319] = C5BF4DC95100E2D7F6792F6AF5F31371
+                               53D418611ED358EB8646CC359FF18770
+                               93C18CF26FC4DD646ECA8C4A199539C6
+                               64C92D30F2F3D652DD2E4CF66A6F1725
+            stream[448..511] = 588425C16BD8DDA6D1D34950A40E35C1
+                               2CBC1F62542B3D3F6AE4069DA42CFE09
+                               8B36BAFC94356A4EFFA655EF8DFC281D
+                               F47FA499717D95FF7CA81EA175E2D6FE
+                  xor-digest = 4F543EF4ACADF04EDCEAB6841B794C70
+                               B9CA52B336CA4D6696E5AF632271367C
+                               29815CA30CB0528546FAB08A6AF9016A
+                               9B25460BD71FC1D00C516961D3A0B448
+
+Set 3, vector#144:
+                         key = 909192939495969798999A9B9C9D9E9F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C95BF1BBEAC136B08DB163D8A12CC5D1
+                               53D2C485C257E16BB5EAD3B93BA84D32
+                               352DD608CE457C3BBC55864B1FAE0296
+                               1180FA7063C3E9AA05A471F89E9E8C92
+            stream[192..255] = 112D3B048885FE87290E91C2288A605C
+                               669795CAB3F78FE8C6E15204E0FEFB5C
+                               9D0C690C2CC57882AA3C276E94414DE9
+                               376531151D9BE1DAC6D784E95FB196B5
+            stream[256..319] = A073295F2907C05C3CC3A17B8E404338
+                               0BC74C10864FE1EC6F043DDEA356CB48
+                               4159EF66A944668B55131F4BE61D7F4B
+                               4EDA1CCC0CDFBDFFD79B9A37D4E0DD01
+            stream[448..511] = 42834D089F1518A4E6167174E844E51F
+                               C31BE2238B7C2F306F1DCC3FF7DD30E6
+                               E9B0CD089B9F9280EE40D3416339E1D3
+                               47F0E29593168593203825261191D02E
+                  xor-digest = 86960034091CFB6A6767B53B66713632
+                               C6272B95347CB92D8D084E8794984516
+                               4AA48669D26826E2C84907C2CEA78727
+                               B0D3C9E240A361FFA661F00670C3060D
+
+Set 3, vector#153:
+                         key = 999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = FB01986DB035CCE47390DB060C6A31D8
+                               3C9E93F728E785ECECE34E41D81133A2
+                               69C5917545B1FF479F4C45BD1F6AA46F
+                               3F9591C54F3D67A8BA7AB6DD9D7D07FC
+            stream[192..255] = A056ECB565EEEE24B5C42C501D78882D
+                               A9AF1A9B5BE4DAD286E695A23D516D52
+                               CA83FEDE7CA0853C01D8043CDEE992FA
+                               1F71C90DD5C3C95ADD5FED24575A4DDC
+            stream[256..319] = FBDC6515174B6E51F3A9804AA2C34DD6
+                               C03F0EB5202CC36D5602D58A2630390B
+                               C9D7A452680F152767F4558B3160BFBC
+                               EFD49175AB0FCF62D2FCB8E78E1CECA6
+            stream[448..511] = 774009D68AE972386F6F4D0467963670
+                               3E08B4CA05B801C5FC84376343B505F3
+                               37B9052F7280733BDCC026529F48BDA4
+                               765D1FB436CDB3DA0FB69F148894E8A9
+                  xor-digest = 41CCA3720EF5CE5F8EFABE447C3BEC9E
+                               DA338E5ED14ED24B21F66BC010077475
+                               16C61E91AC9E3501F2E8D9DE2E619ECD
+                               F995AFBA554A8AF21E89EAAD9FBE9913
+
+Set 3, vector#162:
+                         key = A2A3A4A5A6A7A8A9AAABACADAEAFB0B1
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0DB9C95EF6FA9E4F256789098C2F589E
+                               F5F2C63E8F38F81661A22842C4058E42
+                               D62675CF0F435C6441A905C46A5E2B55
+                               98D87AA7483D5036DBC6DA6F795B95F6
+            stream[192..255] = A195496ABF83B1EA9BAC8FD119F0514D
+                               5C01B2A262090DC52DD00AE0689DA3E7
+                               D9AD502FA2F3740EA254E8542296A3C9
+                               DD4D7ED40EBDAF2237157BB197887DCC
+            stream[256..319] = D5E1BC7E5C9B1F47FE69662C94D2C83A
+                               8B92217E877379F8BAB56CDBD5406CF8
+                               C18E1E2F223226EB9ED272BB66F7AD60
+                               ECEE3CA6C84A5E1BBA1DA733066C0D6F
+            stream[448..511] = C79F97FE9EEC3023430857F95A1541EC
+                               BEEA487C1C072F81736CF02AE97D1A77
+                               2C81A69FD2C58D85976DE47F09958BCD
+                               4382435A952C27B45EC6E387EB0A0333
+                  xor-digest = 65E3A3C2314794333A620A28C23D5EBE
+                               884D04CCEC9F7EC8892535B5E937C9F1
+                               D2B993451DC35047872F562C9ED5EBA8
+                               AD36B8B67325032A2C135495CF8A1683
+
+Set 3, vector#171:
+                         key = ABACADAEAFB0B1B2B3B4B5B6B7B8B9BA
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 505F4C9084D6F5C640C214EFED9E2DF0
+                               8EEF8241ACAE98072B5B3EDB72F1687D
+                               586B2569DC7F58DED2C2BCD134CB6CF3
+                               D80A7A879D7878C080A5BAD5ABA1DCCF
+            stream[192..255] = F38E694DB538EA115B3F765694B7F647
+                               BD16B1E50C927528B13FA2EB811E8E8A
+                               B7A56FCACD80B1E7861733E0F8289E5B
+                               3C461080A858FCAFC85748DC11CA007B
+            stream[256..319] = DEE9825C69B6F6210381ED04A152A029
+                               A7ABC8D6C23D2895B968142E3A9C4D16
+                               8059A067F309C2E9491426BD0953E4B5
+                               A6E545EE62D4E9363205FA50ADECE92E
+            stream[448..511] = E2C07AC69B0D646D013AB6129A979A80
+                               0977C0B2E3505CD4DB4CCB4C2D02A936
+                               DDE87099B8F69301CB8A441A1CE6EEB7
+                               9EB73A32F54D1B3AA1A5FAFAAEB0BFF5
+                  xor-digest = 58B7C17AF5B37A6806E8019BBC243F2F
+                               779B2961C0FF27B78EA54587FDA31F4D
+                               43AA70643AEB9BA547F814C57107B760
+                               8D3DD6B06C6CA5BC0FE55A31274B4B5B
+
+Set 3, vector#180:
+                         key = B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F43EB3DC7366C02A6EAA1BA286589786
+                               3A2221D8679C3F0399B2119FB09D2717
+                               8C262A1CAA0711E961209288EB03BC19
+                               FF9FF74773B10AC28295FF3BEF1E2B70
+            stream[192..255] = 453BA5A1529349A29B1CC75B9835E642
+                               9587A1E06F96A5E575BEDFC7CB6E6C79
+                               C7174D10F908C1688E9CDF6973971A89
+                               2764D7412F054D772BF3B97B194717B0
+            stream[256..319] = B2353310A194E71847B541FA5A301E56
+                               6678FF7148960C4C2EE2139A338EDC4F
+                               082A79EC59E094AE01E3D9585033350F
+                               7E7255838EA448658ACD1D1B56546188
+            stream[448..511] = 647B02009ED90BB30849D5136432AD33
+                               759097A5BB30DAA7D768FD7F7F5FFCE8
+                               513975CE19501ECD4E194A1C172F7A01
+                               E75BE6598CB0BBE4DEE6E1C364BF9C36
+                  xor-digest = 890A2D288B3BDE3AB9B9214DDFA6BB03
+                               390FDC8925358A0C99C44543C8EAF224
+                               64635D46AE1FCE0CA494A6BC7F127F23
+                               2B8EC742C518A73F6B2DE22F2F564749
+
+Set 3, vector#189:
+                         key = BDBEBFC0C1C2C3C4C5C6C7C8C9CACBCC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 17638771CE9C92633C8820B9FF9A7D20
+                               C0BB3ADE5D49E16EE463A6F768D0191F
+                               F624A8E1E36DBE1F35EDB6EBA4587DA0
+                               AD633F1E6CA8072A3871C580037F202C
+            stream[192..255] = 36358F7049F57244EEF847ECC80803B4
+                               A9EDB8B97CF098F87B047D02FAE2043A
+                               B4370B7C4E87777E049A79CA833A2F40
+                               DF221E8B34B710591A24937D19F39BDA
+            stream[256..319] = EC6A73C4A816CA1C3D1DC0B2A1AE5409
+                               AFEA32DD3B961BCE9F27FDF8B46E8300
+                               28C2C75C0596D1394E579BB4239FBAD7
+                               258C7BC7FB9E1C5465439177E454FA6E
+            stream[448..511] = 1A5ED8E740246F0744218C31668F081D
+                               333CB2C4416504584CA1AB6E7C56C82C
+                               AEACD22E01CCC23C1A9E8BE94AF90C7E
+                               DEEE590D8F75C9A1EB2134CC1A44AE0A
+                  xor-digest = 2D664EC9400F9864BFB1CECE43DF3971
+                               B8EEECEFE3507CE09F6572A9C9743EB8
+                               58B433A6FD2DF24605BB505B4D732050
+                               8C89F38BAD818FB3893383DE2C1ABE08
+
+Set 3, vector#198:
+                         key = C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = AECDF83CEAFC62A35AAE0B56DB5E6608
+                               3ED8144A470316E5768F898741181B39
+                               BE1B44248B79446A2B8551A7F71009F3
+                               4BA3799E8967A961169A2949979698BF
+            stream[192..255] = 1162529D235C48CBA87E0FAED1209825
+                               4F0C650835F5A0C44B01FC1AB0A53ACE
+                               496709D34D632E42A98CDA3A14E033AC
+                               F01E869A8263D0921619C26D3EC150EA
+            stream[256..319] = 30F569D183A30142A2C85002A7768DB1
+                               1B12025C41B0331458BE45DC53608B11
+                               63E130EC0D6940C2DA7BCB40881270F1
+                               1D79B941B6DBD4B53A093CDB9DC3BB08
+            stream[448..511] = 6170D203CCDDB9E93F3BBA8E195214E2
+                               485BCD5E96031B5848C433D2BAF4AD4E
+                               2050902F0E6F0D71D034909B58EF6E3A
+                               D8D72DFF40449A96F9DB8A2691FA02ED
+                  xor-digest = 8D8C29A1126A2C135938D456B61C1C22
+                               88F42EA3CC4AE32C2D9AF46A3393EA9D
+                               13719D95D2EE3F62D261807FBD4B504A
+                               A189EF6CEDF6DE1CBD0C9223DC485044
+
+Set 3, vector#207:
+                         key = CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 03FA3028E50F89A3A26FE0C9A59D4D8F
+                               CD4F6664621464876D0DD0070C3C4A4F
+                               BEA73FCF1858F583277C9A8AB098DBD2
+                               CE9DC0BD491A0069D48812B45D99BF6D
+            stream[192..255] = 4BFA1D3877F91E02E7B59C2BA54E80EE
+                               88FD0217E82EDB379B54F8AAD1B87308
+                               E908A3740DD0A6BED98D95A89579E18D
+                               B12960A3E8C2DCF39F84BFE48CD9D8EF
+            stream[256..319] = DF87530FE64F198DE0F5685C24E6F752
+                               776A64B5355FDCC7A734A195350A05EF
+                               A9BCBDC50D12A81CB89F49F330EB2796
+                               F3C0EC3A2AA823AB1787B4AE2E9F4B84
+            stream[448..511] = B62D2660AF636D037FF77CB2DA14EEED
+                               1DA4C10E4C34C3A170F00753256F021C
+                               6B8058A71680B8AC68F0E7B73D491E77
+                               21CB13DA097FBA6630DC814920993501
+                  xor-digest = BFCA05D3C5A76AF3016B56245C890022
+                               F173D207ABFA1355C4AC75CD44440227
+                               40BDF92FA07711FFFB49C3FE49F63375
+                               F242014728E308CE8261AB6971D82EBD
+
+Set 3, vector#216:
+                         key = D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3FF2373E4F64EA27FD8C86D971D6C497
+                               9AA558C47B291B686BA3EB4C848320B4
+                               C2614E739FC890F78FBAF82DDD01EFE8
+                               D93CF5A5068A0BCC4FE41F87B4FE82D7
+            stream[192..255] = 7BD47D4550A516BA255A572D948C143F
+                               8B46F2FDEE81E80D21E9A64A27A89FC6
+                               B00BF842251F5094326BA41055D83D75
+                               3A7A4DC88643BB8D8207CF4E6B5D6360
+            stream[256..319] = 9EC176E21634E97E52F5D8D42BEC590A
+                               5F4A6D0671BE640B7AC3C790AC521911
+                               3862151C7EE904BBA1B1254CA5FF8A72
+                               83EE9F0A3CBA3A0A38F3CBCECA7AC751
+            stream[448..511] = B87FC33D6F13852603A069DD88143790
+                               4922F8B3B98D383B7082257077DCDD01
+                               1B2B0390F6B680719D91B815A0421DBD
+                               5F3687097C63BD0AB1B59EBC12441A43
+                  xor-digest = 819FEAE72A30198453E6B7E0566459FA
+                               3A325C59B0B1BEC7B1311FEABEFAFD0A
+                               F7EA6A01603CD81DE8E338740573C01D
+                               94D57B04AC8F4D5CF26DDCFB7A9A85CA
+
+Set 3, vector#225:
+                         key = E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B378200C66DABE0FB33FFC336DB91F9F
+                               25F65CE152EC1D11738AE1DFA2B419AC
+                               31AA2F559A63CE39B8829E2E880437F5
+                               7D83E3680EB41CF262A6F8025EC8E733
+            stream[192..255] = 739C9F273A1A8312214B4B3FFD58615D
+                               AF751344F8D36BBD79A11BBA93BD0AA3
+                               34CA56667A6B4A98B6209F0765D9E4A5
+                               163756D6AC6861A8DE65777B9B5F4950
+            stream[256..319] = E7C1F35E0596EAAF7954E0C7F0423C54
+                               60E23A0106FEC3F1C4EBC571AE016BD4
+                               B232C2E0A8C079EA1A5DE6A2D18B1B79
+                               5E69ED4DE32AE2011805A439493223DC
+            stream[448..511] = 91D8B977B8BD9F8E84C097AB9454FFE7
+                               794908D3B1D98729036CF2DB77056F10
+                               582C1D1EB084EC97943117FA428C5B9A
+                               7ED1736E05BCBB55E9E0ED1FD0113860
+                  xor-digest = B05B91E712072C9FE4AE5C4BCFF3AAFC
+                               954380E58A9F264458EE46ACE1194032
+                               2B1CAAF21117E26A6B490A1C93761A49
+                               92982F4277E36ED3C4B74D31D3BB2ABA
+
+Set 3, vector#234:
+                         key = EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 77D958F664235976A8696CDBF0A3362C
+                               BCF3EA19D524F379B02D403F79F9A067
+                               BBE8F1365B0BCE68699E0A0DA273F117
+                               2EDA63B4558B062EF10743740825665C
+            stream[192..255] = 99B50E13CEA45209DB8FF0F3FFDB568C
+                               7EFDB1E021435065668313F23A57DD75
+                               0676F550EB7C5C5FDD65EBA84B00AA02
+                               E41039EBCB5AF806339054EC8E9C9567
+            stream[256..319] = 64CAF7DF8BDAA26D9BC8B49F99CAA94A
+                               0ABCD947E23AD676E3CFC95B4461CA78
+                               C17DF55D2ED805AF80B24BB57E3372A5
+                               4F7BD4B4A1A0F65581BF0D409198199F
+            stream[448..511] = 98595F685F9884606A085383B2437A8F
+                               8D8B7536D30C693B13FDE9F19DB847E5
+                               22B1C305A9BBDBB1F0D402A7794460E8
+                               DF5A4E719CDF48986C7E0B91A801742F
+                  xor-digest = 54D02F27FFB007DF1686027BFE0F4978
+                               01C265DAFA66F72EA530F37F82E8F25B
+                               35B6D7E2BBEB36F4DCB98C7526A727F1
+                               452296BB074B8BCFB878A5299E052B9B
+
+Set 3, vector#243:
+                         key = F3F4F5F6F7F8F9FAFBFCFDFEFF000102
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CCFFAD20ADF1C4B744BC6B2EC9CB29B9
+                               12F5577164F188BEAD1B8F5884619756
+                               350C6514969354F92C33DBEB3553E546
+                               D00B7321409CF15C2B1BF1D30E1B808E
+            stream[192..255] = 5D2AB87447F536F42DC3423A3F5E0C3D
+                               354B648D49A1D613E741FCA61E450D7F
+                               4777CB7F19557AFB0E3A49E8005255A3
+                               EF71C5389A5455AAD803CAA30C75E263
+            stream[256..319] = 53764B5DDEF40B7C66414E2855FB5D70
+                               BCE612CB71A7478D3C8D6B42918BB8E1
+                               4B12B5D48BF8C464B60214CE96E1CB2B
+                               6055A167B6BC4BEC2FE87B4C31441CAC
+            stream[448..511] = 2E4FCCA6545573B051885454D384B365
+                               546DE212F89E14DFF2B27A97FA3D5CD3
+                               BA797DAE4815E8E01629F4A95321E1B1
+                               ACAE5AFBB2E1FF74D0FA5A31E09A76BF
+                  xor-digest = 4DCE3E84B2FB36C6A268933805F307D3
+                               6B9F8B2ED75BDFA9528F14E96CDCD7EF
+                               77AD88BB08CD19BEA854C1F66216EB4F
+                               CF23FEC02A128FFBE7219244A72FF66C
+
+Set 3, vector#252:
+                         key = FCFDFEFF000102030405060708090A0B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 87E3FC12C86A001AD83DC4B364F49F3A
+                               331C286890826198B6D4937E6804F17E
+                               A9701A1AE8BD09185C1803649959AF65
+                               1726A25C54533924E6112F923056F09E
+            stream[192..255] = D6E5A2371EC564FD24213259599665D7
+                               9A31404C3493E005F611116C7F7B48FA
+                               CC6A949BB1746BC5EFE93D6114A1AD5D
+                               444A9A0391368106BEC2D5DAB96343D2
+            stream[256..319] = DBB63AE5E1B11D8A014CDECDE7B03DE9
+                               D59A473563285D52DBAD3E7E4C1E99BE
+                               C455E7CAE251B3AF52234CD9DE49BA55
+                               2B19E5A721C994EA57AFF2239B42C0F1
+            stream[448..511] = 339B85580D35BA903A85D2B45249FC31
+                               182D7E1B894DE9584906C2E210319EA1
+                               168E2E9C582CEBFCD96BEAD69E22CAD1
+                               E9C5AD2D5E3B708DC1F6B7E36F6E65EE
+                  xor-digest = B3DA36B9D7E12E6761A1C7F8533370F1
+                               E1D4C4EBA89ACFCE4F24FAC989A7BA87
+                               A1E0E61BD5A89895C04513D4813FE066
+                               6542738B77319BC7282D3209CE08CEF0
+
+Test vectors -- set 4
+=====================
+
+Set 4, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B1B7CB35C1FFBE7A34E645B05C98501F
+                               2364C719BD94186DCD66351EDEDB5179
+                               169D2EFD6BF03AE1B149DA229BE5C961
+                               37C10C3210F8FF34B51A366E437DE0F3
+        stream[65472..65535] = 5610AC7C3006ABADD3E0AB13B3D7E945
+                               586A00964AD6DF9939835FD46D8B2327
+                               15E447AA5D5CC4BAD03A495DC38BBF1A
+                               5C86A7D608D397694BCCCB029ACD1883
+        stream[65536..65599] = 1D7469F8EC3D021C5FB418A0D46A19C4
+                               A632A7C1BF298B500ACC2D5C39384F5E
+                               7837C964465FBF3990602BE3381FF556
+                               38114E41DC091B0AC1BC51FC6E70F98E
+      stream[131008..131071] = 5F1A8DD0D98D377C1378785F9EA7A3E4
+                               B17C9625EFE2650D845A4BAC7723B193
+                               A3AAC199A1950D7CB1D66380A566A8BE
+                               BBCEB0DD7A700C5ED74E55E29933FC6F
+                  xor-digest = 3E9A70E4A49AE98473313B957F781F09
+                               237A172CEFC9068D4F95CABB57358B7F
+                               40839FFF4258C8BEB466A975B4261753
+                               02BD1F4B9D4621436213703A3B99A719
+
+Set 4, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 54182309BD782DEE44FB59B0EC694920
+                               2B372AF8D715271A96D87867E65A067F
+                               A5E52B455B76D400537B5D47C4AC318E
+                               EE4C2ABE29F56107C213071C85828605
+        stream[65472..65535] = F7D1475B3FA625D86467D4C24915038C
+                               43D9B81A13E7A08B333B8232D7F849B3
+                               1442C014F49EC5814E15B607F11A73A9
+                               61C04D305B2F71B7B22DB9D6055B7371
+        stream[65536..65599] = CA286F0F05CD6C3BDDDE6108C8A0AECB
+                               F6ED3FE2A39A976D7970FD100A242464
+                               42D867162B87DF26EC2B04A990AA7305
+                               94C8072994E80B2D6426B90AD0873B61
+      stream[131008..131071] = B1FE56B55C9BB460B8EF4F9157B227DE
+                               AACACFAE9009C61C16754EDC913AE3D0
+                               BEB00C99095C48A12F4485E9AD56BE6A
+                               6F9C214ED11E94086F32F945C0C3F6EF
+                  xor-digest = 4667B465D4CD7E215B6594B648B05EE4
+                               7D2770A69F5FB3A49AD66C1C823F2E6A
+                               AAEAF0680A232F35EA7CAE919F477301
+                               0AE66193179E51600ED840D5047F5493
+
+Set 4, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 203C7A9050F5E4F98CB72D913B8E7FB9
+                               BB2635F8ECCDBFCD231B4EDCA96A24A9
+                               9F71BDD76CE42B982228ADCF9385C702
+                               C2A767488DF42D5DBD8DF2884225367B
+        stream[65472..65535] = 94E590E29B3A371E5638E55DA4AAA1D2
+                               F2369CF9EF69EAA0331B4AB01FC1D7E4
+                               D27A41EEF2C15C51256EA111933BB71B
+                               5E948DE575258966A03ADC426A3AE9E1
+        stream[65536..65599] = BCE13EAD9E39CCB67374B7D845B1B347
+                               DAF7C440162CEA622CCA3E34E9BFE35E
+                               10828358DB1F595C19A0A0CD16C127AC
+                               D49903A5159564038BDA4EF156F9D004
+      stream[131008..131071] = A4300187C3E146EC1C0F3568C147D668
+                               D00BAF2EF5E1F71686DC491745C6FC68
+                               27F54AFEF7B2DBF9F65D5FE549B96919
+                               4BDA10595556840647DD2A4BA22EAB63
+                  xor-digest = C575DB999E785911A2AEAEA074EA0CD9
+                               2BA978DA488A3657341572F1B33E8009
+                               07977C738874012CE18E487514FBBFFC
+                               A2E645EB4632862812B7596ABAF1ACE6
+
+Set 4, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 4A82E7937D7C52907515CDDDC1E8445F
+                               D0ECAD783B25079AEDF9D694CE70B723
+                               792E33F6FFFD438EECFD3DF933AB48CA
+                               7EFBB13A31C1E3E86249B8F9D188B7A3
+        stream[65472..65535] = FD302A0A44AE5D3BD5554C508BD70D8C
+                               A1803BE72ED426B8D57CC13F899A846E
+                               5A7A326AB25645EE27A84973BDDB82EC
+                               103AB97C16080C5FB117E10A8E252A4A
+        stream[65536..65599] = FAF43B81BC56F7E44BF5FD5F49581FC3
+                               51244ED84492382D28A591C022073350
+                               4F7B0267105D68566E9FCE5B52B7EC5F
+                               12A9131FACDC489279F8AA8E9E8E0A2A
+      stream[131008..131071] = 37C98A0BB719D5E166BF79AD35EBA109
+                               9560BFD07144560F4BB91C88B34C008D
+                               E7665BCA98D7B65562B57CED509684C2
+                               6AE9011D0A9D674F30E7F9DC37E680D1
+                  xor-digest = 7139AAF66BE2A8CF28852D9FEDDF47AE
+                               E1E229905F11F191AD60CDD2E1C9433F
+                               41F1D4BC92B10C8B988824C86B04100A
+                               EFF77A48980691C5636814E04F1A656E
+
+Test vectors -- set 5
+=====================
+
+Set 5, vector#  0:
+                         key = 00000000000000000000000000000000
+                          IV = 80000000000000000000000000000000
+               stream[0..63] = 337F8611C6ED615FC2E7D28C6DAAAF1B
+                               2382AE24592D1E61218220A3775F529A
+                               7F050B7D4262E3600940F167742FBE4C
+                               B0C147B3C0592523B890E76F59AFA3A8
+            stream[192..255] = 47B4B94D6032E42E28BA280B06863134
+                               0E65EF25AAE97BCFF5CA83096477B186
+                               352757FAF40E7DC007FAF51484B54651
+                               2B089A7BD3359258F3E8C0E3DE07C316
+            stream[256..319] = CAC4ED541686A3BA14A68CAE81C0B1D0
+                               D973129F8FD712F1E344CC7815614B23
+                               4412F351202D4FC7B622D905B8AC50D6
+                               59613FD8799443F89A8E403EB46F7492
+            stream[448..511] = 5C4ED1241AB7210EF543DC2732594AD5
+                               CC5A18AA3AB2CCB9B2BF17CAC28F6105
+                               1152291EB8674493A12C0B3CC2C7EE09
+                               F1A258C5E078080F5EA70F3F587BEC5A
+                  xor-digest = 4EF4B4DCF35FB72D210AE0546DD4A3FD
+                               9FE632736122E80559A32FC165E9166B
+                               59E2BB15A066307C88DD32611EC849E2
+                               A54DA4B47C5E52AC26375D2585EBE798
+
+Set 5, vector#  9:
+                         key = 00000000000000000000000000000000
+                          IV = 00400000000000000000000000000000
+               stream[0..63] = 982727CC7FECD8C15B09E6967B624366
+                               FC902BBFBF9C608B240626B735C6009B
+                               B6969A8D40EFD0546B056B181561034F
+                               B51A6D7C7BCB34447CF5CC560824BAA3
+            stream[192..255] = E8E61B734A6EC0DDCB4DF3248749B14B
+                               6CCCDADB8F24A090B7E5A49603C475AE
+                               8B6F8353E12FE7D8CB3EDA81E6DE9778
+                               2C52BDA59FCF4CFB2BBAB2D196E08C85
+            stream[256..319] = 06594AA97EDE3ABCD9458DEF29A7FEEE
+                               91965BACFA6A272B31BB644596DC5C66
+                               8F93AAF38F1EFA50D88A9517DFB4B409
+                               9E91F5A1B07C9CA8F36330840A6FCF76
+            stream[448..511] = 32784F6FB85DB3ECA696DD98D75A5031
+                               B3ACD087ABEB6489F20429EBBADF8D87
+                               B0D7C4D54A8A80FA835B5FCDB901CF32
+                               E60269C5DE89409A61ABAAB00B7D8B79
+                  xor-digest = D696A18B23B0927FCA5B766F8C19CE2D
+                               C98F40963485D0A77D92D0096334B9F3
+                               834491F8FB7C5D8BEC499F28A37B7DB3
+                               8E8A6291C1A6F73938B7AF2B74425996
+
+Set 5, vector# 18:
+                         key = 00000000000000000000000000000000
+                          IV = 00002000000000000000000000000000
+               stream[0..63] = B3EC726B0BD04F969BB34A0DFB1AF9A0
+                               880ED66663BC845BEC2CEA9BDDCB0E3C
+                               E6FD6CFE389D544D863AD6B55F45F4BB
+                               14BA866A72D63E4FA83246498EF685FE
+            stream[192..255] = 549E7B93702F139AA76FFF7CBB04EAD4
+                               C091015E6455A9855E3EBE4AB1A80737
+                               9E3E9C9418B909CC26E53470CD323FCD
+                               ECE6BAF53D45BA80C4F03A412FF160C6
+            stream[256..319] = 9599223B02F81DF5D31CE7FC6FD92D70
+                               71ADB8985B61709E6769EF5065905E46
+                               B0AE83DEF7EAEEF01A49D5D855035AF8
+                               6AC78AF9C14A3F8409773252EAC28D4D
+            stream[448..511] = 2C58AF08679A8AE28AF30688B33C417A
+                               392A6E8D6658D262EE24B479CBC4BA4A
+                               C5DCA537CCE7B110489817F9D2858D95
+                               E006D338BA92D7FD664F9CC773AB67D3
+                  xor-digest = E52013C82C2088C5B76988031F0A0930
+                               6322244F357700E3D3BDC71A2385B4BA
+                               F6894A2B177F7BA78D5935521CDB5689
+                               31F7706AE3413B10128CB903D7E27160
+
+Set 5, vector# 27:
+                         key = 00000000000000000000000000000000
+                          IV = 00000010000000000000000000000000
+               stream[0..63] = 6727DB24106CABD6C3A14001BC9E3B5F
+                               90A47B78181576CF5398D8F190CEFC10
+                               6615BDE30159225DD3E14A2F827DA07D
+                               C230D11AFEE96855EE06FB02D23998D9
+            stream[192..255] = 7B9AD4C2472D5816B963BC168F725083
+                               0E900C4E4994711DF7FA494A04A7CB58
+                               C9CAD5513E8C554B47060D9256B4F276
+                               2CD9790666A3C831FE1A9250C2C1F1B2
+            stream[256..319] = F8B0EF0C84EC8375A17C8C36B9F75690
+                               30D6D04687514709215F79B102304807
+                               3FA3F284155CD677B30FEDE6EE33DA7E
+                               5B35636C0F8E981AACF01CFA4E7B00C8
+            stream[448..511] = 023E93B9B5A526DA400CA8A818E506A9
+                               F5B0438F91264727C4FD5CA2FD4A845F
+                               3F2A6E0617A5619CCB0B691C2AE2F459
+                               A7F4764CFEBB22D8FC6AE8E28B08DD4E
+                  xor-digest = A6BB0A1FA9D79299B2FCD3AB9DFE04C7
+                               9BD7B88BB1A49AA7227E9BBD0A211677
+                               283EE5CF808DB24D05227305E67915E8
+                               74CB03402736AC8FFCD746B5AA4DD032
+
+Set 5, vector# 36:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000080000000000000000000000
+               stream[0..63] = 4BBA6A59AD3C1A7298CB38F244AEB7AB
+                               431AC1FEC2D091C4952794AAE9DA762B
+                               0873BEBD04FE1CD68D08654F1DFDD956
+                               59EF5E09238984D834F2631D67E16EB1
+            stream[192..255] = 945C61BFC21691064FDA05A6162869E6
+                               82800A1DB8E19818C2AB13A9280C8CCD
+                               BF9508894CCDE69ABC8A3F0CB2BA545D
+                               3A6D6E7D6E8B5E53683DC3E0018BE954
+            stream[256..319] = CD87390C68404079BCE794A554FC4DE9
+                               695AA78E626CF79094CF0374765C1ADF
+                               8C4054AD4B76535008F8466C806D1775
+                               1987361A852DB77F2CDDDDB34D00A15B
+            stream[448..511] = 319081F4D93C649E6D1D8C4999E0A03C
+                               F4AB23E4EB796B337C84898D6D9F083E
+                               70038515611FA040E686B893D89E28DB
+                               862C6D36F791F27EE05ED97AC636E836
+                  xor-digest = 1B86F56D5C6DDA97E2909873A042A48A
+                               C3C102D22F88E8648C0A7DAB5C34C98F
+                               CDF03CD03B6106095E3BA34969B67886
+                               8AB4D93CF24042F52DB659591D72D0C7
+
+Set 5, vector# 45:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000400000000000000000000
+               stream[0..63] = 2DD3C3CF5E6965EA02C31ED6FC539EEC
+                               E0B8D48345113E978230ACFE35089F9C
+                               D8EC821843DBC90E54010C16A8AEB245
+                               5881FC16B5CC21032958DAD18EF55469
+            stream[192..255] = B9299DC95D2F192F1C53FF23432158DC
+                               2746F64242CF9368D90FA217289BF31E
+                               6F08692251CCF86B2DEB7ADDD14D8E37
+                               0E4D877637A2D499924146D89CB77F44
+            stream[256..319] = A6F9EDFBA2E22CEF8E14BFE5B31ECD14
+                               4114A045BAAF0458BF149F073DF191E7
+                               022A9E518212876F7D6C99F1DDFACCD7
+                               8E0DE69FD43FFD26EBB7E240B5F4B864
+            stream[448..511] = AD29FD814401DB358AC8B2A911E743A7
+                               A594C9781D4F6560E29D8B67AB38D8E1
+                               67AC71AA3855D5BE67998E0B797A64BB
+                               1B26558FD861B845E9B08FA071DDCD75
+                  xor-digest = 2DE49729E28C8B4585BAFB291E77B7FA
+                               6CA9E489C437133EABC613D0893822FD
+                               70A8F88BF6A3D29BA6503F17F055A003
+                               A42605780A79501BB62C35C922DFB1C5
+
+Set 5, vector# 54:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000002000000000000000000
+               stream[0..63] = 8D3CF6CD521B43CF76A6ACA2A036B791
+                               7E06F44E8DE525306C6508C1FE2E3C29
+                               50A53F63B11B57596B76E97C1EB01612
+                               3D33B57CF93E839A169AC49207BB42A2
+            stream[192..255] = C009E0DECD6948B8F29A72F1A2BCAAFF
+                               04043B6B76B623CF977679D74186BB4A
+                               B1C3529D94A5DD5CCDC20AAEC056492E
+                               7B9F9A9EE087187C52C7651F890A0DBA
+            stream[256..319] = DF5DAAFC6D650B0A47AFDD7BEF56634D
+                               13AC2D1442AA1F082715882F9D303170
+                               8D338A7CFB14B100E3D3C645334C5D4C
+                               BA9534475D4BA687956B00E8EAB587AA
+            stream[448..511] = FB2CB04310DC73C7B7312C840123FB0A
+                               783F10FB63F507EEBB012E19A0FBEA30
+                               C324904C02E301F4CE2CC2A1198C0C14
+                               A725FAB705C5176CF19EB2184DF9825A
+                  xor-digest = 3B3136B100FF460D92A0FDEFE864662B
+                               324D7B8C7C3DAA46EBF02F8BD0960345
+                               A1FA8F9B7AB8DF16BC7FDF6B6AA0C61F
+                               FB1C7A599A6474A916A8BB9E4FAB9856
+
+Set 5, vector# 63:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000010000000000000000
+               stream[0..63] = CF1667BC6BF8ECCC72ED756D4623E979
+                               6A8E559E27ECE3DE4FD85DAA60757C33
+                               0C33EE95AFEE6A53D730671F695C0B04
+                               B5968DC2501F48D9A2DB7E20CCEEF297
+            stream[192..255] = BE8163A51FB1FD786E1E5197B5F3FA74
+                               900AE8111592D24733B562187D399B95
+                               79D5F751D722784832AA471C4445FA5E
+                               F2725E23A251EDAE66D60203CB862095
+            stream[256..319] = 8592AA7309D37B63AC539BE5B997AD26
+                               3F6C38DD169535E7BFB1C19965919F55
+                               F4502C5995FF7DEF3021D07A37B9E7C0
+                               FA5E8AD9AECF2B072EE1DE2F2E26DB1A
+            stream[448..511] = F05E64D5CF14CF99154EF83E27CFA2F9
+                               2B269E8E164F1B563F4AFC48C40B5FF8
+                               F40BFC7E59EF0F0B923F7474F30AC114
+                               95EBE3EE8630A214776286D01A20DA23
+                  xor-digest = 46136E7DE5C7186F1F3D04FAA100B991
+                               8FE7E8E02B36C72A92E5650F93F5D936
+                               5675B0D3BD84E5C3E7F5CA7E70ED55FD
+                               027C83E1CB1AF8BDBD1FF1905A6EB596
+
+Set 5, vector# 72:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000080000000000000
+               stream[0..63] = 583E7BA16D617DAD9F2A4A6A7BCB630E
+                               4248E8368A6F45F6BE8CF22C65964D34
+                               49A7AC0EDE8957127CDCCD3AFD666426
+                               B8BD2391698525CD3620558076F61EC5
+            stream[192..255] = 8CE8D0EAF9944E68D7EEA0F83ED86CBF
+                               F87B99C8D87C40FBDA48E777976FB669
+                               CF6A68533BA7875DAD0BCDEEDBD4D136
+                               DCA8A9C9C1C6B30C5CB7B7C5846755BE
+            stream[256..319] = 534AD0B12F8CD7797CAC9E23B1618AA1
+                               B707F28D000422CA73196498C86D51FD
+                               A63DFC791446094F4E146EA451F60B3B
+                               C2711F81B137FF4C0521F94447A486E7
+            stream[448..511] = 540F0CF1CAA5D5CA270FB71BE97FCF9F
+                               F1F30C2F454BA29561F7B7C2D8ABF189
+                               30D107F71560B26CB7E9E416F90604E8
+                               510D29FC0AAFD94EEF254F0F4C0C43C8
+                  xor-digest = 0986B6D195197767683FB8221A50BCA4
+                               A375BC5989C24422855F465CE537FDB3
+                               3894E7383CE580D8204694DD1E82D623
+                               774AD356957E36042735848BBA9649A8
+
+Set 5, vector# 81:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000400000000000
+               stream[0..63] = FF9484C54337D0F0CB2342A7E73B21E8
+                               BA933A679CAA5549AE6218B7E0FCC88F
+                               CEB6CF2158E19C1D30F4E0B0A2D5E052
+                               E4C73F2F2FF423417E67F49F45BEA7C2
+            stream[192..255] = 6AA4E5586B608D3F0E4A394AC7818949
+                               E538604293010925AB3D69AFCD1979C8
+                               A8289CC46776E762452246B54C6C7D3F
+                               E7BA43B8D901D2B55F2F7CE520DF99DB
+            stream[256..319] = AF841581E66BCB36AEEE07534A83B519
+                               60D0DE9740D320D1ED3C542B64FB122F
+                               506B6F573F40AF29A61DC42FE183EEB3
+                               A5D55D0272659028B9B5B353A6292105
+            stream[448..511] = 3E463ED75242C21811F9C2492A71D6B3
+                               E5B2BE3E50151A990F841EF0350259B6
+                               9C727194154288C62DF02075AEEB2598
+                               577A5C0B134EC1206F66AA96233D1BF0
+                  xor-digest = 0C45BDB39F8C038AC8E2E3C41A80FBF7
+                               7B74C948861E7D58F7A89ACCCB4A2D04
+                               7D370BD42B65DE42293C58BDFBC003EE
+                               58D71CA3D01313E8A74C7BEF66CAAC76
+
+Set 5, vector# 90:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000002000000000
+               stream[0..63] = 8C4921B72A3D11BE4DF4E326B9BF85C7
+                               351CF85FE98039D5BFDB889DC5721B17
+                               C02EFE07FACD2F43E95D6EC63F4001EC
+                               FE7355EB565B6E2CEAC64A995324DABC
+            stream[192..255] = 933FFDF78D118A083FB7CE405D042D3F
+                               9173B28879BF4A37A878EF2351622F42
+                               80D218DE417B8503954E991A31BDF73E
+                               B26903D1F7C7361F34D7F01656243B58
+            stream[256..319] = 88E77D9A5FA78C7E348DFE0A66AF1B92
+                               FF564670DCEC867E24AC78CAC005DAF1
+                               5953DEAEAF2C476C2DA514CF79A474DC
+                               D4E68AAA0D52394762953A8A63A0B3A1
+            stream[448..511] = 5FF4F24F6BC7585D16582944166C453D
+                               59A3CA9F9625A5946EE81F561CA183F4
+                               F6D5258F138E994DF848F532F613092E
+                               89FD262FA4899091596A1031913C6C5E
+                  xor-digest = 4770E4B7DB5C5FF7F64BAB6334A13E4F
+                               9DA6686EB2945463852513C770ED64DA
+                               4A0C3D96403F4CD1E96B7FA6495BE23E
+                               15506374CE556E7B50D3ED8A92A643E6
+
+Set 5, vector# 99:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000010000000
+               stream[0..63] = A59AA0661087A6F3498D18BA156FD4EC
+                               E5709F5CF1FF25B006382B250E4481FD
+                               050F68B95D56E1EAF77C619914F30269
+                               4FC8C2461200D9AD357F21E9DA08F489
+            stream[192..255] = 941E849E313B8E214DD6CD1C10FD8D18
+                               05C1892B15623CE0724A3028F978215F
+                               7B6264D4D5CBBEFE12920BCCFD204134
+                               1AF60D460B73D9493BA2AE7B314CAA41
+            stream[256..319] = 2F27FA6FC61D2D84C008DE836B0CDB1A
+                               EB0E62D5E327F88B8A62BFBE70789189
+                               9E1335D20E495D2181253647B0333CA6
+                               6833552B89571E3BC25190C791341940
+            stream[448..511] = 9DACDBDBC8258B52C41788ABA3A7D08E
+                               5D7919C0B583F6AE89036A4EBFFB3AC9
+                               7CD9E9B15E8C811EB6F2BDC7713115A4
+                               5291C4BCA5DE179ECC779093B30870A0
+                  xor-digest = 2C7C5D79F8BC2D8E7B62DCE74340120A
+                               EAEFEA33114403A970F1A51AD9EC9F9F
+                               63F630E74DD83AE5C6824089982685E4
+                               28FF20C49689DAA995D7AF2E80502425
+
+Set 5, vector#108:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000080000
+               stream[0..63] = 869923A0917A8FBD8F45FF074E83FA79
+                               D665A9A44C769CC200A66C254B2D4B98
+                               7D34D66E52EF7A9C7ABFDD7548F08631
+                               49C7CE742F6CA599ECD0BFEB55CC8B6A
+            stream[192..255] = 75386882B941CDA70FDB6D02F165B3C3
+                               B0C7B0A8E4ECB161BBC745EA1AFBF382
+                               C0C09725D0DAE6316C7B956577EE7F97
+                               C4A102B04437F24D2090FDB00B78523F
+            stream[256..319] = 04FBECD2FDE606BC32E46FD0B9950F93
+                               A742DC2534886A3B17C8EEC5CDD28B04
+                               5A03E7C5764EC92C1DC8AAC5F9D5483E
+                               A9890C7322739BC7C73CF8158619F669
+            stream[448..511] = FC322AC5E5635C8DC56895BAFD43A01D
+                               77807CC8CE57DAA306E7DDCC58B24309
+                               4497AFBA51F8EA62922C697FC2EE8945
+                               4926D4975219A40B2D6C9A9620634741
+                  xor-digest = D2E239BDF9A2E04082567893D06DCFB0
+                               4FE50753793F21380F6A91354836C508
+                               837A15527F914190F6F97BA87510180D
+                               67B13994803013B2E4D4A307D80E8EC0
+
+Set 5, vector#117:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000400
+               stream[0..63] = F350AB2F8E1B96AC93F1FAAED04BFB0A
+                               59EC1F7B95383E44878AFFBC5CA7D4AF
+                               2EE76CEFB67906469C9FAA59F4DDD24E
+                               D16796DCAE66011584E8A4B139E016ED
+            stream[192..255] = 48D1D8F4583937C77BDC1757C3DFF07F
+                               D0CD430F3667E37A6D4CE89217729AA5
+                               E480DEF30227A363C800A3153617B04B
+                               50322B06B795B0EEEA039A796C7B6664
+            stream[256..319] = 4DE5C06008FBF0D54EE2E2052AF4EFB1
+                               94AEE33EE7F133F225CDCF2C504AD2AE
+                               AFBB2A2AC50D7F27022DA8D83D6B44F8
+                               4545E8BD15E33CE531C3A7E076B39BED
+            stream[448..511] = 837C91FB8773A4DE4FE79D163FFBD186
+                               2A361B96D79AADDE5AE964A62B3D9CCD
+                               1DDF29D845EB581C33E3ECF1CAC4AE15
+                               3C75E0C5ABAA960389FF0C92205CF575
+                  xor-digest = 29B708C591EA72969C5EAF624B943D55
+                               3A55CD66F13E5E762D6808F5A58D77E8
+                               8CE91C0A7EABDEE8F30C05F4D48C0257
+                               9B38612376DB9E26AE70591760E395AB
+
+Set 5, vector#126:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000002
+               stream[0..63] = 073CD91D0183F07259608257E8267FA7
+                               8799B748A5FEDA25FD40B463F15639E4
+                               CBA06A504C5D4E80A542366DDFDA8EEE
+                               B21BE97CC2FFDFD5FC93792A7CF1C2F7
+            stream[192..255] = D310A845416E7E187D3404B763B46BFA
+                               7EB62B04A06DFD0AC6E9871EB8D74F32
+                               73D7488C8D2197515DBF84ED8EBD3F24
+                               A4B3B69DABB27A3CDA6DEECF2F58EEB7
+            stream[256..319] = A8058C140D6692480614EAEE7AD97DA5
+                               F4423B249C2F0413DF35530CDC40417D
+                               FA6D5007FB9488A073F0631AEC501E15
+                               A94EEF50A2744693EDF07273C5621056
+            stream[448..511] = 44220A7B36E147C5C3F41FD72FD88F50
+                               ECCC2364563085D3409C5508DEE719CE
+                               327EBEEF70917036C37A534B764A4DBB
+                               39B77EDE8C115448096C7E2BF2EC6720
+                  xor-digest = 07C9AF7BD2DBDE982D011798BCF014FE
+                               F9334DAF537AF14589BF2328C45D327A
+                               755F902A389BE04970AF515D5718C891
+                               A77AA50A46D1DD737489E298182BA245
+
+Test vectors -- set 6
+=====================
+
+Set 6, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                          IV = 0D74DB42A91077DE45AC137AE148AF16
+               stream[0..63] = 2E1ED12A8551C05AF41FF39D8F9DF933
+                               122B5235D48FC2A6F20037E69BDBBCE8
+                               05782EFC16C455A4B3FF06142317535E
+                               F876104C32445138CB26EBC2F88A684C
+        stream[65472..65535] = 1D92C4EBF6A256F0D0B0365160D72E90
+                               CA10D7086C58BE13E9325A5088F447D1
+                               572466248CD275A736B83674739899CA
+                               3146963E00E170C6B9DC8B2BE912A5C2
+        stream[65536..65599] = 878A21CA440BA0D659F24A5C986D6CF0
+                               3EA0DD962337935BA0932FAD9599EF61
+                               D805800038AFE4208394C73AA044262C
+                               18490F742A2B7424ED56EF3D1B0F53AF
+      stream[131008..131071] = 99387AFF42EE8C9D4D8400808322114C
+                               F4DF77CDAA363B0E4AFD0D8FF17D3D2C
+                               3303984867021922368A76F7CBD20266
+                               5A962140C8E6C1336CC4071B38ABB957
+                  xor-digest = 0FF8DA8AE74C2F194FE35FEA66F69380
+                               BF1D368CC0282F6E570477EB426F1858
+                               204DD9752E48E32C1F40A2ED3BE10FF6
+                               B5C80216884D0357AFA002E01B7B5FE8
+
+Set 6, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                          IV = 167DE44BB21980E74EB51C83EA51B81F
+               stream[0..63] = 4F864BF3C96D0363B1903F0739189138
+                               F6ED2BC0AF583FEEA0CEA66BA7E06E63
+                               FB28BF8B3CA0031D24ABB511C57DD17B
+                               FC2861C32400072CB680DF2E58A5CECC
+        stream[65472..65535] = A27D9CFEEBB098C44E94F477A5AA9FB6
+                               286339533CF62E2781B574B9CCC53619
+                               CA27303E83FF9D986EFDB5D0AECC93C2
+                               F249325A37779D894549C0408B6A47E1
+        stream[65536..65599] = 36893EF2C9173CABEA2B5BB027938EA6
+                               0004121DDD27E79DB469B6402B4C23AB
+                               C08066B24EF0242234F9439019DADF4D
+                               000A8B68FD539F2B6C8087AAF89C76C6
+      stream[131008..131071] = 8FD0EB93722FCD5093AD826167F0F158
+                               E2A7B86751E85D796D5269866FD317B9
+                               523032CBB52F6978DC7E0933A2312E40
+                               57E0C9B1366C98941867D2EB0CD8CAF9
+                  xor-digest = 63DCDFC74EE1C446705C01CF185C7F23
+                               E083DDD7A70E2685DC1E051F2AAC63EC
+                               7E64399369B7D1CE49A732F594B6A587
+                               3B89E848F70A3AA9B04D219BAF14807F
+
+Set 6, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                          IV = 1F86ED54BB2289F057BE258CF35AC128
+               stream[0..63] = 82168AB0023B79AAF1E6B4D823855E14
+                               A7084378036A951B1CFEF35173875ED8
+                               6CB66AB8410491A08582BE40080C3102
+                               193BA567F9E95D096C3CC60927DD7901
+        stream[65472..65535] = 2A30BFDE279B750D56B0B10A79BDA0DB
+                               21C246D133F4B91E4ECAF80DA7AAC425
+                               646523F6BB762D688BFE2DB1852B77E7
+                               733BC1005CF3D7CFAEC4BD966DCA6773
+        stream[65536..65599] = 991EC57DE1BDFFE2C70A0196A8902C91
+                               D3CE6C63E4B8D81C83AABE7BF370D1B5
+                               4D0B72B0C3C857621A7BBE2B72EBD81F
+                               50B25E08A9D492AFDDD37B983E9E2E4A
+      stream[131008..131071] = BC301B9FD7C554C592EFD092A435C2C6
+                               E74CBBF905CE424FE5872EEFE8DC62BF
+                               F93C3917BD37D142CFCA623B84C2652E
+                               0E61BB5C5D5387AD95EBA7A5ADF16F81
+                  xor-digest = F8F5AA473428C00F7F71E4D1BF1976DC
+                               2856619D2E1CD79BDE2FA1FCE880E816
+                               09B8D5AC28691FB90718E0981C3BB2BF
+                               A7E5888E44A0FEDAE7D481AA3AA684AA
+
+Set 6, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                          IV = 288FF65DC42B92F960C72E95FC63CA31
+               stream[0..63] = 1CD8AEDDFE52E217E835D0B7E84E2922
+                               D04B1ADBCA53C4522B1AA604C42856A9
+                               0AF83E2614BCE65C0AECABDD8975B557
+                               00D6A26D52FFF0888DA38F1DE20B77B7
+        stream[65472..65535] = BB599F93F4F244D717CA9818212B06D5
+                               6D99AD4CA1F78725DBA89EA1D1F05B27
+                               093A17D745396D8CFD0256CD50674046
+                               13108E2200A8F1C49075B376A7460515
+        stream[65536..65599] = 996C074A7C7C524F539037A8A9F3D193
+                               3BC311B548BD567F8AE1B4325C51C5F3
+                               4B0DE1B4A4651829108CA92AE23D57C7
+                               0EAFA766097DB0539BE77E6500703746
+      stream[131008..131071] = 43EF1ADFE8265C46FF7FBA43B78F899F
+                               22C3B9F069B786982145D601627CDC49
+                               2D27BB8D70FF6DA908F2606A0C44690C
+                               8502F9CFB3BD6CBFC9205470E3ABA387
+                  xor-digest = B097BF56D79F1A343F61F7B66AC405AA
+                               6242493ECECBA06876276B36ABDDBFC3
+                               76D8C370503A8B8FF6D121D2FFC4959C
+                               6A96721616782688FFCBC748C9A168A1
+
+
+
+End of test vectors
diff --git a/crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_128IV.txt b/crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_128IV.txt
new file mode 100644
index 000000000..6460df61f
--- /dev/null
+++ b/crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_128IV.txt
@@ -0,0 +1,2337 @@
+********************************************************************************
+*                          ECRYPT Stream Cipher Project                        *
+********************************************************************************
+
+Primitive Name: HC-256
+======================
+Profile: S3___
+Key size: 128 bits
+IV size: 128 bits
+
+Test vectors -- set 1
+=====================
+
+(stream is generated by encrypting 512 zero bytes)
+
+Set 1, vector#  0:
+                         key = 80000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F1B055D7BF34DE7E524D23B5556B743A
+                               EAF06AE9076FD2F48389039C4B24C38D
+                               DFC3AC63A148755FB3CF0CB8FB1EDEEA
+                               63CD484036FFAC3F5F99FC7A10335060
+            stream[192..255] = 2541F0EDA5633B4F47C6B74CDCC612AE
+                               CD27E46B2C8FC9036A09C6FFB5891168
+                               7A8FAEDC225E34C45B6E081EF5279FE7
+                               3271CED417549740EAEC6616C2B6A57F
+            stream[256..319] = 0C8C0567803E2537804BFA15742D3E08
+                               A29985688DF3D6B4C3044464C1D1F2CD
+                               4CBBC470C9A0FB05665CDED63C58E466
+                               896F80ACC020F134CB622487D40E0AF8
+            stream[448..511] = 1FD448C788A21BD30D4B6BC5D8AEF296
+                               2772940557B9434E0FAF636D576B0737
+                               1FF3AC12884BB431F396CF7C189D9AAE
+                               D42797128CE645FE841A4CAABA429324
+                  xor-digest = A3F66A36C20A496A0D4D537B6106662A
+                               DEB5AE1E35FD1486EAB6039F443E5D8A
+                               C6A2D4A2C2E2A9F335E2E468AD8BA51E
+                               550E41533332E6929EC18CE35BBF741A
+
+Set 1, vector#  9:
+                         key = 00400000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 9244D2B190FE8C4BD0E17247C4F1D282
+                               3FECA8DBE546637E34BCA99236D09F79
+                               5A8905A1E0FA94E6C51F7DC0C90FFAE1
+                               A8EBD4C99CC96FB3252DE0A0FB03F971
+            stream[192..255] = BC0ADD787A5EA52E28B45192399DDDE5
+                               CEC4E283181408E554FC714586FB641E
+                               B36F3727358BDD8223B5ADC9B9EF1044
+                               0F7CD97FCF2ABA75AA9972B277CD6656
+            stream[256..319] = C9F6315DA3CBAE23D32685C5549274E6
+                               9C17FB2E46746C5D3260FF2E00FB234A
+                               A460776CB0E7AC3AF0D297825C1796AC
+                               0B689DB219443BF4C0D4D19CD70A49E5
+            stream[448..511] = FBFDF6D40BF2DA0EBB04D52C117E9EBD
+                               6FEF88D39B8EF8B31082EE9B19D50219
+                               183DC962391FA4F602A2510BB476EF4A
+                               A44439F61D589933A1F3F633C96E56FA
+                  xor-digest = 49B435E6FA51A0AF8DC94CF1DE09F8D9
+                               AD76E08C061B54CCD62EF98ABE85969F
+                               3FC41DB934AF9DBC5F32748623639D3E
+                               B15124F13DA8B008CA5016ED61917563
+
+Set 1, vector# 18:
+                         key = 00002000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 9D74BE686C2DE8B207E8D82E49236A3D
+                               E86F5A7EE231B4239080FC9A55FA44ED
+                               7737FA7472B318A4F36FB788E863247F
+                               7067C20DCA632FF051789E9EB99CF409
+            stream[192..255] = 4876774DBB886B72E54EE8160D8BA8DF
+                               6DB032B2A9BA0B79CF82426CEADE421F
+                               EF5ABE9976E909DBADA0442FFC7BBA2B
+                               009F7240941F0C209853A514B0BE9062
+            stream[256..319] = F2499CCE5D3268F4C5515C365D2F4411
+                               B0AA99ED01E7D5328BF0672584AC65CB
+                               E47BCA14C3EB1F838ABDB7C611677BC3
+                               7382E84D05848B9838A166A42E96B016
+            stream[448..511] = C855EF5D1CC991D2DDC892AD8319E39B
+                               734E43E443F5910D03BB79CCEBE70569
+                               F92BBC63363943BEF88BFA5809B3759E
+                               6BA4ECA1FAAC572228458A229DD5BA06
+                  xor-digest = F125B88E0B5F143B836AFD7AC822E027
+                               FF44B736E32627D90FA05F3DB98576E1
+                               9EC41AAF9D61ADE2BF00E38CA4EC2A54
+                               49EE0655FEAE777D67EE127E8A5F8CD8
+
+Set 1, vector# 27:
+                         key = 00000010000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CC447BF1B5D138025BEA2B269E625C4A
+                               D4451F3851F04F118499040C6E564E38
+                               5C5FE17FA7AFAE9FA559CA4835AC1F40
+                               1C045AD439B400BB41984DFE7E4D4CC4
+            stream[192..255] = EEC14B65E027BC2A96E566BB89218A89
+                               31C4AE0BA5C444929EF852EF7E400AC5
+                               D8B3CFC62DEBBC2B20A7B32E350E3839
+                               2953B7839AACC06B2018280770F84B65
+            stream[256..319] = 8870B4F9A62B37A1929973D3975D7ED0
+                               505AA43002B14B55A541EAE00148651A
+                               111D6E5A1581F85FFBC2304783EBF5AC
+                               E924CD8111056B1069F13100DE15EB13
+            stream[448..511] = 1513F3B7A2458674CBA2B566F3AD6169
+                               2BA4EE30687A07AF2FD0D340D92384F5
+                               F5BFD9B8DF2F7098A209C280F6D5AEFF
+                               BC07D167720DB47B4B649C8593E6F40C
+                  xor-digest = FB5EE30BAE44FDFDF105796FB8A66F69
+                               64D502230C191FF9AAF5A4447533D02F
+                               05A3772B99F9FA2A075DBB8BA59D8D5F
+                               F819784D487C305280DF2F19EEA8BD47
+
+Set 1, vector# 36:
+                         key = 00000000080000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 831F1DAB278C6226785209C0AD34759B
+                               9F205B7BC6B987DD145B949336A8FA0E
+                               4550BC1737DAE7DD7D12E2C062BF9693
+                               F08C2FB808A1F0A5887A06B93D132BBC
+            stream[192..255] = 76631E9D4A673D09B9769251433D5EFF
+                               3114AA59E1A9B7E21B4123DE3E34FBF8
+                               4ED6E80EC29B4F75B53A63902C373EB3
+                               D644B8823789743CA407FFEBA4A1AA75
+            stream[256..319] = ABD84B2A5479CDBC5587FB9EEC5DC661
+                               5A3CC6136314F67AD2C96803E8E4BE92
+                               E33DC35F0DBF3C401AA5D7A9F46E54CA
+                               A7ECD68E561BC08E6A5B847A82777E4B
+            stream[448..511] = 9ED1D44510201727B2E92B55DBE06BA1
+                               46762AB34937364B2157292CE68B9D78
+                               3D3C3FFD1FDCA836E4C4FEC750B10668
+                               600C26AC05B4DED64F8CC2EAA0D22052
+                  xor-digest = 843D7B97B3316595111DCBDE3DC13DA4
+                               C14402936D68035CDAF9A1C168120B34
+                               0EBA1FC47E957C5F69F369B4C2ADC4AE
+                               37E743226D72A9F122EC8E00BCAAA126
+
+Set 1, vector# 45:
+                         key = 00000000000400000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = D2D629E84843638274ACB79FA257DD9C
+                               D48A08B823DC9F175CD92C5236B9D230
+                               5931FDEC5A8F531B1ADF30DE0527AD2D
+                               0D2B253D008913558E0FECCA7D7BEA4F
+            stream[192..255] = 6F9322E84D69CFD6A1E589283CD028D1
+                               E2A114B719FB2E18E732B97629313772
+                               CD2F2F8AF77EDB5B4360E4B679441346
+                               03C59E88C042713C3E403E5D93F9BBC2
+            stream[256..319] = EE7BED6C85B20E0A39C103D0B6949F4F
+                               5F6FE0DF2BCE315CCCEF6E537C488525
+                               BFC27FD249A6D36548C558153661861A
+                               78422A563166BBD0D72D6D7876FB4DB4
+            stream[448..511] = D2CFFCD4185EB1D8E15B629225B9C278
+                               6E7BFEACBFE29D7AF396B3D5917A8038
+                               7263018C7E98F49A1D5FA4B64B8E2AA0
+                               7192ADE0376388E8295AE5B54CC51389
+                  xor-digest = A26BEFF2FD72BE47175C1B6F3D749CEB
+                               0E3472FB0FD5E173DE66A5BB60357565
+                               505E3AA44A67651DCA75DFB6F0AFCFE3
+                               F4C89F064FC42D7C2953694B0CD47832
+
+Set 1, vector# 54:
+                         key = 00000000000002000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DD1649517BE76EFF747658F0ACF5D354
+                               2C7FFD52F09FF7DDDFBC48487450607B
+                               CB90ACC3406D0302E84450FC0BFEC660
+                               9BD44C7FFF670D69C9B19FA50C62EBE3
+            stream[192..255] = EEACF8ABD7D48E285A6658C255A6196B
+                               66B091773A9F81807A119DC24023D5C9
+                               041AF75F2C078C5246BC5F50B622A678
+                               64EB7A07DA6A8764437E20C7E1E0E579
+            stream[256..319] = BF55E777AC644A0938D438FA374360ED
+                               F842BECB027FA3A0F364B9150FFBEB47
+                               09FE2D2056A6CD5A7076172152484BEF
+                               A86EC7DDE657307580BC6F9ACEDA4C73
+            stream[448..511] = AB4CF968EC00E7F08553A10270A7D439
+                               68B0BC79C2DAE278AF1CB81FD516CCA6
+                               F5B8A47271FAAC3223F02DB4D0D5945F
+                               9C13A47906B03B80878CB0596D37CC47
+                  xor-digest = 76ADECA36B9401DDD5CBDEE821B70FD6
+                               65EB9CDB1E3F25C0BE90DEC49C03A9CF
+                               4049CD34F9550B28E0187B0AD47D86D4
+                               88DE4617EDB5F03C67FA2E7B9D20AA25
+
+Set 1, vector# 63:
+                         key = 00000000000000010000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C0CEF6E3CA9F0D523587FF47973FE896
+                               9FEB08773E3C694FBAC4804B37121B31
+                               06B99ECC2A08603EBA72EB3DC650E8F3
+                               462119F4685EF4CEA18D5765A6F22765
+            stream[192..255] = 79E92E248BA61D72C610876D3078F1CC
+                               CAD662F2423E7EECA813133136A64E54
+                               A1B6A151BECD2B815EAD959DE8E8DC62
+                               8F388D366103296A058CF60F525D6467
+            stream[256..319] = 03BD62A0892D939C1C28C4EB490F87B2
+                               527536AD6790AAA6C3CC50013E2BB883
+                               5710EAB7916FD89896B7983B326AE271
+                               AF9ECF975CDBBB968D076685BAA3343D
+            stream[448..511] = 98762E306A2B9D488FFB671D3975551E
+                               A06A6CFC5DB719B888E3164387EC922F
+                               12BC31A8DCAB8AC0CD6E12212CDA3B13
+                               4CF7F870221D6CDAC2B222AF4FD93DEE
+                  xor-digest = 606FA49585621E34BCC3748C06B51FE5
+                               A8AF320BFB83A4D1D3AEC6373519B28F
+                               2048A975732BA8DEBDFC5F85B84E7C3A
+                               EC0FCC9B1FA9EBB9D79D6B18BA2D70B7
+
+Set 1, vector# 72:
+                         key = 00000000000000000080000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 33A81D48866B04388451BC2730A2980B
+                               5F5BE248369911340E6C024A1F94D4FE
+                               ACFB246F7C0B9E27A40772D68DB36DE1
+                               7E87AEF19C8A68854A46B3F654E0AEC8
+            stream[192..255] = F67C60413B25FF7CB8647D1E9C361696
+                               3B23ECE23A9DBFEC644E855AEC5212F2
+                               D336E6F074EEC8FF5F8D4FC6398AEB9D
+                               BCAF6C29FDFE6E69A03D906C527FB0B5
+            stream[256..319] = 263D512137BAB758F646C71058D02B20
+                               3920965D84E52A99B50FFE79305E491C
+                               E0D61EF71F7A07937CEC8590B758F63E
+                               B3EB5890E8678F170C2E95B827FD8DDE
+            stream[448..511] = 023AD00A87D3D9441D4E8CB603F5CDDD
+                               AE8F3EBFEFB9C5435B72B9B8D03ACDF1
+                               E4A0FB796FF8401854998015905B878C
+                               99B3EDC7DD33A86AD4EA6AD208440C5D
+                  xor-digest = 5DAC8E3446BB3B0DCFB3F0A3A3E788C6
+                               07FA7436C63BF7AC9FAFCF4A231AFAC7
+                               75A3A810EA0FD4E5E6A5B8FE5D165A80
+                               798A9F58EE1AD27016E867D2E774507A
+
+Set 1, vector# 81:
+                         key = 00000000000000000000400000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B33EA681CA88C80EAD8F2D57C87EA42B
+                               742550FF8AD2B01BDF945BF160AF763B
+                               15D6B3BD92E6CF3E6A2B61A7D4BB94AC
+                               E3DAB365E4EA50EBFD2654E60CE849BE
+            stream[192..255] = E97318BDF61934188A94BCFB4441809D
+                               36C37D1A43BDBB3EB06FFE143B6153FE
+                               C8453A13387923F434CFC7AAF8CBA097
+                               7D796DE95EEFED3B2126B611F477619F
+            stream[256..319] = 4183971367E71731111D2212520306E1
+                               1CBEB05BE6FDB338414C826A8E359C7E
+                               CC680F317C12C6EDE6B443E68B4767AB
+                               4190E95E1AE4E4FFE61707BE742775C1
+            stream[448..511] = 56841724B7D7F95809456EDC1D3A532F
+                               E1C6BA252017DA90EEC71FEE9A639A89
+                               4CB7E1575494BC8B44FE4C5DAF90FF4C
+                               A32E03D6399BCB3D9D25B62764A4977D
+                  xor-digest = 3E80587D70A53AFFB96A62F6493B9BE0
+                               1C25339CBFF7784F5100A7922EE3E6B9
+                               9D17B026C0EE69C5383F63E0E5AEE9DB
+                               5814E2C526192AEFE17004AAA1996280
+
+Set 1, vector# 90:
+                         key = 00000000000000000000002000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 51A7510726D12FE9574095633A3710E6
+                               3EB8196622BC808B8A18800E208648C9
+                               F7031F8171B71F37613753A5E49B37C1
+                               CBC7933A52CAD48601E91CA198EC19EB
+            stream[192..255] = 286EF1C4F74C993A7D783E86527CDFE5
+                               213CE4DF7EC72544685291D8108C7621
+                               50D488AEF761D819781814F4501553CC
+                               B45EDDA85828C33C4D0608169AD20B2A
+            stream[256..319] = 89DF5C916612EF0ACC1035EB75752239
+                               ADE08E0D63B622EA52CC997DC8178C4C
+                               4E57951FC8C6659A225E88502742B888
+                               1F300FC9F278AA3D9C1063A83CF33C44
+            stream[448..511] = B2DE3AE2941AFBDB21D80ABB0EB852D3
+                               A076D98C696F886C302D96D6AD226CA3
+                               7B3213B3E641632B728A0AC7131B74FE
+                               F733D1B18666D36A02C148FC98AD2E89
+                  xor-digest = 01090125BA6C43AAA3910B650D046F37
+                               E04896E9D2BC276D969A10C1B26FAD48
+                               8A2CA5E59044ADDF698588A561557669
+                               A4EF25E1BB85C0A9D63F69FBB2924F83
+
+Set 1, vector# 99:
+                         key = 00000000000000000000000010000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 545E2C75365948B40FFF042EB6919907
+                               6E63EE636CB343C51AF6C17BA24E1BF5
+                               C045B0893B8CBDF6A4068F8574513676
+                               80000B10BA11666A546D8DC75374F5BB
+            stream[192..255] = 9805DCB5596FADF01224553F3A8DCC5C
+                               909D1A5EC2C29BA0DB86A46ABF70BAF4
+                               4A171739309A923428EA7BA8EFCA5CB0
+                               B0B8A5EFE9A4A39BE0EA6CEA782DD862
+            stream[256..319] = 531EE320A584EE1E4E0701400F86DC29
+                               69531C2BB1BC922CFA9E0919A05B84C2
+                               46495A7C358015724B62A986220DFA17
+                               6BF39FE4263A9D27D93F3737CC1D5C59
+            stream[448..511] = 92CC0D63772783AF62E642A5849CE7AF
+                               4D21EC815D644F88887242F4F5F7E1DC
+                               55E241D72691ED50D59CB3E2FE68A856
+                               7696F8B8E3099642D70EC3945B8BA656
+                  xor-digest = 855CFA62E449250845472BCE9453BA45
+                               F91601ABA6BB715B079D407E05D94CF5
+                               93B5A1E2C12C04C78AB719339AFC11C5
+                               213E17ED9DC2B0B9CCF751E0613D4F2C
+
+Set 1, vector#108:
+                         key = 00000000000000000000000000080000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F9748DADA2741A7CA30EFA167ED09978
+                               71619682AB68CB400A74BFD642180CC7
+                               F3499CE2CC86AB7727786DD01AB8D08E
+                               8774C5A3CFB4738FF1E3243DECF720FD
+            stream[192..255] = 5AA20B305F5D6363180CDCD4E16427E7
+                               2E3DFD73D2C4E2498008F6E0FA9CE3BB
+                               D751F6EB8DD5F48EB42B994688601E3D
+                               2CEB3DE19BF16C4BD7FD4B331FC93473
+            stream[256..319] = 81E3D9BB421CB09A9139534C6E430668
+                               FCFCB87E48CFA085D4FA1AB316CD5AB6
+                               35294E434852C1509C1023A85B26622C
+                               68BE19944CA3233A4D3272710A791E3D
+            stream[448..511] = A499D228204BC22C32047DF550E2CCC0
+                               260ECB7BA32E8F5CBA2C1D9A09D1F38D
+                               FB30815BA3C9A8D3243CFE7AC4A14B1A
+                               D6AA67D3EC0A5CB617FAD57E41A2A0DF
+                  xor-digest = 0324B7F1BD990F8DBF19C021CCDF741A
+                               1B4A9C3C3940CC59CD715F0B2CC31C08
+                               82E5B93721AC98B00F7B45FCCF19FFA9
+                               782B7D7FC048F0756A29B066B472B394
+
+Set 1, vector#117:
+                         key = 00000000000000000000000000000400
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 7EA95775329E2D1163E30F429FECAEF4
+                               CA177BB4D3C4D1AEFA6B5A01904266F7
+                               7D7B7243B9DB1490245EC05129CA2DBE
+                               E3A98885DAD0B43B0E725DDA39B444EB
+            stream[192..255] = 78ED15A7B4A8151F384C740B844115CF
+                               D4FA31F9BC16E22158B0F896E70C0F73
+                               F74AA5EF024F6B386ED71239CBD57996
+                               4583C37104AD8C7E5C812C378AF00F98
+            stream[256..319] = 292FF21E49659AF99AB21753BA2A2B28
+                               25DDB156D4F7AFC1888FBE8376AE4C6B
+                               905D5916121E9F9D76C83FB146ADA735
+                               2AAAB6E89CE9398C484D69D1A33F0C97
+            stream[448..511] = A50FF5FC20C57F8297C9CE2599A3E6CE
+                               3193746E8C45FD9AECA0C5A0FB3BF70F
+                               5981B5BA8D2FA57677EF65B535FC3E65
+                               405BECF0A508445E36A7B6DE2BB56106
+                  xor-digest = D9650FA5D128620134828E1C99D9678C
+                               CFD5BDFADC46A5E79D47AC5967B8A1CF
+                               32F7DB65B949C88CCEE0D96D960A110E
+                               FF1D09EF5549B88D5B53ED46D4C2F296
+
+Set 1, vector#126:
+                         key = 00000000000000000000000000000002
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 25874CF64ABA4536844F815F486F9DEF
+                               927E325CFF2FAC48134A4D30824C5BF1
+                               EC75F8FEFC624AFCC717BF2C8EAAE374
+                               0AF399C2653389DBE31F9FF5D451D362
+            stream[192..255] = B151A1EDCCB8B4A3CA9BC98F19EFE637
+                               BE2D6A97A8F794091E7FFF06E7B4E574
+                               46B81E8C787BB77E461592160C44B5AB
+                               49329142D01A1CD5CFC6681F93DF1E33
+            stream[256..319] = 29B2B0C04E07D33EC3146E60AA305F0C
+                               2288913B55DDC18FC17EE836B39193DB
+                               87089DF2BAC4185A57E910331864E25B
+                               540BBC968099900F7BF18645A28A419B
+            stream[448..511] = 286FCC98B40EA26BFCBE5CDEE52B30F5
+                               810CFB26E756C628B56B3B5ACDA49E07
+                               192592CA2241C6C5193221EDA36CB0E7
+                               B5C3132F08087DF0673D3101FC559962
+                  xor-digest = DBF1D7E0AC062FE6BA9834F0AE41ABA2
+                               B28B41FDFEF914F070007B0A48EE9D9F
+                               E69DB8395BECDBA7B545201318177A49
+                               7D343A317B5A37A9DF98DD25C84DF948
+
+Test vectors -- set 2
+=====================
+
+Set 2, vector#  0:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 5B078985D8F6F30D42C5C02FA6B67951
+                               53F06534801F89F24E74248B720B4818
+                               CD9227ECEBCF4DBF8DBF6977E4AE14FA
+                               E8504C7BC8A9F3EA6C0106F5327E6981
+            stream[192..255] = 30DA9453A90909A5675D6B691CB0990F
+                               C423CDD8222EB47245BBB67BCA2B9C10
+                               8D1F016DF0CF8CEAF6829910916DBC1E
+                               113D11E91BEC3D85C47E3042EC865658
+            stream[256..319] = CAFED71B892EDBE13388CEF6A3365797
+                               E0D88C0D3A5B91BE4CBAF5162F69558F
+                               DBB45CA6F8C8D4C371D62736EC244584
+                               60131F54854F3EC804AA9A38E6ADE281
+            stream[448..511] = 531A0ED5D2A51DDC6499FE1BB6E2295F
+                               2C3EA0F56AF46ED93DFAA4E16F5F0831
+                               2D77BD0E9122043CD6A202CBA9351F6A
+                               0E8E6263F4017355136A0C551E6FD0F8
+                  xor-digest = 023D719F61C193E4CCD87755C87F9604
+                               C5A29DD7E31637B3DD70D43441D48CC7
+                               D474013C85EEAB1897C80ED0A0272543
+                               F951C72E3954616CB5D6B51FC24F4B0F
+
+Set 2, vector#  9:
+                         key = 09090909090909090909090909090909
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F5C2926651AEED9AF1A9C2F04C03D081
+                               2145B56AEA46EB283A25A4C9E3D8BEB4
+                               821B418F06F2B9DCDF1A85AB8C02CD14
+                               62E1BBCAEC9AB0E99AA6AFF918BA627C
+            stream[192..255] = 3B3C6E78A8F381EE2C159FAE1C487C58
+                               11FA9BB02CECF7440239FBB0497347EF
+                               D8F1A8AA71AFC70ECCD64E81388E6E87
+                               9521C2B47AD84F9CFD9E240D8D2F3001
+            stream[256..319] = DB04FD01BC18D91E2D31237AD0FE26AD
+                               3C8D6A2EFDAA9CC11BFCC61D94F6104A
+                               4091B3634FA57AB0AB9B209F22DA5529
+                               75C3C322DEBE4AE68623BFE1B2BB7F0A
+            stream[448..511] = 35B290F85EBA78A978750690C4747E8F
+                               72621951483772E8B89876CC5D55F3AB
+                               02D9B8FB35C741279FF9B5B571B26329
+                               4D011F813CB5B209CA1A22D532BF09B7
+                  xor-digest = EA9BB65E87C987EA64BC3F4E710CCC34
+                               F6CD0A795B8347E1441CEBEE35540D41
+                               64FC2B95D71FD47A2C4ADF732261EE52
+                               8125BE374FA4A90132CC1063971A2862
+
+Set 2, vector# 18:
+                         key = 12121212121212121212121212121212
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 397F8EC015ED573967938D1CEAFE9BBD
+                               BD8853C329B3A881B489090853FE0F43
+                               89DA105F0ADFA9CF51DA2521C40FD2B8
+                               FB0BF80B93E3F2B3D8A8EB1C615E0FA6
+            stream[192..255] = 68E7DBF465E3C6994D58B9937A866E4D
+                               43A82A80DAEDBF29C048639BA38B690B
+                               7ED11323E3C0A8E77A16356705431EC9
+                               9F2CB7F7E1ED3B83EAF2CAEC00B00755
+            stream[256..319] = DA51CF3A07EBE7E86E9DDDE5A47E7417
+                               376F334E6AEF9C187012C8AD2B94BE7C
+                               00A876756EB232510FD0798E72EEC87F
+                               75EC1467C07B3A1EFB0D51A5FA65E382
+            stream[448..511] = 0BF3C6FF6794887F2776FD632B83682B
+                               AAFD131432CFD7D2F675E03320395313
+                               AD4ED96E9052FE6B2D2A17428660A25E
+                               EE642B712800BE3F7E44F21A1E6A03AC
+                  xor-digest = EF4E84DBD66497B142EEAC56B830FF78
+                               0465CEE20B9CFAF5727D4B3A588F4D00
+                               AAF718330CFF35508C44C1ADB8476625
+                               2CC3AA6AAAE74F8BF1DDB6D4AADA425E
+
+Set 2, vector# 27:
+                         key = 1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 72BC8A6E1E61E704B142AA00812EE676
+                               263C1CB9AB941119B19D15EBA3462F56
+                               2F69220595DE5E0E7C595FA40F1F06B2
+                               6EC32252AF05310809DDDFAE2E24B170
+            stream[192..255] = B29A740B51B4EA1080666337D5551484
+                               FFED6860A5125DC0573C8F90F23A98E0
+                               BA7B3E4C28C2CEFB1C33D2C36D1B7625
+                               64B9A67240CF174347A4C8D868F00F6F
+            stream[256..319] = 555ABD5577A8909797FBA9769C03A0F6
+                               537C06AFB23354F054E25457B729B534
+                               CD10B2ABD45BE3E38DAF1B7A9103268F
+                               4FDB4C0FC9A80A003FCB907E8F249AE0
+            stream[448..511] = 3B29A43D9C795DAF1760CA9EB57C0B39
+                               F62D54311207B617B727FCCE1B2E762A
+                               060810C4DEF672E7D76083E3E4BED0D1
+                               0BAFD27CDFD2C937E660190D36B3FD7B
+                  xor-digest = 0B3B0B3C69F2E4BDA22E25AEF352234C
+                               18CC5E1E3F6A317ED7257887446EF734
+                               65CA15F51AF5E077B7915062391D8497
+                               8F437985DD08F5FA3A8D74B3227A6EEF
+
+Set 2, vector# 36:
+                         key = 24242424242424242424242424242424
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C845BA29D542FBED2D021C85188E119F
+                               D34967B79D9F44635DD45D2E41DC5AFB
+                               B237AD2FA0E4CF4202D83DF3073C578D
+                               2AA8A32D30FB45DE28F23CEB85E50FBF
+            stream[192..255] = 15C910FDD3C590AED1ED7DA2A7969297
+                               FD12081B4B23F0A32CE5B3196173C7CA
+                               7EDD03F9637E08CA501C4850C15B207D
+                               7AA724377396CED2357B572BBF9E69AA
+            stream[256..319] = E484AF567EF80BAE77461855294E9280
+                               EF57E7366605785034D639D6DE3EBB0D
+                               E21886D0E1E0679BC2E2C9C2D9201484
+                               4A452B6AD3F1AC8B7762FF3C0E405B3B
+            stream[448..511] = 595D9855200786BB575FF7977509F395
+                               7879CA1F19619A99174BF013CB62F85B
+                               FF2C3C4FE724E26DD0C10D7635A2491A
+                               9E7E868D9DAD9201465AA178184D06AC
+                  xor-digest = 08737B82505F46F4FF282EF42F387AA8
+                               0450058F5314389BB73733BC163D75D5
+                               D32FC6408F8DE5F6ED2050027D605FAC
+                               A7119FC2DC1B6D3E84E8048DCC42FBD2
+
+Set 2, vector# 45:
+                         key = 2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CA82A689535CA8BAE01BAFEBA6504B3E
+                               6E6320101999BCE5550C2BBC9BC65D91
+                               FAA2D72FA4BF46B6EE916244048B1D09
+                               A115E3AB6C00BAC8EE382B58859E8157
+            stream[192..255] = DE787B1CE01B0BC09801D78D1FFA3A82
+                               0C18B867C561E96DF4ADADC5A4375E44
+                               5A34F9457E5F8C9A337A0C88DF0F723A
+                               D4509F1449DF2C6AEC0EADF4C7A8139A
+            stream[256..319] = 7E1854FA15DF9D5827F1555F12B292C8
+                               452A1A893EF034C51750388D294947EE
+                               3F505839C69C1708E8323C449C39A96B
+                               FC9EC91B0E1CAA8112057EB0389FDFD2
+            stream[448..511] = C85B42B838FB9C3D4956C9E22FBD8FBC
+                               EDD92C4461EFBA5CF1664B9AF54857BE
+                               C3D00319E5E8A89A8322831151EE1D52
+                               D8585AC79CB60B61ED2C852D04BB0FB1
+                  xor-digest = C65A6BEBC4FE898DB8D6B8F6E8F3680D
+                               2363BC12259B0FDB2BD8F052A572ECA8
+                               D1EF62AA9A48497805A413742B5AF5A2
+                               6DC9FF624B49E5D6FE58BBE5251B4983
+
+Set 2, vector# 54:
+                         key = 36363636363636363636363636363636
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 9F6BCFDE566A1B67C608F11B8461E340
+                               42D4F07DA4D5EB05554CB7426D65C5EC
+                               A93C2D321175B6F72FCBEBA6E38CB098
+                               B72534F7D534B1AADD97B77E8513B482
+            stream[192..255] = B2466A173F436C8433F264CBF125B8E4
+                               C10BC81BD46B5C21FA161CB2AE07D27B
+                               F66812A2C2FCB2B14C23E413CEF4E591
+                               AD52EF810A000B42E5C1B76EEBB17739
+            stream[256..319] = ECBED2058DC50223614EB8635B834C3B
+                               B176719C18CA5E3D087A93E5CDF81123
+                               C6FB819CCAFB5042AADFED5E3C33116A
+                               FD92AA21031165A22F4751C423B8B945
+            stream[448..511] = 758BD9435DE607867DA256064C304C8E
+                               DDDF5B64173CF2C98B2842992F8C5FE1
+                               A37C3227B7F37D49A39F9FF929A883FD
+                               56DB8B1A174E1E55FCB21C9E1164C20B
+                  xor-digest = 31761A49503946701D35306FBCBE10E2
+                               02967E7EC14A328B4DB19FE79F03553F
+                               13A012B7297B2D02F18A216AD24A682B
+                               299518C3769123EE86A4937DAA9FC39B
+
+Set 2, vector# 63:
+                         key = 3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 85C7FF83641ECF1C91B2D996D4EAFF6B
+                               26A4E7E34C0CA9CB9399F655E566383E
+                               246143F57776C8E08951E87F76091FE7
+                               2356CC901F09A07895A890AECF047B3F
+            stream[192..255] = 4CE0C6606195F7562D485E32E8E105AF
+                               C862100A07E55FB449BCFA2D9BD48658
+                               958B37B3EA3565FA66824102A14B5770
+                               5E3914E0680E116ED58212CBF61028E3
+            stream[256..319] = 3BB772A5A8DE2AB14CAC1ACBF45B1701
+                               057710F24C01E680F58090B8E949AF01
+                               8970A43A698A04C0C8639FAA665DA3AA
+                               562B2C5C3A03BCC38FE75DC1821ED718
+            stream[448..511] = C73DEA1F7BFE42DF75EA2681BEB31948
+                               821FBB049DAD15B988A77C0247868A38
+                               2056B66F47B0195FA30C9DB5A2334A9D
+                               CD7C0D22E479FAE1BBCDFFE60F261C7F
+                  xor-digest = 94D41CCAD940CED3C854DA0796DC62E5
+                               6B566A980E34F353CFFD0F53AE9E34FF
+                               A6A057645FE66D86BE30F93805D9E2B5
+                               D78C68EEBF61CE387277A51EB2EF835B
+
+Set 2, vector# 72:
+                         key = 48484848484848484848484848484848
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E45194379659D1D8904DB3698AF8B245
+                               762910B7FBD019AD1AA20A6C433B4C80
+                               308A9EA68697631646BF3A2107C4E7FE
+                               2235E8F3262A9DFD3F5CC23FEB0B2DAB
+            stream[192..255] = 012611EBCFF9F839DDABF99D9D4757DA
+                               4E947598C4757976F6F61DA5F0DAC8BC
+                               DDF72F08BA2F446FA37F9A490F6A2B6D
+                               79227C93271D6B763DA7B2A907220A42
+            stream[256..319] = DDE54F9170D6A4702CAF45CC6F799F74
+                               A43D83AB8ECBAC5206D108F869561D70
+                               F151A0037F8E28951B5026643F8B2D6D
+                               56A62E259F04A5EA304791A9468E66AF
+            stream[448..511] = F70794C084E6EDC07BA0347413B05FC9
+                               FC46994CA820CE4FC037ADBA50EAA9AD
+                               55064ACB7308CFCE3F35AD5C7C628362
+                               F4210FBC2D3264F734728626BABF5356
+                  xor-digest = 31815B36BA034BB1941DB1E45A941A59
+                               7C3882F34BD3BF441CAE8A9790B05BCA
+                               72049FD10C09A14AC9DB867A82C38A5F
+                               524C72F783DFD16980DBCDEB486FAE96
+
+Set 2, vector# 81:
+                         key = 51515151515151515151515151515151
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3C04E21F6937C4EF472BFDDA89F9CAF6
+                               FF53889A9979ABA8F23AA51DB1EDB8E9
+                               D08F696C1100799A7D004DEF1CA94110
+                               FCF0C054B0C131E6FAE0FE2F2DBF22B3
+            stream[192..255] = 9B4ED3EF9639B953186FC7E732E7A9EC
+                               55A5F3F19C5A10E12EBE46DD84F10385
+                               33837693588D584FDAF86E3A217C3CFF
+                               020278736F1A90CE07F0DCE4329005B9
+            stream[256..319] = 135FAD68B5282FE59B28D2DF66463632
+                               06CA92E84A73FA131EDDCE89A5C23B4D
+                               08FA57D455BDB32F8ED58DAF3EF288A2
+                               7C72020E35DAE19B446E4C52DCDAC5B1
+            stream[448..511] = 7D08FE1CAA0E8A0362669B310B99127D
+                               18F2111002891D3229102D72605B9BEE
+                               F5DA36059B0DBBA7646927650305431B
+                               FDA4A97570CD0C484BF1E974B157ED7F
+                  xor-digest = 5125E77698C0DAA89A7E47DC5D038D40
+                               7B732CE56CEB674CE653A1B6661B2740
+                               0C092AFF83BEEE4FC4543B9D725C9387
+                               2F89AA338222ED677BF59397200AB304
+
+Set 2, vector# 90:
+                         key = 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DA2E6F7FF0D1F1C87A97E028D3E20E21
+                               75E9AD91482965B651B495AEE819CC6E
+                               C42AFE2C20EEACCEC4E90710D17210E0
+                               4CC6832905985322C8007F872D3E58E1
+            stream[192..255] = 09B0A38E19DDDA08F7DFEF7D0FC80560
+                               D692A020F0A66F609374ABDCD1343722
+                               05F19CA04EBDD3009844BC540C1B2B41
+                               66D45E8A2E822B906DA34649E7FEEBB3
+            stream[256..319] = 6C8E2CE1D7FABA414432E75BA2EFE4AF
+                               CE2CFE99506677A956AEC86BD290B6AF
+                               C5298A448D0DEFA99AA5CD26D318982F
+                               E786D809C713D5A55B42CA6650191DDC
+            stream[448..511] = 845FEA0A88B521CCB8927C9457AD3225
+                               EF6E3C21705EC9FB24873916A2C24668
+                               963C03FE097DA8224A42A99E5DFFDC17
+                               68CF518DE49CCAC8A70216C62C9CBA6D
+                  xor-digest = A46BFD9D2D0BCC688A032F54733AB7C5
+                               5FF58B296071D5D39349A531E41F0BA9
+                               893A1722B6102740BC5FE394A49363B9
+                               6A626AB43FD6A288CD9B23F7255279F8
+
+Set 2, vector# 99:
+                         key = 63636363636363636363636363636363
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CF0E05248AAD82F1C8CD2095ED2DA333
+                               BCB02E3AD8797377AE1F1B4D6DDB86E6
+                               2A59791CB553550E0492FAB42C7A2C42
+                               3157C5092D2DD37D46589F17FBD86584
+            stream[192..255] = 9E946626F1EAAEDA42E52422B4A84D91
+                               4122EEE5736BCD12061C77DF5B0122B5
+                               1784E946B4E93470170ACDD7E2779591
+                               57BCC9B9F3E11E88BC2F740AA0C10C97
+            stream[256..319] = FF22D8196AB3DF662210D12D0FE79255
+                               6DCD39611C07F089979CF7D693A30CA3
+                               5B795B7F6D64931916E717C8BFB92114
+                               DB75118BDB51D142CE8133415C6B3456
+            stream[448..511] = 971F007EFE17662D95F47F4F28266516
+                               B22A1E50755EEF19149DE3A3121F5FEC
+                               E0D9DFE7A055026CA44193542D7687EC
+                               695B97769BF02F92C1EF3D904A8010C6
+                  xor-digest = D1C4878BEFCE48888A43C6DDE7CC8163
+                               C8D54A4CA36748C74721C7B6E1649A31
+                               4B5B7A4BD43E7C3D2A22F0C8446C7892
+                               90D54D421D37CB16400E59CC86215CC8
+
+Set 2, vector#108:
+                         key = 6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 54F122FC8ECFB176E7F4CF172B2D78B6
+                               54BC11ECF0010D2AEB9F899130F4AC2A
+                               38EBC15C8831D591E6675DC1CE7A471C
+                               4B869FE83CBF37AC70BAAE5D4AC607F9
+            stream[192..255] = 518F298A6008532EEFECB3DCF72103BD
+                               5E3F84FEB6EA2311E8C19A2E93A9C3C3
+                               BB1DA7DBA78D5618D1C4FA5B0B202728
+                               62645A361E55494D66C9359E41E5809B
+            stream[256..319] = BAFFFC9206D1D813F3E2768F08D78B2A
+                               89BB20CCD92E7F13FDD816DD4E4963C2
+                               C5FC2570CBB8BB5C70848B73001F508F
+                               47AF179528200F51CDC6E4854EAA63C3
+            stream[448..511] = 844B1D15FBFD1264169279ACD525611F
+                               A39C7BB41F1E7A1C09090625F7926E51
+                               23A4CD7FE1A3F37ADC67AC437BF0A5AE
+                               FFFC6FB0ABF39D9908145004AA5B958D
+                  xor-digest = EC67596C9DEF4012A2D543842829306A
+                               4285A3B8038818F265065DC848BD80FE
+                               C27C2F66A57B27F7FA8AC912001EC954
+                               05BC6E93D7E555C59060F5D2E294D103
+
+Set 2, vector#117:
+                         key = 75757575757575757575757575757575
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 91D2772A18995DB3C0801DD3740F4466
+                               F9535E5BECB93DDCA0E94D19C0B57BDD
+                               0FFBA9DAF0B11D55C852927F8BA560EC
+                               4999E25848D08FCA7275E7E8571A5F1C
+            stream[192..255] = 72E64FF10CA9F07CC493715724DA7610
+                               9E4358E8B0CAE451348B784A162DF036
+                               AB9796724D17FDBF356031D080A6631C
+                               D1E8D217B041AD2EDF427972653206B2
+            stream[256..319] = 4054F770C93FCAB533143FFCA8E4C0F3
+                               344956C29D10374E502C2EDD177ECE5E
+                               6625BAD9630DAD57976216CD69865058
+                               130B132FEC1AB0C350DF4DACE4C7724A
+            stream[448..511] = 40B4A4DD63F7B6E932482D0E6F5BBB90
+                               E402466550B518A177CD05985D238827
+                               BD92EE7EC22C274F19E682F85ABDAD95
+                               D0EBB3DB6C6134408353C8B0472C9A1D
+                  xor-digest = 9A6C893F2108D13A29373DEDA65386C4
+                               AC356BDDD4A3178952F9126E322B7AE6
+                               83C94F1A131CBEAFF26549D9F84CF04A
+                               1241FA374B055B0ADE7E49E8EC669E65
+
+Set 2, vector#126:
+                         key = 7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 87A7773A3514EB7F882F2C491E90DCF3
+                               059C5CC575D806B9029CCE3FA45A246E
+                               0EBD3AB2F2E324FE36ADC3B56AE2F7EF
+                               C710AA964CB87381386C2A88B1308035
+            stream[192..255] = 415D6F59DD004944D4E45FECC6F1F06E
+                               20BEB18D9C84187C347F43B17E0924F1
+                               2348F825E106E57A00258CE4415294D9
+                               4323A9812D8A71359CEC1001BAA0D567
+            stream[256..319] = 8E20F0D03F37EF4B2C5EE12B5F81F7C5
+                               32D62E779FA0D2D08F8ABB6B0183A4DA
+                               4EE0329215F261D953150B9AB9FCBE2F
+                               568AAE361EAA8636ECC01A63F007977F
+            stream[448..511] = E7C44F44E06321A20E25F73E2069757C
+                               90499DB7E60025CF6D2D445E53A665F3
+                               08EC96F6FE73C0AC90D7E4A712E18C2D
+                               3DED46DFBAFA24C4B0B329E52C525976
+                  xor-digest = 22035341489FA6EEB2A6488CA42F4043
+                               57477C3F55569A1224EC39B1019E90C8
+                               21D37D78ED4DCEAF6EA70724C3751760
+                               38CF25DE4F84BABD80424D83A310881B
+
+Set 2, vector#135:
+                         key = 87878787878787878787878787878787
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CEC0C3852E3B98233EBCB975C10B1191
+                               3C69F2275EB97A1402EDF16C6FBE19BE
+                               79D65360445BCB63676E6553B609A065
+                               0155C3B22DD1975AC0F3F65063A2E16E
+            stream[192..255] = 5E12BA9DE76F9ABF061782EC1C4FBBAB
+                               3373B816DA256CAAC37914B0C161E4E4
+                               5F5ADBE444098A5B2A4CFD4251D79918
+                               987BB834BB50F0834EF4985F356B92A2
+            stream[256..319] = D89642D25DF97D149AE07EA18BA39497
+                               8935978AC34C1DF9F444986D7505DB4C
+                               7E08DB3616B84CD52E7DD7FB108C36B8
+                               B50C2573172F4D3500B6D62A9D20B82A
+            stream[448..511] = A2C17FE7371604556F796429C6BE0688
+                               8611638B310F3E9FAF484BA9EE29C16D
+                               2F842EAF33AFEC557B68D2F453569187
+                               A6F4CD204A0E7A733E81AB7CE9FCAE81
+                  xor-digest = A7C93087CA70DDFE5FA5F1F2F954320B
+                               6E3A61977A7C6AC2F033B826AB9A9957
+                               66671D2A1025CDF8E2824B2F58CB221D
+                               2A68679239D90152FF7D0D39B33FAB93
+
+Set 2, vector#144:
+                         key = 90909090909090909090909090909090
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 7118889F6E46A6523BBEFCDB006B3BC6
+                               71A6D390BC7099A708D370DCD0E3D143
+                               A0334619EBD5C7DA9EF6301F29273F85
+                               2DFA3C580ED65C6E952F88A0B7FE368E
+            stream[192..255] = 31D61E133CA1AAE400CB2DBBAE93C75B
+                               445792061AA0539DA69ED0B77B970C0B
+                               482156A5DEE4082A61364BF06E692399
+                               FB9F4411FEC515291F8949B20F57229E
+            stream[256..319] = 993E815F299D4841518119BFF88F6EFB
+                               F3DB9BAE60238BDE2845DE4DBA6D79DB
+                               C9E42BA5C3C004AE4546FD86C660FFC8
+                               FD6A8A349669FFE3D9E5BDF8E50A407D
+            stream[448..511] = 0F9CEAC6BDCBB56B7E97DDC95877B2B2
+                               1274F4A6D814B5440C74D53A3FF0735D
+                               EF01B14AE4188E215CE7337C04871688
+                               7159695A241BFB9D6B489FE9E23B2AD8
+                  xor-digest = 0BD5739ED28778023E6303FD88DAABC4
+                               0FA0A211A1A5C5F230D9E67DDD9EA517
+                               FEBCDF0BDBC107291B6CF3ACD8B862B8
+                               4BF15400493A54036E97FDEBB9A1DB2C
+
+Set 2, vector#153:
+                         key = 99999999999999999999999999999999
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 236ECC5AB83DB1C5CD1C5A888CFEA2DC
+                               BE99E7E515650511FF7016A0EF287ADE
+                               5A03839C4F83F05FAC3B0B24D4E3F602
+                               3251F8D9CC4530A805F8A6A912EFAB1C
+            stream[192..255] = 792823ACE2C0DDB266A118068AE295CD
+                               716E424D3B98A9DB2501A3F5DF7DC70A
+                               3BD2C6E664D5E13317D6F57B8774C903
+                               D407D2BB6014E0F971141E89569C5868
+            stream[256..319] = 2D6ECCF738FC00ECD5475EDA959A73BB
+                               304C81FA9DDE0C21592247C4098D9347
+                               1DA30294DE8C100E5B17A199F744CAC2
+                               4E33490FC7F223FD6B4923056117C6D9
+            stream[448..511] = E791A6BE7F7593788E5D627F5CDAAB59
+                               349AF2BB1DA2BA622B9824F729929098
+                               BD19DFC05D0D9454F604960C027752F9
+                               7812E53DE6AC6CD2751AB331703646AF
+                  xor-digest = B7C5CE0D2FF66533A1C948C425F33FF2
+                               DC458E7E517637596FC8FB710E2E5636
+                               DB1F14848CB12793D54ABD0856B22F3A
+                               ADFA8C33AD08B8CC5292DD76913CB105
+
+Set 2, vector#162:
+                         key = A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 74490D19F13E7C6D1B25C6408E23F229
+                               8A8806402755660C4A30CD216A500BB6
+                               AE975E08EC62D08425A8A62A71B00215
+                               DE35E5178902348698528CB82296F009
+            stream[192..255] = 51A6EC18829928EE94C37A5CD030CC4C
+                               E4F7E1B3E78C3A5DF07592F45B968BEF
+                               F95B8B257DAF2B468284627AF4481FD2
+                               67BE0B164DD86721DC8C1607A0607EF0
+            stream[256..319] = 75C565D5A5A240B003273F99BEB3E4B3
+                               9C056162B626F383F3E77B5C98C0FBE9
+                               119A7C335C333E6490126AC2510CDFAA
+                               86441C72D1DD9ACBCD3FEFC0D0C794C7
+            stream[448..511] = 2D90CCF0B43239D725E3B53C31B82754
+                               246C065AD23A8D709161FC74B34E23DB
+                               B918EAFA4465125D3780BF0B5803AACA
+                               037AA0A14D977141B611A6CA2278B634
+                  xor-digest = FEFDA1A6E95920B93380CC24FAE214C5
+                               6B009ADCB176D519CA4B8538EDFC95D1
+                               6CA06B730B28A230F0085FE43CBEE2FA
+                               2EE5DCD74D66F5CBB59F256CC1ED885A
+
+Set 2, vector#171:
+                         key = ABABABABABABABABABABABABABABABAB
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 22E1A884ED2C67CCB2977105649B6544
+                               367858D1A730AA2FA96703FA406B337A
+                               B2159A389BEF48D8A215D870B2968E16
+                               B11571F12BEC0A07FA7D3B9790987EC7
+            stream[192..255] = 4C98DD259D03A40AF38E0ED0F37CBD74
+                               B27776E9250B8B063E52E169C7B76A15
+                               0D699278AA4124427B5EB6AFC4AD5DBF
+                               600FEAAA98A88DFF297DACA5ACB4878F
+            stream[256..319] = 5FC732A26406FF0DBC764ACB05C83484
+                               976B640E60CCD6ABFB908583ABEC3E75
+                               2878371EBB5374C9B37A63E0768AE10B
+                               D857253D940AC408EF49EDD590E806AE
+            stream[448..511] = F012E429C44D5DC03B88123855B62C0E
+                               90E06759306017B5773752973850531B
+                               C480316CBBAEDE6353AD5FB298349AA9
+                               16AC0221A4CE1E4729BFB9C230AAF9FB
+                  xor-digest = D73B872315F9052C67C4CFC5CD912DBD
+                               60DA32FD06D9C8E804968E688898200C
+                               1D979DFFCE52E1C3B3309B58D12BDBB3
+                               D3EBA2954D1587D720E004E12EB4A13B
+
+Set 2, vector#180:
+                         key = B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = BEF4DD0101F80A8F880BE0613B2AAF88
+                               D2EF924014F7445ED922E9C021571909
+                               D7E6BFCAEE0724F2A9C522C4BDE4BBE9
+                               FE53FE592C0FEB80D2C7A51FB8BE9EF3
+            stream[192..255] = 6B1966D3EE460999FF09001B0ADEC484
+                               0D22CDDFF39EB0E3D5FDF74C6E7B3394
+                               A0A4271D780DE6DEE9AC58B4903EEDD2
+                               6DD14E14A4DFE506748D5DCA6DDF4C5A
+            stream[256..319] = E79D99119996FBB5163335E2F79F0502
+                               7AEA5372136E7B3C5BE1F4A673A2DC74
+                               60834B81BE6C4976C4A727C8E6046A64
+                               4CAF42EEA6A068B7E532581E9037BE9F
+            stream[448..511] = 5C4F52E0E94884C829DA1FE88EF34614
+                               9F3EE55A136EFA3B417DB63D2487DF82
+                               794E161B3153DDB2E1E4F385E1A848C7
+                               729FF5CB1CB58D5E73FAB1F2DCEEE5AD
+                  xor-digest = 2F3C231B0228C274255F3BD314ECC7F3
+                               1B9C49177009AFF2CD88F807092D77E3
+                               C74C1B9B8650F581EC7603F4D6E70955
+                               1B00C3192414C04AB0AD8B0B9BCFE988
+
+Set 2, vector#189:
+                         key = BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 05AF4F98E9D526CD7912F3E8CAF45410
+                               DED6D4E331633C5621B94E7EBD15E856
+                               04AB202A553EFED55A548C7AFFCD2550
+                               60315FD50A305D8BCAC9C077229D34AC
+            stream[192..255] = 786D24EF3FBFF6883A4ECC4F40E445AF
+                               3CFD130D5B6A9CE37BEBA429AD137A82
+                               44D0586FEB16D086F533D1885A82F73C
+                               F2AD2C645591F80ED09942F0A08D898C
+            stream[256..319] = C214B6AC700164FA66DE346A27A99463
+                               C5B6C0E43A9057384BE168E163058FCB
+                               6E7DEC871C6531EFC8B8D581EF92757E
+                               219294D39E0C9C8276440BE56C3D9941
+            stream[448..511] = 22CF14F5BD70E719AFE76C53E5D611AE
+                               4C8D2171695C9CF97E2936A8BB320670
+                               015825547A508EB43D96F2EE1EE2CB34
+                               4E120F001500F8ACC3E19E30455D09D0
+                  xor-digest = FE5928C74EA21F23E29171E5AAACA20C
+                               DD8571E907763C96B99A8C11F9A1D2F5
+                               78F68A6C440996995F7AB6E69B3CCE33
+                               CF8CE0C16F54355696D47DBF82EA8D56
+
+Set 2, vector#198:
+                         key = C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 75559677D7C762F6CFED942D800F2FAB
+                               AB5F3892DC2C79922E96FD34FE511C11
+                               251C8EB7C639E531CE08A8C99F62E7BC
+                               F68FBAFF99D62348FF91CCFEC2710055
+            stream[192..255] = 149806A4D862EEA81F0208D927339E5E
+                               C98E9C2A6E0DB85CC0380DED7EC5B8AC
+                               4ADAE76AEB9C7B7264C3834316209615
+                               25221D58C0174577110596FF89C8FC69
+            stream[256..319] = 137E527A0ACB8B96A9FA07890B60B78B
+                               3CDD19BF89B31FF75A814F470BF97E0E
+                               1293B750B769F5BDD750DE5025D7534C
+                               AD541A1F26C6AE9AC2FD3237C156AEBB
+            stream[448..511] = 0958243E88921B81F04AE63658E52D76
+                               CF2638495B3A6B970633A7C8F67B8CF9
+                               AC378082F72FC63BEA02881CC5B28D9D
+                               C8C261C78B2872B5EBFC82336D6E1A28
+                  xor-digest = 0084D7BED4953402FE8F7FF71A28CEC7
+                               0028A08A00EF935C06A8B3632DAD5914
+                               84E44E372A753F8E630741266C0F4218
+                               4923608103042C70ED4ECC5112B9AF6B
+
+Set 2, vector#207:
+                         key = CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0C46BF67A3DBA5DCCF8E4A7A65B6FE28
+                               98C701CBF5E88F1F3DCB6B873E5CAEEF
+                               23024ADA678E1A2CA9E25AA8B476CF4F
+                               9FCBC297FF03A9B94A5A736274EA776C
+            stream[192..255] = 73B9891D1770289A67D6338909FB6282
+                               9A425B7947FC30DC52B11E398E85B1EB
+                               537E1C02898FEBFC15A9172C254CA55A
+                               AA1B56EA856F47E37E2F252D92D94ED8
+            stream[256..319] = 6522D372F90F2DAC155D48F165B6DFA4
+                               38B63B9F436FE00CC075C585297B8F90
+                               E6062358D29641FF9C28EED4A23FC53A
+                               6B5C60C2AF1E8146DB27CCF5F43BA838
+            stream[448..511] = 642541A9733946827D79BBD815C03C17
+                               6357BD6E81E9A61FFFD4A0BF6863AC71
+                               72AEFB92C1F235641BBE1457B724A6AA
+                               AF9FAC687552A778B034C4A4F8E41ADE
+                  xor-digest = 9DDBC1E7D31379D027B4F3DFD72C3668
+                               BD0BC5A97655978E79056B3D25DF3E79
+                               5D5D8BE5D1AAE877F2E7D03225CB6609
+                               6EFE11CBCB728039A243E326437CE73B
+
+Set 2, vector#216:
+                         key = D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DBD4E866F4E24E7F66816CAF625BD07F
+                               1F7BDFBB81428FFEE9FBE14DF5F5F3D8
+                               A044EF53A868D989E16165A0F2B95E8D
+                               83439BB4805A125AD0CA7994AE11B852
+            stream[192..255] = 7CACC4E7B9B1957ABB22ECB9D9D67184
+                               EE7A7F4B822A1C955A69E238022AA313
+                               276C2003E27AEF1B4F94B33A6428685B
+                               F048B357EAB297B7DD98E612F054A317
+            stream[256..319] = 286B484FA80A45EE4D5300DFBE173E8C
+                               978B976BE1B6CB0D15C0324D6B70D265
+                               385B615B3EA97A55D94C47F53FF40861
+                               4460857AC9568556AE54A52546B41B5A
+            stream[448..511] = B3AD999394343F6F0BDDD0B1FAE2E3A6
+                               5BE2BF56D2B78A401D5761E2F3AF8B18
+                               A2B1089864999D9B99E5BF6959F8F802
+                               975FBF204D6159CF23F3706CAF0D9BA5
+                  xor-digest = 0957D6887501D4360C430614B67D99B5
+                               32849E2F5C69CE8A9F3F707A2B5438BD
+                               0C1237B5617FB525CC9C043A10DBB265
+                               3C3F0A353E89A19838B8F68542E09526
+
+Set 2, vector#225:
+                         key = E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A6DF8DEE1EF7D1AF773AA3E9651B645A
+                               50CF101BF065F69F3E78BEF5D689B1D1
+                               D306FF41EB3E78BEB75C4200937CFE60
+                               E89E370680C519B2F64E23516ADF8062
+            stream[192..255] = AA30580A210B87727BE17EC52AAAD037
+                               3E0DD11FBFC89B37825CA4D6F9E8D433
+                               E3EA54C37D678B58CE834AFA310F6D4D
+                               06B4603F12DBF38595AC76511D0B13CF
+            stream[256..319] = 5F3E1A55116CB67BC91C8E37182EEEEC
+                               8FC9B09DAA6F418D3434BFBBFF6BFFFB
+                               F93F8A963F2F51CC487BE868F010EC0B
+                               EE17A480542A301E33B36F59BEE13D91
+            stream[448..511] = 672048756C221C12DA6178BE711B3371
+                               525A92BC9A219CABC5501B0DA4CC248B
+                               8742E8BCBD6F5A1CFE522F3DF3BED6B6
+                               5D60D1AC737ADC582C2CB9751521828B
+                  xor-digest = E7CA739E4DE0E74274E491CAA9BF5CAB
+                               3F418EBEB69509D69B2594E964759D15
+                               104F674CD44681AFECC3B4939CA0A0C9
+                               DD7AA5726653ED3FBFC833DDB0C87B42
+
+Set 2, vector#234:
+                         key = EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 2479A8F2872A813D16D15F060D300237
+                               25297B812F6F3B97D74D9716E4403A5A
+                               684D2BFD1E15275470FEDADF1578277E
+                               44C6C06B8A5FCE3D0CCC5E13BF49947C
+            stream[192..255] = DB2F9B25F9523FF5C2CCCB808EFE07F3
+                               132D4B0065A563288F848E05EB45E48B
+                               D15C069C02F90B4FC10AEBF1AF4BF90E
+                               2CF7F48C8CD7A8091014131EBC21FBE8
+            stream[256..319] = 84FAF79797E25BF2CFD54E58F5C7AC1C
+                               EC170B064429EB832924CDA9C47B5174
+                               9BFEF80D96FAE36DDA65659FEA1CC06B
+                               4EA3A1601A3304AA4DDBEB62381FD4DB
+            stream[448..511] = 2C8FC8D23E7DBBC37BB0811D1BC71145
+                               BFBCDBAE19F5281CD0E6AA37419778DA
+                               64DDF68726DD7F4D78BBBFF4576C2AAD
+                               93F477A2AB2C3CA8A381F30BB944C7B0
+                  xor-digest = A6D5F0DDFC0A43491D6D0A17C095C070
+                               9EC7E9B89DB8EEA11045ACC5FF003DC9
+                               CD3318BB6F9675EEF20E15490F525066
+                               AF8380C663B60EDBAE30663C94C39892
+
+Set 2, vector#243:
+                         key = F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CC3701E703946194401D1BA23AD99B5D
+                               F3F856138E142D4B9C23DC9F252A277B
+                               D62DAA33A71A0C61079AD5A20562291A
+                               B6EC92C66D7BE6A17E27D4DDB48EFD31
+            stream[192..255] = D00665FC0A4ACC78758EF25B0B0D6903
+                               D565423614409AD11E821B83F5B35D83
+                               F26F3EF9EC1766FEA9C21C09E0AE248F
+                               4BA01E48BCE09D06471593B3466703DD
+            stream[256..319] = E8B4EEE2C8BBEDBA758C1C2D0889FDDF
+                               96CDC215EF1A62FAA29A5608C852FFA1
+                               18B473C5A7319446F3ED2E8AB39A533D
+                               714325D1B14E838C9EC6E037DB0DD93C
+            stream[448..511] = 4FF3B43841B17A279002EFB07324625B
+                               7E937D480DC73F12836195110ECB4DB5
+                               CD31CA4F92F612A95E82815328DA7D5E
+                               4DCC5BB6791603EDA64C57B5A5AAA04C
+                  xor-digest = 9202B874C48D4B1A9E857E645EE8F884
+                               D971CE97923AC024ABEFB944E34550CE
+                               31712BB832F9174F86FCD369E75CA9AD
+                               85095F43A4B7F33AB641BD6912D2C59C
+
+Set 2, vector#252:
+                         key = FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F374DA745A5CF93A567027609E5D3B1D
+                               5C3C8A4D15203705D978AD42279F6548
+                               51FF713F5120CC93D044EF717F5A75E4
+                               98DBEF559E5F157A8C819E213E93B3F4
+            stream[192..255] = B270F638AAB88DFF69D724F79B70CEC9
+                               175AEAA99D55485954B265B5CAB86509
+                               C810E664766A8E6C90D4BEE3A58B1815
+                               9076959FFFA2F30EEB12343E9E7778C5
+            stream[256..319] = B2CC84A1127B5333B30EC81CC14307FC
+                               418DA96336991A27DADA74FDA987B867
+                               B125C53C0E4E2889FDFEFBFB48797A22
+                               2836B2EA42793CE2BFFD568F6234B368
+            stream[448..511] = B70F4A10A1B75D499E8189C8B92AFB36
+                               4CD2D730DC8D7E183EC55A777C2445EB
+                               BA7E9CD95C8F3A206B73C422AC2E2C08
+                               15A8C6FED156FFF93B63DE512EF69725
+                  xor-digest = 467EDA43B849054EE747A532ED0D9AA4
+                               6EA1BF2B6AF19F481D6E3D55EBAA96FC
+                               6629FE65B5EC4B5EB6A155A6D60FEA32
+                               F04F8230E26390F1C8FA53D47B68FEAE
+
+Test vectors -- set 3
+=====================
+
+Set 3, vector#  0:
+                         key = 000102030405060708090A0B0C0D0E0F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0315CE93BE05F88212B413335CA65F33
+                               6387BA612421C7BE8276299CC178EC31
+                               2143C503A9F2644685882201137BBBD7
+                               3A2385F0AD14B690281B54B8DC064150
+            stream[192..255] = 8B663563AE31DCE7AC61BF4943466774
+                               E9EE784644AA761B9D8AA9B8E04D4C91
+                               75650DDF130454DD60724864DF2FB6B4
+                               31F947F8FCA83F6D3B113BC413D3CC10
+            stream[256..319] = 35EE3D4294E5660A99A1A1C9254D27A4
+                               B42FEA8CBD5C5BD8B902E1B1BFEF17D6
+                               ADC9B6B924C7C53D44A5C58210989BE8
+                               72E532300EA9115CD2AAC8024779B3FC
+            stream[448..511] = 402F841F64827A197FC56EE9C180F5D1
+                               075107622178407B063F70C6C860C6EA
+                               E3016D56F7CDC13A109283F5F4FC9420
+                               6C62BC3D1012EA03EE08EBE8C2DC074A
+                  xor-digest = 6815E00D7D3414FCB103EA82B38FD4F4
+                               68A453E84A520B7119E9D3A4C938BF0B
+                               AC26F7F73EDA7F3E2F20FBA551C15205
+                               EBBF2F6BFE6DBAF95061F0AB3988DD57
+
+Set 3, vector#  9:
+                         key = 090A0B0C0D0E0F101112131415161718
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E695E5417AEC9FBFC0EB0909435E79C6
+                               76AB8E2F28C556CC2C81CFC5F7A2A6F1
+                               254EC0CD2CFAFC257907723557C1DF5A
+                               D81D1E3D201410A12A5FA3A6160F266F
+            stream[192..255] = E3D590D9AF3869FFCBE2A4B8C77A09F6
+                               211193F83B8A43714CCFC02D014376C5
+                               A44FF7C061471AE208F04DCAA89792FF
+                               AE7096EAC47898C1011095DE9B55682F
+            stream[256..319] = 0F31D78C0B86D246FE105AA6D9B93CE0
+                               257E75CC0D2A0BE96B9156555D8A407E
+                               01F47AFF719CC894EE111C32672B0404
+                               B5F26C1DB1D7D0F9E470900AE53B192E
+            stream[448..511] = 1A01733BB8EACDF2B2F4322FB54FB6CB
+                               C92989248FF31BBAAA8304ECC4AF9A39
+                               CAB21BB66E0A144D8B77C537BD52DDD8
+                               C5B0909CC6423D4F243E5AFE6E22D07D
+                  xor-digest = F8C3BF6905A19184D14039E4B7FCFACF
+                               2EFA004B35B55DD04F56199C6C9DE1B4
+                               458C5EFAC45C6062BA1EB726426987ED
+                               88FA899849CF5F6CEF60119F6A68AF9B
+
+Set 3, vector# 18:
+                         key = 12131415161718191A1B1C1D1E1F2021
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3C189DEDA71E56926CA2C3A2974C4FAA
+                               B7EA3C1250E768CEA797ABD6477B59F0
+                               E5494635CB4700A95BBD54B0E93D12A6
+                               423DF8F34BC6B3BE705ED6704BA33894
+            stream[192..255] = F21E411ACF063846BF68F61F7673710D
+                               CFBF8088E2A815F406E17C4BF4E839AA
+                               D2EB9D137B0F7889E68F4B5C8160199A
+                               7C9C697EA6A1794E954ACB535A72B255
+            stream[256..319] = BD7E1C4A54C911E84067AB00F8427810
+                               BDBF4029E78D424E65F477BEB457900D
+                               0EA49B639863BAEB1427A161B8C629D3
+                               55097F5DFFB24BB97329A73B144DB7CA
+            stream[448..511] = A4D9A80D0055F2D8C55D2A49B39DCA69
+                               9A5652C43258152B42BECDE07F21F8D0
+                               EAAC565DCDE549CA4A9A27D82F5AF4BB
+                               1EEB1B0A53A58E50C3E83CBCDCB980F5
+                  xor-digest = FF451365606D0117E15FC2721F40C9CC
+                               0FBF6442A771F8FC3B06186C35C6CA13
+                               B30F65FC84B9A38A6FBA2B6F16541B0A
+                               0D77BDB4F696894B2B73CCCB8D6FA3B7
+
+Set 3, vector# 27:
+                         key = 1B1C1D1E1F202122232425262728292A
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = BE4A26D09D47D25416355FB7FF60AA06
+                               3B3CDE5374780F2C66514A0CAA07406A
+                               88490A2E3D6294A799C9BAAAA1B10ACB
+                               88FF4F6F70EF1F4F67D591040244FEE8
+            stream[192..255] = 54F1AB7235B6440D6A7FC7851E3FFDA8
+                               6CAF44E3F57E1E9406908064FDDA3A3A
+                               3C7AA1CB6ECAAF376C5F290EA02844EA
+                               779A225131F24D2E7D34AD0342399FED
+            stream[256..319] = 81AC4F45FC40CE7E1FF890F5EFF2B583
+                               36F71D1911C7E0227AD8E4DFF7369B41
+                               A8C266B3468A78773C4C40A3EEA6B724
+                               97662462F48835FAC7B6C77CEFD39A65
+            stream[448..511] = CACFA9A51224F533C600BEFF1EC03C7C
+                               7C22EDF93E8596128F8709F0CED4E291
+                               997229AC5542FD2CC9B1167C3D2BB57D
+                               9B08B82C0FC41D93B7CE2211C5E2D534
+                  xor-digest = 0D949205B6024DAC1D215F2AEA7CB484
+                               3FAA9A1719398AB8828A28BD2568369A
+                               C78A224AAD95BAE6A6333C4C13D630B9
+                               42AA52099F6EFD6871B1E45C8DC68AC7
+
+Set 3, vector# 36:
+                         key = 2425262728292A2B2C2D2E2F30313233
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 65906EA9CC0080D2044671D22C7DE242
+                               F764184ABE8DADBCD550225BFD541D6A
+                               762C7A5268EA0ECE51D18269E71A4CCC
+                               054AF634616204C81AE7E515719775DF
+            stream[192..255] = 9ED75834EBBD9576E11DCE8C583ECEDD
+                               2B8780FE98B44E9F08BBE96922C77BEF
+                               08DCE0DFD7C77C42236885BE6EDC8343
+                               24EAED350AA5A513009272818CBC4BE5
+            stream[256..319] = EB1D998260B3AF4472DE59E1C9DD359A
+                               B346B32DCE36C92C9B7BD808BAB76AB1
+                               EDCA2827557501BE0FE28F6498B33B9A
+                               F4EA48786F3158E8047A32A03AE1CD90
+            stream[448..511] = D06B1B9B8110FB9809F5887A35CB24BB
+                               80EDE203AE648AF9FA348B18D8A15B8E
+                               E98E8AB98A7AC5BF71FDEAA1A6E978F6
+                               7D5734AA7FA88E8DA44C861E2F54E585
+                  xor-digest = E77DF8C1D5F46F8896DD00187C840B0A
+                               E4404581DD053C6F39323815729DCE90
+                               0D85C2D8C97D0A3B57CF622F81077B80
+                               92988EFFA36CA176F7393D1E38AAB206
+
+Set 3, vector# 45:
+                         key = 2D2E2F303132333435363738393A3B3C
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3FBFE9A391DE0CE5AAEBF9DA3A15EB99
+                               D6CBAD0341CB78042C89F5D5B0B555C8
+                               A400DC47FD19F40493B348CB51430B44
+                               D05AFCA9D399709EFAB8ED2587F72E85
+            stream[192..255] = 68969047EE54910C44F8B5718E993234
+                               D814C27C0B59EE09F0D35B58352AA6C6
+                               594F605C25C16CDDC29A354A1C6F5948
+                               AE497C093E2D41C211E4C1417DFAAFC4
+            stream[256..319] = 0DD68E08A25ACA4448DF4B562EEBB855
+                               14E41F1F560C479542FE62C2DCBCF03C
+                               30AF180FB71E65A9A09C551551A33942
+                               53558C2440084E6B4CB664A4EAFCAB66
+            stream[448..511] = D93B80D67B6484030103CDD72536E695
+                               E7BAF8B1115109D5D5517BD1E06F4236
+                               A3551688F5C0D78B2CB080AC072B4C48
+                               94A2AF54AD9D816E2068AC569BCD2AE2
+                  xor-digest = 7C071BF395B48A023A7B708A9651EC8F
+                               0C9A00DE8BD9D0764C7F1F394AA2B747
+                               3EF87BF792D5B89AE0548EB9C1344DAB
+                               DF2E4EC6064D50EE1622160D6DD7ADFE
+
+Set 3, vector# 54:
+                         key = 363738393A3B3C3D3E3F404142434445
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 64468807E7EFE78E11B0231D8D7AE80D
+                               BFF3FAE444A60496C8F2DA202941686B
+                               95C48457C1F9DE1AD2FE581336AE36AB
+                               CA574BCB9619CDDB96E4499409516635
+            stream[192..255] = A7DBFEAD9B969D334705B6C53A0CDBC2
+                               21E0BB92854B0B107CC39F8C6E4761C3
+                               EACC8D8C5741AA4243C5BE1A79971A0A
+                               5A23F2BEDE9F3628CB9099B8C7EA9324
+            stream[256..319] = 1A44FB18740973F3124EA805C90C4B27
+                               4EE788D43F4B894B01F63C13410EC204
+                               2607241E87555B0E1A6FF33AF0DB010B
+                               8ADF607E6353FCF74F568E0BAF0F4455
+            stream[448..511] = 11568B95495E520EB6BE106986A07C57
+                               8FDF21463607619E5AAF117D84611E75
+                               F8979F59E60B43C0A37BC24429892742
+                               0D206274DA45EBBA7660422DA45294CD
+                  xor-digest = A70B9BFC683AF2716E17980A49C4F747
+                               AC25992BA7BCA5E5C2AE162497E4E8BB
+                               62C837F64EEBE4A55B5705F115CBA057
+                               C560B1AF0A733B5631E23442601A741F
+
+Set 3, vector# 63:
+                         key = 3F404142434445464748494A4B4C4D4E
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 35865AF843244DD2F95CDF7C9BD54471
+                               9C8432538842C28F93AA21F6E10F8B18
+                               31C2AA7EC010A66E539CF65BE55120BF
+                               090233750995003C7AE414DA6D55F86C
+            stream[192..255] = 190F215FD14E44CD141E47A2322D324A
+                               A63A7B512A77C20A02D3BFC1EF8273C8
+                               F65226CBD1BF32A104D1AFEFD6719E4B
+                               DD6355B044EC8D0CE95023C61007E6BB
+            stream[256..319] = BD02130F7CFDBDBC2171BBDEAB501136
+                               B2364F5879E6E9CCA7E75AD81105D9E4
+                               87E9175B62AFCAD79B23D392B2E9C418
+                               437527118797602E629A70CC869AB7EC
+            stream[448..511] = 1F0DF396B5CA6EC9767B0674B2C7A9C9
+                               133CF872DA39DE78F56D41C7F2FF6B50
+                               716717E995D42C51D6A2ED66FA6CC7DA
+                               92E9B3B4D1F130E699C430CFC96969BB
+                  xor-digest = 70291060FEA7D40B5C3FF731FAF7630F
+                               D9BBED1A7FC25A05E6B3F632E6FD6B91
+                               1F1010E1BEC69F16D44C5183E38BE8DA
+                               8949A4D8AA85F5149C203F8C92887875
+
+Set 3, vector# 72:
+                         key = 48494A4B4C4D4E4F5051525354555657
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = BFFC0703408DF6EB169656D09A5400DD
+                               9C4BAF06A3BC7220E45814104B6D9000
+                               9585BF9B0CD988E94B8C5026D07AD7F5
+                               7D81364775D54D808A5C18453B62A2A1
+            stream[192..255] = 5FC95B73A4C91DB20B93319E420B4C5B
+                               A9DE1873C81C835CB455970A90921594
+                               F9635EF4F411C9ACB4298F75B2CC84F9
+                               7F52182F7F001A1EDF72A68FA1ADE313
+            stream[256..319] = FB24E97B0CCFE15644BAAFF342C55FDF
+                               64434708407AA6D73576E842D5ADF4A2
+                               6B32D329A2DC9F1451C4BF3E9599E9E6
+                               4E5E65F73E09E4F1254BA0DDD8E6C52C
+            stream[448..511] = E2EB303CD0A67C99CDCEE86BEA581FF7
+                               093C9228900B563C6D10B20BF99D3911
+                               D47C805D1447C8F233D3FDD27CF0DA42
+                               D42E0389E2CCE99A274AD9D20B9C6102
+                  xor-digest = F83FB58CAEC8B13BC25C152FCF24E10E
+                               392A197FDA05A6A20E14093EA0B34C5D
+                               FAE102266465324F5AC07FFCECC8E618
+                               D0BB60761A26D5FD59D188097A2348F3
+
+Set 3, vector# 81:
+                         key = 5152535455565758595A5B5C5D5E5F60
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 84076D83A841C8C6ADDE3B5D9FDD6529
+                               4D0F92B549112F0A6DE05236F732E81B
+                               3C8E92229C411D2295129ECD18DD08DD
+                               C98BA78D9BAFF6271D95E1F361EF699A
+            stream[192..255] = 7063A52FB2729433D8A7BF30F27E6EF6
+                               F17C2A422E60A737270787985508D062
+                               4E678A597845CA9EF939F4B8966BD99F
+                               B8633FEA673CE7BFD2ACFB5942D7EDD9
+            stream[256..319] = 4FCE866E8C2359C53F0429F569D02DAE
+                               E99A4062246B633D4C502DC897AD8025
+                               38C95D49D3B1FA94F4E92441357B622A
+                               6264F50D5554BBE42191AB3D6073A8AF
+            stream[448..511] = 2F7C38BD00309FC81D28D84EE4355216
+                               D97A823CC46FAB9DCAF621E4128F9CB8
+                               838BF02E0EF940EFE96860CC0B996044
+                               42CACFD3306335241C1B4B65E790233E
+                  xor-digest = 44038A33AF0013BB34CBCFB77F7E060B
+                               96F5134DFCDBF04EB8F7F29B15C3FDA0
+                               F766DC940FF548C23712625793851A94
+                               294CC7201E1EDC6056C12A46524C6FD0
+
+Set 3, vector# 90:
+                         key = 5A5B5C5D5E5F60616263646566676869
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E811CA3DD1DD0057AD3A1794D3F9CCB6
+                               362049B1692D6ACFE1A6A0FCC99C7A04
+                               3AB9932A146B4040AC9F8E2F0A227C7E
+                               C60B1F35D60EA14483BAE1F8D1AC7FE1
+            stream[192..255] = 865B05E224133AFC45043F05F8082FEA
+                               487BF63BCFB96DA3EE26960061446669
+                               B1C92C6BC5905BD1EB57D579CB62A220
+                               2F35CEB603658237AF1908132A25971C
+            stream[256..319] = A84BE383FC852F1BF44130EAD15B3548
+                               56737C7EA68A0700A22D357FBA70E031
+                               BDC0FE8EC36C41790A8B7706A00CA338
+                               603E054A83881599D718B1911D1CE9D4
+            stream[448..511] = 9286C3479F9A17B51D8749257F59E892
+                               CE7C3EB8638B29C17D779811F01EA405
+                               257062A5F28BCDA1862FE653C7607350
+                               9A87D12EDC5CAAFF9E8F9F76DA0BEDE2
+                  xor-digest = D629CA4708BEF7EED04BB5531DDF9C64
+                               BA4981C9A705D59C4B2391E94B79CFCD
+                               058406845D81E7EBC097330C01FCBCF8
+                               D78940893B4FA38554A32D861AE96D04
+
+Set 3, vector# 99:
+                         key = 636465666768696A6B6C6D6E6F707172
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B89516368AFEEEC12434F76AD1E1ECA8
+                               FF6FEF7B46D05EDD6041C7B8C1E3A33D
+                               2818E38113592B615E980304D93435DF
+                               BDD5676225173331C3667F30AA2A3D2C
+            stream[192..255] = 249528FA392B19B6811711F523D27578
+                               F1BDE75CA167DDEC08303906B64FAC0F
+                               B2912A7A0EDBEDAF9FEDA420DEA330CA
+                               7302F5780827CB11B15A4DD333FD7099
+            stream[256..319] = CECC1B5077BCB9E129B01D8D75089B41
+                               64E76DBC9C8CF2E4D2F17A6248522A51
+                               FCFBFBC992F75D613307F4DD6472B6DF
+                               C8A5B29F1068FC0F1C3F8964B0E09170
+            stream[448..511] = 8B26C436E918B099E4D3A7D4D3395E49
+                               056A8A29130667A32C6A2B0FD08A482F
+                               8F7538ED90374846FFD2E1C733AFFDA1
+                               12148C9718F3F208344D5FC20128AE2C
+                  xor-digest = EAA0ACA59CF63BC27082BD52D6757FD7
+                               620A7AC5AA2FAEC52646978E2057C5FC
+                               F60B36C09D87419C1D1A64133357DB05
+                               6B96C854F38C36DD657524FD09729341
+
+Set 3, vector#108:
+                         key = 6C6D6E6F707172737475767778797A7B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 741C607A6BD38F93B33244C8B7F05D78
+                               46F6A05CEE5A87762480DE123D3BEE63
+                               240928FFC75ECD9AD1785B1664DCB59B
+                               A12F3B64C93BD4FC8C67C0934E5B0ABD
+            stream[192..255] = 3BDB31A701DD7F2E929803C3A47896F0
+                               9E5F569A32AA829E505E34BB7232597D
+                               B838F543A34CC288F9518BE16A228D42
+                               BED0CA3CE0C6E7FF9AEE63625C699B9A
+            stream[256..319] = 1CB7FE159EC1A57043BD142236DC0A18
+                               0CEF37316A6E96354AE319142282F19C
+                               1550EB645DA8F7BEE2ABAE4EAAC0BA29
+                               893E722A6F8E0A9B34368DF56C5845B4
+            stream[448..511] = B6DF810D69EAFB7F2360F6ECB50C5861
+                               7D32B3F495B3E4424045E88CFA0871A2
+                               9314121CC78B98B456ADF53E540346B1
+                               214AE2ADB65C552273F1FA498FA74101
+                  xor-digest = D35A8AE5783348824175BD34F2E16FBB
+                               975E7695DC6C4FF1ED763D404B0D4D30
+                               07AAF01E988BC85DB2FDD017691D3BB9
+                               811355C3C7A6156197AF57B794DCE85D
+
+Set 3, vector#117:
+                         key = 75767778797A7B7C7D7E7F8081828384
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = EA9DA2D5BD4B6E070479ABF8CA2D1B3A
+                               6B968A025D010944FEB51AB2E507F86B
+                               111F8A351A3F32CE1FBC4A75AC34F722
+                               1B5190F2390073084F8153E00BB98D0E
+            stream[192..255] = 0AE0DC3D0E2D3F5F93E446BEBECC4F60
+                               862D190829A209966E132DD029ED6998
+                               DEF4F613F3D53D0A36CFBA2CFE345DCF
+                               013B6CFFEC0116FFC1659A57FB42E0BE
+            stream[256..319] = 5A7FF46C335912389D8B88437CEFD27B
+                               76706405F45F87C91390273D9B70CC5D
+                               89FDFA85E20EC82B98A79BFF5FBF6AB1
+                               4F61F2C1289CD7B8357126C8E13271AD
+            stream[448..511] = 9398E699F5AD8FF31A50C8EFB9DF0D0C
+                               FD612B951A203C1BF85C62AB5AF1C412
+                               42BFD0A55F21820C6F917EC90A8FCAB2
+                               E774A93713A99C7900B80A2BF496D0AF
+                  xor-digest = 05D9732FF20A61E19428873830DA7282
+                               819234F22FE7DFD8871C21CF10C08EF0
+                               7C0413898DB144861B0CCB62992DF40B
+                               29A0A4688C91275F0A198AF39899E362
+
+Set 3, vector#126:
+                         key = 7E7F808182838485868788898A8B8C8D
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 8C4F8495C7231AAEB704E7AB9E79E748
+                               6CB5BC85D3622B8A2E2CB778BBFDACD4
+                               CEF73CC485D8E08406F5986A28706CD0
+                               56D085201DEDB875573B57629B8541C6
+            stream[192..255] = CC6374A744E9205CA39BCD678074B844
+                               16346A7E54F9B87905BADD2FACE7B9F4
+                               B0A366AA3F632A7A67AD8AAC4827C9BB
+                               A1E801A8786BC4FAC2ADE6A6AD6A45F4
+            stream[256..319] = 4F52AAB001BE94A60761CDE0334F8A84
+                               C617195B084E441070E343CEC3189CF6
+                               D6D955F9AD649A3891BDFFACA0A6E6E7
+                               7291396670BA07469D267EB80E48353A
+            stream[448..511] = 673AF85AD5A9A3F26CBABCE9BEBBAE21
+                               E0B6DCCC3256227FC0EAEDF343CC7E9A
+                               8896023DF073E88EEEF135BE34CF67A5
+                               5FB51D3A1754B15A7C4E2CCCB4C8D51C
+                  xor-digest = 2BD4B8BF9B7E79B0EB53318396B03575
+                               0AC918A6A05BBA499D81C9EFD32A0FCA
+                               34A83FC801CD6475A774091F33AE7689
+                               B9FE28645F545E9A9531F528085926F1
+
+Set 3, vector#135:
+                         key = 8788898A8B8C8D8E8F90919293949596
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = BDF2E95B80FDF304C3C4A8081391EDC9
+                               7F9553F93C27788F03797EDEBB8F59EC
+                               2FB2FCCA7727CA1CAEBF5C8DA8719492
+                               F1369D96B2FEFA23D89400CF7CA667EC
+            stream[192..255] = 6AB7500D876A4924DE59800345AD69FB
+                               BA1690733713BF372E0108D9FB65B0E4
+                               50BB89899AB84198381623094F823FF4
+                               8BF9A09F0FCA23684E78654F3D231173
+            stream[256..319] = 34ED638D249BB1AB8B16D350309AE32B
+                               9FB62CAB0EC7AB9D5F3C12C9A6502497
+                               6323EBBBC4CF308FFA68A3D4D8D3959E
+                               AFD3BE46E36072FD15A5DC3FCDECA6D1
+            stream[448..511] = A8BA33AF6CF545424E607A7FC4CBA593
+                               CB05B38C836B21D85B6FB1894926A459
+                               8D71AB424A5A582A491747FED94125D1
+                               08D6C693EC9E4BDE2F418810A921B54F
+                  xor-digest = 84F29F11524741D39779025D792AB735
+                               07963EAA0FA8EE220ECD3592E1320567
+                               BFE76EFC3356860192DDC5F06B94E552
+                               43D659D49FB94C30AB69AB5E9C370A5B
+
+Set 3, vector#144:
+                         key = 909192939495969798999A9B9C9D9E9F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 1C03A0D6CB75670CD7D978B2E371857E
+                               27E597B15B905D5F4F4384FEC227073B
+                               5A56D8C0C4AF767F267DDEFF86AA036C
+                               41EB6170603AEB3E3C1EF3E176CED812
+            stream[192..255] = 6447D1E067550DEC9E8AE89DB02B85B4
+                               3DD7E511C8B98438BAA50CFAF7CDBB68
+                               757DA1D03A29B9EC6BD633E17BEBC8EB
+                               2D8D453F583E4D183AF30C9F47C8DD56
+            stream[256..319] = B324756101C28D9FC4D1F065F1D000F4
+                               1155514EDB30A7FE36C26B18FD93D6D2
+                               0470A41B6F8D2E8BE140568BF72223F0
+                               981CEB9D100B21C8B751BA6B2816B2D0
+            stream[448..511] = 304AADCAE0CE80E91E3558974A944663
+                               D1E2253977CD7B0D1BFAA138DD81A501
+                               D7EADD8FC834931A44642BA9873AC1B2
+                               47A454EE71F7AD8671BC15E088D01532
+                  xor-digest = 5980D43A91C09B20B0F3323F1750CB47
+                               118550920627B6C512AC5CC53AA6AD25
+                               68EE1EFE702FEDE7CADBFA25B32696FA
+                               12A18CCDE35A1B679F709F28920DF92C
+
+Set 3, vector#153:
+                         key = 999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C2083A758037E850A6FE642EFDE59AED
+                               F51F3002BEE2E69DBDB538BE2D93EE8B
+                               27A1CC89672DC14C44DADE531A88A769
+                               5DC730A2CDF3096DE7F4BD08A1ABA918
+            stream[192..255] = F4D19950E6365AE6BE8011A24B9D803A
+                               D9A8547D452D8B0B8C51676E207DF323
+                               808B5A094A2FDEA5DBC86BFCA576E98E
+                               D0E049834CBE0B3AFAD6892B542EC7AF
+            stream[256..319] = 8F2A026EB2165F39E27DB86607878926
+                               4EC8F42A09E8C80B317FD4F1E32AF4C3
+                               73B7F5160C635ECABE495B01A3488E27
+                               94D226E2D86C4654810C08B2FC42610D
+            stream[448..511] = A1D17725577B7A4FD3D1A280BA2B5C0C
+                               386FCFA09E110F00C85ECA05CC142644
+                               4D8EB87CCDC2B23D1CDBBFFF822B5555
+                               11055B93ADC9168B7353CAE10551AF14
+                  xor-digest = 7B4E8A6123216818A218FBD50D8540B0
+                               A0B62DC114F25DD476680F85DEEA9306
+                               4CBC4526C7A8832D4BC534684A403FE7
+                               B80E7F20D967ECE044085B554C158AFA
+
+Set 3, vector#162:
+                         key = A2A3A4A5A6A7A8A9AAABACADAEAFB0B1
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 6FB232154275843C74BB886D09CBE0EC
+                               CCC539DD6DEC1EC6F31578B80DD3BAD8
+                               5C992CB1A0B4EA40B3EE0C5174E36A74
+                               E1CDCAB13830453984E4365A6C599F72
+            stream[192..255] = 2682C05E19F6D8FC4DDB15B2F8385B52
+                               C5A4A70FF5A0063CD696AADBF8505122
+                               6F696746D4F8C314543BC3869B1E7F9B
+                               1C0D004655FB6585723CD1EA7A700A60
+            stream[256..319] = D6BA4C5A33B8C2DE342DE48E26AE7B14
+                               8E91552D0E05AC9458ED0010E6FF53AE
+                               EDE70E910165B5986876799E60B7E6BF
+                               3109B9BAF7EE3670497FA7CAFCB14733
+            stream[448..511] = 70C4E8AB8E8BA681A2A06F319CBC952E
+                               E3E78DA589369FEEF8A6BC6D976BECFE
+                               E6C7143337758929FCA7E0945892411B
+                               047C2CC2F2AA284E95733DD94D46B89B
+                  xor-digest = E2D3DD6AC908FF3BAE4791A50F717B63
+                               FB3F1F380CC738E2B1626FD026C9BEBC
+                               33957AF4ED6E8B9864EEEAE262FC6168
+                               9A34FA14A35BD915B6945F35BC3D5573
+
+Set 3, vector#171:
+                         key = ABACADAEAFB0B1B2B3B4B5B6B7B8B9BA
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = D25BF02A1BB050E0D15246C2EFB3EB89
+                               390BB913916D347586DCDF71D6792CC6
+                               BF72F6F6A9B779BD8833C468684B4480
+                               52E153D11A0CE183CB337450C4482F6B
+            stream[192..255] = 07980A2C57E9094C5334016A782C830E
+                               B59420086EF9D36542A97220A5EEFE42
+                               026B39B1F00A78992ECA17FCDDCEEA2F
+                               88A15F934A1C65EFB770C2FB9712FFF2
+            stream[256..319] = 8C0AF45C68CB7CA8CFF1AB18F2F9659D
+                               E49DB5C4E3609B50C06F94FC01C059B5
+                               40E302FA8604F030701FE3C833617E0B
+                               094D0BBF10580F7C1C7047E86FBF93E2
+            stream[448..511] = 4D4BEFAB68D63085A05C729F54468567
+                               2C2A9452DF6B4B651A29FBC29513E3C9
+                               635DFD75EAC87A5B1362E99033304EF5
+                               DF42420DFD49C1830D66F4F90928F1AE
+                  xor-digest = 9A7DD8AA5D9E9DA4F34AFBDE9D909CE5
+                               DEBC05D2F930FF08AEEE4096B2E1E453
+                               8587B88E535A217E986F31965C5965DE
+                               3BF4A7F99B3B9D938D2C1AF7DFEFA14A
+
+Set 3, vector#180:
+                         key = B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 5FB2BFB5B9CC4F84D7641B4555DA4A7F
+                               C07C0053E7AD2CF2187F7F34ED4068AC
+                               6D5B43A5FA41437C05C65550786D60F9
+                               A737F44BE450A1F416C1B1A49890C609
+            stream[192..255] = 8EDCA89958225E39CF796EE587877A55
+                               F9B7A7381241597CA6280F7617A11922
+                               9268F95BB326585AB59F08BFCE8B5638
+                               B3A0D32A761C796060DFEBB5BCE859D5
+            stream[256..319] = 09601C099BAC574564E4CC6FD659776E
+                               4726FB22E0025C37873042866B913C03
+                               285EA24E37847F9AF6C838B82FE651D4
+                               EC5FBD40A256E6C765757B6A3CD08C92
+            stream[448..511] = CA5AC4ED4FBEF0D754F033B5267B9FDF
+                               3CA52B131E118174F70CD4F833A5ABBB
+                               198DBCDF18BABB0B0CC37ECFC8D93AA1
+                               5949FBB21974169B46D545F0ED03C71D
+                  xor-digest = 5DAFDEBC75291BA8F55B4A370756B28F
+                               554FEADDB7888F2834BA1EF221E917F5
+                               F631D5BD789701282DCF16FA450D250B
+                               52C627741369DA654E237B8D7F4A8BA0
+
+Set 3, vector#189:
+                         key = BDBEBFC0C1C2C3C4C5C6C7C8C9CACBCC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E9EAE6C4903004A2AFCD05FE2E3E7F95
+                               FF8BD2888C4AEBB81CDBBCB7488C54E5
+                               B50467FA82B0CA7EA923C608074E1B45
+                               6452821FC36789C8061E99E8A0C0B579
+            stream[192..255] = 1EC898A6958F23C186261F833BB3EF0B
+                               3C185AE8138311B6AB42098E9C6C7FE1
+                               0306DADE1DBF2B1C3215DEBD88AF1CBD
+                               2D805B8006FA0DCF136E225AE3D91AA3
+            stream[256..319] = 55566604D1C85FFE1D29810B6C49F019
+                               69ACB59765A3FBA2B0B9880064606E47
+                               18BC5F08C32EFC250FEE91FB88077A2E
+                               0840615CCF627C64FBB500B7B800B9CD
+            stream[448..511] = 707821EFE4119A32CFD99F7ED7CEC018
+                               C8EE90493FD9268A83E5482DAF9A646E
+                               8765D8199A56A12ECA50775099179D70
+                               B72A3CEC8F0EFF1AFD074F04548874E3
+                  xor-digest = A51E3C9C948B68A1543FDD1F158DD419
+                               195AE7662739446D9FD543681A866A6C
+                               F09756FF4E0C59BDEFFBF98D53F193A1
+                               77D7BF19320063B8AEEC8A544D5D72C7
+
+Set 3, vector#198:
+                         key = C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = EAA9729F0222A16C750540C605974B55
+                               4FA622F67C71FBA40236A71AC19706F7
+                               9E3792F4B444A39C9C1C902FDBD81898
+                               096338F6A8EB7C934B9558D48AC53301
+            stream[192..255] = 3B5E53787C050061000E3622876AA126
+                               00971A76253833C53B9DABA976169395
+                               3944B5050AB17E492E185737D67581B8
+                               B1C766D50C5B0C2B0D8C78A781E77D89
+            stream[256..319] = 175C28764FEAF8396B3CD34C829D0D0B
+                               E9CE0D75E79017A96C4E7B158B171BE9
+                               4C906FD4BD4946E6DEEC3C78B34C0754
+                               9E85AFCD958AF345E0B432F33C86AA76
+            stream[448..511] = 37BDD665CD9D5A8A8190AC3EEF981379
+                               AD5311E15F853A8A89840879165147A2
+                               807AFABB6236CEA9319DB32344987889
+                               5744A506CA76CE69D9E474840529D667
+                  xor-digest = 4CAAE8F441F6EF3DB6971E274181F8F0
+                               4D7BC603E040833E77921A393EA13F0F
+                               ADFF07AEC94555224F6204874027106A
+                               6D7DDF0546F300D3E84AC87699ED40D2
+
+Set 3, vector#207:
+                         key = CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 83AC8C40850F4FCA5452871C954AA61F
+                               31A9BD276D39EEC03EC5977A71FDAC38
+                               368D110C57C1A19F2A7461BBFA88E372
+                               F78103F9FFAC1361AC2D2AD84C6AA3E8
+            stream[192..255] = 48E95C2FCFC79C91BACD0C41F626F05E
+                               F80E076E359299EB5272A2F688F96F6B
+                               3147C5A19A99D562A11E953CB2A90911
+                               205A7760B5C8CD959EE6C183A8C1420D
+            stream[256..319] = 974A4DE50EB45F6144DAFFA6B4A68E39
+                               48838434497B8F9700FC42005F3C2FB5
+                               A79984CC2E770C5400EA21AA4EC05751
+                               80A288499879E50462225BE03D677875
+            stream[448..511] = 09823B2D55E26C49E42FC0820D7BA081
+                               5A7EA9380637A2AE2C0D29253EEDB884
+                               9BF4F54D64677F08A1763EFFD904B62D
+                               B3843B0ADE885C00640D16A99E28DCC0
+                  xor-digest = E73D8783F926558E0C1E1B0D3FD86CFA
+                               974CD70EBAACC0CEA2D977E9AFCCD384
+                               935584D2FFEDEA813E6234112CAA1401
+                               71E99BCFE61A7D0E430D4D3F75AA3E28
+
+Set 3, vector#216:
+                         key = D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 5DE3EC7E6D724976985B426D722D93E6
+                               1F40F5F17EA14B298AC898CBD69F2BBA
+                               5705E1D0CEF7B7122362FCC0D5106D54
+                               25D51F51E29C938C592D9E862DEE9E33
+            stream[192..255] = E079C49AC8F160A9D529F30151AAA7A3
+                               1D137E03DF4C23F8734AAC3B20BF8520
+                               90E3C2529761EB4D67AEF1CC46399947
+                               1240DEE8343D6355B5D7377A7934B019
+            stream[256..319] = DF574E03ADD1DCBD0712D2748C93CD72
+                               D8488396AE3D3275E5A53CAF3EC112E9
+                               50A79494F25B9EC111FE9A7A68A5AEA9
+                               63A4F87B37F822B79D954436368D8E20
+            stream[448..511] = CCEF4C93BCEB2494EB4C70F5E301E980
+                               C494AF8C117F291DD09E3960D2C5A7F1
+                               9928C08F2F51C419E734DE9AADD25C81
+                               3579A7F0B8B367A49B97DED5793E4DCB
+                  xor-digest = 868706BC1A5F3D0BDF96E10324EC36FE
+                               01596216B0B8BBFF69C5BDAF69D0F38E
+                               FE89FFC32D34D142F413A5BEA7AB38ED
+                               22436C62F86C540101DC0267FAF67904
+
+Set 3, vector#225:
+                         key = E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 45A0736DB4A28A3A6DD181FEF3485F2C
+                               918C65663597C49F4FB23CA550C77CAF
+                               7B331B5D183844278E0D959EA024CC21
+                               CE1A84923E6E782472BA1645BEDFC60D
+            stream[192..255] = E9EE0DFD717F72FD8899D23E87E77DD9
+                               F9DA66B4645AAD8D8C3B489B0A637449
+                               80020326469B4C6403012B6E315CD35A
+                               4344934D720467F30B61C8AEE5C3C342
+            stream[256..319] = 94A2BA2B744CB83A29004AE21470212F
+                               67C2FD18F227FC017131D7F4DD0AB412
+                               48C59BADAE2E408584DF35C603192E37
+                               344C52664DD68B9231661F304F483F41
+            stream[448..511] = 6A29174A1099BF8759D2F5F9BA60816A
+                               B290252AEE08339BE0021033DED03C46
+                               9C8E28AAFAFDC67A7F2219C8942B004E
+                               47263842BEBB47EC6B0666ACCC884591
+                  xor-digest = 7A7411EE5D174907B1138575FCC7479F
+                               AF3437BBF098CCB5D8D25F49E6788374
+                               CBC9CC5812982CBEAF59111813430BEF
+                               56D9DEEDB6C935804013759CFAAC40E4
+
+Set 3, vector#234:
+                         key = EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C430C2A9FC44DE1563B1679C1A2DFA98
+                               91D01A302C5165EC13B26F6EE4F25437
+                               264AE9E18C98BE112BF560C72024827B
+                               85665C491C47BB396B5AEC66CFCCA371
+            stream[192..255] = 60F3A13B9EBF8784CC81C132E004A179
+                               BEA0606D4C2C830077A50004FB0487E6
+                               E179D81FD9784DC3783ABF86523FE4A4
+                               68930272980E3B46F865E4729DD34773
+            stream[256..319] = 44BC861136F6856B1C74C1CC13753B82
+                               A75E34EB40C518400B507D99B42E488C
+                               8A1F2F590E029EF48DAF2674FDB053AE
+                               5C0967923102EB964602256F70A9CC9D
+            stream[448..511] = 0EE3ADBC4CCC63A8B67C7812CD294183
+                               A2E9D4EF0D65F854FE66CF9D76A34F91
+                               867B27336F8EEC2E2CD30CCB98AD5769
+                               77B07C73C833B51753BB9B0DF08C4834
+                  xor-digest = 7F848C96AE9310B5282712493AD7E13E
+                               2B4581545E625A4DCD98576C75835058
+                               6C621244B6CD439F8E62625ECD9460D3
+                               A18BC2F5DCD9FA7E8CF7880CCFD1A44C
+
+Set 3, vector#243:
+                         key = F3F4F5F6F7F8F9FAFBFCFDFEFF000102
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B9B3501C75EE296AE858573B63C4888F
+                               72B18683CBCD6B95602D51E4388D6DD3
+                               7129169A5209202E2C6EDEB5026B6511
+                               55E4747DD706DDF248A8705D50D38A29
+            stream[192..255] = 12F90D1028010D8296DD0D6ECC4F2354
+                               89856C315555279BD0A4E3161178AAAE
+                               BD849EC0A90903CCFE9DC7CC821C1CAA
+                               D63A45A1D0C0247F1FB1423877FE9A32
+            stream[256..319] = 9F0608162C6315D206B5EFB0E40291AD
+                               E882445B9F34154F6E21B9FA23356DD4
+                               79DFFB16482F6A4F28A8A0629E8B1D78
+                               EAA473CB126FB3727B826B4B3D6175E6
+            stream[448..511] = F26FAB00C37C03AE33209E19F865B135
+                               115A5E254A6B5C1A4896987EAC35C2F4
+                               327822E165AC6BF99F535055ED74833B
+                               C1FFEB32588D8995CEF0708E2D3CF832
+                  xor-digest = 87243F1D4D08D7EE39213D1A4B9E2458
+                               368339A11E364345B4367F84154B36DA
+                               03A3728A7EBD4237897F9D1A19CCFE92
+                               B9D67D3A4A755E6EA8382041D4827A17
+
+Set 3, vector#252:
+                         key = FCFDFEFF000102030405060708090A0B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 05A90DAF1A6B6B60CD3B999A11FEEE39
+                               6D38983ECDA326EC9229D2A1EC722B0C
+                               3C0539DDBF6A4CF62B9BAFEA6C60A29D
+                               4AB63BBBC88987E9A74AE2F71B1E8DE2
+            stream[192..255] = 0AE6673D9F99C5EC9A4532B2B9786CB9
+                               E948A206CB992335FE868BB2271DCA5F
+                               9AB75995A7E7D46F8EA6693765C93D90
+                               9D41C24EF4856252986DDFCBE65D2D11
+            stream[256..319] = D8B07A866003059BAEE90378AD5EFFD5
+                               2732755E79402B50BA0F26A038B3D9C8
+                               1481C19080CB39FE840F8E7313D0C034
+                               9FEA4AA4801225630AAED3E522D6F920
+            stream[448..511] = DED21140E5A3C0C4615D7153DF9381F7
+                               269616817A273BFD984AA5E7CD9D9CA1
+                               9C28E51F4C03C262F5BB4175C799236F
+                               DA69AB27590857C0F270CE4BBFE02D5E
+                  xor-digest = 2D47DA3161389F5F54FAB37F391C21CD
+                               63A748112A1AB415670524B6CB93DA0B
+                               6B54C541ED59F3A54DE238C3FADB3236
+                               3871F6DB1A507B33C1B8F280B0C04B1A
+
+Test vectors -- set 4
+=====================
+
+Set 4, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 114265E078311C062B518148B4530F73
+                               DC9B95DCC41C214F8C9486473DC46847
+                               71819020010586A750426A0E633BC787
+                               6E228E2353AC0A68533C85A742387800
+        stream[65472..65535] = 196F53D41603BF286D1D11F012E564E9
+                               3C7FEEEC9539A015D49475DD8CC73C84
+                               2F85521B4DD9789A813A59D444AEC702
+                               164F669C59B43B5115202D08662D4EC2
+        stream[65536..65599] = 8A7B672621B0B77E8BA8EB9A71DB4558
+                               A78364244F182519F89D25D3012CF8C4
+                               E429DD543C8DC56C6DB8FA5E351BF615
+                               106B51F9FD00F54018A94DAA91D76715
+      stream[131008..131071] = 33EC15BB2C553646CAED9ABD83F37ADF
+                               AD3B3313A074B69FEAD405BAF897C3A3
+                               E12BFB2F4CC3136ACFDA284DA1E780DA
+                               B3E4D34C053302989FE6A79A1EB0F5D2
+                  xor-digest = D899BF7CD2972EBB7333D4E57DC809A1
+                               B717373577B15544443915B36ED162E1
+                               25452584F3E0C2B62164092219FBA924
+                               31C1FF2A14C8E2E437427DACF80A200E
+
+Set 4, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 8EA023E23D94434EAA064A4BE52866DB
+                               57EFB7B200DAFF5AF2AA72D3E55EE5F4
+                               5060FA89024F259CD2490C628452B1F0
+                               91020DE10263BA86838B2E388F5AD040
+        stream[65472..65535] = 5BE1EAE0077FCE5C2C21120EFD560A96
+                               27C3DA9462BE42580065C9E51B7D36C1
+                               D9D717DADF4A3122A08303A8E27721E2
+                               1DADC91138A2461713998AEE26F811D5
+        stream[65536..65599] = 482694A9797978003DFDA5183F00FF97
+                               9F38894BC92DC88418FF68156117A2B4
+                               EF10D76923A734ABCAD1A5B4224BBD08
+                               836E3765321045C3BF6A352371F82CAE
+      stream[131008..131071] = 614BC8A38C5F9E8507595E8F5A03484E
+                               C9DEC6CF52DECFAB008327527B822365
+                               A2038FF09411D7B952417C8C7375289A
+                               244D50703B73577EC272827A21BB917F
+                  xor-digest = CA9E6EC13B679609EA778447EEA1157C
+                               B366A08AC5A96A73D0B5E182DF24EBD9
+                               FC297219A0AF67591BFD68B1721B5970
+                               8EBEB3655791107FD2A0F2F2E341FCC4
+
+Set 4, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 5BD3D0625CEAA75ECFC9828179F7B73B
+                               288A208D60A2297F2C328DB0789BC869
+                               4E50F50E8797F8C7A49E24F72A3AC359
+                               796E6188C71A9B3DB88DAEB1BB2C77D3
+        stream[65472..65535] = 726C7D7AD756CF567E0E8F812A282675
+                               7E75D593C7FCBB45F842020AD59F2B53
+                               888354CEF541411B92C3AF6D57ADE7E9
+                               273805927DEEBE552B32D10754C9D2E5
+        stream[65536..65599] = 5703464C0AED290E65815D8D04098B0E
+                               22D2FA825ACD4391B56CA64CB8201BE5
+                               7B4FB9ED6BB7608BD820436146339559
+                               E7464BC13A8AE3167AFCDA58E3C017AE
+      stream[131008..131071] = FFC5787A10E340B07D08160D2C4F653E
+                               407857845A0D68D1EED8EAC0116CC376
+                               E33AF8A1120D8DCAD6C86B757AC50393
+                               46AADEFF012BD0DAA294DD240D87A98C
+                  xor-digest = B3BAA21AA82617D3BB9C2612E177CB71
+                               51A51790D97FE33C3F33C01B32091758
+                               5766643C125293E1F75D6BA3C46AB381
+                               75A2A4934D4C115A6A1547932B077A58
+
+Set 4, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = AC5DEC8B95C89F4794B7289C69FABE29
+                               F4AA64476D057873D87BD524666F62F6
+                               B71B5131BFB897AE64F2D500437E1798
+                               A742E7B7D06B8089F3DB2453D008C554
+        stream[65472..65535] = A2F58800E24BA8B754C64BAD9252BEC3
+                               ED1273598EEF4C6FE42FE2CADB81F220
+                               26A90BC88B43F2F1FD2E054E8EEECF57
+                               A114D087D5228CB276FD5F4FA3ECF4FB
+        stream[65536..65599] = 5C67BC8E188170A57DB85ACD2F7121A3
+                               7D83F1A708ADC54C14064A9559FE7E1E
+                               3F9E60B9670EA4394521B11D8283EE42
+                               12874323628EAEF0B90FC4653106D68F
+      stream[131008..131071] = 8AA6F8A20F7D4A0B7EBAF6A7336B6D76
+                               731E65DCCD179BD53F6B879E70B8776C
+                               6A8EA30BFF09BA3026B3827EDB9F9C2C
+                               0F96655D8B84EF725D0603F8CCE3C2F6
+                  xor-digest = 458DB66B656320F5F7E4FEB12E748C0A
+                               59F0CD8A7ACAECC25479C309628EC0B5
+                               3B441B831B484FD3180C52F63EDA1858
+                               7C232B195356996DC29DE6DF54E5BB37
+
+Test vectors -- set 5
+=====================
+
+Set 5, vector#  0:
+                         key = 00000000000000000000000000000000
+                          IV = 80000000000000000000000000000000
+               stream[0..63] = 04740F92C2470701F289669A25BF9092
+                               EB4212FEACF66DAB6B1D520977945F8C
+                               6D350BF26A1CA35EB37FA53B0BA2CBF6
+                               6AC07A8C75D494B4B8281CFBAD4937BF
+            stream[192..255] = 5E47F5F506AA34E7D296C6911FCD3D43
+                               31A032269214ECEFDDB492C47A51C4B4
+                               DE9EF0A63A6EB32AF1DF1C5576A93F19
+                               02B7BB89F10D8C7CDFF9C097D3D49148
+            stream[256..319] = 015494CB3CC9BDE8A2981B25C06DD18B
+                               52FA7B94CBE24C152FC60762290329C9
+                               E58C4E5148585F417733737059E310D9
+                               309D0CEF48D2F1589994657A081BA6D7
+            stream[448..511] = 3B67C1B37D96E1076595660D61340EC8
+                               DDE8F492134270951D9D4B260C8E2254
+                               A7FE8C10DE837A617A8E261FBBF42259
+                               C636B3DEEA0F373FE7C2CA2B01EE3FC3
+                  xor-digest = A8CC89F06815EFF6A91CA276BEBA7F41
+                               75F842F85BEAE99F4335A3B85FB28394
+                               8B7EE3C659274C6B784035B94886BF9A
+                               5C1483941B20170EE3A374E39006C09B
+
+Set 5, vector#  9:
+                         key = 00000000000000000000000000000000
+                          IV = 00400000000000000000000000000000
+               stream[0..63] = C25BA6DE4C87FE5360BCDEF864F3F778
+                               598A6A584325D5E6C44EEA4464D7580C
+                               9B8D42B5B3634F739D6A53D15FA41070
+                               D1DD4621BF87F53F42107618D9742FD4
+            stream[192..255] = 4A3808B0619C9D94E19F3AEA0BEF3839
+                               21D7E2BED05F1128A82D9DC010654ECF
+                               65199A645606CC44FDAE763694E6757F
+                               8FF864CBE4204D45102E465F16CAB8EC
+            stream[256..319] = 3097394E0CD0A9DAA28EA873566E42A8
+                               710C28366C2B41B6BF6687D881094676
+                               9970A5BA54D28D7BF772C4FED13A9F5C
+                               6E7AD3F6948667D6C2DF981955F73293
+            stream[448..511] = E685BC2ACD3A67791416E78699C83D31
+                               852EBCB1C1AF71B926D9161CB6D894BC
+                               8C5E85C7E30A0896369BAE50C1112D4C
+                               CC583E44A8275F44B7ED140E9721C7F8
+                  xor-digest = D9B51AAF4A9B75508FCD02443EFE2267
+                               1148C73264776B5513860BCE8547370B
+                               2BA66E82CCDB15F3DEB0F0728411B765
+                               1A098C23202745C19B045C58AB196309
+
+Set 5, vector# 18:
+                         key = 00000000000000000000000000000000
+                          IV = 00002000000000000000000000000000
+               stream[0..63] = EE43BB5B79EAFB54B823DE95B71F3BD2
+                               F2A7CBB6D28E9BED590C20A2C52F9B2C
+                               74EEB9A1A48474D5DA4964EEE0BB98E4
+                               88030E213A4482BD1A8CAD4CF8A962CB
+            stream[192..255] = 150C4D68BF29DD27A2E6FFDFBD6984F4
+                               3AB56AACC08AC0C0149008F0882292EC
+                               A5359CCF4C257ADD4FC535E41D6F67CA
+                               E5210068F77A5D5F32A23B17F79EB7A5
+            stream[256..319] = FEA319287C29AB84585D4BF38DCFA71F
+                               A36253AD7F4BF58398731713614D0047
+                               F85A465C6915E05232A5FE5AE7A559EC
+                               42733403ECF6B11E4D5E8F4A8288A3E3
+            stream[448..511] = 79CE66DD3F77D40889906EAB1F671B2F
+                               98D9FBF8693C1EAFC89D19209408F3B2
+                               7CD83CB3B9F33151DD4A8D79911255FD
+                               3CCBA14918744B0ACB93A5F96AC9AB38
+                  xor-digest = E1E3F49B342F873263F585EC34969176
+                               2CC46C17FDEE0B32224BB77A8EC82A87
+                               816DC612439E998476F50E876481EE6C
+                               B32ADBCF6A5D50FA16355AF63AA30D66
+
+Set 5, vector# 27:
+                         key = 00000000000000000000000000000000
+                          IV = 00000010000000000000000000000000
+               stream[0..63] = FB8F4925A4F922119A6F29F8DDC2338C
+                               0AEF333B55919AF0D0D9B1DB61BA2E5E
+                               4CFB394E15F6A78E01B5C4AB043225FD
+                               9C8F50AB1BFDB16F944C2660995AA4DE
+            stream[192..255] = 87767D451D81D5B40503913508C2448B
+                               7CC093982642089843D7D9C3DA05598F
+                               7AEFC5B70ECCE327B20658D6301F4D6B
+                               E58FA5CE0525C9CE8E93FC0B387AE5C6
+            stream[256..319] = D146E4312CC11F11916ED9FF8EA8ABCD
+                               E0736DDD0A8AF3E067CDED397E429D30
+                               8F2DBF848C5C1653EA969B608CE01275
+                               53573C88DDD32937EF6F8B0864C581B4
+            stream[448..511] = CE919096A83BF3702D8899787DA7BC23
+                               43F1F10833F16E3EB467440B4921BA1D
+                               96845B6B4141E1CA85364E2D508456A0
+                               E399DD048E72685389FD7EF3F78B655F
+                  xor-digest = 00333EC3A59AD0B8FCA054A08340BF91
+                               906512917E72BED76BEFFE29FC011632
+                               082CDCB1A656FB817F968E26063279CC
+                               ABA796307912984BFC267325DB84F621
+
+Set 5, vector# 36:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000080000000000000000000000
+               stream[0..63] = 202723F8212AB20D9369C2E1EEF8553D
+                               C468854873D04FDD32641E324DCB4EE0
+                               883AC1D40D7C9C7783DF4132093724DA
+                               113B1CB12144E00509FD5D36957A4E1A
+            stream[192..255] = E6717FE0A77F9043607A1A7665716225
+                               C8D417FFE2CD7572083C7C552B79DB6F
+                               ABEBBC2D4D36AB319407982187C248F4
+                               83596AC071C0B0CED08686603B024E7B
+            stream[256..319] = 8C59D97F7A093EA2D0AB890923AE4DBD
+                               D40C33508838A3966FBA360E776670C4
+                               DEED8BC8CA57592463781550BCFD1E28
+                               818E7C33A3AEC43775ED0A984044E9D8
+            stream[448..511] = 0A3DC66754E02423C6EC1C1DD26CE11E
+                               FD70C386729C8290DF358C69087CA7DF
+                               D11F5E0D37A313F74B09F29C552CAC0A
+                               5621556828B0145A6A1D43F563AFF672
+                  xor-digest = 6673BA5866E8E96FB48FAC88D307079E
+                               77AC03692B23070EB5BB9D04FA94B9C9
+                               6C2F958E834DEB51C6ADCE432BFB9632
+                               9B3151E0A89EB72019A4522233B8FFE2
+
+Set 5, vector# 45:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000400000000000000000000
+               stream[0..63] = 95AE241C4E9B6690C319D1FD828BE454
+                               52F18F061C1B1E13AA409829E194D70C
+                               AD5BBACA2738B508A5398DF6C2552497
+                               6D143DF0405F68037C285A0E19FEC9CC
+            stream[192..255] = C0E2D5C6B614E4A498F46D5399DCE7EB
+                               7DFAFAC62794F5C39864C521B8DB574C
+                               149E35D1F0EA36EA7F24EF8FD855FDCB
+                               9CCC79F1ABB13EC33E00A9E137809C05
+            stream[256..319] = 285907400C1A86AA9942ABD7BEA8EEC8
+                               BB6AF2F9667D424C1DD56349C99FC65E
+                               8A00893AE529D7BA492089EB6B525964
+                               E9CAF15221A342C4F88697D818AC0F1A
+            stream[448..511] = 13D511737F3A092643E94E74F6C76241
+                               0007158FEF40C63B33E10360FFB3B152
+                               8BD8B33093D722BDCAC1FA99D16D1C27
+                               6E59E428601F256542BD3E7A4A135152
+                  xor-digest = 1D1352487AB5081A28DF23B1B19D5ED1
+                               192F08964E4C0F048AFA9CAA8BF17185
+                               D7B97AD6003E2FD2DCCAD492FF3FBE5A
+                               5CD7AAC627DFE7CC6D0972D423B67128
+
+Set 5, vector# 54:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000002000000000000000000
+               stream[0..63] = ECA0F29C3F5C4D62ACBD601C3042673F
+                               6F8B17C946FE8FEEEB0089059765F067
+                               5AF3E5DADF6DECDA20F72AF486E7E967
+                               40B2DBF22B57FCCDFE571B2D8989C95B
+            stream[192..255] = D2BDF6ED912478A3C53713389C9DFA5A
+                               9272D030543295E8CF6F0929F1A56041
+                               EA22BD04E0DD810F43D9D28D94254F04
+                               F73DFF3B766DB55100EFC9697FA844C7
+            stream[256..319] = C7CE1CD4D8C42FA36724A49107A78630
+                               A60E15673A42C57B609740EC8DE78EE0
+                               B48F2644DC0DD1E80FB8326DDBCC7191
+                               5E6C8DEEFCCB1FBE1456532840A89DB6
+            stream[448..511] = 337650A0B03D30C9697CE85449B0F995
+                               668FB2B73E37E1A550E07632F9F5AA3B
+                               04D61AC41F8A830299FB8F70FAA0419A
+                               42C4589D71C965DDB3A9D000667616AA
+                  xor-digest = 7A26C50BA37BD9F38281FD2DA3CC14F2
+                               E1FFEEC9D7776E87D99053B531EEF792
+                               0C0BF834EA9A0065AF38422A40A31BEF
+                               AFAA17AD565F685BD6E505C7E02FB895
+
+Set 5, vector# 63:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000010000000000000000
+               stream[0..63] = 567919917583CE03DBDA69907CBAE562
+                               107FBBABB4DFC81A3A15438C94AC0C28
+                               8CC35A91DED9A79ADF4EF2670A55699C
+                               000994EF33674B578F5D77928A43416F
+            stream[192..255] = 13D0EC5B7302C0D8AB329E7AADFC3FDE
+                               1D24A80B751948C4BCEF516D94DF7AB2
+                               2B1D9E076BBFE367CBED341B2A5A3BA2
+                               D48735F83855460F9D9953279BFC2AA8
+            stream[256..319] = 5EFFE922E2FE25410E8050A973C3FAE2
+                               EE372E9686B6E7B35294B52A579CDB43
+                               9D5CA7F1EABFEB4303DFD7DFBCC812DB
+                               9D70CD0698D1ED051E1E32C855EB39EE
+            stream[448..511] = 91A01C0EF63716515DB8B71273CA4399
+                               1654AAEF2AFD4DEF25E21A08D5385766
+                               D8C29514065FFF00B07DCB32D1A20830
+                               3C3402963EF252A4CAF5CA31A50BE591
+                  xor-digest = 9232F83FB054098FBED8474939476CEA
+                               5E9FC269E7B248E56B14F56CB396BE74
+                               C2B2203D1802D9515EEE232FD612FE21
+                               11C291A46A89D54B2E5437E643239636
+
+Set 5, vector# 72:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000080000000000000
+               stream[0..63] = 507958BFA08EB41F4D18F519E36FC476
+                               5BB8DC6CFCA36290CE9AB8B165D7AF72
+                               CBF49DCF8BA2D145D7935EDD2CD2242A
+                               7B7FCCB85B4C8625532D84B4BC602515
+            stream[192..255] = B2B06A7C3977D4A1A39892E832A32A55
+                               3EE6E52DB24DC453835893A55D0FF3A2
+                               949B8B96688237E13DBBB2D0C9038AFE
+                               8B9D18CCAF62019ACB908499D292F280
+            stream[256..319] = 1D28AADF7B262A1EEEC11D39F4325CAA
+                               6181F9FA1A6C65F3BEF4F1614B0DF599
+                               EC92E5B6B42A931352965CFFC025F68F
+                               DB2D6D0181F259F12989E5FB23ADAE8E
+            stream[448..511] = F60E3DAD5004E31F6DC89292ECF517F1
+                               CD18AF7E79E775334F4644A09346AAF0
+                               F2B4F5C1DD03555A6D27C43AE53EA7BC
+                               7167F793190071C7AB7B5330A6C6CAD0
+                  xor-digest = 5A65D44021E67626E62FE87B8547210E
+                               F736490C0D51485A8EF0E1CCBB512DC6
+                               0FC18114A29AF923EE3E85655771D6C0
+                               7CFE342A52190C540BE3409853F12065
+
+Set 5, vector# 81:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000400000000000
+               stream[0..63] = 2416B634134170CB4F67F431BC94612B
+                               5F2F72545DAED2356081C91A26554614
+                               5FF2526D8D8FC7D02D8BCDD9AE03187A
+                               9E404C360E115CE949667987AC73624F
+            stream[192..255] = 4D456233EC7E761891A56BF9F9659533
+                               22375C169D7F16DD81D8D69B12092F47
+                               09703B85AA3184827935B60C1E5987A3
+                               C4C2EDFEAD4F777B53989C469B575EB4
+            stream[256..319] = 5F9CDDCBE09CD759B346AAADA2436887
+                               0D47BD8859CB9225B61AD9F99197FB14
+                               B5D625F5DBE0955DCBAA5B874A7C89C0
+                               07BF926AEE571CCD7E20635ED4FF312C
+            stream[448..511] = 642391D8851A9BDBDCA37B9587D5D0A4
+                               877EDEC31D6EB78AA3F1E068B0ECE877
+                               D83EA29906D0C0816EDF7EC5BB417A3E
+                               F3DDAA2145CB37CEEAF8C07DDEE0AAD9
+                  xor-digest = DF93E4E01EA55D18AB8AB1A927A5B5AE
+                               9ACB871B7493DC283581262771852013
+                               EE54288580A03B3991126BE8BC20C5D2
+                               230F00D8216CFB632271750F4FD2595A
+
+Set 5, vector# 90:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000002000000000
+               stream[0..63] = 4981C83E26859DEDB32D84C7BE32830E
+                               784376A12FA6D0077D4CB47ECBA08A92
+                               C841D45D6CDAA3F1FB48C6FE747B0F67
+                               1B32C2B35BE69497737FE4B98770DEE9
+            stream[192..255] = 1FA51FFD0360615EFEB03042AE8E4210
+                               D3D38B4EF07536BAFE43C0585818F012
+                               8F8B3F8CA8DADBDF049688253066C74B
+                               01849C5BD85DCE27C0138D24E8B8B198
+            stream[256..319] = 2D8C58008EE94CFEA1EC545C26466D39
+                               D7BFD5B226E32F1270B5BD3677818B7E
+                               CFD98BDEA26488248B10418C1F854159
+                               8F42C6CC237885A1DEAC5C33F22C27CD
+            stream[448..511] = 94502058B5828AE4F4CDC0516E5B5143
+                               1F07EE1ECAD7CA266C931327BE6BF1B7
+                               A34810220CE00497D7BB9600FC524999
+                               CDEB6DDE8919B03064EB56B3766DAFCB
+                  xor-digest = 1DEDBE0B7B6099DCF285B3C30E91AA0F
+                               7859496E034A1EA1AAE3D3D13C2061C6
+                               0878E595B63D849B7DB77BE7E0C08157
+                               94232B645BE946E5D8278B14427172AD
+
+Set 5, vector# 99:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000010000000
+               stream[0..63] = B84C72BF69B601FB1804CE333C5A2C19
+                               25BC8A5877DF9E574295380611D03FD2
+                               46D2EBB58CC6E918F4DB1B1A0E39642B
+                               D6B39DC76764E18108497E4CC4394057
+            stream[192..255] = AA84DF8195B3F7564D0715517476085D
+                               1B40511A72340DFEAE5134C7BB8F39CE
+                               03E6EE15217986C7E4788453EF054027
+                               8CBF6336073092EF661C13C7EA8B4850
+            stream[256..319] = A7F0C413EE143F55C6356519AE620A9F
+                               4CEF8432C51E2677EB5D700CE333F314
+                               ACA374D86A8FD4A67BDC31C1B0DA2AB1
+                               B20E6DB91E7F85DC13E348314A4FC782
+            stream[448..511] = 3445E08F13D09A1AC09EEB65451F4504
+                               0AFFDE94F6C2667BC4D8FCBECD6C6565
+                               F09FD05EC660DD38307F856AACC95549
+                               AEBCF31B3FBE84FFB3261D7FEF7A3379
+                  xor-digest = 360199B22EB28401FB4F621E37800801
+                               FE69C809D83BE29A50FD1A476B6AAF02
+                               54B1F4B048CB6423182C390B8EDFF1FD
+                               9CE49C26727F0D68EB837C19F58F3F42
+
+Set 5, vector#108:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000080000
+               stream[0..63] = BC618F4A557E5B7CB75B3572FFC31CD8
+                               4DB96FD22E281C198DD33B5E9E419099
+                               BE30E84ED61C0EDEC04B1E16E06B40E2
+                               372E0EA1A48DC55BFBFBE3355B566AB9
+            stream[192..255] = 33372015C7E5749D98A92CC55CC22206
+                               90BEC9878D3CA0AC50765D0B4457CE50
+                               9BCE196BF0388599E692B99EA8169474
+                               546F10891A3FCE22DFF0AF9733C2A2EE
+            stream[256..319] = 382684F74B0F02F7B987D37F6BAD97F4
+                               20B4811FFC744CBB9F00C2855A609FC7
+                               7CD24D0137304B95217E25FF45AFA4CF
+                               28E4335D29DA392D26DBD341A44C082A
+            stream[448..511] = B0B2B619708435C5DB45FFADD2FE4449
+                               E603FA9785E1F521E364DEA0B127F72F
+                               6C8A956CAF2AC9ABCE9772ECC58D3E36
+                               2E758BDE3678D4F4C9804CAF11129BE4
+                  xor-digest = 80FC64E2441F6CA9C0F4C207007FD0E2
+                               5F1C0514D203A1B01A6EEFD1055CA355
+                               0174FAAD47ED0956A736A9404164ED85
+                               CBEB31F80561AAFC4ED8EDC9829D83A9
+
+Set 5, vector#117:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000400
+               stream[0..63] = 69FEF0D5DD7CFA6590821B6C12E239E3
+                               5DCDE7B218A66CF3C75ED278092A6228
+                               143EC00BC16DC2FDB8CD9DDBD802AB56
+                               A4011F6A8CF432F2D34657AB84DEFA4C
+            stream[192..255] = 312EBF427B3D22A22EE1F85D89E12AE7
+                               07160C9BBF4073E538171365290B499B
+                               8904B01801CC897FF09A520449A44D0D
+                               34622DB8477EF1E73DCF15417478FA03
+            stream[256..319] = 83CF222FDBEB77FFC6E282C1212D8D1E
+                               014865E9C1251FC07E901A41A50A3AF9
+                               F8E130394F621B739578C7E238866431
+                               10827799C75F08C47664B09B477F31A8
+            stream[448..511] = 4130A8F8015F082EE8712B6D61178CAE
+                               B1D3CF90AC2DB9F2D402F65E8395DE95
+                               DA0605E8540E553CFFBD029AD5BA8FB7
+                               5950C2FB29097E13ED4A1B1818E0D07D
+                  xor-digest = 21FA07F8AA2FBC12F5B2B14E034C2AB4
+                               54D7D8DA66EB0308D9AB024DBFA414B3
+                               38F36D188D33C71E888FFE1A6AC620CD
+                               55B33C1A146AB8FD275584589BD65606
+
+Set 5, vector#126:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000002
+               stream[0..63] = 0CF41A77C30118D0931FF3142132A627
+                               7A778D3BCF7466EFE56238B166A57043
+                               2DB3B222523330233F81836282A27B40
+                               F6823BD076D84DC3B831DD78828F0FD5
+            stream[192..255] = 38A0C28325566FBAEF5AB3D50D54F407
+                               91182DEF4FC945992AA0D62134451914
+                               F07F16E86E20DB119692966E6CD6165B
+                               79BE7CE6C45D1248F2E0432393BFA726
+            stream[256..319] = DE91DACF57B176EF6E59E485DF02A20E
+                               3A4EE5FF44B1AA3D7F36265221CC71EB
+                               FB9565AA4F269B7DBF3CB9631CCBAAA4
+                               BBBB6BFABB97E52954958D4E7A283F20
+            stream[448..511] = 8FFDC8CCBF864721D6C98E1896FA052D
+                               15141D9C3DFEB48AE91B2436C5C3D088
+                               931470CE951B66C38998F15CF23BED01
+                               F6D95D84150D482C0C289A8E5B2C7C10
+                  xor-digest = 03DA7ADC3E5931928D3FD89E1E0876AF
+                               9D4CE659175E671D6D80EEA78F241AB2
+                               86CE3C26DAE267D91DB556AE0CAA60E0
+                               2B481282E6470A7A161AC8E84C2311EB
+
+Test vectors -- set 6
+=====================
+
+Set 6, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                          IV = 0D74DB42A91077DE45AC137AE148AF16
+               stream[0..63] = 425A5E6F68EC055F38383ADC5CA9C048
+                               D6455C56A5ACED215E22665185E497EB
+                               3A2F5C0D45057169965EA37FE19F5D83
+                               C95C4BEE11E8FA89545A38DD9D18AD6D
+        stream[65472..65535] = EFFA27F50B0B4C4AB3C7855CD5DD9EFD
+                               B61783161678C9728B9032C2CB09A0B2
+                               D2578C53BF3C3E67D382BC89D824D63B
+                               20E62F414E4AC36472A16F4992DF4496
+        stream[65536..65599] = 0111EEC218892B446FDFDBA9D0C734DF
+                               C209D35FA86C1BEAC0D266E5DC4B3243
+                               68B4263BA7A3517805D1501B36450FFA
+                               1544812EBC0B9DDED93F5D45C4D83FFC
+      stream[131008..131071] = D966650E1A27DF3CB71B1E64CD3E7EEC
+                               2D3EEEA2953E2FC5571B4380EA3BAEB5
+                               3F014B4EE071A426E4A518E1AF335BD3
+                               76309236760E0DF6184B3E34BF861458
+                  xor-digest = B234A4CB646B0C2792023EABCD3E974F
+                               1E5BF1D5DD8E07E5C11BCC47BF1F1DCD
+                               BFFA3605A37008813029BFC32D1EEC11
+                               FE775D9889560C847C79ABB5C7181E6D
+
+Set 6, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                          IV = 167DE44BB21980E74EB51C83EA51B81F
+               stream[0..63] = 5C1C44F155CF8595D52D003B7CE6C584
+                               F04708B55E3A8B952379A4F03C6C5118
+                               E0848F52C846BEF459335EEF7033CF25
+                               AC643ED139A9383B9DE13A5652E2B754
+        stream[65472..65535] = C4710CE8066A43B7E7FFBC8190CA79ED
+                               5E14AEC2C153F83966322553D5D4824E
+                               782AA1C91400027395D74B3A39DA1925
+                               C6A757E36B48A8F1FFF12321602379CA
+        stream[65536..65599] = DF29C91A08AB080662764B01223C818B
+                               27DCB638FB2535DA034D325DF996F57A
+                               7F4C67BA94C72EA6C88112E575D55906
+                               3C900A87B205A8144FC1717D5ECEB77F
+      stream[131008..131071] = 63FD83511C8C39ED3968EEC5FD281279
+                               70626BB91625CEFA381AC48E166778DF
+                               63709701FDD99F4A547D8CD6F7324B29
+                               A9E0C025EA1BA007246941D3566D15F9
+                  xor-digest = 959850E75A99AA747502E7BA9D19D870
+                               5895593FCB7BFD7A7DD4FB218F17DC6A
+                               BC8B96520FE83F287429BE3B87D35D78
+                               C6F100D8A9561A149297CBC44306E5A4
+
+Set 6, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                          IV = 1F86ED54BB2289F057BE258CF35AC128
+               stream[0..63] = 696FF80A8A547A2E215C6E0572821F70
+                               201A090460E7B36A48ED5CC976417DEC
+                               EE32E7102AC764805E4A1BED3DF7D786
+                               0B3BC625B121B5200629AB58799DC406
+        stream[65472..65535] = 7BF69658F0EA9905897C1460D30333D8
+                               DA83E3F1377FB75D015D927365C7316B
+                               307CD91A7167B87FB13DBD4739F88A20
+                               F7878C2A483A4FFE1AB4A60840EF3EEE
+        stream[65536..65599] = A55326496CDE23F447CA6A4D1BE0182F
+                               ABC30D61C7A9E655CD99273232CA6589
+                               FDDC8179038B720D5A12CB698FA50B28
+                               9E6CF476ECE2DE213F44F9F23E8AB4FF
+      stream[131008..131071] = FB47C745519AC58C91CA9081B1DB0CA2
+                               8662116EE04AC6C4171A4BD11572677E
+                               DA507990B45C145DD21A56E1FD8F7AE7
+                               1BC54AC550309631C12A80FBB27187C4
+                  xor-digest = 3B3E44A1154CA7C4B74A432D0427AA6B
+                               3B6D81FA45AB9D3A37CF075F57E62AFA
+                               15DCED3DB08B96F48A12B176ABF203D0
+                               922DACF266985DB9D52A9D4AA00614E2
+
+Set 6, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                          IV = 288FF65DC42B92F960C72E95FC63CA31
+               stream[0..63] = 0A12311E99506D44616A24E124676D15
+                               D06BB6A73EDDA4E9767952E1FF698BEC
+                               593FF8E2422D80C9C55DD660C6622CA9
+                               86140571D0958C070E2A8929C24E5562
+        stream[65472..65535] = 6BF87D409915D407FDAA06FED0EDA87B
+                               8CC4F20760B7669009795EC87DFA6BB2
+                               9825706AA3ED93F4197B28587D042223
+                               7D1F6761D7F8D8F8B3E0421AE9EBB9BF
+        stream[65536..65599] = 290EBBC73FA33ED00E0BD9CCAE6ABDB5
+                               EB5E86C533BF3E69D24AE720D0FE30AB
+                               F92B57C1EBAEBE8DCD0DE7EBBA5E8CB6
+                               67669D286E0B8F8A3A53C3192D2DCE67
+      stream[131008..131071] = B6082022254F783C501C08370D8F5678
+                               CA2F08825D4F7D09BF0868CE44DB1F5F
+                               AE8D30C6380C3A20B1EEBD4083E58BC7
+                               A4EAEAA9D54117253784E4917C3A7039
+                  xor-digest = 2181364DEDEDCA0C6F51A4634490FD9E
+                               3E89D0D30AE94F5E75730E4B9E82FF68
+                               5D82723A59CA0879C6B80588AD312CDE
+                               18723B80828EA4914BEE062A68EFDCBA
+
+
+
+End of test vectors
diff --git a/crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_256IV.txt b/crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_256IV.txt
new file mode 100644
index 000000000..a4784edac
--- /dev/null
+++ b/crypto/test/data/hc256/hc256/ecrypt_HC-256_128K_256IV.txt
@@ -0,0 +1,2783 @@
+********************************************************************************
+*                          ECRYPT Stream Cipher Project                        *
+********************************************************************************
+
+Primitive Name: HC-256
+======================
+Profile: S3___
+Key size: 128 bits
+IV size: 256 bits
+
+Test vectors -- set 1
+=====================
+
+(stream is generated by encrypting 512 zero bytes)
+
+Set 1, vector#  0:
+                         key = 80000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F1B055D7BF34DE7E524D23B5556B743A
+                               EAF06AE9076FD2F48389039C4B24C38D
+                               DFC3AC63A148755FB3CF0CB8FB1EDEEA
+                               63CD484036FFAC3F5F99FC7A10335060
+            stream[192..255] = 2541F0EDA5633B4F47C6B74CDCC612AE
+                               CD27E46B2C8FC9036A09C6FFB5891168
+                               7A8FAEDC225E34C45B6E081EF5279FE7
+                               3271CED417549740EAEC6616C2B6A57F
+            stream[256..319] = 0C8C0567803E2537804BFA15742D3E08
+                               A29985688DF3D6B4C3044464C1D1F2CD
+                               4CBBC470C9A0FB05665CDED63C58E466
+                               896F80ACC020F134CB622487D40E0AF8
+            stream[448..511] = 1FD448C788A21BD30D4B6BC5D8AEF296
+                               2772940557B9434E0FAF636D576B0737
+                               1FF3AC12884BB431F396CF7C189D9AAE
+                               D42797128CE645FE841A4CAABA429324
+                  xor-digest = A3F66A36C20A496A0D4D537B6106662A
+                               DEB5AE1E35FD1486EAB6039F443E5D8A
+                               C6A2D4A2C2E2A9F335E2E468AD8BA51E
+                               550E41533332E6929EC18CE35BBF741A
+
+Set 1, vector#  9:
+                         key = 00400000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 9244D2B190FE8C4BD0E17247C4F1D282
+                               3FECA8DBE546637E34BCA99236D09F79
+                               5A8905A1E0FA94E6C51F7DC0C90FFAE1
+                               A8EBD4C99CC96FB3252DE0A0FB03F971
+            stream[192..255] = BC0ADD787A5EA52E28B45192399DDDE5
+                               CEC4E283181408E554FC714586FB641E
+                               B36F3727358BDD8223B5ADC9B9EF1044
+                               0F7CD97FCF2ABA75AA9972B277CD6656
+            stream[256..319] = C9F6315DA3CBAE23D32685C5549274E6
+                               9C17FB2E46746C5D3260FF2E00FB234A
+                               A460776CB0E7AC3AF0D297825C1796AC
+                               0B689DB219443BF4C0D4D19CD70A49E5
+            stream[448..511] = FBFDF6D40BF2DA0EBB04D52C117E9EBD
+                               6FEF88D39B8EF8B31082EE9B19D50219
+                               183DC962391FA4F602A2510BB476EF4A
+                               A44439F61D589933A1F3F633C96E56FA
+                  xor-digest = 49B435E6FA51A0AF8DC94CF1DE09F8D9
+                               AD76E08C061B54CCD62EF98ABE85969F
+                               3FC41DB934AF9DBC5F32748623639D3E
+                               B15124F13DA8B008CA5016ED61917563
+
+Set 1, vector# 18:
+                         key = 00002000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 9D74BE686C2DE8B207E8D82E49236A3D
+                               E86F5A7EE231B4239080FC9A55FA44ED
+                               7737FA7472B318A4F36FB788E863247F
+                               7067C20DCA632FF051789E9EB99CF409
+            stream[192..255] = 4876774DBB886B72E54EE8160D8BA8DF
+                               6DB032B2A9BA0B79CF82426CEADE421F
+                               EF5ABE9976E909DBADA0442FFC7BBA2B
+                               009F7240941F0C209853A514B0BE9062
+            stream[256..319] = F2499CCE5D3268F4C5515C365D2F4411
+                               B0AA99ED01E7D5328BF0672584AC65CB
+                               E47BCA14C3EB1F838ABDB7C611677BC3
+                               7382E84D05848B9838A166A42E96B016
+            stream[448..511] = C855EF5D1CC991D2DDC892AD8319E39B
+                               734E43E443F5910D03BB79CCEBE70569
+                               F92BBC63363943BEF88BFA5809B3759E
+                               6BA4ECA1FAAC572228458A229DD5BA06
+                  xor-digest = F125B88E0B5F143B836AFD7AC822E027
+                               FF44B736E32627D90FA05F3DB98576E1
+                               9EC41AAF9D61ADE2BF00E38CA4EC2A54
+                               49EE0655FEAE777D67EE127E8A5F8CD8
+
+Set 1, vector# 27:
+                         key = 00000010000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CC447BF1B5D138025BEA2B269E625C4A
+                               D4451F3851F04F118499040C6E564E38
+                               5C5FE17FA7AFAE9FA559CA4835AC1F40
+                               1C045AD439B400BB41984DFE7E4D4CC4
+            stream[192..255] = EEC14B65E027BC2A96E566BB89218A89
+                               31C4AE0BA5C444929EF852EF7E400AC5
+                               D8B3CFC62DEBBC2B20A7B32E350E3839
+                               2953B7839AACC06B2018280770F84B65
+            stream[256..319] = 8870B4F9A62B37A1929973D3975D7ED0
+                               505AA43002B14B55A541EAE00148651A
+                               111D6E5A1581F85FFBC2304783EBF5AC
+                               E924CD8111056B1069F13100DE15EB13
+            stream[448..511] = 1513F3B7A2458674CBA2B566F3AD6169
+                               2BA4EE30687A07AF2FD0D340D92384F5
+                               F5BFD9B8DF2F7098A209C280F6D5AEFF
+                               BC07D167720DB47B4B649C8593E6F40C
+                  xor-digest = FB5EE30BAE44FDFDF105796FB8A66F69
+                               64D502230C191FF9AAF5A4447533D02F
+                               05A3772B99F9FA2A075DBB8BA59D8D5F
+                               F819784D487C305280DF2F19EEA8BD47
+
+Set 1, vector# 36:
+                         key = 00000000080000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 831F1DAB278C6226785209C0AD34759B
+                               9F205B7BC6B987DD145B949336A8FA0E
+                               4550BC1737DAE7DD7D12E2C062BF9693
+                               F08C2FB808A1F0A5887A06B93D132BBC
+            stream[192..255] = 76631E9D4A673D09B9769251433D5EFF
+                               3114AA59E1A9B7E21B4123DE3E34FBF8
+                               4ED6E80EC29B4F75B53A63902C373EB3
+                               D644B8823789743CA407FFEBA4A1AA75
+            stream[256..319] = ABD84B2A5479CDBC5587FB9EEC5DC661
+                               5A3CC6136314F67AD2C96803E8E4BE92
+                               E33DC35F0DBF3C401AA5D7A9F46E54CA
+                               A7ECD68E561BC08E6A5B847A82777E4B
+            stream[448..511] = 9ED1D44510201727B2E92B55DBE06BA1
+                               46762AB34937364B2157292CE68B9D78
+                               3D3C3FFD1FDCA836E4C4FEC750B10668
+                               600C26AC05B4DED64F8CC2EAA0D22052
+                  xor-digest = 843D7B97B3316595111DCBDE3DC13DA4
+                               C14402936D68035CDAF9A1C168120B34
+                               0EBA1FC47E957C5F69F369B4C2ADC4AE
+                               37E743226D72A9F122EC8E00BCAAA126
+
+Set 1, vector# 45:
+                         key = 00000000000400000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = D2D629E84843638274ACB79FA257DD9C
+                               D48A08B823DC9F175CD92C5236B9D230
+                               5931FDEC5A8F531B1ADF30DE0527AD2D
+                               0D2B253D008913558E0FECCA7D7BEA4F
+            stream[192..255] = 6F9322E84D69CFD6A1E589283CD028D1
+                               E2A114B719FB2E18E732B97629313772
+                               CD2F2F8AF77EDB5B4360E4B679441346
+                               03C59E88C042713C3E403E5D93F9BBC2
+            stream[256..319] = EE7BED6C85B20E0A39C103D0B6949F4F
+                               5F6FE0DF2BCE315CCCEF6E537C488525
+                               BFC27FD249A6D36548C558153661861A
+                               78422A563166BBD0D72D6D7876FB4DB4
+            stream[448..511] = D2CFFCD4185EB1D8E15B629225B9C278
+                               6E7BFEACBFE29D7AF396B3D5917A8038
+                               7263018C7E98F49A1D5FA4B64B8E2AA0
+                               7192ADE0376388E8295AE5B54CC51389
+                  xor-digest = A26BEFF2FD72BE47175C1B6F3D749CEB
+                               0E3472FB0FD5E173DE66A5BB60357565
+                               505E3AA44A67651DCA75DFB6F0AFCFE3
+                               F4C89F064FC42D7C2953694B0CD47832
+
+Set 1, vector# 54:
+                         key = 00000000000002000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = DD1649517BE76EFF747658F0ACF5D354
+                               2C7FFD52F09FF7DDDFBC48487450607B
+                               CB90ACC3406D0302E84450FC0BFEC660
+                               9BD44C7FFF670D69C9B19FA50C62EBE3
+            stream[192..255] = EEACF8ABD7D48E285A6658C255A6196B
+                               66B091773A9F81807A119DC24023D5C9
+                               041AF75F2C078C5246BC5F50B622A678
+                               64EB7A07DA6A8764437E20C7E1E0E579
+            stream[256..319] = BF55E777AC644A0938D438FA374360ED
+                               F842BECB027FA3A0F364B9150FFBEB47
+                               09FE2D2056A6CD5A7076172152484BEF
+                               A86EC7DDE657307580BC6F9ACEDA4C73
+            stream[448..511] = AB4CF968EC00E7F08553A10270A7D439
+                               68B0BC79C2DAE278AF1CB81FD516CCA6
+                               F5B8A47271FAAC3223F02DB4D0D5945F
+                               9C13A47906B03B80878CB0596D37CC47
+                  xor-digest = 76ADECA36B9401DDD5CBDEE821B70FD6
+                               65EB9CDB1E3F25C0BE90DEC49C03A9CF
+                               4049CD34F9550B28E0187B0AD47D86D4
+                               88DE4617EDB5F03C67FA2E7B9D20AA25
+
+Set 1, vector# 63:
+                         key = 00000000000000010000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = C0CEF6E3CA9F0D523587FF47973FE896
+                               9FEB08773E3C694FBAC4804B37121B31
+                               06B99ECC2A08603EBA72EB3DC650E8F3
+                               462119F4685EF4CEA18D5765A6F22765
+            stream[192..255] = 79E92E248BA61D72C610876D3078F1CC
+                               CAD662F2423E7EECA813133136A64E54
+                               A1B6A151BECD2B815EAD959DE8E8DC62
+                               8F388D366103296A058CF60F525D6467
+            stream[256..319] = 03BD62A0892D939C1C28C4EB490F87B2
+                               527536AD6790AAA6C3CC50013E2BB883
+                               5710EAB7916FD89896B7983B326AE271
+                               AF9ECF975CDBBB968D076685BAA3343D
+            stream[448..511] = 98762E306A2B9D488FFB671D3975551E
+                               A06A6CFC5DB719B888E3164387EC922F
+                               12BC31A8DCAB8AC0CD6E12212CDA3B13
+                               4CF7F870221D6CDAC2B222AF4FD93DEE
+                  xor-digest = 606FA49585621E34BCC3748C06B51FE5
+                               A8AF320BFB83A4D1D3AEC6373519B28F
+                               2048A975732BA8DEBDFC5F85B84E7C3A
+                               EC0FCC9B1FA9EBB9D79D6B18BA2D70B7
+
+Set 1, vector# 72:
+                         key = 00000000000000000080000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 33A81D48866B04388451BC2730A2980B
+                               5F5BE248369911340E6C024A1F94D4FE
+                               ACFB246F7C0B9E27A40772D68DB36DE1
+                               7E87AEF19C8A68854A46B3F654E0AEC8
+            stream[192..255] = F67C60413B25FF7CB8647D1E9C361696
+                               3B23ECE23A9DBFEC644E855AEC5212F2
+                               D336E6F074EEC8FF5F8D4FC6398AEB9D
+                               BCAF6C29FDFE6E69A03D906C527FB0B5
+            stream[256..319] = 263D512137BAB758F646C71058D02B20
+                               3920965D84E52A99B50FFE79305E491C
+                               E0D61EF71F7A07937CEC8590B758F63E
+                               B3EB5890E8678F170C2E95B827FD8DDE
+            stream[448..511] = 023AD00A87D3D9441D4E8CB603F5CDDD
+                               AE8F3EBFEFB9C5435B72B9B8D03ACDF1
+                               E4A0FB796FF8401854998015905B878C
+                               99B3EDC7DD33A86AD4EA6AD208440C5D
+                  xor-digest = 5DAC8E3446BB3B0DCFB3F0A3A3E788C6
+                               07FA7436C63BF7AC9FAFCF4A231AFAC7
+                               75A3A810EA0FD4E5E6A5B8FE5D165A80
+                               798A9F58EE1AD27016E867D2E774507A
+
+Set 1, vector# 81:
+                         key = 00000000000000000000400000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = B33EA681CA88C80EAD8F2D57C87EA42B
+                               742550FF8AD2B01BDF945BF160AF763B
+                               15D6B3BD92E6CF3E6A2B61A7D4BB94AC
+                               E3DAB365E4EA50EBFD2654E60CE849BE
+            stream[192..255] = E97318BDF61934188A94BCFB4441809D
+                               36C37D1A43BDBB3EB06FFE143B6153FE
+                               C8453A13387923F434CFC7AAF8CBA097
+                               7D796DE95EEFED3B2126B611F477619F
+            stream[256..319] = 4183971367E71731111D2212520306E1
+                               1CBEB05BE6FDB338414C826A8E359C7E
+                               CC680F317C12C6EDE6B443E68B4767AB
+                               4190E95E1AE4E4FFE61707BE742775C1
+            stream[448..511] = 56841724B7D7F95809456EDC1D3A532F
+                               E1C6BA252017DA90EEC71FEE9A639A89
+                               4CB7E1575494BC8B44FE4C5DAF90FF4C
+                               A32E03D6399BCB3D9D25B62764A4977D
+                  xor-digest = 3E80587D70A53AFFB96A62F6493B9BE0
+                               1C25339CBFF7784F5100A7922EE3E6B9
+                               9D17B026C0EE69C5383F63E0E5AEE9DB
+                               5814E2C526192AEFE17004AAA1996280
+
+Set 1, vector# 90:
+                         key = 00000000000000000000002000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 51A7510726D12FE9574095633A3710E6
+                               3EB8196622BC808B8A18800E208648C9
+                               F7031F8171B71F37613753A5E49B37C1
+                               CBC7933A52CAD48601E91CA198EC19EB
+            stream[192..255] = 286EF1C4F74C993A7D783E86527CDFE5
+                               213CE4DF7EC72544685291D8108C7621
+                               50D488AEF761D819781814F4501553CC
+                               B45EDDA85828C33C4D0608169AD20B2A
+            stream[256..319] = 89DF5C916612EF0ACC1035EB75752239
+                               ADE08E0D63B622EA52CC997DC8178C4C
+                               4E57951FC8C6659A225E88502742B888
+                               1F300FC9F278AA3D9C1063A83CF33C44
+            stream[448..511] = B2DE3AE2941AFBDB21D80ABB0EB852D3
+                               A076D98C696F886C302D96D6AD226CA3
+                               7B3213B3E641632B728A0AC7131B74FE
+                               F733D1B18666D36A02C148FC98AD2E89
+                  xor-digest = 01090125BA6C43AAA3910B650D046F37
+                               E04896E9D2BC276D969A10C1B26FAD48
+                               8A2CA5E59044ADDF698588A561557669
+                               A4EF25E1BB85C0A9D63F69FBB2924F83
+
+Set 1, vector# 99:
+                         key = 00000000000000000000000010000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 545E2C75365948B40FFF042EB6919907
+                               6E63EE636CB343C51AF6C17BA24E1BF5
+                               C045B0893B8CBDF6A4068F8574513676
+                               80000B10BA11666A546D8DC75374F5BB
+            stream[192..255] = 9805DCB5596FADF01224553F3A8DCC5C
+                               909D1A5EC2C29BA0DB86A46ABF70BAF4
+                               4A171739309A923428EA7BA8EFCA5CB0
+                               B0B8A5EFE9A4A39BE0EA6CEA782DD862
+            stream[256..319] = 531EE320A584EE1E4E0701400F86DC29
+                               69531C2BB1BC922CFA9E0919A05B84C2
+                               46495A7C358015724B62A986220DFA17
+                               6BF39FE4263A9D27D93F3737CC1D5C59
+            stream[448..511] = 92CC0D63772783AF62E642A5849CE7AF
+                               4D21EC815D644F88887242F4F5F7E1DC
+                               55E241D72691ED50D59CB3E2FE68A856
+                               7696F8B8E3099642D70EC3945B8BA656
+                  xor-digest = 855CFA62E449250845472BCE9453BA45
+                               F91601ABA6BB715B079D407E05D94CF5
+                               93B5A1E2C12C04C78AB719339AFC11C5
+                               213E17ED9DC2B0B9CCF751E0613D4F2C
+
+Set 1, vector#108:
+                         key = 00000000000000000000000000080000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F9748DADA2741A7CA30EFA167ED09978
+                               71619682AB68CB400A74BFD642180CC7
+                               F3499CE2CC86AB7727786DD01AB8D08E
+                               8774C5A3CFB4738FF1E3243DECF720FD
+            stream[192..255] = 5AA20B305F5D6363180CDCD4E16427E7
+                               2E3DFD73D2C4E2498008F6E0FA9CE3BB
+                               D751F6EB8DD5F48EB42B994688601E3D
+                               2CEB3DE19BF16C4BD7FD4B331FC93473
+            stream[256..319] = 81E3D9BB421CB09A9139534C6E430668
+                               FCFCB87E48CFA085D4FA1AB316CD5AB6
+                               35294E434852C1509C1023A85B26622C
+                               68BE19944CA3233A4D3272710A791E3D
+            stream[448..511] = A499D228204BC22C32047DF550E2CCC0
+                               260ECB7BA32E8F5CBA2C1D9A09D1F38D
+                               FB30815BA3C9A8D3243CFE7AC4A14B1A
+                               D6AA67D3EC0A5CB617FAD57E41A2A0DF
+                  xor-digest = 0324B7F1BD990F8DBF19C021CCDF741A
+                               1B4A9C3C3940CC59CD715F0B2CC31C08
+                               82E5B93721AC98B00F7B45FCCF19FFA9
+                               782B7D7FC048F0756A29B066B472B394
+
+Set 1, vector#117:
+                         key = 00000000000000000000000000000400
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 7EA95775329E2D1163E30F429FECAEF4
+                               CA177BB4D3C4D1AEFA6B5A01904266F7
+                               7D7B7243B9DB1490245EC05129CA2DBE
+                               E3A98885DAD0B43B0E725DDA39B444EB
+            stream[192..255] = 78ED15A7B4A8151F384C740B844115CF
+                               D4FA31F9BC16E22158B0F896E70C0F73
+                               F74AA5EF024F6B386ED71239CBD57996
+                               4583C37104AD8C7E5C812C378AF00F98
+            stream[256..319] = 292FF21E49659AF99AB21753BA2A2B28
+                               25DDB156D4F7AFC1888FBE8376AE4C6B
+                               905D5916121E9F9D76C83FB146ADA735
+                               2AAAB6E89CE9398C484D69D1A33F0C97
+            stream[448..511] = A50FF5FC20C57F8297C9CE2599A3E6CE
+                               3193746E8C45FD9AECA0C5A0FB3BF70F
+                               5981B5BA8D2FA57677EF65B535FC3E65
+                               405BECF0A508445E36A7B6DE2BB56106
+                  xor-digest = D9650FA5D128620134828E1C99D9678C
+                               CFD5BDFADC46A5E79D47AC5967B8A1CF
+                               32F7DB65B949C88CCEE0D96D960A110E
+                               FF1D09EF5549B88D5B53ED46D4C2F296
+
+Set 1, vector#126:
+                         key = 00000000000000000000000000000002
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 25874CF64ABA4536844F815F486F9DEF
+                               927E325CFF2FAC48134A4D30824C5BF1
+                               EC75F8FEFC624AFCC717BF2C8EAAE374
+                               0AF399C2653389DBE31F9FF5D451D362
+            stream[192..255] = B151A1EDCCB8B4A3CA9BC98F19EFE637
+                               BE2D6A97A8F794091E7FFF06E7B4E574
+                               46B81E8C787BB77E461592160C44B5AB
+                               49329142D01A1CD5CFC6681F93DF1E33
+            stream[256..319] = 29B2B0C04E07D33EC3146E60AA305F0C
+                               2288913B55DDC18FC17EE836B39193DB
+                               87089DF2BAC4185A57E910331864E25B
+                               540BBC968099900F7BF18645A28A419B
+            stream[448..511] = 286FCC98B40EA26BFCBE5CDEE52B30F5
+                               810CFB26E756C628B56B3B5ACDA49E07
+                               192592CA2241C6C5193221EDA36CB0E7
+                               B5C3132F08087DF0673D3101FC559962
+                  xor-digest = DBF1D7E0AC062FE6BA9834F0AE41ABA2
+                               B28B41FDFEF914F070007B0A48EE9D9F
+                               E69DB8395BECDBA7B545201318177A49
+                               7D343A317B5A37A9DF98DD25C84DF948
+
+Test vectors -- set 2
+=====================
+
+Set 2, vector#  0:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 5B078985D8F6F30D42C5C02FA6B67951
+                               53F06534801F89F24E74248B720B4818
+                               CD9227ECEBCF4DBF8DBF6977E4AE14FA
+                               E8504C7BC8A9F3EA6C0106F5327E6981
+            stream[192..255] = 30DA9453A90909A5675D6B691CB0990F
+                               C423CDD8222EB47245BBB67BCA2B9C10
+                               8D1F016DF0CF8CEAF6829910916DBC1E
+                               113D11E91BEC3D85C47E3042EC865658
+            stream[256..319] = CAFED71B892EDBE13388CEF6A3365797
+                               E0D88C0D3A5B91BE4CBAF5162F69558F
+                               DBB45CA6F8C8D4C371D62736EC244584
+                               60131F54854F3EC804AA9A38E6ADE281
+            stream[448..511] = 531A0ED5D2A51DDC6499FE1BB6E2295F
+                               2C3EA0F56AF46ED93DFAA4E16F5F0831
+                               2D77BD0E9122043CD6A202CBA9351F6A
+                               0E8E6263F4017355136A0C551E6FD0F8
+                  xor-digest = 023D719F61C193E4CCD87755C87F9604
+                               C5A29DD7E31637B3DD70D43441D48CC7
+                               D474013C85EEAB1897C80ED0A0272543
+                               F951C72E3954616CB5D6B51FC24F4B0F
+
+Set 2, vector#  9:
+                         key = 09090909090909090909090909090909
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F5C2926651AEED9AF1A9C2F04C03D081
+                               2145B56AEA46EB283A25A4C9E3D8BEB4
+                               821B418F06F2B9DCDF1A85AB8C02CD14
+                               62E1BBCAEC9AB0E99AA6AFF918BA627C
+            stream[192..255] = 3B3C6E78A8F381EE2C159FAE1C487C58
+                               11FA9BB02CECF7440239FBB0497347EF
+                               D8F1A8AA71AFC70ECCD64E81388E6E87
+                               9521C2B47AD84F9CFD9E240D8D2F3001
+            stream[256..319] = DB04FD01BC18D91E2D31237AD0FE26AD
+                               3C8D6A2EFDAA9CC11BFCC61D94F6104A
+                               4091B3634FA57AB0AB9B209F22DA5529
+                               75C3C322DEBE4AE68623BFE1B2BB7F0A
+            stream[448..511] = 35B290F85EBA78A978750690C4747E8F
+                               72621951483772E8B89876CC5D55F3AB
+                               02D9B8FB35C741279FF9B5B571B26329
+                               4D011F813CB5B209CA1A22D532BF09B7
+                  xor-digest = EA9BB65E87C987EA64BC3F4E710CCC34
+                               F6CD0A795B8347E1441CEBEE35540D41
+                               64FC2B95D71FD47A2C4ADF732261EE52
+                               8125BE374FA4A90132CC1063971A2862
+
+Set 2, vector# 18:
+                         key = 12121212121212121212121212121212
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 397F8EC015ED573967938D1CEAFE9BBD
+                               BD8853C329B3A881B489090853FE0F43
+                               89DA105F0ADFA9CF51DA2521C40FD2B8
+                               FB0BF80B93E3F2B3D8A8EB1C615E0FA6
+            stream[192..255] = 68E7DBF465E3C6994D58B9937A866E4D
+                               43A82A80DAEDBF29C048639BA38B690B
+                               7ED11323E3C0A8E77A16356705431EC9
+                               9F2CB7F7E1ED3B83EAF2CAEC00B00755
+            stream[256..319] = DA51CF3A07EBE7E86E9DDDE5A47E7417
+                               376F334E6AEF9C187012C8AD2B94BE7C
+                               00A876756EB232510FD0798E72EEC87F
+                               75EC1467C07B3A1EFB0D51A5FA65E382
+            stream[448..511] = 0BF3C6FF6794887F2776FD632B83682B
+                               AAFD131432CFD7D2F675E03320395313
+                               AD4ED96E9052FE6B2D2A17428660A25E
+                               EE642B712800BE3F7E44F21A1E6A03AC
+                  xor-digest = EF4E84DBD66497B142EEAC56B830FF78
+                               0465CEE20B9CFAF5727D4B3A588F4D00
+                               AAF718330CFF35508C44C1ADB8476625
+                               2CC3AA6AAAE74F8BF1DDB6D4AADA425E
+
+Set 2, vector# 27:
+                         key = 1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 72BC8A6E1E61E704B142AA00812EE676
+                               263C1CB9AB941119B19D15EBA3462F56
+                               2F69220595DE5E0E7C595FA40F1F06B2
+                               6EC32252AF05310809DDDFAE2E24B170
+            stream[192..255] = B29A740B51B4EA1080666337D5551484
+                               FFED6860A5125DC0573C8F90F23A98E0
+                               BA7B3E4C28C2CEFB1C33D2C36D1B7625
+                               64B9A67240CF174347A4C8D868F00F6F
+            stream[256..319] = 555ABD5577A8909797FBA9769C03A0F6
+                               537C06AFB23354F054E25457B729B534
+                               CD10B2ABD45BE3E38DAF1B7A9103268F
+                               4FDB4C0FC9A80A003FCB907E8F249AE0
+            stream[448..511] = 3B29A43D9C795DAF1760CA9EB57C0B39
+                               F62D54311207B617B727FCCE1B2E762A
+                               060810C4DEF672E7D76083E3E4BED0D1
+                               0BAFD27CDFD2C937E660190D36B3FD7B
+                  xor-digest = 0B3B0B3C69F2E4BDA22E25AEF352234C
+                               18CC5E1E3F6A317ED7257887446EF734
+                               65CA15F51AF5E077B7915062391D8497
+                               8F437985DD08F5FA3A8D74B3227A6EEF
+
+Set 2, vector# 36:
+                         key = 24242424242424242424242424242424
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = C845BA29D542FBED2D021C85188E119F
+                               D34967B79D9F44635DD45D2E41DC5AFB
+                               B237AD2FA0E4CF4202D83DF3073C578D
+                               2AA8A32D30FB45DE28F23CEB85E50FBF
+            stream[192..255] = 15C910FDD3C590AED1ED7DA2A7969297
+                               FD12081B4B23F0A32CE5B3196173C7CA
+                               7EDD03F9637E08CA501C4850C15B207D
+                               7AA724377396CED2357B572BBF9E69AA
+            stream[256..319] = E484AF567EF80BAE77461855294E9280
+                               EF57E7366605785034D639D6DE3EBB0D
+                               E21886D0E1E0679BC2E2C9C2D9201484
+                               4A452B6AD3F1AC8B7762FF3C0E405B3B
+            stream[448..511] = 595D9855200786BB575FF7977509F395
+                               7879CA1F19619A99174BF013CB62F85B
+                               FF2C3C4FE724E26DD0C10D7635A2491A
+                               9E7E868D9DAD9201465AA178184D06AC
+                  xor-digest = 08737B82505F46F4FF282EF42F387AA8
+                               0450058F5314389BB73733BC163D75D5
+                               D32FC6408F8DE5F6ED2050027D605FAC
+                               A7119FC2DC1B6D3E84E8048DCC42FBD2
+
+Set 2, vector# 45:
+                         key = 2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CA82A689535CA8BAE01BAFEBA6504B3E
+                               6E6320101999BCE5550C2BBC9BC65D91
+                               FAA2D72FA4BF46B6EE916244048B1D09
+                               A115E3AB6C00BAC8EE382B58859E8157
+            stream[192..255] = DE787B1CE01B0BC09801D78D1FFA3A82
+                               0C18B867C561E96DF4ADADC5A4375E44
+                               5A34F9457E5F8C9A337A0C88DF0F723A
+                               D4509F1449DF2C6AEC0EADF4C7A8139A
+            stream[256..319] = 7E1854FA15DF9D5827F1555F12B292C8
+                               452A1A893EF034C51750388D294947EE
+                               3F505839C69C1708E8323C449C39A96B
+                               FC9EC91B0E1CAA8112057EB0389FDFD2
+            stream[448..511] = C85B42B838FB9C3D4956C9E22FBD8FBC
+                               EDD92C4461EFBA5CF1664B9AF54857BE
+                               C3D00319E5E8A89A8322831151EE1D52
+                               D8585AC79CB60B61ED2C852D04BB0FB1
+                  xor-digest = C65A6BEBC4FE898DB8D6B8F6E8F3680D
+                               2363BC12259B0FDB2BD8F052A572ECA8
+                               D1EF62AA9A48497805A413742B5AF5A2
+                               6DC9FF624B49E5D6FE58BBE5251B4983
+
+Set 2, vector# 54:
+                         key = 36363636363636363636363636363636
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 9F6BCFDE566A1B67C608F11B8461E340
+                               42D4F07DA4D5EB05554CB7426D65C5EC
+                               A93C2D321175B6F72FCBEBA6E38CB098
+                               B72534F7D534B1AADD97B77E8513B482
+            stream[192..255] = B2466A173F436C8433F264CBF125B8E4
+                               C10BC81BD46B5C21FA161CB2AE07D27B
+                               F66812A2C2FCB2B14C23E413CEF4E591
+                               AD52EF810A000B42E5C1B76EEBB17739
+            stream[256..319] = ECBED2058DC50223614EB8635B834C3B
+                               B176719C18CA5E3D087A93E5CDF81123
+                               C6FB819CCAFB5042AADFED5E3C33116A
+                               FD92AA21031165A22F4751C423B8B945
+            stream[448..511] = 758BD9435DE607867DA256064C304C8E
+                               DDDF5B64173CF2C98B2842992F8C5FE1
+                               A37C3227B7F37D49A39F9FF929A883FD
+                               56DB8B1A174E1E55FCB21C9E1164C20B
+                  xor-digest = 31761A49503946701D35306FBCBE10E2
+                               02967E7EC14A328B4DB19FE79F03553F
+                               13A012B7297B2D02F18A216AD24A682B
+                               299518C3769123EE86A4937DAA9FC39B
+
+Set 2, vector# 63:
+                         key = 3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 85C7FF83641ECF1C91B2D996D4EAFF6B
+                               26A4E7E34C0CA9CB9399F655E566383E
+                               246143F57776C8E08951E87F76091FE7
+                               2356CC901F09A07895A890AECF047B3F
+            stream[192..255] = 4CE0C6606195F7562D485E32E8E105AF
+                               C862100A07E55FB449BCFA2D9BD48658
+                               958B37B3EA3565FA66824102A14B5770
+                               5E3914E0680E116ED58212CBF61028E3
+            stream[256..319] = 3BB772A5A8DE2AB14CAC1ACBF45B1701
+                               057710F24C01E680F58090B8E949AF01
+                               8970A43A698A04C0C8639FAA665DA3AA
+                               562B2C5C3A03BCC38FE75DC1821ED718
+            stream[448..511] = C73DEA1F7BFE42DF75EA2681BEB31948
+                               821FBB049DAD15B988A77C0247868A38
+                               2056B66F47B0195FA30C9DB5A2334A9D
+                               CD7C0D22E479FAE1BBCDFFE60F261C7F
+                  xor-digest = 94D41CCAD940CED3C854DA0796DC62E5
+                               6B566A980E34F353CFFD0F53AE9E34FF
+                               A6A057645FE66D86BE30F93805D9E2B5
+                               D78C68EEBF61CE387277A51EB2EF835B
+
+Set 2, vector# 72:
+                         key = 48484848484848484848484848484848
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = E45194379659D1D8904DB3698AF8B245
+                               762910B7FBD019AD1AA20A6C433B4C80
+                               308A9EA68697631646BF3A2107C4E7FE
+                               2235E8F3262A9DFD3F5CC23FEB0B2DAB
+            stream[192..255] = 012611EBCFF9F839DDABF99D9D4757DA
+                               4E947598C4757976F6F61DA5F0DAC8BC
+                               DDF72F08BA2F446FA37F9A490F6A2B6D
+                               79227C93271D6B763DA7B2A907220A42
+            stream[256..319] = DDE54F9170D6A4702CAF45CC6F799F74
+                               A43D83AB8ECBAC5206D108F869561D70
+                               F151A0037F8E28951B5026643F8B2D6D
+                               56A62E259F04A5EA304791A9468E66AF
+            stream[448..511] = F70794C084E6EDC07BA0347413B05FC9
+                               FC46994CA820CE4FC037ADBA50EAA9AD
+                               55064ACB7308CFCE3F35AD5C7C628362
+                               F4210FBC2D3264F734728626BABF5356
+                  xor-digest = 31815B36BA034BB1941DB1E45A941A59
+                               7C3882F34BD3BF441CAE8A9790B05BCA
+                               72049FD10C09A14AC9DB867A82C38A5F
+                               524C72F783DFD16980DBCDEB486FAE96
+
+Set 2, vector# 81:
+                         key = 51515151515151515151515151515151
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3C04E21F6937C4EF472BFDDA89F9CAF6
+                               FF53889A9979ABA8F23AA51DB1EDB8E9
+                               D08F696C1100799A7D004DEF1CA94110
+                               FCF0C054B0C131E6FAE0FE2F2DBF22B3
+            stream[192..255] = 9B4ED3EF9639B953186FC7E732E7A9EC
+                               55A5F3F19C5A10E12EBE46DD84F10385
+                               33837693588D584FDAF86E3A217C3CFF
+                               020278736F1A90CE07F0DCE4329005B9
+            stream[256..319] = 135FAD68B5282FE59B28D2DF66463632
+                               06CA92E84A73FA131EDDCE89A5C23B4D
+                               08FA57D455BDB32F8ED58DAF3EF288A2
+                               7C72020E35DAE19B446E4C52DCDAC5B1
+            stream[448..511] = 7D08FE1CAA0E8A0362669B310B99127D
+                               18F2111002891D3229102D72605B9BEE
+                               F5DA36059B0DBBA7646927650305431B
+                               FDA4A97570CD0C484BF1E974B157ED7F
+                  xor-digest = 5125E77698C0DAA89A7E47DC5D038D40
+                               7B732CE56CEB674CE653A1B6661B2740
+                               0C092AFF83BEEE4FC4543B9D725C9387
+                               2F89AA338222ED677BF59397200AB304
+
+Set 2, vector# 90:
+                         key = 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = DA2E6F7FF0D1F1C87A97E028D3E20E21
+                               75E9AD91482965B651B495AEE819CC6E
+                               C42AFE2C20EEACCEC4E90710D17210E0
+                               4CC6832905985322C8007F872D3E58E1
+            stream[192..255] = 09B0A38E19DDDA08F7DFEF7D0FC80560
+                               D692A020F0A66F609374ABDCD1343722
+                               05F19CA04EBDD3009844BC540C1B2B41
+                               66D45E8A2E822B906DA34649E7FEEBB3
+            stream[256..319] = 6C8E2CE1D7FABA414432E75BA2EFE4AF
+                               CE2CFE99506677A956AEC86BD290B6AF
+                               C5298A448D0DEFA99AA5CD26D318982F
+                               E786D809C713D5A55B42CA6650191DDC
+            stream[448..511] = 845FEA0A88B521CCB8927C9457AD3225
+                               EF6E3C21705EC9FB24873916A2C24668
+                               963C03FE097DA8224A42A99E5DFFDC17
+                               68CF518DE49CCAC8A70216C62C9CBA6D
+                  xor-digest = A46BFD9D2D0BCC688A032F54733AB7C5
+                               5FF58B296071D5D39349A531E41F0BA9
+                               893A1722B6102740BC5FE394A49363B9
+                               6A626AB43FD6A288CD9B23F7255279F8
+
+Set 2, vector# 99:
+                         key = 63636363636363636363636363636363
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CF0E05248AAD82F1C8CD2095ED2DA333
+                               BCB02E3AD8797377AE1F1B4D6DDB86E6
+                               2A59791CB553550E0492FAB42C7A2C42
+                               3157C5092D2DD37D46589F17FBD86584
+            stream[192..255] = 9E946626F1EAAEDA42E52422B4A84D91
+                               4122EEE5736BCD12061C77DF5B0122B5
+                               1784E946B4E93470170ACDD7E2779591
+                               57BCC9B9F3E11E88BC2F740AA0C10C97
+            stream[256..319] = FF22D8196AB3DF662210D12D0FE79255
+                               6DCD39611C07F089979CF7D693A30CA3
+                               5B795B7F6D64931916E717C8BFB92114
+                               DB75118BDB51D142CE8133415C6B3456
+            stream[448..511] = 971F007EFE17662D95F47F4F28266516
+                               B22A1E50755EEF19149DE3A3121F5FEC
+                               E0D9DFE7A055026CA44193542D7687EC
+                               695B97769BF02F92C1EF3D904A8010C6
+                  xor-digest = D1C4878BEFCE48888A43C6DDE7CC8163
+                               C8D54A4CA36748C74721C7B6E1649A31
+                               4B5B7A4BD43E7C3D2A22F0C8446C7892
+                               90D54D421D37CB16400E59CC86215CC8
+
+Set 2, vector#108:
+                         key = 6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 54F122FC8ECFB176E7F4CF172B2D78B6
+                               54BC11ECF0010D2AEB9F899130F4AC2A
+                               38EBC15C8831D591E6675DC1CE7A471C
+                               4B869FE83CBF37AC70BAAE5D4AC607F9
+            stream[192..255] = 518F298A6008532EEFECB3DCF72103BD
+                               5E3F84FEB6EA2311E8C19A2E93A9C3C3
+                               BB1DA7DBA78D5618D1C4FA5B0B202728
+                               62645A361E55494D66C9359E41E5809B
+            stream[256..319] = BAFFFC9206D1D813F3E2768F08D78B2A
+                               89BB20CCD92E7F13FDD816DD4E4963C2
+                               C5FC2570CBB8BB5C70848B73001F508F
+                               47AF179528200F51CDC6E4854EAA63C3
+            stream[448..511] = 844B1D15FBFD1264169279ACD525611F
+                               A39C7BB41F1E7A1C09090625F7926E51
+                               23A4CD7FE1A3F37ADC67AC437BF0A5AE
+                               FFFC6FB0ABF39D9908145004AA5B958D
+                  xor-digest = EC67596C9DEF4012A2D543842829306A
+                               4285A3B8038818F265065DC848BD80FE
+                               C27C2F66A57B27F7FA8AC912001EC954
+                               05BC6E93D7E555C59060F5D2E294D103
+
+Set 2, vector#117:
+                         key = 75757575757575757575757575757575
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 91D2772A18995DB3C0801DD3740F4466
+                               F9535E5BECB93DDCA0E94D19C0B57BDD
+                               0FFBA9DAF0B11D55C852927F8BA560EC
+                               4999E25848D08FCA7275E7E8571A5F1C
+            stream[192..255] = 72E64FF10CA9F07CC493715724DA7610
+                               9E4358E8B0CAE451348B784A162DF036
+                               AB9796724D17FDBF356031D080A6631C
+                               D1E8D217B041AD2EDF427972653206B2
+            stream[256..319] = 4054F770C93FCAB533143FFCA8E4C0F3
+                               344956C29D10374E502C2EDD177ECE5E
+                               6625BAD9630DAD57976216CD69865058
+                               130B132FEC1AB0C350DF4DACE4C7724A
+            stream[448..511] = 40B4A4DD63F7B6E932482D0E6F5BBB90
+                               E402466550B518A177CD05985D238827
+                               BD92EE7EC22C274F19E682F85ABDAD95
+                               D0EBB3DB6C6134408353C8B0472C9A1D
+                  xor-digest = 9A6C893F2108D13A29373DEDA65386C4
+                               AC356BDDD4A3178952F9126E322B7AE6
+                               83C94F1A131CBEAFF26549D9F84CF04A
+                               1241FA374B055B0ADE7E49E8EC669E65
+
+Set 2, vector#126:
+                         key = 7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 87A7773A3514EB7F882F2C491E90DCF3
+                               059C5CC575D806B9029CCE3FA45A246E
+                               0EBD3AB2F2E324FE36ADC3B56AE2F7EF
+                               C710AA964CB87381386C2A88B1308035
+            stream[192..255] = 415D6F59DD004944D4E45FECC6F1F06E
+                               20BEB18D9C84187C347F43B17E0924F1
+                               2348F825E106E57A00258CE4415294D9
+                               4323A9812D8A71359CEC1001BAA0D567
+            stream[256..319] = 8E20F0D03F37EF4B2C5EE12B5F81F7C5
+                               32D62E779FA0D2D08F8ABB6B0183A4DA
+                               4EE0329215F261D953150B9AB9FCBE2F
+                               568AAE361EAA8636ECC01A63F007977F
+            stream[448..511] = E7C44F44E06321A20E25F73E2069757C
+                               90499DB7E60025CF6D2D445E53A665F3
+                               08EC96F6FE73C0AC90D7E4A712E18C2D
+                               3DED46DFBAFA24C4B0B329E52C525976
+                  xor-digest = 22035341489FA6EEB2A6488CA42F4043
+                               57477C3F55569A1224EC39B1019E90C8
+                               21D37D78ED4DCEAF6EA70724C3751760
+                               38CF25DE4F84BABD80424D83A310881B
+
+Set 2, vector#135:
+                         key = 87878787878787878787878787878787
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CEC0C3852E3B98233EBCB975C10B1191
+                               3C69F2275EB97A1402EDF16C6FBE19BE
+                               79D65360445BCB63676E6553B609A065
+                               0155C3B22DD1975AC0F3F65063A2E16E
+            stream[192..255] = 5E12BA9DE76F9ABF061782EC1C4FBBAB
+                               3373B816DA256CAAC37914B0C161E4E4
+                               5F5ADBE444098A5B2A4CFD4251D79918
+                               987BB834BB50F0834EF4985F356B92A2
+            stream[256..319] = D89642D25DF97D149AE07EA18BA39497
+                               8935978AC34C1DF9F444986D7505DB4C
+                               7E08DB3616B84CD52E7DD7FB108C36B8
+                               B50C2573172F4D3500B6D62A9D20B82A
+            stream[448..511] = A2C17FE7371604556F796429C6BE0688
+                               8611638B310F3E9FAF484BA9EE29C16D
+                               2F842EAF33AFEC557B68D2F453569187
+                               A6F4CD204A0E7A733E81AB7CE9FCAE81
+                  xor-digest = A7C93087CA70DDFE5FA5F1F2F954320B
+                               6E3A61977A7C6AC2F033B826AB9A9957
+                               66671D2A1025CDF8E2824B2F58CB221D
+                               2A68679239D90152FF7D0D39B33FAB93
+
+Set 2, vector#144:
+                         key = 90909090909090909090909090909090
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 7118889F6E46A6523BBEFCDB006B3BC6
+                               71A6D390BC7099A708D370DCD0E3D143
+                               A0334619EBD5C7DA9EF6301F29273F85
+                               2DFA3C580ED65C6E952F88A0B7FE368E
+            stream[192..255] = 31D61E133CA1AAE400CB2DBBAE93C75B
+                               445792061AA0539DA69ED0B77B970C0B
+                               482156A5DEE4082A61364BF06E692399
+                               FB9F4411FEC515291F8949B20F57229E
+            stream[256..319] = 993E815F299D4841518119BFF88F6EFB
+                               F3DB9BAE60238BDE2845DE4DBA6D79DB
+                               C9E42BA5C3C004AE4546FD86C660FFC8
+                               FD6A8A349669FFE3D9E5BDF8E50A407D
+            stream[448..511] = 0F9CEAC6BDCBB56B7E97DDC95877B2B2
+                               1274F4A6D814B5440C74D53A3FF0735D
+                               EF01B14AE4188E215CE7337C04871688
+                               7159695A241BFB9D6B489FE9E23B2AD8
+                  xor-digest = 0BD5739ED28778023E6303FD88DAABC4
+                               0FA0A211A1A5C5F230D9E67DDD9EA517
+                               FEBCDF0BDBC107291B6CF3ACD8B862B8
+                               4BF15400493A54036E97FDEBB9A1DB2C
+
+Set 2, vector#153:
+                         key = 99999999999999999999999999999999
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 236ECC5AB83DB1C5CD1C5A888CFEA2DC
+                               BE99E7E515650511FF7016A0EF287ADE
+                               5A03839C4F83F05FAC3B0B24D4E3F602
+                               3251F8D9CC4530A805F8A6A912EFAB1C
+            stream[192..255] = 792823ACE2C0DDB266A118068AE295CD
+                               716E424D3B98A9DB2501A3F5DF7DC70A
+                               3BD2C6E664D5E13317D6F57B8774C903
+                               D407D2BB6014E0F971141E89569C5868
+            stream[256..319] = 2D6ECCF738FC00ECD5475EDA959A73BB
+                               304C81FA9DDE0C21592247C4098D9347
+                               1DA30294DE8C100E5B17A199F744CAC2
+                               4E33490FC7F223FD6B4923056117C6D9
+            stream[448..511] = E791A6BE7F7593788E5D627F5CDAAB59
+                               349AF2BB1DA2BA622B9824F729929098
+                               BD19DFC05D0D9454F604960C027752F9
+                               7812E53DE6AC6CD2751AB331703646AF
+                  xor-digest = B7C5CE0D2FF66533A1C948C425F33FF2
+                               DC458E7E517637596FC8FB710E2E5636
+                               DB1F14848CB12793D54ABD0856B22F3A
+                               ADFA8C33AD08B8CC5292DD76913CB105
+
+Set 2, vector#162:
+                         key = A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 74490D19F13E7C6D1B25C6408E23F229
+                               8A8806402755660C4A30CD216A500BB6
+                               AE975E08EC62D08425A8A62A71B00215
+                               DE35E5178902348698528CB82296F009
+            stream[192..255] = 51A6EC18829928EE94C37A5CD030CC4C
+                               E4F7E1B3E78C3A5DF07592F45B968BEF
+                               F95B8B257DAF2B468284627AF4481FD2
+                               67BE0B164DD86721DC8C1607A0607EF0
+            stream[256..319] = 75C565D5A5A240B003273F99BEB3E4B3
+                               9C056162B626F383F3E77B5C98C0FBE9
+                               119A7C335C333E6490126AC2510CDFAA
+                               86441C72D1DD9ACBCD3FEFC0D0C794C7
+            stream[448..511] = 2D90CCF0B43239D725E3B53C31B82754
+                               246C065AD23A8D709161FC74B34E23DB
+                               B918EAFA4465125D3780BF0B5803AACA
+                               037AA0A14D977141B611A6CA2278B634
+                  xor-digest = FEFDA1A6E95920B93380CC24FAE214C5
+                               6B009ADCB176D519CA4B8538EDFC95D1
+                               6CA06B730B28A230F0085FE43CBEE2FA
+                               2EE5DCD74D66F5CBB59F256CC1ED885A
+
+Set 2, vector#171:
+                         key = ABABABABABABABABABABABABABABABAB
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 22E1A884ED2C67CCB2977105649B6544
+                               367858D1A730AA2FA96703FA406B337A
+                               B2159A389BEF48D8A215D870B2968E16
+                               B11571F12BEC0A07FA7D3B9790987EC7
+            stream[192..255] = 4C98DD259D03A40AF38E0ED0F37CBD74
+                               B27776E9250B8B063E52E169C7B76A15
+                               0D699278AA4124427B5EB6AFC4AD5DBF
+                               600FEAAA98A88DFF297DACA5ACB4878F
+            stream[256..319] = 5FC732A26406FF0DBC764ACB05C83484
+                               976B640E60CCD6ABFB908583ABEC3E75
+                               2878371EBB5374C9B37A63E0768AE10B
+                               D857253D940AC408EF49EDD590E806AE
+            stream[448..511] = F012E429C44D5DC03B88123855B62C0E
+                               90E06759306017B5773752973850531B
+                               C480316CBBAEDE6353AD5FB298349AA9
+                               16AC0221A4CE1E4729BFB9C230AAF9FB
+                  xor-digest = D73B872315F9052C67C4CFC5CD912DBD
+                               60DA32FD06D9C8E804968E688898200C
+                               1D979DFFCE52E1C3B3309B58D12BDBB3
+                               D3EBA2954D1587D720E004E12EB4A13B
+
+Set 2, vector#180:
+                         key = B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = BEF4DD0101F80A8F880BE0613B2AAF88
+                               D2EF924014F7445ED922E9C021571909
+                               D7E6BFCAEE0724F2A9C522C4BDE4BBE9
+                               FE53FE592C0FEB80D2C7A51FB8BE9EF3
+            stream[192..255] = 6B1966D3EE460999FF09001B0ADEC484
+                               0D22CDDFF39EB0E3D5FDF74C6E7B3394
+                               A0A4271D780DE6DEE9AC58B4903EEDD2
+                               6DD14E14A4DFE506748D5DCA6DDF4C5A
+            stream[256..319] = E79D99119996FBB5163335E2F79F0502
+                               7AEA5372136E7B3C5BE1F4A673A2DC74
+                               60834B81BE6C4976C4A727C8E6046A64
+                               4CAF42EEA6A068B7E532581E9037BE9F
+            stream[448..511] = 5C4F52E0E94884C829DA1FE88EF34614
+                               9F3EE55A136EFA3B417DB63D2487DF82
+                               794E161B3153DDB2E1E4F385E1A848C7
+                               729FF5CB1CB58D5E73FAB1F2DCEEE5AD
+                  xor-digest = 2F3C231B0228C274255F3BD314ECC7F3
+                               1B9C49177009AFF2CD88F807092D77E3
+                               C74C1B9B8650F581EC7603F4D6E70955
+                               1B00C3192414C04AB0AD8B0B9BCFE988
+
+Set 2, vector#189:
+                         key = BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 05AF4F98E9D526CD7912F3E8CAF45410
+                               DED6D4E331633C5621B94E7EBD15E856
+                               04AB202A553EFED55A548C7AFFCD2550
+                               60315FD50A305D8BCAC9C077229D34AC
+            stream[192..255] = 786D24EF3FBFF6883A4ECC4F40E445AF
+                               3CFD130D5B6A9CE37BEBA429AD137A82
+                               44D0586FEB16D086F533D1885A82F73C
+                               F2AD2C645591F80ED09942F0A08D898C
+            stream[256..319] = C214B6AC700164FA66DE346A27A99463
+                               C5B6C0E43A9057384BE168E163058FCB
+                               6E7DEC871C6531EFC8B8D581EF92757E
+                               219294D39E0C9C8276440BE56C3D9941
+            stream[448..511] = 22CF14F5BD70E719AFE76C53E5D611AE
+                               4C8D2171695C9CF97E2936A8BB320670
+                               015825547A508EB43D96F2EE1EE2CB34
+                               4E120F001500F8ACC3E19E30455D09D0
+                  xor-digest = FE5928C74EA21F23E29171E5AAACA20C
+                               DD8571E907763C96B99A8C11F9A1D2F5
+                               78F68A6C440996995F7AB6E69B3CCE33
+                               CF8CE0C16F54355696D47DBF82EA8D56
+
+Set 2, vector#198:
+                         key = C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 75559677D7C762F6CFED942D800F2FAB
+                               AB5F3892DC2C79922E96FD34FE511C11
+                               251C8EB7C639E531CE08A8C99F62E7BC
+                               F68FBAFF99D62348FF91CCFEC2710055
+            stream[192..255] = 149806A4D862EEA81F0208D927339E5E
+                               C98E9C2A6E0DB85CC0380DED7EC5B8AC
+                               4ADAE76AEB9C7B7264C3834316209615
+                               25221D58C0174577110596FF89C8FC69
+            stream[256..319] = 137E527A0ACB8B96A9FA07890B60B78B
+                               3CDD19BF89B31FF75A814F470BF97E0E
+                               1293B750B769F5BDD750DE5025D7534C
+                               AD541A1F26C6AE9AC2FD3237C156AEBB
+            stream[448..511] = 0958243E88921B81F04AE63658E52D76
+                               CF2638495B3A6B970633A7C8F67B8CF9
+                               AC378082F72FC63BEA02881CC5B28D9D
+                               C8C261C78B2872B5EBFC82336D6E1A28
+                  xor-digest = 0084D7BED4953402FE8F7FF71A28CEC7
+                               0028A08A00EF935C06A8B3632DAD5914
+                               84E44E372A753F8E630741266C0F4218
+                               4923608103042C70ED4ECC5112B9AF6B
+
+Set 2, vector#207:
+                         key = CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 0C46BF67A3DBA5DCCF8E4A7A65B6FE28
+                               98C701CBF5E88F1F3DCB6B873E5CAEEF
+                               23024ADA678E1A2CA9E25AA8B476CF4F
+                               9FCBC297FF03A9B94A5A736274EA776C
+            stream[192..255] = 73B9891D1770289A67D6338909FB6282
+                               9A425B7947FC30DC52B11E398E85B1EB
+                               537E1C02898FEBFC15A9172C254CA55A
+                               AA1B56EA856F47E37E2F252D92D94ED8
+            stream[256..319] = 6522D372F90F2DAC155D48F165B6DFA4
+                               38B63B9F436FE00CC075C585297B8F90
+                               E6062358D29641FF9C28EED4A23FC53A
+                               6B5C60C2AF1E8146DB27CCF5F43BA838
+            stream[448..511] = 642541A9733946827D79BBD815C03C17
+                               6357BD6E81E9A61FFFD4A0BF6863AC71
+                               72AEFB92C1F235641BBE1457B724A6AA
+                               AF9FAC687552A778B034C4A4F8E41ADE
+                  xor-digest = 9DDBC1E7D31379D027B4F3DFD72C3668
+                               BD0BC5A97655978E79056B3D25DF3E79
+                               5D5D8BE5D1AAE877F2E7D03225CB6609
+                               6EFE11CBCB728039A243E326437CE73B
+
+Set 2, vector#216:
+                         key = D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = DBD4E866F4E24E7F66816CAF625BD07F
+                               1F7BDFBB81428FFEE9FBE14DF5F5F3D8
+                               A044EF53A868D989E16165A0F2B95E8D
+                               83439BB4805A125AD0CA7994AE11B852
+            stream[192..255] = 7CACC4E7B9B1957ABB22ECB9D9D67184
+                               EE7A7F4B822A1C955A69E238022AA313
+                               276C2003E27AEF1B4F94B33A6428685B
+                               F048B357EAB297B7DD98E612F054A317
+            stream[256..319] = 286B484FA80A45EE4D5300DFBE173E8C
+                               978B976BE1B6CB0D15C0324D6B70D265
+                               385B615B3EA97A55D94C47F53FF40861
+                               4460857AC9568556AE54A52546B41B5A
+            stream[448..511] = B3AD999394343F6F0BDDD0B1FAE2E3A6
+                               5BE2BF56D2B78A401D5761E2F3AF8B18
+                               A2B1089864999D9B99E5BF6959F8F802
+                               975FBF204D6159CF23F3706CAF0D9BA5
+                  xor-digest = 0957D6887501D4360C430614B67D99B5
+                               32849E2F5C69CE8A9F3F707A2B5438BD
+                               0C1237B5617FB525CC9C043A10DBB265
+                               3C3F0A353E89A19838B8F68542E09526
+
+Set 2, vector#225:
+                         key = E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = A6DF8DEE1EF7D1AF773AA3E9651B645A
+                               50CF101BF065F69F3E78BEF5D689B1D1
+                               D306FF41EB3E78BEB75C4200937CFE60
+                               E89E370680C519B2F64E23516ADF8062
+            stream[192..255] = AA30580A210B87727BE17EC52AAAD037
+                               3E0DD11FBFC89B37825CA4D6F9E8D433
+                               E3EA54C37D678B58CE834AFA310F6D4D
+                               06B4603F12DBF38595AC76511D0B13CF
+            stream[256..319] = 5F3E1A55116CB67BC91C8E37182EEEEC
+                               8FC9B09DAA6F418D3434BFBBFF6BFFFB
+                               F93F8A963F2F51CC487BE868F010EC0B
+                               EE17A480542A301E33B36F59BEE13D91
+            stream[448..511] = 672048756C221C12DA6178BE711B3371
+                               525A92BC9A219CABC5501B0DA4CC248B
+                               8742E8BCBD6F5A1CFE522F3DF3BED6B6
+                               5D60D1AC737ADC582C2CB9751521828B
+                  xor-digest = E7CA739E4DE0E74274E491CAA9BF5CAB
+                               3F418EBEB69509D69B2594E964759D15
+                               104F674CD44681AFECC3B4939CA0A0C9
+                               DD7AA5726653ED3FBFC833DDB0C87B42
+
+Set 2, vector#234:
+                         key = EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 2479A8F2872A813D16D15F060D300237
+                               25297B812F6F3B97D74D9716E4403A5A
+                               684D2BFD1E15275470FEDADF1578277E
+                               44C6C06B8A5FCE3D0CCC5E13BF49947C
+            stream[192..255] = DB2F9B25F9523FF5C2CCCB808EFE07F3
+                               132D4B0065A563288F848E05EB45E48B
+                               D15C069C02F90B4FC10AEBF1AF4BF90E
+                               2CF7F48C8CD7A8091014131EBC21FBE8
+            stream[256..319] = 84FAF79797E25BF2CFD54E58F5C7AC1C
+                               EC170B064429EB832924CDA9C47B5174
+                               9BFEF80D96FAE36DDA65659FEA1CC06B
+                               4EA3A1601A3304AA4DDBEB62381FD4DB
+            stream[448..511] = 2C8FC8D23E7DBBC37BB0811D1BC71145
+                               BFBCDBAE19F5281CD0E6AA37419778DA
+                               64DDF68726DD7F4D78BBBFF4576C2AAD
+                               93F477A2AB2C3CA8A381F30BB944C7B0
+                  xor-digest = A6D5F0DDFC0A43491D6D0A17C095C070
+                               9EC7E9B89DB8EEA11045ACC5FF003DC9
+                               CD3318BB6F9675EEF20E15490F525066
+                               AF8380C663B60EDBAE30663C94C39892
+
+Set 2, vector#243:
+                         key = F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CC3701E703946194401D1BA23AD99B5D
+                               F3F856138E142D4B9C23DC9F252A277B
+                               D62DAA33A71A0C61079AD5A20562291A
+                               B6EC92C66D7BE6A17E27D4DDB48EFD31
+            stream[192..255] = D00665FC0A4ACC78758EF25B0B0D6903
+                               D565423614409AD11E821B83F5B35D83
+                               F26F3EF9EC1766FEA9C21C09E0AE248F
+                               4BA01E48BCE09D06471593B3466703DD
+            stream[256..319] = E8B4EEE2C8BBEDBA758C1C2D0889FDDF
+                               96CDC215EF1A62FAA29A5608C852FFA1
+                               18B473C5A7319446F3ED2E8AB39A533D
+                               714325D1B14E838C9EC6E037DB0DD93C
+            stream[448..511] = 4FF3B43841B17A279002EFB07324625B
+                               7E937D480DC73F12836195110ECB4DB5
+                               CD31CA4F92F612A95E82815328DA7D5E
+                               4DCC5BB6791603EDA64C57B5A5AAA04C
+                  xor-digest = 9202B874C48D4B1A9E857E645EE8F884
+                               D971CE97923AC024ABEFB944E34550CE
+                               31712BB832F9174F86FCD369E75CA9AD
+                               85095F43A4B7F33AB641BD6912D2C59C
+
+Set 2, vector#252:
+                         key = FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F374DA745A5CF93A567027609E5D3B1D
+                               5C3C8A4D15203705D978AD42279F6548
+                               51FF713F5120CC93D044EF717F5A75E4
+                               98DBEF559E5F157A8C819E213E93B3F4
+            stream[192..255] = B270F638AAB88DFF69D724F79B70CEC9
+                               175AEAA99D55485954B265B5CAB86509
+                               C810E664766A8E6C90D4BEE3A58B1815
+                               9076959FFFA2F30EEB12343E9E7778C5
+            stream[256..319] = B2CC84A1127B5333B30EC81CC14307FC
+                               418DA96336991A27DADA74FDA987B867
+                               B125C53C0E4E2889FDFEFBFB48797A22
+                               2836B2EA42793CE2BFFD568F6234B368
+            stream[448..511] = B70F4A10A1B75D499E8189C8B92AFB36
+                               4CD2D730DC8D7E183EC55A777C2445EB
+                               BA7E9CD95C8F3A206B73C422AC2E2C08
+                               15A8C6FED156FFF93B63DE512EF69725
+                  xor-digest = 467EDA43B849054EE747A532ED0D9AA4
+                               6EA1BF2B6AF19F481D6E3D55EBAA96FC
+                               6629FE65B5EC4B5EB6A155A6D60FEA32
+                               F04F8230E26390F1C8FA53D47B68FEAE
+
+Test vectors -- set 3
+=====================
+
+Set 3, vector#  0:
+                         key = 000102030405060708090A0B0C0D0E0F
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 0315CE93BE05F88212B413335CA65F33
+                               6387BA612421C7BE8276299CC178EC31
+                               2143C503A9F2644685882201137BBBD7
+                               3A2385F0AD14B690281B54B8DC064150
+            stream[192..255] = 8B663563AE31DCE7AC61BF4943466774
+                               E9EE784644AA761B9D8AA9B8E04D4C91
+                               75650DDF130454DD60724864DF2FB6B4
+                               31F947F8FCA83F6D3B113BC413D3CC10
+            stream[256..319] = 35EE3D4294E5660A99A1A1C9254D27A4
+                               B42FEA8CBD5C5BD8B902E1B1BFEF17D6
+                               ADC9B6B924C7C53D44A5C58210989BE8
+                               72E532300EA9115CD2AAC8024779B3FC
+            stream[448..511] = 402F841F64827A197FC56EE9C180F5D1
+                               075107622178407B063F70C6C860C6EA
+                               E3016D56F7CDC13A109283F5F4FC9420
+                               6C62BC3D1012EA03EE08EBE8C2DC074A
+                  xor-digest = 6815E00D7D3414FCB103EA82B38FD4F4
+                               68A453E84A520B7119E9D3A4C938BF0B
+                               AC26F7F73EDA7F3E2F20FBA551C15205
+                               EBBF2F6BFE6DBAF95061F0AB3988DD57
+
+Set 3, vector#  9:
+                         key = 090A0B0C0D0E0F101112131415161718
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = E695E5417AEC9FBFC0EB0909435E79C6
+                               76AB8E2F28C556CC2C81CFC5F7A2A6F1
+                               254EC0CD2CFAFC257907723557C1DF5A
+                               D81D1E3D201410A12A5FA3A6160F266F
+            stream[192..255] = E3D590D9AF3869FFCBE2A4B8C77A09F6
+                               211193F83B8A43714CCFC02D014376C5
+                               A44FF7C061471AE208F04DCAA89792FF
+                               AE7096EAC47898C1011095DE9B55682F
+            stream[256..319] = 0F31D78C0B86D246FE105AA6D9B93CE0
+                               257E75CC0D2A0BE96B9156555D8A407E
+                               01F47AFF719CC894EE111C32672B0404
+                               B5F26C1DB1D7D0F9E470900AE53B192E
+            stream[448..511] = 1A01733BB8EACDF2B2F4322FB54FB6CB
+                               C92989248FF31BBAAA8304ECC4AF9A39
+                               CAB21BB66E0A144D8B77C537BD52DDD8
+                               C5B0909CC6423D4F243E5AFE6E22D07D
+                  xor-digest = F8C3BF6905A19184D14039E4B7FCFACF
+                               2EFA004B35B55DD04F56199C6C9DE1B4
+                               458C5EFAC45C6062BA1EB726426987ED
+                               88FA899849CF5F6CEF60119F6A68AF9B
+
+Set 3, vector# 18:
+                         key = 12131415161718191A1B1C1D1E1F2021
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3C189DEDA71E56926CA2C3A2974C4FAA
+                               B7EA3C1250E768CEA797ABD6477B59F0
+                               E5494635CB4700A95BBD54B0E93D12A6
+                               423DF8F34BC6B3BE705ED6704BA33894
+            stream[192..255] = F21E411ACF063846BF68F61F7673710D
+                               CFBF8088E2A815F406E17C4BF4E839AA
+                               D2EB9D137B0F7889E68F4B5C8160199A
+                               7C9C697EA6A1794E954ACB535A72B255
+            stream[256..319] = BD7E1C4A54C911E84067AB00F8427810
+                               BDBF4029E78D424E65F477BEB457900D
+                               0EA49B639863BAEB1427A161B8C629D3
+                               55097F5DFFB24BB97329A73B144DB7CA
+            stream[448..511] = A4D9A80D0055F2D8C55D2A49B39DCA69
+                               9A5652C43258152B42BECDE07F21F8D0
+                               EAAC565DCDE549CA4A9A27D82F5AF4BB
+                               1EEB1B0A53A58E50C3E83CBCDCB980F5
+                  xor-digest = FF451365606D0117E15FC2721F40C9CC
+                               0FBF6442A771F8FC3B06186C35C6CA13
+                               B30F65FC84B9A38A6FBA2B6F16541B0A
+                               0D77BDB4F696894B2B73CCCB8D6FA3B7
+
+Set 3, vector# 27:
+                         key = 1B1C1D1E1F202122232425262728292A
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = BE4A26D09D47D25416355FB7FF60AA06
+                               3B3CDE5374780F2C66514A0CAA07406A
+                               88490A2E3D6294A799C9BAAAA1B10ACB
+                               88FF4F6F70EF1F4F67D591040244FEE8
+            stream[192..255] = 54F1AB7235B6440D6A7FC7851E3FFDA8
+                               6CAF44E3F57E1E9406908064FDDA3A3A
+                               3C7AA1CB6ECAAF376C5F290EA02844EA
+                               779A225131F24D2E7D34AD0342399FED
+            stream[256..319] = 81AC4F45FC40CE7E1FF890F5EFF2B583
+                               36F71D1911C7E0227AD8E4DFF7369B41
+                               A8C266B3468A78773C4C40A3EEA6B724
+                               97662462F48835FAC7B6C77CEFD39A65
+            stream[448..511] = CACFA9A51224F533C600BEFF1EC03C7C
+                               7C22EDF93E8596128F8709F0CED4E291
+                               997229AC5542FD2CC9B1167C3D2BB57D
+                               9B08B82C0FC41D93B7CE2211C5E2D534
+                  xor-digest = 0D949205B6024DAC1D215F2AEA7CB484
+                               3FAA9A1719398AB8828A28BD2568369A
+                               C78A224AAD95BAE6A6333C4C13D630B9
+                               42AA52099F6EFD6871B1E45C8DC68AC7
+
+Set 3, vector# 36:
+                         key = 2425262728292A2B2C2D2E2F30313233
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 65906EA9CC0080D2044671D22C7DE242
+                               F764184ABE8DADBCD550225BFD541D6A
+                               762C7A5268EA0ECE51D18269E71A4CCC
+                               054AF634616204C81AE7E515719775DF
+            stream[192..255] = 9ED75834EBBD9576E11DCE8C583ECEDD
+                               2B8780FE98B44E9F08BBE96922C77BEF
+                               08DCE0DFD7C77C42236885BE6EDC8343
+                               24EAED350AA5A513009272818CBC4BE5
+            stream[256..319] = EB1D998260B3AF4472DE59E1C9DD359A
+                               B346B32DCE36C92C9B7BD808BAB76AB1
+                               EDCA2827557501BE0FE28F6498B33B9A
+                               F4EA48786F3158E8047A32A03AE1CD90
+            stream[448..511] = D06B1B9B8110FB9809F5887A35CB24BB
+                               80EDE203AE648AF9FA348B18D8A15B8E
+                               E98E8AB98A7AC5BF71FDEAA1A6E978F6
+                               7D5734AA7FA88E8DA44C861E2F54E585
+                  xor-digest = E77DF8C1D5F46F8896DD00187C840B0A
+                               E4404581DD053C6F39323815729DCE90
+                               0D85C2D8C97D0A3B57CF622F81077B80
+                               92988EFFA36CA176F7393D1E38AAB206
+
+Set 3, vector# 45:
+                         key = 2D2E2F303132333435363738393A3B3C
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3FBFE9A391DE0CE5AAEBF9DA3A15EB99
+                               D6CBAD0341CB78042C89F5D5B0B555C8
+                               A400DC47FD19F40493B348CB51430B44
+                               D05AFCA9D399709EFAB8ED2587F72E85
+            stream[192..255] = 68969047EE54910C44F8B5718E993234
+                               D814C27C0B59EE09F0D35B58352AA6C6
+                               594F605C25C16CDDC29A354A1C6F5948
+                               AE497C093E2D41C211E4C1417DFAAFC4
+            stream[256..319] = 0DD68E08A25ACA4448DF4B562EEBB855
+                               14E41F1F560C479542FE62C2DCBCF03C
+                               30AF180FB71E65A9A09C551551A33942
+                               53558C2440084E6B4CB664A4EAFCAB66
+            stream[448..511] = D93B80D67B6484030103CDD72536E695
+                               E7BAF8B1115109D5D5517BD1E06F4236
+                               A3551688F5C0D78B2CB080AC072B4C48
+                               94A2AF54AD9D816E2068AC569BCD2AE2
+                  xor-digest = 7C071BF395B48A023A7B708A9651EC8F
+                               0C9A00DE8BD9D0764C7F1F394AA2B747
+                               3EF87BF792D5B89AE0548EB9C1344DAB
+                               DF2E4EC6064D50EE1622160D6DD7ADFE
+
+Set 3, vector# 54:
+                         key = 363738393A3B3C3D3E3F404142434445
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 64468807E7EFE78E11B0231D8D7AE80D
+                               BFF3FAE444A60496C8F2DA202941686B
+                               95C48457C1F9DE1AD2FE581336AE36AB
+                               CA574BCB9619CDDB96E4499409516635
+            stream[192..255] = A7DBFEAD9B969D334705B6C53A0CDBC2
+                               21E0BB92854B0B107CC39F8C6E4761C3
+                               EACC8D8C5741AA4243C5BE1A79971A0A
+                               5A23F2BEDE9F3628CB9099B8C7EA9324
+            stream[256..319] = 1A44FB18740973F3124EA805C90C4B27
+                               4EE788D43F4B894B01F63C13410EC204
+                               2607241E87555B0E1A6FF33AF0DB010B
+                               8ADF607E6353FCF74F568E0BAF0F4455
+            stream[448..511] = 11568B95495E520EB6BE106986A07C57
+                               8FDF21463607619E5AAF117D84611E75
+                               F8979F59E60B43C0A37BC24429892742
+                               0D206274DA45EBBA7660422DA45294CD
+                  xor-digest = A70B9BFC683AF2716E17980A49C4F747
+                               AC25992BA7BCA5E5C2AE162497E4E8BB
+                               62C837F64EEBE4A55B5705F115CBA057
+                               C560B1AF0A733B5631E23442601A741F
+
+Set 3, vector# 63:
+                         key = 3F404142434445464748494A4B4C4D4E
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 35865AF843244DD2F95CDF7C9BD54471
+                               9C8432538842C28F93AA21F6E10F8B18
+                               31C2AA7EC010A66E539CF65BE55120BF
+                               090233750995003C7AE414DA6D55F86C
+            stream[192..255] = 190F215FD14E44CD141E47A2322D324A
+                               A63A7B512A77C20A02D3BFC1EF8273C8
+                               F65226CBD1BF32A104D1AFEFD6719E4B
+                               DD6355B044EC8D0CE95023C61007E6BB
+            stream[256..319] = BD02130F7CFDBDBC2171BBDEAB501136
+                               B2364F5879E6E9CCA7E75AD81105D9E4
+                               87E9175B62AFCAD79B23D392B2E9C418
+                               437527118797602E629A70CC869AB7EC
+            stream[448..511] = 1F0DF396B5CA6EC9767B0674B2C7A9C9
+                               133CF872DA39DE78F56D41C7F2FF6B50
+                               716717E995D42C51D6A2ED66FA6CC7DA
+                               92E9B3B4D1F130E699C430CFC96969BB
+                  xor-digest = 70291060FEA7D40B5C3FF731FAF7630F
+                               D9BBED1A7FC25A05E6B3F632E6FD6B91
+                               1F1010E1BEC69F16D44C5183E38BE8DA
+                               8949A4D8AA85F5149C203F8C92887875
+
+Set 3, vector# 72:
+                         key = 48494A4B4C4D4E4F5051525354555657
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = BFFC0703408DF6EB169656D09A5400DD
+                               9C4BAF06A3BC7220E45814104B6D9000
+                               9585BF9B0CD988E94B8C5026D07AD7F5
+                               7D81364775D54D808A5C18453B62A2A1
+            stream[192..255] = 5FC95B73A4C91DB20B93319E420B4C5B
+                               A9DE1873C81C835CB455970A90921594
+                               F9635EF4F411C9ACB4298F75B2CC84F9
+                               7F52182F7F001A1EDF72A68FA1ADE313
+            stream[256..319] = FB24E97B0CCFE15644BAAFF342C55FDF
+                               64434708407AA6D73576E842D5ADF4A2
+                               6B32D329A2DC9F1451C4BF3E9599E9E6
+                               4E5E65F73E09E4F1254BA0DDD8E6C52C
+            stream[448..511] = E2EB303CD0A67C99CDCEE86BEA581FF7
+                               093C9228900B563C6D10B20BF99D3911
+                               D47C805D1447C8F233D3FDD27CF0DA42
+                               D42E0389E2CCE99A274AD9D20B9C6102
+                  xor-digest = F83FB58CAEC8B13BC25C152FCF24E10E
+                               392A197FDA05A6A20E14093EA0B34C5D
+                               FAE102266465324F5AC07FFCECC8E618
+                               D0BB60761A26D5FD59D188097A2348F3
+
+Set 3, vector# 81:
+                         key = 5152535455565758595A5B5C5D5E5F60
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 84076D83A841C8C6ADDE3B5D9FDD6529
+                               4D0F92B549112F0A6DE05236F732E81B
+                               3C8E92229C411D2295129ECD18DD08DD
+                               C98BA78D9BAFF6271D95E1F361EF699A
+            stream[192..255] = 7063A52FB2729433D8A7BF30F27E6EF6
+                               F17C2A422E60A737270787985508D062
+                               4E678A597845CA9EF939F4B8966BD99F
+                               B8633FEA673CE7BFD2ACFB5942D7EDD9
+            stream[256..319] = 4FCE866E8C2359C53F0429F569D02DAE
+                               E99A4062246B633D4C502DC897AD8025
+                               38C95D49D3B1FA94F4E92441357B622A
+                               6264F50D5554BBE42191AB3D6073A8AF
+            stream[448..511] = 2F7C38BD00309FC81D28D84EE4355216
+                               D97A823CC46FAB9DCAF621E4128F9CB8
+                               838BF02E0EF940EFE96860CC0B996044
+                               42CACFD3306335241C1B4B65E790233E
+                  xor-digest = 44038A33AF0013BB34CBCFB77F7E060B
+                               96F5134DFCDBF04EB8F7F29B15C3FDA0
+                               F766DC940FF548C23712625793851A94
+                               294CC7201E1EDC6056C12A46524C6FD0
+
+Set 3, vector# 90:
+                         key = 5A5B5C5D5E5F60616263646566676869
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = E811CA3DD1DD0057AD3A1794D3F9CCB6
+                               362049B1692D6ACFE1A6A0FCC99C7A04
+                               3AB9932A146B4040AC9F8E2F0A227C7E
+                               C60B1F35D60EA14483BAE1F8D1AC7FE1
+            stream[192..255] = 865B05E224133AFC45043F05F8082FEA
+                               487BF63BCFB96DA3EE26960061446669
+                               B1C92C6BC5905BD1EB57D579CB62A220
+                               2F35CEB603658237AF1908132A25971C
+            stream[256..319] = A84BE383FC852F1BF44130EAD15B3548
+                               56737C7EA68A0700A22D357FBA70E031
+                               BDC0FE8EC36C41790A8B7706A00CA338
+                               603E054A83881599D718B1911D1CE9D4
+            stream[448..511] = 9286C3479F9A17B51D8749257F59E892
+                               CE7C3EB8638B29C17D779811F01EA405
+                               257062A5F28BCDA1862FE653C7607350
+                               9A87D12EDC5CAAFF9E8F9F76DA0BEDE2
+                  xor-digest = D629CA4708BEF7EED04BB5531DDF9C64
+                               BA4981C9A705D59C4B2391E94B79CFCD
+                               058406845D81E7EBC097330C01FCBCF8
+                               D78940893B4FA38554A32D861AE96D04
+
+Set 3, vector# 99:
+                         key = 636465666768696A6B6C6D6E6F707172
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = B89516368AFEEEC12434F76AD1E1ECA8
+                               FF6FEF7B46D05EDD6041C7B8C1E3A33D
+                               2818E38113592B615E980304D93435DF
+                               BDD5676225173331C3667F30AA2A3D2C
+            stream[192..255] = 249528FA392B19B6811711F523D27578
+                               F1BDE75CA167DDEC08303906B64FAC0F
+                               B2912A7A0EDBEDAF9FEDA420DEA330CA
+                               7302F5780827CB11B15A4DD333FD7099
+            stream[256..319] = CECC1B5077BCB9E129B01D8D75089B41
+                               64E76DBC9C8CF2E4D2F17A6248522A51
+                               FCFBFBC992F75D613307F4DD6472B6DF
+                               C8A5B29F1068FC0F1C3F8964B0E09170
+            stream[448..511] = 8B26C436E918B099E4D3A7D4D3395E49
+                               056A8A29130667A32C6A2B0FD08A482F
+                               8F7538ED90374846FFD2E1C733AFFDA1
+                               12148C9718F3F208344D5FC20128AE2C
+                  xor-digest = EAA0ACA59CF63BC27082BD52D6757FD7
+                               620A7AC5AA2FAEC52646978E2057C5FC
+                               F60B36C09D87419C1D1A64133357DB05
+                               6B96C854F38C36DD657524FD09729341
+
+Set 3, vector#108:
+                         key = 6C6D6E6F707172737475767778797A7B
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 741C607A6BD38F93B33244C8B7F05D78
+                               46F6A05CEE5A87762480DE123D3BEE63
+                               240928FFC75ECD9AD1785B1664DCB59B
+                               A12F3B64C93BD4FC8C67C0934E5B0ABD
+            stream[192..255] = 3BDB31A701DD7F2E929803C3A47896F0
+                               9E5F569A32AA829E505E34BB7232597D
+                               B838F543A34CC288F9518BE16A228D42
+                               BED0CA3CE0C6E7FF9AEE63625C699B9A
+            stream[256..319] = 1CB7FE159EC1A57043BD142236DC0A18
+                               0CEF37316A6E96354AE319142282F19C
+                               1550EB645DA8F7BEE2ABAE4EAAC0BA29
+                               893E722A6F8E0A9B34368DF56C5845B4
+            stream[448..511] = B6DF810D69EAFB7F2360F6ECB50C5861
+                               7D32B3F495B3E4424045E88CFA0871A2
+                               9314121CC78B98B456ADF53E540346B1
+                               214AE2ADB65C552273F1FA498FA74101
+                  xor-digest = D35A8AE5783348824175BD34F2E16FBB
+                               975E7695DC6C4FF1ED763D404B0D4D30
+                               07AAF01E988BC85DB2FDD017691D3BB9
+                               811355C3C7A6156197AF57B794DCE85D
+
+Set 3, vector#117:
+                         key = 75767778797A7B7C7D7E7F8081828384
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = EA9DA2D5BD4B6E070479ABF8CA2D1B3A
+                               6B968A025D010944FEB51AB2E507F86B
+                               111F8A351A3F32CE1FBC4A75AC34F722
+                               1B5190F2390073084F8153E00BB98D0E
+            stream[192..255] = 0AE0DC3D0E2D3F5F93E446BEBECC4F60
+                               862D190829A209966E132DD029ED6998
+                               DEF4F613F3D53D0A36CFBA2CFE345DCF
+                               013B6CFFEC0116FFC1659A57FB42E0BE
+            stream[256..319] = 5A7FF46C335912389D8B88437CEFD27B
+                               76706405F45F87C91390273D9B70CC5D
+                               89FDFA85E20EC82B98A79BFF5FBF6AB1
+                               4F61F2C1289CD7B8357126C8E13271AD
+            stream[448..511] = 9398E699F5AD8FF31A50C8EFB9DF0D0C
+                               FD612B951A203C1BF85C62AB5AF1C412
+                               42BFD0A55F21820C6F917EC90A8FCAB2
+                               E774A93713A99C7900B80A2BF496D0AF
+                  xor-digest = 05D9732FF20A61E19428873830DA7282
+                               819234F22FE7DFD8871C21CF10C08EF0
+                               7C0413898DB144861B0CCB62992DF40B
+                               29A0A4688C91275F0A198AF39899E362
+
+Set 3, vector#126:
+                         key = 7E7F808182838485868788898A8B8C8D
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 8C4F8495C7231AAEB704E7AB9E79E748
+                               6CB5BC85D3622B8A2E2CB778BBFDACD4
+                               CEF73CC485D8E08406F5986A28706CD0
+                               56D085201DEDB875573B57629B8541C6
+            stream[192..255] = CC6374A744E9205CA39BCD678074B844
+                               16346A7E54F9B87905BADD2FACE7B9F4
+                               B0A366AA3F632A7A67AD8AAC4827C9BB
+                               A1E801A8786BC4FAC2ADE6A6AD6A45F4
+            stream[256..319] = 4F52AAB001BE94A60761CDE0334F8A84
+                               C617195B084E441070E343CEC3189CF6
+                               D6D955F9AD649A3891BDFFACA0A6E6E7
+                               7291396670BA07469D267EB80E48353A
+            stream[448..511] = 673AF85AD5A9A3F26CBABCE9BEBBAE21
+                               E0B6DCCC3256227FC0EAEDF343CC7E9A
+                               8896023DF073E88EEEF135BE34CF67A5
+                               5FB51D3A1754B15A7C4E2CCCB4C8D51C
+                  xor-digest = 2BD4B8BF9B7E79B0EB53318396B03575
+                               0AC918A6A05BBA499D81C9EFD32A0FCA
+                               34A83FC801CD6475A774091F33AE7689
+                               B9FE28645F545E9A9531F528085926F1
+
+Set 3, vector#135:
+                         key = 8788898A8B8C8D8E8F90919293949596
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = BDF2E95B80FDF304C3C4A8081391EDC9
+                               7F9553F93C27788F03797EDEBB8F59EC
+                               2FB2FCCA7727CA1CAEBF5C8DA8719492
+                               F1369D96B2FEFA23D89400CF7CA667EC
+            stream[192..255] = 6AB7500D876A4924DE59800345AD69FB
+                               BA1690733713BF372E0108D9FB65B0E4
+                               50BB89899AB84198381623094F823FF4
+                               8BF9A09F0FCA23684E78654F3D231173
+            stream[256..319] = 34ED638D249BB1AB8B16D350309AE32B
+                               9FB62CAB0EC7AB9D5F3C12C9A6502497
+                               6323EBBBC4CF308FFA68A3D4D8D3959E
+                               AFD3BE46E36072FD15A5DC3FCDECA6D1
+            stream[448..511] = A8BA33AF6CF545424E607A7FC4CBA593
+                               CB05B38C836B21D85B6FB1894926A459
+                               8D71AB424A5A582A491747FED94125D1
+                               08D6C693EC9E4BDE2F418810A921B54F
+                  xor-digest = 84F29F11524741D39779025D792AB735
+                               07963EAA0FA8EE220ECD3592E1320567
+                               BFE76EFC3356860192DDC5F06B94E552
+                               43D659D49FB94C30AB69AB5E9C370A5B
+
+Set 3, vector#144:
+                         key = 909192939495969798999A9B9C9D9E9F
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 1C03A0D6CB75670CD7D978B2E371857E
+                               27E597B15B905D5F4F4384FEC227073B
+                               5A56D8C0C4AF767F267DDEFF86AA036C
+                               41EB6170603AEB3E3C1EF3E176CED812
+            stream[192..255] = 6447D1E067550DEC9E8AE89DB02B85B4
+                               3DD7E511C8B98438BAA50CFAF7CDBB68
+                               757DA1D03A29B9EC6BD633E17BEBC8EB
+                               2D8D453F583E4D183AF30C9F47C8DD56
+            stream[256..319] = B324756101C28D9FC4D1F065F1D000F4
+                               1155514EDB30A7FE36C26B18FD93D6D2
+                               0470A41B6F8D2E8BE140568BF72223F0
+                               981CEB9D100B21C8B751BA6B2816B2D0
+            stream[448..511] = 304AADCAE0CE80E91E3558974A944663
+                               D1E2253977CD7B0D1BFAA138DD81A501
+                               D7EADD8FC834931A44642BA9873AC1B2
+                               47A454EE71F7AD8671BC15E088D01532
+                  xor-digest = 5980D43A91C09B20B0F3323F1750CB47
+                               118550920627B6C512AC5CC53AA6AD25
+                               68EE1EFE702FEDE7CADBFA25B32696FA
+                               12A18CCDE35A1B679F709F28920DF92C
+
+Set 3, vector#153:
+                         key = 999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = C2083A758037E850A6FE642EFDE59AED
+                               F51F3002BEE2E69DBDB538BE2D93EE8B
+                               27A1CC89672DC14C44DADE531A88A769
+                               5DC730A2CDF3096DE7F4BD08A1ABA918
+            stream[192..255] = F4D19950E6365AE6BE8011A24B9D803A
+                               D9A8547D452D8B0B8C51676E207DF323
+                               808B5A094A2FDEA5DBC86BFCA576E98E
+                               D0E049834CBE0B3AFAD6892B542EC7AF
+            stream[256..319] = 8F2A026EB2165F39E27DB86607878926
+                               4EC8F42A09E8C80B317FD4F1E32AF4C3
+                               73B7F5160C635ECABE495B01A3488E27
+                               94D226E2D86C4654810C08B2FC42610D
+            stream[448..511] = A1D17725577B7A4FD3D1A280BA2B5C0C
+                               386FCFA09E110F00C85ECA05CC142644
+                               4D8EB87CCDC2B23D1CDBBFFF822B5555
+                               11055B93ADC9168B7353CAE10551AF14
+                  xor-digest = 7B4E8A6123216818A218FBD50D8540B0
+                               A0B62DC114F25DD476680F85DEEA9306
+                               4CBC4526C7A8832D4BC534684A403FE7
+                               B80E7F20D967ECE044085B554C158AFA
+
+Set 3, vector#162:
+                         key = A2A3A4A5A6A7A8A9AAABACADAEAFB0B1
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 6FB232154275843C74BB886D09CBE0EC
+                               CCC539DD6DEC1EC6F31578B80DD3BAD8
+                               5C992CB1A0B4EA40B3EE0C5174E36A74
+                               E1CDCAB13830453984E4365A6C599F72
+            stream[192..255] = 2682C05E19F6D8FC4DDB15B2F8385B52
+                               C5A4A70FF5A0063CD696AADBF8505122
+                               6F696746D4F8C314543BC3869B1E7F9B
+                               1C0D004655FB6585723CD1EA7A700A60
+            stream[256..319] = D6BA4C5A33B8C2DE342DE48E26AE7B14
+                               8E91552D0E05AC9458ED0010E6FF53AE
+                               EDE70E910165B5986876799E60B7E6BF
+                               3109B9BAF7EE3670497FA7CAFCB14733
+            stream[448..511] = 70C4E8AB8E8BA681A2A06F319CBC952E
+                               E3E78DA589369FEEF8A6BC6D976BECFE
+                               E6C7143337758929FCA7E0945892411B
+                               047C2CC2F2AA284E95733DD94D46B89B
+                  xor-digest = E2D3DD6AC908FF3BAE4791A50F717B63
+                               FB3F1F380CC738E2B1626FD026C9BEBC
+                               33957AF4ED6E8B9864EEEAE262FC6168
+                               9A34FA14A35BD915B6945F35BC3D5573
+
+Set 3, vector#171:
+                         key = ABACADAEAFB0B1B2B3B4B5B6B7B8B9BA
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = D25BF02A1BB050E0D15246C2EFB3EB89
+                               390BB913916D347586DCDF71D6792CC6
+                               BF72F6F6A9B779BD8833C468684B4480
+                               52E153D11A0CE183CB337450C4482F6B
+            stream[192..255] = 07980A2C57E9094C5334016A782C830E
+                               B59420086EF9D36542A97220A5EEFE42
+                               026B39B1F00A78992ECA17FCDDCEEA2F
+                               88A15F934A1C65EFB770C2FB9712FFF2
+            stream[256..319] = 8C0AF45C68CB7CA8CFF1AB18F2F9659D
+                               E49DB5C4E3609B50C06F94FC01C059B5
+                               40E302FA8604F030701FE3C833617E0B
+                               094D0BBF10580F7C1C7047E86FBF93E2
+            stream[448..511] = 4D4BEFAB68D63085A05C729F54468567
+                               2C2A9452DF6B4B651A29FBC29513E3C9
+                               635DFD75EAC87A5B1362E99033304EF5
+                               DF42420DFD49C1830D66F4F90928F1AE
+                  xor-digest = 9A7DD8AA5D9E9DA4F34AFBDE9D909CE5
+                               DEBC05D2F930FF08AEEE4096B2E1E453
+                               8587B88E535A217E986F31965C5965DE
+                               3BF4A7F99B3B9D938D2C1AF7DFEFA14A
+
+Set 3, vector#180:
+                         key = B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 5FB2BFB5B9CC4F84D7641B4555DA4A7F
+                               C07C0053E7AD2CF2187F7F34ED4068AC
+                               6D5B43A5FA41437C05C65550786D60F9
+                               A737F44BE450A1F416C1B1A49890C609
+            stream[192..255] = 8EDCA89958225E39CF796EE587877A55
+                               F9B7A7381241597CA6280F7617A11922
+                               9268F95BB326585AB59F08BFCE8B5638
+                               B3A0D32A761C796060DFEBB5BCE859D5
+            stream[256..319] = 09601C099BAC574564E4CC6FD659776E
+                               4726FB22E0025C37873042866B913C03
+                               285EA24E37847F9AF6C838B82FE651D4
+                               EC5FBD40A256E6C765757B6A3CD08C92
+            stream[448..511] = CA5AC4ED4FBEF0D754F033B5267B9FDF
+                               3CA52B131E118174F70CD4F833A5ABBB
+                               198DBCDF18BABB0B0CC37ECFC8D93AA1
+                               5949FBB21974169B46D545F0ED03C71D
+                  xor-digest = 5DAFDEBC75291BA8F55B4A370756B28F
+                               554FEADDB7888F2834BA1EF221E917F5
+                               F631D5BD789701282DCF16FA450D250B
+                               52C627741369DA654E237B8D7F4A8BA0
+
+Set 3, vector#189:
+                         key = BDBEBFC0C1C2C3C4C5C6C7C8C9CACBCC
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = E9EAE6C4903004A2AFCD05FE2E3E7F95
+                               FF8BD2888C4AEBB81CDBBCB7488C54E5
+                               B50467FA82B0CA7EA923C608074E1B45
+                               6452821FC36789C8061E99E8A0C0B579
+            stream[192..255] = 1EC898A6958F23C186261F833BB3EF0B
+                               3C185AE8138311B6AB42098E9C6C7FE1
+                               0306DADE1DBF2B1C3215DEBD88AF1CBD
+                               2D805B8006FA0DCF136E225AE3D91AA3
+            stream[256..319] = 55566604D1C85FFE1D29810B6C49F019
+                               69ACB59765A3FBA2B0B9880064606E47
+                               18BC5F08C32EFC250FEE91FB88077A2E
+                               0840615CCF627C64FBB500B7B800B9CD
+            stream[448..511] = 707821EFE4119A32CFD99F7ED7CEC018
+                               C8EE90493FD9268A83E5482DAF9A646E
+                               8765D8199A56A12ECA50775099179D70
+                               B72A3CEC8F0EFF1AFD074F04548874E3
+                  xor-digest = A51E3C9C948B68A1543FDD1F158DD419
+                               195AE7662739446D9FD543681A866A6C
+                               F09756FF4E0C59BDEFFBF98D53F193A1
+                               77D7BF19320063B8AEEC8A544D5D72C7
+
+Set 3, vector#198:
+                         key = C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = EAA9729F0222A16C750540C605974B55
+                               4FA622F67C71FBA40236A71AC19706F7
+                               9E3792F4B444A39C9C1C902FDBD81898
+                               096338F6A8EB7C934B9558D48AC53301
+            stream[192..255] = 3B5E53787C050061000E3622876AA126
+                               00971A76253833C53B9DABA976169395
+                               3944B5050AB17E492E185737D67581B8
+                               B1C766D50C5B0C2B0D8C78A781E77D89
+            stream[256..319] = 175C28764FEAF8396B3CD34C829D0D0B
+                               E9CE0D75E79017A96C4E7B158B171BE9
+                               4C906FD4BD4946E6DEEC3C78B34C0754
+                               9E85AFCD958AF345E0B432F33C86AA76
+            stream[448..511] = 37BDD665CD9D5A8A8190AC3EEF981379
+                               AD5311E15F853A8A89840879165147A2
+                               807AFABB6236CEA9319DB32344987889
+                               5744A506CA76CE69D9E474840529D667
+                  xor-digest = 4CAAE8F441F6EF3DB6971E274181F8F0
+                               4D7BC603E040833E77921A393EA13F0F
+                               ADFF07AEC94555224F6204874027106A
+                               6D7DDF0546F300D3E84AC87699ED40D2
+
+Set 3, vector#207:
+                         key = CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 83AC8C40850F4FCA5452871C954AA61F
+                               31A9BD276D39EEC03EC5977A71FDAC38
+                               368D110C57C1A19F2A7461BBFA88E372
+                               F78103F9FFAC1361AC2D2AD84C6AA3E8
+            stream[192..255] = 48E95C2FCFC79C91BACD0C41F626F05E
+                               F80E076E359299EB5272A2F688F96F6B
+                               3147C5A19A99D562A11E953CB2A90911
+                               205A7760B5C8CD959EE6C183A8C1420D
+            stream[256..319] = 974A4DE50EB45F6144DAFFA6B4A68E39
+                               48838434497B8F9700FC42005F3C2FB5
+                               A79984CC2E770C5400EA21AA4EC05751
+                               80A288499879E50462225BE03D677875
+            stream[448..511] = 09823B2D55E26C49E42FC0820D7BA081
+                               5A7EA9380637A2AE2C0D29253EEDB884
+                               9BF4F54D64677F08A1763EFFD904B62D
+                               B3843B0ADE885C00640D16A99E28DCC0
+                  xor-digest = E73D8783F926558E0C1E1B0D3FD86CFA
+                               974CD70EBAACC0CEA2D977E9AFCCD384
+                               935584D2FFEDEA813E6234112CAA1401
+                               71E99BCFE61A7D0E430D4D3F75AA3E28
+
+Set 3, vector#216:
+                         key = D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 5DE3EC7E6D724976985B426D722D93E6
+                               1F40F5F17EA14B298AC898CBD69F2BBA
+                               5705E1D0CEF7B7122362FCC0D5106D54
+                               25D51F51E29C938C592D9E862DEE9E33
+            stream[192..255] = E079C49AC8F160A9D529F30151AAA7A3
+                               1D137E03DF4C23F8734AAC3B20BF8520
+                               90E3C2529761EB4D67AEF1CC46399947
+                               1240DEE8343D6355B5D7377A7934B019
+            stream[256..319] = DF574E03ADD1DCBD0712D2748C93CD72
+                               D8488396AE3D3275E5A53CAF3EC112E9
+                               50A79494F25B9EC111FE9A7A68A5AEA9
+                               63A4F87B37F822B79D954436368D8E20
+            stream[448..511] = CCEF4C93BCEB2494EB4C70F5E301E980
+                               C494AF8C117F291DD09E3960D2C5A7F1
+                               9928C08F2F51C419E734DE9AADD25C81
+                               3579A7F0B8B367A49B97DED5793E4DCB
+                  xor-digest = 868706BC1A5F3D0BDF96E10324EC36FE
+                               01596216B0B8BBFF69C5BDAF69D0F38E
+                               FE89FFC32D34D142F413A5BEA7AB38ED
+                               22436C62F86C540101DC0267FAF67904
+
+Set 3, vector#225:
+                         key = E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 45A0736DB4A28A3A6DD181FEF3485F2C
+                               918C65663597C49F4FB23CA550C77CAF
+                               7B331B5D183844278E0D959EA024CC21
+                               CE1A84923E6E782472BA1645BEDFC60D
+            stream[192..255] = E9EE0DFD717F72FD8899D23E87E77DD9
+                               F9DA66B4645AAD8D8C3B489B0A637449
+                               80020326469B4C6403012B6E315CD35A
+                               4344934D720467F30B61C8AEE5C3C342
+            stream[256..319] = 94A2BA2B744CB83A29004AE21470212F
+                               67C2FD18F227FC017131D7F4DD0AB412
+                               48C59BADAE2E408584DF35C603192E37
+                               344C52664DD68B9231661F304F483F41
+            stream[448..511] = 6A29174A1099BF8759D2F5F9BA60816A
+                               B290252AEE08339BE0021033DED03C46
+                               9C8E28AAFAFDC67A7F2219C8942B004E
+                               47263842BEBB47EC6B0666ACCC884591
+                  xor-digest = 7A7411EE5D174907B1138575FCC7479F
+                               AF3437BBF098CCB5D8D25F49E6788374
+                               CBC9CC5812982CBEAF59111813430BEF
+                               56D9DEEDB6C935804013759CFAAC40E4
+
+Set 3, vector#234:
+                         key = EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = C430C2A9FC44DE1563B1679C1A2DFA98
+                               91D01A302C5165EC13B26F6EE4F25437
+                               264AE9E18C98BE112BF560C72024827B
+                               85665C491C47BB396B5AEC66CFCCA371
+            stream[192..255] = 60F3A13B9EBF8784CC81C132E004A179
+                               BEA0606D4C2C830077A50004FB0487E6
+                               E179D81FD9784DC3783ABF86523FE4A4
+                               68930272980E3B46F865E4729DD34773
+            stream[256..319] = 44BC861136F6856B1C74C1CC13753B82
+                               A75E34EB40C518400B507D99B42E488C
+                               8A1F2F590E029EF48DAF2674FDB053AE
+                               5C0967923102EB964602256F70A9CC9D
+            stream[448..511] = 0EE3ADBC4CCC63A8B67C7812CD294183
+                               A2E9D4EF0D65F854FE66CF9D76A34F91
+                               867B27336F8EEC2E2CD30CCB98AD5769
+                               77B07C73C833B51753BB9B0DF08C4834
+                  xor-digest = 7F848C96AE9310B5282712493AD7E13E
+                               2B4581545E625A4DCD98576C75835058
+                               6C621244B6CD439F8E62625ECD9460D3
+                               A18BC2F5DCD9FA7E8CF7880CCFD1A44C
+
+Set 3, vector#243:
+                         key = F3F4F5F6F7F8F9FAFBFCFDFEFF000102
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = B9B3501C75EE296AE858573B63C4888F
+                               72B18683CBCD6B95602D51E4388D6DD3
+                               7129169A5209202E2C6EDEB5026B6511
+                               55E4747DD706DDF248A8705D50D38A29
+            stream[192..255] = 12F90D1028010D8296DD0D6ECC4F2354
+                               89856C315555279BD0A4E3161178AAAE
+                               BD849EC0A90903CCFE9DC7CC821C1CAA
+                               D63A45A1D0C0247F1FB1423877FE9A32
+            stream[256..319] = 9F0608162C6315D206B5EFB0E40291AD
+                               E882445B9F34154F6E21B9FA23356DD4
+                               79DFFB16482F6A4F28A8A0629E8B1D78
+                               EAA473CB126FB3727B826B4B3D6175E6
+            stream[448..511] = F26FAB00C37C03AE33209E19F865B135
+                               115A5E254A6B5C1A4896987EAC35C2F4
+                               327822E165AC6BF99F535055ED74833B
+                               C1FFEB32588D8995CEF0708E2D3CF832
+                  xor-digest = 87243F1D4D08D7EE39213D1A4B9E2458
+                               368339A11E364345B4367F84154B36DA
+                               03A3728A7EBD4237897F9D1A19CCFE92
+                               B9D67D3A4A755E6EA8382041D4827A17
+
+Set 3, vector#252:
+                         key = FCFDFEFF000102030405060708090A0B
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 05A90DAF1A6B6B60CD3B999A11FEEE39
+                               6D38983ECDA326EC9229D2A1EC722B0C
+                               3C0539DDBF6A4CF62B9BAFEA6C60A29D
+                               4AB63BBBC88987E9A74AE2F71B1E8DE2
+            stream[192..255] = 0AE6673D9F99C5EC9A4532B2B9786CB9
+                               E948A206CB992335FE868BB2271DCA5F
+                               9AB75995A7E7D46F8EA6693765C93D90
+                               9D41C24EF4856252986DDFCBE65D2D11
+            stream[256..319] = D8B07A866003059BAEE90378AD5EFFD5
+                               2732755E79402B50BA0F26A038B3D9C8
+                               1481C19080CB39FE840F8E7313D0C034
+                               9FEA4AA4801225630AAED3E522D6F920
+            stream[448..511] = DED21140E5A3C0C4615D7153DF9381F7
+                               269616817A273BFD984AA5E7CD9D9CA1
+                               9C28E51F4C03C262F5BB4175C799236F
+                               DA69AB27590857C0F270CE4BBFE02D5E
+                  xor-digest = 2D47DA3161389F5F54FAB37F391C21CD
+                               63A748112A1AB415670524B6CB93DA0B
+                               6B54C541ED59F3A54DE238C3FADB3236
+                               3871F6DB1A507B33C1B8F280B0C04B1A
+
+Test vectors -- set 4
+=====================
+
+Set 4, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 114265E078311C062B518148B4530F73
+                               DC9B95DCC41C214F8C9486473DC46847
+                               71819020010586A750426A0E633BC787
+                               6E228E2353AC0A68533C85A742387800
+        stream[65472..65535] = 196F53D41603BF286D1D11F012E564E9
+                               3C7FEEEC9539A015D49475DD8CC73C84
+                               2F85521B4DD9789A813A59D444AEC702
+                               164F669C59B43B5115202D08662D4EC2
+        stream[65536..65599] = 8A7B672621B0B77E8BA8EB9A71DB4558
+                               A78364244F182519F89D25D3012CF8C4
+                               E429DD543C8DC56C6DB8FA5E351BF615
+                               106B51F9FD00F54018A94DAA91D76715
+      stream[131008..131071] = 33EC15BB2C553646CAED9ABD83F37ADF
+                               AD3B3313A074B69FEAD405BAF897C3A3
+                               E12BFB2F4CC3136ACFDA284DA1E780DA
+                               B3E4D34C053302989FE6A79A1EB0F5D2
+                  xor-digest = D899BF7CD2972EBB7333D4E57DC809A1
+                               B717373577B15544443915B36ED162E1
+                               25452584F3E0C2B62164092219FBA924
+                               31C1FF2A14C8E2E437427DACF80A200E
+
+Set 4, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 8EA023E23D94434EAA064A4BE52866DB
+                               57EFB7B200DAFF5AF2AA72D3E55EE5F4
+                               5060FA89024F259CD2490C628452B1F0
+                               91020DE10263BA86838B2E388F5AD040
+        stream[65472..65535] = 5BE1EAE0077FCE5C2C21120EFD560A96
+                               27C3DA9462BE42580065C9E51B7D36C1
+                               D9D717DADF4A3122A08303A8E27721E2
+                               1DADC91138A2461713998AEE26F811D5
+        stream[65536..65599] = 482694A9797978003DFDA5183F00FF97
+                               9F38894BC92DC88418FF68156117A2B4
+                               EF10D76923A734ABCAD1A5B4224BBD08
+                               836E3765321045C3BF6A352371F82CAE
+      stream[131008..131071] = 614BC8A38C5F9E8507595E8F5A03484E
+                               C9DEC6CF52DECFAB008327527B822365
+                               A2038FF09411D7B952417C8C7375289A
+                               244D50703B73577EC272827A21BB917F
+                  xor-digest = CA9E6EC13B679609EA778447EEA1157C
+                               B366A08AC5A96A73D0B5E182DF24EBD9
+                               FC297219A0AF67591BFD68B1721B5970
+                               8EBEB3655791107FD2A0F2F2E341FCC4
+
+Set 4, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 5BD3D0625CEAA75ECFC9828179F7B73B
+                               288A208D60A2297F2C328DB0789BC869
+                               4E50F50E8797F8C7A49E24F72A3AC359
+                               796E6188C71A9B3DB88DAEB1BB2C77D3
+        stream[65472..65535] = 726C7D7AD756CF567E0E8F812A282675
+                               7E75D593C7FCBB45F842020AD59F2B53
+                               888354CEF541411B92C3AF6D57ADE7E9
+                               273805927DEEBE552B32D10754C9D2E5
+        stream[65536..65599] = 5703464C0AED290E65815D8D04098B0E
+                               22D2FA825ACD4391B56CA64CB8201BE5
+                               7B4FB9ED6BB7608BD820436146339559
+                               E7464BC13A8AE3167AFCDA58E3C017AE
+      stream[131008..131071] = FFC5787A10E340B07D08160D2C4F653E
+                               407857845A0D68D1EED8EAC0116CC376
+                               E33AF8A1120D8DCAD6C86B757AC50393
+                               46AADEFF012BD0DAA294DD240D87A98C
+                  xor-digest = B3BAA21AA82617D3BB9C2612E177CB71
+                               51A51790D97FE33C3F33C01B32091758
+                               5766643C125293E1F75D6BA3C46AB381
+                               75A2A4934D4C115A6A1547932B077A58
+
+Set 4, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = AC5DEC8B95C89F4794B7289C69FABE29
+                               F4AA64476D057873D87BD524666F62F6
+                               B71B5131BFB897AE64F2D500437E1798
+                               A742E7B7D06B8089F3DB2453D008C554
+        stream[65472..65535] = A2F58800E24BA8B754C64BAD9252BEC3
+                               ED1273598EEF4C6FE42FE2CADB81F220
+                               26A90BC88B43F2F1FD2E054E8EEECF57
+                               A114D087D5228CB276FD5F4FA3ECF4FB
+        stream[65536..65599] = 5C67BC8E188170A57DB85ACD2F7121A3
+                               7D83F1A708ADC54C14064A9559FE7E1E
+                               3F9E60B9670EA4394521B11D8283EE42
+                               12874323628EAEF0B90FC4653106D68F
+      stream[131008..131071] = 8AA6F8A20F7D4A0B7EBAF6A7336B6D76
+                               731E65DCCD179BD53F6B879E70B8776C
+                               6A8EA30BFF09BA3026B3827EDB9F9C2C
+                               0F96655D8B84EF725D0603F8CCE3C2F6
+                  xor-digest = 458DB66B656320F5F7E4FEB12E748C0A
+                               59F0CD8A7ACAECC25479C309628EC0B5
+                               3B441B831B484FD3180C52F63EDA1858
+                               7C232B195356996DC29DE6DF54E5BB37
+
+Test vectors -- set 5
+=====================
+
+Set 5, vector#  0:
+                         key = 00000000000000000000000000000000
+                          IV = 80000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 635990D909A80CE2A75E521ABF588B6E
+                               85320D2C722D1C93B42AFBE6358D6E2B
+                               F2BE933BC961FB50F9A2B55389A08CD7
+                               A0131F89CF0E61D0C7071DEA6D8DD4C2
+            stream[192..255] = 0F92D4DCC222BFC7020CA6BC3D044F69
+                               12D9A93668C65401C570A01D6BF6B3BC
+                               A6F00F6FF46AAE3C09C6158EF05A520D
+                               F8D55FF27CDB7AEB5D03C1FFCE7B95ED
+            stream[256..319] = 664CCED71B27680F9458952173BE0043
+                               D3C27F35F9CEE7AE9D783ABA671C4FC6
+                               8F2815DC904316BEB39020F646041276
+                               5BE5500A60DE2209961755C1BF96E1E2
+            stream[448..511] = 8F02C1FB389DD1C5F0CB730ADA528D37
+                               DD778C4782C7B5DF1961F97CC82B63E2
+                               9CF4BE512EE27B50781E297D1633D700
+                               1298F13FD8AF9D1EA83F831A70EE50EA
+                  xor-digest = 3F9A4D249220E1AC8E559399FCA23DD1
+                               1A250DCDA841502F5FEF0F5D4EFE7E46
+                               D9B1E5E4312903E290D695C2B681949F
+                               480D45F78FD69597570338049464FECA
+
+Set 5, vector#  9:
+                         key = 00000000000000000000000000000000
+                          IV = 00400000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 8E932D78DCDE35F1E5B8B2E863859A64
+                               7AEE8B0867F6F221B09C37B7A78B4043
+                               D055164B1FF1608EC17F3F148FEBBFF5
+                               A9FCE4158B33D2CAA4AC5FE5551C788A
+            stream[192..255] = 7034BE31CED03DEFAB3F69A24E622BDD
+                               9B202ADAF05D0324EE933064ED6D965B
+                               937FBC8405F0D7236AC28C320CE66C06
+                               C5B93EC581FDD59ED40102C651495EBD
+            stream[256..319] = 37C4EB0E72191FF0F70C8A70F475061E
+                               A0BEDD8A9AF1901FC6BB5482B5A29469
+                               06E8C40249E02784896D5D42387127DA
+                               CDF1657A66E0D43E6F69632519D1D3A1
+            stream[448..511] = 8CBE98126AE27A51146FE05F40CEA89A
+                               39781F515D621DD48B6D6234F9AFAFF3
+                               6FB862084F5249BCC0018E8FBC090121
+                               E227FF494BC180FF68EA2B134E7B00D6
+                  xor-digest = 24556A29026E3CAE101E7112B2FE5BCD
+                               3D925460B66A9EADDC271E39C317DC27
+                               51DC9254491F76F9163AF09AA5372F34
+                               1B76D54C09DEC9419F839E5C50F1957C
+
+Set 5, vector# 18:
+                         key = 00000000000000000000000000000000
+                          IV = 00002000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = AC05D72564EDC8EB439A95579D04BF65
+                               592AB1024152B9B14D71B18FEB5374A4
+                               C07AA2F58EB2E45F737580241CFB9C0B
+                               842F8CC9230B540FC50A590DEBDC29D8
+            stream[192..255] = 48AB7E018380336AD0CFF37379D9E370
+                               5B0C938600C6713FF4CF5C142F640FF9
+                               72CF147E7C38389DF426FBF560E7DEF8
+                               41B4B1CFE6A4E2DB4A85505C931FFFBF
+            stream[256..319] = E9C6536F67F4B3053B353170CC5B77B3
+                               06A47B759A5FEE5BE45842C01E11519E
+                               5746B056C86D8A6712446949DFFE6935
+                               8E4512E7BBD6E6F544CACA98BDC723E9
+            stream[448..511] = 731EF8977E1307CB5FE80BD4F89025A5
+                               AFEE3E54F7CCEE6556A211097498827F
+                               6219704F96652420BB9EE830DB3DD940
+                               96987BAEC5A43526FCBCD85C9BFDB209
+                  xor-digest = A37E582543E75640DD988C7FB5579D43
+                               9C41669EBCCA5580184743BD54D24CBE
+                               E32F2B1433CDBE51E8208C78FD739CC5
+                               4E2A37E16A7AE4F2193ABC4F04C35D23
+
+Set 5, vector# 27:
+                         key = 00000000000000000000000000000000
+                          IV = 00000010000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 0B295517E5A2E100C262736DAE920F2D
+                               26C40787AFEA87FC34C27D6E0BF98A62
+                               53B695751F9095C8766184EA44042F2D
+                               6DE099A80C75DB1F33F53EFE578A8F0B
+            stream[192..255] = B54C4F2EDF17A1EC22F536586A5BD691
+                               2008DA6642C84AFC8ACD35A7DAE73F79
+                               C835D83F4C0C3B1E510D1BB42013A872
+                               8E4899A8CE134625698CAB31852AA7D2
+            stream[256..319] = BBE2221921E73DC79E795AC0AF9B890F
+                               FE88A14DA29DE45FA38F4C3E94E6BE9D
+                               98238BFB181FE664B4147CDDC125FD06
+                               D11A65F1975A0D781024DE1EF026DFE7
+            stream[448..511] = 83E61FCEEB1367635632B45BC73B8B39
+                               165015E7A6B8D9851390D4CA9DCCB935
+                               F09BDF52883FF37BC77DE94842E39BBE
+                               0BE530FC9D3B4564E11B7EBAC8083818
+                  xor-digest = 55242D44DFDB1A747071F1C825DB5620
+                               EDE1AF37B6D73A22264B14F7D35E4412
+                               4A6242C5AD34B54E98738D6CC90FE355
+                               BB9402DD017B6678FCC0EF27CF5D67C2
+
+Set 5, vector# 36:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000080000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = B89065FE0B458C64FD6EDC6A893C8C81
+                               83578E7D37BE97E6FF82E45110A25960
+                               49A817CDE859B67B56CB80768D6DD275
+                               6EC368FBABC35C8B51C62AC92F913281
+            stream[192..255] = 0E0AB045409ADA1A9540504550404B8B
+                               2C38384E577F2DCAD5316CE7E806A0F1
+                               21D2A3298F71F301340F3C0A9CDD4815
+                               936F16B4EC229E63451980646D45E3AB
+            stream[256..319] = 1DC37BCE039878BA2E5938E4563D2523
+                               7350E41C8EF9262A9EF7D7FED7E22F45
+                               DC3E98EC981D2BCCC1185857C627EE20
+                               C86DFEF500756B241320798764C3C09A
+            stream[448..511] = 9A0082CDB35BB3CB1C74CE337D944D3B
+                               2C833B4F786A92DEA4445A2E5E101384
+                               AEA834F5E01C1B37EF8291D039875A3E
+                               21D613FC71212DE686AE52295B773E42
+                  xor-digest = F94584BB343C6BD6BE3AA1EF799989CD
+                               93F6DDB6A9AC7E2EDFC92460F0905E6E
+                               AA3E81F6E173C7F9FCE8FB5D7B261A58
+                               3FF006AD017A09FBA3B3D084285169A6
+
+Set 5, vector# 45:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000400000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 486343B348F2A1726617D6E93989B000
+                               B41FC9707E2A99C7FE5CE9423DC3004B
+                               67EB02F45B368F87FF2C4CC0C59D1728
+                               9F713E714E049CFD8E5D593255092A7B
+            stream[192..255] = A1A3127E632EF47679F52224E6D5A16A
+                               6E0598271F36F4DAA98B115535E77C71
+                               84170D2DB4B8C5D804790A666D105108
+                               81213A0684DD4AF03DE7707702F4F73A
+            stream[256..319] = C917B1577463E05F34350C4C7F6CBB5B
+                               D63B2D74EAF1500832132CA1A1F289C4
+                               3D93BFDC5E9D91897D2F7E05740F3C95
+                               0AD872A93DAF3850A452410FBD706A92
+            stream[448..511] = 11646E84240BB95D1B14694785E7E119
+                               848855E462DD14176442B8595CF602C2
+                               D1F4A2E09B8D7DE28382D1DA4DB3B1E5
+                               910DAE6ACC02E79FEB07A8E55747046B
+                  xor-digest = 65E9982A725056B8FBC275052EA48C00
+                               69A1BA0939831C4014E81AAF14F66FB0
+                               E01FC0C70A49C4533ACBF304A5309F4B
+                               60D6B310BC66C6684BD5B9C83F994E95
+
+Set 5, vector# 54:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000002000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = ACAB34102EDDB67B8A5D8B135BAC15CB
+                               1CD52AE386364C709C2B9D6BD322D7B8
+                               477577B4958D448A3BEBA473D861E592
+                               CA15371AEA0F500361CBDD865488A7A5
+            stream[192..255] = F25DAF77D7D734E5486A1AAE01794FB3
+                               C17099E01489A5B4213EFAE6D745B798
+                               77939C7A178D1FF09EB2C42A8A3CE51D
+                               59D501B36BF9E4960BF3FC8D50F5A847
+            stream[256..319] = 1C9C6F63998627AE1AA7E8F0B2D73A99
+                               707256CDB12E3AB239EFA72AEC516FBD
+                               6DECC9375EAAC634707A139E59B32B51
+                               5D25ED6951FF4228A11DC87E8DE61385
+            stream[448..511] = 6A997977A25F4E9E0D9AFD8C20B56EE1
+                               C702C301528E332BF8F5E7DBEEE5CC28
+                               C9E12E1A8BD7A2118A0F31F800B574A8
+                               2FC44FE19B20F1D3396432DBB02DACC1
+                  xor-digest = 0B2BA364EE76F0549A10200D129196B8
+                               E2B69667999FADFAD55CA479AE679C56
+                               54A453C43898443B9DF2835AE806C2A5
+                               EF30CB8AC25DBA756A705F66759029FA
+
+Set 5, vector# 63:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000010000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4DD010482D0DB2D09D76872D25F73B26
+                               749FFE70B9674587FC4CEDBA5966D217
+                               489244D0177F676188A1762C430DD8F1
+                               5ED9F7BB67F2E8A79F7633DB7B45CFF3
+            stream[192..255] = 3587F0A7B9F410D45357626BE10B4EAB
+                               FF8798FECA5F91F3AD2543B301B5C301
+                               F84404071C7BC77AC31E423E1AB1E2AC
+                               2CFAA37DBC2A1316D16A5C7BFED1A77B
+            stream[256..319] = BFC632891511228ADBA0211EF390A7F8
+                               08A12AC6BDD7C2E29DF27025EBA1A6EE
+                               00B9718FF2BC003904C1C28878894AE0
+                               E5CE5E9F55CAA522EBEF5747C755CB73
+            stream[448..511] = 513D9FFA86D8AFC20E4870DE0E9B330D
+                               76F02E44A6C4D7C5270B89C6BAC9426B
+                               5A12666244C0CC5A641118B93F72668A
+                               B7C53CD7FAB0940F1B37A85015DC91BE
+                  xor-digest = CACA8BD50E28720128B57B37D45DFB02
+                               206D53785FCE81205AEA085466142DB4
+                               A17F841156916294F3B7CA93CD99CB12
+                               93FF593B5105D2822CA9BC3BAF178935
+
+Set 5, vector# 72:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000080000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4DB6CB1D5BA89BA45BA8E3DFCEFC444B
+                               7D97C73F53EBC50BC46047CD76499CF1
+                               FAB51AA6C8B24118AC4EC8E49192B41A
+                               2812AA1A4325418AA6C69F6143F0A6B9
+            stream[192..255] = 33FB647044F3918513212D3538C31662
+                               1DD9F3A10C0589CB718564CED7ECC391
+                               D9701C7A23AD48E05A79BE9E32F60819
+                               3E57FA8D8EDDF9F43F38BF8BBCBAF52D
+            stream[256..319] = 79F3525A6EE300764DE481C20A40135E
+                               94362F56DBF4C5AFD214F9D4039A0899
+                               F74A7D7C27494B39D1B0145B9F691B5F
+                               F436F2AE8B335EC62CCB0FF506E0240D
+            stream[448..511] = FFE0E6B8D741377FF1A02764FEE3D681
+                               6CD020C6DDA5097989137E9BCFFFD35E
+                               0E6379AD2ED3D9D298C6B98DEA82DE6C
+                               2B66529C860DD4ED56265CA09B16A8A3
+                  xor-digest = BEC66A4FEB220D732F04AE0B98FCDE2C
+                               0B70613BAD57D7590E007E84AC546B09
+                               AF1D5BEB509CFE5523254B5FC8CC2672
+                               215C67477AFF14D0788DB166C5B4B12B
+
+Set 5, vector# 81:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000400000000000
+                               00000000000000000000000000000000
+               stream[0..63] = ED4C49EAEBE78999C0DBC4674757D435
+                               B056A45036DC51B390A6C87B3CE8BCE8
+                               2C7DD348C7775D2402EBE359E7895FEB
+                               B9F44DB5D0F7B40AC207A3CA750EF25A
+            stream[192..255] = 32F897ACB5CE63D1A64781524B1CB4FF
+                               9E595EEF93A3206A0D1B4E6F4ED7501D
+                               2DDFCA31B4FC1A33F589167B070FC003
+                               F67C528B6AB99ED308EC3CEF82B4E2F0
+            stream[256..319] = 57CE29261DAB385309C97955261874B7
+                               676349DEDF7582B7654D1A8DAA570EA5
+                               9745D2167F2AE1ED538F1D0ECE53AA38
+                               379F9AE542EBE229D561E34ACB28FA14
+            stream[448..511] = 667E22A8BE7BB84CA1B1C0848E5F22D7
+                               E98E54A79D5A960C33D07357199AF1AD
+                               53F3F803EA698127C22F75F31C40656F
+                               8C28818775B3D88460CFD29798187537
+                  xor-digest = C68E7F4A7CDB68892794933392C1BA84
+                               5B6B7CF52B8421137EE0220BA67C91E9
+                               81B47F9BFC39FDFF9DD48F3617F2D523
+                               0680B87D18A821A09525FDB79DE6FED2
+
+Set 5, vector# 90:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000002000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 80FC6D794178A189EC423AF926622982
+                               60C44DC5DD5AC91F779D02958366CFE2
+                               C5551DE2A5D635353757AFDDE68DF592
+                               A034D87C871D7D871264BB0F89E99536
+            stream[192..255] = 0BEF31DBC3F3DBCC5B3D28BE296384D5
+                               D33DD0AD9A80D4AB8F58274B4397A658
+                               94F67376AD8DCEC19BC2C74A835D9F70
+                               1F4C60DC256DBA4E83B21D36B66F5DC8
+            stream[256..319] = 625DDFD8D922D848380D45D6D7E730BB
+                               049666B3900E4305218BB7089D059FD5
+                               825F9EAA3AC047A006F1353C37AFD11E
+                               0143DD68CBE9543B959E26ECB4C649A1
+            stream[448..511] = 636E6EB97E3127EB703D5170D2C8FAF8
+                               63E8C333F5EFEFCF9063E3D770FF9E0F
+                               2B37396CEC935239797FE430DA4CFFB2
+                               9B19D833687318DF01750DD2F3D942B5
+                  xor-digest = 0865679CB53BC2845A0B71AB820F61AA
+                               9B99E100AC7F0358D5B610C09EC52C7F
+                               8C7C5D973CB85B18F8990F3BDBFBDCBD
+                               13071BB3AB3F329E75A44E80320BF86E
+
+Set 5, vector# 99:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000010000000
+                               00000000000000000000000000000000
+               stream[0..63] = FC2DEE44B15BD914C17DADE6645A0250
+                               2F40B39C0C6AA26C0250D328112AC67A
+                               0C55D48700EFE67EFBCED927B62427C1
+                               41DB8089774E2DE23C5FDDFD66D39BC3
+            stream[192..255] = B6A4D34FC81937580BFC32E04C8E2B20
+                               309AF3E2152B98BD748A344D4537788D
+                               35B16DD2C01444CAAAB8684916705C88
+                               FE75C53D75713FFFFA2693E91395F919
+            stream[256..319] = 9E619BB0045C58C2D303F79E659CF5E2
+                               011D619E0CB10CFDD53AEE6812DD780E
+                               36407CFE9BFC1C73C27CBBD491BB6A7E
+                               8918023EFD6E2227C0C840F1DFA5924A
+            stream[448..511] = 2A320747019AE86A59D5422B634448E0
+                               B43C41457428AC7A4E5D0C9D7327B44B
+                               BBB6F64CC2423299C009E5B24DDF10C9
+                               F87F2A525ACF803C50837EF6C2FF3D34
+                  xor-digest = 3737C19DCC04C7C72EC9280D53C17E64
+                               E9F4B1E47980711DC64FE6D3E7DD05E0
+                               DEFF339F38868B1F7CFFAD4298127949
+                               11EAD4D34047B22B07C397A37F6BD2A0
+
+Set 5, vector#108:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000080000
+                               00000000000000000000000000000000
+               stream[0..63] = 84F71EA20D46B3802A787C1322DE6A79
+                               34587F447AE7FE277362497E4FDB69CE
+                               129EC4D8D80ABD0C15026EED3DFE2B6F
+                               C48C5DF09CBE035E348A22F8A2AB7DAA
+            stream[192..255] = 6444791C6DE062EB9A494AEB910A458A
+                               DE3D834BD6F87F26A9D6F99FD970C820
+                               ED9FE0DF88A924F97945B0EB10E5D464
+                               559AA278DAF6A942651E06C66D33F7A0
+            stream[256..319] = 1878644E35B3BC562F82647D45C84317
+                               769BACDB95DCEACA456727616BC90FF5
+                               E78FEE1EFB86A714CFCDE79AA9E66FAC
+                               D600B0FC5C471569BBEB5692E7D9616D
+            stream[448..511] = 54BD56C4F0F3A0CB89A678F2912E5B21
+                               C2B225030E82A90470EB6040F50A818D
+                               C91F65BFFCEA3F9041BF110A762DE3D4
+                               B41A8D1E18CAC776063B2DC93BC2D02E
+                  xor-digest = 52E18382B88883C5648E067675468200
+                               2AA9AC5C18A856E89175C449A6033501
+                               87FA4C17A4D36269340F0877385A35AC
+                               4B7FEF6E1463D34BCDF3597618FAF352
+
+Set 5, vector#117:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000400
+                               00000000000000000000000000000000
+               stream[0..63] = 3F40E9A3C872ED15A6AA296F716E095B
+                               F39153C7C6F4ECE6F550AD35582083A1
+                               CA0DC3CD817AE3946E43AA9C8700420F
+                               F0DFC21B34F4E5E40B3EA14299EF468D
+            stream[192..255] = 853C4A895DCBE411B9B2E340B0AB55AC
+                               8EEEC42885768110ED7E1CCADC10121D
+                               8DE12AFD0DCA4507A8A7A2650FF68C6B
+                               5DB1DD670C8C68365E846934D16A46CC
+            stream[256..319] = 565AEFAC0325093EF87FDC51413BD5E8
+                               56AB6C90FCE7D3C6EEB7E58F22AF63D6
+                               73BCF3840D611A5E1102E9A4108CB902
+                               5A1D837510A971536231CA247965379B
+            stream[448..511] = 887287B62116FE2A28957ECC71DE5BA9
+                               CBBC16DBFA4EC141EB617F9314FCD238
+                               91C4237FA35871C0C795E2F3A4197DB4
+                               F81BA4A29759BEB5FA2277CBB9169734
+                  xor-digest = 78E564BE9E7102E2CB009D7A540395C6
+                               188C8499B7E96C0AD709C3BA2C341741
+                               6EED55AB00AE5719F25CFA06F1488E83
+                               798F18BFD755B9061AFB4EA5D864FC24
+
+Set 5, vector#126:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000002
+                               00000000000000000000000000000000
+               stream[0..63] = F4C281D9C88A7FD6B2CBA9EB0366C594
+                               59327932DBEF8118A7A680D0F0AA41A3
+                               735FE0874F047D2B071B5B9E755A7B6A
+                               9426353B923A5913C647A88B642B2C00
+            stream[192..255] = C7DAC2AE7631D11EB21EF15FDCD3EEDE
+                               7DC98A7060613A643EE8A944EEB6C7D1
+                               EDE08538E1BA6092ACDE0C648D29AF5C
+                               309CFCBC4F40A713FA58D93C954961AE
+            stream[256..319] = D1647D6453798B7E15A49199134384B5
+                               C9BDEBF7F859F6460C2666F297410070
+                               E68307CA78790EF01D160D94B69729D6
+                               90A4FE477A27AFF8B254875C98116485
+            stream[448..511] = C6D3DCBD0E9D4746B142C819867E0A14
+                               8B81FEE3D1007E907F8E9D597EAD63F7
+                               A87E6F224C67CF8162C4E92FC1BE44EA
+                               FE3715B3C1C432CC660CCF1536A20F46
+                  xor-digest = 59FDF05B6D16079B7E18F6A8CE0C58FF
+                               AD7C985C01A12C07D1ECEA740A92F761
+                               FDAC3F96357498B5F5FBA91DE6502A86
+                               1332A1B3E85C5E72444A2168C25D6FEB
+
+Set 5, vector#135:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               01000000000000000000000000000000
+               stream[0..63] = 494BAFEFE4FBF2C406F55FFB436105BA
+                               09211B71DA446A0F5436E6DBF42F8E1C
+                               C805E797C9987C14997083E9004473E1
+                               B2B3729DE9B483361CD38CC78C982533
+            stream[192..255] = 3C04C6633F7D8B714E8549AEA1851035
+                               A520EB6422F42B2C840C74CF51A13FA2
+                               9C1875212E8DC07774D6911415F1C305
+                               9826A05DA9F09942273CDB592F7E3A6E
+            stream[256..319] = 1FF6BEFD79A7E5BA0DF64948BA0ECE7D
+                               ABFB3883BF8A95D3E76DEA30550F5C3A
+                               2B67FE2AB78DF091E758E498418EF514
+                               089283275588A41AD20D53E6394635A5
+            stream[448..511] = A4D10D3B6AFDF415D49FB6ADA1245812
+                               1DA1365ECEBDB6C2508F1EB92E91E8EF
+                               90892E6FCC9E70AB9A2EC4D49A11C197
+                               68E6B4C154A4D65C55AFD38B2BE3F4DE
+                  xor-digest = 91D4EA4C6ECE28536C415A6AF46DC432
+                               3B6DC2DC98C3A3FE2BFE53C8FF556C16
+                               0197D655357512A808415BF757AB3A84
+                               6BE7865622D32B7DE3867B3B096408DB
+
+Set 5, vector#144:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00008000000000000000000000000000
+               stream[0..63] = 521913EA655235FA0E713B0DA3ECB98F
+                               7AB817E70827D29E75E3BF2729EC2AAB
+                               8747B8FE0FC9489B6E0EFF45EF985980
+                               CC0189D9D0F2EF34E809D992E7695D9E
+            stream[192..255] = D265AAD80EC96DFF08859F93B236136A
+                               BE146981E919C0554D64FBB7D03DC9AC
+                               9021F2A1B39866567D8BA1DBE2C3CD21
+                               E5C4C94085F7083F4C640E918C4004F1
+            stream[256..319] = 7DCD3CF623332365E6CF2D92FD147BE4
+                               1E532F51F939C921DD4492E026993E56
+                               843ECBF0925CC52D56084E7F2B538653
+                               2020DEE6FE7E85D4A89AEEBD5F3EAAAB
+            stream[448..511] = 00E20611C7ADFC3BD9E59B9E6D7ADB03
+                               F87FAAB01D7771B89299BDC59E1E2EAD
+                               FC9FDE416B62FEF07AB7A816AF261E77
+                               FCF79DBEB09323D44B5956CD93AAA990
+                  xor-digest = 0578B3E20EBF98D89E2DE82A6EA8E34B
+                               424E526CF419713F0AA662B852E58BB6
+                               7ED570D75534E1F23F85F160690A464F
+                               122CCBFA5CD1DCC0969F2E57D65D64F8
+
+Set 5, vector#153:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000040000000000000000000000000
+               stream[0..63] = 2617095641B825094DE44205319CA853
+                               418588D5B6BFC05A2713CF898DC42B3D
+                               6ABDDF4C287235438A48BDDA49E5ECF7
+                               EFA235A23BF667289612893708704F08
+            stream[192..255] = 04F668517ADC1AF6E31DE6B7007ABAC3
+                               59A2DD6DD61755C6CA7053E05FBBA2AC
+                               D9AF682EFC71391EDA4A5872B53D7CFB
+                               BD35ACB719169283EFD9FF9E172269C4
+            stream[256..319] = BCBA3F15D83B9AD41317AB9EF7DFDF0F
+                               FF05CDB058AB08D7BBD720723E969CAD
+                               79F16D26DF0222CFF4249B839EB9F9F1
+                               422EDAFB8EC285F27E347B7B4C9B2C23
+            stream[448..511] = F15F17F38917DFCA9141314047595C17
+                               047F91E4859D849E9A6339F640E3633B
+                               6A1B62D089B24062BA5987C3FAAB6633
+                               99698CDE6FE7A461F127AF67B2C5CFBA
+                  xor-digest = 68B2369B45F059964A1FD3822DAF61B7
+                               82A9FBA7EB563F83DEC4D058CA5D8931
+                               EC74AF4043FEA803B696791C8E0A675B
+                               DD8982AEA862BB76847E1DE12F2A5E86
+
+Set 5, vector#162:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000200000000000000000000000
+               stream[0..63] = B090CC267B29A95ADFAF6BE3E147D647
+                               21ECACBF6B7D0C4061D17FB7DE0A6662
+                               6D6F9FC167FB3FFF237C240AA03FAD55
+                               13B6DA848F22796DB501A8FB89F2B85D
+            stream[192..255] = 1CB95ED9AADFA0E1FFE5704BE69CBA3C
+                               9593746AE87F36A786E5EBE18A1D3B25
+                               F4785EEF4DB439472035BF053687C5F1
+                               0B60EF55A76DD1994FBB482BBD250755
+            stream[256..319] = 826BE3D679C872536D55C3F0E49C2624
+                               D41726A4525A50CF91EB71E7CEC5AC47
+                               F3834358E2296CF0D04B8D8CE8A701B6
+                               6AFBBB8776DB2B75F1CFA01231B365FA
+            stream[448..511] = 244DB28A98619907AFFDCCAF303A3795
+                               3B6D21EE6D22780C4D3C939C084E4181
+                               1FFCD8F2DA2E6A2243BD0B5428FB86C1
+                               F0EA2E8C8B6950ED961F4FA8CDFDCD17
+                  xor-digest = AAAFCEB42F2EF40C4B5462307085434E
+                               E4399F87B4AE5CA828A952A851F47913
+                               A51430A8BB9B3CD0A4B2F12E297F51E8
+                               FE0B1A6FE0F21177EAD9284087D3706A
+
+Set 5, vector#171:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000001000000000000000000000
+               stream[0..63] = 0F4309F63F237DBB51567573126F09E8
+                               E49990F26E541EF888B9F2922FE9D280
+                               C8FF4874C0D4FA3F41034B82E2E026C4
+                               594A79C2B689BC502C41244DC1AD472D
+            stream[192..255] = 95DCF9685E429DEC2833E1B5E78823BB
+                               ACD9332D668C4B342B89A290E1CA6127
+                               B0E5125E44445A1156A70B27966C3E0B
+                               4E0BCBDD9F4561998A5CBCFAA05C7459
+            stream[256..319] = 0886E9887182156005548CA1A08B57C0
+                               E9FA76C2A694E1CEE22E9B715E99B115
+                               9AE064DE644FD580E8356164A45EA1C4
+                               3DD85E16158B5130AA103267C8118105
+            stream[448..511] = F8AF6F9992781BB09808B7AF404F6546
+                               6FA697C2A1BC9BF64F8D6B6D8CA0B856
+                               6B64E6BF0500F6D80113D9457855FDCE
+                               1791C7436F5FF41ADA87562C175942D6
+                  xor-digest = 8D32FFAA409C8CCDA6892C388D5D654B
+                               4AD50ED00BA649737BA8F350811A2AE5
+                               5C89463C7D63F1F1F16C4007826C2CF0
+                               E4BD9453A60D88BE86F60BADC3E71E98
+
+Set 5, vector#180:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000008000000000000000000
+               stream[0..63] = EBABC8B756971D46C1A5E86CC7AEB329
+                               4DEDACFC795F2AE02CCAF68B933DEF4A
+                               19E96BA64DF14EB6FE67CA48861B49BC
+                               16052E33C8B47556DFBD96037B7DE5F2
+            stream[192..255] = 0438A8CF718F4C52E33DA087FFEC01E0
+                               459D26757D5DF55D5D7BC9BA88F57EC0
+                               4B84D854374F95317CBDDEE928A2CCAB
+                               E4BA1BBBF47776B29890DF00D864FBD2
+            stream[256..319] = BC4A80F9CACFE63D2E54044ACFF39F97
+                               2C69015058AD3F81CBBA28FB0987FFCF
+                               9CD1F6AE4F0602BAE2B828D3FA162936
+                               23CF3AC2950BD651F7E467DF8B454BD6
+            stream[448..511] = EDC95FB80C9FED4A73D6EE9B2CD74BB7
+                               E6DEB9E7868D40FC49BD1C52838457F0
+                               88DCB29C2107066D55A80908EFD1392A
+                               B4F2F13C0A79F67E58C91A89A5C88991
+                  xor-digest = BECD7FD2014BB9A25701E69F9788FC84
+                               1AA9DA56CDE1CD93DF45D28F29D32E22
+                               F488B0C2D9FE95B267CBFD35EDB2F6E3
+                               05DFA5A2CF09D7E2D13348BC0C9405E2
+
+Set 5, vector#189:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000040000000000000000
+               stream[0..63] = F28A15A90386237127A5682EB09E0E58
+                               30709455034A7189AC9710DBB50D5012
+                               9EB4E0E9036D4504054B281F3FE9F45F
+                               C80116B8FFC0B42F9A636A399B7A8BD1
+            stream[192..255] = 1219EF9BDC250E88BD0A62DDCF9AA1DB
+                               B62E19FBA748DFE1035C6A5B3B94954E
+                               1370487A455916F7DAB451F79C5E1298
+                               F549CE005A1321E6B136B59BAD9EBCD5
+            stream[256..319] = EBBE81DAE5637C4C7EE6FF9251D5407E
+                               DF7E8EAE384D1E588CAD39AD9F763004
+                               9A8E028120B5065B658EF3E2B357E52F
+                               F18891819EEE3EE021BD1AF08A4B1F53
+            stream[448..511] = 50086FCFCF5EFFEDC4A52B0212B7321A
+                               8664F2976493868F13D7CFDFB7583E99
+                               EBA70778A83CB88850D45B300F7F6A80
+                               E721860560B2FA642B2E77C7F7AB0662
+                  xor-digest = 336516670616300FD5FB014C1076B53F
+                               6637AD0EFB453615924396785CA4D284
+                               B03F526FC2179FF3BFB0A1A2ACFFD87E
+                               EDC4C8360DFFC132CE6A502EB173A0D4
+
+Set 5, vector#198:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000200000000000000
+               stream[0..63] = 93261A7231FD030CEAA974BBF8F3A721
+                               33334C5F3B25D5831B203C353A566D80
+                               DA578081A047E28DDF8E4BD5B68BE4A7
+                               FDE4BB3A4875BA84553AE120ED77C9CF
+            stream[192..255] = DEC4B603E6A6F911B68E5C1265FA2004
+                               71B296A647D20C13E42202C1A3AAE880
+                               305F969BB88002C8FC00CC5DBE40AA06
+                               4AF85646AA8C7F7191FE26FAA2918A95
+            stream[256..319] = 849431145F27957D53CD355501363E4C
+                               5F191DA666B77364E5866CAA16A9DEF0
+                               DDB9BC266EF41DB0C2A7642B9E8DD27D
+                               60DEA6E69052D4BDE9FC83B2578C72E7
+            stream[448..511] = 5556EF9874E3150FC539C9BD3BAFD308
+                               8FB347D5E38DB318A72AE0C6B6FB4163
+                               082545A9AD8872AC383A78230729D083
+                               31BFC3F2C80DA20617435FFDF2529A7D
+                  xor-digest = BA9CA5F3C27246F931824A9A425F2390
+                               E183188FEDE5BE3591053ADCC933E1F3
+                               DDF5627A94F80F8922F53E951490E96B
+                               F51491ED2D6DA26F3BF69CC41B8C0C98
+
+Set 5, vector#207:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000001000000000000
+               stream[0..63] = C449AF4CD437641A3B40D0E0E7B5696D
+                               CE973B3B217E02DC20B2F5573FDDF78F
+                               E6E55D75CFAB8EE04C8962376D22A843
+                               A80BB79C8B8D8B500C4B6DA27748C398
+            stream[192..255] = D5C92B62B0818165096551DF2B007F66
+                               2DF953742EF0BBE97982FF9D3EE83E1B
+                               87EC9D710CF1700262B1CAA9C68A897A
+                               8AB4A162DB0443A43962EECFE5B4C0DF
+            stream[256..319] = 3B8CC7E847669AC6858B7BB716206386
+                               40D8C2DD259EE4970A5F254077101271
+                               DF745AD7F57712065E2D03B9D7220591
+                               5C8C033A4F9146EE561B4179DB465989
+            stream[448..511] = BA4ECB7D74CEE56CF1D5AB636BBD6421
+                               C30A51DABDCED17C8D50F5293424AFCE
+                               33AF71095CAAD3913A8A3A12286A8E91
+                               89DAFCC1E2E744FBF4B526E910B5F2CF
+                  xor-digest = FAD57A608E04CD71B176BBFADED7B229
+                               D855A8025E963B55FB83EC7311427779
+                               490F25D34C6385FE1C036FF0807E136F
+                               40C10588678E2414163AF1819EF7D3C9
+
+Set 5, vector#216:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000008000000000
+               stream[0..63] = 989F302DF6BF8C63F9EB69D2625115B1
+                               2CCDA42A2D33BC6F21BD55E0594DBAAD
+                               9A294DDFD6710E36000C27FEA7E03440
+                               C8A6E728716D0DF14E825B798A6C420C
+            stream[192..255] = 3F3140320AA02367512E7C1789F5C03D
+                               83CC634354237E78E16B1A64DBDFA6EF
+                               0697B28BDFFAEC311C6E2089BCF64203
+                               A2EC7BF3CA922080380241A47A673634
+            stream[256..319] = 6049048A5307D55D6DB387A6149C7B23
+                               0AE33195D53E0026103EB44489BB86C6
+                               BAEC7A0D920CAE25B1E7B9F07C07C4AF
+                               6485FF281C7B7FE1D61E660AE55C20EA
+            stream[448..511] = A6DCBEC85525FA19FA6066470B4CD83F
+                               17D42DB3353B327BF3DD6E7D047CD752
+                               71E79CCBD46E757F3654C2506C2B593A
+                               BC93B8985C491017A8E616D69E8974FD
+                  xor-digest = 55BE97FD8317A47742F8F3BB762160AA
+                               7FDFBA371864823D93EF6C029D457AC1
+                               2D679CB424DA9EAF8E4FE28271C66F06
+                               1E91D8F2EF41733AC1084F54330C9786
+
+Set 5, vector#225:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000040000000
+               stream[0..63] = B8989CF76BB1AE894699604320C14706
+                               E20C8BD86C016B5E2EF705AEC54C6023
+                               2A9AA961C10914A8D910D517059A93F9
+                               78C537767A057E0E11DBB5C9BBC4EFA9
+            stream[192..255] = 83FC232D21D0DB82747D9EDFEDFB58E2
+                               BB37362FA2B4E1AA0C9A58AE521EFC86
+                               C512831CC6D2E85FBD96FD3B60D1D153
+                               E83DDC6C5755899CF96FDF69E3732E4E
+            stream[256..319] = 201DDE5D82B754341A3452BF7DDDBF6F
+                               167B2A087900EF40E4268A80217D7310
+                               F1E9E25C707A1EC05219E3CCFEC0F6F5
+                               28CD98534F6C579A1ACD3171D131D87B
+            stream[448..511] = C2F68B5F03B0045FEE0FC92DA08F8545
+                               762F73E553D2F539C64B88D4FAC9B011
+                               DE0504D66007A115E428F627A667FA2E
+                               296F222734FA0F905548058897DEA990
+                  xor-digest = 7DFA65F57FD58891C5576B3CC7002513
+                               C1A983E9D31317B681604DA09F176AAC
+                               4FD78CE84EB9427BE8D6A63058582F16
+                               148D55B3C2544CF4DB9306699CA74D80
+
+Set 5, vector#234:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000200000
+               stream[0..63] = 307B13F3D3EEEA4C8FAF34416689F354
+                               AD26336D6B33DFC5AA004420D2DEAA69
+                               F69E531EB6D672AD62B2A6A136046373
+                               F70272E84E14CABA9AEA3102863A0B10
+            stream[192..255] = 8E4DA19FEDAD4C842917ECD5E7256097
+                               C2F524324D8A974D4185D8B11B611C72
+                               6C39DDB5E58180971DA181D36A289CBC
+                               1937E8F020645EC8D0363A58C6147F38
+            stream[256..319] = 012A99871D6C4CB7328C1374F37D0BE3
+                               DCC2232F6484A22C8F330D77316A1756
+                               71DF7CB32773F25D772BFE9DED5981B2
+                               0C3F0DDB2879AF61E7549F03AE26D233
+            stream[448..511] = 47C6CA462D35580BC0C78C6427FB96F3
+                               BB762662F5B52FB3938CCCEAC35884C1
+                               54F5BBF513970FC08F51C91059A757B9
+                               A8B6F1EFE467FAADA8D4DF68C6AC1942
+                  xor-digest = 6409F8C255BAE6167686F5F9C7EB2349
+                               0FC7BA4DCBC80006B57A5F56CA9F907F
+                               849C2A0FB0D74CAAFC0E2D4367E2912E
+                               BA6487D8A48DA60E48277A20E326266A
+
+Set 5, vector#243:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000001000
+               stream[0..63] = 543BAEFA799FA0CF5295B92EF3FDC07D
+                               69B87C1B5FF0A9F25B32F8FCC473D04D
+                               54B6E467D6183F25E3664A330889889F
+                               A530E354B6E53EBC78354100637A62C3
+            stream[192..255] = E15997D1E7C0FA38333DEE2EE2477A4F
+                               AD32F0810E8D3D65EAFB110C2B8D0948
+                               59DC45C4AA38B8050A87C23782E1A26C
+                               C193985BB0C3E754A528BEAAE1508D76
+            stream[256..319] = A94F1BD38219097B70EC0700A64B0ADC
+                               7BA8883B5C2C3BBABD0497E80D53121A
+                               2DC5A5C6A77913330EF5469871BABF86
+                               0A09F1474D893ADC28B473EE508F473F
+            stream[448..511] = A43AC01FC186AB42241ED3729E7EEA39
+                               F0823D124E8CB696E2F4B047A6B71164
+                               5B803623CD0371C4975217B3CBD7D9B2
+                               FD89D3B6BD23FD11FEC0B03B9CC22AC0
+                  xor-digest = 792A5EDB6E7FDBE99B7EC2119665C2F2
+                               34038F561BB1923F3BF493AE35CE2006
+                               55B8EE47490B53EBB481AB7C6B82FACB
+                               233AD86D74385FA108C94666CD34C164
+
+Set 5, vector#252:
+                         key = 00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000008
+               stream[0..63] = CB4377099B2D7CD6A982A1B1A53E05F2
+                               E097164EDCB381468C21D8F0615A654A
+                               45A4D09B7C0218A19496EA71CEEEAE5A
+                               886307DB0026C96049B60E5154F99AA4
+            stream[192..255] = 25FCE0B7E28D5D0D1654D912DBB21AE0
+                               288CCC71396CA5AA36AC44AB08EC72A1
+                               01E5B189535C1987B79DE4C4E32DB7FA
+                               48ACBC8F854868FC287E03D54752230C
+            stream[256..319] = D3B02A39A4E467C44C109E1E25593278
+                               2E9B3CCB02D6F107C9263A24E113FAEF
+                               847A9064E1AD1EC8881EFEB239CAD6C4
+                               E90ACEC36A7E87E002F35D477CD63F2B
+            stream[448..511] = 7D4282D7E11439C04ACFF087708DA22D
+                               236F1A08A6343704DA4D24EA3582253A
+                               35419183A915B571DDE80C1DEE2B8A13
+                               76EE973234FFF6A0DD91D31037F51C72
+                  xor-digest = D52720D8DF114235D99E5292E14DE96F
+                               9D8478E016CD40EBA25C4B9D8E11713E
+                               FE9AC151E1F39377FCC07D06E9BF6931
+                               6EFD7E27F87E9F76DCBF7831CC3FA98B
+
+Test vectors -- set 6
+=====================
+
+Set 6, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                          IV = 0D74DB42A91077DE45AC137AE148AF16
+                               7DE44BB21980E74EB51C83EA51B81F86
+               stream[0..63] = 914AEBA9E4BE90FD07AA58B6E2536B59
+                               0DD63BA810A2B96BAD5DAC1818722BEC
+                               61725C75B9E6194F57D3D2BBFE795E73
+                               90405CA97249262093234239E35ED9E4
+        stream[65472..65535] = 346C1A7D71DBB8FB69EA78F07D60A9A7
+                               20D0ED544149AF102C12678D4AE0C5DF
+                               E3521B7344F91977799085008EA00432
+                               772C0B4ABEC1DB2C47608F9A29CC76EA
+        stream[65536..65599] = 6F3B93E808687BE8E37A635E15B13052
+                               60ED65488A59125D84726219AEE62087
+                               47C6672C585759BA60BFD7F55AB975D4
+                               B61596A506F8763F715F27A36082DB51
+      stream[131008..131071] = C64CAD1578C28BF19F11B14F3D33C681
+                               A85D28A4B2D547652A7179C31127C306
+                               DC04BE79BC1DA0279C69F9418311E57C
+                               0F13D9E993008796EA10607A63BDC772
+                  xor-digest = A67B88BA16F74643B49BB149E6E214F4
+                               624BDC9559CEE75DDCDA01CD343FEB4F
+                               A8F6D62492037A0939B7F745FED8C3F4
+                               93102B006D3AF8167E38D1A216B0AE0C
+
+Set 6, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                          IV = 167DE44BB21980E74EB51C83EA51B81F
+                               86ED54BB2289F057BE258CF35AC1288F
+               stream[0..63] = 0B739B0FB68C82FE4120545C8930AB02
+                               F7C1F08E6C5A1EF913F58148283C873C
+                               346703A489B00BACD14E9CF30D8EA149
+                               14937EEA9074DE932F4847E69D793D3F
+        stream[65472..65535] = ABA9A96B26DC34C1684B1B9E565D7292
+                               0B3467672185FC0C000710265DAD5A9F
+                               FDC7D5D42E412170046AB05591C19998
+                               F8AA47E5C634E5719B74936526EF6960
+        stream[65536..65599] = 286FA01C6BA9498FA55E3AB7B7481D21
+                               05D82DBD03CCD59760690DC89EFF5B3F
+                               9D3FE06CD3E8D9C2C77EA2581AA5790A
+                               6D1457D534A1090799EA0B1B3BAB059D
+      stream[131008..131071] = 8FEA40A11790CFB0BA2F199B01F68FB9
+                               33874E294F7A08F319B87D0990317915
+                               C12CE3C47A19001FDAEF72DFD5AE2174
+                               72FA2DC47D492393792C407716CD965E
+                  xor-digest = 7362D014CAB8247E7F5A7476238D5C0E
+                               931B2F9D79D03E773994BBDB93B4447A
+                               81770D6D1EFABAFFB756ACA945D929C7
+                               5CFE214A53F2FE7EF78D76B2FDDC2267
+
+Set 6, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                          IV = 1F86ED54BB2289F057BE258CF35AC128
+                               8FF65DC42B92F960C72E95FC63CA3198
+               stream[0..63] = E6A0C18EE34238191E39B2DD0F0066DD
+                               D7C0033F82C388043CF13C72CCFB9DBB
+                               553D782AAFC983F419649CC9B29510C6
+                               03302235278AC3F1CE5405829F7E63B5
+        stream[65472..65535] = 16B4B4A51FDD9B41DCB8A1CBDFBE8D5E
+                               5E2F60F7ACFE5761826E68F7C4DDACC6
+                               7E0AD9A0B431F089FFE1E5780A66945D
+                               9E3C32136992ED78B8D8F9E7C38DA359
+        stream[65536..65599] = A450FCA398BC87C0079DA4D71E1BF0D5
+                               490FDAC094BF45C7F0FE0BF28017DD19
+                               BD3894BC0E54DEC98F57BBBE71EE25D4
+                               D96A2E1A003CADC37775CA370DA2898E
+      stream[131008..131071] = 17D7D66A32B7A47676FE3BCB180CBF52
+                               C4585015CD9D994C56E6DFA854D9DA76
+                               9AB45C8CFE938901BAEE5CFCE73D8604
+                               A0773736C3336C40355472B6F9208FAB
+                  xor-digest = 9727B576E6090D39333BCC2B993D0F16
+                               CD0508D7273BE022E907C99E93A17FA7
+                               23AB9CDDA9A4D310C8E5A9BAD26767AA
+                               8FF3C514AD1852DC6749F10FE663C9EF
+
+Set 6, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                          IV = 288FF65DC42B92F960C72E95FC63CA31
+                               98FF66CD349B0269D0379E056CD33AA1
+               stream[0..63] = 857EB9871D1CB2623103A4D04443CEF6
+                               5AED61EAF8264866A7B3276F6B5DA8B8
+                               D2E7C63E3213CEA9BD3333E4687C6962
+                               5D2B980D0E28EA54492148AA16EE6FF4
+        stream[65472..65535] = D498F0830A147DF5D15C6DEDC76E0687
+                               20D8A1A57F27DF19895CAFDC92846955
+                               CA942F39F64524E5F70B4B1D3F7B76C9
+                               55877A81311CFBE09AA0E9EABF0403A5
+        stream[65536..65599] = C850035DB7C0750E015EA60DC1EFD84A
+                               79C830EFD07675C0664039C90EBA1442
+                               5C523DCC60A47E60716F7F302BFD4BF0
+                               2A2DBB2CE29DCA01A1AC7B1EE9815727
+      stream[131008..131071] = 6D580F0D0C722DA5F901321F57C3F438
+                               109F2D2F46ED5572298B40F28C204252
+                               6429F5436DC67F15C0427C8EE7FBF49A
+                               8B5674674E1840E0E664E73C429B36F5
+                  xor-digest = 65367188C7BD2B0064CCED9E64FB7531
+                               EFE91EE531F4203B9C367A79B015B4B1
+                               F79349D68DD316899F5B39A867765747
+                               49461826B9511C99C0BB569F7455601C
+
+
+
+End of test vectors
diff --git a/crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_128IV.txt b/crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_128IV.txt
new file mode 100644
index 000000000..46a86d7dd
--- /dev/null
+++ b/crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_128IV.txt
@@ -0,0 +1,2783 @@
+********************************************************************************
+*                          ECRYPT Stream Cipher Project                        *
+********************************************************************************
+
+Primitive Name: HC-256
+======================
+Profile: S3___
+Key size: 256 bits
+IV size: 128 bits
+
+Test vectors -- set 1
+=====================
+
+(stream is generated by encrypting 512 zero bytes)
+
+Set 1, vector#  0:
+                         key = 80000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 240146C5EA6C72A8DFC93E54E8811C32
+                               A85E0BF7291BDDC0DBEAE086D051D5B0
+                               5CC9DD5C311ED2F7E8484CC477C68BC8
+                               C5D3F3450553F5327253768E958C0C55
+            stream[192..255] = 26C5976C37B009E57BE86064A99E8F59
+                               F9536410FAA9BF625D8DD2ABC9AABF09
+                               DF6B5EFC76CC6200F9E321E327AB0703
+                               2C78B351C5F7EEEFF2C6E374521CFF6E
+            stream[256..319] = 2F72E0E6E710D807D5120AD686DAADC3
+                               A5C1544557A4BA6B1D61F90FECD55328
+                               3C8F91B801DC435C5FFB1F8B33A23644
+                               8E21217C367108893D13AD41EA8F20F5
+            stream[448..511] = 68320BFC459C78596162EF5FEE2CF46C
+                               79EAFC681AE91F875672350C59D33D6F
+                               9E0CEEFE42EA9A0485E3E41C241CDE84
+                               9849DEC99219729D91270358B2F83F38
+                  xor-digest = 19E8083DE3499286788AE3A6DFE90AC7
+                               B77084682ED86D8039A67663CDC9ACCE
+                               D297F22C10FF7E4FAD773337B008A32B
+                               A7176F733045DE44782F04C1DDF28776
+
+Set 1, vector#  9:
+                         key = 00400000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 4B1E2D728E06D7356F151D10DE9CBFB3
+                               C66A1E5B5ECD926E33F56B14CEDBFCC5
+                               40CD6D1089DD8E5CF008E4AAA3C4C89D
+                               11B136FB5656B5D4818D1BD1E562BB38
+            stream[192..255] = D5E6B5482535DB7F9352933242C164D7
+                               6528DF7AA013A4FC2F2B8C2D7DC0202F
+                               85774C16FAF22D5071A875B6A671D4B1
+                               A8C396AA5D2F14AFF9C4CD6C1DB89175
+            stream[256..319] = 3D0FCC3C90DE0328FD0C752458996FF2
+                               DF822E496CA42A7D7EBF3D958676A41D
+                               83A16EF3150B8C4C8F1763560B314287
+                               54B4A2EA5C4F74783BF8809F3A624664
+            stream[448..511] = 2D68526D25483C2A1F0B6F7101507804
+                               C9619E267F1FFF28C934D19201351465
+                               31D13592BC9F1739A0B090718052E4A0
+                               CAE9E0FA4555F2FAD27EC8AA2F14CC60
+                  xor-digest = D3C3131E402BCBA54DCE0AD35C5FD241
+                               3ED7056BF67B5163CBE6C9EAA9D27535
+                               7D2BFB7B2843DFE92709F047675CE06F
+                               5201611BCB8FF15C76D0E328D46345E4
+
+Set 1, vector# 18:
+                         key = 00002000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 4A0CCA5AD387D49DF33FE8BE69FAD669
+                               270E3E6CF724F53FC3E509A2CEF1D174
+                               A67C2EF4B9D2C9B8A8177BBFBAA2C45F
+                               BDD25CBECBDB59A402FE3C4835854CAF
+            stream[192..255] = CA0F19D9996E6D3518D28D8169968ED2
+                               B03D118D4BC1C5E1847BA6EFE6A32D6A
+                               32BAF71A4C27B0BBC9B9BA03FE044D7A
+                               C9785A69E3B0E5B3B26AABE3AB093965
+            stream[256..319] = 6FD1A9F1EA228C39625FC0CBB2D4BF8F
+                               2C0EF1F37D4FAC56D8024D1B4F2AF33B
+                               8AB0D452F5155ADD5F0FEEED8104AD55
+                               9946D2E274ADE44170F5113630200B57
+            stream[448..511] = 5DA1476A1CBADD0797DD7EB9C0E563B9
+                               EEA2C55860C42C2C0A6B38B9344BA0C2
+                               345C7143D9A7E5BCDF9FA2606098DEA2
+                               142632258F844AA1A77CC9950D5ABD7F
+                  xor-digest = 0CCEB42D4045C09C45CD6C27B88606BA
+                               ECF7F6B30F50004AB2ACDAF89849519F
+                               61482EC4AAA2CF58C4206A228FA23AFE
+                               DD3BD50BC9C04744940A238966C2926B
+
+Set 1, vector# 27:
+                         key = 00000010000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 77CB199A639DE60664225AD1DB954B5F
+                               70DC01305D2D4073BE772B0863175EBB
+                               64FAB80EF324DBC85A9EF827EBAC7A5F
+                               CB088619C246CECE6F92B89A2122B6AB
+            stream[192..255] = 84C1E9B365F1CD23AFD5711BDF2B6F26
+                               F988A6CE29450108FD6814802355217D
+                               F6F329FCB3F5997401019BAE0AE43760
+                               ED6B658FCB4280F5A070728411EDA4CC
+            stream[256..319] = D0AD4A851E7A60DC789762A554A8FA76
+                               77FA610F4D868CFF1AB6025B2ECDECE8
+                               C554B4C0BDF543F58A1DD7CC68FD7AA6
+                               7EFCFD59D55372E85131D6284E7949AF
+            stream[448..511] = CF7F791090D04350930AA1E1A53B70E2
+                               691A231595E83F8BAB9613BDBAD868AB
+                               197D5E06B3397CC3D81F56B87BC7521E
+                               B0BE346552DABEBA863D5C81D7245C8B
+                  xor-digest = 2C77C0ED1F5AE20A97388ACA5300918D
+                               6246B04429F298E64A75828EDBD01900
+                               FC70CC103C31E0BB67B06D04128686AC
+                               5C5FA63FE714FC4DF18C551BDF81862F
+
+Set 1, vector# 36:
+                         key = 00000000080000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 54A5A2E883714170B471C0651D74A9F7
+                               D51287C89FB345DE0AF7003C3871425E
+                               FC885F033D79BAC9716B1ED5C637BD9B
+                               0F16FD8D613BFFAB634F0EC2497D7B3C
+            stream[192..255] = C7FBA70B19B749BBD0C84C7D31A5AA44
+                               155623116C44CD53D2E640034211E730
+                               277402F62D1FF1578236A2646AFE6108
+                               2C958D9D01C065D7335EF9C29415AD42
+            stream[256..319] = 2385E2A7070FEC7399BB3CEEA43C8D0F
+                               54D3607FC1C21BF173642287C1FC2C96
+                               D37695A7B1310E5E918EBE37113348B1
+                               707BB39E401A10FF14EF020CB7C44261
+            stream[448..511] = 5A87EF81C2CFA70D86B147E9587467B5
+                               22FCDB4EAF0353E11F73F3BCC1EA6C09
+                               E962A87A0842B9225E164DB0CD1A3BA3
+                               DA8C02E6746CD3AE0BC4754ADBE7EF6D
+                  xor-digest = A65BBEA2E397048E4714A8AB3C19EE6E
+                               91B9EB8048F35FA7AB9E003E9359BE0E
+                               C3EDA827AF485C23A941F7D656C76CA2
+                               5D12044923E43E61E7DDEBE7D9C87E3F
+
+Set 1, vector# 45:
+                         key = 00000000000400000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = FF81E156907CC2C01EE23F79F936809E
+                               3F88AC15CC01BDDDA378CC1BD2317444
+                               200E4E2C63E15FF07B0B40721970E7CA
+                               68F748A95A965EEC606318447BB31C2F
+            stream[192..255] = 4C4C42A330AD444388FCA4009CC0B196
+                               84AEC3EE65138A747FE86526A263969D
+                               87CCDDCC4C9A0EBDE2D088CCCEBE76F0
+                               52BAC07636937B1567637ADB498F7F8F
+            stream[256..319] = F550BCDF67C8E9C17B800487DF83A4BC
+                               73B809C4F3279D4CFE857780412F0F7B
+                               B838A9F0322BBA84D7AC51E469C5012E
+                               D774E52E3507C7D069F5169F0403C577
+            stream[448..511] = 9D92715109A301AD47BF2376D65E2519
+                               78E12098B0DEA5B779079A0FAAC4DB42
+                               5BA9EB00301A5F964336F7EE9C0D9667
+                               C4F0DBAE14BED3E49A6A746FCB186C65
+                  xor-digest = AD2264EC651E311BAC5FB36434773F5B
+                               4A4777B2B7F811A755269FDA8339DC97
+                               7A8C6A5F66E8737DD16A88DAB8545110
+                               EAE275892A767BCAC0757C396A690F67
+
+Set 1, vector# 54:
+                         key = 00000000000002000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3DC3C1A1A40E721F8A3A66960DB2C0F0
+                               6D8B7C07FE90D67C26F86200D6A1A1D9
+                               ADE4D53A35F7A016A506D9C62D344D49
+                               5C6DEAAE053247103B8F202B85A5036D
+            stream[192..255] = 9B83E56BB5E10B5C6C05C4B450B64FA5
+                               9C52AA63E207592999CBB48355517F05
+                               C93EA878BFAECE58CBCB948E81BEFD89
+                               AE0C5C13359C6CF5A673B4EDE28FAF0B
+            stream[256..319] = 388163F9F26536BE1221A46834CC77FE
+                               03D021C570A9DA36CD528E887ECEB2A4
+                               7146A8A930D6AC04694A0B9AE50FF55A
+                               41AD3B3D3E53F982563B5B458C078C0E
+            stream[448..511] = 3B0FF94C0C9FA0EB8B8CC1C691D04180
+                               5AB6436BAFCE8C16A1351883C88E945F
+                               8F912FF79CFCEFF7374936E830C9440D
+                               C676A5F00BB50EDB34F810AFFD9CA8B3
+                  xor-digest = 879534CEDD8CDBDDDE2E2216D55529AC
+                               1189B1C34A76ECEC179B8A240E890F8C
+                               640738DC37C14E4B950B9D8C507685B1
+                               28CF4782EC424A3712F54F6265A41E7B
+
+Set 1, vector# 63:
+                         key = 00000000000000010000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 12F0A17DEA167676992DFF2E7D812878
+                               629579519578EAFD885F212C7E04F035
+                               AF03732C3DA8CFB7B73054662F0593E7
+                               E40133706F04B1329BC3155DACD296AC
+            stream[192..255] = 41BB89D0BE44055E23813783C3EC4487
+                               2D102D6EE94475AAFFC7FEB8DE6849A2
+                               6B50DE77EB9B0B96EC9EA0216D13D64B
+                               1264A83D6B571A92948A5E35446B0503
+            stream[256..319] = 15E9C9168AF4AEF7F2EF1E832F40110B
+                               A8C08DE71D4F0AAA3A5C2FC59BF41005
+                               ECA654EB7F316B757FEAD5B0F4BF41F2
+                               C6D035A88B5477632F34D7F904B2939A
+            stream[448..511] = 8A2D446044F7930B696DBA896BA6CE69
+                               8F8B01E4282BCCDC4740BB6AB6ECF7B8
+                               9CA1CFCB5745B6577D0F440AAB7985BE
+                               BEC5DBEBD8B028B15DEA138F09018297
+                  xor-digest = 89CFE7E84993C6B608EAAECBAECD7847
+                               472703F3CD97F9315BA9CA13204B616C
+                               AAC0F37EBD1C58186620710FD6AE5EFC
+                               B7CBADA19AF8C0F7E1FB24913C2300FB
+
+Set 1, vector# 72:
+                         key = 00000000000000000080000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 7BC411ECF4AC2EF2C9B8C5B7CCFD791A
+                               E8250119E08C1B7F7A82F576FF66FC9A
+                               9D9BDB7570EAF276A60A3BC7E7BCBB86
+                               7A791A48F9E742D7D7480FBA67DCDA6E
+            stream[192..255] = F85A8E3219AE1E5F20A4FFC6814458C9
+                               5A4ECFE7FE739E151A45247A136E3BB6
+                               9C11987BB5D13B1B9A3077C8F4ADC9AA
+                               A555FC9725339E02390B9C9F75E1F38C
+            stream[256..319] = 8A2E88E0A773EA00C11138710BF12ED2
+                               7797AE7863B1EC84801D11B5B3914786
+                               F1D547382DAA9D5215CD4CBC783C700A
+                               9B09FCCFED28899D2F2EC148CEFA39B2
+            stream[448..511] = 95E3BA3237F370A4E0850F2CA0FCEC89
+                               E9D832CA6DC6A062BE7ADA8D8AEFD55D
+                               2BC7A3F46BF81DEA5DD9155E8D8FE918
+                               B5DFB1926460AB69663856EEBCD4C338
+                  xor-digest = ECE252DA29D20602D138E13C004D8B66
+                               8B09FD764B7D84FB83B8F4D924504D60
+                               277BAFC521A8AB0464E4EFC6BBB9E4B9
+                               A206C38154AE3A57B84D2D39CF45616E
+
+Set 1, vector# 81:
+                         key = 00000000000000000000400000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 139C2843F0BCBDD32C685F4EE2C7AF4D
+                               E6BC79789B77B1CA6CD94A01645EA243
+                               5B491F27C27D4EEB96FEA0ACE65C0D8B
+                               BAA642B5A07245BCD0930588FFC92A50
+            stream[192..255] = 5C76EB0D5323A7AAAA228F7718BB6736
+                               5B344559C24BEDEB2CA66414B5E81795
+                               428D55868611AF9AC7EA0E7424984037
+                               3251BF5206C361AA3631DEDA52DDD519
+            stream[256..319] = EAB18EFED266D4788015DBDD20A75058
+                               FA4DE35C1DC774ABABC476BCB0AA2CB1
+                               214E5463F4E20E7B999ED475D77DBA9D
+                               70FFCA0C7971CAEC3B285EE8F9F37C02
+            stream[448..511] = 081083D9AC30C9DB4E53597D64249D7B
+                               CCD847495A928CF4CE876237D92ED5E9
+                               E3D723EFC663CA0DDF34DABB941F42C1
+                               B48EFD59DDCAE71A1B82358A3328644A
+                  xor-digest = C08714035439EFBE455BAE68EEDDA0D2
+                               A6968F18827B214A097221C3A77F80AA
+                               E1DD9F3C72FA66C16EE278A76C19107B
+                               37CC32346DBDD29FB30059A8FC732DED
+
+Set 1, vector# 90:
+                         key = 00000000000000000000002000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = AD897A3C509B66728342A817D745460F
+                               6A258386FECF71DB95ADC716B8BC0462
+                               22C4EE887334718534E719F36454E440
+                               F9EC44A2DC38345CEEA9425BF5F10123
+            stream[192..255] = B32235522391A0BE105A993923760C6F
+                               BBDA849213C628776BCC5364F28EE5BA
+                               D498F186C3C57A8DBE5355C2A38DDB82
+                               54B321636EAD186788DF1BFC5B6F85F6
+            stream[256..319] = 499CC51B20538B14A05E490B6D5D10D9
+                               11079F58E3603A84AE6689293E3AEC56
+                               7545823F0B085469CAFFF01D2AFC5076
+                               C155F8B4B7DB4C49A9A993964928D11E
+            stream[448..511] = 65983D36E97AEF89C3A75616F7C098B7
+                               5CFD9C531AFF8184010E2CFD45163312
+                               FFBCF5AC70139CF12D97325CCEFD0B01
+                               FBE571FFBD7DC21B54D4B277A2205E56
+                  xor-digest = 90CD243B35747378B85B99474EE0BB3F
+                               CE7574CC19BEC5220255523276CDECE4
+                               5A16EF44C414ADF1D1CBE264872419CC
+                               EAF664CC74D36072E9B975FF40074006
+
+Set 1, vector# 99:
+                         key = 00000000000000000000000010000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 26F731F36F626943D4CBBD605CB67FBF
+                               E9301F24AA4E93EDB2D0DBB3FB17E8C8
+                               623054B3003BB12E1C8607FB53315AF0
+                               A139CDC381753A14342AB90AFDF43E67
+            stream[192..255] = C3B755D009DE9965D36B4111308B25EF
+                               39A137E373BA0E90E5AE2748115F29FC
+                               562A6F6894BFEA59587F991DD105DE1F
+                               67F62A73A72A4802ACE727335467F503
+            stream[256..319] = BA815578D19B3B384BA7AA7B972B1FC1
+                               7244FA75A4CFDC8C30ABBFDF6861F356
+                               6A9B68A6F60A61E6DC8E046FE75373E4
+                               B45EAC193127CBA3AC4F22345BFDCCFE
+            stream[448..511] = 99C68AC554291FCDC03F300D69CE68D8
+                               C4D4DFF5FB2D4C3079992D40FFCC9683
+                               DE471E6F2A406DCE03AF8EA17B7AE905
+                               12F1368B8EFDA838274812C4F134E2E6
+                  xor-digest = 01AB73AE53306196763ACB9ACFF9A624
+                               B83A7B339DB517AEB408292627EEBC43
+                               FCA6397320F50E96ECC3595B13BFED85
+                               1309458EFE35FA1167C2CCCC6A4CA83D
+
+Set 1, vector#108:
+                         key = 00000000000000000000000000080000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 031A1BAA02280255F0413D76F945138B
+                               C0835BFE7CA64B16AD090454F098B8CF
+                               34B1EE138E03C3CCD9FF918A58D06AD9
+                               2D7F3FB57D2E161A863A0C25391CCABF
+            stream[192..255] = 6810368C2B2A091C6FB3EBB76E960AC3
+                               BFD678F028EB6FC0F5B36C2D386A21A8
+                               FE46A5AE09DB0BD75359A8482EB6F5DF
+                               ADE199B796520807D60D9D93995EAFE7
+            stream[256..319] = 0F2CDD428FF6DF2A4621A8423E09939B
+                               014BEBC0ADBB8CE71B5E587DA408ED43
+                               04A12BD535257322122EEA2840A9447E
+                               CB1B6D3550ED14EE31424F5404B2B5B0
+            stream[448..511] = C63FCB06883F3AC65612EDF28C875477
+                               1D383D42A553EAFA37ECCE26061EC5AD
+                               C6FE3BF23E06CFDB14EC1DD996A7D4E3
+                               FCF7A0B9ACC69F37ADF428B434994595
+                  xor-digest = 463386D0F7A1306E87F3221C4ECC0597
+                               9474F620AF3563686ED5DEE291155225
+                               56B9372496638BA1631982D6B3F58CAE
+                               27810BB7AA93351B838D54EE761A8C94
+
+Set 1, vector#117:
+                         key = 00000000000000000000000000000400
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = AA4E7E8171A8E0AEDA6049999E0A06C2
+                               FFA43B9ADC5E9DCE4ECD8FC1D27BE792
+                               6FBE2ABB69A6B69D8C213A793C77096F
+                               D4DF7BBDBCDF007C914B7C817837D99C
+            stream[192..255] = FC90E3C82B8E7228C1ADC2F555068372
+                               4307902A0750149CE0B2EFD2CCFE9875
+                               DABE60E1B85CA117D05E4BD4F45B42E4
+                               55A9F42C60910C9BFF8DF8FAB53C81E1
+            stream[256..319] = 9BD976B88E9E5E23D0D40779644BB3F4
+                               CE5C6B16FA6D955C32369DFD19D632BC
+                               7730683D562320E39F75D8D8BD074968
+                               9ECAF0DCDCD99FF4C3939092E9576144
+            stream[448..511] = 51BE9CC1362669C0F79D2D88A42DBED6
+                               C3315002380AEB647C8F9C4036590527
+                               1D8915B985B8BE9CC1C5C7652139E609
+                               651EAC8A14DF661D9869982AE5735E9F
+                  xor-digest = 0B0C84D430687F488F8E45DECECD6D7F
+                               1947E32AC49BDD2139F5413E08A88F31
+                               F9AF6599498431F155AA10B7EC09F095
+                               8A5AFDAD486D2E6D50AF77FE98E33738
+
+Set 1, vector#126:
+                         key = 00000000000000000000000000000002
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 52F49050156E957C605656B2DF88EE1A
+                               5E3ADA99F9793B65456C4C6C322B8B5A
+                               28DCC91EE0E711BC33E0C13354542227
+                               613665CFA3A825B943444401EFB06ACB
+            stream[192..255] = D0907F5D5939D7B544476E299605972F
+                               FE422C64BC6343F9C81093AD0E3ACC72
+                               F4B67314892E36764736C0715E4D3438
+                               36BDB105214F5F8925F321F5FD865EE2
+            stream[256..319] = 96EEDA75474D65615795185B1BEE8D44
+                               A687420304B260E4C70FE7F542967325
+                               1826EAE010981F6262EE6CB639996467
+                               5F6B23825748128617721752283C16DB
+            stream[448..511] = D926085A441E507207850AFF3008D59D
+                               F7C9D3B69687D18CCFF2C2E09D4E4EA7
+                               FF0B72C04A86B80923DAE187FFB99170
+                               DBD4902AF77EEC42866A83B519F092FF
+                  xor-digest = 1E068ACCA6062CF26ECEC79F149BE139
+                               24AF8BF44377EAD1550B1560E4A1006A
+                               A6986C61581FF9E47D58F2E52434911D
+                               5AFCF914DBBAE183D02DDA3210768984
+
+Set 1, vector#135:
+                         key = 00000000000000000000000000000000
+                               01000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = EF5BBD7A620E8052F05DC269309AA7CF
+                               8AFD4AB2B941D905AEEFC721562E00D7
+                               04CA70113C8A90FA12A0C9B9CD1B9F9E
+                               6176602CC08B66410A8BB0F5E9837C27
+            stream[192..255] = AB843B43856FC77C1EC09C0DD2248617
+                               820344BD2CA0B025C39B0EBD5A750A6C
+                               7BDCE863C068E0D3A937A5B2C5B6ADFC
+                               609F6DF7778D88238B89288B2768DE99
+            stream[256..319] = 5E6AFBE41F47F35CA9298C973E613174
+                               529D9BEFA6D0713A5BFFD96B70D39044
+                               413E24FE57B01C426E8988EC365FEFEC
+                               1422CDFB956B12C6A799F5FDD4EE43D5
+            stream[448..511] = AA960C189C0A20870901D4E2F1901D0F
+                               A28AF3D974E14FB70736C191D4C9CA26
+                               48EEBA776339F80D57A8B783419E61B7
+                               52541CB296B4CD31C55DE3D34CEF0D31
+                  xor-digest = F163BB7ABD3914204ABAF08B844ECF05
+                               A36B7B37B8345115EFAA2AB2E7763E6A
+                               E044A83597C023FB41EFAEFBB63E4195
+                               B60AEA6399DEBC94C75BE883B3623733
+
+Set 1, vector#144:
+                         key = 00000000000000000000000000000000
+                               00008000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 9198011FAAD874AD77CD0C98DD99C7BA
+                               01B75CF9DE1E26321EC6AD293C73C675
+                               69A349157FD47672C5326276BA40F4C5
+                               0CF8D98134D0BC13879E9EC267110FDE
+            stream[192..255] = A9B3BEEA161ED996C44F6D3B93431C6F
+                               54DCD5DB88E62CA10D1067B9CB5D21DC
+                               D7E04C48D88DF54E1370D1C24C871BD3
+                               BDF9B956315996F95867D1E2494370CD
+            stream[256..319] = D09ECB5DF5B0526372B57CDF5DCA6AE0
+                               F005D2E2F27D50398E3D1D7FF2100BAA
+                               D6F2C03E431345A4F41CEF3E8D3F14CD
+                               C76A423720A936D27322559289F13D92
+            stream[448..511] = 5E8FE7964B052B6D27216E37C49CC913
+                               450FAE159C087E34CF67E8B0B8F516D6
+                               3C0B544CA29F9BCB2B48D3894D69DE3E
+                               1460783E82EB67990FFB7F92DA48E449
+                  xor-digest = 5515E37A3F274746847F551ECB7DB4BC
+                               2BC32237050BEE9AF2AD1BD8577034D3
+                               4A23AB8A2FFD00C7B8CB7D5CA0AB2421
+                               E7CECB2801A1B73A44FF3E798ACA8443
+
+Set 1, vector#153:
+                         key = 00000000000000000000000000000000
+                               00000040000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 02858548ED24761DC0AEC6752076D095
+                               7E78EF1FCFFD8E756C747586A3B59C22
+                               F42A9FCA9F103C3054E0B4F6EEC82101
+                               971F2A6F9611F7541152FA3BD7774474
+            stream[192..255] = C32ADE80873D1190E9807C25D73EC5B7
+                               C208AC693D98A664FF4D11205650F7FA
+                               A36B153BC1A3F0EE0F4319F2100F7F27
+                               31856BFAE36110C12EF0361259641D74
+            stream[256..319] = B8F74AD5930D1F2CEA6B9F7E4E775DF0
+                               AA97744677E5C96B9E55AD77BFAC5E8E
+                               E9BA7A19607D9EC52DEEBECD185DAE13
+                               E304743019D831849F111602EE6EC34B
+            stream[448..511] = 513303A57165287E793DB91F49C9A8ED
+                               522389F03634930512744884BCA45F4C
+                               ACB60FD077BF2C050D4002162FB811EC
+                               4AA855793CFF2E30665188471FFE0847
+                  xor-digest = 7EABCDBDA34E51E3A61D2F3340884BBB
+                               600E1D30216B7117081B3E5D04FD4523
+                               706D4F34C5FD604134DC89F570D6119D
+                               DBB7C5FB7CA90E38AC157832C3C956BD
+
+Set 1, vector#162:
+                         key = 00000000000000000000000000000000
+                               00000000200000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 689E48A85A40BD161BEC710F9B2457FD
+                               276F1156EBC10BB851A8517AFDBD692D
+                               E4827BAAFF218AF886439ED976147EBB
+                               BB1074BD599A80F6324C87BAC987B8C5
+            stream[192..255] = D9BA3E74CBAA58CA97DA3D3B1051BDF3
+                               29F6CD837B72022D2EAB5D20B02F53DC
+                               4755C764C50756A7101998C187E4F0F8
+                               F17A0C6797976C4FF1BA17B3D03C2218
+            stream[256..319] = F6F9B6F0F6E1D756C0242B48BC55EDE3
+                               3038BABF72FCDD5122C61804996F5ED0
+                               86A78B33C517CCED9C34580AA54AC03E
+                               BD0F9698A234787DFE97FCD3D9B7CEBE
+            stream[448..511] = C31091C4C5AD605BA90963B1D469E501
+                               412FEECDE3EA8EE834F188793A98F830
+                               81F8C941F11676E007074B40EB15DDB5
+                               67D93E954422376F2E3039F4E4115D70
+                  xor-digest = DF047B3EE7F2AAACE9D5A2B0F6A1EA0B
+                               97E815E9B9BDD3B7862ECB414E9C08E9
+                               BA0109B1D6866C9D7D6D3DC9FAE5F51A
+                               48DE7B9077DA489B7982BA69228483A2
+
+Set 1, vector#171:
+                         key = 00000000000000000000000000000000
+                               00000000001000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 1F8F707DDF0121AE4DF26A6ABDC195A7
+                               CB9CC8479588D2D436C52483DA54744A
+                               2880E3DC622180D36B64CC053CC245D8
+                               0700EC62ABCA6944BF89C7DE1A532A3C
+            stream[192..255] = CB2D934DD1414C60550CEA6FFA776312
+                               3C9336F99F16F8B5B8E60D5D0CE54A35
+                               E752A4887A03EEC95050E50B58F5C8C2
+                               FD814DE76D3F66B907C77C9B646EFD13
+            stream[256..319] = 10306DD8B3EA307496D7BEB7A679D53C
+                               3650ADC53991D0565856F51DA82CEB45
+                               AFB460D6F90877557E17F534C3375FD9
+                               F96D13AB77FA3996998F5DC6F5D3C9A3
+            stream[448..511] = 42F4D1F669741750B24A44F82990E6AD
+                               065E7B07B2194C96E7578F7A754E52A5
+                               86C820FFDDBA671A7B08D65B51D8736F
+                               D0DA8E81CC69BB8A56565C43845C0AF4
+                  xor-digest = C0535BC269BB39AC2ADCC50C62F87B6F
+                               2C9351DAD49813529A27BAEC163A1D8B
+                               778670F0FF1610A4688F86851050C9B7
+                               275B087A0B5CE01B602F8D1D25C29392
+
+Set 1, vector#180:
+                         key = 00000000000000000000000000000000
+                               00000000000008000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 899C1C50A80E374AE884F10BBD17D036
+                               1632D89938FDB7E4BCFBE1050D5E948C
+                               CF4631EDFEFD2F140FC3FBFCC096CD68
+                               1F6C1B0CE9E395FDEC56295AE331D8D0
+            stream[192..255] = 2F60CFD4D07E58DBC5127A98D2B1DDD6
+                               1F216F61F70AF12427108906AFEDA4AB
+                               B439A99765EB84E43D06EB7B3D984A3B
+                               53D8C054745A6E3B61F8444C84C7F30D
+            stream[256..319] = 1A92F3B4F6C4684201FA4AF201259AC2
+                               53637B41B734062C298E6F932DBDAC5E
+                               999FEC21B63539B5FAFC312D0CCE6137
+                               04AB3CE65E241A1C34D12ECCC840973C
+            stream[448..511] = 83A75C2E2C6D40FAEA049322DC1B2251
+                               306A8906A37DD30182C328D50E7B7AAF
+                               89671DD776C9C730EEE0DACEAC7D7038
+                               4A93426090F31EB851976B8B2ECA1FBA
+                  xor-digest = 6D85E7DA2069F1308D20A56DB17F3629
+                               09E80EA6A045DBE61FB037C3C8B9D448
+                               526A37A431A8BE49CE4F10B8CF6A33B8
+                               82E6ACD6309BA1B716810715666C6CDA
+
+Set 1, vector#189:
+                         key = 00000000000000000000000000000000
+                               00000000000000040000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F9E151BE5EA0F532E56958F173B8F104
+                               DC9E73D8FA289CC2F84C4BB10E8EA769
+                               57FBC8F539365B9E9518F8787D6CF927
+                               55F0C2B2845318337F36B80E22C59FD6
+            stream[192..255] = 27FAFEBD2EBCD2B67AB18BCFB7F8DC96
+                               F54C8A765B0E4B3DDC3013B599DEF791
+                               287FF3C0F48F339DA04B667E54696485
+                               D48751A001B548727338AD6FB82EAE42
+            stream[256..319] = 09DC2AFADEECB86278C64DDCA51EEF97
+                               C10B9852DB5F33A19C99C0D4F36D2959
+                               DE247E4DB356E67F2951E0309F18D6D7
+                               27D2A1BADCC44DC320E2AA80E1834198
+            stream[448..511] = 4103D8455B6DAE658915FACFF2F3F1F2
+                               856E2343143671565936301E9D1F635F
+                               EA732C9A096C3E955D33770E244ACEA4
+                               094E390239489F4D4F0A1F3C26A1589D
+                  xor-digest = 8DF4EC7886C386E5A0D7201A3E731E95
+                               5D1E281321C2B592E31681CC95D173A7
+                               C92E6112197C6A605F494F6E9C4AE73A
+                               21B966CBAB1628794F0E44202742EACE
+
+Set 1, vector#198:
+                         key = 00000000000000000000000000000000
+                               00000000000000000200000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 8B9B0CC804CB353F49564926E3FD846F
+                               A4758692FB110A428FAA3132F4C606CC
+                               A41CA937FDE463D9FEC51F419D60AE60
+                               1E8EDB30AB09E0B08D0143D885161B16
+            stream[192..255] = DC6DFDC4E36FC1D4BD87F731F761BCC3
+                               9837A790DBB766040B4508778C5CFC82
+                               8EF9EC4D76BE3AE0967DBC844A2D252C
+                               B942E97A2C6A185ECF4E1200BF9BC826
+            stream[256..319] = A9DE78C2204B712A9803594B872F29E9
+                               5E8962D7D719702FB3279F053D311292
+                               26A14FB06058AEEB6D283EE0A272C6F2
+                               D392B102E294A7CDF24928D5281D024E
+            stream[448..511] = EB822D7BDDA456BB6E109ECD330D4FB5
+                               1259D7042935BD5DFC787E903758C27C
+                               E9E9B191957E721A7013D36E5A29C09A
+                               3433205956A55460D1498124B2800423
+                  xor-digest = 10128D9A5EEA1D93E65462702DB15A8A
+                               23D0FDFCC5B0871639D704DEB9F580C1
+                               C88213CA166F3BBB89D0926CAE7E64C1
+                               0A24041A42B9D50CB0537A0585EE574D
+
+Set 1, vector#207:
+                         key = 00000000000000000000000000000000
+                               00000000000000000001000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DD4CCBD0B5068DF0193F50C11D2576E1
+                               A70040D6C2CDB98061498891D1791E63
+                               C4B5103A52146CE27D8F721E147EA612
+                               7E5BAE1FCD3DCD9053D5FF5EBA328BBF
+            stream[192..255] = 541F008D78EC1ADC5D1B930CC99D4A3D
+                               61BD60AAB9DDC8AF8594FCA129410232
+                               92BC44EE064E44E88A07ACD1B742666A
+                               D147F14102D23578E3B7DC00905586D1
+            stream[256..319] = 6834D2FB6BF3B46C0552AD83275CE6EB
+                               9482C2DFE40C6B1FD6F743CAC8F40A91
+                               5BA9A90FBE7CC0153D53C444D3F7A23D
+                               CDC3134E237F63E5A07C99C10B8EE87A
+            stream[448..511] = 9F75BC84091695FDAA2579AF9D34B2A7
+                               2B82D39A1E7FCFC4D18D6898A9CD3296
+                               0D50AF1B720E1347A0848782BE6AECC4
+                               684CCA05B893951A65EB7CB37F5FE240
+                  xor-digest = 12F358C7C4C697199F9AF17040115522
+                               062514A5DC3584BC515AAA4474A1D85B
+                               47A6A2D8C39E8234A5D11860BC1036E3
+                               957920C03E9A47E61AAFB058A9850559
+
+Set 1, vector#216:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000008000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C5958694DB1D54B95101A9F48660CB26
+                               8EDADED85C6239098248E0867117607C
+                               D5278E5B5D9CDA7BE8A6BBDCE61215B6
+                               2A93FFF627B28B271CF2275E54EA1CD0
+            stream[192..255] = D9B69B25B5729759F3180FF17421092B
+                               0740B2E1307FA9141915CB8C30C0C322
+                               A1E4710674EE715DF3AC89F447442A7F
+                               845E154393273BA47F2322BC661D1755
+            stream[256..319] = 49412E5F3C9B5B52FF790CBE82D6F037
+                               217A13B7744740A887F7C1FBE3714DEA
+                               2A4EA4A5F444B2EC3C0B160A251CB44F
+                               8DCA914FBB80F72BC8D009F1C7E001EA
+            stream[448..511] = E1C2BE8C64D6BFE081EDD30681763928
+                               85939DD7EBC13E16D83C8E7FF65EDBC5
+                               90FA3904068784806E20F0A61CC73839
+                               E3BACD410F59D3848F5A628EE030FC4E
+                  xor-digest = 54092B3D64197BD598F9050B44D2E785
+                               029F29F46822B72ECA40182E8ABDABA8
+                               751054FC50250DF5AF5AC75F4C51D1D5
+                               D2BE298770C353A7C5D608D1149F1452
+
+Set 1, vector#225:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000040000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 633A6CAC516B7A84CFF8F5702CD9BC81
+                               BCE328741675EBA0FD1368190AB6BEEA
+                               7C8B0256CEDF9E5CC6F9249511AB87AD
+                               ED95BF8E11182B8BEB75FFA279C3F706
+            stream[192..255] = C3F700538A4EEA17773E74D10CE4493E
+                               FB0417B380ED4229F651D6A9BE0AC617
+                               AF66C576B7D06F2210EF226462004D90
+                               E753D805AB198B73B0CCD752C7E57A2A
+            stream[256..319] = 30A11289A9E0C854B980BE044F07E945
+                               06D772861896D0F75D739647FFB939C8
+                               13FE4BE5C8DF84F64827306D0DD82415
+                               E104F787F30CD097EED7DB9340A0F47E
+            stream[448..511] = C2134984733448DD577DC48B5EE5D761
+                               0A54AB6C32E3BB782849D8E7E8B522B8
+                               0D6444342ADD9709D7434F9B4C18C6E0
+                               15AE97DF8F3D29FA6D85DA387157E223
+                  xor-digest = 8613454AD0B424AB6EFCEA96C0802B6F
+                               47F1E98C52BC68DA25E653431CE31078
+                               1658BC45DCC2EB43C4ACF8395727133D
+                               12A127D4CBAABAF24BA44930A58A87B6
+
+Set 1, vector#234:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000200000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 6A0F095C0E23FD6F8DCAEDAE5314141A
+                               0F1CE1C1BD6A16E81FEFF72F0753A5AF
+                               C1C54DFC0DD6ED99F1D416BE3C5EF341
+                               454C18D49729E80EE99F37734817658C
+            stream[192..255] = 05A4DF5BE8A35DC623D107728F28C789
+                               3DE0E75268B3E1F94C07AE50CA0891D6
+                               2B1E764CB41062391B33929273CE6B6D
+                               1C9CEFB35C37AB2FA8EC18749B5292B0
+            stream[256..319] = 41C8AF9ADA46F7BE8EA72BB3B8661B78
+                               2BE5649F18F216B75A0071A6617200B8
+                               463B08F986D706AD140E27C8F4E040BD
+                               6BFB4872D758363281C62AE8C4B64E33
+            stream[448..511] = 58CDA35476767EF58748A504B0E4A38B
+                               64162AD422A0DEC0434D879898558C77
+                               1A8243DC43B15FF996B4C8CAD3C47C6F
+                               26F00C71ADFB538D9A983B7B624D6E62
+                  xor-digest = 240A699AF4DDBB56A4C502A9175C0E3A
+                               BBD654D0717A1F6F6847381B978AE8C8
+                               0EB7CA07A481DFF8606A31BD6B489AE7
+                               89763068D641BAEADCBDA9ECAC465ABC
+
+Set 1, vector#243:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000001000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B3C91DA5911D7D7A4BC16A66988AFD3C
+                               8462A9E9BD0D95C9B9884DD14801E464
+                               C27048FEB5F70B28013099F0A31255A4
+                               9EACE528A13CB5DD067E520D183133BC
+            stream[192..255] = 756EDB0542FE1F11B159C7081D9CD742
+                               2F0E5862D39E2CF1517B2F6F39AE5245
+                               D659A5B93EB8FA8C8FB751B378BB0DEB
+                               481B874663624C8DC15E6A1A64376340
+            stream[256..319] = 436613C9293D5DCB204B46899CF23E65
+                               698BCC3003FE064FD1263EEBC59DDBAC
+                               536566855510FA802128F0A968A2E359
+                               FB68EAFD6AA89D394B32BF6069E92EFC
+            stream[448..511] = 033FF40203ACAEDFBF561A674EE74D97
+                               A535A448AFF94C8C167200E5CA626388
+                               DB1BD6EBD4A1D83CF352E97CD8F02671
+                               18E57B71D33930EC2752D2F262A55F9D
+                  xor-digest = 2CEEE4705688B20B3AF71F285DB9361B
+                               0EC945296B97F3A050C31C54E9A07CA6
+                               498B92917617571928E2663CBBAE21AD
+                               8DD880A037A024E46B6581974838AE1A
+
+Set 1, vector#252:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000008
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A6AFA8AA02C3AE7F29E61202B4A5C25B
+                               6F74BCC176702C9C1D610FF722527A6E
+                               721ED90B871AEEC71EB62B24A8F24357
+                               07765F7724BA03173F51C9B66C9F4BDE
+            stream[192..255] = 002B8929A54C1370067A36DB9057807D
+                               DB747C2A4CE19BC085DDC517AADE3B97
+                               BB1B35F2BAA6A18E8154CD80DA6F9F4B
+                               0DBFD3EA5F69D5ED3B5770C6221A8D66
+            stream[256..319] = AADBBFDFC6FCC6072747BB528EBEEF34
+                               6DA76885CF1616ECFB89D3A134769902
+                               904AA12744DD404F268B0B4B34700928
+                               E3C4B3665B9CFBAD9C528EA06F89CCDA
+            stream[448..511] = DD5453BD0D99E7D2CFC558EA969A4E35
+                               743AFA96D570026106C5CF40037B1325
+                               40C909C1278DAC8369B1AC257FD8D868
+                               3648B4F22F7C66282BAC49D8D23626EB
+                  xor-digest = B3F2AD900155FD5D39768B4F4B7F8E5A
+                               1C557936F2B5F06966DCB884AFF7F01C
+                               7AFC073C20EAF85363DFF41357E626B3
+                               B19607224467413D185A05E7BFBC5F0D
+
+Test vectors -- set 2
+=====================
+
+Set 2, vector#  0:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 5B078985D8F6F30D42C5C02FA6B67951
+                               53F06534801F89F24E74248B720B4818
+                               CD9227ECEBCF4DBF8DBF6977E4AE14FA
+                               E8504C7BC8A9F3EA6C0106F5327E6981
+            stream[192..255] = 30DA9453A90909A5675D6B691CB0990F
+                               C423CDD8222EB47245BBB67BCA2B9C10
+                               8D1F016DF0CF8CEAF6829910916DBC1E
+                               113D11E91BEC3D85C47E3042EC865658
+            stream[256..319] = CAFED71B892EDBE13388CEF6A3365797
+                               E0D88C0D3A5B91BE4CBAF5162F69558F
+                               DBB45CA6F8C8D4C371D62736EC244584
+                               60131F54854F3EC804AA9A38E6ADE281
+            stream[448..511] = 531A0ED5D2A51DDC6499FE1BB6E2295F
+                               2C3EA0F56AF46ED93DFAA4E16F5F0831
+                               2D77BD0E9122043CD6A202CBA9351F6A
+                               0E8E6263F4017355136A0C551E6FD0F8
+                  xor-digest = 023D719F61C193E4CCD87755C87F9604
+                               C5A29DD7E31637B3DD70D43441D48CC7
+                               D474013C85EEAB1897C80ED0A0272543
+                               F951C72E3954616CB5D6B51FC24F4B0F
+
+Set 2, vector#  9:
+                         key = 09090909090909090909090909090909
+                               09090909090909090909090909090909
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F5C2926651AEED9AF1A9C2F04C03D081
+                               2145B56AEA46EB283A25A4C9E3D8BEB4
+                               821B418F06F2B9DCDF1A85AB8C02CD14
+                               62E1BBCAEC9AB0E99AA6AFF918BA627C
+            stream[192..255] = 3B3C6E78A8F381EE2C159FAE1C487C58
+                               11FA9BB02CECF7440239FBB0497347EF
+                               D8F1A8AA71AFC70ECCD64E81388E6E87
+                               9521C2B47AD84F9CFD9E240D8D2F3001
+            stream[256..319] = DB04FD01BC18D91E2D31237AD0FE26AD
+                               3C8D6A2EFDAA9CC11BFCC61D94F6104A
+                               4091B3634FA57AB0AB9B209F22DA5529
+                               75C3C322DEBE4AE68623BFE1B2BB7F0A
+            stream[448..511] = 35B290F85EBA78A978750690C4747E8F
+                               72621951483772E8B89876CC5D55F3AB
+                               02D9B8FB35C741279FF9B5B571B26329
+                               4D011F813CB5B209CA1A22D532BF09B7
+                  xor-digest = EA9BB65E87C987EA64BC3F4E710CCC34
+                               F6CD0A795B8347E1441CEBEE35540D41
+                               64FC2B95D71FD47A2C4ADF732261EE52
+                               8125BE374FA4A90132CC1063971A2862
+
+Set 2, vector# 18:
+                         key = 12121212121212121212121212121212
+                               12121212121212121212121212121212
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 397F8EC015ED573967938D1CEAFE9BBD
+                               BD8853C329B3A881B489090853FE0F43
+                               89DA105F0ADFA9CF51DA2521C40FD2B8
+                               FB0BF80B93E3F2B3D8A8EB1C615E0FA6
+            stream[192..255] = 68E7DBF465E3C6994D58B9937A866E4D
+                               43A82A80DAEDBF29C048639BA38B690B
+                               7ED11323E3C0A8E77A16356705431EC9
+                               9F2CB7F7E1ED3B83EAF2CAEC00B00755
+            stream[256..319] = DA51CF3A07EBE7E86E9DDDE5A47E7417
+                               376F334E6AEF9C187012C8AD2B94BE7C
+                               00A876756EB232510FD0798E72EEC87F
+                               75EC1467C07B3A1EFB0D51A5FA65E382
+            stream[448..511] = 0BF3C6FF6794887F2776FD632B83682B
+                               AAFD131432CFD7D2F675E03320395313
+                               AD4ED96E9052FE6B2D2A17428660A25E
+                               EE642B712800BE3F7E44F21A1E6A03AC
+                  xor-digest = EF4E84DBD66497B142EEAC56B830FF78
+                               0465CEE20B9CFAF5727D4B3A588F4D00
+                               AAF718330CFF35508C44C1ADB8476625
+                               2CC3AA6AAAE74F8BF1DDB6D4AADA425E
+
+Set 2, vector# 27:
+                         key = 1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B
+                               1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 72BC8A6E1E61E704B142AA00812EE676
+                               263C1CB9AB941119B19D15EBA3462F56
+                               2F69220595DE5E0E7C595FA40F1F06B2
+                               6EC32252AF05310809DDDFAE2E24B170
+            stream[192..255] = B29A740B51B4EA1080666337D5551484
+                               FFED6860A5125DC0573C8F90F23A98E0
+                               BA7B3E4C28C2CEFB1C33D2C36D1B7625
+                               64B9A67240CF174347A4C8D868F00F6F
+            stream[256..319] = 555ABD5577A8909797FBA9769C03A0F6
+                               537C06AFB23354F054E25457B729B534
+                               CD10B2ABD45BE3E38DAF1B7A9103268F
+                               4FDB4C0FC9A80A003FCB907E8F249AE0
+            stream[448..511] = 3B29A43D9C795DAF1760CA9EB57C0B39
+                               F62D54311207B617B727FCCE1B2E762A
+                               060810C4DEF672E7D76083E3E4BED0D1
+                               0BAFD27CDFD2C937E660190D36B3FD7B
+                  xor-digest = 0B3B0B3C69F2E4BDA22E25AEF352234C
+                               18CC5E1E3F6A317ED7257887446EF734
+                               65CA15F51AF5E077B7915062391D8497
+                               8F437985DD08F5FA3A8D74B3227A6EEF
+
+Set 2, vector# 36:
+                         key = 24242424242424242424242424242424
+                               24242424242424242424242424242424
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C845BA29D542FBED2D021C85188E119F
+                               D34967B79D9F44635DD45D2E41DC5AFB
+                               B237AD2FA0E4CF4202D83DF3073C578D
+                               2AA8A32D30FB45DE28F23CEB85E50FBF
+            stream[192..255] = 15C910FDD3C590AED1ED7DA2A7969297
+                               FD12081B4B23F0A32CE5B3196173C7CA
+                               7EDD03F9637E08CA501C4850C15B207D
+                               7AA724377396CED2357B572BBF9E69AA
+            stream[256..319] = E484AF567EF80BAE77461855294E9280
+                               EF57E7366605785034D639D6DE3EBB0D
+                               E21886D0E1E0679BC2E2C9C2D9201484
+                               4A452B6AD3F1AC8B7762FF3C0E405B3B
+            stream[448..511] = 595D9855200786BB575FF7977509F395
+                               7879CA1F19619A99174BF013CB62F85B
+                               FF2C3C4FE724E26DD0C10D7635A2491A
+                               9E7E868D9DAD9201465AA178184D06AC
+                  xor-digest = 08737B82505F46F4FF282EF42F387AA8
+                               0450058F5314389BB73733BC163D75D5
+                               D32FC6408F8DE5F6ED2050027D605FAC
+                               A7119FC2DC1B6D3E84E8048DCC42FBD2
+
+Set 2, vector# 45:
+                         key = 2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
+                               2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CA82A689535CA8BAE01BAFEBA6504B3E
+                               6E6320101999BCE5550C2BBC9BC65D91
+                               FAA2D72FA4BF46B6EE916244048B1D09
+                               A115E3AB6C00BAC8EE382B58859E8157
+            stream[192..255] = DE787B1CE01B0BC09801D78D1FFA3A82
+                               0C18B867C561E96DF4ADADC5A4375E44
+                               5A34F9457E5F8C9A337A0C88DF0F723A
+                               D4509F1449DF2C6AEC0EADF4C7A8139A
+            stream[256..319] = 7E1854FA15DF9D5827F1555F12B292C8
+                               452A1A893EF034C51750388D294947EE
+                               3F505839C69C1708E8323C449C39A96B
+                               FC9EC91B0E1CAA8112057EB0389FDFD2
+            stream[448..511] = C85B42B838FB9C3D4956C9E22FBD8FBC
+                               EDD92C4461EFBA5CF1664B9AF54857BE
+                               C3D00319E5E8A89A8322831151EE1D52
+                               D8585AC79CB60B61ED2C852D04BB0FB1
+                  xor-digest = C65A6BEBC4FE898DB8D6B8F6E8F3680D
+                               2363BC12259B0FDB2BD8F052A572ECA8
+                               D1EF62AA9A48497805A413742B5AF5A2
+                               6DC9FF624B49E5D6FE58BBE5251B4983
+
+Set 2, vector# 54:
+                         key = 36363636363636363636363636363636
+                               36363636363636363636363636363636
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 9F6BCFDE566A1B67C608F11B8461E340
+                               42D4F07DA4D5EB05554CB7426D65C5EC
+                               A93C2D321175B6F72FCBEBA6E38CB098
+                               B72534F7D534B1AADD97B77E8513B482
+            stream[192..255] = B2466A173F436C8433F264CBF125B8E4
+                               C10BC81BD46B5C21FA161CB2AE07D27B
+                               F66812A2C2FCB2B14C23E413CEF4E591
+                               AD52EF810A000B42E5C1B76EEBB17739
+            stream[256..319] = ECBED2058DC50223614EB8635B834C3B
+                               B176719C18CA5E3D087A93E5CDF81123
+                               C6FB819CCAFB5042AADFED5E3C33116A
+                               FD92AA21031165A22F4751C423B8B945
+            stream[448..511] = 758BD9435DE607867DA256064C304C8E
+                               DDDF5B64173CF2C98B2842992F8C5FE1
+                               A37C3227B7F37D49A39F9FF929A883FD
+                               56DB8B1A174E1E55FCB21C9E1164C20B
+                  xor-digest = 31761A49503946701D35306FBCBE10E2
+                               02967E7EC14A328B4DB19FE79F03553F
+                               13A012B7297B2D02F18A216AD24A682B
+                               299518C3769123EE86A4937DAA9FC39B
+
+Set 2, vector# 63:
+                         key = 3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F
+                               3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 85C7FF83641ECF1C91B2D996D4EAFF6B
+                               26A4E7E34C0CA9CB9399F655E566383E
+                               246143F57776C8E08951E87F76091FE7
+                               2356CC901F09A07895A890AECF047B3F
+            stream[192..255] = 4CE0C6606195F7562D485E32E8E105AF
+                               C862100A07E55FB449BCFA2D9BD48658
+                               958B37B3EA3565FA66824102A14B5770
+                               5E3914E0680E116ED58212CBF61028E3
+            stream[256..319] = 3BB772A5A8DE2AB14CAC1ACBF45B1701
+                               057710F24C01E680F58090B8E949AF01
+                               8970A43A698A04C0C8639FAA665DA3AA
+                               562B2C5C3A03BCC38FE75DC1821ED718
+            stream[448..511] = C73DEA1F7BFE42DF75EA2681BEB31948
+                               821FBB049DAD15B988A77C0247868A38
+                               2056B66F47B0195FA30C9DB5A2334A9D
+                               CD7C0D22E479FAE1BBCDFFE60F261C7F
+                  xor-digest = 94D41CCAD940CED3C854DA0796DC62E5
+                               6B566A980E34F353CFFD0F53AE9E34FF
+                               A6A057645FE66D86BE30F93805D9E2B5
+                               D78C68EEBF61CE387277A51EB2EF835B
+
+Set 2, vector# 72:
+                         key = 48484848484848484848484848484848
+                               48484848484848484848484848484848
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E45194379659D1D8904DB3698AF8B245
+                               762910B7FBD019AD1AA20A6C433B4C80
+                               308A9EA68697631646BF3A2107C4E7FE
+                               2235E8F3262A9DFD3F5CC23FEB0B2DAB
+            stream[192..255] = 012611EBCFF9F839DDABF99D9D4757DA
+                               4E947598C4757976F6F61DA5F0DAC8BC
+                               DDF72F08BA2F446FA37F9A490F6A2B6D
+                               79227C93271D6B763DA7B2A907220A42
+            stream[256..319] = DDE54F9170D6A4702CAF45CC6F799F74
+                               A43D83AB8ECBAC5206D108F869561D70
+                               F151A0037F8E28951B5026643F8B2D6D
+                               56A62E259F04A5EA304791A9468E66AF
+            stream[448..511] = F70794C084E6EDC07BA0347413B05FC9
+                               FC46994CA820CE4FC037ADBA50EAA9AD
+                               55064ACB7308CFCE3F35AD5C7C628362
+                               F4210FBC2D3264F734728626BABF5356
+                  xor-digest = 31815B36BA034BB1941DB1E45A941A59
+                               7C3882F34BD3BF441CAE8A9790B05BCA
+                               72049FD10C09A14AC9DB867A82C38A5F
+                               524C72F783DFD16980DBCDEB486FAE96
+
+Set 2, vector# 81:
+                         key = 51515151515151515151515151515151
+                               51515151515151515151515151515151
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3C04E21F6937C4EF472BFDDA89F9CAF6
+                               FF53889A9979ABA8F23AA51DB1EDB8E9
+                               D08F696C1100799A7D004DEF1CA94110
+                               FCF0C054B0C131E6FAE0FE2F2DBF22B3
+            stream[192..255] = 9B4ED3EF9639B953186FC7E732E7A9EC
+                               55A5F3F19C5A10E12EBE46DD84F10385
+                               33837693588D584FDAF86E3A217C3CFF
+                               020278736F1A90CE07F0DCE4329005B9
+            stream[256..319] = 135FAD68B5282FE59B28D2DF66463632
+                               06CA92E84A73FA131EDDCE89A5C23B4D
+                               08FA57D455BDB32F8ED58DAF3EF288A2
+                               7C72020E35DAE19B446E4C52DCDAC5B1
+            stream[448..511] = 7D08FE1CAA0E8A0362669B310B99127D
+                               18F2111002891D3229102D72605B9BEE
+                               F5DA36059B0DBBA7646927650305431B
+                               FDA4A97570CD0C484BF1E974B157ED7F
+                  xor-digest = 5125E77698C0DAA89A7E47DC5D038D40
+                               7B732CE56CEB674CE653A1B6661B2740
+                               0C092AFF83BEEE4FC4543B9D725C9387
+                               2F89AA338222ED677BF59397200AB304
+
+Set 2, vector# 90:
+                         key = 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A
+                               5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DA2E6F7FF0D1F1C87A97E028D3E20E21
+                               75E9AD91482965B651B495AEE819CC6E
+                               C42AFE2C20EEACCEC4E90710D17210E0
+                               4CC6832905985322C8007F872D3E58E1
+            stream[192..255] = 09B0A38E19DDDA08F7DFEF7D0FC80560
+                               D692A020F0A66F609374ABDCD1343722
+                               05F19CA04EBDD3009844BC540C1B2B41
+                               66D45E8A2E822B906DA34649E7FEEBB3
+            stream[256..319] = 6C8E2CE1D7FABA414432E75BA2EFE4AF
+                               CE2CFE99506677A956AEC86BD290B6AF
+                               C5298A448D0DEFA99AA5CD26D318982F
+                               E786D809C713D5A55B42CA6650191DDC
+            stream[448..511] = 845FEA0A88B521CCB8927C9457AD3225
+                               EF6E3C21705EC9FB24873916A2C24668
+                               963C03FE097DA8224A42A99E5DFFDC17
+                               68CF518DE49CCAC8A70216C62C9CBA6D
+                  xor-digest = A46BFD9D2D0BCC688A032F54733AB7C5
+                               5FF58B296071D5D39349A531E41F0BA9
+                               893A1722B6102740BC5FE394A49363B9
+                               6A626AB43FD6A288CD9B23F7255279F8
+
+Set 2, vector# 99:
+                         key = 63636363636363636363636363636363
+                               63636363636363636363636363636363
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CF0E05248AAD82F1C8CD2095ED2DA333
+                               BCB02E3AD8797377AE1F1B4D6DDB86E6
+                               2A59791CB553550E0492FAB42C7A2C42
+                               3157C5092D2DD37D46589F17FBD86584
+            stream[192..255] = 9E946626F1EAAEDA42E52422B4A84D91
+                               4122EEE5736BCD12061C77DF5B0122B5
+                               1784E946B4E93470170ACDD7E2779591
+                               57BCC9B9F3E11E88BC2F740AA0C10C97
+            stream[256..319] = FF22D8196AB3DF662210D12D0FE79255
+                               6DCD39611C07F089979CF7D693A30CA3
+                               5B795B7F6D64931916E717C8BFB92114
+                               DB75118BDB51D142CE8133415C6B3456
+            stream[448..511] = 971F007EFE17662D95F47F4F28266516
+                               B22A1E50755EEF19149DE3A3121F5FEC
+                               E0D9DFE7A055026CA44193542D7687EC
+                               695B97769BF02F92C1EF3D904A8010C6
+                  xor-digest = D1C4878BEFCE48888A43C6DDE7CC8163
+                               C8D54A4CA36748C74721C7B6E1649A31
+                               4B5B7A4BD43E7C3D2A22F0C8446C7892
+                               90D54D421D37CB16400E59CC86215CC8
+
+Set 2, vector#108:
+                         key = 6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C
+                               6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 54F122FC8ECFB176E7F4CF172B2D78B6
+                               54BC11ECF0010D2AEB9F899130F4AC2A
+                               38EBC15C8831D591E6675DC1CE7A471C
+                               4B869FE83CBF37AC70BAAE5D4AC607F9
+            stream[192..255] = 518F298A6008532EEFECB3DCF72103BD
+                               5E3F84FEB6EA2311E8C19A2E93A9C3C3
+                               BB1DA7DBA78D5618D1C4FA5B0B202728
+                               62645A361E55494D66C9359E41E5809B
+            stream[256..319] = BAFFFC9206D1D813F3E2768F08D78B2A
+                               89BB20CCD92E7F13FDD816DD4E4963C2
+                               C5FC2570CBB8BB5C70848B73001F508F
+                               47AF179528200F51CDC6E4854EAA63C3
+            stream[448..511] = 844B1D15FBFD1264169279ACD525611F
+                               A39C7BB41F1E7A1C09090625F7926E51
+                               23A4CD7FE1A3F37ADC67AC437BF0A5AE
+                               FFFC6FB0ABF39D9908145004AA5B958D
+                  xor-digest = EC67596C9DEF4012A2D543842829306A
+                               4285A3B8038818F265065DC848BD80FE
+                               C27C2F66A57B27F7FA8AC912001EC954
+                               05BC6E93D7E555C59060F5D2E294D103
+
+Set 2, vector#117:
+                         key = 75757575757575757575757575757575
+                               75757575757575757575757575757575
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 91D2772A18995DB3C0801DD3740F4466
+                               F9535E5BECB93DDCA0E94D19C0B57BDD
+                               0FFBA9DAF0B11D55C852927F8BA560EC
+                               4999E25848D08FCA7275E7E8571A5F1C
+            stream[192..255] = 72E64FF10CA9F07CC493715724DA7610
+                               9E4358E8B0CAE451348B784A162DF036
+                               AB9796724D17FDBF356031D080A6631C
+                               D1E8D217B041AD2EDF427972653206B2
+            stream[256..319] = 4054F770C93FCAB533143FFCA8E4C0F3
+                               344956C29D10374E502C2EDD177ECE5E
+                               6625BAD9630DAD57976216CD69865058
+                               130B132FEC1AB0C350DF4DACE4C7724A
+            stream[448..511] = 40B4A4DD63F7B6E932482D0E6F5BBB90
+                               E402466550B518A177CD05985D238827
+                               BD92EE7EC22C274F19E682F85ABDAD95
+                               D0EBB3DB6C6134408353C8B0472C9A1D
+                  xor-digest = 9A6C893F2108D13A29373DEDA65386C4
+                               AC356BDDD4A3178952F9126E322B7AE6
+                               83C94F1A131CBEAFF26549D9F84CF04A
+                               1241FA374B055B0ADE7E49E8EC669E65
+
+Set 2, vector#126:
+                         key = 7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E
+                               7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 87A7773A3514EB7F882F2C491E90DCF3
+                               059C5CC575D806B9029CCE3FA45A246E
+                               0EBD3AB2F2E324FE36ADC3B56AE2F7EF
+                               C710AA964CB87381386C2A88B1308035
+            stream[192..255] = 415D6F59DD004944D4E45FECC6F1F06E
+                               20BEB18D9C84187C347F43B17E0924F1
+                               2348F825E106E57A00258CE4415294D9
+                               4323A9812D8A71359CEC1001BAA0D567
+            stream[256..319] = 8E20F0D03F37EF4B2C5EE12B5F81F7C5
+                               32D62E779FA0D2D08F8ABB6B0183A4DA
+                               4EE0329215F261D953150B9AB9FCBE2F
+                               568AAE361EAA8636ECC01A63F007977F
+            stream[448..511] = E7C44F44E06321A20E25F73E2069757C
+                               90499DB7E60025CF6D2D445E53A665F3
+                               08EC96F6FE73C0AC90D7E4A712E18C2D
+                               3DED46DFBAFA24C4B0B329E52C525976
+                  xor-digest = 22035341489FA6EEB2A6488CA42F4043
+                               57477C3F55569A1224EC39B1019E90C8
+                               21D37D78ED4DCEAF6EA70724C3751760
+                               38CF25DE4F84BABD80424D83A310881B
+
+Set 2, vector#135:
+                         key = 87878787878787878787878787878787
+                               87878787878787878787878787878787
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CEC0C3852E3B98233EBCB975C10B1191
+                               3C69F2275EB97A1402EDF16C6FBE19BE
+                               79D65360445BCB63676E6553B609A065
+                               0155C3B22DD1975AC0F3F65063A2E16E
+            stream[192..255] = 5E12BA9DE76F9ABF061782EC1C4FBBAB
+                               3373B816DA256CAAC37914B0C161E4E4
+                               5F5ADBE444098A5B2A4CFD4251D79918
+                               987BB834BB50F0834EF4985F356B92A2
+            stream[256..319] = D89642D25DF97D149AE07EA18BA39497
+                               8935978AC34C1DF9F444986D7505DB4C
+                               7E08DB3616B84CD52E7DD7FB108C36B8
+                               B50C2573172F4D3500B6D62A9D20B82A
+            stream[448..511] = A2C17FE7371604556F796429C6BE0688
+                               8611638B310F3E9FAF484BA9EE29C16D
+                               2F842EAF33AFEC557B68D2F453569187
+                               A6F4CD204A0E7A733E81AB7CE9FCAE81
+                  xor-digest = A7C93087CA70DDFE5FA5F1F2F954320B
+                               6E3A61977A7C6AC2F033B826AB9A9957
+                               66671D2A1025CDF8E2824B2F58CB221D
+                               2A68679239D90152FF7D0D39B33FAB93
+
+Set 2, vector#144:
+                         key = 90909090909090909090909090909090
+                               90909090909090909090909090909090
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 7118889F6E46A6523BBEFCDB006B3BC6
+                               71A6D390BC7099A708D370DCD0E3D143
+                               A0334619EBD5C7DA9EF6301F29273F85
+                               2DFA3C580ED65C6E952F88A0B7FE368E
+            stream[192..255] = 31D61E133CA1AAE400CB2DBBAE93C75B
+                               445792061AA0539DA69ED0B77B970C0B
+                               482156A5DEE4082A61364BF06E692399
+                               FB9F4411FEC515291F8949B20F57229E
+            stream[256..319] = 993E815F299D4841518119BFF88F6EFB
+                               F3DB9BAE60238BDE2845DE4DBA6D79DB
+                               C9E42BA5C3C004AE4546FD86C660FFC8
+                               FD6A8A349669FFE3D9E5BDF8E50A407D
+            stream[448..511] = 0F9CEAC6BDCBB56B7E97DDC95877B2B2
+                               1274F4A6D814B5440C74D53A3FF0735D
+                               EF01B14AE4188E215CE7337C04871688
+                               7159695A241BFB9D6B489FE9E23B2AD8
+                  xor-digest = 0BD5739ED28778023E6303FD88DAABC4
+                               0FA0A211A1A5C5F230D9E67DDD9EA517
+                               FEBCDF0BDBC107291B6CF3ACD8B862B8
+                               4BF15400493A54036E97FDEBB9A1DB2C
+
+Set 2, vector#153:
+                         key = 99999999999999999999999999999999
+                               99999999999999999999999999999999
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 236ECC5AB83DB1C5CD1C5A888CFEA2DC
+                               BE99E7E515650511FF7016A0EF287ADE
+                               5A03839C4F83F05FAC3B0B24D4E3F602
+                               3251F8D9CC4530A805F8A6A912EFAB1C
+            stream[192..255] = 792823ACE2C0DDB266A118068AE295CD
+                               716E424D3B98A9DB2501A3F5DF7DC70A
+                               3BD2C6E664D5E13317D6F57B8774C903
+                               D407D2BB6014E0F971141E89569C5868
+            stream[256..319] = 2D6ECCF738FC00ECD5475EDA959A73BB
+                               304C81FA9DDE0C21592247C4098D9347
+                               1DA30294DE8C100E5B17A199F744CAC2
+                               4E33490FC7F223FD6B4923056117C6D9
+            stream[448..511] = E791A6BE7F7593788E5D627F5CDAAB59
+                               349AF2BB1DA2BA622B9824F729929098
+                               BD19DFC05D0D9454F604960C027752F9
+                               7812E53DE6AC6CD2751AB331703646AF
+                  xor-digest = B7C5CE0D2FF66533A1C948C425F33FF2
+                               DC458E7E517637596FC8FB710E2E5636
+                               DB1F14848CB12793D54ABD0856B22F3A
+                               ADFA8C33AD08B8CC5292DD76913CB105
+
+Set 2, vector#162:
+                         key = A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2
+                               A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 74490D19F13E7C6D1B25C6408E23F229
+                               8A8806402755660C4A30CD216A500BB6
+                               AE975E08EC62D08425A8A62A71B00215
+                               DE35E5178902348698528CB82296F009
+            stream[192..255] = 51A6EC18829928EE94C37A5CD030CC4C
+                               E4F7E1B3E78C3A5DF07592F45B968BEF
+                               F95B8B257DAF2B468284627AF4481FD2
+                               67BE0B164DD86721DC8C1607A0607EF0
+            stream[256..319] = 75C565D5A5A240B003273F99BEB3E4B3
+                               9C056162B626F383F3E77B5C98C0FBE9
+                               119A7C335C333E6490126AC2510CDFAA
+                               86441C72D1DD9ACBCD3FEFC0D0C794C7
+            stream[448..511] = 2D90CCF0B43239D725E3B53C31B82754
+                               246C065AD23A8D709161FC74B34E23DB
+                               B918EAFA4465125D3780BF0B5803AACA
+                               037AA0A14D977141B611A6CA2278B634
+                  xor-digest = FEFDA1A6E95920B93380CC24FAE214C5
+                               6B009ADCB176D519CA4B8538EDFC95D1
+                               6CA06B730B28A230F0085FE43CBEE2FA
+                               2EE5DCD74D66F5CBB59F256CC1ED885A
+
+Set 2, vector#171:
+                         key = ABABABABABABABABABABABABABABABAB
+                               ABABABABABABABABABABABABABABABAB
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 22E1A884ED2C67CCB2977105649B6544
+                               367858D1A730AA2FA96703FA406B337A
+                               B2159A389BEF48D8A215D870B2968E16
+                               B11571F12BEC0A07FA7D3B9790987EC7
+            stream[192..255] = 4C98DD259D03A40AF38E0ED0F37CBD74
+                               B27776E9250B8B063E52E169C7B76A15
+                               0D699278AA4124427B5EB6AFC4AD5DBF
+                               600FEAAA98A88DFF297DACA5ACB4878F
+            stream[256..319] = 5FC732A26406FF0DBC764ACB05C83484
+                               976B640E60CCD6ABFB908583ABEC3E75
+                               2878371EBB5374C9B37A63E0768AE10B
+                               D857253D940AC408EF49EDD590E806AE
+            stream[448..511] = F012E429C44D5DC03B88123855B62C0E
+                               90E06759306017B5773752973850531B
+                               C480316CBBAEDE6353AD5FB298349AA9
+                               16AC0221A4CE1E4729BFB9C230AAF9FB
+                  xor-digest = D73B872315F9052C67C4CFC5CD912DBD
+                               60DA32FD06D9C8E804968E688898200C
+                               1D979DFFCE52E1C3B3309B58D12BDBB3
+                               D3EBA2954D1587D720E004E12EB4A13B
+
+Set 2, vector#180:
+                         key = B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4
+                               B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = BEF4DD0101F80A8F880BE0613B2AAF88
+                               D2EF924014F7445ED922E9C021571909
+                               D7E6BFCAEE0724F2A9C522C4BDE4BBE9
+                               FE53FE592C0FEB80D2C7A51FB8BE9EF3
+            stream[192..255] = 6B1966D3EE460999FF09001B0ADEC484
+                               0D22CDDFF39EB0E3D5FDF74C6E7B3394
+                               A0A4271D780DE6DEE9AC58B4903EEDD2
+                               6DD14E14A4DFE506748D5DCA6DDF4C5A
+            stream[256..319] = E79D99119996FBB5163335E2F79F0502
+                               7AEA5372136E7B3C5BE1F4A673A2DC74
+                               60834B81BE6C4976C4A727C8E6046A64
+                               4CAF42EEA6A068B7E532581E9037BE9F
+            stream[448..511] = 5C4F52E0E94884C829DA1FE88EF34614
+                               9F3EE55A136EFA3B417DB63D2487DF82
+                               794E161B3153DDB2E1E4F385E1A848C7
+                               729FF5CB1CB58D5E73FAB1F2DCEEE5AD
+                  xor-digest = 2F3C231B0228C274255F3BD314ECC7F3
+                               1B9C49177009AFF2CD88F807092D77E3
+                               C74C1B9B8650F581EC7603F4D6E70955
+                               1B00C3192414C04AB0AD8B0B9BCFE988
+
+Set 2, vector#189:
+                         key = BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD
+                               BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 05AF4F98E9D526CD7912F3E8CAF45410
+                               DED6D4E331633C5621B94E7EBD15E856
+                               04AB202A553EFED55A548C7AFFCD2550
+                               60315FD50A305D8BCAC9C077229D34AC
+            stream[192..255] = 786D24EF3FBFF6883A4ECC4F40E445AF
+                               3CFD130D5B6A9CE37BEBA429AD137A82
+                               44D0586FEB16D086F533D1885A82F73C
+                               F2AD2C645591F80ED09942F0A08D898C
+            stream[256..319] = C214B6AC700164FA66DE346A27A99463
+                               C5B6C0E43A9057384BE168E163058FCB
+                               6E7DEC871C6531EFC8B8D581EF92757E
+                               219294D39E0C9C8276440BE56C3D9941
+            stream[448..511] = 22CF14F5BD70E719AFE76C53E5D611AE
+                               4C8D2171695C9CF97E2936A8BB320670
+                               015825547A508EB43D96F2EE1EE2CB34
+                               4E120F001500F8ACC3E19E30455D09D0
+                  xor-digest = FE5928C74EA21F23E29171E5AAACA20C
+                               DD8571E907763C96B99A8C11F9A1D2F5
+                               78F68A6C440996995F7AB6E69B3CCE33
+                               CF8CE0C16F54355696D47DBF82EA8D56
+
+Set 2, vector#198:
+                         key = C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6
+                               C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 75559677D7C762F6CFED942D800F2FAB
+                               AB5F3892DC2C79922E96FD34FE511C11
+                               251C8EB7C639E531CE08A8C99F62E7BC
+                               F68FBAFF99D62348FF91CCFEC2710055
+            stream[192..255] = 149806A4D862EEA81F0208D927339E5E
+                               C98E9C2A6E0DB85CC0380DED7EC5B8AC
+                               4ADAE76AEB9C7B7264C3834316209615
+                               25221D58C0174577110596FF89C8FC69
+            stream[256..319] = 137E527A0ACB8B96A9FA07890B60B78B
+                               3CDD19BF89B31FF75A814F470BF97E0E
+                               1293B750B769F5BDD750DE5025D7534C
+                               AD541A1F26C6AE9AC2FD3237C156AEBB
+            stream[448..511] = 0958243E88921B81F04AE63658E52D76
+                               CF2638495B3A6B970633A7C8F67B8CF9
+                               AC378082F72FC63BEA02881CC5B28D9D
+                               C8C261C78B2872B5EBFC82336D6E1A28
+                  xor-digest = 0084D7BED4953402FE8F7FF71A28CEC7
+                               0028A08A00EF935C06A8B3632DAD5914
+                               84E44E372A753F8E630741266C0F4218
+                               4923608103042C70ED4ECC5112B9AF6B
+
+Set 2, vector#207:
+                         key = CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF
+                               CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0C46BF67A3DBA5DCCF8E4A7A65B6FE28
+                               98C701CBF5E88F1F3DCB6B873E5CAEEF
+                               23024ADA678E1A2CA9E25AA8B476CF4F
+                               9FCBC297FF03A9B94A5A736274EA776C
+            stream[192..255] = 73B9891D1770289A67D6338909FB6282
+                               9A425B7947FC30DC52B11E398E85B1EB
+                               537E1C02898FEBFC15A9172C254CA55A
+                               AA1B56EA856F47E37E2F252D92D94ED8
+            stream[256..319] = 6522D372F90F2DAC155D48F165B6DFA4
+                               38B63B9F436FE00CC075C585297B8F90
+                               E6062358D29641FF9C28EED4A23FC53A
+                               6B5C60C2AF1E8146DB27CCF5F43BA838
+            stream[448..511] = 642541A9733946827D79BBD815C03C17
+                               6357BD6E81E9A61FFFD4A0BF6863AC71
+                               72AEFB92C1F235641BBE1457B724A6AA
+                               AF9FAC687552A778B034C4A4F8E41ADE
+                  xor-digest = 9DDBC1E7D31379D027B4F3DFD72C3668
+                               BD0BC5A97655978E79056B3D25DF3E79
+                               5D5D8BE5D1AAE877F2E7D03225CB6609
+                               6EFE11CBCB728039A243E326437CE73B
+
+Set 2, vector#216:
+                         key = D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8
+                               D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DBD4E866F4E24E7F66816CAF625BD07F
+                               1F7BDFBB81428FFEE9FBE14DF5F5F3D8
+                               A044EF53A868D989E16165A0F2B95E8D
+                               83439BB4805A125AD0CA7994AE11B852
+            stream[192..255] = 7CACC4E7B9B1957ABB22ECB9D9D67184
+                               EE7A7F4B822A1C955A69E238022AA313
+                               276C2003E27AEF1B4F94B33A6428685B
+                               F048B357EAB297B7DD98E612F054A317
+            stream[256..319] = 286B484FA80A45EE4D5300DFBE173E8C
+                               978B976BE1B6CB0D15C0324D6B70D265
+                               385B615B3EA97A55D94C47F53FF40861
+                               4460857AC9568556AE54A52546B41B5A
+            stream[448..511] = B3AD999394343F6F0BDDD0B1FAE2E3A6
+                               5BE2BF56D2B78A401D5761E2F3AF8B18
+                               A2B1089864999D9B99E5BF6959F8F802
+                               975FBF204D6159CF23F3706CAF0D9BA5
+                  xor-digest = 0957D6887501D4360C430614B67D99B5
+                               32849E2F5C69CE8A9F3F707A2B5438BD
+                               0C1237B5617FB525CC9C043A10DBB265
+                               3C3F0A353E89A19838B8F68542E09526
+
+Set 2, vector#225:
+                         key = E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1
+                               E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A6DF8DEE1EF7D1AF773AA3E9651B645A
+                               50CF101BF065F69F3E78BEF5D689B1D1
+                               D306FF41EB3E78BEB75C4200937CFE60
+                               E89E370680C519B2F64E23516ADF8062
+            stream[192..255] = AA30580A210B87727BE17EC52AAAD037
+                               3E0DD11FBFC89B37825CA4D6F9E8D433
+                               E3EA54C37D678B58CE834AFA310F6D4D
+                               06B4603F12DBF38595AC76511D0B13CF
+            stream[256..319] = 5F3E1A55116CB67BC91C8E37182EEEEC
+                               8FC9B09DAA6F418D3434BFBBFF6BFFFB
+                               F93F8A963F2F51CC487BE868F010EC0B
+                               EE17A480542A301E33B36F59BEE13D91
+            stream[448..511] = 672048756C221C12DA6178BE711B3371
+                               525A92BC9A219CABC5501B0DA4CC248B
+                               8742E8BCBD6F5A1CFE522F3DF3BED6B6
+                               5D60D1AC737ADC582C2CB9751521828B
+                  xor-digest = E7CA739E4DE0E74274E491CAA9BF5CAB
+                               3F418EBEB69509D69B2594E964759D15
+                               104F674CD44681AFECC3B4939CA0A0C9
+                               DD7AA5726653ED3FBFC833DDB0C87B42
+
+Set 2, vector#234:
+                         key = EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA
+                               EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 2479A8F2872A813D16D15F060D300237
+                               25297B812F6F3B97D74D9716E4403A5A
+                               684D2BFD1E15275470FEDADF1578277E
+                               44C6C06B8A5FCE3D0CCC5E13BF49947C
+            stream[192..255] = DB2F9B25F9523FF5C2CCCB808EFE07F3
+                               132D4B0065A563288F848E05EB45E48B
+                               D15C069C02F90B4FC10AEBF1AF4BF90E
+                               2CF7F48C8CD7A8091014131EBC21FBE8
+            stream[256..319] = 84FAF79797E25BF2CFD54E58F5C7AC1C
+                               EC170B064429EB832924CDA9C47B5174
+                               9BFEF80D96FAE36DDA65659FEA1CC06B
+                               4EA3A1601A3304AA4DDBEB62381FD4DB
+            stream[448..511] = 2C8FC8D23E7DBBC37BB0811D1BC71145
+                               BFBCDBAE19F5281CD0E6AA37419778DA
+                               64DDF68726DD7F4D78BBBFF4576C2AAD
+                               93F477A2AB2C3CA8A381F30BB944C7B0
+                  xor-digest = A6D5F0DDFC0A43491D6D0A17C095C070
+                               9EC7E9B89DB8EEA11045ACC5FF003DC9
+                               CD3318BB6F9675EEF20E15490F525066
+                               AF8380C663B60EDBAE30663C94C39892
+
+Set 2, vector#243:
+                         key = F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3
+                               F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CC3701E703946194401D1BA23AD99B5D
+                               F3F856138E142D4B9C23DC9F252A277B
+                               D62DAA33A71A0C61079AD5A20562291A
+                               B6EC92C66D7BE6A17E27D4DDB48EFD31
+            stream[192..255] = D00665FC0A4ACC78758EF25B0B0D6903
+                               D565423614409AD11E821B83F5B35D83
+                               F26F3EF9EC1766FEA9C21C09E0AE248F
+                               4BA01E48BCE09D06471593B3466703DD
+            stream[256..319] = E8B4EEE2C8BBEDBA758C1C2D0889FDDF
+                               96CDC215EF1A62FAA29A5608C852FFA1
+                               18B473C5A7319446F3ED2E8AB39A533D
+                               714325D1B14E838C9EC6E037DB0DD93C
+            stream[448..511] = 4FF3B43841B17A279002EFB07324625B
+                               7E937D480DC73F12836195110ECB4DB5
+                               CD31CA4F92F612A95E82815328DA7D5E
+                               4DCC5BB6791603EDA64C57B5A5AAA04C
+                  xor-digest = 9202B874C48D4B1A9E857E645EE8F884
+                               D971CE97923AC024ABEFB944E34550CE
+                               31712BB832F9174F86FCD369E75CA9AD
+                               85095F43A4B7F33AB641BD6912D2C59C
+
+Set 2, vector#252:
+                         key = FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC
+                               FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F374DA745A5CF93A567027609E5D3B1D
+                               5C3C8A4D15203705D978AD42279F6548
+                               51FF713F5120CC93D044EF717F5A75E4
+                               98DBEF559E5F157A8C819E213E93B3F4
+            stream[192..255] = B270F638AAB88DFF69D724F79B70CEC9
+                               175AEAA99D55485954B265B5CAB86509
+                               C810E664766A8E6C90D4BEE3A58B1815
+                               9076959FFFA2F30EEB12343E9E7778C5
+            stream[256..319] = B2CC84A1127B5333B30EC81CC14307FC
+                               418DA96336991A27DADA74FDA987B867
+                               B125C53C0E4E2889FDFEFBFB48797A22
+                               2836B2EA42793CE2BFFD568F6234B368
+            stream[448..511] = B70F4A10A1B75D499E8189C8B92AFB36
+                               4CD2D730DC8D7E183EC55A777C2445EB
+                               BA7E9CD95C8F3A206B73C422AC2E2C08
+                               15A8C6FED156FFF93B63DE512EF69725
+                  xor-digest = 467EDA43B849054EE747A532ED0D9AA4
+                               6EA1BF2B6AF19F481D6E3D55EBAA96FC
+                               6629FE65B5EC4B5EB6A155A6D60FEA32
+                               F04F8230E26390F1C8FA53D47B68FEAE
+
+Test vectors -- set 3
+=====================
+
+Set 3, vector#  0:
+                         key = 000102030405060708090A0B0C0D0E0F
+                               101112131415161718191A1B1C1D1E1F
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 7CB997D6E1B46DD7C0A9629B441C3771
+                               14D6C18F230291FA7EF0B039AEDCC9AA
+                               A4AE05BA13F3931E3F8373AA320A8BCF
+                               28E825B2084D0FA486BE52C92C3C6F14
+            stream[192..255] = FD4DC85E176D76062323B2F5B31E219B
+                               786596F3DC0A2AFD31AB48C5F911605D
+                               556399114B0779F43221FE5BDA899627
+                               BA6498C210D5AEC5FEC8733357571F77
+            stream[256..319] = F00E84A92BEA966DC8359FA63B12E8E4
+                               F5611F6C8CDD04CE9D605D770B2EAE49
+                               D6976272057CF275EB5B4CC434EA9B0B
+                               8CD9FEA22D7E919097CBB36C5D239BE6
+            stream[448..511] = 110560BCF38CC42478036CC228E9DBD7
+                               4C44863DAFC81B528AEA2893FDBAC7BB
+                               2F68CCDF566E1602623EC9AE283EA69C
+                               C032E90E409F368E28401AE6905BD4F8
+                  xor-digest = 9CCCCDF3F7D712D6E3931068138F9A9F
+                               8640478BEDFC3C7CD0802954234DD07F
+                               99F4B072D9847DEC2E16FAD0ACCB3609
+                               16243175C84A317191A98AFF5EFCEED2
+
+Set 3, vector#  9:
+                         key = 090A0B0C0D0E0F101112131415161718
+                               191A1B1C1D1E1F202122232425262728
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0889D6D9E155FC208941B945F2B15362
+                               3CE5C79122C1085FC172836FA9B06C0B
+                               50910CACF399EFC9CD9CC484786AAC8B
+                               377972E9A90D7EDD40A59FE1B942710A
+            stream[192..255] = A540BDE9860D8687A45D8CF22E00299A
+                               36BE590AC92E70BA03B8A5F2898C2D1A
+                               B9B1E5C87C4B10C9B6E08EB868AE3B10
+                               3BB95C30831B903A3A9620ED16B96210
+            stream[256..319] = 90E2A684D3960A4B1DA5DF19BF569288
+                               5A23892F2003AF2319FED9C8D37B8702
+                               7E61290E013FDF93683829DB99C177F0
+                               222EDD6A0FE3D5F7F903D3CC15C6C6DF
+            stream[448..511] = AFE7454BF77E3CE1050ABFC2E25F9B15
+                               011F33B93660EA4AB5E7BFC513F2D787
+                               27F8008ABC1E14B06C36F7750AE88C1D
+                               7AA2F6EB9F2E925CD6CBDEC5FBA3EEA8
+                  xor-digest = F1A8C58EA8459686DC5BFA2A81E80653
+                               EF6141903898D1A3C7298358A79D674B
+                               A971C106CAB035722F246D3E67D34543
+                               3E71DD374DAF73036EE55E6C0ECE5FA3
+
+Set 3, vector# 18:
+                         key = 12131415161718191A1B1C1D1E1F2021
+                               22232425262728292A2B2C2D2E2F3031
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = EB11D29C989FB09961A673D8412360B4
+                               F4E6DF0169A3CE207656A7C72D6FB8D0
+                               95CB3A7A6CECDC2E167CD35F62A00110
+                               EF09FD32B61A8B405A3F55A1313F0DFC
+            stream[192..255] = 8ED27EA005A3E298560C829380D4F1E9
+                               F0C7FD5285F04AE6FD66C94CC07C8C51
+                               EE8163B7414A52B0594C5F7F80104D95
+                               0858C9A52F3C156ADAA025C00B180429
+            stream[256..319] = 12DA63247282599F2C50B172CDB4F31B
+                               20952134800FB8BCE743BBA90E6485BA
+                               057A9C5E0989A8FDCEF1C88DD54E920F
+                               7028EB284306FE6A87B0FE063DAB9557
+            stream[448..511] = CD447E9F58BAFB77F6E02AB5A692120D
+                               EC4F7BD597DE5C54523A7944DBA6A3C8
+                               D00000D3E70F7D9292B7135A7F054812
+                               4B98680DEF6631D2D10E0E7B08F188BB
+                  xor-digest = 6EF765CB84937D5E829A1A1664EBD23C
+                               B474FEA3C5AB137F2D9B35BBE0816EDD
+                               B26EC14D74EFD0F9768C521A6FAAF122
+                               B5E34A36344FF0F0DB3CC2F2780D05E8
+
+Set 3, vector# 27:
+                         key = 1B1C1D1E1F202122232425262728292A
+                               2B2C2D2E2F303132333435363738393A
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A71D4189D1338531D3C03D00A480C8B8
+                               49C779B7E113FD8D59516164C161EAE3
+                               AEBF74542FFFDC2FF8C2666FD5AAE413
+                               19072673F958F498F8FB9743BE46863B
+            stream[192..255] = B0B3803396AFF1646369B6FAE62EDBCE
+                               5254E7C8FEE88F9EEE5D8A7B6D44ADC8
+                               B89895198E3C147FAE0C9B8325EB3501
+                               6EADF77C5D7F402CF3168448D2A59E23
+            stream[256..319] = C1CCE6956C8257947C004528F568E3CA
+                               BE9ABF891E2FC2B52D9A1E6EC97A22B1
+                               FFD1C77E50A17CB47014C9EDA1853AFC
+                               11526F6268102780ACB3E0F120398AD0
+            stream[448..511] = 765857312C8994EF6BC7259673F02E38
+                               B7E0A764FB70534190033FB1BA86D5BA
+                               3BC6851DB596970A2F60831EA1A31CAA
+                               96085680CBCFADD9C5F0330CB72AB5E2
+                  xor-digest = 30EF19DE0E750BBF6AB3FC924742CDCF
+                               62B2FE5F25983BB9777C727679CAA39B
+                               1280AB468051463E7EB287AEEFA5AD0B
+                               9C9DFCA45A3124D5F41F4B0AF5849E62
+
+Set 3, vector# 36:
+                         key = 2425262728292A2B2C2D2E2F30313233
+                               3435363738393A3B3C3D3E3F40414243
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 2B9B987B7CADACD2FA50A53A9F9F44CF
+                               4ED11B3E25FE57F1372C6D570B470AFF
+                               5FCF3BEB89D0692D873EFEBD26EAF3E1
+                               1B6892913F0CB27F3CA9BA20AF7A98F8
+            stream[192..255] = 0148F54B1D24F3D69A2086D6938898F5
+                               25BDB1B1F78C5F92BA21FCE803A52591
+                               FCEC9A1AFB0FB3B081CDB1D79D254845
+                               40EB9D624B5E113A4F143716722687ED
+            stream[256..319] = 271FF1107AA8968E0ADDA5371F40224A
+                               D8E134AF80D5ACDC9803B1B3A9819BF4
+                               8ECC3A68B303E1275FA97222F7E984EF
+                               9C73899433230FD746DA6101DE37ADA2
+            stream[448..511] = A66D3BB64C35C71BBAA3F5410F388253
+                               2B32897B1CC1AD610F3AA195CDC1EB82
+                               0262E817374384BFBE200339B284ADF4
+                               BFF6960B6A41AFA9D7C9B67B19C14C37
+                  xor-digest = 3CF10A4A8BA3E0DA3C0B63F1B913B57F
+                               BE47580DF7D90B13459A9BC98B93B014
+                               1185E910EDC0A5B37206542B17CAB8CE
+                               F050A4ED3D7097B6A0738095E4BF7A77
+
+Set 3, vector# 45:
+                         key = 2D2E2F303132333435363738393A3B3C
+                               3D3E3F404142434445464748494A4B4C
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = F32665A4C73608E133D85712D2CC9A76
+                               6D2B83311B3F44564A56A97ACC9B6492
+                               B282A2E62A435A7B7799073E010C78C9
+                               4B7B5BD1B25994D1CE31B51CBB13BE90
+            stream[192..255] = C9F24592930A0A9148486D77C1FFAAA4
+                               4E4EECB088D6AD38D73B195E576BEE56
+                               E2CDA968FEB85D19BF89391813501B02
+                               EAB39A2E78B8CC7456EE60EAC3454051
+            stream[256..319] = D8E1D09F074708379189BBFEB1E24053
+                               E0BB5980FFD0371265320C3047F0ED36
+                               A65CA8D0DDF20DC25B552E1882811C77
+                               6613DBB4297DC6C89E31529DFCD17C82
+            stream[448..511] = 8012813E7879B3E99C40821A97469BF3
+                               9D2EF3B888E3118275F47F8C78A5F7CA
+                               19A98B1817D2D7734E69C5ED43773D68
+                               FA100E2C37F40FF8E018DBA52C5C239C
+                  xor-digest = 8AFB9CD876AF4F9693FF4FF511D89957
+                               C8BB31D9DE3F21B726667681F805FFF0
+                               4B50850696D6C2E5C271D199CF49F1E6
+                               D366C7824273E99360BD5A294E415F0F
+
+Set 3, vector# 54:
+                         key = 363738393A3B3C3D3E3F404142434445
+                               464748494A4B4C4D4E4F505152535455
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = C72B0F98EE5C2D44260E929C70DBF174
+                               02C03543483178C8BC129D67FE2746E2
+                               E881F8439E2A11EBB3716ADB16207BBB
+                               91454A71C444445CE64003F0BB1F481D
+            stream[192..255] = 5590F4278E78AD19293525095C2F76E3
+                               B35A3858CB5912B62304180225BDC985
+                               ED955521436DEC441B9C742B3C5F4CBE
+                               94B99689048AF93E48472980D058807F
+            stream[256..319] = FBAB34E9F432546EC8C52750DA4D2278
+                               4C1323D4E3F4E9B63E65A7E3C8B2637B
+                               AA5D0A3B897113F68C63CCB78B5AB40D
+                               0A0DC3EF1EB09DF5C4770B343B6B5155
+            stream[448..511] = 78B0144CDF2692F0D0F164ECC8621F5D
+                               A00C401007B82AAE7753712FD6185E9D
+                               7ADC8CFEA6D5BBC2F3EDB8BF2C77718B
+                               6A424BAFD30C30934FC645FF05704BB1
+                  xor-digest = 835B5361A9C1F88223DE7BCA09030CD4
+                               67065AAE99198645029CC0AB9B9BD579
+                               14332392ED7A433A64D95B44CE228860
+                               7E029235580276BCAE88F37418FB641C
+
+Set 3, vector# 63:
+                         key = 3F404142434445464748494A4B4C4D4E
+                               4F505152535455565758595A5B5C5D5E
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 804025A410EFFBA58647A9F4B443BFC6
+                               1CDDC30CA04DA8DAB3EC6A098A830D68
+                               2683B59B76C60C09938E67CB41385315
+                               E2504B024DB808923B0909EFC25F0927
+            stream[192..255] = 7A4661190129E3F349DA7B44DAAFC388
+                               5E4BEEAC9308844DDA45E8E06637246A
+                               0E6C8C7D94C5F710CB78CC6E0CA82870
+                               8CA77B6266B41E3ED6BAA2940F1977A5
+            stream[256..319] = A3EBC22126B6069C674DB604F8C22B54
+                               DA68FB4390617E86C4FF089344BD0DB3
+                               887B3438E8EF8207FD89B2A485C0B383
+                               22AEB69750AD054F843DCA7995BB58A9
+            stream[448..511] = BAC68211F125B57B8CE5E42E644997F5
+                               2FD4B8A7D5CBF89ED2F6B5F4D4C7FA5D
+                               0CC34212160C6BA536BB7604C184367F
+                               2E088528F3B3A0A1B20F9249711162B1
+                  xor-digest = F628E74D1EB94591694631F1B2F12234
+                               38B056789D5C2ABD8CF34D9FA7B8C304
+                               5A8C2298B7BEBB90C7CC86895693118B
+                               2A43B7E8AC7E534DA7965EA720F19180
+
+Set 3, vector# 72:
+                         key = 48494A4B4C4D4E4F5051525354555657
+                               58595A5B5C5D5E5F6061626364656667
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 40409D9AD4CFCEAEB8FF613D32B59180
+                               F5DFBBF44C1B7209AD1AD5AE94DBBF3A
+                               83EAB34D2617ABCC396880BD5F5D220F
+                               F434DD575E66CA74BA32862293113C5D
+            stream[192..255] = 42D9EDDAF89B93DAB4AA790BC9C45BAC
+                               5E94575E175C2EB1CC08BB39019E25C0
+                               9B0F4F435ACE371BD9235C61C56A362C
+                               B1A64EE58F4938D59073C5A8A1BA679A
+            stream[256..319] = E40477D1B6C901AFCC4A2C429845C7B9
+                               0DF890C317A5B9D6368672C58E0BD5B2
+                               7E42DA77BDC2BF47F9AD195F7C192B53
+                               24FEF88E6B3DD1669A068E3FCB58B203
+            stream[448..511] = 7616AA094DFFD4BCF94E03C9CCF95C31
+                               8F247AEBDE281334F8E6F46271070BC0
+                               1AC838D8FCFE18865DD30949C68052C8
+                               6E93815B4EA9480B2D0B6A5D9888E597
+                  xor-digest = 1FE60024F188CC243F7D8221D990ECE3
+                               29E89847C9BD60AF23061E9C27C4908F
+                               B00D8813E680F00665658CEB077BEFAB
+                               5DEB41D3547DD645DEDBB3BF5D7B651E
+
+Set 3, vector# 81:
+                         key = 5152535455565758595A5B5C5D5E5F60
+                               6162636465666768696A6B6C6D6E6F70
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 1B8DA47812BF2353C17C89AAA8695E9F
+                               F553BBA44087D262FA0C710B69765F12
+                               FFE190625F58DA899B56FA7AB5E0E674
+                               4CA2B073517B9577712D7155E16A874C
+            stream[192..255] = CD2BB4A6C3D7211773421014611B677C
+                               C0A8107544ABF4F914F825891E52DDDD
+                               76EFDBEE614573FF9674EBC154A3283B
+                               439ED8197E1EE0705955A8B6C8AFF8BD
+            stream[256..319] = A626C40CD2C48AAB016C29020096DE28
+                               F03842E785BCE9D9E385D0B13B63F82D
+                               789588FFAB07B8CC0FFC62AA86D37CAE
+                               5CF8FD43B575F9F4D6E07465B700D47B
+            stream[448..511] = 16A3C84858207E141022D228079D6067
+                               2784EBB56E3B84F7DF07EFC69060E27C
+                               D1311E51F5893AE6BFF80D34464DC60F
+                               61985F8F88164CCA69EFAE568BEB546F
+                  xor-digest = A24EEDA74185884C5B287663C3F5F031
+                               2743CCAC657C702A29E0C20BDDE304AE
+                               A54A9292B447039D50479B6CE475115B
+                               8791854540E15D642859D10561AEF26A
+
+Set 3, vector# 90:
+                         key = 5A5B5C5D5E5F60616263646566676869
+                               6A6B6C6D6E6F70717273747576777879
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3F7261A3A4691A73441762D113EB7817
+                               4C515A96C5C93C514EE559E7F78A633A
+                               01F0891910D44A7EBB18768E3B912488
+                               6069CB5304E79ACA89F62EFEC4EAC11A
+            stream[192..255] = 5F11904F72123CE29D1D883AE5CD2A89
+                               2AB26C9167A24A57D6F64BDE3A8E1A93
+                               7C5347C585226DB44B6252AEBF3CCAAF
+                               2D5E60C56FBBA6068B35AA6A61C84A44
+            stream[256..319] = CD6C5B784854E0121933E77C700D9C1D
+                               7452999F859798499A339F78FCF84615
+                               A3190A2F558CC529E636922A1B75A3A1
+                               AF280FB3F486303093DC1564EA0B6D3F
+            stream[448..511] = 61B8163A84540727204F0B18D9CAED3F
+                               B5FA87089FF4E721D2EC34D21C59B93F
+                               95297725780DF04A5FE405FEBAE80AB9
+                               B8307B9A74774E76063F9218CE243002
+                  xor-digest = 944EF8435F32FF2A67CDA5FBDFE02C81
+                               0997D9C8192633A193D6122A051B801C
+                               15555BDF410917B9E5DB86F4DE8B9874
+                               3E9F92F903543AD14087F4E13A915DE0
+
+Set 3, vector# 99:
+                         key = 636465666768696A6B6C6D6E6F707172
+                               737475767778797A7B7C7D7E7F808182
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 71BA7454CF7F6CC93C89EB22B9D608EA
+                               0FACBB4358DD007421DAC1E65EE99161
+                               C542DF02611AF497B2D53748D0129C0F
+                               5B9704C8A6017507EEFB26B6287662CB
+            stream[192..255] = 92D5D35B2E02D204E68C1AD6C018DBA6
+                               7A1C90F563AEFC3D031FD3F7D4F5E2F4
+                               C47D326A9C49A0B2ADF03D9E7E429AA3
+                               ABF253E623BFB9EB040B5F5CF1FF68DF
+            stream[256..319] = D6C22BEA96DF94CE9D5D34E6231CE4F9
+                               A2D2F6097540F9A9160DE139E2E80D0E
+                               5AFE08131FE10F0DD7367E43D314D7F2
+                               2321B5F89DC64F286576BA599A58F48C
+            stream[448..511] = 43DC3ACAE02DBF68AB5B65A81630474C
+                               639FC4DD36FBED518B6471F7C3E70FDE
+                               23CF1E128B51538DE0D5A47F20A554F2
+                               09668FE28B0C4884888FAC438960CE7F
+                  xor-digest = 7B0EF650F3847E3EB15EA1CB64EE7189
+                               AA5B04F527661C00F4603E48CBE59F7F
+                               48498D80F6C5ED956ABBF97E6910EFB8
+                               341C7BC2E81E66A4B9474BE420DFA5A6
+
+Set 3, vector#108:
+                         key = 6C6D6E6F707172737475767778797A7B
+                               7C7D7E7F808182838485868788898A8B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3C4CBA573D803324D099BE1F436F944F
+                               EE506CE77EBC01FAF0060B76FA5D2005
+                               05CE94AA15F3C4B1E0194264CF13878E
+                               FD36288EA4C2ECBEEB76828EB460AED7
+            stream[192..255] = FFA464FA648309E295314DEF7169DC60
+                               F63C90AEE9F27B534E11D25AEC454823
+                               DF6BD39C1F9CB46276C630C129536506
+                               187251D638D3867E96A84BD570F78461
+            stream[256..319] = 6BE88BD0D2257CF7EBF7100B442F68C1
+                               ACB94B6F8991C1461D318BB80E59A6EB
+                               8009DFF46B8E339A0CD4FB285ED1E433
+                               5FDBD65537D9CF1FBB0F9F10E17952D0
+            stream[448..511] = 909997D084DE4F6C910D57DB89E1EB56
+                               AB3F9974E3DB5935D59917CACCAA31CC
+                               E009324E52334BDD6CA971AF49982122
+                               B195229DF0BFE2C508E981D303061B2A
+                  xor-digest = 8B2B49D564662BFB29A9F4E1A3DC7664
+                               774D41168EA27505A2A518DD94C2A507
+                               0D28E1E69DA2F084DAB024E8EE2D022D
+                               BC73071B8559BE2FCBC2AE3605696482
+
+Set 3, vector#117:
+                         key = 75767778797A7B7C7D7E7F8081828384
+                               85868788898A8B8C8D8E8F9091929394
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 6EE8B7E51036B951205064348C222881
+                               624E9FF59DFED40AC6CDEA0945A39E72
+                               AD05FA929F7AB69BE8234567734F8F96
+                               D74DE6038A463BD8FB86224F5CEA0D45
+            stream[192..255] = DD9CD1757A95E616E99590E76620E9DF
+                               0BF811F73B70C5CE982FC9CECEFFC6BA
+                               F7DCA30517A9BDF44515262ACF297AA2
+                               2CAC3F216C12A9D0D6912578DC672D18
+            stream[256..319] = 0B7DE245062DCC9B1D8A945CD9A04938
+                               EB9BB258B4B7BCC263487B3599B1C6BE
+                               7FDE752D65345F00DF90896DF53244A5
+                               AB111134B36A99E2D2200B4D2003A520
+            stream[448..511] = 2566E8427BBAC7F0A35C6E4BCDD326C9
+                               D7164A9E1F767038A09A75B5076E05AD
+                               C51F008E9E3184FA4DC6E4764B381944
+                               BCB96B57FCE2339A01501BDEED46F8E3
+                  xor-digest = CC16803D36710AFDB1DEBC653DA7DD12
+                               F45B02349B87C3006DDCAC1635956846
+                               E4D7D6064D19012724BBF836A7DB7A3E
+                               3C12E6288F546EF316406D9C5E844BAC
+
+Set 3, vector#126:
+                         key = 7E7F808182838485868788898A8B8C8D
+                               8E8F909192939495969798999A9B9C9D
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 4F4169DF51C9865A20D7E79DEFF7B121
+                               BD61F4C79AFEDD0598F55E9D9A3615AD
+                               19292095DDD83904B3683722A3337BF3
+                               4E98F63EB19927155E176F2E8D5560B3
+            stream[192..255] = CF82F8F2A46A898915B3E371BE941811
+                               682A8A0A20837AF471B5CAA4B4FB01E7
+                               F2B0CA9ED3BA70BE305587F1ED995946
+                               223032F94BB2ED7D418C95F202887E6B
+            stream[256..319] = 219C121E08F7458BD657AC4131221C78
+                               43DB5817B17344922C54A002F3F67574
+                               BEE5F7FFC7EFC5615444B51FDDEE8B71
+                               981FBFF658D2504BB53C13D0342258E4
+            stream[448..511] = 55C2A93F43F260EABBC1A173AAF80A95
+                               A7EA74CCEF6E29C52957AB2247126336
+                               CEA5BD0D08F873AAF733B3A11885F04C
+                               58542B4C8ED3E1BB7F7918C4E92926FB
+                  xor-digest = F69FE6EFBB4A6E65B517445069859EAC
+                               A9C19FCB9C1771E75266E5B4C39019DB
+                               E959AD97F2B8D7F1688FD0AC04AA7C2E
+                               602F28A63DEAA49A7BE1422B47CFBE00
+
+Set 3, vector#135:
+                         key = 8788898A8B8C8D8E8F90919293949596
+                               9798999A9B9C9D9E9FA0A1A2A3A4A5A6
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 3305344A71266B450B2CDEB049A048D2
+                               6171B39A88C25CFC0821E4F4EFE378B0
+                               702DA31652B5E1BAD9FF4C19C20BF329
+                               639D5942DD2209DB1D1474B6A7B41B76
+            stream[192..255] = BBD9714BF2C343B11DD7943DD8CDA8B4
+                               C6A913F1DBE21A0582B3FCFDE91B61A9
+                               8863AAC17D07D8F98AE8E71BA5636251
+                               49FAB3EA775D3C7735BFC732C3C42571
+            stream[256..319] = 473F161607321838FEB9359B0006068F
+                               9D88B1A073DA14E60AAF1501F3A27350
+                               53E3FCC794893257CC3C1D4E1E3CF609
+                               975E865CA46C892823C838822AF0CD2B
+            stream[448..511] = 89F37A53F18778084307D0BB71E5712D
+                               32F0F3B7C2201D01D892F6BF6068E4B5
+                               394995CE6BFACF08587ADA39CC647DAB
+                               9B12F5505055F372FDC4607F0355DBAF
+                  xor-digest = C9E7E4A4D6782C02AAC4F47AF1D142AF
+                               FAE569B755E880C6B8A5773EFC0E63D2
+                               3D7A113738CDB1A0544175861401149C
+                               753D723CC1EF515A9323DDE4B4A765C8
+
+Set 3, vector#144:
+                         key = 909192939495969798999A9B9C9D9E9F
+                               A0A1A2A3A4A5A6A7A8A9AAABACADAEAF
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = B7954C45CF301CCAED3F1E7E77DCE45F
+                               2D41B3B1C1F28F0308B8AB4293B64A60
+                               AA7936DDF062613DC1C454033D2A40A5
+                               E99BD975A26185A7F419E7B337028FAC
+            stream[192..255] = 27AF957AC6C514514C24664AA0C9C23D
+                               B1EE30950177389876FE4FF2E1739912
+                               A09E20A2098751049C8925334960A324
+                               5ABB50F3D333587B67F153DB145B5F6C
+            stream[256..319] = D94FAF9FCB753E992B898178373A36D6
+                               23C6BE2420AC2EA848130073F086164C
+                               9B4E69B024991FFA8FAE94E3C2FB16F9
+                               D747320A748DE9FAE4FE9E6A7E7D5659
+            stream[448..511] = F664AFD3EDC0FAE88016C8A028E98D34
+                               A27843372C6BF8F51C7B49B94A11274A
+                               6A161D776E6C1FF05358F28426C3579E
+                               053B4137F8C4CAE07B994B80DA06DA27
+                  xor-digest = 521594487B583F5F71DA10E2316187F2
+                               2A4885A69D522F82F7FD0D5F93F69B2A
+                               060EB60965AC010BC489B401F02C26E4
+                               FE3F82B83C964B4DB4E0E6BC2CE4B865
+
+Set 3, vector#153:
+                         key = 999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8
+                               A9AAABACADAEAFB0B1B2B3B4B5B6B7B8
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = A5E320FF65811FF5E8934F3AC73B3733
+                               77D3AC52446F64646946BFB8F6DEFE3A
+                               04E859DCCD9F421D2DF541F588B9C204
+                               A9846C7AA1C017D637D7C5E244602105
+            stream[192..255] = BB16A9BDCA0D4BCA589A34F9278AE55D
+                               6A7711EC87563C9F394638041CBB0E40
+                               4CD2149218D501D3B62421CBF81C6576
+                               FA659C2878839FCD6C8DD1BA38F46E6B
+            stream[256..319] = 58B4004C53EE64CD45BC4A1F11F700AF
+                               0EA5ED86C4BBC145C8F588B7F708427C
+                               D2292D76329E4DB1F289DADA687B7784
+                               DABCCD29B8C464CE021856FD06554F76
+            stream[448..511] = 1113D37AB2964AAE6586AEE1B060F0C1
+                               02EB3AF048A59CB709792C9080183CFD
+                               2A1A47277F413F1219B5AAD7C8BC8079
+                               246BD1D6F98C11997E4ED0F68E165D9C
+                  xor-digest = 512F4852425DBF91234DA31986732CC3
+                               1F9649A1965E22E18CF38979EE6D92B0
+                               83333422A92F841C25F827782FD7BDB2
+                               8F4B40AD5EE53C37192651A86F03A17E
+
+Set 3, vector#162:
+                         key = A2A3A4A5A6A7A8A9AAABACADAEAFB0B1
+                               B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 96328CAA099502092359F397972568F8
+                               EE2FF1C4305EA06FFD8CC125CB10BE85
+                               65EA30B621437AD4CF9CE731185720F2
+                               0CFE17DD45E6361A8212EECB346D391F
+            stream[192..255] = 74F26B7A37D673DA0B78B38938C5C1EA
+                               2AC666612468F63B540EE7B17548F8BF
+                               60A9845BECCD7222620FDF7BE904FE24
+                               7D2B7EA749C9590133CD6A218F6EF624
+            stream[256..319] = 8F8AA7A4C64C3AEC5E85581C53E3FA64
+                               22CEB927E370C7B0F98F038E7ACF4D05
+                               B54430D91B0A2CDC001BFDDDCD0081AF
+                               35B67E5BEE6B8E113F36E3B23CE29F57
+            stream[448..511] = 53E20B4B90B2DDAB40DC30643AA5F539
+                               70ADB65DD0B64CECF3D3B4C0567DC818
+                               0362FE9CDF920526C59725AE861940A8
+                               A32C35382571F2FF20E7FBC504E1DF9D
+                  xor-digest = 8C7C45F50A151D551E9EC81EDFDD5B2F
+                               E676E14253FF38EBEA12395040643211
+                               3254B0B7298AF77F8F9F4203B971EBC9
+                               B9850152A96C97BD4FA7BE8592670903
+
+Set 3, vector#171:
+                         key = ABACADAEAFB0B1B2B3B4B5B6B7B8B9BA
+                               BBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CA
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E8DBC8E5D18C5BB2B152A6AE9487AF35
+                               E2044F30EE8189659043923E579C70CD
+                               4A5590968600AAB0F021F7AF283D61B4
+                               13C739DCFC22632E1F6CD553D4F21976
+            stream[192..255] = 8675941731B385016430C9A157007EBB
+                               E9BD8BBBEC44081C1F5E73C7E783AE90
+                               1A7F56A20E5DECD1E94E1C92A07CD2B9
+                               91619BC3358AB812D58E0B98EA288D03
+            stream[256..319] = 8D09462E5B1154175513CE7FAE1AAE89
+                               EA2AFDFDF1B39D69FDF60B1954BF81E1
+                               62F29468E07C251E2D174E9CE924A5F4
+                               8A470D1808C68ECE534CC08204C5A2E6
+            stream[448..511] = 60C5FD4C1831F0EFD70EFF86A5D38D96
+                               2C402453561D0021A51F07D40A7D3B8A
+                               DF455CE484E89437DFADC52A52741B80
+                               ED0EFA9AE4FC39659F8300AE9292B9CE
+                  xor-digest = 12E57044A8E7F02EBF6912BB73836FFB
+                               C4A2F47AE1B824AC97C1237B1B14DEFF
+                               12B5B87DF14A8B5B6C85C0481BD69DDB
+                               FD76FA307F4C1F7D21E60C0BCFECD3E5
+
+Set 3, vector#180:
+                         key = B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3
+                               C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 540980C2A3794C04B93696B90E48999D
+                               ED8E1D3F4720918C80C95B9AC0E911F4
+                               6593C4A920AB291D98891374EF286286
+                               2386B5FE17654278EC413AAFF1C384DC
+            stream[192..255] = F3E036D7620669F851A1B58BCE57B079
+                               F5D75829EDA4E68C36F086CBF2E5DD78
+                               F7F30C1AD9E4CB3C01B7F2FBF53A8AFE
+                               957786B2D3E9CCFE7D6FB24397803BC0
+            stream[256..319] = 1AADB95F07E6268BD82ECF3453DB5014
+                               9745CCEEA9F1887B5F257594ABBFFF43
+                               C3187BD9A9FFBCCACEBD7A21FF90D18B
+                               57FCBAA64B8FECB56D5A7FE05BF03E3E
+            stream[448..511] = 4170D41CAC2A7AA5A3C9228BF386B9C5
+                               57795DB5D1AE547A31C553F55DE02E6E
+                               B69D76A984F4F1D84F29D5CB98190C01
+                               441DEEFABDBFE405F22FFDE734D9497A
+                  xor-digest = CE103B99AA95B51D2D6CC54A15833E34
+                               A11778F5E05BB7AB61505D473228069F
+                               CB40015BCFDD3E1D0D5E1F832791C8DD
+                               3184273D1B4C67D800EF5FF004660440
+
+Set 3, vector#189:
+                         key = BDBEBFC0C1C2C3C4C5C6C7C8C9CACBCC
+                               CDCECFD0D1D2D3D4D5D6D7D8D9DADBDC
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = CA30678AC97B4591E287FF8B5E28A838
+                               611D654A4EC592328039E3A1DFE90FAB
+                               BA5A37133E821E0960520EEC850B6962
+                               B0378E77770681ACC0929D16DD260925
+            stream[192..255] = 79FD1893EBF30CC2CA9C5AE92B0C063D
+                               894EAE4BD50BF462420081D1CAC57A5B
+                               AA92E73D3B3CEA147E1F7127AE1F6FA8
+                               E9B302A068F26157C904E0AA7B7A072F
+            stream[256..319] = 6880FCE56677345CF1CFB2D38F890C15
+                               FE33D377922AE43348F5590B84426EC9
+                               0DC2A3863136790EBB7BD9493D2F0808
+                               CA9287CF95AAF366A11D6E7A556FDB02
+            stream[448..511] = F385299A7038DA8A90058C510727F3E4
+                               524A2D95D217A1C199552753F253D45D
+                               81DA40431910DD54B619A15C5C302411
+                               613D28D53493AD836251F0047FB911DC
+                  xor-digest = F3D10E261AC596959B4AACBCF335D043
+                               FFF65E2651F046D300C19510E1677F1D
+                               45F287DFB8C17055A012C234B6EB04C5
+                               76ED2EDE12DFFE6EBA4A39A64DDC573A
+
+Set 3, vector#198:
+                         key = C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5
+                               D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = D5EC301FD496586D54D9B21FA23DECB2
+                               B25DCC0784BF77DE84898AF96023647B
+                               F1618234A239F63FBF3478FD6EB79299
+                               66BA9B670C64118444C95D31405873C9
+            stream[192..255] = D455D37F435FD0FDD6E1EDF8BAC28D2E
+                               DAF587F938C49A5F58C32CE8D5B8A4EB
+                               884B016E54277300D461FA21512E7695
+                               D2D7489A4560FC7A72A510219DF1C5C4
+            stream[256..319] = A7B93D8B7787B6C8F80EDCE72D4D644F
+                               0C6400C3AD0443FDD19C3F3675083F4C
+                               E5ED87032B1813DDFF758854C8D889A4
+                               6FDC61C210058DB72D838A0913D80611
+            stream[448..511] = 94232F4284F46DD2E7933F9635C26C48
+                               6CB935031095777F59BDAECC4FDB4109
+                               9037C38C91620586DE93B66EC7376502
+                               6853B7390CA516B694583447DD863310
+                  xor-digest = 8596C088FA66361FD90A2132CE33FD52
+                               34910610DB006D223B0574F21BF1CD4E
+                               C282C67B24AF6DB0DB70BAFF65D5D8D2
+                               1C3955D466EA2B49C5E8EB7E07475919
+
+Set 3, vector#207:
+                         key = CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE
+                               DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = DBA2DF9ACC53C3EDBB566C28F689D7AA
+                               EF631CB44EA91610A94685FBD862C9D9
+                               BFCF512BCECF36E035E2E577F6BF6EF9
+                               E4B0E7623E0DB23B10055677C7B9F857
+            stream[192..255] = 8C78C9714577E497E3CDFE3ADE19F03F
+                               D2DAA3211C1E9E5D9F21FD1ED696354A
+                               B7552BFC7FC675FAFE7A739F6E60A839
+                               547F8F15BA5EC6F75BB05606BBF209CC
+            stream[256..319] = B23F187B1BFB5A728BDBD78B75C3265B
+                               B04C6B350A4DA4EB021D6191263F052B
+                               CAE73E5776002FF05DEC3D341AA20D2C
+                               FA523E6B92329A979BE06CF4F848A1B5
+            stream[448..511] = 7E2ADEA91939388D36B3F97DC87C2A86
+                               BDE7BB4884C40D8A202964ECC7440987
+                               1C64B03EAD0F46A3A1CD2CB935DCCD67
+                               0B43292D5B852B7A1B3D1F853EF22EC7
+                  xor-digest = 1AC1E42C2DF9858537D0A1BE3B2AC094
+                               54136E53AE56B006395969C7F999B2E2
+                               DE1DAE62740FF339DFC8769F67AEF352
+                               C4726B4AD4BAAEE56AB8C55FACE34860
+
+Set 3, vector#216:
+                         key = D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7
+                               E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = BB00F8ECA9A10D2B137257E86B455DBD
+                               F9A6A861F19533E38C3C9F54195AB803
+                               171D35043FC9C4204AFC9A8E72EDA4CD
+                               60220B2EDDEBD5482D7833979C15B685
+            stream[192..255] = 6CCE94C2BEBFD223AFB7AF1110F0F6C4
+                               01AFC533BABD84F8C4A54E8A239A194B
+                               B56E0CAFDCC59B9B5103471DCEB9F706
+                               7801D79530B7CF40F2DEC73A169C7481
+            stream[256..319] = 5144745E042B76A6B62E78C92FFC1C0E
+                               E59979CE4B2E4B2CAFFDFCC5E75510A9
+                               201E8A97A6A1729E35CA81D8645FC118
+                               177DA5FACA0293B972AC0957C43BB1FD
+            stream[448..511] = DCF9B6116FA5EB9CFDBFC8C97EFD89B5
+                               268C0D529141FC3C8262B8BE38E94973
+                               A21919D498FCC3896B0FB4CEB24D9E2A
+                               F728003C36838638888FFF1D0D526B37
+                  xor-digest = 99EF8A7D0B8D08E976EFBAE56F7CAA91
+                               B1FFC7428EA56B7A697AA3B621AA8DBD
+                               52681C7A9A415049AFB6B7D8AABAD024
+                               0F9C3112092816F4C69D36B1300ED3E6
+
+Set 3, vector#225:
+                         key = E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0
+                               F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF00
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = E3DAA6E498609DDC5A31BC0B6ACC880B
+                               695097D2CE2D1FD162C7802DC0D00BE3
+                               C0126CF947CEDBA7833421D70A914BD6
+                               C33B0A77BE8BA10879D664F054C29302
+            stream[192..255] = 0015EFCCDC554D042531FD570C6B26D9
+                               059F4F4DA675BCD12C038E4A8D16737B
+                               AAB0D7992340F4EE4324959E96930934
+                               21234D41F56A995C928F82944B46BB19
+            stream[256..319] = 8CE7098F4C64DF2E8A170DA3D02CD99E
+                               0169B99A261D1072FA116ED39244EDBE
+                               73EB9F1CDCF8CCDAA9E94C0DA9C6EDC5
+                               426751AB8300836435BC6F727F793281
+            stream[448..511] = ADF85AF30894BD0207DB4BF72D9DBAC9
+                               144EF6B24E515D96475897EADE40A92C
+                               79B818499B8CC328859561D79D727423
+                               BA81055F3387608E56173AA27D286924
+                  xor-digest = F47ABED85910334919B5868D4531FC15
+                               24D61CB16C23920750C73E2B08A4B5C8
+                               C621482F6D9F01EB59763C5F89AC1514
+                               F6CA4C40216D6385F304E9514B014C02
+
+Set 3, vector#234:
+                         key = EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9
+                               FAFBFCFDFEFF00010203040506070809
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 4728A29A2F2BD276FDE176CF4A38BE65
+                               B84BDD41F065DAFEA8302334CEF92A5A
+                               306EF904DADFE92E3E975EF9EEC9B3C8
+                               4AFC167545A0CFCCB6B1CA688967D8EE
+            stream[192..255] = 734153A78089B6E6EC0F520D39BC3FAA
+                               E1DBAD30CBDA32395E51E500CE4E118E
+                               23BC8CFDB08D443F1932EDEC52CDF3E2
+                               1D021DB791A56A7C16FDA02912FE744C
+            stream[256..319] = C511914A4BD9B29488B7FB1E62DBF905
+                               01C0D85C5A238448065C188F0A4134CF
+                               6A1FE1DAE57DB8BDF89FBF7FA66F3E32
+                               14CC9658DB292E4562A1761B9EA77570
+            stream[448..511] = 946944DF8E41BD585723CA1C03909E01
+                               783617D9D1129220ADAE7E5487AF4B54
+                               FF6593B37BB77AB0025C28727AE5933E
+                               E3873824E46F2209D26936FC5566B21C
+                  xor-digest = 34E04FBDE6E3DF6EE14BD179226D51B0
+                               1513510665589CB794C0C08391FA5929
+                               37B390E86BB4A72D427F58A1EFE10F6F
+                               D8A14A6F38ADE34331C8AC6AECA5DAB3
+
+Set 3, vector#243:
+                         key = F3F4F5F6F7F8F9FAFBFCFDFEFF000102
+                               030405060708090A0B0C0D0E0F101112
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 2AC7F22D838F68107877E90869F98797
+                               493171C8A5EC2E51D536A1578659DC16
+                               BB2F644C290B0F006BFE3FA0FE0CE917
+                               D32E94643848867B230270F54D0037B5
+            stream[192..255] = D21F7FE6E368989CC75E8D9080579385
+                               E31680302BA8B9B2F56984FD49B01F4A
+                               DD36AE4A28EBE23B5567BF5A539E2621
+                               1AA8588507916CCB572611C352E73E42
+            stream[256..319] = 25823586A7212D44811C75023193864D
+                               85DFA17EB7D5A34BD1CDD3260B5D53A5
+                               56EE2E2A06F84E95CC7323379FB924E9
+                               9E1A3F724F8C480A1F40B2C4A6FCD433
+            stream[448..511] = C1DA25F3B4FBF8B2917103E6274FAE81
+                               A5BF4086A161A7786BBD5A33662E48AD
+                               6EB9A944CCA57C51AE266BAF756EA506
+                               AE077AF0AD8B577A5A02F5563FEBA2DF
+                  xor-digest = 6176BC64072356BDF719676CD2ACF288
+                               CE2DC1272ED9C4685A5CBB7327669724
+                               DC8BB64BEBA04564A7879F7B9AD5A936
+                               C4BC1AA4007A0F85A5B5B945B418BC61
+
+Set 3, vector#252:
+                         key = FCFDFEFF000102030405060708090A0B
+                               0C0D0E0F101112131415161718191A1B
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 0854D9B674256934E204484C6D59668E
+                               1C94891FEAF6E08A92038E41EBA38292
+                               D19FDBF852400123237BD7DA620767D3
+                               43C2FAAEB08A394EFD1E7C1A3776B1A7
+            stream[192..255] = 4BBDDBE675E0F9D7DE0BC1B0E0C64FE4
+                               52F95ADE61D5CF2EB805894B3CC3285E
+                               6C6AAB72DAFF826D945B05FC4D4A6BF9
+                               37B352262AC12B7E6F92D5FBC4ABDA05
+            stream[256..319] = 7BD11CF4273EA16E01154EF9615B88D9
+                               C52535D2F0C7FD394D94AA7EE542B448
+                               9A046F2625011EE75F874641D1C5A709
+                               B7FD1DDDCCB2A6F1A47B65361A9B0D6F
+            stream[448..511] = 0AB902B571D11B5F2F24CDC7616143F8
+                               45E7DF2050B263D7A841DA170E17C00B
+                               4A20221D7ACCDCB0E131108D94D903FD
+                               7E2F7988445A7DB54F653186D69F3CCC
+                  xor-digest = 1266CF54E8BFFC95F1CD3C532BD8EAE3
+                               BF000577A811DA58A41AAD9164CCDEFC
+                               401C1B6BD2BDD9E992707718A9802B55
+                               33D7A8F490DF116FBCD8C85E9B580487
+
+Test vectors -- set 4
+=====================
+
+Set 4, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                               3083D6297CCF2275C81B6EC11467BA0D
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 1C43EFA7A2CA90F5E8F9A4F09D4C9077
+                               D5ABD79341FD75BB2DF9F13CA0B1CD6E
+                               065FA86938D971D8FAC8A3C34D08CA2D
+                               1BA08BE56D633951BD0338A227321CAF
+        stream[65472..65535] = 428908B703282E38E1BFDE62C6B0D8A1
+                               BD2AB1F5117C85703E9B656FDEAD2660
+                               4B7B8EAAE16423A3BFE542AB13748DC8
+                               35D81F981CD344015E0DF47BD180541A
+        stream[65536..65599] = 9D6D72F46C846D9BBF3AEEB463B9EF42
+                               F84915D664A20FB78AD94B61FEB7D63E
+                               5411A81D1E8F32BE3044E109C68B9EB5
+                               EC0BF180EF18BF3191D933F86045036B
+      stream[131008..131071] = E462CD92492726928381769FF205DC17
+                               AE7D31E1B82810F3CCB541B58C5F58D1
+                               38DB708C5F5BF07A0432868A1AA40A07
+                               601FCD1A07DE3071E8CE082833F0B02D
+                  xor-digest = CDCA2F92BF75499E49B586BDA7D9306C
+                               12F111D1A9F183A83B5A07549D5F976E
+                               815F96BD716CCAC7178282CA8BEFF4F5
+                               85DAFA9BDDDF8E6420DFDBA2573F0494
+
+Set 4, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                               3588DB2E81D4277ACD2073C6196CBF12
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 4F7D4E56036A57A303A9C7D978290216
+                               297AC26C187E4F07678EC0069C34F93E
+                               072D734DBA239D81E566D1E6DCD09B5C
+                               A132714291631C227E391EC0385A3A64
+        stream[65472..65535] = C508DDD76C070F712FABA944BCB0F5CE
+                               EB645825C520197867623ED5263E22B5
+                               6270F0A878AC7FE03145DD2BF528E1AD
+                               784086FEFAA0D82F0F3571CEEDD3341B
+        stream[65536..65599] = B10CF49FE9266BBCA007C8DB526E760E
+                               79AA4D6A3B29FE82B8698C732FBB81AD
+                               1A27B2AEB06D05F3CF17E875BC0BBAC5
+                               67762275EE650D03F62B29529F3C3E23
+      stream[131008..131071] = 42B4F20EBAFB2C792006BD163064EC7C
+                               F363DD996CDF839CCE61E739C3817B4E
+                               36D311A4C94C7918E82F5158D3A75844
+                               A5603742E33D7FC3AF018660E6B1185C
+                  xor-digest = FB3EDA7C75E0AACEDD95B625F7EEDA62
+                               3DDC94983A9B084645253C0BC72FBF9A
+                               67072228194F96C1E81004CB438D6381
+                               A5C7E9E7D134FB8B67DEF27462AD3335
+
+Set 4, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                               3A8DE03386D92C7FD22578CB1E71C417
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 23DE914D641DC0DCB4F818C687803858
+                               A6673E284F8323787756DAC9352BE031
+                               28BC6149A59785F6AADF92FC68761E8A
+                               862AEDF29E851BF5422A83EE5EABFEE3
+        stream[65472..65535] = D12E0C470A955DDAA7E851F43DA35B08
+                               15D442DBBEDEECE3ADE18FABF08B4443
+                               77ACFE9F138F8725CEA27B0F0ECCB4E2
+                               E5D6E476F88CAB4743E8E43CE2D48F4B
+        stream[65536..65599] = 26635796620003DE67406BF741B93D68
+                               318F9A23FE823B2374E8BD8008EDD7BE
+                               2F750707A3835BBA7DAC45E06537DF8E
+                               53DFCDB928EA34CC08D2841FE3E492C3
+      stream[131008..131071] = D3DFCE281FDC69F7800E765CB0B33D78
+                               8BBDC17DFD11F929295C26AB7ECF21B6
+                               7D4B4EFCC18ECDB8134175A7F198EB12
+                               F7913DAF22D73A4139D5B807C18310A9
+                  xor-digest = BB2C8E7BB894DEFD1D5A7D37C01E8EE5
+                               FD4E052CDF1DDF5FDA90C9818DE71B3E
+                               34392EC3858ADF718F463808ABF841B6
+                               90F49D35A51BE5067B162E72D0101F97
+
+Set 4, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                               3F92E5388BDE3184D72A7DD02376C91C
+                          IV = 00000000000000000000000000000000
+               stream[0..63] = 818C35D2FD72D12115F91BFD32F843E7
+                               ED4D7110D1ADF517226BE797E037AF93
+                               C190025A5E82FA0341667D68FC09E238
+                               49D5A7A9526CA142D60F71C3AEE3A106
+        stream[65472..65535] = F011E9CEE99D94BDD4484408A0FF91DE
+                               EFDC8D8C04ED2B86C51F21058E912C11
+                               F19890E174018308962F5827D2FC1E2B
+                               82BA65688C111AAB5C749D8ABAEC022C
+        stream[65536..65599] = EC2EF21014AACB6215083F784E3ED65D
+                               774124FE60188930E1A90405EAFC8F1C
+                               E75D54AA7D81400E026D799CE06EF532
+                               8002BCF5A10D43E6FB6F80A9D72634E1
+      stream[131008..131071] = 80BC6F7F6B0A7A357F770E7690D94A9D
+                               B8CBA32EA36E124FDCC66ECE8786F95C
+                               22263F09645864087FF4AF97944A226A
+                               CB63DAD316F8CFEF96504AD306C512BE
+                  xor-digest = CB8D4C35D79CCF1D741B9DA09EDA305F
+                               5FA43F9AE9D0E1F576D5C59AFB8471F9
+                               7822C6ACAA197FF01347E397C0382195
+                               865AFAF5F1690B373AA2603C39A13CC0
+
+Test vectors -- set 5
+=====================
+
+Set 5, vector#  0:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 80000000000000000000000000000000
+               stream[0..63] = 04740F92C2470701F289669A25BF9092
+                               EB4212FEACF66DAB6B1D520977945F8C
+                               6D350BF26A1CA35EB37FA53B0BA2CBF6
+                               6AC07A8C75D494B4B8281CFBAD4937BF
+            stream[192..255] = 5E47F5F506AA34E7D296C6911FCD3D43
+                               31A032269214ECEFDDB492C47A51C4B4
+                               DE9EF0A63A6EB32AF1DF1C5576A93F19
+                               02B7BB89F10D8C7CDFF9C097D3D49148
+            stream[256..319] = 015494CB3CC9BDE8A2981B25C06DD18B
+                               52FA7B94CBE24C152FC60762290329C9
+                               E58C4E5148585F417733737059E310D9
+                               309D0CEF48D2F1589994657A081BA6D7
+            stream[448..511] = 3B67C1B37D96E1076595660D61340EC8
+                               DDE8F492134270951D9D4B260C8E2254
+                               A7FE8C10DE837A617A8E261FBBF42259
+                               C636B3DEEA0F373FE7C2CA2B01EE3FC3
+                  xor-digest = A8CC89F06815EFF6A91CA276BEBA7F41
+                               75F842F85BEAE99F4335A3B85FB28394
+                               8B7EE3C659274C6B784035B94886BF9A
+                               5C1483941B20170EE3A374E39006C09B
+
+Set 5, vector#  9:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00400000000000000000000000000000
+               stream[0..63] = C25BA6DE4C87FE5360BCDEF864F3F778
+                               598A6A584325D5E6C44EEA4464D7580C
+                               9B8D42B5B3634F739D6A53D15FA41070
+                               D1DD4621BF87F53F42107618D9742FD4
+            stream[192..255] = 4A3808B0619C9D94E19F3AEA0BEF3839
+                               21D7E2BED05F1128A82D9DC010654ECF
+                               65199A645606CC44FDAE763694E6757F
+                               8FF864CBE4204D45102E465F16CAB8EC
+            stream[256..319] = 3097394E0CD0A9DAA28EA873566E42A8
+                               710C28366C2B41B6BF6687D881094676
+                               9970A5BA54D28D7BF772C4FED13A9F5C
+                               6E7AD3F6948667D6C2DF981955F73293
+            stream[448..511] = E685BC2ACD3A67791416E78699C83D31
+                               852EBCB1C1AF71B926D9161CB6D894BC
+                               8C5E85C7E30A0896369BAE50C1112D4C
+                               CC583E44A8275F44B7ED140E9721C7F8
+                  xor-digest = D9B51AAF4A9B75508FCD02443EFE2267
+                               1148C73264776B5513860BCE8547370B
+                               2BA66E82CCDB15F3DEB0F0728411B765
+                               1A098C23202745C19B045C58AB196309
+
+Set 5, vector# 18:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00002000000000000000000000000000
+               stream[0..63] = EE43BB5B79EAFB54B823DE95B71F3BD2
+                               F2A7CBB6D28E9BED590C20A2C52F9B2C
+                               74EEB9A1A48474D5DA4964EEE0BB98E4
+                               88030E213A4482BD1A8CAD4CF8A962CB
+            stream[192..255] = 150C4D68BF29DD27A2E6FFDFBD6984F4
+                               3AB56AACC08AC0C0149008F0882292EC
+                               A5359CCF4C257ADD4FC535E41D6F67CA
+                               E5210068F77A5D5F32A23B17F79EB7A5
+            stream[256..319] = FEA319287C29AB84585D4BF38DCFA71F
+                               A36253AD7F4BF58398731713614D0047
+                               F85A465C6915E05232A5FE5AE7A559EC
+                               42733403ECF6B11E4D5E8F4A8288A3E3
+            stream[448..511] = 79CE66DD3F77D40889906EAB1F671B2F
+                               98D9FBF8693C1EAFC89D19209408F3B2
+                               7CD83CB3B9F33151DD4A8D79911255FD
+                               3CCBA14918744B0ACB93A5F96AC9AB38
+                  xor-digest = E1E3F49B342F873263F585EC34969176
+                               2CC46C17FDEE0B32224BB77A8EC82A87
+                               816DC612439E998476F50E876481EE6C
+                               B32ADBCF6A5D50FA16355AF63AA30D66
+
+Set 5, vector# 27:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000010000000000000000000000000
+               stream[0..63] = FB8F4925A4F922119A6F29F8DDC2338C
+                               0AEF333B55919AF0D0D9B1DB61BA2E5E
+                               4CFB394E15F6A78E01B5C4AB043225FD
+                               9C8F50AB1BFDB16F944C2660995AA4DE
+            stream[192..255] = 87767D451D81D5B40503913508C2448B
+                               7CC093982642089843D7D9C3DA05598F
+                               7AEFC5B70ECCE327B20658D6301F4D6B
+                               E58FA5CE0525C9CE8E93FC0B387AE5C6
+            stream[256..319] = D146E4312CC11F11916ED9FF8EA8ABCD
+                               E0736DDD0A8AF3E067CDED397E429D30
+                               8F2DBF848C5C1653EA969B608CE01275
+                               53573C88DDD32937EF6F8B0864C581B4
+            stream[448..511] = CE919096A83BF3702D8899787DA7BC23
+                               43F1F10833F16E3EB467440B4921BA1D
+                               96845B6B4141E1CA85364E2D508456A0
+                               E399DD048E72685389FD7EF3F78B655F
+                  xor-digest = 00333EC3A59AD0B8FCA054A08340BF91
+                               906512917E72BED76BEFFE29FC011632
+                               082CDCB1A656FB817F968E26063279CC
+                               ABA796307912984BFC267325DB84F621
+
+Set 5, vector# 36:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000080000000000000000000000
+               stream[0..63] = 202723F8212AB20D9369C2E1EEF8553D
+                               C468854873D04FDD32641E324DCB4EE0
+                               883AC1D40D7C9C7783DF4132093724DA
+                               113B1CB12144E00509FD5D36957A4E1A
+            stream[192..255] = E6717FE0A77F9043607A1A7665716225
+                               C8D417FFE2CD7572083C7C552B79DB6F
+                               ABEBBC2D4D36AB319407982187C248F4
+                               83596AC071C0B0CED08686603B024E7B
+            stream[256..319] = 8C59D97F7A093EA2D0AB890923AE4DBD
+                               D40C33508838A3966FBA360E776670C4
+                               DEED8BC8CA57592463781550BCFD1E28
+                               818E7C33A3AEC43775ED0A984044E9D8
+            stream[448..511] = 0A3DC66754E02423C6EC1C1DD26CE11E
+                               FD70C386729C8290DF358C69087CA7DF
+                               D11F5E0D37A313F74B09F29C552CAC0A
+                               5621556828B0145A6A1D43F563AFF672
+                  xor-digest = 6673BA5866E8E96FB48FAC88D307079E
+                               77AC03692B23070EB5BB9D04FA94B9C9
+                               6C2F958E834DEB51C6ADCE432BFB9632
+                               9B3151E0A89EB72019A4522233B8FFE2
+
+Set 5, vector# 45:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000400000000000000000000
+               stream[0..63] = 95AE241C4E9B6690C319D1FD828BE454
+                               52F18F061C1B1E13AA409829E194D70C
+                               AD5BBACA2738B508A5398DF6C2552497
+                               6D143DF0405F68037C285A0E19FEC9CC
+            stream[192..255] = C0E2D5C6B614E4A498F46D5399DCE7EB
+                               7DFAFAC62794F5C39864C521B8DB574C
+                               149E35D1F0EA36EA7F24EF8FD855FDCB
+                               9CCC79F1ABB13EC33E00A9E137809C05
+            stream[256..319] = 285907400C1A86AA9942ABD7BEA8EEC8
+                               BB6AF2F9667D424C1DD56349C99FC65E
+                               8A00893AE529D7BA492089EB6B525964
+                               E9CAF15221A342C4F88697D818AC0F1A
+            stream[448..511] = 13D511737F3A092643E94E74F6C76241
+                               0007158FEF40C63B33E10360FFB3B152
+                               8BD8B33093D722BDCAC1FA99D16D1C27
+                               6E59E428601F256542BD3E7A4A135152
+                  xor-digest = 1D1352487AB5081A28DF23B1B19D5ED1
+                               192F08964E4C0F048AFA9CAA8BF17185
+                               D7B97AD6003E2FD2DCCAD492FF3FBE5A
+                               5CD7AAC627DFE7CC6D0972D423B67128
+
+Set 5, vector# 54:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000002000000000000000000
+               stream[0..63] = ECA0F29C3F5C4D62ACBD601C3042673F
+                               6F8B17C946FE8FEEEB0089059765F067
+                               5AF3E5DADF6DECDA20F72AF486E7E967
+                               40B2DBF22B57FCCDFE571B2D8989C95B
+            stream[192..255] = D2BDF6ED912478A3C53713389C9DFA5A
+                               9272D030543295E8CF6F0929F1A56041
+                               EA22BD04E0DD810F43D9D28D94254F04
+                               F73DFF3B766DB55100EFC9697FA844C7
+            stream[256..319] = C7CE1CD4D8C42FA36724A49107A78630
+                               A60E15673A42C57B609740EC8DE78EE0
+                               B48F2644DC0DD1E80FB8326DDBCC7191
+                               5E6C8DEEFCCB1FBE1456532840A89DB6
+            stream[448..511] = 337650A0B03D30C9697CE85449B0F995
+                               668FB2B73E37E1A550E07632F9F5AA3B
+                               04D61AC41F8A830299FB8F70FAA0419A
+                               42C4589D71C965DDB3A9D000667616AA
+                  xor-digest = 7A26C50BA37BD9F38281FD2DA3CC14F2
+                               E1FFEEC9D7776E87D99053B531EEF792
+                               0C0BF834EA9A0065AF38422A40A31BEF
+                               AFAA17AD565F685BD6E505C7E02FB895
+
+Set 5, vector# 63:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000010000000000000000
+               stream[0..63] = 567919917583CE03DBDA69907CBAE562
+                               107FBBABB4DFC81A3A15438C94AC0C28
+                               8CC35A91DED9A79ADF4EF2670A55699C
+                               000994EF33674B578F5D77928A43416F
+            stream[192..255] = 13D0EC5B7302C0D8AB329E7AADFC3FDE
+                               1D24A80B751948C4BCEF516D94DF7AB2
+                               2B1D9E076BBFE367CBED341B2A5A3BA2
+                               D48735F83855460F9D9953279BFC2AA8
+            stream[256..319] = 5EFFE922E2FE25410E8050A973C3FAE2
+                               EE372E9686B6E7B35294B52A579CDB43
+                               9D5CA7F1EABFEB4303DFD7DFBCC812DB
+                               9D70CD0698D1ED051E1E32C855EB39EE
+            stream[448..511] = 91A01C0EF63716515DB8B71273CA4399
+                               1654AAEF2AFD4DEF25E21A08D5385766
+                               D8C29514065FFF00B07DCB32D1A20830
+                               3C3402963EF252A4CAF5CA31A50BE591
+                  xor-digest = 9232F83FB054098FBED8474939476CEA
+                               5E9FC269E7B248E56B14F56CB396BE74
+                               C2B2203D1802D9515EEE232FD612FE21
+                               11C291A46A89D54B2E5437E643239636
+
+Set 5, vector# 72:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000080000000000000
+               stream[0..63] = 507958BFA08EB41F4D18F519E36FC476
+                               5BB8DC6CFCA36290CE9AB8B165D7AF72
+                               CBF49DCF8BA2D145D7935EDD2CD2242A
+                               7B7FCCB85B4C8625532D84B4BC602515
+            stream[192..255] = B2B06A7C3977D4A1A39892E832A32A55
+                               3EE6E52DB24DC453835893A55D0FF3A2
+                               949B8B96688237E13DBBB2D0C9038AFE
+                               8B9D18CCAF62019ACB908499D292F280
+            stream[256..319] = 1D28AADF7B262A1EEEC11D39F4325CAA
+                               6181F9FA1A6C65F3BEF4F1614B0DF599
+                               EC92E5B6B42A931352965CFFC025F68F
+                               DB2D6D0181F259F12989E5FB23ADAE8E
+            stream[448..511] = F60E3DAD5004E31F6DC89292ECF517F1
+                               CD18AF7E79E775334F4644A09346AAF0
+                               F2B4F5C1DD03555A6D27C43AE53EA7BC
+                               7167F793190071C7AB7B5330A6C6CAD0
+                  xor-digest = 5A65D44021E67626E62FE87B8547210E
+                               F736490C0D51485A8EF0E1CCBB512DC6
+                               0FC18114A29AF923EE3E85655771D6C0
+                               7CFE342A52190C540BE3409853F12065
+
+Set 5, vector# 81:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000400000000000
+               stream[0..63] = 2416B634134170CB4F67F431BC94612B
+                               5F2F72545DAED2356081C91A26554614
+                               5FF2526D8D8FC7D02D8BCDD9AE03187A
+                               9E404C360E115CE949667987AC73624F
+            stream[192..255] = 4D456233EC7E761891A56BF9F9659533
+                               22375C169D7F16DD81D8D69B12092F47
+                               09703B85AA3184827935B60C1E5987A3
+                               C4C2EDFEAD4F777B53989C469B575EB4
+            stream[256..319] = 5F9CDDCBE09CD759B346AAADA2436887
+                               0D47BD8859CB9225B61AD9F99197FB14
+                               B5D625F5DBE0955DCBAA5B874A7C89C0
+                               07BF926AEE571CCD7E20635ED4FF312C
+            stream[448..511] = 642391D8851A9BDBDCA37B9587D5D0A4
+                               877EDEC31D6EB78AA3F1E068B0ECE877
+                               D83EA29906D0C0816EDF7EC5BB417A3E
+                               F3DDAA2145CB37CEEAF8C07DDEE0AAD9
+                  xor-digest = DF93E4E01EA55D18AB8AB1A927A5B5AE
+                               9ACB871B7493DC283581262771852013
+                               EE54288580A03B3991126BE8BC20C5D2
+                               230F00D8216CFB632271750F4FD2595A
+
+Set 5, vector# 90:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000002000000000
+               stream[0..63] = 4981C83E26859DEDB32D84C7BE32830E
+                               784376A12FA6D0077D4CB47ECBA08A92
+                               C841D45D6CDAA3F1FB48C6FE747B0F67
+                               1B32C2B35BE69497737FE4B98770DEE9
+            stream[192..255] = 1FA51FFD0360615EFEB03042AE8E4210
+                               D3D38B4EF07536BAFE43C0585818F012
+                               8F8B3F8CA8DADBDF049688253066C74B
+                               01849C5BD85DCE27C0138D24E8B8B198
+            stream[256..319] = 2D8C58008EE94CFEA1EC545C26466D39
+                               D7BFD5B226E32F1270B5BD3677818B7E
+                               CFD98BDEA26488248B10418C1F854159
+                               8F42C6CC237885A1DEAC5C33F22C27CD
+            stream[448..511] = 94502058B5828AE4F4CDC0516E5B5143
+                               1F07EE1ECAD7CA266C931327BE6BF1B7
+                               A34810220CE00497D7BB9600FC524999
+                               CDEB6DDE8919B03064EB56B3766DAFCB
+                  xor-digest = 1DEDBE0B7B6099DCF285B3C30E91AA0F
+                               7859496E034A1EA1AAE3D3D13C2061C6
+                               0878E595B63D849B7DB77BE7E0C08157
+                               94232B645BE946E5D8278B14427172AD
+
+Set 5, vector# 99:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000010000000
+               stream[0..63] = B84C72BF69B601FB1804CE333C5A2C19
+                               25BC8A5877DF9E574295380611D03FD2
+                               46D2EBB58CC6E918F4DB1B1A0E39642B
+                               D6B39DC76764E18108497E4CC4394057
+            stream[192..255] = AA84DF8195B3F7564D0715517476085D
+                               1B40511A72340DFEAE5134C7BB8F39CE
+                               03E6EE15217986C7E4788453EF054027
+                               8CBF6336073092EF661C13C7EA8B4850
+            stream[256..319] = A7F0C413EE143F55C6356519AE620A9F
+                               4CEF8432C51E2677EB5D700CE333F314
+                               ACA374D86A8FD4A67BDC31C1B0DA2AB1
+                               B20E6DB91E7F85DC13E348314A4FC782
+            stream[448..511] = 3445E08F13D09A1AC09EEB65451F4504
+                               0AFFDE94F6C2667BC4D8FCBECD6C6565
+                               F09FD05EC660DD38307F856AACC95549
+                               AEBCF31B3FBE84FFB3261D7FEF7A3379
+                  xor-digest = 360199B22EB28401FB4F621E37800801
+                               FE69C809D83BE29A50FD1A476B6AAF02
+                               54B1F4B048CB6423182C390B8EDFF1FD
+                               9CE49C26727F0D68EB837C19F58F3F42
+
+Set 5, vector#108:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000080000
+               stream[0..63] = BC618F4A557E5B7CB75B3572FFC31CD8
+                               4DB96FD22E281C198DD33B5E9E419099
+                               BE30E84ED61C0EDEC04B1E16E06B40E2
+                               372E0EA1A48DC55BFBFBE3355B566AB9
+            stream[192..255] = 33372015C7E5749D98A92CC55CC22206
+                               90BEC9878D3CA0AC50765D0B4457CE50
+                               9BCE196BF0388599E692B99EA8169474
+                               546F10891A3FCE22DFF0AF9733C2A2EE
+            stream[256..319] = 382684F74B0F02F7B987D37F6BAD97F4
+                               20B4811FFC744CBB9F00C2855A609FC7
+                               7CD24D0137304B95217E25FF45AFA4CF
+                               28E4335D29DA392D26DBD341A44C082A
+            stream[448..511] = B0B2B619708435C5DB45FFADD2FE4449
+                               E603FA9785E1F521E364DEA0B127F72F
+                               6C8A956CAF2AC9ABCE9772ECC58D3E36
+                               2E758BDE3678D4F4C9804CAF11129BE4
+                  xor-digest = 80FC64E2441F6CA9C0F4C207007FD0E2
+                               5F1C0514D203A1B01A6EEFD1055CA355
+                               0174FAAD47ED0956A736A9404164ED85
+                               CBEB31F80561AAFC4ED8EDC9829D83A9
+
+Set 5, vector#117:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000400
+               stream[0..63] = 69FEF0D5DD7CFA6590821B6C12E239E3
+                               5DCDE7B218A66CF3C75ED278092A6228
+                               143EC00BC16DC2FDB8CD9DDBD802AB56
+                               A4011F6A8CF432F2D34657AB84DEFA4C
+            stream[192..255] = 312EBF427B3D22A22EE1F85D89E12AE7
+                               07160C9BBF4073E538171365290B499B
+                               8904B01801CC897FF09A520449A44D0D
+                               34622DB8477EF1E73DCF15417478FA03
+            stream[256..319] = 83CF222FDBEB77FFC6E282C1212D8D1E
+                               014865E9C1251FC07E901A41A50A3AF9
+                               F8E130394F621B739578C7E238866431
+                               10827799C75F08C47664B09B477F31A8
+            stream[448..511] = 4130A8F8015F082EE8712B6D61178CAE
+                               B1D3CF90AC2DB9F2D402F65E8395DE95
+                               DA0605E8540E553CFFBD029AD5BA8FB7
+                               5950C2FB29097E13ED4A1B1818E0D07D
+                  xor-digest = 21FA07F8AA2FBC12F5B2B14E034C2AB4
+                               54D7D8DA66EB0308D9AB024DBFA414B3
+                               38F36D188D33C71E888FFE1A6AC620CD
+                               55B33C1A146AB8FD275584589BD65606
+
+Set 5, vector#126:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000002
+               stream[0..63] = 0CF41A77C30118D0931FF3142132A627
+                               7A778D3BCF7466EFE56238B166A57043
+                               2DB3B222523330233F81836282A27B40
+                               F6823BD076D84DC3B831DD78828F0FD5
+            stream[192..255] = 38A0C28325566FBAEF5AB3D50D54F407
+                               91182DEF4FC945992AA0D62134451914
+                               F07F16E86E20DB119692966E6CD6165B
+                               79BE7CE6C45D1248F2E0432393BFA726
+            stream[256..319] = DE91DACF57B176EF6E59E485DF02A20E
+                               3A4EE5FF44B1AA3D7F36265221CC71EB
+                               FB9565AA4F269B7DBF3CB9631CCBAAA4
+                               BBBB6BFABB97E52954958D4E7A283F20
+            stream[448..511] = 8FFDC8CCBF864721D6C98E1896FA052D
+                               15141D9C3DFEB48AE91B2436C5C3D088
+                               931470CE951B66C38998F15CF23BED01
+                               F6D95D84150D482C0C289A8E5B2C7C10
+                  xor-digest = 03DA7ADC3E5931928D3FD89E1E0876AF
+                               9D4CE659175E671D6D80EEA78F241AB2
+                               86CE3C26DAE267D91DB556AE0CAA60E0
+                               2B481282E6470A7A161AC8E84C2311EB
+
+Test vectors -- set 6
+=====================
+
+Set 6, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                               3083D6297CCF2275C81B6EC11467BA0D
+                          IV = 0D74DB42A91077DE45AC137AE148AF16
+               stream[0..63] = 544B400E28A1A4D9E30A3E5BCB5C9FA5
+                               CA066389C693177C4FC721937D0DA5FC
+                               AABF39ED84E1FAD63ADD0C9A86749ED9
+                               86759F8ACD0A5AF2E17B4E3CD5831B44
+        stream[65472..65535] = 6D2242273AEDC611159912EE0EC5D023
+                               44498AB4F513AAFB96E8C240C1F13B12
+                               EFABCDAD424200A53017DA7D34E9AB86
+                               9D099D239AFB45D067BF94A92E7D1007
+        stream[65536..65599] = 403105F52BF3456E08C2C698505E2639
+                               4594A257DC6BCF7E26A9AE184CDC8952
+                               C34D29E116809C91DCEF4B0FE57D87DD
+                               9385BF387732E49E265E67BDCB138D53
+      stream[131008..131071] = 86758A037E90380C2DF4DB0A7E13A115
+                               C0F83A664D5B6270306ED5B9A445D612
+                               DD0F9300603362F2574D8E262650D539
+                               708E2FB5D2CFABD3F365E23783271D2A
+                  xor-digest = 8513C47FCA708D9B3CECFEE6BEA39154
+                               1843C72A2BB767C926EEADB4D3708537
+                               B24A36FBF20273487B312095D6C6D866
+                               C61B0E56F71029E7F71FD091D65C6CB8
+
+Set 6, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                               3588DB2E81D4277ACD2073C6196CBF12
+                          IV = 167DE44BB21980E74EB51C83EA51B81F
+               stream[0..63] = 2C832BE30736D5F5514EA4A748E30EB6
+                               57F418886DF2E25A739E13B6C1B24736
+                               96B44CC2B3A054CE4E6D9817BCE6BE97
+                               E77D0B984C0F039329ADB559266270F8
+        stream[65472..65535] = FD7637AC01D2FFBB5AA389D6E9EE4E39
+                               4E81AF774491678E7A0181B1AD063B22
+                               6CD1703ADE35B17F1A8D4E8B6E0E0138
+                               66A75498C93A19ED37DC0398B61573C3
+        stream[65536..65599] = 318AA03B81B6C5C334E80811384A07F6
+                               BB7D0AB3FBAA1ED873BA2E01F920C1EA
+                               FF35AAB02AE0D4F9612E8171BFE63755
+                               421ECDB540189C2A10027D4199E35959
+      stream[131008..131071] = 7F688C0421F127D0CF5B773AA1B27A74
+                               0ACA0254CABEE4095809FA854A06D746
+                               AA06E56EE3A6AB471F4C46B0528B5D94
+                               BBB9E3BB989E01FE459F3190E2942FF7
+                  xor-digest = 97D161DDF9E98C70E6B63BD4DA8629FA
+                               BA4ACDF112E28FA029DA508F1709E977
+                               F57F3942997822020307071636BFBEE1
+                               AC7E3D9C97717474A8092576536DD8DC
+
+Set 6, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                               3A8DE03386D92C7FD22578CB1E71C417
+                          IV = 1F86ED54BB2289F057BE258CF35AC128
+               stream[0..63] = 31B2E5B938120CA131A0635F2A471710
+                               CDCB494678339BFC7710746BBCDF2700
+                               A0286EA735766D17E9FA270C63AC1C4F
+                               405101CAAFACD6C2BC4306E37E9516C3
+        stream[65472..65535] = E5AD2ACAE7BF99837475EFEB7C8F327C
+                               55811CDE424E7A5AFE33086CAFB6A63E
+                               6607C005DFDB8DB13181CD3FF8584823
+                               F0D6EC38083DFC3C7A8140DEB47372B8
+        stream[65536..65599] = 662728BE1DA1099208BE1BDBE7E5F28E
+                               8E2F112E527D2F48E2C9AF565729524A
+                               175A37A38F5CBB1761D21E907CC62BFC
+                               B3A4ADA96EEA24624C501D237F461E93
+      stream[131008..131071] = 609AD32104EC8FB79D91299D3B3B2942
+                               3E09F451597C0BBA26FA2FE97B9B3BD8
+                               0A8907A8236E245E8BA2332C6D027F66
+                               12DDE13BF4A149A1A6CE2DFA9F8A148F
+                  xor-digest = B245B3176CE7C0690A7CFB4C61C84E06
+                               041650BD4A199986D3AC4DDD80A1C806
+                               2FD17F9EA40D25E86EAC53CA4FF8487D
+                               A4379DB9BABAE6109859D9757A992100
+
+Set 6, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                               3F92E5388BDE3184D72A7DD02376C91C
+                          IV = 288FF65DC42B92F960C72E95FC63CA31
+               stream[0..63] = 8863C707A53A4201F070ECEF33DAD759
+                               712F20660A288C80E6E9073CD850CF84
+                               C96AC6DE9F11F0BA176C395E871C42D0
+                               420FE1D3E9E23C8E9EB4DAAD6C677C50
+        stream[65472..65535] = C9B8301378C62DC67A932B81147E76AD
+                               54A93FFDE7B04E82548B6344B8F63897
+                               3FCDCCE6F69AA0A25BA0BD527EE7C613
+                               5A89C5CEAA4BC69ADE9DDE839FDB47BE
+        stream[65536..65599] = 7079E98749DF66D72B8BBB1DD7A6B7D0
+                               6094E8723BB74D38A7223B2557B8BE25
+                               4313AFD06D79814BEED4F40DC9211D50
+                               165A8CA279AA2CB8A1393099B72607B0
+      stream[131008..131071] = 6C30F5011144AF9AE0D27E2D39E51372
+                               783A5BAEFB58F43578D0FFD947457C87
+                               F138CE84D42891A4BFD1F438735771B0
+                               FD495DF941B8BCE83C2EE9F11C18C04B
+                  xor-digest = 7E9DD203303EE6807075D16469FCDEE3
+                               C5BB95A359D4338AD06546061FA12F3F
+                               C24AAE71EE63F3D892AE93E5E327FE7C
+                               1C168CCEC2BD1CCAF905E5CB2DD75C29
+
+
+
+End of test vectors
diff --git a/crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_256IV.txt b/crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_256IV.txt
new file mode 100644
index 000000000..15554076c
--- /dev/null
+++ b/crypto/test/data/hc256/hc256/ecrypt_HC-256_256K_256IV.txt
@@ -0,0 +1,3257 @@
+********************************************************************************
+*                          ECRYPT Stream Cipher Project                        *
+********************************************************************************
+
+Primitive Name: HC-256
+======================
+Profile: S3___
+Key size: 256 bits
+IV size: 256 bits
+
+Test vectors -- set 1
+=====================
+
+(stream is generated by encrypting 512 zero bytes)
+
+Set 1, vector#  0:
+                         key = 80000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 240146C5EA6C72A8DFC93E54E8811C32
+                               A85E0BF7291BDDC0DBEAE086D051D5B0
+                               5CC9DD5C311ED2F7E8484CC477C68BC8
+                               C5D3F3450553F5327253768E958C0C55
+            stream[192..255] = 26C5976C37B009E57BE86064A99E8F59
+                               F9536410FAA9BF625D8DD2ABC9AABF09
+                               DF6B5EFC76CC6200F9E321E327AB0703
+                               2C78B351C5F7EEEFF2C6E374521CFF6E
+            stream[256..319] = 2F72E0E6E710D807D5120AD686DAADC3
+                               A5C1544557A4BA6B1D61F90FECD55328
+                               3C8F91B801DC435C5FFB1F8B33A23644
+                               8E21217C367108893D13AD41EA8F20F5
+            stream[448..511] = 68320BFC459C78596162EF5FEE2CF46C
+                               79EAFC681AE91F875672350C59D33D6F
+                               9E0CEEFE42EA9A0485E3E41C241CDE84
+                               9849DEC99219729D91270358B2F83F38
+                  xor-digest = 19E8083DE3499286788AE3A6DFE90AC7
+                               B77084682ED86D8039A67663CDC9ACCE
+                               D297F22C10FF7E4FAD773337B008A32B
+                               A7176F733045DE44782F04C1DDF28776
+
+Set 1, vector#  9:
+                         key = 00400000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4B1E2D728E06D7356F151D10DE9CBFB3
+                               C66A1E5B5ECD926E33F56B14CEDBFCC5
+                               40CD6D1089DD8E5CF008E4AAA3C4C89D
+                               11B136FB5656B5D4818D1BD1E562BB38
+            stream[192..255] = D5E6B5482535DB7F9352933242C164D7
+                               6528DF7AA013A4FC2F2B8C2D7DC0202F
+                               85774C16FAF22D5071A875B6A671D4B1
+                               A8C396AA5D2F14AFF9C4CD6C1DB89175
+            stream[256..319] = 3D0FCC3C90DE0328FD0C752458996FF2
+                               DF822E496CA42A7D7EBF3D958676A41D
+                               83A16EF3150B8C4C8F1763560B314287
+                               54B4A2EA5C4F74783BF8809F3A624664
+            stream[448..511] = 2D68526D25483C2A1F0B6F7101507804
+                               C9619E267F1FFF28C934D19201351465
+                               31D13592BC9F1739A0B090718052E4A0
+                               CAE9E0FA4555F2FAD27EC8AA2F14CC60
+                  xor-digest = D3C3131E402BCBA54DCE0AD35C5FD241
+                               3ED7056BF67B5163CBE6C9EAA9D27535
+                               7D2BFB7B2843DFE92709F047675CE06F
+                               5201611BCB8FF15C76D0E328D46345E4
+
+Set 1, vector# 18:
+                         key = 00002000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4A0CCA5AD387D49DF33FE8BE69FAD669
+                               270E3E6CF724F53FC3E509A2CEF1D174
+                               A67C2EF4B9D2C9B8A8177BBFBAA2C45F
+                               BDD25CBECBDB59A402FE3C4835854CAF
+            stream[192..255] = CA0F19D9996E6D3518D28D8169968ED2
+                               B03D118D4BC1C5E1847BA6EFE6A32D6A
+                               32BAF71A4C27B0BBC9B9BA03FE044D7A
+                               C9785A69E3B0E5B3B26AABE3AB093965
+            stream[256..319] = 6FD1A9F1EA228C39625FC0CBB2D4BF8F
+                               2C0EF1F37D4FAC56D8024D1B4F2AF33B
+                               8AB0D452F5155ADD5F0FEEED8104AD55
+                               9946D2E274ADE44170F5113630200B57
+            stream[448..511] = 5DA1476A1CBADD0797DD7EB9C0E563B9
+                               EEA2C55860C42C2C0A6B38B9344BA0C2
+                               345C7143D9A7E5BCDF9FA2606098DEA2
+                               142632258F844AA1A77CC9950D5ABD7F
+                  xor-digest = 0CCEB42D4045C09C45CD6C27B88606BA
+                               ECF7F6B30F50004AB2ACDAF89849519F
+                               61482EC4AAA2CF58C4206A228FA23AFE
+                               DD3BD50BC9C04744940A238966C2926B
+
+Set 1, vector# 27:
+                         key = 00000010000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 77CB199A639DE60664225AD1DB954B5F
+                               70DC01305D2D4073BE772B0863175EBB
+                               64FAB80EF324DBC85A9EF827EBAC7A5F
+                               CB088619C246CECE6F92B89A2122B6AB
+            stream[192..255] = 84C1E9B365F1CD23AFD5711BDF2B6F26
+                               F988A6CE29450108FD6814802355217D
+                               F6F329FCB3F5997401019BAE0AE43760
+                               ED6B658FCB4280F5A070728411EDA4CC
+            stream[256..319] = D0AD4A851E7A60DC789762A554A8FA76
+                               77FA610F4D868CFF1AB6025B2ECDECE8
+                               C554B4C0BDF543F58A1DD7CC68FD7AA6
+                               7EFCFD59D55372E85131D6284E7949AF
+            stream[448..511] = CF7F791090D04350930AA1E1A53B70E2
+                               691A231595E83F8BAB9613BDBAD868AB
+                               197D5E06B3397CC3D81F56B87BC7521E
+                               B0BE346552DABEBA863D5C81D7245C8B
+                  xor-digest = 2C77C0ED1F5AE20A97388ACA5300918D
+                               6246B04429F298E64A75828EDBD01900
+                               FC70CC103C31E0BB67B06D04128686AC
+                               5C5FA63FE714FC4DF18C551BDF81862F
+
+Set 1, vector# 36:
+                         key = 00000000080000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 54A5A2E883714170B471C0651D74A9F7
+                               D51287C89FB345DE0AF7003C3871425E
+                               FC885F033D79BAC9716B1ED5C637BD9B
+                               0F16FD8D613BFFAB634F0EC2497D7B3C
+            stream[192..255] = C7FBA70B19B749BBD0C84C7D31A5AA44
+                               155623116C44CD53D2E640034211E730
+                               277402F62D1FF1578236A2646AFE6108
+                               2C958D9D01C065D7335EF9C29415AD42
+            stream[256..319] = 2385E2A7070FEC7399BB3CEEA43C8D0F
+                               54D3607FC1C21BF173642287C1FC2C96
+                               D37695A7B1310E5E918EBE37113348B1
+                               707BB39E401A10FF14EF020CB7C44261
+            stream[448..511] = 5A87EF81C2CFA70D86B147E9587467B5
+                               22FCDB4EAF0353E11F73F3BCC1EA6C09
+                               E962A87A0842B9225E164DB0CD1A3BA3
+                               DA8C02E6746CD3AE0BC4754ADBE7EF6D
+                  xor-digest = A65BBEA2E397048E4714A8AB3C19EE6E
+                               91B9EB8048F35FA7AB9E003E9359BE0E
+                               C3EDA827AF485C23A941F7D656C76CA2
+                               5D12044923E43E61E7DDEBE7D9C87E3F
+
+Set 1, vector# 45:
+                         key = 00000000000400000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = FF81E156907CC2C01EE23F79F936809E
+                               3F88AC15CC01BDDDA378CC1BD2317444
+                               200E4E2C63E15FF07B0B40721970E7CA
+                               68F748A95A965EEC606318447BB31C2F
+            stream[192..255] = 4C4C42A330AD444388FCA4009CC0B196
+                               84AEC3EE65138A747FE86526A263969D
+                               87CCDDCC4C9A0EBDE2D088CCCEBE76F0
+                               52BAC07636937B1567637ADB498F7F8F
+            stream[256..319] = F550BCDF67C8E9C17B800487DF83A4BC
+                               73B809C4F3279D4CFE857780412F0F7B
+                               B838A9F0322BBA84D7AC51E469C5012E
+                               D774E52E3507C7D069F5169F0403C577
+            stream[448..511] = 9D92715109A301AD47BF2376D65E2519
+                               78E12098B0DEA5B779079A0FAAC4DB42
+                               5BA9EB00301A5F964336F7EE9C0D9667
+                               C4F0DBAE14BED3E49A6A746FCB186C65
+                  xor-digest = AD2264EC651E311BAC5FB36434773F5B
+                               4A4777B2B7F811A755269FDA8339DC97
+                               7A8C6A5F66E8737DD16A88DAB8545110
+                               EAE275892A767BCAC0757C396A690F67
+
+Set 1, vector# 54:
+                         key = 00000000000002000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3DC3C1A1A40E721F8A3A66960DB2C0F0
+                               6D8B7C07FE90D67C26F86200D6A1A1D9
+                               ADE4D53A35F7A016A506D9C62D344D49
+                               5C6DEAAE053247103B8F202B85A5036D
+            stream[192..255] = 9B83E56BB5E10B5C6C05C4B450B64FA5
+                               9C52AA63E207592999CBB48355517F05
+                               C93EA878BFAECE58CBCB948E81BEFD89
+                               AE0C5C13359C6CF5A673B4EDE28FAF0B
+            stream[256..319] = 388163F9F26536BE1221A46834CC77FE
+                               03D021C570A9DA36CD528E887ECEB2A4
+                               7146A8A930D6AC04694A0B9AE50FF55A
+                               41AD3B3D3E53F982563B5B458C078C0E
+            stream[448..511] = 3B0FF94C0C9FA0EB8B8CC1C691D04180
+                               5AB6436BAFCE8C16A1351883C88E945F
+                               8F912FF79CFCEFF7374936E830C9440D
+                               C676A5F00BB50EDB34F810AFFD9CA8B3
+                  xor-digest = 879534CEDD8CDBDDDE2E2216D55529AC
+                               1189B1C34A76ECEC179B8A240E890F8C
+                               640738DC37C14E4B950B9D8C507685B1
+                               28CF4782EC424A3712F54F6265A41E7B
+
+Set 1, vector# 63:
+                         key = 00000000000000010000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 12F0A17DEA167676992DFF2E7D812878
+                               629579519578EAFD885F212C7E04F035
+                               AF03732C3DA8CFB7B73054662F0593E7
+                               E40133706F04B1329BC3155DACD296AC
+            stream[192..255] = 41BB89D0BE44055E23813783C3EC4487
+                               2D102D6EE94475AAFFC7FEB8DE6849A2
+                               6B50DE77EB9B0B96EC9EA0216D13D64B
+                               1264A83D6B571A92948A5E35446B0503
+            stream[256..319] = 15E9C9168AF4AEF7F2EF1E832F40110B
+                               A8C08DE71D4F0AAA3A5C2FC59BF41005
+                               ECA654EB7F316B757FEAD5B0F4BF41F2
+                               C6D035A88B5477632F34D7F904B2939A
+            stream[448..511] = 8A2D446044F7930B696DBA896BA6CE69
+                               8F8B01E4282BCCDC4740BB6AB6ECF7B8
+                               9CA1CFCB5745B6577D0F440AAB7985BE
+                               BEC5DBEBD8B028B15DEA138F09018297
+                  xor-digest = 89CFE7E84993C6B608EAAECBAECD7847
+                               472703F3CD97F9315BA9CA13204B616C
+                               AAC0F37EBD1C58186620710FD6AE5EFC
+                               B7CBADA19AF8C0F7E1FB24913C2300FB
+
+Set 1, vector# 72:
+                         key = 00000000000000000080000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 7BC411ECF4AC2EF2C9B8C5B7CCFD791A
+                               E8250119E08C1B7F7A82F576FF66FC9A
+                               9D9BDB7570EAF276A60A3BC7E7BCBB86
+                               7A791A48F9E742D7D7480FBA67DCDA6E
+            stream[192..255] = F85A8E3219AE1E5F20A4FFC6814458C9
+                               5A4ECFE7FE739E151A45247A136E3BB6
+                               9C11987BB5D13B1B9A3077C8F4ADC9AA
+                               A555FC9725339E02390B9C9F75E1F38C
+            stream[256..319] = 8A2E88E0A773EA00C11138710BF12ED2
+                               7797AE7863B1EC84801D11B5B3914786
+                               F1D547382DAA9D5215CD4CBC783C700A
+                               9B09FCCFED28899D2F2EC148CEFA39B2
+            stream[448..511] = 95E3BA3237F370A4E0850F2CA0FCEC89
+                               E9D832CA6DC6A062BE7ADA8D8AEFD55D
+                               2BC7A3F46BF81DEA5DD9155E8D8FE918
+                               B5DFB1926460AB69663856EEBCD4C338
+                  xor-digest = ECE252DA29D20602D138E13C004D8B66
+                               8B09FD764B7D84FB83B8F4D924504D60
+                               277BAFC521A8AB0464E4EFC6BBB9E4B9
+                               A206C38154AE3A57B84D2D39CF45616E
+
+Set 1, vector# 81:
+                         key = 00000000000000000000400000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 139C2843F0BCBDD32C685F4EE2C7AF4D
+                               E6BC79789B77B1CA6CD94A01645EA243
+                               5B491F27C27D4EEB96FEA0ACE65C0D8B
+                               BAA642B5A07245BCD0930588FFC92A50
+            stream[192..255] = 5C76EB0D5323A7AAAA228F7718BB6736
+                               5B344559C24BEDEB2CA66414B5E81795
+                               428D55868611AF9AC7EA0E7424984037
+                               3251BF5206C361AA3631DEDA52DDD519
+            stream[256..319] = EAB18EFED266D4788015DBDD20A75058
+                               FA4DE35C1DC774ABABC476BCB0AA2CB1
+                               214E5463F4E20E7B999ED475D77DBA9D
+                               70FFCA0C7971CAEC3B285EE8F9F37C02
+            stream[448..511] = 081083D9AC30C9DB4E53597D64249D7B
+                               CCD847495A928CF4CE876237D92ED5E9
+                               E3D723EFC663CA0DDF34DABB941F42C1
+                               B48EFD59DDCAE71A1B82358A3328644A
+                  xor-digest = C08714035439EFBE455BAE68EEDDA0D2
+                               A6968F18827B214A097221C3A77F80AA
+                               E1DD9F3C72FA66C16EE278A76C19107B
+                               37CC32346DBDD29FB30059A8FC732DED
+
+Set 1, vector# 90:
+                         key = 00000000000000000000002000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = AD897A3C509B66728342A817D745460F
+                               6A258386FECF71DB95ADC716B8BC0462
+                               22C4EE887334718534E719F36454E440
+                               F9EC44A2DC38345CEEA9425BF5F10123
+            stream[192..255] = B32235522391A0BE105A993923760C6F
+                               BBDA849213C628776BCC5364F28EE5BA
+                               D498F186C3C57A8DBE5355C2A38DDB82
+                               54B321636EAD186788DF1BFC5B6F85F6
+            stream[256..319] = 499CC51B20538B14A05E490B6D5D10D9
+                               11079F58E3603A84AE6689293E3AEC56
+                               7545823F0B085469CAFFF01D2AFC5076
+                               C155F8B4B7DB4C49A9A993964928D11E
+            stream[448..511] = 65983D36E97AEF89C3A75616F7C098B7
+                               5CFD9C531AFF8184010E2CFD45163312
+                               FFBCF5AC70139CF12D97325CCEFD0B01
+                               FBE571FFBD7DC21B54D4B277A2205E56
+                  xor-digest = 90CD243B35747378B85B99474EE0BB3F
+                               CE7574CC19BEC5220255523276CDECE4
+                               5A16EF44C414ADF1D1CBE264872419CC
+                               EAF664CC74D36072E9B975FF40074006
+
+Set 1, vector# 99:
+                         key = 00000000000000000000000010000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 26F731F36F626943D4CBBD605CB67FBF
+                               E9301F24AA4E93EDB2D0DBB3FB17E8C8
+                               623054B3003BB12E1C8607FB53315AF0
+                               A139CDC381753A14342AB90AFDF43E67
+            stream[192..255] = C3B755D009DE9965D36B4111308B25EF
+                               39A137E373BA0E90E5AE2748115F29FC
+                               562A6F6894BFEA59587F991DD105DE1F
+                               67F62A73A72A4802ACE727335467F503
+            stream[256..319] = BA815578D19B3B384BA7AA7B972B1FC1
+                               7244FA75A4CFDC8C30ABBFDF6861F356
+                               6A9B68A6F60A61E6DC8E046FE75373E4
+                               B45EAC193127CBA3AC4F22345BFDCCFE
+            stream[448..511] = 99C68AC554291FCDC03F300D69CE68D8
+                               C4D4DFF5FB2D4C3079992D40FFCC9683
+                               DE471E6F2A406DCE03AF8EA17B7AE905
+                               12F1368B8EFDA838274812C4F134E2E6
+                  xor-digest = 01AB73AE53306196763ACB9ACFF9A624
+                               B83A7B339DB517AEB408292627EEBC43
+                               FCA6397320F50E96ECC3595B13BFED85
+                               1309458EFE35FA1167C2CCCC6A4CA83D
+
+Set 1, vector#108:
+                         key = 00000000000000000000000000080000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 031A1BAA02280255F0413D76F945138B
+                               C0835BFE7CA64B16AD090454F098B8CF
+                               34B1EE138E03C3CCD9FF918A58D06AD9
+                               2D7F3FB57D2E161A863A0C25391CCABF
+            stream[192..255] = 6810368C2B2A091C6FB3EBB76E960AC3
+                               BFD678F028EB6FC0F5B36C2D386A21A8
+                               FE46A5AE09DB0BD75359A8482EB6F5DF
+                               ADE199B796520807D60D9D93995EAFE7
+            stream[256..319] = 0F2CDD428FF6DF2A4621A8423E09939B
+                               014BEBC0ADBB8CE71B5E587DA408ED43
+                               04A12BD535257322122EEA2840A9447E
+                               CB1B6D3550ED14EE31424F5404B2B5B0
+            stream[448..511] = C63FCB06883F3AC65612EDF28C875477
+                               1D383D42A553EAFA37ECCE26061EC5AD
+                               C6FE3BF23E06CFDB14EC1DD996A7D4E3
+                               FCF7A0B9ACC69F37ADF428B434994595
+                  xor-digest = 463386D0F7A1306E87F3221C4ECC0597
+                               9474F620AF3563686ED5DEE291155225
+                               56B9372496638BA1631982D6B3F58CAE
+                               27810BB7AA93351B838D54EE761A8C94
+
+Set 1, vector#117:
+                         key = 00000000000000000000000000000400
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = AA4E7E8171A8E0AEDA6049999E0A06C2
+                               FFA43B9ADC5E9DCE4ECD8FC1D27BE792
+                               6FBE2ABB69A6B69D8C213A793C77096F
+                               D4DF7BBDBCDF007C914B7C817837D99C
+            stream[192..255] = FC90E3C82B8E7228C1ADC2F555068372
+                               4307902A0750149CE0B2EFD2CCFE9875
+                               DABE60E1B85CA117D05E4BD4F45B42E4
+                               55A9F42C60910C9BFF8DF8FAB53C81E1
+            stream[256..319] = 9BD976B88E9E5E23D0D40779644BB3F4
+                               CE5C6B16FA6D955C32369DFD19D632BC
+                               7730683D562320E39F75D8D8BD074968
+                               9ECAF0DCDCD99FF4C3939092E9576144
+            stream[448..511] = 51BE9CC1362669C0F79D2D88A42DBED6
+                               C3315002380AEB647C8F9C4036590527
+                               1D8915B985B8BE9CC1C5C7652139E609
+                               651EAC8A14DF661D9869982AE5735E9F
+                  xor-digest = 0B0C84D430687F488F8E45DECECD6D7F
+                               1947E32AC49BDD2139F5413E08A88F31
+                               F9AF6599498431F155AA10B7EC09F095
+                               8A5AFDAD486D2E6D50AF77FE98E33738
+
+Set 1, vector#126:
+                         key = 00000000000000000000000000000002
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 52F49050156E957C605656B2DF88EE1A
+                               5E3ADA99F9793B65456C4C6C322B8B5A
+                               28DCC91EE0E711BC33E0C13354542227
+                               613665CFA3A825B943444401EFB06ACB
+            stream[192..255] = D0907F5D5939D7B544476E299605972F
+                               FE422C64BC6343F9C81093AD0E3ACC72
+                               F4B67314892E36764736C0715E4D3438
+                               36BDB105214F5F8925F321F5FD865EE2
+            stream[256..319] = 96EEDA75474D65615795185B1BEE8D44
+                               A687420304B260E4C70FE7F542967325
+                               1826EAE010981F6262EE6CB639996467
+                               5F6B23825748128617721752283C16DB
+            stream[448..511] = D926085A441E507207850AFF3008D59D
+                               F7C9D3B69687D18CCFF2C2E09D4E4EA7
+                               FF0B72C04A86B80923DAE187FFB99170
+                               DBD4902AF77EEC42866A83B519F092FF
+                  xor-digest = 1E068ACCA6062CF26ECEC79F149BE139
+                               24AF8BF44377EAD1550B1560E4A1006A
+                               A6986C61581FF9E47D58F2E52434911D
+                               5AFCF914DBBAE183D02DDA3210768984
+
+Set 1, vector#135:
+                         key = 00000000000000000000000000000000
+                               01000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = EF5BBD7A620E8052F05DC269309AA7CF
+                               8AFD4AB2B941D905AEEFC721562E00D7
+                               04CA70113C8A90FA12A0C9B9CD1B9F9E
+                               6176602CC08B66410A8BB0F5E9837C27
+            stream[192..255] = AB843B43856FC77C1EC09C0DD2248617
+                               820344BD2CA0B025C39B0EBD5A750A6C
+                               7BDCE863C068E0D3A937A5B2C5B6ADFC
+                               609F6DF7778D88238B89288B2768DE99
+            stream[256..319] = 5E6AFBE41F47F35CA9298C973E613174
+                               529D9BEFA6D0713A5BFFD96B70D39044
+                               413E24FE57B01C426E8988EC365FEFEC
+                               1422CDFB956B12C6A799F5FDD4EE43D5
+            stream[448..511] = AA960C189C0A20870901D4E2F1901D0F
+                               A28AF3D974E14FB70736C191D4C9CA26
+                               48EEBA776339F80D57A8B783419E61B7
+                               52541CB296B4CD31C55DE3D34CEF0D31
+                  xor-digest = F163BB7ABD3914204ABAF08B844ECF05
+                               A36B7B37B8345115EFAA2AB2E7763E6A
+                               E044A83597C023FB41EFAEFBB63E4195
+                               B60AEA6399DEBC94C75BE883B3623733
+
+Set 1, vector#144:
+                         key = 00000000000000000000000000000000
+                               00008000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 9198011FAAD874AD77CD0C98DD99C7BA
+                               01B75CF9DE1E26321EC6AD293C73C675
+                               69A349157FD47672C5326276BA40F4C5
+                               0CF8D98134D0BC13879E9EC267110FDE
+            stream[192..255] = A9B3BEEA161ED996C44F6D3B93431C6F
+                               54DCD5DB88E62CA10D1067B9CB5D21DC
+                               D7E04C48D88DF54E1370D1C24C871BD3
+                               BDF9B956315996F95867D1E2494370CD
+            stream[256..319] = D09ECB5DF5B0526372B57CDF5DCA6AE0
+                               F005D2E2F27D50398E3D1D7FF2100BAA
+                               D6F2C03E431345A4F41CEF3E8D3F14CD
+                               C76A423720A936D27322559289F13D92
+            stream[448..511] = 5E8FE7964B052B6D27216E37C49CC913
+                               450FAE159C087E34CF67E8B0B8F516D6
+                               3C0B544CA29F9BCB2B48D3894D69DE3E
+                               1460783E82EB67990FFB7F92DA48E449
+                  xor-digest = 5515E37A3F274746847F551ECB7DB4BC
+                               2BC32237050BEE9AF2AD1BD8577034D3
+                               4A23AB8A2FFD00C7B8CB7D5CA0AB2421
+                               E7CECB2801A1B73A44FF3E798ACA8443
+
+Set 1, vector#153:
+                         key = 00000000000000000000000000000000
+                               00000040000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 02858548ED24761DC0AEC6752076D095
+                               7E78EF1FCFFD8E756C747586A3B59C22
+                               F42A9FCA9F103C3054E0B4F6EEC82101
+                               971F2A6F9611F7541152FA3BD7774474
+            stream[192..255] = C32ADE80873D1190E9807C25D73EC5B7
+                               C208AC693D98A664FF4D11205650F7FA
+                               A36B153BC1A3F0EE0F4319F2100F7F27
+                               31856BFAE36110C12EF0361259641D74
+            stream[256..319] = B8F74AD5930D1F2CEA6B9F7E4E775DF0
+                               AA97744677E5C96B9E55AD77BFAC5E8E
+                               E9BA7A19607D9EC52DEEBECD185DAE13
+                               E304743019D831849F111602EE6EC34B
+            stream[448..511] = 513303A57165287E793DB91F49C9A8ED
+                               522389F03634930512744884BCA45F4C
+                               ACB60FD077BF2C050D4002162FB811EC
+                               4AA855793CFF2E30665188471FFE0847
+                  xor-digest = 7EABCDBDA34E51E3A61D2F3340884BBB
+                               600E1D30216B7117081B3E5D04FD4523
+                               706D4F34C5FD604134DC89F570D6119D
+                               DBB7C5FB7CA90E38AC157832C3C956BD
+
+Set 1, vector#162:
+                         key = 00000000000000000000000000000000
+                               00000000200000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 689E48A85A40BD161BEC710F9B2457FD
+                               276F1156EBC10BB851A8517AFDBD692D
+                               E4827BAAFF218AF886439ED976147EBB
+                               BB1074BD599A80F6324C87BAC987B8C5
+            stream[192..255] = D9BA3E74CBAA58CA97DA3D3B1051BDF3
+                               29F6CD837B72022D2EAB5D20B02F53DC
+                               4755C764C50756A7101998C187E4F0F8
+                               F17A0C6797976C4FF1BA17B3D03C2218
+            stream[256..319] = F6F9B6F0F6E1D756C0242B48BC55EDE3
+                               3038BABF72FCDD5122C61804996F5ED0
+                               86A78B33C517CCED9C34580AA54AC03E
+                               BD0F9698A234787DFE97FCD3D9B7CEBE
+            stream[448..511] = C31091C4C5AD605BA90963B1D469E501
+                               412FEECDE3EA8EE834F188793A98F830
+                               81F8C941F11676E007074B40EB15DDB5
+                               67D93E954422376F2E3039F4E4115D70
+                  xor-digest = DF047B3EE7F2AAACE9D5A2B0F6A1EA0B
+                               97E815E9B9BDD3B7862ECB414E9C08E9
+                               BA0109B1D6866C9D7D6D3DC9FAE5F51A
+                               48DE7B9077DA489B7982BA69228483A2
+
+Set 1, vector#171:
+                         key = 00000000000000000000000000000000
+                               00000000001000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 1F8F707DDF0121AE4DF26A6ABDC195A7
+                               CB9CC8479588D2D436C52483DA54744A
+                               2880E3DC622180D36B64CC053CC245D8
+                               0700EC62ABCA6944BF89C7DE1A532A3C
+            stream[192..255] = CB2D934DD1414C60550CEA6FFA776312
+                               3C9336F99F16F8B5B8E60D5D0CE54A35
+                               E752A4887A03EEC95050E50B58F5C8C2
+                               FD814DE76D3F66B907C77C9B646EFD13
+            stream[256..319] = 10306DD8B3EA307496D7BEB7A679D53C
+                               3650ADC53991D0565856F51DA82CEB45
+                               AFB460D6F90877557E17F534C3375FD9
+                               F96D13AB77FA3996998F5DC6F5D3C9A3
+            stream[448..511] = 42F4D1F669741750B24A44F82990E6AD
+                               065E7B07B2194C96E7578F7A754E52A5
+                               86C820FFDDBA671A7B08D65B51D8736F
+                               D0DA8E81CC69BB8A56565C43845C0AF4
+                  xor-digest = C0535BC269BB39AC2ADCC50C62F87B6F
+                               2C9351DAD49813529A27BAEC163A1D8B
+                               778670F0FF1610A4688F86851050C9B7
+                               275B087A0B5CE01B602F8D1D25C29392
+
+Set 1, vector#180:
+                         key = 00000000000000000000000000000000
+                               00000000000008000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 899C1C50A80E374AE884F10BBD17D036
+                               1632D89938FDB7E4BCFBE1050D5E948C
+                               CF4631EDFEFD2F140FC3FBFCC096CD68
+                               1F6C1B0CE9E395FDEC56295AE331D8D0
+            stream[192..255] = 2F60CFD4D07E58DBC5127A98D2B1DDD6
+                               1F216F61F70AF12427108906AFEDA4AB
+                               B439A99765EB84E43D06EB7B3D984A3B
+                               53D8C054745A6E3B61F8444C84C7F30D
+            stream[256..319] = 1A92F3B4F6C4684201FA4AF201259AC2
+                               53637B41B734062C298E6F932DBDAC5E
+                               999FEC21B63539B5FAFC312D0CCE6137
+                               04AB3CE65E241A1C34D12ECCC840973C
+            stream[448..511] = 83A75C2E2C6D40FAEA049322DC1B2251
+                               306A8906A37DD30182C328D50E7B7AAF
+                               89671DD776C9C730EEE0DACEAC7D7038
+                               4A93426090F31EB851976B8B2ECA1FBA
+                  xor-digest = 6D85E7DA2069F1308D20A56DB17F3629
+                               09E80EA6A045DBE61FB037C3C8B9D448
+                               526A37A431A8BE49CE4F10B8CF6A33B8
+                               82E6ACD6309BA1B716810715666C6CDA
+
+Set 1, vector#189:
+                         key = 00000000000000000000000000000000
+                               00000000000000040000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F9E151BE5EA0F532E56958F173B8F104
+                               DC9E73D8FA289CC2F84C4BB10E8EA769
+                               57FBC8F539365B9E9518F8787D6CF927
+                               55F0C2B2845318337F36B80E22C59FD6
+            stream[192..255] = 27FAFEBD2EBCD2B67AB18BCFB7F8DC96
+                               F54C8A765B0E4B3DDC3013B599DEF791
+                               287FF3C0F48F339DA04B667E54696485
+                               D48751A001B548727338AD6FB82EAE42
+            stream[256..319] = 09DC2AFADEECB86278C64DDCA51EEF97
+                               C10B9852DB5F33A19C99C0D4F36D2959
+                               DE247E4DB356E67F2951E0309F18D6D7
+                               27D2A1BADCC44DC320E2AA80E1834198
+            stream[448..511] = 4103D8455B6DAE658915FACFF2F3F1F2
+                               856E2343143671565936301E9D1F635F
+                               EA732C9A096C3E955D33770E244ACEA4
+                               094E390239489F4D4F0A1F3C26A1589D
+                  xor-digest = 8DF4EC7886C386E5A0D7201A3E731E95
+                               5D1E281321C2B592E31681CC95D173A7
+                               C92E6112197C6A605F494F6E9C4AE73A
+                               21B966CBAB1628794F0E44202742EACE
+
+Set 1, vector#198:
+                         key = 00000000000000000000000000000000
+                               00000000000000000200000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 8B9B0CC804CB353F49564926E3FD846F
+                               A4758692FB110A428FAA3132F4C606CC
+                               A41CA937FDE463D9FEC51F419D60AE60
+                               1E8EDB30AB09E0B08D0143D885161B16
+            stream[192..255] = DC6DFDC4E36FC1D4BD87F731F761BCC3
+                               9837A790DBB766040B4508778C5CFC82
+                               8EF9EC4D76BE3AE0967DBC844A2D252C
+                               B942E97A2C6A185ECF4E1200BF9BC826
+            stream[256..319] = A9DE78C2204B712A9803594B872F29E9
+                               5E8962D7D719702FB3279F053D311292
+                               26A14FB06058AEEB6D283EE0A272C6F2
+                               D392B102E294A7CDF24928D5281D024E
+            stream[448..511] = EB822D7BDDA456BB6E109ECD330D4FB5
+                               1259D7042935BD5DFC787E903758C27C
+                               E9E9B191957E721A7013D36E5A29C09A
+                               3433205956A55460D1498124B2800423
+                  xor-digest = 10128D9A5EEA1D93E65462702DB15A8A
+                               23D0FDFCC5B0871639D704DEB9F580C1
+                               C88213CA166F3BBB89D0926CAE7E64C1
+                               0A24041A42B9D50CB0537A0585EE574D
+
+Set 1, vector#207:
+                         key = 00000000000000000000000000000000
+                               00000000000000000001000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = DD4CCBD0B5068DF0193F50C11D2576E1
+                               A70040D6C2CDB98061498891D1791E63
+                               C4B5103A52146CE27D8F721E147EA612
+                               7E5BAE1FCD3DCD9053D5FF5EBA328BBF
+            stream[192..255] = 541F008D78EC1ADC5D1B930CC99D4A3D
+                               61BD60AAB9DDC8AF8594FCA129410232
+                               92BC44EE064E44E88A07ACD1B742666A
+                               D147F14102D23578E3B7DC00905586D1
+            stream[256..319] = 6834D2FB6BF3B46C0552AD83275CE6EB
+                               9482C2DFE40C6B1FD6F743CAC8F40A91
+                               5BA9A90FBE7CC0153D53C444D3F7A23D
+                               CDC3134E237F63E5A07C99C10B8EE87A
+            stream[448..511] = 9F75BC84091695FDAA2579AF9D34B2A7
+                               2B82D39A1E7FCFC4D18D6898A9CD3296
+                               0D50AF1B720E1347A0848782BE6AECC4
+                               684CCA05B893951A65EB7CB37F5FE240
+                  xor-digest = 12F358C7C4C697199F9AF17040115522
+                               062514A5DC3584BC515AAA4474A1D85B
+                               47A6A2D8C39E8234A5D11860BC1036E3
+                               957920C03E9A47E61AAFB058A9850559
+
+Set 1, vector#216:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000008000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = C5958694DB1D54B95101A9F48660CB26
+                               8EDADED85C6239098248E0867117607C
+                               D5278E5B5D9CDA7BE8A6BBDCE61215B6
+                               2A93FFF627B28B271CF2275E54EA1CD0
+            stream[192..255] = D9B69B25B5729759F3180FF17421092B
+                               0740B2E1307FA9141915CB8C30C0C322
+                               A1E4710674EE715DF3AC89F447442A7F
+                               845E154393273BA47F2322BC661D1755
+            stream[256..319] = 49412E5F3C9B5B52FF790CBE82D6F037
+                               217A13B7744740A887F7C1FBE3714DEA
+                               2A4EA4A5F444B2EC3C0B160A251CB44F
+                               8DCA914FBB80F72BC8D009F1C7E001EA
+            stream[448..511] = E1C2BE8C64D6BFE081EDD30681763928
+                               85939DD7EBC13E16D83C8E7FF65EDBC5
+                               90FA3904068784806E20F0A61CC73839
+                               E3BACD410F59D3848F5A628EE030FC4E
+                  xor-digest = 54092B3D64197BD598F9050B44D2E785
+                               029F29F46822B72ECA40182E8ABDABA8
+                               751054FC50250DF5AF5AC75F4C51D1D5
+                               D2BE298770C353A7C5D608D1149F1452
+
+Set 1, vector#225:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000040000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 633A6CAC516B7A84CFF8F5702CD9BC81
+                               BCE328741675EBA0FD1368190AB6BEEA
+                               7C8B0256CEDF9E5CC6F9249511AB87AD
+                               ED95BF8E11182B8BEB75FFA279C3F706
+            stream[192..255] = C3F700538A4EEA17773E74D10CE4493E
+                               FB0417B380ED4229F651D6A9BE0AC617
+                               AF66C576B7D06F2210EF226462004D90
+                               E753D805AB198B73B0CCD752C7E57A2A
+            stream[256..319] = 30A11289A9E0C854B980BE044F07E945
+                               06D772861896D0F75D739647FFB939C8
+                               13FE4BE5C8DF84F64827306D0DD82415
+                               E104F787F30CD097EED7DB9340A0F47E
+            stream[448..511] = C2134984733448DD577DC48B5EE5D761
+                               0A54AB6C32E3BB782849D8E7E8B522B8
+                               0D6444342ADD9709D7434F9B4C18C6E0
+                               15AE97DF8F3D29FA6D85DA387157E223
+                  xor-digest = 8613454AD0B424AB6EFCEA96C0802B6F
+                               47F1E98C52BC68DA25E653431CE31078
+                               1658BC45DCC2EB43C4ACF8395727133D
+                               12A127D4CBAABAF24BA44930A58A87B6
+
+Set 1, vector#234:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000200000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 6A0F095C0E23FD6F8DCAEDAE5314141A
+                               0F1CE1C1BD6A16E81FEFF72F0753A5AF
+                               C1C54DFC0DD6ED99F1D416BE3C5EF341
+                               454C18D49729E80EE99F37734817658C
+            stream[192..255] = 05A4DF5BE8A35DC623D107728F28C789
+                               3DE0E75268B3E1F94C07AE50CA0891D6
+                               2B1E764CB41062391B33929273CE6B6D
+                               1C9CEFB35C37AB2FA8EC18749B5292B0
+            stream[256..319] = 41C8AF9ADA46F7BE8EA72BB3B8661B78
+                               2BE5649F18F216B75A0071A6617200B8
+                               463B08F986D706AD140E27C8F4E040BD
+                               6BFB4872D758363281C62AE8C4B64E33
+            stream[448..511] = 58CDA35476767EF58748A504B0E4A38B
+                               64162AD422A0DEC0434D879898558C77
+                               1A8243DC43B15FF996B4C8CAD3C47C6F
+                               26F00C71ADFB538D9A983B7B624D6E62
+                  xor-digest = 240A699AF4DDBB56A4C502A9175C0E3A
+                               BBD654D0717A1F6F6847381B978AE8C8
+                               0EB7CA07A481DFF8606A31BD6B489AE7
+                               89763068D641BAEADCBDA9ECAC465ABC
+
+Set 1, vector#243:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000001000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = B3C91DA5911D7D7A4BC16A66988AFD3C
+                               8462A9E9BD0D95C9B9884DD14801E464
+                               C27048FEB5F70B28013099F0A31255A4
+                               9EACE528A13CB5DD067E520D183133BC
+            stream[192..255] = 756EDB0542FE1F11B159C7081D9CD742
+                               2F0E5862D39E2CF1517B2F6F39AE5245
+                               D659A5B93EB8FA8C8FB751B378BB0DEB
+                               481B874663624C8DC15E6A1A64376340
+            stream[256..319] = 436613C9293D5DCB204B46899CF23E65
+                               698BCC3003FE064FD1263EEBC59DDBAC
+                               536566855510FA802128F0A968A2E359
+                               FB68EAFD6AA89D394B32BF6069E92EFC
+            stream[448..511] = 033FF40203ACAEDFBF561A674EE74D97
+                               A535A448AFF94C8C167200E5CA626388
+                               DB1BD6EBD4A1D83CF352E97CD8F02671
+                               18E57B71D33930EC2752D2F262A55F9D
+                  xor-digest = 2CEEE4705688B20B3AF71F285DB9361B
+                               0EC945296B97F3A050C31C54E9A07CA6
+                               498B92917617571928E2663CBBAE21AD
+                               8DD880A037A024E46B6581974838AE1A
+
+Set 1, vector#252:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000008
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = A6AFA8AA02C3AE7F29E61202B4A5C25B
+                               6F74BCC176702C9C1D610FF722527A6E
+                               721ED90B871AEEC71EB62B24A8F24357
+                               07765F7724BA03173F51C9B66C9F4BDE
+            stream[192..255] = 002B8929A54C1370067A36DB9057807D
+                               DB747C2A4CE19BC085DDC517AADE3B97
+                               BB1B35F2BAA6A18E8154CD80DA6F9F4B
+                               0DBFD3EA5F69D5ED3B5770C6221A8D66
+            stream[256..319] = AADBBFDFC6FCC6072747BB528EBEEF34
+                               6DA76885CF1616ECFB89D3A134769902
+                               904AA12744DD404F268B0B4B34700928
+                               E3C4B3665B9CFBAD9C528EA06F89CCDA
+            stream[448..511] = DD5453BD0D99E7D2CFC558EA969A4E35
+                               743AFA96D570026106C5CF40037B1325
+                               40C909C1278DAC8369B1AC257FD8D868
+                               3648B4F22F7C66282BAC49D8D23626EB
+                  xor-digest = B3F2AD900155FD5D39768B4F4B7F8E5A
+                               1C557936F2B5F06966DCB884AFF7F01C
+                               7AFC073C20EAF85363DFF41357E626B3
+                               B19607224467413D185A05E7BFBC5F0D
+
+Test vectors -- set 2
+=====================
+
+Set 2, vector#  0:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 5B078985D8F6F30D42C5C02FA6B67951
+                               53F06534801F89F24E74248B720B4818
+                               CD9227ECEBCF4DBF8DBF6977E4AE14FA
+                               E8504C7BC8A9F3EA6C0106F5327E6981
+            stream[192..255] = 30DA9453A90909A5675D6B691CB0990F
+                               C423CDD8222EB47245BBB67BCA2B9C10
+                               8D1F016DF0CF8CEAF6829910916DBC1E
+                               113D11E91BEC3D85C47E3042EC865658
+            stream[256..319] = CAFED71B892EDBE13388CEF6A3365797
+                               E0D88C0D3A5B91BE4CBAF5162F69558F
+                               DBB45CA6F8C8D4C371D62736EC244584
+                               60131F54854F3EC804AA9A38E6ADE281
+            stream[448..511] = 531A0ED5D2A51DDC6499FE1BB6E2295F
+                               2C3EA0F56AF46ED93DFAA4E16F5F0831
+                               2D77BD0E9122043CD6A202CBA9351F6A
+                               0E8E6263F4017355136A0C551E6FD0F8
+                  xor-digest = 023D719F61C193E4CCD87755C87F9604
+                               C5A29DD7E31637B3DD70D43441D48CC7
+                               D474013C85EEAB1897C80ED0A0272543
+                               F951C72E3954616CB5D6B51FC24F4B0F
+
+Set 2, vector#  9:
+                         key = 09090909090909090909090909090909
+                               09090909090909090909090909090909
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F5C2926651AEED9AF1A9C2F04C03D081
+                               2145B56AEA46EB283A25A4C9E3D8BEB4
+                               821B418F06F2B9DCDF1A85AB8C02CD14
+                               62E1BBCAEC9AB0E99AA6AFF918BA627C
+            stream[192..255] = 3B3C6E78A8F381EE2C159FAE1C487C58
+                               11FA9BB02CECF7440239FBB0497347EF
+                               D8F1A8AA71AFC70ECCD64E81388E6E87
+                               9521C2B47AD84F9CFD9E240D8D2F3001
+            stream[256..319] = DB04FD01BC18D91E2D31237AD0FE26AD
+                               3C8D6A2EFDAA9CC11BFCC61D94F6104A
+                               4091B3634FA57AB0AB9B209F22DA5529
+                               75C3C322DEBE4AE68623BFE1B2BB7F0A
+            stream[448..511] = 35B290F85EBA78A978750690C4747E8F
+                               72621951483772E8B89876CC5D55F3AB
+                               02D9B8FB35C741279FF9B5B571B26329
+                               4D011F813CB5B209CA1A22D532BF09B7
+                  xor-digest = EA9BB65E87C987EA64BC3F4E710CCC34
+                               F6CD0A795B8347E1441CEBEE35540D41
+                               64FC2B95D71FD47A2C4ADF732261EE52
+                               8125BE374FA4A90132CC1063971A2862
+
+Set 2, vector# 18:
+                         key = 12121212121212121212121212121212
+                               12121212121212121212121212121212
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 397F8EC015ED573967938D1CEAFE9BBD
+                               BD8853C329B3A881B489090853FE0F43
+                               89DA105F0ADFA9CF51DA2521C40FD2B8
+                               FB0BF80B93E3F2B3D8A8EB1C615E0FA6
+            stream[192..255] = 68E7DBF465E3C6994D58B9937A866E4D
+                               43A82A80DAEDBF29C048639BA38B690B
+                               7ED11323E3C0A8E77A16356705431EC9
+                               9F2CB7F7E1ED3B83EAF2CAEC00B00755
+            stream[256..319] = DA51CF3A07EBE7E86E9DDDE5A47E7417
+                               376F334E6AEF9C187012C8AD2B94BE7C
+                               00A876756EB232510FD0798E72EEC87F
+                               75EC1467C07B3A1EFB0D51A5FA65E382
+            stream[448..511] = 0BF3C6FF6794887F2776FD632B83682B
+                               AAFD131432CFD7D2F675E03320395313
+                               AD4ED96E9052FE6B2D2A17428660A25E
+                               EE642B712800BE3F7E44F21A1E6A03AC
+                  xor-digest = EF4E84DBD66497B142EEAC56B830FF78
+                               0465CEE20B9CFAF5727D4B3A588F4D00
+                               AAF718330CFF35508C44C1ADB8476625
+                               2CC3AA6AAAE74F8BF1DDB6D4AADA425E
+
+Set 2, vector# 27:
+                         key = 1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B
+                               1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 72BC8A6E1E61E704B142AA00812EE676
+                               263C1CB9AB941119B19D15EBA3462F56
+                               2F69220595DE5E0E7C595FA40F1F06B2
+                               6EC32252AF05310809DDDFAE2E24B170
+            stream[192..255] = B29A740B51B4EA1080666337D5551484
+                               FFED6860A5125DC0573C8F90F23A98E0
+                               BA7B3E4C28C2CEFB1C33D2C36D1B7625
+                               64B9A67240CF174347A4C8D868F00F6F
+            stream[256..319] = 555ABD5577A8909797FBA9769C03A0F6
+                               537C06AFB23354F054E25457B729B534
+                               CD10B2ABD45BE3E38DAF1B7A9103268F
+                               4FDB4C0FC9A80A003FCB907E8F249AE0
+            stream[448..511] = 3B29A43D9C795DAF1760CA9EB57C0B39
+                               F62D54311207B617B727FCCE1B2E762A
+                               060810C4DEF672E7D76083E3E4BED0D1
+                               0BAFD27CDFD2C937E660190D36B3FD7B
+                  xor-digest = 0B3B0B3C69F2E4BDA22E25AEF352234C
+                               18CC5E1E3F6A317ED7257887446EF734
+                               65CA15F51AF5E077B7915062391D8497
+                               8F437985DD08F5FA3A8D74B3227A6EEF
+
+Set 2, vector# 36:
+                         key = 24242424242424242424242424242424
+                               24242424242424242424242424242424
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = C845BA29D542FBED2D021C85188E119F
+                               D34967B79D9F44635DD45D2E41DC5AFB
+                               B237AD2FA0E4CF4202D83DF3073C578D
+                               2AA8A32D30FB45DE28F23CEB85E50FBF
+            stream[192..255] = 15C910FDD3C590AED1ED7DA2A7969297
+                               FD12081B4B23F0A32CE5B3196173C7CA
+                               7EDD03F9637E08CA501C4850C15B207D
+                               7AA724377396CED2357B572BBF9E69AA
+            stream[256..319] = E484AF567EF80BAE77461855294E9280
+                               EF57E7366605785034D639D6DE3EBB0D
+                               E21886D0E1E0679BC2E2C9C2D9201484
+                               4A452B6AD3F1AC8B7762FF3C0E405B3B
+            stream[448..511] = 595D9855200786BB575FF7977509F395
+                               7879CA1F19619A99174BF013CB62F85B
+                               FF2C3C4FE724E26DD0C10D7635A2491A
+                               9E7E868D9DAD9201465AA178184D06AC
+                  xor-digest = 08737B82505F46F4FF282EF42F387AA8
+                               0450058F5314389BB73733BC163D75D5
+                               D32FC6408F8DE5F6ED2050027D605FAC
+                               A7119FC2DC1B6D3E84E8048DCC42FBD2
+
+Set 2, vector# 45:
+                         key = 2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
+                               2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CA82A689535CA8BAE01BAFEBA6504B3E
+                               6E6320101999BCE5550C2BBC9BC65D91
+                               FAA2D72FA4BF46B6EE916244048B1D09
+                               A115E3AB6C00BAC8EE382B58859E8157
+            stream[192..255] = DE787B1CE01B0BC09801D78D1FFA3A82
+                               0C18B867C561E96DF4ADADC5A4375E44
+                               5A34F9457E5F8C9A337A0C88DF0F723A
+                               D4509F1449DF2C6AEC0EADF4C7A8139A
+            stream[256..319] = 7E1854FA15DF9D5827F1555F12B292C8
+                               452A1A893EF034C51750388D294947EE
+                               3F505839C69C1708E8323C449C39A96B
+                               FC9EC91B0E1CAA8112057EB0389FDFD2
+            stream[448..511] = C85B42B838FB9C3D4956C9E22FBD8FBC
+                               EDD92C4461EFBA5CF1664B9AF54857BE
+                               C3D00319E5E8A89A8322831151EE1D52
+                               D8585AC79CB60B61ED2C852D04BB0FB1
+                  xor-digest = C65A6BEBC4FE898DB8D6B8F6E8F3680D
+                               2363BC12259B0FDB2BD8F052A572ECA8
+                               D1EF62AA9A48497805A413742B5AF5A2
+                               6DC9FF624B49E5D6FE58BBE5251B4983
+
+Set 2, vector# 54:
+                         key = 36363636363636363636363636363636
+                               36363636363636363636363636363636
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 9F6BCFDE566A1B67C608F11B8461E340
+                               42D4F07DA4D5EB05554CB7426D65C5EC
+                               A93C2D321175B6F72FCBEBA6E38CB098
+                               B72534F7D534B1AADD97B77E8513B482
+            stream[192..255] = B2466A173F436C8433F264CBF125B8E4
+                               C10BC81BD46B5C21FA161CB2AE07D27B
+                               F66812A2C2FCB2B14C23E413CEF4E591
+                               AD52EF810A000B42E5C1B76EEBB17739
+            stream[256..319] = ECBED2058DC50223614EB8635B834C3B
+                               B176719C18CA5E3D087A93E5CDF81123
+                               C6FB819CCAFB5042AADFED5E3C33116A
+                               FD92AA21031165A22F4751C423B8B945
+            stream[448..511] = 758BD9435DE607867DA256064C304C8E
+                               DDDF5B64173CF2C98B2842992F8C5FE1
+                               A37C3227B7F37D49A39F9FF929A883FD
+                               56DB8B1A174E1E55FCB21C9E1164C20B
+                  xor-digest = 31761A49503946701D35306FBCBE10E2
+                               02967E7EC14A328B4DB19FE79F03553F
+                               13A012B7297B2D02F18A216AD24A682B
+                               299518C3769123EE86A4937DAA9FC39B
+
+Set 2, vector# 63:
+                         key = 3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F
+                               3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 85C7FF83641ECF1C91B2D996D4EAFF6B
+                               26A4E7E34C0CA9CB9399F655E566383E
+                               246143F57776C8E08951E87F76091FE7
+                               2356CC901F09A07895A890AECF047B3F
+            stream[192..255] = 4CE0C6606195F7562D485E32E8E105AF
+                               C862100A07E55FB449BCFA2D9BD48658
+                               958B37B3EA3565FA66824102A14B5770
+                               5E3914E0680E116ED58212CBF61028E3
+            stream[256..319] = 3BB772A5A8DE2AB14CAC1ACBF45B1701
+                               057710F24C01E680F58090B8E949AF01
+                               8970A43A698A04C0C8639FAA665DA3AA
+                               562B2C5C3A03BCC38FE75DC1821ED718
+            stream[448..511] = C73DEA1F7BFE42DF75EA2681BEB31948
+                               821FBB049DAD15B988A77C0247868A38
+                               2056B66F47B0195FA30C9DB5A2334A9D
+                               CD7C0D22E479FAE1BBCDFFE60F261C7F
+                  xor-digest = 94D41CCAD940CED3C854DA0796DC62E5
+                               6B566A980E34F353CFFD0F53AE9E34FF
+                               A6A057645FE66D86BE30F93805D9E2B5
+                               D78C68EEBF61CE387277A51EB2EF835B
+
+Set 2, vector# 72:
+                         key = 48484848484848484848484848484848
+                               48484848484848484848484848484848
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = E45194379659D1D8904DB3698AF8B245
+                               762910B7FBD019AD1AA20A6C433B4C80
+                               308A9EA68697631646BF3A2107C4E7FE
+                               2235E8F3262A9DFD3F5CC23FEB0B2DAB
+            stream[192..255] = 012611EBCFF9F839DDABF99D9D4757DA
+                               4E947598C4757976F6F61DA5F0DAC8BC
+                               DDF72F08BA2F446FA37F9A490F6A2B6D
+                               79227C93271D6B763DA7B2A907220A42
+            stream[256..319] = DDE54F9170D6A4702CAF45CC6F799F74
+                               A43D83AB8ECBAC5206D108F869561D70
+                               F151A0037F8E28951B5026643F8B2D6D
+                               56A62E259F04A5EA304791A9468E66AF
+            stream[448..511] = F70794C084E6EDC07BA0347413B05FC9
+                               FC46994CA820CE4FC037ADBA50EAA9AD
+                               55064ACB7308CFCE3F35AD5C7C628362
+                               F4210FBC2D3264F734728626BABF5356
+                  xor-digest = 31815B36BA034BB1941DB1E45A941A59
+                               7C3882F34BD3BF441CAE8A9790B05BCA
+                               72049FD10C09A14AC9DB867A82C38A5F
+                               524C72F783DFD16980DBCDEB486FAE96
+
+Set 2, vector# 81:
+                         key = 51515151515151515151515151515151
+                               51515151515151515151515151515151
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3C04E21F6937C4EF472BFDDA89F9CAF6
+                               FF53889A9979ABA8F23AA51DB1EDB8E9
+                               D08F696C1100799A7D004DEF1CA94110
+                               FCF0C054B0C131E6FAE0FE2F2DBF22B3
+            stream[192..255] = 9B4ED3EF9639B953186FC7E732E7A9EC
+                               55A5F3F19C5A10E12EBE46DD84F10385
+                               33837693588D584FDAF86E3A217C3CFF
+                               020278736F1A90CE07F0DCE4329005B9
+            stream[256..319] = 135FAD68B5282FE59B28D2DF66463632
+                               06CA92E84A73FA131EDDCE89A5C23B4D
+                               08FA57D455BDB32F8ED58DAF3EF288A2
+                               7C72020E35DAE19B446E4C52DCDAC5B1
+            stream[448..511] = 7D08FE1CAA0E8A0362669B310B99127D
+                               18F2111002891D3229102D72605B9BEE
+                               F5DA36059B0DBBA7646927650305431B
+                               FDA4A97570CD0C484BF1E974B157ED7F
+                  xor-digest = 5125E77698C0DAA89A7E47DC5D038D40
+                               7B732CE56CEB674CE653A1B6661B2740
+                               0C092AFF83BEEE4FC4543B9D725C9387
+                               2F89AA338222ED677BF59397200AB304
+
+Set 2, vector# 90:
+                         key = 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A
+                               5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = DA2E6F7FF0D1F1C87A97E028D3E20E21
+                               75E9AD91482965B651B495AEE819CC6E
+                               C42AFE2C20EEACCEC4E90710D17210E0
+                               4CC6832905985322C8007F872D3E58E1
+            stream[192..255] = 09B0A38E19DDDA08F7DFEF7D0FC80560
+                               D692A020F0A66F609374ABDCD1343722
+                               05F19CA04EBDD3009844BC540C1B2B41
+                               66D45E8A2E822B906DA34649E7FEEBB3
+            stream[256..319] = 6C8E2CE1D7FABA414432E75BA2EFE4AF
+                               CE2CFE99506677A956AEC86BD290B6AF
+                               C5298A448D0DEFA99AA5CD26D318982F
+                               E786D809C713D5A55B42CA6650191DDC
+            stream[448..511] = 845FEA0A88B521CCB8927C9457AD3225
+                               EF6E3C21705EC9FB24873916A2C24668
+                               963C03FE097DA8224A42A99E5DFFDC17
+                               68CF518DE49CCAC8A70216C62C9CBA6D
+                  xor-digest = A46BFD9D2D0BCC688A032F54733AB7C5
+                               5FF58B296071D5D39349A531E41F0BA9
+                               893A1722B6102740BC5FE394A49363B9
+                               6A626AB43FD6A288CD9B23F7255279F8
+
+Set 2, vector# 99:
+                         key = 63636363636363636363636363636363
+                               63636363636363636363636363636363
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CF0E05248AAD82F1C8CD2095ED2DA333
+                               BCB02E3AD8797377AE1F1B4D6DDB86E6
+                               2A59791CB553550E0492FAB42C7A2C42
+                               3157C5092D2DD37D46589F17FBD86584
+            stream[192..255] = 9E946626F1EAAEDA42E52422B4A84D91
+                               4122EEE5736BCD12061C77DF5B0122B5
+                               1784E946B4E93470170ACDD7E2779591
+                               57BCC9B9F3E11E88BC2F740AA0C10C97
+            stream[256..319] = FF22D8196AB3DF662210D12D0FE79255
+                               6DCD39611C07F089979CF7D693A30CA3
+                               5B795B7F6D64931916E717C8BFB92114
+                               DB75118BDB51D142CE8133415C6B3456
+            stream[448..511] = 971F007EFE17662D95F47F4F28266516
+                               B22A1E50755EEF19149DE3A3121F5FEC
+                               E0D9DFE7A055026CA44193542D7687EC
+                               695B97769BF02F92C1EF3D904A8010C6
+                  xor-digest = D1C4878BEFCE48888A43C6DDE7CC8163
+                               C8D54A4CA36748C74721C7B6E1649A31
+                               4B5B7A4BD43E7C3D2A22F0C8446C7892
+                               90D54D421D37CB16400E59CC86215CC8
+
+Set 2, vector#108:
+                         key = 6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C
+                               6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 54F122FC8ECFB176E7F4CF172B2D78B6
+                               54BC11ECF0010D2AEB9F899130F4AC2A
+                               38EBC15C8831D591E6675DC1CE7A471C
+                               4B869FE83CBF37AC70BAAE5D4AC607F9
+            stream[192..255] = 518F298A6008532EEFECB3DCF72103BD
+                               5E3F84FEB6EA2311E8C19A2E93A9C3C3
+                               BB1DA7DBA78D5618D1C4FA5B0B202728
+                               62645A361E55494D66C9359E41E5809B
+            stream[256..319] = BAFFFC9206D1D813F3E2768F08D78B2A
+                               89BB20CCD92E7F13FDD816DD4E4963C2
+                               C5FC2570CBB8BB5C70848B73001F508F
+                               47AF179528200F51CDC6E4854EAA63C3
+            stream[448..511] = 844B1D15FBFD1264169279ACD525611F
+                               A39C7BB41F1E7A1C09090625F7926E51
+                               23A4CD7FE1A3F37ADC67AC437BF0A5AE
+                               FFFC6FB0ABF39D9908145004AA5B958D
+                  xor-digest = EC67596C9DEF4012A2D543842829306A
+                               4285A3B8038818F265065DC848BD80FE
+                               C27C2F66A57B27F7FA8AC912001EC954
+                               05BC6E93D7E555C59060F5D2E294D103
+
+Set 2, vector#117:
+                         key = 75757575757575757575757575757575
+                               75757575757575757575757575757575
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 91D2772A18995DB3C0801DD3740F4466
+                               F9535E5BECB93DDCA0E94D19C0B57BDD
+                               0FFBA9DAF0B11D55C852927F8BA560EC
+                               4999E25848D08FCA7275E7E8571A5F1C
+            stream[192..255] = 72E64FF10CA9F07CC493715724DA7610
+                               9E4358E8B0CAE451348B784A162DF036
+                               AB9796724D17FDBF356031D080A6631C
+                               D1E8D217B041AD2EDF427972653206B2
+            stream[256..319] = 4054F770C93FCAB533143FFCA8E4C0F3
+                               344956C29D10374E502C2EDD177ECE5E
+                               6625BAD9630DAD57976216CD69865058
+                               130B132FEC1AB0C350DF4DACE4C7724A
+            stream[448..511] = 40B4A4DD63F7B6E932482D0E6F5BBB90
+                               E402466550B518A177CD05985D238827
+                               BD92EE7EC22C274F19E682F85ABDAD95
+                               D0EBB3DB6C6134408353C8B0472C9A1D
+                  xor-digest = 9A6C893F2108D13A29373DEDA65386C4
+                               AC356BDDD4A3178952F9126E322B7AE6
+                               83C94F1A131CBEAFF26549D9F84CF04A
+                               1241FA374B055B0ADE7E49E8EC669E65
+
+Set 2, vector#126:
+                         key = 7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E
+                               7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 87A7773A3514EB7F882F2C491E90DCF3
+                               059C5CC575D806B9029CCE3FA45A246E
+                               0EBD3AB2F2E324FE36ADC3B56AE2F7EF
+                               C710AA964CB87381386C2A88B1308035
+            stream[192..255] = 415D6F59DD004944D4E45FECC6F1F06E
+                               20BEB18D9C84187C347F43B17E0924F1
+                               2348F825E106E57A00258CE4415294D9
+                               4323A9812D8A71359CEC1001BAA0D567
+            stream[256..319] = 8E20F0D03F37EF4B2C5EE12B5F81F7C5
+                               32D62E779FA0D2D08F8ABB6B0183A4DA
+                               4EE0329215F261D953150B9AB9FCBE2F
+                               568AAE361EAA8636ECC01A63F007977F
+            stream[448..511] = E7C44F44E06321A20E25F73E2069757C
+                               90499DB7E60025CF6D2D445E53A665F3
+                               08EC96F6FE73C0AC90D7E4A712E18C2D
+                               3DED46DFBAFA24C4B0B329E52C525976
+                  xor-digest = 22035341489FA6EEB2A6488CA42F4043
+                               57477C3F55569A1224EC39B1019E90C8
+                               21D37D78ED4DCEAF6EA70724C3751760
+                               38CF25DE4F84BABD80424D83A310881B
+
+Set 2, vector#135:
+                         key = 87878787878787878787878787878787
+                               87878787878787878787878787878787
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CEC0C3852E3B98233EBCB975C10B1191
+                               3C69F2275EB97A1402EDF16C6FBE19BE
+                               79D65360445BCB63676E6553B609A065
+                               0155C3B22DD1975AC0F3F65063A2E16E
+            stream[192..255] = 5E12BA9DE76F9ABF061782EC1C4FBBAB
+                               3373B816DA256CAAC37914B0C161E4E4
+                               5F5ADBE444098A5B2A4CFD4251D79918
+                               987BB834BB50F0834EF4985F356B92A2
+            stream[256..319] = D89642D25DF97D149AE07EA18BA39497
+                               8935978AC34C1DF9F444986D7505DB4C
+                               7E08DB3616B84CD52E7DD7FB108C36B8
+                               B50C2573172F4D3500B6D62A9D20B82A
+            stream[448..511] = A2C17FE7371604556F796429C6BE0688
+                               8611638B310F3E9FAF484BA9EE29C16D
+                               2F842EAF33AFEC557B68D2F453569187
+                               A6F4CD204A0E7A733E81AB7CE9FCAE81
+                  xor-digest = A7C93087CA70DDFE5FA5F1F2F954320B
+                               6E3A61977A7C6AC2F033B826AB9A9957
+                               66671D2A1025CDF8E2824B2F58CB221D
+                               2A68679239D90152FF7D0D39B33FAB93
+
+Set 2, vector#144:
+                         key = 90909090909090909090909090909090
+                               90909090909090909090909090909090
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 7118889F6E46A6523BBEFCDB006B3BC6
+                               71A6D390BC7099A708D370DCD0E3D143
+                               A0334619EBD5C7DA9EF6301F29273F85
+                               2DFA3C580ED65C6E952F88A0B7FE368E
+            stream[192..255] = 31D61E133CA1AAE400CB2DBBAE93C75B
+                               445792061AA0539DA69ED0B77B970C0B
+                               482156A5DEE4082A61364BF06E692399
+                               FB9F4411FEC515291F8949B20F57229E
+            stream[256..319] = 993E815F299D4841518119BFF88F6EFB
+                               F3DB9BAE60238BDE2845DE4DBA6D79DB
+                               C9E42BA5C3C004AE4546FD86C660FFC8
+                               FD6A8A349669FFE3D9E5BDF8E50A407D
+            stream[448..511] = 0F9CEAC6BDCBB56B7E97DDC95877B2B2
+                               1274F4A6D814B5440C74D53A3FF0735D
+                               EF01B14AE4188E215CE7337C04871688
+                               7159695A241BFB9D6B489FE9E23B2AD8
+                  xor-digest = 0BD5739ED28778023E6303FD88DAABC4
+                               0FA0A211A1A5C5F230D9E67DDD9EA517
+                               FEBCDF0BDBC107291B6CF3ACD8B862B8
+                               4BF15400493A54036E97FDEBB9A1DB2C
+
+Set 2, vector#153:
+                         key = 99999999999999999999999999999999
+                               99999999999999999999999999999999
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 236ECC5AB83DB1C5CD1C5A888CFEA2DC
+                               BE99E7E515650511FF7016A0EF287ADE
+                               5A03839C4F83F05FAC3B0B24D4E3F602
+                               3251F8D9CC4530A805F8A6A912EFAB1C
+            stream[192..255] = 792823ACE2C0DDB266A118068AE295CD
+                               716E424D3B98A9DB2501A3F5DF7DC70A
+                               3BD2C6E664D5E13317D6F57B8774C903
+                               D407D2BB6014E0F971141E89569C5868
+            stream[256..319] = 2D6ECCF738FC00ECD5475EDA959A73BB
+                               304C81FA9DDE0C21592247C4098D9347
+                               1DA30294DE8C100E5B17A199F744CAC2
+                               4E33490FC7F223FD6B4923056117C6D9
+            stream[448..511] = E791A6BE7F7593788E5D627F5CDAAB59
+                               349AF2BB1DA2BA622B9824F729929098
+                               BD19DFC05D0D9454F604960C027752F9
+                               7812E53DE6AC6CD2751AB331703646AF
+                  xor-digest = B7C5CE0D2FF66533A1C948C425F33FF2
+                               DC458E7E517637596FC8FB710E2E5636
+                               DB1F14848CB12793D54ABD0856B22F3A
+                               ADFA8C33AD08B8CC5292DD76913CB105
+
+Set 2, vector#162:
+                         key = A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2
+                               A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 74490D19F13E7C6D1B25C6408E23F229
+                               8A8806402755660C4A30CD216A500BB6
+                               AE975E08EC62D08425A8A62A71B00215
+                               DE35E5178902348698528CB82296F009
+            stream[192..255] = 51A6EC18829928EE94C37A5CD030CC4C
+                               E4F7E1B3E78C3A5DF07592F45B968BEF
+                               F95B8B257DAF2B468284627AF4481FD2
+                               67BE0B164DD86721DC8C1607A0607EF0
+            stream[256..319] = 75C565D5A5A240B003273F99BEB3E4B3
+                               9C056162B626F383F3E77B5C98C0FBE9
+                               119A7C335C333E6490126AC2510CDFAA
+                               86441C72D1DD9ACBCD3FEFC0D0C794C7
+            stream[448..511] = 2D90CCF0B43239D725E3B53C31B82754
+                               246C065AD23A8D709161FC74B34E23DB
+                               B918EAFA4465125D3780BF0B5803AACA
+                               037AA0A14D977141B611A6CA2278B634
+                  xor-digest = FEFDA1A6E95920B93380CC24FAE214C5
+                               6B009ADCB176D519CA4B8538EDFC95D1
+                               6CA06B730B28A230F0085FE43CBEE2FA
+                               2EE5DCD74D66F5CBB59F256CC1ED885A
+
+Set 2, vector#171:
+                         key = ABABABABABABABABABABABABABABABAB
+                               ABABABABABABABABABABABABABABABAB
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 22E1A884ED2C67CCB2977105649B6544
+                               367858D1A730AA2FA96703FA406B337A
+                               B2159A389BEF48D8A215D870B2968E16
+                               B11571F12BEC0A07FA7D3B9790987EC7
+            stream[192..255] = 4C98DD259D03A40AF38E0ED0F37CBD74
+                               B27776E9250B8B063E52E169C7B76A15
+                               0D699278AA4124427B5EB6AFC4AD5DBF
+                               600FEAAA98A88DFF297DACA5ACB4878F
+            stream[256..319] = 5FC732A26406FF0DBC764ACB05C83484
+                               976B640E60CCD6ABFB908583ABEC3E75
+                               2878371EBB5374C9B37A63E0768AE10B
+                               D857253D940AC408EF49EDD590E806AE
+            stream[448..511] = F012E429C44D5DC03B88123855B62C0E
+                               90E06759306017B5773752973850531B
+                               C480316CBBAEDE6353AD5FB298349AA9
+                               16AC0221A4CE1E4729BFB9C230AAF9FB
+                  xor-digest = D73B872315F9052C67C4CFC5CD912DBD
+                               60DA32FD06D9C8E804968E688898200C
+                               1D979DFFCE52E1C3B3309B58D12BDBB3
+                               D3EBA2954D1587D720E004E12EB4A13B
+
+Set 2, vector#180:
+                         key = B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4
+                               B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = BEF4DD0101F80A8F880BE0613B2AAF88
+                               D2EF924014F7445ED922E9C021571909
+                               D7E6BFCAEE0724F2A9C522C4BDE4BBE9
+                               FE53FE592C0FEB80D2C7A51FB8BE9EF3
+            stream[192..255] = 6B1966D3EE460999FF09001B0ADEC484
+                               0D22CDDFF39EB0E3D5FDF74C6E7B3394
+                               A0A4271D780DE6DEE9AC58B4903EEDD2
+                               6DD14E14A4DFE506748D5DCA6DDF4C5A
+            stream[256..319] = E79D99119996FBB5163335E2F79F0502
+                               7AEA5372136E7B3C5BE1F4A673A2DC74
+                               60834B81BE6C4976C4A727C8E6046A64
+                               4CAF42EEA6A068B7E532581E9037BE9F
+            stream[448..511] = 5C4F52E0E94884C829DA1FE88EF34614
+                               9F3EE55A136EFA3B417DB63D2487DF82
+                               794E161B3153DDB2E1E4F385E1A848C7
+                               729FF5CB1CB58D5E73FAB1F2DCEEE5AD
+                  xor-digest = 2F3C231B0228C274255F3BD314ECC7F3
+                               1B9C49177009AFF2CD88F807092D77E3
+                               C74C1B9B8650F581EC7603F4D6E70955
+                               1B00C3192414C04AB0AD8B0B9BCFE988
+
+Set 2, vector#189:
+                         key = BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD
+                               BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 05AF4F98E9D526CD7912F3E8CAF45410
+                               DED6D4E331633C5621B94E7EBD15E856
+                               04AB202A553EFED55A548C7AFFCD2550
+                               60315FD50A305D8BCAC9C077229D34AC
+            stream[192..255] = 786D24EF3FBFF6883A4ECC4F40E445AF
+                               3CFD130D5B6A9CE37BEBA429AD137A82
+                               44D0586FEB16D086F533D1885A82F73C
+                               F2AD2C645591F80ED09942F0A08D898C
+            stream[256..319] = C214B6AC700164FA66DE346A27A99463
+                               C5B6C0E43A9057384BE168E163058FCB
+                               6E7DEC871C6531EFC8B8D581EF92757E
+                               219294D39E0C9C8276440BE56C3D9941
+            stream[448..511] = 22CF14F5BD70E719AFE76C53E5D611AE
+                               4C8D2171695C9CF97E2936A8BB320670
+                               015825547A508EB43D96F2EE1EE2CB34
+                               4E120F001500F8ACC3E19E30455D09D0
+                  xor-digest = FE5928C74EA21F23E29171E5AAACA20C
+                               DD8571E907763C96B99A8C11F9A1D2F5
+                               78F68A6C440996995F7AB6E69B3CCE33
+                               CF8CE0C16F54355696D47DBF82EA8D56
+
+Set 2, vector#198:
+                         key = C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6
+                               C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 75559677D7C762F6CFED942D800F2FAB
+                               AB5F3892DC2C79922E96FD34FE511C11
+                               251C8EB7C639E531CE08A8C99F62E7BC
+                               F68FBAFF99D62348FF91CCFEC2710055
+            stream[192..255] = 149806A4D862EEA81F0208D927339E5E
+                               C98E9C2A6E0DB85CC0380DED7EC5B8AC
+                               4ADAE76AEB9C7B7264C3834316209615
+                               25221D58C0174577110596FF89C8FC69
+            stream[256..319] = 137E527A0ACB8B96A9FA07890B60B78B
+                               3CDD19BF89B31FF75A814F470BF97E0E
+                               1293B750B769F5BDD750DE5025D7534C
+                               AD541A1F26C6AE9AC2FD3237C156AEBB
+            stream[448..511] = 0958243E88921B81F04AE63658E52D76
+                               CF2638495B3A6B970633A7C8F67B8CF9
+                               AC378082F72FC63BEA02881CC5B28D9D
+                               C8C261C78B2872B5EBFC82336D6E1A28
+                  xor-digest = 0084D7BED4953402FE8F7FF71A28CEC7
+                               0028A08A00EF935C06A8B3632DAD5914
+                               84E44E372A753F8E630741266C0F4218
+                               4923608103042C70ED4ECC5112B9AF6B
+
+Set 2, vector#207:
+                         key = CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF
+                               CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 0C46BF67A3DBA5DCCF8E4A7A65B6FE28
+                               98C701CBF5E88F1F3DCB6B873E5CAEEF
+                               23024ADA678E1A2CA9E25AA8B476CF4F
+                               9FCBC297FF03A9B94A5A736274EA776C
+            stream[192..255] = 73B9891D1770289A67D6338909FB6282
+                               9A425B7947FC30DC52B11E398E85B1EB
+                               537E1C02898FEBFC15A9172C254CA55A
+                               AA1B56EA856F47E37E2F252D92D94ED8
+            stream[256..319] = 6522D372F90F2DAC155D48F165B6DFA4
+                               38B63B9F436FE00CC075C585297B8F90
+                               E6062358D29641FF9C28EED4A23FC53A
+                               6B5C60C2AF1E8146DB27CCF5F43BA838
+            stream[448..511] = 642541A9733946827D79BBD815C03C17
+                               6357BD6E81E9A61FFFD4A0BF6863AC71
+                               72AEFB92C1F235641BBE1457B724A6AA
+                               AF9FAC687552A778B034C4A4F8E41ADE
+                  xor-digest = 9DDBC1E7D31379D027B4F3DFD72C3668
+                               BD0BC5A97655978E79056B3D25DF3E79
+                               5D5D8BE5D1AAE877F2E7D03225CB6609
+                               6EFE11CBCB728039A243E326437CE73B
+
+Set 2, vector#216:
+                         key = D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8
+                               D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = DBD4E866F4E24E7F66816CAF625BD07F
+                               1F7BDFBB81428FFEE9FBE14DF5F5F3D8
+                               A044EF53A868D989E16165A0F2B95E8D
+                               83439BB4805A125AD0CA7994AE11B852
+            stream[192..255] = 7CACC4E7B9B1957ABB22ECB9D9D67184
+                               EE7A7F4B822A1C955A69E238022AA313
+                               276C2003E27AEF1B4F94B33A6428685B
+                               F048B357EAB297B7DD98E612F054A317
+            stream[256..319] = 286B484FA80A45EE4D5300DFBE173E8C
+                               978B976BE1B6CB0D15C0324D6B70D265
+                               385B615B3EA97A55D94C47F53FF40861
+                               4460857AC9568556AE54A52546B41B5A
+            stream[448..511] = B3AD999394343F6F0BDDD0B1FAE2E3A6
+                               5BE2BF56D2B78A401D5761E2F3AF8B18
+                               A2B1089864999D9B99E5BF6959F8F802
+                               975FBF204D6159CF23F3706CAF0D9BA5
+                  xor-digest = 0957D6887501D4360C430614B67D99B5
+                               32849E2F5C69CE8A9F3F707A2B5438BD
+                               0C1237B5617FB525CC9C043A10DBB265
+                               3C3F0A353E89A19838B8F68542E09526
+
+Set 2, vector#225:
+                         key = E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1
+                               E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = A6DF8DEE1EF7D1AF773AA3E9651B645A
+                               50CF101BF065F69F3E78BEF5D689B1D1
+                               D306FF41EB3E78BEB75C4200937CFE60
+                               E89E370680C519B2F64E23516ADF8062
+            stream[192..255] = AA30580A210B87727BE17EC52AAAD037
+                               3E0DD11FBFC89B37825CA4D6F9E8D433
+                               E3EA54C37D678B58CE834AFA310F6D4D
+                               06B4603F12DBF38595AC76511D0B13CF
+            stream[256..319] = 5F3E1A55116CB67BC91C8E37182EEEEC
+                               8FC9B09DAA6F418D3434BFBBFF6BFFFB
+                               F93F8A963F2F51CC487BE868F010EC0B
+                               EE17A480542A301E33B36F59BEE13D91
+            stream[448..511] = 672048756C221C12DA6178BE711B3371
+                               525A92BC9A219CABC5501B0DA4CC248B
+                               8742E8BCBD6F5A1CFE522F3DF3BED6B6
+                               5D60D1AC737ADC582C2CB9751521828B
+                  xor-digest = E7CA739E4DE0E74274E491CAA9BF5CAB
+                               3F418EBEB69509D69B2594E964759D15
+                               104F674CD44681AFECC3B4939CA0A0C9
+                               DD7AA5726653ED3FBFC833DDB0C87B42
+
+Set 2, vector#234:
+                         key = EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA
+                               EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 2479A8F2872A813D16D15F060D300237
+                               25297B812F6F3B97D74D9716E4403A5A
+                               684D2BFD1E15275470FEDADF1578277E
+                               44C6C06B8A5FCE3D0CCC5E13BF49947C
+            stream[192..255] = DB2F9B25F9523FF5C2CCCB808EFE07F3
+                               132D4B0065A563288F848E05EB45E48B
+                               D15C069C02F90B4FC10AEBF1AF4BF90E
+                               2CF7F48C8CD7A8091014131EBC21FBE8
+            stream[256..319] = 84FAF79797E25BF2CFD54E58F5C7AC1C
+                               EC170B064429EB832924CDA9C47B5174
+                               9BFEF80D96FAE36DDA65659FEA1CC06B
+                               4EA3A1601A3304AA4DDBEB62381FD4DB
+            stream[448..511] = 2C8FC8D23E7DBBC37BB0811D1BC71145
+                               BFBCDBAE19F5281CD0E6AA37419778DA
+                               64DDF68726DD7F4D78BBBFF4576C2AAD
+                               93F477A2AB2C3CA8A381F30BB944C7B0
+                  xor-digest = A6D5F0DDFC0A43491D6D0A17C095C070
+                               9EC7E9B89DB8EEA11045ACC5FF003DC9
+                               CD3318BB6F9675EEF20E15490F525066
+                               AF8380C663B60EDBAE30663C94C39892
+
+Set 2, vector#243:
+                         key = F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3
+                               F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CC3701E703946194401D1BA23AD99B5D
+                               F3F856138E142D4B9C23DC9F252A277B
+                               D62DAA33A71A0C61079AD5A20562291A
+                               B6EC92C66D7BE6A17E27D4DDB48EFD31
+            stream[192..255] = D00665FC0A4ACC78758EF25B0B0D6903
+                               D565423614409AD11E821B83F5B35D83
+                               F26F3EF9EC1766FEA9C21C09E0AE248F
+                               4BA01E48BCE09D06471593B3466703DD
+            stream[256..319] = E8B4EEE2C8BBEDBA758C1C2D0889FDDF
+                               96CDC215EF1A62FAA29A5608C852FFA1
+                               18B473C5A7319446F3ED2E8AB39A533D
+                               714325D1B14E838C9EC6E037DB0DD93C
+            stream[448..511] = 4FF3B43841B17A279002EFB07324625B
+                               7E937D480DC73F12836195110ECB4DB5
+                               CD31CA4F92F612A95E82815328DA7D5E
+                               4DCC5BB6791603EDA64C57B5A5AAA04C
+                  xor-digest = 9202B874C48D4B1A9E857E645EE8F884
+                               D971CE97923AC024ABEFB944E34550CE
+                               31712BB832F9174F86FCD369E75CA9AD
+                               85095F43A4B7F33AB641BD6912D2C59C
+
+Set 2, vector#252:
+                         key = FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC
+                               FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F374DA745A5CF93A567027609E5D3B1D
+                               5C3C8A4D15203705D978AD42279F6548
+                               51FF713F5120CC93D044EF717F5A75E4
+                               98DBEF559E5F157A8C819E213E93B3F4
+            stream[192..255] = B270F638AAB88DFF69D724F79B70CEC9
+                               175AEAA99D55485954B265B5CAB86509
+                               C810E664766A8E6C90D4BEE3A58B1815
+                               9076959FFFA2F30EEB12343E9E7778C5
+            stream[256..319] = B2CC84A1127B5333B30EC81CC14307FC
+                               418DA96336991A27DADA74FDA987B867
+                               B125C53C0E4E2889FDFEFBFB48797A22
+                               2836B2EA42793CE2BFFD568F6234B368
+            stream[448..511] = B70F4A10A1B75D499E8189C8B92AFB36
+                               4CD2D730DC8D7E183EC55A777C2445EB
+                               BA7E9CD95C8F3A206B73C422AC2E2C08
+                               15A8C6FED156FFF93B63DE512EF69725
+                  xor-digest = 467EDA43B849054EE747A532ED0D9AA4
+                               6EA1BF2B6AF19F481D6E3D55EBAA96FC
+                               6629FE65B5EC4B5EB6A155A6D60FEA32
+                               F04F8230E26390F1C8FA53D47B68FEAE
+
+Test vectors -- set 3
+=====================
+
+Set 3, vector#  0:
+                         key = 000102030405060708090A0B0C0D0E0F
+                               101112131415161718191A1B1C1D1E1F
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 7CB997D6E1B46DD7C0A9629B441C3771
+                               14D6C18F230291FA7EF0B039AEDCC9AA
+                               A4AE05BA13F3931E3F8373AA320A8BCF
+                               28E825B2084D0FA486BE52C92C3C6F14
+            stream[192..255] = FD4DC85E176D76062323B2F5B31E219B
+                               786596F3DC0A2AFD31AB48C5F911605D
+                               556399114B0779F43221FE5BDA899627
+                               BA6498C210D5AEC5FEC8733357571F77
+            stream[256..319] = F00E84A92BEA966DC8359FA63B12E8E4
+                               F5611F6C8CDD04CE9D605D770B2EAE49
+                               D6976272057CF275EB5B4CC434EA9B0B
+                               8CD9FEA22D7E919097CBB36C5D239BE6
+            stream[448..511] = 110560BCF38CC42478036CC228E9DBD7
+                               4C44863DAFC81B528AEA2893FDBAC7BB
+                               2F68CCDF566E1602623EC9AE283EA69C
+                               C032E90E409F368E28401AE6905BD4F8
+                  xor-digest = 9CCCCDF3F7D712D6E3931068138F9A9F
+                               8640478BEDFC3C7CD0802954234DD07F
+                               99F4B072D9847DEC2E16FAD0ACCB3609
+                               16243175C84A317191A98AFF5EFCEED2
+
+Set 3, vector#  9:
+                         key = 090A0B0C0D0E0F101112131415161718
+                               191A1B1C1D1E1F202122232425262728
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 0889D6D9E155FC208941B945F2B15362
+                               3CE5C79122C1085FC172836FA9B06C0B
+                               50910CACF399EFC9CD9CC484786AAC8B
+                               377972E9A90D7EDD40A59FE1B942710A
+            stream[192..255] = A540BDE9860D8687A45D8CF22E00299A
+                               36BE590AC92E70BA03B8A5F2898C2D1A
+                               B9B1E5C87C4B10C9B6E08EB868AE3B10
+                               3BB95C30831B903A3A9620ED16B96210
+            stream[256..319] = 90E2A684D3960A4B1DA5DF19BF569288
+                               5A23892F2003AF2319FED9C8D37B8702
+                               7E61290E013FDF93683829DB99C177F0
+                               222EDD6A0FE3D5F7F903D3CC15C6C6DF
+            stream[448..511] = AFE7454BF77E3CE1050ABFC2E25F9B15
+                               011F33B93660EA4AB5E7BFC513F2D787
+                               27F8008ABC1E14B06C36F7750AE88C1D
+                               7AA2F6EB9F2E925CD6CBDEC5FBA3EEA8
+                  xor-digest = F1A8C58EA8459686DC5BFA2A81E80653
+                               EF6141903898D1A3C7298358A79D674B
+                               A971C106CAB035722F246D3E67D34543
+                               3E71DD374DAF73036EE55E6C0ECE5FA3
+
+Set 3, vector# 18:
+                         key = 12131415161718191A1B1C1D1E1F2021
+                               22232425262728292A2B2C2D2E2F3031
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = EB11D29C989FB09961A673D8412360B4
+                               F4E6DF0169A3CE207656A7C72D6FB8D0
+                               95CB3A7A6CECDC2E167CD35F62A00110
+                               EF09FD32B61A8B405A3F55A1313F0DFC
+            stream[192..255] = 8ED27EA005A3E298560C829380D4F1E9
+                               F0C7FD5285F04AE6FD66C94CC07C8C51
+                               EE8163B7414A52B0594C5F7F80104D95
+                               0858C9A52F3C156ADAA025C00B180429
+            stream[256..319] = 12DA63247282599F2C50B172CDB4F31B
+                               20952134800FB8BCE743BBA90E6485BA
+                               057A9C5E0989A8FDCEF1C88DD54E920F
+                               7028EB284306FE6A87B0FE063DAB9557
+            stream[448..511] = CD447E9F58BAFB77F6E02AB5A692120D
+                               EC4F7BD597DE5C54523A7944DBA6A3C8
+                               D00000D3E70F7D9292B7135A7F054812
+                               4B98680DEF6631D2D10E0E7B08F188BB
+                  xor-digest = 6EF765CB84937D5E829A1A1664EBD23C
+                               B474FEA3C5AB137F2D9B35BBE0816EDD
+                               B26EC14D74EFD0F9768C521A6FAAF122
+                               B5E34A36344FF0F0DB3CC2F2780D05E8
+
+Set 3, vector# 27:
+                         key = 1B1C1D1E1F202122232425262728292A
+                               2B2C2D2E2F303132333435363738393A
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = A71D4189D1338531D3C03D00A480C8B8
+                               49C779B7E113FD8D59516164C161EAE3
+                               AEBF74542FFFDC2FF8C2666FD5AAE413
+                               19072673F958F498F8FB9743BE46863B
+            stream[192..255] = B0B3803396AFF1646369B6FAE62EDBCE
+                               5254E7C8FEE88F9EEE5D8A7B6D44ADC8
+                               B89895198E3C147FAE0C9B8325EB3501
+                               6EADF77C5D7F402CF3168448D2A59E23
+            stream[256..319] = C1CCE6956C8257947C004528F568E3CA
+                               BE9ABF891E2FC2B52D9A1E6EC97A22B1
+                               FFD1C77E50A17CB47014C9EDA1853AFC
+                               11526F6268102780ACB3E0F120398AD0
+            stream[448..511] = 765857312C8994EF6BC7259673F02E38
+                               B7E0A764FB70534190033FB1BA86D5BA
+                               3BC6851DB596970A2F60831EA1A31CAA
+                               96085680CBCFADD9C5F0330CB72AB5E2
+                  xor-digest = 30EF19DE0E750BBF6AB3FC924742CDCF
+                               62B2FE5F25983BB9777C727679CAA39B
+                               1280AB468051463E7EB287AEEFA5AD0B
+                               9C9DFCA45A3124D5F41F4B0AF5849E62
+
+Set 3, vector# 36:
+                         key = 2425262728292A2B2C2D2E2F30313233
+                               3435363738393A3B3C3D3E3F40414243
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 2B9B987B7CADACD2FA50A53A9F9F44CF
+                               4ED11B3E25FE57F1372C6D570B470AFF
+                               5FCF3BEB89D0692D873EFEBD26EAF3E1
+                               1B6892913F0CB27F3CA9BA20AF7A98F8
+            stream[192..255] = 0148F54B1D24F3D69A2086D6938898F5
+                               25BDB1B1F78C5F92BA21FCE803A52591
+                               FCEC9A1AFB0FB3B081CDB1D79D254845
+                               40EB9D624B5E113A4F143716722687ED
+            stream[256..319] = 271FF1107AA8968E0ADDA5371F40224A
+                               D8E134AF80D5ACDC9803B1B3A9819BF4
+                               8ECC3A68B303E1275FA97222F7E984EF
+                               9C73899433230FD746DA6101DE37ADA2
+            stream[448..511] = A66D3BB64C35C71BBAA3F5410F388253
+                               2B32897B1CC1AD610F3AA195CDC1EB82
+                               0262E817374384BFBE200339B284ADF4
+                               BFF6960B6A41AFA9D7C9B67B19C14C37
+                  xor-digest = 3CF10A4A8BA3E0DA3C0B63F1B913B57F
+                               BE47580DF7D90B13459A9BC98B93B014
+                               1185E910EDC0A5B37206542B17CAB8CE
+                               F050A4ED3D7097B6A0738095E4BF7A77
+
+Set 3, vector# 45:
+                         key = 2D2E2F303132333435363738393A3B3C
+                               3D3E3F404142434445464748494A4B4C
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = F32665A4C73608E133D85712D2CC9A76
+                               6D2B83311B3F44564A56A97ACC9B6492
+                               B282A2E62A435A7B7799073E010C78C9
+                               4B7B5BD1B25994D1CE31B51CBB13BE90
+            stream[192..255] = C9F24592930A0A9148486D77C1FFAAA4
+                               4E4EECB088D6AD38D73B195E576BEE56
+                               E2CDA968FEB85D19BF89391813501B02
+                               EAB39A2E78B8CC7456EE60EAC3454051
+            stream[256..319] = D8E1D09F074708379189BBFEB1E24053
+                               E0BB5980FFD0371265320C3047F0ED36
+                               A65CA8D0DDF20DC25B552E1882811C77
+                               6613DBB4297DC6C89E31529DFCD17C82
+            stream[448..511] = 8012813E7879B3E99C40821A97469BF3
+                               9D2EF3B888E3118275F47F8C78A5F7CA
+                               19A98B1817D2D7734E69C5ED43773D68
+                               FA100E2C37F40FF8E018DBA52C5C239C
+                  xor-digest = 8AFB9CD876AF4F9693FF4FF511D89957
+                               C8BB31D9DE3F21B726667681F805FFF0
+                               4B50850696D6C2E5C271D199CF49F1E6
+                               D366C7824273E99360BD5A294E415F0F
+
+Set 3, vector# 54:
+                         key = 363738393A3B3C3D3E3F404142434445
+                               464748494A4B4C4D4E4F505152535455
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = C72B0F98EE5C2D44260E929C70DBF174
+                               02C03543483178C8BC129D67FE2746E2
+                               E881F8439E2A11EBB3716ADB16207BBB
+                               91454A71C444445CE64003F0BB1F481D
+            stream[192..255] = 5590F4278E78AD19293525095C2F76E3
+                               B35A3858CB5912B62304180225BDC985
+                               ED955521436DEC441B9C742B3C5F4CBE
+                               94B99689048AF93E48472980D058807F
+            stream[256..319] = FBAB34E9F432546EC8C52750DA4D2278
+                               4C1323D4E3F4E9B63E65A7E3C8B2637B
+                               AA5D0A3B897113F68C63CCB78B5AB40D
+                               0A0DC3EF1EB09DF5C4770B343B6B5155
+            stream[448..511] = 78B0144CDF2692F0D0F164ECC8621F5D
+                               A00C401007B82AAE7753712FD6185E9D
+                               7ADC8CFEA6D5BBC2F3EDB8BF2C77718B
+                               6A424BAFD30C30934FC645FF05704BB1
+                  xor-digest = 835B5361A9C1F88223DE7BCA09030CD4
+                               67065AAE99198645029CC0AB9B9BD579
+                               14332392ED7A433A64D95B44CE228860
+                               7E029235580276BCAE88F37418FB641C
+
+Set 3, vector# 63:
+                         key = 3F404142434445464748494A4B4C4D4E
+                               4F505152535455565758595A5B5C5D5E
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 804025A410EFFBA58647A9F4B443BFC6
+                               1CDDC30CA04DA8DAB3EC6A098A830D68
+                               2683B59B76C60C09938E67CB41385315
+                               E2504B024DB808923B0909EFC25F0927
+            stream[192..255] = 7A4661190129E3F349DA7B44DAAFC388
+                               5E4BEEAC9308844DDA45E8E06637246A
+                               0E6C8C7D94C5F710CB78CC6E0CA82870
+                               8CA77B6266B41E3ED6BAA2940F1977A5
+            stream[256..319] = A3EBC22126B6069C674DB604F8C22B54
+                               DA68FB4390617E86C4FF089344BD0DB3
+                               887B3438E8EF8207FD89B2A485C0B383
+                               22AEB69750AD054F843DCA7995BB58A9
+            stream[448..511] = BAC68211F125B57B8CE5E42E644997F5
+                               2FD4B8A7D5CBF89ED2F6B5F4D4C7FA5D
+                               0CC34212160C6BA536BB7604C184367F
+                               2E088528F3B3A0A1B20F9249711162B1
+                  xor-digest = F628E74D1EB94591694631F1B2F12234
+                               38B056789D5C2ABD8CF34D9FA7B8C304
+                               5A8C2298B7BEBB90C7CC86895693118B
+                               2A43B7E8AC7E534DA7965EA720F19180
+
+Set 3, vector# 72:
+                         key = 48494A4B4C4D4E4F5051525354555657
+                               58595A5B5C5D5E5F6061626364656667
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 40409D9AD4CFCEAEB8FF613D32B59180
+                               F5DFBBF44C1B7209AD1AD5AE94DBBF3A
+                               83EAB34D2617ABCC396880BD5F5D220F
+                               F434DD575E66CA74BA32862293113C5D
+            stream[192..255] = 42D9EDDAF89B93DAB4AA790BC9C45BAC
+                               5E94575E175C2EB1CC08BB39019E25C0
+                               9B0F4F435ACE371BD9235C61C56A362C
+                               B1A64EE58F4938D59073C5A8A1BA679A
+            stream[256..319] = E40477D1B6C901AFCC4A2C429845C7B9
+                               0DF890C317A5B9D6368672C58E0BD5B2
+                               7E42DA77BDC2BF47F9AD195F7C192B53
+                               24FEF88E6B3DD1669A068E3FCB58B203
+            stream[448..511] = 7616AA094DFFD4BCF94E03C9CCF95C31
+                               8F247AEBDE281334F8E6F46271070BC0
+                               1AC838D8FCFE18865DD30949C68052C8
+                               6E93815B4EA9480B2D0B6A5D9888E597
+                  xor-digest = 1FE60024F188CC243F7D8221D990ECE3
+                               29E89847C9BD60AF23061E9C27C4908F
+                               B00D8813E680F00665658CEB077BEFAB
+                               5DEB41D3547DD645DEDBB3BF5D7B651E
+
+Set 3, vector# 81:
+                         key = 5152535455565758595A5B5C5D5E5F60
+                               6162636465666768696A6B6C6D6E6F70
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 1B8DA47812BF2353C17C89AAA8695E9F
+                               F553BBA44087D262FA0C710B69765F12
+                               FFE190625F58DA899B56FA7AB5E0E674
+                               4CA2B073517B9577712D7155E16A874C
+            stream[192..255] = CD2BB4A6C3D7211773421014611B677C
+                               C0A8107544ABF4F914F825891E52DDDD
+                               76EFDBEE614573FF9674EBC154A3283B
+                               439ED8197E1EE0705955A8B6C8AFF8BD
+            stream[256..319] = A626C40CD2C48AAB016C29020096DE28
+                               F03842E785BCE9D9E385D0B13B63F82D
+                               789588FFAB07B8CC0FFC62AA86D37CAE
+                               5CF8FD43B575F9F4D6E07465B700D47B
+            stream[448..511] = 16A3C84858207E141022D228079D6067
+                               2784EBB56E3B84F7DF07EFC69060E27C
+                               D1311E51F5893AE6BFF80D34464DC60F
+                               61985F8F88164CCA69EFAE568BEB546F
+                  xor-digest = A24EEDA74185884C5B287663C3F5F031
+                               2743CCAC657C702A29E0C20BDDE304AE
+                               A54A9292B447039D50479B6CE475115B
+                               8791854540E15D642859D10561AEF26A
+
+Set 3, vector# 90:
+                         key = 5A5B5C5D5E5F60616263646566676869
+                               6A6B6C6D6E6F70717273747576777879
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3F7261A3A4691A73441762D113EB7817
+                               4C515A96C5C93C514EE559E7F78A633A
+                               01F0891910D44A7EBB18768E3B912488
+                               6069CB5304E79ACA89F62EFEC4EAC11A
+            stream[192..255] = 5F11904F72123CE29D1D883AE5CD2A89
+                               2AB26C9167A24A57D6F64BDE3A8E1A93
+                               7C5347C585226DB44B6252AEBF3CCAAF
+                               2D5E60C56FBBA6068B35AA6A61C84A44
+            stream[256..319] = CD6C5B784854E0121933E77C700D9C1D
+                               7452999F859798499A339F78FCF84615
+                               A3190A2F558CC529E636922A1B75A3A1
+                               AF280FB3F486303093DC1564EA0B6D3F
+            stream[448..511] = 61B8163A84540727204F0B18D9CAED3F
+                               B5FA87089FF4E721D2EC34D21C59B93F
+                               95297725780DF04A5FE405FEBAE80AB9
+                               B8307B9A74774E76063F9218CE243002
+                  xor-digest = 944EF8435F32FF2A67CDA5FBDFE02C81
+                               0997D9C8192633A193D6122A051B801C
+                               15555BDF410917B9E5DB86F4DE8B9874
+                               3E9F92F903543AD14087F4E13A915DE0
+
+Set 3, vector# 99:
+                         key = 636465666768696A6B6C6D6E6F707172
+                               737475767778797A7B7C7D7E7F808182
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 71BA7454CF7F6CC93C89EB22B9D608EA
+                               0FACBB4358DD007421DAC1E65EE99161
+                               C542DF02611AF497B2D53748D0129C0F
+                               5B9704C8A6017507EEFB26B6287662CB
+            stream[192..255] = 92D5D35B2E02D204E68C1AD6C018DBA6
+                               7A1C90F563AEFC3D031FD3F7D4F5E2F4
+                               C47D326A9C49A0B2ADF03D9E7E429AA3
+                               ABF253E623BFB9EB040B5F5CF1FF68DF
+            stream[256..319] = D6C22BEA96DF94CE9D5D34E6231CE4F9
+                               A2D2F6097540F9A9160DE139E2E80D0E
+                               5AFE08131FE10F0DD7367E43D314D7F2
+                               2321B5F89DC64F286576BA599A58F48C
+            stream[448..511] = 43DC3ACAE02DBF68AB5B65A81630474C
+                               639FC4DD36FBED518B6471F7C3E70FDE
+                               23CF1E128B51538DE0D5A47F20A554F2
+                               09668FE28B0C4884888FAC438960CE7F
+                  xor-digest = 7B0EF650F3847E3EB15EA1CB64EE7189
+                               AA5B04F527661C00F4603E48CBE59F7F
+                               48498D80F6C5ED956ABBF97E6910EFB8
+                               341C7BC2E81E66A4B9474BE420DFA5A6
+
+Set 3, vector#108:
+                         key = 6C6D6E6F707172737475767778797A7B
+                               7C7D7E7F808182838485868788898A8B
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3C4CBA573D803324D099BE1F436F944F
+                               EE506CE77EBC01FAF0060B76FA5D2005
+                               05CE94AA15F3C4B1E0194264CF13878E
+                               FD36288EA4C2ECBEEB76828EB460AED7
+            stream[192..255] = FFA464FA648309E295314DEF7169DC60
+                               F63C90AEE9F27B534E11D25AEC454823
+                               DF6BD39C1F9CB46276C630C129536506
+                               187251D638D3867E96A84BD570F78461
+            stream[256..319] = 6BE88BD0D2257CF7EBF7100B442F68C1
+                               ACB94B6F8991C1461D318BB80E59A6EB
+                               8009DFF46B8E339A0CD4FB285ED1E433
+                               5FDBD65537D9CF1FBB0F9F10E17952D0
+            stream[448..511] = 909997D084DE4F6C910D57DB89E1EB56
+                               AB3F9974E3DB5935D59917CACCAA31CC
+                               E009324E52334BDD6CA971AF49982122
+                               B195229DF0BFE2C508E981D303061B2A
+                  xor-digest = 8B2B49D564662BFB29A9F4E1A3DC7664
+                               774D41168EA27505A2A518DD94C2A507
+                               0D28E1E69DA2F084DAB024E8EE2D022D
+                               BC73071B8559BE2FCBC2AE3605696482
+
+Set 3, vector#117:
+                         key = 75767778797A7B7C7D7E7F8081828384
+                               85868788898A8B8C8D8E8F9091929394
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 6EE8B7E51036B951205064348C222881
+                               624E9FF59DFED40AC6CDEA0945A39E72
+                               AD05FA929F7AB69BE8234567734F8F96
+                               D74DE6038A463BD8FB86224F5CEA0D45
+            stream[192..255] = DD9CD1757A95E616E99590E76620E9DF
+                               0BF811F73B70C5CE982FC9CECEFFC6BA
+                               F7DCA30517A9BDF44515262ACF297AA2
+                               2CAC3F216C12A9D0D6912578DC672D18
+            stream[256..319] = 0B7DE245062DCC9B1D8A945CD9A04938
+                               EB9BB258B4B7BCC263487B3599B1C6BE
+                               7FDE752D65345F00DF90896DF53244A5
+                               AB111134B36A99E2D2200B4D2003A520
+            stream[448..511] = 2566E8427BBAC7F0A35C6E4BCDD326C9
+                               D7164A9E1F767038A09A75B5076E05AD
+                               C51F008E9E3184FA4DC6E4764B381944
+                               BCB96B57FCE2339A01501BDEED46F8E3
+                  xor-digest = CC16803D36710AFDB1DEBC653DA7DD12
+                               F45B02349B87C3006DDCAC1635956846
+                               E4D7D6064D19012724BBF836A7DB7A3E
+                               3C12E6288F546EF316406D9C5E844BAC
+
+Set 3, vector#126:
+                         key = 7E7F808182838485868788898A8B8C8D
+                               8E8F909192939495969798999A9B9C9D
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4F4169DF51C9865A20D7E79DEFF7B121
+                               BD61F4C79AFEDD0598F55E9D9A3615AD
+                               19292095DDD83904B3683722A3337BF3
+                               4E98F63EB19927155E176F2E8D5560B3
+            stream[192..255] = CF82F8F2A46A898915B3E371BE941811
+                               682A8A0A20837AF471B5CAA4B4FB01E7
+                               F2B0CA9ED3BA70BE305587F1ED995946
+                               223032F94BB2ED7D418C95F202887E6B
+            stream[256..319] = 219C121E08F7458BD657AC4131221C78
+                               43DB5817B17344922C54A002F3F67574
+                               BEE5F7FFC7EFC5615444B51FDDEE8B71
+                               981FBFF658D2504BB53C13D0342258E4
+            stream[448..511] = 55C2A93F43F260EABBC1A173AAF80A95
+                               A7EA74CCEF6E29C52957AB2247126336
+                               CEA5BD0D08F873AAF733B3A11885F04C
+                               58542B4C8ED3E1BB7F7918C4E92926FB
+                  xor-digest = F69FE6EFBB4A6E65B517445069859EAC
+                               A9C19FCB9C1771E75266E5B4C39019DB
+                               E959AD97F2B8D7F1688FD0AC04AA7C2E
+                               602F28A63DEAA49A7BE1422B47CFBE00
+
+Set 3, vector#135:
+                         key = 8788898A8B8C8D8E8F90919293949596
+                               9798999A9B9C9D9E9FA0A1A2A3A4A5A6
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 3305344A71266B450B2CDEB049A048D2
+                               6171B39A88C25CFC0821E4F4EFE378B0
+                               702DA31652B5E1BAD9FF4C19C20BF329
+                               639D5942DD2209DB1D1474B6A7B41B76
+            stream[192..255] = BBD9714BF2C343B11DD7943DD8CDA8B4
+                               C6A913F1DBE21A0582B3FCFDE91B61A9
+                               8863AAC17D07D8F98AE8E71BA5636251
+                               49FAB3EA775D3C7735BFC732C3C42571
+            stream[256..319] = 473F161607321838FEB9359B0006068F
+                               9D88B1A073DA14E60AAF1501F3A27350
+                               53E3FCC794893257CC3C1D4E1E3CF609
+                               975E865CA46C892823C838822AF0CD2B
+            stream[448..511] = 89F37A53F18778084307D0BB71E5712D
+                               32F0F3B7C2201D01D892F6BF6068E4B5
+                               394995CE6BFACF08587ADA39CC647DAB
+                               9B12F5505055F372FDC4607F0355DBAF
+                  xor-digest = C9E7E4A4D6782C02AAC4F47AF1D142AF
+                               FAE569B755E880C6B8A5773EFC0E63D2
+                               3D7A113738CDB1A0544175861401149C
+                               753D723CC1EF515A9323DDE4B4A765C8
+
+Set 3, vector#144:
+                         key = 909192939495969798999A9B9C9D9E9F
+                               A0A1A2A3A4A5A6A7A8A9AAABACADAEAF
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = B7954C45CF301CCAED3F1E7E77DCE45F
+                               2D41B3B1C1F28F0308B8AB4293B64A60
+                               AA7936DDF062613DC1C454033D2A40A5
+                               E99BD975A26185A7F419E7B337028FAC
+            stream[192..255] = 27AF957AC6C514514C24664AA0C9C23D
+                               B1EE30950177389876FE4FF2E1739912
+                               A09E20A2098751049C8925334960A324
+                               5ABB50F3D333587B67F153DB145B5F6C
+            stream[256..319] = D94FAF9FCB753E992B898178373A36D6
+                               23C6BE2420AC2EA848130073F086164C
+                               9B4E69B024991FFA8FAE94E3C2FB16F9
+                               D747320A748DE9FAE4FE9E6A7E7D5659
+            stream[448..511] = F664AFD3EDC0FAE88016C8A028E98D34
+                               A27843372C6BF8F51C7B49B94A11274A
+                               6A161D776E6C1FF05358F28426C3579E
+                               053B4137F8C4CAE07B994B80DA06DA27
+                  xor-digest = 521594487B583F5F71DA10E2316187F2
+                               2A4885A69D522F82F7FD0D5F93F69B2A
+                               060EB60965AC010BC489B401F02C26E4
+                               FE3F82B83C964B4DB4E0E6BC2CE4B865
+
+Set 3, vector#153:
+                         key = 999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8
+                               A9AAABACADAEAFB0B1B2B3B4B5B6B7B8
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = A5E320FF65811FF5E8934F3AC73B3733
+                               77D3AC52446F64646946BFB8F6DEFE3A
+                               04E859DCCD9F421D2DF541F588B9C204
+                               A9846C7AA1C017D637D7C5E244602105
+            stream[192..255] = BB16A9BDCA0D4BCA589A34F9278AE55D
+                               6A7711EC87563C9F394638041CBB0E40
+                               4CD2149218D501D3B62421CBF81C6576
+                               FA659C2878839FCD6C8DD1BA38F46E6B
+            stream[256..319] = 58B4004C53EE64CD45BC4A1F11F700AF
+                               0EA5ED86C4BBC145C8F588B7F708427C
+                               D2292D76329E4DB1F289DADA687B7784
+                               DABCCD29B8C464CE021856FD06554F76
+            stream[448..511] = 1113D37AB2964AAE6586AEE1B060F0C1
+                               02EB3AF048A59CB709792C9080183CFD
+                               2A1A47277F413F1219B5AAD7C8BC8079
+                               246BD1D6F98C11997E4ED0F68E165D9C
+                  xor-digest = 512F4852425DBF91234DA31986732CC3
+                               1F9649A1965E22E18CF38979EE6D92B0
+                               83333422A92F841C25F827782FD7BDB2
+                               8F4B40AD5EE53C37192651A86F03A17E
+
+Set 3, vector#162:
+                         key = A2A3A4A5A6A7A8A9AAABACADAEAFB0B1
+                               B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 96328CAA099502092359F397972568F8
+                               EE2FF1C4305EA06FFD8CC125CB10BE85
+                               65EA30B621437AD4CF9CE731185720F2
+                               0CFE17DD45E6361A8212EECB346D391F
+            stream[192..255] = 74F26B7A37D673DA0B78B38938C5C1EA
+                               2AC666612468F63B540EE7B17548F8BF
+                               60A9845BECCD7222620FDF7BE904FE24
+                               7D2B7EA749C9590133CD6A218F6EF624
+            stream[256..319] = 8F8AA7A4C64C3AEC5E85581C53E3FA64
+                               22CEB927E370C7B0F98F038E7ACF4D05
+                               B54430D91B0A2CDC001BFDDDCD0081AF
+                               35B67E5BEE6B8E113F36E3B23CE29F57
+            stream[448..511] = 53E20B4B90B2DDAB40DC30643AA5F539
+                               70ADB65DD0B64CECF3D3B4C0567DC818
+                               0362FE9CDF920526C59725AE861940A8
+                               A32C35382571F2FF20E7FBC504E1DF9D
+                  xor-digest = 8C7C45F50A151D551E9EC81EDFDD5B2F
+                               E676E14253FF38EBEA12395040643211
+                               3254B0B7298AF77F8F9F4203B971EBC9
+                               B9850152A96C97BD4FA7BE8592670903
+
+Set 3, vector#171:
+                         key = ABACADAEAFB0B1B2B3B4B5B6B7B8B9BA
+                               BBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CA
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = E8DBC8E5D18C5BB2B152A6AE9487AF35
+                               E2044F30EE8189659043923E579C70CD
+                               4A5590968600AAB0F021F7AF283D61B4
+                               13C739DCFC22632E1F6CD553D4F21976
+            stream[192..255] = 8675941731B385016430C9A157007EBB
+                               E9BD8BBBEC44081C1F5E73C7E783AE90
+                               1A7F56A20E5DECD1E94E1C92A07CD2B9
+                               91619BC3358AB812D58E0B98EA288D03
+            stream[256..319] = 8D09462E5B1154175513CE7FAE1AAE89
+                               EA2AFDFDF1B39D69FDF60B1954BF81E1
+                               62F29468E07C251E2D174E9CE924A5F4
+                               8A470D1808C68ECE534CC08204C5A2E6
+            stream[448..511] = 60C5FD4C1831F0EFD70EFF86A5D38D96
+                               2C402453561D0021A51F07D40A7D3B8A
+                               DF455CE484E89437DFADC52A52741B80
+                               ED0EFA9AE4FC39659F8300AE9292B9CE
+                  xor-digest = 12E57044A8E7F02EBF6912BB73836FFB
+                               C4A2F47AE1B824AC97C1237B1B14DEFF
+                               12B5B87DF14A8B5B6C85C0481BD69DDB
+                               FD76FA307F4C1F7D21E60C0BCFECD3E5
+
+Set 3, vector#180:
+                         key = B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3
+                               C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 540980C2A3794C04B93696B90E48999D
+                               ED8E1D3F4720918C80C95B9AC0E911F4
+                               6593C4A920AB291D98891374EF286286
+                               2386B5FE17654278EC413AAFF1C384DC
+            stream[192..255] = F3E036D7620669F851A1B58BCE57B079
+                               F5D75829EDA4E68C36F086CBF2E5DD78
+                               F7F30C1AD9E4CB3C01B7F2FBF53A8AFE
+                               957786B2D3E9CCFE7D6FB24397803BC0
+            stream[256..319] = 1AADB95F07E6268BD82ECF3453DB5014
+                               9745CCEEA9F1887B5F257594ABBFFF43
+                               C3187BD9A9FFBCCACEBD7A21FF90D18B
+                               57FCBAA64B8FECB56D5A7FE05BF03E3E
+            stream[448..511] = 4170D41CAC2A7AA5A3C9228BF386B9C5
+                               57795DB5D1AE547A31C553F55DE02E6E
+                               B69D76A984F4F1D84F29D5CB98190C01
+                               441DEEFABDBFE405F22FFDE734D9497A
+                  xor-digest = CE103B99AA95B51D2D6CC54A15833E34
+                               A11778F5E05BB7AB61505D473228069F
+                               CB40015BCFDD3E1D0D5E1F832791C8DD
+                               3184273D1B4C67D800EF5FF004660440
+
+Set 3, vector#189:
+                         key = BDBEBFC0C1C2C3C4C5C6C7C8C9CACBCC
+                               CDCECFD0D1D2D3D4D5D6D7D8D9DADBDC
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = CA30678AC97B4591E287FF8B5E28A838
+                               611D654A4EC592328039E3A1DFE90FAB
+                               BA5A37133E821E0960520EEC850B6962
+                               B0378E77770681ACC0929D16DD260925
+            stream[192..255] = 79FD1893EBF30CC2CA9C5AE92B0C063D
+                               894EAE4BD50BF462420081D1CAC57A5B
+                               AA92E73D3B3CEA147E1F7127AE1F6FA8
+                               E9B302A068F26157C904E0AA7B7A072F
+            stream[256..319] = 6880FCE56677345CF1CFB2D38F890C15
+                               FE33D377922AE43348F5590B84426EC9
+                               0DC2A3863136790EBB7BD9493D2F0808
+                               CA9287CF95AAF366A11D6E7A556FDB02
+            stream[448..511] = F385299A7038DA8A90058C510727F3E4
+                               524A2D95D217A1C199552753F253D45D
+                               81DA40431910DD54B619A15C5C302411
+                               613D28D53493AD836251F0047FB911DC
+                  xor-digest = F3D10E261AC596959B4AACBCF335D043
+                               FFF65E2651F046D300C19510E1677F1D
+                               45F287DFB8C17055A012C234B6EB04C5
+                               76ED2EDE12DFFE6EBA4A39A64DDC573A
+
+Set 3, vector#198:
+                         key = C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5
+                               D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = D5EC301FD496586D54D9B21FA23DECB2
+                               B25DCC0784BF77DE84898AF96023647B
+                               F1618234A239F63FBF3478FD6EB79299
+                               66BA9B670C64118444C95D31405873C9
+            stream[192..255] = D455D37F435FD0FDD6E1EDF8BAC28D2E
+                               DAF587F938C49A5F58C32CE8D5B8A4EB
+                               884B016E54277300D461FA21512E7695
+                               D2D7489A4560FC7A72A510219DF1C5C4
+            stream[256..319] = A7B93D8B7787B6C8F80EDCE72D4D644F
+                               0C6400C3AD0443FDD19C3F3675083F4C
+                               E5ED87032B1813DDFF758854C8D889A4
+                               6FDC61C210058DB72D838A0913D80611
+            stream[448..511] = 94232F4284F46DD2E7933F9635C26C48
+                               6CB935031095777F59BDAECC4FDB4109
+                               9037C38C91620586DE93B66EC7376502
+                               6853B7390CA516B694583447DD863310
+                  xor-digest = 8596C088FA66361FD90A2132CE33FD52
+                               34910610DB006D223B0574F21BF1CD4E
+                               C282C67B24AF6DB0DB70BAFF65D5D8D2
+                               1C3955D466EA2B49C5E8EB7E07475919
+
+Set 3, vector#207:
+                         key = CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE
+                               DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = DBA2DF9ACC53C3EDBB566C28F689D7AA
+                               EF631CB44EA91610A94685FBD862C9D9
+                               BFCF512BCECF36E035E2E577F6BF6EF9
+                               E4B0E7623E0DB23B10055677C7B9F857
+            stream[192..255] = 8C78C9714577E497E3CDFE3ADE19F03F
+                               D2DAA3211C1E9E5D9F21FD1ED696354A
+                               B7552BFC7FC675FAFE7A739F6E60A839
+                               547F8F15BA5EC6F75BB05606BBF209CC
+            stream[256..319] = B23F187B1BFB5A728BDBD78B75C3265B
+                               B04C6B350A4DA4EB021D6191263F052B
+                               CAE73E5776002FF05DEC3D341AA20D2C
+                               FA523E6B92329A979BE06CF4F848A1B5
+            stream[448..511] = 7E2ADEA91939388D36B3F97DC87C2A86
+                               BDE7BB4884C40D8A202964ECC7440987
+                               1C64B03EAD0F46A3A1CD2CB935DCCD67
+                               0B43292D5B852B7A1B3D1F853EF22EC7
+                  xor-digest = 1AC1E42C2DF9858537D0A1BE3B2AC094
+                               54136E53AE56B006395969C7F999B2E2
+                               DE1DAE62740FF339DFC8769F67AEF352
+                               C4726B4AD4BAAEE56AB8C55FACE34860
+
+Set 3, vector#216:
+                         key = D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7
+                               E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = BB00F8ECA9A10D2B137257E86B455DBD
+                               F9A6A861F19533E38C3C9F54195AB803
+                               171D35043FC9C4204AFC9A8E72EDA4CD
+                               60220B2EDDEBD5482D7833979C15B685
+            stream[192..255] = 6CCE94C2BEBFD223AFB7AF1110F0F6C4
+                               01AFC533BABD84F8C4A54E8A239A194B
+                               B56E0CAFDCC59B9B5103471DCEB9F706
+                               7801D79530B7CF40F2DEC73A169C7481
+            stream[256..319] = 5144745E042B76A6B62E78C92FFC1C0E
+                               E59979CE4B2E4B2CAFFDFCC5E75510A9
+                               201E8A97A6A1729E35CA81D8645FC118
+                               177DA5FACA0293B972AC0957C43BB1FD
+            stream[448..511] = DCF9B6116FA5EB9CFDBFC8C97EFD89B5
+                               268C0D529141FC3C8262B8BE38E94973
+                               A21919D498FCC3896B0FB4CEB24D9E2A
+                               F728003C36838638888FFF1D0D526B37
+                  xor-digest = 99EF8A7D0B8D08E976EFBAE56F7CAA91
+                               B1FFC7428EA56B7A697AA3B621AA8DBD
+                               52681C7A9A415049AFB6B7D8AABAD024
+                               0F9C3112092816F4C69D36B1300ED3E6
+
+Set 3, vector#225:
+                         key = E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0
+                               F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF00
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = E3DAA6E498609DDC5A31BC0B6ACC880B
+                               695097D2CE2D1FD162C7802DC0D00BE3
+                               C0126CF947CEDBA7833421D70A914BD6
+                               C33B0A77BE8BA10879D664F054C29302
+            stream[192..255] = 0015EFCCDC554D042531FD570C6B26D9
+                               059F4F4DA675BCD12C038E4A8D16737B
+                               AAB0D7992340F4EE4324959E96930934
+                               21234D41F56A995C928F82944B46BB19
+            stream[256..319] = 8CE7098F4C64DF2E8A170DA3D02CD99E
+                               0169B99A261D1072FA116ED39244EDBE
+                               73EB9F1CDCF8CCDAA9E94C0DA9C6EDC5
+                               426751AB8300836435BC6F727F793281
+            stream[448..511] = ADF85AF30894BD0207DB4BF72D9DBAC9
+                               144EF6B24E515D96475897EADE40A92C
+                               79B818499B8CC328859561D79D727423
+                               BA81055F3387608E56173AA27D286924
+                  xor-digest = F47ABED85910334919B5868D4531FC15
+                               24D61CB16C23920750C73E2B08A4B5C8
+                               C621482F6D9F01EB59763C5F89AC1514
+                               F6CA4C40216D6385F304E9514B014C02
+
+Set 3, vector#234:
+                         key = EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9
+                               FAFBFCFDFEFF00010203040506070809
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4728A29A2F2BD276FDE176CF4A38BE65
+                               B84BDD41F065DAFEA8302334CEF92A5A
+                               306EF904DADFE92E3E975EF9EEC9B3C8
+                               4AFC167545A0CFCCB6B1CA688967D8EE
+            stream[192..255] = 734153A78089B6E6EC0F520D39BC3FAA
+                               E1DBAD30CBDA32395E51E500CE4E118E
+                               23BC8CFDB08D443F1932EDEC52CDF3E2
+                               1D021DB791A56A7C16FDA02912FE744C
+            stream[256..319] = C511914A4BD9B29488B7FB1E62DBF905
+                               01C0D85C5A238448065C188F0A4134CF
+                               6A1FE1DAE57DB8BDF89FBF7FA66F3E32
+                               14CC9658DB292E4562A1761B9EA77570
+            stream[448..511] = 946944DF8E41BD585723CA1C03909E01
+                               783617D9D1129220ADAE7E5487AF4B54
+                               FF6593B37BB77AB0025C28727AE5933E
+                               E3873824E46F2209D26936FC5566B21C
+                  xor-digest = 34E04FBDE6E3DF6EE14BD179226D51B0
+                               1513510665589CB794C0C08391FA5929
+                               37B390E86BB4A72D427F58A1EFE10F6F
+                               D8A14A6F38ADE34331C8AC6AECA5DAB3
+
+Set 3, vector#243:
+                         key = F3F4F5F6F7F8F9FAFBFCFDFEFF000102
+                               030405060708090A0B0C0D0E0F101112
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 2AC7F22D838F68107877E90869F98797
+                               493171C8A5EC2E51D536A1578659DC16
+                               BB2F644C290B0F006BFE3FA0FE0CE917
+                               D32E94643848867B230270F54D0037B5
+            stream[192..255] = D21F7FE6E368989CC75E8D9080579385
+                               E31680302BA8B9B2F56984FD49B01F4A
+                               DD36AE4A28EBE23B5567BF5A539E2621
+                               1AA8588507916CCB572611C352E73E42
+            stream[256..319] = 25823586A7212D44811C75023193864D
+                               85DFA17EB7D5A34BD1CDD3260B5D53A5
+                               56EE2E2A06F84E95CC7323379FB924E9
+                               9E1A3F724F8C480A1F40B2C4A6FCD433
+            stream[448..511] = C1DA25F3B4FBF8B2917103E6274FAE81
+                               A5BF4086A161A7786BBD5A33662E48AD
+                               6EB9A944CCA57C51AE266BAF756EA506
+                               AE077AF0AD8B577A5A02F5563FEBA2DF
+                  xor-digest = 6176BC64072356BDF719676CD2ACF288
+                               CE2DC1272ED9C4685A5CBB7327669724
+                               DC8BB64BEBA04564A7879F7B9AD5A936
+                               C4BC1AA4007A0F85A5B5B945B418BC61
+
+Set 3, vector#252:
+                         key = FCFDFEFF000102030405060708090A0B
+                               0C0D0E0F101112131415161718191A1B
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 0854D9B674256934E204484C6D59668E
+                               1C94891FEAF6E08A92038E41EBA38292
+                               D19FDBF852400123237BD7DA620767D3
+                               43C2FAAEB08A394EFD1E7C1A3776B1A7
+            stream[192..255] = 4BBDDBE675E0F9D7DE0BC1B0E0C64FE4
+                               52F95ADE61D5CF2EB805894B3CC3285E
+                               6C6AAB72DAFF826D945B05FC4D4A6BF9
+                               37B352262AC12B7E6F92D5FBC4ABDA05
+            stream[256..319] = 7BD11CF4273EA16E01154EF9615B88D9
+                               C52535D2F0C7FD394D94AA7EE542B448
+                               9A046F2625011EE75F874641D1C5A709
+                               B7FD1DDDCCB2A6F1A47B65361A9B0D6F
+            stream[448..511] = 0AB902B571D11B5F2F24CDC7616143F8
+                               45E7DF2050B263D7A841DA170E17C00B
+                               4A20221D7ACCDCB0E131108D94D903FD
+                               7E2F7988445A7DB54F653186D69F3CCC
+                  xor-digest = 1266CF54E8BFFC95F1CD3C532BD8EAE3
+                               BF000577A811DA58A41AAD9164CCDEFC
+                               401C1B6BD2BDD9E992707718A9802B55
+                               33D7A8F490DF116FBCD8C85E9B580487
+
+Test vectors -- set 4
+=====================
+
+Set 4, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                               3083D6297CCF2275C81B6EC11467BA0D
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 1C43EFA7A2CA90F5E8F9A4F09D4C9077
+                               D5ABD79341FD75BB2DF9F13CA0B1CD6E
+                               065FA86938D971D8FAC8A3C34D08CA2D
+                               1BA08BE56D633951BD0338A227321CAF
+        stream[65472..65535] = 428908B703282E38E1BFDE62C6B0D8A1
+                               BD2AB1F5117C85703E9B656FDEAD2660
+                               4B7B8EAAE16423A3BFE542AB13748DC8
+                               35D81F981CD344015E0DF47BD180541A
+        stream[65536..65599] = 9D6D72F46C846D9BBF3AEEB463B9EF42
+                               F84915D664A20FB78AD94B61FEB7D63E
+                               5411A81D1E8F32BE3044E109C68B9EB5
+                               EC0BF180EF18BF3191D933F86045036B
+      stream[131008..131071] = E462CD92492726928381769FF205DC17
+                               AE7D31E1B82810F3CCB541B58C5F58D1
+                               38DB708C5F5BF07A0432868A1AA40A07
+                               601FCD1A07DE3071E8CE082833F0B02D
+                  xor-digest = CDCA2F92BF75499E49B586BDA7D9306C
+                               12F111D1A9F183A83B5A07549D5F976E
+                               815F96BD716CCAC7178282CA8BEFF4F5
+                               85DAFA9BDDDF8E6420DFDBA2573F0494
+
+Set 4, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                               3588DB2E81D4277ACD2073C6196CBF12
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4F7D4E56036A57A303A9C7D978290216
+                               297AC26C187E4F07678EC0069C34F93E
+                               072D734DBA239D81E566D1E6DCD09B5C
+                               A132714291631C227E391EC0385A3A64
+        stream[65472..65535] = C508DDD76C070F712FABA944BCB0F5CE
+                               EB645825C520197867623ED5263E22B5
+                               6270F0A878AC7FE03145DD2BF528E1AD
+                               784086FEFAA0D82F0F3571CEEDD3341B
+        stream[65536..65599] = B10CF49FE9266BBCA007C8DB526E760E
+                               79AA4D6A3B29FE82B8698C732FBB81AD
+                               1A27B2AEB06D05F3CF17E875BC0BBAC5
+                               67762275EE650D03F62B29529F3C3E23
+      stream[131008..131071] = 42B4F20EBAFB2C792006BD163064EC7C
+                               F363DD996CDF839CCE61E739C3817B4E
+                               36D311A4C94C7918E82F5158D3A75844
+                               A5603742E33D7FC3AF018660E6B1185C
+                  xor-digest = FB3EDA7C75E0AACEDD95B625F7EEDA62
+                               3DDC94983A9B084645253C0BC72FBF9A
+                               67072228194F96C1E81004CB438D6381
+                               A5C7E9E7D134FB8B67DEF27462AD3335
+
+Set 4, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                               3A8DE03386D92C7FD22578CB1E71C417
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 23DE914D641DC0DCB4F818C687803858
+                               A6673E284F8323787756DAC9352BE031
+                               28BC6149A59785F6AADF92FC68761E8A
+                               862AEDF29E851BF5422A83EE5EABFEE3
+        stream[65472..65535] = D12E0C470A955DDAA7E851F43DA35B08
+                               15D442DBBEDEECE3ADE18FABF08B4443
+                               77ACFE9F138F8725CEA27B0F0ECCB4E2
+                               E5D6E476F88CAB4743E8E43CE2D48F4B
+        stream[65536..65599] = 26635796620003DE67406BF741B93D68
+                               318F9A23FE823B2374E8BD8008EDD7BE
+                               2F750707A3835BBA7DAC45E06537DF8E
+                               53DFCDB928EA34CC08D2841FE3E492C3
+      stream[131008..131071] = D3DFCE281FDC69F7800E765CB0B33D78
+                               8BBDC17DFD11F929295C26AB7ECF21B6
+                               7D4B4EFCC18ECDB8134175A7F198EB12
+                               F7913DAF22D73A4139D5B807C18310A9
+                  xor-digest = BB2C8E7BB894DEFD1D5A7D37C01E8EE5
+                               FD4E052CDF1DDF5FDA90C9818DE71B3E
+                               34392EC3858ADF718F463808ABF841B6
+                               90F49D35A51BE5067B162E72D0101F97
+
+Set 4, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                               3F92E5388BDE3184D72A7DD02376C91C
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 818C35D2FD72D12115F91BFD32F843E7
+                               ED4D7110D1ADF517226BE797E037AF93
+                               C190025A5E82FA0341667D68FC09E238
+                               49D5A7A9526CA142D60F71C3AEE3A106
+        stream[65472..65535] = F011E9CEE99D94BDD4484408A0FF91DE
+                               EFDC8D8C04ED2B86C51F21058E912C11
+                               F19890E174018308962F5827D2FC1E2B
+                               82BA65688C111AAB5C749D8ABAEC022C
+        stream[65536..65599] = EC2EF21014AACB6215083F784E3ED65D
+                               774124FE60188930E1A90405EAFC8F1C
+                               E75D54AA7D81400E026D799CE06EF532
+                               8002BCF5A10D43E6FB6F80A9D72634E1
+      stream[131008..131071] = 80BC6F7F6B0A7A357F770E7690D94A9D
+                               B8CBA32EA36E124FDCC66ECE8786F95C
+                               22263F09645864087FF4AF97944A226A
+                               CB63DAD316F8CFEF96504AD306C512BE
+                  xor-digest = CB8D4C35D79CCF1D741B9DA09EDA305F
+                               5FA43F9AE9D0E1F576D5C59AFB8471F9
+                               7822C6ACAA197FF01347E397C0382195
+                               865AFAF5F1690B373AA2603C39A13CC0
+
+Test vectors -- set 5
+=====================
+
+Set 5, vector#  0:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 80000000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 635990D909A80CE2A75E521ABF588B6E
+                               85320D2C722D1C93B42AFBE6358D6E2B
+                               F2BE933BC961FB50F9A2B55389A08CD7
+                               A0131F89CF0E61D0C7071DEA6D8DD4C2
+            stream[192..255] = 0F92D4DCC222BFC7020CA6BC3D044F69
+                               12D9A93668C65401C570A01D6BF6B3BC
+                               A6F00F6FF46AAE3C09C6158EF05A520D
+                               F8D55FF27CDB7AEB5D03C1FFCE7B95ED
+            stream[256..319] = 664CCED71B27680F9458952173BE0043
+                               D3C27F35F9CEE7AE9D783ABA671C4FC6
+                               8F2815DC904316BEB39020F646041276
+                               5BE5500A60DE2209961755C1BF96E1E2
+            stream[448..511] = 8F02C1FB389DD1C5F0CB730ADA528D37
+                               DD778C4782C7B5DF1961F97CC82B63E2
+                               9CF4BE512EE27B50781E297D1633D700
+                               1298F13FD8AF9D1EA83F831A70EE50EA
+                  xor-digest = 3F9A4D249220E1AC8E559399FCA23DD1
+                               1A250DCDA841502F5FEF0F5D4EFE7E46
+                               D9B1E5E4312903E290D695C2B681949F
+                               480D45F78FD69597570338049464FECA
+
+Set 5, vector#  9:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00400000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 8E932D78DCDE35F1E5B8B2E863859A64
+                               7AEE8B0867F6F221B09C37B7A78B4043
+                               D055164B1FF1608EC17F3F148FEBBFF5
+                               A9FCE4158B33D2CAA4AC5FE5551C788A
+            stream[192..255] = 7034BE31CED03DEFAB3F69A24E622BDD
+                               9B202ADAF05D0324EE933064ED6D965B
+                               937FBC8405F0D7236AC28C320CE66C06
+                               C5B93EC581FDD59ED40102C651495EBD
+            stream[256..319] = 37C4EB0E72191FF0F70C8A70F475061E
+                               A0BEDD8A9AF1901FC6BB5482B5A29469
+                               06E8C40249E02784896D5D42387127DA
+                               CDF1657A66E0D43E6F69632519D1D3A1
+            stream[448..511] = 8CBE98126AE27A51146FE05F40CEA89A
+                               39781F515D621DD48B6D6234F9AFAFF3
+                               6FB862084F5249BCC0018E8FBC090121
+                               E227FF494BC180FF68EA2B134E7B00D6
+                  xor-digest = 24556A29026E3CAE101E7112B2FE5BCD
+                               3D925460B66A9EADDC271E39C317DC27
+                               51DC9254491F76F9163AF09AA5372F34
+                               1B76D54C09DEC9419F839E5C50F1957C
+
+Set 5, vector# 18:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00002000000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = AC05D72564EDC8EB439A95579D04BF65
+                               592AB1024152B9B14D71B18FEB5374A4
+                               C07AA2F58EB2E45F737580241CFB9C0B
+                               842F8CC9230B540FC50A590DEBDC29D8
+            stream[192..255] = 48AB7E018380336AD0CFF37379D9E370
+                               5B0C938600C6713FF4CF5C142F640FF9
+                               72CF147E7C38389DF426FBF560E7DEF8
+                               41B4B1CFE6A4E2DB4A85505C931FFFBF
+            stream[256..319] = E9C6536F67F4B3053B353170CC5B77B3
+                               06A47B759A5FEE5BE45842C01E11519E
+                               5746B056C86D8A6712446949DFFE6935
+                               8E4512E7BBD6E6F544CACA98BDC723E9
+            stream[448..511] = 731EF8977E1307CB5FE80BD4F89025A5
+                               AFEE3E54F7CCEE6556A211097498827F
+                               6219704F96652420BB9EE830DB3DD940
+                               96987BAEC5A43526FCBCD85C9BFDB209
+                  xor-digest = A37E582543E75640DD988C7FB5579D43
+                               9C41669EBCCA5580184743BD54D24CBE
+                               E32F2B1433CDBE51E8208C78FD739CC5
+                               4E2A37E16A7AE4F2193ABC4F04C35D23
+
+Set 5, vector# 27:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000010000000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 0B295517E5A2E100C262736DAE920F2D
+                               26C40787AFEA87FC34C27D6E0BF98A62
+                               53B695751F9095C8766184EA44042F2D
+                               6DE099A80C75DB1F33F53EFE578A8F0B
+            stream[192..255] = B54C4F2EDF17A1EC22F536586A5BD691
+                               2008DA6642C84AFC8ACD35A7DAE73F79
+                               C835D83F4C0C3B1E510D1BB42013A872
+                               8E4899A8CE134625698CAB31852AA7D2
+            stream[256..319] = BBE2221921E73DC79E795AC0AF9B890F
+                               FE88A14DA29DE45FA38F4C3E94E6BE9D
+                               98238BFB181FE664B4147CDDC125FD06
+                               D11A65F1975A0D781024DE1EF026DFE7
+            stream[448..511] = 83E61FCEEB1367635632B45BC73B8B39
+                               165015E7A6B8D9851390D4CA9DCCB935
+                               F09BDF52883FF37BC77DE94842E39BBE
+                               0BE530FC9D3B4564E11B7EBAC8083818
+                  xor-digest = 55242D44DFDB1A747071F1C825DB5620
+                               EDE1AF37B6D73A22264B14F7D35E4412
+                               4A6242C5AD34B54E98738D6CC90FE355
+                               BB9402DD017B6678FCC0EF27CF5D67C2
+
+Set 5, vector# 36:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000080000000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = B89065FE0B458C64FD6EDC6A893C8C81
+                               83578E7D37BE97E6FF82E45110A25960
+                               49A817CDE859B67B56CB80768D6DD275
+                               6EC368FBABC35C8B51C62AC92F913281
+            stream[192..255] = 0E0AB045409ADA1A9540504550404B8B
+                               2C38384E577F2DCAD5316CE7E806A0F1
+                               21D2A3298F71F301340F3C0A9CDD4815
+                               936F16B4EC229E63451980646D45E3AB
+            stream[256..319] = 1DC37BCE039878BA2E5938E4563D2523
+                               7350E41C8EF9262A9EF7D7FED7E22F45
+                               DC3E98EC981D2BCCC1185857C627EE20
+                               C86DFEF500756B241320798764C3C09A
+            stream[448..511] = 9A0082CDB35BB3CB1C74CE337D944D3B
+                               2C833B4F786A92DEA4445A2E5E101384
+                               AEA834F5E01C1B37EF8291D039875A3E
+                               21D613FC71212DE686AE52295B773E42
+                  xor-digest = F94584BB343C6BD6BE3AA1EF799989CD
+                               93F6DDB6A9AC7E2EDFC92460F0905E6E
+                               AA3E81F6E173C7F9FCE8FB5D7B261A58
+                               3FF006AD017A09FBA3B3D084285169A6
+
+Set 5, vector# 45:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000400000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 486343B348F2A1726617D6E93989B000
+                               B41FC9707E2A99C7FE5CE9423DC3004B
+                               67EB02F45B368F87FF2C4CC0C59D1728
+                               9F713E714E049CFD8E5D593255092A7B
+            stream[192..255] = A1A3127E632EF47679F52224E6D5A16A
+                               6E0598271F36F4DAA98B115535E77C71
+                               84170D2DB4B8C5D804790A666D105108
+                               81213A0684DD4AF03DE7707702F4F73A
+            stream[256..319] = C917B1577463E05F34350C4C7F6CBB5B
+                               D63B2D74EAF1500832132CA1A1F289C4
+                               3D93BFDC5E9D91897D2F7E05740F3C95
+                               0AD872A93DAF3850A452410FBD706A92
+            stream[448..511] = 11646E84240BB95D1B14694785E7E119
+                               848855E462DD14176442B8595CF602C2
+                               D1F4A2E09B8D7DE28382D1DA4DB3B1E5
+                               910DAE6ACC02E79FEB07A8E55747046B
+                  xor-digest = 65E9982A725056B8FBC275052EA48C00
+                               69A1BA0939831C4014E81AAF14F66FB0
+                               E01FC0C70A49C4533ACBF304A5309F4B
+                               60D6B310BC66C6684BD5B9C83F994E95
+
+Set 5, vector# 54:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000002000000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = ACAB34102EDDB67B8A5D8B135BAC15CB
+                               1CD52AE386364C709C2B9D6BD322D7B8
+                               477577B4958D448A3BEBA473D861E592
+                               CA15371AEA0F500361CBDD865488A7A5
+            stream[192..255] = F25DAF77D7D734E5486A1AAE01794FB3
+                               C17099E01489A5B4213EFAE6D745B798
+                               77939C7A178D1FF09EB2C42A8A3CE51D
+                               59D501B36BF9E4960BF3FC8D50F5A847
+            stream[256..319] = 1C9C6F63998627AE1AA7E8F0B2D73A99
+                               707256CDB12E3AB239EFA72AEC516FBD
+                               6DECC9375EAAC634707A139E59B32B51
+                               5D25ED6951FF4228A11DC87E8DE61385
+            stream[448..511] = 6A997977A25F4E9E0D9AFD8C20B56EE1
+                               C702C301528E332BF8F5E7DBEEE5CC28
+                               C9E12E1A8BD7A2118A0F31F800B574A8
+                               2FC44FE19B20F1D3396432DBB02DACC1
+                  xor-digest = 0B2BA364EE76F0549A10200D129196B8
+                               E2B69667999FADFAD55CA479AE679C56
+                               54A453C43898443B9DF2835AE806C2A5
+                               EF30CB8AC25DBA756A705F66759029FA
+
+Set 5, vector# 63:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000010000000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4DD010482D0DB2D09D76872D25F73B26
+                               749FFE70B9674587FC4CEDBA5966D217
+                               489244D0177F676188A1762C430DD8F1
+                               5ED9F7BB67F2E8A79F7633DB7B45CFF3
+            stream[192..255] = 3587F0A7B9F410D45357626BE10B4EAB
+                               FF8798FECA5F91F3AD2543B301B5C301
+                               F84404071C7BC77AC31E423E1AB1E2AC
+                               2CFAA37DBC2A1316D16A5C7BFED1A77B
+            stream[256..319] = BFC632891511228ADBA0211EF390A7F8
+                               08A12AC6BDD7C2E29DF27025EBA1A6EE
+                               00B9718FF2BC003904C1C28878894AE0
+                               E5CE5E9F55CAA522EBEF5747C755CB73
+            stream[448..511] = 513D9FFA86D8AFC20E4870DE0E9B330D
+                               76F02E44A6C4D7C5270B89C6BAC9426B
+                               5A12666244C0CC5A641118B93F72668A
+                               B7C53CD7FAB0940F1B37A85015DC91BE
+                  xor-digest = CACA8BD50E28720128B57B37D45DFB02
+                               206D53785FCE81205AEA085466142DB4
+                               A17F841156916294F3B7CA93CD99CB12
+                               93FF593B5105D2822CA9BC3BAF178935
+
+Set 5, vector# 72:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000080000000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 4DB6CB1D5BA89BA45BA8E3DFCEFC444B
+                               7D97C73F53EBC50BC46047CD76499CF1
+                               FAB51AA6C8B24118AC4EC8E49192B41A
+                               2812AA1A4325418AA6C69F6143F0A6B9
+            stream[192..255] = 33FB647044F3918513212D3538C31662
+                               1DD9F3A10C0589CB718564CED7ECC391
+                               D9701C7A23AD48E05A79BE9E32F60819
+                               3E57FA8D8EDDF9F43F38BF8BBCBAF52D
+            stream[256..319] = 79F3525A6EE300764DE481C20A40135E
+                               94362F56DBF4C5AFD214F9D4039A0899
+                               F74A7D7C27494B39D1B0145B9F691B5F
+                               F436F2AE8B335EC62CCB0FF506E0240D
+            stream[448..511] = FFE0E6B8D741377FF1A02764FEE3D681
+                               6CD020C6DDA5097989137E9BCFFFD35E
+                               0E6379AD2ED3D9D298C6B98DEA82DE6C
+                               2B66529C860DD4ED56265CA09B16A8A3
+                  xor-digest = BEC66A4FEB220D732F04AE0B98FCDE2C
+                               0B70613BAD57D7590E007E84AC546B09
+                               AF1D5BEB509CFE5523254B5FC8CC2672
+                               215C67477AFF14D0788DB166C5B4B12B
+
+Set 5, vector# 81:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000400000000000
+                               00000000000000000000000000000000
+               stream[0..63] = ED4C49EAEBE78999C0DBC4674757D435
+                               B056A45036DC51B390A6C87B3CE8BCE8
+                               2C7DD348C7775D2402EBE359E7895FEB
+                               B9F44DB5D0F7B40AC207A3CA750EF25A
+            stream[192..255] = 32F897ACB5CE63D1A64781524B1CB4FF
+                               9E595EEF93A3206A0D1B4E6F4ED7501D
+                               2DDFCA31B4FC1A33F589167B070FC003
+                               F67C528B6AB99ED308EC3CEF82B4E2F0
+            stream[256..319] = 57CE29261DAB385309C97955261874B7
+                               676349DEDF7582B7654D1A8DAA570EA5
+                               9745D2167F2AE1ED538F1D0ECE53AA38
+                               379F9AE542EBE229D561E34ACB28FA14
+            stream[448..511] = 667E22A8BE7BB84CA1B1C0848E5F22D7
+                               E98E54A79D5A960C33D07357199AF1AD
+                               53F3F803EA698127C22F75F31C40656F
+                               8C28818775B3D88460CFD29798187537
+                  xor-digest = C68E7F4A7CDB68892794933392C1BA84
+                               5B6B7CF52B8421137EE0220BA67C91E9
+                               81B47F9BFC39FDFF9DD48F3617F2D523
+                               0680B87D18A821A09525FDB79DE6FED2
+
+Set 5, vector# 90:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000002000000000
+                               00000000000000000000000000000000
+               stream[0..63] = 80FC6D794178A189EC423AF926622982
+                               60C44DC5DD5AC91F779D02958366CFE2
+                               C5551DE2A5D635353757AFDDE68DF592
+                               A034D87C871D7D871264BB0F89E99536
+            stream[192..255] = 0BEF31DBC3F3DBCC5B3D28BE296384D5
+                               D33DD0AD9A80D4AB8F58274B4397A658
+                               94F67376AD8DCEC19BC2C74A835D9F70
+                               1F4C60DC256DBA4E83B21D36B66F5DC8
+            stream[256..319] = 625DDFD8D922D848380D45D6D7E730BB
+                               049666B3900E4305218BB7089D059FD5
+                               825F9EAA3AC047A006F1353C37AFD11E
+                               0143DD68CBE9543B959E26ECB4C649A1
+            stream[448..511] = 636E6EB97E3127EB703D5170D2C8FAF8
+                               63E8C333F5EFEFCF9063E3D770FF9E0F
+                               2B37396CEC935239797FE430DA4CFFB2
+                               9B19D833687318DF01750DD2F3D942B5
+                  xor-digest = 0865679CB53BC2845A0B71AB820F61AA
+                               9B99E100AC7F0358D5B610C09EC52C7F
+                               8C7C5D973CB85B18F8990F3BDBFBDCBD
+                               13071BB3AB3F329E75A44E80320BF86E
+
+Set 5, vector# 99:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000010000000
+                               00000000000000000000000000000000
+               stream[0..63] = FC2DEE44B15BD914C17DADE6645A0250
+                               2F40B39C0C6AA26C0250D328112AC67A
+                               0C55D48700EFE67EFBCED927B62427C1
+                               41DB8089774E2DE23C5FDDFD66D39BC3
+            stream[192..255] = B6A4D34FC81937580BFC32E04C8E2B20
+                               309AF3E2152B98BD748A344D4537788D
+                               35B16DD2C01444CAAAB8684916705C88
+                               FE75C53D75713FFFFA2693E91395F919
+            stream[256..319] = 9E619BB0045C58C2D303F79E659CF5E2
+                               011D619E0CB10CFDD53AEE6812DD780E
+                               36407CFE9BFC1C73C27CBBD491BB6A7E
+                               8918023EFD6E2227C0C840F1DFA5924A
+            stream[448..511] = 2A320747019AE86A59D5422B634448E0
+                               B43C41457428AC7A4E5D0C9D7327B44B
+                               BBB6F64CC2423299C009E5B24DDF10C9
+                               F87F2A525ACF803C50837EF6C2FF3D34
+                  xor-digest = 3737C19DCC04C7C72EC9280D53C17E64
+                               E9F4B1E47980711DC64FE6D3E7DD05E0
+                               DEFF339F38868B1F7CFFAD4298127949
+                               11EAD4D34047B22B07C397A37F6BD2A0
+
+Set 5, vector#108:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000080000
+                               00000000000000000000000000000000
+               stream[0..63] = 84F71EA20D46B3802A787C1322DE6A79
+                               34587F447AE7FE277362497E4FDB69CE
+                               129EC4D8D80ABD0C15026EED3DFE2B6F
+                               C48C5DF09CBE035E348A22F8A2AB7DAA
+            stream[192..255] = 6444791C6DE062EB9A494AEB910A458A
+                               DE3D834BD6F87F26A9D6F99FD970C820
+                               ED9FE0DF88A924F97945B0EB10E5D464
+                               559AA278DAF6A942651E06C66D33F7A0
+            stream[256..319] = 1878644E35B3BC562F82647D45C84317
+                               769BACDB95DCEACA456727616BC90FF5
+                               E78FEE1EFB86A714CFCDE79AA9E66FAC
+                               D600B0FC5C471569BBEB5692E7D9616D
+            stream[448..511] = 54BD56C4F0F3A0CB89A678F2912E5B21
+                               C2B225030E82A90470EB6040F50A818D
+                               C91F65BFFCEA3F9041BF110A762DE3D4
+                               B41A8D1E18CAC776063B2DC93BC2D02E
+                  xor-digest = 52E18382B88883C5648E067675468200
+                               2AA9AC5C18A856E89175C449A6033501
+                               87FA4C17A4D36269340F0877385A35AC
+                               4B7FEF6E1463D34BCDF3597618FAF352
+
+Set 5, vector#117:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000400
+                               00000000000000000000000000000000
+               stream[0..63] = 3F40E9A3C872ED15A6AA296F716E095B
+                               F39153C7C6F4ECE6F550AD35582083A1
+                               CA0DC3CD817AE3946E43AA9C8700420F
+                               F0DFC21B34F4E5E40B3EA14299EF468D
+            stream[192..255] = 853C4A895DCBE411B9B2E340B0AB55AC
+                               8EEEC42885768110ED7E1CCADC10121D
+                               8DE12AFD0DCA4507A8A7A2650FF68C6B
+                               5DB1DD670C8C68365E846934D16A46CC
+            stream[256..319] = 565AEFAC0325093EF87FDC51413BD5E8
+                               56AB6C90FCE7D3C6EEB7E58F22AF63D6
+                               73BCF3840D611A5E1102E9A4108CB902
+                               5A1D837510A971536231CA247965379B
+            stream[448..511] = 887287B62116FE2A28957ECC71DE5BA9
+                               CBBC16DBFA4EC141EB617F9314FCD238
+                               91C4237FA35871C0C795E2F3A4197DB4
+                               F81BA4A29759BEB5FA2277CBB9169734
+                  xor-digest = 78E564BE9E7102E2CB009D7A540395C6
+                               188C8499B7E96C0AD709C3BA2C341741
+                               6EED55AB00AE5719F25CFA06F1488E83
+                               798F18BFD755B9061AFB4EA5D864FC24
+
+Set 5, vector#126:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000002
+                               00000000000000000000000000000000
+               stream[0..63] = F4C281D9C88A7FD6B2CBA9EB0366C594
+                               59327932DBEF8118A7A680D0F0AA41A3
+                               735FE0874F047D2B071B5B9E755A7B6A
+                               9426353B923A5913C647A88B642B2C00
+            stream[192..255] = C7DAC2AE7631D11EB21EF15FDCD3EEDE
+                               7DC98A7060613A643EE8A944EEB6C7D1
+                               EDE08538E1BA6092ACDE0C648D29AF5C
+                               309CFCBC4F40A713FA58D93C954961AE
+            stream[256..319] = D1647D6453798B7E15A49199134384B5
+                               C9BDEBF7F859F6460C2666F297410070
+                               E68307CA78790EF01D160D94B69729D6
+                               90A4FE477A27AFF8B254875C98116485
+            stream[448..511] = C6D3DCBD0E9D4746B142C819867E0A14
+                               8B81FEE3D1007E907F8E9D597EAD63F7
+                               A87E6F224C67CF8162C4E92FC1BE44EA
+                               FE3715B3C1C432CC660CCF1536A20F46
+                  xor-digest = 59FDF05B6D16079B7E18F6A8CE0C58FF
+                               AD7C985C01A12C07D1ECEA740A92F761
+                               FDAC3F96357498B5F5FBA91DE6502A86
+                               1332A1B3E85C5E72444A2168C25D6FEB
+
+Set 5, vector#135:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               01000000000000000000000000000000
+               stream[0..63] = 494BAFEFE4FBF2C406F55FFB436105BA
+                               09211B71DA446A0F5436E6DBF42F8E1C
+                               C805E797C9987C14997083E9004473E1
+                               B2B3729DE9B483361CD38CC78C982533
+            stream[192..255] = 3C04C6633F7D8B714E8549AEA1851035
+                               A520EB6422F42B2C840C74CF51A13FA2
+                               9C1875212E8DC07774D6911415F1C305
+                               9826A05DA9F09942273CDB592F7E3A6E
+            stream[256..319] = 1FF6BEFD79A7E5BA0DF64948BA0ECE7D
+                               ABFB3883BF8A95D3E76DEA30550F5C3A
+                               2B67FE2AB78DF091E758E498418EF514
+                               089283275588A41AD20D53E6394635A5
+            stream[448..511] = A4D10D3B6AFDF415D49FB6ADA1245812
+                               1DA1365ECEBDB6C2508F1EB92E91E8EF
+                               90892E6FCC9E70AB9A2EC4D49A11C197
+                               68E6B4C154A4D65C55AFD38B2BE3F4DE
+                  xor-digest = 91D4EA4C6ECE28536C415A6AF46DC432
+                               3B6DC2DC98C3A3FE2BFE53C8FF556C16
+                               0197D655357512A808415BF757AB3A84
+                               6BE7865622D32B7DE3867B3B096408DB
+
+Set 5, vector#144:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00008000000000000000000000000000
+               stream[0..63] = 521913EA655235FA0E713B0DA3ECB98F
+                               7AB817E70827D29E75E3BF2729EC2AAB
+                               8747B8FE0FC9489B6E0EFF45EF985980
+                               CC0189D9D0F2EF34E809D992E7695D9E
+            stream[192..255] = D265AAD80EC96DFF08859F93B236136A
+                               BE146981E919C0554D64FBB7D03DC9AC
+                               9021F2A1B39866567D8BA1DBE2C3CD21
+                               E5C4C94085F7083F4C640E918C4004F1
+            stream[256..319] = 7DCD3CF623332365E6CF2D92FD147BE4
+                               1E532F51F939C921DD4492E026993E56
+                               843ECBF0925CC52D56084E7F2B538653
+                               2020DEE6FE7E85D4A89AEEBD5F3EAAAB
+            stream[448..511] = 00E20611C7ADFC3BD9E59B9E6D7ADB03
+                               F87FAAB01D7771B89299BDC59E1E2EAD
+                               FC9FDE416B62FEF07AB7A816AF261E77
+                               FCF79DBEB09323D44B5956CD93AAA990
+                  xor-digest = 0578B3E20EBF98D89E2DE82A6EA8E34B
+                               424E526CF419713F0AA662B852E58BB6
+                               7ED570D75534E1F23F85F160690A464F
+                               122CCBFA5CD1DCC0969F2E57D65D64F8
+
+Set 5, vector#153:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000040000000000000000000000000
+               stream[0..63] = 2617095641B825094DE44205319CA853
+                               418588D5B6BFC05A2713CF898DC42B3D
+                               6ABDDF4C287235438A48BDDA49E5ECF7
+                               EFA235A23BF667289612893708704F08
+            stream[192..255] = 04F668517ADC1AF6E31DE6B7007ABAC3
+                               59A2DD6DD61755C6CA7053E05FBBA2AC
+                               D9AF682EFC71391EDA4A5872B53D7CFB
+                               BD35ACB719169283EFD9FF9E172269C4
+            stream[256..319] = BCBA3F15D83B9AD41317AB9EF7DFDF0F
+                               FF05CDB058AB08D7BBD720723E969CAD
+                               79F16D26DF0222CFF4249B839EB9F9F1
+                               422EDAFB8EC285F27E347B7B4C9B2C23
+            stream[448..511] = F15F17F38917DFCA9141314047595C17
+                               047F91E4859D849E9A6339F640E3633B
+                               6A1B62D089B24062BA5987C3FAAB6633
+                               99698CDE6FE7A461F127AF67B2C5CFBA
+                  xor-digest = 68B2369B45F059964A1FD3822DAF61B7
+                               82A9FBA7EB563F83DEC4D058CA5D8931
+                               EC74AF4043FEA803B696791C8E0A675B
+                               DD8982AEA862BB76847E1DE12F2A5E86
+
+Set 5, vector#162:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000200000000000000000000000
+               stream[0..63] = B090CC267B29A95ADFAF6BE3E147D647
+                               21ECACBF6B7D0C4061D17FB7DE0A6662
+                               6D6F9FC167FB3FFF237C240AA03FAD55
+                               13B6DA848F22796DB501A8FB89F2B85D
+            stream[192..255] = 1CB95ED9AADFA0E1FFE5704BE69CBA3C
+                               9593746AE87F36A786E5EBE18A1D3B25
+                               F4785EEF4DB439472035BF053687C5F1
+                               0B60EF55A76DD1994FBB482BBD250755
+            stream[256..319] = 826BE3D679C872536D55C3F0E49C2624
+                               D41726A4525A50CF91EB71E7CEC5AC47
+                               F3834358E2296CF0D04B8D8CE8A701B6
+                               6AFBBB8776DB2B75F1CFA01231B365FA
+            stream[448..511] = 244DB28A98619907AFFDCCAF303A3795
+                               3B6D21EE6D22780C4D3C939C084E4181
+                               1FFCD8F2DA2E6A2243BD0B5428FB86C1
+                               F0EA2E8C8B6950ED961F4FA8CDFDCD17
+                  xor-digest = AAAFCEB42F2EF40C4B5462307085434E
+                               E4399F87B4AE5CA828A952A851F47913
+                               A51430A8BB9B3CD0A4B2F12E297F51E8
+                               FE0B1A6FE0F21177EAD9284087D3706A
+
+Set 5, vector#171:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000001000000000000000000000
+               stream[0..63] = 0F4309F63F237DBB51567573126F09E8
+                               E49990F26E541EF888B9F2922FE9D280
+                               C8FF4874C0D4FA3F41034B82E2E026C4
+                               594A79C2B689BC502C41244DC1AD472D
+            stream[192..255] = 95DCF9685E429DEC2833E1B5E78823BB
+                               ACD9332D668C4B342B89A290E1CA6127
+                               B0E5125E44445A1156A70B27966C3E0B
+                               4E0BCBDD9F4561998A5CBCFAA05C7459
+            stream[256..319] = 0886E9887182156005548CA1A08B57C0
+                               E9FA76C2A694E1CEE22E9B715E99B115
+                               9AE064DE644FD580E8356164A45EA1C4
+                               3DD85E16158B5130AA103267C8118105
+            stream[448..511] = F8AF6F9992781BB09808B7AF404F6546
+                               6FA697C2A1BC9BF64F8D6B6D8CA0B856
+                               6B64E6BF0500F6D80113D9457855FDCE
+                               1791C7436F5FF41ADA87562C175942D6
+                  xor-digest = 8D32FFAA409C8CCDA6892C388D5D654B
+                               4AD50ED00BA649737BA8F350811A2AE5
+                               5C89463C7D63F1F1F16C4007826C2CF0
+                               E4BD9453A60D88BE86F60BADC3E71E98
+
+Set 5, vector#180:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000008000000000000000000
+               stream[0..63] = EBABC8B756971D46C1A5E86CC7AEB329
+                               4DEDACFC795F2AE02CCAF68B933DEF4A
+                               19E96BA64DF14EB6FE67CA48861B49BC
+                               16052E33C8B47556DFBD96037B7DE5F2
+            stream[192..255] = 0438A8CF718F4C52E33DA087FFEC01E0
+                               459D26757D5DF55D5D7BC9BA88F57EC0
+                               4B84D854374F95317CBDDEE928A2CCAB
+                               E4BA1BBBF47776B29890DF00D864FBD2
+            stream[256..319] = BC4A80F9CACFE63D2E54044ACFF39F97
+                               2C69015058AD3F81CBBA28FB0987FFCF
+                               9CD1F6AE4F0602BAE2B828D3FA162936
+                               23CF3AC2950BD651F7E467DF8B454BD6
+            stream[448..511] = EDC95FB80C9FED4A73D6EE9B2CD74BB7
+                               E6DEB9E7868D40FC49BD1C52838457F0
+                               88DCB29C2107066D55A80908EFD1392A
+                               B4F2F13C0A79F67E58C91A89A5C88991
+                  xor-digest = BECD7FD2014BB9A25701E69F9788FC84
+                               1AA9DA56CDE1CD93DF45D28F29D32E22
+                               F488B0C2D9FE95B267CBFD35EDB2F6E3
+                               05DFA5A2CF09D7E2D13348BC0C9405E2
+
+Set 5, vector#189:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000040000000000000000
+               stream[0..63] = F28A15A90386237127A5682EB09E0E58
+                               30709455034A7189AC9710DBB50D5012
+                               9EB4E0E9036D4504054B281F3FE9F45F
+                               C80116B8FFC0B42F9A636A399B7A8BD1
+            stream[192..255] = 1219EF9BDC250E88BD0A62DDCF9AA1DB
+                               B62E19FBA748DFE1035C6A5B3B94954E
+                               1370487A455916F7DAB451F79C5E1298
+                               F549CE005A1321E6B136B59BAD9EBCD5
+            stream[256..319] = EBBE81DAE5637C4C7EE6FF9251D5407E
+                               DF7E8EAE384D1E588CAD39AD9F763004
+                               9A8E028120B5065B658EF3E2B357E52F
+                               F18891819EEE3EE021BD1AF08A4B1F53
+            stream[448..511] = 50086FCFCF5EFFEDC4A52B0212B7321A
+                               8664F2976493868F13D7CFDFB7583E99
+                               EBA70778A83CB88850D45B300F7F6A80
+                               E721860560B2FA642B2E77C7F7AB0662
+                  xor-digest = 336516670616300FD5FB014C1076B53F
+                               6637AD0EFB453615924396785CA4D284
+                               B03F526FC2179FF3BFB0A1A2ACFFD87E
+                               EDC4C8360DFFC132CE6A502EB173A0D4
+
+Set 5, vector#198:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000200000000000000
+               stream[0..63] = 93261A7231FD030CEAA974BBF8F3A721
+                               33334C5F3B25D5831B203C353A566D80
+                               DA578081A047E28DDF8E4BD5B68BE4A7
+                               FDE4BB3A4875BA84553AE120ED77C9CF
+            stream[192..255] = DEC4B603E6A6F911B68E5C1265FA2004
+                               71B296A647D20C13E42202C1A3AAE880
+                               305F969BB88002C8FC00CC5DBE40AA06
+                               4AF85646AA8C7F7191FE26FAA2918A95
+            stream[256..319] = 849431145F27957D53CD355501363E4C
+                               5F191DA666B77364E5866CAA16A9DEF0
+                               DDB9BC266EF41DB0C2A7642B9E8DD27D
+                               60DEA6E69052D4BDE9FC83B2578C72E7
+            stream[448..511] = 5556EF9874E3150FC539C9BD3BAFD308
+                               8FB347D5E38DB318A72AE0C6B6FB4163
+                               082545A9AD8872AC383A78230729D083
+                               31BFC3F2C80DA20617435FFDF2529A7D
+                  xor-digest = BA9CA5F3C27246F931824A9A425F2390
+                               E183188FEDE5BE3591053ADCC933E1F3
+                               DDF5627A94F80F8922F53E951490E96B
+                               F51491ED2D6DA26F3BF69CC41B8C0C98
+
+Set 5, vector#207:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000001000000000000
+               stream[0..63] = C449AF4CD437641A3B40D0E0E7B5696D
+                               CE973B3B217E02DC20B2F5573FDDF78F
+                               E6E55D75CFAB8EE04C8962376D22A843
+                               A80BB79C8B8D8B500C4B6DA27748C398
+            stream[192..255] = D5C92B62B0818165096551DF2B007F66
+                               2DF953742EF0BBE97982FF9D3EE83E1B
+                               87EC9D710CF1700262B1CAA9C68A897A
+                               8AB4A162DB0443A43962EECFE5B4C0DF
+            stream[256..319] = 3B8CC7E847669AC6858B7BB716206386
+                               40D8C2DD259EE4970A5F254077101271
+                               DF745AD7F57712065E2D03B9D7220591
+                               5C8C033A4F9146EE561B4179DB465989
+            stream[448..511] = BA4ECB7D74CEE56CF1D5AB636BBD6421
+                               C30A51DABDCED17C8D50F5293424AFCE
+                               33AF71095CAAD3913A8A3A12286A8E91
+                               89DAFCC1E2E744FBF4B526E910B5F2CF
+                  xor-digest = FAD57A608E04CD71B176BBFADED7B229
+                               D855A8025E963B55FB83EC7311427779
+                               490F25D34C6385FE1C036FF0807E136F
+                               40C10588678E2414163AF1819EF7D3C9
+
+Set 5, vector#216:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000008000000000
+               stream[0..63] = 989F302DF6BF8C63F9EB69D2625115B1
+                               2CCDA42A2D33BC6F21BD55E0594DBAAD
+                               9A294DDFD6710E36000C27FEA7E03440
+                               C8A6E728716D0DF14E825B798A6C420C
+            stream[192..255] = 3F3140320AA02367512E7C1789F5C03D
+                               83CC634354237E78E16B1A64DBDFA6EF
+                               0697B28BDFFAEC311C6E2089BCF64203
+                               A2EC7BF3CA922080380241A47A673634
+            stream[256..319] = 6049048A5307D55D6DB387A6149C7B23
+                               0AE33195D53E0026103EB44489BB86C6
+                               BAEC7A0D920CAE25B1E7B9F07C07C4AF
+                               6485FF281C7B7FE1D61E660AE55C20EA
+            stream[448..511] = A6DCBEC85525FA19FA6066470B4CD83F
+                               17D42DB3353B327BF3DD6E7D047CD752
+                               71E79CCBD46E757F3654C2506C2B593A
+                               BC93B8985C491017A8E616D69E8974FD
+                  xor-digest = 55BE97FD8317A47742F8F3BB762160AA
+                               7FDFBA371864823D93EF6C029D457AC1
+                               2D679CB424DA9EAF8E4FE28271C66F06
+                               1E91D8F2EF41733AC1084F54330C9786
+
+Set 5, vector#225:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000040000000
+               stream[0..63] = B8989CF76BB1AE894699604320C14706
+                               E20C8BD86C016B5E2EF705AEC54C6023
+                               2A9AA961C10914A8D910D517059A93F9
+                               78C537767A057E0E11DBB5C9BBC4EFA9
+            stream[192..255] = 83FC232D21D0DB82747D9EDFEDFB58E2
+                               BB37362FA2B4E1AA0C9A58AE521EFC86
+                               C512831CC6D2E85FBD96FD3B60D1D153
+                               E83DDC6C5755899CF96FDF69E3732E4E
+            stream[256..319] = 201DDE5D82B754341A3452BF7DDDBF6F
+                               167B2A087900EF40E4268A80217D7310
+                               F1E9E25C707A1EC05219E3CCFEC0F6F5
+                               28CD98534F6C579A1ACD3171D131D87B
+            stream[448..511] = C2F68B5F03B0045FEE0FC92DA08F8545
+                               762F73E553D2F539C64B88D4FAC9B011
+                               DE0504D66007A115E428F627A667FA2E
+                               296F222734FA0F905548058897DEA990
+                  xor-digest = 7DFA65F57FD58891C5576B3CC7002513
+                               C1A983E9D31317B681604DA09F176AAC
+                               4FD78CE84EB9427BE8D6A63058582F16
+                               148D55B3C2544CF4DB9306699CA74D80
+
+Set 5, vector#234:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000200000
+               stream[0..63] = 307B13F3D3EEEA4C8FAF34416689F354
+                               AD26336D6B33DFC5AA004420D2DEAA69
+                               F69E531EB6D672AD62B2A6A136046373
+                               F70272E84E14CABA9AEA3102863A0B10
+            stream[192..255] = 8E4DA19FEDAD4C842917ECD5E7256097
+                               C2F524324D8A974D4185D8B11B611C72
+                               6C39DDB5E58180971DA181D36A289CBC
+                               1937E8F020645EC8D0363A58C6147F38
+            stream[256..319] = 012A99871D6C4CB7328C1374F37D0BE3
+                               DCC2232F6484A22C8F330D77316A1756
+                               71DF7CB32773F25D772BFE9DED5981B2
+                               0C3F0DDB2879AF61E7549F03AE26D233
+            stream[448..511] = 47C6CA462D35580BC0C78C6427FB96F3
+                               BB762662F5B52FB3938CCCEAC35884C1
+                               54F5BBF513970FC08F51C91059A757B9
+                               A8B6F1EFE467FAADA8D4DF68C6AC1942
+                  xor-digest = 6409F8C255BAE6167686F5F9C7EB2349
+                               0FC7BA4DCBC80006B57A5F56CA9F907F
+                               849C2A0FB0D74CAAFC0E2D4367E2912E
+                               BA6487D8A48DA60E48277A20E326266A
+
+Set 5, vector#243:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000001000
+               stream[0..63] = 543BAEFA799FA0CF5295B92EF3FDC07D
+                               69B87C1B5FF0A9F25B32F8FCC473D04D
+                               54B6E467D6183F25E3664A330889889F
+                               A530E354B6E53EBC78354100637A62C3
+            stream[192..255] = E15997D1E7C0FA38333DEE2EE2477A4F
+                               AD32F0810E8D3D65EAFB110C2B8D0948
+                               59DC45C4AA38B8050A87C23782E1A26C
+                               C193985BB0C3E754A528BEAAE1508D76
+            stream[256..319] = A94F1BD38219097B70EC0700A64B0ADC
+                               7BA8883B5C2C3BBABD0497E80D53121A
+                               2DC5A5C6A77913330EF5469871BABF86
+                               0A09F1474D893ADC28B473EE508F473F
+            stream[448..511] = A43AC01FC186AB42241ED3729E7EEA39
+                               F0823D124E8CB696E2F4B047A6B71164
+                               5B803623CD0371C4975217B3CBD7D9B2
+                               FD89D3B6BD23FD11FEC0B03B9CC22AC0
+                  xor-digest = 792A5EDB6E7FDBE99B7EC2119665C2F2
+                               34038F561BB1923F3BF493AE35CE2006
+                               55B8EE47490B53EBB481AB7C6B82FACB
+                               233AD86D74385FA108C94666CD34C164
+
+Set 5, vector#252:
+                         key = 00000000000000000000000000000000
+                               00000000000000000000000000000000
+                          IV = 00000000000000000000000000000000
+                               00000000000000000000000000000008
+               stream[0..63] = CB4377099B2D7CD6A982A1B1A53E05F2
+                               E097164EDCB381468C21D8F0615A654A
+                               45A4D09B7C0218A19496EA71CEEEAE5A
+                               886307DB0026C96049B60E5154F99AA4
+            stream[192..255] = 25FCE0B7E28D5D0D1654D912DBB21AE0
+                               288CCC71396CA5AA36AC44AB08EC72A1
+                               01E5B189535C1987B79DE4C4E32DB7FA
+                               48ACBC8F854868FC287E03D54752230C
+            stream[256..319] = D3B02A39A4E467C44C109E1E25593278
+                               2E9B3CCB02D6F107C9263A24E113FAEF
+                               847A9064E1AD1EC8881EFEB239CAD6C4
+                               E90ACEC36A7E87E002F35D477CD63F2B
+            stream[448..511] = 7D4282D7E11439C04ACFF087708DA22D
+                               236F1A08A6343704DA4D24EA3582253A
+                               35419183A915B571DDE80C1DEE2B8A13
+                               76EE973234FFF6A0DD91D31037F51C72
+                  xor-digest = D52720D8DF114235D99E5292E14DE96F
+                               9D8478E016CD40EBA25C4B9D8E11713E
+                               FE9AC151E1F39377FCC07D06E9BF6931
+                               6EFD7E27F87E9F76DCBF7831CC3FA98B
+
+Test vectors -- set 6
+=====================
+
+Set 6, vector#  0:
+                         key = 0053A6F94C9FF24598EB3E91E4378ADD
+                               3083D6297CCF2275C81B6EC11467BA0D
+                          IV = 0D74DB42A91077DE45AC137AE148AF16
+                               7DE44BB21980E74EB51C83EA51B81F86
+               stream[0..63] = 23D9E70A45EB0127884D66D9F6F23C01
+                               D1F88AFD629270127247256C1FFF91E9
+                               1A797BD98ADD23AE15BEE6EEA3CEFDBF
+                               A3ED6D22D9C4F459DB10C40CDF4F4DFF
+        stream[65472..65535] = CFF0058C45807C1F4300D118FDFC3B21
+                               370936B39391791C92A821E1C8E8F248
+                               BBBF378679468218FF5F6560B79A6015
+                               82B81315DC19D8583263958B068BEA48
+        stream[65536..65599] = 871A09D393D8888EBEA453F518BD300D
+                               8233E906A31631D29A4A1834E268C3E4
+                               F65F4F65B1B9E55606BDF28A571CA4E7
+                               59BDE4718E1E13731663F5CAF1CB0F1E
+      stream[131008..131071] = 15360407DA7B389DF28C08B2221F5E0D
+                               96B34839325795A70A3F65D9CBB3848D
+                               8C0793A53E8C4D71D8B53B2923A90B37
+                               FE412A4485F0CC741E65743C6F1ECB4A
+                  xor-digest = C08A2B344B4A486BEB4568EFA585A481
+                               64C90A34752FC3523C3A99D764AE33D6
+                               825915067FD64D90EE81175416A3B4CE
+                               780426A44A4530994A1A8A83A5E9E243
+
+Set 6, vector#  1:
+                         key = 0558ABFE51A4F74A9DF04396E93C8FE2
+                               3588DB2E81D4277ACD2073C6196CBF12
+                          IV = 167DE44BB21980E74EB51C83EA51B81F
+                               86ED54BB2289F057BE258CF35AC1288F
+               stream[0..63] = C44B5262F2EAD9C018213127686DB742
+                               A72D3F2D61D18F0F4E7DE5B4F7ADABE0
+                               7E0C82033B139F02BAACB4E2F2D0BE30
+                               110C3A8A2B621523756692877C905DD0
+        stream[65472..65535] = 5989C607133DBC6C0F2DD022D4812ABF
+                               91111E266BBC8EF91F1759B3CFD73E12
+                               432C1334E3549EA54917BC0156672E13
+                               DBFDE5F0CE6C504EF4AB69A9C311FC79
+        stream[65536..65599] = 0D22D9DD0AAC594F812839C7C4D0B690
+                               7A19FE4985E1A0DCCA5930E6F5A70055
+                               452978828569A28AC62C30274CAAD865
+                               F4F8BC7E3F058B50C454F3CA360264AF
+      stream[131008..131071] = D17E6611F2754F60629B7CF29CF35888
+                               3765A08C62167AC620C1CBCD1058F527
+                               4B2D4335591F7962A0A76D5F430332AD
+                               C16B13E7EEA80188974860D2EE3BE81F
+                  xor-digest = B7163FD0F8A41562DCB10212DB9C97DF
+                               C25C6BEBEB6331F072118F046E508887
+                               FB82C0A3FF8B0E0B5765131BD58F3181
+                               AFB3803A2C1C8C70877AE29F74D433F4
+
+Set 6, vector#  2:
+                         key = 0A5DB00356A9FC4FA2F5489BEE4194E7
+                               3A8DE03386D92C7FD22578CB1E71C417
+                          IV = 1F86ED54BB2289F057BE258CF35AC128
+                               8FF65DC42B92F960C72E95FC63CA3198
+               stream[0..63] = 9D13AA06122F4F03AE60D507701F1ED0
+                               63D7530FF35EE76CAEDCBFB01D8A239E
+                               FA4A44B272DE9B4092E2AD56E87C3A60
+                               89F5A074D1F6E5B8FC6FABEE0C936F06
+        stream[65472..65535] = 85D7E59D15760E12C5E8D0D5CD9B46E7
+                               00F8E821C91CAC8C37A6200E61A71E84
+                               15932834C0A06DC7E5738E11A0F9A9C4
+                               38ECE66D8D5A654A754FC5858B28EE21
+        stream[65536..65599] = CEC10B6D37543B35CE32B152BE2928FD
+                               C8476E341F23AFB3B404D40EC0657A8E
+                               95F5CF7297EB1948385A5FB2FBBFAF66
+                               E252F35AA1DF199FED99DA532E5858E3
+      stream[131008..131071] = 9DF7785EB3E69ED977E6DCC59EDA18A7
+                               41029BCCC4590A46B8F9FAB96B5C4268
+                               2FE49EC0BF79FBB637E6DEEACC068E4C
+                               93D215555CF876E17F37968576C5D5FC
+                  xor-digest = 0B36039A89999715A7F53207DD60203A
+                               B397397C718C7057E82E36C05E49506C
+                               911F9596F2A5818E0ABE6BE666086DA7
+                               9B18E89A43C64B9227BF9DF65CD55C35
+
+Set 6, vector#  3:
+                         key = 0F62B5085BAE0154A7FA4DA0F34699EC
+                               3F92E5388BDE3184D72A7DD02376C91C
+                          IV = 288FF65DC42B92F960C72E95FC63CA31
+                               98FF66CD349B0269D0379E056CD33AA1
+               stream[0..63] = C8632038DA61679C4685288B37D3E232
+                               7BC2D28C266B041FE0CA0D3CFEED8FD5
+                               753259BAB757168F85EA96ADABD823CA
+                               4684E918423E091565713FEDDE2CCFE0
+        stream[65472..65535] = 340CA4A2B985CCB5C07964B36AB84409
+                               679FFBC616ECFCC672A0F61BBE94AD0F
+                               E6C065CFC069BCA7D33FF35BB2967D0F
+                               FE84BC6006E46D7CA0C1AAEE279E8C32
+        stream[65536..65599] = B5221331961267143AF1A5EC7D1118CD
+                               C96A4B088404F5B6C5BE7320C87C4E90
+                               F5333906AC759D7747EA06903525620B
+                               D05703033C5F1973809B9D674688461B
+      stream[131008..131071] = DF8934D8386B59B681CC9146E6EF9A7D
+                               765366267B4BDE3DE8DD15B714A397D4
+                               08432F2B975F6274132FECDA89E0FB32
+                               379023ACDA101452D30657E6D5059828
+                  xor-digest = 36D3E252F992C30C76818B3364613BE3
+                               7F84FC4B848272404E7D9E689BCB945A
+                               A85CBA790187A4FAF9811CB0824F2F46
+                               6DB05D3F96A0AF233486AD28A593AC24
+
+
+
+End of test vectors
diff --git a/crypto/test/data/keys/README.txt b/crypto/test/data/keys/README.txt
new file mode 100644
index 000000000..352170fec
--- /dev/null
+++ b/crypto/test/data/keys/README.txt
@@ -0,0 +1,4 @@
+The pbes1 and pbes2 folders contain a series of encrypted private keys generated with openssl.
+
+The password for all keys is "12345678a".
+
diff --git a/crypto/test/data/keys/pbes1/pbeWithMD2AndDES_CBC.key b/crypto/test/data/keys/pbes1/pbeWithMD2AndDES_CBC.key
new file mode 100644
index 000000000..a765d9c62
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbeWithMD2AndDES_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbeWithMD2AndRC2_CBC.key b/crypto/test/data/keys/pbes1/pbeWithMD2AndRC2_CBC.key
new file mode 100644
index 000000000..40b449b40
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbeWithMD2AndRC2_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbeWithMD5AndDES_CBC.key b/crypto/test/data/keys/pbes1/pbeWithMD5AndDES_CBC.key
new file mode 100644
index 000000000..f54557e4d
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbeWithMD5AndDES_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbeWithMD5AndRC2_CBC.key b/crypto/test/data/keys/pbes1/pbeWithMD5AndRC2_CBC.key
new file mode 100644
index 000000000..595ee5049
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbeWithMD5AndRC2_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbeWithSHA1AndDES_CBC.key b/crypto/test/data/keys/pbes1/pbeWithSHA1AndDES_CBC.key
new file mode 100644
index 000000000..2eb164ac5
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbeWithSHA1AndDES_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbeWithSHA1AndRC2_CBC.key b/crypto/test/data/keys/pbes1/pbeWithSHA1AndRC2_CBC.key
new file mode 100644
index 000000000..c724d63e4
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbeWithSHA1AndRC2_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC2_CBC.key b/crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC2_CBC.key
new file mode 100644
index 000000000..4455719c4
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC2_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC4.key b/crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC4.key
new file mode 100644
index 000000000..efc0c1e00
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbe_WithSHA1And128BitRC4.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbe_WithSHA1And2_Key_TripleDES_CBC.key b/crypto/test/data/keys/pbes1/pbe_WithSHA1And2_Key_TripleDES_CBC.key
new file mode 100644
index 000000000..ba349f1f6
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbe_WithSHA1And2_Key_TripleDES_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbe_WithSHA1And3_Key_TripleDES_CBC.key b/crypto/test/data/keys/pbes1/pbe_WithSHA1And3_Key_TripleDES_CBC.key
new file mode 100644
index 000000000..a9098b7f9
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbe_WithSHA1And3_Key_TripleDES_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC2_CBC.key b/crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC2_CBC.key
new file mode 100644
index 000000000..71dafa9bf
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC2_CBC.key
Binary files differdiff --git a/crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC4.key b/crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC4.key
new file mode 100644
index 000000000..85a18e48f
--- /dev/null
+++ b/crypto/test/data/keys/pbes1/pbe_WithSHA1And40BitRC4.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-128-cbc.key b/crypto/test/data/keys/pbes2/pbes2.aes-128-cbc.key
new file mode 100644
index 000000000..8b8fa28d5
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-128-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb.key b/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb.key
new file mode 100644
index 000000000..a30a3e384
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb1.key b/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb1.key
new file mode 100644
index 000000000..9b3515487
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb1.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb8.key b/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb8.key
new file mode 100644
index 000000000..dc974b0fd
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-128-cfb8.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-128-ecb.key b/crypto/test/data/keys/pbes2/pbes2.aes-128-ecb.key
new file mode 100644
index 000000000..1a9dbfa0e
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-128-ecb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-128-ofb.key b/crypto/test/data/keys/pbes2/pbes2.aes-128-ofb.key
new file mode 100644
index 000000000..0cb9df7ba
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-128-ofb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-192-cbc.key b/crypto/test/data/keys/pbes2/pbes2.aes-192-cbc.key
new file mode 100644
index 000000000..fa9b39b9c
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-192-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb.key b/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb.key
new file mode 100644
index 000000000..ac21ae937
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb1.key b/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb1.key
new file mode 100644
index 000000000..c33f3ea04
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb1.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb8.key b/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb8.key
new file mode 100644
index 000000000..31016341d
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-192-cfb8.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-192-ecb.key b/crypto/test/data/keys/pbes2/pbes2.aes-192-ecb.key
new file mode 100644
index 000000000..0a061a073
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-192-ecb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-192-ofb.key b/crypto/test/data/keys/pbes2/pbes2.aes-192-ofb.key
new file mode 100644
index 000000000..cdc4cb48a
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-192-ofb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-256-cbc.key b/crypto/test/data/keys/pbes2/pbes2.aes-256-cbc.key
new file mode 100644
index 000000000..393f89244
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-256-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb.key b/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb.key
new file mode 100644
index 000000000..7e88cb710
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb1.key b/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb1.key
new file mode 100644
index 000000000..9a8e33fb3
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb1.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb8.key b/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb8.key
new file mode 100644
index 000000000..84643b610
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-256-cfb8.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-256-ecb.key b/crypto/test/data/keys/pbes2/pbes2.aes-256-ecb.key
new file mode 100644
index 000000000..293bde51a
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-256-ecb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes-256-ofb.key b/crypto/test/data/keys/pbes2/pbes2.aes-256-ofb.key
new file mode 100644
index 000000000..f47d92f95
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes-256-ofb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes128.key b/crypto/test/data/keys/pbes2/pbes2.aes128.key
new file mode 100644
index 000000000..0711ff29a
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes128.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes192.key b/crypto/test/data/keys/pbes2/pbes2.aes192.key
new file mode 100644
index 000000000..6fea76e44
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes192.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.aes256.key b/crypto/test/data/keys/pbes2/pbes2.aes256.key
new file mode 100644
index 000000000..b449e07bc
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.aes256.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.bf-cbc.key b/crypto/test/data/keys/pbes2/pbes2.bf-cbc.key
new file mode 100644
index 000000000..4b2601e74
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.bf-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.bf.key b/crypto/test/data/keys/pbes2/pbes2.bf.key
new file mode 100644
index 000000000..7fbb6ed8c
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.bf.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.blowfish.key b/crypto/test/data/keys/pbes2/pbes2.blowfish.key
new file mode 100644
index 000000000..2b19b2446
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.blowfish.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.cast-cbc.key b/crypto/test/data/keys/pbes2/pbes2.cast-cbc.key
new file mode 100644
index 000000000..383b6d447
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.cast-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.cast.key b/crypto/test/data/keys/pbes2/pbes2.cast.key
new file mode 100644
index 000000000..208cc5fa6
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.cast.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.cast5-cbc.key b/crypto/test/data/keys/pbes2/pbes2.cast5-cbc.key
new file mode 100644
index 000000000..728de6fc0
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.cast5-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-cbc.key b/crypto/test/data/keys/pbes2/pbes2.des-cbc.key
new file mode 100644
index 000000000..8c8f4bc6e
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-cfb.key b/crypto/test/data/keys/pbes2/pbes2.des-cfb.key
new file mode 100644
index 000000000..0cdba7c57
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-cfb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-cfb1.key b/crypto/test/data/keys/pbes2/pbes2.des-cfb1.key
new file mode 100644
index 000000000..9474026e6
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-cfb1.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-cfb8.key b/crypto/test/data/keys/pbes2/pbes2.des-cfb8.key
new file mode 100644
index 000000000..c5d5594c0
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-cfb8.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-ecb.key b/crypto/test/data/keys/pbes2/pbes2.des-ecb.key
new file mode 100644
index 000000000..1798e4d0c
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-ecb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-ede.key b/crypto/test/data/keys/pbes2/pbes2.des-ede.key
new file mode 100644
index 000000000..0ca0df8f4
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-ede.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-ede3-cbc.key b/crypto/test/data/keys/pbes2/pbes2.des-ede3-cbc.key
new file mode 100644
index 000000000..dd3579bbe
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-ede3-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des-ofb.key b/crypto/test/data/keys/pbes2/pbes2.des-ofb.key
new file mode 100644
index 000000000..d92de62ca
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des-ofb.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des.key b/crypto/test/data/keys/pbes2/pbes2.des.key
new file mode 100644
index 000000000..3b4f3cb1a
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.des3.key b/crypto/test/data/keys/pbes2/pbes2.des3.key
new file mode 100644
index 000000000..78ca4a517
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.des3.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.rc2-40-cbc.key b/crypto/test/data/keys/pbes2/pbes2.rc2-40-cbc.key
new file mode 100644
index 000000000..6f50f1381
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.rc2-40-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.rc2-64-cbc.key b/crypto/test/data/keys/pbes2/pbes2.rc2-64-cbc.key
new file mode 100644
index 000000000..1a70f9721
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.rc2-64-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.rc2-cbc.key b/crypto/test/data/keys/pbes2/pbes2.rc2-cbc.key
new file mode 100644
index 000000000..c8778c41f
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.rc2-cbc.key
Binary files differdiff --git a/crypto/test/data/keys/pbes2/pbes2.rc2.key b/crypto/test/data/keys/pbes2/pbes2.rc2.key
new file mode 100644
index 000000000..fef0f143a
--- /dev/null
+++ b/crypto/test/data/keys/pbes2/pbes2.rc2.key
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/README.txt b/crypto/test/data/openpgp/dsa/README.txt
new file mode 100644
index 000000000..9abffbf27
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/README.txt
@@ -0,0 +1,36 @@
+This archive contains material to help verify interoperability to the
+OpenPGP DSA2 design as implemented in GnuPG.
+
+Keys are located in the keys directory.  Included are:
+
+ 1024 bits, 160 bit q size (i.e. regular old DSA)
+ 2048 bits, 224 bit q size
+ 3072 bits, 256 bit q size
+ 7680 bits, 384 bit q size
+15360 bits, 512 bit q size
+
+All secret keys have the passphrase "test".
+
+Note the inclusion of 7680/384 and 15360/512 keys.  They're large,
+inconvenient and absurdly slow.  GnuPG will accept any size key, but
+will not generate DSA keys over 3072 bits.  I include these keys
+mainly for be-liberal-in-what-you-accept testing.
+
+There are are signatures issued by these keys in the sigs directory.
+The filenames indicate the key used to make the signature, and the
+number of bits of the hash.  In the case of the 1024-bit DSA key
+(160-bit q size), there are 5 signatures using different hashes.  This
+is to demonstrate hash truncation to fit in the 160-bit hash size of
+that key.
+
+File			Key size    Hash
+----------------------  ----------  -------
+dsa-1024-160-sign.gpg	 1024 bits  SHA-1
+dsa-1024-224-sign.gpg	 1024 bits  SHA-224 (truncated to 160 bits)
+dsa-1024-256-sign.gpg	 1024 bits  SHA-256 (truncated to 160 bits)
+dsa-1024-384-sign.gpg	 1024 bits  SHA-384 (truncated to 160 bits)
+dsa-1024-512-sign.gpg	 1024 bits  SHA-512 (truncated to 160 bits)
+dsa-2048-224-sign.gpg	 2048 bits  SHA-224
+dsa-3072-256-sign.gpg	 3072 bits  SHA-256
+dsa-7680-384-sign.gpg	 7680 bits  SHA-384
+dsa-15360-512-sign.gpg	15360 bits  SHA-512
diff --git a/crypto/test/data/openpgp/dsa/keys/DSA-1024-160.pub b/crypto/test/data/openpgp/dsa/keys/DSA-1024-160.pub
new file mode 100644
index 000000000..3fec64eb8
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-1024-160.pub
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-1024-160.sec b/crypto/test/data/openpgp/dsa/keys/DSA-1024-160.sec
new file mode 100644
index 000000000..8ee1179a8
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-1024-160.sec
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-15360-512.pub b/crypto/test/data/openpgp/dsa/keys/DSA-15360-512.pub
new file mode 100644
index 000000000..4f931c657
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-15360-512.pub
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-15360-512.sec b/crypto/test/data/openpgp/dsa/keys/DSA-15360-512.sec
new file mode 100644
index 000000000..3c204bff2
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-15360-512.sec
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-2048-224.pub b/crypto/test/data/openpgp/dsa/keys/DSA-2048-224.pub
new file mode 100644
index 000000000..1c8dc6984
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-2048-224.pub
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-2048-224.sec b/crypto/test/data/openpgp/dsa/keys/DSA-2048-224.sec
new file mode 100644
index 000000000..776edfcb5
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-2048-224.sec
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-3072-256.pub b/crypto/test/data/openpgp/dsa/keys/DSA-3072-256.pub
new file mode 100644
index 000000000..307205cf2
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-3072-256.pub
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-3072-256.sec b/crypto/test/data/openpgp/dsa/keys/DSA-3072-256.sec
new file mode 100644
index 000000000..66008cb29
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-3072-256.sec
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-7680-384.pub b/crypto/test/data/openpgp/dsa/keys/DSA-7680-384.pub
new file mode 100644
index 000000000..6c888a44d
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-7680-384.pub
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/keys/DSA-7680-384.sec b/crypto/test/data/openpgp/dsa/keys/DSA-7680-384.sec
new file mode 100644
index 000000000..b57f5d9ea
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/keys/DSA-7680-384.sec
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-1024-160-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-160-sign.gpg
new file mode 100644
index 000000000..c90658540
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-160-sign.gpg
@@ -0,0 +1 @@
+$xp=)O'gT<ꑚ_(ba~IbSZ/겠պe,(p̊=sK
\ No newline at end of file
diff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-1024-224-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-224-sign.gpg
new file mode 100644
index 000000000..8485bd335
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-224-sign.gpg
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-1024-256-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-256-sign.gpg
new file mode 100644
index 000000000..bebe1fdbb
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-256-sign.gpg
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-1024-384-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-384-sign.gpg
new file mode 100644
index 000000000..f84c3035d
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-384-sign.gpg
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-1024-512-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-512-sign.gpg
new file mode 100644
index 000000000..f700ce473
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-1024-512-sign.gpg
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-15360-512-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-15360-512-sign.gpg
new file mode 100644
index 000000000..bbdb44c2a
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-15360-512-sign.gpg
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-2048-224-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-2048-224-sign.gpg
new file mode 100644
index 000000000..d64c8176f
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-2048-224-sign.gpg
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-3072-256-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-3072-256-sign.gpg
new file mode 100644
index 000000000..2da027129
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-3072-256-sign.gpg
Binary files differdiff --git a/crypto/test/data/openpgp/dsa/sigs/dsa-7680-384-sign.gpg b/crypto/test/data/openpgp/dsa/sigs/dsa-7680-384-sign.gpg
new file mode 100644
index 000000000..f313c6aec
--- /dev/null
+++ b/crypto/test/data/openpgp/dsa/sigs/dsa-7680-384-sign.gpg
Binary files differdiff --git a/crypto/test/data/openssl/README.txt b/crypto/test/data/openssl/README.txt
new file mode 100644
index 000000000..03d993374
--- /dev/null
+++ b/crypto/test/data/openssl/README.txt
@@ -0,0 +1,8 @@
+Some OpenSSL-generated files, all containing the same DSA or RSA key,
+with various types of encryption applied (as well as the unencrypted version).
+
+The password used for all the encrypted files is "changeit".
+
+The PKCS#8 files which contain ENCRYPTED PRIVATE KEY use this password for
+the EncryptedPrivateKeyInfo object stored in them.
+
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes128_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_cbc.pem
new file mode 100644
index 000000000..7af858e9c
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,3D7028A746BE6B09694E16A222C543CB
+
+RkTEJRJjGfaMfNc876Tx1hD92cblJRj7TvUafRKnH0J3Zv7l67MSG/6rY5HD91HP
+s9i9Se+H8Sjn/HaUl3QTZv04egloNlL3MPSkI5fusR6maZGPVLRJBLfVKYQZVDja
+9YRe+ZhXMS8jTe/IhYMcTlQLBnnwmmgZC09Y9Wm39idu7lytOl3JBMgz0aUNA+P6
+lN2MtaQyIBXHbaqfNDGFn/r7+MH4CGw6MtrPzGqRJgGMHhV6T5o/x0nEU+loQVOK
+mPkSZTxBbn7xUb4JvFPnLTbsI4Cnre3QmfmDwkCAklQXqAIT9Ex1Slq8qaCc6TEf
+mWJQCYPUkpQOqyinR8o1VbYm3DFFvE5F+CktJrppqkQvAct0dQNjMTBFxUjCkZum
+qGfAslGPBREmmnsExm5GThYqA5LN+qo2prBtvt6Eso0i2jNiXA8bi5OfDzDr24R5
+/RKUdFPf7keaAjg9jSArwp6EfM3y3sj2riibwZlty2ckPJw3SwxIe6QSMwKRbKlh
+GJoi05/cO0NxQYhMmlwVN9v5+YpvWmT3CsFvCA+Zb5rXPx2AZpFv8YoHdQb0qyEs
+b5YuVoavL58+BWIPQpeYy/jttR5pEPpgM+C/6/1o4Cae4lwppP2OYFl1fsqyqbKh
+iadErB6QRaJCnfnhG6511CxY+vZtQE5EM36blOl/op+6G+36ApuqDtfA0C074daV
+uHfcqA/g5dODEJP+ps6yoWtM5lbd5bZZVidWhrU6Skbt0faF9w5ECF0qkYDGqF85
+qqFcaoimq+NP7EtUEFSneOee72zYALXyzjoEU9InktzDi0Oufojzc1gjhh7LbObw
+UBANPHTsbaL6FPTEs4a3JYSyat9m/R5GAaT0EBynHxvdQRGNhtEWFPkpGYUrAz9W
+0A9mNX1as8Jsxkh9wqjgOR6Xpbqh0aFHNnkodwV72H5ROga5EN8/bbuCBxInNzy8
+o9z19AnajR7vCW/p42QwsGfSolQgE3KBdqWsle81LcCPVQPQshXzcjgBHZbH9/mY
+M4bX4iEsC9yeNgoMcHtIagOKipsqd4nuPskutf07Mh71OXFuxsVyGcOBVhhdZCb0
+3ZYzVi+nzORPRZ93nPXipy3+NmoARk7mhXDgX9p1bPI=
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes128_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_cfb.pem
new file mode 100644
index 000000000..de088f91e
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CFB,C0CCB782DF620FA388D9A356F8B7C346
+
+DftIvr+HZuCHBanw4n8P5ZajHAw1ldQkSgLxtxY0ZYhhVDLEqEqh6z+4ySjZz5SR
+KY7kYFo6yJnURurg3DAGvJ55s6jgyrRHQZkhiO1fBxhyarOfcBjJauJKDT4uhFtC
+LWZ7dqft3PlcHi09mFKjK+BYjULe1QkdrKQlV5FBpCj7ENuHqtfx//bV+IWWVnbu
+QRx4ec2nNCiS2qiI9Qg7fgMdXWrpJlr8Zvfmn0Mta3Dn9SWR9hK5J4d3xiBtaF0F
++BNuszy9poxnsRaORZYAsBh2vdLaQyn1gGdehlsWG4J2Zb5RHApYczJcp2AoPX4K
+j9wAzlfLRSZ4Lt5edShd1zf/iDxegBKQFFHTfPA6uu+fe38qckdxVyBdGaCCBvUz
+Quu2DjjXdCWWo8To5C28LVoVyAy+qJaX86vn7yw03/6n0y2dkydiB3u6wnucsom2
+HfLX+pdyarFoNvtCeSW3Y/1Eqd54dDhz3GrSTh6c7G+wiRziKpTduEmoZ+l+CIrl
+tWxmh59YTSeX4mi48+fxTA8xaVwD/j3VuA/jTOQWDW+DXU2z6OcAQ9rlOnT6Jad6
+P2El+vgLrIFbC4eJs2ry6bszqFJ4wieBVnazPCUADLSsXVwbFuO9oB4129y3Yg+U
+dE+lN24KV0kC/YIdO7c2PghaFY98CVrBX/oocHy4j122fHfboiPNh7S7n6cqJHh2
+JKKQK1qTdfULAN5ypecl27gWeM2i3ib2C5jJiOFUlwiAkZWLRJlsiJOk+b/rI5FD
+tM7yFanhEtcYumRRoSzKII3tF0h+z2AwzPdsyJDdASCzo/DmhB0fg0O8G0q/isNi
+VV2zL+w7mNmf79QsrGVA39Y+G/uKS2QPf3bGFthzYZwKH1M9hTN/do8wCCJJv7MR
+Ejnd32srumBOvGXnYtGuHnT3qRA1mj82B00bdfwCd09GGUr6mEQwfvsDOR3q4OfH
+eGCn9NkWKYvf/QAxCG9Vh7u62sUlXKS08hJcVAgBOzN10wFISTIOAvedt/q5GMvm
+nRuF/ixs6f6LNy/VgyztHoQ4vN4HBf8teDsbWSMDvlLkU6tQZjyuu8JkTjeDaqMv
+GbCzrRBldS3zMXX2OaWpZohi
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes128_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_ecb.pem
new file mode 100644
index 000000000..4f69fa7c7
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-ECB,174C8C70B397BCF00CAECA7AAF7A0A73
+
+wzs0bJqGg+Scn00TgtgXyV6hopQKVWMEFnMpu6R/Sp1tbPVlr+m5+SppJFVyW3WJ
+YeFSwXzuVAsnbD9qIZpAlco1ZYpmRXaY6IfXJKYf58v2IrqkxVd6AwjGN2FloSNp
+b/DinJXJe807tNAkuBLQ/7QlkCv/BmZMeYBl60XYIH8LDF/T/ON2hREl49zr/GLY
+bwmVzgRpfl3c8QIt6Yl9uKOqCFJmMHD3YS+dT2RwuQwqY+U3DNzVoCci6Zjd+gL3
+eb/S6VstodSR55qF8Fkwt+sy5yL6XmhQaGWEgCwDwArN40MWIEpx4NaBxCcqHF7g
+o26bg6CZwY7Rv42RTHKHNPETegZneAMK+e1lNassSijak+A3ng9bxiBquWSKHe0i
+s265Rptr/GvQX0hLxmfjEjvL98dKVDZpvdBaWRqV2lS26jDPiFAHtVsXvF8uo25J
+1aS8FDHaD2DghC5aXTQRaVy1jlMTm2YZeVfiU6+7HVXBkLsVbShqEHxKylxgtB/1
+OAui+st60+o8lvRmn5dT2xnxLn81Bt4qron4pz0LdzC2xl0DqjhXyRsf7kdxr44h
+YN1YzmdU3fYFzQw+VmE8xECIjPukp+0HSb4n7BTGsWvqzntFIrzWGeRmNhjtMcwy
+YJoWGnz+WbxP3DJqSGNdFME7mNI/kaybIkOpbHLLlmgD7XWpeyGYtsU/rzrh5NXN
+YRj6Nf3TWI1zwS2xx95+/5vc5Df+sb1+/33J4hbGOx9KdfqoVlJZ16puvdTq97dF
+x8TVYxk2PfBJpvpChCsFlYBOB29F+kY2qoBKPbrvmFPsPCgI2q4gFuJ9pq1qyDbK
+pq9d1oewOOxR22VMQNGG7tL0tMmtXJ/z0n3Y1UE3aYiSG7apOhooBAQ8grpuwqbn
+mGTz6sYB8fHdCnedcxEUxxuFjXupmBcT2ulUjFZgFrG0SEMElgTDjtG21eurqPKh
+ZgxfkW+tM251WTi6sqjiQO8WYHlU7+XyO3BKfH5v3kz4qXxsmvKfh4UOfRy5f9YT
+Ft5oi1bos0soTvms0d8ckLt9Tph2wgoz3Sc++4DRcF53Ks9N6iUgtTpkEtmd/Uc2
+5+xewYmlfYO2qfiqiF/6dSVfDPjJYR/YLx8KBZ40/e0=
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes128_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_ofb.pem
new file mode 100644
index 000000000..cddcea9fa
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes128_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-OFB,B32C602DACAACE3A4C55B4600D974E5F
+
+w1+kMXURdxpREW3giZg+PooayvatT1Pf1bY/h0Wcm8z0w7zRtQOyjCOdEPNxsdd5
+ZYn3qEIOO+wkw0v0PdK1AaegJfYMbMpSp/iEyFXU/LHS0FpO7o8zmUiAvdeEKAFt
+Qk90gFBiyQyvWEWsp32KQH1/eDSeSLeQbfRfDbh70DkB4nUjYMW/eFL9E/cHCmdw
+0LKUpEycc4s8i/mWCYJF+cQd4J8RHK+Ose2+5z86kHTrbFSlTBEZEXPDRHl8ZsZE
+477A6/Ndy0Mq3+NgMLSl8xacs2v3itdza3AJREVOzvnRmV+NmWtYQ4MQrJrLg2yv
+wfAf4b2r+k8Igbpzn3NCEYolecGfyEWftzTsqTutlFO7RfeW8go4v2MvEsmHTphQ
+k2qaQkdSTFaA7a2O4PKezJap4RRCJhq1d5bw7RwkCpbRshsvrKQqGdTGJxEZZfGY
+6pOt/qRL9LVCGUVdTTdje7fx9okx0LvKo62eKcUBh/AwZGE+ue28g6/77iABuVtQ
+6kgJ3lQK3AQwKislF5cBC9MAkiIomsoVOKiP6+yX74XIa7T+3aWXlsY1oX13+kMW
+zijwOrc114Sus2eS3xSCOWLYN+0GECMrh2NDGDW6tx7i3R20BuEF/IwHob1qjbkz
+hnS8KrRY+174avQDeF1lMSBz4Wfi0O1IDuxWRDRT2z31E4E8EIoJh+73NZr7w6JA
+8usK8RkiJ4ypoOPtRegXX6GBG5UYgI5bn1Ms2X5xSUGIXgG8IwjHDbAAd5xLSWp+
+01HzUsR+6wA3MxYiybTU4eOKNMviM1G4gGsKeuGrDsNnidrHfSzVyOGVVHr51xRI
+9Xie4FX/VX8/7Q5RMsA8Y2eN/yeVwXup65JRhDD5LjILVMy7aA90KX7y/s8KIYae
+n6lB7PtcpRWwhdYSYtnlrJmYmrl55d6ZQtJm2/xjnOBd+igY4YKNjh11xBL8YNo3
+wBjW4/lgrlvC7kbLxO6JIWipPr/6F3bjvmeLclTAZxjM1NU5HhTScGaEA8A4bq4+
+6Jiw9ZUw+TDCOmntkgEublcCMjcAxrawWYO/5EWuOAOkyBsa7BbfsUv3pgPugz70
+qa/CEkshP5e/1VZgFq/BNFtb
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes192_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_cbc.pem
new file mode 100644
index 000000000..9b916321a
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,7FA13403627D9E1FA02FF88F6D594679
+
+hZYB09uY4gjQFEHX8KGI33EzcJijYhBMNJCR9v8UK8IcQIITOfZxYV2BmrfQhuVh
+Kcar1JrQdnc4S7+UDFIjlLV9ErBCvIUQEflP2ByDhxl892EtVcoMKB3BJ2Rgi9mk
+32KhayXo5V2bu2kOv2nTAjp91LebDz/ylmhhJhI86BL0DLjnjTEl99v9OHQsMtb9
+cXZb51mwIynmqU7Wf+PchH83Yw0WOKs4MOrCtsqO9lL7Mf/MiSSiE+S/rpKLPXY0
+4aBxP6fw+HG57gPlNAvv/qKtJu8YgZDqVXhIKNDZRTSRX+B9R1Yo1tgmJVPhk/7x
+mmYUxIb7w9nqa5OrxzFHyNvo1U5dJcXyCEhvUZ3ImR1DZt/oGJYgrPd/8YcYbsNP
+LKmTLUKI5CARZ5KcOjfM8vpKqlfpCg3Yl1FaNIjM0eAhD6XrepLj3faAJW4/YEoZ
+SGMO5atbM0ERT9sNDJTG0iMW6xGL5l/6pzfsTKI/2yMaAeWAyvg1PySNoSH7s6CC
+CfqF0w0VpQEiOPb+qjtmjBDB/VW5kNrRiBQqZAgpO6mED0jAdg9o31tyuuaFDWzX
+41C2viVvxTx5A/xOtPvaDo9EMecc+7MpPLM2VhWhPDiDBYb8PCKqBOEwIyH119MN
+gQEC0IN/itc/J9ybHLCjrF1Rp83T3/XhAaXNVU9msBBpKNjawnwsUUj8gI0JRbx/
+5ehO32sQm8wkMyP/8iKDAqBRkDT3RIEmLi8ms+ZZRmLwGBkSZZzvOK3A5Dder4bp
+dIhOOetvoN6Bs9l1i6Dds64pwsy8IcnLLeNmOag+Qh8+pVUBNZ1zUV3KSizRKh5U
+dyT6VMILd2EAUJYLXs9HNFTtHZglRb96jQ3rkHGmAepeIVnJlNGKByvDUsJQDGl/
+bGNk5Ejz93ylY8JzR1GaYyFVIUU0qY8khbo7bSn/o6II+KjyTTyTkV28jTSD5dYe
+upGHOzmqpGi3Pzaz3DXpbLcMzwYrMP9FuXuqkVWToDs87DCfGqskKtko+zlTV7/P
+eBILwUawtXMJfYntkV247FffKgS3/BNkgEE+iNthOsFMSoqX/3ESBKJdJDfKRH0J
+BkYL8O0I7OwYzfU3gCWVZ8AvAhd+nSqp4H3QUK0QM2w=
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes192_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_cfb.pem
new file mode 100644
index 000000000..9dd5b153f
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CFB,3E445502677C77AC6ED115F8EFD9BBB7
+
+fJXVVcgxhZJXZANfEWDbVmz75ocICvntATRNVgt92sHgl1B2c4cgQC4Xmu7WM/Bc
+ocUlcSpWnoHtWRDumw2cwB+fDb5k3e9qb+aL2juzHkK+kYd2mkRjW8KSG6D8HIwq
+fpvV6NQmVrxI5+n+uabwfil8Ecg9V7GD6ta0QSgt0lc8clp01se+VDacX1uCB7zG
+NtJsr1wUM0SQbEWPEcpLUoYfK0qSO0h8fpnagKrNQLfzFbk85arkpD9XBzxpNO2p
+2fYsc3xZ0RkFauSZGt6ehu0jh1TZNPYDURvSn3uVrseLyR0Gt8LWp+hjIUp9Kpo2
+fLUVaH/7wxpdCAYzo4Ub/gHPfbxo2E5qYmE1oTJyAHplaDqSg8pbwJofiXl12gMM
+IyIC3SCHZJph7xqbKa+W/X4ChxYuN23ZMZ72cmqH4tH/j9IpKrpWEeqjxaj0EwDs
+R06Sz/qAqs9iDMKTkuFTMxGhc09DV9sN4NYczEIEas7gploOdryJGMCM96RtMDS1
+gjW21w0wyfqa7ogsDJJ2/HqKL73Zfn7l0jzmqya7YwcToEfKOSP+a2Q/y3Exr4KO
+FY5PLwKvpBaFcFzJoYhAaPphUzzAQuQFgXj34f4JU9bAXbf7ol7Swcv9JP9tN/mF
+n7z55BbPfC1EiyGyDjeUDWw4XIYF6LtRK3lnvn4uSZFXLmYMJJthwwC/yS+D65LW
+vsW9uuQ2qEfEC3hVbMPP+1KMgRkb9CVbSXBH+B7UoaUkGsJYzdSDeHZHbwiHgxqH
+jb6WcjtUjh7W2VO/MnHBrLg8dnC77OnR4IiqJq/6TenuSu0N/4mm73SH7BtYAugu
+ok/2H7GYfGfWjOnd+QvG/Vjsb+l9gtB6SXYFiWuThjB/sU4kHH8LUUOmGRlC3NDz
+w4pv+cR3tS1zX+evPL0BsZ3ynDSGRbMpss7xVooxIPacFwDN8kHUnWvIBpQKAizq
+blt1owc97vidf9OnZxUMpzw28/PZ+y/vRYSPQrde3kH8mJmu1FC6tLZnqzuCSsgR
+SJSr3/8qqSj3XrAW+nj0Y2P8lItNdFXex7j/RuX3eV5QIyK7uY+z8ZP4gf5q9w54
+p+dQi7Vx8acRjbsU+r85+MRR
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes192_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_ecb.pem
new file mode 100644
index 000000000..c7608e02e
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-ECB,C625A2E97BCB192B31A8E33CB0CD857C
+
+jM0PVjU2r063OACSZgLkaS9ppOj4idZ9hgkdMi58Oi+C5bfhZavbjROyxCG0EMGz
+HnAIRJ4pkJeZTnGElmOEFbaNPb42NAvcrYXAP4XNu5FbZ2SqGKwRnjjN8z7s8+Ip
+MrCyJsWycYy2BNaksJRaDNgazjKgqQxGFlQPJ+j99E4dk5QaduOCrf6YQ2G+1Q+m
+2/uqVujTwmverPnHDNhQI0ZYMY+l8+oVcPHIY3TR3ufecvrGkjFgKH0B+/L7gWSd
+ASvldEnWuFtPMiYnqCPtLgJNKSXO2nlumLc4Gz2ruvYKI1qGPXsVLIGnxISVLUzT
+VQz7NrRYwlvSLWdQNqbrEPvEu4q1KstqIkiPRoC98vG4+VRkf9AXAGqxA+vKYktP
+2Ui/SLhoC/seh9pxYXLsmqP+8bxcNM3VsJQoUUFM2PtfyvzBtuQ7mJQTSFSXgBym
+qXvzx749S4xOot+H6r/bCh8753MMEsgsM39jBsRm1zbaBjaNFG0UBdfFigHWh1zx
+4I44pIHu1AQDexjnfaUVrZFbys0CtM/Wy/3y0I3+mar1Wg3Rc1XL1PJzwDqBoZst
+vg1h0L5OPV1c4CekFnAEx+VI6ImxENoYtZCpbpt90kz3GxRY/eS8roS/SRJ7KizC
+p9bWEsUMwJ4Jl+xvV/VtVG96nKzlU13gkI6lMATYzImK4Fh7hH/LBy/UhNVL8X76
+3fo64CCwE3YkrWEmBDdxt/K8Knj4MUPjBgy/ETVRC7ziG0rUwRSd7zLOoEALMHig
+AtNX+juPvPU7yARw317Q9lZXeytf1AmGiFGjYZR/mduAa9M415uWm6zutIJEz+q8
+KV93bm18JUaQSrX4D6m8IgNhX0EfmRYAIFnB3rv+1rsb61q+4USk0L/1vKT/fGGm
+yvXMCA10N50wGS4wovMYQIl/giMEU8e88f+gqImU1kporgESIOUYUm9tOZ80w4R6
+ITlKCzRuoptMQBGZeJIWfWNLxwYq7NXKpvjNeSOeOqQ4fxhkzEetFERG/2hnszmM
+pqwoZBZQ8bb+T6cmJD1GuxoO3ev258WIUkEZTkFYK2Q/+QKymPZO4ATSAO4N2UqQ
+4TXRqUs4i+1f/BJU0ahnSgmzrynGmskUonKxt6T87lE=
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes192_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_ofb.pem
new file mode 100644
index 000000000..501003586
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes192_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-OFB,7E4DC037A44E5DEE4E005CED36B18C16
+
+hvLtWTLg0+cMFDo3jN0yZc8S7fE6cDdZcBK0aRy+Eg+9kWlnmR/VYqG4xaich3VQ
+wkyhNpBSAoUHY8OKkB8hYsqbGkuKxQ6Db4IJlahCTFgb0yO2C7pUrtGDTvmXVq2n
+qJ4c+4CILeyzIp5yfy0dE8CAsZZcLEdSpPvaNK0VPZEPhelm4WdqqLozYVibR0KS
+2BbVO+E7yHGC/G3xtdbduuYpID1pLwyaebUCNgblggn6FJ0G2+Iu7lndmMU4B1Wr
+phvb+Fd1kL5421u8OOKRVLS2yMtlzbK2Mz7NclEzEs1m6K/xJUzztxImAxElBiiB
+YfOw5WLy278DuD1GCBkSuAKB4XWUtlq0+tJnCzAG0yrdMloKH1m+XF3MXFiRTXgE
+k08PcZchoNgGP51Rcg77skATP9OMamcjnkMx1B8YxTx9O5Vv/oSIjGQrr+t2np2t
+JU1dHTr9QrCeadSz+My0sjlZrL3ZisAwBbu6C0Zta1P1eB+i8ORZvm9HvmadcyyE
+y5oQWv7XwSfAQup/4uuAJ8bQBunIH/ajMF1WmD8rzLcUjG8W0rnBWUtjaxxBdkWv
+xBzgMPm7Q+L/5yhL/TMH3dkUBq+Cg5VQSe9EspNRGKBUgfKYk67Y343Mv91xKtX8
+8Tmh/WlnYXDv8QBnFJZXVnf8HeSFHsHDzfTgAmWHdhisTNwmgSFvBK5ghvhvkbXI
+UIPi+FgeB7P3ccFYnmoMq5qgK0Ki4lU6v57soDrjRl/NttfXdQEhLfWO1zXNANLk
+lqEhJSvBPZY4/FiOW4kNaZg2oRswz/+Bmp3amsK5TwBcI72rnH6SW5ADqPCcTP+h
+IrH4L9wnhOXw7QLk/h58JwiEc8suj5n0PJPQeHKajizd/EpUzVAuRTAl4GMvxLCY
+rALxeRaEXfJH5i/0UQydEvdU3ZP/LTibAqStXyVlSBZmKOg0GNQ+aAiHZyBnI3oq
+QuD0KuJi84ETMLU2baRydTbVlQDr8O0vxnCNlPkFFOqVpWyOyBgMctUfFJiM5c0l
+1UT6dc2F7NF5WOuoDCVw+Jp974CJuBSRGpdQKGms1Dvjwrtnf0ycstswXHvp2ZhV
+IVeCbT4WWh4f9bp6STkdquSc
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes256_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_cbc.pem
new file mode 100644
index 000000000..17289b2db
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,307CEE18F79CA333A38CA90E75B248C5
+
+qyg9Q1cX/FGOoP0NFzrCRLwmR6bai7JzDiCLFCthciYkMIWLIVzvyTg850YD3dw3
+Wusli8EQJig8DEpFSM0WBc1Rne8U4168nKuRnFUaP+VWuD4UpNDt66cT6dMoqATD
+kZGdd+p8ReO9TK9gO/ZZU4R+q3OUpjxX44szxj/EIVSgphi8R0rRSxl/yFRnGHyO
+xfpM9NxgMvBYlyxl5w1Lp/ictuF3D505nF/uuhzGL5a+WWhSnssMFHF9vxXTu21/
+3Cy0C3Qah9eV/C2oyAU7GGsXHIfqFqsgMjQN+cTFqMyFeg6g0J7hytDAgZVBXIFw
+UuzMbxUUZU9VHcZzwqstkg5BmUI3sgW6gibBUzuJrmo7uLrCvHyj9oehSMqeuPUC
+EXFqhw6Nb+jZMkvW9J9qFYG9eg3PQsDErIdVK8aWdLrLyc+O4gycOdMbR8aq/3Z4
+TlV7Ye650EvQ13bwZghZyKel6Rjt4P1MagGriNqCcLVVsyrRXAiqjq8cyJgYtoXF
+1VMBZz8ob2FH9+kvk2sb4+T22sTYwiqAVaLnCsuJ4dmS5wdBrhfF4oyHYV2KOVgG
+64GqxiF9/whvbAWSM4cU+KslKnWGZwz53LKleafrgeFJ2P1ldqnl0on5EQ/m9bzt
++GSGwzZGRmhf5NoyhaH+OCkq/h1UP+LZ5kDJCqH/l1JZbvJQkGNKzt1OroW17GnQ
+EgihXAmhy/xOAIZkz1XKa3bNvgS1F9yreAxJAvBHB0QzZ1HrablsaTKsZOtY1Qvq
+e2OdpJFm+SrI7RUtbp787Yl9pH2cLEdto+WH8gtgXloS+b11Q7broE42w9MIJrno
+kzs6eDWafSExTvpi+29OJEtK4PNezmhOxzTUIsG0/8d9Vd2WYqrLD34ze68X8qUa
+CoIXYP8VsQLoXVzX7VnMBYTQ+YOR0Ntq6pRj07RbJrNiOt8qcWGslzE17ERuCr0+
+ZFTGy77KOksKjLksvRj4oshQjRhVYZscPNnwKODFDvOPsGFjDoU2Sg+W8kcfE6Bc
+1RQwk4N0cjkC2JXXk61QQjh+efWRBqPN6va+ixUcsZSxndCIoBk4qtqtsyTFEcC7
+LdfCC96RGnXlvroiPHvrmJYN69JAyyRrnhiYfaaC98s=
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes256_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_cfb.pem
new file mode 100644
index 000000000..06718a55b
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CFB,337D3978222A1367F5CFE08611416E9C
+
+GVmy9WG3oR1Vpfxnfpv1hFvXGzBgE+c4jplSw2BAlKnbznCPbZLc3WF/ZMv2851O
+iE/8sdcetzoAlm3jGPoDi6Y/FqMFmcbqtro7vUz/SVgi1HDI0FXjOTPtFe6xfzhv
+84qt5lz5VAUueTKFXEZHqM9tV7lHt1FX86VutNObn8pE7nAWVX/Xvq+qWUsEx0ik
+YjZjLY696pyz61hnxZE4jKZLRx/9a6vWYaVfzsEi2FLw9qAsw6ILp+xDaAeKa+Il
+YVkgDPi62NPr7cRX1WCiw+/feNYPgUfGiBNkd2mOnAr1yOXFM+YALw5V+q8I6ZKN
+k8R7skAzRZkwTJ9WaaFGD/UypYmhe2b9Jp2n0BMEn5RpW4o1DTIHmfMSUmUPp5w3
+HjbtdDUWIiuplrz7mUE2sez/3bMbcoiO2Ym9SInJKBrMFSvyasg403u4QESYQhC2
+Lwcocb5ixXoczHjef3CogL6BhL2oZwXCl3OBqpMOJJJKXUPRhN8bvgV41UIsiGtN
+TFUXqYdpbmMkxJNMGiD3mKWpSm2MMdQYnRlxNh0wXLi5sHckD/WS4yFrNsCIMVDT
+W094liK/Z7BmplY4TyqKhsRlFVQ4VOo/W0WNh7Ayp0siIfo8vHDyoQsnUkn/EUER
+UZG1lIy6/y1RSg15GWpdi1bvT9URjElh/U944LSYD28K2VU8aPKaRBokk+K3AyR6
+YhZRCBr6uIVZ8HDkBL5OW0eP69/jdbyc4MnWRa6C0d0boA7N639j+NQz9erYT6wu
+RkInmBbVfxQD6HLkMwiuU23qLP+QQTLkH7rQJmnRPSwAKEE8RiXWi4/TnYW7d0AC
+Bj8oaK6DO+J9t1pdj0IGluf52iUwAOf2Pxwvu44ovaF+yb2n3P7S5maDGLTV/xBW
+D6nEAct9cYj22/aRDTLdpOfG0L242vjQLnjrgezBLraa9eTy29hR5FU5ACH5sB72
+rxUSwoCHCJuNFSxC27QwZqeCFw51epwXxLv1CjqsQi2So12qH+vFVtL/1YrFBct0
+dzwbdNk0S6UyPRqfiOE/+Iszzahmb/GgskPJdfT5Y03FnpDWfOotpaAebrY4t6kz
+/gs8pxupvdKw4eWsxVCL9KOP
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes256_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_ecb.pem
new file mode 100644
index 000000000..ab0f64d8e
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-ECB,267E98B92F05ECECABF28790E81DCFA0
+
+MkVFB5/gKxAksBI/g96MmN+ujdt0XFXC+7MI+0/OJ/H0LXlHlLpwfGlx/Je73Imt
+rOZveXf4I8sBCF1Z0Fhzb3TTTDxcastJGKWAVKaPzKkWdxNeUjx0kinbrkM7Spfa
+yG+wW+Srtfyi6LzEsbCduDK7hzfDnLbgKymdDeP0TVeJzEdXgXcV09a01GA+CEVX
+aHesQLNHyYm9nxFxK0fAnKo5r1I2JsozSWNTG3VNbiItxtfoJdXTn25I16qXjKzn
+MOn/A+RBpO+P01j4uk0q0SPJMlIYIX+RjgAoPiI5R5vSeucsdUJo1sWnSfqLc4yP
+vUG5wD/+lYrxsXiW61KdwIg3vy/ty5+GqwNgNvN0FZM8DvK+NQ9K/IpoW5RE4ioS
+ZNm1JpeGJiywsBf3Pi9mwR44tTVY0Jwa/TTQp1kEYGjhYXMIEvf+LUHwG5KO2wmD
+kDediMDUPaUx9K34eSpgIUln5d+1viMpC2VcDIg4tYjAODtGRxzgDUr3mbuoVl8f
+GqusTAdsNoIyilY44XxA2odHa4S8yXsx1f54P8fRYbA4Xo179LY1Nh7PwQPm+rI2
+mERkCsvns9jP1zJRuS1lYW1Dqjtxxq8Nt5RAsEwKQYLO4DfsuMZPblEXPAwSGb/N
+69xNs8ZFHm3KT1r7FdUrVpHk2vmqsetNa/g2wRTEuBmRCgrtTtEDWgdBNtDoHlBR
+pDIWgwNvt7oJIU0EbQkUgW8bmg1p7jxXN8Bk2QKZoOytxA4TB3fR1p92VkXzrkxn
+l+Z815BNfqnNCU5nNzLwk3jLgksZrDnLu4sXykIBC/bpP5fubnT7iJYh9h6ZGFeY
+QLUP//ssuZM2auNjTVykWUtAiglROzxnFZjMXEbujOKbm70Uj3YvAHjoKalkti9x
+MTj/vpR0xBv/iDtTFl12HIg+IEGL1PfX4xy2avvJO+XGFD4zcnrLfTMwtUJQjdQH
+dUMWP8VI266u+B6wGfcrhdCYqtvuLVUvbISU3YD/tP+esXh563kPnXd2UuaS3ErE
+/7Y/hzyUkDjJ2g37Hq3M4wbaEg/a6osDtfg73thDMadsbTLIDjHKgAgBv4umNtA8
++EaP0stzRH3ayHL/f4I5bHC8bMIAumKM6zap6tBiork=
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_aes256_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_ofb.pem
new file mode 100644
index 000000000..7192ffc10
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_aes256_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-OFB,A2D4D65382905DF6EEE7A315B10CF2D9
+
+CpLeywQMv8uZGrgJYM8rZ01awWHJWH/ZKkNi1rpQhaI1BAShQbIUvpY1IsMLa0/E
+g2+oj+Aa1UE4UDsAlzcfsKG9QHS8nOYWuLpU7VAyjC6wUPn0yI0sxxKRd4dmPIgW
+w3r0xO187yqLAjIZCj4y+3ANCjw+rLpZ5Zq8KAN4j6H1NEmzNoNVQbwY0hpsyxwE
+Tg7TkI5IyNKQSQC48EuZh16cJR48l36gzFOmZKr47gzS0zivvED4Vxdaey+WZkoF
+1XW4VbQGHRnLEn/I8rziic9E5pvvcZt6K2NwvzXrkS53ufFYZcgxNRxrdM4yLz+r
+20Unn2F2KqumB1RAliKo/PtudO7XfsPNc7rbF/stGhlxDWTyPU2HMX9tw3JkWDfG
+rRsG4RJOQgsx0Q73/7XPhgu1J2Wp39a/QI/IHwZ+rWIerdUPhs/MRRPoduAfSSZo
+r2z8OPJAlMWLwAjmmKDGhpTp/21n9xLo8tbvqmy8Frz+kAxAHXeHCTWUbxA+URKb
+s5NKQALX3wYHT9Xq0A27A/Zrqs5elqc/IQL58nU/Da3a3OfPB4+MNWeWU781ohhi
+VkBgMRbnQNCC8OPoeMd/At9GDEEj1rDxx49pJdMMwxXS04P43LiuNSmndCei2cQh
+/7cho8YTbdgjKF2kVCZvYXBVsu7Nn834kJw7eMH6slU+VM45jTkOTr2uLzKWrBL6
+YONiK2xdD9NlDcTsX4YRkt+dByJEcDAuvprVdnLKpFXAOWDLW6e0o0siuFIGBtgX
+NR5vA5llpOkladJk+j+dxX4u5Ql9KFPtD9uM05ik5VQCZN8pxy6On3GUeSdoAE9i
+i+rtgZofs39mZOTxhYr+Djnq3WiWntV91GImwhqiXxUBI/fs91+yy+FWphpGORaT
++Rab+cyvauBsdTAoSjjd5cNXXsztfDxEhLnZ1yWMQZxVgV7tcLevVo7e75pSZrN0
+/gMQAH1Fcxtbrdzg1fehLiqTEWp14lFyDCkqAqQ5C9niCqwyf8+6Axaukk4ImmP5
+n9eIykRezLizjA+GCe2oC1jXpVEEYVzOJpbBAwZqk/jlyNd0m01URxvhOaW1/M41
+uWDeQp7ljJrtiyMqD5P3STGR
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cbc.pem
new file mode 100644
index 000000000..8b71187c2
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CBC,B23E9DCDF6361CCB
+
+BTPCHNUVRgsKo1up9Ktshx00vDANb05S4S0LPU/wzG8sj60db3bX7Uzr0PPy7ShH
+1zPv0PECYla1dh9nVBPOS4EQE3uHyzuDMTg0AsiR8TpysuI+a4y8XJeAhkU1DTD6
+YzmaodjbCrhautYUCzvcui/sWWXTUSWH/yrFOxaaxLpccacCssGlPc3Tmr5brPmO
+xaZvO32ii6z7WAP/WmyRoYH+BSqmUBhObolifBD5kg1ilPfCk3xMtz4lbJRWANsS
+r6YWPwo+qh1TIQWw40Kz4oQOteVNiwh/dvYGxMkd9Gs4J9nY5deKYExoWlYcci6N
+VOrGA6HBWzfFx/QWWGK77xE8yQ8HeeZUgkWwYoSyAmxjPWgCj+BT5gbYV3W9E6UR
+T3lsKGtI/lMW9N0DVcLdur0lLIBFiVbzxoUAL1SteLJ0mbu/Vnk4VhI5z5mOmSxo
+bU/HElXdjIhk7hdTU5PMNSKiAsxNh03NiPsTpEASMhz+oP8BuJZh6Zi/K3qMYH3u
+6BYmA+Ua23fFYd/kz2TclVwiQ1HQjO3+9l0aSgLhHFb3t0spYbx1Ld5+bAb8b30Q
+9w/fNab1mB6hFgaqruPErfI0K8BZ845oAiakZBfKnTRQxAlKNY5gWvSiPDWlkfIb
+uSBW6csh62iQM1/bcW0voR21NGS+WdQ3eg16vv0HMhmEXmEvtAuCGb6ZMqY117s/
+VciBymZzwdLKFjCqrLn6enYrT7uneOoq/8PaXD1rdMuKGL4W2LqGH+Q0RU+1hyBJ
+7ipTQqystqi6HUU2R1/PI4K73X0MMTB0Jfkd81S6GmjkMYCFCHmHXCdNULjbjzT4
+gppgVW5joIbLKNPHJ78lw4BuMxcAgptmtQBADnWZQNF/pBnIVAY/pdHgreIBTQ7R
+KL1/ATp3+gtGd37FOGZilhq8C4ML+w18M0iTUUfGg5svUvmtw+NpNWMijTJpu3Uo
+KqjMj3NbwCwu2b9qxwalC3qWOgAJf4Z784+i2GOvACk2Mw2QyXoZV8Qm520M+idR
+rj6DIfzEf/86TWH9IrGukDbJNB74QHgdXd9upyt4sL6uHMxPwz4nnhBB7I8B/Q59
+oB+3CBpYIANihDscUbiNSsw5/AXNtMuA
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cfb.pem
new file mode 100644
index 000000000..8372cff2e
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CFB,A39496D20CA5F694
+
+A9ZO/WPm319cQ3hoxaEsmuGVDkMVhCuRzFfSWC4hVBsxKHd3FIw8xZpGSkEI7+aL
+cMtcyxTQn4jVV71Sw3vyb4N1+2i+DAd+63l8LztpTBQi1o2gTBqmqL9esV3shqWB
+JV7uyOi94olPea0Rf5PMRXx1bAZs9U0TV+5XHAQxM04lXRJajxiN9LBZ1OMRiUVu
+SdoHdXh077ylUQmgDaGQktWYuVH6leq7Yc9CF3nre6njFiUrpk61iPki7+/FgWzq
+vToqiYaWffy+1lB7sXcL88BtFaMWAOV5A48Mv05miTb00VbJqdKL+SDmu6j2Soxi
+Qk3k6Le0heXFHqqkURMKOrr6tepqKEjmy8WTELwMnuT5vNngMqDKpNyhdsIEJW69
++L0imi4fWIelCd7PMI1bbPAp2QsB8Rndjlfj3irVm0AtubL/rbep3JT0ezukoScd
+wLYNTlDdaLfEggry/1kYvPBMolU4xqDxg7C0quwYxLuycEFzU2QmWNtRn0xkfx+j
+ruApr4getT6q2fJznW7coiW+OE9Ik7JgtYUGEZuWFUeydDHa9PiJ34w9t/aw50Sk
+arATzKH66zM//g1zgzg31SmziKeE375skyQr2+1S9RajmdZzEUDL5ajsdrbALflf
+UPQNr0YEF92DRHsI4O39L/+k5fesiiU38u0NoKv5DDRb5T1lQeesDZCZBowQP5KP
++6o6lnj8kCeccpGX/eUukPXFl6mdddAJ/vLptHC1zaRp2dlKPRfedZkRm4Wduplh
+vQ+6oGqkjep0Q/LSRcVP69m91CZot86lAn9Ct0jfJu8o7Ua7KBeOB2k/rx1nUaZG
+BOjHQRaSvPA7FVKCP1UlT0GR2hTb/VcW3UQJ7fCY8E4hc1kPfoa/T+mf0JrHtlMm
+364YQh6KLgcsgVjsPBXnTN1+POH0Qy0xp/0VwQIQFWKwU7gsXprfs/uYx0uD2Ev1
+w9kIWLovIGmBh6HKptqTnjtdwhqueez5kb3MkrCMi3kqVmV1TEQoklz6eBbloXbX
+SyR5jivLmuaoCJOA3oQ/A+75bwcvUP4iULZbdTpM2rnURyljKNU9Hwxim0neZ0Zv
+4kiOZuhQKkGfj0gv5bRkDAZC
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ecb.pem
new file mode 100644
index 000000000..58acd6f7d
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-ECB,6105920EB281329C
+
+ungL+71R1VG+DP1CKuROEP1pESqlLeGoX/vupWbGTWR9VoK4v/9e1Bh96r+hEobm
+LvgsV1xhWrnyRMMw+W5bSJCfBH627SxqHltgxPhyKCNAf76cTIAdxxXgLZAxjtJi
+mjuBDTNHdJ8NiAxJKLL6dr/hh+Vt1Lk9Gr/x7UdocQnhxG+IZLDSOFdXnFb8EBtK
+kmAXXyOL14Rerywi6pmbxaculi/CihuFm4u6GXvunFjtP33eObzKLRub5ktbCtol
+97rbDoAAUsPPm4efu6Fs/3CE/BfvjUf+cmOYu6pIKQil9VHtxXloXwkeykI9Kl92
+uZVT+e9WEn6oZslAzCnjT/r69+V0Bf06AP0zkdTK7lRNBhmcR9fAgHpxz52GC2Bt
+xsqEzU7d+adCy1M73tT+bA2RBUnbA6BoCDHkvtmZTGV4mkAv11tVxU9Zqeglvi/w
+6QVDQYo/b9U8GVkQFo0oh4xNaAUNdT/i1OIy7d+6UR8k1S9+r6SGVwS3er20trWN
+8mAJ3dWiy3yLreggSqEvwHSpwrUQP8uxdTZOlFAy+xmwuEb3AgT4/sHQN7sJjAN9
+ISdzp+B5tBbM3kQgvEXUZckVykM7jgyv7SJ9DoDaYXvlfOVFo1oM3aWf57DcB8KH
+WIV94r4USVElJERYHH9sR61YtTi2lIi1zuAQZKCf3ShJcgU+vh2ZZ3vRPQhAMXjZ
+0Doi5uxi7HK/MVenO1CzNmsc6XQtyTtONqlJVmBoSq3Il8phMkMXnaOeNrQsT/1X
+PzbQ6MpWEr2WkKsQn5hNA9b8BIZ+cwk9zeFbhwLH5ewjO25BWJkFra4gGFJl+HZf
+vMNFjlnxuMjqM+Fjn3YH/O08P3nF/3ZGezqTCV8OJigB4Cdfbf9OrNtJSvCVsH1q
+YB/3+KOO5mKObH0Y+k1pvwZsXMkj7exAEHh+nFLldjo7tBAycqUHK0RaZ29TOjqH
+J6/4SSzMTJL5PF9Ayjtx0Vai4sFrjRGgnvdd8tddA/bWq6JC5i0yWIWjCEu0+b1q
+q8EHdE39+gbANJn2lKsEAOOt242bsjKR+bblijaaEgZXHZyALOThcEXxn1RaFFgC
+4Iv+DftZrU8lOiEvN8w00K6GDy9gbByG
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ofb.pem
new file mode 100644
index 000000000..2558ae409
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_blowfish_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-OFB,56A8F965C6533468
+
+91TyUkVkBxdl1ZXkXezMngH3YsE2cuXhiEFySx+dWZqFWcOQ3S6izXXqvk9B5sZg
+O95SFlZ917dU+SFACzB8dqwYo0QmxvH0zaAIMBguuYib6YZVCd8/ElX0vyEEo68O
+9V856HAks6w5WZk4zTC/75skb3tdLRWgG42oBlXHW7GsL6y29Dy3xvaWHJ3vpKXF
+HygbvR/TiSzhWj/jJB6V4kCQAAm99yyMxpmo3e4Wis5AwGgf9XyHJx0gUCeyNqez
+i6UJMGnYsHl1H67ltpN13trIXRcXTUDhFTadRz/suaR1R8IEefkpsnBEPnJwBuPY
+tUQzlolPKuwbPXFukpJrhi7It7dLsDsw5DUYvyOnHkDXJ4vFAIplCKdG0+KLaYKJ
+pXI8FH6X4M1YbIPTF+k1dhCAz7Cz+cEBA5hfJfSA4p7L6f9NBPWso3DDsyAbdPx9
+JJkVPtu0ofZHzYuD9nIhRsXjK9zaQXU0szLBdtGw7rfmPp3ftXeBcXDnO2ZdXL+j
+PK6CJm0ktjnUMKY8gpWahUUfImwebQ8+uQYv+NNn61rtfCaGQWMStXaNYgq54YLs
+D5ImRdvWm936tNUCeoik0yhPVlriNC4gKswRSUxD/nNIetsPl4FB4DIS/W5fvWZf
+WYKwW1UlpC/HagbUVIuZcOrAMFTG+zLYS617lzZh7Y7K87GJH+jVwgbYSbHHFWCp
+V215NLfofwlV5pFwq8djbeEnBhKi9SbGlZUyaZKKyDoIIEnwaxg8BoModBEWHyWp
+OUmw/v81TQu6RwJYxl1C1U9n5w4yjtXr5oowgu6WRYXwWXZtevtLkHrhcuWt21ud
+Cq42ojFrb0GqIcYWDXF3Wjp4nLZ4pIqg5kadpJpcFYx+fcL++Jnxs9l8Ohqwn1br
+/UvY+gTmTwnICapIwovVjN6p6cT6MAok82oemWPZNPYXVwVkGewCH3DWqfeRYsdg
+6gDWeIwyk2Eqn4bxFz40NrNZaLqcmQPaJVRReCV7Y0jQuQWqSYKkBHgFodf2GPMg
+DRqs7doN2MW7Is6qjyc8CDDzPcSuaqUz0gzohupDfD1vAtuoC0X6U+m/8NM3yuE5
+CKE8rofcKcxmFAr52CUUsJBL
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des1_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des1_cbc.pem
new file mode 100644
index 000000000..f6fb1c9bf
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des1_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,7D7F5AED62DF7398
+
+PvrGaVyP4qWxH3LR5bOjrjTZN9KEZ7eujPyBYWV8pE7+kBc01RKaHuOfntMncXPj
+cTvtvPq4z/Odrme5s5fem88QAoxB2BqM0VNviUMcCcAG+hgsYjYWjUDdSY+piAD5
+dhPcTHfSwgkA16c9pd+vNojdDKHEXzIci/gdrkJQXi9z+Orfb++NluGFUjAvQNlh
+n+wi72AVwFaSPfguwAtWAZNmL37dZO8VzuCTkhciHaJSZFtS1G5rLBIo4JzW6AZI
+PLEENN8fE9C60WYkfQB0PI27ksTS2xPF2b7MeaBwdPRU++hwZ2QwXH7nYlCWn522
+8wg3/QWuFIMdqtKaOjjlwvQxApV7OouRCxIFnolM8HvpZ7HvEVVT6oqcsJG339FJ
+Ru60QxuVsnz6ykuP2OoGTtGZNYo5cgBSpXrpUSmOp8HHblWa6+FSatNkBf5MxJvv
+pMRxcYJ7ftFCGgpKI38GgeBPkpv9Rr8PUplZlgnXkZl8trhjb0hzAAJrMqPkMQ2m
+rOgsIWF+gK6MdnZdSnY1DktPYSFCkfJt0BZMGBDXcbr8RKHeV1vJNWAPOcmTsV/y
+nwzv9EA1KHeMnT+wQ54q7jkRtDLIS+zSWt3qW0fJQzNR3BrMBrsij6GfRZ++PL3v
+4y9D+cDFVX6LMXUDLK8kxZ11A5rSuL4HROtNnIQf/MItKNK4Y5c4PAKAMGLQpPS+
+5dgmKiu6jAIKUVT4BOEjMJ0P03JZKQkPxVB9GgLQLGCq77vz6NaTWhJmz+qTdZoL
+JCvAAShdkVa5gl4hzuvKnmY9VftsPVlOUthuO4NYimnjZs6p0sXZKnxQ4J4BpbkX
+mX5Fs6RU0YTQphu2v+NFhcPpYwRiwn15CVUDW61Sb87HZ5xAzwQrlpFY0LI4TqE9
+6ITUYzgpVVAlslKHNePMcjTj78V2MImHlq7xHSVPEGkkPlsDWxG0snZRkmM9aAu2
+g8kqf8MVngWbWhxqXHA35wunnaBhpBxAgqE4r2yAhyfCJNF3B01zwjt4LeTnduj7
+1ZA6EPechsSQUGQNGBoSbO5zVbIQaRZvAl2MwPU1YWCCbjaiDDRp9bHhX8vQbI/v
+4TRfKX8FUSai83qORQ+Ncshg+gYkeCJc
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des1_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des1_cfb.pem
new file mode 100644
index 000000000..c3af8d5e6
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des1_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CFB,6215481F0FAE54A9
+
+4ZA2xcGT6hS0kQObPwTWmluIl2wTnoL2jRMbxrr7usOZSLYISprcATZWieEKLsu0
+kNNzIptFCmRDt0b8VlothTS2jBIh5nlu9LqvaUlIrVuMEn7umslWrLK8JWnHVKOO
+dMfqNcgmYlkbEfmmXLtlCbfQHT2kVlopD58yxf26FTQ+27l+hSX4wn2uD+xFUAcn
++9ZxAWQDhi2PYVKqTTPfhCPaKW7hjYdocADnIZg+1mhH++8fPxlDmBQBmMOid53Q
+WV9LI4Fps90d7GumX7qSUFZTkBKN3v+E2ahnoP2bTBQGkqWamKFTc/4uLCEGlSWU
+qXaGCy1AwPa9As1+B/jLkTstoslJppqvOooWW2R1o7JHqN44luXXQPZ+BcA7dSdf
+zRcMCpudB0AwHBy3mnUNuBlUjsf4rEpq51HPSS8duYow2I127uI8m8OCoZCaUVid
+msxVMSJIiDCiBi18EfCjMfGLtQVxJefMv2hmcAXQXSRDJTEw8Lrtm0Mtp7XK2B0A
+v8Kqpf3x+VBc770Xoy0K1/fe5oLdvJrJOLO5PVcVXIS9B/DTqIQ8ObABJPZ1sCKA
+sV8XebteS8fNXmFrVKBTmHBpUY8H5Z++VfDtKZZUBYSOqbFT+UU/+xJKlKICzFTo
+YWsmPTgFsu0Z7/PMyg/rccrb9fMWRXa8et0JGoF2NlYu+lkRb/nYPe84oS8RzZT1
+dtWJMiiom4xRgENDhV6/AmA9IuyXT3QbDfFB+ntdyk94U+Ms0ODNcdA4JmEa/f2k
+zFjtEGWHPH8Quit+zUt+8JnWSSFp0mjyA2ZtEj/6Qg5rqAZMdlpTo7rcuYOTHScn
+ic/H7V43SuMlRAM+xx1bGrNzjWUugHrVb7Kar56pSRPtSOQ00Dmz7gB8V5LU63n1
+YX3faatiPUNRG1dArcW36o9dZ5x8O5TErPHRJNYG+96UNoAzHMXoi5thuRyVbzne
+FpOqgxsryobcht7fwHuYgUq92QoY2qG6qMwHc2A3NrVFi8lJ0R83SN0lOzLebulu
++zDvrvkkRyH14uoAWi/o5IGBv1yIkO9vYApntrSO2aLnbevht9MuDJqW/Lkb579Y
+LG/sVwxTmBT6jdCgTdpd1ExE
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des1_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des1_ecb.pem
new file mode 100644
index 000000000..d17a90f37
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des1_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-ECB,1040C4105685E404
+
+66Uasevd2pON2SFWljlVyWqmErfZn4XomzLHlUoagIwnQUEgCBCCpUscES98fini
+roGF/iaY59JnUCMieugke7/GZF1C0aXbIReqds7S6VFfu4Ni1OQTkL4rIauHrWab
+vgoE4+18OlWw6Rc0wwJ8NT/NCOmb397yTeb0w8VYERyzpwSLXxQ0BCOq4vOUX7BT
+2ABX0moazjUSyTO9BQZpABF2SshxaWFbAc3QRwH4QnO1bm7Pv7b1rvjrvPZ9LxgN
+fwjXG+yfHFBBojbEtFvgXRsSSyV5WCmAgYLgk5/nIDFSnRQGty0OuP+itX7SUK1I
+PH/ZjdIwezMKbyuon9D1AvdOEC1xiKEdmJCWSokm0djIVNmYbv4dtfrQE6hYdMtt
+C0LbsT7ef+jl0xG3k+WK24OsBVhTaqj8axIPZIVLELOPlx4EMfaFQgUjgqf5vPhO
+x6RSSRy+poFwtjI6ip/xu7ygqmcY9COXCcSffk1vpw9v+6WcMaYmDLwBTrTCNsdI
+7i6VJa1GiCrsn5o6ydGgdRNkF0N0sUfGnSzRUgd3BGd/fvxhBmcxHUnr8srrHYm7
+D54VL0EUsP33F1VF2ELl94GlWqfAj8NGBDkTbpUcqOeL/ERxdUWfX5IEc3h7fprs
+UjjjQ+d3GRliRs27m4ZuLtGeDEhDtlTC6qtKyqgVziPMwG46tcqyFzhbLCErHNW1
+07JcoDRc1LkXImSeWgjjhskUX8nc2/q5giTVtGmiWMQwEc7aYQ1wPbVAIGPQ4PE2
+XB8zvvPEaj0wXs0JjicrfzUBo6cRbdfmWIfp+ZoTUfr+gS/aZm+VYt1G7v6u7Qel
+AtoSdpN623OvqIP5ZDjOKROmAdMbXkxwwusVNQhkbdTzDYNy/yJnJqUUlhsN0VTQ
+y+O8Fz7Q7fEYIk8Euz3Uf/BTVGbLSNSA9n++CJYg1nam1S51WhCXRDckDLR0c4C8
+v3zpJvaQYW+xZUmlzrYRQgxkfzv4+j9W+kZLgvitQizXfTsuDyO8gwIt2csfGkaL
+EgX2+oITD/sGoaSoGknY42ePI3pPXHlhBjPq6ZWZ7uh6Ia90nV1j/PAcOEoAspAh
+pEdIAkFJA76qN9JBnK7lRMFXu/EWtBjD
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des1_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des1_ofb.pem
new file mode 100644
index 000000000..2d36cbfd8
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des1_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-OFB,BB20E846FFFBD3EF
+
+WeRgcZKkDTSxqvtZvx9WwUZYqXUUpY7siLG1Vm5jXPaEFOEQhmvGuNYn2cwwUYKD
+RMN5+sE51urDgI/xk6jdS9oZE6IlfkGeQSUoEOOfPVyVD/0/E2G0QTcKAAWB56K3
+setBb2ORbM2ZhetYUp1scaLObMEMQ5LrZaqtA/jUd2Pbs9D2MqafEH0Gde8e7mXy
+1fGNJWlj8XtAdmi2BeDKZHx5Hu0r/BOTic++L0Sv66wbjHw7RDji9Rdv/vyq6DIi
+0v0ZCexiNVed4mqD/3+8eGQ2z02UD7aZPy6T7E+b8kBuBi2ouB4HqgexVtz1L9x8
+VBBOBdpOLefwCZlNaeceg2kSIP9mMK919hlH472BO615YB4ugaCilUNLpvv9T85K
+s4hTB5oDcQH6W68mz44vWqSwED8JcdMYvivWY+3/zBSUvkyI8+8AErnVr8tvTX29
+aBhfegKV0MbRRRirj/EcxhUhtfgbAtllZ/Wpo0LWpIsHT0GeUfWdUerbFyh/8Tfr
+OQzC14xoLHdACDz5IDrLaLd87hZrKDJOELvzoSugg2W9NAzGbfoWJGVlvZ0miZcO
+teULyYcK/A7Wcba+jmFaXMrKVhNH0IuGcU+Pf1lYcchjAsdnrFMVRsNJ99QWlN0F
++dTyRgaiCInnmJqT83fI58dMmaJPpMeW26jItPWZWAA0vlQB1RgZ8C7i7V4keuVc
+0PYolX8WpLrrpUpJKOTdW6rmeHokJC46gOZoXEwZCSKUUgreROLgRN79RMBHKjoj
+0vSZWowgH82fNWYWQbJk5z4ldulWEVye3tQhRNsZarAWPFEteiKDTSkawmBpaA6q
+dJWiA+EdrVvnNmw5+xkbciMX0nj4xKsjRgPawdMFZaZNE3xu2LkrfGKDa1ne3JdL
+nDeyygGRDsl93oJ799maHaTLDyub0CMdyf2MssPLFklJdxwbtxNzbI0gt0NhZu43
+FDg91Z3hlAjg/Q2h1dVM22m3pnju2ygF11HUQdNExHlv5w8LWMeqWQ5j7WhSbM4c
+s2v5JURZ+jXFEf3jCs9h6pLlQNaipDkUQA/6DKHf0VbZJzKxBiRCwSP/YuQ6H3yP
+dHGRAd5CQnNc3Vv+yyRqQT56
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des2_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des2_cbc.pem
new file mode 100644
index 000000000..98d36821a
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des2_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CBC,89A720DEE88FA71E
+
+ozUacsBZx7E1NCxbVYJJHQ0VTWl8RX0z/JzYNP58zcCIi3Cab2qlUshZP+Zb0Na9
+vlHabEqQCGsP8uLzneN6LDDaLmf+ucxKvCRrx5h8wl7DQcA5cAQhGofZuqChPqLj
+1lExS4ZaAi9lRL6aZhf6rgI/apkj+9Ky89sOqJxNhj66NgoOOh9XH1Uvrffv3jT9
+RxeVv5qYcAgfX4aIAM6KjC6iTZ8NyWmIoc8izYQycOsSAn6cqtdjmyc/264OZUd/
+1Tj5PG0q/Kinh9UBJ2F+pQgU4pDlWczXEIwtnmJ2mWyHBe2zuGWtP1uQFUIfwkEz
+KDTTFB0lm/00Xts+vGXgy2q+IvhqlOXfCkJGcP+OArLoyE8cu2xU4KS4qXUITSr0
+i3seUuTrda4aqrfyjNuM0tL/cUSEuT7aSlKdqSmRtYl9fTsmbCbndLKKuDJnxUrB
+ocXfuCEZNMQ/q/8DvwIX3l7RRIiJwqEg5+Ue/s2FTFJh4Iar/1gNQSApwToFHHhV
+XOU0pLY899B+1z10Nop7ELgJEKBK5+zMMBhB2t6nlMU3YojAH5qWEPa6D2Wr0Wu7
+x4DHqk0wEB6cDZ0PZGlWNOBP5bDB85GehAWKy73A73wYZCi9eCQnLh1Zjcjl+6T4
+fli2K+944sUKaUnY8sVT/20aXm1CRqNvgLknZMsg/eGZWX5F9+Jn/MviXmsH3LfE
+6VShEkNTFEsRUqF44Tvd2BZ6pObDPRDOkMgapzqdubujUesvb7LU3yNCRPBPngRT
+ZTXQynnbH0yfnFm6+0BYWtD5NeIzILwZfS6IRMSsCBMas5rCc7O2Iv0yhk/8K0f1
+Og1YH7pctbz1oAPmN/EgKZ1K36GTt33zfrwHpmKZ0jOWF90BQMgZ9dL+VyOMJYjL
+MiyetxwDdiP5TUUAKxXdr9t3AvxVPxL8aVjLb86kJ9HD+IgWUDqiROe88sD30Vww
+7R3sQhhl7drDGwUBj5MLCVhtE8Uli7HdaYC5CvuvlCAQN871whhk2gN27eqp81ou
+RB4kNaDK8qSn83ISnueg1jsQhUGy6B2Rx+rePxx3QwDsrMGf/u/tFJ1VcLlhmOJa
+svVKTMq88OAnZA1Hg6QlB03obSF9U6lJ
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des2_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des2_cfb.pem
new file mode 100644
index 000000000..edd5d8b3a
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des2_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CFB,AC1BA482ADC9EB3E
+
+tPu6t71kZlKyKaRiXgAMCmyxL/P6dVH/sPVY3KDFI0FsAGoPZaD8s7BkLLOy30Y1
+66kmaaWiaPjQN2g5zMrszrXh4AXazrjMrmIJ2NksNXz7aiySFafyYjyCPA+LIu/n
+KnfoE42KYEmENgMSUV9sh/nlwYS8I6LWva384BIWaG3qnFgfZ4gwgiI/R+1/lPXa
+olOpnI5szYMiV+som2E+I8lgd+Ahf2rempMnuwyWTDmUvYWwst7F5bz9XbmJyeWY
+HDDaTPy2Q1yRYBRvLTm64iA0J9j1TpJnSNm0uIRTVOEIZfOwOx20tFjo7RREunAx
+mEm+kmn4AIYhw5RQE5XQQvD42X4MLyc0M94k5pQHvgJFypXeJ4VsH8pkd4bqfy91
+qiPiKdA7nWnbedExwiwSPOhjOLkmQrXjsMVmoqqexhckJfmNOaXYtnQ8cZc50HjB
+6ccsjyLdQbLx1KT3e/NgfH4VxW4/hbbt3p0HMIxTnwt2lNG3AoKmLlOYSecuA4PB
+EE6oOauIKyJM8pwMV0hfBQ/MUQOnhHG+dbTn0kW91fRZiVPPvJiJ4NmEwD3ks3jM
+pLYZRot1Cd2ksJ79G4NXDFakB2bZ8EwtlQUrQHwW/ykPwiwpqCCha1PUzgsmG3hK
+U8bDWWQMqXtpSmItno1mF0H2TZzdbLpRAZe2lu8/mwww1qZfPE+MLPnCp050+BCw
+Hbq8fF1WVpJvsE5CKzi7Ll7bSrJ6BslrlzL4mFnnGmuz/mbBIL0MO24FNyVGKQlI
+hEzGu8lgp53pG4oSUZ+79CWBkn8mesk6iEOWcFojLKrlhnxZ7mDxBYfDp/2Bmna4
+lFt53zmQHJeYiO4J2TEXOQxvDWvcOK/SnAoLXEhUCRP9vTQm2Ahj1QMmEVvEybOd
+mRpcaJXUOgirS7Ulwc6ZhW7MoFFnS3UluI+gS0oXRW6hCm6l9poDem4etU+IsG2m
+4k6MoMLrak9lSheB1uL+xC0S9k20CZH0X8Hj5atb4R7T5+lTle/fVw1RGdfil1NK
+/ytD+CLpSV15Z6VGVGlzfXTIXYgCIgbZpFxOZk2tsdUm0dPBjR/ZhdUh4ofaxA8K
+jE8HLuW7kCkvmEfdsJxuRVVQ
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des2_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des2_ecb.pem
new file mode 100644
index 000000000..35c220f7b
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des2_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE,3D3D716B17DFBD33
+
+XDCVsv17xsOpLWONR8xKRYxnxvWs+bdU+2XCqoqH+cM/vR4+g4lqSPSAco0/LkyX
+q0/C7/BE7mN6fzUMiECYUKS2c739CBVwDJZJBVGbMNFexaQRmlSxqhmbQ60oalaG
+HZfpCLLHQvrOZ3O82aYuEfsbqJTEPkGm4lUn/5psQwudmu4qyv8GFR4wVpNcg9JB
+rDzesxi1aU6dgHSlLHrG5ot+lAITh40SCBQdwkcvixyDIi6l4FX2AyNrcQYmFGp1
+C3XaOn74ADLyo31Iy6rCb0KId6J+S+1aPUW2r1Xb6irI13/QYzIe8/fDfuyV7Ofq
+BKtHdu/oIfzl2X8BkuxJ0CEFxyyEE9majfItPnUEjX0Sn2PfOEwzq5LYYExpNuxe
+pHr9gtB+hSXC5t1b6ifv9PHErMNmBLdgLX/FT4PuL6URrn3LtydPcfW6XMkHtGgH
+zD/nnn8Kl1qXmkRbWHbREcOJB/O/Q53UwD26BsX+Sjwn2cfsgwQvZFzvmq/RwsCg
+Ej9FK80Tvn3ce+Kdt7LGUc9+KaH1OIn7qLcYu0Fhid/TzPCBPQffxpUJ1HylDaUz
+v1txJe3C//rg/42e5GUlKqf+/nzCmQeoaqZDG+VU3UKlngIYitlpwEq5fq/E8V35
+JeuHzFjYj0k9VNsOHY/4AqmEm9qi1yxb7WGINsysO+29RvfRD1bm2Zqhi/Mg7YBo
+8K1GowhW6uGFf+VCPORihMIxoT6xBU4xn2kX09EKrVdekrAi23QzslZXM6Ze0fxH
+7LlktJwah4/QFHwB5qXwmHq3lN4Nj1id+CElVZXjvbKvc4+mRd7VSn++05IFjTK5
+2r4FHifwpkGASJtVbF/7ZseaoOz9sHARx/MFSUp8kRZjOCzstWj6I0Fou51BTtRn
+1ZCey4e1eKVnV4F1XNdo27Aw9aZjF4Zn5hZfUPuUYBwN3W33l8FXRdYEoT/JpiQO
+8LS36SSZGVA0c6nanZoeDZsrPNtPJa8ANHR0QMwBDOwNr22uuJEG/nLvBfquG4HL
+Iy7nxBebe/0MXvsxK4OjjDzmYQL2msMlYffOABOVLCbtaPC/HBKUcmcpZ28WAzdN
+ArkPEcJFTgzI+hCAVG//uV59MkDnUZ+e
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des2_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des2_ofb.pem
new file mode 100644
index 000000000..d06c31f16
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des2_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-OFB,0472499818A0CFA5
+
+A+t7NfS0c6IsREc9+AzXRaMGW5GR2Ao+WBBxXdxNJZ2n6DWTcNHYL1VZsnVOoc9z
+N2PBfTjYQkNtehp4LDnypbooUI8gJ98T33PLkJ0/L03fs5iEiULcrpBLGc9gsNoO
++f0JcI4xNfE7bGvtveliBWBsn6KeCdwrdcOXziWGQCge0pftf7m4HZ/t/0ISfjXK
+x3ftgiwrvLSnCHfp50xXdN4FGRaIj/V+C50efu/hkAaZ4rCcTxgEcvi+TKdDjmcy
+MfxWmUmeGiT0MRongCZB7XH6g4sI3nwiDASLzvZ2dBysLD0wOhR+g8yumSH2RW5V
+rTr7JQANZzdZm4MpOv2fMCHzDcKEtPd+OlYMHegwE3p0y4CLeYByT4IdyKHVLiWx
+lwAKtZ15VlREgXqBIgrtG5ooEIIjdlabIckAhRc5yOX9sXsMePRyPgQSnG+nSbQ7
+6Y1l+3XueWXjsnr6SIXI5wbszM+TFbZAU6d9tb7B63R8ancHHSUgAbmSL7QpYZxD
+oNYseUzgPv62oMbX9VxiWJ5ZgwzS+D0zGALw3Tb/YVTxI+/VZ58ITZ59I1cg26HT
+H3P1thNPIee0zz3zewMdILgQLh5RWkJhn8/oawDhVVPBba72uw2nGF2aXwbLWx7G
+eJ94GeikGHOJby/J4G+0D2lLlI90jP8KB2fVqHxENGKSMLjZFERGvpiPTgHxWcgI
+SS3ORTxuJDzqG3qFfMhFwQnq6tbOsny27scEQZeNMGecfqGLWE+oclqfKKDQDm11
+JUQnsnFAT3cNFyd2bKefeN9co9NS1UTUw1m3gDH29kwmggFLwSccTFobrIoh5/le
+qiaHdEdmd1Fvp2nMAVufwmb6G1dizT37benyr5Gzc8CHZUMibFEIhjkmG8RQ4dyb
+Byai6j2gf6rzsbKiVtKqgCgMCw5LG8xypzitCBc0+DsYBnlAyS4hXYm41eqMtMsF
+vrP5uS50iDbAMBjuIpWdlRewjxEqiLPZofjbMGwbrvDu45LQ76rwLww5OUj6567b
+FJRcXQdyt/bWqB47GnAZq8NABCtY9HG77nTgqstOqYOOsdkuZC33JHAwTwa+b8tq
+2Y7Zo35CmITqLxfjr2IT5Yeu
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des3_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des3_cbc.pem
new file mode 100644
index 000000000..f73edf131
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des3_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,9BF24F7ACA100D50
+
+71AQTQlq7BkcUMR0+Ghc8O2ykT347aaFUD9BYHXBW7SzEq4th3itEQQ4QxflbgR0
+2XZQE+dNK+s891XnEkf+8ZIIQc4LKr4m3P1t8UeAQvMbHRfAQ1u2/fMf5xwYMqsW
+BscjoQ0lFOcb69nb24E4taRu+MRDF2+eah2hlbHGbsTezIm1VzFRX2C4mnWyfffX
+2WyJQPlZpvOY4kkv8tRvW+nbZ0P7bRjjxrSbCeUVI8X3m0fiCJ0fMVg1MMaj8JxD
+AgIKBBIJV8SYRw3NqiGk/mIlMq4Qtl8PWEFBRf30DRD8RIqOO0yV9Czu/u1hcmxN
+x1/ZExbwOFAFwE/GU+NMegFRXC4toNIU2Xo1C84URpAvVAwwe6SiqWFTSTEHnRu2
+N/tfJlaL2yFrfRnp6mcNN3T8Rk376skXk1zml8Deh6rNU254yK2CFRgm+79W+CeR
+Gb1wxDw0GQ07Zr6/hNBfpAND4qEdyxYAfJQYOCufXiFFxWp+99TGKN4T/+Ab5D2j
+zKmpYFPJj2vuULLPGIJPnCVNjM5v2KwbFY/95Jh3JEF255TORfj2P6HETcjZr0pD
+TCk13jxgKs3mq98Vr5LGEJ4nUcm4GoZayIbeaM7heJTWmvQyP6PRZIDWi5mHs7K2
+wGUrutGZcxzLtaQkavQPf79xt+0CI9D8Nuz4FrKMS2ng+rWLzT3be46f6hJaX1KP
+cy8RLQfaWpFGBPHr8UKhicOpdbGjxxfBUM7Jlg2o1hQIWmSuj53SygZ/EQnqBV7E
+GG+Gf3RDl1Ab9ncOr2WAA5TOQ/yVBEYXy2W3TDmxuwf/fWvwF2z4DLq/J7pieEM1
+b1IuOlcDWNu6eKAhsrq0t6I/wYNB/7qOmIcMxn1dzDHjic3uO65IMH2swXmk7tuZ
+ExdHGutPDZKYG3TgMyMYk3W9YeoEZAjF3TodOYNpmtaDmftjIuxlaYzmtkQCFHGh
+cRlnPXJwaExSYrySX+1zsuqU2QaLB0AyTlAgkUdiLQOzfmHtiHt4Pgyv/o1z/PgJ
+VTVyu2IFh75H6CnSQGgNHIH6QGN3mcMIZQ5G0U2r46X+7+nnodOky09H2Gq71nQf
+vSk1M2ZoaOuo437zG8SlEuPKimz/d+PH
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des3_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des3_cfb.pem
new file mode 100644
index 000000000..eb957ba43
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des3_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CFB,DDDE26F919588654
+
+ulZ1WOcK/yY3ugpb4uN9s8ejFImurz+p4en3zaCfEMdv93V0JT2T/49e+OvIMaOz
+4ShAD3AO5zOXkZd5AUDI5Oi7mMIH2sUmhiJ+0xZMWITbAduYvt69lCGFchpQ/YRD
+G4jT1PY4WQX9o7nN1EYyPnH/vx4Rk6lnOZz7UNpK51SBSBk9lkF/d3bH3J2+pYaN
+G8VET28OIVTs4nqNdu8nxoE8u/Y3aW3FVsFCA/ZhmBD81Odb4rHAHCqJl00ApW91
+nvpTkTjfF9+EfdOE3mfLA4R7CEVWaqnfzvNrVCOILs3qSFGKbIBPBBBJbc4d4pEm
+G+8g5gimV+oL/Q6njSi8s8yV1WWf/nqK6EKd2JJglW700V8dbGHjhGChNTM4Px+C
+RfTF+kXcQZpcsax5ULUz+4KKD2Ub5EcWumg+LAe36VVTz/zDTxhTzsm0/iN68KTM
+jzKjIY9PkVIhZikVkp4s8pL97rL9Tota4OGMacPx3C58MSwJSg7fdUehAcnj+GC6
+Nfi+iHxVpJP4QnFi4BotFxlb2FoVhoh51YdaUehqD0IsoBxrQCmT8nVaz9asJMCY
+CRXNO/2pUpNJY0iGjHfvdmT/aRf+gmat41bX/1r6Xxujf09JF1iS5v/fpYQsshZc
+N+xysjZ8Bps2Kx57XSUTz3NrwMuliJgw6ZbDYBHGSSl2lueUanNArE4iLakuf5BK
+zuf7iVNTZEww904RhnA3HnivRH2b+Q1mWxTezSYZTs2Qr62mJ5ewiFjOlv6hPUfx
+T8/ka54Am8dHsgc3LUDK4pFFR0Nk82yU52FJPbGsggKZAde2tUnDgup6gNmzEjA7
+rSWxEfg53fHda79SQzrKaPGsuWr5b+cl20rGycqN54qZafKFah2tfCzgGdVZG+Yn
+Wq5wvZK7Elmjz+URvKitFhw39yscj4TLlEQ3K/jZVu5/lsyyu3imiUholwMCSuhV
+fg667XbT1qSw8KPWoloOSDQr60d2cK8Olg9DjfMgqmDxVHMuALB+O/dhJq4Jaa9c
+e6ycERign27Fv6j09/aAGrsaB9gMXCOmMhYGSoBUptjb2dx8mN/z3fEG9ykvaDiq
+i1+9GnfRKIYzfxTa3PCpA0B+
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des3_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des3_ecb.pem
new file mode 100644
index 000000000..1dc818296
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des3_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3,695F5DA31042DDE2
+
+dzOyRB2M6CfzgilwOWNhrea/0Zt1EmJSCDPXO7kQz0LpP3/keHgFL14NqxQU6puh
+gYn8TKE+H2f+l8xoNhT6kdRI5OZP85NlC/RvzcIPJkriBgMeLwsRCvhxg0EujRa8
+popm8yF2E8N9YPdz2CcrUW0mttVYeSy2YO/pi5rTJBeqqIjqFYjHPEmlnoNqboQk
+aflRKFw/rZgsE4gzoMKR/yso/GmSIXj48h9G9CyLWPFIDi8LdiiBG62wxK1TDFDI
+FIcU4KY8QyHSYc3DdYJJM2kXxvSy5BxbvWkD9cZS9+CuAvDyGI9dfF6g60f2tCA2
+AxIHRn78StCNbRN1xBfkqw0BremGo8G3H8w6FrdeS1rKzzYqAe3XhDO/uN/0aRAz
+Yact4CIYbZgMRhTJh6YhWma9UfYtxslmTNkxmMptS2SvOVSbhPFSQJFIVWaN105f
+HGmLwoRwV+Xd7nLX5hcR0Sozr58m/1FYun4c4797/bcGA5nDKQ9+u/GvOtqGhIU4
+EY5mkMhqt4MdDdKozQvATqWeSlESIFBZgG5sAQWuRJ9g2Pn1N2GTveY0ofIXV575
+WsharLOALP87zUur0E92LoBrbFAS7/nJ7T7F1Ye8ZoG88qs+vJy8SUVCrDjUqfgL
+90YHTKvmq3fJ+DO+40pLU+aiRBPin65h+5J0jW7f+eGpJV1S5dxIYKW0D1+PgcP5
+URVYuN+cGWROH4DN7zyIFPh1lls0GtAf1to+zBy9QYUFAjt2lB/oL/d8RRso4rHG
+8cUdXilKzAApI63nq0pKN2k9hAH5wGzxg3vWJCbsrXuqExsgZ0EFLR1IOX5ISCCZ
+g6TKiLDDSFBfWKTsix169JzCCptFwE+u8lY1b0A2ApCClXeS5+HvWlC/vtkuqCKj
+V51xSR7ltzosktG/gSc6wesbp0RlldK3Ee1l5Ld3sgoxFZd8aBuMVVfvqz0Li0ac
+883Yr9+nSvc9WspdytrfjcbUxmWtBxsDtVqhuIM4eNusUPY/L6FJhfX2kgjc8RNf
+MNJXiMOaTmQfVCTmKZDF1EN+4IZfdrudL+UoesTzasdlDXGKc5gCecWiQpn/hKto
+6YwKToh84r1R4gDcQGM+DL6wa1W5bVbD
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_des3_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_des3_ofb.pem
new file mode 100644
index 000000000..86f201939
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_des3_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-OFB,BB994897E99A8F6F
+
+Gx0S/6H98EIJK9lM7TBQrFejxjBVE0kcbBTVNTCJCuJ1Ik0s6+OqG1OFOLdXJWva
+M+k0WEWKhTAXtrrbzPiu01u+OVpIQ3xhgzt0rcU8UigfLLvMdqXoyuUTzCYHBraA
+ByJ0+Z9nK5r/OAJkq4gnRfhsDajZgOy8rZAdyIui9rom5emcx1GsnpW8WdRCuu5l
+kHEyaG5nHtUyZobZk1kNbkqelByCAFndV/eook4kycEytZWNPpFP+tUaXma92vDV
+sg3h2qODMr9ElrbvKYujOuFoO77BYM4oxlE/WtWpD29hmxaIgmnlvwUI7HerpZg8
+DbKYV/8ncRolxoE1GqO2dM2nLKaNKra+n5REJBpUDjwe/eV6dwcj5Uvk9nocEt55
+3qtmPbevuXga9mL5iTN8dm5RgrkzCX4LBu5fB3WviuseUBAqpKgq73RCutNM2gDm
+5CkV7Iar6tV+LgiUcgoo8RAnJbysFT6jQkGPYhABFKzdzrFFDDQUBpcLo6hgHpyb
+uQqjVXR69JFxdQpJSuc6cH60jzRQOvgwpCzpRiJL0mgXNXv51K87ucEzM81Z0UpG
+O4GYnsbo7PQfeLAE1PjP2B3xj8kgcRxWbHkQ/vIHTEAtJcXmAquULi+mNKAFb578
+qlBs77sLICgtpqBUzfoiH1ozcKHOJ3XB3yPYt7WKIxn3/rwqrgRDrPbyrrDmV+FC
+veepr8m8ZssbZjKy3z1js+jcvjKJOY6U/7Uc7IfZ6AjBXrkJIDEtn9RPoexG+av/
+P/LDsCF0ChhP44KZi5q5TLNvAmbvNL/7oogaSq9nw5hJYLiu2gScOAAv1h/j9yhE
+f2mz/xTHjr35m3Ax6wLPk2yS53PATS7XXQtWY8E0LJz7gOkSDvolwnyc5aRgS9WF
+H8DyqWi8vYzVLNd1qM1mAR55qrVhWnmlDmw+f2OJmP+6MNAoptW9nsUaeOk5xJVy
+QNSwJCjzp6ujIn5UhmrS2u59HW3hiW0J/O7aalBXYQxUv/qllKkrNmX8HlB/1r2C
+IniTw/Rd33TsNTBx8tqq9IpnAG4s51xHBeXT0+Sd4zNh+fIqAYLNuMllHMlM/oFu
+A7+h4TYAxEccchEha3GD6CMl
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cbc.pem
new file mode 100644
index 000000000..8a7d018e5
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CBC,B0CBF8975CC514AC
+
+eH3gBb3Shpdi9fkBr66H3xWR0XnIrKhPU1KABtoaYxE3N7su3duXHlx4zpc3YyO3
+s2YwjN64PdGYgFdwrznf97SjdI+MSJgu2wMxxTwJwOltEPBdbvNWEpq8SLdfdlDv
++zndoR7YnMIhQPp5Hch07dhwpY0hn3RELxYf32ALEbe4+xG8/LZWUBoKdgOn+trk
+1Oh0VB3eupjtsdxDWMMN3Ar+l/1AfdBoaQcHg3UdO52U+mTc38QAaMA+9Gplkz+Z
+YwjWz4tyltvTDWGAYGuhxTPVt3IoSewGVHWxKezFujNEhj6wuJBTlpN5T1pALfbD
+JUiGEmBXOPcxwa3QKmVKJFcA+p5eOYY15sqsIhcaXxPgzjO6JQWMErkaOnyB9sHg
+fQTXHwMau2HqzjOM8Qa/lQyv9nf45IFupKoTT6Kja2WzAVxd9KGW+NZSAa+okRSr
+GQrsXrJBFl3+wKpXN3alj94GK6aqCBiyd3d+pp2NyM9TorZhfWxbQamPmQVaU4aF
++nJjB+lW30wPZM6Ik4UqsgXolYXZCtV4cOaZ7g9ub2AYmYCA6yIagRFfjuEs0/f2
+MNN+qu1Z0sg0oCCpqO9kVcnnC4jIaXvU0egZVlGZ51GP7iR5VsLmi3VTbebnsvT7
+x8XYI1WHYuANsSBNRJj7vmrolzVErsX90FInNcnc7o43KQGyeR4E+vSdqoLHbk3A
+2HL9YLDV5cdvGafL6faVKFxUaA5CWCFVtrV6MPJAm/xWs5nu3wr6aNsDk/0R4mqi
+vzQe9EjkMprrihpXqFGpTaehJQFgLaE3FwnxPeUFawqdKIqaKf+stx3i24LkDSPs
+ukLiYS7cPcDYXN9kI6a0fqGtT/gL7NVa/jxsrl5+da/alvm/Ai7TJsUUi8dMzqIy
+85Hv6xWyPrwCbar4Ehq1CopxWvINo1AnvajIkBHvh4EtK7B51stOO6yNEV7spYxb
+nze92IMAtRNWO/yp/p/nccy9PB8/e2v41T8EN4MJuDxGX4k4cG0k2IGzBDcBM1pC
+YfmkHzMBGPsq3CQ85balLEWQTgR5nr/8+TabxyloED/Sw7mLM4gqMmn2KukzMxT6
+qeiFiGtmv2TbD7OWkaLj1Mth/ns1Of8U
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cfb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cfb.pem
new file mode 100644
index 000000000..acd0a47a8
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CFB,CB9482EEE6EC0DA2
+
+Bo62wJPRVVYQKoP0egdW3dLX4yU/Dbkx8TtIsNxNFhdwpGWtEGzervoU73+6aaWF
+LME/HVPUh+iZPKh9HuwSiP0GtwJzCv8arDp09mxGJ7XFcqz3AS7T+K9A1OclVa5o
+LwQ6ynBtCsmgiVlS/haNjeONqCtpy0kERgathUclwQCLTnQBZmu/l2Pk8Gdtc1Tc
+osmKc6BDlPOyofTt/UnrhVuZxasrS7tKEnVn/iZr5mjUZAqmC2mJcWT5YNahJpfO
+rawRjukIUOm0feFwov45+joTSIGDsNTYD3OV/+BF4ZgBMm33ApAE31JFoweUcI03
+2l+WS5qtmcwuOYGp0Np0BWg09KVwNbIghfiVUEjnqy55PCVOFH1RZrmHhPndCvHQ
+BwAaac0yAtd5vFWjeUf+pTbDmkA44g5f5aO9uQuB58WWkB8JCFpGZLizK4ISy5ay
+dE8+SjVGiMSZBDfAmiEokoYymc7L8bkTIl5Jo4TuMmtFcHnfohZd6Nue3aRzNZHJ
+E/V81IxIytHRlMl/dZjSujPw9FgmXSip/U1s8ESIVOVoy93HnaifgRfkkGggxp4l
+S8QqBvJTAJrQ9ygO3PBjgdKGi1XWvhH1Y5EwPJ6Wor4zzltftELEs1O9xfBT/zeV
+GENfUZZU+5V5ICm4K844WoiTkH5OIWAi/ZLK9XRqchaGWvMpv9UwBy3c0KOx1O4f
+j1/8pbXDv1iey2USNL/Nbw3nanIG0dIbUZ2g2U/FeKtfCfVHu5LJY+v6njKl58X4
+mthqvCZyyJy2U31MYUUDN/lgNffwLnzFc1AxYyxDZwviKmAIN+Ylh5jbxuElCS1T
+bpVd1+4aber+qv9Ar9G/PJEt9ZdHR3RB/tsEXv7ORke+fVzlKFQu9PKo4k25U/mn
+qfBcwlut9rMu19xsjbowqHyYJbenyrF55d00pp6P037cOKLStJECtpgir6HgTpo2
+Oyavx3OIH7ypvcyaqhFUqZI2EiGOdBwbSBp/jCqOrnAwTKo9uMcnmrsKj6EpjJzO
+VGK0DoieTEQ9VzGbqZKK34NHidE4j/MYW9lGKAADSy7Ey0CllvumHiICWOn9aJYy
+ObB64C3p8NFEcW5SrTzPtXeD
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ecb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ecb.pem
new file mode 100644
index 000000000..1ded3d7bc
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-ECB,4C5CF049EFF2E116
+
+M9XRNeRQW2K6U0bfpl3axdvsuTmsiFLkZ4C/76MLePY0HxePs3icSW82+t6awIpG
+gHfei8zevNlF331hGPW81XZAl8OaXWi+iGhIfKAInLKY//DBVI5dMTQUKTwBa87k
+oby7hLD+V4lVKr9o/tf2A43QjEkScVlxcofEnWUG84LkgXalsloaIAt7iu4qUMTA
+C1gTbkwex6bId97wvPQLvhFiOyrpsi5Nm98vEeJwMdb6dMNfLAd3Stjvhh5dGGaR
+BsRwDqgrkycYj6pOT0Zvg9fBxwLYeMk7PPo0bTEdY4itvpHXaRHcogsBJ62qnsFM
+mxk1opz6U0W9xKSNTCwLzg9xinRPXGDP5jz0zqE1nlQ1lrsPcsY+omKdaL/SGYlN
+vxDbm725eOoi1H0jsTGJsgcKJ7sKd6LTUEIAEsUvRAN+ro2zLhxteDP+gpCxTNRr
+ElOLddlDm6TB55lBkZVrH/0k/QQQ+L0lBi5Kgg/hE6oanMRGeKQvxhxRuBbK6tZB
+e0b0lffgZR0m49i3A+fTxa68lb6Lexggp6LAkheh6qOVAzSDWbk00fJ9SWNWO4oC
+9FNqu1yafLt3Xiyqv7iD1EOyGhYF8NDvbMpu+gM7qwbTPMjgXf9N9g+AxSbvrmHR
+5zGtJd+8BtU+139ZlsEv+cux1yxkYEypKm5MHfaa783b2zKuyOTMgOStvSOUgGhz
+c9dlWYPkgdgRkAMHzfIigHr9rQssde7pR7ZMlw75PxI7BI2ZF1Vj4weIkwH0SKFE
+fui/C67Uf78OHx4cVPANDk6cf4Ow8buH/vWjEX0p/jpOfNT9ZA6Otj0CyIQ56MjU
+L4nwFU7GqCbVkJtsHLI4sZmP4kH/3zuqVtwRTzQbQAWeTi6RCSwa8/amAStTPcX2
+WPRezgAtNzS1MBhileGuTP+opGdGOOp4AeCCJdFBzkEacRXylxdY7PUsCZI7mRSZ
+7AL1n9jbUbbgnl6zmqn7fybigjaTpLNSkVPOvVBxnNXxOW4n2HD4vA+q3a4d212X
+fWI+/y7mbYLLRs1LPPgjSLfPQ7Ye1Cj4KWy45Z9YBUtjdsEbaaHNp8TidgJKJuMJ
++sDQ3lvtJdIZZy26tzLf3ryE/+2KMTwG
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ofb.pem b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ofb.pem
new file mode 100644
index 000000000..331542c4e
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_128_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-OFB,F01B181DC9520301
+
+azqFQnexfYYO2tX4qlC6XLU2tPX5EdwOHsruz4uzVJmYFyRLlrgG57KkahVjWupu
+AHkkjhr9d9m/0/t2vFy5JEnF9WWcNA1nxqzfsaIKmnuCULzYzMWu1cFfTV2DZoAn
+npdxa/eYmcGRZ0u3aZHRGpGtP1y2sKvWmUInYCc69oigiEn1qyDkRE/tDAREh7C6
+DWRcva94GLj1igIHc61lBugZKBlchv+q8t02Ga1slM10QRg2dgAlF8uCPZe+NLUk
+8uOifATkKTsA8OsUgn9nRK9dH4FuZeD64NMCszOw7mYtjJ7YW0J0wYgC9BuEUcNm
+QTxellBcs/qSdi4pZWsO9JXxvoc0lTmvoiS0rL+JlB/UfubVQYq+C7ScVJeTUNKL
+6fF8hvfQzqDDjqx+qP4SgboAmIbL7tTJBeABnnhCOtaY5vSuT0l96rIQm/EZdlWD
+hXKcrhawaq6pqh/mV2S16e2gDRQyUX+jKvumTQhjN1+AkIb7EMR1ZLJFX1l343Fj
+5/V4D2+H3EZhbCdkz4uI6I0swDasUjtigcn19kOy5t1r49zpTJ3wxQptLRx4AXUZ
+zjVXVebGyFYSdu+Lks1VC9WDeisBW18kCg5IpOz3eo9ULBBQZnzSKS30OXlyO000
+/1Em8FPKSKYeST3SmI1aDObXOG/s4tyKTCj+e2VKROq8hDhJQUYUP0AgYkAnwURR
++XylYEfUrW9v758Kk3u82ZhEen/lLUQhWeXkzhVi44Lgih3Bjsm3jP5f7KO/5KfM
+UqECKIHR/p/H/klXPNmdFo919AFGcnxFjQCyhlv0Bl8FSc5FUkRl9TTLu+h5m/p2
+ONV63odsVGt2q/HmL+3hojX/BxSEP/8Mq1JHR4Dk0qqUpSxRtDw0XE9/LU6s9NZp
+zm6lkr5E2U6EN677bmem5QoxObNvc88EXGr0EvoWPnhh20lD3vQok7GBucnycoj0
+9NMmRUIflnj47quAGXI6LuTSzKqOOCZC4yNvdyRdil3DgyLLefr99m2WEe0HolDu
+pIyUsgHMlZC/YRVzqP/6DklhKDcvgWbBeqqhV1r/30rRkegHdsWiAEjmJadlBrJF
+szJZpa9obMH/q0xUH3AXXCkS
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_rc2_40_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_40_cbc.pem
new file mode 100644
index 000000000..d44bc8631
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_40_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-40-CBC,7AFE1927D7FEE9F6
+
+WgKt23n2XggL+3rzABzjmOq8sdOYfFuuYUzP6UNH3zdXRt/fh24/WRgRw+WCa5/l
+3Tt0/spkkMsgkkDwPPVLu0MUhfoUQyErK0F+8HeEdA82C7uGIgst4E2MS4bRXPR6
+w9U2R88xdUaljjahEbSMUG7JXecjL0WG+zLVDpDqMdlKNcMz1tnQbO1JNLZCJlfX
+ZlVPslMmTTxs1sqYgDhkAgh3FwSsKMj51nvedVCq2bAtSmgnz/bFDLT4c6N4iLf5
+MXP5ZUMUtWCac1hXayVw4koOkuPELKi2/1vWe7qDWJfqhKmRT2DV0Z1GKPjQp3Q6
+kGnD8oVxbKfCQDI6PSMOeBcWu40Y1yTbBHBFJO5+MdWsNOQI6CZGJCHNu2ZbOd+w
+tIcxZZjy5d4uY869PxxVxO8TmCRUn9hham6qfTw5Mmh7bOyxqID3fXlyrcE7KRel
+dlL9eQuLcA7wtH5vqpy6V28yWculvP7qmXAGUd1gqSYHUs8kipf46ecFwieCNPEH
+x/6hDl38UsuixchyyJTp5u9L5cKPy5PWXv773xcPguk01YhlmqrpTNZsdoJ/CTBg
+gal+o01rXd6snhp7IwSAppCPwh4YJumwdPjF6jUlmB/2AStF6kGaOA6BbJ/lQlCa
+cHAUaVlTZEyzSGShBGJUAN2AughiOq+2POgr5IgeoC0NL8ieMg7bMYjn7+Np4yZN
+KGmT1jZo7OmyVdh9mheahXTT4Axihfmy+uPTECuGjq4X3DVv79OvSFRpHXIXLnX9
+QkizsJKZc6v3FM6o5tbMDbJyelzaj8Xn8ANrugYMC1R4XImDSel6Bgxni2gHuTEc
+WrrILWnNSmNjz/yziFdu5VuQmYaJ1e50uenmOxiSQhL+53UzhhGCrw4ooAOSF5or
+s87oY1HO2aYq784A5UZVYGA6mYFjDDQSsbwp1LYomjoTrwoJML3P9x5SnaSrkEEC
+3Gm0R/t7SkdMmJhRc28uYarO2qdwyBuhoYRxw9Z6bXeaUN2WhJ7hILCL0KKZE4vB
+DuKxE/KgD8ijKpkUn+6fizWau6Lm5mqxyMyEDnCDkvlvv7DMoqZRJvVWSddNMd6t
+T94SaIiCDOY3SuQCi1361GGbVH2dXH+X
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_rc2_64_cbc.pem b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_64_cbc.pem
new file mode 100644
index 000000000..4a1ec9823
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_rc2_64_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-64-CBC,6646FC6A291EFE41
+
+KWLSTeo6nX30rQ3WbgL/13WAEMCtaC32ksYorVhlN4ijjiDu5gEnmfLRNYK4c3LH
+IUJawIdZvHSVxjrKNjmKA18w+4kedYCCL9NbNswd5eO18wldFR5NlSI2FGggzANN
+OwJoHUOXggYxhc2/xbYHpQpl7gvJqZtAjyewyTDYeTC3VDFoB/JywQ/8vv1MN8Ce
+Zx1k6preAQrnqo/LEIm+GPUa9flzWZlCGTIC+obNkjJGZPuUKLM/1TqNsrum33aa
+gFwnz//khQULylIRwxfuOMCHTslFmrs/7MLLbJQyTa99S9kc+s2VDlaKWUn0BVe/
+MoCseykcuIcskavuj01SYySJU1YHBTu7RvhuYO8AQmnsAP3gWQUMvKy9aXmzsoC2
+0Nk3QCZiG+1hN423So4NPOh42OWbqrDls9PKhXvQ8H+58rAxW2s7OTN29Klo39ek
+w8SFjMEtt9kLNpwBCJrIlolXvhD5WQu6XbqI0CtoOrh2Ote1c4uN88HyIUi1Y2Op
+QsfLkKyx7yJcJrz356Ab5lbJKVpKJW+frEHI7rLlfJrj88uzsh1B7oPL/4fhaj84
+vNUfadRJ25ZivBiHHdUTrKk9CLsIDS/1DWM6sDclYjXiA7kgGNwJupOb2L6VEKPv
+eimiJ9ooKq00E96Dc8s23FteQqySNaUAcqDnAkS+ck6pXQECZs4uD79k4pck1SX4
+O20OIPo79pzcWrmYOrTIXH6ttOcB3lUQtB1fmcMT5RSJYVSKtgBxLPKhLcL18xfb
+1HbDkpdUqS0R/nK7ecMd/LP+UmMKPUyMUTfTUnlXZzsNsgIBkm1eDn9RkOGaV+oc
+wau6FWmxVSPs9Inb+7A+B/2bP0qyYnciKX41I/PClKGitm52ScJyrEN0XJhQ0O+C
+mPp9weJI3IwpDn/Mc46NQO9uk4rC2P9o1zfJXC38PlEDEC66a1Y6SEQOVN6iYkYm
+rVytxWjD4o5vC+GwYJPYrmkOg/SQK1AlK8TSpNC5TeRcZ8YIbPLRfKRUQvUVtFS0
+fyPK9zdariwubkiG1a9/NWCF9gN1/DPKFYy+p5Au2ICD0iTtOND9I/Yw8dqsjzsF
+4jhYQ+No+ytLYc4Zo+8s1RO7yduFz7XQ
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/dsa/openssl_dsa_unencrypted.pem b/crypto/test/data/openssl/dsa/openssl_dsa_unencrypted.pem
new file mode 100644
index 000000000..ee815db16
--- /dev/null
+++ b/crypto/test/data/openssl/dsa/openssl_dsa_unencrypted.pem
@@ -0,0 +1,20 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIDPgIBAAKCAQEAyKItMopMK218pcmy6PkrMVXAv5dt07TdGBuNhVWpQ52ldK9X
+mL7CPKpo4Dy85EZRPvRNyOnhe+LRJZ+ReKntpEkEiar/ZsKVkUthPsiUMpoM5S79
+JK8iT8F9HdFjIFKaXGySBZ4xcrj8HQ/v75iolYCso+66Ybgjs9/nsWS0UQyGE6rc
+ibx7xPAtcbaGZUBaBtdkNER7+P2ueJwej89aNZxj+AKuvrWrArq6/5zOIhGR12wQ
+EQQjj7FQ66ZFivJ/AYsv1yXDS7mZBNp5eMuxk8Kmis/++HKcP7tdbVRnlfTGdBuN
+BMyOcBTIsE11jwikcI+KIbr9cEZoaikkm4KyuwIVAP4DZEC+/JZJ0PHSEtJTt6uz
+yn1hAoIBAHhLbqDib7zqaFBrNnbaBSNiltY3GxWM6uQT88NH9YWz3wXRb6i4KJFH
+9NtLbK0RF7MoQVprJY6LuGQHZ/e61Fs2EabDwT4vB2HT619fVUvDndbuSW6qfUR4
+y9kbG7zLkE4Mnym/ikmUwLABLA67cZUS9yjtcRXGpOkiTAQfCGBeUH6nWOFEaWjI
+fGNMQ5awKvZhIvGyN4Zvd+mE+199s/kAsCKFux2Sq9tYw3qS0Tw2IEebHsHvX7A3
+bvxV6p7czVxlO9+O0w7bBTekPpw1BnCYmPyy0H36g/7aF2V70UCWzER8zT1Pfh7d
+3P0hLqHYzX375l/7oxuDawtcDAV++iwCggEASajPdllHVQ8JvKdPH6qDkjC5XJTZ
+RK46mYm1cCu8Q9Dy9ZfL67CcJBpwKVHNC3sXmk4XPfs91AZf/t01qbMJvCrR8NHs
+jRyJkNIaMyDeWcFmO0KmMi374BQpFyIDQ6mK1y9BilneZ6gHDdfHMsKniLFW+SQf
+9hlwlArIPYuELu7riJhNcuRUTJEfybDHwM4/ht0IFbyUIFl00mMdTrozk+e/esEs
+QdWbx2UBjNs8meZPivFbT2HpQF1I0qZhtn3e7jcR5YatBQ3e4abnu1RrDc73q7d4
+g2SYQK3PmIWwxiFhJQTzeiQtl5rKzEn76knAydOtPVRgjXWzHUoW6Az0qwIVAMvw
+thRrEZxNdxELdnwW3rpYBm6B
+-----END DSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/eckey.pem b/crypto/test/data/openssl/eckey.pem
new file mode 100644
index 000000000..8ceb3a8a3
--- /dev/null
+++ b/crypto/test/data/openssl/eckey.pem
@@ -0,0 +1,9 @@
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIg==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCSBU3vo7ieeKs0ABQamy/ynxlde7Ylr8HmyfLaNnMrjAwPp9R+KMUE
+hB7zxSAXv9KgBwYFK4EEACKhZANiAQQyyolMpg+TyB4o9kPWqafHIOe8o9K1glus
++w2sY8OIPQQWGb5i5LdAyi/SscwU24rZM0yiL3BHodp9ccwyhLrFYgXJUOQcCN2d
+no1GMols5497in5gL5+zn0yMsRtyv5o=
+-----END EC PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/enckey.pem b/crypto/test/data/openssl/enckey.pem
new file mode 100644
index 000000000..137fab345
--- /dev/null
+++ b/crypto/test/data/openssl/enckey.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIpII67Pp5Vs8CAggA
+MB0GCWCGSAFlAwQBKgQQBpkbyKLxdtlBlp6tm6lZoASCBND/h43o5NNNmTXWHN2+
+N9ncoFknxohgShAc8WHKMHt0SCEJab8E2IAxVkYFMOMpvi1KVldcveLlg7hcMIDm
+74pJmvXOW6b0bENvPMOxFadzr9NjO7j5ZT81dwNLz2pBLyiUMYElWl0LVnxKThQF
+qijJTDPcmTpFwDiUyTxzHxMx4DsoFYQulRBsZbRCAjsFpPM+OrOekSAyQHKMSbHU
+LvcdWCrSDRtKOyCeCPbBA4OzPJFyzep6trhbQii6rkddf9o54/oJut+LMuUblrHE
+2yMStfW0G5ZyI7AeOxAy1gKG/CQrvFHn/yhtyjkvPa0sYVGtR4pGew+cs9iIsdFk
+nXOf9frJMA2agQZKc4+rf66NPv+dxVecm40HIR3omk7EnxR8s6msXOOn4qnY7qae
+aq1M7pKNqCu6eW5560mW6buLpOkpm/kDbr4v9rfCX41b5rIRzOdfAt71FSJcHp6K
+FNojK86YsNJWYh9pnfDbjEk7346cCIeJVgICGTmL8Tg6TUy9wIB6eKUXmIG3fKjI
+Ep8OzYAU3/ae8vdmZqD12l3v75muRPs4bP1RdjaVrux5Xlq8TkzU21ixWG6Odj7I
+1jusSUjz16iR29XhLP/HI80GKYQMc2yHWcYQ1YVXyLzhnHYydrqjW5OTKZW01rbe
+9BC8XlRzKZJ4IOQMfSiZxcdERtImO86Kprl4du7gvWaTUGTyiQ721Q08GfFdVuAn
+OO/J8stTLv2Ee7ugTeAFA2+qpz2vAo5JIPOmqjNqI2ytPjLRb80B3tSVXT41OodT
+D4v5YbNpySMDpw2F052Wx37hl2wNxIP98U6aw3ZjJdM/YfLdGOJhdoRTBDAvygRU
+Di6F56sDvX8bdXDUZURMg+iMx3Noc5G3TB3JpYunm3BL9lwGWesrkDzg3Vs1J/6c
+4AMhAsw9+5tzvyGEDHnGZRg07K0eyWskDK0/Qb+vjSLOj8+QphM+EPCmugNnXRNo
+AdslIFoVfrcKruS1/DeSIesXvMd7sj2RH/xYDcAIGzmwbc+Ki4JTPuoZlF3pGMYE
+YkkYj2KHjJeX7CeUjCmU9Y7/jHp+fzlKsQAMQLVm8bRjDpvLA84RDJRoCPav333F
+YqRciZzMjfx2f6AJTCT+/8nv+DBiWcRtab1u6f+p1iDUa8bVt0Y8PB71gwAyonmY
+gp4A3fSilIlKEGsP2Hb4aU9V5vy1EZT0K0PuAY4yxGPmhedLCKdBqOuwQBxsLDP2
+YmXR5wQOsI0dVE8zogpgOGOEE9RXNAf7QV7pBOPNu4HQLNuZi22dKi+wkyMLsIR5
+dGEz7uDIaGQMvlprtOA02RON3gBnQTJAp7E/YMd7OldSBShRRGeIDw7yTrLoHwLI
+YnA5+ZwFLBPnOrnBC47CwgB2X/+ooL8/+yigoajZIIE5RvzuKRQGjC/ZgSHXSHrt
+mJKGerOR/3+OYYCTctTa3wTPVRc/vB1hZac9OPmnKpeywCJ4Q+jX+ZOhHOM671H6
+h9fLPd0tSE75gIkSuJqBuLV2TB1cp7BTnrZxLywCxC779lZBTVLctXu60kiIoW46
+zgEz1dyf22vfMN5ss0ybvBVCl8ROmrVr8ZWObzkj1MUyifDM8Tayd3uZ3SdHPo8L
+2G24+4bjyVdFjUvrBdzB5dNzAQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/pkcs7.pem b/crypto/test/data/openssl/pkcs7.pem
new file mode 100644
index 000000000..6104acd72
--- /dev/null
+++ b/crypto/test/data/openssl/pkcs7.pem
@@ -0,0 +1,54 @@
+-----BEGIN PKCS7-----
+MIIJogYJKoZIhvcNAQcDoIIJkzCCCY8CAQAxgfgwgfUCAQAwXjBZMQswCQYDVQQG
+EwJHQjESMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYD
+VQQKEw5NeSBDb21wYW55IEx0ZDELMAkGA1UEAxMCWFgCAQAwDQYJKoZIhvcNAQEB
+BQAEgYAikb9cD39oDYpMHzLuqA4BonNpPx+jYtqlUIaJv30V03nUz1MLm7IH7TFt
+ZhL6BXAbdC2iwk62KVS66ZCLBKdsqtD3w9N2HtxTEW6AdaNHKNUb6z83yarNQGzB
+67llZjeCLeipP7RWIvBZcV0OoqCgLcpZkpZqzrmz5MjxTCmB/DCCCI0GCSqGSIb3
+DQEHATAUBggqhkiG9w0DBwQIja9nGhuQE1GAgghocswhe5MZRov9Zo1gnB25S0P8
+Mw3463VaOcb+ljX1mXkT3fivkBv0plLlmVT+m+CRgczup9p21+t1OqsdaITNIyrG
+hYSVETWyFA/Yn7dQupK+cdCaVLKC3lT8f13iPrU40wnbeo4ZKi2vbv/X3uU4fRMZ
+wSlyczFozcviUYURtA5MZaS2e6/2r1eLZcUlcZ0BDcuD+FNdryGbKztSWa2ye0Ym
+Uilu+GAZr5CQi3IxpRxDqrS+RUQZNllcg8nGZ2UP5W8FjH+Z568NJ7djoziCX0EH
+yd4vp+g0LRG2dkhGXIff4ufO2U3QOAgCIOuZmG5YSpRN2U7F6T8W/FwShFO1u+QH
+YduA3pA/5K+IDfCbEZDMWznd13lTEZQlLSXV7dLNCqpR30JWpGg956rJR0k2bT7G
+KFTXhSUK/Puac5y6IVmJwPxqAkjH+xjXpE32/AcRHi77La3nKp1aQEKo5uHg7HEg
+w160S1LUenJSqcmOuk5XWvM1wdsUJl5Qk4m9a0VyovLPm/RrnulMtUjRugxJLfZK
+27NivOrLl9h/Wm6BXYq4PohM5d+5zPYqupn5ipKHsA68Ps7rnDEGS3VzOQ32hqu4
+kdm6xI2zLWK0+6mQnusBPO0IAxtja6BPz8vTMlWjZtWZgEIMppQMhQJKBEQG6HTV
+z+/gkFds2pFO0v8pLcMBy9+8nqhzwGacymnupXJzB6l3gon2t/e2zJjAPKUSCbHI
+QhCjW2JK9tGKTbF40uYMUGMIPhxr7j1u4LKNEhKCNhlUz82NSsdJ00YNQdwuDMWN
+CTAE9/STmRGF3ZHT9KWmz5MQECp/pGORD7LtOQslbUYiMH5oCYP1jD8eM+KxCljv
+1pFPf+sZdpboAkdaXKcZVnKqOuPBP3Y1jBkLCZykgnXkVbEYM7gSdvsCGK52GcxH
+yi/gOhfOIgywmFB3B4Yk4mDtU84WpK5sVlrZ2vZuTaAmOHaTIkVMvkq30F/jpVy3
+OF4v9/EbEAJGv6rqHMhKmuIHP530CKtWkUUfGv7qQilZ1Qi6NyFJJTfb1bhyENJt
+j8A1QQFIYHDzMolmUoQgqOXJ/6xc9AtCv0fU2LijLUNFjB4rapJggo5UnZE98+Iq
+UAT7tWalpbFisOdX5Dy582hhvcFn/1DDpISXpF0kgE8TV/swkJ7zuu+hO/Yj1HNd
+cwG6NC9+wUCjaRqAobBtvPQyK666I8C12pnW0AeuqtznnZve2B0/a83ECS0tUmxC
+PO9zv9RNwcakynklrupw7B4PcXEaEbxpvHE+/zNLgfrPRggoFdqSIRFS9xQRPE9T
+uO7jEh+tyh70eLqce2jqKpRwxItZst3ABT5XarJ6vfGxxcs55sJG7xjv52xuMikY
+gOagSKpETRdkeE1aAmKwpa/vEFu2J4Oq1Aiv+D2Gc7G04cOsdc+6P+N9EEv70v0R
+3NA4vg3gTBcO3wxwnJZAS7GwUJOcrqC1cAaQkc5NR0lUx0lMzgWWDDS5qKX+YwIU
+7KEQiyhqQ74rkf6hxQyfesaBxqxCZZkikbwBHlDZwoPfwnfrV4X4/xyo3cqCqbhf
+FFlHOAXissz14wsTPh4XQumj5RZSnwj8gGK2xou9H9wMrwuZ2eAT/3L3OtbIr/Sz
+Cbp8Y95Tz8FgmrJXvygMVO1xv77PA1DzE9SLiLyB6TL8lsxFQ1ZF2D8JhpDeIPpj
+L0k2vTrmCgENJ+tCc0ngZO55ZgRbo1fbB/RUfkTRgEKF9WmJYnlXUVoh77kZ0cc9
+Y+KsueEZp1woSTywJb3tc/jXeRGSmcaWe6pa0DcfM50coV0y4lw1ednEV3zkA1r4
+zVtUBw8Xvr9GKcNfWdmqgIJKsQraq6WCeIxCPPJw708+/RERQBoUobXI4+Jatw/z
+XiV9SjrjK9nJ4H1YKyOjyz3SAbeYrgdgrTGvkETCPAALb+4Rg1FHymSMfDquwOsB
+63Mdl63DIkJpicA6CY6yk/LgOADQzEipjcdKqzQOjlb4hsQZxN83kzGJiWB0qZOL
+XVLrGXP4xRYS2bUFB0T8pon0K5qsZ9oKKf+HZaHMYkni43Ef9IRA0qeDl4FfAupA
+kL0lLnBjgGRHc6rMBy4qL18xRjTtR9hsn4Z/pYhIgqMm3QEVkK/aOgTOlwXHdIwu
++Hvzx0Y/BgMdCZSlrspPbQBDgrlWzr+PjcjEvDf3LYj9whtRJP5cXVxiYqi/SpCk
+Ghy47RfNYfkkJs/gbojlO/lDvM8oo+XPi22zAN6yFLuxr65lJZK7QIvabHvTkEIN
+wmpnWcRH+MwcFZO3yKt6lxY7nJWuW5hh8O7k4/oN0pNdGtv1/2XgXFOCREQ4CcPn
+Zm/vXULLCCh7oP+RyklnwyedvfeSfY4lpldwyHCIsYyYmfZHMw32zqH5jCnSxZA4
+fHBrblr4Mj/5jyHLUF5xGsJdm5RtDfwJWe6NelO/kJMs35UjA6dhSOfHEkw73M5P
+jcRo1OtYZGu19x2QguhILpZxuAvNtLpOt88z3PtsxA6Fc0BGpQXPJTYwtXiPf1lj
+fUd5KFsPohPJOIEJAaFHL3GTwmWFtK1dHofPQukiOTb6pC6yKlM/zGWLOyzTM4qP
+UvuUSwg1UY8GplCeqhCJNTieNmyY70vzG2CWcotAwRPeVbpa4MEWRXHf9ft4Mawb
+qn2J48iW4Zgh82vFHNYcGRjKRJqLzp4VBn/qpRaX+aWEsdXq4shRgFOAOKyQNMex
+GZyd9amkblqjEOOEzzxPUdmt8k+QEm+JC80NR2sv1mw80PqU/his5zUJ1Aj4tzkF
+fi4jy2nPNvVSpjWiAI6cpZsbdhdh9iayij4YdQg3HB20+1K9VcFnTmBqLKiBbG2o
+4oX2oNPE9Vr3H9Y8YaVoeUU+Kiqo5g==
+-----END PKCS7-----
diff --git a/crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa.pem b/crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa.pem
new file mode 100644
index 000000000..8111b0d69
--- /dev/null
+++ b/crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDIY6+Wgj6MqdEd
+Yq6FgH5xMgTBmFqAonR/eshjxY2C6MHs+WmCmNSDik2NgZWIaODvOF9uOEK2U0Zf
+JEG2LcZxoeIEgg/mfII2f4DLy1JYajm/llzwFBzAd/Rkcs3qwP2ba5VKn/pSqNLl
+nKHMXkXO+9SjfHDx95x2dK1dB8eGQGculOMcTm3uK7UlWNO4TSlwG9qHZ1aoM3GI
+g5C1fIpbxJqDVjFq6fFAapE3KRIWIQmKd3E5ICcDErqr/AapxnfO8UFNxVWSOLW7
+ZAfis4w/c8/EAgyQHw42R0dNyjUOZsToF8McCsOpRjGolSU8aUyqspvd8IWJPd5d
+6HBHueXNAgMBAAECggEAV3q9MpVVPQ79TTjBO2Km0D+nt+QMzk8dUHGHfZbGejmm
+Pw96shqJ24rK5FWHs+8lEwmnD3TcGsAr3mjzjtZY5U5oXtNwoYwFRElRLqZqIlLt
+NugrVltRWeyD8j30CuGJVQoYOGWyX9d3ielg8NjO3NcvMtembttLoKK68/vrbH11
+9W7wr5p8/xyMfyl9curnmCFk5QqJ1FBpjPWY05NDIBCUJB0tGAqViCpxEeWPSlvb
+xcElqWfdbtnsYUxYU+iOTHHotoKnz4nLHYK2/njMhlCEyMXfu1DJOd8rg5yXewJF
+v6NhXgWStSexAT1bZ17LROazVcHfWB9QmXF1Fm7vOQKBgQD+dZxPDOi3Y4gCFegn
+Z+epNyl2aPTkseEZxrIqPKLHsGxUfYjQqkX2RdfTrq2vf4vFlN6uCXhSlZKXfLH/
+iQ8FAzqenhVVHK2fv5xB0SE5zNmcHDrHshl+/zUNI2u5AMFECVO2SVbgoFjvgkou
+FolK8XUXfHfb4f732LUyYI0lEwKBgQDJmkWHhzekz3P5iWaAt1SH8bZpt2hqa6Bx
+A4VvMdtmjCxEDETN0Rb3CPYxw3qa3xGfW1y1j/49xi4gr69yaT2Tbca7PFGUmWRo
+OJwfCUB5uBUi6UVytK19OVKReOm4666x8P3YO4cxxSI/HeoSU0HR1kkX9rGmrsGN
+MgUQ15+FnwKBgAKf6/DUzUG3ARwkZbSiWb1hGEhkZMJHI29EoWnWHke5BiUI9nRQ
+jVAxADzqvFfnFOYA1xssddVEPbLaUmu0WjdPBTfFoaqzFQdkzpPPOGyENGpr0B9n
+MuQgdceg6eeKnnO5NOfYcdD3VnOCAInhKaFgRDjty7604hBkZ9oRLOOJAoGBAIJ+
+dmUMlGr80XADjTLh+DhqsA1r542DDv44LkXUetS9BOYjHuIuZnQO+/UoOBNJMsn4
+xGDNzN7FihQkRCeFkZL9arbFi3TpeUGw6vV38qEXE69eWVKvOuEkmpqJLphBDfom
+KNmvZopDtTAvt9SWybL+xp9ZUpK26ZfwebD2MU63AoGBAOa2Kt01DxoqiWiQP/ds
+Mc9wOw1zJsSmIK7wEiW3FkCz8uw3UgjF9ymYY/YAW3eZtuUpuxEzyENb9f21p4b2
+zYoZ7nCUo4TmVXxgCjiEWglg3b/R3xjQr1dAABhTeI8bXMv5r/tMUsnS79uKqwGD
+2Gc1syc3+055K4qcfZHH0XWu
+-----END PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa_enc.pem b/crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa_enc.pem
new file mode 100644
index 000000000..fa3cff6b3
--- /dev/null
+++ b/crypto/test/data/openssl/pkcs8/openssl_pkcs8_rsa_enc.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIleYNcQVMEocCAggA
+MBQGCCqGSIb3DQMHBAjb8ZXri5RWRwSCBMjR3ICOxCzBu74U87lV1QXPNlnlHD2v
+TlRv2LNLPseEBAMiJkgP47rYwpzMmJjW5bNzCLxT0pYv2Z3/pXPUqy6aNJmOgCmU
+HvVGdz2jS+WYBtfijc1J6MkuvkhRIBxL4CYJidVurc5X/ebRu3BHbj9Kg/j5Hjx7
+DV4qTxZR8vbRFH+ETdnVqj3pCYNOeYXvV+S0W7IN3rKmEk2su3u19YhbwnZH7Ny2
+YMjAn9FaYT8bK+zlPBZBiQ8TuZxm/jxvW2ScQPLk1pRUs8WkDsaYY1gdg5XuKDND
+xA+mq5xskAMUliQmhJaYxlmv83QZ89JzSd44lLvnNeiaP2xjAhj10ZSVQ8eOXP63
+NfHr9Ehqne5k0CI2fGg78pp8vIihw5D4WjHR46NvmbL1KIlxuYi4nFMtc9aK1zgq
+3rhDL9m3fZZ9Rdd6lb1LN3ZOL8e54tL4KKVkl5jxhrThHujACB94remv6da2z6K1
+LZPuDwI0njzC6Y6LgyGgAP75NKNAH0UzbpPncZxBdhyI5mOgRZnTMNt1XoToXOHP
+CMR5JfKqpczhoJnfcQJhFy44E1NH+qBOsNQTpypDe7Qiz878e6ebfcmXID0OyU/j
+o8czO+1BVT1S2LoN+xpeWcyNYoT+BnRVC99G7vKUoOeo90zNzQQOAEyoAjAg/52Y
+JWnOqnaxDqa0uJ/BPmESFvxeYZypJtoTd/g7n45J4fGBSwiH05TB9PbLHD3YcfxR
+NorFiq/RVXMXkgOGv+2ovJ/A6GK5mS/r1xr4qKnnO44zqwaie/xdZpXuQfQ8ZS7H
+XLVWgbdGP7fbTW72mAG5UzUr6c6gwPo8g6aiOaOnRU32SswhLp4CFgiKFhhgZ4YW
+tLmWc1Lz92D8ctTMvXhV+z8NEPF+livmfANpyhXl6ErCr8jEnhGgj4r7BA19dUXC
+Tttq+Gpo05tMXqom8/6PbQ3Cg2iCT8RGk6v0p2ne3Dg1LlbnklEfV8/DbYO5tUD/
++BXZhF1otr/ZaSdz/jJ+GzmD9KvhheQHBikj1/KicYp1KHYfo9oZJT5ulBO1UX/w
+JbpLaarntLOqb5im6OdjkPFkklVV9m6EByrfd35BTEfowNaasEvrj/VpchGPo7yf
+eFB6HGeIFHNloG7xXn9rv4npJLJOleqmBgyb4cQAk2KwjEJ38LHOyXQL/+tfI5DK
+NKzoFH33dtHnP2ZwaAE5ffMYv284y06n09yOFqPi8YkeFs+UiFeV4Kcht1gUNkPo
+IOLhwfVxoc9H5CbIBC3emckvbpnuBT9+EefGU3pU9e9et60mQ8sp28vtx16rN/e9
+CiXhRXcLyQZxucmoLKXnyXgJbf3+nXcr4zMkNurqUisc+YVMALePkJCCsqRWPCvo
+vDqwMl8rkG3jAqmMJbtZCx7+vvnRnFQSE4BXOlzEQNPZK+EdlfvY5uvksIt93FF+
+E6CIPHW4ki/X6gTIR6piDKiNEle+2e/fJpYqk/pFuVfmiN50QXzrnLrPCznhzQ9V
+GN2j9/b8iKzBk5y4wMNkOS8LT2qdcJoJRzZBb4VV981GwFxhAagwM29wko4sdNG/
+vU4hrrm8WAfmp6d3/UdG6VdQj0O57z7BX6Vr91OBNw5RZKRkQvMu3Q5vCH7ZfYEj
++YM=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/pkcs8test.pem b/crypto/test/data/openssl/pkcs8test.pem
new file mode 100644
index 000000000..17606931b
--- /dev/null
+++ b/crypto/test/data/openssl/pkcs8test.pem
@@ -0,0 +1,175 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBvYyk4LsBVS3S
+34GZc8uuddHq7cUJx1lZaxWK7C6nnTNKJmJEhxW80VIukpo2RODL1hPFlgCJY3ch
+/4437UoG8ZNAE1BfuVMIkS1AX/l/KAyqUIX/bsXgvZch0Joo92KaPfDB7QA8VCGd
+NCcRaOnusDdsFDdF4/Mrd7/x+Ipkd56FXVEk14QGizFc86aNJrzXjy9ent34PTcS
+uGPXUX7pbiZj8gK9f77pDuH+JymqXdfBKz/x0T54i8N4QFfVp2LbGzeRnduaX4Ff
+79ikdo/XQYTPOYoDwgdiAR+n0+mvDNkI5rbukSLcz+xbWdkJ1ReHW/QQAiqQWK37
+4D1fFNrZAgMBAAECggEAGbH+GVAE/WRCs5kZIzUMapMNyE7It0dNPmLJdKdmeKyM
+xOTaW6Re6bAJakvfUBtKhT5bWPVQFOiwQD4Yqqo6Czm3AeSN4GQ/8v7uNX+FI6w4
+Ic6UNxCGBgyfIsj76TsGRNa6O74nLdkqrCLim5iCjjmo4Bi+S/Kzqaw0NO91y2Um
+9XyCzM7Oh4LukmF94pd5gZBQjjVEkEsw3+oQlOznm3rCNIhYSjfStnFZT5stvcIw
+BscQg386Wo+UvXV8zDI0qrAi0pNepVGsdpGGGUIHkogaF9HHElcSIAVBOQLhxvf5
+S27j3bvHBzWmmR/MgOsBH5+ZqQCTzVGJdzIzXkCRUQKBgQDkQIQNsRv0V44UriNr
+nageBkbjVFxczl5k2qN193qb0GalSOoeKcT9jsBO32mcaBd84vuueSNS69rGlj8+
+7rKyMsRAnjhbMJ0FCWv2muQjxZWEcTWV38wgXkbzos4fon19wQo3JPg0ikOjmGbK
+Z4EIJE0PIw6hjGrTXqc9wK4kgwKBgQDZSv2KVaTX80ZyLIOlbs5+CTAzlEde8+u+
+7LcFOvrrzeo86i6+65yvu395Dlm6PAhz0KocaUECeEDakdQHEDfvEf29BsU+p7fU
+kfNPotacAD7kNo2WenzH0mIhtBWchSUz1P3cIbq4Rxm4XPlAzMEXcDtFRqf+4wVV
+d8Thcjl8cwKBgQCKVGczfRC6Bo3/DoI86DFI8PjpMOlA/XjLmo3SIofWAnkS1pu8
+aAgQuwDlTBTPS25gq5doZ9X2nSXbkJcH5tW5lXbGypzQ9ydSNCGQNNLqswYoXAvj
+ptwpCbnqUdKl7W4sVl+AiBE8lkbj0KsLI6tZadahw9dMJLNhIk4s6KchTQKBgB4f
+PCh6GODq04AuVY2QX8WvBmSQEJjEHZEZBYIPHAumPut010gWJ2FhD5m7eIrNmapc
+aciIer+Z5fumrYrRH7/fcZpLnvpBi8VG+kC25SM5EX7XZSdQEY4txva/HSPWfULD
+KvHiJx02lgUttkvaVoYmQ8Elu1IlLG8drEhIalmrAoGAKLjcIIAcAhuE0QkstS/z
+ZiFhp7tCCrH5sVvXPJfxuKtEC3iTfgOoMywaX3SQGkOP5kVngziGemv1b493Vmek
+T8JLbnNbkooCvPsbMlMgcqZcb/5ckymabMaJBTqhYP4w/uRETNyjmb0uxX2CqXk0
+RoIdgWsw0IiLCNMn16z5O5w=
+-----END PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIGQp1RhqLV50CAggA
+MB0GCWCGSAFlAwQBAgQQhMfC5lWjUndHWVmSgLGLMgSCBNBZEZlGvXV9XjzWo0di
+IJof42XSh+mrOdRvUPUS0uPzctmnXZjhKdu42v5jrbyNdruqZsMXTnnQC/UW7Fox
+fp3JzOM5w7wEmgrJybOZgA5spNkiWDdlnmqKme34wEPKv+GPEuHj7w+Z4hc7MSdg
+T6Q3CJFLJDCEvfK70Gyxp6X90HN1riQQVxFOTSg9TJsnsvkOJ9Ju3VCTOqt3jlW0
+FEzrC3lV4AcxfWZct7tkqOTXygWMGinz7OqLxIcmlrF3oc0bLxEQzQuGCJIzrhKo
+3Lb73Xto/kC/uqbCdU+v1zafdKLI/0Uj3/GOGLUu/PeMo7VaHbAj/AOX63Yvj3zm
+WOgJwnOis5iP5rqL3lfdeJrkmE1w7xTLn9fUWXXr+qcVBLeZY30TE9wW9gRCDCka
+09ZVw9MnrodTgvWVSI3xHxjYin8GcxQ+VZTxQMQFHA2cyR60yMG+eGm5t3TZNHVW
+h3uqVxjbN7tMYbjUo1NdbINntOQZhqMje39ai3mWIhGPO09yfsw7ZRX9hhKlrIYo
+UQ4LcEgMZsZDDtAY+Mol7pYB7KpM2iftBT8KSkBLSlqpndl4PJHLUaNBgbNDP6py
+PB8FjPO49qPybeVCIgg3AswxJwGE9bXtO9SLcf/p6S0IWvVcWn+VV5sX+9Bav0eZ
+nCO0WJYrWcjUBzYJLWIDcPviYkoMkFrsFGUP0DA7OneLlW84YUh3AeqqJppb/qve
+UeUXZipLEHf+Z/ToGW+RzPQmFTVDqIx0FdQCi3EefBr3CbN/KtLdRjbP4kyeRGlw
+CUS+BWQ+W/NtVUfVmBvsSLtVfW1pevemt4FE9rP9qUa8KeRpOJIzF4kHUmHyDfp6
+rvQTSS6d3a+N1GyJA5/N4UM6g7FbVnbngPvM1hMNfK6xbIcxQJudBQa/bHqf8DXu
+61npKQYir+TmgDXlc9iD23M+TH2VgeunrFKuVMNVl4igH3+mcHyXpZ/EGM0KyIhq
+PJjPRKD0qcCvs4mPRiOx1wJbCYMdYfEF7sIlkQgKjbQZQyRlDKLkLl4pGWXxaqUm
+iyo6VpK2phKcA/hPYz10isRfy1WrKdNHW0B5DPyreko2H0akapfqMjROE0JHtVGs
+gKg0FrbZXUP+QuKm0V91ShA7c3mRfN2XNbxEc9JFzkDJs4JBxj2H7MxvPQyRrWE3
+sKsQWtr5AFpFb5p5kqCtyyu7ag9pGicqlaFuLda/PR0ykMrhMU4RBO0OulOGl8ZP
+9RC1GCArbSSUYH9xvwthGdaDylONVmHwunFMHs8pblTyo6FiKn1q7lIVXYO3AJ/5
+NfKgryp50SXq0p41i8Dtu+4R6CKx4xTMilPYKYDiDPCRtnwvckI/PshGMA/CHLzr
+LLZUlRt1iup5SDjqRIjquw/aDRe+Wy4AXXniHOnlSrNynHcJRWz+pnLT3Bi6Z2nQ
+ERY4pCIQ/ZdhAHHldFZ7WJ2wrwhf4MQ7sF20HLgXeUN3qj4xYcwR3CykU8f7dfI7
+TIo26asqsVDsVL02tr4dUrtm4J8yQsH8jD0nCpvGwJ9gswUBPmo9YreN82Kt/LSy
+YZISyo2BnoowEcAEGnZBf+PLwBeePeXC2/vrxHlMl7JPkPesEHtTuET034woXELi
+wO/DuStXmiIydT29G1n81zmdVw==
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI7ITJ8AdDrO0CAggA
+MBQGCCqGSIb3DQMHBAinsLeB93eJ2QSCBMhi3oBwLoE4PNYkIpp3FVk6VHzs7SGQ
+u/KcyYQk0Shjbe/ykNJx72OVfzYemlcNpr4p9Jt3VbXxisiZyRs2m1Edqxzdt3zb
+AcRSVNIbph8V9mSZNBl2hR3GAsrbSTkwM4xzXCQRvA50z1DIABlVFR9AB/52JQ/f
+IQx9NrG6SxlzcNjJMzHpR46ELG0Z5EqPLrdyScVX7TEFWl2ue9P/MOhjfZH0/Wgk
+fFCFNoPsABQ6az/lTj1f7hkYMOIw2tayHAuAXTbqyuOVWhVfAqr3H/XuJvXspjDC
+SmIr9jIdJKOTNrJD1/rG4wnh9U0OHxceQqf+TJisWd12WVjwMZ1jIqjk0g+BQeId
+JJvuJTdVVGee1C3enPjG5qBiSJpD+BEsfk7YQFRzW5TzlzELIdkjru3k3cqSp+dX
+Hp1LT6E8TTcdX4wdhKWf7VV6sayleiaiB+9XufqU7FwnOJbe0sydnn8L7A07qFcs
+9WrXmCSCpB2bH0MYDvuauqHjpIZmaHUAUpXYUjjj8EnuhesJAz2bzO7fQ9rZAQ0D
+6Gq4SLbjTtOlpS2LZeNio5ibyeQkgNs76Tq0zdS+5fFnL/6tIIsJUbdZdLz/5isq
+j+SO+7TiGL8a5URZO2pc3Dh/TtjV/lSiI8qb/MMUAmCL0vWe/FKx3xx4dCrRfDX1
+GyeclEl4pWFqnwSQyHadr1nvnvGrG4/pcwrcnhNNb+Y80RIw15A/kNjsKP1f3XWr
+eHAp+YGqDbJ/RuvoVunoAx3PwA56NTQLMmzYakgQFEPtModtvHTQnLkGozg0VjWk
+TdkB7R8GS87IHpOUyrZcxKYDwOmhR2bHgtosvZ4XK+GAwjIGUzGKtg6MyMh3ynsP
+68Vaj4PgkvmItmdZKrvkinophdFqFlqCLLNf6NtaVUMfz3Ap/vmX+EK+2YWxezNa
+qFMNXO76xoKj+piF47vN7zjGsJ59yLLWZHO9J8hFLqSgArhVcV69j7JVMD3XugbG
+YEFudiVEwE8Kl190CVP1BX8DXYhMrrDL/4QD+jccgLfK20bWdaCtPOs6SxahhsvU
+wRX8hwf3QLiuZxfAIlVCn2eL+9QffJYETjfhAuvPK/HwM6+/n+9GpYc4Ezs593KJ
+9/mZLuMKc0b9tDc0dQ5ld7aNiWuWyP46Da9FWBdbjoiBOHIUp8h5METE1NuH2d1l
+THWYaD0OyOgyi2gosRkjJxqDp0IVxIymsKhX0K/EBcYuKiPKZLL8lCTdrzGlhRC7
+M7N99j2elk3k6BJYewdiklmWHEXFOFo8NWwLKKQPi/rSQHcJy1o4WBiXV5UOYJ2b
+50DAF52281ao7BZhYTt5JKy+KYvP9Znkk/Kklx79SHx/bSrXHZJCLoVJaWRFp332
+vQASx042mXMeNDPy7dC9NP3eSyv/niIUWI4t+ktUds1OmWIAMs+2gQqD0Eq7gAfu
+i8SKjiAXPADx57dg7loU0O9IyErJpY4HrvDLLMQaxLLpJxl3YSrgEVkrkEQvP0vv
+ktUR9qQbIJ3BGD3YuQ3cxAgKWaaZWdEJjKqalTYACS3mg/RHYAb0xnTUX7nkUch6
+D79p6fAhhWe9KG2f8tJVuHfUOnEBi1XR5755Vqt4xgUqMI82z4iqAU8ieBvYpy8G
+ImM=
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6jAcBgoqhkiG9w0BDAEDMA4ECBztmnlgZpEhAgIIAASCBMggv6vLTkuAj/y7
+wLaJLezGOWe1JyFmhxfn6FMMNIZruIYUdoVNpsUzeOhedtawTszOOLtDtprsqvNz
+/oDWQs2B+JqpLjalfRfkjJjtzkkeij3mVNZH69XPabO/QXnHxjeW/S0Ps5gsIpsf
+6+eklLo7LI+KgVMWVIdZ5bC0P/FFi+Bf+sI20NQN3RchJMT8lKcV+2PHZQIb7diJ
+UuYPf3GRg9XtBb0pXssAC8Do84y1kKYj8xil3g4oe27jn1wlQ0+c8DeqXrXAcnIk
+/tFAfvNyO8EMfaP74vlDC4aATXY1O8UEAStTothbtahFNpFfB/9UbvKG0ac0KC4x
+43Ftv1H3xtyn9vVA4qDCmLK0cNDFKCRo+A41kEE6AKYKctbthhC0GMoj69EYPMhE
+Yg9+1Ev+qI2l8jB9kGbN6YlAkM4bUDHT98fFeS/wrCnzxmmiDD/rsHzv6cdkNw0z
+G5F+Wvf3cT1sVGd6RexVydmfzjEeP/6z9Xr3oMqW2CVY9mHFlq2dBkR1LR8Kju+l
+vWspR2YjzggylL8CpCpeCWzd7O0Q3sni3onHFwEen9fQ0GxM9FS0bH7Ty0+gf0jm
+ZFxwcHnH1mMOS5W4yg00Ri8QDgvz4M9BT+HLu+yId4QwGQFlQqg2+tLKsm9mVAnP
+0Ew+dV90r7/cRUCV0kUmbYissi39OHw5sOs0GDMUiNck77E0paBnTb0s+UzBIdnq
+wy+ojiDxhANB8iabKnfF/9fJ6XB0pxUQkXmKfFJZqpVzEq7ZVQLFPfyjJhQD4vTE
+jOG3PdamAFOjiBBqtxbBF5s+pLZL3sZhStugqJ1l63E5tgMcJ8w0czifLjjUULtG
+8O4V58yAkuqu8ICyhXXOA7Bhmn/vymBIS5VmxvR6NZA9qK9XEh5it1ngNZt3oc/e
+vclArrVbev8Q+Jz6X6aAbTsDleihsRrugGkWeZCjkFIYPKlA58FKmfB7xRcvkpYn
+8iuI1DJCiT99mF0YUjEkKWsbShUElR4ok474SsXt5gHtCtykXrncAPtouYPnXRuY
+MS9pYhgtoMhNPXotZwMsj+YvoWJBbeBgc7WgxZkcxbum3I3ns3E0+RCz1gAI6u7F
+ZUfLogdk+Og/wbv7B5NRncRT2UnWfOyyxlGtxrwqXxaOyIF9007F+Xe8NbRO/EAH
+1yFMdL1jA40lacQdbxrVDQ1nVXRGL6l0O51zWC2E3HkZMclTdWp1yoV3F4r5EY7b
+OLjdZ3ip/vWuMcaHpkP1lp41Q00oZpxkfhq6hrw5agpv1o9OTUr260nmHALDZ6dy
+2qWNqyFYyDuSSGB7spbBeuLq30WuXNO7kLBW3Z1MGq2AmOimUR8r79OkMBkZzZol
+IHgfjedxE/1uOmU5vcEnW/rGrFavTu9BvjoDLVV7/5Gc9z/q8CQbYW/cK77qD8ZC
+J22oFudz2qjl377LRIjmbZp5FvU1fIPy29/7LnuB1b3xfYvFwk/6YSM2FlT57HIL
+PmAHNYzW+Uwst0khEkzcagqqMDERcD/2WKedXUDNwxAm5AU8v31FYLLjeZfkmeNj
+NVYXzstYWgLPtUhODf63pGuILuxQFth4YrdZitda3RRCFI2F8NVFTADbwQWKZUMg
+KSVe9u9LXFxPNijyRpk=
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE4zAcBgoqhkiG9w0BDAEBMA4ECMpfoO3NymimAgIIAASCBMG1ImpwNjYr+SIa
+FEBPpj57UpoC8FqFKe4bnFkYK+KVapykY/p6KRlo5GyZZHycWbLhQ6LDwCgsgPcp
+x/BTghqMvztLDtO+jIaEqcudX/dp0VhDZazeFJ3hYhjgmPCfTSEBYXAKmtdEPCri
+eRqO1FLw8rAX+n1dJg0wnPly6M8kY4KE331G87+IAynsbieaAVkVAFm4T5+kqLXz
+dC36WzcrpaXln15ydp4Ok7i0/TLcTCfVh5zGvlujKrogJ4EJyFzThyByrRWYAx+H
+3RdtjgL3zoMs7s8qXDVcmActX+PCdDz8w4lqkuG362TTdewDnEc3PQNJPjzWWhWk
+QZ1vbUa2lszxAnBSxHMEs0pvXy4Owboh/FCRJ+0kpZrnEzdNumn9jWWkFxkhZeZU
+BD1QHEyuVN4ZzG4Vr28uZham74RQOHZwv3hiLMKXC0K8A4VSfnWZGGXaa39J58N4
+LpPwORBJOv5haLzi1VZj/IzfN6oc5PnCS51+MYOFcLYf/2qvoQbB6SNw9PxpNf4E
+cgPxXMYJQcgSf2uDJwjsRLmAe8ChD2xvo357fhDZ/y+j4viB8pzKhX9uG16c1Wbo
+7BHnXdqrcbgeNgk4s9elWSr1kKb0gTSkqIRh42s4d51Zrb6qQjgwM0UfydfWyMu4
+y1acFtQPicFoIfvrKxnHEjwDLW3nOhxGL3ORL42U8ICJl8XzLRLYKMQnH6k/Idod
+thZO6v0habuoPp0ozYml77BmmFkdSoR9CZKweoA5Xb9KjeLGIoQk0Kg9Roxw/KV6
+3EBLrP6HLTex/QhhribaHUoz9i9tWKKWGwOl9JXeV/BM3P+JmW05h5LY4THBG68w
+7P+kFvmUAXl4SOd7AVMQCJeUKIbif+Wr7UnRM/G3lJtg3VSp3IkINW2WuUgfWSVw
+T/OUObFOKRZUKqEmPd3HYvlguVJM76jQ0uVi9XiEJtpNVo7UJWw5dk+V8obANxcu
+qNldaXJCDspJe9Ep0NqkfQIuXMZGQo3hcbirH0y3HlBBXdE40Oc6WA0fu/L2D/Ff
+sYCEaGZ0mBOuOi9CP9HailwAEL8Bf/3LsYBLSqKR1vjSC8n2bfD+Sy598QQ8Ti7C
+7XpuKBCAws+cVUnMQVuqckuEm454tQxlWNnmTqoKnIwlEw7atE3Fi7xd0Yk3xO2Z
+m/1+jLMfvUsYr9uYFWYt0SV7GTOHyfc9HWFb8Mtz9XvlA7RQ3gx5hNoovJeeK3Ho
+3f6h8S0BYFWOOvKXk27ZF9OgEqeRryH+B1y32n6AtgeZspnOLPlMTgmvjvqYiocA
+4iaTAoX5PGZuNKRqBhfiCLUT2AI6Coq+LjRdHn1mwLqBnagJFYsaXcTjZNKUr47M
+7kbXX5JC12d1lcCxkTqkhV88SZhgvPzt9J/3Kvx6iOMRinWfxGGFQqiTFEwvk5zI
+64aA80Z/N0jkhiibbsl/quQqi9Tlvqd1wpHcJ28t25H0eKWfiktvuxWRNj86JzHk
+ZMKv1ReqWrihQyfwSG4nvMKaSJSlwuzbb7D5g71bMCHdj9ZddgsWdu93mR7xv8Ok
+tatasiU0x4bZvqaOk7qjgHJCsK0dQHsfF5kIQJ1eC0akqRP1KfDs/Jskefr6e/PX
+1hql/nLztg==
+-----END ENCRYPTED PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQowDgQI3TbGvnzF0LACAggABIIEyLCaObV7h//eWCwg
+detit/l8jaBe2pHs/JPd1qJjnvAjqnSBVQjkbXjxU6ERAXC2IhQzF4ZlW29RrdLC
+ocxhHHM1Pt2+E2T+wiALFYidQIfawiobru3Tb8FN0QaFoyVZgUHzxeZUdot2ceW5
+TrP3PaNSWTnPl2boYy/TBlbw3W5QvmApHvA5RFR0uVqO6kASCPmThVTrutPVPsRo
+Z5QZCTgZWrPXzQmyUzF5z0uBY2i2jWDwZWso63UZh3A+7Au7hn/NAqKNDeN+TZqc
+nniJXD8PTJ8eNtrwk758lhbbrh7orAzy85e+WmHnmVWuZ88kULBiDdUFu+uUNaqD
+gukACGRDe0tGEq/CFKJVkSDvKPKrnBLHo4uBootK+Chj5iY8KMVVJ/IWGjgYL7Bo
+R5zZYos6qubuzfycRCWXHnR5cp3qqgO6oRubRXvWaYuOx5gf/trCK7dDVptYHSzB
+dK5CtlgOQY9mVM6THkgzPNKlaoaWXcAz2YdROMkqEvhGHWTnREuDRmqlsCQKSDkS
+ljyBFHVLEGFrqChnZmIi5x8M8rMQHTjQYYPatIUEr10suWz9So2fSNtrlbzXrk4c
+rQR3XFedszYSCoBVofW4Nt5iSdRldkYh+DGuKG40UKltCfu3EYl3xKgf6VB0quqI
+l6CjQY/XlDirwLVOE0zPTqKeMGsi4UW6Tecri07/48JWBZtYPLEj7LWTG59GmLPl
+LFMZd8JO0au/8UESxFBIg8lBVjGpNV8F3YdI0x/inZFaESKJqK3eNccBMSCIZVxY
++gE/8iNIn/bBGFWGxpJSVAjaGMjXnkRtYCcriTKchvWq8gljhRpTt8y/hEvHzmaM
+rUbY6jJyAJ9Jeso3nzpBetDUImZ89iN9LC6Znz0g2ot1iLEL9Lvtnayn4Aik6wfA
+Ha7R8qy8JjCpSJtV8/COtRrzbzcuZw5I3Hsm3cTCERP1zmNZbm0MFM7WJVMdXPUi
+1OS+vwlUvXt12dfxtABJG+wbsTQ9lPVGph+aixG1QvZVTq7eq0MWo+dJRev2656a
+5VcdmtVo1YiNCG2TniZjcIugksxbjwRdmOaxei7VPn0GuD+4oi5fon8IlpjosJJW
+FEc17IO7rqidXmeFttnnPLooAO5wajNVdAyuCs3HKJsnVLXZK42doWnNm7k+/uca
+K+ai0RHyQLqWfxcU2U78cVVhdgnmFU/9d/+gHhTfhzpCW029NlIgNuQTgU+mAiug
+27Mbrm2Q2f69SNXwWgKw2h6MfMsQxDNZI0vqbA6gvcmkwgbCrrZJr1rSl7dZaZuI
+ek7l/yG/dqyzUWKcHko6jL2OM16cKkVWTRv7o7Au8RrLA2G7BA+FpHt9ZnthzX6K
+LMPr6an9LMwjvnxD15YfENWphVqx7r0VYQnL3AfEinuJ9K4jyGZ1nny35jUHg1tF
+XQbVIBfxoMuSLUjDep9E+iyfL5Qogh2hlZ8HuXcRXb44BucBlwruDuJm8Ft6Q84k
++pw93biUrfEm/7SXIjC5+Daf+49fCrJbMQjfGUAxRxB63qkEtNo5AbLZMlujQxFt
+ByA2F5l6hq5cT97uCDPcYdW+QRr7Q+rFVy8sqxtp3K/D1LHX752yRqBl+pnf1tJA
+Dud9ALqr+fQhxbd3Hw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes128_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_cbc.pem
new file mode 100644
index 000000000..e31505333
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,8DA91D5A71988E3D4431D9C2C009F249
+
+ZUo4tso7YF0+ayrQpLsgM4TN2H31b5g5ryj//QqqVG/WmvYgl56Vu7fDbYXytgnb
+PQoJLo+8iUI1d51nirw3RrtAx7Z9lrBu6mX+JBE7nwCVsjBVVlAx1B6d6Jwc20wj
+935VaUkwT3n0zZ1dwb9HLjEGUp82TIbiZ3KjWKnfER2AhFXJl3SzswA5Fvwe0AYm
+KTAEYaaxigTTPgltiEQDIvA/Pnh9ZHjh6rbM816Fa2hdk30wjU4U/KkTYbg4hdoV
+vLeQpYnMT2uICCuvNXq0cXXetfbgdMFsLTxvVElUZrjyMTsw1QtjijeM+gj1dbDj
+HGzR0k97Xj3q+84m+SoNW29zPLZzSaFDX4KdKKG2cHs9BTYJmzb0h7qP4pCXjGgF
+8V2iUDMs7BQlgNnOa9gwT7x7DN4HM6J0MIlNIiYQZnupqqYQTDR0rd+fhdIsXHkA
+qNZKI/4ep7voVIufSS8ZyoISES3f7dvs5nnM2C+QAtL+l/yaaqRdfUyn9BL1djaP
+akSRPXmHrmed8s8YamuhLHyf+GPL2uYpd4i1voA2KKYSx4PnfjH/F/8fXPZr3dNh
+sDtcjhgXHTNAEVVek9VOaHtlUNZEY0UcbP5uqBZta+wP2rBTC94DxIbN+k8A2SlP
+cKGkaRltjnPJAXWmwKMRm1J7vXngXYq0r5VUvnGPiUhFlQwAW5TUml4+1SMEUirZ
+y/Oh3AjhOus67uiAXAQoqlr9KykueXobFrhZjLCgRf7iDmP/t1eK40UyV83w85yz
+cORi8FNfqvCARz05qXwfhf2NBMTRbLNzKCGjS4iY0dLNk+QYNgJGoM4nFVkHYgbM
+pTThzpYgtRnxQf1mYTZFtqr8hRJqiRfexzCyk2JC3rDtEO8WUmNdvdKNN0KwCd4+
+dcVS8KzNov9fYMqiiol0dL89WBN1RN+hs7HnOJkNZZgaNVspOLCT4+SN5fLgtbJI
+BzbAgTK1ILrSom5fyzZcRkYwzIqNc97YhRYnxDp7vJFlgsBqySJgtdGUkTPrrzAO
+CCYyi/ukSVphPe+qRsvj9L4syZgpLRgDdZaW+BR0pbTUg2WQvZuKL5iMhfB8cbAC
++FjoKeSlxI68jukrAYHBNcco+qaAYrUaHsJFUsbf7j85DzHxnaA3M+P0i+LWJwOI
+3G751QR2CrjgK+QD7XUtUjBMrsVGlJmfaQsEm7+rtuPynXq+ArJrvgha4lc0GRD6
+yNDCTTMafuBnJ72wop1UEE8zGOsqERsgvOAL10J1s5KCcPHGwrDhjhr3/x1GI6/e
+H80zp/E9mPgzYQMfhl06s9SwyvsxFCIZAfrKIhq7lVqeEDiusYbe15kCLmTVNZ6C
+c/BhDc76vwek05AOLaZLGbdpMRwevbOn4WvUHV0o5Yr1h1IGZKx9BQYwFS65SDCg
+uxfM+dKulE6MWD2hPUP9s47+R812cBnHu5BVV+Cq52YygAiAP1+nfFw7TBKzqczo
+fnIsoL69JthqtkZiwl36uMmcoWwZM621ZqYFJI53WO57uhW0uuoyidQj8HoNG/re
+o3OyAgVO6sTFsw/Dwxo4WX2AKuIt9W2IJMFNC7aS7lH0iPrtiVC3FFXvuY5agipH
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes128_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_cfb.pem
new file mode 100644
index 000000000..8bd32ace1
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CFB,2F7AF90B0C0A420FFD62214EBEFC4CD5
+
+hciElffC9lqjzOx+aBT3DYY0/oZrI0Q34xfQg7IOTUPUAxrrT/UjHlToX56VIbRm
+PH2M5yoF88Ji7BI2V/Y2QRAjAYRFVjZvPO9ke4IGYI8xfnKRivfxLtW/YfaiKnqc
+7VyyO2UI2tYGm27+JJbGLR+GdaHmcnLmencGdS4Hn3KDQ9IK4eLLXrBPWyzGnxEZ
+qA2OWdzqodjppFCjlx892YJUsq+w3BXu5lkPoooTEoxB5RywZfngUY9Y+raN60S6
+zhjkaaJTEqAfnAsdVMUvzpkYpoH5LCO1vl4+XpKdeUu3wJ5p3D9TVc4kt6/V/MeL
+rHJVN8FKJKYddTlaP7xOmh4bivrJao6LzRUdnyxGL6SkVQ4ipitgWcSwFGgRQc1m
+/MzFmTATtC8tocSqXMY8nblp0/sabGhUSTGG+uBGddDr16D/8J5rb8cMCfR0KLPF
+3uwV89PbbqpS73IUKkolRjxslO74TPDT5ds0i+UV+J+AJM+9CnyY7WI3FgMlVvRn
+KwYJuihDzFjozJfe386XWYs2Joa3Eo0vbaVvp4hbHq5Gh7S2iiBpqy2uN0xxuZA9
+QB1XpLd+rOC0y5l1usuVc9kBlGsTiFVyBoZo/pWVlTU3z8Hzgv8p1TAJN6jgqVH7
+oMVgubXsz1XPHrrjjgZEEpxqzXtKJw3DKchGDfAn4VLTSrOINwMC5sR8l30OZVtD
+IdlmftUBhv2AeVUqkLsSMKGdeagfwoqOlfL4FKvSt4n8Vq+Hn9lY/S7n3cjM17YE
+YAgpBjX4PJqXsp8K5KmBHPQMB08jW+NQFABOprdes5bwflrERogdLZmQH4vxqUvs
+DFhHVJxo1wxeRDOftVgtxnmHzU+SaB9MgdWWhC/4pxx5uzqYi0Q2kSOZ27EXZNdh
+MgVX16W6jLUw9zaR1wJIJZU7SmhJOL1fxvt85RytaD28+JvPTNs2ffDpjPu0sXh9
+n0gYiWztuBNUv1m+LMpi1SPtHvtoZLhc++9g4BXoZevtgNl+FqvHs2Ob9w3yXqkT
+lyJQbqju674MaKXDoQ+3+tnXad8MRGCvIgmIUzmMZj3O7QcrBbDY/pbcxoEDOaKI
+SygvYvKfrBIKq6PuGsN1KHSMrjc2A4+wuTYy75xsai9YtwwT1tyIIeCv5NXbbtJq
+vW+nbSNYW+khIicBc+Ye+GFfUh2MXj+iC1lK+5i+1leKo4zLNFDmnXKgZ4jOOPMa
+FMYPZkwANQ6//tyP/qzLWGyBucIC/Ym9hUvi0HlYjjU3Z+Zv92vM+2+li4mtMy7M
+tdcm72bqsT3+1rtJKKRaYG/FiQizOGTDyhgV+JX9MEVwJPa+61V9jwkIPPR6iBrl
+u7NoFfSp666XbD+LurRh82vlS7KYOB2zimHFxI6nOHBsypJynqtgIzLg5N1+LhVz
+t+cxucW9eFvkEEXmjZwofqlxq9BDso587kKY+EpOkXrlnG/ha9XeZcyUipn+jQ0Q
+64Cb7LfvcU5UEXTcMh6BKkoeNP07O1ecpD1LXMGYFn2HsfYHigwwcZ7sm9oCCC9q
+vF/rjXg/oIMagmc6MZOjRE2eT9tpLRAaMynLiln7XS5u+Q8O3RexEw==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes128_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_ecb.pem
new file mode 100644
index 000000000..b6def0873
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-ECB,3E3ACDA483AAD613760CC55C7DBFE582
+
+PJupElZP0QC92uiYotAm/CG6i8ypU5SXxc3zmrk7sBdxVU9JQXsIE/oIUK40AlFW
+cGuHWxxYkdYNtTpuwG/CVlsrq20YfpxQrl525f4pz8ETWt/P5+aLQ0TemEKr+LVE
+921o6LNstZpftQJbe3yMz0cFTjSfsxsHbadfUZUQzobr1XcbazPyhr5rrSntgIMy
+rJ5M4G6QrOEAIHfVVZ1oizlFnd4vjGOKk1i6APgEEqJTIyFWoCXEzDtaMcl97GEI
+EWGusd8DJrqpJKnohVoTZdOzLrnerJXEUEJ0cz+UjvljAYg2MBSJk5v6HCp8aWcc
+CCoWUbJp2933n4nLBq7EXTVmJ1pwbB4cjNM1oL2BznW/pdznrSRcw8qut35ikEKW
+mB97+IMVr03orl0uFjHBIch6cPLYkXKi5w7CO4vvJeqqPK+mCtckzgIlzsdTL7Pp
+tp+wrMBtG2Ibh2HeJuvvlFCgoYBY482aPu/4NMei2eqfs0p5g0bf67R/BiG2Sxxr
+4o8hmR14v+dzLsQeoKrr3RnMqfmrbqgdkUfgBomlsunHUu9u7jB70TuYsZk/COPn
+SgMM0T1pxEuHdXfyZPSS9u2SFGEhbW4zIuVz79Lo7h3sKdYJqmwmgOk1P3IL/nra
+YpcacWzmV0g/GK8O+2CSGvEh1+m0ffQac1Pd2Abjzg9jghshsBTVTpkcFI0UfkIm
+gpP/hwLONl5a1KJn7u/ltFPdZkJ5CWPe0ZQ1mqjhDaPnc8j7iuFzUilsWITLRof0
+KHUDsAZSV7gZ5G/Lh6DGZdlwfkD4b+2GOPayQ44mr4p2hdOque6Z/LEXtOv+UvvF
+kR9azOu2RXVTiDLL4c/ntltS6laT/nCg0goMs5NAis+3cxKd7Uk/yXBAulwR6wmy
+MIZuSM4gk2pqbt6TJWIfxl4ZtPwp+jYIpMZc47XQ7w5m7YSquJzjilaj+IDVPkhF
+TWTMf+Ucb4duBD39HZjBWAoLkF487M8KDtcxL60uHuhVJsKyYsb8b20ukA++c6aH
+0VqU3NB8VXH7De3pA08G51P+XLurlLUUr118STaEd4r7GR8FddFmSh5x+PSuVXut
+D2p2W7pfvS8OTuaMF0PZo0KkUq/TbTpvMcTax+G0DgGJqFFhqxNur6WoJyYbQE0M
+nX8USnuJhS+BRNPEXc5i14dWmZEeE8i2KGm8RlL3KZfyrpBk2zwnGs+WM8xAlBSY
+KnGO6bLvRaUl+8IT1nKfY30HLr2tX+F0fEM9Tn443VgsXkYnMoaPDU0aW6+J0lLE
+lTeqJn8MPVRbU0Ss/0Q2PQLpayHrR+ly6yxJPOY6Nc1eLkhXoB1DwiGh5Mp7J6+V
+R5UL4nRr40hZy+35sH1lf/+1mY95Rb1hAYP9r5K9dAvqkdUMSPz8rtzb/4gevLi2
+rxB5XyOHM/qZL9ySpJWjFPBwOtJ/EJioRTvnG+/8jdxXWBiGKdkGLKV8k1z7gOee
+ewq2/8n4HnzMm5YKdTesy6LuaO5TaOAUe89Eo/CxPgdM5YnxSxRsxunrPR8JMLYI
+V6xyNRRHLOy2ffGdJZ3nqbSOxCNiHW+Glh5I2jyrKG5Bs0S1jbt3l0hZKWSU8k5k
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes128_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_ofb.pem
new file mode 100644
index 000000000..2986eb219
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes128_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-OFB,271025C313E6EFC0403320C73382F15B
+
+/L1xK2Hx7pYQBTuhHX1P/mkXqLAlbSSz58hL1E4oxsDJODiVH+ueTSKajA8+tbxG
+eBK4p0s5j1fp7SJ9m4QXBwvhCnis992H9kQws6U9gGFrofrYAniRFhX6yzvm86ee
+deQ2Pfcv+evGRPigkoeRSQGxSa40fJ+5cBs4G22cfrKabaEKxnLtQpqPG17JQ4/f
+LdrHz64IyJTgvV6LCzJxShO7vxwIXaA82HNR6Qp09WUXxLB1/pfQ8oQfZbTUkvWi
+CBdXWT42VZklPl7StNiAN9U85K/USIYkKG47CpJvWMYbWJ3Dt1EFiEFi/wmYTinv
+b2K0xUrVUKxAMfmVtr1wGSJA9P9AT0/sBO2vTn5ibXVVHibtAET+vGXLtpGqf89/
+RmcqNEFYxvLzoTyR2FONtVluAC2yk10cKHY/pzZwQyVfjcgMlbnrZz9Pp1Y6ntR5
+AfXpVR/qyYOaQ8BeMCXkfR79GPyCPV6txy3KE2mbajwamvL7eR0+0R3Q0lhVcWGp
+g91D1nbgVFkHGOugO+2yb8vLq9k7K84Za+TY9NCqCG6g0S46yAgZD2rqrAAO4UIf
+6+nno8TS41W5wmsdEarbRoIg7iIKaPKzEmRRurSdlj/s7MKHgQFoet/OdZuAQkV6
+FumyDmqekmPAgIIJEO2NdrWo87RWKCzc61Yl52qmWsqrJIHrPORMGdjdlLVxXXIE
+XZQot33Rx7/f0VZktYB5fWk08kjWQ0sKTDiHEp8Xobq/RDyMTm9TFIkeFm4rLkl6
+Zt2bzp7ssoKeYuJgpoRzUmGP83wgl+AaJZpupARdz5MlqXd5knuPTETFPaFIf98d
+r/sl/V4E1nh0x83HNOBrLlpKbeWocVV4zv22q4zemALPCOQKUPWulINQWAYiTPDA
+lBQhFRnJXSZYFUqFWpxjp3yIWCvTZd4wgX5IQpaJvG+ehRn0H4FR0hJukMG7Pn5y
+ye0M0XlvVYWfxhLRDK23iNkRzVIbIxZfxqaInpGvatcTHyb2vnVFateSGlXIk0wU
+GxgytnTGW2fZtCDOqeQxCL66nIkpqKhB2hJKaD5WIG7SUikjBblvVcN+gkj9IWML
+7LB7xjE+4cyt27Rt9QHuLchdgSScPnPTZhdX0iK1LVELlJQFx8WPZpfXwpQR/xz8
+tqAKOfyhOX2XxYYOoaNN+ffQ3mEnsVFx2uQOp7PvNjL06XdYP4p/AruzVnbqsDsG
+BIo+oo7PfepNw1jRxcmeoaMotIZ8Feq8H8QEARqQSnzRWAJZhV5D9ztmUtaeqyy4
+QDbgxBxdV0nLAWG7e54FMn5yJfjqq2pkBl69ZvR3N+F+L5/eWlEpalIoq2l8AffY
+gDxlGgp030MAyFYSLJNYj+UUwq8k5INaC0QKjARbBMblf0HOX4U6RBqrpzn2xyvU
+mlM6pTiO+mOpG9WLgQS9XTUk2te8n0vAVUTk4Camj94Vdl8JWFNsfJIgwE59hprg
+a3Pz4FosIcBbj1pYtlA9Lz3kIGe9U3z9rHeQHNxJ8agW8NKGvlzY/YBdb115UhnM
+WOVp5TkpF2MyE+TGWqXzwNo3GutaNVs5YO5nX3Mtx4ClRrsmQYVTMg==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes192_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_cbc.pem
new file mode 100644
index 000000000..b80686d8a
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,51C73DF9487965B976234C88321E3F30
+
+6yLkX7C2XTX5AE6KqWsB2Lmt+TMGsoHIH5BDl+o7Yjx7aBSzB9X9KPTsVoPmTCOg
++yhhV6am/yBImCdyuY8d9Q0A1kPIJTEkshgk5vc2KpW08blLCHSCjokEVbQ4TJDH
+bMtrEBVMU1g9KBTMuBpbu6MLVaFth2GTsqExX2gu7FB5EAKvEGhkmLudo1jKkgvR
+aiiyMd2CH2MTdatZtw5PrJmkhV/6RMZRKP8r9wkez8NN14ehmk5QDY2s/hj5uaEf
+xK0GXY6OcwoRo85PsOYhmOeFDqHKGRo9a0pPBy5ZaV4udj0QZekE1fziOxiPf6K8
+0BL50UUzQBW+3n0dIZbzlOiJQScQkjoxi0kc088FHXHf74VBoJUo6pckAu4OwpXW
+L4XLIGAr2Kv4OMiFSJOcaihyawE312B2URcAzVCO7skhTYHaC0fMYDJCGTc2D9rR
++V5tVfT1dG4xdB+p/b9TQyAu8PE10jT+tVNJqGsZRI8I3iOtyWsBcn4sQInpYFYU
+R/v2tgG4hDdq1beEY5N/ZaLsoSyFYZmwbzB+BVhPg0W/9s91/nYAQgOL6XrExQjF
+lZxS28ujAq1LDNzg0NDA2KsDGJF2TuST2stnxyvf23h8+KV2nZLOZXjhlVl/Nr5O
+WPm3gCmuPf8F6FPqM+zI4YBBRtvLRkXafUNuvc7PYVNiaPyuMh7I7U1EUUzTpkqi
+OI/YD4xv6DpDand/WEtLHaYfVYU6PAapLV0T28BoFITp/qxHYYnXVfhn4htSgiwW
+R1btcxWyNjsIedjb1LJ2EwEfuXqZmzDz51uDLBq3XQ/dbvDkDzfZR3O1KGaACxAT
+tAeAdnTnAVliWYQiJ7BHn4LTJZ0ERGL/R1xpQs4quki4WHtEBRRzP6BbmUYYhigO
+QwvTK9darP1Ev7miF5BkRnrzWqCQHNTlDB3i/RzIfIDChQbSZtrpZH/V/quPuPlO
+1353Q6D221UiChhw0+8GmIszbLwBkDq+Zr7/poUBAqHmTaA3LeiahACM55ATbg1+
+FKf0nvUL0SaEBAqFxSdQ1mnW83VCMlCE7Luh49BDl4/nufCdF+iv3cYRW2SDHPrU
+HELYYLz+b4QLl+XO2SgUYEkU9s1Z+eCKcVUXGzz6vZUsA8UwvYIy8b/1cz4Y5sZ4
+MLpEXnQRMwAjArh4fvmosAG+diC18H2asLWpUS5HBBrSb8lAqKPLl+n72SlZkFjE
+WP+qq3koz3EyJsjwH2qbpx5BLhTPcEVHl3DZ1eOQmCXcpSm/cqKp2MKQFubCC4rr
+nphTD8uYKCP3mJXB8vqIIO9ho7+GVlCHJdZGu+3bw1L89O6ZG6WClbY56eGz2xUn
+DBmikb9sppeYSs0eX+yQ9kjQRf/BGnRab2dSTGtDT7jp6cL+zWUUOawLHWS72XtN
+3XYSEvvAWPygwbBuAuw17pwPPmTXduRiJosR1lRk28FGsMwzbj4byXm77IO3vD80
+cyrAQ/bmSpvlmYEHvmRn9N7QT7SFANY4a03aBK2iuqZQUz/zeo3eyrJudBXIiwUz
+/ZRteBa6SQagqDsmfeuGCjgTFGVnutCokh9lajm9BZ1pZtCmHEDd7yz4Odx5CmxG
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes192_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_cfb.pem
new file mode 100644
index 000000000..00cbae570
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CFB,58F8574921C585278A50F7A2EA529595
+
+RQtPMTKDNttPq1R+DiwHrEK33FOfxK1Cst5x1jrDhXe5MObLhqbz4Ft2idjtG/vC
+pemznnZqQYKsuJl/Th6Ydsthkg7HH1pYLRstc/tWQTESa0RseHDtdw3e/Wxhm6DH
+pSqymOfRq8R7PQKPxboj9fjxeooWlA+RQxGdyRJ6gki6PljOD29C2hxZV4HuL2II
+tUn/cdzaGu6bCvpFDvDuFja3TRtIrHSbCq01uZg6XrFui7BuwJxxR5lERsauJ6RX
++lAvhwXqN4nsEQefvZc/GeTFzklsoJ+c3HJy7pN15nyfwNzmmH5EK7C4CdBJQymv
+MRwe9hY/LGXB5IFEgXvop9bh2qYk9tb/zb8aAHcLS9rwFsGOo+5+Yib3ds4GC5fx
+ILKH234g+hkhutao530kmWXFf7qup8lvTlBZueAWcIFdmBCsWjm8ejxQUZaPCqEY
+sZ1UMDw1HPX7/4TXdVNZWrxHisv0VWnhwJNflEcI/k/GR0/qUgkHnUPycWTtg0W2
+7ivs7D0EkIJy2OyFj5swWs+eqhsSDmd0BgGL0VduLB0voi1eU908Af3PllsTwf4D
+UaLFvOkllIbul+YweImT9TinmkWIFMZuNDR/PHjpbLN/39YkvSub6oS4LOgKEu1Y
+Xr779QOZHMcIP+PXoaxqOWls9hgI6M3PAH+gAjwF77OWIQIh8JZCibR6HWYcr/qo
+iFTzJGNN7P06s3IOek+YoHG1c0GoPsNungPOzthNnaAUcRyvZ1Yg8cy/nhrA8Eeo
+A4G/I241jr/Ex5jooykpeotV1/AMIF7qxFeTARQgObRi/fiR0r9rjaSMbOt4PlRv
+Ln0ZBqedtkkRBPRGO0VViSbUAUOq0oSb98FWqPFpcFl8tXRyqe9m/W2zACczZplz
+OySvRuASdKYpGk4DmMlQtS8wjzMYTesBx68OiZfw9W2nkH+Xapc4cH8hyb3+aXXb
+b53nbp59+mx4UwPOcrdzVHdKhDT3BjYrJTv9kHAY8yA4Nr08ZsO5tOeI7vF+bUKx
+kWu4AIEccB030iu87/xHXUEOBzsV6HzzT1TrZ5GKSh43vhRwoasYON2xlO6RuKCD
+Yv6GbcPd4lv2mv4lAaDXk5IThABHUL8yhqfwru4L43av5AwdslRKIvBM7UWrlXFe
+A/Hipy6jjcusGiOyH7WfWBFV2/f6NtX6lGuna03F/yMZcHI/HEK5RyhqOYOmcxfw
+A1eGKSqOnq9IJ6vXnF8PuRYKB9i8Ha0z5JmWkh/dX5dhTzwH6wOz4+bLgkgXBdhY
+jptSs5zsvrxGiLCbENPTjArsBbT5NISh+VTrrUtmA5BLPWx6d4NNJ5eBXTnpOIJr
+rxA0halZtFYKj0mp1ZgnVylHC45QDiwzDnhXra83RVrcgQjcX4npjKOaYZRQ5cKR
+2F1QdvoLvE9YqhjH0QFQWMWfvmLHGIDIDkSB6EyFsgzWdv6kIaiYsmdir5FzE8c5
+SvHvu28j1X4OL62AquOFKMXQVns1/jLp0KERx1EhrQChHUxpA/cbqNJbhjHoRQK6
+0zXWP9gNlyrSIKY4egyQmjcTDvNXVcSDu2o7EfnprNCYirFgsAbw5A==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes192_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_ecb.pem
new file mode 100644
index 000000000..106704e94
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-ECB,A3A4C4B92548B906A635B84B3D67591E
+
+E4I7KvCs0qknDw8D9ISQev5oQCNiHskfB/SvuKJ/qJoJP52qk+ajN9pNMp+011R+
+MRaMlK7tANTrQ0L/Yc6QNUZW2aHyiex0aoC4ien4ojgvqHfaP12dMxFhOoLctN+N
+zrAPSuQg2OEBiWxEoDqpgA7FTUbxPiJ3QdtwwOXS5kqAKIEIoNnCPCL+45uKBrP8
+encSI+nrZIXLFqGEukKZuFH9qzdF2leOKSmEW1kmwxMOfQLMVQMJyVzd19cCxU/1
+FZtPRRIzFlx4PlNYLKDpypSUavgo5V/o3UHk6vbP/Wd+Wy1ERwNliV7CTCCpOrBH
+qJezvhkbktiHQQ7+5zU0jsTzTlZcxATdm2ktyfEa5GKrCNfrmUYNwNSi8DC2Dn1x
+4z9r6OfKV3dKcSkgmFS3ZI97ZhrnMqpvo0h1kg8tuiboI9pPWp8OsLIvw5+jz707
+GLsl6hI0EX61YFc7bqeetnObgiaJMJxQJXHi0U+Z01GjZ+qgGb6USmQ1D8r34nuj
+4l88VYW4jBhxa/IFpzUoxIioKG58xQT+OK2Fi7BF/OJLQpj+3RA3YLqry0D+AOT+
+f+nDJepwrQ/CZtoQl53ssct+mDY0D1IU6u7ah9WdIuuptV7+WxutFfDpXsmErKcZ
+eILXaH5zK9iNVnVNQDmnVacjQt0x0Rm28wrjI5N7M8jGWKWi9PMLElx3BTo9EbON
+pJ6x6xshjmdCR3gOLo86CZGkoUM1eNGhJuihrl6HelcZxeFnuiNYnLb5hIaqDd1v
+NpFUQBRC6Q3jz85zIvVsiN2vIyak2OGDRs7r5dqb1x9QVz5tMjxuKe3t+rfX1FN1
+vCusACQQzOl6NdTgmm5Of+pMniOL/kRF78e7zva8vM1Qf31/z8wtq3gemt+pZstW
+WV/kRhIvY/p2Nm41TtltlctThbYquFTEy8gxhB/Cot2k7Z494+8UBVIn7SjsdDpU
+X+N24itXM9/sd1LHrXBSbBT5PzSBJFC5MS4Nt6qpvSKIRbyWINjUoTvbbUwoCo6g
+soYBPJR9KeAcQ8YdBOEXtFScq7c5ZPOGCj/+3p++Pk7yMmlxNPvs6HLjdHchjAYz
+jycK/uWYNLOwKS/AMxwi4R3i45pPgIRuwGdRyi17Z8kOKATdyQwScbPOShW9/066
+OA0rEORx3C9gMoKa9QYo3O9YLjA7NS1ERSY9c3X9anSgR7eSs+DLRwFiB3EHoCba
+ULqd3n7qBKgkQpVF60p34yKb3K8o5s0cIE7oAm3VdoI/O/RSs87rDmUbpuYzAA24
+mXRwBvPpwEhke5PoPeFIYmcWa4wUZOJWuF78U/tZw047vcLKgr60Z1s+DlQJvFXI
+tXkV3qS45f9UDaWQ15YNev9fq+x/1JDO1LjQ9AHANBjRQSzE9K6YpyIw/SZlbo1O
+xuFrE077EL3hrRNh00O2rtcrK53mAOKMX9D5xifIcN4/uD9AdwU24YvC44gij47m
+hSg5wz0RokMNGLKTXaJxJGs4+ZK8JWQs/Kf/V9j6j/i4iDWuy5Ra7+/dIU/Qy1ZW
+cc8Uo2ji4i2z+QyzbpbR/jBqO++lcV2byEVDy8Xp/0X2G9mY0ymIbm7ATTlzE2/b
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes192_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_ofb.pem
new file mode 100644
index 000000000..88dd91a78
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes192_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-OFB,9797077D8AC3052C37DE4D719CA8FC00
+
+SU3g1XmkcVhlJpQSWXdeHcHI8IQCQBg0oenT/35NKgWnFBlysqwGwl/pwgdDBmm4
+jLsPaE5Vanm4aqWv9DNhItOQokIbIkxF6qKeV3wNSNbTsSaG2LNphwMiLs9rw4G9
+3aFV+0THPLAy3BDTsB3NPuRqlOSVcwVrfaeMXQGhCOPGmsGDeczai1xH7eq1C1no
+KUqNMGdf8g1NuCmQnvswuTF9BCi6rIO0JRqLPTxoz/1emKfHhJFefpSj88zg3ucm
+cz6ZOAlsmWm1MQrktXd+odzpmjHtd1vNsgr4GSYUeVxxWQX4o8pVFqWqiQXii+HS
+ubtMARXAuFIGoM1RCMN8o7sJG00RbG7zNxfhHqe4wSkKgx3qEuusUDewXkDeYhHJ
+HGQCD1epByGHCZkLwBntccOqbCQoSNB0/PcFU6vJrtgVFl8N4VsNMRuLj2ZJ7uuL
+/EZ3qkLTk/Ek68++m2dtAdyj2KF1O4z2SFROSh7MCqWl2rYh4zZcBtGEfmQe5Pwz
++kPycc76ayzHO8Bjg6rl/16Ua5Wx7d6vy4Hg7JYb5eDmj2UGJ8p/z83KBdQnb1ku
+84ZjpYgmtjZ1vY8Z5iZqfZro9JBjWM4wFZIKNXcBniC7kBV9fRC5nzpjs6qWTPRb
+bd7PLMuyRZz9PO6cRuhqYlP5tYSGYYVhAMVutIqSrQVRDV8AnmblfPiOtT5lHC48
+GR/xPTIFxxVqsDmeyBzyXn9gzAJKgjTVCXNksXojM/ZMfDDvAF6m/Ntz/izp2CbI
+f2lcHgsm7SwVn2fvHikAugA9B6ixMCXygO0L5OEUDJW1e1fB7FMasjrwRorDsxsj
+JUNDW0KhUXWt/U8lNyfRm3oNUjQQU3x1iEymjQZV10ZO9DTn28fZOF70moUWnl0y
+ffELY1vLtLNP7Y5tcGNtJARSGnMUW99P7OKpLNXkhL8zE3DGEL1N+gDS1n81kzTH
+7hPjM6yR6gJQVsQrQmXrEpIlHQeGA99LYchzyVog14qMhvQItDlCsr5UIPwVwhMP
+LTA2LITZOYieRAqrv3vn+yFHYG4k9/C/xHwKHE/4pDw8bLn1o8thGv5ZW4yDsHGx
+n6F6vqJrkPW6vXkmwcgO5jK8JBbEpyzAPc6aSsibH3JF0ufsfs2hQ4bwb96OmU6v
+mukMLjQoi3BJC70Op1bpe7wtCELJw1oFvbZDoXLYsa3c06HK1M4rmzJQTIEBjqxd
+vs3g4L4CQ4RHAzlkjLrCF+wcBHt33586bDrt03qBEA7GSyAUu1NSM3UKjjM0OydG
+u8echgFIz6XetqDICHdN0r3ZWyICM/FgnVQhs39fCgafVJsy9C4p5jByUuDPvebP
++gvvVqkb+DGwfkKT3RUFAcYiNHdtIob3kmp8OJKTFk/nwdUwqUTEu3VFCmWog9ps
+oe/0KOL7j1Kn1xEFkOt5MdSFCcpbsYjQNi7F1gWAr1vMXDDPsSizsniGSvXZIYBt
+Pk5AH4MflqbHFofWClhGczSLi0FRiVPqWyudoU7LOesQhhN74Dn5IzkeAGtDL8r6
+4vC+G61PZdFXhLXQfOEL99hgJ2mjQP4rVqwdz143YE4/CUHmpq6d8g==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes256_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_cbc.pem
new file mode 100644
index 000000000..7b032036d
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,1876F5A50C9046D504D47B2BF8951875
+
+BAPOppBjFxMrMU+NI00PbmXXutKdPAiP+If8JqX5xGQDB9bSt5Q9R2QkaMx8Z94f
+trVbp82iERyPYnwcnA1Av+pcZhKi/mYFgDBPP+dDLp8qKRFAWil0zc0U2jkfo0U7
+v8cpO5+oipkJ9RtjaTg3/XmrwCUFZH4KA6G+SUFc4Oxj8/dzQ5YUDtJ5iyArRlnr
+v4nsvP4OvsI5UFYwp/T97ks0KSmo6YLMpJwUBwcleX2vOhX8fd3thk9I+EbVVt/f
++JztCTwr4EsLxWe4XVmit9AKfLU0AhmcA20j2YXE1VFvRJdyr+gOGPD2SDoRgiZH
+rRBhfi7cou3QmZ5d43jFYoYCBc98blEV07umH0DXMTL8XSrfWNIjZf8uQR3+ZbHt
+W60jVdhOCEb40KoRTHQAMBQdgVVkrbXCFyc9NeVzzhPqyKXElGxLBjRB9u0h15DV
+WCJUdc9UGuHzFpVFzpEaehdm/7vl+SZXUzAOgAQDtL+ATsvZglyMx5y2UA+5L1eZ
+grA6e3tQFdBcv8w+WgYW37oAY2VkHKjoHs1TnR8z1t+OpVovnpcklawybh9Avv5J
+kXyZGc+lbbb2gvUw33VeYR8yIE4zBoePuhTFM3K4NfkBbKavBBXMjQlsdRzlt48r
+RqdFnpYc1XB4ZLP2VparhG+Q1UueVML8uBcd5F6X/0u9n78LfIITwRUpVoaLXRzs
+94Us0pbzWFDxqxtqKPZHLAVJOYvEOwZD5Haw/bwho73EHEx38MY7mk9T5PonsBko
+7Op6aEmKK1qfpJ1aPvy74UmIlVDHu5WEMkYx7nQL67gnFXHY0yKjmP6dc2y3+nfR
+qNK95RTaS9VbACRS+re+P9+Z3aAsQGvj3MA+4Q+qlscUmb8uk+M7tg9ADk0VSe1u
+Ts2x7UZroI61c+WzgsQzMAwm2QLPoKQcvv2b+iGD82enAtleTTHL9rkoS+KmNNU6
+hWL+AJ7HP9s/5+FJ7/4CD84pcLECXQ+f185vvE42TfdZmoq6NgSKrGVZPLxYnyjO
+qa2sTRzImZrXPtsnFEL9OBflWA+ZHaAGo4HJNxZW4Z90HJlAZN3isSZnE3jPToKP
+YFdHsPv5m/KpNa5luh4L3K41QWzLmPlRR0aygWM7/0fYkgxI8PnBeCp4OjoK6qHx
+VYTWMKJQTLyji3YwMr4CufFAVty3InUZzm+ALMFHqEORB6JqPTR9mtnR145FHtxE
+1z0LnEoDFEdGuLjtC57yR+lYS/vgMbtj4EqQ2zK93JaXvI2HxxOiZCZEDww262Bx
+QZo0vBoAd5vkMKmz5eAMpRVkguF1wN1RPvao7I2auJIHp/3zoaUowpZgtbmDHZFA
+Kddfc927GQRxtUH3QQVe1R6FFAa7JBHNeJsBvZu3bj3l/7BATzcne5OPhjZ/t8Sl
+hMqEBZuo0svrEc0w+e8dpbPEjuj8UwBmHYZWlALby5N+YJ1NEtLYmyHe2PFNXwK0
+2fo45CCSyl7YJrHD1ONJ0M804ML4nMwmYq6fOAaV9ufQBFqQQj/hyyE93blB8f2E
+I8LMN/SUKN06YU0nErN0PRdm7CkrS+kutn/Pz2H4oSbUZ67z4Ee1tpnVQjoDYdQU
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes256_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_cfb.pem
new file mode 100644
index 000000000..a616b68fd
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CFB,37639E4753C0E4CD43EEDEEA18AA66D7
+
+HKuYoKfUqTRf4sW12EzTuIFK5J1FkeJAD+ajYnKeKYneNiDbmDlQv0kIk12qBv6l
+LA0oBH62QKjUDKi/sg8NAO5CqYkN2ZB0gQurTgGT/jrvMkkkkwE0x1n69bGNScCN
+mkqMnAnjQqbo1xERzwqX5OWNTTb4iDLiPyjiUlQDONl14pe4x6zGpVziCVCQh8Q6
+rAPDryZBg/wQtPXNhNpk8MiTiSwe03wq10QP6W5TmUIKp3kD4OVfBxpW1N4znyIu
+unJDVcRdBf6XA+aL7plAsETL6F9Tx3Mxm5GaeaJcSOWWzKMvqYhAcEYwM01lx0w8
+LMMRUogny67ZqaLywXZWH6FCJGCnJK5oaJE+jlnKZ6xhbwAxMyxWRCZC9pF22ocI
+3IY602+shDOWZQDoihhddwPJejh+o3mVFEglco3YEByL7Cy6GvqxhctEEH7uKvlQ
+gXGb7srmOpeHHfP76N9afF2hn0mqyToakdZqgnlgT2jm4UDHJ1vQ+onIksV56I07
+tVMEmPhXQCIHhfKdzEgI/v8CiLL3W/g8r+20/5qyKCL5vPBLAxmRudYKbGkhm5pq
+GkzaSp1cKe4ipUfVc5OEUikOMCuadal0TUQZ+h658aBCxLWHNPdZCzNdY/bZLN9z
+XPhAzml/H6VOZyIxb9hm+FNESvqNKdlU2NaE7HW0ILKaDif7gsZhvogP4qNDp2P9
+xPANQh9UxpA16AUTUNOqk78t9aQVpbjZfAeGmcw6AxJ77uK649JgkEnKqcuxcDSi
+zn/8NGeaKow/bTW6jJJj7b4cMys32uxRjeeeClC0moQiy28OIJpRRCRJIs7Muka+
+dMBoNyftBnCONH+oqj+F5au3QPMwKH4v/4VpO3hcByXcqxegH+BPEZzzYJ1OnI3u
+dh9VlpTdC/CD+Gn3ZRqYbguSaqow1ZF+nlpD0xcs0IQjNEe2BVR7CULUFVXIgF44
+pTv96/LvbG1J9b0VuBr+iIp30FG9azd2xyn4O3lW2xk1uzvo/Wf1vDGvT6AYyXNG
+DQS1dGtIm3+sy975sNTlba5gWgh0YNHjeiQq19I6ZzLFhkvLKfh7zpx+R53YcqSY
+lXj62N0u2s4KUygqg14oiIUoEnNr+n7Pq0es/gYs34mY/KvlqA8Prax91BaoqqLW
+qHN5bEv90KdKaJlvdWsCUjA3wReeaQa+U737GMXaON9/oOJ02bWC8/OIzUPgfGRH
+v/8YL7kMnTd+Col0f+XxnebWSfJsAzT7mjfly+An9EjccTeiOon8submd+L8WySK
+lVvWzBD3l4HKjQkr/3/YtmpuymVZyeTzngVuSdw+iXWPmOOuXHyjyD2Htn5iNWch
+Zlw37a5sHhiFtpNZtOnhpmDbX9sgt68KJMB/E9Mh3JuWCaKZZ3Cv/22KA4KQRlNB
+FSvDDKJBrM1m599A6GPJisR+iC7g7asJQ8hI1OqaY69v8nP0Fo+Qk8+Ac1L/n/Vm
+RjksignkKjvqgWENNn5Bf9A9+zZrLLu9wJJLae7wIiw4UgsNob68sGjWdLyg+tab
+QTxd15H5VUIuD6pkeAI2qC+0sSw9V6LKm6pmEIIbp188CzApcsGBXA==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes256_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_ecb.pem
new file mode 100644
index 000000000..f679d6dcd
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-ECB,C5DF56EE3F83A1F8C1AC805EA73D4D24
+
+ac22chm8+bxXpppAKfsrFJwCY0S4VPnXmFRqlAPZRuqBH9ylFcG+F8TuHdIsLeof
+q6s8yxkXa8y+/3hyqIZeMwN5Ai1Cas4P1iMwEtMUCMeaip5t0nf+yeCyx433hDSW
+dVnsdeuiFCiBUPUXfp6dCGO9kOLUEwu4wM4lIJkJ4QVyauO0/DwObQ6s6xEMFvQH
+GF1AFFTfW39CpZuS1rguG4hTxW6aNxjEaSKHJnzWu+kduMLJEaLUiL5+i/tUw937
+V8DhGdWU//1Q6KKLMr+5w0k9i/FhVxAGJZoZ5j79ToYORGr4jpkDPOvHaCydM6Iv
+JH0epC0wfG8L/dArNGLEftTpVVlvqHMpAlc0Rgvn+LtqstfyWFXqbQ90NBxC5Fs5
+xiGxKFGpkX4stoKIaOvFVw/hoCI/oxs8Eihz8u4QjBsl/3TdYQ6AUyfBGEWImy/y
+hh+QKCVOfzAmVGcffXYf7fvZETVgpo6tynxKVlSRXO9ZuzANJCC8jkUEOjc7jSKl
+jyMKQMNnQxyplgaFxnWIfs/snvlLQW8DlpMPH8xSkHkUgLKMWrSLB9Cisv0N7V5t
+Zl7Xxm3tOteLG73JxJKJkSZ9djlhkPvlvS///mvLQc6jse8EzY8peQMI1pYQu87U
+CvHVDOYn56SFVJmo2koER8FG8a1910NqdCKpNkzjqTl1Qbz7Z2VwghTslM7sUA2L
+AJP6PgdCkiGbi3oU8moPy3Nyg908j/17Bj9VyCXiegMAOxI6Kefim5Nn/sq+2/7Z
+MHIucQX6ka8KjEp9jvf7jvNC5WYxJkKIl+yzwAzqRQ395Lp1sun6jPfngnPQmkXY
+toeOeFvKlxaQu3QgNY7Hq9wwGbK/uo+rLK+Jbnt/75w7x5aGHQF3kf36epr3O/0l
+MyZPPx6sLblYcNQhBV8rnSey1WeO6105h61xTXdKV6To/m+RDZYvt+qs4z5SNQlj
+oKTezoQUh4J4QMg0EPhghyCS+/+cPMdnVnwX6Ds6nD2feX2CpN27xieGEp5ZhioG
+qWi6/59B38kBW2e60eQyL5f53bhWvywBg3HeUsXCD0ujtXBqPMuNnO6FU+/5Ohg5
+BAJ/bXaWiOkobmppBeaViidGv3NytL48ZIuQ1PZsYQajFb/k1SkyLebmeC2NYdO8
+VBWxAz5glgIKP11K9DJMD3n6PVl+ZyvlYZUGXjfUhOxHKVmNDHv2o5Pv8jf3WEhs
+yuWEoRECvfNlkDrmda0MxMhEYjeTysbxeX6fvwD2InzuFKhfzwh49p5LdZLurEm8
+DI8KBIXUx8g3svArJRvbVLyW0deMlXBY7h8Yc/2y7c5qBwfYrYhgazxVBfRqS3lt
+EsO2sa0V0GaGhPh7LUt+n1qDDYmaOfxOdpZoSLm/surciEQIQVNXt264YuFJS+ot
+vHWWVHzS1AZIgizu7NHRVeUmu4XEgT8vRsJYeogyG9o3U27L/lF1L5ysvYQjtvkd
+q5idZxCnY5RctE2wa5gjxPjmgbt1sUN23KOiPyz2cmXGBh/dwqEhIV6j7+WeS4/r
+SFBZBeGRHi8tACblT/6G9UB6FcycyD3hf317Zb3jXZLve17ozwRZRQ8aBkz07+iy
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_aes256_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_ofb.pem
new file mode 100644
index 000000000..34ed53b55
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_aes256_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-OFB,E6AB8D4FECB44185E26505049A97B0D6
+
+Fg8Nq9CxyVZmBNEiN9vBI+gsZL4lvWqCPaR5E+Po7acLxYGos4zIcmLCBa2X8lvM
+UInn087k98OAClm+0PvhZ64/AdDE952UclD/xiNvQCH25HGQy7wk/BxuOM5/FT0S
+rlV6RGMibelHpnv+yploYoHD8CSo77N4RHdEuepPwod2fGTKu5Cbbt1FBGU5LXWJ
+BrDMOlSN8P/rD5ePADhDsYnh86g4cBVHTb3MkrteLa0m1Szt47E6d3s+Ued8Cg5S
+7tiJOTFnXkmG87LsLZ0HDp6yML3g2gpTL/1Zhn9zS9lZc3cnkBfRJmttLBPjVCiB
+mStjlXnuJTDBdgQhJPJ4+2xJiR/ucFbCnUF/VICsl0hdz2Hd0PCOdhzj6U3jbRk4
+uI2sv5TV/E+e/Ppvdh2W8LISSBdIwp9CJf3se8RFz1dUXwTMGM50LKr/dpvy3T4m
+NMO/Cf/LyA7HBFJxjqf++wi5LPDXzROm1QHncvXNUjypNPND3RhP53pMeQ/Ffd04
+dw29zrmbyQKQOOac5Ss9Lj33Q/WzBgw5UxxxMxwRVDyfFpdz6JRfMrnj2c97auLI
+RI3euI9A9yRNxneBKTobS0EjYyqAiU6b5MbNwrybqvavbA/+ZMEg9Ylg7vtBOXpW
+YLLYFYPhWNEambOfNJi4tHcX8znGACxO/W7v3Ir+QFhw2IzSvntcMODKGaNKMGys
+HJ6mqKbmYidjhtKen1qHB5u2bukaGWUj2kjkv7jjuDK3ExsvB2PjEV5d0foPEwW7
+9QQeKc5pY4tOxFVA4qCq1tTzUhWr0mBkPhnFjc7XOLbu0sHYdr6ArZ3SadaNT12w
+LG2yg5r8BgmaUVTTQAzIiHhAQYZoCHAq+ohNocIikIh7lPE58DL2GPpEdXZsgzTi
+T+EUSkSw4VtIMmnWw5GNE3zCOxvx5qzhKiXVcnB+2+IF3nlHkQqFXcYNGhezZjnJ
+4FlR4FPzumRmMj1x0zmdbp7eTFpipUpKqJtC8iuea29pEl8opXDNhvmpmrT4/429
+7x8eJOjZhm8WL1dVpV2/Ikc9boEsYzHcBkY7kuaTqT8I9tdQ08ODo8UE5aReaFuZ
+vlBY4J+A4lltQ7qQ+sAk6gUMvlY8h/9L9gZiGbLe438Ndizskuwy+jAZAEx0f0cK
+YnTsZxBHPkWQXgBHMhe3BAAA+CZaXPps0SjD0yMQs7lkAgag6zBXW2vqttoJLU9R
+f6uP+BLwZCFDF1NtkROLV1oROnaGvMbHWcar2tw5qNe3BAsPQqGk8XnqwILz4IwX
+MN6QrjzbBC2jcL5jsxPZ/Tis9+wfI3t1Ke0EljYqA9RVWuC2KtRK+X3xOK6tWEK+
+QlagHRDI0Z0u0slCLjpB/ev9Ajqwlr0h25T5ucdsLd3FFEKZbzspdfsJuOXPM5la
+Uv9gpYIcuFrKcVbvuBPzt6NX/rp9gozZv7ZOnujjor6RDorHsfbgbEfcerydvJGu
+PRk788TkAB0LOE2wD2J2UO8+Ufp1qK9GWmtr0WFCazqFfeiorTh71iS7pwUt08so
+0BRkqfrfP6pXEcnh4p+LKh+dnbgIBD+KH0qHsyc0ci43byoOSDDHnQ==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cbc.pem
new file mode 100644
index 000000000..e3f6e2443
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CBC,E59962EBB3DD3C74
+
+1FpslA4+P9E8HcUUGpkIMWeZYV2XxCgOiSgCe2NAUiutcRkVAg9nPbzwnsQTbckx
+d5uOE/w53BURpxPkz3nNcike0sr3fa/MzaoRUDo0P4MU5bmAihjnZqhRllqvw4Zt
+BsyxjHVn54RaqZC4RNQUqwIHYZwJmHUi7Zk3+Sw7fivMZBr/AWqa66I2hk20+obB
+y5ubRjtjw6uaciPLIoMZksxoEwi5xv4KnQHAQnaihQ558RPpUwweqHXyOZPEC1Kx
+gNQPrTGc4Zm+CKqR4CceACSYzcYtechZpSQqn61emmtyhowDqXpqqjG2nimNihcI
+hbp5O+O3fKZFkJllB20xuaj0rK1NFF4aLiS3BK6aWeCZ6aXFawSvbQb6vGx+pQmP
+eQemfllRXXkT43CHUmMTaf6gKnz5DaxDBqdVP73dBa6UoWnxTrZcUNKiPUCvB3g1
+ciJePjBnsijb2Bh6jIwr7yghIbS65AYE/0V+5Duw360Fa1OqJkMuz5pKeJIUcYEZ
+3yuI22CZeorkvymKhrt1hUn5xLIKRZkWg7UbXG1WXCrGtPdJ+CxnwupHMdL8iMLi
+1haNeJ3E/PeMjehQRzSEEFwDljn/b1JtoWsEwnQPTPKY3505OWIhYRwRXLEo5n1y
+QEfktZ9UtIsJcIpfi7hMvbpp/7Njlu2MJKZ/1ZtvwVLoaXFTSivqcAkDdP7u5enb
+OJ4EaDWrRXS3Zj31fpYTV5p0fRaejFPevRNnYvMLRiSoFobd5MUrKjxpxPRCLiW7
+24BF9QY7C2Nso9yR7gNkzLw5x/725lGxa2ZD16nJmiECOaEB8ORVlilmjX2OQi66
+hpGVtjHMaoGr5IvBrtc7Q9aM0bdoFZD5I2mOm0hniNHG9es2IMByHWRAQFzOOLGH
+IFoIyW3OIuzK3cz8lMLsh/Hlbzo/3bpX0rbrn1XZULWAJ1oNzRJRi6a3Sw2YoIMh
+656IJB/fGRbG9CMVMl0T7onDUhZYLA/mV+xy2CjkQdPBjFpQUTn5YHu6zMU7gejo
+YSV/4esuUfhogLiqw7sPuCDqLL2UftN29xloQDTY6MlrkFb9jCciAwn02DAmsN4h
+7Utus3Z2N7gJnxt1dRecqr2o/agIINm3tMh0LK3/CydmlthZQNpsxMD7IqaWFfQR
+Uq7zQUfYZi0l2J6iy6FUHUokskqwgiNhMP2Z+uZ1xHUnoP7E0IZMHnVWEKBIQZ0d
+ddDucux1jOBlMwLqom3jYPjPkxoeSU2E0ozVNSOqsPnoKkz2qKnEHhea2sAPg4eX
+lsZ9ENQyQMZVapjic41BU/32pbrE/+JkK2Cc+dcLlrnHo+JpFeTdbleJhZ2JgXHW
+8r04vZHA7tQOc0KNR522Niu7dvOW302lwmfp7D5xfon62/AxVhos1DSZuNpVClm3
+V59lqeCBDm1yJwdM/946Eq45YJiTNTzYsPPFl25KNv+3+GKkhZ20GuLiaqprel3S
+MC5XbMJg4nc0LiAfDT/q1jO/EKZ5LzRRtkVvx1D8To6DAptyFoJSMKyFu79tQdfN
+371+sXEX1VjpEGxO2t/DUmuERIBdc9X7rPNOXSl31QxsXy4s73zcAhI94X8xrqYZ
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cfb.pem
new file mode 100644
index 000000000..b3581daaf
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CFB,A6C793D28C38F56A
+
+sjmmZGwl3qF65MFuXEtiTkltbaXuionUsMtzc/XzyPPaIxcdl/03iR5Fix0hTY2Y
+/W9BntQGcycH7uNcoYwOUScTRr2BJncyoDXZaUx/WOQ6cDHuhRWWwpLpmitfsn1B
+SRvLdKddL1GE2nfG2xhCdN4N7pVPUwIahHye1AkaSJ4gur8tU0++mJQTjDo63xKB
+oTh3mZB0OCnelXtoYFKGFXNh5ouAPZgcE84breDJBoGReH6f4elkigtSx/J2QhgN
+vXERboYz/HHhHSRCtMSp0qLEQo+uLcFxZcSMQE12eglOOucht877V5n5RMLFT/3c
+DeZdg6D1b52UzaSjTvLm/jJCdkYqZf4SFuBgLHF/rEALQ1vBqDiKQ7QxuWz5ApPm
+P0ntscETngWuJ2g2M1EoxGehwNiJJEslYE/CB0Aky1XeUmUAUm++Q3QVfUA3G3C7
+pP7whQSr1Y7gL44EmttFCX+dX8GWXuZDXa399wijphVw+6bl0gp/hWRWriTern1D
++/4S78ddrci4slA+/Kkq423wjLNGZtOoy9cXRmFdbQlMfVaeu5U7LmrTQRrgGVM6
+GQjgNanXYhkCNubQ+v2Q6FflAdri8Ac8ZvFXxSIGZ3JG14cm072vOdp0/rCNkzSb
+fmtyzXUGgNgKzfp/GFvIXD04lLfeipzlUhNvDK8AKUNIctrMHZegpbfSm6HD6BiV
+rUFNLvr58WDK0eLeRxg4pFTCf9QXr9Q1v4MWehkn+LOTconhJtRictdlj+G2ymOQ
+LYgSRPPdXVNxlBI6u5WRtMxzZM6G3N8jkEvFfFsyeMtE+R0OsXiIwvGzdksnI/1F
+deQJzav9uMBj4A0bJuMQ3Ls8ydZNFU2RDofSU84bP/g6TzU8MpT7QXQXPD2jKdLp
+JouxtbRw+YY+9p0sk5PFYxti+T17jZN//pqiBrZUzvspwr5sWoa8BbA3bWE2gnXT
+cmx98wREJ3wWRx+t0k44084kD5/cvVH7MsAQ75XxGa0ofVj3crMCL29c+/QaUnhR
+GrdJ0sVJeIthiOQZZ5zBqG+IhJfG/jkKpweA9fkQ5gm+FoasTfDnAdSJjah7WfoO
+C6LKzNBB1FaOHqy4X6LUN5wraEOP+0OI3hKPdOB47yUzPF6FGneGk4BajDHG4RyT
+F2ZnG1aa+FRfakQ6l7ok4j+VPtDlCPY2jnT7muj2F78G69abNOS7ASXg5+PJzso0
+liaWo1d8TDfEazlDQvglDAKpzYw2mSbpJVmmbPSaVZxUARcIIaBqxu6xWepfdN8v
+qZGrOp7vTOuGu8f2YmWKd3+lcNm2CwwGYIPpuTFjtUuF7guKEdTffyj5tpOdo942
+RAy/F3tCy5zfZrI8SkSkx+wfZAnkUnI3xQNdKKVLCXcpBtQWht2UGO1G9W84OmFy
+eg21zeITIwPJZfUif9WHihdINSlfm0CiS+gDRzXukS4HgniPfS3NPo6HAepc2Gzr
+QUGF/ENern3v85DCEE/AebRaQN7liM+6Z55UZ4GOT3Tj64+Nth7MNQXqBYEmCS8P
+ndWvlalOs+vlj2Rl13IcSUOK8OOr6S7jeZhoutej1b4lbw8RwYBXGg==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ecb.pem
new file mode 100644
index 000000000..bc3353eca
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-ECB,1E15270A7DD42BA2
+
+zz3p7Ml80hSdlJsI5RyvOScQlsGC1GLg3AK0dC/Hh0IKPTDF7a2OITL6H/y/3txz
+LJ6jAcobjRfVMWGAJUwFaSlE5QF5W1+RauV+M8oMmv+Mf2K/Urha6m63EauLEVWu
+IDtxj74qfQgyd//qWHU+XmWhhNEGk5MrH163VITZqpG3Qe9dYHdalh4TB/ILJqfN
+URKLjdz8L4YbL48dwK6UxargixQ3tfrvIdTr4mkMiquNlayTk9g5qXWnEXy+I1DB
+HweXveJeSUHhYRXdx37y2I8Bz8HcuZF5wODEDJJuYXy7a8Q+Ar0Ll/uQ4NXE3iI0
+NA8RA0caAlc+Du/xfzKdUgIPQaLt/sjhM4gPBDLlASUmO+PJfb1VYgDIbNbXiR9x
+92ePzennPnbhKsPcuZzXoc/jH2BiQwwRT2gLscZ86n9O1FNoaPAnYERlyNIVrQoC
+0Ll6NnGBM9Ls5k1royQQtZU2x5Yu5Q7DGcNqX2yI14AZrI4e9/Y0nEa+17WRD6eO
+fdaIC5dVrv8HZxlfzwFs33FpufovP2vlINWM3IqDjMf4FIQsoLdnmTsgoLRYm4JK
+zfcyiImXPt2iUrcybZHKa0EXYjrcoIVBS8YP1UTcG8WHnj3ploMxXOw0AmpXcznf
+sbLsaehbs4ugM5G358PMeWFXTv8K2YXRtArXHtkIYzA45zqWzpta5E7LiTQJfBRL
+VNtLja40a0gaajvROCekEzWhezZc7bu6RQ/XZXxBYHx9m7nhzKRkDlBrrJVpWSW7
+QmS0ptXblyt2tbaUtNLsi2SP7gP9ggTlc5hCpwygT+lxrcr6j18CiPgMYOgDmFY7
+gZ3jZ+HHd2+8GnimOai+r8wh1aW06/tLfIZxpIn4T9yGh/EMW/R1RTJjN0xe6oqw
+wC+TPUM2bMvDtAvdn8bYh3pVVLXnFa6LjhhgNvnx6wBoiBCJ4E9R1Ec0QA4jF/97
+B4e8TEv7PAFB+VGhIPnQqfsAqRfM88FwgZqSfZrBXKMVWA7I4fBeVD0cJQq8TwCz
+TY9Fi1YnomqTfacH1hf9KiX3j8OkfrhIM3+w26nE553/wOcO42YJ55NgnNXlQL2e
+e1s4uJ9lroATY2WqvgLy5Th8n5y6kVkjuODb/8hk3KXqiLqbUOmZCYLuT4ZHZ+Rk
+xtWuFpmFiuWgbg6Nr2t2KYXwD39pjGBRmmwMX1mBxmUD9NK28yO4HEgiPVzfn7sU
+1PWC7HpgPf797M2/N1gyUfrBbfw4OXWpycvmtJLXHEJi/p/H1bz0MuMJvPtNhzUO
+CP4jq0xbu9nT5eW9rD7kgvv10W+aUf314RcWKaLkOxkk2dTENjbviASce5X3ZU4l
+eGG2wtoHvCvHnNVj2ImKf0jbAL7dymVJlA1XwsLANAmk+9RGyVJgHn7ZkOfRVJmW
+VMfZ6AVeFY5BeJ0LCq1uE6QMClVx8fLN2iBEqamBNekcZ62Qz3b1R7ZbN2tlPKee
+JnLSouju6Mu8U9twVI2tr63OTh/a0XAjtlO0OAXuVcOmYOHT9fSjPdAAt3Rp50Sj
+PDvgN8s+qSkQKpx7C2OA9Wisrr71UrBrCfBhCOmN5gyWFg24PwwRKUnc1a8mT5Zx
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ofb.pem
new file mode 100644
index 000000000..acbd8da99
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_blowfish_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-OFB,B9F95E282FEAA06D
+
+StEkcUPp3txNaJlYBP+eVabWYcEzAkX64aj8vaDX64i7bVl4ospAs2stac7uXtXG
+IZLTqNNACoqC0jWWTDJca9vTEoqjDRKjN9yjXYfrovj5oKi79wfsSU29oH1dcKG8
+G4y8qNsA9TexRQDWTBxYO6EiQFVie9O3oXzjhO1hYwxldSWOV5ZRWoVmg16vAOxX
+Gx2W1twtjQXG/hp0HxosPkZteUDdhMZLWonYuqEw1oBC4iDG1Tjp0p5uSnb1gaIr
+pzZScikP0Z4/8CxiKV9/C1VNE70EHdAUYKjUx2PAbPaMFyO/sAXOy1INI7Wis7jh
+U2wKeXgCMRxmca4OMITcjDp6OGmKf41uWyTFwjO1scMvjSJsOZxNjAjcrZW1PPRA
+tvnhRpU9h1G9BOH2rM7VUI6zJ2FSNKG9R6M0WOQqxRegJzvK+YNLhw5lUzrbWOR0
+RdkKL15gfnuXqLTDTMuLX+aCDS1Mu/ZRmDqLWkJH4W1HJ4l2rBojX5fcbamueMyf
+Sbd1S7QtmF/B9LaGDEPMT12kOQHZkRBUYpyolK6BoMuRPYnGS0RkUwvIuPZA8uJU
+vHHuYRZsOA45YFEipyB/sek61bvqYy+8TaPxzpfj0fkh7AUSQmbk3qQRkQbltzqq
+/MkFShIzS7SUkyiowOet8fVjXDJPsw2bS3uOHC4zy2QQmhVKzCYWd4yCFl+WtJnZ
+eEkrZH2BpoCDEzKlex/NQlH9KBLOor221nJEVd5tkdWWZt71eGld20eFL3ewtDqV
+GJX8jFmR51vQL6NZ2Ehp/5zhearuBJ8VKJfFxIKSrbPjyCbEwUgYOyVHHyvYyMR/
+6hcflrUu1IFFwFhryg2bucAkdX9AhsO1dimxSgZKEFlZbihPBysCdUw3WRea57iS
+n/zqLrOm786KiWh0ndBgJ973g1x+OeuUvbNl/0yiO4Vjny6PkXcBOORu+ILEflzf
+UiEKyG8+cYzoYZjeiCFBxsA2+gZMdgjxVYF/lKzTqFkfpwYV+tF2K5N8W51cL8Is
+yhz5OHiENobjx3QeFCZ4LWDEXg1H8cA34i9oELbXtyG7W+hkZp0B9tRDrXcDwVWk
+4oYqWLNCQXqr1lL6cCuctKLdXbc1ibLt1nYGpJrPkPCbOshsI+iCMmulT23s+jqW
+TMW0RNb3wFjR5z9A1YTWfiqMKEcyzRhP6bEM/+WNmHE5LRefx+dnvZrVJzGZA/3k
+JAOpsxEPKv7YNR8N9yoAopRfFEOH4HYtLbsAA2sZfD6iVAXAAeiZ2Ehn+Bvek5lV
+5zIOtsXswRgzXvxXCPy0V5GWqMglbkUS2HGsWaHpxDSMbvBJuaSi2blZ16p3IICM
+7YcCLolKUaWqpXjhb3UypoYRwJs+40EiXid7aJ8rKoeId1SeETOwVWkz95NMiVK9
+5K37/OMvxOAdjAUxtmz/+v+twKfrUhYqP3Qkapy6FgA+qxnzpCFZZXrMKjpr99Pc
+QVNcvM/SKWB34jZGTo+Styc7d+iXDC1BUS/43Pvbka/Aa2IV/LPQA2pD44aP5l3V
+/tOfQFQWI0wCqpBPV8aXqGuqZU2ES0yc9DJ974a8NvS1cNWfsMcvNg==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des1_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des1_cbc.pem
new file mode 100644
index 000000000..2d2233e45
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des1_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,4629ADA1FF55BE00
+
+2093wYtiVZThSK/Ecf2pxfukmymwYi+yaWhMDfxz/O001tbrlC/emwfU7iprUPeD
+NJyyAV4GLjUBA51tfDqia3ATKaBfUtMQoC48+q/Lkr5KhLZEU0LLVuGrfvmDXmPb
+Ne9Ud8XZGnrDmvAFkguzK7cF4PFWUX3l5oYKinm8he7pA+t9RJ6QX7+BHKQHlWcR
+cT9e1iN7MykRD2Hh7YjSxg1uRlJ+1H5zIJBDjQ/WIUMj4EdNJriurt7eYY2XrP9M
+fyvTOBgYRHn6uQU0tdV0619j5yjEBpPTRf2M4RGOeNYGfvmk4RcyZPdnccDq5bWT
+w2XhhBPZMdCHmDPTCOwgfSvqBBX6OtH2EKd1aJQmtudMATPjA49Q2v9ZrgIQQxmA
+ZXIXuYH8wNPlzpm+abolucwIQhWJqr5TP5q7IKfYLD7FIjyrPBJecGoDuPB/Qp8x
+D9G73DKYgu3aYEFxcjs7tWwWe93pn7glEPmuybK2HP0iD5/YhXy9OUElAUZVBHXb
+WNyFdcdmyP/hcex5nI3Q27yM1auTS4Wpmvg9I5Psr1NN5ilWFNiJ0fr/YcOMpVsz
+NqQPuSLqxX5sg7X6m7MkE0/k8PfFO+tpy1cC/K18nnka8WgH4SJ+R1I8WXLKFznU
+X+mWcOaci2YBUHT7TWRzJ9/5bL0CEWlheabTjqbaV/4kiE5L0Wcbh/am56c2YAzi
+6MzassP58vp4hHXTyda94+Kj4ymYFbRBLqh9CVspolwDhy6e7ydcspGz/RRbuWrN
+Xc+lsExkvnLkYvkfmaAU/C5ME5PNjgM0kH0qXLyXPPtdKmwWrkGjElzaY2iajzpP
+XEmnYu4E8AsNdNg3HVcQfoUU7jFq1NeB4uibFrq8vh6VLmqGvK6XCul0gxJsfsh+
+j/38B1+5I97I0oplDZrAQMgek3BXegw6HZVqADC2KH4Jir50rYNCFrN1un9aohHG
+BdTzB1wGkjW2fJ/yrU5nkkTYcNhl9zU0D09XvFvXyeRdLzJL5eFqqZluwsPPw/TM
+CSwjTZbbeS2LvvstAsoYGfQTUr/E+BOXVpFmNg+94DBxwM7lCy57nG2Y6oIy8Qcb
+IfmF+wKMZEVJxy8O2uaCYUwU7qpucq1tz8l4bTo8wUctxw80Iflq7WYg/8V2ilro
+F1nSJ7gF0bn33KwlLxLy7akXiol8Rg6aOg+cAiMi2Apfg+5DXWrKf9YOwebDLOX3
+LWvDuMYRVccwVWsA+X4zUezGjVNuxjnjtsDfeiScf9QyliK8kjlMP/r+chrhFFzc
+LXARzcVfYCQhF6heOOY9YTHvcySV4NmgRKC/dlzvN4NMGh8VxWiEFDo7Vu8XTXpN
+7OiSd/BvmOism6emrC8zRMD8c1ZgCxuY1MOMVXRir/Qy1IWZXiYmI71mmJmRhE79
+Gn5JJ3aZ9xZmr34l296CWOBY/suTRvkrfyMRoSTC8Z9K5nbd+cm0MLzWMgiT5PAg
+cy6PHN9zVWInz/2z00qf+3lx45ZmMeVj2+2h1PFapXaCwvek3VgsXL2HUV/mKNcU
+ZH7mV8imvIopRSS4YQXB0Ophiv6i7lJWdKrSYd/Ac+Bt2E4z7q7y4wFNlZBvsBoO
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des1_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des1_cfb.pem
new file mode 100644
index 000000000..814ff8946
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des1_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CFB,07BD7DC7BB2EAC98
+
+yH7T+ZIRWmzcMociF5wV3YjHWCUMs9C/GUrnBP37vvJrBDBB3x0u6aQMaOs0U1Ih
+xbGOweaw7cMag1HhafjVK9ZFZlYsCfXRZk6JdOvzPchDctQrnjkDxnwpOllmp0w4
+Mg9mYLuEvN968Tx2TS26va/rPAu3xxA8mrcCuSfyt6O9HteT1axwDpZzOktmnbYy
+xHQDRcpDXaXspP2sVTaZJ3oq/AMGfrFXCu2m9jFHcyZKmEm/DW2aLmfOI5I7gCLP
+1KMekkauODnQZEE2Iyi1SVbTBKH5DPp7yXAXWOtugBcWNHbMF9QHqKlMs5Hd2MYg
+doXtBSRRBc9pLdF1FMwHHjPFI+GZL3hurqcD+YyZJqYvzEgnI9dls2K8MzQKYKDn
+6VpDCNbEf8aC0QmvCLIjqei5fH2RVYeV2M4Db1GDmpRAIRJEq0fXf5ojAD0Mhv6p
+DZYsz+f/MLTGwce+HCWxZyAyfptdK2ScfvaH8mUr1OHd5IdvRudh5+9sCtch5xQL
+DFIp1eBRd+2gvLBMja7gBE/xHXoFZtTR8xORCwgYXVrLLf4wG27XLdKQVQiS8dpi
+E+xCtiZmZfxb/1Ly9yHP/ehWD9DmxRRr/n1QeGMjSlLSzffuLgt/0tftK5yOSZri
+Xc1T83n5rLqhBglNEvwR1ewsTgeIxkgZo7q/LFajrnGh4L62cIoLkLX3lG0jaEC5
+VTa06i0b7U1nJ6kiqjHuXzkZWjTim4V7p7r/SQtAGuK3s8AmqJH53EMmiK0zFq9Q
+ao1ewixzD4NplA2HY4kAAVRQMR7WWIRrV2wXRTqoKwITMbZ8Yio8PwgSjsYhuzwv
+Mct1CmTc2FcCH/+AZOqc2HNS4qwQVmwLnOLmsr7L9kgf9aPIl1hkn9KzC6GAU+fZ
+F+N0Ti7d+ZkNAtAUg8fi2Bf/rtPvxmyJp6QICI4Tj4MFpGIRWP5rLwU6XXNch0l1
+nAcIYFvzLNL1v0TDnDz/CFW7XSp4IaDl0OLyAt+JxnPuFOAo1wJOhUWHheGynEBP
+U3K4u+761XMdqHb1n14OSgfyynIuLM6WtnBDoevKX8v0dYjO6PnvcuZoRqs1sYKr
+D93XsV8uMv79Oo84xQPHpJrUIJVLDeE5GLFimD7rUPvMURg1IrFnGyfcMGTvsv9O
+us/B1dNmOHjG7eZwJ/8MDNsYcpwm7CQsTOJUZkQDN7MZOKJZJr2gQK659eULJwaZ
+lEkR2p6A51etvlSPZ2pjy2Mgxk/T0mX/mVprEvCkxFWGlAxys1UFWKHDOOP4rUZs
+iE7nxBMyW+4zHAcco4Nly5gryqWiW0gn99/I7+qQHkb5X6ydP+GKOHmUdcb8RPIH
+Ec3bV7mBtfYxDC/ouStuQdVC7jWGwU7PeQqoz4d3mhK8dfeOvpudiTD1BLw30LKE
+Dt8/tob6zIHMEA5NTu6g5cbfa0lhRH1tD+O/7RejWPwOTc1LbY2igvHoh5uWTo8G
+ufvYO41PElmJoujef4njSZHcMvHArinYdlWlvMIg52d7Y3lQTTztY2UeO6DKRHx8
+Qjda5g8SDiqgFktkl5r9FYfqMQFqheSgKnHaJ2oPPbwuJyuNdy2Rug==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des1_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des1_ecb.pem
new file mode 100644
index 000000000..91a3f4900
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des1_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-ECB,451BC59702897B57
+
+lYkflQyHR1brYuUKx2oj0+L9fRwOhpKR6NMeH2nlLEMz1yntUt9DGuBRwP4RJs8o
+AHo7amQ1YzGpQCEZx3p+tMmk/hHRcRmU3ZeuP3SlGwpUmbMe3NI8I2dvh/qDL3Rb
+QParp+YK2vH/u/N2VPB11NvgwoUQpfS35vOhoLk3GUcupSKfbsbl/gn398DsgfoI
+d0qD5VSxNutst5I05pl4JFnL5+DBv1s9w68TdvAvBqWmsfhb4ei/mSp81e6ndxOR
+VLF5hgXauJjEHvI+c/ITF0roIyyxiMMjFd8IuIHbeznIjOWn4P5YcNcSswSG2wOz
+1wB0e8dlskukcUGqFS6W6mJzqb2TK1Eo+l0w2B2rNGX/MlGV9f6r7e0DQQFH0nCI
+nLS76C+WB5G6RA/7OMOWtsMnYSLldvXBxxZktcD1CNjyvuCOI5NK1KmG/Kajho6S
+/+A1mTs274pI6sIsCNl4ay2pfgwjZSWh95l8+YNt7o0C5lHudZ4hZHCDT8U2uCoe
+7dhj+KTuIS3VPI7lzruMZBGAj+haZ/cAEdqYGXizOle4MwKM5+lS8E5gEviTABua
+7jqhqbBE7CkN05Y3QmyE48yzi58hzSmiTOuAJ6jhB47A6Vsp/FpKFzfsK4BoD0Zh
+0ujT2BeJhtsFmPY6+RLtGITnl1498j9FTfy8ZNdrXEMxvp8SnEzlIKytLQyNoz7a
+tPCe1od1w+MUz0PHqDO/Av3YMULGLCUgnuZc0YjZv3P54FdC6si6KFEEqotIGD0j
+C24TXqlBpn8Qqkht/0TmzVHq6U7jynOjD1VUeB/gudPlHGLs468c7HzEzbpE5h0G
+1e5o6D5u9Nh1ItMObNrjt8NUxbi2/FX/Nkm3J1Ogno0ngzh15jZUfWFPAGkI1nho
+12F8Sf7YTBizPW+sd5hDbVejJURyoj/jt6UfiVKUg9iUgOW+ZzgkbD8RvC207xis
+QoF+2Lr8mPsNabUaFbsXmQ+6F0Pn05BzyBN2fyTxRt6u0CKmLE1fqkIuQywk83UD
+hBJfeewGoOGvoXDSy0ggIkjaRCsk//Xvntt5HEmKwc/wy/1Nzuu9H3C6n7qLqyNJ
+mPhrOGXt6C4LG1JscqS87z4VmhV7mol/Umdg00HRHs7l9qKRTePdlq52JL7oUws2
+CJs/UTaBHdbV2vh06qmymtEyNmQ+PrweEL5U/neyeYyrx6DsyUDdY1h1n+aKSEyR
+eittKv/pouPSLlIiMeY/DzQwN1ifoGsfYgJRst9Ry4MdlahpCTX+K7X6ryEOoJ/H
+1IEOm2aSlC3qEABUGo50IqiNF/PWugS7Qf/JzXAyjtcgQdW3cskNDCR7JVJDtATu
+0817ST0QXBL8qT1C3z843LcY1HpnQ1MiQvM3maDHCxuoEoUrRILWc59mc14gmowq
+g5XLMOLC/y5mX5LDqkxoKhoED9eM9/9EGSSy83dWWVZlGNLzu/JHBiWa3tVhas0U
+LytNa+kN8UfTC8KPe6i8euhauunLIKkq+MUBWy6agFR+jflE0zd0Av7Ox8HPbGe5
+0fraChwokeFM44fy5cOH7zENfng0jVUUreTpDtcfp390QW5Ca59J5/5P2aUBLZHi
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des1_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des1_ofb.pem
new file mode 100644
index 000000000..93766e7b8
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des1_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-OFB,62D0879F9BE636D0
+
++iyQyk6TcPldmHOJyjJjsJ4BgdDqqdQYRzQWC/WfDLJyw3CXLquWDciAw5aCof3k
+b6R4PvJHzvG6j9jdlcv+yD5M3j9ZVHYkLL0fTZA/LEODUOTX74gNZfoz3FGarYIV
+TabFLgwQh4YJ0+Nb5N/oISaNszC+wxf20D4N445kvuHKbak7o2j+5ZzGId9zYIPU
+Jat1HygggKh9PtE4NildizyVVK5h8ws8qPWbe2/m00Hf5R2oP2YC3Afn6kqMuueJ
+RrvP9l26WboAKFED91xY3gJy8r3KkkLOJq9856BlndtgkA3USqRM31W6RvLqHUDy
+3l4ZY3wSTCdZIX+iHV6Qm3xYaIHNzYjHRcPQKdOVmEYiUSmAZmcavcsPC7sEfD7d
+OMEbrYrztF8iO90Myey/lJxo9RaL5PfWbtXqnXKUZtbcudEQd1fXM6gzdMm8AT4F
+eUSayg1/3AGEEHq2PH8kKtxnWAb7xBOgLbjTuC68f38dFw2P8iWZerG5lbLsFuwD
+YZ5eItuDhL8+dbFxisBX6H0lzcm0pwK1HCHOvSCcYfpWC4QrU08WbtI7NCqIuRWv
+4QOHU6SoNGW99BSnUlsqgLdIcsWsyTwiotZqusZV9AusdsGqU5ixwal4YX/8JRg+
+93EwnFnl1Y0Bj/yoAwNfvPlZhtjevsMnPEbrXbFEm0Xw1kdhOYokrx0hQWUmdt7m
+cFdmFBYQGsiKucvRpmInylrS41VQNbNySqQ5iGa+vDaPBMKZusvgPgwWSchotkzT
+qTQ7HNjszwR4eIjBOiBSvY5YXoa9H3irdmLn76mOyDMjaQyC9o/0tbAagLKADuF1
+Ui4Z/3WV67SuUoawqDJsYEWbOaNFX04wFby0k7oACoNxqoGFM3ITRzmxnz3ZyiPE
+DV/grOZICMLfTQ81VvE8/w+w697F6EJ8rY1yOznglP4GXrtIiXAaJbxEOhosyuN7
+HikpDQ3GRnPzXeg/Yngzpp8JMVdxKdEItcXnWd9uhB2Ok1vXH8LjhVkhrL76bJe7
+bhagz+LphPaLnkE5BPHKLUwL8bQQguz7ITfxsEFpWIHG5zCtpaQwdMEj2ePVubN8
+sfZ3qhDRNG8DdwXgCbCot16SKGuOawMMC5tsoeg3DFQ4MBDrKUv3C9nF8izTs1Zr
+3J7kWYrZg6+hVcJDgLS3t/lbFIhaNAULmep6wl4Vcp6nBqr395r8/uDroOpoBxoa
+BNjvFaztkRy3XmNHp3TOYLg5HZPWsK3KXOs0FvdTMEEsnoj3PXz6+hw0gMV6huYp
+o24r34gKiwdbrkbwLRnyh0oF6d3bPOZ9WnPgA2y2MB+slulA47+hOMcP9+WiQxE/
+eGd6TTRjMPopQXJw7/tZEf6qyVYLWfKJmI0tljsea48NocZdsek+e4ZsTW/iP0oZ
+wPDYNt95V64APcDZfNtfzydp0516KY7p624TanOXsxNNiBV6Nuqmd0dGhbmcRC8Q
+KNgGNvgjF3rhqrXZyFpnZNQewE7a87bgmO1O772QU6GmPUZr3nzPRwE/8+TNA9AP
+hHL9HtItZ3arx7eJ42obFrxj3uzpQ8WQo/cGLgQT0lz6u91xJyWi2A==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des2_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des2_cbc.pem
new file mode 100644
index 000000000..9dbe30d5c
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des2_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CBC,A48C2683D96452DF
+
+dRu5UKxN6kr8aSBwZnynPwIA2y8Dgu6Xf2vCf0JswuFMJAwFGjiHoZTmIHuAjArK
+GWhiMl6ak552D/Nugz2SNgC3eJo/LOP/g2NIJnG09GuWOGXkiagjDKNbPCiIBPww
+STIBg5ilKV07lryS0FxQSUWsjI/2c0yxk/6MGSzQ6rrAWB4Cf843u482w6Hidr/E
+euPsqXJDtlQrKQ1gaMTJiOY9Y2H81b485MBN9BnKfDH4WHp49b/akcditst59fty
+FtzwyUTee9SGY6u7oKaUUe6sRzFOeeRR2TgWG5Bs5sne1AFFen2/q59Va/7/iXRd
+TOKKUGR4yj9gA+9EIpDF3n8Vn3G9LnTDFK0Xh1m61C1mQmXgEOqJGLVreFq4u1xq
+0J1yEZKoXreZJH95+gYAW5lmG+jNCMy0RO5PsTClx7G4XcIGFZAXi8sXfk3FYLT8
+nboMgQ8IXFjqO85FIVMt+xCpov+S8yOfPMOU63zxrynaXD2eGv7y2dTpeF3Mf4Ek
+be0YrQEWpCtYUdZ9AwA4N0/vkdp84/WZ3Aw/i+KUqYKtK2agkJYtarqj6iUweUvW
+GgWvZqNiTAd3sGcxffSbcdSRpuNttnBG77qAFgFiPXtvJu4wRkGlaxhwVTyUWK2E
+HvCEsssbzX4tZ6GUXScXv4zg3YaDP6HXsnBENl5SGXK8Uelett6PJhwH7bfpWysG
+Z1TD75uk6twThhtPURGG4GUaQ6cZ1RUsL9/y06v3ZmfUBxeVGLKwyMzlr2FTYenU
++LcvzriycweTLMO6llLVQH8XwlbAZ7JgndCjZodtFXhjhrS5Iu0sO6J2D7xFvL3q
+/Ym8PhhRStcVjijX+5+9aiA8AkXK3khP14T3yhPLu7iayl836Lh1+O1BHiYgr9Z6
+DdhCmO2Esa822yxyOdiwVlF+mYQylEZQy3D3kqqJytO9pn87cSvR3WbPtFOStlcs
+Htms8SdqLAamuWLGZiycPr87mSH2By2JED//80fNHdR1D7cvPU7oL/ClFMX/F3EW
+UJAwSXswmUxqccBR2hOJ6K3OvSIULoUn3awM/qPNTQL7rg++dSzUDbIiUywxuU9N
+nXkqfBVjoJTjafgWd39G3RdoK0ohf9QFj1nqYfaQGKy90cPVw/FdjRyszJWDUBTq
+jlKXnap6ZS9PGztjEoLqmFaFT75RUR49NnNtmcKmH0i6anjwFWEYBM61jox7gH+g
+W0r+0R2yijAspXHVpuibx9vdgkq/WR4A36t6DEMajOHM3SVzbPzkHTV5HyYQKnaw
+SZLSdUk8VwYkGSylm3f64PJLxBl7TNtrQhFLgR/9QXkhN7U2Qc7WxRQzhLQsLbtL
+qcBLGH34SGQarQZ5dfo3t+B6IIW2HvHNOiT9HQsIJTz4Er1SbLNH6bco7hud6aOA
+eSifKkWLp3SXXS6wjQZzsSGZ7Mws1DRcL9gEhb4tgIvopQK773AbQ1SJDEcmBpD1
+NmxrTbb1TngaW6u/79Nng84YEUiWNDKu3ovoe/HLVZoDr3tGmy5ch0jfA6NOxEn3
+KXZCiu/PjU005SLyLql5dcGzagjnnURDi7TLue/97xtpI/ac0vL868Cqfm0+e26H
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des2_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des2_cfb.pem
new file mode 100644
index 000000000..451670c08
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des2_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CFB,36E0C8A965F07E25
+
+L0GHzT9XVnA03q7rlchpiD4JCgzISj+B9GxKCrKSJJBC8bRTgjgrwySMQyhdX1nw
+DiCtb9q7UCxQ/j0VvHuoA3OS1/Q95mwCsnjUXYAPiXeR0NMJkLgv1hFU8EjAJHY8
+ZenlgfC1RNoUONucq7v3F7jpsqBWrxjyDXFnWwe3edSfUzkfkG27NK6LPScjqdY6
+kJWAkHGpoGog7cYVBJ78LbYYHSBR+xfeFzhVMqB78mH8/Y/CGlKvXnPFpiJCY7Af
+zpd4/PJRVubXVyANc42k+0/E2oPOSKiwiKV79BxFw8g+NxkhRzXeCDuzvExKL457
+cuPNB0CQLSVNmOWKr6mA1bIBiJXgASzijsjkyoH62D/QoBo+kBT8W3hiHooSzJ89
+flhyknT+rVuAbFdPGqriS8siN/r4Qq/gbQIFhNe9jsSQesfr7lM3oK2EPGpDxstf
+eKc+EhHBlT4S9X+AilnjK5il2X5szyhOFZQ7RdAiqZ7X2KPNNqbeS2L530ZvlL+W
+Yw4qco88cilN276QQWCcrp3YcWv+MzawlNvfOOAb4GfUlR+njPxRAxM3rGVXiMn+
+6UL3X1SqZfADJOn57S4cDoP/A0i3FUfoPTwQW77LOAIzLSeMi7brQkZi5J9s5Izm
+OMcEi+GwBrkbPl67fKMnt3cHeFGJmOftrLZCt8HpGEdiQzP5iiC828XvLLxby5Ue
+BGoBILGIHL3OqkTVjBbSODKFZTIOQdVkqrWKyXlrfoI1meATptP7/GhdQP2DTW8B
+ppmNgtwIbGLg/AwNmGPdpL2mP5SZLIDJHd81BL00xPJFCR9wxXLk3hgm6auzAsZV
+FYjaIQ0Qza5kBCKNqu8ad8edqgp5Rj1/ZzfCWEkPRHD/lZ7nj9vuC/dMnPphohKz
+q8/L1+gbp8dwER7sEVBiWDE5u3lpSbx+1qkk2CwOjE9eBh2Mr6qLL2WIFb4YUvYI
+OAWIU1ftenOEjgjvYZcdeEOYT0UF6/avfHDPvkTIwl52UUhunbnqCjQM3qr18rbV
+8vB1bC64DxetUPhDymLqJCe4QVQajdO5BxQ2wwRjHlBi94nlAS/uOFV+WwqtFKZD
+TakruYhw3VjGxtnjukruMzNjDSqxd8Jabp1oTHY57C+aYQcBo34XAr+j+PQTPXEj
+GNL19MUMHJo/yk05NZfkyf3/+YtAV+/Gle7TlWWCV1nvEwrHPE4yCGi8j6qtCzBC
+TgpXl/lxJendZgVzIGGzMDemJgyrLNV6ar8TbOz6d5GDV3S84g2S7cToMVHX4Z8M
+bR53pt/KfH27Wdn68z3Zd7sT8R0g7yCVIc0BJgRrZ1aLnyKLSUk7iJULg3+B5NwK
+JNucRiU6mT5SUiyS5WjD6vZVDjggAx7H74DP04rzgzcHvTB2gzx1hFzw6WW9wcCk
+7+RiY0j13M/nD8UjW+pp/Ugk4Oc/bvxsA2tWQ1BeyF+KSNj/zjHMwN/sp1/of43X
+D+lcWS1hCwMiy79KQudrkc2DiYKWSIiXEFlblSJGiQz7SxybtO+D0PpVmlEYWiDF
+AAMz3hM+CrWcXIFNw86mHSsJHvYsSjbCB3ydG8L9OdATYsS3tZo38g==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des2_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des2_ecb.pem
new file mode 100644
index 000000000..c3f285f0f
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des2_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE,8B0E5396F9D19442
+
+Ym7x4lqzxkC0K7f3nTtR7/ZVi0Vj36NLORWiJig0qvSmH1rhkkmMjssQqc17kWRT
+ttLj4D4s1ueQBlDFaumMrXloVp8c4zQS5jbHNmf+bUsom+HXGFHbjPC0usHm9TAl
+pPBWMCON5uUxoqJhw2mvrGSlkQhkkh3+Oiag6fxNxnN8Te/yTPC1XXCqIh7zRjCN
+q3wjkh8+0QP8ui2jK/2zrlbwvCyggs4q1YhVzWYiecFro1llb+CDCz0mzKEXj1MM
+MLyMdcooxXTb4t5PhkW87N8PSWXeJEJTxcWYbZ7bf+Bf68iHm6JChc/HTXZRLUfo
+3lACV21KTTI/614rLl44l/Ftg4HDSE4UV/J2JoenbRecljKXneeVj48Lmurc3zZa
+rj46e/pXEGfeEGmkuVnriWhRBcK8Mq33XfY870RsP+4bfxd2ykJYyxFZyoTT0sAU
+LJ4KIVZVc3/jB58CRBZDV4s6/cA0uHPhprtzEHSxp7vI9N4dQAWaUBMnDtPVC999
+QjVGYKRUUNp2S4XVLtMH3+jZ5ntvCTTabjuie/4TAxoUY45CwKjEFpWtDBEWBbXe
+zmIQYCE+o8hSVtt8DFWdz8+PGqF9QgWZ5iQtnp5hUKA4rVeaxF7+ktumTrwguZcZ
+6ZK+K3t4lcHyPZMQBoiWijmBLoRsoQ7NIFEE3sn9muV0XUz3hMCRapWsqS4fd3N0
+LRXrBmZuizqzaNBcDku7lBbembdW7EI9flzY/0Q0xRl7WjOdK6Nj4V2A2MblQoh1
+J+pvV9Tc4PANApNLcFZSPawOJVyUtmpX8QZYTe7QlXQrVIQE4HX4od1S3/ZlydfT
+DL8Atfec1sabrRFs1M86lJGnYxsvismLVH0VmkigWe+4sClAl5QrtCfGQepYmsYi
+jyVruF3FzbOCjcv04x4a4HyKRHeCVlsRlSq/njqCh0WSc7OMacpQJZVvsUYRCaS1
+7WhmzeiVNjgKXg5lPwta78Kh+XbQUtUGryQQrwOnbj0SDsho2hBTt/gbWDpxoQjL
+LGPHVxwqm0GZ4bw+4IXwltfei7MG/ceWxLZYk8ZTkc6r+w0+5HQFKZ3JuSKB3OLm
+rK0m87IybLY/Zfap/WLAmreRMUz/FbsY9Vjh3gt6NqrDhqLFYCyyUKZyKrWnVlIj
+j5vohFGbq968UYVavCZ2eqmtwWywsBXLOabypgrIUQhmCxOUBM7Mi2NVrTqn8uIO
+G5+mwzsy8imChv3Zk2/LafxPpajlu1MuC6CtMdZjV+zrGxJBEUxADaTJU7tTAWef
+lUjlZ4l/XO3vxSvv/F3yONmgKp1t3naS0ZxxYalcMRi6xTznW24r5voOAsVqIz5y
+Nl5FtPMSCBE4FONoUI4Gq1GAen2h2/Dz1Q3CMYAvJz/QfpZFu4DZ+jAUISU7URfL
+7P/lXQhg3onHVy5tgXhiXDhCCxY4pUPSy57eE32F+sIGeltoXU2Okx5/ey8ijr+i
+5URStFLeFp90ke/EhdOuhDoE++7G826ky3twqtSBTt4jU9IemH0agFU3PWIJffm3
++Ezce6LusooS8Bqs9rYXHHGe2q0oUNY3ipggOzx4Th4mwg1HzBQnD6FU33M/WyCw
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des2_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des2_ofb.pem
new file mode 100644
index 000000000..c34872d3a
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des2_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-OFB,0A4E382F6060AA1B
+
+hIbY73AFUCWIkdT7MEKMhr7+uSoSMO9wihHjhiHn01cq6kTe66Vy/z9dmTcgbK2q
+edRngIRyiTqyul1dhQ2ezVDisowHAtdiD7O2/Z+YiXc1hsuC/uELnYV1hTUg73Qb
+v760pWyH5AXNpqGsx2LLw+hstiiWVO+/Hs+CqtM/RgONfvUCzbyOQknDfSTDoVXB
+W4gEDKSDj+ydXm0ZmMS17DLCXgk4HBsJxyiK666l2TzB9pnzj6EDA6hDsiHfy3z4
++MxfcnLxWw9TJPxdLYVdw8WNWsXQd1JHQz/BQ/Hum4eNoYxLGgsV/hWQmkFil1XO
+GkPjF2z44fxN4FJjvQskrQox+5/gvnG+KamfvQt62qN16Z6ROZu5buPijxmXoecq
+gW6SyeFbnYFn27hglllax9awEEUtcJwi6OxKAkWD3REjqCfNAwcqoFqwkxlPN3IH
+00Rksn3P7cN5IqePVjSdwIhZtCfeBW2267oNxb870CDon7OlrUdK8KIjp/x5jKUs
+Pjehw1Ovtvn2YUQnTPvIYQsgdq3BMb9ETcnPDneCVweSxHxpb8ao2hyBMyYtQG8f
+LNqvLnjh7FUyRenf3XRbqka2w8B1CFTTErkMm9E0OPD8tMtDyakI+8fMJDkGhGI5
+jMwY2q98Z+Ef4wDifOi6qNklBlJwjvvybeqhqWOoXKbQMhnQPqFnLGjp5GQMczII
+m9a0anYSvmNKjRtD1LBL0KDMUgIx35U+7GKQfjrRTURYtAK8EITKUqYoWJWXUevR
+t9cikdwQ2yDuDH/C+a2eaEHJITerdW7ba/Rxzh50VdPq03uUNkN21VZEMjcU+GPB
+sLQ50j+gSFRMMzMfDx0G3wHoEJNAul8x2+umCUSpzPfC5D6kjbyREm/fWEuQkvL6
+AUCheoD7ouRR66R8syjIbeCKhjZEXUOvxxNYHSySrxHyiCGE5xCSVDlTzAutvcOn
+kivQqRlO1C6ZoEWbGr1SPoIoi0iMoh+TKZDgMy6/pRWVbELW5P9JnH8K+IreOIXd
+IgnCsqKZBVN4qRPrW8HtEwiWW7MsoXGjhpVl8wer8cNmcfPTo3x2l2+mjV2r0xEZ
+Xmv2LEtjDfIUP6yXuID4OrV6kpqSDax+wmujr8jlETKf0uEi4PZAXqhrgh/fgH2p
+VE+Ey0vnDaXcEhS0ketOGmBIYaKzWbMH9iX46YSkA++5/PavhlbCqZZN+906jwEW
+6MS7Nq1UBoUiql1Xa8AL0p/7QKZH2mgxpFcBeCHF4q6HhebbQbCpveJgBSR7/12H
+fJOIubovV6AOx2kBRAf27bii5iwMjfzC9IBE+GLCX3CXR+BLfOWutTcqbaBRdmQv
+K4yJqB/WHYcjlLKf/Q8+B6elmMc59NVUfStMszkIGlTzMFIkObLHH1NYPSC700rH
+ZkrdbRGfcncT2OcyFbWZ/tIvUER/aHjh/BvZ9s8UyEVEZzsFJI8HA66sJzZ3fKaM
+8P7nXXagyarILIzO90JIwkX+ip//QtpSDPkrUtii6Wj7n7RO0REe5N5+NA3A7WUs
+Aret+KXgmsOi2fnTmCFjVN2QgmQvOg8PGx0yYx8gxWog/NAmLCVMjw==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des3_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des3_cbc.pem
new file mode 100644
index 000000000..6a632f23f
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des3_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6D7B3D8B829964B1
+
+mw05Vw0Y4gDohoiqd0xLN6ZKCalPCK2F0QFSyAVeoPY39y1RyKdsg8xt/qDx73jZ
+rgZb/fQLKs/W6SqCAAk/7EIBNTCWf+yD5TTdG9n8viNDSNXWdyq172rEnRV1CWGe
+beo+YjNDh6UlZ1FcXLj82TpZ9EokUKLabzNkY/coVPLlytqTSO5oZmbdreuUxOyJ
+ktQJUmGBmBY0aHJmV2wCkOFAXbzoSfo+SNPntEUNTa8i0cSIgmZd4/QS2Xfa8qRZ
+c2R2hNyVZygru5t8eckKj6uvj/Yszg6XqQby4ktK/cYfveS85CNlu03WfjfI5V78
+vY5efs3+NVJi2+ush4p4TfgT0PAKTWjXwpMEiGVlmxBoPoFGtTXY3Xp+64QICgTa
+MdrxPDDBw2yxmWAOpm58eeRqAN7Jd42qBxerJFiOUZxYPyRrQvro6fkldUlbPNon
+53Hzb+zHXv9xM5aUqfEjMO4HyprhKT/8aZgQiDE8fHgJhI/S2Ho6Fzqz2/uOHzBB
+gx0m8fM8puQ11eRxO+oSE4OSKbEQG0Uj66cHXY6FbJUhsLkGo9HdjLSGW67vx7RY
+Q3PQApOCFcXLecfkXrUaAEeRPNqZXjCkF6s8bfCOXD1cr9BulaGpiGxdspu5Tk9Q
+bLtoX5VHnW9VoIoFsIWs1G0h3WILs7ynCE2ttDSnIjYZhE6pRBiDHRs3J6dH/oOh
+c4dFaapkisk0BANJduvB7vLvvbJ0Xs42q+sRUCWzHNnJ3BqQZtL5f0dqu1AXafji
+qwxcbrEqJc1kOQ+iRAZ83nVlVkI/UgWzTceYPR24Q0PnAux1LkoIO/FWbhm62j3u
+xS669GX+GS9urX8oC3JUYT2n9dnPL8ouB77KfP6c0GVxR2hhiLYmyP2600C5q5DU
+6rdNm6fb75nrAmD0cgPxbdOB8zbgVvQuPXG8QnTO5Vvhp5ETgifIXPCIWwNHg5xL
+o2zrAdrNaio8FZUVPHOvMKE6Wl9QDMqnnShH+8VhLk7+LQpVDewBnWaMd8pK8qGn
+robl+i4HWtn20uZIDFyI4ioSa0S3Kanvd9TkchEbDjKAVi1QXdcD+q9O0AYt/X6n
+ygx2DGhkNYMrQmc+AIt7dAPa6RdZv50AAc0R3S0DBaxtd36pWugT4WIEexmuYj8S
+NbRNLuyjQMYCeFs/Ff4df0gmfeyH88YSlafnLyFhvv041LAbU52e/yExCEUvKr5J
+Oj2qVHJVe3eVW+FX8hsoUAte/a5foVe067dThfZDVp0TirozHAycgfKI600VF3Rh
+rvQiHzmXRoMptt5g/yLsTVYiKAF1n2hU9556sJPARFrG1xXoFFwhpzCS5t8ywniN
+6wwV+V0s4LSJFQJBFjLrreu9ZkYMdEOrekzqBohF5wG/BJILkN8hBmnD5gckbLIM
+QUzGTGxu+BIUi8JNkso0hwZDAKnYit+FVAs+5yU0NVQU6e3fW/+m48YI5gqFI+k0
+gIGmAyU6zaUJBJJQ4wc3+dOsy8sokqRhVmA59Tv20IKHh54zWq4ouFAg4Yc0bwK0
+1ua9GJMGTXN0+Trb7MKZQVKokyNA0RVCDN9AIfwCA5hDhJTahsO8Lp4Eolz2TFaQ
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des3_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des3_cfb.pem
new file mode 100644
index 000000000..129e02eef
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des3_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CFB,B99E3DD88C3A9D7B
+
+4Dsk+pNUGsgEqelOveMyrkoDb+khouKf83Yt4/qxX8CHs5q6i70NLViQWwqvIqQP
+g3h8Gs8cYKZfkEAFKP6BRFPy8EttnBCzhAdvLKrKFCZoDmhxC5ia+FxPLtNaDEb5
+6bgSoZ07KUMvfMZdnG5Kogex4DedqENVHBi2Rl3Dck1pAgxwzMntgHsluT4ht3id
+SgyUT/xAaMSwIklsjclR998N6V8Nilu8TDDf5X12RHOq/MSqGZ7yJC3Wb/dsirNs
+7jsEQwg9tIg5B/5hxjN12E4Ov7orIuO/WHNVtLznx1w1t/umPjLFn100Kln8GvfN
+jiGSB5TUz4t8r3deN7oDrGjoyr5OMnKWSsIwKcMsNSh9aTdkjIJBUUhIB2PStdX7
+WbeNXicNMQeteIrY+ZDDPpMbjsH1Kqcz5y9OWnvaXso5lSHLBp1IamCv/XbQcAPR
+zbnbN8DCOYAMcUiwcRAt0U+BNc1edX8VmCB0d4RQq5BTFbjGKqzo6yFVUOVLhiFg
+E8G3v8sTqUhJyH4Dmjn0oDMtfdplk30Ywg2wZAahnI9w+cZFvzqXshL3mGdu+rbb
+h7PkiJE5vS6/4VKA7pngsVanCRQa3btL43ekShth+DXwsziQixGD9HhTb2iYeF+u
+9niDPI5gzi9IfxIpb3QjR1xDJYAzKDDBA4gHhbEBSObByMsVzjS0+dwP9N6DV60v
+3x7RfO094FXxlVWSh2SMvz/sB9fsD9dCp/gadqHxhk2aJf7lfSU1C7EmM9hxGZku
+vR3J1QcSu2FMrvHyRzFZGKozSHq3QunOLno/KmY0ja1754NEkntGvPuB7LhGBNB6
+14NvQsl7qFw5wJxmEdY5rhVdz4PxLfjnMyvCiWlku83QIC51I5DbhRP7eG9rJSMw
+b7KFSQwmp2yzDeX+Ipd0JAgd14GvtmICKJVushO352O7mVnx3Jy1ZtJsonhzySz6
+1fGIvJI8jxZOdO7q1OD0bfrXS/kwdXnxoxn4pkjw3ZN3hdFTfAerVQ+qYJ7zIez5
+0lUihHNw1C/KRsggraOl9rTUNppcNtMYwKXCJOGXI2UEn8p3JIxEHLwXyOjTDfg/
+5oK2nPAmBdGsLb5ivJLPivmaqDXf7fdn0XBQQmtYUQRotlGmfpztujt/b2pL5YSE
+Uqginw65zyedjL6Aff3crvP8/CUR0JARx9vF12R+v2iAnDqVk/yqYpRqOp5elm1t
+yGB/PtpoRFsNU1hDnPZDu7kZV9oSeXaBDFOnHmX09qE2r869Aye1xOVmxiG5tm/u
+KGA+zlJVVpQSwnPc/qk17S0dvNAlgt6MH+vYlhKw8zk1nDCuavUK3hTFT+9w31cQ
+yjPdV4/K8seK4zIqpH4LZrC306/1/7BT5JXL6ZChATHaI68xwEY2GsEl/Ze0JrQv
+WpWSN/I269rUfaBDE6eFaiSDzq1xY+qyApHSTNPSPDHbFeCXz+puqv9lw0bJFnRJ
+nLsK2fUAKNvyCF18IydyhiGz42LYbwwjlEWuVsfWtgvftDebZRIfQFlj7DJwXfZU
+zcEOI5YyuQs+wFK/8b/bknF4xRpaXwt9Il7tcV07h96TDJV05illig==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des3_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des3_ecb.pem
new file mode 100644
index 000000000..bcdc5d3f6
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des3_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3,9675E5342C359F94
+
+aqJHsie4Ls1x3Tk73mbL7VyTembpkhx/a8Mc345TuZOZEkU9XYrkFMvhEB+jcVoo
+9ydosCL2d8xjDusry+vn5yF3iwE9HFHQ52M0/a5IH3sTtJ18BzAOi72ykGb2r6ly
+FzTq7xdXNihN19wHHnI98GKdxdQmNR9uITx8VRBbZdbRNGdJopS8zT96+AV1QAE6
+lyKKLA7qbATHR7JWQN2OYz05vGt48Vmq+da+qs5liEtx+GtNUxS5x8lAC6Llmq2s
+/Xv8X6kjYmxHSYWM2JyxsznGfdXKXe9f4Xxwyhedei6JgrTHa/JN/+tvgh5NWODK
+er1tLBRRA7atlSoB2AAegJC7gJRVOxRF4hiKX/19cfEpq8hF9+6EHGYm/IQRSI/J
+F0RGcnSdiddYbEb667qTkbLZi/d3Ih3KwKGww6ZzkHe/qPi230/cDR8tac26jmG8
+qoCwj+XCNOe9IUJsCN6RmLcFp4Tr4UVSsswxReN+xs5Ui+S3AY8IKscLSo+bB8gq
+DVBvVFUBTiF5/zO8q8H8Xv2c0aA3S9UQla+l3yoZygiUym+Q204Li+tDXiM602kr
+GGDA5/cGpQuit/7O51KF2OSwnnvLdu96qz0f9X+rq4QVNAy5PXcr2pj/y88UfSXN
+GAbogEXqpQzn0rmV1OWM8hsnOpN2DLcuZICCJFJc/BHO4elt65OfBjAvbxjhFU6s
+nJLUcR5EopLex46WwuucR6W6wjAuO8ET3cDV5L9wQI6DT+XItotk+yJyYawNPda7
+wfmxZ0o3qdcpRp7aw0ohfshRGJMuLnGVgLczU4hwO2/1LgRMnCywldacAfo8Ot8s
+WnC7d0jVOre2K67Omh4gLQTzikvFoxg5kjmFFxF+QOFakT/B3RMa9mgjtOlX0boK
+HepTxOtCaS+cZnL/fUCbWdnPxqooKid2DnVTNIXXBg3S97ReediwpSn6v6gU8QXI
+O0X/+syPkCRAOKLjCdgxFXRB1UA13v6iqeja9aXgzbUnk/MrT6G4ivAMsNS1cEdA
+KVKVpbiKchEpiiSiPyo7buZN6t3m4JnupU+UvcJAEFgdbPvP/kFvxywpPBcAycAM
+HgujJ9bE3OR1lfyHHTGF/f5lXGDzB0/ND8h7Pm+Bd0AFde79rCswhnR4oJsPLuij
+Uy499ouKhoxFTn3WMF6at2QLf36rfLHl41uSN0tky8trT9SE1PjX6yQUjl48bJh3
+MWUFPYBDfDPGTddENYo7hDmwoSLbE5WFxbAeJa86wgV/P4/QcDF0IPVa/wsDTPKR
+RIy7eNqxXBYhFeOBCkTKHMJ0XCawi4q2CAwo7RNuAmTrHOBN2hZOwYd6yoEQ4ALq
+70cflG8+rITJHOdAjXYAlcuuB1FjDWJjO1E3P9MwMfiFZBnJBsYkDT6ablfwgpaQ
+z9ngnzRqxIjqAxrRY9GdR3BEWgRIiKXljUgkk8qFSRIS1i3w+nHAipreOwizTVUw
+otTU++EjpQBracFsuGP6w9vcyhHOp3K+RzGYEQoh2vJm25lzUWBHvmVpCw5BBTms
+RgurNRdm1IlN+qSzriotjPuHr9Ucit7VFV/gXtmyJiNNPjTLpLQEZOUpz15eaFs+
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_des3_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_des3_ofb.pem
new file mode 100644
index 000000000..dad36ead7
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_des3_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-OFB,C8F1482CB09D61BF
+
+0GfYpcSxvnnRri3s5PutcESsHTuupx6UcprKRS+B1neyPR7Ga0Z3mZ2/X0trJVpM
+cxJW4g/cU4TknCZLjIJlClYQenpPRH69yw6BTi6/pgUhKeGmQK9Oob6G1RMjS9lO
+MTb8DKz8P9GmDR4/3SvJwPU0aEM1EAmwGJV2beB2QWRhaPkAZBzeijYf+uYn0mgm
+hZwjU8tdwnNnCdUXdaHeRkeqFcL6OjJHV+U5SZaMbaky1U9lyIJL+GUQZkRfZzJD
+41Qt6yVtetTgzljtCtd4ix+RX6EYsWfZ3OVtwHGYpg28IdfJ3LVE//O9EkLZoBeg
+DyU9c0gDnQ8Dxl9VHGFwQvgdSEyJLvWDv+6RXvCX4Kb2Spy847yxqcfqDpjUhzgv
+C7FoBwswS0pkQzGXKgdM+WlBe9/GYOrzW08IYwrX88aihf50jXi472th6ILIkFHD
+6m419YsrmOeEMXGW/VIKxk8H8MGHwdvK82xewu8Ftgfx0WihfA70EyI28VLMQTAE
+MMHxxCWtdWWnmd1xiHQSX6vedPLXQKKt2AYxYmHQYfqNFMcvDc5uM5uM+mNkX0qt
+VL5PeYRYtdDtT5Xj4/acZD7X7DhqcOwvNll3J7PRdadNXKfjHR7iRP62YkIiESE5
+sCHhYXmtQqK2JUJr8a9M1QPhmAIF3FYr8wSFu/eWw8ooBaTxVoGCw70lT8LNHVql
+TYdW9sOnvUjz36oz6H+z55CNldor0tS/Bu5jNPOZ8F6j5r4xpTWi3d/UWLW7uBbw
+VTAG25EiFvQBXpJFqgRCBdD1Gcfoc+ZefLXQ1l0RJpRf1jJMkfSWvUWDRNm87PSs
+qTeDBzuLNx4A1wYcJ1H+R7ds5QK4moNlvv0hJrsqbOESpLv/XPcYrFgzms0b+Q1d
+uJEWjz38AgIJQxBxmoglzDSRx9OBh9D8HQ+aJLSVcz0dBmEOEtPjZn2AmxxccwCc
+NkMnAxXyNPEJhecTp2/lOOupQqMYTGe8aoiee3m01QPzfgL6m5p6IJdKzOKi0TGJ
+xNW6fD486B7i8d+VOnst6vnd4xiQ03gNNA654mrXIM881X5elqmoFWyup+Ct9lw5
+lxllAJGh7w+hf8P6mIsezOkZGieGhzrFnuLVM2srRDEId+shTV/0lZi4LhfDYroN
+VAbZ6bySn9fmP4Pn42zu4XjoZJffF74u8gFPo8oSFYg88tzjbPN9KAPInNxD6lBA
+cwp3vc1n71CEepmfeZFR6pm1wKRSupkOZNL/PV9rqsyP1pmPE3AEU7WYjNbf2ah0
+GE9f6dtLWcDP/3SssoSnZGy5SdqcNPymG9vOR+QD12YNxn7yA87HM3+swparlSYy
+Mhg1BuDXb5Q5XFVFdajFwAnXJblAIbuJAeHQ/mNCAnR3HNv/Qic2GF7X757MA+dP
+z86gFzJJtb7dtZ0WDQzzEVHgnfVHP5buXnHdepFLsETw9fp4ZjqPfHjLXIOvp9/9
+G9pmSzB1JL8kK8sexWgsMRnl2j2hUDYiVJ/LQjMzk2YLF5I0D5msNTAJvb/gFBdv
+ynVKUpIoJEfRaY7pxR3tufbzADNiqa8OUCGxZ8jo26j7XWDkunfGAw==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cbc.pem
new file mode 100644
index 000000000..176334059
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CBC,C9CEE2FFE7D795D6
+
+hcUF0vilpOxap0mbziQfS/5kPdXsFb59D6myNYdLDAvBWUVAuu5g8iDDJIS8KPb2
+xvmWdXRhbsnfeQGcGWM1rMc7brutqefFp/OAJVymI0TpILMgef0abf49PEqNUa/N
+rYs2dd39fsyrJ0rcEWT2lBA/+GTLATB+16/9aCwjHjQ4L7d4Soh1laMo2K2Us6Eq
+pB8f6an5Y/vSIlnljl4upKOlcLItd//2ehQnkuEhI2Vafz+kX08Z3+OCLZfdNEq0
++8b5GbOvygEZbG+amZDB/tXnR1HB+AI7lR94PmM+h24COWAelatj2uPOGov54gXc
+iO7NDGoouysqfkfcMpuy5SkLVW4FoCAxfOl+LOU9p4x8+iaJt7Np+TO16dvX8MOL
+4WcIz4huaT125V38Q4UiB+WbsvQXrHRM4WCyJBGBhakr+FpNFdH1UPb9Unb+8UQL
+BeddEGT0l9AiSebT/JMKgFUOInQdKxOjg4NBp3asVEUeTGLeTN3o06zUoopzT0S3
+CHrpgvpZLf+4NATrFMw0HkcUK4GHZl/Q68C67qNGTc4B37eGcxzGo8QOyjXzKxL8
+Lh+Ry3eJpEXae5xDUn9yt8eqYI2vdwjA/3+XE6mRhu1sbPNJCcWo2kLZ0ibYgqdB
+FLsXBT8aoeKrW2p82OpehslbmswOKZgrPRYmNh1GAPz2jwBFfCEOLQYXAjCFViiL
+ipFLKLGt2dhjk5RbCraN6eYRn2XcIai/7dnaYxXkjOsNH4mmPzlzjhvRh/2E/r2Z
+hbTOoa2uFUtZHWtDXUz7ZzCJErJaA00ont37BksfHDdDw1HIt4z6Ut8Jm1cR5zPO
+pC7s7ohOS5j8Vr8j947bEXITC2ozcvVVZOCcHwF/PnUE1zx48HBp2m9NAZ8Bz3LS
+Zn799/RrNtJLnkheG0wIrizk72M5L9PZQ4FXlupfJ9c9XniaQ23GQFszagceDN8j
+z/MR4tTfdWRy/889lqZ6ccNmPAXdwwijC6Tw6V9HooN9m3++ZlbPfHpboQUp6+V0
+Wwq8gdnlYW/i++9n251xBsR7mQtFNXaYwFmLUTt9C8OobyWSsX/OaeQGbWiVnmAv
+vPkr7mh6g0ha/x+1vKgEOjqItJsGdspf8ePHQ3FaTkfFwhQ4eN9w4QR3uzM/7fnj
+ql3yA+G8ftpaU9omFbs+VqIVNej5tvjODQ02BbjSuRklAGxnReCS14vLwjg9BV6t
+Ow74oIttwlZof21BWsCISgybkPmMhkIhUNAAkHexzY3AiqjAtEGnpmvfZAX9zN8+
++Kg58DxudjHQwUO4cwP9p50NndrilBShkotdYIqekXn6h0frYuhspJVWwIVswNjX
+BuEZE5B+Otswbt/caj9C5tfsyKmnGToG4fpDdk0ItxRq2126crKQd49zZybyR3zR
+phLeduyS5h0oYNwTjq+Fg2Z+f6d/iyCAE8ynfqcAPK1WpM/02DBoLsOmve5BCSPB
+YYKdrKfkGbj4J2klrptGmqgctyW5jKGddE6NO4XFYV174rsdPoErNWWcfptHEMLR
+BWfopqdN/HMrpRLTkjx9rIeBJ0F+wQEEH1JehnWExSSSAhm/gzQc1kU/wihOStU4
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cfb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cfb.pem
new file mode 100644
index 000000000..4284fff63
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CFB,AEA62B1564D645C9
+
+NX4iex15O1Dwp6ADN+uFIycPB1ELvBDVRGh+OZnisNU9h+8dPO1cb3j2tkwLFK4i
+Pml4zz797d4I4GqdF2Y23dz2AoBrl2Lj0N0W01AlOGagh92pZ9dKjjU+S5N85OBw
+buDbADh16fSPW6Y88guWFXYBlGJ6HZFK/9D4CZmEfI2Pt9AwEIZ/JvWrs/zW5eGP
+YMFsLslsNu9TOIKF8iDnfcWM9MFpgwcFCIqTwyQ/+dka0hw33WsBREhFcNleLxhW
+NKBIMC6jNjpW916IClH5sBu7T8ps/7JVw4DUfpl8NAOaqJSicPGpZrGIZ9N9cfLp
+KD1XEy+yWc9ahV0mfiyOuzNnP2x9IEBdrk5uqJwIT9RuiFZixIH9MRuqAtrA5BIP
+dc2kw50AbXRghE0JdUEFfUm9zcRKdG366SgADnteNk/77gqI0OZJDD0XL9R/N3Tn
+uh3EI9joJciWDbEX0/751MfcLaa/EkI7quKMEyFGWvox9sKLLEKRUV6SfO/YX8ZM
+RV7ebJdW+Mxya/beG3Yb9TAYkrG2TT2+uhRqZlZllJQFnX7k5MxyfN5I+WJP7SEs
+Uy5PAkNv3h7DTV7dBFMy/gPYAooY4JzBnbq33af+w/VbhyhVid/hn9UAONahw7H/
+1Ao24IlYMza2fJ9yOn+ejLhjvwYIP5992cmElneqMdBfV+oaQTHtWUuVF6g4gJBw
+9QucqxH4JbYccwA1UiKIqkmOlePm5I57RbBw1OG/Un3SiPcAwiAW/UpI5yv8kNwq
+kZeWnD79kMBEW2pU1CTvf5f8aBmcgQykC0M8H25Jj2kVvj0EsRGx1LuQx3ZCSM9y
+sZejgZouYA1WuZaIsz+3t4fgYFiOHDxmSvPt6VtZAMJGmLB/Xa/PVI4rsyNv99wB
+UinlINhzeGKpYYHnUgN0PrRQl0LBR0TdrJ0eG1djEvflXsuAQVP7+gP+oCckkT2c
+pIVm2IzplT2wzsza6+o1SA5BF7RKI3A6IxySFEBJTeaiZnYeeJHxE2DJvU1Fe29G
+ML/lM02waLJNbIs0Vk/i+hyE1wtMwZetptG+En5TDzTkWlVSLSqW6LXVJ53J2E+q
+wypuz4akL8CaYRm4XTmIH3Tom3qSf7rdbL9gk8llZacFNqAl7x1C9zDUzKU0DAOg
+qPKAtD1s7Rtg+4p+5cIEAWD0TKX6DlXKC/EdYO1w0vmavGSvQrr+KENE4+/gIRst
+qlTCiEW2U+PPyOgpZAFF0g5y5Xw0Fea/0HwBBLfCiPKRmDHQIzWIEW7RkkNfQlHC
+iCTBoMRFDbwXJEI9XUu2N4RdmlP+84i6fSRWuzZGUACvzEnRJEc6H0FaaN+fX0wM
+Op5O2hcdA0YTGGmTLUAeajiQnqGRobC8jQL/WQRVwOiFU9rgy1K4Cu2T6eBubvVh
+gk/R12LezvD/KwLgQz1+vXa5Vgjp0xhpnLnJVzPqLG0Fmj3V4uRDc1Lvvl4uLJiR
+VFjFYlqxP6w+ToRqnrfbmUCuiq6pS9FQi2Tghd02P5TnZcyS2xF2X7o45gegMplS
+skPzTCON8140xpx6Flep3bHwzEI0CEwO8goVMc6x4a2Ggekjn/Nz2A==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ecb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ecb.pem
new file mode 100644
index 000000000..d9609d749
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-ECB,270AFD04879E8434
+
+u8jYUJhoDMDNI5cHXhnJJ7Pm0lF+MrOl84maQOwfwZ5hBbjpx9s+z5SMYpWfz0yQ
+WlgBuGkaY1UNBDrwH6baA9/eqUzem9ZK+mYmjKC30OaumjKVJIB7cJfJf6Itcaom
+SH1W0kJYeDn7ANdmstOGxbr2TDCr0BXa+7j8cTo2TZX1rfsXcdmjQ+8Qa8zfQ3Q5
+FbrO+VNmAQwO7HeFjms38+ukJRW30EPibmbzx/YTCZ7XtCsXt6t6ggYja9Kvk/eI
+khwvFFk4g6Dv9YU+x2pyrkquIiTUo+jm3Vqhz2m0cGcqfynVEYn4fNPc27Ekw3uj
+CrprMgnfaX8QVx/EkpDYp7gpjcLYJObpUTcBo5iA7R3lpQ8itY1Ky7u6MMwQ2VHd
+XZcsS6b06mp2EW1CO951ZaPyma4AqoLl2gZ3zH4qPygp7uxrGdFdFSqrapVkDee/
+lLtj8Z+/g1IyVSIW2FP/SCoustCHcqeDDq70GKY9qiahNFybWn49vZAPB3HPM22f
+mCcw4ALiKr0S9oofxrb8PKxmDQMZAJqjc8qRMLktYh9rJLMoUG2bmQqpKmLLpx5q
+3CaKi3wofc005VcILyRgjumscAcpbTEz4vcR4jTwMPNP+WI8+AHtg0OcF+7hE8qc
+a9KTSsx3eJNbqq5UYxVjV/DcttNx9ENllnG+jEdttkaf+T9rJiayc0WPd+Eg0XlN
+ByBG0RCPQVJ9YH1Yke9HGE0FXv7FV6x4c22ePePcyE6VUNBoxdmXw+KRhRlvtXtM
+1fFMwUrY//jEpfbf193avTVVctDTLxDSmwY6eAMBm81uDTlpUm0q7l2rRuKzdgFd
+bG/MTOd/j7wtKJbQpbUfUNFtF6zjssPdGhJ3l+8Rg4xZyHWHgU5FYGodp9RsxUhm
+8AzoPDcVbbvu5YlPP+XvyEO1860fX6iSZKuOV+owjh2i51CPzsgX6OrOEb6/1rc3
+M5AkLVl4insmetdTqb9PHCgfD6bLYcDBj7Qnf4HEDQUGcRFe+jogOoSH40C5UgPq
+F83nXv6WYBb2Y97lhb44x7d1MzE1kkzQXlyf3QuZ0ZjOvm+LuOWkbQWmLj5JhFJv
+9CqY2MBL39EFamKjmmBmjrRsI9XMLHvB7VvT1hJPzxbF3UwDZ5BsA8IXSps0EjXR
+rZXSwo+vqTa3NlvysgvuJJUjwyf6mN2SVrNaKnZZ1OGFY1oQ3bmOgdI+SW9cpGzY
+Y8eFpaG2RAiOfBZ0JIyBUoHUH1MMMPw+Mh7KzIknP7O9htwiAWEvkcjWr7X6jpG8
+sBdBmszX3TMDTToQ6DvyjVRP7mJ39dV83bLI3EA+N8bJcTOcHijCvbzQM50WzMu1
+2UA9e6rG+ouQAgwaAHdR6bwm+Zr3e7MswZ0Q8/Snd1UdpyMyJ9nb031NSRSvkEyB
+ipu85/738J/g7tAIOJwwHeVWjL4lnrLC3CwbtvWAQ9Ox8Sjv848608GzQxFwHBHJ
+0NWgt/AfLYsq4bmmFWtqvqTjWeAeUsM+67UY8m6/kxhfRNNN3zZcckq2zlF7TRNU
+5AL/3KbVVLQl/7fD36m8AK5eImR+Gvom8ryzNacbNCL55ks0sycbICulXbdb0Jgm
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ofb.pem b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ofb.pem
new file mode 100644
index 000000000..cafccf9ea
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_128_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-OFB,E5989634C878E65D
+
+6o45POmHfE72UAdMBQrRIm2+oZCd8GmkmrFZMXYnVWP8ciNiGVQqUxVJS9j5Rx17
+8qxpNrzvcWEGWcgs9AOqog7YXHkxo/s/RIOKjUu0WhY59UrYcbkN7Rjyn3wSSD8X
+kN4Z2tz3iR8LnfljD2ApbR3yEYz2NvmifZzsac58R3LvuFg3Tsl0QetPSC7PfMUh
+B7dezaycDcx8QJy+nRPcqpGzeL/VVk3F4Hppc15gfdWtVellGcYsT0Z2Iu42I5nx
+HYFajRliBukH98M1d905lk1aNLDj54BBcq08JsDJN/V6DY+mUpJCFOK4DfP5WLJb
+/HCQg0wqsUmRHK3dVo09ilZa4OfrrRD5qTWr5boDngAqyD1r1fiHxcv7uU/HOSvt
+PU53frz38BA+w1pHtlE0TSG0oBe/+741kJtpvj/1Ts7nUeYJ/DGR4vmLpg4rnbZJ
+Yky5TaDV2LVLFR4syqombb3eiK5xbnjePCQFLwxYLQKZFINiS5zDr5mdjhWbIhpA
+7wg9BKNpUeXRDtntWXvEH9FmyIicbk670riEYEo/EniwrxW9f7MFhPUpOb9ktE56
+RnaU0EK9zUx1sIvcu7LVq1G2EVG8IrOKGcj4LHysBtg6PQW5mvN4AA5PZlc2Sux4
+L5Z6mJfwgBbBB4OuRXAYxHZbnfMTs75vL3d/HIcvSPcvb+7nfvNLiwlaBxaUfBFh
+fyDurHkMG6tBgE6OORgWraNEINJeOYcG2WK60qC4E8YfYCmc9V+28A//bsyRWyku
+xIDup68r+Os5RMRAaZrkIqaH+h4Oyd5RqcjLnAFF/wLGnNwSttYT8o7WwCf9ZCCy
+NFvHDWyWMUxonaWgvuSm9YPfh9/9CEsHkKh2RqBffFcZ1ktEiYaI+dGyty12QW2Y
+909pnCZkKsm1Lt3ts/xie20/gcwfsnvUC8OveKPaiCnJxDv3r9pMCNFPdcXo0GuR
+oadhn9r2CqNCDo+l6JWVRka2t8+yCAskZC7bKJnSeKlEDyn7A/2SLb196G2k9cve
+V2qQenhzuHmG5PEVfhLWQ7fL1BmJcRDuQlSmMGrdmOD4Zb0Truq0zpFL2qaMBQvb
+58hG5YkYehE25j8PpJYovOQA2hih6v9RytR2VKlTeYNFbREf1sdLfeIphB9tlHlp
+qZ7eOFAjjVzLsC4LmoCzWMaQuwNO1f3WiNdGVvulHkWqFnGS9bBBTahUUWI5SYiQ
+90vhSmJ7R7461rqWwn34Om5jlgRV4+2LhUbp+XdOyklujQYviHsOs8/wlg3lKr76
+SwrU5oYqlJ7FJoDq4IPpOnJaxsRjkr9foecgdqrU4SJKyJJDbkHNfoYq9r/aZJ21
+ruPFv5t021gJmWa87199GlhBZD8dxeXo0PT298Y3pmaaSdQIWLPeDAtc1R9EJLwD
+6+ydhg3ZVtSgXU0zQ2SRVMGhqoEXHDUrMtjKzuaZsYL57tqH6At6vWS+xA0CJBCw
+7GkDpM/lLGjyisFEQL73F0YmJPpb5s4izzCLUMxZQZ3u4T3f9OPRvAIUf8MiFJxh
+RJq2Is1gD7M8+dySkFeAbQ1STvLy29uIxKTE6BgNng5NrY03GuK/5A==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_rc2_40_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_40_cbc.pem
new file mode 100644
index 000000000..5a9eecfeb
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_40_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-40-CBC,BA10EF99A1862AB2
+
+/CfoFtIX0zgNckXzuODWoCYVY6NoXOvu1jt7J5/BfSZUydRWKa2lpR3SWAUAesQX
+H/IK9Wkz4um0QgrHy2fmVaAS1G3ifwgQ9dhW1EMiCEAmuNwPsT2YBatSyxnzWjHa
+dv4eZ0Snk4DsS/Ajwn+Oc9uZ3u5gKnfYk3tXoZ9BDPQbgIz01UI/AyGHttB43brl
+e1C+zKgCSa5WB8wfxCJsKHDSEHx+qlipVvDk/pntc9m4AM0sp5wsHRw3i1iirQOw
+AG6qRs3Ro3jwajlEWPmJolhbRQWyA2rUfSIajElYFlFgxPLI10m0tO5M55VYXpWe
+cprQNe/TxK+YJTcBvyhFmP4Ha9NeC0Vq6aHiECpZ1uObH1brZ1bdYUsSGodRzGMC
+ucOkFDpsp9We48TAHqEGArCsKexxe1dDe8b+cxdvyv33ZI7dyr7DfHek3X7B2rHv
+tZYjgx0cKn8SNl9qdRync9wLqjL2R99sHgphkXUA7qLP7ZdvZEeAGs5NEuq5oyDj
+4aybPFJu/xvByOEZBwEtrixVJ/2h4KYF6g2vK5CgmnYrq8SUNGobt+oLv3FywKhQ
+AK/YvDt97wXNdPNqPciqCP9LIeo0B0cgxFIbOOE3mvYgPaUoTtZ48B/hpkY4flKR
+U7opVqbNl/pnh1OCI1ce/K5KPw0rvYgsEQ8Q04+dipPdmvONYGhcgHflS52xju6s
+RbosS+iET3a6BB8ydRS8V4oezbr7AgzoSv7Od6geru87fYpVW3WbGag4w+Xgil7u
+C22epy/AX8naBOsMa2QMCZ97avi/qhMFIERzhQJcxULff0lHQBq+HMGsSI8jMEiH
+d2OIERTWasAEPdoBnELO3l4oywb4NmSp09m9imihdgocDAQEXyLkjmRqkm5H3Tdm
+ALFIaSwU5SE/dk3T+BTmnfl+Anx7QNWTdg+ykfH8VHbs10A/K2zt6RyJGLdStfKq
+VWORUG7gYcVGIQrcJllxt3Jt4sG3t3rSKA5dukM7+D1d54ExiJN5DrnaQ4kX/v7O
+nENonLRtV1KqrH32R+tIuBVA8rbmyseVequTBQpkHbG/IczTG1k6p0Qye17XlnPl
+kEPE3CG8+1RMLvflA1rTimSh1WafHsDwvwmTAgdkG5btLlfTpPnoKDy2hPS4Pd0P
+mF7OPVfA0Hl/oEqP7bqyUxuwFrz7pZXQrKDS02nXaqVAP02nKsiEUZNo2kprAO2v
+9ceOhXP3M+ItlWeNcX5jKRaaLddQvj1ntOKqDMfRk4yWm9ro8/E56Fkrq7GpKrXL
+FCJJTdrWk6EcSfI6grVjPbZGBJiA+21G4IPQWskPkr9gLuE0E9I1UAdliYKXOrPK
+F1lZ1ZBpG1ZBe9H8Gr2sK42pzJoFJsOvGRjCxlHpf/gBoOADH/hcxvQqBGizEr0F
+kKraZWJnlL8qhDzfJ7YLMqzFsOu7uYQRqfOcv+66FqT/by9rD7dR/M03YJReupoL
+lynJfffGCG6aeM8hLZ8iizjIc/RzCY0QS4lLPkRVSRNt3Z8RNX/nFuYhYgOx38pu
+6dflN059kTC5iyjsI5Ka/Xzq69kR21qCcHOoq6IQqZ7q5RM4Cj0SCXw8/4jeT2xY
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_rc2_64_cbc.pem b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_64_cbc.pem
new file mode 100644
index 000000000..7d0960811
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_rc2_64_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-64-CBC,DA39EAD05DD48A5B
+
+mil5OpL9dVqnEoKF7dNjIRYLgDjCBmTDZ//Bmkd4aqkPszHaCoQqgyGYOuqWXdT2
+FAluu/fHMLDTizyr2Jh00ekcR3nmnGM3B0oDiEtq84YMHPWYopWkpId1ZaoqluUe
+6NP6Zew4DZ8mEQvOxIxBEZqk0ye6srtLszByw/dTy4i9S7l4oR8hx1i6Jj9lLXS1
+y24lC68igFNeIecggG8uwZBVmnHCldZGn6DBBqcC0b415+59vwGuvc+POy0Hog/4
+ADPuZcXEO2whVGyOjCF7CjhEFfo0CO2niwS9PiUIYNsUluwfS+y1qhw4VJ61sQ/q
+7cNHrD4NfZHGwpIRXk4c27YHS+JsxH8Kh61e/dQPoeTf5NBQs3PthFcx+hzlTBAq
+VK/4TtRRlnqTVFKRydpKo3cNGp8qm9Kvz6fr/yLb7CJvdoGDyHVO7JvT8nYL5gC0
+dvN2RySKXMrgmPS7uMAWjpnDCdNoOX4pRTRPEdBw8WsdXqnBqXM8tvrkolF9n3//
+lldN3sSGLiYM1cwD4dXlYJEJNaarelHk6vpJIU4A6gYyN9MQnv061jd7sibrTAjZ
+Rx06R0FrYFbfkp4yAmUbrPO5gdwZPBGS9XzkZmZr+S4u1fH7tTFxIlWNgxwSzsZJ
+P9LXM8Iy408gDn1AJlbT7WbdWfcFzqIsmauRIXE66TloS+485ro9zX7O27MumF8S
+hjD+cRMieUEREuAAlpNxZj5kcT3SpxfSdaAZtJv8OKeRHz796LRxlLmx3ZDAjgN5
+0H37gSCXJDP2a4YnsiI7th5fNba84t1Qt4Q36v6EZT2kscv0TB04ov1+4UX9jCQI
+zn2zxzJk42kkxRSEBP3BnZf/qV5t6/+BKmg1QGCmS5AkIIlCDjTPpAom3n7YH9LV
+ykAQ6Wcdo/7dGtghgaHbPGl3cXR1u7BI97GCU4vzRbW58ULh7KSC1xptDJrP7tPE
+6OwwYk5YZ6lmg54cLbQcxeFwYQg1dc4pYAgBppUFUB/uWeQrbJP8/FN/GlW0HTOU
+kUIz5pbI7nstb2hHrRMTtG4c0oGO1ACD2LigQo5Cl7jR0sBC3I2MB/JcBBwAHPVP
+tePpIdSAZjAYI+x7LFxxXvT7eXe+BU4ZLGLcTISGJjtsbJG1oJ/e7dPP5bLL+zjJ
+MrwoE6awH5GKOOxB0iUGce8jg8566qY4e2vbmVL4a2qRiKyLowr7Lcz01VzzE/RX
+0Ec1I8noUmsystH/57UMBuhZNFjW3LtTaw6vuTrrmFtdmJcGwars9tBtH0LPip9X
+xQbwIiTJZCyDjql7Ecgu2ncw7zHZzbHrmoEF7VEdPT4z21utXgzJ3HubvB7Agvyz
+sB+EXeUqwZHnyN0GdGd6sqlHkW7TP1XxMrjewUHjXuY4SvsosJ/GqMY7uKJXK/Lt
+0kqYrV/YDIVsJ2JqyxwXYYIqmZfQ2xXTLuESuesT7omKFh4cgwbYHd33YWRCsZJB
+7Og8d3ciguWDutd1LOgx7da2ZA+3UVz8X601GRpFD8YoZTo8QOayXFvv7L1F3oeK
+b0w11lT0npxstmeMQUkbxAyCnKrwpQagiwBzKlr9ymJvh/ot6sJ5bAFDvZBBKkQU
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/rsa/openssl_rsa_unencrypted.pem b/crypto/test/data/openssl/rsa/openssl_rsa_unencrypted.pem
new file mode 100644
index 000000000..f540dccf7
--- /dev/null
+++ b/crypto/test/data/openssl/rsa/openssl_rsa_unencrypted.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7Plp
+gpjUg4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc
+8BQcwHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTj
+HE5t7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindx
+OSAnAxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfD
+HArDqUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABAoIBAFd6vTKVVT0O/U04
+wTtiptA/p7fkDM5PHVBxh32Wxno5pj8PerIaiduKyuRVh7PvJRMJpw903BrAK95o
+847WWOVOaF7TcKGMBURJUS6maiJS7TboK1ZbUVnsg/I99ArhiVUKGDhlsl/Xd4np
+YPDYztzXLzLXpm7bS6CiuvP762x9dfVu8K+afP8cjH8pfXLq55ghZOUKidRQaYz1
+mNOTQyAQlCQdLRgKlYgqcRHlj0pb28XBJaln3W7Z7GFMWFPojkxx6LaCp8+Jyx2C
+tv54zIZQhMjF37tQyTnfK4Ocl3sCRb+jYV4FkrUnsQE9W2dey0Tms1XB31gfUJlx
+dRZu7zkCgYEA/nWcTwzot2OIAhXoJ2fnqTcpdmj05LHhGcayKjyix7BsVH2I0KpF
+9kXX066tr3+LxZTergl4UpWSl3yx/4kPBQM6np4VVRytn7+cQdEhOczZnBw6x7IZ
+fv81DSNruQDBRAlTtklW4KBY74JKLhaJSvF1F3x32+H+99i1MmCNJRMCgYEAyZpF
+h4c3pM9z+YlmgLdUh/G2abdoamugcQOFbzHbZowsRAxEzdEW9wj2McN6mt8Rn1tc
+tY/+PcYuIK+vcmk9k23GuzxRlJlkaDicHwlAebgVIulFcrStfTlSkXjpuOuusfD9
+2DuHMcUiPx3qElNB0dZJF/axpq7BjTIFENefhZ8CgYACn+vw1M1BtwEcJGW0olm9
+YRhIZGTCRyNvRKFp1h5HuQYlCPZ0UI1QMQA86rxX5xTmANcbLHXVRD2y2lJrtFo3
+TwU3xaGqsxUHZM6TzzhshDRqa9AfZzLkIHXHoOnnip5zuTTn2HHQ91ZzggCJ4Smh
+YEQ47cu+tOIQZGfaESzjiQKBgQCCfnZlDJRq/NFwA40y4fg4arANa+eNgw7+OC5F
+1HrUvQTmIx7iLmZ0Dvv1KDgTSTLJ+MRgzczexYoUJEQnhZGS/Wq2xYt06XlBsOr1
+d/KhFxOvXllSrzrhJJqaiS6YQQ36JijZr2aKQ7UwL7fUlsmy/safWVKStumX8Hmw
+9jFOtwKBgQDmtirdNQ8aKolokD/3bDHPcDsNcybEpiCu8BIltxZAs/LsN1IIxfcp
+mGP2AFt3mbblKbsRM8hDW/X9taeG9s2KGe5wlKOE5lV8YAo4hFoJYN2/0d8Y0K9X
+QAAYU3iPG1zL+a/7TFLJ0u/biqsBg9hnNbMnN/tOeSuKnH2Rx9F1rg==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/openssl/test.pem b/crypto/test/data/openssl/test.pem
new file mode 100644
index 000000000..c52453c61
--- /dev/null
+++ b/crypto/test/data/openssl/test.pem
@@ -0,0 +1,133 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,079DD7CA8A9BAA19
+
+jIqIT0DIvUlwvkREv6gnCTVFdOsoVwUS9nxcVuQ8JOwg+TB42GnhgZ5x6MFczgNd
+Dw9L60zono+ethYfYB91CdIcVULzvg61/DCAFDjIFPgOIYTVNmteUq75Dmt6wDTV
+4A07iMwjwBk+0YHaeVwcr0AkdvXEcVySOGdGrwy10K8Eq/kSndzm1Sm6tUCJ45+v
+zSUelLlT9fgRTmAbeowT1/tlt/q52bGTcXJzIWBxDuOxK5ASCTjk28kri9WeRUb/
+iCnXn+cqR3BvkDCdlhk2A6A6Q8U9vo0m1MPtwwsolz76jnxbtBNr6Sc+zcny0brP
+jCPMP1qF+IIk01N3YsAZ9mbJmXYoFf9B0VwNUjPudWlSqhvmzzanatevgZ9TID8G
+Mnltd2XsqIgdvu0JhhEJRC6n7hBvn+l7iwYKtBoK+rJmEWWttkoP82UGgjzjzqKa
+rEtdaZPUCEiBLqHPyiIaDWm5Pe4sZZqrV8Ix8vDLKK59ZUkgmYXyCul2yL/cfO5T
+gjMqh9EeQCrNsu3hJGuEEE3MlskQkCpEspm9qDGbKPkMno7CE37plVopx0o0oovE
+S8MZn0v2lIzV8yZ6krtcEA==
+-----END DSA PRIVATE KEY-----
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,9AC3CD3B4ED42426
+
+AzAvQsDkxXGdPMlFjqO0lYXSlypkfGJWIMqij00cZI1B6K7pMnBHo3wIYStlKDg2
+SMMTYwJfsbFA8+cyCyzsqVBQC63ZgEnStMrDOt/U0SGXNb/C4mFsf1ksnAI6y/3J
+3lhuPAZbMKCmANslivbj9gp4hSe828btXDhvIPKKJgKHhwHveeW9JDulySAN5KYn
+s4aeasvSWVBOYtefFaS+NzrXjDnPtOMX6TQDxd9CE8es1RQbU9Ze2CEa9S7l4coj
+0abWVTjxu55foDCDzbukkQm+eU0aaI4OoydoOCz6bcOfADgRx3/fJ9Z9IuS5w73O
+BiF8Z4S8e7GYpgsPVEqj06PuNH7t6bwzKC9U2FTiNcejZIYPqz21d9iA4hsEfFDd
+0DlXqYUKMazE+TjU8goss5cEqyLNDQmWLYLKUE2p8QmSZC/UqEsZ9pu1VZz3xpFT
+k2sju26HCV14XPG5oi9LpxDQaVRmXBMFxz5b+RmUwPfZuWntTzHQXuNyH2J3B9FN
+el8gaskt4hxHI28hB/eF0h7pOIBUDiR9n/BB+feOrNW8y7/ThSkdI3OK0+dyOzLg
+go9s7SGz5WLyy8FWevw0k2Is4IpCueTwclDrOAPixW+paHhDGIasnvvCsz5jGqQz
+4F4JPmA2ZYg/Z8dYob/ZeF/3KuJqFZAm9gseGS19sT7UzVvvmSf5IXOFfpb7VdRn
+ScFMRVr8PY9ANGh7zYg/8w+G3JJj4C7djA3RB/yOhK4KwbTz/2cnEDI26VREjKs0
+7/WPQXxr/oQ+XEBTnYuJZfa7o7orGL+6wA0Vk/GJqjA=
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBkDCB+gIBADAlMSMwIQYDVQQDExpSZXF1ZXN0ZWQgVGVzdCBDZXJ0aWZpY2F0
+ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsO4slP/KdZQsZyYn3asTWDtX
+E1YN+QQbbHELK7boPQa91YHv5DV/SgucThoXXCtSA45d3dQhrEbZ2+HRBarZIylk
+Nc+VmcV1qFX5KsD9wCYPMtdAYYog6jz259yCOKPDXPm787Q5t9h2zV3Ml1i0eWhC
+cdRYiWHQ5g20W4Bq3GsCAwEAAaAsMCoGCSqGSIb3DQEJDjEdMBswGQYDVR0RBBIw
+EIEOdGVzdEB0ZXN0LnRlc3QwDQYJKoZIhvcNAQELBQADgYEAZGPA0Jyw49cHPJjG
+bloqKAPNlBO200AiRFsHnkOQ1DopJff3mW+FdszAc9g6rTB4/YAiM4r0E314e0vm
+XSlW2q8sp+c2XJO7PUIdJIuAUnvSmMb/uwXFP2SzLdjLcmymMsnFfjvwkht0K2it
+O5HuUDuhLnxEimGlUEBrfkdrsH0=
+-----END CERTIFICATE REQUEST-----
+-----BEGIN NEW CERTIFICATE REQUEST-----
+MIIBkDCB+gIBADAlMSMwIQYDVQQDExpSZXF1ZXN0ZWQgVGVzdCBDZXJ0aWZpY2F0
+ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsO4slP/KdZQsZyYn3asTWDtX
+E1YN+QQbbHELK7boPQa91YHv5DV/SgucThoXXCtSA45d3dQhrEbZ2+HRBarZIylk
+Nc+VmcV1qFX5KsD9wCYPMtdAYYog6jz259yCOKPDXPm787Q5t9h2zV3Ml1i0eWhC
+cdRYiWHQ5g20W4Bq3GsCAwEAAaAsMCoGCSqGSIb3DQEJDjEdMBswGQYDVR0RBBIw
+EIEOdGVzdEB0ZXN0LnRlc3QwDQYJKoZIhvcNAQELBQADgYEAZGPA0Jyw49cHPJjG
+bloqKAPNlBO200AiRFsHnkOQ1DopJff3mW+FdszAc9g6rTB4/YAiM4r0E314e0vm
+XSlW2q8sp+c2XJO7PUIdJIuAUnvSmMb/uwXFP2SzLdjLcmymMsnFfjvwkht0K2it
+O5HuUDuhLnxEimGlUEBrfkdrsH0=
+-----END NEW CERTIFICATE REQUEST-----
+-----BEGIN CERTIFICATE-----
+MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx
+ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY
+BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ
+d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2
+MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW
+BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM
+dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l
+Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv
+bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re
+Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO
+Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE
+7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy
+QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0
+ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw
+DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL
+iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4
+yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF
+5/8=
+-----END CERTIFICATE-----
+-----BEGIN X509 CERTIFICATE-----
+MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx
+ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY
+BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB
+dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ
+d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2
+MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW
+BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM
+dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l
+Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv
+bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re
+Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO
+Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE
+7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy
+QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0
+ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw
+DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL
+iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4
+yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF
+5/8=
+-----END X509 CERTIFICATE-----
+-----BEGIN ATTRIBUTE CERTIFICATE-----
+MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl
+IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy
+aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV
+BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv
+dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw
+MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV
+MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI
+NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7
+eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G
+odUBlSsJwPPQjZSU
+-----END ATTRIBUTE CERTIFICATE-----
+-----BEGIN X509 CRL-----
+MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT
+F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw
+MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw
+MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw
+MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw
+MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw
+MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw
+MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw
+NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw
+NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF
+AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ
+wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt
+JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v
+-----END X509 CRL-----
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,ADBCD679C6C6363E
+
+MmYmhTgKNKwwnA4AIskePMy+gp3Ch7Pn/UqRGjQypIyibbp/UFY+aSbQmvQNG2R9
+6Zj6cbBJGt/C2EYXk9UonUTA9Q+FVytkpR8ON6NHlSc2twrvDpqi7lpeSB9ywlH7
+WLffwNZMNsNHfcNK2slHf4RCmpqcGsXffHe45dQG0CI=
+-----END EC PRIVATE KEY-----
diff --git a/crypto/test/data/rfc4134/3.1.bin b/crypto/test/data/rfc4134/3.1.bin
new file mode 100644
index 000000000..c4e92dd7c
--- /dev/null
+++ b/crypto/test/data/rfc4134/3.1.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/3.2.bin b/crypto/test/data/rfc4134/3.2.bin
new file mode 100644
index 000000000..9c82edf72
--- /dev/null
+++ b/crypto/test/data/rfc4134/3.2.bin
@@ -0,0 +1 @@
+0+	*H
This is some sample content.
\ No newline at end of file
diff --git a/crypto/test/data/rfc4134/4.1.bin b/crypto/test/data/rfc4134/4.1.bin
new file mode 100644
index 000000000..d99f79d34
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.1.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.10.bin b/crypto/test/data/rfc4134/4.10.bin
new file mode 100644
index 000000000..d3815bdfa
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.10.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.11.bin b/crypto/test/data/rfc4134/4.11.bin
new file mode 100644
index 000000000..e203651ff
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.11.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.2.bin b/crypto/test/data/rfc4134/4.2.bin
new file mode 100644
index 000000000..c1b602413
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.2.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.3.bin b/crypto/test/data/rfc4134/4.3.bin
new file mode 100644
index 000000000..1bc6b1549
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.3.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.4.bin b/crypto/test/data/rfc4134/4.4.bin
new file mode 100644
index 000000000..3245c115d
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.4.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.5.bin b/crypto/test/data/rfc4134/4.5.bin
new file mode 100644
index 000000000..6608d9b13
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.5.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.6.bin b/crypto/test/data/rfc4134/4.6.bin
new file mode 100644
index 000000000..1a7eb9591
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.6.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.7.bin b/crypto/test/data/rfc4134/4.7.bin
new file mode 100644
index 000000000..ea6b1df67
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.7.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/4.8.eml b/crypto/test/data/rfc4134/4.8.eml
new file mode 100644
index 000000000..206ebf023
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.8.eml
@@ -0,0 +1,39 @@
+MIME-Version: 1.0
+To: User2@examples.com
+From: aliceDss@examples.com
+Subject: Example 4.8
+Message-Id: <020906002550300.249@examples.com>
+Date: Fri, 06 Sep 2002 00:25:21 -0300 
+Content-Type: multipart/signed;
+    micalg=SHA1;
+    boundary="----=_NextBoundry____Fri,_06_Sep_2002_00:25:21";
+    protocol="application/pkcs7-signature"
+
+This is a multi-part message in MIME format.
+
+------=_NextBoundry____Fri,_06_Sep_2002_00:25:21
+
+This is some sample content.
+------=_NextBoundry____Fri,_06_Sep_2002_00:25:21
+Content-Type: application/pkcs7-signature; name=smime.p7s
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7s
+
+MIIDdwYJKoZIhvcNAQcCoIIDaDCCA2QCAQExCTAHBgUrDgMCGjALBgkqhkiG9w0BBwGgggLgMIIC
+3DCCApugAwIBAgICAMgwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTMB4XDTk5MDgxNzAx
+MTA0OVoXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIQWxpY2VEU1MwggG2MIIBKwYHKoZIzjgE
+ATCCAR4CgYEAgY3N7YPqCp45PsJIKKPkR5PdDteoDuxTxauECE//lOFzSH4M1vNESNH+n6+koYkv
+4dkwyDbeP5u/t0zcX2mK5HXQNwyRCJWb3qde+fz0ny/dQ6iLVPE/sAcIR01diMPDtbPjVQh11Tl2
+EMR4vf+dsISXN/LkURu15AmWXPN+W9sCFQDiR6YaRWa4E8baj7g3IStii/eTzQKBgCY40BSJMqo5
++z5t2UtZakx2IzkEAjVc8ssaMMMeUF3dm1nizaoFPVjAe6I2uG4Hr32KQiWn9HXPSgheSz6Q+G3q
+nMkhijt2FOnOLl2jB80jhbgvMAF8bUmJEYk2RL34yJVKU1a14vlz7BphNh8Rf8K97dFQ/5h0wtGB
+SmA5ujY5A4GEAAKBgFzjuVp1FJYLqXrd4z+p7Kxe3L23ExE0phaJKBEj2TSGZ3V1ExI9Q1tv5VG/
++onyohs+JH09B41bY8i7RaWgSuOF1s4GgD/oI34a8iSrUxq4Jw0e7wi/ZhSAXGKsZfoVi/G7NNTS
+ljf2YUeyxDKE8H5BQP1Gp2NOM/Kl4vTyg+W4o4GBMH8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8E
+BAMCBsAwHwYDVR0jBBgwFoAUcEQ+gi5vh95K03XjPSC8QyuT8R8wHQYDVR0OBBYEFL5sobPjwfft
+Q3CkzhMB4v3jl/7NMB8GA1UdEQQYMBaBFEFsaWNlRFNTQGV4YW1wbGUuY29tMAkGByqGSM44BAMD
+MAAwLQIUVQykGR9CK4lxIjONg2q1PWdrv0UCFQCfYVNSVAtcst3a53Yd4hBSW0NevTFjMGECAQEw
+GDASMRAwDgYDVQQDEwdDYXJsRFNTAgIAyDAHBgUrDgMCGjAJBgcqhkjOOAQDBC4wLAIUM/mGf6gk
+gp9Z0XtRdGimJeB/BxUCFGFFJqwYRt1WYcIOQoGiaowqGzVI
+
+------=_NextBoundry____Fri,_06_Sep_2002_00:25:21--
diff --git a/crypto/test/data/rfc4134/4.9.eml b/crypto/test/data/rfc4134/4.9.eml
new file mode 100644
index 000000000..543157589
--- /dev/null
+++ b/crypto/test/data/rfc4134/4.9.eml
@@ -0,0 +1,28 @@
+MIME-Version: 1.0
+To: User2@examples.com
+From: aliceDss@examples.com
+Subject: Example 4.9
+Message-Id: <021031164540300.304@examples.com>
+Date: Thu, 31 Oct 2002 16:45:14 -0300 
+Content-Type: application/pkcs7-mime; smime-type=signed-data;
+    name=smime.p7m
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7m
+
+MIIDmQYJKoZIhvcNAQcCoIIDijCCA4YCAQExCTAHBgUrDgMCGjAtBgkqhkiG9w0BBwGgIAQeDQpU
+aGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQuoIIC4DCCAtwwggKboAMCAQICAgDIMAkGByqGSM44
+BAMwEjEQMA4GA1UEAxMHQ2FybERTUzAeFw05OTA4MTcwMTEwNDlaFw0zOTEyMzEyMzU5NTlaMBMx
+ETAPBgNVBAMTCEFsaWNlRFNTMIIBtjCCASsGByqGSM44BAEwggEeAoGBAIGNze2D6gqeOT7CSCij
+5EeT3Q7XqA7sU8WrhAhP/5Thc0h+DNbzREjR/p+vpKGJL+HZMMg23j+bv7dM3F9piuR10DcMkQiV
+m96nXvn89J8v3UOoi1TxP7AHCEdNXYjDw7Wz41UIddU5dhDEeL3/nbCElzfy5FEbteQJllzzflvb
+AhUA4kemGkVmuBPG2o+4NyErYov3k80CgYAmONAUiTKqOfs+bdlLWWpMdiM5BAI1XPLLGjDDHlBd
+3ZtZ4s2qBT1YwHuiNrhuB699ikIlp/R1z0oIXks+kPht6pzJIYo7dhTpzi5dowfNI4W4LzABfG1J
+iRGJNkS9+MiVSlNWteL5c+waYTYfEX/Cve3RUP+YdMLRgUpgObo2OQOBhAACgYBc47ladRSWC6l6
+3eM/qeysXty9txMRNKYWiSgRI9k0hmd1dRMSPUNbb+VRv/qJ8qIbPiR9PQeNW2PIu0WloErjhdbO
+BoA/6CN+GvIkq1MauCcNHu8Iv2YUgFxirGX6FYvxuzTU0pY39mFHssQyhPB+QUD9RqdjTjPypeL0
+8oPluKOBgTB/MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgbAMB8GA1UdIwQYMBaAFHBEPoIu
+b4feStN14z0gvEMrk/EfMB0GA1UdDgQWBBS+bKGz48H37UNwpM4TAeL945f+zTAfBgNVHREEGDAW
+gRRBbGljZURTU0BleGFtcGxlLmNvbTAJBgcqhkjOOAQDAzAAMC0CFFUMpBkfQiuJcSIzjYNqtT1n
+a79FAhUAn2FTUlQLXLLd2ud2HeIQUltDXr0xYzBhAgEBMBgwEjEQMA4GA1UEAxMHQ2FybERTUwIC
+AMgwBwYFKw4DAhowCQYHKoZIzjgEAwQuMCwCFD1cSW6LIUFzeXle3YI5SKSBer/sAhQmCq7s/CTF
+HOEjgASeUjbMpx5g6A==
diff --git a/crypto/test/data/rfc4134/5.1.bin b/crypto/test/data/rfc4134/5.1.bin
new file mode 100644
index 000000000..9750174a0
--- /dev/null
+++ b/crypto/test/data/rfc4134/5.1.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/5.2.bin b/crypto/test/data/rfc4134/5.2.bin
new file mode 100644
index 000000000..de17b0137
--- /dev/null
+++ b/crypto/test/data/rfc4134/5.2.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/5.3.eml b/crypto/test/data/rfc4134/5.3.eml
new file mode 100644
index 000000000..55013adcf
--- /dev/null
+++ b/crypto/test/data/rfc4134/5.3.eml
@@ -0,0 +1,19 @@
+MIME-Version: 1.0
+Message-Id: <00103112005203.00349@amyemily.ig.com>
+Date: Tue, 31 Oct 2000 12:00:52 -0600 (Central Standard Time)
+From: User1
+To: User2
+Subject: Example 5.3
+Content-Type: application/pkcs7-mime;
+	name=smime.p7m;
+	smime-type=enveloped-data
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7m
+
+MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYDVQQDEwdDYXJsUlNB
+AhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUABIGAC3EN5nGIiJi2lsGPcP2iJ97a4e8k
+bKQz36zg6Z2i0yx6zYC4mZ7mX7FBs3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadCDgO8/nUkUNYeNxJ
+tuzubGgzoyEd8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJKoZI
+hvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43LrY4OxUk660cu1lXeCSFOSOpO
+J7FuVyU=
+
diff --git a/crypto/test/data/rfc4134/6.0.bin b/crypto/test/data/rfc4134/6.0.bin
new file mode 100644
index 000000000..dfbfaaaed
--- /dev/null
+++ b/crypto/test/data/rfc4134/6.0.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/7.1.bin b/crypto/test/data/rfc4134/7.1.bin
new file mode 100644
index 000000000..9184c5852
--- /dev/null
+++ b/crypto/test/data/rfc4134/7.1.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/7.2.bin b/crypto/test/data/rfc4134/7.2.bin
new file mode 100644
index 000000000..b95b34140
--- /dev/null
+++ b/crypto/test/data/rfc4134/7.2.bin
Binary files differdiff --git a/crypto/test/data/rfc4134/AliceDSSSignByCarlNoInherit.cer b/crypto/test/data/rfc4134/AliceDSSSignByCarlNoInherit.cer
new file mode 100644
index 000000000..7e96210fc
--- /dev/null
+++ b/crypto/test/data/rfc4134/AliceDSSSignByCarlNoInherit.cer
Binary files differdiff --git a/crypto/test/data/rfc4134/AlicePrivDSSSign.pri b/crypto/test/data/rfc4134/AlicePrivDSSSign.pri
new file mode 100644
index 000000000..e123ee72d
--- /dev/null
+++ b/crypto/test/data/rfc4134/AlicePrivDSSSign.pri
Binary files differdiff --git a/crypto/test/data/rfc4134/AlicePrivRSASign.pri b/crypto/test/data/rfc4134/AlicePrivRSASign.pri
new file mode 100644
index 000000000..c885108e7
--- /dev/null
+++ b/crypto/test/data/rfc4134/AlicePrivRSASign.pri
Binary files differdiff --git a/crypto/test/data/rfc4134/AliceRSASignByCarl.cer b/crypto/test/data/rfc4134/AliceRSASignByCarl.cer
new file mode 100644
index 000000000..848ba8726
--- /dev/null
+++ b/crypto/test/data/rfc4134/AliceRSASignByCarl.cer
Binary files differdiff --git a/crypto/test/data/rfc4134/BobPrivRSAEncrypt.pri b/crypto/test/data/rfc4134/BobPrivRSAEncrypt.pri
new file mode 100644
index 000000000..b0805b84a
--- /dev/null
+++ b/crypto/test/data/rfc4134/BobPrivRSAEncrypt.pri
Binary files differdiff --git a/crypto/test/data/rfc4134/BobRSASignByCarl.cer b/crypto/test/data/rfc4134/BobRSASignByCarl.cer
new file mode 100644
index 000000000..1068ab9d4
--- /dev/null
+++ b/crypto/test/data/rfc4134/BobRSASignByCarl.cer
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlDSSCRLEmpty.crl b/crypto/test/data/rfc4134/CarlDSSCRLEmpty.crl
new file mode 100644
index 000000000..42af3a09a
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlDSSCRLEmpty.crl
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlDSSCRLForAll.crl b/crypto/test/data/rfc4134/CarlDSSCRLForAll.crl
new file mode 100644
index 000000000..52b818d4a
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlDSSCRLForAll.crl
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlDSSCRLForCarl.crl b/crypto/test/data/rfc4134/CarlDSSCRLForCarl.crl
new file mode 100644
index 000000000..2a4e79499
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlDSSCRLForCarl.crl
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlDSSSelf.cer b/crypto/test/data/rfc4134/CarlDSSSelf.cer
new file mode 100644
index 000000000..b47c682fd
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlDSSSelf.cer
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlPrivDSSSign.pri b/crypto/test/data/rfc4134/CarlPrivDSSSign.pri
new file mode 100644
index 000000000..4b1fdc00d
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlPrivDSSSign.pri
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlPrivRSASign.pri b/crypto/test/data/rfc4134/CarlPrivRSASign.pri
new file mode 100644
index 000000000..7fee220a6
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlPrivRSASign.pri
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlRSACRLEmpty.crl b/crypto/test/data/rfc4134/CarlRSACRLEmpty.crl
new file mode 100644
index 000000000..c3eb30466
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlRSACRLEmpty.crl
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlRSACRLForAll.crl b/crypto/test/data/rfc4134/CarlRSACRLForAll.crl
new file mode 100644
index 000000000..3708ccbf5
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlRSACRLForAll.crl
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlRSACRLForCarl.crl b/crypto/test/data/rfc4134/CarlRSACRLForCarl.crl
new file mode 100644
index 000000000..2ce8e4db5
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlRSACRLForCarl.crl
Binary files differdiff --git a/crypto/test/data/rfc4134/CarlRSASelf.cer b/crypto/test/data/rfc4134/CarlRSASelf.cer
new file mode 100644
index 000000000..ce6737d90
--- /dev/null
+++ b/crypto/test/data/rfc4134/CarlRSASelf.cer
Binary files differdiff --git a/crypto/test/data/rfc4134/DianeDSSSignByCarlInherit.cer b/crypto/test/data/rfc4134/DianeDSSSignByCarlInherit.cer
new file mode 100644
index 000000000..e0fa3ac75
--- /dev/null
+++ b/crypto/test/data/rfc4134/DianeDSSSignByCarlInherit.cer
Binary files differdiff --git a/crypto/test/data/rfc4134/DianePrivDSSSign.pri b/crypto/test/data/rfc4134/DianePrivDSSSign.pri
new file mode 100644
index 000000000..68ddc9594
--- /dev/null
+++ b/crypto/test/data/rfc4134/DianePrivDSSSign.pri
Binary files differdiff --git a/crypto/test/data/rfc4134/DianePrivRSASignEncrypt.pri b/crypto/test/data/rfc4134/DianePrivRSASignEncrypt.pri
new file mode 100644
index 000000000..b7bcb2953
--- /dev/null
+++ b/crypto/test/data/rfc4134/DianePrivRSASignEncrypt.pri
Binary files differdiff --git a/crypto/test/data/rfc4134/DianeRSASignByCarl.cer b/crypto/test/data/rfc4134/DianeRSASignByCarl.cer
new file mode 100644
index 000000000..062260a9d
--- /dev/null
+++ b/crypto/test/data/rfc4134/DianeRSASignByCarl.cer
Binary files differdiff --git a/crypto/test/data/rfc4134/ExContent.bin b/crypto/test/data/rfc4134/ExContent.bin
new file mode 100644
index 000000000..22ddba65c
--- /dev/null
+++ b/crypto/test/data/rfc4134/ExContent.bin
@@ -0,0 +1 @@
+This is some sample content.
\ No newline at end of file
diff --git a/crypto/test/data/rfc4134/rfc4134.txt b/crypto/test/data/rfc4134/rfc4134.txt
new file mode 100644
index 000000000..a53cec5e1
--- /dev/null
+++ b/crypto/test/data/rfc4134/rfc4134.txt
@@ -0,0 +1,7619 @@
+
+
+
+
+
+
+Network Working Group                                    P. Hoffman, Ed.
+Request for Comments: 4134                      Internet Mail Consortium
+Category: Informational                                        July 2005
+
+
+                      Examples of S/MIME Messages
+
+Status of This Memo
+
+   This memo provides information for the Internet community.  It does
+   not specify an Internet standard of any kind.  Distribution of this
+   memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2005).
+
+Abstract
+
+   This document gives examples of message bodies formatted using
+   S/MIME.  Specifically, it has examples of Cryptographic Message
+   Syntax (CMS) objects and S/MIME messages (including the MIME
+   formatting).  It includes examples of many common CMS formats.  The
+   purpose of this document is to help increase interoperability for
+   S/MIME and other protocols that rely on CMS.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                      [Page 1]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+Table of Contents
+
+   1.  Introduction ................................................   3
+   2.  Constants Used in the Examples ..............................   3
+       2.1.  Content of Documents ..................................   4
+       2.2.  Private Keys ..........................................   4
+       2.3.  Certificates ..........................................  13
+       2.4.  CRLs ..................................................  33
+   3.  Trivial Examples ............................................  39
+       3.1.  ContentInfo with Data Type, BER .......................  39
+       3.2.  ContentInfo with Data Type, DER .......................  39
+   4.  Signed-data .................................................  39
+       4.1.  Basic Signed Content, DSS .............................  39
+       4.2.  Basic Signed Content, RSA .............................  44
+       4.3.  Basic Signed Content, Detached Content ................  49
+       4.4.  Fancier Signed Content ................................  53
+       4.5.  All RSA Signed Message ................................  68
+       4.6.  Multiple Signers ......................................  75
+       4.7.  Signing Using SKI .....................................  83
+       4.8.  S/MIME multipart/signed Message .......................  87
+       4.9.  S/MIME application/pkcs7-mime Signed Message ..........  88
+       4.10. SignedData with Attributes ............................  89
+       4.11. SignedData with Certificates Only ..................... 101
+   5.  Enveloped-data .............................................. 109
+       5.1.  Basic Encrypted Content, TripleDES and RSA ............ 109
+       5.2.  Basic Encrypted Content, RC2/128 and RSA .............. 110
+       5.3.  S/MIME application/pkcs7-mime Encrypted Message ....... 112
+   6.  Digested-data ............................................... 112
+   7.  Encrypted-data .............................................. 113
+       7.1.  Simple EncryptedData .................................. 113
+       7.2.  EncryptedData with Unprotected Attributes ............. 114
+   8.  Security Considerations ..................................... 115
+   9.  References .................................................. 115
+       9.1.  Normative References .................................. 115
+       9.2.  Informative References ................................ 115
+   A.  Binaries of the Examples .................................... 116
+       A.1.  How the Binaries and Extractor Works .................. 116
+       A.2.  Example Extraction Program ............................ 116
+   B.  Examples in Order of Appearance ............................. 118
+   C.  Acknowledgements ............................................ 135
+
+
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                      [Page 2]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+1.  Introduction
+
+   The examples in this document show the structure and format of CMS
+   message bodies, as described in [CMS].  They are useful to
+   implementors who use protocols that rely on CMS, such as the S/MIME
+   message format protocol.  There are also examples of simple S/MIME
+   messages [SMIME-MSG] (including the MIME headers).
+
+   Every example in this document has been checked by two different
+   implementors.  This strongly indicates (but does not assure) that the
+   examples are correct.  All CMS implementors must read the CMS
+   document carefully before implementing from it.  No one should use
+   the examples in this document as stand-alone explanations of how to
+   create CMS message bodies.
+
+   This document explicitly does not attempt to cover many PKIX [PKIX]
+   examples.  Documents with examples of that format may be forthcoming.
+   Also, note that [DVCS], which covers PKIX Data Validation and
+   Certification Server Protocols, has examples of formats for its
+   protocol.
+
+   The examples shown here were created and validated by many different
+   people over a long period of time.  Because of this, some of the
+   dates used in the examples are many years in the past.  This, plus
+   the fact that some of the certificates in the examples have very long
+   lifespans, may cause problems in some test situations.
+
+2.  Constants Used in the Examples
+
+   This section defines the data used in the rest of the document.  The
+   names of the constants indicate their use.  For example,
+   AlicePrivDSSSign is the private part of Alice's DSS signing key.
+
+   - Alice is the creator of the message bodies in this document.
+
+   - Bob is the recipient of the messages.
+
+   - Carl is a CA.
+
+   - Diane sometimes gets involved with these folks.
+
+   - Erica also sometimes gets involved.
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                      [Page 3]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+2.1.  Content of Documents
+
+   ExContent is the following sentence:
+
+      This is some sample content.
+
+   That is, it is the string of characters starting with "T" up to and
+   including the ".".
+
+   The hex for ExContent is
+
+   5468 6973 2069 7320 736f 6d65 2073 616d 706c 6520 636f 6e74 656e 742e
+
+   The MD5 hash of ExContent is
+
+   9898 cac8 fab7 691f f89d c207 24e7 4a04
+
+   The SHA-1 hash of ExContent is
+
+   406a ec08 5279 ba6e 1602 2d9e 0629 c022 9687 dd48
+
+2.2.  Private Keys
+
+   The following private keys are needed to create the samples.  To find
+   the public keys, see the certificates in the next section.
+
+   AlicePrivDSSSign =
+      0 30  331: SEQUENCE {
+      4 02    1:   INTEGER 0
+      7 30  299:   SEQUENCE {
+     11 06    7:     OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
+               :       (ANSI X9.57 algorithm)
+     20 30  286:     SEQUENCE {
+     24 02  129:       INTEGER
+               :         00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+               :         48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+               :         53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+               :         0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+               :         2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+               :         DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+               :         9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+               :         8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+               :         C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+               :         78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+               :         B5 E4 09 96 5C F3 7E 5B DB
+    156 02   21:       INTEGER
+               :         00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+               :         B8 37 21 2B 62 8B F7 93 CD
+
+
+
+Hoffman, Ed.                 Informational                      [Page 4]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    179 02  128:       INTEGER
+               :         26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+               :         4B 59 6A 4C 76 23 39 04 02 35 5C F2
+               :         CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+               :         AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+               :         7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+               :         3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+               :         E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+               :         01 7C 6D 49 89 11 89 36 44 BD F8 C8
+               :         95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+               :         1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+               :         D1 81 4A 60 39 BA 36 39
+               :       }
+               :     }
+    310 04   23:   OCTET STRING, encapsulates {
+    312 02   21:       INTEGER
+               :         00 BB 44 46 D1 A5 C9 46 07 2E D0 FE
+               :         7A D6 92 07 F0 9A 85 89 3F
+               :       }
+               :   }
+
+   AlicePrivRSASign =
+      0 30  630: SEQUENCE {
+      4 02    1:   INTEGER 0
+      7 30   13:   SEQUENCE {
+      9 06    9:     OBJECT IDENTIFIER
+               :       rsaEncryption (1 2 840 113549 1 1 1)
+               :       (PKCS #1)
+     20 05    0:     NULL
+               :     }
+     22 04  608:   OCTET STRING, encapsulates {
+     26 30  604:       SEQUENCE {
+     30 02    1:         INTEGER 0
+     33 02  129:         INTEGER
+               :           00 E0 89 73 39 8D D8 F5 F5 E8 87 76
+               :           39 7F 4E B0 05 BB 53 83 DE 0F B7 AB
+               :           DC 7D C7 75 29 0D 05 2E 6D 12 DF A6
+               :           86 26 D4 D2 6F AA 58 29 FC 97 EC FA
+               :           82 51 0F 30 80 BE B1 50 9E 46 44 F1
+               :           2C BB D8 32 CF C6 68 6F 07 D9 B0 60
+               :           AC BE EE 34 09 6A 13 F5 F7 05 05 93
+               :           DF 5E BA 35 56 D9 61 FF 19 7F C9 81
+               :           E6 F8 6C EA 87 40 70 EF AC 6D 2C 74
+               :           9F 2D FA 55 3A B9 99 77 02 A6 48 52
+               :           8C 4E F3 57 38 57 74 57 5F
+    165 02    3:         INTEGER 65537
+    170 02  128:         INTEGER
+               :           00 A4 03 C3 27 47 76 34 34 6C A6 86
+
+
+
+Hoffman, Ed.                 Informational                      [Page 5]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           B5 79 49 01 4B 2E 8A D2 C8 62 B2 C7
+               :           D7 48 09 6A 8B 91 F7 36 F2 75 D6 E8
+               :           CD 15 90 60 27 31 47 35 64 4D 95 CD
+               :           67 63 CE B4 9F 56 AC 2F 37 6E 1C EE
+               :           0E BF 28 2D F4 39 90 6F 34 D8 6E 08
+               :           5B D5 65 6A D8 41 F3 13 D7 2D 39 5E
+               :           FE 33 CB FF 29 E4 03 0B 3D 05 A2 8F
+               :           B7 F1 8E A2 76 37 B0 79 57 D3 2F 2B
+               :           DE 87 06 22 7D 04 66 5E C9 1B AF 8B
+               :           1A C3 EC 91 44 AB 7F 21
+    301 02   65:         INTEGER
+               :           00 F6 D6 E0 22 21 4C 5F 0A 70 FF 27
+               :           FC E5 B3 50 6A 9D E5 0F B5 85 96 C6
+               :           40 FA A8 0A B4 9B 9B 0C 55 C2 01 1D
+               :           F9 37 82 8A 14 C8 F2 93 0E 92 CD A5
+               :           66 21 B9 3C D2 06 BF B4 55 31 C9 DC
+               :           AD CA 98 2D D1
+    368 02   65:         INTEGER
+               :           00 E8 DE B0 11 25 09 D2 02 51 01 DE
+               :           8A E8 98 50 F5 77 77 61 A4 45 93 6B
+               :           08 55 96 73 5D F4 C8 5B 12 93 22 73
+               :           8B 7F D3 70 7F F5 A4 AA BB 74 FD 3C
+               :           22 6A DA 38 91 2A 86 5B 6C 14 E8 AE
+               :           4C 9E FA 8E 2F
+    435 02   65:         INTEGER
+               :           00 97 4C F0 87 9B 17 7F EE 1B 83 1B
+               :           14 B6 0B 6A 90 5F 86 27 51 E1 B7 A0
+               :           7F F5 E4 88 E3 59 B9 F9 1E 9B D3 29
+               :           77 38 22 48 D7 22 B1 25 98 BA 3D 59
+               :           53 B7 FA 1E 20 B2 C8 51 16 23 75 93
+               :           51 E7 AB CD F1
+    502 02   64:         INTEGER
+               :           2C F0 24 5B FA A0 CD 85 22 EA D0 6E
+               :           4F FA 6C CD 21 D3 C8 E4 F1 84 44 48
+               :           64 73 D7 29 8F 7E 46 8C EC 15 DE E4
+               :           51 B3 94 E7 2C 99 2D 55 65 7B 24 EA
+               :           A3 62 1F 3E 6C 4D 67 41 11 3B E1 BE
+               :           E9 83 02 83
+    568 02   64:         INTEGER
+               :           58 88 D9 A1 50 38 84 6A AB 03 BC BB
+               :           DF 4B F4 9C 6F B8 B4 2A 25 FB F6 E4
+               :           05 2F 6E E2 88 89 21 6F 4B 25 9E D0
+               :           AB 50 93 CA BF 40 71 EC 21 25 C5 7F
+               :           FB 02 E9 21 96 B8 33 CD E2 C6 95 EE
+               :           6F 8D 5F 28
+               :         }
+               :       }
+               :   }
+
+
+
+Hoffman, Ed.                 Informational                      [Page 6]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+   BobPrivRSAEncrypt =
+      0 30  645: SEQUENCE {
+      4 02    1:   INTEGER 0
+      7 30   13:   SEQUENCE {
+      9 06    9:     OBJECT IDENTIFIER
+               :       rsaEncryption (1 2 840 113549 1 1 1)
+               :       (PKCS #1)
+     20 05    0:     NULL
+               :     }
+     22 04  608:   OCTET STRING, encapsulates {
+     26 30  604:       SEQUENCE {
+     30 02    1:         INTEGER 0
+     33 02  129:         INTEGER
+               :           00 A9 E1 67 98 3F 39 D5 5F F2 A0 93
+               :           41 5E A6 79 89 85 C8 35 5D 9A 91 5B
+               :           FB 1D 01 DA 19 70 26 17 0F BD A5 22
+               :           D0 35 85 6D 7A 98 66 14 41 5C CF B7
+               :           B7 08 3B 09 C9 91 B8 19 69 37 6D F9
+               :           65 1E 7B D9 A9 33 24 A3 7F 3B BB AF
+               :           46 01 86 36 34 32 CB 07 03 59 52 FC
+               :           85 8B 31 04 B8 CC 18 08 14 48 E6 4F
+               :           1C FB 5D 60 C4 E0 5C 1F 53 D3 7F 53
+               :           D8 69 01 F1 05 F8 7A 70 D1 BE 83 C6
+               :           5F 38 CF 1C 2C AA 6A A7 EB
+    165 02    3:         INTEGER 65537
+    170 02  128:         INTEGER
+               :           67 CD 48 4C 9A 0D 8F 98 C2 1B 65 FF
+               :           22 83 9C 6D F0 A6 06 1D BC ED A7 03
+               :           88 94 F2 1C 6B 0F 8B 35 DE 0E 82 78
+               :           30 CB E7 BA 6A 56 AD 77 C6 EB 51 79
+               :           70 79 0A A0 F4 FE 45 E0 A9 B2 F4 19
+               :           DA 87 98 D6 30 84 74 E4 FC 59 6C C1
+               :           C6 77 DC A9 91 D0 7C 30 A0 A2 C5 08
+               :           5E 21 71 43 FC 0D 07 3D F0 FA 6D 14
+               :           9E 4E 63 F0 17 58 79 1C 4B 98 1C 3D
+               :           3D B0 1B DF FA 25 3B A3 C0 2C 98 05
+               :           F6 10 09 D8 87 DB 03 19
+    301 02   65:         INTEGER
+               :           00 D0 C3 22 C6 DE A2 99 18 76 8F 8D
+               :           BC A6 75 D6 66 3F D4 8D 45 52 8C 76
+               :           F5 72 C4 EB F0 46 9A F1 3E 5C AA 55
+               :           0B 9B DA DD 6B 6D F8 FC 3B 3C 08 43
+               :           93 B5 5B FE CE EA FD 68 84 23 62 AF
+               :           F3 31 C2 B9 E5
+    368 02   65:         INTEGER
+               :           00 D0 51 FC 1E 22 B7 5B ED B5 8E 01
+               :           C8 D7 AB F2 58 D4 F7 82 94 F3 53 A8
+               :           19 45 CB 66 CA 28 19 5F E2 10 2B F3
+
+
+
+Hoffman, Ed.                 Informational                      [Page 7]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           8F EC 6A 30 74 F8 4D 11 F4 A7 C4 20
+               :           B5 47 21 DC 49 01 F9 0A 20 29 F0 24
+               :           08 84 60 7D 8F
+    435 02   64:         INTEGER
+               :           34 BA 64 C9 48 28 57 74 D7 55 50 DE
+               :           6A 48 EF 1B 2A 5A 1C 48 7B 1E 21 59
+               :           C3 60 3B 9B 97 A9 C0 EF 18 66 A9 4E
+               :           62 52 38 84 CE E5 09 88 48 94 69 C5
+               :           20 14 99 5A 57 FE 23 6C E4 A7 23 7B
+               :           D0 80 B7 85
+    501 02   65:         INTEGER
+               :           00 9E 2F B3 37 9A FB 0B 06 5D 57 E1
+               :           09 06 A4 5D D9 90 96 06 05 5F 24 06
+               :           40 72 9C 3A 88 85 9C 87 0F 9D 62 12
+               :           88 16 68 A8 35 1A 1B 43 E8 38 C0 98
+               :           69 AF 03 0A 48 32 04 4E E9 0F 8F 77
+               :           7D 34 30 25 07
+    568 02   64:         INTEGER
+               :           57 18 67 D6 0A D2 B5 AB C2 BA 7A E7
+               :           54 DA 9C 05 4F 81 D4 EF 01 89 1E 32
+               :           3D 69 CB 31 C4 52 C8 54 55 25 00 3B
+               :           1C 2A 7C 26 50 D5 E9 A6 D7 77 CB CF
+               :           15 F5 EE 0B D5 8D EE B3 AF 4C A1 7C
+               :           63 46 41 F6
+               :         }
+               :       }
+    634 A0   13:   [0] {
+    636 30   11:     SEQUENCE {
+    638 06    3:       OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :         (X.509 id-ce (2 5 29))
+    643 31    4:       SET {
+    645 03    2:         BIT STRING 0 unused bits
+               :           '00001000'B (bit 3)
+               :           Error: Spurious zero bits in bitstring.
+               :         }
+               :       }
+               :     }
+               :   }
+
+   CarlPrivDSSSign =
+      0 30  330: SEQUENCE {
+      4 02    1:   INTEGER 0
+      7 30  299:   SEQUENCE {
+     11 06    7:     OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
+               :       (ANSI X9.57 algorithm)
+     20 30  286:     SEQUENCE {
+     24 02  129:       INTEGER
+               :         00 B6 49 18 3E 8A 44 C1 29 71 94 4C
+
+
+
+Hoffman, Ed.                 Informational                      [Page 8]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :         01 C4 12 C1 7A 79 CB 54 4D AB 1E 81
+               :         FB C6 4C B3 0E 94 09 06 EB 01 D4 B1
+               :         C8 71 4B C7 45 C0 50 25 5D 9C FC DA
+               :         E4 6D D3 E2 86 48 84 82 7D BA 15 95
+               :         4A 16 F6 46 ED DD F6 98 D2 BB 7E 8A
+               :         0A 8A BA 16 7B B9 50 01 48 93 8B EB
+               :         25 15 51 97 55 DC 8F 53 0E 10 A9 50
+               :         FC 70 B7 CD 30 54 FD DA DE A8 AA 22
+               :         B5 A1 AF 8B CC 02 88 E7 8B 70 5F B9
+               :         AD E1 08 D4 6D 29 2D D6 E9
+    156 02   21:       INTEGER
+               :         00 DD C1 2F DF 53 CE 0B 34 60 77 3E
+               :         02 A4 BF 8A 5D 98 B9 10 D5
+    179 02  128:       INTEGER
+               :         0C EE 57 9B 4B BD DA B6 07 6A 74 37
+               :         4F 55 7F 9D ED BC 61 0D EB 46 59 3C
+               :         56 0B 2B 5B 0C 91 CE A5 62 52 69 CA
+               :         E1 6D 3E BD BF FE E1 B7 B9 2B 61 3C
+               :         AD CB AE 45 E3 06 AC 8C 22 9D 9C 44
+               :         87 0B C7 CD F0 1C D9 B5 4E 5D 73 DE
+               :         AF 0E C9 1D 5A 51 F5 4F 44 79 35 5A
+               :         73 AA 7F 46 51 1F A9 42 16 9C 48 EB
+               :         8A 79 61 B4 D5 2F 53 22 44 63 1F 86
+               :         B8 A3 58 06 25 F8 29 C0 EF BA E0 75
+               :         F0 42 C4 63 65 52 9B 0A
+               :       }
+               :     }
+    310 04   22:   OCTET STRING, encapsulates {
+    312 02   20:       INTEGER
+               :         19 B3 38 A5 21 62 31 50 E5 7F B9 3E
+               :         08 46 78 D1 3E B5 E5 72
+               :       }
+               :   }
+
+   CarlPrivRSASign =
+      0 30  630: SEQUENCE {
+      4 02    1:   INTEGER 0
+      7 30   13:   SEQUENCE {
+      9 06    9:     OBJECT IDENTIFIER
+               :       rsaEncryption (1 2 840 113549 1 1 1)
+               :       (PKCS #1)
+     20 05    0:     NULL
+               :     }
+     22 04  608:   OCTET STRING, encapsulates {
+     26 30  604:       SEQUENCE {
+     30 02    1:         INTEGER 0
+     33 02  129:         INTEGER
+               :           00 E4 4B FF 18 B8 24 57 F4 77 FF 6E
+
+
+
+Hoffman, Ed.                 Informational                      [Page 9]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           73 7B 93 71 5C BC 33 1A 92 92 72 23
+               :           D8 41 46 D0 CD 11 3A 04 B3 8E AF 82
+               :           9D BD 51 1E 17 7A F2 76 2C 2B 86 39
+               :           A7 BD D7 8D 1A 53 EC E4 00 D5 E8 EC
+               :           A2 36 B1 ED E2 50 E2 32 09 8A 3F 9F
+               :           99 25 8F B8 4E AB B9 7D D5 96 65 DA
+               :           16 A0 C5 BE 0E AE 44 5B EF 5E F4 A7
+               :           29 CB 82 DD AC 44 E9 AA 93 94 29 0E
+               :           F8 18 D6 C8 57 5E F2 76 C4 F2 11 60
+               :           38 B9 1B 3C 1D 97 C9 6A F1
+    165 02    3:         INTEGER 65537
+    170 02  129:         INTEGER
+               :           00 AE 73 E4 5B 5F 5B 66 5A C9 D7 C6
+               :           EF 38 5F 53 21 2A 2F 62 FE DE 29 9A
+               :           7A 86 67 36 E7 7D 62 78 75 3D 73 A0
+               :           BC 29 0E F3 8F BD C3 C9 C9 B6 F8 BA
+               :           D6 13 9B C3 97 7A CA 6A F0 B8 85 65
+               :           4E 0F BD A7 A8 F7 54 06 41 BD EB DC
+               :           20 77 90 DF 61 9B 9A 6F 74 DE EA 3B
+               :           D4 9C 87 60 ED 76 84 F1 6A 30 37 D5
+               :           E0 90 16 F8 80 47 C3 19 6B ED 75 77
+               :           BA 4A ED 39 B6 5D 02 47 3B 5F 1B C8
+               :           1C AB CB E8 F5 26 3F A4 81
+    302 02   65:         INTEGER
+               :           00 FF DF 09 A0 56 0B 42 52 9E C4 4D
+               :           93 B3 B0 49 BB DE E7 81 7D 28 99 D0
+               :           B1 48 BA 0B 39 E1 1C 7B 22 18 33 B6
+               :           40 F6 BF DC AE 1D D0 A1 AD 04 71 5A
+               :           61 0A 6E 3B CE 30 DA 36 9F 65 25 29
+               :           BB A7 0E 7F 0B
+    369 02   65:         INTEGER
+               :           00 E4 69 68 18 5F F9 57 D0 7C 66 89
+               :           0F BA 63 1D 72 CB 20 A4 81 76 64 89
+               :           CD 7D D1 C2 27 A9 2E AC 7A 56 9A 85
+               :           07 D9 30 03 A3 03 AB 7F 88 92 50 24
+               :           01 AA 1B 07 1F 20 4C B7 C9 7B 56 F7
+               :           B6 C2 7E AB 73
+    436 02   64:         INTEGER
+               :           57 36 6C 8F 8C 04 76 6C B6 D4 EE 24
+               :           44 00 F8 80 E2 AF 42 01 A9 0F 14 84
+               :           F8 E7 00 E0 8F 8C 27 A4 2D 5F A2 E5
+               :           6D B5 63 C0 AD 44 E9 76 91 A7 19 49
+               :           2E 46 F8 77 85 4B 3B 87 04 F0 AF D2
+               :           D8 54 26 95
+    502 02   64:         INTEGER
+               :           64 A1 0F AC 55 74 1B BD 0D 61 7B 17
+               :           03 CD B0 E6 A7 19 1D 80 AF F1 41 48
+               :           D8 1A B6 88 14 A0 2C 7A C5 76 D4 0F
+
+
+
+Hoffman, Ed.                 Informational                     [Page 10]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           0E 1F 7A 2A B2 6E 37 04 AB 39 45 73
+               :           BA 46 A8 0F 8D 82 5F 22 14 05 CF A2
+               :           A3 F3 7C 83
+    568 02   64:         INTEGER
+               :           26 1E 1D 1C A1 98 2B E4 DB 38 E8 57
+               :           6E 6B 73 19 88 61 3A FA 74 4A 36 8B
+               :           47 68 5D 50 EB 26 E3 EA 7D 9B 4E 65
+               :           A9 AF 7B AB 4B 2E 76 51 3D A8 D0 11
+               :           AB A3 D6 A8 C0 27 36 1D 54 0B AA A7
+               :           D1 6D 8D FA
+               :         }
+               :       }
+               :   }
+
+   DianePrivDSSSign =
+      0 30  331: SEQUENCE {
+      4 02    1:   INTEGER 0
+      7 30  299:   SEQUENCE {
+     11 06    7:     OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
+               :       (ANSI X9.57 algorithm)
+     20 30  286:     SEQUENCE {
+     24 02  129:       INTEGER
+               :         00 B6 49 18 3E 8A 44 C1 29 71 94 4C
+               :         01 C4 12 C1 7A 79 CB 54 4D AB 1E 81
+               :         FB C6 4C B3 0E 94 09 06 EB 01 D4 B1
+               :         C8 71 4B C7 45 C0 50 25 5D 9C FC DA
+               :         E4 6D D3 E2 86 48 84 82 7D BA 15 95
+               :         4A 16 F6 46 ED DD F6 98 D2 BB 7E 8A
+               :         0A 8A BA 16 7B B9 50 01 48 93 8B EB
+               :         25 15 51 97 55 DC 8F 53 0E 10 A9 50
+               :         FC 70 B7 CD 30 54 FD DA DE A8 AA 22
+               :         B5 A1 AF 8B CC 02 88 E7 8B 70 5F B9
+               :         AD E1 08 D4 6D 29 2D D6 E9
+    156 02   21:       INTEGER
+               :         00 DD C1 2F DF 53 CE 0B 34 60 77 3E
+               :         02 A4 BF 8A 5D 98 B9 10 D5
+    179 02  128:       INTEGER
+               :         0C EE 57 9B 4B BD DA B6 07 6A 74 37
+               :         4F 55 7F 9D ED BC 61 0D EB 46 59 3C
+               :         56 0B 2B 5B 0C 91 CE A5 62 52 69 CA
+               :         E1 6D 3E BD BF FE E1 B7 B9 2B 61 3C
+               :         AD CB AE 45 E3 06 AC 8C 22 9D 9C 44
+               :         87 0B C7 CD F0 1C D9 B5 4E 5D 73 DE
+               :         AF 0E C9 1D 5A 51 F5 4F 44 79 35 5A
+               :         73 AA 7F 46 51 1F A9 42 16 9C 48 EB
+               :         8A 79 61 B4 D5 2F 53 22 44 63 1F 86
+               :         B8 A3 58 06 25 F8 29 C0 EF BA E0 75
+               :         F0 42 C4 63 65 52 9B 0A
+
+
+
+Hoffman, Ed.                 Informational                     [Page 11]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :       }
+               :     }
+    310 04   23:   OCTET STRING, encapsulates {
+    312 02   21:       INTEGER
+               :         00 96 95 F9 E0 C1 E0 41 2D 32 0F 8B
+               :         42 52 93 2A E6 1E 0E 21 29
+               :       }
+               :   }
+
+   DianePrivRSASignEncrypt =
+      0 30  631: SEQUENCE {
+      4 02    1:   INTEGER 0
+      7 30   13:   SEQUENCE {
+      9 06    9:     OBJECT IDENTIFIER
+               :       rsaEncryption (1 2 840 113549 1 1 1)
+               :       (PKCS #1)
+     20 05    0:     NULL
+               :     }
+     22 04  609:   OCTET STRING, encapsulates {
+     26 30  605:       SEQUENCE {
+     30 02    1:         INTEGER 0
+     33 02  129:         INTEGER
+               :           00 D6 FD B8 C0 70 C6 4C 25 EC EA CF
+               :           EA 7C BB A2 62 FA F0 E6 32 3A 53 FF
+               :           B1 92 5A 17 F4 20 E1 99 24 82 0A D0
+               :           F6 7C FB 44 CA 8B 27 06 F1 7E 26 03
+               :           A9 76 9D CF EC A0 2C 70 96 F2 83 42
+               :           F6 D4 B7 28 0A BB F8 BF 4A 4C 19 3F
+               :           07 DB A0 C1 60 1E B7 7E 67 F7 DE B1
+               :           C3 60 49 AC 45 D7 F8 C6 EF 08 37 21
+               :           93 47 EE F0 73 35 72 B0 02 C4 F3 11
+               :           C3 5E 47 E5 0A B7 83 F1 DB 74 69 64
+               :           8B 44 1D 95 5D CD 28 C0 85
+    165 02    3:         INTEGER 65537
+    170 02  128:         INTEGER
+               :           3D BD CD C2 0E 61 14 5B 4B E7 BF 60
+               :           23 04 2B C5 6B 35 A5 96 45 23 FC 69
+               :           7D 93 3C 0F D3 25 96 BA 62 52 42 E2
+               :           96 CF FE 58 80 8F EB B1 8C BD D4 0D
+               :           65 D0 3A 77 45 24 9E 0C EB 86 80 C3
+               :           AC 21 11 71 44 E3 B2 A8 A9 2E AC 17
+               :           D2 A3 84 25 63 B5 BC 2F 1E DD F6 21
+               :           FF 15 20 24 5B F1 80 2F D5 41 0E 32
+               :           24 F7 D4 4A 32 9E B9 49 D8 19 8E 3F
+               :           39 8D 62 BD 80 FC 0C 24 92 93 E4 C3
+               :           D7 05 91 53 BB 96 B6 41
+    301 02   65:         INTEGER
+               :           00 F3 B8 3F 4A D1 94 B0 91 60 13 41
+
+
+
+Hoffman, Ed.                 Informational                     [Page 12]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           92 0D 8D 44 3F 77 1D FF 96 23 44 08
+               :           D4 0B 70 C9 1A AF E9 90 94 F2 B0 D5
+               :           5F 4F 19 85 50 A1 90 91 AE BD 05 76
+               :           52 B3 22 D8 A8 7C 8E 54 7F 00 72 4F
+               :           36 75 68 73 B5
+    368 02   65:         INTEGER
+               :           00 E1 D2 E7 11 57 06 AE 72 95 22 16
+               :           AA 02 B4 5A ED 4E 9D 82 11 4F 96 3C
+               :           86 C9 10 8D 56 7B 31 75 79 69 E7 75
+               :           68 38 00 4B 2E D2 26 32 DD B1 E2 E0
+               :           2C 54 80 0A 75 BA D1 66 96 1B B0 0E
+               :           A0 7E D2 BB 91
+    435 02   65:         INTEGER
+               :           00 AF B6 BC DB 22 73 43 41 EC B4 B5
+               :           67 A9 A1 99 FC EF D2 8E FD 1D FB E5
+               :           29 8B FE 0A DF D4 C8 5E 57 25 0A 5D
+               :           2B D4 09 A0 56 5B C5 B1 62 FC 20 BE
+               :           08 2D E3 07 B5 A1 E7 B3 FF C4 C0 A5
+               :           5F AC 12 5C A9
+    502 02   65:         INTEGER
+               :           00 B9 98 41 FC 08 50 1F 73 60 8A 01
+               :           A2 7C 52 8A 20 5A EA 2C 89 D9 A5 19
+               :           DD 94 C6 1B C3 25 C0 82 51 E4 EE 2B
+               :           9A 19 DC 73 ED E9 1D 27 D4 F8 6C 03
+               :           DD AB 1D 08 7B B5 AC 7F E9 82 9B F1
+               :           89 8A 71 DB 61
+    569 02   64:         INTEGER
+               :           01 07 21 97 5F 7A 60 A8 FD 5A 5C 07
+               :           DF A8 DE F7 E2 B1 34 7D FC EB 91 BD
+               :           B0 73 74 C8 C4 BE 3F 58 45 30 06 90
+               :           B3 AC 69 CC B3 F7 3F 7C AC C7 B8 1B
+               :           65 A1 16 39 39 B0 E3 74 7D CF CD C5
+               :           AC 6C BF E5
+               :         }
+               :       }
+               :   }
+
+2.3.  Certificates
+
+   AliceDSSSignByCarlNoInherit =
+      0 30  732: SEQUENCE {
+      4 30  667:   SEQUENCE {
+      8 A0    3:     [0] {
+     10 02    1:       INTEGER 2
+               :       }
+     13 02    2:     INTEGER 200
+     17 30    9:     SEQUENCE {
+     19 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 13]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :         (ANSI X9.57 algorithm)
+               :       }
+     28 30   18:     SEQUENCE {
+     30 31   16:       SET {
+     32 30   14:         SEQUENCE {
+     34 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     39 13    7:           PrintableString 'CarlDSS'
+               :           }
+               :         }
+               :       }
+     48 30   30:     SEQUENCE {
+     50 17   13:       UTCTime '990817011049Z'
+     65 17   13:       UTCTime '391231235959Z'
+               :       }
+     80 30   19:     SEQUENCE {
+     82 31   17:       SET {
+     84 30   15:         SEQUENCE {
+     86 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     91 13    8:           PrintableString 'AliceDSS'
+               :           }
+               :         }
+               :       }
+    101 30  438:     SEQUENCE {
+    105 30  299:       SEQUENCE {
+    109 06    7:         OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
+               :           (ANSI X9.57 algorithm)
+    118 30  286:         SEQUENCE {
+    122 02  129:           INTEGER
+               :             00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+               :             48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+               :             53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+               :             0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+               :             2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+               :             DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+               :             9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+               :             8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+               :             C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+               :             78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+               :             B5 E4 09 96 5C F3 7E 5B DB
+    254 02   21:           INTEGER
+               :             00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+               :             B8 37 21 2B 62 8B F7 93 CD
+    277 02  128:           INTEGER
+               :             26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+               :             4B 59 6A 4C 76 23 39 04 02 35 5C F2
+               :             CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+
+
+
+Hoffman, Ed.                 Informational                     [Page 14]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+               :             7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+               :             3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+               :             E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+               :             01 7C 6D 49 89 11 89 36 44 BD F8 C8
+               :             95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+               :             1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+               :             D1 81 4A 60 39 BA 36 39
+               :           }
+               :         }
+    408 03  132:       BIT STRING 0 unused bits, encapsulates {
+    412 02  128:           INTEGER
+               :             5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+               :             3F A9 EC AC 5E DC BD B7 13 11 34 A6
+               :             16 89 28 11 23 D9 34 86 67 75 75 13
+               :             12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+               :             1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+               :             A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+               :             7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+               :             08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+               :             F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+               :             32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+               :             F2 A5 E2 F4 F2 83 E5 B8
+               :           }
+               :       }
+    543 A3  129:     [3] {
+    546 30  127:       SEQUENCE {
+    548 30   12:         SEQUENCE {
+    550 06    3:           OBJECT IDENTIFIER
+               :             basicConstraints (2 5 29 19)
+               :             (X.509 id-ce (2 5 29))
+    555 01    1:           BOOLEAN TRUE
+    558 04    2:           OCTET STRING, encapsulates {
+    560 30    0:               SEQUENCE {}
+               :               }
+               :           }
+    562 30   14:         SEQUENCE {
+    564 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :             (X.509 id-ce (2 5 29))
+    569 01    1:           BOOLEAN TRUE
+    572 04    4:           OCTET STRING, encapsulates {
+    574 03    2:               BIT STRING 6 unused bits
+               :                 '11'B
+               :               }
+               :           }
+    578 30   31:         SEQUENCE {
+    580 06    3:           OBJECT IDENTIFIER
+               :             authorityKeyIdentifier (2 5 29 35)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 15]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             (X.509 id-ce (2 5 29))
+    585 04   24:           OCTET STRING, encapsulates {
+    587 30   22:               SEQUENCE {
+    589 80   20:                 [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                 }
+               :               }
+               :           }
+    611 30   29:         SEQUENCE {
+    613 06    3:           OBJECT IDENTIFIER
+               :             subjectKeyIdentifier (2 5 29 14)
+               :             (X.509 id-ce (2 5 29))
+    618 04   22:           OCTET STRING, encapsulates {
+    620 04   20:               OCTET STRING
+               :                 BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+               :                 13 01 E2 FD E3 97 FE CD
+               :               }
+               :           }
+    642 30   31:         SEQUENCE {
+    644 06    3:           OBJECT IDENTIFIER subjectAltName (2 5 29 17)
+               :             (X.509 id-ce (2 5 29))
+    649 04   24:           OCTET STRING, encapsulates {
+    651 30   22:               SEQUENCE {
+    653 81   20:                 [1] 'AliceDSS@example.com'
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+    675 30    9:   SEQUENCE {
+    677 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :       (ANSI X9.57 algorithm)
+               :     }
+    686 03   48:   BIT STRING 0 unused bits, encapsulates {
+    689 30   45:       SEQUENCE {
+    691 02   20:         INTEGER
+               :           55 0C A4 19 1F 42 2B 89 71 22 33 8D
+               :           83 6A B5 3D 67 6B BF 45
+    713 02   21:         INTEGER
+               :           00 9F 61 53 52 54 0B 5C B2 DD DA E7
+               :           76 1D E2 10 52 5B 43 5E BD
+               :         }
+               :       }
+               :   }
+
+   AliceRSASignByCarl =
+
+
+
+Hoffman, Ed.                 Informational                     [Page 16]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+      0 30  556: SEQUENCE {
+      4 30  405:   SEQUENCE {
+      8 A0    3:     [0] {
+     10 02    1:       INTEGER 2
+               :       }
+     13 02   16:     INTEGER
+               :       46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :       C4 10 B3 B0
+     31 30   13:     SEQUENCE {
+     33 06    9:       OBJECT IDENTIFIER
+               :         sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :         (PKCS #1)
+     44 05    0:       NULL
+               :       }
+     46 30   18:     SEQUENCE {
+     48 31   16:       SET {
+     50 30   14:         SEQUENCE {
+     52 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     57 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+     66 30   30:     SEQUENCE {
+     68 17   13:       UTCTime '990919010847Z'
+     83 17   13:       UTCTime '391231235959Z'
+               :       }
+     98 30   19:     SEQUENCE {
+    100 31   17:       SET {
+    102 30   15:         SEQUENCE {
+    104 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+    109 13    8:           PrintableString 'AliceRSA'
+               :           }
+               :         }
+               :       }
+    119 30  159:     SEQUENCE {
+    122 30   13:       SEQUENCE {
+    124 06    9:         OBJECT IDENTIFIER
+               :           rsaEncryption (1 2 840 113549 1 1 1)
+               :           (PKCS #1)
+    135 05    0:         NULL
+               :         }
+    137 03  141:       BIT STRING 0 unused bits, encapsulates {
+    141 30  137:           SEQUENCE {
+    144 02  129:             INTEGER
+               :               00 E0 89 73 39 8D D8 F5 F5 E8 87 76
+               :               39 7F 4E B0 05 BB 53 83 DE 0F B7 AB
+
+
+
+Hoffman, Ed.                 Informational                     [Page 17]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :               DC 7D C7 75 29 0D 05 2E 6D 12 DF A6
+               :               86 26 D4 D2 6F AA 58 29 FC 97 EC FA
+               :               82 51 0F 30 80 BE B1 50 9E 46 44 F1
+               :               2C BB D8 32 CF C6 68 6F 07 D9 B0 60
+               :               AC BE EE 34 09 6A 13 F5 F7 05 05 93
+               :               DF 5E BA 35 56 D9 61 FF 19 7F C9 81
+               :               E6 F8 6C EA 87 40 70 EF AC 6D 2C 74
+               :               9F 2D FA 55 3A B9 99 77 02 A6 48 52
+               :               8C 4E F3 57 38 57 74 57 5F
+    276 02    3:             INTEGER 65537
+               :             }
+               :           }
+               :       }
+    281 A3  129:     [3] {
+    284 30  127:       SEQUENCE {
+    286 30   12:         SEQUENCE {
+    288 06    3:           OBJECT IDENTIFIER
+               :             basicConstraints (2 5 29 19)
+               :             (X.509 id-ce (2 5 29))
+    293 01    1:           BOOLEAN TRUE
+    296 04    2:           OCTET STRING, encapsulates {
+    298 30    0:               SEQUENCE {}
+               :               }
+               :           }
+    300 30   14:         SEQUENCE {
+    302 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :             (X.509 id-ce (2 5 29))
+    307 01    1:           BOOLEAN TRUE
+    310 04    4:           OCTET STRING, encapsulates {
+    312 03    2:               BIT STRING 6 unused bits
+               :                 '11'B
+               :               }
+               :           }
+    316 30   31:         SEQUENCE {
+    318 06    3:           OBJECT IDENTIFIER
+               :             authorityKeyIdentifier (2 5 29 35)
+               :             (X.509 id-ce (2 5 29))
+    323 04   24:           OCTET STRING, encapsulates {
+    325 30   22:               SEQUENCE {
+    327 80   20:                 [0]
+               :                   E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                   42 37 4E 22 AE 9E 38 BB
+               :                 }
+               :               }
+               :           }
+    349 30   29:         SEQUENCE {
+    351 06    3:           OBJECT IDENTIFIER
+               :             subjectKeyIdentifier (2 5 29 14)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 18]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             (X.509 id-ce (2 5 29))
+    356 04   22:           OCTET STRING, encapsulates {
+    358 04   20:               OCTET STRING
+               :                 77 D2 B4 D1 B7 4C 8A 8A A3 CE 45 9D
+               :                 CE EC 3C A0 3A E3 FF 50
+               :               }
+               :           }
+    380 30   31:         SEQUENCE {
+    382 06    3:           OBJECT IDENTIFIER subjectAltName (2 5 29 17)
+               :             (X.509 id-ce (2 5 29))
+    387 04   24:           OCTET STRING, encapsulates {
+    389 30   22:               SEQUENCE {
+    391 81   20:                 [1] 'AliceRSA@example.com'
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+    413 30   13:   SEQUENCE {
+    415 06    9:     OBJECT IDENTIFIER
+               :       sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :       (PKCS #1)
+    426 05    0:     NULL
+               :     }
+    428 03  129:   BIT STRING 0 unused bits
+               :     3E 70 47 A8 48 CC 13 58 8F CA 51 71
+               :     6B 4E 36 18 5D 04 7E 80 B1 8D 4D CC
+               :     CA A3 8F CC 7D 56 C8 BC CF 6E B3 1C
+               :     59 A9 20 AA 05 81 A8 4E 25 AD A7 70
+               :     14 75 2F F5 C7 9B D1 0E E9 63 D2 64
+               :     B7 C6 66 6E 73 21 54 DF F4 BA 25 5D
+               :     7D 49 D3 94 6B 22 36 74 73 B8 4A EC
+               :     2F 64 ED D3 3D D2 A7 42 C5 E8 37 8A
+               :     B4 DB 9F 67 E4 BD 9F F9 FE 74 EF EA
+               :     F9 EE 63 6A D8 3F 4B 25 09 B5 D8 1A
+               :     76 AE EB 9B DB 49 B0 22
+               :   }
+
+   BobRSASignByCarl =
+      0 30  551: SEQUENCE {
+      4 30  400:   SEQUENCE {
+      8 A0    3:     [0] {
+     10 02    1:       INTEGER 2
+               :       }
+     13 02   16:     INTEGER
+               :       46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :       CD 5D 71 D0
+
+
+
+Hoffman, Ed.                 Informational                     [Page 19]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+     31 30   13:     SEQUENCE {
+     33 06    9:       OBJECT IDENTIFIER
+               :         sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :         (PKCS #1)
+     44 05    0:       NULL
+               :       }
+     46 30   18:     SEQUENCE {
+     48 31   16:       SET {
+     50 30   14:         SEQUENCE {
+     52 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     57 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+     66 30   30:     SEQUENCE {
+     68 17   13:       UTCTime '990919010902Z'
+     83 17   13:       UTCTime '391231235959Z'
+               :       }
+     98 30   17:     SEQUENCE {
+    100 31   15:       SET {
+    102 30   13:         SEQUENCE {
+    104 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+    109 13    6:           PrintableString 'BobRSA'
+               :           }
+               :         }
+               :       }
+    117 30  159:     SEQUENCE {
+    120 30   13:       SEQUENCE {
+    122 06    9:         OBJECT IDENTIFIER
+               :           rsaEncryption (1 2 840 113549 1 1 1)
+               :           (PKCS #1)
+    133 05    0:         NULL
+               :         }
+    135 03  141:       BIT STRING 0 unused bits, encapsulates {
+    139 30  137:           SEQUENCE {
+    142 02  129:             INTEGER
+               :               00 A9 E1 67 98 3F 39 D5 5F F2 A0 93
+               :               41 5E A6 79 89 85 C8 35 5D 9A 91 5B
+               :               FB 1D 01 DA 19 70 26 17 0F BD A5 22
+               :               D0 35 85 6D 7A 98 66 14 41 5C CF B7
+               :               B7 08 3B 09 C9 91 B8 19 69 37 6D F9
+               :               65 1E 7B D9 A9 33 24 A3 7F 3B BB AF
+               :               46 01 86 36 34 32 CB 07 03 59 52 FC
+               :               85 8B 31 04 B8 CC 18 08 14 48 E6 4F
+               :               1C FB 5D 60 C4 E0 5C 1F 53 D3 7F 53
+               :               D8 69 01 F1 05 F8 7A 70 D1 BE 83 C6
+
+
+
+Hoffman, Ed.                 Informational                     [Page 20]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :               5F 38 CF 1C 2C AA 6A A7 EB
+    274 02    3:             INTEGER 65537
+               :             }
+               :           }
+               :       }
+    279 A3  127:     [3] {
+    281 30  125:       SEQUENCE {
+    283 30   12:         SEQUENCE {
+    285 06    3:           OBJECT IDENTIFIER
+               :             basicConstraints (2 5 29 19)
+               :             (X.509 id-ce (2 5 29))
+    290 01    1:           BOOLEAN TRUE
+    293 04    2:           OCTET STRING, encapsulates {
+    295 30    0:               SEQUENCE {}
+               :               }
+               :           }
+    297 30   14:         SEQUENCE {
+    299 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :             (X.509 id-ce (2 5 29))
+    304 01    1:           BOOLEAN TRUE
+    307 04    4:           OCTET STRING, encapsulates {
+    309 03    2:               BIT STRING 5 unused bits
+               :                 '100'B (bit 2)
+               :               }
+               :           }
+    313 30   31:         SEQUENCE {
+    315 06    3:           OBJECT IDENTIFIER
+               :             authorityKeyIdentifier (2 5 29 35)
+               :             (X.509 id-ce (2 5 29))
+    320 04   24:           OCTET STRING, encapsulates {
+    322 30   22:               SEQUENCE {
+    324 80   20:                 [0]
+               :                   E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                   42 37 4E 22 AE 9E 38 BB
+               :                 }
+               :               }
+               :           }
+    346 30   29:         SEQUENCE {
+    348 06    3:           OBJECT IDENTIFIER
+               :             subjectKeyIdentifier (2 5 29 14)
+               :             (X.509 id-ce (2 5 29))
+    353 04   22:           OCTET STRING, encapsulates {
+    355 04   20:               OCTET STRING
+               :                 E8 F4 B8 67 D8 B3 96 A4 2A F3 11 AA
+               :                 29 D3 95 5A 86 16 B4 24
+               :               }
+               :           }
+    377 30   29:         SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 21]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    379 06    3:           OBJECT IDENTIFIER subjectAltName (2 5 29 17)
+               :             (X.509 id-ce (2 5 29))
+    384 04   22:           OCTET STRING, encapsulates {
+    386 30   20:               SEQUENCE {
+    388 81   18:                 [1] 'BobRSA@example.com'
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+    408 30   13:   SEQUENCE {
+    410 06    9:     OBJECT IDENTIFIER
+               :       sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :       (PKCS #1)
+    421 05    0:     NULL
+               :     }
+    423 03  129:   BIT STRING 0 unused bits
+               :     7B 8E 66 C5 F1 10 3F 10 20 4C 88 71
+               :     AB 7B 40 6B 21 33 FA 4A 95 DE 9D 0E
+               :     5B 6B 94 21 05 C0 F2 E1 7E 2A CD 9C
+               :     93 88 87 FB 8B B7 7E 7D 41 61 E1 E4
+               :     D6 6D F9 E2 04 55 61 45 BC 64 27 44
+               :     C0 A1 BD 59 79 D9 1D 64 3C 21 D6 45
+               :     B0 5D 68 33 92 EA AC F1 57 E5 81 7D
+               :     98 E6 35 91 A3 39 DE 77 F4 E8 1C 3B
+               :     29 DC 7F 51 07 97 F3 36 F0 50 0A DD
+               :     9B DE B6 5E 38 11 2B FB 57 EA 89 6D
+               :     AD C9 88 D8 8F CF 2B D3
+               :   }
+
+   CarlDSSSelf =
+      0 30  667: SEQUENCE {
+      4 30  602:   SEQUENCE {
+      8 A0    3:     [0] {
+     10 02    1:       INTEGER 2
+               :       }
+     13 02    1:     INTEGER 1
+     16 30    9:     SEQUENCE {
+     18 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :         (ANSI X9.57 algorithm)
+               :       }
+     27 30   18:     SEQUENCE {
+     29 31   16:       SET {
+     31 30   14:         SEQUENCE {
+     33 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     38 13    7:           PrintableString 'CarlDSS'
+
+
+
+Hoffman, Ed.                 Informational                     [Page 22]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           }
+               :         }
+               :       }
+     47 30   30:     SEQUENCE {
+     49 17   13:       UTCTime '990816225050Z'
+     64 17   13:       UTCTime '391231235959Z'
+               :       }
+     79 30   18:     SEQUENCE {
+     81 31   16:       SET {
+     83 30   14:         SEQUENCE {
+     85 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     90 13    7:           PrintableString 'CarlDSS'
+               :           }
+               :         }
+               :       }
+     99 30  439:     SEQUENCE {
+    103 30  299:       SEQUENCE {
+    107 06    7:         OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
+               :           (ANSI X9.57 algorithm)
+    116 30  286:         SEQUENCE {
+    120 02  129:           INTEGER
+               :             00 B6 49 18 3E 8A 44 C1 29 71 94 4C
+               :             01 C4 12 C1 7A 79 CB 54 4D AB 1E 81
+               :             FB C6 4C B3 0E 94 09 06 EB 01 D4 B1
+               :             C8 71 4B C7 45 C0 50 25 5D 9C FC DA
+               :             E4 6D D3 E2 86 48 84 82 7D BA 15 95
+               :             4A 16 F6 46 ED DD F6 98 D2 BB 7E 8A
+               :             0A 8A BA 16 7B B9 50 01 48 93 8B EB
+               :             25 15 51 97 55 DC 8F 53 0E 10 A9 50
+               :             FC 70 B7 CD 30 54 FD DA DE A8 AA 22
+               :             B5 A1 AF 8B CC 02 88 E7 8B 70 5F B9
+               :             AD E1 08 D4 6D 29 2D D6 E9
+    252 02   21:           INTEGER
+               :             00 DD C1 2F DF 53 CE 0B 34 60 77 3E
+               :             02 A4 BF 8A 5D 98 B9 10 D5
+    275 02  128:           INTEGER
+               :             0C EE 57 9B 4B BD DA B6 07 6A 74 37
+               :             4F 55 7F 9D ED BC 61 0D EB 46 59 3C
+               :             56 0B 2B 5B 0C 91 CE A5 62 52 69 CA
+               :             E1 6D 3E BD BF FE E1 B7 B9 2B 61 3C
+               :             AD CB AE 45 E3 06 AC 8C 22 9D 9C 44
+               :             87 0B C7 CD F0 1C D9 B5 4E 5D 73 DE
+               :             AF 0E C9 1D 5A 51 F5 4F 44 79 35 5A
+               :             73 AA 7F 46 51 1F A9 42 16 9C 48 EB
+               :             8A 79 61 B4 D5 2F 53 22 44 63 1F 86
+               :             B8 A3 58 06 25 F8 29 C0 EF BA E0 75
+               :             F0 42 C4 63 65 52 9B 0A
+
+
+
+Hoffman, Ed.                 Informational                     [Page 23]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           }
+               :         }
+    406 03  133:       BIT STRING 0 unused bits, encapsulates {
+    410 02  129:           INTEGER
+               :             00 99 87 74 27 03 66 A0 B1 C0 AD DC
+               :             2C 75 BB E1 6C 44 9C DA 21 6D 4D 47
+               :             6D B1 62 09 E9 D8 AE 1E F2 3A B4 94
+               :             B1 A3 8E 7A 9B 71 4E 00 94 C9 B4 25
+               :             4E B9 60 96 19 24 01 F3 62 0C FE 75
+               :             C0 FB CE D8 68 00 E3 FD D5 70 4F DF
+               :             23 96 19 06 94 F4 B1 61 8F 3A 57 B1
+               :             08 11 A4 0B 26 25 F0 52 76 81 EA 0B
+               :             62 0D 95 2A E6 86 BA 72 B2 A7 50 83
+               :             0B AA 27 CD 1B A9 4D 89 9A D7 8D 18
+               :             39 84 3F 8B C5 56 4D 80 7A
+               :           }
+               :       }
+    542 A3   66:     [3] {
+    544 30   64:       SEQUENCE {
+    546 30   15:         SEQUENCE {
+    548 06    3:           OBJECT IDENTIFIER
+               :             basicConstraints (2 5 29 19)
+               :             (X.509 id-ce (2 5 29))
+    553 01    1:           BOOLEAN TRUE
+    556 04    5:           OCTET STRING, encapsulates {
+    558 30    3:               SEQUENCE {
+    560 01    1:                 BOOLEAN TRUE
+               :                 }
+               :               }
+               :           }
+    563 30   14:         SEQUENCE {
+    565 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :             (X.509 id-ce (2 5 29))
+    570 01    1:           BOOLEAN TRUE
+    573 04    4:           OCTET STRING, encapsulates {
+    575 03    2:               BIT STRING 1 unused bits
+               :                 '1100001'B
+               :               }
+               :           }
+    579 30   29:         SEQUENCE {
+    581 06    3:           OBJECT IDENTIFIER
+               :             subjectKeyIdentifier (2 5 29 14)
+               :             (X.509 id-ce (2 5 29))
+    586 04   22:           OCTET STRING, encapsulates {
+    588 04   20:               OCTET STRING
+               :                 70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                 3D 20 BC 43 2B 93 F1 1F
+               :               }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 24]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           }
+               :         }
+               :       }
+               :     }
+    610 30    9:   SEQUENCE {
+    612 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :       (ANSI X9.57 algorithm)
+               :     }
+    621 03   48:   BIT STRING 0 unused bits, encapsulates {
+    624 30   45:       SEQUENCE {
+    626 02   20:         INTEGER
+               :           6B A9 F0 4E 7A 5A 79 E3 F9 BE 3D 2B
+               :           C9 06 37 E9 11 17 A1 13
+    648 02   21:         INTEGER
+               :           00 8F 34 69 2A 8B B1 3C 03 79 94 32
+               :           4D 12 1F CE 89 FB 46 B2 3B
+               :         }
+               :       }
+               :   }
+
+   CarlRSASelf =
+      0 30  491: SEQUENCE {
+      4 30  340:   SEQUENCE {
+      8 A0    3:     [0] {
+     10 02    1:       INTEGER 2
+               :       }
+     13 02   16:     INTEGER
+               :       46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :       9F F2 50 20
+     31 30   13:     SEQUENCE {
+     33 06    9:       OBJECT IDENTIFIER
+               :         sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :         (PKCS #1)
+     44 05    0:       NULL
+               :       }
+     46 30   18:     SEQUENCE {
+     48 31   16:       SET {
+     50 30   14:         SEQUENCE {
+     52 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     57 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+     66 30   30:     SEQUENCE {
+     68 17   13:       UTCTime '990818070000Z'
+     83 17   13:       UTCTime '391231235959Z'
+               :       }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 25]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+     98 30   18:     SEQUENCE {
+    100 31   16:       SET {
+    102 30   14:         SEQUENCE {
+    104 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+    109 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+    118 30  159:     SEQUENCE {
+    121 30   13:       SEQUENCE {
+    123 06    9:         OBJECT IDENTIFIER
+               :           rsaEncryption (1 2 840 113549 1 1 1)
+               :           (PKCS #1)
+    134 05    0:         NULL
+               :         }
+    136 03  141:       BIT STRING 0 unused bits, encapsulates {
+    140 30  137:           SEQUENCE {
+    143 02  129:             INTEGER
+               :               00 E4 4B FF 18 B8 24 57 F4 77 FF 6E
+               :               73 7B 93 71 5C BC 33 1A 92 92 72 23
+               :               D8 41 46 D0 CD 11 3A 04 B3 8E AF 82
+               :               9D BD 51 1E 17 7A F2 76 2C 2B 86 39
+               :               A7 BD D7 8D 1A 53 EC E4 00 D5 E8 EC
+               :               A2 36 B1 ED E2 50 E2 32 09 8A 3F 9F
+               :               99 25 8F B8 4E AB B9 7D D5 96 65 DA
+               :               16 A0 C5 BE 0E AE 44 5B EF 5E F4 A7
+               :               29 CB 82 DD AC 44 E9 AA 93 94 29 0E
+               :               F8 18 D6 C8 57 5E F2 76 C4 F2 11 60
+               :               38 B9 1B 3C 1D 97 C9 6A F1
+    275 02    3:             INTEGER 65537
+               :             }
+               :           }
+               :       }
+    280 A3   66:     [3] {
+    282 30   64:       SEQUENCE {
+    284 30   15:         SEQUENCE {
+    286 06    3:           OBJECT IDENTIFIER
+               :             basicConstraints (2 5 29 19)
+               :             (X.509 id-ce (2 5 29))
+    291 01    1:           BOOLEAN TRUE
+    294 04    5:           OCTET STRING, encapsulates {
+    296 30    3:               SEQUENCE {
+    298 01    1:                 BOOLEAN TRUE
+               :                 }
+               :               }
+               :           }
+    301 30   14:         SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 26]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    303 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :             (X.509 id-ce (2 5 29))
+    308 01    1:           BOOLEAN TRUE
+    311 04    4:           OCTET STRING, encapsulates {
+    313 03    2:               BIT STRING 1 unused bits
+               :                 '1100001'B
+               :               }
+               :           }
+    317 30   29:         SEQUENCE {
+    319 06    3:           OBJECT IDENTIFIER
+               :             subjectKeyIdentifier (2 5 29 14)
+               :             (X.509 id-ce (2 5 29))
+    324 04   22:           OCTET STRING, encapsulates {
+    326 04   20:               OCTET STRING
+               :                 E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                 42 37 4E 22 AE 9E 38 BB
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+    348 30   13:   SEQUENCE {
+    350 06    9:     OBJECT IDENTIFIER
+               :       sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :       (PKCS #1)
+    361 05    0:     NULL
+               :     }
+    363 03  129:   BIT STRING 0 unused bits
+               :     B7 9E D4 04 D3 ED 29 E4 FF 89 89 15
+               :     2E 4C DB 0C F0 48 0F 32 61 EE C4 04
+               :     EC 12 5D 2D FF 0F 64 59 7E 0A C3 ED
+               :     18 FD E3 56 40 37 A7 07 B5 F0 38 12
+               :     61 50 ED EF DD 3F E3 0B B8 61 A5 A4
+               :     9B 3C E6 9E 9C 54 9A B6 95 D6 DA 6C
+               :     3B B5 2D 45 35 9D 49 01 76 FA B9 B9
+               :     31 F9 F9 6B 12 53 A0 F5 14 60 9B 7D
+               :     CA 3E F2 53 6B B0 37 6F AD E6 74 D7
+               :     DB FA 5A EA 14 41 63 5D CD BE C8 0E
+               :     C1 DA 6A 8D 53 34 18 02
+               :   }
+
+   DianeDSSSignByCarlInherit =
+      0 30  440: SEQUENCE {
+      4 30  375:   SEQUENCE {
+      8 A0    3:     [0] {
+     10 02    1:       INTEGER 2
+               :       }
+     13 02    2:     INTEGER 210
+
+
+
+Hoffman, Ed.                 Informational                     [Page 27]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+     17 30    9:     SEQUENCE {
+     19 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :         (ANSI X9.57 algorithm)
+               :       }
+     28 30   18:     SEQUENCE {
+     30 31   16:       SET {
+     32 30   14:         SEQUENCE {
+     34 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     39 13    7:           PrintableString 'CarlDSS'
+               :           }
+               :         }
+               :       }
+     48 30   30:     SEQUENCE {
+     50 17   13:       UTCTime '990817020810Z'
+     65 17   13:       UTCTime '391231235959Z'
+               :       }
+     80 30   19:     SEQUENCE {
+     82 31   17:       SET {
+     84 30   15:         SEQUENCE {
+     86 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     91 13    8:           PrintableString 'DianeDSS'
+               :           }
+               :         }
+               :       }
+    101 30  147:     SEQUENCE {
+    104 30    9:       SEQUENCE {
+    106 06    7:         OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
+               :           (ANSI X9.57 algorithm)
+               :         }
+    115 03  133:       BIT STRING 0 unused bits, encapsulates {
+    119 02  129:           INTEGER
+               :             00 A0 00 17 78 2C EE 7E 81 53 2E 2E
+               :             61 08 0F A1 9B 51 52 1A DA 59 A8 73
+               :             2F 12 25 B6 08 CB CA EF 2A 44 76 8A
+               :             52 09 EA BD 05 22 D5 0F F6 FD 46 D7
+               :             AF 99 38 09 0E 13 CB 4F 2C DD 1C 34
+               :             F7 1C BF 25 FF 23 D3 3B 59 E7 82 97
+               :             37 BE 31 24 D8 18 C8 F3 49 39 5B B7
+               :             E2 E5 27 7E FC 8C 45 72 5B 7E 3E 8F
+               :             68 4D DD 46 7A 22 BE 8E FF CC DA 39
+               :             29 A3 39 E5 9F 43 E9 55 C9 D7 5B A6
+               :             81 67 CC C0 AA CD 2E C5 23
+               :           }
+               :       }
+    251 A3  129:     [3] {
+    254 30  127:       SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 28]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    256 30   12:         SEQUENCE {
+    258 06    3:           OBJECT IDENTIFIER
+               :             basicConstraints (2 5 29 19)
+               :             (X.509 id-ce (2 5 29))
+    263 01    1:           BOOLEAN TRUE
+    266 04    2:           OCTET STRING, encapsulates {
+    268 30    0:               SEQUENCE {}
+               :               }
+               :           }
+    270 30   14:         SEQUENCE {
+    272 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :             (X.509 id-ce (2 5 29))
+    277 01    1:           BOOLEAN TRUE
+    280 04    4:           OCTET STRING, encapsulates {
+    282 03    2:               BIT STRING 6 unused bits
+               :                 '11'B
+               :               }
+               :           }
+    286 30   31:         SEQUENCE {
+    288 06    3:           OBJECT IDENTIFIER
+               :             authorityKeyIdentifier (2 5 29 35)
+               :             (X.509 id-ce (2 5 29))
+    293 04   24:           OCTET STRING, encapsulates {
+    295 30   22:               SEQUENCE {
+    297 80   20:                 [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                 }
+               :               }
+               :           }
+    319 30   29:         SEQUENCE {
+    321 06    3:           OBJECT IDENTIFIER
+               :             subjectKeyIdentifier (2 5 29 14)
+               :             (X.509 id-ce (2 5 29))
+    326 04   22:           OCTET STRING, encapsulates {
+    328 04   20:               OCTET STRING
+               :                 64 30 99 7D 5C DC 45 0B 99 3A 52 2F
+               :                 16 BF 58 50 DD CE 2B 18
+               :               }
+               :           }
+    350 30   31:         SEQUENCE {
+    352 06    3:           OBJECT IDENTIFIER subjectAltName (2 5 29 17)
+               :             (X.509 id-ce (2 5 29))
+    357 04   24:           OCTET STRING, encapsulates {
+    359 30   22:               SEQUENCE {
+    361 81   20:                 [1] 'DianeDSS@example.com'
+               :                 }
+               :               }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 29]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           }
+               :         }
+               :       }
+               :     }
+    383 30    9:   SEQUENCE {
+    385 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :       (ANSI X9.57 algorithm)
+               :     }
+    394 03   48:   BIT STRING 0 unused bits, encapsulates {
+    397 30   45:       SEQUENCE {
+    399 02   21:         INTEGER
+               :           00 A1 1A F8 17 0E 3E 5D A8 8C F4 B6
+               :           55 33 1E 4B E3 2C AC B9 5F
+    422 02   20:         INTEGER
+               :           28 4B 10 45 58 D2 1C 9D 55 35 14 18
+               :           91 B2 3F 39 DF B5 6E D3
+               :         }
+               :       }
+               :   }
+
+   DianeRSASignByCarl =
+      0 30  556: SEQUENCE {
+      4 30  405:   SEQUENCE {
+      8 A0    3:     [0] {
+     10 02    1:       INTEGER 2
+               :       }
+     13 02   16:     INTEGER
+               :       46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :       D5 9A 30 90
+     31 30   13:     SEQUENCE {
+     33 06    9:       OBJECT IDENTIFIER
+               :         sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :         (PKCS #1)
+     44 05    0:       NULL
+               :       }
+     46 30   18:     SEQUENCE {
+     48 31   16:       SET {
+     50 30   14:         SEQUENCE {
+     52 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     57 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+     66 30   30:     SEQUENCE {
+     68 17   13:       UTCTime '990819070000Z'
+     83 17   13:       UTCTime '391231235959Z'
+               :       }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 30]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+     98 30   19:     SEQUENCE {
+    100 31   17:       SET {
+    102 30   15:         SEQUENCE {
+    104 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+    109 13    8:           PrintableString 'DianeRSA'
+               :           }
+               :         }
+               :       }
+    119 30  159:     SEQUENCE {
+    122 30   13:       SEQUENCE {
+    124 06    9:         OBJECT IDENTIFIER
+               :           rsaEncryption (1 2 840 113549 1 1 1)
+               :           (PKCS #1)
+    135 05    0:         NULL
+               :         }
+    137 03  141:       BIT STRING 0 unused bits, encapsulates {
+    141 30  137:           SEQUENCE {
+    144 02  129:             INTEGER
+               :               00 D6 FD B8 C0 70 C6 4C 25 EC EA CF
+               :               EA 7C BB A2 62 FA F0 E6 32 3A 53 FF
+               :               B1 92 5A 17 F4 20 E1 99 24 82 0A D0
+               :               F6 7C FB 44 CA 8B 27 06 F1 7E 26 03
+               :               A9 76 9D CF EC A0 2C 70 96 F2 83 42
+               :               F6 D4 B7 28 0A BB F8 BF 4A 4C 19 3F
+               :               07 DB A0 C1 60 1E B7 7E 67 F7 DE B1
+               :               C3 60 49 AC 45 D7 F8 C6 EF 08 37 21
+               :               93 47 EE F0 73 35 72 B0 02 C4 F3 11
+               :               C3 5E 47 E5 0A B7 83 F1 DB 74 69 64
+               :               8B 44 1D 95 5D CD 28 C0 85
+    276 02    3:             INTEGER 65537
+               :             }
+               :           }
+               :       }
+    281 A3  129:     [3] {
+    284 30  127:       SEQUENCE {
+    286 30   12:         SEQUENCE {
+    288 06    3:           OBJECT IDENTIFIER
+               :             basicConstraints (2 5 29 19)
+               :             (X.509 id-ce (2 5 29))
+    293 01    1:           BOOLEAN TRUE
+    296 04    2:           OCTET STRING, encapsulates {
+    298 30    0:               SEQUENCE {}
+               :               }
+               :           }
+    300 30   14:         SEQUENCE {
+    302 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
+               :             (X.509 id-ce (2 5 29))
+
+
+
+Hoffman, Ed.                 Informational                     [Page 31]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    307 01    1:           BOOLEAN TRUE
+    310 04    4:           OCTET STRING, encapsulates {
+    312 03    2:               BIT STRING 5 unused bits
+               :                 '111'B
+               :               }
+               :           }
+    316 30   31:         SEQUENCE {
+    318 06    3:           OBJECT IDENTIFIER
+               :             authorityKeyIdentifier (2 5 29 35)
+               :             (X.509 id-ce (2 5 29))
+    323 04   24:           OCTET STRING, encapsulates {
+    325 30   22:               SEQUENCE {
+    327 80   20:                 [0]
+               :                   E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                   42 37 4E 22 AE 9E 38 BB
+               :                 }
+               :               }
+               :           }
+    349 30   29:         SEQUENCE {
+    351 06    3:           OBJECT IDENTIFIER
+               :             subjectKeyIdentifier (2 5 29 14)
+               :             (X.509 id-ce (2 5 29))
+    356 04   22:           OCTET STRING, encapsulates {
+    358 04   20:               OCTET STRING
+               :                 8C F3 CB 75 0E 8D 31 F6 D4 29 DA 44
+               :                 92 75 B8 FE ED 4F 39 0C
+               :               }
+               :           }
+    380 30   31:         SEQUENCE {
+    382 06    3:           OBJECT IDENTIFIER subjectAltName (2 5 29 17)
+               :             (X.509 id-ce (2 5 29))
+    387 04   24:           OCTET STRING, encapsulates {
+    389 30   22:               SEQUENCE {
+    391 81   20:                 [1] 'DianeRSA@example.com'
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+    413 30   13:   SEQUENCE {
+    415 06    9:     OBJECT IDENTIFIER
+               :       sha1withRSAEncryption (1 2 840 113549 1 1 5)
+               :       (PKCS #1)
+    426 05    0:     NULL
+               :     }
+    428 03  129:   BIT STRING 0 unused bits
+               :     7D A6 2C B5 78 42 D6 79 F3 31 FE F6
+
+
+
+Hoffman, Ed.                 Informational                     [Page 32]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :     42 CA 0F 13 07 92 09 1B E0 6F B0 91
+               :     18 F6 BF 4A FB CC 63 79 FB 81 BF DD
+               :     97 C7 90 6B CB 0A 37 2B 41 6A 03 98
+               :     C5 1B 3E 32 C8 45 2B 86 01 9C 1C E2
+               :     36 EF 16 C1 1A 92 B8 BE 62 FB 53 3E
+               :     49 47 0B C4 B9 E4 2B 58 A6 06 83 F0
+               :     B2 A7 BB 85 7E D5 C6 DA CE 9C 7B 31
+               :     72 D7 A2 EA 41 AB 6A C0 DD 1F B9 14
+               :     44 18 CF 84 57 66 E8 C5 E6 B8 DC 2D
+               :     B3 1F 1B 28 43 36 75 7A
+               :   }
+
+2.4.  CRLs
+
+   CarlDSSCRLForAll =
+      0 30  216: SEQUENCE {
+      3 30  153:   SEQUENCE {
+      6 30    9:     SEQUENCE {
+      8 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :         (ANSI X9.57 algorithm)
+               :       }
+     17 30   18:     SEQUENCE {
+     19 31   16:       SET {
+     21 30   14:         SEQUENCE {
+     23 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     28 13    7:           PrintableString 'CarlDSS'
+               :           }
+               :         }
+               :       }
+     37 17   13:     UTCTime '990827070000Z'
+     52 30  105:     SEQUENCE {
+     54 30   19:       SEQUENCE {
+     56 02    2:         INTEGER 200
+     60 17   13:         UTCTime '990822070000Z'
+               :         }
+     75 30   19:       SEQUENCE {
+     77 02    2:         INTEGER 201
+     81 17   13:         UTCTime '990822070000Z'
+               :         }
+     96 30   19:       SEQUENCE {
+     98 02    2:         INTEGER 211
+    102 17   13:         UTCTime '990822070000Z'
+               :         }
+    117 30   19:       SEQUENCE {
+    119 02    2:         INTEGER 210
+    123 17   13:         UTCTime '990822070000Z'
+               :         }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 33]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    138 30   19:       SEQUENCE {
+    140 02    2:         INTEGER 212
+    144 17   13:         UTCTime '990824070000Z'
+               :         }
+               :       }
+               :     }
+    159 30    9:   SEQUENCE {
+    161 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :       (ANSI X9.57 algorithm)
+               :     }
+    170 03   47:   BIT STRING 0 unused bits, encapsulates {
+    173 30   44:       SEQUENCE {
+    175 02   20:         INTEGER
+               :           7E 65 52 76 33 FE 34 73 17 D1 F7 96
+               :           F9 A0 D4 D8 6D 5C 7D 3D
+    197 02   20:         INTEGER
+               :           02 7A 5B B7 D5 5B 18 C1 CF 87 EF 7E
+               :           DA 24 F3 2A 83 9C 35 A1
+               :         }
+               :       }
+               :   }
+
+   CarlDSSCRLForCarl =
+      0 30  131: SEQUENCE {
+      3 30   68:   SEQUENCE {
+      5 30    9:     SEQUENCE {
+      7 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :         (ANSI X9.57 algorithm)
+               :       }
+     16 30   18:     SEQUENCE {
+     18 31   16:       SET {
+     20 30   14:         SEQUENCE {
+     22 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     27 13    7:           PrintableString 'CarlDSS'
+               :           }
+               :         }
+               :       }
+     36 17   13:     UTCTime '990825070000Z'
+     51 30   20:     SEQUENCE {
+     53 30   18:       SEQUENCE {
+     55 02    1:         INTEGER 1
+     58 17   13:         UTCTime '990822070000Z'
+               :         }
+               :       }
+               :     }
+     73 30    9:   SEQUENCE {
+     75 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 34]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :       (ANSI X9.57 algorithm)
+               :     }
+     84 03   48:   BIT STRING 0 unused bits, encapsulates {
+     87 30   45:       SEQUENCE {
+     89 02   21:         INTEGER
+               :           00 B3 1F C5 4F 7A 3D EC 76 D5 60 F9
+               :           DE 79 22 EC 4F B0 90 FE 97
+    112 02   20:         INTEGER
+               :           5A 8B C3 84 BC 66 87 1B BF 79 82 5B
+               :           0A 5D 07 F6 BA A9 05 29
+               :         }
+               :       }
+               :   }
+
+   CarlDSSCRLEmpty =
+      0 30  109: SEQUENCE {
+      2 30   46:   SEQUENCE {
+      4 30    9:     SEQUENCE {
+      6 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :         (ANSI X9.57 algorithm)
+               :       }
+     15 30   18:     SEQUENCE {
+     17 31   16:       SET {
+     19 30   14:         SEQUENCE {
+     21 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     26 13    7:           PrintableString 'CarlDSS'
+               :           }
+               :         }
+               :       }
+     35 17   13:     UTCTime '990820070000Z'
+               :     }
+     50 30    9:   SEQUENCE {
+     52 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
+               :       (ANSI X9.57 algorithm)
+               :     }
+     61 03   48:   BIT STRING 0 unused bits, encapsulates {
+     64 30   45:       SEQUENCE {
+     66 02   20:         INTEGER
+               :           62 3F 36 17 31 58 2E 67 50 79 F5 09
+               :           4B 8C AD D4 6B F4 64 9F
+     88 02   21:         INTEGER
+               :           00 B5 3B 4E A1 4C 7B FD 0F C3 8D 9B
+               :           B6 FE C3 5D 6F DE 65 28 7D
+               :         }
+               :       }
+               :   }
+
+
+
+
+Hoffman, Ed.                 Informational                     [Page 35]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+   CarlRSACRLForAll =
+      0 30  307: SEQUENCE {
+      4 30  157:   SEQUENCE {
+      7 30   13:     SEQUENCE {
+      9 06    9:       OBJECT IDENTIFIER
+               :         md5withRSAEncryption (1 2 840 113549 1 1 4)
+               :         (PKCS #1)
+     20 05    0:       NULL
+               :       }
+     22 30   18:     SEQUENCE {
+     24 31   16:       SET {
+     26 30   14:         SEQUENCE {
+     28 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     33 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+     42 17   13:     UTCTime '990827070000Z'
+     57 30  105:     SEQUENCE {
+     59 30   33:       SEQUENCE {
+     61 02   16:         INTEGER
+               :           46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :           C4 10 B3 B0
+     79 17   13:         UTCTime '990822070000Z'
+               :         }
+     94 30   33:       SEQUENCE {
+     96 02   16:         INTEGER
+               :           46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :           D5 9A 30 90
+    114 17   13:         UTCTime '990822070000Z'
+               :         }
+    129 30   33:       SEQUENCE {
+    131 02   16:         INTEGER
+               :           46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :           CD 5D 71 D0
+    149 17   13:         UTCTime '990824070000Z'
+               :         }
+               :       }
+               :     }
+    164 30   13:   SEQUENCE {
+    166 06    9:     OBJECT IDENTIFIER
+               :       md5withRSAEncryption (1 2 840 113549 1 1 4)
+               :       (PKCS #1)
+    177 05    0:     NULL
+               :     }
+    179 03  129:   BIT STRING 0 unused bits
+               :     BF B3 97 AA 53 F0 32 21 16 2B 77 92
+
+
+
+Hoffman, Ed.                 Informational                     [Page 36]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :     7A 6B BB 97 C8 DC EA F1 FA 66 16 30
+               :     0E B5 9E 5C F0 81 D4 5E B3 6E C1 88
+               :     6B 8C D4 5E C5 4D FB 47 5E 66 F3 5D
+               :     AB E5 B4 18 36 60 A8 4D 9C 3C 89 EC
+               :     6F 27 BF 35 50 71 81 C2 B9 44 5B 62
+               :     89 19 12 31 A9 7B 9A D3 CC 66 CB 11
+               :     D9 0B 10 47 77 AD 4F 22 D9 E5 7F 30
+               :     F2 5B FC 94 51 A5 58 76 3B 1F A8 46
+               :     A6 1F F6 A1 DE 55 A1 ED 31 88 69 97
+               :     0F 08 D3 D4 0C 60 5B 1E
+               :   }
+
+   CarlRSACRLForCarl =
+      0 30  236: SEQUENCE {
+      3 30   87:   SEQUENCE {
+      5 30   13:     SEQUENCE {
+      7 06    9:       OBJECT IDENTIFIER
+               :         md5withRSAEncryption (1 2 840 113549 1 1 4)
+               :         (PKCS #1)
+     18 05    0:       NULL
+               :       }
+     20 30   18:     SEQUENCE {
+     22 31   16:       SET {
+     24 30   14:         SEQUENCE {
+     26 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     31 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+     40 17   13:     UTCTime '990825070000Z'
+     55 30   35:     SEQUENCE {
+     57 30   33:       SEQUENCE {
+     59 02   16:         INTEGER
+               :           46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :           9F F2 50 20
+     77 17   13:         UTCTime '990822070000Z'
+               :         }
+               :       }
+               :     }
+     92 30   13:   SEQUENCE {
+     94 06    9:     OBJECT IDENTIFIER
+               :       md5withRSAEncryption (1 2 840 113549 1 1 4)
+               :       (PKCS #1)
+    105 05    0:     NULL
+               :     }
+    107 03  129:   BIT STRING 0 unused bits
+               :     21 EF 21 D4 C1 1A 85 95 49 6B CA 45
+
+
+
+Hoffman, Ed.                 Informational                     [Page 37]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :     62 DC D7 09 FF A9 51 2E 8E D9 47 18
+               :     FA F8 E5 72 DD 4F ED 74 74 E3 F3 65
+               :     32 65 28 2C 9A 1D 57 E5 D5 26 06 EA
+               :     D5 E6 23 95 84 8D 0E 89 9E EE 9B 0C
+               :     2F CE 07 F7 A3 D1 6B 85 4C 0F FF E6
+               :     DD FC DC CD 73 2C 1E 7D DC B0 71 C5
+               :     4C FC 01 6E 52 57 69 1E 39 63 DF 12
+               :     22 30 C7 13 55 94 05 6E 2A 00 A9 5B
+               :     C4 2A 66 94 62 CE 36 33 C2 2B 63 47
+               :     25 9D F3 DE 70 EE 00 56
+               :   }
+
+   CarlRSACRLEmpty =
+      0 30  199: SEQUENCE {
+      3 30   50:   SEQUENCE {
+      5 30   13:     SEQUENCE {
+      7 06    9:       OBJECT IDENTIFIER
+               :         md5withRSAEncryption (1 2 840 113549 1 1 4)
+               :         (PKCS #1)
+     18 05    0:       NULL
+               :       }
+     20 30   18:     SEQUENCE {
+     22 31   16:       SET {
+     24 30   14:         SEQUENCE {
+     26 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
+               :             (X.520 id-at (2 5 4))
+     31 13    7:           PrintableString 'CarlRSA'
+               :           }
+               :         }
+               :       }
+     40 17   13:     UTCTime '990820070000Z'
+               :     }
+     55 30   13:   SEQUENCE {
+     57 06    9:     OBJECT IDENTIFIER
+               :       md5withRSAEncryption (1 2 840 113549 1 1 4)
+               :       (PKCS #1)
+     68 05    0:     NULL
+               :     }
+     70 03  129:   BIT STRING 0 unused bits
+               :     A9 C5 21 B8 13 7C 74 F3 B5 11 EC 04
+               :     F3 20 45 86 1E 0B 6E 7F 83 6D 5F F4
+               :     34 76 06 59 25 0E 04 3D 88 09 88 81
+               :     37 C4 DC 20 98 FA 17 81 0B 37 94 AC
+               :     B4 8F 7B 51 89 14 A4 CB 72 73 14 07
+               :     BC 22 9C 40 A1 07 FC 44 7C 85 0F 0B
+               :     88 D1 EE E1 0E AF F6 16 74 AD A1 AF
+               :     C1 00 75 00 64 EA A5 9A F6 0B 08 A2
+               :     DB 95 19 5F A6 A7 B9 39 45 25 0A 0E
+
+
+
+Hoffman, Ed.                 Informational                     [Page 38]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :     F6 5E 84 E7 F8 B9 5A C9 18 C2 0E B8
+               :     A0 96 BE 81 3A 80 6D C9
+               :   }
+
+3.  Trivial Examples
+
+   This section covers examples of small CMS types.
+
+3.1.  ContentInfo with Data Type, BER
+
+   The object is a ContentInfo containing a Data object in BER format
+   that is ExContent.
+
+      0 30 NDEF: SEQUENCE {
+      2 06    9:   OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :     (PKCS #7)
+     13 A0 NDEF:   [0] {
+     15 24 NDEF:     OCTET STRING {
+     17 04    4:       OCTET STRING 'This'
+     23 04   24:       OCTET STRING ' is some sample content.'
+               :       }
+               :     }
+               :   }
+
+3.2.  ContentInfo with Data Type, DER
+
+   The object is a ContentInfo containing a Data object in DER format
+   that is ExContent.
+
+      0 30   43: SEQUENCE {
+      2 06    9:   OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :     (PKCS #7)
+     13 A0   30:   [0] {
+     15 04   28:     OCTET STRING 'This is some sample content.'
+               :     }
+               :   }
+
+4.  Signed-data
+
+4.1.  Basic Signed Content, DSS
+
+   A SignedData with no attribute certificates, signed by Alice using
+   DSS, just her certificate (not Carl's root cert), no CRL.  The
+   message is ExContent, and is included in the eContent.  There are no
+   signed or unsigned attributes.
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                     [Page 39]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+      0 30  919: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+               :     (PKCS #7)
+     15 A0  904:   [0] {
+     19 30  900:     SEQUENCE {
+     23 02    1:       INTEGER 1
+     26 31    9:       SET {
+     28 30    7:         SEQUENCE {
+     30 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :             (OIW)
+               :           }
+               :         }
+     37 30   43:       SEQUENCE {
+     39 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     50 A0   30:         [0] {
+     52 04   28:           OCTET STRING 'This is some sample content.'
+               :           }
+               :         }
+     82 A0  736:       [0] {
+     86 30  732:         SEQUENCE {
+     90 30  667:           SEQUENCE {
+     94 A0    3:             [0] {
+     96 02    1:               INTEGER 2
+               :               }
+     99 02    2:             INTEGER 200
+    103 30    9:             SEQUENCE {
+    105 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+    114 30   18:             SEQUENCE {
+    116 31   16:               SET {
+    118 30   14:                 SEQUENCE {
+    120 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    125 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+    134 30   30:             SEQUENCE {
+    136 17   13:               UTCTime '990817011049Z'
+    151 17   13:               UTCTime '391231235959Z'
+               :               }
+    166 30   19:             SEQUENCE {
+    168 31   17:               SET {
+    170 30   15:                 SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 40]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    172 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    177 13    8:                   PrintableString 'AliceDSS'
+               :                   }
+               :                 }
+               :               }
+    187 30  438:             SEQUENCE {
+    191 30  299:               SEQUENCE {
+    195 06    7:                 OBJECT IDENTIFIER
+               :                   dsa (1 2 840 10040 4 1)
+               :                   (ANSI X9.57 algorithm)
+    204 30  286:                 SEQUENCE {
+    208 02  129:                   INTEGER
+               :                   00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+               :                   48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+               :                   53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+               :                   0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+               :                   2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+               :                   DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+               :                   9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+               :                   8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+               :                   C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+               :                   78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+               :                   B5 E4 09 96 5C F3 7E 5B DB
+    340 02   21:                   INTEGER
+               :                   00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+               :                   B8 37 21 2B 62 8B F7 93 CD
+    363 02  128:                   INTEGER
+               :                   26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+               :                   4B 59 6A 4C 76 23 39 04 02 35 5C F2
+               :                   CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+               :                   AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+               :                   7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+               :                   3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+               :                   E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+               :                   01 7C 6D 49 89 11 89 36 44 BD F8 C8
+               :                   95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+               :                   1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+               :                   D1 81 4A 60 39 BA 36 39
+               :                   }
+               :                 }
+    494 03  132:               BIT STRING 0 unused bits, encapsulates {
+    498 02  128:                   INTEGER
+               :                   5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+               :                   3F A9 EC AC 5E DC BD B7 13 11 34 A6
+               :                   16 89 28 11 23 D9 34 86 67 75 75 13
+               :                   12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+
+
+
+Hoffman, Ed.                 Informational                     [Page 41]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+               :                   A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+               :                   7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+               :                   08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+               :                   F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+               :                   32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+               :                   F2 A5 E2 F4 F2 83 E5 B8
+               :                   }
+               :               }
+    629 A3  129:             [3] {
+    632 30  127:               SEQUENCE {
+    634 30   12:                 SEQUENCE {
+    636 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+    641 01    1:                   BOOLEAN TRUE
+    644 04    2:                   OCTET STRING, encapsulates {
+    646 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+    648 30   14:                 SEQUENCE {
+    650 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    655 01    1:                   BOOLEAN TRUE
+    658 04    4:                   OCTET STRING, encapsulates {
+    660 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+    664 30   31:                 SEQUENCE {
+    666 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+    671 04   24:                   OCTET STRING, encapsulates {
+    673 30   22:                       SEQUENCE {
+    675 80   20:                         [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                         }
+               :                       }
+               :                   }
+    697 30   29:                 SEQUENCE {
+    699 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    704 04   22:                   OCTET STRING, encapsulates {
+    706 04   20:                       OCTET STRING
+
+
+
+Hoffman, Ed.                 Informational                     [Page 42]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+               :                   13 01 E2 FD E3 97 FE CD
+               :                       }
+               :                   }
+    728 30   31:                 SEQUENCE {
+    730 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+    735 04   24:                   OCTET STRING, encapsulates {
+    737 30   22:                       SEQUENCE {
+    739 81   20:                         [1] 'AliceDSS@example.com'
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+    761 30    9:           SEQUENCE {
+    763 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+    772 03   48:           BIT STRING 0 unused bits, encapsulates {
+    775 30   45:               SEQUENCE {
+    777 02   20:                 INTEGER
+               :                   55 0C A4 19 1F 42 2B 89 71 22 33 8D
+               :                   83 6A B5 3D 67 6B BF 45
+    799 02   21:                 INTEGER
+               :                   00 9F 61 53 52 54 0B 5C B2 DD DA E7
+               :                   76 1D E2 10 52 5B 43 5E BD
+               :                 }
+               :               }
+               :           }
+               :         }
+    822 31   99:       SET {
+    824 30   97:         SEQUENCE {
+    826 02    1:           INTEGER 1
+    829 30   24:           SEQUENCE {
+    831 30   18:             SEQUENCE {
+    833 31   16:               SET {
+    835 30   14:                 SEQUENCE {
+    837 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    842 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 43]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    851 02    2:             INTEGER 200
+               :             }
+    855 30    7:           SEQUENCE {
+    857 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+               :             }
+    864 30    9:           SEQUENCE {
+    866 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+    875 04   46:           OCTET STRING, encapsulates {
+    877 30   44:               SEQUENCE {
+    879 02   20:                 INTEGER
+               :                   09 91 FE EB D2 69 F5 18 B7 D7 CD 55
+               :                   F4 81 EA 2A 42 6A AD 03
+    901 02   20:                 INTEGER
+               :                   3A 07 CC C3 21 BE E1 1A 4B 7F 3E B5
+               :                   0D DB BA 1C EA BC CD 89
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+               :   }
+
+4.2.  Basic Signed Content, RSA
+
+   Same as 4.1, except using RSA signatures.  A SignedData with no
+   attribute certificates, signed by Alice using RSA, just her
+   certificate (not Carl's root cert), no CRL.  The message is
+   ExContent, and is included in the eContent.  There are no signed or
+   unsigned attributes.
+
+      0 30  850: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+               :     (PKCS #7)
+     15 A0  835:   [0] {
+     19 30  831:     SEQUENCE {
+     23 02    1:       INTEGER 1
+     26 31   11:       SET {
+     28 30    9:         SEQUENCE {
+     30 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :             (OIW)
+     37 05    0:           NULL
+               :           }
+               :         }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 44]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+     39 30   43:       SEQUENCE {
+     41 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     52 A0   30:         [0] {
+     54 04   28:           OCTET STRING 'This is some sample content.'
+               :           }
+               :         }
+     84 A0  560:       [0] {
+     88 30  556:         SEQUENCE {
+     92 30  405:           SEQUENCE {
+     96 A0    3:             [0] {
+     98 02    1:               INTEGER 2
+               :               }
+    101 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               C4 10 B3 B0
+    119 30   13:             SEQUENCE {
+    121 06    9:               OBJECT IDENTIFIER
+               :                 sha1withRSAEncryption
+               :                     (1 2 840 113549 1 1 5)
+               :                 (PKCS #1)
+    132 05    0:               NULL
+               :               }
+    134 30   18:             SEQUENCE {
+    136 31   16:               SET {
+    138 30   14:                 SEQUENCE {
+    140 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    145 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+    154 30   30:             SEQUENCE {
+    156 17   13:               UTCTime '990919010847Z'
+    171 17   13:               UTCTime '391231235959Z'
+               :               }
+    186 30   19:             SEQUENCE {
+    188 31   17:               SET {
+    190 30   15:                 SEQUENCE {
+    192 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    197 13    8:                   PrintableString 'AliceRSA'
+               :                   }
+               :                 }
+               :               }
+    207 30  159:             SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 45]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    210 30   13:               SEQUENCE {
+    212 06    9:                 OBJECT IDENTIFIER
+               :                   rsaEncryption (1 2 840 113549 1 1 1)
+               :                   (PKCS #1)
+    223 05    0:                 NULL
+               :                 }
+    225 03  141:               BIT STRING 0 unused bits, encapsulates {
+    229 30  137:                   SEQUENCE {
+    232 02  129:                     INTEGER
+               :                   00 E0 89 73 39 8D D8 F5 F5 E8 87 76
+               :                   39 7F 4E B0 05 BB 53 83 DE 0F B7 AB
+               :                   DC 7D C7 75 29 0D 05 2E 6D 12 DF A6
+               :                   86 26 D4 D2 6F AA 58 29 FC 97 EC FA
+               :                   82 51 0F 30 80 BE B1 50 9E 46 44 F1
+               :                   2C BB D8 32 CF C6 68 6F 07 D9 B0 60
+               :                   AC BE EE 34 09 6A 13 F5 F7 05 05 93
+               :                   DF 5E BA 35 56 D9 61 FF 19 7F C9 81
+               :                   E6 F8 6C EA 87 40 70 EF AC 6D 2C 74
+               :                   9F 2D FA 55 3A B9 99 77 02 A6 48 52
+               :                   8C 4E F3 57 38 57 74 57 5F
+    364 02    3:                     INTEGER 65537
+               :                     }
+               :                   }
+               :               }
+    369 A3  129:             [3] {
+    372 30  127:               SEQUENCE {
+    374 30   12:                 SEQUENCE {
+    376 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+    381 01    1:                   BOOLEAN TRUE
+    384 04    2:                   OCTET STRING, encapsulates {
+    386 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+    388 30   14:                 SEQUENCE {
+    390 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    395 01    1:                   BOOLEAN TRUE
+    398 04    4:                   OCTET STRING, encapsulates {
+    400 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+    404 30   31:                 SEQUENCE {
+    406 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 46]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                     (X.509 id-ce (2 5 29))
+    411 04   24:                   OCTET STRING, encapsulates {
+    413 30   22:                       SEQUENCE {
+    415 80   20:                         [0]
+               :                   E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                   42 37 4E 22 AE 9E 38 BB
+               :                         }
+               :                       }
+               :                   }
+    437 30   29:                 SEQUENCE {
+    439 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    444 04   22:                   OCTET STRING, encapsulates {
+    446 04   20:                       OCTET STRING
+               :                   77 D2 B4 D1 B7 4C 8A 8A A3 CE 45 9D
+               :                   CE EC 3C A0 3A E3 FF 50
+               :                       }
+               :                   }
+    468 30   31:                 SEQUENCE {
+    470 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+    475 04   24:                   OCTET STRING, encapsulates {
+    477 30   22:                       SEQUENCE {
+    479 81   20:                         [1] 'AliceRSA@example.com'
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+    501 30   13:           SEQUENCE {
+    503 06    9:             OBJECT IDENTIFIER
+               :               sha1withRSAEncryption
+               :                   (1 2 840 113549 1 1 5)
+               :               (PKCS #1)
+    514 05    0:             NULL
+               :             }
+    516 03  129:           BIT STRING 0 unused bits
+               :             3E 70 47 A8 48 CC 13 58 8F CA 51 71
+               :             6B 4E 36 18 5D 04 7E 80 B1 8D 4D CC
+               :             CA A3 8F CC 7D 56 C8 BC CF 6E B3 1C
+               :             59 A9 20 AA 05 81 A8 4E 25 AD A7 70
+               :             14 75 2F F5 C7 9B D1 0E E9 63 D2 64
+               :             B7 C6 66 6E 73 21 54 DF F4 BA 25 5D
+               :             7D 49 D3 94 6B 22 36 74 73 B8 4A EC
+               :             2F 64 ED D3 3D D2 A7 42 C5 E8 37 8A
+
+
+
+Hoffman, Ed.                 Informational                     [Page 47]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             B4 DB 9F 67 E4 BD 9F F9 FE 74 EF EA
+               :             F9 EE 63 6A D8 3F 4B 25 09 B5 D8 1A
+               :             76 AE EB 9B DB 49 B0 22
+               :           }
+               :         }
+    648 31  203:       SET {
+    651 30  200:         SEQUENCE {
+    654 02    1:           INTEGER 1
+    657 30   38:           SEQUENCE {
+    659 30   18:             SEQUENCE {
+    661 31   16:               SET {
+    663 30   14:                 SEQUENCE {
+    665 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    670 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+    679 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               C4 10 B3 B0
+               :             }
+    697 30    9:           SEQUENCE {
+    699 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+    706 05    0:             NULL
+               :             }
+    708 30   13:           SEQUENCE {
+    710 06    9:             OBJECT IDENTIFIER
+               :               rsaEncryption (1 2 840 113549 1 1 1)
+               :               (PKCS #1)
+    721 05    0:             NULL
+               :             }
+    723 04  128:           OCTET STRING
+               :             2F 23 82 D2 F3 09 5F B8 0C 58 EB 4E
+               :             9D BF 89 9A 81 E5 75 C4 91 3D D3 D0
+               :             D5 7B B6 D5 FE 94 A1 8A AC E3 C4 84
+               :             F5 CD 60 4E 27 95 F6 CF 00 86 76 75
+               :             3F 2B F0 E7 D4 02 67 A7 F5 C7 8D 16
+               :             04 A5 B3 B5 E7 D9 32 F0 24 EF E7 20
+               :             44 D5 9F 07 C5 53 24 FA CE 01 1D 0F
+               :             17 13 A7 2A 95 9D 2B E4 03 95 14 0B
+               :             E9 39 0D BA CE 6E 9C 9E 0C E8 98 E6
+               :             55 13 D4 68 6F D0 07 D7 A2 B1 62 4C
+               :             E3 8F AF FD E0 D5 5D C7
+               :           }
+               :         }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 48]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :       }
+               :     }
+               :   }
+
+4.3.  Basic Signed Content, Detached Content
+
+   Same as 4.1, except with no eContent.  A SignedData with no attribute
+   certificates, signed by Alice using DSS, just her certificate (not
+   Carl's root cert), no CRL.  The message is ExContent, but the
+   eContent is not included.  There are no signed or unsigned
+   attributes.
+
+      0 30  887: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+               :     (PKCS #7)
+     15 A0  872:   [0] {
+     19 30  868:     SEQUENCE {
+     23 02    1:       INTEGER 1
+     26 31    9:       SET {
+     28 30    7:         SEQUENCE {
+     30 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :             (OIW)
+               :           }
+               :         }
+     37 30   11:       SEQUENCE {
+     39 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+               :         }
+     50 A0  736:       [0] {
+     54 30  732:         SEQUENCE {
+     58 30  667:           SEQUENCE {
+     62 A0    3:             [0] {
+     64 02    1:               INTEGER 2
+               :               }
+     67 02    2:             INTEGER 200
+     71 30    9:             SEQUENCE {
+     73 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+     82 30   18:             SEQUENCE {
+     84 31   16:               SET {
+     86 30   14:                 SEQUENCE {
+     88 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+     93 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 49]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                 }
+               :               }
+    102 30   30:             SEQUENCE {
+    104 17   13:               UTCTime '990817011049Z'
+    119 17   13:               UTCTime '391231235959Z'
+               :               }
+    134 30   19:             SEQUENCE {
+    136 31   17:               SET {
+    138 30   15:                 SEQUENCE {
+    140 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    145 13    8:                   PrintableString 'AliceDSS'
+               :                   }
+               :                 }
+               :               }
+    155 30  438:             SEQUENCE {
+    159 30  299:               SEQUENCE {
+    163 06    7:                 OBJECT IDENTIFIER
+               :                   dsa (1 2 840 10040 4 1)
+               :                   (ANSI X9.57 algorithm)
+    172 30  286:                 SEQUENCE {
+    176 02  129:                   INTEGER
+               :                   00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+               :                   48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+               :                   53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+               :                   0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+               :                   2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+               :                   DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+               :                   9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+               :                   8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+               :                   C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+               :                   78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+               :                   B5 E4 09 96 5C F3 7E 5B DB
+    308 02   21:                   INTEGER
+               :                   00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+               :                   B8 37 21 2B 62 8B F7 93 CD
+    331 02  128:                   INTEGER
+               :                   26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+               :                   4B 59 6A 4C 76 23 39 04 02 35 5C F2
+               :                   CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+               :                   AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+               :                   7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+               :                   3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+               :                   E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+               :                   01 7C 6D 49 89 11 89 36 44 BD F8 C8
+               :                   95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+               :                   1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+
+
+
+Hoffman, Ed.                 Informational                     [Page 50]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   D1 81 4A 60 39 BA 36 39
+               :                   }
+               :                 }
+    462 03  132:               BIT STRING 0 unused bits, encapsulates {
+    466 02  128:                   INTEGER
+               :                   5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+               :                   3F A9 EC AC 5E DC BD B7 13 11 34 A6
+               :                   16 89 28 11 23 D9 34 86 67 75 75 13
+               :                   12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+               :                   1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+               :                   A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+               :                   7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+               :                   08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+               :                   F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+               :                   32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+               :                   F2 A5 E2 F4 F2 83 E5 B8
+               :                   }
+               :               }
+    597 A3  129:             [3] {
+    600 30  127:               SEQUENCE {
+    602 30   12:                 SEQUENCE {
+    604 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+    609 01    1:                   BOOLEAN TRUE
+    612 04    2:                   OCTET STRING, encapsulates {
+    614 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+    616 30   14:                 SEQUENCE {
+    618 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    623 01    1:                   BOOLEAN TRUE
+    626 04    4:                   OCTET STRING, encapsulates {
+    628 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+    632 30   31:                 SEQUENCE {
+    634 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+    639 04   24:                   OCTET STRING, encapsulates {
+    641 30   22:                       SEQUENCE {
+    643 80   20:                         [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+
+
+
+Hoffman, Ed.                 Informational                     [Page 51]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                         }
+               :                       }
+               :                   }
+    665 30   29:                 SEQUENCE {
+    667 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    672 04   22:                   OCTET STRING, encapsulates {
+    674 04   20:                       OCTET STRING
+               :                   BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+               :                   13 01 E2 FD E3 97 FE CD
+               :                       }
+               :                   }
+    696 30   31:                 SEQUENCE {
+    698 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+    703 04   24:                   OCTET STRING, encapsulates {
+    705 30   22:                       SEQUENCE {
+    707 81   20:                         [1] 'AliceDSS@example.com'
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+    729 30    9:           SEQUENCE {
+    731 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+    740 03   48:           BIT STRING 0 unused bits, encapsulates {
+    743 30   45:               SEQUENCE {
+    745 02   20:                 INTEGER
+               :                   55 0C A4 19 1F 42 2B 89 71 22 33 8D
+               :                   83 6A B5 3D 67 6B BF 45
+    767 02   21:                 INTEGER
+               :                   00 9F 61 53 52 54 0B 5C B2 DD DA E7
+               :                   76 1D E2 10 52 5B 43 5E BD
+               :                 }
+               :               }
+               :           }
+               :         }
+    790 31   99:       SET {
+    792 30   97:         SEQUENCE {
+    794 02    1:           INTEGER 1
+    797 30   24:           SEQUENCE {
+    799 30   18:             SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 52]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    801 31   16:               SET {
+    803 30   14:                 SEQUENCE {
+    805 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    810 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+    819 02    2:             INTEGER 200
+               :             }
+    823 30    7:           SEQUENCE {
+    825 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+               :             }
+    832 30    9:           SEQUENCE {
+    834 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+    843 04   46:           OCTET STRING, encapsulates {
+    845 30   44:               SEQUENCE {
+    847 02   20:                 INTEGER
+               :                   06 FB C7 2A 24 D5 34 89 F7 8B B5 FD
+               :                   73 24 A5 86 C8 0F 5A 6C
+    869 02   20:                 INTEGER
+               :                   66 69 19 BC 68 58 D1 8D B1 9D 52 3F
+               :                   DA 14 88 0D FD C9 A1 B8
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+               :   }
+
+4.4.  Fancier Signed Content
+
+   Same as 4.1, but includes Carl's root cert, Carl's CRL, some signed
+   and unsigned attributes (Countersignature by Diane).  A SignedData
+   with no attribute certificates, signed by Alice using DSS, her
+   certificate and Carl's root cert, Carl's DSS CRL.  The message is
+   ExContent, and is included in the eContent.  The signed attributes
+   are Content Type, Message Digest and Signing Time; the unsigned
+   attributes are content hint and counter signature.  The message
+   includes also Alice's RSA certificate.
+
+
+
+
+
+Hoffman, Ed.                 Informational                     [Page 53]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+      0 30 2829: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+               :     (PKCS #7)
+     15 A0 2814:   [0] {
+     19 30 2810:     SEQUENCE {
+     23 02    1:       INTEGER 1
+     26 31    9:       SET {
+     28 30    7:         SEQUENCE {
+     30 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :             (OIW)
+               :           }
+               :         }
+     37 30   43:       SEQUENCE {
+     39 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     50 A0   30:         [0] {
+     52 04   28:           OCTET STRING 'This is some sample content.'
+               :           }
+               :         }
+     82 A0 1967:       [0] {
+     86 30  556:         SEQUENCE {
+     90 30  405:           SEQUENCE {
+     94 A0    3:             [0] {
+     96 02    1:               INTEGER 2
+               :               }
+     99 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               C4 10 B3 B0
+    117 30   13:             SEQUENCE {
+    119 06    9:               OBJECT IDENTIFIER
+               :                 sha1withRSAEncryption
+               :                     (1 2 840 113549 1 1 5)
+               :                 (PKCS #1)
+    130 05    0:               NULL
+               :               }
+    132 30   18:             SEQUENCE {
+    134 31   16:               SET {
+    136 30   14:                 SEQUENCE {
+    138 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    143 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+    152 30   30:             SEQUENCE {
+    154 17   13:               UTCTime '990919010847Z'
+    169 17   13:               UTCTime '391231235959Z'
+
+
+
+Hoffman, Ed.                 Informational                     [Page 54]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :               }
+    184 30   19:             SEQUENCE {
+    186 31   17:               SET {
+    188 30   15:                 SEQUENCE {
+    190 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    195 13    8:                   PrintableString 'AliceRSA'
+               :                   }
+               :                 }
+               :               }
+    205 30  159:             SEQUENCE {
+    208 30   13:               SEQUENCE {
+    210 06    9:                 OBJECT IDENTIFIER
+               :                   rsaEncryption (1 2 840 113549 1 1 1)
+               :                   (PKCS #1)
+    221 05    0:                 NULL
+               :                 }
+    223 03  141:               BIT STRING 0 unused bits, encapsulates {
+    227 30  137:                   SEQUENCE {
+    230 02  129:                     INTEGER
+               :                   00 E0 89 73 39 8D D8 F5 F5 E8 87 76
+               :                   39 7F 4E B0 05 BB 53 83 DE 0F B7 AB
+               :                   DC 7D C7 75 29 0D 05 2E 6D 12 DF A6
+               :                   86 26 D4 D2 6F AA 58 29 FC 97 EC FA
+               :                   82 51 0F 30 80 BE B1 50 9E 46 44 F1
+               :                   2C BB D8 32 CF C6 68 6F 07 D9 B0 60
+               :                   AC BE EE 34 09 6A 13 F5 F7 05 05 93
+               :                   DF 5E BA 35 56 D9 61 FF 19 7F C9 81
+               :                   E6 F8 6C EA 87 40 70 EF AC 6D 2C 74
+               :                   9F 2D FA 55 3A B9 99 77 02 A6 48 52
+               :                   8C 4E F3 57 38 57 74 57 5F
+    362 02    3:                     INTEGER 65537
+               :                     }
+               :                   }
+               :               }
+    367 A3  129:             [3] {
+    370 30  127:               SEQUENCE {
+    372 30   12:                 SEQUENCE {
+    374 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+    379 01    1:                   BOOLEAN TRUE
+    382 04    2:                   OCTET STRING, encapsulates {
+    384 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+    386 30   14:                 SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 55]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    388 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    393 01    1:                   BOOLEAN TRUE
+    396 04    4:                   OCTET STRING, encapsulates {
+    398 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+    402 30   31:                 SEQUENCE {
+    404 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+    409 04   24:                   OCTET STRING, encapsulates {
+    411 30   22:                       SEQUENCE {
+    413 80   20:                         [0]
+               :                   E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                   42 37 4E 22 AE 9E 38 BB
+               :                         }
+               :                       }
+               :                   }
+    435 30   29:                 SEQUENCE {
+    437 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    442 04   22:                   OCTET STRING, encapsulates {
+    444 04   20:                       OCTET STRING
+               :                   77 D2 B4 D1 B7 4C 8A 8A A3 CE 45 9D
+               :                   CE EC 3C A0 3A E3 FF 50
+               :                       }
+               :                   }
+    466 30   31:                 SEQUENCE {
+    468 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+    473 04   24:                   OCTET STRING, encapsulates {
+    475 30   22:                       SEQUENCE {
+    477 81   20:                         [1] 'AliceRSA@example.com'
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+    499 30   13:           SEQUENCE {
+    501 06    9:             OBJECT IDENTIFIER
+               :               sha1withRSAEncryption
+               :                   (1 2 840 113549 1 1 5)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 56]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :               (PKCS #1)
+    512 05    0:             NULL
+               :             }
+    514 03  129:           BIT STRING 0 unused bits
+               :             3E 70 47 A8 48 CC 13 58 8F CA 51 71
+               :             6B 4E 36 18 5D 04 7E 80 B1 8D 4D CC
+               :             CA A3 8F CC 7D 56 C8 BC CF 6E B3 1C
+               :             59 A9 20 AA 05 81 A8 4E 25 AD A7 70
+               :             14 75 2F F5 C7 9B D1 0E E9 63 D2 64
+               :             B7 C6 66 6E 73 21 54 DF F4 BA 25 5D
+               :             7D 49 D3 94 6B 22 36 74 73 B8 4A EC
+               :             2F 64 ED D3 3D D2 A7 42 C5 E8 37 8A
+               :             B4 DB 9F 67 E4 BD 9F F9 FE 74 EF EA
+               :             F9 EE 63 6A D8 3F 4B 25 09 B5 D8 1A
+               :             76 AE EB 9B DB 49 B0 22
+               :           }
+    646 30  667:         SEQUENCE {
+    650 30  602:           SEQUENCE {
+    654 A0    3:             [0] {
+    656 02    1:               INTEGER 2
+               :               }
+    659 02    1:             INTEGER 1
+    662 30    9:             SEQUENCE {
+    664 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+    673 30   18:             SEQUENCE {
+    675 31   16:               SET {
+    677 30   14:                 SEQUENCE {
+    679 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    684 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+    693 30   30:             SEQUENCE {
+    695 17   13:               UTCTime '990816225050Z'
+    710 17   13:               UTCTime '391231235959Z'
+               :               }
+    725 30   18:             SEQUENCE {
+    727 31   16:               SET {
+    729 30   14:                 SEQUENCE {
+    731 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    736 13    7:                   PrintableString 'CarlDSS'
+
+
+
+Hoffman, Ed.                 Informational                     [Page 57]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   }
+               :                 }
+               :               }
+    745 30  439:             SEQUENCE {
+    749 30  299:               SEQUENCE {
+    753 06    7:                 OBJECT IDENTIFIER
+               :                   dsa (1 2 840 10040 4 1)
+               :                   (ANSI X9.57 algorithm)
+    762 30  286:                 SEQUENCE {
+    766 02  129:                   INTEGER
+               :                   00 B6 49 18 3E 8A 44 C1 29 71 94 4C
+               :                   01 C4 12 C1 7A 79 CB 54 4D AB 1E 81
+               :                   FB C6 4C B3 0E 94 09 06 EB 01 D4 B1
+               :                   C8 71 4B C7 45 C0 50 25 5D 9C FC DA
+               :                   E4 6D D3 E2 86 48 84 82 7D BA 15 95
+               :                   4A 16 F6 46 ED DD F6 98 D2 BB 7E 8A
+               :                   0A 8A BA 16 7B B9 50 01 48 93 8B EB
+               :                   25 15 51 97 55 DC 8F 53 0E 10 A9 50
+               :                   FC 70 B7 CD 30 54 FD DA DE A8 AA 22
+               :                   B5 A1 AF 8B CC 02 88 E7 8B 70 5F B9
+               :                   AD E1 08 D4 6D 29 2D D6 E9
+    898 02   21:                   INTEGER
+               :                   00 DD C1 2F DF 53 CE 0B 34 60 77 3E
+               :                   02 A4 BF 8A 5D 98 B9 10 D5
+    921 02  128:                   INTEGER
+               :                   0C EE 57 9B 4B BD DA B6 07 6A 74 37
+               :                   4F 55 7F 9D ED BC 61 0D EB 46 59 3C
+               :                   56 0B 2B 5B 0C 91 CE A5 62 52 69 CA
+               :                   E1 6D 3E BD BF FE E1 B7 B9 2B 61 3C
+               :                   AD CB AE 45 E3 06 AC 8C 22 9D 9C 44
+               :                   87 0B C7 CD F0 1C D9 B5 4E 5D 73 DE
+               :                   AF 0E C9 1D 5A 51 F5 4F 44 79 35 5A
+               :                   73 AA 7F 46 51 1F A9 42 16 9C 48 EB
+               :                   8A 79 61 B4 D5 2F 53 22 44 63 1F 86
+               :                   B8 A3 58 06 25 F8 29 C0 EF BA E0 75
+               :                   F0 42 C4 63 65 52 9B 0A
+               :                   }
+               :                 }
+   1052 03  133:               BIT STRING 0 unused bits, encapsulates {
+   1056 02  129:                   INTEGER
+               :                   00 99 87 74 27 03 66 A0 B1 C0 AD DC
+               :                   2C 75 BB E1 6C 44 9C DA 21 6D 4D 47
+               :                   6D B1 62 09 E9 D8 AE 1E F2 3A B4 94
+               :                   B1 A3 8E 7A 9B 71 4E 00 94 C9 B4 25
+               :                   4E B9 60 96 19 24 01 F3 62 0C FE 75
+               :                   C0 FB CE D8 68 00 E3 FD D5 70 4F DF
+               :                   23 96 19 06 94 F4 B1 61 8F 3A 57 B1
+               :                   08 11 A4 0B 26 25 F0 52 76 81 EA 0B
+
+
+
+Hoffman, Ed.                 Informational                     [Page 58]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   62 0D 95 2A E6 86 BA 72 B2 A7 50 83
+               :                   0B AA 27 CD 1B A9 4D 89 9A D7 8D 18
+               :                   39 84 3F 8B C5 56 4D 80 7A
+               :                   }
+               :               }
+   1188 A3   66:             [3] {
+   1190 30   64:               SEQUENCE {
+   1192 30   15:                 SEQUENCE {
+   1194 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+   1199 01    1:                   BOOLEAN TRUE
+   1202 04    5:                   OCTET STRING, encapsulates {
+   1204 30    3:                       SEQUENCE {
+   1206 01    1:                         BOOLEAN TRUE
+               :                         }
+               :                       }
+               :                   }
+   1209 30   14:                 SEQUENCE {
+   1211 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+   1216 01    1:                   BOOLEAN TRUE
+   1219 04    4:                   OCTET STRING, encapsulates {
+   1221 03    2:                       BIT STRING 1 unused bits
+               :                         '1100001'B
+               :                       }
+               :                   }
+   1225 30   29:                 SEQUENCE {
+   1227 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+   1232 04   22:                   OCTET STRING, encapsulates {
+   1234 04   20:                       OCTET STRING
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+   1256 30    9:           SEQUENCE {
+   1258 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+   1267 03   48:           BIT STRING 0 unused bits, encapsulates {
+   1270 30   45:               SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 59]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+   1272 02   20:                 INTEGER
+               :                   6B A9 F0 4E 7A 5A 79 E3 F9 BE 3D 2B
+               :                   C9 06 37 E9 11 17 A1 13
+   1294 02   21:                 INTEGER
+               :                   00 8F 34 69 2A 8B B1 3C 03 79 94 32
+               :                   4D 12 1F CE 89 FB 46 B2 3B
+               :                 }
+               :               }
+               :           }
+   1317 30  732:         SEQUENCE {
+   1321 30  667:           SEQUENCE {
+   1325 A0    3:             [0] {
+   1327 02    1:               INTEGER 2
+               :               }
+   1330 02    2:             INTEGER 200
+   1334 30    9:             SEQUENCE {
+   1336 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+   1345 30   18:             SEQUENCE {
+   1347 31   16:               SET {
+   1349 30   14:                 SEQUENCE {
+   1351 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+   1356 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+   1365 30   30:             SEQUENCE {
+   1367 17   13:               UTCTime '990817011049Z'
+   1382 17   13:               UTCTime '391231235959Z'
+               :               }
+   1397 30   19:             SEQUENCE {
+   1399 31   17:               SET {
+   1401 30   15:                 SEQUENCE {
+   1403 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+   1408 13    8:                   PrintableString 'AliceDSS'
+               :                   }
+               :                 }
+               :               }
+   1418 30  438:             SEQUENCE {
+   1422 30  299:               SEQUENCE {
+   1426 06    7:                 OBJECT IDENTIFIER
+               :                   dsa (1 2 840 10040 4 1)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 60]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   (ANSI X9.57 algorithm)
+   1435 30  286:                 SEQUENCE {
+   1439 02  129:                   INTEGER
+               :                   00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+               :                   48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+               :                   53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+               :                   0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+               :                   2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+               :                   DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+               :                   9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+               :                   8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+               :                   C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+               :                   78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+               :                   B5 E4 09 96 5C F3 7E 5B DB
+   1571 02   21:                   INTEGER
+               :                   00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+               :                   B8 37 21 2B 62 8B F7 93 CD
+   1594 02  128:                   INTEGER
+               :                   26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+               :                   4B 59 6A 4C 76 23 39 04 02 35 5C F2
+               :                   CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+               :                   AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+               :                   7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+               :                   3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+               :                   E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+               :                   01 7C 6D 49 89 11 89 36 44 BD F8 C8
+               :                   95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+               :                   1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+               :                   D1 81 4A 60 39 BA 36 39
+               :                   }
+               :                 }
+   1725 03  132:               BIT STRING 0 unused bits, encapsulates {
+   1729 02  128:                   INTEGER
+               :                   5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+               :                   3F A9 EC AC 5E DC BD B7 13 11 34 A6
+               :                   16 89 28 11 23 D9 34 86 67 75 75 13
+               :                   12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+               :                   1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+               :                   A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+               :                   7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+               :                   08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+               :                   F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+               :                   32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+               :                   F2 A5 E2 F4 F2 83 E5 B8
+               :                   }
+               :               }
+   1860 A3  129:             [3] {
+   1863 30  127:               SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 61]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+   1865 30   12:                 SEQUENCE {
+   1867 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+   1872 01    1:                   BOOLEAN TRUE
+   1875 04    2:                   OCTET STRING, encapsulates {
+   1877 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+   1879 30   14:                 SEQUENCE {
+   1881 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+   1886 01    1:                   BOOLEAN TRUE
+   1889 04    4:                   OCTET STRING, encapsulates {
+   1891 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+   1895 30   31:                 SEQUENCE {
+   1897 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+   1902 04   24:                   OCTET STRING, encapsulates {
+   1904 30   22:                       SEQUENCE {
+   1906 80   20:                         [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                         }
+               :                       }
+               :                   }
+   1928 30   29:                 SEQUENCE {
+   1930 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+   1935 04   22:                   OCTET STRING, encapsulates {
+   1937 04   20:                       OCTET STRING
+               :                   BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+               :                   13 01 E2 FD E3 97 FE CD
+               :                       }
+               :                   }
+   1959 30   31:                 SEQUENCE {
+   1961 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+   1966 04   24:                   OCTET STRING, encapsulates {
+   1968 30   22:                       SEQUENCE {
+   1970 81   20:                         [1] 'AliceDSS@example.com'
+
+
+
+Hoffman, Ed.                 Informational                     [Page 62]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+   1992 30    9:           SEQUENCE {
+   1994 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+   2003 03   48:           BIT STRING 0 unused bits, encapsulates {
+   2006 30   45:               SEQUENCE {
+   2008 02   20:                 INTEGER
+               :                   55 0C A4 19 1F 42 2B 89 71 22 33 8D
+               :                   83 6A B5 3D 67 6B BF 45
+   2030 02   21:                 INTEGER
+               :                   00 9F 61 53 52 54 0B 5C B2 DD DA E7
+               :                   76 1D E2 10 52 5B 43 5E BD
+               :                 }
+               :               }
+               :           }
+               :         }
+   2053 A1  219:       [1] {
+   2056 30  216:         SEQUENCE {
+   2059 30  153:           SEQUENCE {
+   2062 30    9:             SEQUENCE {
+   2064 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+   2073 30   18:             SEQUENCE {
+   2075 31   16:               SET {
+   2077 30   14:                 SEQUENCE {
+   2079 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+   2084 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+   2093 17   13:             UTCTime '990827070000Z'
+   2108 30  105:             SEQUENCE {
+   2110 30   19:               SEQUENCE {
+   2112 02    2:                 INTEGER 200
+   2116 17   13:                 UTCTime '990822070000Z'
+               :                 }
+   2131 30   19:               SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 63]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+   2133 02    2:                 INTEGER 201
+   2137 17   13:                 UTCTime '990822070000Z'
+               :                 }
+   2152 30   19:               SEQUENCE {
+   2154 02    2:                 INTEGER 211
+   2158 17   13:                 UTCTime '990822070000Z'
+               :                 }
+   2173 30   19:               SEQUENCE {
+   2175 02    2:                 INTEGER 210
+   2179 17   13:                 UTCTime '990822070000Z'
+               :                 }
+   2194 30   19:               SEQUENCE {
+   2196 02    2:                 INTEGER 212
+   2200 17   13:                 UTCTime '990824070000Z'
+               :                 }
+               :               }
+               :             }
+   2215 30    9:           SEQUENCE {
+   2217 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+   2226 03   47:           BIT STRING 0 unused bits, encapsulates {
+   2229 30   44:               SEQUENCE {
+   2231 02   20:                 INTEGER
+               :                   7E 65 52 76 33 FE 34 73 17 D1 F7 96
+               :                   F9 A0 D4 D8 6D 5C 7D 3D
+   2253 02   20:                 INTEGER
+               :                   02 7A 5B B7 D5 5B 18 C1 CF 87 EF 7E
+               :                   DA 24 F3 2A 83 9C 35 A1
+               :                 }
+               :               }
+               :           }
+               :         }
+   2275 31  554:       SET {
+   2279 30  550:         SEQUENCE {
+   2283 02    1:           INTEGER 1
+   2286 30   24:           SEQUENCE {
+   2288 30   18:             SEQUENCE {
+   2290 31   16:               SET {
+   2292 30   14:                 SEQUENCE {
+   2294 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+   2299 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 64]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+   2308 02    2:             INTEGER 200
+               :             }
+   2312 30    7:           SEQUENCE {
+   2314 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+               :             }
+   2321 A0   93:           [0] {
+   2323 30   24:             SEQUENCE {
+   2325 06    9:               OBJECT IDENTIFIER
+               :                 contentType (1 2 840 113549 1 9 3)
+               :                 (PKCS #9 (1 2 840 113549 1 9))
+   2336 31   11:               SET {
+   2338 06    9:                 OBJECT IDENTIFIER
+               :                   data (1 2 840 113549 1 7 1)
+               :                   (PKCS #7)
+               :                 }
+               :               }
+   2349 30   28:             SEQUENCE {
+   2351 06    9:               OBJECT IDENTIFIER
+               :                 signingTime (1 2 840 113549 1 9 5)
+               :                 (PKCS #9 (1 2 840 113549 1 9))
+   2362 31   15:               SET {
+   2364 17   13:                 UTCTime '030514153900Z'
+               :                 }
+               :               }
+   2379 30   35:             SEQUENCE {
+   2381 06    9:               OBJECT IDENTIFIER
+               :                 messageDigest (1 2 840 113549 1 9 4)
+               :                 (PKCS #9 (1 2 840 113549 1 9))
+   2392 31   22:               SET {
+   2394 04   20:                 OCTET STRING
+               :                   40 6A EC 08 52 79 BA 6E 16 02 2D 9E
+               :                   06 29 C0 22 96 87 DD 48
+               :                 }
+               :               }
+               :             }
+   2416 30    9:           SEQUENCE {
+   2418 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+   2427 04   46:           OCTET STRING, encapsulates {
+   2429 30   44:               SEQUENCE {
+   2431 02   20:                 INTEGER
+               :                   3B A5 E0 4A DB 6D 58 E0 19 D1 00 1C
+               :                   4F 44 9A 57 7A 71 66 68
+   2453 02   20:                 INTEGER
+               :                   1A 11 98 D6 1F 1F AF 34 81 01 DE BE
+
+
+
+Hoffman, Ed.                 Informational                     [Page 65]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   8B DC B6 A8 6A 91 69 13
+               :                 }
+               :               }
+   2475 A1  354:           [1] {
+   2479 30   62:             SEQUENCE {
+   2481 06   11:               OBJECT IDENTIFIER
+               :                 id-aa-contentHint
+               :                     (1 2 840 113549 1 9 16 2 4)
+               :                 (S/MIME Authenticated Attributes
+               :                     (1 2 840 113549 1 9 16 2))
+   2494 31   47:               SET {
+   2496 30   45:                 SEQUENCE {
+   2498 0C   32:                   UTF8String
+               :                   'Content Hints Description Buffer'
+   2532 06    9:                   OBJECT IDENTIFIER
+               :                     data (1 2 840 113549 1 7 1)
+               :                     (PKCS #7)
+               :                   }
+               :                 }
+               :               }
+   2543 30  286:             SEQUENCE {
+   2547 06    9:               OBJECT IDENTIFIER
+               :                 countersignature (1 2 840 113549 1 9 6)
+               :                 (PKCS #9 (1 2 840 113549 1 9))
+   2558 31  271:               SET {
+   2562 30  267:                 SEQUENCE {
+   2566 02    1:                   INTEGER 1
+   2569 30   38:                   SEQUENCE {
+   2571 30   18:                     SEQUENCE {
+   2573 31   16:                       SET {
+   2575 30   14:                         SEQUENCE {
+   2577 06    3:                           OBJECT IDENTIFIER
+               :                             commonName (2 5 4 3)
+               :                             (X.520 id-at (2 5 4))
+   2582 13    7:                           PrintableString 'CarlRSA'
+               :                           }
+               :                         }
+               :                       }
+   2591 02   16:                     INTEGER
+               :                   46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :                   C4 10 B3 B0
+               :                     }
+   2609 30    7:                   SEQUENCE {
+   2611 06    5:                     OBJECT IDENTIFIER
+               :                       sha1 (1 3 14 3 2 26)
+               :                       (OIW)
+               :                     }
+   2618 A0   67:                   [0] {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 66]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+   2620 30   28:                     SEQUENCE {
+   2622 06    9:                       OBJECT IDENTIFIER
+               :                         signingTime
+               :                             (1 2 840 113549 1 9 5)
+               :                         (PKCS #9 (1 2 840 113549 1 9))
+   2633 31   15:                       SET {
+   2635 17   13:                         UTCTime '030514153900Z'
+               :                         }
+               :                       }
+   2650 30   35:                     SEQUENCE {
+   2652 06    9:                       OBJECT IDENTIFIER
+               :                         messageDigest
+               :                             (1 2 840 113549 1 9 4)
+               :                         (PKCS #9 (1 2 840 113549 1 9))
+   2663 31   22:                       SET {
+   2665 04   20:                         OCTET STRING
+               :                   02 5F 49 4E 39 98 50 85 B3 66 D3 8A
+               :                   1F 7B 9E 69 AA FB D8 33
+               :                         }
+               :                       }
+               :                     }
+   2687 30   13:                   SEQUENCE {
+   2689 06    9:                     OBJECT IDENTIFIER
+               :                       rsaEncryption
+               :                           (1 2 840 113549 1 1 1)
+               :                       (PKCS #1)
+   2700 05    0:                     NULL
+               :                     }
+   2702 04  128:                   OCTET STRING
+               :                   6D AA 20 24 ED 7A EE A5 5E 87 DD 75
+               :                   1F 2B 54 10 65 F4 CE 9B B1 2C 78 74
+               :                   BC 8B 1C 60 B5 DB 8B 03 9E 49 F2 2B
+               :                   7F 93 6E 3D 89 14 C9 E3 6B F4 F6 7D
+               :                   76 AE 3E 58 1F 9B BB BC 7C 30 19 4E
+               :                   10 F7 02 F1 8B 5B B4 DB 9A BB 93 B4
+               :                   18 D0 CC 2B C9 91 A9 AD D9 46 F8 65
+               :                   A9 E2 71 95 D0 D4 4E 1F CD 74 6F 82
+               :                   E8 37 6F 5A 3D CB C7 D4 5F C2 80 1B
+               :                   DA D3 84 40 68 5F 56 9A 62 F5 3B 0D
+               :                   6C 33 C3 ED 67 3F 43 BF
+               :                   }
+               :                 }
+               :               }
+               :             }
+               :           }
+               :         }
+               :       }
+               :     }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 67]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :   }
+
+4.5.  All RSA Signed Message
+
+   Same as 4.2, but includes Carl's RSA root cert (but no CRL).  A
+   SignedData with no attribute certificates, signed by Alice using RSA,
+   her certificate and Carl's root cert, no CRL.  The message is
+   ExContent, and is included in the eContent.  There are no signed or
+   unsigned attributes.
+
+      0 30 NDEF: SEQUENCE {
+      2 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+               :     (PKCS #7)
+     13 A0 NDEF:   [0] {
+     15 30 NDEF:     SEQUENCE {
+     17 02    1:       INTEGER 1
+     20 31   11:       SET {
+     22 30    9:         SEQUENCE {
+     24 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :             (OIW)
+     31 05    0:           NULL
+               :           }
+               :         }
+     33 30 NDEF:       SEQUENCE {
+     35 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     46 A0 NDEF:         [0] {
+     48 24 NDEF:           OCTET STRING {
+     50 04    4:             OCTET STRING 'This'
+     56 04   24:             OCTET STRING ' is some sample content.'
+               :             }
+               :           }
+               :         }
+     88 A0 NDEF:       [0] {
+     90 30  491:         SEQUENCE {
+     94 30  340:           SEQUENCE {
+     98 A0    3:             [0] {
+    100 02    1:               INTEGER 2
+               :               }
+    103 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               9F F2 50 20
+    121 30   13:             SEQUENCE {
+    123 06    9:               OBJECT IDENTIFIER
+               :                 sha1withRSAEncryption
+               :                     (1 2 840 113549 1 1 5)
+               :                 (PKCS #1)
+    134 05    0:               NULL
+
+
+
+Hoffman, Ed.                 Informational                     [Page 68]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :               }
+    136 30   18:             SEQUENCE {
+    138 31   16:               SET {
+    140 30   14:                 SEQUENCE {
+    142 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    147 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+    156 30   30:             SEQUENCE {
+    158 17   13:               UTCTime '990818070000Z'
+    173 17   13:               UTCTime '391231235959Z'
+               :               }
+    188 30   18:             SEQUENCE {
+    190 31   16:               SET {
+    192 30   14:                 SEQUENCE {
+    194 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    199 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+    208 30  159:             SEQUENCE {
+    211 30   13:               SEQUENCE {
+    213 06    9:                 OBJECT IDENTIFIER
+               :                   rsaEncryption (1 2 840 113549 1 1 1)
+               :                   (PKCS #1)
+    224 05    0:                 NULL
+               :                 }
+    226 03  141:               BIT STRING 0 unused bits, encapsulates {
+    230 30  137:                   SEQUENCE {
+    233 02  129:                     INTEGER
+               :                   00 E4 4B FF 18 B8 24 57 F4 77 FF 6E
+               :                   73 7B 93 71 5C BC 33 1A 92 92 72 23
+               :                   D8 41 46 D0 CD 11 3A 04 B3 8E AF 82
+               :                   9D BD 51 1E 17 7A F2 76 2C 2B 86 39
+               :                   A7 BD D7 8D 1A 53 EC E4 00 D5 E8 EC
+               :                   A2 36 B1 ED E2 50 E2 32 09 8A 3F 9F
+               :                   99 25 8F B8 4E AB B9 7D D5 96 65 DA
+               :                   16 A0 C5 BE 0E AE 44 5B EF 5E F4 A7
+               :                   29 CB 82 DD AC 44 E9 AA 93 94 29 0E
+               :                   F8 18 D6 C8 57 5E F2 76 C4 F2 11 60
+               :                   38 B9 1B 3C 1D 97 C9 6A F1
+    365 02    3:                     INTEGER 65537
+               :                     }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 69]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   }
+               :               }
+    370 A3   66:             [3] {
+    372 30   64:               SEQUENCE {
+    374 30   15:                 SEQUENCE {
+    376 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+    381 01    1:                   BOOLEAN TRUE
+    384 04    5:                   OCTET STRING, encapsulates {
+    386 30    3:                       SEQUENCE {
+    388 01    1:                         BOOLEAN TRUE
+               :                         }
+               :                       }
+               :                   }
+    391 30   14:                 SEQUENCE {
+    393 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    398 01    1:                   BOOLEAN TRUE
+    401 04    4:                   OCTET STRING, encapsulates {
+    403 03    2:                       BIT STRING 1 unused bits
+               :                         '1100001'B
+               :                       }
+               :                   }
+    407 30   29:                 SEQUENCE {
+    409 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    414 04   22:                   OCTET STRING, encapsulates {
+    416 04   20:                       OCTET STRING
+               :                   E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                   42 37 4E 22 AE 9E 38 BB
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+    438 30   13:           SEQUENCE {
+    440 06    9:             OBJECT IDENTIFIER
+               :               sha1withRSAEncryption
+               :                   (1 2 840 113549 1 1 5)
+               :               (PKCS #1)
+    451 05    0:             NULL
+               :             }
+    453 03  129:           BIT STRING 0 unused bits
+               :             B7 9E D4 04 D3 ED 29 E4 FF 89 89 15
+               :             2E 4C DB 0C F0 48 0F 32 61 EE C4 04
+
+
+
+Hoffman, Ed.                 Informational                     [Page 70]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             EC 12 5D 2D FF 0F 64 59 7E 0A C3 ED
+               :             18 FD E3 56 40 37 A7 07 B5 F0 38 12
+               :             61 50 ED EF DD 3F E3 0B B8 61 A5 A4
+               :             9B 3C E6 9E 9C 54 9A B6 95 D6 DA 6C
+               :             3B B5 2D 45 35 9D 49 01 76 FA B9 B9
+               :             31 F9 F9 6B 12 53 A0 F5 14 60 9B 7D
+               :             CA 3E F2 53 6B B0 37 6F AD E6 74 D7
+               :             DB FA 5A EA 14 41 63 5D CD BE C8 0E
+               :             C1 DA 6A 8D 53 34 18 02
+               :           }
+    585 30  556:         SEQUENCE {
+    589 30  405:           SEQUENCE {
+    593 A0    3:             [0] {
+    595 02    1:               INTEGER 2
+               :               }
+    598 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               C4 10 B3 B0
+    616 30   13:             SEQUENCE {
+    618 06    9:               OBJECT IDENTIFIER
+               :                 sha1withRSAEncryption
+               :                     (1 2 840 113549 1 1 5)
+               :                 (PKCS #1)
+    629 05    0:               NULL
+               :               }
+    631 30   18:             SEQUENCE {
+    633 31   16:               SET {
+    635 30   14:                 SEQUENCE {
+    637 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    642 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+    651 30   30:             SEQUENCE {
+    653 17   13:               UTCTime '990919010847Z'
+    668 17   13:               UTCTime '391231235959Z'
+               :               }
+    683 30   19:             SEQUENCE {
+    685 31   17:               SET {
+    687 30   15:                 SEQUENCE {
+    689 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    694 13    8:                   PrintableString 'AliceRSA'
+               :                   }
+               :                 }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 71]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :               }
+    704 30  159:             SEQUENCE {
+    707 30   13:               SEQUENCE {
+    709 06    9:                 OBJECT IDENTIFIER
+               :                   rsaEncryption (1 2 840 113549 1 1 1)
+               :                   (PKCS #1)
+    720 05    0:                 NULL
+               :                 }
+    722 03  141:               BIT STRING 0 unused bits, encapsulates {
+    726 30  137:                   SEQUENCE {
+    729 02  129:                     INTEGER
+               :                   00 E0 89 73 39 8D D8 F5 F5 E8 87 76
+               :                   39 7F 4E B0 05 BB 53 83 DE 0F B7 AB
+               :                   DC 7D C7 75 29 0D 05 2E 6D 12 DF A6
+               :                   86 26 D4 D2 6F AA 58 29 FC 97 EC FA
+               :                   82 51 0F 30 80 BE B1 50 9E 46 44 F1
+               :                   2C BB D8 32 CF C6 68 6F 07 D9 B0 60
+               :                   AC BE EE 34 09 6A 13 F5 F7 05 05 93
+               :                   DF 5E BA 35 56 D9 61 FF 19 7F C9 81
+               :                   E6 F8 6C EA 87 40 70 EF AC 6D 2C 74
+               :                   9F 2D FA 55 3A B9 99 77 02 A6 48 52
+               :                   8C 4E F3 57 38 57 74 57 5F
+    861 02    3:                     INTEGER 65537
+               :                     }
+               :                   }
+               :               }
+    866 A3  129:             [3] {
+    869 30  127:               SEQUENCE {
+    871 30   12:                 SEQUENCE {
+    873 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+    878 01    1:                   BOOLEAN TRUE
+    881 04    2:                   OCTET STRING, encapsulates {
+    883 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+    885 30   14:                 SEQUENCE {
+    887 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    892 01    1:                   BOOLEAN TRUE
+    895 04    4:                   OCTET STRING, encapsulates {
+    897 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+    901 30   31:                 SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 72]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    903 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+    908 04   24:                   OCTET STRING, encapsulates {
+    910 30   22:                       SEQUENCE {
+    912 80   20:                         [0]
+               :                   E9 E0 90 27 AC 78 20 7A 9A D3 4C F2
+               :                   42 37 4E 22 AE 9E 38 BB
+               :                         }
+               :                       }
+               :                   }
+    934 30   29:                 SEQUENCE {
+    936 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    941 04   22:                   OCTET STRING, encapsulates {
+    943 04   20:                       OCTET STRING
+               :                   77 D2 B4 D1 B7 4C 8A 8A A3 CE 45 9D
+               :                   CE EC 3C A0 3A E3 FF 50
+               :                       }
+               :                   }
+    965 30   31:                 SEQUENCE {
+    967 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+    972 04   24:                   OCTET STRING, encapsulates {
+    974 30   22:                       SEQUENCE {
+    976 81   20:                         [1] 'AliceRSA@example.com'
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+    998 30   13:           SEQUENCE {
+   1000 06    9:             OBJECT IDENTIFIER
+               :               sha1withRSAEncryption
+               :                   (1 2 840 113549 1 1 5)
+               :               (PKCS #1)
+   1011 05    0:             NULL
+               :             }
+   1013 03  129:           BIT STRING 0 unused bits
+               :             3E 70 47 A8 48 CC 13 58 8F CA 51 71
+               :             6B 4E 36 18 5D 04 7E 80 B1 8D 4D CC
+               :             CA A3 8F CC 7D 56 C8 BC CF 6E B3 1C
+               :             59 A9 20 AA 05 81 A8 4E 25 AD A7 70
+               :             14 75 2F F5 C7 9B D1 0E E9 63 D2 64
+               :             B7 C6 66 6E 73 21 54 DF F4 BA 25 5D
+
+
+
+Hoffman, Ed.                 Informational                     [Page 73]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             7D 49 D3 94 6B 22 36 74 73 B8 4A EC
+               :             2F 64 ED D3 3D D2 A7 42 C5 E8 37 8A
+               :             B4 DB 9F 67 E4 BD 9F F9 FE 74 EF EA
+               :             F9 EE 63 6A D8 3F 4B 25 09 B5 D8 1A
+               :             76 AE EB 9B DB 49 B0 22
+               :           }
+               :         }
+   1147 31  203:       SET {
+   1150 30  200:         SEQUENCE {
+   1153 02    1:           INTEGER 1
+   1156 30   38:           SEQUENCE {
+   1158 30   18:             SEQUENCE {
+   1160 31   16:               SET {
+   1162 30   14:                 SEQUENCE {
+   1164 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+   1169 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+   1178 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               C4 10 B3 B0
+               :             }
+   1196 30    9:           SEQUENCE {
+   1198 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+   1205 05    0:             NULL
+               :             }
+   1207 30   13:           SEQUENCE {
+   1209 06    9:             OBJECT IDENTIFIER
+               :               rsaEncryption (1 2 840 113549 1 1 1)
+               :               (PKCS #1)
+   1220 05    0:             NULL
+               :             }
+   1222 04  128:           OCTET STRING
+               :             2F 23 82 D2 F3 09 5F B8 0C 58 EB 4E
+               :             9D BF 89 9A 81 E5 75 C4 91 3D D3 D0
+               :             D5 7B B6 D5 FE 94 A1 8A AC E3 C4 84
+               :             F5 CD 60 4E 27 95 F6 CF 00 86 76 75
+               :             3F 2B F0 E7 D4 02 67 A7 F5 C7 8D 16
+               :             04 A5 B3 B5 E7 D9 32 F0 24 EF E7 20
+               :             44 D5 9F 07 C5 53 24 FA CE 01 1D 0F
+               :             17 13 A7 2A 95 9D 2B E4 03 95 14 0B
+               :             E9 39 0D BA CE 6E 9C 9E 0C E8 98 E6
+               :             55 13 D4 68 6F D0 07 D7 A2 B1 62 4C
+               :             E3 8F AF FD E0 D5 5D C7
+
+
+
+Hoffman, Ed.                 Informational                     [Page 74]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           }
+               :         }
+               :       }
+               :     }
+               :   }
+
+4.6.  Multiple Signers
+
+   Similar to 4.1, but the message is also signed by Diane.  Two
+   signerInfos (one for Alice, one for Diane) with no attribute
+   certificates, each signed using DSS, Alice's and Diane's certificate
+   (not Carl's root cert), no CRL.  The message is ExContent, and is
+   included in the eContent.  There are no signed or unsigned
+   attributes.
+
+      0 30 1463: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+               :     (PKCS #7)
+     15 A0 1448:   [0] {
+     19 30 1444:     SEQUENCE {
+     23 02    1:       INTEGER 1
+     26 31    9:       SET {
+     28 30    7:         SEQUENCE {
+     30 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :             (OIW)
+               :           }
+               :         }
+     37 30   43:       SEQUENCE {
+     39 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     50 A0   30:         [0] {
+     52 04   28:           OCTET STRING 'This is some sample content.'
+               :           }
+               :         }
+     82 A0 1180:       [0] {
+     86 30  440:         SEQUENCE {
+     90 30  375:           SEQUENCE {
+     94 A0    3:             [0] {
+     96 02    1:               INTEGER 2
+               :               }
+     99 02    2:             INTEGER 210
+    103 30    9:             SEQUENCE {
+    105 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+    114 30   18:             SEQUENCE {
+    116 31   16:               SET {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 75]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    118 30   14:                 SEQUENCE {
+    120 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    125 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+    134 30   30:             SEQUENCE {
+    136 17   13:               UTCTime '990817020810Z'
+    151 17   13:               UTCTime '391231235959Z'
+               :               }
+    166 30   19:             SEQUENCE {
+    168 31   17:               SET {
+    170 30   15:                 SEQUENCE {
+    172 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    177 13    8:                   PrintableString 'DianeDSS'
+               :                   }
+               :                 }
+               :               }
+    187 30  147:             SEQUENCE {
+    190 30    9:               SEQUENCE {
+    192 06    7:                 OBJECT IDENTIFIER
+               :                   dsa (1 2 840 10040 4 1)
+               :                   (ANSI X9.57 algorithm)
+               :                 }
+    201 03  133:               BIT STRING 0 unused bits, encapsulates {
+    205 02  129:                   INTEGER
+               :                   00 A0 00 17 78 2C EE 7E 81 53 2E 2E
+               :                   61 08 0F A1 9B 51 52 1A DA 59 A8 73
+               :                   2F 12 25 B6 08 CB CA EF 2A 44 76 8A
+               :                   52 09 EA BD 05 22 D5 0F F6 FD 46 D7
+               :                   AF 99 38 09 0E 13 CB 4F 2C DD 1C 34
+               :                   F7 1C BF 25 FF 23 D3 3B 59 E7 82 97
+               :                   37 BE 31 24 D8 18 C8 F3 49 39 5B B7
+               :                   E2 E5 27 7E FC 8C 45 72 5B 7E 3E 8F
+               :                   68 4D DD 46 7A 22 BE 8E FF CC DA 39
+               :                   29 A3 39 E5 9F 43 E9 55 C9 D7 5B A6
+               :                   81 67 CC C0 AA CD 2E C5 23
+               :                   }
+               :               }
+    337 A3  129:             [3] {
+    340 30  127:               SEQUENCE {
+    342 30   12:                 SEQUENCE {
+    344 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+
+
+
+Hoffman, Ed.                 Informational                     [Page 76]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                     (X.509 id-ce (2 5 29))
+    349 01    1:                   BOOLEAN TRUE
+    352 04    2:                   OCTET STRING, encapsulates {
+    354 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+    356 30   14:                 SEQUENCE {
+    358 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    363 01    1:                   BOOLEAN TRUE
+    366 04    4:                   OCTET STRING, encapsulates {
+    368 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+    372 30   31:                 SEQUENCE {
+    374 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+    379 04   24:                   OCTET STRING, encapsulates {
+    381 30   22:                       SEQUENCE {
+    383 80   20:                         [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                         }
+               :                       }
+               :                   }
+    405 30   29:                 SEQUENCE {
+    407 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    412 04   22:                   OCTET STRING, encapsulates {
+    414 04   20:                       OCTET STRING
+               :                   64 30 99 7D 5C DC 45 0B 99 3A 52 2F
+               :                   16 BF 58 50 DD CE 2B 18
+               :                       }
+               :                   }
+    436 30   31:                 SEQUENCE {
+    438 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+    443 04   24:                   OCTET STRING, encapsulates {
+    445 30   22:                       SEQUENCE {
+    447 81   20:                         [1] 'DianeDSS@example.com'
+               :                         }
+               :                       }
+               :                   }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 77]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                 }
+               :               }
+               :             }
+    469 30    9:           SEQUENCE {
+    471 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+    480 03   48:           BIT STRING 0 unused bits, encapsulates {
+    483 30   45:               SEQUENCE {
+    485 02   21:                 INTEGER
+               :                   00 A1 1A F8 17 0E 3E 5D A8 8C F4 B6
+               :                   55 33 1E 4B E3 2C AC B9 5F
+    508 02   20:                 INTEGER
+               :                   28 4B 10 45 58 D2 1C 9D 55 35 14 18
+               :                   91 B2 3F 39 DF B5 6E D3
+               :                 }
+               :               }
+               :           }
+    530 30  732:         SEQUENCE {
+    534 30  667:           SEQUENCE {
+    538 A0    3:             [0] {
+    540 02    1:               INTEGER 2
+               :               }
+    543 02    2:             INTEGER 200
+    547 30    9:             SEQUENCE {
+    549 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+    558 30   18:             SEQUENCE {
+    560 31   16:               SET {
+    562 30   14:                 SEQUENCE {
+    564 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    569 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+    578 30   30:             SEQUENCE {
+    580 17   13:               UTCTime '990817011049Z'
+    595 17   13:               UTCTime '391231235959Z'
+               :               }
+    610 30   19:             SEQUENCE {
+    612 31   17:               SET {
+    614 30   15:                 SEQUENCE {
+    616 06    3:                   OBJECT IDENTIFIER
+
+
+
+Hoffman, Ed.                 Informational                     [Page 78]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    621 13    8:                   PrintableString 'AliceDSS'
+               :                   }
+               :                 }
+               :               }
+    631 30  438:             SEQUENCE {
+    635 30  299:               SEQUENCE {
+    639 06    7:                 OBJECT IDENTIFIER
+               :                   dsa (1 2 840 10040 4 1)
+               :                   (ANSI X9.57 algorithm)
+    648 30  286:                 SEQUENCE {
+    652 02  129:                   INTEGER
+               :                   00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+               :                   48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+               :                   53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+               :                   0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+               :                   2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+               :                   DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+               :                   9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+               :                   8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+               :                   C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+               :                   78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+               :                   B5 E4 09 96 5C F3 7E 5B DB
+    784 02   21:                   INTEGER
+               :                   00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+               :                   B8 37 21 2B 62 8B F7 93 CD
+    807 02  128:                   INTEGER
+               :                   26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+               :                   4B 59 6A 4C 76 23 39 04 02 35 5C F2
+               :                   CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+               :                   AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+               :                   7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+               :                   3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+               :                   E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+               :                   01 7C 6D 49 89 11 89 36 44 BD F8 C8
+               :                   95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+               :                   1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+               :                   D1 81 4A 60 39 BA 36 39
+               :                   }
+               :                 }
+    938 03  132:               BIT STRING 0 unused bits, encapsulates {
+    942 02  128:                   INTEGER
+               :                   5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+               :                   3F A9 EC AC 5E DC BD B7 13 11 34 A6
+               :                   16 89 28 11 23 D9 34 86 67 75 75 13
+               :                   12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+               :                   1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+
+
+
+Hoffman, Ed.                 Informational                     [Page 79]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+               :                   7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+               :                   08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+               :                   F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+               :                   32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+               :                   F2 A5 E2 F4 F2 83 E5 B8
+               :                   }
+               :               }
+   1073 A3  129:             [3] {
+   1076 30  127:               SEQUENCE {
+   1078 30   12:                 SEQUENCE {
+   1080 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+   1085 01    1:                   BOOLEAN TRUE
+   1088 04    2:                   OCTET STRING, encapsulates {
+   1090 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+   1092 30   14:                 SEQUENCE {
+   1094 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+   1099 01    1:                   BOOLEAN TRUE
+   1102 04    4:                   OCTET STRING, encapsulates {
+   1104 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+   1108 30   31:                 SEQUENCE {
+   1110 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+   1115 04   24:                   OCTET STRING, encapsulates {
+   1117 30   22:                       SEQUENCE {
+   1119 80   20:                         [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                         }
+               :                       }
+               :                   }
+   1141 30   29:                 SEQUENCE {
+   1143 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+   1148 04   22:                   OCTET STRING, encapsulates {
+   1150 04   20:                       OCTET STRING
+               :                   BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+
+
+
+Hoffman, Ed.                 Informational                     [Page 80]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   13 01 E2 FD E3 97 FE CD
+               :                       }
+               :                   }
+   1172 30   31:                 SEQUENCE {
+   1174 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+   1179 04   24:                   OCTET STRING, encapsulates {
+   1181 30   22:                       SEQUENCE {
+   1183 81   20:                         [1] 'AliceDSS@example.com'
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+   1205 30    9:           SEQUENCE {
+   1207 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+   1216 03   48:           BIT STRING 0 unused bits, encapsulates {
+   1219 30   45:               SEQUENCE {
+   1221 02   20:                 INTEGER
+               :                   55 0C A4 19 1F 42 2B 89 71 22 33 8D
+               :                   83 6A B5 3D 67 6B BF 45
+   1243 02   21:                 INTEGER
+               :                   00 9F 61 53 52 54 0B 5C B2 DD DA E7
+               :                   76 1D E2 10 52 5B 43 5E BD
+               :                 }
+               :               }
+               :           }
+               :         }
+   1266 31  198:       SET {
+   1269 30   97:         SEQUENCE {
+   1271 02    1:           INTEGER 1
+   1274 30   24:           SEQUENCE {
+   1276 30   18:             SEQUENCE {
+   1278 31   16:               SET {
+   1280 30   14:                 SEQUENCE {
+   1282 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+   1287 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+   1296 02    2:             INTEGER 200
+
+
+
+Hoffman, Ed.                 Informational                     [Page 81]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             }
+   1300 30    7:           SEQUENCE {
+   1302 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+               :             }
+   1309 30    9:           SEQUENCE {
+   1311 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+   1320 04   46:           OCTET STRING, encapsulates {
+   1322 30   44:               SEQUENCE {
+   1324 02   20:                 INTEGER
+               :                   48 24 DE 8B 85 F2 16 AF EC 82 61 A9
+               :                   54 D0 2D 04 A1 CC 5A 4F
+   1346 02   20:                 INTEGER
+               :                   17 ED D5 77 02 EE 75 13 D8 10 BD 3D
+               :                   97 17 20 88 BB FD 7B 81
+               :                 }
+               :               }
+               :           }
+   1368 30   97:         SEQUENCE {
+   1370 02    1:           INTEGER 1
+   1373 30   24:           SEQUENCE {
+   1375 30   18:             SEQUENCE {
+   1377 31   16:               SET {
+   1379 30   14:                 SEQUENCE {
+   1381 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+   1386 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+   1395 02    2:             INTEGER 210
+               :             }
+   1399 30    7:           SEQUENCE {
+   1401 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+               :             }
+   1408 30    9:           SEQUENCE {
+   1410 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+   1419 04   46:           OCTET STRING, encapsulates {
+   1421 30   44:               SEQUENCE {
+   1423 02   20:                 INTEGER
+
+
+
+Hoffman, Ed.                 Informational                     [Page 82]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   15 FF 81 4D 8C AD 80 4E 9B 35 58 04
+               :                   37 6E 63 6E E9 5B 83 FA
+   1445 02   20:                 INTEGER
+               :                   06 7E 58 4E 2B 31 84 41 ED 49 79 38
+               :                   3E 77 D2 A6 8C 75 08 21
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+               :   }
+
+4.7.  Signing Using SKI
+
+   Same as 4.1, but the signature uses the SKI instead of the
+   issuer/serial number in the cert.  A SignedData with no attribute
+   certificates, signed by Alice using DSS, just her certificate (not
+   Carl's root cert), identified by the SKI, no CRL.  The message is
+   ExContent, and is included in the eContent.  There are no signed or
+   unsigned attributes.
+
+      0 30  915: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+               :     (PKCS #7)
+     15 A0  900:   [0] {
+     19 30  896:     SEQUENCE {
+     23 02    1:       INTEGER 3
+     26 31    9:       SET {
+     28 30    7:         SEQUENCE {
+     30 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :             (OIW)
+               :           }
+               :         }
+     37 30   43:       SEQUENCE {
+     39 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     50 A0   30:         [0] {
+     52 04   28:           OCTET STRING 'This is some sample content.'
+               :           }
+               :         }
+     82 A0  736:       [0] {
+     86 30  732:         SEQUENCE {
+     90 30  667:           SEQUENCE {
+     94 A0    3:             [0] {
+     96 02    1:               INTEGER 2
+               :               }
+     99 02    2:             INTEGER 200
+
+
+
+Hoffman, Ed.                 Informational                     [Page 83]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    103 30    9:             SEQUENCE {
+    105 06    7:               OBJECT IDENTIFIER
+               :                 dsaWithSha1 (1 2 840 10040 4 3)
+               :                 (ANSI X9.57 algorithm)
+               :               }
+    114 30   18:             SEQUENCE {
+    116 31   16:               SET {
+    118 30   14:                 SEQUENCE {
+    120 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    125 13    7:                   PrintableString 'CarlDSS'
+               :                   }
+               :                 }
+               :               }
+    134 30   30:             SEQUENCE {
+    136 17   13:               UTCTime '990817011049Z'
+    151 17   13:               UTCTime '391231235959Z'
+               :               }
+    166 30   19:             SEQUENCE {
+    168 31   17:               SET {
+    170 30   15:                 SEQUENCE {
+    172 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+    177 13    8:                   PrintableString 'AliceDSS'
+               :                   }
+               :                 }
+               :               }
+    187 30  438:             SEQUENCE {
+    191 30  299:               SEQUENCE {
+    195 06    7:                 OBJECT IDENTIFIER
+               :                   dsa (1 2 840 10040 4 1)
+               :                   (ANSI X9.57 algorithm)
+    204 30  286:                 SEQUENCE {
+    208 02  129:                   INTEGER
+               :                   00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+               :                   48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+               :                   53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+               :                   0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+               :                   2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+               :                   DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+               :                   9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+               :                   8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+               :                   C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+               :                   78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+               :                   B5 E4 09 96 5C F3 7E 5B DB
+    340 02   21:                   INTEGER
+
+
+
+Hoffman, Ed.                 Informational                     [Page 84]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+               :                   B8 37 21 2B 62 8B F7 93 CD
+    363 02  128:                   INTEGER
+               :                   26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+               :                   4B 59 6A 4C 76 23 39 04 02 35 5C F2
+               :                   CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+               :                   AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+               :                   7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+               :                   3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+               :                   E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+               :                   01 7C 6D 49 89 11 89 36 44 BD F8 C8
+               :                   95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+               :                   1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+               :                   D1 81 4A 60 39 BA 36 39
+               :                   }
+               :                 }
+    494 03  132:               BIT STRING 0 unused bits, encapsulates {
+    498 02  128:                   INTEGER
+               :                   5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+               :                   3F A9 EC AC 5E DC BD B7 13 11 34 A6
+               :                   16 89 28 11 23 D9 34 86 67 75 75 13
+               :                   12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+               :                   1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+               :                   A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+               :                   7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+               :                   08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+               :                   F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+               :                   32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+               :                   F2 A5 E2 F4 F2 83 E5 B8
+               :                   }
+               :               }
+    629 A3  129:             [3] {
+    632 30  127:               SEQUENCE {
+    634 30   12:                 SEQUENCE {
+    636 06    3:                   OBJECT IDENTIFIER
+               :                     basicConstraints (2 5 29 19)
+               :                     (X.509 id-ce (2 5 29))
+    641 01    1:                   BOOLEAN TRUE
+    644 04    2:                   OCTET STRING, encapsulates {
+    646 30    0:                       SEQUENCE {}
+               :                       }
+               :                   }
+    648 30   14:                 SEQUENCE {
+    650 06    3:                   OBJECT IDENTIFIER
+               :                     keyUsage (2 5 29 15)
+               :                     (X.509 id-ce (2 5 29))
+    655 01    1:                   BOOLEAN TRUE
+    658 04    4:                   OCTET STRING, encapsulates {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 85]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    660 03    2:                       BIT STRING 6 unused bits
+               :                         '11'B
+               :                       }
+               :                   }
+    664 30   31:                 SEQUENCE {
+    666 06    3:                   OBJECT IDENTIFIER
+               :                     authorityKeyIdentifier (2 5 29 35)
+               :                     (X.509 id-ce (2 5 29))
+    671 04   24:                   OCTET STRING, encapsulates {
+    673 30   22:                       SEQUENCE {
+    675 80   20:                         [0]
+               :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+               :                   3D 20 BC 43 2B 93 F1 1F
+               :                         }
+               :                       }
+               :                   }
+    697 30   29:                 SEQUENCE {
+    699 06    3:                   OBJECT IDENTIFIER
+               :                     subjectKeyIdentifier (2 5 29 14)
+               :                     (X.509 id-ce (2 5 29))
+    704 04   22:                   OCTET STRING, encapsulates {
+    706 04   20:                       OCTET STRING
+               :                   BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+               :                   13 01 E2 FD E3 97 FE CD
+               :                       }
+               :                   }
+    728 30   31:                 SEQUENCE {
+    730 06    3:                   OBJECT IDENTIFIER
+               :                     subjectAltName (2 5 29 17)
+               :                     (X.509 id-ce (2 5 29))
+    735 04   24:                   OCTET STRING, encapsulates {
+    737 30   22:                       SEQUENCE {
+    739 81   20:                         [1] 'AliceDSS@example.com'
+               :                         }
+               :                       }
+               :                   }
+               :                 }
+               :               }
+               :             }
+    761 30    9:           SEQUENCE {
+    763 06    7:             OBJECT IDENTIFIER
+               :               dsaWithSha1 (1 2 840 10040 4 3)
+               :               (ANSI X9.57 algorithm)
+               :             }
+    772 03   48:           BIT STRING 0 unused bits, encapsulates {
+    775 30   45:               SEQUENCE {
+    777 02   20:                 INTEGER
+               :                   55 0C A4 19 1F 42 2B 89 71 22 33 8D
+
+
+
+Hoffman, Ed.                 Informational                     [Page 86]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :                   83 6A B5 3D 67 6B BF 45
+    799 02   21:                 INTEGER
+               :                   00 9F 61 53 52 54 0B 5C B2 DD DA E7
+               :                   76 1D E2 10 52 5B 43 5E BD
+               :                 }
+               :               }
+               :           }
+               :         }
+    822 31   95:       SET {
+    824 30   93:         SEQUENCE {
+    826 02    1:           INTEGER 3
+    829 80   20:           [0]
+               :             BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+               :             13 01 E2 FD E3 97 FE CD
+    851 30    7:           SEQUENCE {
+    853 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :               (OIW)
+               :             }
+    860 30    9:           SEQUENCE {
+    862 06    7:             OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
+               :               (ANSI X9.57 algorithm)
+               :             }
+    871 04   46:           OCTET STRING, encapsulates {
+    873 30   44:               SEQUENCE {
+    875 02   20:                 INTEGER
+               :                   6D 8E 5A CD 28 A0 1F D9 86 AD 7A E9
+               :                   DF AC D7 BE EC BE 3F F8
+    897 02   20:                 INTEGER
+               :                   7C 8A 06 1E FC A4 41 35 7E F7 24 14
+               :                   FD 3D C0 56 B7 05 27 D5
+               :                 }
+               :               }
+               :           }
+               :         }
+               :       }
+               :     }
+               :   }
+
+4.8.  S/MIME multipart/signed Message
+
+   A full S/MIME message, including MIME, that includes the body part
+   from 4.3 and the body containing the content of the message.
+
+MIME-Version: 1.0
+To: User2@examples.com
+From: aliceDss@examples.com
+Subject: Example 4.8
+Message-Id: <020906002550300.249@examples.com>
+
+
+
+Hoffman, Ed.                 Informational                     [Page 87]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+Date: Fri, 06 Sep 2002 00:25:21 -0300
+Content-Type: multipart/signed;
+    micalg=SHA1;
+    boundary="----=_NextBoundry____Fri,_06_Sep_2002_00:25:21";
+    protocol="application/pkcs7-signature"
+
+This is a multi-part message in MIME format.
+
+------=_NextBoundry____Fri,_06_Sep_2002_00:25:21
+
+This is some sample content.
+------=_NextBoundry____Fri,_06_Sep_2002_00:25:21
+Content-Type: application/pkcs7-signature; name=smime.p7s
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7s
+
+MIIDdwYJKoZIhvcNAQcCoIIDaDCCA2QCAQExCTAHBgUrDgMCGjALBgkqhkiG9w0BBwGgggL
+gMIIC3DCCApugAwIBAgICAMgwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTMB4XDT
+k5MDgxNzAxMTA0OVoXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIQWxpY2VEU1MwggG2M
+IIBKwYHKoZIzjgEATCCAR4CgYEAgY3N7YPqCp45PsJIKKPkR5PdDteoDuxTxauECE//lOFz
+SH4M1vNESNH+n6+koYkv4dkwyDbeP5u/t0zcX2mK5HXQNwyRCJWb3qde+fz0ny/dQ6iLVPE
+/sAcIR01diMPDtbPjVQh11Tl2EMR4vf+dsISXN/LkURu15AmWXPN+W9sCFQDiR6YaRWa4E8
+baj7g3IStii/eTzQKBgCY40BSJMqo5+z5t2UtZakx2IzkEAjVc8ssaMMMeUF3dm1nizaoFP
+VjAe6I2uG4Hr32KQiWn9HXPSgheSz6Q+G3qnMkhijt2FOnOLl2jB80jhbgvMAF8bUmJEYk2
+RL34yJVKU1a14vlz7BphNh8Rf8K97dFQ/5h0wtGBSmA5ujY5A4GEAAKBgFzjuVp1FJYLqXr
+d4z+p7Kxe3L23ExE0phaJKBEj2TSGZ3V1ExI9Q1tv5VG/+onyohs+JH09B41bY8i7RaWgSu
+OF1s4GgD/oI34a8iSrUxq4Jw0e7wi/ZhSAXGKsZfoVi/G7NNTSljf2YUeyxDKE8H5BQP1Gp
+2NOM/Kl4vTyg+W4o4GBMH8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBsAwHwYDVR0j
+BBgwFoAUcEQ+gi5vh95K03XjPSC8QyuT8R8wHQYDVR0OBBYEFL5sobPjwfftQ3CkzhMB4v3
+jl/7NMB8GA1UdEQQYMBaBFEFsaWNlRFNTQGV4YW1wbGUuY29tMAkGByqGSM44BAMDMAAwLQ
+IUVQykGR9CK4lxIjONg2q1PWdrv0UCFQCfYVNSVAtcst3a53Yd4hBSW0NevTFjMGECAQEwG
+DASMRAwDgYDVQQDEwdDYXJsRFNTAgIAyDAHBgUrDgMCGjAJBgcqhkjOOAQDBC4wLAIUM/mG
+f6gkgp9Z0XtRdGimJeB/BxUCFGFFJqwYRt1WYcIOQoGiaowqGzVI
+
+------=_NextBoundry____Fri,_06_Sep_2002_00:25:21--
+
+4.9.  S/MIME application/pkcs7-mime Signed Message
+
+   A full S/MIME message, including the MIME parts.
+
+MIME-Version: 1.0
+To: User2@examples.com
+From: aliceDss@examples.com
+Subject: Example 4.9
+Message-Id: <021031164540300.304@examples.com>
+Date: Thu, 31 Oct 2002 16:45:14 -0300
+Content-Type: application/pkcs7-mime; smime-type=signed-data;
+    name=smime.p7m
+
+
+
+Hoffman, Ed.                 Informational                     [Page 88]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7m
+
+MIIDmQYJKoZIhvcNAQcCoIIDijCCA4YCAQExCTAHBgUrDgMCGjAtBgkqhkiG9w0BBwGgIAQ
+eDQpUaGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQuoIIC4DCCAtwwggKboAMCAQICAgDIMA
+kGByqGSM44BAMwEjEQMA4GA1UEAxMHQ2FybERTUzAeFw05OTA4MTcwMTEwNDlaFw0zOTEyM
+zEyMzU5NTlaMBMxETAPBgNVBAMTCEFsaWNlRFNTMIIBtjCCASsGByqGSM44BAEwggEeAoGB
+AIGNze2D6gqeOT7CSCij5EeT3Q7XqA7sU8WrhAhP/5Thc0h+DNbzREjR/p+vpKGJL+HZMMg
+23j+bv7dM3F9piuR10DcMkQiVm96nXvn89J8v3UOoi1TxP7AHCEdNXYjDw7Wz41UIddU5dh
+DEeL3/nbCElzfy5FEbteQJllzzflvbAhUA4kemGkVmuBPG2o+4NyErYov3k80CgYAmONAUi
+TKqOfs+bdlLWWpMdiM5BAI1XPLLGjDDHlBd3ZtZ4s2qBT1YwHuiNrhuB699ikIlp/R1z0oI
+Xks+kPht6pzJIYo7dhTpzi5dowfNI4W4LzABfG1JiRGJNkS9+MiVSlNWteL5c+waYTYfEX/
+Cve3RUP+YdMLRgUpgObo2OQOBhAACgYBc47ladRSWC6l63eM/qeysXty9txMRNKYWiSgRI9
+k0hmd1dRMSPUNbb+VRv/qJ8qIbPiR9PQeNW2PIu0WloErjhdbOBoA/6CN+GvIkq1MauCcNH
+u8Iv2YUgFxirGX6FYvxuzTU0pY39mFHssQyhPB+QUD9RqdjTjPypeL08oPluKOBgTB/MAwG
+A1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgbAMB8GA1UdIwQYMBaAFHBEPoIub4feStN14z0
+gvEMrk/EfMB0GA1UdDgQWBBS+bKGz48H37UNwpM4TAeL945f+zTAfBgNVHREEGDAWgRRBbG
+ljZURTU0BleGFtcGxlLmNvbTAJBgcqhkjOOAQDAzAAMC0CFFUMpBkfQiuJcSIzjYNqtT1na
+79FAhUAn2FTUlQLXLLd2ud2HeIQUltDXr0xYzBhAgEBMBgwEjEQMA4GA1UEAxMHQ2FybERT
+UwICAMgwBwYFKw4DAhowCQYHKoZIzjgEAwQuMCwCFD1cSW6LIUFzeXle3YI5SKSBer/sAhQ
+mCq7s/CTFHOEjgASeUjbMpx5g6A==
+
+4.10.  SignedData with Attributes
+
+   A SignedData message with the following list of signedAttributes:
+
+   -unknown OID
+   -contentHints
+   -smimeCapablilties
+   -securityLabel
+   -ContentReference
+   -smimeEncryptKeyPreference
+   -mlExpansionHistory
+   -EquivalentLabel
+
+   0 30 2047: SEQUENCE {
+   4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+            :     (PKCS #7)
+  15 A0 2032:   [0] {
+  19 30 2028:     SEQUENCE {
+  23 02    1:       INTEGER 1
+  26 31    9:       SET {
+  28 30    7:         SEQUENCE {
+  30 06    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+            :             (OIW)
+            :           }
+            :         }
+  37 30   43:       SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 89]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+  39 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+            :           (PKCS #7)
+  50 A0   30:         [0] {
+  52 04   28:           OCTET STRING 'This is some sample content.'
+            :           }
+            :         }
+  82 A0  736:       [0] {
+  86 30  732:         SEQUENCE {
+  90 30  667:           SEQUENCE {
+  94 A0    3:             [0] {
+  96 02    1:               INTEGER 2
+            :               }
+  99 02    2:             INTEGER 200
+ 103 30    9:             SEQUENCE {
+ 105 06    7:               OBJECT IDENTIFIER
+            :                 dsaWithSha1 (1 2 840 10040 4 3)
+            :                 (ANSI X9.57 algorithm)
+            :               }
+ 114 30   18:             SEQUENCE {
+ 116 31   16:               SET {
+ 118 30   14:                 SEQUENCE {
+ 120 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+            :                     (X.520 id-at (2 5 4))
+ 125 13    7:                   PrintableString 'CarlDSS'
+            :                   }
+            :                 }
+            :               }
+ 134 30   30:             SEQUENCE {
+ 136 17   13:               UTCTime '990817011049Z'
+ 151 17   13:               UTCTime '391231235959Z'
+            :               }
+ 166 30   19:             SEQUENCE {
+ 168 31   17:               SET {
+ 170 30   15:                 SEQUENCE {
+ 172 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+            :                     (X.520 id-at (2 5 4))
+ 177 13    8:                   PrintableString 'AliceDSS'
+            :                   }
+            :                 }
+            :               }
+ 187 30  438:             SEQUENCE {
+ 191 30  299:               SEQUENCE {
+ 195 06    7:                 OBJECT IDENTIFIER
+            :                   dsa (1 2 840 10040 4 1)
+            :                   (ANSI X9.57 algorithm)
+ 204 30  286:                 SEQUENCE {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 90]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+ 208 02  129:                   INTEGER
+            :                   00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+            :                   48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+            :                   53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+            :                   0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+            :                   2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+            :                   DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+            :                   9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+            :                   8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+            :                   C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+            :                   78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+            :                   B5 E4 09 96 5C F3 7E 5B DB
+ 340 02   21:                   INTEGER
+            :                   00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+            :                   B8 37 21 2B 62 8B F7 93 CD
+ 363 02  128:                   INTEGER
+            :                   26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+            :                   4B 59 6A 4C 76 23 39 04 02 35 5C F2
+            :                   CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+            :                   AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+            :                   7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+            :                   3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+            :                   E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+            :                   01 7C 6D 49 89 11 89 36 44 BD F8 C8
+            :                   95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+            :                   1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+            :                   D1 81 4A 60 39 BA 36 39
+            :                   }
+            :                 }
+ 494 03  132:               BIT STRING 0 unused bits, encapsulates {
+ 498 02  128:                   INTEGER
+            :                   5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+            :                   3F A9 EC AC 5E DC BD B7 13 11 34 A6
+            :                   16 89 28 11 23 D9 34 86 67 75 75 13
+            :                   12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+            :                   1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+            :                   A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+            :                   7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+            :                   08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+            :                   F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+            :                   32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+            :                   F2 A5 E2 F4 F2 83 E5 B8
+            :                   }
+            :               }
+ 629 A3  129:             [3] {
+ 632 30  127:               SEQUENCE {
+ 634 30   12:                 SEQUENCE {
+ 636 06    3:                   OBJECT IDENTIFIER
+
+
+
+Hoffman, Ed.                 Informational                     [Page 91]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                     basicConstraints (2 5 29 19)
+            :                     (X.509 id-ce (2 5 29))
+ 641 01    1:                   BOOLEAN TRUE
+ 644 04    2:                   OCTET STRING, encapsulates {
+ 646 30    0:                       SEQUENCE {}
+            :                       }
+            :                   }
+ 648 30   14:                 SEQUENCE {
+ 650 06    3:                   OBJECT IDENTIFIER
+            :                     keyUsage (2 5 29 15)
+            :                     (X.509 id-ce (2 5 29))
+ 655 01    1:                   BOOLEAN TRUE
+ 658 04    4:                   OCTET STRING, encapsulates {
+ 660 03    2:                       BIT STRING 6 unused bits
+            :                         '11'B
+            :                       }
+            :                   }
+ 664 30   31:                 SEQUENCE {
+ 666 06    3:                   OBJECT IDENTIFIER
+            :                     authorityKeyIdentifier (2 5 29 35)
+            :                     (X.509 id-ce (2 5 29))
+ 671 04   24:                   OCTET STRING, encapsulates {
+ 673 30   22:                       SEQUENCE {
+ 675 80   20:                         [0]
+            :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+            :                   3D 20 BC 43 2B 93 F1 1F
+            :                         }
+            :                       }
+            :                   }
+ 697 30   29:                 SEQUENCE {
+ 699 06    3:                   OBJECT IDENTIFIER
+            :                     subjectKeyIdentifier (2 5 29 14)
+            :                     (X.509 id-ce (2 5 29))
+ 704 04   22:                   OCTET STRING, encapsulates {
+ 706 04   20:                       OCTET STRING
+            :                   BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+            :                   13 01 E2 FD E3 97 FE CD
+            :                       }
+            :                   }
+ 728 30   31:                 SEQUENCE {
+ 730 06    3:                   OBJECT IDENTIFIER
+            :                     subjectAltName (2 5 29 17)
+            :                     (X.509 id-ce (2 5 29))
+ 735 04   24:                   OCTET STRING, encapsulates {
+ 737 30   22:                       SEQUENCE {
+ 739 81   20:                         [1] 'AliceDSS@example.com'
+            :                         }
+            :                       }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 92]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                   }
+            :                 }
+            :               }
+            :             }
+ 761 30    9:           SEQUENCE {
+ 763 06    7:             OBJECT IDENTIFIER
+            :               dsaWithSha1 (1 2 840 10040 4 3)
+            :               (ANSI X9.57 algorithm)
+            :             }
+ 772 03   48:           BIT STRING 0 unused bits, encapsulates {
+ 775 30   45:               SEQUENCE {
+ 777 02   20:                 INTEGER
+            :                   55 0C A4 19 1F 42 2B 89 71 22 33 8D
+            :                   83 6A B5 3D 67 6B BF 45
+ 799 02   21:                 INTEGER
+            :                   00 9F 61 53 52 54 0B 5C B2 DD DA E7
+            :                   76 1D E2 10 52 5B 43 5E BD
+            :                 }
+            :               }
+            :           }
+            :         }
+ 822 31 1225:       SET {
+ 826 30 1221:         SEQUENCE {
+ 830 02    1:           INTEGER 1
+ 833 30   24:           SEQUENCE {
+ 835 30   18:             SEQUENCE {
+ 837 31   16:               SET {
+ 839 30   14:                 SEQUENCE {
+ 841 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+            :                     (X.520 id-at (2 5 4))
+ 846 13    7:                   PrintableString 'CarlDSS'
+            :                   }
+            :                 }
+            :               }
+ 855 02    2:             INTEGER 200
+            :             }
+ 859 30    7:           SEQUENCE {
+ 861 06    5:             OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+            :               (OIW)
+            :             }
+ 868 A0 1119:           [0] {
+ 872 30   24:             SEQUENCE {
+ 874 06    9:               OBJECT IDENTIFIER
+            :                 contentType (1 2 840 113549 1 9 3)
+            :                 (PKCS #9 (1 2 840 113549 1 9))
+ 885 31   11:               SET {
+ 887 06    9:                 OBJECT IDENTIFIER
+
+
+
+Hoffman, Ed.                 Informational                     [Page 93]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                   data (1 2 840 113549 1 7 1)
+            :                   (PKCS #7)
+            :                 }
+            :               }
+ 898 30   35:             SEQUENCE {
+ 900 06    9:               OBJECT IDENTIFIER
+            :                 messageDigest (1 2 840 113549 1 9 4)
+            :                 (PKCS #9 (1 2 840 113549 1 9))
+ 911 31   22:               SET {
+ 913 04   20:                 OCTET STRING
+            :                   40 6A EC 08 52 79 BA 6E 16 02 2D 9E
+            :                   06 29 C0 22 96 87 DD 48
+            :                 }
+            :               }
+ 935 30   56:             SEQUENCE {
+ 937 06    3:               OBJECT IDENTIFIER '1 2 5555'
+ 942 31   49:               SET {
+ 944 04   47:                 OCTET STRING
+            :                   'This is a test General ASN Attribut'
+            :                   'e, number 1.'
+            :                 }
+            :               }
+ 993 30   62:             SEQUENCE {
+ 995 06   11:               OBJECT IDENTIFIER
+            :                 id-aa-contentHint
+            :                     (1 2 840 113549 1 9 16 2 4)
+            :                 (S/MIME Authenticated Attributes
+            :                     (1 2 840 113549 1 9 16 2))
+1008 31   47:               SET {
+1010 30   45:                 SEQUENCE {
+1012 0C   32:                   UTF8String
+            :                   'Content Hints Description Buffer'
+1046 06    9:                   OBJECT IDENTIFIER
+            :                     data (1 2 840 113549 1 7 1)
+            :                     (PKCS #7)
+            :                   }
+            :                 }
+            :               }
+1057 30   74:             SEQUENCE {
+1059 06    9:               OBJECT IDENTIFIER
+            :                 sMIMECapabilities
+            :                     (1 2 840 113549 1 9 15)
+            :                 (PKCS #9
+            :                     (1 2 840 113549 1 9))
+1070 31   61:               SET {
+1072 30   59:                 SEQUENCE {
+1074 30    7:                   SEQUENCE {
+1076 06    5:                     OBJECT IDENTIFIER '1 2 3 4 5 6'
+
+
+
+Hoffman, Ed.                 Informational                     [Page 94]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                     }
+1083 30   48:                   SEQUENCE {
+1085 06    6:                     OBJECT IDENTIFIER '1 2 3 4 5 6 77'
+1093 04   38:                     OCTET STRING
+            :                   'Smime Capabilities parameters buffe'
+            :                   'r 2'
+            :                     }
+            :                   }
+            :                 }
+            :               }
+1133 30  109:             SEQUENCE {
+1135 06   11:               OBJECT IDENTIFIER
+            :                 id-aa-securityLabel
+            :                     (1 2 840 113549 1 9 16 2 2)
+            :                 (S/MIME Authenticated Attributes
+            :                     (1 2 840 113549 1 9 16 2))
+1148 31   94:               SET {
+1150 31   92:                 SET {
+1152 02    1:                   INTEGER 1
+1155 06    7:                   OBJECT IDENTIFIER '1 2 3 4 5 6 7 8'
+1164 13   27:                   PrintableString
+            :                   'THIS IS A PRIVACY MARK TEST'
+1193 31   49:                   SET {
+1195 30   47:                     SEQUENCE {
+1197 80    8:                       [0]
+            :                   2A 03 04 05 06 07 86 78
+1207 A1   35:                       [1] {
+1209 13   33:                         PrintableString
+            :                         'THIS IS A TEST SECURITY-'
+            :                         'CATEGORY.'
+            :                         }
+            :                       }
+            :                     }
+            :                   }
+            :                 }
+            :               }
+1244 30  111:             SEQUENCE {
+1246 06   11:               OBJECT IDENTIFIER
+            :                 id-aa-contentReference
+            :                     (1 2 840 113549 1 9 16 2 10)
+            :                 (S/MIME Authenticated Attributes
+            :                     (1 2 840 113549 1 9 16 2))
+1259 31   96:               SET {
+1261 30   94:                 SEQUENCE {
+1263 06    5:                   OBJECT IDENTIFIER '1 2 3 4 5 6'
+1270 04   43:                   OCTET STRING
+            :                   'Content Reference Content Identifie'
+            :                   'r Buffer'
+
+
+
+Hoffman, Ed.                 Informational                     [Page 95]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+1315 04   40:                   OCTET STRING
+            :                   'Content Reference Signature Value B'
+            :                   'uffer'
+            :                   }
+            :                 }
+            :               }
+1357 30  115:             SEQUENCE {
+1359 06   11:               OBJECT IDENTIFIER
+            :                 id-aa-encrypKeyPref
+            :                     (1 2 840 113549 1 9 16 2 11)
+            :                 (S/MIME Authenticated Attributes
+            :                     (1 2 840 113549 1 9 16 2))
+1372 31  100:               SET {
+1374 A0   98:                 [0] {
+1376 30   90:                   SEQUENCE {
+1378 31   11:                     SET {
+1380 30    9:                       SEQUENCE {
+1382 06    3:                         OBJECT IDENTIFIER
+            :                           countryName (2 5 4 6)
+            :                           (X.520 id-at (2 5 4))
+1387 13    2:                         PrintableString 'US'
+            :                         }
+            :                       }
+1391 31   22:                     SET {
+1393 30   20:                       SEQUENCE {
+1395 06    3:                         OBJECT IDENTIFIER
+            :                           organizationName (2 5 4 10)
+            :                           (X.520 id-at (2 5 4))
+1400 13   13:                         PrintableString 'US Government'
+            :                         }
+            :                       }
+1415 31   17:                     SET {
+1417 30   15:                       SEQUENCE {
+1419 06    3:                         OBJECT IDENTIFIER
+            :                           organizationalUnitName
+            :                               (2 5 4 11)
+            :                           (X.520 id-at (2 5 4))
+1424 13    8:                         PrintableString 'VDA Site'
+            :                         }
+            :                       }
+1434 31   12:                     SET {
+1436 30   10:                       SEQUENCE {
+1438 06    3:                         OBJECT IDENTIFIER
+            :                           organizationalUnitName
+            :                               (2 5 4 11)
+            :                           (X.520 id-at (2 5 4))
+1443 13    3:                         PrintableString 'VDA'
+            :                         }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 96]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                       }
+1448 31   18:                     SET {
+1450 30   16:                       SEQUENCE {
+1452 06    3:                         OBJECT IDENTIFIER
+            :                           commonName (2 5 4 3)
+            :                           (X.520 id-at (2 5 4))
+1457 13    9:                         PrintableString 'Daisy RSA'
+            :                         }
+            :                       }
+            :                     }
+1468 02    4:                   INTEGER 173360179
+            :                   }
+            :                 }
+            :               }
+1474 30  252:             SEQUENCE {
+1477 06   11:               OBJECT IDENTIFIER
+            :                 id-aa-mlExpandHistory
+            :                     (1 2 840 113549 1 9 16 2 3)
+            :                 (S/MIME Authenticated Attributes
+            :                     (1 2 840 113549 1 9 16 2))
+1490 31  236:               SET {
+1493 30  233:                 SEQUENCE {
+1496 30  230:                   SEQUENCE {
+1499 04    7:                     OCTET STRING '5738299'
+1508 18   15:                     GeneralizedTime '19990311104433Z'
+1525 A1  201:                     [1] {
+1528 30  198:                       SEQUENCE {
+1531 A4   97:                         [4] {
+1533 30   95:                           SEQUENCE {
+1535 31   11:                             SET {
+1537 30    9:                               SEQUENCE {
+1539 06    3:                                 OBJECT IDENTIFIER
+            :                                   countryName (2 5 4 6)
+            :                                   (X.520 id-at (2 5 4))
+1544 13    2:                                 PrintableString 'US'
+            :                                 }
+            :                               }
+1548 31   22:                             SET {
+1550 30   20:                               SEQUENCE {
+1552 06    3:                                 OBJECT IDENTIFIER
+            :                                   organizationName
+            :                                       (2 5 4 10)
+            :                                   (X.520 id-at (2 5 4))
+1557 13   13:                                 PrintableString
+            :                                 'US Government'
+            :                                 }
+            :                               }
+1572 31   17:                             SET {
+
+
+
+Hoffman, Ed.                 Informational                     [Page 97]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+1574 30   15:                               SEQUENCE {
+1576 06    3:                                 OBJECT IDENTIFIER
+            :                                   organizationalUnitName
+            :                                       (2 5 4 11)
+            :                                   (X.520 id-at (2 5 4))
+1581 13    8:                                 PrintableString
+            :                                 'VDA Site'
+            :                                 }
+            :                               }
+1591 31   12:                             SET {
+1593 30   10:                               SEQUENCE {
+1595 06    3:                                 OBJECT IDENTIFIER
+            :                                   organizationalUnitName
+            :                                       (2 5 4 11)
+            :                                   (X.520 id-at (2 5 4))
+1600 13    3:                                 PrintableString 'VDA'
+            :                                 }
+            :                               }
+1605 31   23:                             SET {
+1607 30   21:                               SEQUENCE {
+1609 06    3:                                 OBJECT IDENTIFIER
+            :                                   commonName (2 5 4 3)
+            :                                   (X.520 id-at (2 5 4))
+1614 13   14:                                 PrintableString
+            :                                 'Bugs Bunny DSA'
+            :                                 }
+            :                               }
+            :                             }
+            :                           }
+1630 A4   97:                         [4] {
+1632 30   95:                           SEQUENCE {
+1634 31   11:                             SET {
+1636 30    9:                               SEQUENCE {
+1638 06    3:                                 OBJECT IDENTIFIER
+            :                                   countryName (2 5 4 6)
+            :                                   (X.520 id-at (2 5 4))
+1643 13    2:                                 PrintableString 'US'
+            :                                 }
+            :                               }
+1647 31   22:                             SET {
+1649 30   20:                               SEQUENCE {
+1651 06    3:                                 OBJECT IDENTIFIER
+            :                                   organizationName
+            :                                       (2 5 4 10)
+            :                                   (X.520 id-at (2 5 4))
+1656 13   13:                                 PrintableString
+            :                                 'US Government'
+            :                                 }
+
+
+
+Hoffman, Ed.                 Informational                     [Page 98]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                               }
+1671 31   17:                             SET {
+1673 30   15:                               SEQUENCE {
+1675 06    3:                                 OBJECT IDENTIFIER
+            :                                   organizationalUnitName
+            :                                       (2 5 4 11)
+            :                                   (X.520 id-at (2 5 4))
+1680 13    8:                                 PrintableString
+            :                                 'VDA Site'
+            :                                 }
+            :                               }
+1690 31   12:                             SET {
+1692 30   10:                               SEQUENCE {
+1694 06    3:                                 OBJECT IDENTIFIER
+            :                                   organizationalUnitName
+            :                                       (2 5 4 11)
+            :                                   (X.520 id-at (2 5 4))
+1699 13    3:                                 PrintableString 'VDA'
+            :                                 }
+            :                               }
+1704 31   23:                             SET {
+1706 30   21:                               SEQUENCE {
+1708 06    3:                                 OBJECT IDENTIFIER
+            :                                   commonName (2 5 4 3)
+            :                                   (X.520 id-at (2 5 4))
+1713 13   14:                                 PrintableString
+            :                                 'Elmer Fudd DSA'
+            :                                 }
+            :                               }
+            :                             }
+            :                           }
+            :                         }
+            :                       }
+            :                     }
+            :                   }
+            :                 }
+            :               }
+1729 30  258:             SEQUENCE {
+1733 06   11:               OBJECT IDENTIFIER
+            :                 id-aa-equivalentLabels
+            :                     (1 2 840 113549 1 9 16 2 9)
+            :                 (S/MIME Authenticated Attributes
+            :                     (1 2 840 113549 1 9 16 2))
+1746 31  242:               SET {
+1749 30  239:                 SEQUENCE {
+1752 31  114:                   SET {
+1754 02    1:                     INTEGER 1
+1757 06    7:                     OBJECT IDENTIFIER '1 2 3 4 5 6 7 9'
+
+
+
+Hoffman, Ed.                 Informational                     [Page 99]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+1766 13   38:                     PrintableString
+            :                   'EQUIVALENT THIS IS A PRIVACY MARK T'
+            :                   'EST'
+1806 31   60:                     SET {
+1808 30   58:                       SEQUENCE {
+1810 80    8:                         [0]
+            :                   2A 03 04 05 06 07 86 78
+1820 A1   46:                         [1] {
+1822 13   44:                           PrintableString
+            :                   'EQUIVALENT THIS IS A TEST SECURITY-'
+            :                   'CATEGORY.'
+            :                           }
+            :                         }
+            :                       }
+            :                     }
+1868 31  121:                   SET {
+1870 02    1:                     INTEGER 1
+1873 06    7:                     OBJECT IDENTIFIER
+            :                     '1 2 3 4 5 6 7 10'
+1882 13   45:                     PrintableString
+            :                   'EQUIVALENT THIS IS A SECOND PRIVACY'
+            :                   ' MARK TEST'
+1929 31   60:                     SET {
+1931 30   58:                       SEQUENCE {
+1933 80    8:                         [0]
+            :                   2A 03 04 05 06 07 86 78
+1943 A1   46:                         [1] {
+1945 13   44:                           PrintableString
+            :                   'EQUIVALENT THIS IS A TEST SECURITY-'
+            :                   'CATEGORY.'
+            :                           }
+            :                         }
+            :                       }
+            :                     }
+            :                   }
+            :                 }
+            :               }
+            :             }
+1991 30    9:           SEQUENCE {
+1993 06    7:             OBJECT IDENTIFIER
+            :               dsaWithSha1 (1 2 840 10040 4 3)
+            :               (ANSI X9.57 algorithm)
+            :             }
+2002 04   47:           OCTET STRING, encapsulates {
+2004 30   45:               SEQUENCE {
+2006 02   21:                 INTEGER
+            :                   00 BC 33 37 65 C4 F7 70 5C 17 49 13
+            :                   AA 4C 85 CA BB 52 91 48 59
+
+
+
+Hoffman, Ed.                 Informational                    [Page 100]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+2029 02   20:                 INTEGER
+            :                   63 96 A2 14 8B CF 57 DE B0 48 5F 6C
+            :                   64 DD 84 04 49 5F 1C CA
+            :                 }
+            :               }
+            :           }
+            :         }
+            :       }
+            :     }
+            :   }
+
+4.11.  SignedData with Certificates Only
+
+   CA SignedData message with no content or signature, containing only
+   Alices's and Carl's certificates.
+
+   0 30 1672: SEQUENCE {
+   4 06    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
+            :     (PKCS #7)
+  15 A0 1657:   [0] {
+  19 30 1653:     SEQUENCE {
+  23 02    1:       INTEGER 1
+  26 31    0:       SET {}
+  28 30   11:       SEQUENCE {
+  30 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+            :           (PKCS #7)
+            :         }
+  41 A0 1407:       [0] {
+  45 30  667:         SEQUENCE {
+  49 30  602:           SEQUENCE {
+  53 A0    3:             [0] {
+  55 02    1:               INTEGER 2
+            :               }
+  58 02    1:             INTEGER 1
+  61 30    9:             SEQUENCE {
+  63 06    7:               OBJECT IDENTIFIER
+            :                 dsaWithSha1 (1 2 840 10040 4 3)
+            :                 (ANSI X9.57 algorithm)
+            :               }
+  72 30   18:             SEQUENCE {
+  74 31   16:               SET {
+  76 30   14:                 SEQUENCE {
+  78 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+            :                     (X.520 id-at (2 5 4))
+  83 13    7:                   PrintableString 'CarlDSS'
+            :                   }
+            :                 }
+
+
+
+Hoffman, Ed.                 Informational                    [Page 101]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :               }
+  92 30   30:             SEQUENCE {
+  94 17   13:               UTCTime '990816225050Z'
+ 109 17   13:               UTCTime '391231235959Z'
+            :               }
+ 124 30   18:             SEQUENCE {
+ 126 31   16:               SET {
+ 128 30   14:                 SEQUENCE {
+ 130 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+            :                     (X.520 id-at (2 5 4))
+ 135 13    7:                   PrintableString 'CarlDSS'
+            :                   }
+            :                 }
+            :               }
+ 144 30  439:             SEQUENCE {
+ 148 30  299:               SEQUENCE {
+ 152 06    7:                 OBJECT IDENTIFIER
+            :                   dsa (1 2 840 10040 4 1)
+            :                   (ANSI X9.57 algorithm)
+ 161 30  286:                 SEQUENCE {
+ 165 02  129:                   INTEGER
+            :                   00 B6 49 18 3E 8A 44 C1 29 71 94 4C
+            :                   01 C4 12 C1 7A 79 CB 54 4D AB 1E 81
+            :                   FB C6 4C B3 0E 94 09 06 EB 01 D4 B1
+            :                   C8 71 4B C7 45 C0 50 25 5D 9C FC DA
+            :                   E4 6D D3 E2 86 48 84 82 7D BA 15 95
+            :                   4A 16 F6 46 ED DD F6 98 D2 BB 7E 8A
+            :                   0A 8A BA 16 7B B9 50 01 48 93 8B EB
+            :                   25 15 51 97 55 DC 8F 53 0E 10 A9 50
+            :                   FC 70 B7 CD 30 54 FD DA DE A8 AA 22
+            :                   B5 A1 AF 8B CC 02 88 E7 8B 70 5F B9
+            :                   AD E1 08 D4 6D 29 2D D6 E9
+ 297 02   21:                   INTEGER
+            :                   00 DD C1 2F DF 53 CE 0B 34 60 77 3E
+            :                   02 A4 BF 8A 5D 98 B9 10 D5
+ 320 02  128:                   INTEGER
+            :                   0C EE 57 9B 4B BD DA B6 07 6A 74 37
+            :                   4F 55 7F 9D ED BC 61 0D EB 46 59 3C
+            :                   56 0B 2B 5B 0C 91 CE A5 62 52 69 CA
+            :                   E1 6D 3E BD BF FE E1 B7 B9 2B 61 3C
+            :                   AD CB AE 45 E3 06 AC 8C 22 9D 9C 44
+            :                   87 0B C7 CD F0 1C D9 B5 4E 5D 73 DE
+            :                   AF 0E C9 1D 5A 51 F5 4F 44 79 35 5A
+            :                   73 AA 7F 46 51 1F A9 42 16 9C 48 EB
+            :                   8A 79 61 B4 D5 2F 53 22 44 63 1F 86
+            :                   B8 A3 58 06 25 F8 29 C0 EF BA E0 75
+            :                   F0 42 C4 63 65 52 9B 0A
+
+
+
+Hoffman, Ed.                 Informational                    [Page 102]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                   }
+            :                 }
+ 451 03  133:               BIT STRING 0 unused bits, encapsulates {
+ 455 02  129:                   INTEGER
+            :                   00 99 87 74 27 03 66 A0 B1 C0 AD DC
+            :                   2C 75 BB E1 6C 44 9C DA 21 6D 4D 47
+            :                   6D B1 62 09 E9 D8 AE 1E F2 3A B4 94
+            :                   B1 A3 8E 7A 9B 71 4E 00 94 C9 B4 25
+            :                   4E B9 60 96 19 24 01 F3 62 0C FE 75
+            :                   C0 FB CE D8 68 00 E3 FD D5 70 4F DF
+            :                   23 96 19 06 94 F4 B1 61 8F 3A 57 B1
+            :                   08 11 A4 0B 26 25 F0 52 76 81 EA 0B
+            :                   62 0D 95 2A E6 86 BA 72 B2 A7 50 83
+            :                   0B AA 27 CD 1B A9 4D 89 9A D7 8D 18
+            :                   39 84 3F 8B C5 56 4D 80 7A
+            :                   }
+            :               }
+ 587 A3   66:             [3] {
+ 589 30   64:               SEQUENCE {
+ 591 30   15:                 SEQUENCE {
+ 593 06    3:                   OBJECT IDENTIFIER
+            :                     basicConstraints (2 5 29 19)
+            :                     (X.509 id-ce (2 5 29))
+ 598 01    1:                   BOOLEAN TRUE
+ 601 04    5:                   OCTET STRING, encapsulates {
+ 603 30    3:                       SEQUENCE {
+ 605 01    1:                         BOOLEAN TRUE
+            :                         }
+            :                       }
+            :                   }
+ 608 30   14:                 SEQUENCE {
+ 610 06    3:                   OBJECT IDENTIFIER
+            :                     keyUsage (2 5 29 15)
+            :                     (X.509 id-ce (2 5 29))
+ 615 01    1:                   BOOLEAN TRUE
+ 618 04    4:                   OCTET STRING, encapsulates {
+ 620 03    2:                       BIT STRING 1 unused bits
+            :                         '1100001'B
+            :                       }
+            :                   }
+ 624 30   29:                 SEQUENCE {
+ 626 06    3:                   OBJECT IDENTIFIER
+            :                     subjectKeyIdentifier (2 5 29 14)
+            :                     (X.509 id-ce (2 5 29))
+ 631 04   22:                   OCTET STRING, encapsulates {
+ 633 04   20:                       OCTET STRING
+            :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+            :                   3D 20 BC 43 2B 93 F1 1F
+
+
+
+Hoffman, Ed.                 Informational                    [Page 103]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                       }
+            :                   }
+            :                 }
+            :               }
+            :             }
+ 655 30    9:           SEQUENCE {
+ 657 06    7:             OBJECT IDENTIFIER
+            :               dsaWithSha1 (1 2 840 10040 4 3)
+            :               (ANSI X9.57 algorithm)
+            :             }
+ 666 03   48:           BIT STRING 0 unused bits, encapsulates {
+ 669 30   45:               SEQUENCE {
+ 671 02   20:                 INTEGER
+            :                   6B A9 F0 4E 7A 5A 79 E3 F9 BE 3D 2B
+            :                   C9 06 37 E9 11 17 A1 13
+ 693 02   21:                 INTEGER
+            :                   00 8F 34 69 2A 8B B1 3C 03 79 94 32
+            :                   4D 12 1F CE 89 FB 46 B2 3B
+            :                 }
+            :               }
+            :           }
+ 716 30  732:         SEQUENCE {
+ 720 30  667:           SEQUENCE {
+ 724 A0    3:             [0] {
+ 726 02    1:               INTEGER 2
+            :               }
+ 729 02    2:             INTEGER 200
+ 733 30    9:             SEQUENCE {
+ 735 06    7:               OBJECT IDENTIFIER
+            :                 dsaWithSha1 (1 2 840 10040 4 3)
+            :                 (ANSI X9.57 algorithm)
+            :               }
+ 744 30   18:             SEQUENCE {
+ 746 31   16:               SET {
+ 748 30   14:                 SEQUENCE {
+ 750 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+            :                     (X.520 id-at (2 5 4))
+ 755 13    7:                   PrintableString 'CarlDSS'
+            :                   }
+            :                 }
+            :               }
+ 764 30   30:             SEQUENCE {
+ 766 17   13:               UTCTime '990817011049Z'
+ 781 17   13:               UTCTime '391231235959Z'
+            :               }
+ 796 30   19:             SEQUENCE {
+ 798 31   17:               SET {
+
+
+
+Hoffman, Ed.                 Informational                    [Page 104]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+ 800 30   15:                 SEQUENCE {
+ 802 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+            :                     (X.520 id-at (2 5 4))
+ 807 13    8:                   PrintableString 'AliceDSS'
+            :                   }
+            :                 }
+            :               }
+ 817 30  438:             SEQUENCE {
+ 821 30  299:               SEQUENCE {
+ 825 06    7:                 OBJECT IDENTIFIER
+            :                   dsa (1 2 840 10040 4 1)
+            :                   (ANSI X9.57 algorithm)
+ 834 30  286:                 SEQUENCE {
+ 838 02  129:                   INTEGER
+            :                   00 81 8D CD ED 83 EA 0A 9E 39 3E C2
+            :                   48 28 A3 E4 47 93 DD 0E D7 A8 0E EC
+            :                   53 C5 AB 84 08 4F FF 94 E1 73 48 7E
+            :                   0C D6 F3 44 48 D1 FE 9F AF A4 A1 89
+            :                   2F E1 D9 30 C8 36 DE 3F 9B BF B7 4C
+            :                   DC 5F 69 8A E4 75 D0 37 0C 91 08 95
+            :                   9B DE A7 5E F9 FC F4 9F 2F DD 43 A8
+            :                   8B 54 F1 3F B0 07 08 47 4D 5D 88 C3
+            :                   C3 B5 B3 E3 55 08 75 D5 39 76 10 C4
+            :                   78 BD FF 9D B0 84 97 37 F2 E4 51 1B
+            :                   B5 E4 09 96 5C F3 7E 5B DB
+ 970 02   21:                   INTEGER
+            :                   00 E2 47 A6 1A 45 66 B8 13 C6 DA 8F
+            :                   B8 37 21 2B 62 8B F7 93 CD
+ 993 02  128:                   INTEGER
+            :                   26 38 D0 14 89 32 AA 39 FB 3E 6D D9
+            :                   4B 59 6A 4C 76 23 39 04 02 35 5C F2
+            :                   CB 1A 30 C3 1E 50 5D DD 9B 59 E2 CD
+            :                   AA 05 3D 58 C0 7B A2 36 B8 6E 07 AF
+            :                   7D 8A 42 25 A7 F4 75 CF 4A 08 5E 4B
+            :                   3E 90 F8 6D EA 9C C9 21 8A 3B 76 14
+            :                   E9 CE 2E 5D A3 07 CD 23 85 B8 2F 30
+            :                   01 7C 6D 49 89 11 89 36 44 BD F8 C8
+            :                   95 4A 53 56 B5 E2 F9 73 EC 1A 61 36
+            :                   1F 11 7F C2 BD ED D1 50 FF 98 74 C2
+            :                   D1 81 4A 60 39 BA 36 39
+            :                   }
+            :                 }
+1124 03  132:               BIT STRING 0 unused bits, encapsulates {
+1128 02  128:                   INTEGER
+            :                   5C E3 B9 5A 75 14 96 0B A9 7A DD E3
+            :                   3F A9 EC AC 5E DC BD B7 13 11 34 A6
+            :                   16 89 28 11 23 D9 34 86 67 75 75 13
+
+
+
+Hoffman, Ed.                 Informational                    [Page 105]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                   12 3D 43 5B 6F E5 51 BF FA 89 F2 A2
+            :                   1B 3E 24 7D 3D 07 8D 5B 63 C8 BB 45
+            :                   A5 A0 4A E3 85 D6 CE 06 80 3F E8 23
+            :                   7E 1A F2 24 AB 53 1A B8 27 0D 1E EF
+            :                   08 BF 66 14 80 5C 62 AC 65 FA 15 8B
+            :                   F1 BB 34 D4 D2 96 37 F6 61 47 B2 C4
+            :                   32 84 F0 7E 41 40 FD 46 A7 63 4E 33
+            :                   F2 A5 E2 F4 F2 83 E5 B8
+            :                   }
+            :               }
+1259 A3  129:             [3] {
+1262 30  127:               SEQUENCE {
+1264 30   12:                 SEQUENCE {
+1266 06    3:                   OBJECT IDENTIFIER
+            :                     basicConstraints (2 5 29 19)
+            :                     (X.509 id-ce (2 5 29))
+1271 01    1:                   BOOLEAN TRUE
+1274 04    2:                   OCTET STRING, encapsulates {
+1276 30    0:                       SEQUENCE {}
+            :                       }
+            :                   }
+1278 30   14:                 SEQUENCE {
+1280 06    3:                   OBJECT IDENTIFIER
+            :                     keyUsage (2 5 29 15)
+            :                     (X.509 id-ce (2 5 29))
+1285 01    1:                   BOOLEAN TRUE
+1288 04    4:                   OCTET STRING, encapsulates {
+1290 03    2:                       BIT STRING 6 unused bits
+            :                         '11'B
+            :                       }
+            :                   }
+1294 30   31:                 SEQUENCE {
+1296 06    3:                   OBJECT IDENTIFIER
+            :                     authorityKeyIdentifier (2 5 29 35)
+            :                     (X.509 id-ce (2 5 29))
+1301 04   24:                   OCTET STRING, encapsulates {
+1303 30   22:                       SEQUENCE {
+1305 80   20:                         [0]
+            :                   70 44 3E 82 2E 6F 87 DE 4A D3 75 E3
+            :                   3D 20 BC 43 2B 93 F1 1F
+            :                         }
+            :                       }
+            :                   }
+1327 30   29:                 SEQUENCE {
+1329 06    3:                   OBJECT IDENTIFIER
+            :                     subjectKeyIdentifier (2 5 29 14)
+            :                     (X.509 id-ce (2 5 29))
+1334 04   22:                   OCTET STRING, encapsulates {
+
+
+
+Hoffman, Ed.                 Informational                    [Page 106]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+1336 04   20:                       OCTET STRING
+            :                   BE 6C A1 B3 E3 C1 F7 ED 43 70 A4 CE
+            :                   13 01 E2 FD E3 97 FE CD
+            :                       }
+            :                   }
+1358 30   31:                 SEQUENCE {
+1360 06    3:                   OBJECT IDENTIFIER
+            :                     subjectAltName (2 5 29 17)
+            :                     (X.509 id-ce (2 5 29))
+1365 04   24:                   OCTET STRING, encapsulates {
+1367 30   22:                       SEQUENCE {
+1369 81   20:                         [1] 'AliceDSS@example.com'
+            :                         }
+            :                       }
+            :                   }
+            :                 }
+            :               }
+            :             }
+1391 30    9:           SEQUENCE {
+1393 06    7:             OBJECT IDENTIFIER
+            :               dsaWithSha1 (1 2 840 10040 4 3)
+            :               (ANSI X9.57 algorithm)
+            :             }
+1402 03   48:           BIT STRING 0 unused bits, encapsulates {
+1405 30   45:               SEQUENCE {
+1407 02   20:                 INTEGER
+            :                   55 0C A4 19 1F 42 2B 89 71 22 33 8D
+            :                   83 6A B5 3D 67 6B BF 45
+1429 02   21:                 INTEGER
+            :                   00 9F 61 53 52 54 0B 5C B2 DD DA E7
+            :                   76 1D E2 10 52 5B 43 5E BD
+            :                 }
+            :               }
+            :           }
+            :         }
+1452 A1  219:       [1] {
+1455 30  216:         SEQUENCE {
+1458 30  153:           SEQUENCE {
+1461 30    9:             SEQUENCE {
+1463 06    7:               OBJECT IDENTIFIER
+            :                 dsaWithSha1 (1 2 840 10040 4 3)
+            :                 (ANSI X9.57 algorithm)
+            :               }
+1472 30   18:             SEQUENCE {
+1474 31   16:               SET {
+1476 30   14:                 SEQUENCE {
+1478 06    3:                   OBJECT IDENTIFIER
+            :                     commonName (2 5 4 3)
+
+
+
+Hoffman, Ed.                 Informational                    [Page 107]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :                     (X.520 id-at (2 5 4))
+1483 13    7:                   PrintableString 'CarlDSS'
+            :                   }
+            :                 }
+            :               }
+1492 17   13:             UTCTime '990827070000Z'
+1507 30  105:             SEQUENCE {
+1509 30   19:               SEQUENCE {
+1511 02    2:                 INTEGER 200
+1515 17   13:                 UTCTime '990822070000Z'
+            :                 }
+1530 30   19:               SEQUENCE {
+1532 02    2:                 INTEGER 201
+1536 17   13:                 UTCTime '990822070000Z'
+            :                 }
+1551 30   19:               SEQUENCE {
+1553 02    2:                 INTEGER 211
+1557 17   13:                 UTCTime '990822070000Z'
+            :                 }
+1572 30   19:               SEQUENCE {
+1574 02    2:                 INTEGER 210
+1578 17   13:                 UTCTime '990822070000Z'
+            :                 }
+1593 30   19:               SEQUENCE {
+1595 02    2:                 INTEGER 212
+1599 17   13:                 UTCTime '990824070000Z'
+            :                 }
+            :               }
+            :             }
+1614 30    9:           SEQUENCE {
+1616 06    7:             OBJECT IDENTIFIER
+            :               dsaWithSha1 (1 2 840 10040 4 3)
+            :               (ANSI X9.57 algorithm)
+            :             }
+1625 03   47:           BIT STRING 0 unused bits, encapsulates {
+1628 30   44:               SEQUENCE {
+1630 02   20:                 INTEGER
+            :                   7E 65 52 76 33 FE 34 73 17 D1 F7 96
+            :                   F9 A0 D4 D8 6D 5C 7D 3D
+1652 02   20:                 INTEGER
+            :                   02 7A 5B B7 D5 5B 18 C1 CF 87 EF 7E
+            :                   DA 24 F3 2A 83 9C 35 A1
+            :                 }
+            :               }
+            :           }
+            :         }
+1674 31    0:       SET {}
+            :       }
+
+
+
+Hoffman, Ed.                 Informational                    [Page 108]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+            :     }
+            :   }
+
+5.  Enveloped-data
+
+5.1.  Basic Encrypted Content, TripleDES and RSA
+
+   An EnvelopedData from Alice to Bob of ExContent using TripleDES for
+   encrypting and RSA for key management.  Does not have an
+   OriginatorInfo.
+
+      0 30  286: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER
+               :     envelopedData (1 2 840 113549 1 7 3)
+               :     (PKCS #7)
+     15 A0  271:   [0] {
+     19 30  267:     SEQUENCE {
+     23 02    1:       INTEGER 0
+     26 31  192:       SET {
+     29 30  189:         SEQUENCE {
+     32 02    1:           INTEGER 0
+     35 30   38:           SEQUENCE {
+     37 30   18:             SEQUENCE {
+     39 31   16:               SET {
+     41 30   14:                 SEQUENCE {
+     43 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+     48 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+     57 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               CD 5D 71 D0
+               :             }
+     75 30   13:           SEQUENCE {
+     77 06    9:             OBJECT IDENTIFIER
+               :               rsaEncryption (1 2 840 113549 1 1 1)
+               :               (PKCS #1)
+     88 05    0:             NULL
+               :             }
+     90 04  128:           OCTET STRING
+               :             0B 71 0D E6 71 88 88 98 B6 96 C1 8F
+               :             70 FD A2 27 DE DA E1 EF 24 6C A4 33
+               :             DF AC E0 E9 9D A2 D3 2C 7A CD 80 B8
+               :             99 9E E6 5F B1 41 B3 72 16 83 E7 FA
+               :             2A 00 8B C7 73 35 78 26 D6 C7 CF 8C
+
+
+
+Hoffman, Ed.                 Informational                    [Page 109]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :             0C 56 DB A5 76 9D 08 38 0E F3 F9 D4
+               :             91 43 58 78 DC 49 B6 EC EE 6C 68 33
+               :             A3 21 1D F0 28 78 1F F7 5D F6 07 73
+               :             4D DF AD 69 31 20 4B 48 A9 75 22 6E
+               :             36 79 15 63 8F CC EB 9D A3 28 A1 D1
+               :             2C 57 F4 DA 1A 2C 75 1F
+               :           }
+               :         }
+    221 30   67:       SEQUENCE {
+    223 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+    234 30   20:         SEQUENCE {
+    236 06    8:           OBJECT IDENTIFIER
+               :             des-EDE3-CBC (1 2 840 113549 3 7)
+               :             (RSADSI encryptionAlgorithm
+               :                 (1 2 840 113549 3))
+    246 04    8:           OCTET STRING
+               :             2D 68 C5 E9 47 06 51 35
+               :           }
+    256 80   32:         [0]
+               :           0E C8 92 7F C6 7D 3F 8D CB AD 8E 0E
+               :           C5 49 3A EB 47 2E D6 55 DE 09 21 4E
+               :           48 EA 4E 27 B1 6E 57 25
+               :         }
+               :       }
+               :     }
+               :   }
+
+5.2.  Basic Encrypted Content, RC2/128 and RSA
+
+   Same as 5.1, except using RC2/128 for encryption and RSA for key
+   management.  An EnvelopedData from Alice to Bob of ExContent using
+   RC2/40 for encrypting and RSA for key management.  Does not have an
+   OriginatorInfo or any attributes.
+
+      0 30  291: SEQUENCE {
+      4 06    9:   OBJECT IDENTIFIER
+               :     envelopedData (1 2 840 113549 1 7 3)
+               :     (PKCS #7)
+     15 A0  276:   [0] {
+     19 30  272:     SEQUENCE {
+     23 02    1:       INTEGER 0
+     26 31  192:       SET {
+     29 30  189:         SEQUENCE {
+     32 02    1:           INTEGER 0
+     35 30   38:           SEQUENCE {
+     37 30   18:             SEQUENCE {
+     39 31   16:               SET {
+
+
+
+Hoffman, Ed.                 Informational                    [Page 110]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+     41 30   14:                 SEQUENCE {
+     43 06    3:                   OBJECT IDENTIFIER
+               :                     commonName (2 5 4 3)
+               :                     (X.520 id-at (2 5 4))
+     48 13    7:                   PrintableString 'CarlRSA'
+               :                   }
+               :                 }
+               :               }
+     57 02   16:             INTEGER
+               :               46 34 6B C7 80 00 56 BC 11 D3 6E 2E
+               :               CD 5D 71 D0
+               :             }
+     75 30   13:           SEQUENCE {
+     77 06    9:             OBJECT IDENTIFIER
+               :               rsaEncryption (1 2 840 113549 1 1 1)
+               :               (PKCS #1)
+     88 05    0:             NULL
+               :             }
+     90 04  128:           OCTET STRING
+               :             85 42 BE E3 0B 2E E5 0F 09 AA 24 CA
+               :             DE DA C1 D3 09 B8 27 2B 25 CB D5 71
+               :             FB C9 9C DB F0 B2 6E A0 8A 5F 1C 9D
+               :             4A ED 98 9D 15 39 26 01 1A 2E 6B F0
+               :             44 39 89 37 3C 6F C7 4A 61 0B 0B 27
+               :             77 AA F9 D4 97 A4 D2 21 3F C2 3F 20
+               :             D4 DC 10 E9 D6 3F 00 DB 9C 82 47 D6
+               :             7E 96 FF 12 6E 87 84 A0 BA ED 81 0F
+               :             56 6D A6 1D EB AB C3 B7 A1 B9 F8 5F
+               :             8B CC 1B 4A E5 14 36 06 61 D0 C7 64
+               :             5F 69 67 91 A9 50 EE D8
+               :           }
+               :         }
+    221 30   72:       SEQUENCE {
+    223 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+    234 30   25:         SEQUENCE {
+    236 06    8:           OBJECT IDENTIFIER rc2CBC (1 2 840 113549 3 2)
+               :             (RSADSI encryptionAlgorithm
+               :                 (1 2 840 113549 3))
+    246 30   13:           SEQUENCE {
+    248 02    1:             INTEGER 58
+    251 04    8:             OCTET STRING
+               :               E8 70 81 E2 EF C5 15 57
+               :             }
+               :           }
+    261 80   32:         [0]
+               :           06 53 0A 7B 8D 5C 16 0D CC D5 76 D6
+               :           8B 59 D6 45 8C 1A 1A 0C E6 1E F3 DE
+
+
+
+Hoffman, Ed.                 Informational                    [Page 111]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+               :           43 56 00 9B 40 8C 38 5D
+               :         }
+               :       }
+               :     }
+               :   }
+
+5.3.  S/MIME application/pkcs7-mime Encrypted Message
+
+   A full S/MIME message, including MIME, that includes the body part
+   from 5.1.
+
+MIME-Version: 1.0
+Message-Id: <00103112005203.00349@amyemily.ig.com>
+Date: Tue, 31 Oct 2000 12:00:52 -0600 (Central Standard Time)
+From: User1
+To: User2
+Subject: Example 5.3
+Content-Type: application/pkcs7-mime;
+        name=smime.p7m;
+        smime-type=enveloped-data
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename=smime.p7m
+
+MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYDVQQDEwdDYXJ
+sUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUABIGAC3EN5nGIiJi2lsGPcP
+2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FBs3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadC
+DgO8/nUkUNYeNxJtuzubGgzoyEd8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHR
+LFf02hosdR8wQwYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43
+LrY4OxUk660cu1lXeCSFOSOpOJ7FuVyU=
+
+6.  Digested-data
+
+   A DigestedData from Alice to Bob of ExContent using SHA-1.
+
+      0 30   94: SEQUENCE {
+      2 06    9:   OBJECT IDENTIFIER digestedData (1 2 840 113549 1 7 5)
+               :     (PKCS #7)
+     13 A0   81:   [0] {
+     15 30   79:     SEQUENCE {
+     17 02    1:       INTEGER 0
+     20 30    7:       SEQUENCE {
+     22 06    5:         OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
+               :           (OIW)
+               :         }
+     29 30   43:       SEQUENCE {
+     31 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     42 A0   30:         [0] {
+
+
+
+Hoffman, Ed.                 Informational                    [Page 112]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+     44 04   28:           OCTET STRING 'This is some sample content.'
+               :           }
+               :         }
+     74 04   20:       OCTET STRING
+               :         40 6A EC 08 52 79 BA 6E 16 02 2D 9E
+               :         06 29 C0 22 96 87 DD 48
+               :       }
+               :     }
+               :   }
+
+7.  Encrypted-data
+
+7.1.  Simple EncryptedData
+
+   An EncryptedData from Alice to Bob of ExContent with no attributes.
+
+      0 30   87: SEQUENCE {
+      2 06    9:   OBJECT IDENTIFIER
+               :     encryptedData (1 2 840 113549 1 7 6)
+               :     (PKCS #7)
+     13 A0   74:   [0] {
+     15 30   72:     SEQUENCE {
+     17 02    1:       INTEGER 0
+     20 30   67:       SEQUENCE {
+     22 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     33 30   20:         SEQUENCE {
+     35 06    8:           OBJECT IDENTIFIER
+               :             des-EDE3-CBC (1 2 840 113549 3 7)
+               :             (RSADSI encryptionAlgorithm
+               :                 (1 2 840 113549 3))
+     45 04    8:           OCTET STRING
+               :             B3 6B 6B FB 62 31 08 4E
+               :           }
+     55 80   32:         [0]
+               :           FA FC ED DB 3F 18 17 1D 38 89 11 EA
+               :           34 D6 20 DB F4 C3 D9 58 15 EF 93 3B
+               :           9A F5 D7 04 F6 B5 70 E2
+               :         }
+               :       }
+               :     }
+               :   }
+
+   The TripleDES key is:
+
+       73 7c 79 1f 25 ea d0 e0 46 29 25 43 52 f7 dc 62
+       91 e5 cb 26 91 7a da 32
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 113]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+7.2.  EncryptedData with Unprotected Attributes
+
+   An EncryptedData from Alice to Bob of ExContent with unprotected
+   attributes.
+
+      0 30  149: SEQUENCE {
+      3 06    9:   OBJECT IDENTIFIER
+               :     encryptedData (1 2 840 113549 1 7 6)
+               :     (PKCS #7)
+     14 A0  135:   [0] {
+     17 30  132:     SEQUENCE {
+     20 02    1:       INTEGER 2
+     23 30   67:       SEQUENCE {
+     25 06    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
+               :           (PKCS #7)
+     36 30   20:         SEQUENCE {
+     38 06    8:           OBJECT IDENTIFIER
+               :             des-EDE3-CBC (1 2 840 113549 3 7)
+               :             (RSADSI encryptionAlgorithm
+               :                 (1 2 840 113549 3))
+     48 04    8:           OCTET STRING
+               :             07 27 20 85 90 9E B0 7E
+               :           }
+     58 80   32:         [0]
+               :           D2 20 8F 67 48 8A CB 41 E4 22 68 5D
+               :           BE 77 05 52 26 ED E3 01 BD 00 91 58
+               :           A7 35 6E BC 4B A2 07 33
+               :         }
+     92 A1   58:       [1] {
+     94 30   56:         SEQUENCE {
+     96 06    3:           OBJECT IDENTIFIER '1 2 5555'
+    101 31   49:           SET {
+    103 04   47:             OCTET STRING
+               :               'This is a test General ASN Attribut'
+               :               'e, number 1.'
+               :             }
+               :           }
+               :         }
+               :       }
+               :     }
+               :   }
+
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 114]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+8.  Security Considerations
+
+   Because this document shows examples of S/MIME and CMS messages, this
+   document also inherits all of the security considerations from
+   [SMIME-MSG] and [CMS].
+
+   The Perl script in Appendix A writes to the user's local hard drive.
+   A malicious attacker could modify the Perl script in this document.
+   Be sure to read the Perl code carefully before executing it.
+
+9.  References
+
+9.1.  Normative References
+
+   [CMS]       Housley, R., "Cryptographic Message Syntax (CMS)", RFC
+               3852, July 2004.
+
+   [PKIX]      Housley, R., Polk, W., Ford, W., and D. Solo, "Internet
+               X.509 Public Key Infrastructure Certificate and
+               Certificate Revocation List (CRL) Profile", RFC 3280,
+               April 2002.
+
+   [SMIME-MSG] Ramsdell, B., "Secure/Multipurpose Internet Mail
+               Extensions (S/MIME) Version 3.1 Message Specification",
+               RFC 3851, July 2004.
+
+9.2.  Informative References
+
+   [DVCS]      Adams, C., Sylvester, P., Zolotarev, M., and R.
+               Zuccherato, "Internet X.509 Public Key Infrastructure
+               Data Validation and Certification Server Protocols", RFC
+               3029, February 2001.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 115]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+A.  Binaries of the Examples
+
+   This section contains the binaries of the examples shown in the rest
+   of the document.  The binaries are stored in a modified Base64
+   format.  There is a Perl program that, when run over the contents of
+   this document, will extract the following binaries and write them out
+   to disk.  The program requires Perl.
+
+A.1.  How the Binaries and Extractor Works
+
+   The program in the next section looks for lines that begin with a '|'
+   character (or some whitespace followed by a '|'), ignoring all other
+   lines.  If the line begins with '|', the second character tells what
+   kind of line it is:
+
+      A line that begins with |* is a comment
+      A line that begins with |> gives the name of a new file to start
+      A line that begins with |< tells to end the file (and checks the
+            file name for sanity)
+      A line that begins with |anythingelse is a Base64 line
+
+   The program writes out a series of files, so you should run this in
+   an empty directory.  The program will overwrite files (if it can),
+   but won't delete other files already in the directory.
+
+   Run this program with this document as the standard input, such as:
+
+      ./extractsample.pl <draft-ietf-smime-examples
+
+   If you want to extract without the program, copy all the lines
+   between the "|>" and "|<" markers, remove any page breaks, and remove
+   the "|" in the first column of each line.  The result is a valid
+   Base64 blob that can be processed by any Base64 decoder.
+
+A.2.  Example Extraction Program
+
+#!/usr/bin/perl
+
+# CMS Samples extraction program. v 1.1
+
+# Get all the input as an array of lines
+@AllIn = (); while (<STDIN>) { push(@AllIn, $_) }
+
+$Base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr' .
+    'stuvwxyz0123456789+/=';
+$LineCount = 0; $CurrFile = '';
+
+foreach $Line (@AllIn) {
+
+
+
+Hoffman, Ed.                 Informational                    [Page 116]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+    $LineCount++;  # Keep the line counter for error messages
+    $Line =~ s/^\s*//;  # Get rid of leading whitespace
+    chomp($Line);  # Get rid of CR or CRLF at the end of the line
+    if(substr($Line, 0, 1) ne '|') { next }  # Not a special line
+    elsif(substr($Line, 1, 1) eq '*') { next }  # It is a comment
+    elsif(substr($Line, 1, 1) eq '>')
+      { &StartNewFile(substr($Line, 2)) }  # Start a new file
+    elsif(substr($Line, 1, 1) eq '<')
+      { &EndCurrFile(substr($Line, 2)) }  # End the current file
+    else { &DoBase64(substr($Line, 1)) }  # It is a line of Base64
+}
+
+sub StartNewFile {
+    $TheNewFile = shift(@_);
+    if($CurrFile ne '') { die "Was about to start a new file at " .
+      "line $LineCount, but the old file, $CurrFile, was open\n" }
+    open(OUT, ">$TheNewFile") or
+      die "Could not open $TheNewFile for writing: $!\n";
+    binmode(OUT);  # This is needed for Windows, is a noop on Unix
+    $CurrFile = $TheNewFile;
+    $LeftOver = 0;  # Amount left from previous Base64 character
+    $NextPos = 0;  # Bit position to start the next Base64 character
+                   #     (bits are numbered 01234567)
+    $OutString = '';  # Holds the text going out to the file
+}
+
+sub EndCurrFile {
+    $FileToEnd = shift(@_);
+    if($CurrFile ne $FileToEnd) { die "Was about to close " .
+      "$FileToEnd at line $LineCount, but that name didn't match " .
+      "the name of the currently open file, $CurrFile\n" }
+    print OUT $OutString;
+    close(OUT);
+    $CurrFile = '';
+}
+
+sub DoBase64 {
+    $TheIn = shift(@_);
+    if($CurrFile eq '') { die "Got some Base64 at line $LineCount, " .
+      "but appear to not be writing to any particular file.\n" }
+    @Chars = split(//, $TheIn);  # Make an array of the characters
+    foreach $ThisChar (@Chars) {
+    # $ThisVal is the position in the string and the Base64 value
+      $ThisVal = index($Base64Chars, $ThisChar);
+      if($ThisVal == -1) { die "At line $LineCount, found the " .
+          "character $ThisChar, which is not a Base64 character\n" }
+      if($ThisVal == 64) { last }  # It is a "=", so we're done
+      if ($NextPos == 0 ) {
+
+
+
+Hoffman, Ed.                 Informational                    [Page 117]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+          # Don't output anything, just fill the left of $LeftOver
+          $LeftOver = $ThisVal * 4;
+          $NextPos = 6;
+      } elsif ($NextPos == 2) {
+        # Add $ThisVal to $LeftOver, output, and reset
+          $OutString .= chr($LeftOver + $ThisVal);
+          $LeftOver = 0;
+          $NextPos = 0;
+      } elsif ($NextPos == 4) {
+          # Add upper 4 bits of $ThisVal to $LeftOver and output
+          $Upper4 = ($ThisVal & 60);
+          $OutString .= chr($LeftOver + ($Upper4/4));
+          $LeftOver = (($ThisVal - $Upper4) * 64);
+          $NextPos = 2;
+      } elsif ($NextPos == 6) {
+          # Add upper 2 bits of $ThisVal to $LeftOver and output
+          $Upper2 = ($ThisVal & 48);
+          $OutString .= chr($LeftOver + ($Upper2/16));
+          $LeftOver = (($ThisVal - $Upper2) * 16);
+          $NextPos = 4;
+      } else { die "\$NextPos has an illegal value: $NextPos." }
+    }
+}
+
+B.  Examples in Order of Appearance
+
+From Section 2.1
+
+***ExContent.bin***
+
+|* Section 2.1
+|>ExContent.bin
+|VGhpcyBpcyBzb21lIHNhbXBsZSBjb250ZW50Lg==
+|<ExContent.bin
+
+From Section 2.2
+
+***AlicePrivDSSSign.pri***
+
+|* Example AlicePrivDSSSign.pri
+|>AlicePrivDSSSign.pri
+|MIIBSwIBADCCASsGByqGSM44BAEwggEeAoGBAIGNze2D6gqeOT7CSCij5EeT3Q7XqA7sU8
+|WrhAhP/5Thc0h+DNbzREjR/p+vpKGJL+HZMMg23j+bv7dM3F9piuR10DcMkQiVm96nXvn8
+|9J8v3UOoi1TxP7AHCEdNXYjDw7Wz41UIddU5dhDEeL3/nbCElzfy5FEbteQJllzzflvbAh
+|UA4kemGkVmuBPG2o+4NyErYov3k80CgYAmONAUiTKqOfs+bdlLWWpMdiM5BAI1XPLLGjDD
+|HlBd3ZtZ4s2qBT1YwHuiNrhuB699ikIlp/R1z0oIXks+kPht6pzJIYo7dhTpzi5dowfNI4
+|W4LzABfG1JiRGJNkS9+MiVSlNWteL5c+waYTYfEX/Cve3RUP+YdMLRgUpgObo2OQQXAhUA
+|u0RG0aXJRgcu0P561pIH8JqFiT8=
+
+
+
+Hoffman, Ed.                 Informational                    [Page 118]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|<AlicePrivDSSSign.pri
+
+***AlicePrivRSASign.pri***
+
+|* Example AlicePrivRSASign.pri
+|>AlicePrivRSASign.pri
+|MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOCJczmN2PX16Id2OX9OsA
+|W7U4PeD7er3H3HdSkNBS5tEt+mhibU0m+qWCn8l+z6glEPMIC+sVCeRkTxLLvYMs/GaG8H
+|2bBgrL7uNAlqE/X3BQWT3166NVbZYf8Zf8mB5vhs6odAcO+sbSx0ny36VTq5mXcCpkhSjE
+|7zVzhXdFdfAgMBAAECgYAApAPDJ0d2NDRspoa1eUkBSy6K0shissfXSAlqi5H3NvJ11ujN
+|FZBgJzFHNWRNlc1nY860n1asLzduHO4Ovygt9DmQbzTYbghb1WVq2EHzE9ctOV7+M8v/Ke
+|QDCz0Foo+38Y6idjeweVfTLyvehwYifQRmXskbr4saw+yRRKt/IQJBAPbW4CIhTF8KcP8n
+|/OWzUGqd5Q+1hZbGQPqoCrSbmwxVwgEd+TeCihTI8pMOks2lZiG5PNIGv7RVMcncrcqYLd
+|ECQQDo3rARJQnSAlEB3oromFD1d3dhpEWTawhVlnNd9MhbEpMic4t/03B/9aSqu3T9PCJq
+|2jiRKoZbbBTorkye+o4vAkEAl0zwh5sXf+4bgxsUtgtqkF+GJ1Hht6B/9eSI41m5+R6b0y
+|l3OCJI1yKxJZi6PVlTt/oeILLIURYjdZNR56vN8QJALPAkW/qgzYUi6tBuT/pszSHTyOTx
+|hERIZHPXKY9+RozsFd7kUbOU5yyZLVVleyTqo2IfPmxNZ0ERO+G+6YMCgwJAWIjZoVA4hG
+|qrA7y730v0nG+4tCol+/bkBS9u4oiJIW9LJZ7Qq1CTyr9AcewhJcV/+wLpIZa4M83ixpXu
+|b41fKA==
+|<AlicePrivRSASign.pri
+
+***BobPrivRSAEncrypt.pri***
+
+|* Example BobPrivRSAEncrypt.pri
+|>BobPrivRSAEncrypt.pri
+|MIIChQIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnhZ5g/OdVf8qCTQV6meY
+|mFyDVdmpFb+x0B2hlwJhcPvaUi0DWFbXqYZhRBXM+3twg7CcmRuBlpN235ZR572akzJKN/
+|O7uvRgGGNjQyywcDWVL8hYsxBLjMGAgUSOZPHPtdYMTgXB9T039T2GkB8QX4enDRvoPGXz
+|jPHCyqaqfrAgMBAAECgYBnzUhMmg2PmMIbZf8ig5xt8KYGHbztpwOIlPIcaw+LNd4Ogngw
+|y+e6alatd8brUXlweQqg9P5F4Kmy9Bnah5jWMIR05PxZbMHGd9ypkdB8MKCixQheIXFD/A
+|0HPfD6bRSeTmPwF1h5HEuYHD09sBvf+iU7o8AsmAX2EAnYh9sDGQJBANDDIsbeopkYdo+N
+|vKZ11mY/1I1FUox29XLE6/BGmvE+XKpVC5va3Wtt+Pw7PAhDk7Vb/s7q/WiEI2Kv8zHCue
+|UCQQDQUfweIrdb7bWOAcjXq/JY1PeClPNTqBlFy2bKKBlf4hAr84/sajB0+E0R9KfEILVH
+|IdxJAfkKICnwJAiEYH2PAkA0umTJSChXdNdVUN5qSO8bKlocSHseIVnDYDubl6nA7xhmqU
+|5iUjiEzuUJiEiUacUgFJlaV/4jbOSnI3vQgLeFAkEAni+zN5r7CwZdV+EJBqRd2ZCWBgVf
+|JAZAcpw6iIWchw+dYhKIFmioNRobQ+g4wJhprwMKSDIETukPj3d9NDAlBwJAVxhn1grSta
+|vCunrnVNqcBU+B1O8BiR4yPWnLMcRSyFRVJQA7HCp8JlDV6abXd8vPFfXuC9WN7rOvTKF8
+|Y0ZB9qANMAsGA1UdDzEEAwIAEA==
+|<BobPrivRSAEncrypt.pri
+
+***CarlPrivDSSSign.pri***
+
+|* Example CarlPrivDSSSign.pri
+|>CarlPrivDSSSign.pri
+|MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBALZJGD6KRMEpcZRMAcQSwXp5y1RNqx6B+8
+|ZMsw6UCQbrAdSxyHFLx0XAUCVdnPza5G3T4oZIhIJ9uhWVShb2Ru3d9pjSu36KCoq6Fnu5
+|UAFIk4vrJRVRl1Xcj1MOEKlQ/HC3zTBU/dreqKoitaGvi8wCiOeLcF+5reEI1G0pLdbpAh
+|UA3cEv31POCzRgdz4CpL+KXZi5ENUCgYAM7lebS73atgdqdDdPVX+d7bxhDetGWTxWCytb
+
+
+
+Hoffman, Ed.                 Informational                    [Page 119]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|DJHOpWJSacrhbT69v/7ht7krYTyty65F4wasjCKdnESHC8fN8BzZtU5dc96vDskdWlH1T0
+|R5NVpzqn9GUR+pQhacSOuKeWG01S9TIkRjH4a4o1gGJfgpwO+64HXwQsRjZVKbCgQWAhQZ
+|szilIWIxUOV/uT4IRnjRPrXlcg==
+|<CarlPrivDSSSign.pri
+
+***CarlPrivRSASign.pri***
+
+|* Example CarlPrivRSASign.pri
+|>CarlPrivRSASign.pri
+|MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAORL/xi4JFf0d/9uc3uTcV
+|y8MxqSknIj2EFG0M0ROgSzjq+Cnb1RHhd68nYsK4Y5p73XjRpT7OQA1ejsojax7eJQ4jIJ
+|ij+fmSWPuE6ruX3VlmXaFqDFvg6uRFvvXvSnKcuC3axE6aqTlCkO+BjWyFde8nbE8hFgOL
+|kbPB2XyWrxAgMBAAECgYEArnPkW19bZlrJ18bvOF9TISovYv7eKZp6hmc2531ieHU9c6C8
+|KQ7zj73Dycm2+LrWE5vDl3rKavC4hWVOD72nqPdUBkG969wgd5DfYZuab3Te6jvUnIdg7X
+|aE8WowN9XgkBb4gEfDGWvtdXe6Su05tl0CRztfG8gcq8vo9SY/pIECQQD/3wmgVgtCUp7E
+|TZOzsEm73ueBfSiZ0LFIugs54Rx7IhgztkD2v9yuHdChrQRxWmEKbjvOMNo2n2UlKbunDn
+|8LAkEA5GloGF/5V9B8ZokPumMdcssgpIF2ZInNfdHCJ6kurHpWmoUH2TADowOrf4iSUCQB
+|qhsHHyBMt8l7Vve2wn6rcwJAVzZsj4wEdmy21O4kRAD4gOKvQgGpDxSE+OcA4I+MJ6QtX6
+|LlbbVjwK1E6XaRpxlJLkb4d4VLO4cE8K/S2FQmlQJAZKEPrFV0G70NYXsXA82w5qcZHYCv
+|8UFI2Bq2iBSgLHrFdtQPDh96KrJuNwSrOUVzukaoD42CXyIUBc+io/N8gwJAJh4dHKGYK+
+|TbOOhXbmtzGYhhOvp0SjaLR2hdUOsm4+p9m05lqa97q0sudlE9qNARq6PWqMAnNh1UC6qn
+|0W2N+g==
+|<CarlPrivRSASign.pri
+
+***DianePrivDSSSign.pri***
+
+|* Example DianePrivDSSSign.pri
+|>DianePrivDSSSign.pri
+|MIIBSwIBADCCASsGByqGSM44BAEwggEeAoGBALZJGD6KRMEpcZRMAcQSwXp5y1RNqx6B+8
+|ZMsw6UCQbrAdSxyHFLx0XAUCVdnPza5G3T4oZIhIJ9uhWVShb2Ru3d9pjSu36KCoq6Fnu5
+|UAFIk4vrJRVRl1Xcj1MOEKlQ/HC3zTBU/dreqKoitaGvi8wCiOeLcF+5reEI1G0pLdbpAh
+|UA3cEv31POCzRgdz4CpL+KXZi5ENUCgYAM7lebS73atgdqdDdPVX+d7bxhDetGWTxWCytb
+|DJHOpWJSacrhbT69v/7ht7krYTyty65F4wasjCKdnESHC8fN8BzZtU5dc96vDskdWlH1T0
+|R5NVpzqn9GUR+pQhacSOuKeWG01S9TIkRjH4a4o1gGJfgpwO+64HXwQsRjZVKbCgQXAhUA
+|lpX54MHgQS0yD4tCUpMq5h4OISk=
+|<DianePrivDSSSign.pri
+
+***DianePrivRSASignEncrypt.pri***
+
+|* Example DianePrivRSASignEncrypt.pri
+|>DianePrivRSASignEncrypt.pri
+|MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANb9uMBwxkwl7OrP6ny7om
+|L68OYyOlP/sZJaF/Qg4ZkkggrQ9nz7RMqLJwbxfiYDqXadz+ygLHCW8oNC9tS3KAq7+L9K
+|TBk/B9ugwWAet35n996xw2BJrEXX+MbvCDchk0fu8HM1crACxPMRw15H5Qq3g/HbdGlki0
+|QdlV3NKMCFAgMBAAECgYA9vc3CDmEUW0vnv2AjBCvFazWllkUj/Gl9kzwP0yWWumJSQuKW
+|z/5YgI/rsYy91A1l0Dp3RSSeDOuGgMOsIRFxROOyqKkurBfSo4QlY7W8Lx7d9iH/FSAkW/
+|GAL9VBDjIk99RKMp65SdgZjj85jWK9gPwMJJKT5MPXBZFTu5a2QQJBAPO4P0rRlLCRYBNB
+|kg2NRD93Hf+WI0QI1AtwyRqv6ZCU8rDVX08ZhVChkJGuvQV2UrMi2Kh8jlR/AHJPNnVoc7
+
+
+
+Hoffman, Ed.                 Informational                    [Page 120]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|UCQQDh0ucRVwaucpUiFqoCtFrtTp2CEU+WPIbJEI1WezF1eWnndWg4AEsu0iYy3bHi4CxU
+|gAp1utFmlhuwDqB+0ruRAkEAr7a82yJzQ0HstLVnqaGZ/O/Sjv0d++Upi/4K39TIXlclCl
+|0r1AmgVlvFsWL8IL4ILeMHtaHns//EwKVfrBJcqQJBALmYQfwIUB9zYIoBonxSiiBa6iyJ
+|2aUZ3ZTGG8MlwIJR5O4rmhncc+3pHSfU+GwD3asdCHu1rH/pgpvxiYpx22ECQAEHIZdfem
+|Co/VpcB9+o3vfisTR9/OuRvbBzdMjEvj9YRTAGkLOsacyz9z98rMe4G2WhFjk5sON0fc/N
+|xaxsv+U=
+|<DianePrivRSASignEncrypt.pri
+
+From Section 2.3
+
+***AliceDSSSignByCarlNoInherit.cer***
+
+|* Example AliceDSSSignByCarlNoInherit.cer
+|>AliceDSSSignByCarlNoInherit.cer
+|MIIC3DCCApugAwIBAgICAMgwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTMB4XDT
+|k5MDgxNzAxMTA0OVoXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIQWxpY2VEU1MwggG2
+|MIIBKwYHKoZIzjgEATCCAR4CgYEAgY3N7YPqCp45PsJIKKPkR5PdDteoDuxTxauECE//lO
+|FzSH4M1vNESNH+n6+koYkv4dkwyDbeP5u/t0zcX2mK5HXQNwyRCJWb3qde+fz0ny/dQ6iL
+|VPE/sAcIR01diMPDtbPjVQh11Tl2EMR4vf+dsISXN/LkURu15AmWXPN+W9sCFQDiR6YaRW
+|a4E8baj7g3IStii/eTzQKBgCY40BSJMqo5+z5t2UtZakx2IzkEAjVc8ssaMMMeUF3dm1ni
+|zaoFPVjAe6I2uG4Hr32KQiWn9HXPSgheSz6Q+G3qnMkhijt2FOnOLl2jB80jhbgvMAF8bU
+|mJEYk2RL34yJVKU1a14vlz7BphNh8Rf8K97dFQ/5h0wtGBSmA5ujY5A4GEAAKBgFzjuVp1
+|FJYLqXrd4z+p7Kxe3L23ExE0phaJKBEj2TSGZ3V1ExI9Q1tv5VG/+onyohs+JH09B41bY8
+|i7RaWgSuOF1s4GgD/oI34a8iSrUxq4Jw0e7wi/ZhSAXGKsZfoVi/G7NNTSljf2YUeyxDKE
+|8H5BQP1Gp2NOM/Kl4vTyg+W4o4GBMH8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBs
+|AwHwYDVR0jBBgwFoAUcEQ+gi5vh95K03XjPSC8QyuT8R8wHQYDVR0OBBYEFL5sobPjwfft
+|Q3CkzhMB4v3jl/7NMB8GA1UdEQQYMBaBFEFsaWNlRFNTQGV4YW1wbGUuY29tMAkGByqGSM
+|44BAMDMAAwLQIUVQykGR9CK4lxIjONg2q1PWdrv0UCFQCfYVNSVAtcst3a53Yd4hBSW0Ne
+|vQ==
+|<AliceDSSSignByCarlNoInherit.cer
+
+***AliceRSASignByCarl.cer***
+
+|* Example AliceRSASignByCarl.cer
+|>AliceRSASignByCarl.cer
+|MIICLDCCAZWgAwIBAgIQRjRrx4AAVrwR024uxBCzsDANBgkqhkiG9w0BAQUFADASMRAwDg
+|YDVQQDEwdDYXJsUlNBMB4XDTk5MDkxOTAxMDg0N1oXDTM5MTIzMTIzNTk1OVowEzERMA8G
+|A1UEAxMIQWxpY2VSU0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOCJczmN2PX16I
+|d2OX9OsAW7U4PeD7er3H3HdSkNBS5tEt+mhibU0m+qWCn8l+z6glEPMIC+sVCeRkTxLLvY
+|Ms/GaG8H2bBgrL7uNAlqE/X3BQWT3166NVbZYf8Zf8mB5vhs6odAcO+sbSx0ny36VTq5mX
+|cCpkhSjE7zVzhXdFdfAgMBAAGjgYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIG
+|wDAfBgNVHSMEGDAWgBTp4JAnrHggeprTTPJCN04irp44uzAdBgNVHQ4EFgQUd9K00bdMio
+|qjzkWdzuw8oDrj/1AwHwYDVR0RBBgwFoEUQWxpY2VSU0FAZXhhbXBsZS5jb20wDQYJKoZI
+|hvcNAQEFBQADgYEAPnBHqEjME1iPylFxa042GF0EfoCxjU3MyqOPzH1WyLzPbrMcWakgqg
+|WBqE4lradwFHUv9ceb0Q7pY9Jkt8ZmbnMhVN/0uiVdfUnTlGsiNnRzuErsL2Tt0z3Sp0LF
+|6DeKtNufZ+S9n/n+dO/q+e5jatg/SyUJtdgadq7rm9tJsCI=
+|<AliceRSASignByCarl.cer
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 121]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+***BobRSASignByCarl.cer***
+
+|* Example BobRSASignByCarl.cer
+|>BobRSASignByCarl.cer
+|MIICJzCCAZCgAwIBAgIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQUFADASMRAwDg
+|YDVQQDEwdDYXJsUlNBMB4XDTk5MDkxOTAxMDkwMloXDTM5MTIzMTIzNTk1OVowETEPMA0G
+|A1UEAxMGQm9iUlNBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp4WeYPznVX/Kgk0
+|FepnmJhcg1XZqRW/sdAdoZcCYXD72lItA1hW16mGYUQVzPt7cIOwnJkbgZaTdt+WUee9mp
+|MySjfzu7r0YBhjY0MssHA1lS/IWLMQS4zBgIFEjmTxz7XWDE4FwfU9N/U9hpAfEF+Hpw0b
+|6Dxl84zxwsqmqn6wIDAQABo38wfTAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFIDAf
+|BgNVHSMEGDAWgBTp4JAnrHggeprTTPJCN04irp44uzAdBgNVHQ4EFgQU6PS4Z9izlqQq8x
+|GqKdOVWoYWtCQwHQYDVR0RBBYwFIESQm9iUlNBQGV4YW1wbGUuY29tMA0GCSqGSIb3DQEB
+|BQUAA4GBAHuOZsXxED8QIEyIcat7QGshM/pKld6dDltrlCEFwPLhfirNnJOIh/uLt359QW
+|Hh5NZt+eIEVWFFvGQnRMChvVl52R1kPCHWRbBdaDOS6qzxV+WBfZjmNZGjOd539OgcOync
+|f1EHl/M28FAK3Zvetl44ESv7V+qJba3JiNiPzyvT
+|<BobRSASignByCarl.cer
+
+***CarlDSSSelf.cer***
+
+|* Example CarlDSSSelf.cer
+|>CarlDSSSelf.cer
+|MIICmzCCAlqgAwIBAgIBATAJBgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MwHhcNOT
+|kwODE2MjI1MDUwWhcNMzkxMjMxMjM1OTU5WjASMRAwDgYDVQQDEwdDYXJsRFNTMIIBtzCC
+|ASsGByqGSM44BAEwggEeAoGBALZJGD6KRMEpcZRMAcQSwXp5y1RNqx6B+8ZMsw6UCQbrAd
+|SxyHFLx0XAUCVdnPza5G3T4oZIhIJ9uhWVShb2Ru3d9pjSu36KCoq6Fnu5UAFIk4vrJRVR
+|l1Xcj1MOEKlQ/HC3zTBU/dreqKoitaGvi8wCiOeLcF+5reEI1G0pLdbpAhUA3cEv31POCz
+|Rgdz4CpL+KXZi5ENUCgYAM7lebS73atgdqdDdPVX+d7bxhDetGWTxWCytbDJHOpWJSacrh
+|bT69v/7ht7krYTyty65F4wasjCKdnESHC8fN8BzZtU5dc96vDskdWlH1T0R5NVpzqn9GUR
+|+pQhacSOuKeWG01S9TIkRjH4a4o1gGJfgpwO+64HXwQsRjZVKbCgOBhQACgYEAmYd0JwNm
+|oLHArdwsdbvhbESc2iFtTUdtsWIJ6diuHvI6tJSxo456m3FOAJTJtCVOuWCWGSQB82IM/n
+|XA+87YaADj/dVwT98jlhkGlPSxYY86V7EIEaQLJiXwUnaB6gtiDZUq5oa6crKnUIMLqifN
+|G6lNiZrXjRg5hD+LxVZNgHqjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAg
+|GGMB0GA1UdDgQWBBRwRD6CLm+H3krTdeM9ILxDK5PxHzAJBgcqhkjOOAQDAzAAMC0CFGup
+|8E56Wnnj+b49K8kGN+kRF6ETAhUAjzRpKouxPAN5lDJNEh/OiftGsjs=
+|<CarlDSSSelf.cer
+
+***CarlRSASelf.cer***
+
+|* Example CarlRSASelf.cer
+|>CarlRSASelf.cer
+|MIIB6zCCAVSgAwIBAgIQRjRrx4AAVrwR024un/JQIDANBgkqhkiG9w0BAQUFADASMRAwDg
+|YDVQQDEwdDYXJsUlNBMB4XDTk5MDgxODA3MDAwMFoXDTM5MTIzMTIzNTk1OVowEjEQMA4G
+|A1UEAxMHQ2FybFJTQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Ev/GLgkV/R3/2
+|5ze5NxXLwzGpKSciPYQUbQzRE6BLOOr4KdvVEeF3rydiwrhjmnvdeNGlPs5ADV6OyiNrHt
+|4lDiMgmKP5+ZJY+4Tqu5fdWWZdoWoMW+Dq5EW+9e9Kcpy4LdrETpqpOUKQ74GNbIV17yds
+|TyEWA4uRs8HZfJavECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+|AYYwHQYDVR0OBBYEFOngkCeseCB6mtNM8kI3TiKunji7MA0GCSqGSIb3DQEBBQUAA4GBAL
+|ee1ATT7Snk/4mJFS5M2wzwSA8yYe7EBOwSXS3/D2RZfgrD7Rj941ZAN6cHtfA4EmFQ7e/d
+
+
+
+Hoffman, Ed.                 Informational                    [Page 122]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|P+MLuGGlpJs85p6cVJq2ldbabDu1LUU1nUkBdvq5uTH5+WsSU6D1FGCbfco+8lNrsDdvre
+|Z019v6WuoUQWNdzb7IDsHaao1TNBgC
+|<CarlRSASelf.cer
+
+***DianeDSSSignByCarlInherit.cer***
+
+|* Example DianeDSSSignByCarlInherit.cer
+|>DianeDSSSignByCarlInherit.cer
+|MIIBuDCCAXegAwIBAgICANIwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTMB4XDT
+|k5MDgxNzAyMDgxMFoXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIRGlhbmVEU1MwgZMw
+|CQYHKoZIzjgEAQOBhQACgYEAoAAXeCzufoFTLi5hCA+hm1FSGtpZqHMvEiW2CMvK7ypEdo
+|pSCeq9BSLVD/b9RtevmTgJDhPLTyzdHDT3HL8l/yPTO1nngpc3vjEk2BjI80k5W7fi5Sd+
+|/IxFclt+Po9oTd1GeiK+jv/M2jkpoznln0PpVcnXW6aBZ8zAqs0uxSOjgYEwfzAMBgNVHR
+|MBAf8EAjAAMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBRwRD6CLm+H3krTdeM9ILxD
+|K5PxHzAdBgNVHQ4EFgQUZDCZfVzcRQuZOlIvFr9YUN3OKxgwHwYDVR0RBBgwFoEURGlhbm
+|VEU1NAZXhhbXBsZS5jb20wCQYHKoZIzjgEAwMwADAtAhUAoRr4Fw4+XaiM9LZVMx5L4yys
+|uV8CFChLEEVY0hydVTUUGJGyPznftW7T
+|<DianeDSSSignByCarlInherit.cer
+
+***DianeRSASignByCarl.cer***
+
+|* Example DianeRSASignByCarl.cer
+|>DianeRSASignByCarl.cer
+|MIICLDCCAZWgAwIBAgIQRjRrx4AAVrwR024u1ZowkDANBgkqhkiG9w0BAQUFADASMRAwDg
+|YDVQQDEwdDYXJsUlNBMB4XDTk5MDgxOTA3MDAwMFoXDTM5MTIzMTIzNTk1OVowEzERMA8G
+|A1UEAxMIRGlhbmVSU0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANb9uMBwxkwl7O
+|rP6ny7omL68OYyOlP/sZJaF/Qg4ZkkggrQ9nz7RMqLJwbxfiYDqXadz+ygLHCW8oNC9tS3
+|KAq7+L9KTBk/B9ugwWAet35n996xw2BJrEXX+MbvCDchk0fu8HM1crACxPMRw15H5Qq3g/
+|HbdGlki0QdlV3NKMCFAgMBAAGjgYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF
+|4DAfBgNVHSMEGDAWgBTp4JAnrHggeprTTPJCN04irp44uzAdBgNVHQ4EFgQUjPPLdQ6NMf
+|bUKdpEknW4/u1POQwwHwYDVR0RBBgwFoEURGlhbmVSU0FAZXhhbXBsZS5jb20wDQYJKoZI
+|hvcNAQEFBQADgYEAfaYstXhC1nnzMf72QsoPEweSCRvgb7CRGPa/SvvMY3n7gb/dl8eQa8
+|sKNytBagOYxRs+MshFK4YBnBziNu8WwRqSuL5i+1M+SUcLxLnkK1imBoPwsqe7hX7VxtrO
+|nHsxctei6kGrasDdH7kURBjPhFdm6MXmuNwtsx8bKEM2dXo=
+|<DianeRSASignByCarl.cer
+
+From Section 2.4
+
+***CarlDSSCRLForAll.crl***
+
+|* Example CarlDSSCRLForAll.crl
+|>CarlDSSCRLForAll.crl
+|MIHYMIGZMAkGByqGSM44BAMwEjEQMA4GA1UEAxMHQ2FybERTUxcNOTkwODI3MDcwMDAwWj
+|BpMBMCAgDIFw05OTA4MjIwNzAwMDBaMBMCAgDJFw05OTA4MjIwNzAwMDBaMBMCAgDTFw05
+|OTA4MjIwNzAwMDBaMBMCAgDSFw05OTA4MjIwNzAwMDBaMBMCAgDUFw05OTA4MjQwNzAwMD
+|BaMAkGByqGSM44BAMDLwAwLAIUfmVSdjP+NHMX0feW+aDU2G1cfT0CFAJ6W7fVWxjBz4fv
+|ftok8yqDnDWh
+|<CarlDSSCRLForAll.crl
+
+
+
+Hoffman, Ed.                 Informational                    [Page 123]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+***CarlDSSCRLForCarl.crl***
+
+|* Example CarlDSSCRLForCarl.crl
+|>CarlDSSCRLForCarl.crl
+|MIGDMEQwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTFw05OTA4MjUwNzAwMDBaMB
+|QwEgIBARcNOTkwODIyMDcwMDAwWjAJBgcqhkjOOAQDAzAAMC0CFQCzH8VPej3sdtVg+d55
+|IuxPsJD+lwIUWovDhLxmhxu/eYJbCl0H9rqpBSk=
+|<CarlDSSCRLForCarl.crl
+
+***CarlDSSCRLEmpty.crl***
+
+|* Example CarlDSSCRLEmpty.crl
+|>CarlDSSCRLEmpty.crl
+|MG0wLjAJBgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MXDTk5MDgyMDA3MDAwMFowCQ
+|YHKoZIzjgEAwMwADAtAhRiPzYXMVguZ1B59QlLjK3Ua/RknwIVALU7TqFMe/0Pw42btv7D
+|XW/eZSh9
+|<CarlDSSCRLEmpty.crl
+
+***CarlRSACRLForAll.crl***
+
+|* Example CarlRSACRLForAll.crl
+|>CarlRSACRLForAll.crl
+|MIIBMzCBnTANBgkqhkiG9w0BAQQFADASMRAwDgYDVQQDEwdDYXJsUlNBFw05OTA4MjcwNz
+|AwMDBaMGkwIQIQRjRrx4AAVrwR024uxBCzsBcNOTkwODIyMDcwMDAwWjAhAhBGNGvHgABW
+|vBHTbi7VmjCQFw05OTA4MjIwNzAwMDBaMCECEEY0a8eAAFa8EdNuLs1dcdAXDTk5MDgyND
+|A3MDAwMFowDQYJKoZIhvcNAQEEBQADgYEAv7OXqlPwMiEWK3eSemu7l8jc6vH6ZhYwDrWe
+|XPCB1F6zbsGIa4zUXsVN+0deZvNdq+W0GDZgqE2cPInsbye/NVBxgcK5RFtiiRkSMal7mt
+|PMZssR2QsQR3etTyLZ5X8w8lv8lFGlWHY7H6hGph/2od5Voe0xiGmXDwjT1AxgWx4=
+|<CarlRSACRLForAll.crl
+
+***CarlRSACRLForCarl.crl***
+
+|* Example CarlRSACRLForCarl.crl
+|>CarlRSACRLForCarl.crl
+|MIHsMFcwDQYJKoZIhvcNAQEEBQAwEjEQMA4GA1UEAxMHQ2FybFJTQRcNOTkwODI1MDcwMD
+|AwWjAjMCECEEY0a8eAAFa8EdNuLp/yUCAXDTk5MDgyMjA3MDAwMFowDQYJKoZIhvcNAQEE
+|BQADgYEAIe8h1MEahZVJa8pFYtzXCf+pUS6O2UcY+vjlct1P7XR04/NlMmUoLJodV+XVJg
+|bq1eYjlYSNDome7psML84H96PRa4VMD//m3fzczXMsHn3csHHFTPwBblJXaR45Y98SIjDH
+|E1WUBW4qAKlbxCpmlGLONjPCK2NHJZ3z3nDuAFY=
+|<CarlRSACRLForCarl.crl
+
+***CarlRSACRLEmpty.crl***
+
+|* Example CarlRSACRLEmpty.crl
+|>CarlRSACRLEmpty.crl
+|MIHHMDIwDQYJKoZIhvcNAQEEBQAwEjEQMA4GA1UEAxMHQ2FybFJTQRcNOTkwODIwMDcwMD
+|AwWjANBgkqhkiG9w0BAQQFAAOBgQCpxSG4E3x087UR7ATzIEWGHgtuf4NtX/Q0dgZZJQ4E
+|PYgJiIE3xNwgmPoXgQs3lKy0j3tRiRSky3JzFAe8IpxAoQf8RHyFDwuI0e7hDq/2FnStoa
+
+
+
+Hoffman, Ed.                 Informational                    [Page 124]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|/BAHUAZOqlmvYLCKLblRlfpqe5OUUlCg72XoTn+LlayRjCDriglr6BOoBtyQ==
+|<CarlRSACRLEmpty.crl
+
+Rest of the sections
+
+***3.1.bin***
+
+|* Example 3.1.bin
+|>3.1.bin
+|MIAGCSqGSIb3DQEHAaCAJIAEBFRoaXMEGCBpcyBzb21lIHNhbXBsZSBjb250ZW50LgAAAA
+|AAAA==
+|<3.1.bin
+
+***3.2.bin***
+
+|* Example 3.2.bin
+|>3.2.bin
+|MCsGCSqGSIb3DQEHAaAeBBxUaGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQu
+|<3.2.bin
+
+***4.1.bin***
+
+|* Example 4.1.bin
+|>4.1.bin
+|MIIDlwYJKoZIhvcNAQcCoIIDiDCCA4QCAQExCTAHBgUrDgMCGjArBgkqhkiG9w0BBwGgHg
+|QcVGhpcyBpcyBzb21lIHNhbXBsZSBjb250ZW50LqCCAuAwggLcMIICm6ADAgECAgIAyDAJ
+|BgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MwHhcNOTkwODE3MDExMDQ5WhcNMzkxMj
+|MxMjM1OTU5WjATMREwDwYDVQQDEwhBbGljZURTUzCCAbYwggErBgcqhkjOOAQBMIIBHgKB
+|gQCBjc3tg+oKnjk+wkgoo+RHk90O16gO7FPFq4QIT/+U4XNIfgzW80RI0f6fr6ShiS/h2T
+|DINt4/m7+3TNxfaYrkddA3DJEIlZvep175/PSfL91DqItU8T+wBwhHTV2Iw8O1s+NVCHXV
+|OXYQxHi9/52whJc38uRRG7XkCZZc835b2wIVAOJHphpFZrgTxtqPuDchK2KL95PNAoGAJj
+|jQFIkyqjn7Pm3ZS1lqTHYjOQQCNVzyyxowwx5QXd2bWeLNqgU9WMB7oja4bgevfYpCJaf0
+|dc9KCF5LPpD4beqcySGKO3YU6c4uXaMHzSOFuC8wAXxtSYkRiTZEvfjIlUpTVrXi+XPsGm
+|E2HxF/wr3t0VD/mHTC0YFKYDm6NjkDgYQAAoGAXOO5WnUUlgupet3jP6nsrF7cvbcTETSm
+|FokoESPZNIZndXUTEj1DW2/lUb/6ifKiGz4kfT0HjVtjyLtFpaBK44XWzgaAP+gjfhryJK
+|tTGrgnDR7vCL9mFIBcYqxl+hWL8bs01NKWN/ZhR7LEMoTwfkFA/UanY04z8qXi9PKD5bij
+|gYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBRwRD6CLm
+|+H3krTdeM9ILxDK5PxHzAdBgNVHQ4EFgQUvmyhs+PB9+1DcKTOEwHi/eOX/s0wHwYDVR0R
+|BBgwFoEUQWxpY2VEU1NAZXhhbXBsZS5jb20wCQYHKoZIzjgEAwMwADAtAhRVDKQZH0IriX
+|EiM42DarU9Z2u/RQIVAJ9hU1JUC1yy3drndh3iEFJbQ169MWMwYQIBATAYMBIxEDAOBgNV
+|BAMTB0NhcmxEU1MCAgDIMAcGBSsOAwIaMAkGByqGSM44BAMELjAsAhQJkf7r0mn1GLfXzV
+|X0geoqQmqtAwIUOgfMwyG+4RpLfz61Ddu6HOq8zYk=
+|<4.1.bin
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 125]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+***4.2.bin***
+
+|* Example 4.2.bin
+|>4.2.bin
+|MIIDUgYJKoZIhvcNAQcCoIIDQzCCAz8CAQExCzAJBgUrDgMCGgUAMCsGCSqGSIb3DQEHAa
+|AeBBxUaGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQuoIICMDCCAiwwggGVoAMCAQICEEY0
+|a8eAAFa8EdNuLsQQs7AwDQYJKoZIhvcNAQEFBQAwEjEQMA4GA1UEAxMHQ2FybFJTQTAeFw
+|05OTA5MTkwMTA4NDdaFw0zOTEyMzEyMzU5NTlaMBMxETAPBgNVBAMTCEFsaWNlUlNBMIGf
+|MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgiXM5jdj19eiHdjl/TrAFu1OD3g+3q9x9x3
+|UpDQUubRLfpoYm1NJvqlgp/Jfs+oJRDzCAvrFQnkZE8Sy72DLPxmhvB9mwYKy+7jQJahP1
+|9wUFk99eujVW2WH/GX/Jgeb4bOqHQHDvrG0sdJ8t+lU6uZl3AqZIUoxO81c4V3RXXwIDAQ
+|ABo4GBMH8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBsAwHwYDVR0jBBgwFoAU6eCQ
+|J6x4IHqa00zyQjdOIq6eOLswHQYDVR0OBBYEFHfStNG3TIqKo85Fnc7sPKA64/9QMB8GA1
+|UdEQQYMBaBFEFsaWNlUlNBQGV4YW1wbGUuY29tMA0GCSqGSIb3DQEBBQUAA4GBAD5wR6hI
+|zBNYj8pRcWtONhhdBH6AsY1NzMqjj8x9Vsi8z26zHFmpIKoFgahOJa2ncBR1L/XHm9EO6W
+|PSZLfGZm5zIVTf9LolXX1J05RrIjZ0c7hK7C9k7dM90qdCxeg3irTbn2fkvZ/5/nTv6vnu
+|Y2rYP0slCbXYGnau65vbSbAiMYHLMIHIAgEBMCYwEjEQMA4GA1UEAxMHQ2FybFJTQQIQRj
+|Rrx4AAVrwR024uxBCzsDAJBgUrDgMCGgUAMA0GCSqGSIb3DQEBAQUABIGALyOC0vMJX7gM
+|WOtOnb+JmoHldcSRPdPQ1Xu21f6UoYqs48SE9c1gTieV9s8AhnZ1Pyvw59QCZ6f1x40WBK
+|WztefZMvAk7+cgRNWfB8VTJPrOAR0PFxOnKpWdK+QDlRQL6TkNus5unJ4M6JjmVRPUaG/Q
+|B9eisWJM44+v/eDVXcc=
+|<4.2.bin
+
+***4.3.bin***
+
+|* Example 4.3.bin
+|>4.3.bin
+|MIIDdwYJKoZIhvcNAQcCoIIDaDCCA2QCAQExCTAHBgUrDgMCGjALBgkqhkiG9w0BBwGggg
+|LgMIIC3DCCApugAwIBAgICAMgwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNTMB4X
+|DTk5MDgxNzAxMTA0OVoXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIQWxpY2VEU1Mwgg
+|G2MIIBKwYHKoZIzjgEATCCAR4CgYEAgY3N7YPqCp45PsJIKKPkR5PdDteoDuxTxauECE//
+|lOFzSH4M1vNESNH+n6+koYkv4dkwyDbeP5u/t0zcX2mK5HXQNwyRCJWb3qde+fz0ny/dQ6
+|iLVPE/sAcIR01diMPDtbPjVQh11Tl2EMR4vf+dsISXN/LkURu15AmWXPN+W9sCFQDiR6Ya
+|RWa4E8baj7g3IStii/eTzQKBgCY40BSJMqo5+z5t2UtZakx2IzkEAjVc8ssaMMMeUF3dm1
+|nizaoFPVjAe6I2uG4Hr32KQiWn9HXPSgheSz6Q+G3qnMkhijt2FOnOLl2jB80jhbgvMAF8
+|bUmJEYk2RL34yJVKU1a14vlz7BphNh8Rf8K97dFQ/5h0wtGBSmA5ujY5A4GEAAKBgFzjuV
+|p1FJYLqXrd4z+p7Kxe3L23ExE0phaJKBEj2TSGZ3V1ExI9Q1tv5VG/+onyohs+JH09B41b
+|Y8i7RaWgSuOF1s4GgD/oI34a8iSrUxq4Jw0e7wi/ZhSAXGKsZfoVi/G7NNTSljf2YUeyxD
+|KE8H5BQP1Gp2NOM/Kl4vTyg+W4o4GBMH8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMC
+|BsAwHwYDVR0jBBgwFoAUcEQ+gi5vh95K03XjPSC8QyuT8R8wHQYDVR0OBBYEFL5sobPjwf
+|ftQ3CkzhMB4v3jl/7NMB8GA1UdEQQYMBaBFEFsaWNlRFNTQGV4YW1wbGUuY29tMAkGByqG
+|SM44BAMDMAAwLQIUVQykGR9CK4lxIjONg2q1PWdrv0UCFQCfYVNSVAtcst3a53Yd4hBSW0
+|NevTFjMGECAQEwGDASMRAwDgYDVQQDEwdDYXJsRFNTAgIAyDAHBgUrDgMCGjAJBgcqhkjO
+|OAQDBC4wLAIUBvvHKiTVNIn3i7X9cySlhsgPWmwCFGZpGbxoWNGNsZ1SP9oUiA39yaG4
+|<4.3.bin
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 126]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+***4.4.bin***
+
+|* Example 4.4.bin
+|>4.4.bin
+|MIILDQYJKoZIhvcNAQcCoIIK/jCCCvoCAQExCTAHBgUrDgMCGjArBgkqhkiG9w0BBwGgHg
+|QcVGhpcyBpcyBzb21lIHNhbXBsZSBjb250ZW50LqCCB68wggIsMIIBlaADAgECAhBGNGvH
+|gABWvBHTbi7EELOwMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNVBAMTB0NhcmxSU0EwHhcNOT
+|kwOTE5MDEwODQ3WhcNMzkxMjMxMjM1OTU5WjATMREwDwYDVQQDEwhBbGljZVJTQTCBnzAN
+|BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4IlzOY3Y9fXoh3Y5f06wBbtTg94Pt6vcfcd1KQ
+|0FLm0S36aGJtTSb6pYKfyX7PqCUQ8wgL6xUJ5GRPEsu9gyz8ZobwfZsGCsvu40CWoT9fcF
+|BZPfXro1Vtlh/xl/yYHm+Gzqh0Bw76xtLHSfLfpVOrmZdwKmSFKMTvNXOFd0V18CAwEAAa
+|OBgTB/MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgbAMB8GA1UdIwQYMBaAFOngkCes
+|eCB6mtNM8kI3TiKunji7MB0GA1UdDgQWBBR30rTRt0yKiqPORZ3O7DygOuP/UDAfBgNVHR
+|EEGDAWgRRBbGljZVJTQUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQUFAAOBgQA+cEeoSMwT
+|WI/KUXFrTjYYXQR+gLGNTczKo4/MfVbIvM9usxxZqSCqBYGoTiWtp3AUdS/1x5vRDulj0m
+|S3xmZucyFU3/S6JV19SdOUayI2dHO4SuwvZO3TPdKnQsXoN4q0259n5L2f+f507+r57mNq
+|2D9LJQm12Bp2ruub20mwIjCCApswggJaoAMCAQICAQEwCQYHKoZIzjgEAzASMRAwDgYDVQ
+|QDEwdDYXJsRFNTMB4XDTk5MDgxNjIyNTA1MFoXDTM5MTIzMTIzNTk1OVowEjEQMA4GA1UE
+|AxMHQ2FybERTUzCCAbcwggErBgcqhkjOOAQBMIIBHgKBgQC2SRg+ikTBKXGUTAHEEsF6ec
+|tUTasegfvGTLMOlAkG6wHUschxS8dFwFAlXZz82uRt0+KGSISCfboVlUoW9kbt3faY0rt+
+|igqKuhZ7uVABSJOL6yUVUZdV3I9TDhCpUPxwt80wVP3a3qiqIrWhr4vMAojni3Bfua3hCN
+|RtKS3W6QIVAN3BL99Tzgs0YHc+AqS/il2YuRDVAoGADO5Xm0u92rYHanQ3T1V/ne28YQ3r
+|Rlk8VgsrWwyRzqViUmnK4W0+vb/+4be5K2E8rcuuReMGrIwinZxEhwvHzfAc2bVOXXPerw
+|7JHVpR9U9EeTVac6p/RlEfqUIWnEjrinlhtNUvUyJEYx+GuKNYBiX4KcDvuuB18ELEY2VS
+|mwoDgYUAAoGBAJmHdCcDZqCxwK3cLHW74WxEnNohbU1HbbFiCenYrh7yOrSUsaOOeptxTg
+|CUybQlTrlglhkkAfNiDP51wPvO2GgA4/3VcE/fI5YZBpT0sWGPOlexCBGkCyYl8FJ2geoL
+|Yg2VKuaGunKyp1CDC6onzRupTYma140YOYQ/i8VWTYB6o0IwQDAPBgNVHRMBAf8EBTADAQ
+|H/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUcEQ+gi5vh95K03XjPSC8QyuT8R8wCQYH
+|KoZIzjgEAwMwADAtAhRrqfBOelp54/m+PSvJBjfpERehEwIVAI80aSqLsTwDeZQyTRIfzo
+|n7RrI7MIIC3DCCApugAwIBAgICAMgwCQYHKoZIzjgEAzASMRAwDgYDVQQDEwdDYXJsRFNT
+|MB4XDTk5MDgxNzAxMTA0OVoXDTM5MTIzMTIzNTk1OVowEzERMA8GA1UEAxMIQWxpY2VEU1
+|MwggG2MIIBKwYHKoZIzjgEATCCAR4CgYEAgY3N7YPqCp45PsJIKKPkR5PdDteoDuxTxauE
+|CE//lOFzSH4M1vNESNH+n6+koYkv4dkwyDbeP5u/t0zcX2mK5HXQNwyRCJWb3qde+fz0ny
+|/dQ6iLVPE/sAcIR01diMPDtbPjVQh11Tl2EMR4vf+dsISXN/LkURu15AmWXPN+W9sCFQDi
+|R6YaRWa4E8baj7g3IStii/eTzQKBgCY40BSJMqo5+z5t2UtZakx2IzkEAjVc8ssaMMMeUF
+|3dm1nizaoFPVjAe6I2uG4Hr32KQiWn9HXPSgheSz6Q+G3qnMkhijt2FOnOLl2jB80jhbgv
+|MAF8bUmJEYk2RL34yJVKU1a14vlz7BphNh8Rf8K97dFQ/5h0wtGBSmA5ujY5A4GEAAKBgF
+|zjuVp1FJYLqXrd4z+p7Kxe3L23ExE0phaJKBEj2TSGZ3V1ExI9Q1tv5VG/+onyohs+JH09
+|B41bY8i7RaWgSuOF1s4GgD/oI34a8iSrUxq4Jw0e7wi/ZhSAXGKsZfoVi/G7NNTSljf2YU
+|eyxDKE8H5BQP1Gp2NOM/Kl4vTyg+W4o4GBMH8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8E
+|BAMCBsAwHwYDVR0jBBgwFoAUcEQ+gi5vh95K03XjPSC8QyuT8R8wHQYDVR0OBBYEFL5sob
+|PjwfftQ3CkzhMB4v3jl/7NMB8GA1UdEQQYMBaBFEFsaWNlRFNTQGV4YW1wbGUuY29tMAkG
+|ByqGSM44BAMDMAAwLQIUVQykGR9CK4lxIjONg2q1PWdrv0UCFQCfYVNSVAtcst3a53Yd4h
+|BSW0NevaGB2zCB2DCBmTAJBgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MXDTk5MDgy
+|NzA3MDAwMFowaTATAgIAyBcNOTkwODIyMDcwMDAwWjATAgIAyRcNOTkwODIyMDcwMDAwWj
+|ATAgIA0xcNOTkwODIyMDcwMDAwWjATAgIA0hcNOTkwODIyMDcwMDAwWjATAgIA1BcNOTkw
+|ODI0MDcwMDAwWjAJBgcqhkjOOAQDAy8AMCwCFH5lUnYz/jRzF9H3lvmg1NhtXH09AhQCel
+|u31VsYwc+H737aJPMqg5w1oTGCAiowggImAgEBMBgwEjEQMA4GA1UEAxMHQ2FybERTUwIC
+
+
+
+Hoffman, Ed.                 Informational                    [Page 127]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|AMgwBwYFKw4DAhqgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBT
+|EPFw0wMzA1MTQxNTM5MDBaMCMGCSqGSIb3DQEJBDEWBBRAauwIUnm6bhYCLZ4GKcAilofd
+|SDAJBgcqhkjOOAQDBC4wLAIUO6XgStttWOAZ0QAcT0SaV3pxZmgCFBoRmNYfH680gQHevo
+|vctqhqkWkToYIBYjA+BgsqhkiG9w0BCRACBDEvMC0MIENvbnRlbnQgSGludHMgRGVzY3Jp
+|cHRpb24gQnVmZmVyBgkqhkiG9w0BBwEwggEeBgkqhkiG9w0BCQYxggEPMIIBCwIBATAmMB
+|IxEDAOBgNVBAMTB0NhcmxSU0ECEEY0a8eAAFa8EdNuLsQQs7AwBwYFKw4DAhqgQzAcBgkq
+|hkiG9w0BCQUxDxcNMDMwNTE0MTUzOTAwWjAjBgkqhkiG9w0BCQQxFgQUAl9JTjmYUIWzZt
+|OKH3ueaar72DMwDQYJKoZIhvcNAQEBBQAEgYBtqiAk7XrupV6H3XUfK1QQZfTOm7EseHS8
+|ixxgtduLA55J8it/k249iRTJ42v09n12rj5YH5u7vHwwGU4Q9wLxi1u025q7k7QY0MwryZ
+|GprdlG+GWp4nGV0NROH810b4LoN29aPcvH1F/CgBva04RAaF9WmmL1Ow1sM8PtZz9Dvw==
+|<4.4.bin
+
+***4.5.bin***
+
+|* Example 4.5.bin
+|>4.5.bin
+|MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCAJIAEBF
+|RoaXMEGCBpcyBzb21lIHNhbXBsZSBjb250ZW50LgAAAAAAAKCAMIIB6zCCAVSgAwIBAgIQ
+|RjRrx4AAVrwR024un/JQIDANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdDYXJsUlNBMB
+|4XDTk5MDgxODA3MDAwMFoXDTM5MTIzMTIzNTk1OVowEjEQMA4GA1UEAxMHQ2FybFJTQTCB
+|nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Ev/GLgkV/R3/25ze5NxXLwzGpKSciPYQU
+|bQzRE6BLOOr4KdvVEeF3rydiwrhjmnvdeNGlPs5ADV6OyiNrHt4lDiMgmKP5+ZJY+4Tqu5
+|fdWWZdoWoMW+Dq5EW+9e9Kcpy4LdrETpqpOUKQ74GNbIV17ydsTyEWA4uRs8HZfJavECAw
+|EAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFOng
+|kCeseCB6mtNM8kI3TiKunji7MA0GCSqGSIb3DQEBBQUAA4GBALee1ATT7Snk/4mJFS5M2w
+|zwSA8yYe7EBOwSXS3/D2RZfgrD7Rj941ZAN6cHtfA4EmFQ7e/dP+MLuGGlpJs85p6cVJq2
+|ldbabDu1LUU1nUkBdvq5uTH5+WsSU6D1FGCbfco+8lNrsDdvreZ019v6WuoUQWNdzb7IDs
+|Haao1TNBgCMIICLDCCAZWgAwIBAgIQRjRrx4AAVrwR024uxBCzsDANBgkqhkiG9w0BAQUF
+|ADASMRAwDgYDVQQDEwdDYXJsUlNBMB4XDTk5MDkxOTAxMDg0N1oXDTM5MTIzMTIzNTk1OV
+|owEzERMA8GA1UEAxMIQWxpY2VSU0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOCJ
+|czmN2PX16Id2OX9OsAW7U4PeD7er3H3HdSkNBS5tEt+mhibU0m+qWCn8l+z6glEPMIC+sV
+|CeRkTxLLvYMs/GaG8H2bBgrL7uNAlqE/X3BQWT3166NVbZYf8Zf8mB5vhs6odAcO+sbSx0
+|ny36VTq5mXcCpkhSjE7zVzhXdFdfAgMBAAGjgYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDw
+|EB/wQEAwIGwDAfBgNVHSMEGDAWgBTp4JAnrHggeprTTPJCN04irp44uzAdBgNVHQ4EFgQU
+|d9K00bdMioqjzkWdzuw8oDrj/1AwHwYDVR0RBBgwFoEUQWxpY2VSU0FAZXhhbXBsZS5jb2
+|0wDQYJKoZIhvcNAQEFBQADgYEAPnBHqEjME1iPylFxa042GF0EfoCxjU3MyqOPzH1WyLzP
+|brMcWakgqgWBqE4lradwFHUv9ceb0Q7pY9Jkt8ZmbnMhVN/0uiVdfUnTlGsiNnRzuErsL2
+|Tt0z3Sp0LF6DeKtNufZ+S9n/n+dO/q+e5jatg/SyUJtdgadq7rm9tJsCIAADGByzCByAIB
+|ATAmMBIxEDAOBgNVBAMTB0NhcmxSU0ECEEY0a8eAAFa8EdNuLsQQs7AwCQYFKw4DAhoFAD
+|ANBgkqhkiG9w0BAQEFAASBgC8jgtLzCV+4DFjrTp2/iZqB5XXEkT3T0NV7ttX+lKGKrOPE
+|hPXNYE4nlfbPAIZ2dT8r8OfUAmen9ceNFgSls7Xn2TLwJO/nIETVnwfFUyT6zgEdDxcTpy
+|qVnSvkA5UUC+k5DbrObpyeDOiY5lUT1Ghv0AfXorFiTOOPr/3g1V3HAAAAAAAA
+|<4.5.bin
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 128]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+***4.6.bin***
+
+|* Example 4.6.bin
+|>4.6.bin
+|MIIFtwYJKoZIhvcNAQcCoIIFqDCCBaQCAQExCTAHBgUrDgMCGjArBgkqhkiG9w0BBwGgHg
+|QcVGhpcyBpcyBzb21lIHNhbXBsZSBjb250ZW50LqCCBJwwggG4MIIBd6ADAgECAgIA0jAJ
+|BgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MwHhcNOTkwODE3MDIwODEwWhcNMzkxMj
+|MxMjM1OTU5WjATMREwDwYDVQQDEwhEaWFuZURTUzCBkzAJBgcqhkjOOAQBA4GFAAKBgQCg
+|ABd4LO5+gVMuLmEID6GbUVIa2lmocy8SJbYIy8rvKkR2ilIJ6r0FItUP9v1G16+ZOAkOE8
+|tPLN0cNPccvyX/I9M7WeeClze+MSTYGMjzSTlbt+LlJ378jEVyW34+j2hN3UZ6Ir6O/8za
+|OSmjOeWfQ+lVyddbpoFnzMCqzS7FI6OBgTB/MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BA
+|QDAgbAMB8GA1UdIwQYMBaAFHBEPoIub4feStN14z0gvEMrk/EfMB0GA1UdDgQWBBRkMJl9
+|XNxFC5k6Ui8Wv1hQ3c4rGDAfBgNVHREEGDAWgRREaWFuZURTU0BleGFtcGxlLmNvbTAJBg
+|cqhkjOOAQDAzAAMC0CFQChGvgXDj5dqIz0tlUzHkvjLKy5XwIUKEsQRVjSHJ1VNRQYkbI/
+|Od+1btMwggLcMIICm6ADAgECAgIAyDAJBgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1
+|MwHhcNOTkwODE3MDExMDQ5WhcNMzkxMjMxMjM1OTU5WjATMREwDwYDVQQDEwhBbGljZURT
+|UzCCAbYwggErBgcqhkjOOAQBMIIBHgKBgQCBjc3tg+oKnjk+wkgoo+RHk90O16gO7FPFq4
+|QIT/+U4XNIfgzW80RI0f6fr6ShiS/h2TDINt4/m7+3TNxfaYrkddA3DJEIlZvep175/PSf
+|L91DqItU8T+wBwhHTV2Iw8O1s+NVCHXVOXYQxHi9/52whJc38uRRG7XkCZZc835b2wIVAO
+|JHphpFZrgTxtqPuDchK2KL95PNAoGAJjjQFIkyqjn7Pm3ZS1lqTHYjOQQCNVzyyxowwx5Q
+|Xd2bWeLNqgU9WMB7oja4bgevfYpCJaf0dc9KCF5LPpD4beqcySGKO3YU6c4uXaMHzSOFuC
+|8wAXxtSYkRiTZEvfjIlUpTVrXi+XPsGmE2HxF/wr3t0VD/mHTC0YFKYDm6NjkDgYQAAoGA
+|XOO5WnUUlgupet3jP6nsrF7cvbcTETSmFokoESPZNIZndXUTEj1DW2/lUb/6ifKiGz4kfT
+|0HjVtjyLtFpaBK44XWzgaAP+gjfhryJKtTGrgnDR7vCL9mFIBcYqxl+hWL8bs01NKWN/Zh
+|R7LEMoTwfkFA/UanY04z8qXi9PKD5bijgYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/w
+|QEAwIGwDAfBgNVHSMEGDAWgBRwRD6CLm+H3krTdeM9ILxDK5PxHzAdBgNVHQ4EFgQUvmyh
+|s+PB9+1DcKTOEwHi/eOX/s0wHwYDVR0RBBgwFoEUQWxpY2VEU1NAZXhhbXBsZS5jb20wCQ
+|YHKoZIzjgEAwMwADAtAhRVDKQZH0IriXEiM42DarU9Z2u/RQIVAJ9hU1JUC1yy3drndh3i
+|EFJbQ169MYHGMGECAQEwGDASMRAwDgYDVQQDEwdDYXJsRFNTAgIAyDAHBgUrDgMCGjAJBg
+|cqhkjOOAQDBC4wLAIUSCTei4XyFq/sgmGpVNAtBKHMWk8CFBft1XcC7nUT2BC9PZcXIIi7
+|/XuBMGECAQEwGDASMRAwDgYDVQQDEwdDYXJsRFNTAgIA0jAHBgUrDgMCGjAJBgcqhkjOOA
+|QDBC4wLAIUFf+BTYytgE6bNVgEN25jbulbg/oCFAZ+WE4rMYRB7Ul5OD530qaMdQgh
+|<4.6.bin
+
+***4.7.bin***
+
+|* Example 4.7.bin
+|>4.7.bin
+|MIIDlAYJKoZIhvcNAQcCoIIDhTCCA4ECAQMxCTAHBgUrDgMCGjArBgkqhkiG9w0BBwGgHg
+|QcVGhpcyBpcyBzb21lIHNhbXBsZSBjb250ZW50LqCCAuAwggLcMIICm6ADAgECAgIAyDAJ
+|BgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MwHhcNOTkwODE3MDExMDQ5WhcNMzkxMj
+|MxMjM1OTU5WjATMREwDwYDVQQDEwhBbGljZURTUzCCAbYwggErBgcqhkjOOAQBMIIBHgKB
+|gQCBjc3tg+oKnjk+wkgoo+RHk90O16gO7FPFq4QIT/+U4XNIfgzW80RI0f6fr6ShiS/h2T
+|DINt4/m7+3TNxfaYrkddA3DJEIlZvep175/PSfL91DqItU8T+wBwhHTV2Iw8O1s+NVCHXV
+|OXYQxHi9/52whJc38uRRG7XkCZZc835b2wIVAOJHphpFZrgTxtqPuDchK2KL95PNAoGAJj
+|jQFIkyqjn7Pm3ZS1lqTHYjOQQCNVzyyxowwx5QXd2bWeLNqgU9WMB7oja4bgevfYpCJaf0
+|dc9KCF5LPpD4beqcySGKO3YU6c4uXaMHzSOFuC8wAXxtSYkRiTZEvfjIlUpTVrXi+XPsGm
+|E2HxF/wr3t0VD/mHTC0YFKYDm6NjkDgYQAAoGAXOO5WnUUlgupet3jP6nsrF7cvbcTETSm
+
+
+
+Hoffman, Ed.                 Informational                    [Page 129]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|FokoESPZNIZndXUTEj1DW2/lUb/6ifKiGz4kfT0HjVtjyLtFpaBK44XWzgaAP+gjfhryJK
+|tTGrgnDR7vCL9mFIBcYqxl+hWL8bs01NKWN/ZhR7LEMoTwfkFA/UanY04z8qXi9PKD5bij
+|gYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBRwRD6CLm
+|+H3krTdeM9ILxDK5PxHzAdBgNVHQ4EFgQUvmyhs+PB9+1DcKTOEwHi/eOX/s0wHwYDVR0R
+|BBgwFoEUQWxpY2VEU1NAZXhhbXBsZS5jb20wCQYHKoZIzjgEAwMwADAtAhRVDKQZH0IriX
+|EiM42DarU9Z2u/RQIVAJ9hU1JUC1yy3drndh3iEFJbQ169MWAwXgIBA4AUvmyhs+PB9+1D
+|cKTOEwHi/eOX/s0wBwYFKw4DAhowCQYHKoZIzjgEAwQvMC0CFQCJw2t7VvfDEgBl8Tf1xF
+|gXjRFXgwIUCw9DOqrs3nphLIyc9UGZpzwgw7c=
+|<4.7.bin
+
+***4.8.eml***
+
+|* Example 4.8.eml
+|>4.8.eml
+|TUlNRS1WZXJzaW9uOiAxLjAKVG86IFVzZXIyQGV4YW1wbGVzLmNvbQpGcm9tOiBhbGljZU
+|Rzc0BleGFtcGxlcy5jb20KU3ViamVjdDogRXhhbXBsZSA0LjgKTWVzc2FnZS1JZDogPDAy
+|MDkwNjAwMjU1MDMwMC4yNDlAZXhhbXBsZXMuY29tPgpEYXRlOiBGcmksIDA2IFNlcCAyMD
+|AyIDAwOjI1OjIxIC0wMzAwIApDb250ZW50LVR5cGU6IG11bHRpcGFydC9zaWduZWQ7CiAg
+|ICBtaWNhbGc9U0hBMTsKICAgIGJvdW5kYXJ5PSItLS0tPV9OZXh0Qm91bmRyeV9fX19Gcm
+|ksXzA2X1NlcF8yMDAyXzAwOjI1OjIxIjsKICAgIHByb3RvY29sPSJhcHBsaWNhdGlvbi9w
+|a2NzNy1zaWduYXR1cmUiCgpUaGlzIGlzIGEgbXVsdGktcGFydCBtZXNzYWdlIGluIE1JTU
+|UgZm9ybWF0LgoKLS0tLS0tPV9OZXh0Qm91bmRyeV9fX19GcmksXzA2X1NlcF8yMDAyXzAw
+|OjI1OjIxCgpUaGlzIGlzIHNvbWUgc2FtcGxlIGNvbnRlbnQuCi0tLS0tLT1fTmV4dEJvdW
+|5kcnlfX19fRnJpLF8wNl9TZXBfMjAwMl8wMDoyNToyMQpDb250ZW50LVR5cGU6IGFwcGxp
+|Y2F0aW9uL3BrY3M3LXNpZ25hdHVyZTsgbmFtZT1zbWltZS5wN3MKQ29udGVudC1UcmFuc2
+|Zlci1FbmNvZGluZzogYmFzZTY0CkNvbnRlbnQtRGlzcG9zaXRpb246IGF0dGFjaG1lbnQ7
+|IGZpbGVuYW1lPXNtaW1lLnA3cwoKTUlJRGR3WUpLb1pJaHZjTkFRY0NvSUlEYURDQ0EyUU
+|NBUUV4Q1RBSEJnVXJEZ01DR2pBTEJna3Foa2lHOXcwQkJ3R2dnZ0xnTUlJQwozRENDQXB1
+|Z0F3SUJBZ0lDQU1nd0NRWUhLb1pJempnRUF6QVNNUkF3RGdZRFZRUURFd2REWVhKc1JGTl
+|RNQjRYRFRrNU1EZ3hOekF4Ck1UQTBPVm9YRFRNNU1USXpNVEl6TlRrMU9Wb3dFekVSTUE4
+|R0ExVUVBeE1JUVd4cFkyVkVVMU13Z2dHMk1JSUJLd1lIS29aSXpqZ0UKQVRDQ0FSNENnWU
+|VBZ1kzTjdZUHFDcDQ1UHNKSUtLUGtSNVBkRHRlb0R1eFR4YXVFQ0UvL2xPRnpTSDRNMXZO
+|RVNOSCtuNitrb1lrdgo0ZGt3eURiZVA1dS90MHpjWDJtSzVIWFFOd3lSQ0pXYjNxZGUrZn
+|owbnkvZFE2aUxWUEUvc0FjSVIwMWRpTVBEdGJQalZRaDExVGwyCkVNUjR2Zitkc0lTWE4v
+|TGtVUnUxNUFtV1hQTitXOXNDRlFEaVI2WWFSV2E0RThiYWo3ZzNJU3RpaS9lVHpRS0JnQ1
+|k0MEJTSk1xbzUKK3o1dDJVdFpha3gySXprRUFqVmM4c3NhTU1NZVVGM2RtMW5pemFvRlBW
+|akFlNkkydUc0SHIzMktRaVduOUhYUFNnaGVTejZRK0czcQpuTWtoaWp0MkZPbk9MbDJqQj
+|gwamhiZ3ZNQUY4YlVtSkVZazJSTDM0eUpWS1UxYTE0dmx6N0JwaE5oOFJmOEs5N2RGUS81
+|aDB3dEdCClNtQTV1alk1QTRHRUFBS0JnRnpqdVZwMUZKWUxxWHJkNHorcDdLeGUzTDIzRX
+|hFMHBoYUpLQkVqMlRTR1ozVjFFeEk5UTF0djVWRy8KK29ueW9ocytKSDA5QjQxYlk4aTdS
+|YVdnU3VPRjFzNEdnRC9vSTM0YThpU3JVeHE0SncwZTd3aS9aaFNBWEdLc1pmb1ZpL0c3Tk
+|5UUwpsamYyWVVleXhES0U4SDVCUVAxR3AyTk9NL0tsNHZUeWcrVzRvNEdCTUg4d0RBWURW
+|UjBUQVFIL0JBSXdBREFPQmdOVkhROEJBZjhFCkJBTUNCc0F3SHdZRFZSMGpCQmd3Rm9BVW
+|NFUStnaTV2aDk1SzAzWGpQU0M4UXl1VDhSOHdIUVlEVlIwT0JCWUVGTDVzb2JQandmZnQK
+|UTNDa3poTUI0djNqbC83Tk1COEdBMVVkRVFRWU1CYUJGRUZzYVdObFJGTlRRR1Y0WVcxd2
+|JHVXVZMjl0TUFrR0J5cUdTTTQ0QkFNRApNQUF3TFFJVVZReWtHUjlDSzRseElqT05nMnEx
+|UFdkcnYwVUNGUUNmWVZOU1ZBdGNzdDNhNTNZZDRoQlNXME5ldlRGak1HRUNBUUV3CkdEQV
+|NNUkF3RGdZRFZRUURFd2REWVhKc1JGTlRBZ0lBeURBSEJnVXJEZ01DR2pBSkJnY3Foa2pP
+
+
+
+Hoffman, Ed.                 Informational                    [Page 130]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|T0FRREJDNHdMQUlVTS9tR2Y2Z2sKZ3A5WjBYdFJkR2ltSmVCL0J4VUNGR0ZGSnF3WVJ0MV
+|dZY0lPUW9HaWFvd3FHelZJCgotLS0tLS09X05leHRCb3VuZHJ5X19fX0ZyaSxfMDZfU2Vw
+|XzIwMDJfMDA6MjU6MjEtLQo=
+|<4.8.eml
+
+***4.9.eml***
+
+|* Example 4.9.eml
+|>4.9.eml
+|TUlNRS1WZXJzaW9uOiAxLjAKVG86IFVzZXIyQGV4YW1wbGVzLmNvbQpGcm9tOiBhbGljZU
+|Rzc0BleGFtcGxlcy5jb20KU3ViamVjdDogRXhhbXBsZSA0LjkKTWVzc2FnZS1JZDogPDAy
+|MTAzMTE2NDU0MDMwMC4zMDRAZXhhbXBsZXMuY29tPgpEYXRlOiBUaHUsIDMxIE9jdCAyMD
+|AyIDE2OjQ1OjE0IC0wMzAwIApDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL3BrY3M3LW1p
+|bWU7IHNtaW1lLXR5cGU9c2lnbmVkLWRhdGE7CiAgICBuYW1lPXNtaW1lLnA3bQpDb250ZW
+|50LVRyYW5zZmVyLUVuY29kaW5nOiBiYXNlNjQKQ29udGVudC1EaXNwb3NpdGlvbjogYXR0
+|YWNobWVudDsgZmlsZW5hbWU9c21pbWUucDdtCgpNSUlEbVFZSktvWklodmNOQVFjQ29JSU
+|RpakNDQTRZQ0FRRXhDVEFIQmdVckRnTUNHakF0QmdrcWhraUc5dzBCQndHZ0lBUWVEUXBV
+|CmFHbHpJR2x6SUhOdmJXVWdjMkZ0Y0d4bElHTnZiblJsYm5RdW9JSUM0RENDQXR3d2dnS2
+|JvQU1DQVFJQ0FnRElNQWtHQnlxR1NNNDQKQkFNd0VqRVFNQTRHQTFVRUF4TUhRMkZ5YkVS
+|VFV6QWVGdzA1T1RBNE1UY3dNVEV3TkRsYUZ3MHpPVEV5TXpFeU16VTVOVGxhTUJNeApFVE
+|FQQmdOVkJBTVRDRUZzYVdObFJGTlRNSUlCdGpDQ0FTc0dCeXFHU000NEJBRXdnZ0VlQW9H
+|QkFJR056ZTJENmdxZU9UN0NTQ2lqCjVFZVQzUTdYcUE3c1U4V3JoQWhQLzVUaGMwaCtETm
+|J6UkVqUi9wK3ZwS0dKTCtIWk1NZzIzaitidjdkTTNGOXBpdVIxMERjTWtRaVYKbTk2blh2
+|bjg5Sjh2M1VPb2kxVHhQN0FIQ0VkTlhZakR3N1d6NDFVSWRkVTVkaERFZUwzL25iQ0Vsem
+|Z5NUZFYnRlUUpsbHp6Zmx2YgpBaFVBNGtlbUdrVm11QlBHMm8rNE55RXJZb3YzazgwQ2dZ
+|QW1PTkFVaVRLcU9mcytiZGxMV1dwTWRpTTVCQUkxWFBMTEdqRERIbEJkCjNadFo0czJxQl
+|QxWXdIdWlOcmh1QjY5OWlrSWxwL1IxejBvSVhrcytrUGh0NnB6SklZbzdkaFRwemk1ZG93
+|Zk5JNFc0THpBQmZHMUoKaVJHSk5rUzkrTWlWU2xOV3RlTDVjK3dhWVRZZkVYL0N2ZTNSVV
+|ArWWRNTFJnVXBnT2JvMk9RT0JoQUFDZ1lCYzQ3bGFkUlNXQzZsNgozZU0vcWV5c1h0eTl0
+|eE1STktZV2lTZ1JJOWswaG1kMWRSTVNQVU5iYitWUnYvcUo4cUliUGlSOVBRZU5XMlBJdT
+|BXbG9FcmpoZGJPCkJvQS82Q04rR3ZJa3ExTWF1Q2NOSHU4SXYyWVVnRnhpckdYNkZZdnh1
+|elRVMHBZMzltRkhzc1F5aFBCK1FVRDlScWRqVGpQeXBlTDAKOG9QbHVLT0JnVEIvTUF3R0
+|ExVWRFd0VCL3dRQ01BQXdEZ1lEVlIwUEFRSC9CQVFEQWdiQU1COEdBMVVkSXdRWU1CYUFG
+|SEJFUG9JdQpiNGZlU3ROMTR6MGd2RU1yay9FZk1CMEdBMVVkRGdRV0JCUytiS0d6NDhIMz
+|dVTndwTTRUQWVMOTQ1Zit6VEFmQmdOVkhSRUVHREFXCmdSUkJiR2xqWlVSVFUwQmxlR0Z0
+|Y0d4bExtTnZiVEFKQmdjcWhrak9PQVFEQXpBQU1DMENGRlVNcEJrZlFpdUpjU0l6allOcX
+|RUMW4KYTc5RkFoVUFuMkZUVWxRTFhMTGQydWQySGVJUVVsdERYcjB4WXpCaEFnRUJNQmd3
+|RWpFUU1BNEdBMVVFQXhNSFEyRnliRVJUVXdJQwpBTWd3QndZRkt3NERBaG93Q1FZSEtvWk
+|l6amdFQXdRdU1Dd0NGRDFjU1c2TElVRnplWGxlM1lJNVNLU0Jlci9zQWhRbUNxN3MvQ1RG
+|CkhPRWpnQVNlVWpiTXB4NWc2QT09Cg==
+|<4.9.eml
+
+***4.10.bin***
+
+|* Example 4.10.bin
+|>4.10.bin
+|MIIH/wYJKoZIhvcNAQcCoIIH8DCCB+wCAQExCTAHBgUrDgMCGjArBgkqhkiG9w0BBwGgHg
+|QcVGhpcyBpcyBzb21lIHNhbXBsZSBjb250ZW50LqCCAuAwggLcMIICm6ADAgECAgIAyDAJ
+
+
+
+Hoffman, Ed.                 Informational                    [Page 131]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|BgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MwHhcNOTkwODE3MDExMDQ5WhcNMzkxMj
+|MxMjM1OTU5WjATMREwDwYDVQQDEwhBbGljZURTUzCCAbYwggErBgcqhkjOOAQBMIIBHgKB
+|gQCBjc3tg+oKnjk+wkgoo+RHk90O16gO7FPFq4QIT/+U4XNIfgzW80RI0f6fr6ShiS/h2T
+|DINt4/m7+3TNxfaYrkddA3DJEIlZvep175/PSfL91DqItU8T+wBwhHTV2Iw8O1s+NVCHXV
+|OXYQxHi9/52whJc38uRRG7XkCZZc835b2wIVAOJHphpFZrgTxtqPuDchK2KL95PNAoGAJj
+|jQFIkyqjn7Pm3ZS1lqTHYjOQQCNVzyyxowwx5QXd2bWeLNqgU9WMB7oja4bgevfYpCJaf0
+|dc9KCF5LPpD4beqcySGKO3YU6c4uXaMHzSOFuC8wAXxtSYkRiTZEvfjIlUpTVrXi+XPsGm
+|E2HxF/wr3t0VD/mHTC0YFKYDm6NjkDgYQAAoGAXOO5WnUUlgupet3jP6nsrF7cvbcTETSm
+|FokoESPZNIZndXUTEj1DW2/lUb/6ifKiGz4kfT0HjVtjyLtFpaBK44XWzgaAP+gjfhryJK
+|tTGrgnDR7vCL9mFIBcYqxl+hWL8bs01NKWN/ZhR7LEMoTwfkFA/UanY04z8qXi9PKD5bij
+|gYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBRwRD6CLm
+|+H3krTdeM9ILxDK5PxHzAdBgNVHQ4EFgQUvmyhs+PB9+1DcKTOEwHi/eOX/s0wHwYDVR0R
+|BBgwFoEUQWxpY2VEU1NAZXhhbXBsZS5jb20wCQYHKoZIzjgEAwMwADAtAhRVDKQZH0IriX
+|EiM42DarU9Z2u/RQIVAJ9hU1JUC1yy3drndh3iEFJbQ169MYIEyTCCBMUCAQEwGDASMRAw
+|DgYDVQQDEwdDYXJsRFNTAgIAyDAHBgUrDgMCGqCCBF8wGAYJKoZIhvcNAQkDMQsGCSqGSI
+|b3DQEHATAjBgkqhkiG9w0BCQQxFgQUQGrsCFJ5um4WAi2eBinAIpaH3UgwOAYDKqszMTEE
+|L1RoaXMgaXMgYSB0ZXN0IEdlbmVyYWwgQVNOIEF0dHJpYnV0ZSwgbnVtYmVyIDEuMD4GCy
+|qGSIb3DQEJEAIEMS8wLQwgQ29udGVudCBIaW50cyBEZXNjcmlwdGlvbiBCdWZmZXIGCSqG
+|SIb3DQEHATBKBgkqhkiG9w0BCQ8xPTA7MAcGBSoDBAUGMDAGBioDBAUGTQQmU21pbWUgQ2
+|FwYWJpbGl0aWVzIHBhcmFtZXRlcnMgYnVmZmVyIDIwbQYLKoZIhvcNAQkQAgIxXjFcAgEB
+|BgcqAwQFBgcIExtUSElTIElTIEEgUFJJVkFDWSBNQVJLIFRFU1QxMTAvgAgqAwQFBgeGeK
+|EjEyFUSElTIElTIEEgVEVTVCBTRUNVUklUWS1DQVRFR09SWS4wbwYLKoZIhvcNAQkQAgox
+|YDBeBgUqAwQFBgQrQ29udGVudCBSZWZlcmVuY2UgQ29udGVudCBJZGVudGlmaWVyIEJ1Zm
+|ZlcgQoQ29udGVudCBSZWZlcmVuY2UgU2lnbmF0dXJlIFZhbHVlIEJ1ZmZlcjBzBgsqhkiG
+|9w0BCRACCzFkoGIwWjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDVVTIEdvdmVybm1lbnQxET
+|APBgNVBAsTCFZEQSBTaXRlMQwwCgYDVQQLEwNWREExEjAQBgNVBAMTCURhaXN5IFJTQQIE
+|ClVEMzCB/AYLKoZIhvcNAQkQAgMxgewwgekwgeYEBzU3MzgyOTkYDzE5OTkwMzExMTA0ND
+|MzWqGByTCBxqRhMF8xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1VUyBHb3Zlcm5tZW50MREw
+|DwYDVQQLEwhWREEgU2l0ZTEMMAoGA1UECxMDVkRBMRcwFQYDVQQDEw5CdWdzIEJ1bm55IE
+|RTQaRhMF8xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1VUyBHb3Zlcm5tZW50MREwDwYDVQQL
+|EwhWREEgU2l0ZTEMMAoGA1UECxMDVkRBMRcwFQYDVQQDEw5FbG1lciBGdWRkIERTQTCCAQ
+|IGCyqGSIb3DQEJEAIJMYHyMIHvMXICAQEGByoDBAUGBwkTJkVRVUlWQUxFTlQgVEhJUyBJ
+|UyBBIFBSSVZBQ1kgTUFSSyBURVNUMTwwOoAIKgMEBQYHhnihLhMsRVFVSVZBTEVOVCBUSE
+|lTIElTIEEgVEVTVCBTRUNVUklUWS1DQVRFR09SWS4xeQIBAQYHKgMEBQYHChMtRVFVSVZB
+|TEVOVCBUSElTIElTIEEgU0VDT05EIFBSSVZBQ1kgTUFSSyBURVNUMTwwOoAIKgMEBQYHhn
+|ihLhMsRVFVSVZBTEVOVCBUSElTIElTIEEgVEVTVCBTRUNVUklUWS1DQVRFR09SWS4wCQYH
+|KoZIzjgEAwQvMC0CFQC8MzdlxPdwXBdJE6pMhcq7UpFIWQIUY5aiFIvPV96wSF9sZN2EBE
+|lfHMo=
+|<4.10.bin
+
+***4.11.bin***
+
+|* Example 4.11.bin
+|>4.11.bin
+|MIIGiAYJKoZIhvcNAQcCoIIGeTCCBnUCAQExADALBgkqhkiG9w0BBwGgggV/MIICmzCCAl
+|qgAwIBAgIBATAJBgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MwHhcNOTkwODE2MjI1
+|MDUwWhcNMzkxMjMxMjM1OTU5WjASMRAwDgYDVQQDEwdDYXJsRFNTMIIBtzCCASsGByqGSM
+|44BAEwggEeAoGBALZJGD6KRMEpcZRMAcQSwXp5y1RNqx6B+8ZMsw6UCQbrAdSxyHFLx0XA
+
+
+
+Hoffman, Ed.                 Informational                    [Page 132]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+|UCVdnPza5G3T4oZIhIJ9uhWVShb2Ru3d9pjSu36KCoq6Fnu5UAFIk4vrJRVRl1Xcj1MOEK
+|lQ/HC3zTBU/dreqKoitaGvi8wCiOeLcF+5reEI1G0pLdbpAhUA3cEv31POCzRgdz4CpL+K
+|XZi5ENUCgYAM7lebS73atgdqdDdPVX+d7bxhDetGWTxWCytbDJHOpWJSacrhbT69v/7ht7
+|krYTyty65F4wasjCKdnESHC8fN8BzZtU5dc96vDskdWlH1T0R5NVpzqn9GUR+pQhacSOuK
+|eWG01S9TIkRjH4a4o1gGJfgpwO+64HXwQsRjZVKbCgOBhQACgYEAmYd0JwNmoLHArdwsdb
+|vhbESc2iFtTUdtsWIJ6diuHvI6tJSxo456m3FOAJTJtCVOuWCWGSQB82IM/nXA+87YaADj
+|/dVwT98jlhkGlPSxYY86V7EIEaQLJiXwUnaB6gtiDZUq5oa6crKnUIMLqifNG6lNiZrXjR
+|g5hD+LxVZNgHqjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1Ud
+|DgQWBBRwRD6CLm+H3krTdeM9ILxDK5PxHzAJBgcqhkjOOAQDAzAAMC0CFGup8E56Wnnj+b
+|49K8kGN+kRF6ETAhUAjzRpKouxPAN5lDJNEh/OiftGsjswggLcMIICm6ADAgECAgIAyDAJ
+|BgcqhkjOOAQDMBIxEDAOBgNVBAMTB0NhcmxEU1MwHhcNOTkwODE3MDExMDQ5WhcNMzkxMj
+|MxMjM1OTU5WjATMREwDwYDVQQDEwhBbGljZURTUzCCAbYwggErBgcqhkjOOAQBMIIBHgKB
+|gQCBjc3tg+oKnjk+wkgoo+RHk90O16gO7FPFq4QIT/+U4XNIfgzW80RI0f6fr6ShiS/h2T
+|DINt4/m7+3TNxfaYrkddA3DJEIlZvep175/PSfL91DqItU8T+wBwhHTV2Iw8O1s+NVCHXV
+|OXYQxHi9/52whJc38uRRG7XkCZZc835b2wIVAOJHphpFZrgTxtqPuDchK2KL95PNAoGAJj
+|jQFIkyqjn7Pm3ZS1lqTHYjOQQCNVzyyxowwx5QXd2bWeLNqgU9WMB7oja4bgevfYpCJaf0
+|dc9KCF5LPpD4beqcySGKO3YU6c4uXaMHzSOFuC8wAXxtSYkRiTZEvfjIlUpTVrXi+XPsGm
+|E2HxF/wr3t0VD/mHTC0YFKYDm6NjkDgYQAAoGAXOO5WnUUlgupet3jP6nsrF7cvbcTETSm
+|FokoESPZNIZndXUTEj1DW2/lUb/6ifKiGz4kfT0HjVtjyLtFpaBK44XWzgaAP+gjfhryJK
+|tTGrgnDR7vCL9mFIBcYqxl+hWL8bs01NKWN/ZhR7LEMoTwfkFA/UanY04z8qXi9PKD5bij
+|gYEwfzAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBRwRD6CLm
+|+H3krTdeM9ILxDK5PxHzAdBgNVHQ4EFgQUvmyhs+PB9+1DcKTOEwHi/eOX/s0wHwYDVR0R
+|BBgwFoEUQWxpY2VEU1NAZXhhbXBsZS5jb20wCQYHKoZIzjgEAwMwADAtAhRVDKQZH0IriX
+|EiM42DarU9Z2u/RQIVAJ9hU1JUC1yy3drndh3iEFJbQ169oYHbMIHYMIGZMAkGByqGSM44
+|BAMwEjEQMA4GA1UEAxMHQ2FybERTUxcNOTkwODI3MDcwMDAwWjBpMBMCAgDIFw05OTA4Mj
+|IwNzAwMDBaMBMCAgDJFw05OTA4MjIwNzAwMDBaMBMCAgDTFw05OTA4MjIwNzAwMDBaMBMC
+|AgDSFw05OTA4MjIwNzAwMDBaMBMCAgDUFw05OTA4MjQwNzAwMDBaMAkGByqGSM44BAMDLw
+|AwLAIUfmVSdjP+NHMX0feW+aDU2G1cfT0CFAJ6W7fVWxjBz4fvftok8yqDnDWhMQA=
+|<4.11.bin
+
+***5.1.bin***
+
+|* Example 5.1.bin
+|>5.1.bin
+|MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYDVQQDEwdDYX
+|JsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUABIGAC3EN5nGIiJi2lsGP
+|cP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FBs3IWg+f6KgCLx3M1eCbWx8+MDFbbpX
+|adCDgO8/nUkUNYeNxJtuzubGgzoyEd8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652j
+|KKHRLFf02hosdR8wQwYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8
+|Z9P43LrY4OxUk660cu1lXeCSFOSOpOJ7FuVyU=
+|<5.1.bin
+
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 133]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+***5.2.bin***
+
+|* Example 5.2.bin
+|>5.2.bin
+|MIIBZQYJKoZIhvcNAQcDoIIBVjCCAVICAQIxggEAMIG9AgEAMCYwEjEQMA4GA1UEAxMHQ2
+|FybFJTQQIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQEFAASBgJQmQojGi7Z4IP+C
+|VypBmNFoCDoEp87khtgyff2N4SmqD3RxPx+8hbLQt9i3YcMwcap+aiOkyqjMalT03VUC0X
+|BOGv+HYI3HBZm/aFzxoq+YOXAWs5xlGerZwTOc9j6AYlK4qXvnztR5SQ8TBjlzytm4V7zg
+|+TGrnGVNQBNw47Ewoj4CAQQwDQQLTWFpbExpc3RSQzIwEAYLKoZIhvcNAQkQAwcCAToEGH
+|cUr5MSJ/g9HnJVHsQ6X56VcwYb+OfojTBJBgkqhkiG9w0BBwEwGgYIKoZIhvcNAwIwDgIC
+|AKAECJwE0hkuKlWhgCBeKNXhojuej3org9Lt7n+wWxOhnky5V50vSpoYRfRRyw==
+|<5.2.bin
+
+***5.3.eml***
+
+|* Example 5.3.eml
+|>5.3.eml
+|TUlNRS1WZXJzaW9uOiAxLjAKTWVzc2FnZS1JZDogPDAwMTAzMTEyMDA1MjAzLjAwMzQ5QG
+|FteWVtaWx5LmlnLmNvbT4KRGF0ZTogVHVlLCAzMSBPY3QgMjAwMCAxMjowMDo1MiAtMDYw
+|MCAoQ2VudHJhbCBTdGFuZGFyZCBUaW1lKQpGcm9tOiBVc2VyMQpUbzogVXNlcjIKU3Viam
+|VjdDogRXhhbXBsZSA1LjMKQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9wa2NzNy1taW1l
+|OwoJbmFtZT1zbWltZS5wN207CglzbWltZS10eXBlPWVudmVsb3BlZC1kYXRhCkNvbnRlbn
+|QtVHJhbnNmZXItRW5jb2Rpbmc6IGJhc2U2NApDb250ZW50LURpc3Bvc2l0aW9uOiBhdHRh
+|Y2htZW50OyBmaWxlbmFtZT1zbWltZS5wN20KCk1JSUJIZ1lKS29aSWh2Y05BUWNEb0lJQk
+|R6Q0NBUXNDQVFBeGdjQXdnYjBDQVFBd0pqQVNNUkF3RGdZRFZRUURFd2REWVhKc1VsTkIK
+|QWhCR05HdkhnQUJXdkJIVGJpN05YWEhRTUEwR0NTcUdTSWIzRFFFQkFRVUFCSUdBQzNFTj
+|VuR0lpSmkybHNHUGNQMmlKOTdhNGU4awpiS1F6MzZ6ZzZaMmkweXg2ellDNG1aN21YN0ZC
+|czNJV2crZjZLZ0NMeDNNMWVDYld4OCtNREZiYnBYYWRDRGdPOC9uVWtVTlllTnhKCnR1en
+|ViR2d6b3lFZDhDaDRIL2RkOWdkelRkK3RhVEVnUzBpcGRTSnVObmtWWTQvTTY1MmpLS0hS
+|TEZmMDJob3NkUjh3UXdZSktvWkkKaHZjTkFRY0JNQlFHQ0NxR1NJYjNEUU1IQkFndGFNWH
+|BSd1pSTllBZ0RzaVNmOFo5UDQzTHJZNE94VWs2NjBjdTFsWGVDU0ZPU09wTwpKN0Z1VnlV
+|PQoK
+|<5.3.eml
+
+***6.0.bin***
+
+|* Example 6.0.bin
+|>6.0.bin
+|MF4GCSqGSIb3DQEHBaBRME8CAQAwBwYFKw4DAhowKwYJKoZIhvcNAQcBoB4EHFRoaXMgaX
+|Mgc29tZSBzYW1wbGUgY29udGVudC4EFEBq7AhSebpuFgItngYpwCKWh91I
+|<6.0.bin
+
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 134]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+***7.1.bin***
+
+|* Example 7.1.bin
+|>7.1.bin
+|MFcGCSqGSIb3DQEHBqBKMEgCAQAwQwYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAiza2v7Yj
+|EIToAg+vzt2z8YFx04iRHqNNYg2/TD2VgV75M7mvXXBPa1cOI=
+|<7.1.bin
+
+***7.2.bin***
+
+|* Example 7.2.bin
+|>7.2.bin
+|MIGVBgkqhkiG9w0BBwaggYcwgYQCAQIwQwYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgHJy
+|CFkJ6wfoAg0iCPZ0iKy0HkImhdvncFUibt4wG9AJFYpzVuvEuiBzOhOjA4BgMqqzMxMQQv
+|VGhpcyBpcyBhIHRlc3QgR2VuZXJhbCBBU04gQXR0cmlidXRlLCBudW1iZXIgMS4=
+|<7.2.bin
+
+C.  Acknowledgements
+
+   Blake Ramsdell, Jim Schaad, and John Pawling contributed the vast
+   majority of the examples in this document, and/or correct examples
+   during the early versions of this document.  Additional examples came
+   from many people, including Rob Colestock and Paul Hoffman.
+   Additional testing came from Holger Ebel and Russ Housley.
+
+   The examples are displayed with a modified version of Peter Gutmann's
+   "dumpasn1" program.  Peter and Jim Schaad and Blake Ramsdell have
+   been updating the program based on input from the process of writing
+   this draft.
+
+Editor's Address
+
+   Paul Hoffman
+   Internet Mail Consortium
+   127 Segre Place
+   Santa Cruz, CA  95060 USA
+
+   EMail: phoffman@imc.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 135]
+
+RFC 4134              Examples of S/MIME Messages              July 2005
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2005).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at ietf-
+   ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+Hoffman, Ed.                 Informational                    [Page 136]
+
diff --git a/crypto/test/data/rsa3/self-testcase-A.p12 b/crypto/test/data/rsa3/self-testcase-A.p12
new file mode 100644
index 000000000..79fe2f2fd
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-A.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-A.pem b/crypto/test/data/rsa3/self-testcase-A.pem
new file mode 100644
index 000000000..3e507ba9c
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-A.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAC0dXvAI0/fhu22j15YEo
+F8M3OYM8fwlvxs2/qtwELR3hVckpRIJmfGpUutb6/TBPgTS8a/fmzcrxLsL/aGSD
+jH4/TmTHrRmhlT/einuudpAXPxaS27Yz7duxRPmyXeyHy3P0ulXDEzOaZdV8kxQs
+J/v+z0knwdAh91omHRfJuNxDQtLfjp1Qtz+jrBCI6s864UblKXG/AwjWOLFQ1E0N
+A2bDo72tr3aw01gryggFkyNrB9K5/15+jJLVLFjuJfP7m3FUjPfGQB9+eZMBWpNH
+hGcSsPibqWVTDMjN0Z/mTGMzZDsEXX0Ao1K21q5vK1sfFYEahv/PCwkcW1dOeTGF
+pQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-B.p12 b/crypto/test/data/rsa3/self-testcase-B.p12
new file mode 100644
index 000000000..ef5013228
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-B.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-B.pem b/crypto/test/data/rsa3/self-testcase-B.pem
new file mode 100644
index 000000000..6c449109a
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-B.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAIYpxwPMRRjPuRBsWKhB0
+ACZHEaO6RtSwu28sHO2TF1o0kHONAnqR37OhMuPR70qBynd5dVDkjpxXUfxhLDPh
+jdaxXuj2vMrbAvDJFsIsKDatlc632IsicSR4DVEnpJmUtLBQFC2VylHMxkGoo5eJ
+dsf5ZY/QqUXf+VReLWfyQXEaSGe8nI7fP61xqTsgzcN4ziqkKSKGvsEtPU/oo23Y
+xZDJpRMPdzu7TqkP3PnzRFy6HUamM2Xpyl2qeYELtGu7nuoSaF/1AX21bPtU9N9N
++wbxlGuq7NVIKdlIaoQ3FfgCVZGrVwjr7uxow7Gob+pWJJKjOS+IlSRL0MqH1t/U
+yQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-C.p12 b/crypto/test/data/rsa3/self-testcase-C.p12
new file mode 100644
index 000000000..72527d634
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-C.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-C.pem b/crypto/test/data/rsa3/self-testcase-C.pem
new file mode 100644
index 000000000..f844ee47f
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-C.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAkWkqxLQH4vvX5e2oiydv
+VN8Et+ZznJ78yifF7Tctjm9+EfEBRupHwXHlAZd2n2CsZfhVTqk/Rnffb078X3g5
+9jx9ka0/hhkYyG6XqLybS3yXVpC/mvaeQMRu0Ubi0uSOkcf6rYiaqGjcG5DRaSAz
+SNNrDTEDYNxsuaPJoxZtQ+o1VaB3ksJ2UanzAHy45IJKXlSWS4l0Xsu6NZJxeMLB
+0iL0j5+TcaK37dkNpDi4dhFbeOi30Q8rvC5BDorFMM8GEl+GevH6Rpk0P67WlnOY
+qeDoKjzKi1w0ZDBS8XI95DLsmnHXcg2Iu8Dx1iBJMFST6mLtsMdVQAD+y2NTkbpM
+xA==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-D.p12 b/crypto/test/data/rsa3/self-testcase-D.p12
new file mode 100644
index 000000000..c2fa40bb5
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-D.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-D.pem b/crypto/test/data/rsa3/self-testcase-D.pem
new file mode 100644
index 000000000..6f93f1c06
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-D.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAkSFw/c7vnAAs4wKzS24X
+oyJrIiazcZD4A2ioqWMQD+QxFJlplJsyE5vcyVxv5Pww5Od1aPJCsSEd/C7h12eA
+576kkQcbv5KQ8LUlpj6eRjzI4E97yc9Yi9C3YibniGCv5mxLpw2bOxix9l8EBj6h
+vTfDMdoQVXkGyI2TCbYppkffJgxrL/wj82XbYeIHL27REf4+bNVRYD3LMXl7koPc
+4vUC6lyxYUELfv6UnAzppqDl+LSUkKvQEe26syIUAE3ArGvy/aYjIYBCwQQu4r9H
+WnXdIvcTdZqi3x9z/aN8Or9/IYIXpk3td6lLqI/DUwkPRS6zcthDo3x/1IFhUCB3
+KQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-E.p12 b/crypto/test/data/rsa3/self-testcase-E.p12
new file mode 100644
index 000000000..026564215
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-E.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-E.pem b/crypto/test/data/rsa3/self-testcase-E.pem
new file mode 100644
index 000000000..0c30777de
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-E.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAkFwewElSyXCGG2ygI3I4
+iYLtjAJAy002ES4JGHvr39dNhYoZ1poop18AU52mrx+SKX5vc/hAipisVa0rK9Jl
+91GF5NQdhU0KWxNCBHZAy3dUf1M63jvTC3eiG8LVV+C77Cx936i8qO5f3qWCN40z
+4W8eMwkCoVtpfzuuHk1by0VwCgU5IYuNIrwxR1bjudOctyhXNJjgr3SIsjDrqpTA
+nS4AauNFVqFfSyyaw5AX+7eA/WrMOGdJBJT1bEhHqrWxLtQzwSzKBKu7FpuF3mVX
+SHcSW4AzA6Yzq2Hcedo+SJt96IDr5xT17ncPMBzdq9pdoHlyJVq9+3O5JQOTx1WD
+6g==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-F.p12 b/crypto/test/data/rsa3/self-testcase-F.p12
new file mode 100644
index 000000000..58410dcab
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-F.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-F.pem b/crypto/test/data/rsa3/self-testcase-F.pem
new file mode 100644
index 000000000..fcc520547
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-F.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAaiR5Rnhj/vUqDgVqHaJk
+0VcMuvDzkQVmUlAZlsDa3uH3CW43yAXXM6ahacYnOgpLB96aq6cI8E74hHzO6PU6
+M50LLdp+KWu5InQv7+6fgSpShRxnHBKigCuoLy6oKFkCTTnnK002Mplr8+eHZHbi
+clm+k9rQejNalv+P9GSE5JcIEkTSXUDbfe81/ej9DCOcGbFPuL5hFQ8GNIuf+uv2
+OKXQtdpuayFZnD3hoWYE1LMT5W1lK1Jewx03phYeCMAY+MibRhzXWLDMBiwXpvW8
+cgCv777p+tRedunb5eLF+FT+/r617rskD9i9mJjqvoxQaXaYe++UX5mt9xpXZ9oM
+1g==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-G.p12 b/crypto/test/data/rsa3/self-testcase-G.p12
new file mode 100644
index 000000000..c8184a252
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-G.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-G.pem b/crypto/test/data/rsa3/self-testcase-G.pem
new file mode 100644
index 000000000..d10c2283b
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-G.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAoLujmlhRD05T4G8CQa+g
+kIW/l43pazV1+iWaPnADd3/ywX7BNrVkGDaJHPci1BBq8lsiIA9nu7Gfxjl9TsZe
+wwLzZ/LxI9tTR+ikYxy0MID+x45rk1dF0nnya9S3wQAXDhP8ZKN0d8ezvbQ2N2LG
+74YPAtQZngMLMvYlG6MgoDNYOHHDkYZ6uL8PEwU9DtlZ+JPwxI7o7/E/T3XdDpvI
+UcI15axKbD5QMqGQxZwgQYFVMDvKou1upkLQ6ymHYgEzSqNNSzTYVdhVrGgTX+xl
+VZQFdJqR/gkloXbzxC/WqFTGrX1WN6kMvL+ZnVEh7DWELPmLFMfoWYCd4Q2hIjdx
+MQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-H.p12 b/crypto/test/data/rsa3/self-testcase-H.p12
new file mode 100644
index 000000000..b38c9eb71
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-H.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-H.pem b/crypto/test/data/rsa3/self-testcase-H.pem
new file mode 100644
index 000000000..0cab07503
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-H.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAPaezAGexMlsmptKQBlrV
+iTDBKfTs555wM05d0CRzd6dq9GHYNk/BMPy0mPmpxLwuyQqjB3rw9+mlGre1jcLf
+Kthaz+Vna1yIGqg5dqqdu7NUX6/8x51hKQ+8B3rmlqx3wjt+bWgo2Qgl8otrHXKY
+EWrKfmTNd3z0+nklqaLFvxmQwQ33CKciw6k9A2O3DaOdf1smCfFyjF/hi4I0pJaX
+vFB/CbCAF/zVmQW+uXMNooZmd+DcKsK5ZN6LzxDXC6iqqaN0WS1kmctjYQ4pOomg
+5pdKfv+gUwUqUTbtL2/WeyuOcHY9XLluYk+nwtdFS25uQpmHZcQ4baeKB5N9IJy8
+jg==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-I.p12 b/crypto/test/data/rsa3/self-testcase-I.p12
new file mode 100644
index 000000000..7b97f68d6
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-I.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-I.pem b/crypto/test/data/rsa3/self-testcase-I.pem
new file mode 100644
index 000000000..8717fd869
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-I.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAJanu4ytjXr/ppQEiEsJ3
+1TqGBIoASHHWZsjd4DZmigBgERJqtXK/AsTsljFrSo1lhP3Q9TFqOeikvJ5T3y4q
+8yYY5qaEICsjUuySTIT3r7O00O5mtpdnpsRkBceqvBDDqfWefau00SVoBaqmt2P+
+Bq3x4l7MYqJNI8fPNVHqhSBlnWfxgYO/GZd4ZshhOZgrb96B98XpRlD5uYSlTpJt
+cYvSb2s+BX4RCZIGSpoQJ0dgz3uU5H5i949fbuTbyGLVka0t8gvWN0IPoSPEp3Zj
+mEw5Oz2UV0/R0qF2/yeKKNH3aFMEAzYUAmVqA5OdWiiZgLYcIm6pQvT0iAtgnT9x
+rQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-J.p12 b/crypto/test/data/rsa3/self-testcase-J.p12
new file mode 100644
index 000000000..4073ea600
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-J.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-J.pem b/crypto/test/data/rsa3/self-testcase-J.pem
new file mode 100644
index 000000000..c3fba7935
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-J.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEADFGQ9QEI1TU+qRg2QFLZ
+OhYryOaAXNOaEBR+f0LCG5My9j0vI3/1BKHwq6kVPVDkfSPrrX1ZNUPOAI+PLrwI
+RGsJw6ST8dyWXeY4LEarHOPLvSTD2u+WaPcRMJSsSTFnsscKgrAeu4VfZixOTpBp
+tI3bfqTPkY9Fra8R1M9PbNsPik0WI34nPS0T9XqF+s/FhHCcL/mX/Hj5aD0qEZWd
+wCSJGDyoZRQeMc7LowMGHpu1eqcqfSLt2TCPeXebVB031AioCe1iJUddb9WxHixH
+GyNlzJl7YwztT9Z3yRqHKde6Dun128N2YThQ/7/Dn54hXcWQCK4gFCTz2deD5S9Z
+TQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/self-testcase-L.p12 b/crypto/test/data/rsa3/self-testcase-L.p12
new file mode 100644
index 000000000..50b3b76f2
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-L.p12
Binary files differdiff --git a/crypto/test/data/rsa3/self-testcase-L.pem b/crypto/test/data/rsa3/self-testcase-L.pem
new file mode 100644
index 000000000..b9805f5b0
--- /dev/null
+++ b/crypto/test/data/rsa3/self-testcase-L.pem
@@ -0,0 +1,52 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBsMQswCQYDVQQGEwJHQjES
+MBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N
+eSBDb21wYW55IEx0ZDEKMAgGA1UECxMBYTESMBAGA1UEAxMJbG9jYWxob3N0MB4X
+DTA2MDkxMzE4MjYzMloXDTA3MDkxMzE4MjYzMlowbDELMAkGA1UEBhMCR0IxEjAQ
+BgNVBAgTCUJlcmtzaGlyZTEQMA4GA1UEBxMHTmV3YnVyeTEXMBUGA1UEChMOTXkg
+Q29tcGFueSBMdGQxCjAIBgNVBAsTAWExEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKtexL4ZP1CWMsVedm+pD2xPG+md
+VbRqkVSDQYxrHUyRVKletjluY95908bsAlJR9oK/YehXe9W7r+LnotaR+yy1P45g
+hSWa6TNl1sz3NGIZwdU9WdqdNNs9YyDgzFezxzZffrh9xFTSF0CR66Tm1VasKa20
+69RTx4fE5n4kZx+DKfBGCX3PBprvIANZp0nrfuhf21ij9lORI9OkITwqR72PrybB
+9QDZB+7og1jGLAGbRBNR61mLVfKrg2yJVhpk1dHPsUzeVr3BB5XK8i7DvflWw5di
+PeyU4S7qm7WLZ9Wdg1XOchkQWmzqEUPG71dGzG6joPhdp56LFg2Yg58myRcCAwEA
+AaOByTCBxjAdBgNVHQ4EFgQUPd6mAcGQZ8iNGajt0kffN4AeDZswgZYGA1UdIwSB
+jjCBi4AUPd6mAcGQZ8iNGajt0kffN4AeDZuhcKRuMGwxCzAJBgNVBAYTAkdCMRIw
+EAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15
+IENvbXBhbnkgTHRkMQowCAYDVQQLEwFhMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAw
+DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOCAQEAoArZH56QUnasmPqCd68C
+kcG6hw5S6p7wloY9jz+iwh9b2tF3k1SPCeE7rBV7cevr1ruv/wWttBFiGfJK/hlL
+8C/MMPj1X5JuLY3JgNmNDSK9MLr5Ejvps0AQ+kA4CCSxxpTLWeUlqNnGk/Zcfoqa
+Gyk37PDlHMQC3QWLgAX+wG/rg8WvrAP1ZjM6t25yb6hIPZgCWZbq+j8X5kS3Qxz0
+buc9HMi9oeuejeP7zWRJHhnCcDuClmpI6pk9nkjmunYtF2rMWi7f2eJ0Qjbo1wnn
+rUU5sCGLZ6i3ux/HvMgynho7RVqV+bqV+G9wZem3crNbtLhUSB2SAgYZnMqrLcW9
+jQ==
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAq17Evhk/UJYyxV52b6kPbE8b6Z1VtGqRVINBjGsdTJFUqV62
+OW5j3n3TxuwCUlH2gr9h6Fd71buv4uei1pH7LLU/jmCFJZrpM2XWzPc0YhnB1T1Z
+2p002z1jIODMV7PHNl9+uH3EVNIXQJHrpObVVqwprbTr1FPHh8TmfiRnH4Mp8EYJ
+fc8Gmu8gA1mnSet+6F/bWKP2U5Ej06QhPCpHvY+vJsH1ANkH7uiDWMYsAZtEE1Hr
+WYtV8quDbIlWGmTV0c+xTN5WvcEHlcryLsO9+VbDl2I97JThLuqbtYtn1Z2DVc5y
+GRBabOoRQ8bvV0bMbqOg+F2nnosWDZiDnybJFwIDAQABAoIBAGA8GNn0DaUwo5RI
+htQPqVSWXENlklJ9od1G1FGJeWudFWEDietYfYbdPEcyE9+snXUxCkdSkX0mKBCR
+KdW7JsUlh2pp83t5scmmP+jcTbNlaX9ZM5Nbwun3YCp/cuExWQbEu8HZBp7nWB1v
+lFgHNPi2N7WPqvuSjLNGtHVT9gEwWGUl1zfbuZp8pNT4r1l7nwj+S9pGF3v5RXDt
+qZWSbfPF3ESPkMOpXxGk5uDLx3aoeHBQALVjeNdVlkyxjrG75Pv7ZnrmXjXzcuVv
+aVACiCPWxzaRFR9cRCx/Z34KrJorLglrfIPIrRMKJY33QO2gpYYEpFkLsLth/Ip4
+NMSJ3KkCgYEA36skUOFK0iQcdEaUXR2zcvQd3P3ctxe0JqD7dHFWnY2ndA5+VvAP
+vUjemZgw+tNt1qjLCAwxMi4cEOEICG6zSlMBRcVbqkKPS3gd3fGvD/lfQZ02EePz
+6KYVC7xz1WXIcId/HvkBNmbPEyOLqi9fIJQoYrM3LnB3AFIUqQ4K3UMCgYEAxCRT
+Z6yLGFb6Evkvvc6usqDhpAjWaaTSxlsSf9IGsKXW90OronB1IiTaWgJze1PrwWy4
+z4YOSI8oEEpF7LdwI9hztg9wFGht8lahGkfHtgR7V/QzyLMYfcU/57STI9vvsw2S
+FNqIdeP1Bd/CE8iI6o6HOAadsWlTBBUBUtnZnZ0CgYA/ecthpL5eKt9kZE9gqbgu
+rHb5K5aC45g9yjvyjOO+7N+UATT7qT9eQZrizh1AYdZvMBIGo6cmjY1rgOGNuxTo
+x+u5iEv+YstV6K3ZOeiryOKutVYN97pV0SRx4zagXjVnMhzyhkpAzSaBUPom/zCp
+B0L618+WP1aWYbT5UUHmDwKBgA3Ju+86yuBgJN42lCuUnuVBt/rvABuXEZYOCuPf
+YMcEMXNaV3No0mMfEhZnu7R8tsL3IJq+Ar0JCzjx765vSrvKWIAA39EfcjMp8dNG
+HnzmHcGWEhnWtS8KMa7ZG8rWiCgfGRjML/GRn8TU8PCxFSbf9BN1K5qwG7zauSgY
+1lplAoGAfl1Qw77H27TYGMVBgco/2g05MaKb8TZ4PKn1znlPnNcqFEBi779W0/dD
+Zgb1mjnRQkw68Jj5XA2zv/06yjvTS+nHVEDCdgIrZI2p1IrI3F4tihSoWgYtoe+8
+5OVDiHQ73d6lxVLqIRoRic8ZtWR02PbrK5SmoPsFdeTcmtzqo6c=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/rsa3/testcases.README b/crypto/test/data/rsa3/testcases.README
new file mode 100644
index 000000000..648574027
--- /dev/null
+++ b/crypto/test/data/rsa3/testcases.README
Binary files differdiff --git a/crypto/test/data/scrypt/TestVectors.txt b/crypto/test/data/scrypt/TestVectors.txt
new file mode 100644
index 000000000..1b54dd696
--- /dev/null
+++ b/crypto/test/data/scrypt/TestVectors.txt
@@ -0,0 +1,20 @@
+scrypt(“”, “”, 16, 1, 1, 64) =
+77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97
+f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42
+fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17
+e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06
+scrypt(“password”, “NaCl”, 1024, 8, 16, 64) =
+fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe
+7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62
+2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da
+c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40
+scrypt(“pleaseletmein”, “SodiumChloride”, 16384, 8, 1, 64) =
+70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb
+fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2
+d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9
+e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87
+scrypt(“pleaseletmein”, “SodiumChloride”, 1048576, 8, 1, 64) =
+21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81
+ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47
+8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3
+37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4
diff --git a/crypto/test/data/tls/README.txt b/crypto/test/data/tls/README.txt
new file mode 100644
index 000000000..2f456ed68
--- /dev/null
+++ b/crypto/test/data/tls/README.txt
@@ -0,0 +1,8 @@
+The key and certificate .pem files here were generated using GnuTLS certtool and the accompanying template files:
+
+    certtool --generate-privkey > x509-ca-key.pem
+    certtool --generate-privkey > x509-client-key.pem
+    certtool --generate-privkey > x509-server-key.pem
+    certtool --generate-self-signed --load-privkey x509-ca-key.pem --template ca.tmpl --outfile x509-ca.pem
+    certtool --generate-certificate --load-privkey x509-client-key.pem --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem --template client.tmpl --outfile x509-client.pem
+    certtool --generate-certificate --load-privkey x509-server-key.pem --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem --template server.tmpl --outfile x509-server.pem
diff --git a/crypto/test/data/tls/ca.tmpl b/crypto/test/data/tls/ca.tmpl
new file mode 100644
index 000000000..44319d2de
--- /dev/null
+++ b/crypto/test/data/tls/ca.tmpl
@@ -0,0 +1,4 @@
+cn = BouncyCastle TLS Test CA
+ca
+cert_signing_key
+expiration_days = 7300
diff --git a/crypto/test/data/tls/client.tmpl b/crypto/test/data/tls/client.tmpl
new file mode 100644
index 000000000..f7f7e08a5
--- /dev/null
+++ b/crypto/test/data/tls/client.tmpl
@@ -0,0 +1,5 @@
+cn = BouncyCastle Test Client
+tls_www_client
+encryption_key
+signing_key
+expiration_days = 7300
diff --git a/crypto/test/data/tls/keystores/client_store.dsa b/crypto/test/data/tls/keystores/client_store.dsa
new file mode 100644
index 000000000..77c6e47c0
--- /dev/null
+++ b/crypto/test/data/tls/keystores/client_store.dsa
Binary files differdiff --git a/crypto/test/data/tls/keystores/client_store.rsa b/crypto/test/data/tls/keystores/client_store.rsa
new file mode 100644
index 000000000..fb4810331
--- /dev/null
+++ b/crypto/test/data/tls/keystores/client_store.rsa
Binary files differdiff --git a/crypto/test/data/tls/keystores/server_store.dsa b/crypto/test/data/tls/keystores/server_store.dsa
new file mode 100644
index 000000000..819cecd70
--- /dev/null
+++ b/crypto/test/data/tls/keystores/server_store.dsa
Binary files differdiff --git a/crypto/test/data/tls/keystores/server_store.rsa b/crypto/test/data/tls/keystores/server_store.rsa
new file mode 100644
index 000000000..5ade0b7b9
--- /dev/null
+++ b/crypto/test/data/tls/keystores/server_store.rsa
Binary files differdiff --git a/crypto/test/data/tls/server.tmpl b/crypto/test/data/tls/server.tmpl
new file mode 100644
index 000000000..e406c48b4
--- /dev/null
+++ b/crypto/test/data/tls/server.tmpl
@@ -0,0 +1,5 @@
+cn = BouncyCastle Test Server
+tls_www_server
+encryption_key
+signing_key
+expiration_days = 7300
diff --git a/crypto/test/data/tls/x509-ca-key.pem b/crypto/test/data/tls/x509-ca-key.pem
new file mode 100644
index 000000000..b9144d2ba
--- /dev/null
+++ b/crypto/test/data/tls/x509-ca-key.pem
@@ -0,0 +1,32 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIFegIBAAKCATEAzIc3nB+Rux7seSPAeH7Q2CkHwRKRgZRQdmL259ySG7RKZ2N7
+rSaJFhnW02OaF5/GpkkWRT/WSZQQz6wMqKf/1H7idANZ9sA4hR1HDzHNQ4Ou7h+O
+Hxom+fbZzleGtMOMRdfBVYDx/vtlcv2WP1Y0gCHzHVN5854dae+OHbBI06o+HriY
+3MvQgr6VuwNItGbl87ZJDWb3FZ7JAq77hyrIQGaD6HbSFtRuunr2UAhkCCRy8gEg
+In0BXtXPFZSfFOGec0HiXtug4zEReSK2CVpeNyBWKw3xQuMfvRJ1SnRNoPeQ/Zk5
+FgMF/P8uXlszwY+7mri3XN+gj3yXJ+kNLIRsTG5/jo9v5qxfHKvYVwXtHLkSx/Be
+5OsBsc1c8eMIszMrAiiaF2FZxMPQD97kmalzQwIDAQABAoIBMCCrbJ+R5LD+Cd8j
+wye8IgHqiTmMN2p6VWFDrOrGWcmhF81sn6G907c7CLdFY/oSuc7FQpBsglRzGT2t
+iWwbQbXLUBggkkCO3bhYP98ry6eAI54Xs5eWPCmWBkkmbqGgfAnf98V/o6gLYgi8
+fEEWX6vOlcsrvVbDp9vMZGgA85u+cs5sxXC8rEwQw1FW/0hfCKt62i+7hbY8bgCK
+AuWV3y4B8gLxMNybvTKzeUcVhG2Bs8ZzdfP9auVILEsp6CjoqlW1QPsOJ6cJSVek
+3P7k8UyY++IpajMJZ0RxD5+MgqNvrU+F9fdk0W+z8ZW/FFncmtBS/xLAxg9lCicR
+qoiRGy4y/t8vKqtbMmqgev2JxSYYbE7AXD0Pp51hTRKAFASo6VdPh2/LBdXEU3uw
+4cXszskCgZkA3rdK8gg8/wMXjznff/Z3a6K0c5KPGGd+SK/Q4KwND6C0ca9JouVv
+PZ4qbqT++Ye1a5R3S5BSwCx13pNVmVicQQ4xQTCedaaTyhcNu3sClrK5uM4F1G7g
+p5RmUFPZFWODrFpqF39wwjGaUY229+JDI++c3hUfoSNQkLqKwwu0Z4aH/0UIDMy2
+5AbX4/QMvOdosTPDDBa/9rcCgZkA6xgXtiGl4PJ7bBCAtpEZ436qFjJOnhrBoxoP
+iK9wtp5alTrGYj9a0omia2Eg+JVDR2CkSsb5/98phaR0JY9dLFrk60a02YUhQAL8
+unkD0mBBRTuKejl/I31t2OTzUZOqfm7ggL6Jwy4BUkPmQbcKJg9CRs7vjF3lGmBd
+EPGQi+Dj1FnBMBnqWQ5zP2kjMNQ0uHWaHlWTO9UCgZgBnTx60pp2krQqApZfHA8z
+hYNfTxGgcKeWqUePSU/y7AxCwq1688TBopLWKHX8owIqnHHc51fiMrBMA69cJCtF
+wW+T9GFBowpxLYeY80RKiVMVRtD+ACu6qzWuoVzybb03k5QvRWowziE7NBa+ZzJr
+YUI2zdpj1Ziw49k7nqsZEP2NWRe82AL/VhlceplZCShWGHTycnvDswKBmCNkKx2m
+DxzAJEhua5IQYf9XcC+LPz6Z9JCjObdwAd3cFPLmODtOIlQTmDnmE1qYzdoO+Gyx
+a61TYSLXUQzeej5VKKUqrcsZOZozWOyRjzu6ddkAT6Z6xWMIXOMMBH1BZ6dE9dMr
+2/1gDZ7ezekSrxpvraCPQoy1Depcm2YTl5kXL/Ul1elx3U+u1zaykzOknpMuURdD
+9rhJAoGYX90aFh+SHKIc0nLBPCZA1dvvB6Nvwvynyr6pHDYFNZvsNBAqYQpLYgdY
+QRiGIHeUJgdDfuQADaTQy0t7fWuWE1orvK9ywrdXCo9KlstMmSInZ5LlF54wtgpw
+ivt7YjT1ewzxBJz67NdDVDLrOAo32ZTJ/iKUHoqXZGcCCWAtENzv9vRvcSJLIMYt
+bUtLF3QhyUCj7/ASc+Q=
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/tls/x509-ca.pem b/crypto/test/data/tls/x509-ca.pem
new file mode 100644
index 000000000..1639512b8
--- /dev/null
+++ b/crypto/test/data/tls/x509-ca.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAh+gAwIBAgIEUqKcyzANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhC
+b3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTMxMjA3MDM1ODAzWhcNMzMxMjAy
+MDM1ODAzWjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwggFS
+MA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQDMhzecH5G7Hux5I8B4ftDYKQfB
+EpGBlFB2Yvbn3JIbtEpnY3utJokWGdbTY5oXn8amSRZFP9ZJlBDPrAyop//UfuJ0
+A1n2wDiFHUcPMc1Dg67uH44fGib59tnOV4a0w4xF18FVgPH++2Vy/ZY/VjSAIfMd
+U3nznh1p744dsEjTqj4euJjcy9CCvpW7A0i0ZuXztkkNZvcVnskCrvuHKshAZoPo
+dtIW1G66evZQCGQIJHLyASAifQFe1c8VlJ8U4Z5zQeJe26DjMRF5IrYJWl43IFYr
+DfFC4x+9EnVKdE2g95D9mTkWAwX8/y5eWzPBj7uauLdc36CPfJcn6Q0shGxMbn+O
+j2/mrF8cq9hXBe0cuRLH8F7k6wGxzVzx4wizMysCKJoXYVnEw9AP3uSZqXNDAgMB
+AAGjQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4E
+FgQU9mOvr6Pi7+4O5bKxRihqeCkyHukwDQYJKoZIhvcNAQELBQADggExAKyMiFmj
+YxzjXpQBD5dvRI7xZn79vH3lo13XRBXj/sbPXDXWIv21iLfutXn/RGGsq8piPXHG
+5UY3cpZR6gOq6QO1dJ91K0ViAJBFQdkhhtfbhqGY4jvj0vGO6zenG/WrjH26nCT7
+8S4L6ZoF6Y0EfQXluP50vEitTaZ6x/rung9h2JQ8rYKiRRVCA+tgBWK/CNhQ9LXy
+k3GU0mKLik0AkEFS17C0NWePIPEs/Kxv9iTEFacAN9wVHjZcMYnYtWaPNX0LWV8s
+2V2DMJxrmgCEcoXgJxlyEmvyqwpjB+2AiIQVIuWcwPqgBQoKHThT2zJcXV+bMhMs
+6cGvaIdvPxttduQsP349GcmUIlV6zFJq+HcMjfa8hZNIkuGBpUzdRQnu1+vYTkwz
+eVOPEIBZLzg9e2k=
+-----END CERTIFICATE-----
diff --git a/crypto/test/data/tls/x509-client-key.pem b/crypto/test/data/tls/x509-client-key.pem
new file mode 100644
index 000000000..386711f9a
--- /dev/null
+++ b/crypto/test/data/tls/x509-client-key.pem
@@ -0,0 +1,32 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIFewIBAAKCATEA2HMtdpNQ+bHX26BW/haQL42XQKpZb71KRCtUnYVZbYNTriRc
+t9NIs+Ifm7clUH/hLTNE3xYHoBhG/quXl1NwJT7rq4vBZ2m2iHhV3GkV8mhfbIAn
+7Uw64ehw+US/CvvNccX8gA9aCjNqRdqXEcWGwKRoW0D0kEoSXzctCqdo5h0mwcPR
++DVVMwQiFDXS+LkqhL3eF2WsebQhuFiMNi+QShO6vgWIelGvj7kjmEVttEOsRDUx
+HAVtv7kMjmsi7QAyesLmyyFt7RF6BLYZZvVbjyz+Augr+MXmY2noH/ExkKfrhaLv
+dql3qEA1xKNFxi7LLJ8BU1P9jJ1So7nYX4P8Cely6oq/Gee1bPdhLK61K+R/wf9i
+L70krkxud7hmIlmvf0Ma0dHH3HM6dvjYaZ5/JwIDAQABAoIBMCdNzuEbwhX9Tcmj
+VXihJ0CDUQZciI4KTNyRE7Xg24rP0JesIav9sVN8yamQebWi6wQ2rZhm2y6eifG/
+vfCsJY6V3NyTLaT2JL+mPk0eRe51NnKw2M81yvFvsGgLLDe13qn8viuQ3hRBHtid
+Z1ZCTIRZtltvsZkr4icpEURAfwNeIsYHpW6RXK29X+TUm0Ev+oENKzGLdGTK06Xk
+6RRV7a34BIdg+7qVWL4ROzKPHKIrHw/Jmg+775UekvkGfos8Cd2eseHJROhAIje1
+WQTvDzOfx3PiUW9RW9/CKUXNeRtWJVhUG8lfqdKejn1+8CxPzwqgNRJbpGvCFa0R
+oDQ7+3l9ELdcA+sv9Qp2OFXIhagzXlGcC4SwMQrBiz6oK5dDqb7VEjE2igOGrRUZ
+i+7G3lECgZkA2qztgn6CbUhvLEXtiUr1EwX6ZHiB1ZVWjGo8cGmS2wI4/z48Ogln
+IvxnfAF7y9PYdHuNFkwbzFVRRdToLSw0bjkZVVzRodEJexvsK8LJQu2LycKOPO0n
+TLuWmr030wuZyU8ebrfuvdM7qDSSzrUc28+BUkPGiWAQ4lybqppoXtgXFeOLrDvn
+vp4OTkJmphM4eOSn8aPQSHECgZkA/WUAmT+/l+y6q6xo8WqEbvIkVzSfrSG3oXCd
+V40oNhEPHRRDWugq19mkBOMdFWEabAKaZTl1lLfijvs0fN2RIcARVAYrg2IlJvj4
+20/muERs3yM7tX7MgFCAdApgTGBToDy2O2ANdOhgG9KCcmf1D9ZKGnum7WhQHQaD
+3RV+S9LRhVyiIbeQzJxv8ejAaQVJPe99vez+TRcCgZgkLRuVzQwSvDr4HhFv9yCY
+JxMHcBA6n1wUGrco+a474SBAybD5APk5BnywPSaXz9ItYwsyNyEaKrspTFGkt31t
+BrE0OAjONmDVJwdpLe5Rzi6kEDWryqgHv7jonIkRtweYECi+tFsguENUTm5DGB9Q
+FgIU8/VyYJwqdpuiG61Mk38uNdizg62REWDYfY+xxdg/18QY67rXYQKBmGG/UaDM
+T5tKjaPlyUG/hkDKFayyNxpxVEXpjDiW0jkxEXR1OZpazxQe97+O4Mw7fhbGVkrQ
+BISO/s2LJ+83BWJQlh6klqqC9LP4/P6U7vqMIrdc/w5/UGH7K+IXkphD3F6GrQFw
+hyBe95wj84Awi/9E+acHphgU0jqwJbPmM6cKNxrL5hs9lZToj+Jwl7CrglprBUV7
+o4mXAoGZAJZ5BBXWeXf161K/n1hQY9dFLSYHjgv4sZMkDqyNhDpdW9HqJ2XEuscG
+Gf7vaCMEV+iOHFKYBS6XMcRXg+R7VOPRvPBNwQXf1ImcQzTVlerWHwMW+y0NAubd
+IIzAXPMzjcOBBiac2wg3cvBTQE29XJ/hy4Rk6qz/oWaIinYStCelCr1FR/Vw5HzE
+/SYmOzdAkWM9bv3Mp/g2
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/tls/x509-client.pem b/crypto/test/data/tls/x509-client.pem
new file mode 100644
index 000000000..4f2341995
--- /dev/null
+++ b/crypto/test/data/tls/x509-client.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDmjCCAlKgAwIBAgIEUqKc2jANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhC
+b3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTMxMjA3MDM1ODE4WhcNMzMxMjAy
+MDM1ODE4WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBDbGllbnQwggFS
+MA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQDYcy12k1D5sdfboFb+FpAvjZdA
+qllvvUpEK1SdhVltg1OuJFy300iz4h+btyVQf+EtM0TfFgegGEb+q5eXU3AlPuur
+i8FnabaIeFXcaRXyaF9sgCftTDrh6HD5RL8K+81xxfyAD1oKM2pF2pcRxYbApGhb
+QPSQShJfNy0Kp2jmHSbBw9H4NVUzBCIUNdL4uSqEvd4XZax5tCG4WIw2L5BKE7q+
+BYh6Ua+PuSOYRW20Q6xENTEcBW2/uQyOayLtADJ6wubLIW3tEXoEthlm9VuPLP4C
+6Cv4xeZjaegf8TGQp+uFou92qXeoQDXEo0XGLsssnwFTU/2MnVKjudhfg/wJ6XLq
+ir8Z57Vs92EsrrUr5H/B/2IvvSSuTG53uGYiWa9/QxrR0cfcczp2+Nhpnn8nAgMB
+AAGjdjB0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0P
+AQH/BAUDAwegADAdBgNVHQ4EFgQU+vZUEQX5t+SGCe44YgvMmiMm8NkwHwYDVR0j
+BBgwFoAU9mOvr6Pi7+4O5bKxRihqeCkyHukwDQYJKoZIhvcNAQELBQADggExAI17
+s7teVt0hE9Zp40++AkK1k3/z7CCFsg+yS8+1VgFx5mU5XgNZMMgaASo1PCd9ZxFF
+QPXJ18MT4YjI6kWIC5RZspsTCwCq7jyg8bw36MHTNFUTYgfgMbhWPrUHRuOq0iG4
++wJVR6lXuHz/yaqMVNiy4yxBero7+zYiPZ+PKjEcvQxfcG+dIgptR6plNkFeZipT
+VCsSrit6iuStqmR7Jpj3nxPkR+g8aAfPCeiCxrSLNJFBj5J5AGSfkBzgjF5IE/z+
+tOgcmlFwtwOAIdRn/FUr7g1FFZh+Wy7AiB7qU4EcoW1HpcXJuRuKDrTzFH7L88zu
+nrv8n9XJSMDxdnP6kNwIv89HmYJWxtToO68PsATiGA6DiUUPk+FqIHqP0kgXXMSc
+ODFGSlXqh4ocvtA4APE=
+-----END CERTIFICATE-----
diff --git a/crypto/test/data/tls/x509-server-key.pem b/crypto/test/data/tls/x509-server-key.pem
new file mode 100644
index 000000000..894fbb999
--- /dev/null
+++ b/crypto/test/data/tls/x509-server-key.pem
@@ -0,0 +1,32 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIFfAIBAAKCATEAsy/PN54P7ZkH23FHjtgZuzpyGa84+YZOM3snikem660o90Ws
+TquMMtXNeAQPGAFUpu2Qxo416ogolqqtTXYJz9qsp/eDvzlNCJN7HKb5Fg28HiCc
+dMx2AR03qlGkxI3WsCPxFsX83zrz8wZSvrO7jjS1/WfJW1vYme+kktYcg90+5pJ0
+5hEAIwFU/mh9KnVRVdnINCcCqdnwpA1fAPXLwqNYdRolaczaQFI1ml8YbOgCnefz
+uxeSt9qz/7TkBITVvBf3AH5fUG6UezNxma85o7b1P4QJNiWGA7uwh7iABpIR7795
+Fk8ebOSUD9lZ9iqo0CzXBDAiwJe3uzSLBITlF0xbyveH+ILj7sKpa0CkV+5yZ1Cm
+B426lluuBlYxbi2wfAgN8arfQtnTobl/m+ClrQIDAQABAoIBMAEZ6kKNFNbIeBqT
+24dTDIUsj+DCbGPsR86wsG5FOgFRa96K0qcAS53nBAXDynKFl6igJcXs4WfLiRnN
+QGcgob+cIgM6pT8rDnlZT/291pH9mD/MwnyHDwak7C7dGXrRojWQl1TGZqjJS0f5
+enaN5lUnXwROZqsxUYohFkmtj1dpjxTqUGZ0In1JdG2mDmunMgjkJ/UqtCp0QFCp
+xtd1u5/913RBFC+n/CJl1+TnNQ4WNDRtkHZfJpVp+dOldQr028CJU3C5u1JB9ped
+JK+dywUFlqH1Tdk2v5CQV5esvbFpXX7FIlHuId+JOwFyvkR5+7NmyQ2uAz/Yeg8K
+ItdRhNQCJpYPlPH9Yb1JooEhPYrQX6oz/q2R3qiFdtc1cMZW3KCtIALZk30lW/o+
+B4EiysECgZkA1cYcdgNKy5K1O/IOyhr1eYK2us738Z3A57gC1y+m58D02dzmwacg
+HKZI9Cz98L8yEyORkdxpg86xi+NIcdU15BXXioFgMI5ZSfNVBcO4rv8G/QCxEWDr
+gnXe7FYuLlOKBbVXx7fJ0IXRUVbUlH5ZqE2HlFbSdPJmlaKtbxxyT7xhhWkf/MuI
+hRn+MFvbXvC+JqL+FS141kECgZkA1pS74hc7H5blq0J51E8EDtgU5m770VlQKhbW
+Z1D0oXVfB19DD3SX4xu22/6XlKXLlQDx4ssxVw11VIkd9WhkIrqq4U644XL5xXmf
+PMsR+fG2o+Y7MY4TNy+4qcuOK17n6R2pxR4zQoVnZs/qL4s5jPKMsC76C4Udfxfh
+yup0eFEJ+jPQdWYWQ6uX3UF0rA5x0Tb200aKbG0CgZkAkwaoeHoXLR//yfTXOyWD
+g0jliGHkoabQEA681WcOsgJB5L1LcBETwuCS+G0hUj0NoaAq9FjVsTOtZPqyzqfH
+YtGq5rXIhFzDCFt1NHvCP4ljMwsQvVUdZSLQaVd0d6Q5H2fzsYa0JNiEeB7yIhcs
+btaz0tBL+ubkqzGxeuPjsvdrUyhUObd6c6DG9FeY7xlAjq43djVKEIECgZhITde9
+SDyo2UzMV1r72iAw7EimmPELSsADXqyiJZo4qXb64fOTyqK/aQBFwtTKxs8Bh076
+L6ORhLxrXsSUg7dyKFoaD0+mz/ovu1qXvolxIix7r8F0Yj5BUzgzJp7iKFmWqGMj
+Q5jcKl18PETZ/lzHDJexajLhHNqij6aKnFPgktX80+bDGEIaTUCf0kWBEGDzsUSc
+TmGoRQKBmQDVFQ6EAOXXNp2bMLZ78qnxmS+NZPijBDeVu1cXMYdRSBoldrtSHKUM
+NFjPfesz4IRbEePK5s0vgM88QCDaspy8aLj//gh9YuqijbHOfhvMUP6MqzU/jJN7
+MDAxcGbcoFqdWTP1HB9qeX91UNRwN+2/xfO6SrLbfTvG4v/sntr8YfVYya2EuAa9
+qLk0TB3QXaoHknsz7EhRnw==
+-----END RSA PRIVATE KEY-----
diff --git a/crypto/test/data/tls/x509-server.pem b/crypto/test/data/tls/x509-server.pem
new file mode 100644
index 000000000..efc806967
--- /dev/null
+++ b/crypto/test/data/tls/x509-server.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDmjCCAlKgAwIBAgIEUqKc4DANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDExhC
+b3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTMxMjA3MDM1ODI0WhcNMzMxMjAy
+MDM1ODI0WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBTZXJ2ZXIwggFS
+MA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQCzL883ng/tmQfbcUeO2Bm7OnIZ
+rzj5hk4zeyeKR6brrSj3RaxOq4wy1c14BA8YAVSm7ZDGjjXqiCiWqq1NdgnP2qyn
+94O/OU0Ik3scpvkWDbweIJx0zHYBHTeqUaTEjdawI/EWxfzfOvPzBlK+s7uONLX9
+Z8lbW9iZ76SS1hyD3T7mknTmEQAjAVT+aH0qdVFV2cg0JwKp2fCkDV8A9cvCo1h1
+GiVpzNpAUjWaXxhs6AKd5/O7F5K32rP/tOQEhNW8F/cAfl9QbpR7M3GZrzmjtvU/
+hAk2JYYDu7CHuIAGkhHvv3kWTx5s5JQP2Vn2KqjQLNcEMCLAl7e7NIsEhOUXTFvK
+94f4guPuwqlrQKRX7nJnUKYHjbqWW64GVjFuLbB8CA3xqt9C2dOhuX+b4KWtAgMB
+AAGjdjB0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0P
+AQH/BAUDAwegADAdBgNVHQ4EFgQUlILGBt8EzhYtlNrOPrhfwi0s6bkwHwYDVR0j
+BBgwFoAU9mOvr6Pi7+4O5bKxRihqeCkyHukwDQYJKoZIhvcNAQELBQADggExAMQd
+MLOlWKWJxh6IP7sRlWKjpWZyu43eSOfvEpVljW8VaRxJC8UdhpFxsXS6Ml7wEMUC
+BkVNHGMxho/GJMXUBV7OsQSv0et1o45bmkN+KKisSVReSgcj6Drp/BRcUcybPtcJ
+aDW1txh/suHWppVmtkIkZIF/3IR2qFekDdCLoluiEOvbNn3YjUnQLm6Eo0pBxgpb
+W5MF3/19UckP1sLrs5vFk1dtDBZ/agpI9I0psv+6OsjosvrdpjIPHjwmoZ+oYtKc
+4Q30vzLCVtGGyzXWBZ+Z6AbmZpJPDQtul522XKE2vE8GA3+X/RXVAZB8a86DWtzq
+J1O6D+KOyA9zwe1CO+VJ5fMkjSNXY6WDzEXqyKEBP8tkkvSByiM546CXtNDbEwBe
+PtYQf223mpK56XTFq4k=
+-----END CERTIFICATE-----
diff --git a/crypto/test/lib/nunit.core.dll b/crypto/test/lib/nunit.core.dll
new file mode 100644
index 000000000..f58c07d42
--- /dev/null
+++ b/crypto/test/lib/nunit.core.dll
Binary files differdiff --git a/crypto/test/lib/nunit.core.interfaces.dll b/crypto/test/lib/nunit.core.interfaces.dll
new file mode 100644
index 000000000..cdf50b687
--- /dev/null
+++ b/crypto/test/lib/nunit.core.interfaces.dll
Binary files differdiff --git a/crypto/test/lib/nunit.framework.dll b/crypto/test/lib/nunit.framework.dll
new file mode 100644
index 000000000..c7b1c65d9
--- /dev/null
+++ b/crypto/test/lib/nunit.framework.dll
Binary files differdiff --git a/crypto/test/src/asn1/test/ASN1SequenceParserTest.cs b/crypto/test/src/asn1/test/ASN1SequenceParserTest.cs
new file mode 100644
index 000000000..030da04cb
--- /dev/null
+++ b/crypto/test/src/asn1/test/ASN1SequenceParserTest.cs
@@ -0,0 +1,359 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class Asn1SequenceParserTest
+    {
+        private static readonly byte[] seqData = Hex.Decode("3006020100060129");
+        private static readonly byte[] nestedSeqData = Hex.Decode("300b0201000601293003020101");
+        private static readonly byte[] expTagSeqData = Hex.Decode("a1083006020100060129");
+        private static readonly byte[] implTagSeqData = Hex.Decode("a106020100060129");
+        private static readonly byte[] nestedSeqExpTagData = Hex.Decode("300d020100060129a1053003020101");
+        private static readonly byte[] nestedSeqImpTagData = Hex.Decode("300b020100060129a103020101");
+
+		private static readonly byte[] berSeqData = Hex.Decode("30800201000601290000");
+        private static readonly byte[] berDerNestedSeqData = Hex.Decode("308002010006012930030201010000");
+        private static readonly byte[] berNestedSeqData = Hex.Decode("3080020100060129308002010100000000");
+        private static readonly byte[] berExpTagSeqData = Hex.Decode("a180308002010006012900000000");
+		private static readonly byte[] berSeqWithDERNullData = Hex.Decode("308005000201000601290000");
+
+		[Test]
+		public void TestDerWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            DerSequenceGenerator seqGen = new DerSequenceGenerator(bOut);
+
+			seqGen.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen.AddObject(new DerObjectIdentifier("1.1"));
+
+			seqGen.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(seqData, bOut.ToArray()), "basic DER writing test failed.");
+        }
+
+		[Test]
+		public void TestNestedDerWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            DerSequenceGenerator seqGen1 = new DerSequenceGenerator(bOut);
+
+			seqGen1.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen1.AddObject(new DerObjectIdentifier("1.1"));
+
+			DerSequenceGenerator seqGen2 = new DerSequenceGenerator(seqGen1.GetRawOutputStream());
+
+			seqGen2.AddObject(new DerInteger(BigInteger.One));
+
+			seqGen2.Close();
+
+			seqGen1.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(nestedSeqData, bOut.ToArray()), "nested DER writing test failed.");
+        }
+
+		[Test]
+		public void TestDerExplicitTaggedSequenceWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            DerSequenceGenerator seqGen = new DerSequenceGenerator(bOut, 1, true);
+
+            seqGen.AddObject(new DerInteger(BigInteger.Zero));
+
+            seqGen.AddObject(new DerObjectIdentifier("1.1"));
+
+            seqGen.Close();
+
+            Assert.IsTrue(Arrays.AreEqual(expTagSeqData, bOut.ToArray()), "explicit tag writing test failed.");
+        }
+
+		[Test]
+		public void TestDerImplicitTaggedSequenceWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            DerSequenceGenerator seqGen = new DerSequenceGenerator(bOut, 1, false);
+
+			seqGen.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen.AddObject(new DerObjectIdentifier("1.1"));
+
+			seqGen.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(implTagSeqData, bOut.ToArray()), "implicit tag writing test failed.");
+        }
+
+		[Test]
+		public void TestNestedExplicitTagDerWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            DerSequenceGenerator  seqGen1 = new DerSequenceGenerator(bOut);
+
+            seqGen1.AddObject(new DerInteger(BigInteger.Zero));
+
+            seqGen1.AddObject(new DerObjectIdentifier("1.1"));
+
+            DerSequenceGenerator seqGen2 = new DerSequenceGenerator(seqGen1.GetRawOutputStream(), 1, true);
+
+            seqGen2.AddObject(new DerInteger(BigInteger.ValueOf(1)));
+
+            seqGen2.Close();
+
+            seqGen1.Close();
+
+            Assert.IsTrue(Arrays.AreEqual(nestedSeqExpTagData, bOut.ToArray()), "nested explicit tagged DER writing test failed.");
+        }
+
+		[Test]
+		public void TestNestedImplicitTagDerWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            DerSequenceGenerator seqGen1 = new DerSequenceGenerator(bOut);
+
+			seqGen1.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen1.AddObject(new DerObjectIdentifier("1.1"));
+
+			DerSequenceGenerator seqGen2 = new DerSequenceGenerator(seqGen1.GetRawOutputStream(), 1, false);
+
+			seqGen2.AddObject(new DerInteger(BigInteger.ValueOf(1)));
+
+			seqGen2.Close();
+
+			seqGen1.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(nestedSeqImpTagData, bOut.ToArray()), "nested implicit tagged DER writing test failed.");
+        }
+
+		[Test]
+		public void TestBerWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BerSequenceGenerator seqGen = new BerSequenceGenerator(bOut);
+
+			seqGen.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen.AddObject(new DerObjectIdentifier("1.1"));
+
+			seqGen.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(berSeqData, bOut.ToArray()), "basic BER writing test failed.");
+        }
+
+		[Test]
+		public void TestNestedBerDerWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BerSequenceGenerator seqGen1 = new BerSequenceGenerator(bOut);
+
+			seqGen1.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen1.AddObject(new DerObjectIdentifier("1.1"));
+
+			DerSequenceGenerator seqGen2 = new DerSequenceGenerator(seqGen1.GetRawOutputStream());
+
+			seqGen2.AddObject(new DerInteger(BigInteger.ValueOf(1)));
+
+			seqGen2.Close();
+
+			seqGen1.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(berDerNestedSeqData, bOut.ToArray()), "nested BER/DER writing test failed.");
+        }
+
+		[Test]
+		public void TestNestedBerWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BerSequenceGenerator seqGen1 = new BerSequenceGenerator(bOut);
+
+			seqGen1.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen1.AddObject(new DerObjectIdentifier("1.1"));
+
+			BerSequenceGenerator seqGen2 = new BerSequenceGenerator(seqGen1.GetRawOutputStream());
+
+			seqGen2.AddObject(new DerInteger(BigInteger.ValueOf(1)));
+
+			seqGen2.Close();
+
+			seqGen1.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(berNestedSeqData, bOut.ToArray()), "nested BER writing test failed.");
+        }
+
+		[Test]
+		public void TestDerReading()
+        {
+            Asn1StreamParser aIn = new Asn1StreamParser(seqData);
+
+			Asn1SequenceParser seq = (Asn1SequenceParser)aIn.ReadObject();
+            int count = 0;
+
+			Assert.IsNotNull(seq, "null sequence returned");
+
+			object o;
+			while ((o = seq.ReadObject()) != null)
+            {
+                switch (count)
+                {
+                    case 0:
+                        Assert.IsTrue(o is DerInteger);
+                        break;
+                    case 1:
+                        Assert.IsTrue(o is DerObjectIdentifier);
+                        break;
+                }
+                count++;
+            }
+
+			Assert.AreEqual(2, count, "wrong number of objects in sequence");
+        }
+
+		private void doTestNestedReading(
+            byte[] data)
+        {
+            Asn1StreamParser aIn = new Asn1StreamParser(data);
+
+			Asn1SequenceParser seq = (Asn1SequenceParser) aIn.ReadObject();
+            object o = null;
+            int count = 0;
+
+			Assert.IsNotNull(seq, "null sequence returned");
+
+			while ((o = seq.ReadObject()) != null)
+            {
+                switch (count)
+                {
+                    case 0:
+                        Assert.IsTrue(o is DerInteger);
+                        break;
+                    case 1:
+                        Assert.IsTrue(o is DerObjectIdentifier);
+                        break;
+                    case 2:
+                        Assert.IsTrue(o is Asn1SequenceParser);
+
+						Asn1SequenceParser s = (Asn1SequenceParser)o;
+
+						// NB: Must exhaust the nested parser
+						while (s.ReadObject() != null)
+						{
+							// Ignore
+						}
+
+						break;
+                }
+                count++;
+            }
+
+			Assert.AreEqual(3, count, "wrong number of objects in sequence");
+        }
+
+		[Test]
+		public void TestNestedDerReading()
+        {
+            doTestNestedReading(nestedSeqData);
+        }
+
+		[Test]
+		public void TestBerReading()
+        {
+            Asn1StreamParser aIn = new Asn1StreamParser(berSeqData);
+
+			Asn1SequenceParser seq = (Asn1SequenceParser) aIn.ReadObject();
+            object o = null;
+            int count = 0;
+
+			Assert.IsNotNull(seq, "null sequence returned");
+
+			while ((o = seq.ReadObject()) != null)
+            {
+                switch (count)
+                {
+                    case 0:
+                        Assert.IsTrue(o is DerInteger);
+                        break;
+                    case 1:
+                        Assert.IsTrue(o is DerObjectIdentifier);
+                        break;
+                }
+                count++;
+            }
+
+			Assert.AreEqual(2, count, "wrong number of objects in sequence");
+        }
+
+		[Test]
+		public void TestNestedBerDerReading()
+        {
+            doTestNestedReading(berDerNestedSeqData);
+        }
+
+		[Test]
+		public void TestNestedBerReading()
+        {
+            doTestNestedReading(berNestedSeqData);
+        }
+
+		[Test]
+		public void TestBerExplicitTaggedSequenceWriting()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BerSequenceGenerator seqGen = new BerSequenceGenerator(bOut, 1, true);
+
+			seqGen.AddObject(new DerInteger(BigInteger.Zero));
+
+			seqGen.AddObject(new DerObjectIdentifier("1.1"));
+
+			seqGen.Close();
+
+			Assert.IsTrue(Arrays.AreEqual(berExpTagSeqData, bOut.ToArray()), "explicit BER tag writing test failed.");
+        }
+
+		[Test]
+		public void TestSequenceWithDerNullReading()
+		{
+			doTestParseWithNull(berSeqWithDERNullData);
+		}
+
+		private void doTestParseWithNull(
+			byte[] data)
+		{
+			Asn1StreamParser aIn = new Asn1StreamParser(data);
+			Asn1SequenceParser seq = (Asn1SequenceParser) aIn.ReadObject();
+			object o;
+			int count = 0;
+
+			Assert.IsNotNull(seq, "null sequence returned");
+
+			while ((o = seq.ReadObject()) != null)
+			{
+				switch (count)
+				{
+					case 0:
+						Assert.IsTrue(o is Asn1Null);
+						break;
+					case 1:
+						Assert.IsTrue(o is DerInteger);
+						break;
+					case 2:
+						Assert.IsTrue(o is DerObjectIdentifier);
+						break;
+				}
+				count++;
+			}
+
+			Assert.AreEqual(3, count, "wrong number of objects in sequence");
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/ASN1UnitTest.cs b/crypto/test/src/asn1/test/ASN1UnitTest.cs
new file mode 100644
index 000000000..88492bede
--- /dev/null
+++ b/crypto/test/src/asn1/test/ASN1UnitTest.cs
@@ -0,0 +1,88 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	public abstract class Asn1UnitTest
+		: SimpleTest
+	{
+		protected void checkMandatoryField(string name, Asn1Encodable expected, Asn1Encodable present)
+		{
+			if (!expected.Equals(present))
+			{
+				Fail(name + " field doesn't match.");
+			}
+		}
+
+		protected void checkMandatoryField(string name, string expected, string present)
+		{
+			if (!expected.Equals(present))
+			{
+				Fail(name + " field doesn't match.");
+			}
+		}
+
+		protected void checkMandatoryField(string name, byte[] expected, byte[] present)
+		{
+			if (!AreEqual(expected, present))
+			{
+				Fail(name + " field doesn't match.");
+			}
+		}
+
+		protected void checkMandatoryField(string name, int expected, int present)
+		{
+			if (expected != present)
+			{
+				Fail(name + " field doesn't match.");
+			}
+		}
+
+		protected void checkOptionalField(string name, Asn1Encodable expected, Asn1Encodable present)
+		{
+			if (expected != null)
+			{
+				if (!expected.Equals(present))
+				{
+					Fail(name + " field doesn't match.");
+				}
+			}
+			else if (present != null)
+			{
+				Fail(name + " field found when none expected.");
+			}
+		}
+
+		protected void checkOptionalField(string name, string expected, string present)
+		{
+			if (expected != null)
+			{
+				if (!expected.Equals(present))
+				{
+					Fail(name + " field doesn't match.");
+				}
+			}
+			else if (present != null)
+			{
+				Fail(name + " field found when none expected.");
+			}
+		}
+
+		protected void checkOptionalField(string name, BigInteger expected, BigInteger present)
+		{
+			if (expected != null)
+			{
+				if (!expected.Equals(present))
+				{
+					Fail(name + " field doesn't match.");
+				}
+			}
+			else if (present != null)
+			{
+				Fail(name + " field found when none expected.");
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/AdditionalInformationSyntaxUnitTest.cs b/crypto/test/src/asn1/test/AdditionalInformationSyntaxUnitTest.cs
new file mode 100644
index 000000000..ac4ff9809
--- /dev/null
+++ b/crypto/test/src/asn1/test/AdditionalInformationSyntaxUnitTest.cs
@@ -0,0 +1,77 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class AdditionalInformationSyntaxUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "AdditionalInformationSyntax"; }
+		}
+
+		public override void PerformTest()
+		{
+			AdditionalInformationSyntax syntax = new AdditionalInformationSyntax("hello world");
+
+			checkConstruction(syntax, new DirectoryString("hello world"));
+
+			try
+			{
+				AdditionalInformationSyntax.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			AdditionalInformationSyntax syntax,
+			DirectoryString information)
+		{
+			checkValues(syntax, information);
+
+			syntax = AdditionalInformationSyntax.GetInstance(syntax);
+
+			checkValues(syntax, information);
+
+			Asn1InputStream aIn = new Asn1InputStream(syntax.ToAsn1Object().GetEncoded());
+
+			IAsn1String info = (IAsn1String) aIn.ReadObject();
+
+			syntax = AdditionalInformationSyntax.GetInstance(info);
+
+			checkValues(syntax, information);
+		}
+
+		private void checkValues(
+			AdditionalInformationSyntax syntax,
+			DirectoryString information)
+		{
+			checkMandatoryField("information", information, syntax.Information);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new AdditionalInformationSyntaxUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/AdmissionSyntaxUnitTest.cs b/crypto/test/src/asn1/test/AdmissionSyntaxUnitTest.cs
new file mode 100644
index 000000000..59464d212
--- /dev/null
+++ b/crypto/test/src/asn1/test/AdmissionSyntaxUnitTest.cs
@@ -0,0 +1,99 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class AdmissionSyntaxUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "AdmissionSyntax"; }
+		}
+
+		public override void PerformTest()
+		{
+			GeneralName name = new GeneralName(new X509Name("CN=hello world"));
+			Asn1Sequence admissions = new DerSequence(
+				new Admissions(name,
+				new NamingAuthority(new DerObjectIdentifier("1.2.3"), "url", new DirectoryString("fred")),
+				new ProfessionInfo[0]));
+			AdmissionSyntax syntax = new AdmissionSyntax(name, admissions);
+
+			checkConstruction(syntax, name, admissions);
+
+			syntax = AdmissionSyntax.GetInstance(null);
+
+			if (syntax != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				AdmissionSyntax.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			AdmissionSyntax	syntax,
+			GeneralName		authority,
+			Asn1Sequence	admissions)
+		{
+			checkValues(syntax, authority, admissions);
+
+			syntax = AdmissionSyntax.GetInstance(syntax);
+
+			checkValues(syntax, authority, admissions);
+
+			Asn1InputStream aIn = new Asn1InputStream(syntax.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence info = (Asn1Sequence) aIn.ReadObject();
+
+			syntax = AdmissionSyntax.GetInstance(info);
+
+			checkValues(syntax, authority, admissions);
+		}
+
+		private void checkValues(
+			AdmissionSyntax syntax,
+			GeneralName     authority,
+			Asn1Sequence    admissions)
+		{
+			checkMandatoryField("admissionAuthority", authority, syntax.AdmissionAuthority);
+
+			Admissions[] adm = syntax.GetContentsOfAdmissions();
+
+			if (adm.Length != 1 || !adm[0].Equals(admissions[0]))
+			{
+				Fail("admissions check failed");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new AdmissionSyntaxUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/AdmissionsUnitTest.cs b/crypto/test/src/asn1/test/AdmissionsUnitTest.cs
new file mode 100644
index 000000000..edefeb830
--- /dev/null
+++ b/crypto/test/src/asn1/test/AdmissionsUnitTest.cs
@@ -0,0 +1,90 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class AdmissionsUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "Admissions"; }
+		}
+
+		public override void PerformTest()
+		{
+			GeneralName name = new GeneralName(new X509Name("CN=hello world"));
+			NamingAuthority auth = new NamingAuthority(new DerObjectIdentifier("1.2.3"), "url", new DirectoryString("fred"));
+			Admissions admissions = new Admissions(name, auth, new ProfessionInfo[0]);
+
+			checkConstruction(admissions, name, auth);
+
+			admissions = Admissions.GetInstance(null);
+
+			if (admissions != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				Admissions.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			Admissions      admissions,
+			GeneralName     name,
+			NamingAuthority auth)
+		{
+			checkValues(admissions, name, auth);
+
+			admissions = Admissions.GetInstance(admissions);
+
+			checkValues(admissions, name, auth);
+
+			Asn1InputStream aIn = new Asn1InputStream(admissions.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence info = (Asn1Sequence)aIn.ReadObject();
+
+			admissions = Admissions.GetInstance(info);
+
+			checkValues(admissions, name, auth);
+		}
+
+		private void checkValues(
+			Admissions		admissions,
+			GeneralName		name,
+			NamingAuthority	auth)
+		{
+			checkMandatoryField("admissionAuthority", name, admissions.AdmissionAuthority);
+			checkMandatoryField("namingAuthority", auth, admissions.NamingAuthority);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new AdmissionsUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/AllTests.cs b/crypto/test/src/asn1/test/AllTests.cs
new file mode 100644
index 000000000..a1ae8fd48
--- /dev/null
+++ b/crypto/test/src/asn1/test/AllTests.cs
@@ -0,0 +1,32 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    public class AllTests
+    {
+        public static void Main(string[] args)
+        {
+//            junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            suite().Run(el);
+        }
+
+		public static TestSuite suite()
+        {
+            TestSuite suite = new TestSuite("ASN.1 tests");
+
+			suite.Add(new AllTests());
+
+			// TODO Add these tests to RegressionTest list
+			suite.Add(new Asn1SequenceParserTest());
+			suite.Add(new OctetStringTest());
+			suite.Add(new ParseTest());
+			suite.Add(new TimeTest());
+
+			return suite;
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/AttributeTableUnitTest.cs b/crypto/test/src/asn1/test/AttributeTableUnitTest.cs
new file mode 100644
index 000000000..5dcf349cc
--- /dev/null
+++ b/crypto/test/src/asn1/test/AttributeTableUnitTest.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Asn1Cms = Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class AttributeTableUnitTest
+        : SimpleTest
+    {
+        private static readonly DerObjectIdentifier type1 = new DerObjectIdentifier("1.1.1");
+        private static readonly DerObjectIdentifier type2 = new DerObjectIdentifier("1.1.2");
+        private static readonly DerObjectIdentifier type3 = new DerObjectIdentifier("1.1.3");
+
+		public override string Name
+		{
+			get { return "AttributeTable"; }
+		}
+
+		public override void PerformTest()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				new Asn1Cms.Attribute(type1, new DerSet(type1)),
+				new Asn1Cms.Attribute(type2, new DerSet(type2)));
+
+			Asn1Cms.AttributeTable table = new Asn1Cms.AttributeTable(v);
+
+			Asn1Cms.Attribute a = table[type1];
+            if (a == null)
+            {
+                Fail("type1 attribute not found.");
+            }
+            if (!a.AttrValues.Equals(new DerSet(type1)))
+            {
+                Fail("wrong value retrieved for type1!");
+            }
+
+			a = table[type2];
+            if (a == null)
+            {
+                Fail("type2 attribute not found.");
+            }
+            if (!a.AttrValues.Equals(new DerSet(type2)))
+            {
+                Fail("wrong value retrieved for type2!");
+            }
+
+			a = table[type3];
+            if (a != null)
+            {
+                Fail("type3 attribute found when none expected.");
+            }
+
+			Asn1EncodableVector vec = table.GetAll(type1);
+            if (vec.Count != 1)
+            {
+                Fail("wrong vector size for type1.");
+            }
+
+			vec = table.GetAll(type3);
+            if (vec.Count != 0)
+            {
+                Fail("wrong vector size for type3.");
+            }
+
+			vec = table.ToAsn1EncodableVector();
+            if (vec.Count != 2)
+            {
+                Fail("wrong vector size for single.");
+            }
+
+            IDictionary t = table.ToDictionary();
+
+			if (t.Count != 2)
+            {
+                Fail("hashtable wrong size.");
+            }
+
+            // multiple
+
+			v = new Asn1EncodableVector(
+				new Asn1Cms.Attribute(type1, new DerSet(type1)),
+				new Asn1Cms.Attribute(type1, new DerSet(type2)),
+				new Asn1Cms.Attribute(type1, new DerSet(type3)),
+				new Asn1Cms.Attribute(type2, new DerSet(type2)));
+
+			table = new Asn1Cms.AttributeTable(v);
+
+			a = table[type1];
+            if (!a.AttrValues.Equals(new DerSet(type1)))
+            {
+                Fail("wrong value retrieved for type1 multi Get!");
+            }
+
+			vec = table.GetAll(type1);
+            if (vec.Count != 3)
+            {
+                Fail("wrong vector size for multiple type1.");
+            }
+
+			a = (Asn1Cms.Attribute)vec[0];
+            if (!a.AttrValues.Equals(new DerSet(type1)))
+            {
+                Fail("wrong value retrieved for type1(0)!");
+            }
+
+            a = (Asn1Cms.Attribute)vec[1];
+            if (!a.AttrValues.Equals(new DerSet(type2)))
+            {
+                Fail("wrong value retrieved for type1(1)!");
+            }
+
+            a = (Asn1Cms.Attribute)vec[2];
+            if (!a.AttrValues.Equals(new DerSet(type3)))
+            {
+                Fail("wrong value retrieved for type1(2)!");
+            }
+
+            vec = table.GetAll(type2);
+            if (vec.Count != 1)
+            {
+                Fail("wrong vector size for multiple type2.");
+            }
+
+            vec = table.ToAsn1EncodableVector();
+            if (vec.Count != 4)
+            {
+                Fail("wrong vector size for multiple.");
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new AttributeTableUnitTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/BiometricDataUnitTest.cs b/crypto/test/src/asn1/test/BiometricDataUnitTest.cs
new file mode 100644
index 000000000..a542f71af
--- /dev/null
+++ b/crypto/test/src/asn1/test/BiometricDataUnitTest.cs
@@ -0,0 +1,133 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class BiometricDataUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "BiometricData"; }
+        }
+
+		private byte[] GenerateHash()
+        {
+            Random rand = new Random();
+            byte[] bytes = new byte[20];
+            rand.NextBytes(bytes);
+            return bytes;
+        }
+
+		public override void PerformTest()
+        {
+            TypeOfBiometricData dataType = new TypeOfBiometricData(TypeOfBiometricData.HandwrittenSignature);
+            AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+            Asn1OctetString     dataHash = new DerOctetString(GenerateHash());
+            BiometricData       bd = new BiometricData(dataType, hashAlgorithm, dataHash);
+
+            CheckConstruction(bd, dataType, hashAlgorithm, dataHash, null);
+
+            DerIA5String dataUri = new DerIA5String("http://test");
+
+            bd = new BiometricData(dataType, hashAlgorithm, dataHash, dataUri);
+
+            CheckConstruction(bd, dataType, hashAlgorithm, dataHash, dataUri);
+
+            bd = BiometricData.GetInstance(null);
+
+            if (bd != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+            try
+            {
+                BiometricData.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        private void CheckConstruction(
+            BiometricData bd,
+            TypeOfBiometricData dataType,
+            AlgorithmIdentifier hashAlgorithm,
+            Asn1OctetString dataHash,
+            DerIA5String dataUri)
+        {
+            CheckValues(bd, dataType, hashAlgorithm, dataHash, dataUri);
+
+            bd = BiometricData.GetInstance(bd);
+
+            CheckValues(bd, dataType, hashAlgorithm, dataHash, dataUri);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(bd.ToAsn1Object().GetEncoded());
+
+			bd = BiometricData.GetInstance(seq);
+
+			CheckValues(bd, dataType, hashAlgorithm, dataHash, dataUri);
+        }
+
+        private void CheckValues(
+            BiometricData       bd,
+            TypeOfBiometricData dataType,
+            AlgorithmIdentifier algID,
+            Asn1OctetString     dataHash,
+            DerIA5String        sourceDataURI)
+        {
+            if (!bd.TypeOfBiometricData.Equals(dataType))
+            {
+                Fail("types don't match.");
+            }
+
+            if (!bd.HashAlgorithm.Equals(algID))
+            {
+                Fail("hash algorithms don't match.");
+            }
+
+            if (!bd.BiometricDataHash.Equals(dataHash))
+            {
+                Fail("hash algorithms don't match.");
+            }
+
+            if (sourceDataURI != null)
+            {
+                if (!bd.SourceDataUri.Equals(sourceDataURI))
+                {
+                    Fail("data uris don't match.");
+                }
+            }
+            else if (bd.SourceDataUri != null)
+            {
+                Fail("data uri found when none expected.");
+            }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            RunTest(new BiometricDataUnitTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/BitStringConstantTester.cs b/crypto/test/src/asn1/test/BitStringConstantTester.cs
new file mode 100644
index 000000000..bb966d3e4
--- /dev/null
+++ b/crypto/test/src/asn1/test/BitStringConstantTester.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	public class BitStringConstantTester
+	{
+		private static readonly int[] bits =
+		{
+			1 << 7, 1 << 6, 1 << 5, 1 << 4, 1 << 3, 1 << 2, 1 << 1, 1 << 0,
+			1 << 15, 1 << 14, 1 << 13, 1 << 12, 1 << 11, 1 << 10, 1 << 9, 1 << 8,
+			1 << 23, 1 << 22, 1 << 21, 1 << 20, 1 << 19, 1 << 18, 1 << 17, 1 << 16,
+			1 << 31, 1 << 30, 1 << 29, 1 << 28, 1 << 27, 1 << 26, 1 << 25, 1 << 24
+		};
+
+		public static void testFlagValueCorrect(
+			int bitNo,
+			int value)
+		{
+			if (bits[bitNo] != value)
+			{
+				throw new ArgumentException("bit value " + bitNo + " wrong");
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/BitStringTest.cs b/crypto/test/src/asn1/test/BitStringTest.cs
new file mode 100644
index 000000000..3a2dc3156
--- /dev/null
+++ b/crypto/test/src/asn1/test/BitStringTest.cs
@@ -0,0 +1,82 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class BitStringTest
+        : ITest
+    {
+        public ITestResult Perform()
+        {
+            KeyUsage k = new KeyUsage(KeyUsage.DigitalSignature);
+            if ((k.GetBytes()[0] != (byte)KeyUsage.DigitalSignature) || (k.PadBits != 7))
+            {
+                return new SimpleTestResult(false, Name + ": failed digitalSignature");
+            }
+
+            k = new KeyUsage(KeyUsage.NonRepudiation);
+            if ((k.GetBytes()[0] != (byte)KeyUsage.NonRepudiation) || (k.PadBits != 6))
+            {
+                return new SimpleTestResult(false, Name + ": failed nonRepudiation");
+            }
+
+            k = new KeyUsage(KeyUsage.KeyEncipherment);
+            if ((k.GetBytes()[0] != (byte)KeyUsage.KeyEncipherment) || (k.PadBits != 5))
+            {
+                return new SimpleTestResult(false, Name + ": failed keyEncipherment");
+            }
+
+            k = new KeyUsage(KeyUsage.CrlSign);
+            if ((k.GetBytes()[0] != (byte)KeyUsage.CrlSign)  || (k.PadBits != 1))
+            {
+                return new SimpleTestResult(false, Name + ": failed cRLSign");
+            }
+
+            k = new KeyUsage(KeyUsage.DecipherOnly);
+            if ((k.GetBytes()[1] != (byte)(KeyUsage.DecipherOnly >> 8))  || (k.PadBits != 7))
+            {
+                return new SimpleTestResult(false, Name + ": failed decipherOnly");
+            }
+
+			// test for zero length bit string
+			try
+			{
+				Asn1Object.FromByteArray(new DerBitString(new byte[0], 0).GetEncoded());
+			}
+			catch (IOException e)
+			{
+				return new SimpleTestResult(false, Name + ": " + e);
+			}
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public string Name
+        {
+			get { return "BitString"; }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            ITest test = new BitStringTest();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/CMSTest.cs b/crypto/test/src/asn1/test/CMSTest.cs
new file mode 100644
index 000000000..1afb363af
--- /dev/null
+++ b/crypto/test/src/asn1/test/CMSTest.cs
@@ -0,0 +1,306 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class CmsTest
+		: ITest
+	{
+		//
+		// compressed data object
+		//
+		private static readonly byte[] compData = Base64.Decode(
+			"MIAGCyqGSIb3DQEJEAEJoIAwgAIBADANBgsqhkiG9w0BCRADCDCABgkqhkiG9w0BBwGggCSABIIC"
+			+ "Hnic7ZRdb9owFIbvK/k/5PqVYPFXGK12YYyboVFASSp1vQtZGiLRACZE49/XHoUW7S/0tXP8Efux"
+			+ "fU5ivWnasml72XFb3gb5druui7ytN803M570nii7C5r8tfwR281hy/p/KSM3+jzH5s3+pbQ90xSb"
+			+ "P3VT3QbLusnt8WPIuN5vN/vaA2+DulnXTXkXvNTr8j8ouZmkCmGI/UW+ZS/C8zP0bz2dz0zwLt+1"
+			+ "UEk2M8mlaxjRMByAhZTj0RGYg4TvogiRASROsZgjpVcJCb1KV6QzQeDJ1XkoQ5Jm+C5PbOHZZGRi"
+			+ "v+ORAcshOGeCcdFJyfgFxdtCdEcmOrbinc/+BBMzRThEYpwl+jEBpciSGWQkI0TSlREmD/eOHb2D"
+			+ "SGLuESm/iKUFt1y4XHBO2a5oq0IKJKWLS9kUZTA7vC5LSxYmgVL46SIWxIfWBQd6AdrnjLmH94UT"
+			+ "vGxVibLqRCtIpp4g2qpdtqK1LiOeolpVK5wVQ5P7+QjZAlrh0cePYTx/gNZuB9Vhndtgujl9T/tg"
+			+ "W9ogK+3rnmg3YWygnTuF5GDS+Q/jIVLnCcYZFc6Kk/+c80wKwZjwdZIqDYWRH68MuBQSXLgXYXj2"
+			+ "3CAaYOBNJMliTl0X7eV5DnoKIFSKYdj3cRpD/cK/JWTHJRe76MUXnfBW8m7Hd5zhQ4ri2NrVF/WL"
+			+ "+kV1/3AGSlJ32bFPd2BsQD8uSzIx6lObkjdz95c0AAAAAAAAAAAAAAAA");
+
+		//
+		// enveloped data
+		//
+		private static readonly byte[] envDataKeyTrns = Base64.Decode(
+			  "MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKEw1Cb3Vu"
+			+ "Y3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBCjANBgkqhkiG9w0BAQEFAASBgC5vdGrB"
+			+ "itQSGwifLf3KwPILjaB4WEXgT/IIO1KDzrsbItCJsMA0Smq2y0zptxT0pSRL6JRg"
+			+ "NMxLk1ySnrIrvGiEPLMR1zjxlT8yQ6VLX+kEoK43ztd1aaLw0oBfrcXcLN7BEpZ1"
+			+ "TIdjlBfXIOx1S88WY1MiYqJJFc3LMwRUaTEDMIAGCSqGSIb3DQEHATAdBglghkgB"
+			+ "ZQMEARYEEAfxLMWeaBOTTZQwUq0Y5FuggAQgwOJhL04rjSZCBCSOv5i5XpFfGsOd"
+			+ "YSHSqwntGpFqCx4AAAAAAAAAAAAA");
+
+		private static readonly byte[] envDataKEK = Base64.Decode(
+			  "MIAGCSqGSIb3DQEHA6CAMIACAQIxUqJQAgEEMAcEBQECAwQFMBAGCyqGSIb3DQEJE"
+			+ "AMHAgE6BDC7G/HyUPilIrin2Yeajqmj795VoLWETRnZAAFcAiQdoQWyz+oCh6WY/H"
+			+ "jHHi+0y+cwgAYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAiY3eDBBbF6naCABBiNdzJb"
+			+ "/v6+UZB3XXKipxFDUpz9GyjzB+gAAAAAAAAAAAAA");
+
+		private static readonly byte[] envDataNestedNDEF = Base64.Decode(
+			  "MIAGCSqGSIb3DQEHA6CAMIACAQAxge8wgewCAQAwgZUwgY8xKDAmBgNVBAoMH1RoZSBMZWdpb24g"
+			+ "b2YgdGhlIEJvdW5jeSBDYXN0bGUxLzAtBgkqhkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3Vu"
+			+ "Y3ljYXN0bGUub3JnMREwDwYDVQQIDAhWaWN0b3JpYTESMBAGA1UEBwwJTWVsYm91cm5lMQswCQYD"
+			+ "VQQGEwJBVQIBATANBgkqhkiG9w0BAQEFAARABIXMd8xiTyWDKO/LQfvdGYTPW3I9oSQWwtm4OIaN"
+			+ "VINpfY2lfwTvbmE6VXiLKeALC0dMBV8z7DEM9hE0HVmvLDCABgkqhkiG9w0BBwEwHQYJYIZIAWUD"
+			+ "BAECBBB32ko6WrVxDTqwUYEpV6IUoIAEggKgS6RowrhNlmWWI13zxD/lryxkZ5oWXPUfNiUxYX/P"
+			+ "r5iscW3s8VKJKUpJ4W5SNA7JGL4l/5LmSnJ4Qu/xzxcoH4r4vmt75EDE9p2Ob2Xi1NuSFAZubJFc"
+			+ "Zlnp4e05UHKikmoaz0PbiAi277sLQlK2FcVsntTYVT00y8+IwuuQu0ATVqkXC+VhfjV/sK6vQZnw"
+			+ "2rQKedZhLB7B4dUkmxCujb/UAq4lgSpLMXg2P6wMimTczXyQxRiZxPeI4ByCENjkafXbfcJft2eD"
+			+ "gv1DEDdYM5WrW9Z75b4lmJiOJ/xxDniHCvum7KGXzpK1d1mqTlpzPC2xoz08/MO4lRf5Mb0bYdq6"
+			+ "CjMaYqVwGsYryp/2ayX+d8H+JphEG+V9Eg8uPcDoibwhDI4KkoyGHstPw5bxcy7vVFt7LXUdNjJc"
+			+ "K1wxaUKEXDGKt9Vj93FnBTLMX0Pc9HpueV5o1ipX34dn/P3HZB9XK8ScbrE38B1VnIgylStnhVFO"
+			+ "Cj9s7qSVqI2L+xYHJRHsxaMumIRnmRuOqdXDfIo28EZAnFtQ/b9BziMGVvAW5+A8h8s2oazhSmK2"
+			+ "23ftV7uv98ScgE8fCd3PwT1kKJM83ThTYyBzokvMfPYCCvsonMV+kTWXhWcwjYTS4ukrpR452ZdW"
+			+ "l3aJqDnzobt5FK4T8OGciOj+1PxYFZyRmCuafm2Dx6o7Et2Tu/T5HYvhdY9jHyqtDl2PXH4CTnVi"
+			+ "gA1YOAArjPVmsZVwAM3Ml46uyXXhcsXwQ1X0Tv4D+PSa/id4UQ2cObOw8Cj1eW2GB8iJIZVqkZaU"
+			+ "XBexqgWYOIoxjqODSeoZKiBsTK3c+oOUBqBDueY1i55swE2o6dDt95FluX6iyr/q4w2wLt3upY1J"
+			+ "YL+TuvZxAKviuAczMS1bAAAAAAAAAAAAAA==");
+
+		//
+		// signed data
+		//
+		private static readonly byte[] signedData = Base64.Decode(
+			  "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCA"
+			+ "JIAEDEhlbGxvIFdvcmxkIQAAAAAAAKCCBGIwggINMIIBdqADAgECAgEBMA0GCSqG"
+			+ "SIb3DQEBBAUAMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNVBAYTAkFV"
+			+ "MB4XDTA0MTAyNDA0MzA1OFoXDTA1MDIwMTA0MzA1OFowJTEWMBQGA1UEChMNQm91"
+			+ "bmN5IENhc3RsZTELMAkGA1UEBhMCQVUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ"
+			+ "AoGBAJj3OAshAOgDmPcYZ1jdNSuhOHRH9VhC/PG17FdiInVGc2ulJhEifEQga/uq"
+			+ "ZCpSd1nHsJUZKm9k1bVneWzC0941i9Znfxgb2jnXXsa5kwB2KEVESrOWsRjSRtnY"
+			+ "iLgqBG0rzpaMn5A5ntu7N0406EesBhe19cjZAageEHGZDbufAgMBAAGjTTBLMB0G"
+			+ "A1UdDgQWBBR/iHNKOo6f4ByWFFywRNZ65XSr1jAfBgNVHSMEGDAWgBR/iHNKOo6f"
+			+ "4ByWFFywRNZ65XSr1jAJBgNVHRMEAjAAMA0GCSqGSIb3DQEBBAUAA4GBAFMJJ7QO"
+			+ "pHo30bnlQ4Ny3PCnK+Se+Gw3TpaYGp84+a8fGD9Dme78G6NEsgvpFGTyoLxvJ4CB"
+			+ "84Kzys+1p2HdXzoZiyXAer5S4IwptE3TxxFwKyj28cRrM6dK47DDyXUkV0qwBAMN"
+			+ "luwnk/no4K7ilzN2MZk5l7wXyNa9yJ6CHW6dMIICTTCCAbagAwIBAgIBAjANBgkq"
+			+ "hkiG9w0BAQQFADAlMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJB"
+			+ "VTAeFw0wNDEwMjQwNDMwNTlaFw0wNTAyMDEwNDMwNTlaMGUxGDAWBgNVBAMTD0Vy"
+			+ "aWMgSC4gRWNoaWRuYTEkMCIGCSqGSIb3DQEJARYVZXJpY0Bib3VuY3ljYXN0bGUu"
+			+ "b3JnMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVTCBnzANBgkq"
+			+ "hkiG9w0BAQEFAAOBjQAwgYkCgYEAm+5CnGU6W45iUpCsaGkn5gDruZv3j/o7N6ag"
+			+ "mRZhikaLG2JF6ECaX13iioVJfmzBsPKxAACWwuTXCoSSXG8viK/qpSHwJpfQHYEh"
+			+ "tcC0CxIqlnltv3KQAGwh/PdwpSPvSNnkQBGvtFq++9gnXDBbynfP8b2L2Eis0X9U"
+			+ "2y6gFiMCAwEAAaNNMEswHQYDVR0OBBYEFEAmOksnF66FoQm6IQBVN66vJo1TMB8G"
+			+ "A1UdIwQYMBaAFH+Ic0o6jp/gHJYUXLBE1nrldKvWMAkGA1UdEwQCMAAwDQYJKoZI"
+			+ "hvcNAQEEBQADgYEAEeIjvNkKMPU/ZYCu1TqjGZPEqi+glntg2hC/CF0oGyHFpMuG"
+			+ "tMepF3puW+uzKM1s61ar3ahidp3XFhr/GEU/XxK24AolI3yFgxP8PRgUWmQizTQX"
+			+ "pWUmhlsBe1uIKVEfNAzCgtYfJQ8HJIKsUCcdWeCKVKs4jRionsek1rozkPExggEv"
+			+ "MIIBKwIBATAqMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNVBAYTAkFV"
+			+ "AgECMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqG"
+			+ "SIb3DQEJBTEPFw0wNDEwMjQwNDMwNTlaMCMGCSqGSIb3DQEJBDEWBBQu973mCM5U"
+			+ "BOl9XwQvlfifHCMocTANBgkqhkiG9w0BAQEFAASBgGHbe3/jcZu6b/erRhc3PEji"
+			+ "MUO8mEIRiNYBr5/vFNhkry8TrGfOpI45m7gu1MS0/vdas7ykvidl/sNZfO0GphEI"
+			+ "UaIjMRT3U6yuTWF4aLpatJbbRsIepJO/B2kdIAbV5SCbZgVDJIPOR2qnruHN2wLF"
+			+ "a+fEv4J8wQ8Xwvk0C8iMAAAAAAAA");
+
+		private static void Touch(object o)
+		{
+		}
+
+		private ITestResult CompressionTest()
+		{
+			try
+			{
+				ContentInfo info = ContentInfo.GetInstance(
+					Asn1Object.FromByteArray(compData));
+				CompressedData data = CompressedData.GetInstance(info.Content);
+
+				data = new CompressedData(data.CompressionAlgorithmIdentifier, data.EncapContentInfo);
+				info = new ContentInfo(CmsObjectIdentifiers.CompressedData, data);
+
+				if (!Arrays.AreEqual(info.GetEncoded(), compData))
+				{
+					return new SimpleTestResult(false, Name + ": CMS compression failed to re-encode");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": CMS compression failed - " + e.ToString(), e);
+			}
+		}
+
+		private ITestResult EnvelopedTest()
+		{
+			try
+			{
+				// Key trans
+				ContentInfo info = ContentInfo.GetInstance(
+					Asn1Object.FromByteArray(envDataKeyTrns));
+				EnvelopedData envData = EnvelopedData.GetInstance(info.Content);
+				Asn1Set s = envData.RecipientInfos;
+
+				if (s.Count != 1)
+				{
+					return new SimpleTestResult(false, Name + ": CMS KeyTrans enveloped, wrong number of recipients");
+				}
+
+				RecipientInfo recip = RecipientInfo.GetInstance(s[0]);
+
+				if (recip.Info is KeyTransRecipientInfo)
+				{
+					KeyTransRecipientInfo inf = KeyTransRecipientInfo.GetInstance(recip.Info);
+
+					inf = new KeyTransRecipientInfo(inf.RecipientIdentifier, inf.KeyEncryptionAlgorithm, inf.EncryptedKey);
+
+					s = new DerSet(new RecipientInfo(inf));
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": CMS KeyTrans enveloped, wrong recipient type");
+				}
+
+				envData = new EnvelopedData(envData.OriginatorInfo, s, envData.EncryptedContentInfo, envData.UnprotectedAttrs);
+				info = new ContentInfo(CmsObjectIdentifiers.EnvelopedData, envData);
+
+				if (!Arrays.AreEqual(info.GetEncoded(), envDataKeyTrns))
+				{
+					return new SimpleTestResult(false, Name + ": CMS KeyTrans enveloped failed to re-encode");
+				}
+
+
+				// KEK
+				info = ContentInfo.GetInstance(
+					Asn1Object.FromByteArray(envDataKEK));
+				envData = EnvelopedData.GetInstance(info.Content);
+				s = envData.RecipientInfos;
+
+				if (s.Count != 1)
+				{
+					return new SimpleTestResult(false, Name + ": CMS KEK enveloped, wrong number of recipients");
+				}
+
+				recip = RecipientInfo.GetInstance(s[0]);
+
+				if (recip.Info is KekRecipientInfo)
+				{
+					KekRecipientInfo inf = KekRecipientInfo.GetInstance(recip.Info);
+
+					inf = new KekRecipientInfo(inf.KekID, inf.KeyEncryptionAlgorithm, inf.EncryptedKey);
+
+					s = new DerSet(new RecipientInfo(inf));
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": CMS KEK enveloped, wrong recipient type");
+				}
+
+				envData = new EnvelopedData(envData.OriginatorInfo, s, envData.EncryptedContentInfo, envData.UnprotectedAttrs);
+				info = new ContentInfo(CmsObjectIdentifiers.EnvelopedData, envData);
+
+				if (!Arrays.AreEqual(info.GetEncoded(), envDataKEK))
+				{
+					return new SimpleTestResult(false, Name + ": CMS KEK enveloped failed to re-encode");
+				}
+
+				// Nested NDEF problem
+				Asn1StreamParser asn1In = new Asn1StreamParser(new MemoryStream(envDataNestedNDEF, false));
+				ContentInfoParser ci = new ContentInfoParser((Asn1SequenceParser)asn1In.ReadObject());
+				EnvelopedDataParser ed = new EnvelopedDataParser((Asn1SequenceParser)ci
+					.GetContent(Asn1Tags.Sequence));
+				Touch(ed.Version);
+				ed.GetOriginatorInfo();
+				ed.GetRecipientInfos().ToAsn1Object();
+				EncryptedContentInfoParser eci = ed.GetEncryptedContentInfo();
+				Touch(eci.ContentType);
+				Touch(eci.ContentEncryptionAlgorithm);
+
+				Stream dataIn = ((Asn1OctetStringParser)eci.GetEncryptedContent(Asn1Tags.OctetString))
+					.GetOctetStream();
+				Streams.Drain(dataIn);
+				dataIn.Close();
+
+				// Test data doesn't have unprotected attrs, bug was being thrown by this call
+				Asn1SetParser upa = ed.GetUnprotectedAttrs();
+				if (upa != null)
+				{
+					upa.ToAsn1Object();
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": CMS enveloped failed - " + e.ToString(), e);
+			}
+		}
+
+		private ITestResult SignedTest()
+		{
+			try
+			{
+				ContentInfo info = ContentInfo.GetInstance(
+					Asn1Object.FromByteArray(signedData));
+				SignedData sData = SignedData.GetInstance(info.Content);
+
+				sData = new SignedData(sData.DigestAlgorithms, sData.EncapContentInfo, sData.Certificates, sData.CRLs, sData.SignerInfos);
+				info = new ContentInfo(CmsObjectIdentifiers.SignedData, sData);
+
+				if (!Arrays.AreEqual(info.GetEncoded(), signedData))
+				{
+					return new SimpleTestResult(false, Name + ": CMS signed failed to re-encode");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": CMS signed failed - " + e.ToString(), e);
+			}
+		}
+
+		public ITestResult Perform()
+		{
+			ITestResult res = CompressionTest();
+
+			if (!res.IsSuccessful())
+			{
+				return res;
+			}
+
+			res = EnvelopedTest();
+			if (!res.IsSuccessful())
+			{
+				return res;
+			}
+
+			return SignedTest();
+		}
+
+		public string Name
+		{
+			get { return "CMS"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new CmsTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/CertHashUnitTest.cs b/crypto/test/src/asn1/test/CertHashUnitTest.cs
new file mode 100644
index 000000000..1e271a9c0
--- /dev/null
+++ b/crypto/test/src/asn1/test/CertHashUnitTest.cs
@@ -0,0 +1,93 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.Ocsp;
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class CertHashUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "CertHash"; }
+		}
+
+		public override void PerformTest()
+		{
+			AlgorithmIdentifier algId = new AlgorithmIdentifier(new DerObjectIdentifier("1.2.2.3"));
+			byte[] digest = new byte[20];
+
+			CertHash certID = new CertHash(algId, digest);
+
+			checkConstruction(certID, algId, digest);
+
+			certID = CertHash.GetInstance(null);
+
+			if (certID != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				CertHash.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			CertHash			certHash,
+			AlgorithmIdentifier	algId,
+			byte[]				digest)
+		{
+			checkValues(certHash, algId, digest);
+
+			certHash = CertHash.GetInstance(certHash);
+
+			checkValues(certHash, algId, digest);
+
+			Asn1InputStream aIn = new Asn1InputStream(certHash.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			certHash = CertHash.GetInstance(seq);
+
+			checkValues(certHash, algId, digest);
+		}
+
+		private void checkValues(
+			CertHash certHash,
+			AlgorithmIdentifier algId,
+			byte[] digest)
+		{
+			checkMandatoryField("algorithmHash", algId, certHash.HashAlgorithm);
+
+			checkMandatoryField("certificateHash", digest, certHash.CertificateHash);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CertHashUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/CertificateTest.cs b/crypto/test/src/asn1/test/CertificateTest.cs
new file mode 100644
index 000000000..532e81aba
--- /dev/null
+++ b/crypto/test/src/asn1/test/CertificateTest.cs
@@ -0,0 +1,395 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class CertificateTest
+		: SimpleTest
+	{
+		//
+		// server.crt
+		//
+		private static readonly byte[] cert1 = Base64.Decode(
+			"MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+			+ "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+			+ "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+			+ "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+			+ "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+			+ "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+			+ "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+			+ "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+			+ "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+			+ "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+			+ "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+			+ "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+			+ "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+			+ "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+			+ "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+			+ "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+			+ "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+			+ "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+			+ "5/8=");
+
+		//
+		// ca.crt
+		//
+		private static readonly byte[] cert2 = Base64.Decode(
+			"MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+			+ "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+			+ "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+			+ "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+			+ "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+			+ "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+			+ "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+			+ "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+			+ "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+			+ "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+			+ "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+			+ "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+			+ "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+			+ "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+			+ "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+			+ "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+			+ "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+			+ "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+			+ "DhkaJ8VqOMajkQFma2r9iA==");
+
+		//
+		// testx509.pem
+		//
+		private static readonly byte[] cert3 = Base64.Decode(
+			"MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+			+ "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+			+ "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+			+ "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+			+ "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+			+ "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+			+ "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+			+ "zl9HYIMxATFyqSiD9jsx");
+
+		//
+		// v3-cert1.pem
+		//
+		private static readonly byte[] cert4 = Base64.Decode(
+			"MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+			+ "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+			+ "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+			+ "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+			+ "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+			+ "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+			+ "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+			+ "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+			+ "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+			+ "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+			+ "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+			+ "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+			+ "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+			+ "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+		//
+		// v3-cert2.pem
+		//
+		private static readonly byte[] cert5 = Base64.Decode(
+			"MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+			+ "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+			+ "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+			+ "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+			+ "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+			+ "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+			+ "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+			+ "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+			+ "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+			+ "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+			+ "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+			+ "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+			+ "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+			+ "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+		private static readonly byte[] cert6 = Base64.Decode(
+			"MIIEDjCCAvagAwIBAgIEFAAq2jANBgkqhkiG9w0BAQUFADBLMSowKAYDVQQDEyFT"
+			+ "dW4gTWljcm9zeXN0ZW1zIEluYyBDQSAoQ2xhc3MgQikxHTAbBgNVBAoTFFN1biBN"
+			+ "aWNyb3N5c3RlbXMgSW5jMB4XDTA0MDIyOTAwNDMzNFoXDTA5MDMwMTAwNDMzNFow"
+			+ "NzEdMBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxFjAUBgNVBAMTDXN0b3Jl"
+			+ "LnN1bi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAP9ErzFT7MPg2bVV"
+			+ "LNmHTgN4kmiRNlPpuLGWS7EDIXYBbLeSSOCp/e1ANcOGnsuf0WIq9ejd/CPyEfh4"
+			+ "sWoVvQzpOfHZ/Jyei29PEuxzWT+4kQmCx3+sLK25lAnDFsz1KiFmB6Y3GJ/JSjpp"
+			+ "L0Yy1R9YlIc82I8gSw44y5JDABW5AgMBAAGjggGQMIIBjDAOBgNVHQ8BAf8EBAMC"
+			+ "BaAwHQYDVR0OBBYEFG1WB3PApZM7OPPVWJ31UrERaoKWMEcGA1UdIARAMD4wPAYL"
+			+ "YIZIAYb3AIN9k18wLTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5zdW4uY29tL3Br"
+			+ "aS9jcHMuaHRtbDCBhQYDVR0fBH4wfDB6oCegJYYjaHR0cDovL3d3dy5zdW4uY29t"
+			+ "L3BraS9wa2lzbWljYS5jcmyiT6RNMEsxKjAoBgNVBAMTIVN1biBNaWNyb3N5c3Rl"
+			+ "bXMgSW5jIENBIChDbGFzcyBCKTEdMBsGA1UEChMUU3VuIE1pY3Jvc3lzdGVtcyBJ"
+			+ "bmMwHwYDVR0jBBgwFoAUT7ZnqR/EEBSgG6h1wdYMI5RiiWswVAYIKwYBBQUHAQEE"
+			+ "SDBGMB0GCCsGAQUFBzABhhFodHRwOi8vdmEuc3VuLmNvbTAlBggrBgEFBQcwAYYZ"
+			+ "aHR0cDovL3ZhLmNlbnRyYWwuc3VuLmNvbTATBgNVHSUEDDAKBggrBgEFBQcDATAN"
+			+ "BgkqhkiG9w0BAQUFAAOCAQEAq3byQgyU24tBpR07iQK7agm1zQyzDQ6itdbji0ln"
+			+ "T7fOd5Pnp99iig8ovwWliNtXKAmgtJY60jWz7nEuk38AioZJhS+RPWIWX/+2PRV7"
+			+ "s2aWTzM3n43BypD+jU2qF9c9kDWP/NW9K9IcrS7SfU/2MZVmiCMD/9FEL+CWndwE"
+			+ "JJQ/oenXm44BFISI/NjV7fMckN8EayPvgtzQkD5KnEiggOD6HOrwTDFR+tmAEJ0K"
+			+ "ZttQNwOzCOcEdxXTg6qBHUbONdL7bjTT5NzV+JR/bnfiCqHzdnGwfbHzhmrnXw8j"
+			+ "QCVXcfBfL9++nmpNNRlnJMRdYGeCY6OAfh/PRo8/fXak1Q==");
+
+		private static readonly byte[] cert7 = Base64.Decode(
+			"MIIFJDCCBAygAwIBAgIKEcJZuwAAAAAABzANBgkqhkiG9w0BAQUFADAPMQ0wCwYD"
+			+ "VQQDEwRNU0NBMB4XDTA0MDUyMjE2MTM1OFoXDTA1MDUyMjE2MjM1OFowaTEbMBkG"
+			+ "CSqGSIb3DQEJCBMMMTkyLjE2OC4xLjMzMScwJQYJKoZIhvcNAQkCExhwaXhmaXJl"
+			+ "d2FsbC5jaXNjb3BpeC5jb20xITAfBgNVBAMTGHBpeGZpcmV3YWxsLmNpc2NvcGl4"
+			+ "LmNvbTB8MA0GCSqGSIb3DQEBAQUAA2sAMGgCYQCbcsY7vrjweXZiFQdhUafEjJV+"
+			+ "HRy5UKmuCy0237ffmYrN+XNLw0h90cdCSK6KPZebd2E2Bc2UmTikc/FY8meBT3/E"
+			+ "O/Osmywzi++Ur8/IrDvtuR1zd0c/xEPnV1ZRezkCAwEAAaOCAs4wggLKMAsGA1Ud"
+			+ "DwQEAwIFoDAdBgNVHQ4EFgQUzJBSxkQiN9TKvhTMQ1/Aq4gZnHswHwYDVR0jBBgw"
+			+ "FoAUMsxzXVh+5UKMNpwNHmqSfcRYfJ4wgfcGA1UdHwSB7zCB7DCB6aCB5qCB44aB"
+			+ "r2xkYXA6Ly8vQ049TVNDQSxDTj1NQVVELENOPUNEUCxDTj1QdWJsaWMlMjBLZXkl"
+			+ "MjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWludCxE"
+			+ "Qz1wcmltZWtleSxEQz1zZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/"
+			+ "b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGL2h0dHA6Ly9tYXVkLmlu"
+			+ "dC5wcmltZWtleS5zZS9DZXJ0RW5yb2xsL01TQ0EuY3JsMIIBEAYIKwYBBQUHAQEE"
+			+ "ggECMIH/MIGqBggrBgEFBQcwAoaBnWxkYXA6Ly8vQ049TVNDQSxDTj1BSUEsQ049"
+			+ "UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJh"
+			+ "dGlvbixEQz1pbnQsREM9cHJpbWVrZXksREM9c2U/Y0FDZXJ0aWZpY2F0ZT9iYXNl"
+			+ "P29iamVjdENsYXNzPWNlcnRpZmljYXRpb25BdXRob3JpdHkwUAYIKwYBBQUHMAKG"
+			+ "RGh0dHA6Ly9tYXVkLmludC5wcmltZWtleS5zZS9DZXJ0RW5yb2xsL01BVUQuaW50"
+			+ "LnByaW1la2V5LnNlX01TQ0EuY3J0MCwGA1UdEQEB/wQiMCCCGHBpeGZpcmV3YWxs"
+			+ "LmNpc2NvcGl4LmNvbYcEwKgBITA/BgkrBgEEAYI3FAIEMh4wAEkAUABTAEUAQwBJ"
+			+ "AG4AdABlAHIAbQBlAGQAaQBhAHQAZQBPAGYAZgBsAGkAbgBlMA0GCSqGSIb3DQEB"
+			+ "BQUAA4IBAQCa0asiPbObLJjpSz6ndJ7y4KOWMiuuBc/VQBnLr7RBCF3ZlZ6z1+e6"
+			+ "dmv8se/z11NgateKfxw69IhLCriA960HEgX9Z61MiVG+DrCFpbQyp8+hPFHoqCZN"
+			+ "b7upc8k2OtJW6KPaP9k0DW52YQDIky4Vb2rZeC4AMCorWN+KlndHhr1HFA14HxwA"
+			+ "4Mka0FM6HNWnBV2UmTjBZMDr/OrGH1jLYIceAaZK0X2R+/DWXeeqIga8jwP5empq"
+			+ "JetYnkXdtTbEh3xL0BX+mZl8vDI+/PGcwox/7YjFmyFWphRMxk9CZ3rF2/FQWMJP"
+			+ "YqQpKiQOmQg5NAhcwffLAuVjVVibPYqi");
+
+		private static readonly byte[] cert8 = Base64.Decode(
+			"MIIB0zCCATwCAQEwbqBsMGekZTBjMQswCQYDVQQGEwJERTELMAkGA1UECBMCQlkx"
+			+ "EzARBgNVBAcTClJlZ2Vuc2J1cmcxEDAOBgNVBAoTB0FDIFRlc3QxCzAJBgNVBAsT"
+			+ "AkNBMRMwEQYDVQQDEwpBQyBUZXN0IENBAgEBoHYwdKRyMHAxCzAJBgNVBAYTAkRF"
+			+ "MQswCQYDVQQIEwJCWTETMBEGA1UEBxMKUmVnZW5zYnVyZzESMBAGA1UEChMJQUMg"
+			+ "SXNzdWVyMRowGAYDVQQLExFBQyBJc3N1ZXIgc2VjdGlvbjEPMA0GA1UEAxMGQUMg"
+			+ "TWFuMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIwMDQxMTI2MTI1MjUxWhgPMjAwNDEy"
+			+ "MzEyMzAwMDBaMBkwFwYDVRhIMRAwDoEMREFVMTIzNDU2Nzg5MA0GCSqGSIb3DQEB"
+			+ "BQUAA4GBABd4Odx3yEMGL/BvItuT1RafNR2uuWuZbajg0pD6bshUsl+WCIfRiEkq"
+			+ "lHMkpI7WqAZikdnAEQ5jQsVWEuVejWxR6gjejKxc0fb9qpIui7/GoI5Eh6dmG20e"
+			+ "xbwJL3+6YYFrZwxR8cC5rPvWrblUR5XKJy+Zp/H5+t9iANnL1L8J");
+
+		private static readonly string[] subjects =
+		{
+			"C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Webserver Team,CN=www2.connect4.com.au,E=webmaster@connect4.com.au",
+			"C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Certificate Authority,CN=Connect 4 CA,E=webmaster@connect4.com.au",
+			"C=AU,ST=QLD,CN=SSLeay/rsa test cert",
+			"C=US,O=National Aeronautics and Space Administration,SERIALNUMBER=16+CN=Steve Schoch",
+			"E=cooke@issl.atl.hp.com,C=US,OU=Hewlett Packard Company (ISSL),CN=Paul A. Cooke",
+			"O=Sun Microsystems Inc,CN=store.sun.com",
+			"unstructuredAddress=192.168.1.33,unstructuredName=pixfirewall.ciscopix.com,CN=pixfirewall.ciscopix.com"
+		};
+
+		public override string Name
+		{
+			get { return "Certificate"; }
+		}
+
+		public void CheckCertificate(
+			int		id,
+			byte[]	cert)
+		{
+			Asn1Object seq = Asn1Object.FromByteArray(cert);
+			string dump = Asn1Dump.DumpAsString(seq);
+
+			X509CertificateStructure obj = X509CertificateStructure.GetInstance(seq);
+			TbsCertificateStructure tbsCert = obj.TbsCertificate;
+
+			if (!tbsCert.Subject.ToString().Equals(subjects[id - 1]))
+			{
+				Fail("failed subject test for certificate id " + id
+					+ " got " + tbsCert.Subject.ToString());
+			}
+
+			if (tbsCert.Version == 3)
+			{
+				X509Extensions ext = tbsCert.Extensions;
+				if (ext != null)
+				{
+					foreach (DerObjectIdentifier oid in ext.ExtensionOids)
+					{
+						X509Extension extVal = ext.GetExtension(oid);
+						Asn1Object extObj = Asn1Object.FromByteArray(extVal.Value.GetOctets());
+
+						if (oid.Equals(X509Extensions.SubjectKeyIdentifier))
+						{
+							SubjectKeyIdentifier.GetInstance(extObj);
+						}
+						else if (oid.Equals(X509Extensions.KeyUsage))
+						{
+							KeyUsage.GetInstance(extObj);
+						}
+						else if (oid.Equals(X509Extensions.ExtendedKeyUsage))
+						{
+							ExtendedKeyUsage ku = ExtendedKeyUsage.GetInstance(extObj);
+
+							Asn1Sequence sq = (Asn1Sequence)ku.ToAsn1Object();
+							for (int i = 0; i != sq.Count; i++)
+							{
+								KeyPurposeID.GetInstance(sq[i]);
+							}
+						}
+						else if (oid.Equals(X509Extensions.SubjectAlternativeName))
+						{
+							GeneralNames gn = GeneralNames.GetInstance(extObj);
+
+							Asn1Sequence sq = (Asn1Sequence)gn.ToAsn1Object();
+							for (int i = 0; i != sq.Count; i++)
+							{
+								GeneralName.GetInstance(sq[i]);
+							}
+						}
+						else if (oid.Equals(X509Extensions.IssuerAlternativeName))
+						{
+							GeneralNames gn = GeneralNames.GetInstance(extObj);
+
+							Asn1Sequence sq = (Asn1Sequence)gn.ToAsn1Object();
+							for (int i = 0; i != sq.Count; i++)
+							{
+								GeneralName.GetInstance(sq[i]);
+							}
+						}
+						else if (oid.Equals(X509Extensions.CrlDistributionPoints))
+						{
+							CrlDistPoint p = CrlDistPoint.GetInstance(extObj);
+
+							DistributionPoint[] points = p.GetDistributionPoints();
+							for (int i = 0; i != points.Length; i++)
+							{
+								// do nothing
+							}
+						}
+						else if (oid.Equals(X509Extensions.CertificatePolicies))
+						{
+							Asn1Sequence cp = (Asn1Sequence) extObj;
+
+							for (int i = 0; i != cp.Count; i++)
+							{
+								PolicyInformation.GetInstance(cp[i]);
+							}
+						}
+						else if (oid.Equals(X509Extensions.AuthorityKeyIdentifier))
+						{
+							AuthorityKeyIdentifier.GetInstance(extObj);
+						}
+						else if (oid.Equals(X509Extensions.BasicConstraints))
+						{
+							BasicConstraints.GetInstance(extObj);
+						}
+						else
+						{
+							//Console.WriteLine(oid.Id);
+						}
+					}
+				}
+			}
+		}
+
+		public void CheckAttributeCertificate(
+			int		id,
+			byte[]	cert)
+		{
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(cert);
+			string dump = Asn1Dump.DumpAsString(seq);
+
+			AttributeCertificate obj = AttributeCertificate.GetInstance(seq);
+			AttributeCertificateInfo acInfo = obj.ACInfo;
+
+			// Version
+			if (!(acInfo.Version.Equals(new DerInteger(1)))
+				&& (!(acInfo.Version.Equals(new DerInteger(2)))))
+			{
+				Fail("failed AC Version test for id " + id);
+			}
+
+			// Holder
+			Holder h = acInfo.Holder;
+			if (h == null)
+			{
+				Fail("failed AC Holder test, it's null, for id " + id);
+			}
+
+			// Issuer
+			AttCertIssuer aci = acInfo.Issuer;
+			if (aci == null)
+			{
+				Fail("failed AC Issuer test, it's null, for id " + id);
+			}
+
+			// Signature
+			AlgorithmIdentifier sig = acInfo.Signature;
+			if (sig == null)
+			{
+				Fail("failed AC Signature test for id " + id);
+			}
+
+			// Serial
+			DerInteger serial = acInfo.SerialNumber;
+
+			// Validity
+			AttCertValidityPeriod validity = acInfo.AttrCertValidityPeriod;
+			if (validity == null)
+			{
+				Fail("failed AC AttCertValidityPeriod test for id " + id);
+			}
+
+			// Attributes
+			Asn1Sequence attribSeq = acInfo.Attributes;
+			AttributeX509[] att = new AttributeX509[attribSeq.Count];
+			for (int i = 0; i < attribSeq.Count; i++)
+			{
+				att[i] = AttributeX509.GetInstance(attribSeq[i]);
+			}
+
+			// IssuerUniqueId
+			// TODO, how to best test?
+
+			// X509 Extensions
+			X509Extensions ext = acInfo.Extensions;
+			if (ext != null)
+			{
+				foreach (DerObjectIdentifier oid in ext.ExtensionOids)
+				{
+					X509Extension extVal = ext.GetExtension(oid);
+				}
+			}
+		}
+
+		public override void PerformTest()
+		{
+			CheckCertificate(1, cert1);
+			CheckCertificate(2, cert2);
+			CheckCertificate(3, cert3);
+			CheckCertificate(4, cert4);
+			CheckCertificate(5, cert5);
+			CheckCertificate(6, cert6);
+			CheckCertificate(7, cert7);
+			CheckAttributeCertificate(8, cert8);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CertificateTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/CommitmentTypeIndicationUnitTest.cs b/crypto/test/src/asn1/test/CommitmentTypeIndicationUnitTest.cs
new file mode 100644
index 000000000..20c2d18e3
--- /dev/null
+++ b/crypto/test/src/asn1/test/CommitmentTypeIndicationUnitTest.cs
@@ -0,0 +1,107 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Esf;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class CommitmentTypeIndicationUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "CommitmentTypeIndication"; }
+        }
+
+		public override void PerformTest()
+        {
+            CommitmentTypeIndication cti = new CommitmentTypeIndication(CommitmentTypeIdentifier.ProofOfOrigin);
+
+            CheckConstruction(cti, CommitmentTypeIdentifier.ProofOfOrigin, null);
+
+            Asn1Sequence qualifier = new DerSequence(new DerObjectIdentifier("1.2"));
+
+            cti = new CommitmentTypeIndication(CommitmentTypeIdentifier.ProofOfOrigin, qualifier);
+
+            CheckConstruction(cti, CommitmentTypeIdentifier.ProofOfOrigin, qualifier);
+
+            cti = CommitmentTypeIndication.GetInstance(null);
+
+            if (cti != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+            try
+            {
+                CommitmentTypeIndication.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        private void CheckConstruction(
+            CommitmentTypeIndication mv,
+            DerObjectIdentifier commitmenttTypeId,
+            Asn1Encodable qualifier)
+        {
+            CheckStatement(mv, commitmenttTypeId, qualifier);
+
+			mv = CommitmentTypeIndication.GetInstance(mv);
+
+			CheckStatement(mv, commitmenttTypeId, qualifier);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				mv.ToAsn1Object().GetEncoded());
+
+			mv = CommitmentTypeIndication.GetInstance(seq);
+
+			CheckStatement(mv, commitmenttTypeId, qualifier);
+        }
+
+		private void CheckStatement(
+            CommitmentTypeIndication cti,
+            DerObjectIdentifier     commitmentTypeId,
+            Asn1Encodable           qualifier)
+        {
+            if (!cti.CommitmentTypeID.Equals(commitmentTypeId))
+            {
+                Fail("commitmentTypeIds don't match.");
+            }
+
+            if (qualifier != null)
+            {
+                if (!cti.CommitmentTypeQualifier.Equals(qualifier))
+                {
+                    Fail("qualifiers don't match.");
+                }
+            }
+            else if (cti.CommitmentTypeQualifier != null)
+            {
+                Fail("qualifier found when none expected.");
+            }
+        }
+
+        public static void Main(
+            string[]    args)
+        {
+            RunTest(new CommitmentTypeIndicationUnitTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/CommitmentTypeQualifierUnitTest.cs b/crypto/test/src/asn1/test/CommitmentTypeQualifierUnitTest.cs
new file mode 100644
index 000000000..192ac52f6
--- /dev/null
+++ b/crypto/test/src/asn1/test/CommitmentTypeQualifierUnitTest.cs
@@ -0,0 +1,107 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Esf;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class CommitmentTypeQualifierUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "CommitmentTypeQualifier"; }
+        }
+
+		public override void PerformTest()
+        {
+            CommitmentTypeQualifier ctq = new CommitmentTypeQualifier(CommitmentTypeIdentifier.ProofOfOrigin);
+
+            CheckConstruction(ctq, CommitmentTypeIdentifier.ProofOfOrigin, null);
+
+            Asn1Encodable info = new DerObjectIdentifier("1.2");
+
+            ctq = new CommitmentTypeQualifier(CommitmentTypeIdentifier.ProofOfOrigin, info);
+
+            CheckConstruction(ctq, CommitmentTypeIdentifier.ProofOfOrigin, info);
+
+            ctq = CommitmentTypeQualifier.GetInstance(null);
+
+            if (ctq != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+            try
+            {
+                CommitmentTypeQualifier.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        private void CheckConstruction(
+            CommitmentTypeQualifier mv,
+            DerObjectIdentifier commitmenttTypeId,
+            Asn1Encodable qualifier)
+        {
+            CheckStatement(mv, commitmenttTypeId, qualifier);
+
+			mv = CommitmentTypeQualifier.GetInstance(mv);
+
+			CheckStatement(mv, commitmenttTypeId, qualifier);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				mv.ToAsn1Object().GetEncoded());
+
+			mv = CommitmentTypeQualifier.GetInstance(seq);
+
+			CheckStatement(mv, commitmenttTypeId, qualifier);
+        }
+
+		private void CheckStatement(
+            CommitmentTypeQualifier ctq,
+            DerObjectIdentifier     commitmentTypeId,
+            Asn1Encodable           qualifier)
+        {
+            if (!ctq.CommitmentTypeIdentifier.Equals(commitmentTypeId))
+            {
+                Fail("commitmentTypeIds don't match.");
+            }
+
+            if (qualifier != null)
+            {
+                if (!ctq.Qualifier.Equals(qualifier))
+                {
+                    Fail("qualifiers don't match.");
+                }
+            }
+            else if (ctq.Qualifier != null)
+            {
+                Fail("qualifier found when none expected.");
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new CommitmentTypeQualifierUnitTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/ContentHintsUnitTest.cs b/crypto/test/src/asn1/test/ContentHintsUnitTest.cs
new file mode 100644
index 000000000..d7453c27e
--- /dev/null
+++ b/crypto/test/src/asn1/test/ContentHintsUnitTest.cs
@@ -0,0 +1,93 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Ess;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class ContentHintsUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "ContentHints"; }
+		}
+
+		public override void PerformTest()
+		{
+			DerUtf8String contentDescription = new DerUtf8String("Description");
+			DerObjectIdentifier contentType = new DerObjectIdentifier("1.2.2.3");
+
+			ContentHints hints = new ContentHints(contentType);
+
+			checkConstruction(hints, contentType, null);
+
+			hints = new ContentHints(contentType, contentDescription);
+
+			checkConstruction(hints, contentType, contentDescription);
+
+			hints = ContentHints.GetInstance(null);
+
+			if (hints != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				ContentHints.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			ContentHints		hints,
+			DerObjectIdentifier	contentType,
+			DerUtf8String		description)
+		{
+			checkValues(hints, contentType, description);
+
+			hints = ContentHints.GetInstance(hints);
+
+			checkValues(hints, contentType, description);
+
+			Asn1InputStream aIn = new Asn1InputStream(hints.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			hints = ContentHints.GetInstance(seq);
+
+			checkValues(hints, contentType, description);
+		}
+
+		private void checkValues(
+			ContentHints		hints,
+			DerObjectIdentifier	contentType,
+			DerUtf8String		description)
+		{
+			checkMandatoryField("contentType", contentType, hints.ContentType);
+			checkOptionalField("description", description, hints.ContentDescription);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ContentHintsUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/CscaMasterListTest.cs b/crypto/test/src/asn1/test/CscaMasterListTest.cs
new file mode 100644
index 000000000..814e98b2a
--- /dev/null
+++ b/crypto/test/src/asn1/test/CscaMasterListTest.cs
@@ -0,0 +1,57 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Icao;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class CscaMasterListTest
+        : SimpleTest
+    {
+		public override string Name
+		{
+			get { return "CscaMasterList"; }
+		}
+
+		public override void PerformTest() 
+		{
+			byte[] input = GetInput("masterlist-content.data");
+			CscaMasterList parsedList = CscaMasterList.GetInstance(Asn1Object.FromByteArray(input));
+
+			if (parsedList.GetCertStructs().Length != 3)
+			{
+				Fail("Cert structure parsing failed: incorrect length");
+			}
+
+			byte[] output = parsedList.GetEncoded();
+			if (!AreEqual(input, output))
+			{
+				Fail("Encoding failed after parse");
+			}
+		}
+
+		private byte[] GetInput(string name)
+		{
+			return Streams.ReadAll(SimpleTest.GetTestDataAsStream("asn1." + name));
+		}
+
+		public static void Main(
+            string[] args)
+        {
+            RunTest(new CscaMasterListTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+	}
+}
diff --git a/crypto/test/src/asn1/test/DERApplicationSpecificTest.cs b/crypto/test/src/asn1/test/DERApplicationSpecificTest.cs
new file mode 100644
index 000000000..a61ae87e8
--- /dev/null
+++ b/crypto/test/src/asn1/test/DERApplicationSpecificTest.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class DerApplicationSpecificTest
+		: SimpleTest
+	{
+		private static readonly byte[] impData = Hex.Decode("430109");
+
+		private static readonly byte[] certData = Hex.Decode(
+			  "7F218201897F4E8201495F290100420E44454356434145504153533030317F49"
+			+ "81FD060A04007F00070202020202811CD7C134AA264366862A18302575D1D787"
+			+ "B09F075797DA89F57EC8C0FF821C68A5E62CA9CE6C1C299803A6C1530B514E18"
+			+ "2AD8B0042A59CAD29F43831C2580F63CCFE44138870713B1A92369E33E2135D2"
+			+ "66DBB372386C400B8439040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C"
+			+ "1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D376"
+			+ "1402CD851CD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A793"
+			+ "9F863904393EE8E06DB6C7F528F8B4260B49AA93309824D92CDB1807E5437EE2"
+			+ "E26E29B73A7111530FA86B350037CB9415E153704394463797139E148701015F"
+			+ "200E44454356434145504153533030317F4C0E060904007F0007030102015301"
+			+ "C15F25060007000400015F24060009000400015F37384CCF25C59F3612EEE188"
+			+ "75F6C5F2E2D21F0395683B532A26E4C189B71EFE659C3F26E0EB9AEAE9986310"
+			+ "7F9B0DADA16414FFA204516AEE2B");
+
+		public override string Name
+		{
+			get { return "DerApplicationSpecific"; }
+		}
+
+		public override void PerformTest()
+		{
+			DerInteger val = new DerInteger(9);
+
+			DerApplicationSpecific tagged = new DerApplicationSpecific(false, 3, val);
+
+			if (!AreEqual(impData, tagged.GetEncoded()))
+			{
+				Fail("implicit encoding failed");
+			}
+
+			DerInteger recVal = (DerInteger) tagged.GetObject(Asn1Tags.Integer);
+
+			if (!val.Equals(recVal))
+			{
+				Fail("implicit read back failed");
+			}
+
+			DerApplicationSpecific certObj = (DerApplicationSpecific)
+				Asn1Object.FromByteArray(certData);
+
+			if (!certObj.IsConstructed() || certObj.ApplicationTag != 33)
+			{
+				Fail("parsing of certificate data failed");
+			}
+
+			byte[] encoded = certObj.GetDerEncoded();
+
+			if (!Arrays.AreEqual(certData, encoded))
+			{
+				Console.WriteLine(Encoding.ASCII.GetString(certData, 0, certData.Length).Substring(0, 20));
+				Console.WriteLine(Encoding.ASCII.GetString(encoded, 0, encoded.Length).Substring(0, 20));
+				Fail("re-encoding of certificate data failed");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new DerApplicationSpecificTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/DERUTF8StringTest.cs b/crypto/test/src/asn1/test/DERUTF8StringTest.cs
new file mode 100644
index 000000000..be4dace79
--- /dev/null
+++ b/crypto/test/src/asn1/test/DERUTF8StringTest.cs
@@ -0,0 +1,113 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class DerUtf8StringTest
+		: ITest
+	{
+		/**
+			* Unicode code point U+10400 coded as surrogate in two native Java UTF-16
+			* code units
+			*/
+		private readonly static char[] glyph1_utf16 = { (char)0xd801, (char)0xdc00 };
+
+		/**
+		 * U+10400 coded in UTF-8
+		 */
+		private readonly static byte[] glyph1_utf8 = { (byte)0xF0, (byte)0x90, (byte)0x90, (byte)0x80 };
+
+		/**
+		 * Unicode code point U+6771 in native Java UTF-16
+		 */
+		private readonly static char[] glyph2_utf16 = { (char)0x6771 };
+
+		/**
+		 * U+6771 coded in UTF-8
+		 */
+		private readonly static byte[] glyph2_utf8 = { (byte)0xE6, (byte)0x9D, (byte)0xB1 };
+
+		/**
+		 * Unicode code point U+00DF in native Java UTF-16
+		 */
+		private readonly static char[] glyph3_utf16 = { (char)0x00DF };
+
+		/**
+		 * U+00DF coded in UTF-8
+		 */
+		private readonly static byte[] glyph3_utf8 = { (byte)0xC3, (byte)0x9f };
+
+		/**
+		 * Unicode code point U+0041 in native Java UTF-16
+		 */
+		private readonly static char[] glyph4_utf16 = { (char)0x0041 };
+
+		/**
+		 * U+0041 coded in UTF-8
+		 */
+		private readonly static byte[] glyph4_utf8 = { 0x41 };
+
+		private readonly static byte[][] glyphs_utf8 = { glyph1_utf8, glyph2_utf8, glyph3_utf8, glyph4_utf8 };
+
+		private readonly static char[][] glyphs_utf16 = { glyph1_utf16, glyph2_utf16, glyph3_utf16, glyph4_utf16 };
+
+		public ITestResult Perform()
+		{
+			try
+			{
+				for (int i = 0; i < glyphs_utf16.Length; i++)
+				{
+					string s = new string(glyphs_utf16[i]);
+					byte[] b1 = new DerUtf8String(s).GetEncoded();
+					byte[] temp = new byte[b1.Length - 2];
+					Array.Copy(b1, 2, temp, 0, b1.Length - 2);
+					byte[] b2 = new DerUtf8String(new DerOctetString(temp).GetOctets()).GetEncoded();
+					if (!Arrays.AreEqual(b1, b2))
+					{
+						return new SimpleTestResult(false, Name + ": failed UTF-8 encoding and decoding");
+					}
+					if (!Arrays.AreEqual(temp, glyphs_utf8[i]))
+					{
+						return new SimpleTestResult(false, Name + ": failed UTF-8 encoding and decoding");
+					}
+				}
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed with Exception " + e.Message);
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public string Name
+		{
+			get
+			{
+				return "DERUTF8String";
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			DerUtf8StringTest test = new DerUtf8StringTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/DataGroupHashUnitTest.cs b/crypto/test/src/asn1/test/DataGroupHashUnitTest.cs
new file mode 100644
index 000000000..dcebf4670
--- /dev/null
+++ b/crypto/test/src/asn1/test/DataGroupHashUnitTest.cs
@@ -0,0 +1,106 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Icao;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class DataGroupHashUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "DataGroupHash"; }
+        }
+
+		private byte[] GenerateHash()
+        {
+            Random rand = new Random();
+            byte[] bytes = new byte[20];
+			rand.NextBytes(bytes);
+			return bytes;
+        }
+
+		public override void PerformTest()
+        {
+            int dataGroupNumber = 1;
+            Asn1OctetString dataHash = new DerOctetString(GenerateHash());
+            DataGroupHash dg = new DataGroupHash(dataGroupNumber, dataHash);
+
+            CheckConstruction(dg, dataGroupNumber, dataHash);
+
+			try
+			{
+				DataGroupHash.GetInstance(null);
+			}
+			catch (Exception)
+			{
+				Fail("GetInstance() failed to handle null.");
+			}
+
+			try
+            {
+                DataGroupHash.GetInstance(new object());
+
+				Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+		private void CheckConstruction(
+            DataGroupHash dg,
+            int dataGroupNumber,
+            Asn1OctetString     dataGroupHashValue)
+        {
+            CheckValues(dg, dataGroupNumber, dataGroupHashValue);
+
+			dg = DataGroupHash.GetInstance(dg);
+
+			CheckValues(dg, dataGroupNumber, dataGroupHashValue);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				dg.ToAsn1Object().GetEncoded());
+
+			dg = DataGroupHash.GetInstance(seq);
+
+			CheckValues(dg, dataGroupNumber, dataGroupHashValue);
+        }
+
+		private void CheckValues(
+            DataGroupHash	dg,
+            int				dataGroupNumber,
+            Asn1OctetString	dataGroupHashValue)
+        {
+            if (dg.DataGroupNumber != dataGroupNumber)
+            {
+                Fail("group number don't match.");
+            }
+
+			if (!dg.DataGroupHashValue.Equals(dataGroupHashValue))
+            {
+                Fail("hash value don't match.");
+            }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            RunTest(new DataGroupHashUnitTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/DeclarationOfMajorityUnitTest.cs b/crypto/test/src/asn1/test/DeclarationOfMajorityUnitTest.cs
new file mode 100644
index 000000000..bd1fb5a9e
--- /dev/null
+++ b/crypto/test/src/asn1/test/DeclarationOfMajorityUnitTest.cs
@@ -0,0 +1,97 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class DeclarationOfMajorityUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "DeclarationOfMajority"; }
+		}
+
+		public override void PerformTest()
+		{
+			DerGeneralizedTime dateOfBirth = new DerGeneralizedTime("20070315173729Z");
+			DeclarationOfMajority decl = new DeclarationOfMajority(dateOfBirth);
+
+			checkConstruction(decl, DeclarationOfMajority.Choice.DateOfBirth, dateOfBirth, -1);
+
+			decl = new DeclarationOfMajority(6);
+
+			checkConstruction(decl, DeclarationOfMajority.Choice.NotYoungerThan, null, 6);
+
+			decl = DeclarationOfMajority.GetInstance(null);
+
+			if (decl != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				DeclarationOfMajority.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			DeclarationOfMajority			decl,
+			DeclarationOfMajority.Choice	type,
+			DerGeneralizedTime				dateOfBirth,
+			int								notYoungerThan)
+		{
+			checkValues(decl, type, dateOfBirth, notYoungerThan);
+
+			decl = DeclarationOfMajority.GetInstance(decl);
+
+			checkValues(decl, type, dateOfBirth, notYoungerThan);
+
+			Asn1InputStream aIn = new Asn1InputStream(decl.ToAsn1Object().GetEncoded());
+
+			DerTaggedObject info = (DerTaggedObject) aIn.ReadObject();
+
+			decl = DeclarationOfMajority.GetInstance(info);
+
+			checkValues(decl, type, dateOfBirth, notYoungerThan);
+		}
+
+		private void checkValues(
+			DeclarationOfMajority			decl,
+			DeclarationOfMajority.Choice	type,
+			DerGeneralizedTime				dateOfBirth,
+			int								notYoungerThan)
+		{
+			checkMandatoryField("type", (int) type, (int) decl.Type);
+			checkOptionalField("dateOfBirth", dateOfBirth, decl.DateOfBirth);
+			if (notYoungerThan != -1 && notYoungerThan != decl.NotYoungerThan)
+			{
+				Fail("notYoungerThan mismatch");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new DeclarationOfMajorityUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/EncryptedPrivateKeyInfoTest.cs b/crypto/test/src/asn1/test/EncryptedPrivateKeyInfoTest.cs
new file mode 100644
index 000000000..a84df59cc
--- /dev/null
+++ b/crypto/test/src/asn1/test/EncryptedPrivateKeyInfoTest.cs
@@ -0,0 +1,152 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    /**
+     * Test the reading and writing of EncryptedPrivateKeyInfo objects using
+     * the test vectors provided at
+     * <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html">
+     * RSA's Pkcs5 Page</a>.
+     * <br/>
+     * The vectors are Base 64 encoded and encrypted using the password "password"
+     * (without quotes). They should all yield the same PrivateKeyInfo object.
+     */
+    [TestFixture]
+    public class EncryptedPrivateKeyInfoTest
+        : ITest
+    {
+		static byte[] sample1 = Base64.Decode(
+			  "MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA"
+			+ "MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y"
+			+ "9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ"
+			+ "0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo"
+			+ "f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO"
+			+ "Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v"
+			+ "aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks"
+			+ "2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM"
+			+ "75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA");
+
+		static byte[] sample2 = Base64.Decode(
+			  "MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA"
+			+ "MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/"
+			+ "koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8"
+			+ "+MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5"
+			+ "6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi"
+			+ "5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ"
+			+ "BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8"
+			+ "z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr"
+			+ "u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB");
+
+		static byte[] sample3 = Base64.Decode(
+			  "MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA"
+			+ "AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop"
+			+ "7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f"
+			+ "wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21"
+			+ "RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6"
+			+ "VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1"
+			+ "MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz"
+			+ "tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH"
+			+ "2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO"
+			+ "6DA=");
+
+		public string Name
+		{
+			get { return "EncryptedPrivateKeyInfoTest"; }
+		}
+
+        private ITestResult DoTest(
+            int		id,
+            byte[]	sample)
+        {
+            EncryptedPrivateKeyInfo info;
+            try
+            {
+				info = EncryptedPrivateKeyInfo.GetInstance(Asn1Object.FromByteArray(sample));
+            }
+            catch (Exception e)
+            {
+                return new SimpleTestResult(false, Name + ": test " + id + " failed construction - exception "
+                    + e.ToString());
+            }
+
+			byte[] bytes;
+            try
+            {
+            	bytes = info.GetDerEncoded();
+            }
+            catch (Exception e)
+            {
+                return new SimpleTestResult(false,
+                    Name + ": test " + id + " failed writing - exception " + e.ToString());
+            }
+
+            if (!Arrays.AreEqual(bytes, sample))
+            {
+                try
+                {
+                    Asn1Object obj = Asn1Object.FromByteArray(bytes);
+
+                    return new SimpleTestResult(false, Name + ": test " + id
+                        + " length mismatch - expected " + sample.Length + SimpleTest.NewLine
+                        + Asn1Dump.DumpAsString(info) + " got " + bytes.Length + SimpleTest.NewLine
+                        + Asn1Dump.DumpAsString(obj));
+                }
+                catch (Exception e)
+                {
+                    return new SimpleTestResult(false, Name + ": test " + id + " data mismatch - exception " + e.ToString());
+                }
+            }
+
+            return new SimpleTestResult(true, Name + ": test " + id + " Okay");
+        }
+
+        public ITestResult Perform()
+        {
+            ITestResult  result = DoTest(0, sample1);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            result = DoTest(1, sample2);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            result = DoTest(2, sample3);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new EncryptedPrivateKeyInfoTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/EnumeratedTest.cs b/crypto/test/src/asn1/test/EnumeratedTest.cs
new file mode 100644
index 000000000..29e90326b
--- /dev/null
+++ b/crypto/test/src/asn1/test/EnumeratedTest.cs
@@ -0,0 +1,115 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    /// <summary>
+    /// Tests used to verify correct decoding of the ENUMERATED type.
+    /// </summary>
+    [TestFixture]
+    public class EnumeratedTest
+    {
+        /// <summary>
+        /// Test vector used to test decoding of multiple items.
+        /// </summary>
+        /// <remarks>This sample uses an ENUMERATED and a BOOLEAN.</remarks>
+        private static readonly byte[] MultipleSingleByteItems = Hex.Decode("30060a01010101ff");
+
+        /// <summary>
+        /// Test vector used to test decoding of multiple items.
+        /// </summary>
+        /// <remarks>This sample uses two ENUMERATEDs.</remarks>
+        private static readonly byte[] MultipleDoubleByteItems = Hex.Decode("30080a0201010a020202");
+
+        /// <summary>
+        /// Test vector used to test decoding of multiple items.
+        /// </summary>
+        /// <remarks>This sample uses an ENUMERATED and an OBJECT IDENTIFIER.</remarks>
+        private static readonly byte[] MultipleTripleByteItems = Hex.Decode("300a0a0301010106032b0601");
+
+        /// <summary>
+        /// Makes sure multiple identically sized values are parsed correctly.
+        /// </summary>
+        [Test]
+        public void TestReadingMultipleSingleByteItems()
+        {
+            Asn1Object obj = Asn1Object.FromByteArray(MultipleSingleByteItems);
+
+            Assert.IsTrue(obj is DerSequence, "Null ASN.1 SEQUENCE");
+
+            DerSequence sequence = (DerSequence)obj;
+
+            Assert.AreEqual(2, sequence.Count, "2 items expected");
+
+            DerEnumerated enumerated = sequence[0] as DerEnumerated;
+
+            Assert.IsNotNull(enumerated, "ENUMERATED expected");
+
+            Assert.AreEqual(1, enumerated.Value.IntValue, "Unexpected ENUMERATED value");
+
+            DerBoolean boolean = sequence[1] as DerBoolean;
+
+            Assert.IsNotNull(boolean, "BOOLEAN expected");
+
+            Assert.IsTrue(boolean.IsTrue, "Unexpected BOOLEAN value");
+        }
+
+        /// <summary>
+        /// Makes sure multiple identically sized values are parsed correctly.
+        /// </summary>
+        [Test]
+        public void TestReadingMultipleDoubleByteItems()
+        {
+            Asn1Object obj = Asn1Object.FromByteArray(MultipleDoubleByteItems);
+
+            Assert.IsTrue(obj is DerSequence, "Null ASN.1 SEQUENCE");
+
+            DerSequence sequence = (DerSequence)obj;
+
+            Assert.AreEqual(2, sequence.Count, "2 items expected");
+
+            DerEnumerated enumerated1 = sequence[0] as DerEnumerated;
+
+            Assert.IsNotNull(enumerated1, "ENUMERATED expected");
+
+            Assert.AreEqual(257, enumerated1.Value.IntValue, "Unexpected ENUMERATED value");
+
+            DerEnumerated enumerated2 = sequence[1] as DerEnumerated;
+
+            Assert.IsNotNull(enumerated2, "ENUMERATED expected");
+
+            Assert.AreEqual(514, enumerated2.Value.IntValue, "Unexpected ENUMERATED value");
+        }
+
+        /// <summary>
+        /// Makes sure multiple identically sized values are parsed correctly.
+        /// </summary>
+        [Test]
+        public void TestReadingMultipleTripleByteItems()
+        {
+            Asn1Object obj = Asn1Object.FromByteArray(MultipleTripleByteItems);
+
+            Assert.IsTrue(obj is DerSequence, "Null ASN.1 SEQUENCE");
+
+            DerSequence sequence = (DerSequence)obj;
+
+            Assert.AreEqual(2, sequence.Count, "2 items expected");
+
+            DerEnumerated enumerated = sequence[0] as DerEnumerated;
+
+            Assert.IsNotNull(enumerated, "ENUMERATED expected");
+
+            Assert.AreEqual(65793, enumerated.Value.IntValue, "Unexpected ENUMERATED value");
+
+            DerObjectIdentifier objectId = sequence[1] as DerObjectIdentifier;
+
+            Assert.IsNotNull(objectId, "OBJECT IDENTIFIER expected");
+
+            Assert.AreEqual("1.3.6.1", objectId.Id, "Unexpected OBJECT IDENTIFIER value");
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/EqualsAndHashCodeTest.cs b/crypto/test/src/asn1/test/EqualsAndHashCodeTest.cs
new file mode 100644
index 000000000..7e0695341
--- /dev/null
+++ b/crypto/test/src/asn1/test/EqualsAndHashCodeTest.cs
@@ -0,0 +1,93 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class EqualsAndHashCodeTest
+        : SimpleTest
+    {
+        public override void PerformTest()
+        {
+            byte[] data = { 0, 1, 0, 1, 0, 0, 1 };
+
+			Asn1Object[] values =
+			{
+                new BerOctetString(data),
+                new BerSequence(new DerPrintableString("hello world")),
+                new BerSet(new DerPrintableString("hello world")),
+                new BerTaggedObject(0, new DerPrintableString("hello world")),
+				new DerApplicationSpecific(0, data),
+                new DerBitString(data),
+                new DerBmpString("hello world"),
+                DerBoolean.True,
+                DerBoolean.False,
+                new DerEnumerated(100),
+				new DerGeneralizedTime("20070315173729Z"),
+				new DerGeneralString("hello world"),
+                new DerIA5String("hello"),
+                new DerInteger(1000),
+                DerNull.Instance,
+                new DerNumericString("123456"),
+                new DerObjectIdentifier("1.1.1.10000.1"),
+                new DerOctetString(data),
+                new DerPrintableString("hello world"),
+                new DerSequence(new DerPrintableString("hello world")),
+                new DerSet(new DerPrintableString("hello world")),
+                new DerT61String("hello world"),
+                new DerTaggedObject(0, new DerPrintableString("hello world")),
+                new DerUniversalString(data),
+                new DerUtcTime(new DateTime()),
+                new DerUtf8String("hello world"),
+                new DerVisibleString("hello world")
+            };
+
+			MemoryStream bOut = new MemoryStream();
+            Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+
+            for (int i = 0; i != values.Length; i++)
+            {
+                aOut.WriteObject(values[i]);
+            }
+
+			Asn1InputStream aIn = new Asn1InputStream(bOut.ToArray());
+
+			for (int i = 0; i != values.Length; i++)
+            {
+                Asn1Object o = aIn.ReadObject();
+                if (!o.Equals(values[i]))
+                {
+                    Fail("Failed equality test for " + o.GetType().Name);
+                }
+
+                if (o.GetHashCode() != values[i].GetHashCode())
+                {
+                    Fail("Failed hashCode test for " + o.GetType().Name);
+                }
+            }
+        }
+
+		public override string Name
+		{
+			get { return "EqualsAndHashCode"; }
+		}
+
+        public static void Main(
+            string[] args)
+        {
+			RunTest(new EqualsAndHashCodeTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/EssCertIDv2UnitTest.cs b/crypto/test/src/asn1/test/EssCertIDv2UnitTest.cs
new file mode 100644
index 000000000..9aac777e1
--- /dev/null
+++ b/crypto/test/src/asn1/test/EssCertIDv2UnitTest.cs
@@ -0,0 +1,46 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+	public class EssCertIDv2UnitTest
+	: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "ESSCertIDv2"; }
+		}
+
+		public override void PerformTest()
+		{
+			// check GetInstance on default algorithm.
+			byte[] digest = new byte[32];
+			EssCertIDv2 essCertIdv2 = new EssCertIDv2(
+				new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256), digest);
+			Asn1Object asn1Object = essCertIdv2.ToAsn1Object();
+
+			EssCertIDv2.GetInstance(asn1Object);
+		}
+	
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new EssCertIDv2UnitTest());
+		}
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+	}
+}
diff --git a/crypto/test/src/asn1/test/GeneralNameTest.cs b/crypto/test/src/asn1/test/GeneralNameTest.cs
new file mode 100644
index 000000000..e9c3b5861
--- /dev/null
+++ b/crypto/test/src/asn1/test/GeneralNameTest.cs
@@ -0,0 +1,116 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class GeneralNameTest
+		: SimpleTest
+	{
+		private static readonly byte[] ipv4 = Hex.Decode("87040a090800");
+		private static readonly byte[] ipv4WithMask = Hex.Decode("87080a090800ffffff00");
+
+		private static readonly byte[] ipv6a = Hex.Decode("871020010db885a308d313198a2e03707334");
+		private static readonly byte[] ipv6b = Hex.Decode("871020010db885a3000013198a2e03707334");
+		private static readonly byte[] ipv6c = Hex.Decode("871000000000000000000000000000000001");
+		private static readonly byte[] ipv6d = Hex.Decode("871020010db885a3000000008a2e03707334");
+		private static readonly byte[] ipv6e = Hex.Decode("871020010db885a3000000008a2e0a090800");
+		private static readonly byte[] ipv6f = Hex.Decode("872020010db885a3000000008a2e0a090800ffffffffffff00000000000000000000");
+		private static readonly byte[] ipv6g = Hex.Decode("872020010db885a3000000008a2e0a090800ffffffffffffffffffffffffffffffff");
+		private static readonly byte[] ipv6h = Hex.Decode("872020010db885a300000000000000000000ffffffffffff00000000000000000000");
+	    
+		public override string Name
+		{
+			get { return "GeneralName"; }
+		}
+
+		public override void PerformTest()
+		{
+			GeneralName nm = new GeneralName(GeneralName.IPAddress, "10.9.8.0");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv4))
+			{
+				Fail("ipv4 encoding failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "10.9.8.0/255.255.255.0");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv4WithMask))
+			{
+				Fail("ipv4 with netmask 1 encoding failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "10.9.8.0/24");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv4WithMask))
+			{
+				Fail("ipv4 with netmask 2 encoding failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "2001:0db8:85a3:08d3:1319:8a2e:0370:7334");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6a))
+			{
+				Fail("ipv6 with netmask encoding failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "2001:0db8:85a3::1319:8a2e:0370:7334");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6b))
+			{
+				Fail("ipv6b encoding failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "::1");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6c))
+			{
+				Fail("ipv6c failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "2001:0db8:85a3::8a2e:0370:7334");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6d))
+			{
+				Fail("ipv6d failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "2001:0db8:85a3::8a2e:10.9.8.0");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6e))
+			{
+				Fail("ipv6e failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "2001:0db8:85a3::8a2e:10.9.8.0/ffff:ffff:ffff::0000");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6f))
+			{
+				Fail("ipv6f failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "2001:0db8:85a3::8a2e:10.9.8.0/128");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6g))
+			{
+				Fail("ipv6g failed");
+			}
+
+			nm = new GeneralName(GeneralName.IPAddress, "2001:0db8:85a3::/48");
+			if (!Arrays.AreEqual(nm.GetEncoded(), ipv6h))
+			{
+				Fail("ipv6h failed");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new GeneralNameTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(resultText, Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/GeneralizedTimeTest.cs b/crypto/test/src/asn1/test/GeneralizedTimeTest.cs
new file mode 100644
index 000000000..51995e195
--- /dev/null
+++ b/crypto/test/src/asn1/test/GeneralizedTimeTest.cs
@@ -0,0 +1,231 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    /**
+     * X.690 test example
+     */
+    [TestFixture]
+    public class GeneralizedTimeTest
+        : SimpleTest
+    {
+        private static readonly string[] input =
+        {
+            "20020122122220",
+            "20020122122220Z",
+            "20020122122220-1000",
+            "20020122122220+00",
+            "20020122122220.1",
+            "20020122122220.1Z",
+            "20020122122220.1-1000",
+            "20020122122220.1+00",
+            "20020122122220.01",
+            "20020122122220.01Z",
+            "20020122122220.01-1000",
+            "20020122122220.01+00",
+            "20020122122220.001",
+            "20020122122220.001Z",
+            "20020122122220.001-1000",
+            "20020122122220.001+00",
+            "20020122122220.0001",
+            "20020122122220.0001Z",
+            "20020122122220.0001-1000",
+            "20020122122220.0001+00",
+            "20020122122220.0001+1000"
+        };
+
+        private static readonly string[] output =
+        {
+            "20020122122220",
+            "20020122122220GMT+00:00",
+            "20020122122220GMT-10:00",
+            "20020122122220GMT+00:00",
+            "20020122122220.1",
+            "20020122122220.1GMT+00:00",
+            "20020122122220.1GMT-10:00",
+            "20020122122220.1GMT+00:00",
+            "20020122122220.01",
+            "20020122122220.01GMT+00:00",
+            "20020122122220.01GMT-10:00",
+            "20020122122220.01GMT+00:00",
+            "20020122122220.001",
+            "20020122122220.001GMT+00:00",
+            "20020122122220.001GMT-10:00",
+            "20020122122220.001GMT+00:00",
+            "20020122122220.0001",
+            "20020122122220.0001GMT+00:00",
+            "20020122122220.0001GMT-10:00",
+            "20020122122220.0001GMT+00:00",
+            "20020122122220.0001GMT+10:00"
+        };
+
+        private static readonly string[] zOutput =
+        {
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122222220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122222220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122222220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122222220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122122220Z",
+            "20020122222220Z",
+            "20020122122220Z",
+            "20020122022220Z"
+        };
+        
+        private static readonly string[] mzOutput =
+        {
+            "20020122122220.000Z",
+            "20020122122220.000Z",
+            "20020122222220.000Z",
+            "20020122122220.000Z",
+            "20020122122220.100Z",
+            "20020122122220.100Z",
+            "20020122222220.100Z",
+            "20020122122220.100Z",
+            "20020122122220.010Z",
+            "20020122122220.010Z",
+            "20020122222220.010Z",
+            "20020122122220.010Z",
+            "20020122122220.001Z",
+            "20020122122220.001Z",
+            "20020122222220.001Z",
+            "20020122122220.001Z",
+            "20020122122220.000Z",
+            "20020122122220.000Z",
+            "20020122222220.000Z",
+            "20020122122220.000Z",
+            "20020122022220.000Z"
+        };
+
+        public override string Name
+        {
+            get { return "GeneralizedTime"; }
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i != input.Length; i++)
+            {
+                string ii = input[i], oi = output[i];
+
+                DerGeneralizedTime t = new DerGeneralizedTime(ii);
+                DateTime dt = t.ToDateTime();
+                string st = t.GetTime();
+
+                if (oi.IndexOf('G') > 0)   // don't check local time the same way
+                {
+                    if (!st.Equals(oi))
+                    {
+                        Fail("failed conversion test");
+                    }
+
+                    string dts = dt.ToString(@"yyyyMMddHHmmss\Z");
+                    string zi = zOutput[i];
+                    if (!dts.Equals(zi))
+                    {
+                        Fail("failed date conversion test");
+                    }
+                }
+                else
+                {
+                    string offset = CalculateGmtOffset(dt);
+                    if (!st.Equals(oi + offset))
+                    {
+                        Fail("failed conversion test");
+                    }
+                }
+            }
+
+            for (int i = 0; i != input.Length; i++)
+            {
+                DerGeneralizedTime t = new DerGeneralizedTime(input[i]);
+
+                if (!t.ToDateTime().ToString(@"yyyyMMddHHmmss.fff\Z").Equals(mzOutput[i]))
+                {
+                    Console.WriteLine("{0} != {1}", t.ToDateTime().ToString(@"yyyyMMddHHmmss.SSS\Z"), mzOutput[i]);
+
+                    Fail("failed long date conversion test");
+                }
+            }
+
+            /*
+             * [BMA-87]
+             */
+            {
+                DateTime t1 = new DerUtcTime("110616114855Z").ToDateTime();
+                DateTime t2 = new DerGeneralizedTime("20110616114855Z").ToDateTime();
+
+                if (t1 != t2)
+                {
+                    Fail("failed UTC equivalence test");
+                }
+
+                DateTime u1 = t1.ToUniversalTime();
+                DateTime u2 = t2.ToUniversalTime();
+
+                if (u1 != u2)
+                {
+                    Fail("failed UTC conversion test");
+                }
+            }
+        }
+
+        private string CalculateGmtOffset(
+            DateTime date)
+        {
+            char sign = '+';
+
+            // Note: GetUtcOffset incorporates Daylight Savings offset
+            TimeSpan offset =  TimeZone.CurrentTimeZone.GetUtcOffset(date);
+            if (offset.CompareTo(TimeSpan.Zero) < 0)
+            {
+                sign = '-';
+                offset = offset.Duration();
+            }
+            int hours = offset.Hours;
+            int minutes = offset.Minutes;
+
+            return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
+        }
+
+        private string Convert(int time)
+        {
+            if (time < 10)
+            {
+                return "0" + time;
+            }
+
+            return time.ToString();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new GeneralizedTimeTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/GenerationTest.cs b/crypto/test/src/asn1/test/GenerationTest.cs
new file mode 100644
index 000000000..5acf8e149
--- /dev/null
+++ b/crypto/test/src/asn1/test/GenerationTest.cs
@@ -0,0 +1,325 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class GenerationTest
+        :	SimpleTest
+    {
+        private static readonly byte[] v1Cert = Base64.Decode(
+			"MIGtAgEBMA0GCSqGSIb3DQEBBAUAMCUxCzAJBgNVBAMMAkFVMRYwFAYDVQQKDA1Cb"
+			+ "3VuY3kgQ2FzdGxlMB4XDTcwMDEwMTAwMDAwMVoXDTcwMDEwMTAwMDAxMlowNjELMA"
+			+ "kGA1UEAwwCQVUxFjAUBgNVBAoMDUJvdW5jeSBDYXN0bGUxDzANBgNVBAsMBlRlc3Q"
+			+ "gMTAaMA0GCSqGSIb3DQEBAQUAAwkAMAYCAQECAQI=");
+
+		private static readonly byte[] v3Cert = Base64.Decode(
+			"MIIBSKADAgECAgECMA0GCSqGSIb3DQEBBAUAMCUxCzAJBgNVBAMMAkFVMRYwFAYD"
+			+ "VQQKDA1Cb3VuY3kgQ2FzdGxlMB4XDTcwMDEwMTAwMDAwMVoXDTcwMDEwMTAwMDAw"
+			+ "MlowNjELMAkGA1UEAwwCQVUxFjAUBgNVBAoMDUJvdW5jeSBDYXN0bGUxDzANBgNV"
+			+ "BAsMBlRlc3QgMjAYMBAGBisOBwIBATAGAgEBAgECAwQAAgEDo4GVMIGSMGEGA1Ud"
+			+ "IwEB/wRXMFWAFDZPdpHPzKi7o8EJokkQU2uqCHRRoTqkODA2MQswCQYDVQQDDAJB"
+			+ "VTEWMBQGA1UECgwNQm91bmN5IENhc3RsZTEPMA0GA1UECwwGVGVzdCAyggECMCAG"
+			+ "A1UdDgEB/wQWBBQ2T3aRz8you6PBCaJJEFNrqgh0UTALBgNVHQ8EBAMCBBA=");
+
+		private static readonly byte[] v3CertNullSubject = Base64.Decode(
+			"MIHGoAMCAQICAQIwDQYJKoZIhvcNAQEEBQAwJTELMAkGA1UEAwwCQVUxFjAUBgNVB"
+			+ "AoMDUJvdW5jeSBDYXN0bGUwHhcNNzAwMTAxMDAwMDAxWhcNNzAwMTAxMDAwMDAyWj"
+			+ "AAMBgwEAYGKw4HAgEBMAYCAQECAQIDBAACAQOjSjBIMEYGA1UdEQEB/wQ8MDqkODA"
+			+ "2MQswCQYDVQQDDAJBVTEWMBQGA1UECgwNQm91bmN5IENhc3RsZTEPMA0GA1UECwwG"
+			+ "VGVzdCAy");
+
+		private static readonly byte[] v2CertList = Base64.Decode(
+			"MIIBRQIBATANBgkqhkiG9w0BAQUFADAlMQswCQYDVQQDDAJBVTEWMBQGA1UECgwN"
+			+ "Qm91bmN5IENhc3RsZRcNNzAwMTAxMDAwMDAwWhcNNzAwMTAxMDAwMDAyWjAkMCIC"
+			+ "AQEXDTcwMDEwMTAwMDAwMVowDjAMBgNVHRUEBQoDAIAAoIHFMIHCMGEGA1UdIwEB"
+			+ "/wRXMFWAFDZPdpHPzKi7o8EJokkQU2uqCHRRoTqkODA2MQswCQYDVQQDDAJBVTEW"
+			+ "MBQGA1UECgwNQm91bmN5IENhc3RsZTEPMA0GA1UECwwGVGVzdCAyggECMEMGA1Ud"
+			+ "EgQ8MDqkODA2MQswCQYDVQQDDAJBVTEWMBQGA1UECgwNQm91bmN5IENhc3RsZTEP"
+			+ "MA0GA1UECwwGVGVzdCAzMAoGA1UdFAQDAgEBMAwGA1UdHAEB/wQCMAA=");
+
+        private void TbsV1CertGenerate()
+        {
+			V1TbsCertificateGenerator gen = new V1TbsCertificateGenerator();
+            DateTime startDate = new DateTime(1970, 1, 1, 0, 0, 1);
+            DateTime endDate = new DateTime(1970, 1, 1, 0, 0, 12);
+
+            gen.SetSerialNumber(new DerInteger(1));
+
+            gen.SetStartDate(new Time(startDate));
+            gen.SetEndDate(new Time(endDate));
+
+            gen.SetIssuer(new X509Name("CN=AU,O=Bouncy Castle"));
+            gen.SetSubject(new X509Name("CN=AU,O=Bouncy Castle,OU=Test 1"));
+
+            gen.SetSignature(new AlgorithmIdentifier(PkcsObjectIdentifiers.MD5WithRsaEncryption, DerNull.Instance));
+
+            SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PkcsObjectIdentifiers.RsaEncryption, DerNull.Instance),
+                new RsaPublicKeyStructure(BigInteger.One, BigInteger.Two));
+
+            gen.SetSubjectPublicKeyInfo(info);
+
+            TbsCertificateStructure tbs = gen.GenerateTbsCertificate();
+
+			if (!Arrays.AreEqual(tbs.GetEncoded(), v1Cert))
+            {
+                Fail("failed v1 cert generation");
+            }
+
+            //
+            // read back test
+            //
+            Asn1InputStream aIn = new Asn1InputStream(v1Cert);
+            Asn1Object o = aIn.ReadObject();
+
+            if (!Arrays.AreEqual(o.GetEncoded(), v1Cert))
+            {
+                Fail("failed v1 cert read back test");
+            }
+        }
+
+		private AuthorityKeyIdentifier CreateAuthorityKeyId(
+            SubjectPublicKeyInfo	info,
+            X509Name				name,
+            int						sNumber)
+        {
+            GeneralName genName = new GeneralName(name);
+
+			return new AuthorityKeyIdentifier(
+				info,
+				GeneralNames.GetInstance(new DerSequence(genName)),
+				BigInteger.ValueOf(sNumber));
+        }
+
+		private void TbsV3CertGenerate()
+        {
+			V3TbsCertificateGenerator gen = new V3TbsCertificateGenerator();
+			DateTime startDate = new DateTime(1970, 1, 1, 0, 0, 1);
+			DateTime endDate = new DateTime(1970, 1, 1, 0, 0, 2);
+
+			gen.SetSerialNumber(new DerInteger(2));
+
+			gen.SetStartDate(new Time(startDate));
+			gen.SetEndDate(new Time(endDate));
+
+			gen.SetIssuer(new X509Name("CN=AU,O=Bouncy Castle"));
+			gen.SetSubject(new X509Name("CN=AU,O=Bouncy Castle,OU=Test 2"));
+
+			gen.SetSignature(new AlgorithmIdentifier(PkcsObjectIdentifiers.MD5WithRsaEncryption, DerNull.Instance));
+
+			SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+				new AlgorithmIdentifier(
+					OiwObjectIdentifiers.ElGamalAlgorithm,
+					new ElGamalParameter(BigInteger.One, BigInteger.Two)),
+				new DerInteger(3));
+
+			gen.SetSubjectPublicKeyInfo(info);
+
+			//
+			// add extensions
+			//
+			IList order = new ArrayList();
+			IDictionary extensions = new Hashtable();
+
+			order.Add(X509Extensions.AuthorityKeyIdentifier);
+			order.Add(X509Extensions.SubjectKeyIdentifier);
+			order.Add(X509Extensions.KeyUsage);
+
+			extensions.Add(X509Extensions.AuthorityKeyIdentifier, new X509Extension(true, new DerOctetString(CreateAuthorityKeyId(info, new X509Name("CN=AU,O=Bouncy Castle,OU=Test 2"), 2))));
+			extensions.Add(X509Extensions.SubjectKeyIdentifier, new X509Extension(true, new DerOctetString(new SubjectKeyIdentifier(info))));
+			extensions.Add(X509Extensions.KeyUsage, new X509Extension(false, new DerOctetString(new KeyUsage(KeyUsage.DataEncipherment))));
+
+			X509Extensions ex = new X509Extensions(order, extensions);
+
+			gen.SetExtensions(ex);
+
+			TbsCertificateStructure tbs = gen.GenerateTbsCertificate();
+
+			if (!Arrays.AreEqual(tbs.GetEncoded(), v3Cert))
+			{
+				Fail("failed v3 cert generation");
+			}
+
+			//
+			// read back test
+			//
+			Asn1Object o = Asn1Object.FromByteArray(v3Cert);
+
+			if (!Arrays.AreEqual(o.GetEncoded(), v3Cert))
+			{
+				Fail("failed v3 cert read back test");
+			}
+        }
+
+		private void TbsV3CertGenWithNullSubject()
+		{
+			V3TbsCertificateGenerator gen = new V3TbsCertificateGenerator();
+			DateTime startDate = new DateTime(1970, 1, 1, 0, 0, 1);
+			DateTime endDate = new DateTime(1970, 1, 1, 0, 0, 2);
+
+			gen.SetSerialNumber(new DerInteger(2));
+
+			gen.SetStartDate(new Time(startDate));
+			gen.SetEndDate(new Time(endDate));
+
+			gen.SetIssuer(new X509Name("CN=AU,O=Bouncy Castle"));
+
+			gen.SetSignature(new AlgorithmIdentifier(PkcsObjectIdentifiers.MD5WithRsaEncryption, DerNull.Instance));
+
+			SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+				new AlgorithmIdentifier(OiwObjectIdentifiers.ElGamalAlgorithm,
+					new ElGamalParameter(BigInteger.One, BigInteger.Two)),
+				new DerInteger(3));
+
+			gen.SetSubjectPublicKeyInfo(info);
+
+			try
+			{
+				gen.GenerateTbsCertificate();
+				Fail("null subject not caught!");
+			}
+			catch (InvalidOperationException e)
+			{
+				if (!e.Message.Equals("not all mandatory fields set in V3 TBScertificate generator"))
+				{
+					Fail("unexpected exception", e);
+				}
+			}
+
+			//
+			// add extensions
+			//
+			IList order = new ArrayList();
+			IDictionary extensions = new Hashtable();
+
+			order.Add(X509Extensions.SubjectAlternativeName);
+
+			extensions.Add(
+				X509Extensions.SubjectAlternativeName,
+				new X509Extension(
+					true,
+					new DerOctetString(
+						new GeneralNames(
+							new GeneralName(
+								new X509Name("CN=AU,O=Bouncy Castle,OU=Test 2"))))));
+
+			X509Extensions ex = new X509Extensions(order, extensions);
+
+			gen.SetExtensions(ex);
+
+			TbsCertificateStructure tbs = gen.GenerateTbsCertificate();
+
+			if (!Arrays.AreEqual(tbs.GetEncoded(), v3CertNullSubject))
+			{
+				Fail("failed v3 null sub cert generation");
+			}
+
+			//
+			// read back test
+			//
+			Asn1Object o = Asn1Object.FromByteArray(v3CertNullSubject);
+
+			if (!Arrays.AreEqual(o.GetEncoded(), v3CertNullSubject))
+			{
+				Fail("failed v3 null sub cert read back test");
+			}
+		}
+
+		private void TbsV2CertListGenerate()
+        {
+            V2TbsCertListGenerator gen = new V2TbsCertListGenerator();
+
+            gen.SetIssuer(new X509Name("CN=AU,O=Bouncy Castle"));
+
+            gen.AddCrlEntry(new DerInteger(1), new Time(new DateTime(1970, 1, 1, 0, 0, 1)), ReasonFlags.AACompromise);
+
+            gen.SetNextUpdate(new Time(new DateTime(1970, 1, 1, 0, 0, 2)));
+
+            gen.SetThisUpdate(new Time(new DateTime(1970, 1, 1, 0, 0, 0, 500)));
+
+            gen.SetSignature(new AlgorithmIdentifier(PkcsObjectIdentifiers.Sha1WithRsaEncryption, DerNull.Instance));
+
+            //
+            // extensions
+            //
+            IList order = new ArrayList();
+            IDictionary extensions = new Hashtable();
+            SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+				new AlgorithmIdentifier(
+					OiwObjectIdentifiers.ElGamalAlgorithm,
+					new ElGamalParameter(BigInteger.One, BigInteger.Two)),
+				new DerInteger(3));
+
+			order.Add(X509Extensions.AuthorityKeyIdentifier);
+            order.Add(X509Extensions.IssuerAlternativeName);
+            order.Add(X509Extensions.CrlNumber);
+            order.Add(X509Extensions.IssuingDistributionPoint);
+
+            extensions.Add(X509Extensions.AuthorityKeyIdentifier, new X509Extension(true, new DerOctetString(CreateAuthorityKeyId(info, new X509Name("CN=AU,O=Bouncy Castle,OU=Test 2"), 2))));
+            extensions.Add(X509Extensions.IssuerAlternativeName, new X509Extension(false, new DerOctetString(GeneralNames.GetInstance(new DerSequence(new GeneralName(new X509Name("CN=AU,O=Bouncy Castle,OU=Test 3")))))));
+            extensions.Add(X509Extensions.CrlNumber, new X509Extension(false, new DerOctetString(new DerInteger(1))));
+            extensions.Add(X509Extensions.IssuingDistributionPoint, new X509Extension(true, new DerOctetString(IssuingDistributionPoint.GetInstance(DerSequence.Empty))));
+
+            X509Extensions ex = new X509Extensions(order, extensions);
+
+            gen.SetExtensions(ex);
+
+            TbsCertificateList tbs = gen.GenerateTbsCertList();
+
+            if (!Arrays.AreEqual(tbs.GetEncoded(), v2CertList))
+            {
+                Fail("failed v2 cert list generation");
+            }
+
+            //
+            // read back test
+            //
+            Asn1InputStream aIn = new Asn1InputStream(v2CertList);
+            Asn1Object o = aIn.ReadObject();
+
+            if (!Arrays.AreEqual(o.GetEncoded(), v2CertList))
+            {
+                Fail("failed v2 cert list read back test");
+            }
+        }
+
+		public override void PerformTest()
+        {
+            TbsV1CertGenerate();
+            TbsV3CertGenerate();
+			TbsV3CertGenWithNullSubject();
+            TbsV2CertListGenerate();
+        }
+
+		public override string Name
+		{
+			get { return "Generation"; }
+		}
+
+        public static void Main(
+            string[] args)
+        {
+			RunTest(new GenerationTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(resultText, Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/InputStreamTest.cs b/crypto/test/src/asn1/test/InputStreamTest.cs
new file mode 100644
index 000000000..1d92759e0
--- /dev/null
+++ b/crypto/test/src/asn1/test/InputStreamTest.cs
@@ -0,0 +1,85 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class InputStreamTest
+		: SimpleTest
+	{
+		private static readonly byte[] outOfBoundsLength = new byte[] { (byte)0x30, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff };
+		private static readonly byte[] negativeLength = new byte[] { (byte)0x30, (byte)0x84, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff };
+		private static readonly byte[] outsideLimitLength = new byte[] { (byte)0x30, (byte)0x83, (byte)0x0f, (byte)0xff, (byte)0xff };
+
+		public override string Name
+		{
+			get { return "InputStream"; }
+		}
+
+		public override void PerformTest()
+		{
+			Asn1InputStream aIn = new Asn1InputStream(outOfBoundsLength);
+
+			try
+			{
+				aIn.ReadObject();
+				Fail("out of bounds length not detected.");
+			}
+			catch (IOException e)
+			{
+				if (!e.Message.StartsWith("DER length more than 4 bytes"))
+				{
+					Fail("wrong exception: " + e.Message);
+				}
+			}
+
+			aIn = new Asn1InputStream(negativeLength);
+
+			try
+			{
+				aIn.ReadObject();
+				Fail("negative length not detected.");
+			}
+			catch (IOException e)
+			{
+				if (!e.Message.Equals("Corrupted stream - negative length found"))
+				{
+					Fail("wrong exception: " + e.Message);
+				}
+			}
+
+			aIn = new Asn1InputStream(outsideLimitLength);
+
+			try
+			{
+				aIn.ReadObject();
+				Fail("outside limit length not detected.");
+			}
+			catch (IOException e)
+			{
+				if (!e.Message.Equals("Corrupted stream - out of bounds length found"))
+				{
+					Fail("wrong exception: " + e.Message);
+				}
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new InputStreamTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/Iso4217CurrencyCodeUnitTest.cs b/crypto/test/src/asn1/test/Iso4217CurrencyCodeUnitTest.cs
new file mode 100644
index 000000000..bb6076a93
--- /dev/null
+++ b/crypto/test/src/asn1/test/Iso4217CurrencyCodeUnitTest.cs
@@ -0,0 +1,156 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class Iso4217CurrencyCodeUnitTest
+        : SimpleTest
+    {
+        private const string AlphabeticCurrencyCode = "AUD";
+        private const int NUMERIC_CurrencyCode = 1;
+
+		public override string Name
+        {
+			get { return "Iso4217CurrencyCode"; }
+        }
+
+		public override void PerformTest()
+        {
+            //
+            // alphabetic
+            //
+            Iso4217CurrencyCode cc = new Iso4217CurrencyCode(AlphabeticCurrencyCode);
+
+            CheckNumeric(cc, AlphabeticCurrencyCode);
+
+            cc = Iso4217CurrencyCode.GetInstance(cc);
+
+            CheckNumeric(cc, AlphabeticCurrencyCode);
+
+            Asn1Object obj = cc.ToAsn1Object();
+
+            cc = Iso4217CurrencyCode.GetInstance(obj);
+
+            CheckNumeric(cc, AlphabeticCurrencyCode);
+
+            //
+            // numeric
+            //
+            cc = new Iso4217CurrencyCode(NUMERIC_CurrencyCode);
+
+            CheckNumeric(cc, NUMERIC_CurrencyCode);
+
+            cc = Iso4217CurrencyCode.GetInstance(cc);
+
+            CheckNumeric(cc, NUMERIC_CurrencyCode);
+
+            obj = cc.ToAsn1Object();
+
+            cc = Iso4217CurrencyCode.GetInstance(obj);
+
+            CheckNumeric(cc, NUMERIC_CurrencyCode);
+
+            cc = Iso4217CurrencyCode.GetInstance(null);
+
+            if (cc != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+            try
+            {
+                Iso4217CurrencyCode.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                new Iso4217CurrencyCode("ABCD");
+
+                Fail("constructor failed to detect out of range currencycode.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                new Iso4217CurrencyCode(0);
+
+                Fail("constructor failed to detect out of range small numeric code.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                new Iso4217CurrencyCode(1000);
+
+                Fail("constructor failed to detect out of range large numeric code.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        private void CheckNumeric(
+            Iso4217CurrencyCode cc,
+            string              code)
+        {
+            if (!cc.IsAlphabetic)
+            {
+                Fail("non-alphabetic code found when one expected.");
+            }
+
+            if (!cc.Alphabetic.Equals(code))
+            {
+                Fail("string codes don't match.");
+            }
+        }
+
+        private void CheckNumeric(
+            Iso4217CurrencyCode cc,
+            int                 code)
+        {
+            if (cc.IsAlphabetic)
+            {
+                Fail("alphabetic code found when one not expected.");
+            }
+
+            if (cc.Numeric != code)
+            {
+                Fail("numeric codes don't match.");
+            }
+        }
+
+        public static void Main(
+            string[]    args)
+        {
+            RunTest(new Iso4217CurrencyCodeUnitTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/IssuingDistributionPointTest.cs b/crypto/test/src/asn1/test/IssuingDistributionPointTest.cs
new file mode 100644
index 000000000..b5f5c88bb
--- /dev/null
+++ b/crypto/test/src/asn1/test/IssuingDistributionPointTest.cs
@@ -0,0 +1,133 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class IssuingDistributionPointUnitTest 
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "IssuingDistributionPoint"; }
+		}
+
+		public override void PerformTest()
+		{
+			DistributionPointName name = new DistributionPointName(
+				new GeneralNames(new GeneralName(new X509Name("cn=test"))));
+			ReasonFlags reasonFlags = new ReasonFlags(ReasonFlags.CACompromise);
+
+			checkPoint(6, name, true, true, reasonFlags, true, true);
+
+			checkPoint(2, name, false, false, reasonFlags, false, false);
+
+			checkPoint(0, null, false, false, null, false, false);
+
+			try
+			{
+				IssuingDistributionPoint.GetInstance(new object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkPoint(
+			int						size,
+			DistributionPointName	distributionPoint,
+			bool					onlyContainsUserCerts,
+			bool					onlyContainsCACerts,
+			ReasonFlags				onlySomeReasons,
+			bool					indirectCRL,
+			bool					onlyContainsAttributeCerts)
+		{
+			IssuingDistributionPoint point = new IssuingDistributionPoint(distributionPoint, onlyContainsUserCerts, onlyContainsCACerts, onlySomeReasons, indirectCRL, onlyContainsAttributeCerts);
+
+			checkValues(point, distributionPoint, onlyContainsUserCerts, onlyContainsCACerts, onlySomeReasons, indirectCRL, onlyContainsAttributeCerts);
+
+			Asn1Sequence seq = Asn1Sequence.GetInstance(Asn1Object.FromByteArray(point.GetEncoded()));
+
+			if (seq.Count != size)
+			{
+				Fail("size mismatch");
+			}
+
+			point = IssuingDistributionPoint.GetInstance(seq);
+
+			checkValues(point, distributionPoint, onlyContainsUserCerts, onlyContainsCACerts, onlySomeReasons, indirectCRL, onlyContainsAttributeCerts);
+		}
+
+		private void checkValues(
+			IssuingDistributionPoint	point,
+			DistributionPointName		distributionPoint,
+			bool						onlyContainsUserCerts,
+			bool						onlyContainsCACerts,
+			ReasonFlags					onlySomeReasons,
+			bool						indirectCRL,
+			bool						onlyContainsAttributeCerts)
+		{
+			if (point.OnlyContainsUserCerts != onlyContainsUserCerts)
+			{
+				Fail("mismatch on onlyContainsUserCerts");
+			}
+
+			if (point.OnlyContainsCACerts != onlyContainsCACerts)
+			{
+				Fail("mismatch on onlyContainsCACerts");
+			}
+
+			if (point.IsIndirectCrl != indirectCRL)
+			{
+				Fail("mismatch on indirectCRL");
+			}
+
+			if (point.OnlyContainsAttributeCerts != onlyContainsAttributeCerts)
+			{
+				Fail("mismatch on onlyContainsAttributeCerts");
+			}
+
+			if (!isEquiv(onlySomeReasons, point.OnlySomeReasons))
+			{
+				Fail("mismatch on onlySomeReasons");
+			}
+
+			if (!isEquiv(distributionPoint, point.DistributionPoint))
+			{
+				Fail("mismatch on distributionPoint");
+			}
+		}
+
+		private bool isEquiv(object o1, object o2)
+		{
+			if (o1 == null)
+			{
+				return o2 == null;
+			}
+
+			return o1.Equals(o2);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new IssuingDistributionPointUnitTest());
+		}
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+	}
+}
diff --git a/crypto/test/src/asn1/test/KeyUsageTest.cs b/crypto/test/src/asn1/test/KeyUsageTest.cs
new file mode 100644
index 000000000..d7ed3655d
--- /dev/null
+++ b/crypto/test/src/asn1/test/KeyUsageTest.cs
@@ -0,0 +1,49 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class KeyUsageTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get
+			{
+				return "KeyUsage";
+			}
+		}
+
+		public override void PerformTest()
+		{
+			BitStringConstantTester.testFlagValueCorrect(0, KeyUsage.DigitalSignature);
+			BitStringConstantTester.testFlagValueCorrect(1, KeyUsage.NonRepudiation);
+			BitStringConstantTester.testFlagValueCorrect(2, KeyUsage.KeyEncipherment);
+			BitStringConstantTester.testFlagValueCorrect(3, KeyUsage.DataEncipherment);
+			BitStringConstantTester.testFlagValueCorrect(4, KeyUsage.KeyAgreement);
+			BitStringConstantTester.testFlagValueCorrect(5, KeyUsage.KeyCertSign);
+			BitStringConstantTester.testFlagValueCorrect(6, KeyUsage.CrlSign);
+			BitStringConstantTester.testFlagValueCorrect(7, KeyUsage.EncipherOnly);
+			BitStringConstantTester.testFlagValueCorrect(8, KeyUsage.DecipherOnly);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new KeyUsageTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/LDSSecurityObjectUnitTest.cs b/crypto/test/src/asn1/test/LDSSecurityObjectUnitTest.cs
new file mode 100644
index 000000000..042781632
--- /dev/null
+++ b/crypto/test/src/asn1/test/LDSSecurityObjectUnitTest.cs
@@ -0,0 +1,208 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Icao;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class LDSSecurityObjectUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "LDSSecurityObject"; }
+        }
+
+		private byte[] GenerateHash()
+        {
+            Random rand = new Random();
+            byte[] bytes = new byte[20];
+            rand.NextBytes(bytes);
+            return bytes;
+        }
+
+        public override void PerformTest()
+        {
+            AlgorithmIdentifier  algoId = new AlgorithmIdentifier("1.3.14.3.2.26");
+            DataGroupHash[] datas = new DataGroupHash[2];
+
+            datas[0] = new DataGroupHash(1, new DerOctetString(GenerateHash()));
+            datas[1] = new DataGroupHash(2, new DerOctetString(GenerateHash()));
+
+            LdsSecurityObject so = new LdsSecurityObject(algoId, datas);
+
+			CheckConstruction(so, algoId, datas);
+
+			LdsVersionInfo versionInfo = new LdsVersionInfo("Hello", "world");
+
+			so = new LdsSecurityObject(algoId, datas, versionInfo);
+
+			CheckConstruction(so, algoId, datas, versionInfo);
+
+			try
+			{
+				LdsSecurityObject.GetInstance(null);
+			}
+			catch (Exception)
+			{
+				Fail("GetInstance() failed to handle null.");
+			}
+
+			try
+            {
+                LdsSecurityObject.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+			try
+            {
+				LdsSecurityObject.GetInstance(DerSequence.Empty);
+
+				Fail("constructor failed to detect empty sequence.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+			try
+            {
+                new LdsSecurityObject(algoId, new DataGroupHash[1]);
+
+				Fail("constructor failed to detect small DataGroupHash array.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+			try
+            {
+                new LdsSecurityObject(algoId, new DataGroupHash[LdsSecurityObject.UBDataGroups + 1]);
+
+				Fail("constructor failed to out of bounds DataGroupHash array.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+		private void CheckConstruction(
+            LdsSecurityObject	so,
+            AlgorithmIdentifier	digestAlgorithmIdentifier,
+            DataGroupHash[]		datagroupHash)
+        {
+            CheckStatement(so, digestAlgorithmIdentifier, datagroupHash, null);
+
+			so = LdsSecurityObject.GetInstance(so);
+
+			CheckStatement(so, digestAlgorithmIdentifier, datagroupHash, null);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				so.ToAsn1Object().GetEncoded());
+
+			so = LdsSecurityObject.GetInstance(seq);
+
+			CheckStatement(so, digestAlgorithmIdentifier, datagroupHash, null);
+        }
+		
+		private void CheckConstruction(
+			LdsSecurityObject	so,
+			AlgorithmIdentifier	digestAlgorithmIdentifier,
+			DataGroupHash[]		datagroupHash,
+			LdsVersionInfo		versionInfo)
+		{
+			if (!so.Version.Equals(BigInteger.One))
+			{
+				Fail("version number not 1");
+			}
+
+			CheckStatement(so, digestAlgorithmIdentifier, datagroupHash, versionInfo);
+
+			so = LdsSecurityObject.GetInstance(so);
+
+			CheckStatement(so, digestAlgorithmIdentifier, datagroupHash, versionInfo);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				so.ToAsn1Object().GetEncoded());
+
+			so = LdsSecurityObject.GetInstance(seq);
+
+			CheckStatement(so, digestAlgorithmIdentifier, datagroupHash, versionInfo);
+		}
+
+		private void CheckStatement(
+            LdsSecurityObject	so,
+            AlgorithmIdentifier	digestAlgorithmIdentifier,
+            DataGroupHash[]		datagroupHash,
+			LdsVersionInfo		versionInfo)
+        {
+            if (digestAlgorithmIdentifier != null)
+            {
+                if (!so.DigestAlgorithmIdentifier.Equals(digestAlgorithmIdentifier))
+                {
+                    Fail("ids don't match.");
+                }
+            }
+            else if (so.DigestAlgorithmIdentifier != null)
+            {
+                Fail("digest algorithm Id found when none expected.");
+            }
+
+			if (datagroupHash != null)
+            {
+                DataGroupHash[] datas = so.GetDatagroupHash();
+
+                for (int i = 0; i != datas.Length; i++)
+                {
+                    if (!datagroupHash[i].Equals(datas[i]))
+                    {
+                        Fail("name registration authorities don't match.");
+                    }
+                }
+            }
+            else if (so.GetDatagroupHash() != null)
+            {
+                Fail("data hash groups found when none expected.");
+            }
+
+			if (versionInfo != null)
+			{
+				if (!versionInfo.Equals(so.VersionInfo))
+				{
+					Fail("versionInfo doesn't match");
+				}
+			}
+			else if (so.VersionInfo != null)
+			{
+				Fail("version info found when none expected.");
+			}
+        }
+
+		public static void Main(
+            string[]    args)
+        {
+            RunTest(new LDSSecurityObjectUnitTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/MiscTest.cs b/crypto/test/src/asn1/test/MiscTest.cs
new file mode 100644
index 000000000..42f5dbd01
--- /dev/null
+++ b/crypto/test/src/asn1/test/MiscTest.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class MiscTest
+        : ITest
+    {
+        public ITestResult Perform()
+        {
+            byte[] testIv = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+            Asn1Encodable[] values =
+            {
+                new Cast5CbcParameters(testIv, 128),
+                new NetscapeCertType(NetscapeCertType.Smime),
+                new VerisignCzagExtension(new DerIA5String("hello")),
+                new IdeaCbcPar(testIv),
+                new NetscapeRevocationUrl(new DerIA5String("http://test"))
+            };
+
+            byte[] data = Base64.Decode("MA4ECAECAwQFBgcIAgIAgAMCBSAWBWhlbGxvMAoECAECAwQFBgcIFgtodHRwOi8vdGVzdA==");
+
+            try
+            {
+                MemoryStream bOut = new MemoryStream();
+                Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+
+                for (int i = 0; i != values.Length; i++)
+                {
+                    aOut.WriteObject(values[i]);
+                }
+
+                if (!Arrays.AreEqual(bOut.ToArray(), data))
+                {
+                    return new SimpleTestResult(false, Name + ": Failed data check");
+                }
+
+                Asn1InputStream aIn = new Asn1InputStream(bOut.ToArray());
+
+                for (int i = 0; i != values.Length; i++)
+                {
+                    Asn1Object o = aIn.ReadObject();
+
+                    if (!values[i].Equals(o))
+                    {
+                        return new SimpleTestResult(false, Name + ": Failed equality test for " + o);
+                    }
+
+                    if (o.GetHashCode() != values[i].GetHashCode())
+                    {
+                        return new SimpleTestResult(false, Name + ": Failed hashCode test for " + o);
+                    }
+                }
+
+                return new SimpleTestResult(true, Name + ": Okay");
+            }
+            catch (Exception e)
+            {
+                return new SimpleTestResult(false, Name + ": Failed - exception " + e.ToString(), e);
+            }
+        }
+
+        public string Name
+        {
+            get { return "Misc"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new MiscTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/MonetaryLimitUnitTest.cs b/crypto/test/src/asn1/test/MonetaryLimitUnitTest.cs
new file mode 100644
index 000000000..cdeb2eca5
--- /dev/null
+++ b/crypto/test/src/asn1/test/MonetaryLimitUnitTest.cs
@@ -0,0 +1,93 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class MonetaryLimitUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "MonetaryLimit"; }
+		}
+
+		public override void PerformTest()
+		{
+			string currency = "AUD";
+			int    amount = 1;
+			int    exponent = 2;
+
+			MonetaryLimit limit = new MonetaryLimit(currency, amount, exponent);
+
+			checkConstruction(limit, currency, amount, exponent);
+
+			limit = MonetaryLimit.GetInstance(null);
+
+			if (limit != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				MonetaryLimit.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			MonetaryLimit	limit,
+			string			currency,
+			int				amount,
+			int				exponent)
+		{
+			checkValues(limit, currency, amount, exponent);
+
+			limit = MonetaryLimit.GetInstance(limit);
+
+			checkValues(limit, currency, amount, exponent);
+
+			Asn1InputStream aIn = new Asn1InputStream(limit.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			limit = MonetaryLimit.GetInstance(seq);
+
+			checkValues(limit, currency, amount, exponent);
+		}
+
+		private void checkValues(
+			MonetaryLimit	limit,
+			string			currency,
+			int				amount,
+			int				exponent)
+		{
+			checkMandatoryField("currency", currency, limit.Currency);
+			checkMandatoryField("amount", amount, limit.Amount.IntValue);
+			checkMandatoryField("exponent", exponent, limit.Exponent.IntValue);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new MonetaryLimitUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/MonetaryValueUnitTest.cs b/crypto/test/src/asn1/test/MonetaryValueUnitTest.cs
new file mode 100644
index 000000000..c75d74505
--- /dev/null
+++ b/crypto/test/src/asn1/test/MonetaryValueUnitTest.cs
@@ -0,0 +1,99 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class MonetaryValueUnitTest
+        : SimpleTest
+    {
+        private const int TestAmount = 100;
+        private const int ZeroExponent = 0;
+
+        private const string CurrencyCode = "AUD";
+
+        public override string Name
+        {
+			get { return "MonetaryValue"; }
+        }
+
+		public override void PerformTest()
+        {
+            MonetaryValue mv = new MonetaryValue(new Iso4217CurrencyCode(CurrencyCode), TestAmount, ZeroExponent);
+
+			CheckValues(mv, TestAmount, ZeroExponent);
+
+			mv = MonetaryValue.GetInstance(mv);
+
+			CheckValues(mv, TestAmount, ZeroExponent);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				mv.ToAsn1Object().GetEncoded());
+
+			mv = MonetaryValue.GetInstance(seq);
+
+			CheckValues(mv, TestAmount, ZeroExponent);
+
+			mv = MonetaryValue.GetInstance(null);
+
+			if (mv != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+			try
+            {
+                MonetaryValue.GetInstance(new object());
+
+				Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+		private void CheckValues(
+            MonetaryValue mv,
+            int           amount,
+            int           exponent)
+        {
+            if (mv.Amount.IntValue != amount)
+            {
+                Fail("amounts don't match.");
+            }
+
+            if (mv.Exponent.IntValue != exponent)
+            {
+                Fail("exponents don't match.");
+            }
+
+            Iso4217CurrencyCode cc = mv.Currency;
+
+            if (!cc.Alphabetic.Equals(CurrencyCode))
+            {
+                Fail("currency code wrong");
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new MonetaryValueUnitTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/NameOrPseudonymUnitTest.cs b/crypto/test/src/asn1/test/NameOrPseudonymUnitTest.cs
new file mode 100644
index 000000000..45f66613b
--- /dev/null
+++ b/crypto/test/src/asn1/test/NameOrPseudonymUnitTest.cs
@@ -0,0 +1,114 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509.SigI;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class NameOrPseudonymUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "NameOrPseudonym"; }
+		}
+
+		public override void PerformTest()
+		{
+			string pseudonym = "pseudonym";
+			DirectoryString surname = new DirectoryString("surname");
+			Asn1Sequence givenName = new DerSequence(new DirectoryString("givenName"));
+
+			NameOrPseudonym id = new NameOrPseudonym(pseudonym);
+
+			checkConstruction(id, pseudonym, null, null);
+
+			id = new NameOrPseudonym(surname, givenName);
+
+			checkConstruction(id, null, surname, givenName);
+
+			id = NameOrPseudonym.GetInstance(null);
+
+			if (id != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				NameOrPseudonym.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			NameOrPseudonym	id,
+			string			pseudonym,
+			DirectoryString	surname,
+			Asn1Sequence	givenName)
+		{
+			checkValues(id, pseudonym, surname, givenName);
+
+			id = NameOrPseudonym.GetInstance(id);
+
+			checkValues(id, pseudonym, surname, givenName);
+
+			Asn1InputStream aIn = new Asn1InputStream(id.ToAsn1Object().GetEncoded());
+
+			if (surname != null)
+			{
+				Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+				id = NameOrPseudonym.GetInstance(seq);
+			}
+			else
+			{
+				IAsn1String s = (IAsn1String) aIn.ReadObject();
+
+				id = NameOrPseudonym.GetInstance(s);
+			}
+
+			checkValues(id, pseudonym, surname, givenName);
+		}
+
+		private void checkValues(
+			NameOrPseudonym	id,
+			string			pseudonym,
+			DirectoryString	surname,
+			Asn1Sequence	givenName)
+		{
+
+			if (surname != null)
+			{
+				checkMandatoryField("surname", surname, id.Surname);
+				checkMandatoryField("givenName", givenName, new DerSequence(id.GetGivenName()[0]));
+			}
+			else
+			{
+				checkOptionalField("pseudonym", new DirectoryString(pseudonym), id.Pseudonym);
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new NameOrPseudonymUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/NamingAuthorityUnitTest.cs b/crypto/test/src/asn1/test/NamingAuthorityUnitTest.cs
new file mode 100644
index 000000000..787b2c32d
--- /dev/null
+++ b/crypto/test/src/asn1/test/NamingAuthorityUnitTest.cs
@@ -0,0 +1,106 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class NamingAuthorityUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "NamingAuthority"; }
+		}
+
+		public override void PerformTest()
+		{
+			DerObjectIdentifier namingAuthorityID = new DerObjectIdentifier("1.2.3");
+			string namingAuthorityURL = "url";
+			DirectoryString namingAuthorityText = new DirectoryString("text");
+
+			NamingAuthority auth =  new NamingAuthority(namingAuthorityID, namingAuthorityURL, namingAuthorityText);
+
+			checkConstruction(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText);
+
+			auth =  new NamingAuthority(null, namingAuthorityURL, namingAuthorityText);
+
+			checkConstruction(auth, null, namingAuthorityURL, namingAuthorityText);
+
+			auth =  new NamingAuthority(namingAuthorityID, null, namingAuthorityText);
+
+			checkConstruction(auth, namingAuthorityID, null, namingAuthorityText);
+
+			auth =  new NamingAuthority(namingAuthorityID, namingAuthorityURL, null);
+
+			checkConstruction(auth, namingAuthorityID, namingAuthorityURL, null);
+
+			auth = NamingAuthority.GetInstance(null);
+
+			if (auth != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				NamingAuthority.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			NamingAuthority		auth,
+			DerObjectIdentifier	namingAuthorityID,
+			string				namingAuthorityURL,
+			DirectoryString		namingAuthorityText)
+		{
+			checkValues(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText);
+
+			auth = NamingAuthority.GetInstance(auth);
+
+			checkValues(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText);
+
+			Asn1InputStream aIn = new Asn1InputStream(auth.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			auth = NamingAuthority.GetInstance(seq);
+
+			checkValues(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText);
+		}
+
+		private void checkValues(
+			NamingAuthority		auth,
+			DerObjectIdentifier	namingAuthorityId,
+			string				namingAuthorityURL,
+			DirectoryString		namingAuthorityText)
+		{
+			checkOptionalField("namingAuthorityId", namingAuthorityId, auth.NamingAuthorityID);
+			checkOptionalField("namingAuthorityURL", namingAuthorityURL, auth.NamingAuthorityUrl);
+			checkOptionalField("namingAuthorityText", namingAuthorityText, auth.NamingAuthorityText);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new NamingAuthorityUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/NetscapeCertTypeTest.cs b/crypto/test/src/asn1/test/NetscapeCertTypeTest.cs
new file mode 100644
index 000000000..8db5d990c
--- /dev/null
+++ b/crypto/test/src/asn1/test/NetscapeCertTypeTest.cs
@@ -0,0 +1,45 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class NetscapeCertTypeTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "NetscapeCertType"; }
+		}
+
+		public override void PerformTest()
+		{
+			BitStringConstantTester.testFlagValueCorrect(0, NetscapeCertType.SslClient);
+			BitStringConstantTester.testFlagValueCorrect(1, NetscapeCertType.SslServer);
+			BitStringConstantTester.testFlagValueCorrect(2, NetscapeCertType.Smime);
+			BitStringConstantTester.testFlagValueCorrect(3, NetscapeCertType.ObjectSigning);
+			BitStringConstantTester.testFlagValueCorrect(4, NetscapeCertType.Reserved);
+			BitStringConstantTester.testFlagValueCorrect(5, NetscapeCertType.SslCA);
+			BitStringConstantTester.testFlagValueCorrect(6, NetscapeCertType.SmimeCA);
+			BitStringConstantTester.testFlagValueCorrect(7, NetscapeCertType.ObjectSigningCA);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new NetscapeCertTypeTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/OCSPTest.cs b/crypto/test/src/asn1/test/OCSPTest.cs
new file mode 100644
index 000000000..13f59d3d1
--- /dev/null
+++ b/crypto/test/src/asn1/test/OCSPTest.cs
@@ -0,0 +1,183 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class OcspTest
+		: ITest
+	{
+		private static byte[] unsignedReq = Base64.Decode(
+			"MEIwQDA+MDwwOjAJBgUrDgMCGgUABBRDb9GODnq7lRhSkEqw4XX24huERwQUkY4j"
+			+ "a6eKuDlkVP9hRgkEvIWqHPECAQE=");
+
+		private static byte[] signedReq = Base64.Decode(
+			"MIIC9jBAMD4wPDA6MAkGBSsOAwIaBQAEFENv0Y4OeruVGFKQSrDhdfbiG4RHBBTc"
+			+ "Mr1fP+mZAxbF2ZdehWxn6mtAngIBAaCCArAwggKsMA0GCSqGSIb3DQEBBQUAA4GB"
+			+ "AAzHBm4nL5AcRQB3Jkz7ScNeZF+GbRZ0p4kBDTnqi3IeESuso12yJhpqqyijdnj5"
+			+ "gd4/GsSAgdluLHyYZ6wgozV7G9MDXCnFnG4PBUW05HaVX81JYAp+amVyU0NOgNrG"
+			+ "90npVBsHb0o+UlkxNgMiEbSkp/TeGb6YURsYKhmwp7BgoIICFTCCAhEwggINMIIB"
+			+ "dqADAgECAgEBMA0GCSqGSIb3DQEBBAUAMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0"
+			+ "bGUxCzAJBgNVBAYTAkFVMB4XDTA0MTAyNDEzNDc0M1oXDTA1MDIwMTEzNDc0M1ow"
+			+ "JTEWMBQGA1UEChMNQm91bmN5IENhc3RsZTELMAkGA1UEBhMCQVUwgZ8wDQYJKoZI"
+			+ "hvcNAQEBBQADgY0AMIGJAoGBAJBmLeIzthMHUeTkOeJ76iBxcMHY31o/i3a9VT12"
+			+ "y2FcS/ejJmeUCMTdtwl5alOwXY66vF4DyT1VU/nJG3mHpSoqq7qrMXOIFGcXg1Wf"
+			+ "oJRrQgTOLdQ6bod7i9ME/EjEJy70orh0nVS7NGcu0R5TjcbLde2J5zxjb/W9wqfy"
+			+ "RovJAgMBAAGjTTBLMB0GA1UdDgQWBBTcMr1fP+mZAxbF2ZdehWxn6mtAnjAfBgNV"
+			+ "HSMEGDAWgBTcMr1fP+mZAxbF2ZdehWxn6mtAnjAJBgNVHRMEAjAAMA0GCSqGSIb3"
+			+ "DQEBBAUAA4GBAF/4EH1KkNrNxocJPIp7lThmG1KIVYESIadowMowrbok46ESofRF"
+			+ "OIPku07W+e1Y1Y1KXLIiPMG3IGwrBrn04iLsbbBUiN37BcC/VyT4xKJ2MYscGjKL"
+			+ "ua/9bU0lOyeTRAwqb8towWRd5lLYAI3RQ7dhStUTFp3Vqd803PJ/cpR6");
+
+		private static byte[] _response = Base64.Decode(
+			"MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx"
+			+ "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE"
+			+ "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG"
+			+ "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv"
+			+ "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ"
+			+ "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF"
+			+ "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1"
+			+ "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/"
+			+ "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt"
+			+ "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk"
+			+ "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI"
+			+ "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN"
+			+ "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww"
+			+ "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k"
+			+ "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz"
+			+ "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg"
+			+ "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK"
+			+ "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw"
+			+ "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI"
+			+ "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF"
+			+ "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH"
+			+ "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm"
+			+ "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E"
+			+ "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG"
+			+ "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E"
+			+ "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG"
+			+ "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4"
+			+ "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc"
+			+ "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V"
+			+ "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I"
+			+ "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq"
+			+ "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ");
+
+		private ITestResult unSignedRequest()
+		{
+			try
+			{
+				OcspRequest req = OcspRequest.GetInstance(
+					Asn1Object.FromByteArray(unsignedReq));
+
+				if (!Arrays.AreEqual(req.GetEncoded(), unsignedReq))
+				{
+					return new SimpleTestResult(false, Name + ": Ocsp unsigned request failed to re-encode");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed unsigned exception - " + e.ToString(), e);
+			}
+		}
+
+		private ITestResult SignedRequest()
+		{
+			try
+			{
+				OcspRequest req = OcspRequest.GetInstance(
+					Asn1Object.FromByteArray(signedReq));
+
+				if (!Arrays.AreEqual(req.GetEncoded(), signedReq))
+				{
+					return new SimpleTestResult(false, Name + ": Ocsp signed request failed to re-encode");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed signed exception - " + e.ToString(), e);
+			}
+		}
+
+		private ITestResult Response()
+		{
+			try
+			{
+				OcspResponse resp = OcspResponse.GetInstance(
+					Asn1Object.FromByteArray(_response));
+				ResponseBytes rBytes = ResponseBytes.GetInstance(resp.ResponseBytes);
+
+				BasicOcspResponse bResp = BasicOcspResponse.GetInstance(
+					Asn1Object.FromByteArray(rBytes.Response.GetOctets()));
+
+				resp = new OcspResponse(
+					resp.ResponseStatus,
+					new ResponseBytes(
+						rBytes.ResponseType,
+						new DerOctetString(bResp.GetEncoded())));
+
+				if (!Arrays.AreEqual(resp.GetEncoded(), _response))
+				{
+					return new SimpleTestResult(false, Name + ": Ocsp response failed to re-encode");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed response exception - " + e.ToString(), e);
+			}
+		}
+
+		public ITestResult Perform()
+		{
+			ITestResult res = unSignedRequest();
+
+			if (!res.IsSuccessful())
+			{
+				return res;
+			}
+
+			res = SignedRequest();
+			if (!res.IsSuccessful())
+			{
+				return res;
+			}
+
+			return Response();
+		}
+
+		public string Name
+		{
+			get { return "Ocsp"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new OcspTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/OIDTest.cs b/crypto/test/src/asn1/test/OIDTest.cs
new file mode 100644
index 000000000..b0782db04
--- /dev/null
+++ b/crypto/test/src/asn1/test/OIDTest.cs
@@ -0,0 +1,149 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	/**
+	 * X.690 test example
+	 */
+	[TestFixture]
+	public class OidTest
+		: SimpleTest
+	{
+		byte[] req1 = Hex.Decode("0603813403");
+		byte[] req2 = Hex.Decode("06082A36FFFFFFDD6311");
+
+		public override string Name
+		{
+			get { return "OID"; }
+		}
+
+		private void recodeCheck(
+			string	oid,
+			byte[]	enc)
+		{
+			DerObjectIdentifier o = new DerObjectIdentifier(oid);
+			DerObjectIdentifier encO = (DerObjectIdentifier) Asn1Object.FromByteArray(enc);
+
+			if (!o.Equals(encO))
+			{
+				Fail("oid ID didn't match", o, encO);
+			}
+
+			byte[] bytes = o.GetDerEncoded();
+
+			if (!Arrays.AreEqual(bytes, enc))
+			{
+				Fail("failed comparison test", Hex.ToHexString(enc), Hex.ToHexString(bytes));
+			}
+		}
+
+		private void validOidCheck(
+			string oid)
+		{
+			DerObjectIdentifier o = new DerObjectIdentifier(oid);
+			o = (DerObjectIdentifier) Asn1Object.FromByteArray(o.GetEncoded());
+
+			if (!o.Id.Equals(oid))
+			{
+				Fail("failed oid check: " + oid);
+			}
+		}
+
+		private void invalidOidCheck(
+			string oid)
+		{
+			try
+			{
+				new DerObjectIdentifier(oid);
+				Fail("failed to catch bad oid: " + oid);
+			}
+			catch (FormatException)
+			{
+				// expected
+			}
+		}
+
+		private void branchCheck(string stem, string branch)
+		{
+			string expected = stem + "." + branch;
+			string actual = new DerObjectIdentifier(stem).Branch(branch).Id;
+
+			if (expected != actual)
+			{
+				Fail("failed 'branch' check for " + stem + "/" + branch);
+			}
+		}
+
+		private void onCheck(String stem, String test, bool expected)
+		{
+			if (expected != new DerObjectIdentifier(test).On(new DerObjectIdentifier(stem)))
+			{
+				Fail("failed 'on' check for " + stem + "/" + test);
+			}
+		}
+
+		public override void PerformTest()
+		{
+			recodeCheck("2.100.3", req1);
+			recodeCheck("1.2.54.34359733987.17", req2);
+
+			validOidCheck(PkcsObjectIdentifiers.Pkcs9AtContentType.Id);
+			validOidCheck("0.1");
+			validOidCheck("1.1.127.32512.8323072.2130706432.545460846592.139637976727552.35747322042253312.9151314442816847872");
+			validOidCheck("1.2.123.12345678901.1.1.1");
+			validOidCheck("2.25.196556539987194312349856245628873852187.1");
+
+			invalidOidCheck("0");
+			invalidOidCheck("1");
+			invalidOidCheck("2");
+			invalidOidCheck("3.1");
+			invalidOidCheck("..1");
+			invalidOidCheck("192.168.1.1");
+			invalidOidCheck(".123452");
+			invalidOidCheck("1.");
+			invalidOidCheck("1.345.23.34..234");
+			invalidOidCheck("1.345.23.34.234.");
+			invalidOidCheck(".12.345.77.234");
+			invalidOidCheck(".12.345.77.234.");
+			invalidOidCheck("1.2.3.4.A.5");
+			invalidOidCheck("1,2");
+
+			branchCheck("1.1", "2.2");
+
+			onCheck("1.1", "1.1", false);
+			onCheck("1.1", "1.2", false);
+			onCheck("1.1", "1.2.1", false);
+			onCheck("1.1", "2.1", false);
+			onCheck("1.1", "1.11", false);
+			onCheck("1.12", "1.1.2", false);
+			onCheck("1.1", "1.1.1", true);
+			onCheck("1.1", "1.1.2", true);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new OidTest();
+			ITestResult	result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/OctetStringTest.cs b/crypto/test/src/asn1/test/OctetStringTest.cs
new file mode 100644
index 000000000..8bae1b057
--- /dev/null
+++ b/crypto/test/src/asn1/test/OctetStringTest.cs
@@ -0,0 +1,186 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class OctetStringTest
+	{
+		[Test]
+		public void TestReadingWriting()
+		{
+			MemoryStream bOut = new MemoryStream();
+			BerOctetStringGenerator octGen = new BerOctetStringGenerator(bOut);
+
+			Stream outStream = octGen.GetOctetOutputStream();
+
+			outStream.Write(new byte[] { 1, 2, 3, 4 }, 0, 4);
+			outStream.Write(new byte[4], 0, 4);
+
+			outStream.Close();
+
+			Asn1StreamParser aIn = new Asn1StreamParser(bOut.ToArray());
+
+			BerOctetStringParser s = (BerOctetStringParser)aIn.ReadObject();
+
+			Stream inStream = s.GetOctetStream();
+			int count = 0;
+
+			while (inStream.ReadByte() >= 0)
+			{
+				count++;
+			}
+
+			Assert.AreEqual(8, count);
+		}
+
+		[Test]
+		public void TestReadingWritingZeroInLength()
+		{
+			MemoryStream bOut = new MemoryStream();
+			BerOctetStringGenerator octGen = new BerOctetStringGenerator(bOut);
+
+			Stream outStream = octGen.GetOctetOutputStream();
+
+			outStream.Write(new byte[] { 1, 2, 3, 4 }, 0, 4);
+			outStream.Write(new byte[512], 0, 512);  // forces a zero to appear in length
+
+			outStream.Close();
+
+			Asn1StreamParser aIn = new Asn1StreamParser(bOut.ToArray());
+
+			BerOctetStringParser s = (BerOctetStringParser)aIn.ReadObject();
+
+			Stream inStream = s.GetOctetStream();
+			int         count = 0;
+
+			while (inStream.ReadByte() >= 0)
+			{
+				count++;
+			}
+
+			Assert.AreEqual(516, count);
+		}
+
+		[Test]
+		public void TestReadingWritingNested()
+		{
+			MemoryStream bOut = new MemoryStream();
+			BerSequenceGenerator sGen = new BerSequenceGenerator(bOut);
+			BerOctetStringGenerator octGen = new BerOctetStringGenerator(sGen.GetRawOutputStream());
+
+			Stream outStream = octGen.GetOctetOutputStream();
+
+			BerSequenceGenerator inSGen = new BerSequenceGenerator(outStream);
+
+			BerOctetStringGenerator inOctGen = new BerOctetStringGenerator(inSGen.GetRawOutputStream());
+
+			Stream inOut = inOctGen.GetOctetOutputStream();
+
+			inOut.Write(new byte[] { 1, 2, 3, 4 }, 0, 4);
+			inOut.Write(new byte[10], 0, 10);
+
+			inOut.Close();
+
+			inSGen.Close();
+
+			outStream.Close();
+
+			sGen.Close();
+
+			Asn1StreamParser aIn = new Asn1StreamParser(bOut.ToArray());
+
+			BerSequenceParser sq = (BerSequenceParser)aIn.ReadObject();
+
+			BerOctetStringParser s = (BerOctetStringParser)sq.ReadObject();
+
+			Asn1StreamParser aIn2 = new Asn1StreamParser(s.GetOctetStream());
+
+			BerSequenceParser sq2 = (BerSequenceParser)aIn2.ReadObject();
+
+			BerOctetStringParser inS = (BerOctetStringParser)sq2.ReadObject();
+
+			Stream inStream = inS.GetOctetStream();
+			int         count = 0;
+
+			while (inStream.ReadByte() >= 0)
+			{
+				count++;
+			}
+
+			Assert.AreEqual(14, count);
+		}
+
+		[Test]
+		public void TestNestedStructure()
+		{
+			MemoryStream bOut = new MemoryStream();
+
+			BerSequenceGenerator sGen = new BerSequenceGenerator(bOut);
+
+			sGen.AddObject(new DerObjectIdentifier(CmsObjectIdentifiers.CompressedData.Id));
+
+			BerSequenceGenerator cGen = new BerSequenceGenerator(sGen.GetRawOutputStream(), 0, true);
+
+			cGen.AddObject(new DerInteger(0));
+
+			//
+			// AlgorithmIdentifier
+			//
+			DerSequenceGenerator algGen = new DerSequenceGenerator(cGen.GetRawOutputStream());
+
+			algGen.AddObject(new DerObjectIdentifier("1.2"));
+
+			algGen.Close();
+
+			//
+			// Encapsulated ContentInfo
+			//
+			BerSequenceGenerator eiGen = new BerSequenceGenerator(cGen.GetRawOutputStream());
+
+			eiGen.AddObject(new DerObjectIdentifier("1.1"));
+
+			BerOctetStringGenerator octGen = new BerOctetStringGenerator(eiGen.GetRawOutputStream(), 0, true);
+
+			//
+			// output containing zeroes
+			//
+			Stream outStream = octGen.GetOctetOutputStream();
+
+			outStream.Write(new byte[] { 1, 2, 3, 4 }, 0, 4);
+			outStream.Write(new byte[4], 0, 4);
+			outStream.Write(new byte[20], 0, 20);
+
+			outStream.Close();
+			eiGen.Close();
+			cGen.Close();
+			sGen.Close();
+
+			//
+			// reading back
+			//
+			Asn1StreamParser aIn = new Asn1StreamParser(bOut.ToArray());
+
+			ContentInfoParser cp = new ContentInfoParser((Asn1SequenceParser)aIn.ReadObject());
+
+			CompressedDataParser comData = new CompressedDataParser((Asn1SequenceParser)cp.GetContent(Asn1Tags.Sequence));
+			ContentInfoParser content = comData.GetEncapContentInfo();
+
+			Asn1OctetStringParser bytes = (Asn1OctetStringParser)content.GetContent(Asn1Tags.OctetString);
+
+			Stream inStream = bytes.GetOctetStream();
+			int count = 0;
+
+			while (inStream.ReadByte() >= 0)
+			{
+				count++;
+			}
+
+			Assert.AreEqual(28, count);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/OtherCertIDUnitTest.cs b/crypto/test/src/asn1/test/OtherCertIDUnitTest.cs
new file mode 100644
index 000000000..a09c18e8a
--- /dev/null
+++ b/crypto/test/src/asn1/test/OtherCertIDUnitTest.cs
@@ -0,0 +1,100 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Esf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class OtherCertIDUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "OtherCertID"; }
+		}
+
+		public override void PerformTest()
+		{
+			AlgorithmIdentifier algId = new AlgorithmIdentifier(new DerObjectIdentifier("1.2.2.3"));
+			byte[] digest = new byte[20];
+			OtherHash otherHash = new OtherHash(new OtherHashAlgAndValue(algId, digest));
+			IssuerSerial issuerSerial = new IssuerSerial(new GeneralNames(new GeneralName(new X509Name("CN=test"))), new DerInteger(1));
+
+			OtherCertID certID = new OtherCertID(otherHash);
+
+			checkConstruction(certID, algId, digest, null);
+
+			certID = new OtherCertID(otherHash, issuerSerial);
+
+			checkConstruction(certID, algId, digest, issuerSerial);
+
+			certID = OtherCertID.GetInstance(null);
+
+			if (certID != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				OtherCertID.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			OtherCertID			certID,
+			AlgorithmIdentifier	algId,
+			byte[]				digest,
+			IssuerSerial		issuerSerial)
+		{
+			checkValues(certID, algId, digest, issuerSerial);
+
+			certID = OtherCertID.GetInstance(certID);
+
+			checkValues(certID, algId, digest, issuerSerial);
+
+			Asn1InputStream aIn = new Asn1InputStream(certID.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			certID = OtherCertID.GetInstance(seq);
+
+			checkValues(certID, algId, digest, issuerSerial);
+		}
+
+		private void checkValues(
+			OtherCertID			certID,
+			AlgorithmIdentifier	algId,
+			byte[]				digest,
+			IssuerSerial		issuerSerial)
+		{
+			checkMandatoryField("hashAlgorithm", algId, certID.OtherCertHash.HashAlgorithm);
+			checkMandatoryField("hashValue", digest, certID.OtherCertHash.GetHashValue());
+
+			checkOptionalField("issuerSerial", issuerSerial, certID.IssuerSerial);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new OtherCertIDUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/OtherSigningCertificateUnitTest.cs b/crypto/test/src/asn1/test/OtherSigningCertificateUnitTest.cs
new file mode 100644
index 000000000..4410d8e4c
--- /dev/null
+++ b/crypto/test/src/asn1/test/OtherSigningCertificateUnitTest.cs
@@ -0,0 +1,94 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Esf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class OtherSigningCertificateUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "OtherSigningCertificate"; }
+		}
+
+		public override void PerformTest()
+		{
+			AlgorithmIdentifier algId = new AlgorithmIdentifier(new DerObjectIdentifier("1.2.2.3"));
+			byte[] digest = new byte[20];
+			OtherHash otherHash = new OtherHash(
+				new OtherHashAlgAndValue(algId, digest));
+			OtherCertID otherCertID = new OtherCertID(otherHash);
+
+			OtherSigningCertificate otherCert = new OtherSigningCertificate(otherCertID);
+
+			checkConstruction(otherCert, otherCertID);
+
+			otherCert = OtherSigningCertificate.GetInstance(null);
+
+			if (otherCert != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				OtherCertID.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			OtherSigningCertificate	otherCert,
+			OtherCertID				otherCertID)
+		{
+			checkValues(otherCert, otherCertID);
+
+			otherCert = OtherSigningCertificate.GetInstance(otherCert);
+
+			checkValues(otherCert, otherCertID);
+
+			Asn1InputStream aIn = new Asn1InputStream(otherCert.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			otherCert = OtherSigningCertificate.GetInstance(seq);
+
+			checkValues(otherCert, otherCertID);
+		}
+
+		private void checkValues(
+			OtherSigningCertificate	otherCert,
+			OtherCertID				otherCertID)
+		{
+			if (otherCert.GetCerts().Length != 1)
+			{
+				Fail("GetCerts() length wrong");
+			}
+			checkMandatoryField("GetCerts()[0]", otherCertID, otherCert.GetCerts()[0]);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new OtherSigningCertificateUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/PKCS10Test.cs b/crypto/test/src/asn1/test/PKCS10Test.cs
new file mode 100644
index 000000000..28736b816
--- /dev/null
+++ b/crypto/test/src/asn1/test/PKCS10Test.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class Pkcs10Test
+        : ITest
+    {
+        byte[]    req1 = Base64.Decode(
+                    "MIHoMIGTAgEAMC4xDjAMBgNVBAMTBVRlc3QyMQ8wDQYDVQQKEwZBbmFUb20xCzAJBgNVBAYTAlNF"
+                +   "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALlEt31Tzt2MlcOljvacJgzQVhmlMoqAOgqJ9Pgd3Gux"
+                +   "Z7/WcIlgW4QCB7WZT21O1YoghwBhPDMcNGrHei9kHQkCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA0EA"
+                +   "NDEI4ecNtJ3uHwGGlitNFq9WxcoZ0djbQJ5hABMotav6gtqlrwKXY2evaIrsNwkJtNdwwH18aQDU"
+                +   "KCjOuBL38Q==");
+
+        byte[]    req2 = Base64.Decode(
+                   "MIIB6TCCAVICAQAwgagxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQH"
+                +  "EwtTYW50YSBDbGFyYTEMMAoGA1UEChMDQUJCMVEwTwYDVQQLHEhQAAAAAAAAAG8AAAAAAAAAdwAA"
+                +  "AAAAAABlAAAAAAAAAHIAAAAAAAAAIAAAAAAAAABUAAAAAAAAABxIAAAAAAAARAAAAAAAAAAxDTAL"
+                +  "BgNVBAMTBGJsdWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANETRZ+6occCOrFxNhfKIp4C"
+                +  "mMkxwhBNb7TnnahpbM9O0r4hrBPcfYuL7u9YX/jN0YNUP+/CiT39HhSe/bikaBPDEyNsl988I8vX"
+                +  "piEdgxYq/+LTgGHbjRsRYCkPtmzwBbuBldNF8bV7pu0v4UScSsExmGqqDlX1TbPU8KkPU1iTAgMB"
+                +  "AAGgADANBgkqhkiG9w0BAQQFAAOBgQAFbrs9qUwh93CtETk7DeUD5HcdCnxauo1bck44snSV6MZV"
+                +  "OCIGaYu1501kmhEvAtVVRr6SEHwimfQDDIjnrWwYsEr/DT6tkTZAbfRd3qUu3iKjT0H0vlUZp0hJ"
+                +  "66mINtBM84uZFBfoXiWY8M3FuAnGmvy6ah/dYtJorTxLKiGkew==");
+
+        public string Name
+        {
+			get
+			{
+				return "Pkcs10";
+			}
+        }
+
+        public ITestResult BasicPkcs10Test(
+            string  testName,
+            byte[]  req)
+        {
+            try
+            {
+				CertificationRequest r = new CertificationRequest(
+					(Asn1Sequence)Asn1Object.FromByteArray(req));
+				byte[] bytes = r.GetDerEncoded();
+
+				if (!Arrays.AreEqual(bytes, req))
+				{
+					return new SimpleTestResult(false, Name + ": " + testName + " failed comparison test");
+				}
+			}
+            catch (Exception e)
+            {
+                return new SimpleTestResult(false, Name + ": Exception - " + testName + " " + e.ToString());
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public ITestResult Perform()
+        {
+            ITestResult res = BasicPkcs10Test("basic CR", req1);
+
+            if (!res.IsSuccessful())
+            {
+                return res;
+            }
+
+            return BasicPkcs10Test("Universal CR", req2);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new Pkcs10Test();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/PKCS12Test.cs b/crypto/test/src/asn1/test/PKCS12Test.cs
new file mode 100644
index 000000000..c20fa8cc6
--- /dev/null
+++ b/crypto/test/src/asn1/test/PKCS12Test.cs
@@ -0,0 +1,210 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class Pkcs12Test
+		: SimpleTest
+	{
+		private static byte[] pkcs12 = Base64.Decode(
+			  "MIACAQMwgAYJKoZIhvcNAQcBoIAkgASCA+gwgDCABgkqhkiG9w0BBwGggCSA"
+			+ "BIIDRDCCA0AwggM8BgsqhkiG9w0BDAoBAqCCArEwggKtMCcGCiqGSIb3DQEM"
+			+ "AQMwGQQUFlnNVpQoEHc+J3UEGxARipkHu5kCAWQEggKAAH9tmy40lly6QDoc"
+			+ "1TfmY9y2qysD+lrgk+dnxP04RfoJfycTRDeaz2sPLImZtio9nsqCFqtzU/sl"
+			+ "eWigbH34BpKU1sC0Gq1cyik0GO65sW95S6YjKtGcGOBfQCPk1oQjfiqnfU3G"
+			+ "oeOaG3COQJukMFj8unv55u0xbX1hwO8SsZmr9RjPzLrVaeY6BP5+CCzOKBaj"
+			+ "GxneIDqnQW7/kBIVWK7M+JXGdgQyiKhD6NvXL/zD8oKEne0nIX7IokQuWEn6"
+			+ "8Sglv5OSclsSdvHTk57bCuV5lVzoIzczA4J/LZWdrtITeVefBLQSalBzpRde"
+			+ "rSTMj485z2x5ChizhjE627/KQ5vkKQkQVqXYYXVyeTvKZRpL7vz13C4DUCwN"
+			+ "im1XvNSCNebXS1yHJRtcONDhGJN3UsrVjHr+2kCfE5SCEeSU/dqgNLuLa1tk"
+			+ "5+jwZFNj/HjO88wlOwPCol1uuJjDpaEW7dxu5qsVSfZhEXWHs8rZAMttFMzi"
+			+ "yxsEkZe8kqngRbNJOY6KpppYedsMWDusUJGfIHo+8zymiw3gv/z+lmFOlDGt"
+			+ "CKMk9Es/MgfjpbfhbTVYHOBKS6Qyrz7LdTuBMI8XdsZMuN+Uf73690ggLmKW"
+			+ "IELUg8h1RX0ra2n6jOc/1rnebAifMhiMkL1ABQvqOobfOrG/9h9XcXoi64Qr"
+			+ "htc3T7yMAHafBX5KUcNkbcn6kssYhpvd8bPADoLBnbx3GxGh/uziB0zKQEI0"
+			+ "GnaY4SL7aR4C5xNNi41lYtsR6ohKyfPEGslhrhd4axx0cKxC2sHgVl0k+r8B"
+			+ "8Vu44XHbW8LqdspjOHN9qg2erES1Dvgj05SfHDup+V6a3ogJo2YKXOiu3DF4"
+			+ "MFEGCSqGSIb3DQEJFDFEHkIARABhAHYAaQBkACAARwAuACAASABvAG8AawAn"
+			+ "AHMAIABWAGUAcgBpAFMAaQBnAG4ALAAgAEkAbgBjAC4AIABJAEQwIwYJKoZI"
+			+ "hvcNAQkVMRYEFKEcMJ798oZLFkH0OnpbUBnrTLgWAAAAAAAAMIAGCSqGSIb3"
+			+ "DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMCcGCiqGSIb3DQEMAQYwGQQUTErH"
+			+ "kWZ8nBXZYWO53FH4yqRZZsECAWSggASCDGCreuCr6/azcOv5w04bN3jkg4G2"
+			+ "dsvTPAjL8bichaEOQCykhuNPt1dv3FsjUsdFC550K0+Y48RyBIID6JTiN9Gj"
+			+ "K+a5aLPaXgTRdY74Toof1hYtZ4DIcVyq25LezVQHoe/++pAgEpWjqHTxVDIv"
+			+ "YFAgT2oDB+2vkeXM61XnNWOjwCY3pXpk/VGjyN4USkD7Q/Y6tPjQOywvQE7c"
+			+ "Ab1z62k9iMia7Yk/qmh+zJu4SSneo0/RLLdMZOlGZv89MResVG038TC8MTA9"
+			+ "Uf+wDRcS20d7XDbTaBAgju8TpFIw5/lbDi0feUVlk6L+jkT1ktaTc1Pwtxn7"
+			+ "psXMFW6HAWB4exOi09297R9BCOQX6vcetK/iA/3jIC6NuTdizYof0DWetdGy"
+			+ "haIkMiEnERYE3unJocH4fq585Rw6mE+BYssPVPkVWZZInF3l69bKduuxsQt+"
+			+ "pcApgBVsTjsU+1FOiUxuW2wWKi70RcQprPv5Ef1A5FRNxPFp+7IzLNlE4qCo"
+			+ "wvC6NTpeuRw3aGsXSfqHmSddrHugNPmghNgG5lv1Ef7A8MUuyp8fyjAgxCDk"
+			+ "4Hpb8PCHGj5t//Fr6Cd0MygJMIFQmv4kUd2LVHxQ9A9WFNCqTz/nBe+ZRLJL"
+			+ "NghTv6gGpjGJiBnXYv6Sod2fs+5J2GIvex4qbdh6gzZIU2YTAwpj6Aca3SjA"
+			+ "X8+m8AXt2SC3Z6T5+m8SxyiNp2P511paV/TZKtLWXQGKeEX1JXhQkaM6Q5W/"
+			+ "IhSgC8/gppk1gbIraBqrW8bEnGBnC03wi0OnMz3ohM4CVHyaW3dQquT2+u6F"
+			+ "8VeGXAYHU022NkrpPl/VlfNNEAyisU2+oJqpPZkqL6FsDWF3k6Fq2jXBLL+/"
+			+ "a0WA82jIpgjNeXze/cgoHtU023V9E9Qcu+5nPBYdCTR4sRxvHLANii0W8lPv"
+			+ "tvU5XO1UsEjHDfKL4E1bhGzGpb/OU5yg/98EN95r/xdFL5G+XVyHeR0UtkcB"
+			+ "IuvyBdhkwoprCjkcgLZe8FPIBNw84HRe7Ye6f2gDW/F5uej6rBehJS1VFvCh"
+			+ "DXzkajGmK40Gc2APS1/1vZqPu68polgw9dT84rem36PLEOq4KuU7n4QE0g7T"
+			+ "YR2G8+4FNgQTjjg/qw3lX+sj6yLn1lYt1dOVvkiM8i8tdZg/3pCKKAW1uV7a"
+			+ "astlBxVSkFfn1BrFTc2oFGkTrlUg90a+parOfGHTfDiaHX8ouEg63fk0+Xdi"
+			+ "FCarXsqHNPDbpmWLKw8TAmdeneGipyScntJJk4ajy+jROQBgGew3ofOmfkqm"
+			+ "oJFNwUvKOXN2ucViLZgsdK/7YgV1OR7oiTh8knQNPk3d5fRYSMFf9GJTjQRV"
+			+ "y2CLdICAVzvrUXf9k7miWYkjIp2/HGD7pOH018sX9MrpfJKqvdPFOssZiFd0"
+			+ "I2FUbgcEggPotvnT0XoabEiurTm8EPPpw66NKmK/H1kQL0hEtdIazPxfLmm/"
+			+ "ZUDokwa7d4bE3BwFh0weQfEvMzJu6Y5E7ir2MqD33XaGMOGys1nst1SPPyDB"
+			+ "WpOWD9w7Ng3yU1JVzqFWuVXaXDYbfnlG7AGevKF5PYNZj/RIQBBf5Xle9hTd"
+			+ "c9CtxPkrsJwA8DeAwKl2WIfbXGzAYLSnXoYUcoTkWn/O81BlUFgAXv80gLe8"
+			+ "NUrH7bhsnyGaPY953NyDk8IWUYrsn/sXvxTy5B0/7/WGMh3CSZrLX3p7TcFY"
+			+ "yBrL6SRas4q9rrcwuhBq0tUUbbgWi92nhZl4bOGmx7ehHnwuUId2HWXyVGoB"
+			+ "qToee/2E4PZFxSZwKCY6dahswFq5QGDrQKN2/qpOLZcJib6SvSGyEZl2pqr0"
+			+ "lqk7tVPzBkN/4uP0qrcbZCDbGW6IXwu3RGMRehqj/HEJcs92lZKfVrk/U07X"
+			+ "MBAiQHqV+kLw7kStECR/MGJG1c0xhqqBrf0W74+LpJiv/Q9iFNdWbXvE/cAk"
+			+ "G7+OTUABd2kI88uA43T0UoRuPOi5KnLuD3AG+7IuyGyP69Xncd4u0srMg2fn"
+			+ "DiLLZUy6vWmxwRFsSMCEfQNLtZaggukoPIihQvbX3mQS9izwLs6D89WtEcZ5"
+			+ "6DVbIlUqUinnNKsT8vW1DZo5FMJkUxB666YIPVmkQbbJOEUU89dZg5Gw0og6"
+			+ "rn4irEr4xHFdx+S7iqJXhzs9THg/9e4/k8KQ136z7LALOqDookcSdBzW6H8c"
+			+ "STjs4qKQyNimsLB90mEuIEApzhseAaLFl+kgORGJv/2a+uoukZchMsJ98MVo"
+			+ "sEPS1oBXJl2m9AshkWfON2GDeJatgcw6CyC1mSx++Gg602ZKUZZUaWxkz1Sw"
+			+ "zTj3nhiJe+SZsdfxhsojNq7zfxqgY/Rq7BwvphU3StjnxvkB4rTkbmbiGOBO"
+			+ "cvTFg4yOtQGRcifk2/XH/bgYiPqQrYSXpO3WRASV005RaSGufcpTtj3YlHGe"
+			+ "8FUgZfDtfiGezhNET9KO3/Q0i34bGEpoIb/9uOWH4ZHULIlfdSm1ynV50nE4"
+			+ "mJTXccrF6BE80KZI5GWGhqXdfPFaHTK1S20+XCw7bRJCGeiwVxvGfB+C0SZ4"
+			+ "ndtqx165dKG5JwFukcygiIZN6foh0/PhwzmFxmPtZuPQt9dtuIQ35Y7PSDsy"
+			+ "IH2Ot0Hh0YIN99lHJ6n9HomSjpwcgDXGssEuevbpz27u/MI/Uhq4Gfx0k5RF"
+			+ "0pcRYtk1dYSx44a+8WgqZLF8DUNtyjSE/H8P5iGa6tqOl7kNyeeEkfoTtKst"
+			+ "asGFwL4Qxxus4GC7repyVi7IJgSCA+iopiqKQJ2IqUHvoIEuD//sZooDx0Je"
+			+ "oFRO5VakkTO6WHd8JpOOEU2f6Zjg++HdIl0QK7xcUaRH075LzEfqgn1vyw6J"
+			+ "N6ex8D76sf/nAy01NvDPij48Z50XDwXu4kJGJvv0AJwId8BpjziBF0j3K/DI"
+			+ "YOOpd6nW4EvdivCgaCnxqlIU/u1OP4BwpO+AUjJh6RKlKviGihQpi103DFhR"
+			+ "yXNDhh55pqgCCCuNeEB+ovRt7UxzlGAVRSxJh1Zbjp/+iQun0E32RlSR4Diz"
+			+ "p5vDk8NBZpIiKRqI+8GWZc3G1igp7dvViTLw4OdWMKwhccV5+3Ll/W72aNVm"
+			+ "azYUoYOVn+OYS1NJkER0tjFOCozRGm5hfkxGlP+02wbH5uu/AQoJMqWIxT6l"
+			+ "46IWC24lmAnDCXuM+gWmwUvyXLwuBdejVK8iG1Lnfg1qztoLpYRbBROgRdpt"
+			+ "2cbPRm+9seqrth3eJbtmxCvuh3bZ3pR2e0/r5Tob/fDcOc5Kp+j4ndXWkwpa"
+			+ "OuH1yxam7zNJR+mcYp1Wiujia5qIeY1QCAEY5QgAWaSHtjlEprwUuootA2Xm"
+			+ "V7D8Vsr9BValhm9zMKj6IzsPmM+HZJWlhHcoucuAmPK6Lnys3Kv/mbkSgNOq"
+			+ "fJDY901veFfKeqiCbAm6hZjNWoQDNJKFhjXUALrcOv9VCFPA3bMW3Xul/sB4"
+			+ "Mq595e+x/1HkNOgZorBv97C6X7ENVDaAFcyZvrRU/ZeDnvFhisfxS4EJhzxl"
+			+ "cWWnQhzD+ur1FTTlkmUFzgoB/rW+i3XigiHOuRRnkcoMy1uV17rwH8eELHJu"
+			+ "Yni5vu2QUaD4jNEhliE2XCsn8Sm6bcXnfzBa7FXC39QvAcdJHzqcD6iIwjIz"
+			+ "hKLu+/XoWFMFFNsgV78AwzPAn6TRya8LLCYPoIZkEP4qBoeZtUZ8PIS/Y7M9"
+			+ "QStMwa/NI9SPswb3iScTGvor/obUEQS4QM6mVxFMpQWfwJfyU6jingX4EHRE"
+			+ "mqvZ3ehzU8ZLOdKzRKuk022YDT7hwEQ+VL0Fg0Ld9oexqT96nQpUTHZtDRMV"
+			+ "iTuJoUYTneDs2c9tsY4mWBqamZQSfTegj4sLMZagkuSUp/SpPM2zSGuD3nY6"
+			+ "u3553gIM9jYhvLBEXwjGudVCwMd3bqo/4EhnKb2PcwUzdaMkipQlNteHZjBT"
+			+ "1ici63xjJva+di0qTV+W9cyYyHwg1927X2qcMh06BhbHlcXQKbgmbL18KJEt"
+			+ "K+GGhGNkP7mtPyHHgBb6vref/z8p7oxT2CG+oBuN/z+xQoYfe9c4IC3e/kNN"
+			+ "DIoyYvPyEzAdfMS2aL8qDxzc5GH9UE9kcusJ/2dNEFTzBH2GK1CItL3IACv/"
+			+ "LwX1SkI0w7oIQTL127CSnuTrUUkvJ/+rOYScQTMD/ntZPdLdu2ffszg3SzhN"
+			+ "ELgojK8ss1OBlruWRHw/fP736Nx8MNsuOvXMnO8lruz+uyuEhF3BLv96oTcg"
+			+ "XVHdWhPmOoqNdBQdRgAAAAAAAAAAAAAAAAAAAAAAADA8MCEwCQYFKw4DAhoF"
+			+ "AAQUJMZn7MEKv4vW/+voCVyHBa6B0EMEFJOzH/BEjRtNNsZWlo/4L840aE5r"
+			+ "AgFkAAA=");
+
+		public override void PerformTest()
+		{
+			Asn1Sequence obj = (Asn1Sequence) Asn1Object.FromByteArray(pkcs12);
+
+			Pfx                 bag = new Pfx(obj);
+			ContentInfo         info = bag.AuthSafe;
+			MacData             mData = bag.MacData;
+			DigestInfo          dInfo = mData.Mac;
+			AlgorithmIdentifier algId = dInfo.AlgorithmID;
+			byte[]              salt = mData.GetSalt();
+			int                 itCount = mData.IterationCount.IntValue;
+
+			byte[] octets = ((Asn1OctetString) info.Content).GetOctets();
+			AuthenticatedSafe authSafe = new AuthenticatedSafe(
+				(Asn1Sequence) Asn1Object.FromByteArray(octets));
+			ContentInfo[] c = authSafe.GetContentInfo();
+
+			//
+			// private key section
+			//
+			if (!c[0].ContentType.Equals(PkcsObjectIdentifiers.Data))
+			{
+				Fail("Failed comparison data test");
+			}
+
+			octets = ((Asn1OctetString)c[0].Content).GetOctets();
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(octets);
+
+			SafeBag b = new SafeBag((Asn1Sequence)seq[0]);
+			if (!b.BagID.Equals(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag))
+			{
+				Fail("Failed comparison shroudedKeyBag test");
+			}
+
+			EncryptedPrivateKeyInfo encInfo = EncryptedPrivateKeyInfo.GetInstance(b.BagValue);
+
+			encInfo = new EncryptedPrivateKeyInfo(encInfo.EncryptionAlgorithm, encInfo.GetEncryptedData());
+
+			b = new SafeBag(PkcsObjectIdentifiers.Pkcs8ShroudedKeyBag, encInfo.ToAsn1Object(), b.BagAttributes);
+
+			byte[] encodedBytes = new DerSequence(b).GetEncoded();
+
+			c[0] = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(encodedBytes));
+
+			//
+			// certificates
+			//
+			if (!c[1].ContentType.Equals(PkcsObjectIdentifiers.EncryptedData))
+			{
+				Fail("Failed comparison encryptedData test");
+			}
+
+			EncryptedData eData = EncryptedData.GetInstance(c[1].Content);
+
+			c[1] = new ContentInfo(PkcsObjectIdentifiers.EncryptedData, eData);
+
+			//
+			// create an octet stream to represent the BER encoding of authSafe
+			//
+			authSafe = new AuthenticatedSafe(c);
+
+			info = new ContentInfo(PkcsObjectIdentifiers.Data, new BerOctetString(authSafe.GetEncoded()));
+
+			mData = new MacData(new DigestInfo(algId, dInfo.GetDigest()), salt, itCount);
+
+			bag = new Pfx(info, mData);
+
+			//
+			// comparison test
+			//
+			if (!Arrays.AreEqual(bag.GetEncoded(), pkcs12))
+			{
+				Fail("Failed comparison test");
+			}
+		}
+
+		public override string Name
+		{
+			get { return "Pkcs12"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Pkcs12Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/PKIFailureInfoTest.cs b/crypto/test/src/asn1/test/PKIFailureInfoTest.cs
new file mode 100644
index 000000000..734dbbc14
--- /dev/null
+++ b/crypto/test/src/asn1/test/PKIFailureInfoTest.cs
@@ -0,0 +1,76 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	/**
+	* PKIFailureInfoTest
+	*/
+	[TestFixture]
+	public class PkiFailureInfoTest
+		: SimpleTest
+	{
+		// A correct hex encoded BAD_DATA_FORMAT PkiFailureInfo
+		private static readonly byte[] CORRECT_FAILURE_INFO = Base64.Decode("AwIANQ==");
+
+		public override string Name
+		{
+			get { return "PkiFailureInfo"; }
+		}
+
+		private void doTestEncoding()
+		{
+			DerBitString bitString = (DerBitString) Asn1Object.FromByteArray(CORRECT_FAILURE_INFO);
+			PkiFailureInfo correct = new PkiFailureInfo(bitString);
+
+			PkiFailureInfo bug = new PkiFailureInfo(PkiFailureInfo.BadRequest | PkiFailureInfo.BadTime | PkiFailureInfo.BadDataFormat | PkiFailureInfo.IncorrectData);
+
+			if (!Arrays.AreEqual(correct.GetDerEncoded(), bug.GetDerEncoded()))
+			{
+				Fail("encoding doesn't match");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			BitStringConstantTester.testFlagValueCorrect(0, PkiFailureInfo.BadAlg);
+			BitStringConstantTester.testFlagValueCorrect(1, PkiFailureInfo.BadMessageCheck);
+			BitStringConstantTester.testFlagValueCorrect(2, PkiFailureInfo.BadRequest);
+			BitStringConstantTester.testFlagValueCorrect(3, PkiFailureInfo.BadTime);
+			BitStringConstantTester.testFlagValueCorrect(4, PkiFailureInfo.BadCertId);
+			BitStringConstantTester.testFlagValueCorrect(5, PkiFailureInfo.BadDataFormat);
+			BitStringConstantTester.testFlagValueCorrect(6, PkiFailureInfo.WrongAuthority);
+			BitStringConstantTester.testFlagValueCorrect(7, PkiFailureInfo.IncorrectData);
+			BitStringConstantTester.testFlagValueCorrect(8, PkiFailureInfo.MissingTimeStamp);
+			BitStringConstantTester.testFlagValueCorrect(9, PkiFailureInfo.BadPop);
+			BitStringConstantTester.testFlagValueCorrect(14, PkiFailureInfo.TimeNotAvailable);
+			BitStringConstantTester.testFlagValueCorrect(15, PkiFailureInfo.UnacceptedPolicy);
+			BitStringConstantTester.testFlagValueCorrect(16, PkiFailureInfo.UnacceptedExtension);
+			BitStringConstantTester.testFlagValueCorrect(17, PkiFailureInfo.AddInfoNotAvailable);
+			BitStringConstantTester.testFlagValueCorrect(25, PkiFailureInfo.SystemFailure);
+
+			doTestEncoding();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PkiFailureInfoTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/ParseTest.cs b/crypto/test/src/asn1/test/ParseTest.cs
new file mode 100644
index 000000000..c649fdb8d
--- /dev/null
+++ b/crypto/test/src/asn1/test/ParseTest.cs
@@ -0,0 +1,303 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class ParseTest
+    {
+        private static readonly byte[] classCastTest = Base64.Decode(
+            "MIIXqAYJKoZIhvcNAQcDoIIXmTCCF5UCAQAxggG1MIIBsQIBADCBmDCBkDEL"
+            + "MAkGA1UEBhMCVVMxETAPBgNVBAgTCE1pY2hpZ2FuMQ0wCwYDVQQHEwRUcm95"
+            + "MQwwCgYDVQQKEwNFRFMxGTAXBgNVBAsTEEVMSVQgRW5naW5lZXJpbmcxJDAi"
+            + "BgkqhkiG9w0BCQEWFUVsaXQuU2VydmljZXNAZWRzLmNvbTEQMA4GA1UEAxMH"
+            + "RURTRUxJVAIDD6FBMA0GCSqGSIb3DQEBAQUABIIBAGh04C2SyEnH9J2Va18w"
+            + "3vdp5L7immD5h5CDZFgdgHln5QBzT7hodXMVHmyGnycsWnAjYqpsil96H3xQ"
+            + "A6+9a7yB6TYSLTNv8zhL2qU3IrfdmUJyxxfsFJlWFO1MlRmu9xEAW5CeauXs"
+            + "RurQCT+C5tLc5uytbvw0Jqbz+Qp1+eaRbfvyhWFGkO/BYZ89hVL9Yl1sg/Ls"
+            + "mA5jwTj2AvHkAwis+F33ZhYlto2QDvbPsUa0cldnX8+1Pz4QzKMHmfUbFD2D"
+            + "ngaYN1tDlmezCsYFQmNx1th1SaQtTefvPr+qaqRsm8KEXlWbJQXmIfdyi0zY"
+            + "qiwztEtO81hXZYkKqc5fKMMwghXVBgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcE"
+            + "CEq3cLLWVds9gIIVsAAik3al6Nn5pr7r0mSy9Ki3vEeCBcV9EzEG44BvNHNA"
+            + "WyEsqQsdSxuF7h1/DJAMuZFwCbGflaRGx/1L94zrmtpeuH501lzPMvvZCmpj"
+            + "KrOF8e1B4MVQ5TfQTdUVyRnbcDa6E4V1ZZIdAI7BgDeJttS4+L6btquXfxUg"
+            + "ttPYQkevF7MdShYNnfLkY4vUMDOp3+iVzrOlq0elM95dfSA7OdBavgDJbz/7"
+            + "mro3AFTytnWjGz8TUos+oUujTk9/kHOn4cEAIm0hHrNhPS5qoj3QnNduNrad"
+            + "rLpGtcYyNlHIsYCsvPMxwoHmIw+r9xQQRjjzmVYzidn+cNOt0FmLs6YE8ds4"
+            + "wvHRO9S69TgKPHRgk2bihgHqII9lF9qIzfG40YwJLHzGoEwVO1O0+wn8j2EP"
+            + "O9I/Q3vreCH+5VbpUD2NGTwsMwZ3YlUesurLwse/YICxmgdN5Ro4DeQJSa9M"
+            + "iJnRFYWRq+58cKgr+L11mNc9nApZBShlpPP7pdNqWOafStIEjo+dsY/J+iyS"
+            + "6WLlUvNt/12qF4NAgZMb3FvRQ9PrMe87lqSRnHcpLWHcFjuKbMKCBvcdWGWI"
+            + "R7JR8UNzUvoLGGAUI9Ck+yTq4QtfgtL5MLmdBGxSKzgs44Mmek+LnrFx+e9n"
+            + "pkrdDf2gM/m7E50FnLYqzUjctKYGLNYpXQorq9MJx6TB20CHXcqOOoQqesXa"
+            + "9jL9PIOtBQy1Ow5Bh4SP07nTFWFSMI/Wt4ZvNvWJj3ecA9KjMOA9EXWUDS/H"
+            + "k9iCb2EEMo7fe5mhoyxMxPO+EIa1sEC9A1+rDACKPQCHOLI0uPmsdo0AEECC"
+            + "QLgOQkcwQlkHexOyHiOOtBxehtGZ1eBQQZ+31DF+RRU6WvS6grg58eS4gGOQ"
+            + "bd7CS9yYebvAQkz61J8KprWdtZuG1gBGma12wKMuQuC6RuWlKsj+rPMvaQCt"
+            + "8mucGbkElPGZVhdyD8/BvpSCNbgRwb6iSiw4EECovu4P4GFJaMGUYEuCA711"
+            + "itEieYc1QqS6ULjb3LFL/RcwSw0fGdjnt6B2nHckC2VsYKU1NwU7j0R1Omb4"
+            + "y5AvSgpuWjTXWnHnE9Ey0B+KP5ERZA+jJGiwYz48ynYlvQFSbBm4I6nh/DuI"
+            + "dWB2dLNxWuhdfzafBGtEHhLHzjW3WQwwRZsKesgHLrrj9hBUObodl1uvqvZN"
+            + "AjMOj8DrqbGOhAClj1t4S1Zk1ZekuMjsuoxEL+/lgtbT+056ES0k3A/LnpRb"
+            + "uxA1ZBr26Im+GVFzEcsV0hB4vNujSwStTTZH5jX5rMyi085yJfnikcLYUn9N"
+            + "apl+srhpIZlDJPw7IHaw8tsqXKDxF7MozIXo8B45CKv5Am+BMrIemCMX/ehu"
+            + "PODICl98Ur8tNAn1L+m0nj7H3c8HW2vNuBLEI3SEHHgm2Ij3IY5pyyeVUaWC"
+            + "pumhy8Ru5dj3fZcfKgYuJBQxWMf+UqPsf4iUK3923pouJ1cQ8XU8gOXIRrtX"
+            + "e41d/yR+UAZXSig6SITLw+wLtvitSvtxvjcUSUOI9CYTovKyuz1PQKiaLsV5"
+            + "4CoJhMQ5uRlVFS3H829I2d2gLRpSp6pNWeIZO2NMBxPYf2qcSHyHqQjR7xP2"
+            + "ZTg7U3OO6dZHORfXxzAnW2ExavBIYQmZh1gLn5jSS4wXFPXyvnJAsF4s5wed"
+            + "YHsyAqM/ek0n2Oo/zAh7UcP2vcb9FOoeRK8qC9HjTciS6WbjskRN0ft4T69G"
+            + "+1RsH8/edBxo2LZeA48BSCXDXOlBZJBsOptzYJD8HSZONPnef0jn23lk0fkU"
+            + "C3BjJu2ubFChctRvJniTko4klpidkHwuJgrTnL4er8rG3RfiiEHn/d5era15"
+            + "E1cekdVYWqwQOObOd4v+0gZSJgI48TBc5Qdy8F6wIU38DR2pn/5uNthNDgXk"
+            + "NcV9a2gOE3DoLe8CEIPMihqYMPY8NuSp97eHB2YhKpjP7qX9TUMoOdE2Iat2"
+            + "klNxadJt6JTFeiBPL6R9RHAD5sVBrkrl0S+oYtgF92f9WHVwAXU7zP6IgM4x"
+            + "hhzeJT07yyIp44mKd//F+7ntbgQjZ/iLbHh0mtOlUmzkFsDR0UNSXEQoourZ"
+            + "EY4A62HXj0DMqEQbik6QwEF7FKuwZX2opdOyVKH9MzJxNfDLd5dc8wAc8bCX"
+            + "jcCx5/GzHx2S5DndWQEVhp2hOQYuoJS3r6QCYFaHtDPKnFHS2PBFyFWL+2UK"
+            + "c0WsvVaHYqYKnksmxse9I9oU75kx5O05DZCThPX6h8J8MHRuxU9tcuuleIUQ"
+            + "XY8On+JeEtLSUZgp+Z7ITLuagf6yuKQpaR396MlDii/449/dvBiXAXeduyO1"
+            + "QzSkQCh37fdasqGL3mP0ssMcxM/qpOwQsx3gMtwiHQRi1oQE1QHb8qZHDE4m"
+            + "I5afQJ9O/H/m/EVlGUSn2yYOsPlZrWuI3BBZKoRzRq1lZOQDtOh18BE3tWmX"
+            + "viGIAxajam0i2Ce3h2U7vNwtiePRNEgPmQ7RwTTv0U6X8qqkjeYskiF4Cv9G"
+            + "nrB0WreC19ih5psEWLIkCYKTr+OhQuRrtv7RcyUi9QSneh7BjcvRjlGB6joA"
+            + "F6J4Y6ENAA/nzOZJ699VkljTi59bbNJYlONpQhOeRTu8M/wExkIJz7yR9DTY"
+            + "bY4/JdbdHNFf5DSDmYAHaFLmdnnfuRy+tC9CGGJvlcLVv5LMFJQGt2Wi15p8"
+            + "lctx7sL6yNCi7OakWbEOCvGPOxY7ejnvOjVK/Krx1T+dAXNUqrsDZmvmakOP"
+            + "We+P4Di1GqcyLVOTP8wNCkuAUoN0JFoBHy336/Xnae91KlY4DciPMpEOIpPN"
+            + "oB+3h6CozV7IWX5Wh3rhfC25nyGJshIBUS6cMXAsswQI8rOylMlGaekNcSU4"
+            + "gNKNDZAK5jNkS0Z/ziIrElSvMNTfYbnx3gCkY0pV18uadmchXihVT11Bt77O"
+            + "8KCKHycR39WYFIRO09wvGv6P42CRBFTdQbWFtkSwRiH8l6x39Z7pIkDFxokT"
+            + "Dp6Htkj3ywfQXNbFgRXZUXqgD1gZVFDFx920hcJnuu65CKz6pEL6X0XUwNPg"
+            + "vtraA2nj4wjVB/y+Cxc+1FgzeELB4CAmWO1OfRVLjYe7WEe/X5DPT6p8HBkB"
+            + "5mWuv+iQ3e37e1Lrsjt2frRYQWoOSP5Lv7c8tZiNfuIp07IYnJKBWZLTqNf9"
+            + "60uiY93ssE0gr3mfYOj+fSbbjy6NgAenT7NRZmFCjFwAfmapIV0hJoqnquaN"
+            + "jj5KKOP72hp+Zr9l8cEcvIhG/BbkY3kYbx3JJ9lnujBVr69PphHQTdw67CNB"
+            + "mDkH7y3bvZ+YaDY0vdKOJif9YwW2qoALXKgVBu1T2BONbCTIUTOzrKhWEvW8"
+            + "D6x03JsWrMMqOKeoyomf1iMt4dIOjp7yGl/lQ3iserzzLsAzR699W2+PWrAT"
+            + "5vLgklJPX/Fb3Tojbsc074lBq669WZe3xzlj85hFcBmoLPPyBE91BLhEwlGC"
+            + "+lWmwFOENLFGZE0mGoRN+KYxwqfA2N6H8TWoz6m0oPUW4uQvy9sGtYTSyQO9"
+            + "6ZwVNT3ndlFrP5p2atdEFVc5aO5FsK8/Fenwez06B2wv9cE9QTVpFrnJkKtF"
+            + "SaPCZkignj64XN7cHbk7Ys6nC3WIrTCcj1UOyp5ihuMS9eL9vosYADsmrR6M"
+            + "uqqeqHsf2+6U1sO1JBkDYtLzoaILTJoqg9/eH7cTA0T0mEfxVos9kAzk5nVN"
+            + "nVOKFrCGVIbOStpYlWP6wyykIKVkssfO6D42D5Im0zmgUwgNEkB+Vxvs8bEs"
+            + "l1wPuB2YPRDCEvwM3A5d5vTKhPtKMECIcDxpdwkD5RmLt+iaYN6oSFzyeeU0"
+            + "YvXBQzq8gfpqJu/lP8cFsjEJ0qCKdDHVTAAeWE6s5XpIzXt5cEWa5JK7Us+I"
+            + "VbSmri4z0sVwSpuopXmhLqLlNWLGXRDyTjZSGGJbguczXCq5XJ2E3E4WGYd6"
+            + "mUWhnP5H7gfW7ILOUN8HLbwOWon8A6xZlMQssL/1PaP3nL8ukvOqzbIBCZQY"
+            + "nrIYGowGKDU83zhO6IOgO8RIVQBJsdjXbN0FyV/sFCs5Sf5WyPlXw/dUAXIA"
+            + "cQiVKM3GiVeAg/q8f5nfrr8+OD4TGMVtUVYujfJocDEtdjxBuyFz3aUaKj0F"
+            + "r9DM3ozAxgWcEvl2CUqJLPHH+AWn5kM7bDyQ2sTIUf5M6hdeick09hwrmXRF"
+            + "NdIoUpn7rZORh0h2VX3XytLj2ERmvv/jPVC97VKU916n1QeMJLprjIsp7GsH"
+            + "KieC1RCKEfg4i9uHoIyHo/VgnKrnTOGX/ksj2ArMhviUJ0yjDDx5jo/k5wLn"
+            + "Rew2+bhiQdghRSriUMkubFh7TN901yl1kF2BBP5PHbpgfTP6R7qfl8ZEwzzO"
+            + "elHe7t7SvI7ff5LkwDvUXSEIrHPGajYvBNZsgro+4Sx5rmaE0QSXACG228OQ"
+            + "Qaju8qWqA2UaPhcHSPHO/u7ad/r8kHceu0dYnSFNe1p5v9Tjux0Yn6y1c+xf"
+            + "V1cu3plCwzW3Byw14PH9ATmi8KJpZQaJOqTxn+zD9TvOa93blK/9b5KDY1QM"
+            + "1s70+VOq0lEMI6Ch3QhFbXaslpgMUJLgvEa5fz3GhmD6+BRHkqjjwlLdwmyR"
+            + "qbr4v6o+vnJKucoUmzvDT8ZH9nH2WCtiiEtQaLNU2vsJ4kZvEy0CEajOrqUF"
+            + "d8qgEAHgh9it5oiyGBB2X/52notXWOi6OMKgWlxxKHPTJDvEVcQ4zZUverII"
+            + "4vYrveRXdiDodggfrafziDrA/0eEKWpcZj7fDBYjUBazwjrsn5VIWfwP2AUE"
+            + "wNn+xR81/so8Nl7EDBeoRXttyH7stbZYdRnkPK025CQug9RLzfhEAgjdgQYw"
+            + "uG+z0IuyctJW1Q1E8YSOpWEFcOK5okQkLFUfB63sO1M2LS0dDHzmdZriCfIE"
+            + "F+9aPMzojaHg3OQmZD7MiIjioV6w43bzVmtMRG22weZIYH/Sh3lDRZn13AS9"
+            + "YV6L7hbFtKKYrie79SldtYazYT8FTSNml/+Qv2TvYTjVwYwHpm7t479u+MLh"
+            + "LxMRVsVeJeSxjgufHmiLk7yYJajNyS2j9Kx/fmXmJbWZNcerrfLP+q+b594Y"
+            + "1TGWr8E6ZTh9I1gU2JR7WYl/hB2/eT6sgSYHTPyGSxTEvEHP242lmjkiHY94"
+            + "CfiTMDu281gIsnAskl05aeCBkj2M5S0BWCxy7bpVAVFf5nhf74EFIBOtHaJl"
+            + "/8psz1kGVF3TzgYHkZXpUjVX/mJX8FG0R8HN7g/xK73HSvqeamr4qVz3Kmm/"
+            + "kMtYRbZre7E1D10qh/ksNYnOkYBcG4P2JyjZ5q+8CQNungz2/b0Glg5LztNz"
+            + "hUgG27xDOUraJXjkkZl/GOh0eTqhfLHXC/TfyoEAQOPcA59MKqvroFC5Js0Q"
+            + "sTgqm2lWzaLNz+PEXpJHuSifHFXaYIkLUJs+8X5711+0M03y8iP4jZeEOrjI"
+            + "l9t3ZYbazwsI3hBIke2hGprw4m3ZmSvQ22g+N6+hnitnDALMsZThesjb6aJd"
+            + "XOwhjLkWRD4nQN594o6ZRrfv4bFEPTp4ev8l6diouKlXSFFnVqz7AZw3Pe53"
+            + "BvIsoh66zHBpZhauPV/s/uLb5x6Z8sU2OK6AoJ7b8R9V/AT7zvonBi/XQNw3"
+            + "nwkwGnTS9Mh7PFnGHLJWTKKlYXrSpNviR1vPxqHMO6b+Lki10d/YMY0vHQrY"
+            + "P6oSVkA6RIKsepHWo11+rV838+2NRrdedCe91foUmOs+eoWQnwmTy2CTZmQ5"
+            + "b7/TTcau9ewimZAqI+MtDWcmWoZfgibZmnIITGcduNOJDRn+aLt9dz+zr1qA"
+            + "HxlLXCOyBPdtfx6eo4Jon+fVte37i3HmxHk+8ZGMMSS9hJbLQEkA59b4E+7L"
+            + "GI3JZjvEkhizB4n/aFeG7KT7K3x072DMbHLZ7VgsXQ1VDDmcZmizFwgyNqKy"
+            + "hKCKxU+I2O10IMtiZUpEzV1Pw7hD5Kv/eFCsJFPXOJ2j3KP6qPtX5IYki1qH"
+            + "Juo5C5uGKtqNc6OzkXsvNUfBz5sJkEYl0WfitSSo4ARyshFUNh2hGxNxUVKM"
+            + "2opOcuHSxBgwUSmVprym50C305zdHulBXv3mLzGjvRstE9qfkQ8qVJYLQEkL"
+            + "1Yn7E92ex71YsC8JhNNMy0/YZwMkiFrqyaFd/LrblWpBbGumhe4reCJ4K3mk"
+            + "lFGEsICcMoe+zU1+QuLlz/bQ+UtvClHUe8hTyIjfY04Fwo2vbdSc1U/SHho5"
+            + "thQy+lOZ/HijzCmfWK3aTqYMdwCUTCsoxri2N8vyD/K2kbMLQWUfUlBQfDOK"
+            + "VrksBoSfcluNVaO56uEUw3enPhhJghfNlJnpr5gUcrAMES53DfkjNr0dCsfM"
+            + "JOY2ZfQEwwYey1c4W1MNNMoegSTg4aXzjVc0xDgKa7RGbtRmVNbOxIhUNAVi"
+            + "thQV3Qujoz1ehDt2GyLpjGjHSpQo3WlIU4OUqJaQfF6EH+3khFqUmp1LT7Iq"
+            + "zH3ydYsoCDjvdXSSEY3hLcZVijUJqoaNWBLb/LF8OG5qTjsM2gLgy2vgO/lM"
+            + "NsqkHnWTtDimoaRRjZBlYLhdzf6QlfLi7RPmmRriiAOM0nXmylF5xBPHQLoz"
+            + "LO9lXYIfNbVJVqQsV43z52MvEQCqPNpGqjB+Au/PZalYHbosiVOQLgTB9hTI"
+            + "sGutSXXeLnf5rftCFvWyL3n5DgURzDFLibrbyVGGKAk166bK1RyVP9XZJonr"
+            + "hPYELk4KawCysJJSmC0E8sSsuXpfd6PPDru6nCV1EdXKR7DybS7NVHCktiPR"
+            + "4B4y8O/AgfJX8sb6LuxmjaINtUKEJ1+O88Gb69uy6b/Kpu2ri/SUBaNNw4Sn"
+            + "/tuaD+jxroL7RlZmt9ME/saNKn9OmLuggd6IUKAL4Ifsx9i7+JKcYuP8Cjdf"
+            + "Rx6U6H4qkEwwYGXnZYqF3jxplyOfqA2Vpvp4rnf8mST6dRLKk49IhKGTzwZr"
+            + "4za/RZhyl6lyoRAFDrVs1b+tj6RYZk0QnK3dLiN1MFYojLyz5Uvi5KlSyFw9"
+            + "trsvXyfyWdyRmJqo1fT7OUe0ImJW2RN3v/qs1k+EXizgb7DW4Rc2goDsCGrZ"
+            + "ZdMwuAdpRnyg9WNtmWwp4XXeb66u3hJHr4RwMd5oyKFB1GsmzZF7aOhSIb2B"
+            + "t3coNXo/Y+WpEj9fD7/snq7I1lS2+3Jrnna1048O7N4b5S4b5TtEcCBILP1C"
+            + "SRvaHyZhBtJpoH6UyimKfabXi08ksrcHmbs1+HRvn+3pl0bHcdeBIQS/wjk1"
+            + "TVEDtaP+K9zkJxaExtoa45QvqowxtcKtMftNoznF45LvwriXEDV9jCXvKMcO"
+            + "nxG5aQ//fbnn4j4q1wsKXxn61wuLUW5Nrg9fIhX7nTNAAooETO7bMUeOWjig"
+            + "2S1nscmtwaV+Sumyz/XUhvWynwE0AXveLrA8Gxfx");
+
+        private static readonly byte[] derExpTest = Base64.Decode(
+            "MIIS6AYJKoZIhvcNAQcDoIIS2TCCEtUCAQAxggG1MIIBsQIBADCBmDCBkDEL"
+            + "MAkGA1UEBhMCVVMxETAPBgNVBAgTCE1pY2hpZ2FuMQ0wCwYDVQQHEwRUcm95"
+            + "MQwwCgYDVQQKEwNFRFMxGTAXBgNVBAsTEEVMSVQgRW5naW5lZXJpbmcxJDAi"
+            + "BgkqhkiG9w0BCQEWFUVsaXQuU2VydmljZXNAZWRzLmNvbTEQMA4GA1UEAxMH"
+            + "RURTRUxJVAIDD6FBMA0GCSqGSIb3DQEBAQUABIIBAGsRYK/jP1YujirddAMl"
+            + "ATysfLCwd0eZhENohVqLiMleH25Dnwf+tBaH4a9hyW+7VrWw/LC6ILPVbKpo"
+            + "oLBAOical40cw6C3zulajc4gM3AlE2KEeAWtI+bgPMXhumqiWDb4byX/APYk"
+            + "53Gk7WXF6Xs4hj3tmrHSJxCUOsTdHKUJYvOqjwKGARPQDjP0EUbVJezeAwBA"
+            + "RMlJ/qBVLBj2UW28n5oJZm3oaSaU93Uc6GPVIk43IWrmEUcWVPiMfUtUCwcX"
+            + "tRNtHuQ9os++rmdNBiuB5p+vtUeA45KWnTUtkwJXvrzE6Sf9AUH/p8uOvvZJ"
+            + "3yt9LhPxcZukGIVvcQnBxLswghEVBgkqhkiG9w0BBwEwFAYIKoZIhvcNAwcE"
+            + "CGObmTycubs2gIIQ8AKUC8ciGPxa3sFJ1EPeX/nRwYGNAarlpVnG+07NITL2"
+            + "pUzqZSgsYh5JiKd8TptQBZNdebzNmCvjrVv5s9PaescGcypL7FNVPEubh0w/"
+            + "8h9rTACqUpF5yRgfcgpAGeK29F1hyZ1WaIH43avUCaDnrZcOKB7wc1ats1aQ"
+            + "TSDLImyFn4KjSo5k0Ec/xSoWnfg391vebp8eOsyHZhFMffFtKQMaayZNHJ7Q"
+            + "BzG3r/ysUbkgI5x+0bX0QfZjEIs7yuV5Wt8DxMTueCm3RQ+HkR4lNdTBkM4V"
+            + "qozCqC1SjcAF5YHB0WFkGouEPGgTlmyvLqR2xerEXVZn9YwSnT48kOde3oGt"
+            + "EAYyg0yHbNbL0sp6LDM7upRmrgWwxf0BR6lP4wyWdv/XSLatEB7twSNiPBJ4"
+            + "PJ+QagK08yQJ84UB7YpMTudKsaUs7zW76eA7KkW3TndfDYGdhbmZ5wxNl+5x"
+            + "yPZc/jcQHW7vplMfWglUVxnzibNW12th0QXSB57Mzk8v1Rvc/HLGvAOJZG/S"
+            + "N12FZOxbUrMIHGi3kXsmfWznVyq92X4P9tuDDD7sxkSGsyUAm/UJIZ3KsXhV"
+            + "QeaRHVTVDxtJtnbYxBupy1FDBO6AhVrp16Blvnip9cPn/aLfxDoFHzmsZmEg"
+            + "IcOFqpT1fW+KN6i/JxLD3mn3gKzzdL1/8F36A2GxhCbefQFp0MfIovlnMLFv"
+            + "mrINwMP8a9VnP8gIV5oW5CxmmMUPHuGkXrfg+69iVACaC2sTq6KGebhtg9OC"
+            + "8vZhmu7+Eescst694pYa3b8Sbr5bTFXV68mMMjuRnhvF2NZgF+O0jzU+sFps"
+            + "o7s1rUloCBk1clJUJ/r+j9vbhVahCeJQw62JAqjZu4R1JYAzON3S7jWU5zJ7"
+            + "pWYPSAQkLYUz3FmRRS2Yv65mXDNHqR9vqkHTIphwA9CLMKC2rIONxSVB57q1"
+            + "Npa/TFkVdXnw+cmYjyFWiWeDP7Mw0Kwy7tO008UrBY0rKQU466RI5ezDqYPc"
+            + "Lm73dUH2EjUYmKUi8zCtXpzgfTYVa/DmkbVUL9ThHMVRq1OpT2nctE7kpXZk"
+            + "OsZjEZHZX4MCrSOlc10ZW7MJIRreWMs70n7JX7MISU+8fK6JKOuaQNG8XcQp"
+            + "5IrCTIH8vmN2rVt4UT8zgm640FtO3jWUxScvxCtUJJ49hGCwK+HwDDpO6fLw"
+            + "LFuybey+6hnAbtaDyqgsgDh2KN8GSkQT9wixqwQPWsMQ4h0xQixf4IMdFOjP"
+            + "ciwp3ul8KAp/q70i0xldWGqcDjUasx6WHKc++rFjVJjoVvijKgEhlod5wJIw"
+            + "BqQVMKRsXle07NS1MOB+CRTVW6mwBEhDDERL+ym2GT2Q4uSDzoolmLq2y5vL"
+            + "+RfDHuh3W0UeC3Q5D2bJclgMsVjgfQUN19iD+lPFp2xvLTaNWi5fYDn4uuJL"
+            + "lgVDXIMmM8I+Z2hlTXTM1Pldz2/UFe3QXTbYnjP6kfd7Bo2Webhhgs/YmSR2"
+            + "XPuA42tWNAAjlK77lETWodxi3UC7XELjZ9xoGPRbxjOklXXvev9v5Vo+vcmN"
+            + "0KrLXhLdkyHRSm81SRsWoadCTSyT8ibv66P00GOt+OlIUOt0YKSUkULQfPvC"
+            + "EgMpeTm1/9l8n9bJ6td5fpJFDqLDm+FpJX6T2sWevV/Tyt6aoDPuET5iHBHW"
+            + "PoHxKl8YPRHBf+nRWoh45QMGQWNSrJRDlO8oYOhdznh4wxLn3DXEfDr0Z7Kd"
+            + "gEg6xr1XCobBn6Gi7wWXp5FDTaRF41t7fH8VxPwwDa8Yfu3vsgB6q426kjAj"
+            + "Q77wx1QFIg8gOYopTOgqze1i4h1U8ehP9btznDD6OR8+hPsVKoXYGp8Ukkc7"
+            + "JBA0o8l9O2DSGh0StsD94UhdYzn+ri7ozkXFy2SHFT2/saC34NHLoIF0v/aw"
+            + "L9G506Dtz6xXOACZ4brCG+NNnPLIcGblXIrYTy4+sm0KSdsl6BGzYh9uc8tu"
+            + "tfCh+iDuhT0n+nfnvdCmPwonONFb53Is1+dz5sisILfjB7OPRW4ngyfjgfHm"
+            + "oxxHDC/N01uoJIdmQRIisLi2nLhG+si8+Puz0SyPaB820VuV2mp77Y2osTAB"
+            + "0hTDv/sU0DQjqcuepYPUMvMs3SlkEmaEzNSiu7xOOBQYB8FoK4PeOXDIW6n2"
+            + "0hv6iS17hcZ+8GdhwC4x2Swkxt99ikRM0AxWrh1lCk5BagVN5xG79c/ZQ1M7"
+            + "a0k3WTzYF1Y4d6QPNOYeOBP9+G7/a2o3hGXDRRXnFpO7gQtlXy9A15RfvsWH"
+            + "O+UuFsOTtuiiZk1qRgWW5nkSCPCl2rP1Z7bwr3VD7o6VYhNCSdjuFfxwgNbW"
+            + "x8t35dBn6xLkc6QcBs2SZaRxvPTSAfjON++Ke0iK5w3mec0Br4QSNB1B0Aza"
+            + "w3t3AleqPyJC6IP1OQl5bi+PA+h3YZthwQmcwgXgW9bWxNDqUjUPZfsnNNDX"
+            + "MU9ANDLjITxvwr3F3ZSfJyeeDdbhr3EJUTtnzzWC6157EL9dt0jdPO35V0w4"
+            + "iUyZIW1FcYlCJp6t6Sy9n3TmxeLbq2xML4hncJBClaDMOp2QfabJ0XEYrD8F"
+            + "jq+aDM0NEUHng+Gt9WNqnjc8GzNlhxTNm3eQ6gyM/9Ip154GhH6c9hsmkMy5"
+            + "DlMjGFpFnsSTNFka2+DOzumWUiXLGbe4M3RePl1N4MLwXrkR2llguQynyoqF"
+            + "Ptat2Ky5yW2q9+IQHY49NJTlsCpunE5HFkAK9rY/4lM4/Q7hVunP6U4a0Kbu"
+            + "beFuOQMKQlBZvcplnYBefXD79uarY/q7ui6nFHlqND5mlXMknMrsQk3papfp"
+            + "OpMS4T07rCTLek0ODtb5KsHdIF76NZXevko4+d/xbv7HLCUYd8xuOuqf+y4I"
+            + "VJiT1FmYtZd9w+ubfHrOfHxY+SBtN6fs02WAccZqBXUYzZEijRbN2YUv1OnG"
+            + "rfYe4EcfOu/Sa+wLbB7msYpLfvUfEO3iseKf4LXZkgtF5P610PBZR8edeSgr"
+            + "YZW+J0K78PRAl5nEi1mvzBxi9DyNf6iQ9mWLyyCmr9p9HGE+aCMKVCn9jfZH"
+            + "WeBDAJNYDcUh5NEckqJtbEc2S1FJM7yZBWLQUt3NCQvj+nvQT45osZ3BJvFg"
+            + "IcGJ0CysoblVz4fCLybrYxby9HP89WMLHqdqsIeVX8IJ3x84SqLPuzrqf9FT"
+            + "ZVYLo0F2oBjAzjT7obt9+NJc/psOMCg+OGQkAfwj3VNvaqkkQsVxSiozgxrC"
+            + "7KaTXuAL6eKKspman96kz4QVk9P0usUPii+LFnW4XYc0RNfgJVO6BgJT7pLX"
+            + "NWwv/izMIMNAqSiWfzHHRVkhq4f1TMSF91auXOSICpJb3QQ4XFh52Mgl8+zs"
+            + "fobsb0geyb49WqFrZhUu+X+8LfQztppGmiUpFL+8EW0aPHbfaf4y9J1/Wthy"
+            + "c28Yqu62j/ljXq4Qa21uaEkoxzH1wPKCoKM9TXJtZJ39Yl9cf119Qy4M6QsB"
+            + "6oMXExlMjqIMCCWaLXLRiqbc2Y7rZHgEr08msibdoYHbSkEl8U+Kii2p6Vdx"
+            + "zyiEIz4CadrFbrAzxmrR/+3u8JuBdq0K3KNR0WWx73BU+G0rgBX56GnP7Ixy"
+            + "fuvkRb4YfJUF4PkDa50BGVhybPrIhoFteT6bSh6LQtBm9c4Kop8Svx3ZbqOT"
+            + "kgQDa0n+O0iR7x3fvNZ0Wz4YJrKGnVOPCqJSlSsnX6v2JScmaNdrSwkMTnUf"
+            + "F9450Hasd88+skC4jVAv3WAB03Gz1MtiGDhdUKFnHnU9HeHUnh38peCFEfnK"
+            + "WihakVQNfc72YoFVZHeJI5fJAW8P7xGTZ95ysyirtirxt2zkRVJa5p7semOw"
+            + "bL/lBC1bp4J6xHF/NHY8NQjvuhqkDyNlh3dRpIBVBu6Z04hRhLFW6IBxcCCv"
+            + "pjfoxJoox9yxKQKpr3J6MiZKBlndZRbSogO/wYwFeh7HhUzMNM1xIy3jWVVC"
+            + "CrzWp+Q1uxnL74SwrMP/EcZh+jZO4CYWk6guUMhTo1kbW03BZfyAqbPM+X+e"
+            + "ZqMZljydH8AWgl0MZd2IAfajDxI03/6XZSgzq24n+J7wKMYWS3WzB98OIwr+"
+            + "oKoQ7aKwaaT/KtR8ggUVYsCLs4ScFY24MnjUvMm+gQcVyeX74UlqR30Aipnf"
+            + "qzDRVcAUMMNcs0fuqePcrZ/yxPo+P135YClPDo9J8bwNpioUY8g+BQxjEQTj"
+            + "py3i2rAoX+Z5fcGjnZQVPMog0niIvLPRJ1Xl7yzPW0SevhlnMo6uDYDjWgQ2"
+            + "TLeTehRCiSd3z7ZunYR3kvJIw1Kzo4YjdO3l3WNf3RQvxPmJcSKzeqKVxWxU"
+            + "QBMIC/dIzmRDcY787qjAlKDZOdDp7qBKIqnfodWolxBA0KhvE61eYabZqUCT"
+            + "G2HJaQE1SvOdL9KM4ORFlxE3/dqv8ttBJ6N1qKk423CJjajZHYTwf1dCfj8T"
+            + "VAE/A3INTc6vg02tfkig+7ebmbeXJRH93KveEo2Wi1xQDsWNA+3DVzsMyTqV"
+            + "+AgfSjjwKouXAznhpgNc5QjmD2I6RyTf+hngftve18ZmVhtlW5+K6qi62M7o"
+            + "aM83KweH1QgCS12/p2tMEAfz//pPbod2NrFDxnmozhp2ZnD04wC+6HGz6bX/"
+            + "h8x2PDaXrpuqnZREFEYzUDKQqxdglXj5oE/chBR8+eBfYSS4JW3TBkW6RfwM"
+            + "KOBBOOv8pe3Sfq/bg7OLq5bn0jKwulqP50bysZJNlQUG/KqJagKRx60fnTqB"
+            + "7gZRebvtqgn3JQU3fRCm8ikmGz9XHruoPlrUQJitWIt4AWFxjyl3oj+suLJn"
+            + "7sK62KwsqAztLV7ztoC9dxldJF34ykok1XQ2cMT+uSrD6ghYZrmrG5QDkiKW"
+            + "tOQCUvVh/CorZNlON2rt67UvueMoW+ua25K4pLKDW316c2hGZRf/jmCpRSdb"
+            + "Xr3RDaRFIK6JpmEiFMMOEnk9yf4rChnS6MHrun7vPkf82w6Q0VxoR8NRdFyW"
+            + "3mETtm2mmG5zPFMMD8uM0BYJ/mlJ2zUcD4P3hWZ8NRiU5y1kazvrC6v7NijV"
+            + "o459AKOasZUj1rDMlXDLPloTHT2ViURHh/8GKqFHi2PDhIjPYUlLR5IrPRAl"
+            + "3m6DLZ7/tvZ1hHEu9lUMMcjrt7EJ3ujS/RRkuxhrM9BFlwzpa2VK8eckuCHm"
+            + "j89UH5Nn7TvH964K67hp3TeV5DKV6WTJmtIoZKCxSi6FFzMlky73gHZM4Vur"
+            + "eccwycFHu+8o+tQqbIAVXaJvdDstHpluUCMtb2SzVmI0bxABXp5XrkOOCg8g"
+            + "EDZz1I7rKLFcyERSifhsnXaC5E99BY0DJ/7v668ZR3bE5cU7Pmo/YmJctK3n"
+            + "m8cThrYDXJNbUi0c5vrAs36ZQECn7BY/bdDDk2NPgi36UfePI8XsbezcyrUR"
+            + "ZZwT+uQ5LOB931NjD5GOMEb96cjmECONcRjB0uD7DoTiVeS3QoWmf7Yz4g0p"
+            + "v9894YWQgOl+CvmTERO4dxd7X5wJsM3Y0acGPwneDF+HtQrIpJlslm2DivEv"
+            + "sikc6DtAQrnVRSNDr67HPPeIpgzThbxH3bm5UjvnP/zcGV1W8Nzk/OBQWi0l"
+            + "fQM9DccS6P/DW3XPSD1+fDtUK5dfH8DFf8wwgnxeVwi/1hCBq9+33XPwiVpz"
+            + "489DnjGhHqq7BdHjTIqAZvNm8UPQfXRpeexbkFZx1mJvS7so54Cs58/hHgQN"
+            + "GHJh4AUCLEt0v7Hc3CMy38ovLr3Q8eZsyNGKO5GvGNa7EffGjzOKxgqtMwT2"
+            + "yv8TOTFCWnZEUTtVA9+2CpwfmuEjD2UQ4vxoM+o=");
+
+		private static readonly byte[] longTagged = Hex.Decode("9f1f023330");
+
+		[Test]
+		public void TestClassCast()
+        {
+            ParseEnveloped(classCastTest);
+        }
+
+		[Test]
+		public void TestDerExp()
+        {
+            ParseEnveloped(derExpTest);
+        }
+
+        [Test]
+		public void TestLongTag()
+		{
+			Asn1StreamParser aIn = new Asn1StreamParser(longTagged);
+			Asn1TaggedObjectParser tagged = (Asn1TaggedObjectParser)aIn.ReadObject();
+
+			Assert.AreEqual(31, tagged.TagNo);
+		}
+
+		private void ParseEnveloped(
+			byte[] data)
+        {
+            Asn1StreamParser aIn = new Asn1StreamParser(data);
+
+			ContentInfoParser cP = new ContentInfoParser((Asn1SequenceParser)aIn.ReadObject());
+
+			EnvelopedDataParser eP = new EnvelopedDataParser((Asn1SequenceParser)cP.GetContent(Asn1Tags.Sequence));
+
+			eP.GetRecipientInfos().ToAsn1Object(); // Must drain the parser!
+
+			EncryptedContentInfoParser ecP = eP.GetEncryptedContentInfo();
+
+			Asn1OctetStringParser content = (Asn1OctetStringParser)ecP.GetEncryptedContent(Asn1Tags.OctetString);
+
+			Streams.Drain(content.GetOctetStream());
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/ParsingTest.cs b/crypto/test/src/asn1/test/ParsingTest.cs
new file mode 100644
index 000000000..bb219e2fc
--- /dev/null
+++ b/crypto/test/src/asn1/test/ParsingTest.cs
@@ -0,0 +1,104 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	public class ParsingTest
+		: SimpleTest
+	{
+		private static readonly string[] streams = {
+			"oRNphCO0F+jcMQKC1uMO8qFBPikDDYmtfVGeB45xvbfj1qu696YGjdW2igRnePYM/KkQtADG7gMHIhqBRcl7dBtkejNeolOklPNA3NgsACTiVN9JFUsYq0a5842+TU+U2/6Kt/D0kvz0WmwWFRPHWEWVM9PYOWabGsh28Iucc6s7eEqmr8NEzWUx/jM3dmjpFYVpSpxt2KbbT+yUO0EqFQyy8hQ7JvKRgv1AoWQfPjMsfjkKgxnA8DjenmwXaZnDaKEvQIKQl46L1Yyu3boN082SQliSJMJVgNuNNLFIt5QSUdG1ant5O6f9Yr0niAkAoqGzmqz+LZE1S7RrGHWiQ3DowE9NzviBuaAoI4WdCn1ClMwb9fdEmBMU4C7DJSgs3qaJzPUuaAT9vU3GhZqZ0wcTV5DHxSRzGLqg9JEJRi4qyeuG3Qkg3YBtathl+FiLJ7mVoO3dFIccRuuqp2MpMhfuP1DxHLNLNiUZEhLMQ0CLTGabUISBuyQudVFlKBZIpcLD0k7fKpMPuywrYiDrTinMc2ZP3fOGevoR5fnZ6kZAE5oMTtMNokzBuctGqVapblXNrVMLYbriT538oYz5",
+			"KEKVhHxtyUR9D3v5K4IJbVQLAMiVKoK9z7wFWUjzvLFNLg9C/r8zKfBa3YgZrt0Nq64+MxBePMbiNLCnfditc2qUcQZUHnvNnhwT6uGK37JmXg7MvQiKwvi31EIYt6ghqBZVs1iaqc0ep7wuQ16uwSQMlaDdXc9Qf1L0dGO/6eLyREz+p4UR4NOXK+GooQLfMxYL40zJlYcwNyR0rigvIr84WP2IMS2hZjqXtyS6HMM4yUv70hkIorjr7+JC4GtU1MyWuPuNSAGen0AZTaEEXd5sMbqXMqWg3jeM4mzRH1Kb3WdAChO5vMJZPBj9jZZKgXzmxkUh5GlIhUdYgztoNceBzQ3PIc7slCDUw9I2PjB87xsfy7jA5tFtFADs2EUyxUTMCuhilP664jSHgwbrr80k9Xc4sU+MCwCq2nQmcZYcPgKb4M31VJMlKwnZF3JUU2Jtqgg4gbErw58YoBwSkEcMJ2Juhiyx9U36MzxHs9OcTURfpsilMy+mDL8arCDx1knM1KkAHCLjWuJI+p1PvuIypgCwVc+MtGfd7wW8iR1JPJLBiuoZyNJ+xx9htd/HVB+rLtB57H8Gz8W+R00f",
+			"Ol9I/rXMwbLpxTY97v70B+HCl2+cojz2574x/cC56A7KGVF13La8RdzOOvSkl338ct9T/blEFa6QwNz3GmF+MoPdH9lncwz+tqixIqGU02Bp5swH0qjbp/Yjaeq91eR6B+9fl+KKrpglBr8S1BrI4Ey5v3AxxJdCWP8Gd+6Sp15/HMYanwlHBpCsW4+Kq8sGJoJXUXpQ/GBUJKs+WjX1zE6PsvF7/B8cByuqE3NJt7x4Oa+qZtF8qNc0CFDNj31Yhdt7JkAoD30IAd+ue9OhImQMCWwFwySRIRJXU3865K2dBR+VhLuI2aKzLh7MlgVKJk6b2P/ZIkc86ksR1sOUiHrs9EdoYuIssAgMc8QGzn4VN8lxopdzQYVG6pbXGS/VQlHkGdyLd+OHt4srz/NTUWiOquVTRxa6GgtlBFfIXikPTb+iT2pZKyKUlBvpgo0BY9vVUadsteHAI5qrFZBrL5ecK/Qtl9hf/M8qEjyjt2aCXe9B96Hg2QR5A53qW2PJW5VzS0AeB3g+zJSPCTpygrBs20q5Xrna0ux2l17r6HT9Q/AXIOkwPZUXXn0d02igS4D6Hxrg3Fhdp+OTXL8G",
+			"o3eXWpwAGmUkxHEKm/pGkDb1ZQQctCQ06lltZjeMXDp9AkowmA0KXjPQCQwyWE/nqEvk2g/58AxNU0TWSujo5uU0h4/hdMZ7Mrj33NSskWvDpKe7lE5tUjPi74Rmc5RRS+1T/EQobpNxoic3+tTO7NBbZfJtcUYeZ3jqxL+3YQL3PrGe/Zpno9TnQW8mWbbhKhDRtKY4p3Pgk9hPSpJCM9xYo3EMAOAIiH2P6RKH6uX/gSaUY2b6DE/TT0V6v/jdSmYM4+cnYiTyJCi5txI35jfCqIlVCXJd7klirvUMg9SXBhGR25AgQ5Z8yjd7lbB8FvD8JQAXZrp6xiHxbLIW7G11fWEo7RGLFtALI6H38Ud0vKjsEN7N5AibJcxS2A/CWk9R00sTHRBHFUP8o5mz8nE7FeCiwJPs/+tCt04nGb9wxBFMsmWcPEDfIzphCaO6U/D/tQHlA846gbKoikv/6LI0ussSR/i85XBclNcvzTctxylSbCR02lZ+go6fe5rmMouiel/0Tndz8t1YpQGilVeOQ3mqAFyAJk3dgfTNKZuOhNzVIZ5GWScKQ5ZtNcWrg6siR+6YwKvLiRb/TJZk",
+			"PwRUnW4yU8PI7ggbI1BIO9fcTup8optkqCirodyHCiqsPOMZ4g28bJ2+kpfQRujWGlKFYQzA1ZT32s9hdci+fvXPX0KAjcUgcxsGzMABFbEm04BwDF2WLgg9s4/x71r5JrgME1S08I3mCo4N0eFHWDeLJL1b5YNNo6tfO5V2WpIE867N9zdAgvp1gijVjUNWqEB3A/NLb3reLMu2hYgqRFTCVBfcFclD46k0XEfUJqwWdQhOz92WNl/3g53bjKX1hDZgjLIzK6m+SU6+J/h4NidrS7E0gOBevZW8gRYdKMVqNWxzUfxv6kgG+kIeF9JqMcO6jdh/Zu/0tpZoHFeCweZ1jT1eEtltFu1FcTTPc1UT0pT+ZNVgefrBONoGnvn8+dBjPese6F2TmRCExJq9taKlIh/kHdkbpaa7vwrBpYRgVGfARPyM9SSCaE7pVBDuwkFeYiGU4tamm5Gq10ojRQgetJ3UOg/PGTJcxo97GBiG5zAST9NdHdgK3eI4FAbWpGwmWxNpPWOst0a7zuGKAzYU+1IQh8XA3IgJ2vy3+w0JihU6G+12LUzsL2aQtpG7d1PqLhwOqHq3Qqv3SDsB",
+			"ZIAKizvGzbvqvqOlxOeVgHGHV9TfKNjjqyzbCj8tggv2yp7kkq1D3yRlC349tuul3zN9g4u83Ctio9Gg3HiLzMULxoOImF/hKRDhJpPLbLm0jSq1fyF+N7/YvyLeFhGoPhYEBUihDcxo1NIcWy66aBt3EuOlTyDQWrDe0Za3mrTrrl10uLHVKcQMgeD+UMgjQqmHzQJR8wdNjHPKHWVvZEdiwI031nV2giHJHXv08Jvf4vmw4dAlH2drCl6cBgg33jy7ohK8IiXz6eCw6iY9Ri8YaMzxOhgE2BOHzEz5ZC2hilL4xO/ambTER4bhb4+9VTUIehHP18FcXm8TKPQRMqyKP2fMlzWW3/uelYfPP5SHlyLAULa1KjDCkLIDunEKZDpv2ljGB6JPrTlNwFsvlZcihfOAwjbr2jW3MwP704OA8xzd/dynBU47unIZEu0LAvQ3TUz3PLga0GGO1LZGtg0Foo9zFG2wuVCdgYHmozOQ+8I3gRguW1CjGy7ZCTBuN1GZ510ERhae+bRQtldHsLeiHTghnkU1xEX1+W0iEf3csDYrgpuq3NaBYRGirovDiPBYFHmru0AMclhFnpcX",
+			"uG0wQ55kMlfZtJFAqTl0bnYW/oy9NFOi0e4FqAYwsvMxGO4JtGzXgkVwEUAC0AUDItRUjxBl+TkoPTYaprgn0M/NQvKPpXJ+yzI7Ssi+F2alLR0T6eF/4rQ32AVjnANJaghXZm0ZKduckbhSxk5lilJVJRuzXKchZRtlPluvlj448bq+iThktsEQoNP8NMpi7n/EVxovp+dow4Q6t7msSRP4cGXtyYoWKbf/7e5XzBKOZZ1/f3s86uJke4dcKIaljpJfBrtuFxZC6NYXzX6PkoDoBgqQ8RBrxsX54S9cBDAPxxmkq8zviAOW3oqPMULGGmQzHBiRwE8oeDFoMnzF5aR/lkbNuTLOxhbIkosgLWlDNVEFYx9bVhdLzO7VwaAK829dimlPOo5loKB7Pd2G7ekRKXwu7wNvJBq8KRkhtLKbKoS8D6TaRWUMb9VBJ1CMy4mrw+YwTmAKURQ6Dko9J/RgzRg5Y/sUlwdMYS9HOnvKiTVu5I/ha35wwkhIPVm+FCn05tstntZaXXXu4xExHeugAKNBhkcc/SQt+GFdxXDd+R4C2LfKxGDSyZKVTFYojHTdZUo8Gx6SZLY6b2SZ",
+			"sH0kIwIq1THAfTLfqUKJfG1YauCQKPc9/mk3l39yK6zgxSpCH2IjZIwhhJtGm3F+8PTneT725OuyR617nxqrgqMGkkZkyY4DA5CjsikpBo5mo8TspX1g+vtXXtxymJMTMo8JwX3nSH4gSb3vPia+gwOW2TcJmxVdp3ITPA4gJpMfqoMBqRM+eDWO6QXW5ijVL4+wnp40u5bU4fQLVzpg25+QGLqBHD6PZTQaN6F9Vy5XpsAGDlncCklVuX3Lkp3Xb9cTiNa/4ii04uwZqx0juszjwFAMPPb6u56crvN1x4FXfXzabWECHbdQLlKazowvU9bEnqG2i4H44Ae+v8Iw8HK5mbZ6ercLTD9oPgs7Ogal037l2WwLApUz/fmD5fV8SxHh+vKDpfOzv6xcQxynS82jAJw9AdUwE/4ndGzzHPIu2M81gbAgZQ02EurMMU62hYgiXeridrtyh+H5R+CiwQdEyX7/op6WVihsYj2O3O/1hgjhGQRFD6sGwnko50jgWRxaMMfJGNlyGoT8WT5k931jU7547u7Ovr7XP/t8r3G7ceCiCcYjQgdwXdvIStzPvvV7Yy02isZjiJF8TLJQ",
+			"tycxf1mOz1yLE6cT/ZlCxMeTxlEEHFeIdw0+nF/40Tsw4vLco+4kR2A6cVml611CSpN6l/RMKk2LnAkprrbJ/Uam902WBnQ+I6Vsl6GkFFq7362bdixojqMFVKYytXLCT8I78f6s8M6a3jSALQloD6Ftvn+cc+cctO3weaaaPgAlrz+f2MFs8bqpnLQYbbY/JS9IAYJFH+yVtLz7eKcedEp9JMlJ3/43szU2fDN9ZMxBoQnxEmF3WZv6GF0WRc8VhTblXRgk4mlz6Fu3IXvwW/rbn+VCYYIk/XaVLrxFAnnw6mBozAF7vmV0OrIYBlSDU8rMb+F7AvE7pwErO9TJtCE8IUvQf8TsJYRoYv21/X57pzcBedtqVeU3DnTlmESHxG6H1uJbadSFLWSxKS4svfp8T9FWqX5815yD/UplAKEIeorLTAlPIC2ASKDU6SQW260biNAfY8FYQCWa8btaTwFuY8NMwSHzyqgU0aoPKnagi/4hOIWNO5rZ8Xcnzx+ELtEl33hQnzc4OUlT5eeVYQWkz2IWVQ6Re4JWF3L4OXzNZWgefKGMzZU6IHoBeCgfi+popLRJpaOx0dcvwGjk",
+			"oDsoFvUA+sGOoMyZY6w1UhY3NBkeoozzjEkDSRN1golyXJ1dC5CtYNEjvAJYKj+sqNwg9mBlYyybYpnI3GSP125zMeBHPCoy5CoNOkJW4OH/oLyjVeQbFNic/b2Jcz6lTguYhep8hq9EM2XuFV8T1rm5+4ucI7fH1UiOqRZyuHBAJ0Cna5kv6D3efsa9rd+swybiMIUjmPWpyxzNOOihCYuf4JqRh/D5eZKm6x0Zj2uRhTAYYxI7Q3czd0R9490ufG8VbF8ASBMireMONNNAA/OZCpxJh6xnIANBqV6YDeysws3NBWY2QuNumvg5Kr3/g+VMzJHi4wGuJjraKWi9+ylMfelHF5h/h+pAQVxCotq8JU3OTnMUW4rQp2a8BR5S+mZqPSPlb87tDG9r0+yqb1uO4UIo71C7Xxwoq4M0tXjk6mSmtP/sm+Lh14qfUzKRhTHVdz91TK104mbTJNXbK+jGPD/2BJO9fiaXY8IYanpfDLBfJo06VYbm6HehRZTwnDHnN50j7ki4aMS3COZvffjRInXD8dS5h9zmtKNpoqg//lPg4gpS+4Th2sJ3SGtBV0Ne89r7AfZMAVa26PMK",
+			"MIDLuZTrtZnEBOB6l14iSEyokAg5Wf5JviumhfPeL7WSFTHfOodU2hrvhyvM6oAlRHY1blTj7mw+Tcf9Tmc+/FHT6PGu0NT5UAqaqChX0gS9jizgAE2Yfhd4X/DoeQySMAixKuhu8TbvDxb54jeW9+7LVkmlntJ/0SkMgsT+WQ31OfpwDmEGDczYc+Ol14aJS+EW+rnGv9d38bo/cy+EnpNh8iV2rGGoC8fDzFHKU4gqGFSZF/tnD2OfCne0Vjr/GD6kyp2MVcHig19DBg2toGRkHnuY5kLkwOanztXA80IaAmv8e6s62U8CE8ozUZeDBcvBigEkSGx79Vsyiks8+9Kq9xLHLeS5kRT6zSl8whe8U1fIfrgic34KPlozcQVahwCru1XWyQ+9uevih8x4zMftkJ3JBZhPrnlgtx9McntH/Ss9fdUEkNwWpDnq8Xby8/5gMMMwQ13XDB73vqqteDiltMq8i7LRez4iIHfSBBfIkZIzMZAblQXaSm029iBcAAUes7wcGHUl7KOpRy18jNtI3+h7e1Ri6sT2vJYQaove0nzZ5xAjpBKnbJX+lpGVlI00fC2YSTfyNqFA0jkL",
+			"MG4QbKLbQR3enPn6Z/kEUtHrzWBIqYKR7Gvs5QHLPF6417p1O58suZq38Bb8dO5udtgOqNEVAPGmOuidYygWWfWOP5ReggTUk5XlrkvRxCU0MHWbkSKkJ+T4nLjozreqTJ0io41sFVrpxuOugAvXJ6QtMmixSABUaNgU9SkkWf9pOEiJI8dfND51HxJCbXHwsMCMBp5FbaMZmlWPwirRdAox4wbLk9ZLmoWUcorUjdaWhKvT/LnjMgPmwnwwKpN/4MOnRDdAPdzXX3aWHdkzpfsQnqt3UJsTsSaJlzeUja5C5L4CXGyt99qmfcwB8OB9TL4EYTIl3maD/gUWBfckOsji8x2E2c2iuKKrcmMmcChYr4wCjtTjEeVKOAZ2m9mU2MKc2z2hDw3AuZxsY6aOtdAjnrwl5QXGRg9I5LVl5SI5RwnLwk90pJzDGuSSCtSmzh9DUZ4WpfN+1393aTGRqCMOsB4KxbXjspUbVMFJbnXXlsSNWaoFTpHjK6b6Ghi2/re7KJpoKElM3nGs3qvxdvGTKu7LKr/sgKDL6uQLRKoyk8AHSIGX9c8ZUTk7Sq9jV9p4QfV1WFVpaBxSsEmw",
+			"MR0BACgWKis9/AKwG9/ARgGWJn1aM3nU8YXzWG+b7aeRUkVCjl4WxeL38E3FAMLW4UcyLzxeb+CskOqhPPTglmxhK7jQcrNILsWcZvdZfApYIvk5uKqA5FKuUuL48uvD0aKGRENe/VEUFlkQru5YX4Xnp+ZThrJJlgn7ANat/qAdP6ULEcLaOQlLYcGRh5ttsJTRT4+cZQggTJjWt+9idUQ66HfC6zQ1qHcMuochy7GHiUmNXAs0AgwOF9Jwet/Qh74KGMtmppJ9gkEqiYECFQA2gVgKc1AufHJS6S6Re72FfH/UkL41L2hvlwktkD5/hZrUZ1R+RG12Eip2zKgus4g/aGl0V8B/JvkcnFUsZJ6uxs24arOBDJOuzzxky5F5B/hwVGPEdcfHunqndUcx26/KCK72hOljlqTXl8yEbXlcMqVFNByZLr7TnGzGGUlO7kuHPW/ItZUJvrHokpsLLrb3ZhEZ8pTQd75gFcf0Ve8CYzEtk2ISHtNJQV6Iz4AZHWssU6F6YWM/OlJz5JGTtPHfGMJXgl4oxbBjeenS3JQ0X7vWXYMwPe3U1dat6m5hrRC1KzI6e6w+gPDtF8GQ",
+			"DH2WX6XoIseX6lHIey3seUr3DAz82fyk0jL7xc5IDTrDfqS64QBhHDpqHETF/81MrPXsM3IANBfjDOl9g/gua8wWPpPNxuWZMNh0GLcAr6PJ939TCbjE3soZHF2wiA82nZEO8jIZosDVRWFUfJS6Y3nrJz63SExqB6OUdBfvSfz1Y1M/90ofBxkfeuS85deMdn+1rZdsnZJYwz2Z6lCDvYjUTfrSwfVFJBP8Y2BXr8WClUYkfGG4eNG7IPNBRuMmhrhHj5y9z+5Jor+EbbTi5F5Jvdu2/bDM7s32XsaMNLYuVtNYONrbQ+3QZ746/yKZM4hDREvxyGLgDx3Apz7pyvwKm0//iTCY3yJLxZifGLh2uc28cFBln7IH1x8oui4Xq9vF+Z2EH4Ow48Ln5pzggBKMGy4dsfW6266TNYd/Z3SZUi28sxondqhGCSGUo7ZVPAOoYDcYKvjdI/cJ688PHliyZSYBYVmR5HBxZ57sqWwgZQ7zVvwv4CHHysvb92sPrXijHxBIkwpNuK56UMyQCcywlTRLDCMAMNAEGi4fWbDQIoPfn+NixMhEieg3Zh7GXPwHxW8morlgBW5aF76P",
+			"AwClK6Tq9R2DYGf8RAHu9dEttLeOfUVmS4WPwX0NehsnyM7y7n2sgGnXsiva3yFqK1hKZICkVukvHF7/bpgEEm/jRwcAhQUoG+c1qVde38eHJXj58YOBGTveruc+021or9/tHBtenmYPO6+arLQtONi43NKm7+I6ugkgQlp6iBr4haa0XMDTzMX9c8Qm/O+MrVo3qESYKkVtoSSK7SGZTBaRWNF/dOM0NQxeMP+XTVOuroqE23ZNsubBTEZnd4vUilFb/iKnhyT9XnIo7gM/Yz7HLVU5yc3yIj2sFUE+DcwpvcNO5EnPhj3bHsJvf3N4r72+5my2KjoR3KAJE1Imabd54o4xZ/9UaR93qLkVuXMkLRCCU/zlZDtfbJDsRR0C5rSYd2k6IPlNcl7PgmUpsNPUyoDYqvhuRUZxgoUAfKbogzJX8FU/QpllsKVtt68ucBi0bqC5pVKu23j79nDvYQsSlYY3JwJQaM5M558J5qpP1yEF2p4kSRphnB9UR29wWgch5eWZ4a02LlHVM5Msl6W5PdmHt+eFARBRv6edIyYDFzxm4WZroH5F/GxBhM0KObgawkxa5VWsYm0VhhXb",
+			"KACwq8rZuOLHuNnZJA07WzI7kppCwptbcYU2B7t86QcZrnadCtxoM5QNcl9rsbMA26iWCPV3VlDAmLSWcxtMoSKWuo4edJpk8K915xkFU5U6I/901vx5hqAECQDy/Q+QDWmWTXDoVHqFV9wvIj3wCJPpJL/Ewpl0NZd+68jjOjUhjIdNebLrWNK2nhTPiIjFjkcVqEgashpOmnbHT+2MV/CHoixmUEiuRI1B0dvSf7FHGRgbXGBubisuu60g8XTens5zyRo4Qn/LTxIu2aj4LTtyLonV3sXr+y35A1zq5mCrE1f1nOINVzwYYY76iJGIaBkZuMU3366FPIbYkmXwla6RQU1FA0Y7n05qczw7Ie5TveRTByKFtUqW8OAb9vH+H2ezJ4CXE3AGbu/nTj64KClO/zL499GA+97g+X6tTN6xOJdNknlqw6ZnFNtCL8+A3hL4OyOgWD0IGC+xFvcKjDUaaJenCtQvprCJaFrvoOS+yYmixnFqglnPYL/64/Lca8NmDVpPzlHI8HNwUDzKiXTw3q7GnQZWmUYzu1vLIEi6/hyqrULRN1vLdd/8HCMNQFj4ot61UftHtOG8MCKa",
+			"rUABPQ3SEWE5rY16pM+o+7EObLNM1jEa5YCMQM/aen0PWajWNax3Pyo6TZL8aGDXZF0yWqDM3b2m6UHOr6yqsUSrD+0jXPT48QN1VdBmh+AFRK+UcaYO383a0nvtv0c9uHt4yfceXLPGWrNjW+uTnS/lKpCdpE4GfLF1SFHIUcMxT+3At7hwDHNkLXllEXqbgDP8LyQSlYwT5jQUDCOzwc8CSxAryUOj6fN+iLKAiw4haPV/WZDG+JOmDMG2azo8SoBMi3y6Z2Le2fz2dMuvn5DUvCUvazrUmWYx4NEdSzc9GfBc6cXkduMqCs+lT2Ik2GHO0WjhrEB6j5NULOaCtbrislM85P6QutN4Pj9l18pcD6vZCcDTOwMj/BznclH342jeMn7rBgpW1YSzbNGP6KC4NeNW1H2xqNtuyhcJvasx4dwhzO18A36H6HtkiQyJNnfnVHh1oviO6mi3atmnh9B/55ugXM1Wf/6Kv8kJyaKtK8cWo+jCAR0/P/EsPtzToJM9Yk2+qxaPFd3k7T2KXvCQ9D1jLeECxL59L+WDvdBtxOEBD7W0a/Mn/9LuQPOiwARKJSTU+blJ6ezTeo83",
+			"poA1hF4zRh7HF0xVglYoLFqkUR7Pru/qYFnfMKBPuEOOGdgO3MMcAvIZ+w+Ug4THr/6+Vux0TN3wdOB+beObOboLgNE2zaD65lyMFbaulzrEnWjUgIg63CdpQJ2ESaimHGg/GmsipUCndRJ37TbUtn8W112SehsAgrsjiBcuJhw61i4bVfAZEcycq4Y/FlEDxtzoH8WzDoESNbl+r5agLcHGr37BFi81IXS8TLihC1T8b7d6tLb6lpXT+9IR4xAyZTw1IFMDZZEzVmHgYE/Et20/WhkX/oGghkWSpCxR0kynDplk+BEK2oyGKnl+rf4vymhsse2iQ/C99PhaodZjDfuGVSwPLoU0AYyAKaEwmgHPOFbDlrAmNk4iBp+IZYm9guZM2hcQ4GeA5WQyZzw4C1yMywWbdjtL9ZhpClmmPZ28nmwNORAat7tXPJoBBdXFB0gNT/wU7UYIKU5GnAiDIFJ0o8ijnuAMat3AsBki2vxwdypuBq5M6OF9DVA0HRUjOA0l4JHjK8Y282mz3U34PDPQvwCT342uD9cO3uXoSr3T2FnDmsVHz4Q9zYpSjioLmZk9ZTnQWgN5V5Oyat6m"
+		};
+
+		public override string Name
+		{
+			get { return "ParsingTest"; }
+		}
+
+		public override void PerformTest()
+		{
+			inputStreamTest();
+			parserTest();
+		}
+
+		private void parserTest()
+		{
+			foreach (string stream in streams)
+			{
+				Asn1StreamParser aIn = new Asn1StreamParser(Base64.Decode(stream));
+
+				try
+				{
+					Object obj;
+					while ((obj = aIn.ReadObject()) != null)
+					{
+					}
+
+					Fail("bad stream parsed successfully!");
+				}
+				catch (IOException)
+				{
+					// ignore
+				}
+				// Note: C# may throw these instead, since no InMemoryRepresentable support
+				catch (Asn1ParsingException)
+				{
+					// ignore
+				}
+			}
+		}
+
+		private void inputStreamTest()
+		{
+			foreach (string stream in streams)
+			{
+				Asn1InputStream aIn = new Asn1InputStream(Base64.Decode(stream));
+
+				try
+				{
+					Object obj;
+					while ((obj = aIn.ReadObject()) != null)
+					{
+					}
+
+					Fail("bad stream parsed successfully!");
+				}
+				catch (IOException)
+				{
+					// ignore
+				}
+				// Note: C# may throw these instead, since no InMemoryRepresentable support
+				catch (Asn1ParsingException)
+				{
+					// ignore
+				}
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ParsingTest());
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/PersonalDataUnitTest.cs b/crypto/test/src/asn1/test/PersonalDataUnitTest.cs
new file mode 100644
index 000000000..f92e619cf
--- /dev/null
+++ b/crypto/test/src/asn1/test/PersonalDataUnitTest.cs
@@ -0,0 +1,127 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509.SigI;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class PersonalDataUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "PersonalData"; }
+		}
+
+		public override void PerformTest()
+		{
+			NameOrPseudonym nameOrPseudonym = new NameOrPseudonym("pseudonym");
+			BigInteger nameDistinguisher = BigInteger.ValueOf(10);
+			DerGeneralizedTime dateOfBirth= new DerGeneralizedTime("20070315173729Z");
+			DirectoryString placeOfBirth = new DirectoryString("placeOfBirth");
+			string gender = "M";
+			DirectoryString postalAddress = new DirectoryString("address");
+
+			PersonalData data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress);
+
+			checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress);
+
+			data = new PersonalData(nameOrPseudonym, null, dateOfBirth, placeOfBirth, gender, postalAddress);
+
+			checkConstruction(data, nameOrPseudonym, null, dateOfBirth, placeOfBirth, gender, postalAddress);
+
+			data = new PersonalData(nameOrPseudonym, nameDistinguisher, null, placeOfBirth, gender, postalAddress);
+
+			checkConstruction(data, nameOrPseudonym, nameDistinguisher, null, placeOfBirth, gender, postalAddress);
+
+			data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, null, gender, postalAddress);
+
+			checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, null, gender, postalAddress);
+
+			data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, null, postalAddress);
+
+			checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, null, postalAddress);
+
+			data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, null);
+
+			checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, null);
+
+			data = PersonalData.GetInstance(null);
+
+			if (data != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				PersonalData.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			PersonalData		data,
+			NameOrPseudonym		nameOrPseudonym,
+			BigInteger			nameDistinguisher,
+			DerGeneralizedTime	dateOfBirth,
+			DirectoryString		placeOfBirth,
+			string				gender,
+			DirectoryString		postalAddress)
+		{
+			checkValues(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress);
+
+			data = PersonalData.GetInstance(data);
+
+			checkValues(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress);
+
+			Asn1InputStream aIn = new Asn1InputStream(data.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			data = PersonalData.GetInstance(seq);
+
+			checkValues(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress);
+		}
+
+		private void checkValues(
+			PersonalData		data,
+			NameOrPseudonym		nameOrPseudonym,
+			BigInteger			nameDistinguisher,
+			DerGeneralizedTime	dateOfBirth,
+			DirectoryString		placeOfBirth,
+			string				gender,
+			DirectoryString		postalAddress)
+		{
+			checkMandatoryField("nameOrPseudonym", nameOrPseudonym, data.NameOrPseudonym);
+			checkOptionalField("nameDistinguisher", nameDistinguisher, data.NameDistinguisher);
+			checkOptionalField("dateOfBirth", dateOfBirth, data.DateOfBirth);
+			checkOptionalField("placeOfBirth", placeOfBirth, data.PlaceOfBirth);
+			checkOptionalField("gender", gender, data.Gender);
+			checkOptionalField("postalAddress", postalAddress, data.PostalAddress);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PersonalDataUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/ProcurationSyntaxUnitTest.cs b/crypto/test/src/asn1/test/ProcurationSyntaxUnitTest.cs
new file mode 100644
index 000000000..97d0e3eee
--- /dev/null
+++ b/crypto/test/src/asn1/test/ProcurationSyntaxUnitTest.cs
@@ -0,0 +1,111 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class ProcurationSyntaxUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "ProcurationSyntax"; }
+		}
+
+		public override void PerformTest()
+		{
+			string country = "AU";
+			DirectoryString typeOfSubstitution = new DirectoryString("substitution");
+			GeneralName thirdPerson = new GeneralName(new X509Name("CN=thirdPerson"));
+			IssuerSerial certRef = new IssuerSerial(new GeneralNames(new GeneralName(new X509Name("CN=test"))), new DerInteger(1));
+
+			ProcurationSyntax procuration = new ProcurationSyntax(country, typeOfSubstitution, thirdPerson);
+
+			checkConstruction(procuration, country, typeOfSubstitution, thirdPerson, null);
+
+			procuration = new ProcurationSyntax(country, typeOfSubstitution, certRef);
+
+			checkConstruction(procuration, country, typeOfSubstitution, null, certRef);
+
+			procuration = new ProcurationSyntax(null, typeOfSubstitution, certRef);
+
+			checkConstruction(procuration, null, typeOfSubstitution, null, certRef);
+
+			procuration = new ProcurationSyntax(country, null, certRef);
+
+			checkConstruction(procuration, country, null, null, certRef);
+
+			procuration = ProcurationSyntax.GetInstance(null);
+
+			if (procuration != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				ProcurationSyntax.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			ProcurationSyntax	procuration,
+			string				country,
+			DirectoryString		typeOfSubstitution,
+			GeneralName			thirdPerson,
+			IssuerSerial		certRef)
+		{
+			checkValues(procuration, country, typeOfSubstitution, thirdPerson, certRef);
+
+			procuration = ProcurationSyntax.GetInstance(procuration);
+
+			checkValues(procuration, country, typeOfSubstitution, thirdPerson, certRef);
+
+			Asn1InputStream aIn = new Asn1InputStream(procuration.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			procuration = ProcurationSyntax.GetInstance(seq);
+
+			checkValues(procuration, country, typeOfSubstitution, thirdPerson, certRef);
+		}
+
+		private void checkValues(
+			ProcurationSyntax procuration,
+			string country,
+			DirectoryString  typeOfSubstitution,
+			GeneralName thirdPerson,
+			IssuerSerial certRef)
+		{
+			checkOptionalField("country", country, procuration.Country);
+			checkOptionalField("typeOfSubstitution", typeOfSubstitution, procuration.TypeOfSubstitution);
+			checkOptionalField("thirdPerson", thirdPerson, procuration.ThirdPerson);
+			checkOptionalField("certRef", certRef, procuration.CertRef);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ProcurationSyntaxUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/ProfessionInfoUnitTest.cs b/crypto/test/src/asn1/test/ProfessionInfoUnitTest.cs
new file mode 100644
index 000000000..6af2658ef
--- /dev/null
+++ b/crypto/test/src/asn1/test/ProfessionInfoUnitTest.cs
@@ -0,0 +1,121 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class ProfessionInfoUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "ProfessionInfo"; }
+		}
+
+		public override void PerformTest()
+		{
+			NamingAuthority auth =  new NamingAuthority(new DerObjectIdentifier("1.2.3"), "url", new DirectoryString("fred"));
+			DirectoryString[] professionItems = { new DirectoryString("substitution") };
+			DerObjectIdentifier[] professionOids = { new DerObjectIdentifier("1.2.3") };
+			string registrationNumber = "12345";
+			DerOctetString addProfInfo = new DerOctetString(new byte[20]);
+
+			ProfessionInfo info = new ProfessionInfo(auth, professionItems, professionOids, registrationNumber, addProfInfo);
+
+			checkConstruction(info, auth, professionItems, professionOids, registrationNumber, addProfInfo);
+
+			info = new ProfessionInfo(null, professionItems, professionOids, registrationNumber, addProfInfo);
+
+			checkConstruction(info, null, professionItems, professionOids, registrationNumber, addProfInfo);
+
+			info = new ProfessionInfo(auth, professionItems, null, registrationNumber, addProfInfo);
+
+			checkConstruction(info, auth, professionItems, null, registrationNumber, addProfInfo);
+
+			info = new ProfessionInfo(auth, professionItems, professionOids, null, addProfInfo);
+
+			checkConstruction(info, auth, professionItems, professionOids, null, addProfInfo);
+
+			info = new ProfessionInfo(auth, professionItems, professionOids, registrationNumber, null);
+
+			checkConstruction(info, auth, professionItems, professionOids, registrationNumber, null);
+
+			info = ProfessionInfo.GetInstance(null);
+
+			if (info != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				ProcurationSyntax.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			ProfessionInfo			profInfo,
+			NamingAuthority			auth,
+			DirectoryString[]		professionItems,
+			DerObjectIdentifier[]	professionOids,
+			string					registrationNumber,
+			DerOctetString			addProfInfo)
+		{
+			checkValues(profInfo, auth, professionItems, professionOids, registrationNumber, addProfInfo);
+
+			profInfo = ProfessionInfo.GetInstance(profInfo);
+
+			checkValues(profInfo, auth, professionItems, professionOids, registrationNumber, addProfInfo);
+
+			Asn1InputStream aIn = new Asn1InputStream(profInfo.ToAsn1Object().GetEncoded());
+
+			Asn1Sequence seq = (Asn1Sequence) aIn.ReadObject();
+
+			profInfo = ProfessionInfo.GetInstance(seq);
+
+			checkValues(profInfo, auth, professionItems, professionOids, registrationNumber, addProfInfo);
+		}
+
+		private void checkValues(
+			ProfessionInfo			profInfo,
+			NamingAuthority			auth,
+			DirectoryString[]		professionItems,
+			DerObjectIdentifier[]	professionOids,
+			string					registrationNumber,
+			DerOctetString			addProfInfo)
+		{
+			checkOptionalField("auth", auth, profInfo.NamingAuthority);
+			checkMandatoryField("professionItems", professionItems[0], profInfo.GetProfessionItems()[0]);
+			if (professionOids != null)
+			{
+				checkOptionalField("professionOids", professionOids[0], profInfo.GetProfessionOids()[0]);
+			}
+			checkOptionalField("registrationNumber", registrationNumber, profInfo.RegistrationNumber);
+			checkOptionalField("addProfessionInfo", addProfInfo, profInfo.AddProfessionInfo);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ProfessionInfoUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/QCStatementUnitTest.cs b/crypto/test/src/asn1/test/QCStatementUnitTest.cs
new file mode 100644
index 000000000..8d8ec9ec7
--- /dev/null
+++ b/crypto/test/src/asn1/test/QCStatementUnitTest.cs
@@ -0,0 +1,108 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class QCStatementUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "QCStatement"; }
+        }
+
+		public override void PerformTest()
+        {
+            QCStatement mv = new QCStatement(Rfc3739QCObjectIdentifiers.IdQcsPkixQCSyntaxV1);
+
+            CheckConstruction(mv, Rfc3739QCObjectIdentifiers.IdQcsPkixQCSyntaxV1, null);
+
+			Asn1Encodable info = new SemanticsInformation(new DerObjectIdentifier("1.2"));
+
+            mv = new QCStatement(Rfc3739QCObjectIdentifiers.IdQcsPkixQCSyntaxV1, info);
+
+            CheckConstruction(mv, Rfc3739QCObjectIdentifiers.IdQcsPkixQCSyntaxV1, info);
+
+            mv = QCStatement.GetInstance(null);
+
+			if (mv != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+			try
+            {
+                QCStatement.GetInstance(new object());
+
+				Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+		private void CheckConstruction(
+            QCStatement mv,
+            DerObjectIdentifier statementId,
+            Asn1Encodable statementInfo)
+        {
+            CheckStatement(mv, statementId, statementInfo);
+
+			mv = QCStatement.GetInstance(mv);
+
+			CheckStatement(mv, statementId, statementInfo);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				mv.ToAsn1Object().GetEncoded());
+
+			mv = QCStatement.GetInstance(seq);
+
+			CheckStatement(mv, statementId, statementInfo);
+        }
+
+		private void CheckStatement(
+            QCStatement         qcs,
+            DerObjectIdentifier statementId,
+            Asn1Encodable       statementInfo)
+        {
+            if (!qcs.StatementId.Equals(statementId))
+            {
+                Fail("statementIds don't match.");
+            }
+
+			if (statementInfo != null)
+            {
+                if (!qcs.StatementInfo.Equals(statementInfo))
+                {
+                    Fail("statementInfos don't match.");
+                }
+            }
+            else if (qcs.StatementInfo != null)
+            {
+                Fail("statementInfo found when none expected.");
+            }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            RunTest(new QCStatementUnitTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/ReasonFlagsTest.cs b/crypto/test/src/asn1/test/ReasonFlagsTest.cs
new file mode 100644
index 000000000..ef404b3e1
--- /dev/null
+++ b/crypto/test/src/asn1/test/ReasonFlagsTest.cs
@@ -0,0 +1,46 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class ReasonFlagsTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "ReasonFlags"; }
+		}
+
+		public override void PerformTest()
+		{
+			BitStringConstantTester.testFlagValueCorrect(0, ReasonFlags.Unused);
+			BitStringConstantTester.testFlagValueCorrect(1, ReasonFlags.KeyCompromise);
+			BitStringConstantTester.testFlagValueCorrect(2, ReasonFlags.CACompromise);
+			BitStringConstantTester.testFlagValueCorrect(3, ReasonFlags.AffiliationChanged);
+			BitStringConstantTester.testFlagValueCorrect(4, ReasonFlags.Superseded);
+			BitStringConstantTester.testFlagValueCorrect(5, ReasonFlags.CessationOfOperation);
+			BitStringConstantTester.testFlagValueCorrect(6, ReasonFlags.CertificateHold);
+			BitStringConstantTester.testFlagValueCorrect(7, ReasonFlags.PrivilegeWithdrawn);
+			BitStringConstantTester.testFlagValueCorrect(8, ReasonFlags.AACompromise);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ReasonFlagsTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/RegressionTest.cs b/crypto/test/src/asn1/test/RegressionTest.cs
new file mode 100644
index 000000000..873ab4396
--- /dev/null
+++ b/crypto/test/src/asn1/test/RegressionTest.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    public class RegressionTest
+    {
+        public static readonly ITest[] tests =
+        {
+			new AdditionalInformationSyntaxUnitTest(),
+			new AdmissionSyntaxUnitTest(),
+			new AdmissionsUnitTest(),
+			new AttributeTableUnitTest(),
+            new BiometricDataUnitTest(),
+            new BitStringTest(),
+			new CertHashUnitTest(),
+			new CertificateTest(),
+            new CmsTest(),
+            new CommitmentTypeIndicationUnitTest(),
+            new CommitmentTypeQualifierUnitTest(),
+			new ContentHintsUnitTest(),
+			new CscaMasterListTest(),
+			new DataGroupHashUnitTest(),
+			new DeclarationOfMajorityUnitTest(),
+			new DerApplicationSpecificTest(),
+			new DerUtf8StringTest(),
+			new EncryptedPrivateKeyInfoTest(),
+            new EqualsAndHashCodeTest(),
+			new EssCertIDv2UnitTest(),
+            new GeneralizedTimeTest(),
+			new GeneralNameTest(),
+			new GenerationTest(),
+			new InputStreamTest(),
+            new Iso4217CurrencyCodeUnitTest(),
+			new IssuingDistributionPointUnitTest(),
+			new KeyUsageTest(),
+            new LDSSecurityObjectUnitTest(),
+            new MiscTest(),
+			new MonetaryLimitUnitTest(),
+			new MonetaryValueUnitTest(),
+			new NameOrPseudonymUnitTest(),
+			new NamingAuthorityUnitTest(),
+			new NetscapeCertTypeTest(),
+            new OcspTest(),
+            new OidTest(),
+			new OtherCertIDUnitTest(),
+			new OtherSigningCertificateUnitTest(),
+			new ParsingTest(),
+			new PersonalDataUnitTest(),
+			new Pkcs10Test(),
+            new Pkcs12Test(),
+			new PkiFailureInfoTest(),
+			new ProcurationSyntaxUnitTest(),
+			new ProfessionInfoUnitTest(),
+			new QCStatementUnitTest(),
+			new ReasonFlagsTest(),
+			new RequestedCertificateUnitTest(),
+			new RestrictionUnitTest(),
+			new SemanticsInformationUnitTest(),
+            new SetTest(),
+            new SignerLocationUnitTest(),
+            new SmimeTest(),
+			new StringTest(),
+			new SubjectKeyIdentifierTest(),
+			new TagTest(),
+			new TargetInformationTest(),
+			new TypeOfBiometricDataUnitTest(),
+			new UtcTimeTest(),
+			new X509ExtensionsTest(),
+			new X509NameTest(),
+            new X9Test(),
+        };
+
+        public static void Main(
+            string[] args)
+        {
+            for (int i = 0; i != tests.Length; i++)
+            {
+                ITestResult  result = tests[i].Perform();
+                Console.WriteLine(result);
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/RequestedCertificateUnitTest.cs b/crypto/test/src/asn1/test/RequestedCertificateUnitTest.cs
new file mode 100644
index 000000000..767504173
--- /dev/null
+++ b/crypto/test/src/asn1/test/RequestedCertificateUnitTest.cs
@@ -0,0 +1,117 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class RequestedCertificateUnitTest
+		: Asn1UnitTest
+	{
+		private static readonly byte[] certBytes = Base64.Decode(
+			"MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+			+ "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+			+ "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+			+ "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+			+ "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+			+ "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+			+ "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+			+ "zl9HYIMxATFyqSiD9jsx");
+
+		public override string Name
+		{
+			get { return "RequestedCertificate"; }
+		}
+
+		public override void PerformTest()
+		{
+			RequestedCertificate.Choice type = RequestedCertificate.Choice.AttributeCertificate;
+			X509CertificateStructure cert = X509CertificateStructure.GetInstance(
+				Asn1Object.FromByteArray(certBytes));
+
+			byte[] certOctets = new byte[20];
+			RequestedCertificate requested = new RequestedCertificate(type, certOctets);
+
+			checkConstruction(requested, type, certOctets, null);
+
+			requested = new RequestedCertificate(cert);
+
+			checkConstruction(requested, RequestedCertificate.Choice.Certificate, null, cert);
+
+			requested = RequestedCertificate.GetInstance(null);
+
+			if (requested != null)
+			{
+				Fail("null GetInstance() failed.");
+			}
+
+			try
+			{
+				RequestedCertificate.GetInstance(new object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			RequestedCertificate		requested,
+			RequestedCertificate.Choice	type,
+			byte[]						certOctets,
+			X509CertificateStructure	cert)
+		{
+			checkValues(requested, type, certOctets, cert);
+
+			requested = RequestedCertificate.GetInstance(requested);
+
+			checkValues(requested, type, certOctets, cert);
+
+			Asn1InputStream aIn = new Asn1InputStream(requested.ToAsn1Object().GetEncoded());
+
+			object obj = aIn.ReadObject();
+
+			requested = RequestedCertificate.GetInstance(obj);
+
+			checkValues(requested, type, certOctets, cert);
+		}
+
+		private void checkValues(
+			RequestedCertificate		requested,
+			RequestedCertificate.Choice	type,
+			byte[]						certOctets,
+			X509CertificateStructure	cert)
+		{
+			checkMandatoryField("certType", (int) type, (int) requested.Type);
+
+			if (requested.Type == RequestedCertificate.Choice.Certificate)
+			{
+				checkMandatoryField("certificate", cert.GetEncoded(), requested.GetCertificateBytes());
+			}
+			else
+			{
+				checkMandatoryField("certificateOctets", certOctets, requested.GetCertificateBytes());
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new RequestedCertificateUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/RestrictionUnitTest.cs b/crypto/test/src/asn1/test/RestrictionUnitTest.cs
new file mode 100644
index 000000000..5dd6438cb
--- /dev/null
+++ b/crypto/test/src/asn1/test/RestrictionUnitTest.cs
@@ -0,0 +1,78 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.IsisMtt.X509;
+using Org.BouncyCastle.Asn1.X500;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class RestrictionUnitTest
+		: Asn1UnitTest
+	{
+		public override string Name
+		{
+			get { return "Restriction"; }
+		}
+
+		public override void PerformTest()
+		{
+			DirectoryString res = new DirectoryString("test");
+			Restriction restriction = new Restriction(res.GetString());
+
+			checkConstruction(restriction, res);
+
+			try
+			{
+				Restriction.GetInstance(new Object());
+
+				Fail("GetInstance() failed to detect bad object.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkConstruction(
+			Restriction		restriction,
+			DirectoryString	res)
+		{
+			checkValues(restriction, res);
+
+			restriction = Restriction.GetInstance(restriction);
+
+			checkValues(restriction, res);
+
+			Asn1InputStream aIn = new Asn1InputStream(restriction.ToAsn1Object().GetEncoded());
+
+			IAsn1String str = (IAsn1String) aIn.ReadObject();
+
+			restriction = Restriction.GetInstance(str);
+
+			checkValues(restriction, res);
+		}
+
+		private void checkValues(
+			Restriction		restriction,
+			DirectoryString	res)
+		{
+			checkMandatoryField("restriction", res, restriction.RestrictionString);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new RestrictionUnitTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/SMIMETest.cs b/crypto/test/src/asn1/test/SMIMETest.cs
new file mode 100644
index 000000000..adb90e093
--- /dev/null
+++ b/crypto/test/src/asn1/test/SMIMETest.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Smime;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class SmimeTest
+		: ITest
+	{
+		private static byte[] attrBytes = Base64.Decode("MDQGCSqGSIb3DQEJDzEnMCUwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMAcGBSsOAwIH");
+		private static byte[] prefBytes = Base64.Decode("MCwGCyqGSIb3DQEJEAILMR2hGwQIAAAAAAAAAAAYDzIwMDcwMzE1MTczNzI5Wg==");
+
+		public ITestResult Perform()
+		{
+			SmimeCapabilityVector caps = new SmimeCapabilityVector();
+
+			caps.AddCapability(SmimeCapability.DesEde3Cbc);
+			caps.AddCapability(SmimeCapability.RC2Cbc, 128);
+			caps.AddCapability(SmimeCapability.DesCbc);
+
+			SmimeCapabilitiesAttribute attr = new SmimeCapabilitiesAttribute(caps);
+
+			SmimeEncryptionKeyPreferenceAttribute pref = new SmimeEncryptionKeyPreferenceAttribute(
+				new RecipientKeyIdentifier(new DerOctetString(new byte[8]),
+				new DerGeneralizedTime("20070315173729Z"),
+				null));
+
+			try
+			{
+				if (!Arrays.AreEqual(attr.GetEncoded(), attrBytes))
+				{
+					return new SimpleTestResult(false, Name + ": Failed attr data check");
+				}
+
+				Asn1Object o = Asn1Object.FromByteArray(attrBytes);
+				if (!attr.Equals(o))
+				{
+					return new SimpleTestResult(false, Name + ": Failed equality test for attr");
+				}
+
+				if (!Arrays.AreEqual(pref.GetEncoded(), prefBytes))
+				{
+					return new SimpleTestResult(false, Name + ": Failed attr data check");
+				}
+
+				o = Asn1Object.FromByteArray(prefBytes);
+				if (!pref.Equals(o))
+				{
+					return new SimpleTestResult(false, Name + ": Failed equality test for pref");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": Failed - exception " + e.ToString(), e);
+			}
+		}
+
+		public string Name
+		{
+			get { return "SMIME"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new SmimeTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/SemanticsInformationUnitTest.cs b/crypto/test/src/asn1/test/SemanticsInformationUnitTest.cs
new file mode 100644
index 000000000..8f1f85f19
--- /dev/null
+++ b/crypto/test/src/asn1/test/SemanticsInformationUnitTest.cs
@@ -0,0 +1,138 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class SemanticsInformationUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "SemanticsInformation"; }
+        }
+
+		public override void PerformTest()
+        {
+            DerObjectIdentifier statementId = new DerObjectIdentifier("1.1");
+            SemanticsInformation mv = new SemanticsInformation(statementId);
+
+			CheckConstruction(mv, statementId, null);
+
+            GeneralName[] names = new GeneralName[2];
+
+            names[0] = new GeneralName(GeneralName.Rfc822Name, "test@test.org");
+            names[1] = new GeneralName(new X509Name("cn=test"));
+
+            mv = new SemanticsInformation(statementId, names);
+
+			CheckConstruction(mv, statementId, names);
+
+			mv = new SemanticsInformation(names);
+
+			CheckConstruction(mv, null, names);
+
+			mv = SemanticsInformation.GetInstance(null);
+
+			if (mv != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+			try
+            {
+                SemanticsInformation.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+			try
+            {
+                new SemanticsInformation(DerSequence.Empty);
+
+				Fail("constructor failed to detect empty sequence.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+		private void CheckConstruction(
+            SemanticsInformation	mv,
+            DerObjectIdentifier		semanticsIdentifier,
+            GeneralName[]			names)
+        {
+            CheckStatement(mv, semanticsIdentifier, names);
+
+			mv = SemanticsInformation.GetInstance(mv);
+
+			CheckStatement(mv, semanticsIdentifier, names);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(mv.ToAsn1Object().GetEncoded());
+
+			mv = SemanticsInformation.GetInstance(seq);
+
+			CheckStatement(mv, semanticsIdentifier, names);
+        }
+
+		private void CheckStatement(
+            SemanticsInformation si,
+            DerObjectIdentifier  id,
+            GeneralName[]        names)
+        {
+            if (id != null)
+            {
+                if (!si.SemanticsIdentifier.Equals(id))
+                {
+                    Fail("ids don't match.");
+                }
+            }
+            else if (si.SemanticsIdentifier != null)
+            {
+                Fail("statementId found when none expected.");
+            }
+
+            if (names != null)
+            {
+                GeneralName[] siNames = si.GetNameRegistrationAuthorities();
+
+                for (int i = 0; i != siNames.Length; i++)
+                {
+                    if (!names[i].Equals(siNames[i]))
+                    {
+                        Fail("name registration authorities don't match.");
+                    }
+                }
+            }
+            else if (si.GetNameRegistrationAuthorities() != null)
+            {
+                Fail("name registration authorities found when none expected.");
+            }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            RunTest(new SemanticsInformationUnitTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/SetTest.cs b/crypto/test/src/asn1/test/SetTest.cs
new file mode 100644
index 000000000..57c46603d
--- /dev/null
+++ b/crypto/test/src/asn1/test/SetTest.cs
@@ -0,0 +1,117 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	/// <remarks>Set sorting test example.</remarks>
+	[TestFixture]
+	public class SetTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "Set"; }
+		}
+
+		private void checkSortedSet(
+			int		attempt,
+			Asn1Set	s)
+		{
+			if (s[0] is DerBoolean
+				&& s[1] is DerInteger
+				&& s[2] is DerBitString
+				&& s[3] is DerOctetString)
+			{
+				return;
+			}
+
+			Fail("sorting failed on attempt: " + attempt);
+		}
+
+		public override void PerformTest()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+			byte[] data = new byte[10];
+
+			v.Add(new DerOctetString(data));
+			v.Add(new DerBitString(data));
+			v.Add(new DerInteger(100));
+			v.Add(DerBoolean.True);
+
+			checkSortedSet(0, new DerSet(v));
+
+			v = new Asn1EncodableVector();
+			v.Add(new DerInteger(100));
+			v.Add(DerBoolean.True);
+			v.Add(new DerOctetString(data));
+			v.Add(new DerBitString(data));
+
+			checkSortedSet(1, new DerSet(v));
+
+			v = new Asn1EncodableVector();
+			v.Add(DerBoolean.True);
+			v.Add(new DerOctetString(data));
+			v.Add(new DerBitString(data));
+			v.Add(new DerInteger(100));
+
+
+			checkSortedSet(2, new DerSet(v));
+
+			v = new Asn1EncodableVector();
+			v.Add(new DerBitString(data));
+			v.Add(new DerOctetString(data));
+			v.Add(new DerInteger(100));
+			v.Add(DerBoolean.True);
+
+			checkSortedSet(3, new DerSet(v));
+
+			v = new Asn1EncodableVector();
+			v.Add(new DerOctetString(data));
+			v.Add(new DerBitString(data));
+			v.Add(new DerInteger(100));
+			v.Add(DerBoolean.True);
+
+			Asn1Set s = new BerSet(v);
+
+			if (!(s[0] is DerOctetString))
+			{
+				Fail("BER set sort order changed.");
+			}
+
+			// create an implicitly tagged "set" without sorting
+			Asn1TaggedObject tag = new DerTaggedObject(false, 1, new DerSequence(v));
+			s = Asn1Set.GetInstance(tag, false);
+
+			if (s[0] is DerBoolean)
+			{
+				Fail("sorted when shouldn't be.");
+			}
+
+			// equality test
+			v = new Asn1EncodableVector();
+
+			v.Add(DerBoolean.True);
+			v.Add(DerBoolean.True);
+			v.Add(DerBoolean.True);
+
+			s = new DerSet(v);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SetTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+		    string resultText = Perform().ToString();
+
+		    Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/SignerLocationUnitTest.cs b/crypto/test/src/asn1/test/SignerLocationUnitTest.cs
new file mode 100644
index 000000000..bf20f1fda
--- /dev/null
+++ b/crypto/test/src/asn1/test/SignerLocationUnitTest.cs
@@ -0,0 +1,195 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Esf;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class SignerLocationUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "SignerLocation"; }
+        }
+
+		public override void PerformTest()
+        {
+            DerUtf8String countryName = new DerUtf8String("Australia");
+
+            SignerLocation sl = new SignerLocation(countryName, null, null);
+
+            CheckConstruction(sl, countryName, null, null);
+
+            DerUtf8String localityName = new DerUtf8String("Melbourne");
+
+            sl = new SignerLocation(null, localityName, null);
+
+			CheckConstruction(sl, null, localityName, null);
+
+			sl = new SignerLocation(countryName, localityName, null);
+
+			CheckConstruction(sl, countryName, localityName, null);
+
+			Asn1Sequence postalAddress = new DerSequence(
+				new DerUtf8String("line 1"),
+				new DerUtf8String("line 2"));
+
+            sl = new SignerLocation(null, null, postalAddress);
+
+            CheckConstruction(sl, null, null, postalAddress);
+
+            sl = new SignerLocation(countryName, null, postalAddress);
+
+            CheckConstruction(sl, countryName, null, postalAddress);
+
+            sl = new SignerLocation(countryName, localityName, postalAddress);
+
+            CheckConstruction(sl, countryName, localityName, postalAddress);
+
+            sl = SignerLocation.GetInstance(null);
+
+            if (sl != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+            try
+            {
+                SignerLocation.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            //
+            // out of range postal address
+            //
+			postalAddress = new DerSequence(
+				new DerUtf8String("line 1"),
+				new DerUtf8String("line 2"),
+				new DerUtf8String("line 3"),
+				new DerUtf8String("line 4"),
+				new DerUtf8String("line 5"),
+				new DerUtf8String("line 6"),
+				new DerUtf8String("line 7"));
+
+			try
+            {
+                new SignerLocation(null, null, postalAddress);
+
+                Fail("constructor failed to detect bad postalAddress.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                new SignerLocation(new DerSequence(new DerTaggedObject(2, postalAddress)));
+
+                Fail("sequence constructor failed to detect bad postalAddress.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                new SignerLocation(new DerSequence(new DerTaggedObject(5, postalAddress)));
+
+                Fail("sequence constructor failed to detect bad tag.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+		private void CheckConstruction(
+            SignerLocation sl,
+            DerUtf8String  countryName,
+            DerUtf8String  localityName,
+            Asn1Sequence   postalAddress)
+        {
+            CheckValues(sl, countryName, localityName, postalAddress);
+
+			sl = SignerLocation.GetInstance(sl);
+
+			CheckValues(sl, countryName, localityName, postalAddress);
+
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(
+				sl.ToAsn1Object().GetEncoded());
+
+			sl = SignerLocation.GetInstance(seq);
+
+			CheckValues(sl, countryName, localityName, postalAddress);
+        }
+
+		private void CheckValues(
+            SignerLocation sl,
+            DerUtf8String  countryName,
+            DerUtf8String  localityName,
+            Asn1Sequence   postalAddress)
+        {
+            if (countryName != null)
+            {
+                if (!countryName.Equals(sl.CountryName))
+                {
+                    Fail("countryNames don't match.");
+                }
+            }
+            else if (sl.CountryName != null)
+            {
+                Fail("countryName found when none expected.");
+            }
+
+            if (localityName != null)
+            {
+                if (!localityName.Equals(sl.LocalityName))
+                {
+                    Fail("localityNames don't match.");
+                }
+            }
+            else if (sl.LocalityName != null)
+            {
+                Fail("localityName found when none expected.");
+            }
+
+            if (postalAddress != null)
+            {
+                if (!postalAddress.Equals(sl.PostalAddress))
+                {
+                    Fail("postalAddresses don't match.");
+                }
+            }
+            else if (sl.PostalAddress != null)
+            {
+                Fail("postalAddress found when none expected.");
+            }
+        }
+
+		public static void Main(
+			string[] args)
+        {
+            RunTest(new SignerLocationUnitTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/StringTest.cs b/crypto/test/src/asn1/test/StringTest.cs
new file mode 100644
index 000000000..acfd380b2
--- /dev/null
+++ b/crypto/test/src/asn1/test/StringTest.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	/**
+	* X.690 test example
+	*/
+	[TestFixture]
+	public class StringTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "String"; }
+		}
+
+		public override void PerformTest()
+		{
+			DerBitString bs = new DerBitString(
+				new byte[] { (byte)0x01,(byte)0x23,(byte)0x45,(byte)0x67,(byte)0x89,(byte)0xab,(byte)0xcd,(byte)0xef });
+
+			if (!bs.GetString().Equals("#0309000123456789ABCDEF"))
+			{
+				Fail("DerBitString.GetString() result incorrect");
+			}
+
+			if (!bs.ToString().Equals("#0309000123456789ABCDEF"))
+			{
+				Fail("DerBitString.ToString() result incorrect");
+			}
+
+			bs = new DerBitString(
+				new byte[] { (byte)0xfe,(byte)0xdc,(byte)0xba,(byte)0x98,(byte)0x76,(byte)0x54,(byte)0x32,(byte)0x10 });
+
+			if (!bs.GetString().Equals("#030900FEDCBA9876543210"))
+			{
+				Fail("DerBitString.GetString() result incorrect");
+			}
+
+			if (!bs.ToString().Equals("#030900FEDCBA9876543210"))
+			{
+				Fail("DerBitString.ToString() result incorrect");
+			}
+
+			DerUniversalString us = new DerUniversalString(
+				new byte[] { (byte)0x01,(byte)0x23,(byte)0x45,(byte)0x67,(byte)0x89,(byte)0xab,(byte)0xcd,(byte)0xef });
+
+			if (!us.GetString().Equals("#1C080123456789ABCDEF"))
+			{
+				Fail("DerUniversalString.GetString() result incorrect");
+			}
+
+			if (!us.ToString().Equals("#1C080123456789ABCDEF"))
+			{
+				Fail("DerUniversalString.ToString() result incorrect");
+			}
+
+			us = new DerUniversalString(
+				new byte[] { (byte)0xfe,(byte)0xdc,(byte)0xba,(byte)0x98,(byte)0x76,(byte)0x54,(byte)0x32,(byte)0x10 });
+
+			if (!us.GetString().Equals("#1C08FEDCBA9876543210"))
+			{
+				Fail("DerUniversalString.GetString() result incorrect");
+			}
+
+			if (!us.ToString().Equals("#1C08FEDCBA9876543210"))
+			{
+				Fail("DerUniversalString.ToString() result incorrect");
+			}
+
+			byte[] t61Bytes = new byte[] { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8 };
+			string t61String = Encoding.GetEncoding("iso-8859-1").GetString(t61Bytes, 0, t61Bytes.Length);
+			DerT61String t61 = new DerT61String(t61Bytes);
+
+			if (!t61.GetString().Equals(t61String))
+			{
+				Fail("DerT61String.GetString() result incorrect");
+			}
+
+			if (!t61.ToString().Equals(t61String))
+			{
+				Fail("DerT61String.ToString() result incorrect");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new StringTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/SubjectKeyIdentifierTest.cs b/crypto/test/src/asn1/test/SubjectKeyIdentifierTest.cs
new file mode 100644
index 000000000..127c47a3a
--- /dev/null
+++ b/crypto/test/src/asn1/test/SubjectKeyIdentifierTest.cs
@@ -0,0 +1,61 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class SubjectKeyIdentifierTest
+		: SimpleTest
+	{
+		private static byte[] pubKeyInfo = Base64.Decode(
+			"MFgwCwYJKoZIhvcNAQEBA0kAMEYCQQC6wMMmHYMZszT/7bNFMn+gaZoiWJLVP8ODRuu1C2jeAe" +
+			"QpxM+5Oe7PaN2GNy3nBE4EOYkB5pMJWA0y9n04FX8NAgED");
+
+		private static byte[] shaID = Hex.Decode("d8128a06d6c2feb0865994a2936e7b75b836a021");
+		private static byte[] shaTruncID = Hex.Decode("436e7b75b836a021");
+
+		public override string Name
+		{
+			get { return "SubjectKeyIdentifier"; }
+		}
+
+		public override void PerformTest()
+		{
+			SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.GetInstance(
+				Asn1Object.FromByteArray(pubKeyInfo));
+			SubjectKeyIdentifier ski = SubjectKeyIdentifier.CreateSha1KeyIdentifier(pubInfo);
+
+			if (!Arrays.AreEqual(shaID, ski.GetKeyIdentifier()))
+			{
+				Fail("SHA-1 ID does not match");
+			}
+
+			ski = SubjectKeyIdentifier.CreateTruncatedSha1KeyIdentifier(pubInfo);
+
+			if (!Arrays.AreEqual(shaTruncID, ski.GetKeyIdentifier()))
+			{
+				Fail("truncated SHA-1 ID does not match");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SubjectKeyIdentifierTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/TagTest.cs b/crypto/test/src/asn1/test/TagTest.cs
new file mode 100644
index 000000000..c5fce6dbc
--- /dev/null
+++ b/crypto/test/src/asn1/test/TagTest.cs
@@ -0,0 +1,115 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	/**
+	* X.690 test example
+	*/
+	[TestFixture]
+	public class TagTest
+		: SimpleTest
+	{
+		private static readonly byte[] longTagged = Base64.Decode(
+			  "ZSRzIp8gEEZFRENCQTk4NzY1NDMyMTCfIQwyMDA2MDQwMTEyMzSUCCAFERVz"
+			+ "A4kCAHEXGBkalAggBRcYGRqUCCAFZS6QAkRFkQlURUNITklLRVKSBQECAwQF"
+			+ "kxAREhMUFRYXGBkalAggBREVcwOJAgBxFxgZGpQIIAUXGBkalAggBWUukAJE"
+			+ "RZEJVEVDSE5JS0VSkgUBAgMEBZMQERITFBUWFxgZGpQIIAURFXMDiQIAcRcY"
+			+ "GRqUCCAFFxgZGpQIIAVlLpACREWRCVRFQ0hOSUtFUpIFAQIDBAWTEBESExQV"
+			+ "FhcYGRqUCCAFERVzA4kCAHEXGBkalAggBRcYGRqUCCAFFxgZGpQIIAUXGBka"
+			+ "lAg=");
+
+		private static readonly byte[] longAppSpecificTag = Hex.Decode("5F610101");
+
+		public override string Name
+		{
+			get { return "Tag"; }
+		}
+
+		public override void PerformTest()
+		{
+			DerApplicationSpecific app = (DerApplicationSpecific)
+				Asn1Object.FromByteArray(longTagged);
+
+			app = (DerApplicationSpecific) Asn1Object.FromByteArray(app.GetContents());
+
+			Asn1InputStream aIn = new Asn1InputStream(app.GetContents());
+
+			Asn1TaggedObject tagged = (Asn1TaggedObject) aIn.ReadObject();
+
+			if (tagged.TagNo != 32)
+			{
+				Fail("unexpected tag value found - not 32");
+			}
+
+			tagged = (Asn1TaggedObject) Asn1Object.FromByteArray(tagged.GetEncoded());
+
+			if (tagged.TagNo != 32)
+			{
+				Fail("unexpected tag value found on recode - not 32");
+			}
+
+			tagged = (Asn1TaggedObject) aIn.ReadObject();
+
+			if (tagged.TagNo != 33)
+			{
+				Fail("unexpected tag value found - not 33");
+			}
+
+			tagged = (Asn1TaggedObject) Asn1Object.FromByteArray(tagged.GetEncoded());
+
+			if (tagged.TagNo != 33)
+			{
+				Fail("unexpected tag value found on recode - not 33");
+			}
+
+			aIn = new Asn1InputStream(longAppSpecificTag);
+
+			app = (DerApplicationSpecific)aIn.ReadObject();
+
+			if (app.ApplicationTag != 97)
+			{
+				Fail("incorrect tag number read");
+			}
+
+			app = (DerApplicationSpecific)Asn1Object.FromByteArray(app.GetEncoded());
+
+			if (app.ApplicationTag != 97)
+			{
+				Fail("incorrect tag number read on recode");
+			}
+
+			SecureRandom sr = new SecureRandom();
+			for (int i = 0; i < 100; ++i)
+			{
+				int testTag = (sr.NextInt() & int.MaxValue) >> sr.Next(26);
+				app = new DerApplicationSpecific(testTag, new byte[]{ 1 });
+				app = (DerApplicationSpecific)Asn1Object.FromByteArray(app.GetEncoded());
+
+				if (app.ApplicationTag != testTag)
+				{
+					Fail("incorrect tag number read on recode (random test value: " + testTag + ")");
+				}
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new TagTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/TargetInformationTest.cs b/crypto/test/src/asn1/test/TargetInformationTest.cs
new file mode 100644
index 000000000..7fa04cd01
--- /dev/null
+++ b/crypto/test/src/asn1/test/TargetInformationTest.cs
@@ -0,0 +1,58 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class TargetInformationTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "TargetInformation"; }
+		}
+
+		public override void PerformTest()
+		{
+			Target[] targets = new Target[2];
+			Target targetName = new Target(Target.Choice.Name, new GeneralName(GeneralName.DnsName, "www.test.com"));
+			Target targetGroup = new Target(Target.Choice.Group, new GeneralName(GeneralName.DirectoryName, "o=Test, ou=Test"));
+			targets[0] = targetName;
+			targets[1] = targetGroup;
+			Targets targetss = new Targets(targets);
+			TargetInformation targetInformation1 = new TargetInformation(targetss);
+			// use an Target array
+			TargetInformation targetInformation2 = new TargetInformation(targets);
+			// targetInformation1 and targetInformation2 must have same
+			// encoding.
+			if (!targetInformation1.Equals(targetInformation2))
+			{
+				Fail("targetInformation1 and targetInformation2 should have the same encoding.");
+			}
+			TargetInformation targetInformation3 = TargetInformation.GetInstance(targetInformation1.ToAsn1Object());
+			TargetInformation targetInformation4 = TargetInformation.GetInstance(targetInformation2.ToAsn1Object());
+			if (!targetInformation3.Equals(targetInformation4))
+			{
+				Fail("targetInformation3 and targetInformation4 should have the same encoding.");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new TargetInformationTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/TimeTest.cs b/crypto/test/src/asn1/test/TimeTest.cs
new file mode 100644
index 000000000..6f6bd6f2c
--- /dev/null
+++ b/crypto/test/src/asn1/test/TimeTest.cs
@@ -0,0 +1,28 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class TimeTest
+	{
+		[Test]
+		public void CheckCmsTimeVsX509Time()
+		{
+			DateTime now = DateTime.UtcNow;
+
+			// Time classes only have a resolution of seconds
+			now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
+
+			Org.BouncyCastle.Asn1.Cms.Time cmsTime = new Org.BouncyCastle.Asn1.Cms.Time(now);
+			Org.BouncyCastle.Asn1.X509.Time x509Time = new Org.BouncyCastle.Asn1.X509.Time(now);
+
+//			Assert.AreEqual(cmsTime.Date, x509Time.ToDateTime());
+			Assert.AreEqual(now, cmsTime.Date);
+			Assert.AreEqual(now, x509Time.ToDateTime());
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/TypeOfBiometricDataUnitTest.cs b/crypto/test/src/asn1/test/TypeOfBiometricDataUnitTest.cs
new file mode 100644
index 000000000..a59415c31
--- /dev/null
+++ b/crypto/test/src/asn1/test/TypeOfBiometricDataUnitTest.cs
@@ -0,0 +1,152 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509.Qualified;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class TypeOfBiometricDataUnitTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "TypeOfBiometricData"; }
+        }
+
+		public override void PerformTest()
+        {
+            //
+            // predefined
+            //
+            CheckPredefinedType(TypeOfBiometricData.Picture);
+
+            CheckPredefinedType(TypeOfBiometricData.HandwrittenSignature);
+
+			//
+            // non-predefined
+            //
+            DerObjectIdentifier localType = new DerObjectIdentifier("1.1");
+
+			TypeOfBiometricData type = new TypeOfBiometricData(localType);
+
+			CheckNonPredefined(type, localType);
+
+            type = TypeOfBiometricData.GetInstance(type);
+
+            CheckNonPredefined(type, localType);
+
+            Asn1Object obj = type.ToAsn1Object();
+
+            type = TypeOfBiometricData.GetInstance(obj);
+
+            CheckNonPredefined(type, localType);
+
+            type = TypeOfBiometricData.GetInstance(null);
+
+            if (type != null)
+            {
+                Fail("null GetInstance() failed.");
+            }
+
+            try
+            {
+                TypeOfBiometricData.GetInstance(new object());
+
+                Fail("GetInstance() failed to detect bad object.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                new TypeOfBiometricData(100);
+
+                Fail("constructor failed to detect bad predefined type.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+			// Call Equals to avoid unreachable code warning
+            if (!Equals(TypeOfBiometricData.Picture, 0))
+            {
+                Fail("predefined picture should be 0");
+            }
+
+			// Call Equals to avoid unreachable code warning
+			if (!Equals(TypeOfBiometricData.HandwrittenSignature, 1))
+			{
+                Fail("predefined handwritten signature should be 1");
+            }
+        }
+
+		private void CheckPredefinedType(
+            int predefinedType)
+        {
+            TypeOfBiometricData type = new TypeOfBiometricData(predefinedType);
+
+            CheckPredefined(type, predefinedType);
+
+            type = TypeOfBiometricData.GetInstance(type);
+
+			CheckPredefined(type, predefinedType);
+
+			Asn1Object obj = Asn1Object.FromByteArray(type.ToAsn1Object().GetEncoded());
+
+			type = TypeOfBiometricData.GetInstance(obj);
+
+			CheckPredefined(type, predefinedType);
+        }
+
+		private void CheckPredefined(
+            TypeOfBiometricData	type,
+            int					val)
+        {
+            if (!type.IsPredefined)
+            {
+                Fail("predefined type expected but not found.");
+            }
+
+			if (type.PredefinedBiometricType != val)
+            {
+                Fail("predefined type does not match.");
+            }
+        }
+
+		private void CheckNonPredefined(
+            TypeOfBiometricData type,
+            DerObjectIdentifier val)
+        {
+            if (type.IsPredefined)
+            {
+                Fail("predefined type found when not expected.");
+            }
+
+			if (!type.BiometricDataOid.Equals(val))
+            {
+                Fail("data oid does not match.");
+            }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            RunTest(new TypeOfBiometricDataUnitTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/UTCTimeTest.cs b/crypto/test/src/asn1/test/UTCTimeTest.cs
new file mode 100644
index 000000000..07abbc911
--- /dev/null
+++ b/crypto/test/src/asn1/test/UTCTimeTest.cs
@@ -0,0 +1,122 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	/**
+	* X.690 test example
+	*/
+	[TestFixture]
+	public class UtcTimeTest
+		: SimpleTest
+	{
+		private static readonly string[] input =
+		{
+			"020122122220Z",
+			"020122122220-1000",
+			"020122122220+1000",
+			"020122122220+00",
+			"0201221222Z",
+			"0201221222-1000",
+			"0201221222+1000",
+			"0201221222+00",
+			"550122122220Z",
+			"5501221222Z"
+		};
+
+		private static readonly string[] output =
+		{
+			"20020122122220GMT+00:00",
+			"20020122122220GMT-10:00",
+			"20020122122220GMT+10:00",
+			"20020122122220GMT+00:00",
+			"20020122122200GMT+00:00",
+			"20020122122200GMT-10:00",
+			"20020122122200GMT+10:00",
+			"20020122122200GMT+00:00",
+			"19550122122220GMT+00:00",
+			"19550122122200GMT+00:00"
+		};
+
+		private static readonly string[] zOutput1 =
+		{
+			"20020122122220Z",
+			"20020122222220Z",
+			"20020122022220Z",
+			"20020122122220Z",
+			"20020122122200Z",
+			"20020122222200Z",
+			"20020122022200Z",
+			"20020122122200Z",
+			"19550122122220Z",
+			"19550122122200Z"
+		};
+
+		private static readonly string[] zOutput2 =
+		{
+			"20020122122220Z",
+			"20020122222220Z",
+			"20020122022220Z",
+			"20020122122220Z",
+			"20020122122200Z",
+			"20020122222200Z",
+			"20020122022200Z",
+			"20020122122200Z",
+			"19550122122220Z",
+			"19550122122200Z"
+		};
+
+		public override string Name
+		{
+			get { return "UTCTime"; }
+		}
+
+		public override void PerformTest()
+		{
+//			SimpleDateFormat yyyyF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+//			SimpleDateFormat yyF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+
+//			yyyyF.setTimeZone(new SimpleTimeZone(0,"Z"));
+//			yyF.setTimeZone(new SimpleTimeZone(0,"Z"));
+
+			for (int i = 0; i != input.Length; i++)
+			{
+				DerUtcTime t = new DerUtcTime(input[i]);
+
+				if (!t.AdjustedTimeString.Equals(output[i]))
+				{
+					Fail("failed conversion test " + i);
+				}
+
+//				if (!yyyyF.format(t.getAdjustedDate()).Equals(zOutput1[i]))
+				if (!t.ToAdjustedDateTime().ToString(@"yyyyMMddHHmmss\Z").Equals(zOutput1[i]))
+				{
+					Fail("failed date conversion test " + i);
+				}
+
+//				if (!yyF.format(t.getDate()).Equals(zOutput2[i]))
+				if (!t.ToDateTime().ToString(@"yyyyMMddHHmmss\Z").Equals(zOutput2[i]))
+				{
+					Fail("failed date shortened conversion test " + i);
+				}
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new UtcTimeTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/X509ExtensionsTest.cs b/crypto/test/src/asn1/test/X509ExtensionsTest.cs
new file mode 100644
index 000000000..f1efd3a9b
--- /dev/null
+++ b/crypto/test/src/asn1/test/X509ExtensionsTest.cs
@@ -0,0 +1,117 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+	[TestFixture]
+	public class X509ExtensionsTest
+		: SimpleTest
+	{
+		private static readonly DerObjectIdentifier Oid1 = new DerObjectIdentifier("1.2.1");
+		private static readonly DerObjectIdentifier Oid2 = new DerObjectIdentifier("1.2.2");
+		private static readonly DerObjectIdentifier Oid3 = new DerObjectIdentifier("1.2.3");
+
+		public override string Name
+		{
+			get { return "X509Extensions"; }
+		}
+
+		public override void PerformTest()
+		{
+			X509ExtensionsGenerator gen = new X509ExtensionsGenerator();
+
+			gen.AddExtension(Oid1, true, new byte[20]);
+			gen.AddExtension(Oid2, true, new byte[20]);
+
+			X509Extensions ext1 = gen.Generate();
+			X509Extensions ext2 = gen.Generate();
+
+			if (!ext1.Equals(ext2))
+			{
+				Fail("Equals test failed");
+			}
+
+			gen.Reset();
+
+			gen.AddExtension(Oid2, true, new byte[20]);
+			gen.AddExtension(Oid1, true, new byte[20]);
+
+			ext2 = gen.Generate();
+
+			if (ext1.Equals(ext2))
+			{
+				Fail("inequality test failed");
+			}
+
+			if (!ext1.Equivalent(ext2))
+			{
+				Fail("equivalence true failed");
+			}
+
+			gen.Reset();
+
+			gen.AddExtension(Oid1, true, new byte[22]);
+			gen.AddExtension(Oid2, true, new byte[20]);
+
+			ext2 = gen.Generate();
+
+			if (ext1.Equals(ext2))
+			{
+				Fail("inequality 1 failed");
+			}
+
+			if (ext1.Equivalent(ext2))
+			{
+				Fail("non-equivalence 1 failed");
+			}
+
+			gen.Reset();
+
+			gen.AddExtension(Oid3, true, new byte[20]);
+			gen.AddExtension(Oid2, true, new byte[20]);
+
+			ext2 = gen.Generate();
+
+			if (ext1.Equals(ext2))
+			{
+				Fail("inequality 2 failed");
+			}
+
+			if (ext1.Equivalent(ext2))
+			{
+				Fail("non-equivalence 2 failed");
+			}
+
+			try
+			{
+				gen.AddExtension(Oid2, true, new byte[20]);
+				Fail("repeated oid");
+			}
+			catch (ArgumentException e)
+			{
+				if (!e.Message.Equals("extension 1.2.2 already added"))
+				{
+					Fail("wrong exception on repeated oid: " + e.Message);
+				}
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new X509ExtensionsTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/asn1/test/X509NameTest.cs b/crypto/test/src/asn1/test/X509NameTest.cs
new file mode 100644
index 000000000..9a564f72f
--- /dev/null
+++ b/crypto/test/src/asn1/test/X509NameTest.cs
@@ -0,0 +1,674 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class X509NameTest
+        : SimpleTest
+    {
+        private static readonly string[] subjects =
+        {
+            "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Webserver Team,CN=www2.connect4.com.au,E=webmaster@connect4.com.au",
+            "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Certificate Authority,CN=Connect 4 CA,E=webmaster@connect4.com.au",
+            "C=AU,ST=QLD,CN=SSLeay/rsa test cert",
+            "C=US,O=National Aeronautics and Space Administration,SERIALNUMBER=16+CN=Steve Schoch",
+            "E=cooke@issl.atl.hp.com,C=US,OU=Hewlett Packard Company (ISSL),CN=Paul A. Cooke",
+            "O=Sun Microsystems Inc,CN=store.sun.com",
+            "unstructuredAddress=192.168.1.33,unstructuredName=pixfirewall.ciscopix.com,CN=pixfirewall.ciscopix.com"
+        };
+
+        public override string Name
+        {
+            get { return "X509Name"; }
+        }
+
+        private static X509Name FromBytes(
+            byte[] bytes)
+        {
+            return X509Name.GetInstance(Asn1Object.FromByteArray(bytes));
+        }
+
+        private IAsn1Convertible createEntryValue(
+            DerObjectIdentifier	oid,
+            string				value)
+        {
+            IDictionary attrs = new Hashtable();
+            attrs.Add(oid, value);
+
+            IList ord = new ArrayList();
+            ord.Add(oid);
+
+            X509Name name = new X509Name(ord, attrs);
+
+            Asn1Sequence seq = (Asn1Sequence)name.ToAsn1Object();
+            Asn1Set set = (Asn1Set)seq[0];
+            seq = (Asn1Sequence)set[0];
+
+            return seq[1];
+        }
+
+        private IAsn1Convertible createEntryValueFromString(
+            DerObjectIdentifier	oid,
+            string				val)
+        {
+            IDictionary attrs = new Hashtable();
+            attrs.Add(oid, val);
+
+            IList ord = new ArrayList(attrs.Keys);
+
+            X509Name name = new X509Name(new X509Name(ord, attrs).ToString());
+
+            Asn1Sequence seq = (Asn1Sequence) name.ToAsn1Object();
+            Asn1Set asn1Set = (Asn1Set) seq[0];
+            seq = (Asn1Sequence) asn1Set[0];
+
+            return seq[1];
+        }
+
+        private void doTestEncodingPrintableString(
+            DerObjectIdentifier	oid,
+            string				value)
+        {
+            IAsn1Convertible converted = createEntryValue(oid, value);
+            if (!(converted is DerPrintableString))
+            {
+                Fail("encoding for " + oid + " not printable string");
+            }
+        }
+
+        private void doTestEncodingIA5String(
+            DerObjectIdentifier oid,
+            string				value)
+        {
+            IAsn1Convertible converted = createEntryValue(oid, value);
+            if (!(converted is DerIA5String))
+            {
+                Fail("encoding for " + oid + " not IA5String");
+            }
+        }
+
+        private void doTestEncodingGeneralizedTime(
+            DerObjectIdentifier	oid,
+            string				val)
+        {
+            IAsn1Convertible converted = createEntryValue(oid, val);
+            if (!(converted is DerGeneralizedTime))
+            {
+                Fail("encoding for " + oid + " not GeneralizedTime");
+            }
+            converted = createEntryValueFromString(oid, val);
+            if (!(converted is DerGeneralizedTime))
+            {
+                Fail("encoding for " + oid + " not GeneralizedTime");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            doTestEncodingPrintableString(X509Name.C, "AU");
+            doTestEncodingPrintableString(X509Name.SerialNumber, "123456");
+            doTestEncodingPrintableString(X509Name.DnQualifier, "123456");
+            doTestEncodingIA5String(X509Name.EmailAddress, "test@test.com");
+            doTestEncodingIA5String(X509Name.DC, "test");
+            // correct encoding
+            doTestEncodingGeneralizedTime(X509Name.DateOfBirth, "#180F32303032303132323132323232305A");
+            // compatability encoding
+            doTestEncodingGeneralizedTime(X509Name.DateOfBirth, "20020122122220Z");
+
+            //
+            // composite
+            //
+            IDictionary attrs = new Hashtable();
+            attrs.Add(X509Name.C, "AU");
+            attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+            attrs.Add(X509Name.L, "Melbourne");
+            attrs.Add(X509Name.ST, "Victoria");
+            attrs.Add(X509Name.E, "feedback-crypto@bouncycastle.org");
+
+            IList order = new ArrayList();
+            order.Add(X509Name.C);
+            order.Add(X509Name.O);
+            order.Add(X509Name.L);
+            order.Add(X509Name.ST);
+            order.Add(X509Name.E);
+
+            X509Name name1 = new X509Name(order, attrs);
+
+            if (!name1.Equivalent(name1))
+            {
+                Fail("Failed same object test");
+            }
+
+            if (!name1.Equivalent(name1, true))
+            {
+                Fail("Failed same object test - in Order");
+            }
+
+            X509Name name2 = new X509Name(order, attrs);
+
+            if (!name1.Equivalent(name2))
+            {
+                Fail("Failed same name test");
+            }
+
+            if (!name1.Equivalent(name2, true))
+            {
+                Fail("Failed same name test - in Order");
+            }
+
+            if (name1.GetHashCode() != name2.GetHashCode())
+            {
+                Fail("Failed same name test - in Order");
+            }
+
+            IList ord1 = new ArrayList();
+
+            ord1.Add(X509Name.C);
+            ord1.Add(X509Name.O);
+            ord1.Add(X509Name.L);
+            ord1.Add(X509Name.ST);
+            ord1.Add(X509Name.E);
+
+            IList ord2 = new ArrayList();
+
+            ord2.Add(X509Name.E);
+            ord2.Add(X509Name.ST);
+            ord2.Add(X509Name.L);
+            ord2.Add(X509Name.O);
+            ord2.Add(X509Name.C);
+
+            name1 = new X509Name(ord1, attrs);
+            name2 = new X509Name(ord2, attrs);
+
+            if (!name1.Equivalent(name2))
+            {
+                Fail("Failed reverse name test");
+            }
+
+            // FIXME Sort out X509Name hashcode problem
+//			if (name1.GetHashCode() != name2.GetHashCode())
+//			{
+//				Fail("Failed reverse name test GetHashCode");
+//			}
+
+            if (name1.Equivalent(name2, true))
+            {
+                Fail("Failed reverse name test - in Order");
+            }
+
+            if (!name1.Equivalent(name2, false))
+            {
+                Fail("Failed reverse name test - in Order false");
+            }
+
+            IList oids = name1.GetOidList();
+            if (!CompareVectors(oids, ord1))
+            {
+                Fail("oid comparison test");
+            }
+
+            IList val1 = new ArrayList();
+
+            val1.Add("AU");
+            val1.Add("The Legion of the Bouncy Castle");
+            val1.Add("Melbourne");
+            val1.Add("Victoria");
+            val1.Add("feedback-crypto@bouncycastle.org");
+
+            name1 = new X509Name(ord1, val1);
+
+            IList values = name1.GetValueList();
+            if (!CompareVectors(values, val1))
+            {
+                Fail("value comparison test");
+            }
+
+            ord2 = new ArrayList();
+
+            ord2.Add(X509Name.ST);
+            ord2.Add(X509Name.ST);
+            ord2.Add(X509Name.L);
+            ord2.Add(X509Name.O);
+            ord2.Add(X509Name.C);
+
+            name1 = new X509Name(ord1, attrs);
+            name2 = new X509Name(ord2, attrs);
+
+            if (name1.Equivalent(name2))
+            {
+                Fail("Failed different name test");
+            }
+
+            ord2 = new ArrayList();
+
+            ord2.Add(X509Name.ST);
+            ord2.Add(X509Name.L);
+            ord2.Add(X509Name.O);
+            ord2.Add(X509Name.C);
+
+            name1 = new X509Name(ord1, attrs);
+            name2 = new X509Name(ord2, attrs);
+
+            if (name1.Equivalent(name2))
+            {
+                Fail("Failed subset name test");
+            }
+
+
+            compositeTest();
+
+
+            //
+            // getValues test
+            //
+            IList v1 = name1.GetValueList(X509Name.O);
+
+            if (v1.Count != 1 || !v1[0].Equals("The Legion of the Bouncy Castle"))
+            {
+                Fail("O test failed");
+            }
+
+            IList v2 = name1.GetValueList(X509Name.L);
+
+            if (v2.Count != 1 || !v2[0].Equals("Melbourne"))
+            {
+                Fail("L test failed");
+            }
+
+            //
+            // general subjects test
+            //
+            for (int i = 0; i != subjects.Length; i++)
+            {
+                X509Name name = new X509Name(subjects[i]);
+                byte[] encodedName = name.GetEncoded();
+                name = X509Name.GetInstance(Asn1Object.FromByteArray(encodedName));
+
+                if (!name.ToString().Equals(subjects[i]))
+                {
+                    Fail("Failed regeneration test " + i);
+                }
+            }
+
+            //
+            // sort test
+            //
+            X509Name unsorted = new X509Name("SERIALNUMBER=BBB + CN=AA");
+
+            if (!FromBytes(unsorted.GetEncoded()).ToString().Equals("CN=AA+SERIALNUMBER=BBB"))
+            {
+                Fail("Failed sort test 1");
+            }
+
+            unsorted = new X509Name("CN=AA + SERIALNUMBER=BBB");
+
+            if (!FromBytes(unsorted.GetEncoded()).ToString().Equals("CN=AA+SERIALNUMBER=BBB"))
+            {
+                Fail("Failed sort test 2");
+            }
+
+            unsorted = new X509Name("SERIALNUMBER=B + CN=AA");
+
+            if (!FromBytes(unsorted.GetEncoded()).ToString().Equals("SERIALNUMBER=B+CN=AA"))
+            {
+                Fail("Failed sort test 3");
+            }
+
+            unsorted = new X509Name("CN=AA + SERIALNUMBER=B");
+
+            if (!FromBytes(unsorted.GetEncoded()).ToString().Equals("SERIALNUMBER=B+CN=AA"))
+            {
+                Fail("Failed sort test 4");
+            }
+
+            //
+            // equality tests
+            //
+            equalityTest(new X509Name("CN=The     Legion"), new X509Name("CN=The Legion"));
+            equalityTest(new X509Name("CN=   The Legion"), new X509Name("CN=The Legion"));
+            equalityTest(new X509Name("CN=The Legion   "), new X509Name("CN=The Legion"));
+            equalityTest(new X509Name("CN=  The     Legion "), new X509Name("CN=The Legion"));
+            equalityTest(new X509Name("CN=  the     legion "), new X509Name("CN=The Legion"));
+
+            // # test
+
+            X509Name n1 = new X509Name("SERIALNUMBER=8,O=ABC,CN=ABC Class 3 CA,C=LT");
+            X509Name n2 = new X509Name("2.5.4.5=8,O=ABC,CN=ABC Class 3 CA,C=LT");
+            X509Name n3 = new X509Name("2.5.4.5=#130138,O=ABC,CN=ABC Class 3 CA,C=LT");
+
+            equalityTest(n1, n2);
+            equalityTest(n2, n3);
+            equalityTest(n3, n1);
+
+            n1 = new X509Name(true, "2.5.4.5=#130138,CN=SSC Class 3 CA,O=UAB Skaitmeninio sertifikavimo centras,C=LT");
+            n2 = new X509Name(true, "SERIALNUMBER=#130138,CN=SSC Class 3 CA,O=UAB Skaitmeninio sertifikavimo centras,C=LT");
+            n3 = X509Name.GetInstance(Asn1Object.FromByteArray(Hex.Decode("3063310b3009060355040613024c54312f302d060355040a1326"
+                + "55414220536b6169746d656e696e696f20736572746966696b6176696d6f2063656e74726173311730150603550403130e53534320436c6173732033204341310a30080603550405130138")));
+
+            equalityTest(n1, n2);
+            equalityTest(n2, n3);
+            equalityTest(n3, n1);
+
+            n1 = new X509Name("SERIALNUMBER=8,O=XX,CN=ABC Class 3 CA,C=LT");
+            n2 = new X509Name("2.5.4.5=8,O=,CN=ABC Class 3 CA,C=LT");
+
+            if (n1.Equivalent(n2))
+            {
+                Fail("empty inequality check failed");
+            }
+
+            n1 = new X509Name("SERIALNUMBER=8,O=,CN=ABC Class 3 CA,C=LT");
+            n2 = new X509Name("2.5.4.5=8,O=,CN=ABC Class 3 CA,C=LT");
+
+            equalityTest(n1, n2);
+
+            //
+            // inequality to sequences
+            //
+            name1 = new X509Name("CN=The Legion");
+
+            if (name1.Equals(DerSequence.Empty))
+            {
+                Fail("inequality test with sequence");
+            }
+
+            if (name1.Equals(new DerSequence(DerSet.Empty)))
+            {
+                Fail("inequality test with sequence and set");
+            }
+
+            Asn1EncodableVector v = new Asn1EncodableVector(
+                new DerObjectIdentifier("1.1"),
+                new DerObjectIdentifier("1.1"));
+
+            if (name1.Equals(new DerSequence(new DerSet(new DerSet(v)))))
+            {
+                Fail("inequality test with sequence and bad set");
+            }
+
+//			if (name1.Equals(new DerSequence(new DerSet(new DerSet(v))), true))
+//			{
+//				Fail("inequality test with sequence and bad set");
+//			}
+            try
+            {
+                X509Name.GetInstance(new DerSequence(new DerSet(new DerSet(v))));
+                Fail("GetInstance should reject bad sequence");
+            }
+            catch (ArgumentException)
+            {
+                //expected
+            }
+
+            if (name1.Equals(new DerSequence(new DerSet(DerSequence.Empty))))
+            {
+                Fail("inequality test with sequence and short sequence");
+            }
+
+//			if (name1.Equals(new DerSequence(new DerSet(DerSequence.Empty)), true))
+//			{
+//				Fail("inequality test with sequence and short sequence");
+//			}
+            try
+            {
+                X509Name.GetInstance(new DerSequence(new DerSet(DerSequence.Empty)));
+                Fail("GetInstance should reject short sequence");
+            }
+            catch (ArgumentException)
+            {
+                //expected
+            }
+
+            v = new Asn1EncodableVector(
+                new DerObjectIdentifier("1.1"),
+                DerSequence.Empty);
+
+            if (name1.Equals(new DerSequence(new DerSet(new DerSequence(v)))))
+            {
+                Fail("inequality test with sequence and bad sequence");
+            }
+
+            if (name1.Equivalent(null))
+            {
+                Fail("inequality test with null");
+            }
+
+            if (name1.Equivalent(null, true))
+            {
+                Fail("inequality test with null");
+            }
+
+            //
+            // this is contrived but it checks sorting of sets with equal elements
+            //
+            unsorted = new X509Name("CN=AA + CN=AA + CN=AA");
+
+            //
+            // tagging test - only works if CHOICE implemented
+            //
+            /*
+            ASN1TaggedObject tag = new DERTaggedObject(false, 1, new X509Name("CN=AA"));
+
+            if (!tag.isExplicit())
+            {
+                Fail("failed to explicitly tag CHOICE object");
+            }
+
+            X509Name name = X509Name.getInstance(tag, false);
+
+            if (!name.equals(new X509Name("CN=AA")))
+            {
+                Fail("failed to recover tagged name");
+            }
+            */
+
+            DerUtf8String testString = new DerUtf8String("The Legion of the Bouncy Castle");
+            byte[] encodedBytes = testString.GetEncoded();
+            string hexEncodedString = "#" + Hex.ToHexString(encodedBytes);
+
+            DerUtf8String converted = (DerUtf8String)
+                new X509DefaultEntryConverter().GetConvertedValue(
+                X509Name.L , hexEncodedString);
+
+            if (!converted.Equals(testString))
+            {
+                Fail("Failed X509DefaultEntryConverter test");
+            }
+
+            //
+            // try escaped.
+            //
+            converted = (DerUtf8String) new X509DefaultEntryConverter().GetConvertedValue(
+                X509Name.L , "\\" + hexEncodedString);
+
+            if (!converted.Equals(new DerUtf8String(hexEncodedString)))
+            {
+                Fail("Failed X509DefaultEntryConverter test got " + converted + " expected: " + hexEncodedString);
+            }
+
+            //
+            // try a weird value
+            //
+            X509Name n = new X509Name("CN=\\#nothex#string");
+
+            if (!n.ToString().Equals("CN=\\#nothex#string"))
+            {
+                Fail("# string not properly escaped.");
+            }
+
+            IList vls = n.GetValueList(X509Name.CN);
+            if (vls.Count != 1 || !vls[0].Equals("#nothex#string"))
+            {
+                Fail("Escaped # not reduced properly");
+            }
+
+            n = new X509Name("CN=\"a+b\"");
+
+            vls = n.GetValueList(X509Name.CN);
+            if (vls.Count != 1 || !vls[0].Equals("a+b"))
+            {
+                Fail("Escaped + not reduced properly");
+            }
+
+            n = new X509Name("CN=a\\+b");
+
+            vls = n.GetValueList(X509Name.CN);
+            if (vls.Count != 1 || !vls[0].Equals("a+b"))
+            {
+                Fail("Escaped + not reduced properly");
+            }
+
+            if (!n.ToString().Equals("CN=a\\+b"))
+            {
+                Fail("+ in string not properly escaped.");
+            }
+
+            n = new X509Name("CN=a\\=b");
+
+            vls = n.GetValueList(X509Name.CN);
+            if (vls.Count != 1 || !vls[0].Equals("a=b"))
+            {
+                Fail("Escaped = not reduced properly");
+            }
+
+            if (!n.ToString().Equals("CN=a\\=b"))
+            {
+                Fail("= in string not properly escaped.");
+            }
+
+            n = new X509Name("TELEPHONENUMBER=\"+61999999999\"");
+
+            vls = n.GetValueList(X509Name.TelephoneNumber);
+            if (vls.Count != 1 || !vls[0].Equals("+61999999999"))
+            {
+                Fail("telephonenumber escaped + not reduced properly");
+            }
+
+            n = new X509Name("TELEPHONENUMBER=\\+61999999999");
+
+            vls = n.GetValueList(X509Name.TelephoneNumber);
+            if (vls.Count != 1 || !vls[0].Equals("+61999999999"))
+            {
+                Fail("telephonenumber escaped + not reduced properly");
+            }
+
+            n = new X509Name(@"TELEPHONENUMBER=\+61999999999");
+
+            vls = n.GetValueList(X509Name.TelephoneNumber);
+            if (vls.Count != 1 || !vls[0].Equals("+61999999999"))
+            {
+                Fail("telephonenumber escaped + not reduced properly");
+            }
+        }
+
+        private void compositeTest()
+        {
+            //
+            // composite test
+            //
+            byte[] enc = Hex.Decode("305e310b300906035504061302415531283026060355040a0c1f546865204c6567696f6e206f662074686520426f756e637920436173746c653125301006035504070c094d656c626f75726e653011060355040b0c0a4173636f742056616c65");
+            X509Name n = X509Name.GetInstance(Asn1Object.FromByteArray(enc));
+
+            if (!n.ToString().Equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale"))
+            {
+                Fail("Failed composite to string test got: " + n.ToString());
+            }
+
+            IDictionary symbols = X509Name.DefaultSymbols;
+            if (!n.ToString(true, symbols).Equals("L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU"))
+            {
+                Fail("Failed composite to string test got: " + n.ToString(true, symbols));
+            }
+
+            n = new X509Name(true, "L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU");
+            if (!n.ToString().Equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale"))
+            {
+                Fail("Failed composite to string reversal test got: " + n.ToString());
+            }
+
+            n = new X509Name("C=AU, O=The Legion of the Bouncy Castle, L=Melbourne + OU=Ascot Vale");
+
+            MemoryStream bOut = new MemoryStream();
+            Asn1OutputStream aOut = new Asn1OutputStream(bOut);
+
+            aOut.WriteObject(n);
+
+            byte[] enc2 = bOut.ToArray();
+
+            if (!Arrays.AreEqual(enc, enc2))
+            {
+                Fail("Failed composite string to encoding test");
+            }
+
+            //
+            // dud name test - handle empty DN without barfing.
+            //
+            n = new X509Name("C=CH,O=,OU=dummy,CN=mail@dummy.com");
+
+            n = X509Name.GetInstance(Asn1Object.FromByteArray(n.GetEncoded()));
+        }
+
+        private void equalityTest(
+            X509Name	x509Name,
+            X509Name	x509Name1)
+        {
+            if (!x509Name.Equivalent(x509Name1))
+            {
+                Fail("equality test failed for " + x509Name + " : " + x509Name1);
+            }
+
+            // FIXME Sort out X509Name hashcode problem
+//			if (x509Name.GetHashCode() != x509Name1.GetHashCode())
+//			{
+//				Fail("GetHashCode test failed for " + x509Name + " : " + x509Name1);
+//			}
+
+            if (!x509Name.Equivalent(x509Name1, true))
+            {
+                Fail("equality test failed for " + x509Name + " : " + x509Name1);
+            }
+        }
+
+        private bool CompareVectors(
+            IList	one,
+            IList	two)
+        {
+            if (one.Count != two.Count)
+                return false;
+
+            for (int i = 0; i < one.Count; ++i)
+            {
+                if (!one[i].Equals(two[i]))
+                    return false;
+            }
+
+            return true;
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new X509NameTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/asn1/test/X9Test.cs b/crypto/test/src/asn1/test/X9Test.cs
new file mode 100644
index 000000000..e310811ea
--- /dev/null
+++ b/crypto/test/src/asn1/test/X9Test.cs
@@ -0,0 +1,168 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Asn1.Tests
+{
+    [TestFixture]
+    public class X9Test
+        : SimpleTest
+    {
+        private static readonly byte[] namedPub = Base64.Decode("MDcwEwYHKoZIzj0CAQYIKoZIzj0DAQEDIAADG5xRI+Iki/JrvL20hoDUa7Cggzorv5B9yyqSMjYu");
+        private static readonly byte[] expPub = Base64.Decode(
+              "MIH8MIHXBgcqhkjOPQIBMIHLAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAA"
+            + "AAAH///////zBXBB5///////////////9///////+AAAAAAAB///////wEHiVXBfoqMGZUsfTL"
+            + "A9anUKMMJQEC1JiHF9m6FattPgMVAH1zdBaP/jRxtgqFdoahlHXTv6L/BB8DZ2iujhi7ks/PAF"
+            + "yUmqLG2UhT0OZgu/hUsclQX+laAh5///////////////9///+XXetBs6YFfDxDIUZSZVECAQED"
+            + "IAADG5xRI+Iki/JrvL20hoDUa7Cggzorv5B9yyqSMjYu");
+
+        private static readonly byte[] namedPriv = Base64.Decode("MCICAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEECDAGAgEBBAEK");
+        private static readonly byte[] expPriv = Base64.Decode(
+              "MIHnAgEAMIHXBgcqhkjOPQIBMIHLAgEBMCkGByqGSM49AQECHn///////////////3///////4"
+            + "AAAAAAAH///////zBXBB5///////////////9///////+AAAAAAAB///////wEHiVXBfoqMGZU"
+            + "sfTLA9anUKMMJQEC1JiHF9m6FattPgMVAH1zdBaP/jRxtgqFdoahlHXTv6L/BB8DZ2iujhi7ks"
+            + "/PAFyUmqLG2UhT0OZgu/hUsclQX+laAh5///////////////9///+XXetBs6YFfDxDIUZSZVEC"
+            + "AQEECDAGAgEBBAEU");
+
+        private void EncodePublicKey()
+        {
+            X9ECParameters ecP = X962NamedCurves.GetByOid(X9ObjectIdentifiers.Prime239v3);
+
+            if (X9IntegerConverter.GetByteLength(ecP.Curve) != 30)
+            {
+                Fail("wrong byte length reported for curve");
+            }
+
+            if (ecP.Curve.FieldSize != 239)
+            {
+                Fail("wrong field size reported for curve");
+            }
+
+            //
+            // named curve
+            //
+            X962Parameters _params = new X962Parameters(X9ObjectIdentifiers.Prime192v1);
+            ECPoint point = ecP.G.Multiply(BigInteger.ValueOf(100));
+
+            DerOctetString p = new DerOctetString(point.GetEncoded(true));
+
+            SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, _params), p.GetOctets());
+            if (!Arrays.AreEqual(info.GetEncoded(), namedPub))
+            {
+                Fail("failed public named generation");
+            }
+
+            X9ECPoint x9P = new X9ECPoint(ecP.Curve, p);
+
+            if (!Arrays.AreEqual(p.GetOctets(), x9P.Point.GetEncoded()))
+            {
+                Fail("point encoding not preserved");
+            }
+
+            Asn1Object o = Asn1Object.FromByteArray(namedPub);
+
+            if (!info.Equals(o))
+            {
+                Fail("failed public named equality");
+            }
+
+            //
+            // explicit curve parameters
+            //
+            _params = new X962Parameters(ecP);
+
+            info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, _params), p.GetOctets());
+
+            if (!Arrays.AreEqual(info.GetEncoded(), expPub))
+            {
+                Fail("failed public explicit generation");
+            }
+
+            o = Asn1Object.FromByteArray(expPub);
+
+            if (!info.Equals(o))
+            {
+                Fail("failed public explicit equality");
+            }
+        }
+
+        private void EncodePrivateKey()
+        {
+            X9ECParameters ecP = X962NamedCurves.GetByOid(X9ObjectIdentifiers.Prime239v3);
+
+            //
+            // named curve
+            //
+            X962Parameters _params = new X962Parameters(X9ObjectIdentifiers.Prime192v1);
+
+            PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, _params), new ECPrivateKeyStructure(BigInteger.Ten).ToAsn1Object());
+
+            if (!Arrays.AreEqual(info.GetEncoded(), namedPriv))
+            {
+                Fail("failed private named generation");
+            }
+
+            Asn1Object o = Asn1Object.FromByteArray(namedPriv);
+
+            if (!info.Equals(o))
+            {
+                Fail("failed private named equality");
+            }
+
+            //
+            // explicit curve parameters
+            //
+            _params = new X962Parameters(ecP);
+
+            info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, _params), new ECPrivateKeyStructure(BigInteger.ValueOf(20)).ToAsn1Object());
+
+            if (!Arrays.AreEqual(info.GetEncoded(), expPriv))
+            {
+                Fail("failed private explicit generation");
+            }
+
+            o = Asn1Object.FromByteArray(expPriv);
+
+            if (!info.Equals(o))
+            {
+                Fail("failed private explicit equality");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            EncodePublicKey();
+            EncodePrivateKey();
+        }
+
+        public override string Name
+        {
+            get { return "X9"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new X9Test());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/cms/test/AllTests.cs b/crypto/test/src/cms/test/AllTests.cs
new file mode 100644
index 000000000..1ce3b7c8d
--- /dev/null
+++ b/crypto/test/src/cms/test/AllTests.cs
@@ -0,0 +1,35 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+    public class AllTests
+    {
+        public static void Main(
+			string[] args)
+        {
+            //junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            suite().Run(el);
+        }
+
+		public static TestSuite suite()
+        {
+            TestSuite suite = new TestSuite("CMS Tests");
+
+			suite.Add(new CompressedDataTest());
+            suite.Add(new CompressedDataStreamTest());
+			suite.Add(new EnvelopedDataTest());
+			suite.Add(new EnvelopedDataStreamTest());
+			suite.Add(new Rfc4134Test());
+			suite.Add(new SignedDataTest());
+			suite.Add(new SignedDataStreamTest());
+
+			return suite;
+        }
+    }
+}
diff --git a/crypto/test/src/cms/test/AuthenticatedDataStreamTest.cs b/crypto/test/src/cms/test/AuthenticatedDataStreamTest.cs
new file mode 100644
index 000000000..89a2174b7
--- /dev/null
+++ b/crypto/test/src/cms/test/AuthenticatedDataStreamTest.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class AuthenticatedDataStreamTest
+	{
+		private const string SignDN = "O=Bouncy Castle, C=AU";
+
+		private static AsymmetricCipherKeyPair signKP;
+//		private static X509Certificate signCert;
+		//signCert = CmsTestUtil.MakeCertificate(_signKP, SignDN, _signKP, SignDN);
+
+//		private const string OrigDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+
+//		private static AsymmetricCipherKeyPair origKP;
+		//origKP = CmsTestUtil.MakeKeyPair();
+//		private static X509Certificate origCert;
+		//origCert = CmsTestUtil.MakeCertificate(_origKP, OrigDN, _signKP, SignDN);
+
+		private const string ReciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+
+		private static AsymmetricCipherKeyPair reciKP;
+		private static X509Certificate reciCert;
+
+		private static AsymmetricCipherKeyPair origECKP;
+		private static AsymmetricCipherKeyPair reciECKP;
+		private static X509Certificate reciECCert;
+
+		private static AsymmetricCipherKeyPair SignKP
+		{
+			get { return signKP == null ? (signKP = CmsTestUtil.MakeKeyPair()) : signKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciKP
+		{
+			get { return reciKP == null ? (reciKP = CmsTestUtil.MakeKeyPair()) : reciKP; }
+		}
+
+		private static X509Certificate ReciCert
+		{
+			get { return reciCert == null ? (reciCert = CmsTestUtil.MakeCertificate(ReciKP, ReciDN, SignKP, SignDN)) : reciCert; }
+		}
+
+		private static AsymmetricCipherKeyPair OrigECKP
+		{
+			get { return origECKP == null ? (origECKP = CmsTestUtil.MakeECDsaKeyPair()) : origECKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciECKP
+		{
+			get { return reciECKP == null ? (reciECKP = CmsTestUtil.MakeECDsaKeyPair()) : reciECKP; }
+		}
+
+		private static X509Certificate ReciECCert
+		{
+			get { return reciECCert == null ? (reciECCert = CmsTestUtil.MakeCertificate(ReciECKP, ReciDN, SignKP, SignDN)) : reciECCert; }
+		}
+
+		[Test]
+		public void TestKeyTransDESede()
+		{
+			tryKeyTrans(CmsAuthenticatedDataGenerator.DesEde3Cbc);
+		}
+
+		private void tryKeyTrans(
+			string macAlg)
+		{
+			byte[] data = Encoding.ASCII.GetBytes("Eric H. Echidna");
+
+			CmsAuthenticatedDataStreamGenerator adGen = new CmsAuthenticatedDataStreamGenerator();
+
+			adGen.AddKeyTransRecipient(ReciCert);
+
+			MemoryStream bOut = new MemoryStream();
+			Stream aOut = adGen.Open(bOut, macAlg);
+			aOut.Write(data, 0, data.Length);
+			aOut.Close();
+
+			CmsAuthenticatedDataParser ad = new CmsAuthenticatedDataParser(bOut.ToArray());
+
+			RecipientInformationStore recipients = ad.GetRecipientInfos();
+
+			Assert.AreEqual(ad.MacAlgOid, macAlg);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/cms/test/AuthenticatedDataTest.cs b/crypto/test/src/cms/test/AuthenticatedDataTest.cs
new file mode 100644
index 000000000..0ad34a95b
--- /dev/null
+++ b/crypto/test/src/cms/test/AuthenticatedDataTest.cs
@@ -0,0 +1,320 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class AuthenticatedDataTest
+	{
+		private const string SignDN = "O=Bouncy Castle, C=AU";
+
+		private static AsymmetricCipherKeyPair signKP;
+//		private static X509Certificate signCert;
+		//signCert = CmsTestUtil.MakeCertificate(_signKP, SignDN, _signKP, SignDN);
+
+//		private const string OrigDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+
+//		private static AsymmetricCipherKeyPair origKP;
+		//origKP = CmsTestUtil.MakeKeyPair();
+//		private static X509Certificate origCert;
+		//origCert = CmsTestUtil.MakeCertificate(_origKP, OrigDN, _signKP, SignDN);
+
+		private const string ReciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+
+		private static AsymmetricCipherKeyPair reciKP;
+		private static X509Certificate reciCert;
+
+		private static AsymmetricCipherKeyPair origECKP;
+		private static AsymmetricCipherKeyPair reciECKP;
+		private static X509Certificate reciECCert;
+
+		private static AsymmetricCipherKeyPair SignKP
+		{
+			get { return signKP == null ? (signKP = CmsTestUtil.MakeKeyPair()) : signKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciKP
+		{
+			get { return reciKP == null ? (reciKP = CmsTestUtil.MakeKeyPair()) : reciKP; }
+		}
+
+		private static X509Certificate ReciCert
+		{
+			get { return reciCert == null ? (reciCert = CmsTestUtil.MakeCertificate(ReciKP, ReciDN, SignKP, SignDN)) : reciCert; }
+		}
+
+		private static AsymmetricCipherKeyPair OrigECKP
+		{
+			get { return origECKP == null ? (origECKP = CmsTestUtil.MakeECDsaKeyPair()) : origECKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciECKP
+		{
+			get { return reciECKP == null ? (reciECKP = CmsTestUtil.MakeECDsaKeyPair()) : reciECKP; }
+		}
+
+		private static X509Certificate ReciECCert
+		{
+			get { return reciECCert == null ? (reciECCert = CmsTestUtil.MakeCertificate(ReciECKP, ReciDN, SignKP, SignDN)) : reciECCert; }
+		}
+		
+//		private static string          _signDN;
+//		private static KeyPair _signKP;
+//		private static X509Certificate _signCert;
+//	
+//		private static string          _origDN;
+//		private static KeyPair         _origKP;
+//		private static X509Certificate _origCert;
+//	
+//		private static string          _reciDN;
+//		private static KeyPair         _reciKP;
+//		private static X509Certificate _reciCert;
+//	
+//		private static KeyPair         _origEcKP;
+//		private static KeyPair         _reciEcKP;
+//		private static X509Certificate _reciEcCert;
+//	
+//		private static bool         _initialised = false;
+//	
+//		public bool DEBUG = true;
+//	
+//		private static void init()
+//		{
+//			if (!_initialised)
+//			{
+//			_initialised = true;
+//			
+//			_signDN   = "O=Bouncy Castle, C=AU";
+//			_signKP   = CmsTestUtil.makeKeyPair();
+//			_signCert = CmsTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN);
+//			
+//			_origDN   = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+//			_origKP   = CmsTestUtil.makeKeyPair();
+//			_origCert = CmsTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN);
+//			
+//			_reciDN   = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+//			_reciKP   = CmsTestUtil.makeKeyPair();
+//			_reciCert = CmsTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN);
+//			
+//			_origEcKP = CmsTestUtil.makeEcDsaKeyPair();
+//			_reciEcKP = CmsTestUtil.makeEcDsaKeyPair();
+//			_reciEcCert = CmsTestUtil.makeCertificate(_reciEcKP, _reciDN, _signKP, _signDN);
+//			}
+//		}
+//	
+//		public void setUp()
+//		{
+//			init();
+//		}
+//		
+//		public AuthenticatedDataTest(string name)
+//		{
+//		super(name);
+//		}
+//		
+//		public static void main(string args[])
+//		{
+//		junit.textui.TestRunner.run(AuthenticatedDataTest.class);
+//		}
+//		
+//		public static Test suite()
+//		throws Exception
+//		{
+//		init();
+//		
+//		return new CMSTestSetup(new TestSuite(AuthenticatedDataTest.class));
+//		}
+
+		[Test]
+		public void TestKeyTransDESede()
+		{
+			tryKeyTrans(CmsAuthenticatedDataGenerator.DesEde3Cbc);
+		}
+		
+		[Test]
+		public void TestKEKDESede()
+		{
+			tryKekAlgorithm(CmsTestUtil.MakeDesEde192Key(), new DerObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
+		}
+		
+		[Test]
+		public void TestPasswordAES256()
+		{
+			passwordTest(CmsAuthenticatedDataGenerator.Aes256Cbc);
+		}
+		
+		[Test]
+		public void TestECKeyAgree()
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsAuthenticatedDataGenerator adGen = new CmsAuthenticatedDataGenerator();
+
+			adGen.AddKeyAgreementRecipient(CmsAuthenticatedDataGenerator.ECDHSha1Kdf, OrigECKP.Private, OrigECKP.Public, ReciECCert, CmsAuthenticatedDataGenerator.Aes128Wrap);
+
+			CmsAuthenticatedData ad = adGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsAuthenticatedDataGenerator.DesEde3Cbc);
+
+			RecipientInformationStore recipients = ad.GetRecipientInfos();
+
+			Assert.AreEqual(CmsAuthenticatedDataGenerator.DesEde3Cbc, ad.MacAlgOid);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciECKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
+			}
+		}
+		
+		[Test]
+		public void TestEncoding()
+		{
+			byte[] data = Encoding.ASCII.GetBytes("Eric H. Echidna");
+
+			CmsAuthenticatedDataGenerator adGen = new CmsAuthenticatedDataGenerator();
+
+			adGen.AddKeyTransRecipient(ReciCert);
+
+			CmsAuthenticatedData ad = adGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsAuthenticatedDataGenerator.DesEde3Cbc);
+
+			ad = new CmsAuthenticatedData(ad.GetEncoded());
+
+			RecipientInformationStore recipients = ad.GetRecipientInfos();
+
+			Assert.AreEqual(CmsAuthenticatedDataGenerator.DesEde3Cbc, ad.MacAlgOid);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
+			}
+		}
+
+		private void tryKeyTrans(string macAlg)
+		{
+			byte[] data = Encoding.ASCII.GetBytes("Eric H. Echidna");
+
+			CmsAuthenticatedDataGenerator adGen = new CmsAuthenticatedDataGenerator();
+
+			adGen.AddKeyTransRecipient(ReciCert);
+
+			CmsAuthenticatedData ad = adGen.Generate(
+				new CmsProcessableByteArray(data),
+				macAlg);
+
+			RecipientInformationStore recipients = ad.GetRecipientInfos();
+
+			Assert.AreEqual(ad.MacAlgOid, macAlg);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
+			}
+		}
+		
+		private void tryKekAlgorithm(KeyParameter kek, DerObjectIdentifier algOid)
+		{
+			byte[] data = Encoding.ASCII.GetBytes("Eric H. Echidna");
+
+			CmsAuthenticatedDataGenerator adGen = new CmsAuthenticatedDataGenerator();
+
+			byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+			// FIXME Will this work for macs?
+			string keyAlgorithm = ParameterUtilities.GetCanonicalAlgorithmName(algOid.Id);
+
+			adGen.AddKekRecipient(keyAlgorithm, kek, kekId);
+
+			CmsAuthenticatedData ad = adGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsAuthenticatedDataGenerator.DesEde3Cbc);
+
+			RecipientInformationStore recipients = ad.GetRecipientInfos();
+
+			Assert.AreEqual(CmsAuthenticatedDataGenerator.DesEde3Cbc, ad.MacAlgOid);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, algOid.Id);
+
+				byte[] recData = recipient.GetContent(kek);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
+			}
+		}
+		
+		private void passwordTest(string algorithm)
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsAuthenticatedDataGenerator adGen = new CmsAuthenticatedDataGenerator();
+
+			adGen.AddPasswordRecipient(new Pkcs5Scheme2PbeKey("password".ToCharArray(), new byte[20], 5), algorithm);
+		
+			CmsAuthenticatedData ad = adGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsAuthenticatedDataGenerator.DesEde3Cbc);
+
+			RecipientInformationStore recipients = ad.GetRecipientInfos();
+
+			Assert.AreEqual(CmsAuthenticatedDataGenerator.DesEde3Cbc, ad.MacAlgOid);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (PasswordRecipientInformation recipient in c)
+			{
+				CmsPbeKey key = new Pkcs5Scheme2PbeKey("password".ToCharArray(), recipient.KeyDerivationAlgorithm);
+
+				byte[] recData = recipient.GetContent(key);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+				Assert.IsTrue(Arrays.AreEqual(ad.GetMac(), recipient.GetMac()));
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/CMSSampleMessages.cs b/crypto/test/src/cms/test/CMSSampleMessages.cs
new file mode 100644
index 000000000..ae4f60fd1
--- /dev/null
+++ b/crypto/test/src/cms/test/CMSSampleMessages.cs
@@ -0,0 +1,147 @@
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	internal class CmsSampleMessages
+	{
+		internal static readonly byte[] originatorMessage = Base64.Decode(
+			  "MIIYGgYJKoZIhvcNAQcDoIIYCzCCGAcCAQKgggRJoIIERTCCBEEwggIpAgkA"
+			+ "xS/+IvjTL8YwDQYJKoZIhvcNAQEFBQAwaTELMAkGA1UEBhMCVVMxGDAWBgNV"
+			+ "BAoTD1UuUy4gR292ZXJubWVudDESMBAGA1UECxMJSFNQRDEyTGFiMQ8wDQYD"
+			+ "VQQLEwZBZ2VudHMxGzAZBgNVBAMTEkhTUEQxMiBMYWIgQ0EgUm9vdDAeFw0w"
+			+ "NzA1MTQxNzEzMzRaFw0wODA1MTMxNzEzMzRaMFwxCzAJBgNVBAYTAlVTMRgw"
+			+ "FgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxEjAQBgNVBAsTCUhTUEQxMkxhYjEP"
+			+ "MA0GA1UECxMGQWdlbnRzMQ4wDAYDVQQDEwV1c2VyMTCCASIwDQYJKoZIhvcN"
+			+ "AQEBBQADggEPADCCAQoCggEBALC54HvfpSE3yq/EkpNCkUEV6a6Df3q4k8EM"
+			+ "dlg0nQSf2FgYh1GMiztw8SVjrF80l4+Hg5/FW2XN2kpVQBap/H5ziPYXenbi"
+			+ "VLJHCF9LVyYDOS7xGfRtQ+ZhFUcECtaCLJsR7HIiFyKZWGg0c3bFZvFkdZqT"
+			+ "8MMwjhcIVE1BptMqcGriqqMQAUKYmOguAOzMCTGAOxqBXYFmR68WtggVNMMc"
+			+ "5qU6S/4OxeCmaNSPG5p7pA1o4Cnv4aJF1mAPedVPQpAS4Lu2K9nNhRkug0yd"
+			+ "6nPaxgQudk5YxlreNOPKiAHApk9RhGVepGchJCFP2aIPu9tkIiSe3omezSZu"
+			+ "Sy/3F5UCAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAGDxqVI4aR4XNfbk2MtXF"
+			+ "agNYZOswn85X84um9gG323qjYhroW0QDuy3CwtUwhH866mpnJyhJvKx3b8UE"
+			+ "7pZInoNEz1UVn+wgJVXMmaG5mfp3X6z0xDAEaKmDMJXl66wlFGG1iveGgcEi"
+			+ "oMkrxFJKvu/FXywzPvz2pXD9LQapogOQpVsvg/hed//wijDG94UBkhbHTZ53"
+			+ "6ODKuHGmooO6bgqJxKcVyLwQAq/lXGtLqODK9BDicfUzuhLWA0si7Y1daehj"
+			+ "fjgAqFGirqRtPDdk1jywoMJdDCQqocNqNGuu/+9ZoRNtY7XFbiN7h4s4KTkw"
+			+ "YqCph8g+RZYJVZJDw/+qc5ymYZiufbImA08D7x7IzqX9eeuAqKCebkxcK0Dz"
+			+ "eh/wT7Ff8csw0xqkkEbi5sTORogPexKGo9T1P4j/UbOyCHaIwFQVE67kYJqZ"
+			+ "U3BB7mGNE/dKru7jC7Aadorpj7P/EQ8sfoq5wC9r3wfFB1f5znN9ZfXd3zSU"
+			+ "Gxne2PGl3Ry4DhrhWGy/HqB+StPSkLPJL1RNtKkywtaJG1QBnrMnLNsV7T0R"
+			+ "mIDn69NkDkc59LAuB7yxwBmhYA7c7cHckdX3bE7zgN6yYdiyLyXr+ZQl+3J8"
+			+ "bBPN/IVSs5Wr1kK9RDrFX8MdP95LZxHlgMATwAqoEPe5r2tvvGBoajoIA2Tw"
+			+ "71QxggGSMIIBjgIBADB2MGkxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu"
+			+ "IEdvdmVybm1lbnQxEjAQBgNVBAsTCUhTUEQxMkxhYjEPMA0GA1UECxMGQWdl"
+			+ "bnRzMRswGQYDVQQDExJIU1BEMTIgTGFiIENBIFJvb3QCCQDFL/4i+NMvyTAN"
+			+ "BgkqhkiG9w0BAQEFAASCAQCGpoi8DBLf6I2fwqVp9MPA5M0QNRnC34AMoc7N"
+			+ "/JGKM5dWcGNpN83yL9QmOfjgyxzwJ3L3e3hYdoXp9MNelzG5ssyyKw4NxRgM"
+			+ "C1aRPWx1R1aKee/NAgvBjN3FyDN3Pl4ACz2EMrDMmilR0zmSJkDBVbGjxNzs"
+			+ "ZPxtsBlHeLRky/K/ZrTy5jIheFcKt/0dNJiMsFh+677OlRhDihdLzYeV4RK1"
+			+ "5Iy1j18ls5rJMYh1fmZOx9T6wvlpw84IjFHzUcIxIBg8t1cUkncXbg1r+rxm"
+			+ "zIaalAKdYp58oMpjy9wV6E1mxgAM/lvE/jwiYP4/a6TsXTLDPNIxe9RZVdhA"
+			+ "GCPvMIISHQYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgQBLQIaeQQMYCCEfgv"
+			+ "FBzVKLnlRNCjs2JE/G8jBI8aduv6YQTYTt0ePh9JEHTmSi7ISbCDdAf5baKN"
+			+ "mzVGQJj87Srz3YyEmUcozxscWnWgVWpUbx0GJkjz6LqyGLQ3VnqUDG80xnXo"
+			+ "nQY5q4ko6avyMIDZ+zzI2fs9ChAlBjZ41Qb0FnwDPZBH3N43q+puVWesE4wj"
+			+ "LGftt63T4k2D/qMdg7fVfHkAsXPJIxkvR4vUrGEvxTl9e24146wYgCXe+66T"
+			+ "UcAMViNCMr8UiFQFQYSmuPcSTHgQHqEaBwYys6X+fe61yE16mUazs32yVH2v"
+			+ "Cyf1mG4/GAaSmqR/BIU7y7trGd+g/KaT1Kp76e+Rys9G/oakoeIH3Hkgdhmc"
+			+ "pFBPklIlgA57EocK5n84tFRv9n9cmsbOfy0EjEa6vU4ImMPZQS4iyhLCWD1u"
+			+ "tQziu5FyHSb9COveUPuGY2iTrOWG34rHIagNndXi1OuAIGQrLjbntHmogqxb"
+			+ "zkB+yojr+WBwY1efb8X+WQ2L+us9v31qNGA0wyfg4AC5FZur90rBxBq59UPz"
+			+ "JAVRD6NP5FRPdxuvHclDoGBoiMr9NXO3Uv0tJuYADHlWMQnUGoPEL7UxzuPJ"
+			+ "VAWuHpGiywzOcWMiFEiDSIZrv4RViIVIRhEtm2bO7Ta/AGTfvJcyb6ySexc1"
+			+ "aR5TWYOjqv1NaGAVQ1vPyqazH+g17y5wnBRj2c3nSMwksn/nC60e4ax+/yaE"
+			+ "Ls9Qou9a0L2IyQgDlvhBA4CcRGcHklhlzAovGBX2gWG31CK05doZhH7bRIrj"
+			+ "8h1XOF2izffrfWb6LcDcZptw5BQWT5XeyoKD4eNZfJ4ww+dMw4+0MkXPZEn6"
+			+ "Fqg+jam9ZioqXiw5Y6bdzxawefe6gvxeca3f53KDXEm4qFaVuDgyjNZhEmyB"
+			+ "gmsWRKokQ5DDlj1PfVlO4g2Uee4zbvmr7Yx6tGnnxm6o5i/COwvvRSXp8Oj7"
+			+ "Zej0ZA+1zenNRAGXwuTKrbQ9ZZYRi4LCXluuVmy8vocGm8bnuqulMyz5hsUi"
+			+ "QMAl1knunhaT+/kQOLRwEdJUgfq8ME14XsTNiVq26W8n+9AsYHoFzJhFoCfe"
+			+ "i2wngAs1MMnw1erfnhWibkFZDlG9/5OPBZ3ZzJfgMEdT5Fs+hJxrw7UqNMkb"
+			+ "EoH+3HpzEXfcGqCL6RfdbS0hu85v1CrZv0veK8qI+rQnoqXp+xmBRiSCyWNR"
+			+ "ITepXcJsi6vWYX0nvNNbBjTsFqi78BSVRpg/zOFRvw1gX1TtTXQLcEdalKgf"
+			+ "tEo+An3f3GugB3CFw38IM4JwCB06vXTRQAoK4PM4uNYVXEgSPq4vg9UuHZ3n"
+			+ "V5l96emGLK55N5FO6FvlHFft/7elEFglbnSzSQnzVyj36Z6P7x/Q3td5SY4J"
+			+ "VAJWvR/X4Fe2G6ebIZdNSJef9UyuNPee0Fi1iJUL8L4qO61ijkjYdE3bBcGm"
+			+ "61eWj8NgxtELVgRyXq1vNgMOFlVAwkf2ZNDgNRUM49UnIFTNKnTaeAVB9pW2"
+			+ "DGrZER8LA8ABctAdElECceoMVRUG1uFdAicrEbBHcWJkTdjBPjumE4bE6HUm"
+			+ "vbpNBC4wyoPS6CSvNut/re7I4wgZwho6C6GRUuwraxJZlS+jwEvC+F4Bzlf5"
+			+ "aPygECgVaNmSGP1E/vyN2aF8CLo4NL/5o9GG8DWg9O5GdNSislr4r6ciEjCr"
+			+ "0a6rk47QDn4rDQy8iu/YkZz9u8/GJCAinWQzAvV8byhZxc81CfKj9xYTclDX"
+			+ "AB75blJvUQIP4U7gpWxLB/1sdN2V5f9jw+xTLSpoJ7r/tIeBygF6rFe402Sd"
+			+ "840SLi8ZSufAVeHUoNNDYkA/c1b6k5FaxDtN22tYQi4y3Hs7k03mGhvvLC0l"
+			+ "05fMmvtasFaW5Bupqw8E2a7wHSLmRAXrPvnrblSL/wajptKPJWDJ+oH/9d9k"
+			+ "NkC4EFBpcMEfIDky4PoCtfKQBFa5LT1WDQGfcCnrC9SDfUfhfRLBOpoFmUaT"
+			+ "O0xc0vI/jmDRsoBy9d42ebyGMg5uD6tTOIvszEirpMy5SYPPa64zhHcN+Pzs"
+			+ "db+J6fthc3aVIoob9jdv/aRUH3gDwltSnaLUIc7CWcuHSCGyM/zQPiAzkw0z"
+			+ "x6ii5fdKXsmnQn88E+YqiJTPH0fG+kkhokAGU76bQMn7fJyBeVHhF2hqSr/0"
+			+ "4zCIjgq1Zb+d9sEuRZWF+/XsGl2gwk4vgHTwM+XfU7edQssUR6kyD6wkw7EU"
+			+ "6HaRrflymAHTEvdAB+PaREQbyej7/2lY41qmA9df2I5Izb60NxmMFj9F4M4V"
+			+ "bLJOVNX5fuc8vaIhPG82hIiqe05cnBfRhtmcUUb1WDHVH3klRkti+fHrnbAW"
+			+ "TpWd5m6Wi3VssopaUozWgYVgW9M+Zr5ZUAN9H0Kb4CatxG5YFkD0MCZShGl/"
+			+ "lSc1SUxho6YakBB+5HxCI853/sQ3RMgSrMk+8ftalM2+BrT+V9wMK2O+wM5W"
+			+ "ujrAcM85sQ4OqSZfJ7MmKT8+pcIsRRocmlM/cxUf5hKXfXrmCR5mkf9jxF8B"
+			+ "J1JOwhkD8zQP7sPUcOWEcT8ctOKPygtz6tWWQDW8ciiYULYyJA6ydGrrn6T+"
+			+ "fQj8M2VsM1y4YK9dMfJUeaiP+m4BeoOjs0vqz6pBI6J3lrNz31DaNO6SApUL"
+			+ "4cOx8EZMg498TG0zmQ87yVw4mGmL3JpWBZH89HiNEY5eJ0zEIS3lMaOADRMf"
+			+ "kX8B5YHadeTuAEjXsGtFIlSf1xo45kwCxIfUcikdfu2rb+Bh251Im0oq/XTj"
+			+ "XPeviXasfas6VsMHsmTrqynFdP8THnrmHLCoeAMvgpjirXfIdR7tULJcFJtr"
+			+ "0lZLZfdZgbTsbn9GMQKwMkAAjJLfJq42usvzf4ShC7IRtvOEVAMrebaaK1YF"
+			+ "rtV5z1WNo3VRFonakKj85nXLOAdCNe6T3zESebexJKFn8e/6+shp9IDIRmWr"
+			+ "hiWut6KPFiSgAgfqpeIt9fuHiYeIK8DqISA7QUdAZrgPe8GlctvKkQLvjNW0"
+			+ "srglx9CQuDqZC6C1BLaIs3sE//yLvEd06vDFjDa0WGKWjM/Uo29af/tlL1kC"
+			+ "vDQtDPi8OPIebK8OwI2uNDZ+cnHhv3gZXCdbKkRZc1W+mrU7rUk1Fa0ViVmc"
+			+ "zhVGX22fDXbIrs9zJ+sA+3Towrx2XmMZ+PDkVBxHFE2bk+GABM62BW9YZoX4"
+			+ "R4U+n7E8Ec0sI8srcxEZYX8LWHh1XSU0yEHYjkIWDQUUSGpsbgqnjXJcnTdk"
+			+ "KK5PLk4sthLYwT4o1Gg4lRpc4dn26bIQcpGdY5PEknItDt6IBSc6bYYYoQrl"
+			+ "PIufY67haoc//d5y1LpCi5vc0wTcvbdoVepLrxVAn4MPsejbfIFJ01N0qKgv"
+			+ "fGWVxmRGtGXHe3iNLsMrvSE2FkORSc4sgjC42hfxHTEVmhTnzOplxTsN/MzE"
+			+ "S7ESv/c0rIen+zwXgtiFnTg1VPHcaT4z0DtLBMNjqYNoyDrIHUrWguFeV7/i"
+			+ "RSP7SiztMmlfKhrxlQpaNNm/XvKa1OpKbVStHMgOdpMaaCp8WaX++wb9lG6V"
+			+ "3PqBeVSCuFm1xq6KAERLUdF4XsdXNM/uUhYZX7cGIqRS3vSDJB1EfrZTpUY5"
+			+ "xGllybE/P2gufnG5EMpC2FHx4iW4pWMkYhIpzKv1Tkxe3K6ISs4wEs4n/AtL"
+			+ "hupMGZE9hDJ0LV0nRvRbY8YCRXoBaj6/qF1QED7CG4hx16yrkLAR7Th5rbH7"
+			+ "GFEzNSq1HI0IssDIimD2ZN9Cf++uH6ZpP2JZeJ/gEqGi17ovtnuklx6dtu0l"
+			+ "KL0pQjCyAoQFEFSaVJ1m4oOQJyb58lsG4gOPaPvOw1ruiJ2obt4228VR1pA8"
+			+ "Vm9A41E4pk/vA+VFJ/tSmkB5s2gmBBVcA8mU8iIyzMmliTNHeg53EYAytF5M"
+			+ "X2rA7Ct8ApqbrYSSBTUPC+MEBV7UajamWB6UaSUj575MhEnzm0xl/lFqU6ZF"
+			+ "6w0rdey/KvTiotErOS1q8RcY2dcs9Mz8Dm/8IMBcGfny0i/KLtz0OUOLFg3P"
+			+ "/VrPBt7f+YfDqLVc8AujhrxAH/hwYauJ+Q6HSVTSJI7aXB9xtdsijzMZCmnE"
+			+ "1oKRBkACSWD9BGvS3hpv/VqaHWU4B2dnv2oyrIkdkgQu2OtlFxpcOkqwexIj"
+			+ "ssxxOCmT6dpB8JNehjLDU8WXhtFJVFuR84V7KlyeG/s8TaZgCW6uLLVmpteE"
+			+ "J15bnM9jRTW/FZiHwsjy9kVbvaAT+bbIjn5u7qdGsgAQHdeKy191ONvHIttZ"
+			+ "l/qnvrygLImaTOcuMMzU/0ECNlk0QiU0YbfS/RGH2LtRzk8x3FLFVXRiNtrD"
+			+ "uJuwzlP4RufuoZfJsi0rFOuxNFQ/cZEq1q7TCzqP+saRoSLFK1iRE/Ei06pS"
+			+ "JH+cwHMxk3u7k4+HxF72uK9XHIgY6G6WfZTklH2w2VrsLLZLmJ9SO6Zpyt48"
+			+ "KcwvEcxYoZxp1gfPYDCMHeb7oi/gRj9FjnBaNf2dW3a1RqVo5y0QeSfSH4k8"
+			+ "YWX6k+Yh803ZmoIb//TEbfkbXe8XOIffbMSUuIozCQY/Rt9wAHesMWfgTuB5"
+			+ "LSoa8R+mR5lIS/P1ANHdgNrh+XRFrNFeD0dCw6bdYWUXMVaZbCE8Z8pXQ0LO"
+			+ "ItiPuI+w/izD/lXdKXWJJmN/bq2RJRo4WFEDe6sJH9G2Poe/T4xwTm4kX2uA"
+			+ "IZkYy7bZcez8a0bFJzcsJxUbBPRq93J0fXzpvQsszbVZh94VSc9nkH4FnAxT"
+			+ "Kk2bLcsXANJlw3cFO9jOygrXh6R2fyHX0E8WExb2Q7lG68wU1BJVupT8rZ0Y"
+			+ "oRY6WBYG0LuZb+4VAQuI0/Are3BznsgkqudCjf+JUhu1Yefh2hblWuMPNEWb"
+			+ "mOorerNiIzkrt5tjXyBj0g8w/pL//BIlkW5JerMtKTPMfZSroHw9wuAuqHqF"
+			+ "2sMjsW/Lbr5b8SIdIgo3vrS6EM9MGkATfSZz4z+ZWG3EB6QqcMXCZ4N2/WWl"
+			+ "EPKsIqY/509NZRzqOavcMXkOryRJ7GQpmotNbbalI6r6swRoEQ2IzK5XPCC1"
+			+ "iv52YpcRaV9BDpNNByk4l3ddOiEc4dsOkHjaLNvj6Vo1pG/C1Z8VXRRY909D"
+			+ "nH2+PfUL684WZ6kIPeLfqr7N3ZbNxZAVozVG+WXwBlLFT7L+axeGHOhHdH/g"
+			+ "SVMSmWdRX4eNuofmpsU8f3A9aCnPGDxPnB4WKnAGw34TYZrtZ9mHcjYPsq1q"
+			+ "zY6brfZD4T7tktjAlRL2PYZ15MfWVXVH1xoyjeWImTi0o4nyuy/M0HukDfwY"
+			+ "l6nW77TMRiH54wdQqIZUxa32dNNhjcNslRlpOf6td3FbELqhTiaptRSuKjs9"
+			+ "8evbDFK7rb7n6RSSzAwb3oU8pwr4dM8ArTVc0EqnvdSCs1tx46ckIK3AFgcd"
+			+ "opmNq+Qa7qhN5Zgds3cLPIQiyDThhYGPaIgyn4j/dZb1Qwa2U7urijJrBqeS"
+			+ "/kJ2rEXV9v+OX9yTYKypM05A2gOK/ESPbx24C/HmmGm/yBXBx3pABvKt41Dh"
+			+ "b0syB4hYrsq0RriovGemBrNgy4tiJB5BDI9VpWFC/7LR0quFFOrxxm7YvH2h"
+			+ "GkR0oUc/socA80WZx9TegdiBg9TVPbe0gZmoeQc6XLfscBol0QdZWSmLqFxf"
+			+ "TFN7ksaVAUPXA9phBg/k51YmrwNvx4D/A1bBQRtQmq2N4R0j3uMkynubBEfb"
+			+ "9qvQNXpdygouzKUyrN/w+7clilaq2P+R9i7rriZ1waHyjfvAdeBzQQ/pVmgh"
+			+ "o8EiL/TZpIZ71sTYv28scY+V7yYgBA5S/Y4bdmvzSSoMoK8yH/LcBFJOZLQd"
+			+ "YPt7uKWSwQN8iVDA6ZcsYoKuAUw3ziiRaf+GN58ihLB/y/sGmAmX2XwLsPSZ"
+			+ "uQIF/gT8yXjxoyWDLXl3MUgfx+pGg5vBwAtk9a2elEQR9C3a8PPsOy3N9Jh3"
+			+ "xY/A1gJ/rjuubwrb0Sd2LinzPg5uVuKR1jeMSCEebgoyBj8/t8HvknBqJkpl"
+			+ "tjZ6AxGiQ8+v5jRBzYSyiTQfPMxWzdBKqUePdJcLPITf/XitegQnikgAN6bh"
+			+ "kYMS2G9kXJH2CgDm9z3svmu/0Oz2XWEpVHlOjknghPlTaLRqgWoQbK5dkuiV"
+			+ "k9HhGwwsgiR+");
+	}
+}
diff --git a/crypto/test/src/cms/test/CMSTestUtil.cs b/crypto/test/src/cms/test/CMSTestUtil.cs
new file mode 100644
index 000000000..ef7f9169f
--- /dev/null
+++ b/crypto/test/src/cms/test/CMSTestUtil.cs
@@ -0,0 +1,480 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	public class CmsTestUtil
+	{
+		public static SecureRandom rand;
+		private static IAsymmetricCipherKeyPairGenerator kpg;
+		private static IAsymmetricCipherKeyPairGenerator gostKpg;
+		private static IAsymmetricCipherKeyPairGenerator dsaKpg;
+		private static IAsymmetricCipherKeyPairGenerator ecGostKpg;
+		private static IAsymmetricCipherKeyPairGenerator ecDsaKpg;
+		public static CipherKeyGenerator aes192kg;
+		public static CipherKeyGenerator desede128kg;
+		public static CipherKeyGenerator desede192kg;
+		public static CipherKeyGenerator rc240kg;
+		public static CipherKeyGenerator rc264kg;
+		public static CipherKeyGenerator rc2128kg;
+		public static CipherKeyGenerator aesKg;
+		public static CipherKeyGenerator seedKg;
+		public static CipherKeyGenerator camelliaKg;
+		public static BigInteger serialNumber;
+
+		private static readonly byte[] attrCert = Base64.Decode(
+			  "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+			+ "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+			+ "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+			+ "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+			+ "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+			+ "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+			+ "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+			+ "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+			+ "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+			+ "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+			+ "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+			+ "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+			+ "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+			+ "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+			+ "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+			+ "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+			+ "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+			+ "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+			+ "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+			+ "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+			+ "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+			+ "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+			+ "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+			+ "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+			+ "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+			+ "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+			+ "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+			+ "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+			+ "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+			+ "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+			+ "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+			+ "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+			+ "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+			+ "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+			+ "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+			+ "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+			+ "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+			+ "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+			+ "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+		private static IAsymmetricCipherKeyPairGenerator Kpg
+		{
+			get
+			{
+				if (kpg == null)
+				{
+					kpg = GeneratorUtilities.GetKeyPairGenerator("RSA");
+					kpg.Init(new RsaKeyGenerationParameters(
+						BigInteger.ValueOf(17), rand, 1024, 25));
+				}
+
+				return kpg;
+			}
+		}
+
+		private static IAsymmetricCipherKeyPairGenerator GostKpg
+		{
+			get
+			{
+				if (gostKpg == null)
+				{
+					gostKpg = GeneratorUtilities.GetKeyPairGenerator("GOST3410");
+					gostKpg.Init(
+						new Gost3410KeyGenerationParameters(
+							rand,
+							CryptoProObjectIdentifiers.GostR3410x94CryptoProA));
+				}
+
+				return gostKpg;
+			}
+		}
+
+		private static IAsymmetricCipherKeyPairGenerator DsaKpg
+		{
+			get
+			{
+				if (dsaKpg == null)
+				{
+					DsaParameters dsaSpec = new DsaParameters(
+						new BigInteger("7434410770759874867539421675728577177024889699586189000788950934679315164676852047058354758883833299702695428196962057871264685291775577130504050839126673"),
+						new BigInteger("1138656671590261728308283492178581223478058193247"),
+						new BigInteger("4182906737723181805517018315469082619513954319976782448649747742951189003482834321192692620856488639629011570381138542789803819092529658402611668375788410"));
+					dsaKpg = GeneratorUtilities.GetKeyPairGenerator("DSA");
+					dsaKpg.Init(new DsaKeyGenerationParameters(rand, dsaSpec));
+				}
+
+				return dsaKpg;
+			}
+		}
+
+		private static IAsymmetricCipherKeyPairGenerator ECGostKpg
+		{
+			get
+			{
+				if (ecGostKpg == null)
+				{
+					ecGostKpg = GeneratorUtilities.GetKeyPairGenerator("ECGOST3410");
+					ecGostKpg.Init(
+						new ECKeyGenerationParameters(
+							CryptoProObjectIdentifiers.GostR3410x2001CryptoProA,
+							new SecureRandom()));
+				}
+
+				return ecGostKpg;
+			}
+		}
+
+		private static IAsymmetricCipherKeyPairGenerator ECDsaKpg
+		{
+			get
+			{
+				if (ecDsaKpg == null)
+				{
+					ecDsaKpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+					ecDsaKpg.Init(new KeyGenerationParameters(rand, 239));
+				}
+
+				return ecDsaKpg;
+			}
+		}
+
+		static CmsTestUtil()
+		{
+		    try
+		    {
+		        rand = new SecureRandom();
+
+				aes192kg = GeneratorUtilities.GetKeyGenerator("AES");
+				aes192kg.Init(new KeyGenerationParameters(rand, 192));
+
+		        desede128kg = GeneratorUtilities.GetKeyGenerator("DESEDE");
+				desede128kg.Init(new KeyGenerationParameters(rand, 112));
+
+				desede192kg = GeneratorUtilities.GetKeyGenerator("DESEDE");
+				desede192kg.Init(new KeyGenerationParameters(rand, 168));
+
+				rc240kg = GeneratorUtilities.GetKeyGenerator("RC2");
+				rc240kg.Init(new KeyGenerationParameters(rand, 40));
+
+				rc264kg = GeneratorUtilities.GetKeyGenerator("RC2");
+				rc264kg.Init(new KeyGenerationParameters(rand, 64));
+
+				rc2128kg = GeneratorUtilities.GetKeyGenerator("RC2");
+				rc2128kg.Init(new KeyGenerationParameters(rand, 128));
+
+				aesKg = GeneratorUtilities.GetKeyGenerator("AES");
+
+				seedKg = GeneratorUtilities.GetKeyGenerator("SEED");
+
+				camelliaKg = GeneratorUtilities.GetKeyGenerator("Camellia");
+
+				serialNumber = BigInteger.One;
+		    }
+		    catch (Exception ex)
+		    {
+		        throw new Exception(ex.ToString());
+		    }
+		}
+
+		public static string DumpBase64(
+			byte[] data)
+		{
+			StringBuilder buf = new StringBuilder();
+
+			data = Base64.Encode(data);
+
+			for (int i = 0; i < data.Length; i += 64)
+			{
+				if (i + 64 < data.Length)
+				{
+					buf.Append(Encoding.Default.GetString(data, i, 64));
+				}
+				else
+				{
+					buf.Append(Encoding.Default.GetString(data, i, data.Length - i));
+				}
+				buf.Append('\n');
+			}
+
+			return buf.ToString();
+		}
+
+		public static IX509AttributeCertificate GetAttributeCertificate()
+		{
+//			X509StreamParser parser = X509StreamParser.GetInstance("AttributeCertificate");
+//			parser.Init(CmsTestUtil.attrCert);
+//			return (X509AttributeCertificate) parser.Read();
+
+			return new X509AttrCertParser().ReadAttrCert(attrCert);
+		}
+
+		public static AsymmetricCipherKeyPair MakeKeyPair()
+		{
+			return Kpg.GenerateKeyPair();
+		}
+
+		public static AsymmetricCipherKeyPair MakeGostKeyPair()
+		{
+			return GostKpg.GenerateKeyPair();
+		}
+
+		public static AsymmetricCipherKeyPair MakeDsaKeyPair()
+		{
+			return DsaKpg.GenerateKeyPair();
+		}
+
+		public static AsymmetricCipherKeyPair MakeECGostKeyPair()
+		{
+			return ECGostKpg.GenerateKeyPair();
+		}
+
+		public static AsymmetricCipherKeyPair MakeECDsaKeyPair()
+		{
+			return ECDsaKpg.GenerateKeyPair();
+		}
+
+		public static KeyParameter MakeDesEde128Key()
+		{
+			return ParameterUtilities.CreateKeyParameter("DESEDE", desede128kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeAes192Key()
+		{
+			return ParameterUtilities.CreateKeyParameter("AES", aes192kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeDesEde192Key()
+		{
+			return ParameterUtilities.CreateKeyParameter("DESEDE", desede192kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeRC240Key()
+		{
+			return ParameterUtilities.CreateKeyParameter("RC2", rc240kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeRC264Key()
+		{
+			return ParameterUtilities.CreateKeyParameter("RC2", rc264kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeRC2128Key()
+		{
+			return ParameterUtilities.CreateKeyParameter("RC2", rc2128kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeSeedKey()
+		{
+			return ParameterUtilities.CreateKeyParameter("SEED", seedKg.GenerateKey());
+		}
+
+		public static KeyParameter MakeAesKey(
+			int keySize)
+		{
+			aesKg.Init(new KeyGenerationParameters(rand, keySize));
+
+			return ParameterUtilities.CreateKeyParameter("AES", aesKg.GenerateKey());
+		}
+
+		public static KeyParameter MakeCamelliaKey(
+			int keySize)
+		{
+			camelliaKg.Init(new KeyGenerationParameters(rand, keySize));
+
+			return ParameterUtilities.CreateKeyParameter("CAMELLIA", camelliaKg.GenerateKey());
+		}
+
+		public static X509Certificate MakeCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN)
+		{
+			return MakeCertificate(_subKP, _subDN, _issKP, _issDN, false);
+		}
+
+		public static X509Certificate MakeCACertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN)
+		{
+			return MakeCertificate(_subKP, _subDN, _issKP, _issDN, true);
+		}
+
+		public static X509Certificate MakeV1Certificate(AsymmetricCipherKeyPair subKP,
+			string _subDN, AsymmetricCipherKeyPair issKP, string _issDN)
+		{
+			AsymmetricKeyParameter subPub = subKP.Public;
+			AsymmetricKeyParameter issPriv = issKP.Private;
+			AsymmetricKeyParameter issPub = issKP.Public;
+
+			X509V1CertificateGenerator v1CertGen = new X509V1CertificateGenerator();
+
+			v1CertGen.Reset();
+			v1CertGen.SetSerialNumber(AllocateSerialNumber());
+			v1CertGen.SetIssuerDN(new X509Name(_issDN));
+			v1CertGen.SetNotBefore(DateTime.UtcNow);
+			v1CertGen.SetNotAfter(DateTime.UtcNow.AddDays(100));
+			v1CertGen.SetSubjectDN(new X509Name(_subDN));
+			v1CertGen.SetPublicKey(subPub);
+
+			if (issPub is RsaKeyParameters)
+			{
+				v1CertGen.SetSignatureAlgorithm("SHA1WithRSA");
+			}
+			else if (issPub is DsaPublicKeyParameters)
+			{
+				v1CertGen.SetSignatureAlgorithm("SHA1withDSA");
+			}
+			else if (issPub is ECPublicKeyParameters)
+			{
+				ECPublicKeyParameters ecPub = (ECPublicKeyParameters)issPub;
+				if (ecPub.AlgorithmName == "ECGOST3410")
+				{
+					v1CertGen.SetSignatureAlgorithm("GOST3411withECGOST3410");
+				}
+				else
+				{
+					v1CertGen.SetSignatureAlgorithm("SHA1withECDSA");
+				}	
+			}
+			else
+			{
+				v1CertGen.SetSignatureAlgorithm("GOST3411WithGOST3410");
+			}
+
+			X509Certificate _cert = v1CertGen.Generate(issPriv);
+
+			_cert.CheckValidity(DateTime.UtcNow);
+			_cert.Verify(issPub);
+
+			return _cert;
+		}
+
+		public static X509Certificate MakeCertificate(
+			AsymmetricCipherKeyPair subKP, string _subDN,
+			AsymmetricCipherKeyPair issKP, string _issDN, bool _ca)
+		{
+			AsymmetricKeyParameter subPub = subKP.Public;
+			AsymmetricKeyParameter issPriv = issKP.Private;
+			AsymmetricKeyParameter issPub = issKP.Public;
+
+			X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+			v3CertGen.Reset();
+			v3CertGen.SetSerialNumber(AllocateSerialNumber());
+			v3CertGen.SetIssuerDN(new X509Name(_issDN));
+			v3CertGen.SetNotBefore(DateTime.UtcNow);
+			v3CertGen.SetNotAfter(DateTime.UtcNow.AddDays(100));
+			v3CertGen.SetSubjectDN(new X509Name(_subDN));
+			v3CertGen.SetPublicKey(subPub);
+
+			if (issPub is RsaKeyParameters)
+			{
+				v3CertGen.SetSignatureAlgorithm("SHA1WithRSA");
+			}
+			else if (issPub is ECPublicKeyParameters)
+			{
+				ECPublicKeyParameters ecPub = (ECPublicKeyParameters) issPub;
+				if (ecPub.AlgorithmName == "ECGOST3410")
+				{
+					v3CertGen.SetSignatureAlgorithm("GOST3411withECGOST3410");
+				}
+				else
+				{
+					v3CertGen.SetSignatureAlgorithm("SHA1withECDSA");
+				}
+			}
+			else
+			{
+				v3CertGen.SetSignatureAlgorithm("GOST3411WithGOST3410");
+			}
+
+			v3CertGen.AddExtension(
+				X509Extensions.SubjectKeyIdentifier,
+				false,
+				CreateSubjectKeyId(subPub));
+
+			v3CertGen.AddExtension(
+				X509Extensions.AuthorityKeyIdentifier,
+				false,
+				CreateAuthorityKeyId(issPub));
+
+			v3CertGen.AddExtension(
+				X509Extensions.BasicConstraints,
+				false,
+				new BasicConstraints(_ca));
+
+			X509Certificate _cert = v3CertGen.Generate(issPriv);
+
+			_cert.CheckValidity();
+			_cert.Verify(issPub);
+
+			return _cert;
+		}
+
+		public static X509Crl MakeCrl(
+			AsymmetricCipherKeyPair pair)
+		{
+			X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
+			DateTime now = DateTime.UtcNow;
+
+			crlGen.SetIssuerDN(new X509Name("CN=Test CA"));
+
+			crlGen.SetThisUpdate(now);
+			crlGen.SetNextUpdate(now.AddSeconds(100));
+			crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+			crlGen.AddCrlEntry(BigInteger.One, now, CrlReason.PrivilegeWithdrawn);
+
+			crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.Public));
+
+			return crlGen.Generate(pair.Private);
+		}
+
+		/*
+		*
+		*  INTERNAL METHODS
+		*
+		*/
+		private static AuthorityKeyIdentifier CreateAuthorityKeyId(
+			AsymmetricKeyParameter _pubKey)
+		{
+			SubjectPublicKeyInfo _info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_pubKey);
+			return new AuthorityKeyIdentifier(_info);
+		}
+
+		internal static SubjectKeyIdentifier CreateSubjectKeyId(
+			AsymmetricKeyParameter _pubKey)
+		{
+			SubjectPublicKeyInfo _info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_pubKey);
+			return new SubjectKeyIdentifier(_info);
+		}
+
+		private static BigInteger AllocateSerialNumber()
+		{
+			BigInteger _tmp = serialNumber;
+			serialNumber = serialNumber.Add(BigInteger.One);
+			return _tmp;
+		}
+
+		public static byte[] StreamToByteArray(
+			Stream inStream)
+		{
+			return Streams.ReadAll(inStream);
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/CompressedDataStreamTest.cs b/crypto/test/src/cms/test/CompressedDataStreamTest.cs
new file mode 100644
index 000000000..48a6c56ee
--- /dev/null
+++ b/crypto/test/src/cms/test/CompressedDataStreamTest.cs
@@ -0,0 +1,116 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class CompressedDataStreamTest
+	{
+		private static readonly byte[] compData = Base64.Decode(
+			  "MIAGCyqGSIb3DQEJEAEJoIAwgAIBADANBgsqhkiG9w0BCRADCDCABgkqhkiG9w0BBwGggCSABIIC"
+			+ "Hnic7ZRdb9owFIbvK/k/5PqVYPFXGK12YYyboVFASSp1vQtZGiLRACZE49/XHoUW7S/0tXP8Efux"
+			+ "fU5ivWnasml72XFb3gb5druui7ytN803M570nii7C5r8tfwR281hy/p/KSM3+jzH5s3+pbQ90xSb"
+			+ "P3VT3QbLusnt8WPIuN5vN/vaA2+DulnXTXkXvNTr8j8ouZmkCmGI/UW+ZS/C8zP0bz2dz0zwLt+1"
+			+ "UEk2M8mlaxjRMByAhZTj0RGYg4TvogiRASROsZgjpVcJCb1KV6QzQeDJ1XkoQ5Jm+C5PbOHZZGRi"
+			+ "v+ORAcshOGeCcdFJyfgFxdtCdEcmOrbinc/+BBMzRThEYpwl+jEBpciSGWQkI0TSlREmD/eOHb2D"
+			+ "SGLuESm/iKUFt1y4XHBO2a5oq0IKJKWLS9kUZTA7vC5LSxYmgVL46SIWxIfWBQd6AdrnjLmH94UT"
+			+ "vGxVibLqRCtIpp4g2qpdtqK1LiOeolpVK5wVQ5P7+QjZAlrh0cePYTx/gNZuB9Vhndtgujl9T/tg"
+			+ "W9ogK+3rnmg3YWygnTuF5GDS+Q/jIVLnCcYZFc6Kk/+c80wKwZjwdZIqDYWRH68MuBQSXLgXYXj2"
+			+ "3CAaYOBNJMliTl0X7eV5DnoKIFSKYdj3cRpD/cK/JWTHJRe76MUXnfBW8m7Hd5zhQ4ri2NrVF/WL"
+			+ "+kV1/3AGSlJ32bFPd2BsQD8uSzIx6lObkjdz95c0AAAAAAAAAAAAAAAA");
+
+		private static readonly byte[] uncompData = Base64.Decode(
+			  "Q29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9FREktWDEyOyBuYW1lPUdyb3VwMi54MTINCkNvbnRl"
+			+ "bnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJpbmFyeQ0KQ29udGVudC1EaXNwb3NpdGlvbjogaW5saW5l"
+			+ "OyBmaWxlbmFtZT1Hcm91cDIueDEyDQoNCklTQSowMCpzc3Nzc3Nzc3NzKjAwKnJycnJycnJycnIqW"
+			+ "loqQ1lDTE9ORSAgICAgICAgKlpaKlBBUlRORVIgICAgICAgICo5NjEwMDcqMjAxMypVKjAwMjAwKj"
+			+ "AwMDAwMDAwMSowKlQqKg1HUypQTypTMVMxUzFTMVMxUzFTMVMqUjFSMVIxUjFSMVIxUjFSKjk2MTA"
+			+ "wNyoyMDEzKjAwMDAwMDAwNCpYKjAwMzA1MA1TVCo4NTAqMDAwMDQwMDAxDUJFRyowMCpCRSoyYSo0"
+			+ "MzMyNDIzNHY1NTIzKjk2MTAwNyoyM3RjNHZ5MjR2MmgzdmgzdmgqWloqSUVMKjA5KlJFKjA5DUNVU"
+			+ "ioxMSpUUk4qNTY1Nio2NSo1NjYqSU1GKjAwNio5NjEwMDcNUkVGKjZBKjQzM3IxYzNyMzRyMzRjMz"
+			+ "MxMnFjdGdjNTQqUmVmZXJlbmNlIE51bWJlcg1QRVIqQUEqSGFucyBHdXR0ZW4qQ1AqMS4zMjIuMzI"
+			+ "zLjQ0NDQqKioqKnJnZzRlZ3Y0dDQNVEFYKjR0Z3RidDR0cjR0cipHTCpnaGdoKioqKioqKioqRypD"
+			+ "DUZPQipUUCpDQSpVU0EqMDIqRE9NKkNDKlJlZ3VsYXIgTG9jYXRpb25zIHBlciBUZXJtcw1DVFAqR"
+			+ "EUqQzA0KjQ1MyoyNTAwMCpEOSpTRUwqMjMyMTQqMjM0MzI0MjM0MjMqRVMqNDIyNDM0MjMNU0FDKk"
+			+ "EqQjAwMCpBRSozNTQ1KjM0NDIzMDANQ1VSKjExKjc2Nyo3NzY3KjY1DVBPMSoxMTEtYWFhKjEwMDA"
+			+ "wMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioq"
+			+ "KioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzN"
+			+ "HE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMD"
+			+ "AwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKio"
+			+ "qKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRx"
+			+ "NmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwM"
+			+ "CpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKi"
+			+ "oqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZ"
+			+ "mMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAq"
+			+ "QVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqK"
+			+ "kExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2Zj"
+			+ "M1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkF"
+			+ "TKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipB"
+			+ "MSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzN"
+			+ "TM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNQ1RUKjENU0UqMjIqMDAwMDQwMDAxDU"
+			+ "dFKjEqMDAwMDAwMDA0DUlFQSoxKjAwMDAwMDAwMQ0=");
+
+		[Test]
+		public void TestWorkingData()
+		{
+			CmsCompressedDataParser ed = new CmsCompressedDataParser(compData);
+
+			Assert.IsTrue(Arrays.AreEqual(uncompData, CmsTestUtil.StreamToByteArray(ed.GetContent().ContentStream)));
+		}
+
+		[Test]
+		public void TestEach()
+		{
+			byte[] testData = Encoding.ASCII.GetBytes("Hello world!");
+
+			CmsCompressedDataStreamGenerator gen = new CmsCompressedDataStreamGenerator();
+			MemoryStream bOut = new MemoryStream();
+
+			Stream cOut = gen.Open(bOut, CmsCompressedDataStreamGenerator.ZLib);
+
+			cOut.Write(testData, 0, testData.Length);
+
+			cOut.Close();
+
+			CmsCompressedDataParser ed = new CmsCompressedDataParser(bOut.ToArray());
+
+			Assert.IsTrue(Arrays.AreEqual(testData, CmsTestUtil.StreamToByteArray(ed.GetContent().ContentStream)));
+		}
+
+		[Test]
+		public void Test1000()
+		{
+			byte[] testData = new byte[10000];
+			SecureRandom rand = new SecureRandom();
+
+			rand.SetSeed(0);
+
+			for (int i = 0; i != 10; i++)
+			{
+				CmsCompressedDataStreamGenerator gen = new CmsCompressedDataStreamGenerator();
+				MemoryStream bOut = new MemoryStream();
+
+				Stream cOut = gen.Open(bOut, CmsCompressedDataStreamGenerator.ZLib);
+
+				rand.NextBytes(testData);
+
+				cOut.Write(testData, 0, testData.Length);
+
+				cOut.Close();
+
+				CmsCompressedDataParser ed = new CmsCompressedDataParser(bOut.ToArray());
+
+				Assert.IsTrue(Arrays.AreEqual(testData, CmsTestUtil.StreamToByteArray(ed.GetContent().ContentStream)));
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/CompressedDataTest.cs b/crypto/test/src/cms/test/CompressedDataTest.cs
new file mode 100644
index 000000000..6df85d9fd
--- /dev/null
+++ b/crypto/test/src/cms/test/CompressedDataTest.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class CompressedDataTest
+	{
+		private static readonly byte[] TEST_DATA = Encoding.ASCII.GetBytes("Hello world!");
+
+		private static readonly byte[] compData = Base64.Decode(
+			  "MIAGCyqGSIb3DQEJEAEJoIAwgAIBADANBgsqhkiG9w0BCRADCDCABgkqhkiG9w0BBwGggCSABIIC"
+			+ "Hnic7ZRdb9owFIbvK/k/5PqVYPFXGK12YYyboVFASSp1vQtZGiLRACZE49/XHoUW7S/0tXP8Efux"
+			+ "fU5ivWnasml72XFb3gb5druui7ytN803M570nii7C5r8tfwR281hy/p/KSM3+jzH5s3+pbQ90xSb"
+			+ "P3VT3QbLusnt8WPIuN5vN/vaA2+DulnXTXkXvNTr8j8ouZmkCmGI/UW+ZS/C8zP0bz2dz0zwLt+1"
+			+ "UEk2M8mlaxjRMByAhZTj0RGYg4TvogiRASROsZgjpVcJCb1KV6QzQeDJ1XkoQ5Jm+C5PbOHZZGRi"
+			+ "v+ORAcshOGeCcdFJyfgFxdtCdEcmOrbinc/+BBMzRThEYpwl+jEBpciSGWQkI0TSlREmD/eOHb2D"
+			+ "SGLuESm/iKUFt1y4XHBO2a5oq0IKJKWLS9kUZTA7vC5LSxYmgVL46SIWxIfWBQd6AdrnjLmH94UT"
+			+ "vGxVibLqRCtIpp4g2qpdtqK1LiOeolpVK5wVQ5P7+QjZAlrh0cePYTx/gNZuB9Vhndtgujl9T/tg"
+			+ "W9ogK+3rnmg3YWygnTuF5GDS+Q/jIVLnCcYZFc6Kk/+c80wKwZjwdZIqDYWRH68MuBQSXLgXYXj2"
+			+ "3CAaYOBNJMliTl0X7eV5DnoKIFSKYdj3cRpD/cK/JWTHJRe76MUXnfBW8m7Hd5zhQ4ri2NrVF/WL"
+			+ "+kV1/3AGSlJ32bFPd2BsQD8uSzIx6lObkjdz95c0AAAAAAAAAAAAAAAA");
+
+		private static readonly byte[] uncompData = Base64.Decode(
+			  "Q29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9FREktWDEyOyBuYW1lPUdyb3VwMi54MTINCkNvbnRl"
+			+ "bnQtVHJhbnNmZXItRW5jb2Rpbmc6IGJpbmFyeQ0KQ29udGVudC1EaXNwb3NpdGlvbjogaW5saW5l"
+			+ "OyBmaWxlbmFtZT1Hcm91cDIueDEyDQoNCklTQSowMCpzc3Nzc3Nzc3NzKjAwKnJycnJycnJycnIqW"
+			+ "loqQ1lDTE9ORSAgICAgICAgKlpaKlBBUlRORVIgICAgICAgICo5NjEwMDcqMjAxMypVKjAwMjAwKj"
+			+ "AwMDAwMDAwMSowKlQqKg1HUypQTypTMVMxUzFTMVMxUzFTMVMqUjFSMVIxUjFSMVIxUjFSKjk2MTA"
+			+ "wNyoyMDEzKjAwMDAwMDAwNCpYKjAwMzA1MA1TVCo4NTAqMDAwMDQwMDAxDUJFRyowMCpCRSoyYSo0"
+			+ "MzMyNDIzNHY1NTIzKjk2MTAwNyoyM3RjNHZ5MjR2MmgzdmgzdmgqWloqSUVMKjA5KlJFKjA5DUNVU"
+			+ "ioxMSpUUk4qNTY1Nio2NSo1NjYqSU1GKjAwNio5NjEwMDcNUkVGKjZBKjQzM3IxYzNyMzRyMzRjMz"
+			+ "MxMnFjdGdjNTQqUmVmZXJlbmNlIE51bWJlcg1QRVIqQUEqSGFucyBHdXR0ZW4qQ1AqMS4zMjIuMzI"
+			+ "zLjQ0NDQqKioqKnJnZzRlZ3Y0dDQNVEFYKjR0Z3RidDR0cjR0cipHTCpnaGdoKioqKioqKioqRypD"
+			+ "DUZPQipUUCpDQSpVU0EqMDIqRE9NKkNDKlJlZ3VsYXIgTG9jYXRpb25zIHBlciBUZXJtcw1DVFAqR"
+			+ "EUqQzA0KjQ1MyoyNTAwMCpEOSpTRUwqMjMyMTQqMjM0MzI0MjM0MjMqRVMqNDIyNDM0MjMNU0FDKk"
+			+ "EqQjAwMCpBRSozNTQ1KjM0NDIzMDANQ1VSKjExKjc2Nyo3NzY3KjY1DVBPMSoxMTEtYWFhKjEwMDA"
+			+ "wMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioq"
+			+ "KioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzN"
+			+ "HE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMD"
+			+ "AwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKio"
+			+ "qKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRx"
+			+ "NmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwM"
+			+ "CpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2ZjM1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKi"
+			+ "oqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkFTKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZ"
+			+ "mMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipBMSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAq"
+			+ "QVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzNTM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqK"
+			+ "kExKnl0cmgNUE8xKjExMS1hYWEqMTAwMDAwMCpBUyo5MC4wMCpCRCpBSyoyMzQyMzV2MzUzNHE2Zj"
+			+ "M1MzR2NDM1MzQ1M3ZxM3EzMioqKioqKioqKioqQTEqeXRyaA1QTzEqMTExLWFhYSoxMDAwMDAwKkF"
+			+ "TKjkwLjAwKkJEKkFLKjIzNDIzNXYzNTM0cTZmMzUzNHY0MzUzNDUzdnEzcTMyKioqKioqKioqKipB"
+			+ "MSp5dHJoDVBPMSoxMTEtYWFhKjEwMDAwMDAqQVMqOTAuMDAqQkQqQUsqMjM0MjM1djM1MzRxNmYzN"
+			+ "TM0djQzNTM0NTN2cTNxMzIqKioqKioqKioqKkExKnl0cmgNQ1RUKjENU0UqMjIqMDAwMDQwMDAxDU"
+			+ "dFKjEqMDAwMDAwMDA0DUlFQSoxKjAwMDAwMDAwMQ0=");
+
+		[Test]
+		public void TestWorkingData()
+		{
+			CmsCompressedData ed = new CmsCompressedData(compData);
+
+			Assert.IsTrue(Arrays.AreEqual(uncompData, ed.GetContent()));
+		}
+
+		[Test]
+		public void TestEach()
+		{
+			CmsCompressedData cd = GetStdData();
+
+			Assert.IsTrue(Arrays.AreEqual(TEST_DATA, cd.GetContent()));
+		}
+
+		[Test]
+		public void TestLimitUnder()
+		{
+			CmsCompressedData cd = GetStdData();
+
+			try
+			{
+				cd.GetContent(TEST_DATA.Length / 2);
+			}
+			catch (CmsException e)
+			{
+				Assert.IsTrue(e.InnerException is StreamOverflowException);
+			}
+		}
+
+		[Test]
+		public void TestLimitOver()
+		{
+			CmsCompressedData cd = GetStdData();
+
+			Assert.IsTrue(Arrays.AreEqual(TEST_DATA, cd.GetContent(TEST_DATA.Length * 2)));
+		}
+
+		[Test]
+		public void TestLimitEqual()
+		{
+			CmsCompressedData cd = GetStdData();
+
+			Assert.IsTrue(Arrays.AreEqual(TEST_DATA, cd.GetContent(TEST_DATA.Length)));
+		}
+
+		private CmsCompressedData GetStdData()
+		{
+			CmsProcessableByteArray testData = new CmsProcessableByteArray(TEST_DATA);
+			CmsCompressedDataGenerator gen = new CmsCompressedDataGenerator();
+			return gen.Generate(testData, CmsCompressedDataGenerator.ZLib);
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/EnvelopedDataStreamTest.cs b/crypto/test/src/cms/test/EnvelopedDataStreamTest.cs
new file mode 100644
index 000000000..8512f6622
--- /dev/null
+++ b/crypto/test/src/cms/test/EnvelopedDataStreamTest.cs
@@ -0,0 +1,537 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class EnvelopedDataStreamTest
+	{
+		private const int BufferSize = 4000;
+
+		private const string SignDN = "O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair signKP;
+//		private static X509Certificate signCert;
+		//signCert = CmsTestUtil.MakeCertificate(_signKP, SignDN, _signKP, SignDN);
+
+//		private const string OrigDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+//		private static AsymmetricCipherKeyPair origKP;
+		//origKP   = CmsTestUtil.MakeKeyPair();
+//		private static X509Certificate origCert;
+		//origCert = CmsTestUtil.MakeCertificate(origKP, OrigDN, _signKP, SignDN);
+
+		private const string ReciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair reciKP;
+		private static X509Certificate reciCert;
+
+		private static AsymmetricCipherKeyPair origECKP;
+		private static AsymmetricCipherKeyPair reciECKP;
+		private static X509Certificate reciECCert;
+
+		private static AsymmetricCipherKeyPair SignKP
+		{
+			get { return signKP == null ? (signKP   = CmsTestUtil.MakeKeyPair()) : signKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciKP
+		{
+			get { return reciKP == null ? (reciKP   = CmsTestUtil.MakeKeyPair()) : reciKP; }
+		}
+
+		private static X509Certificate ReciCert
+		{
+			get { return reciCert == null ? (reciCert = CmsTestUtil.MakeCertificate(ReciKP, ReciDN, SignKP, SignDN)) : reciCert;}
+		}
+
+		private static AsymmetricCipherKeyPair OrigECKP
+		{
+			get { return origECKP == null ? (origECKP = CmsTestUtil.MakeECDsaKeyPair()) : origECKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciECKP
+		{
+			get { return reciECKP == null ? (reciECKP = CmsTestUtil.MakeECDsaKeyPair()) : reciECKP; }
+		}
+
+		private static X509Certificate ReciECCert
+		{
+			get { return reciECCert == null ? (reciECCert = CmsTestUtil.MakeCertificate(ReciECKP, ReciDN, SignKP, SignDN)) : reciECCert;}
+		}
+
+		[Test]
+		public void TestWorkingData()
+		{
+			byte[] keyData = Base64.Decode(
+				"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKrAz/SQKrcQ" +
+				"nj9IxHIfKDbuXsMqUpI06s2gps6fp7RDNvtUDDMOciWGFhD45YSy8GO0mPx3" +
+				"Nkc7vKBqX4TLcqLUz7kXGOHGOwiPZoNF+9jBMPNROe/B0My0PkWg9tuq+nxN" +
+				"64oD47+JvDwrpNOS5wsYavXeAW8Anv9ZzHLU7KwZAgMBAAECgYA/fqdVt+5K" +
+				"WKGfwr1Z+oAHvSf7xtchiw/tGtosZ24DOCNP3fcTXUHQ9kVqVkNyzt9ZFCT3" +
+				"bJUAdBQ2SpfuV4DusVeQZVzcROKeA09nPkxBpTefWbSDQGhb+eZq9L8JDRSW" +
+				"HyYqs+MBoUpLw7GKtZiJkZyY6CsYkAnQ+uYVWq/TIQJBAP5zafO4HUV/w4KD" +
+				"VJi+ua+GYF1Sg1t/dYL1kXO9GP1p75YAmtm6LdnOCas7wj70/G1YlPGkOP0V" +
+				"GFzeG5KAmAUCQQCryvKU9nwWA+kypcQT9Yr1P4vGS0APYoBThnZq7jEPc5Cm" +
+				"ZI82yseSxSeea0+8KQbZ5mvh1p3qImDLEH/iNSQFAkAghS+tboKPN10NeSt+" +
+				"uiGRRWNbiggv0YJ7Uldcq3ZeLQPp7/naiekCRUsHD4Qr97OrZf7jQ1HlRqTu" +
+				"eZScjMLhAkBNUMZCQnhwFAyEzdPkQ7LpU1MdyEopYmRssuxijZao5JLqQAGw" +
+				"YCzXokGFa7hz72b09F4DQurJL/WuDlvvu4jdAkEAxwT9lylvfSfEQw4/qQgZ" +
+				"MFB26gqB6Gqs1pHIZCzdliKx5BO3VDeUGfXMI8yOkbXoWbYx5xPid/+N8R//" +
+				"+sxLBw==");
+
+			byte[] envData = Base64.Decode(
+				"MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKEw1C" +
+				"b3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBHjANBgkqhkiG9w0BAQEFAASB" +
+				"gDmnaDZ0vDJNlaUSYyEXsgbaUH+itNTjCOgv77QTX2ImXj+kTctM19PQF2I1" +
+				"0/NL0fjakvCgBTHKmk13a7jqB6cX3bysenHNrglHsgNGgeXQ7ggAq5fV/JQQ" +
+				"T7rSxEtuwpbuHQnoVUZahOHVKy/a0uLr9iIh1A3y+yZTZaG505ZJMIAGCSqG" +
+				"SIb3DQEHATAdBglghkgBZQMEAQIEENmkYNbDXiZxJWtq82qIRZKggAQgkOGr" +
+				"1JcTsADStez1eY4+rO4DtyBIyUYQ3pilnbirfPkAAAAAAAAAAAAA");
+
+
+			CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(envData);
+
+			RecipientInformationStore recipients = ep.GetRecipientInfos();
+
+			Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+//            PKCS8EncodedKeySpec	keySpec = new PKCS8EncodedKeySpec(keyData);
+//            KeyFactory			keyFact = KeyFactory.GetInstance("RSA");
+//            Key					priKey = keyFact.generatePrivate(keySpec);
+			AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(keyData);
+            byte[] data = Hex.Decode("57616c6c6157616c6c6157617368696e67746f6e");
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				CmsTypedStream recData = recipient.GetContentStream(priKey);
+
+				byte[] compare = CmsTestUtil.StreamToByteArray(recData.ContentStream);
+				Assert.IsTrue(Arrays.AreEqual(data, compare));
+			}
+		}
+
+		private void VerifyData(
+			byte[]	encodedBytes,
+			string	expectedOid,
+			byte[]	expectedData)
+		{
+			CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(encodedBytes);
+			RecipientInformationStore recipients = ep.GetRecipientInfos();
+
+			Assert.AreEqual(ep.EncryptionAlgOid, expectedOid);
+
+			ICollection c = recipients.GetRecipients();
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				CmsTypedStream recData = recipient.GetContentStream(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(expectedData, CmsTestUtil.StreamToByteArray(
+					recData.ContentStream)));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransAes128BufferedStream()
+		{
+			byte[] data = new byte[2000];
+			for (int i = 0; i != 2000; i++)
+			{
+				data[i] = (byte)(i & 0xff);
+			}
+
+			//
+			// unbuffered
+			//
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream outStream = edGen.Open(
+				bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			for (int i = 0; i != 2000; i++)
+			{
+				outStream.WriteByte(data[i]);
+			}
+
+			outStream.Close();
+
+			VerifyData(bOut.ToArray(), CmsEnvelopedDataGenerator.Aes128Cbc, data);
+
+			int unbufferedLength = bOut.ToArray().Length;
+
+			//
+			// Using buffered output - should be == to unbuffered
+			//
+			edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			bOut.SetLength(0);
+
+			outStream = edGen.Open(bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			Streams.PipeAll(new MemoryStream(data, false), outStream);
+			outStream.Close();
+
+			VerifyData(bOut.ToArray(), CmsEnvelopedDataGenerator.Aes128Cbc, data);
+
+			Assert.AreEqual(unbufferedLength, bOut.ToArray().Length);
+		}
+
+		[Test]
+		public void TestKeyTransAes128Buffered()
+		{
+			byte[] data = new byte[2000];
+			for (int i = 0; i != 2000; i++)
+			{
+				data[i] = (byte)(i & 0xff);
+			}
+
+			//
+			// unbuffered
+			//
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			MemoryStream  bOut = new MemoryStream();
+
+			Stream outStream = edGen.Open(
+				bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			for (int i = 0; i != 2000; i++)
+			{
+				outStream.WriteByte(data[i]);
+			}
+
+			outStream.Close();
+
+			VerifyData(bOut.ToArray(), CmsEnvelopedDataGenerator.Aes128Cbc, data);
+
+			int unbufferedLength = bOut.ToArray().Length;
+
+			//
+			// buffered - less than default of 1000
+			//
+			edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.SetBufferSize(300);
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			bOut.SetLength(0);
+
+			outStream = edGen.Open(bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			for (int i = 0; i != 2000; i++)
+			{
+				outStream.WriteByte(data[i]);
+			}
+
+			outStream.Close();
+
+			VerifyData(bOut.ToArray(), CmsEnvelopedDataGenerator.Aes128Cbc, data);
+
+			Assert.IsTrue(unbufferedLength < bOut.ToArray().Length);
+		}
+
+		[Test]
+		public void TestKeyTransAes128Der()
+		{
+			byte[] data = new byte[2000];
+			for (int i = 0; i != 2000; i++)
+			{
+				data[i] = (byte)(i & 0xff);
+			}
+
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream outStream = edGen.Open(
+				bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			for (int i = 0; i != 2000; i++)
+			{
+				outStream.WriteByte(data[i]);
+			}
+
+			outStream.Close();
+
+			// convert to DER
+			byte[] derEncodedBytes = Asn1Object.FromByteArray(bOut.ToArray()).GetDerEncoded();
+
+			VerifyData(derEncodedBytes, CmsEnvelopedDataGenerator.Aes128Cbc, data);
+		}
+
+		[Test]
+		public void TestKeyTransAes128Throughput()
+		{
+			byte[] data = new byte[40001];
+			for (int i = 0; i != data.Length; i++)
+			{
+				data[i] = (byte)(i & 0xff);
+			}
+
+			//
+			// buffered
+			//
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.SetBufferSize(BufferSize);
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream outStream = edGen.Open(bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			for (int i = 0; i != data.Length; i++)
+			{
+				outStream.WriteByte(data[i]);
+			}
+
+			outStream.Close();
+
+			CmsEnvelopedDataParser		ep = new CmsEnvelopedDataParser(bOut.ToArray());
+			RecipientInformationStore	recipients = ep.GetRecipientInfos();
+			ICollection					c = recipients.GetRecipients();
+
+			IEnumerator e = c.GetEnumerator();
+
+			if (e.MoveNext())
+			{
+				RecipientInformation recipient = (RecipientInformation) e.Current;
+
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				CmsTypedStream recData = recipient.GetContentStream(ReciKP.Private);
+
+				Stream dataStream = recData.ContentStream;
+				MemoryStream dataOut = new MemoryStream();
+				int len;
+				byte[] buf = new byte[BufferSize];
+				int count = 0;
+
+				while (count != 10 && (len = dataStream.Read(buf, 0, buf.Length)) > 0)
+				{
+					Assert.AreEqual(buf.Length, len);
+
+					dataOut.Write(buf, 0, buf.Length);
+					count++;
+				}
+
+				len = dataStream.Read(buf, 0, buf.Length);
+				dataOut.Write(buf, 0, len);
+
+				Assert.IsTrue(Arrays.AreEqual(data, dataOut.ToArray()));
+			}
+			else
+			{
+				Assert.Fail("recipient not found.");
+			}
+		}
+
+		[Test]
+		public void TestKeyTransAes128()
+		{
+			byte[] data = Encoding.Default.GetBytes("WallaWallaWashington");
+
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream outStream = edGen.Open(
+				bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			outStream.Write(data, 0, data.Length);
+
+			outStream.Close();
+
+			CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray());
+
+			RecipientInformationStore recipients = ep.GetRecipientInfos();
+
+			Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				CmsTypedStream recData = recipient.GetContentStream(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream)));
+			}
+
+			ep.Close();
+		}
+
+		[Test]
+		public void TestAesKek()
+		{
+			byte[] data = Encoding.Default.GetBytes("WallaWallaWashington");
+			KeyParameter kek = CmsTestUtil.MakeAes192Key();
+
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+			edGen.AddKekRecipient("AES192", kek, kekId);
+
+			MemoryStream  bOut = new MemoryStream();
+
+			Stream outStream = edGen.Open(
+				bOut,
+				CmsEnvelopedDataGenerator.DesEde3Cbc);
+			outStream.Write(data, 0, data.Length);
+
+			outStream.Close();
+
+			CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray());
+
+			RecipientInformationStore recipients = ep.GetRecipientInfos();
+
+			Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, "2.16.840.1.101.3.4.1.25");
+
+				CmsTypedStream recData = recipient.GetContentStream(kek);
+
+				Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream)));
+			}
+
+			ep.Close();
+		}
+
+		[Test]
+		public void TestTwoAesKek()
+		{
+			byte[] data = Encoding.Default.GetBytes("WallaWallaWashington");
+			KeyParameter kek1 = CmsTestUtil.MakeAes192Key();
+			KeyParameter kek2 = CmsTestUtil.MakeAes192Key();
+
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			byte[]  kekId1 = new byte[] { 1, 2, 3, 4, 5 };
+			byte[]  kekId2 = new byte[] { 5, 4, 3, 2, 1 };
+
+			edGen.AddKekRecipient("AES192", kek1, kekId1);
+			edGen.AddKekRecipient("AES192", kek2, kekId2);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream outStream = edGen.Open(
+				bOut,
+				CmsEnvelopedDataGenerator.DesEde3Cbc);
+			outStream.Write(data, 0, data.Length);
+
+			outStream.Close();
+
+			CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray());
+
+			RecipientInformationStore recipients = ep.GetRecipientInfos();
+
+			Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			RecipientID recSel = new RecipientID();
+
+			recSel.KeyIdentifier = kekId2;
+
+			RecipientInformation recipient = recipients.GetFirstRecipient(recSel);
+
+			Assert.AreEqual(recipient.KeyEncryptionAlgOid, "2.16.840.1.101.3.4.1.25");
+
+			CmsTypedStream recData = recipient.GetContentStream(kek2);
+
+			Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream)));
+
+			ep.Close();
+		}
+
+		[Test]
+		public void TestECKeyAgree()
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+
+			edGen.AddKeyAgreementRecipient(
+				CmsEnvelopedDataGenerator.ECDHSha1Kdf,
+				OrigECKP.Private,
+				OrigECKP.Public,
+				ReciECCert,
+				CmsEnvelopedDataGenerator.Aes128Wrap);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream outStr = edGen.Open(bOut, CmsEnvelopedDataGenerator.Aes128Cbc);
+			outStr.Write(data, 0, data.Length);
+
+			outStr.Close();
+
+			CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray());
+
+			RecipientInformationStore recipients = ep.GetRecipientInfos();
+
+			Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientID recSel = new RecipientID();
+
+//			recSel.SetIssuer(PrincipalUtilities.GetIssuerX509Principal(ReciECCert).GetEncoded());
+			recSel.Issuer = PrincipalUtilities.GetIssuerX509Principal(ReciECCert);
+			recSel.SerialNumber = ReciECCert.SerialNumber;
+
+			RecipientInformation recipient = recipients.GetFirstRecipient(recSel);
+
+			CmsTypedStream recData = recipient.GetContentStream(ReciECKP.Private);
+
+			Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream)));
+
+			ep.Close();
+		}
+
+		[Test]
+		public void TestOriginatorInfo()
+		{
+			CmsEnvelopedDataParser env = new CmsEnvelopedDataParser(CmsSampleMessages.originatorMessage);
+
+			env.GetRecipientInfos();
+
+			Assert.AreEqual(CmsEnvelopedDataGenerator.DesEde3Cbc, env.EncryptionAlgOid);
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/EnvelopedDataTest.cs b/crypto/test/src/cms/test/EnvelopedDataTest.cs
new file mode 100644
index 000000000..be588ef42
--- /dev/null
+++ b/crypto/test/src/cms/test/EnvelopedDataTest.cs
@@ -0,0 +1,866 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class EnvelopedDataTest
+	{
+		private const string SignDN = "O=Bouncy Castle, C=AU";
+
+		private static AsymmetricCipherKeyPair signKP;
+//		private static X509Certificate signCert;
+		//signCert = CmsTestUtil.MakeCertificate(_signKP, SignDN, _signKP, SignDN);
+
+//		private const string OrigDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+
+//		private static AsymmetricCipherKeyPair origKP;
+		//origKP = CmsTestUtil.MakeKeyPair();
+//		private static X509Certificate origCert;
+		//origCert = CmsTestUtil.MakeCertificate(_origKP, OrigDN, _signKP, SignDN);
+
+		private const string ReciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+		private const string ReciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU";
+
+		private static AsymmetricCipherKeyPair reciKP;
+		private static X509Certificate reciCert;
+
+		private static AsymmetricCipherKeyPair origECKP;
+		private static AsymmetricCipherKeyPair reciECKP;
+		private static X509Certificate reciECCert;
+		private static AsymmetricCipherKeyPair reciECKP2;
+		private static X509Certificate reciECCert2;
+
+		private static AsymmetricCipherKeyPair SignKP
+		{
+			get { return signKP == null ? (signKP = CmsTestUtil.MakeKeyPair()) : signKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciKP
+		{
+			get { return reciKP == null ? (reciKP = CmsTestUtil.MakeKeyPair()) : reciKP; }
+		}
+
+		private static X509Certificate ReciCert
+		{
+			get { return reciCert == null ? (reciCert = CmsTestUtil.MakeCertificate(ReciKP, ReciDN, SignKP, SignDN)) : reciCert; }
+		}
+
+		private static AsymmetricCipherKeyPair OrigECKP
+		{
+			get { return origECKP == null ? (origECKP = CmsTestUtil.MakeECDsaKeyPair()) : origECKP; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciECKP
+		{
+			get { return reciECKP == null ? (reciECKP = CmsTestUtil.MakeECDsaKeyPair()) : reciECKP; }
+		}
+
+		private static X509Certificate ReciECCert
+		{
+			get { return reciECCert == null ? (reciECCert = CmsTestUtil.MakeCertificate(ReciECKP, ReciDN, SignKP, SignDN)) : reciECCert; }
+		}
+
+		private static AsymmetricCipherKeyPair ReciECKP2
+		{
+			get { return reciECKP2 == null ? (reciECKP2 = CmsTestUtil.MakeECDsaKeyPair()) : reciECKP2; }
+		}
+
+		private static X509Certificate ReciECCert2
+		{
+			get { return reciECCert2 == null ? (reciECCert2 = CmsTestUtil.MakeCertificate(ReciECKP2, ReciDN2, SignKP, SignDN)) : reciECCert2; }
+		}
+
+		private static readonly byte[] oldKEK = Base64.Decode(
+			"MIAGCSqGSIb3DQEHA6CAMIACAQIxQaI/MD0CAQQwBwQFAQIDBAUwDQYJYIZIAWUDBAEFBQAEI"
+			+ "Fi2eHTPM4bQSjP4DUeDzJZLpfemW2gF1SPq7ZPHJi1mMIAGCSqGSIb3DQEHATAUBggqhkiG9w"
+			+ "0DBwQImtdGyUdGGt6ggAQYk9X9z01YFBkU7IlS3wmsKpm/zpZClTceAAAAAAAAAAAAAA==");
+
+		private static readonly byte[] ecKeyAgreeMsgAES256 = Base64.Decode(
+			"MIAGCSqGSIb3DQEHA6CAMIACAQIxgcShgcECAQOgQ6FBMAsGByqGSM49AgEF"
+			+ "AAMyAAPdXlSTpub+qqno9hUGkUDl+S3/ABhPziIB5yGU4678tgOgU5CiKG9Z"
+			+ "kfnabIJ3nZYwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBLQUAMFswWTAtMCgx"
+			+ "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBCi/"
+			+ "rJRLbFwEVW6PcLLmojjW9lI/xGD7CfZzXrqXFw8iHaf3hTRau1gYMIAGCSqG"
+			+ "SIb3DQEHATAdBglghkgBZQMEASoEEMtCnKKPwccmyrbgeSIlA3qggAQQDLw8"
+			+ "pNJR97bPpj6baG99bQQQwhEDsoj5Xg1oOxojHVcYzAAAAAAAAAAAAAA=");
+
+		private static readonly byte[] ecKeyAgreeMsgAES128 = Base64.Decode(
+			"MIAGCSqGSIb3DQEHA6CAMIACAQIxgbShgbECAQOgQ6FBMAsGByqGSM49AgEF"
+			+ "AAMyAAL01JLEgKvKh5rbxI/hOxs/9WEezMIsAbUaZM4l5tn3CzXAN505nr5d"
+			+ "LhrcurMK+tAwGgYJK4EFEIZIPwACMA0GCWCGSAFlAwQBBQUAMEswSTAtMCgx"
+			+ "EzARBgNVBAMTCkFkbWluLU1EU0UxETAPBgNVBAoTCDRCQ1QtMklEAgEBBBhi"
+			+ "FLjc5g6aqDT3f8LomljOwl1WTrplUT8wgAYJKoZIhvcNAQcBMB0GCWCGSAFl"
+			+ "AwQBAgQQzXjms16Y69S/rB0EbHqRMaCABBAFmc/QdVW6LTKdEy97kaZzBBBa"
+			+ "fQuviUS03NycpojELx0bAAAAAAAAAAAAAA==");
+
+		private static readonly byte[] ecKeyAgreeMsgDESEDE = Base64.Decode(
+			"MIAGCSqGSIb3DQEHA6CAMIACAQIxgcahgcMCAQOgQ6FBMAsGByqGSM49AgEF"
+			+ "AAMyAALIici6Nx1WN5f0ThH2A8ht9ovm0thpC5JK54t73E1RDzCifePaoQo0"
+			+ "xd6sUqoyGaYwHAYJK4EFEIZIPwACMA8GCyqGSIb3DQEJEAMGBQAwWzBZMC0w"
+			+ "KDETMBEGA1UEAxMKQWRtaW4tTURTRTERMA8GA1UEChMINEJDVC0ySUQCAQEE"
+			+ "KJuqZQ1NB1vXrKPOnb4TCpYOsdm6GscWdwAAZlm2EHMp444j0s55J9wwgAYJ"
+			+ "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAjwnsDMsafCrKCABBjyPvqFOVMKxxut"
+			+ "VfTx4fQlNGJN8S2ATRgECMcTQ/dsmeViAAAAAAAAAAAAAA==");
+
+		private static readonly byte[] ecMqvKeyAgreeMsgAes128 = Base64.Decode(
+			  "MIAGCSqGSIb3DQEHA6CAMIACAQIxgf2hgfoCAQOgQ6FBMAsGByqGSM49AgEF"
+			+ "AAMyAAPDKU+0H58tsjpoYmYCInMr/FayvCCkupebgsnpaGEB7qS9vzcNVUj6"
+			+ "mrnmiC2grpmhRwRFMEMwQTALBgcqhkjOPQIBBQADMgACZpD13z9c7DzRWx6S"
+			+ "0xdbq3S+EJ7vWO+YcHVjTD8NcQDcZcWASW899l1PkL936zsuMBoGCSuBBRCG"
+			+ "SD8AEDANBglghkgBZQMEAQUFADBLMEkwLTAoMRMwEQYDVQQDEwpBZG1pbi1N"
+			+ "RFNFMREwDwYDVQQKEwg0QkNULTJJRAIBAQQYFq58L71nyMK/70w3nc6zkkRy"
+			+ "RL7DHmpZMIAGCSqGSIb3DQEHATAdBglghkgBZQMEAQIEEDzRUpreBsZXWHBe"
+			+ "onxOtSmggAQQ7csAZXwT1lHUqoazoy8bhAQQq+9Zjj8iGdOWgyebbfj67QAA"
+			+ "AAAAAAAAAAA=");
+
+		private static readonly byte[] ecKeyAgreeKey = Base64.Decode(
+			"MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8vp7xVTbKSgYVU5Wc"
+			+ "hGkWbzaj+yUFETIWP1Dt7+WSpq3ikSPdl7PpHPqnPVZfoIWhZANiAgSYHTgxf+Dd"
+			+ "Tt84dUvuSKkFy3RhjxJmjwIscK6zbEUzKhcPQG2GHzXhWK5x1kov0I74XpGhVkya"
+			+ "ElH5K6SaOXiXAzcyNGggTOk4+ZFnz5Xl0pBje3zKxPhYu0SnCw7Pcqw=");
+
+		private static readonly byte[] bobPrivRsaEncrypt = Base64.Decode(
+			"MIIChQIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnhZ5g/OdVf"
+			+ "8qCTQV6meYmFyDVdmpFb+x0B2hlwJhcPvaUi0DWFbXqYZhRBXM+3twg7CcmR"
+			+ "uBlpN235ZR572akzJKN/O7uvRgGGNjQyywcDWVL8hYsxBLjMGAgUSOZPHPtd"
+			+ "YMTgXB9T039T2GkB8QX4enDRvoPGXzjPHCyqaqfrAgMBAAECgYBnzUhMmg2P"
+			+ "mMIbZf8ig5xt8KYGHbztpwOIlPIcaw+LNd4Ogngwy+e6alatd8brUXlweQqg"
+			+ "9P5F4Kmy9Bnah5jWMIR05PxZbMHGd9ypkdB8MKCixQheIXFD/A0HPfD6bRSe"
+			+ "TmPwF1h5HEuYHD09sBvf+iU7o8AsmAX2EAnYh9sDGQJBANDDIsbeopkYdo+N"
+			+ "vKZ11mY/1I1FUox29XLE6/BGmvE+XKpVC5va3Wtt+Pw7PAhDk7Vb/s7q/WiE"
+			+ "I2Kv8zHCueUCQQDQUfweIrdb7bWOAcjXq/JY1PeClPNTqBlFy2bKKBlf4hAr"
+			+ "84/sajB0+E0R9KfEILVHIdxJAfkKICnwJAiEYH2PAkA0umTJSChXdNdVUN5q"
+			+ "SO8bKlocSHseIVnDYDubl6nA7xhmqU5iUjiEzuUJiEiUacUgFJlaV/4jbOSn"
+			+ "I3vQgLeFAkEAni+zN5r7CwZdV+EJBqRd2ZCWBgVfJAZAcpw6iIWchw+dYhKI"
+			+ "FmioNRobQ+g4wJhprwMKSDIETukPj3d9NDAlBwJAVxhn1grStavCunrnVNqc"
+			+ "BU+B1O8BiR4yPWnLMcRSyFRVJQA7HCp8JlDV6abXd8vPFfXuC9WN7rOvTKF8"
+			+ "Y0ZB9qANMAsGA1UdDzEEAwIAEA==");
+
+		private static readonly byte[] rfc4134ex5_1 = Base64.Decode(
+			"MIIBHgYJKoZIhvcNAQcDoIIBDzCCAQsCAQAxgcAwgb0CAQAwJjASMRAwDgYD"
+			+ "VQQDEwdDYXJsUlNBAhBGNGvHgABWvBHTbi7NXXHQMA0GCSqGSIb3DQEBAQUA"
+			+ "BIGAC3EN5nGIiJi2lsGPcP2iJ97a4e8kbKQz36zg6Z2i0yx6zYC4mZ7mX7FB"
+			+ "s3IWg+f6KgCLx3M1eCbWx8+MDFbbpXadCDgO8/nUkUNYeNxJtuzubGgzoyEd"
+			+ "8Ch4H/dd9gdzTd+taTEgS0ipdSJuNnkVY4/M652jKKHRLFf02hosdR8wQwYJ"
+			+ "KoZIhvcNAQcBMBQGCCqGSIb3DQMHBAgtaMXpRwZRNYAgDsiSf8Z9P43LrY4O"
+			+ "xUk660cu1lXeCSFOSOpOJ7FuVyU=");
+
+		private static readonly byte[] rfc4134ex5_2 = Base64.Decode(
+			"MIIBZQYJKoZIhvcNAQcDoIIBVjCCAVICAQIxggEAMIG9AgEAMCYwEjEQMA4G"
+			+ "A1UEAxMHQ2FybFJTQQIQRjRrx4AAVrwR024uzV1x0DANBgkqhkiG9w0BAQEF"
+			+ "AASBgJQmQojGi7Z4IP+CVypBmNFoCDoEp87khtgyff2N4SmqD3RxPx+8hbLQ"
+			+ "t9i3YcMwcap+aiOkyqjMalT03VUC0XBOGv+HYI3HBZm/aFzxoq+YOXAWs5xl"
+			+ "GerZwTOc9j6AYlK4qXvnztR5SQ8TBjlzytm4V7zg+TGrnGVNQBNw47Ewoj4C"
+			+ "AQQwDQQLTWFpbExpc3RSQzIwEAYLKoZIhvcNAQkQAwcCAToEGHcUr5MSJ/g9"
+			+ "HnJVHsQ6X56VcwYb+OfojTBJBgkqhkiG9w0BBwEwGgYIKoZIhvcNAwIwDgIC"
+			+ "AKAECJwE0hkuKlWhgCBeKNXhojuej3org9Lt7n+wWxOhnky5V50vSpoYRfRR"
+			+ "yw==");
+
+		[Test]
+		public void TestKeyTrans()
+		{
+			byte[] data = Encoding.ASCII.GetBytes("WallaWallaWashington");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransRC4()
+		{
+			byte[] data = Encoding.ASCII.GetBytes("WallaWallaBouncyCastle");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				"1.2.840.113549.3.4"); // RC4 OID
+
+			RecipientInformationStore  recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid, "1.2.840.113549.3.4");
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTrans128RC4()
+		{
+			byte[] data = Encoding.ASCII.GetBytes("WallaWallaBouncyCastle");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				"1.2.840.113549.3.4", 128);  // RC4 OID
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid, "1.2.840.113549.3.4");
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransOdes()
+		{
+			byte[] data = Encoding.ASCII.GetBytes("WallaWallaBouncyCastle");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				OiwObjectIdentifiers.DesCbc.Id);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid, OiwObjectIdentifiers.DesCbc.Id);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransSmallAes()
+		{
+			byte[] data = new byte[] { 0, 1, 2, 3 };
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid,
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestKeyTransCast5()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.Cast5Cbc,
+				new DerObjectIdentifier(CmsEnvelopedDataGenerator.Cast5Cbc),
+				typeof(Asn1Sequence));
+		}
+
+		[Test]
+		public void TestKeyTransAes128()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.Aes128Cbc,
+				NistObjectIdentifiers.IdAes128Cbc,
+				typeof(DerOctetString));
+		}
+
+		[Test]
+		public void TestKeyTransAes192()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.Aes192Cbc,
+				NistObjectIdentifiers.IdAes192Cbc,
+				typeof(DerOctetString));
+		}
+
+		[Test]
+		public void TestKeyTransAes256()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.Aes256Cbc,
+				NistObjectIdentifiers.IdAes256Cbc,
+				typeof(DerOctetString));
+		}
+
+		[Test]
+		public void TestKeyTransSeed()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.SeedCbc,
+				KisaObjectIdentifiers.IdSeedCbc,
+				typeof(DerOctetString));
+		}
+
+		public void TestKeyTransCamellia128()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.Camellia128Cbc,
+				NttObjectIdentifiers.IdCamellia128Cbc,
+				typeof(DerOctetString));
+		}
+
+		public void TestKeyTransCamellia192()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.Camellia192Cbc,
+				NttObjectIdentifiers.IdCamellia192Cbc,
+				typeof(DerOctetString));
+		}
+
+		public void TestKeyTransCamellia256()
+		{
+			TryKeyTrans(CmsEnvelopedDataGenerator.Camellia256Cbc,
+				NttObjectIdentifiers.IdCamellia256Cbc,
+				typeof(DerOctetString));
+		}
+
+		private void TryKeyTrans(
+			string				generatorOID,
+			DerObjectIdentifier	checkOID,
+			Type				asn1Params)
+		{
+			byte[] data = Encoding.ASCII.GetBytes("WallaWallaWashington");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyTransRecipient(ReciCert);
+
+			CmsEnvelopedData ed = edGen.Generate(new CmsProcessableByteArray(data), generatorOID);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(checkOID.Id, ed.EncryptionAlgOid);
+
+			if (asn1Params != null)
+			{
+				Assert.IsTrue(asn1Params.IsInstanceOfType(ed.EncryptionAlgorithmID.Parameters));
+			}
+
+			ArrayList c = new ArrayList(recipients.GetRecipients());
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+				byte[] recData = recipient.GetContent(ReciKP.Private);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestErroneousKek()
+		{
+			byte[] data = Encoding.ASCII.GetBytes("WallaWallaWashington");
+			KeyParameter kek = ParameterUtilities.CreateKeyParameter(
+				"AES",
+				new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 });
+
+			CmsEnvelopedData ed = new CmsEnvelopedData(oldKEK);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(recipient.KeyEncryptionAlgOid, NistObjectIdentifiers.IdAes128Wrap.Id);
+
+				byte[] recData = recipient.GetContent(kek);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestDesKek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeDesEde192Key(), new DerObjectIdentifier("1.2.840.113549.1.9.16.3.6"));
+		}
+
+		[Test]
+		public void TestRC2128Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeRC2128Key(), new DerObjectIdentifier("1.2.840.113549.1.9.16.3.7"));
+		}
+
+		[Test]
+		public void TestAes128Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeAesKey(128), NistObjectIdentifiers.IdAes128Wrap);
+		}
+
+		[Test]
+		public void TestAes192Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeAesKey(192), NistObjectIdentifiers.IdAes192Wrap);
+		}
+
+		[Test]
+		public void TestAes256Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeAesKey(256), NistObjectIdentifiers.IdAes256Wrap);
+		}
+
+		[Test]
+		public void TestSeed128Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeSeedKey(), KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap);
+		}
+
+		[Test]
+		public void TestCamellia128Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeCamelliaKey(128), NttObjectIdentifiers.IdCamellia128Wrap);
+		}
+
+		[Test]
+		public void TestCamellia192Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeCamelliaKey(192), NttObjectIdentifiers.IdCamellia192Wrap);
+		}
+
+		[Test]
+		public void TestCamellia256Kek()
+		{
+			TryKekAlgorithm(CmsTestUtil.MakeCamelliaKey(256), NttObjectIdentifiers.IdCamellia256Wrap);
+		}
+
+		private void TryKekAlgorithm(
+			KeyParameter		kek,
+			DerObjectIdentifier	algOid)
+		{
+			byte[] data = Encoding.ASCII.GetBytes("WallaWallaWashington");
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			byte[] kekId = new byte[] { 1, 2, 3, 4, 5 };
+
+			string keyAlgorithm = ParameterUtilities.GetCanonicalAlgorithmName(algOid.Id);
+
+			edGen.AddKekRecipient(keyAlgorithm, kek, kekId);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			ArrayList c = new ArrayList(recipients.GetRecipients());
+
+			Assert.IsTrue(c.Count > 0);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual(algOid.Id, recipient.KeyEncryptionAlgOid);
+
+				byte[] recData = recipient.GetContent(kek);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestECKeyAgree()
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyAgreementRecipient(
+				CmsEnvelopedDataGenerator.ECDHSha1Kdf,
+				OrigECKP.Private,
+				OrigECKP.Public,
+				ReciECCert,
+				CmsEnvelopedDataGenerator.Aes128Wrap);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			ConfirmDataReceived(recipients, data, ReciECCert, ReciECKP.Private);
+			ConfirmNumberRecipients(recipients, 1);
+		}
+
+		[Test]
+		public void TestECMqvKeyAgree()
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddKeyAgreementRecipient(
+				CmsEnvelopedDataGenerator.ECMqvSha1Kdf,
+				OrigECKP.Private,
+				OrigECKP.Public,
+				ReciECCert,
+				CmsEnvelopedDataGenerator.Aes128Wrap);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			ConfirmDataReceived(recipients, data, ReciECCert, ReciECKP.Private);
+			ConfirmNumberRecipients(recipients, 1);
+		}
+
+		[Test]
+		public void TestECMqvKeyAgreeMultiple()
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			ArrayList recipientCerts = new ArrayList();
+			recipientCerts.Add(ReciECCert);
+			recipientCerts.Add(ReciECCert2);
+
+			edGen.AddKeyAgreementRecipients(
+				CmsEnvelopedDataGenerator.ECMqvSha1Kdf,
+				OrigECKP.Private,
+				OrigECKP.Public,
+				recipientCerts,
+				CmsEnvelopedDataGenerator.Aes128Wrap);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			ConfirmDataReceived(recipients, data, ReciECCert, ReciECKP.Private);
+			ConfirmDataReceived(recipients, data, ReciECCert2, ReciECKP2.Private);
+			ConfirmNumberRecipients(recipients, 2);
+		}
+
+		private static void ConfirmDataReceived(RecipientInformationStore recipients,
+			byte[] expectedData, X509Certificate reciCert, AsymmetricKeyParameter reciPrivKey)
+		{
+			RecipientID rid = new RecipientID();
+			rid.Issuer = PrincipalUtilities.GetIssuerX509Principal(reciCert);
+			rid.SerialNumber = reciCert.SerialNumber;
+
+			RecipientInformation recipient = recipients[rid];
+			Assert.IsNotNull(recipient);
+
+			byte[] actualData = recipient.GetContent(reciPrivKey);
+			Assert.IsTrue(Arrays.AreEqual(expectedData, actualData));
+		}
+
+		private static void ConfirmNumberRecipients(RecipientInformationStore recipients, int count)
+		{
+			Assert.AreEqual(count, recipients.GetRecipients().Count);
+		}
+
+		[Test]
+		public void TestECKeyAgreeVectors()
+		{
+			AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(ecKeyAgreeKey);
+
+			VerifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.42", ecKeyAgreeMsgAES256);
+			VerifyECKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecKeyAgreeMsgAES128);
+			VerifyECKeyAgreeVectors(privKey, "1.2.840.113549.3.7", ecKeyAgreeMsgDESEDE);
+		}
+
+		[Test]
+		public void TestECMqvKeyAgreeVectors()
+		{
+			AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(ecKeyAgreeKey);
+
+			VerifyECMqvKeyAgreeVectors(privKey, "2.16.840.1.101.3.4.1.2", ecMqvKeyAgreeMsgAes128);
+		}
+
+		[Test]
+		public void TestPasswordAes256()
+		{
+			PasswordTest(CmsEnvelopedDataGenerator.Aes256Cbc);
+			PasswordUtf8Test(CmsEnvelopedDataGenerator.Aes256Cbc);
+		}
+
+		[Test]
+		public void TestPasswordDesEde()
+		{
+			PasswordTest(CmsEnvelopedDataGenerator.DesEde3Cbc);
+			PasswordUtf8Test(CmsEnvelopedDataGenerator.DesEde3Cbc);
+		}
+
+		[Test]
+		public void TestRfc4134Ex5_1()
+		{
+			byte[] data = Hex.Decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+//			KeyFactory kFact = KeyFactory.GetInstance("RSA");
+//			Key key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+			AsymmetricKeyParameter key = PrivateKeyFactory.CreateKey(bobPrivRsaEncrypt);
+
+			CmsEnvelopedData ed = new CmsEnvelopedData(rfc4134ex5_1);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual("1.2.840.113549.3.7", ed.EncryptionAlgOid);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				byte[] recData = recipient.GetContent(key);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		[Test]
+		public void TestRfc4134Ex5_2()
+		{
+			byte[] data = Hex.Decode("5468697320697320736f6d652073616d706c6520636f6e74656e742e");
+
+//			KeyFactory kFact = KeyFactory.GetInstance("RSA");
+//			Key key = kFact.generatePrivate(new PKCS8EncodedKeySpec(bobPrivRsaEncrypt));
+			AsymmetricKeyParameter key = PrivateKeyFactory.CreateKey(bobPrivRsaEncrypt);
+
+			CmsEnvelopedData ed = new CmsEnvelopedData(rfc4134ex5_2);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual("1.2.840.113549.3.2", ed.EncryptionAlgOid);
+
+			ICollection c = recipients.GetRecipients();
+			IEnumerator e = c.GetEnumerator();
+
+			if (e.MoveNext())
+			{
+				do
+				{
+					RecipientInformation recipient = (RecipientInformation) e.Current;
+
+					if (recipient is KeyTransRecipientInformation)
+					{
+						byte[] recData = recipient.GetContent(key);
+
+						Assert.IsTrue(Arrays.AreEqual(data, recData));
+					}
+				}
+				while (e.MoveNext());
+			}
+			else
+			{
+				Assert.Fail("no recipient found");
+			}
+		}
+
+		[Test]
+		public void TestOriginatorInfo()
+		{
+			CmsEnvelopedData env = new CmsEnvelopedData(CmsSampleMessages.originatorMessage);
+
+			RecipientInformationStore  recipients = env.GetRecipientInfos();
+
+			Assert.AreEqual(CmsEnvelopedDataGenerator.DesEde3Cbc, env.EncryptionAlgOid);
+		}
+
+		private void PasswordTest(
+			string algorithm)
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddPasswordRecipient(new Pkcs5Scheme2PbeKey("password".ToCharArray(), new byte[20], 5), algorithm);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (PasswordRecipientInformation recipient in c)
+			{
+				CmsPbeKey key = new Pkcs5Scheme2PbeKey("password".ToCharArray(), recipient.KeyDerivationAlgorithm);
+
+				byte[] recData = recipient.GetContent(key);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		private void PasswordUtf8Test(
+			string algorithm)
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedDataGenerator edGen = new CmsEnvelopedDataGenerator();
+
+			edGen.AddPasswordRecipient(
+				new Pkcs5Scheme2Utf8PbeKey("abc\u5639\u563b".ToCharArray(), new byte[20], 5),
+				algorithm);
+
+			CmsEnvelopedData ed = edGen.Generate(
+				new CmsProcessableByteArray(data),
+				CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(ed.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (PasswordRecipientInformation recipient in c)
+			{
+				CmsPbeKey key = new Pkcs5Scheme2Utf8PbeKey(
+					"abc\u5639\u563b".ToCharArray(), recipient.KeyDerivationAlgorithm);
+
+				byte[] recData = recipient.GetContent(key);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		private void VerifyECKeyAgreeVectors(
+			AsymmetricKeyParameter	privKey,
+			string					wrapAlg,
+			byte[]					message)
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedData ed = new CmsEnvelopedData(message);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			Assert.AreEqual(wrapAlg, ed.EncryptionAlgOid);
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual("1.3.133.16.840.63.0.2", recipient.KeyEncryptionAlgOid);
+
+				byte[] recData = recipient.GetContent(privKey);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+
+		private void VerifyECMqvKeyAgreeVectors(
+			AsymmetricKeyParameter	privKey,
+			string					wrapAlg,
+			byte[]					message)
+		{
+			byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65");
+
+			CmsEnvelopedData ed = new CmsEnvelopedData(message);
+
+			RecipientInformationStore recipients = ed.GetRecipientInfos();
+
+			ICollection c = recipients.GetRecipients();
+
+			Assert.AreEqual(wrapAlg, ed.EncryptionAlgOid);
+			Assert.AreEqual(1, c.Count);
+
+			foreach (RecipientInformation recipient in c)
+			{
+				Assert.AreEqual("1.3.133.16.840.63.0.16", recipient.KeyEncryptionAlgOid);
+
+				byte[] recData = recipient.GetContent(privKey);
+
+				Assert.IsTrue(Arrays.AreEqual(data, recData));
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/MiscDataStreamTest.cs b/crypto/test/src/cms/test/MiscDataStreamTest.cs
new file mode 100644
index 000000000..f958d058f
--- /dev/null
+++ b/crypto/test/src/cms/test/MiscDataStreamTest.cs
@@ -0,0 +1,221 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class MiscDataStreamTest
+	{
+		private const string TestMessage = "Hello World!";
+		private const string SignDN = "O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair signKP;
+		private static X509Certificate signCert;
+
+		private const string OrigDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair origKP;
+		private static X509Certificate origCert;
+
+		private const string ReciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+		//		private static AsymmetricCipherKeyPair reciKP;
+		//		private static X509Certificate reciCert;
+
+		private static AsymmetricCipherKeyPair origDsaKP;
+		private static X509Certificate origDsaCert;
+
+		private static X509Crl signCrl;
+		private static X509Crl origCrl;
+
+		private static AsymmetricCipherKeyPair SignKP
+		{
+			get { return signKP == null ? (signKP = CmsTestUtil.MakeKeyPair()) : signKP; }
+		}
+
+		private static AsymmetricCipherKeyPair OrigKP
+		{
+			get { return origKP == null ? (origKP = CmsTestUtil.MakeKeyPair()) : origKP; }
+		}
+
+		//		private static AsymmetricCipherKeyPair ReciKP
+		//		{
+		//			get { return reciKP == null ? (reciKP = CmsTestUtil.MakeKeyPair()) : reciKP; }
+		//		}
+
+		private static AsymmetricCipherKeyPair OrigDsaKP
+		{
+			get { return origDsaKP == null ? (origDsaKP = CmsTestUtil.MakeDsaKeyPair()) : origDsaKP; }
+		}
+
+		private static X509Certificate SignCert
+		{
+			get { return signCert == null ? (signCert = CmsTestUtil.MakeCertificate(SignKP, SignDN, SignKP, SignDN)) : signCert; }
+		}
+
+		private static X509Certificate OrigCert
+		{
+			get { return origCert == null ? (origCert = CmsTestUtil.MakeCertificate(OrigKP, OrigDN, SignKP, SignDN)) : origCert; }
+		}
+
+		//		private static X509Certificate ReciCert
+		//		{
+		//			get { return reciCert == null ? (reciCert = CmsTestUtil.MakeCertificate(ReciKP, ReciDN, SignKP, SignDN)) : reciCert; }
+		//		}
+
+		private static X509Certificate OrigDsaCert
+		{
+			get { return origDsaCert == null ? (origDsaCert = CmsTestUtil.MakeCertificate(OrigDsaKP, OrigDN, SignKP, SignDN)) : origDsaCert; }
+		}
+
+		private static X509Crl SignCrl
+		{
+			get { return signCrl == null ? (signCrl = CmsTestUtil.MakeCrl(SignKP)) : signCrl; }
+		}
+
+		private static X509Crl OrigCrl
+		{
+			get { return origCrl == null ? (origCrl = CmsTestUtil.MakeCrl(OrigKP)) : origCrl; }
+		}
+
+		private void VerifySignatures(
+			CmsSignedDataParser	sp,
+			byte[]				contentDigest)
+		{
+			IX509Store certStore = sp.GetCertificates("Collection");
+			SignerInformationStore signers = sp.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				ICollection certCollection = certStore.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate	cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+
+				if (contentDigest != null)
+				{
+					Assert.IsTrue(Arrays.AreEqual(contentDigest, signer.GetContentDigest()));
+				}
+			}
+		}
+
+		private void VerifySignatures(
+			CmsSignedDataParser sp)
+		{
+			VerifySignatures(sp, null);
+		}
+
+		private void VerifyEncodedData(
+			MemoryStream bOut)
+		{
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+
+			sp.Close();
+		}
+
+		private void CheckSigParseable(byte[] sig)
+		{
+			CmsSignedDataParser sp = new CmsSignedDataParser(sig);
+			sp.Version.ToString();
+			CmsTypedStream sc = sp.GetSignedContent();
+			if (sc != null)
+			{
+				sc.Drain();
+			}
+			sp.GetAttributeCertificates("Collection");
+			sp.GetCertificates("Collection");
+			sp.GetCrls("Collection");
+			sp.GetSignerInfos();
+			sp.Close();
+		}
+
+		[Test]
+		public void TestSha1WithRsa()
+		{
+			IList certList = new ArrayList();
+			IList crlList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			crlList.Add(SignCrl);
+			crlList.Add(OrigCrl);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+			IX509Store x509Crls = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(crlList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+			gen.AddCrls(x509Crls);
+
+			Stream sigOut = gen.Open(bOut);
+
+			CmsCompressedDataStreamGenerator cGen = new CmsCompressedDataStreamGenerator();
+
+			Stream cOut = cGen.Open(sigOut, CmsCompressedDataStreamGenerator.ZLib);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			cOut.Write(testBytes, 0, testBytes.Length);
+
+			cOut.Close();
+
+			sigOut.Close();
+
+			CheckSigParseable(bOut.ToArray());
+
+			// generate compressed stream
+			MemoryStream cDataOut = new MemoryStream();
+		    
+			cOut = cGen.Open(cDataOut, CmsCompressedDataStreamGenerator.ZLib);
+
+			cOut.Write(testBytes, 0, testBytes.Length);
+
+			cOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(
+				new CmsTypedStream(new MemoryStream(cDataOut.ToArray(), false)), bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			//
+			// compute expected content digest
+			//
+			IDigest md = DigestUtilities.GetDigest("SHA1");
+			byte[] cDataOutBytes = cDataOut.ToArray();
+			md.BlockUpdate(cDataOutBytes, 0, cDataOutBytes.Length);
+			byte[] hash = DigestUtilities.DoFinal(md);
+
+			VerifySignatures(sp, hash);
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/Rfc4134Test.cs b/crypto/test/src/cms/test/Rfc4134Test.cs
new file mode 100644
index 000000000..3bfbd1358
--- /dev/null
+++ b/crypto/test/src/cms/test/Rfc4134Test.cs
@@ -0,0 +1,344 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class Rfc4134Test
+	{
+		private static readonly byte[] exContent = GetRfc4134Data("ExContent.bin");
+		private static readonly byte[] sha1 = Hex.Decode("406aec085279ba6e16022d9e0629c0229687dd48");
+
+		[Test]
+		public void Test4_1()
+		{
+			byte[] data = GetRfc4134Data("4.1.bin");
+			CmsSignedData signedData = new CmsSignedData(data);
+
+			VerifySignatures(signedData);
+
+			CmsSignedDataParser parser = new CmsSignedDataParser(data);
+
+			VerifySignatures(parser);
+		}
+
+		[Test]
+		public void Test4_2()
+		{
+			byte[] data = GetRfc4134Data("4.2.bin");
+			CmsSignedData signedData = new CmsSignedData(data);
+
+			VerifySignatures(signedData);
+
+			CmsSignedDataParser parser = new CmsSignedDataParser(data);
+
+			VerifySignatures(parser);
+		}
+
+		[Test]
+		public void Test4_3()
+		{
+			CmsProcessableByteArray unencap = new CmsProcessableByteArray(exContent);
+			byte[] data = GetRfc4134Data("4.3.bin");
+			CmsSignedData signedData = new CmsSignedData(unencap, data);
+
+			VerifySignatures(signedData, sha1);
+
+			CmsSignedDataParser parser = new CmsSignedDataParser(
+				new CmsTypedStream(unencap.GetInputStream()), data);
+
+			VerifySignatures(parser);
+		}
+
+		[Test]
+		public void Test4_4()
+		{
+			byte[] data = GetRfc4134Data("4.4.bin");
+			byte[] counterSigCert = GetRfc4134Data("AliceRSASignByCarl.cer");
+			CmsSignedData signedData = new CmsSignedData(data);
+
+			VerifySignatures(signedData, sha1);
+
+			VerifySignerInfo4_4(GetFirstSignerInfo(signedData.GetSignerInfos()), counterSigCert);
+
+			CmsSignedDataParser parser = new CmsSignedDataParser(data);
+
+			VerifySignatures(parser);
+
+			VerifySignerInfo4_4(GetFirstSignerInfo(parser.GetSignerInfos()), counterSigCert);
+		}
+
+		[Test]
+		public void Test4_5()
+		{
+			byte[] data = GetRfc4134Data("4.5.bin");
+			CmsSignedData signedData = new CmsSignedData(data);
+
+			VerifySignatures(signedData);
+
+			CmsSignedDataParser parser = new CmsSignedDataParser(data);
+
+			VerifySignatures(parser);
+		}
+
+		[Test]
+		public void Test4_6()
+		{
+			byte[] data = GetRfc4134Data("4.6.bin");
+			CmsSignedData signedData = new CmsSignedData(data);
+
+			VerifySignatures(signedData);
+
+			CmsSignedDataParser parser = new CmsSignedDataParser(data);
+
+			VerifySignatures(parser);
+		}
+		
+		[Test]
+		public void Test4_7()
+		{
+			byte[] data = GetRfc4134Data("4.7.bin");
+			CmsSignedData signedData = new CmsSignedData(data);
+
+			VerifySignatures(signedData);
+
+			CmsSignedDataParser parser = new CmsSignedDataParser(data);
+
+			VerifySignatures(parser);
+		}
+
+		[Test]
+		public void Test5_1()
+		{
+			byte[] data = GetRfc4134Data("5.1.bin");
+			CmsEnvelopedData envelopedData = new CmsEnvelopedData(data);
+
+			VerifyEnvelopedData(envelopedData, CmsEnvelopedDataGenerator.DesEde3Cbc);
+
+			CmsEnvelopedDataParser envelopedParser = new CmsEnvelopedDataParser(data);
+
+			VerifyEnvelopedData(envelopedParser, CmsEnvelopedDataGenerator.DesEde3Cbc);
+		}
+
+		[Test]
+		public void Test5_2()
+		{
+			byte[] data = GetRfc4134Data("5.2.bin");
+			CmsEnvelopedData envelopedData = new CmsEnvelopedData(data);
+
+			VerifyEnvelopedData(envelopedData, CmsEnvelopedDataGenerator.RC2Cbc);
+
+			CmsEnvelopedDataParser envelopedParser = new CmsEnvelopedDataParser(data);
+
+			VerifyEnvelopedData(envelopedParser, CmsEnvelopedDataGenerator.RC2Cbc);
+		}
+
+		private void VerifyEnvelopedData(CmsEnvelopedData envelopedData, string symAlgorithmOID)
+		{
+			byte[] privKeyData = GetRfc4134Data("BobPrivRSAEncrypt.pri");
+			AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyData);
+			Assert.IsTrue(privKey.IsPrivate);
+			Assert.IsTrue(privKey is RsaKeyParameters);
+
+			RecipientInformationStore recipients = envelopedData.GetRecipientInfos();
+
+			Assert.AreEqual(envelopedData.EncryptionAlgOid, symAlgorithmOID);
+
+			ArrayList c = new ArrayList(recipients.GetRecipients());
+			Assert.LessOrEqual(1, c.Count);
+			Assert.GreaterOrEqual(2, c.Count);
+
+			VerifyRecipient((RecipientInformation)c[0], privKey);
+
+			if (c.Count == 2)
+			{
+				RecipientInformation recInfo = (RecipientInformation)c[1];
+
+				Assert.AreEqual(PkcsObjectIdentifiers.IdAlgCmsRC2Wrap.Id, recInfo.KeyEncryptionAlgOid);
+			}
+		}
+
+		private void VerifyEnvelopedData(CmsEnvelopedDataParser envelopedParser, string symAlgorithmOID)
+		{
+			byte[] privKeyData = GetRfc4134Data("BobPrivRSAEncrypt.pri");
+			AsymmetricKeyParameter privKey = PrivateKeyFactory.CreateKey(privKeyData);
+			Assert.IsTrue(privKey.IsPrivate);
+			Assert.IsTrue(privKey is RsaKeyParameters);
+
+			RecipientInformationStore recipients = envelopedParser.GetRecipientInfos();
+
+			Assert.AreEqual(envelopedParser.EncryptionAlgOid, symAlgorithmOID);
+
+			ArrayList c = new ArrayList(recipients.GetRecipients());
+			Assert.LessOrEqual(1, c.Count);
+			Assert.GreaterOrEqual(2, c.Count);
+
+			VerifyRecipient((RecipientInformation)c[0], privKey);
+
+			if (c.Count == 2)
+			{
+				RecipientInformation recInfo = (RecipientInformation)c[1];
+
+				Assert.AreEqual(PkcsObjectIdentifiers.IdAlgCmsRC2Wrap.Id, recInfo.KeyEncryptionAlgOid);
+			}
+		}
+
+		private void VerifyRecipient(RecipientInformation recipient, AsymmetricKeyParameter privKey)
+		{
+			Assert.IsTrue(privKey.IsPrivate);
+
+			Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id);
+
+			byte[] recData = recipient.GetContent(privKey);
+
+			Assert.IsTrue(Arrays.AreEqual(exContent, recData));
+		}
+
+		private void VerifySignerInfo4_4(SignerInformation signerInfo, byte[] counterSigCert)
+		{
+			VerifyCounterSignature(signerInfo, counterSigCert);
+
+			VerifyContentHint(signerInfo);
+		}
+
+		private SignerInformation GetFirstSignerInfo(SignerInformationStore store)
+		{
+			IEnumerator e = store.GetSigners().GetEnumerator();
+			e.MoveNext();
+			return (SignerInformation)e.Current;
+		}
+
+		private void VerifyCounterSignature(SignerInformation signInfo, byte[] certificate)
+		{
+			SignerInformation csi = GetFirstSignerInfo(signInfo.GetCounterSignatures());
+
+			X509Certificate cert = new X509CertificateParser().ReadCertificate(certificate);
+
+			Assert.IsTrue(csi.Verify(cert));
+		}
+
+		private void VerifyContentHint(SignerInformation signInfo)
+		{
+			Asn1.Cms.AttributeTable attrTable = signInfo.UnsignedAttributes;
+
+			Asn1.Cms.Attribute attr = attrTable[CmsAttributes.ContentHint];
+
+			Assert.AreEqual(1, attr.AttrValues.Count);
+		
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerUtf8String("Content Hints Description Buffer"),
+				CmsObjectIdentifiers.Data);
+
+			Assert.IsTrue(attr.AttrValues[0].Equals(new DerSequence(v)));
+		}
+
+		private void VerifySignatures(CmsSignedData s, byte[] contentDigest)
+		{
+			IX509Store x509Certs = s.GetCertificates("Collection");
+			IX509Store x509Crls = s.GetCrls("Collection");
+			SignerInformationStore signers = s.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				VerifySigner(signer, cert);
+
+				if (contentDigest != null)
+				{
+					Assert.IsTrue(Arrays.AreEqual(contentDigest, signer.GetContentDigest()));
+				}
+			}
+
+			ICollection certColl = x509Certs.GetMatches(null);
+			ICollection crlColl = x509Crls.GetMatches(null);
+
+			Assert.AreEqual(certColl.Count, s.GetCertificates("Collection").GetMatches(null).Count);
+			Assert.AreEqual(crlColl.Count, s.GetCrls("Collection").GetMatches(null).Count);
+		}
+
+		private void VerifySignatures(CmsSignedData s)
+		{
+			VerifySignatures(s, null);
+		}
+
+		private void VerifySignatures(CmsSignedDataParser sp)
+		{
+	        CmsTypedStream sc = sp.GetSignedContent();
+	        if (sc != null)
+	        {
+	            sc.Drain();
+	        }
+			
+			IX509Store x509Certs = sp.GetCertificates("Collection");
+			SignerInformationStore signers = sp.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate)certEnum.Current;
+
+				VerifySigner(signer, cert);
+			}
+		}
+
+		private void VerifySigner(SignerInformation signer, X509Certificate cert)
+		{
+			if (cert.GetPublicKey() is DsaPublicKeyParameters)
+			{
+				DsaPublicKeyParameters key = (DsaPublicKeyParameters)cert.GetPublicKey();
+
+				if (key.Parameters == null)
+				{
+					Assert.IsTrue(signer.Verify(GetInheritedKey(key)));
+				}
+				else
+				{
+					Assert.IsTrue(signer.Verify(cert));
+				}
+			}
+			else
+			{
+				Assert.IsTrue(signer.Verify(cert));
+			}
+		}
+
+		private DsaPublicKeyParameters GetInheritedKey(DsaPublicKeyParameters dsaPubKey)
+		{
+			X509Certificate cert = new X509CertificateParser().ReadCertificate(
+				GetRfc4134Data("CarlDSSSelf.cer"));
+
+			DsaParameters dsaParams = ((DsaPublicKeyParameters)cert.GetPublicKey()).Parameters;
+
+			return new DsaPublicKeyParameters(dsaPubKey.Y, dsaParams);
+		}
+
+		private static byte[] GetRfc4134Data(string name)
+		{
+			return Streams.ReadAll(SimpleTest.GetTestDataAsStream("rfc4134." + name));
+		}
+	}
+}
diff --git a/crypto/test/src/cms/test/SignedDataStreamTest.cs b/crypto/test/src/cms/test/SignedDataStreamTest.cs
new file mode 100644
index 000000000..96f3f125d
--- /dev/null
+++ b/crypto/test/src/cms/test/SignedDataStreamTest.cs
@@ -0,0 +1,1235 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class SignedDataStreamTest
+	{
+		private const string TestMessage = "Hello World!";
+		private const string SignDN = "O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair signKP;
+		private static X509Certificate signCert;
+
+		private const string OrigDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair origKP;
+		private static X509Certificate origCert;
+
+		private const string ReciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+//		private static AsymmetricCipherKeyPair reciKP;
+//		private static X509Certificate reciCert;
+
+		private static AsymmetricCipherKeyPair origDsaKP;
+		private static X509Certificate origDsaCert;
+
+		private static X509Crl signCrl;
+		private static X509Crl origCrl;
+
+		private static AsymmetricCipherKeyPair SignKP
+		{
+			get { return signKP == null ? (signKP = CmsTestUtil.MakeKeyPair()) : signKP; }
+		}
+
+		private static AsymmetricCipherKeyPair OrigKP
+		{
+			get { return origKP == null ? (origKP = CmsTestUtil.MakeKeyPair()) : origKP; }
+		}
+
+//		private static AsymmetricCipherKeyPair ReciKP
+//		{
+//			get { return reciKP == null ? (reciKP = CmsTestUtil.MakeKeyPair()) : reciKP; }
+//		}
+
+		private static AsymmetricCipherKeyPair OrigDsaKP
+		{
+			get { return origDsaKP == null ? (origDsaKP = CmsTestUtil.MakeDsaKeyPair()) : origDsaKP; }
+		}
+
+		private static X509Certificate SignCert
+		{
+			get { return signCert == null ? (signCert = CmsTestUtil.MakeCertificate(SignKP, SignDN, SignKP, SignDN)) : signCert; }
+		}
+
+		private static X509Certificate OrigCert
+		{
+			get { return origCert == null ? (origCert = CmsTestUtil.MakeCertificate(OrigKP, OrigDN, SignKP, SignDN)) : origCert; }
+		}
+
+//		private static X509Certificate ReciCert
+//		{
+//			get { return reciCert == null ? (reciCert = CmsTestUtil.MakeCertificate(ReciKP, ReciDN, SignKP, SignDN)) : reciCert; }
+//		}
+
+		private static X509Certificate OrigDsaCert
+		{
+			get { return origDsaCert == null ? (origDsaCert = CmsTestUtil.MakeCertificate(OrigDsaKP, OrigDN, SignKP, SignDN)) : origDsaCert; }
+		}
+
+		private static X509Crl SignCrl
+		{
+			get { return signCrl == null ? (signCrl = CmsTestUtil.MakeCrl(SignKP)) : signCrl; }
+		}
+
+		private static X509Crl OrigCrl
+		{
+			get { return origCrl == null ? (origCrl = CmsTestUtil.MakeCrl(OrigKP)) : origCrl; }
+		}
+
+		private void VerifySignatures(
+			CmsSignedDataParser	sp,
+			byte[]				contentDigest)
+		{
+			IX509Store certStore = sp.GetCertificates("Collection");
+			SignerInformationStore signers = sp.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				ICollection certCollection = certStore.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate	cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+
+				if (contentDigest != null)
+				{
+					Assert.IsTrue(Arrays.AreEqual(contentDigest, signer.GetContentDigest()));
+				}
+			}
+		}
+
+		private void VerifySignatures(
+			CmsSignedDataParser sp)
+		{
+			VerifySignatures(sp, null);
+		}
+
+		private void VerifyEncodedData(
+			MemoryStream bOut)
+		{
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+
+			sp.Close();
+		}
+
+	    private void CheckSigParseable(byte[] sig)
+	    {
+	        CmsSignedDataParser sp = new CmsSignedDataParser(sig);
+	        sp.Version.ToString();
+	        CmsTypedStream sc = sp.GetSignedContent();
+	        if (sc != null)
+	        {
+	            sc.Drain();
+	        }
+	        sp.GetAttributeCertificates("Collection");
+	        sp.GetCertificates("Collection");
+	        sp.GetCrls("Collection");
+	        sp.GetSignerInfos();
+	        sp.Close();
+	    }
+
+		[Test]
+		public void TestEarlyInvalidKeyException()
+		{
+			try
+			{
+				CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+				gen.AddSigner(OrigKP.Private, OrigCert,
+					"DSA", // DOESN'T MATCH KEY ALG
+					CmsSignedDataStreamGenerator.DigestSha1);
+
+				Assert.Fail("Expected InvalidKeyException in AddSigner");
+			}
+			catch (InvalidKeyException)
+			{
+				// Ignore
+			}
+		}
+
+		[Test]
+		public void TestEarlyNoSuchAlgorithmException()
+		{
+			try
+			{
+				CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+				gen.AddSigner(OrigKP.Private, OrigCert,
+					CmsSignedDataStreamGenerator.DigestSha1, // BAD OID!
+					CmsSignedDataStreamGenerator.DigestSha1);
+
+				Assert.Fail("Expected NoSuchAlgorithmException in AddSigner");
+			}
+			catch (SecurityUtilityException)
+			{
+				// Ignore
+			}
+		}
+
+		[Test]
+		public void TestSha1EncapsulatedSignature()
+		{
+			byte[]  encapSigData = Base64.Decode(
+				"MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEH"
+				+ "AaCAJIAEDEhlbGxvIFdvcmxkIQAAAAAAAKCCBGIwggINMIIBdqADAgECAgEF"
+				+ "MA0GCSqGSIb3DQEBBAUAMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJ"
+				+ "BgNVBAYTAkFVMB4XDTA1MDgwNzA2MjU1OVoXDTA1MTExNTA2MjU1OVowJTEW"
+				+ "MBQGA1UEChMNQm91bmN5IENhc3RsZTELMAkGA1UEBhMCQVUwgZ8wDQYJKoZI"
+				+ "hvcNAQEBBQADgY0AMIGJAoGBAI1fZGgH9wgC3QiK6yluH6DlLDkXkxYYL+Qf"
+				+ "nVRszJVYl0LIxZdpb7WEbVpO8fwtEgFtoDsOdxyqh3dTBv+L7NVD/v46kdPt"
+				+ "xVkSNHRbutJVY8Xn4/TC/CDngqtbpbniMO8n0GiB6vs94gBT20M34j96O2IF"
+				+ "73feNHP+x8PkJ+dNAgMBAAGjTTBLMB0GA1UdDgQWBBQ3XUfEE6+D+t+LIJgK"
+				+ "ESSUE58eyzAfBgNVHSMEGDAWgBQ3XUfEE6+D+t+LIJgKESSUE58eyzAJBgNV"
+				+ "HRMEAjAAMA0GCSqGSIb3DQEBBAUAA4GBAFK3r1stYOeXYJOlOyNGDTWEhZ+a"
+				+ "OYdFeFaS6c+InjotHuFLAy+QsS8PslE48zYNFEqYygGfLhZDLlSnJ/LAUTqF"
+				+ "01vlp+Bgn/JYiJazwi5WiiOTf7Th6eNjHFKXS3hfSGPNPIOjvicAp3ce3ehs"
+				+ "uK0MxgLAaxievzhFfJcGSUMDMIICTTCCAbagAwIBAgIBBzANBgkqhkiG9w0B"
+				+ "AQQFADAlMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVTAe"
+				+ "Fw0wNTA4MDcwNjI1NTlaFw0wNTExMTUwNjI1NTlaMGUxGDAWBgNVBAMTD0Vy"
+				+ "aWMgSC4gRWNoaWRuYTEkMCIGCSqGSIb3DQEJARYVZXJpY0Bib3VuY3ljYXN0"
+				+ "bGUub3JnMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVTCB"
+				+ "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAgHCJyfwV6/V3kqSu2SOU2E/K"
+				+ "I+N0XohCMUaxPLLNtNBZ3ijxwaV6JGFz7siTgZD/OGfzir/eZimkt+L1iXQn"
+				+ "OAB+ZChivKvHtX+dFFC7Vq+E4Uy0Ftqc/wrGxE6DHb5BR0hprKH8wlDS8wSP"
+				+ "zxovgk4nH0ffUZOoDSuUgjh3gG8CAwEAAaNNMEswHQYDVR0OBBYEFLfY/4EG"
+				+ "mYrvJa7Cky+K9BJ7YmERMB8GA1UdIwQYMBaAFDddR8QTr4P634sgmAoRJJQT"
+				+ "nx7LMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEEBQADgYEADIOmpMd6UHdMjkyc"
+				+ "mIE1yiwfClCsGhCK9FigTg6U1G2FmkBwJIMWBlkeH15uvepsAncsgK+Cn3Zr"
+				+ "dZMb022mwtTJDtcaOM+SNeuCnjdowZ4i71Hf68siPm6sMlZkhz49rA0Yidoo"
+				+ "WuzYOO+dggzwDsMldSsvsDo/ARyCGOulDOAxggEvMIIBKwIBATAqMCUxFjAU"
+				+ "BgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNVBAYTAkFVAgEHMAkGBSsOAwIa"
+				+ "BQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEP"
+				+ "Fw0wNTA4MDcwNjI1NTlaMCMGCSqGSIb3DQEJBDEWBBQu973mCM5UBOl9XwQv"
+				+ "lfifHCMocTANBgkqhkiG9w0BAQEFAASBgGxnBl2qozYKLgZ0ygqSFgWcRGl1"
+				+ "LgNuE587LtO+EKkgoc3aFqEdjXlAyP8K7naRsvWnFrsB6pUpnrgI9Z8ZSKv8"
+				+ "98IlpsSSJ0jBlEb4gzzavwcBpYbr2ryOtDcF+kYmKIpScglyyoLzm+KPXOoT"
+				+ "n7MsJMoKN3Kd2Vzh6s10PFgeAAAAAAAA");
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(encapSigData);
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+		}
+
+//		[Test]
+//		public void TestSha1WithRsaNoAttributes()
+//		{
+//			IList certList = new ArrayList();
+//			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes(TestMessage));
+//
+//			certList.Add(OrigCert);
+//			certList.Add(SignCert);
+//
+//			IX509Store x509Certs = X509StoreFactory.Create(
+//				"Certificate/Collection",
+//				new X509CollectionStoreParameters(certList));
+//
+//			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+//
+//			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+//
+//			gen.AddCertificates(x509Certs);
+//
+//			CmsSignedData s = gen.Generate(CmsSignedDataGenerator.Data, msg, false, false);
+//
+//			CmsSignedDataParser sp = new CmsSignedDataParser(
+//				new CmsTypedStream(new MemoryStream(Encoding.ASCII.GetBytes(TestMessage), false)), s.GetEncoded());
+//
+//			sp.GetSignedContent().Drain();
+//
+//			//
+//			// compute expected content digest
+//			//
+//			IDigest md = DigestUtilities.GetDigest("SHA1");
+//
+//			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+//			md.BlockUpdate(testBytes, 0, testBytes.Length);
+//			byte[] hash = DigestUtilities.DoFinal(md);
+//
+//			VerifySignatures(sp, hash);
+//		}
+
+//		[Test]
+//		public void TestDsaNoAttributes()
+//		{
+//			IList certList = new ArrayList();
+//			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes(TestMessage));
+//
+//			certList.Add(OrigDsaCert);
+//			certList.Add(SignCert);
+//
+//			IX509Store x509Certs = X509StoreFactory.Create(
+//				"Certificate/Collection",
+//				new X509CollectionStoreParameters(certList));
+//
+//			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+//
+//			gen.AddSigner(OrigDsaKP.Private, OrigDsaCert, CmsSignedDataGenerator.DigestSha1);
+//
+//			gen.AddCertificates(x509Certs);
+//
+//			CmsSignedData s = gen.Generate(CmsSignedDataGenerator.Data, msg, false, false);
+//
+//			CmsSignedDataParser sp = new CmsSignedDataParser(
+//				new CmsTypedStream(
+//				new MemoryStream(Encoding.ASCII.GetBytes(TestMessage), false)),
+//				s.GetEncoded());
+//
+//			sp.GetSignedContent().Drain();
+//
+//			//
+//			// compute expected content digest
+//			//
+//			IDigest md = DigestUtilities.GetDigest("SHA1");
+//
+//			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+//			md.BlockUpdate(testBytes, 0, testBytes.Length);
+//			byte[] hash = DigestUtilities.DoFinal(md);
+//
+//			VerifySignatures(sp, hash);
+//		}
+
+		[Test]
+		public void TestSha1WithRsa()
+		{
+			IList certList = new ArrayList();
+			IList crlList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			crlList.Add(SignCrl);
+			crlList.Add(OrigCrl);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+			IX509Store x509Crls = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(crlList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+			gen.AddCrls(x509Crls);
+
+			Stream sigOut = gen.Open(bOut);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CheckSigParseable(bOut.ToArray());
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(
+				new CmsTypedStream(new MemoryStream(testBytes, false)), bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			//
+			// compute expected content digest
+			//
+			IDigest md = DigestUtilities.GetDigest("SHA1");
+			md.BlockUpdate(testBytes, 0, testBytes.Length);
+			byte[] hash = DigestUtilities.DoFinal(md);
+
+			VerifySignatures(sp, hash);
+
+			//
+			// try using existing signer
+			//
+			gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigners(sp.GetSignerInfos());
+
+			gen.AddCertificates(sp.GetCertificates("Collection"));
+			gen.AddCrls(sp.GetCrls("Collection"));
+
+			bOut.SetLength(0);
+
+			sigOut = gen.Open(bOut, true);
+
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			VerifyEncodedData(bOut);
+
+			//
+			// look for the CRLs
+			//
+			ArrayList col = new ArrayList(x509Crls.GetMatches(null));
+
+			Assert.AreEqual(2, col.Count);
+			Assert.IsTrue(col.Contains(SignCrl));
+			Assert.IsTrue(col.Contains(OrigCrl));
+		}
+
+		[Test]
+		public void TestSha1WithRsaNonData()
+		{
+			IList certList = new ArrayList();
+			IList crlList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			crlList.Add(SignCrl);
+			crlList.Add(OrigCrl);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+			IX509Store x509Crls = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(crlList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+			gen.AddCrls(x509Crls);
+
+			Stream sigOut = gen.Open(bOut, "1.2.3.4", true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			CmsTypedStream stream = sp.GetSignedContent();
+
+			Assert.AreEqual("1.2.3.4", stream.ContentType);
+
+			stream.Drain();
+
+			//
+			// compute expected content digest
+			//
+			IDigest md = DigestUtilities.GetDigest("SHA1");
+			md.BlockUpdate(testBytes, 0, testBytes.Length);
+			byte[] hash = DigestUtilities.DoFinal(md);
+
+			VerifySignatures(sp, hash);
+		}
+
+		[Test]
+		public void TestSha1AndMD5WithRsa()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddDigests(CmsSignedDataStreamGenerator.DigestSha1,
+				CmsSignedDataStreamGenerator.DigestMD5);
+
+			Stream sigOut = gen.Open(bOut);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			gen.AddCertificates(x509Certs);
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestMD5);
+
+			sigOut.Close();
+
+			CheckSigParseable(bOut.ToArray());
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(
+				new CmsTypedStream(new MemoryStream(testBytes, false)), bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+		}
+
+		[Test]
+		public void TestSha1WithRsaEncapsulatedBufferedStream()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			//
+			// find unbuffered length
+			//
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			for (int i = 0; i != 2000; i++)
+			{
+				sigOut.WriteByte((byte)(i & 0xff));
+			}
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+
+			int unbufferedLength = bOut.ToArray().Length;
+
+			//
+			// find buffered length with buffered stream - should be equal
+			//
+			bOut.SetLength(0);
+
+			gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			sigOut = gen.Open(bOut, true);
+
+			byte[] data = new byte[2000];
+			for (int i = 0; i != 2000; i++)
+			{
+				data[i] = (byte)(i & 0xff);
+			}
+
+			Streams.PipeAll(new MemoryStream(data, false), sigOut);
+			sigOut.Close();
+
+			VerifyEncodedData(bOut);
+
+			Assert.AreEqual(unbufferedLength, bOut.ToArray().Length);
+		}
+
+		[Test]
+		public void TestSha1WithRsaEncapsulatedBuffered()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			//
+			// find unbuffered length
+			//
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			for (int i = 0; i != 2000; i++)
+			{
+				sigOut.WriteByte((byte)(i & 0xff));
+			}
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+
+			int unbufferedLength = bOut.ToArray().Length;
+
+			//
+			// find buffered length - buffer size less than default
+			//
+			bOut.SetLength(0);
+
+			gen = new CmsSignedDataStreamGenerator();
+
+			gen.SetBufferSize(300);
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			sigOut = gen.Open(bOut, true);
+
+			for (int i = 0; i != 2000; i++)
+			{
+				sigOut.WriteByte((byte)(i & 0xff));
+			}
+
+			sigOut.Close();
+
+			VerifyEncodedData(bOut);
+
+			Assert.IsTrue(unbufferedLength < bOut.ToArray().Length);
+		}
+
+		[Test]
+		public void TestSha1WithRsaEncapsulated()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+
+			byte[] contentDigest = (byte[])gen.GetGeneratedDigests()[CmsSignedGenerator.DigestSha1];
+
+			ArrayList signers = new ArrayList(sp.GetSignerInfos().GetSigners());
+
+			AttributeTable table = ((SignerInformation) signers[0]).SignedAttributes;
+			Asn1.Cms.Attribute hash = table[CmsAttributes.MessageDigest];
+
+			Assert.IsTrue(Arrays.AreEqual(contentDigest, ((Asn1OctetString)hash.AttrValues[0]).GetOctets()));
+
+			//
+			// try using existing signer
+			//
+			gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigners(sp.GetSignerInfos());
+
+			gen.AddCertificates(sp.GetCertificates("Collection"));
+			gen.AddCrls(sp.GetCrls("Collection"));
+
+			bOut.SetLength(0);
+
+			sigOut = gen.Open(bOut, true);
+
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedData sd = new CmsSignedData(
+				new CmsProcessableByteArray(testBytes), bOut.ToArray());
+
+			Assert.AreEqual(1, sd.GetSignerInfos().GetSigners().Count);
+
+			VerifyEncodedData(bOut);
+		}
+
+		private static readonly DerObjectIdentifier dummyOid1 = new DerObjectIdentifier("1.2.3");
+		private static readonly DerObjectIdentifier dummyOid2 = new DerObjectIdentifier("1.2.3.4");
+
+		private class SignedGenAttributeTableGenerator
+			: DefaultSignedAttributeTableGenerator
+		{
+			public override AttributeTable GetAttributes(
+				IDictionary parameters)
+			{
+				IDictionary table = createStandardAttributeTable(parameters);
+
+				DerOctetString val = new DerOctetString((byte[])parameters[CmsAttributeTableParameter.Digest]);
+				Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(dummyOid1, new DerSet(val));
+
+				table[attr.AttrType] = attr;
+
+				return new AttributeTable(table);
+			}
+		};
+
+		private class UnsignedGenAttributeTableGenerator
+			: CmsAttributeTableGenerator
+		{
+			public AttributeTable GetAttributes(
+				IDictionary parameters)
+			{
+				DerOctetString val = new DerOctetString((byte[])parameters[CmsAttributeTableParameter.Signature]);
+				Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(dummyOid2, new DerSet(val));
+
+				return new AttributeTable(new DerSet(attr));
+			}
+		};
+
+		[Test]
+	    public void TestSha1WithRsaEncapsulatedSubjectKeyID()
+	    {
+	        IList certList = new ArrayList();
+	        MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+	        gen.AddSigner(OrigKP.Private,
+				CmsTestUtil.CreateSubjectKeyId(OrigCert.GetPublicKey()).GetKeyIdentifier(),
+				CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+
+			byte[] contentDigest = (byte[])gen.GetGeneratedDigests()[CmsSignedGenerator.DigestSha1];
+
+			ArrayList signers = new ArrayList(sp.GetSignerInfos().GetSigners());
+
+			AttributeTable table = ((SignerInformation) signers[0]).SignedAttributes;
+			Asn1.Cms.Attribute hash = table[CmsAttributes.MessageDigest];
+
+			Assert.IsTrue(Arrays.AreEqual(contentDigest, ((Asn1OctetString)hash.AttrValues[0]).GetOctets()));
+
+			//
+			// try using existing signer
+			//
+			gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigners(sp.GetSignerInfos());
+
+//			gen.AddCertificatesAndCRLs(sp.getCertificatesAndCRLs("Collection", "BC"));
+			gen.AddCertificates(sp.GetCertificates("Collection"));
+
+			bOut.SetLength(0);
+
+			sigOut = gen.Open(bOut, true);
+
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedData sd = new CmsSignedData(new CmsProcessableByteArray(testBytes), bOut.ToArray());
+
+			Assert.AreEqual(1, sd.GetSignerInfos().GetSigners().Count);
+
+	        VerifyEncodedData(bOut);
+	    }
+
+		[Test]
+		public void TestAttributeGenerators()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			CmsAttributeTableGenerator signedGen = new SignedGenAttributeTableGenerator();
+			CmsAttributeTableGenerator unsignedGen = new UnsignedGenAttributeTableGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert,
+				CmsSignedDataStreamGenerator.DigestSha1, signedGen, unsignedGen);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+
+			//
+			// check attributes
+			//
+			SignerInformationStore signers = sp.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				checkAttribute(signer.GetContentDigest(), signer.SignedAttributes[dummyOid1]);
+				checkAttribute(signer.GetSignature(), signer.UnsignedAttributes[dummyOid2]);
+			}
+		}
+
+		private void checkAttribute(
+			byte[]				expected,
+			Asn1.Cms.Attribute	attr)
+		{
+			DerOctetString value = (DerOctetString)attr.AttrValues[0];
+
+			Assert.AreEqual(new DerOctetString(expected), value);
+		}
+
+		[Test]
+		public void TestWithAttributeCertificate()
+		{
+			IList certList = new ArrayList();
+
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			IX509AttributeCertificate attrCert = CmsTestUtil.GetAttributeCertificate();
+
+			ArrayList attrCerts = new ArrayList();
+			attrCerts.Add(attrCert);
+			IX509Store store = X509StoreFactory.Create(
+				"AttributeCertificate/Collection",
+				new X509CollectionStoreParameters(attrCerts));
+
+			gen.AddAttributeCertificates(store);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			Assert.AreEqual(4, sp.Version);
+
+			store = sp.GetAttributeCertificates("Collection");
+
+			ArrayList coll = new ArrayList(store.GetMatches(null));
+
+			Assert.AreEqual(1, coll.Count);
+
+			Assert.IsTrue(coll.Contains(attrCert));
+		}
+
+		[Test]
+		public void TestSignerStoreReplacement()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+			byte[] data = Encoding.ASCII.GetBytes(TestMessage);
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, false);
+
+			sigOut.Write(data, 0, data.Length);
+
+			sigOut.Close();
+
+			CheckSigParseable(bOut.ToArray());
+
+			//
+			// create new Signer
+			//
+			MemoryStream original = new MemoryStream(bOut.ToArray(), false);
+
+			bOut.SetLength(0);
+
+			gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha224);
+
+			gen.AddCertificates(x509Certs);
+
+			sigOut = gen.Open(bOut);
+
+			sigOut.Write(data, 0, data.Length);
+
+			sigOut.Close();
+
+			CheckSigParseable(bOut.ToArray());
+
+			CmsSignedData sd = new CmsSignedData(bOut.ToArray());
+
+			//
+			// replace signer
+			//
+			MemoryStream newOut = new MemoryStream();
+
+			CmsSignedDataParser.ReplaceSigners(original, sd.GetSignerInfos(), newOut);
+
+			sd = new CmsSignedData(new CmsProcessableByteArray(data), newOut.ToArray());
+
+			IEnumerator signerEnum = sd.GetSignerInfos().GetSigners().GetEnumerator();
+			signerEnum.MoveNext();
+			SignerInformation signer = (SignerInformation) signerEnum.Current;
+
+			Assert.AreEqual(signer.DigestAlgOid, CmsSignedDataStreamGenerator.DigestSha224);
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(new CmsTypedStream(
+				new MemoryStream(data, false)), newOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+		}
+
+		[Test]
+		public void TestEncapsulatedSignerStoreReplacement()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			//
+			// create new Signer
+			//
+			MemoryStream  original = new MemoryStream(bOut.ToArray(), false);
+
+			bOut.SetLength(0);
+
+			gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha224);
+
+			gen.AddCertificates(x509Certs);
+
+			sigOut = gen.Open(bOut, true);
+
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedData sd = new CmsSignedData(bOut.ToArray());
+
+			//
+			// replace signer
+			//
+			MemoryStream newOut = new MemoryStream();
+
+			CmsSignedDataParser.ReplaceSigners(original, sd.GetSignerInfos(), newOut);
+
+			sd = new CmsSignedData(newOut.ToArray());
+
+			IEnumerator signerEnum = sd.GetSignerInfos().GetSigners().GetEnumerator();
+			signerEnum.MoveNext();
+			SignerInformation signer = (SignerInformation) signerEnum.Current;
+
+			Assert.AreEqual(signer.DigestAlgOid, CmsSignedDataStreamGenerator.DigestSha224);
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(newOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+		}
+
+		[Test]
+		public void TestCertStoreReplacement()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+			byte[] data = Encoding.ASCII.GetBytes(TestMessage);
+
+			certList.Add(OrigDsaCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut);
+
+			sigOut.Write(data, 0, data.Length);
+
+			sigOut.Close();
+
+			CheckSigParseable(bOut.ToArray());
+
+			//
+			// create new certstore with the right certificates
+			//
+			certList = new ArrayList();
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			//
+			// replace certs
+			//
+			MemoryStream original = new MemoryStream(bOut.ToArray(), false);
+			MemoryStream newOut = new MemoryStream();
+
+			CmsSignedDataParser.ReplaceCertificatesAndCrls(original, x509Certs, null, null, newOut);
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(new CmsTypedStream(new MemoryStream(data, false)), newOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+		}
+
+		[Test]
+		public void TestEncapsulatedCertStoreReplacement()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigDsaCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			//
+			// create new certstore with the right certificates
+			//
+			certList = new ArrayList();
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			//
+			// replace certs
+			//
+			MemoryStream original = new MemoryStream(bOut.ToArray(), false);
+			MemoryStream newOut = new MemoryStream();
+
+			CmsSignedDataParser.ReplaceCertificatesAndCrls(original, x509Certs, null, null, newOut);
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(newOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+		}
+
+		[Test]
+		public void TestCertOrdering1()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+			x509Certs = sp.GetCertificates("Collection");
+			ArrayList a = new ArrayList(x509Certs.GetMatches(null));
+
+			Assert.AreEqual(2, a.Count);
+			Assert.AreEqual(OrigCert, a[0]);
+			Assert.AreEqual(SignCert, a[1]);
+		}
+
+		[Test]
+		public void TestCertOrdering2()
+		{
+			IList certList = new ArrayList();
+			MemoryStream bOut = new MemoryStream();
+
+			certList.Add(SignCert);
+			certList.Add(OrigCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataStreamGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			Stream sigOut = gen.Open(bOut, true);
+
+			byte[] testBytes = Encoding.ASCII.GetBytes(TestMessage);
+			sigOut.Write(testBytes, 0, testBytes.Length);
+
+			sigOut.Close();
+
+			CmsSignedDataParser sp = new CmsSignedDataParser(bOut.ToArray());
+
+			sp.GetSignedContent().Drain();
+			x509Certs = sp.GetCertificates("Collection");
+			ArrayList a = new ArrayList(x509Certs.GetMatches(null));
+
+			Assert.AreEqual(2, a.Count);
+			Assert.AreEqual(SignCert, a[0]);
+			Assert.AreEqual(OrigCert, a[1]);
+		}
+
+        [Test]
+        public void TestCertsOnly()
+        {
+            IList certList = new ArrayList();
+            certList.Add(OrigCert);
+            certList.Add(SignCert);
+
+            IX509Store x509Certs = X509StoreFactory.Create(
+                "Certificate/Collection",
+                new X509CollectionStoreParameters(certList));
+
+            MemoryStream bOut = new MemoryStream();
+
+            CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+            gen.AddCertificates(x509Certs);
+            gen.Open(bOut).Close();
+
+            CheckSigParseable(bOut.ToArray());
+        }
+	}
+}
diff --git a/crypto/test/src/cms/test/SignedDataTest.cs b/crypto/test/src/cms/test/SignedDataTest.cs
new file mode 100644
index 000000000..96f00eadc
--- /dev/null
+++ b/crypto/test/src/cms/test/SignedDataTest.cs
@@ -0,0 +1,1480 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Cms.Tests
+{
+	[TestFixture]
+	public class SignedDataTest
+	{
+		private const string OrigDN = "O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair origKP;
+		private static X509Certificate origCert;
+
+		private const string SignDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU";
+		private static AsymmetricCipherKeyPair signKP;
+		private static X509Certificate signCert;
+
+		private const string ReciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU";
+//		private static AsymmetricCipherKeyPair reciKP;
+//		private static X509Certificate reciCert;
+
+		private static X509Crl signCrl;
+
+		private static AsymmetricCipherKeyPair signGostKP;
+		private static X509Certificate signGostCert;
+
+		private static AsymmetricCipherKeyPair signDsaKP;
+		private static X509Certificate signDsaCert;
+
+		private static AsymmetricCipherKeyPair signECGostKP;
+		private static X509Certificate signECGostCert;
+
+		private static AsymmetricCipherKeyPair signECDsaKP;
+		private static X509Certificate signECDsaCert;
+
+		private static AsymmetricCipherKeyPair OrigKP
+		{
+			get { return origKP == null ? (origKP = CmsTestUtil.MakeKeyPair()) : origKP; }
+		}
+
+		private static AsymmetricCipherKeyPair SignKP
+		{
+			get { return signKP == null ? (signKP = CmsTestUtil.MakeKeyPair()) : signKP; }
+		}
+
+//		private static AsymmetricCipherKeyPair ReciKP
+//		{
+//			get { return reciKP == null ? (reciKP = CmsTestUtil.MakeKeyPair()) : reciKP; }
+//		}
+
+		private static AsymmetricCipherKeyPair SignGostKP
+		{
+			get { return signGostKP == null ? (signGostKP = CmsTestUtil.MakeGostKeyPair()) : signGostKP; }
+		}
+
+		private static AsymmetricCipherKeyPair SignDsaKP
+		{
+			get { return signDsaKP == null ? (signDsaKP = CmsTestUtil.MakeDsaKeyPair()) : signDsaKP; }
+		}
+
+		private static AsymmetricCipherKeyPair SignECGostKP
+		{
+			get { return signECGostKP == null ? (signECGostKP = CmsTestUtil.MakeECGostKeyPair()) : signECGostKP; }
+		}
+
+		private static AsymmetricCipherKeyPair SignECDsaKP
+		{
+			get { return signECDsaKP == null ? (signECDsaKP = CmsTestUtil.MakeECDsaKeyPair()) : signECDsaKP; }
+		}
+
+		private static X509Certificate OrigCert
+		{
+			get { return origCert == null ? (origCert = CmsTestUtil.MakeCertificate(OrigKP, OrigDN, OrigKP, OrigDN)) : origCert; }
+		}
+
+		private static X509Certificate SignCert
+		{
+			get { return signCert == null ? (signCert = CmsTestUtil.MakeCertificate(SignKP, SignDN, OrigKP, OrigDN)) : signCert; }
+		}
+
+//		private static X509Certificate ReciCert
+//		{
+//			get { return reciCert == null ? (reciCert = CmsTestUtil.MakeCertificate(ReciKP, ReciDN, SignKP, SignDN)) : reciCert; }
+//		}
+
+		private static X509Crl SignCrl
+		{
+			get { return signCrl == null ? (signCrl = CmsTestUtil.MakeCrl(SignKP)) : signCrl; }
+		}
+
+		private static X509Certificate SignGostCert
+		{
+			get { return signGostCert == null ? (signGostCert = CmsTestUtil.MakeCertificate(SignGostKP, SignDN, OrigKP, OrigDN)) : signGostCert; }
+		}
+
+		private static X509Certificate SignECGostCert
+		{
+			get { return signECGostCert == null ? (signECGostCert = CmsTestUtil.MakeCertificate(SignECGostKP, SignDN, OrigKP, OrigDN)) : signECGostCert; }
+		}
+
+		private static X509Certificate SignDsaCert
+		{
+			get { return signDsaCert == null ? (signDsaCert = CmsTestUtil.MakeCertificate(SignDsaKP, SignDN, OrigKP, OrigDN)) : signDsaCert; }
+		}
+
+		private static X509Certificate SignECDsaCert
+		{
+			get { return signECDsaCert == null ? (signECDsaCert = CmsTestUtil.MakeCertificate(SignECDsaKP, SignDN, OrigKP, OrigDN)) : signECDsaCert; }
+		}
+
+		private static readonly byte[] disorderedMessage = Base64.Decode(
+			"SU9fc3RkaW5fdXNlZABfX2xpYmNfc3RhcnRfbWFpbgBnZXRob3N0aWQAX19n"
+			+ "bW9uX3M=");
+
+		private static readonly byte[] disorderedSet = Base64.Decode(
+			"MIIYXQYJKoZIhvcNAQcCoIIYTjCCGEoCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+			+ "SIb3DQEHAaCCFqswggJUMIIBwKADAgECAgMMg6wwCgYGKyQDAwECBQAwbzEL"
+			+ "MAkGA1UEBhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbI"
+			+ "dXIgVGVsZWtvbW11bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwEx"
+			+ "MBEGA1UEAxQKNFItQ0EgMTpQTjAiGA8yMDAwMDMyMjA5NDM1MFoYDzIwMDQw"
+			+ "MTIxMTYwNDUzWjBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1"
+			+ "bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEh"
+			+ "MAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1DQSAxOlBOMIGhMA0GCSqGSIb3"
+			+ "DQEBAQUAA4GPADCBiwKBgQCKHkFTJx8GmoqFTxEOxpK9XkC3NZ5dBEKiUv0I"
+			+ "fe3QMqeGMoCUnyJxwW0k2/53duHxtv2yHSZpFKjrjvE/uGwdOMqBMTjMzkFg"
+			+ "19e9JPv061wyADOucOIaNAgha/zFt9XUyrHF21knKCvDNExv2MYIAagkTKaj"
+			+ "LMAw0bu1J0FadQIFAMAAAAEwCgYGKyQDAwECBQADgYEAgFauXpoTLh3Z3pT/"
+			+ "3bhgrxO/2gKGZopWGSWSJPNwq/U3x2EuctOJurj+y2inTcJjespThflpN+7Q"
+			+ "nvsUhXU+jL2MtPlObU0GmLvWbi47cBShJ7KElcZAaxgWMBzdRGqTOdtMv+ev"
+			+ "2t4igGF/q71xf6J2c3pTLWr6P8s6tzLfOCMwggJDMIIBr6ADAgECAgQAuzyu"
+			+ "MAoGBiskAwMBAgUAMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGll"
+			+ "cnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"
+			+ "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE4wIhgPMjAwMTA4"
+			+ "MjAwODA4MjBaGA8yMDA1MDgyMDA4MDgyMFowSzELMAkGA1UEBhMCREUxEjAQ"
+			+ "BgNVBAoUCVNpZ250cnVzdDEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFDQSBT"
+			+ "SUdOVFJVU1QgMTpQTjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAhV12"
+			+ "N2WhlR6f+3CXP57GrBM9la5Vnsu2b92zv5MZqQOPeEsYbZqDCFkYg1bSwsDE"
+			+ "XsGVQqXdQNAGUaapr/EUVVN+hNZ07GcmC1sPeQECgUkxDYjGi4ihbvzxlahj"
+			+ "L4nX+UTzJVBfJwXoIvJ+lMHOSpnOLIuEL3SRhBItvRECxN0CAwEAAaMSMBAw"
+			+ "DgYDVR0PAQH/BAQDAgEGMAoGBiskAwMBAgUAA4GBACDc9Pc6X8sK1cerphiV"
+			+ "LfFv4kpZb9ev4WPy/C6987Qw1SOTElhZAmxaJQBqmDHWlQ63wj1DEqswk7hG"
+			+ "LrvQk/iX6KXIn8e64uit7kx6DHGRKNvNGofPjr1WelGeGW/T2ZJKgmPDjCkf"
+			+ "sIKt2c3gwa2pDn4mmCz/DStUIqcPDbqLMIICVTCCAcGgAwIBAgIEAJ16STAK"
+			+ "BgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1"
+			+ "bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEh"
+			+ "MAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1DQSAxOlBOMCIYDzIwMDEwMjAx"
+			+ "MTM0NDI1WhgPMjAwNTAzMjIwODU1NTFaMG8xCzAJBgNVBAYTAkRFMT0wOwYD"
+			+ "VQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0"
+			+ "aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjZSLUNhIDE6"
+			+ "UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGLAoGBAIOiqxUkzVyqnvthihnl"
+			+ "tsE5m1Xn5TZKeR/2MQPStc5hJ+V4yptEtIx+Fn5rOoqT5VEVWhcE35wdbPvg"
+			+ "JyQFn5msmhPQT/6XSGOlrWRoFummXN9lQzAjCj1sgTcmoLCVQ5s5WpCAOXFw"
+			+ "VWu16qndz3sPItn3jJ0F3Kh3w79NglvPAgUAwAAAATAKBgYrJAMDAQIFAAOB"
+			+ "gQBpSRdnDb6AcNVaXSmGo6+kVPIBhot1LzJOGaPyDNpGXxd7LV4tMBF1U7gr"
+			+ "4k1g9BO6YiMWvw9uiTZmn0CfV8+k4fWEuG/nmafRoGIuay2f+ILuT+C0rnp1"
+			+ "4FgMsEhuVNJJAmb12QV0PZII+UneyhAneZuQQzVUkTcVgYxogxdSOzCCAlUw"
+			+ "ggHBoAMCAQICBACdekowCgYGKyQDAwECBQAwbzELMAkGA1UEBhMCREUxPTA7"
+			+ "BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlr"
+			+ "YXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNlItQ2Eg"
+			+ "MTpQTjAiGA8yMDAxMDIwMTEzNDcwN1oYDzIwMDUwMzIyMDg1NTUxWjBvMQsw"
+			+ "CQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1"
+			+ "ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEw"
+			+ "EQYDVQQDFAo1Ui1DQSAxOlBOMIGhMA0GCSqGSIb3DQEBAQUAA4GPADCBiwKB"
+			+ "gQCKHkFTJx8GmoqFTxEOxpK9XkC3NZ5dBEKiUv0Ife3QMqeGMoCUnyJxwW0k"
+			+ "2/53duHxtv2yHSZpFKjrjvE/uGwdOMqBMTjMzkFg19e9JPv061wyADOucOIa"
+			+ "NAgha/zFt9XUyrHF21knKCvDNExv2MYIAagkTKajLMAw0bu1J0FadQIFAMAA"
+			+ "AAEwCgYGKyQDAwECBQADgYEAV1yTi+2gyB7sUhn4PXmi/tmBxAfe5oBjDW8m"
+			+ "gxtfudxKGZ6l/FUPNcrSc5oqBYxKWtLmf3XX87LcblYsch617jtNTkMzhx9e"
+			+ "qxiD02ufcrxz2EVt0Akdqiz8mdVeqp3oLcNU/IttpSrcA91CAnoUXtDZYwb/"
+			+ "gdQ4FI9l3+qo/0UwggJVMIIBwaADAgECAgQAxIymMAoGBiskAwMBAgUAMG8x"
+			+ "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+			+ "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+			+ "MTARBgNVBAMUCjZSLUNhIDE6UE4wIhgPMjAwMTEwMTUxMzMxNThaGA8yMDA1"
+			+ "MDYwMTA5NTIxN1owbzELMAkGA1UEBhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVy"
+			+ "dW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11bmlrYXRpb24gdW5kIFBvc3Qx"
+			+ "ITAMBgcCggYBCgcUEwExMBEGA1UEAxQKN1ItQ0EgMTpQTjCBoTANBgkqhkiG"
+			+ "9w0BAQEFAAOBjwAwgYsCgYEAiokD/j6lEP4FexF356OpU5teUpGGfUKjIrFX"
+			+ "BHc79G0TUzgVxqMoN1PWnWktQvKo8ETaugxLkP9/zfX3aAQzDW4Zki6x6GDq"
+			+ "fy09Agk+RJvhfbbIzRkV4sBBco0n73x7TfG/9NTgVr/96U+I+z/1j30aboM6"
+			+ "9OkLEhjxAr0/GbsCBQDAAAABMAoGBiskAwMBAgUAA4GBAHWRqRixt+EuqHhR"
+			+ "K1kIxKGZL2vZuakYV0R24Gv/0ZR52FE4ECr+I49o8FP1qiGSwnXB0SwjuH2S"
+			+ "iGiSJi+iH/MeY85IHwW1P5e+bOMvEOFhZhQXQixOD7totIoFtdyaj1XGYRef"
+			+ "0f2cPOjNJorXHGV8wuBk+/j++sxbd/Net3FtMIICVTCCAcGgAwIBAgIEAMSM"
+			+ "pzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+			+ "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+			+ "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo3Ui1DQSAxOlBOMCIYDzIwMDEx"
+			+ "MDE1MTMzNDE0WhgPMjAwNTA2MDEwOTUyMTdaMG8xCzAJBgNVBAYTAkRFMT0w"
+			+ "OwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5p"
+			+ "a2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjZSLUNh"
+			+ "IDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGLAoGBAIOiqxUkzVyqnvth"
+			+ "ihnltsE5m1Xn5TZKeR/2MQPStc5hJ+V4yptEtIx+Fn5rOoqT5VEVWhcE35wd"
+			+ "bPvgJyQFn5msmhPQT/6XSGOlrWRoFummXN9lQzAjCj1sgTcmoLCVQ5s5WpCA"
+			+ "OXFwVWu16qndz3sPItn3jJ0F3Kh3w79NglvPAgUAwAAAATAKBgYrJAMDAQIF"
+			+ "AAOBgQBi5W96UVDoNIRkCncqr1LLG9vF9SGBIkvFpLDIIbcvp+CXhlvsdCJl"
+			+ "0pt2QEPSDl4cmpOet+CxJTdTuMeBNXxhb7Dvualog69w/+K2JbPhZYxuVFZs"
+			+ "Zh5BkPn2FnbNu3YbJhE60aIkikr72J4XZsI5DxpZCGh6xyV/YPRdKSljFjCC"
+			+ "AlQwggHAoAMCAQICAwyDqzAKBgYrJAMDAQIFADBvMQswCQYDVQQGEwJERTE9"
+			+ "MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVu"
+			+ "aWthdGlvbiB1bmQgUG9zdDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAo1Ui1D"
+			+ "QSAxOlBOMCIYDzIwMDAwMzIyMDk0MTI3WhgPMjAwNDAxMjExNjA0NTNaMG8x"
+			+ "CzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBm"
+			+ "yHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMB"
+			+ "MTARBgNVBAMUCjRSLUNBIDE6UE4wgaEwDQYJKoZIhvcNAQEBBQADgY8AMIGL"
+			+ "AoGBAI8x26tmrFJanlm100B7KGlRemCD1R93PwdnG7svRyf5ZxOsdGrDszNg"
+			+ "xg6ouO8ZHQMT3NC2dH8TvO65Js+8bIyTm51azF6clEg0qeWNMKiiXbBXa+ph"
+			+ "hTkGbXiLYvACZ6/MTJMJ1lcrjpRF7BXtYeYMcEF6znD4pxOqrtbf9z5hAgUA"
+			+ "wAAAATAKBgYrJAMDAQIFAAOBgQB99BjSKlGPbMLQAgXlvA9jUsDNhpnVm3a1"
+			+ "YkfxSqS/dbQlYkbOKvCxkPGA9NBxisBM8l1zFynVjJoy++aysRmcnLY/sHaz"
+			+ "23BF2iU7WERy18H3lMBfYB6sXkfYiZtvQZcWaO48m73ZBySuiV3iXpb2wgs/"
+			+ "Cs20iqroAWxwq/W/9jCCAlMwggG/oAMCAQICBDsFZ9UwCgYGKyQDAwECBQAw"
+			+ "bzELMAkGA1UEBhMCREUxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNFItQ0Eg"
+			+ "MTpQTjE9MDsGA1UEChQ0UmVndWxpZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxl"
+			+ "a29tbXVuaWthdGlvbiB1bmQgUG9zdDAiGA8xOTk5MDEyMTE3MzUzNFoYDzIw"
+			+ "MDQwMTIxMTYwMDAyWjBvMQswCQYDVQQGEwJERTE9MDsGA1UEChQ0UmVndWxp"
+			+ "ZXJ1bmdzYmVoyG9yZGUgZsh1ciBUZWxla29tbXVuaWthdGlvbiB1bmQgUG9z"
+			+ "dDEhMAwGBwKCBgEKBxQTATEwEQYDVQQDFAozUi1DQSAxOlBOMIGfMA0GCSqG"
+			+ "SIb3DQEBAQUAA4GNADCBiQKBgI4B557mbKQg/AqWBXNJhaT/6lwV93HUl4U8"
+			+ "u35udLq2+u9phns1WZkdM3gDfEpL002PeLfHr1ID/96dDYf04lAXQfombils"
+			+ "of1C1k32xOvxjlcrDOuPEMxz9/HDAQZA5MjmmYHAIulGI8Qg4Tc7ERRtg/hd"
+			+ "0QX0/zoOeXoDSEOBAgTAAAABMAoGBiskAwMBAgUAA4GBAIyzwfT3keHI/n2P"
+			+ "LrarRJv96mCohmDZNpUQdZTVjGu5VQjVJwk3hpagU0o/t/FkdzAjOdfEw8Ql"
+			+ "3WXhfIbNLv1YafMm2eWSdeYbLcbB5yJ1od+SYyf9+tm7cwfDAcr22jNRBqx8"
+			+ "wkWKtKDjWKkevaSdy99sAI8jebHtWz7jzydKMIID9TCCA16gAwIBAgICbMcw"
+			+ "DQYJKoZIhvcNAQEFBQAwSzELMAkGA1UEBhMCREUxEjAQBgNVBAoUCVNpZ250"
+			+ "cnVzdDEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFDQSBTSUdOVFJVU1QgMTpQ"
+			+ "TjAeFw0wNDA3MzAxMzAyNDZaFw0wNzA3MzAxMzAyNDZaMDwxETAPBgNVBAMM"
+			+ "CFlhY29tOlBOMQ4wDAYDVQRBDAVZYWNvbTELMAkGA1UEBhMCREUxCjAIBgNV"
+			+ "BAUTATEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIWzLlYLQApocXIp"
+			+ "pgCCpkkOUVLgcLYKeOd6/bXAnI2dTHQqT2bv7qzfUnYvOqiNgYdF13pOYtKg"
+			+ "XwXMTNFL4ZOI6GoBdNs9TQiZ7KEWnqnr2945HYx7UpgTBclbOK/wGHuCdcwO"
+			+ "x7juZs1ZQPFG0Lv8RoiV9s6HP7POqh1sO0P/AgMBAAGjggH1MIIB8TCBnAYD"
+			+ "VR0jBIGUMIGRgBQcZzNghfnXoXRm8h1+VITC5caNRqFzpHEwbzELMAkGA1UE"
+			+ "BhMCREUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVs"
+			+ "ZWtvbW11bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UE"
+			+ "AxQKNVItQ0EgMTpQToIEALs8rjAdBgNVHQ4EFgQU2e5KAzkVuKaM9I5heXkz"
+			+ "bcAIuR8wDgYDVR0PAQH/BAQDAgZAMBIGA1UdIAQLMAkwBwYFKyQIAQEwfwYD"
+			+ "VR0fBHgwdjB0oCygKoYobGRhcDovL2Rpci5zaWdudHJ1c3QuZGUvbz1TaWdu"
+			+ "dHJ1c3QsYz1kZaJEpEIwQDEdMBsGA1UEAxMUQ1JMU2lnblNpZ250cnVzdDE6"
+			+ "UE4xEjAQBgNVBAoTCVNpZ250cnVzdDELMAkGA1UEBhMCREUwYgYIKwYBBQUH"
+			+ "AQEEVjBUMFIGCCsGAQUFBzABhkZodHRwOi8vZGlyLnNpZ250cnVzdC5kZS9T"
+			+ "aWdudHJ1c3QvT0NTUC9zZXJ2bGV0L2h0dHBHYXRld2F5LlBvc3RIYW5kbGVy"
+			+ "MBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwDgYHAoIGAQoMAAQDAQH/MA0G"
+			+ "CSqGSIb3DQEBBQUAA4GBAHn1m3GcoyD5GBkKUY/OdtD6Sj38LYqYCF+qDbJR"
+			+ "6pqUBjY2wsvXepUppEler+stH8mwpDDSJXrJyuzf7xroDs4dkLl+Rs2x+2tg"
+			+ "BjU+ABkBDMsym2WpwgA8LCdymmXmjdv9tULxY+ec2pjSEzql6nEZNEfrU8nt"
+			+ "ZCSCavgqW4TtMYIBejCCAXYCAQEwUTBLMQswCQYDVQQGEwJERTESMBAGA1UE"
+			+ "ChQJU2lnbnRydXN0MSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEUNBIFNJR05U"
+			+ "UlVTVCAxOlBOAgJsxzAJBgUrDgMCGgUAoIGAMBgGCSqGSIb3DQEJAzELBgkq"
+			+ "hkiG9w0BBwEwIwYJKoZIhvcNAQkEMRYEFIYfhPoyfGzkLWWSSLjaHb4HQmaK"
+			+ "MBwGCSqGSIb3DQEJBTEPFw0wNTAzMjQwNzM4MzVaMCEGBSskCAYFMRgWFi92"
+			+ "YXIvZmlsZXMvdG1wXzEvdGVzdDEwDQYJKoZIhvcNAQEFBQAEgYA2IvA8lhVz"
+			+ "VD5e/itUxbFboKxeKnqJ5n/KuO/uBCl1N14+7Z2vtw1sfkIG+bJdp3OY2Cmn"
+			+ "mrQcwsN99Vjal4cXVj8t+DJzFG9tK9dSLvD3q9zT/GQ0kJXfimLVwCa4NaSf"
+			+ "Qsu4xtG0Rav6bCcnzabAkKuNNvKtH8amSRzk870DBg==");
+
+		private static readonly byte[] xtraCounterSig = Base64.Decode(
+			  "MIIR/AYJKoZIhvcNAQcCoIIR7TCCEekCAQExCzAJBgUrDgMCGgUAMBoGCSqG"
+			+ "SIb3DQEHAaANBAtIZWxsbyB3b3JsZKCCDnkwggTPMIIDt6ADAgECAgRDnYD3"
+			+ "MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5U"
+			+ "ZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmlj"
+			+ "YXRpb24gQXV0aG9yaXR5MB4XDTA4MDkxMjExNDMxMloXDTEwMDkxMjExNDMx"
+			+ "MlowgdgxCzAJBgNVBAYTAklUMSIwIAYDVQQKDBlJbnRlc2EgUy5wLkEuLzA1"
+			+ "MjYyODkwMDE0MSowKAYDVQQLDCFCdXNpbmVzcyBDb2xsYWJvcmF0aW9uICYg"
+			+ "U2VjdXJpdHkxHjAcBgNVBAMMFU1BU1NJTUlMSUFOTyBaSUNDQVJESTERMA8G"
+			+ "A1UEBAwIWklDQ0FSREkxFTATBgNVBCoMDE1BU1NJTUlMSUFOTzEcMBoGA1UE"
+			+ "BRMTSVQ6WkNDTVNNNzZIMTRMMjE5WTERMA8GA1UELhMIMDAwMDI1ODUwgaAw"
+			+ "DQYJKoZIhvcNAQEBBQADgY4AMIGKAoGBALeJTjmyFgx1SIP6c2AuB/kuyHo5"
+			+ "j/prKELTALsFDimre/Hxr3wOSet1TdQfFzU8Lu+EJqgfV9cV+cI1yeH1rZs7"
+			+ "lei7L3tX/VR565IywnguX5xwvteASgWZr537Fkws50bvTEMyYOj1Tf3FZvZU"
+			+ "z4n4OD39KI4mfR9i1eEVIxR3AgQAizpNo4IBoTCCAZ0wHQYDVR0RBBYwFIES"
+			+ "emljY2FyZGlAaW50ZXNhLml0MC8GCCsGAQUFBwEDBCMwITAIBgYEAI5GAQEw"
+			+ "CwYGBACORgEDAgEUMAgGBgQAjkYBBDBZBgNVHSAEUjBQME4GBgQAizABATBE"
+			+ "MEIGCCsGAQUFBwIBFjZodHRwOi8vZS10cnVzdGNvbS5pbnRlc2EuaXQvY2Ff"
+			+ "cHViYmxpY2EvQ1BTX0lOVEVTQS5odG0wDgYDVR0PAQH/BAQDAgZAMIGDBgNV"
+			+ "HSMEfDB6gBQZCQOW0bjFWBt+EORuxPagEgkQqKFcpFowWDELMAkGA1UEBhMC"
+			+ "SVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJbi5U"
+			+ "ZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHmCBDzRARMwOwYDVR0f"
+			+ "BDQwMjAwoC6gLIYqaHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L0NSTC9J"
+			+ "TlRFU0EuY3JsMB0GA1UdDgQWBBTf5ItL8KmQh541Dxt7YxcWI1254TANBgkq"
+			+ "hkiG9w0BAQUFAAOCAQEAgW+uL1CVWQepbC/wfCmR6PN37Sueb4xiKQj2mTD5"
+			+ "UZ5KQjpivy/Hbuf0NrfKNiDEhAvoHSPC31ebGiKuTMFNyZPHfPEUnyYGSxea"
+			+ "2w837aXJFr6utPNQGBRi89kH90sZDlXtOSrZI+AzJJn5QK3F9gjcayU2NZXQ"
+			+ "MJgRwYmFyn2w4jtox+CwXPQ9E5XgxiMZ4WDL03cWVXDLX00EOJwnDDMUNTRI"
+			+ "m9Zv+4SKTNlfFbi9UTBqWBySkDzAelsfB2U61oqc2h1xKmCtkGMmN9iZT+Qz"
+			+ "ZC/vaaT+hLEBFGAH2gwFrYc4/jTBKyBYeU1vsAxsibIoTs1Apgl6MH75qPDL"
+			+ "BzCCBM8wggO3oAMCAQICBEOdgPcwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE"
+			+ "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+			+ "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwOTEy"
+			+ "MTE0MzEyWhcNMTAwOTEyMTE0MzEyWjCB2DELMAkGA1UEBhMCSVQxIjAgBgNV"
+			+ "BAoMGUludGVzYSBTLnAuQS4vMDUyNjI4OTAwMTQxKjAoBgNVBAsMIUJ1c2lu"
+			+ "ZXNzIENvbGxhYm9yYXRpb24gJiBTZWN1cml0eTEeMBwGA1UEAwwVTUFTU0lN"
+			+ "SUxJQU5PIFpJQ0NBUkRJMREwDwYDVQQEDAhaSUNDQVJESTEVMBMGA1UEKgwM"
+			+ "TUFTU0lNSUxJQU5PMRwwGgYDVQQFExNJVDpaQ0NNU003NkgxNEwyMTlZMREw"
+			+ "DwYDVQQuEwgwMDAwMjU4NTCBoDANBgkqhkiG9w0BAQEFAAOBjgAwgYoCgYEA"
+			+ "t4lOObIWDHVIg/pzYC4H+S7IejmP+msoQtMAuwUOKat78fGvfA5J63VN1B8X"
+			+ "NTwu74QmqB9X1xX5wjXJ4fWtmzuV6Lsve1f9VHnrkjLCeC5fnHC+14BKBZmv"
+			+ "nfsWTCznRu9MQzJg6PVN/cVm9lTPifg4Pf0ojiZ9H2LV4RUjFHcCBACLOk2j"
+			+ "ggGhMIIBnTAdBgNVHREEFjAUgRJ6aWNjYXJkaUBpbnRlc2EuaXQwLwYIKwYB"
+			+ "BQUHAQMEIzAhMAgGBgQAjkYBATALBgYEAI5GAQMCARQwCAYGBACORgEEMFkG"
+			+ "A1UdIARSMFAwTgYGBACLMAEBMEQwQgYIKwYBBQUHAgEWNmh0dHA6Ly9lLXRy"
+			+ "dXN0Y29tLmludGVzYS5pdC9jYV9wdWJibGljYS9DUFNfSU5URVNBLmh0bTAO"
+			+ "BgNVHQ8BAf8EBAMCBkAwgYMGA1UdIwR8MHqAFBkJA5bRuMVYG34Q5G7E9qAS"
+			+ "CRCooVykWjBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5BLiBT"
+			+ "LnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9uIEF1"
+			+ "dGhvcml0eYIEPNEBEzA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vZS10cnVz"
+			+ "dGNvbS5pbnRlc2EuaXQvQ1JML0lOVEVTQS5jcmwwHQYDVR0OBBYEFN/ki0vw"
+			+ "qZCHnjUPG3tjFxYjXbnhMA0GCSqGSIb3DQEBBQUAA4IBAQCBb64vUJVZB6ls"
+			+ "L/B8KZHo83ftK55vjGIpCPaZMPlRnkpCOmK/L8du5/Q2t8o2IMSEC+gdI8Lf"
+			+ "V5saIq5MwU3Jk8d88RSfJgZLF5rbDzftpckWvq6081AYFGLz2Qf3SxkOVe05"
+			+ "Ktkj4DMkmflArcX2CNxrJTY1ldAwmBHBiYXKfbDiO2jH4LBc9D0TleDGIxnh"
+			+ "YMvTdxZVcMtfTQQ4nCcMMxQ1NEib1m/7hIpM2V8VuL1RMGpYHJKQPMB6Wx8H"
+			+ "ZTrWipzaHXEqYK2QYyY32JlP5DNkL+9ppP6EsQEUYAfaDAWthzj+NMErIFh5"
+			+ "TW+wDGyJsihOzUCmCXowfvmo8MsHMIIEzzCCA7egAwIBAgIEQ52A9zANBgkq"
+			+ "hkiG9w0BAQUFADBYMQswCQYDVQQGEwJJVDEaMBgGA1UEChMRSW4uVGUuUy5B"
+			+ "LiBTLnAuQS4xLTArBgNVBAMTJEluLlRlLlMuQS4gLSBDZXJ0aWZpY2F0aW9u"
+			+ "IEF1dGhvcml0eTAeFw0wODA5MTIxMTQzMTJaFw0xMDA5MTIxMTQzMTJaMIHY"
+			+ "MQswCQYDVQQGEwJJVDEiMCAGA1UECgwZSW50ZXNhIFMucC5BLi8wNTI2Mjg5"
+			+ "MDAxNDEqMCgGA1UECwwhQnVzaW5lc3MgQ29sbGFib3JhdGlvbiAmIFNlY3Vy"
+			+ "aXR5MR4wHAYDVQQDDBVNQVNTSU1JTElBTk8gWklDQ0FSREkxETAPBgNVBAQM"
+			+ "CFpJQ0NBUkRJMRUwEwYDVQQqDAxNQVNTSU1JTElBTk8xHDAaBgNVBAUTE0lU"
+			+ "OlpDQ01TTTc2SDE0TDIxOVkxETAPBgNVBC4TCDAwMDAyNTg1MIGgMA0GCSqG"
+			+ "SIb3DQEBAQUAA4GOADCBigKBgQC3iU45shYMdUiD+nNgLgf5Lsh6OY/6ayhC"
+			+ "0wC7BQ4pq3vx8a98DknrdU3UHxc1PC7vhCaoH1fXFfnCNcnh9a2bO5Xouy97"
+			+ "V/1UeeuSMsJ4Ll+ccL7XgEoFma+d+xZMLOdG70xDMmDo9U39xWb2VM+J+Dg9"
+			+ "/SiOJn0fYtXhFSMUdwIEAIs6TaOCAaEwggGdMB0GA1UdEQQWMBSBEnppY2Nh"
+			+ "cmRpQGludGVzYS5pdDAvBggrBgEFBQcBAwQjMCEwCAYGBACORgEBMAsGBgQA"
+			+ "jkYBAwIBFDAIBgYEAI5GAQQwWQYDVR0gBFIwUDBOBgYEAIswAQEwRDBCBggr"
+			+ "BgEFBQcCARY2aHR0cDovL2UtdHJ1c3Rjb20uaW50ZXNhLml0L2NhX3B1YmJs"
+			+ "aWNhL0NQU19JTlRFU0EuaHRtMA4GA1UdDwEB/wQEAwIGQDCBgwYDVR0jBHww"
+			+ "eoAUGQkDltG4xVgbfhDkbsT2oBIJEKihXKRaMFgxCzAJBgNVBAYTAklUMRow"
+			+ "GAYDVQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5B"
+			+ "LiAtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ80QETMDsGA1UdHwQ0MDIw"
+			+ "MKAuoCyGKmh0dHA6Ly9lLXRydXN0Y29tLmludGVzYS5pdC9DUkwvSU5URVNB"
+			+ "LmNybDAdBgNVHQ4EFgQU3+SLS/CpkIeeNQ8be2MXFiNdueEwDQYJKoZIhvcN"
+			+ "AQEFBQADggEBAIFvri9QlVkHqWwv8Hwpkejzd+0rnm+MYikI9pkw+VGeSkI6"
+			+ "Yr8vx27n9Da3yjYgxIQL6B0jwt9XmxoirkzBTcmTx3zxFJ8mBksXmtsPN+2l"
+			+ "yRa+rrTzUBgUYvPZB/dLGQ5V7Tkq2SPgMySZ+UCtxfYI3GslNjWV0DCYEcGJ"
+			+ "hcp9sOI7aMfgsFz0PROV4MYjGeFgy9N3FlVwy19NBDicJwwzFDU0SJvWb/uE"
+			+ "ikzZXxW4vVEwalgckpA8wHpbHwdlOtaKnNodcSpgrZBjJjfYmU/kM2Qv72mk"
+			+ "/oSxARRgB9oMBa2HOP40wSsgWHlNb7AMbImyKE7NQKYJejB++ajwywcxggM8"
+			+ "MIIDOAIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYDVQQKExFJbi5UZS5TLkEu"
+			+ "IFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAtIENlcnRpZmljYXRpb24g"
+			+ "QXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYB+"
+			+ "lH2cwLqc91mP8prvgSV+RRzk13dJdZvdoVjgQoFrPhBiZCNIEoHvIhMMA/sM"
+			+ "X6euSRZk7EjD24FasCEGYyd0mJVLEy6TSPmuW+wWz/28w3a6IWXBGrbb/ild"
+			+ "/CJMkPgLPGgOVD1WDwiNKwfasiQSFtySf5DPn3jFevdLeMmEY6GCAjIwggEV"
+			+ "BgkqhkiG9w0BCQYxggEGMIIBAgIBATBgMFgxCzAJBgNVBAYTAklUMRowGAYD"
+			+ "VQQKExFJbi5UZS5TLkEuIFMucC5BLjEtMCsGA1UEAxMkSW4uVGUuUy5BLiAt"
+			+ "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5AgRDnYD3MAkGBSsOAwIaBQAwDQYJ"
+			+ "KoZIhvcNAQEBBQAEgYBHlOULfT5GDigIvxP0qZOy8VbpntmzaPF55VV4buKV"
+			+ "35J+uHp98gXKp0LrHM69V5IRKuyuQzHHFBqsXxsRI9o6KoOfgliD9Xc+BeMg"
+			+ "dKzQhBhBYoFREq8hQM0nSbqDNHYAQyNHMzUA/ZQUO5dlFuH8Dw3iDYAhNtfd"
+			+ "PrlchKJthDCCARUGCSqGSIb3DQEJBjGCAQYwggECAgEBMGAwWDELMAkGA1UE"
+			+ "BhMCSVQxGjAYBgNVBAoTEUluLlRlLlMuQS4gUy5wLkEuMS0wKwYDVQQDEyRJ"
+			+ "bi5UZS5TLkEuIC0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkCBEOdgPcwCQYF"
+			+ "Kw4DAhoFADANBgkqhkiG9w0BAQEFAASBgEeU5Qt9PkYOKAi/E/Spk7LxVume"
+			+ "2bNo8XnlVXhu4pXfkn64en3yBcqnQusczr1XkhEq7K5DMccUGqxfGxEj2joq"
+			+ "g5+CWIP1dz4F4yB0rNCEGEFigVESryFAzSdJuoM0dgBDI0czNQD9lBQ7l2UW"
+			+ "4fwPDeINgCE2190+uVyEom2E");
+
+		private void VerifySignatures(
+			CmsSignedData	s,
+			byte[]			contentDigest)
+		{
+			IX509Store x509Certs = s.GetCertificates("Collection");
+
+			SignerInformationStore signers = s.GetSignerInfos();
+			ICollection c = signers.GetSigners();
+
+			foreach (SignerInformation signer in c)
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+
+				if (contentDigest != null)
+				{
+					Assert.IsTrue(Arrays.AreEqual(contentDigest, signer.GetContentDigest()));
+				}
+			}
+		}
+
+		private void VerifySignatures(
+			CmsSignedData s)
+		{
+			VerifySignatures(s, null);
+		}
+
+		[Test]
+		public void TestDetachedVerification()
+		{
+			byte[] data = Encoding.ASCII.GetBytes("Hello World!");
+			CmsProcessable msg = new CmsProcessableByteArray(data);
+
+			IList certList = new ArrayList();
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestMD5);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData s = gen.Generate(msg);
+
+			IDictionary hashes = new Hashtable();
+			hashes.Add(CmsSignedDataGenerator.DigestSha1, CalculateHash("SHA1", data));
+			hashes.Add(CmsSignedDataGenerator.DigestMD5, CalculateHash("MD5", data));
+
+			s = new CmsSignedData(hashes, s.GetEncoded());
+
+			VerifySignatures(s, null);
+		}
+
+		private byte[] CalculateHash(
+			string	digestName,
+			byte[]	data)
+		{
+			IDigest digest = DigestUtilities.GetDigest(digestName);
+			digest.BlockUpdate(data, 0, data.Length);
+			return DigestUtilities.DoFinal(digest);
+		}
+
+		[Test]
+		public void TestSha1AndMD5WithRsaEncapsulatedRepeated()
+		{
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestMD5);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData s = gen.Generate(msg, true);
+
+			s = new CmsSignedData(ContentInfo.GetInstance(Asn1Object.FromByteArray(s.GetEncoded())));
+
+			x509Certs = s.GetCertificates("Collection");
+
+			SignerInformationStore signers = s.GetSignerInfos();
+
+			Assert.AreEqual(2, signers.Count);
+
+			SignerID sid = null;
+			ICollection c = signers.GetSigners();
+
+			foreach (SignerInformation signer in c)
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				sid = signer.SignerID;
+
+				Assert.IsTrue(signer.Verify(cert));
+
+				//
+				// check content digest
+				//
+
+				byte[] contentDigest = (byte[])gen.GetGeneratedDigests()[signer.DigestAlgOid];
+
+				AttributeTable table = signer.SignedAttributes;
+				Asn1.Cms.Attribute hash = table[CmsAttributes.MessageDigest];
+
+				Assert.IsTrue(Arrays.AreEqual(contentDigest, ((Asn1OctetString)hash.AttrValues[0]).GetOctets()));
+			}
+
+			c = signers.GetSigners(sid);
+
+			Assert.AreEqual(2, c.Count);
+
+			//
+			// try using existing signer
+			//
+
+			gen = new CmsSignedDataGenerator();
+
+			gen.AddSigners(s.GetSignerInfos());
+
+			gen.AddCertificates(s.GetCertificates("Collection"));
+			gen.AddCrls(s.GetCrls("Collection"));
+
+			s = gen.Generate(msg, true);
+
+			s = new CmsSignedData(ContentInfo.GetInstance(Asn1Object.FromByteArray(s.GetEncoded())));
+
+			x509Certs = s.GetCertificates("Collection");
+
+			signers = s.GetSignerInfos();
+			c = signers.GetSigners();
+
+			Assert.AreEqual(2, c.Count);
+
+			foreach (SignerInformation signer in c)
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.AreEqual(true, signer.Verify(cert));
+			}
+
+			CheckSignerStoreReplacement(s, signers);
+		}
+
+		// NB: C# build doesn't support "no attributes" version of CmsSignedDataGenerator.Generate
+//		[Test]
+//		public void TestSha1WithRsaNoAttributes()
+//		{
+//			IList certList = new ArrayList();
+//			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello world!"));
+//
+//			certList.Add(OrigCert);
+//			certList.Add(SignCert);
+//
+//			IX509Store x509Certs = X509StoreFactory.Create(
+//				"Certificate/Collection",
+//				new X509CollectionStoreParameters(certList));
+//
+//			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+//
+//			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+//
+//			gen.AddCertificates(x509Certs);
+//
+//			CmsSignedData s = gen.Generate(CmsSignedDataGenerator.Data, msg, false, false);
+//
+//			//
+//			// compute expected content digest
+//			//
+//			IDigest md = DigestUtilities.GetDigest("SHA1");
+//
+//			byte[] testBytes = Encoding.ASCII.GetBytes("Hello world!");
+//			md.BlockUpdate(testBytes, 0, testBytes.Length);
+//			byte[] hash = DigestUtilities.DoFinal(md);
+//
+//			VerifySignatures(s, hash);
+//		}
+
+		[Test]
+		public void TestSha1WithRsaAndAttributeTable()
+		{
+			byte[] testBytes = Encoding.ASCII.GetBytes("Hello world!");
+
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(testBytes);
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			IDigest md = DigestUtilities.GetDigest("SHA1");
+			md.BlockUpdate(testBytes, 0, testBytes.Length);
+			byte[] hash = DigestUtilities.DoFinal(md);
+
+			Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.MessageDigest,
+				new DerSet(new DerOctetString(hash)));
+
+			Asn1EncodableVector v = new Asn1EncodableVector(attr);
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1,
+				new AttributeTable(v), null);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData s = gen.Generate(CmsSignedDataGenerator.Data, null, false);
+
+			//
+			// the signature is detached, so need to add msg before passing on
+			//
+			s = new CmsSignedData(msg, s.GetEncoded());
+
+			//
+			// compute expected content digest
+			//
+			VerifySignatures(s, hash);
+		}
+
+		[Test]
+		public void TestSha1WithRsaEncapsulated()
+		{
+			EncapsulatedTest(SignKP, SignCert, CmsSignedDataGenerator.DigestSha1);
+		}
+
+		[Test]
+		public void TestSha1WithRsaEncapsulatedSubjectKeyID()
+		{
+			SubjectKeyIDTest(SignKP, SignCert, CmsSignedDataGenerator.DigestSha1);
+		}
+
+		[Test]
+		public void TestSha1WithRsaPss()
+		{
+			rsaPssTest("SHA1", CmsSignedDataGenerator.DigestSha1);
+		}
+
+		[Test]
+		public void TestSha224WithRsaPss()
+		{
+			rsaPssTest("SHA224", CmsSignedDataGenerator.DigestSha224);
+		}
+
+		[Test]
+		public void TestSha256WithRsaPss()
+		{
+			rsaPssTest("SHA256", CmsSignedDataGenerator.DigestSha256);
+		}
+
+		[Test]
+		public void TestSha384WithRsaPss()
+		{
+			rsaPssTest("SHA384", CmsSignedDataGenerator.DigestSha384);
+		}
+
+		[Test]
+		public void TestSha224WithRsaEncapsulated()
+		{
+			EncapsulatedTest(SignKP, SignCert, CmsSignedDataGenerator.DigestSha224);
+		}
+
+		[Test]
+		public void TestSha256WithRsaEncapsulated()
+		{
+			EncapsulatedTest(SignKP, SignCert, CmsSignedDataGenerator.DigestSha256);
+		}
+
+		[Test]
+		public void TestRipeMD128WithRsaEncapsulated()
+		{
+			EncapsulatedTest(SignKP, SignCert, CmsSignedDataGenerator.DigestRipeMD128);
+		}
+
+		[Test]
+		public void TestRipeMD160WithRsaEncapsulated()
+		{
+			EncapsulatedTest(SignKP, SignCert, CmsSignedDataGenerator.DigestRipeMD160);
+		}
+
+		[Test]
+		public void TestRipeMD256WithRsaEncapsulated()
+		{
+			EncapsulatedTest(SignKP, SignCert, CmsSignedDataGenerator.DigestRipeMD256);
+		}
+
+		[Test]
+		public void TestECDsaEncapsulated()
+		{
+			EncapsulatedTest(SignECDsaKP, SignECDsaCert, CmsSignedDataGenerator.DigestSha1);
+		}
+
+		[Test]
+		public void TestECDsaEncapsulatedSubjectKeyID()
+		{
+			SubjectKeyIDTest(SignECDsaKP, SignECDsaCert, CmsSignedDataGenerator.DigestSha1);
+		}
+
+		[Test]
+		public void TestECDsaSha224Encapsulated()
+		{
+			EncapsulatedTest(SignECDsaKP, SignECDsaCert, CmsSignedDataGenerator.DigestSha224);
+		}
+
+		[Test]
+		public void TestECDsaSha256Encapsulated()
+		{
+			EncapsulatedTest(SignECDsaKP, SignECDsaCert, CmsSignedDataGenerator.DigestSha256);
+		}
+
+		[Test]
+		public void TestECDsaSha384Encapsulated()
+		{
+			EncapsulatedTest(SignECDsaKP, SignECDsaCert, CmsSignedDataGenerator.DigestSha384);
+		}
+
+		[Test]
+		public void TestECDsaSha512Encapsulated()
+		{
+			EncapsulatedTest(SignECDsaKP, SignECDsaCert, CmsSignedDataGenerator.DigestSha512);
+		}
+
+		[Test]
+		public void TestECDsaSha512EncapsulatedWithKeyFactoryAsEC()
+		{
+//			X509EncodedKeySpec  pubSpec = new X509EncodedKeySpec(_signEcDsaKP.getPublic().getEncoded());
+			byte[] pubEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(SignECDsaKP.Public).GetDerEncoded();
+//			PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(_signEcDsaKP.Private.getEncoded());
+			byte[] privEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(SignECDsaKP.Private).GetDerEncoded();
+//			KeyFactory          keyFact = KeyFactory.GetInstance("EC", "BC");
+//			KeyPair             kp = new KeyPair(keyFact.generatePublic(pubSpec), keyFact.generatePrivate(privSpec));
+			AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(
+                PublicKeyFactory.CreateKey(pubEnc),
+				PrivateKeyFactory.CreateKey(privEnc));
+
+			EncapsulatedTest(kp, SignECDsaCert, CmsSignedDataGenerator.DigestSha512);
+		}
+
+		[Test]
+		public void TestDsaEncapsulated()
+		{
+			EncapsulatedTest(SignDsaKP, SignDsaCert, CmsSignedDataGenerator.DigestSha1);
+		}
+
+		[Test]
+		public void TestDsaEncapsulatedSubjectKeyID()
+		{
+			SubjectKeyIDTest(SignDsaKP, SignDsaCert, CmsSignedDataGenerator.DigestSha1);
+		}
+
+		[Test]
+		public void TestGost3411WithGost3410Encapsulated()
+		{
+			EncapsulatedTest(SignGostKP, SignGostCert, CmsSignedDataGenerator.DigestGost3411);
+		}
+
+		[Test]
+		public void TestGost3411WithECGost3410Encapsulated()
+		{
+			EncapsulatedTest(SignECGostKP, SignECGostCert, CmsSignedDataGenerator.DigestGost3411);
+		}
+
+		[Test]
+		public void TestSha1WithRsaCounterSignature()
+		{
+			IList certList = new ArrayList();
+			IList crlList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(SignCert);
+			certList.Add(OrigCert);
+
+			crlList.Add(SignCrl);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+			IX509Store x509Crls = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(crlList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(SignKP.Private, SignCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+			gen.AddCrls(x509Crls);
+
+			CmsSignedData s = gen.Generate(msg, true);
+			SignerInformation origSigner = (SignerInformation) new ArrayList(s.GetSignerInfos().GetSigners())[0];
+			SignerInformationStore counterSigners1 = gen.GenerateCounterSigners(origSigner);
+			SignerInformationStore counterSigners2 = gen.GenerateCounterSigners(origSigner);
+
+			SignerInformation signer1 = SignerInformation.AddCounterSigners(origSigner, counterSigners1);
+			SignerInformation signer2 = SignerInformation.AddCounterSigners(signer1, counterSigners2);
+
+			SignerInformationStore cs = signer2.GetCounterSignatures();
+			ICollection csSigners = cs.GetSigners();
+			Assert.AreEqual(2, csSigners.Count);
+
+			foreach (SignerInformation cSigner in csSigners)
+			{
+				ICollection certCollection = x509Certs.GetMatches(cSigner.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsNull(cSigner.SignedAttributes[Asn1.Pkcs.PkcsObjectIdentifiers.Pkcs9AtContentType]);
+				Assert.IsTrue(cSigner.Verify(cert));
+			}
+		}
+
+		private void rsaPssTest(
+			string	digestName,
+			string	digestOID)
+		{
+			IList certList = new ArrayList();
+			byte[] msgBytes = Encoding.ASCII.GetBytes("Hello World!");
+			CmsProcessable msg = new CmsProcessableByteArray(msgBytes);
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.EncryptionRsaPss, digestOID);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData s = gen.Generate(CmsSignedDataGenerator.Data, msg, false);
+
+			//
+			// compute expected content digest
+			//
+			IDigest md = DigestUtilities.GetDigest(digestName);
+			md.BlockUpdate(msgBytes, 0, msgBytes.Length);
+			byte[] expectedDigest = DigestUtilities.DoFinal(md);
+
+			VerifySignatures(s, expectedDigest);
+		}
+
+		private void SubjectKeyIDTest(
+			AsymmetricCipherKeyPair	signaturePair,
+			X509Certificate			signatureCert,
+			string					digestAlgorithm)
+		{
+			IList certList = new ArrayList();
+			IList crlList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(signatureCert);
+			certList.Add(OrigCert);
+
+			crlList.Add(SignCrl);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+			IX509Store x509Crls = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(crlList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(signaturePair.Private,
+				CmsTestUtil.CreateSubjectKeyId(signatureCert.GetPublicKey()).GetKeyIdentifier(),
+				digestAlgorithm);
+
+			gen.AddCertificates(x509Certs);
+			gen.AddCrls(x509Crls);
+
+			CmsSignedData s = gen.Generate(msg, true);
+
+			Assert.AreEqual(3, s.Version);
+
+			MemoryStream bIn = new MemoryStream(s.GetEncoded(), false);
+			Asn1InputStream aIn = new Asn1InputStream(bIn);
+
+			s = new CmsSignedData(ContentInfo.GetInstance(aIn.ReadObject()));
+
+			x509Certs = s.GetCertificates("Collection");
+			x509Crls = s.GetCrls("Collection");
+
+			SignerInformationStore signers = s.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+			}
+
+			//
+			// check for CRLs
+			//
+			ArrayList crls = new ArrayList(x509Crls.GetMatches(null));
+
+			Assert.AreEqual(1, crls.Count);
+
+			Assert.IsTrue(crls.Contains(SignCrl));
+
+			//
+			// try using existing signer
+			//
+
+			gen = new CmsSignedDataGenerator();
+
+			gen.AddSigners(s.GetSignerInfos());
+
+			gen.AddCertificates(s.GetCertificates("Collection"));
+			gen.AddCrls(s.GetCrls("Collection"));
+
+			s = gen.Generate(msg, true);
+
+			bIn = new MemoryStream(s.GetEncoded(), false);
+			aIn = new Asn1InputStream(bIn);
+
+			s = new CmsSignedData(ContentInfo.GetInstance(aIn.ReadObject()));
+
+			x509Certs = s.GetCertificates("Collection");
+			x509Crls = s.GetCrls("Collection");
+
+			signers = s.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+			}
+
+			CheckSignerStoreReplacement(s, signers);
+		}
+
+		private void EncapsulatedTest(
+			AsymmetricCipherKeyPair	signaturePair,
+			X509Certificate			signatureCert,
+			string					digestAlgorithm)
+		{
+			IList certList = new ArrayList();
+			IList crlList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(signatureCert);
+			certList.Add(OrigCert);
+
+			crlList.Add(SignCrl);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+			IX509Store x509Crls = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(crlList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(signaturePair.Private, signatureCert, digestAlgorithm);
+
+			gen.AddCertificates(x509Certs);
+			gen.AddCrls(x509Crls);
+
+			CmsSignedData s = gen.Generate(msg, true);
+
+			s = new CmsSignedData(ContentInfo.GetInstance(Asn1Object.FromByteArray(s.GetEncoded())));
+
+			x509Certs = s.GetCertificates("Collection");
+			x509Crls = s.GetCrls("Collection");
+
+			SignerInformationStore signers = s.GetSignerInfos();
+			ICollection c = signers.GetSigners();
+
+			foreach (SignerInformation signer in c)
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+			}
+
+			//
+			// check for CRLs
+			//
+			ArrayList crls = new ArrayList(x509Crls.GetMatches(null));
+
+			Assert.AreEqual(1, crls.Count);
+
+			Assert.IsTrue(crls.Contains(SignCrl));
+
+			//
+			// try using existing signer
+			//
+
+			gen = new CmsSignedDataGenerator();
+
+			gen.AddSigners(s.GetSignerInfos());
+
+			gen.AddCertificates(s.GetCertificates("Collection"));
+			gen.AddCrls(s.GetCrls("Collection"));
+
+			s = gen.Generate(msg, true);
+
+			s = new CmsSignedData(ContentInfo.GetInstance(Asn1Object.FromByteArray(s.GetEncoded())));
+
+			x509Certs = s.GetCertificates("Collection");
+			x509Crls = s.GetCrls("Collection");
+
+			signers = s.GetSignerInfos();
+			c = signers.GetSigners();
+
+			foreach (SignerInformation signer in c)
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+			}
+
+			CheckSignerStoreReplacement(s, signers);
+		}
+
+		//
+		// signerInformation store replacement test.
+		//
+		private void CheckSignerStoreReplacement(
+			CmsSignedData orig,
+			SignerInformationStore signers)
+		{
+			CmsSignedData s = CmsSignedData.ReplaceSigners(orig, signers);
+
+			IX509Store x509Certs = s.GetCertificates("Collection");
+
+			signers = s.GetSignerInfos();
+			ICollection c = signers.GetSigners();
+
+			foreach (SignerInformation signer in c)
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+			}
+		}
+
+		[Test]
+		public void TestUnsortedAttributes()
+		{
+			CmsSignedData s = new CmsSignedData(new CmsProcessableByteArray(disorderedMessage), disorderedSet);
+
+			IX509Store x509Certs = s.GetCertificates("Collection");
+
+			SignerInformationStore	signers = s.GetSignerInfos();
+			ICollection				c = signers.GetSigners();
+
+			foreach (SignerInformation signer in c)
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate) certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+			}
+		}
+
+		[Test]
+		public void TestNullContentWithSigner()
+		{
+			IList certList = new ArrayList();
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData s = gen.Generate(null, false);
+
+			s = new CmsSignedData(ContentInfo.GetInstance(Asn1Object.FromByteArray(s.GetEncoded())));
+
+			VerifySignatures(s);
+		}
+
+		[Test]
+		public void TestWithAttributeCertificate()
+		{
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(SignDsaCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			IX509AttributeCertificate attrCert = CmsTestUtil.GetAttributeCertificate();
+
+			ArrayList attrCerts = new ArrayList();
+			attrCerts.Add(attrCert);
+
+			IX509Store store = X509StoreFactory.Create(
+				"AttributeCertificate/Collection",
+				new X509CollectionStoreParameters(attrCerts));
+
+			gen.AddAttributeCertificates(store);
+
+			CmsSignedData sd = gen.Generate(msg);
+
+			Assert.AreEqual(4, sd.Version);
+
+			store = sd.GetAttributeCertificates("Collection");
+
+			ArrayList coll = new ArrayList(store.GetMatches(null));
+
+			Assert.AreEqual(1, coll.Count);
+
+			Assert.IsTrue(coll.Contains(attrCert));
+
+			//
+			// create new certstore
+			//
+			certList = new ArrayList();
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			//
+			// replace certs
+			//
+			sd = CmsSignedData.ReplaceCertificatesAndCrls(sd, x509Certs, null, null);
+
+			VerifySignatures(sd);
+		}
+
+		[Test]
+		public void TestCertStoreReplacement()
+		{
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(SignDsaCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData sd = gen.Generate(msg);
+
+			//
+			// create new certstore
+			//
+			certList = new ArrayList();
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			//
+			// replace certs
+			//
+			sd = CmsSignedData.ReplaceCertificatesAndCrls(sd, x509Certs, null, null);
+
+			VerifySignatures(sd);
+		}
+
+		[Test]
+		public void TestEncapsulatedCertStoreReplacement()
+		{
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(SignDsaCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData sd = gen.Generate(msg, true);
+
+			//
+			// create new certstore
+			//
+			certList = new ArrayList();
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			//
+			// replace certs
+			//
+			sd = CmsSignedData.ReplaceCertificatesAndCrls(sd, x509Certs, null, null);
+
+			VerifySignatures(sd);
+		}
+
+		[Test]
+		public void TestCertOrdering1()
+		{
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+			certList.Add(SignDsaCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData sd = gen.Generate(msg, true);
+
+			x509Certs = sd.GetCertificates("Collection");
+			ArrayList a = new ArrayList(x509Certs.GetMatches(null));
+
+			Assert.AreEqual(3, a.Count);
+			Assert.AreEqual(OrigCert, a[0]);
+			Assert.AreEqual(SignCert, a[1]);
+			Assert.AreEqual(SignDsaCert, a[2]);
+		}
+
+		[Test]
+		public void TestCertOrdering2()
+		{
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(SignCert);
+			certList.Add(SignDsaCert);
+			certList.Add(OrigCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+	
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData sd = gen.Generate(msg, true);
+
+			x509Certs = sd.GetCertificates("Collection");
+			ArrayList a = new ArrayList(x509Certs.GetMatches(null));
+
+			Assert.AreEqual(3, a.Count);
+			Assert.AreEqual(SignCert, a[0]);
+			Assert.AreEqual(SignDsaCert, a[1]);
+			Assert.AreEqual(OrigCert, a[2]);
+		}
+
+		[Test]
+		public void TestSignerStoreReplacement()
+		{
+			IList certList = new ArrayList();
+			CmsProcessable msg = new CmsProcessableByteArray(Encoding.ASCII.GetBytes("Hello World!"));
+
+			certList.Add(OrigCert);
+			certList.Add(SignCert);
+
+			IX509Store x509Certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha1);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData original = gen.Generate(msg, true);
+
+			//
+			// create new Signer
+			//
+			gen = new CmsSignedDataGenerator();
+
+			gen.AddSigner(OrigKP.Private, OrigCert, CmsSignedDataGenerator.DigestSha224);
+
+			gen.AddCertificates(x509Certs);
+
+			CmsSignedData newSD = gen.Generate(msg, true);
+
+			//
+			// replace signer
+			//
+			CmsSignedData sd = CmsSignedData.ReplaceSigners(original, newSD.GetSignerInfos());
+
+			IEnumerator signerEnum = sd.GetSignerInfos().GetSigners().GetEnumerator();
+			signerEnum.MoveNext();
+			SignerInformation signer = (SignerInformation) signerEnum.Current;
+
+			Assert.AreEqual(CmsSignedDataGenerator.DigestSha224, signer.DigestAlgOid);
+
+			// we use a parser here as it requires the digests to be correct in the digest set, if it
+			// isn't we'll get a NullPointerException
+			CmsSignedDataParser sp = new CmsSignedDataParser(sd.GetEncoded());
+
+			sp.GetSignedContent().Drain();
+
+			VerifySignatures(sp);
+		}
+
+		[Test]
+		public void TestEncapsulatedSamples()
+		{
+			doTestSample("PSSSignDataSHA1Enc.sig");
+			doTestSample("PSSSignDataSHA256Enc.sig");
+			doTestSample("PSSSignDataSHA512Enc.sig");
+		}
+
+		[Test]
+		public void TestSamples()
+		{
+			doTestSample("PSSSignData.data", "PSSSignDataSHA1.sig");
+			doTestSample("PSSSignData.data", "PSSSignDataSHA256.sig");
+			doTestSample("PSSSignData.data", "PSSSignDataSHA512.sig");
+		}
+
+		[Test]
+		public void TestCounterSig()
+		{
+			CmsSignedData sig = new CmsSignedData(GetInput("counterSig.p7m"));
+
+			SignerInformationStore ss = sig.GetSignerInfos();
+			ArrayList signers = new ArrayList(ss.GetSigners());
+
+			SignerInformationStore cs = ((SignerInformation)signers[0]).GetCounterSignatures();
+			ArrayList csSigners = new ArrayList(cs.GetSigners());
+			Assert.AreEqual(1, csSigners.Count);
+
+			foreach (SignerInformation cSigner in csSigners)
+			{
+				ArrayList certCollection = new ArrayList(
+					sig.GetCertificates("Collection").GetMatches(cSigner.SignerID));
+
+				X509Certificate cert = (X509Certificate)certCollection[0];
+
+				Assert.IsNull(cSigner.SignedAttributes[Asn1.Pkcs.PkcsObjectIdentifiers.Pkcs9AtContentType]);
+				Assert.IsTrue(cSigner.Verify(cert));
+			}
+
+			VerifySignatures(sig);
+		}
+
+		private void doTestSample(
+			string sigName)
+		{
+			CmsSignedData sig = new CmsSignedData(GetInput(sigName));
+			VerifySignatures(sig);
+		}
+
+		private void doTestSample(
+			string	messageName,
+			string	sigName)
+		{
+			CmsSignedData sig = new CmsSignedData(
+				new CmsProcessableByteArray(GetInput(messageName)),
+				GetInput(sigName));
+
+			VerifySignatures(sig);
+		}
+
+		private byte[] GetInput(
+			string name)
+		{
+			return Streams.ReadAll(SimpleTest.GetTestDataAsStream("cms.sigs." + name));
+		}
+
+		[Test]
+		public void TestForMultipleCounterSignatures()
+		{
+			CmsSignedData sd = new CmsSignedData(xtraCounterSig);
+
+			foreach (SignerInformation sigI in sd.GetSignerInfos().GetSigners())
+			{
+				SignerInformationStore counter = sigI.GetCounterSignatures();
+				IList sigs = new ArrayList(counter.GetSigners());
+
+				Assert.AreEqual(2, sigs.Count);
+			}
+		}
+
+		private void VerifySignatures(
+			CmsSignedDataParser sp)
+		{
+			IX509Store x509Certs = sp.GetCertificates("Collection");
+			SignerInformationStore signers = sp.GetSignerInfos();
+
+			foreach (SignerInformation signer in signers.GetSigners())
+			{
+				ICollection certCollection = x509Certs.GetMatches(signer.SignerID);
+
+				IEnumerator certEnum = certCollection.GetEnumerator();
+				certEnum.MoveNext();
+				X509Certificate cert = (X509Certificate)certEnum.Current;
+
+				Assert.IsTrue(signer.Verify(cert));
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/examples/DESExample.cs b/crypto/test/src/crypto/examples/DESExample.cs
new file mode 100644
index 000000000..c026d3159
--- /dev/null
+++ b/crypto/test/src/crypto/examples/DESExample.cs
@@ -0,0 +1,396 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Examples
+{
+	/**
+	* DesExample is a simple DES based encryptor/decryptor.
+	* <p>
+	* The program is command line driven, with the input
+	* and output files specified on the command line.
+	* <pre>
+	* java org.bouncycastle.crypto.examples.DesExample infile outfile [keyfile]
+	* </pre>
+	* A new key is generated for each encryption, if key is not specified,
+	* then the example will assume encryption is required, and as output
+	* create deskey.dat in the current directory.  This key is a hex
+	* encoded byte-stream that is used for the decryption.  The output
+	* file is Hex encoded, 60 characters wide text file.
+	* </p>
+	* <p>
+	* When encrypting;
+	* <ul>
+	*  <li>the infile is expected to be a byte stream (text or binary)</li>
+	*  <li>there is no keyfile specified on the input line</li>
+	* </ul>
+	* </p>
+	* <p>
+	* When decrypting;
+	*  <li>the infile is expected to be the 60 character wide base64 
+	*    encoded file</li>
+	*  <li>the keyfile is expected to be a base64 encoded file</li>
+	* </p>
+	* <p>
+	* This example shows how to use the light-weight API, DES and
+	* the filesystem for message encryption and decryption.
+	* </p>
+	*/
+	public class DesExample
+	{
+		// Encrypting or decrypting ?
+		private bool encrypt = true;
+
+		// To hold the initialised DESede cipher
+		private PaddedBufferedBlockCipher cipher = null;
+
+		// The input stream of bytes to be processed for encryption
+		private Stream inStr = null;
+
+		// The output stream of bytes to be procssed
+		private Stream outStr = null;
+
+		// The key
+		private byte[] key = null;
+
+		/*
+		* start the application
+		*/
+		public static int Main(
+			string[] args)
+		{
+			bool encrypt = true;
+			string infile = null;
+			string outfile = null;
+			string keyfile = null;
+
+			if (args.Length < 2)
+			{
+//				Console.Error.WriteLine("Usage: java " + typeof(DesExample).Name + " infile outfile [keyfile]");
+				Console.Error.WriteLine("Usage: " + typeof(DesExample).Name + " infile outfile [keyfile]");
+				return 1;
+			}
+
+			keyfile = "deskey.dat";
+			infile = args[0];
+			outfile = args[1];
+
+			if (args.Length > 2)
+			{
+				encrypt = false;
+				keyfile = args[2];
+			}
+
+			try
+			{
+				DesExample de = new DesExample(infile, outfile, keyfile, encrypt);
+				de.process();
+			}
+			catch (Exception)
+			{
+				return 1;
+			}
+
+			return 0;
+		}
+
+		// Default constructor, used for the usage message
+		public DesExample()
+		{
+		}
+
+		/*
+		* Constructor, that takes the arguments appropriate for
+		* processing the command line directives.
+		*/
+		public DesExample(
+			string	infile,
+			string	outfile,
+			string	keyfile,
+			bool	encrypt)
+		{
+			/* 
+			* First, determine that infile & keyfile exist as appropriate.
+			*
+			* This will also create the BufferedInputStream as required
+			* for reading the input file.  All input files are treated
+			* as if they are binary, even if they contain text, it's the
+			* bytes that are encrypted.
+			*/
+			this.encrypt = encrypt;
+			try
+			{
+				inStr = File.OpenRead(infile);
+			}
+			catch (FileNotFoundException e)
+			{
+				Console.Error.WriteLine("Input file not found ["+infile+"]");
+				throw e;
+			}
+
+			try
+			{
+				outStr = File.Create(outfile);
+			}
+			catch (IOException e)
+			{
+				Console.Error.WriteLine("Output file not created ["+outfile+"]");
+				throw e;
+			}
+
+			if (encrypt)
+			{
+				try
+				{
+					/*
+					* The process of creating a new key requires a 
+					* number of steps.
+					*
+					* First, create the parameters for the key generator
+					* which are a secure random number generator, and
+					* the length of the key (in bits).
+					*/
+					SecureRandom sr = new SecureRandom();
+
+					KeyGenerationParameters kgp = new KeyGenerationParameters(
+						sr, 
+						DesEdeParameters.DesEdeKeyLength * 8);
+
+					/*
+					* Second, initialise the key generator with the parameters
+					*/
+					DesEdeKeyGenerator kg = new DesEdeKeyGenerator();
+					kg.Init(kgp);
+
+					/*
+					* Third, and finally, generate the key
+					*/
+					key = kg.GenerateKey();
+
+					/*
+					* We can now output the key to the file, but first
+					* hex Encode the key so that we can have a look
+					* at it with a text editor if we so desire
+					*/
+					using (Stream keystream = File.Create(keyfile))
+					{
+						Hex.Encode(key, keystream);
+					}
+				}
+				catch (IOException e)
+				{
+					Console.Error.WriteLine("Could not decryption create key file "+
+										"["+keyfile+"]");
+					throw e;
+				}
+			}
+			else
+			{
+				try
+				{
+					// TODO This block is a bit dodgy
+
+					// read the key, and Decode from hex encoding
+					Stream keystream = File.OpenRead(keyfile);
+//					int len = keystream.available();
+					int len = (int) keystream.Length;
+					byte[] keyhex = new byte[len];
+					keystream.Read(keyhex, 0, len);
+					key = Hex.Decode(keyhex);
+				}
+				catch (IOException e)
+				{
+					Console.Error.WriteLine("Decryption key file not found, "
+						+ "or not valid ["+keyfile+"]");
+					throw e;
+				}
+			}
+		}
+
+		private void process()
+		{
+			/* 
+			* Setup the DESede cipher engine, create a PaddedBufferedBlockCipher
+			* in CBC mode.
+			*/
+			cipher = new PaddedBufferedBlockCipher(
+				new CbcBlockCipher(new DesEdeEngine()));
+
+			/*
+			* The input and output streams are currently set up
+			* appropriately, and the key bytes are ready to be
+			* used.
+			*
+			*/
+
+			if (encrypt)
+			{
+				performEncrypt(key);
+			}
+			else
+			{
+				performDecrypt(key);
+			}
+
+			// after processing clean up the files
+			try
+			{
+				inStr.Close();
+				outStr.Flush();
+				outStr.Close();
+			}
+			catch (IOException)
+			{
+			}
+		}
+
+		/*
+		* This method performs all the encryption and writes
+		* the cipher text to the buffered output stream created
+		* previously.
+		*/
+		private void performEncrypt(byte[] key)
+		{
+			// initialise the cipher with the key bytes, for encryption
+			cipher.Init(true, new KeyParameter(key));
+
+			/*
+			* Create some temporary byte arrays for use in
+			* encryption, make them a reasonable size so that
+			* we don't spend forever reading small chunks from
+			* a file.
+			*
+			* There is no particular reason for using getBlockSize()
+			* to determine the size of the input chunk.  It just
+			* was a convenient number for the example.  
+			*/
+			// int inBlockSize = cipher.getBlockSize() * 5;
+			int inBlockSize = 47;
+			int outBlockSize = cipher.GetOutputSize(inBlockSize);
+
+			byte[] inblock = new byte[inBlockSize];
+			byte[] outblock = new byte[outBlockSize];
+
+			/* 
+			* now, read the file, and output the chunks
+			*/
+			try
+			{
+				int inL;
+				int outL;
+				while ((inL = inStr.Read(inblock, 0, inBlockSize)) > 0)
+				{
+					outL = cipher.ProcessBytes(inblock, 0, inL, outblock, 0);
+
+					/*
+					* Before we write anything out, we need to make sure
+					* that we've got something to write out. 
+					*/
+					if (outL > 0)
+					{
+						Hex.Encode(outblock, 0, outL, outStr);
+						outStr.WriteByte((byte)'\n');
+					}
+				}
+
+				try
+				{
+					/*
+					* Now, process the bytes that are still buffered
+					* within the cipher.
+					*/
+					outL = cipher.DoFinal(outblock, 0);
+					if (outL > 0)
+					{
+						Hex.Encode(outblock, 0, outL, outStr);
+						outStr.WriteByte((byte) '\n');
+					}
+				}
+				catch (CryptoException)
+				{
+
+				}
+			}
+			catch (IOException ioeread)
+			{
+				Console.Error.WriteLine(ioeread.StackTrace);
+			}
+		}
+
+		/*
+		* This method performs all the decryption and writes
+		* the plain text to the buffered output stream created
+		* previously.
+		*/
+		private void performDecrypt(byte[] key)
+		{    
+			// initialise the cipher for decryption
+			cipher.Init(false, new KeyParameter(key));
+
+			/* 
+			* As the decryption is from our preformatted file,
+			* and we know that it's a hex encoded format, then
+			* we wrap the InputStream with a BufferedReader
+			* so that we can read it easily.
+			*/
+//			BufferedReader br = new BufferedReader(new StreamReader(inStr));
+			StreamReader br = new StreamReader(inStr); // 'inStr' already buffered
+
+			/* 
+			* now, read the file, and output the chunks
+			*/
+			try
+			{
+				int outL;
+				byte[] inblock = null;
+				byte[] outblock = null;
+				string rv = null;
+				while ((rv = br.ReadLine()) != null)
+				{
+					inblock = Hex.Decode(rv);
+					outblock = new byte[cipher.GetOutputSize(inblock.Length)];
+
+					outL = cipher.ProcessBytes(inblock, 0, inblock.Length, outblock, 0);
+					/*
+					* Before we write anything out, we need to make sure
+					* that we've got something to write out. 
+					*/
+					if (outL > 0)
+					{
+						outStr.Write(outblock, 0, outL);
+					}
+				}
+
+				try
+				{
+					/*
+					* Now, process the bytes that are still buffered
+					* within the cipher.
+					*/
+					outL = cipher.DoFinal(outblock, 0);
+					if (outL > 0)
+					{
+						outStr.Write(outblock, 0, outL);
+					}
+				}
+				catch (CryptoException)
+				{
+
+				}
+			}
+			catch (IOException ioeread)
+			{
+				Console.Error.WriteLine(ioeread.StackTrace);
+			}
+		}
+
+	}
+}
diff --git a/crypto/test/src/crypto/io/test/AllTests.cs b/crypto/test/src/crypto/io/test/AllTests.cs
new file mode 100644
index 000000000..0296a2dc0
--- /dev/null
+++ b/crypto/test/src/crypto/io/test/AllTests.cs
@@ -0,0 +1,27 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Crypto.IO.Tests
+{
+	public class AllTests
+	{
+		public static void Main(
+			string[] args)
+		{
+//            junit.textui.TestRunner.run(suite());
+			EventListener el = new NullListener();
+			suite().Run(el);
+		}
+
+		public static TestSuite suite()
+		{
+			TestSuite suite = new TestSuite("IO tests");
+
+			suite.Add(new CipherStreamTest());
+
+			return suite;
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/io/test/CipherStreamTest.cs b/crypto/test/src/crypto/io/test/CipherStreamTest.cs
new file mode 100644
index 000000000..8f03c5770
--- /dev/null
+++ b/crypto/test/src/crypto/io/test/CipherStreamTest.cs
@@ -0,0 +1,166 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.IO.Tests
+{
+	[TestFixture]
+	public class CipherStreamTest
+	{
+		private const string DATA = "This will be encrypted and then decrypted and checked for correctness";
+
+		[Test]
+		public void TestEncryptDecryptA()
+		{
+			byte[] dataBytes = Encoding.ASCII.GetBytes(DATA);
+			byte[] encryptedDataBytes = encryptOnWrite(dataBytes);
+
+			byte[] decryptedDataBytes = decryptOnRead(encryptedDataBytes);
+			string decryptedData = Encoding.ASCII.GetString(decryptedDataBytes, 0, decryptedDataBytes.Length);
+			Assert.AreEqual(DATA, decryptedData);
+		}
+
+		[Test]
+		public void TestEncryptDecryptB()
+		{
+			byte[] dataBytes = Encoding.ASCII.GetBytes(DATA);
+			byte[] encryptedDataBytes = encryptOnRead(dataBytes);
+
+			byte[] decryptedDataBytes = decryptOnWrite(encryptedDataBytes);
+			string decryptedData = Encoding.ASCII.GetString(decryptedDataBytes, 0, decryptedDataBytes.Length);
+			Assert.AreEqual(DATA, decryptedData);
+		}
+
+		[Test]
+		public void TestEncryptDecryptC()
+		{
+			byte[] dataBytes = Encoding.ASCII.GetBytes(DATA);
+			byte[] encryptedDataBytes = encryptOnWrite(dataBytes);
+
+			byte[] decryptedDataBytes = decryptOnWrite(encryptedDataBytes);
+			string decryptedData = Encoding.ASCII.GetString(decryptedDataBytes, 0, decryptedDataBytes.Length);
+			Assert.AreEqual(DATA, decryptedData);
+		}
+
+		[Test]
+		public void TestEncryptDecryptD()
+		{
+			byte[] dataBytes = Encoding.ASCII.GetBytes(DATA);
+			byte[] encryptedDataBytes = encryptOnRead(dataBytes);
+
+			byte[] decryptedDataBytes = decryptOnRead(encryptedDataBytes);
+			string decryptedData = Encoding.ASCII.GetString(decryptedDataBytes, 0, decryptedDataBytes.Length);
+			Assert.AreEqual(DATA, decryptedData);
+		}
+
+		private byte[] encryptOnWrite(byte[] dataBytes)
+		{
+			MemoryStream encryptedDataStream = new MemoryStream();
+			IBufferedCipher outCipher = createCipher(true);
+			CipherStream outCipherStream = new CipherStream(encryptedDataStream, null, outCipher);
+			outCipherStream.Write(dataBytes, 0, dataBytes.Length);
+			Assert.AreEqual(0L, encryptedDataStream.Position % outCipher.GetBlockSize());
+
+			outCipherStream.Close();
+			byte[] encryptedDataBytes = encryptedDataStream.ToArray();
+			Assert.AreEqual(dataBytes.Length, encryptedDataBytes.Length);
+
+			return encryptedDataBytes;
+		}
+
+		private byte[] encryptOnRead(byte[] dataBytes)
+		{
+			MemoryStream dataStream = new MemoryStream(dataBytes, false);
+			MemoryStream encryptedDataStream = new MemoryStream();
+			IBufferedCipher inCipher = createCipher(true);
+			CipherStream inCipherStream = new CipherStream(dataStream, inCipher, null);
+
+			int ch;
+			while ((ch = inCipherStream.ReadByte()) >= 0)
+			{
+				encryptedDataStream.WriteByte((byte) ch);
+			}
+
+			encryptedDataStream.Close();
+			inCipherStream.Close();
+
+			byte[] encryptedDataBytes = encryptedDataStream.ToArray();
+			Assert.AreEqual(dataBytes.Length, encryptedDataBytes.Length);
+
+			return encryptedDataBytes;
+		}
+
+		private byte[] decryptOnRead(byte[] encryptedDataBytes)
+		{
+			MemoryStream encryptedDataStream = new MemoryStream(encryptedDataBytes, false);
+			MemoryStream dataStream = new MemoryStream();
+			IBufferedCipher inCipher = createCipher(false);
+			CipherStream inCipherStream = new CipherStream(encryptedDataStream, inCipher, null);
+
+			int ch;
+			while ((ch = inCipherStream.ReadByte()) >= 0)
+			{
+				dataStream.WriteByte((byte) ch);
+			}
+
+			inCipherStream.Close();
+			dataStream.Close();
+
+			byte[] dataBytes = dataStream.ToArray();
+			Assert.AreEqual(encryptedDataBytes.Length, dataBytes.Length);
+
+			return dataBytes;
+		}
+
+		private byte[] decryptOnWrite(byte[] encryptedDataBytes)
+		{
+			MemoryStream encryptedDataStream = new MemoryStream(encryptedDataBytes, false);
+			MemoryStream dataStream = new MemoryStream();
+			IBufferedCipher outCipher = createCipher(false);
+			CipherStream outCipherStream = new CipherStream(dataStream, null, outCipher);
+
+			int ch;
+			while ((ch = encryptedDataStream.ReadByte()) >= 0)
+			{
+				outCipherStream.WriteByte((byte) ch);
+			}
+
+			outCipherStream.Close();
+			encryptedDataStream.Close();
+
+			byte[] dataBytes = dataStream.ToArray();
+			Assert.AreEqual(encryptedDataBytes.Length, dataBytes.Length);
+
+			return dataBytes;
+		}
+
+		private IBufferedCipher createCipher(bool forEncryption)
+		{
+//			IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CFB/NoPadding");
+
+			IBlockCipher blockCipher = new AesEngine();
+			int bits = 8 * blockCipher.GetBlockSize(); // TODO Is this right?
+			blockCipher = new CfbBlockCipher(blockCipher, bits);
+			IBufferedCipher cipher = new BufferedBlockCipher(blockCipher);
+
+//			SecureRandom random = new SecureRandom();
+			byte[] keyBytes = new byte[32];
+			//random.NextBytes(keyBytes);
+			KeyParameter key = new KeyParameter(keyBytes);
+
+			byte[] iv = new byte[cipher.GetBlockSize()];
+			//random.NextBytes(iv);
+
+			cipher.Init(forEncryption, new ParametersWithIV(key, iv));
+
+			return cipher;
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/AESFastTest.cs b/crypto/test/src/crypto/test/AESFastTest.cs
new file mode 100644
index 000000000..5513a0e78
--- /dev/null
+++ b/crypto/test/src/crypto/test/AESFastTest.cs
@@ -0,0 +1,168 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* Test vectors from the NIST standard tests and Brian Gladman's vector set
+	* <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">
+	* http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+	*/
+	[TestFixture]
+	public class AesFastTest
+		: CipherTest
+	{
+		static SimpleTest[]  tests =
+		{
+			new BlockCipherVectorTest(0, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+					"00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+			new BlockCipherVectorTest(1, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000080")),
+					"00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+			new BlockCipherMonteCarloTest(2, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+					"00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+			new BlockCipherMonteCarloTest(3, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")),
+					"355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+			new BlockCipherVectorTest(4, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+			new BlockCipherMonteCarloTest(5, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")),
+					"F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+			new BlockCipherVectorTest(6, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+			new BlockCipherMonteCarloTest(7, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")),
+					"C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"),
+			new BlockCipherVectorTest(8, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+					"00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+			new BlockCipherVectorTest(9, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000080")),
+					"00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+			new BlockCipherMonteCarloTest(10, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+					"00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+			new BlockCipherMonteCarloTest(11, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")),
+					"355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+			new BlockCipherVectorTest(12, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+			new BlockCipherMonteCarloTest(13, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")),
+					"F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+			new BlockCipherVectorTest(14, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+			new BlockCipherMonteCarloTest(15, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")),
+					"C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"),
+			new BlockCipherVectorTest(16, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+					"00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+			new BlockCipherVectorTest(17, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000080")),
+					"00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+			new BlockCipherMonteCarloTest(18, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+					"00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+			new BlockCipherMonteCarloTest(19, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")),
+					"355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+			new BlockCipherVectorTest(20, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+			new BlockCipherMonteCarloTest(21, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")),
+					"F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+			new BlockCipherVectorTest(22, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+			new BlockCipherMonteCarloTest(23, 10000, new AesFastEngine(),
+					new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")),
+					"C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168")
+		};
+
+		private IBlockCipher _engine = new AesFastEngine();
+
+		public AesFastTest()
+			: base(tests, new AesFastEngine(), new KeyParameter(new byte[16]))
+		{
+		}
+
+		public override string Name
+		{
+			get
+			{
+				return "AESFast";
+			}
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			byte[] keyBytes = new byte[16];
+
+			_engine.Init(true, new KeyParameter(keyBytes));
+
+			//
+			// init tests
+			//
+			try
+			{
+				byte[] dudKey = new byte[6];
+
+				_engine.Init(true, new KeyParameter(dudKey));
+
+				Fail("failed key length check");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+
+			try
+			{
+				byte[] iv = new byte[16];
+
+				_engine.Init(true, new ParametersWithIV(null, iv));
+
+				Fail("failed parameter check");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			AesFastTest test = new AesFastTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/AESLightTest.cs b/crypto/test/src/crypto/test/AESLightTest.cs
new file mode 100644
index 000000000..0b5777ba1
--- /dev/null
+++ b/crypto/test/src/crypto/test/AESLightTest.cs
@@ -0,0 +1,168 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* Test vectors from the NIST standard tests and Brian Gladman's vector set
+	* <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">
+	* http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+	*/
+	[TestFixture]
+	public class AesLightTest
+		: CipherTest
+	{
+		static SimpleTest[]  tests =
+		{
+			new BlockCipherVectorTest(0, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+					"00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+			new BlockCipherVectorTest(1, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000080")),
+					"00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+			new BlockCipherMonteCarloTest(2, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+					"00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+			new BlockCipherMonteCarloTest(3, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")),
+					"355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+			new BlockCipherVectorTest(4, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+			new BlockCipherMonteCarloTest(5, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")),
+					"F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+			new BlockCipherVectorTest(6, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+			new BlockCipherMonteCarloTest(7, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")),
+					"C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"),
+			new BlockCipherVectorTest(8, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+					"00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+			new BlockCipherVectorTest(9, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000080")),
+					"00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+			new BlockCipherMonteCarloTest(10, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+					"00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+			new BlockCipherMonteCarloTest(11, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")),
+					"355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+			new BlockCipherVectorTest(12, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+			new BlockCipherMonteCarloTest(13, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")),
+					"F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+			new BlockCipherVectorTest(14, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+			new BlockCipherMonteCarloTest(15, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")),
+					"C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"),
+			new BlockCipherVectorTest(16, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+					"00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+			new BlockCipherVectorTest(17, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000080")),
+					"00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+			new BlockCipherMonteCarloTest(18, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+					"00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+			new BlockCipherMonteCarloTest(19, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")),
+					"355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+			new BlockCipherVectorTest(20, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+			new BlockCipherMonteCarloTest(21, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")),
+					"F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+			new BlockCipherVectorTest(22, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+					"80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+			new BlockCipherMonteCarloTest(23, 10000, new AesLightEngine(),
+					new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")),
+					"C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168")
+		};
+
+		private IBlockCipher _engine = new AesLightEngine();
+
+		public AesLightTest()
+			: base(tests, new AesLightEngine(), new KeyParameter(new byte[16]))
+		{
+		}
+
+		public override string Name
+		{
+			get
+			{
+				return "AESLight";
+			}
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			byte[] keyBytes = new byte[16];
+
+			_engine.Init(true, new KeyParameter(keyBytes));
+
+			//
+			// init tests
+			//
+			try
+			{
+				byte[] dudKey = new byte[6];
+
+				_engine.Init(true, new KeyParameter(dudKey));
+
+				Fail("failed key length check");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+
+			try
+			{
+				byte[] iv = new byte[16];
+
+				_engine.Init(true, new ParametersWithIV(null, iv));
+
+				Fail("failed parameter check");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			AesLightTest test = new AesLightTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/AESTest.cs b/crypto/test/src/crypto/test/AESTest.cs
new file mode 100644
index 000000000..7b8fc34cf
--- /dev/null
+++ b/crypto/test/src/crypto/test/AESTest.cs
@@ -0,0 +1,178 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> Test vectors from the NIST standard tests and Brian Gladman's vector set
+    /// <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">
+    /// http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+    /// </summary>
+    [TestFixture]
+    public class AesTest : CipherTest
+    {
+        internal static SimpleTest[] tests = new SimpleTest[]{
+            new BlockCipherVectorTest(0, new AesEngine(), new KeyParameter(Hex.Decode("80000000000000000000000000000000")), "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+            new BlockCipherVectorTest(1, new AesEngine(), new KeyParameter(Hex.Decode("00000000000000000000000000000080")), "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+            new BlockCipherMonteCarloTest(2, 10000, new AesEngine(), new KeyParameter(Hex.Decode("00000000000000000000000000000000")), "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+            new BlockCipherMonteCarloTest(3, 10000, new AesEngine(), new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")), "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+            new BlockCipherVectorTest(4, new AesEngine(), new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+            new BlockCipherMonteCarloTest(5, 10000, new AesEngine(), new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+            new BlockCipherVectorTest(6, new AesEngine(), new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+            new BlockCipherMonteCarloTest(7, 10000, new AesEngine(), new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"),
+            new BlockCipherVectorTest(8, new AesEngine(), new KeyParameter(Hex.Decode("80000000000000000000000000000000")), "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+            new BlockCipherVectorTest(9, new AesEngine(), new KeyParameter(Hex.Decode("00000000000000000000000000000080")), "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+            new BlockCipherMonteCarloTest(10, 10000, new AesEngine(), new KeyParameter(Hex.Decode("00000000000000000000000000000000")), "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+            new BlockCipherMonteCarloTest(11, 10000, new AesEngine(), new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")), "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+            new BlockCipherVectorTest(12, new AesEngine(), new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+            new BlockCipherMonteCarloTest(13, 10000, new AesEngine(), new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+            new BlockCipherVectorTest(14, new AesEngine(), new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+            new BlockCipherMonteCarloTest(15, 10000, new AesEngine(), new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"),
+            new BlockCipherVectorTest(16, new AesEngine(), new KeyParameter(Hex.Decode("80000000000000000000000000000000")), "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+            new BlockCipherVectorTest(17, new AesEngine(), new KeyParameter(Hex.Decode("00000000000000000000000000000080")), "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+            new BlockCipherMonteCarloTest(18, 10000, new AesEngine(), new KeyParameter(Hex.Decode("00000000000000000000000000000000")), "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+            new BlockCipherMonteCarloTest(19, 10000, new AesEngine(), new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")), "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+            new BlockCipherVectorTest(20, new AesEngine(), new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+            new BlockCipherMonteCarloTest(21, 10000, new AesEngine(), new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+            new BlockCipherVectorTest(22, new AesEngine(), new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")), "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+            new BlockCipherMonteCarloTest(23, 10000, new AesEngine(), new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168")};
+
+        public override string Name { get { return "AES"; } }
+
+		public AesTest()
+			: base(tests, new AesEngine(), new KeyParameter(new byte[16]))
+		{
+		}
+
+		private ITestResult WrapTest(int id, byte[] kek, byte[] input, byte[] outBytes)
+        {
+            IWrapper wrapper = new AesWrapEngine();
+
+            wrapper.Init(true, new KeyParameter(kek));
+
+            try
+            {
+                byte[] cText = wrapper.Wrap(input, 0, input.Length);
+
+				if (!Arrays.AreEqual(cText, outBytes))
+                {
+                    return new SimpleTestResult(false, Name + ": failed wrap test " + id
+						+ " expected " + Hex.ToHexString(outBytes)
+						+ " got " + Hex.ToHexString(cText));
+                }
+            }
+            catch (System.Exception e)
+            {
+                return new SimpleTestResult(false, Name + ": failed wrap test exception " + e.ToString());
+            }
+
+            wrapper.Init(false, new KeyParameter(kek));
+
+            try
+            {
+                byte[] pText = wrapper.Unwrap(outBytes, 0, outBytes.Length);
+                if (!Arrays.AreEqual(pText, input))
+                {
+                    return new SimpleTestResult(false, Name + ": failed unwrap test " + id
+						+ " expected " + Hex.ToHexString(input)
+						+ " got " + Hex.ToHexString(pText));
+                }
+            }
+            catch (Exception e)
+            {
+                return new SimpleTestResult(false, Name + ": failed unwrap test exception.", e);
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public override ITestResult Perform()
+        {
+            ITestResult result = base.Perform();
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            byte[] kek1 = Hex.Decode("000102030405060708090a0b0c0d0e0f");
+            byte[] in1 = Hex.Decode("00112233445566778899aabbccddeeff");
+            byte[] out1 = Hex.Decode("1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5");
+            result = WrapTest(1, kek1, in1, out1);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            byte[] kek2 = Hex.Decode("000102030405060708090a0b0c0d0e0f1011121314151617");
+            byte[] in2 = Hex.Decode("00112233445566778899aabbccddeeff");
+            byte[] out2 = Hex.Decode("96778b25ae6ca435f92b5b97c050aed2468ab8a17ad84e5d");
+            result = WrapTest(2, kek2, in2, out2);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            byte[] kek3 = Hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
+            byte[] in3 = Hex.Decode("00112233445566778899aabbccddeeff");
+            byte[] out3 = Hex.Decode("64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7");
+            result = WrapTest(3, kek3, in3, out3);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            byte[] kek4 = Hex.Decode("000102030405060708090a0b0c0d0e0f1011121314151617");
+            byte[] in4 = Hex.Decode("00112233445566778899aabbccddeeff0001020304050607");
+            byte[] out4 = Hex.Decode("031d33264e15d33268f24ec260743edce1c6c7ddee725a936ba814915c6762d2");
+            result = WrapTest(4, kek4, in4, out4);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            byte[] kek5 = Hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
+            byte[] in5 = Hex.Decode("00112233445566778899aabbccddeeff0001020304050607");
+            byte[] out5 = Hex.Decode("a8f9bc1612c68b3ff6e6f4fbe30e71e4769c8b80a32cb8958cd5d17d6b254da1");
+            result = WrapTest(5, kek5, in5, out5);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            byte[] kek6 = Hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
+            byte[] in6 = Hex.Decode("00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f");
+            byte[] out6 = Hex.Decode("28c9f404c4b810f4cbccb35cfb87f8263f5786e2d80ed326cbc7f0e71a99f43bfb988b9b7a02dd21");
+            result = WrapTest(6, kek6, in6, out6);
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+	        string[] args)
+        {
+            AesTest test = new AesTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/AESWrapTest.cs b/crypto/test/src/crypto/test/AESWrapTest.cs
new file mode 100644
index 000000000..11b46098e
--- /dev/null
+++ b/crypto/test/src/crypto/test/AESWrapTest.cs
@@ -0,0 +1,214 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* Wrap Test
+	*/
+	[TestFixture]
+	public class AesWrapTest
+		: ITest
+	{
+		public string Name
+		{
+			get
+			{
+				return "AESWrap";
+			}
+		}
+
+		private ITestResult wrapTest(
+			int     id,
+			byte[]  kek,
+			byte[]  inBytes,
+			byte[]  outBytes)
+		{
+			IWrapper wrapper = new AesWrapEngine();
+
+			wrapper.Init(true, new KeyParameter(kek));
+
+			try
+			{
+				byte[]  cText = wrapper.Wrap(inBytes, 0, inBytes.Length);
+				if (!Arrays.AreEqual(cText, outBytes))
+				{
+					return new SimpleTestResult(false, Name + ": failed wrap test " + id
+						+ " expected " + Hex.ToHexString(outBytes)
+						+ " got " + Hex.ToHexString(cText));
+				}
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed wrap test exception " + e);
+			}
+
+			wrapper.Init(false, new KeyParameter(kek));
+
+			try
+			{
+				byte[]  pText = wrapper.Unwrap(outBytes, 0, outBytes.Length);
+				if (!Arrays.AreEqual(pText, inBytes))
+				{
+					return new SimpleTestResult(false, Name + ": failed unwrap test " + id
+						+ " expected " + Hex.ToHexString(inBytes)
+						+ " got " + Hex.ToHexString(pText));
+				}
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed unwrap test exception.", e);
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public ITestResult Perform()
+		{
+			byte[]  kek1 = Hex.Decode("000102030405060708090a0b0c0d0e0f");
+			byte[]  in1 = Hex.Decode("00112233445566778899aabbccddeeff");
+			byte[]  out1 = Hex.Decode("1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5");
+			ITestResult result = wrapTest(1, kek1, in1, out1);
+
+			if (!result.IsSuccessful())
+			{
+				return result;
+			}
+
+			byte[]  kek2 = Hex.Decode("000102030405060708090a0b0c0d0e0f1011121314151617");
+			byte[]  in2 = Hex.Decode("00112233445566778899aabbccddeeff");
+			byte[]  out2 = Hex.Decode("96778b25ae6ca435f92b5b97c050aed2468ab8a17ad84e5d");
+			result = wrapTest(2, kek2, in2, out2);
+			if (!result.IsSuccessful())
+			{
+				return result;
+			}
+
+			byte[]  kek3 = Hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
+			byte[]  in3 = Hex.Decode("00112233445566778899aabbccddeeff");
+			byte[]  out3 = Hex.Decode("64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7");
+			result = wrapTest(3, kek3, in3, out3);
+			if (!result.IsSuccessful())
+			{
+				return result;
+			}
+
+			byte[]  kek4 = Hex.Decode("000102030405060708090a0b0c0d0e0f1011121314151617");
+			byte[]  in4 = Hex.Decode("00112233445566778899aabbccddeeff0001020304050607");
+			byte[]  out4 = Hex.Decode("031d33264e15d33268f24ec260743edce1c6c7ddee725a936ba814915c6762d2");
+			result = wrapTest(4, kek4, in4, out4);
+			if (!result.IsSuccessful())
+			{
+				return result;
+			}
+
+			byte[]  kek5 = Hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
+			byte[]  in5 = Hex.Decode("00112233445566778899aabbccddeeff0001020304050607");
+			byte[]  out5 = Hex.Decode("a8f9bc1612c68b3ff6e6f4fbe30e71e4769c8b80a32cb8958cd5d17d6b254da1");
+			result = wrapTest(5, kek5, in5, out5);
+			if (!result.IsSuccessful())
+			{
+				return result;
+			}
+
+			byte[]  kek6 = Hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
+			byte[]  in6 = Hex.Decode("00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f");
+			byte[]  out6 = Hex.Decode("28c9f404c4b810f4cbccb35cfb87f8263f5786e2d80ed326cbc7f0e71a99f43bfb988b9b7a02dd21");
+			result = wrapTest(6, kek6, in6, out6);
+			if (!result.IsSuccessful())
+			{
+				return result;
+			}
+
+			IWrapper wrapper = new AesWrapEngine();
+			KeyParameter key = new KeyParameter(new byte[16]);
+			byte[]       buf = new byte[16];
+
+			try
+			{
+				wrapper.Init(true, key);
+
+				wrapper.Unwrap(buf, 0, buf.Length);
+
+				return new SimpleTestResult(false, Name + ": failed unwrap state test.");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+			catch (InvalidCipherTextException e)
+			{
+				return new SimpleTestResult(false, Name + ": unexpected exception: " + e, e);
+			}
+
+			try
+			{
+				wrapper.Init(false, key);
+
+				wrapper.Wrap(buf, 0, buf.Length);
+
+				return new SimpleTestResult(false, Name + ": failed unwrap state test.");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+
+			//
+			// short test
+			//
+			try
+			{
+				wrapper.Init(false, key);
+
+				wrapper.Unwrap(buf, 0, buf.Length / 2);
+
+				return new SimpleTestResult(false, Name + ": failed unwrap short test.");
+			}
+			catch (InvalidCipherTextException)
+			{
+				// expected
+			}
+
+			try
+			{
+				wrapper.Init(true, key);
+
+				wrapper.Wrap(buf, 0, 15);
+
+				return new SimpleTestResult(false, Name + ": failed wrap length test.");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			AesWrapTest test = new AesWrapTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/AeadTestUtilities.cs b/crypto/test/src/crypto/test/AeadTestUtilities.cs
new file mode 100644
index 000000000..40f334202
--- /dev/null
+++ b/crypto/test/src/crypto/test/AeadTestUtilities.cs
@@ -0,0 +1,14 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    public class AeadTestUtilities
+    {
+        internal static AeadParameters ReuseKey(AeadParameters p)
+        {
+            return new AeadParameters(null, p.MacSize, p.GetNonce(), p.GetAssociatedText());
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/AllTests.cs b/crypto/test/src/crypto/test/AllTests.cs
new file mode 100644
index 000000000..1cb1b965d
--- /dev/null
+++ b/crypto/test/src/crypto/test/AllTests.cs
@@ -0,0 +1,47 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class AllTests
+	{
+		[Suite]
+		public static TestSuite Suite
+		{
+			get
+			{
+				TestSuite suite = new TestSuite("Lightweight Crypto Tests");
+				suite.Add(new AllTests());
+		        suite.Add(new GcmReorderTest());
+				return suite;
+			}
+		}
+
+		[Test]
+		public void TestCrypto()
+		{
+			foreach (Org.BouncyCastle.Utilities.Test.ITest test in RegressionTest.tests)
+			{
+				SimpleTestResult result = (SimpleTestResult)test.Perform();
+
+				if (!result.IsSuccessful())
+				{
+					Assert.Fail(result.ToString());
+				}
+			}
+		}
+
+        public static void Main(
+			string[] args)
+        {
+            //junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            Suite.Run(el);
+        }
+	}
+}
diff --git a/crypto/test/src/crypto/test/BlockCipherMonteCarloTest.cs b/crypto/test/src/crypto/test/BlockCipherMonteCarloTest.cs
new file mode 100644
index 000000000..1a46a3201
--- /dev/null
+++ b/crypto/test/src/crypto/test/BlockCipherMonteCarloTest.cs
@@ -0,0 +1,83 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* a basic test that takes a cipher, key parameter, and an input
+	* and output string. This test wraps the engine in a buffered block
+	* cipher with padding disabled.
+	*/
+	public class BlockCipherMonteCarloTest
+		: SimpleTest
+	{
+		int					id;
+		int					iterations;
+		IBlockCipher		engine;
+		ICipherParameters	param;
+		byte[]				input;
+		byte[]				output;
+
+		public BlockCipherMonteCarloTest(
+			int                 id,
+			int                 iterations,
+			IBlockCipher         engine,
+			ICipherParameters    param,
+			string              input,
+			string              output)
+		{
+			this.id = id;
+			this.iterations = iterations;
+			this.engine = engine;
+			this.param = param;
+			this.input = Hex.Decode(input);
+			this.output = Hex.Decode(output);
+		}
+
+		public override string Name
+		{
+			get { return engine.AlgorithmName + " Monte Carlo Test " + id; }
+		}
+
+		public override void PerformTest()
+		{
+			BufferedBlockCipher cipher = new BufferedBlockCipher(engine);
+
+			cipher.Init(true, param);
+
+			byte[]  outBytes = new byte[input.Length];
+
+			Array.Copy(input, 0, outBytes, 0, outBytes.Length);
+
+			for (int i = 0; i != iterations; i++)
+			{
+				int len1 = cipher.ProcessBytes(outBytes, 0, outBytes.Length, outBytes, 0);
+
+				cipher.DoFinal(outBytes, len1);
+			}
+
+			if (!AreEqual(outBytes, output))
+			{
+				Fail("failed - " + "expected " + Hex.ToHexString(output) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			cipher.Init(false, param);
+
+			for (int i = 0; i != iterations; i++)
+			{
+				int len1 = cipher.ProcessBytes(outBytes, 0, outBytes.Length, outBytes, 0);
+
+				cipher.DoFinal(outBytes, len1);
+			}
+
+			if (!AreEqual(input, outBytes))
+			{
+				Fail("failed reversal");
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/BlockCipherVectorTest.cs b/crypto/test/src/crypto/test/BlockCipherVectorTest.cs
new file mode 100644
index 000000000..1ce9fa477
--- /dev/null
+++ b/crypto/test/src/crypto/test/BlockCipherVectorTest.cs
@@ -0,0 +1,75 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* a basic test that takes a cipher, key parameter, and an input
+	* and output string. This test wraps the engine in a buffered block
+	* cipher with padding disabled.
+	*/
+	public class BlockCipherVectorTest
+		: SimpleTest
+	{
+		int                 id;
+		IBlockCipher         engine;
+		ICipherParameters    param;
+		byte[]              input;
+		byte[]              output;
+
+		public BlockCipherVectorTest(
+			int					id,
+			IBlockCipher		engine,
+			ICipherParameters	param,
+			string				input,
+			string				output)
+		{
+			this.id = id;
+			this.engine = engine;
+			this.param = param;
+			this.input = Hex.Decode(input);
+			this.output = Hex.Decode(output);
+		}
+
+		public override string Name
+		{
+			get
+			{
+				return engine.AlgorithmName + " Vector Test " + id;
+			}
+		}
+
+		public override void PerformTest()
+		{
+			BufferedBlockCipher cipher = new BufferedBlockCipher(engine);
+
+			cipher.Init(true, param);
+
+			byte[]  outBytes = new byte[input.Length];
+
+			int len1 = cipher.ProcessBytes(input, 0, input.Length, outBytes, 0);
+
+				cipher.DoFinal(outBytes, len1);
+
+			if (!AreEqual(outBytes, output))
+			{
+				Fail("failed - " + "expected " + Hex.ToHexString(output) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			cipher.Init(false, param);
+
+			int len2 = cipher.ProcessBytes(output, 0, output.Length, outBytes, 0);
+
+			cipher.DoFinal(outBytes, len2);
+
+			if (!AreEqual(input, outBytes))
+			{
+				Fail("failed reversal got " + Hex.ToHexString(outBytes));
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/BlowfishTest.cs b/crypto/test/src/crypto/test/BlowfishTest.cs
new file mode 100644
index 000000000..780dd3abd
--- /dev/null
+++ b/crypto/test/src/crypto/test/BlowfishTest.cs
@@ -0,0 +1,55 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <remarks>Blowfish tester - vectors from http://www.counterpane.com/vectors.txt</remarks>
+    [TestFixture]
+    public class BlowfishTest
+		: CipherTest
+    {
+        public override string Name
+        {
+			get { return "Blowfish"; }
+        }
+
+        internal static SimpleTest[] tests = new SimpleTest[]{
+            new BlockCipherVectorTest(0, new BlowfishEngine(), new KeyParameter(Hex.Decode("0000000000000000")), "0000000000000000", "4EF997456198DD78"),
+            new BlockCipherVectorTest(1, new BlowfishEngine(), new KeyParameter(Hex.Decode("FFFFFFFFFFFFFFFF")), "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A"),
+            new BlockCipherVectorTest(2, new BlowfishEngine(), new KeyParameter(Hex.Decode("3000000000000000")), "1000000000000001", "7D856F9A613063F2"),
+            new BlockCipherVectorTest(3, new BlowfishEngine(), new KeyParameter(Hex.Decode("1111111111111111")), "1111111111111111", "2466DD878B963C9D"),
+            new BlockCipherVectorTest(4, new BlowfishEngine(), new KeyParameter(Hex.Decode("0123456789ABCDEF")), "1111111111111111", "61F9C3802281B096"),
+            new BlockCipherVectorTest(5, new BlowfishEngine(), new KeyParameter(Hex.Decode("FEDCBA9876543210")), "0123456789ABCDEF", "0ACEAB0FC6A0A28D"),
+            new BlockCipherVectorTest(6, new BlowfishEngine(), new KeyParameter(Hex.Decode("7CA110454A1A6E57")), "01A1D6D039776742", "59C68245EB05282B"),
+            new BlockCipherVectorTest(7, new BlowfishEngine(), new KeyParameter(Hex.Decode("0131D9619DC1376E")), "5CD54CA83DEF57DA", "B1B8CC0B250F09A0")
+        };
+
+        public BlowfishTest()
+			: base(tests, new BlowfishEngine(), new KeyParameter(new byte[16]))
+		{
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+		public static void Main(
+			string[] args)
+        {
+            ITest test = new BlowfishTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/CAST6Test.cs b/crypto/test/src/crypto/test/CAST6Test.cs
new file mode 100644
index 000000000..7517b6737
--- /dev/null
+++ b/crypto/test/src/crypto/test/CAST6Test.cs
@@ -0,0 +1,57 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <remarks>Cast6 tester - vectors from http://www.ietf.org/rfc/rfc2612.txt</remarks>
+    [TestFixture]
+    public class Cast6Test : CipherTest
+    {
+        public override string Name
+        {
+			get { return "CAST6"; }
+        }
+
+		internal static SimpleTest[] tests = new SimpleTest[]
+		{
+			new BlockCipherVectorTest(0, new Cast6Engine(),
+				new KeyParameter(Hex.Decode("2342bb9efa38542c0af75647f29f615d")),
+				"00000000000000000000000000000000",
+				"c842a08972b43d20836c91d1b7530f6b"),
+			new BlockCipherVectorTest(0, new Cast6Engine(),
+				new KeyParameter(Hex.Decode("2342bb9efa38542cbed0ac83940ac298bac77a7717942863")),
+				"00000000000000000000000000000000",
+				"1b386c0210dcadcbdd0e41aa08a7a7e8"),
+			new BlockCipherVectorTest(0, new Cast6Engine(),
+				new KeyParameter(Hex.Decode("2342bb9efa38542cbed0ac83940ac2988d7c47ce264908461cc1b5137ae6b604")),
+				"00000000000000000000000000000000",
+				"4f6a2038286897b9c9870136553317fa")
+		};
+
+        public Cast6Test()
+			: base(tests, new Cast6Engine(), new KeyParameter(new byte[16]))
+        {
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            ITest test = new Cast6Test();
+            ITestResult result = test.Perform();
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/CCMTest.cs b/crypto/test/src/crypto/test/CCMTest.cs
new file mode 100644
index 000000000..4a54fb4f9
--- /dev/null
+++ b/crypto/test/src/crypto/test/CCMTest.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* First four test vectors from
+	* NIST Special Publication 800-38C.
+	*/
+	[TestFixture]
+	public class CcmTest
+		: SimpleTest
+	{
+		private byte[] K1 = Hex.Decode("404142434445464748494a4b4c4d4e4f");
+		private byte[] N1 = Hex.Decode("10111213141516");
+		private byte[] A1 = Hex.Decode("0001020304050607");
+		private byte[] P1 = Hex.Decode("20212223");
+		private byte[] C1 = Hex.Decode("7162015b4dac255d");
+		private byte[] T1 = Hex.Decode("6084341b");
+
+		private byte[] K2 = Hex.Decode("404142434445464748494a4b4c4d4e4f");
+		private byte[] N2 = Hex.Decode("1011121314151617");
+		private byte[] A2 = Hex.Decode("000102030405060708090a0b0c0d0e0f");
+		private byte[] P2 = Hex.Decode("202122232425262728292a2b2c2d2e2f");
+		private byte[] C2 = Hex.Decode("d2a1f0e051ea5f62081a7792073d593d1fc64fbfaccd");
+		private byte[] T2 = Hex.Decode("7f479ffca464");
+
+		private byte[] K3 = Hex.Decode("404142434445464748494a4b4c4d4e4f");
+		private byte[] N3 = Hex.Decode("101112131415161718191a1b");
+		private byte[] A3 = Hex.Decode("000102030405060708090a0b0c0d0e0f10111213");
+		private byte[] P3 = Hex.Decode("202122232425262728292a2b2c2d2e2f3031323334353637");
+		private byte[] C3 = Hex.Decode("e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5484392fbc1b09951");
+		private byte[] T3 = Hex.Decode("67c99240c7d51048");
+
+		private byte[] K4 = Hex.Decode("404142434445464748494a4b4c4d4e4f");
+		private byte[] N4 = Hex.Decode("101112131415161718191a1b1c");
+		private byte[] A4 = Hex.Decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff");
+		private byte[] P4 = Hex.Decode("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f");
+		private byte[] C4 = Hex.Decode("69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72b4ac6bec93e8598e7f0dadbcea5b");
+		private byte[] T4 = Hex.Decode("f4dd5d0ee404617225ffe34fce91");
+
+		//
+		// long data vector
+		//
+		private byte[] C5 = Hex.Decode("49b17d8d3ea4e6174a48e2b65e6d8b417ac0dd3f8ee46ce4a4a2a509661cef52528c1cd9805333a5cfd482fa3f095a3c2fdd1cc47771c5e55fddd60b5c8d6d3fa5c8dd79d08b16242b6642106e7c0c28bd1064b31e6d7c9800c8397dbc3fa8071e6a38278b386c18d65d39c6ad1ef9501a5c8f68d38eb6474799f3cc898b4b9b97e87f9c95ce5c51bc9d758f17119586663a5684e0a0daf6520ec572b87473eb141d10471e4799ded9e607655402eca5176bbf792ef39dd135ac8d710da8e9e854fd3b95c681023f36b5ebe2fb213d0b62dd6e9e3cfe190b792ccb20c53423b2dca128f861a61d306910e1af418839467e466f0ec361d2539eedd99d4724f1b51c07beb40e875a87491ec8b27cd1");
+		private byte[] T5 = Hex.Decode("5c768856796b627b13ec8641581b");
+
+		public override void PerformTest()
+		{
+			CcmBlockCipher ccm = new CcmBlockCipher(new AesEngine());
+
+			checkVectors(0, ccm, K1, 32, N1, A1, P1, T1, C1);
+			checkVectors(1, ccm, K2, 48, N2, A2, P2, T2, C2);
+			checkVectors(2, ccm, K3, 64, N3, A3, P3, T3, C3);
+
+			ivParamTest(0, ccm, K1, N1);
+
+			//
+			// 4 has a reduced associated text which needs to be replicated
+			//
+			byte[] a4 = new byte[65536]; // 524288 / 8
+
+			for (int i = 0; i < a4.Length; i += A4.Length)
+			{
+				Array.Copy(A4, 0, a4, i, A4.Length);
+			}
+
+			checkVectors(3, ccm, K4, 112, N4, a4, P4, T4, C4);
+
+			//
+			// long data test
+			//
+			checkVectors(4, ccm, K4, 112, N4, A4, A4, T5, C5);
+
+			//
+			// exception tests
+			//
+
+			try
+			{
+				ccm.Init(false, new AeadParameters(new KeyParameter(K1), 32, N2, A2));
+
+				ccm.ProcessPacket(C2, 0, C2.Length);
+
+				Fail("invalid cipher text not picked up");
+			}
+			catch (InvalidCipherTextException)
+			{
+				// expected
+			}
+
+			try
+			{
+				ccm = new CcmBlockCipher(new DesEngine());
+
+				Fail("incorrect block size not picked up");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+
+			try
+			{
+				ccm.Init(false, new KeyParameter(K1));
+
+				Fail("illegal argument not picked up");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		private void checkVectors(
+			int count,
+			CcmBlockCipher ccm,
+			byte[] k,
+			int macSize,
+			byte[] n,
+			byte[] a,
+			byte[] p,
+			byte[] t,
+			byte[] c)
+        {
+            byte[] fa = new byte[a.Length / 2];
+            byte[] la = new byte[a.Length - (a.Length / 2)];
+            Array.Copy(a, 0, fa, 0, fa.Length);
+            Array.Copy(a, fa.Length, la, 0, la.Length);
+
+            checkVectors(count, ccm, "all initial associated data", k, macSize, n, a, null, p, t, c);
+            checkVectors(count, ccm, "subsequent associated data", k, macSize, n, null, a, p, t, c);
+            checkVectors(count, ccm, "split associated data", k, macSize, n, fa, la, p, t, c);
+    //      checkVectors(count, ccm, "reuse key", null, macSize, n, fa, la, p, t, c);
+        }
+
+        private void checkVectors(
+            int count,
+            CcmBlockCipher ccm,
+            string additionalDataType,
+            byte[] k,
+            int macSize,
+            byte[] n,
+            byte[] a,
+            byte[] sa,
+            byte[] p,
+            byte[] t,
+            byte[] c)
+        {
+            KeyParameter keyParam = (k == null) ? null : new KeyParameter(k);
+
+            ccm.Init(true, new AeadParameters(keyParam, macSize, n, a));
+
+			byte[] enc = new byte[c.Length];
+
+            if (sa != null)
+            {
+                ccm.ProcessAadBytes(sa, 0, sa.Length);
+            }
+
+			int len = ccm.ProcessBytes(p, 0, p.Length, enc, 0);
+
+			len += ccm.DoFinal(enc, len);
+
+//			ccm.Init(true, new AeadParameters(new KeyParameter(k), macSize, n, a));
+//
+//			byte[] enc = ccm.ProcessPacket(p, 0, p.Length);
+
+			if (!AreEqual(c, enc))
+			{
+                Fail("encrypted stream fails to match in test " + count + " with " + additionalDataType);
+            }
+
+//			ccm.Init(false, new AeadParameters(new KeyParameter(k), macSize, n, a));
+//
+//			byte[] dec = ccm.ProcessPacket(enc, 0, enc.Length);
+
+			ccm.Init(false, new AeadParameters(new KeyParameter(k), macSize, n, a));
+
+			byte[] tmp = new byte[enc.Length];
+
+            if (sa != null)
+            {
+                ccm.ProcessAadBytes(sa, 0, sa.Length);
+            }
+
+            len = ccm.ProcessBytes(enc, 0, enc.Length, tmp, 0);
+
+			len += ccm.DoFinal(tmp, len);
+
+			byte[] dec = new byte[len];
+
+			Array.Copy(tmp, 0, dec, 0, len);
+
+			if (!AreEqual(p, dec))
+			{
+                Fail("decrypted stream fails to match in test " + count + " with " + additionalDataType);
+            }
+
+			if (!AreEqual(t, ccm.GetMac()))
+			{
+                Fail("MAC fails to match in test " + count + " with " + additionalDataType);
+            }
+		}
+
+		private void ivParamTest(
+			int				count,
+			CcmBlockCipher	ccm,
+			byte[]			k,
+			byte[]			n)
+		{
+			byte[] p = Encoding.ASCII.GetBytes("hello world!!");
+
+			ccm.Init(true, new ParametersWithIV(new KeyParameter(k), n));
+
+			byte[] enc = new byte[p.Length + 8];
+
+			int len = ccm.ProcessBytes(p, 0, p.Length, enc, 0);
+
+			len += ccm.DoFinal(enc, len);
+
+			ccm.Init(false, new ParametersWithIV(new KeyParameter(k), n));
+
+			byte[] tmp = new byte[enc.Length];
+
+			len = ccm.ProcessBytes(enc, 0, enc.Length, tmp, 0);
+
+			len += ccm.DoFinal(tmp, len);
+
+			byte[] dec = new byte[len];
+
+			Array.Copy(tmp, 0, dec, 0, len);
+
+			if (!AreEqual(p, dec))
+			{
+				Fail("decrypted stream fails to match in test " + count);
+			}
+		}
+
+		public override string Name
+		{
+			get { return "CCM"; }
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CcmTest());
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/CMacTest.cs b/crypto/test/src/crypto/test/CMacTest.cs
new file mode 100644
index 000000000..d71b69f98
--- /dev/null
+++ b/crypto/test/src/crypto/test/CMacTest.cs
@@ -0,0 +1,302 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * CMAC tester - <a href="http://www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/tv/omac1-tv.txt">Official Test Vectors</a>.
+     */
+    [TestFixture]
+    public class CMacTest
+        : SimpleTest
+    {
+        private static readonly byte[] keyBytes128 = Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c");
+        private static readonly byte[] keyBytes192 = Hex.Decode(
+            "8e73b0f7da0e6452c810f32b809079e5"
+            + "62f8ead2522c6b7b");
+        private static readonly byte[] keyBytes256 = Hex.Decode(
+            "603deb1015ca71be2b73aef0857d7781"
+            + "1f352c073b6108d72d9810a30914dff4");
+
+        private static readonly byte[] input0 = Hex.Decode("");
+        private static readonly byte[] input16 = Hex.Decode("6bc1bee22e409f96e93d7e117393172a");
+        private static readonly byte[] input40 = Hex.Decode(
+            "6bc1bee22e409f96e93d7e117393172a"
+            + "ae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411");
+        private static readonly byte[] input64 = Hex.Decode(
+            "6bc1bee22e409f96e93d7e117393172a"
+            + "ae2d8a571e03ac9c9eb76fac45af8e51"
+            + "30c81c46a35ce411e5fbc1191a0a52ef"
+            + "f69f2445df4f9b17ad2b417be66c3710");
+
+        private static readonly byte[] output_k128_m0 = Hex.Decode("bb1d6929e95937287fa37d129b756746");
+        private static readonly byte[] output_k128_m16 = Hex.Decode("070a16b46b4d4144f79bdd9dd04a287c");
+        private static readonly byte[] output_k128_m40 = Hex.Decode("dfa66747de9ae63030ca32611497c827");
+        private static readonly byte[] output_k128_m64 = Hex.Decode("51f0bebf7e3b9d92fc49741779363cfe");
+
+        private static readonly byte[] output_k192_m0 = Hex.Decode("d17ddf46adaacde531cac483de7a9367");
+        private static readonly byte[] output_k192_m16 = Hex.Decode("9e99a7bf31e710900662f65e617c5184");
+        private static readonly byte[] output_k192_m40 = Hex.Decode("8a1de5be2eb31aad089a82e6ee908b0e");
+        private static readonly byte[] output_k192_m64 = Hex.Decode("a1d5df0eed790f794d77589659f39a11");
+
+        private static readonly byte[] output_k256_m0 = Hex.Decode("028962f61b7bf89efc6b551f4667d983");
+        private static readonly byte[] output_k256_m16 = Hex.Decode("28a7023f452e8f82bd4bf28d8c37c35c");
+        private static readonly byte[] output_k256_m40 = Hex.Decode("aaf3d8f1de5640c232f5b169b9c911e6");
+        private static readonly byte[] output_k256_m64 = Hex.Decode("e1992190549f6ed5696a2c056c315410");
+
+        public CMacTest()
+        {
+        }
+
+        public override void PerformTest()
+        {
+            IBlockCipher cipher = new AesFastEngine();
+            IMac mac = new CMac(cipher, 128);
+
+            //128 bytes key
+
+            KeyParameter key = new KeyParameter(keyBytes128);
+
+            // 0 bytes message - 128 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input0, 0, input0.Length);
+
+            byte[] outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k128_m0))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k128_m0) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 16 bytes message - 128 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input16, 0, input16.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k128_m16))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k128_m16) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 40 bytes message - 128 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input40, 0, input40.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k128_m40))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k128_m40) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 64 bytes message - 128 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input64, 0, input64.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k128_m64))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k128_m64) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            //192 bytes key
+            key = new KeyParameter(keyBytes192);
+
+            // 0 bytes message - 192 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input0, 0, input0.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k192_m0))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k192_m0) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 16 bytes message - 192 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input16, 0, input16.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k192_m16))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k192_m16) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 40 bytes message - 192 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input40, 0, input40.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k192_m40))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k192_m40) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 64 bytes message - 192 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input64, 0, input64.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k192_m64))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k192_m64) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            //256 bytes key
+
+            key = new KeyParameter(keyBytes256);
+
+            // 0 bytes message - 256 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input0, 0, input0.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k256_m0))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k256_m0) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 16 bytes message - 256 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input16, 0, input16.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k256_m16))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k256_m16) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 40 bytes message - 256 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input40, 0, input40.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k256_m40))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k256_m40) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // 64 bytes message - 256 bytes key
+            mac.Init(key);
+
+            mac.BlockUpdate(input64, 0, input64.Length);
+
+            outBytes = new byte[16];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output_k256_m64))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output_k256_m64) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            TestExceptions();
+        }
+
+        private void TestExceptions()
+        {
+            try 
+            {
+                CMac mac = new CMac(new AesEngine());
+                mac.Init(new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]));
+                Fail("CMac does not accept IV");
+            }
+            catch(ArgumentException)
+            {
+                // Expected
+            }
+        }
+
+        public override string Name
+        {
+            get { return "CMac"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new CMacTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/CTSTest.cs b/crypto/test/src/crypto/test/CTSTest.cs
new file mode 100644
index 000000000..9d001bc68
--- /dev/null
+++ b/crypto/test/src/crypto/test/CTSTest.cs
@@ -0,0 +1,192 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> CTS tester</summary>
+    [TestFixture]
+    public class CTSTest : ITest
+    {
+        public string Name
+        {
+			get
+			{
+				return "CTS";
+			}
+        }
+
+        internal static byte[] in1;
+
+        internal static byte[] in2;
+
+        internal static byte[] out1;
+
+        internal static byte[] out2;
+
+        internal static byte[] out3;
+
+        private class CTSTester : ITest
+        {
+            private void  InitBlock(CTSTest enclosingInstance)
+            {
+                this.enclosingInstance = enclosingInstance;
+            }
+            private CTSTest enclosingInstance;
+
+            public string Name
+            {
+				get
+				{
+					return "CTS";
+				}
+            }
+
+            public CTSTest Enclosing_Instance
+            {
+                get
+                {
+                    return enclosingInstance;
+                }
+
+            }
+
+            private int id;
+            private IBlockCipher cipher;
+            private ICipherParameters parameters;
+            private byte[] input;
+            private byte[] output;
+
+            internal CTSTester(CTSTest enclosingInstance, int id, IBlockCipher cipher, ICipherParameters parameters, byte[] input, byte[] output)
+            {
+                InitBlock(enclosingInstance);
+                this.id = id;
+                this.cipher = cipher;
+                this.parameters = parameters;
+                this.input = input;
+                this.output = output;
+            }
+
+            public virtual ITestResult Perform()
+            {
+                byte[] outBytes = new byte[input.Length];
+                BufferedBlockCipher engine = new CtsBlockCipher(cipher);
+
+                engine.Init(true, parameters);
+
+                int len = engine.ProcessBytes(input, 0, input.Length, outBytes, 0);
+
+                try
+                {
+                    engine.DoFinal(outBytes, len);
+                }
+                catch (Exception e)
+                {
+                    return new SimpleTestResult(false, Name + ": encryption exception - " + e.ToString());
+                }
+
+                for (int i = 0; i != output.Length; i++)
+                {
+                    if (outBytes[i] != output[i])
+                    {
+                        return new SimpleTestResult(false, Name + ": failed encryption expected "
+							+ Hex.ToHexString(output) + " got " + Hex.ToHexString(outBytes));
+                    }
+                }
+
+                engine.Init(false, parameters);
+
+                len = engine.ProcessBytes(output, 0, output.Length, outBytes, 0);
+
+                try
+                {
+                    engine.DoFinal(outBytes, len);
+                }
+                catch (Exception e)
+                {
+                    return new SimpleTestResult(false, Name + ": decryption exception - " + e.ToString());
+                }
+
+                for (int i = 0; i != input.Length; i++)
+                {
+                    if (outBytes[i] != input[i])
+                    {
+                        return new SimpleTestResult(false, Name + ": failed encryption expected "
+							+ Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+                    }
+                }
+
+                return new SimpleTestResult(true, Name + ": Okay");
+            }
+        }
+
+        public CTSTest()
+        {
+        }
+
+        public virtual ITestResult Perform()
+        {
+            byte[] key1 = new byte[]{(byte) 0x01, (byte) 0x23, (byte) 0x45, (byte) 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF};
+            byte[] key2 = new byte[]{(byte) 0x01, (byte) 0x23, (byte) 0x45, (byte) 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF, (byte) 0xee, (byte) 0xff };
+            byte[] iv = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
+
+            ITest test = new CTSTester(this, 1, new DesEngine(), new KeyParameter(key1), in1, out1);
+            ITestResult result = test.Perform();
+
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            test = new CTSTester(this, 2, new CbcBlockCipher(new DesEngine()), new ParametersWithIV(new KeyParameter(key1), iv), in1, out2);
+            result = test.Perform();
+
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            test = new CTSTester(this, 3, new CbcBlockCipher(new SkipjackEngine()), new ParametersWithIV(new KeyParameter(key2), iv), in2, out3);
+            result = test.Perform();
+
+            if (!result.IsSuccessful())
+            {
+                return result;
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            CTSTest test = new CTSTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        static CTSTest()
+        {
+            in1 = Hex.Decode("4e6f7720697320746865207420");
+            in2 = Hex.Decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa");
+            out1 = Hex.Decode("9952f131588465033fa40e8a98");
+            out2 = Hex.Decode("358f84d01eb42988dc34efb994");
+            out3 = Hex.Decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6");
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/CamelliaLightTest.cs b/crypto/test/src/crypto/test/CamelliaLightTest.cs
new file mode 100644
index 000000000..2247178f2
--- /dev/null
+++ b/crypto/test/src/crypto/test/CamelliaLightTest.cs
@@ -0,0 +1,80 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* Camellia tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ and RFC 3713
+	*/
+	[TestFixture]
+	public class CamelliaLightTest
+		: CipherTest
+	{
+		static SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"80000000000000000000000000000000", "07923A39EB0A817D1C4D87BDB82D1F1C"),
+			new BlockCipherVectorTest(1, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+				"00000000000000000000000000000000", "6C227F749319A3AA7DA235A9BBA05A2C"),
+			new BlockCipherVectorTest(2, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("0123456789abcdeffedcba9876543210")),
+				"0123456789abcdeffedcba9876543210", "67673138549669730857065648eabe43"),
+			//
+			// 192 bit
+			//
+			new BlockCipherVectorTest(3, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("0123456789abcdeffedcba98765432100011223344556677")),
+				"0123456789abcdeffedcba9876543210", "b4993401b3e996f84ee5cee7d79b09b9"),
+			new BlockCipherVectorTest(4, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+				"00040000000000000000000000000000", "9BCA6C88B928C1B0F57F99866583A9BC"),
+			new BlockCipherVectorTest(5, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("949494949494949494949494949494949494949494949494")),
+				"636EB22D84B006381235641BCF0308D2", "94949494949494949494949494949494"),
+			//
+			// 256 bit
+			//
+			new BlockCipherVectorTest(6, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff")),
+				"0123456789abcdeffedcba9876543210", "9acc237dff16d76c20ef7c919e3a7509"),
+			new BlockCipherVectorTest(7, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A")),
+				"057764FE3A500EDBD988C5C3B56CBA9A", "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A"),
+			new BlockCipherVectorTest(8, new CamelliaLightEngine(),
+				new KeyParameter(Hex.Decode("0303030303030303030303030303030303030303030303030303030303030303")),
+				"7968B08ABA92193F2295121EF8D75C8A", "03030303030303030303030303030303"),
+		};
+
+		public CamelliaLightTest()
+			: base(tests, new CamelliaLightEngine(), new KeyParameter(new byte[32]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "CamelliaLight"; }
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CamelliaLightTest());
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/CamelliaTest.cs b/crypto/test/src/crypto/test/CamelliaTest.cs
new file mode 100644
index 000000000..a134546b7
--- /dev/null
+++ b/crypto/test/src/crypto/test/CamelliaTest.cs
@@ -0,0 +1,80 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * Camellia tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ and RFC 3713
+	 */
+	[TestFixture]
+	public class CamelliaTest
+		: CipherTest
+	{
+		static SimpleTest[]  tests =
+		{
+			new BlockCipherVectorTest(0, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"80000000000000000000000000000000", "07923A39EB0A817D1C4D87BDB82D1F1C"),
+			new BlockCipherVectorTest(1, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+				"00000000000000000000000000000000", "6C227F749319A3AA7DA235A9BBA05A2C"),
+			new BlockCipherVectorTest(2, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("0123456789abcdeffedcba9876543210")),
+				"0123456789abcdeffedcba9876543210", "67673138549669730857065648eabe43"),
+			//
+			// 192 bit
+			//
+			new BlockCipherVectorTest(3, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("0123456789abcdeffedcba98765432100011223344556677")),
+				"0123456789abcdeffedcba9876543210", "b4993401b3e996f84ee5cee7d79b09b9"),
+			new BlockCipherVectorTest(4, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+				"00040000000000000000000000000000", "9BCA6C88B928C1B0F57F99866583A9BC"),
+			new BlockCipherVectorTest(5, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("949494949494949494949494949494949494949494949494")),
+				"636EB22D84B006381235641BCF0308D2", "94949494949494949494949494949494"),
+			//
+			// 256 bit
+			//
+			new BlockCipherVectorTest(6, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff")),
+				"0123456789abcdeffedcba9876543210", "9acc237dff16d76c20ef7c919e3a7509"),
+			new BlockCipherVectorTest(7, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A")),
+				"057764FE3A500EDBD988C5C3B56CBA9A", "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A"),
+			new BlockCipherVectorTest(8, new CamelliaEngine(),
+				new KeyParameter(Hex.Decode("0303030303030303030303030303030303030303030303030303030303030303")),
+				"7968B08ABA92193F2295121EF8D75C8A", "03030303030303030303030303030303"),
+		};
+
+		public CamelliaTest()
+			: base(tests, new CamelliaEngine(), new KeyParameter(new byte[32]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "Camellia"; }
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CamelliaTest());
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/Cast5Test.cs b/crypto/test/src/crypto/test/Cast5Test.cs
new file mode 100644
index 000000000..ea2e0c540
--- /dev/null
+++ b/crypto/test/src/crypto/test/Cast5Test.cs
@@ -0,0 +1,49 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <remarks>Cast tester - vectors from http://www.ietf.org/rfc/rfc2144.txt</remarks>
+    [TestFixture]
+    public class Cast5Test
+		: CipherTest
+    {
+        public override string Name
+        {
+			get { return "Cast5"; }
+        }
+
+		internal static SimpleTest[] testlist = new SimpleTest[]{
+            new BlockCipherVectorTest(0, new Cast5Engine(), new KeyParameter(Hex.Decode("0123456712345678234567893456789A")), "0123456789ABCDEF", "238B4FE5847E44B2"),
+            new BlockCipherVectorTest(0, new Cast5Engine(), new KeyParameter(Hex.Decode("01234567123456782345")), "0123456789ABCDEF", "EB6A711A2C02271B"),
+            new BlockCipherVectorTest(0, new Cast5Engine(), new KeyParameter(Hex.Decode("0123456712")), "0123456789ABCDEF", "7Ac816d16E9B302E")};
+
+		public Cast5Test()
+			: base(testlist , new Cast5Engine(), new KeyParameter(new byte[16]))
+        {
+        }
+
+        public static void Main(
+			string[] args)
+        {
+            ITest test = new Cast5Test();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ChaChaTest.cs b/crypto/test/src/crypto/test/ChaChaTest.cs
new file mode 100644
index 000000000..0b394c91e
--- /dev/null
+++ b/crypto/test/src/crypto/test/ChaChaTest.cs
@@ -0,0 +1,319 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * ChaCha Test
+     * <p>
+     * Test cases generated using ref version of ChaCha20 in estreambench-20080905.
+     * </p>
+     */
+    [TestFixture]
+    public class ChaChaTest
+        : SimpleTest
+    {
+        private static readonly byte[] zeroes = Hex.Decode(
+            "00000000000000000000000000000000"
+            + "00000000000000000000000000000000"
+            + "00000000000000000000000000000000"
+            + "00000000000000000000000000000000");
+
+        private static readonly string set1v0_0 =
+            "FBB87FBB8395E05DAA3B1D683C422046"
+            + "F913985C2AD9B23CFC06C1D8D04FF213"
+            + "D44A7A7CDB84929F915420A8A3DC58BF"
+            + "0F7ECB4B1F167BB1A5E6153FDAF4493D";
+
+        private static readonly string set1v0_192 =
+            "D9485D55B8B82D792ED1EEA8E93E9BC1"
+            + "E2834AD0D9B11F3477F6E106A2F6A5F2"
+            + "EA8244D5B925B8050EAB038F58D4DF57"
+            + "7FAFD1B89359DAE508B2B10CBD6B488E";
+
+        private static readonly string set1v0_256 =
+            "08661A35D6F02D3D9ACA8087F421F7C8"
+            + "A42579047D6955D937925BA21396DDD4"
+            + "74B1FC4ACCDCAA33025B4BCE817A4FBF"
+            + "3E5D07D151D7E6FE04934ED466BA4779";
+
+        private static readonly string set1v0_448 =
+            "A7E16DD38BA48CCB130E5BE9740CE359"
+            + "D631E91600F85C8A5D0785A612D1D987"
+            + "90780ACDDC26B69AB106CCF6D866411D"
+            + "10637483DBF08CC5591FD8B3C87A3AE0";
+
+        private static readonly string set1v9_0 =
+            "A276339F99316A913885A0A4BE870F06"
+            + "91E72B00F1B3F2239F714FE81E88E00C"
+            + "BBE52B4EBBE1EA15894E29658C4CB145"
+            + "E6F89EE4ABB045A78514482CE75AFB7C";
+
+        private static readonly string set1v9_192 =
+            "0DFB9BD4F87F68DE54FBC1C6428FDEB0"
+            + "63E997BE8490C9B7A4694025D6EBA2B1"
+            + "5FE429DB82A7CAE6AAB22918E8D00449"
+            + "6FB6291467B5AE81D4E85E81D8795EBB";
+
+        private static readonly string set1v9_256 =
+            "546F5BB315E7F71A46E56D4580F90889"
+            + "639A2BA528F757CF3B048738BA141AF3"
+            + "B31607CB21561BAD94721048930364F4"
+            + "B1227CFEB7CDECBA881FB44903550E68";
+
+        private static readonly string set1v9_448 =
+            "6F813586E76691305A0CF048C0D8586D"
+            + "C89460207D8B230CD172398AA33D19E9"
+            + "2D24883C3A9B0BB7CD8C6B2668DB142E"
+            + "37A97948A7A01498A21110297984CD20";
+
+        private static readonly string set6v0_0 =
+            "57459975BC46799394788DE80B928387"
+            + "862985A269B9E8E77801DE9D874B3F51"
+            + "AC4610B9F9BEE8CF8CACD8B5AD0BF17D"
+            + "3DDF23FD7424887EB3F81405BD498CC3";
+
+        private static readonly string set6v0_65472 =
+            "EF9AEC58ACE7DB427DF012B2B91A0C1E"
+            + "8E4759DCE9CDB00A2BD59207357BA06C"
+            + "E02D327C7719E83D6348A6104B081DB0"
+            + "3908E5186986AE41E3AE95298BB7B713";
+
+        private static readonly string set6v0_65536 =
+            "17EF5FF454D85ABBBA280F3A94F1D26E"
+            + "950C7D5B05C4BB3A78326E0DC5731F83"
+            + "84205C32DB867D1B476CE121A0D7074B"
+            + "AA7EE90525D15300F48EC0A6624BD0AF";
+
+        private static readonly string set6v1_0 =
+            "92A2508E2C4084567195F2A1005E552B"
+            + "4874EC0504A9CD5E4DAF739AB553D2E7"
+            + "83D79C5BA11E0653BEBB5C116651302E"
+            + "8D381CB728CA627B0B246E83942A2B99";
+
+        private static readonly string set6v1_65472 =
+            "E1974EC3063F7BD0CBA58B1CE34BC874"
+            + "67AAF5759B05EA46682A5D4306E5A76B"
+            + "D99A448DB8DE73AF97A73F5FBAE2C776"
+            + "35040464524CF14D7F08D4CE1220FD84";
+
+        private static readonly string set6v1_65536 =
+            "BE3436141CFD62D12FF7D852F80C1344"
+            + "81F152AD0235ECF8CA172C55CA8C031B"
+            + "2E785D773A988CA8D4BDA6FAE0E493AA"
+            + "71DCCC4C894D1F106CAC62A9FC0A9607";
+
+        // ChaCha12
+        private static readonly string chacha12_set1v0_0 =
+            "36CF0D56E9F7FBF287BC5460D95FBA94"
+            + "AA6CBF17D74E7C784DDCF7E0E882DDAE"
+            + "3B5A58243EF32B79A04575A8E2C2B73D"
+            + "C64A52AA15B9F88305A8F0CA0B5A1A25";
+
+        private static readonly string chacha12_set1v0_192 =
+            "83496792AB68FEC75ADB16D3044420A4"
+            + "A00A6E9ADC41C3A63DBBF317A8258C85"
+            + "A9BC08B4F76B413A4837324AEDF8BC2A"
+            + "67D53C9AB9E1C5BC5F379D48DF9AF730";
+
+        private static readonly string chacha12_set1v0_256 = 
+            "BAA28ED593690FD760ADA07C95E3B888"
+            + "4B4B64E488CA7A2D9BDC262243AB9251"
+            + "394C5037E255F8BCCDCD31306C508FFB"
+            + "C9E0161380F7911FCB137D46D9269250";
+
+        private static readonly string chacha12_set1v0_448 =
+            "B7ECFB6AE0B51915762FE1FD03A14D0C"
+            + "9E54DA5DC76EB16EBA5313BC535DE63D"
+            + "C72D7F9F1874E301E99C8531819F4E37"
+            + "75793F6A5D19C717FA5C78A39EB804A6";
+
+        // ChaCha8
+        private static readonly string chacha8_set1v0_0 =
+            "BEB1E81E0F747E43EE51922B3E87FB38"
+            + "D0163907B4ED49336032AB78B67C2457"
+            + "9FE28F751BD3703E51D876C017FAA435"
+            + "89E63593E03355A7D57B2366F30047C5";
+
+        private static readonly string chacha8_set1v0_192 =
+            "33B8B7CA8F8E89F0095ACE75A379C651"
+            + "FD6BDD55703C90672E44C6BAB6AACDD8"
+            + "7C976A87FD264B906E749429284134C2"
+            + "38E3B88CF74A68245B860D119A8BDF43";
+
+        private static readonly string chacha8_set1v0_256 =
+            "F7CA95BF08688BD3BE8A27724210F9DC"
+            + "16F32AF974FBFB09E9F757C577A245AB"
+            + "F35F824B70A4C02CB4A8D7191FA8A5AD"
+            + "6A84568743844703D353B7F00A8601F4";
+
+        private static readonly string chacha8_set1v0_448 =
+            "7B4117E8BFFD595CD8482270B08920FB"
+            + "C9B97794E1809E07BB271BF07C861003"
+            + "4C38DBA6ECA04E5474F399A284CBF6E2"
+            + "7F70142E604D0977797DE5B58B6B25E0";
+
+        public override string Name
+        {
+            get { return "ChaCha"; }
+        }
+
+        public override void PerformTest()
+        {
+            chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")),
+                    set1v0_0, set1v0_192,  set1v0_256,  set1v0_448);
+            chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("00400000000000000000000000000000")), Hex.Decode("0000000000000000")),
+                    set1v9_0, set1v9_192,  set1v9_256,  set1v9_448);
+            chachaTest1(12, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")),
+                    chacha12_set1v0_0, chacha12_set1v0_192,  chacha12_set1v0_256,  chacha12_set1v0_448);
+            chachaTest1(8, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")),
+                    chacha8_set1v0_0, chacha8_set1v0_192,  chacha8_set1v0_256,  chacha8_set1v0_448);
+            chachaTest2(new ParametersWithIV(new KeyParameter(Hex.Decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.Decode("0D74DB42A91077DE")),
+                    set6v0_0, set6v0_65472, set6v0_65536);
+            chachaTest2(new ParametersWithIV(new KeyParameter(Hex.Decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.Decode("167DE44BB21980E7")),
+                    set6v1_0, set6v1_65472, set6v1_65536);
+            reinitBug();
+        }
+
+        private void chachaTest1(
+            int rounds,
+            ICipherParameters	parameters,
+            string				v0,
+            string				v192,
+            string				v256,
+            string				v448)
+        {
+            IStreamCipher salsa = new ChaChaEngine(rounds);
+            byte[]       buf = new byte[64];
+
+            salsa.Init(true, parameters);
+
+            for (int i = 0; i != 7; i++)
+            {
+                salsa.ProcessBytes(zeroes, 0, 64, buf, 0);
+                switch (i)
+                {
+                case 0:
+                    if (!AreEqual(buf, Hex.Decode(v0)))
+                    {
+                        mismatch("v0/" + rounds, v0, buf);
+                    }
+                    break;
+                case 3:
+                    if (!AreEqual(buf, Hex.Decode(v192)))
+                    {
+                        mismatch("v192/" + rounds, v192, buf);
+                    }
+                    break;
+                case 4:
+                    if (!AreEqual(buf, Hex.Decode(v256)))
+                    {
+                        mismatch("v256/" + rounds, v256, buf);
+                    }
+                    break;
+                default:
+                    // ignore
+                    break;
+                }
+            }
+
+            for (int i = 0; i != 64; i++)
+            {
+                buf[i] = salsa.ReturnByte(zeroes[i]);
+            }
+
+            if (!AreEqual(buf, Hex.Decode(v448)))
+            {
+                mismatch("v448", v448, buf);
+            }       
+        }
+
+        private void chachaTest2(
+            ICipherParameters	parameters,
+            string				v0,
+            string				v65472,
+            string				v65536)
+        {
+            IStreamCipher salsa = new ChaChaEngine();
+            byte[]       buf = new byte[64];
+
+            salsa.Init(true, parameters);
+
+            for (int i = 0; i != 1025; i++)
+            {
+                salsa.ProcessBytes(zeroes, 0, 64, buf, 0);
+                switch (i)
+                {
+                case 0:
+                    if (!AreEqual(buf, Hex.Decode(v0)))
+                    {
+                        mismatch("v0", v0, buf);
+                    }
+                    break;
+                case 1023:
+                    if (!AreEqual(buf, Hex.Decode(v65472)))
+                    {
+                        mismatch("v65472", v65472, buf);
+                    }
+                    break;
+                case 1024:
+                    if (!AreEqual(buf, Hex.Decode(v65536)))
+                    {
+                        mismatch("v65536", v65536, buf);
+                    }
+                    break;
+                default:
+                    // ignore
+                    break;
+                }
+            }
+        }
+
+        private void mismatch(
+            string	name,
+            string	expected,
+            byte[]	found)
+        {
+            Fail("mismatch on " + name, expected, Hex.ToHexString(found));
+        }
+
+        private void reinitBug()
+        {
+            KeyParameter key = new KeyParameter(Hex.Decode("80000000000000000000000000000000"));
+            ParametersWithIV parameters = new ParametersWithIV(key, Hex.Decode("0000000000000000"));
+
+            IStreamCipher chacha = new ChaChaEngine();
+
+            chacha.Init(true, parameters);
+
+            try
+            {
+                chacha.Init(true, key);
+                Fail("ChaCha should throw exception if no IV in Init");
+            }
+            catch (ArgumentException)
+            {
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ChaChaTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/CipherTest.cs b/crypto/test/src/crypto/test/CipherTest.cs
new file mode 100644
index 000000000..d9c085d44
--- /dev/null
+++ b/crypto/test/src/crypto/test/CipherTest.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	public abstract class CipherTest
+		: SimpleTest
+	{
+		private SimpleTest[]      _tests;
+		private IBlockCipher _engine;
+		private KeyParameter _validKey;
+
+//		protected CipherTest(
+//			SimpleTest[]	tests)
+//		{
+//			_tests = tests;
+//		}
+
+		protected CipherTest(
+			SimpleTest[]	tests,
+			IBlockCipher	engine,
+			KeyParameter	validKey)
+		{
+			_tests = tests;
+			_engine = engine;
+			_validKey = validKey;
+		}
+
+		public override void PerformTest()
+		{
+			for (int i = 0; i != _tests.Length; i++)
+			{
+				_tests[i].PerformTest();
+			}
+
+			if (_engine != null)
+			{
+				//
+				// state tests
+				//
+				byte[] buf = new byte[_engine.GetBlockSize()];
+
+				try
+				{
+					_engine.ProcessBlock(buf, 0, buf, 0);
+
+					Fail("failed initialisation check");
+				}
+				catch (InvalidOperationException)
+				{
+					// expected
+				}
+
+				bufferSizeCheck((_engine));
+			}
+		}
+
+		private void bufferSizeCheck(
+			IBlockCipher engine)
+		{
+			byte[] correctBuf = new byte[engine.GetBlockSize()];
+			byte[] shortBuf = new byte[correctBuf.Length / 2];
+
+			engine.Init(true, _validKey);
+
+			try
+			{
+				engine.ProcessBlock(shortBuf, 0, correctBuf, 0);
+
+				Fail("failed short input check");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+
+			try
+			{
+				engine.ProcessBlock(correctBuf, 0, shortBuf, 0);
+
+				Fail("failed short output check");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+
+			engine.Init(false, _validKey);
+
+			try
+			{
+				engine.ProcessBlock(shortBuf, 0, correctBuf, 0);
+
+				Fail("failed short input check");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+
+			try
+			{
+				engine.ProcessBlock(correctBuf, 0, shortBuf, 0);
+
+				Fail("failed short output check");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/DESTest.cs b/crypto/test/src/crypto/test/DESTest.cs
new file mode 100644
index 000000000..cf1022eae
--- /dev/null
+++ b/crypto/test/src/crypto/test/DESTest.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	internal class DesParityTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "DESParityTest"; }
+		}
+
+		public override void PerformTest()
+		{
+			byte[] k1In = { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+							   (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff };
+			byte[] k1Out = { (byte)0xfe, (byte)0xfe, (byte)0xfe, (byte)0xfe,
+								(byte)0xfe, (byte)0xfe, (byte)0xfe, (byte)0xfe };
+
+			byte[] k2In = { (byte)0xef, (byte)0xcb, (byte)0xda, (byte)0x4f,
+							   (byte)0xaa, (byte)0x99, (byte)0x7f, (byte)0x63 };
+			byte[] k2Out = { (byte)0xef, (byte)0xcb, (byte)0xda, (byte)0x4f,
+								(byte)0xab, (byte)0x98, (byte)0x7f, (byte)0x62 };
+
+			DesParameters.SetOddParity(k1In);
+
+			for (int i = 0; i != k1In.Length; i++)
+			{
+				if (k1In[i] != k1Out[i])
+				{
+					Fail("Failed "
+						+ "got " + Hex.ToHexString(k1In)
+						+ " expected " + Hex.ToHexString(k1Out));
+				}
+			}
+
+			DesParameters.SetOddParity(k2In);
+
+			for (int i = 0; i != k2In.Length; i++)
+			{
+				if (k2In[i] != k2Out[i])
+				{
+					Fail("Failed "
+						+ "got " + Hex.ToHexString(k2In)
+						+ " expected " + Hex.ToHexString(k2Out));
+				}
+			}
+		}
+	}
+
+	internal class KeyGenTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "KeyGenTest"; }
+		}
+
+		public override void PerformTest()
+		{
+			DesKeyGenerator keyGen = new DesKeyGenerator();
+
+			keyGen.Init(new KeyGenerationParameters(new SecureRandom(), 56));
+
+			byte[] kB = keyGen.GenerateKey();
+
+			if (kB.Length != 8)
+			{
+				Fail("DES bit key wrong length.");
+			}
+		}
+	}
+
+	internal class DesParametersTest
+		: SimpleTest
+	{
+		private static readonly byte[] weakKeys =
+		{
+			(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
+		};
+
+		public override string Name
+		{
+			get { return "DesParameters"; }
+		}
+
+		public override void PerformTest()
+		{
+			try
+			{
+				DesParameters.IsWeakKey(new byte[4], 0);
+				Fail("no exception on small key");
+			}
+			catch (ArgumentException e)
+			{
+				if (!e.Message.Equals("key material too short."))
+				{
+					Fail("wrong exception");
+				}
+			}
+
+			try
+			{
+				new DesParameters(weakKeys);
+				Fail("no exception on weak key");
+			}
+			catch (ArgumentException e)
+			{
+				if (!e.Message.Equals("attempt to create weak DES key"))
+				{
+					Fail("wrong exception");
+				}
+			}
+
+			for (int i = 0; i != weakKeys.Length; i += 8)
+			{
+				if (!DesParameters.IsWeakKey(weakKeys, i))
+				{
+					Fail("weakKey test failed");
+				}
+			}
+		}
+	}
+
+	/**
+	 * DES tester - vectors from <a href="http://www.itl.nist.gov/fipspubs/fip81.htm">FIPS 81</a>
+	 */
+	[TestFixture]
+	public class DesTest
+		: CipherTest
+	{
+		static string input1 = "4e6f77206973207468652074696d6520666f7220616c6c20";
+		static string input2 = "4e6f7720697320746865";
+		static string input3 = "4e6f7720697320746865aabbcc";
+
+		static SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new DesEngine(),
+				new DesParameters(Hex.Decode("0123456789abcdef")),
+				input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"),
+			new BlockCipherVectorTest(1, new CbcBlockCipher(new DesEngine()),
+				new ParametersWithIV(new DesParameters(Hex.Decode("0123456789abcdef")), Hex.Decode("1234567890abcdef")),
+				input1, "e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6"),
+			new BlockCipherVectorTest(2, new CfbBlockCipher(new DesEngine(), 8),
+				new ParametersWithIV(new DesParameters(Hex.Decode("0123456789abcdef")), Hex.Decode("1234567890abcdef")),
+				input2, "f31fda07011462ee187f"),
+			new BlockCipherVectorTest(3, new CfbBlockCipher(new DesEngine(), 64),
+				new ParametersWithIV(new DesParameters(Hex.Decode("0123456789abcdef")), Hex.Decode("1234567890abcdef")),
+				input1, "f3096249c7f46e51a69e839b1a92f78403467133898ea622"),
+			new BlockCipherVectorTest(4, new OfbBlockCipher(new DesEngine(), 8),
+				new ParametersWithIV(new DesParameters(Hex.Decode("0123456789abcdef")), Hex.Decode("1234567890abcdef")),
+				input2, "f34a2850c9c64985d684"),
+			new BlockCipherVectorTest(5, new CfbBlockCipher(new DesEngine(), 64),
+				new ParametersWithIV(new DesParameters(Hex.Decode("0123456789abcdef")), Hex.Decode("1234567890abcdef")),
+				input3, "f3096249c7f46e51a69e0954bf"),
+			new BlockCipherVectorTest(6, new OfbBlockCipher(new DesEngine(), 64),
+				new ParametersWithIV(new DesParameters(Hex.Decode("0123456789abcdef")), Hex.Decode("1234567890abcdef")),
+				input3, "f3096249c7f46e5135f2c0eb8b"),
+			new DesParityTest(),
+			new DesParametersTest(),
+			new KeyGenTest()
+		};
+
+		public DesTest()
+			: base(tests, new DesEngine(), new DesParameters(new byte[8]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "DES"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new DesTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/DESedeTest.cs b/crypto/test/src/crypto/test/DESedeTest.cs
new file mode 100644
index 000000000..aa61844f2
--- /dev/null
+++ b/crypto/test/src/crypto/test/DESedeTest.cs
@@ -0,0 +1,187 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+/**
+ * DESede tester
+ */
+	[TestFixture]
+	public class DesEdeTest
+		:CipherTest
+	{
+		private static readonly byte[] weakKey =     // first 8 bytes non-weak
+		{
+			(byte)0x06,(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,
+		};
+
+		private const string input1 = "4e6f77206973207468652074696d6520666f7220616c6c20";
+//		private const string input2 = "4e6f7720697320746865";
+
+		private static SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new DesEdeEngine(),
+				new DesEdeParameters(Hex.Decode("0123456789abcdef0123456789abcdef")),
+				input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"),
+			new BlockCipherVectorTest(1, new DesEdeEngine(),
+				new DesEdeParameters(Hex.Decode("0123456789abcdeffedcba9876543210")),
+				input1, "d80a0d8b2bae5e4e6a0094171abcfc2775d2235a706e232c"),
+			new BlockCipherVectorTest(2, new DesEdeEngine(),
+				new DesEdeParameters(Hex.Decode("0123456789abcdef0123456789abcdef0123456789abcdef")),
+				input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"),
+			new BlockCipherVectorTest(3, new DesEdeEngine(),
+				new DesEdeParameters(Hex.Decode("0123456789abcdeffedcba98765432100123456789abcdef")),
+				input1, "d80a0d8b2bae5e4e6a0094171abcfc2775d2235a706e232c")
+		};
+
+		public DesEdeTest()
+			: base(tests, new DesEdeEngine(), new DesEdeParameters(new byte[16]))
+		{
+		}
+
+		private void WrapTest(
+			int     id,
+			byte[]  kek,
+			byte[]  iv,
+			byte[]  input,
+			byte[]  output)
+		{
+			IWrapper wrapper = new DesEdeWrapEngine();
+
+			wrapper.Init(true, new ParametersWithIV(new DesEdeParameters(kek), iv));
+
+			try
+			{
+				byte[] cText = wrapper.Wrap(input, 0, input.Length);
+				if (!AreEqual(cText, output))
+				{
+					Fail(": failed wrap test " + id  + " expected " + Hex.ToHexString(output)
+						+ " got " + Hex.ToHexString(cText));
+				}
+			}
+			catch (Exception e)
+			{
+				Fail("failed wrap test exception: " + e.ToString(), e);
+			}
+
+			wrapper.Init(false, new DesEdeParameters(kek));
+
+			try
+			{
+				byte[] pText = wrapper.Unwrap(output, 0, output.Length);
+				if (!AreEqual(pText, input))
+				{
+					Fail("failed unwrap test " + id  + " expected " + Hex.ToHexString(input)
+						+ " got " + Hex.ToHexString(pText));
+				}
+			}
+			catch (Exception e)
+			{
+				Fail("failed unwrap test exception: " + e.ToString(), e);
+			}
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			byte[] kek1 = Hex.Decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f");
+			byte[] iv1 = Hex.Decode("5dd4cbfc96f5453b");
+			byte[] in1 = Hex.Decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98");
+			byte[] out1 = Hex.Decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4");
+
+			WrapTest(1, kek1, iv1, in1, out1);
+
+			//
+			// key generation
+			//
+			SecureRandom random = new SecureRandom();
+			DesEdeKeyGenerator keyGen = new DesEdeKeyGenerator();
+
+			keyGen.Init(new KeyGenerationParameters(random, 112));
+
+			byte[] kB = keyGen.GenerateKey();
+	        
+			if (kB.Length != 16)
+			{
+				Fail("112 bit key wrong length.");
+			}
+	        
+			keyGen.Init(new KeyGenerationParameters(random, 168));
+	        
+			kB = keyGen.GenerateKey();
+	        
+			if (kB.Length != 24)
+			{
+				Fail("168 bit key wrong length.");
+			}
+	        
+			try
+			{
+				keyGen.Init(new KeyGenerationParameters(random, 200));
+	            
+				Fail("invalid key length not detected.");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+
+			try
+			{
+				DesEdeParameters.IsWeakKey(new byte[4], 0);
+				Fail("no exception on small key");
+			}
+			catch (ArgumentException e)
+			{
+				if (!e.Message.Equals("key material too short."))
+				{
+					Fail("wrong exception");
+				}
+			}
+
+			try
+			{
+				new DesEdeParameters(weakKey);
+				Fail("no exception on weak key");
+			}
+			catch (ArgumentException e)
+			{
+				if (!e.Message.Equals("attempt to create weak DESede key"))
+				{
+					Fail("wrong exception");
+				}
+			}
+		}
+
+		public override string Name
+		{
+			get { return "DESede"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new DesEdeTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/DHKEKGeneratorTest.cs b/crypto/test/src/crypto/test/DHKEKGeneratorTest.cs
new file mode 100644
index 000000000..eee408f97
--- /dev/null
+++ b/crypto/test/src/crypto/test/DHKEKGeneratorTest.cs
@@ -0,0 +1,79 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <remarks>DHKEK Generator tests - from RFC 2631.</remarks>
+	[TestFixture]
+	public class DHKekGeneratorTest
+		: SimpleTest
+	{
+		private byte[] seed1 = Hex.Decode("000102030405060708090a0b0c0d0e0f10111213");
+		private DerObjectIdentifier alg1 = PkcsObjectIdentifiers.IdAlgCms3DesWrap;
+		private byte[] result1 = Hex.Decode("a09661392376f7044d9052a397883246b67f5f1ef63eb5fb");
+
+		private byte[] seed2 = Hex.Decode("000102030405060708090a0b0c0d0e0f10111213");
+		private DerObjectIdentifier alg2 = PkcsObjectIdentifiers.IdAlgCmsRC2Wrap;
+		private byte[] partyAInfo = Hex.Decode(
+				"0123456789abcdeffedcba9876543201"
+			+ "0123456789abcdeffedcba9876543201"
+			+ "0123456789abcdeffedcba9876543201"
+			+ "0123456789abcdeffedcba9876543201");
+		private byte[] result2 = Hex.Decode("48950c46e0530075403cce72889604e0");
+
+		public DHKekGeneratorTest()
+		{
+		}
+
+		public override void PerformTest()
+		{
+			CheckMask(1, new DHKekGenerator(new Sha1Digest()), new DHKdfParameters(alg1, 192, seed1), result1);
+			CheckMask(2, new DHKekGenerator(new Sha1Digest()), new DHKdfParameters(alg2, 128, seed2, partyAInfo), result2);
+		}
+
+		private void CheckMask(
+			int						count,
+			IDerivationFunction		kdf,
+			IDerivationParameters	parameters,
+			byte[]					result)
+		{
+			byte[] data = new byte[result.Length];
+
+			kdf.Init(parameters);
+
+			kdf.GenerateBytes(data, 0, data.Length);
+
+			if (!AreEqual(result, data))
+			{
+				Fail("DHKekGenerator failed generator test " + count);
+			}
+		}
+
+		public override string Name
+		{
+			get { return "DHKekGenerator"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new DHKekGeneratorTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/DHTest.cs b/crypto/test/src/crypto/test/DHTest.cs
new file mode 100644
index 000000000..b460f41a5
--- /dev/null
+++ b/crypto/test/src/crypto/test/DHTest.cs
@@ -0,0 +1,403 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class DHTest
+		: SimpleTest
+	{
+		private static readonly BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+		private static readonly BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+		private static readonly BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16);
+		private static readonly BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16);
+
+		private static readonly BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16);
+		private static readonly BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16);
+
+		public override string Name
+		{
+			get { return "DH"; }
+		}
+
+		private void doTestDH(
+			int         size,
+			BigInteger  g,
+			BigInteger  p)
+		{
+			DHKeyPairGenerator kpGen = getDHKeyPairGenerator(g, p);
+
+			//
+			// generate first pair
+			//
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.Private;
+			//
+			// generate second pair
+			//
+			pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.Private;
+
+			//
+			// two way
+			//
+			DHAgreement e1 = new DHAgreement();
+			DHAgreement e2 = new DHAgreement();
+
+			e1.Init(pv1);
+			e2.Init(pv2);
+
+			BigInteger m1 = e1.CalculateMessage();
+			BigInteger m2 = e2.CalculateMessage();
+
+			BigInteger k1 = e1.CalculateAgreement(pu2, m2);
+			BigInteger k2 = e2.CalculateAgreement(pu1, m1);
+
+			if (!k1.Equals(k2))
+			{
+				Fail(size + " bit 2-way test failed");
+			}
+		}
+
+		private void doTestDHBasic(
+			int         size,
+			int         privateValueSize,
+			BigInteger  g,
+			BigInteger  p)
+		{
+			DHBasicKeyPairGenerator kpGen = getDHBasicKeyPairGenerator(g, p, privateValueSize);
+
+			//
+			// generate first pair
+			//
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.Private;
+
+			checkKeySize(privateValueSize, pv1);
+			//
+			// generate second pair
+			//
+			pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.Private;
+
+			checkKeySize(privateValueSize, pv2);
+			//
+			// two way
+			//
+			DHBasicAgreement e1 = new DHBasicAgreement();
+			DHBasicAgreement e2 = new DHBasicAgreement();
+
+			e1.Init(pv1);
+			e2.Init(pv2);
+
+			BigInteger k1 = e1.CalculateAgreement(pu2);
+			BigInteger k2 = e2.CalculateAgreement(pu1);
+
+			if (!k1.Equals(k2))
+			{
+				Fail("basic " + size + " bit 2-way test failed");
+			}
+		}
+
+		private void checkKeySize(
+			int privateValueSize,
+			DHPrivateKeyParameters priv)
+		{
+			if (privateValueSize != 0)
+			{
+				if (priv.X.BitLength != privateValueSize)
+				{
+					Fail("limited key check failed for key size " + privateValueSize);
+				}
+			}
+		}
+
+		private void doTestGPWithRandom(
+			DHKeyPairGenerator kpGen)
+		{
+			//
+			// generate first pair
+			//
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.Private;
+			//
+			// generate second pair
+			//
+			pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.Private;
+
+			//
+			// two way
+			//
+			DHAgreement e1 = new DHAgreement();
+			DHAgreement e2 = new DHAgreement();
+
+			e1.Init(new ParametersWithRandom(pv1, new SecureRandom()));
+			e2.Init(new ParametersWithRandom(pv2, new SecureRandom()));
+
+			BigInteger m1 = e1.CalculateMessage();
+			BigInteger m2 = e2.CalculateMessage();
+
+			BigInteger k1 = e1.CalculateAgreement(pu2, m2);
+			BigInteger k2 = e2.CalculateAgreement(pu1, m1);
+
+			if (!k1.Equals(k2))
+			{
+				Fail("basic with random 2-way test failed");
+			}
+		}
+
+		private void doTestSimpleWithRandom(
+			DHBasicKeyPairGenerator kpGen)
+		{
+			//
+			// generate first pair
+			//
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.Private;
+			//
+			// generate second pair
+			//
+			pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.Private;
+
+			//
+			// two way
+			//
+			DHBasicAgreement e1 = new DHBasicAgreement();
+			DHBasicAgreement e2 = new DHBasicAgreement();
+
+			e1.Init(new ParametersWithRandom(pv1, new SecureRandom()));
+			e2.Init(new ParametersWithRandom(pv2, new SecureRandom()));
+
+			BigInteger   k1 = e1.CalculateAgreement(pu2);
+			BigInteger   k2 = e2.CalculateAgreement(pu1);
+
+			if (!k1.Equals(k2))
+			{
+				Fail("basic with random 2-way test failed");
+			}
+		}
+
+		private DHBasicKeyPairGenerator getDHBasicKeyPairGenerator(
+			BigInteger g,
+			BigInteger p,
+			int        privateValueSize)
+		{
+			DHParameters dhParams = new DHParameters(p, g, null, privateValueSize);
+			DHKeyGenerationParameters dhkgParams = new DHKeyGenerationParameters(new SecureRandom(), dhParams);
+			DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator();
+
+			kpGen.Init(dhkgParams);
+
+			return kpGen;
+		}
+
+		private DHKeyPairGenerator getDHKeyPairGenerator(
+			BigInteger g,
+			BigInteger p)
+		{
+			DHParameters dhParams = new DHParameters(p, g);
+			DHKeyGenerationParameters dhkgParams = new DHKeyGenerationParameters(new SecureRandom(), dhParams);
+			DHKeyPairGenerator kpGen = new DHKeyPairGenerator();
+
+			kpGen.Init(dhkgParams);
+
+			return kpGen;
+		}
+
+		/**
+		 * this test is can take quiet a while
+		 */
+		private void doTestGeneration(
+			int size)
+		{
+			DHParametersGenerator pGen = new DHParametersGenerator();
+
+			pGen.Init(size, 10, new SecureRandom());
+
+			DHParameters dhParams = pGen.GenerateParameters();
+
+			if (dhParams.L != 0)
+			{
+				Fail("DHParametersGenerator failed to set J to 0 in generated DHParameters");
+			}
+
+			DHKeyGenerationParameters dhkgParams = new DHKeyGenerationParameters(new SecureRandom(), dhParams);
+
+			DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator();
+
+			kpGen.Init(dhkgParams);
+
+			//
+			// generate first pair
+			//
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.Private;
+
+			//
+			// generate second pair
+			//
+			dhkgParams = new DHKeyGenerationParameters(new SecureRandom(), pu1.Parameters);
+
+			kpGen.Init(dhkgParams);
+
+			pair = kpGen.GenerateKeyPair();
+
+			DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.Private;
+
+			//
+			// two way
+			//
+			DHBasicAgreement e1 = new DHBasicAgreement();
+			DHBasicAgreement e2 = new DHBasicAgreement();
+
+			e1.Init(new ParametersWithRandom(pv1, new SecureRandom()));
+			e2.Init(new ParametersWithRandom(pv2, new SecureRandom()));
+
+			BigInteger k1 = e1.CalculateAgreement(pu2);
+			BigInteger k2 = e2.CalculateAgreement(pu1);
+
+			if (!k1.Equals(k2))
+			{
+				Fail("basic with " + size + " bit 2-way test failed");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			doTestDHBasic(512, 0, g512, p512);
+			doTestDHBasic(768, 0, g768, p768);
+			doTestDHBasic(1024, 0, g1024, p1024);
+
+			doTestDHBasic(512, 64, g512, p512);
+			doTestDHBasic(768, 128, g768, p768);
+			doTestDHBasic(1024, 256, g1024, p1024);
+
+			doTestDH(512, g512, p512);
+			doTestDH(768, g768, p768);
+			doTestDH(1024, g1024, p1024);
+
+			//
+			// generation test.
+			//
+			doTestGeneration(256);
+
+			//
+			// with random test
+			//
+			DHBasicKeyPairGenerator kpBasicGen = getDHBasicKeyPairGenerator(g512, p512, 0);
+
+			doTestSimpleWithRandom(kpBasicGen);
+
+			DHKeyPairGenerator kpGen = getDHKeyPairGenerator(g512, p512);
+
+			doTestGPWithRandom(kpGen);
+
+			//
+			// parameter tests
+			//
+			DHAgreement dh = new DHAgreement();
+			AsymmetricCipherKeyPair dhPair = kpGen.GenerateKeyPair();
+
+			try
+			{
+				dh.Init(dhPair.Public);
+				Fail("DHAgreement key check failed");
+			}
+			catch (ArgumentException)
+			{
+				// ignore
+			}
+
+			DHKeyPairGenerator kpGen768 = getDHKeyPairGenerator(g768, p768);
+
+			try
+			{
+				dh.Init(dhPair.Private);
+
+				dh.CalculateAgreement((DHPublicKeyParameters)kpGen768.GenerateKeyPair().Public, BigInteger.ValueOf(100));
+
+				Fail("DHAgreement agreement check failed");
+			}
+			catch (ArgumentException)
+			{
+				// ignore
+			}
+
+			DHBasicAgreement dhBasic = new DHBasicAgreement();
+			AsymmetricCipherKeyPair dhBasicPair = kpBasicGen.GenerateKeyPair();
+
+			try
+			{
+				dhBasic.Init(dhBasicPair.Public);
+				Fail("DHBasicAgreement key check failed");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+
+			DHBasicKeyPairGenerator kpBasicGen768 = getDHBasicKeyPairGenerator(g768, p768, 0);
+
+			try
+			{
+				dhBasic.Init(dhPair.Private);
+
+				dhBasic.CalculateAgreement((DHPublicKeyParameters)kpBasicGen768.GenerateKeyPair().Public);
+
+				Fail("DHBasicAgreement agreement check failed");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new DHTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/DSATest.cs b/crypto/test/src/crypto/test/DSATest.cs
new file mode 100644
index 000000000..0e6367150
--- /dev/null
+++ b/crypto/test/src/crypto/test/DSATest.cs
@@ -0,0 +1,615 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary>Test based on FIPS 186-2, Appendix 5, an example of DSA, and FIPS 168-3 test vectors.</summary>
+    [TestFixture]
+    public class DsaTest
+        : SimpleTest
+    {
+        public override string Name
+        {
+            get { return "DSA"; }
+        }
+
+        internal BigInteger pValue = new BigInteger("8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291", 16);
+        internal BigInteger qValue = new BigInteger("c773218c737ec8ee993b4f2ded30f48edace915f", 16);
+
+        public override void PerformTest()
+        {
+            byte[] k1 = Hex.Decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
+            byte[] k2 = Hex.Decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
+
+            SecureRandom random = FixedSecureRandom.From(k1, k2);
+
+            byte[] keyData = Hex.Decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
+
+            SecureRandom keyRandom = FixedSecureRandom.From(keyData, keyData);
+
+            BigInteger r = new BigInteger("68076202252361894315274692543577577550894681403");
+            BigInteger s = new BigInteger("1089214853334067536215539335472893651470583479365");
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+
+            pGen.Init(512, 80, random);
+
+            DsaParameters parameters = pGen.GenerateParameters();
+            DsaValidationParameters pValid = parameters.ValidationParameters;
+
+            if (pValid.Counter != 105)
+            {
+                Fail("Counter wrong");
+            }
+
+            if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+            {
+                Fail("p or q wrong");
+            }
+
+            DsaKeyPairGenerator dsaKeyGen = new DsaKeyPairGenerator();
+            DsaKeyGenerationParameters genParam = new DsaKeyGenerationParameters(keyRandom, parameters);
+
+            dsaKeyGen.Init(genParam);
+
+            AsymmetricCipherKeyPair pair = dsaKeyGen.GenerateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.Private, keyRandom);
+
+            DsaSigner dsa = new DsaSigner();
+
+            dsa.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").ToByteArrayUnsigned();
+            BigInteger[] sig = dsa.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            dsa.Init(false, pair.Public);
+
+            if (!dsa.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("verification fails");
+            }
+
+            Dsa2Test1();
+            Dsa2Test2();
+            Dsa2Test3();
+            Dsa2Test4();
+        }
+
+        private void Dsa2Test1()
+        {
+            byte[] seed = Hex.Decode("ED8BEE8D1CB89229D2903CBF0E51EE7377F48698");
+
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+
+            pGen.Init(new DsaParameterGenerationParameters(1024, 160, 80, new DsaTestSecureRandom(seed)));
+
+            DsaParameters parameters = pGen.GenerateParameters();
+
+            DsaValidationParameters pv = parameters.ValidationParameters;
+
+            if (pv.Counter != 5)
+            {
+                Fail("counter incorrect");
+            }
+
+            if (!AreEqual(seed, pv.GetSeed()))
+            {
+                Fail("seed incorrect");
+            }
+
+            if (!parameters.Q.Equals(new BigInteger("E950511EAB424B9A19A2AEB4E159B7844C589C4F", 16)))
+            {
+                Fail("Q incorrect");
+            }
+
+            if (!parameters.P.Equals(new BigInteger(
+                "E0A67598CD1B763B" +
+                "C98C8ABB333E5DDA0CD3AA0E5E1FB5BA8A7B4EABC10BA338" +
+                "FAE06DD4B90FDA70D7CF0CB0C638BE3341BEC0AF8A7330A3" +
+                "307DED2299A0EE606DF035177A239C34A912C202AA5F83B9" +
+                "C4A7CF0235B5316BFC6EFB9A248411258B30B839AF172440" +
+                "F32563056CB67A861158DDD90E6A894C72A5BBEF9E286C6B", 16)))
+            {
+                Fail("P incorrect");
+            }
+
+            if (!parameters.G.Equals(new BigInteger(
+                "D29D5121B0423C27" +
+                "69AB21843E5A3240FF19CACC792264E3BB6BE4F78EDD1B15" +
+                "C4DFF7F1D905431F0AB16790E1F773B5CE01C804E509066A" +
+                "9919F5195F4ABC58189FD9FF987389CB5BEDF21B4DAB4F8B" +
+                "76A055FFE2770988FE2EC2DE11AD92219F0B351869AC24DA" +
+                "3D7BA87011A701CE8EE7BFE49486ED4527B7186CA4610A75", 16)))
+            {
+                Fail("G incorrect");
+            }
+
+            DsaKeyPairGenerator kpGen = new DsaKeyPairGenerator();
+
+            kpGen.Init(new DsaKeyGenerationParameters(FixedSecureRandom.From(Hex.Decode("D0EC4E50BB290A42E9E355C73D8809345DE2E139")), parameters));
+
+            AsymmetricCipherKeyPair kp = kpGen.GenerateKeyPair();
+
+            DsaPublicKeyParameters pub = (DsaPublicKeyParameters)kp.Public;
+            DsaPrivateKeyParameters priv = (DsaPrivateKeyParameters)kp.Private;
+
+            if (!pub.Y.Equals(new BigInteger(
+                "25282217F5730501" +
+                "DD8DBA3EDFCF349AAFFEC20921128D70FAC44110332201BB" +
+                "A3F10986140CBB97C726938060473C8EC97B4731DB004293" +
+                "B5E730363609DF9780F8D883D8C4D41DED6A2F1E1BBBDC97" +
+                "9E1B9D6D3C940301F4E978D65B19041FCF1E8B518F5C0576" +
+                "C770FE5A7A485D8329EE2914A2DE1B5DA4A6128CEAB70F79", 16)))
+            {
+                Fail("Y value incorrect");
+            }
+
+            if (!priv.X.Equals(
+                new BigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16)))
+            {
+                Fail("X value incorrect");
+            }
+
+            DsaSigner signer = new DsaSigner();
+
+            signer.Init(true, new ParametersWithRandom(kp.Private, FixedSecureRandom.From(Hex.Decode("349C55648DCF992F3F33E8026CFAC87C1D2BA075"))));
+
+            byte[] msg = Hex.Decode("A9993E364706816ABA3E25717850C26C9CD0D89D");
+
+            BigInteger[] sig = signer.GenerateSignature(msg);
+
+            if (!sig[0].Equals(new BigInteger("636155AC9A4633B4665D179F9E4117DF68601F34", 16)))
+            {
+                Fail("R value incorrect");
+            }
+
+            if (!sig[1].Equals(new BigInteger("6C540B02D9D4852F89DF8CFC99963204F4347704", 16)))
+            {
+                Fail("S value incorrect");
+            }
+
+            signer.Init(false, kp.Public);
+
+            if (!signer.VerifySignature(msg, sig[0], sig[1]))
+            {
+                Fail("signature not verified");
+            }
+
+        }
+
+        private void Dsa2Test2()
+        {
+            byte[] seed = Hex.Decode("5AFCC1EFFC079A9CCA6ECA86D6E3CC3B18642D9BE1CC6207C84002A9");
+
+            DsaParametersGenerator pGen = new DsaParametersGenerator(new Sha224Digest());
+
+            pGen.Init(new DsaParameterGenerationParameters(2048, 224, 80, new DsaTestSecureRandom(seed)));
+
+            DsaParameters parameters = pGen.GenerateParameters();
+
+            DsaValidationParameters pv = parameters.ValidationParameters;
+
+            if (pv.Counter != 21)
+            {
+                Fail("counter incorrect");
+            }
+
+            if (!AreEqual(seed, pv.GetSeed()))
+            {
+                Fail("seed incorrect");
+            }
+
+            if (!parameters.Q.Equals(new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16)))
+            {
+                Fail("Q incorrect");
+            }
+
+            if (!parameters.P.Equals(new BigInteger(
+                "C196BA05AC29E1F9C3C72D56DFFC6154" +
+                "A033F1477AC88EC37F09BE6C5BB95F51C296DD20D1A28A06" +
+                "7CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" +
+                "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE6" +
+                "19ECACC7E0B51652A8776D02A425567DED36EABD90CA33A1" +
+                "E8D988F0BBB92D02D1D20290113BB562CE1FC856EEB7CDD9" +
+                "2D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" +
+                "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E" +
+                "5320121496DC65B3930E38047294FF877831A16D5228418D" +
+                "E8AB275D7D75651CEFED65F78AFC3EA7FE4D79B35F62A040" +
+                "2A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16)))
+            {
+                Fail("P incorrect");
+            }
+
+            if (!parameters.G.Equals(new BigInteger(
+                "A59A749A11242C58C894E9E5A91804E8"+
+                "FA0AC64B56288F8D47D51B1EDC4D65444FECA0111D78F35F"+
+                "C9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50"+
+                "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B"+
+                "6E770409494B7FEE1DBB1E4B2BC2A53D4F893D418B715959"+
+                "2E4FFFDF6969E91D770DAEBD0B5CB14C00AD68EC7DC1E574"+
+                "5EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF"+
+                "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E69"+
+                "5515B05BD412F5B8C2F4C77EE10DA48ABD53F5DD498927EE"+
+                "7B692BBBCDA2FB23A516C5B4533D73980B2A3B60E384ED20"+
+                "0AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16)))
+            {
+                Fail("G incorrect");
+            }
+
+            DsaKeyPairGenerator kpGen = new DsaKeyPairGenerator();
+
+            kpGen.Init(new DsaKeyGenerationParameters(
+                FixedSecureRandom.From(Hex.Decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), parameters));
+
+            AsymmetricCipherKeyPair kp = kpGen.GenerateKeyPair();
+
+            DsaPublicKeyParameters pub = (DsaPublicKeyParameters)kp.Public;
+            DsaPrivateKeyParameters priv = (DsaPrivateKeyParameters)kp.Private;
+
+            if (!pub.Y.Equals(new BigInteger(
+                "70035C9A3B225B258F16741F3941FBF0" +
+                "6F3D056CD7BD864604CBB5EE9DD85304EE8E8E4ABD5E9032" +
+                "11DDF25CE149075510ACE166970AFDC7DF552B7244F342FA" +
+                "02F7A621405B754909D757F97290E1FE5036E904CF593446" +
+                "0C046D95659821E1597ED9F2B1F0E20863A6BBD0CE74DACB" +
+                "A5D8C68A90B29C2157CDEDB82EC12B81EE3068F9BF5F7F34" +
+                "6ECA41ED174CCCD7D154FA4F42F80FFE1BF46AE9D8125DEB" +
+                "5B4BA08A72BDD86596DBEDDC9550FDD650C58F5AE5133509" +
+                "A702F79A31ECB490F7A3C5581631F7C5BE4FF7F9E9F27FA3" +
+                "90E47347AD1183509FED6FCF198BA9A71AB3335B4F38BE8D" +
+                "15496A00B6DC2263E20A5F6B662320A3A1EC033AA61E3B68", 16)))
+            {
+                Fail("Y value incorrect");
+            }
+
+            if (!priv.X.Equals(
+                new BigInteger("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17", 16)))
+            {
+                Fail("X value incorrect");
+            }
+
+            DsaSigner signer = new DsaSigner();
+
+            signer.Init(true, new ParametersWithRandom(kp.Private,
+                FixedSecureRandom.From(Hex.Decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05"))));
+
+            byte[] msg = Hex.Decode("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7");
+
+            BigInteger[] sig = signer.GenerateSignature(msg);
+
+            if (!sig[0].Equals(new BigInteger("4400138D05F9639CAF54A583CAAF25D2B76D0C3EAD752CE17DBC85FE", 16)))
+            {
+                Fail("R value incorrect");
+            }
+
+            if (!sig[1].Equals(new BigInteger("874D4F12CB13B61732D398445698CFA9D92381D938AA57EE2C9327B3", 16)))
+            {
+                Fail("S value incorrect");
+            }
+
+            signer.Init(false, kp.Public);
+
+            if (!signer.VerifySignature(msg, sig[0], sig[1]))
+            {
+                Fail("signature not verified");
+            }
+        }
+
+        private void Dsa2Test3()
+        {
+            byte[] seed = Hex.Decode("4783081972865EA95D43318AB2EAF9C61A2FC7BBF1B772A09017BDF5A58F4FF0");
+
+            DsaParametersGenerator pGen = new DsaParametersGenerator(new Sha256Digest());
+
+            pGen.Init(new DsaParameterGenerationParameters(2048, 256, 80, new DsaTestSecureRandom(seed)));
+
+            DsaParameters parameters = pGen.GenerateParameters();
+
+            DsaValidationParameters pv = parameters.ValidationParameters;
+
+            if (pv.Counter != 12)
+            {
+                Fail("counter incorrect");
+            }
+
+            if (!AreEqual(seed, pv.GetSeed()))
+            {
+                Fail("seed incorrect");
+            }
+
+            if (!parameters.Q.Equals(new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16)))
+            {
+                Fail("Q incorrect");
+            }
+
+            if (!parameters.P.Equals(new BigInteger(
+                "F56C2A7D366E3EBDEAA1891FD2A0D099" +
+                "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" +
+                "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" +
+                "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" +
+                "5909132627F51A0C866877E672E555342BDF9355347DBD43" +
+                "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" +
+                "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" +
+                "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" +
+                "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" +
+                "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" +
+                "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16)))
+            {
+                Fail("P incorrect");
+            }
+
+            if (!parameters.G.Equals(new BigInteger(
+                "8DC6CC814CAE4A1C05A3E186A6FE27EA" +
+                "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" +
+                "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" +
+                "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" +
+                "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" +
+                "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" +
+                "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" +
+                "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" +
+                "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" +
+                "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" +
+                "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16)))
+            {
+                Fail("G incorrect");
+            }
+
+            DsaKeyPairGenerator kpGen = new DsaKeyPairGenerator();
+
+            kpGen.Init(new DsaKeyGenerationParameters(
+                FixedSecureRandom.From(Hex.Decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), parameters));
+
+            AsymmetricCipherKeyPair kp = kpGen.GenerateKeyPair();
+
+            DsaPublicKeyParameters pub = (DsaPublicKeyParameters)kp.Public;
+            DsaPrivateKeyParameters priv = (DsaPrivateKeyParameters)kp.Private;
+
+            if (!pub.Y.Equals(new BigInteger(
+                "2828003D7C747199143C370FDD07A286" +
+                "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" +
+                "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" +
+                "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" +
+                "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" +
+                "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" +
+                "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" +
+                "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" +
+                "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" +
+                "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" +
+                "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16)))
+            {
+                Fail("Y value incorrect");
+            }
+
+            if (!priv.X.Equals(
+                new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16)))
+            {
+                Fail("X value incorrect");
+            }
+
+            DsaSigner signer = new DsaSigner();
+
+            signer.Init(true, new ParametersWithRandom(kp.Private,
+                FixedSecureRandom.From(Hex.Decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C"))));
+
+            byte[] msg = Hex.Decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD");
+
+            BigInteger[] sig = signer.GenerateSignature(msg);
+
+            if (!sig[0].Equals(new BigInteger("315C875DCD4850E948B8AC42824E9483A32D5BA5ABE0681B9B9448D444F2BE3C", 16)))
+            {
+                Fail("R value incorrect");
+            }
+
+            if (!sig[1].Equals(new BigInteger("89718D12E54A8D9ED066E4A55F7ED5A2229CD23B9A3CEE78F83ED6AA61F6BCB9", 16)))
+            {
+                Fail("S value incorrect");
+            }
+
+            signer.Init(false, kp.Public);
+
+            if (!signer.VerifySignature(msg, sig[0], sig[1]))
+            {
+                Fail("signature not verified");
+            }
+        }
+
+        private void Dsa2Test4()
+        {
+            byte[] seed = Hex.Decode("193AFCA7C1E77B3C1ECC618C81322E47B8B8B997C9C83515C59CC446C2D9BD47");
+
+            DsaParametersGenerator pGen = new DsaParametersGenerator(new Sha256Digest());
+
+            pGen.Init(new DsaParameterGenerationParameters(3072, 256, 80, new DsaTestSecureRandom(seed)));
+
+            DsaParameters parameters = pGen.GenerateParameters();
+
+            DsaValidationParameters pv = parameters.ValidationParameters;
+
+            if (pv.Counter != 20)
+            {
+                Fail("counter incorrect");
+            }
+
+            if (!AreEqual(seed, pv.GetSeed()))
+            {
+                Fail("seed incorrect");
+            }
+
+            if (!parameters.Q.Equals(new BigInteger("CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D", 16)))
+            {
+                Fail("Q incorrect");
+            }
+
+            if (!parameters.P.Equals(new BigInteger(
+                "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD610" +
+                "37E56258A7795A1C7AD46076982CE6BB956936C6AB4DCFE0" +
+                "5E6784586940CA544B9B2140E1EB523F009D20A7E7880E4E" +
+                "5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" +
+                "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D" +
+                "3485261CD068699B6BA58A1DDBBEF6DB51E8FE34E8A78E54" +
+                "2D7BA351C21EA8D8F1D29F5D5D15939487E27F4416B0CA63" +
+                "2C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" +
+                "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0E" +
+                "E6F29AF7F642773EBE8CD5402415A01451A840476B2FCEB0" +
+                "E388D30D4B376C37FE401C2A2C2F941DAD179C540C1C8CE0" +
+                "30D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" +
+                "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C56" +
+                "0EA878DE87C11E3D597F1FEA742D73EEC7F37BE43949EF1A" +
+                "0D15C3F3E3FC0A8335617055AC91328EC22B50FC15B941D3" +
+                "D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73", 16)))
+            {
+                Fail("P incorrect");
+            }
+
+            if (!parameters.G.Equals(new BigInteger(
+                "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE" +
+                "3B7ACCC54D521E37F84A4BDD5B06B0970CC2D2BBB715F7B8" +
+                "2846F9A0C393914C792E6A923E2117AB805276A975AADB52" +
+                "61D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" +
+                "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A" +
+                "60126FEB2CF05DB8A7F0F09B3397F3937F2E90B9E5B9C9B6" +
+                "EFEF642BC48351C46FB171B9BFA9EF17A961CE96C7E7A7CC" +
+                "3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" +
+                "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B6" +
+                "7299E231F8BD90B39AC3AE3BE0C6B6CACEF8289A2E2873D5" +
+                "8E51E029CAFBD55E6841489AB66B5B4B9BA6E2F784660896" +
+                "AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" +
+                "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B98856" +
+                "7A88126B914D7828E2B63A6D7ED0747EC59E0E0A23CE7D8A" +
+                "74C1D2C2A7AFB6A29799620F00E11C33787F7DED3B30E1A2" +
+                "2D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B", 16)))
+            {
+                Fail("G incorrect");
+            }
+
+            DsaKeyPairGenerator kpGen = new DsaKeyPairGenerator();
+
+            kpGen.Init(new DsaKeyGenerationParameters(
+                FixedSecureRandom.From(Hex.Decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), parameters));
+
+            AsymmetricCipherKeyPair kp = kpGen.GenerateKeyPair();
+
+            DsaPublicKeyParameters pub = (DsaPublicKeyParameters)kp.Public;
+            DsaPrivateKeyParameters priv = (DsaPrivateKeyParameters)kp.Private;
+
+            if (!pub.Y.Equals(new BigInteger(
+                "8B891C8692D3DE875879390F2698B26FBECCA6B075535DCE" +
+                "6B0C862577F9FA0DEF6074E7A7624121224A595896ABD4CD" +
+                "A56B2CEFB942E025D2A4282FFAA98A48CDB47E1A6FCB5CFB" +
+                "393EF35AF9DF913102BB303C2B5C36C3F8FC04ED7B8B69FE" +
+                "FE0CF3E1FC05CFA713B3435B2656E913BA8874AEA9F93600" +
+                "6AEB448BCD005D18EC3562A33D04CF25C8D3D69844343442" +
+                "FA3DB7DE618C5E2DA064573E61E6D5581BFB694A23AC87FD" +
+                "5B52D62E954E1376DB8DDB524FFC0D469DF978792EE44173" +
+                "8E5DB05A7DC43E94C11A2E7A4FBE383071FA36D2A7EC8A93" +
+                "88FE1C4F79888A99D3B6105697C2556B79BB4D7E781CEBB3" +
+                "D4866AD825A5E830846072289FDBC941FA679CA82F5F78B7" +
+                "461B2404DB883D215F4E0676CF5493950AC5591697BFEA8D" +
+                "1EE6EC016B89BA51CAFB5F9C84C989FA117375E94578F28B" +
+                "E0B34CE0545DA46266FD77F62D8F2CEE92AB77012AFEBC11" +
+                "008985A821CD2D978C7E6FE7499D1AAF8DE632C21BB48CA5" +
+                "CBF9F31098FD3FD3854C49A65D9201744AACE540354974F9", 16)))
+            {
+                Fail("Y value incorrect");
+            }
+
+            if (!priv.X.Equals(
+                new BigInteger("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764", 16)))
+            {
+                Fail("X value incorrect");
+            }
+
+            DsaSigner signer = new DsaSigner();
+
+            signer.Init(true, new ParametersWithRandom(kp.Private,
+                FixedSecureRandom.From(Hex.Decode("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE"))));
+
+            byte[] msg = Hex.Decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD");
+
+            BigInteger[] sig = signer.GenerateSignature(msg);
+
+            if (!sig[0].Equals(new BigInteger("5F184E645A38BE8FB4A6871B6503A9D12924C7ABE04B71410066C2ECA6E3BE3E", 16)))
+            {
+                Fail("R value incorrect");
+            }
+
+            if (!sig[1].Equals(new BigInteger("91EB0C7BA3D4B9B60B825C3D9F2CADA8A2C9D7723267B033CBCDCF8803DB9C18", 16)))
+            {
+                Fail("S value incorrect");
+            }
+
+            signer.Init(false, kp.Public);
+
+            if (!signer.VerifySignature(msg, sig[0], sig[1]))
+            {
+                Fail("signature not verified");
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new DsaTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        private class DsaTestSecureRandom
+            : FixedSecureRandom
+        {
+            private bool first = true;
+
+            public DsaTestSecureRandom(byte[] value)
+                : base(Arrays.Clone(value))
+            {
+            }
+
+            public override void NextBytes(byte[] bytes)
+            {
+                if (first)
+                {
+                    base.NextBytes(bytes);
+                    first = false;
+                }
+                else
+                {
+                    bytes[bytes.Length - 1] = 2;
+                }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/DeterministicDSATest.cs b/crypto/test/src/crypto/test/DeterministicDSATest.cs
new file mode 100644
index 000000000..914a770bd
--- /dev/null
+++ b/crypto/test/src/crypto/test/DeterministicDSATest.cs
@@ -0,0 +1,511 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary>
+    /// Tests are taken from RFC 6979 - "Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)".
+    /// </summary>
+    [TestFixture]
+    public class DeterministicDsaTest
+        :   SimpleTest
+    {
+        public static readonly byte[] SAMPLE = Hex.Decode("73616d706c65"); // "sample"
+        public static readonly byte[] TEST = Hex.Decode("74657374"); // "test"
+
+        // test vectors from appendix in RFC 6979
+        private void TestHMacDeterministic()
+        {
+            DsaParameters dsaParameters = new DsaParameters(
+                new BigInteger("86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447" +
+                               "E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88" +
+                               "73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C" +
+                               "881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779", 16),
+                new BigInteger("996F967F6C8E388D9E28D01E205FBA957A5698B1", 16),
+                new BigInteger("07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D" +
+                               "89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD" +
+                               "87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4" +
+                               "17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD", 16));
+
+            DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters(new BigInteger("411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", 16), dsaParameters);
+
+            DoTestHMacDetDsaSample(new Sha1Digest(), privKey, new BigInteger("2E1A0C2562B2912CAAF89186FB0F42001585DA55", 16), new BigInteger("29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", 16));
+            DoTestHMacDetDsaSample(new Sha224Digest(), privKey, new BigInteger("4BC3B686AEA70145856814A6F1BB53346F02101E", 16), new BigInteger("410697B92295D994D21EDD2F4ADA85566F6F94C1", 16));
+            DoTestHMacDetDsaSample(new Sha256Digest(), privKey, new BigInteger("81F2F5850BE5BC123C43F71A3033E9384611C545", 16), new BigInteger("4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", 16));
+            DoTestHMacDetDsaSample(new Sha384Digest(), privKey, new BigInteger("07F2108557EE0E3921BC1774F1CA9B410B4CE65A", 16), new BigInteger("54DF70456C86FAC10FAB47C1949AB83F2C6F7595", 16));
+            DoTestHMacDetDsaSample(new Sha512Digest(), privKey, new BigInteger("16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", 16), new BigInteger("02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", 16));
+
+            DoTestHMacDetDsaTest(new Sha1Digest(), privKey, new BigInteger("42AB2052FD43E123F0607F115052A67DCD9C5C77", 16), new BigInteger("183916B0230D45B9931491D4C6B0BD2FB4AAF088", 16));
+            DoTestHMacDetDsaTest(new Sha224Digest(), privKey, new BigInteger("6868E9964E36C1689F6037F91F28D5F2C30610F2", 16), new BigInteger("49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F", 16));
+            DoTestHMacDetDsaTest(new Sha256Digest(), privKey, new BigInteger("22518C127299B0F6FDC9872B282B9E70D0790812", 16), new BigInteger("6837EC18F150D55DE95B5E29BE7AF5D01E4FE160", 16));
+            DoTestHMacDetDsaTest(new Sha384Digest(), privKey, new BigInteger("854CF929B58D73C3CBFDC421E8D5430CD6DB5E66", 16), new BigInteger("91D0E0F53E22F898D158380676A871A157CDA622", 16));
+            DoTestHMacDetDsaTest(new Sha512Digest(), privKey, new BigInteger("8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0", 16), new BigInteger("7C670C7AD72B6C050C109E1790008097125433E8", 16));
+
+            dsaParameters = new DsaParameters(
+                new BigInteger("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" +
+                    "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" +
+                    "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" +
+                    "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" +
+                    "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" +
+                    "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" +
+                    "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" +
+                    "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16),
+                new BigInteger("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", 16),
+                new BigInteger("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" +
+                    "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" +
+                    "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" +
+                    "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" +
+                    "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" +
+                    "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" +
+                    "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" +
+                    "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16));
+
+            privKey = new DsaPrivateKeyParameters(new BigInteger("69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", 16), dsaParameters);
+
+            DoTestHMacDetDsaSample(new Sha1Digest(), privKey, new BigInteger("3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A", 16), new BigInteger("D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF", 16));
+            DoTestHMacDetDsaSample(new Sha224Digest(), privKey, new BigInteger("DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C", 16), new BigInteger("A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC", 16));
+            DoTestHMacDetDsaSample(new Sha256Digest(), privKey, new BigInteger("EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809", 16), new BigInteger("7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53", 16));
+            DoTestHMacDetDsaSample(new Sha384Digest(), privKey, new BigInteger("B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B", 16), new BigInteger("19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B", 16));
+            DoTestHMacDetDsaSample(new Sha512Digest(), privKey, new BigInteger("2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E", 16), new BigInteger("D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351", 16));
+
+            DoTestHMacDetDsaTest(new Sha1Digest(), privKey, new BigInteger("C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0", 16), new BigInteger("414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA", 16));
+            DoTestHMacDetDsaTest(new Sha224Digest(), privKey, new BigInteger("272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3", 16), new BigInteger("E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806", 16));
+            DoTestHMacDetDsaTest(new Sha256Digest(), privKey, new BigInteger("8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0", 16), new BigInteger("7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E", 16));
+            DoTestHMacDetDsaTest(new Sha384Digest(), privKey, new BigInteger("239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE", 16), new BigInteger("6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961", 16));
+            DoTestHMacDetDsaTest(new Sha512Digest(), privKey, new BigInteger("89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307", 16), new BigInteger("C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1", 16));
+        }
+
+        private void DoTestHMacDetDsaSample(IDigest digest, DsaPrivateKeyParameters privKey, BigInteger r, BigInteger s)
+        {
+            DoTestHMacDetECDsa(new DsaSigner(new HMacDsaKCalculator(digest)), digest, SAMPLE, privKey, r, s);
+        }
+
+        private void DoTestHMacDetDsaTest(IDigest digest, DsaPrivateKeyParameters privKey, BigInteger r, BigInteger s)
+        {
+            DoTestHMacDetECDsa(new DsaSigner(new HMacDsaKCalculator(digest)), digest, TEST, privKey, r, s);
+        }
+
+        // test vectors from appendix in RFC 6979
+        private void TestECHMacDeterministic()
+        {
+            X9ECParameters x9ECParameters = NistNamedCurves.GetByName("P-192");
+            ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(new BigInteger("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", 16), new BigInteger("57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", 16), new BigInteger("E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", 16), new BigInteger("CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", 16), new BigInteger("C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", 16), new BigInteger("3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey,   new BigInteger("0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", 16), new BigInteger("EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", 16), new BigInteger("B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", 16), new BigInteger("5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", 16), new BigInteger("7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", 16), new BigInteger("74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("P-224");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("F220266E1105BFE3083E03EC7A3A654651F45E37167E88600BF257C1", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("22226F9D40A96E19C4A301CE5B74B115303C0F3A4FD30FC257FB57AC", 16), new BigInteger("66D1CDD83E3AF75605DD6E2FEFF196D30AA7ED7A2EDF7AF475403D69", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E", 16), new BigInteger("A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA", 16), new BigInteger("BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("0B115E5E36F0F9EC81F1325A5952878D745E19D7BB3EABFABA77E953", 16), new BigInteger("830F34CCDFE826CCFDC81EB4129772E20E122348A2BBD889A1B1AF1D", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("074BD1D979D5F32BF958DDC61E4FB4872ADCAFEB2256497CDAC30397", 16), new BigInteger("A4CECA196C3D5A1FF31027B33185DC8EE43F288B21AB342E5D8EB084", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey,   new BigInteger("DEAA646EC2AF2EA8AD53ED66B2E2DDAA49A12EFD8356561451F3E21C", 16), new BigInteger("95987796F6CF2062AB8135271DE56AE55366C045F6D9593F53787BD2", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019", 16), new BigInteger("902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6", 16), new BigInteger("178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("389B92682E399B26518A95506B52C03BC9379A9DADF3391A21FB0EA4", 16), new BigInteger("414A718ED3249FF6DBC5B50C27F71F01F070944DA22AB1F78F559AAB", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("049F050477C5ADD858CAC56208394B5A55BAEBBE887FDF765047C17C", 16), new BigInteger("077EB13E7005929CEFA3CD0403C7CDCC077ADF4E44F3C41B2F60ECFF", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("P-256");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32", 16), new BigInteger("6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F", 16), new BigInteger("B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716", 16), new BigInteger("F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719", 16), new BigInteger("4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00", 16), new BigInteger("2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey,   new BigInteger("0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89", 16), new BigInteger("01B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692", 16), new BigInteger("C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367", 16), new BigInteger("019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB6", 16), new BigInteger("8DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04", 16), new BigInteger("39AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("P-384");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D8" +
+                                                                "96D5724E4C70A825F872C9EA60D2EDF5", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey, new BigInteger("EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA3" +
+                                                                        "7B9BA002899F6FDA3A4A9386790D4EB2", 16),
+                                                                new BigInteger("A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF" +
+                                                                        "26F49CA031D4857570CCB5CA4424A443", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366" +
+                                                                            "450F76EE3DE43F5A125333A6BE060122", 16),
+                                                                  new BigInteger("9DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E483" +
+                                                                            "4C082C03D83028EFBF93A3C23940CA8D", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33" +
+                                                                            "BDE1E888E63355D92FA2B3C36D8FB2CD", 16),
+                                                                    new BigInteger("F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEB" +
+                                                                            "EFDC63ECCD1AC42EC0CB8668A4FA0AB0", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C" +
+                                                                            "81A648152E44ACF96E36DD1E80FABE46", 16),
+                                                                    new BigInteger("99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94F" +
+                                                                            "A329C145786E679E7B82C71A38628AC8", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799C" +
+                                                                            "FE30F35CC900056D7C99CD7882433709", 16),
+                                                                    new BigInteger("512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112" +
+                                                                            "DC7CC3EF3446DEFCEB01A45C2667FDD5", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey, new BigInteger("4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678" +
+                                                                        "ACD9D29876DAF46638645F7F404B11C7", 16),
+                                                                new BigInteger("D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A29916" +
+                                                                        "95BA1C84541327E966FA7B50F7382282", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E624" +
+                                                                        "64A9A817C47FF78B8C11066B24080E72", 16),
+                                                                new BigInteger("07041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C614" +
+                                                                        "1C53EA5ABEF0D8231077A04540A96B66", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559" +
+                                                                        "F918EEDAF2293BE5B475CC8F0188636B", 16),
+                                                                new BigInteger("2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D" +
+                                                                        "51AB373F9845C0514EEFB14024787265", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB" +
+                                                                        "0542A7F0812998DA8F1DD3CA3CF023DB", 16),
+                                                                new BigInteger("DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E0" +
+                                                                        "6A739F040649A667BF3B828246BAA5A5", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D0" +
+                                                                        "6FB6495CD21B4B6E340FC236584FB277", 16),
+                                                                new BigInteger("976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B22463" +
+                                                                        "4A2092CD3792E0159AD9CEE37659C736", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("P-521");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75C" +
+                                                                "AA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83" +
+                                                                "538", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("0343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910" +
+                                                                                 "FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D" +
+                                                                                 "75D", 16),
+                                                                  new BigInteger("0E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D" +
+                                                                                 "5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5" +
+                                                                                 "D16", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("1776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A3" +
+                                                                                "0715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2E" +
+                                                                                "D2E", 16),
+                                                                  new BigInteger("050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17B" +
+                                                                                "A41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B" +
+                                                                                "41F", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("1511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659" +
+                                                                                 "D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E" +
+                                                                                 "1A7", 16),
+                                                                  new BigInteger("04A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916" +
+                                                                                  "E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7E" +
+                                                                                  "CFC", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("1EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4" +
+                                                                                "B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67" +
+                                                                                "451", 16),
+                                                                  new BigInteger("1F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5" +
+                                                                                  "FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65" +
+                                                                                  "D61", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F1" +
+                                                                                "74E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E37" +
+                                                                                "7FA", 16),
+                                                                  new BigInteger("0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF2" +
+                                                                                  "82623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A" +
+                                                                                  "67A", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey,   new BigInteger("13BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0" +
+                                                                        "693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0" +
+                                                                        "367", 16),
+                                                                  new BigInteger("1E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90" +
+                                                                      "F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC91679" +
+                                                                      "7FF", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("1C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086" +
+                                                                        "BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE1" +
+                                                                        "7FB", 16),
+                                                                  new BigInteger("177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5" +
+                                                                      "BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD51" +
+                                                                      "9A4", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("00E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D807104" +
+                                                                        "2EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656" +
+                                                                        "AA8", 16),
+                                                                  new BigInteger("0CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9" +
+                                                                      "FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694" +
+                                                                      "E86", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("14BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C" +
+                                                                        "89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF60755" +
+                                                                        "78C", 16),
+                                                                  new BigInteger("133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0E" +
+                                                                      "D94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B" +
+                                                                      "979", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10" +
+                                                                        "CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47E" +
+                                                                        "E6D", 16),
+                                                                  new BigInteger("1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78" +
+                                                                      "A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4D" +
+                                                                      "CE3", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("B-163");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("35318FC447D48D7E6BC93B48617DDDEDF26AA658F", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("153FEBD179A69B6122DEBF5BC61EB947B24C93526", 16), new BigInteger("37AC9C670F8CF18045049BAE7DD35553545C19E49", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("0A379E69C44F9C16EA3215EA39EB1A9B5D58CC955", 16), new BigInteger("04BAFF5308DA2A7FE2C1742769265AD3ED1D24E74", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("134E00F78FC1CB9501675D91C401DE20DDF228CDC", 16), new BigInteger("373273AEC6C36CB7BAFBB1903A5F5EA6A1D50B624", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("29430B935AF8E77519B0CA4F6903B0B82E6A21A66", 16), new BigInteger("1EA1415306E9353FA5AA54BC7C2581DFBB888440D", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("0B2F177A99F9DF2D51CCAF55F015F326E4B65E7A0", 16), new BigInteger("0DF1FB4487E9B120C5E970EFE48F55E406306C3A1", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey,   new BigInteger("256D4079C6C7169B8BC92529D701776A269D56308", 16), new BigInteger("341D3FFEC9F1EB6A6ACBE88E3C86A1C8FDEB8B8E1", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("28ECC6F1272CE80EA59DCF32F7AC2D861BA803393", 16), new BigInteger("0AD4AE2C06E60183C1567D2B82F19421FE3053CE2", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("227DF377B3FA50F90C1CB3CDCBBDBA552C1D35104", 16), new BigInteger("1F7BEAD92583FE920D353F368C1960D0E88B46A56", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("11811DAFEEA441845B6118A0DFEE8A0061231337D", 16), new BigInteger("36258301865EE48C5C6F91D63F62695002AB55B57", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("3B6BB95CA823BE2ED8E3972FF516EB8972D765571", 16), new BigInteger("13DC6F420628969DF900C3FCC48220B38BE24A541", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("B-233");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("07ADC13DD5BF34D1DDEEB50B2CE23B5F5E6D18067306D60C5F6FF11E5D3", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("015CC6FD78BB06E0878E71465515EA5A21A2C18E6FC77B4B158DBEB3944", 16), new BigInteger("0822A4A6C2EB2DF213A5E90BF40377956365EE8C4B4A5A4E2EB9270CB6A", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("05D9920B53471148E10502AB49AB7A3F11084820A074FD89883CF51BC1A", 16), new BigInteger("04D3938900C0A9AAA7080D1DFEB56CFB0FADABE4214536C7ED5117ED13A", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("0A797F3B8AEFCE7456202DF1E46CCC291EA5A49DA3D4BDDA9A4B62D5E0D", 16), new BigInteger("01F6F81DA55C22DA4152134C661588F4BD6F82FDBAF0C5877096B070DC2", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("015E85A8D46225DD7E314A1C4289731FC14DECE949349FE535D11043B85", 16), new BigInteger("03F189D37F50493EFD5111A129443A662AB3C6B289129AD8C0CAC85119C", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("03B62A4BF783919098B1E42F496E65F7621F01D1D466C46940F0F132A95", 16), new BigInteger("0F4BE031C6E5239E7DAA014CBBF1ED19425E49DAEB426EC9DF4C28A2E30", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey,   new BigInteger("02F1FEDC57BE203E4C8C6B8C1CEB35E13C1FCD956AB41E3BD4C8A6EFB1F", 16), new BigInteger("05738EC8A8EDEA8E435EE7266AD3EDE1EEFC2CEBE2BE1D614008D5D2951", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("0CCE175124D3586BA7486F7146894C65C2A4A5A1904658E5C7F9DF5FA5D", 16), new BigInteger("08804B456D847ACE5CA86D97BF79FD6335E5B17F6C0D964B5D0036C867E", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("035C3D6DFEEA1CFB29B93BE3FDB91A7B130951770C2690C16833A159677", 16), new BigInteger("0600F7301D12AB376B56D4459774159ADB51F97E282FF384406AFD53A02", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("061602FC8068BFD5FB86027B97455D200EC603057446CCE4D76DB8EF42C", 16), new BigInteger("03396DD0D59C067BB999B422D9883736CF9311DFD6951F91033BD03CA8D", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("07E12CB60FDD614958E8E34B3C12DDFF35D85A9C5800E31EA2CC2EF63B1", 16), new BigInteger("0E8970FD99D836F3CC1C807A2C58760DE6EDAA23705A82B9CB1CE93FECC", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("B-283");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("14510D4BC44F2D26F4553942C98073C1BD35545CEABB5CC138853C5158D2729EA408836", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("201E18D48C6DB3D5D097C4DCE1E25587E1501FC3CF47BDB5B4289D79E273D6A9" +
+                "ACB8285", 16), new BigInteger("151AE05712B024CE617358260774C8CA8B0E7A7E72EF8229BF2ACE7609560CB3" +
+                "0322C4F", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("143E878DDFD4DF40D97B8CD638B3C4706501C2201CF7108F2FB91478C11D6947" +
+                "3246925", 16), new BigInteger("0CBF1B9717FEEA3AABB09D9654110144267098E0E1E8D0289A6211BE0EEDFDD8" +
+                "6A3DB79", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("29FD82497FB3E5CEF65579272138DE59E2B666B8689466572B3B69A172CEE83B" +
+                "E145659", 16), new BigInteger("05A89D9166B40795AF0FE5958201B9C0523E500013CA12B4840EA2BC53F25F9B" +
+                "3CE87C0", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("2F00689C1BFCD2A8C7A41E0DE55AE182E6463A152828EF89FE3525139B660329" +
+                "4E69353", 16), new BigInteger("1744514FE0A37447250C8A329EAAADA81572226CABA16F39270EE5DD03F27B1F" +
+                "665EB5D", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("0DA43A9ADFAA6AD767998A054C6A8F1CF77A562924628D73C62761847AD8286E" +
+                "0D91B47", 16), new BigInteger("1D118733AE2C88357827CAFC6F68ABC25C80C640532925E95CFE66D40F8792F3" +
+                "AC44C42", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey,   new BigInteger("05A408133919F2CDCDBE5E4C14FBC706C1F71BADAFEF41F5DE4EC27272FC1CA9" +
+                "366FBB2", 16), new BigInteger("012966272872C097FEA7BCE64FAB1A81982A773E26F6E4EF7C99969846E67CA9" +
+                "CBE1692", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("08F3824E40C16FF1DDA8DC992776D26F4A5981AB5092956C4FDBB4F1AE0A711E" +
+                "EAA10E5", 16), new BigInteger("0A64B91EFADB213E11483FB61C73E3EF63D3B44EEFC56EA401B99DCC60CC28E9" +
+                "9F0F1FA", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("3597B406F5329D11A79E887847E5EC60861CCBB19EC61F252DB7BD549C699951" +
+                "C182796", 16), new BigInteger("0A6A100B997BC622D91701D9F5C6F6D3815517E577622DA69D3A0E8917C1CBE6" +
+                "3ACD345", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("1BB490926E5A1FDC7C5AA86D0835F9B994EDA315CA408002AF54A298728D422E" +
+                "BF59E4C", 16), new BigInteger("36C682CFC9E2C89A782BFD3A191609D1F0C1910D5FD6981442070393159D65FB" +
+                "CC0A8BA", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("19944AA68F9778C2E3D6E240947613E6DA60EFCE9B9B2C063FF5466D72745B5A" +
+                "0B25BA2", 16), new BigInteger("03F1567B3C5B02DF15C874F0EE22850824693D5ADC4663BAA19E384E550B1DD4" +
+                "1F31EE6", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("B-409");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("0494994CC325B08E7B4CE038BD9436F90B5E59A2C13C3140CD3AE07C04A01FC489F572CE0569A6DB7B8060393DE76330C624177", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey,   new BigInteger("0D8783188E1A540E2022D389E1D35B32F56F8C2BB5636B8ABF7718806B27A713" +
+                "EBAE37F63ECD4B61445CEF5801B62594EF3E982", 16), new BigInteger("03A6B4A80E204DB0DE12E7415C13C9EC091C52935658316B4A0C591216A38791" +
+                "54BEB1712560E346E7EF26517707435B55C3141", 16));
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("0EE4F39ACC2E03CE96C3D9FCBAFA5C22C89053662F8D4117752A9B10F09ADFDA" +
+                "59DB061E247FE5321D6B170EE758ACE1BE4D157", 16), new BigInteger("00A2B83265B456A430A8BF27DCC8A9488B3F126C10F0D6D64BF7B8A218FAAF20" +
+                "E51A295A3AE78F205E5A4A6AE224C3639F1BB34", 16));
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("02D8B1B31E33E74D7EB46C30FDE5AD2CA04EC8FE08FBA0E73BA5E568953AC5EA" +
+                "307C072942238DFC07F4A4D7C7C6A9F86436D17", 16), new BigInteger("079F7D471E6CB73234AF7F7C381D2CE15DE35BAF8BB68393B73235B3A26EC2DF" +
+                "4842CE433FB492D6E074E604D4870024D42189A", 16));
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("07BC638B7E7CE6FEE5E9C64A0F966D722D01BB4BC3F3A35F30D4CDDA92DFC5F7" +
+                "F0B4BBFE8065D9AD452FD77A1914BE3A2440C18", 16), new BigInteger("06D904429850521B28A32CBF55C7C0FDF35DC4E0BDA2552C7BF68A171E970E67" +
+                "88ACC0B9521EACB4796E057C70DD9B95FED5BFB", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("05D178DECAFD2D02A3DA0D8BA1C4C1D95EE083C760DF782193A9F7B4A8BE6FC5" +
+                "C21FD60613BCA65C063A61226E050A680B3ABD4", 16), new BigInteger("013B7581E98F6A63FBBCB3E49BCDA60F816DB230B888506D105DC229600497C3" +
+                "B46588C784BE3AA9343BEF82F7C9C80AEB63C3B", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey, new BigInteger("049F54E7C10D2732B4638473053782C6919218BBEFCEC8B51640FC193E832291" +
+                "F05FA12371E9B448417B3290193F08EE9319195", 16), new BigInteger("0499E267DEC84E02F6F108B10E82172C414F15B1B7364BE8BFD66ADC0C5DE23F" +
+                "EE3DF0D811134C25AFE0E05A6672F98889F28F1", 16));
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("0B1527FFAA7DD7C7E46B628587A5BEC0539A2D04D3CF27C54841C2544E1BBDB4" +
+                "2FDBDAAF8671A4CA86DFD619B1E3732D7BB56F2", 16), new BigInteger("0442C68C044868DF4832C807F1EDDEBF7F5052A64B826FD03451440794063F52" +
+                "B022DF304F47403D4069234CA9EB4C964B37C02", 16));
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("0BB27755B991D6D31757BCBF68CB01225A38E1CFA20F775E861055DD108ED7EA" +
+                "455E4B96B2F6F7CD6C6EC2B3C70C3EDDEB9743B", 16), new BigInteger("0C5BE90980E7F444B5F7A12C9E9AC7A04CA81412822DD5AD1BE7C45D5032555E" +
+                "A070864245CF69266871FEB8CD1B7EDC30EF6D5", 16));
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("04EFEB7098772187907C87B33E0FBBA4584226C50C11E98CA7AAC6986F8D3BE0" +
+                "44E5B52D201A410B852536527724CA5F8CE6549", 16), new BigInteger("09574102FEB3EF87E6D66B94119F5A6062950FF4F902EA1E6BD9E2037F33FF99" +
+                "1E31F5956C23AFE48FCDC557FD6F088C7C9B2B3", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("07E0249C68536AE2AEC2EC30090340DA49E6DC9E9EEC8F85E5AABFB234B6DA7D" +
+                "2E9524028CF821F21C6019770474CC40B01FAF6", 16), new BigInteger("08125B5A03FB44AE81EA46D446130C2A415ECCA265910CA69D55F2453E16CD7B" +
+                "2DFA4E28C50FA8137F9C0C6CEE4CD37ABCCF6D8", 16));
+
+            x9ECParameters = NistNamedCurves.GetByName("B-571");
+            ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
+
+            privKey = new ECPrivateKeyParameters(new BigInteger("028A04857F24C1C082DF0D909C0E72F453F2E2340CCB071F0E389BCA2575DA19" +
+                                                                "124198C57174929AD26E348CF63F78D28021EF5A9BF2D5CBEAF6B7CCB6C4DA82" +
+                                                                "4DD5C82CFB24E11", 16), ecDomainParameters);
+
+            DoTestHMacDetECDsaSample(new Sha1Digest(), privKey, new BigInteger("147D3EB0EDA9F2152DFD014363D6A9CE816D7A1467D326A625FC4AB0C786E1B7" +
+                                                                                "4DDF7CD4D0E99541391B266C704BB6B6E8DCCD27B460802E0867143727AA4155" +
+                                                                                "55454321EFE5CB6", 16),
+                                                                  new BigInteger("17319571CAF533D90D2E78A64060B9C53169AB7FC908947B3EDADC54C79CCF0A" +
+                                                                                  "7920B4C64A4EAB6282AFE9A459677CDA37FD6DD50BEF18709590FE18B923BDF7" +
+                                                                                  "4A66B189A850819", 16));
+
+            DoTestHMacDetECDsaSample(new Sha224Digest(), privKey, new BigInteger("10F4B63E79B2E54E4F4F6A2DBC786D8F4A143ECA7B2AD97810F6472AC6AE2085" +
+                                                                                "3222854553BE1D44A7974599DB7061AE8560DF57F2675BE5F9DD94ABAF3D47F1" +
+                                                                                "582B318E459748B", 16),
+                                                                  new BigInteger("3BBEA07C6B269C2B7FE9AE4DDB118338D0C2F0022920A7F9DCFCB7489594C03B" +
+                                                                                  "536A9900C4EA6A10410007222D3DAE1A96F291C4C9275D75D98EB290DC0EEF17" +
+                                                                                  "6037B2C7A7A39A3", 16));
+
+            DoTestHMacDetECDsaSample(new Sha256Digest(), privKey, new BigInteger("213EF9F3B0CFC4BF996B8AF3A7E1F6CACD2B87C8C63820000800AC787F17EC99" +
+                                                                                "C04BCEDF29A8413CFF83142BB88A50EF8D9A086AF4EB03E97C567500C21D8657" +
+                                                                                "14D832E03C6D054", 16),
+                                                                  new BigInteger("3D32322559B094E20D8935E250B6EC139AC4AAB77920812C119AF419FB62B332" +
+                                                                                  "C8D226C6C9362AE3C1E4AABE19359B8428EA74EC8FBE83C8618C2BCCB6B43FBA" +
+                                                                                  "A0F2CCB7D303945", 16));
+
+            DoTestHMacDetECDsaSample(new Sha384Digest(), privKey, new BigInteger("375D8F49C656A0BBD21D3F54CDA287D853C4BB1849983CD891EF6CD6BB56A62B" +
+                                                                                "687807C16685C2C9BCA2663C33696ACCE344C45F3910B1DF806204FF731ECB28" +
+                                                                                "9C100EF4D1805EC", 16),
+                                                                  new BigInteger("1CDEC6F46DFEEE44BCE71D41C60550DC67CF98D6C91363625AC2553E4368D2DF" +
+                                                                                "B734A8E8C72E118A76ACDB0E58697940A0F3DF49E72894BD799450FC9E550CC0" +
+                                                                                "4B9FF9B0380021C", 16));
+            DoTestHMacDetECDsaSample(new Sha512Digest(), privKey, new BigInteger("1C26F40D940A7EAA0EB1E62991028057D91FEDA0366B606F6C434C361F04E545" +
+                                                                                "A6A51A435E26416F6838FFA260C617E798E946B57215284182BE55F29A355E60" +
+                                                                                "24FE32A47289CF0", 16),
+                                                                  new BigInteger("3691DE4369D921FE94EDDA67CB71FBBEC9A436787478063EB1CC778B3DCDC1C4" +
+                                                                                "162662752D28DEEDF6F32A269C82D1DB80C87CE4D3B662E03AC347806E3F19D1" +
+                                                                                "8D6D4DE7358DF7E", 16));
+
+            DoTestHMacDetECDsaTest(new Sha1Digest(), privKey, new BigInteger("133F5414F2A9BC41466D339B79376038A64D045E5B0F792A98E5A7AA87E0AD01" +
+                "6419E5F8D176007D5C9C10B5FD9E2E0AB8331B195797C0358BA05ECBF24ACE59" +
+                "C5F368A6C0997CC", 16),
+                new BigInteger("3D16743AE9F00F0B1A500F738719C5582550FEB64689DA241665C4CE4F328BA0" +
+                    "E34A7EF527ED13BFA5889FD2D1D214C11EB17D6BC338E05A56F41CAFF1AF7B8D" +
+                    "574DB62EF0D0F21", 16));
+
+            DoTestHMacDetECDsaTest(new Sha224Digest(), privKey, new BigInteger("3048E76506C5C43D92B2E33F62B33E3111CEEB87F6C7DF7C7C01E3CDA28FA5E8" +
+                "BE04B5B23AA03C0C70FEF8F723CBCEBFF0B7A52A3F5C8B84B741B4F6157E69A5" +
+                "FB0524B48F31828", 16),
+                new BigInteger("2C99078CCFE5C82102B8D006E3703E020C46C87C75163A2CD839C885550BA5CB" +
+                    "501AC282D29A1C26D26773B60FBE05AAB62BFA0BA32127563D42F7669C97784C" +
+                    "8897C22CFB4B8FA", 16));
+
+            DoTestHMacDetECDsaTest(new Sha256Digest(), privKey, new BigInteger("184BC808506E11A65D628B457FDA60952803C604CC7181B59BD25AEE1411A66D" +
+                                                                        "12A777F3A0DC99E1190C58D0037807A95E5080FA1B2E5CCAA37B50D401CFFC34" +
+                                                                        "17C005AEE963469", 16),
+                                                                  new BigInteger("27280D45F81B19334DBDB07B7E63FE8F39AC7E9AE14DE1D2A6884D2101850289" +
+                                                                      "D70EE400F26ACA5E7D73F534A14568478E59D00594981ABE6A1BA18554C13EB5" +
+                                                                      "E03921E4DC98333", 16));
+
+            DoTestHMacDetECDsaTest(new Sha384Digest(), privKey, new BigInteger("319EE57912E7B0FAA1FBB145B0505849A89C6DB1EC06EA20A6A7EDE072A6268A" +
+                "F6FD9C809C7E422A5F33C6C3326EAD7402467DF3272A1B2726C1C20975950F0F" +
+                "50D8324578F13EC", 16),
+                new BigInteger("2CF3EA27EADD0612DD2F96F46E89AB894B01A10DF985C5FC099CFFE0EA083EB4" +
+                    "4BE682B08BFE405DAD5F37D0A2C59015BA41027E24B99F8F75A70B6B7385BF39" +
+                    "BBEA02513EB880C", 16));
+            DoTestHMacDetECDsaTest(new Sha512Digest(), privKey, new BigInteger("2AA1888EAB05F7B00B6A784C4F7081D2C833D50794D9FEAF6E22B8BE728A2A90" +
+                "BFCABDC803162020AA629718295A1489EE7ED0ECB8AAA197B9BDFC49D18DDD78" +
+                "FC85A48F9715544", 16),
+                new BigInteger("0AA5371FE5CA671D6ED9665849C37F394FED85D51FEF72DA2B5F28EDFB2C6479" +
+                    "CA63320C19596F5E1101988E2C619E302DD05112F47E8823040CE540CD3E90DC" +
+                    "F41DBC461744EE9", 16));
+
+        }
+
+        private void DoTestHMacDetECDsaSample(IDigest digest, ECPrivateKeyParameters privKey, BigInteger r, BigInteger s)
+        {
+            DoTestHMacDetECDsa(new ECDsaSigner(new HMacDsaKCalculator(digest)), digest, SAMPLE, privKey, r, s);
+        }
+
+        private void DoTestHMacDetECDsaTest(IDigest digest, ECPrivateKeyParameters privKey, BigInteger r, BigInteger s)
+        {
+            DoTestHMacDetECDsa(new ECDsaSigner(new HMacDsaKCalculator(digest)), digest, TEST, privKey, r, s);
+        }
+
+        private void DoTestHMacDetECDsa(IDsa detSigner, IDigest digest, byte[] data, ICipherParameters privKey, BigInteger r, BigInteger s)
+        {
+            byte[] m = new byte[digest.GetDigestSize()];
+
+            digest.BlockUpdate(data, 0, data.Length);
+
+            digest.DoFinal(m, 0);
+
+            detSigner.Init(true, privKey);
+
+            BigInteger[] rs = detSigner.GenerateSignature(m);
+
+            if (!r.Equals(rs[0]))
+            {
+                Fail("r value wrong");
+            }
+            if (!s.Equals(rs[1]))
+            {
+                Fail("s value wrong");
+            }
+        }
+
+        public override string Name
+        {
+            get { return "DeterministicDSA"; }
+        }
+
+        public override void PerformTest()
+        {
+            TestHMacDeterministic();
+            TestECHMacDeterministic();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new DeterministicDsaTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/DigestRandomNumberTest.cs b/crypto/test/src/crypto/test/DigestRandomNumberTest.cs
new file mode 100644
index 000000000..cee2e354e
--- /dev/null
+++ b/crypto/test/src/crypto/test/DigestRandomNumberTest.cs
@@ -0,0 +1,163 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class DigestRandomNumberTest
+		: SimpleTest
+	{
+		private static readonly byte[] ZERO_SEED = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+		private static readonly byte[] TEST_SEED = Hex.Decode("81dcfafc885914057876");
+
+		private static readonly byte[] expected0SHA1 = Hex.Decode("95bca677b3d4ff793213c00892d2356ec729ee02");
+		private static readonly byte[] noCycle0SHA1 = Hex.Decode("d57ccd0eb12c3938d59226412bc1268037b6b846");
+		private static readonly byte[] expected0SHA256 = Hex.Decode("587e2dfd597d086e47ddcd343eac983a5c913bef8c6a1a560a5c1bc3a74b0991");
+		private static readonly byte[] noCycle0SHA256 = Hex.Decode("e5776c4483486ba7be081f4e1b9dafbab25c8fae290fd5474c1ceda2c16f9509");
+		private static readonly byte[] expected100SHA1 = Hex.Decode("b9d924092546e0876cafd4937d7364ebf9efa4be");
+		private static readonly byte[] expected100SHA256 = Hex.Decode("fbc4aa54b948b99de104c44563a552899d718bb75d1941cc62a2444b0506abaf");
+		private static readonly byte[] expectedTestSHA1 = Hex.Decode("e9ecef9f5306daf1ac51a89a211a64cb24415649");
+		private static readonly byte[] expectedTestSHA256 = Hex.Decode("bdab3ca831b472a2fa09bd1bade541ef16c96640a91fcec553679a136061de98");
+
+		private static readonly byte[] sha1Xors = Hex.Decode("7edcc1216934f3891b03ffa65821611a3e2b1f79");
+		private static readonly byte[] sha256Xors = Hex.Decode("5ec48189cc0aa71e79c707bc3c33ffd47bbba368a83d6cfebf3cd3969d7f3eed");
+
+		public override string Name
+		{
+			get { return "DigestRandomNumber"; }
+		}
+
+		private void doExpectedTest(IDigest digest, int seed, byte[] expected)
+		{
+			doExpectedTest(digest, seed, expected, null);
+		}
+	    
+		private void doExpectedTest(IDigest digest, int seed, byte[] expected, byte[] noCycle)
+		{
+			DigestRandomGenerator rGen = new DigestRandomGenerator(digest);
+			byte[] output = new byte[digest.GetDigestSize()];
+
+			rGen.AddSeedMaterial(seed);
+
+			for (int i = 0; i != 1024; i++)
+			{
+				rGen.NextBytes(output);
+			}
+
+			if (noCycle != null)
+			{
+				if (Arrays.AreEqual(noCycle, output))
+				{
+					Fail("seed not being cycled!");
+				}
+			}
+
+			if (!Arrays.AreEqual(expected, output))
+			{
+				Fail("expected output doesn't match");
+			}
+		}
+
+		private void doExpectedTest(IDigest digest, byte[] seed, byte[] expected)
+		{
+			DigestRandomGenerator rGen = new DigestRandomGenerator(digest);
+			byte[] output = new byte[digest.GetDigestSize()];
+
+			rGen.AddSeedMaterial(seed);
+
+			for (int i = 0; i != 1024; i++)
+			{
+				rGen.NextBytes(output);
+			}
+
+			if (!Arrays.AreEqual(expected, output))
+			{
+				Fail("expected output doesn't match");
+			}
+		}
+
+		private void doCountTest(IDigest digest, byte[] seed, byte[] expectedXors)
+		{
+			DigestRandomGenerator rGen = new DigestRandomGenerator(digest);
+			byte[] output = new byte[digest.GetDigestSize()];
+			int[] averages = new int[digest.GetDigestSize()];
+			byte[] ands = new byte[digest.GetDigestSize()];
+			byte[] xors = new byte[digest.GetDigestSize()];
+			byte[] ors = new byte[digest.GetDigestSize()];
+
+			rGen.AddSeedMaterial(seed);
+
+			for (int i = 0; i != 1000000; i++)
+			{
+				rGen.NextBytes(output);
+				for (int j = 0; j != output.Length; j++)
+				{
+					averages[j] += output[j] & 0xff;
+					ands[j] &= output[j];
+					xors[j] ^= output[j];
+					ors[j] |= output[j];
+				}
+			}
+
+			for (int i = 0; i != output.Length; i++)
+			{
+				if ((averages[i] / 1000000) != 127)
+				{
+					Fail("average test failed for " + digest.AlgorithmName);
+				}
+				if (ands[i] != 0)
+				{
+					Fail("and test failed for " + digest.AlgorithmName);
+				}
+				if ((ors[i] & 0xff) != 0xff)
+				{
+					Fail("or test failed for " + digest.AlgorithmName);
+				}
+				if (xors[i] != expectedXors[i])
+				{
+					Fail("xor test failed for " + digest.AlgorithmName);
+				}
+			}
+		}
+
+		public override void PerformTest()
+		{
+			doExpectedTest(new Sha1Digest(), 0, expected0SHA1, noCycle0SHA1);
+			doExpectedTest(new Sha256Digest(), 0, expected0SHA256, noCycle0SHA256);
+
+			doExpectedTest(new Sha1Digest(), 100, expected100SHA1);
+			doExpectedTest(new Sha256Digest(), 100, expected100SHA256);
+
+			doExpectedTest(new Sha1Digest(), ZERO_SEED, expected0SHA1);
+			doExpectedTest(new Sha256Digest(), ZERO_SEED, expected0SHA256);
+
+			doExpectedTest(new Sha1Digest(), TEST_SEED, expectedTestSHA1);
+			doExpectedTest(new Sha256Digest(), TEST_SEED, expectedTestSHA256);
+
+			doCountTest(new Sha1Digest(), TEST_SEED, sha1Xors);
+			doCountTest(new Sha256Digest(), TEST_SEED, sha256Xors);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new DigestRandomNumberTest());
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/DigestTest.cs b/crypto/test/src/crypto/test/DigestTest.cs
new file mode 100644
index 000000000..930979643
--- /dev/null
+++ b/crypto/test/src/crypto/test/DigestTest.cs
@@ -0,0 +1,183 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	public abstract class DigestTest
+		: SimpleTest
+	{
+		private IDigest digest;
+		private string[] input;
+		private string[] results;
+
+		protected DigestTest(
+			IDigest digest,
+			string[] input,
+			string[] results)
+		{
+			this.digest = digest;
+			this.input = input;
+			this.results = results;
+		}
+
+		public override string Name
+		{
+			get { return digest.AlgorithmName; }
+		}
+
+		public override void PerformTest()
+		{
+			byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			for (int i = 0; i < input.Length - 1; i++)
+			{
+				byte[] msg = toByteArray(input[i]);
+
+				vectorTest(digest, i, resBuf, msg, Hex.Decode(results[i]));
+			}
+
+			byte[] lastV = toByteArray(input[input.Length - 1]);
+			byte[] lastDigest = Hex.Decode(results[input.Length - 1]);
+
+			vectorTest(digest, input.Length - 1, resBuf, lastV, Hex.Decode(results[input.Length - 1]));
+
+			//
+			// clone test
+			//
+			digest.BlockUpdate(lastV, 0, lastV.Length/2);
+
+			// clone the Digest
+			IDigest d = CloneDigest(digest);
+
+			digest.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing clone vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
+
+			d.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			d.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing second clone vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
+
+			//
+			// memo test
+			//
+			IMemoable m = (IMemoable)digest;
+
+			digest.BlockUpdate(lastV, 0, lastV.Length/2);
+
+			// copy the Digest
+			IMemoable copy1 = m.Copy();
+			IMemoable copy2 = copy1.Copy();
+
+			digest.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing memo vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
+
+			m.Reset(copy1);
+
+			digest.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing memo reset vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
+
+			IDigest md = (IDigest)copy2;
+
+			md.BlockUpdate(lastV, lastV.Length/2, lastV.Length - lastV.Length/2);
+			md.DoFinal(resBuf, 0);
+
+			if (!AreEqual(lastDigest, resBuf))
+			{
+				Fail("failing memo copy vector test", results[results.Length - 1], Hex.ToHexString(resBuf));
+			}
+		}
+
+		private byte[] toByteArray(
+			string input)
+		{
+			byte[] bytes = new byte[input.Length];
+
+			for (int i = 0; i != bytes.Length; i++)
+			{
+				bytes[i] = (byte)input[i];
+			}
+
+			return bytes;
+		}
+
+		private void vectorTest(
+			IDigest digest,
+			int count,
+			byte[] resBuf,
+			byte[] input,
+			byte[] expected)
+		{
+			digest.BlockUpdate(input, 0, input.Length);
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(resBuf, expected))
+			{
+				Fail("Vector " + count + " failed got " + Hex.ToHexString(resBuf));
+			}
+		}
+
+		protected abstract IDigest CloneDigest(IDigest digest);
+
+		//
+		// optional tests
+		//
+		protected void millionATest(
+			string expected)
+		{
+			byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			for (int i = 0; i < 1000000; i++)
+			{
+				digest.Update((byte)'a');
+			}
+
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(resBuf, Hex.Decode(expected)))
+			{
+				Fail("Million a's failed");
+			}
+		}
+
+		protected void sixtyFourKTest(
+			string expected)
+		{
+			byte[] resBuf = new byte[digest.GetDigestSize()];
+
+			for (int i = 0; i < 65536; i++)
+			{
+				digest.Update((byte)(i & 0xff));
+			}
+
+			digest.DoFinal(resBuf, 0);
+
+			if (!AreEqual(resBuf, Hex.Decode(expected)))
+			{
+				Fail("64k test failed");
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/EAXTest.cs b/crypto/test/src/crypto/test/EAXTest.cs
new file mode 100644
index 000000000..c6be118b2
--- /dev/null
+++ b/crypto/test/src/crypto/test/EAXTest.cs
@@ -0,0 +1,352 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class EaxTest
+		: SimpleTest
+	{
+		private static readonly byte[] K1 = Hex.Decode("233952DEE4D5ED5F9B9C6D6FF80FF478");
+		private static readonly byte[] N1 = Hex.Decode("62EC67F9C3A4A407FCB2A8C49031A8B3");
+		private static readonly byte[] A1 = Hex.Decode("6BFB914FD07EAE6B");
+		private static readonly byte[] P1 = Hex.Decode("");
+		private static readonly byte[] C1 = Hex.Decode("E037830E8389F27B025A2D6527E79D01");
+		private static readonly byte[] T1 = Hex.Decode("E037830E8389F27B025A2D6527E79D01");
+
+		private static readonly byte[] K2 = Hex.Decode("91945D3F4DCBEE0BF45EF52255F095A4");
+		private static readonly byte[] N2 = Hex.Decode("BECAF043B0A23D843194BA972C66DEBD");
+		private static readonly byte[] A2 = Hex.Decode("FA3BFD4806EB53FA");
+		private static readonly byte[] P2 = Hex.Decode("F7FB");
+		private static readonly byte[] C2 = Hex.Decode("19DD5C4C9331049D0BDAB0277408F67967E5");
+		private static readonly byte[] T2 = Hex.Decode("5C4C9331049D0BDAB0277408F67967E5");
+
+		private static readonly byte[] K3 = Hex.Decode("01F74AD64077F2E704C0F60ADA3DD523");
+		private static readonly byte[] N3 = Hex.Decode("70C3DB4F0D26368400A10ED05D2BFF5E");
+		private static readonly byte[] A3 = Hex.Decode("234A3463C1264AC6");
+		private static readonly byte[] P3 = Hex.Decode("1A47CB4933");
+		private static readonly byte[] C3 = Hex.Decode("D851D5BAE03A59F238A23E39199DC9266626C40F80");
+		private static readonly byte[] T3 = Hex.Decode("3A59F238A23E39199DC9266626C40F80");
+
+		private static readonly byte[] K4 = Hex.Decode("D07CF6CBB7F313BDDE66B727AFD3C5E8");
+		private static readonly byte[] N4 = Hex.Decode("8408DFFF3C1A2B1292DC199E46B7D617");
+		private static readonly byte[] A4 = Hex.Decode("33CCE2EABFF5A79D");
+		private static readonly byte[] P4 = Hex.Decode("481C9E39B1");
+		private static readonly byte[] C4 = Hex.Decode("632A9D131AD4C168A4225D8E1FF755939974A7BEDE");
+		private static readonly byte[] T4 = Hex.Decode("D4C168A4225D8E1FF755939974A7BEDE");
+
+		private static readonly byte[] K5 = Hex.Decode("35B6D0580005BBC12B0587124557D2C2");
+		private static readonly byte[] N5 = Hex.Decode("FDB6B06676EEDC5C61D74276E1F8E816");
+		private static readonly byte[] A5 = Hex.Decode("AEB96EAEBE2970E9");
+		private static readonly byte[] P5 = Hex.Decode("40D0C07DA5E4");
+		private static readonly byte[] C5 = Hex.Decode("071DFE16C675CB0677E536F73AFE6A14B74EE49844DD");
+		private static readonly byte[] T5 = Hex.Decode("CB0677E536F73AFE6A14B74EE49844DD");
+
+		private static readonly byte[] K6 = Hex.Decode("BD8E6E11475E60B268784C38C62FEB22");
+		private static readonly byte[] N6 = Hex.Decode("6EAC5C93072D8E8513F750935E46DA1B");
+		private static readonly byte[] A6 = Hex.Decode("D4482D1CA78DCE0F");
+		private static readonly byte[] P6 = Hex.Decode("4DE3B35C3FC039245BD1FB7D");
+		private static readonly byte[] C6 = Hex.Decode("835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F");
+		private static readonly byte[] T6 = Hex.Decode("ABB8644FD6CCB86947C5E10590210A4F");
+
+		private static readonly byte[] K7 = Hex.Decode("7C77D6E813BED5AC98BAA417477A2E7D");
+		private static readonly byte[] N7 = Hex.Decode("1A8C98DCD73D38393B2BF1569DEEFC19");
+		private static readonly byte[] A7 = Hex.Decode("65D2017990D62528");
+		private static readonly byte[] P7 = Hex.Decode("8B0A79306C9CE7ED99DAE4F87F8DD61636");
+		private static readonly byte[] C7 = Hex.Decode("02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2");
+		private static readonly byte[] T7 = Hex.Decode("137327D10649B0AA6E1C181DB617D7F2");
+
+		private static readonly byte[] K8 = Hex.Decode("5FFF20CAFAB119CA2FC73549E20F5B0D");
+		private static readonly byte[] N8 = Hex.Decode("DDE59B97D722156D4D9AFF2BC7559826");
+		private static readonly byte[] A8 = Hex.Decode("54B9F04E6A09189A");
+		private static readonly byte[] P8 = Hex.Decode("1BDA122BCE8A8DBAF1877D962B8592DD2D56");
+		private static readonly byte[] C8 = Hex.Decode("2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A");
+		private static readonly byte[] T8 = Hex.Decode("3B60450599BD02C96382902AEF7F832A");
+
+		private static readonly byte[] K9 = Hex.Decode("A4A4782BCFFD3EC5E7EF6D8C34A56123");
+		private static readonly byte[] N9 = Hex.Decode("B781FCF2F75FA5A8DE97A9CA48E522EC");
+		private static readonly byte[] A9 = Hex.Decode("899A175897561D7E");
+		private static readonly byte[] P9 = Hex.Decode("6CF36720872B8513F6EAB1A8A44438D5EF11");
+		private static readonly byte[] C9 = Hex.Decode("0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700");
+		private static readonly byte[] T9 = Hex.Decode("E7F6D2231618102FDB7FE55FF1991700");
+
+		private static readonly byte[] K10 = Hex.Decode("8395FCF1E95BEBD697BD010BC766AAC3");
+		private static readonly byte[] N10 = Hex.Decode("22E7ADD93CFC6393C57EC0B3C17D6B44");
+		private static readonly byte[] A10 = Hex.Decode("126735FCC320D25A");
+		private static readonly byte[] P10 = Hex.Decode("CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7");
+		private static readonly byte[] C10 = Hex.Decode("CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E");
+		private static readonly byte[] T10 = Hex.Decode("CFC46AFC253B4652B1AF3795B124AB6E");
+
+		private static readonly byte[] K11 = Hex.Decode("8395FCF1E95BEBD697BD010BC766AAC3");
+		private static readonly byte[] N11 = Hex.Decode("22E7ADD93CFC6393C57EC0B3C17D6B44");
+		private static readonly byte[] A11 = Hex.Decode("126735FCC320D25A");
+		private static readonly byte[] P11 = Hex.Decode("CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7");
+		private static readonly byte[] C11 = Hex.Decode("CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC");
+		private static readonly byte[] T11 = Hex.Decode("CFC46AFC");
+
+		private const int NONCE_LEN = 8;
+		private const int MAC_LEN = 8;
+		private const int AUTHEN_LEN = 20;
+
+		public override string Name
+		{
+			get { return "EAX"; }
+		}
+
+		public override void PerformTest()
+		{
+			checkVectors(1, K1, 128, N1, A1, P1, T1, C1);
+			checkVectors(2, K2, 128, N2, A2, P2, T2, C2);
+			checkVectors(3, K3, 128, N3, A3, P3, T3, C3);
+			checkVectors(4, K4, 128, N4, A4, P4, T4, C4);
+			checkVectors(5, K5, 128, N5, A5, P5, T5, C5);
+			checkVectors(6, K6, 128, N6, A6, P6, T6, C6);
+			checkVectors(7, K7, 128, N7, A7, P7, T7, C7);
+			checkVectors(8, K8, 128, N8, A8, P8, T8, C8);
+			checkVectors(9, K9, 128, N9, A9, P9, T9, C9);
+			checkVectors(10, K10, 128, N10, A10, P10, T10, C10);
+			checkVectors(11, K11, 32, N11, A11, P11, T11, C11);
+
+			EaxBlockCipher eax = new EaxBlockCipher(new AesEngine());
+			ivParamTest(1, eax, K1, N1);
+
+			//
+			// exception tests
+			//
+
+			try
+			{
+				eax.Init(false, new AeadParameters(new KeyParameter(K1), 32, N2, A2));
+
+				byte[] enc = new byte[C2.Length]; 
+				int len = eax.ProcessBytes(C2, 0, C2.Length, enc, 0);
+
+				len += eax.DoFinal(enc, len);
+
+				Fail("invalid cipher text not picked up");
+			}
+			catch (InvalidCipherTextException)
+			{
+				// expected
+			}
+
+			try
+			{
+				eax.Init(false, new KeyParameter(K1));
+
+				Fail("illegal argument not picked up");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+
+			randomTests();
+		}
+
+		private void checkVectors(
+			int				count,
+			byte[]			k,
+			int				macSize,
+			byte[]			n,
+			byte[]			a,
+			byte[]			p,
+			byte[]			t,
+			byte[]			c)
+        {
+            byte[] fa = new byte[a.Length / 2];
+            byte[] la = new byte[a.Length - (a.Length / 2)];
+            Array.Copy(a, 0, fa, 0, fa.Length);
+            Array.Copy(a, fa.Length, la, 0, la.Length);
+
+            checkVectors(count, "all initial associated data", k, macSize, n, a, null, p, t, c);
+            checkVectors(count, "subsequent associated data", k, macSize, n, null, a, p, t, c);
+            checkVectors(count, "split associated data", k, macSize, n, fa, la, p, t, c);
+        }
+
+        private void checkVectors(
+            int count,
+            string additionalDataType,
+            byte[] k,
+            int macSize,
+            byte[] n,
+            byte[] a,
+            byte[] sa,
+            byte[] p,
+            byte[] t,
+            byte[] c)
+        {
+			EaxBlockCipher encEax = new EaxBlockCipher(new AesFastEngine());
+			EaxBlockCipher decEax = new EaxBlockCipher(new AesFastEngine());
+
+			AeadParameters parameters = new AeadParameters(new KeyParameter(k), macSize, n, a);
+			encEax.Init(true, parameters);
+			decEax.Init(false, parameters);
+
+            runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c);
+            runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c);
+
+            // key reuse test
+            parameters = new AeadParameters(null, macSize, n, a);
+            encEax.Init(true, parameters);
+            decEax.Init(false, parameters);
+
+            runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c);
+            runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c);
+        }
+
+		private void runCheckVectors(
+			int				count,
+			EaxBlockCipher	encEax,
+			EaxBlockCipher	decEax,
+            string          additionalDataType,
+            byte[]          sa,
+            byte[]          p,
+			byte[]			t,
+			byte[]			c)
+		{
+			byte[] enc = new byte[c.Length];
+
+            if (sa != null)
+            {
+                encEax.ProcessAadBytes(sa, 0, sa.Length);
+            }
+
+			int len = encEax.ProcessBytes(p, 0, p.Length, enc, 0);
+
+			len += encEax.DoFinal(enc, len);
+
+			if (!AreEqual(c, enc))
+			{
+                Fail("encrypted stream fails to match in test " + count + " with " + additionalDataType);
+            }
+
+			byte[] tmp = new byte[enc.Length];
+
+            if (sa != null)
+            {
+                decEax.ProcessAadBytes(sa, 0, sa.Length);
+            }
+
+            len = decEax.ProcessBytes(enc, 0, enc.Length, tmp, 0);
+
+			len += decEax.DoFinal(tmp, len);
+
+			byte[] dec = new byte[len];
+
+			Array.Copy(tmp, 0, dec, 0, len);
+
+			if (!AreEqual(p, dec))
+			{
+                Fail("decrypted stream fails to match in test " + count + " with " + additionalDataType);
+            }
+
+			if (!AreEqual(t, decEax.GetMac()))
+			{
+                Fail("MAC fails to match in test " + count + " with " + additionalDataType);
+            }
+		}
+
+        private void ivParamTest(
+			int					count,
+			IAeadBlockCipher	eax,
+			byte[]				k,
+			byte[]				n)
+		{
+			byte[] p = Encoding.ASCII.GetBytes("hello world!!");
+
+			eax.Init(true, new ParametersWithIV(new KeyParameter(k), n));
+
+			byte[] enc = new byte[p.Length + 8];
+
+			int len = eax.ProcessBytes(p, 0, p.Length, enc, 0);
+
+			len += eax.DoFinal(enc, len);
+
+			eax.Init(false, new ParametersWithIV(new KeyParameter(k), n));
+
+			byte[] tmp = new byte[enc.Length];
+
+			len = eax.ProcessBytes(enc, 0, enc.Length, tmp, 0);
+
+			len += eax.DoFinal(tmp, len);
+
+			byte[] dec = new byte[len];
+
+			Array.Copy(tmp, 0, dec, 0, len);
+
+			if (!AreEqual(p, dec))
+			{
+				Fail("decrypted stream fails to match in test " + count);
+			}
+		}
+
+		private void randomTests()
+		{
+			SecureRandom srng = new SecureRandom();
+			for (int i = 0; i < 10; ++i)
+			{
+				randomTest(srng);
+			}
+		}
+
+		private void randomTest(
+			SecureRandom srng)
+		{
+			int DAT_LEN = srng.Next(1024);
+			byte[] nonce = new byte[NONCE_LEN];
+			byte[] authen = new byte[AUTHEN_LEN];
+			byte[] datIn = new byte[DAT_LEN];
+			byte[] key = new byte[16];
+			srng.NextBytes(nonce);
+			srng.NextBytes(authen);
+			srng.NextBytes(datIn);
+			srng.NextBytes(key);
+
+			AesFastEngine engine = new AesFastEngine();
+			KeyParameter sessKey = new KeyParameter(key);
+			EaxBlockCipher eaxCipher = new EaxBlockCipher(engine);
+
+			AeadParameters parameters = new AeadParameters(sessKey, MAC_LEN * 8, nonce, authen);
+			eaxCipher.Init(true, parameters);
+
+			byte[] intrDat = new byte[eaxCipher.GetOutputSize(datIn.Length)];
+			int outOff = eaxCipher.ProcessBytes(datIn, 0, DAT_LEN, intrDat, 0);
+			outOff += eaxCipher.DoFinal(intrDat, outOff);
+
+			eaxCipher.Init(false, parameters);
+			byte[] datOut = new byte[eaxCipher.GetOutputSize(outOff)];
+			int resultLen = eaxCipher.ProcessBytes(intrDat, 0, outOff, datOut, 0);
+			eaxCipher.DoFinal(datOut, resultLen);
+
+			if (!AreEqual(datIn, datOut))
+			{
+				Fail("EAX roundtrip failed to match");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new EaxTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/ECDHKEKGeneratorTest.cs b/crypto/test/src/crypto/test/ECDHKEKGeneratorTest.cs
new file mode 100644
index 000000000..250b2ca22
--- /dev/null
+++ b/crypto/test/src/crypto/test/ECDHKEKGeneratorTest.cs
@@ -0,0 +1,80 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <remarks>ECDHKEK Generator tests.</remarks>
+	[TestFixture]
+	public class ECDHKekGeneratorTest
+		: SimpleTest
+	{
+		private byte[] seed1 = Hex.Decode("db4a8daba1f98791d54e940175dd1a5f3a0826a1066aa9b668d4dc1e1e0790158dcad1533c03b44214d1b61fefa8b579");
+		private DerObjectIdentifier alg1 = NistObjectIdentifiers.IdAes256Wrap;
+		private byte[] result1 = Hex.Decode("8ecc6d85caf25eaba823a7d620d4ab0d33e4c645f2");
+
+		private byte[] seed2 = Hex.Decode("75d7487b5d3d2bfb3c69ce0365fe64e3bfab5d0d63731628a9f47eb8fddfa28c65decaf228a0b38f0c51c6a3356d7c56");
+		private DerObjectIdentifier alg2 = NistObjectIdentifiers.IdAes128Wrap;
+		private byte[] result2 = Hex.Decode("042be1faca3a4a8fc859241bfb87ba35");
+
+		private byte[] seed3 = Hex.Decode("fdeb6d809f997e8ac174d638734dc36d37aaf7e876e39967cd82b1cada3de772449788461ee7f856bad9305627f8e48b");
+		private DerObjectIdentifier alg3 = PkcsObjectIdentifiers.IdAlgCms3DesWrap;
+		private byte[] result3 = Hex.Decode("bcd701fc92109b1b9d6f3b6497ad5ca9627fa8a597010305");
+
+		public ECDHKekGeneratorTest()
+		{
+		}
+
+		public override void PerformTest()
+		{
+			CheckMask(1, new ECDHKekGenerator(new Sha1Digest()), new DHKdfParameters(alg1, 256, seed1), result1);
+			CheckMask(2, new ECDHKekGenerator(new Sha1Digest()), new DHKdfParameters(alg2, 128, seed2), result2);
+			CheckMask(3, new ECDHKekGenerator(new Sha1Digest()), new DHKdfParameters(alg3, 192, seed3), result3);
+		}
+
+		private void CheckMask(
+			int						count,
+			IDerivationFunction		kdf,
+			IDerivationParameters	parameters,
+			byte[]					result)
+		{
+			byte[] data = new byte[result.Length];
+
+			kdf.Init(parameters);
+
+			kdf.GenerateBytes(data, 0, data.Length);
+
+			if (!AreEqual(result, data))
+			{
+				Fail("ECDHKekGenerator failed generator test " + count);
+			}
+		}
+
+		public override string Name
+		{
+			get { return "ECDHKekGenerator"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ECDHKekGeneratorTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/ECGOST3410Test.cs b/crypto/test/src/crypto/test/ECGOST3410Test.cs
new file mode 100644
index 000000000..37cb23ecf
--- /dev/null
+++ b/crypto/test/src/crypto/test/ECGOST3410Test.cs
@@ -0,0 +1,345 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     *  ECGOST3410 tests are taken from GOST R 34.10-2001.
+     */
+    [TestFixture]
+    public class ECGost3410Test
+        : SimpleTest
+    {
+        private static readonly byte[] hashmessage = Hex.Decode("3042453136414534424341374533364339313734453431443642453241453435");
+
+        /**
+        * ECGOST3410 over the field Fp<br/>
+        */
+        BigInteger r = new BigInteger("29700980915817952874371204983938256990422752107994319651632687982059210933395");
+        BigInteger s = new BigInteger("574973400270084654178925310019147038455227042649098563933718999175515839552");
+
+        byte[] kData = new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395").ToByteArray();
+
+        private readonly SecureRandom k;
+
+        public ECGost3410Test()
+        {
+            k = FixedSecureRandom.From(kData);
+        }
+
+        private void ecGOST3410_TEST()
+        {
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p
+            BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619");
+
+            FpCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("7"), // a
+                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b
+                mod_q, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+                    new BigInteger("2"), // x
+                    new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y
+                mod_q);
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECGOST3410",
+                new BigInteger("55441196065363246126355624130324183196576709222340016572108097750006097525544"), // d
+                parameters);
+
+            ParametersWithRandom param = new ParametersWithRandom(priKey, k);
+
+            ECGost3410Signer ecgost3410 = new ECGost3410Signer();
+
+            ecgost3410.Init(true, param);
+
+            byte[] mVal = new BigInteger("20798893674476452017134061561508270130637142515379653289952617252661468872421").ToByteArray();
+            byte[] message = new byte[mVal.Length];
+
+            for (int i = 0; i != mVal.Length; i++)
+            {
+                message[i] = mVal[mVal.Length - 1 - i];
+            }
+
+            BigInteger[] sig = ecgost3410.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong.", r, sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong.", s, sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECGOST3410",
+                curve.CreatePoint(
+                    new BigInteger("57520216126176808443631405023338071176630104906313632182896741342206604859403"), // x
+                    new BigInteger("17614944419213781543809391949654080031942662045363639260709847859438286763994")), // y
+                parameters);
+
+            ecgost3410.Init(false, pubKey);
+            if (!ecgost3410.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("verification fails");
+            }
+        }
+
+        /**
+         * Test Sign and Verify with test parameters
+         * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt
+         * gostR3410-2001-TestParamSet  P.46
+         */
+        private void ecGOST3410_TestParam()
+        {
+            SecureRandom    random = new SecureRandom();
+
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p
+            BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619");
+
+            FpCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("7"), // a
+                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b
+                mod_q, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+                    new BigInteger("2"), // x
+                    new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y
+                mod_q);
+
+            ECKeyPairGenerator          pGen = new ECKeyPairGenerator();
+            ECKeyGenerationParameters   genParam = new ECKeyGenerationParameters(
+                parameters,
+                random);
+
+            pGen.Init(genParam);
+
+            AsymmetricCipherKeyPair  pair = pGen.GenerateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+            ECGost3410Signer ecgost3410 = new ECGost3410Signer();
+
+            ecgost3410.Init(true, param);
+
+            //get hash message using the digest GOST3411.
+            byte[] message = Encoding.ASCII.GetBytes("Message for sign");
+            Gost3411Digest gost3411 = new Gost3411Digest();
+            gost3411.BlockUpdate(message, 0, message.Length);
+            byte[] hashmessage = new byte[gost3411.GetDigestSize()];
+            gost3411.DoFinal(hashmessage, 0);
+
+            BigInteger[] sig = ecgost3410.GenerateSignature(hashmessage);
+
+            ecgost3410.Init(false, pair.Public);
+
+            if (!ecgost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        /**
+         * Test Sign and Verify with A parameters
+         * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt
+         * gostR3410-2001-CryptoPro-A-ParamSet  P.47
+         */
+        public void ecGOST3410_AParam()
+        {
+            SecureRandom    random = new SecureRandom();
+
+            BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); //p
+            BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
+
+            FpCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
+                new BigInteger("166"), // b
+                mod_q, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+                    new BigInteger("1"), // x
+                    new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y
+                mod_q);
+
+            ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410");
+            ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
+                parameters,
+                random);
+
+            pGen.Init(genParam);
+
+            AsymmetricCipherKeyPair  pair = pGen.GenerateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+            ECGost3410Signer ecgost3410 = new ECGost3410Signer();
+
+            ecgost3410.Init(true, param);
+
+            BigInteger[] sig = ecgost3410.GenerateSignature(hashmessage);
+
+            ecgost3410.Init(false, pair.Public);
+
+            if (!ecgost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        /**
+         * Test Sign and Verify with B parameters
+         * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt
+         * gostR3410-2001-CryptoPro-B-ParamSet  P.47-48
+         */
+        private void ecGOST3410_BParam()
+        {
+            SecureRandom random = new SecureRandom();
+
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p
+            BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703");
+
+            FpCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a
+                new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b
+                mod_q, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+                    new BigInteger("1"), // x
+                    new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y
+                mod_q);
+
+            ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410");
+            ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
+                parameters,
+                random);
+
+            pGen.Init(genParam);
+
+            AsymmetricCipherKeyPair pair = pGen.GenerateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+            ECGost3410Signer ecgost3410 = new ECGost3410Signer();
+
+            ecgost3410.Init(true, param);
+
+            BigInteger[] sig = ecgost3410.GenerateSignature(hashmessage);
+
+            ecgost3410.Init(false, pair.Public);
+
+            if (!ecgost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        /**
+         * Test Sign and Verify with C parameters
+         * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt
+         * gostR3410-2001-CryptoPro-C-ParamSet  P.48
+         */
+        private void ecGOST3410_CParam()
+        {
+            SecureRandom random = new SecureRandom();
+
+            BigInteger mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p
+            BigInteger mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601");
+
+            FpCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a
+                new BigInteger("32858"), // b
+                mod_q, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+                    new BigInteger("0"), // x
+                    new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y
+                mod_q);
+
+            ECKeyPairGenerator pGen = new ECKeyPairGenerator("ECGOST3410");
+            ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
+                parameters,
+                random);
+
+            pGen.Init(genParam);
+
+            AsymmetricCipherKeyPair pair = pGen.GenerateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+            ECGost3410Signer ecgost3410 = new ECGost3410Signer();
+
+            ecgost3410.Init(true, param);
+
+            BigInteger[] sig = ecgost3410.GenerateSignature(hashmessage);
+
+            ecgost3410.Init(false, pair.Public);
+
+            if (!ecgost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        public override string Name
+        {
+            get { return "ECGOST3410"; }
+        }
+
+        public override void PerformTest()
+        {
+            ecGOST3410_TEST();
+            ecGOST3410_TestParam();
+            ecGOST3410_AParam();
+            ecGOST3410_BParam();
+            ecGOST3410_CParam();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ECGost3410Test test = new ECGost3410Test();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ECIESTest.cs b/crypto/test/src/crypto/test/ECIESTest.cs
new file mode 100644
index 000000000..e8cfd6df4
--- /dev/null
+++ b/crypto/test/src/crypto/test/ECIESTest.cs
@@ -0,0 +1,252 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <remarks>Test for ECIES - Elliptic Curve Integrated Encryption Scheme</remarks>
+    [TestFixture]
+    public class EcIesTest
+        : SimpleTest
+    {
+        public EcIesTest()
+        {
+        }
+
+        public override string Name
+        {
+            get { return "ECIES"; }
+        }
+
+        private void StaticTest()
+        {
+            BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
+                    n);
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECDH",
+                new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d
+                parameters);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDH",
+                curve.DecodePoint(Hex.Decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q
+                parameters);
+
+            AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey);
+            AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey);
+
+            //
+            // stream test
+            //
+            IesEngine i1 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()));
+            IesEngine i2 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()));
+            byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+            byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };
+            IesParameters p = new IesParameters(d, e, 64);
+
+            i1.Init(true, p1.Private, p2.Public, p);
+            i2.Init(false, p2.Private, p1.Public, p);
+
+            byte[] message = Hex.Decode("1234567890abcdef");
+
+            byte[] out1 = i1.ProcessBlock(message, 0, message.Length);
+
+            if (!AreEqual(out1, Hex.Decode("468d89877e8238802403ec4cb6b329faeccfa6f3a730f2cdb3c0a8e8")))
+            {
+                Fail("stream cipher test failed on enc");
+            }
+
+            byte[] out2 = i2.ProcessBlock(out1, 0, out1.Length);
+
+            if (!AreEqual(out2, message))
+            {
+                Fail("stream cipher test failed");
+            }
+
+            //
+            // twofish with CBC
+            //
+            BufferedBlockCipher c1 = new PaddedBufferedBlockCipher(
+                new CbcBlockCipher(new TwofishEngine()));
+            BufferedBlockCipher c2 = new PaddedBufferedBlockCipher(
+                new CbcBlockCipher(new TwofishEngine()));
+            i1 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()),
+                c1);
+            i2 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()),
+                c2);
+            d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+            e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };
+            p = new IesWithCipherParameters(d, e, 64, 128);
+
+            i1.Init(true, p1.Private, p2.Public, p);
+            i2.Init(false, p2.Private, p1.Public, p);
+
+            message = Hex.Decode("1234567890abcdef");
+
+            out1 = i1.ProcessBlock(message, 0, message.Length);
+
+            if (!AreEqual(out1, Hex.Decode("b8a06ea5c2b9df28b58a0a90a734cde8c9c02903e5c220021fe4417410d1e53a32a71696")))
+            {
+                Fail("twofish cipher test failed on enc");
+            }
+
+            out2 = i2.ProcessBlock(out1, 0, out1.Length);
+
+            if (!AreEqual(out2, message))
+            {
+                Fail("twofish cipher test failed");
+            }
+        }
+
+        private void DoTest(
+            AsymmetricCipherKeyPair	p1,
+            AsymmetricCipherKeyPair	p2)
+        {
+            //
+            // stream test
+            //
+            IesEngine i1 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()));
+            IesEngine i2 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()));
+            byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+            byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };
+            IesParameters  p = new IesParameters(d, e, 64);
+
+            i1.Init(true, p1.Private, p2.Public, p);
+            i2.Init(false, p2.Private, p1.Public, p);
+
+            byte[] message = Hex.Decode("1234567890abcdef");
+
+            byte[] out1 = i1.ProcessBlock(message, 0, message.Length);
+
+            byte[] out2 = i2.ProcessBlock(out1, 0, out1.Length);
+
+            if (!AreEqual(out2, message))
+            {
+                Fail("stream cipher test failed");
+            }
+
+            //
+            // twofish with CBC
+            //
+            BufferedBlockCipher c1 = new PaddedBufferedBlockCipher(
+                new CbcBlockCipher(new TwofishEngine()));
+            BufferedBlockCipher c2 = new PaddedBufferedBlockCipher(
+                new CbcBlockCipher(new TwofishEngine()));
+            i1 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()),
+                c1);
+            i2 = new IesEngine(
+                new ECDHBasicAgreement(),
+                new Kdf2BytesGenerator(new Sha1Digest()),
+                new HMac(new Sha1Digest()),
+                c2);
+            d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+            e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };
+            p = new IesWithCipherParameters(d, e, 64, 128);
+
+            i1.Init(true, p1.Private, p2.Public, p);
+            i2.Init(false, p2.Private, p1.Public, p);
+
+            message = Hex.Decode("1234567890abcdef");
+
+            out1 = i1.ProcessBlock(message, 0, message.Length);
+
+            out2 = i2.ProcessBlock(out1, 0, out1.Length);
+
+            if (!AreEqual(out2, message))
+            {
+                Fail("twofish cipher test failed");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            StaticTest();
+
+            BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                    curve,
+                    curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
+                    n);
+
+            ECKeyPairGenerator eGen = new ECKeyPairGenerator();
+            KeyGenerationParameters gParam = new ECKeyGenerationParameters(parameters, new SecureRandom());
+
+            eGen.Init(gParam);
+
+            AsymmetricCipherKeyPair p1 = eGen.GenerateKeyPair();
+            AsymmetricCipherKeyPair p2 = eGen.GenerateKeyPair();
+
+            DoTest(p1, p2);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new EcIesTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ECNRTest.cs b/crypto/test/src/crypto/test/ECNRTest.cs
new file mode 100644
index 000000000..5eae9f097
--- /dev/null
+++ b/crypto/test/src/crypto/test/ECNRTest.cs
@@ -0,0 +1,118 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * ECNR tests.
+     */
+    [TestFixture]
+    public class EcNrTest
+        : SimpleTest
+    {
+        /**
+            * a basic regression test with 239 bit prime
+            */
+        BigInteger r = new BigInteger("308636143175167811492623515537541734843573549327605293463169625072911693");
+        BigInteger s = new BigInteger("852401710738814635664888632022555967400445256405412579597015412971797143");
+
+        byte[] kData = BigIntegers.AsUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
+
+        private readonly SecureRandom k;
+
+        public EcNrTest()
+        {
+            k = FixedSecureRandom.From(kData);
+        }
+
+        private void ecNR239bitPrime()
+        {
+            BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                n);
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+                parameters);
+
+            ECNRSigner ecnr = new ECNRSigner();
+            ParametersWithRandom param = new ParametersWithRandom(priKey, k);
+
+            ecnr.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").ToByteArray();
+            BigInteger[] sig = ecnr.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong.", r, sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong.", s, sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                curve.DecodePoint(Hex.Decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+                parameters);
+
+            ecnr.Init(false, pubKey);
+            if (!ecnr.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        public override string Name
+        {
+            get
+            {
+                return "ECNR";
+            }
+        }
+
+        public override void PerformTest()
+        {
+            ecNR239bitPrime();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            EcNrTest test = new EcNrTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ECTest.cs b/crypto/test/src/crypto/test/ECTest.cs
new file mode 100644
index 000000000..5697f41eb
--- /dev/null
+++ b/crypto/test/src/crypto/test/ECTest.cs
@@ -0,0 +1,932 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * ECDSA tests are taken from X9.62.
+     */
+    [TestFixture]
+    public class ECTest
+        : SimpleTest
+    {
+        /**
+        * X9.62 - 1998,<br/>
+        * J.3.1, Page 152, ECDSA over the field Fp<br/>
+        * an example with 192 bit prime
+        */
+        [Test]
+        public void TestECDsa192bitPrime()
+        {
+            BigInteger r = new BigInteger("3342403536405981729393488334694600415596881826869351677613");
+            BigInteger s = new BigInteger("5735822328888155254683894997897571951568553642892029982342");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(new BigInteger("6140507067065001063065065565667405560006161556565665656654"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G
+                n);
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d
+                parameters);
+
+            ParametersWithRandom param = new ParametersWithRandom(priKey, k);
+
+            ECDsaSigner ecdsa = new ECDsaSigner();
+
+            ecdsa.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").ToByteArray();
+            BigInteger[] sig = ecdsa.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(Hex.Decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q
+                parameters);
+
+            ecdsa.Init(false, pubKey);
+            if (!ecdsa.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("verification fails");
+            }
+        }
+
+        [Test]
+        public void TestDecode()
+        {
+            FpCurve curve = new FpCurve(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
+
+            ECPoint p = curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")).Normalize();
+
+            if (!p.AffineXCoord.ToBigInteger().Equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16)))
+            {
+                Fail("x uncompressed incorrectly");
+            }
+
+            if (!p.AffineYCoord.ToBigInteger().Equals(new BigInteger("7192b95ffc8da78631011ed6b24cdd573f977a11e794811", 16)))
+            {
+                Fail("y uncompressed incorrectly");
+            }
+
+            byte[] encoding = p.GetEncoded();
+
+            if (!AreEqual(encoding, Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")))
+            {
+                Fail("point compressed incorrectly");
+            }
+        }
+
+        /**
+         * X9.62 - 1998,<br/>
+         * J.3.2, Page 155, ECDSA over the field Fp<br/>
+         * an example with 239 bit prime
+         */
+        [Test]
+        public void TestECDsa239bitPrime()
+        {
+            BigInteger r = new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176");
+            BigInteger s = new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                n);
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+                parameters);
+
+            ECDsaSigner ecdsa = new ECDsaSigner();
+            ParametersWithRandom param = new ParametersWithRandom(priKey, k);
+
+            ecdsa.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").ToByteArray();
+            BigInteger[] sig = ecdsa.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(Hex.Decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+                parameters);
+
+            ecdsa.Init(false, pubKey);
+            if (!ecdsa.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+
+        /**
+         * X9.62 - 1998,<br/>
+         * J.2.1, Page 100, ECDSA over the field F2m<br/>
+         * an example with 191 bit binary field
+         */
+        [Test]
+        public void TestECDsa191bitBinary()
+        {
+            BigInteger r = new BigInteger("87194383164871543355722284926904419997237591535066528048");
+            BigInteger s = new BigInteger("308992691965804947361541664549085895292153777025772063598");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(new BigInteger("1542725565216523985789236956265265265235675811949404040041"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            F2mCurve curve = new F2mCurve(
+                191, // m
+                9, //k
+                new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16), // a
+                new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16)); // b
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("0436B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB")), // G
+                new BigInteger("1569275433846670190958947355803350458831205595451630533029"), // n
+                BigInteger.Two); // h
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("1275552191113212300012030439187146164646146646466749494799"), // d
+                parameters);
+
+            ECDsaSigner ecdsa = new ECDsaSigner();
+            ParametersWithRandom param = new ParametersWithRandom(priKey, k);
+
+            ecdsa.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").ToByteArray();
+            BigInteger[] sig = ecdsa.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(Hex.Decode("045DE37E756BD55D72E3768CB396FFEB962614DEA4CE28A2E755C0E0E02F5FB132CAF416EF85B229BBB8E1352003125BA1")), // Q
+                parameters);
+
+            ecdsa.Init(false, pubKey);
+            if (!ecdsa.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        /**
+         * X9.62 - 1998,<br/>
+         * J.2.1, Page 100, ECDSA over the field F2m<br/>
+         * an example with 191 bit binary field
+         */
+        [Test]
+        public void TestECDsa239bitBinary()
+        {
+            BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
+            BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            F2mCurve curve = new F2mCurve(
+                239, // m
+                36, //k
+                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
+                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
+                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
+                BigInteger.ValueOf(4)); // h
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
+                parameters);
+
+            ECDsaSigner ecdsa = new ECDsaSigner();
+            ParametersWithRandom param = new ParametersWithRandom(priKey, k);
+
+            ecdsa.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").ToByteArray();
+            BigInteger[] sig = ecdsa.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(Hex.Decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
+                parameters);
+
+            ecdsa.Init(false, pubKey);
+            if (!ecdsa.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        // L 4.1  X9.62 2005
+        [Test]
+        public void TestECDsaP224Sha224()
+        {
+            X9ECParameters p = NistNamedCurves.GetByName("P-224");
+            ECDomainParameters parameters = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d
+                parameters);
+            SecureRandom k = FixedSecureRandom.From(BigIntegers.AsUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601")));
+        
+            byte[] M = Hex.Decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79");
+
+            ECDsaSigner dsa = new ECDsaSigner();
+
+            dsa.Init(true, new ParametersWithRandom(priKey, k));
+
+            BigInteger[] sig = dsa.GenerateSignature(M);
+
+            BigInteger r = new BigInteger("26477406756127720855365980332052585411804331993436302005017227573742");
+            BigInteger s = new BigInteger("17694958233103667059888193972742186995283044672015112738919822429978");
+        
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                parameters.Curve.DecodePoint(Hex.Decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q
+                parameters);
+
+            dsa.Init(false, pubKey);
+            if (!dsa.VerifySignature(M, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        [Test]
+        public void TestECDsaSecP224k1Sha256()
+        {
+            X9ECParameters p = SecNamedCurves.GetByName("secp224k1");
+            ECDomainParameters parameters = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("BE6F6E91FE96840A6518B56F3FE21689903A64FA729057AB872A9F51", 16), // d
+                parameters);
+            SecureRandom k = FixedSecureRandom.From(Hex.Decode("00c39beac93db21c3266084429eb9b846b787c094f23a4de66447efbb3"));
+       
+            byte[] M = Hex.Decode("E5D5A7ADF73C5476FAEE93A2C76CE94DC0557DB04CDC189504779117920B896D");
+
+            ECDsaSigner dsa = new ECDsaSigner();
+
+            dsa.Init(true, new ParametersWithRandom(priKey, k));
+
+            BigInteger[] sig = dsa.GenerateSignature(M);
+
+            BigInteger r = new BigInteger("8163E5941BED41DA441B33E653C632A55A110893133351E20CE7CB75", 16);
+            BigInteger s = new BigInteger("D12C3FC289DDD5F6890DCE26B65792C8C50E68BF551D617D47DF15A8", 16);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                parameters.Curve.DecodePoint(Hex.Decode("04C5C9B38D3603FCCD6994CBB9594E152B658721E483669BB42728520F484B537647EC816E58A8284D3B89DFEDB173AFDC214ECA95A836FA7C")), // Q
+                parameters);
+
+            dsa.Init(false, pubKey);
+            if (!dsa.VerifySignature(M, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        // L4.2  X9.62 2005
+        [Test]
+        public void TestECDsaP256Sha256()
+        {
+            X9ECParameters p = NistNamedCurves.GetByName("P-256");
+            ECDomainParameters parameters = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d
+                parameters);
+            SecureRandom k = FixedSecureRandom.From(BigIntegers.AsUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335")));
+
+            byte[] M = Hex.Decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD");
+
+            ECDsaSigner dsa = new ECDsaSigner();
+
+            dsa.Init(true, new ParametersWithRandom(priKey, k));
+
+            BigInteger[] sig = dsa.GenerateSignature(M);
+
+            BigInteger r = new BigInteger("97354732615802252173078420023658453040116611318111190383344590814578738210384");
+            BigInteger s = new BigInteger("98506158880355671805367324764306888225238061309262649376965428126566081727535");
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                parameters.Curve.DecodePoint(Hex.Decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q
+                parameters);
+
+            dsa.Init(false, pubKey);
+            if (!dsa.VerifySignature(M, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        [Test]
+        public void TestECDsaP224OneByteOver()
+        {
+            X9ECParameters p = NistNamedCurves.GetByName("P-224");
+            ECDomainParameters parameters = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d
+                parameters);
+            SecureRandom    k = FixedSecureRandom.From(BigIntegers.AsUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601")));
+
+            byte[] M = Hex.Decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79FF");
+
+            ECDsaSigner dsa = new ECDsaSigner();
+
+            dsa.Init(true, new ParametersWithRandom(priKey, k));
+
+            BigInteger[] sig = dsa.GenerateSignature(M);
+
+            BigInteger r = new BigInteger("26477406756127720855365980332052585411804331993436302005017227573742");
+            BigInteger s = new BigInteger("17694958233103667059888193972742186995283044672015112738919822429978");
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                parameters.Curve.DecodePoint(Hex.Decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q
+                parameters);
+
+            dsa.Init(false, pubKey);
+            if (!dsa.VerifySignature(M, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        // L4.3  X9.62 2005
+        [Test]
+        public void TestECDsaP521Sha512()
+        {
+            X9ECParameters p = NistNamedCurves.GetByName("P-521");
+            ECDomainParameters parameters = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("617573726813476282316253885608633222275541026607493641741273231656161177732180358888434629562647985511298272498852936680947729040673640492310550142822667389"), // d
+                parameters);
+            SecureRandom k = FixedSecureRandom.From(BigIntegers.AsUnsignedByteArray(new BigInteger("6806532878215503520845109818432174847616958675335397773700324097584974639728725689481598054743894544060040710846048585856076812050552869216017728862957612913")));
+
+            byte[] M = Hex.Decode("6893B64BD3A9615C39C3E62DDD269C2BAAF1D85915526083183CE14C2E883B48B193607C1ED871852C9DF9C3147B574DC1526C55DE1FE263A676346A20028A66");
+
+            ECDsaSigner dsa = new ECDsaSigner();
+
+            dsa.Init(true, new ParametersWithRandom(priKey, k));
+
+            BigInteger[] sig = dsa.GenerateSignature(M);
+
+            BigInteger r = new BigInteger("1368926195812127407956140744722257403535864168182534321188553460365652865686040549247096155740756318290773648848859639978618869784291633651685766829574104630");
+            BigInteger s = new BigInteger("1624754720348883715608122151214003032398685415003935734485445999065609979304811509538477657407457976246218976767156629169821116579317401249024208611945405790");
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                parameters.Curve.DecodePoint(Hex.Decode("020145E221AB9F71C5FE740D8D2B94939A09E2816E2167A7D058125A06A80C014F553E8D6764B048FB6F2B687CEC72F39738F223D4CE6AFCBFF2E34774AA5D3C342CB3")), // Q
+                parameters);
+
+            dsa.Init(false, pubKey);
+            if (!dsa.VerifySignature(M, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        /**
+         * General test for long digest.
+         */
+        [Test]
+        public void TestECDsa239bitBinaryAndLargeDigest()
+        {
+            BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
+            BigInteger s = new BigInteger("144940322424411242416373536877786566515839911620497068645600824084578597");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(
+                new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            F2mCurve curve = new F2mCurve(
+                239, // m
+                36, //k
+                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
+                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(
+                    Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
+                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
+                BigInteger.ValueOf(4)); // h
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
+                parameters);
+
+            ECDsaSigner ecdsa = new ECDsaSigner();
+            ParametersWithRandom param = new ParametersWithRandom(priKey, k);
+
+            ecdsa.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517").ToByteArray();
+            BigInteger[] sig = ecdsa.GenerateSignature(message);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+
+            // Verify the signature
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(
+                    Hex.Decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
+                parameters);
+
+            ecdsa.Init(false, pubKey);
+            if (!ecdsa.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        /**
+         * key generation test
+         */
+        [Test]
+        public void TestECDsaKeyGenTest()
+        {
+            SecureRandom random = new SecureRandom();
+
+            BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                n);
+
+            ECKeyPairGenerator pGen = new ECKeyPairGenerator();
+            ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
+                parameters,
+                random);
+
+            pGen.Init(genParam);
+
+            AsymmetricCipherKeyPair pair = pGen.GenerateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+            ECDsaSigner ecdsa = new ECDsaSigner();
+
+            ecdsa.Init(true, param);
+
+            byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").ToByteArray();
+            BigInteger[] sig = ecdsa.GenerateSignature(message);
+
+            ecdsa.Init(false, pair.Public);
+
+            if (!ecdsa.VerifySignature(message, sig[0], sig[1]))
+            {
+                Fail("signature fails");
+            }
+        }
+
+        /**
+         * Basic Key Agreement Test
+         */
+        [Test]
+        public void TestECBasicAgreementTest()
+        {
+            SecureRandom random = new SecureRandom();
+
+            BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                n);
+
+            ECKeyPairGenerator pGen = new ECKeyPairGenerator();
+            ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(parameters, random);
+
+            pGen.Init(genParam);
+
+            AsymmetricCipherKeyPair p1 = pGen.GenerateKeyPair();
+            AsymmetricCipherKeyPair p2 = pGen.GenerateKeyPair();
+
+            //
+            // two way
+            //
+            IBasicAgreement e1 = new ECDHBasicAgreement();
+            IBasicAgreement e2 = new ECDHBasicAgreement();
+
+            e1.Init(p1.Private);
+            e2.Init(p2.Private);
+
+            BigInteger   k1 = e1.CalculateAgreement(p2.Public);
+            BigInteger   k2 = e2.CalculateAgreement(p1.Public);
+
+            if (!k1.Equals(k2))
+            {
+                Fail("calculated agreement test failed");
+            }
+
+            //
+            // two way
+            //
+            e1 = new ECDHCBasicAgreement();
+            e2 = new ECDHCBasicAgreement();
+
+            e1.Init(p1.Private);
+            e2.Init(p2.Private);
+
+            k1 = e1.CalculateAgreement(p2.Public);
+            k2 = e2.CalculateAgreement(p1.Public);
+
+            if (!k1.Equals(k2))
+            {
+                Fail("calculated agreement test failed");
+            }
+        }
+
+        [Test]
+        public void TestECMqvTestVector1()
+        {
+            // Test Vector from GEC-2
+
+            X9ECParameters x9 = SecNamedCurves.GetByName("secp160r1");
+            ECDomainParameters p = new ECDomainParameters(
+                x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+
+            AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("0251B4496FECC406ED0E75A24A3C03206251419DC0")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("AA374FFC3CE144E6B073307972CB6D57B2A4E982", 16), p));
+
+            AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("03D99CE4D8BF52FA20BD21A962C6556B0F71F4CA1F")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("149EC7EA3A220A887619B3F9E5B4CA51C7D1779C", 16), p));
+
+            AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("0349B41E0E9C0369C2328739D90F63D56707C6E5BC")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("45FB58A92A17AD4B15101C66E74F277E2B460866", 16), p));
+
+            AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("02706E5D6E1F640C6E9C804E75DBC14521B1E5F3B5")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("18C13FCED9EADF884F7C595C8CB565DEFD0CB41E", 16), p));
+
+            BigInteger x = calculateAgreement(U1, U2, V1, V2);
+
+            if (x == null
+                || !x.Equals(new BigInteger("5A6955CEFDB4E43255FB7FCF718611E4DF8E05AC", 16)))
+            {
+                Fail("MQV Test Vector #1 agreement failed");
+            }
+        }
+
+        [Test]
+        public void TestECMqvTestVector2()
+        {
+            // Test Vector from GEC-2
+
+            X9ECParameters x9 = SecNamedCurves.GetByName("sect163k1");
+            ECDomainParameters p = new ECDomainParameters(
+                x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+
+            AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("03037D529FA37E42195F10111127FFB2BB38644806BC")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("03A41434AA99C2EF40C8495B2ED9739CB2155A1E0D", 16), p));
+
+            AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("02015198E74BC2F1E5C9A62B80248DF0D62B9ADF8429")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("032FC4C61A8211E6A7C4B8B0C03CF35F7CF20DBD52", 16), p));
+
+            AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("03072783FAAB9549002B4F13140B88132D1C75B3886C")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("57E8A78E842BF4ACD5C315AA0569DB1703541D96", 16), p));
+
+            AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair(
+                new ECPublicKeyParameters(
+                    p.Curve.DecodePoint(Hex.Decode("03067E3AEA3510D69E8EDD19CB2A703DDC6CF5E56E32")), p),
+                new ECPrivateKeyParameters(
+                    new BigInteger("02BD198B83A667A8D908EA1E6F90FD5C6D695DE94F", 16), p));
+
+            BigInteger x = calculateAgreement(U1, U2, V1, V2);
+
+            if (x == null
+                || !x.Equals(new BigInteger("038359FFD30C0D5FC1E6154F483B73D43E5CF2B503", 16)))
+            {
+                Fail("MQV Test Vector #2 agreement failed");
+            }
+        }
+
+        [Test]
+        public void TestECMqvRandom()
+        {
+            SecureRandom random = new SecureRandom();
+
+            BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b
+                n, BigInteger.One);
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                n);
+
+            ECKeyPairGenerator pGen = new ECKeyPairGenerator();
+
+            pGen.Init(new ECKeyGenerationParameters(parameters, random));
+
+
+            // Pre-established key pairs
+            AsymmetricCipherKeyPair U1 = pGen.GenerateKeyPair();
+            AsymmetricCipherKeyPair V1 = pGen.GenerateKeyPair();
+
+            // Ephemeral key pairs
+            AsymmetricCipherKeyPair U2 = pGen.GenerateKeyPair();
+            AsymmetricCipherKeyPair V2 = pGen.GenerateKeyPair();
+
+            BigInteger x = calculateAgreement(U1, U2, V1, V2);
+
+            if (x == null)
+            {
+                Fail("MQV Test Vector (random) agreement failed");
+            }
+        }
+
+        private static BigInteger calculateAgreement(
+            AsymmetricCipherKeyPair U1,
+            AsymmetricCipherKeyPair U2,
+            AsymmetricCipherKeyPair V1,
+            AsymmetricCipherKeyPair V2)
+        {
+            ECMqvBasicAgreement u = new ECMqvBasicAgreement();
+            u.Init(new MqvPrivateParameters(
+                (ECPrivateKeyParameters)U1.Private,
+                (ECPrivateKeyParameters)U2.Private,
+                (ECPublicKeyParameters)U2.Public));
+            BigInteger ux = u.CalculateAgreement(new MqvPublicParameters(
+                (ECPublicKeyParameters)V1.Public,
+                (ECPublicKeyParameters)V2.Public));
+
+            ECMqvBasicAgreement v = new ECMqvBasicAgreement();
+            v.Init(new MqvPrivateParameters(
+                (ECPrivateKeyParameters)V1.Private,
+                (ECPrivateKeyParameters)V2.Private,
+                (ECPublicKeyParameters)V2.Public));
+            BigInteger vx = v.CalculateAgreement(new MqvPublicParameters(
+                (ECPublicKeyParameters)U1.Public,
+                (ECPublicKeyParameters)U2.Public));
+
+            if (ux.Equals(vx))
+                return ux;
+
+            return null;
+        }
+
+        public override string Name
+        {
+            get { return "EC"; }
+        }
+
+        public override void PerformTest()
+        {
+            TestDecode();
+            TestECDsa192bitPrime();
+            TestECDsa239bitPrime();
+            TestECDsa191bitBinary();
+            TestECDsa239bitBinary();
+            TestECDsaKeyGenTest();
+            TestECBasicAgreementTest();
+
+            TestECDsaP224Sha224();
+            TestECDsaP224OneByteOver();
+            TestECDsaP256Sha256();
+            TestECDsaP521Sha512();
+            TestECDsaSecP224k1Sha256();
+            TestECDsa239bitBinaryAndLargeDigest();
+
+            TestECMqvTestVector1();
+            TestECMqvTestVector2();
+            TestECMqvRandom();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ECTest());
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ElGamalTest.cs b/crypto/test/src/crypto/test/ElGamalTest.cs
new file mode 100644
index 000000000..1caa70387
--- /dev/null
+++ b/crypto/test/src/crypto/test/ElGamalTest.cs
@@ -0,0 +1,278 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class ElGamalTest
+		: SimpleTest
+	{
+		private static readonly BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+		private static readonly BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+		private static readonly BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16);
+		private static readonly BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16);
+
+		private static readonly BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16);
+		private static readonly BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16);
+
+		private static readonly BigInteger yPgpBogusPSamp = new BigInteger("de4688497cc05b45fe8559bc9918c45afcad69b74123a7236eba409fd9de8ea34c7869839ee9df35e3d97576145d089841aa65b5b4e061fae52c37e430354269a02496b8ed8456f2d0d7c9b0db985fbcb21ae9f78507ed6e3a29db595b201b1a4f931c7d791eede65ccf918e8a61cf146859151c78c41ad48853694623467d78", 16);
+		private static readonly BigInteger xPgpBogusPSamp = new BigInteger("cbaf780f2cfe4f987bbc5fcb0738bbd7912060ccfdf37cbfeea65c0fd857e74a8df6cc359375f28cf5725d081813c614410a78cbe4b06d677beea9ff0fa10b1dbc47a6ed8c5b8466d6a95d6574029dbdf72596392e1b6b230faf9916dc8455821c10527a375a4d1c8a54947d1fe714d321aca25ad486b4b456506999fd2fd11a", 16);
+		private static readonly BigInteger gPgpBogusPSamp = new BigInteger("153ffe9522076d1cbd6e75f0816a0fc2ebd8b0e0091406587387a1763022088a03b411eed07ff50efb82b21f1608c352d10f63ba7e7e981a2f3387cec8af2915953d00493857663ae8919f517fe90f1d2abe7af4305a344b10d1a25d75f65902cd7fd775853d3ac43d7c5253ad666e1e63ee98cdcb10af81273d4ff053ff07d51", 16);
+		private static readonly BigInteger pPgpBogusPSamp = new BigInteger("15061b26cdab4e865098a01c86f13b03220104c5443e950658b36b85245aa0c616a0c0d8d99c454bea087c172315e45b3bc9b925443948a2b6ba47608a6035b9a79a4ef34a78d7274a12ede8364f02d5030db864988643d7e92753df603bd69fbd2682ab0af64d1a866d1131a2cb13333cedb0a9e6eefddd9fff8154d34c2daab", 16);
+		private const int lPgpBogusPSamp = 0;
+
+		public override string Name
+		{
+			get { return "ElGamal"; }
+		}
+
+		private void doTestEnc(
+			int         size,
+			int         privateValueSize,
+			BigInteger  g,
+			BigInteger  p)
+		{
+			ElGamalParameters dhParams = new ElGamalParameters(p, g, privateValueSize);
+			ElGamalKeyGenerationParameters ekgParams = new ElGamalKeyGenerationParameters(new SecureRandom(), dhParams);
+			ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator();
+
+			kpGen.Init(ekgParams);
+
+			//
+			// generate pair
+			//
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+			ElGamalPublicKeyParameters pu = (ElGamalPublicKeyParameters) pair.Public;
+			ElGamalPrivateKeyParameters pv = (ElGamalPrivateKeyParameters) pair.Private;
+
+			checkKeySize(privateValueSize, pv);
+
+			ElGamalEngine e = new ElGamalEngine();
+
+			e.Init(true, pu);
+
+			if (e.GetOutputBlockSize() != size / 4)
+			{
+				Fail(size + " GetOutputBlockSize() on encryption failed.");
+			}
+
+			byte[] message = Hex.Decode("5468697320697320612074657374");
+
+			byte[] pText = message;
+			byte[] cText = e.ProcessBlock(pText, 0, pText.Length);
+
+			e.Init(false, pv);
+
+			if (e.GetOutputBlockSize() != (size / 8) - 1)
+			{
+				Fail(size + " GetOutputBlockSize() on decryption failed.");
+			}
+
+			pText = e.ProcessBlock(cText, 0, cText.Length);
+
+			if (!Arrays.AreEqual(message, pText))
+			{
+				Fail(size + " bit test failed");
+			}
+
+
+
+			e.Init(true, pu);
+			byte[] bytes = new byte[e.GetInputBlockSize() + 2];
+
+			try
+			{
+				e.ProcessBlock(bytes, 0, bytes.Length);
+
+				Fail("out of range block not detected");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+
+			try
+			{
+				bytes[0] = (byte)0xff;
+
+				e.ProcessBlock(bytes, 0, bytes.Length - 1);
+
+				Fail("out of range block not detected");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+
+			try
+			{
+				bytes[0] = (byte)0x7f;
+
+				e.ProcessBlock(bytes, 0, bytes.Length - 1);
+			}
+			catch (DataLengthException)
+			{
+				Fail("in range block failed");
+			}
+		}
+
+		private void checkKeySize(
+			int							privateValueSize,
+			ElGamalPrivateKeyParameters	priv)
+		{
+			if (privateValueSize != 0)
+			{
+				if (priv.X.BitLength != privateValueSize)
+				{
+					Fail("limited key check failed for key size " + privateValueSize);
+				}
+			}
+		}
+
+		/**
+		 * this test is can take quiet a while
+		 *
+		 * @param size size of key in bits.
+		 */
+		private void doTestGeneration(
+			int size)
+		{
+			ElGamalParametersGenerator pGen = new ElGamalParametersGenerator();
+
+			pGen.Init(size, 10, new SecureRandom());
+
+			ElGamalParameters elParams = pGen.GenerateParameters();
+
+			if (elParams.L != 0)
+			{
+				Fail("ElGamalParametersGenerator failed to set L to 0 in generated ElGamalParameters");
+			}
+
+			ElGamalKeyGenerationParameters ekgParams = new ElGamalKeyGenerationParameters(new SecureRandom(), elParams);
+
+			ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator();
+
+			kpGen.Init(ekgParams);
+
+			//
+			// generate first pair
+			//
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+			ElGamalPublicKeyParameters pu = (ElGamalPublicKeyParameters)pair.Public;
+			ElGamalPrivateKeyParameters pv = (ElGamalPrivateKeyParameters)pair.Private;
+
+			ElGamalEngine e = new ElGamalEngine();
+
+			e.Init(true, new ParametersWithRandom(pu, new SecureRandom()));
+
+			byte[] message = Hex.Decode("5468697320697320612074657374");
+
+			byte[] pText = message;
+			byte[] cText = e.ProcessBlock(pText, 0, pText.Length);
+
+			e.Init(false, pv);
+
+			pText = e.ProcessBlock(cText, 0, cText.Length);
+
+			if (!Arrays.AreEqual(message, pText))
+			{
+				Fail("generation test failed");
+			}
+		}
+
+		[Test]
+		public void TestInvalidP()
+		{
+			ElGamalParameters dhParams = new ElGamalParameters(pPgpBogusPSamp, gPgpBogusPSamp, lPgpBogusPSamp);
+			ElGamalPublicKeyParameters pu = new ElGamalPublicKeyParameters(yPgpBogusPSamp, dhParams);
+			ElGamalPrivateKeyParameters pv = new ElGamalPrivateKeyParameters(xPgpBogusPSamp, dhParams);
+
+			ElGamalEngine e = new ElGamalEngine();
+
+			e.Init(true, pu);
+
+			byte[] message = Hex.Decode("5468697320697320612074657374");
+
+			byte[] pText = message;
+			byte[] cText = e.ProcessBlock(pText, 0, pText.Length);
+
+			e.Init(false, pv);
+
+			pText = e.ProcessBlock(cText, 0, cText.Length);
+
+			if (Arrays.AreEqual(message, pText))
+			{
+				Fail("invalid test failed");
+			}
+		}
+
+		[Test]
+		public void TestEnc512()
+		{
+			doTestEnc(512, 0, g512, p512);
+			doTestEnc(512, 64, g512, p512);
+		}
+
+		[Test]
+		public void TestEnc768()
+		{
+			doTestEnc(768, 0, g768, p768);
+			doTestEnc(768, 128, g768, p768);
+		}
+
+		[Test]
+		public void TestEnc1024()
+		{
+			doTestEnc(1024, 0, g1024, p1024);
+		}
+
+		[Test]
+		public void TestGeneration258()
+		{
+			doTestGeneration(258);
+		}
+
+		[Test]
+		public void TestInitCheck()
+		{
+			try
+			{
+				new ElGamalEngine().ProcessBlock(new byte[]{ 1 }, 0, 1);
+				Fail("failed initialisation check");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+		}
+
+		public override void PerformTest()
+		{
+			TestInvalidP();
+			TestEnc512();
+			TestEnc768();
+			TestEnc1024();
+			TestGeneration258();
+			TestInitCheck();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ElGamalTest());
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/EqualsHashCodeTest.cs b/crypto/test/src/crypto/test/EqualsHashCodeTest.cs
new file mode 100644
index 000000000..05cc9ad53
--- /dev/null
+++ b/crypto/test/src/crypto/test/EqualsHashCodeTest.cs
@@ -0,0 +1,262 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	internal class DHTestKeyParameters
+		: DHKeyParameters
+	{
+		public DHTestKeyParameters(
+			bool			isPrivate,
+			DHParameters	parameters)
+			: base(isPrivate, parameters)
+		{
+		}
+	}
+
+	internal class ElGamalTestKeyParameters
+		: ElGamalKeyParameters
+	{
+		public ElGamalTestKeyParameters(
+			bool				isPrivate,
+			ElGamalParameters	parameters)
+			: base(isPrivate, parameters)
+		{
+		}
+	}
+
+	[TestFixture]
+	public class EqualsHashCodeTest
+		: SimpleTest
+	{
+		private static object Other = new object();
+
+		public override string Name
+		{
+			get { return "EqualsHashCode"; }
+		}
+
+		private void doTest(
+			object	a,
+			object	equalsA,
+			object	notEqualsA)
+		{
+			if (a.Equals(null))
+			{
+				Fail("a equaled null");
+			}
+
+			if (!a.Equals(equalsA) || !equalsA.Equals(a))
+			{
+				Fail("equality failed");
+			}
+
+			if (a.Equals(Other))
+			{
+				Fail("other inequality failed");
+			}
+
+			if (a.Equals(notEqualsA) || notEqualsA.Equals(a))
+			{
+				Fail("inequality failed");
+			}
+
+			if (a.GetHashCode() != equalsA.GetHashCode())
+			{
+				Fail("hashCode equality failed");
+			}
+		}
+
+		[Test]
+		public void TestDH()
+		{
+			BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+			BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+			DHParameters dhParams = new DHParameters(p512, g512);
+			DHKeyGenerationParameters parameters = new DHKeyGenerationParameters(new SecureRandom(), dhParams);         DHKeyPairGenerator          kpGen = new DHKeyPairGenerator();
+
+			kpGen.Init(parameters);
+
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+			DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.Public;
+			DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.Private;
+
+			DHPublicKeyParameters pu2 = new DHPublicKeyParameters(pu1.Y, pu1.Parameters);
+			DHPrivateKeyParameters pv2 = new DHPrivateKeyParameters(pv1.X, pv1.Parameters);
+			DHPublicKeyParameters pu3 = new DHPublicKeyParameters(pv1.X, pu1.Parameters);
+			DHPrivateKeyParameters pv3 = new DHPrivateKeyParameters(pu1.Y, pu1.Parameters);
+
+			doTest(pu1, pu2, pu3);
+			doTest(pv1, pv2, pv3);
+
+			DHParameters pr1 = pu1.Parameters;
+			DHParameters pr2 = new DHParameters(
+				pr1.P, pr1.G, pr1.Q, pr1.M, pr1.L, pr1.J, pr1.ValidationParameters);
+			DHParameters pr3 = new DHParameters(
+				pr1.P.Add(BigInteger.Two), pr1.G, pr1.Q, pr1.M, pr1.L, pr1.J, pr1.ValidationParameters);
+
+			doTest(pr1, pr2, pr3);
+
+			pr3 = new DHParameters(
+				pr1.P, pr1.G.Add(BigInteger.One), pr1.Q, pr1.M, pr1.L, pr1.J, pr1.ValidationParameters);
+
+			doTest(pr1, pr2, pr3);
+
+			pu2 = new DHPublicKeyParameters(pu1.Y, pr2);
+			pv2 = new DHPrivateKeyParameters(pv1.X, pr2);
+
+			doTest(pu1, pu2, pu3);
+			doTest(pv1, pv2, pv3);
+
+			DHValidationParameters vp1 = new DHValidationParameters(new byte[20], 1024);
+			DHValidationParameters vp2 = new DHValidationParameters(new byte[20], 1024);
+			DHValidationParameters vp3 = new DHValidationParameters(new byte[24], 1024);
+
+			doTest(vp1, vp1, vp3);
+			doTest(vp1, vp2, vp3);
+
+			byte[] bytes = new byte[20];
+			bytes[0] = 1;
+
+			vp3 = new DHValidationParameters(bytes, 1024);
+
+			doTest(vp1, vp2, vp3);
+
+			vp3 = new DHValidationParameters(new byte[20], 2048);
+
+			doTest(vp1, vp2, vp3);
+
+			DHTestKeyParameters k1 = new DHTestKeyParameters(false, null);
+			DHTestKeyParameters k2 = new DHTestKeyParameters(false, null);
+			DHTestKeyParameters k3 = new DHTestKeyParameters(false, pu1.Parameters);
+
+			doTest(k1, k2, k3);
+		}
+
+		[Test]
+		public void TestElGamal()
+		{
+			BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+			BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+			ElGamalParameters dhParams = new ElGamalParameters(p512, g512);
+			ElGamalKeyGenerationParameters parameters = new ElGamalKeyGenerationParameters(new SecureRandom(), dhParams);         ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator();
+
+			kpGen.Init(parameters);
+
+			AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+			ElGamalPublicKeyParameters pu1 = (ElGamalPublicKeyParameters)pair.Public;
+			ElGamalPrivateKeyParameters pv1 = (ElGamalPrivateKeyParameters)pair.Private;
+
+			ElGamalPublicKeyParameters pu2 = new ElGamalPublicKeyParameters(pu1.Y, pu1.Parameters);
+			ElGamalPrivateKeyParameters pv2 = new ElGamalPrivateKeyParameters(pv1.X, pv1.Parameters);
+			ElGamalPublicKeyParameters pu3 = new ElGamalPublicKeyParameters(pv1.X, pu1.Parameters);
+			ElGamalPrivateKeyParameters pv3 = new ElGamalPrivateKeyParameters(pu1.Y, pu1.Parameters);
+
+			doTest(pu1, pu2, pu3);
+			doTest(pv1, pv2, pv3);
+
+			ElGamalParameters pr1 = pu1.Parameters;
+			ElGamalParameters pr2 = new ElGamalParameters(pr1.P, pr1.G);
+			ElGamalParameters pr3 = new ElGamalParameters(pr1.G, pr1.P);
+
+			doTest(pr1, pr2, pr3);
+
+			pu2 = new ElGamalPublicKeyParameters(pu1.Y, pr2);
+			pv2 = new ElGamalPrivateKeyParameters(pv1.X, pr2);
+
+			doTest(pu1, pu2, pu3);
+			doTest(pv1, pv2, pv3);
+
+			ElGamalTestKeyParameters k1 = new ElGamalTestKeyParameters(false, null);
+			ElGamalTestKeyParameters k2 = new ElGamalTestKeyParameters(false, null);
+			ElGamalTestKeyParameters k3 = new ElGamalTestKeyParameters(false, pu1.Parameters);
+
+			doTest(k1, k2, k3);
+		}
+
+		[Test]
+		public void TestDsa()
+		{
+			BigInteger a = BigInteger.ValueOf(1), b = BigInteger.ValueOf(2), c = BigInteger.ValueOf(3);
+
+			DsaParameters dsaP1 = new DsaParameters(a, b, c);
+			DsaParameters dsaP2 = new DsaParameters(a, b, c);
+			DsaParameters dsaP3 = new DsaParameters(b, c, a);
+
+			doTest(dsaP1, dsaP2, dsaP3);
+
+			DsaValidationParameters vp1 = new DsaValidationParameters(new byte[20], 1024);
+			DsaValidationParameters vp2 = new DsaValidationParameters(new byte[20], 1024);
+			DsaValidationParameters vp3 = new DsaValidationParameters(new byte[24], 1024);
+
+			doTest(vp1, vp1, vp3);
+			doTest(vp1, vp2, vp3);
+
+			byte[] bytes = new byte[20];
+			bytes[0] = 1;
+
+			vp3 = new DsaValidationParameters(bytes, 1024);
+
+			doTest(vp1, vp2, vp3);
+
+			vp3 = new DsaValidationParameters(new byte[20], 2048);
+
+			doTest(vp1, vp2, vp3);
+		}
+
+		[Test]
+		public void TestGost3410()
+		{
+			BigInteger a = BigInteger.ValueOf(1), b = BigInteger.ValueOf(2), c = BigInteger.ValueOf(3);
+
+			Gost3410Parameters g1 = new Gost3410Parameters(a, b, c);
+			Gost3410Parameters g2 = new Gost3410Parameters(a, b, c);
+			Gost3410Parameters g3 = new Gost3410Parameters(a, c, c);
+
+			doTest(g1, g2, g3);
+
+			Gost3410ValidationParameters v1 = new Gost3410ValidationParameters(100, 1);
+			Gost3410ValidationParameters v2 = new Gost3410ValidationParameters(100, 1);
+			Gost3410ValidationParameters v3 = new Gost3410ValidationParameters(101, 1);
+
+			doTest(v1, v2, v3);
+
+			v3 = new Gost3410ValidationParameters(100, 2);
+
+			doTest(v1, v2, v3);
+
+			v1 = new Gost3410ValidationParameters(100L, 1L);
+			v2 = new Gost3410ValidationParameters(100L, 1L);
+			v3 = new Gost3410ValidationParameters(101L, 1L);
+
+			doTest(v1, v2, v3);
+
+			v3 = new Gost3410ValidationParameters(100L, 2L);
+
+			doTest(v1, v2, v3);
+		}
+
+		public override void PerformTest()
+		{
+			TestDH();
+			TestElGamal();
+			TestGost3410();
+			TestDsa();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new EqualsHashCodeTest());
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/GCMTest.cs b/crypto/test/src/crypto/test/GCMTest.cs
new file mode 100644
index 000000000..943ffdad4
--- /dev/null
+++ b/crypto/test/src/crypto/test/GCMTest.cs
@@ -0,0 +1,711 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Modes.Gcm;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary>
+    /// Test vectors from "The Galois/Counter Mode of Operation (GCM)", McGrew/Viega, Appendix B
+    /// </summary>
+    [TestFixture]
+    public class GcmTest
+        : SimpleTest
+    {
+        private static readonly string[][] TestVectors = new string[][]
+        {
+            new string[]
+            {
+                "Test Case 1",
+                "00000000000000000000000000000000",
+                "",
+                "",
+                "000000000000000000000000",
+                "",
+                "58e2fccefa7e3061367f1d57a4e7455a",
+            },
+            new string[]
+            {
+                "Test Case 2",
+                "00000000000000000000000000000000",
+                "00000000000000000000000000000000",
+                "",
+                "000000000000000000000000",
+                "0388dace60b6a392f328c2b971b2fe78",
+                "ab6e47d42cec13bdf53a67b21257bddf",
+            },
+            new string[]
+            {
+                "Test Case 3",
+                "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b391aafd255",
+                "",
+                "cafebabefacedbaddecaf888",
+                "42831ec2217774244b7221b784d0d49c"
+                + "e3aa212f2c02a4e035c17e2329aca12e"
+                + "21d514b25466931c7d8f6a5aac84aa05"
+                + "1ba30b396a0aac973d58e091473f5985",
+                "4d5c2af327cd64a62cf35abd2ba6fab4",
+            },
+            new string[]
+            {
+                "Test Case 4",
+                "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "cafebabefacedbaddecaf888",
+                "42831ec2217774244b7221b784d0d49c"
+                + "e3aa212f2c02a4e035c17e2329aca12e"
+                + "21d514b25466931c7d8f6a5aac84aa05"
+                + "1ba30b396a0aac973d58e091",
+                "5bc94fbc3221a5db94fae95ae7121a47",
+            },
+            new string[]
+            {
+                "Test Case 5",
+                "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "cafebabefacedbad",
+                "61353b4c2806934a777ff51fa22a4755"
+                + "699b2a714fcdc6f83766e5f97b6c7423"
+                + "73806900e49f24b22b097544d4896b42"
+                + "4989b5e1ebac0f07c23f4598",
+                "3612d2e79e3b0785561be14aaca2fccb",
+            },
+            new string[]
+            {
+                "Test Case 6",
+                "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "9313225df88406e555909c5aff5269aa"
+                + "6a7a9538534f7da1e4c303d2a318a728"
+                + "c3c0c95156809539fcf0e2429a6b5254"
+                + "16aedbf5a0de6a57a637b39b",
+                "8ce24998625615b603a033aca13fb894"
+                + "be9112a5c3a211a8ba262a3cca7e2ca7"
+                + "01e4a9a4fba43c90ccdcb281d48c7c6f"
+                + "d62875d2aca417034c34aee5",
+                "619cc5aefffe0bfa462af43c1699d050",
+            },
+            new string[]
+            {
+                "Test Case 7",
+                "00000000000000000000000000000000"
+                + "0000000000000000",
+                "",
+                "",
+                "000000000000000000000000",
+                "",
+                "cd33b28ac773f74ba00ed1f312572435",
+            },
+            new string[]
+            {
+                "Test Case 8",
+                "00000000000000000000000000000000"
+                + "0000000000000000",
+                "00000000000000000000000000000000",
+                "",
+                "000000000000000000000000",
+                "98e7247c07f0fe411c267e4384b0f600",
+                "2ff58d80033927ab8ef4d4587514f0fb",
+            },
+            new string[]
+            {
+                "Test Case 9",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b391aafd255",
+                "",
+                "cafebabefacedbaddecaf888",
+                "3980ca0b3c00e841eb06fac4872a2757"
+                + "859e1ceaa6efd984628593b40ca1e19c"
+                + "7d773d00c144c525ac619d18c84a3f47"
+                + "18e2448b2fe324d9ccda2710acade256",
+                "9924a7c8587336bfb118024db8674a14",
+            },
+            new string[]
+            {
+                "Test Case 10",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "cafebabefacedbaddecaf888",
+                "3980ca0b3c00e841eb06fac4872a2757"
+                + "859e1ceaa6efd984628593b40ca1e19c"
+                + "7d773d00c144c525ac619d18c84a3f47"
+                + "18e2448b2fe324d9ccda2710",
+                "2519498e80f1478f37ba55bd6d27618c",
+            },
+            new string[]
+            {
+                "Test Case 11",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "cafebabefacedbad",
+                "0f10f599ae14a154ed24b36e25324db8"
+                + "c566632ef2bbb34f8347280fc4507057"
+                + "fddc29df9a471f75c66541d4d4dad1c9"
+                + "e93a19a58e8b473fa0f062f7",
+                "65dcc57fcf623a24094fcca40d3533f8",
+            },
+            new string[]
+            {
+                "Test Case 12",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "9313225df88406e555909c5aff5269aa"
+                + "6a7a9538534f7da1e4c303d2a318a728"
+                + "c3c0c95156809539fcf0e2429a6b5254"
+                + "16aedbf5a0de6a57a637b39b",
+                "d27e88681ce3243c4830165a8fdcf9ff"
+                + "1de9a1d8e6b447ef6ef7b79828666e45"
+                + "81e79012af34ddd9e2f037589b292db3"
+                + "e67c036745fa22e7e9b7373b",
+                "dcf566ff291c25bbb8568fc3d376a6d9",
+            },
+            new string[]
+            {
+                "Test Case 13",
+                "00000000000000000000000000000000"
+                + "00000000000000000000000000000000",
+                "",
+                "",
+                "000000000000000000000000",
+                "",
+                "530f8afbc74536b9a963b4f1c4cb738b",
+            },
+            new string[]
+            {
+                "Test Case 14",
+                "00000000000000000000000000000000"
+                + "00000000000000000000000000000000",
+                "00000000000000000000000000000000",
+                "",
+                "000000000000000000000000",
+                "cea7403d4d606b6e074ec5d3baf39d18",
+                "d0d1c8a799996bf0265b98b5d48ab919",
+            },
+            new string[]
+            {
+                "Test Case 15",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b391aafd255",
+                "",
+                "cafebabefacedbaddecaf888",
+                "522dc1f099567d07f47f37a32a84427d"
+                + "643a8cdcbfe5c0c97598a2bd2555d1aa"
+                + "8cb08e48590dbb3da7b08b1056828838"
+                + "c5f61e6393ba7a0abcc9f662898015ad",
+                "b094dac5d93471bdec1a502270e3cc6c",
+            },
+            new string[]
+            {
+                "Test Case 16",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "cafebabefacedbaddecaf888",
+                "522dc1f099567d07f47f37a32a84427d"
+                + "643a8cdcbfe5c0c97598a2bd2555d1aa"
+                + "8cb08e48590dbb3da7b08b1056828838"
+                + "c5f61e6393ba7a0abcc9f662",
+                "76fc6ece0f4e1768cddf8853bb2d551b",
+            },
+            new string[]
+            {
+                "Test Case 17",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "cafebabefacedbad",
+                "c3762df1ca787d32ae47c13bf19844cb"
+                + "af1ae14d0b976afac52ff7d79bba9de0"
+                + "feb582d33934a4f0954cc2363bc73f78"
+                + "62ac430e64abe499f47c9b1f",
+                "3a337dbf46a792c45e454913fe2ea8f2",
+            },
+            new string[]
+            {
+                "Test Case 18",
+                "feffe9928665731c6d6a8f9467308308"
+                + "feffe9928665731c6d6a8f9467308308",
+                "d9313225f88406e5a55909c5aff5269a"
+                + "86a7a9531534f7da2e4c303d8a318a72"
+                + "1c3c0c95956809532fcf0e2449a6b525"
+                + "b16aedf5aa0de657ba637b39",
+                "feedfacedeadbeeffeedfacedeadbeef"
+                + "abaddad2",
+                "9313225df88406e555909c5aff5269aa"
+                + "6a7a9538534f7da1e4c303d2a318a728"
+                + "c3c0c95156809539fcf0e2429a6b5254"
+                + "16aedbf5a0de6a57a637b39b",
+                "5a8def2f0c9e53f1f75d7853659e2a20"
+                + "eeb2b22aafde6419a058ab4f6f746bf4"
+                + "0fc0c3b780f244452da3ebf1c5d82cde"
+                + "a2418997200ef82e44ae7e3f",
+                "a44a8266ee1c8eb0c8b5d4cf5ae9f19a",
+            },
+        };
+
+        public override string Name
+        {
+            get { return "GCM"; }
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i < TestVectors.Length; ++i)
+            {
+                RunTestCase(TestVectors[i]);
+            }
+
+            RandomTests();
+            OutputSizeTests();
+            DoTestExceptions();
+        }
+
+        protected IBlockCipher CreateAesEngine()
+        {
+            return new AesFastEngine();
+        }
+
+        private void DoTestExceptions()
+        {
+            GcmBlockCipher gcm = new GcmBlockCipher(CreateAesEngine());
+
+            try
+            {
+                gcm = new GcmBlockCipher(new DesEngine());
+
+                Fail("incorrect block size not picked up");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                gcm.Init(false, new KeyParameter(new byte[16]));
+
+                Fail("illegal argument not picked up");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            // TODO
+            //AEADTestUtil.testReset(this, new GCMBlockCipher(createAESEngine()), new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]));
+            //AEADTestUtil.testTampering(this, gcm, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]));
+            //AEADTestUtil.testOutputSizes(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(new KeyParameter(
+            //        new byte[16]), 128, new byte[16]));
+            //AEADTestUtil.testBufferSizeChecks(this, new GCMBlockCipher(createAESEngine()), new AEADParameters(
+            //        new KeyParameter(new byte[16]), 128, new byte[16]));
+        }
+
+        private void RunTestCase(string[] testVector)
+        {
+            for (int macLength = 12; macLength <= 16; ++macLength)
+            {
+                RunTestCase(testVector, macLength);
+            }
+        }
+
+        private void RunTestCase(string[] testVector, int macLength)
+        {
+            int pos = 0;
+            string testName = testVector[pos++];
+            byte[] K = Hex.Decode(testVector[pos++]);
+            byte[] P = Hex.Decode(testVector[pos++]);
+            byte[] A = Hex.Decode(testVector[pos++]);
+            byte[] IV = Hex.Decode(testVector[pos++]);
+            byte[] C = Hex.Decode(testVector[pos++]);
+
+            // For short MAC, take leading bytes
+            byte[] t = Hex.Decode(testVector[pos++]);
+            byte[] T = new byte[macLength];
+            Array.Copy(t, T, T.Length);
+
+            // Default multiplier
+            RunTestCase(null, null, testName, K, IV, A, P, C, T);
+
+            RunTestCase(new BasicGcmMultiplier(), new BasicGcmMultiplier(), testName, K, IV, A, P, C, T);
+            RunTestCase(new Tables8kGcmMultiplier(), new Tables8kGcmMultiplier(), testName, K, IV, A, P, C, T);
+            RunTestCase(new Tables64kGcmMultiplier(), new Tables64kGcmMultiplier(), testName, K, IV, A, P, C, T);
+        }
+
+        private void RunTestCase(
+            IGcmMultiplier	encM,
+            IGcmMultiplier	decM,
+            string			testName,
+            byte[]          K,
+            byte[]          IV,
+            byte[]          A,
+            byte[]          P,
+            byte[]			C,
+            byte[]			T)
+        {
+            byte[] fa = new byte[A.Length / 2];
+            byte[] la = new byte[A.Length - (A.Length / 2)];
+            Array.Copy(A, 0, fa, 0, fa.Length);
+            Array.Copy(A, fa.Length, la, 0, la.Length);
+
+            RunTestCase(encM, decM, testName + " all initial associated data", K, IV, A, null, P, C, T);
+            RunTestCase(encM, decM, testName + " all subsequent associated data", K, IV, null, A, P, C, T);
+            RunTestCase(encM, decM, testName + " split associated data", K, IV, fa, la, P, C, T);
+        }
+
+        private void RunTestCase(
+            IGcmMultiplier  encM,
+            IGcmMultiplier  decM,
+            string          testName,
+            byte[]          K,
+            byte[]          IV,
+            byte[]          A,
+            byte[]          SA,
+            byte[]          P,
+            byte[]          C,
+            byte[]          T)
+        {
+            AeadParameters parameters = new AeadParameters(new KeyParameter(K), T.Length * 8, IV, A);
+            GcmBlockCipher encCipher = InitCipher(encM, true, parameters);
+            GcmBlockCipher decCipher = InitCipher(decM, false, parameters);
+            CheckTestCase(encCipher, decCipher, testName, SA, P, C, T);
+            CheckTestCase(encCipher, decCipher, testName + " (reused)", SA, P, C, T);
+
+            // Key reuse
+            AeadParameters keyReuseParams = AeadTestUtilities.ReuseKey(parameters);
+            encCipher.Init(true, keyReuseParams);
+            decCipher.Init(false, keyReuseParams);
+            CheckTestCase(encCipher, decCipher, testName + " (key reuse)", SA, P, C, T);
+        }
+
+        private GcmBlockCipher InitCipher(
+            IGcmMultiplier	m,
+            bool			forEncryption,
+            AeadParameters	parameters)
+        {
+            GcmBlockCipher c = new GcmBlockCipher(CreateAesEngine(), m);
+            c.Init(forEncryption, parameters);
+            return c;
+        }
+
+        private void CheckTestCase(
+            GcmBlockCipher	encCipher,
+            GcmBlockCipher	decCipher,
+            string			testName,
+            byte[]          SA,
+            byte[]          P,
+            byte[]			C,
+            byte[]			T)
+        {
+            byte[] enc = new byte[encCipher.GetOutputSize(P.Length)];
+            if (SA != null)
+            {
+                encCipher.ProcessAadBytes(SA, 0, SA.Length);
+            }
+            int len = encCipher.ProcessBytes(P, 0, P.Length, enc, 0);
+            len += encCipher.DoFinal(enc, len);
+
+            if (enc.Length != len)
+            {
+//				Console.WriteLine("" + enc.Length + "/" + len);
+                Fail("encryption reported incorrect length: " + testName);
+            }
+
+            byte[] mac = encCipher.GetMac();
+
+            byte[] data = new byte[P.Length];
+            Array.Copy(enc, data, data.Length);
+            byte[] tail = new byte[enc.Length - P.Length];
+            Array.Copy(enc, P.Length, tail, 0, tail.Length);
+
+            if (!AreEqual(C, data))
+            {
+                Fail("incorrect encrypt in: " + testName);
+            }
+
+            if (!AreEqual(T, mac))
+            {
+                Fail("GetMac() returned wrong mac in: " + testName);
+            }
+
+            if (!AreEqual(T, tail))
+            {
+                Fail("stream contained wrong mac in: " + testName);
+            }
+
+            byte[] dec = new byte[decCipher.GetOutputSize(enc.Length)];
+            if (SA != null)
+            {
+                decCipher.ProcessAadBytes(SA, 0, SA.Length);
+            }
+            len = decCipher.ProcessBytes(enc, 0, enc.Length, dec, 0);
+            len += decCipher.DoFinal(dec, len);
+            mac = decCipher.GetMac();
+
+            data = new byte[C.Length];
+            Array.Copy(dec, data, data.Length);
+
+            if (!AreEqual(P, data))
+            {
+                Fail("incorrect decrypt in: " + testName);
+            }
+        }
+
+        private void RandomTests()
+        {
+            SecureRandom srng = new SecureRandom();
+            srng.SetSeed(DateTimeUtilities.CurrentUnixMs());
+            RandomTests(srng, null);
+            RandomTests(srng, new BasicGcmMultiplier());
+            RandomTests(srng, new Tables8kGcmMultiplier());
+            RandomTests(srng, new Tables64kGcmMultiplier());
+        }
+
+        private void RandomTests(SecureRandom srng, IGcmMultiplier m)
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                RandomTest(srng, m);
+            }
+        }
+
+        private void RandomTest(SecureRandom srng, IGcmMultiplier m)
+        {
+            int kLength = 16 + 8 * srng.Next(3);
+            byte[] K = new byte[kLength];
+            srng.NextBytes(K);
+
+            int pLength = srng.Next(65536);
+            byte[] P = new byte[pLength];
+            srng.NextBytes(P);
+
+            int aLength = srng.Next(256);
+            byte[] A = new byte[aLength];
+            srng.NextBytes(A);
+
+            int saLength = srng.Next(256);
+            byte[] SA = new byte[saLength];
+            srng.NextBytes(SA);
+
+            int ivLength = 1 + srng.Next(256);
+            byte[] IV = new byte[ivLength];
+            srng.NextBytes(IV);
+
+            AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A);
+            GcmBlockCipher cipher = InitCipher(m, true, parameters);
+            byte[] C = new byte[cipher.GetOutputSize(P.Length)];
+            int predicted = cipher.GetUpdateOutputSize(P.Length);
+
+            int split = srng.Next(SA.Length + 1);
+            cipher.ProcessAadBytes(SA, 0, split);
+            int len = cipher.ProcessBytes(P, 0, P.Length, C, 0);
+            cipher.ProcessAadBytes(SA, split, SA.Length - split);
+
+            if (predicted != len)
+            {
+                Fail("encryption reported incorrect update length in randomised test");
+            }
+
+            len += cipher.DoFinal(C, len);
+
+            if (C.Length != len)
+            {
+                Fail("encryption reported incorrect length in randomised test");
+            }
+
+            byte[] encT = cipher.GetMac();
+            byte[] tail = new byte[C.Length - P.Length];
+            Array.Copy(C, P.Length, tail, 0, tail.Length);
+
+            if (!AreEqual(encT, tail))
+            {
+                Fail("stream contained wrong mac in randomised test");
+            }
+
+            cipher.Init(false, parameters);
+            byte[] decP = new byte[cipher.GetOutputSize(C.Length)];
+            predicted = cipher.GetUpdateOutputSize(C.Length);
+
+            split = srng.Next(SA.Length + 1);
+            cipher.ProcessAadBytes(SA, 0, split);
+            len = cipher.ProcessBytes(C, 0, C.Length, decP, 0);
+            cipher.ProcessAadBytes(SA, split, SA.Length - split);
+
+            if (predicted != len)
+            {
+                Fail("decryption reported incorrect update length in randomised test");
+            }
+
+            len += cipher.DoFinal(decP, len);
+
+            if (!AreEqual(P, decP))
+            {
+                Fail("incorrect decrypt in randomised test");
+            }
+
+            byte[] decT = cipher.GetMac();
+            if (!AreEqual(encT, decT))
+            {
+                Fail("decryption produced different mac from encryption");
+            }
+
+            //
+            // key reuse test
+            //
+            cipher.Init(false, AeadTestUtilities.ReuseKey(parameters));
+            decP = new byte[cipher.GetOutputSize(C.Length)];
+
+            split = NextInt(srng, SA.Length + 1);
+            cipher.ProcessAadBytes(SA, 0, split);
+            len = cipher.ProcessBytes(C, 0, C.Length, decP, 0);
+            cipher.ProcessAadBytes(SA, split, SA.Length - split);
+
+            len += cipher.DoFinal(decP, len);
+
+            if (!AreEqual(P, decP))
+            {
+                Fail("incorrect decrypt in randomised test");
+            }
+
+            decT = cipher.GetMac();
+            if (!AreEqual(encT, decT))
+            {
+                Fail("decryption produced different mac from encryption");
+            }
+        }
+
+        private void OutputSizeTests()
+        {
+            byte[] K = new byte[16];
+            byte[] A = null;
+            byte[] IV = new byte[16];
+
+            AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A);
+            GcmBlockCipher cipher = InitCipher(null, true, parameters);
+
+            if (cipher.GetUpdateOutputSize(0) != 0)
+            {
+                Fail("incorrect getUpdateOutputSize for initial 0 bytes encryption");
+            }
+
+            if (cipher.GetOutputSize(0) != 16)
+            {
+                Fail("incorrect getOutputSize for initial 0 bytes encryption");
+            }
+
+            cipher.Init(false, parameters);
+
+            if (cipher.GetUpdateOutputSize(0) != 0)
+            {
+                Fail("incorrect getUpdateOutputSize for initial 0 bytes decryption");
+            }
+
+            // NOTE: 0 bytes would be truncated data, but we want it to fail in the doFinal, not here
+            if (cipher.GetOutputSize(0) != 0)
+            {
+                Fail("fragile getOutputSize for initial 0 bytes decryption");
+            }
+
+            if (cipher.GetOutputSize(16) != 0)
+            {
+                Fail("incorrect getOutputSize for initial MAC-size bytes decryption");
+            }
+        }
+
+        private static int NextInt(SecureRandom rand, int n)
+        {
+            if ((n & -n) == n)  // i.e., n is a power of 2
+            {
+                return (int)(((uint)n * (ulong)((uint)rand.NextInt() >> 1)) >> 31);
+            }
+
+            int bits, value;
+            do
+            {
+                bits = (int)((uint)rand.NextInt() >> 1);
+                value = bits % n;
+            }
+            while (bits - value + (n - 1) < 0);
+
+            return value;
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new GcmTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/GMacTest.cs b/crypto/test/src/crypto/test/GMacTest.cs
new file mode 100644
index 000000000..383ff96b7
--- /dev/null
+++ b/crypto/test/src/crypto/test/GMacTest.cs
@@ -0,0 +1,187 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * Test vectors for AES-GMAC, extracted from <a
+     * href="http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip">NIST CAVP GCM test
+     * vectors</a>.
+     * 
+     */
+    [TestFixture]
+    public class GMacTest 
+        : SimpleTest
+    {
+        private class TestCase
+        {
+            private byte[] key;
+            private byte[] iv;
+            private byte[] ad;
+            private byte[] tag;
+            private string name;
+
+            internal TestCase(string name, string key, string iv, string ad, string tag)
+            {
+                this.name = name;
+                this.key = Hex.Decode(key);
+                this.iv = Hex.Decode(iv);
+                this.ad = Hex.Decode(ad);
+                this.tag = Hex.Decode(tag);
+            }
+
+            public string getName()
+            {
+                return name;
+            }
+
+            public byte[] getKey()
+            {
+                return key;
+            }
+
+            public byte[] getIv()
+            {
+                return iv;
+            }
+
+            public byte[] getAd()
+            {
+                return ad;
+            }
+
+            public byte[] getTag()
+            {
+                return tag;
+            }
+        }
+
+        private TestCase[] TEST_VECTORS = new TestCase[] {
+            // Count = 0, from each of the PTlen = 0 test vector sequences
+            new TestCase("128/96/0/128", "11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "",
+                         "250327c674aaf477aef2675748cf6971"),
+            new TestCase("128/96/0/120", "272f16edb81a7abbea887357a58c1917", "794ec588176c703d3d2a7a07", "",
+                         "b6e6f197168f5049aeda32dafbdaeb"),
+            new TestCase("128/96/0/112", "81b6844aab6a568c4556a2eb7eae752f", "ce600f59618315a6829bef4d", "",
+                         "89b43e9dbc1b4f597dbbc7655bb5"),
+            new TestCase("128/96/0/104", "cde2f9a9b1a004165ef9dc981f18651b", "29512c29566c7322e1e33e8e", "",
+                         "2e58ce7dabd107c82759c66a75"),
+            new TestCase("128/96/0/96", "b01e45cc3088aaba9fa43d81d481823f", "5a2c4a66468713456a4bd5e1", "",
+                         "014280f944f53c681164b2ff"),
+
+            new TestCase("128/96/128/128", "77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3",
+                         "7a43ec1d9c0a5a78a0b16533a6213cab", "209fcc8d3675ed938e9c7166709dd946"),
+            new TestCase("128/96/128/96", "bea48ae4980d27f357611014d4486625", "32bddb5c3aa998a08556454c",
+                         "8a50b0b8c7654bced884f7f3afda2ead", "8e0f6d8bf05ffebe6f500eb1"),
+
+            new TestCase("128/96/384/128", "99e3e8793e686e571d8285c564f75e2b", "c2dd0ab868da6aa8ad9c0d23",
+                         "b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc",
+                         "3f4fba100eaf1f34b0baadaae9995d85"),
+            new TestCase("128/96/384/96", "c77acd1b0918e87053cb3e51651e7013", "39ff857a81745d10f718ac00",
+                         "407992f82ea23b56875d9a3cb843ceb83fd27cb954f7c5534d58539fe96fb534502a1b38ea4fac134db0a42de4be1137",
+                         "2a5dc173285375dc82835876"),
+
+            new TestCase(
+                "128/1024/0/128",
+                "d0f1f4defa1e8c08b4b26d576392027c",
+                "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
+                "", "7ab49b57ddf5f62c427950111c5c4f0d"),
+            new TestCase(
+                "128/1024/384/96",
+                "3cce72d37933394a8cac8a82deada8f0",
+                "aa2f0d676d705d9733c434e481972d4888129cf7ea55c66511b9c0d25a92a174b1e28aa072f27d4de82302828955aadcb817c4907361869bd657b45ff4a6f323871987fcf9413b0702d46667380cd493ed24331a28b9ce5bbfa82d3a6e7679fcce81254ba64abcad14fd18b22c560a9d2c1cd1d3c42dac44c683edf92aced894",
+                "5686b458e9c176f4de8428d9ebd8e12f569d1c7595cf49a4b0654ab194409f86c0dd3fdb8eb18033bb4338c70f0b97d1",
+                "a3a9444b21f330c3df64c8b6"), };
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i < TEST_VECTORS.Length; i++)
+            {
+                TestCase testCase = TEST_VECTORS[i];
+
+                IMac mac = new GMac(new GcmBlockCipher(new AesFastEngine()), testCase.getTag().Length * 8);
+                ICipherParameters key = new KeyParameter(testCase.getKey());
+                mac.Init(new ParametersWithIV(key, testCase.getIv()));
+
+                testSingleByte(mac, testCase);
+                testMultibyte(mac, testCase);
+            }
+
+            // Invalid mac size
+            testInvalidMacSize(97);
+            testInvalidMacSize(136);
+            testInvalidMacSize(24);
+        }
+
+        private void testInvalidMacSize(int size)
+        {
+            try
+            {
+                GMac mac = new GMac(new GcmBlockCipher(new AesFastEngine()), size);
+                mac.Init(new ParametersWithIV(null, new byte[16]));
+                Fail("Expected failure for illegal mac size " + size);
+            }
+            catch (ArgumentException e)
+            {
+                if (!e.Message.StartsWith("Invalid value for MAC size"))
+                {
+                    Fail("Illegal mac size failed with unexpected message");
+                }
+            }
+        }
+
+        private void testMultibyte(IMac mac, TestCase testCase)
+        {
+            mac.BlockUpdate(testCase.getAd(), 0, testCase.getAd().Length);
+            checkMac(mac, testCase);
+        }
+
+        private void testSingleByte(IMac mac, TestCase testCase)
+        {
+            byte[] ad = testCase.getAd();
+            for (int i = 0; i < ad.Length; i++)
+            {
+                mac.Update(ad[i]);
+            }
+            checkMac(mac, testCase);
+        }
+
+        private void checkMac(IMac mac, TestCase testCase)
+        {
+            byte[] generatedMac = new byte[mac.GetMacSize()];
+            mac.DoFinal(generatedMac, 0);
+            if (!AreEqual(testCase.getTag(), generatedMac))
+            {
+                Fail("Failed " + testCase.getName() + " - expected " + Hex.ToHexString(testCase.getTag()) + " got "
+                     + Hex.ToHexString(generatedMac));
+            }
+        }
+
+        public override string Name
+        {
+            get { return "GMac"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new GMacTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/GOST28147MacTest.cs b/crypto/test/src/crypto/test/GOST28147MacTest.cs
new file mode 100644
index 000000000..5f3188f48
--- /dev/null
+++ b/crypto/test/src/crypto/test/GOST28147MacTest.cs
@@ -0,0 +1,105 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * GOST 28147 MAC tester
+	 */
+	[TestFixture]
+	public class Gost28147MacTest
+		:	ITest
+	{
+		//
+		// these GOSTMac for testing.
+		//
+		static byte[]   gkeyBytes1 = Hex.Decode("6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49");
+		static byte[]   gkeyBytes2 = Hex.Decode("6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49");
+
+		static byte[]   input3 = Hex.Decode("7768617420646f2079612077616e7420666f72206e6f7468696e673f");
+		static byte[]   input4 = Hex.Decode("7768617420646f2079612077616e7420666f72206e6f7468696e673f");
+
+		static byte[]   output7 = Hex.Decode("93468a46");
+		static byte[]   output8 = Hex.Decode("93468a46");
+
+		public Gost28147MacTest()
+		{
+		}
+
+		public ITestResult Perform()
+		{
+			// test1
+			IMac mac = new Gost28147Mac();
+			KeyParameter key = new KeyParameter(gkeyBytes1);
+
+			mac.Init(key);
+
+			mac.BlockUpdate(input3, 0, input3.Length);
+
+			byte[] outBytes = new byte[4];
+
+			mac.DoFinal(outBytes, 0);
+
+			if (!Arrays.AreEqual(outBytes, output7))
+			{
+				return new SimpleTestResult(false, Name + ": Failed test 1 - expected "
+					+ Hex.ToHexString(output7)
+					+ " got " + Hex.ToHexString(outBytes));
+			}
+
+			// test2
+			key = new KeyParameter(gkeyBytes2);
+
+			ParametersWithSBox gparam = new ParametersWithSBox(key, Gost28147Engine.GetSBox("E-A"));
+
+			mac.Init(gparam);
+
+			mac.BlockUpdate(input4, 0, input4.Length);
+
+			outBytes = new byte[4];
+
+			mac.DoFinal(outBytes, 0);
+
+			if (!Arrays.AreEqual(outBytes, output8))
+			{
+				return new SimpleTestResult(false, Name + ": Failed test 2 - expected "
+					+ Hex.ToHexString(output8)
+					+ " got " + Hex.ToHexString(outBytes));
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public string Name
+		{
+			get { return "Gost28147Mac"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new Gost28147MacTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/GOST28147Test.cs b/crypto/test/src/crypto/test/GOST28147Test.cs
new file mode 100644
index 000000000..5b6753517
--- /dev/null
+++ b/crypto/test/src/crypto/test/GOST28147Test.cs
@@ -0,0 +1,334 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class Gost28147Test
+		: CipherTest
+	{
+		static string input1 =  "0000000000000000";
+		static string output1 = "1b0bbc32cebcab42";
+		static string input2 =  "bc350e71aac5f5c2";
+		static string output2 = "d35ab653493b49f5";
+		static string input3 =  "bc350e71aa11345709acde";
+		static string output3 = "8824c124c4fd14301fb1e8";
+		static string input4 =  "000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f";
+		static string output4 = "29b7083e0a6d955ca0ec5b04fdb4ea41949f1dd2efdf17baffc1780b031f3934";
+
+		static byte[] TestSBox = {
+				0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,
+				0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0,
+				0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,
+				0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0,
+				0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,
+				0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0,
+				0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF,
+				0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0
+		};
+
+		static SimpleTest[] tests =
+		{   new BlockCipherVectorTest(1, new Gost28147Engine(),
+				new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")),
+					input1, output1),
+			new BlockCipherVectorTest(2, new CbcBlockCipher(new Gost28147Engine()),
+				new ParametersWithIV(new KeyParameter(Hex.Decode("00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF")),
+				Hex.Decode("1234567890abcdef")), input2, output2),
+			new BlockCipherVectorTest(3, new GOfbBlockCipher(new Gost28147Engine()),
+				new ParametersWithIV(new KeyParameter(Hex.Decode("0011223344556677889900112233445566778899001122334455667788990011")),
+				Hex.Decode("1234567890abcdef")), //IV
+				input3, output3),
+			new BlockCipherVectorTest(4, new CfbBlockCipher(new Gost28147Engine(), 64),
+				new ParametersWithIV(new KeyParameter(Hex.Decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5")),
+				Hex.Decode("aafd12f659cae634")), input4, output4),
+
+			//tests with parameters, set S-box.
+			new BlockCipherVectorTest(5, new Gost28147Engine(),
+				new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")),//key , default parameter S-box set to D-Test
+				input1, output1),
+			new BlockCipherVectorTest(6, new CfbBlockCipher(new Gost28147Engine(), 64),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						Gost28147Engine.GetSBox("D-Test")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"b587f7a0814c911d"), //encrypt message
+			new BlockCipherVectorTest(7, new CfbBlockCipher(new Gost28147Engine(), 64),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						Gost28147Engine.GetSBox("E-Test")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"e8287f53f991d52b"), //encrypt message
+			new BlockCipherVectorTest(8, new CfbBlockCipher(new Gost28147Engine(), 64),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						Gost28147Engine.GetSBox("E-A")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"c41009dba22ebe35"), //encrypt message
+			new BlockCipherVectorTest(9, new CfbBlockCipher(new Gost28147Engine(), 8),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						Gost28147Engine.GetSBox("E-B")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"80d8723fcd3aba28"), //encrypt message
+			new BlockCipherVectorTest(10, new CfbBlockCipher(new Gost28147Engine(), 8),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						Gost28147Engine.GetSBox("E-C")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"739f6f95068499b5"), //encrypt message
+			new BlockCipherVectorTest(11, new CfbBlockCipher(new Gost28147Engine(), 8),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						Gost28147Engine.GetSBox("E-D")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"4663f720f4340f57"), //encrypt message
+			new BlockCipherVectorTest(12, new CfbBlockCipher(new Gost28147Engine(), 8),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						Gost28147Engine.GetSBox("D-A")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"5bb0a31d218ed564"), //encrypt message
+			new BlockCipherVectorTest(13, new CfbBlockCipher(new Gost28147Engine(), 8),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+						new KeyParameter(Hex.Decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key
+						TestSBox), //set own S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"0000000000000000", //input message
+					"c3af96ef788667c5"), //encrypt message
+			new BlockCipherVectorTest(14, new GOfbBlockCipher(new Gost28147Engine()),
+				new ParametersWithIV(
+					new ParametersWithSBox(
+							new KeyParameter(Hex.Decode("4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d")), //key
+							Gost28147Engine.GetSBox("E-A")), //type S-box
+					Hex.Decode("1234567890abcdef")), //IV
+					"bc350e71aa11345709acde",  //input message
+					"1bcc2282707c676fb656dc"), //encrypt message
+
+		};
+
+		private const int Gost28147_KEY_LENGTH = 32;
+
+		private byte[] generateKey(byte[] startkey)
+		{
+			byte[] newKey = new byte[Gost28147_KEY_LENGTH];
+
+			Gost3411Digest digest = new Gost3411Digest();
+
+			digest.BlockUpdate(startkey, 0, startkey.Length);
+			digest.DoFinal(newKey, 0);
+
+			return newKey;
+		}
+
+		public Gost28147Test()
+			: base(tests, new Gost28147Engine(), new KeyParameter(new byte[32]))
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			//advanced tests with Gost28147KeyGenerator:
+			//encrypt on hesh message; ECB mode:
+			byte[] inBytes = Hex.Decode("4e6f77206973207468652074696d6520666f7220616c6c20");
+			byte[] output = Hex.Decode("8ad3c8f56b27ff1fbd46409359bdc796bc350e71aac5f5c0");
+			byte[] outBytes = new byte[inBytes.Length];
+
+			byte[] key = generateKey(Hex.Decode("0123456789abcdef"));  //!!! heshing start_key - get 256 bits !!!
+	//        System.out.println(new string(Hex.Encode(key)));
+			ICipherParameters  param = new ParametersWithSBox(new KeyParameter(key), Gost28147Engine.GetSBox("E-A"));
+			//CipherParameters  param = new Gost28147Parameters(key,"D-Test");
+			BufferedBlockCipher cipher = new BufferedBlockCipher(new Gost28147Engine());
+
+			cipher.Init(true, param);
+			int len1 = cipher.ProcessBytes(inBytes, 0, inBytes.Length, outBytes, 0);
+			try
+			{
+				cipher.DoFinal(outBytes, len1);
+			}
+			catch (CryptoException e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (outBytes.Length != output.Length)
+			{
+				Fail("failed - "
+					+ "expected " + Hex.ToHexString(output) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+			for (int i = 0; i != outBytes.Length; i++)
+			{
+				if (outBytes[i] != output[i])
+				{
+					Fail("failed - "
+						+ "expected " + Hex.ToHexString(output)
+						+ " got " + Hex.ToHexString(outBytes));
+				}
+			}
+
+
+			//encrypt on hesh message; CFB mode:
+			inBytes = Hex.Decode("bc350e71aac5f5c2");
+			output = Hex.Decode("0ebbbafcf38f14a5");
+			outBytes = new byte[inBytes.Length];
+
+			key = generateKey(Hex.Decode("0123456789abcdef"));  //!!! heshing start_key - get 256 bits !!!
+			param = new ParametersWithIV(
+				new ParametersWithSBox(
+					new KeyParameter(key), //key
+					Gost28147Engine.GetSBox("E-A")), //type S-box
+				Hex.Decode("1234567890abcdef")); //IV
+
+			cipher = new BufferedBlockCipher(new CfbBlockCipher(new Gost28147Engine(), 64));
+
+			cipher.Init(true, param);
+			len1 = cipher.ProcessBytes(inBytes, 0, inBytes.Length, outBytes, 0);
+			try
+			{
+				cipher.DoFinal(outBytes, len1);
+			}
+			catch (CryptoException e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+			if (outBytes.Length != output.Length)
+			{
+				Fail("failed - "
+					+ "expected " + Hex.ToHexString(output)
+					+ " got " + Hex.ToHexString(outBytes));
+			}
+			for (int i = 0; i != outBytes.Length; i++)
+			{
+				if (outBytes[i] != output[i])
+				{
+					Fail("failed - "
+						+ "expected " + Hex.ToHexString(output)
+						+ " got " + Hex.ToHexString(outBytes));
+				}
+			}
+
+
+			//encrypt on hesh message; CFB mode:
+			inBytes = Hex.Decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f");
+			output = Hex.Decode("64988982819f0a1655e226e19ecad79d10cc73bac95c5d7da034786c12294225");
+			outBytes = new byte[inBytes.Length];
+
+			key = generateKey(Hex.Decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5"));  //!!! heshing start_key - get 256 bits !!!
+			param = new ParametersWithIV(
+				new ParametersWithSBox(
+					new KeyParameter(key), //key
+					Gost28147Engine.GetSBox("E-A")), //type S-box
+				Hex.Decode("aafd12f659cae634")); //IV
+
+			cipher = new BufferedBlockCipher(new CfbBlockCipher(new Gost28147Engine(), 64));
+
+			cipher.Init(true, param);
+			len1 = cipher.ProcessBytes(inBytes, 0, inBytes.Length, outBytes, 0);
+
+			cipher.DoFinal(outBytes, len1);
+
+			if (outBytes.Length != output.Length)
+			{
+				Fail("failed - "
+					+ "expected " + Hex.ToHexString(output)
+					+ " got " + Hex.ToHexString(outBytes));
+			}
+
+			for (int i = 0; i != outBytes.Length; i++)
+			{
+				if (outBytes[i] != output[i])
+				{
+					Fail("failed - "
+						+ "expected " + Hex.ToHexString(output)
+						+ " got " + Hex.ToHexString(outBytes));
+				}
+			}
+
+			//encrypt on hesh message; OFB mode:
+			inBytes = Hex.Decode("bc350e71aa11345709acde");
+			output = Hex.Decode("1bcc2282707c676fb656dc");
+			outBytes = new byte[inBytes.Length];
+
+			key = generateKey(Hex.Decode("0123456789abcdef"));  //!!! heshing start_key - get 256 bits !!!
+			param = new ParametersWithIV(
+				new ParametersWithSBox(
+					new KeyParameter(key), //key
+					Gost28147Engine.GetSBox("E-A")), //type S-box
+				Hex.Decode("1234567890abcdef")); //IV
+
+			cipher = new BufferedBlockCipher(new GOfbBlockCipher(new Gost28147Engine()));
+
+			cipher.Init(true, param);
+			len1 = cipher.ProcessBytes(inBytes, 0, inBytes.Length, outBytes, 0);
+
+			cipher.DoFinal(outBytes, len1);
+
+			if (outBytes.Length != output.Length)
+			{
+				Fail("failed - "
+					+ "expected " + Hex.ToHexString(output)
+					+ " got " + Hex.ToHexString(outBytes));
+			}
+
+			for (int i = 0; i != outBytes.Length; i++)
+			{
+				if (outBytes[i] != output[i])
+				{
+					Fail("failed - "
+						+ "expected " + Hex.ToHexString(output)
+						+ " got " + Hex.ToHexString(outBytes));
+				}
+			}
+		}
+
+		public override string Name
+		{
+			get { return "Gost28147"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new Gost28147Test();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/GOST3410Test.cs b/crypto/test/src/crypto/test/GOST3410Test.cs
new file mode 100644
index 000000000..f54662770
--- /dev/null
+++ b/crypto/test/src/crypto/test/GOST3410Test.cs
@@ -0,0 +1,1604 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class Gost3410Test
+		: ITest
+	{
+		private static readonly byte[] hashmessage = Hex.Decode("3042453136414534424341374533364339313734453431443642453241453435");
+
+		private static byte[] zeroTwo(int length)
+		{
+			byte[] data = new byte[length];
+			data[data.Length - 1] = 0x02;
+			return data;
+		}
+
+		private class Gost3410_TEST1_512
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-TEST1-512"; }
+			}
+
+			FixedSecureRandom init_random = FixedSecureRandom.From(Hex.Decode("00005EC900007341"), zeroTwo(64));
+			FixedSecureRandom random = FixedSecureRandom.From(Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"));
+			FixedSecureRandom keyRandom = FixedSecureRandom.From(Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046"));
+
+			BigInteger pValue = new BigInteger("EE8172AE8996608FB69359B89EB82A69854510E2977A4D63BC97322CE5DC3386EA0A12B343E9190F23177539845839786BB0C345D165976EF2195EC9B1C379E3", 16);
+			BigInteger qValue = new BigInteger("98915E7EC8265EDFCDA31E88F24809DDB064BDC7285DD50D7289F0AC6F49DD2D", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("3e5f895e276d81d2d52c0763270a458157b784c57abdbd807bc44fd43a32ac06",16);
+				BigInteger s = new BigInteger("3f0dd5d4400d47c08e4ce505ff7434b6dbf729592e37c74856dab85115a60955",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(512, 1, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (parameters.ValidationParameters == null)
+				{
+					return new SimpleTestResult(false, Name + "validation parameters wrong");
+				}
+
+				if (parameters.ValidationParameters.C != 29505
+					||  parameters.ValidationParameters.X0 != 24265)
+				{
+					return new SimpleTestResult(false, Name + "validation parameters values wrong");
+				}
+
+				if (!init_random.IsExhausted)
+				{
+					return new SimpleTestResult(false, Name
+						+ ": unexpected number of bytes used from 'init_random'.");
+				}
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator         Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters  genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair  pair = Gost3410KeyGen.GenerateKeyPair();
+
+				if (!keyRandom.IsExhausted)
+				{
+					return new SimpleTestResult(false, Name
+						+ ": unexpected number of bytes used from 'keyRandom'.");
+				}
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer gost3410 = new Gost3410Signer();
+
+				gost3410.Init(true, param);
+
+				BigInteger[] sig = gost3410.GenerateSignature(hashmessage);
+
+				if (!random.IsExhausted)
+				{
+					return new SimpleTestResult(false, Name
+						+ ": unexpected number of bytes used from 'random'.");
+				}
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				gost3410.Init(false, pair.Public);
+
+				if (gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_TEST2_512
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-TEST2-512"; }
+			}
+
+			FixedSecureRandom init_random = FixedSecureRandom.From(Hex.Decode("000000003DFC46F1000000000000000D"), zeroTwo(64));
+			FixedSecureRandom random = FixedSecureRandom.From(Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"));
+			FixedSecureRandom keyRandom = FixedSecureRandom.From(Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046"));
+
+			BigInteger pValue = new BigInteger("8b08eb135af966aab39df294538580c7da26765d6d38d30cf1c06aae0d1228c3316a0e29198460fad2b19dc381c15c888c6dfd0fc2c565abb0bf1faff9518f85", 16);
+			BigInteger qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("7c07c8cf035c2a1cb2b7fae5807ac7cd623dfca7a1a68f6d858317822f1ea00d",16);
+				BigInteger s = new BigInteger("7e9e036a6ff87dbf9b004818252b1f6fc310bdd4d17cb8c37d9c36c7884de60c",16);
+				Gost3410ParametersGenerator  pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(512, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!init_random.IsExhausted)
+				{
+					return new SimpleTestResult(false, Name
+						+ ": unexpected number of bytes used from 'init_random'.");
+				}
+
+				if (parameters.ValidationParameters == null)
+				{
+					return new SimpleTestResult(false, Name + ": validation parameters wrong");
+				}
+
+				if (parameters.ValidationParameters.CL != 13
+					||  parameters.ValidationParameters.X0L != 1039943409)
+				{
+					return new SimpleTestResult(false, Name + ": validation parameters values wrong");
+				}
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				if (!keyRandom.IsExhausted)
+				{
+					return new SimpleTestResult(false, Name
+						+ ": unexpected number of bytes used from 'keyRandom'.");
+				}
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!random.IsExhausted)
+				{
+					return new SimpleTestResult(false, Name
+						+ ": unexpected number of bytes used from 'random'.");
+				}
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (!Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+		}
+
+		private class Gost3410_TEST1_1024
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-TEST1-1024"; }
+			}
+
+			private class SecureRandomImpl1 : SecureRandom
+			{
+				bool firstInt = true;
+
+				public override int NextInt()
+				{
+					string x0 = "0xA565";
+					string c =  "0x538B";
+
+					if (firstInt)
+					{
+						firstInt = false;
+						return NumberParsing.DecodeIntFromHex(x0);
+					}
+					return NumberParsing.DecodeIntFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+
+					byte[] d = Hex.Decode("02");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl1();
+
+			private class SecureRandomImpl2 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl2();
+
+			private class SecureRandomImpl3 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl3();
+
+			BigInteger  pValue = new BigInteger("ab8f37938356529e871514c1f48c5cbce77b2f4fc9a2673ac2c1653da8984090c0ac73775159a26bef59909d4c9846631270e16653a6234668f2a52a01a39b921490e694c0f104b58d2e14970fccb478f98d01e975a1028b9536d912de5236d2dd2fc396b77153594d4178780e5f16f718471e2111c8ce64a7d7e196fa57142d", 16);
+			BigInteger  qValue = new BigInteger("bcc02ca0ce4f0753ec16105ee5d530aa00d39f3171842ab2c334a26b5f576e0f", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("a8790aabbd5a998ff524bad048ac69cd1faff2dab048265c8d60d1471c44a9ee",16);
+				BigInteger s = new BigInteger("30df5ba32ac77170b9632559bef7d37620017756dff3fea1088b4267db0944b8",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 1, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_TEST2_1024
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-TEST2-1024"; }
+			}
+
+			private class SecureRandomImpl4 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0x3DFC46F1";
+					string c =  "0xD";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+
+					byte[] d = Hex.Decode("02");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl4();
+
+			private class SecureRandomImpl5 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl5();
+
+			private class SecureRandomImpl6 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl6();
+
+			BigInteger  pValue = new BigInteger("e2c4191c4b5f222f9ac2732562f6d9b4f18e7fb67a290ea1e03d750f0b9806755fc730d975bf3faa606d05c218b35a6c3706919aab92e0c58b1de4531c8fa8e7af43c2bff016251e21b2870897f6a27ac4450bca235a5b748ad386e4a0e4dfcb09152435abcfe48bd0b126a8122c7382f285a9864615c66decddf6afd355dfb7", 16);
+			BigInteger  qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger              r = new BigInteger("81d69a192e9c7ac21fc07da41bd07e230ba6a94eb9f3c1fd104c7bd976733ca5",16);
+				BigInteger              s = new BigInteger("315c879c8414f35feb4deb15e7cc0278c48e6ca1596325d6959338d860b0c47a",16);
+				Gost3410ParametersGenerator  pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters           parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator         Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters  genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair  pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_AParam
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-AParam"; }
+			}
+
+			private class SecureRandomImpl7 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0x520874F5";
+					string c =  "0xEE39ADB3";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+
+					byte[] d = Hex.Decode("02");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl7();
+
+			private class SecureRandomImpl8 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl8();
+
+			private class SecureRandomImpl9 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl9();
+
+			BigInteger  pValue = new BigInteger("b4e25efb018e3c8b87505e2a67553c5edc56c2914b7e4f89d23f03f03377e70a2903489dd60e78418d3d851edb5317c4871e40b04228c3b7902963c4b7d85d52b9aa88f2afdbeb28da8869d6df846a1d98924e925561bd69300b9ddd05d247b5922d967cbb02671881c57d10e5ef72d3e6dad4223dc82aa1f7d0294651a480df", 16);
+			BigInteger  qValue = new BigInteger("972432a437178b30bd96195b773789ab2fff15594b176dd175b63256ee5af2cf", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("64a8856628e5669d85f62cd763dd4a99bc56d33dc0e1859122855d141e9e4774",16);
+				BigInteger s = new BigInteger("319ebac97092b288d469a4b988248794f60c865bc97858d9a3135c6d1a1bf2dd",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_BParam
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-BParam"; }
+			}
+
+			private class SecureRandomImpl10 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0x5B977CDB";
+					string c =  "0x6E9692DD";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] d = Hex.Decode("bc3cbbdb7e6f848286e19ad9a27a8e297e5b71c53dd974cdf60f937356df69cbc97a300ccc71685c553046147f11568c4fddf363d9d886438345a62c3b75963d6546adfabf31b31290d12cae65ecb8309ef66782");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl10();
+
+			private class SecureRandomImpl11 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl11();
+
+			private class SecureRandomImpl12 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl12();
+
+			BigInteger  pValue = new BigInteger("c6971fc57524b30c9018c5e621de15499736854f56a6f8aee65a7a404632b3540f09020f67f04dc2e6783b141dceffd21a703035b7d0187c6e12cb4229922bafdb2225b73e6b23a0de36e20047065aea000c1a374283d0ad8dc1981e3995f0bb8c72526041fcb98ae6163e1e71a669d8364e9c4c3188f673c5f8ee6fadb41abf", 16);
+			BigInteger  qValue = new BigInteger("b09d634c10899cd7d4c3a7657403e05810b07c61a688bab2c37f475e308b0607", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("860d82c60e9502cd00c0e9e1f6563feafec304801974d745c5e02079946f729e",16);
+				BigInteger s = new BigInteger("7ef49264ef022801aaa03033cd97915235fbab4c823ed936b0f360c22114688a",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_CParam
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-CParam"; }
+			}
+
+			private class SecureRandomImpl13 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0x43848744";
+					string c =  "0xB50A826D";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] d = Hex.Decode("7F575E8194BC5BDF");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl13();
+
+			private class SecureRandomImpl14 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl14();
+
+			private class SecureRandomImpl15 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl15();
+
+			BigInteger  pValue = new BigInteger("9d88e6d7fe3313bd2e745c7cdd2ab9ee4af3c8899e847de74a33783ea68bc30588ba1f738c6aaf8ab350531f1854c3837cc3c860ffd7e2e106c3f63b3d8a4c034ce73942a6c3d585b599cf695ed7a3c4a93b2b947b7157bb1a1c043ab41ec8566c6145e938a611906de0d32e562494569d7e999a0dda5c879bdd91fe124df1e9", 16);
+			BigInteger  qValue = new BigInteger("fadd197abd19a1b4653eecf7eca4d6a22b1f7f893b641f901641fbb555354faf", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("4deb95a0b35e7ed7edebe9bef5a0f93739e16b7ff27fe794d989d0c13159cfbc",16);
+				BigInteger s = new BigInteger("e1d0d30345c24cfeb33efde3deee5fbbda78ddc822b719d860cd0ba1fb6bd43b",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_DParam
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-DParam"; }
+			}
+
+			private class SecureRandomImpl16 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0x13DA8B9D";
+					string c =  "0xA0E9DE4B";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+
+					byte[] d = Hex.Decode("41ab97857f42614355d32db0b1069f109a4da283676c7c53a68185b4");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl16();
+
+			private class SecureRandomImpl17 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl17();
+
+			private class SecureRandomImpl18 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl18();
+
+			BigInteger  pValue = new BigInteger("80f102d32b0fd167d069c27a307adad2c466091904dbaa55d5b8cc7026f2f7a1919b890cb652c40e054e1e9306735b43d7b279eddf9102001cd9e1a831fe8a163eed89ab07cf2abe8242ac9dedddbf98d62cddd1ea4f5f15d3a42a6677bdd293b24260c0f27c0f1d15948614d567b66fa902baa11a69ae3bceadbb83e399c9b5", 16);
+			BigInteger  qValue = new BigInteger("f0f544c418aac234f683f033511b65c21651a6078bda2d69bb9f732867502149", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger              r = new BigInteger("712592d285b792e33b8a9a11e8e6c4f512ddf0042972bbfd1abb0a93e8fc6f54",16);
+				BigInteger              s = new BigInteger("2cf26758321258b130d5612111339f09ceb8668241f3482e38baa56529963f07",16);
+				Gost3410ParametersGenerator  pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_AExParam
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-AExParam"; }
+			}
+
+			private class SecureRandomImpl19 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0xD05E9F14";
+					string c =  "0x46304C5F";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] d = Hex.Decode("35ab875399cda33c146ca629660e5a5e5c07714ca326db032dd6751995cdb90a612b9228932d8302704ec24a5def7739c5813d83");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl19();
+
+			private class SecureRandomImpl20 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl20();
+
+			private class SecureRandomImpl21 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl21();
+
+			BigInteger  pValue = new BigInteger("ca3b3f2eee9fd46317d49595a9e7518e6c63d8f4eb4d22d10d28af0b8839f079f8289e603b03530784b9bb5a1e76859e4850c670c7b71c0df84ca3e0d6c177fe9f78a9d8433230a883cd82a2b2b5c7a3306980278570cdb79bf01074a69c9623348824b0c53791d53c6a78cab69e1cfb28368611a397f50f541e16db348dbe5f", 16);
+			BigInteger  qValue = new BigInteger("cae4d85f80c147704b0ca48e85fb00a9057aa4acc44668e17f1996d7152690d9", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("90892707282f433398488f19d31ac48523a8e2ded68944e0da91c6895ee7045e",16);
+				BigInteger s = new BigInteger("3be4620ee88f1ee8f9dd63c7d145b7e554839feeca125049118262ea4651e9de",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_BExParam
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-BExParam"; }
+			}
+
+			private class SecureRandomImpl22 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0x7A007804";
+					string c =  "0xD31A4FF7";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] d = Hex.Decode("7ec123d161477762838c2bea9dbdf33074af6d41d108a066a1e7a07ab3048de2");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl22();
+
+			private class SecureRandomImpl23 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl23();
+
+			private class SecureRandomImpl24 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl24();
+
+			BigInteger  pValue = new BigInteger("9286dbda91eccfc3060aa5598318e2a639f5ba90a4ca656157b2673fb191cd0589ee05f4cef1bd13508408271458c30851ce7a4ef534742bfb11f4743c8f787b11193ba304c0e6bca25701bf88af1cb9b8fd4711d89f88e32b37d95316541bf1e5dbb4989b3df13659b88c0f97a3c1087b9f2d5317d557dcd4afc6d0a754e279", 16);
+			BigInteger  qValue = new BigInteger("c966e9b3b8b7cdd82ff0f83af87036c38f42238ec50a876cd390e43d67b6013f", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("8f79a582513df84dc247bcb624340cc0e5a34c4324a20ce7fe3ab8ff38a9db71",16);
+				BigInteger s = new BigInteger("7508d22fd6cbb45efd438cb875e43f137247088d0f54b29a7c91f68a65b5fa85",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		private class Gost3410_CExParam
+			: ITest
+		{
+			public string Name
+			{
+				get { return "Gost3410-CExParam"; }
+			}
+
+			private class SecureRandomImpl25 : SecureRandom
+			{
+				bool firstLong = true;
+
+				public override long NextLong()
+				{
+					string x0 = "0x162AB910";
+					string c =  "0x93F828D3";
+
+					if (firstLong)
+					{
+						firstLong = false;
+						return NumberParsing.DecodeLongFromHex(x0);
+					}
+					return NumberParsing.DecodeLongFromHex(c);
+				}
+
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] d = Hex.Decode("ca82cce78a738bc46f103d53b9bf809745ec845e4f6da462606c51f60ecf302e31204b81");
+
+					Array.Copy(d, 0, bytes, bytes.Length-d.Length, d.Length);
+				}
+			};
+			SecureRandom init_random = new SecureRandomImpl25();
+
+			private class SecureRandomImpl26 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] k = Hex.Decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - k.Length); i += k.Length)
+					{
+						Array.Copy(k, 0, bytes, i, k.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(k, 0, bytes, i - k.Length, bytes.Length - (i - k.Length));
+					}
+					else
+					{
+						Array.Copy(k, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom random = new SecureRandomImpl26();
+
+			private class SecureRandomImpl27 : SecureRandom
+			{
+				public override void NextBytes(byte[] bytes)
+				{
+					byte[] x = Hex.Decode("3036314538303830343630454235324435324234314132373832433138443046");
+
+					int i;
+
+					for (i = 0; i < (bytes.Length - x.Length); i += x.Length)
+					{
+						Array.Copy(x, 0, bytes, i, x.Length);
+					}
+
+					if (i > bytes.Length)
+					{
+						Array.Copy(x, 0, bytes, i - x.Length, bytes.Length - (i - x.Length));
+					}
+					else
+					{
+						Array.Copy(x, 0, bytes, i, bytes.Length - i);
+					}
+				}
+			};
+			SecureRandom keyRandom = new SecureRandomImpl27();
+
+			BigInteger  pValue = new BigInteger("b194036ace14139d36d64295ae6c50fc4b7d65d8b340711366ca93f383653908ee637be428051d86612670ad7b402c09b820fa77d9da29c8111a8496da6c261a53ed252e4d8a69a20376e6addb3bdcd331749a491a184b8fda6d84c31cf05f9119b5ed35246ea4562d85928ba1136a8d0e5a7e5c764ba8902029a1336c631a1d", 16);
+			BigInteger  qValue = new BigInteger("96120477df0f3896628e6f4a88d83c93204c210ff262bccb7dae450355125259", 16);
+
+			public ITestResult Perform()
+			{
+				BigInteger r = new BigInteger("169fdb2dc09f690b71332432bfec806042e258fa9a21dafe73c6abfbc71407d9",16);
+				BigInteger s = new BigInteger("9002551808ae40d19f6f31fb67e4563101243cf07cffd5f2f8ff4c537b0c9866",16);
+				Gost3410ParametersGenerator pGen = new Gost3410ParametersGenerator();
+
+				pGen.Init(1024, 2, init_random);
+
+				Gost3410Parameters parameters = pGen.GenerateParameters();
+
+				if (!pValue.Equals(parameters.P) || !qValue.Equals(parameters.Q))
+				{
+					return new SimpleTestResult(false, Name + ": p or q wrong");
+				}
+
+				Gost3410KeyPairGenerator Gost3410KeyGen = new Gost3410KeyPairGenerator();
+				Gost3410KeyGenerationParameters genParam = new Gost3410KeyGenerationParameters(keyRandom, parameters);
+
+				Gost3410KeyGen.Init(genParam);
+
+				AsymmetricCipherKeyPair pair = Gost3410KeyGen.GenerateKeyPair();
+
+				ParametersWithRandom param = new ParametersWithRandom(pair.Private, random);
+
+				Gost3410Signer Gost3410 = new Gost3410Signer();
+
+				Gost3410.Init(true, param);
+
+				BigInteger[] sig = Gost3410.GenerateSignature(hashmessage);
+
+				if (!r.Equals(sig[0]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": r component wrong." + SimpleTest.NewLine
+						+ " expecting: " + r.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[0].ToString(16));
+				}
+
+				if (!s.Equals(sig[1]))
+				{
+					return new SimpleTestResult(false, Name
+						+ ": s component wrong." + SimpleTest.NewLine
+						+ " expecting: " + s.ToString(16) + SimpleTest.NewLine
+						+ " got      : " + sig[1].ToString(16));
+				}
+
+				Gost3410.Init(false, pair.Public);
+
+				if (Gost3410.VerifySignature(hashmessage, sig[0], sig[1]))
+				{
+					return new SimpleTestResult(true, Name + ": Okay");
+				}
+				else
+				{
+					return new SimpleTestResult(false, Name + ": verification fails");
+				}
+			}
+		}
+
+		ITest[] tests =
+		{
+			new Gost3410_TEST1_512(),
+			new Gost3410_TEST2_512(),
+//	        new Gost3410_TEST1_1024(),
+//	        new Gost3410_TEST2_1024(),
+//	        new Gost3410_AParam(),
+//	        new Gost3410_BParam(),
+//	        new Gost3410_CParam(),
+//	        new Gost3410_DParam(),
+//	        new Gost3410_AExParam(),
+//	        new Gost3410_BExParam(),
+//	        new Gost3410_CExParam()
+		};
+
+		public string Name
+		{
+			get { return "Gost3410"; }
+		}
+
+		public ITestResult Perform()
+		{
+			for (int i = 0; i != tests.Length; i++)
+			{
+				ITestResult result = tests[i].Perform();
+
+				if (!result.IsSuccessful())
+				{
+					return result;
+				}
+			}
+
+			return new SimpleTestResult(true, "Gost3410: Okay");
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new Gost3410Test();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/GOST3411DigestTest.cs b/crypto/test/src/crypto/test/GOST3411DigestTest.cs
new file mode 100644
index 000000000..1826b28c9
--- /dev/null
+++ b/crypto/test/src/crypto/test/GOST3411DigestTest.cs
@@ -0,0 +1,79 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class Gost3411DigestTest
+		: DigestTest
+	{
+		private static readonly string[] messages =
+		{
+			"",
+			"This is message, length=32 bytes",
+			"Suppose the original message has length = 50 bytes",
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+		};
+
+		//  If S-box = D-A (see: digest/Gost3411Digest.java; function: E(byte[] in, byte[] key); string: CipherParameters  param = new Gost28147Parameters(key,"D-A");)
+		private static readonly string[] digests =
+		{
+			"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0",
+			"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb",
+			"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011",
+			"73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61"
+		};
+
+		//  If S-box = D-Test (see: digest/GOST3411Digest.cs; function:E(byte[] in, byte[] key); string: ICipherParameters p = new Gost28147Parameters(key, "D-Test");)
+//		private static readonly string[] digests =
+//		{
+//			"ce85b99cc46752fffee35cab9a7b0278abb4c2d2055cff685af4912c49490f8d",
+//			"b1c466d37519b82e8319819ff32595e047a28cb6f83eff1c6916a815a637fffa",
+//			"471aba57a60a770d3a76130635c1fbea4ef14de51f78b4ae57dd893b62f55208",
+//			"95c1af627c356496d80274330b2cff6a10c67b5f597087202f94d06d2338cf8e"
+//		};
+
+		// 1 million 'a'
+		static private string  million_a_digest = "8693287aa62f9478f7cb312ec0866b6c4e4a0f11160441e8f4ffcd2715dd554f";
+
+		public Gost3411DigestTest()
+			: base(new Gost3411Digest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			millionATest(million_a_digest);
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new Gost3411Digest((Gost3411Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new Gost3411DigestTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/GcmReorderTest.cs b/crypto/test/src/crypto/test/GcmReorderTest.cs
new file mode 100644
index 000000000..54d17f4f4
--- /dev/null
+++ b/crypto/test/src/crypto/test/GcmReorderTest.cs
@@ -0,0 +1,362 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Modes.Gcm;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class GcmReorderTest
+	{
+		private static readonly byte[] H;
+		private static readonly SecureRandom random = new SecureRandom(); 
+		private static readonly IGcmMultiplier mul = new Tables64kGcmMultiplier();
+		private static readonly IGcmExponentiator exp = new Tables1kGcmExponentiator();
+		private static readonly byte[] Empty = new byte[0];
+
+		static GcmReorderTest()
+		{
+			H = new byte[16];
+			random.NextBytes(H);
+			mul.Init(Arrays.Clone(H));
+			exp.Init(Arrays.Clone(H));
+		}
+
+		[Test]
+		public void TestCombine()
+		{
+			for (int count = 0; count < 10; ++count)
+			{
+				byte[] A = randomBytes(1000);
+				byte[] C = randomBytes(1000);
+
+				byte[] ghashA_ = GHASH(A, Empty);
+				byte[] ghash_C = GHASH(Empty, C);
+				byte[] ghashAC = GHASH(A, C);
+
+				byte[] ghashCombine = combine_GHASH(ghashA_, (long)A.Length * 8, ghash_C, (long)C.Length * 8);
+
+				Assert.IsTrue(Arrays.AreEqual(ghashAC, ghashCombine));
+			}
+		}
+
+		[Test]
+		public void TestConcatAuth()
+		{
+			for (int count = 0; count < 10; ++count)
+			{
+				byte[] P = randomBlocks(100);
+				byte[] A = randomBytes(1000);
+				byte[] PA = concatArrays(P, A);
+
+				byte[] ghashP_ = GHASH(P, Empty);
+				byte[] ghashA_ = GHASH(A, Empty);
+				byte[] ghashPA_val = GHASH(PA, Empty);
+				byte[] ghashConcat = concatAuth_GHASH(ghashP_, (long)P.Length * 8, ghashA_, (long)A.Length * 8);
+
+				Assert.IsTrue(Arrays.AreEqual(ghashPA_val, ghashConcat));
+			}
+		}
+
+		[Test]
+		public void TestConcatCrypt()
+		{
+			for (int count = 0; count < 10; ++count)
+			{
+				byte[] P = randomBlocks(100);
+				byte[] A = randomBytes(1000);
+				byte[] PA = concatArrays(P, A);
+
+				byte[] ghash_P = GHASH(Empty, P);
+				byte[] ghash_A = GHASH(Empty, A);
+				byte[] ghash_PA = GHASH(Empty, PA);
+				byte[] ghashConcat = concatCrypt_GHASH(ghash_P, (long)P.Length * 8, ghash_A, (long)A.Length * 8);
+
+				Assert.IsTrue(Arrays.AreEqual(ghash_PA, ghashConcat));
+			}
+		}
+
+		[Test]
+		public void TestExp()
+		{
+			{
+				byte[] buf1 = new byte[16];
+				buf1[0] = 0x80;
+
+				byte[] buf2 = new byte[16];
+
+				for (int pow = 0; pow != 100; ++pow)
+				{
+					exp.ExponentiateX(pow, buf2);
+
+					Assert.IsTrue(Arrays.AreEqual(buf1, buf2));
+
+					mul.MultiplyH(buf1);
+				}
+			}
+
+			long[] testPow = new long[]{ 10, 1, 8, 17, 24, 13, 2, 13, 2, 3 };
+			byte[][] testData = new byte[][]{
+				Hex.Decode("9185848a877bd87ba071e281f476e8e7"),
+				Hex.Decode("697ce3052137d80745d524474fb6b290"),
+				Hex.Decode("2696fc47198bb23b11296e4f88720a17"),
+				Hex.Decode("01f2f0ead011a4ae0cf3572f1b76dd8e"),
+				Hex.Decode("a53060694a044e4b7fa1e661c5a7bb6b"),
+				Hex.Decode("39c0392e8b6b0e04a7565c85394c2c4c"),
+				Hex.Decode("519c362d502e07f2d8b7597a359a5214"),
+				Hex.Decode("5a527a393675705e19b2117f67695af4"),
+				Hex.Decode("27fc0901d1d332a53ba4d4386c2109d2"),
+				Hex.Decode("93ca9b57174aabedf8220e83366d7df6"),
+			};
+
+			for (int i = 0; i != 10; ++i)
+			{
+				long pow = testPow[i];
+				byte[] data = Arrays.Clone(testData[i]);
+
+				byte[] expected = Arrays.Clone(data);
+				for (int j = 0; j < pow; ++j)
+				{
+					mul.MultiplyH(expected);
+				}
+
+				byte[] H_a = new byte[16];
+				exp.ExponentiateX(pow, H_a);
+				byte[] actual = multiply(data, H_a);
+
+				Assert.IsTrue(Arrays.AreEqual(expected, actual));
+			}
+		}
+
+		[Test]
+		public void TestMultiply()
+		{
+			byte[] expected = Arrays.Clone(H);
+			mul.MultiplyH(expected);
+
+			Assert.IsTrue(Arrays.AreEqual(expected, multiply(H, H)));
+
+			for (int count = 0; count < 10; ++count)
+			{
+				byte[] a = new byte[16];
+				random.NextBytes(a);
+
+				byte[] b = new byte[16];
+				random.NextBytes(b);
+
+				expected = Arrays.Clone(a);
+				mul.MultiplyH(expected);
+				Assert.IsTrue(Arrays.AreEqual(expected, multiply(a, H)));
+				Assert.IsTrue(Arrays.AreEqual(expected, multiply(H, a)));
+				
+				expected = Arrays.Clone(b);
+				mul.MultiplyH(expected);
+				Assert.IsTrue(Arrays.AreEqual(expected, multiply(b, H)));
+				Assert.IsTrue(Arrays.AreEqual(expected, multiply(H, b)));
+				
+				Assert.IsTrue(Arrays.AreEqual(multiply(a, b), multiply(b, a)));
+			}
+		}
+
+		private byte[] randomBlocks(int upper)
+		{
+			byte[] bs = new byte[16 * random.Next(upper)];
+			random.NextBytes(bs);
+			return bs;
+		}
+
+		private byte[] randomBytes(int upper)
+		{
+			byte[] bs = new byte[random.Next(upper)];
+			random.NextBytes(bs);
+			return bs;
+		}
+
+		private byte[] concatArrays(byte[] a, byte[] b)
+		{
+			byte[] ab = new byte[a.Length + b.Length];
+			Array.Copy(a, 0, ab, 0, a.Length);
+			Array.Copy(b, 0, ab, a.Length, b.Length);
+			return ab;
+		}
+
+		private byte[] combine_GHASH(byte[] ghashA_, long bitlenA, byte[] ghash_C, long bitlenC)
+		{
+			// Note: bitlenA must be aligned to the block size
+
+			long c = (bitlenC + 127) >> 7;
+
+			byte[] H_c = new byte[16];
+			exp.ExponentiateX(c, H_c);
+
+			byte[] tmp1 = lengthBlock(bitlenA, 0);
+			mul.MultiplyH(tmp1);
+
+			byte[] ghashAC = Arrays.Clone(ghashA_);
+			xor(ghashAC, tmp1);
+			ghashAC = multiply(ghashAC, H_c);
+			// No need to touch the len(C) part (second 8 bytes)
+			xor(ghashAC, tmp1);
+			xor(ghashAC, ghash_C);
+
+			return ghashAC;
+		}
+
+		private byte[] concatAuth_GHASH(byte[] ghashP, long bitlenP, byte[] ghashA, long bitlenA)
+		{
+			// Note: bitlenP must be aligned to the block size
+
+			long a = (bitlenA + 127) >> 7;
+
+			byte[] tmp1 = lengthBlock(bitlenP, 0);
+			mul.MultiplyH(tmp1);
+
+			byte[] tmp2 = lengthBlock(bitlenA ^ (bitlenP + bitlenA), 0);
+			mul.MultiplyH(tmp2);
+
+			byte[] H_a = new byte[16];
+			exp.ExponentiateX(a, H_a);
+
+			byte[] ghashC = Arrays.Clone(ghashP);
+			xor(ghashC, tmp1);
+			ghashC = multiply(ghashC, H_a);
+			xor(ghashC, tmp2);
+			xor(ghashC, ghashA);
+			return ghashC;
+		}
+
+		private byte[] concatCrypt_GHASH(byte[] ghashP, long bitlenP, byte[] ghashA, long bitlenA)
+		{
+			// Note: bitlenP must be aligned to the block size
+			
+			long a = (bitlenA + 127) >> 7;
+
+			byte[] tmp1 = lengthBlock(0, bitlenP);
+			mul.MultiplyH(tmp1);
+
+			byte[] tmp2 = lengthBlock(0, bitlenA ^ (bitlenP + bitlenA));
+			mul.MultiplyH(tmp2);
+
+			byte[] H_a = new byte[16];
+			exp.ExponentiateX(a, H_a);
+
+			byte[] ghashC = Arrays.Clone(ghashP);
+			xor(ghashC, tmp1);
+			ghashC = multiply(ghashC, H_a);
+			xor(ghashC, tmp2);
+			xor(ghashC, ghashA);
+			return ghashC;
+		}
+
+		private byte[] GHASH(byte[] A, byte[] C)
+		{
+			byte[] X = new byte[16];
+
+			{
+				for (int pos = 0; pos < A.Length; pos += 16)
+				{
+					byte[] tmp = new byte[16];
+					int num = System.Math.Min(A.Length - pos, 16);
+					Array.Copy(A, pos, tmp, 0, num);
+					xor(X, tmp);
+					mul.MultiplyH(X);
+				}
+			}
+
+			{
+				for (int pos = 0; pos < C.Length; pos += 16)
+				{
+					byte[] tmp = new byte[16];
+					int num = System.Math.Min(C.Length - pos, 16);
+					Array.Copy(C, pos, tmp, 0, num);
+					xor(X, tmp);
+					mul.MultiplyH(X);
+				}
+			}
+
+			{
+				xor(X, lengthBlock((long)A.Length * 8, (long)C.Length * 8));
+				mul.MultiplyH(X);
+			}
+
+			return X;
+		}
+
+		private static byte[] lengthBlock(long bitlenA, long bitlenC)
+		{
+			byte[] tmp = new byte[16];
+			UInt64_To_BE((ulong)bitlenA, tmp, 0);
+			UInt64_To_BE((ulong)bitlenC, tmp, 8);
+			return tmp;
+		}
+
+		private static void xor(byte[] block, byte[] val)
+		{
+			for (int i = 15; i >= 0; --i)
+			{
+				block[i] ^= val[i];
+			}
+		}
+
+		private static void UInt64_To_BE(ulong n, byte[] bs, int off)
+		{
+			UInt32_To_BE((uint)(n >> 32), bs, off);
+			UInt32_To_BE((uint)(n), bs, off + 4);
+		}
+
+		private static void UInt32_To_BE(uint n, byte[] bs, int off)
+		{
+			bs[  off] = (byte)(n >> 24);
+			bs[++off] = (byte)(n >> 16);
+			bs[++off] = (byte)(n >>  8);
+			bs[++off] = (byte)(n      );
+		}
+
+		private static byte[] multiply(byte[] a, byte[] b)
+		{
+			byte[] c = new byte[16];
+			byte[] tmp = Arrays.Clone(b);
+
+			for (int i = 0; i < 16; ++i)
+			{
+				byte bits = a[i];
+				for (int j = 7; j >= 0; --j)
+				{
+					if ((bits & (1 << j)) != 0)
+					{
+						xor(c, tmp);
+					}
+
+					bool lsb = (tmp[15] & 1) != 0;
+					shiftRight(tmp);
+					if (lsb)
+					{
+						// R = new byte[]{ 0xe1, ... };
+						//GcmUtilities.Xor(tmp, R);
+						tmp[0] ^= (byte)0xe1;
+					}
+				}
+			}
+
+			return c;
+		}
+
+		private static void shiftRight(byte[] block)
+		{
+			int i = 0;
+			byte bit = 0;
+			for (;;)
+			{
+				byte b = block[i];
+				block[i] = (byte)((b >> 1) | bit);
+				if (++i == 16) break;
+				bit = (byte)(b << 7);
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/HCFamilyTest.cs b/crypto/test/src/crypto/test/HCFamilyTest.cs
new file mode 100644
index 000000000..0904bc9eb
--- /dev/null
+++ b/crypto/test/src/crypto/test/HCFamilyTest.cs
@@ -0,0 +1,192 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * HC-128 and HC-256 Tests. Based on the test vectors in the official reference
+	 * papers, respectively:
+	 * <pre>
+	 * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf
+	 * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
+	 * </pre>
+	 * See HCFamilyVecTest for a more exhaustive test based on the ecrypt vectors.
+	 */
+	public class HCFamilyTest
+		: SimpleTest
+	{
+		private static readonly byte[] MSG = new byte[64];
+
+		private static readonly string[][] HC128_VerifiedTest = new string[][]
+		{
+			new string[]{
+				"Set 2, vector#  0",
+				"00000000000000000000000000000000",
+				"00000000000000000000000000000000",
+				"82001573A003FD3B7FD72FFB0EAF63AA" +
+				"C62F12DEB629DCA72785A66268EC758B" +
+				"1EDB36900560898178E0AD009ABF1F49" +
+				"1330DC1C246E3D6CB264F6900271D59C"
+			},
+			new string[]{
+				"Set 6, vector#  0",
+				"0053A6F94C9FF24598EB3E91E4378ADD",
+				"0D74DB42A91077DE45AC137AE148AF16",
+				"2E1ED12A8551C05AF41FF39D8F9DF933" +
+				"122B5235D48FC2A6F20037E69BDBBCE8" +
+				"05782EFC16C455A4B3FF06142317535E" +
+				"F876104C32445138CB26EBC2F88A684C"
+			},
+			new string[]{
+				"Set 6, vector#  1",
+				"0558ABFE51A4F74A9DF04396E93C8FE2",
+				"167DE44BB21980E74EB51C83EA51B81F",
+				"4F864BF3C96D0363B1903F0739189138" +
+				"F6ED2BC0AF583FEEA0CEA66BA7E06E63" +
+				"FB28BF8B3CA0031D24ABB511C57DD17B" +
+				"FC2861C32400072CB680DF2E58A5CECC"
+			},
+			new string[]{
+				"Set 6, vector#  2",
+				"0A5DB00356A9FC4FA2F5489BEE4194E7",
+				"1F86ED54BB2289F057BE258CF35AC128",
+				"82168AB0023B79AAF1E6B4D823855E14" +
+				"A7084378036A951B1CFEF35173875ED8" +
+				"6CB66AB8410491A08582BE40080C3102" +
+				"193BA567F9E95D096C3CC60927DD7901"
+			},
+			new string[]{
+				"Set 6, vector#  3",
+				"0F62B5085BAE0154A7FA4DA0F34699EC",
+				"288FF65DC42B92F960C72E95FC63CA31",
+				"1CD8AEDDFE52E217E835D0B7E84E2922" +
+				"D04B1ADBCA53C4522B1AA604C42856A9" +
+				"0AF83E2614BCE65C0AECABDD8975B557" +
+				"00D6A26D52FFF0888DA38F1DE20B77B7"
+			}
+		};
+
+		private static readonly string[][] HC256_VerifiedTest = new string[][]
+		{
+			new string[]{
+				"Set 2, vector#  0",
+				"00000000000000000000000000000000",
+				"00000000000000000000000000000000",
+				"5B078985D8F6F30D42C5C02FA6B67951" +
+				"53F06534801F89F24E74248B720B4818" +
+				"CD9227ECEBCF4DBF8DBF6977E4AE14FA" +
+				"E8504C7BC8A9F3EA6C0106F5327E6981"
+			},
+			new string[]{
+				"Set 2, vector#  9",
+				"09090909090909090909090909090909",
+				"00000000000000000000000000000000",
+				"F5C2926651AEED9AF1A9C2F04C03D081" +
+				"2145B56AEA46EB283A25A4C9E3D8BEB4" +
+				"821B418F06F2B9DCDF1A85AB8C02CD14" +
+				"62E1BBCAEC9AB0E99AA6AFF918BA627C"
+			},
+			new string[]{
+				"Set 2, vector#135",
+				"87878787878787878787878787878787",
+				"00000000000000000000000000000000",
+				"CEC0C3852E3B98233EBCB975C10B1191" +
+				"3C69F2275EB97A1402EDF16C6FBE19BE" +
+				"79D65360445BCB63676E6553B609A065" +
+				"0155C3B22DD1975AC0F3F65063A2E16E"
+			},
+			new string[]{
+				"Set 6, vector#  0",
+				"0053A6F94C9FF24598EB3E91E4378ADD" +
+				"3083D6297CCF2275C81B6EC11467BA0D",
+				"0D74DB42A91077DE45AC137AE148AF16" +
+				"7DE44BB21980E74EB51C83EA51B81F86",
+				"23D9E70A45EB0127884D66D9F6F23C01" +
+				"D1F88AFD629270127247256C1FFF91E9" +
+				"1A797BD98ADD23AE15BEE6EEA3CEFDBF" +
+				"A3ED6D22D9C4F459DB10C40CDF4F4DFF"
+			},
+			new string[]{
+				"Set 6, vector#  1",
+				"0558ABFE51A4F74A9DF04396E93C8FE2" +
+				"3588DB2E81D4277ACD2073C6196CBF12",
+				"167DE44BB21980E74EB51C83EA51B81F" +
+				"86ED54BB2289F057BE258CF35AC1288F",
+				"C44B5262F2EAD9C018213127686DB742" +
+				"A72D3F2D61D18F0F4E7DE5B4F7ADABE0" +
+				"7E0C82033B139F02BAACB4E2F2D0BE30" +
+				"110C3A8A2B621523756692877C905DD0"
+			},
+			new string[]{
+				"Set 6, vector#  2",
+				"0A5DB00356A9FC4FA2F5489BEE4194E7" +
+				"3A8DE03386D92C7FD22578CB1E71C417",
+				"1F86ED54BB2289F057BE258CF35AC128" +
+				"8FF65DC42B92F960C72E95FC63CA3198",
+				"9D13AA06122F4F03AE60D507701F1ED0" +
+				"63D7530FF35EE76CAEDCBFB01D8A239E" +
+				"FA4A44B272DE9B4092E2AD56E87C3A60" +
+				"89F5A074D1F6E5B8FC6FABEE0C936F06"
+			},
+			new string[]{
+				"Set 6, vector#  3",
+				"0F62B5085BAE0154A7FA4DA0F34699EC" +
+				"3F92E5388BDE3184D72A7DD02376C91C",
+				"288FF65DC42B92F960C72E95FC63CA31" +
+				"98FF66CD349B0269D0379E056CD33AA1",
+				"C8632038DA61679C4685288B37D3E232" +
+				"7BC2D28C266B041FE0CA0D3CFEED8FD5" +
+				"753259BAB757168F85EA96ADABD823CA" +
+				"4684E918423E091565713FEDDE2CCFE0"
+			}
+		};
+
+		public override string Name
+		{
+			get { return "HC-128 and HC-256"; }
+		}
+
+		public override void PerformTest()
+		{
+			IStreamCipher hc = new HC256Engine();
+
+			for (int i = 0; i != HC256_VerifiedTest.Length; i++)
+			{
+				string[] test = HC256_VerifiedTest[i];
+				HCTest(hc, "HC-256 - " + test[0], Hex.Decode(test[1]), Hex.Decode(test[2]), Hex.Decode(test[3]));
+			}
+
+			hc = new HC128Engine();
+
+			for (int i = 0; i != HC128_VerifiedTest.Length; i++)
+			{
+				string[] test = HC128_VerifiedTest[i];
+				HCTest(hc, "HC-128 - " + test[0], Hex.Decode(test[1]), Hex.Decode(test[2]), Hex.Decode(test[3]));
+			}
+		}
+
+		private void HCTest(IStreamCipher hc, string test, byte[] key, byte[] IV, byte[] expected)
+		{
+			KeyParameter kp = new KeyParameter(key);
+			ParametersWithIV ivp = new ParametersWithIV(kp, IV);
+
+			hc.Init(true, ivp);
+			for (int i = 0; i < 64; i++)
+			{
+				if (hc.ReturnByte(MSG[i]) != expected[i])
+				{
+					Fail(test + " failure at byte " + i);
+				}
+			}
+		}
+
+		public static void Main(string[] args)
+		{
+			RunTest(new HCFamilyTest());
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/HCFamilyVecTest.cs b/crypto/test/src/crypto/test/HCFamilyVecTest.cs
new file mode 100644
index 000000000..00b0ee75c
--- /dev/null
+++ b/crypto/test/src/crypto/test/HCFamilyVecTest.cs
@@ -0,0 +1,184 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* HC-128 and HC-256 Tests. Based on the test vectors in the official reference
+	* papers, respectively:
+	* 
+	* http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf
+	* http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
+	*/
+	[TestFixture]
+	public class HCFamilyVecTest
+		: SimpleTest
+	{
+		private class PeekableLineReader
+			: StreamReader
+		{
+			public PeekableLineReader(Stream s)
+				: base(s)
+			{
+				peek = base.ReadLine();
+			}
+
+			public string PeekLine()
+			{
+				return peek;
+			}
+
+			public override string ReadLine()
+			{
+				string tmp = peek;
+				peek = base.ReadLine();
+				return tmp;
+			}
+
+			private string peek; 
+	    }
+
+		public override string Name
+		{
+			get { return "HC-128 and HC-256"; }
+		}
+
+		public override void PerformTest()
+		{
+			RunTests(new HC128Engine(), "hc128/ecrypt_HC-128.txt");
+			RunTests(new HC256Engine(), "hc256/ecrypt_HC-256_128K_128IV.txt");
+			RunTests(new HC256Engine(), "hc256/ecrypt_HC-256_256K_128IV.txt");
+			RunTests(new HC256Engine(), "hc256/ecrypt_HC-256_128K_256IV.txt");
+			RunTests(new HC256Engine(), "hc256/ecrypt_HC-256_256K_256IV.txt");
+		}
+
+		private void RunTests(IStreamCipher hc, string fileName)
+		{
+			Stream resource = SimpleTest.GetTestDataAsStream(
+				"hc256." + fileName.Replace('/', '.'));
+			PeekableLineReader r = new PeekableLineReader(resource);
+			RunAllVectors(hc, fileName, r);
+		}
+
+		private void RunAllVectors(IStreamCipher hc, string fileName, PeekableLineReader r)
+		{
+			for (;;)
+			{
+				string line = r.ReadLine();
+				if (line == null)
+					break;
+
+				line = line.Trim();
+
+				if (line.StartsWith("Set "))
+				{
+					RunVector(hc, fileName, r, line.Replace(":", ""));
+				}
+			}
+		}
+
+		private void RunVector(IStreamCipher hc, string fileName, PeekableLineReader r, string vectorName)
+		{
+//			Console.WriteLine(fileName + " => " + vectorName);
+			string hexKey = ReadBlock(r);
+			string hexIV = ReadBlock(r);
+
+			ICipherParameters cp = new KeyParameter(Hex.Decode(hexKey));
+			cp = new ParametersWithIV(cp, Hex.Decode(hexIV));
+			hc.Init(true, cp);
+
+			byte[] input = new byte[64];
+			byte[] output = new byte[64];
+			byte[] digest = new byte[64];
+			int pos = 0;
+
+			for (;;)
+			{
+				string line1 = r.PeekLine().Trim();
+				int equalsPos = line1.IndexOf('=');
+				string lead = line1.Substring(0, equalsPos - 1);
+
+				string hexData = ReadBlock(r);
+				byte[] data = Hex.Decode(hexData);
+
+				if (lead.Equals("xor-digest"))
+				{
+					if (!Arrays.AreEqual(data, digest))
+					{
+						Fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead);
+//						Console.WriteLine(fileName + " => " + vectorName + " failed at " + lead); return;
+					}
+					break;
+				}
+
+				int posA = lead.IndexOf('[');
+				int posB = lead.IndexOf("..");
+				int posC = lead.IndexOf(']');
+				int start = Int32.Parse(lead.Substring(posA + 1, posB - (posA + 1)));
+				int end = Int32.Parse(lead.Substring(posB + 2, posC - (posB + 2)));
+
+				if (start % 64 != 0 || (end - start != 63))
+					throw new InvalidOperationException(vectorName + ": " + lead + " not on 64 byte boundaries");
+
+				while (pos < end)
+				{
+					hc.ProcessBytes(input, 0, input.Length, output, 0);
+					xor(digest, output);
+					pos += 64;
+				}
+
+				if (!Arrays.AreEqual(data, output))
+				{
+					Fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead);
+//					Console.WriteLine(fileName + " => " + vectorName + " failed at " + lead); return;
+				}
+			}
+		}
+
+		private static string ReadBlock(PeekableLineReader r)
+		{
+			string first = r.ReadLine().Trim();
+			string result = first.Substring(first.LastIndexOf(' ') + 1);
+
+			for (;;)
+			{
+				string peek = r.PeekLine().Trim();
+				if (peek.Length < 1 || peek.IndexOf('=') >= 0)
+					break;
+				result += r.ReadLine().Trim();
+			}
+
+			return result;
+		}
+
+		private static void xor(byte[] digest, byte[] block)
+		{
+			for (int i = 0; i < digest.Length; ++i)
+			{
+				digest[i] ^= block[i];
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new HCFamilyVecTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/IDEATest.cs b/crypto/test/src/crypto/test/IDEATest.cs
new file mode 100644
index 000000000..fbbd1ae17
--- /dev/null
+++ b/crypto/test/src/crypto/test/IDEATest.cs
@@ -0,0 +1,53 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class IdeaTest
+        : CipherTest
+    {
+        public override string Name
+        {
+            get { return "IDEA"; }
+        }
+
+        internal static SimpleTest[] tests = new SimpleTest[]
+        {
+            new BlockCipherVectorTest(0, new IdeaEngine(),
+                new KeyParameter(Hex.Decode("00112233445566778899AABBCCDDEEFF")),
+                "000102030405060708090a0b0c0d0e0f",
+                "ed732271a7b39f475b4b2b6719f194bf"),
+            new BlockCipherVectorTest(0, new IdeaEngine(),
+                new KeyParameter(Hex.Decode("00112233445566778899AABBCCDDEEFF")),
+                "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+                "b8bc6ed5c899265d2bcfad1fc6d4287d")
+        };
+
+        public IdeaTest()
+            : base(tests, new IdeaEngine(), new KeyParameter(new byte[32]))
+        {
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new IdeaTest();
+            ITestResult result = test.Perform();
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ISAACTest.cs b/crypto/test/src/crypto/test/ISAACTest.cs
new file mode 100644
index 000000000..1782bbc98
--- /dev/null
+++ b/crypto/test/src/crypto/test/ISAACTest.cs
@@ -0,0 +1,196 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* ISAAC Test - see http://www.burtleburtle.net/bob/rand/isaacafa.html
+	*/
+	[TestFixture]
+	public class IsaacTest
+		: SimpleTest
+	{
+		byte[] outBase = Hex.Decode(
+			"f650e4c8e448e96d98db2fb4f5fad54f433f1afbedec154ad837048746ca4f9a" +
+			"5de3743e88381097f1d444eb823cedb66a83e1e04a5f6355c744243325890e2e" +
+			"7452e31957161df638a824f3002ed71329f5544951c08d83d78cb99ea0cc74f3" +
+			"8f651659cbc8b7c2f5f71c6912ad6419e5792e1b860536b809b3ce98d45d6d81" +
+			"f3b2612917e38f8529cf72ce349947b0c998f9ffb5e13dae32ae2a2bf7cf814c" +
+			"8ebfa303cf22e0640b923200eca4d58aef53cec4d0f7b37d9c411a2affdf8a80" +
+			"b40e27bcb4d2f97644b89b08f37c71d51a70e7e90bdb9c3060dc5207b3c3f24b" +
+			"d7386806229749b54e232cd091dabc65a70e11018b87437e5781414fcdbc62e2" +
+			"8107c9ff69d2e4ae3b18e752b143b6886f4e077295138769943c3c74afc17a97" +
+			"0fd439636a529b0bd8c58a6aa8bcc22d2db35dfea7a2f4026cb167db538e1f4e" +
+			"7275e2771d3b8e97ecc5dc9115e3a5b90369661430ab93ecac9fe69d7bc76811" +
+			"60eda8da28833522d5295ebc5adb60e7f7e1cdd097166d14b67ec13a210f3925" +
+			"64af0fef0d0286843aea3decb058bafbb8b0ccfcf2b5cc05e3a662d9814bc24c" +
+			"2364a1aa37c0ed052b36505c451e7ec85d2a542fe43d0fbb91c8d92560d4d5f8" +
+			"12a0594b9e8a51dacd49ebdb1b0dcdc1cd57c7f7e63444517ded386f2f36fa86" +
+			"a6d1210133bc405db388d96cdb6dbe96fe29661c13edc0cbcb0eee4a70cc94ae" +
+			"de11ed340606cf9f3a6ce38923d74f4ea37f63ff917bdec2d73f72d40e7e0e67" +
+			"3d77d9a213add9228891b3db01a9bd7056a001e3d51f093dcc033ce35ad0d3b0" +
+			"34105a8c6a123f57bd2e50247364944be89b1a3b21835c4d9f39e2d9d405ded8" +
+			"294d37e5bccaaeed35a124b56708a2bcb00960ba2a98121a4d8fae820bb3263f" +
+			"12595a196a1075890809e49421c171ec884d682514c8009bb0b84e7b03fb88f4" +
+			"28e7cb789388b13bdd2dc1d5848f520a07c28cd168a3935872c9137d127dd430" +
+			"c613f1578c2f0d55f7d3f39f309bfb788406b13746c0a6f53718d59708607f04" +
+			"76904b6d04db4e13cd7411a7b510ce0ebfc7f7ccb83f957afdfef62dc35e4580" +
+			"3ff1e5244112d96c02c9b944d5990dfbe7e265810d9c7e7e826dfa8966f1e0ab" +
+			"30bcc764eadebeaced35e5ee0c571a7de4f3a26af7f58f7badf6bc235d023e65" +
+			"1ed3ff4eec46b0b6d2a93b51e75b41c97e315aeb61119a5a53245b7933f6d7b1" +
+			"cae8deba50fc8194afa92a6dc87c80064188bfcd8bace62e78ffa5685597ec0f" +
+			"b4415f7d08294766ad56764309c36f903dde9f394a0a283c18080c8e080c79ec" +
+			"79ae4c10cb9e15637cdd662f62d31911a4ca0cf15cf824cd3b708f991e16614c" +
+			"b6b9d7665de87abb7229ea81d5b2d75056e6cd21fe1e42d596da2655c2b9aa36" +
+			"b8f6fd4a6a158d1001913fd3af7d1fb80b5e435f90c107576554abda7a68710f" +
+			"82ac484fd7e1c7be95c85eaa94a302f44d3cfbda786b29081010b27582d53d12" +
+			"21e2a51c3d1e9150b059261dd0638e1a31860f0581f2864dff4cfc350451516d" +
+			"bd086f26bc5654c165dfa427a82427f5582e3014b8d2486dc79a17499a1d7745" +
+			"8766bb541e04a7f73d3dff8ad5ec6bf4dbef7d9f36ec0ea31feb2e4f15cfcc5c" +
+			"d8c423fbd0ef3cc9eb244925ba5590c8a5f48ac433c5321c613b67b2479c3a22" +
+			"e21339cc10d210aa931dd7e2ef05ee06b82f2703a385cb2c5d67133c877eb7b4" +
+			"1e3437f75afb43ae53c078f394d904811d96458908063a85e13222281956b1e5" +
+			"31860f132e7b022f21182ca396f703ac46819e2e0d28fe523724d4dca0eabe6b" +
+			"c66699fdc6112fdd19c1e69c04d3658a4b55dd9931907d62f854b5224d678f26" +
+			"22ae0582eafed133e4a51d2184bd6dd6c1a513753f28ee63fb737b1a70a1660e" +
+			"8a8dfaa31be79937f7476978513c1764531ac6bf12c06908001cdb951a4b6a53" +
+			"d067fce512b2cfb69ddb477f740e006639ddf25acc8bfa2df1b20eaf64f2632c" +
+			"9783cdee63bfd4d80084cfe575f4e9e219b48fd06c48ddd87a36af9371865c4c" +
+			"9ce0199d867027d72cb7b77f84ef01da72f5972f040f7074df9afa29c921f94e" +
+			"75c08a3618c1ef9ad649a428c5b719378a30738ad97cd348858129a6239e3b0a" +
+			"bbb8abc480fac4c2ecfcf20bd9d711f9e2a4ef71b5fe87c0be8b06b2aafef5a7" +
+			"9c15db3b0aeb81654389a84a253b1d7a19047c797cdc78a2d20adf0356f55a71" +
+			"3e730fa8fd8650d8959e234eb7546681dad1b22a142a6e858ef4bce668235b9d" +
+			"85a13f8574096ae7a949bea229322d0dd568385882846526403dae086dd1943a" +
+			"e1279bff9e7e4f041c3a4524484525e481d4cc5fe24124c0037464c0bf1bd691" +
+			"26ceb003275ead3ac5bde90826414ff3a30519add7b43abe2ce5d3d588412761" +
+			"97ca2070e5fbb9c7276df0b4308f751f37a97df6c9cd808cfe4cb3803d469303" +
+			"aee19096c0d5d42a4e823ad3f5f9cc3b4286619c9ca45e1c66c97340891aec49" +
+			"45bae606c798f04752649d6cce86fdfc80c6e402d6ec2f2b27c822821fe26ce0" +
+			"92f57ea7de462f4d07497cae5a48755c721502dd6cbe7935836d80039ead7f70" +
+			"9ab3a42f4c8652d632e39273e8fa38601da4f25a0cd6ef8102503f7d8854a0a1" +
+			"9a30c4e88815715305efe29457c4c9252887d96fc1a71e3ce9f841632d0985de" +
+			"d21e796c6fb5ce5602614abfc3c7be2cb54fed6fa617a083c3142d8f6079e4ce" +
+			"ceffc1471d0cb81bdc153e5fe36ef5bbd531161a165b10157aa114ed3f7579b3" +
+			"f7f395f1bc6172c7a86f875e0e6c51b3cdfec2af73c0e762824c2009c5a87748" +
+			"94d401258aba3ffbd32be0608c17eff021e2547e07cffad905340e15f3310c92" +
+			"9d8d190886ba527ff943f672ef73fbf046d95ca5c54cd95b9d855e894bb5af29");
+
+		byte[] outFFFFFFFF = Hex.Decode(
+			"de3b3f3c19e0629c1fc8b7836695d523e7804edd86ff7ce9b106f52caebae9d9" +
+			"72f845d49ce17d7da44e49bae954aac0d0b1284b98a88eec1524fb6bc91a16b5" +
+			"1192ac5334131446ac2442de9ff3d5867b9b9148881ee30a6e87dd88e5d1f7cd" +
+			"98db31ff36f70d9850cfefaef42abb00ecc39ed308bf4b8030cdc2b6b7e42f0e" +
+			"908030dd282f96edacc888b3a986e109c129998f89baa1b5da8970b07a6ab012" +
+			"f10264f23c315c9c8e0c164955c68517b6a4f982b2626db70787f869ac6d551b" +
+			"e34931627c7058e965c502e18d2cd370e6db3b70d947d61aa9717cf8394f48c6" +
+			"3c796f3a154950846badb28b70d982f29bc670254e3e5e0f8e36b0a5f6da0a04" +
+			"6b235ed6a42988c012bde74d879fa8eb5d59f5f40ed5e76601c9847b3edb2690");
+
+		byte[] outFFFF0000 = Hex.Decode(
+			"26c54b1f8c4e3fc582e9e8180f7aba5380463dcf58b03cbeda0ecc8ba90ccff8" +
+			"5bd50896313d7efed44015faeac6964b241a7fb8a2e37127a7cbea0fd7c020f2" +
+			"406371b87ef5185089504751e5e44352eff63e00e5c28f5dff0616a9a3a00f1f" +
+			"4a1350e3a17be9abddfc2c94571450a0dc4c3c0c7c7f98e80c95f607d50c676a" +
+			"9a3006f9d279a79a4d66b2ab0c52930c9ee84bc09895e70fa041b1a3a2966f11" +
+			"6a47fd09705124b1f5c7ae055e54536e66584b1608f3612d81b72f109a385831" +
+			"121945b207b90ac72437a248f27a121c2801f4153a8699fb047e193f7ba69e1b" +
+			"b117869675d4c963e6070c2ca3d332ce830cb5e3d9ed2eee7faf0acc20fbe154" +
+			"188ae789e95bd5c1f459dbd150aab6eb833170257084bc5d44e9df09f5624f9d" +
+			"afecd0c9340ac8587f8625d343f7efd1cc8abcf7a6f90eabd4e8e2d906278d6e" +
+			"431fcade165c8c467887fbf5c26d341557b064b98c60dd40ab262dc046d69647" +
+			"56f3ddc1a07ae5f87be878b9334fcde40add68d2ca1dc05fb1670f998c7c4607" +
+			"9a6e48bdb330ad8d30b61b5cc8dc156f5733905931949783f89ac396b65aa4b8" +
+			"51f746b53ed8ea66130e1d75e8eab136e60450e3e600226bc8e17d03744ce94c" +
+			"0eec9234fea5f18eef65d81f2f10cfbc0b112b8cde17c32eb33ed81d7356eac3" +
+			"eb1cb9cefa6604c2d707949b6e5a83e60705bf6aae76dcc7d35d68ff149c1ac5" +
+			"424bb4a39e2f496f886637fce3db4ba4ad12c1a32d25e1606f6635ff636486f6" +
+			"714997b45477f38813c02afce4bebf196b813332f0decd567c745f441e736364");
+
+		byte[] out0000FFFF = Hex.Decode(
+			"bc31712f2a2f467a5abc737c57ce0f8d49d2f775eb850fc8f856daf19310fee2"+
+			"5bab40e78403c9ef4ccd971418992faf4e85ca643fa6b482f30c4659066158a6"+
+			"5bc3e620ba7ea5c34dd0eac5aabb2cf078d915fd1f8c437ed00423076c10f701"+
+			"eefa7fc7c461aca5db8a87be29d925c4212d4adcfa71ff5b06af15c048aa0dfd"+
+			"f0e645bc09fea200c430a88eb38c466ff358b836f1159656a078f6fc752f6db1"+
+			"6680bb30fc771a6a785bbb2298e947d7b3500e557775962248bedf4e82c16e66"+
+			"f39283ccb95e5399061056a11c4a280f00f7487888199487905273c7aa13012b"+
+			"4849eca626cbf071c782e084f9fded57de92313e5f61a6e81117fb1115eff275"+
+			"66fd5c755bb3b01bba69aeb8f1b1b1cc9709734be31b35bc707d372ba6fe70d1"+
+			"e2c3b0e5e74a7058faff6b11d3a168f19fecc9fcb36b3e6a5f828c01c22ac0c2"+
+			"5da2a3a9eec7e0ebbbf51472e430ed4cf1c7ab57ef9aea511e40250846d260b6"+
+			"17a3fdeba16cf4afaf700144d3296b58b22a3c79ed96f3e2fc8d9e3c660ae153"+
+			"8e0c285ccdc48b59117e80413bd0ad24c6a8d4f133fe1496f14351bb89904fa5"+
+			"e10c4b8d50e0604578389c336a9ab3d292beb90ce640fc028e697cf54e021e2f"+
+			"c0ca3fe0471fde5e5462f221739a74f5a13ae0621fe2a82e752bc294f63de48d"+
+			"e85430af71307a30441b861ab5380e6a6dbe1251c9baa567da14e38e5a0ccddf"+
+			"0127205c38fc3b77065e98101d219246103438d223ec7f8f533d4bb3a3d3407a"+
+			"944910f11e8e5492e86de7a0471250eca32f0838b3db02fffe71898712af3261");
+
+		public override string Name
+		{
+			get { return "ISAAC"; }
+		}
+
+		public override void PerformTest()
+		{
+			IsaacEngine engine = new IsaacEngine();
+
+			doTest(engine, Hex.Decode("00000000"), outBase);
+			doTest(engine, Hex.Decode("ffffffff"), outFFFFFFFF);
+
+			byte[] k = new byte[256 * 4];
+			for (int i = 0; i != k.Length; i++)
+			{
+				k[i] = (byte)((i % 4 == 0 || i % 4 == 1) ? 0xff : 0x00);
+			}
+			doTest(engine, k, outFFFF0000);
+			k = new byte[256 * 4];
+			for (int i = 0; i != k.Length; i++)
+			{
+				k[i] = (byte)((i % 4 == 2 || i % 4 == 3) ? 0xff : 0x00);
+			}
+			doTest(engine, k, out0000FFFF);
+		}
+
+		private void doTest(
+			IsaacEngine	engine,
+			byte[]		key,
+			byte[]		output)
+		{
+			byte[] input = new byte[output.Length];
+			byte[] enc = new byte[output.Length];
+			engine.Init(true, new KeyParameter(key));
+			engine.ProcessBytes(input, 0, input.Length, enc, 0);
+			if (!AreEqual(enc, output))
+			{
+				Fail("ciphertext mismatch");
+			}
+			engine.Init(false, new KeyParameter(key));
+			engine.ProcessBytes(enc, 0, enc.Length, enc, 0);
+			if (!AreEqual(enc, input))
+			{
+				Fail("plaintext mismatch");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new IsaacTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/ISO9796Test.cs b/crypto/test/src/crypto/test/ISO9796Test.cs
new file mode 100644
index 000000000..562238bca
--- /dev/null
+++ b/crypto/test/src/crypto/test/ISO9796Test.cs
@@ -0,0 +1,961 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> test vectors from ISO 9796-1 and ISO 9796-2 edition 1.</summary>
+    [TestFixture]
+    public class ISO9796Test
+        : SimpleTest
+    {
+        static BigInteger mod1 = new BigInteger("0100000000000000000000000000000000bba2d15dbb303c8a21c5ebbcbae52b7125087920dd7cdf358ea119fd66fb064012ec8ce692f0a0b8e8321b041acd40b7", 16);
+
+        static BigInteger pub1 = new BigInteger("03", 16);
+
+        static BigInteger pri1 = new BigInteger("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac9f0783a49dd5f6c5af651f4c9d0dc9281c96a3f16a85f9572d7cc3f2d0f25a9dbf1149e4cdc32273faadd3fda5dcda7", 16);
+
+        static BigInteger mod2 = new BigInteger("ffffff7fa27087c35ebead78412d2bdffe0301edd494df13458974ea89b364708f7d0f5a00a50779ddf9f7d4cb80b8891324da251a860c4ec9ef288104b3858d", 16);
+
+        static BigInteger pub2 = new BigInteger("03", 16);
+
+        static BigInteger pri2 = new BigInteger("2aaaaa9545bd6bf5e51fc7940adcdca5550080524e18cfd88b96e8d1c19de6121b13fac0eb0495d47928e047724d91d1740f6968457ce53ec8e24c9362ce84b5", 16);
+
+        static byte[] msg1 = Hex.Decode("0cbbaa99887766554433221100");
+
+        //
+        // you'll need to see the ISO 9796 to make sense of this
+        //
+        static byte[] sig1 = mod1.Subtract(new BigInteger("309f873d8ded8379490f6097eaafdabc137d3ebfd8f25ab5f138d56a719cdc526bdd022ea65dabab920a81013a85d092e04d3e421caab717c90d89ea45a8d23a", 16)).ToByteArray();
+
+        static byte[] msg2 = Hex.Decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210");
+
+        static byte[] sig2 = new BigInteger("319bb9becb49f3ed1bca26d0fcf09b0b0a508e4d0bd43b350f959b72cd25b3af47d608fdcd248eada74fbe19990dbeb9bf0da4b4e1200243a14e5cab3f7e610c", 16).ToByteArray();
+
+        static byte[] msg3 = Hex.Decode("0112233445566778899aabbccd");
+
+        static byte[] sig3 = mod2.Subtract(new BigInteger("58e59ffb4b1fb1bcdbf8d1fe9afa3730c78a318a1134f5791b7313d480ff07ac319b068edf8f212945cb09cf33df30ace54f4a063fcca0b732f4b662dc4e2454", 16)).ToByteArray();
+
+        //
+        // ISO 9796-2
+        //
+        static BigInteger mod3 = new BigInteger("ffffffff78f6c55506c59785e871211ee120b0b5dd644aa796d82413a47b24573f1be5745b5cd9950f6b389b52350d4e01e90009669a8720bf265a2865994190a661dea3c7828e2e7ca1b19651adc2d5", 16);
+
+        static BigInteger pub3 = new BigInteger("03", 16);
+
+        static BigInteger pri3 = new BigInteger("2aaaaaaa942920e38120ee965168302fd0301d73a4e60c7143ceb0adf0bf30b9352f50e8b9e4ceedd65343b2179005b2f099915e4b0c37e41314bb0821ad8330d23cba7f589e0f129b04c46b67dfce9d", 16);
+
+        static BigInteger mod4 = new BigInteger("FFFFFFFF45f1903ebb83d4d363f70dc647b839f2a84e119b8830b2dec424a1ce0c9fd667966b81407e89278283f27ca8857d40979407fc6da4cc8a20ecb4b8913b5813332409bc1f391a94c9c328dfe46695daf922259174544e2bfbe45cc5cd", 16);
+        static BigInteger pub4 = new BigInteger("02", 16);
+        static BigInteger pri4 = new BigInteger("1fffffffe8be3207d7707a9a6c7ee1b8c8f7073e5509c2337106165bd8849439c193faccf2cd70280fd124f0507e4f94cb66447680c6b87b6599d1b61c8f3600854a618262e9c1cb1438e485e47437be036d94b906087a61ee74ab0d9a1accd8", 16);
+
+        static byte[] msg4 = Hex.Decode("6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071");
+        static byte[] sig4 = Hex.Decode("374695b7ee8b273925b4656cc2e008d41463996534aa5aa5afe72a52ffd84e118085f8558f36631471d043ad342de268b94b080bee18a068c10965f581e7f32899ad378835477064abed8ef3bd530fce");
+
+        static byte[] msg5 = Hex.Decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210");
+        static byte[] sig5 = Hex.Decode("5cf9a01854dbacaec83aae8efc563d74538192e95466babacd361d7c86000fe42dcb4581e48e4feb862d04698da9203b1803b262105104d510b365ee9c660857ba1c001aa57abfd1c8de92e47c275cae");
+
+        //
+        // scheme 2 data
+        //
+        static BigInteger mod6 = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16);
+        static BigInteger pub6 = new BigInteger("11", 16);
+        static BigInteger pri6 = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16);
+
+        //		static byte[] sig6 = new BigInteger("0073FEAF13EB12914A43FE635022BB4AB8188A8F3ABD8D8A9E4AD6C355EE920359C7F237AE36B1212FE947F676C68FE362247D27D1F298CA9302EB21F4A64C26CE44471EF8C0DFE1A54606F0BA8E63E87CDACA993BFA62973B567473B4D38FAE73AB228600934A9CC1D3263E632E21FD52D2B95C5F7023DA63DE9509C01F6C7BBC", 16).ModPow(pri6, mod6).ToByteArray();
+        static byte[] sig6 = new BigInteger("0073FEAF13EB12914A43FE635022BB4AB8188A8F3ABD8D8A9E4AD6C355EE920359C7F237AE36B1212FE947F676C68FE362247D27D1F298CA9302EB21F4A64C26CE44471EF8C0DFE1A54606F0BA8E63E87CDACA993BFA62973B567473B4D38FAE73AB228600934A9CC1D3263E632E21FD52D2B95C5F7023DA63DE9509C01F6C7BBC", 16).ModPow(pri6, mod6).ToByteArray();
+
+        static byte[] msg7 = Hex.Decode("6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70716F70717270717273");
+        static byte[] sig7 = new BigInteger("296B06224010E1EC230D4560A5F88F03550AAFCE31C805CE81E811E5E53E5F71AE64FC2A2A486B193E87972D90C54B807A862F21A21919A43ECF067240A8C8C641DE8DCDF1942CF790D136728FFC0D98FB906E7939C1EC0E64C0E067F0A7443D6170E411DF91F797D1FFD74009C4638462E69D5923E7433AEC028B9A90E633CC", 16).ModPow(pri6, mod6).ToByteArray();
+
+        static byte[] msg8 = Hex.Decode("FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA98");
+        static byte[] sig8 = new BigInteger("01402B29ABA104079677CE7FC3D5A84DB24494D6F9508B4596484F5B3CC7E8AFCC4DDE7081F21CAE9D4F94D6D2CCCB43FCEDA0988FFD4EF2EAE72CFDEB4A2638F0A34A0C49664CD9DB723315759D758836C8BA26AC4348B66958AC94AE0B5A75195B57ABFB9971E21337A4B517F2E820B81F26BCE7C66F48A2DB12A8F3D731CC", 16).ModPow(pri6, mod6).ToByteArray();
+
+        static byte[] msg9 = Hex.Decode("6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70716F707172707172737172737472737475737475767475767775767778767778797778797A78797A61797A61627A6162636162636462636465");
+        static byte[] sig9 = new BigInteger("6F2BB97571FE2EF205B66000E9DD06656655C1977F374E8666D636556A5FEEEEAF645555B25F45567C4EE5341F96FED86508C90A9E3F11B26E8D496139ED3E55ECE42860A6FB3A0817DAFBF13019D93E1D382DA07264FE99D9797D2F0B7779357CA7E74EE440D8855B7DDF15F000AC58EE3FFF144845E771907C0C83324A6FBC", 16).ModPow(pri6, mod6).ToByteArray();
+
+        public override string Name
+        {
+            get { return "ISO9796"; }
+        }
+
+        private bool IsSameAs(
+            byte[]	a,
+            int		off,
+            byte[]	b)
+        {
+            if ((a.Length - off) != b.Length)
+            {
+                return false;
+            }
+
+            for (int i = 0; i != b.Length; i++)
+            {
+                if (a[i + off] != b[i])
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private bool StartsWith(
+            byte[]	a,
+            byte[]	b)
+        {
+            if (a.Length < b.Length)
+                return false;
+
+            for (int i = 0; i != b.Length; i++)
+            {
+                if (a[i] != b[i])
+                    return false;
+            }
+
+            return true;
+        }
+
+        [Test]
+        public virtual void DoTest1()
+        {
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod1, pub1);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod1, pri1);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-1 - public encrypt, private decrypt
+            //
+            ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa);
+
+            eng.Init(true, privParameters);
+
+            eng.SetPadBits(4);
+
+            data = eng.ProcessBlock(msg1, 0, msg1.Length);
+
+            eng.Init(false, pubParameters);
+
+            if (!AreEqual(sig1, data))
+            {
+                Fail("failed ISO9796-1 generation Test 1");
+            }
+
+            data = eng.ProcessBlock(data, 0, data.Length);
+
+            if (!AreEqual(msg1, data))
+            {
+                Fail("failed ISO9796-1 retrieve Test 1");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest2()
+        {
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod1, pub1);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod1, pri1);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-1 - public encrypt, private decrypt
+            //
+            ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa);
+
+            eng.Init(true, privParameters);
+
+            data = eng.ProcessBlock(msg2, 0, msg2.Length);
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(data, 1, sig2))
+            {
+                Fail("failed ISO9796-1 generation Test 2");
+            }
+
+            data = eng.ProcessBlock(data, 0, data.Length);
+
+            if (!AreEqual(msg2, data))
+            {
+                Fail("failed ISO9796-1 retrieve Test 2");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest3()
+        {
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod2, pub2);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod2, pri2);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-1 - public encrypt, private decrypt
+            //
+            ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa);
+
+            eng.Init(true, privParameters);
+
+            eng.SetPadBits(4);
+
+            data = eng.ProcessBlock(msg3, 0, msg3.Length);
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(sig3, 1, data))
+            {
+                Fail("failed ISO9796-1 generation Test 3");
+            }
+
+            data = eng.ProcessBlock(data, 0, data.Length);
+
+            if (!IsSameAs(msg3, 0, data))
+            {
+                Fail("failed ISO9796-1 retrieve Test 3");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest4()
+        {
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod3, pub3);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod3, pri3);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-2 - Signing
+            //
+            Iso9796d2Signer eng = new Iso9796d2Signer(rsa, new RipeMD128Digest());
+
+            eng.Init(true, privParameters);
+
+            eng.Update(msg4[0]);
+            eng.BlockUpdate(msg4, 1, msg4.Length - 1);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(sig4, 0, data))
+            {
+                Fail("failed ISO9796-2 generation Test 4");
+            }
+
+            eng.Update(msg4[0]);
+            eng.BlockUpdate(msg4, 1, msg4.Length - 1);
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 4");
+            }
+
+            if (eng.HasFullMessage())
+            {
+                eng = new Iso9796d2Signer(rsa, new RipeMD128Digest());
+
+                eng.Init(false, pubParameters);
+
+                if (!eng.VerifySignature(sig4))
+                {
+                    Fail("failed ISO9796-2 verify and recover Test 4");
+                }
+
+                if(!IsSameAs(eng.GetRecoveredMessage(), 0, msg4))
+                {
+                    Fail("failed ISO9796-2 recovered message Test 4");
+                }
+
+                // try update with recovered
+                eng.UpdateWithRecoveredMessage(sig4);
+
+                if(!IsSameAs(eng.GetRecoveredMessage(), 0, msg4))
+                {
+                    Fail("failed ISO9796-2 updateWithRecovered recovered message Test 4");
+                }
+                
+                if (!eng.VerifySignature(sig4))
+                {
+                    Fail("failed ISO9796-2 updateWithRecovered verify and recover Test 4");
+                }
+                
+                if(!IsSameAs(eng.GetRecoveredMessage(), 0, msg4))
+                {
+                    Fail("failed ISO9796-2 updateWithRecovered recovered verify message Test 4");
+                }
+                
+                // should fail
+                eng.UpdateWithRecoveredMessage(sig4);
+                
+                eng.BlockUpdate(msg4, 0, msg4.Length);
+                
+                if (eng.VerifySignature(sig4))
+                {
+                    Fail("failed ISO9796-2 updateWithRecovered verify and recover Test 4");
+                }
+            }
+            else
+            {
+                Fail("full message flag false - Test 4");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest5()
+        {
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod3, pub3);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod3, pri3);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-2 - Signing
+            //
+            Iso9796d2Signer eng = new Iso9796d2Signer(rsa, new RipeMD160Digest(), true);
+
+            eng.Init(true, privParameters);
+
+            eng.Update(msg5[0]);
+            eng.BlockUpdate(msg5, 1, msg5.Length - 1);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(sig5, 0, data))
+            {
+                Fail("failed ISO9796-2 generation Test 5");
+            }
+
+            eng.Update(msg5[0]);
+            eng.BlockUpdate(msg5, 1, msg5.Length - 1);
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 5");
+            }
+
+            if (eng.HasFullMessage())
+            {
+                Fail("fullMessage true - Test 5");
+            }
+
+            if (!StartsWith(msg5, eng.GetRecoveredMessage()))
+            {
+                Fail("failed ISO9796-2 partial recovered message Test 5");
+            }
+
+            int length = eng.GetRecoveredMessage().Length;
+
+            if (length >= msg5.Length)
+            {
+                Fail("Test 5 recovered message too long");
+            }
+
+            eng = new Iso9796d2Signer(rsa, new RipeMD160Digest(), true);
+
+            eng.Init(false, pubParameters);
+
+            eng.UpdateWithRecoveredMessage(sig5);
+
+            if (!StartsWith(msg5, eng.GetRecoveredMessage()))
+            {
+                Fail("failed ISO9796-2 updateWithRecovered partial recovered message Test 5");
+            }
+
+            if (eng.HasFullMessage())
+            {
+                Fail("fullMessage updateWithRecovered true - Test 5");
+            }
+
+            for (int i = length ; i != msg5.Length; i++)
+            {
+                eng.Update(msg5[i]);
+            }
+
+            if (!eng.VerifySignature(sig5))
+            {
+                Fail("failed ISO9796-2 verify Test 5");
+            }
+
+            if (eng.HasFullMessage())
+            {
+                Fail("fullMessage updateWithRecovered true - Test 5");
+            }
+
+            // should fail
+            eng.UpdateWithRecoveredMessage(sig5);
+
+            eng.BlockUpdate(msg5, 0, msg5.Length);
+
+            if (eng.VerifySignature(sig5))
+            {
+                Fail("failed ISO9796-2 updateWithRecovered verify fail Test 5");
+            }
+        }
+
+        //
+        // against a zero length string
+        //
+        [Test]
+        public virtual void DoTest6()
+        {
+            byte[] salt = Hex.Decode("61DF870C4890FE85D6E3DD87C3DCE3723F91DB49");
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod6, pub6);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod6, pri6);
+            ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-2 - PSS Signing
+            //
+            Iso9796d2PssSigner eng = new Iso9796d2PssSigner(rsa, new RipeMD160Digest(), 20, true);
+
+            eng.Init(true, sigParameters);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(sig6, 1, data))
+            {
+                Fail("failed ISO9796-2 generation Test 6");
+            }
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 6");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest7()
+        {
+            byte[] salt = new byte[0];
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod6, pub6);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod6, pri6);
+            ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-2 - PSS Signing
+            //
+            Iso9796d2PssSigner eng = new Iso9796d2PssSigner(rsa, new Sha1Digest(), 0, false);
+
+            eng.Init(true, sigParameters);
+
+            eng.Update(msg7[0]);
+            eng.BlockUpdate(msg7, 1, msg7.Length - 1);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(sig7, 0, data))
+            {
+                Fail("failed ISO9796-2 generation Test 7");
+            }
+
+            eng.Update(msg7[0]);
+            eng.BlockUpdate(msg7, 1, msg7.Length - 1);
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 7");
+            }
+
+            if (!IsSameAs(msg7, 0, eng.GetRecoveredMessage()))
+            {
+                Fail("failed ISO9796-2 recovery Test 7");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest8()
+        {
+            byte[] salt = Hex.Decode("78E293203CBA1B7F92F05F4D171FF8CA3E738FF8");
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod6, pub6);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod6, pri6);
+            ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-2 - PSS Signing
+            //
+            Iso9796d2PssSigner eng = new Iso9796d2PssSigner(rsa, new RipeMD160Digest(), 20, false);
+
+            eng.Init(true, sigParameters);
+
+            eng.Update(msg8[0]);
+            eng.BlockUpdate(msg8, 1, msg8.Length - 1);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(sig8, 0, data))
+            {
+                Fail("failed ISO9796-2 generation Test 8");
+            }
+
+            eng.Update(msg8[0]);
+            eng.BlockUpdate(msg8, 1, msg8.Length - 1);
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 8");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest9()
+        {
+            RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod6, pub6);
+            RsaKeyParameters privParameters = new RsaKeyParameters(true, mod6, pri6);
+            RsaEngine rsa = new RsaEngine();
+            byte[] data;
+
+            //
+            // ISO 9796-2 - PSS Signing
+            //
+            Iso9796d2PssSigner eng = new Iso9796d2PssSigner(rsa, new RipeMD160Digest(), 0, true);
+
+            eng.Init(true, privParameters);
+
+            eng.Update(msg9[0]);
+            eng.BlockUpdate(msg9, 1, msg9.Length - 1);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            if (!IsSameAs(sig9, 0, data))
+            {
+                Fail("failed ISO9796-2 generation Test 9");
+            }
+
+            eng.Update(msg9[0]);
+            eng.BlockUpdate(msg9, 1, msg9.Length - 1);
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 9");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest10()
+        {
+            BigInteger          mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16);
+            BigInteger          pubExp = new BigInteger("65537", 10);
+            BigInteger          priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16);
+            RsaKeyParameters    pubParameters = new RsaKeyParameters(false, mod, pubExp);
+            RsaKeyParameters    privParameters = new RsaKeyParameters(true, mod, priExp);
+            RsaEngine           rsa = new RsaEngine();
+            byte[]              data;
+
+            //
+            // ISO 9796-2 - PSS Signing
+            //
+            IDigest              dig = new Sha1Digest();
+            Iso9796d2PssSigner  eng = new Iso9796d2PssSigner(rsa, dig, dig.GetDigestSize());
+
+            //
+            // as the padding is random this test needs to repeat a few times to
+            // make sure
+            //
+            for (int i = 0; i != 500; i++)
+            {
+                eng.Init(true, privParameters);
+
+                eng.Update(msg9[0]);
+                eng.BlockUpdate(msg9, 1, msg9.Length - 1);
+
+                data = eng.GenerateSignature();
+
+                eng.Init(false, pubParameters);
+
+                eng.Update(msg9[0]);
+                eng.BlockUpdate(msg9, 1, msg9.Length - 1);
+
+                if (!eng.VerifySignature(data))
+                {
+                    Fail("failed ISO9796-2 verify Test 10");
+                }
+            }
+        }
+
+        [Test]
+        public virtual void DoTest11()
+        {
+            BigInteger          mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16);
+            BigInteger          pubExp = new BigInteger("65537", 10);
+            BigInteger          priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16);
+            RsaKeyParameters    pubParameters = new RsaKeyParameters(false, mod, pubExp);
+            RsaKeyParameters    privParameters = new RsaKeyParameters(true, mod, priExp);
+            RsaEngine           rsa = new RsaEngine();
+            byte[]              data;
+            byte[]              m1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+            byte[]              m2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+            byte[]              m3 = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+            //
+            // ISO 9796-2 - PSS Signing
+            //
+            IDigest              dig = new Sha1Digest();
+            Iso9796d2PssSigner  eng = new Iso9796d2PssSigner(rsa, dig, dig.GetDigestSize());
+
+            //
+            // check message bounds
+            //
+            eng.Init(true, privParameters);
+
+            eng.BlockUpdate(m1, 0, m1.Length);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            eng.BlockUpdate(m2, 0, m2.Length);
+
+            if (eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 m2 verify Test 11");
+            }
+
+            eng.Init(false, pubParameters);
+
+            eng.BlockUpdate(m3, 0, m3.Length);
+
+            if (eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 m3 verify Test 11");
+            }
+
+            eng.Init(false, pubParameters);
+
+            eng.BlockUpdate(m1, 0, m1.Length);
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 11");
+            }
+        }
+
+        [Test]
+        public virtual void DoTest12()
+        {
+            BigInteger          mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16);
+            BigInteger          pubExp = new BigInteger("65537", 10);
+            BigInteger          priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16);
+            RsaKeyParameters    pubParameters = new RsaKeyParameters(false, mod, pubExp);
+            RsaKeyParameters    privParameters = new RsaKeyParameters(true, mod, priExp);
+            RsaEngine           rsa = new RsaEngine();
+            byte[]              data;
+            byte[]              m1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+            byte[]              m2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+            byte[]              m3 = { 1, 2, 3, 4, 5, 6, 7, 8 };
+
+            //
+            // ISO 9796-2 - Regular Signing
+            //
+            IDigest           dig = new Sha1Digest();
+            Iso9796d2Signer  eng = new Iso9796d2Signer(rsa, dig);
+
+            //
+            // check message bounds
+            //
+            eng.Init(true, privParameters);
+
+            eng.BlockUpdate(m1, 0, m1.Length);
+
+            data = eng.GenerateSignature();
+
+            eng.Init(false, pubParameters);
+
+            eng.BlockUpdate(m2, 0, m2.Length);
+
+            if (eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 m2 verify Test 12");
+            }
+
+            eng.Init(false, pubParameters);
+
+            eng.BlockUpdate(m3, 0, m3.Length);
+
+            if (eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 m3 verify Test 12");
+            }
+
+            eng.Init(false, pubParameters);
+
+            eng.BlockUpdate(m1, 0, m1.Length);
+
+            if (!eng.VerifySignature(data))
+            {
+                Fail("failed ISO9796-2 verify Test 12");
+            }
+        }
+
+        [Test]
+        public void DoTest13()
+        {
+            BigInteger modulus = new BigInteger(1, Hex.Decode("CDCBDABBF93BE8E8294E32B055256BBD0397735189BF75816341BB0D488D05D627991221DF7D59835C76A4BB4808ADEEB779E7794504E956ADC2A661B46904CDC71337DD29DDDD454124EF79CFDD7BC2C21952573CEFBA485CC38C6BD2428809B5A31A898A6B5648CAA4ED678D9743B589134B7187478996300EDBA16271A861"));
+            BigInteger pubExp = new BigInteger(1, Hex.Decode("010001"));
+            BigInteger privExp = new BigInteger(1, Hex.Decode("4BA6432AD42C74AA5AFCB6DF60FD57846CBC909489994ABD9C59FE439CC6D23D6DE2F3EA65B8335E796FD7904CA37C248367997257AFBD82B26F1A30525C447A236C65E6ADE43ECAAF7283584B2570FA07B340D9C9380D88EAACFFAEEFE7F472DBC9735C3FF3A3211E8A6BBFD94456B6A33C17A2C4EC18CE6335150548ED126D"));
+
+            RsaKeyParameters pubParams = new RsaKeyParameters(false, modulus, pubExp);
+            RsaKeyParameters privParams = new RsaKeyParameters(true, modulus, privExp);
+
+            IAsymmetricBlockCipher rsaEngine = new RsaBlindedEngine();
+            IDigest digest = new Sha256Digest();
+
+            // set challenge to all zero's for verification
+            byte[] challenge = new byte[8];
+
+            // DOES NOT USE FINAL BOOLEAN TO INDICATE RECOVERY
+            Iso9796d2Signer signer = new Iso9796d2Signer(rsaEngine, digest, false);
+
+            // sign
+            signer.Init(true, privParams);
+            signer.BlockUpdate(challenge, 0, challenge.Length);
+
+            byte[]  sig = signer.GenerateSignature();
+
+            // verify
+            signer.Init(false, pubParams);
+            signer.BlockUpdate(challenge, 0, challenge.Length);
+
+            if (!signer.VerifySignature(sig))
+            {
+                Fail("basic verification failed");
+            }
+
+            // === LETS ACTUALLY DO SOME RECOVERY, USING INPUT FROM INTERNAL AUTHENTICATE ===
+
+            signer.Reset();
+
+            string args0 = "482E20D1EDDED34359C38F5E7C01203F9D6B2641CDCA5C404D49ADAEDE034C7481D781D043722587761C90468DE69C6585A1E8B9C322F90E1B580EEDAB3F6007D0C366CF92B4DB8B41C8314929DCE2BE889C0129123484D2FD3D12763D2EBFD12AC8E51D7061AFCA1A53DEDEC7B9A617472A78C952CCC72467AE008E5F132994";
+
+            digest = new Sha1Digest();
+
+            signer = new Iso9796d2Signer(rsaEngine, digest, true);
+
+
+            signer.Init(false, pubParams);
+            byte[] signature = Hex.Decode(args0);
+            signer.UpdateWithRecoveredMessage(signature);
+            signer.BlockUpdate(challenge, 0, challenge.Length);
+
+            if (!signer.VerifySignature(signature))
+            {
+                Fail("recovered + challenge signature failed");
+            }
+
+            // === FINALLY, USING SHA-256 ===
+
+            signer.Reset();
+
+            digest = new Sha256Digest();
+
+            // NOTE setting implicit to false does not actually do anything for verification !!!
+            signer = new Iso9796d2Signer(rsaEngine, digest, false);
+
+
+            signer.Init(true, privParams);
+            // generate NONCE of correct length using some inner knowledge
+            int nonceLength = modulus.BitLength / 8 - 1 - digest.GetDigestSize() - 2;
+            byte[] nonce = new byte[nonceLength];
+            SecureRandom rnd = new SecureRandom();
+
+            rnd.NextBytes(nonce);
+
+            signer.BlockUpdate(nonce, 0, nonce.Length);
+            signer.BlockUpdate(challenge, 0, challenge.Length);
+            byte[] sig3 = signer.GenerateSignature();
+
+            signer.Init(false, pubParams);
+            signer.UpdateWithRecoveredMessage(sig3);
+            signer.BlockUpdate(challenge, 0, challenge.Length);
+            if (signer.VerifySignature(sig3))
+            {
+                if (signer.HasFullMessage())
+                {
+                    Fail("signer indicates full message");
+                }
+                byte[] recoverableMessage = signer.GetRecoveredMessage();
+
+                // sanity check, normally the nonce is ignored in eMRTD specs (PKI Technical Report)
+                if (!Arrays.AreEqual(nonce, recoverableMessage))
+                {
+                    Fail("Nonce compare with recoverable part of message failed");
+                }
+            }
+            else
+            {
+                Fail("recoverable + nonce failed.");
+            }
+        }
+
+        private static readonly byte[] longMessage = Base64.Decode(
+            "VVNIKzErU0U2ODAxNTMyOTcxOSsyKzErNisyKzErMTo6OTk5OTk5OTk5OTk5"
+          + "OTo6OSsyOjo3Nzc3Nzc3Nzc3Nzc3Ojo5Kys1OjIwMTMwNDA1OjExMzUyMCdV"
+          + "U0ErMTo6OjE2OjEnVVNDKzRmYjk3YzFhNDI5ZGIyZDYnVVNBKzY6MTY6MTox"
+          + "MDoxKzE0OjIwNDgrMTI6/vn3S0h96eNhfmPN6OZUxXhd815h0tP871Hl+V1r"
+          + "fHHUXvrPXmjHV0vdb8fYY1zxwvnQUcFBWXT43PFi7Xbow0/9e9l6/mhs1UJq"
+          + "VPvp+ELbeXfn4Nj02ttk0e3H5Hfa69NYRuHv1WBO6lfizNnM9m9XYmh9TOrg"
+          + "f9rDRtd+ZNbf4lz9fPTt9OXyxOJWRPr/0FLzxUVsddplfHxM3ndETFD7ffjI"
+          + "/mhRYuL8WXZ733LeWFRCeOzKzmDz/HvT3GZx/XJMbFpqyOZjedzh6vZr1vrD"
+          + "615TQfN7wtJJ29bN2Hvzb2f1xGHaXl7af0/w9dpR2dr7/HzuZEJKYc7JSkv4"
+          + "/k37yERIbcrfbVTeVtR+dcVoeeRT41fmzMfzf8RnWOX4YMNifl0rMTM68EFA"
+          + "QSdCR00rMzgwKzk5OTk5OTk5J0RUTSsxMzc6MjAxMzA0MDU6MTAyJ0ZUWCtB"
+          + "QUkrKytJTlZPSUNFIFRFU1QnUkZGK09OOjEyMzQ1NidSRkYrRFE6MjIyMjIy"
+          + "MjIyJ0RUTSsxNzE6MjAxMzA0MDE6MTAyJ05BRCtTVSs5OTk5OTk5OTk5OTk5"
+          + "Ojo5KytURVNUIFNVUFBMSUVSOjpUcmFzZSByZWdpc3RlciBYWFhYWFhYK1Rl"
+          + "c3QgYWRkcmVzcyBzdXBwbGllcitDaXR5KysxMjM0NStERSdSRkYrVkE6QTEy"
+          + "MzQ1Njc4J05BRCtTQ08rOTk5OTk5OTk5OTk5OTo6OSsrVEVTVCBTVVBQTElF"
+          + "Ujo6VHJhc2UgcmVnaXN0ZXIgWFhYWFhYWCtUZXN0IGFkZHJlc3Mgc3VwcGxp"
+          + "ZXIrQ2l0eSsrMTIzNDUrREUnUkZGK1ZBOkExMjM0NTY3OCdOQUQrQlkrODg4"
+          + "ODg4ODg4ODg4ODo6OSdOQUQrSVYrNzc3Nzc3Nzc3Nzc3Nzo6OSsrVEVTVCBC"
+          + "VVlFUitUZXN0IGFkZHJlc3MgYnV5ZXIrQ2l0eTIrKzU0MzIxK0RFJ1JGRitW"
+          + "QTpKODc2NTQzMjEnTkFEK0JDTys3Nzc3Nzc3Nzc3Nzc3Ojo5KytURVNUIEJV"
+          + "WUVSK1Rlc3QgYWRkcmVzcyBidXllcitDaXR5MisrNTQzMjErREUnUkZGK1ZB"
+          + "Oko4NzY1NDMyMSdOQUQrRFArODg4ODg4ODg4ODg4ODo6OSdOQUQrUFIrNzc3"
+          + "Nzc3Nzc3Nzc3Nzo6OSdDVVgrMjpFVVI6NCdQQVQrMzUnRFRNKzEzOjIwMTMw"
+          + "NjI0OjEwMidMSU4rMSsrMTExMTExMTExMTExMTpFTidQSUErMStBQUFBQUFB"
+          + "OlNBJ0lNRCtGK00rOjo6UFJPRFVDVCBURVNUIDEnUVRZKzQ3OjEwLjAwMCdN"
+          + "T0ErNjY6Ny4wMCdQUkkrQUFCOjEuMDAnUFJJK0FBQTowLjcwJ1JGRitPTjox"
+          + "MjM0NTYnUkZGK0RROjIyMjIyMjIyMidUQVgrNytWQVQrKys6OjoyMS4wMDAn"
+          + "QUxDK0ErKysxK1REJ1BDRCsxOjMwLjAwMCdNT0ErMjA0OjMuMDAnTElOKzIr"
+          + "KzIyMjIyMjIyMjIyMjI6RU4nUElBKzErQkJCQkJCQjpTQSdJTUQrRitNKzo6"
+          + "OlBST0RVQ1QgVEVTVCAyJ1FUWSs0NzoyMC4wMDAnTU9BKzY2OjgwLjAwJ1BS"
+          + "SStBQUI6NS4wMCdQUkkrQUFBOjQuMDAnUkZGK09OOjEyMzQ1NidSRkYrRFE6"
+          + "MjIyMjIyMjIyJ1RBWCs3K1ZBVCsrKzo6OjIxLjAwMCdBTEMrQSsrKzErVEQn"
+          + "UENEKzE6MjAuMDAwJ01PQSsyMDQ6MjAuMDAnVU5TK1MnQ05UKzI6MidNT0Er"
+          + "Nzk6ODcuMDAnTU9BKzEzOToxMDUuMjcnTU9BKzEyNTo4Ny4wMCdNT0ErMjYw"
+          + "OjAuMDAnTU9BKzI1OTowLjAwJ01PQSsxNzY6MTguMjcnVEFYKzcrVkFUKysr"
+          + "Ojo6MjEuMDAwJ01PQSsxNzY6MTguMjcnTU9BKzEyNTo4Ny4wMCc=");
+
+        private static readonly byte[] shortPartialSig = Base64.Decode(
+            "sb8yyKk6HM1cJhICScMx7QRQunRyrZ1fbI42+T+TBGNjOknvzKuvG7aftGX7"
+          + "O/RXuYgk6LTxpXv7+O5noUhMBsR2PKaHveuylU1WSPmDxDCui3kp4frqVH0w"
+          + "8Vjpl5CsKqBsmKkbGCKE+smM0xFXhYxV8QUTB2XsWNCQiFiHPgwbpfWzZUNY"
+          + "QPWd0A99P64EuUIYz1tkkDnLFmwQ19/PJu1a8orIQInmkVYWSsBsZ/7Ks6lx"
+          + "nDHpAvgiRe+OXmJ/yuQy1O3FJYdyoqvjYRPBu3qYeBK9+9L3lExLilImH5aD"
+          + "nJznaXcO8QFOxVPbrF2s4GdPIMDonEyAHdrnzoghlg==");
+
+        [Test]
+        public void DoShortPartialTest()
+        {
+            byte[]     recovered = Hex.Decode("5553482b312b534536383031353332393731392b322b312b362b322b312b313a3a393939393939393939393939393a3a392b323a3a373737373737373737373737373a3a392b2b353a32303133303430353a313133");
+            BigInteger exp = new BigInteger("10001", 16);
+            BigInteger mod = new BigInteger("b9b70b083da9e37e23cde8e654855db31e21d2d3fc11a5f91d2b3c311efa8f5e28c757dd6fc798631cb1b9d051c14119749cb122ad76e8c3fd7bd93abe282c026a14fba9f8023977a7a0d8b49a24d1ad87e4379a931846a1ef9520ea57e28c998cf65722683d0caaa0da8306973e2496a25cbd3cb4adb4b284e25604fabf12f385456c75da7c3c4cde37440cfb7db8c8fe6851e2bc59767b9f7218540238ac8acef3bc7bd3dc6671320c2c1a2ac8a6799ce1eaf62b9683ab1e1341b37b9249dbd6cd987b2f27b5c4619a1eda7f0fb0b59a519afbbc3cee640261cec90a4bb8fefbc844082dca9f549e56943e758579a453a357e6ccb37fc46718a5b8c3227e5d", 16);
+
+            AsymmetricKeyParameter pubKey = new RsaKeyParameters(false, mod, exp);
+
+            Iso9796d2PssSigner pssSign = new Iso9796d2PssSigner(new RsaEngine(), new Sha1Digest(), 20);
+
+            pssSign.Init(false, pubKey);
+
+            pssSign.UpdateWithRecoveredMessage(shortPartialSig);
+
+            byte[] recoveredMessage = pssSign.GetRecoveredMessage();
+            pssSign.BlockUpdate(longMessage, recoveredMessage.Length, longMessage.Length - recoveredMessage.Length);
+
+            if (!pssSign.VerifySignature(shortPartialSig))
+            {
+                Fail("short partial PSS sig verification failed.");
+            }
+
+            byte[] mm = pssSign.GetRecoveredMessage();
+
+            if (!Arrays.AreEqual(recovered, mm))
+            {
+                Fail("short partial PSS recovery failed");
+            }
+        }
+
+        [Test]
+        public void DoFullMessageTest()
+        {
+            BigInteger modulus = new BigInteger(1, Hex.Decode("CDCBDABBF93BE8E8294E32B055256BBD0397735189BF75816341BB0D488D05D627991221DF7D59835C76A4BB4808ADEEB779E7794504E956ADC2A661B46904CDC71337DD29DDDD454124EF79CFDD7BC2C21952573CEFBA485CC38C6BD2428809B5A31A898A6B5648CAA4ED678D9743B589134B7187478996300EDBA16271A861"));
+            BigInteger pubExp = new BigInteger(1, Hex.Decode("010001"));
+            BigInteger privExp = new BigInteger(1, Hex.Decode("4BA6432AD42C74AA5AFCB6DF60FD57846CBC909489994ABD9C59FE439CC6D23D6DE2F3EA65B8335E796FD7904CA37C248367997257AFBD82B26F1A30525C447A236C65E6ADE43ECAAF7283584B2570FA07B340D9C9380D88EAACFFAEEFE7F472DBC9735C3FF3A3211E8A6BBFD94456B6A33C17A2C4EC18CE6335150548ED126D"));
+            RsaKeyParameters pubParams = new RsaKeyParameters(false, modulus, pubExp);
+            RsaKeyParameters privParams = new RsaKeyParameters(true, modulus, privExp);
+
+            IAsymmetricBlockCipher rsaEngine = new RsaBlindedEngine();
+
+            // set challenge to all zero's for verification
+            byte[] challenge = new byte[8];
+
+            Iso9796d2PssSigner pssSign = new Iso9796d2PssSigner(new RsaEngine(), new Sha256Digest(), 20, true);
+
+            pssSign.Init(true, privParams);
+
+            pssSign.BlockUpdate(challenge, 0, challenge.Length);
+
+            byte[] sig = pssSign.GenerateSignature();
+
+            pssSign.Init(false, pubParams);
+
+            pssSign.UpdateWithRecoveredMessage(sig);
+
+            if (!pssSign.VerifySignature(sig))
+            {
+                Fail("challenge PSS sig verification failed.");
+            }
+
+            byte[] mm = pssSign.GetRecoveredMessage();
+
+            if (!Arrays.AreEqual(challenge, mm))
+            {
+                Fail("challenge partial PSS recovery failed");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            DoTest1();
+            DoTest2();
+            DoTest3();
+            DoTest4();
+            DoTest5();
+            DoTest6();
+            DoTest7();
+            DoTest8();
+            DoTest9();
+            DoTest10();
+            DoTest11();
+            DoTest12();
+            DoTest13();
+            DoShortPartialTest();
+            DoFullMessageTest();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ISO9796Test());
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ISO9797Alg3MacTest.cs b/crypto/test/src/crypto/test/ISO9797Alg3MacTest.cs
new file mode 100644
index 000000000..9d5d8b6b7
--- /dev/null
+++ b/crypto/test/src/crypto/test/ISO9797Alg3MacTest.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class ISO9797Alg3MacTest
+		: SimpleTest
+	{
+		static byte[] keyBytes = Hex.Decode("7CA110454A1A6E570131D9619DC1376E");
+		static byte[] ivBytes = Hex.Decode("0000000000000000");
+
+		static byte[] input1 = Encoding.ASCII.GetBytes("Hello World !!!!");
+
+		static byte[] output1 = Hex.Decode("F09B856213BAB83B");
+
+		public ISO9797Alg3MacTest()
+		{
+		}
+
+		public override void PerformTest()
+		{
+			KeyParameter key = new KeyParameter(keyBytes);
+			IBlockCipher cipher = new DesEngine();
+			IMac mac = new ISO9797Alg3Mac(cipher);
+
+			//
+			// standard DAC - zero IV
+			//
+			mac.Init(key);
+
+			mac.BlockUpdate(input1, 0, input1.Length);
+
+			byte[] outBytes = new byte[8];
+
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, output1))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output1) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			//
+			//  reset
+			//
+			mac.Reset();
+
+			mac.Init(key);
+
+			for (int i = 0; i != input1.Length / 2; i++)
+			{
+				mac.Update(input1[i]);
+			}
+
+			mac.BlockUpdate(input1, input1.Length / 2, input1.Length - (input1.Length / 2));
+
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, output1))
+			{
+				Fail("Reset failed - expected " + Hex.ToHexString(output1) + " got " + Hex.ToHexString(outBytes));
+			}
+		}
+
+		public override string Name
+		{
+			get
+			{
+				return "ISO9797Alg3Mac";
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ISO9797Alg3MacTest test = new ISO9797Alg3MacTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/KDF1GeneratorTest.cs b/crypto/test/src/crypto/test/KDF1GeneratorTest.cs
new file mode 100644
index 000000000..89c8d5453
--- /dev/null
+++ b/crypto/test/src/crypto/test/KDF1GeneratorTest.cs
@@ -0,0 +1,103 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * KDF1 tests - vectors from ISO 18033.
+	 */
+	[TestFixture]
+	public class Kdf1GeneratorTest
+		: SimpleTest
+	{
+		private byte[] seed1 = Hex.Decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d");
+		private byte[] mask1 = Hex.Decode(
+			"0742ba966813af75536bb6149cc44fc256fd6406df79665bc31dc5"
+			+ "a62f70535e52c53015b9d37d412ff3c1193439599e1b628774c50d9c"
+			+ "cb78d82c425e4521ee47b8c36a4bcffe8b8112a89312fc04420a39de"
+			+ "99223890e74ce10378bc515a212b97b8a6447ba6a8870278");
+
+		private byte[] seed2 = Hex.Decode(
+			"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741"
+			+ "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4");
+		private byte[] mask2 = Hex.Decode(
+			"5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca9"
+			+ "75bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263c"
+			+ "fccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e"
+			+ "7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04");
+
+		private byte[] seed3;
+		private byte[] mask3= Hex.Decode(
+			"09e2decf2a6e1666c2f6071ff4298305e2643fd510a2403db42a8743cb989de86e"
+			+ "668d168cbe604611ac179f819a3d18412e9eb45668f2923c087c12fee0c5a0d2a8aa"
+			+ "70185401fbbd99379ec76c663e875a60b4aacb1319fa11c3365a8b79a44669f26fb5"
+			+ "55c80391847b05eca1cb5cf8c2d531448d33fbaca19f6410ee1fcb");
+
+		public Kdf1GeneratorTest()
+		{
+			seed3 = seed2;
+		}
+
+		public override void PerformTest()
+		{
+			checkMask(1, new Kdf1BytesGenerator(new ShortenedDigest(new Sha256Digest(), 20)), seed1, mask1);
+			checkMask(2, new Kdf1BytesGenerator(new Sha1Digest()), seed2, mask2);
+			checkMask(3, new Kdf1BytesGenerator(new ShortenedDigest(new Sha256Digest(), 20)), seed3, mask3);
+
+			try
+			{
+				new Kdf1BytesGenerator(new Sha1Digest()).GenerateBytes(new byte[10], 0, 20);
+
+				Fail("short input array not caught");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+		}
+
+		private void checkMask(
+			int					count,
+			IDerivationFunction	kdf,
+			byte[]				seed,
+			byte[]				result)
+		{
+			byte[] data = new byte[result.Length];
+
+			kdf.Init(new Iso18033KdfParameters(seed));
+
+			kdf.GenerateBytes(data, 0, data.Length);
+
+			if (!AreEqual(result, data))
+			{
+				Fail("KDF1 failed generator test " + count);
+			}
+		}
+
+		public override string Name
+		{
+			get { return "KDF1"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Kdf1GeneratorTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/KDF2GeneratorTest.cs b/crypto/test/src/crypto/test/KDF2GeneratorTest.cs
new file mode 100644
index 000000000..e184e0b40
--- /dev/null
+++ b/crypto/test/src/crypto/test/KDF2GeneratorTest.cs
@@ -0,0 +1,115 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* KDF2 tests - vectors from ISO 18033.
+	*/
+	[TestFixture]
+	public class Kdf2GeneratorTest
+		: SimpleTest
+	{
+		private static readonly byte[] seed1 = Hex.Decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d");
+		private static readonly byte[] mask1 = Hex.Decode(
+			"df79665bc31dc5a62f70535e52c53015b9d37d412ff3c119343959"
+			+ "9e1b628774c50d9ccb78d82c425e4521ee47b8c36a4bcffe8b8112a8"
+			+ "9312fc04420a39de99223890e74ce10378bc515a212b97b8a6447ba6"
+			+ "a8870278f0262727ca041fa1aa9f7b5d1cf7f308232fe861");
+
+		private static readonly byte[] seed2 = Hex.Decode(
+			"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741"
+			+ "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4");
+		private static readonly byte[] mask2 = Hex.Decode(
+			"10a2403db42a8743cb989de86e668d168cbe604611ac179f819a3d18412e9eb456"
+			+ "68f2923c087c12fee0c5a0d2a8aa70185401fbbd99379ec76c663e875a60b4aacb13"
+			+ "19fa11c3365a8b79a44669f26fb555c80391847b05eca1cb5cf8c2d531448d33fbac"
+			+ "a19f6410ee1fcb260892670e0814c348664f6a7248aaf998a3acc6");
+		private static readonly byte[] adjustedMask2 = Hex.Decode(
+			"10a2403db42a8743cb989de86e668d168cbe6046e23ff26f741e87949a3bba1311ac1"
+			+ "79f819a3d18412e9eb45668f2923c087c1299005f8d5fd42ca257bc93e8fee0c5a0d2"
+			+ "a8aa70185401fbbd99379ec76c663e9a29d0b70f3fe261a59cdc24875a60b4aacb131"
+			+ "9fa11c3365a8b79a44669f26fba933d012db213d7e3b16349");
+
+		private static readonly byte[] sha1Mask = Hex.Decode(
+			"0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d800c46954840ff32"
+			+ "052cdf0d640562bdfadfa263cfccf3c52b29f2af4a1869959bc77f854cf15bd7a2519"
+			+ "2985a842dbff8e13efee5b7e7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837ee"
+			+ "a4e0a2f04b53ca8f50fb31225c1be2d0126c8c7a4753b0807");
+
+		private static readonly byte[] seed3 = Hex.Decode("CA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A");
+		private static readonly byte[] mask3 = Hex.Decode("744AB703F5BC082E59185F6D049D2D367DB245C2");
+
+		private static readonly byte[] seed4 = Hex.Decode("0499B502FC8B5BAFB0F4047E731D1F9FD8CD0D8881");
+		private static readonly byte[] mask4 = Hex.Decode("03C62280C894E103C680B13CD4B4AE740A5EF0C72547292F82DC6B1777F47D63BA9D1EA732DBF386");
+
+		public Kdf2GeneratorTest()
+		{
+		}
+
+		public override void PerformTest()
+		{
+			checkMask(1, new Kdf2BytesGenerator(new ShortenedDigest(new Sha256Digest(), 20)), seed1, mask1);
+			checkMask(2, new Kdf2BytesGenerator(new ShortenedDigest(new Sha256Digest(), 20)), seed2, mask2);
+			checkMask(3, new Kdf2BytesGenerator(new Sha256Digest()), seed2, adjustedMask2);
+			checkMask(4, new Kdf2BytesGenerator(new Sha1Digest()), seed2, sha1Mask);
+			checkMask(5, new Kdf2BytesGenerator(new Sha1Digest()), seed3, mask3);
+			checkMask(6, new Kdf2BytesGenerator(new Sha1Digest()), seed4, mask4);
+
+			try
+			{
+				new Kdf2BytesGenerator(new Sha1Digest()).GenerateBytes(new byte[10], 0, 20);
+
+				Fail("short input array not caught");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+		}
+
+		private void checkMask(
+			int					count,
+			IDerivationFunction	kdf,
+			byte[]				seed,
+			byte[]				result)
+		{
+			byte[] data = new byte[result.Length];
+
+			kdf.Init(new KdfParameters(seed, new byte[0]));
+
+			kdf.GenerateBytes(data, 0, data.Length);
+
+			if (!AreEqual(result, data))
+			{
+				Fail("KDF2 failed generator test " + count);
+			}
+		}
+
+		public override string Name
+		{
+			get { return "KDF2"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Kdf2GeneratorTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/MD2DigestTest.cs b/crypto/test/src/crypto/test/MD2DigestTest.cs
new file mode 100644
index 000000000..4f4da516b
--- /dev/null
+++ b/crypto/test/src/crypto/test/MD2DigestTest.cs
@@ -0,0 +1,67 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for MD2
+     * from RFC1319 by B.Kaliski of RSA Laboratories April 1992
+     *
+     */
+    [TestFixture]
+    public class MD2DigestTest
+        : DigestTest
+    {
+        static string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "message digest",
+            "abcdefghijklmnopqrstuvwxyz",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+            "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+        };
+
+        static string[] digests =
+        { 
+            "8350e5a3e24c153df2275c9f80692773",
+            "32ec01ec4a6dac72c0ab96fb34c0b5d1",
+            "da853b0d3f88d99b30283a69e6ded6bb",
+            "ab4f496bfb2a530b219ff33031fe06b0",
+            "4e8ddff3650292ab5a4108c3aa47940b",
+            "da33def2a42df13975352846c30338cd",
+            "d5976f79d83d3a0dc9806c3c66f3efd8" 
+        };
+
+        public MD2DigestTest()
+            : base(new MD2Digest(), messages, digests)
+        {
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new MD2Digest((MD2Digest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new MD2DigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/MD4DigestTest.cs b/crypto/test/src/crypto/test/MD4DigestTest.cs
new file mode 100644
index 000000000..4fd4e0931
--- /dev/null
+++ b/crypto/test/src/crypto/test/MD4DigestTest.cs
@@ -0,0 +1,59 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for MD4 from RFC 1320.
+     */
+    [TestFixture]
+    public class MD4DigestTest
+        : DigestTest
+    {
+        static private string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+        };
+
+        static private string[] digests =
+        {
+            "31d6cfe0d16ae931b73c59d7e0c089c0",
+            "bde52cb31de33e46245e05fbdbd6fb24",
+            "a448017aaf21d8525fc10ae87aa6729d",
+            "e33b4ddc9c38f2199c3e7b164fcc0536"
+        };
+
+        public MD4DigestTest()
+            : base(new MD4Digest(), messages, digests)
+        {
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new MD4Digest((MD4Digest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new MD4DigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/MD5DigestTest.cs b/crypto/test/src/crypto/test/MD5DigestTest.cs
new file mode 100644
index 000000000..cc914165c
--- /dev/null
+++ b/crypto/test/src/crypto/test/MD5DigestTest.cs
@@ -0,0 +1,59 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for MD5 from "Handbook of Applied Cryptography", page 345.
+     */
+    [TestFixture]
+    public class MD5DigestTest
+        : DigestTest
+    {
+        static string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "abcdefghijklmnopqrstuvwxyz"
+        };
+
+        static string[] digests =
+        {
+            "d41d8cd98f00b204e9800998ecf8427e",
+            "0cc175b9c0f1b6a831c399e269772661",
+            "900150983cd24fb0d6963f7d28e17f72",
+            "c3fcd3d76192e4007dfb496cca67e13b"
+        };
+
+        public MD5DigestTest()
+            : base(new MD5Digest(), messages, digests)
+        {
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new MD5Digest((MD5Digest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new MD5DigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/MD5HMacTest.cs b/crypto/test/src/crypto/test/MD5HMacTest.cs
new file mode 100644
index 000000000..101b8be3c
--- /dev/null
+++ b/crypto/test/src/crypto/test/MD5HMacTest.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <remarks> MD5 HMac Test, test vectors from RFC 2202</remarks>
+    [TestFixture]
+    public class MD5HMacTest
+		: ITest
+    {
+        public string Name
+        {
+			get { return "MD5HMac"; }
+        }
+
+		internal static readonly string[] keys = new string[]{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "4a656665", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "0102030405060708090a0b0c0d0e0f10111213141516171819", "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
+        internal static readonly string[] digests = new string[]{"9294727a3638bb1c13f48ef8158bfc9d", "750c783e6ab0b503eaa86e310a5db738", "56be34521d144c88dbb8c733f0e8b3f6", "697eaf0aca3a3aea3a75164746ffaa79", "56461ef2342edc00f9bab995690efd4c", "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd", "6f630fad67cda0ee1fb1f562db3aa53e"};
+        internal static readonly string[] messages = new string[]{"Hi There", "what do ya want for nothing?", "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", "Test With Truncation", "Test Using Larger Than Block-Size Key - Hash Key First", "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"};
+
+		public virtual ITestResult Perform()
+        {
+            HMac hmac = new HMac(new MD5Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+			for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + "Vector " + i + " failed");
+                }
+            }
+
+			// test reset
+            int vector = 0; // vector used for test
+            byte[] m2 = Encoding.ASCII.GetBytes(messages[vector]);
+            if (messages[vector].StartsWith("0x"))
+            {
+                m2 = Hex.Decode(messages[vector].Substring(2));
+            }
+            hmac.Init(new KeyParameter(Hex.Decode(keys[vector])));
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+            hmac.Reset();
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+
+			if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[vector])))
+            {
+                return new SimpleTestResult(false, Name + "Reset with vector " + vector + " failed");
+            }
+
+			return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            ITest test = new MD5HMacTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/MGF1GeneratorTest.cs b/crypto/test/src/crypto/test/MGF1GeneratorTest.cs
new file mode 100644
index 000000000..ee67ffa1c
--- /dev/null
+++ b/crypto/test/src/crypto/test/MGF1GeneratorTest.cs
@@ -0,0 +1,103 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * MGF1 tests - vectors from ISO 18033 for KDF1 (equivalent).
+	 */
+	[TestFixture]
+	public class Mgf1GeneratorTest
+		: SimpleTest
+	{
+		private byte[] seed1 = Hex.Decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d");
+		private byte[] mask1 = Hex.Decode(
+			"0742ba966813af75536bb6149cc44fc256fd6406df79665bc31dc5"
+			+ "a62f70535e52c53015b9d37d412ff3c1193439599e1b628774c50d9c"
+			+ "cb78d82c425e4521ee47b8c36a4bcffe8b8112a89312fc04420a39de"
+			+ "99223890e74ce10378bc515a212b97b8a6447ba6a8870278");
+
+		private byte[] seed2 = Hex.Decode(
+			"032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741"
+			+ "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4");
+		private byte[] mask2 = Hex.Decode(
+			"5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca9"
+			+ "75bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263c"
+			+ "fccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e"
+			+ "7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04");
+
+		private byte[] seed3;
+		private byte[] mask3= Hex.Decode(
+			"09e2decf2a6e1666c2f6071ff4298305e2643fd510a2403db42a8743cb989de86e"
+			+ "668d168cbe604611ac179f819a3d18412e9eb45668f2923c087c12fee0c5a0d2a8aa"
+			+ "70185401fbbd99379ec76c663e875a60b4aacb1319fa11c3365a8b79a44669f26fb5"
+			+ "55c80391847b05eca1cb5cf8c2d531448d33fbaca19f6410ee1fcb");
+
+		public Mgf1GeneratorTest()
+		{
+			seed3 = seed2;
+		}
+
+		public override void PerformTest()
+		{
+			checkMask(1, new Mgf1BytesGenerator(new ShortenedDigest(new Sha256Digest(), 20)), seed1, mask1);
+			checkMask(2, new Mgf1BytesGenerator(new Sha1Digest()), seed2, mask2);
+			checkMask(3, new Mgf1BytesGenerator(new ShortenedDigest(new Sha256Digest(), 20)), seed3, mask3);
+
+			try
+			{
+				new Mgf1BytesGenerator(new Sha1Digest()).GenerateBytes(new byte[10], 0, 20);
+
+				Fail("short input array not caught");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+		}
+
+		private void checkMask(
+			int                count,
+			IDerivationFunction kdf,
+			byte[]             seed,
+			byte[]             result)
+		{
+			byte[]             data = new byte[result.Length];
+
+			kdf.Init(new MgfParameters(seed));
+
+			kdf.GenerateBytes(data, 0, data.Length);
+
+			if (!AreEqual(result, data))
+			{
+				Fail("MGF1 failed generator test " + count);
+			}
+		}
+
+		public override string Name
+		{
+			get { return "MGF1"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Mgf1GeneratorTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/MacTest.cs b/crypto/test/src/crypto/test/MacTest.cs
new file mode 100644
index 000000000..9a58f8a8c
--- /dev/null
+++ b/crypto/test/src/crypto/test/MacTest.cs
@@ -0,0 +1,214 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <remarks> MAC tester - vectors from
+    /// <a href="http://www.itl.nist.gov/fipspubs/fip81.htm">FIP 81</a> and
+    /// <a href="http://www.itl.nist.gov/fipspubs/fip113.htm">FIP 113</a>.
+    /// </remarks>
+    [TestFixture]
+    public class MacTest
+		: ITest
+    {
+        public string Name
+        {
+			get { return "IMac"; }
+        }
+
+		internal static byte[] keyBytes;
+        internal static byte[] ivBytes;
+        internal static byte[] input1;
+        internal static byte[] output1;
+        internal static byte[] output2;
+        internal static byte[] output3;
+
+        //
+        // these aren't NIST vectors, just for regression testing.
+        //
+        internal static byte[] input2;
+        internal static byte[] output4;
+        internal static byte[] output5;
+        internal static byte[] output6;
+
+        public MacTest()
+        {
+        }
+
+        public virtual ITestResult Perform()
+        {
+            KeyParameter key = new KeyParameter(keyBytes);
+            IBlockCipher cipher = new DesEngine();
+            IMac mac = new CbcBlockCipherMac(cipher);
+
+            //
+            // standard DAC - zero IV
+            //
+            mac.Init(key);
+
+            mac.BlockUpdate(input1, 0, input1.Length);
+
+            byte[] outBytes = new byte[4];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output1))
+            {
+                return new SimpleTestResult(false, Name + ": Failed - expected "
+					+ Hex.ToHexString(output1) + " got " + Hex.ToHexString(outBytes));
+            }
+
+            //
+            // mac with IV.
+            //
+            ParametersWithIV param = new ParametersWithIV(key, ivBytes);
+
+            mac.Init(param);
+
+            mac.BlockUpdate(input1, 0, input1.Length);
+
+            outBytes = new byte[4];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output2))
+            {
+                return new SimpleTestResult(false, Name + ": Failed - expected "
+					+ Hex.ToHexString(output2) + " got " + Hex.ToHexString(outBytes));
+            }
+
+            //
+            // CFB mac with IV - 8 bit CFB mode
+            //
+            param = new ParametersWithIV(key, ivBytes);
+
+            mac = new CfbBlockCipherMac(cipher);
+
+            mac.Init(param);
+
+            mac.BlockUpdate(input1, 0, input1.Length);
+
+            outBytes = new byte[4];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output3))
+            {
+                return new SimpleTestResult(false, Name + ": Failed - expected "
+					+ Hex.ToHexString(output3) + " got " + Hex.ToHexString(outBytes));
+            }
+
+            //
+            // word aligned data - zero IV
+            //
+            mac.Init(key);
+
+            mac.BlockUpdate(input2, 0, input2.Length);
+
+            outBytes = new byte[4];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output4))
+            {
+                return new SimpleTestResult(false, Name + ": Failed - expected "
+					+ Hex.ToHexString(output4) + " got " + Hex.ToHexString(outBytes));
+            }
+
+            //
+            // word aligned data - zero IV - CBC padding
+            //
+            mac = new CbcBlockCipherMac(cipher, new Pkcs7Padding());
+
+            mac.Init(key);
+
+            mac.BlockUpdate(input2, 0, input2.Length);
+
+            outBytes = new byte[4];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output5))
+            {
+                return new SimpleTestResult(false, Name + ": Failed - expected "
+					+ Hex.ToHexString(output5) + " got " + Hex.ToHexString(outBytes));
+            }
+
+            //
+            // non-word aligned data - zero IV - CBC padding
+            //
+            mac.Reset();
+
+            mac.BlockUpdate(input1, 0, input1.Length);
+
+            outBytes = new byte[4];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output6))
+            {
+                return new SimpleTestResult(false, Name + ": Failed - expected "
+					+ Hex.ToHexString(output6) + " got " + Hex.ToHexString(outBytes));
+            }
+
+            //
+            // non-word aligned data - zero IV - CBC padding
+            //
+            mac.Init(key);
+
+            mac.BlockUpdate(input1, 0, input1.Length);
+
+            outBytes = new byte[4];
+
+            mac.DoFinal(outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output6))
+            {
+                return new SimpleTestResult(false, Name + ": Failed - expected "
+					+ Hex.ToHexString(output6) + " got " + Hex.ToHexString(outBytes));
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            MacTest test = new MacTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        static MacTest()
+        {
+            keyBytes = Hex.Decode("0123456789abcdef");
+            ivBytes = Hex.Decode("1234567890abcdef");
+            input1 = Hex.Decode("37363534333231204e6f77206973207468652074696d6520666f7220");
+            output1 = Hex.Decode("f1d30f68");
+            output2 = Hex.Decode("58d2e77e");
+            output3 = Hex.Decode("cd647403");
+            input2 = Hex.Decode("3736353433323120");
+            output4 = Hex.Decode("3af549c9");
+            output5 = Hex.Decode("188fbdd5");
+            output6 = Hex.Decode("7045eecd");
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ModeTest.cs b/crypto/test/src/crypto/test/ModeTest.cs
new file mode 100644
index 000000000..c67dce094
--- /dev/null
+++ b/crypto/test/src/crypto/test/ModeTest.cs
@@ -0,0 +1,108 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <remarks> CFB/OFB Mode test of IV padding.</remarks>
+	[TestFixture]
+	public class ModeTest
+		: ITest
+	{
+		public string Name
+		{
+			get { return "ModeTest"; }
+		}
+
+		public ModeTest()
+		{
+		}
+
+		public virtual ITestResult Perform()
+		{
+			KeyParameter key = new KeyParameter(Hex.Decode("0011223344556677"));
+			byte[] input = Hex.Decode("4e6f7720");
+			byte[] out1 = new byte[4];
+			byte[] out2 = new byte[4];
+
+
+			IBlockCipher ofb = new OfbBlockCipher(new DesEngine(), 32);
+
+			ofb.Init(true, new ParametersWithIV(key, Hex.Decode("1122334455667788")));
+
+			ofb.ProcessBlock(input, 0, out1, 0);
+
+			ofb.Init(false, new ParametersWithIV(key, Hex.Decode("1122334455667788")));
+			ofb.ProcessBlock(out1, 0, out2, 0);
+
+			if (!Arrays.AreEqual(out2, input))
+			{
+				return new SimpleTestResult(false, Name + ": test 1 - in != out");
+			}
+
+			ofb.Init(true, new ParametersWithIV(key, Hex.Decode("11223344")));
+
+			ofb.ProcessBlock(input, 0, out1, 0);
+
+			ofb.Init(false, new ParametersWithIV(key, Hex.Decode("0000000011223344")));
+			ofb.ProcessBlock(out1, 0, out2, 0);
+
+			if (!Arrays.AreEqual(out2, input))
+			{
+				return new SimpleTestResult(false, Name + ": test 2 - in != out");
+			}
+
+			IBlockCipher cfb = new CfbBlockCipher(new DesEngine(), 32);
+
+			cfb.Init(true, new ParametersWithIV(key, Hex.Decode("1122334455667788")));
+
+			cfb.ProcessBlock(input, 0, out1, 0);
+
+			cfb.Init(false, new ParametersWithIV(key, Hex.Decode("1122334455667788")));
+			cfb.ProcessBlock(out1, 0, out2, 0);
+
+			if (!Arrays.AreEqual(out2, input))
+			{
+				return new SimpleTestResult(false, Name + ": test 3 - in != out");
+			}
+
+			cfb.Init(true, new ParametersWithIV(key, Hex.Decode("11223344")));
+
+			cfb.ProcessBlock(input, 0, out1, 0);
+
+			cfb.Init(false, new ParametersWithIV(key, Hex.Decode("0000000011223344")));
+			cfb.ProcessBlock(out1, 0, out2, 0);
+
+			if (!Arrays.AreEqual(out2, input))
+			{
+				return new SimpleTestResult(false, Name + ": test 4 - in != out");
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new ModeTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/NaccacheSternTest.cs b/crypto/test/src/crypto/test/NaccacheSternTest.cs
new file mode 100644
index 000000000..faa845059
--- /dev/null
+++ b/crypto/test/src/crypto/test/NaccacheSternTest.cs
@@ -0,0 +1,354 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * Test case for NaccacheStern cipher. For details on this cipher, please see
+	 *
+	 * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+	 *
+	 * Performs the following tests:
+	 *  <ul>
+	 *  <li> Toy example from the NaccacheSternPaper </li>
+	 *  <li> 768 bit test with text "Now is the time for all good men." (ripped from RSA test) and
+	 *     the same test with the first byte replaced by 0xFF </li>
+	 *  <li> 1024 bit test analog to 768 bit test </li>
+	 *  </ul>
+	 */
+	[TestFixture, Explicit]
+	public class NaccacheSternTest
+		: SimpleTest
+	{
+		static bool debug = false;
+
+		static readonly NaccacheSternEngine cryptEng = new NaccacheSternEngine();
+		static readonly NaccacheSternEngine decryptEng = new NaccacheSternEngine();
+
+		static NaccacheSternTest()
+		{
+			cryptEng.Debug = debug;
+			decryptEng.Debug = debug;
+		}
+
+		// Values from NaccacheStern paper
+		static readonly BigInteger a = BigInteger.ValueOf(101);
+		static readonly BigInteger u1 = BigInteger.ValueOf(3);
+		static readonly BigInteger u2 = BigInteger.ValueOf(5);
+		static readonly BigInteger u3 = BigInteger.ValueOf(7);
+		static readonly BigInteger b = BigInteger.ValueOf(191);
+		static readonly BigInteger v1 = BigInteger.ValueOf(11);
+		static readonly BigInteger v2 = BigInteger.ValueOf(13);
+		static readonly BigInteger v3 = BigInteger.ValueOf(17);
+
+		static readonly BigInteger sigma
+			= u1.Multiply(u2).Multiply(u3).Multiply(v1).Multiply(v2).Multiply(v3);
+
+		static readonly BigInteger p
+			= BigInteger.Two.Multiply(a).Multiply(u1).Multiply(u2).Multiply(u3).Add(BigInteger.One);
+
+		static readonly BigInteger q
+			= BigInteger.Two.Multiply(b).Multiply(v1).Multiply(v2).Multiply(v3).Add(BigInteger.One);
+
+		static readonly BigInteger n = p.Multiply(q);
+
+		static readonly BigInteger phi_n
+			= p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
+
+		static readonly BigInteger g = BigInteger.ValueOf(131);
+
+		static readonly IList smallPrimes = new ArrayList();
+
+		// static final BigInteger paperTest = BigInteger.ValueOf(202);
+
+		static readonly string input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
+
+		static readonly BigInteger paperTest = BigInteger.ValueOf(202);
+
+		//
+		// to check that we handling byte extension by big number correctly.
+		//
+		static readonly string edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
+
+		public override string Name
+		{
+			get { return "NaccacheStern"; }
+		}
+
+		public override void PerformTest()
+		{
+			// Test with given key from NaccacheSternPaper (totally insecure)
+
+			// First the Parameters from the NaccacheStern Paper
+			// (see http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf )
+
+			smallPrimes.Add(u1);
+			smallPrimes.Add(u2);
+			smallPrimes.Add(u3);
+			smallPrimes.Add(v1);
+			smallPrimes.Add(v2);
+			smallPrimes.Add(v3);
+
+			NaccacheSternKeyParameters pubParameters = new NaccacheSternKeyParameters(false, g, n, sigma.BitLength);
+
+			NaccacheSternPrivateKeyParameters privParameters = new NaccacheSternPrivateKeyParameters(g, n, sigma
+				.BitLength, smallPrimes, phi_n);
+
+			AsymmetricCipherKeyPair pair = new AsymmetricCipherKeyPair(pubParameters, privParameters);
+
+			// Initialize Engines with KeyPair
+
+			if (debug)
+			{
+				Console.WriteLine("initializing encryption engine");
+			}
+			cryptEng.Init(true, pair.Public);
+
+			if (debug)
+			{
+				Console.WriteLine("initializing decryption engine");
+			}
+			decryptEng.Init(false, pair.Private);
+
+			byte[] data = paperTest.ToByteArray();
+
+			if (!new BigInteger(data).Equals(new BigInteger(enDeCrypt(data))))
+			{
+				Fail("failed NaccacheStern paper test");
+			}
+
+			//
+			// key generation test
+			//
+
+			//
+			// 768 Bit test
+			//
+
+			if (debug)
+			{
+				Console.WriteLine();
+				Console.WriteLine("768 Bit TEST");
+			}
+
+			// specify key generation parameters
+			NaccacheSternKeyGenerationParameters genParam
+				= new NaccacheSternKeyGenerationParameters(new SecureRandom(), 768, 8, 30, debug);
+
+			// Initialize Key generator and generate key pair
+			NaccacheSternKeyPairGenerator pGen = new NaccacheSternKeyPairGenerator();
+			pGen.Init(genParam);
+
+			pair = pGen.GenerateKeyPair();
+
+			if (((NaccacheSternKeyParameters)pair.Public).Modulus.BitLength < 768)
+			{
+				Console.WriteLine("FAILED: key size is <786 bit, exactly "
+						   + ((NaccacheSternKeyParameters)pair.Public).Modulus.BitLength + " bit");
+				Fail("failed key generation (768) length test");
+			}
+
+			// Initialize Engines with KeyPair
+
+			if (debug)
+			{
+				Console.WriteLine("initializing " + genParam.Strength + " bit encryption engine");
+			}
+			cryptEng.Init(true, pair.Public);
+
+			if (debug)
+			{
+				Console.WriteLine("initializing " + genParam.Strength + " bit decryption engine");
+			}
+			decryptEng.Init(false, pair.Private);
+
+			// Basic data input
+			data = Hex.Decode(input);
+
+			if (!new BigInteger(1, data).Equals(new BigInteger(1, enDeCrypt(data))))
+			{
+				Fail("failed encryption decryption (" + genParam.Strength + ") basic test");
+			}
+
+			// Data starting with FF byte (would be interpreted as negative
+			// BigInteger)
+
+			data = Hex.Decode(edgeInput);
+
+			if (!new BigInteger(1, data).Equals(new BigInteger(1, enDeCrypt(data))))
+			{
+				Fail("failed encryption decryption (" + genParam.Strength + ") edgeInput test");
+			}
+
+			//
+			// 1024 Bit Test
+			//
+			/*
+					if (debug)
+					{
+						Console.WriteLine();
+						Console.WriteLine("1024 Bit TEST");
+					}
+
+					// specify key generation parameters
+					genParam = new NaccacheSternKeyGenerationParameters(new SecureRandom(), 1024, 8, 40, debug);
+
+					pGen.Init(genParam);
+					pair = pGen.generateKeyPair();
+
+					if (((NaccacheSternKeyParameters)pair.Public).getModulus().bitLength() < 1024)
+					{
+						if (debug)
+						{
+							Console.WriteLine("FAILED: key size is <1024 bit, exactly "
+											+ ((NaccacheSternKeyParameters)pair.Public).getModulus().bitLength() + " bit");
+						}
+						Fail("failed key generation (1024) length test");
+					}
+
+					// Initialize Engines with KeyPair
+
+					if (debug)
+					{
+						Console.WriteLine("initializing " + genParam.getStrength() + " bit encryption engine");
+					}
+					cryptEng.Init(true, pair.Public);
+
+					if (debug)
+					{
+						Console.WriteLine("initializing " + genParam.getStrength() + " bit decryption engine");
+					}
+					decryptEng.Init(false, pair.Private);
+
+					if (debug)
+					{
+						Console.WriteLine("Data is           " + new BigInteger(1, data));
+					}
+
+					// Basic data input
+					data = Hex.Decode(input);
+
+					if (!new BigInteger(1, data).Equals(new BigInteger(1, enDeCrypt(data))))
+					{
+						Fail("failed encryption decryption (" + genParam.getStrength() + ") basic test");
+					}
+
+					// Data starting with FF byte (would be interpreted as negative
+					// BigInteger)
+
+					data = Hex.Decode(edgeInput);
+
+					if (!new BigInteger(1, data).Equals(new BigInteger(1, enDeCrypt(data))))
+					{
+						Fail("failed encryption decryption (" + genParam.getStrength() + ") edgeInput test");
+					}
+			*/
+			// END OF TEST CASE
+
+			try
+			{
+				new NaccacheSternEngine().ProcessBlock(new byte[]{ 1 }, 0, 1);
+				Fail("failed initialisation check");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+
+			if (debug)
+			{
+				Console.WriteLine("All tests successful");
+			}
+		}
+
+		private byte[] enDeCrypt(
+			byte[] input)
+		{
+			// create work array
+			byte[] data = new byte[input.Length];
+			Array.Copy(input, 0, data, 0, data.Length);
+
+			// Perform encryption like in the paper from Naccache-Stern
+			if (debug)
+			{
+				Console.WriteLine("encrypting data. Data representation\n"
+					//                    + "As string:.... " + new string(data) + "\n"
+					+ "As BigInteger: " + new BigInteger(1, data));
+				Console.WriteLine("data length is " + data.Length);
+			}
+
+			try
+			{
+				data = cryptEng.ProcessData(data);
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (debug)
+				{
+					Console.WriteLine("failed - exception " + e + "\n" + e.Message);
+				}
+				Fail("failed - exception " + e + "\n" + e.Message);
+			}
+
+			if (debug)
+			{
+				Console.WriteLine("enrypted data representation\n"
+						   //                    + "As string:.... " + new string(data) + "\n"
+						   + "As BigInteger: " + new BigInteger(1, data));
+				Console.WriteLine("data length is " + data.Length);
+			}
+
+			try
+			{
+				data = decryptEng.ProcessData(data);
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (debug)
+				{
+					Console.WriteLine("failed - exception " + e + "\n" + e.Message);
+				}
+				Fail("failed - exception " + e + "\n" + e.Message);
+			}
+
+			if (debug)
+			{
+				Console.WriteLine("decrypted data representation\n"
+					//                    + "As string:.... " + new string(data) + "\n"
+					+ "As BigInteger: " + new BigInteger(1, data));
+				Console.WriteLine("data length is " + data.Length);
+			}
+
+			return data;
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new NaccacheSternTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/NoekeonTest.cs b/crypto/test/src/crypto/test/NoekeonTest.cs
new file mode 100644
index 000000000..b6fff70ce
--- /dev/null
+++ b/crypto/test/src/crypto/test/NoekeonTest.cs
@@ -0,0 +1,59 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* Noekeon tester
+	*/
+	[TestFixture]
+	public class NoekeonTest
+		: CipherTest
+	{
+		private static readonly SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new NoekeonEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"00000000000000000000000000000000",
+				"b1656851699e29fa24b70148503d2dfc"),
+			new BlockCipherVectorTest(1, new NoekeonEngine(),
+				new KeyParameter(Hex.Decode("ffffffffffffffffffffffffffffffff")),
+				"ffffffffffffffffffffffffffffffff",
+				"2a78421b87c7d0924f26113f1d1349b2"),
+			new BlockCipherVectorTest(2, new NoekeonEngine(),
+				new KeyParameter(Hex.Decode("b1656851699e29fa24b70148503d2dfc")),
+				"2a78421b87c7d0924f26113f1d1349b2",
+				"e2f687e07b75660ffc372233bc47532c")
+		};
+
+		public NoekeonTest()
+			: base(tests, new NoekeonEngine(), new KeyParameter(new byte[16]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "Noekeon"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new NoekeonTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/NullTest.cs b/crypto/test/src/crypto/test/NullTest.cs
new file mode 100644
index 000000000..16a51808f
--- /dev/null
+++ b/crypto/test/src/crypto/test/NullTest.cs
@@ -0,0 +1,88 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class NullTest
+		: CipherTest
+	{
+		static SimpleTest[]  tests =
+		{
+			new BlockCipherVectorTest(0, new NullEngine(),
+					new KeyParameter(Hex.Decode("00")), "00", "00")
+		};
+
+		public NullTest()
+			: base(tests, new NullEngine(), new KeyParameter(new byte[2]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "Null"; }
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			IBlockCipher engine = new NullEngine();
+
+			engine.Init(true, null);
+
+			byte[] buf = new byte[1];
+
+			engine.ProcessBlock(buf, 0, buf, 0);
+
+			if (buf[0] != 0)
+			{
+				Fail("NullCipher changed data!");
+			}
+
+			byte[] shortBuf = new byte[0];
+
+			try
+			{
+				engine.ProcessBlock(shortBuf, 0, buf, 0);
+
+				Fail("failed short input check");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+
+			try
+			{
+				engine.ProcessBlock(buf, 0, shortBuf, 0);
+
+				Fail("failed short output check");
+			}
+			catch (DataLengthException)
+			{
+				// expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new NullTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/OAEPTest.cs b/crypto/test/src/crypto/test/OAEPTest.cs
new file mode 100644
index 000000000..b4c375eec
--- /dev/null
+++ b/crypto/test/src/crypto/test/OAEPTest.cs
@@ -0,0 +1,798 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class OaepTest
+        : SimpleTest
+    {
+        private static readonly byte[] pubKeyEnc1 =
+        {
+            (byte)0x30, (byte)0x5a, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86,
+            (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05,
+            (byte)0x00, (byte)0x03, (byte)0x49, (byte)0x00, (byte)0x30, (byte)0x46, (byte)0x02, (byte)0x41,
+            (byte)0x00, (byte)0xaa, (byte)0x36, (byte)0xab, (byte)0xce, (byte)0x88, (byte)0xac, (byte)0xfd,
+            (byte)0xff, (byte)0x55, (byte)0x52, (byte)0x3c, (byte)0x7f, (byte)0xc4, (byte)0x52, (byte)0x3f,
+            (byte)0x90, (byte)0xef, (byte)0xa0, (byte)0x0d, (byte)0xf3, (byte)0x77, (byte)0x4a, (byte)0x25,
+            (byte)0x9f, (byte)0x2e, (byte)0x62, (byte)0xb4, (byte)0xc5, (byte)0xd9, (byte)0x9c, (byte)0xb5,
+            (byte)0xad, (byte)0xb3, (byte)0x00, (byte)0xa0, (byte)0x28, (byte)0x5e, (byte)0x53, (byte)0x01,
+            (byte)0x93, (byte)0x0e, (byte)0x0c, (byte)0x70, (byte)0xfb, (byte)0x68, (byte)0x76, (byte)0x93,
+            (byte)0x9c, (byte)0xe6, (byte)0x16, (byte)0xce, (byte)0x62, (byte)0x4a, (byte)0x11, (byte)0xe0,
+            (byte)0x08, (byte)0x6d, (byte)0x34, (byte)0x1e, (byte)0xbc, (byte)0xac, (byte)0xa0, (byte)0xa1,
+            (byte)0xf5, (byte)0x02, (byte)0x01, (byte)0x11
+        };
+
+        private static readonly byte[] privKeyEnc1 =
+        {
+            (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x52, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30,
+            (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7,
+            (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x82,
+            (byte)0x01, (byte)0x3c, (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x38, (byte)0x02, (byte)0x01,
+            (byte)0x00, (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xaa, (byte)0x36, (byte)0xab, (byte)0xce,
+            (byte)0x88, (byte)0xac, (byte)0xfd, (byte)0xff, (byte)0x55, (byte)0x52, (byte)0x3c, (byte)0x7f,
+            (byte)0xc4, (byte)0x52, (byte)0x3f, (byte)0x90, (byte)0xef, (byte)0xa0, (byte)0x0d, (byte)0xf3,
+            (byte)0x77, (byte)0x4a, (byte)0x25, (byte)0x9f, (byte)0x2e, (byte)0x62, (byte)0xb4, (byte)0xc5,
+            (byte)0xd9, (byte)0x9c, (byte)0xb5, (byte)0xad, (byte)0xb3, (byte)0x00, (byte)0xa0, (byte)0x28,
+            (byte)0x5e, (byte)0x53, (byte)0x01, (byte)0x93, (byte)0x0e, (byte)0x0c, (byte)0x70, (byte)0xfb,
+            (byte)0x68, (byte)0x76, (byte)0x93, (byte)0x9c, (byte)0xe6, (byte)0x16, (byte)0xce, (byte)0x62,
+            (byte)0x4a, (byte)0x11, (byte)0xe0, (byte)0x08, (byte)0x6d, (byte)0x34, (byte)0x1e, (byte)0xbc,
+            (byte)0xac, (byte)0xa0, (byte)0xa1, (byte)0xf5, (byte)0x02, (byte)0x01, (byte)0x11, (byte)0x02,
+            (byte)0x40, (byte)0x0a, (byte)0x03, (byte)0x37, (byte)0x48, (byte)0x62, (byte)0x64, (byte)0x87,
+            (byte)0x69, (byte)0x5f, (byte)0x5f, (byte)0x30, (byte)0xbc, (byte)0x38, (byte)0xb9, (byte)0x8b,
+            (byte)0x44, (byte)0xc2, (byte)0xcd, (byte)0x2d, (byte)0xff, (byte)0x43, (byte)0x40, (byte)0x98,
+            (byte)0xcd, (byte)0x20, (byte)0xd8, (byte)0xa1, (byte)0x38, (byte)0xd0, (byte)0x90, (byte)0xbf,
+            (byte)0x64, (byte)0x79, (byte)0x7c, (byte)0x3f, (byte)0xa7, (byte)0xa2, (byte)0xcd, (byte)0xcb,
+            (byte)0x3c, (byte)0xd1, (byte)0xe0, (byte)0xbd, (byte)0xba, (byte)0x26, (byte)0x54, (byte)0xb4,
+            (byte)0xf9, (byte)0xdf, (byte)0x8e, (byte)0x8a, (byte)0xe5, (byte)0x9d, (byte)0x73, (byte)0x3d,
+            (byte)0x9f, (byte)0x33, (byte)0xb3, (byte)0x01, (byte)0x62, (byte)0x4a, (byte)0xfd, (byte)0x1d,
+            (byte)0x51, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0xd8, (byte)0x40, (byte)0xb4, (byte)0x16,
+            (byte)0x66, (byte)0xb4, (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, (byte)0xb4,
+            (byte)0x32, (byte)0x04, (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x33, (byte)0x52, (byte)0x52,
+            (byte)0x4d, (byte)0x04, (byte)0x16, (byte)0xa5, (byte)0xa4, (byte)0x41, (byte)0xe7, (byte)0x00,
+            (byte)0xaf, (byte)0x46, (byte)0x12, (byte)0x0d, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0xc9,
+            (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4, (byte)0x53, (byte)0xf6, (byte)0x34,
+            (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1, (byte)0xd9, (byte)0x35, (byte)0x3f,
+            (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66, (byte)0xb1, (byte)0xd0, (byte)0x5a,
+            (byte)0x0f, (byte)0x20, (byte)0x35, (byte)0x02, (byte)0x8b, (byte)0x9d, (byte)0x89, (byte)0x02,
+            (byte)0x20, (byte)0x59, (byte)0x0b, (byte)0x95, (byte)0x72, (byte)0xa2, (byte)0xc2, (byte)0xa9,
+            (byte)0xc4, (byte)0x06, (byte)0x05, (byte)0x9d, (byte)0xc2, (byte)0xab, (byte)0x2f, (byte)0x1d,
+            (byte)0xaf, (byte)0xeb, (byte)0x7e, (byte)0x8b, (byte)0x4f, (byte)0x10, (byte)0xa7, (byte)0x54,
+            (byte)0x9e, (byte)0x8e, (byte)0xed, (byte)0xf5, (byte)0xb4, (byte)0xfc, (byte)0xe0, (byte)0x9e,
+            (byte)0x05, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0x8e, (byte)0x3c, (byte)0x05, (byte)0x21,
+            (byte)0xfe, (byte)0x15, (byte)0xe0, (byte)0xea, (byte)0x06, (byte)0xa3, (byte)0x6f, (byte)0xf0,
+            (byte)0xf1, (byte)0x0c, (byte)0x99, (byte)0x52, (byte)0xc3, (byte)0x5b, (byte)0x7a, (byte)0x75,
+            (byte)0x14, (byte)0xfd, (byte)0x32, (byte)0x38, (byte)0xb8, (byte)0x0a, (byte)0xad, (byte)0x52,
+            (byte)0x98, (byte)0x62, (byte)0x8d, (byte)0x51, (byte)0x02, (byte)0x20, (byte)0x36, (byte)0x3f,
+            (byte)0xf7, (byte)0x18, (byte)0x9d, (byte)0xa8, (byte)0xe9, (byte)0x0b, (byte)0x1d, (byte)0x34,
+            (byte)0x1f, (byte)0x71, (byte)0xd0, (byte)0x9b, (byte)0x76, (byte)0xa8, (byte)0xa9, (byte)0x43,
+            (byte)0xe1, (byte)0x1d, (byte)0x10, (byte)0xb2, (byte)0x4d, (byte)0x24, (byte)0x9f, (byte)0x2d,
+            (byte)0xea, (byte)0xfe, (byte)0xf8, (byte)0x0c, (byte)0x18, (byte)0x26
+        };
+
+        private static readonly byte[] output1 = 
+        { 
+            (byte)0x1b, (byte)0x8f, (byte)0x05, (byte)0xf9, (byte)0xca, (byte)0x1a, (byte)0x79, (byte)0x52,
+            (byte)0x6e, (byte)0x53, (byte)0xf3, (byte)0xcc, (byte)0x51, (byte)0x4f, (byte)0xdb, (byte)0x89,
+            (byte)0x2b, (byte)0xfb, (byte)0x91, (byte)0x93, (byte)0x23, (byte)0x1e, (byte)0x78, (byte)0xb9,
+            (byte)0x92, (byte)0xe6, (byte)0x8d, (byte)0x50, (byte)0xa4, (byte)0x80, (byte)0xcb, (byte)0x52,
+            (byte)0x33, (byte)0x89, (byte)0x5c, (byte)0x74, (byte)0x95, (byte)0x8d, (byte)0x5d, (byte)0x02,
+            (byte)0xab, (byte)0x8c, (byte)0x0f, (byte)0xd0, (byte)0x40, (byte)0xeb, (byte)0x58, (byte)0x44,
+            (byte)0xb0, (byte)0x05, (byte)0xc3, (byte)0x9e, (byte)0xd8, (byte)0x27, (byte)0x4a, (byte)0x9d,
+            (byte)0xbf, (byte)0xa8, (byte)0x06, (byte)0x71, (byte)0x40, (byte)0x94, (byte)0x39, (byte)0xd2
+        };
+
+        private static readonly byte[] pubKeyEnc2 =
+        {
+            (byte)0x30, (byte)0x4c, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86,
+            (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05,
+            (byte)0x00, (byte)0x03, (byte)0x3b, (byte)0x00, (byte)0x30, (byte)0x38, (byte)0x02, (byte)0x33,
+            (byte)0x00, (byte)0xa3, (byte)0x07, (byte)0x9a, (byte)0x90, (byte)0xdf, (byte)0x0d, (byte)0xfd,
+            (byte)0x72, (byte)0xac, (byte)0x09, (byte)0x0c, (byte)0xcc, (byte)0x2a, (byte)0x78, (byte)0xb8,
+            (byte)0x74, (byte)0x13, (byte)0x13, (byte)0x3e, (byte)0x40, (byte)0x75, (byte)0x9c, (byte)0x98,
+            (byte)0xfa, (byte)0xf8, (byte)0x20, (byte)0x4f, (byte)0x35, (byte)0x8a, (byte)0x0b, (byte)0x26,
+            (byte)0x3c, (byte)0x67, (byte)0x70, (byte)0xe7, (byte)0x83, (byte)0xa9, (byte)0x3b, (byte)0x69,
+            (byte)0x71, (byte)0xb7, (byte)0x37, (byte)0x79, (byte)0xd2, (byte)0x71, (byte)0x7b, (byte)0xe8,
+            (byte)0x34, (byte)0x77, (byte)0xcf, (byte)0x02, (byte)0x01, (byte)0x03
+        };
+
+        private static readonly byte[] privKeyEnc2 =
+        {
+            (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x13, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30,
+            (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7,
+            (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x81,
+            (byte)0xfe, (byte)0x30, (byte)0x81, (byte)0xfb, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02,
+            (byte)0x33, (byte)0x00, (byte)0xa3, (byte)0x07, (byte)0x9a, (byte)0x90, (byte)0xdf, (byte)0x0d,
+            (byte)0xfd, (byte)0x72, (byte)0xac, (byte)0x09, (byte)0x0c, (byte)0xcc, (byte)0x2a, (byte)0x78,
+            (byte)0xb8, (byte)0x74, (byte)0x13, (byte)0x13, (byte)0x3e, (byte)0x40, (byte)0x75, (byte)0x9c,
+            (byte)0x98, (byte)0xfa, (byte)0xf8, (byte)0x20, (byte)0x4f, (byte)0x35, (byte)0x8a, (byte)0x0b,
+            (byte)0x26, (byte)0x3c, (byte)0x67, (byte)0x70, (byte)0xe7, (byte)0x83, (byte)0xa9, (byte)0x3b,
+            (byte)0x69, (byte)0x71, (byte)0xb7, (byte)0x37, (byte)0x79, (byte)0xd2, (byte)0x71, (byte)0x7b,
+            (byte)0xe8, (byte)0x34, (byte)0x77, (byte)0xcf, (byte)0x02, (byte)0x01, (byte)0x03, (byte)0x02,
+            (byte)0x32, (byte)0x6c, (byte)0xaf, (byte)0xbc, (byte)0x60, (byte)0x94, (byte)0xb3, (byte)0xfe,
+            (byte)0x4c, (byte)0x72, (byte)0xb0, (byte)0xb3, (byte)0x32, (byte)0xc6, (byte)0xfb, (byte)0x25,
+            (byte)0xa2, (byte)0xb7, (byte)0x62, (byte)0x29, (byte)0x80, (byte)0x4e, (byte)0x68, (byte)0x65,
+            (byte)0xfc, (byte)0xa4, (byte)0x5a, (byte)0x74, (byte)0xdf, (byte)0x0f, (byte)0x8f, (byte)0xb8,
+            (byte)0x41, (byte)0x3b, (byte)0x52, (byte)0xc0, (byte)0xd0, (byte)0xe5, (byte)0x3d, (byte)0x9b,
+            (byte)0x59, (byte)0x0f, (byte)0xf1, (byte)0x9b, (byte)0xe7, (byte)0x9f, (byte)0x49, (byte)0xdd,
+            (byte)0x21, (byte)0xe5, (byte)0xeb, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0xcf, (byte)0x20,
+            (byte)0x35, (byte)0x02, (byte)0x8b, (byte)0x9d, (byte)0x86, (byte)0x98, (byte)0x40, (byte)0xb4,
+            (byte)0x16, (byte)0x66, (byte)0xb4, (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3,
+            (byte)0xb4, (byte)0x32, (byte)0x04, (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x91, (byte)0x02,
+            (byte)0x1a, (byte)0x00, (byte)0xc9, (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4,
+            (byte)0x53, (byte)0xf6, (byte)0x34, (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1,
+            (byte)0xd9, (byte)0x35, (byte)0x3f, (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66,
+            (byte)0xb1, (byte)0xd0, (byte)0x5f, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0x8a, (byte)0x15,
+            (byte)0x78, (byte)0xac, (byte)0x5d, (byte)0x13, (byte)0xaf, (byte)0x10, (byte)0x2b, (byte)0x22,
+            (byte)0xb9, (byte)0x99, (byte)0xcd, (byte)0x74, (byte)0x61, (byte)0xf1, (byte)0x5e, (byte)0x6d,
+            (byte)0x22, (byte)0xcc, (byte)0x03, (byte)0x23, (byte)0xdf, (byte)0xdf, (byte)0x0b, (byte)0x02,
+            (byte)0x1a, (byte)0x00, (byte)0x86, (byte)0x55, (byte)0x21, (byte)0x4a, (byte)0xc5, (byte)0x4d,
+            (byte)0x8d, (byte)0x4e, (byte)0xcd, (byte)0x61, (byte)0x77, (byte)0xf1, (byte)0xc7, (byte)0x36,
+            (byte)0x90, (byte)0xce, (byte)0x2a, (byte)0x48, (byte)0x2c, (byte)0x8b, (byte)0x05, (byte)0x99,
+            (byte)0xcb, (byte)0xe0, (byte)0x3f, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0x83, (byte)0xef,
+            (byte)0xef, (byte)0xb8, (byte)0xa9, (byte)0xa4, (byte)0x0d, (byte)0x1d, (byte)0xb6, (byte)0xed,
+            (byte)0x98, (byte)0xad, (byte)0x84, (byte)0xed, (byte)0x13, (byte)0x35, (byte)0xdc, (byte)0xc1,
+            (byte)0x08, (byte)0xf3, (byte)0x22, (byte)0xd0, (byte)0x57, (byte)0xcf, (byte)0x8d
+        };
+
+        private static readonly byte[] output2 =
+        {
+            (byte)0x14, (byte)0xbd, (byte)0xdd, (byte)0x28, (byte)0xc9, (byte)0x83, (byte)0x35, (byte)0x19,
+            (byte)0x23, (byte)0x80, (byte)0xe8, (byte)0xe5, (byte)0x49, (byte)0xb1, (byte)0x58, (byte)0x2a,
+            (byte)0x8b, (byte)0x40, (byte)0xb4, (byte)0x48, (byte)0x6d, (byte)0x03, (byte)0xa6, (byte)0xa5,
+            (byte)0x31, (byte)0x1f, (byte)0x1f, (byte)0xd5, (byte)0xf0, (byte)0xa1, (byte)0x80, (byte)0xe4,
+            (byte)0x17, (byte)0x53, (byte)0x03, (byte)0x29, (byte)0xa9, (byte)0x34, (byte)0x90, (byte)0x74,
+            (byte)0xb1, (byte)0x52, (byte)0x13, (byte)0x54, (byte)0x29, (byte)0x08, (byte)0x24, (byte)0x52,
+            (byte)0x62, (byte)0x51
+        };
+
+        private static readonly byte[] pubKeyEnc3 =
+        {
+            (byte)0x30, (byte)0x81, (byte)0x9d, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a,
+            (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01,
+            (byte)0x05, (byte)0x00, (byte)0x03, (byte)0x81, (byte)0x8b, (byte)0x00, (byte)0x30, (byte)0x81,
+            (byte)0x87, (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xbb, (byte)0xf8, (byte)0x2f,
+            (byte)0x09, (byte)0x06, (byte)0x82, (byte)0xce, (byte)0x9c, (byte)0x23, (byte)0x38, (byte)0xac,
+            (byte)0x2b, (byte)0x9d, (byte)0xa8, (byte)0x71, (byte)0xf7, (byte)0x36, (byte)0x8d, (byte)0x07,
+            (byte)0xee, (byte)0xd4, (byte)0x10, (byte)0x43, (byte)0xa4, (byte)0x40, (byte)0xd6, (byte)0xb6,
+            (byte)0xf0, (byte)0x74, (byte)0x54, (byte)0xf5, (byte)0x1f, (byte)0xb8, (byte)0xdf, (byte)0xba,
+            (byte)0xaf, (byte)0x03, (byte)0x5c, (byte)0x02, (byte)0xab, (byte)0x61, (byte)0xea, (byte)0x48,
+            (byte)0xce, (byte)0xeb, (byte)0x6f, (byte)0xcd, (byte)0x48, (byte)0x76, (byte)0xed, (byte)0x52,
+            (byte)0x0d, (byte)0x60, (byte)0xe1, (byte)0xec, (byte)0x46, (byte)0x19, (byte)0x71, (byte)0x9d,
+            (byte)0x8a, (byte)0x5b, (byte)0x8b, (byte)0x80, (byte)0x7f, (byte)0xaf, (byte)0xb8, (byte)0xe0,
+            (byte)0xa3, (byte)0xdf, (byte)0xc7, (byte)0x37, (byte)0x72, (byte)0x3e, (byte)0xe6, (byte)0xb4,
+            (byte)0xb7, (byte)0xd9, (byte)0x3a, (byte)0x25, (byte)0x84, (byte)0xee, (byte)0x6a, (byte)0x64,
+            (byte)0x9d, (byte)0x06, (byte)0x09, (byte)0x53, (byte)0x74, (byte)0x88, (byte)0x34, (byte)0xb2,
+            (byte)0x45, (byte)0x45, (byte)0x98, (byte)0x39, (byte)0x4e, (byte)0xe0, (byte)0xaa, (byte)0xb1,
+            (byte)0x2d, (byte)0x7b, (byte)0x61, (byte)0xa5, (byte)0x1f, (byte)0x52, (byte)0x7a, (byte)0x9a,
+            (byte)0x41, (byte)0xf6, (byte)0xc1, (byte)0x68, (byte)0x7f, (byte)0xe2, (byte)0x53, (byte)0x72,
+            (byte)0x98, (byte)0xca, (byte)0x2a, (byte)0x8f, (byte)0x59, (byte)0x46, (byte)0xf8, (byte)0xe5,
+            (byte)0xfd, (byte)0x09, (byte)0x1d, (byte)0xbd, (byte)0xcb, (byte)0x02, (byte)0x01, (byte)0x11
+        };
+
+        private static readonly byte[] privKeyEnc3 =
+        {
+            (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x75, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30,
+            (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7,
+            (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x82,
+            (byte)0x02, (byte)0x5f, (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x5b, (byte)0x02, (byte)0x01,
+            (byte)0x00, (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xbb, (byte)0xf8, (byte)0x2f,
+            (byte)0x09, (byte)0x06, (byte)0x82, (byte)0xce, (byte)0x9c, (byte)0x23, (byte)0x38, (byte)0xac,
+            (byte)0x2b, (byte)0x9d, (byte)0xa8, (byte)0x71, (byte)0xf7, (byte)0x36, (byte)0x8d, (byte)0x07,
+            (byte)0xee, (byte)0xd4, (byte)0x10, (byte)0x43, (byte)0xa4, (byte)0x40, (byte)0xd6, (byte)0xb6,
+            (byte)0xf0, (byte)0x74, (byte)0x54, (byte)0xf5, (byte)0x1f, (byte)0xb8, (byte)0xdf, (byte)0xba,
+            (byte)0xaf, (byte)0x03, (byte)0x5c, (byte)0x02, (byte)0xab, (byte)0x61, (byte)0xea, (byte)0x48,
+            (byte)0xce, (byte)0xeb, (byte)0x6f, (byte)0xcd, (byte)0x48, (byte)0x76, (byte)0xed, (byte)0x52,
+            (byte)0x0d, (byte)0x60, (byte)0xe1, (byte)0xec, (byte)0x46, (byte)0x19, (byte)0x71, (byte)0x9d,
+            (byte)0x8a, (byte)0x5b, (byte)0x8b, (byte)0x80, (byte)0x7f, (byte)0xaf, (byte)0xb8, (byte)0xe0,
+            (byte)0xa3, (byte)0xdf, (byte)0xc7, (byte)0x37, (byte)0x72, (byte)0x3e, (byte)0xe6, (byte)0xb4,
+            (byte)0xb7, (byte)0xd9, (byte)0x3a, (byte)0x25, (byte)0x84, (byte)0xee, (byte)0x6a, (byte)0x64,
+            (byte)0x9d, (byte)0x06, (byte)0x09, (byte)0x53, (byte)0x74, (byte)0x88, (byte)0x34, (byte)0xb2,
+            (byte)0x45, (byte)0x45, (byte)0x98, (byte)0x39, (byte)0x4e, (byte)0xe0, (byte)0xaa, (byte)0xb1,
+            (byte)0x2d, (byte)0x7b, (byte)0x61, (byte)0xa5, (byte)0x1f, (byte)0x52, (byte)0x7a, (byte)0x9a,
+            (byte)0x41, (byte)0xf6, (byte)0xc1, (byte)0x68, (byte)0x7f, (byte)0xe2, (byte)0x53, (byte)0x72,
+            (byte)0x98, (byte)0xca, (byte)0x2a, (byte)0x8f, (byte)0x59, (byte)0x46, (byte)0xf8, (byte)0xe5,
+            (byte)0xfd, (byte)0x09, (byte)0x1d, (byte)0xbd, (byte)0xcb, (byte)0x02, (byte)0x01, (byte)0x11,
+            (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xa5, (byte)0xda, (byte)0xfc, (byte)0x53,
+            (byte)0x41, (byte)0xfa, (byte)0xf2, (byte)0x89, (byte)0xc4, (byte)0xb9, (byte)0x88, (byte)0xdb,
+            (byte)0x30, (byte)0xc1, (byte)0xcd, (byte)0xf8, (byte)0x3f, (byte)0x31, (byte)0x25, (byte)0x1e,
+            (byte)0x06, (byte)0x68, (byte)0xb4, (byte)0x27, (byte)0x84, (byte)0x81, (byte)0x38, (byte)0x01,
+            (byte)0x57, (byte)0x96, (byte)0x41, (byte)0xb2, (byte)0x94, (byte)0x10, (byte)0xb3, (byte)0xc7,
+            (byte)0x99, (byte)0x8d, (byte)0x6b, (byte)0xc4, (byte)0x65, (byte)0x74, (byte)0x5e, (byte)0x5c,
+            (byte)0x39, (byte)0x26, (byte)0x69, (byte)0xd6, (byte)0x87, (byte)0x0d, (byte)0xa2, (byte)0xc0,
+            (byte)0x82, (byte)0xa9, (byte)0x39, (byte)0xe3, (byte)0x7f, (byte)0xdc, (byte)0xb8, (byte)0x2e,
+            (byte)0xc9, (byte)0x3e, (byte)0xda, (byte)0xc9, (byte)0x7f, (byte)0xf3, (byte)0xad, (byte)0x59,
+            (byte)0x50, (byte)0xac, (byte)0xcf, (byte)0xbc, (byte)0x11, (byte)0x1c, (byte)0x76, (byte)0xf1,
+            (byte)0xa9, (byte)0x52, (byte)0x94, (byte)0x44, (byte)0xe5, (byte)0x6a, (byte)0xaf, (byte)0x68,
+            (byte)0xc5, (byte)0x6c, (byte)0x09, (byte)0x2c, (byte)0xd3, (byte)0x8d, (byte)0xc3, (byte)0xbe,
+            (byte)0xf5, (byte)0xd2, (byte)0x0a, (byte)0x93, (byte)0x99, (byte)0x26, (byte)0xed, (byte)0x4f,
+            (byte)0x74, (byte)0xa1, (byte)0x3e, (byte)0xdd, (byte)0xfb, (byte)0xe1, (byte)0xa1, (byte)0xce,
+            (byte)0xcc, (byte)0x48, (byte)0x94, (byte)0xaf, (byte)0x94, (byte)0x28, (byte)0xc2, (byte)0xb7,
+            (byte)0xb8, (byte)0x88, (byte)0x3f, (byte)0xe4, (byte)0x46, (byte)0x3a, (byte)0x4b, (byte)0xc8,
+            (byte)0x5b, (byte)0x1c, (byte)0xb3, (byte)0xc1, (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xee,
+            (byte)0xcf, (byte)0xae, (byte)0x81, (byte)0xb1, (byte)0xb9, (byte)0xb3, (byte)0xc9, (byte)0x08,
+            (byte)0x81, (byte)0x0b, (byte)0x10, (byte)0xa1, (byte)0xb5, (byte)0x60, (byte)0x01, (byte)0x99,
+            (byte)0xeb, (byte)0x9f, (byte)0x44, (byte)0xae, (byte)0xf4, (byte)0xfd, (byte)0xa4, (byte)0x93,
+            (byte)0xb8, (byte)0x1a, (byte)0x9e, (byte)0x3d, (byte)0x84, (byte)0xf6, (byte)0x32, (byte)0x12,
+            (byte)0x4e, (byte)0xf0, (byte)0x23, (byte)0x6e, (byte)0x5d, (byte)0x1e, (byte)0x3b, (byte)0x7e,
+            (byte)0x28, (byte)0xfa, (byte)0xe7, (byte)0xaa, (byte)0x04, (byte)0x0a, (byte)0x2d, (byte)0x5b,
+            (byte)0x25, (byte)0x21, (byte)0x76, (byte)0x45, (byte)0x9d, (byte)0x1f, (byte)0x39, (byte)0x75,
+            (byte)0x41, (byte)0xba, (byte)0x2a, (byte)0x58, (byte)0xfb, (byte)0x65, (byte)0x99, (byte)0x02,
+            (byte)0x41, (byte)0x00, (byte)0xc9, (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4,
+            (byte)0x53, (byte)0xf6, (byte)0x34, (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1,
+            (byte)0xd9, (byte)0x35, (byte)0x3f, (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66,
+            (byte)0xb1, (byte)0xd0, (byte)0x5a, (byte)0x0f, (byte)0x20, (byte)0x35, (byte)0x02, (byte)0x8b,
+            (byte)0x9d, (byte)0x86, (byte)0x98, (byte)0x40, (byte)0xb4, (byte)0x16, (byte)0x66, (byte)0xb4,
+            (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, (byte)0xb4, (byte)0x32, (byte)0x04,
+            (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x33, (byte)0x52, (byte)0x52, (byte)0x4d, (byte)0x04,
+            (byte)0x16, (byte)0xa5, (byte)0xa4, (byte)0x41, (byte)0xe7, (byte)0x00, (byte)0xaf, (byte)0x46,
+            (byte)0x15, (byte)0x03, (byte)0x02, (byte)0x40, (byte)0x54, (byte)0x49, (byte)0x4c, (byte)0xa6,
+            (byte)0x3e, (byte)0xba, (byte)0x03, (byte)0x37, (byte)0xe4, (byte)0xe2, (byte)0x40, (byte)0x23,
+            (byte)0xfc, (byte)0xd6, (byte)0x9a, (byte)0x5a, (byte)0xeb, (byte)0x07, (byte)0xdd, (byte)0xdc,
+            (byte)0x01, (byte)0x83, (byte)0xa4, (byte)0xd0, (byte)0xac, (byte)0x9b, (byte)0x54, (byte)0xb0,
+            (byte)0x51, (byte)0xf2, (byte)0xb1, (byte)0x3e, (byte)0xd9, (byte)0x49, (byte)0x09, (byte)0x75,
+            (byte)0xea, (byte)0xb7, (byte)0x74, (byte)0x14, (byte)0xff, (byte)0x59, (byte)0xc1, (byte)0xf7,
+            (byte)0x69, (byte)0x2e, (byte)0x9a, (byte)0x2e, (byte)0x20, (byte)0x2b, (byte)0x38, (byte)0xfc,
+            (byte)0x91, (byte)0x0a, (byte)0x47, (byte)0x41, (byte)0x74, (byte)0xad, (byte)0xc9, (byte)0x3c,
+            (byte)0x1f, (byte)0x67, (byte)0xc9, (byte)0x81, (byte)0x02, (byte)0x40, (byte)0x47, (byte)0x1e,
+            (byte)0x02, (byte)0x90, (byte)0xff, (byte)0x0a, (byte)0xf0, (byte)0x75, (byte)0x03, (byte)0x51,
+            (byte)0xb7, (byte)0xf8, (byte)0x78, (byte)0x86, (byte)0x4c, (byte)0xa9, (byte)0x61, (byte)0xad,
+            (byte)0xbd, (byte)0x3a, (byte)0x8a, (byte)0x7e, (byte)0x99, (byte)0x1c, (byte)0x5c, (byte)0x05,
+            (byte)0x56, (byte)0xa9, (byte)0x4c, (byte)0x31, (byte)0x46, (byte)0xa7, (byte)0xf9, (byte)0x80,
+            (byte)0x3f, (byte)0x8f, (byte)0x6f, (byte)0x8a, (byte)0xe3, (byte)0x42, (byte)0xe9, (byte)0x31,
+            (byte)0xfd, (byte)0x8a, (byte)0xe4, (byte)0x7a, (byte)0x22, (byte)0x0d, (byte)0x1b, (byte)0x99,
+            (byte)0xa4, (byte)0x95, (byte)0x84, (byte)0x98, (byte)0x07, (byte)0xfe, (byte)0x39, (byte)0xf9,
+            (byte)0x24, (byte)0x5a, (byte)0x98, (byte)0x36, (byte)0xda, (byte)0x3d, (byte)0x02, (byte)0x41,
+            (byte)0x00, (byte)0xb0, (byte)0x6c, (byte)0x4f, (byte)0xda, (byte)0xbb, (byte)0x63, (byte)0x01,
+            (byte)0x19, (byte)0x8d, (byte)0x26, (byte)0x5b, (byte)0xdb, (byte)0xae, (byte)0x94, (byte)0x23,
+            (byte)0xb3, (byte)0x80, (byte)0xf2, (byte)0x71, (byte)0xf7, (byte)0x34, (byte)0x53, (byte)0x88,
+            (byte)0x50, (byte)0x93, (byte)0x07, (byte)0x7f, (byte)0xcd, (byte)0x39, (byte)0xe2, (byte)0x11,
+            (byte)0x9f, (byte)0xc9, (byte)0x86, (byte)0x32, (byte)0x15, (byte)0x4f, (byte)0x58, (byte)0x83,
+            (byte)0xb1, (byte)0x67, (byte)0xa9, (byte)0x67, (byte)0xbf, (byte)0x40, (byte)0x2b, (byte)0x4e,
+            (byte)0x9e, (byte)0x2e, (byte)0x0f, (byte)0x96, (byte)0x56, (byte)0xe6, (byte)0x98, (byte)0xea,
+            (byte)0x36, (byte)0x66, (byte)0xed, (byte)0xfb, (byte)0x25, (byte)0x79, (byte)0x80, (byte)0x39,
+            (byte)0xf7
+        };
+
+        private static readonly byte[] output3 = Hex.Decode(
+              "b8246b56a6ed5881aeb585d9a25b2ad790c417e080681bf1ac2bc3deb69d8bce"
+            + "f0c4366fec400af052a72e9b0effb5b3f2f192dbeaca03c12740057113bf1f06"
+            + "69ac22e9f3a7852e3c15d913cab0b8863a95c99294ce8674214954610346f4d4"
+            + "74b26f7c48b42ee68e1f572a1fc4026ac456b4f59f7b621ea1b9d88f64202fb1");
+
+        private static readonly byte[] seed = {
+            (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59,
+            (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4,
+            (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde,
+            (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f
+        };
+
+        private class VecRand
+            : SecureRandom
+        {
+            private readonly byte[] seed;
+
+            internal VecRand(byte[] seed)
+            {
+                this.seed = seed;
+            }
+
+            public override void NextBytes(
+                byte[] bytes)
+            {
+                Array.Copy(seed, 0, bytes, 0, bytes.Length);
+            }
+        }
+
+        private void BaseOaepTest(
+            int		id,
+            byte[]	pubKeyEnc,
+            byte[]	privKeyEnc,
+            byte[]	output)
+        {
+            //
+            // extract the public key info.
+            //
+            Asn1Object pubKeyObj = Asn1Object.FromByteArray(pubKeyEnc);
+            RsaPublicKeyStructure pubStruct = RsaPublicKeyStructure.GetInstance(
+                SubjectPublicKeyInfo.GetInstance(pubKeyObj).GetPublicKey());
+
+            //
+            // extract the private key info.
+            //
+            Asn1Object privKeyObj = Asn1Object.FromByteArray(privKeyEnc);
+            RsaPrivateKeyStructure privStruct = new RsaPrivateKeyStructure(
+                (Asn1Sequence)PrivateKeyInfo.GetInstance(privKeyObj).ParsePrivateKey());
+
+            RsaKeyParameters pubParameters = new RsaKeyParameters(
+                false,
+                pubStruct.Modulus,
+                pubStruct.PublicExponent);
+
+            RsaKeyParameters privParameters = new RsaPrivateCrtKeyParameters(
+                privStruct.Modulus,
+                privStruct.PublicExponent,
+                privStruct.PrivateExponent,
+                privStruct.Prime1,
+                privStruct.Prime2,
+                privStruct.Exponent1,
+                privStruct.Exponent2,
+                privStruct.Coefficient);
+
+            byte[] input = new byte[] {
+                (byte)0x54, (byte)0x85, (byte)0x9b, (byte)0x34,
+                (byte)0x2c, (byte)0x49, (byte)0xea, (byte)0x2a
+            };
+
+            EncDec("id(" + id + ")", pubParameters, privParameters, seed, input, output);
+        }
+
+        private void EncDec(
+            string				label,
+            RsaKeyParameters	pubParameters,
+            RsaKeyParameters	privParameters,
+            byte[]				seed,
+            byte[]				input,
+            byte[]				output)
+        {
+            IAsymmetricBlockCipher cipher = new OaepEncoding(new RsaEngine());
+
+            cipher.Init(true, new ParametersWithRandom(pubParameters, new VecRand(seed)));
+
+            byte[] outBytes = cipher.ProcessBlock(input, 0, input.Length);
+
+            for (int i = 0; i != output.Length; i++)
+            {
+                if (outBytes[i] != output[i])
+                {
+                    Fail(label + " failed encryption");
+                }
+            }
+
+            cipher.Init(false, privParameters);
+
+            outBytes = cipher.ProcessBlock(output, 0, output.Length);
+
+            for (int i = 0; i != input.Length; i++)
+            {
+                if (outBytes[i] != input[i])
+                {
+                    Fail(label + " failed decoding");
+                }
+            }
+        }
+
+        /*
+        * RSA vector tests from PKCS#1 page
+        */
+        private static readonly byte[] modulus_1024 = Hex.Decode(
+              "a8b3b284af8eb50b387034a860f146c4"
+            + "919f318763cd6c5598c8ae4811a1e0ab"
+            + "c4c7e0b082d693a5e7fced675cf46685"
+            + "12772c0cbc64a742c6c630f533c8cc72"
+            + "f62ae833c40bf25842e984bb78bdbf97"
+            + "c0107d55bdb662f5c4e0fab9845cb514"
+            + "8ef7392dd3aaff93ae1e6b667bb3d424"
+            + "7616d4f5ba10d4cfd226de88d39f16fb");
+
+        private static readonly byte[] pubExp_1024 = Hex.Decode("010001");
+
+        private static readonly byte[] privExp_1024 = Hex.Decode(
+              "53339cfdb79fc8466a655c7316aca85c"
+            + "55fd8f6dd898fdaf119517ef4f52e8fd"
+            + "8e258df93fee180fa0e4ab29693cd83b"
+            + "152a553d4ac4d1812b8b9fa5af0e7f55"
+            + "fe7304df41570926f3311f15c4d65a73"
+            + "2c483116ee3d3d2d0af3549ad9bf7cbf"
+            + "b78ad884f84d5beb04724dc7369b31de"
+            + "f37d0cf539e9cfcdd3de653729ead5d1");
+
+        private static readonly byte[] prime1_1024 = Hex.Decode(
+              "d32737e7267ffe1341b2d5c0d150a81b"
+            + "586fb3132bed2f8d5262864a9cb9f30a"
+            + "f38be448598d413a172efb802c21acf1"
+            + "c11c520c2f26a471dcad212eac7ca39d");
+
+        private static readonly byte[] prime2_1024 = Hex.Decode(
+              "cc8853d1d54da630fac004f471f281c7"
+            + "b8982d8224a490edbeb33d3e3d5cc93c"
+            + "4765703d1dd791642f1f116a0dd852be"
+            + "2419b2af72bfe9a030e860b0288b5d77");
+
+        private static readonly byte[] primeExp1_1024 = Hex.Decode(
+              "0e12bf1718e9cef5599ba1c3882fe804"
+            + "6a90874eefce8f2ccc20e4f2741fb0a3"
+            + "3a3848aec9c9305fbecbd2d76819967d"
+            + "4671acc6431e4037968db37878e695c1");
+
+        private static readonly byte[] primeExp2_1024 = Hex.Decode(
+              "95297b0f95a2fa67d00707d609dfd4fc"
+            + "05c89dafc2ef6d6ea55bec771ea33373"
+            + "4d9251e79082ecda866efef13c459e1a"
+            + "631386b7e354c899f5f112ca85d71583");
+
+        private static readonly byte[] crtCoef_1024 = Hex.Decode(
+              "4f456c502493bdc0ed2ab756a3a6ed4d"
+            + "67352a697d4216e93212b127a63d5411"
+            + "ce6fa98d5dbefd73263e372814274381"
+            + "8166ed7dd63687dd2a8ca1d2f4fbd8e1");
+
+        private static readonly byte[] input_1024_1 = Hex.Decode(
+              "6628194e12073db03ba94cda9ef95323"
+            + "97d50dba79b987004afefe34");
+
+        private static readonly byte[] seed_1024_1 = Hex.Decode(
+              "18b776ea21069d69776a33e96bad48e1"
+            + "dda0a5ef");
+
+        private static readonly byte[] output_1024_1 = Hex.Decode(
+              "354fe67b4a126d5d35fe36c777791a3f"
+            + "7ba13def484e2d3908aff722fad468fb"
+            + "21696de95d0be911c2d3174f8afcc201"
+            + "035f7b6d8e69402de5451618c21a535f"
+            + "a9d7bfc5b8dd9fc243f8cf927db31322"
+            + "d6e881eaa91a996170e657a05a266426"
+            + "d98c88003f8477c1227094a0d9fa1e8c"
+            + "4024309ce1ecccb5210035d47ac72e8a");
+
+        private static readonly byte[] input_1024_2 = Hex.Decode(
+              "750c4047f547e8e41411856523298ac9"
+            + "bae245efaf1397fbe56f9dd5");
+
+        private static readonly byte[] seed_1024_2 = Hex.Decode(
+              "0cc742ce4a9b7f32f951bcb251efd925"
+            + "fe4fe35f");
+
+        private static readonly byte[] output_1024_2 = Hex.Decode(
+              "640db1acc58e0568fe5407e5f9b701df"
+            + "f8c3c91e716c536fc7fcec6cb5b71c11"
+            + "65988d4a279e1577d730fc7a29932e3f"
+            + "00c81515236d8d8e31017a7a09df4352"
+            + "d904cdeb79aa583adcc31ea698a4c052"
+            + "83daba9089be5491f67c1a4ee48dc74b"
+            + "bbe6643aef846679b4cb395a352d5ed1"
+            + "15912df696ffe0702932946d71492b44");
+
+        private static readonly byte[] input_1024_3 = Hex.Decode(
+              "d94ae0832e6445ce42331cb06d531a82"
+            + "b1db4baad30f746dc916df24d4e3c245"
+            + "1fff59a6423eb0e1d02d4fe646cf699d"
+            + "fd818c6e97b051");
+
+        private static readonly byte[] seed_1024_3 = Hex.Decode(
+              "2514df4695755a67b288eaf4905c36ee"
+            + "c66fd2fd");
+
+        private static readonly byte[] output_1024_3 = Hex.Decode(
+              "423736ed035f6026af276c35c0b3741b"
+            + "365e5f76ca091b4e8c29e2f0befee603"
+            + "595aa8322d602d2e625e95eb81b2f1c9"
+            + "724e822eca76db8618cf09c5343503a4"
+            + "360835b5903bc637e3879fb05e0ef326"
+            + "85d5aec5067cd7cc96fe4b2670b6eac3"
+            + "066b1fcf5686b68589aafb7d629b02d8"
+            + "f8625ca3833624d4800fb081b1cf94eb");
+
+        private static readonly byte[] input_1024_4 = Hex.Decode(
+              "52e650d98e7f2a048b4f86852153b97e"
+            + "01dd316f346a19f67a85");
+
+        private static readonly byte[] seed_1024_4 = Hex.Decode(
+              "c4435a3e1a18a68b6820436290a37cef"
+            + "b85db3fb");
+
+        private static readonly byte[] output_1024_4 = Hex.Decode(
+              "45ead4ca551e662c9800f1aca8283b05"
+            + "25e6abae30be4b4aba762fa40fd3d38e"
+            + "22abefc69794f6ebbbc05ddbb1121624"
+            + "7d2f412fd0fba87c6e3acd888813646f"
+            + "d0e48e785204f9c3f73d6d8239562722"
+            + "dddd8771fec48b83a31ee6f592c4cfd4"
+            + "bc88174f3b13a112aae3b9f7b80e0fc6"
+            + "f7255ba880dc7d8021e22ad6a85f0755");
+
+        private static readonly byte[] input_1024_5 = Hex.Decode(
+              "8da89fd9e5f974a29feffb462b49180f"
+            + "6cf9e802");
+
+        private static readonly byte[] seed_1024_5 = Hex.Decode(
+              "b318c42df3be0f83fea823f5a7b47ed5"
+            + "e425a3b5");
+
+        private static readonly byte[] output_1024_5 = Hex.Decode(
+              "36f6e34d94a8d34daacba33a2139d00a"
+            + "d85a9345a86051e73071620056b920e2"
+            + "19005855a213a0f23897cdcd731b4525"
+            + "7c777fe908202befdd0b58386b1244ea"
+            + "0cf539a05d5d10329da44e13030fd760"
+            + "dcd644cfef2094d1910d3f433e1c7c6d"
+            + "d18bc1f2df7f643d662fb9dd37ead905"
+            + "9190f4fa66ca39e869c4eb449cbdc439");
+
+        private static readonly byte[] input_1024_6 = Hex.Decode("26521050844271");
+
+        private static readonly byte[] seed_1024_6 = Hex.Decode(
+              "e4ec0982c2336f3a677f6a356174eb0c"
+            + "e887abc2");
+
+        private static readonly byte[] output_1024_6 = Hex.Decode(
+              "42cee2617b1ecea4db3f4829386fbd61"
+            + "dafbf038e180d837c96366df24c097b4"
+            + "ab0fac6bdf590d821c9f10642e681ad0"
+            + "5b8d78b378c0f46ce2fad63f74e0ad3d"
+            + "f06b075d7eb5f5636f8d403b9059ca76"
+            + "1b5c62bb52aa45002ea70baace08ded2"
+            + "43b9d8cbd62a68ade265832b56564e43"
+            + "a6fa42ed199a099769742df1539e8255");
+
+        private static readonly byte[] modulus_1027 = Hex.Decode(
+              "051240b6cc0004fa48d0134671c078c7"
+            + "c8dec3b3e2f25bc2564467339db38853"
+            + "d06b85eea5b2de353bff42ac2e46bc97"
+            + "fae6ac9618da9537a5c8f553c1e35762"
+            + "5991d6108dcd7885fb3a25413f53efca"
+            + "d948cb35cd9b9ae9c1c67626d113d57d"
+            + "de4c5bea76bb5bb7de96c00d07372e96"
+            + "85a6d75cf9d239fa148d70931b5f3fb0"
+            + "39");
+
+        private static readonly byte[] pubExp_1027 = Hex.Decode("010001");
+
+        private static readonly byte[] privExp_1027 = Hex.Decode(
+              "0411ffca3b7ca5e9e9be7fe38a85105e"
+            + "353896db05c5796aecd2a725161eb365"
+            + "1c8629a9b862b904d7b0c7b37f8cb5a1"
+            + "c2b54001018a00a1eb2cafe4ee4e9492"
+            + "c348bc2bedab4b9ebbf064e8eff322b9"
+            + "009f8eec653905f40df88a3cdc49d456"
+            + "7f75627d41aca624129b46a0b7c698e5"
+            + "e65f2b7ba102c749a10135b6540d0401");
+
+        private static readonly byte[] prime1_1027 = Hex.Decode(
+              "027458c19ec1636919e736c9af25d609"
+            + "a51b8f561d19c6bf6943dd1ee1ab8a4a"
+            + "3f232100bd40b88decc6ba235548b6ef"
+            + "792a11c9de823d0a7922c7095b6eba57"
+            + "01");
+
+        private static readonly byte[] prime2_1027 = Hex.Decode(
+              "0210ee9b33ab61716e27d251bd465f4b"
+            + "35a1a232e2da00901c294bf22350ce49"
+            + "0d099f642b5375612db63ba1f2038649"
+            + "2bf04d34b3c22bceb909d13441b53b51"
+            + "39");
+
+        private static readonly byte[] primeExp1_1027 = Hex.Decode(
+              "39fa028b826e88c1121b750a8b242fa9"
+            + "a35c5b66bdfd1fa637d3cc48a84a4f45"
+            + "7a194e7727e49f7bcc6e5a5a412657fc"
+            + "470c7322ebc37416ef458c307a8c0901");
+
+        private static readonly byte[] primeExp2_1027 = Hex.Decode(
+              "015d99a84195943979fa9e1be2c3c1b6"
+            + "9f432f46fd03e47d5befbbbfd6b1d137"
+            + "1d83efb330a3e020942b2fed115e5d02"
+            + "be24fd92c9019d1cecd6dd4cf1e54cc8"
+            + "99");
+
+        private static readonly byte[] crtCoef_1027 = Hex.Decode(
+              "01f0b7015170b3f5e42223ba30301c41"
+            + "a6d87cbb70e30cb7d3c67d25473db1f6"
+            + "cbf03e3f9126e3e97968279a865b2c2b"
+            + "426524cfc52a683d31ed30eb984be412"
+            + "ba");
+
+        private static readonly byte[] input_1027_1 = Hex.Decode(
+              "4a86609534ee434a6cbca3f7e962e76d"
+            + "455e3264c19f605f6e5ff6137c65c56d"
+            + "7fb344cd52bc93374f3d166c9f0c6f9c"
+            + "506bad19330972d2");
+
+        private static readonly byte[] seed_1027_1 = Hex.Decode(
+              "1cac19ce993def55f98203f6852896c9"
+            + "5ccca1f3");
+
+        private static readonly byte[] output_1027_1 = Hex.Decode(
+              "04cce19614845e094152a3fe18e54e33"
+            + "30c44e5efbc64ae16886cb1869014cc5"
+            + "781b1f8f9e045384d0112a135ca0d12e"
+            + "9c88a8e4063416deaae3844f60d6e96f"
+            + "e155145f4525b9a34431ca3766180f70"
+            + "e15a5e5d8e8b1a516ff870609f13f896"
+            + "935ced188279a58ed13d07114277d75c"
+            + "6568607e0ab092fd803a223e4a8ee0b1"
+            + "a8");
+
+        private static readonly byte[] input_1027_2 = Hex.Decode(
+              "b0adc4f3fe11da59ce992773d9059943"
+            + "c03046497ee9d9f9a06df1166db46d98"
+            + "f58d27ec074c02eee6cbe2449c8b9fc5"
+            + "080c5c3f4433092512ec46aa793743c8");
+
+        private static readonly byte[] seed_1027_2 = Hex.Decode(
+              "f545d5897585e3db71aa0cb8da76c51d"
+            + "032ae963");
+
+        private static readonly byte[] output_1027_2 = Hex.Decode(
+              "0097b698c6165645b303486fbf5a2a44"
+            + "79c0ee85889b541a6f0b858d6b6597b1"
+            + "3b854eb4f839af03399a80d79bda6578"
+            + "c841f90d645715b280d37143992dd186"
+            + "c80b949b775cae97370e4ec97443136c"
+            + "6da484e970ffdb1323a20847821d3b18"
+            + "381de13bb49aaea66530c4a4b8271f3e"
+            + "ae172cd366e07e6636f1019d2a28aed1"
+            + "5e");
+
+        private static readonly byte[] input_1027_3 = Hex.Decode(
+              "bf6d42e701707b1d0206b0c8b45a1c72"
+            + "641ff12889219a82bdea965b5e79a96b"
+            + "0d0163ed9d578ec9ada20f2fbcf1ea3c"
+            + "4089d83419ba81b0c60f3606da99");
+
+        private static readonly byte[] seed_1027_3 = Hex.Decode(
+              "ad997feef730d6ea7be60d0dc52e72ea"
+            + "cbfdd275");
+
+        private static readonly byte[] output_1027_3 = Hex.Decode(
+              "0301f935e9c47abcb48acbbe09895d9f"
+            + "5971af14839da4ff95417ee453d1fd77"
+            + "319072bb7297e1b55d7561cd9d1bb24c"
+            + "1a9a37c619864308242804879d86ebd0"
+            + "01dce5183975e1506989b70e5a834341"
+            + "54d5cbfd6a24787e60eb0c658d2ac193"
+            + "302d1192c6e622d4a12ad4b53923bca2"
+            + "46df31c6395e37702c6a78ae081fb9d0"
+            + "65");
+
+        private static readonly byte[] input_1027_4 = Hex.Decode(
+              "fb2ef112f5e766eb94019297934794f7"
+            + "be2f6fc1c58e");
+
+        private static readonly byte[] seed_1027_4 = Hex.Decode(
+              "136454df5730f73c807a7e40d8c1a312"
+            + "ac5b9dd3");
+
+        private static readonly byte[] output_1027_4 = Hex.Decode(
+              "02d110ad30afb727beb691dd0cf17d0a"
+            + "f1a1e7fa0cc040ec1a4ba26a42c59d0a"
+            + "796a2e22c8f357ccc98b6519aceb682e"
+            + "945e62cb734614a529407cd452bee3e4"
+            + "4fece8423cc19e55548b8b994b849c7e"
+            + "cde4933e76037e1d0ce44275b08710c6"
+            + "8e430130b929730ed77e09b015642c55"
+            + "93f04e4ffb9410798102a8e96ffdfe11"
+            + "e4");
+
+        private static readonly byte[] input_1027_5 = Hex.Decode(
+              "28ccd447bb9e85166dabb9e5b7d1adad"
+            + "c4b9d39f204e96d5e440ce9ad928bc1c"
+            + "2284");
+
+        private static readonly byte[] seed_1027_5 = Hex.Decode(
+              "bca8057f824b2ea257f2861407eef63d"
+            + "33208681");
+
+        private static readonly byte[] output_1027_5 = Hex.Decode(
+              "00dbb8a7439d90efd919a377c54fae8f"
+            + "e11ec58c3b858362e23ad1b8a4431079"
+            + "9066b99347aa525691d2adc58d9b06e3"
+            + "4f288c170390c5f0e11c0aa3645959f1"
+            + "8ee79e8f2be8d7ac5c23d061f18dd74b"
+            + "8c5f2a58fcb5eb0c54f99f01a8324756"
+            + "8292536583340948d7a8c97c4acd1e98"
+            + "d1e29dc320e97a260532a8aa7a758a1e"
+            + "c2");
+
+        private static readonly byte[] input_1027_6 = Hex.Decode("f22242751ec6b1");
+
+        private static readonly byte[] seed_1027_6 = Hex.Decode(
+              "2e7e1e17f647b5ddd033e15472f90f68"
+            + "12f3ac4e");
+
+        private static readonly byte[] output_1027_6 = Hex.Decode(
+              "00a5ffa4768c8bbecaee2db77e8f2eec"
+            + "99595933545520835e5ba7db9493d3e1"
+            + "7cddefe6a5f567624471908db4e2d83a"
+            + "0fbee60608fc84049503b2234a07dc83"
+            + "b27b22847ad8920ff42f674ef79b7628"
+            + "0b00233d2b51b8cb2703a9d42bfbc825"
+            + "0c96ec32c051e57f1b4ba528db89c37e"
+            + "4c54e27e6e64ac69635ae887d9541619"
+            + "a9");
+
+        private void OaepVecTest(
+            int					keySize,
+            int					no,
+            RsaKeyParameters	pubParam,
+            RsaKeyParameters	privParam,
+            byte[]				seed,
+            byte[]				input,
+            byte[]				output)
+        {
+            EncDec(keySize + " " + no, pubParam, privParam, seed, input, output);
+        }
+
+        public override string Name
+        {
+            get { return "OAEP"; }
+        }
+
+        public override void PerformTest()
+        {
+            BaseOaepTest(1, pubKeyEnc1, privKeyEnc1, output1);
+            BaseOaepTest(2, pubKeyEnc2, privKeyEnc2, output2);
+            BaseOaepTest(3, pubKeyEnc3, privKeyEnc3, output3);
+
+            RsaKeyParameters pubParam = new RsaKeyParameters(
+                false,
+                new BigInteger(1, modulus_1024),
+                new BigInteger(1, pubExp_1024));
+            RsaKeyParameters privParam = new RsaPrivateCrtKeyParameters(
+                pubParam.Modulus,
+                pubParam.Exponent,
+                new BigInteger(1, privExp_1024),
+                new BigInteger(1, prime1_1024),
+                new BigInteger(1, prime2_1024),
+                new BigInteger(1, primeExp1_1024),
+                new BigInteger(1, primeExp2_1024),
+                new BigInteger(1, crtCoef_1024));
+
+            OaepVecTest(1024, 1, pubParam, privParam, seed_1024_1, input_1024_1, output_1024_1);
+            OaepVecTest(1024, 2, pubParam, privParam, seed_1024_2, input_1024_2, output_1024_2);
+            OaepVecTest(1024, 3, pubParam, privParam, seed_1024_3, input_1024_3, output_1024_3);
+            OaepVecTest(1024, 4, pubParam, privParam, seed_1024_4, input_1024_4, output_1024_4);
+            OaepVecTest(1024, 5, pubParam, privParam, seed_1024_5, input_1024_5, output_1024_5);
+            OaepVecTest(1024, 6, pubParam, privParam, seed_1024_6, input_1024_6, output_1024_6);
+
+            pubParam = new RsaKeyParameters(
+                false,
+                new BigInteger(1, modulus_1027),
+                new BigInteger(1, pubExp_1027));
+            privParam = new RsaPrivateCrtKeyParameters(
+                pubParam.Modulus,
+                pubParam.Exponent,
+                new BigInteger(1, privExp_1027),
+                new BigInteger(1, prime1_1027),
+                new BigInteger(1, prime2_1027),
+                new BigInteger(1, primeExp1_1027),
+                new BigInteger(1, primeExp2_1027),
+                new BigInteger(1, crtCoef_1027));
+
+            OaepVecTest(1027, 1, pubParam, privParam, seed_1027_1, input_1027_1, output_1027_1);
+            OaepVecTest(1027, 2, pubParam, privParam, seed_1027_2, input_1027_2, output_1027_2);
+            OaepVecTest(1027, 3, pubParam, privParam, seed_1027_3, input_1027_3, output_1027_3);
+            OaepVecTest(1027, 4, pubParam, privParam, seed_1027_4, input_1027_4, output_1027_4);
+            OaepVecTest(1027, 5, pubParam, privParam, seed_1027_5, input_1027_5, output_1027_5);
+            OaepVecTest(1027, 6, pubParam, privParam, seed_1027_6, input_1027_6, output_1027_6);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new OaepTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/OCBTest.cs b/crypto/test/src/crypto/test/OCBTest.cs
new file mode 100644
index 000000000..9f898fbe2
--- /dev/null
+++ b/crypto/test/src/crypto/test/OCBTest.cs
@@ -0,0 +1,515 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * Test vectors from <a href="http://tools.ietf.org/html/rfc7253">RFC 7253 on The OCB
+     * Authenticated-Encryption Algorithm</a>
+     */
+    public class OcbTest
+        : SimpleTest
+    {
+        private const string KEY_128 = "000102030405060708090A0B0C0D0E0F";
+        private const string KEY_96 = "0F0E0D0C0B0A09080706050403020100";
+
+        /*
+         * Test vectors from Appendix A of the specification, containing the strings N, A, P, C in order
+         */
+
+        private static readonly string[][] TEST_VECTORS_128 = new string[][]{
+            new string[]{ "BBAA99887766554433221100",
+              "",
+              "",
+              "785407BFFFC8AD9EDCC5520AC9111EE6" },
+            new string[]{ "BBAA99887766554433221101",
+              "0001020304050607",
+              "0001020304050607",
+              "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009" },
+            new string[]{ "BBAA99887766554433221102",
+              "0001020304050607",
+              "",
+              "81017F8203F081277152FADE694A0A00" },
+            new string[]{ "BBAA99887766554433221103",
+              "",
+              "0001020304050607",
+              "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9" },
+            new string[]{ "BBAA99887766554433221104",
+              "000102030405060708090A0B0C0D0E0F",
+              "000102030405060708090A0B0C0D0E0F",
+              "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5701C1CCEC8FC3358" },
+            new string[]{ "BBAA99887766554433221105",
+              "000102030405060708090A0B0C0D0E0F",
+              "",
+              "8CF761B6902EF764462AD86498CA6B97" },
+            new string[]{ "BBAA99887766554433221106",
+              "",
+              "000102030405060708090A0B0C0D0E0F",
+              "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436BDF06D8FA1ECA343D" },
+            new string[]{ "BBAA99887766554433221107",
+              "000102030405060708090A0B0C0D0E0F1011121314151617",
+              "000102030405060708090A0B0C0D0E0F1011121314151617",
+              "1CA2207308C87C010756104D8840CE1952F09673A448A122C92C62241051F57356D7F3C90BB0E07F" },
+            new string[]{ "BBAA99887766554433221108",
+              "000102030405060708090A0B0C0D0E0F1011121314151617",
+              "",
+              "6DC225A071FC1B9F7C69F93B0F1E10DE" },
+            new string[]{ "BBAA99887766554433221109",
+              "",
+              "000102030405060708090A0B0C0D0E0F1011121314151617",
+              "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3CE725F32494B9F914D85C0B1EB38357FF" },
+            new string[]{ "BBAA9988776655443322110A",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+              "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DEAFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240" },
+            new string[]{ "BBAA9988776655443322110B",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+              "",
+              "FE80690BEE8A485D11F32965BC9D2A32" },
+            new string[]{ "BBAA9988776655443322110C",
+              "",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F",
+              "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF46040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF" },
+            new string[]{ "BBAA9988776655443322110D",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+              "D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483A7035490C5769E60" },
+            new string[]{ "BBAA9988776655443322110E",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+              "",
+              "C5CD9D1850C141E358649994EE701B68" },
+            new string[]{ "BBAA9988776655443322110F",
+              "",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+              "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95A98CA5F3000B1479" },
+        };
+
+        private static readonly string[][] TEST_VECTORS_96 = new string[][]{
+            new string[]{ "BBAA9988776655443322110D",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+              "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627",
+              "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FDAC4F02AA" },
+        };
+
+        public override string Name
+        {
+            get { return "OCB"; }
+        }
+
+        public override void PerformTest()
+        {
+            byte[] K128 = Hex.Decode(KEY_128);
+            for (int i = 0; i < TEST_VECTORS_128.Length; ++i)
+            {
+                RunTestCase("Test Case " + i, TEST_VECTORS_128[i], 128, K128);
+            }
+
+            byte[] K96 = Hex.Decode(KEY_96);
+            for (int i = 0; i < TEST_VECTORS_96.Length; ++i)
+            {
+                RunTestCase("Test Case " + i, TEST_VECTORS_96[i], 96, K96);
+            }
+
+            RunLongerTestCase(128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2");
+            RunLongerTestCase(192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17");
+            RunLongerTestCase(256, 128, "D90EB8E9C977C88B79DD793D7FFA161C");
+            RunLongerTestCase(128, 96, "77A3D8E73589158D25D01209");
+            RunLongerTestCase(192, 96, "05D56EAD2752C86BE6932C5E");
+            RunLongerTestCase(256, 96, "5458359AC23B0CBA9E6330DD");
+            RunLongerTestCase(128, 64, "192C9B7BD90BA06A");
+            RunLongerTestCase(192, 64, "0066BC6E0EF34E24");
+            RunLongerTestCase(256, 64, "7D4EA5D445501CBE");
+
+            RandomTests();
+            OutputSizeTests();
+            DoTestExceptions();
+        }
+
+        private void DoTestExceptions()
+        {
+            IAeadBlockCipher ocb = CreateOcbCipher();
+
+            try
+            {
+                ocb = new OcbBlockCipher(new DesEngine(), new DesEngine());
+                Fail("incorrect block size not picked up");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            try
+            {
+                ocb.Init(false, new KeyParameter(new byte[16]));
+                Fail("illegal argument not picked up");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+
+            // TODO
+            //AEADTestUtil.testReset(this, createOCBCipher(), createOCBCipher(), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[15]));
+            //AEADTestUtil.testTampering(this, ocb, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[15]));
+        }
+
+        private void RunTestCase(string testName, string[] testVector, int macLengthBits, byte[] K)
+        {
+            int pos = 0;
+            byte[] N = Hex.Decode(testVector[pos++]);
+            byte[] A = Hex.Decode(testVector[pos++]);
+            byte[] P = Hex.Decode(testVector[pos++]);
+            byte[] C = Hex.Decode(testVector[pos++]);
+
+            int macLengthBytes = macLengthBits / 8;
+
+            KeyParameter keyParameter = new KeyParameter(K);
+            AeadParameters parameters = new AeadParameters(keyParameter, macLengthBits, N, A);
+
+            IAeadBlockCipher encCipher = InitOcbCipher(true, parameters);
+            IAeadBlockCipher decCipher = InitOcbCipher(false, parameters);
+
+            CheckTestCase(encCipher, decCipher, testName, macLengthBytes, P, C);
+            CheckTestCase(encCipher, decCipher, testName + " (reused)", macLengthBytes, P, C);
+
+            // Key reuse
+            AeadParameters keyReuseParams = AeadTestUtilities.ReuseKey(parameters);
+            encCipher.Init(true, keyReuseParams);
+            decCipher.Init(false, keyReuseParams);
+            CheckTestCase(encCipher, decCipher, testName + " (key reuse)", macLengthBytes, P, C);
+        }
+
+        private IBlockCipher CreateUnderlyingCipher()
+        {
+            return new AesEngine();
+        }
+
+        private IAeadBlockCipher CreateOcbCipher()
+        {
+            return new OcbBlockCipher(CreateUnderlyingCipher(), CreateUnderlyingCipher());
+        }
+
+        private IAeadBlockCipher InitOcbCipher(bool forEncryption, AeadParameters parameters)
+        {
+            IAeadBlockCipher c = CreateOcbCipher();
+            c.Init(forEncryption, parameters);
+            return c;
+        }
+
+        private void CheckTestCase(IAeadBlockCipher encCipher, IAeadBlockCipher decCipher, string testName,
+            int macLengthBytes, byte[] P, byte[] C)
+        {
+            byte[] tag = Arrays.CopyOfRange(C, C.Length - macLengthBytes, C.Length);
+
+            {
+                byte[] enc = new byte[encCipher.GetOutputSize(P.Length)];
+                int len = encCipher.ProcessBytes(P, 0, P.Length, enc, 0);
+                len += encCipher.DoFinal(enc, len);
+
+                if (enc.Length != len)
+                {
+                    Fail("encryption reported incorrect length: " + testName);
+                }
+
+                if (!AreEqual(C, enc))
+                {
+                    Fail("incorrect encrypt in: " + testName);
+                }
+
+                if (!AreEqual(tag, encCipher.GetMac()))
+                {
+                    Fail("getMac() not the same as the appended tag: " + testName);
+                }
+            }
+
+            {
+                byte[] dec = new byte[decCipher.GetOutputSize(C.Length)];
+                int len = decCipher.ProcessBytes(C, 0, C.Length, dec, 0);
+                len += decCipher.DoFinal(dec, len);
+
+                if (dec.Length != len)
+                {
+                    Fail("decryption reported incorrect length: " + testName);
+                }
+
+                if (!AreEqual(P, dec))
+                {
+                    Fail("incorrect decrypt in: " + testName);
+                }
+
+                if (!AreEqual(tag, decCipher.GetMac()))
+                {
+                    Fail("getMac() not the same as the appended tag: " + testName);
+                }
+            }
+        }
+
+        private void RunLongerTestCase(int keyLen, int tagLen, string expectedOutputHex)
+        {
+            byte[] expectedOutput = Hex.Decode(expectedOutputHex);
+            byte[] keyBytes = new byte[keyLen / 8];
+            keyBytes[keyBytes.Length - 1] = (byte)tagLen;
+            KeyParameter key = new KeyParameter(keyBytes);
+
+            IAeadBlockCipher c1 = InitOcbCipher(true, new AeadParameters(key, tagLen, CreateNonce(385)));
+            IAeadBlockCipher c2 = CreateOcbCipher();
+
+            long total = 0;
+
+            byte[] S = new byte[128];
+
+            uint n = 0;
+            for (int i = 0; i < 128; ++i)
+            {
+                c2.Init(true, new AeadParameters(key, tagLen, CreateNonce(++n)));
+                total += UpdateCiphers(c1, c2, S, i, true, true);
+                c2.Init(true, new AeadParameters(key, tagLen, CreateNonce(++n)));
+                total += UpdateCiphers(c1, c2, S, i, false, true);
+                c2.Init(true, new AeadParameters(key, tagLen, CreateNonce(++n)));
+                total += UpdateCiphers(c1, c2, S, i, true, false);
+            }
+
+            long expectedTotal = 16256 + (48 * tagLen);
+
+            if (total != expectedTotal)
+            {
+                Fail("test generated the wrong amount of input: " + total);
+            }
+
+            byte[] output = new byte[c1.GetOutputSize(0)];
+            c1.DoFinal(output, 0);
+
+            if (!AreEqual(expectedOutput, output))
+            {
+                Fail("incorrect encrypt in long-form test");
+            }
+        }
+
+        private byte[] CreateNonce(uint n)
+        {
+            return new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)(n >> 8), (byte)n };
+        }
+
+        private int UpdateCiphers(IAeadBlockCipher c1, IAeadBlockCipher c2, byte[] S, int i,
+            bool includeAAD, bool includePlaintext)
+        {
+            int inputLen = includePlaintext ? i : 0;
+            int outputLen = c2.GetOutputSize(inputLen);
+
+            byte[] output = new byte[outputLen];
+
+            int len = 0;
+
+            if (includeAAD) {
+                c2.ProcessAadBytes(S, 0, i);
+            }
+
+            if (includePlaintext) {
+                len += c2.ProcessBytes(S, 0, i, output, len);
+            }
+
+            len += c2.DoFinal(output, len);
+
+            c1.ProcessAadBytes(output, 0, len);
+
+            return len;
+        }
+
+        private void RandomTests()
+        {
+            SecureRandom srng = new SecureRandom();
+            srng.SetSeed(DateTimeUtilities.CurrentUnixMs());
+            for (int i = 0; i < 10; ++i)
+            {
+                RandomTest(srng);
+            }
+        }
+
+        private void RandomTest(SecureRandom srng)
+        {
+            int kLength = 16 + 8 * (System.Math.Abs(srng.NextInt()) % 3);
+            byte[] K = new byte[kLength];
+            srng.NextBytes(K);
+
+            int pLength = (int)((uint)srng.NextInt() >> 16);
+            byte[] P = new byte[pLength];
+            srng.NextBytes(P);
+
+            int aLength = (int)((uint)srng.NextInt() >> 24);
+            byte[] A = new byte[aLength];
+            srng.NextBytes(A);
+
+            int saLength = (int)((uint)srng.NextInt() >> 24);
+            byte[] SA = new byte[saLength];
+            srng.NextBytes(SA);
+
+            int ivLength = 1 + NextInt(srng, 15);
+            byte[] IV = new byte[ivLength];
+            srng.NextBytes(IV);
+
+            AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A);
+            IAeadBlockCipher cipher = InitOcbCipher(true, parameters);
+            byte[] C = new byte[cipher.GetOutputSize(P.Length)];
+            int predicted = cipher.GetUpdateOutputSize(P.Length);
+
+            int split = NextInt(srng, SA.Length + 1);
+            cipher.ProcessAadBytes(SA, 0, split);
+            int len = cipher.ProcessBytes(P, 0, P.Length, C, 0);
+            cipher.ProcessAadBytes(SA, split, SA.Length - split);
+
+            if (predicted != len)
+            {
+                Fail("encryption reported incorrect update length in randomised test");
+            }
+
+            len += cipher.DoFinal(C, len);
+
+            if (C.Length != len)
+            {
+                Fail("encryption reported incorrect length in randomised test");
+            }
+
+            byte[] encT = cipher.GetMac();
+            byte[] tail = new byte[C.Length - P.Length];
+            Array.Copy(C, P.Length, tail, 0, tail.Length);
+
+            if (!AreEqual(encT, tail))
+            {
+                Fail("stream contained wrong mac in randomised test");
+            }
+
+            cipher.Init(false, parameters);
+            byte[] decP = new byte[cipher.GetOutputSize(C.Length)];
+            predicted = cipher.GetUpdateOutputSize(C.Length);
+
+            split = NextInt(srng, SA.Length + 1);
+            cipher.ProcessAadBytes(SA, 0, split);
+            len = cipher.ProcessBytes(C, 0, C.Length, decP, 0);
+            cipher.ProcessAadBytes(SA, split, SA.Length - split);
+
+            if (predicted != len)
+            {
+                Fail("decryption reported incorrect update length in randomised test");
+            }
+
+            len += cipher.DoFinal(decP, len);
+
+            if (!AreEqual(P, decP))
+            {
+                Fail("incorrect decrypt in randomised test");
+            }
+
+            byte[] decT = cipher.GetMac();
+            if (!AreEqual(encT, decT))
+            {
+                Fail("decryption produced different mac from encryption");
+            }
+
+            //
+            // key reuse test
+            //
+            cipher.Init(false, AeadTestUtilities.ReuseKey(parameters));
+            decP = new byte[cipher.GetOutputSize(C.Length)];
+
+            split = NextInt(srng, SA.Length + 1);
+            cipher.ProcessAadBytes(SA, 0, split);
+            len = cipher.ProcessBytes(C, 0, C.Length, decP, 0);
+            cipher.ProcessAadBytes(SA, split, SA.Length - split);
+
+            len += cipher.DoFinal(decP, len);
+
+            if (!AreEqual(P, decP))
+            {
+                Fail("incorrect decrypt in randomised test");
+            }
+
+            decT = cipher.GetMac();
+            if (!AreEqual(encT, decT))
+            {
+                Fail("decryption produced different mac from encryption");
+            }
+        }
+
+        private void OutputSizeTests()
+        {
+            byte[] K = new byte[16];
+            byte[] A = null;
+            byte[] IV = new byte[15];
+
+            AeadParameters parameters = new AeadParameters(new KeyParameter(K), 16 * 8, IV, A);
+            IAeadBlockCipher cipher = InitOcbCipher(true, parameters);
+
+            if (cipher.GetUpdateOutputSize(0) != 0)
+            {
+                Fail("incorrect getUpdateOutputSize for initial 0 bytes encryption");
+            }
+
+            if (cipher.GetOutputSize(0) != 16)
+            {
+                Fail("incorrect getOutputSize for initial 0 bytes encryption");
+            }
+
+            cipher.Init(false, parameters);
+
+            if (cipher.GetUpdateOutputSize(0) != 0)
+            {
+                Fail("incorrect getUpdateOutputSize for initial 0 bytes decryption");
+            }
+
+            // NOTE: 0 bytes would be truncated data, but we want it to fail in the doFinal, not here
+            if (cipher.GetOutputSize(0) != 0)
+            {
+                Fail("fragile getOutputSize for initial 0 bytes decryption");
+            }
+
+            if (cipher.GetOutputSize(16) != 0)
+            {
+                Fail("incorrect getOutputSize for initial MAC-size bytes decryption");
+            }
+        }
+
+        private static int NextInt(SecureRandom rand, int n)
+        {
+            if ((n & -n) == n)  // i.e., n is a power of 2
+            {
+                return (int)(((uint)n * (ulong)((uint)rand.NextInt() >> 1)) >> 31);
+            }
+
+            int bits, value;
+            do
+            {
+                bits = (int)((uint)rand.NextInt() >> 1);
+                value = bits % n;
+            }
+            while (bits - value + (n - 1) < 0);
+
+            return value;
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new OcbTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/PSSBlindTest.cs b/crypto/test/src/crypto/test/PSSBlindTest.cs
new file mode 100644
index 000000000..d887a8f08
--- /dev/null
+++ b/crypto/test/src/crypto/test/PSSBlindTest.cs
@@ -0,0 +1,399 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/*
+	* RSA PSS test vectors for PKCS#1 V2.1 with blinding
+	*/
+	[TestFixture]
+	public class PssBlindTest
+		: SimpleTest
+	{
+		private readonly int DATA_LENGTH = 1000;
+		private readonly int NUM_TESTS = 50;
+		private readonly int NUM_TESTS_WITH_KEY_GENERATION = 10;
+
+		private class FixedRandom
+			: SecureRandom
+		{
+			private readonly byte[] vals;
+
+			public FixedRandom(
+				byte[] vals)
+			{
+				this.vals = vals;
+			}
+
+			public override void NextBytes(
+				byte[] bytes)
+			{
+				Array.Copy(vals, 0, bytes, 0, vals.Length);
+			}
+		}
+
+		//
+		// Example 1: A 1024-bit RSA keypair
+		//
+		private RsaKeyParameters pub1 = new RsaKeyParameters(false,
+					new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+					new BigInteger("010001",16));
+
+		private RsaKeyParameters prv1 = new RsaPrivateCrtKeyParameters(
+					new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+					new BigInteger("010001",16),
+					new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+					new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+					new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+					new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+					new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+					new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+		// PSSExample1.1
+
+		private byte[] msg1a = Hex.Decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0");
+
+		private byte[] slt1a = Hex.Decode("dee959c7e06411361420ff80185ed57f3e6776af");
+
+		private byte[] sig1a = Hex.Decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c");
+
+		// PSSExample1.2
+
+		private byte[] msg1b = Hex.Decode("851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e");
+
+		private byte[] slt1b = Hex.Decode("ef2869fa40c346cb183dab3d7bffc98fd56df42d");
+
+		private byte[] sig1b = Hex.Decode("3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843");
+
+		//
+		// Example 2: A 1025-bit RSA keypair
+		//
+
+		private RsaKeyParameters pub2 = new RsaKeyParameters(false,
+					new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16),
+					new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv2 = new RsaPrivateCrtKeyParameters(
+					new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16),
+					new BigInteger("010001", 16),
+					new BigInteger("027d147e4673057377fd1ea201565772176a7dc38358d376045685a2e787c23c15576bc16b9f444402d6bfc5d98a3e88ea13ef67c353eca0c0ddba9255bd7b8bb50a644afdfd1dd51695b252d22e7318d1b6687a1c10ff75545f3db0fe602d5f2b7f294e3601eab7b9d1cecd767f64692e3e536ca2846cb0c2dd486a39fa75b1", 16),
+					new BigInteger("016601e926a0f8c9e26ecab769ea65a5e7c52cc9e080ef519457c644da6891c5a104d3ea7955929a22e7c68a7af9fcad777c3ccc2b9e3d3650bce404399b7e59d1", 16),
+					new BigInteger("014eafa1d4d0184da7e31f877d1281ddda625664869e8379e67ad3b75eae74a580e9827abd6eb7a002cb5411f5266797768fb8e95ae40e3e8a01f35ff89e56c079", 16),
+					new BigInteger("e247cce504939b8f0a36090de200938755e2444b29539a7da7a902f6056835c0db7b52559497cfe2c61a8086d0213c472c78851800b171f6401de2e9c2756f31", 16),
+					new BigInteger("b12fba757855e586e46f64c38a70c68b3f548d93d787b399999d4c8f0bbd2581c21e19ed0018a6d5d3df86424b3abcad40199d31495b61309f27c1bf55d487c1", 16),
+					new BigInteger("564b1e1fa003bda91e89090425aac05b91da9ee25061e7628d5f51304a84992fdc33762bd378a59f030a334d532bd0dae8f298ea9ed844636ad5fb8cbdc03cad", 16));
+
+		// PSS Example 2.1
+
+		private byte[] msg2a = Hex.Decode("daba032066263faedb659848115278a52c44faa3a76f37515ed336321072c40a9d9b53bc05014078adf520875146aae70ff060226dcb7b1f1fc27e9360");
+		private byte[] slt2a = Hex.Decode("57bf160bcb02bb1dc7280cf0458530b7d2832ff7");
+		private byte[] sig2a = Hex.Decode("014c5ba5338328ccc6e7a90bf1c0ab3fd606ff4796d3c12e4b639ed9136a5fec6c16d8884bdd99cfdc521456b0742b736868cf90de099adb8d5ffd1deff39ba4007ab746cefdb22d7df0e225f54627dc65466131721b90af445363a8358b9f607642f78fab0ab0f43b7168d64bae70d8827848d8ef1e421c5754ddf42c2589b5b3");
+
+		// PSS Example 2.2
+
+		private byte[] msg2b = Hex.Decode("e4f8601a8a6da1be34447c0959c058570c3668cfd51dd5f9ccd6ad4411fe8213486d78a6c49f93efc2ca2288cebc2b9b60bd04b1e220d86e3d4848d709d032d1e8c6a070c6af9a499fcf95354b14ba6127c739de1bb0fd16431e46938aec0cf8ad9eb72e832a7035de9b7807bdc0ed8b68eb0f5ac2216be40ce920c0db0eddd3860ed788efaccaca502d8f2bd6d1a7c1f41ff46f1681c8f1f818e9c4f6d91a0c7803ccc63d76a6544d843e084e363b8acc55aa531733edb5dee5b5196e9f03e8b731b3776428d9e457fe3fbcb3db7274442d785890e9cb0854b6444dace791d7273de1889719338a77fe");
+		private byte[] slt2b = Hex.Decode("7f6dd359e604e60870e898e47b19bf2e5a7b2a90");
+		private byte[] sig2b = Hex.Decode("010991656cca182b7f29d2dbc007e7ae0fec158eb6759cb9c45c5ff87c7635dd46d150882f4de1e9ae65e7f7d9018f6836954a47c0a81a8a6b6f83f2944d6081b1aa7c759b254b2c34b691da67cc0226e20b2f18b42212761dcd4b908a62b371b5918c5742af4b537e296917674fb914194761621cc19a41f6fb953fbcbb649dea");
+
+		//
+		//  Example 4: A 1027-bit RSA key pair
+		//
+
+		private RsaKeyParameters pub4 = new RsaKeyParameters(false,
+					new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16),
+					new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv4 = new RsaPrivateCrtKeyParameters(
+					new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16),
+					new BigInteger("010001", 16),
+					new BigInteger("fa041f8cd9697ceed38ec8caa275523b4dd72b09a301d3541d72f5d31c05cbce2d6983b36183af10690bd46c46131e35789431a556771dd0049b57461bf060c1f68472e8a67c25f357e5b6b4738fa541a730346b4a07649a2dfa806a69c975b6aba64678acc7f5913e89c622f2d8abb1e3e32554e39df94ba60c002e387d9011", 16),
+					new BigInteger("029232336d2838945dba9dd7723f4e624a05f7375b927a87abe6a893a1658fd49f47f6c7b0fa596c65fa68a23f0ab432962d18d4343bd6fd671a5ea8d148413995", 16),
+					new BigInteger("020ef5efe7c5394aed2272f7e81a74f4c02d145894cb1b3cab23a9a0710a2afc7e3329acbb743d01f680c4d02afb4c8fde7e20930811bb2b995788b5e872c20bb1", 16),
+					new BigInteger("026e7e28010ecf2412d9523ad704647fb4fe9b66b1a681581b0e15553a89b1542828898f27243ebab45ff5e1acb9d4df1b051fbc62824dbc6f6c93261a78b9a759", 16),
+					new BigInteger("012ddcc86ef655998c39ddae11718669e5e46cf1495b07e13b1014cd69b3af68304ad2a6b64321e78bf3bbca9bb494e91d451717e2d97564c6549465d0205cf421", 16),
+					new BigInteger("010600c4c21847459fe576703e2ebecae8a5094ee63f536bf4ac68d3c13e5e4f12ac5cc10ab6a2d05a199214d1824747d551909636b774c22cac0b837599abcc75", 16));
+
+		// PSS Example 4.1
+
+		private byte[] msg4a = Hex.Decode("9fb03b827c8217d9");
+
+		private byte[] slt4a = Hex.Decode("ed7c98c95f30974fbe4fbddcf0f28d6021c0e91d");
+
+		private byte[] sig4a = Hex.Decode("0323d5b7bf20ba4539289ae452ae4297080feff4518423ff4811a817837e7d82f1836cdfab54514ff0887bddeebf40bf99b047abc3ecfa6a37a3ef00f4a0c4a88aae0904b745c846c4107e8797723e8ac810d9e3d95dfa30ff4966f4d75d13768d20857f2b1406f264cfe75e27d7652f4b5ed3575f28a702f8c4ed9cf9b2d44948");
+
+		// PSS Example 4.2
+
+		private byte[] msg4b = Hex.Decode("0ca2ad77797ece86de5bf768750ddb5ed6a3116ad99bbd17edf7f782f0db1cd05b0f677468c5ea420dc116b10e80d110de2b0461ea14a38be68620392e7e893cb4ea9393fb886c20ff790642305bf302003892e54df9f667509dc53920df583f50a3dd61abb6fab75d600377e383e6aca6710eeea27156e06752c94ce25ae99fcbf8592dbe2d7e27453cb44de07100ebb1a2a19811a478adbeab270f94e8fe369d90b3ca612f9f");
+
+		private byte[] slt4b = Hex.Decode("22d71d54363a4217aa55113f059b3384e3e57e44");
+
+		private byte[] sig4b = Hex.Decode("049d0185845a264d28feb1e69edaec090609e8e46d93abb38371ce51f4aa65a599bdaaa81d24fba66a08a116cb644f3f1e653d95c89db8bbd5daac2709c8984000178410a7c6aa8667ddc38c741f710ec8665aa9052be929d4e3b16782c1662114c5414bb0353455c392fc28f3db59054b5f365c49e1d156f876ee10cb4fd70598");
+
+
+		//
+		// Example 8: A 1031-bit RSA key pair
+		//
+
+		private RsaKeyParameters pub8 = new RsaKeyParameters(false,
+					new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16),
+					new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv8 = new RsaPrivateCrtKeyParameters(
+					new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16),
+					new BigInteger("010001", 16),
+					new BigInteger("6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701c2d6266d517219ad0ec6d347dbe9", 16),
+					new BigInteger("08dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab72619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c8060645a1d29edb", 16),
+					new BigInteger("0847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca4174825b48f49706d", 16),
+					new BigInteger("05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fce69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee103deb771d105fd85", 16),
+					new BigInteger("04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b3669bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e30a7e7d241551e1b9", 16),
+					new BigInteger("07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef531b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7b06e45307dc91f3f", 16));
+
+		// PSS Example 8.1
+
+		private byte[] msg8a = Hex.Decode("81332f4be62948415ea1d899792eeacf6c6e1db1da8be13b5cea41db2fed467092e1ff398914c714259775f595f8547f735692a575e6923af78f22c6997ddb90fb6f72d7bb0dd5744a31decd3dc3685849836ed34aec596304ad11843c4f88489f209735f5fb7fdaf7cec8addc5818168f880acbf490d51005b7a8e84e43e54287977571dd99eea4b161eb2df1f5108f12a4142a83322edb05a75487a3435c9a78ce53ed93bc550857d7a9fb");
+
+		private byte[] slt8a = Hex.Decode("1d65491d79c864b373009be6f6f2467bac4c78fa");
+
+		private byte[] sig8a = Hex.Decode("0262ac254bfa77f3c1aca22c5179f8f040422b3c5bafd40a8f21cf0fa5a667ccd5993d42dbafb409c520e25fce2b1ee1e716577f1efa17f3da28052f40f0419b23106d7845aaf01125b698e7a4dfe92d3967bb00c4d0d35ba3552ab9a8b3eef07c7fecdbc5424ac4db1e20cb37d0b2744769940ea907e17fbbca673b20522380c5");
+
+		// PSS Example 8.2
+
+		private byte[] msg8b = Hex.Decode("e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3cede9d0faabf4fcc8e60a973e5595fd9ea08");
+
+		private byte[] slt8b = Hex.Decode("435c098aa9909eb2377f1248b091b68987ff1838");
+
+		private byte[] sig8b = Hex.Decode("2707b9ad5115c58c94e932e8ec0a280f56339e44a1b58d4ddcff2f312e5f34dcfe39e89c6a94dcee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6c86ee68396e8b3a14c9c8f34b178eb741f9d3f121109bf5c8172fada2e768f9ea1433032c004a8aa07eb990000a48dc94c8bac8aabe2b09b1aa46c0a2aa0e12f63fbba775ba7e");
+
+		//
+		// Example 9: A 1536-bit RSA key pair
+		//
+
+		private RsaKeyParameters pub9 = new RsaKeyParameters(false,
+					new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16),
+					new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv9 = new RsaPrivateCrtKeyParameters(
+					new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16),
+					new BigInteger("010001", 16),
+					new BigInteger("6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d51410b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf21311666070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab328ce420689903c00c7b5fd31b75503a6d419684d629", 16),
+					new BigInteger("f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f6154a762aed165d47dee367", 16),
+					new BigInteger("ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e4728cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b489c176128092d629e49d3d", 16),
+					new BigInteger("2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0ab556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec993e9353e480d9eec6289f", 16),
+					new BigInteger("4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56ee4dba42c5fdb61aec2669", 16),
+					new BigInteger("77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124cbbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65757bb3f857a58dce52156", 16));
+
+		// PSS Example 9.1
+
+		private byte[] msg9a = Hex.Decode("a88e265855e9d7ca36c68795f0b31b591cd6587c71d060a0b3f7f3eaef43795922028bc2b6ad467cfc2d7f659c5385aa70ba3672cdde4cfe4970cc7904601b278872bf51321c4a972f3c95570f3445d4f57980e0f20df54846e6a52c668f1288c03f95006ea32f562d40d52af9feb32f0fa06db65b588a237b34e592d55cf979f903a642ef64d2ed542aa8c77dc1dd762f45a59303ed75e541ca271e2b60ca709e44fa0661131e8d5d4163fd8d398566ce26de8730e72f9cca737641c244159420637028df0a18079d6208ea8b4711a2c750f5");
+
+		private byte[] slt9a = Hex.Decode("c0a425313df8d7564bd2434d311523d5257eed80");
+
+		private byte[] sig9a = Hex.Decode("586107226c3ce013a7c8f04d1a6a2959bb4b8e205ba43a27b50f124111bc35ef589b039f5932187cb696d7d9a32c0c38300a5cdda4834b62d2eb240af33f79d13dfbf095bf599e0d9686948c1964747b67e89c9aba5cd85016236f566cc5802cb13ead51bc7ca6bef3b94dcbdbb1d570469771df0e00b1a8a06777472d2316279edae86474668d4e1efff95f1de61c6020da32ae92bbf16520fef3cf4d88f61121f24bbd9fe91b59caf1235b2a93ff81fc403addf4ebdea84934a9cdaf8e1a9e");
+
+		// PSS Example 9.2
+
+		private byte[] msg9b = Hex.Decode("c8c9c6af04acda414d227ef23e0820c3732c500dc87275e95b0d095413993c2658bc1d988581ba879c2d201f14cb88ced153a01969a7bf0a7be79c84c1486bc12b3fa6c59871b6827c8ce253ca5fefa8a8c690bf326e8e37cdb96d90a82ebab69f86350e1822e8bd536a2e");
+
+		private byte[] slt9b = Hex.Decode("b307c43b4850a8dac2f15f32e37839ef8c5c0e91");
+
+		private byte[] sig9b = Hex.Decode("80b6d643255209f0a456763897ac9ed259d459b49c2887e5882ecb4434cfd66dd7e1699375381e51cd7f554f2c271704b399d42b4be2540a0eca61951f55267f7c2878c122842dadb28b01bd5f8c025f7e228418a673c03d6bc0c736d0a29546bd67f786d9d692ccea778d71d98c2063b7a71092187a4d35af108111d83e83eae46c46aa34277e06044589903788f1d5e7cee25fb485e92949118814d6f2c3ee361489016f327fb5bc517eb50470bffa1afa5f4ce9aa0ce5b8ee19bf5501b958");
+
+
+		public override string Name
+		{
+			get { return "PssBlindTest"; }
+		}
+
+		private void testSig(
+			int                 id,
+			RsaKeyParameters    pub,
+			RsaKeyParameters    prv,
+			byte[]              slt,
+			byte[]              msg,
+			byte[]              sig)
+		{
+			RsaBlindingFactorGenerator blindFactorGen = new RsaBlindingFactorGenerator();
+			RsaBlindingEngine blindingEngine = new RsaBlindingEngine();
+			PssSigner blindSigner = new PssSigner(blindingEngine, new Sha1Digest(), 20);
+			PssSigner signer = new PssSigner(new RsaEngine(), new Sha1Digest(), 20);
+
+			blindFactorGen.Init(pub);
+
+			BigInteger blindFactor = blindFactorGen.GenerateBlindingFactor();
+			RsaBlindingParameters parameters = new RsaBlindingParameters(pub, blindFactor);
+
+			// generate a blind signature
+			blindSigner.Init(true, new ParametersWithRandom(parameters, new FixedRandom(slt)));
+
+			blindSigner.BlockUpdate(msg, 0, msg.Length);
+
+			byte[] blindedData = blindSigner.GenerateSignature();
+
+			RsaEngine signerEngine = new RsaEngine();
+
+			signerEngine.Init(true, prv);
+
+			byte[] blindedSig = signerEngine.ProcessBlock(blindedData, 0, blindedData.Length);
+
+			// unblind the signature
+			blindingEngine.Init(false, parameters);
+
+			byte[] s = blindingEngine.ProcessBlock(blindedSig, 0, blindedSig.Length);
+
+			//signature verification
+			if (!AreEqual(s, sig))
+			{
+				Fail("test " + id + " failed generation");
+			}
+	        
+			//verify signature with PssSigner
+			signer.Init(false, pub);
+			signer.BlockUpdate(msg, 0, msg.Length);
+
+			if (!signer.VerifySignature(s))
+			{
+        		Fail("test " + id + " failed PssSigner verification");
+			}
+		}
+
+		private bool isProcessingOkay(
+			RsaKeyParameters    pub,
+			RsaKeyParameters    prv,
+			byte[]              data,
+			SecureRandom        random)
+		{
+			RsaBlindingFactorGenerator blindFactorGen = new RsaBlindingFactorGenerator();
+			RsaBlindingEngine blindingEngine = new RsaBlindingEngine();
+			PssSigner blindSigner = new PssSigner(blindingEngine, new Sha1Digest(), 20);
+			PssSigner pssEng = new PssSigner(new RsaEngine(), new Sha1Digest(), 20);
+
+			random.NextBytes(data);
+
+			blindFactorGen.Init(pub);
+
+			BigInteger blindFactor = blindFactorGen.GenerateBlindingFactor();
+			RsaBlindingParameters parameters = new RsaBlindingParameters(pub, blindFactor);
+
+			// generate a blind signature
+			blindSigner.Init(true, new ParametersWithRandom(parameters, random));
+
+			blindSigner.BlockUpdate(data, 0, data.Length);
+
+			byte[] blindedData = blindSigner.GenerateSignature();
+
+			RsaEngine signerEngine = new RsaEngine();
+
+			signerEngine.Init(true, prv);
+
+			byte[] blindedSig = signerEngine.ProcessBlock(blindedData, 0, blindedData.Length);
+
+			// unblind the signature
+			blindingEngine.Init(false, parameters);
+
+			byte[] s = blindingEngine.ProcessBlock(blindedSig, 0, blindedSig.Length);
+
+			//verify signature with PssSigner
+			pssEng.Init(false, pub);
+			pssEng.BlockUpdate(data, 0, data.Length);
+
+			return pssEng.VerifySignature(s);
+		}
+
+		public override void PerformTest()
+		{
+			testSig(1, pub1, prv1, slt1a, msg1a, sig1a);
+			testSig(2, pub1, prv1, slt1b, msg1b, sig1b);
+			testSig(3, pub2, prv2, slt2a, msg2a, sig2a);
+			testSig(4, pub2, prv2, slt2b, msg2b, sig2b);
+			testSig(5, pub4, prv4, slt4a, msg4a, sig4a);
+			testSig(6, pub4, prv4, slt4b, msg4b, sig4b);
+			testSig(7, pub8, prv8, slt8a, msg8a, sig8a);
+			testSig(8, pub8, prv8, slt8b, msg8b, sig8b);
+			testSig(9, pub9, prv9, slt9a, msg9a, sig9a);
+			testSig(10, pub9, prv9, slt9b, msg9b, sig9b);
+	        
+			//
+			// loop test
+			//
+			int failed = 0;
+			byte[] data = new byte[DATA_LENGTH];
+
+			SecureRandom    random = new SecureRandom();
+
+
+			RsaKeyParameters[] kprv ={prv1, prv2, prv4, prv8, prv9};
+			RsaKeyParameters[] kpub ={pub1, pub2, pub4, pub8, pub9};
+
+			for (int j = 0, i = 0; j < NUM_TESTS; j++, i++)
+			{
+        		if (i == kprv.Length)
+				{
+					i = 0;
+				}
+
+				if (!isProcessingOkay(kpub[i], kprv[i], data, random))
+				{
+            		failed++;
+				}
+			}
+
+			if (failed != 0)
+			{
+				Fail("loop test failed - failures: " + failed);
+			}
+
+			//
+			// key generation test
+			//
+			RsaKeyPairGenerator pGen = new RsaKeyPairGenerator();
+			RsaKeyGenerationParameters genParam = new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x11), new SecureRandom(), 1024, 25);
+
+			pGen.Init(genParam);
+			failed = 0;
+
+			for (int k = 0; k < NUM_TESTS_WITH_KEY_GENERATION; k++)
+			{
+        		AsymmetricCipherKeyPair pair = pGen.GenerateKeyPair();
+
+				for (int j = 0; j < NUM_TESTS; j++)
+				{
+					if (!isProcessingOkay((RsaKeyParameters)pair.Public, (RsaKeyParameters)pair.Private, data, random))
+					{
+						failed++;
+					}
+				}
+			}
+
+			if (failed != 0)
+			{
+				Fail("loop test with key generation failed - failures: " + failed);
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PssBlindTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/PSSTest.cs b/crypto/test/src/crypto/test/PSSTest.cs
new file mode 100644
index 000000000..91d8d3a6e
--- /dev/null
+++ b/crypto/test/src/crypto/test/PSSTest.cs
@@ -0,0 +1,338 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <remarks>RSA PSS test vectors for PKCS#1 V2.1</remarks>
+	[TestFixture]
+	public class PssTest
+		: SimpleTest
+	{
+		private const int DataLength = 1000;
+		private const int NumTests = 500;
+
+		private class FixedRandom
+			: SecureRandom
+		{
+			private readonly byte[] vals;
+
+			public FixedRandom(
+				byte[] vals)
+			{
+				this.vals = vals;
+			}
+
+			public override void NextBytes(
+				byte[] bytes)
+			{
+				Array.Copy(vals, 0, bytes, 0, vals.Length);
+			}
+		}
+
+		//
+		// Example 1: A 1024-bit RSA keypair
+		//
+		private RsaKeyParameters pub1 = new RsaKeyParameters(false,
+			new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+			new BigInteger("010001",16));
+
+		private RsaKeyParameters prv1 = new RsaPrivateCrtKeyParameters(
+			new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+			new BigInteger("010001",16),
+			new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+			new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+			new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+			new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+			new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+			new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+		// PSSExample1.1
+
+		private byte[] msg1a = Hex.Decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0");
+
+		private byte[] slt1a = Hex.Decode("dee959c7e06411361420ff80185ed57f3e6776af");
+
+		private byte[] sig1a = Hex.Decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c");
+
+		// PSSExample1.2
+
+		private byte[] msg1b = Hex.Decode("851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e");
+
+		private byte[] slt1b = Hex.Decode("ef2869fa40c346cb183dab3d7bffc98fd56df42d");
+
+		private byte[] sig1b = Hex.Decode("3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843");
+
+		//
+		// Example 2: A 1025-bit RSA keypair
+		//
+
+		private RsaKeyParameters pub2 = new RsaKeyParameters(false,
+			new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16),
+			new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv2 = new RsaPrivateCrtKeyParameters(
+			new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16),
+			new BigInteger("010001", 16),
+			new BigInteger("027d147e4673057377fd1ea201565772176a7dc38358d376045685a2e787c23c15576bc16b9f444402d6bfc5d98a3e88ea13ef67c353eca0c0ddba9255bd7b8bb50a644afdfd1dd51695b252d22e7318d1b6687a1c10ff75545f3db0fe602d5f2b7f294e3601eab7b9d1cecd767f64692e3e536ca2846cb0c2dd486a39fa75b1", 16),
+			new BigInteger("016601e926a0f8c9e26ecab769ea65a5e7c52cc9e080ef519457c644da6891c5a104d3ea7955929a22e7c68a7af9fcad777c3ccc2b9e3d3650bce404399b7e59d1", 16),
+			new BigInteger("014eafa1d4d0184da7e31f877d1281ddda625664869e8379e67ad3b75eae74a580e9827abd6eb7a002cb5411f5266797768fb8e95ae40e3e8a01f35ff89e56c079", 16),
+			new BigInteger("e247cce504939b8f0a36090de200938755e2444b29539a7da7a902f6056835c0db7b52559497cfe2c61a8086d0213c472c78851800b171f6401de2e9c2756f31", 16),
+			new BigInteger("b12fba757855e586e46f64c38a70c68b3f548d93d787b399999d4c8f0bbd2581c21e19ed0018a6d5d3df86424b3abcad40199d31495b61309f27c1bf55d487c1", 16),
+			new BigInteger("564b1e1fa003bda91e89090425aac05b91da9ee25061e7628d5f51304a84992fdc33762bd378a59f030a334d532bd0dae8f298ea9ed844636ad5fb8cbdc03cad", 16));
+
+		// PSS Example 2.1
+
+		private byte[] msg2a = Hex.Decode("daba032066263faedb659848115278a52c44faa3a76f37515ed336321072c40a9d9b53bc05014078adf520875146aae70ff060226dcb7b1f1fc27e9360");
+		private byte[] slt2a = Hex.Decode("57bf160bcb02bb1dc7280cf0458530b7d2832ff7");
+		private byte[] sig2a = Hex.Decode("014c5ba5338328ccc6e7a90bf1c0ab3fd606ff4796d3c12e4b639ed9136a5fec6c16d8884bdd99cfdc521456b0742b736868cf90de099adb8d5ffd1deff39ba4007ab746cefdb22d7df0e225f54627dc65466131721b90af445363a8358b9f607642f78fab0ab0f43b7168d64bae70d8827848d8ef1e421c5754ddf42c2589b5b3");
+
+		// PSS Example 2.2
+
+		private byte[] msg2b = Hex.Decode("e4f8601a8a6da1be34447c0959c058570c3668cfd51dd5f9ccd6ad4411fe8213486d78a6c49f93efc2ca2288cebc2b9b60bd04b1e220d86e3d4848d709d032d1e8c6a070c6af9a499fcf95354b14ba6127c739de1bb0fd16431e46938aec0cf8ad9eb72e832a7035de9b7807bdc0ed8b68eb0f5ac2216be40ce920c0db0eddd3860ed788efaccaca502d8f2bd6d1a7c1f41ff46f1681c8f1f818e9c4f6d91a0c7803ccc63d76a6544d843e084e363b8acc55aa531733edb5dee5b5196e9f03e8b731b3776428d9e457fe3fbcb3db7274442d785890e9cb0854b6444dace791d7273de1889719338a77fe");
+		private byte[] slt2b = Hex.Decode("7f6dd359e604e60870e898e47b19bf2e5a7b2a90");
+		private byte[] sig2b = Hex.Decode("010991656cca182b7f29d2dbc007e7ae0fec158eb6759cb9c45c5ff87c7635dd46d150882f4de1e9ae65e7f7d9018f6836954a47c0a81a8a6b6f83f2944d6081b1aa7c759b254b2c34b691da67cc0226e20b2f18b42212761dcd4b908a62b371b5918c5742af4b537e296917674fb914194761621cc19a41f6fb953fbcbb649dea");
+
+		//
+		//  Example 4: A 1027-bit RSA key pair
+		//
+
+		private RsaKeyParameters pub4 = new RsaKeyParameters(false,
+			new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16),
+			new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv4 = new RsaPrivateCrtKeyParameters(
+			new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16),
+			new BigInteger("010001", 16),
+			new BigInteger("fa041f8cd9697ceed38ec8caa275523b4dd72b09a301d3541d72f5d31c05cbce2d6983b36183af10690bd46c46131e35789431a556771dd0049b57461bf060c1f68472e8a67c25f357e5b6b4738fa541a730346b4a07649a2dfa806a69c975b6aba64678acc7f5913e89c622f2d8abb1e3e32554e39df94ba60c002e387d9011", 16),
+			new BigInteger("029232336d2838945dba9dd7723f4e624a05f7375b927a87abe6a893a1658fd49f47f6c7b0fa596c65fa68a23f0ab432962d18d4343bd6fd671a5ea8d148413995", 16),
+			new BigInteger("020ef5efe7c5394aed2272f7e81a74f4c02d145894cb1b3cab23a9a0710a2afc7e3329acbb743d01f680c4d02afb4c8fde7e20930811bb2b995788b5e872c20bb1", 16),
+			new BigInteger("026e7e28010ecf2412d9523ad704647fb4fe9b66b1a681581b0e15553a89b1542828898f27243ebab45ff5e1acb9d4df1b051fbc62824dbc6f6c93261a78b9a759", 16),
+			new BigInteger("012ddcc86ef655998c39ddae11718669e5e46cf1495b07e13b1014cd69b3af68304ad2a6b64321e78bf3bbca9bb494e91d451717e2d97564c6549465d0205cf421", 16),
+			new BigInteger("010600c4c21847459fe576703e2ebecae8a5094ee63f536bf4ac68d3c13e5e4f12ac5cc10ab6a2d05a199214d1824747d551909636b774c22cac0b837599abcc75", 16));
+
+		// PSS Example 4.1
+
+		private byte[] msg4a = Hex.Decode("9fb03b827c8217d9");
+
+		private byte[] slt4a = Hex.Decode("ed7c98c95f30974fbe4fbddcf0f28d6021c0e91d");
+
+		private byte[] sig4a = Hex.Decode("0323d5b7bf20ba4539289ae452ae4297080feff4518423ff4811a817837e7d82f1836cdfab54514ff0887bddeebf40bf99b047abc3ecfa6a37a3ef00f4a0c4a88aae0904b745c846c4107e8797723e8ac810d9e3d95dfa30ff4966f4d75d13768d20857f2b1406f264cfe75e27d7652f4b5ed3575f28a702f8c4ed9cf9b2d44948");
+
+		// PSS Example 4.2
+
+		private byte[] msg4b = Hex.Decode("0ca2ad77797ece86de5bf768750ddb5ed6a3116ad99bbd17edf7f782f0db1cd05b0f677468c5ea420dc116b10e80d110de2b0461ea14a38be68620392e7e893cb4ea9393fb886c20ff790642305bf302003892e54df9f667509dc53920df583f50a3dd61abb6fab75d600377e383e6aca6710eeea27156e06752c94ce25ae99fcbf8592dbe2d7e27453cb44de07100ebb1a2a19811a478adbeab270f94e8fe369d90b3ca612f9f");
+
+		private byte[] slt4b = Hex.Decode("22d71d54363a4217aa55113f059b3384e3e57e44");
+
+		private byte[] sig4b = Hex.Decode("049d0185845a264d28feb1e69edaec090609e8e46d93abb38371ce51f4aa65a599bdaaa81d24fba66a08a116cb644f3f1e653d95c89db8bbd5daac2709c8984000178410a7c6aa8667ddc38c741f710ec8665aa9052be929d4e3b16782c1662114c5414bb0353455c392fc28f3db59054b5f365c49e1d156f876ee10cb4fd70598");
+
+
+		//
+		// Example 8: A 1031-bit RSA key pair
+		//
+
+		private RsaKeyParameters pub8 = new RsaKeyParameters(false,
+			new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16),
+			new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv8 = new RsaPrivateCrtKeyParameters(
+			new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16),
+			new BigInteger("010001", 16),
+			new BigInteger("6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701c2d6266d517219ad0ec6d347dbe9", 16),
+			new BigInteger("08dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab72619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c8060645a1d29edb", 16),
+			new BigInteger("0847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca4174825b48f49706d", 16),
+			new BigInteger("05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fce69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee103deb771d105fd85", 16),
+			new BigInteger("04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b3669bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e30a7e7d241551e1b9", 16),
+			new BigInteger("07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef531b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7b06e45307dc91f3f", 16));
+
+		// PSS Example 8.1
+
+		private byte[] msg8a = Hex.Decode("81332f4be62948415ea1d899792eeacf6c6e1db1da8be13b5cea41db2fed467092e1ff398914c714259775f595f8547f735692a575e6923af78f22c6997ddb90fb6f72d7bb0dd5744a31decd3dc3685849836ed34aec596304ad11843c4f88489f209735f5fb7fdaf7cec8addc5818168f880acbf490d51005b7a8e84e43e54287977571dd99eea4b161eb2df1f5108f12a4142a83322edb05a75487a3435c9a78ce53ed93bc550857d7a9fb");
+
+		private byte[] slt8a = Hex.Decode("1d65491d79c864b373009be6f6f2467bac4c78fa");
+
+		private byte[] sig8a = Hex.Decode("0262ac254bfa77f3c1aca22c5179f8f040422b3c5bafd40a8f21cf0fa5a667ccd5993d42dbafb409c520e25fce2b1ee1e716577f1efa17f3da28052f40f0419b23106d7845aaf01125b698e7a4dfe92d3967bb00c4d0d35ba3552ab9a8b3eef07c7fecdbc5424ac4db1e20cb37d0b2744769940ea907e17fbbca673b20522380c5");
+
+		// PSS Example 8.2
+
+		private byte[] msg8b = Hex.Decode("e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3cede9d0faabf4fcc8e60a973e5595fd9ea08");
+
+		private byte[] slt8b = Hex.Decode("435c098aa9909eb2377f1248b091b68987ff1838");
+
+		private byte[] sig8b = Hex.Decode("2707b9ad5115c58c94e932e8ec0a280f56339e44a1b58d4ddcff2f312e5f34dcfe39e89c6a94dcee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6c86ee68396e8b3a14c9c8f34b178eb741f9d3f121109bf5c8172fada2e768f9ea1433032c004a8aa07eb990000a48dc94c8bac8aabe2b09b1aa46c0a2aa0e12f63fbba775ba7e");
+
+		//
+		// Example 9: A 1536-bit RSA key pair
+		//
+
+		private RsaKeyParameters pub9 = new RsaKeyParameters(false,
+			new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16),
+			new BigInteger("010001", 16));
+
+		private RsaKeyParameters prv9 = new RsaPrivateCrtKeyParameters(
+			new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16),
+			new BigInteger("010001", 16),
+			new BigInteger("6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d51410b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf21311666070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab328ce420689903c00c7b5fd31b75503a6d419684d629", 16),
+			new BigInteger("f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f6154a762aed165d47dee367", 16),
+			new BigInteger("ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e4728cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b489c176128092d629e49d3d", 16),
+			new BigInteger("2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0ab556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec993e9353e480d9eec6289f", 16),
+			new BigInteger("4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56ee4dba42c5fdb61aec2669", 16),
+			new BigInteger("77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124cbbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65757bb3f857a58dce52156", 16));
+
+		// PSS Example 9.1
+
+		private byte[] msg9a = Hex.Decode("a88e265855e9d7ca36c68795f0b31b591cd6587c71d060a0b3f7f3eaef43795922028bc2b6ad467cfc2d7f659c5385aa70ba3672cdde4cfe4970cc7904601b278872bf51321c4a972f3c95570f3445d4f57980e0f20df54846e6a52c668f1288c03f95006ea32f562d40d52af9feb32f0fa06db65b588a237b34e592d55cf979f903a642ef64d2ed542aa8c77dc1dd762f45a59303ed75e541ca271e2b60ca709e44fa0661131e8d5d4163fd8d398566ce26de8730e72f9cca737641c244159420637028df0a18079d6208ea8b4711a2c750f5");
+
+		private byte[] slt9a = Hex.Decode("c0a425313df8d7564bd2434d311523d5257eed80");
+
+		private byte[] sig9a = Hex.Decode("586107226c3ce013a7c8f04d1a6a2959bb4b8e205ba43a27b50f124111bc35ef589b039f5932187cb696d7d9a32c0c38300a5cdda4834b62d2eb240af33f79d13dfbf095bf599e0d9686948c1964747b67e89c9aba5cd85016236f566cc5802cb13ead51bc7ca6bef3b94dcbdbb1d570469771df0e00b1a8a06777472d2316279edae86474668d4e1efff95f1de61c6020da32ae92bbf16520fef3cf4d88f61121f24bbd9fe91b59caf1235b2a93ff81fc403addf4ebdea84934a9cdaf8e1a9e");
+
+		// PSS Example 9.2
+
+		private byte[] msg9b = Hex.Decode("c8c9c6af04acda414d227ef23e0820c3732c500dc87275e95b0d095413993c2658bc1d988581ba879c2d201f14cb88ced153a01969a7bf0a7be79c84c1486bc12b3fa6c59871b6827c8ce253ca5fefa8a8c690bf326e8e37cdb96d90a82ebab69f86350e1822e8bd536a2e");
+
+		private byte[] slt9b = Hex.Decode("b307c43b4850a8dac2f15f32e37839ef8c5c0e91");
+
+		private byte[] sig9b = Hex.Decode("80b6d643255209f0a456763897ac9ed259d459b49c2887e5882ecb4434cfd66dd7e1699375381e51cd7f554f2c271704b399d42b4be2540a0eca61951f55267f7c2878c122842dadb28b01bd5f8c025f7e228418a673c03d6bc0c736d0a29546bd67f786d9d692ccea778d71d98c2063b7a71092187a4d35af108111d83e83eae46c46aa34277e06044589903788f1d5e7cee25fb485e92949118814d6f2c3ee361489016f327fb5bc517eb50470bffa1afa5f4ce9aa0ce5b8ee19bf5501b958");
+
+
+		public override string Name
+		{
+			get { return "PSSTest"; }
+		}
+
+		private void doTestSig(
+			int					id,
+			RsaKeyParameters	pub,
+			RsaKeyParameters	prv,
+			byte[]				slt,
+			byte[]				msg,
+			byte[]				sig)
+		{
+			PssSigner eng = new PssSigner(new RsaEngine(), new Sha1Digest(), 20);
+
+			eng.Init(true, new ParametersWithRandom(prv, new FixedRandom(slt)));
+
+			eng.BlockUpdate(msg, 0, msg.Length);
+
+			byte[] s = eng.GenerateSignature();
+
+			if (!AreEqual(s, sig))
+			{
+				Fail("test " + id + " failed generation");
+			}
+
+			eng.Init(false, pub);
+
+			eng.BlockUpdate(msg, 0, msg.Length);
+
+			if (!eng.VerifySignature(s))
+			{
+				Fail("test " + id + " failed verification");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			doTestSig(1, pub1, prv1, slt1a, msg1a, sig1a);
+			doTestSig(2, pub1, prv1, slt1b, msg1b, sig1b);
+			doTestSig(3, pub2, prv2, slt2a, msg2a, sig2a);
+			doTestSig(4, pub2, prv2, slt2b, msg2b, sig2b);
+			doTestSig(5, pub4, prv4, slt4a, msg4a, sig4a);
+			doTestSig(6, pub4, prv4, slt4b, msg4b, sig4b);
+			doTestSig(7, pub8, prv8, slt8a, msg8a, sig8a);
+			doTestSig(8, pub8, prv8, slt8b, msg8b, sig8b);
+			doTestSig(9, pub9, prv9, slt9a, msg9a, sig9a);
+			doTestSig(10, pub9, prv9, slt9b, msg9b, sig9b);
+
+			//
+			// loop test - sha-1 only
+			//
+			PssSigner eng = new PssSigner(new RsaEngine(), new Sha1Digest(), 20);
+			int failed = 0;
+			byte[] data = new byte[DataLength];
+
+			SecureRandom random = new SecureRandom();
+			random.NextBytes(data);
+
+			for (int j = 0; j < NumTests; j++)
+			{
+				eng.Init(true, new ParametersWithRandom(prv8, random));
+
+				eng.BlockUpdate(data, 0, data.Length);
+
+				byte[] s = eng.GenerateSignature();
+
+				eng.Init(false, pub8);
+
+				eng.BlockUpdate(data, 0, data.Length);
+
+				if (!eng.VerifySignature(s))
+				{
+					failed++;
+				}
+			}
+
+			if (failed != 0)
+			{
+				Fail("loop test failed - failures: " + failed);
+			}
+
+			//
+			// loop test - sha-256 and sha-1
+			//
+			eng = new PssSigner(new RsaEngine(), new Sha256Digest(), new Sha1Digest(), 20);
+			failed = 0;
+			data = new byte[DataLength];
+
+			random.NextBytes(data);
+
+			for (int j = 0; j < NumTests; j++)
+			{
+				eng.Init(true, new ParametersWithRandom(prv8, random));
+
+				eng.BlockUpdate(data, 0, data.Length);
+
+				byte[] s = eng.GenerateSignature();
+
+				eng.Init(false, pub8);
+
+				eng.BlockUpdate(data, 0, data.Length);
+
+				if (!eng.VerifySignature(s))
+				{
+					failed++;
+				}
+			}
+
+			if (failed != 0)
+			{
+				Fail("loop test failed - failures: " + failed);
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PssTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/PaddingTest.cs b/crypto/test/src/crypto/test/PaddingTest.cs
new file mode 100644
index 000000000..6f41d754c
--- /dev/null
+++ b/crypto/test/src/crypto/test/PaddingTest.cs
@@ -0,0 +1,171 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* General Padding tests.
+	*/
+	[TestFixture]
+	public class PaddingTest : SimpleTest
+	{
+		public PaddingTest()
+		{
+		}
+
+		private void blockCheck(
+			PaddedBufferedBlockCipher   cipher,
+			IBlockCipherPadding          padding,
+			KeyParameter                key,
+			byte[]                      data)
+		{
+			byte[]  outBytes = new byte[data.Length + 8];
+			byte[]  dec = new byte[data.Length];
+
+			try
+			{
+				cipher.Init(true, key);
+
+				int    len = cipher.ProcessBytes(data, 0, data.Length, outBytes, 0);
+
+				len += cipher.DoFinal(outBytes, len);
+
+				cipher.Init(false, key);
+
+				int    decLen = cipher.ProcessBytes(outBytes, 0, len, dec, 0);
+
+				decLen += cipher.DoFinal(dec, decLen);
+
+				if (!AreEqual(data, dec))
+				{
+					Fail("failed to decrypt - i = " + data.Length + ", padding = " + padding.PaddingName);
+				}
+			}
+			catch (Exception e)
+			{
+				Fail("Exception - " + e.ToString(), e);
+			}
+		}
+
+		public void doTestPadding(
+			IBlockCipherPadding  padding,
+			SecureRandom        rand,
+			byte[]              ffVector,
+			byte[]              ZeroVector)
+		{
+			PaddedBufferedBlockCipher    cipher = new PaddedBufferedBlockCipher(new DesEngine(), padding);
+			KeyParameter                 key = new KeyParameter(Hex.Decode("0011223344556677"));
+
+			//
+			// ff test
+			//
+			byte[]    data = { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0 };
+
+			if (ffVector != null)
+			{
+				padding.AddPadding(data, 3);
+
+				if (!AreEqual(data, ffVector))
+				{
+					Fail("failed ff test for " + padding.PaddingName);
+				}
+			}
+
+			//
+			// zero test
+			//
+			if (ZeroVector != null)
+			{
+				data = new byte[8];
+				padding.AddPadding(data, 4);
+
+				if (!AreEqual(data, ZeroVector))
+				{
+					Fail("failed zero test for " + padding.PaddingName);
+				}
+			}
+
+			for (int i = 1; i != 200; i++)
+			{
+				data = new byte[i];
+
+				rand.NextBytes(data);
+
+				blockCheck(cipher, padding, key, data);
+			}
+		}
+
+		public override void PerformTest()
+		{
+			SecureRandom    rand = new SecureRandom(new byte[20]);
+
+			rand.SetSeed(DateTime.Now.Ticks);
+
+			doTestPadding(new Pkcs7Padding(), rand,
+				Hex.Decode("ffffff0505050505"),
+				Hex.Decode("0000000004040404"));
+
+			Pkcs7Padding padder = new Pkcs7Padding();
+			try
+			{
+				padder.PadCount(new byte[8]);
+
+				Fail("invalid padding not detected");
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (!"pad block corrupted".Equals(e.Message))
+				{
+					Fail("wrong exception for corrupt padding: " + e);
+				}
+			} 
+
+			doTestPadding(new ISO10126d2Padding(), rand,
+				null,
+				null);
+
+			doTestPadding(new X923Padding(), rand,
+				null,
+				null);
+
+			doTestPadding(new TbcPadding(), rand,
+				Hex.Decode("ffffff0000000000"),
+				Hex.Decode("00000000ffffffff"));
+
+			doTestPadding(new ZeroBytePadding(), rand,
+				Hex.Decode("ffffff0000000000"),
+				null);
+
+			doTestPadding(new ISO7816d4Padding(), rand,
+				Hex.Decode("ffffff8000000000"),
+				Hex.Decode("0000000080000000"));
+		}
+
+		public override string Name
+		{
+			get { return "PaddingTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PaddingTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/Pkcs12Test.cs b/crypto/test/src/crypto/test/Pkcs12Test.cs
new file mode 100644
index 000000000..29d5a3942
--- /dev/null
+++ b/crypto/test/src/crypto/test/Pkcs12Test.cs
@@ -0,0 +1,101 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <remarks> test for Pkcs12 key generation - vectors from
+	/// <a href="http://www.drh-consultancy.demon.co.uk/test.txt">
+	///	http://www.drh-consultancy.demon.co.uk/test.txt</a>
+	/// </remarks>
+	[TestFixture]
+	public class Pkcs12Test
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "Pkcs12Test"; }
+		}
+
+		internal char[] password1 = new char[]{'s', 'm', 'e', 'g'};
+		internal char[] password2 = new char[]{'q', 'u', 'e', 'e', 'g'};
+
+		private void Run1(int id, char[] password, byte[] salt, int iCount, byte[] result)
+		{
+			PbeParametersGenerator generator = new Pkcs12ParametersGenerator(new Sha1Digest());
+
+			generator.Init(PbeParametersGenerator.Pkcs12PasswordToBytes(password), salt, iCount);
+
+			ICipherParameters key = generator.GenerateDerivedParameters("DESEDE", 24 * 8);
+
+			if (!Arrays.AreEqual(result, ((KeyParameter) key).GetKey()))
+			{
+				Fail("id " + id + " Failed");
+			}
+		}
+
+		private void Run2(int id, char[] password, byte[] salt, int iCount, byte[] result)
+		{
+			PbeParametersGenerator generator = new Pkcs12ParametersGenerator(new Sha1Digest());
+
+			generator.Init(PbeParametersGenerator.Pkcs12PasswordToBytes(password), salt, iCount);
+
+			ParametersWithIV parameters = (ParametersWithIV)
+				generator.GenerateDerivedParameters("DES", 64, 64);
+
+			if (!Arrays.AreEqual(result, parameters.GetIV()))
+			{
+				Fail("id " + id + " Failed");
+			}
+		}
+
+		private void Run3(int id, char[] password, byte[] salt, int iCount, byte[] result)
+		{
+			PbeParametersGenerator generator = new Pkcs12ParametersGenerator(new Sha1Digest());
+
+			generator.Init(PbeParametersGenerator.Pkcs12PasswordToBytes(password), salt, iCount);
+
+			ICipherParameters key = generator.GenerateDerivedMacParameters(160);
+
+			if (!Arrays.AreEqual(result, ((KeyParameter) key).GetKey()))
+			{
+				Fail("id " + id + " Failed");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			Run1(1, password1, Hex.Decode("0A58CF64530D823F"), 1, Hex.Decode("8AAAE6297B6CB04642AB5B077851284EB7128F1A2A7FBCA3"));
+			Run2(2, password1, Hex.Decode("0A58CF64530D823F"), 1, Hex.Decode("79993DFE048D3B76"));
+			Run1(3, password1, Hex.Decode("642B99AB44FB4B1F"), 1, Hex.Decode("F3A95FEC48D7711E985CFE67908C5AB79FA3D7C5CAA5D966"));
+			Run2(4, password1, Hex.Decode("642B99AB44FB4B1F"), 1, Hex.Decode("C0A38D64A79BEA1D"));
+			Run3(5, password1, Hex.Decode("3D83C0E4546AC140"), 1, Hex.Decode("8D967D88F6CAA9D714800AB3D48051D63F73A312"));
+			Run1(6, password2, Hex.Decode("05DEC959ACFF72F7"), 1000, Hex.Decode("ED2034E36328830FF09DF1E1A07DD357185DAC0D4F9EB3D4"));
+			Run2(7, password2, Hex.Decode("05DEC959ACFF72F7"), 1000, Hex.Decode("11DEDAD7758D4860"));
+			Run1(8, password2, Hex.Decode("1682C0FC5B3F7EC5"), 1000, Hex.Decode("483DD6E919D7DE2E8E648BA8F862F3FBFBDC2BCB2C02957F"));
+			Run2(9, password2, Hex.Decode("1682C0FC5B3F7EC5"), 1000, Hex.Decode("9D461D1B00355C50"));
+			Run3(10, password2, Hex.Decode("263216FCC2FAB31C"), 1000, Hex.Decode("5EC4C7A80DF652294C3925B6489A7AB857C83476"));
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Pkcs12Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/Pkcs5Test.cs b/crypto/test/src/crypto/test/Pkcs5Test.cs
new file mode 100644
index 000000000..8066e8e41
--- /dev/null
+++ b/crypto/test/src/crypto/test/Pkcs5Test.cs
@@ -0,0 +1,243 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+    /// <summary> A test class for Pkcs5 PbeS2 with PBKDF2 (Pkcs5 v2.0) using
+    /// test vectors provider at
+    /// <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html">
+    /// RSA's Pkcs5 Page</a>
+    /// <br/>
+    /// The vectors are Base 64 encoded and encrypted using the password "password"
+    /// (without quotes). They should all yield the same PrivateKeyInfo object.
+    /// </summary>
+    [TestFixture]
+    public class Pkcs5Test
+        : SimpleTest
+    {
+        public override string Name
+        {
+            get { return "Pkcs5Test"; }
+        }
+
+        /// <summary> encrypted using des-cbc.</summary>
+        internal static byte[] sample1;
+
+        /// <summary> encrypted using des-ede3-cbc.</summary>
+        internal static byte[] sample2;
+
+        /// <summary> encrypted using rc2-cbc.</summary>
+        internal static byte[] sample3;
+
+        internal static byte[] result;
+
+        private class PbeTest
+            : SimpleTest
+        {
+            private Pkcs5Test enclosingInstance;
+
+            private void InitBlock(
+                Pkcs5Test enclosingInstance)
+            {
+                this.enclosingInstance = enclosingInstance;
+            }
+
+            public override string Name
+            {
+                get { return cipher.AlgorithmName + " Pkcs5S2 Test " + id; }
+            }
+
+            public Pkcs5Test Enclosing_Instance
+            {
+                get { return enclosingInstance; }
+            }
+
+            internal int id;
+            internal BufferedBlockCipher cipher;
+            internal byte[] sample;
+            internal int keySize;
+
+            internal PbeTest(
+                Pkcs5Test			enclosingInstance,
+                int					id,
+                BufferedBlockCipher	cipher,
+                byte[]				sample,
+                int					keySize)
+            {
+                InitBlock(enclosingInstance);
+
+                this.id = id;
+                this.cipher = cipher;
+                this.sample = sample;
+                this.keySize = keySize;
+            }
+
+            public override void PerformTest()
+            {
+                char[] password = "password".ToCharArray();
+                PbeParametersGenerator generator = new Pkcs5S2ParametersGenerator();
+
+                EncryptedPrivateKeyInfo info = null;
+                try
+                {
+                    info = EncryptedPrivateKeyInfo.GetInstance(Asn1Object.FromByteArray(sample));
+                }
+                catch (System.Exception e)
+                {
+                    Fail("failed construction - exception " + e.ToString(), e);
+                }
+
+                PbeS2Parameters alg = PbeS2Parameters.GetInstance(info.EncryptionAlgorithm.Parameters);
+                Pbkdf2Params func = Pbkdf2Params.GetInstance(alg.KeyDerivationFunc.Parameters);
+                EncryptionScheme scheme = alg.EncryptionScheme;
+
+                if (func.KeyLength != null)
+                {
+                    keySize = func.KeyLength.IntValue * 8;
+                }
+
+                int iterationCount = func.IterationCount.IntValue;
+                byte[] salt = func.GetSalt();
+
+                generator.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password), salt, iterationCount);
+
+                DerObjectIdentifier algOid = scheme.ObjectID;
+
+                byte[] iv;
+                if (algOid.Equals(PkcsObjectIdentifiers.RC2Cbc))
+                {
+                    RC2CbcParameter rc2Params = RC2CbcParameter.GetInstance(scheme.Asn1Object);
+                    iv = rc2Params.GetIV();
+                }
+                else
+                {
+                    iv = ((Asn1OctetString) scheme.Asn1Object).GetOctets();
+                }
+
+                ICipherParameters param = new ParametersWithIV(
+                    generator.GenerateDerivedParameters(algOid.Id, keySize), iv);
+
+                cipher.Init(false, param);
+
+                byte[] data = info.GetEncryptedData();
+                byte[] outBytes = new byte[cipher.GetOutputSize(data.Length)];
+                int len = cipher.ProcessBytes(data, 0, data.Length, outBytes, 0);
+
+                try
+                {
+                    len += cipher.DoFinal(outBytes, len);
+                }
+                catch (Exception e)
+                {
+                    Fail("failed DoFinal - exception " + e.ToString());
+                }
+
+                if (result.Length != len)
+                {
+                    Fail("failed length");
+                }
+
+                for (int i = 0; i != len; i++)
+                {
+                    if (outBytes[i] != result[i])
+                    {
+                        Fail("failed comparison");
+                    }
+                }
+            }
+        }
+
+        public override void PerformTest()
+        {
+            BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new DesEngine()));
+            SimpleTest test = new PbeTest(this, 0, cipher, sample1, 64);
+
+            test.PerformTest();
+
+            cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new DesEdeEngine()));
+            test = new PbeTest(this, 1, cipher, sample2, 192);
+
+            test.PerformTest();
+
+            cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new RC2Engine()));
+            test = new PbeTest(this, 2, cipher, sample3, 0);
+
+            test.PerformTest();
+
+            //
+            // RFC 3211 tests
+            //
+            char[] password = "password".ToCharArray();
+            PbeParametersGenerator generator = new Pkcs5S2ParametersGenerator();
+
+            byte[] salt = Hex.Decode("1234567878563412");
+
+            generator.Init(
+                PbeParametersGenerator.Pkcs5PasswordToBytes(password),
+                salt,
+                5);
+
+            if (!AreEqual(((KeyParameter)generator.GenerateDerivedParameters("DES", 64)).GetKey(),
+                Hex.Decode("d1daa78615f287e6")))
+            {
+                Fail("64 test failed");
+            }
+
+            password = "All n-entities must communicate with other n-entities via n-1 entiteeheehees".ToCharArray();
+
+            generator.Init(
+                PbeParametersGenerator.Pkcs5PasswordToBytes(password),
+                salt,
+                500);
+
+            if (!AreEqual(((KeyParameter)generator.GenerateDerivedParameters("DESEDE", 192)).GetKey(),
+                Hex.Decode("6a8970bf68c92caea84a8df28510858607126380cc47ab2d")))
+            {
+                Fail("192 test failed");
+            }
+
+            generator.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password), salt, 60000);
+            if (!AreEqual(((KeyParameter)generator.GenerateDerivedParameters("DESEDE", 192)).GetKey(),
+                Hex.Decode("29aaef810c12ecd2236bbcfb55407f9852b5573dc1c095bb")))
+            {
+                Fail("192 (60000) test failed");
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new Pkcs5Test());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        static Pkcs5Test()
+        {
+            sample1 = Base64.Decode("MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA" + "MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y" + "9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ" + "0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo" + "f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO" + "Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v" + "aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks" + "2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM" + "75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA");
+            sample2 = Base64.Decode("MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA" + "MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/" + "koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8" + "+MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5" + "6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi" + "5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ" + "BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8" + "z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr" + "u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB");
+            sample3 = Base64.Decode("MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA" + "AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop" + "7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f" + "wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21" + "RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6" + "VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1" + "MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz" + "tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH" + "2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO" + "6DA=");
+            result = Hex.Decode("30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100" + "debbfc2c09d61bada2a9462f24224e54cc6b3cc0755f15ce318ef57e79df17026b6a85cc" + "a12428027245045df2052a329a2f9ad3d17b78a10572ad9b22bf343b020301000102402d" + "90a96adcec472743527bc023153d8f0d6e96b40c8ed228276d467d843306429f8670559b" + "f376dd41857f6397c2fc8d95e0e53ed62de420b855430ee4a1b8a1022100ffcaf0838239" + "31e073ff534f06a5d415b3d414bc614a4544a3dff7ed271817eb022100deea30242117db" + "2d3b8837f58f1da530ff83cf9283680da33683ec4e583610f1022100e6026381adb0a683" + "f16a8f4c096b462979b9e4277cc89f3ed8a905b46fa9ff9f02210097c146d4d1d2b3dbaf" + "53a504ff51674c5c271800de84d003f4f10ac6ab36e38102202bfa141f10bda874e1017d" + "845e82767c1c38e82745daf421f0c8cd09d7652387");
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/Poly1305Test.cs b/crypto/test/src/crypto/test/Poly1305Test.cs
new file mode 100644
index 000000000..a1513165b
--- /dev/null
+++ b/crypto/test/src/crypto/test/Poly1305Test.cs
@@ -0,0 +1,395 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/*
+	 */
+	public class Poly1305Test
+		: SimpleTest
+	{
+		private const int MAXLEN = 1000;
+
+		private class KeyEngine
+			: IBlockCipher
+		{
+
+			private byte[] key;
+			private int blockSize;
+
+			public KeyEngine(int blockSize)
+			{
+				this.blockSize = blockSize;
+			}
+
+			public void Init(bool forEncryption, ICipherParameters parameters)
+			{
+				if (parameters is KeyParameter)
+				{
+					this.key = ((KeyParameter)parameters).GetKey();
+				}
+			}
+
+			public bool IsPartialBlockOkay 
+			{ 
+				get { return false; } 
+			}
+
+			public string AlgorithmName
+			{
+				get { return "Key"; }
+			}
+
+			public int GetBlockSize()
+			{
+				return blockSize;
+			}
+
+			public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
+			{
+				Array.Copy(key, 0, output, outOff, key.Length);
+				return key.Length;
+			}
+
+			public void Reset()
+			{
+			}
+
+		}
+
+		private class TestCase
+		{
+			internal byte[] key;
+			internal byte[] nonce;
+			internal byte[] message;
+			internal byte[] expectedMac;
+
+			public TestCase(string key, string nonce, string message, string expectedMac)
+			{
+				this.key = Hex.Decode(key);
+				// nacl test case keys are not pre-Clamped
+				Poly1305KeyGenerator.Clamp(this.key);
+				this.nonce = (nonce == null) ? null : Hex.Decode(nonce);
+				this.message = Hex.Decode(message);
+				this.expectedMac = Hex.Decode(expectedMac);
+			}
+		}
+
+		private static TestCase[] CASES = {
+			// Raw Poly1305
+			// onetimeauth.c from nacl-20110221
+			new TestCase("2539121d8e234e652d651fa4c8cff880eea6a7251c1e72916d11c2cb214d3c25", null,
+			             "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a"
+			             + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738"
+			             + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da"
+			             + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5",
+			             "f3ffc7703f9400e52a7dfb4b3d3305d9"),
+
+			// Poly1305-AES
+			// Loop 1 of test-poly1305aes from poly1305aes-20050218
+			new TestCase("0000000000000000000000000000000000000000000000000000000000000000",
+			             "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"),
+			new TestCase("f795bd4a52e29ed713d313fa20e98dbcf795bd0a50e29e0710d3130a20e98d0c",
+			             "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"),
+			new TestCase("e69dae0aab9f91c03a325dcc9436fa903ef49901c8e11c000430d90ad45e7603",
+			             "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"),
+			new TestCase("85a4ea91a7de0b0d96eed0d4bf6ecf1cda4afc035087d90e503f8f0ea08c3e0d",
+			             "0b6ef7a0b8f8c738b0f8d5995415271f",
+			             "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea",
+			             "3c5a13adb18d31c64cc29972030c917d"),
+			new TestCase(
+				"25eb69bac5cdf7d6bfcee4d9d5507b82ca3c6a0da0a864024ca3090628c28e0d",
+				"046772a4f0a8de92e4f0d628cdb04484",
+				"66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de",
+				"fc5fb58dc65daf19b14d1d05da1064e8"),
+
+			// Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that
+			// expose Java unsigned integer problems
+			new TestCase(
+				"95cc0e44d0b79a8856afcae1bec4fe3c" + "01bcb20bfc8b6e03609ddd09f44b060f",
+				null,
+				"66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de"
+				+ "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55"
+				+ "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930"
+				+ "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97"
+				+ "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b"
+				+ "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4"
+				+ "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee"
+				+ "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a"
+				+ "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd"
+				+ "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633"
+				+ "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13"
+				+ "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"),
+			new TestCase(
+				"76fb3635a2dc92a1f768163ab12f2187" + "cd07fd0ef8c0be0afcbdb30af4af0009",
+				null,
+				"f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab",
+				"045be28cc52009f506bdbfabedacf0b4"),
+
+		};
+
+		public override string Name
+		{
+			get { return "Poly1305"; }
+		}
+
+		public override void PerformTest()
+		{
+			testKeyGenerator();
+			testInit();
+			for (int i = 0; i < CASES.Length; i++)
+			{
+				testCase(i);
+			}
+			testSequential();
+			testReset();
+		}
+
+		private void testCase(int i)
+		{
+			byte[] output = new byte[16];
+			TestCase tc = CASES[i];
+
+			IMac mac;
+			if (tc.nonce == null)
+			{
+				// Raw Poly1305 test - don't do any transform on AES key part
+				mac = new Poly1305(new KeyEngine(16));
+				mac.Init(new ParametersWithIV(new KeyParameter(tc.key), new byte[16]));
+			}
+			else
+			{
+				mac = new Poly1305(new AesFastEngine());
+				mac.Init(new ParametersWithIV(new KeyParameter(tc.key), tc.nonce));
+			}
+			mac.BlockUpdate(tc.message, 0, tc.message.Length);
+			mac.DoFinal(output, 0);
+
+			if (!Arrays.AreEqual(output, tc.expectedMac))
+			{
+				Fail("Mismatched output " + i, Hex.ToHexString(tc.expectedMac), Hex.ToHexString(output));
+			}
+		}
+
+		private void testSequential()
+		{
+			// Sequential test, adapted from test-poly1305aes
+			int len;
+			byte[] kr = new byte[32];
+			byte[] m = new byte[MAXLEN];
+			byte[] n = new byte[16];
+			byte[] output = new byte[16];
+
+			int c = 0;
+			IMac mac = new Poly1305(new AesFastEngine());
+			for (int loop = 0; loop < 13; loop++)
+			{
+				len = 0;
+				for (;;)
+				{
+					c++;
+					mac.Init(new ParametersWithIV(new KeyParameter(kr), n));
+					mac.BlockUpdate(m, 0, len);
+					mac.DoFinal(output, 0);
+
+					// if (c == 678)
+					// {
+					// TestCase tc = CASES[0];
+					//
+					// if (!Arrays.AreEqual(tc.key, kr))
+					// {
+					// System.err.println("Key bad");
+					// System.err.println(Hex.ToHexString(tc.key)));
+					// System.err.println(Hex.ToHexString(kr)));
+					// System.exit(1);
+					// }
+					// if (!Arrays.AreEqual(tc.nonce, n))
+					// {
+					// System.err.println("Nonce bad");
+					// System.exit(1);
+					// }
+					// System.out.printf("[%d] m: %s\n", c, Hex.ToHexString(m, 0, len)));
+					// System.out.printf("[%d] K: %s\n", c, new string(Hex.encodje(kr)));
+					// System.out.printf("[%d] N: %s\n", c, Hex.ToHexString(n)));
+					// System.out.printf("[%d] M: ", c);
+					// }
+					// System.out.printf("%d/%s\n", c, Hex.ToHexString(out)));
+
+					if (len >= MAXLEN)
+						break;
+					n[0] = (byte)(n[0] ^ loop);
+					for (int i = 0; i < 16; ++i)
+						n[i] ^= output[i];
+					if (len % 2 != 0)
+						for (int i = 0; i < 16; ++i)
+							kr[i] ^= output[i];
+					if (len % 3 != 0)
+						for (int i = 0; i < 16; ++i)
+							kr[i + 16] ^= output[i];
+					Poly1305KeyGenerator.Clamp(kr);
+					m[len++] ^= output[0];
+				}
+			}
+			// Output after 13 loops as generated by poly1305 ref
+			if (c != 13013 || !Arrays.AreEqual(output, Hex.Decode("c96f60a23701a5b0fd2016f58cbe4f7e")))
+			{
+				Fail("Sequential Poly1305 " + c, "c96f60a23701a5b0fd2016f58cbe4f7e", Hex.ToHexString(output));
+			}
+		}
+
+		private void testReset()
+		{
+			CipherKeyGenerator gen = new Poly1305KeyGenerator();
+			gen.Init(new KeyGenerationParameters(new SecureRandom(), 256));
+			byte[] k = gen.GenerateKey();
+
+			byte[] m = new byte[10000];
+			byte[] check = new byte[16];
+			byte[] output = new byte[16];
+
+			// Generate baseline
+			IMac poly = new Poly1305(new AesFastEngine());
+			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
+
+			poly.BlockUpdate(m, 0, m.Length);
+			poly.DoFinal(check, 0);
+
+			// Check reset after doFinal
+			poly.BlockUpdate(m, 0, m.Length);
+			poly.DoFinal(output, 0);
+
+			if (!Arrays.AreEqual(check, output))
+			{
+				Fail("Mac not reset after doFinal");
+			}
+
+			// Check reset
+			poly.Update((byte)1);
+			poly.Update((byte)2);
+			poly.Reset();
+			poly.BlockUpdate(m, 0, m.Length);
+			poly.DoFinal(output, 0);
+
+			if (!Arrays.AreEqual(check, output))
+			{
+				Fail("Mac not reset after doFinal");
+			}
+
+			// Check init resets
+			poly.Update((byte)1);
+			poly.Update((byte)2);
+			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
+			poly.BlockUpdate(m, 0, m.Length);
+			poly.DoFinal(output, 0);
+
+			if (!Arrays.AreEqual(check, output))
+			{
+				Fail("Mac not reset after doFinal");
+			}
+		}
+
+		private void testInit()
+		{
+			CipherKeyGenerator gen = new Poly1305KeyGenerator();
+			gen.Init(new KeyGenerationParameters(new SecureRandom(), 256));
+			byte[] k = gen.GenerateKey();
+
+			IMac poly = new Poly1305(new AesFastEngine());
+			poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
+
+			try
+			{
+				poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[15]));
+				Fail("16 byte nonce required");
+			} catch (ArgumentException)
+			{
+				// Expected
+			}
+
+			try
+			{
+				byte[] k2 = new byte[k.Length - 1];
+				Array.Copy(k, 0, k2, 0, k2.Length);
+				poly.Init(new ParametersWithIV(new KeyParameter(k2), new byte[16]));
+				Fail("32 byte key required");
+			} catch (ArgumentException)
+			{
+				// Expected
+			}
+
+			try
+			{
+				k[19] = (byte)0xFF;
+				poly.Init(new ParametersWithIV(new KeyParameter(k), new byte[16]));
+				Fail("UnClamped key should not be accepted.");
+			} catch (ArgumentException)
+			{
+				// Expected
+			}
+
+		}
+
+		private void testKeyGenerator()
+		{
+			CipherKeyGenerator gen = new Poly1305KeyGenerator();
+			gen.Init(new KeyGenerationParameters(new SecureRandom(), 256));
+			byte[] k = gen.GenerateKey();
+
+			if (k.Length != 32)
+			{
+				Fail("Poly1305 key should be 256 bits.");
+			}
+
+			try
+			{
+				Poly1305KeyGenerator.CheckKey(k);
+			} catch (ArgumentException)
+			{
+				Fail("Poly1305 key should be Clamped on generation.");
+			}
+
+			byte[] k2 = new byte[k.Length];
+			Array.Copy(k, 0, k2, 0, k2.Length);
+			Poly1305KeyGenerator.Clamp(k);
+			if (!Arrays.AreEqual(k, k2))
+			{
+				Fail("Poly1305 key should be Clamped on generation.");
+			}
+
+			try
+			{
+				k2[19] = (byte)0xff;
+				Poly1305KeyGenerator.CheckKey(k2);
+				Fail("UnClamped key should fail check.");
+			} catch (ArgumentException)
+			{
+				// Expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Poly1305Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/RC2Test.cs b/crypto/test/src/crypto/test/RC2Test.cs
new file mode 100644
index 000000000..177c1817d
--- /dev/null
+++ b/crypto/test/src/crypto/test/RC2Test.cs
@@ -0,0 +1,58 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+    /// <summary> RC2 tester - vectors from  ftp://ftp.isi.edu/in-notes/rfc2268.txt
+    ///
+    /// RFC 2268 "A Description of the RC2(r) Encryption Algorithm"
+    /// </summary>
+
+    [TestFixture]
+    public class RC2Test:CipherTest
+    {
+        public override string Name
+        {
+			get { return "RC2"; }
+        }
+
+		internal static BlockCipherVectorTest[] tests = new BlockCipherVectorTest[]{
+            new BlockCipherVectorTest(0, new RC2Engine(), new RC2Parameters(Hex.Decode("0000000000000000"), 63), "0000000000000000", "ebb773f993278eff"),
+            new BlockCipherVectorTest(1, new RC2Engine(), new RC2Parameters(Hex.Decode("ffffffffffffffff"), 64), "ffffffffffffffff", "278b27e42e2f0d49"),
+            new BlockCipherVectorTest(2, new RC2Engine(), new RC2Parameters(Hex.Decode("3000000000000000"), 64), "1000000000000001", "30649edf9be7d2c2"),
+            new BlockCipherVectorTest(3, new RC2Engine(), new RC2Parameters(Hex.Decode("88"), 64), "0000000000000000", "61a8a244adacccf0"),
+            new BlockCipherVectorTest(4, new RC2Engine(), new RC2Parameters(Hex.Decode("88bca90e90875a"), 64), "0000000000000000", "6ccf4308974c267f"),
+            new BlockCipherVectorTest(5, new RC2Engine(), new RC2Parameters(Hex.Decode("88bca90e90875a7f0f79c384627bafb2"), 64), "0000000000000000", "1a807d272bbe5db1"),
+            new BlockCipherVectorTest(6, new RC2Engine(), new RC2Parameters(Hex.Decode("88bca90e90875a7f0f79c384627bafb2"), 128), "0000000000000000", "2269552ab0f85ca6"),
+            new BlockCipherVectorTest(7, new RC2Engine(), new RC2Parameters(Hex.Decode("88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e"), 129), "0000000000000000", "5b78d3a43dfff1f1")};
+
+		public RC2Test()
+			:base(tests, new RC2Engine(), new RC2Parameters(new byte[16]))
+        {
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            ITest test = new RC2Test();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RC2WrapTest.cs b/crypto/test/src/crypto/test/RC2WrapTest.cs
new file mode 100644
index 000000000..fc27acd2c
--- /dev/null
+++ b/crypto/test/src/crypto/test/RC2WrapTest.cs
@@ -0,0 +1,123 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* RC2 wrap tester
+	*/
+	[TestFixture]
+	public class RC2WrapTest
+		: ITest
+	{
+		private class RFCRandom
+			: SecureRandom
+		{
+			public override void NextBytes(
+				byte[] nextBytes)
+			{
+				Array.Copy(Hex.Decode("4845cce7fd1250"), 0, nextBytes, 0, nextBytes.Length);
+			}
+		}
+
+		private ITestResult wrapTest(
+			int     id,
+			ICipherParameters paramsWrap,
+			ICipherParameters paramsUnwrap,
+			byte[]  inBytes,
+			byte[]  outBytes)
+		{
+			IWrapper wrapper = new RC2WrapEngine();
+
+			wrapper.Init(true, paramsWrap);
+
+			try
+			{
+				byte[]  cText = wrapper.Wrap(inBytes, 0, inBytes.Length);
+				if (!Arrays.AreEqual(cText, outBytes))
+				{
+					return new SimpleTestResult(false, Name + ": failed wrap test " + id
+						+ " expected " + Hex.ToHexString(outBytes)
+						+ " got " + Hex.ToHexString(cText));
+				}
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed wrap test exception " + e, e);
+			}
+
+			wrapper.Init(false, paramsUnwrap);
+
+			try
+			{
+				byte[]  pText = wrapper.Unwrap(outBytes, 0, outBytes.Length);
+				if (!Arrays.AreEqual(pText, inBytes))
+				{
+					return new SimpleTestResult(false, Name + ": failed unwrap test " + id
+						+ " expected " + Hex.ToHexString(inBytes)
+						+ " got " + Hex.ToHexString(pText));
+				}
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": failed unwrap test exception " + e, e);
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public ITestResult Perform()
+		{
+			byte[]  kek1 = Hex.Decode("fd04fd08060707fb0003fefffd02fe05");
+			byte[]  iv1 = Hex.Decode("c7d90059b29e97f7");
+			byte[]  in1 = Hex.Decode("b70a25fbc9d86a86050ce0d711ead4d9");
+			byte[]  out1 = Hex.Decode("70e699fb5701f7833330fb71e87c85a420bdc99af05d22af5a0e48d35f3138986cbaafb4b28d4f35");
+			//
+			// note the RFC 3217 test specifies a key to be used with an effective key size of
+			// 40 bits which is why it is done here - in practice nothing less than 128 bits should be used.
+			//
+			ICipherParameters paramWrap = new ParametersWithRandom(new ParametersWithIV(new RC2Parameters(kek1, 40), iv1), new RFCRandom());
+			ICipherParameters paramUnwrap = new RC2Parameters(kek1, 40);
+
+			ITestResult result = wrapTest(1, paramWrap, paramUnwrap, in1, out1);
+
+			if (!result.IsSuccessful())
+			{
+				return result;
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public string Name
+		{
+			get { return "RC2Wrap"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new RC2WrapTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/RC4Test.cs b/crypto/test/src/crypto/test/RC4Test.cs
new file mode 100644
index 000000000..7c1ac9162
--- /dev/null
+++ b/crypto/test/src/crypto/test/RC4Test.cs
@@ -0,0 +1,59 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> RC4 Test</summary>
+    [TestFixture]
+    public class RC4Test
+		: ITest
+    {
+        public string Name
+        {
+			get { return "RC4"; }
+        }
+
+		internal StreamCipherVectorTest[] tests = new StreamCipherVectorTest[]{
+            new StreamCipherVectorTest(0, new RC4Engine(), new KeyParameter(Hex.Decode("0123456789ABCDEF")), "4e6f772069732074", "3afbb5c77938280d"),
+            new StreamCipherVectorTest(0, new RC4Engine(), new KeyParameter(Hex.Decode("0123456789ABCDEF")), "68652074696d6520", "1cf1e29379266d59"),
+            new StreamCipherVectorTest(0, new RC4Engine(), new KeyParameter(Hex.Decode("0123456789ABCDEF")), "666f7220616c6c20", "12fbb0c771276459")};
+
+        public virtual ITestResult Perform()
+        {
+            for (int i = 0; i != tests.Length; i++)
+            {
+                ITestResult res = tests[i].Perform();
+
+                if (!res.IsSuccessful())
+                {
+                    return res;
+                }
+            }
+
+			return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            ITest test = new RC4Test();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RC5Test.cs b/crypto/test/src/crypto/test/RC5Test.cs
new file mode 100644
index 000000000..e50878a0e
--- /dev/null
+++ b/crypto/test/src/crypto/test/RC5Test.cs
@@ -0,0 +1,201 @@
+using System;
+
+using NUnit.Framework;
+
+using System.Text;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+    /**
+    * RC5 tester - vectors from ftp://ftp.nordu.net/rfc/rfc2040.txt
+    *
+    * RFC 2040 "The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms"
+    */
+    [TestFixture]
+    public class RC5Test: ITest
+    {
+        BlockCipherVectorTest[] tests =
+        {
+            new BlockCipherVectorTest(0, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 0),
+                        Hex.Decode("0000000000000000")),
+                    "0000000000000000", "7a7bba4d79111d1e"),
+            new BlockCipherVectorTest(1, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 0),
+                        Hex.Decode("0000000000000000")),
+                    "ffffffffffffffff", "797bba4d78111d1e"),
+            new BlockCipherVectorTest(2, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 0),
+                        Hex.Decode("0000000000000001")),
+                    "0000000000000000", "7a7bba4d79111d1f"),
+            new BlockCipherVectorTest(3, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 0),
+                        Hex.Decode("0000000000000000")),
+                    "0000000000000001", "7a7bba4d79111d1f"),
+            new BlockCipherVectorTest(4, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 0),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "8b9ded91ce7794a6"),
+            new BlockCipherVectorTest(5, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("11"), 1),
+                        Hex.Decode("0000000000000000")),
+                    "0000000000000000", "2f759fe7ad86a378"),
+            new BlockCipherVectorTest(6, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 2),
+                        Hex.Decode("0000000000000000")),
+                    "0000000000000000", "dca2694bf40e0788"),
+            new BlockCipherVectorTest(7, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00000000"), 2),
+                        Hex.Decode("0000000000000000")),
+                    "0000000000000000", "dca2694bf40e0788"),
+            new BlockCipherVectorTest(8, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00000000"), 8),
+                        Hex.Decode("0000000000000000")),
+                    "0000000000000000", "dcfe098577eca5ff"),
+            new BlockCipherVectorTest(9, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 8),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "9646fb77638f9ca8"),
+            new BlockCipherVectorTest(10, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 12),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "b2b3209db6594da4"),
+            new BlockCipherVectorTest(11, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 16),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "545f7f32a5fc3836"),
+            new BlockCipherVectorTest(12, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("01020304"), 8),
+                        Hex.Decode("0000000000000000")),
+                    "ffffffffffffffff", "8285e7c1b5bc7402"),
+            new BlockCipherVectorTest(13, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("01020304"), 12),
+                        Hex.Decode("0000000000000000")),
+                    "ffffffffffffffff", "fc586f92f7080934"),
+            new BlockCipherVectorTest(14, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("01020304"), 16),
+                        Hex.Decode("0000000000000000")),
+                    "ffffffffffffffff", "cf270ef9717ff7c4"),
+            new BlockCipherVectorTest(15, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("0102030405060708"), 12),
+                        Hex.Decode("0000000000000000")),
+                    "ffffffffffffffff", "e493f1c1bb4d6e8c"),
+            new BlockCipherVectorTest(16, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("0102030405060708"), 8),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "5c4c041e0f217ac3"),
+            new BlockCipherVectorTest(17, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("0102030405060708"), 12),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "921f12485373b4f7"),
+            new BlockCipherVectorTest(18, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("0102030405060708"), 16),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "5ba0ca6bbe7f5fad"),
+            new BlockCipherVectorTest(19, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("01020304050607081020304050607080"), 8),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "c533771cd0110e63"),
+            new BlockCipherVectorTest(20, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("01020304050607081020304050607080"), 12),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "294ddb46b3278d60"),
+            new BlockCipherVectorTest(21, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("01020304050607081020304050607080"), 16),
+                        Hex.Decode("0102030405060708")),
+                    "1020304050607080", "dad6bda9dfe8f7e8"),
+            new BlockCipherVectorTest(22, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("0102030405"), 12),
+                        Hex.Decode("0000000000000000")),
+                    "ffffffffffffffff", "97e0787837ed317f"),
+            new BlockCipherVectorTest(23, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("0102030405"), 8),
+                        Hex.Decode("0000000000000000")),
+                    "ffffffffffffffff", "7875dbf6738c6478"),
+            new BlockCipherVectorTest(23, new CbcBlockCipher(new RC532Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("0102030405"), 8),
+                        Hex.Decode("7875dbf6738c6478")),
+                    "0808080808080808", "8f34c3c681c99695"),
+            new BlockCipherVectorTest(640, new CbcBlockCipher(new RC564Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 0),
+                        Hex.Decode("00000000000000000000000000000000")),
+                    "00000000000000000000000000000000", "9f09b98d3f6062d9d4d59973d00e0e63"),
+            new BlockCipherVectorTest(641, new CbcBlockCipher(new RC564Engine()),
+                    new ParametersWithIV(
+                        new RC5Parameters(Hex.Decode("00"), 0),
+                        Hex.Decode("00000000000000000000000000000000")),
+                    "ffffffffffffffffffffffffffffffff", "9e09b98d3f6062d9d3d59973d00e0e63")
+        };
+
+		public string Name
+        {
+			get { return "RC5"; }
+        }
+
+		public ITestResult Perform()
+        {
+            for (int i = 0; i != tests.Length; i++)
+            {
+                ITestResult  res = tests[i].Perform();
+
+                if (!res.IsSuccessful())
+                {
+                    return res;
+                }
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RC5Test test = new RC5Test();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RC6Test.cs b/crypto/test/src/crypto/test/RC6Test.cs
new file mode 100644
index 000000000..4f59ec4e9
--- /dev/null
+++ b/crypto/test/src/crypto/test/RC6Test.cs
@@ -0,0 +1,54 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <remarks> RC6 Test - test vectors from AES Submitted RSA Reference implementation.
+    /// ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/aes/rc6-unix-refc.tar
+    /// </remarks>
+	[TestFixture]
+    public class RC6Test
+		: CipherTest
+    {
+        public override string Name
+        {
+			get { return "RC6"; }
+        }
+
+		internal static SimpleTest[] tests = new SimpleTest[]{
+            new BlockCipherVectorTest(0, new RC6Engine(), new KeyParameter(Hex.Decode("00000000000000000000000000000000")), "80000000000000000000000000000000", "f71f65e7b80c0c6966fee607984b5cdf"),
+            new BlockCipherVectorTest(1, new RC6Engine(), new KeyParameter(Hex.Decode("000000000000000000000000000000008000000000000000")), "00000000000000000000000000000000", "dd04c176440bbc6686c90aee775bd368"),
+            new BlockCipherVectorTest(2, new RC6Engine(), new KeyParameter(Hex.Decode("000000000000000000000000000000000000001000000000")), "00000000000000000000000000000000", "937fe02d20fcb72f0f57201012b88ba4"),
+            new BlockCipherVectorTest(3, new RC6Engine(), new KeyParameter(Hex.Decode("00000001000000000000000000000000")), "00000000000000000000000000000000", "8a380594d7396453771a1dfbe2914c8e"),
+            new BlockCipherVectorTest(4, new RC6Engine(), new KeyParameter(Hex.Decode("1000000000000000000000000000000000000000000000000000000000000000")), "00000000000000000000000000000000", "11395d4bfe4c8258979ee2bf2d24dff4"),
+            new BlockCipherVectorTest(5, new RC6Engine(), new KeyParameter(Hex.Decode("0000000000000000000000000000000000080000000000000000000000000000")), "00000000000000000000000000000000", "3d6f7e99f6512553bb983e8f75672b97")};
+
+        public RC6Test()
+			: base(tests, new RC6Engine(), new KeyParameter(new byte[32]))
+        {
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new RC6Test();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RFC3211WrapTest.cs b/crypto/test/src/crypto/test/RFC3211WrapTest.cs
new file mode 100644
index 000000000..bdef7c999
--- /dev/null
+++ b/crypto/test/src/crypto/test/RFC3211WrapTest.cs
@@ -0,0 +1,216 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* Wrap Test based on RFC3211 test vectors
+	*/
+	[TestFixture]
+	public class Rfc3211WrapTest
+		: SimpleTest
+	{
+		// Note: These test data assume the Rfc3211WrapEngine will call SecureRandom.NextBytes
+
+		SecureRandom r1 = FixedSecureRandom.From(
+			new byte[]{ 0xC4, 0x36, 0xF5, 0x41 });
+
+		SecureRandom r2 = FixedSecureRandom.From(
+			new byte[]{ 0xFA, 0x06, 0x0A, 0x45 });
+
+		public override string Name
+		{
+			get { return "RFC3211Wrap"; }
+		}
+
+		private void doWrapTest(
+			int				id,
+			IBlockCipher	engine,
+			byte[]			kek,
+			byte[]			iv,
+			SecureRandom	rand,
+			byte[]			inBytes,
+			byte[]			outBytes)
+		{
+			IWrapper wrapper = new Rfc3211WrapEngine(engine);
+
+			wrapper.Init(true, new ParametersWithRandom(
+				new ParametersWithIV(new KeyParameter(kek), iv), rand));
+
+			byte[] cText = wrapper.Wrap(inBytes, 0, inBytes.Length);
+			if (!AreEqual(cText, outBytes))
+			{
+				Fail("failed Wrap test " + id  + " expected "
+					+ Hex.ToHexString(outBytes) + " got " + Hex.ToHexString(cText));
+			}
+
+			wrapper.Init(false, new ParametersWithIV(new KeyParameter(kek), iv));
+
+			byte[] pText = wrapper.Unwrap(outBytes, 0, outBytes.Length);
+			if (!AreEqual(pText, inBytes))
+			{
+				Fail("rfailed Unwrap test " + id  + " expected "
+					+ Hex.ToHexString(inBytes) + " got " + Hex.ToHexString(pText));
+			}
+		}
+
+		private void doTestCorruption()
+		{
+			byte[] kek = Hex.Decode("D1DAA78615F287E6");
+			byte[] iv = Hex.Decode("EFE598EF21B33D6D");
+
+			IWrapper wrapper = new Rfc3211WrapEngine(new DesEngine());
+
+			wrapper.Init(false, new ParametersWithIV(new KeyParameter(kek), iv));
+
+			byte[] block = Hex.Decode("ff739D838C627C897323A2F8C436F541");
+			encryptBlock(kek, iv, block);
+
+			try
+			{
+				wrapper.Unwrap(block, 0, block.Length);
+
+				Fail("bad length not detected");
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (!e.Message.Equals("wrapped key corrupted"))
+				{
+					Fail("wrong exception on length");
+				}
+			}
+
+			block = Hex.Decode("08639D838C627C897323A2F8C436F541");
+			doTestChecksum(kek, iv, block, wrapper);
+
+			block = Hex.Decode("08736D838C627C897323A2F8C436F541");
+			doTestChecksum(kek, iv, block, wrapper);
+	        
+			block = Hex.Decode("08739D638C627C897323A2F8C436F541");
+			doTestChecksum(kek, iv, block, wrapper);
+		}
+
+		private void doTestChecksum(
+			byte[]		kek,
+			byte[]		iv,
+			byte[]		block,
+			IWrapper	wrapper)
+		{
+			encryptBlock(kek, iv, block);
+
+			try
+			{
+				wrapper.Unwrap(block, 0, block.Length);
+
+				Fail("bad checksum not detected");
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (!e.Message.Equals("wrapped key fails checksum"))
+				{
+					Fail("wrong exception");
+				}
+			}
+		}
+
+		private void encryptBlock(byte[] key, byte[] iv, byte[] cekBlock)
+		{
+			IBlockCipher engine = new CbcBlockCipher(new DesEngine());
+
+			engine.Init(true, new ParametersWithIV(new KeyParameter(key), iv));
+
+			for (int i = 0; i < cekBlock.Length; i += 8)
+			{
+				engine.ProcessBlock(cekBlock, i, cekBlock, i);
+			}
+
+			for (int i = 0; i < cekBlock.Length; i += 8)
+			{
+				engine.ProcessBlock(cekBlock, i, cekBlock, i);
+			}
+		}
+
+		public override void PerformTest()
+		{
+			doWrapTest(1, new DesEngine(), Hex.Decode("D1DAA78615F287E6"), Hex.Decode("EFE598EF21B33D6D"), r1, Hex.Decode("8C627C897323A2F8"), Hex.Decode("B81B2565EE373CA6DEDCA26A178B0C10"));
+			doWrapTest(2, new DesEdeEngine(), Hex.Decode("6A8970BF68C92CAEA84A8DF28510858607126380CC47AB2D"), Hex.Decode("BAF1CA7931213C4E"), r2,
+				Hex.Decode("8C637D887223A2F965B566EB014B0FA5D52300A3F7EA40FFFC577203C71BAF3B"),
+				Hex.Decode("C03C514ABDB9E2C5AAC038572B5E24553876B377AAFB82ECA5A9D73F8AB143D9EC74E6CAD7DB260C"));
+
+			doTestCorruption();
+	        
+			IWrapper wrapper = new Rfc3211WrapEngine(new DesEngine());
+			ParametersWithIV parameters = new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]);
+			byte[] buf = new byte[16];
+
+			try
+			{
+				wrapper.Init(true, parameters);
+
+				wrapper.Unwrap(buf, 0, buf.Length);
+
+				Fail("failed Unwrap state test.");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+			catch (InvalidCipherTextException e)
+			{
+				Fail("unexpected exception: " + e, e);
+			}
+
+			try
+			{
+				wrapper.Init(false, parameters);
+
+				wrapper.Wrap(buf, 0, buf.Length);
+
+				Fail("failed Unwrap state test.");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+
+			//
+			// short test
+			//
+			try
+			{
+				wrapper.Init(false, parameters);
+
+				wrapper.Unwrap(buf, 0, buf.Length / 2);
+
+				Fail("failed Unwrap short test.");
+			}
+			catch (InvalidCipherTextException)
+			{
+				// expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Rfc3211WrapTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/RSABlindedTest.cs b/crypto/test/src/crypto/test/RSABlindedTest.cs
new file mode 100644
index 000000000..80d6e8e49
--- /dev/null
+++ b/crypto/test/src/crypto/test/RSABlindedTest.cs
@@ -0,0 +1,449 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class RsaBlindedTest
+		: SimpleTest
+	{
+		static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16);
+		static BigInteger  pubExp = new BigInteger("11", 16);
+		static BigInteger  privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16);
+		static BigInteger  p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16);
+		static BigInteger  q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16);
+		static BigInteger  pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16);
+		static BigInteger  qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16);
+		static BigInteger  crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16);
+
+		static string input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
+
+		//
+		// to check that we handling byte extension by big number correctly.
+		//
+		static string edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
+
+		static byte[] oversizedSig = Hex.Decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] dudBlock = Hex.Decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] truncatedDataBlock = Hex.Decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] incorrectPadding = Hex.Decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] missingDataBlock = Hex.Decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+
+		public override string Name
+		{
+			get { return "RSABlinded"; }
+		}
+
+		private void doTestStrictPkcs1Length(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			IAsymmetricBlockCipher eng = new RsaBlindedEngine();
+
+			eng.Init(true, privParameters);
+
+			byte[] data = null;
+
+			try
+			{
+				data = eng.ProcessBlock(oversizedSig, 0, oversizedSig.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("RSA: failed - exception " + e.ToString(), e);
+			}
+
+			eng = new Pkcs1Encoding(eng);
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+
+				Fail("oversized signature block not recognised");
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (!e.Message.Equals("block incorrect size"))
+				{
+					Fail("RSA: failed - exception " + e.ToString(), e);
+				}
+			}
+
+
+			// Create the encoding with StrictLengthEnabled=false (done thru environment in Java version)
+			Pkcs1Encoding.StrictLengthEnabled = false;
+
+			eng = new Pkcs1Encoding(new RsaBlindedEngine());
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (InvalidCipherTextException e)
+			{
+				Fail("RSA: failed - exception " + e.ToString(), e);
+			}
+
+			Pkcs1Encoding.StrictLengthEnabled = true;
+		}
+
+		private void doTestTruncatedPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated");
+		}
+
+		private void doTestDudPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, dudBlock, "unknown block type");
+		}
+
+		private void doTestWrongPaddingPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect");
+		}
+
+		private void doTestMissingDataPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, missingDataBlock, "no data in block");
+		}
+
+		private void checkForPkcs1Exception(RsaKeyParameters pubParameters, RsaKeyParameters privParameters, byte[] inputData, string expectedMessage)
+		{
+			IAsymmetricBlockCipher eng = new RsaBlindedEngine();
+
+			eng.Init(true, privParameters);
+
+			byte[] data = null;
+
+			try
+			{
+				data = eng.ProcessBlock(inputData, 0, inputData.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("RSA: failed - exception " + e.ToString(), e);
+			}
+
+			eng = new Pkcs1Encoding(eng);
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+
+				Fail("missing data block not recognised");
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (!e.Message.Equals(expectedMessage))
+				{
+					Fail("RSA: failed - exception " + e.ToString(), e);
+				}
+			}
+		}
+
+		private void doTestOaep(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			//
+			// OAEP - public encrypt, private decrypt
+			//
+			IAsymmetricBlockCipher eng = new OaepEncoding(new RsaBlindedEngine());
+			byte[] data = Hex.Decode(input);
+
+			eng.Init(true, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed OAEP Test");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod, pubExp);
+			RsaKeyParameters privParameters = new RsaPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
+			byte[] data = Hex.Decode(edgeInput);
+
+			//
+			// RAW
+			//
+			IAsymmetricBlockCipher eng = new RsaBlindedEngine();
+
+			eng.Init(true, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("RSA: failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!edgeInput.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed RAW edge Test");
+			}
+
+			data = Hex.Decode(input);
+
+			eng.Init(true, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed RAW Test");
+			}
+
+			//
+			// PKCS1 - public encrypt, private decrypt
+			//
+			eng = new Pkcs1Encoding(eng);
+
+			eng.Init(true, pubParameters);
+
+			if (eng.GetOutputBlockSize() != ((Pkcs1Encoding)eng).GetUnderlyingCipher().GetOutputBlockSize())
+			{
+				Fail("PKCS1 output block size incorrect");
+			}
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed PKCS1 public/private Test");
+			}
+
+			//
+			// PKCS1 - private encrypt, public decrypt
+			//
+			eng = new Pkcs1Encoding(((Pkcs1Encoding)eng).GetUnderlyingCipher());
+
+			eng.Init(true, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed PKCS1 private/public Test");
+			}
+
+			//
+			// key generation test
+			//
+			RsaKeyPairGenerator pGen = new RsaKeyPairGenerator();
+			RsaKeyGenerationParameters genParam = new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x11), new SecureRandom(), 768, 25);
+
+			pGen.Init(genParam);
+
+			AsymmetricCipherKeyPair pair = pGen.GenerateKeyPair();
+
+			eng = new RsaBlindedEngine();
+
+			if (((RsaKeyParameters)pair.Public).Modulus.BitLength < 768)
+			{
+				Fail("failed key generation (768) length test");
+			}
+
+			eng.Init(true, pair.Public);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, pair.Private);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed key generation (768) Test");
+			}
+
+			genParam = new RsaKeyGenerationParameters(BigInteger.ValueOf(0x11), new SecureRandom(), 1024, 25);
+
+			pGen.Init(genParam);
+			pair = pGen.GenerateKeyPair();
+
+			eng.Init(true, pair.Public);
+
+			if (((RsaKeyParameters)pair.Public).Modulus.BitLength < 1024)
+			{
+				Fail("failed key generation (1024) length test");
+			}
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, pair.Private);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed key generation (1024) test");
+			}
+
+			doTestOaep(pubParameters, privParameters);
+			doTestStrictPkcs1Length(pubParameters, privParameters);
+			doTestDudPkcs1Block(pubParameters, privParameters);
+			doTestMissingDataPkcs1Block(pubParameters, privParameters);
+			doTestTruncatedPkcs1Block(pubParameters, privParameters);
+			doTestWrongPaddingPkcs1Block(pubParameters, privParameters);
+
+			try
+			{
+				new RsaBlindedEngine().ProcessBlock(new byte[]{ 1 }, 0, 1);
+				Fail("failed initialisation check");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new RsaBlindedTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs
new file mode 100644
index 000000000..27d6bb0e9
--- /dev/null
+++ b/crypto/test/src/crypto/test/RegressionTest.cs
@@ -0,0 +1,135 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    public class RegressionTest
+    {
+        public static ITest[] tests = new ITest[]
+        {
+            new AesTest(),
+            new AesLightTest(),
+            new AesFastTest(),
+            new AesWrapTest(),
+            new DesTest(),
+            new DesEdeTest(),
+            new ModeTest(),
+            new PaddingTest(),
+            new DHTest(),
+            new ElGamalTest(),
+            new DsaTest(),
+            new ECTest(),
+            new DeterministicDsaTest(),
+            new Gost3410Test(),
+            new ECGost3410Test(),
+            new EcIesTest(),
+            new EcNrTest(),
+            new MacTest(),
+            new Gost28147MacTest(),
+            new RC2Test(),
+            new RC2WrapTest(),
+            new RC4Test(),
+            new RC5Test(),
+            new RC6Test(),
+            new RijndaelTest(),
+            new SerpentTest(),
+            new CamelliaTest(),
+            new CamelliaLightTest(),
+            new DigestRandomNumberTest(),
+            new SkipjackTest(),
+            new BlowfishTest(),
+            new TwofishTest(),
+            new Threefish256Test(),
+            new Threefish512Test(),
+            new Threefish1024Test(),
+            new SkeinDigestTest(),
+            new SkeinMacTest(),
+            new Cast5Test(),
+            new Cast6Test(),
+            new Gost28147Test(),
+            new IdeaTest(),
+            new RsaBlindedTest(),
+            new RsaTest(),
+            new ISO9796Test(),
+            new ISO9797Alg3MacTest(),
+            new MD2DigestTest(),
+            new MD4DigestTest(),
+            new MD5DigestTest(),
+            new PssBlindTest(),
+            new Sha1DigestTest(),
+            new Sha224DigestTest(),
+            new Sha256DigestTest(),
+            new Sha384DigestTest(),
+            new Sha512DigestTest(),
+            new Sha512t224DigestTest(),
+            new Sha512t256DigestTest(),
+            new Sha3DigestTest(),
+            new RipeMD128DigestTest(),
+            new RipeMD160DigestTest(),
+            new RipeMD256DigestTest(),
+            new RipeMD320DigestTest(),
+            new TigerDigestTest(),
+            new Gost3411DigestTest(),
+            new WhirlpoolDigestTest(),
+            new MD5HMacTest(),
+            new Sha1HMacTest(),
+            new Sha224HMacTest(),
+            new Sha256HMacTest(),
+            new Sha384HMacTest(),
+            new Sha512HMacTest(),
+            new RipeMD128HMacTest(),
+            new RipeMD160HMacTest(),
+            new OaepTest(),
+            new PssTest(),
+            new CTSTest(),
+            new CcmTest(),
+            new Pkcs5Test(),
+            new Pkcs12Test(),
+            new Kdf1GeneratorTest(),
+            new Kdf2GeneratorTest(),
+            new Mgf1GeneratorTest(),
+            new DHKekGeneratorTest(),
+            new ECDHKekGeneratorTest(),
+            new ShortenedDigestTest(),
+            new EqualsHashCodeTest(),
+            new TeaTest(),
+            new XteaTest(),
+            new Rfc3211WrapTest(),
+            new SeedTest(),
+            new NaccacheSternTest(),
+            new Salsa20Test(),
+            new XSalsa20Test(),
+            new ChaChaTest(),
+            new CMacTest(),
+            new EaxTest(),
+            new GcmTest(),
+            new GMacTest(),
+            new HCFamilyTest(),
+            new HCFamilyVecTest(),
+            new IsaacTest(),
+            new NoekeonTest(),
+            new VmpcKsa3Test(),
+            new VmpcMacTest(),
+            new VmpcTest(),
+            new Srp6Test(),
+            new SCryptTest(),
+            new NullTest(),
+            new SipHashTest(),
+            new Poly1305Test(),
+            new OcbTest(),
+            new SM3DigestTest()
+        };
+
+        public static void Main(
+            string[] args)
+        {
+            for (int i = 0; i != tests.Length; i++)
+            {
+                ITestResult result = tests[i].Perform();
+
+                Console.WriteLine(result);
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RijndaelTest.cs b/crypto/test/src/crypto/test/RijndaelTest.cs
new file mode 100644
index 000000000..f714c83eb
--- /dev/null
+++ b/crypto/test/src/crypto/test/RijndaelTest.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+    * Test vectors from the NIST standard tests and Brian Gladman's vector set
+    * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">
+    * http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+    */
+    [TestFixture]
+    public class RijndaelTest
+		: CipherTest
+    {
+        static SimpleTest[] tests =
+        {
+            new BlockCipherVectorTest(0, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+                    "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"),
+            new BlockCipherVectorTest(1, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("00000000000000000000000000000080")),
+                    "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"),
+            new BlockCipherMonteCarloTest(2, 10000, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+                    "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"),
+            new BlockCipherMonteCarloTest(3, 10000, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("5F060D3716B345C253F6749ABAC10917")),
+                    "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"),
+            new BlockCipherVectorTest(4, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+                    "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"),
+            new BlockCipherMonteCarloTest(5, 10000, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")),
+                    "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"),
+            new BlockCipherVectorTest(6, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+                    "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"),
+            new BlockCipherMonteCarloTest(7, 10000, new RijndaelEngine(128),
+                    new KeyParameter(Hex.Decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")),
+                    "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"),
+            new BlockCipherVectorTest(8, new RijndaelEngine(160),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c")),
+                    "3243f6a8885a308d313198a2e03707344a409382", "16e73aec921314c29df905432bc8968ab64b1f51"),
+            new BlockCipherVectorTest(8, new RijndaelEngine(160),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")),
+                    "3243f6a8885a308d313198a2e03707344a409382", "0553eb691670dd8a5a5b5addf1aa7450f7a0e587"),
+            new BlockCipherVectorTest(8, new RijndaelEngine(160),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")),
+                    "3243f6a8885a308d313198a2e03707344a409382", "73cd6f3423036790463aa9e19cfcde894ea16623"),
+            new BlockCipherVectorTest(8, new RijndaelEngine(160),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")),
+                    "3243f6a8885a308d313198a2e03707344a409382", "601b5dcd1cf4ece954c740445340bf0afdc048df"),
+            new BlockCipherVectorTest(8, new RijndaelEngine(160),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")),
+                    "3243f6a8885a308d313198a2e03707344a409382", "579e930b36c1529aa3e86628bacfe146942882cf"),
+            new BlockCipherVectorTest(8, new RijndaelEngine(192),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d", "b24d275489e82bb8f7375e0d5fcdb1f481757c538b65148a"),
+            new BlockCipherVectorTest(9, new RijndaelEngine(192),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d", "725ae43b5f3161de806a7c93e0bca93c967ec1ae1b71e1cf"),
+            new BlockCipherVectorTest(10, new RijndaelEngine(192),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d", "bbfc14180afbf6a36382a061843f0b63e769acdc98769130"),
+            new BlockCipherVectorTest(11, new RijndaelEngine(192),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d", "0ebacf199e3315c2e34b24fcc7c46ef4388aa475d66c194c"),
+            new BlockCipherVectorTest(12, new RijndaelEngine(224),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "b0a8f78f6b3c66213f792ffd2a61631f79331407a5e5c8d3793aceb1"),
+            new BlockCipherVectorTest(13, new RijndaelEngine(224),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "08b99944edfce33a2acb131183ab0168446b2d15e958480010f545e3"),
+            new BlockCipherVectorTest(14, new RijndaelEngine(224),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "be4c597d8f7efe22a2f7e5b1938e2564d452a5bfe72399c7af1101e2"),
+            new BlockCipherVectorTest(15, new RijndaelEngine(224),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "ef529598ecbce297811b49bbed2c33bbe1241d6e1a833dbe119569e8"),
+            new BlockCipherVectorTest(16, new RijndaelEngine(224),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "02fafc200176ed05deb8edb82a3555b0b10d47a388dfd59cab2f6c11"),
+            new BlockCipherVectorTest(17, new RijndaelEngine(256),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "7d15479076b69a46ffb3b3beae97ad8313f622f67fedb487de9f06b9ed9c8f19"),
+            new BlockCipherVectorTest(18, new RijndaelEngine(256),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "514f93fb296b5ad16aa7df8b577abcbd484decacccc7fb1f18dc567309ceeffd"),
+            new BlockCipherVectorTest(19, new RijndaelEngine(256),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "5d7101727bb25781bf6715b0e6955282b9610e23a43c2eb062699f0ebf5887b2"),
+            new BlockCipherVectorTest(20, new RijndaelEngine(256),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "d56c5a63627432579e1dd308b2c8f157b40a4bfb56fea1377b25d3ed3d6dbf80"),
+            new BlockCipherVectorTest(21, new RijndaelEngine(256),
+                    new KeyParameter(Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")),
+                    "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "a49406115dfb30a40418aafa4869b7c6a886ff31602a7dd19c889dc64f7e4e7a")
+        };
+
+		public RijndaelTest()
+			: base(tests, new RijndaelEngine(128), new KeyParameter(new byte[16]))
+		{
+		}
+
+		public override string Name
+        {
+			get { return "Rijndael"; }
+        }
+
+        public static void Main(
+			string[] args)
+        {
+            ITest test = new RijndaelTest();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+
+}
diff --git a/crypto/test/src/crypto/test/RipeMD128DigestTest.cs b/crypto/test/src/crypto/test/RipeMD128DigestTest.cs
new file mode 100644
index 000000000..ead4f06ad
--- /dev/null
+++ b/crypto/test/src/crypto/test/RipeMD128DigestTest.cs
@@ -0,0 +1,74 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * RIPEMD128 Digest Test
+	 */
+	[TestFixture]
+	public class RipeMD128DigestTest
+		: DigestTest
+	{
+		readonly static string[] messages = {
+			"",
+			"a",
+			"abc",
+			"message digest",
+			"abcdefghijklmnopqrstuvwxyz",
+			"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+			"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+		};
+
+		readonly static string[] digests = {
+			"cdf26213a150dc3ecb610f18f6b38b46",
+			"86be7afa339d0fc7cfc785e72f578d33",
+			"c14a12199c66e4ba84636b0f69144c77",
+			"9e327b3d6e523062afc1132d7df9d1b8",
+			"fd2aa607f71dc8f510714922b371834e",
+			"a1aa0689d0fafa2ddc22e88b49133a06",
+			"d1e959eb179c911faea4624c60c5c702",
+			"3f45ef194732c2dbb2c4a2c769795fa3"
+		};
+
+		readonly static String million_a_digest = "4a7f5723f954eba1216c9d8f6320431f";
+
+		public RipeMD128DigestTest()
+			: base(new RipeMD128Digest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			millionATest(million_a_digest);
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new RipeMD128Digest((RipeMD128Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new RipeMD128DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/RipeMD128HMacTest.cs b/crypto/test/src/crypto/test/RipeMD128HMacTest.cs
new file mode 100644
index 000000000..2f6a2d979
--- /dev/null
+++ b/crypto/test/src/crypto/test/RipeMD128HMacTest.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * RipeMD128 HMac Test, test vectors from RFC 2286
+     */
+    [TestFixture]
+    public class RipeMD128HMacTest: ITest
+    {
+        readonly static string[] keys =
+        {
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            "4a656665",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "0102030405060708090a0b0c0d0e0f10111213141516171819",
+            "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        };
+
+        readonly static string[] digests = {
+            "fbf61f9492aa4bbf81c172e84e0734db",
+            "875f828862b6b334b427c55f9f7ff09b",
+            "09f0b2846d2f543da363cbec8d62a38d",
+            "bdbbd7cf03e44b5aa60af815be4d2294",
+            "e79808f24b25fd031c155f0d551d9a3a",
+            "dc732928de98104a1f59d373c150acbb",
+            "5c6bec96793e16d40690c237635f30c5"
+        };
+
+        readonly static string[] messages = {
+            "Hi There",
+            "what do ya want for nothing?",
+            "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+            "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "Test With Truncation",
+            "Test Using Larger Than Block-Size Key - Hash Key First",
+            "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+        };
+
+		public string Name
+        {
+			get { return "RipeMD128HMac"; }
+        }
+
+		public ITestResult Perform()
+        {
+            HMac hmac = new HMac(new RipeMD128Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+            for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + ": Vector " + i + " failed");
+                }
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new RipeMD128HMacTest();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/RipeMD160DigestTest.cs b/crypto/test/src/crypto/test/RipeMD160DigestTest.cs
new file mode 100644
index 000000000..15e53f2a0
--- /dev/null
+++ b/crypto/test/src/crypto/test/RipeMD160DigestTest.cs
@@ -0,0 +1,74 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * RIPEMD160 Digest Test
+	 */
+	[TestFixture]
+	public class RipeMD160DigestTest
+		: DigestTest
+	{
+		readonly static string[] messages = {
+			"",
+			"a",
+			"abc",
+			"message digest",
+			"abcdefghijklmnopqrstuvwxyz",
+			"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+			"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+		};
+
+		readonly static string[] digests = {
+			"9c1185a5c5e9fc54612808977ee8f548b2258d31",
+			"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
+			"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
+			"5d0689ef49d2fae572b881b123a85ffa21595f36",
+			"f71c27109c692c1b56bbdceb5b9d2865b3708dbc",
+			"12a053384a9c0c88e405a06c27dcf49ada62eb2b",
+			"b0e20b6e3116640286ed3a87a5713079b21f5189",
+			"9b752e45573d4b39f4dbd3323cab82bf63326bfb"
+		};
+
+		readonly static string million_a_digest = "52783243c1697bdbe16d37f97f68f08325dc1528";
+
+		public RipeMD160DigestTest()
+			: base(new RipeMD160Digest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			millionATest(million_a_digest);
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new RipeMD160Digest((RipeMD160Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new RipeMD160DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/RipeMD160HMacTest.cs b/crypto/test/src/crypto/test/RipeMD160HMacTest.cs
new file mode 100644
index 000000000..cc87a535f
--- /dev/null
+++ b/crypto/test/src/crypto/test/RipeMD160HMacTest.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * RipeMD160 HMac Test, test vectors from RFC 2286
+     */
+    [TestFixture]
+    public class RipeMD160HMacTest
+		: ITest
+    {
+        readonly static string[] keys =
+        {
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            "4a656665",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "0102030405060708090a0b0c0d0e0f10111213141516171819",
+            "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        };
+
+        readonly static string[] digests = {
+            "24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668",
+            "dda6c0213a485a9e24f4742064a7f033b43c4069",
+            "b0b105360de759960ab4f35298e116e295d8e7c1",
+            "d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4",
+            "7619693978f91d90539ae786500ff3d8e0518e39",
+            "6466ca07ac5eac29e1bd523e5ada7605b791fd8b",
+            "69ea60798d71616cce5fd0871e23754cd75d5a0a"
+        };
+
+        readonly static string[] messages = {
+            "Hi There",
+            "what do ya want for nothing?",
+            "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+            "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "Test With Truncation",
+            "Test Using Larger Than Block-Size Key - Hash Key First",
+            "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+        };
+
+        public string Name
+        {
+			get { return "RipeMD160HMac"; }
+        }
+
+		public ITestResult Perform()
+        {
+            HMac hmac = new HMac(new RipeMD160Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+            for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + ": Vector " + i + " failed");
+                }
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new RipeMD160HMacTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+
+}
diff --git a/crypto/test/src/crypto/test/RipeMD256DigestTest.cs b/crypto/test/src/crypto/test/RipeMD256DigestTest.cs
new file mode 100644
index 000000000..5b3e6b10b
--- /dev/null
+++ b/crypto/test/src/crypto/test/RipeMD256DigestTest.cs
@@ -0,0 +1,74 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * RIPEMD256 Digest Test
+	 */
+	[TestFixture]
+	public class RipeMD256DigestTest
+		: DigestTest
+	{
+		readonly static string[] messages = {
+			"",
+			"a",
+			"abc",
+			"message digest",
+			"abcdefghijklmnopqrstuvwxyz",
+			"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+			"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+		};
+
+		readonly static string[] digests = {
+			"02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d",
+			"f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925",
+			"afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65",
+			"87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e",
+			"649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133",
+			"3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f",
+			"5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8",
+			"06fdcc7a409548aaf91368c06a6275b553e3f099bf0ea4edfd6778df89a890dd"
+		};
+
+		readonly static string million_a_digest = "ac953744e10e31514c150d4d8d7b677342e33399788296e43ae4850ce4f97978";
+
+		public RipeMD256DigestTest()
+			: base(new RipeMD256Digest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			millionATest(million_a_digest);
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new RipeMD256Digest((RipeMD256Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new RipeMD256DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/RipeMD320DigestTest.cs b/crypto/test/src/crypto/test/RipeMD320DigestTest.cs
new file mode 100644
index 000000000..047d68aa7
--- /dev/null
+++ b/crypto/test/src/crypto/test/RipeMD320DigestTest.cs
@@ -0,0 +1,74 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * RIPEMD320 Digest Test
+	 */
+	[TestFixture]
+	public class RipeMD320DigestTest
+		: DigestTest
+	{
+		readonly static string[] messages = {
+			"",
+			"a",
+			"abc",
+			"message digest",
+			"abcdefghijklmnopqrstuvwxyz",
+			"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+			"12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+		};
+
+		readonly static string[] digests = {
+			"22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8",
+			"ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d",
+			"de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d",
+			"3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197",
+			"cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009",
+			"d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac",
+			"ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4",
+			"557888af5f6d8ed62ab66945c6d2a0a47ecd5341e915eb8fea1d0524955f825dc717e4a008ab2d42"
+		};
+
+		readonly static string million_a_digest = "bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66";
+
+		public RipeMD320DigestTest()
+			: base(new RipeMD320Digest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			millionATest(million_a_digest);
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new RipeMD320Digest((RipeMD320Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new RipeMD320DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/RsaTest.cs b/crypto/test/src/crypto/test/RsaTest.cs
new file mode 100644
index 000000000..c343f0ba5
--- /dev/null
+++ b/crypto/test/src/crypto/test/RsaTest.cs
@@ -0,0 +1,596 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class RsaTest
+		: SimpleTest
+	{
+		static BigInteger  mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16);
+		static BigInteger  pubExp = new BigInteger("11", 16);
+		static BigInteger  privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16);
+		static BigInteger  p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16);
+		static BigInteger  q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16);
+		static BigInteger  pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16);
+		static BigInteger  qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16);
+		static BigInteger  crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16);
+
+		static string input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
+
+		//
+		// to check that we handling byte extension by big number correctly.
+		//
+		static string edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e";
+
+		static byte[] oversizedSig = Hex.Decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] dudBlock = Hex.Decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] truncatedDataBlock = Hex.Decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] incorrectPadding = Hex.Decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e");
+		static byte[] missingDataBlock = Hex.Decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+
+		public override string Name
+		{
+			get { return "RSA"; }
+		}
+
+		private void doTestStrictPkcs1Length(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			IAsymmetricBlockCipher   eng = new RsaEngine();
+
+			eng.Init(true, privParameters);
+
+			byte[] data = null;
+
+			try
+			{
+				data = eng.ProcessBlock(oversizedSig, 0, oversizedSig.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("RSA: failed - exception " + e.ToString(), e);
+			}
+
+			eng = new Pkcs1Encoding(eng);
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+
+				Fail("oversized signature block not recognised");
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (!e.Message.Equals("block incorrect size"))
+				{
+					Fail("RSA: failed - exception " + e.ToString(), e);
+				}
+			}
+
+
+			// Create the encoding with StrictLengthEnabled=false (done thru environment in Java version)
+			Pkcs1Encoding.StrictLengthEnabled = false;
+
+			eng = new Pkcs1Encoding(new RsaEngine());
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (InvalidCipherTextException e)
+			{
+				Fail("RSA: failed - exception " + e.ToString(), e);
+			}
+
+			Pkcs1Encoding.StrictLengthEnabled = true;
+		}
+
+		private void doTestTruncatedPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, truncatedDataBlock, "block truncated");
+		}
+
+		private void doTestDudPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, dudBlock, "unknown block type");
+		}
+
+		private void doTestWrongPaddingPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, incorrectPadding, "block padding incorrect");
+		}
+
+		private void doTestMissingDataPkcs1Block(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			checkForPkcs1Exception(pubParameters, privParameters, missingDataBlock, "no data in block");
+		}
+
+		private void checkForPkcs1Exception(RsaKeyParameters pubParameters, RsaKeyParameters privParameters, byte[] inputData, string expectedMessage)
+		{
+			IAsymmetricBlockCipher   eng = new RsaEngine();
+
+			eng.Init(true, privParameters);
+
+			byte[] data = null;
+
+			try
+			{
+				data = eng.ProcessBlock(inputData, 0, inputData.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("RSA: failed - exception " + e.ToString(), e);
+			}
+
+			eng = new Pkcs1Encoding(eng);
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+
+				Fail("missing data block not recognised");
+			}
+			catch (InvalidCipherTextException e)
+			{
+				if (!e.Message.Equals(expectedMessage))
+				{
+					Fail("RSA: failed - exception " + e.ToString(), e);
+				}
+			}
+		}
+
+		private void doTestOaep(RsaKeyParameters pubParameters, RsaKeyParameters privParameters)
+		{
+			//
+			// OAEP - public encrypt, private decrypt
+			//
+			IAsymmetricBlockCipher eng = new OaepEncoding(new RsaEngine());
+			byte[] data = Hex.Decode(input);
+
+			eng.Init(true, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed OAEP Test");
+			}
+		}
+
+		// TODO Move this when other JCE tests are ported from Java
+		/**
+		 * signature with a "forged signature" (sig block not at end of plain text)
+		 */
+		private void doTestBadSig()//PrivateKey priv, PublicKey pub)
+		{
+//			Signature           sig = Signature.getInstance("SHA1WithRSAEncryption", "BC");
+			ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
+//			KeyPairGenerator    fact;
+//			KeyPair             keyPair;
+//			byte[]              data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+//			fact = KeyPairGenerator.getInstance("RSA", "BC");
+			RsaKeyPairGenerator fact = new RsaKeyPairGenerator();
+
+//			fact.initialize(768, new SecureRandom());
+			RsaKeyGenerationParameters factParams = new RsaKeyGenerationParameters(
+//				BigInteger.ValueOf(0x11), new SecureRandom(), 768, 25);
+				BigInteger.ValueOf(3), new SecureRandom(), 768, 25);
+			fact.Init(factParams);
+
+//			keyPair = fact.generateKeyPair();
+//
+//			PrivateKey  signingKey = keyPair.getPrivate();
+//			PublicKey   verifyKey = keyPair.getPublic();
+			AsymmetricCipherKeyPair keyPair = fact.GenerateKeyPair();
+
+			AsymmetricKeyParameter priv = keyPair.Private;
+			AsymmetricKeyParameter pub = keyPair.Public;
+
+//			testBadSig(signingKey, verifyKey);
+
+
+
+
+
+//			MessageDigest sha1 = MessageDigest.getInstance("SHA1", "BC");
+			IDigest sha1 = DigestUtilities.GetDigest("SHA1");
+
+//			Cipher signer = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
+//			IBufferedCipher signer = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");
+			IAsymmetricBlockCipher signer = new Pkcs1Encoding(new RsaEngine());
+
+//			signer.init(Cipher.ENCRYPT_MODE, priv);
+			signer.Init(true, priv);
+
+//			byte[] block = new byte[signer.getBlockSize()];
+//			byte[] block = new byte[signer.GetBlockSize()];
+			byte[] block = new byte[signer.GetInputBlockSize()];
+
+//			sha1.update((byte)0);
+			sha1.Update(0);
+
+//			byte[] sigHeader = Hex.decode("3021300906052b0e03021a05000414");
+			byte[] sigHeader = Hex.Decode("3021300906052b0e03021a05000414");
+//			System.arraycopy(sigHeader, 0, block, 0, sigHeader.length);
+			Array.Copy(sigHeader, 0, block, 0, sigHeader.Length);
+
+//			sha1.digest(block, sigHeader.length, sha1.getDigestLength());
+			sha1.DoFinal(block, sigHeader.Length);
+
+//			System.arraycopy(sigHeader, 0, block,
+//				sigHeader.length + sha1.getDigestLength(), sigHeader.length);
+			Array.Copy(sigHeader, 0, block,
+				sigHeader.Length + sha1.GetDigestSize(), sigHeader.Length);
+
+//			byte[] sigBytes = signer.doFinal(block);
+			byte[] sigBytes = signer.ProcessBlock(block, 0, block.Length);
+
+//			Signature verifier = Signature.getInstance("SHA1WithRSA", "BC");
+			ISigner verifier = SignerUtilities.GetSigner("SHA1WithRSA");
+
+//			verifier.initVerify(pub);
+			verifier.Init(false, pub);
+
+//			verifier.update((byte)0);
+			verifier.Update(0);
+
+//			if (verifier.verify(sig))
+			if (verifier.VerifySignature(sigBytes))
+			{
+//				fail("bad signature passed");
+				Fail("bad signature passed");
+			}
+		}
+
+		private void testZeroBlock(ICipherParameters encParameters, ICipherParameters decParameters)
+		{
+			IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
+		
+			eng.Init(true, encParameters);
+
+			if (eng.GetOutputBlockSize() != ((Pkcs1Encoding)eng).GetUnderlyingCipher().GetOutputBlockSize())
+			{
+				Fail("PKCS1 output block size incorrect");
+			}
+
+			byte[] zero = new byte[0];
+			byte[] data = null;
+
+			try
+			{
+				data = eng.ProcessBlock(zero, 0, zero.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			eng.Init(false, decParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString(), e);
+			}
+
+			if (!Arrays.AreEqual(zero, data))
+			{
+				Fail("failed PKCS1 zero Test");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			RsaKeyParameters pubParameters = new RsaKeyParameters(false, mod, pubExp);
+			RsaKeyParameters privParameters = new RsaPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef);
+			byte[] data = Hex.Decode(edgeInput);
+
+			//
+			// RAW
+			//
+			IAsymmetricBlockCipher   eng = new RsaEngine();
+
+			eng.Init(true, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("RSA: failed - exception " + e.ToString());
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			if (!edgeInput.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed RAW edge Test");
+			}
+
+			data = Hex.Decode(input);
+
+			eng.Init(true, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed RAW Test");
+			}
+
+			//
+			// PKCS1 - public encrypt, private decrypt
+			//
+			eng = new Pkcs1Encoding(eng);
+
+			eng.Init(true, pubParameters);
+
+			if (eng.GetOutputBlockSize() != ((Pkcs1Encoding)eng).GetUnderlyingCipher().GetOutputBlockSize())
+			{
+				Fail("PKCS1 output block size incorrect");
+			}
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			eng.Init(false, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed PKCS1 public/private Test");
+			}
+
+			//
+			// PKCS1 - private encrypt, public decrypt
+			//
+			eng = new Pkcs1Encoding(((Pkcs1Encoding)eng).GetUnderlyingCipher());
+
+			eng.Init(true, privParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			eng.Init(false, pubParameters);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed PKCS1 private/public Test");
+			}
+
+			testZeroBlock(pubParameters, privParameters);
+			testZeroBlock(privParameters, pubParameters);
+
+			//
+			// key generation test
+			//
+			RsaKeyPairGenerator  pGen = new RsaKeyPairGenerator();
+			RsaKeyGenerationParameters  genParam = new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x11), new SecureRandom(), 768, 25);
+
+			pGen.Init(genParam);
+
+			AsymmetricCipherKeyPair  pair = pGen.GenerateKeyPair();
+
+			eng = new RsaEngine();
+
+			if (((RsaKeyParameters)pair.Public).Modulus.BitLength < 768)
+			{
+				Fail("failed key generation (768) length test");
+			}
+
+			eng.Init(true, pair.Public);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			eng.Init(false, pair.Private);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed key generation (768) Test");
+			}
+
+			genParam = new RsaKeyGenerationParameters(BigInteger.ValueOf(0x11), new SecureRandom(), 1024, 25);
+
+			pGen.Init(genParam);
+			pair = pGen.GenerateKeyPair();
+
+			eng.Init(true, pair.Public);
+
+			if (((RsaKeyParameters)pair.Public).Modulus.BitLength < 1024)
+			{
+				Fail("failed key generation (1024) length test");
+			}
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			eng.Init(false, pair.Private);
+
+			try
+			{
+				data = eng.ProcessBlock(data, 0, data.Length);
+			}
+			catch (Exception e)
+			{
+				Fail("failed - exception " + e.ToString());
+			}
+
+			if (!input.Equals(Hex.ToHexString(data)))
+			{
+				Fail("failed key generation (1024) test");
+			}
+
+			genParam = new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x11), new SecureRandom(), 16, 25);
+			pGen.Init(genParam);
+
+			for (int i = 0; i < 100; ++i)
+			{
+				pair = pGen.GenerateKeyPair();
+				RsaPrivateCrtKeyParameters privKey = (RsaPrivateCrtKeyParameters) pair.Private;
+				BigInteger pqDiff = privKey.P.Subtract(privKey.Q).Abs();
+
+				if (pqDiff.BitLength < 5)
+				{
+					Fail("P and Q too close in RSA key pair");
+				}
+			}
+
+			doTestBadSig();
+			doTestOaep(pubParameters, privParameters);
+			doTestStrictPkcs1Length(pubParameters, privParameters);
+			doTestDudPkcs1Block(pubParameters, privParameters);
+			doTestMissingDataPkcs1Block(pubParameters, privParameters);
+			doTestTruncatedPkcs1Block(pubParameters, privParameters);
+			doTestWrongPaddingPkcs1Block(pubParameters, privParameters);
+
+			try
+			{
+				new RsaEngine().ProcessBlock(new byte[]{ 1 }, 0, 1);
+				Fail("failed initialisation check");
+			}
+			catch (InvalidOperationException)
+			{
+				// expected
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new RsaTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SCryptTest.cs b/crypto/test/src/crypto/test/SCryptTest.cs
new file mode 100644
index 000000000..c055ab718
--- /dev/null
+++ b/crypto/test/src/crypto/test/SCryptTest.cs
@@ -0,0 +1,103 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <summary>
+	/// scrypt test vectors from "Stronger Key Derivation Via Sequential Memory-hard Functions" Appendix B.
+	/// (http://www.tarsnap.com/scrypt/scrypt.pdf)
+	/// </summary>
+	[TestFixture]
+	public class SCryptTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "SCrypt"; }
+		}
+
+		public override void PerformTest()
+		{
+			using (StreamReader sr = new StreamReader(SimpleTest.GetTestDataAsStream("scrypt.TestVectors.txt")))
+			{
+				int count = 0;
+				string line = sr.ReadLine();
+
+				while (line != null)
+				{
+					++count;
+					string header = line;
+					StringBuilder data = new StringBuilder();
+
+					while (!IsEndData(line = sr.ReadLine()))
+					{
+						data.Append(line.Replace(" ", ""));
+					}
+
+					int start = header.IndexOf('(') + 1;
+					int limit = header.LastIndexOf(')');
+					string argStr = header.Substring(start, limit - start);
+					string[] args = argStr.Split(',');
+
+					byte[] P = ExtractQuotedString(args[0]);
+					byte[] S = ExtractQuotedString(args[1]);
+					int N = ExtractInteger(args[2]);
+					int r = ExtractInteger(args[3]);
+					int p = ExtractInteger(args[4]);
+					int dkLen = ExtractInteger(args[5]);
+					byte[] expected = Hex.Decode(data.ToString());
+
+					// This skips very expensive test case(s), remove check to re-enable
+					if (N <= 16384)
+					{
+						byte[] result = SCrypt.Generate(P, S, N, r, p, dkLen);
+
+						if (!AreEqual(expected, result))
+						{
+							Fail("Result does not match expected value in test case " + count);
+						}
+					}
+				}
+			}
+		}
+
+		private static bool IsEndData(string line)
+		{
+			return line == null || line.StartsWith("scrypt");
+		}
+
+		private static byte[] ExtractQuotedString(string arg)
+		{
+			arg = arg.Trim();
+			arg = arg.Substring(1, arg.Length - 2);
+			return Encoding.ASCII.GetBytes(arg);
+		}
+
+		private static int ExtractInteger(string arg)
+		{
+			return int.Parse(arg.Trim());
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SCryptTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SEEDTest.cs b/crypto/test/src/crypto/test/SEEDTest.cs
new file mode 100644
index 000000000..2fcb242cc
--- /dev/null
+++ b/crypto/test/src/crypto/test/SEEDTest.cs
@@ -0,0 +1,65 @@
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* SEED tester - vectors http://www.ietf.org/rfc/rfc4009.txt
+	*/
+	[TestFixture]
+	public class SeedTest
+		: CipherTest
+	{
+		static SimpleTest[]  tests =
+		{
+			new BlockCipherVectorTest(0, new SeedEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"000102030405060708090a0b0c0d0e0f",
+				"5EBAC6E0054E166819AFF1CC6D346CDB"),
+			new BlockCipherVectorTest(0, new SeedEngine(),
+				new KeyParameter(Hex.Decode("000102030405060708090a0b0c0d0e0f")),
+				"00000000000000000000000000000000",
+				"c11f22f20140505084483597e4370f43"),
+			new BlockCipherVectorTest(0, new SeedEngine(),
+				new KeyParameter(Hex.Decode("4706480851E61BE85D74BFB3FD956185")),
+				"83A2F8A288641FB9A4E9A5CC2F131C7D",
+				"EE54D13EBCAE706D226BC3142CD40D4A"),
+			new BlockCipherVectorTest(0, new SeedEngine(),
+				new KeyParameter(Hex.Decode("28DBC3BC49FFD87DCFA509B11D422BE7")),
+				"B41E6BE2EBA84A148E2EED84593C5EC7",
+				"9B9B7BFCD1813CB95D0B3618F40F5122"),
+			new BlockCipherVectorTest(0, new SeedEngine(),
+				new KeyParameter(Hex.Decode("0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E")),
+				"0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E",
+				"8296F2F1B007AB9D533FDEE35A9AD850"),
+		};
+
+		public SeedTest()
+			: base(tests, new SeedEngine(), new KeyParameter(new byte[16]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "SEED"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SeedTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SHA1DigestTest.cs b/crypto/test/src/crypto/test/SHA1DigestTest.cs
new file mode 100644
index 000000000..318035b0c
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA1DigestTest.cs
@@ -0,0 +1,57 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <remarks>Standard vector test for SHA-1 from "Handbook of Applied Cryptography", page 345.</remarks>
+	[TestFixture]
+	public class Sha1DigestTest
+		: DigestTest
+	{
+		private static string[] messages =
+		{
+			"",
+			"a",
+			"abc",
+			"abcdefghijklmnopqrstuvwxyz"
+		};
+
+		private static string[] digests =
+		{
+			"da39a3ee5e6b4b0d3255bfef95601890afd80709",
+			"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
+			"a9993e364706816aba3e25717850c26c9cd0d89d",
+			"32d10c7b8cf96570ca04ce37f2a19d84240d3a89"
+		};
+
+		public Sha1DigestTest()
+			: base(new Sha1Digest(), messages, digests)
+		{
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new Sha1Digest((Sha1Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Sha1DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SHA1HMacTest.cs b/crypto/test/src/crypto/test/SHA1HMacTest.cs
new file mode 100644
index 000000000..865f5b58b
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA1HMacTest.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> SHA1 HMac Test, test vectors from RFC 2202</summary>
+    [TestFixture]
+    public class Sha1HMacTest
+		: ITest
+    {
+        public string Name
+        {
+			get { return "SHA1HMac"; }
+        }
+
+		public static readonly string[] keys = new string[]{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "4a656665", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "0102030405060708090a0b0c0d0e0f10111213141516171819", "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"};
+        public static readonly string[] digests = new string[]{"b617318655057264e28bc0b6fb378c8ef146be00", "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", "125d7342b9ac11cd91a39af48aa17b4f63f175d3", "4c9007f4026250c6bc8414f9bf50c86c2d7235da", "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", "aa4ae5e15272d00e95705637ce8a3b55ed402112", "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", "aa4ae5e15272d00e95705637ce8a3b55ed402112", "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"};
+        public static readonly string[] messages = new string[]{"Hi There", "what do ya want for nothing?", "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", "Test With Truncation", "Test Using Larger Than Block-Size Key - Hash Key First", "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"};
+
+		public virtual ITestResult Perform()
+        {
+            HMac hmac = new HMac(new Sha1Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+            for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + ": Vector " + i + " failed");
+                }
+            }
+
+            //
+            // test reset
+            //
+            int vector = 0; // vector used for test
+            byte[] m2 = Encoding.ASCII.GetBytes(messages[vector]);
+            if (messages[vector].StartsWith("0x"))
+            {
+                m2 = Hex.Decode(messages[vector].Substring(2));
+            }
+            hmac.Init(new KeyParameter(Hex.Decode(keys[vector])));
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+            hmac.Reset();
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+
+            if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[vector])))
+            {
+                return new SimpleTestResult(false, Name + "Reset with vector " + vector + " failed");
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new Sha1HMacTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA224DigestTest.cs b/crypto/test/src/crypto/test/SHA224DigestTest.cs
new file mode 100644
index 000000000..9469b651b
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA224DigestTest.cs
@@ -0,0 +1,70 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * standard vector test for SHA-224 from RFC 3874 - only the last three are in
+	 * the RFC.
+	 */
+	[TestFixture]
+	public class Sha224DigestTest
+		: DigestTest
+	{
+		private static string[] messages =
+		{
+			"",
+			"a",
+			"abc",
+			"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+		};
+
+		private static string[] digests =
+		{
+			"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
+			"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5",
+			"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
+			"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"
+		};
+
+		// 1 million 'a'
+		private static string million_a_digest = "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67";
+
+		public Sha224DigestTest()
+			: base(new Sha224Digest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			millionATest(million_a_digest);
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new Sha224Digest((Sha224Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Sha224DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SHA224HMacTest.cs b/crypto/test/src/crypto/test/SHA224HMacTest.cs
new file mode 100644
index 000000000..06c6ea1cb
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA224HMacTest.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> SHA224 HMac Test, test vectors from RFC</summary>
+    [TestFixture]
+    public class Sha224HMacTest
+		: ITest
+    {
+        public string Name
+        {
+			get { return "SHA224HMac"; }
+        }
+
+		public static readonly string[] keys =
+		{
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            "4a656665",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "0102030405060708090a0b0c0d0e0f10111213141516171819",
+            "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        };
+
+		public static readonly string[] digests =
+		{
+            "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22",
+            "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44",
+            "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea",
+            "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a",
+            "0e2aea68a90c8d37c988bcdb9fca6fa8099cd857c7ec4a1815cac54c",
+            "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e",
+            "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1"
+        };
+
+		public static readonly string[] messages =
+		{
+            "Hi There",
+            "what do ya want for nothing?",
+            "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+            "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "Test With Truncation",
+            "Test Using Larger Than Block-Size Key - Hash Key First",
+            "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."
+        };
+
+		public virtual ITestResult Perform()
+        {
+            HMac hmac = new HMac(new Sha224Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+            for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + ": Vector " + i + " failed");
+                }
+            }
+
+            //
+            // test reset
+            //
+            int vector = 0; // vector used for test
+            byte[] m2 = Encoding.ASCII.GetBytes(messages[vector]);
+            if (messages[vector].StartsWith("0x"))
+            {
+                m2 = Hex.Decode(messages[vector].Substring(2));
+            }
+            hmac.Init(new KeyParameter(Hex.Decode(keys[vector])));
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+            hmac.Reset();
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+
+            if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[vector])))
+            {
+                return new SimpleTestResult(false, Name + "Reset with vector " + vector + " failed");
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new Sha224HMacTest();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA256DigestTest.cs b/crypto/test/src/crypto/test/SHA256DigestTest.cs
new file mode 100644
index 000000000..d2ae89e56
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA256DigestTest.cs
@@ -0,0 +1,71 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for SHA-256 from FIPS Draft 180-2.
+     *
+     * Note, the first two vectors are _not_ from the draft, the last three are.
+     */
+    [TestFixture]
+    public class Sha256DigestTest
+        : DigestTest
+    {
+        private static string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+        };
+
+        private static string[] digests =
+        {
+            "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+            "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
+            "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
+            "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
+        };
+
+        // 1 million 'a'
+        static private string  million_a_digest = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0";
+
+        public Sha256DigestTest()
+            : base(new Sha256Digest(), messages, digests)
+        {
+        }
+
+        public override void PerformTest()
+        {
+            base.PerformTest();
+
+            millionATest(million_a_digest);
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new Sha256Digest((Sha256Digest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new Sha256DigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA256HMacTest.cs b/crypto/test/src/crypto/test/SHA256HMacTest.cs
new file mode 100644
index 000000000..a9016af21
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA256HMacTest.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> SHA256 HMac Test, test vectors from RFC</summary>
+    [TestFixture]
+    public class Sha256HMacTest
+		: ITest
+    {
+        public string Name
+        {
+			get { return "SHA256HMac"; }
+        }
+
+		public static readonly string[] keys =
+		{
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            "4a656665",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "0102030405060708090a0b0c0d0e0f10111213141516171819",
+            "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        };
+
+		public static readonly string[] digests =
+		{
+            "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+            "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+            "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+            "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+            "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5",
+            "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+            "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"
+        };
+
+		public static readonly string[] messages =
+		{
+            "Hi There",
+            "what do ya want for nothing?",
+            "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+            "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "Test With Truncation",
+            "Test Using Larger Than Block-Size Key - Hash Key First",
+            "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."
+        };
+
+		public virtual ITestResult Perform()
+        {
+            HMac hmac = new HMac(new Sha256Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+            for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + ": Vector " + i + " failed");
+                }
+            }
+
+            //
+            // test reset
+            //
+            int vector = 0; // vector used for test
+            byte[] m2 = Encoding.ASCII.GetBytes(messages[vector]);
+            if (messages[vector].StartsWith("0x"))
+            {
+                m2 = Hex.Decode(messages[vector].Substring(2));
+            }
+            hmac.Init(new KeyParameter(Hex.Decode(keys[vector])));
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+            hmac.Reset();
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+
+            if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[vector])))
+            {
+                return new SimpleTestResult(false, Name + "Reset with vector " + vector + " failed");
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new Sha256HMacTest();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA384DigestTest.cs b/crypto/test/src/crypto/test/SHA384DigestTest.cs
new file mode 100644
index 000000000..99363ac5a
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA384DigestTest.cs
@@ -0,0 +1,70 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for SHA-384 from FIPS Draft 180-2.
+     *
+     * Note, the first two vectors are _not_ from the draft, the last three are.
+     */
+    [TestFixture]
+    public class Sha384DigestTest
+        : DigestTest
+    {
+        private static string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+        };
+
+        private static string[] digests =
+        {
+            "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
+            "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
+            "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
+            "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039"
+        };
+
+        static private string  million_a_digest = "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985";
+
+        public Sha384DigestTest()
+            : base(new Sha384Digest(), messages, digests)
+        {
+        }
+
+        public override void PerformTest()
+        {
+            base.PerformTest();
+
+            millionATest(million_a_digest);
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new Sha384Digest((Sha384Digest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new Sha384DigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA384HMacTest.cs b/crypto/test/src/crypto/test/SHA384HMacTest.cs
new file mode 100644
index 000000000..0caba12c4
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA384HMacTest.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary> SHA384 HMac Test, test vectors from RFC</summary>
+    [TestFixture]
+    public class Sha384HMacTest
+		: ITest
+    {
+        public string Name
+        {
+			get { return "SHA384HMac"; }
+        }
+
+		public static readonly string[] keys =
+		{
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            "4a656665",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "0102030405060708090a0b0c0d0e0f10111213141516171819",
+            "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        };
+
+		public static readonly string[] digests =
+		{
+            "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6",
+            "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
+            "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27",
+            "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb",
+            "3abf34c3503b2a23a46efc619baef897f4c8e42c934ce55ccbae9740fcbc1af4ca62269e2a37cd88ba926341efe4aeea",
+            "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952",
+            "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e"
+        };
+
+		public static readonly string[] messages =
+		{
+            "Hi There",
+            "what do ya want for nothing?",
+            "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+            "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "Test With Truncation",
+            "Test Using Larger Than Block-Size Key - Hash Key First",
+            "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."
+        };
+
+		public virtual ITestResult Perform()
+        {
+            HMac hmac = new HMac(new Sha384Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+            for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + ": Vector " + i + " failed");
+                }
+            }
+
+            //
+            // test reset
+            //
+            int vector = 0; // vector used for test
+            byte[] m2 = Encoding.ASCII.GetBytes(messages[vector]);
+            if (messages[vector].StartsWith("0x"))
+            {
+                m2 = Hex.Decode(messages[vector].Substring(2));
+            }
+            hmac.Init(new KeyParameter(Hex.Decode(keys[vector])));
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+            hmac.Reset();
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+
+            if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[vector])))
+            {
+                return new SimpleTestResult(false, Name + "Reset with vector " + vector + " failed");
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new Sha384HMacTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA3DigestTest.cs b/crypto/test/src/crypto/test/SHA3DigestTest.cs
new file mode 100644
index 000000000..2b8ae4a63
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA3DigestTest.cs
@@ -0,0 +1,374 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * SHA3 Digest Test
+     */
+    [TestFixture]
+    public class Sha3DigestTest
+        : SimpleTest
+    {
+        readonly static string[] messages = {
+            "",
+            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67",
+            "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e"
+        };
+
+        readonly static string[] digests288 = { // the default settings
+            "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d01",  // message[0]    
+            "0bbe6afae0d7e89054085c1cc47b1689772c89a41796891e197d1ca1b76f288154933ded",  // message[1]
+            "82558a209b960ddeb531e6dcb281885b2400ca160472462486e79f071e88a3330a8a303d",  // message[2]
+            "94049e1ad7ef5d5b0df2b880489e7ab09ec937c3bfc1b04470e503e1ac7b1133c18f86da",  // 64k a-test
+            "a9cb5a75b5b81b7528301e72553ed6770214fa963956e790528afe420de33c074e6f4220",  // random alphabet test
+            "eadaf5ba2ad6a2f6f338fce0e1efdad2a61bb38f6be6068b01093977acf99e97a5d5827c"   // extremely long data test
+        };
+
+        readonly static string[] digests224 = {
+            "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd",
+            "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe",
+            "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab",
+            "f621e11c142fbf35fa8c22841c3a812ba1e0151be4f38d80b9f1ff53",
+            "68b5fc8c87193155bba68a2485377e809ee4f81a85ef023b9e64add0",
+            "c42e4aee858e1a8ad2976896b9d23dd187f64436ee15969afdbc68c5"
+        };
+
+        readonly static string[] digests256 = {
+            "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
+            "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15",
+            "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d",
+            "0047a916daa1f92130d870b542e22d3108444f5a7e4429f05762fb647e6ed9ed",
+            "db368762253ede6d4f1db87e0b799b96e554eae005747a2ea687456ca8bcbd03",
+            "5f313c39963dcf792b5470d4ade9f3a356a3e4021748690a958372e2b06f82a4"
+        };
+
+        readonly static string[] digests384 = {
+            "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff",
+            "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3",
+            "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b",
+            "c704cfe7a1a53208ca9526cd24251e0acdc252ecd978eee05acd16425cfb404ea81f5a9e2e5e97784d63ee6a0618a398",
+            "d4fe8586fd8f858dd2e4dee0bafc19b4c12b4e2a856054abc4b14927354931675cdcaf942267f204ea706c19f7beefc4",
+            "9b7168b4494a80a86408e6b9dc4e5a1837c85dd8ff452ed410f2832959c08c8c0d040a892eb9a755776372d4a8732315"
+        };
+
+        readonly static string[] digests512 = {
+            "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e",
+            "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609",
+            "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760",
+            "34341ead153aa1d1fdcf6cf624c2b4f6894b6fd16dc38bd4ec971ac0385ad54fafcb2e0ed86a1e509456f4246fdcb02c3172824cd649d9ad54c51f7fb49ea67c",
+            "dc44d4f4d36b07ab5fc04016cbe53548e5a7778671c58a43cb379fd00c06719b8073141fc22191ffc3db5f8b8983ae8341fa37f18c1c969664393aa5ceade64e",
+            "3e122edaf37398231cfaca4c7c216c9d66d5b899ec1d7ac617c40c7261906a45fc01617a021e5da3bd8d4182695b5cb785a28237cbb167590e34718e56d8aab8"
+        };
+
+        // test vectors from  http://www.di-mgt.com.au/hmac_sha3_testvectors.html
+        readonly static byte[][] macKeys =
+        {
+            Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
+            Hex.Decode("4a656665"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
+            Hex.Decode("0102030405060708090a0b0c0d0e0f10111213141516171819"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaa"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaa"),
+            Hex.Decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
+                       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
+        };
+
+        readonly static string[] macData =
+        {
+            "4869205468657265",
+            "7768617420646f2079612077616e7420666f72206e6f7468696e673f",
+            "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" +
+                "dddddddddddddddddddddddddddddddddddd",
+            "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" +
+                "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+            "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" +
+                "65204b6579202d2048617368204b6579204669727374",
+            "5468697320697320612074657374207573696e672061206c6172676572207468" +
+                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
+                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
+                "647320746f20626520686173686564206265666f7265206265696e6720757365" +
+                "642062792074686520484d414320616c676f726974686d2e",
+            "5468697320697320612074657374207573696e672061206c6172676572207468" +
+                "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" +
+                "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" +
+                "647320746f20626520686173686564206265666f7265206265696e6720757365\n" +
+                "642062792074686520484d414320616c676f726974686d2e"
+        };
+
+        readonly static string[] mac224 =
+        {
+            "b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc",
+            "e824fec96c074f22f99235bb942da1982664ab692ca8501053cbd414",
+            "770df38c99d6e2bacd68056dcfe07d4c89ae20b2686a6185e1faa449",
+            "305a8f2dfb94bad28861a03cbc4d590febe775c58cb4961c28428a0b",
+            "e7a52dfa45f95a217c100066b239aa8ad519be9b35d667268b1b57ff",
+            "ba13009405a929f398b348885caa5419191bb948ada32194afc84104",
+            "92649468be236c3c72c189909c063b13f994be05749dc91310db639e"
+        };
+
+        readonly static string[] mac256 =
+        {
+            "9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821",
+            "aa9aed448c7abc8b5e326ffa6a01cdedf7b4b831881468c044ba8dd4566369a1",
+            "95f43e50f8df80a21977d51a8db3ba572dcd71db24687e6f86f47c1139b26260",
+            "6331ba9b4af5804a68725b3663eb74814494b63c6093e35fb320a85d507936fd",
+            "b4d0cdee7ec2ba81a88b86918958312300a15622377929a054a9ce3ae1fac2b6",
+            "1fdc8cb4e27d07c10d897dec39c217792a6e64fa9c63a77ce42ad106ef284e02",
+            "fdaa10a0299aecff9bb411cf2d7748a4022e4a26be3fb5b11b33d8c2b7ef5484"
+        };
+
+        readonly static string[] mac384 =
+        {
+            "892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048",
+            "5af5c9a77a23a6a93d80649e562ab77f4f3552e3c5caffd93bdf8b3cfc6920e3023fc26775d9df1f3c94613146ad2c9d",
+            "4243c29f2201992ff96441e3b91ff81d8c601d706fbc83252684a4bc51101ca9b2c06ddd03677303c502ac5331752a3c",
+            "b730724d3d4090cda1be799f63acbbe389fef7792fc18676fa5453aab398664650ed029c3498bbe8056f06c658e1e693",
+            "d62482ef601d7847439b55236e9679388ffcd53c62cd126f39be6ea63de762e26cd5974cb9a8de401b786b5555040f6f",
+            "4860ea191ac34994cf88957afe5a836ef36e4cc1a66d75bf77defb7576122d75f60660e4cf731c6effac06402787e2b9",
+            "fe9357e3cfa538eb0373a2ce8f1e26ad6590afdaf266f1300522e8896d27e73f654d0631c8fa598d4bb82af6b744f4f5"
+        };
+
+        readonly static string[] mac512 =
+        {
+            "8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755",
+            "c2962e5bbe1238007852f79d814dbbecd4682e6f097d37a363587c03bfa2eb0859d8d9c701e04cececfd3dd7bfd438f20b8b648e01bf8c11d26824b96cebbdcb",
+            "eb0ed9580e0ec11fc66cbb646b1be904eaff6da4556d9334f65ee4b2c85739157bae9027c51505e49d1bb81cfa55e6822db55262d5a252c088a29a5e95b84a66",
+            "b46193bb59f4f696bf702597616da91e2a4558a593f4b015e69141ba81e1e50ea580834c2b87f87baa25a3a03bfc9bb389847f2dc820beae69d30c4bb75369cb",
+            "d05888a6ebf8460423ea7bc85ea4ffda847b32df32291d2ce115fd187707325c7ce4f71880d91008084ce24a38795d20e6a28328a0f0712dc38253370da3ebb5",
+            "2c6b9748d35c4c8db0b4407dd2ed2381f133bdbd1dfaa69e30051eb6badfcca64299b88ae05fdbd3dd3dd7fe627e42e39e48b0fe8c7f1e85f2dbd52c2d753572",
+            "6adc502f14e27812402fc81a807b28bf8a53c87bea7a1df6256bf66f5de1a4cb741407ad15ab8abc136846057f881969fbb159c321c904bfb557b77afb7778c8"
+        };
+
+        readonly static KeyParameter truncKey = new KeyParameter(Hex.Decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"));
+        readonly static byte[] truncData = Hex.Decode("546573742057697468205472756e636174696f6e");
+
+        readonly static byte[] trunc224 = Hex.Decode("f52bbcfd654264e7133085c5e69b72c3");
+        readonly static byte[] trunc256 = Hex.Decode("745e7e687f8335280d54202ef13cecc6");
+        readonly static byte[] trunc384 = Hex.Decode("fa9aea2bc1e181e47cbb8c3df243814d");
+        readonly static byte[] trunc512 = Hex.Decode("04c929fead434bba190dacfa554ce3f5");
+
+        readonly static byte[] xtremeData = Hex.Decode("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f");
+
+        public override string Name
+        {
+            get { return "SHA3"; }
+        }
+
+        private void TestDigest(IDigest digest, string[] expected)
+        {
+            byte[] hash = new byte[digest.GetDigestSize()];
+
+            for (int i = 0; i != messages.Length; i++)
+            {
+                if (messages.Length != 0)
+                {
+                    byte[] data = Hex.Decode(messages[i]);
+
+                    digest.BlockUpdate(data, 0, data.Length);
+                }
+
+                digest.DoFinal(hash, 0);
+
+                if (!Arrays.AreEqual(Hex.Decode(expected[i]), hash))
+                {
+                    Fail("sha3 mismatch on " + digest.AlgorithmName + " index " + i);
+                }
+            }
+
+            byte[] k64 = new byte[1024 * 64];
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                k64[i] = (byte)'a';
+            }
+
+            digest.BlockUpdate(k64, 0, k64.Length);
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            {
+                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k a");
+            }
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                digest.Update((byte)'a');
+            }
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length]), hash))
+            {
+                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k a single");
+            }
+
+
+            for (int i = 0; i != k64.Length; i++)
+            {
+                k64[i] = (byte)('a' + (i % 26));
+            }
+
+            digest.BlockUpdate(k64, 0, k64.Length);
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            {
+                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k alpha");
+            }
+
+            for (int i = 0; i != 64; i++)
+            {
+                digest.Update(k64[i * 1024]);
+                digest.BlockUpdate(k64, i * 1024 + 1, 1023);
+            }
+
+            digest.DoFinal(hash, 0);
+
+            if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 1]), hash))
+            {
+                Fail("sha3 mismatch on " + digest.AlgorithmName + " 64k chunked alpha");
+            }
+
+            TestDigestDoFinal(digest);
+
+            //
+            // extremely long data test
+            //
+            //Console.WriteLine("Starting very long");
+            //for (int i = 0; i != 16384; i++)
+            //{
+            //    for (int j = 0; j != 1024; j++)
+            //    {
+            //        digest.BlockUpdate(xtremeData, 0, xtremeData.Length);
+            //    }
+            //}
+    
+            //digest.DoFinal(hash, 0);
+    
+            //if (!Arrays.AreEqual(Hex.Decode(expected[messages.Length + 2]), hash))
+            //{
+            //    Fail("sha3 mismatch on " + digest.AlgorithmName + " extreme data test");
+            //}
+            //Console.WriteLine("Done");
+        }
+
+        private void TestDigestDoFinal(IDigest digest)
+        {
+            byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+            for (int i = 0; i <= digest.GetDigestSize(); ++i)
+            {
+                byte[] cmp = new byte[2 * digest.GetDigestSize()];
+                Array.Copy(hash, 0, cmp, i, hash.Length);
+
+                byte[] buf = new byte[2 * digest.GetDigestSize()];
+                digest.DoFinal(buf, i);
+
+                if (!Arrays.AreEqual(cmp, buf))
+                {
+                    Fail("sha3 offset DoFinal on " + digest.AlgorithmName);
+                }
+            }
+        }
+
+        private void TestMac(IDigest digest, byte[][] keys, String[] data, String[] expected, byte[] truncExpected)
+        {
+            IMac mac = new HMac(digest);
+
+            for (int i = 0; i != keys.Length; i++)
+            {
+                mac.Init(new KeyParameter(keys[i]));
+
+                byte[] mData = Hex.Decode(data[i]);
+
+                mac.BlockUpdate(mData, 0, mData.Length);
+
+                byte[] macV = new byte[mac.GetMacSize()];
+
+                mac.DoFinal(macV, 0);
+
+                if (!Arrays.AreEqual(Hex.Decode(expected[i]), macV))
+                {
+                    Fail("sha3 HMAC mismatch on " + digest.AlgorithmName);
+                }
+            }
+
+            {
+                mac = new HMac(digest);
+
+                mac.Init(truncKey);
+
+                mac.BlockUpdate(truncData, 0, truncData.Length);
+
+                byte[] macV = new byte[mac.GetMacSize()];
+
+                mac.DoFinal(macV, 0);
+
+                for (int i = 0; i != truncExpected.Length; i++)
+                {
+                    if (macV[i] != truncExpected[i])
+                    {
+                        Fail("mismatch on truncated HMAC for " + digest.AlgorithmName);
+                    }
+                }
+            }
+        }
+
+        public override void PerformTest()
+        {
+            TestDigest(new Sha3Digest(), digests288);
+            TestDigest(new Sha3Digest(224), digests224);
+            TestDigest(new Sha3Digest(256), digests256);
+            TestDigest(new Sha3Digest(384), digests384);
+            TestDigest(new Sha3Digest(512), digests512);
+
+            TestMac(new Sha3Digest(224), macKeys, macData, mac224, trunc224);
+            TestMac(new Sha3Digest(256), macKeys, macData, mac256, trunc256);
+            TestMac(new Sha3Digest(384), macKeys, macData, mac384, trunc384);
+            TestMac(new Sha3Digest(512), macKeys, macData, mac512, trunc512);
+        }
+
+        protected virtual IDigest CloneDigest(IDigest digest)
+        {
+            return new Sha3Digest((Sha3Digest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new Sha3DigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA512DigestTest.cs b/crypto/test/src/crypto/test/SHA512DigestTest.cs
new file mode 100644
index 000000000..d4f56e15e
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA512DigestTest.cs
@@ -0,0 +1,70 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/// <summary>
+	/// Standard vector test for SHA-512 from FIPS Draft 180-2.
+	/// Note, the first two vectors are _not_ from the draft, the last three are.
+	/// </summary>
+	[TestFixture]
+	public class Sha512DigestTest
+		: DigestTest
+	{
+		private static string[] messages =
+		{
+			"",
+			"a",
+			"abc",
+			"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+		};
+
+		private static string[] digests =
+		{
+			"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
+			"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
+			"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
+			"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"   
+		};
+
+		// 1 million 'a'
+		static private string  million_a_digest = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b";
+
+		public Sha512DigestTest()
+			: base(new Sha512Digest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			millionATest(million_a_digest);
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new Sha512Digest((Sha512Digest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Sha512DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SHA512HMacTest.cs b/crypto/test/src/crypto/test/SHA512HMacTest.cs
new file mode 100644
index 000000000..c091a7220
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA512HMacTest.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+    /// <summary> SHA512 HMac Test, test vectors from RFC</summary>
+    [TestFixture]
+    public class Sha512HMacTest
+		: ITest
+    {
+        public string Name
+        {
+			get { return "SHA512HMac"; }
+        }
+
+		public static readonly string[] keys =
+		{
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            "4a656665",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "0102030405060708090a0b0c0d0e0f10111213141516171819",
+            "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+        };
+
+		public static readonly string[] digests =
+		{
+            "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854",
+            "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
+            "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb",
+            "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd",
+            "415fad6271580a531d4179bc891d87a650188707922a4fbb36663a1eb16da008711c5b50ddd0fc235084eb9d3364a1454fb2ef67cd1d29fe6773068ea266e96b",
+            "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598",
+            "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"
+        };
+
+		public static readonly string[] messages =
+		{
+			"Hi There",
+			"what do ya want for nothing?",
+			"0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+			"0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+			"Test With Truncation",
+			"Test Using Larger Than Block-Size Key - Hash Key First",
+			"This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."
+		};
+
+		public virtual ITestResult Perform()
+        {
+            HMac hmac = new HMac(new Sha512Digest());
+            byte[] resBuf = new byte[hmac.GetMacSize()];
+
+            for (int i = 0; i < messages.Length; i++)
+            {
+                byte[] m = Encoding.ASCII.GetBytes(messages[i]);
+                if (messages[i].StartsWith("0x"))
+                {
+                    m = Hex.Decode(messages[i].Substring(2));
+                }
+                hmac.Init(new KeyParameter(Hex.Decode(keys[i])));
+                hmac.BlockUpdate(m, 0, m.Length);
+                hmac.DoFinal(resBuf, 0);
+
+                if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[i])))
+                {
+                    return new SimpleTestResult(false, Name + ": Vector " + i + " failed");
+                }
+            }
+
+            //
+            // test reset
+            //
+            int vector = 0; // vector used for test
+            byte[] m2 = Encoding.ASCII.GetBytes(messages[vector]);
+            if (messages[vector].StartsWith("0x"))
+            {
+                m2 = Hex.Decode(messages[vector].Substring(2));
+            }
+            hmac.Init(new KeyParameter(Hex.Decode(keys[vector])));
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+            hmac.Reset();
+            hmac.BlockUpdate(m2, 0, m2.Length);
+            hmac.DoFinal(resBuf, 0);
+
+            if (!Arrays.AreEqual(resBuf, Hex.Decode(digests[vector])))
+            {
+                return new SimpleTestResult(false, Name + "Reset with vector " + vector + " failed");
+            }
+
+            return new SimpleTestResult(true, Name + ": Okay");
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            ITest test = new Sha512HMacTest();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA512t224DigestTest.cs b/crypto/test/src/crypto/test/SHA512t224DigestTest.cs
new file mode 100644
index 000000000..a3d68e1ab
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA512t224DigestTest.cs
@@ -0,0 +1,62 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for SHA-512/224 from FIPS 180-4.
+     *
+     * Note, only the last 2 message entries are FIPS originated..
+     */
+    public class Sha512t224DigestTest
+        : DigestTest
+    {
+        private static string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+        };
+
+        private static string[] digests =
+        {
+            "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",
+            "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327",
+            "4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA",
+            "23FEC5BB94D60B23308192640B0C453335D664734FE40E7268674AF9"
+        };
+
+        // 1 million 'a'
+        private const string million_a_digest = "37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287";
+
+        internal Sha512t224DigestTest()
+            : base(new Sha512tDigest(224), messages, digests)
+        {
+        }
+
+        public override void PerformTest()
+        {
+            base.PerformTest();
+
+            millionATest(million_a_digest);
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new Sha512tDigest((Sha512tDigest)digest);
+        }
+
+        public static void Main(
+            string[]    args)
+        {
+            RunTest(new Sha512t224DigestTest());
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SHA512t256DigestTest.cs b/crypto/test/src/crypto/test/SHA512t256DigestTest.cs
new file mode 100644
index 000000000..c957aa660
--- /dev/null
+++ b/crypto/test/src/crypto/test/SHA512t256DigestTest.cs
@@ -0,0 +1,62 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * standard vector test for SHA-512/256 from FIPS 180-4.
+     *
+     * Note, only the last 2 message entries are FIPS originated..
+     */
+    public class Sha512t256DigestTest
+        : DigestTest
+    {
+        private static string[] messages =
+        {
+            "",
+            "a",
+            "abc",
+            "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
+        };
+
+        private static string[] digests =
+        {
+            "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
+            "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8",
+            "53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23",
+            "3928E184FB8690F840DA3988121D31BE65CB9D3EF83EE6146FEAC861E19B563A"
+        };
+
+        // 1 million 'a'
+        private const string million_a_digest = "9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21";
+
+        internal Sha512t256DigestTest()
+            : base(new Sha512tDigest(256), messages, digests)
+        {
+        }
+
+        public override void PerformTest()
+        {
+            base.PerformTest();
+
+            millionATest(million_a_digest);
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new Sha512tDigest((Sha512tDigest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new Sha512t256DigestTest());
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SM3DigestTest.cs b/crypto/test/src/crypto/test/SM3DigestTest.cs
new file mode 100644
index 000000000..113789897
--- /dev/null
+++ b/crypto/test/src/crypto/test/SM3DigestTest.cs
@@ -0,0 +1,74 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	 * standard vector test for SM3 digest from chinese specification
+	 */
+	[TestFixture]
+	public class SM3DigestTest
+	    : DigestTest
+	{
+	    private static string[] messages = {
+	        // Standard test vectors
+	        "abc",
+	        "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
+	        // Non-standard test vectors
+	        "",
+	        "a",
+	        "abcdefghijklmnopqrstuvwxyz",
+	    };
+
+	    private static string[] digests = {
+	        // Standard test vectors
+	        "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
+	        "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732",
+	        // Non-standard test vectors
+	        "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b",
+	        "623476ac18f65a2909e43c7fec61b49c7e764a91a18ccb82f1917a29c86c5e88",
+	        "b80fe97a4da24afc277564f66a359ef440462ad28dcc6d63adb24d5c20a61595",
+	    };
+
+	    private static string sixtyFourKdigest = "97049bdc8f0736bc7300eafa9980aeb9cf00f24f7ec3a8f1f8884954d7655c1d";
+	    private static string million_a_digest = "c8aaf89429554029e231941a2acc0ad61ff2a5acd8fadd25847a3a732b3b02c3";
+
+	    public SM3DigestTest()
+			: base(new SM3Digest(), messages, digests)
+	    {
+	    }
+
+	    public override void PerformTest()
+	    {
+	        base.PerformTest();
+
+	        sixtyFourKTest(sixtyFourKdigest);
+	        millionATest(million_a_digest);
+	    }
+
+	    protected override IDigest CloneDigest(IDigest digest)
+	    {
+	        return new SM3Digest((SM3Digest)digest);
+	    }
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SM3DigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SRP6Test.cs b/crypto/test/src/crypto/test/SRP6Test.cs
new file mode 100644
index 000000000..3b80e2c16
--- /dev/null
+++ b/crypto/test/src/crypto/test/SRP6Test.cs
@@ -0,0 +1,300 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class Srp6Test
+		: SimpleTest
+	{
+	    private static BigInteger FromHex(string hex)
+	    {
+	        return new BigInteger(1, Hex.Decode(hex));
+	    }
+
+		// 1024 bit example prime from RFC5054 and corresponding generator
+		private static readonly BigInteger N_1024 = FromHex("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+	            + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+	            + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+	            + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+	            + "FD5138FE8376435B9FC61D2FC0EB06E3");
+		private static readonly BigInteger g_1024 = BigInteger.Two;
+
+		private readonly SecureRandom random = new SecureRandom();
+
+	    public override string Name
+	    {
+	        get { return "SRP6"; }
+	    }
+
+	    public override void PerformTest()
+	    {
+	    	rfc5054AppendixBTestVectors();
+
+	        testMutualVerification(N_1024, g_1024);
+	        testClientCatchesBadB(N_1024, g_1024);
+	        testServerCatchesBadA(N_1024, g_1024);
+
+			testWithRandomParams(256);
+			testWithRandomParams(384);
+			testWithRandomParams(512);
+	    }
+
+	    private void rfc5054AppendixBTestVectors()
+	    {
+	    	byte[] I = Encoding.UTF8.GetBytes("alice");
+	    	byte[] P = Encoding.UTF8.GetBytes("password123");
+	    	byte[] s = Hex.Decode("BEB25379D1A8581EB5A727673A2441EE");
+	    	BigInteger N = N_1024;
+	    	BigInteger g = g_1024;
+	    	BigInteger a = FromHex("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393");
+	    	BigInteger b = FromHex("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20");
+
+	    	BigInteger expect_k = FromHex("7556AA045AEF2CDD07ABAF0F665C3E818913186F");
+	    	BigInteger expect_x = FromHex("94B7555AABE9127CC58CCF4993DB6CF84D16C124");
+	    	BigInteger expect_v = FromHex("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812"
+	            + "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5"
+	            + "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5"
+	            + "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78"
+	            + "E955A5E29E7AB245DB2BE315E2099AFB");
+	    	BigInteger expect_A = FromHex("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
+	            + "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+	            + "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+	            + "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+	            + "B349EF5D76988A3672FAC47B0769447B");
+	    	BigInteger expect_B = FromHex("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
+	            + "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
+	            + "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
+	            + "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
+	            + "EB4012B7D7665238A8E3FB004B117B58");
+	    	BigInteger expect_u = FromHex("CE38B9593487DA98554ED47D70A7AE5F462EF019");
+	    	BigInteger expect_S = FromHex("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D"
+	            + "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C"
+	            + "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F"
+	            + "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
+	            + "C346D7E474B29EDE8A469FFECA686E5A");
+
+	    	BigInteger k = Srp6Utilities.CalculateK(new Sha1Digest(), N, g);
+	    	if (!k.Equals(expect_k))
+	    	{
+	    		Fail("wrong value of 'k'");
+	    	}
+
+	    	BigInteger x = Srp6Utilities.CalculateX(new Sha1Digest(), N, s, I, P);
+	    	if (!x.Equals(expect_x))
+	    	{
+	    		Fail("wrong value of 'x'");
+	    	}
+
+	    	Srp6VerifierGenerator gen = new Srp6VerifierGenerator();
+	    	gen.Init(N, g, new Sha1Digest());
+	    	BigInteger v = gen.GenerateVerifier(s, I, P);
+	    	if (!v.Equals(expect_v))
+	    	{
+	    		Fail("wrong value of 'v'");
+	    	}
+
+	        Srp6Client client = new MySrp6Client(a);
+	        client.Init(N, g, new Sha1Digest(), random);
+
+	    	BigInteger A = client.GenerateClientCredentials(s, I, P);
+	    	if (!A.Equals(expect_A))
+	    	{
+	    		Fail("wrong value of 'A'");
+	    	}
+
+	    	Srp6Server server = new MySrp6Server(b);
+	        server.Init(N, g, v, new Sha1Digest(), random);
+
+	    	BigInteger B = server.GenerateServerCredentials();
+	    	if (!B.Equals(expect_B))
+	    	{
+	    		Fail("wrong value of 'B'");
+	    	}
+
+	        BigInteger u = Srp6Utilities.CalculateU(new Sha1Digest(), N, A, B);
+	    	if (!u.Equals(expect_u))
+	    	{
+	    		Fail("wrong value of 'u'");
+	    	}
+
+	        BigInteger clientS = client.CalculateSecret(B);
+	        if (!clientS.Equals(expect_S))
+	    	{
+	    		Fail("wrong value of 'S' (client)");
+	    	}
+
+	        BigInteger serverS = server.CalculateSecret(A);
+	        if (!serverS.Equals(expect_S))
+	    	{
+	    		Fail("wrong value of 'S' (server)");
+	    	}
+	    }
+
+		private void testWithRandomParams(int bits)
+		{
+	        DHParametersGenerator paramGen = new DHParametersGenerator();
+	        paramGen.Init(bits, 25, random);
+	        DHParameters parameters = paramGen.GenerateParameters();
+
+	        BigInteger g = parameters.G;
+	        BigInteger p = parameters.P;
+
+	        testMutualVerification(p, g);
+		}
+
+	    private void testMutualVerification(BigInteger N, BigInteger g)
+	    {
+	        byte[] I = Encoding.UTF8.GetBytes("username");
+	        byte[] P = Encoding.UTF8.GetBytes("password");
+	        byte[] s = new byte[16];
+	        random.NextBytes(s);
+
+	        Srp6VerifierGenerator gen = new Srp6VerifierGenerator();
+	        gen.Init(N, g, new Sha256Digest());
+	        BigInteger v = gen.GenerateVerifier(s, I, P);
+
+	        Srp6Client client = new Srp6Client();
+	        client.Init(N, g, new Sha256Digest(), random);
+
+	        Srp6Server server = new Srp6Server();
+	        server.Init(N, g, v, new Sha256Digest(), random);
+
+	        BigInteger A = client.GenerateClientCredentials(s, I, P);
+	        BigInteger B = server.GenerateServerCredentials();
+
+	        BigInteger clientS = client.CalculateSecret(B);
+	        BigInteger serverS = server.CalculateSecret(A);
+
+	        if (!clientS.Equals(serverS))
+	        {
+	            Fail("SRP agreement failed - client/server calculated different secrets");
+	        }
+	    }
+
+	    private void testClientCatchesBadB(BigInteger N, BigInteger g)
+	    {
+	        byte[] I = Encoding.UTF8.GetBytes("username");
+	        byte[] P = Encoding.UTF8.GetBytes("password");
+	        byte[] s = new byte[16];
+	        random.NextBytes(s);
+
+	        Srp6Client client = new Srp6Client();
+	        client.Init(N, g, new Sha256Digest(), random);
+
+	        client.GenerateClientCredentials(s, I, P);
+
+	        try
+	        {
+	        	client.CalculateSecret(BigInteger.Zero);
+	        	Fail("Client failed to detect invalid value for 'B'");
+	        }
+	        catch (CryptoException)
+	        {
+	        	// Expected
+	        }
+
+	        try
+	        {
+	        	client.CalculateSecret(N);
+	        	Fail("Client failed to detect invalid value for 'B'");
+	        }
+	        catch (CryptoException)
+	        {
+	        	// Expected
+	        }
+	    }
+
+	    private void testServerCatchesBadA(BigInteger N, BigInteger g)
+	    {
+	        byte[] I = Encoding.UTF8.GetBytes("username");
+	        byte[] P = Encoding.UTF8.GetBytes("password");
+	        byte[] s = new byte[16];
+	        random.NextBytes(s);
+
+	        Srp6VerifierGenerator gen = new Srp6VerifierGenerator();
+	        gen.Init(N, g, new Sha256Digest());
+	        BigInteger v = gen.GenerateVerifier(s, I, P);
+
+	        Srp6Server server = new Srp6Server();
+	        server.Init(N, g, v, new Sha256Digest(), random);
+
+	        server.GenerateServerCredentials();
+
+	        try
+	        {
+	        	server.CalculateSecret(BigInteger.Zero);
+	        	Fail("Client failed to detect invalid value for 'A'");
+	        }
+	        catch (CryptoException)
+	        {
+	        	// Expected
+	        }
+
+	        try
+	        {
+	        	server.CalculateSecret(N);
+	        	Fail("Client failed to detect invalid value for 'A'");
+	        }
+	        catch (CryptoException)
+	        {
+	        	// Expected
+	        }
+	    }
+
+	    public static void Main(string[] args)
+	    {
+	        RunTest(new Srp6Test());
+	    }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+		private class MySrp6Client
+			: Srp6Client
+		{
+			private readonly BigInteger nonRandomPrivA;
+
+			internal MySrp6Client(BigInteger nonRandomPrivA)
+			{
+				this.nonRandomPrivA = nonRandomPrivA;
+			}
+
+            protected override BigInteger SelectPrivateValue()
+            {
+                return nonRandomPrivA;
+            }
+		}
+
+		private class MySrp6Server
+			: Srp6Server
+		{
+			private readonly BigInteger nonRandomPrivB;
+
+			internal MySrp6Server(BigInteger nonRandomPrivB)
+			{
+				this.nonRandomPrivB = nonRandomPrivB;
+			}
+
+            protected override BigInteger SelectPrivateValue()
+            {
+                return nonRandomPrivB;
+            }
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/Salsa20Test.cs b/crypto/test/src/crypto/test/Salsa20Test.cs
new file mode 100644
index 000000000..b4dc1ef2b
--- /dev/null
+++ b/crypto/test/src/crypto/test/Salsa20Test.cs
@@ -0,0 +1,318 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* Salsa20 Test
+	*/
+	[TestFixture]
+	public class Salsa20Test
+		: SimpleTest
+	{
+		private static readonly byte[] zeroes = Hex.Decode(
+			  "00000000000000000000000000000000"
+			+ "00000000000000000000000000000000"
+			+ "00000000000000000000000000000000"
+			+ "00000000000000000000000000000000");
+
+		private static readonly string set1v0_0 =
+			  "4DFA5E481DA23EA09A31022050859936"
+			+ "DA52FCEE218005164F267CB65F5CFD7F"
+			+ "2B4F97E0FF16924A52DF269515110A07"
+			+ "F9E460BC65EF95DA58F740B7D1DBB0AA";
+
+		private static readonly string set1v0_192 =
+			  "DA9C1581F429E0A00F7D67E23B730676"
+			+ "783B262E8EB43A25F55FB90B3E753AEF"
+			+ "8C6713EC66C51881111593CCB3E8CB8F"
+			+ "8DE124080501EEEB389C4BCB6977CF95";
+
+		private static readonly string set1v0_256 =
+			  "7D5789631EB4554400E1E025935DFA7B"
+			+ "3E9039D61BDC58A8697D36815BF1985C"
+			+ "EFDF7AE112E5BB81E37ECF0616CE7147"
+			+ "FC08A93A367E08631F23C03B00A8DA2F";
+
+		private static readonly string set1v0_448 =
+			  "B375703739DACED4DD4059FD71C3C47F"
+			+ "C2F9939670FAD4A46066ADCC6A564578"
+			+ "3308B90FFB72BE04A6B147CBE38CC0C3"
+			+ "B9267C296A92A7C69873F9F263BE9703";
+
+		private static readonly string set1v9_0 =
+			  "0471076057830FB99202291177FBFE5D"
+			+ "38C888944DF8917CAB82788B91B53D1C"
+			+ "FB06D07A304B18BB763F888A61BB6B75"
+			+ "5CD58BEC9C4CFB7569CB91862E79C459";
+
+		private static readonly string set1v9_192 =
+			  "D1D7E97556426E6CFC21312AE3811425"
+			+ "9E5A6FB10DACBD88E4354B0472556935"
+			+ "2B6DA5ACAFACD5E266F9575C2ED8E6F2"
+			+ "EFE4B4D36114C3A623DD49F4794F865B";
+
+		private static readonly string set1v9_256 =
+			  "AF06FAA82C73291231E1BD916A773DE1"
+			+ "52FD2126C40A10C3A6EB40F22834B8CC"
+			+ "68BD5C6DBD7FC1EC8F34165C517C0B63"
+			+ "9DB0C60506D3606906B8463AA0D0EC2F";
+
+		private static readonly string set1v9_448 =
+			  "AB3216F1216379EFD5EC589510B8FD35"
+			+ "014D0AA0B613040BAE63ECAB90A9AF79"
+			+ "661F8DA2F853A5204B0F8E72E9D9EB4D"
+			+ "BA5A4690E73A4D25F61EE7295215140C";
+
+		private static readonly string set6v0_0 =
+			  "F5FAD53F79F9DF58C4AEA0D0ED9A9601"
+			+ "F278112CA7180D565B420A48019670EA"
+			+ "F24CE493A86263F677B46ACE1924773D"
+			+ "2BB25571E1AA8593758FC382B1280B71";
+
+		private static readonly string set6v0_65472 =
+			  "B70C50139C63332EF6E77AC54338A407"
+			+ "9B82BEC9F9A403DFEA821B83F7860791"
+			+ "650EF1B2489D0590B1DE772EEDA4E3BC"
+			+ "D60FA7CE9CD623D9D2FD5758B8653E70";
+
+		private static readonly string set6v0_65536 =
+			  "81582C65D7562B80AEC2F1A673A9D01C"
+			+ "9F892A23D4919F6AB47B9154E08E699B"
+			+ "4117D7C666477B60F8391481682F5D95"
+			+ "D96623DBC489D88DAA6956B9F0646B6E";
+
+		private static readonly string set6v1_0 =
+			  "3944F6DC9F85B128083879FDF190F7DE"
+			+ "E4053A07BC09896D51D0690BD4DA4AC1"
+			+ "062F1E47D3D0716F80A9B4D85E6D6085"
+			+ "EE06947601C85F1A27A2F76E45A6AA87";
+
+		private static readonly string set6v1_65472 =
+			  "36E03B4B54B0B2E04D069E690082C8C5"
+			+ "92DF56E633F5D8C7682A02A65ECD1371"
+			+ "8CA4352AACCB0DA20ED6BBBA62E177F2"
+			+ "10E3560E63BB822C4158CAA806A88C82";
+
+		private static readonly string set6v1_65536 =
+			  "1B779E7A917C8C26039FFB23CF0EF8E0"
+			+ "8A1A13B43ACDD9402CF5DF38501098DF"
+			+ "C945A6CC69A6A17367BC03431A86B3ED"
+			+ "04B0245B56379BF997E25800AD837D7D";
+
+		// Salsa20/12
+
+		private static readonly string salsa12_set1v0_0 = 
+			"FC207DBFC76C5E1774961E7A5AAD0906"
+			+ "9B2225AC1CE0FE7A0CE77003E7E5BDF8"
+			+ "B31AF821000813E6C56B8C1771D6EE70"
+			+ "39B2FBD0A68E8AD70A3944B677937897";
+
+		private static readonly string salsa12_set1v0_192 = 
+			"4B62A4881FA1AF9560586510D5527ED4"
+			+ "8A51ECAFA4DECEEBBDDC10E9918D44AB"
+			+ "26B10C0A31ED242F146C72940C6E9C37"
+			+ "53F641DA84E9F68B4F9E76B6C48CA5AC";
+
+		private static readonly string salsa12_set1v0_256 = 
+			"F52383D9DEFB20810325F7AEC9EADE34"
+			+ "D9D883FEE37E05F74BF40875B2D0BE79"
+			+ "ED8886E5BFF556CEA8D1D9E86B1F68A9"
+			+ "64598C34F177F8163E271B8D2FEB5996";
+
+		private static readonly string salsa12_set1v0_448 =
+			"A52ED8C37014B10EC0AA8E05B5CEEE12"
+			+ "3A1017557FB3B15C53E6C5EA8300BF74"
+			+ "264A73B5315DC821AD2CAB0F3BB2F152"
+			+ "BDAEA3AEE97BA04B8E72A7B40DCC6BA4";
+
+		// Salsa20/8
+
+		private static readonly string salsa8_set1v0_0 =
+			"A9C9F888AB552A2D1BBFF9F36BEBEB33"
+			+ "7A8B4B107C75B63BAE26CB9A235BBA9D"
+			+ "784F38BEFC3ADF4CD3E266687EA7B9F0"
+			+ "9BA650AE81EAC6063AE31FF12218DDC5";
+
+		private static readonly string salsa8_set1v0_192 =
+			"BB5B6BB2CC8B8A0222DCCC1753ED4AEB"
+			+ "23377ACCBD5D4C0B69A8A03BB115EF71"
+			+ "871BC10559080ACA7C68F0DEF32A80DD"
+			+ "BAF497259BB76A3853A7183B51CC4B9F";
+
+		private static readonly string salsa8_set1v0_256 =
+			"4436CDC0BE39559F5E5A6B79FBDB2CAE"
+			+ "4782910F27FFC2391E05CFC78D601AD8"
+			+ "CD7D87B074169361D997D1BED9729C0D"
+			+ "EB23418E0646B7997C06AA84E7640CE3";
+
+		private static readonly string salsa8_set1v0_448 =
+			"BEE85903BEA506B05FC04795836FAAAC"
+			+ "7F93F785D473EB762576D96B4A65FFE4"
+			+ "63B34AAE696777FC6351B67C3753B89B"
+			+ "A6B197BD655D1D9CA86E067F4D770220";
+
+		public override string Name
+		{
+			get { return "Salsa20"; }
+		}
+
+		public override void PerformTest()
+		{
+			salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")),
+					set1v0_0, set1v0_192,  set1v0_256,  set1v0_448);
+			salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.Decode("00400000000000000000000000000000")), Hex.Decode("0000000000000000")),
+					set1v9_0, set1v9_192,  set1v9_256,  set1v9_448);
+			salsa20Test1(12, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")),
+		             salsa12_set1v0_0, salsa12_set1v0_192,  salsa12_set1v0_256,  salsa12_set1v0_448);
+			salsa20Test1(8, new ParametersWithIV(new KeyParameter(Hex.Decode("80000000000000000000000000000000")), Hex.Decode("0000000000000000")),
+		             salsa8_set1v0_0, salsa8_set1v0_192,  salsa8_set1v0_256,  salsa8_set1v0_448);
+			salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.Decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.Decode("0D74DB42A91077DE")),
+					set6v0_0, set6v0_65472, set6v0_65536);
+			salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.Decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.Decode("167DE44BB21980E7")),
+					set6v1_0, set6v1_65472, set6v1_65536);
+			reinitBug();
+		}
+
+		private void salsa20Test1(
+			int rounds,
+			ICipherParameters	parameters,
+			string				v0,
+			string				v192,
+			string				v256,
+			string				v448)
+		{
+			IStreamCipher salsa = new Salsa20Engine(rounds);
+			byte[]       buf = new byte[64];
+
+			salsa.Init(true, parameters);
+
+			for (int i = 0; i != 7; i++)
+			{
+				salsa.ProcessBytes(zeroes, 0, 64, buf, 0);
+				switch (i)
+				{
+				case 0:
+					if (!AreEqual(buf, Hex.Decode(v0)))
+					{
+						mismatch("v0/" + rounds, v0, buf);
+					}
+					break;
+				case 3:
+					if (!AreEqual(buf, Hex.Decode(v192)))
+					{
+						mismatch("v192/" + rounds, v192, buf);
+					}
+					break;
+				case 4:
+					if (!AreEqual(buf, Hex.Decode(v256)))
+					{
+						mismatch("v256/" + rounds, v256, buf);
+					}
+					break;
+				default:
+					// ignore
+					break;
+				}
+			}
+
+			for (int i = 0; i != 64; i++)
+			{
+				buf[i] = salsa.ReturnByte(zeroes[i]);
+			}
+
+			if (!AreEqual(buf, Hex.Decode(v448)))
+			{
+				mismatch("v448", v448, buf);
+			}       
+		}
+
+		private void salsa20Test2(
+			ICipherParameters	parameters,
+			string				v0,
+			string				v65472,
+			string				v65536)
+		{
+			IStreamCipher salsa = new Salsa20Engine();
+			byte[]       buf = new byte[64];
+
+			salsa.Init(true, parameters);
+
+			for (int i = 0; i != 1025; i++)
+			{
+				salsa.ProcessBytes(zeroes, 0, 64, buf, 0);
+				switch (i)
+				{
+				case 0:
+					if (!AreEqual(buf, Hex.Decode(v0)))
+					{
+						mismatch("v0", v0, buf);
+					}
+					break;
+				case 1023:
+					if (!AreEqual(buf, Hex.Decode(v65472)))
+					{
+						mismatch("v65472", v65472, buf);
+					}
+					break;
+				case 1024:
+					if (!AreEqual(buf, Hex.Decode(v65536)))
+					{
+						mismatch("v65536", v65536, buf);
+					}
+					break;
+				default:
+					// ignore
+					break;
+				}
+			}
+		}
+
+		private void mismatch(
+			string	name,
+			string	expected,
+			byte[]	found)
+		{
+			Fail("mismatch on " + name, expected, Hex.ToHexString(found));
+		}
+
+		private void reinitBug()
+		{
+			KeyParameter key = new KeyParameter(Hex.Decode("80000000000000000000000000000000"));
+			ParametersWithIV parameters = new ParametersWithIV(key, Hex.Decode("0000000000000000"));
+
+			IStreamCipher salsa = new Salsa20Engine();
+
+			salsa.Init(true, parameters);
+
+			try
+			{
+				salsa.Init(true, key);
+				Fail("Salsa20 should throw exception if no IV in Init");
+			}
+			catch (ArgumentException)
+			{
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Salsa20Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/SerpentTest.cs b/crypto/test/src/crypto/test/SerpentTest.cs
new file mode 100644
index 000000000..2467797e9
--- /dev/null
+++ b/crypto/test/src/crypto/test/SerpentTest.cs
@@ -0,0 +1,119 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class SerpentTest: CipherTest
+    {
+        static SimpleTest[]  tests =
+        {
+            new BlockCipherVectorTest(0, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+                "00000000000000000000000000000000", "8910494504181950f98dd998a82b6749"),
+            new BlockCipherVectorTest(1, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+                "80000000000000000000000000000000", "10b5ffb720b8cb9002a1142b0ba2e94a"),
+            new BlockCipherVectorTest(2, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+                "00000000008000000000000000000000", "4f057a42d8d5bd9746e434680ddcd5e5"),
+            new BlockCipherVectorTest(3, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+                "00000000000000000000400000000000", "99407bf8582ef12550886ef5b6f169b9"),
+            new BlockCipherVectorTest(4, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+                "40000000000000000000000000000000", "d522a3b8d6d89d4d2a124fdd88f36896"),
+            new BlockCipherVectorTest(5, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+                "00000000000200000000000000000000", "189b8ec3470085b3da97e82ca8964e32"),
+            new BlockCipherVectorTest(6, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("000000000000000000000000000000000000000000000000")),
+                "00000000000000000000008000000000", "f77d868cf760b9143a89809510ccb099"),
+            new BlockCipherVectorTest(7, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+                "08000000000000000000000000000000", "d43b7b981b829342fce0e3ec6f5f4c82"),
+            new BlockCipherVectorTest(8, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+                "00000000000000000100000000000000", "0bf30e1a0c33ccf6d5293177886912a7"),
+            new BlockCipherVectorTest(9, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000000000000")),
+                "00000000000000000000000000000001", "6a7f3b805d2ddcba49b89770ade5e507"),
+            new BlockCipherVectorTest(10, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("80000000000000000000000000000000")),
+                "00000000000000000000000000000000", "49afbfad9d5a34052cd8ffa5986bd2dd"),
+            new BlockCipherVectorTest(11, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("000000000000000000000000004000000000000000000000")),
+                "00000000000000000000000000000000", "ba8829b1de058c4b48615d851fc74f17"),
+            new BlockCipherVectorTest(12, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("0000000000000000000000000000000000000000000000000000000100000000")),
+                "00000000000000000000000000000000", "89f64377bf1e8a46c8247044e8056a98"),
+/*
+            new BlockCipherMonteCarloTest(13, 10000, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("47f5f881daab9b67b43bd1342e339c19")),
+                "7a4f7db38c52a8b711b778a38d203b6b", "003380e19f10065740394f48e2fe80b7"),
+*/
+            new BlockCipherMonteCarloTest(13, 100, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("47f5f881daab9b67b43bd1342e339c19")),
+                "7a4f7db38c52a8b711b778a38d203b6b", "4db75303d815c2f7cc6ca935d1c5a046"),
+/*
+            new BlockCipherMonteCarloTest(14, 10000, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("31fba879ebc5e80df35e6fa33eaf92d6")),
+                "70a05e12f74589009692a337f53ff614", "afb5425426906db26b70bdf842ac5400"),
+*/
+            new BlockCipherMonteCarloTest(14, 100, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("31fba879ebc5e80df35e6fa33eaf92d6")),
+                "70a05e12f74589009692a337f53ff614", "fc53a50f4d3bc9836001893d2f41742d"),
+/*
+            new BlockCipherMonteCarloTest(15, 10000, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("bde6dd392307984695aee80e574f9977caae9aa78eda53e8")),
+                "9cc523d034a93740a0aa4e2054bb34d8", "1949d506ada7de1f1344986e8ea049b2"),
+*/
+            new BlockCipherMonteCarloTest(15, 100, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("bde6dd392307984695aee80e574f9977caae9aa78eda53e8")),
+                "9cc523d034a93740a0aa4e2054bb34d8", "77117e6a9e80f40b2a36b7d755573c2d"),
+/*
+            new BlockCipherMonteCarloTest(16, 10000, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("60f6f8ad4290699dc50921a1bbcca92da914e7d9cf01a9317c79c0af8f2487a1")),
+                "ee1a61106fae2d381d686cbf854bab65", "e57f45559027cb1f2ed9603d814e1c34"),
+*/
+            new BlockCipherMonteCarloTest(16, 100, new SerpentEngine(),
+                new KeyParameter(Hex.Decode("60f6f8ad4290699dc50921a1bbcca92da914e7d9cf01a9317c79c0af8f2487a1")),
+                "ee1a61106fae2d381d686cbf854bab65", "dcd7f13ea0dcdfd0139d1a42e2ffb84b")
+        };
+
+		public SerpentTest()
+			: base(tests, new SerpentEngine(), new KeyParameter(new byte[32]))
+		{
+		}
+
+		public override string Name
+        {
+			get { return "Serpent"; }
+        }
+
+		public static void Main(
+	        string[] args)
+        {
+            ITest test = new SerpentTest();
+            ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/ShortenedDigestTest.cs b/crypto/test/src/crypto/test/ShortenedDigestTest.cs
new file mode 100644
index 000000000..4956b5b39
--- /dev/null
+++ b/crypto/test/src/crypto/test/ShortenedDigestTest.cs
@@ -0,0 +1,98 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class ShortenedDigestTest : SimpleTest
+	{
+		public override void PerformTest()
+		{
+			IDigest  d = new Sha1Digest();
+			ShortenedDigest sd = new ShortenedDigest(new Sha1Digest(), 10);
+
+			if (sd.GetDigestSize() != 10)
+			{
+				Fail("size check wrong for SHA-1");
+			}
+
+			if (sd.GetByteLength() != d.GetByteLength())
+			{
+				Fail("byte length check wrong for SHA-1");
+			}
+
+			//
+			// check output fits
+			//
+			sd.DoFinal(new byte[10], 0);
+
+			d = new Sha512Digest();
+			sd = new ShortenedDigest(new Sha512Digest(), 20);
+
+			if (sd.GetDigestSize() != 20)
+			{
+				Fail("size check wrong for SHA-512");
+			}
+
+			if (sd.GetByteLength() != d.GetByteLength())
+			{
+				Fail("byte length check wrong for SHA-512");
+			}
+
+			//
+			// check output fits
+			//
+			sd.DoFinal(new byte[20], 0);
+
+			try
+			{
+				new ShortenedDigest(null, 20);
+
+				Fail("null parameter not caught");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+
+			try
+			{
+				new ShortenedDigest(new Sha1Digest(), 50);
+
+				Fail("short digest not caught");
+			}
+			catch (ArgumentException)
+			{
+				// expected
+			}
+		}
+
+		public override string Name
+		{
+			get { return "ShortenedDigest"; }
+		}
+
+		public static void Main(
+			string[]    args)
+		{
+			RunTest(new ShortenedDigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/SipHashTest.cs b/crypto/test/src/crypto/test/SipHashTest.cs
new file mode 100644
index 000000000..82dfce82c
--- /dev/null
+++ b/crypto/test/src/crypto/test/SipHashTest.cs
@@ -0,0 +1,156 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /// <summary>
+    /// SipHash test values from "SipHash: a fast short-input PRF", by Jean-Philippe
+    /// Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf), Appendix A.
+    /// </summary>
+    [TestFixture]
+    public class SipHashTest
+        : SimpleTest
+    {
+        private const int UPDATE_BYTES = 0;
+        private const int UPDATE_FULL = 1;
+        private const int UPDATE_MIX = 2;
+
+        public override string Name
+        {
+            get { return "SipHash"; }
+        }
+
+        public override void PerformTest()
+        {
+            byte[] key = Hex.Decode("000102030405060708090a0b0c0d0e0f");
+            byte[] input = Hex.Decode("000102030405060708090a0b0c0d0e");
+
+            RunMac(key, input, UPDATE_BYTES);
+            RunMac(key, input, UPDATE_FULL);
+            RunMac(key, input, UPDATE_MIX);
+
+            SecureRandom random = new SecureRandom();
+            for (int i = 0; i < 100; ++i)
+            {
+                RandomTest(random);
+            }
+        }
+
+        private void RunMac(byte[] key, byte[] input, int updateType)
+        {
+            long expected = unchecked((long)0xa129ca6149be45e5);
+
+            SipHash mac = new SipHash();
+            mac.Init(new KeyParameter(key));
+
+            UpdateMac(mac, input, updateType);
+
+            long result = mac.DoFinal();
+            if (expected != result)
+            {
+                Fail("Result does not match expected value for DoFinal()");
+            }
+
+            // NOTE: Little-endian representation of 0xa129ca6149be45e5
+            byte[] expectedBytes = Hex.Decode("e545be4961ca29a1");
+
+            UpdateMac(mac, input, updateType);
+
+            byte[] output = new byte[mac.GetMacSize()];
+            int len = mac.DoFinal(output, 0);
+            if (len != output.Length)
+            {
+                Fail("Result length does not equal GetMacSize() for DoFinal(byte[],int)");
+            }
+            if (!AreEqual(expectedBytes, output))
+            {
+                Fail("Result does not match expected value for DoFinal(byte[],int)");
+            }
+        }
+
+        private void RandomTest(SecureRandom random)
+        {
+            byte[] key = new byte[16];
+            random.NextBytes(key);
+
+            int length = 1 + random.Next(1024);
+            byte[] input = new byte[length];
+            random.NextBytes(input);
+
+            SipHash mac = new SipHash();
+            mac.Init(new KeyParameter(key));
+
+            UpdateMac(mac, input, UPDATE_BYTES);
+            long result1 = mac.DoFinal();
+
+            UpdateMac(mac, input, UPDATE_FULL);
+            long result2 = mac.DoFinal();
+
+            UpdateMac(mac, input, UPDATE_MIX);
+            long result3 = mac.DoFinal();
+
+            if (result1 != result2 || result1 != result3)
+            {
+                Fail("Inconsistent results in random test");
+            }
+        }
+
+        private void UpdateMac(SipHash mac, byte[] input, int updateType)
+        {
+            switch (updateType)
+            {
+            case UPDATE_BYTES:
+            {
+                for (int i = 0; i < input.Length; ++i)
+                {
+                    mac.Update(input[i]);
+                }
+                break;
+            }
+            case UPDATE_FULL:
+            {
+                mac.BlockUpdate(input, 0, input.Length);
+                break;
+            }
+            case UPDATE_MIX:
+            {
+                int step = System.Math.Max(1, input.Length / 3);
+                int pos = 0;
+                while (pos < input.Length)
+                {
+                    mac.Update(input[pos++]);
+                    int len = System.Math.Min(input.Length - pos, step);
+                    mac.BlockUpdate(input, pos, len);
+                    pos += len;
+                }
+                break;
+            }
+            default:
+                throw new InvalidOperationException();
+            }
+        }
+
+        public static void Main(string[] args)
+        {
+            RunTest(new SipHashTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/SkeinDigestTest.cs b/crypto/test/src/crypto/test/SkeinDigestTest.cs
new file mode 100644
index 000000000..b6f1c542b
--- /dev/null
+++ b/crypto/test/src/crypto/test/SkeinDigestTest.cs
@@ -0,0 +1,303 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+	[TestFixture]
+	public class SkeinDigestTest
+		: SimpleTest
+	{
+		private class Case
+		{
+			private byte[] message;
+			private byte[] digest;
+			private int blockSize;
+			private int outputSize;
+
+			public Case(int blockSize, int outputSize, string message, string digest)
+			{
+				this.blockSize = blockSize;
+				this.outputSize = outputSize;
+				this.message = Hex.Decode(message);
+				this.digest = Hex.Decode(digest);
+			}
+
+			public int getOutputSize()
+			{
+				return outputSize;
+			}
+
+			public int getBlockSize()
+			{
+				return blockSize;
+			}
+
+			public byte[] getMessage()
+			{
+				return message;
+			}
+
+			public byte[] getDigest()
+			{
+				return digest;
+			}
+
+		}
+
+		// Test cases from skein_golden_kat.txt and skein_golden_kat_short.txt in Skein 1.3 NIST CD
+		private static readonly Case[] TEST_CASES = {
+			new Case(256, 256, "", "c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba"),
+			new Case(256, 256, "fb", "088eb23cc2bccfb8171aa64e966d4af937325167dfcd170700ffd21f8a4cbdac"),
+			new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8",
+			         "5c3002ff57a627089ea2f97a5000d5678416389019e80e45a3bbcab118315d26"),
+			new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a129233",
+			         "640c894a4bba6574c83e920ddf7dd2982fc634881bbbcb9d774eae0a285e89ce"),
+			new Case(256, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "0cd491b7715704c3a15a45a1ca8d93f8f646d3a1"),
+			new Case(256, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "afd1e2d0f5b6cd4e1f8b3935fa2497d27ee97e72060adac099543487"),
+			new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "4de6fe2bfdaa3717a4261030ef0e044ced9225d066354610842a24a3eafd1dcf"),
+			new Case(256, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "954620fb31e8b782a2794c6542827026fe069d715df04261629fcbe81d7d529b"
+			         + "95ba021fa4239fb00afaa75f5fd8e78b"),
+			new Case(256, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "51347e27c7eabba514959f899a6715ef6ad5cf01c23170590e6a8af399470bf9"
+			         + "0ea7409960a708c1dbaa90e86389df254abc763639bb8cdf7fb663b29d9557c3"),
+			new Case(256, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "6c9b6facbaf116b538aa655e0be0168084aa9f1be445f7e06714585e5999a6c9"
+			         + "84fffa9d41a316028692d4aad18f573fbf27cf78e84de26da1928382b023987d"
+			         + "cfe002b6201ea33713c54a8a5d9eb346f0365e04330d2faaf7bc8aba92a5d7fb"
+			         + "6345c6fb26750bce65ab2045c233627679ac6e9acb33602e26fe3526063ecc8b"),
+
+			new Case(512, 512, "", "bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af4"
+			         + "1fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a"),
+			new Case(512, 512, "fb", "c49e03d50b4b2cc46bd3b7ef7014c8a45b016399fd1714467b7596c86de98240"
+			         + "e35bf7f9772b7d65465cd4cffab14e6bc154c54fc67b8bc340abf08eff572b9e"),
+			new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8",
+			         "abefb179d52f68f86941acbbe014cc67ec66ad78b7ba9508eb1400ee2cbdb06f"
+			         + "9fe7c2a260a0272d0d80e8ef5e8737c0c6a5f1c02ceb00fb2746f664b85fcef5"),
+			new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a129233",
+			         "5c5b7956f9d973c0989aa40a71aa9c48a65af2757590e9a758343c7e23ea2df4"
+			         + "057ce0b49f9514987feff97f648e1dd065926e2c371a0211ca977c213f14149f"),
+			new Case(512, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "ef03079d61b57c6047e15fa2b35b46fa24279539"),
+			new Case(512, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "d9e3219b214e15246a2038f76a573e018ef69b385b3bd0576b558231"),
+			new Case(512, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "809dd3f763a11af90912bbb92bc0d94361cbadab10142992000c88b4ceb88648"),
+			new Case(512, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "825f5cbd5da8807a7b4d3e7bd9cd089ca3a256bcc064cd73a9355bf3ae67f2bf"
+			         + "93ac7074b3b19907a0665ba3a878b262"),
+			new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "1a0d5abf4432e7c612d658f8dcfa35b0d1ab68b8d6bd4dd115c23cc57b5c5bcd"
+			         + "de9bff0ece4208596e499f211bc07594d0cb6f3c12b0e110174b2a9b4b2cb6a9"),
+
+			new Case(1024, 1024, "", "0fff9563bb3279289227ac77d319b6fff8d7e9f09da1247b72a0a265cd6d2a62"
+			         + "645ad547ed8193db48cff847c06494a03f55666d3b47eb4c20456c9373c86297"
+			         + "d630d5578ebd34cb40991578f9f52b18003efa35d3da6553ff35db91b81ab890"
+			         + "bec1b189b7f52cb2a783ebb7d823d725b0b4a71f6824e88f68f982eefc6d19c6"),
+			new Case(1024, 1024, "fb", "6426bdc57b2771a6ef1b0dd39f8096a9a07554565743ac3de851d28258fcff22"
+			         + "9993e11c4e6bebc8b6ecb0ad1b140276081aa390ec3875960336119427827473"
+			         + "4770671b79f076771e2cfdaaf5adc9b10cbae43d8e6cd2b1c1f5d6c82dc96618"
+			         + "00ddc476f25865b8748253173187d81da971c027d91d32fb390301c2110d2db2"),
+			new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8",
+			         "140e93726ab0b0467c0b8a834ad8cda4d1769d273661902b70db0dcb5ee692ac"
+			         + "b3f852d03b11f857850f2428432811309c1dcbe5724f00267ea3667e89fadb4e"
+			         + "4911da6b0ba8a7eddf87c1c67152ef0f07b7fead3557318478bdef5ad1e5926d"
+			         + "7071fdd4bfa5076d4b3253f8de479ebdf5357676f1641b2f097e9b785e9e528e"),
+			new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a129233",
+			         "31105e1ef042c30b95b16e0f6e6a1a19172bb7d54a0597dd0c711194888efe1d"
+			         + "bce82d47416df9577ca387219f06e45cd10964ff36f6711edbbea0e9595b0f66"
+			         + "f72b755d70a46857e0aec98561a743d49370d8e572e212811273125f66cc30bf"
+			         + "117d3221894c48012bf6e2219de91e064b01523517420a1e00f71c4cc04bab62"),
+			new Case(1024, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "2e6a4cbf2ef05ea9c24b93e8d1de732ddf2739eb"),
+			new Case(1024, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "1d6de19f37f7a3c265440eecb4b9fbd3300bb5ac60895cfc0d4d3c72"),
+			new Case(1024, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "986a4d472b123e8148731a8eac9db23325f0058c4ccbc44a5bb6fe3a8db672d7"),
+			new Case(1024, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "9c3d0648c11f31c18395d5e6c8ebd73f43d189843fc45235e2c35e345e12d62b"
+			         + "c21a41f65896ddc6a04969654c2e2ce9"),
+			new Case(1024, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "5d0416f49c2d08dfd40a1446169dc6a1d516e23b8b853be4933513051de8d5c2"
+			         + "6baccffb08d3b16516ba3c6ccf3e9a6c78fff6ef955f2dbc56e1459a7cdba9a5"),
+			new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8"
+			         + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb"
+			         + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a"
+			         + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410",
+			         "96ca81f586c825d0360aef5acaec49ad55289e1797072eee198b64f349ce65b6"
+			         + "e6ed804fe38f05135fe769cc56240ddda5098f620865ce4a4278c77fa2ec6bc3"
+			         + "1c0f354ca78c7ca81665bfcc5dc54258c3b8310ed421d9157f36c093814d9b25"
+			         + "103d83e0ddd89c52d0050e13a64c6140e6388431961685734b1f138fe2243086"),
+
+		};
+
+		public override string Name
+		{
+			get { return "SkeinDigest"; }
+		}
+
+		public override void PerformTest()
+		{
+			for (int i = 0; i < TEST_CASES.Length; i++)
+			{
+				Case test = TEST_CASES[i];
+				runTest(test);
+			}
+		}
+
+		private void runTest(Case dc)
+		{
+			SkeinDigest digest = new SkeinDigest(dc.getBlockSize(), dc.getOutputSize());
+
+			byte[] message = dc.getMessage();
+			digest.BlockUpdate(message, 0, message.Length);
+
+			byte[] output = new byte[digest.GetDigestSize()];
+			digest.DoFinal(output, 0);
+
+			if (!AreEqual(output, dc.getDigest()))
+			{
+				Fail(digest.AlgorithmName + " message mismatch.\n Message " + Hex.ToHexString(dc.getMessage()),
+				     Hex.ToHexString(dc.getDigest()), Hex.ToHexString(output));
+			}
+
+			// Clone test
+			digest.BlockUpdate(message, 0, message.Length / 2);
+
+			// clone the Digest
+			IDigest d = new SkeinDigest(digest);
+
+			digest.BlockUpdate(message, message.Length / 2, message.Length - message.Length / 2);
+			digest.DoFinal(output, 0);
+
+			if (!AreEqual(dc.getDigest(), output))
+			{
+				Fail("failing clone vector test", Hex.ToHexString(dc.getDigest()), Hex.ToHexString(output));
+			}
+
+			d.BlockUpdate(message, message.Length / 2, message.Length - message.Length / 2);
+			d.DoFinal(output, 0);
+
+			if (!AreEqual(dc.getDigest(), output))
+			{
+				Fail("failing second clone vector test", Hex.ToHexString(dc.getDigest()), Hex.ToHexString(output));
+			}
+
+			//	        //
+			//	        // memo test
+			//	        //
+			//	        Memoable m = (Memoable)digest;
+			//
+			//	        digest.Update(message, 0, message.Length / 2);
+			//
+			//	        // copy the Digest
+			//	        Memoable copy1 = m.copy();
+			//	        Memoable copy2 = copy1.copy();
+			//
+			//	        digest.Update(message, message.Length / 2, message.Length - message.Length / 2);
+			//	        digest.DoFinal(output, 0);
+			//
+			//	        if (!AreEqual(dc.getDigest(), output))
+			//	        {
+			//				Fail("failing memo vector test", Hex.ToHexString(dc.getDigest()), Hex.ToHexString(output));
+			//	        }
+			//
+			//	        m.reset(copy1);
+			//
+			//	        digest.Update(message, message.Length / 2, message.Length - message.Length / 2);
+			//	        digest.DoFinal(output, 0);
+			//
+			//	        if (!AreEqual(dc.getDigest(), output))
+			//	        {
+			//				fail("failing memo reset vector test", Hex.ToHexString(dc.getDigest()), Hex.ToHexString(output));
+			//	        }
+			//
+			//	        IDigest md = (IDigest)copy2;
+			//
+			//	        md.Update(message, message.Length / 2, message.Length - message.Length / 2);
+			//	        md.DoFinal(output, 0);
+			//
+			//	        if (!AreEqual(dc.getDigest(), output))
+			//	        {
+			//				Fail("failing memo copy vector test", Hex.ToHexString(dc.getDigest()), Hex.ToHexString(output));
+			//	        }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SkeinDigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/SkeinMacTest.cs b/crypto/test/src/crypto/test/SkeinMacTest.cs
new file mode 100644
index 000000000..852c3b2c7
--- /dev/null
+++ b/crypto/test/src/crypto/test/SkeinMacTest.cs
@@ -0,0 +1,174 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+	[TestFixture]
+	public class SkeinMacTest
+		: SimpleTest
+	{
+		private class Case
+		{
+			private byte[] message;
+			private byte[] digest;
+			private byte[] key;
+			private int blockSize;
+			private int outputSize;
+
+			public Case(int blockSize, int outputSize, String message, String key, String digest)
+			{
+				this.blockSize = blockSize;
+				this.outputSize = outputSize;
+				this.message = Hex.Decode(message);
+				this.key = Hex.Decode(key);
+				this.digest = Hex.Decode(digest);
+			}
+
+			public int getOutputSize()
+			{
+				return outputSize;
+			}
+
+			public int getBlockSize()
+			{
+				return blockSize;
+			}
+
+			public byte[] getMessage()
+			{
+				return message;
+			}
+
+			public byte[] getKey()
+			{
+				return key;
+			}
+
+			public byte[] getDigest()
+			{
+				return digest;
+			}
+
+			public override string ToString()
+			{
+				return String.Format("new Case({0}, {1}, \"{2}\", \"{3}\", \"{4}\"),", blockSize, outputSize,
+				                     Hex.ToHexString(message), Hex.ToHexString(key), Hex.ToHexString(digest));
+			}
+
+		}
+
+		// Test cases from skein_golden_kat.txt in Skein 1.3 NIST CD
+		// Excludes empty '(none)' key 'random+MAC' tests, which are in effect digest 
+		private static readonly Case[] TEST_CASES = {
+			new Case(256, 256, "", "cb41f1706cde09651203c2d0efbaddf8", "886e4efefc15f06aa298963971d7a25398fffe5681c84db39bd00851f64ae29d"),
+			new Case(256, 256, "d3", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "979422a94e3afaa46664124d4e5e8b9422b1d8baf11c6ae6725992ac72a112ca"),
+			new Case(256, 256, "d3090c72", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "1d658372cbea2f9928493cc47599d6f4ad8ce33536bedfa20b739f07516519d5"),
+			new Case(256, 256, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "41ef6b0f0fad81c040284f3b1a91e9c44e4c26a6d7207f3aac4362856ef12aca"),
+			new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "ca8208119b9e4e4057631ab31015cfd256f6763a0a34381633d97f640899b84f"),
+			new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "9e9980fcc16ee082cf164a5147d0e0692aeffe3dcb8d620e2bb542091162e2e9"),
+			new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc235", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "c353a316558ec34f8245dd2f9c2c4961fbc7decc3b69053c103e4b8aaaf20394"),
+			new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf8", "b1b8c18188e69a6ecae0b6018e6b638c6a91e6de6881e32a60858468c17b520d"),
+			new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "1dfd2515a412e78852cd81a7f2167711b4ca19b2891c2ea36ba94f8451944793"),
+			new Case(256, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf8", "a097340709b443ed2c0a921f5dcefef3ead65c4f0bcd5f13da54d7ed"),
+			new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "ac1b4fab6561c92d0c487e082daec53e0db4f505e08bf51cae4fd5375e37fc04"),
+			new Case(256, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "96e6cebb23573d0a70ce36a67aa05d2403148093f25c695e1254887cc97f9771d2518413af4286bf2a06b61a53f7fcec"),
+			new Case(256, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "0e95e597e71d6350f20b99c4179f54f43a4722705c06ba765a82cb0a314fe2fe87ef8090063b757e53182706ed18737dadc0da1e1c66518f08334052702c5ed7"),
+			new Case(256, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf8", "064abd4896f460b1953f5a357e7f7c5256e29cdb62b8740d0b52295cfa2ef4c7a2"),
+			new Case(256, 520, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "edf220e43e048603bd16197d59b673b9974de5b8bcf7cb1558a4799f6fd3743eb5fb400cd6129afc0c60e7b741b7e5806f0e0b93eb8429fbc7efa222175a9c80fd"),
+			new Case(256, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "f3f59fb07399c7b73aae02a8590883cb2fdfde75c55654e71846522301bde48d267169adcc559e038e8c2f28faa552b550d51874055384adea93c036c71a1f0af0c7bcc3bc923738d5307b9da7cb423d4e615c629c4aba71f70d4c9d1fa008176825e51bfa0203445a4083947ec19f6a0fbd082b5b970f2396fb67420639410447"),
+			new Case(256, 2056, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "80eb80d9b8836b32fa576fc84ba08edfbdfd6979123d61914e610a70a372b37f560a10909484f9f4a377c93e29ba681dfe522c41dc83b5ee0567e5370007c7bbe4df0b2b4a25e088f80d72fc30734cdcd76d817b42fbd44dca881019afb25306f19d4e91848778af306517d2072cef72caa327e877c5b6554f83cec3d00877131b47c4d3b557f5a13541c4d5080ee3ce7a658993d083efd0db3496a8752060c3c8552f44b290cabdcc867f691ad605836c08dbd59c9528d885b600b85fdfc8a9d0e636ac3ad8b4295bcb0169e78dc358e77eacc8c4b61bddfa9e5f32d2268a006cfe05c57150fe8e68cabd21cf6cf6035aa1fe4db36c922b765aad0b64e82a2c37"),
+			new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed696e6c9db1e6abea026288954a9c2d5758d7c5db7c9e48aa3d21cae3d977a7c3926066aa393dbd538dd0c30da8916c8757f24c18488014668a2627163a37b261833dc2f8c3c56b1b2e0be21fd3fbdb507b2950b77a6cc02efb393e57419383a920767bca2c972107aa61384542d47cbfb82cfe5c415389d1b0a2d74e2c5da851", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "8f88de68f03cd2f396ccdd49c3a0f4ff15bcda7eb357da9753f6116b124de91d"),
+			new Case(512, 512, "", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "9bd43d2a2fcfa92becb9f69faab3936978f1b865b7e44338fc9c8f16aba949ba340291082834a1fc5aa81649e13d50cd98641a1d0883062bfe2c16d1faa7e3aa"),
+			new Case(512, 512, "d3", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "f0c0a10f031c8fc69cfabcd54154c318b5d6cd95d06b12cf20264402492211ee010d5cecc2dc37fd772afac0596b2bf71e6020ef2dee7c860628b6e643ed9ff6"),
+			new Case(512, 512, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "0c1f1921253dd8e5c2d4c5f4099f851042d91147892705829161f5fc64d89785226eb6e187068493ee4c78a4b7c0f55a8cbbb1a5982c2daf638fc6a74b16b0d7"),
+			new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "478d7b6c0cc6e35d9ebbdedf39128e5a36585db6222891692d1747d401de34ce3db6fcbab6c968b7f2620f4a844a2903b547775579993736d2493a75ff6752a1"),
+			new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e59", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "13c170bac1de35e5fb843f65fabecf214a54a6e0458a4ff6ea5df91915468f4efcd371effa8965a9e82c5388d84730490dcf3976af157b8baf550655a5a6ab78"),
+			new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc235", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "a947812529a72fd3b8967ec391b298bee891babc8487a1ec4ea3d88f6b2b5be09ac6a780f30f8e8c3bbb4f18bc302a28f3e87d170ba0f858a8fefe3487478cca"),
+			new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "7690ba61f10e0bba312980b0212e6a9a51b0e9aadfde7ca535754a706e042335b29172aae29d8bad18efaf92d43e6406f3098e253f41f2931eda5911dc740352"),
+			new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "d10e3ba81855ac087fbf5a3bc1f99b27d05f98ba22441138026225d34a418b93fd9e8dfaf5120757451adabe050d0eb59d271b0fe1bbf04badbcf9ba25a8791b"),
+			new Case(512, 160, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "5670b226156570dff3efe16661ab86eb24982cdf"),
+			new Case(512, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "c41b9ff9753e6c0f8ed88866e320535e927fe4da552c289841a920db"),
+			new Case(512, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "dfbf5c1319a1d9d70efb2f1600fbcf694f935907f31d24a16d6cd2fb2d7855a769681766c0a29da778eed346cd1d740f"),
+			new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "04d8cddb0ad931d54d195899a094684344e902286037272890bce98a41813edc37a3cee190a693fcca613ee30049ce7ec2bdff9613f56778a13f8c28a21d167a"),
+			new Case(512, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "08fca368b3b14ac406676adf37ac9be2dbb8704e694055a0c6331184d4f0070098f23f0963ee29002495771bf56fb4d3d9ff3506abcd80be927379f7880d5d7703919fbf92184f498ac44f47f015ce676eded9165d47d53733f5a27abbc05f45acd98b97cc15ffdced641defd1a5119ef841b452a1b8f94ee69004466ccdc143"),
+			new Case(512, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "669e770ebe7eacc2b64caaf049923ad297a5b37cfa61c283392d81ccfcb9bbbc09"),
+			new Case(512, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "acc2e03f07f33e9820a6038421089429adcd6a7a83f733beec048c05bf37531a170a5537fcb565c348a70a83217f8be768ff6f95fd2b3d89cb7d8a3dc849505e3710eb4e65a8e7134bbf580d92fe18c9aa987563669b1f014aa5e092519089355534eaa9f0bdc99f6839f54080ffe74623254c906ecb8896b4346c3178a0bc2898"),
+			new Case(512, 2056, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "9f3e082223c43090a4a3ffbdcd469cbabfe0c1399d1edf45a5dfc18f4db5428928a76e979b8d0d5dffec0e6a59ada448c1ffbc06cc80a2006f002adc0c6dbf458563762228dce4381944e460ebebfe06f1237093634625107469a22a189a47f8b025899265d8890a1b39df64552394377e88ba2ad44a8c8d174f884ac8c3ae24ddb0affca5fceb6aa76e09706881e8371774b9b050a69b96ef5e97e81043f8b7e9479e287ab441bacd62caf768a82c8c3e3107be70eb8799a39856fe29842a04e25de0ef9de1b7e65bd0f1f7306835287fc957388e2035b7d22d3aa9c06a9fefbca16f3f60e1c4def89038d918942152a069aa2e0be8ae7475d859031adec84583"),
+			new Case(1024, 1024, "", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "bcf37b3459c88959d6b6b58b2bfe142cef60c6f4ec56b0702480d7893a2b0595aa354e87102a788b61996b9cbc1eade7dafbf6581135572c09666d844c90f066b800fc4f5fd1737644894ef7d588afc5c38f5d920bdbd3b738aea3a3267d161ed65284d1f57da73b68817e17e381ca169115152b869c66b812bb9a84275303f0"),
+			new Case(1024, 1024, "d3090c72", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "df0596e5808835a3e304aa27923db05f61dac57c0696a1d19abf188e70aa9dbcc659e9510f7c9a37fbc025bd4e5ea293e78ed7838dd0b08864e8ad40ddb3a88031ebefc21572a89960d1916107a7da7ac0c067e34ec46a86a29ca63fa250bd398eb32ec1ed0f8ac8329f26da018b029e41e2e58d1dfc44de81615e6c987ed9c9"),
+			new Case(1024, 1024, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "3cfbb79cd88af8ee09c7670bcbab6907a31f80fa31d9d7c9d50826c9568f307a78bd254961398c76b6e338fd9ca5f351059350d30963c3320659b223b991fc46d1307686fe2b4763d9f593c57ad5adbc45caf2ea3dc6090f5a74fa5fa6d9e9838964ea0a2aa216831ab069b00629a1a9b037083403bdb25d3d06a21c430c87dd"),
+			new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e59", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "0a1b960099fc9d653b0fd1f5b6b972fb366907b772cbce5a59b6171d7935506f70c212bd169d68c5cfd8618343611b7eb2e686ff1dc7c03a57e1a55ed10726848161eea903d53b58459be42d95df989c66c2eea4e51cde272c2d8be67bf3bca2aee633777eb8486781eaa060d0f538abd6c93dbd2d1bf66e6f50bfdcac3725a4"),
+			new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "3e0cd7938d71c39ffbb08a6ba7995ade3ad140e2c0c45cdbafb099247e08e4c20b61c1f885ced5ed2f816680925034918236e5807f0eecf3f27e9cfca36675eb75873efa1fb41f17541dc2f7c2469eaecb35cc7ca58e489804caf56f09fb97c9f689c64ad49c6888f86c483e901bd3d25798b394ef93faf9154900f92f31f433"),
+			new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "7266752f7e9aa04bd7d8a1b16030677de6021301f6a62473c76bae2b98bbf8aad73bd00a4b5035f741caf2317ab80e4e97f5c5bbe8acc0e8b424bcb13c7c6740a985801fba54addde8d4f13f69d2bfc98ae104d46a211145217e51d510ea846cec9581d14fda079f775c8b18d66cb31bf7060996ee8a69eee7f107909ce59a97"),
+			new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "71f40bf2aa635125ef83c8df0d4e9ea18b73b56be4f45e89b910a7c68d396b65b09d18abc7d1b6de3f53fd5de583e6f22e612dd17b292068af6027daaf8b4cd60acf5bc85044741e9f7a1f423f5827f5e360930a2e71912239af9fc6343604fdcf3f3569854f2bb8d25a81e3b3f5261a02fe8292aaaa50c324101ab2c7a2f349"),
+			new Case(1024, 160, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "17c3c533b27d666da556ae586e641b7a3a0bcc45"),
+			new Case(1024, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "6625df9801581009125ea4e5c94ad6f1a2d692c278822ccb6eb67235"),
+			new Case(1024, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "6c5b671c1766f6eecea6d24b641d4a6bf84bba13a1976f8f80b3f30ee2f93de6"),
+			new Case(1024, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "98af454d7fa3706dfaafbf58c3f9944868b57f68f493987347a69fce19865febba0407a16b4e82065035651f0b1e0327"),
+			new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "211ac479e9961141da3aac19d320a1dbbbfad55d2dce87e6a345fcd58e36827597378432b482d89bad44dddb13e6ad86e0ee1e0882b4eb0cd6a181e9685e18dd302ebb3aa74502c06254dcadfb2bd45d288f82366b7afc3bc0f6b1a3c2e8f84d37fbedd07a3f8fcff84faf24c53c11da600aaa118e76cfdcb366d0b3f7729dce"),
+			new Case(1024, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "dc1d253b7cadbdaef18503b1809a7f1d4f8c323b7f6f8ca50b76d3864649ce1c7d"),
+			new Case(1024, 520, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "decd79578d12bf6806530c382230a2c7836429c70cac941179e1dd982938bab91fb6f3638df1cc1ef615ecfc4249e5aca8a73c4c1eebef662a836d0be903b00146"),
+			new Case(1024, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "440fe691e04f1fed8c253d6c4670646156f33fffaea702de9445df5739eb960cecf85d56e2e6860a610211a5c909932ab774b978aa0b0d5bbce82775172ab12dceddd51d1eb030057ce61bea6c18f6bb368d26ae76a9e44a962eb132e6c42c25d9fecc4f13348300ca55c78e0990de96c1ae24eb3ee3324782c93dd628260a2c8d"),
+			new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed696e6c9db1e6abea026288954a9c2d5758d7c5db7c9e48aa3d21cae3d977a7c3926066aa393dbd538dd0c30da8916c8757f24c18488014668a2627163a37b261833dc2f8c3c56b1b2e0be21fd3fbdb507b2950b77a6cc02efb393e57419383a920767bca2c972107aa61384542d47cbfb82cfe5c415389d1b0a2d74e2c5da851", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "46a42b0d7b8679f8fcea156c072cf9833c468a7d59ac5e5d326957d60dfe1cdfb27eb54c760b9e049fda47f0b847ac68d6b340c02c39d4a18c1bdfece3f405fae8aa848bdbefe3a4c277a095e921228618d3be8bd1999a071682810de748440ad416a97742cc9e8a9b85455b1d76472cf562f525116698d5cd0a35ddf86e7f8a"),
+
+		};
+
+		public override string Name
+		{
+			get { return "SkeinMac"; }
+		}
+
+		public override void PerformTest()
+		{
+			for (int i = 0; i < TEST_CASES.Length; i++)
+			{
+				Case test = TEST_CASES[i];
+				runTest(test);
+			}
+		}
+
+		private void runTest(Case dc)
+		{
+			IMac digest = new SkeinMac(dc.getBlockSize(), dc.getOutputSize());
+			digest.Init(new KeyParameter(dc.getKey()));
+
+			byte[] message = dc.getMessage();
+			digest.BlockUpdate(message, 0, message.Length);
+
+			byte[] output = new byte[digest.GetMacSize()];
+			digest.DoFinal(output, 0);
+
+			if (!AreEqual(output, dc.getDigest()))
+			{
+				Fail(digest.AlgorithmName + " message " + (dc.getMessage().Length * 8) + " mismatch.\n Message  " + Hex.ToHexString(dc.getMessage())
+				     + "\n Key      " + Hex.ToHexString(dc.getKey()) + "\n Expected "
+				     + Hex.ToHexString(dc.getDigest()) + "\n Actual   " + Hex.ToHexString(output));
+			}
+
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SkeinMacTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/SkipjackTest.cs b/crypto/test/src/crypto/test/SkipjackTest.cs
new file mode 100644
index 000000000..d9fe6e4b4
--- /dev/null
+++ b/crypto/test/src/crypto/test/SkipjackTest.cs
@@ -0,0 +1,46 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class SkipjackTest
+		: CipherTest
+    {
+        public override string Name
+        {
+			get { return "SKIPJACK"; }
+        }
+
+        internal static SimpleTest[] tests = new SimpleTest[]{
+            new BlockCipherVectorTest(0, new SkipjackEngine(), new KeyParameter(Hex.Decode("00998877665544332211")), "33221100ddccbbaa", "2587cae27a12d300")};
+
+		public SkipjackTest()
+			: base(tests, new SkipjackEngine(), new KeyParameter(new byte[16]))
+		{
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            ITest test = new SkipjackTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/StreamCipherVectorTest.cs b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
new file mode 100644
index 000000000..ead2f16c3
--- /dev/null
+++ b/crypto/test/src/crypto/test/StreamCipherVectorTest.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    /**
+     * a basic test that takes a stream cipher, key parameter, and an input
+     * and output string.
+     */
+    public class StreamCipherVectorTest: ITest
+    {
+        int                 id;
+        IStreamCipher       cipher;
+        ICipherParameters    param;
+        byte[]              input;
+        byte[]              output;
+
+        public StreamCipherVectorTest(
+            int                 id,
+            IStreamCipher       cipher,
+            ICipherParameters    param,
+            string              input,
+            string              output)
+        {
+            this.id = id;
+            this.cipher = cipher;
+            this.param = param;
+            this.input = Hex.Decode(input);
+            this.output = Hex.Decode(output);
+        }
+
+		public string Name
+		{
+			get { return cipher.AlgorithmName + " Vector Test " + id; }
+		}
+
+		public ITestResult Perform()
+        {
+            cipher.Init(true, param);
+
+            byte[] outBytes = new byte[input.Length];
+
+            cipher.ProcessBytes(input, 0, input.Length, outBytes, 0);
+
+            if (!Arrays.AreEqual(outBytes, output))
+            {
+                return new SimpleTestResult(false, Name + ": failed - "
+					+ "expected " + Hex.ToHexString(output)
+					+ " got " + Hex.ToHexString(outBytes));
+            }
+
+            cipher.Init(false, param);
+
+            cipher.ProcessBytes(output, 0, output.Length, outBytes, 0);
+
+            if (!Arrays.AreEqual(input, outBytes))
+            {
+                return new SimpleTestResult(false, Name + ": failed reversal");
+            }
+
+            return new SimpleTestResult(true, Name + ": OKAY");
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/TEATest.cs b/crypto/test/src/crypto/test/TEATest.cs
new file mode 100644
index 000000000..525941dbf
--- /dev/null
+++ b/crypto/test/src/crypto/test/TEATest.cs
@@ -0,0 +1,59 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* TEA tester - based on C implementation results from http://www.simonshepherd.supanet.com/tea.htm
+	*/
+	[TestFixture]
+	public class TeaTest
+		: CipherTest
+	{
+		private static readonly SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new TeaEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"0000000000000000","41ea3a0a94baa940"),
+			new BlockCipherVectorTest(1, new TeaEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"0102030405060708", "6a2f9cf3fccf3c55"),
+			new BlockCipherVectorTest(2, new TeaEngine(),
+				new KeyParameter(Hex.Decode("0123456712345678234567893456789A")),
+				"0000000000000000", "34e943b0900f5dcb"),
+			new BlockCipherVectorTest(3, new TeaEngine(),
+				new KeyParameter(Hex.Decode("0123456712345678234567893456789A")),
+				"0102030405060708", "773dc179878a81c0"),
+		};
+
+		public TeaTest()
+			: base(tests, new TeaEngine(), new KeyParameter(new byte[16]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "TEA"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new TeaTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/Threefish1024Test.cs b/crypto/test/src/crypto/test/Threefish1024Test.cs
new file mode 100644
index 000000000..64f9aa29f
--- /dev/null
+++ b/crypto/test/src/crypto/test/Threefish1024Test.cs
@@ -0,0 +1,74 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+	[TestFixture]
+	public class Threefish1024Test
+		: CipherTest
+	{
+		// Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD
+		static SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024),
+			                          new TweakableBlockCipherParameters(
+				new KeyParameter(new byte[128]),
+				new byte[16]),
+			                          "0000000000000000000000000000000000000000000000000000000000000000" +
+			                          "0000000000000000000000000000000000000000000000000000000000000000" +
+			                          "0000000000000000000000000000000000000000000000000000000000000000" +
+			                          "0000000000000000000000000000000000000000000000000000000000000000",
+			                          "f05c3d0a3d05b304f785ddc7d1e036015c8aa76e2f217b06c6e1544c0bc1a90d" +
+			                          "f0accb9473c24e0fd54fea68057f43329cb454761d6df5cf7b2e9b3614fbd5a2" +
+			                          "0b2e4760b40603540d82eabc5482c171c832afbe68406bc39500367a592943fa" +
+			                          "9a5b4a43286ca3c4cf46104b443143d560a4b230488311df4feef7e1dfe8391e"),
+			new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024),
+			                          new TweakableBlockCipherParameters(
+				new KeyParameter(Hex.Decode(
+				"101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" +
+				"303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" +
+				"505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f" +
+				"707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f")),
+				Hex.Decode("000102030405060708090a0b0c0d0e0f")),
+			                          "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0" +
+			                          "dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0" +
+			                          "bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a0" +
+			                          "9f9e9d9c9b9a999897969594939291908f8e8d8c8b8a89888786858483828180",
+			                          "a6654ddbd73cc3b05dd777105aa849bce49372eaaffc5568d254771bab85531c" +
+			                          "94f780e7ffaae430d5d8af8c70eebbe1760f3b42b737a89cb363490d670314bd" +
+			                          "8aa41ee63c2e1f45fbd477922f8360b388d6125ea6c7af0ad7056d01796e90c8" +
+			                          "3313f4150a5716b30ed5f569288ae974ce2b4347926fce57de44512177dd7cde")
+		};
+
+		public Threefish1024Test()
+			: base(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), new KeyParameter(new byte[128]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "Threefish-1024"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Threefish1024Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/Threefish256Test.cs b/crypto/test/src/crypto/test/Threefish256Test.cs
new file mode 100644
index 000000000..e44299a31
--- /dev/null
+++ b/crypto/test/src/crypto/test/Threefish256Test.cs
@@ -0,0 +1,59 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+	[TestFixture]
+	public class Threefish256Test
+		: CipherTest
+	{
+		// Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD
+		static SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256),
+			                          new TweakableBlockCipherParameters(
+				new KeyParameter(new byte[32]),
+				new byte[16]),
+			                          "0000000000000000000000000000000000000000000000000000000000000000",
+			                          "84da2a1f8beaee947066ae3e3103f1ad536db1f4a1192495116b9f3ce6133fd8"),
+			new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256),
+			                          new TweakableBlockCipherParameters(
+				new KeyParameter(Hex.Decode(
+				"101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")),
+				Hex.Decode("000102030405060708090a0b0c0d0e0f")),
+			                          "FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0",
+			                          "e0d091ff0eea8fdfc98192e62ed80ad59d865d08588df476657056b5955e97df")
+		};
+
+		public Threefish256Test()
+			: base(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), new KeyParameter(new byte[32]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "Threefish-256"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Threefish256Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/Threefish512Test.cs b/crypto/test/src/crypto/test/Threefish512Test.cs
new file mode 100644
index 000000000..8f4ec6345
--- /dev/null
+++ b/crypto/test/src/crypto/test/Threefish512Test.cs
@@ -0,0 +1,64 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+	[TestFixture]
+	public class Threefish512Test
+		: CipherTest
+	{
+		// Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD
+		static SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512),
+			                          new TweakableBlockCipherParameters(
+				new KeyParameter(new byte[64]),
+				new byte[16]),
+			                          "0000000000000000000000000000000000000000000000000000000000000000" +
+			                          "0000000000000000000000000000000000000000000000000000000000000000",
+			                          "b1a2bbc6ef6025bc40eb3822161f36e375d1bb0aee3186fbd19e47c5d479947b" +
+			                          "7bc2f8586e35f0cff7e7f03084b0b7b1f1ab3961a580a3e97eb41ea14a6d7bbe"),
+			new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512),
+			                          new TweakableBlockCipherParameters(
+				new KeyParameter(Hex.Decode(
+				"101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" +
+				"303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f")),
+				Hex.Decode("000102030405060708090a0b0c0d0e0f")),
+			                          "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0" +
+			                          "dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0",
+			                          "e304439626d45a2cb401cad8d636249a6338330eb06d45dd8b36b90e97254779" +
+			                          "272a0a8d99463504784420ea18c9a725af11dffea10162348927673d5c1caf3d")
+		};
+
+		public Threefish512Test()
+			: base(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), new KeyParameter(new byte[64]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "Threefish-512"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Threefish512Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/crypto/test/TigerDigestTest.cs b/crypto/test/src/crypto/test/TigerDigestTest.cs
new file mode 100644
index 000000000..b351c4b5e
--- /dev/null
+++ b/crypto/test/src/crypto/test/TigerDigestTest.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+    /**
+     * Tiger Digest Test
+     */
+    [TestFixture]
+    public class TigerDigestTest
+        : DigestTest
+    {
+        readonly static string[] messages =
+        {
+            "",
+            "abc",
+            "Tiger",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789",
+            "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.",
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"
+        };
+
+        readonly static string[] digests = {
+            "3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3",
+            "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93",
+            "DD00230799F5009FEC6DEBC838BB6A27DF2B9D6F110C7937",
+            "F71C8583902AFB879EDFE610F82C0D4786A3A534504486B5",
+            "38F41D9D9A710A10C3727AC0DEEAA270727D9F926EC10139",
+            "48CEEB6308B87D46E95D656112CDF18D97915F9765658957",
+            "631ABDD103EB9A3D245B6DFD4D77B257FC7439501D1568DD",
+            "C54034E5B43EB8005848A7E0AE6AAC76E4FF590AE715FD25",
+            "C54034E5B43EB8005848A7E0AE6AAC76E4FF590AE715FD25"
+        };
+
+        readonly static string hash64k = "FDF4F5B35139F48E710E421BE5AF411DE1A8AAC333F26204";
+
+        public TigerDigestTest()
+            : base(new TigerDigest(), messages, digests)
+        {
+        }
+
+        public override void PerformTest()
+        {
+            base.PerformTest();
+
+            sixtyFourKTest(hash64k);
+        }
+
+        protected override IDigest CloneDigest(IDigest digest)
+        {
+            return new TigerDigest((TigerDigest)digest);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new TigerDigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/TwofishTest.cs b/crypto/test/src/crypto/test/TwofishTest.cs
new file mode 100644
index 000000000..9425d2e60
--- /dev/null
+++ b/crypto/test/src/crypto/test/TwofishTest.cs
@@ -0,0 +1,54 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+    [TestFixture]
+    public class TwofishTest
+		: CipherTest
+    {
+        public override string Name
+        {
+			get { return "Twofish"; }
+        }
+
+        internal static string key1 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
+        internal static string key2 = "000102030405060708090a0b0c0d0e0f1011121314151617";
+        internal static string key3 = "000102030405060708090a0b0c0d0e0f";
+
+        internal static string input = "000102030405060708090A0B0C0D0E0F";
+
+        internal static SimpleTest[] tests = new SimpleTest[]{
+            new BlockCipherVectorTest(0, new TwofishEngine(), new KeyParameter(Hex.Decode(key1)), input, "8ef0272c42db838bcf7b07af0ec30f38"),
+            new BlockCipherVectorTest(1, new TwofishEngine(), new KeyParameter(Hex.Decode(key2)), input, "95accc625366547617f8be4373d10cd7"),
+            new BlockCipherVectorTest(2, new TwofishEngine(), new KeyParameter(Hex.Decode(key3)), input, "9fb63337151be9c71306d159ea7afaa4")};
+
+        public TwofishTest()
+			: base(tests, new TwofishEngine(), new KeyParameter(new byte[32]))
+		{
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            ITest test = new TwofishTest();
+            ITestResult result = test.Perform();
+
+            Console.WriteLine(result);
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/test/VMPCKSA3Test.cs b/crypto/test/src/crypto/test/VMPCKSA3Test.cs
new file mode 100644
index 000000000..a25105b77
--- /dev/null
+++ b/crypto/test/src/crypto/test/VMPCKSA3Test.cs
@@ -0,0 +1,112 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* VMPC Test
+	*/
+	[TestFixture]
+	public class VmpcKsa3Test
+		: SimpleTest
+	{
+		private static readonly byte[] input = new byte[1000000];
+
+		public override string Name
+		{
+			get { return "VMPC-KSA3"; }
+		}
+
+		private void checkByte(byte[] array, int position, byte b)
+		{
+			if (array[position] != b)
+			{
+				Fail("Fail on position " + position,
+					Hex.ToHexString(new byte[] { b }),
+					Hex.ToHexString(new byte[] { array[position] }));
+			}
+		}
+
+		public override void PerformTest()
+		{
+			byte[] key = Hex.Decode("9661410AB797D8A9EB767C21172DF6C7");
+			byte[] iv = Hex.Decode("4B5C2F003E67F39557A8D26F3DA2B155");
+			ICipherParameters kp = new KeyParameter(key);
+			ICipherParameters kpwiv = new ParametersWithIV(kp, iv);
+
+			VmpcKsa3Engine engine = new VmpcKsa3Engine();
+
+			try
+			{
+				engine.Init(true, kp);
+				Fail("Init failed to throw expected exception");
+			}
+			catch (ArgumentException)
+			{
+				// Expected
+			}
+
+			engine.Init(true, kpwiv);
+			checkEngine(engine);
+
+			engine.Reset();
+			byte[] output = checkEngine(engine);
+
+			engine.Init(false, kpwiv);
+			byte[] recovered = new byte[output.Length];
+			engine.ProcessBytes(output, 0, output.Length, recovered, 0);
+
+			if (!Arrays.AreEqual(input, recovered))
+			{
+				Fail("decrypted bytes differ from original bytes");
+			}
+		}
+
+		private byte[] checkEngine(VmpcKsa3Engine engine)
+		{
+			byte[] output = new byte[input.Length];
+			engine.ProcessBytes(input, 0, output.Length, output, 0);
+
+			checkByte(output, 0, (byte) 0xB6);
+			checkByte(output, 1, (byte) 0xEB);
+			checkByte(output, 2, (byte) 0xAE);
+			checkByte(output, 3, (byte) 0xFE);
+			checkByte(output, 252, (byte) 0x48);
+			checkByte(output, 253, (byte) 0x17);
+			checkByte(output, 254, (byte) 0x24);
+			checkByte(output, 255, (byte) 0x73);
+			checkByte(output, 1020, (byte) 0x1D);
+			checkByte(output, 1021, (byte) 0xAE);
+			checkByte(output, 1022, (byte) 0xC3);
+			checkByte(output, 1023, (byte) 0x5A);
+			checkByte(output, 102396, (byte) 0x1D);
+			checkByte(output, 102397, (byte) 0xA7);
+			checkByte(output, 102398, (byte) 0xE1);
+			checkByte(output, 102399, (byte) 0xDC);
+
+			return output;
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new VmpcKsa3Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/VMPCMacTest.cs b/crypto/test/src/crypto/test/VMPCMacTest.cs
new file mode 100644
index 000000000..0ddb5506f
--- /dev/null
+++ b/crypto/test/src/crypto/test/VMPCMacTest.cs
@@ -0,0 +1,68 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	[TestFixture]
+	public class VmpcMacTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "VMPC-MAC"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new VmpcMacTest());
+		}
+
+		private static byte[] output1 = Hex.Decode("9BDA16E2AD0E284774A3ACBC8835A8326C11FAAD");
+
+		public override void PerformTest()
+		{
+			ICipherParameters kp = new KeyParameter(
+				Hex.Decode("9661410AB797D8A9EB767C21172DF6C7"));
+			ICipherParameters kpwiv = new ParametersWithIV(kp,
+				Hex.Decode("4B5C2F003E67F39557A8D26F3DA2B155"));
+
+			byte[] m = new byte[256];
+			for (int i = 0; i < 256; i++)
+			{
+				m[i] = (byte) i;
+			}
+
+			VmpcMac mac = new VmpcMac();
+			mac.Init(kpwiv);
+
+			mac.BlockUpdate(m, 0, m.Length);
+
+			byte[] output = new byte[20];
+			mac.DoFinal(output, 0);
+
+			if (!Arrays.AreEqual(output, output1))
+			{
+				Fail("Fail",
+					Hex.ToHexString(output1),
+					Hex.ToHexString(output));
+			}
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/VMPCTest.cs b/crypto/test/src/crypto/test/VMPCTest.cs
new file mode 100644
index 000000000..6186c4733
--- /dev/null
+++ b/crypto/test/src/crypto/test/VMPCTest.cs
@@ -0,0 +1,112 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* VMPC Test
+	*/
+	[TestFixture]
+	public class VmpcTest
+		: SimpleTest
+	{
+		private static readonly byte[] input = new byte[1000000];
+
+		public override string Name
+		{
+			get { return "VMPC"; }
+		}
+
+		private void checkByte(byte[] array, int position, byte b)
+		{
+			if (array[position] != b)
+			{
+				Fail("Fail on position " + position,
+					Hex.ToHexString(new byte[] { b }),
+					Hex.ToHexString(new byte[] { array[position] }));
+			}
+		}
+
+		public override void PerformTest()
+		{
+			byte[] key = Hex.Decode("9661410AB797D8A9EB767C21172DF6C7");
+			byte[] iv = Hex.Decode("4B5C2F003E67F39557A8D26F3DA2B155");
+			ICipherParameters kp = new KeyParameter(key);
+			ICipherParameters kpwiv = new ParametersWithIV(kp, iv);
+
+			VmpcEngine engine = new VmpcEngine();
+
+			try
+			{
+				engine.Init(true, kp);
+				Fail("Init failed to throw expected exception");
+			}
+			catch (ArgumentException)
+			{
+				// Expected
+			}
+
+			engine.Init(true, kpwiv);
+			checkEngine(engine);
+
+			engine.Reset();
+			byte[] output = checkEngine(engine);
+
+			engine.Init(false, kpwiv);
+			byte[] recovered = new byte[output.Length];
+			engine.ProcessBytes(output, 0, output.Length, recovered, 0);
+
+			if (!Arrays.AreEqual(input, recovered))
+			{
+				Fail("decrypted bytes differ from original bytes");
+			}
+		}
+
+		private byte[] checkEngine(VmpcEngine engine)
+		{
+			byte[] output = new byte[input.Length];
+			engine.ProcessBytes(input, 0, output.Length, output, 0);
+
+			checkByte(output, 0, (byte) 0xA8);
+			checkByte(output, 1, (byte) 0x24);
+			checkByte(output, 2, (byte) 0x79);
+			checkByte(output, 3, (byte) 0xF5);
+			checkByte(output, 252, (byte) 0xB8);
+			checkByte(output, 253, (byte) 0xFC);
+			checkByte(output, 254, (byte) 0x66);
+			checkByte(output, 255, (byte) 0xA4);
+			checkByte(output, 1020, (byte) 0xE0);
+			checkByte(output, 1021, (byte) 0x56);
+			checkByte(output, 1022, (byte) 0x40);
+			checkByte(output, 1023, (byte) 0xA5);
+			checkByte(output, 102396, (byte) 0x81);
+			checkByte(output, 102397, (byte) 0xCA);
+			checkByte(output, 102398, (byte) 0x49);
+			checkByte(output, 102399, (byte) 0x9A);
+
+			return output;
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new VmpcTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/WhirlpoolDigestTest.cs b/crypto/test/src/crypto/test/WhirlpoolDigestTest.cs
new file mode 100644
index 000000000..1445b8977
--- /dev/null
+++ b/crypto/test/src/crypto/test/WhirlpoolDigestTest.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+
+	/**
+	 * ISO vector test for Whirlpool
+	 *  
+	 */
+	[TestFixture]
+	public class WhirlpoolDigestTest
+		: DigestTest
+	{
+		private static string[] messages =
+		{
+			"",
+			"a",
+			"abc",
+			"message digest",
+			"abcdefghijklmnopqrstuvwxyz",
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+			"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+			"abcdbcdecdefdefgefghfghighijhijk"
+		};
+
+		private static string[] digests =
+		{
+			"19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3",
+			"8ACA2602792AEC6F11A67206531FB7D7F0DFF59413145E6973C45001D0087B42D11BC645413AEFF63A42391A39145A591A92200D560195E53B478584FDAE231A",
+			"4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5",
+			"378C84A4126E2DC6E56DCC7458377AAC838D00032230F53CE1F5700C0FFB4D3B8421557659EF55C106B4B52AC5A4AAA692ED920052838F3362E86DBD37A8903E",
+			"F1D754662636FFE92C82EBB9212A484A8D38631EAD4238F5442EE13B8054E41B08BF2A9251C30B6A0B8AAE86177AB4A6F68F673E7207865D5D9819A3DBA4EB3B",
+			"DC37E008CF9EE69BF11F00ED9ABA26901DD7C28CDEC066CC6AF42E40F82F3A1E08EBA26629129D8FB7CB57211B9281A65517CC879D7B962142C65F5A7AF01467",
+			"466EF18BABB0154D25B9D38A6414F5C08784372BCCB204D6549C4AFADB6014294D5BD8DF2A6C44E538CD047B2681A51A2C60481E88C5A20B2C2A80CF3A9A083B",
+			"2A987EA40F917061F5D6F0A0E4644F488A7A5A52DEEE656207C562F988E95C6916BDC8031BC5BE1B7B947639FE050B56939BAAA0ADFF9AE6745B7B181C3BE3FD"
+		};
+
+		private static string _millionAResultVector = "0C99005BEB57EFF50A7CF005560DDF5D29057FD86B20BFD62DECA0F1CCEA4AF51FC15490EDDC47AF32BB2B66C34FF9AD8C6008AD677F77126953B226E4ED8B01";
+
+		private static string _thirtyOneZeros = "3E3F188F8FEBBEB17A933FEAF7FE53A4858D80C915AD6A1418F0318E68D49B4E459223CD414E0FBC8A57578FD755D86E827ABEF4070FC1503E25D99E382F72BA";
+
+		public WhirlpoolDigestTest()
+			: base(new WhirlpoolDigest(), messages, digests)
+		{
+		}
+
+		public override void PerformTest()
+		{
+			base.PerformTest();
+
+			byte[] thirtyOneZeros = new byte[31];
+			performStandardVectorTest("31 zeroes test", 
+			                          thirtyOneZeros, _thirtyOneZeros);
+
+			byte[] millionAInByteArray = new byte[1000000];
+			Arrays.Fill(millionAInByteArray, (byte)'a');
+
+			performStandardVectorTest("Million 'a' test", 
+			                          millionAInByteArray, _millionAResultVector);
+		}
+
+		private void performStandardVectorTest(string testTitle, byte[] inputBytes,
+		                                       string resultsAsHex)
+		{
+			doPerformTest(testTitle, inputBytes, resultsAsHex);        
+		}
+
+		private void doPerformTest(string testTitle, byte[] inputBytes, string resultsAsHex)
+		{
+			string resStr = createHexOutputFromDigest(inputBytes);
+			if (!resultsAsHex.Equals(resStr.ToUpper()))
+			{
+				Fail(testTitle, resultsAsHex, resStr);
+			}
+		}
+
+		private string createHexOutputFromDigest(byte[] digestBytes)
+		{
+			string resStr;
+			IDigest digest = new WhirlpoolDigest();
+			byte[] resBuf = new byte[digest.GetDigestSize()];
+			digest.BlockUpdate(digestBytes, 0, digestBytes.Length);
+			digest.DoFinal(resBuf, 0);
+			resStr = Hex.ToHexString(resBuf);
+			return resStr;
+		}
+
+		protected override IDigest CloneDigest(IDigest digest)
+		{
+			return new WhirlpoolDigest((WhirlpoolDigest)digest);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new WhirlpoolDigestTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/XSalsa20Test.cs b/crypto/test/src/crypto/test/XSalsa20Test.cs
new file mode 100644
index 000000000..74ed04e88
--- /dev/null
+++ b/crypto/test/src/crypto/test/XSalsa20Test.cs
@@ -0,0 +1,183 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* XSalsa20 Test
+	*/
+	[TestFixture]
+	public class XSalsa20Test 
+		: SimpleTest
+	{
+		private class TestCase
+		{
+
+			private byte[] key;
+			private byte[] iv;
+			private byte[] plaintext;
+			private byte[] ciphertext;
+
+			public TestCase(String key, string iv, string plaintext, string ciphertext)
+			{
+				this.key = Hex.Decode(key);
+				this.iv = Hex.Decode(iv);
+				this.plaintext = Hex.Decode(plaintext);
+				this.ciphertext = Hex.Decode(ciphertext);
+			}
+
+			public byte[] Key
+			{
+				get { return key; }
+			}
+
+			public byte[] Iv
+			{
+				get { return iv; }
+			}
+
+			public byte[] Plaintext
+			{
+				get { return plaintext; }
+			}
+
+			public byte[] Ciphertext
+			{
+				get { return ciphertext; }
+			}
+		}
+
+		// Test cases generated by naclcrypto-20090308, as used by cryptopp
+		private static readonly TestCase[] TEST_CASES = new TestCase[] {
+			new TestCase(
+				"a6a7251c1e72916d11c2cb214d3c252539121d8e234e652d651fa4c8cff88030",
+				"9e645a74e9e0a60d8243acd9177ab51a1beb8d5a2f5d700c",
+				"093c5e5585579625337bd3ab619d615760d8c5b224a85b1d0efe0eb8a7ee163abb0376529fcc09bab506c618e13ce777d82c3ae9d1a6f972d4160287cbfe60bf2130fc0a6ff6049d0a5c8a82f429231f008082e845d7e189d37f9ed2b464e6b919e6523a8c1210bd52a02a4c3fe406d3085f5068d1909eeeca6369abc981a42e87fe665583f0ab85ae71f6f84f528e6b397af86f6917d9754b7320dbdc2fea81496f2732f532ac78c4e9c6cfb18f8e9bdf74622eb126141416776971a84f94d156beaf67aecbf2ad412e76e66e8fad7633f5b6d7f3d64b5c6c69ce29003c6024465ae3b89be78e915d88b4b5621d",
+				"b2af688e7d8fc4b508c05cc39dd583d6714322c64d7f3e63147aede2d9534934b04ff6f337b031815cd094bdbc6d7a92077dce709412286822ef0737ee47f6b7ffa22f9d53f11dd2b0a3bb9fc01d9a88f9d53c26e9365c2c3c063bc4840bfc812e4b80463e69d179530b25c158f543191cff993106511aa036043bbc75866ab7e34afc57e2cce4934a5faae6eabe4f221770183dd060467827c27a354159a081275a291f69d946d6fe28ed0b9ce08206cf484925a51b9498dbde178ddd3ae91a8581b91682d860f840782f6eea49dbb9bd721501d2c67122dea3b7283848c5f13e0c0de876bd227a856e4de593a3"),
+			new TestCase(
+				"9e1da239d155f52ad37f75c7368a536668b051952923ad44f57e75ab588e475a",
+				"af06f17859dffa799891c4288f6635b5c5a45eee9017fd72",
+				"feac9d54fc8c115ae247d9a7e919dd76cfcbc72d32cae4944860817cbdfb8c04e6b1df76a16517cd33ccf1acda9206389e9e318f5966c093cfb3ec2d9ee2de856437ed581f552f26ac2907609df8c613b9e33d44bfc21ff79153e9ef81a9d66cc317857f752cc175fd8891fefebb7d041e6517c3162d197e2112837d3bc4104312ad35b75ea686e7c70d4ec04746b52ff09c421451459fb59f",
+				"2c261a2f4e61a62e1b27689916bf03453fcbc97bb2af6f329391ef063b5a219bf984d07d70f602d85f6db61474e9d9f5a2deecb4fcd90184d16f3b5b5e168ee03ea8c93f3933a22bc3d1a5ae8c2d8b02757c87c073409052a2a8a41e7f487e041f9a49a0997b540e18621cad3a24f0a56d9b19227929057ab3ba950f6274b121f193e32e06e5388781a1cb57317c0ba6305e910961d01002f0"),
+			new TestCase("d5c7f6797b7e7e9c1d7fd2610b2abf2bc5a7885fb3ff78092fb3abe8986d35e2",
+	             "744e17312b27969d826444640e9c4a378ae334f185369c95",
+	             "7758298c628eb3a4b6963c5445ef66971222be5d1a4ad839715d1188071739b77cc6e05d5410f963a64167629757",
+	             "27b8cfe81416a76301fd1eec6a4d99675069b2da2776c360db1bdfea7c0aa613913e10f7a60fec04d11e65f2d64e"),
+			new TestCase(
+				"737d7811ce96472efed12258b78122f11deaec8759ccbd71eac6bbefa627785c",
+				"6fb2ee3dda6dbd12f1274f126701ec75c35c86607adb3edd",
+				"501325fb2645264864df11faa17bbd58312b77cad3d94ac8fb8542f0eb653ad73d7fce932bb874cb89ac39fc47f8267cf0f0c209f204b2d8578a3bdf461cb6a271a468bebaccd9685014ccbc9a73618c6a5e778a21cc8416c60ad24ddc417a130d53eda6dfbfe47d09170a7be1a708b7b5f3ad464310be36d9a2a95dc39e83d38667e842eb6411e8a23712297b165f690c2d7ca1b1346e3c1fccf5cafd4f8be0",
+				"6724c372d2e9074da5e27a6c54b2d703dc1d4c9b1f8d90f00c122e692ace7700eadca942544507f1375b6581d5a8fb39981c1c0e6e1ff2140b082e9ec016fce141d5199647d43b0b68bfd0fea5e00f468962c7384dd6129aea6a3fdfe75abb210ed5607cef8fa0e152833d5ac37d52e557b91098a322e76a45bbbcf4899e790618aa3f4c2e5e0fc3de93269a577d77a5502e8ea02f717b1dd2df1ec69d8b61ca"),
+			new TestCase(
+				"760158da09f89bbab2c99e6997f9523a95fcef10239bcca2573b7105f6898d34",
+				"43636b2cc346fc8b7c85a19bf507bdc3dafe953b88c69dba",
+				"d30a6d42dff49f0ed039a306bae9dec8d9e88366cc19e8c3642fd58fa0794ebf8029d949730339b0823a51f0f49f0d2c71f1051c1e0e2c86941f172789cdb1b0107413e70f982ff9761877bb526ef1c3eb1106a948d60ef21bd35d32cfd64f89b79ed63ecc5cca56246af736766f285d8e6b0da9cb1cd21020223ffacc5a32",
+				"c815b6b79b64f9369aec8dce8c753df8a50f2bc97c70ce2f014db33a65ac5816bac9e30ac08bdded308c65cb87e28e2e71b677dc25c5a6499c1553555daf1f55270a56959dffa0c66f24e0af00951ec4bb59ccc3a6c5f52e0981647e53e439313a52c40fa7004c855b6e6eb25b212a138e843a9ba46edb2a039ee82a263abe"),
+			new TestCase(
+				"27ba7e81e7edd4e71be53c07ce8e633138f287e155c7fa9e84c4ad804b7fa1b9",
+				"ea05f4ebcd2fb6b000da0612861ba54ff5c176fb601391aa",
+				"e09ff5d2cb050d69b2d42494bde5825238c756d6991d99d7a20d1ef0b83c371c89872690b2fc11d5369f4fc4971b6d3d6c078aef9b0f05c0e61ab89c025168054defeb03fef633858700c58b1262ce011300012673e893e44901dc18eee3105699c44c805897bdaf776af1833162a21a",
+				"a23e7ef93c5d0667c96d9e404dcbe6be62026fa98f7a3ff9ba5d458643a16a1cef7272dc6097a9b52f35983557c77a11b314b4f7d5dc2cca15ee47616f861873cbfed1d32372171a61e38e447f3cf362b3abbb2ed4170d89dcb28187b7bfd206a3e026f084a7e0ed63d319de6bc9afc0"),
+			new TestCase("6799d76e5ffb5b4920bc2768bafd3f8c16554e65efcf9a16f4683a7a06927c11",
+	             "61ab951921e54ff06d9b77f313a4e49df7a057d5fd627989", "472766", "8fd7df"),
+			new TestCase(
+				"f68238c08365bb293d26980a606488d09c2f109edafa0bbae9937b5cc219a49c",
+				"5190b51e9b708624820b5abdf4e40fad1fb950ad1adc2d26",
+				"47ec6b1f73c4b7ff5274a0bfd7f45f864812c85a12fbcb3c2cf8a3e90cf66ccf2eacb521e748363c77f52eb426ae57a0c6c78f75af71284569e79d1a92f949a9d69c4efc0b69902f1e36d7562765543e2d3942d9f6ff5948d8a312cff72c1afd9ea3088aff7640bfd265f7a9946e606abc77bcedae6bddc75a0dba0bd917d73e3bd1268f727e0096345da1ed25cf553ea7a98fea6b6f285732de37431561ee1b3064887fbcbd71935e02",
+				"36160e88d3500529ba4edba17bc24d8cfaca9a0680b3b1fc97cf03f3675b7ac301c883a68c071bc54acdd3b63af4a2d72f985e51f9d60a4c7fd481af10b2fc75e252fdee7ea6b6453190617dcc6e2fe1cd56585fc2f0b0e97c5c3f8ad7eb4f31bc4890c03882aac24cc53acc1982296526690a220271c2f6e326750d3fbda5d5b63512c831f67830f59ac49aae330b3e0e02c9ea0091d19841f1b0e13d69c9fbfe8a12d6f30bb734d9d2"),
+			new TestCase(
+				"45b2bd0de4ed9293ec3e26c4840faaf64b7d619d51e9d7a2c7e36c83d584c3df",
+				"546c8c5d6be8f90952cab3f36d7c1957baaa7a59abe3d7e5",
+				"5007c8cd5b3c40e17d7fe423a87ae0ced86bec1c39dc07a25772f3e96dabd56cd3fd7319f6c9654925f2d87087a700e1b130da796895d1c9b9acd62b266144067d373ed51e787498b03c52faad16bb3826fa511b0ed2a19a8663f5ba2d6ea7c38e7212e9697d91486c49d8a000b9a1935d6a7ff7ef23e720a45855481440463b4ac8c4f6e7062adc1f1e1e25d3d65a31812f58a71160",
+				"8eacfba568898b10c0957a7d44100685e8763a71a69a8d16bc7b3f88085bb9a2f09642e4d09a9f0ad09d0aad66b22610c8bd02ff6679bb92c2c026a216bf425c6be35fb8dae7ff0c72b0efd6a18037c70eed0ca90062a49a3c97fdc90a8f9c2ea536bfdc41918a7582c9927fae47efaa3dc87967b7887dee1bf071734c7665901d9105dae2fdf66b4918e51d8f4a48c60d19fbfbbcba"),
+			new TestCase(
+				"fe559c9a282beb40814d016d6bfcb2c0c0d8bf077b1110b8703a3ce39d70e0e1",
+				"b076200cc7011259805e18b304092754002723ebec5d6200",
+				"6db65b9ec8b114a944137c821fd606be75478d928366d5284096cdef782fcff7e8f59cb8ffcda979757902c5ffa6bc477ceaa4cb5d5ea76f94d91e833f823a6bc78f1055dfa6a97bea8965c1cde67a668e001257334a585727d9e0f7c1a06e88d3d25a4e6d9096c968bf138e116a3ebeffd4bb4808adb1fd698164ba0a35c709a47f16f1f4435a2345a9194a00b95abd51851d505809a6077da9baca5831afff31578c487ee68f2767974a98a7e803aac788da98319c4ea8eaa3d394855651f484cef543f537e35158ee29",
+				"4dce9c8f97a028051b0727f34e1b9ef21f06f0760f36e71713204027902090ba2bb6b13436ee778d9f50530efbd7a32b0d41443f58ccaee781c7b716d3a96fdec0e3764ed7959f34c3941278591ea033b5cbadc0f1916032e9bebbd1a8395b83fb63b1454bd775bd20b3a2a96f951246ac14daf68166ba62f6cbff8bd121ac9498ff8852fd2be975df52b5daef3829d18eda42e715022dcbf930d0a789ee6a146c2c7088c35773c63c06b4af4559856ac199ced86863e4294707825337c5857970eb7fddeb263781309011"),
+			new TestCase(
+				"0ae10012d7e56614b03dcc89b14bae9242ffe630f3d7e35ce8bbb97bbc2c92c3",
+				"f96b025d6cf46a8a12ac2af1e2aef1fb83590adadaa5c5ea",
+				"ea0f354e96f12bc72bbaa3d12b4a8ed879b042f0689878f46b651cc4116d6f78409b11430b3aaa30b2076891e8e1fa528f2fd169ed93dc9f84e24409eec2101daf4d057be2492d11de640cbd7b355ad29fb70400fffd7cd6d425abeeb732a0eaa4330af4c656252c4173deab653eb85c58462d7ab0f35fd12b613d29d473d330310dc323d3c66348bbdbb68a326324657cae7b77a9e34358f2cec50c85609e73056856796e3be8d62b6e2fe9f953",
+				"e8abd48924b54e5b80866be7d4ebe5cf4274cafff08b39cb2d40a8f0b472398aedc776e0793812fbf1f60078635d2ed86b15efcdba60411ee23b07233592a44ec31b1013ce8964236675f8f183aef885e864f2a72edf4215b5338fa2b54653dfa1a8c55ce5d95cc605b9b311527f2e3463ffbec78a9d1d65dabad2f338769c9f43f133a791a11c7eca9af0b771a4ac32963dc8f631a2c11217ac6e1b9430c1aae1ceebe22703f429998a8fb8c641"),
+			new TestCase(
+				"082c539bc5b20f97d767cd3f229eda80b2adc4fe49c86329b5cd6250a9877450",
+				"845543502e8b64912d8f2c8d9fffb3c69365686587c08d0c",
+				"a96bb7e910281a6dfad7c8a9c370674f0ceec1ad8d4f0de32f9ae4a23ed329e3d6bc708f876640a229153ac0e7281a8188dd77695138f01cda5f41d5215fd5c6bdd46d982cb73b1efe2997970a9fdbdb1e768d7e5db712068d8ba1af6067b5753495e23e6e1963af012f9c7ce450bf2de619d3d59542fb55f3",
+				"835da74fc6de08cbda277a7966a07c8dcd627e7b17adde6d930b6581e3124b8baad096f693991fedb1572930601fc7709541839b8e3ffd5f033d2060d999c6c6e3048276613e648000acb5212cc632a916afce290e20ebdf612d08a6aa4c79a74b070d3f872a861f8dc6bb07614db515d363349d3a8e3336a3"),
+			new TestCase("3d02bff3375d403027356b94f514203737ee9a85d2052db3e4e5a217c259d18a",
+	             "74216c95031895f48c1dba651555ebfa3ca326a755237025",
+	             "0d4b0f54fd09ae39baa5fa4baccf2e6682e61b257e01f42b8f",
+	             "16c4006c28365190411eb1593814cf15e74c22238f210afc3d"),
+			new TestCase(
+				"ad1a5c47688874e6663a0f3fa16fa7efb7ecadc175c468e5432914bdb480ffc6",
+				"e489eed440f1aae1fac8fb7a9825635454f8f8f1f52e2fcc",
+				"aa6c1e53580f03a9abb73bfdadedfecada4c6b0ebe020ef10db745e54ba861caf65f0e40dfc520203bb54d29e0a8f78f16b3f1aa525d6bfa33c54726e59988cfbec78056",
+				"02fe84ce81e178e7aabdd3ba925a766c3c24756eefae33942af75e8b464556b5997e616f3f2dfc7fce91848afd79912d9fb55201b5813a5a074d2c0d4292c1fd441807c5"),
+			new TestCase(
+				"053a02bedd6368c1fb8afc7a1b199f7f7ea2220c9a4b642a6850091c9d20ab9c",
+				"c713eea5c26dad75ad3f52451e003a9cb0d649f917c89dde",
+				"8f0a8a164760426567e388840276de3f95cb5e3fadc6ed3f3e4fe8bc169d9388804dcb94b6587dbb66cb0bd5f87b8e98b52af37ba290629b858e0e2aa7378047a26602",
+				"516710e59843e6fbd4f25d0d8ca0ec0d47d39d125e9dad987e0518d49107014cb0ae405e30c2eb3794750bca142ce95e290cf95abe15e822823e2e7d3ab21bc8fbd445"),
+			new TestCase(
+				"5b14ab0fbed4c58952548a6cb1e0000cf4481421f41288ea0aa84add9f7deb96",
+				"54bf52b911231b952ba1a6af8e45b1c5a29d97e2abad7c83",
+				"37fb44a675978b560ff9a4a87011d6f3ad2d37a2c3815b45a3c0e6d1b1d8b1784cd468927c2ee39e1dccd4765e1c3d676a335be1ccd6900a45f5d41a317648315d8a8c24adc64eb285f6aeba05b9029586353d303f17a807658b9ff790474e1737bd5fdc604aeff8dfcaf1427dcc3aacbb0256badcd183ed75a2dc52452f87d3c1ed2aa583472b0ab91cda20614e9b6fdbda3b49b098c95823cc72d8e5b717f2314b0324e9ce",
+				"ae6deb5d6ce43d4b09d0e6b1c0e9f46157bcd8ab50eaa3197ff9fa2bf7af649eb52c68544fd3adfe6b1eb316f1f23538d470c30dbfec7e57b60cbcd096c782e7736b669199c8253e70214cf2a098fda8eac5da79a9496a3aae754d03b17c6d70d1027f42bf7f95ce3d1d9c338854e158fcc803e4d6262fb639521e47116ef78a7a437ca9427ba645cd646832feab822a208278e45e93e118d780b988d65397eddfd7a819526e"),
+			new TestCase(
+				"d74636e3413a88d85f322ca80fb0bd650bd0bf0134e2329160b69609cd58a4b0",
+				"efb606aa1d9d9f0f465eaa7f8165f1ac09f5cb46fecf2a57",
+				"f85471b75f6ec81abac2799ec09e98e280b2ffd64ca285e5a0109cfb31ffab2d617b2c2952a2a8a788fc0da2af7f530758f74f1ab56391ab5ff2adbcc5be2d6c7f49fbe8118104c6ff9a23c6dfe52f57954e6a69dcee5db06f514f4a0a572a9a8525d961dae72269b987189d465df6107119c7fa790853e063cba0fab7800ca932e258880fd74c33c784675bedad0e7c09e9cc4d63dd5e9713d5d4a0196e6b562226ac31b4f57c04f90a181973737ddc7e80f364112a9fbb435ebdbcabf7d490ce52",
+				"b2b795fe6c1d4c83c1327e015a67d4465fd8e32813575cbab263e20ef05864d2dc17e0e4eb81436adfe9f638dcc1c8d78f6b0306baf938e5d2ab0b3e05e735cc6fff2d6e02e3d60484bea7c7a8e13e23197fea7b04d47d48f4a4e5944174539492800d3ef51e2ee5e4c8a0bdf050c2dd3dd74fce5e7e5c37364f7547a11480a3063b9a0a157b15b10a5a954de2731ced055aa2e2767f0891d4329c426f3808ee867bed0dc75b5922b7cfb895700fda016105a4c7b7f0bb90f029f6bbcb04ac36ac16") };
+
+		public override string Name
+		{
+			get { return "XSalsa20"; }
+		}
+
+		public override void PerformTest()
+		{
+			for (int i = 0; i < TEST_CASES.Length; i++)
+			{
+				performTest(i, TEST_CASES[i]);
+			}
+		}
+
+		private void performTest(int number, TestCase testCase)
+		{
+			byte[] plaintext = testCase.Plaintext;
+			byte[] output = new byte[plaintext.Length];
+
+			XSalsa20Engine engine = new XSalsa20Engine();
+			engine.Init(false, new ParametersWithIV(new KeyParameter(testCase.Key), testCase.Iv));
+
+			engine.ProcessBytes(testCase.Plaintext, 0, testCase.Plaintext.Length, output, 0);
+
+			if (!Arrays.AreEqual(testCase.Ciphertext, output))
+			{
+				Fail("mismatch on " + number, Hex.ToHexString(testCase.Ciphertext), Hex.ToHexString(output));
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new XSalsa20Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/test/XTEATest.cs b/crypto/test/src/crypto/test/XTEATest.cs
new file mode 100644
index 000000000..a1ea65298
--- /dev/null
+++ b/crypto/test/src/crypto/test/XTEATest.cs
@@ -0,0 +1,59 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tests
+{
+	/**
+	* TEA tester - based on C implementation results from http://www.simonshepherd.supanet.com/tea.htm
+	*/
+	[TestFixture]
+	public class XteaTest
+		: CipherTest
+	{
+		private static readonly SimpleTest[] tests =
+		{
+			new BlockCipherVectorTest(0, new XteaEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"0000000000000000", "dee9d4d8f7131ed9"),
+			new BlockCipherVectorTest(1, new XteaEngine(),
+				new KeyParameter(Hex.Decode("00000000000000000000000000000000")),
+				"0102030405060708", "065c1b8975c6a816"),
+			new BlockCipherVectorTest(2, new XteaEngine(),
+				new KeyParameter(Hex.Decode("0123456712345678234567893456789A")),
+				"0000000000000000", "1ff9a0261ac64264"),
+			new BlockCipherVectorTest(3, new XteaEngine(),
+				new KeyParameter(Hex.Decode("0123456712345678234567893456789A")),
+				"0102030405060708", "8c67155b2ef91ead"),
+		};
+
+		public XteaTest()
+			: base(tests, new XteaEngine(), new KeyParameter(new byte[16]))
+		{
+		}
+
+		public override string Name
+		{
+			get { return "XTEA"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new XteaTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/crypto/tls/test/MockTlsClient.cs b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
new file mode 100644
index 000000000..61521adca
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/MockTlsClient.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class MockTlsClient
+        :   DefaultTlsClient
+    {
+        internal TlsSession mSession;
+
+        internal MockTlsClient(TlsSession session)
+        {
+            this.mSession = session;
+        }
+
+        public override TlsSession GetSessionToResume()
+        {
+            return this.mSession;
+        }
+
+        public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS client raised alert (AlertLevel." + alertLevel + ", AlertDescription." + alertDescription
+                + ")");
+            if (message != null)
+            {
+                output.WriteLine("> " + message);
+            }
+            if (cause != null)
+            {
+                output.WriteLine(cause);
+            }
+        }
+
+        public override void NotifyAlertReceived(byte alertLevel, byte alertDescription)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS client received alert (AlertLevel." + alertLevel + ", AlertDescription."
+                + alertDescription + ")");
+        }
+
+        public override int[] GetCipherSuites()
+        {
+            return Arrays.Concatenate(base.GetCipherSuites(),
+                new int[]
+                {
+                    CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+                    CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1,
+                    CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1,
+                    CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1,
+                    CipherSuite.TLS_RSA_WITH_SALSA20_SHA1,
+                });
+        }
+
+        public override IDictionary GetClientExtensions()
+        {
+            IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions());
+            TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions);
+            TlsExtensionsUtilities.AddMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9);
+            TlsExtensionsUtilities.AddTruncatedHMacExtension(clientExtensions);
+            return clientExtensions;
+        }
+
+        public override void NotifyServerVersion(ProtocolVersion serverVersion)
+        {
+            base.NotifyServerVersion(serverVersion);
+
+            Console.WriteLine("TLS client negotiated " + serverVersion);
+        }
+
+        public override TlsAuthentication GetAuthentication()
+        {
+            return new MyTlsAuthentication(mContext);
+        }
+
+        public override void NotifyHandshakeComplete()
+        {
+            base.NotifyHandshakeComplete();
+
+            TlsSession newSession = mContext.ResumableSession;
+            if (newSession != null)
+            {
+                byte[] newSessionID = newSession.SessionID;
+                string hex = Hex.ToHexString(newSessionID);
+
+                if (this.mSession != null && Arrays.AreEqual(this.mSession.SessionID, newSessionID))
+                {
+                    Console.WriteLine("Resumed session: " + hex);
+                }
+                else
+                {
+                    Console.WriteLine("Established session: " + hex);
+                }
+
+                this.mSession = newSession;
+            }
+        }
+
+        internal class MyTlsAuthentication
+            :   TlsAuthentication
+        {
+            private readonly TlsContext mContext;
+
+            internal MyTlsAuthentication(TlsContext context)
+            {
+                this.mContext = context;
+            }
+
+            public virtual void NotifyServerCertificate(Certificate serverCertificate)
+            {
+                X509CertificateStructure[] chain = serverCertificate.GetCertificateList();
+                Console.WriteLine("TLS client received server certificate chain of length " + chain.Length);
+                for (int i = 0; i != chain.Length; i++)
+                {
+                    X509CertificateStructure entry = chain[i];
+                    // TODO Create Fingerprint based on certificate signature algorithm digest
+                    Console.WriteLine("    Fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
+                        + entry.Subject + ")");
+                }
+            }
+
+            public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+            {
+                byte[] certificateTypes = certificateRequest.CertificateTypes;
+                if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign))
+                    return null;
+
+                SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
+                IList sigAlgs = certificateRequest.SupportedSignatureAlgorithms;
+                if (sigAlgs != null)
+                {
+                    foreach (SignatureAndHashAlgorithm sigAlg in sigAlgs)
+                    {
+                        if (sigAlg.Signature == SignatureAlgorithm.rsa)
+                        {
+                            signatureAndHashAlgorithm = sigAlg;
+                            break;
+                        }
+                    }
+
+                    if (signatureAndHashAlgorithm == null)
+                    {
+                        return null;
+                    }
+                }
+
+                return TlsTestUtilities.LoadSignerCredentials(mContext, new string[] { "x509-client.pem", "x509-ca.pem" },
+                    "x509-client-key.pem", signatureAndHashAlgorithm);
+            }
+        };
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/MockTlsServer.cs b/crypto/test/src/crypto/tls/test/MockTlsServer.cs
new file mode 100644
index 000000000..54a645d96
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/MockTlsServer.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    internal class MockTlsServer
+        :   DefaultTlsServer
+    {
+        public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS client raised alert (AlertLevel." + alertLevel + ", AlertDescription." + alertDescription
+                + ")");
+            if (message != null)
+            {
+                output.WriteLine("> " + message);
+            }
+            if (cause != null)
+            {
+                output.WriteLine(cause);
+            }
+        }
+
+        public override void NotifyAlertReceived(byte alertLevel, byte alertDescription)
+        {
+            TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
+            output.WriteLine("TLS client received alert (AlertLevel." + alertLevel + ", AlertDescription."
+                + alertDescription + ")");
+        }
+
+        protected override int[] GetCipherSuites()
+        {
+            return Arrays.Concatenate(base.GetCipherSuites(),
+                new int[]
+                {
+                    CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+                    CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1,
+                    CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1,
+                    CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1,
+                    CipherSuite.TLS_RSA_WITH_SALSA20_SHA1,
+                });
+        }
+
+        protected override ProtocolVersion MaximumVersion
+        {
+            get { return ProtocolVersion.TLSv12; }
+        }
+
+        public override ProtocolVersion GetServerVersion()
+        {
+            ProtocolVersion serverVersion = base.GetServerVersion();
+
+            Console.WriteLine("TLS server negotiated " + serverVersion);
+
+            return serverVersion;
+        }
+
+        public override CertificateRequest GetCertificateRequest()
+        {
+            IList serverSigAlgs = null;
+
+            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mServerVersion))
+            {
+                byte[] hashAlgorithms = new byte[]{ HashAlgorithm.sha512, HashAlgorithm.sha384, HashAlgorithm.sha256,
+                    HashAlgorithm.sha224, HashAlgorithm.sha1 };
+                byte[] signatureAlgorithms = new byte[]{ SignatureAlgorithm.rsa };
+
+                serverSigAlgs = new ArrayList();
+                for (int i = 0; i < hashAlgorithms.Length; ++i)
+                {
+                    for (int j = 0; j < signatureAlgorithms.Length; ++j)
+                    {
+                        serverSigAlgs.Add(new SignatureAndHashAlgorithm(hashAlgorithms[i],
+                            signatureAlgorithms[j]));
+                    }
+                }
+            }
+
+            IList certificateAuthorities = new ArrayList();
+            certificateAuthorities.Add(TlsTestUtilities.LoadCertificateResource("x509-ca.pem").Subject);
+
+            return new CertificateRequest(new byte[]{ ClientCertificateType.rsa_sign }, serverSigAlgs, certificateAuthorities);
+        }
+
+        public override void NotifyClientCertificate(Certificate clientCertificate)
+        {
+            X509CertificateStructure[] chain = clientCertificate.GetCertificateList();
+            Console.WriteLine("TLS server received client certificate chain of length " + chain.Length);
+            for (int i = 0; i != chain.Length; i++)
+            {
+                X509CertificateStructure entry = chain[i];
+                // TODO Create fingerprint based on certificate signature algorithm digest
+                Console.WriteLine("    fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " ("
+                    + entry.Subject + ")");
+            }
+        }
+
+        protected override TlsEncryptionCredentials GetRsaEncryptionCredentials()
+        {
+            return TlsTestUtilities.LoadEncryptionCredentials(mContext, new string[]{"x509-server.pem", "x509-ca.pem"},
+                "x509-server-key.pem");
+        }
+
+        protected override TlsSignerCredentials GetRsaSignerCredentials()
+        {
+            /*
+             * TODO Note that this code fails to provide default value for the client supported
+             * algorithms if it wasn't sent.
+             */
+            SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
+            IList sigAlgs = mSupportedSignatureAlgorithms;
+            if (sigAlgs != null)
+            {
+                foreach (SignatureAndHashAlgorithm sigAlg in sigAlgs)
+                {
+                    if (sigAlg.Signature == SignatureAlgorithm.rsa)
+                    {
+                        signatureAndHashAlgorithm = sigAlg;
+                        break;
+                    }
+                }
+
+                if (signatureAndHashAlgorithm == null)
+                {
+                    return null;
+                }
+            }
+
+            return TlsTestUtilities.LoadSignerCredentials(mContext, new string[]{"x509-server.pem", "x509-ca.pem"},
+                "x509-server-key.pem", signatureAndHashAlgorithm);
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsClientTest.cs b/crypto/test/src/crypto/tls/test/TlsClientTest.cs
new file mode 100644
index 000000000..c9a5ef9ad
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsClientTest.cs
@@ -0,0 +1,66 @@
+using System;
+using System.IO;
+using System.Net.Sockets;
+using System.Text;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    /**
+     * A simple test designed to conduct a TLS handshake with an external TLS server.
+     * <p/>
+     * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in
+     * this package (under 'src/test/resources') for help configuring an external TLS server.
+     */
+    public class TlsClientTest
+    {
+        private static readonly SecureRandom secureRandom = new SecureRandom();
+
+        public static void Main(string[] args)
+        {
+            string hostname = "localhost";
+            int port = 5556;
+
+            long time1 = DateTime.UtcNow.Ticks;
+
+            MockTlsClient client = new MockTlsClient(null);
+            TlsClientProtocol protocol = OpenTlsConnection(hostname, port, client);
+            protocol.Close();
+
+            long time2 = DateTime.UtcNow.Ticks;
+            Console.WriteLine("Elapsed 1: " + (time2 - time1)/TimeSpan.TicksPerMillisecond + "ms");
+
+            client = new MockTlsClient(client.GetSessionToResume());
+            protocol = OpenTlsConnection(hostname, port, client);
+
+            long time3 = DateTime.UtcNow.Ticks;
+            Console.WriteLine("Elapsed 2: " + (time3 - time2)/TimeSpan.TicksPerMillisecond + "ms");
+
+            byte[] req = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\n\r\n");
+
+            Stream tlsStream = protocol.Stream;
+            tlsStream.Write(req, 0, req.Length);
+            tlsStream.Flush();
+
+            StreamReader reader = new StreamReader(tlsStream);
+
+            String line;
+            while ((line = reader.ReadLine()) != null)
+            {
+                Console.WriteLine(">>> " + line);
+            }
+
+            protocol.Close();
+        }
+
+        internal static TlsClientProtocol OpenTlsConnection(string hostname, int port, TlsClient client)
+        {
+            TcpClient tcp = new TcpClient(hostname, port);
+
+            TlsClientProtocol protocol = new TlsClientProtocol(tcp.GetStream(), secureRandom);
+            protocol.Connect(client);
+            return protocol;
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsServerTest.cs b/crypto/test/src/crypto/tls/test/TlsServerTest.cs
new file mode 100644
index 000000000..77adf22f7
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsServerTest.cs
@@ -0,0 +1,78 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    /**
+     * A simple test designed to conduct a TLS handshake with an external TLS client.
+     * <p/>
+     * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in
+     * this package (under 'src/test/resources') for help configuring an external TLS client.
+     */
+    public class TlsServerTest
+    {
+        private static readonly SecureRandom secureRandom = new SecureRandom();
+
+        public static void Main(string[] args)
+        {
+            int port = 5556;
+
+            TcpListener ss = new TcpListener(IPAddress.Any, port);
+            ss.Start();
+            Stream stdout = Console.OpenStandardOutput();
+            while (true)
+            {
+                TcpClient s = ss.AcceptTcpClient();
+                Console.WriteLine("--------------------------------------------------------------------------------");
+                Console.WriteLine("Accepted " + s);
+                ServerThread st = new ServerThread(s, stdout);
+                Thread t = new Thread(new ThreadStart(st.Run));
+                t.Start();
+            }
+        }
+
+        internal class ServerThread
+        {
+            private readonly TcpClient s;
+            private readonly Stream stdout;
+
+            internal ServerThread(TcpClient s, Stream stdout)
+            {
+                this.s = s;
+                this.stdout = stdout;
+            }
+
+            public void Run()
+            {
+                try
+                {
+                    MockTlsServer server = new MockTlsServer();
+                    TlsServerProtocol serverProtocol = new TlsServerProtocol(s.GetStream(), secureRandom);
+                    serverProtocol.Accept(server);
+                    Stream log = new TeeOutputStream(serverProtocol.Stream, stdout);
+                    Streams.PipeAll(serverProtocol.Stream, log);
+                    serverProtocol.Close();
+                }
+                finally
+                {
+                    try
+                    {
+                        s.Close();
+                    }
+                    catch (IOException)
+                    {
+                    }
+                    finally
+                    {
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs b/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs
new file mode 100644
index 000000000..272dfd4fd
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+    public abstract class TlsTestUtilities
+    {
+        internal static readonly byte[] RsaCertData = Base64
+            .Decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2"
+                + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq"
+                + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA2MDIwNVoXDTEzMDIyNT"
+                + "A2MDM0NVowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw"
+                + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG"
+                + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy"
+                + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCBSAwEgYDVR"
+                + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAHU55Ncz"
+                + "eglREcTg54YLUlGWu2WOYWhit/iM1eeq8Kivro7q98eW52jTuMI3CI5ulqd0hYzshQKQaZ5GDzErMyM=");
+
+        internal static readonly byte[] DudRsaCertData = Base64
+            .Decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2"
+                + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq"
+                + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA1NDcyOFoXDTEzMDIyNT"
+                + "A1NDkwOFowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw"
+                + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG"
+                + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy"
+                + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCAAEwEgYDVR"
+                + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS"
+                + "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0=");
+
+        internal static string Fingerprint(X509CertificateStructure c)
+        {
+            byte[] der = c.GetEncoded();
+            byte[] sha1 = Sha256DigestOf(der);
+            byte[] hexBytes = Hex.Encode(sha1);
+            string hex = Encoding.ASCII.GetString(hexBytes).ToUpper(CultureInfo.InvariantCulture);
+
+            StringBuilder fp = new StringBuilder();
+            int i = 0;
+            fp.Append(hex.Substring(i, 2));
+            while ((i += 2) < hex.Length)
+            {
+                fp.Append(':');
+                fp.Append(hex.Substring(i, 2));
+            }
+            return fp.ToString();
+        }
+
+        internal static byte[] Sha256DigestOf(byte[] input)
+        {
+            return DigestUtilities.CalculateDigest("SHA256", input);
+        }
+
+        internal static TlsAgreementCredentials LoadAgreementCredentials(TlsContext context,
+            string[] certResources, string keyResource)
+        {
+            Certificate certificate = LoadCertificateChain(certResources);
+            AsymmetricKeyParameter privateKey = LoadPrivateKeyResource(keyResource);
+
+            return new DefaultTlsAgreementCredentials(certificate, privateKey);
+        }
+
+        internal static TlsEncryptionCredentials LoadEncryptionCredentials(TlsContext context,
+            string[] certResources, string keyResource)
+        {
+            Certificate certificate = LoadCertificateChain(certResources);
+            AsymmetricKeyParameter privateKey = LoadPrivateKeyResource(keyResource);
+
+            return new DefaultTlsEncryptionCredentials(context, certificate, privateKey);
+        }
+
+        internal static TlsSignerCredentials LoadSignerCredentials(TlsContext context, string[] certResources,
+            string keyResource, SignatureAndHashAlgorithm signatureAndHashAlgorithm)
+        {
+            Certificate certificate = LoadCertificateChain(certResources);
+            AsymmetricKeyParameter privateKey = LoadPrivateKeyResource(keyResource);
+
+            return new DefaultTlsSignerCredentials(context, certificate, privateKey, signatureAndHashAlgorithm);
+        }
+
+        internal static Certificate LoadCertificateChain(string[] resources)
+        {
+            X509CertificateStructure[] chain = new X509CertificateStructure[resources.Length];
+            for (int i = 0; i < resources.Length; ++i)
+            {
+                chain[i] = LoadCertificateResource(resources[i]);
+            }
+            return new Certificate(chain);
+        }
+
+        internal static X509CertificateStructure LoadCertificateResource(string resource)
+        {
+            PemObject pem = LoadPemResource(resource);
+            if (pem.Type.EndsWith("CERTIFICATE"))
+            {
+                return X509CertificateStructure.GetInstance(pem.Content);
+            }
+            throw new ArgumentException("doesn't specify a valid certificate", "resource");
+        }
+
+        internal static AsymmetricKeyParameter LoadPrivateKeyResource(string resource)
+        {
+            PemObject pem = LoadPemResource(resource);
+            if (pem.Type.EndsWith("RSA PRIVATE KEY"))
+            {
+                RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(pem.Content);
+                return new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent,
+                    rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1,
+                    rsa.Exponent2, rsa.Coefficient);
+            }
+            if (pem.Type.EndsWith("PRIVATE KEY"))
+            {
+                return PrivateKeyFactory.CreateKey(pem.Content);
+            }
+            throw new ArgumentException("doesn't specify a valid private key", "resource");
+        }
+
+        internal static PemObject LoadPemResource(string resource)
+        {
+            Stream s = SimpleTest.GetTestDataAsStream("tls." + resource);
+            PemReader p = new PemReader(new StreamReader(s));
+            PemObject o = p.ReadPemObject();
+            p.Reader.Close();
+            return o;
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/AllTests.cs b/crypto/test/src/math/ec/test/AllTests.cs
new file mode 100644
index 000000000..d4c7dc768
--- /dev/null
+++ b/crypto/test/src/math/ec/test/AllTests.cs
@@ -0,0 +1,28 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Math.EC.Tests
+{
+    public class AllTests
+    {
+        public static void Main(
+            string[] args)
+        {
+//            junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            suite().Run(el);
+        }
+
+        public static TestSuite suite()
+        {
+            TestSuite suite = new TestSuite("EC Math tests");
+
+            suite.Add(new ECAlgorithmsTest());
+            suite.Add(new ECPointTest());
+
+            return suite;
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/ECAlgorithmsTest.cs b/crypto/test/src/math/ec/test/ECAlgorithmsTest.cs
new file mode 100644
index 000000000..b950c8b4b
--- /dev/null
+++ b/crypto/test/src/math/ec/test/ECAlgorithmsTest.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Math.EC.Tests
+{
+    [TestFixture]
+    public class ECAlgorithmsTest
+    {
+        private const int SCALE = 4;
+        private static readonly SecureRandom RND = new SecureRandom();
+
+        [Test]
+        public void TestSumOfMultiplies()
+        {
+            foreach (X9ECParameters x9 in GetTestCurves())
+            {
+                ECPoint[] points = new ECPoint[SCALE];
+                BigInteger[] scalars = new BigInteger[SCALE];
+                for (int i = 0; i < SCALE; ++i)
+                {
+                    points[i] = GetRandomPoint(x9);
+                    scalars[i] = GetRandomScalar(x9);
+                }
+
+                ECPoint u = x9.Curve.Infinity;
+                for (int i = 0; i < SCALE; ++i)
+                {
+                    u = u.Add(points[i].Multiply(scalars[i]));
+
+                    ECPoint v = ECAlgorithms.SumOfMultiplies(CopyPoints(points, i + 1), CopyScalars(scalars, i + 1));
+
+                    ECPoint[] results = new ECPoint[] { u, v };
+                    x9.Curve.NormalizeAll(results);
+
+                    AssertPointsEqual("ECAlgorithms.SumOfMultiplies is incorrect", results[0], results[1]);
+                }
+            }
+        }
+
+        [Test]
+        public void TestSumOfTwoMultiplies()
+        {
+            foreach (X9ECParameters x9 in GetTestCurves())
+            {
+                ECPoint p = GetRandomPoint(x9);
+                BigInteger a = GetRandomScalar(x9);
+
+                for (int i = 0; i < SCALE; ++i)
+                {
+                    ECPoint q = GetRandomPoint(x9);
+                    BigInteger b = GetRandomScalar(x9);
+
+                    ECPoint u = p.Multiply(a).Add(q.Multiply(b));
+                    ECPoint v = ECAlgorithms.ShamirsTrick(p, a, q, b);
+                    ECPoint w = ECAlgorithms.SumOfTwoMultiplies(p, a, q, b);
+
+                    ECPoint[] results = new ECPoint[] { u, v, w };
+                    x9.Curve.NormalizeAll(results);
+
+                    AssertPointsEqual("ECAlgorithms.ShamirsTrick is incorrect", results[0], results[1]);
+                    AssertPointsEqual("ECAlgorithms.SumOfTwoMultiplies is incorrect", results[0], results[2]);
+
+                    p = q;
+                    a = b;
+                }
+            }
+        }
+
+        private void AssertPointsEqual(string message, ECPoint a, ECPoint b)
+        {
+            Assert.AreEqual(a, b, message);
+        }
+
+        private ECPoint[] CopyPoints(ECPoint[] ps, int len)
+        {
+            ECPoint[] result = new ECPoint[len];
+            Array.Copy(ps, 0, result, 0, len);
+            return result;
+        }
+
+        private BigInteger[] CopyScalars(BigInteger[] ks, int len)
+        {
+            BigInteger[] result = new BigInteger[len];
+            Array.Copy(ks, 0, result, 0, len);
+            return result;
+        }
+
+        private ECPoint GetRandomPoint(X9ECParameters x9)
+        {
+            return x9.G.Multiply(GetRandomScalar(x9));
+        }
+
+        private BigInteger GetRandomScalar(X9ECParameters x9)
+        {
+            return new BigInteger(x9.N.BitLength, RND);
+        }
+
+        private IList GetTestCurves()
+        {
+            ArrayList x9s = new ArrayList();
+            ArrayList names = new ArrayList();
+            CollectionUtilities.AddRange(names, ECNamedCurveTable.Names);
+            CollectionUtilities.AddRange(names, CustomNamedCurves.Names);
+            foreach (string name in names)
+            {
+                X9ECParameters x9 = ECNamedCurveTable.GetByName(name);
+                if (x9 != null)
+                {
+                    AddTestCurves(x9s, x9);
+                }
+
+                x9 = CustomNamedCurves.GetByName(name);
+                if (x9 != null)
+                {
+                    AddTestCurves(x9s, x9);
+                }
+            }
+            return x9s;
+        }
+
+        private void AddTestCurves(IList x9s, X9ECParameters x9)
+        {
+            ECCurve curve = x9.Curve;
+
+            int[] coords = ECCurve.GetAllCoordinateSystems();
+            for (int i = 0; i < coords.Length; ++i)
+            {
+                int coord = coords[i];
+                if (curve.CoordinateSystem == coord)
+                {
+                    x9s.Add(x9);
+                }
+                else if (curve.SupportsCoordinateSystem(coord))
+                {
+                    ECCurve c = curve.Configure().SetCoordinateSystem(coord).Create();
+                    x9s.Add(new X9ECParameters(c, c.ImportPoint(x9.G), x9.N, x9.H));
+                }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/ECPointPerformanceTest.cs b/crypto/test/src/math/ec/test/ECPointPerformanceTest.cs
new file mode 100644
index 000000000..2bcd5b502
--- /dev/null
+++ b/crypto/test/src/math/ec/test/ECPointPerformanceTest.cs
@@ -0,0 +1,209 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Math.EC.Tests
+{
+    /**
+    * Compares the performance of the the window NAF point multiplication against
+    * conventional point multiplication.
+    */
+    [TestFixture, Explicit]
+    public class ECPointPerformanceTest
+    {
+        internal const int MILLIS_PER_ROUND = 200;
+        internal const int MILLIS_WARMUP = 1000;
+
+        internal const int MULTS_PER_CHECK = 16;
+        internal const int NUM_ROUNDS = 10;
+
+        private static string[] COORD_NAMES = new string[]{ "AFFINE", "HOMOGENEOUS", "JACOBIAN", "JACOBIAN-CHUDNOVSKY",
+            "JACOBIAN-MODIFIED", "LAMBDA-AFFINE", "LAMBDA-PROJECTIVE", "SKEWED" };
+
+        private void RandMult(string curveName)
+        {
+            X9ECParameters spec = ECNamedCurveTable.GetByName(curveName);
+            if (spec != null)
+            {
+                RandMult(curveName, spec);
+            }
+
+            spec = CustomNamedCurves.GetByName(curveName);
+            if (spec != null)
+            {
+                RandMult(curveName + " (custom)", spec);
+            }
+        }
+
+        private void RandMult(string label, X9ECParameters spec)
+        {
+            ECCurve C = spec.Curve;
+            ECPoint G = (ECPoint)spec.G;
+            BigInteger n = spec.N;
+
+            SecureRandom random = new SecureRandom();
+            random.SetSeed(DateTimeUtilities.CurrentUnixMs());
+
+            Console.WriteLine(label);
+
+            int[] coords = ECCurve.GetAllCoordinateSystems();
+            for (int i = 0; i < coords.Length; ++i)
+            {
+                int coord = coords[i];
+                if (C.SupportsCoordinateSystem(coord))
+                {
+                    ECCurve c = C;
+                    ECPoint g = G;
+
+                    bool defaultCoord = (c.CoordinateSystem == coord);
+                    if (!defaultCoord)
+                    {
+                        c = C.Configure().SetCoordinateSystem(coord).Create();
+                        g = c.ImportPoint(G);
+                    }
+
+                    double avgRate = RandMult(random, g, n);
+                    string coordName = COORD_NAMES[coord];
+                    StringBuilder sb = new StringBuilder();
+                    sb.Append("   ");
+                    sb.Append(defaultCoord ? '*' : ' ');
+                    sb.Append(coordName);
+                    for (int j = sb.Length; j < 30; ++j)
+                    {
+                        sb.Append(' ');
+                    }
+                    sb.Append(": ");
+                    sb.Append(avgRate);
+                    sb.Append(" mults/sec");
+                    for (int j = sb.Length; j < 64; ++j)
+                    {
+                        sb.Append(' ');
+                    }
+                    sb.Append('(');
+                    sb.Append(1000.0 / avgRate);
+                    sb.Append(" millis/mult)");
+                    Console.WriteLine(sb.ToString());
+                }
+            }
+        }
+
+        private double RandMult(SecureRandom random, ECPoint g, BigInteger n)
+        {
+            BigInteger[] ks = new BigInteger[128];
+            for (int i = 0; i < ks.Length; ++i)
+            {
+                ks[i] = new BigInteger(n.BitLength - 1, random);
+            }
+
+            int ki = 0;
+            ECPoint p = g;
+
+            {
+                long startTime = DateTimeUtilities.CurrentUnixMs();
+                long goalTime = startTime + MILLIS_WARMUP;
+
+                do
+                {
+                    BigInteger k = ks[ki];
+                    p = g.Multiply(k);
+                    if ((ki & 1) != 0)
+                    {
+                        g = p;
+                    }
+                    if (++ki == ks.Length)
+                    {
+                        ki = 0;
+                    }
+                }
+                while (DateTimeUtilities.CurrentUnixMs() < goalTime);
+            }
+
+            double minRate = Double.MaxValue, maxRate = Double.MinValue, totalRate = 0.0;
+
+            for (int i = 1; i <= NUM_ROUNDS; i++)
+            {
+                long startTime = DateTimeUtilities.CurrentUnixMs();
+                long goalTime = startTime + MILLIS_PER_ROUND;
+                long count = 0, endTime;
+
+                do
+                {
+                    ++count;
+
+                    for (int j = 0; j < MULTS_PER_CHECK; ++j)
+                    {
+                        BigInteger k = ks[ki];
+                        p = g.Multiply(k);
+                        if ((ki & 1) != 0)
+                        {
+                            g = p;
+                        }
+                        if (++ki == ks.Length)
+                        {
+                            ki = 0;
+                        }
+                    }
+
+                    endTime = DateTimeUtilities.CurrentUnixMs();
+                }
+                while (endTime < goalTime);
+
+                double roundElapsed = (double)(endTime - startTime);
+                double roundRate = count * MULTS_PER_CHECK * 1000L / roundElapsed;
+
+                minRate = System.Math.Min(minRate, roundRate);
+                maxRate = System.Math.Max(maxRate, roundRate);
+                totalRate += roundRate;
+            }
+
+            return (totalRate - minRate - maxRate) / (NUM_ROUNDS - 2);
+        }
+
+        [Test]
+        public void TestMultiply()
+        {
+            ArrayList nameList = new ArrayList();
+            CollectionUtilities.AddRange(nameList, ECNamedCurveTable.Names);
+            CollectionUtilities.AddRange(nameList, CustomNamedCurves.Names);
+
+            string[] names = (string[])nameList.ToArray(typeof(string));
+            Array.Sort(names);
+            ISet oids = new HashSet();
+            foreach (string name in names)
+            {
+                DerObjectIdentifier oid = ECNamedCurveTable.GetOid(name);
+                if (oid == null)
+                {
+                    oid = CustomNamedCurves.GetOid(name);
+                }
+                if (oid != null)
+                {
+                    if (oids.Contains(oid))
+                        continue;
+
+                    oids.Add(oid);
+                }
+
+                RandMult(name);
+            }
+        }
+
+        public static void Main(string[] args)
+        {
+            new ECPointPerformanceTest().TestMultiply();
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/ECPointTest.cs b/crypto/test/src/math/ec/test/ECPointTest.cs
new file mode 100644
index 000000000..8430f437d
--- /dev/null
+++ b/crypto/test/src/math/ec/test/ECPointTest.cs
@@ -0,0 +1,507 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Math.EC.Tests
+{
+    /**
+     * Test class for {@link org.bouncycastle.math.ec.ECPoint ECPoint}. All
+     * literature values are taken from "Guide to elliptic curve cryptography",
+     * Darrel Hankerson, Alfred J. Menezes, Scott Vanstone, 2004, Springer-Verlag
+     * New York, Inc.
+     */
+    [TestFixture]
+    public class ECPointTest
+    {
+        /**
+         * Random source used to generate random points
+         */
+        private SecureRandom secRand = new SecureRandom();
+
+//		private ECPointTest.Fp fp = null;
+
+//		private ECPointTest.F2m f2m = null;
+
+        /**
+         * Nested class containing sample literature values for <code>Fp</code>.
+         */
+        public class Fp
+        {
+            internal static readonly BigInteger q = new BigInteger("29");
+
+            internal static readonly BigInteger a = new BigInteger("4");
+
+            internal static readonly BigInteger b = new BigInteger("20");
+
+            internal static readonly BigInteger n = new BigInteger("38");
+
+            internal static readonly BigInteger h = new BigInteger("1");
+
+            internal static readonly ECCurve curve = new FpCurve(q, a, b, n, h);
+
+            internal static readonly ECPoint infinity = curve.Infinity;
+
+            internal static readonly int[] pointSource = { 5, 22, 16, 27, 13, 6, 14, 6 };
+
+            internal static ECPoint[] p = new ECPoint[pointSource.Length / 2];
+
+            /**
+             * Creates the points on the curve with literature values.
+             */
+            internal static void CreatePoints()
+            {
+                for (int i = 0; i < pointSource.Length / 2; i++)
+                {
+                    p[i] = curve.CreatePoint(
+                        new BigInteger(pointSource[2 * i].ToString()),
+                        new BigInteger(pointSource[2 * i + 1].ToString()));
+                }
+            }
+        }
+
+        /**
+         * Nested class containing sample literature values for <code>F2m</code>.
+         */
+        public class F2m
+        {
+            // Irreducible polynomial for TPB z^4 + z + 1
+            internal const int m = 4;
+
+            internal const int k1 = 1;
+
+            // a = z^3
+            internal static readonly BigInteger aTpb = new BigInteger("1000", 2);
+
+            // b = z^3 + 1
+            internal static readonly BigInteger bTpb = new BigInteger("1001", 2);
+
+            internal static readonly BigInteger n = new BigInteger("23");
+
+            internal static readonly BigInteger h = new BigInteger("1");
+
+            internal static readonly ECCurve curve = new F2mCurve(m, k1, aTpb, bTpb, n, h);
+
+            internal static readonly ECPoint infinity = curve.Infinity;
+
+            internal static readonly String[] pointSource = { "0010", "1111", "1100", "1100",
+                    "0001", "0001", "1011", "0010" };
+
+            internal static readonly ECPoint[] p = new ECPoint[pointSource.Length / 2];
+
+            /**
+             * Creates the points on the curve with literature values.
+             */
+            internal static void CreatePoints()
+            {
+                for (int i = 0; i < pointSource.Length / 2; i++)
+                {
+                    p[i] = curve.CreatePoint(
+                        new BigInteger(pointSource[2 * i], 2),
+                        new BigInteger(pointSource[2 * i + 1], 2));
+                }
+            }
+        }
+
+        [SetUp]
+        public void setUp()
+        {
+//			fp = new ECPointTest.Fp();
+            Fp.CreatePoints();
+
+//			f2m = new ECPointTest.F2m();
+            F2m.CreatePoints();
+        }
+
+        /**
+         * Tests, if inconsistent points can be created, i.e. points with exactly
+         * one null coordinate (not permitted).
+         */
+        [Test]
+        public void TestPointCreationConsistency()
+        {
+            try
+            {
+                ECPoint bad = Fp.curve.CreatePoint(BigInteger.ValueOf(12), null);
+                Assert.Fail();
+            }
+            catch (ArgumentException)
+            {
+                // Expected
+            }
+
+            try
+            {
+                ECPoint bad = Fp.curve.CreatePoint(null, BigInteger.ValueOf(12));
+                Assert.Fail();
+            }
+            catch (ArgumentException)
+            {
+                // Expected
+            }
+
+            try
+            {
+                ECPoint bad = F2m.curve.CreatePoint(new BigInteger("1011"), null);
+                Assert.Fail();
+            }
+            catch (ArgumentException)
+            {
+                // Expected
+            }
+
+            try
+            {
+                ECPoint bad = F2m.curve.CreatePoint(null, new BigInteger("1011"));
+                Assert.Fail();
+            }
+            catch (ArgumentException)
+            {
+                // Expected
+            }
+        }
+
+        /**
+         * Tests <code>ECPoint.add()</code> against literature values.
+         *
+         * @param p
+         *            The array of literature values.
+         * @param infinity
+         *            The point at infinity on the respective curve.
+         */
+        private void ImplTestAdd(ECPoint[] p, ECPoint infinity)
+        {
+            AssertPointsEqual("p0 plus p1 does not equal p2", p[2], p[0].Add(p[1]));
+            AssertPointsEqual("p1 plus p0 does not equal p2", p[2], p[1].Add(p[0]));
+            for (int i = 0; i < p.Length; i++)
+            {
+                AssertPointsEqual("Adding infinity failed", p[i], p[i].Add(infinity));
+                AssertPointsEqual("Adding to infinity failed", p[i], infinity.Add(p[i]));
+            }
+        }
+
+        /**
+         * Calls <code>implTestAdd()</code> for <code>Fp</code> and
+         * <code>F2m</code>.
+         */
+        [Test]
+        public void TestAdd()
+        {
+            ImplTestAdd(Fp.p, Fp.infinity);
+            ImplTestAdd(F2m.p, F2m.infinity);
+        }
+
+        /**
+         * Tests <code>ECPoint.twice()</code> against literature values.
+         *
+         * @param p
+         *            The array of literature values.
+         */
+        private void ImplTestTwice(ECPoint[] p)
+        {
+            AssertPointsEqual("Twice incorrect", p[3], p[0].Twice());
+            AssertPointsEqual("Add same point incorrect", p[3], p[0].Add(p[0]));
+        }
+
+        /**
+         * Calls <code>implTestTwice()</code> for <code>Fp</code> and
+         * <code>F2m</code>.
+         */
+        [Test]
+        public void TestTwice()
+        {
+            ImplTestTwice(Fp.p);
+            ImplTestTwice(F2m.p);
+        }
+
+        private void ImplTestThreeTimes(ECPoint[] p)
+        {
+            ECPoint P = p[0];
+            ECPoint _3P = P.Add(P).Add(P);
+            AssertPointsEqual("ThreeTimes incorrect", _3P, P.ThreeTimes());
+            AssertPointsEqual("TwicePlus incorrect", _3P, P.TwicePlus(P));
+        }
+
+        /**
+         * Calls <code>implTestThreeTimes()</code> for <code>Fp</code> and
+         * <code>F2m</code>.
+         */
+        [Test]
+        public void TestThreeTimes()
+        {
+            ImplTestThreeTimes(Fp.p);
+            ImplTestThreeTimes(F2m.p);
+        }
+
+        /**
+         * Goes through all points on an elliptic curve and checks, if adding a
+         * point <code>k</code>-times is the same as multiplying the point by
+         * <code>k</code>, for all <code>k</code>. Should be called for points
+         * on very small elliptic curves only.
+         *
+         * @param p
+         *            The base point on the elliptic curve.
+         * @param infinity
+         *            The point at infinity on the elliptic curve.
+         */
+        private void ImplTestAllPoints(ECPoint p, ECPoint infinity)
+        {
+            ECPoint adder = infinity;
+            ECPoint multiplier = infinity;
+
+            BigInteger i = BigInteger.One;
+            do
+            {
+                adder = adder.Add(p);
+                multiplier = p.Multiply(i);
+                AssertPointsEqual("Results of Add() and Multiply() are inconsistent " + i, adder, multiplier);
+                i = i.Add(BigInteger.One);
+            }
+            while (!(adder.Equals(infinity)));
+        }
+
+        /**
+         * Calls <code>implTestAllPoints()</code> for the small literature curves,
+         * both for <code>Fp</code> and <code>F2m</code>.
+         */
+        [Test]
+        public void TestAllPoints()
+        {
+            for (int i = 0; i < Fp.p.Length; i++)
+            {
+                ImplTestAllPoints(Fp.p[0], Fp.infinity);
+            }
+
+            for (int i = 0; i < F2m.p.Length; i++)
+            {
+                ImplTestAllPoints(F2m.p[0], F2m.infinity);
+            }
+        }
+
+        /**
+         * Checks, if the point multiplication algorithm of the given point yields
+         * the same result as point multiplication done by the reference
+         * implementation given in <code>multiply()</code>. This method chooses a
+         * random number by which the given point <code>p</code> is multiplied.
+         *
+         * @param p
+         *            The point to be multiplied.
+         * @param numBits
+         *            The bitlength of the random number by which <code>p</code>
+         *            is multiplied.
+         */
+        private void ImplTestMultiply(ECPoint p, int numBits)
+        {
+            BigInteger k = new BigInteger(numBits, secRand);
+            ECPoint reff = ECAlgorithms.ReferenceMultiply(p, k);
+            ECPoint q = p.Multiply(k);
+            AssertPointsEqual("ECPoint.Multiply is incorrect", reff, q);
+        }
+
+        /**
+         * Checks, if the point multiplication algorithm of the given point yields
+         * the same result as point multiplication done by the reference
+         * implementation given in <code>multiply()</code>. This method tests
+         * multiplication of <code>p</code> by every number of bitlength
+         * <code>numBits</code> or less.
+         *
+         * @param p
+         *            The point to be multiplied.
+         * @param numBits
+         *            Try every multiplier up to this bitlength
+         */
+        private void ImplTestMultiplyAll(ECPoint p, int numBits)
+        {
+            BigInteger bound = BigInteger.One.ShiftLeft(numBits);
+            BigInteger k = BigInteger.Zero;
+
+            do
+            {
+                ECPoint reff = ECAlgorithms.ReferenceMultiply(p, k);
+                ECPoint q = p.Multiply(k);
+                AssertPointsEqual("ECPoint.Multiply is incorrect", reff, q);
+                k = k.Add(BigInteger.One);
+            }
+            while (k.CompareTo(bound) < 0);
+        }
+
+        /**
+         * Tests <code>ECPoint.add()</code> and <code>ECPoint.subtract()</code>
+         * for the given point and the given point at infinity.
+         *
+         * @param p
+         *            The point on which the tests are performed.
+         * @param infinity
+         *            The point at infinity on the same curve as <code>p</code>.
+         */
+        private void ImplTestAddSubtract(ECPoint p, ECPoint infinity)
+        {
+            AssertPointsEqual("Twice and Add inconsistent", p.Twice(), p.Add(p));
+            AssertPointsEqual("Twice p - p is not p", p, p.Twice().Subtract(p));
+            AssertPointsEqual("TwicePlus(p, -p) is not p", p, p.TwicePlus(p.Negate()));
+            AssertPointsEqual("p - p is not infinity", infinity, p.Subtract(p));
+            AssertPointsEqual("p plus infinity is not p", p, p.Add(infinity));
+            AssertPointsEqual("infinity plus p is not p", p, infinity.Add(p));
+            AssertPointsEqual("infinity plus infinity is not infinity ", infinity, infinity.Add(infinity));
+            AssertPointsEqual("Twice infinity is not infinity ", infinity, infinity.Twice());
+        }
+
+        /**
+         * Calls <code>implTestAddSubtract()</code> for literature values, both
+         * for <code>Fp</code> and <code>F2m</code>.
+         */
+        [Test]
+        public void TestAddSubtractMultiplySimple()
+        {
+            int fpBits = Fp.curve.Order.BitLength;
+            for (int iFp = 0; iFp < Fp.pointSource.Length / 2; iFp++)
+            {
+                ImplTestAddSubtract(Fp.p[iFp], Fp.infinity);
+
+                ImplTestMultiplyAll(Fp.p[iFp], fpBits);
+                ImplTestMultiplyAll(Fp.infinity, fpBits);
+            }
+
+            int f2mBits = F2m.curve.Order.BitLength;
+            for (int iF2m = 0; iF2m < F2m.pointSource.Length / 2; iF2m++)
+            {
+                ImplTestAddSubtract(F2m.p[iF2m], F2m.infinity);
+
+                ImplTestMultiplyAll(F2m.p[iF2m], f2mBits);
+                ImplTestMultiplyAll(F2m.infinity, f2mBits);
+            }
+        }
+
+        /**
+         * Test encoding with and without point compression.
+         *
+         * @param p
+         *            The point to be encoded and decoded.
+         */
+        private void ImplTestEncoding(ECPoint p)
+        {
+            // Not Point Compression
+            byte[] unCompBarr = p.GetEncoded(false);
+            ECPoint decUnComp = p.Curve.DecodePoint(unCompBarr);
+            AssertPointsEqual("Error decoding uncompressed point", p, decUnComp);
+
+            // Point compression
+            byte[] compBarr = p.GetEncoded(true);
+            ECPoint decComp = p.Curve.DecodePoint(compBarr);
+            AssertPointsEqual("Error decoding compressed point", p, decComp);
+        }
+
+        private void ImplAddSubtractMultiplyTwiceEncodingTest(ECCurve curve, ECPoint q, BigInteger n)
+        {
+            // Get point at infinity on the curve
+            ECPoint infinity = curve.Infinity;
+
+            ImplTestAddSubtract(q, infinity);
+            ImplTestMultiply(q, n.BitLength);
+            ImplTestMultiply(infinity, n.BitLength);
+
+            ECPoint p = q;
+            for (int i = 0; i < 10; ++i)
+            {
+                ImplTestEncoding(p);
+                p = p.Twice();
+            }
+        }
+
+        private void ImplSqrtTest(ECCurve c)
+        {
+            if (ECAlgorithms.IsFpCurve(c))
+            {
+                BigInteger p = c.Field.Characteristic;
+                BigInteger pMinusOne = p.Subtract(BigInteger.One);
+                BigInteger legendreExponent = p.ShiftRight(1);
+
+                int count = 0;
+                while (count < 10)
+                {
+                    BigInteger nonSquare = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusOne, secRand);
+                    if (!nonSquare.ModPow(legendreExponent, p).Equals(BigInteger.One))
+                    {
+                        ECFieldElement root = c.FromBigInteger(nonSquare).Sqrt();
+                        Assert.IsNull(root);
+                        ++count;
+                    }
+                }
+            }
+        }
+
+        private void ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(X9ECParameters x9ECParameters)
+        {
+            BigInteger n = x9ECParameters.N;
+            ECPoint G = x9ECParameters.G;
+            ECCurve C = x9ECParameters.Curve;
+
+            int[] coords = ECCurve.GetAllCoordinateSystems();
+            for (int i = 0; i < coords.Length; ++i)
+            {
+                int coord = coords[i];
+                if (C.SupportsCoordinateSystem(coord))
+                {
+                    ECCurve c = C;
+                    ECPoint g = G;
+
+                    if (c.CoordinateSystem != coord)
+                    {
+                        c = C.Configure().SetCoordinateSystem(coord).Create();
+                        g = c.ImportPoint(G);
+                    }
+
+                    // The generator is multiplied by random b to get random q
+                    BigInteger b = new BigInteger(n.BitLength, secRand);
+                    ECPoint q = g.Multiply(b).Normalize();
+
+                    ImplAddSubtractMultiplyTwiceEncodingTest(c, q, n);
+
+                    ImplSqrtTest(c);
+                }
+            }
+        }
+
+        /**
+         * Calls <code>implTestAddSubtract()</code>,
+         * <code>implTestMultiply</code> and <code>implTestEncoding</code> for
+         * the standard elliptic curves as given in <code>SecNamedCurves</code>.
+         */
+        [Test]
+        public void TestAddSubtractMultiplyTwiceEncoding()
+        {
+            ArrayList names = new ArrayList();
+            CollectionUtilities.AddRange(names, ECNamedCurveTable.Names);
+            CollectionUtilities.AddRange(names, CustomNamedCurves.Names);
+
+            foreach (string name in names)
+            {
+                X9ECParameters x9ECParameters = ECNamedCurveTable.GetByName(name);
+                if (x9ECParameters != null)
+                {
+                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9ECParameters);
+                }
+
+                x9ECParameters = CustomNamedCurves.GetByName(name);
+                if (x9ECParameters != null)
+                {
+                    ImplAddSubtractMultiplyTwiceEncodingTestAllCoords(x9ECParameters);
+                }
+            }
+        }
+
+        private void AssertPointsEqual(string message, ECPoint a, ECPoint b)
+        {
+            Assert.AreEqual(a, b, message);
+        }
+    }
+}
diff --git a/crypto/test/src/math/ec/test/F2mProofer.cs b/crypto/test/src/math/ec/test/F2mProofer.cs
new file mode 100644
index 000000000..727d32c55
--- /dev/null
+++ b/crypto/test/src/math/ec/test/F2mProofer.cs
@@ -0,0 +1,201 @@
+// TODO Need a replacement for the Java properties class to finish this class
+
+//using System;
+//using System.IO;
+//using System.Text;
+//
+//using Org.BouncyCastle.Asn1.Sec;
+//using Org.BouncyCastle.Asn1.X9;
+//using Org.BouncyCastle.Math.EC;
+//using Org.BouncyCastle.Security;
+//
+//namespace Org.BouncyCastle.Math.EC.Tests
+//{
+//	public class F2mProofer
+//	{
+//		private const int NUM_SAMPLES = 1000;
+//
+//		private static readonly string PATH = "crypto/test/src/org/bouncycastle/math/ec/test/samples/";
+//
+//		private static readonly string INPUT_FILE_NAME_PREFIX = "Input_";
+//
+//		private static readonly string RESULT_FILE_NAME_PREFIX = "Output_";
+//
+//		/**
+//		* The standard curves on which the tests are done
+//		*/
+//		public static readonly string[] Curves = { "sect163r2", "sect233r1",
+//			"sect283r1", "sect409r1", "sect571r1" };
+//
+//		private string pointToString(F2mPoint p)
+//		{
+//			F2mFieldElement x = (F2mFieldElement) p.X;
+//			F2mFieldElement y = (F2mFieldElement) p.Y;
+//
+//			int m = x.M;
+//			int len = m / 2 + 5;
+//
+//			StringBuilder sb = new StringBuilder(len);
+//			sb.Append('(');
+//			sb.Append(x.ToBigInteger().ToString(16));
+//			sb.Append(", ");
+//			sb.Append(y.ToBigInteger().ToString(16));
+//			sb.Append(')');
+//
+//			return sb.ToString();
+//		}
+//
+//		private void generateRandomInput(X9ECParameters x9ECParameters)
+//		{
+//			F2mPoint g = (F2mPoint) x9ECParameters.G;
+//			int m = ((F2mFieldElement) g.X).M;
+//
+//			SecureRandom secRand = new SecureRandom(); //SecureRandom.GetInstance("SHA1PRNG");
+//			Properties inputProps = new Properties();
+//			for (int i = 0; i < NUM_SAMPLES; i++)
+//			{
+//				BigInteger rand = new BigInteger(m, secRand);
+//				inputProps.put(i.ToString(), rand.ToString(16));
+//			}
+//			string bits = m.ToString();
+//			FileStream fos = File.Create(PATH
+//				+ INPUT_FILE_NAME_PREFIX + bits + ".properties");
+//			inputProps.store(fos, "Input Samples of length" + bits);
+//			fos.Close();
+//		}
+//
+//		private void multiplyPoints(X9ECParameters x9ECParameters,
+//			string classPrefix)
+//		{
+//			F2mPoint g = (F2mPoint) x9ECParameters.G;
+//			int m = ((F2mFieldElement) g.X).M;
+//
+//			string inputFileName = PATH + INPUT_FILE_NAME_PREFIX + m
+//				+ ".properties";
+//			Properties inputProps = new Properties();
+//			FileStream fis = File.OpenRead(inputFileName); 
+//			inputProps.load(fis);
+//			fis.Close();
+//
+//			Properties outputProps = new Properties();
+//
+//			for (int i = 0; i < NUM_SAMPLES; i++)
+//			{
+//				BigInteger rand = new BigInteger(inputProps.getProperty(Integer
+//					.ToString(i)), 16);
+//				F2mPoint result = (F2mPoint) g.Multiply(rand).normalize();
+//				string resultStr = pointToString(result);
+//				outputProps.setProperty(i.ToString(), resultStr);
+//			}
+//
+//			string outputFileName = PATH + RESULT_FILE_NAME_PREFIX + classPrefix
+//				+ "_" + m + ".properties";
+//			FileStream fos = File.Create(outputFileName);
+//			outputProps.store(fos, "Output Samples of length" + m);
+//			fos.Close();
+//		}
+//
+//		private Properties loadResults(string classPrefix, int m)
+//		{
+//			FileStream fis = File.OpenRead(PATH
+//				+ RESULT_FILE_NAME_PREFIX + classPrefix + "_" + m + ".properties");
+//			Properties res = new Properties();
+//			res.load(fis);
+//			fis.Close();
+//			return res;
+//		}
+//
+//		private void compareResult(X9ECParameters x9ECParameters,
+//			string classPrefix1, string classPrefix2)
+//		{
+//			F2mPoint g = (F2mPoint) x9ECParameters.G;
+//			int m = ((F2mFieldElement) g.X).M;
+//
+//			Properties res1 = loadResults(classPrefix1, m);
+//			Properties res2 = loadResults(classPrefix2, m);
+//
+//			Set keys = res1.keySet();
+//			Iterator iter = keys.iterator();
+//			while (iter.hasNext())
+//			{
+//				string key = (string) iter.next();
+//				string result1 = res1.getProperty(key);
+//				string result2 = res2.getProperty(key);
+//				if (!(result1.Equals(result2)))
+//				{
+//					Console.Error.WriteLine("Difference found: m = " + m + ", "
+//						+ result1 + " does not equal " + result2);
+//				}
+//			}
+//
+//		}
+//
+//		private static void usage()
+//		{
+//			Console.Error.WriteLine("Usage: F2mProofer [-init | -Multiply <className> "
+//				+ "| -compare <className1> <className2>]");
+//		}
+//
+//		public static void Main(string[] args)
+//		{
+//			if (args.Length == 0)
+//			{
+//				usage();
+//				return;
+//			}
+//			F2mProofer proofer = new F2mProofer();
+//			if (args[0].Equals("-init"))
+//			{
+//				Console.WriteLine("Generating random input...");
+//				for (int i = 0; i < Curves.Length; i++)
+//				{
+//					X9ECParameters x9ECParameters = SecNamedCurves
+//						.GetByName(Curves[i]);
+//					proofer.generateRandomInput(x9ECParameters);
+//				}
+//				Console.WriteLine("Successfully generated random input in " + PATH);
+//			}
+//			else if (args[0].Equals("-compare"))
+//			{
+//				if (args.Length < 3)
+//				{
+//					usage();
+//					return;
+//				}
+//				string classPrefix1 = args[1];
+//				string classPrefix2 = args[2];
+//				Console.WriteLine("Comparing results...");
+//				for (int i = 0; i < Curves.Length; i++)
+//				{
+//					X9ECParameters x9ECParameters = SecNamedCurves
+//						.GetByName(Curves[i]);
+//					proofer.compareResult(x9ECParameters, classPrefix1,
+//						classPrefix2);
+//				}
+//				Console.WriteLine("Successfully compared results in " + PATH);
+//			}
+//			else if (args[0].Equals("-Multiply"))
+//			{
+//				if (args.Length < 2)
+//				{
+//					usage();
+//					return;
+//				}
+//				string classPrefix = args[1];
+//				Console.WriteLine("Multiplying points...");
+//				for (int i = 0; i < Curves.Length; i++)
+//				{
+//					X9ECParameters x9ECParameters = SecNamedCurves
+//						.GetByName(Curves[i]);
+//					proofer.multiplyPoints(x9ECParameters, classPrefix);
+//				}
+//				Console.WriteLine("Successfully generated multiplied points in "
+//					+ PATH);
+//			}
+//			else
+//			{
+//				usage();
+//			}
+//		}
+//	}
+//}
diff --git a/crypto/test/src/math/ec/test/TnafTest.cs b/crypto/test/src/math/ec/test/TnafTest.cs
new file mode 100644
index 000000000..c04ae00d2
--- /dev/null
+++ b/crypto/test/src/math/ec/test/TnafTest.cs
@@ -0,0 +1,158 @@
+//using System;
+//using System.Text;
+//
+//using NUnit.Framework;
+//
+//using Org.BouncyCastle.Asn1.Sec;
+//using Org.BouncyCastle.Asn1.X9;
+//using Org.BouncyCastle.Math.EC.Multiplier;
+//using Org.BouncyCastle.Utilities.Date;
+//
+//namespace Org.BouncyCastle.Math.EC.Tests
+//{
+//	[TestFixture, Explicit]
+//	public class TnafTest
+//	{
+//		private Random m_rand = new Random();
+//
+//		private string ecPointToString(
+//			ECPoint p) 
+//		{
+//			StringBuilder sb = new StringBuilder("x = ");
+//			sb.Append(p.X.ToBigInteger().ToString());
+//			sb.Append("; y = ");
+//			sb.Append(p.Y.ToBigInteger().ToString());
+//			return sb.ToString();
+//		}
+//
+//		private ECPoint repeatedMultiply(ECPoint p, BigInteger k)
+//		{
+//			ECPoint result = p.Multiply(k);
+//			for (int i = 1; i < 10; ++i)
+//			{
+//				ECPoint check = p.Multiply(k);
+//				Assert.AreEqual(result, check);
+//			}
+//			return result;
+//		}
+//
+//		private void ImplTestMultiplyTnaf(string curveName) 
+//		{
+//			X9ECParameters x9ECParameters = SecNamedCurves.GetByName(curveName);
+//
+//			F2mCurve curve = (F2mCurve)x9ECParameters.Curve;
+//			BigInteger n = curve.N;
+//
+//			// The generator is multiplied by random b to get random q
+//			BigInteger b = new BigInteger(n.BitLength, m_rand);
+//			ECPoint g = x9ECParameters.G;
+//			F2mPoint p = (F2mPoint) g.Multiply(b);
+//
+//			BigInteger k = new BigInteger(n.BitLength, m_rand);
+//			long now1 = DateTimeUtilities.CurrentUnixMs();
+//			p.SetECMultiplier(new WTauNafMultiplier());
+//			ECPoint refRWTnaf = repeatedMultiply(p, k);
+//			long now2 = DateTimeUtilities.CurrentUnixMs();
+//			p.SetECMultiplier(new WNafMultiplier());
+//			ECPoint refWnaf = repeatedMultiply(p, k);
+//			long now3 = DateTimeUtilities.CurrentUnixMs();
+//			p.SetECMultiplier(new FpNafMultiplier());
+//			ECPoint refFpNaf = repeatedMultiply(p, k);
+//			long now4 = DateTimeUtilities.CurrentUnixMs();
+//			p.SetECMultiplier(new ReferenceMultiplier());
+//			ECPoint reference = repeatedMultiply(p, k);
+//			long now5 = DateTimeUtilities.CurrentUnixMs();
+//
+//			Assert.AreEqual(reference, refRWTnaf, "WTNAF multiplication is incorrect");
+//			Assert.AreEqual(reference, refFpNaf, "FPNAF multiplication is incorrect");
+//			Assert.AreEqual(reference, refWnaf, "WNAF multiplication is incorrect");
+//
+//			Console.WriteLine(curveName + ": Multiply WTNAF took millis:  " + (now2 - now1));
+//			Console.WriteLine(curveName + ": Multiply WNAF took millis:   " + (now3 - now2));
+//			Console.WriteLine(curveName + ": Multiply FPNAF took millis:  " + (now4 - now3));
+//			Console.WriteLine(curveName + ": Multiply REFE took millis:   " + (now5 - now4));
+//
+////			Console.WriteLine(curveName + ": refRWTnaf  = " + ecPointToString(refRWTnaf));
+////			Console.WriteLine(curveName + ": refWnaf    = " + ecPointToString(refWnaf));
+////			Console.WriteLine(curveName + ": refFpNaf   = " + ecPointToString(refFpNaf));
+////			Console.WriteLine(curveName + ": reference  = " + ecPointToString(reference) + "\n");
+//			Console.WriteLine();
+//		}
+//
+//		[Test]
+//		public void TestMultiplyTnaf() 
+//		{
+//			Console.WriteLine("\n\n\n*****  Start test multiplications on F2m (Koblitz) *****");
+//			ImplTestMultiplyTnaf("sect163k1");
+//			ImplTestMultiplyTnaf("sect233k1");
+//			ImplTestMultiplyTnaf("sect239k1");
+//			ImplTestMultiplyTnaf("sect283k1");
+//			ImplTestMultiplyTnaf("sect409k1");
+//			ImplTestMultiplyTnaf("sect571k1");
+//		}
+//
+//		private void ImplTestMultiplyWnaf(String curveName) 
+//		{
+//			X9ECParameters x9ECParameters = SecNamedCurves.GetByName(curveName);
+//
+//			BigInteger r = x9ECParameters.N;
+//
+//			// The generator is multiplied by random b to get random q
+//			BigInteger b = new BigInteger(r.BitLength, m_rand);
+//			ECPoint g = x9ECParameters.G;
+//			ECPoint p = g.Multiply(b);
+//
+//			BigInteger k = new BigInteger(r.BitLength, m_rand);
+//			long now1 = DateTimeUtilities.CurrentUnixMs();
+//			p.SetECMultiplier(new WNafMultiplier());
+//			ECPoint refWnaf = repeatedMultiply(p, k);
+//			long now2 = DateTimeUtilities.CurrentUnixMs();
+//			p.SetECMultiplier(new FpNafMultiplier());
+//			ECPoint refFpNaf = repeatedMultiply(p, k);
+//			long now3 = DateTimeUtilities.CurrentUnixMs();
+//			p.SetECMultiplier(new ReferenceMultiplier());
+//			ECPoint reference = repeatedMultiply(p, k);
+//			long now4 = DateTimeUtilities.CurrentUnixMs();
+//
+//			Assert.AreEqual(reference, refWnaf, "WNAF multiplication is incorrect");
+//			Assert.AreEqual(reference, refFpNaf, "FPNAF multiplication is incorrect");
+//
+//			Console.WriteLine(curveName + ": Multiply WNAF took millis:   " + (now2 - now1));
+//			Console.WriteLine(curveName + ": Multiply FPNAF took millis:  " + (now3 - now2));
+//			Console.WriteLine(curveName + ": Multiply REFE took millis:   " + (now4 - now3));
+//
+////			Console.WriteLine(curveName + ": refWnaf    = " + ecPointToString(refWnaf));
+////			Console.WriteLine(curveName + ": refFpNaf   = " + ecPointToString(refFpNaf));
+////			Console.WriteLine(curveName + ": reference  = " + ecPointToString(reference));
+//			Console.WriteLine();
+//		}
+//
+//		[Test]
+//		public void TestMultiplyWnaf() 
+//		{
+//			Console.WriteLine("\n\n\n*****  Start test multiplications on F2m *****");
+//			ImplTestMultiplyWnaf("sect113r1");
+//			ImplTestMultiplyWnaf("sect113r2");
+//			ImplTestMultiplyWnaf("sect131r1");
+//			ImplTestMultiplyWnaf("sect131r2");
+//			ImplTestMultiplyWnaf("sect163r1");
+//			ImplTestMultiplyWnaf("sect163r2");
+//			ImplTestMultiplyWnaf("sect193r1");
+//			ImplTestMultiplyWnaf("sect193r2");
+//			ImplTestMultiplyWnaf("sect233r1");
+//			ImplTestMultiplyWnaf("sect283r1");
+//			ImplTestMultiplyWnaf("sect409r1");
+//			ImplTestMultiplyWnaf("sect571r1");
+//
+//			Console.WriteLine("\n\n\n*****  Start test multiplications on Fp  *****");
+//			ImplTestMultiplyWnaf("secp112r1");
+//			ImplTestMultiplyWnaf("secp128r1");
+//			ImplTestMultiplyWnaf("secp160r1");
+//			ImplTestMultiplyWnaf("secp192r1");
+//			ImplTestMultiplyWnaf("secp224r1");
+//			ImplTestMultiplyWnaf("secp256r1");
+//			ImplTestMultiplyWnaf("secp384r1");
+//			ImplTestMultiplyWnaf("secp521r1");
+//		}
+//	}
+//}
diff --git a/crypto/test/src/math/test/AllTests.cs b/crypto/test/src/math/test/AllTests.cs
new file mode 100644
index 000000000..6f2b50140
--- /dev/null
+++ b/crypto/test/src/math/test/AllTests.cs
@@ -0,0 +1,27 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Math.Tests
+{
+    public class AllTests
+    {
+        public static void Main(
+			string[] args)
+        {
+//            junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            suite().Run(el);
+        }
+
+        public static TestSuite suite()
+        {
+			TestSuite suite = new TestSuite("Math tests");
+
+			suite.Add(new BigIntegerTest());
+
+			return suite;
+        }
+    }
+}
diff --git a/crypto/test/src/math/test/BigIntegerTest.cs b/crypto/test/src/math/test/BigIntegerTest.cs
new file mode 100644
index 000000000..8196cc6ec
--- /dev/null
+++ b/crypto/test/src/math/test/BigIntegerTest.cs
@@ -0,0 +1,1048 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Math.Tests
+{
+    [TestFixture]
+    public class BigIntegerTest
+    {
+        private static Random random = new Random();
+
+        [Test]
+        public void MonoBug81857()
+        {
+            BigInteger b = new BigInteger("18446744073709551616");
+            BigInteger exp = BigInteger.Two;
+            BigInteger mod = new BigInteger("48112959837082048697");
+            BigInteger expected = new BigInteger("4970597831480284165");
+
+            BigInteger manual = b.Multiply(b).Mod(mod);
+            Assert.AreEqual(expected, manual, "b * b % mod");
+        }
+
+        [Test]
+        public void TestAbs()
+        {
+            Assert.AreEqual(zero, zero.Abs());
+
+            Assert.AreEqual(one, one.Abs());
+            Assert.AreEqual(one, minusOne.Abs());
+
+            Assert.AreEqual(two, two.Abs());
+            Assert.AreEqual(two, minusTwo.Abs());
+        }
+
+        [Test]
+        public void TestAdd()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(
+                        val(i + j),
+                        val(i).Add(val(j)),
+                        "Problem: " + i + ".Add(" + j + ") should be " + (i + j));
+                }
+            }
+        }
+
+        [Test]
+        public void TestAnd()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(
+                        val(i & j),
+                        val(i).And(val(j)),
+                        "Problem: " + i + " AND " + j + " should be " + (i & j));
+                }
+            }
+        }
+
+        [Test]
+        public void TestAndNot()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(
+                        val(i & ~j),
+                        val(i).AndNot(val(j)),
+                        "Problem: " + i + " AND NOT " + j + " should be " + (i & ~j));
+                }
+            }
+        }
+
+        [Test]
+        public void TestBitCount()
+        {
+            Assert.AreEqual(0, zero.BitCount);
+            Assert.AreEqual(1, one.BitCount);
+            Assert.AreEqual(0, minusOne.BitCount);
+            Assert.AreEqual(1, two.BitCount);
+            Assert.AreEqual(1, minusTwo.BitCount);
+
+            for (int i = 0; i < 100; ++i)
+            {
+                BigInteger pow2 = one.ShiftLeft(i);
+
+                Assert.AreEqual(1, pow2.BitCount);
+                Assert.AreEqual(i, pow2.Negate().BitCount);
+            }
+
+            for (int i = 0; i < 10; ++i)
+            {
+                BigInteger test = new BigInteger(128, 0, random);
+                int bitCount = 0;
+
+                for (int bit = 0; bit < test.BitLength; ++bit)
+                {
+                    if (test.TestBit(bit))
+                    {
+                        ++bitCount;
+                    }
+                }
+
+                Assert.AreEqual(bitCount, test.BitCount);
+            }
+        }
+
+        [Test]
+        public void TestBitLength()
+        {
+            Assert.AreEqual(0, zero.BitLength);
+            Assert.AreEqual(1, one.BitLength);
+            Assert.AreEqual(0, minusOne.BitLength);
+            Assert.AreEqual(2, two.BitLength);
+            Assert.AreEqual(1, minusTwo.BitLength);
+
+            for (int i = 0; i < 100; ++i)
+            {
+                int bit = i + random.Next(64);
+                BigInteger odd = new BigInteger(bit, random).SetBit(bit + 1).SetBit(0);
+                BigInteger pow2 = one.ShiftLeft(bit);
+
+                Assert.AreEqual(bit + 2, odd.BitLength);
+                Assert.AreEqual(bit + 2, odd.Negate().BitLength);
+                Assert.AreEqual(bit + 1, pow2.BitLength);
+                Assert.AreEqual(bit, pow2.Negate().BitLength);
+            }
+        }
+
+        [Test]
+        public void TestClearBit()
+        {
+            Assert.AreEqual(zero, zero.ClearBit(0));
+            Assert.AreEqual(zero, one.ClearBit(0));
+            Assert.AreEqual(two, two.ClearBit(0));
+
+            Assert.AreEqual(zero, zero.ClearBit(1));
+            Assert.AreEqual(one, one.ClearBit(1));
+            Assert.AreEqual(zero, two.ClearBit(1));
+
+            // TODO Tests for clearing bits in negative numbers
+
+            // TODO Tests for clearing extended bits
+
+            for (int i = 0; i < 10; ++i)
+            {
+                BigInteger n = new BigInteger(128, random);
+
+                for (int j = 0; j < 10; ++j)
+                {
+                    int pos = random.Next(128);
+                    BigInteger m = n.ClearBit(pos);
+                    bool test = m.ShiftRight(pos).Remainder(two).Equals(one);
+
+                    Assert.IsFalse(test);
+                }
+            }
+
+            for (int i = 0; i < 100; ++i)
+            {
+                BigInteger pow2 = one.ShiftLeft(i);
+                BigInteger minusPow2 = pow2.Negate();
+
+                Assert.AreEqual(zero, pow2.ClearBit(i));
+                Assert.AreEqual(minusPow2.ShiftLeft(1), minusPow2.ClearBit(i));
+
+                BigInteger bigI = BigInteger.ValueOf(i);
+                BigInteger negI = bigI.Negate();
+
+                for (int j = 0; j < 10; ++j)
+                {
+                    string data = "i=" + i + ", j=" + j;
+                    Assert.AreEqual(bigI.AndNot(one.ShiftLeft(j)), bigI.ClearBit(j), data);
+                    Assert.AreEqual(negI.AndNot(one.ShiftLeft(j)), negI.ClearBit(j), data);
+                }
+            }
+        }
+
+        [Test]
+        public void TestCompareTo()
+        {
+            Assert.AreEqual(0, minusTwo.CompareTo(minusTwo));
+            Assert.AreEqual(-1, minusTwo.CompareTo(minusOne));
+            Assert.AreEqual(-1, minusTwo.CompareTo(zero));
+            Assert.AreEqual(-1, minusTwo.CompareTo(one));
+            Assert.AreEqual(-1, minusTwo.CompareTo(two));
+
+            Assert.AreEqual(1, minusOne.CompareTo(minusTwo));
+            Assert.AreEqual(0, minusOne.CompareTo(minusOne));
+            Assert.AreEqual(-1, minusOne.CompareTo(zero));
+            Assert.AreEqual(-1, minusOne.CompareTo(one));
+            Assert.AreEqual(-1, minusOne.CompareTo(two));
+
+            Assert.AreEqual(1, zero.CompareTo(minusTwo));
+            Assert.AreEqual(1, zero.CompareTo(minusOne));
+            Assert.AreEqual(0, zero.CompareTo(zero));
+            Assert.AreEqual(-1, zero.CompareTo(one));
+            Assert.AreEqual(-1, zero.CompareTo(two));
+
+            Assert.AreEqual(1, one.CompareTo(minusTwo));
+            Assert.AreEqual(1, one.CompareTo(minusOne));
+            Assert.AreEqual(1, one.CompareTo(zero));
+            Assert.AreEqual(0, one.CompareTo(one));
+            Assert.AreEqual(-1, one.CompareTo(two));
+
+            Assert.AreEqual(1, two.CompareTo(minusTwo));
+            Assert.AreEqual(1, two.CompareTo(minusOne));
+            Assert.AreEqual(1, two.CompareTo(zero));
+            Assert.AreEqual(1, two.CompareTo(one));
+            Assert.AreEqual(0, two.CompareTo(two));
+        }
+
+        [Test]
+        public void TestConstructors()
+        {
+            Assert.AreEqual(BigInteger.Zero, new BigInteger(new byte[]{ 0 }));
+            Assert.AreEqual(BigInteger.Zero, new BigInteger(new byte[]{ 0, 0 }));
+
+            for (int i = 0; i < 10; ++i)
+            {
+                Assert.IsTrue(new BigInteger(i + 3, 0, random).TestBit(0));
+            }
+
+            // TODO Other constructors
+        }
+
+        [Test]
+        public void TestDivide()
+        {
+            for (int i = -5; i <= 5; ++i)
+            {
+                try
+                {
+                    val(i).Divide(zero);
+                    Assert.Fail("expected ArithmeticException");
+                }
+                catch (ArithmeticException) {}
+            }
+
+            int product = 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9;
+            int productPlus = product + 1;
+
+            BigInteger bigProduct = val(product);
+            BigInteger bigProductPlus = val(productPlus);
+
+            for (int divisor = 1; divisor < 10; ++divisor)
+            {
+                // Exact division
+                BigInteger expected = val(product / divisor);
+
+                Assert.AreEqual(expected, bigProduct.Divide(val(divisor)));
+                Assert.AreEqual(expected.Negate(), bigProduct.Negate().Divide(val(divisor)));
+                Assert.AreEqual(expected.Negate(), bigProduct.Divide(val(divisor).Negate()));
+                Assert.AreEqual(expected, bigProduct.Negate().Divide(val(divisor).Negate()));
+
+                expected = val((product + 1)/divisor);
+
+                Assert.AreEqual(expected, bigProductPlus.Divide(val(divisor)));
+                Assert.AreEqual(expected.Negate(), bigProductPlus.Negate().Divide(val(divisor)));
+                Assert.AreEqual(expected.Negate(), bigProductPlus.Divide(val(divisor).Negate()));
+                Assert.AreEqual(expected, bigProductPlus.Negate().Divide(val(divisor).Negate()));
+            }
+
+            for (int rep = 0; rep < 10; ++rep)
+            {
+                BigInteger a = new BigInteger(100 - rep, 0, random);
+                BigInteger b = new BigInteger(100 + rep, 0, random);
+                BigInteger c = new BigInteger(10 + rep, 0, random);
+                BigInteger d = a.Multiply(b).Add(c);
+                BigInteger e = d.Divide(a);
+
+                Assert.AreEqual(b, e);
+            }
+
+            // Special tests for power of two since uses different code path internally
+            for (int i = 0; i < 100; ++i)
+            {
+                int shift = random.Next(64);
+                BigInteger a = one.ShiftLeft(shift);
+                BigInteger b = new BigInteger(64 + random.Next(64), random);
+                BigInteger bShift = b.ShiftRight(shift);
+
+                string data = "shift=" + shift +", b=" + b.ToString(16);
+
+                Assert.AreEqual(bShift, b.Divide(a), data);
+                Assert.AreEqual(bShift.Negate(), b.Divide(a.Negate()), data);
+                Assert.AreEqual(bShift.Negate(), b.Negate().Divide(a), data);
+                Assert.AreEqual(bShift, b.Negate().Divide(a.Negate()), data);
+            }
+
+            // Regression
+            {
+                int shift = 63;
+                BigInteger a = one.ShiftLeft(shift);
+                BigInteger b = new BigInteger(1, Hex.Decode("2504b470dc188499"));
+                BigInteger bShift = b.ShiftRight(shift);
+
+                string data = "shift=" + shift +", b=" + b.ToString(16);
+
+                Assert.AreEqual(bShift, b.Divide(a), data);
+                Assert.AreEqual(bShift.Negate(), b.Divide(a.Negate()), data);
+//				Assert.AreEqual(bShift.Negate(), b.Negate().Divide(a), data);
+                Assert.AreEqual(bShift, b.Negate().Divide(a.Negate()), data);
+            }
+        }
+
+        [Test]
+        public void TestDivideAndRemainder()
+        {
+            // TODO More basic tests
+
+            BigInteger n = new BigInteger(48, random);
+            BigInteger[] qr = n.DivideAndRemainder(n);
+            Assert.AreEqual(one, qr[0]);
+            Assert.AreEqual(zero, qr[1]);
+            qr = n.DivideAndRemainder(one);
+            Assert.AreEqual(n, qr[0]);
+            Assert.AreEqual(zero, qr[1]);
+
+            for (int rep = 0; rep < 10; ++rep)
+            {
+                BigInteger a = new BigInteger(100 - rep, 0, random);
+                BigInteger b = new BigInteger(100 + rep, 0, random);
+                BigInteger c = new BigInteger(10 + rep, 0, random);
+                BigInteger d = a.Multiply(b).Add(c);
+                BigInteger[] es = d.DivideAndRemainder(a);
+
+                Assert.AreEqual(b, es[0]);
+                Assert.AreEqual(c, es[1]);
+            }
+
+            // Special tests for power of two since uses different code path internally
+            for (int i = 0; i < 100; ++i)
+            {
+                int shift = random.Next(64);
+                BigInteger a = one.ShiftLeft(shift);
+                BigInteger b = new BigInteger(64 + random.Next(64), random);
+                BigInteger bShift = b.ShiftRight(shift);
+                BigInteger bMod = b.And(a.Subtract(one));
+
+                string data = "shift=" + shift +", b=" + b.ToString(16);
+
+                qr = b.DivideAndRemainder(a);
+                Assert.AreEqual(bShift, qr[0], data);
+                Assert.AreEqual(bMod, qr[1], data);
+
+                qr = b.DivideAndRemainder(a.Negate());
+                Assert.AreEqual(bShift.Negate(), qr[0], data);
+                Assert.AreEqual(bMod, qr[1], data);
+
+                qr = b.Negate().DivideAndRemainder(a);
+                Assert.AreEqual(bShift.Negate(), qr[0], data);
+                Assert.AreEqual(bMod.Negate(), qr[1], data);
+
+                qr = b.Negate().DivideAndRemainder(a.Negate());
+                Assert.AreEqual(bShift, qr[0], data);
+                Assert.AreEqual(bMod.Negate(), qr[1], data);
+            }
+        }
+
+        [Test]
+        public void TestFlipBit()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                BigInteger a = new BigInteger(128, 0, random);
+                BigInteger b = a;
+
+                for (int x = 0; x < 100; ++x)
+                {
+                    // Note: Intentionally greater than initial size
+                    int pos = random.Next(256);
+
+                    a = a.FlipBit(pos);
+                    b = b.TestBit(pos) ? b.ClearBit(pos) : b.SetBit(pos);
+                }
+
+                Assert.AreEqual(a, b);
+            }
+
+            for (int i = 0; i < 100; ++i)
+            {
+                BigInteger pow2 = one.ShiftLeft(i);
+                BigInteger minusPow2 = pow2.Negate();
+
+                Assert.AreEqual(zero, pow2.FlipBit(i));
+                Assert.AreEqual(minusPow2.ShiftLeft(1), minusPow2.FlipBit(i));
+
+                BigInteger bigI = BigInteger.ValueOf(i);
+                BigInteger negI = bigI.Negate();
+
+                for (int j = 0; j < 10; ++j)
+                {
+                    string data = "i=" + i + ", j=" + j;
+                    Assert.AreEqual(bigI.Xor(one.ShiftLeft(j)), bigI.FlipBit(j), data);
+                    Assert.AreEqual(negI.Xor(one.ShiftLeft(j)), negI.FlipBit(j), data);
+                }
+            }
+        }
+
+        [Test]
+        public void TestGcd()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                BigInteger fac = new BigInteger(32, random).Add(two);
+                BigInteger p1 = BigInteger.ProbablePrime(63, random);
+                BigInteger p2 = BigInteger.ProbablePrime(64, random);
+
+                BigInteger gcd = fac.Multiply(p1).Gcd(fac.Multiply(p2));
+
+                Assert.AreEqual(fac, gcd);
+            }
+        }
+
+        [Test]
+        public void TestGetLowestSetBit()
+        {
+            for (int i = 1; i <= 100; ++i)
+            {
+                BigInteger test = new BigInteger(i + 1, 0, random).Add(one);
+                int bit1 = test.GetLowestSetBit();
+                Assert.AreEqual(test, test.ShiftRight(bit1).ShiftLeft(bit1));
+                int bit2 = test.ShiftLeft(i + 1).GetLowestSetBit();
+                Assert.AreEqual(i + 1, bit2 - bit1);
+                int bit3 = test.ShiftLeft(3 * i).GetLowestSetBit();
+                Assert.AreEqual(3 * i, bit3 - bit1);
+            }
+        }
+
+        [Test]
+        public void TestIntValue()
+        {
+            int[] tests = new int[]{ int.MinValue, -1234, -10, -1, 0, ~0, 1, 10, 5678, int.MaxValue };
+
+            foreach (int test in tests)
+            {
+                Assert.AreEqual(test, val(test).IntValue);
+            }
+
+            // TODO Tests for large numbers
+        }
+
+        [Test]
+        public void TestIsProbablePrime()
+        {
+            Assert.IsFalse(zero.IsProbablePrime(100));
+            Assert.IsFalse(zero.IsProbablePrime(100));
+            Assert.IsTrue(zero.IsProbablePrime(0));
+            Assert.IsTrue(zero.IsProbablePrime(-10));
+            Assert.IsFalse(minusOne.IsProbablePrime(100));
+            Assert.IsTrue(minusTwo.IsProbablePrime(100));
+            Assert.IsTrue(val(-17).IsProbablePrime(100));
+            Assert.IsTrue(val(67).IsProbablePrime(100));
+            Assert.IsTrue(val(773).IsProbablePrime(100));
+
+            foreach (int p in firstPrimes)
+            {
+                Assert.IsTrue(val(p).IsProbablePrime(100));
+                Assert.IsTrue(val(-p).IsProbablePrime(100));
+            }
+
+            foreach (int c in nonPrimes)
+            {
+                Assert.IsFalse(val(c).IsProbablePrime(100));
+                Assert.IsFalse(val(-c).IsProbablePrime(100));
+            }
+
+            foreach (int e in mersennePrimeExponents)
+            {
+                Assert.IsTrue(mersenne(e).IsProbablePrime(100));
+                Assert.IsTrue(mersenne(e).Negate().IsProbablePrime(100));
+            }
+
+            foreach (int e in nonPrimeExponents)
+            {
+                Assert.IsFalse(mersenne(e).IsProbablePrime(100));
+                Assert.IsFalse(mersenne(e).Negate().IsProbablePrime(100));
+            }
+
+            // TODO Other examples of 'tricky' values?
+        }
+
+        [Test]
+        public void TestLongValue()
+        {
+            long[] tests = new long[]{ long.MinValue, -1234, -10, -1, 0L, ~0L, 1, 10, 5678, long.MaxValue };
+
+            foreach (long test in tests)
+            {
+                Assert.AreEqual(test, val(test).LongValue);
+            }
+
+            // TODO Tests for large numbers
+        }
+
+        [Test]
+        public void TestMax()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(val(System.Math.Max(i, j)), val(i).Max(val(j)));
+                }
+            }
+        }
+
+        [Test]
+        public void TestMin()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(val(System.Math.Min(i, j)), val(i).Min(val(j)));
+                }
+            }
+        }
+
+        [Test]
+        public void TestMod()
+        {
+            // TODO Basic tests
+
+            for (int rep = 0; rep < 100; ++rep)
+            {
+                int diff = random.Next(25);
+                BigInteger a = new BigInteger(100 - diff, 0, random);
+                BigInteger b = new BigInteger(100 + diff, 0, random);
+                BigInteger c = new BigInteger(10 + diff, 0, random);
+
+                BigInteger d = a.Multiply(b).Add(c);
+                BigInteger e = d.Mod(a);
+                Assert.AreEqual(c, e);
+
+                BigInteger pow2 = one.ShiftLeft(random.Next(128));
+                Assert.AreEqual(b.And(pow2.Subtract(one)), b.Mod(pow2));
+            }
+        }
+
+        [Test]
+        public void TestModInverse()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                BigInteger p = BigInteger.ProbablePrime(64, random);
+                BigInteger q = new BigInteger(63, random).Add(one);
+                BigInteger inv = q.ModInverse(p);
+                BigInteger inv2 = inv.ModInverse(p);
+
+                Assert.AreEqual(q, inv2);
+                Assert.AreEqual(one, q.Multiply(inv).Mod(p));
+            }
+
+            // ModInverse a power of 2 for a range of powers
+            for (int i = 1; i <= 128; ++i)
+            {
+                BigInteger m = one.ShiftLeft(i);
+                BigInteger d = new BigInteger(i, random).SetBit(0);
+                BigInteger x = d.ModInverse(m);
+                BigInteger check = x.Multiply(d).Mod(m);
+
+                Assert.AreEqual(one, check);
+            }
+        }
+
+        [Test]
+        public void TestModPow()
+        {
+            try
+            {
+                two.ModPow(one, zero);
+                Assert.Fail("expected ArithmeticException");
+            }
+            catch (ArithmeticException) {}
+
+            Assert.AreEqual(zero, zero.ModPow(zero, one));
+            Assert.AreEqual(one, zero.ModPow(zero, two));
+            Assert.AreEqual(zero, two.ModPow(one, one));
+            Assert.AreEqual(one, two.ModPow(zero, two));
+
+            for (int i = 0; i < 100; ++i)
+            {
+                BigInteger m = BigInteger.ProbablePrime(10 + i, random);
+                BigInteger x = new BigInteger(m.BitLength - 1, random);
+
+                Assert.AreEqual(x, x.ModPow(m, m));
+                if (x.SignValue != 0)
+                {
+                    Assert.AreEqual(zero, zero.ModPow(x, m));
+                    Assert.AreEqual(one, x.ModPow(m.Subtract(one), m));
+                }
+
+                BigInteger y = new BigInteger(m.BitLength - 1, random);
+                BigInteger n = new BigInteger(m.BitLength - 1, random);
+                BigInteger n3 = n.ModPow(three, m);
+
+                BigInteger resX = n.ModPow(x, m);
+                BigInteger resY = n.ModPow(y, m);
+                BigInteger res = resX.Multiply(resY).Mod(m);
+                BigInteger res3 = res.ModPow(three, m);
+
+                Assert.AreEqual(res3, n3.ModPow(x.Add(y), m));
+
+                BigInteger a = x.Add(one); // Make sure it's not zero
+                BigInteger b = y.Add(one); // Make sure it's not zero
+
+                Assert.AreEqual(a.ModPow(b, m).ModInverse(m), a.ModPow(b.Negate(), m));
+            }
+        }
+
+        [Test]
+        public void TestMultiply()
+        {
+            BigInteger one = BigInteger.One;
+
+            Assert.AreEqual(one, one.Negate().Multiply(one.Negate()));
+
+            for (int i = 0; i < 100; ++i)
+            {
+                int aLen = 64 + random.Next(64);
+                int bLen = 64 + random.Next(64);
+
+                BigInteger a = new BigInteger(aLen, random).SetBit(aLen);
+                BigInteger b = new BigInteger(bLen, random).SetBit(bLen);
+                BigInteger c = new BigInteger(32, random);
+
+                BigInteger ab = a.Multiply(b);
+                BigInteger bc = b.Multiply(c);
+
+                Assert.AreEqual(ab.Add(bc), a.Add(c).Multiply(b));
+                Assert.AreEqual(ab.Subtract(bc), a.Subtract(c).Multiply(b));
+            }
+
+            // Special tests for power of two since uses different code path internally
+            for (int i = 0; i < 100; ++i)
+            {
+                int shift = random.Next(64);
+                BigInteger a = one.ShiftLeft(shift);
+                BigInteger b = new BigInteger(64 + random.Next(64), random);
+                BigInteger bShift = b.ShiftLeft(shift);
+
+                Assert.AreEqual(bShift, a.Multiply(b));
+                Assert.AreEqual(bShift.Negate(), a.Multiply(b.Negate()));
+                Assert.AreEqual(bShift.Negate(), a.Negate().Multiply(b));
+                Assert.AreEqual(bShift, a.Negate().Multiply(b.Negate()));
+
+                Assert.AreEqual(bShift, b.Multiply(a));
+                Assert.AreEqual(bShift.Negate(), b.Multiply(a.Negate()));
+                Assert.AreEqual(bShift.Negate(), b.Negate().Multiply(a));
+                Assert.AreEqual(bShift, b.Negate().Multiply(a.Negate()));
+            }
+        }
+
+        [Test]
+        public void TestNegate()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                Assert.AreEqual(val(-i), val(i).Negate());
+            }
+        }
+
+        [Test]
+        public void TestNextProbablePrime()
+        {
+            BigInteger firstPrime = BigInteger.ProbablePrime(32, random);
+            BigInteger nextPrime = firstPrime.NextProbablePrime();
+
+            Assert.IsTrue(firstPrime.IsProbablePrime(10));
+            Assert.IsTrue(nextPrime.IsProbablePrime(10));
+
+            BigInteger check = firstPrime.Add(one);
+
+            while (check.CompareTo(nextPrime) < 0)
+            {
+                Assert.IsFalse(check.IsProbablePrime(10));
+                check = check.Add(one);
+            }
+        }
+
+        [Test]
+        public void TestNot()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                Assert.AreEqual(
+                    val(~i),
+                    val(i).Not(),
+                    "Problem: ~" + i + " should be " + ~i);
+            }
+        }
+
+        [Test]
+        public void TestOr()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(
+                        val(i | j),
+                        val(i).Or(val(j)),
+                        "Problem: " + i + " OR " + j + " should be " + (i | j));
+                }
+            }
+        }
+
+        [Test]
+        public void TestPow()
+        {
+            Assert.AreEqual(one, zero.Pow(0));
+            Assert.AreEqual(zero, zero.Pow(123));
+            Assert.AreEqual(one, one.Pow(0));
+            Assert.AreEqual(one, one.Pow(123));
+
+            Assert.AreEqual(two.Pow(147), one.ShiftLeft(147));
+            Assert.AreEqual(one.ShiftLeft(7).Pow(11), one.ShiftLeft(77));
+
+            BigInteger n = new BigInteger("1234567890987654321");
+            BigInteger result = one;
+
+            for (int i = 0; i < 10; ++i)
+            {
+                try
+                {
+                    val(i).Pow(-1);
+                    Assert.Fail("expected ArithmeticException");
+                }
+                catch (ArithmeticException) {}
+
+                Assert.AreEqual(result, n.Pow(i));
+
+                result = result.Multiply(n);
+            }
+        }
+
+        [Test]
+        public void TestRemainder()
+        {
+            // TODO Basic tests
+
+            for (int rep = 0; rep < 10; ++rep)
+            {
+                BigInteger a = new BigInteger(100 - rep, 0, random);
+                BigInteger b = new BigInteger(100 + rep, 0, random);
+                BigInteger c = new BigInteger(10 + rep, 0, random);
+                BigInteger d = a.Multiply(b).Add(c);
+                BigInteger e = d.Remainder(a);
+
+                Assert.AreEqual(c, e);
+            }
+        }
+
+        [Test]
+        public void TestSetBit()
+        {
+            Assert.AreEqual(one, zero.SetBit(0));
+            Assert.AreEqual(one, one.SetBit(0));
+            Assert.AreEqual(three, two.SetBit(0));
+
+            Assert.AreEqual(two, zero.SetBit(1));
+            Assert.AreEqual(three, one.SetBit(1));
+            Assert.AreEqual(two, two.SetBit(1));
+
+            // TODO Tests for setting bits in negative numbers
+
+            // TODO Tests for setting extended bits
+
+            for (int i = 0; i < 10; ++i)
+            {
+                BigInteger n = new BigInteger(128, random);
+
+                for (int j = 0; j < 10; ++j)
+                {
+                    int pos = random.Next(128);
+                    BigInteger m = n.SetBit(pos);
+                    bool test = m.ShiftRight(pos).Remainder(two).Equals(one);
+
+                    Assert.IsTrue(test);
+                }
+            }
+
+            for (int i = 0; i < 100; ++i)
+            {
+                BigInteger pow2 = one.ShiftLeft(i);
+                BigInteger minusPow2 = pow2.Negate();
+
+                Assert.AreEqual(pow2, pow2.SetBit(i));
+                Assert.AreEqual(minusPow2, minusPow2.SetBit(i));
+
+                BigInteger bigI = BigInteger.ValueOf(i);
+                BigInteger negI = bigI.Negate();
+
+                for (int j = 0; j < 10; ++j)
+                {
+                    string data = "i=" + i + ", j=" + j;
+                    Assert.AreEqual(bigI.Or(one.ShiftLeft(j)), bigI.SetBit(j), data);
+                    Assert.AreEqual(negI.Or(one.ShiftLeft(j)), negI.SetBit(j), data);
+                }
+            }
+        }
+
+        [Test]
+        public void TestShiftLeft()
+        {
+            for (int i = 0; i < 100; ++i)
+            {
+                int shift = random.Next(128);
+
+                BigInteger a = new BigInteger(128 + i, random).Add(one);
+                int bits = a.BitCount; // Make sure nBits is set
+
+                BigInteger negA = a.Negate();
+                bits = negA.BitCount; // Make sure nBits is set
+
+                BigInteger b = a.ShiftLeft(shift);
+                BigInteger c = negA.ShiftLeft(shift);
+
+                Assert.AreEqual(a.BitCount, b.BitCount);
+                Assert.AreEqual(negA.BitCount + shift, c.BitCount);
+                Assert.AreEqual(a.BitLength + shift, b.BitLength);
+                Assert.AreEqual(negA.BitLength + shift, c.BitLength);
+
+                int j = 0;
+                for (; j < shift; ++j)
+                {
+                    Assert.IsFalse(b.TestBit(j));
+                }
+
+                for (; j < b.BitLength; ++j)
+                {
+                    Assert.AreEqual(a.TestBit(j - shift), b.TestBit(j));
+                }
+            }
+        }
+
+        [Test]
+        public void TestShiftRight()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                int shift = random.Next(128);
+                BigInteger a = new BigInteger(256 + i, random).SetBit(256 + i);
+                BigInteger b = a.ShiftRight(shift);
+
+                Assert.AreEqual(a.BitLength - shift, b.BitLength);
+
+                for (int j = 0; j < b.BitLength; ++j)
+                {
+                    Assert.AreEqual(a.TestBit(j + shift), b.TestBit(j));
+                }
+            }
+        }
+
+        [Test]
+        public void TestSignValue()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                Assert.AreEqual(i < 0 ? -1 : i > 0 ? 1 : 0, val(i).SignValue);
+            }
+        }
+
+        [Test]
+        public void TestSubtract()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(
+                        val(i - j),
+                        val(i).Subtract(val(j)),
+                        "Problem: " + i + ".Subtract(" + j + ") should be " + (i - j));
+                }
+            }
+        }
+
+        [Test]
+        public void TestTestBit()
+        {
+            for (int i = 0; i < 10; ++i)
+            {
+                BigInteger n = new BigInteger(128, random);
+
+                Assert.IsFalse(n.TestBit(128));
+                Assert.IsTrue(n.Negate().TestBit(128));
+
+                for (int j = 0; j < 10; ++j)
+                {
+                    int pos = random.Next(128);
+                    bool test = n.ShiftRight(pos).Remainder(two).Equals(one);
+
+                    Assert.AreEqual(test, n.TestBit(pos));
+                }
+            }
+        }
+
+        [Test]
+        public void TestToByteArray()
+        {
+            byte[] z = BigInteger.Zero.ToByteArray();
+            Assert.IsTrue(Arrays.AreEqual(new byte[1], z));
+
+            for (int i = 16; i <= 48; ++i)
+            {
+                BigInteger x = BigInteger.ProbablePrime(i, random);
+                byte[] b = x.ToByteArray();
+                Assert.AreEqual((i / 8 + 1), b.Length);
+                BigInteger y = new BigInteger(b);
+                Assert.AreEqual(x, y);
+
+                x = x.Negate();
+                b = x.ToByteArray();
+                Assert.AreEqual((i / 8 + 1), b.Length);
+                y = new BigInteger(b);
+                Assert.AreEqual(x, y);
+            }
+        }
+
+        [Test]
+        public void TestToByteArrayUnsigned()
+        {
+            byte[] z = BigInteger.Zero.ToByteArrayUnsigned();
+            Assert.IsTrue(Arrays.AreEqual(new byte[0], z));
+
+            for (int i = 16; i <= 48; ++i)
+            {
+                BigInteger x = BigInteger.ProbablePrime(i, random);
+                byte[] b = x.ToByteArrayUnsigned();
+                Assert.AreEqual((i + 7) / 8, b.Length);
+                BigInteger y = new BigInteger(1, b);
+                Assert.AreEqual(x, y);
+
+                x = x.Negate();
+                b = x.ToByteArrayUnsigned();
+                Assert.AreEqual(i / 8 + 1, b.Length);
+                y = new BigInteger(b);
+                Assert.AreEqual(x, y);
+            }
+        }
+
+        [Test]
+        public void TestToString()
+        {
+            string s = "12345667890987654321";
+
+            Assert.AreEqual(s, new BigInteger(s).ToString());
+            Assert.AreEqual(s, new BigInteger(s, 10).ToString(10));
+            Assert.AreEqual(s, new BigInteger(s, 16).ToString(16));
+
+            for (int i = 0; i < 100; ++i)
+            {
+                BigInteger n = new BigInteger(i, random);
+
+                Assert.AreEqual(n, new BigInteger(n.ToString(2), 2));
+                Assert.AreEqual(n, new BigInteger(n.ToString(10), 10));
+                Assert.AreEqual(n, new BigInteger(n.ToString(16), 16));
+            }
+
+            // Radix version
+            int[] radices = new int[] { 2, 8, 10, 16 };
+            int trials = 256;
+
+            BigInteger[] tests = new BigInteger[trials];
+            for (int i = 0; i < trials; ++i)
+            {
+                int len = random.Next(i + 1);
+                tests[i] = new BigInteger(len, random);
+            }
+
+            foreach (int radix in radices)
+            {
+                for (int i = 0; i < trials; ++i)
+                {
+                    BigInteger n1 = tests[i];
+                    string str = n1.ToString(radix);
+                    BigInteger n2 = new BigInteger(str, radix);
+                    Assert.AreEqual(n1, n2);
+                }
+            }
+        }
+
+        [Test]
+        public void TestValueOf()
+        {
+            Assert.AreEqual(-1, BigInteger.ValueOf(-1).SignValue);
+            Assert.AreEqual(0, BigInteger.ValueOf(0).SignValue);
+            Assert.AreEqual(1, BigInteger.ValueOf(1).SignValue);
+
+            for (long i = -5; i < 5; ++i)
+            {
+                Assert.AreEqual(i, BigInteger.ValueOf(i).IntValue);
+            }
+        }
+
+        [Test]
+        public void TestXor()
+        {
+            for (int i = -10; i <= 10; ++i)
+            {
+                for (int j = -10; j <= 10; ++j)
+                {
+                    Assert.AreEqual(
+                        val(i ^ j),
+                        val(i).Xor(val(j)),
+                        "Problem: " + i + " XOR " + j + " should be " + (i ^ j));
+                }
+            }
+        }
+
+        private static BigInteger val(long n)
+        {
+            return BigInteger.ValueOf(n);
+        }
+
+        private static BigInteger mersenne(int e)
+        {
+            return two.Pow(e).Subtract(one);
+        }
+
+        private static readonly BigInteger minusTwo = BigInteger.Two.Negate();
+        private static readonly BigInteger minusOne = BigInteger.One.Negate();
+        private static readonly BigInteger zero = BigInteger.Zero;
+        private static readonly BigInteger one = BigInteger.One;
+        private static readonly BigInteger two = BigInteger.Two;
+        private static readonly BigInteger three = BigInteger.Three;
+
+        private static int[] firstPrimes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
+        private static int[] nonPrimes = { 0, 1, 4, 10, 20, 21, 22, 25, 26, 27 };
+
+        private static int[] mersennePrimeExponents = { 2, 3, 5, 7, 13, 17, 19, 31, 61, 89 };
+        private static int[] nonPrimeExponents = { 1, 4, 6, 9, 11, 15, 23, 29, 37, 41 };
+    }
+}
diff --git a/crypto/test/src/ocsp/test/AllTests.cs b/crypto/test/src/ocsp/test/AllTests.cs
new file mode 100644
index 000000000..2b30e3ad4
--- /dev/null
+++ b/crypto/test/src/ocsp/test/AllTests.cs
@@ -0,0 +1,29 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Ocsp.Tests
+{
+	public class AllTests
+	{
+		public static void Main(
+			string[] args)
+		{
+			//junit.textui.TestRunner.run(suite());
+			EventListener el = new NullListener();
+			suite().Run(el);
+		}
+
+		public static TestSuite suite()
+		{
+			TestSuite suite = new TestSuite("OCSP Tests");
+
+			suite.Add(new OcspTest());
+
+			return suite;
+		}
+	}
+}
diff --git a/crypto/test/src/ocsp/test/OCSPTest.cs b/crypto/test/src/ocsp/test/OCSPTest.cs
new file mode 100644
index 000000000..823de90f9
--- /dev/null
+++ b/crypto/test/src/ocsp/test/OCSPTest.cs
@@ -0,0 +1,852 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.Ocsp.Tests
+{
+	[TestFixture]
+	public class OcspTest
+		: SimpleTest
+	{
+		private static readonly byte[] testResp1 = Base64.Decode(
+			  "MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx"
+			+ "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE"
+			+ "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG"
+			+ "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv"
+			+ "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ"
+			+ "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF"
+			+ "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1"
+			+ "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/"
+			+ "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt"
+			+ "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk"
+			+ "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI"
+			+ "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN"
+			+ "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww"
+			+ "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k"
+			+ "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz"
+			+ "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg"
+			+ "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK"
+			+ "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw"
+			+ "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI"
+			+ "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF"
+			+ "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH"
+			+ "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm"
+			+ "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E"
+			+ "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG"
+			+ "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E"
+			+ "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG"
+			+ "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4"
+			+ "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc"
+			+ "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V"
+			+ "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I"
+			+ "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq"
+			+ "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ"
+//			+ "====");
+			+ "");
+
+		private static readonly byte[] testResp2 = Base64.Decode(
+			  "MIII1QoBAKCCCM4wggjKBgkrBgEFBQcwAQEEggi7MIIItzCBjqADAgEAoSMw"
+			+ "ITEfMB0GA1UEAxMWT0NTUCBjZXJ0LVFBLUNMSUVOVC04NxgPMjAwMzA1MTky"
+			+ "MDI2MzBaMFEwTzA6MAkGBSsOAwIaBQAEFJniwiUuyrhKIEF2TjVdVdCAOw0z"
+			+ "BBR2olPKrPOJUVyGZ7BXOC4L2BmAqgIBL4AAGA8yMDAzMDUxOTIwMjYzMFow"
+			+ "DQYJKoZIhvcNAQEEBQADggEBALImFU3kUtpNVf4tIFKg/1sDHvGpk5Pk0uhH"
+			+ "TiNp6vdPfWjOgPkVXskx9nOTabVOBE8RusgwEcK1xeBXSHODb6mnjt9pkfv3"
+			+ "ZdbFLFvH/PYjOb6zQOgdIOXhquCs5XbcaSFCX63hqnSaEqvc9w9ctmQwds5X"
+			+ "tCuyCB1fWu/ie8xfuXR5XZKTBf5c6dO82qFE65gTYbGOxJBYiRieIPW1XutZ"
+			+ "A76qla4m+WdxubV6SPG8PVbzmAseqjsJRn4jkSKOGenqSOqbPbZn9oBsU0Ku"
+			+ "hul3pwsNJvcBvw2qxnWybqSzV+n4OvYXk+xFmtTjw8H9ChV3FYYDs8NuUAKf"
+			+ "jw1IjWegggcOMIIHCjCCAzMwggIboAMCAQICAQIwDQYJKoZIhvcNAQEEBQAw"
+			+ "bzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMRAwDgYDVQQHEwdXYWx0aGFt"
+			+ "MRYwFAYDVQQKEw1Gb3J1bSBTeXN0ZW1zMQswCQYDVQQLEwJRQTEcMBoGA1UE"
+			+ "AxMTQ2VydGlmaWNhdGUgTWFuYWdlcjAeFw0wMzAzMjEwNTAwMDBaFw0yNTAz"
+			+ "MjEwNTAwMDBaMCExHzAdBgNVBAMTFk9DU1AgY2VydC1RQS1DTElFTlQtODcw"
+			+ "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVuxRCZgJAYAftYuRy"
+			+ "9axdtsHrkIJyVVRorLCTWOoLmx2tlrGqKbHOGKmvqEPEpeCDYQk+0WIlWMuM"
+			+ "2pgiYAolwqSFBwCjkjQN3fCIHXiby0JBgCCLoe7wa0pZffE+8XZH0JdSjoT3"
+			+ "2OYD19wWZeY2VB0JWJFWYAnIL+R5Eg7LwJ5QZSdvghnOWKTv60m/O1rC0see"
+			+ "9lbPO+3jRuaDyCUKYy/YIKBYC9rtC4hS47jg70dTfmE2nccjn7rFCPBrVr4M"
+			+ "5szqdRzwu3riL9W+IE99LTKXOH/24JX0S4woeGXMS6me7SyZE6x7P2tYkNXM"
+			+ "OfXk28b3SJF75K7vX6T6ecWjAgMBAAGjKDAmMBMGA1UdJQQMMAoGCCsGAQUF"
+			+ "BwMJMA8GCSsGAQUFBzABBQQCBQAwDQYJKoZIhvcNAQEEBQADggEBAKNSn7pp"
+			+ "UEC1VTN/Iqk8Sc2cAYM7KSmeB++tuyes1iXY4xSQaEgOxRa5AvPAKnXKSzfY"
+			+ "vqi9WLdzdkpTo4AzlHl5nqU/NCUv3yOKI9lECVMgMxLAvZgMALS5YXNZsqrs"
+			+ "hP3ASPQU99+5CiBGGYa0PzWLstXLa6SvQYoHG2M8Bb2lHwgYKsyrUawcfc/s"
+			+ "jE3jFJeyCyNwzH0eDJUVvW1/I3AhLNWcPaT9/VfyIWu5qqZU+ukV/yQXrKiB"
+			+ "glY8v4QDRD4aWQlOuiV2r9sDRldOPJe2QSFDBe4NtBbynQ+MRvF2oQs/ocu+"
+			+ "OAHX7uiskg9GU+9cdCWPwJf9cP/Zem6MemgwggPPMIICt6ADAgECAgEBMA0G"
+			+ "CSqGSIb3DQEBBQUAMG8xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNQTEQMA4G"
+			+ "A1UEBxMHV2FsdGhhbTEWMBQGA1UEChMNRm9ydW0gU3lzdGVtczELMAkGA1UE"
+			+ "CxMCUUExHDAaBgNVBAMTE0NlcnRpZmljYXRlIE1hbmFnZXIwHhcNMDMwMzIx"
+			+ "MDUwMDAwWhcNMjUwMzIxMDUwMDAwWjBvMQswCQYDVQQGEwJVUzELMAkGA1UE"
+			+ "CBMCTUExEDAOBgNVBAcTB1dhbHRoYW0xFjAUBgNVBAoTDUZvcnVtIFN5c3Rl"
+			+ "bXMxCzAJBgNVBAsTAlFBMRwwGgYDVQQDExNDZXJ0aWZpY2F0ZSBNYW5hZ2Vy"
+			+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4VeU+48VBjI0mGRt"
+			+ "9qlD+WAhx3vv4KCOD5f3HWLj8D2DcoszVTVDqtRK+HS1eSpO/xWumyXhjV55"
+			+ "FhG2eYi4e0clv0WyswWkGLqo7IxYn3ZhVmw04ohdTjdhVv8oS+96MUqPmvVW"
+			+ "+MkVRyqm75HdgWhKRr/lEpDNm+RJe85xMCipkyesJG58p5tRmAZAAyRs3jYw"
+			+ "5YIFwDOnt6PCme7ui4xdas2zolqOlynMuq0ctDrUPKGLlR4mVBzgAVPeatcu"
+			+ "ivEQdB3rR6UN4+nv2jx9kmQNNb95R1M3J9xHfOWX176UWFOZHJwVq8eBGF9N"
+			+ "pav4ZGBAyqagW7HMlo7Hw0FzUwIDAQABo3YwdDARBglghkgBhvhCAQEEBAMC"
+			+ "AJcwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU64zBxl1yKES8tjU3/rBA"
+			+ "NaeBpjkwHwYDVR0jBBgwFoAU64zBxl1yKES8tjU3/rBANaeBpjkwDgYDVR0P"
+			+ "AQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQAzHnf+Z+UgxDVOpCu0DHF+"
+			+ "qYZf8IaUQxLhUD7wjwnt3lJ0QV1z4oyc6Vs9J5xa8Mvf7u1WMmOxvN8r8Kb0"
+			+ "k8DlFszLd0Qwr+NVu5NQO4Vn01UAzCtH4oX2bgrVzotqDnzZ4TcIr11EX3Nb"
+			+ "tO8yWWl+xWIuxKoAO8a0Rh97TyYfAj4++GIm43b2zIvRXEWAytjz7rXUMwRC"
+			+ "1ipRQwSA9gyw2y0s8emV/VwJQXsTe9xtDqlEC67b90V/BgL/jxck5E8yrY9Z"
+			+ "gNxlOgcqscObisAkB5I6GV+dfa+BmZrhSJ/bvFMUrnFzjLFvZp/9qiK11r5K"
+			+ "A5oyOoNv0w+8bbtMNEc1"
+//			+ "====");
+			+ "");
+
+		/**
+		 * extra version number encoding.
+		 */
+		private static readonly byte[] irregReq = Base64.Decode(
+			  "MIIQpTBUoAMCAQAwTTBLMEkwCQYFKw4DAhoFAAQUIcFvFFVjPem15pKox4cfcnzF"
+			+ "Kf4EFJf8OQzmVmyJ/hc4EhitQbXcqAzDAhB9ePsP19SuP6CsAgFwQuEAoIIQSzCC"
+			+ "EEcwDQYJKoZIhvcNAQEFBQADgYEAlq/Tjl8OtFM8Tib1JYTiaPy9vFDr8UZhqXJI"
+			+ "FyrdgtUyyDt0EcrgnBGacAeRZzF5sokIC6DjXweU7EItGqrpw/RaCUPUWFpPxR6y"
+			+ "HjuzrLmICocTI9MH7dRUXm0qpxoY987sx1PtWB4pSR99ixBtq3OPNdsI0uJ+Qkei"
+			+ "LbEZyvWggg+wMIIPrDCCA5owggKCoAMCAQICEEAxXx/eFe7gm/NX7AkcS68wDQYJ"
+			+ "KoZIhvcNAQEFBQAwgZoxCzAJBgNVBAYTAlNFMTMwMQYDVQQKDCpMw6Ruc2bDtnJz"
+			+ "w6RrcmluZ2FyIEJhbmsgQWt0aWVib2xhZyAocHVibCkxFTATBgNVBAUTDDExMTEx"
+			+ "MTExMTExMTE/MD0GA1UEAww2TMOkbnNmw7Zyc8Oka3JpbmdhciBCYW5rIFB1cmNo"
+			+ "YXNlciBDQTEgZm9yIEJhbmtJRCBURVNUMB4XDTA4MTAwNjIyMDAwMFoXDTEwMTAx"
+			+ "MDIxNTk1OVowgZExCzAJBgNVBAYTAlNFMTMwMQYDVQQKDCpMw6Ruc2bDtnJzw6Rr"
+			+ "cmluZ2FyIEJhbmsgQWt0aWVib2xhZyAocHVibCkxFTATBgNVBAUTDDExMTExMTEx"
+			+ "MTExMTE2MDQGA1UEAwwtTMOkbnNmw7Zyc8Oka3JpbmdhciBCYW5rIE9DU1AgZm9y"
+			+ "IEJhbmtJRCBURVNUMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5e/h6aL2m"
+			+ "DVpWeu5e5p1Ps9kbvuuGeAp9zJDYLbZz7uzT67X+s59HaViroD2+2my/gg7rX7tK"
+			+ "H9VXpJad1W9O19SjfNyxgeAMwVMkrbb4IlrQwu0v/Ub8JPxSWwZZXYiODq5abeXA"
+			+ "abMYIHxSaSkhrsUj1dpSAohHLJRlq707swIDAQABo2cwZTAfBgNVHSMEGDAWgBTR"
+			+ "vcp2QyNdNGZ+q7TjKSrrHZqxmDATBgNVHSAEDDAKMAgGBiqFcDwBBjAOBgNVHQ8B"
+			+ "Af8EBAMCBkAwHQYDVR0OBBYEFF/3557FEvkA8iiPv2XcBclxKnTdMA0GCSqGSIb3"
+			+ "DQEBBQUAA4IBAQAOxRvHO89XJ0v83BZdPFzEBA4B2Tqc1oABUn13S6fAkcGWvOmG"
+			+ "eY61MK16aMnLPNDadZrAqJc6PEtVY57uaywE9acwv9XpHO0bcS94tLwvZZJ2KBt0"
+			+ "Oq96gaI6gnJViUjyWjm+qBZvod0QPOLGv6wUPoiNcCpSid/COTjKpLYpCJj3ZWUV"
+			+ "nsTRWSRVXsdY/xI0gs/A8/c5P1PuTxoi99RTmcruoFxvV4MmhWyX7IGqG4OAtLdo"
+			+ "yefz/90FPGOrmqY9OgEb+gNuTM26YDvSs1dfarPl89d8jjwxHgNbZjh2VHFqKolJ"
+			+ "8TB8ZS5aNvhHPumOOE47y95rTBxrxSmGvKb8MIIENDCCAxygAwIBAgIRAJAFaeOw"
+			+ "7XbxH/DN/Vvhjx8wDQYJKoZIhvcNAQEFBQAwgZUxCzAJBgNVBAYTAlNFMTMwMQYD"
+			+ "VQQKDCpMw6Ruc2bDtnJzw6RrcmluZ2FyIEJhbmsgQWt0aWVib2xhZyAocHVibCkx"
+			+ "FTATBgNVBAUTDDExMTExMTExMTExMTE6MDgGA1UEAwwxTMOkbnNmw7Zyc8Oka3Jp"
+			+ "bmdhciBCYW5rIFJvb3QgQ0ExIGZvciBCYW5rSUQgVEVTVDAeFw0wNzEwMDExMjAw"
+			+ "MzdaFw0yOTA3MDExMjAwMzdaMIGaMQswCQYDVQQGEwJTRTEzMDEGA1UECgwqTMOk"
+			+ "bnNmw7Zyc8Oka3JpbmdhciBCYW5rIEFrdGllYm9sYWcgKHB1YmwpMRUwEwYDVQQF"
+			+ "EwwxMTExMTExMTExMTExPzA9BgNVBAMMNkzDpG5zZsO2cnPDpGtyaW5nYXIgQmFu"
+			+ "ayBQdXJjaGFzZXIgQ0ExIGZvciBCYW5rSUQgVEVTVDCCASIwDQYJKoZIhvcNAQEB"
+			+ "BQADggEPADCCAQoCggEBAMK5WbYojYRX1ZKrbxJBgbd4x503LfMWgr67sVD5L0NY"
+			+ "1RPhZVFJRKJWvawE5/eXJ4oNQwc831h2jiOgINXuKyGXqdAVGBcpFwIxTfzxwT4l"
+			+ "fvztr8pE6wk7mLLwKUvIjbM3EF1IL3zUI3UU/U5ioyGmcb/o4GGN71kMmvV/vrkU"
+			+ "02/s7xicXNxYej4ExLiCkS5+j/+3sR47Uq5cL9e8Yg7t5/6FyLGQjKoS8HU/abYN"
+			+ "4kpx/oyrxzrXMhnMVDiI8QX9NYGJwI8KZ/LU6GDq/NnZ3gG5v4l4UU1GhgUbrk4I"
+			+ "AZPDu99zvwCtkdj9lJN0eDv8jdyEPZ6g1qPBE0pCNqcCAwEAAaN4MHYwDwYDVR0T"
+			+ "AQH/BAUwAwEB/zATBgNVHSAEDDAKMAgGBiqFcDwBBjAOBgNVHQ8BAf8EBAMCAQYw"
+			+ "HwYDVR0jBBgwFoAUnkjp1bkQUOrkRiLgxpxwAe2GQFYwHQYDVR0OBBYEFNG9ynZD"
+			+ "I100Zn6rtOMpKusdmrGYMA0GCSqGSIb3DQEBBQUAA4IBAQAPVSC4HEd+yCtSgL0j"
+			+ "NI19U2hJeP28lAD7OA37bcLP7eNrvfU/2tuqY7rEn1m44fUbifewdgR8x2DzhM0m"
+			+ "fJcA5Z12PYUb85L9z8ewGQdyHLNlMpKSTP+0lebSc/obFbteC4jjuvux60y5KVOp"
+			+ "osXbGw2qyrS6uhZJrTDP1B+bYg/XBttG+i7Qzx0S5Tq//VU9OfAQZWpvejadKAk9"
+			+ "WCcXq6zALiJcxsUwOHZRvvHDxkHuf5eZpPvm1gaqa+G9CtV+oysZMU1eTRasBHsB"
+			+ "NRWYfOSXggsyqRHfIAVieB4VSsB8WhZYm8UgYoLhAQfSJ5Xq5cwBOHkVj33MxAyP"
+			+ "c7Y5MIID/zCCAuegAwIBAgIRAOXEoBcV4gV3Z92gk5AuRgwwDQYJKoZIhvcNAQEF"
+			+ "BQAwZjEkMCIGA1UECgwbRmluYW5zaWVsbCBJRC1UZWtuaWsgQklEIEFCMR8wHQYD"
+			+ "VQQLDBZCYW5rSUQgTWVtYmVyIEJhbmtzIENBMR0wGwYDVQQDDBRCYW5rSUQgUm9v"
+			+ "dCBDQSBURVNUMjAeFw0wNzEwMDExMTQ1NDlaFw0yOTA4MDExMTU4MjVaMIGVMQsw"
+			+ "CQYDVQQGEwJTRTEzMDEGA1UECgwqTMOkbnNmw7Zyc8Oka3JpbmdhciBCYW5rIEFr"
+			+ "dGllYm9sYWcgKHB1YmwpMRUwEwYDVQQFEwwxMTExMTExMTExMTExOjA4BgNVBAMM"
+			+ "MUzDpG5zZsO2cnPDpGtyaW5nYXIgQmFuayBSb290IENBMSBmb3IgQmFua0lEIFRF"
+			+ "U1QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBzn7IXIpyOGCCTuzL"
+			+ "DKE/T+pFRTgFh3QgKtifZ4zxdvB2Sd5+90vUEGcGExUhzpgb9gOUrT1eE0XhdiUR"
+			+ "YuYYpJI/nzPQWTsRtEaql7NHBPKnEauoA9oAhCT4pE5gLlqpTfkB8nAsRTI2XqpI"
+			+ "hQ7vTvnTRx20xog21NIbz1GztV8H1kBH2eDvRX7cXGiugp6CXV/le9cB+/4TBNUN"
+			+ "Xqupt79dM49KCoDuYr72W7Hv4BSWw3IInEN2m8T2X6UBpBGkCiGwLQy/+KOmYRK7"
+			+ "1PSFC0rXDwOJ0HJ/8fHwx6vLMxHAQ6s/9vOW10MjgjSQlbVqH/4Pa+TlpWumSV4E"
+			+ "l0z9AgMBAAGjeDB2MA8GA1UdEwEB/wQFMAMBAf8wEwYDVR0gBAwwCjAIBgYqhXA8"
+			+ "AQYwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQYMBaAFJuTMPljHcYdrRO9sEi1amb4"
+			+ "tE3VMB0GA1UdDgQWBBSeSOnVuRBQ6uRGIuDGnHAB7YZAVjANBgkqhkiG9w0BAQUF"
+			+ "AAOCAQEArnW/9n+G+84JOgv1Wn4tsBBS7QgJp1rdCoiNrZPx2du/7Wz3wQVNKBjL"
+			+ "eMCyLjg0OVHuq4hpCv9MZpUqdcUW8gpp4dLDAAd1uE7xqVuG8g4Ir5qocxbZHQew"
+			+ "fnqSJJDlEZgDeZIzod92OO+htv0MWqKWbr3Mo2Hqhn+t0+UVWsW4k44e7rUw3xQq"
+			+ "r2VdMJv/C68BXUgqh3pplUDjWyXfreiACTT0q3HT6v6WaihKCa2WY9Kd1IkDcLHb"
+			+ "TZk8FqMmGn72SgJw3H5Dvu7AiZijjNAUulMnMpxBEKyFTU2xRBlZZVcp50VJ2F7+"
+			+ "siisxbcYOAX4GztLMlcyq921Ov/ipDCCA88wggK3oAMCAQICEQCmaX+5+m5bF5us"
+			+ "CtyMq41SMA0GCSqGSIb3DQEBBQUAMGYxJDAiBgNVBAoMG0ZpbmFuc2llbGwgSUQt"
+			+ "VGVrbmlrIEJJRCBBQjEfMB0GA1UECwwWQmFua0lEIE1lbWJlciBCYW5rcyBDQTEd"
+			+ "MBsGA1UEAwwUQmFua0lEIFJvb3QgQ0EgVEVTVDIwHhcNMDQwODEzMDcyMDEwWhcN"
+			+ "MjkwODEyMTIwMjQ2WjBmMSQwIgYDVQQKDBtGaW5hbnNpZWxsIElELVRla25payBC"
+			+ "SUQgQUIxHzAdBgNVBAsMFkJhbmtJRCBNZW1iZXIgQmFua3MgQ0ExHTAbBgNVBAMM"
+			+ "FEJhbmtJRCBSb290IENBIFRFU1QyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB"
+			+ "CgKCAQEA25D0f1gipbACk4Bg3t6ODUlCWOU0TWeTkzAHR7IRB5T++yvsVosedMMW"
+			+ "6KYYTbPONeJSt5kydX+wZi9nVNdlhkNULLbDKWfRY7x+B9MR1Q0Kq/e4VR0uRsak"
+			+ "Bv5iwEYZ7cSR63HfBaPTqQsGobq+wtGH5JeTBrmCt4A3kN1UWgX32Dv/I3m7v8bK"
+			+ "iwh4cnvAD9PIOtq6pOmAkSvLvp8jCy3qFLe9KAxm8M/ZAmnxYaRV8DVEg57FGoG6"
+			+ "oiG3Ixx8PSVVdzpFY4kuUFLi4ueMPwjnXFiBhhWJJeOtFG3Lc2aW3zvcDbD/MsDm"
+			+ "rSZNTmtbOOou8xuMKjlNY9PU5MHIaQIDAQABo3gwdjAPBgNVHRMBAf8EBTADAQH/"
+			+ "MBMGA1UdIAQMMAowCAYGKoVwPAEGMA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW"
+			+ "gBSbkzD5Yx3GHa0TvbBItWpm+LRN1TAdBgNVHQ4EFgQUm5Mw+WMdxh2tE72wSLVq"
+			+ "Zvi0TdUwDQYJKoZIhvcNAQEFBQADggEBAIQ4ZBHWssA38pfNzH5A+H3SXpAlI8Jc"
+			+ "LuoMVOIwwbfd1Up0xopCs+Ay41v8FZtcTMFqCVTih2nzVusTgnFBPMPJ2cnTlRue"
+			+ "kAtVRNsiWn2/Ool/OXoYf5YnpgYu8t9jLCBCoDS5YJg714r9V9hCwfey8TCWBU80"
+			+ "vL7EIfjK13nUxf8d49GzZlFMNqGDMjfMp1FYrHBGLZBr8br/G/7em1Cprw7iR8cw"
+			+ "pddz+QXXFIrIz5Y9D/x1RrwoLibPw0kMrSwI2G4aCvoBySfbD6cpnJf6YHRctdSb"
+			+ "755zhdBW7XWTl6ReUVuEt0hTFms4F60kFAi5hIbDRSN1Slv5yP2b0EA=");
+
+		public override string Name
+		{
+			get { return "OCSP"; }
+		}
+
+		private void doTestECDsa()
+		{
+			string signDN = "O=Bouncy Castle, C=AU";
+			AsymmetricCipherKeyPair signKP = OcspTestUtil.MakeECKeyPair();
+			X509Certificate testCert = OcspTestUtil.MakeECDsaCertificate(signKP, signDN, signKP, signDN);
+
+			string origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+			GeneralName origName = new GeneralName(new X509Name(origDN));
+
+			//
+			// general id value for our test issuer cert and a serial number.
+			//
+			CertificateID id = new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One);
+
+			//
+			// basic request generation
+			//
+			OcspReqGenerator gen = new OcspReqGenerator();
+
+			gen.AddRequest(id);
+
+			OcspReq req = gen.Generate();
+
+			if (req.IsSigned)
+			{
+				Fail("signed but shouldn't be");
+			}
+
+			X509Certificate[] certs = req.GetCerts();
+
+			if (certs != null)
+			{
+				Fail("null certs expected, but not found");
+			}
+
+			Req[] requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			//
+			// request generation with signing
+			//
+			X509Certificate[] chain = new X509Certificate[1];
+
+			gen = new OcspReqGenerator();
+
+			gen.SetRequestorName(new GeneralName(GeneralName.DirectoryName, new X509Name("CN=fred")));
+
+			gen.AddRequest(new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			chain[0] = testCert;
+
+			req = gen.Generate("SHA1withECDSA", signKP.Private, chain);
+
+			if (!req.IsSigned)
+			{
+				Fail("not signed but should be");
+			}
+
+			if (!req.Verify(signKP.Public))
+			{
+				Fail("signature failed to Verify");
+			}
+
+			requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			certs = req.GetCerts();
+
+			if (certs == null)
+			{
+				Fail("null certs found");
+			}
+
+			if (certs.Length != 1 || !certs[0].Equals(testCert))
+			{
+				Fail("incorrect certs found in request");
+			}
+
+			//
+			// encoding test
+			//
+			byte[] reqEnc = req.GetEncoded();
+
+			OcspReq newReq = new OcspReq(reqEnc);
+
+			if (!newReq.Verify(signKP.Public))
+			{
+				Fail("newReq signature failed to Verify");
+			}
+
+			//
+			// request generation with signing and nonce
+			//
+			chain = new X509Certificate[1];
+
+			gen = new OcspReqGenerator();
+
+			IList oids = new ArrayList();
+			IList values = new ArrayList();
+			byte[] sampleNonce = new byte[16];
+			Random rand = new Random();
+
+			rand.NextBytes(sampleNonce);
+
+			gen.SetRequestorName(new GeneralName(GeneralName.DirectoryName, new X509Name("CN=fred")));
+
+			oids.Add(OcspObjectIdentifiers.PkixOcspNonce);
+			values.Add(new X509Extension(false, new DerOctetString(new DerOctetString(sampleNonce))));
+
+			gen.SetRequestExtensions(new X509Extensions(oids, values));
+
+			gen.AddRequest(new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			chain[0] = testCert;
+
+			req = gen.Generate("SHA1withECDSA", signKP.Private, chain);
+
+			if (!req.IsSigned)
+			{
+				Fail("not signed but should be");
+			}
+
+			if (!req.Verify(signKP.Public))
+			{
+				Fail("signature failed to Verify");
+			}
+
+			//
+			// extension check.
+			//
+			ISet extOids = req.GetCriticalExtensionOids();
+
+			if (extOids.Count != 0)
+			{
+				Fail("wrong number of critical extensions in OCSP request.");
+			}
+
+			extOids = req.GetNonCriticalExtensionOids();
+
+			if (extOids.Count != 1)
+			{
+				Fail("wrong number of non-critical extensions in OCSP request.");
+			}
+
+			Asn1OctetString extValue = req.GetExtensionValue(OcspObjectIdentifiers.PkixOcspNonce);
+
+			Asn1Encodable extObj = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+			if (!(extObj is Asn1OctetString))
+			{
+				Fail("wrong extension type found.");
+			}
+
+			if (!AreEqual(((Asn1OctetString)extObj).GetOctets(), sampleNonce))
+			{
+				Fail("wrong extension value found.");
+			}
+
+			//
+			// request list check
+			//
+			requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			//
+			// response generation
+			//
+			BasicOcspRespGenerator respGen = new BasicOcspRespGenerator(signKP.Public);
+
+			respGen.AddResponse(id, CertificateStatus.Good);
+
+			respGen.Generate("SHA1withECDSA", signKP.Private, chain, DateTime.UtcNow);
+		}
+
+		private void doTestRsa()
+		{
+			string signDN = "O=Bouncy Castle, C=AU";
+			AsymmetricCipherKeyPair signKP = OcspTestUtil.MakeKeyPair();
+			X509Certificate testCert = OcspTestUtil.MakeCertificate(signKP, signDN, signKP, signDN);
+
+			string origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+			GeneralName origName = new GeneralName(new X509Name(origDN));
+
+			//
+			// general id value for our test issuer cert and a serial number.
+			//
+			CertificateID id = new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One);
+
+			//
+			// basic request generation
+			//
+			OcspReqGenerator gen = new OcspReqGenerator();
+
+			gen.AddRequest(
+				new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			OcspReq req = gen.Generate();
+
+			if (req.IsSigned)
+			{
+				Fail("signed but shouldn't be");
+			}
+
+			X509Certificate[] certs = req.GetCerts();
+
+			if (certs != null)
+			{
+				Fail("null certs expected, but not found");
+			}
+
+			Req[] requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			//
+			// request generation with signing
+			//
+			X509Certificate[] chain = new X509Certificate[1];
+
+			gen = new OcspReqGenerator();
+
+			gen.SetRequestorName(new GeneralName(GeneralName.DirectoryName, new X509Name("CN=fred")));
+
+			gen.AddRequest(
+				new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			chain[0] = testCert;
+
+			req = gen.Generate("SHA1withRSA", signKP.Private, chain);
+
+			if (!req.IsSigned)
+			{
+				Fail("not signed but should be");
+			}
+
+			if (!req.Verify(signKP.Public))
+			{
+				Fail("signature failed to Verify");
+			}
+
+			requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			certs = req.GetCerts();
+
+			if (certs == null)
+			{
+				Fail("null certs found");
+			}
+
+			if (certs.Length != 1 || !certs[0].Equals(testCert))
+			{
+				Fail("incorrect certs found in request");
+			}
+
+			//
+			// encoding test
+			//
+			byte[] reqEnc = req.GetEncoded();
+
+			OcspReq newReq = new OcspReq(reqEnc);
+
+			if (!newReq.Verify(signKP.Public))
+			{
+				Fail("newReq signature failed to Verify");
+			}
+
+			//
+			// request generation with signing and nonce
+			//
+			chain = new X509Certificate[1];
+
+			gen = new OcspReqGenerator();
+
+			IList oids = new ArrayList();
+			IList values = new ArrayList();
+			byte[] sampleNonce = new byte[16];
+			Random rand = new Random();
+
+			rand.NextBytes(sampleNonce);
+
+			gen.SetRequestorName(new GeneralName(GeneralName.DirectoryName, new X509Name("CN=fred")));
+
+			oids.Add(OcspObjectIdentifiers.PkixOcspNonce);
+			values.Add(new X509Extension(false, new DerOctetString(new DerOctetString(sampleNonce))));
+
+			gen.SetRequestExtensions(new X509Extensions(oids, values));
+
+			gen.AddRequest(
+				new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			chain[0] = testCert;
+
+			req = gen.Generate("SHA1withRSA", signKP.Private, chain);
+
+			if (!req.IsSigned)
+			{
+				Fail("not signed but should be");
+			}
+
+			if (!req.Verify(signKP.Public))
+			{
+				Fail("signature failed to Verify");
+			}
+
+			//
+			// extension check.
+			//
+			ISet extOids = req.GetCriticalExtensionOids();
+
+			if (extOids.Count != 0)
+			{
+				Fail("wrong number of critical extensions in OCSP request.");
+			}
+
+			extOids = req.GetNonCriticalExtensionOids();
+
+			if (extOids.Count != 1)
+			{
+				Fail("wrong number of non-critical extensions in OCSP request.");
+			}
+
+			Asn1OctetString extValue = req.GetExtensionValue(OcspObjectIdentifiers.PkixOcspNonce);
+
+			Asn1Object extObj = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+			if (!(extObj is Asn1OctetString))
+			{
+				Fail("wrong extension type found.");
+			}
+
+			if (!AreEqual(((Asn1OctetString)extObj).GetOctets(), sampleNonce))
+			{
+				Fail("wrong extension value found.");
+			}
+
+			//
+			// request list check
+			//
+			requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			//
+			// response generation
+			//
+			BasicOcspRespGenerator respGen = new BasicOcspRespGenerator(signKP.Public);
+
+			respGen.AddResponse(id, CertificateStatus.Good);
+
+			BasicOcspResp resp = respGen.Generate("SHA1withRSA", signKP.Private, chain, DateTime.UtcNow);
+			OCSPRespGenerator rGen = new OCSPRespGenerator();
+
+			byte[] enc = rGen.Generate(OCSPRespGenerator.Successful, resp).GetEncoded();
+		}
+
+		private void doTestIrregularVersionReq()
+		{
+			OcspReq ocspRequest = new OcspReq(irregReq);
+			X509Certificate cert = ocspRequest.GetCerts()[0];
+			if (!ocspRequest.Verify(cert.GetPublicKey()))
+			{
+				Fail("extra version encoding test failed");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			string signDN = "O=Bouncy Castle, C=AU";
+			AsymmetricCipherKeyPair signKP = OcspTestUtil.MakeKeyPair();
+			X509Certificate testCert = OcspTestUtil.MakeCertificate(signKP, signDN, signKP, signDN);
+
+			string origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+			GeneralName origName = new GeneralName(new X509Name(origDN));
+
+			//
+			// general id value for our test issuer cert and a serial number.
+			//
+			CertificateID   id = new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One);
+
+			//
+			// basic request generation
+			//
+			OcspReqGenerator gen = new OcspReqGenerator();
+
+			gen.AddRequest(
+				new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			OcspReq req = gen.Generate();
+
+			if (req.IsSigned)
+			{
+				Fail("signed but shouldn't be");
+			}
+
+			X509Certificate[] certs = req.GetCerts();
+
+			if (certs != null)
+			{
+				Fail("null certs expected, but not found");
+			}
+
+			Req[] requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			//
+			// request generation with signing
+			//
+			X509Certificate[] chain = new X509Certificate[1];
+
+			gen = new OcspReqGenerator();
+
+			gen.SetRequestorName(new GeneralName(GeneralName.DirectoryName, new X509Name("CN=fred")));
+
+			gen.AddRequest(
+				new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			chain[0] = testCert;
+
+			req = gen.Generate("SHA1withRSA", signKP.Private, chain);
+
+			if (!req.IsSigned)
+			{
+				Fail("not signed but should be");
+			}
+
+			if (!req.Verify(signKP.Public))
+			{
+				Fail("signature failed to Verify");
+			}
+
+			requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			certs = req.GetCerts();
+
+			if (certs == null)
+			{
+				Fail("null certs found");
+			}
+
+			if (certs.Length != 1 || !testCert.Equals(certs[0]))
+			{
+				Fail("incorrect certs found in request");
+			}
+
+			//
+			// encoding test
+			//
+			byte[] reqEnc = req.GetEncoded();
+
+			OcspReq newReq = new OcspReq(reqEnc);
+
+			if (!newReq.Verify(signKP.Public))
+			{
+				Fail("newReq signature failed to Verify");
+			}
+
+			//
+			// request generation with signing and nonce
+			//
+			chain = new X509Certificate[1];
+
+			gen = new OcspReqGenerator();
+
+			IList oids = new ArrayList();
+			IList values = new ArrayList();
+			byte[] sampleNonce = new byte[16];
+			Random rand = new Random();
+
+			rand.NextBytes(sampleNonce);
+
+			gen.SetRequestorName(new GeneralName(GeneralName.DirectoryName, new X509Name("CN=fred")));
+
+			oids.Add(OcspObjectIdentifiers.PkixOcspNonce);
+			values.Add(new X509Extension(false, new DerOctetString(new DerOctetString(sampleNonce))));
+
+			gen.SetRequestExtensions(new X509Extensions(oids, values));
+
+			gen.AddRequest(
+				new CertificateID(CertificateID.HashSha1, testCert, BigInteger.One));
+
+			chain[0] = testCert;
+
+			req = gen.Generate("SHA1withRSA", signKP.Private, chain);
+
+			if (!req.IsSigned)
+			{
+				Fail("not signed but should be");
+			}
+
+			if (!req.Verify(signKP.Public))
+			{
+				Fail("signature failed to Verify");
+			}
+
+			//
+			// extension check.
+			//
+			ISet extOids = req.GetCriticalExtensionOids();
+
+			if (extOids.Count != 0)
+			{
+				Fail("wrong number of critical extensions in OCSP request.");
+			}
+
+			extOids = req.GetNonCriticalExtensionOids();
+
+			if (extOids.Count != 1)
+			{
+				Fail("wrong number of non-critical extensions in OCSP request.");
+			}
+
+			Asn1OctetString extValue = req.GetExtensionValue(OcspObjectIdentifiers.PkixOcspNonce);
+			Asn1Object extObj = X509ExtensionUtilities.FromExtensionValue(extValue);
+
+			if (!(extObj is Asn1OctetString))
+			{
+				Fail("wrong extension type found.");
+			}
+
+			byte[] compareNonce = ((Asn1OctetString) extObj).GetOctets();
+
+			if (!AreEqual(compareNonce, sampleNonce))
+			{
+				Fail("wrong extension value found.");
+			}
+
+			//
+			// request list check
+			//
+			requests = req.GetRequestList();
+
+			if (!requests[0].GetCertID().Equals(id))
+			{
+				Fail("Failed isFor test");
+			}
+
+			//
+			// response parsing - test 1
+			//
+			OcspResp response = new OcspResp(testResp1);
+
+			if (response.Status != 0)
+			{
+				Fail("response status not zero.");
+			}
+
+			BasicOcspResp brep = (BasicOcspResp) response.GetResponseObject();
+			chain = brep.GetCerts();
+
+			if (!brep.Verify(chain[0].GetPublicKey()))
+			{
+				Fail("response 1 failed to Verify.");
+			}
+
+			//
+			// test 2
+			//
+			SingleResp[] singleResp = brep.Responses;
+
+			response = new OcspResp(testResp2);
+
+			if (response.Status != 0)
+			{
+				Fail("response status not zero.");
+			}
+
+			brep = (BasicOcspResp)response.GetResponseObject();
+			chain = brep.GetCerts();
+
+			if (!brep.Verify(chain[0].GetPublicKey()))
+			{
+				Fail("response 2 failed to Verify.");
+			}
+
+			singleResp = brep.Responses;
+
+			//
+			// simple response generation
+			//
+			OCSPRespGenerator respGen = new OCSPRespGenerator();
+			OcspResp resp = respGen.Generate(OCSPRespGenerator.Successful, response.GetResponseObject());
+
+			if (!resp.GetResponseObject().Equals(response.GetResponseObject()))
+			{
+				Fail("response fails to match");
+			}
+
+			doTestECDsa();
+			doTestRsa();
+			doTestIrregularVersionReq();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new OcspTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/ocsp/test/OCSPTestUtil.cs b/crypto/test/src/ocsp/test/OCSPTestUtil.cs
new file mode 100644
index 000000000..53b8f5bb9
--- /dev/null
+++ b/crypto/test/src/ocsp/test/OCSPTestUtil.cs
@@ -0,0 +1,147 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Ocsp.Tests
+{
+	public class OcspTestUtil
+	{
+		public static SecureRandom rand;
+		public static IAsymmetricCipherKeyPairGenerator kpg, ecKpg;
+		public static CipherKeyGenerator desede128kg;
+		public static CipherKeyGenerator desede192kg;
+		public static CipherKeyGenerator rc240kg;
+		public static CipherKeyGenerator rc264kg;
+		public static CipherKeyGenerator rc2128kg;
+		public static BigInteger serialNumber;
+
+		public static readonly bool Debug = true;
+
+		static OcspTestUtil()
+		{
+			rand = new SecureRandom();
+
+//			kpg  = KeyPairGenerator.GetInstance("RSA");
+//			kpg.initialize(1024, rand);
+			kpg = GeneratorUtilities.GetKeyPairGenerator("RSA");
+			kpg.Init(new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x10001), rand, 1024, 25));
+
+			serialNumber = BigInteger.One;
+
+			ecKpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+			ecKpg.Init(new KeyGenerationParameters(rand, 192));
+		}
+
+		public static AsymmetricCipherKeyPair MakeKeyPair()
+		{
+			return kpg.GenerateKeyPair();
+		}
+
+		public static AsymmetricCipherKeyPair MakeECKeyPair()
+		{
+			return ecKpg.GenerateKeyPair();
+		}
+
+		public static X509Certificate MakeCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN)
+		{
+			return MakeCertificate(_subKP, _subDN, _issKP, _issDN, false);
+		}
+
+		public static X509Certificate MakeECDsaCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN)
+		{
+			return MakeECDsaCertificate(_subKP, _subDN, _issKP, _issDN, false);
+		}
+
+		public static X509Certificate MakeCACertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN)
+		{
+
+			return MakeCertificate(_subKP, _subDN, _issKP, _issDN, true);
+		}
+
+		public static X509Certificate MakeCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN, bool _ca)
+		{
+			return MakeCertificate(_subKP,_subDN, _issKP, _issDN, "MD5withRSA", _ca);
+		}
+
+		public static X509Certificate MakeECDsaCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN, bool _ca)
+		{
+			return MakeCertificate(_subKP,_subDN, _issKP, _issDN, "SHA1WithECDSA", _ca);
+		}
+
+		public static X509Certificate MakeCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN, string algorithm, bool _ca)
+		{
+			AsymmetricKeyParameter _subPub = _subKP.Public;
+			AsymmetricKeyParameter _issPriv = _issKP.Private;
+			AsymmetricKeyParameter _issPub = _issKP.Public;
+
+			X509V3CertificateGenerator _v3CertGen = new X509V3CertificateGenerator();
+
+			_v3CertGen.Reset();
+			_v3CertGen.SetSerialNumber(allocateSerialNumber());
+			_v3CertGen.SetIssuerDN(new X509Name(_issDN));
+			_v3CertGen.SetNotBefore(DateTime.UtcNow);
+			_v3CertGen.SetNotAfter(DateTime.UtcNow.AddDays(100));
+			_v3CertGen.SetSubjectDN(new X509Name(_subDN));
+			_v3CertGen.SetPublicKey(_subPub);
+			_v3CertGen.SetSignatureAlgorithm(algorithm);
+
+			_v3CertGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false,
+				createSubjectKeyId(_subPub));
+
+			_v3CertGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false,
+				createAuthorityKeyId(_issPub));
+
+			_v3CertGen.AddExtension(X509Extensions.BasicConstraints, false,
+				new BasicConstraints(_ca));
+
+			X509Certificate _cert = _v3CertGen.Generate(_issPriv);
+
+			_cert.CheckValidity(DateTime.UtcNow);
+			_cert.Verify(_issPub);
+
+			return _cert;
+		}
+
+		/*
+		 *
+		 * INTERNAL METHODS
+		 *
+		 */
+
+		private static AuthorityKeyIdentifier createAuthorityKeyId(
+			AsymmetricKeyParameter _pubKey)
+		{
+			SubjectPublicKeyInfo _info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_pubKey);
+			return new AuthorityKeyIdentifier(_info);
+		}
+
+		private static SubjectKeyIdentifier createSubjectKeyId(
+			AsymmetricKeyParameter _pubKey)
+		{
+			SubjectPublicKeyInfo _info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_pubKey);
+			return new SubjectKeyIdentifier(_info);
+		}
+
+		private static BigInteger allocateSerialNumber()
+		{
+			BigInteger _tmp = serialNumber;
+			serialNumber = serialNumber.Add(BigInteger.One);
+			return _tmp;
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/examples/ByteArrayHandler.cs b/crypto/test/src/openpgp/examples/ByteArrayHandler.cs
new file mode 100644
index 000000000..676db8766
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/ByteArrayHandler.cs
@@ -0,0 +1,195 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * Simple routine to encrypt and decrypt using a passphrase.
+    * This service routine provides the basic PGP services between
+    * byte arrays.
+    *
+    * Note: this code plays no attention to -Console in the file name
+    * the specification of "_CONSOLE" in the filename.
+    * It also expects that a single pass phrase will have been used.
+    *
+    */
+    public sealed class ByteArrayHandler
+    {
+        private ByteArrayHandler()
+        {
+        }
+
+        /**
+        * decrypt the passed in message stream
+        *
+        * @param encrypted  The message to be decrypted.
+        * @param passPhrase Pass phrase (key)
+        *
+        * @return Clear text as a byte array.  I18N considerations are
+        *         not handled by this routine
+        * @exception IOException
+        * @exception PgpException
+        */
+        public static byte[] Decrypt(
+            byte[] encrypted,
+            char[] passPhrase)
+        {
+            Stream inputStream = new MemoryStream(encrypted);
+
+            inputStream = PgpUtilities.GetDecoderStream(inputStream);
+
+            PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
+            PgpEncryptedDataList enc = null;
+            PgpObject o = pgpF.NextPgpObject();
+
+			//
+            // the first object might be a PGP marker packet.
+            //
+            if (o is PgpEncryptedDataList)
+            {
+                enc = (PgpEncryptedDataList) o;
+            }
+            else
+            {
+                enc = (PgpEncryptedDataList) pgpF.NextPgpObject();
+            }
+
+            PgpPbeEncryptedData pbe = (PgpPbeEncryptedData)enc[0];
+
+            Stream clear = pbe.GetDataStream(passPhrase);
+
+            PgpObjectFactory pgpFact = new PgpObjectFactory(clear);
+
+            PgpCompressedData cData = (PgpCompressedData) pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(cData.GetDataStream());
+
+            PgpLiteralData ld = (PgpLiteralData) pgpFact.NextPgpObject();
+
+            Stream unc = ld.GetInputStream();
+
+			return Streams.ReadAll(unc);
+        }
+
+        /**
+        * Simple PGP encryptor between byte[].
+        *
+        * @param clearData  The test to be encrypted
+        * @param passPhrase The pass phrase (key).  This method assumes that the
+        *                   key is a simple pass phrase, and does not yet support
+        *                   RSA or more sophisiticated keying.
+        * @param fileName   File name. This is used in the Literal Data Packet (tag 11)
+        *                   which is really inly important if the data is to be
+        *                   related to a file to be recovered later.  Because this
+        *                   routine does not know the source of the information, the
+        *                   caller can set something here for file name use that
+        *                   will be carried.  If this routine is being used to
+        *                   encrypt SOAP MIME bodies, for example, use the file name from the
+        *                   MIME type, if applicable. Or anything else appropriate.
+        *
+        * @param armor
+        *
+        * @return encrypted data.
+        * @exception IOException
+        * @exception PgpException
+        */
+        public static byte[] Encrypt(
+            byte[]						clearData,
+            char[]						passPhrase,
+            string						fileName,
+            SymmetricKeyAlgorithmTag	algorithm,
+            bool						armor)
+        {
+            if (fileName == null)
+            {
+                fileName = PgpLiteralData.Console;
+            }
+
+			byte[] compressedData = Compress(clearData, fileName, CompressionAlgorithmTag.Zip);
+
+			MemoryStream bOut = new MemoryStream();
+
+			Stream output = bOut;
+			if (armor)
+			{
+				output = new ArmoredOutputStream(output);
+			}
+
+			PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(algorithm, new SecureRandom());
+            encGen.AddMethod(passPhrase);
+
+			Stream encOut = encGen.Open(output, compressedData.Length);
+
+			encOut.Write(compressedData, 0, compressedData.Length);
+			encOut.Close();
+			
+			if (armor)
+			{
+				output.Close();
+			}
+
+			return bOut.ToArray();
+        }
+
+		private static byte[] Compress(byte[] clearData, string fileName, CompressionAlgorithmTag algorithm)
+		{
+            MemoryStream bOut = new MemoryStream();
+
+            PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(algorithm);
+            Stream cos = comData.Open(bOut); // open it with the final destination
+            PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
+
+            // we want to Generate compressed data. This might be a user option later,
+            // in which case we would pass in bOut.
+            Stream pOut = lData.Open(
+				cos,					// the compressed output stream
+                PgpLiteralData.Binary,
+                fileName,				// "filename" to store
+                clearData.Length,		// length of clear data
+                DateTime.UtcNow			// current time
+            );
+
+			pOut.Write(clearData, 0, clearData.Length);
+			pOut.Close();
+
+			comData.Close();
+
+			return bOut.ToArray();
+		}
+
+		private static string GetAsciiString(byte[] bs)
+		{
+			return Encoding.ASCII.GetString(bs, 0, bs.Length);
+		}
+
+        public static void Main(
+			string[] args)
+        {
+            string passPhrase = "Dick Beck";
+            char[] passArray = passPhrase.ToCharArray();
+
+            byte[] original = Encoding.ASCII.GetBytes("Hello world");
+            Console.WriteLine("Starting PGP test");
+            byte[] encrypted = Encrypt(original, passArray, "iway", SymmetricKeyAlgorithmTag.Cast5, true);
+
+            Console.WriteLine("\nencrypted data = '"+Hex.ToHexString(encrypted)+"'");
+            byte[] decrypted= Decrypt(encrypted,passArray);
+
+            Console.WriteLine("\ndecrypted data = '"+GetAsciiString(decrypted)+"'");
+
+            encrypted = Encrypt(original, passArray, "iway", SymmetricKeyAlgorithmTag.Aes256, false);
+
+            Console.WriteLine("\nencrypted data = '"+Hex.ToHexString(encrypted)+"'");
+            decrypted= Decrypt(encrypted, passArray);
+
+            Console.WriteLine("\ndecrypted data = '"+GetAsciiString(decrypted)+"'");
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs b/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs
new file mode 100644
index 000000000..14fa37269
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/ClearSignedFileProcessor.cs
@@ -0,0 +1,375 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that creates clear signed files and verifies them.
+    * <p>
+    * To sign a file: ClearSignedFileProcessor -s fileName secretKey passPhrase.
+	* </p>
+    * <p>
+    * To decrypt: ClearSignedFileProcessor -v fileName signatureFile publicKeyFile.
+	* </p>
+    */
+    public sealed class ClearSignedFileProcessor
+    {
+        private ClearSignedFileProcessor()
+        {
+        }
+
+		private static int ReadInputLine(
+			MemoryStream	bOut,
+			Stream			fIn)
+		{
+			bOut.SetLength(0);
+
+			int lookAhead = -1;
+			int ch;
+
+			while ((ch = fIn.ReadByte()) >= 0)
+			{
+				bOut.WriteByte((byte) ch);
+				if (ch == '\r' || ch == '\n')
+				{
+					lookAhead = ReadPassedEol(bOut, ch, fIn);
+					break;
+				}
+			}
+
+			return lookAhead;
+		}
+
+		private static int ReadInputLine(
+			MemoryStream	bOut,
+			int				lookAhead,
+			Stream			fIn)
+		{
+			bOut.SetLength(0);
+
+			int ch = lookAhead;
+
+			do
+			{
+				bOut.WriteByte((byte) ch);
+				if (ch == '\r' || ch == '\n')
+				{
+					lookAhead = ReadPassedEol(bOut, ch, fIn);
+					break;
+				}
+			}
+			while ((ch = fIn.ReadByte()) >= 0);
+
+			if (ch < 0)
+			{
+				lookAhead = -1;
+			}
+
+			return lookAhead;
+		}
+
+		private static int ReadPassedEol(
+			MemoryStream	bOut,
+			int				lastCh,
+			Stream			fIn)
+		{
+			int lookAhead = fIn.ReadByte();
+
+			if (lastCh == '\r' && lookAhead == '\n')
+			{
+				bOut.WriteByte((byte) lookAhead);
+				lookAhead = fIn.ReadByte();
+			}
+
+			return lookAhead;
+		}
+
+		/*
+		* verify a clear text signed file
+		*/
+        private static void VerifyFile(
+            Stream	inputStream,
+            Stream	keyIn,
+			string	resultName)
+        {
+			ArmoredInputStream aIn = new ArmoredInputStream(inputStream);
+			Stream outStr = File.Create(resultName);
+
+			//
+			// write out signed section using the local line separator.
+			// note: trailing white space needs to be removed from the end of
+			// each line RFC 4880 Section 7.1
+			//
+			MemoryStream lineOut = new MemoryStream();
+			int lookAhead = ReadInputLine(lineOut, aIn);
+			byte[] lineSep = LineSeparator;
+
+			if (lookAhead != -1 && aIn.IsClearText())
+			{
+				byte[] line = lineOut.ToArray();
+				outStr.Write(line, 0, GetLengthWithoutSeparatorOrTrailingWhitespace(line));
+				outStr.Write(lineSep, 0, lineSep.Length);
+
+				while (lookAhead != -1 && aIn.IsClearText())
+				{
+					lookAhead = ReadInputLine(lineOut, lookAhead, aIn);
+                
+					line = lineOut.ToArray();
+					outStr.Write(line, 0, GetLengthWithoutSeparatorOrTrailingWhitespace(line));
+					outStr.Write(lineSep, 0, lineSep.Length);
+				}
+			}
+
+			outStr.Close();
+
+			PgpPublicKeyRingBundle pgpRings = new PgpPublicKeyRingBundle(keyIn);
+
+			PgpObjectFactory pgpFact = new PgpObjectFactory(aIn);
+			PgpSignatureList p3 = (PgpSignatureList) pgpFact.NextPgpObject();
+			PgpSignature sig = p3[0];
+
+			sig.InitVerify(pgpRings.GetPublicKey(sig.KeyId));
+
+			//
+			// read the input, making sure we ignore the last newline.
+			//
+			Stream sigIn = File.OpenRead(resultName);
+
+			lookAhead = ReadInputLine(lineOut, sigIn);
+
+			ProcessLine(sig, lineOut.ToArray());
+
+			if (lookAhead != -1)
+			{
+				do
+				{
+					lookAhead = ReadInputLine(lineOut, lookAhead, sigIn);
+
+					sig.Update((byte) '\r');
+					sig.Update((byte) '\n');
+
+					ProcessLine(sig, lineOut.ToArray());
+				}
+				while (lookAhead != -1);
+			}
+
+			sigIn.Close();
+
+			if (sig.Verify())
+            {
+                Console.WriteLine("signature verified.");
+            }
+            else
+            {
+                Console.WriteLine("signature verification failed.");
+            }
+        }
+
+		private static byte[] LineSeparator
+		{
+			get { return Encoding.ASCII.GetBytes(SimpleTest.NewLine); }
+		}
+
+        /*
+        * create a clear text signed file.
+        */
+        private static void SignFile(
+            string	fileName,
+            Stream	keyIn,
+            Stream	outputStream,
+            char[]	pass,
+			string	digestName)
+        {
+			HashAlgorithmTag digest;
+
+			if (digestName.Equals("SHA256"))
+			{
+				digest = HashAlgorithmTag.Sha256;
+			}
+			else if (digestName.Equals("SHA384"))
+			{
+				digest = HashAlgorithmTag.Sha384;
+			}
+			else if (digestName.Equals("SHA512"))
+			{
+				digest = HashAlgorithmTag.Sha512;
+			}
+			else if (digestName.Equals("MD5"))
+			{
+				digest = HashAlgorithmTag.MD5;
+			}
+			else if (digestName.Equals("RIPEMD160"))
+			{
+				digest = HashAlgorithmTag.RipeMD160;
+			}
+			else
+			{
+				digest = HashAlgorithmTag.Sha1;
+			}
+
+			PgpSecretKey                    pgpSecKey = PgpExampleUtilities.ReadSecretKey(keyIn);
+            PgpPrivateKey                   pgpPrivKey = pgpSecKey.ExtractPrivateKey(pass);
+            PgpSignatureGenerator           sGen = new PgpSignatureGenerator(pgpSecKey.PublicKey.Algorithm, digest);
+            PgpSignatureSubpacketGenerator  spGen = new PgpSignatureSubpacketGenerator();
+
+			sGen.InitSign(PgpSignature.CanonicalTextDocument, pgpPrivKey);
+
+			IEnumerator enumerator = pgpSecKey.PublicKey.GetUserIds().GetEnumerator();
+            if (enumerator.MoveNext())
+            {
+                spGen.SetSignerUserId(false, (string) enumerator.Current);
+                sGen.SetHashedSubpackets(spGen.Generate());
+            }
+
+            Stream fIn = File.OpenRead(fileName);
+			ArmoredOutputStream aOut = new ArmoredOutputStream(outputStream);
+
+			aOut.BeginClearText(digest);
+
+			//
+			// note the last \n/\r/\r\n in the file is ignored
+			//
+			MemoryStream lineOut = new MemoryStream();
+			int lookAhead = ReadInputLine(lineOut, fIn);
+
+			ProcessLine(aOut, sGen, lineOut.ToArray());
+
+			if (lookAhead != -1)
+			{
+				do
+				{
+					lookAhead = ReadInputLine(lineOut, lookAhead, fIn);
+
+					sGen.Update((byte) '\r');
+					sGen.Update((byte) '\n');
+
+					ProcessLine(aOut, sGen, lineOut.ToArray());
+				}
+				while (lookAhead != -1);
+			}
+
+			fIn.Close();
+
+			aOut.EndClearText();
+
+			BcpgOutputStream bOut = new BcpgOutputStream(aOut);
+
+            sGen.Generate().Encode(bOut);
+
+            aOut.Close();
+        }
+
+		private static void ProcessLine(
+			PgpSignature	sig,
+			byte[]			line)
+		{
+			// note: trailing white space needs to be removed from the end of
+			// each line for signature calculation RFC 4880 Section 7.1
+			int length = GetLengthWithoutWhiteSpace(line);
+			if (length > 0)
+			{
+				sig.Update(line, 0, length);
+			}
+		}
+
+		private static void ProcessLine(
+			Stream					aOut,
+			PgpSignatureGenerator	sGen,
+			byte[]					line)
+		{
+			int length = GetLengthWithoutWhiteSpace(line);
+			if (length > 0)
+			{
+				sGen.Update(line, 0, length);
+			}
+
+			aOut.Write(line, 0, line.Length);
+		}
+
+		private static int GetLengthWithoutSeparatorOrTrailingWhitespace(byte[] line)
+		{
+			int end = line.Length - 1;
+
+			while (end >= 0 && IsWhiteSpace(line[end]))
+			{
+				end--;
+			}
+
+			return end + 1;
+		}
+
+		private static bool IsLineEnding(
+			byte b)
+		{
+			return b == '\r' || b == '\n';
+		}
+
+		private static int GetLengthWithoutWhiteSpace(
+			byte[] line)
+		{
+			int end = line.Length - 1;
+
+			while (end >= 0 && IsWhiteSpace(line[end]))
+			{
+				end--;
+			}
+
+			return end + 1;
+		}
+
+		private static bool IsWhiteSpace(
+			byte b)
+		{
+			return IsLineEnding(b) || b == '\t' || b == ' ';
+		}
+
+		public static int Main(
+            string[] args)
+        {
+            if (args[0].Equals("-s"))
+            {
+				Stream fis = File.OpenRead(args[2]);
+				Stream fos = File.Create(args[1] + ".asc");
+
+				Stream keyIn = PgpUtilities.GetDecoderStream(fis);
+
+				string digestName = (args.Length == 4)
+					?	"SHA1"
+					:	args[4];
+
+				SignFile(args[1], keyIn, fos, args[3].ToCharArray(), digestName);
+
+				fis.Close();
+				fos.Close();
+            }
+            else if (args[0].Equals("-v"))
+            {
+				if (args[1].IndexOf(".asc") < 0)
+				{
+					Console.Error.WriteLine("file needs to end in \".asc\"");
+					return 1;
+				}
+
+				Stream fin = File.OpenRead(args[1]);
+				Stream fis = File.OpenRead(args[2]);
+
+				Stream keyIn = PgpUtilities.GetDecoderStream(fis);
+
+				VerifyFile(fin, keyIn, args[1].Substring(0, args[1].Length - 4));
+
+				fin.Close();
+				fis.Close();
+            }
+            else
+            {
+                Console.Error.WriteLine("usage: ClearSignedFileProcessor [-s file keyfile passPhrase]|[-v sigFile keyFile]");
+            }
+			return 0;
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/DetachedSignatureProcessor.cs b/crypto/test/src/openpgp/examples/DetachedSignatureProcessor.cs
new file mode 100644
index 000000000..c4959844d
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/DetachedSignatureProcessor.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections;
+using System.IO;
+
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that creates seperate signatures for files and verifies them.
+    * <p>
+    * To sign a file: DetachedSignatureProcessor -s [-a] fileName secretKey passPhrase.<br/>
+    * If -a is specified the output file will be "ascii-armored".</p>
+    * <p>
+    * To decrypt: DetachedSignatureProcessor -v  fileName signatureFile publicKeyFile.</p>
+    * <p>
+    * Note: this example will silently overwrite files.
+    * It also expects that a single pass phrase
+    * will have been used.</p>
+    */
+    public sealed class DetachedSignatureProcessor
+    {
+        private DetachedSignatureProcessor()
+        {
+        }
+
+		private static void VerifySignature(
+			string	fileName,
+			string	inputFileName,
+			string	keyFileName)
+		{
+			using (Stream input = File.OpenRead(inputFileName),
+				keyIn = File.OpenRead(keyFileName))
+			{
+				VerifySignature(fileName, input, keyIn);
+			}
+		}
+
+		/**
+        * verify the signature in in against the file fileName.
+        */
+        private static void VerifySignature(
+            string	fileName,
+            Stream	inputStream,
+            Stream	keyIn)
+        {
+            inputStream = PgpUtilities.GetDecoderStream(inputStream);
+
+            PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream);
+            PgpSignatureList p3 = null;
+            PgpObject o = pgpFact.NextPgpObject();
+            if (o is PgpCompressedData)
+            {
+                PgpCompressedData c1 = (PgpCompressedData)o;
+                pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+                p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+            }
+            else
+            {
+                p3 = (PgpSignatureList)o;
+            }
+
+            PgpPublicKeyRingBundle pgpPubRingCollection = new PgpPublicKeyRingBundle(
+				PgpUtilities.GetDecoderStream(keyIn));
+            Stream dIn = File.OpenRead(fileName);
+            PgpSignature sig = p3[0];
+            PgpPublicKey key = pgpPubRingCollection.GetPublicKey(sig.KeyId);
+            sig.InitVerify(key);
+
+			int ch;
+            while ((ch = dIn.ReadByte()) >= 0)
+            {
+                sig.Update((byte)ch);
+            }
+
+			dIn.Close();
+
+			if (sig.Verify())
+            {
+                Console.WriteLine("signature verified.");
+            }
+            else
+            {
+                Console.WriteLine("signature verification failed.");
+            }
+        }
+
+		private static void CreateSignature(
+			string	inputFileName,
+			string	keyFileName,
+			string	outputFileName,
+			char[]	pass,
+			bool	armor)
+		{
+			using (Stream keyIn = File.OpenRead(keyFileName),
+				output = File.OpenRead(outputFileName))
+			{
+				CreateSignature(inputFileName, keyIn, output, pass, armor);
+			}
+		}
+
+		private static void CreateSignature(
+			string	fileName,
+			Stream	keyIn,
+			Stream	outputStream,
+			char[]	pass,
+			bool	armor)
+        {
+            if (armor)
+            {
+                outputStream = new ArmoredOutputStream(outputStream);
+            }
+
+            PgpSecretKey pgpSec = PgpExampleUtilities.ReadSecretKey(keyIn);
+            PgpPrivateKey pgpPrivKey = pgpSec.ExtractPrivateKey(pass);
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+				pgpSec.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+
+			sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
+
+			BcpgOutputStream bOut = new BcpgOutputStream(outputStream);
+
+			Stream fIn = File.OpenRead(fileName);
+
+            int ch;
+            while ((ch = fIn.ReadByte()) >= 0)
+            {
+                sGen.Update((byte)ch);
+            }
+
+			fIn.Close();
+
+			sGen.Generate().Encode(bOut);
+
+			if (armor)
+			{
+				outputStream.Close();
+			}
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            if (args[0].Equals("-s"))
+            {
+                if (args[1].Equals("-a"))
+                {
+					CreateSignature(args[2], args[3], args[2] + ".asc", args[4].ToCharArray(), true);
+                }
+                else
+                {
+					CreateSignature(args[1], args[2], args[1] + ".bpg", args[3].ToCharArray(), false);
+                }
+            }
+            else if (args[0].Equals("-v"))
+            {
+				VerifySignature(args[1], args[2], args[3]);
+			}
+            else
+            {
+                Console.Error.WriteLine("usage: DetachedSignatureProcessor [-s [-a] file keyfile passPhrase]|[-v file sigFile keyFile]");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/DirectKeySignature.cs b/crypto/test/src/openpgp/examples/DirectKeySignature.cs
new file mode 100644
index 000000000..a6bf8e755
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/DirectKeySignature.cs
@@ -0,0 +1,140 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg;
+using Org.BouncyCastle.Bcpg.Sig;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+	/**
+	* A simple utility class that directly signs a public key and writes the signed key to "SignedKey.asc" in 
+	* the current working directory.
+	* <p>
+	* To sign a key: DirectKeySignature secretKeyFile secretKeyPass publicKeyFile(key to be signed) NotationName NotationValue.<br/>
+	* </p><p>
+	* To display a NotationData packet from a publicKey previously signed: DirectKeySignature signedPublicKeyFile.<br/>
+	* </p><p>
+	* <b>Note</b>: this example will silently overwrite files, nor does it pay any attention to
+	* the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
+	* will have been used.
+	* </p>
+	*/
+	public class DirectKeySignature
+	{
+		public static void Main(
+			string[] args)
+		{
+			if (args.Length == 1)
+			{
+				Stream fis = File.OpenRead(args[0]);
+
+				PgpPublicKeyRing ring = new PgpPublicKeyRing(
+					PgpUtilities.GetDecoderStream(fis));
+				PgpPublicKey key = ring.GetPublicKey();
+
+				// iterate through all direct key signautures and look for NotationData subpackets
+				foreach (PgpSignature sig in key.GetSignaturesOfType(PgpSignature.DirectKey))
+				{
+					Console.WriteLine("Signature date is: "
+						+ sig.GetHashedSubPackets().GetSignatureCreationTime());
+
+					NotationData[] data = sig.GetHashedSubPackets().GetNotationDataOccurences();
+
+					for (int i = 0; i < data.Length; i++)
+					{
+						Console.WriteLine("Found Notaion named '" + data[i].GetNotationName()
+							+"' with content '" + data[i].GetNotationValue() + "'.");
+					}
+				}
+
+				fis.Close();
+			}
+			else if (args.Length == 5)
+			{
+				Stream secFis = File.OpenRead(args[0]);
+				Stream pubFis = File.OpenRead(args[2]);
+
+				// gather command line arguments
+				PgpSecretKeyRing secRing = new PgpSecretKeyRing(
+					PgpUtilities.GetDecoderStream(secFis));
+				String secretKeyPass = args[1];
+				PgpPublicKeyRing ring = new PgpPublicKeyRing(
+					PgpUtilities.GetDecoderStream(pubFis));
+				String notationName = args[3];
+				String notationValue = args[4];
+
+				// create the signed keyRing
+				PgpPublicKeyRing sRing = null;
+				sRing = new PgpPublicKeyRing(
+					new MemoryStream(
+						SignPublicKey(secRing.GetSecretKey(), secretKeyPass,
+							ring.GetPublicKey(), notationName, notationValue, true),
+						false));
+				ring = sRing;
+
+				secFis.Close();
+				pubFis.Close();
+
+				Stream fos = File.Create("SignedKey.asc");
+
+				// write the created keyRing to file
+				ArmoredOutputStream aOut = new ArmoredOutputStream(fos);
+				sRing.Encode(aOut);
+				aOut.Close();
+
+				// Note: ArmoredOutputStream.Close() leaves underlying stream open
+				fos.Close();
+			}
+			else
+			{
+				Console.Error.WriteLine("usage: DirectKeySignature secretKeyFile secretKeyPass publicKeyFile(key to be signed) NotationName NotationValue");
+				Console.Error.WriteLine("or: DirectKeySignature signedPublicKeyFile");
+			}
+		}
+
+		private static byte[] SignPublicKey(
+			PgpSecretKey	secretKey,
+			string			secretKeyPass,
+			PgpPublicKey	keyToBeSigned,
+			string			notationName,
+			string			notationValue,
+			bool			armor)
+		{
+			Stream os = new MemoryStream();
+			if (armor)
+			{
+				os = new ArmoredOutputStream(os);
+			}
+
+			PgpPrivateKey pgpPrivKey = secretKey.ExtractPrivateKey(
+				secretKeyPass.ToCharArray());
+
+			PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+				secretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+
+			sGen.InitSign(PgpSignature.DirectKey, pgpPrivKey);
+
+			BcpgOutputStream bOut = new BcpgOutputStream(os);
+
+			sGen.GenerateOnePassVersion(false).Encode(bOut);
+
+			PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
+
+			bool isHumanReadable = true;
+
+			spGen.SetNotationData(true, isHumanReadable, notationName, notationValue);
+
+			PgpSignatureSubpacketVector packetVector = spGen.Generate();
+			sGen.SetHashedSubpackets(packetVector);
+
+			bOut.Flush();
+
+			if (armor)
+			{
+				os.Close();
+			}
+
+			return PgpPublicKey.AddCertification(keyToBeSigned, sGen.Generate()).GetEncoded();
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/examples/DsaElGamalKeyRingGenerator.cs b/crypto/test/src/openpgp/examples/DsaElGamalKeyRingGenerator.cs
new file mode 100644
index 000000000..6040351a3
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/DsaElGamalKeyRingGenerator.cs
@@ -0,0 +1,134 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that Generates a public/secret keyring containing a DSA signing
+    * key and an El Gamal key for encryption.
+    * <p>
+    * usage: DSAElGamalKeyRingGenerator [-a] identity passPhrase</p>
+    * <p>
+    * Where identity is the name to be associated with the public key. The keys are placed
+    * in the files pub.[asc|bpg] and secret.[asc|bpg].</p>
+    * <p>
+    * <b>Note</b>: this example encrypts the secret key using AES_256, many PGP products still
+    * do not support this, if you are having problems importing keys try changing the algorithm
+    * id to PgpEncryptedData.Cast5. CAST5 is more widelysupported.</p>
+    */
+    public sealed class DsaElGamalKeyRingGenerator
+    {
+        private DsaElGamalKeyRingGenerator()
+        {
+        }
+
+		private static void ExportKeyPair(
+            Stream					secretOut,
+            Stream					publicOut,
+            AsymmetricCipherKeyPair	dsaKp,
+            AsymmetricCipherKeyPair	elgKp,
+            string					identity,
+            char[]					passPhrase,
+            bool					armor)
+        {
+            if (armor)
+            {
+                secretOut = new ArmoredOutputStream(secretOut);
+            }
+
+			PgpKeyPair dsaKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.Dsa, dsaKp, DateTime.UtcNow);
+            PgpKeyPair elgKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.ElGamalEncrypt, elgKp, DateTime.UtcNow);
+
+			PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification, dsaKeyPair,
+				identity, SymmetricKeyAlgorithmTag.Aes256, passPhrase, true, null, null, new SecureRandom());
+
+			keyRingGen.AddSubKey(elgKeyPair);
+
+			keyRingGen.GenerateSecretKeyRing().Encode(secretOut);
+
+			if (armor)
+            {
+				secretOut.Close();
+				publicOut = new ArmoredOutputStream(publicOut);
+            }
+
+			keyRingGen.GeneratePublicKeyRing().Encode(publicOut);
+
+			if (armor)
+			{
+				publicOut.Close();
+			}
+        }
+
+		public static int Main(
+            string[] args)
+        {
+            if (args.Length < 2)
+            {
+                Console.WriteLine("DsaElGamalKeyRingGenerator [-a] identity passPhrase");
+                return 0;
+            }
+
+			IAsymmetricCipherKeyPairGenerator dsaKpg = GeneratorUtilities.GetKeyPairGenerator("DSA");
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+            pGen.Init(1024, 80, new SecureRandom());
+            DsaParameters dsaParams = pGen.GenerateParameters();
+            DsaKeyGenerationParameters kgp = new DsaKeyGenerationParameters(new SecureRandom(), dsaParams);
+            dsaKpg.Init(kgp);
+
+
+			//
+            // this takes a while as the key generator has to Generate some DSA parameters
+            // before it Generates the key.
+            //
+            AsymmetricCipherKeyPair dsaKp = dsaKpg.GenerateKeyPair();
+
+
+			IAsymmetricCipherKeyPairGenerator elgKpg = GeneratorUtilities.GetKeyPairGenerator("ELGAMAL");
+
+			BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+            BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+			ElGamalParameters elParams = new ElGamalParameters(p, g);
+            ElGamalKeyGenerationParameters elKgp = new ElGamalKeyGenerationParameters(new SecureRandom(), elParams);
+            elgKpg.Init(elKgp);
+
+			//
+            // this is quicker because we are using preGenerated parameters.
+            //
+            AsymmetricCipherKeyPair elgKp = elgKpg.GenerateKeyPair();
+
+			Stream out1, out2;
+			if (args[0].Equals("-a"))
+            {
+                if (args.Length < 3)
+                {
+                    Console.WriteLine("DSAElGamalKeyRingGenerator [-a] identity passPhrase");
+                    return 0;
+                }
+
+				out1 = File.Create("secret.asc");
+                out2 = File.Create("pub.asc");
+
+				ExportKeyPair(out1, out2, dsaKp, elgKp, args[1], args[2].ToCharArray(), true);
+            }
+            else
+            {
+                out1 = File.Create("secret.bpg");
+                out2 = File.Create("pub.bpg");
+
+				ExportKeyPair(out1, out2, dsaKp, elgKp, args[0], args[1].ToCharArray(), false);
+            }
+			out1.Close();
+			out2.Close();
+			return 0;
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/KeyBasedFileProcessor.cs b/crypto/test/src/openpgp/examples/KeyBasedFileProcessor.cs
new file mode 100644
index 000000000..c77408b1f
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/KeyBasedFileProcessor.cs
@@ -0,0 +1,259 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that encrypts/decrypts public key based
+    * encryption files.
+    * <p>
+    * To encrypt a file: KeyBasedFileProcessor -e [-a|-ai] fileName publicKeyFile.<br/>
+    * If -a is specified the output file will be "ascii-armored".
+    * If -i is specified the output file will be have integrity checking added.</p>
+    * <p>
+    * To decrypt: KeyBasedFileProcessor -d fileName secretKeyFile passPhrase.</p>
+    * <p>
+	* Note 1: this example will silently overwrite files, nor does it pay any attention to
+	* the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
+	* will have been used.</p>
+	* <p>
+	* Note 2: if an empty file name has been specified in the literal data object contained in the
+	* encrypted packet a file with the name filename.out will be generated in the current working directory.</p>
+    */
+    public sealed class KeyBasedFileProcessor
+    {
+        private KeyBasedFileProcessor()
+        {
+        }
+
+		private static void DecryptFile(
+			string	inputFileName,
+			string	keyFileName,
+			char[]	passwd,
+			string	defaultFileName)
+		{
+			using (Stream input = File.OpenRead(inputFileName),
+			       keyIn = File.OpenRead(keyFileName))
+			{
+				DecryptFile(input, keyIn, passwd, defaultFileName);
+			}
+		}
+
+		/**
+		 * decrypt the passed in message stream
+		 */
+		private static void DecryptFile(
+			Stream	inputStream,
+			Stream	keyIn,
+			char[]	passwd,
+			string	defaultFileName)
+		{
+            inputStream = PgpUtilities.GetDecoderStream(inputStream);
+
+            try
+            {
+                PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
+                PgpEncryptedDataList enc;
+
+                PgpObject o = pgpF.NextPgpObject();
+                //
+                // the first object might be a PGP marker packet.
+                //
+                if (o is PgpEncryptedDataList)
+                {
+                    enc = (PgpEncryptedDataList)o;
+                }
+                else
+                {
+                    enc = (PgpEncryptedDataList)pgpF.NextPgpObject();
+                }
+
+                //
+                // find the secret key
+                //
+                PgpPrivateKey sKey = null;
+                PgpPublicKeyEncryptedData pbe = null;
+				PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(
+					PgpUtilities.GetDecoderStream(keyIn));
+
+				foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
+                {
+                    sKey = PgpExampleUtilities.FindSecretKey(pgpSec, pked.KeyId, passwd);
+
+                    if (sKey != null)
+                    {
+                        pbe = pked;
+                        break;
+                    }
+                }
+
+				if (sKey == null)
+                {
+                    throw new ArgumentException("secret key for message not found.");
+                }
+
+                Stream clear = pbe.GetDataStream(sKey);
+
+                PgpObjectFactory plainFact = new PgpObjectFactory(clear);
+
+                PgpObject message = plainFact.NextPgpObject();
+
+                if (message is PgpCompressedData)
+                {
+                    PgpCompressedData cData = (PgpCompressedData)message;
+                    PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream());
+
+                    message = pgpFact.NextPgpObject();
+                }
+
+                if (message is PgpLiteralData)
+                {
+                    PgpLiteralData ld = (PgpLiteralData)message;
+
+					string outFileName = ld.FileName;
+					if (outFileName.Length == 0)
+					{
+						outFileName = defaultFileName;
+					}
+
+					Stream fOut = File.Create(outFileName);
+					Stream unc = ld.GetInputStream();
+					Streams.PipeAll(unc, fOut);
+					fOut.Close();
+                }
+                else if (message is PgpOnePassSignatureList)
+                {
+                    throw new PgpException("encrypted message contains a signed message - not literal data.");
+                }
+                else
+                {
+                    throw new PgpException("message is not a simple encrypted file - type unknown.");
+                }
+
+                if (pbe.IsIntegrityProtected())
+                {
+                    if (!pbe.Verify())
+                    {
+                        Console.Error.WriteLine("message failed integrity check");
+                    }
+                    else
+                    {
+                        Console.Error.WriteLine("message integrity check passed");
+                    }
+                }
+                else
+                {
+                    Console.Error.WriteLine("no message integrity check");
+                }
+            }
+            catch (PgpException e)
+            {
+                Console.Error.WriteLine(e);
+
+                Exception underlyingException = e.InnerException;
+                if (underlyingException != null)
+                {
+                    Console.Error.WriteLine(underlyingException.Message);
+                    Console.Error.WriteLine(underlyingException.StackTrace);
+                }
+            }
+        }
+		
+		private static void EncryptFile(
+			string	outputFileName,
+			string	inputFileName,
+			string	encKeyFileName,
+			bool	armor,
+			bool	withIntegrityCheck)
+		{
+			PgpPublicKey encKey = PgpExampleUtilities.ReadPublicKey(encKeyFileName);
+
+			using (Stream output = File.Create(outputFileName))
+			{
+				EncryptFile(output, inputFileName, encKey, armor, withIntegrityCheck);
+			}
+		}
+
+        private static void EncryptFile(
+            Stream			outputStream,
+            string			fileName,
+            PgpPublicKey	encKey,
+            bool			armor,
+            bool			withIntegrityCheck)
+        {
+            if (armor)
+            {
+                outputStream = new ArmoredOutputStream(outputStream);
+            }
+
+            try
+            {
+            	byte[] bytes = PgpExampleUtilities.CompressFile(fileName, CompressionAlgorithmTag.Zip);
+
+				PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(
+					SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
+				encGen.AddMethod(encKey);
+
+				Stream cOut = encGen.Open(outputStream, bytes.Length);
+
+				cOut.Write(bytes, 0, bytes.Length);
+				cOut.Close();
+
+				if (armor)
+				{
+					outputStream.Close();
+				}
+            }
+            catch (PgpException e)
+            {
+                Console.Error.WriteLine(e);
+
+                Exception underlyingException = e.InnerException;
+                if (underlyingException != null)
+                {
+                    Console.Error.WriteLine(underlyingException.Message);
+                    Console.Error.WriteLine(underlyingException.StackTrace);
+                }
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            if (args.Length == 0)
+            {
+                Console.Error.WriteLine("usage: KeyBasedFileProcessor -e|-d [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
+                return;
+            }
+
+            if (args[0].Equals("-e"))
+            {
+                if (args[1].Equals("-a") || args[1].Equals("-ai") || args[1].Equals("-ia"))
+                {
+					EncryptFile(args[2] + ".asc", args[2], args[3], true, (args[1].IndexOf('i') > 0));
+                }
+                else if (args[1].Equals("-i"))
+                {
+					EncryptFile(args[2] + ".bpg", args[2], args[3], false, true);
+                }
+                else
+                {
+					EncryptFile(args[1] + ".bpg", args[1], args[2], false, false);
+                }
+            }
+            else if (args[0].Equals("-d"))
+            {
+				DecryptFile(args[1], args[2], args[3].ToCharArray(), new FileInfo(args[1]).Name + ".out");
+            }
+            else
+            {
+                Console.Error.WriteLine("usage: KeyBasedFileProcessor -d|-e [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/KeyBasedLargeFileProcessor.cs b/crypto/test/src/openpgp/examples/KeyBasedLargeFileProcessor.cs
new file mode 100644
index 000000000..7fb00a3b7
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/KeyBasedLargeFileProcessor.cs
@@ -0,0 +1,267 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that encrypts/decrypts public key based
+    * encryption large files.
+    * <p>
+    * To encrypt a file: KeyBasedLargeFileProcessor -e [-a|-ai] fileName publicKeyFile.<br/>
+    * If -a is specified the output file will be "ascii-armored".
+    * If -i is specified the output file will be have integrity checking added.</p>
+    * <p>
+    * To decrypt: KeyBasedLargeFileProcessor -d fileName secretKeyFile passPhrase.</p>
+    * <p>
+    * Note 1: this example will silently overwrite files, nor does it pay any attention to
+    * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
+    * will have been used.</p>
+    * <p>
+    * Note 2: this example Generates partial packets to encode the file, the output it Generates
+    * will not be readable by older PGP products or products that don't support partial packet
+    * encoding.</p>
+	* <p>
+	* Note 3: if an empty file name has been specified in the literal data object contained in the
+	* encrypted packet a file with the name filename.out will be generated in the current working directory.</p>
+    */
+    public sealed class KeyBasedLargeFileProcessor
+    {
+        private KeyBasedLargeFileProcessor()
+        {
+        }
+
+		private static void DecryptFile(
+			string	inputFileName,
+			string	keyFileName,
+			char[]	passwd,
+			string	defaultFileName)
+		{
+			using (Stream input = File.OpenRead(inputFileName),
+			       keyIn = File.OpenRead(keyFileName))
+			{
+				DecryptFile(input, keyIn, passwd, defaultFileName);
+			}
+		}
+
+		/**
+        * decrypt the passed in message stream
+        */
+        private static void DecryptFile(
+            Stream	inputStream,
+            Stream	keyIn,
+			char[]	passwd,
+			string	defaultFileName)
+		{
+            inputStream = PgpUtilities.GetDecoderStream(inputStream);
+
+            try
+            {
+                PgpObjectFactory        pgpF = new PgpObjectFactory(inputStream);
+                PgpEncryptedDataList    enc;
+
+                PgpObject o = pgpF.NextPgpObject();
+                //
+                // the first object might be a PGP marker packet.
+                //
+                if (o is PgpEncryptedDataList)
+                {
+                    enc = (PgpEncryptedDataList)o;
+                }
+                else
+                {
+                    enc = (PgpEncryptedDataList)pgpF.NextPgpObject();
+                }
+
+                //
+                // find the secret key
+                //
+                PgpPrivateKey sKey = null;
+                PgpPublicKeyEncryptedData pbe = null;
+				PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(
+					PgpUtilities.GetDecoderStream(keyIn));
+
+				foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
+                {
+                    sKey = PgpExampleUtilities.FindSecretKey(pgpSec, pked.KeyId, passwd);
+
+                    if (sKey != null)
+                    {
+                        pbe = pked;
+                        break;
+                    }
+                }
+
+                if (sKey == null)
+                {
+                    throw new ArgumentException("secret key for message not found.");
+                }
+
+                Stream clear = pbe.GetDataStream(sKey);
+
+                PgpObjectFactory plainFact = new PgpObjectFactory(clear);
+
+                PgpCompressedData cData = (PgpCompressedData) plainFact.NextPgpObject();
+
+                PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream());
+
+                PgpObject message = pgpFact.NextPgpObject();
+
+                if (message is PgpLiteralData)
+                {
+                    PgpLiteralData ld = (PgpLiteralData)message;
+
+					string outFileName = ld.FileName;
+					if (outFileName.Length == 0)
+					{
+						outFileName = defaultFileName;
+					}
+
+					Stream fOut = File.Create(outFileName);
+                    Stream unc = ld.GetInputStream();
+					Streams.PipeAll(unc, fOut);
+					fOut.Close();
+                }
+                else if (message is PgpOnePassSignatureList)
+                {
+                    throw new PgpException("encrypted message contains a signed message - not literal data.");
+                }
+                else
+                {
+                    throw new PgpException("message is not a simple encrypted file - type unknown.");
+                }
+
+                if (pbe.IsIntegrityProtected())
+                {
+                    if (!pbe.Verify())
+                    {
+                        Console.Error.WriteLine("message failed integrity check");
+                    }
+                    else
+                    {
+                        Console.Error.WriteLine("message integrity check passed");
+                    }
+                }
+                else
+                {
+                    Console.Error.WriteLine("no message integrity check");
+                }
+            }
+            catch (PgpException e)
+            {
+                Console.Error.WriteLine(e);
+
+                Exception underlyingException = e.InnerException;
+                if (underlyingException != null)
+                {
+                    Console.Error.WriteLine(underlyingException.Message);
+                    Console.Error.WriteLine(underlyingException.StackTrace);
+                }
+            }
+        }
+
+		private static void EncryptFile(
+			string	outputFileName,
+			string	inputFileName,
+			string	encKeyFileName,
+			bool	armor,
+			bool	withIntegrityCheck)
+		{
+			PgpPublicKey encKey = PgpExampleUtilities.ReadPublicKey(encKeyFileName);
+
+			using (Stream output = File.Create(outputFileName))
+			{
+				EncryptFile(output, inputFileName, encKey, armor, withIntegrityCheck);
+			}
+		}
+
+        private static void EncryptFile(
+            Stream			outputStream,
+            string			fileName,
+            PgpPublicKey	encKey,
+            bool			armor,
+            bool			withIntegrityCheck)
+        {
+            if (armor)
+            {
+                outputStream = new ArmoredOutputStream(outputStream);
+            }
+
+            try
+            {
+                PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
+
+                cPk.AddMethod(encKey);
+
+                Stream cOut = cPk.Open(outputStream, new byte[1 << 16]);
+
+                PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(
+					CompressionAlgorithmTag.Zip);
+
+				PgpUtilities.WriteFileToLiteralData(
+					comData.Open(cOut),
+					PgpLiteralData.Binary,
+					new FileInfo(fileName),
+					new byte[1 << 16]);
+
+				comData.Close();
+
+				cOut.Close();
+
+				if (armor)
+				{
+					outputStream.Close();
+				}
+            }
+            catch (PgpException e)
+            {
+                Console.Error.WriteLine(e);
+
+                Exception underlyingException = e.InnerException;
+                if (underlyingException != null)
+                {
+                    Console.Error.WriteLine(underlyingException.Message);
+                    Console.Error.WriteLine(underlyingException.StackTrace);
+                }
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            if (args.Length == 0)
+            {
+                Console.Error.WriteLine("usage: KeyBasedLargeFileProcessor -e|-d [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
+                return;
+            }
+
+            if (args[0].Equals("-e"))
+            {
+                if (args[1].Equals("-a") || args[1].Equals("-ai") || args[1].Equals("-ia"))
+                {
+					EncryptFile(args[2] + ".asc", args[2], args[3], true, (args[1].IndexOf('i') > 0));
+                }
+                else if (args[1].Equals("-i"))
+                {
+					EncryptFile(args[2] + ".bpg", args[2], args[3], false, true);
+                }
+                else
+                {
+					EncryptFile(args[1] + ".bpg", args[1], args[2], false, false);
+                }
+            }
+            else if (args[0].Equals("-d"))
+            {
+				DecryptFile(args[1], args[2], args[3].ToCharArray(), new FileInfo(args[1]).Name + ".out");
+            }
+            else
+            {
+                Console.Error.WriteLine("usage: KeyBasedLargeFileProcessor -d|-e [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/PbeFileProcessor.cs b/crypto/test/src/openpgp/examples/PbeFileProcessor.cs
new file mode 100644
index 000000000..66b1cc4ed
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/PbeFileProcessor.cs
@@ -0,0 +1,183 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that encrypts/decrypts password based
+    * encryption files.
+    * <p>
+    * To encrypt a file: PBEFileProcessor -e [-ai] fileName passPhrase.<br/>
+    * If -a is specified the output file will be "ascii-armored".<br/>
+    * If -i is specified the output file will be "integrity protected".</p>
+    * <p>
+    * To decrypt: PBEFileProcessor -d fileName passPhrase.</p>
+    * <p>
+    * Note: this example will silently overwrite files, nor does it pay any attention to
+    * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
+    * will have been used.</p>
+    */
+    public sealed class PbeFileProcessor
+    {
+        private PbeFileProcessor() {}
+
+		private static void DecryptFile(string inputFileName, char[] passPhrase)
+		{
+			using (Stream input = File.OpenRead(inputFileName))
+			{
+				DecryptFile(input, passPhrase);
+			}
+		}
+
+        /**
+        * decrypt the passed in message stream
+        */
+        private static void DecryptFile(
+            Stream	inputStream,
+            char[]	passPhrase)
+        {
+            inputStream = PgpUtilities.GetDecoderStream(inputStream);
+
+			PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
+            PgpObject o = pgpF.NextPgpObject();
+
+            //
+            // the first object might be a PGP marker packet.
+            //
+			PgpEncryptedDataList enc = o as PgpEncryptedDataList;
+            if (enc == null)
+            {
+                enc = (PgpEncryptedDataList)pgpF.NextPgpObject();
+            }
+
+            PgpPbeEncryptedData pbe = (PgpPbeEncryptedData)enc[0];
+
+            Stream clear = pbe.GetDataStream(passPhrase);
+
+            PgpObjectFactory pgpFact = new PgpObjectFactory(clear);
+
+			//
+			// if we're trying to read a file generated by someone other than us
+			// the data might not be compressed, so we check the return type from
+			// the factory and behave accordingly.
+			//
+			o = pgpFact.NextPgpObject();
+			if (o is PgpCompressedData)
+			{
+				PgpCompressedData cData = (PgpCompressedData) o;
+				pgpFact = new PgpObjectFactory(cData.GetDataStream());
+				o = pgpFact.NextPgpObject();
+			}
+
+			PgpLiteralData ld = (PgpLiteralData) o;
+			Stream unc = ld.GetInputStream();
+            Stream fOut = File.Create(ld.FileName);
+			Streams.PipeAll(unc, fOut);
+			fOut.Close();
+
+			if (pbe.IsIntegrityProtected())
+            {
+                if (!pbe.Verify())
+                {
+                    Console.Error.WriteLine("message failed integrity check");
+                }
+                else
+                {
+                    Console.Error.WriteLine("message integrity check passed");
+                }
+            }
+            else
+            {
+                Console.Error.WriteLine("no message integrity check");
+            }
+        }
+
+		private static void EncryptFile(
+			string	outputFileName,
+			string	inputFileName,
+			char[]	passPhrase,
+			bool	armor,
+			bool	withIntegrityCheck)
+		{
+			using (Stream output = File.Create(outputFileName))
+			{
+				EncryptFile(output, inputFileName, passPhrase, armor, withIntegrityCheck);
+			}
+		}
+
+        private static void EncryptFile(
+            Stream	outputStream,
+            string	fileName,
+            char[]	passPhrase,
+            bool	armor,
+            bool	withIntegrityCheck)
+        {
+            if (armor)
+            {
+                outputStream = new ArmoredOutputStream(outputStream);
+            }
+
+			try
+            {
+				byte[] compressedData = PgpExampleUtilities.CompressFile(fileName, CompressionAlgorithmTag.Zip);
+
+				PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(
+					SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
+				encGen.AddMethod(passPhrase);
+
+				Stream encOut = encGen.Open(outputStream, compressedData.Length);
+
+	            encOut.Write(compressedData, 0, compressedData.Length);
+				encOut.Close();
+
+				if (armor)
+				{
+					outputStream.Close();
+				}
+            }
+            catch (PgpException e)
+            {
+                Console.Error.WriteLine(e);
+
+                Exception underlyingException = e.InnerException;
+                if (underlyingException != null)
+                {
+                    Console.Error.WriteLine(underlyingException.Message);
+                    Console.Error.WriteLine(underlyingException.StackTrace);
+                }
+            }
+        }
+
+		public static void Main(
+			string[] args)
+        {
+            if (args[0].Equals("-e"))
+            {
+                if (args[1].Equals("-a") || args[1].Equals("-ai") || args[1].Equals("-ia"))
+                {
+					EncryptFile(args[2] + ".asc", args[2], args[3].ToCharArray(), true, (args[1].IndexOf('i') > 0));
+                }
+                else if (args[1].Equals("-i"))
+                {
+					EncryptFile(args[2] + ".bpg", args[2], args[3].ToCharArray(), false, true);
+                }
+                else
+                {
+					EncryptFile(args[1] + ".bpg", args[1], args[2].ToCharArray(), false, false);
+                }
+            }
+            else if (args[0].Equals("-d"))
+            {
+				DecryptFile(args[1], args[2].ToCharArray());
+            }
+            else
+            {
+                Console.Error.WriteLine("usage: PbeFileProcessor -e [-ai]|-d file passPhrase");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/PgpExampleUtilities.cs b/crypto/test/src/openpgp/examples/PgpExampleUtilities.cs
new file mode 100644
index 000000000..fd371d7af
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/PgpExampleUtilities.cs
@@ -0,0 +1,123 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+	internal class PgpExampleUtilities
+	{
+		internal static byte[] CompressFile(string fileName, CompressionAlgorithmTag algorithm)
+		{
+			MemoryStream bOut = new MemoryStream();
+			PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(algorithm);
+			PgpUtilities.WriteFileToLiteralData(comData.Open(bOut), PgpLiteralData.Binary,
+				new FileInfo(fileName));
+			comData.Close();
+			return bOut.ToArray();
+		}
+
+		/**
+		 * Search a secret key ring collection for a secret key corresponding to keyID if it
+		 * exists.
+		 * 
+		 * @param pgpSec a secret key ring collection.
+		 * @param keyID keyID we want.
+		 * @param pass passphrase to decrypt secret key with.
+		 * @return
+		 * @throws PGPException
+		 * @throws NoSuchProviderException
+		 */
+		internal static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyID, char[] pass)
+		{
+			PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyID);
+
+			if (pgpSecKey == null)
+			{
+				return null;
+			}
+
+			return pgpSecKey.ExtractPrivateKey(pass);
+		}
+
+		internal static PgpPublicKey ReadPublicKey(string fileName)
+		{
+			using (Stream keyIn = File.OpenRead(fileName))
+			{
+				return ReadPublicKey(keyIn);
+			}
+		}
+
+		/**
+		 * A simple routine that opens a key ring file and loads the first available key
+		 * suitable for encryption.
+		 * 
+		 * @param input
+		 * @return
+		 * @throws IOException
+		 * @throws PGPException
+		 */
+		internal static PgpPublicKey ReadPublicKey(Stream input)
+		{
+			PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(
+				PgpUtilities.GetDecoderStream(input));
+
+			//
+			// we just loop through the collection till we find a key suitable for encryption, in the real
+			// world you would probably want to be a bit smarter about this.
+			//
+
+			foreach (PgpPublicKeyRing keyRing in pgpPub.GetKeyRings())
+			{
+				foreach (PgpPublicKey key in keyRing.GetPublicKeys())
+				{
+					if (key.IsEncryptionKey)
+					{
+						return key;
+					}
+				}
+			}
+
+			throw new ArgumentException("Can't find encryption key in key ring.");
+		}
+
+		internal static PgpSecretKey ReadSecretKey(string fileName)
+		{
+			using (Stream keyIn = File.OpenRead(fileName))
+			{
+				return ReadSecretKey(keyIn);
+			}
+		}
+
+		/**
+		 * A simple routine that opens a key ring file and loads the first available key
+		 * suitable for signature generation.
+		 * 
+		 * @param input stream to read the secret key ring collection from.
+		 * @return a secret key.
+		 * @throws IOException on a problem with using the input stream.
+		 * @throws PGPException if there is an issue parsing the input stream.
+		 */
+		internal static PgpSecretKey ReadSecretKey(Stream input)
+		{
+			PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle(
+				PgpUtilities.GetDecoderStream(input));
+
+			//
+			// we just loop through the collection till we find a key suitable for encryption, in the real
+			// world you would probably want to be a bit smarter about this.
+			//
+
+			foreach (PgpSecretKeyRing keyRing in pgpSec.GetKeyRings())
+			{
+				foreach (PgpSecretKey key in keyRing.GetSecretKeys())
+				{
+					if (key.IsSigningKey)
+					{
+						return key;
+					}
+				}
+			}
+
+			throw new ArgumentException("Can't find signing key in key ring.");
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/examples/PublicKeyRingDump.cs b/crypto/test/src/openpgp/examples/PublicKeyRingDump.cs
new file mode 100644
index 000000000..bb6108f2d
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/PublicKeyRingDump.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * Basic class which just lists the contents of the public key file passed
+    * as an argument. If the file contains more than one "key ring" they are
+    * listed in the order found.
+    */
+    public sealed class PublicKeyRingDump
+    {
+        private PublicKeyRingDump()
+        {
+        }
+
+        public static string GetAlgorithm(
+            PublicKeyAlgorithmTag algId)
+        {
+            switch (algId)
+            {
+                case PublicKeyAlgorithmTag.RsaGeneral:
+                    return "RsaGeneral";
+                case PublicKeyAlgorithmTag.RsaEncrypt:
+                    return "RsaEncrypt";
+                case PublicKeyAlgorithmTag.RsaSign:
+                    return "RsaSign";
+                case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                    return "ElGamalEncrypt";
+                case PublicKeyAlgorithmTag.Dsa:
+                    return "DSA";
+                case PublicKeyAlgorithmTag.EC:
+                    return "EC";
+                case PublicKeyAlgorithmTag.ECDsa:
+                    return "ECDSA";
+                case PublicKeyAlgorithmTag.ElGamalGeneral:
+                    return "ElGamalGeneral";
+                case PublicKeyAlgorithmTag.DiffieHellman:
+                    return "DiffieHellman";
+            }
+
+            return "unknown";
+        }
+
+		public static void Main(
+			string[] args)
+        {
+			Stream fs = File.OpenRead(args[0]);
+
+			//
+            // Read the public key rings
+            //
+            PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(
+                PgpUtilities.GetDecoderStream(fs));
+
+			fs.Close();
+
+			foreach (PgpPublicKeyRing pgpPub in pubRings.GetKeyRings())
+            {
+                try
+                {
+					//PgpPublicKey pubKey =
+					pgpPub.GetPublicKey();
+                }
+                catch (Exception e)
+                {
+                    Console.Error.WriteLine(e.Message);
+                    Console.Error.WriteLine(e.StackTrace);
+                    continue;
+                }
+
+				bool first = true;
+
+				foreach (PgpPublicKey pgpKey in pgpPub.GetPublicKeys())
+                {
+                    if (first)
+                    {
+                        Console.WriteLine("Key ID: " +  pgpKey.KeyId.ToString("X"));
+                        first = false;
+                    }
+                    else
+                    {
+                        Console.WriteLine("Key ID: " + pgpKey.KeyId.ToString("X") + " (subkey)");
+                    }
+
+					Console.WriteLine("            Algorithm: " + GetAlgorithm(pgpKey.Algorithm));
+                    Console.WriteLine("            Fingerprint: " + Hex.ToHexString(pgpKey.GetFingerprint()));
+                }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/RsaKeyRingGenerator.cs b/crypto/test/src/openpgp/examples/RsaKeyRingGenerator.cs
new file mode 100644
index 000000000..284118b99
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/RsaKeyRingGenerator.cs
@@ -0,0 +1,115 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that Generates a RSA PgpPublicKey/PgpSecretKey pair.
+    * <p>
+    * usage: RsaKeyRingGenerator [-a] identity passPhrase</p>
+    * <p>
+    * Where identity is the name to be associated with the public key. The keys are placed
+    * in the files pub.[asc|bpg] and secret.[asc|bpg].</p>
+    */
+    public sealed class RsaKeyRingGenerator
+    {
+        private RsaKeyRingGenerator()
+        {
+        }
+
+		private static void ExportKeyPair(
+            Stream                   secretOut,
+            Stream                   publicOut,
+            AsymmetricKeyParameter   publicKey,
+            AsymmetricKeyParameter   privateKey,
+            string                   identity,
+            char[]                   passPhrase,
+            bool                     armor)
+        {
+			if (armor)
+			{
+				secretOut = new ArmoredOutputStream(secretOut);
+			}
+
+			PgpSecretKey secretKey = new PgpSecretKey(
+                PgpSignature.DefaultCertification,
+                PublicKeyAlgorithmTag.RsaGeneral,
+                publicKey,
+                privateKey,
+                DateTime.UtcNow,
+                identity,
+                SymmetricKeyAlgorithmTag.Cast5,
+                passPhrase,
+                null,
+                null,
+                new SecureRandom()
+                );
+
+            secretKey.Encode(secretOut);
+
+			if (armor)
+            {
+				secretOut.Close();
+				publicOut = new ArmoredOutputStream(publicOut);
+            }
+
+            PgpPublicKey key = secretKey.PublicKey;
+
+            key.Encode(publicOut);
+
+			if (armor)
+			{
+				publicOut.Close();
+			}
+        }
+
+		public static int Main(
+			string[] args)
+        {
+            IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator("RSA");
+
+            kpg.Init(new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x10001), new SecureRandom(), 1024, 25));
+
+            AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+
+            if (args.Length < 2)
+            {
+                Console.WriteLine("RsaKeyPairGenerator [-a] identity passPhrase");
+                return 0;
+            }
+
+			Stream out1, out2;
+            if (args[0].Equals("-a"))
+            {
+                if (args.Length < 3)
+                {
+                    Console.WriteLine("RsaKeyPairGenerator [-a] identity passPhrase");
+					return 0;
+				}
+
+				out1 = File.Create("secret.asc");
+                out2 = File.Create("pub.asc");
+
+                ExportKeyPair(out1, out2, kp.Public, kp.Private, args[1], args[2].ToCharArray(), true);
+            }
+            else
+            {
+                out1 = File.Create("secret.bpg");
+                out2 = File.Create("pub.bpg");
+
+                ExportKeyPair(out1, out2, kp.Public, kp.Private, args[0], args[1].ToCharArray(), false);
+            }
+			out1.Close();
+			out2.Close();
+			return 0;
+		}
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/SignedFileProcessor.cs b/crypto/test/src/openpgp/examples/SignedFileProcessor.cs
new file mode 100644
index 000000000..1ad0d102b
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/SignedFileProcessor.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections;
+using System.IO;
+
+
+using Org.BouncyCastle.Bcpg.OpenPgp;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
+{
+    /**
+    * A simple utility class that signs and verifies files.
+    * <p>
+    * To sign a file: SignedFileProcessor -s [-a] fileName secretKey passPhrase.<br/>
+    * If -a is specified the output file will be "ascii-armored".</p>
+    * <p>
+    * To decrypt: SignedFileProcessor -v fileName publicKeyFile.</p>
+    * <p>
+    * <b>Note</b>: this example will silently overwrite files, nor does it pay any attention to
+    * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase
+    * will have been used.</p>
+    * <p>
+    * <b>Note</b>: the example also makes use of PGP compression. If you are having difficulty Getting it
+    * to interoperate with other PGP programs try removing the use of compression first.</p>
+    */
+    public sealed class SignedFileProcessor
+    {
+        private SignedFileProcessor() {}
+
+		/**
+        * verify the passed in file as being correctly signed.
+        */
+        private static void VerifyFile(
+            Stream	inputStream,
+            Stream	keyIn)
+        {
+            inputStream = PgpUtilities.GetDecoderStream(inputStream);
+
+            PgpObjectFactory			pgpFact = new PgpObjectFactory(inputStream);
+            PgpCompressedData			c1 = (PgpCompressedData) pgpFact.NextPgpObject();
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            PgpOnePassSignatureList		p1 = (PgpOnePassSignatureList) pgpFact.NextPgpObject();
+            PgpOnePassSignature			ops = p1[0];
+
+            PgpLiteralData				p2 = (PgpLiteralData) pgpFact.NextPgpObject();
+            Stream						dIn = p2.GetInputStream();
+            PgpPublicKeyRingBundle		pgpRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn));
+            PgpPublicKey				key = pgpRing.GetPublicKey(ops.KeyId);
+            Stream						fos = File.Create(p2.FileName);
+
+			ops.InitVerify(key);
+
+			int ch;
+			while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte)ch);
+                fos.WriteByte((byte) ch);
+            }
+            fos.Close();
+
+            PgpSignatureList	p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+			PgpSignature		firstSig = p3[0];
+            if (ops.Verify(firstSig))
+            {
+                Console.Out.WriteLine("signature verified.");
+            }
+            else
+            {
+                Console.Out.WriteLine("signature verification failed.");
+            }
+        }
+
+        /**
+        * Generate an encapsulated signed file.
+        *
+        * @param fileName
+        * @param keyIn
+        * @param outputStream
+        * @param pass
+        * @param armor
+        */
+        private static void SignFile(
+            string	fileName,
+            Stream	keyIn,
+            Stream	outputStream,
+            char[]	pass,
+            bool	armor,
+			bool	compress)
+        {
+            if (armor)
+            {
+                outputStream = new ArmoredOutputStream(outputStream);
+            }
+
+            PgpSecretKey pgpSec = PgpExampleUtilities.ReadSecretKey(keyIn);
+            PgpPrivateKey pgpPrivKey = pgpSec.ExtractPrivateKey(pass);
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
+            foreach (string userId in pgpSec.PublicKey.GetUserIds())
+            {
+                PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
+                spGen.SetSignerUserId(false, userId);
+                sGen.SetHashedSubpackets(spGen.Generate());
+                // Just the first one!
+                break;
+            }
+
+            Stream cOut = outputStream;
+			PgpCompressedDataGenerator cGen = null;
+			if (compress)
+			{
+				cGen = new PgpCompressedDataGenerator(CompressionAlgorithmTag.ZLib);
+
+				cOut = cGen.Open(cOut);
+			}
+
+			BcpgOutputStream bOut = new BcpgOutputStream(cOut);
+
+            sGen.GenerateOnePassVersion(false).Encode(bOut);
+
+            FileInfo					file = new FileInfo(fileName);
+            PgpLiteralDataGenerator     lGen = new PgpLiteralDataGenerator();
+            Stream						lOut = lGen.Open(bOut, PgpLiteralData.Binary, file);
+            FileStream					fIn = file.OpenRead();
+            int                         ch = 0;
+
+			while ((ch = fIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte) ch);
+                sGen.Update((byte)ch);
+            }
+
+			fIn.Close();
+			lGen.Close();
+
+			sGen.Generate().Encode(bOut);
+
+			if (cGen != null)
+			{
+				cGen.Close();
+			}
+
+			if (armor)
+			{
+				outputStream.Close();
+			}
+        }
+
+		public static void Main(
+            string[] args)
+        {
+			// TODO provide command-line option to determine whether to use compression in SignFile
+            if (args[0].Equals("-s"))
+            {
+				Stream keyIn, fos;
+                if (args[1].Equals("-a"))
+                {
+                    keyIn = File.OpenRead(args[3]);
+                    fos = File.Create(args[2] + ".asc");
+
+					SignFile(args[2], keyIn, fos, args[4].ToCharArray(), true, true);
+                }
+                else
+                {
+                    keyIn = File.OpenRead(args[2]);
+                    fos = File.Create(args[1] + ".bpg");
+
+					SignFile(args[1], keyIn, fos, args[3].ToCharArray(), false, true);
+                }
+				keyIn.Close();
+				fos.Close();
+            }
+            else if (args[0].Equals("-v"))
+            {
+				using (Stream fis = File.OpenRead(args[1]),
+                	keyIn = File.OpenRead(args[2]))
+				{
+					VerifyFile(fis, keyIn);
+				}
+			}
+            else
+            {
+                Console.Error.WriteLine("usage: SignedFileProcessor -v|-s [-a] file keyfile [passPhrase]");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/examples/test/AllTests.cs b/crypto/test/src/openpgp/examples/test/AllTests.cs
new file mode 100644
index 000000000..180d2fa80
--- /dev/null
+++ b/crypto/test/src/openpgp/examples/test/AllTests.cs
@@ -0,0 +1,403 @@
+using System;
+using System.IO;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples.Tests
+{
+	[TestFixture]
+	public class AllTests
+	{
+		private static readonly byte[] clearSignedPublicKey = Base64.Decode(
+			  "mQELBEQh2+wBCAD26kte0hO6flr7Y2aetpPYutHY4qsmDPy+GwmmqVeCDkX+"
+			+ "r1g7DuFbMhVeu0NkKDnVl7GsJ9VarYsFYyqu0NzLa9XS2qlTIkmJV+2/xKa1"
+			+ "tzjn18fT/cnAWL88ZLCOWUr241aPVhLuIc6vpHnySpEMkCh4rvMaimnTrKwO"
+			+ "42kgeDGd5cXfs4J4ovRcTbc4hmU2BRVsRjiYMZWWx0kkyL2zDVyaJSs4yVX7"
+			+ "Jm4/LSR1uC/wDT0IJJuZT/gQPCMJNMEsVCziRgYkAxQK3OWojPSuv4rXpyd4"
+			+ "Gvo6IbvyTgIskfpSkCnQtORNLIudQSuK7pW+LkL62N+ohuKdMvdxauOnAAYp"
+			+ "tBNnZ2dnZ2dnZyA8Z2dnQGdnZ2c+iQE2BBMBAgAgBQJEIdvsAhsDBgsJCAcD"
+			+ "AgQVAggDBBYCAwECHgECF4AACgkQ4M/Ier3f9xagdAf/fbKWBjLQM8xR7JkR"
+			+ "P4ri8YKOQPhK+VrddGUD59/wzVnvaGyl9MZE7TXFUeniQq5iXKnm22EQbYch"
+			+ "v2Jcxyt2H9yptpzyh4tP6tEHl1C887p2J4qe7F2ATua9CzVGwXQSUbKtj2fg"
+			+ "UZP5SsNp25guhPiZdtkf2sHMeiotmykFErzqGMrvOAUThrO63GiYsRk4hF6r"
+			+ "cQ01d+EUVpY/sBcCxgNyOiB7a84sDtrxnX5BTEZDTEj8LvuEyEV3TMUuAjx1"
+			+ "7Eyd+9JtKzwV4v3hlTaWOvGro9nPS7YaPuG+RtufzXCUJPbPfTjTvtGOqvEz"
+			+ "oztls8tuWA0OGHba9XfX9rfgorACAAM=");
+
+		private static readonly string crOnlyMessage =
+			"\r"
+			+ " hello world!\r"
+			+ "\r"
+			+ "- dash\r";
+
+		private static readonly string nlOnlyMessage =
+			"\n"
+			+ " hello world!\n"
+			+ "\n"
+			+ "- dash\n";
+
+		private static readonly string crNlMessage =
+			"\r\n"
+			+ " hello world!\r\n"
+			+ "\r\n"
+			+ "- dash\r\n";
+
+		private static readonly string crNlMessageTrailingWhiteSpace =
+			"\r\n"
+			+ " hello world! \t\r\n"
+			+ "\r\n"
+			+ "\r\n";
+
+		private static readonly string crOnlySignedMessage =
+			"-----BEGIN PGP SIGNED MESSAGE-----\r"
+			+ "Hash: SHA256\r"
+			+ "\r"
+			+ "\r"
+			+ " hello world!\r"
+			+ "\r"
+			+ "- - dash\r"
+			+ "-----BEGIN PGP SIGNATURE-----\r"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\r"
+			+ "\r"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r"
+			+ "=84Nd\r"
+			+ "-----END PGP SIGNATURE-----\r";
+
+		private static readonly string nlOnlySignedMessage =
+			"-----BEGIN PGP SIGNED MESSAGE-----\n"
+			+ "Hash: SHA256\n"
+			+ "\n"
+			+ "\n"
+			+ " hello world!\n"
+			+ "\n"
+			+ "- - dash\n"
+			+ "-----BEGIN PGP SIGNATURE-----\n"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\n"
+			+ "\n"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\n"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\n"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\n"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\n"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\n"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\n"
+			+ "=84Nd\n"
+			+ "-----END PGP SIGNATURE-----\n";
+
+		private static readonly string crNlSignedMessage =
+			"-----BEGIN PGP SIGNED MESSAGE-----\r\n"
+			+ "Hash: SHA256\r\n"
+			+ "\r\n"
+			+ "\r\n"
+			+ " hello world!\r\n"
+			+ "\r\n"
+			+ "- - dash\r\n"
+			+ "-----BEGIN PGP SIGNATURE-----\r\n"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n"
+			+ "\r\n"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n"
+			+ "=84Nd\r"
+			+ "-----END PGP SIGNATURE-----\r\n";
+
+		private static readonly string crNlSignedMessageTrailingWhiteSpace =
+			"-----BEGIN PGP SIGNED MESSAGE-----\r\n"
+			+ "Hash: SHA256\r\n"
+			+ "\r\n"
+			+ "\r\n"
+			+ " hello world! \t\r\n"
+			+ "\r\n"
+			+ "- - dash\r\n"
+			+ "-----BEGIN PGP SIGNATURE-----\r\n"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n"
+			+ "\r\n"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n"
+			+ "=84Nd\r"
+			+ "-----END PGP SIGNATURE-----\r\n";
+
+		private TextWriter _oldOut;
+		private TextWriter _oldErr;
+
+		private MemoryStream _currentOut;
+		private MemoryStream _currentErr;
+
+		[SetUp]
+		public void SetUp()
+		{
+			_oldOut = Console.Out;
+			_oldErr = Console.Error;
+			_currentOut = new MemoryStream();
+			_currentErr = new MemoryStream();
+
+			Console.SetOut(new StreamWriter(_currentOut));
+			Console.SetError(new StreamWriter(_currentErr));
+		}
+
+		[TearDown]
+		public void TearDown()
+		{
+			Console.SetOut(_oldOut);
+			Console.SetError(_oldErr);
+		}
+
+		[Test]
+		public void TestRsaKeyGeneration() 
+		{
+			RsaKeyRingGenerator.Main(new string[] { "test", "password" });
+
+			CreateSmallTestInput();
+			CreateLargeTestInput();
+
+			CheckSigning("bpg");
+			CheckKeyBasedEncryption("bpg");
+			CheckLargeKeyBasedEncryption("bpg");
+
+			RsaKeyRingGenerator.Main(new string[] { "-a", "test", "password" });
+
+			CheckSigning("asc");
+			CheckKeyBasedEncryption("asc");
+			CheckLargeKeyBasedEncryption("asc");
+		}
+
+		[Test]
+		public void TestDsaElGamalKeyGeneration() 
+		{
+			DsaElGamalKeyRingGenerator.Main(new string[] { "test", "password" });
+
+			CreateSmallTestInput();
+			CreateLargeTestInput();
+
+			CheckSigning("bpg");
+			CheckKeyBasedEncryption("bpg");
+			CheckLargeKeyBasedEncryption("bpg");
+
+			DsaElGamalKeyRingGenerator.Main(new string[] { "-a", "test", "password" });
+
+			CheckSigning("asc");
+			CheckKeyBasedEncryption("asc");
+			CheckLargeKeyBasedEncryption("asc");
+		}
+
+		[Test]
+		public void TestPbeEncryption() 
+		{
+			Console.Error.Flush();
+			_currentErr.SetLength(0);
+
+			PbeFileProcessor.Main(new string[] { "-e", "test.txt", "password" });
+
+			PbeFileProcessor.Main(new string[] { "-d", "test.txt.bpg", "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("no message integrity check", GetLine(_currentErr));
+
+			PbeFileProcessor.Main(new string[] { "-e", "-i", "test.txt", "password" });
+
+			PbeFileProcessor.Main(new string[] { "-d", "test.txt.bpg", "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("message integrity check passed", GetLine(_currentErr));
+
+			PbeFileProcessor.Main(new string[] { "-e", "-ai", "test.txt", "password" });
+
+			PbeFileProcessor.Main(new string[] { "-d", "test.txt.asc", "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("message integrity check passed", GetLine(_currentErr));
+		}
+
+		[Test]
+		public void TestClearSigned()
+		{
+			CreateTestFile(clearSignedPublicKey, "pub.bpg");
+
+			CheckClearSignedVerify(nlOnlySignedMessage);
+			CheckClearSignedVerify(crOnlySignedMessage);
+			CheckClearSignedVerify(crNlSignedMessage);
+			CheckClearSignedVerify(crNlSignedMessageTrailingWhiteSpace);
+
+			ClearSignedFileProcessor.Main(new string[] { "-v", "test.txt.asc", "pub.bpg" });
+
+			RsaKeyRingGenerator.Main(new string[] { "test", "password" });
+
+			CheckClearSigned(crOnlyMessage);
+			CheckClearSigned(nlOnlyMessage);
+			CheckClearSigned(crNlMessage);
+			CheckClearSigned(crNlMessageTrailingWhiteSpace);
+		}
+
+		[Test]
+		public void TestClearSignedBogusInput()
+		{
+			CreateTestFile(clearSignedPublicKey, "test.txt");
+
+			ClearSignedFileProcessor.Main(new String[] { "-s", "test.txt", "secret.bpg", "password" });
+		}
+
+		private void CheckClearSignedVerify(
+			string message)
+		{
+			CreateTestData(message, "test.txt.asc");
+
+			ClearSignedFileProcessor.Main(new string[] { "-v", "test.txt.asc", "pub.bpg" });
+		}
+
+		private void CheckClearSigned(
+			string message)
+		{
+			CreateTestData(message, "test.txt");
+
+			ClearSignedFileProcessor.Main(new string[] { "-s", "test.txt", "secret.bpg", "password" });
+			ClearSignedFileProcessor.Main(new string[] { "-v", "test.txt.asc", "pub.bpg" });
+		}
+
+		private void CheckSigning(
+			string type) 
+		{
+			Console.Out.Flush();
+			_currentOut.SetLength(0);
+
+			SignedFileProcessor.Main(new string[] { "-s", "test.txt", "secret." + type, "password" });
+			SignedFileProcessor.Main(new string[] { "-v", "test.txt.bpg", "pub." + type });
+
+			Console.Out.Flush();
+			Assert.AreEqual("signature verified.", GetLine(_currentOut));
+
+			SignedFileProcessor.Main(new string[] { "-s", "-a", "test.txt", "secret." + type, "password" });
+			SignedFileProcessor.Main(new string[] { "-v", "test.txt.asc", "pub." + type });
+
+			Console.Out.Flush();
+			Assert.AreEqual("signature verified.", GetLine(_currentOut));
+		}
+
+		private void CheckKeyBasedEncryption(
+			string type) 
+		{
+			Console.Error.Flush();
+			_currentErr.SetLength(0);
+
+			KeyBasedFileProcessor.Main(new string[] { "-e", "test.txt", "pub." + type });
+			KeyBasedFileProcessor.Main(new string[] { "-d", "test.txt.bpg", "secret." + type, "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("no message integrity check", GetLine(_currentErr));
+
+			KeyBasedFileProcessor.Main(new string[] { "-e", "-i", "test.txt", "pub." + type });
+			KeyBasedFileProcessor.Main(new string[] { "-d", "test.txt.bpg", "secret." + type, "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("message integrity check passed", GetLine(_currentErr));
+
+			KeyBasedFileProcessor.Main(new string[] { "-e", "-ai", "test.txt", "pub." + type });
+			KeyBasedFileProcessor.Main(new string[] { "-d", "test.txt.asc", "secret." + type, "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("message integrity check passed", GetLine(_currentErr));
+		}
+
+		private void CheckLargeKeyBasedEncryption(
+			string type) 
+		{
+			Console.Error.Flush();
+			_currentErr.SetLength(0);
+
+			KeyBasedLargeFileProcessor.Main(new string[] { "-e", "large.txt", "pub." + type });
+			KeyBasedLargeFileProcessor.Main(new string[] { "-d", "large.txt.bpg", "secret." + type, "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("no message integrity check", GetLine(_currentErr));
+
+			KeyBasedLargeFileProcessor.Main(new string[] { "-e", "-i", "large.txt", "pub." + type });
+			KeyBasedLargeFileProcessor.Main(new string[] { "-d", "large.txt.bpg", "secret." + type, "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("message integrity check passed", GetLine(_currentErr));
+
+			KeyBasedLargeFileProcessor.Main(new string[] { "-e", "-ai", "large.txt", "pub." + type });
+			KeyBasedLargeFileProcessor.Main(new string[] { "-d", "large.txt.asc", "secret." + type, "password" });
+
+			Console.Error.Flush();
+			Assert.AreEqual("message integrity check passed", GetLine(_currentErr));
+		}
+
+		private void CreateSmallTestInput() 
+		{
+			TextWriter bfOut = new StreamWriter(File.Create("test.txt"));
+			bfOut.WriteLine("hello world!");
+			bfOut.Close();
+		}
+
+		private void CreateLargeTestInput() 
+		{
+			TextWriter bfOut = new StreamWriter(File.Create("large.txt"));
+
+			for (int i = 1; i <= 2000; i++)
+			{
+				bfOut.WriteLine("hello to planet " + i + "!");
+			}
+
+			bfOut.Close();
+		}
+
+		private void CreateTestData(
+			string	testData,
+			string	name)
+		{
+			TextWriter bfOut = new StreamWriter(File.Create(name));
+			bfOut.Write(testData);
+			bfOut.Close();
+		}
+
+		private void CreateTestFile(
+			byte[]	keyData,
+			string	name)
+		{
+			FileStream fOut = File.Create(name);
+			fOut.Write(keyData, 0, keyData.Length);
+			fOut.Close();
+		}
+
+		private string GetLine(
+			MemoryStream outStr) 
+		{
+			byte[] b = outStr.ToArray();
+			TextReader bRd = new StreamReader(new MemoryStream(b, false));
+			outStr.SetLength(0);
+			return bRd.ReadLine();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			//junit.textui.TestRunner.run(suite());
+			EventListener el = new NullListener();
+			suite().Run(el);
+		}
+
+		public static TestSuite suite()
+		{
+			TestSuite suite = new TestSuite("OpenPGP Example Tests");
+
+			suite.Add(new AllTests());
+
+			return suite;
+		}
+
+	}
+}
diff --git a/crypto/test/src/openpgp/test/DSA2Test.cs b/crypto/test/src/openpgp/test/DSA2Test.cs
new file mode 100644
index 000000000..883ae317f
--- /dev/null
+++ b/crypto/test/src/openpgp/test/DSA2Test.cs
@@ -0,0 +1,237 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+	/**
+	* GPG compatability test vectors
+	*/
+	[TestFixture]
+	public class Dsa2Test
+		//extends TestCase
+	{
+		[Test]
+		public void TestK1024H160()
+		{
+			doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-160-sign.gpg");
+		}
+
+		[Test]
+		public void TestK1024H224()
+		{
+			doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-224-sign.gpg");
+		}
+
+		[Test]
+		public void TestK1024H256()
+		{
+			doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-256-sign.gpg");
+		}
+
+		[Test]
+		public void TestK1024H384()
+		{
+			doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-384-sign.gpg");
+		}
+
+		[Test]
+		public void TestK1024H512()
+		{
+			doSigVerifyTest("DSA-1024-160.pub", "dsa-1024-512-sign.gpg");
+		}
+
+		[Test]
+		public void TestK2048H224()
+		{
+			doSigVerifyTest("DSA-2048-224.pub", "dsa-2048-224-sign.gpg");
+		}
+
+		[Test]
+		public void TestK3072H256()
+		{
+			doSigVerifyTest("DSA-3072-256.pub", "dsa-3072-256-sign.gpg");
+		}
+
+		[Test]
+		public void TestK7680H384()
+		{
+			doSigVerifyTest("DSA-7680-384.pub", "dsa-7680-384-sign.gpg");
+		}
+
+		[Test]
+		public void TestK15360H512()
+		{
+			doSigVerifyTest("DSA-15360-512.pub", "dsa-15360-512-sign.gpg");
+		}
+
+		[Test]
+		public void TestGenerateK1024H224()
+		{
+			doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", HashAlgorithmTag.Sha224);
+		}
+
+		[Test]
+		public void TestGenerateK1024H256()
+		{
+			doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", HashAlgorithmTag.Sha256);
+		}
+
+		[Test]
+		public void TestGenerateK1024H384()
+		{
+			doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", HashAlgorithmTag.Sha384);
+		}
+
+		[Test]
+		public void TestGenerateK1024H512()
+		{
+			doSigGenerateTest("DSA-1024-160.sec", "DSA-1024-160.pub", HashAlgorithmTag.Sha512);
+		}
+
+		[Test]
+		public void TestGenerateK2048H256()
+		{
+			doSigGenerateTest("DSA-2048-224.sec", "DSA-2048-224.pub", HashAlgorithmTag.Sha256);
+		}
+
+		[Test]
+		public void TestGenerateK2048H512()
+		{
+			doSigGenerateTest("DSA-2048-224.sec", "DSA-2048-224.pub", HashAlgorithmTag.Sha512);
+		}
+
+		private void doSigGenerateTest(
+			string				privateKeyFile,
+			string				publicKeyFile,
+			HashAlgorithmTag	digest)
+		{
+			PgpSecretKeyRing		secRing = loadSecretKey(privateKeyFile);
+			PgpPublicKeyRing		pubRing = loadPublicKey(publicKeyFile);
+			string					data = "hello world!";
+			byte[]					dataBytes = Encoding.ASCII.GetBytes(data);
+			MemoryStream			bOut = new MemoryStream();
+			MemoryStream			testIn = new MemoryStream(dataBytes, false);
+			PgpSignatureGenerator	sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.Dsa, digest);
+
+			sGen.InitSign(PgpSignature.BinaryDocument, secRing.GetSecretKey().ExtractPrivateKey("test".ToCharArray()));
+
+			BcpgOutputStream bcOut = new BcpgOutputStream(bOut);
+
+			sGen.GenerateOnePassVersion(false).Encode(bcOut);
+
+			PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+
+//			Date testDate = new Date((System.currentTimeMillis() / 1000) * 1000);
+			DateTime testDate = new DateTime(
+				(DateTime.UtcNow.Ticks / TimeSpan.TicksPerSecond) * TimeSpan.TicksPerSecond);
+
+			Stream lOut = lGen.Open(
+				new UncloseableStream(bcOut),
+				PgpLiteralData.Binary,
+				"_CONSOLE",
+				dataBytes.Length,
+				testDate);
+
+			int ch;
+			while ((ch = testIn.ReadByte()) >= 0)
+			{
+				lOut.WriteByte((byte)ch);
+				sGen.Update((byte)ch);
+			}
+
+			lGen.Close();
+
+			sGen.Generate().Encode(bcOut);
+
+			PgpObjectFactory        pgpFact = new PgpObjectFactory(bOut.ToArray());
+			PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+			PgpOnePassSignature     ops = p1[0];
+
+			Assert.AreEqual(digest, ops.HashAlgorithm);
+			Assert.AreEqual(PublicKeyAlgorithmTag.Dsa, ops.KeyAlgorithm);
+
+			PgpLiteralData          p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+			if (!p2.ModificationTime.Equals(testDate))
+			{
+				Assert.Fail("Modification time not preserved");
+			}
+
+			Stream dIn = p2.GetInputStream();
+
+			ops.InitVerify(pubRing.GetPublicKey());
+
+			while ((ch = dIn.ReadByte()) >= 0)
+			{
+				ops.Update((byte)ch);
+			}
+
+			PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+			PgpSignature sig = p3[0];
+
+			Assert.AreEqual(digest, sig.HashAlgorithm);
+			Assert.AreEqual(PublicKeyAlgorithmTag.Dsa, sig.KeyAlgorithm);
+
+			Assert.IsTrue(ops.Verify(sig));
+		}
+
+		private void doSigVerifyTest(
+			string	publicKeyFile,
+			string	sigFile)
+		{
+			PgpPublicKeyRing publicKey = loadPublicKey(publicKeyFile);
+			PgpObjectFactory pgpFact = loadSig(sigFile);
+
+			PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+			pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+			PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+			PgpOnePassSignature ops = p1[0];
+
+			PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+
+			Stream dIn = p2.GetInputStream();
+
+			ops.InitVerify(publicKey.GetPublicKey());
+
+			int ch;
+			while ((ch = dIn.ReadByte()) >= 0)
+			{
+				ops.Update((byte)ch);
+			}
+
+			PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+
+			Assert.IsTrue(ops.Verify(p3[0]));
+		}
+
+		private PgpObjectFactory loadSig(
+			string sigName)
+		{
+			Stream fIn = SimpleTest.GetTestDataAsStream("openpgp.dsa.sigs." + sigName);
+
+			return new PgpObjectFactory(fIn);
+		}
+
+		private PgpPublicKeyRing loadPublicKey(
+			string keyName)
+		{
+			Stream fIn = SimpleTest.GetTestDataAsStream("openpgp.dsa.keys." + keyName);
+
+			return new PgpPublicKeyRing(fIn);
+		}
+
+		private PgpSecretKeyRing loadSecretKey(
+			string keyName)
+		{
+			Stream fIn = SimpleTest.GetTestDataAsStream("openpgp.dsa.keys." + keyName);
+
+			return new PgpSecretKeyRing(fIn);
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/test/PGPArmoredTest.cs b/crypto/test/src/openpgp/test/PGPArmoredTest.cs
new file mode 100644
index 000000000..aa13477ed
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPArmoredTest.cs
@@ -0,0 +1,265 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+	[TestFixture]
+	public class PgpArmoredTest
+		: SimpleTest
+	{
+		private static readonly byte[] sample = Base64.Decode(
+				"mQGiBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn"
+			+ "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg"
+			+ "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf"
+			+ "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ"
+			+ "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G"
+			+ "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ"
+			+ "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG"
+			+ "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP"
+			+ "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif"
+			+ "IIeLOTI5Dc4XKeV32a+bWrQidGVzdCAoVGVzdCBrZXkpIDx0ZXN0QHViaWNh"
+			+ "bGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB4TOABgsJCAcDAgMVAgMDFgIB"
+			+ "Ah4BAheAAAoJEJh8Njfhe8KmGDcAoJWr8xgPr75y/Cp1kKn12oCCOb8zAJ4p"
+			+ "xSvk4K6tB2jYbdeSrmoWBZLdMLACAAC5AQ0EQDzfARAEAJeUAPvUzJJbKcc5"
+			+ "5Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj47UPAD/tQxwz8VAwJySx82ggN"
+			+ "LxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j2BVqZAaX3q79a3eMiql1T0oE"
+			+ "AGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOHAAQNBACD0mVMlAUgd7REYy/1"
+			+ "mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWaHz6CN1XptdwpDeSYEOFZ0PSu"
+			+ "qH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85efMBA9jUv/DeBOzRWMFG6sC6y"
+			+ "k8NGG7Swea7EHKeQI40G3jgO/+xANtMyTIhPBBgRAgAPBQJAPN8BAhsMBQkB"
+			+ "4TOAAAoJEJh8Njfhe8KmG7kAn00mTPGJCWqmskmzgdzeky5fWd7rAKCNCp3u"
+			+ "ZJhfg0htdgAfIy8ppm05vLACAAA=");
+
+		private static readonly byte[] marker = Hex.Decode("2d2d2d2d2d454e4420504750205055424c4943204b455920424c4f434b2d2d2d2d2d");
+
+		// Contains "Hello World!" as an armored message
+		// The 'blank line' after the headers contains (legal) whitespace - see RFC2440 6.2
+		private static readonly string blankLineData =
+			  "-----BEGIN PGP MESSAGE-----\n"
+			+ "Version: BCPG v1.32\n"
+			+ "Comment: A dummy message\n"
+			+ " \t \t\n"
+			+ "SGVsbG8gV29ybGQh\n"
+			+ "=d9Xi\n"
+			+ "-----END PGP MESSAGE-----\n";
+
+		private int markerCount(
+			byte[] data)
+		{
+			int ind = 0;
+			int matches = 0;
+
+			while (ind < data.Length)
+			{
+				if (data[ind] == 0x2d)
+				{
+					int count = 0;
+					while (count < marker.Length)
+					{
+						if (data[ind + count] != marker[count])
+						{
+							break;
+						}
+						count++;
+					}
+
+					if (count == marker.Length)
+					{
+						matches++;
+					}
+
+					// TODO Is this correct?
+					ind += count;
+				}
+				else
+				{
+					ind++;
+				}
+			}
+
+			return matches;
+		}
+
+		private void blankLineTest()
+		{
+			byte[] blankLineBytes = Encoding.ASCII.GetBytes(blankLineData);
+			MemoryStream bIn = new MemoryStream(blankLineBytes, false);
+			ArmoredInputStream aIn = new ArmoredInputStream(bIn, true);
+
+			MemoryStream bOut = new MemoryStream();
+			int c;
+			while ((c = aIn.ReadByte()) >= 0)
+			{
+				bOut.WriteByte((byte)c);
+			}
+
+			byte[] expected = Encoding.ASCII.GetBytes("Hello World!");
+
+			if (!Arrays.AreEqual(expected, bOut.ToArray()))
+			{
+				Fail("Incorrect message retrieved in blank line test.");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			//
+			// test immediate close
+			//
+			MemoryStream bOut = new MemoryStream();
+			ArmoredOutputStream aOut = new ArmoredOutputStream(bOut);
+
+			aOut.Close();
+
+			byte[] data = bOut.ToArray();
+
+			if (data.Length != 0)
+			{
+				Fail("No data should have been written");
+			}
+
+			//
+			// multiple close
+			//
+			bOut = new MemoryStream();
+			aOut = new ArmoredOutputStream(bOut);
+
+			aOut.Write(sample, 0, sample.Length);
+
+			aOut.Close();
+			aOut.Close();
+
+			int mc = markerCount(bOut.ToArray());
+
+			if (mc < 1)
+			{
+				Fail("No end marker found");
+			}
+
+			if (mc > 1)
+			{
+				Fail("More than one end marker found");
+			}
+
+			//
+			// writing and reading single objects
+			//
+			bOut = new MemoryStream();
+			aOut = new ArmoredOutputStream(bOut);
+
+			aOut.Write(sample, 0, sample.Length);
+
+			aOut.Close();
+
+			ArmoredInputStream aIn = new ArmoredInputStream(
+				new MemoryStream(bOut.ToArray(), false));
+
+			PgpObjectFactory fact = new PgpObjectFactory(aIn);
+			int count = 0;
+
+			while (fact.NextPgpObject() != null)
+			{
+				count++;
+			}
+
+			if (count != 1)
+			{
+				Fail("wrong number of objects found: " + count);
+			}
+
+			//
+			// writing and reading multiple objects  - in single block
+			//
+			bOut = new MemoryStream();
+			aOut = new ArmoredOutputStream(bOut);
+
+			aOut.Write(sample, 0, sample.Length);
+			aOut.Write(sample, 0, sample.Length);
+
+			aOut.Close();
+
+			aIn = new ArmoredInputStream(
+				new MemoryStream(bOut.ToArray(), false));
+
+			fact = new PgpObjectFactory(aIn);
+			count = 0;
+
+			while (fact.NextPgpObject() != null)
+			{
+				count++;
+			}
+
+			if (count != 2)
+			{
+				Fail("wrong number of objects found: " + count);
+			}
+
+			//
+			// writing and reading multiple objects  - in single block
+			//
+			bOut = new MemoryStream();
+			aOut = new ArmoredOutputStream(bOut);
+
+			aOut.Write(sample, 0, sample.Length);
+
+			aOut.Close();     // does not close underlying stream
+
+			aOut = new ArmoredOutputStream(bOut);
+
+			aOut.Write(sample, 0, sample.Length);
+
+			aOut.Close();
+
+			aIn = new ArmoredInputStream(
+				new MemoryStream(bOut.ToArray(), false));
+
+			count = 0;
+			bool atLeastOne;
+			do
+			{
+				atLeastOne = false;
+				fact = new PgpObjectFactory(aIn);
+
+				while (fact.NextPgpObject() != null)
+				{
+					atLeastOne = true;
+					count++;
+				}
+			}
+			while (atLeastOne);
+
+			if (count != 2)
+			{
+				Fail("wrong number of objects found: " + count);
+			}
+
+			blankLineTest();
+		}
+
+		public override string Name
+		{
+			get { return "PGPArmoredTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PgpArmoredTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/test/PGPClearSignedSignatureTest.cs b/crypto/test/src/openpgp/test/PGPClearSignedSignatureTest.cs
new file mode 100644
index 000000000..668f8cce2
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPClearSignedSignatureTest.cs
@@ -0,0 +1,445 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+	[TestFixture]
+	public class PgpClearSignedSignatureTest
+		: SimpleTest
+	{
+		private static readonly byte[] publicKey = Base64.Decode(
+			  "mQELBEQh2+wBCAD26kte0hO6flr7Y2aetpPYutHY4qsmDPy+GwmmqVeCDkX+"
+			+ "r1g7DuFbMhVeu0NkKDnVl7GsJ9VarYsFYyqu0NzLa9XS2qlTIkmJV+2/xKa1"
+			+ "tzjn18fT/cnAWL88ZLCOWUr241aPVhLuIc6vpHnySpEMkCh4rvMaimnTrKwO"
+			+ "42kgeDGd5cXfs4J4ovRcTbc4hmU2BRVsRjiYMZWWx0kkyL2zDVyaJSs4yVX7"
+			+ "Jm4/LSR1uC/wDT0IJJuZT/gQPCMJNMEsVCziRgYkAxQK3OWojPSuv4rXpyd4"
+			+ "Gvo6IbvyTgIskfpSkCnQtORNLIudQSuK7pW+LkL62N+ohuKdMvdxauOnAAYp"
+			+ "tBNnZ2dnZ2dnZyA8Z2dnQGdnZ2c+iQE2BBMBAgAgBQJEIdvsAhsDBgsJCAcD"
+			+ "AgQVAggDBBYCAwECHgECF4AACgkQ4M/Ier3f9xagdAf/fbKWBjLQM8xR7JkR"
+			+ "P4ri8YKOQPhK+VrddGUD59/wzVnvaGyl9MZE7TXFUeniQq5iXKnm22EQbYch"
+			+ "v2Jcxyt2H9yptpzyh4tP6tEHl1C887p2J4qe7F2ATua9CzVGwXQSUbKtj2fg"
+			+ "UZP5SsNp25guhPiZdtkf2sHMeiotmykFErzqGMrvOAUThrO63GiYsRk4hF6r"
+			+ "cQ01d+EUVpY/sBcCxgNyOiB7a84sDtrxnX5BTEZDTEj8LvuEyEV3TMUuAjx1"
+			+ "7Eyd+9JtKzwV4v3hlTaWOvGro9nPS7YaPuG+RtufzXCUJPbPfTjTvtGOqvEz"
+			+ "oztls8tuWA0OGHba9XfX9rfgorACAAM=");
+
+		private static readonly byte[] secretKey = Base64.Decode(
+			  "lQOWBEQh2+wBCAD26kte0hO6flr7Y2aetpPYutHY4qsmDPy+GwmmqVeCDkX+"
+			+ "r1g7DuFbMhVeu0NkKDnVl7GsJ9VarYsFYyqu0NzLa9XS2qlTIkmJV+2/xKa1"
+			+ "tzjn18fT/cnAWL88ZLCOWUr241aPVhLuIc6vpHnySpEMkCh4rvMaimnTrKwO"
+			+ "42kgeDGd5cXfs4J4ovRcTbc4hmU2BRVsRjiYMZWWx0kkyL2zDVyaJSs4yVX7"
+			+ "Jm4/LSR1uC/wDT0IJJuZT/gQPCMJNMEsVCziRgYkAxQK3OWojPSuv4rXpyd4"
+			+ "Gvo6IbvyTgIskfpSkCnQtORNLIudQSuK7pW+LkL62N+ohuKdMvdxauOnAAYp"
+			+ "AAf+JCJJeAXEcrTVHotsrRR5idzmg6RK/1MSQUijwPmP7ZGy1BmpAmYUfbxn"
+			+ "B56GvXyFV3Pbj9PgyJZGS7cY+l0BF4ZqN9USiQtC9OEpCVT5LVMCFXC/lahC"
+			+ "/O3EkjQy0CYK+GwyIXa+Flxcr460L/Hvw2ZEXJZ6/aPdiR+DU1l5h99Zw8V1"
+			+ "Y625MpfwN6ufJfqE0HLoqIjlqCfi1iwcKAK2oVx2SwnT1W0NwUUXjagGhD2s"
+			+ "VzJVpLqhlwmS0A+RE9Niqrf80/zwE7QNDF2DtHxmMHJ3RY/pfu5u1rrFg9YE"
+			+ "lmS60mzOe31CaD8Li0k5YCJBPnmvM9mN3/DWWprSZZKtmQQA96C2/VJF5EWm"
+			+ "+/Yxi5J06dG6Bkz311Ui4p2zHm9/4GvTPCIKNpGx9Zn47YFD3tIg3fIBVPOE"
+			+ "ktG38pEPx++dSSFF9Ep5UgmYFNOKNUVq3yGpatBtCQBXb1LQLAMBJCJ5TQmk"
+			+ "68hMOEaqjMHSOa18cS63INgA6okb/ueAKIHxYQcEAP9DaXu5n9dZQw7pshbN"
+			+ "Nu/T5IP0/D/wqM+W5r+j4P1N7PgiAnfKA4JjKrUgl8PGnI2qM/Qu+g3qK++c"
+			+ "F1ESHasnJPjvNvY+cfti06xnJVtCB/EBOA2UZkAr//Tqa76xEwYAWRBnO2Y+"
+			+ "KIVOT+nMiBFkjPTrNAD6fSr1O4aOueBhBAC6aA35IfjC2h5MYk8+Z+S4io2o"
+			+ "mRxUZ/dUuS+kITvWph2e4DT28Xpycpl2n1Pa5dCDO1lRqe/5JnaDYDKqxfmF"
+			+ "5tTG8GR4d4nVawwLlifXH5Ll7t5NcukGNMCsGuQAHMy0QHuAaOvMdLs5kGHn"
+			+ "8VxfKEVKhVrXsvJSwyXXSBtMtUcRtBNnZ2dnZ2dnZyA8Z2dnQGdnZ2c+iQE2"
+			+ "BBMBAgAgBQJEIdvsAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQ4M/I"
+			+ "er3f9xagdAf/fbKWBjLQM8xR7JkRP4ri8YKOQPhK+VrddGUD59/wzVnvaGyl"
+			+ "9MZE7TXFUeniQq5iXKnm22EQbYchv2Jcxyt2H9yptpzyh4tP6tEHl1C887p2"
+			+ "J4qe7F2ATua9CzVGwXQSUbKtj2fgUZP5SsNp25guhPiZdtkf2sHMeiotmykF"
+			+ "ErzqGMrvOAUThrO63GiYsRk4hF6rcQ01d+EUVpY/sBcCxgNyOiB7a84sDtrx"
+			+ "nX5BTEZDTEj8LvuEyEV3TMUuAjx17Eyd+9JtKzwV4v3hlTaWOvGro9nPS7Ya"
+			+ "PuG+RtufzXCUJPbPfTjTvtGOqvEzoztls8tuWA0OGHba9XfX9rfgorACAAA=");
+
+		private static readonly string crOnlyMessage =
+				"\r"
+			+ " hello world!\r"
+			+ "\r"
+			+ "- dash\r";
+
+		private static readonly string nlOnlyMessage =
+			"\n"
+			+ " hello world!\n"
+			+ "\n"
+			+ "- dash\n";
+
+		private static readonly string crNlMessage =
+			"\r\n"
+			+ " hello world!\r\n"
+			+ "\r\n"
+			+ "- dash\r\n";
+
+		private static readonly string crOnlySignedMessage =
+				"-----BEGIN PGP SIGNED MESSAGE-----\r"
+			+ "Hash: SHA256\r"
+			+ "\r"
+			+ "\r"
+			+ " hello world!\r"
+			+ "\r"
+			+ "- - dash\r"
+			+ "-----BEGIN PGP SIGNATURE-----\r"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\r"
+			+ "\r"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r"
+			+ "=84Nd\r"
+			+ "-----END PGP SIGNATURE-----\r";
+
+		private static readonly string nlOnlySignedMessage =
+			"-----BEGIN PGP SIGNED MESSAGE-----\n"
+			+ "Hash: SHA256\n"
+			+ "\n"
+			+ "\n"
+			+ " hello world!\n"
+			+ "\n"
+			+ "- - dash\n"
+			+ "-----BEGIN PGP SIGNATURE-----\n"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\n"
+			+ "\n"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\n"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\n"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\n"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\n"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\n"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\n"
+			+ "=84Nd\n"
+			+ "-----END PGP SIGNATURE-----\n";
+
+		private static readonly string crNlSignedMessage =
+				"-----BEGIN PGP SIGNED MESSAGE-----\r\n"
+			+ "Hash: SHA256\r\n"
+			+ "\r\n"
+			+ "\r\n"
+			+ " hello world!\r\n"
+			+ "\r\n"
+			+ "- - dash\r\n"
+			+ "-----BEGIN PGP SIGNATURE-----\r\n"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n"
+			+ "\r\n"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n"
+			+ "=84Nd\r"
+			+ "-----END PGP SIGNATURE-----\r\n";
+
+		private static readonly string crNlSignedMessageTrailingWhiteSpace =
+			"-----BEGIN PGP SIGNED MESSAGE-----\r\n"
+			+ "Hash: SHA256\r\n"
+			+ "\r\n"
+			+ "\r\n"
+			+ " hello world! \t\r\n"
+			+ "\r\n"
+			+ "- - dash\r\n"
+			+ "-----BEGIN PGP SIGNATURE-----\r\n"
+			+ "Version: GnuPG v1.4.2.1 (GNU/Linux)\r\n"
+			+ "\r\n"
+			+ "iQEVAwUBRCNS8+DPyHq93/cWAQi6SwgAj3ItmSLr/sd/ixAQLW7/12jzEjfNmFDt\r\n"
+			+ "WOZpJFmXj0fnMzTrOILVnbxHv2Ru+U8Y1K6nhzFSR7d28n31/XGgFtdohDEaFJpx\r\n"
+			+ "Fl+KvASKIonnpEDjFJsPIvT1/G/eCPalwO9IuxaIthmKj0z44SO1VQtmNKxdLAfK\r\n"
+			+ "+xTnXGawXS1WUE4CQGPM45mIGSqXcYrLtJkAg3jtRa8YRUn2d7b2BtmWH+jVaVuC\r\n"
+			+ "hNrXYv7iHFOu25yRWhUQJisvdC13D/gKIPRvARXPgPhAC2kovIy6VS8tDoyG6Hm5\r\n"
+			+ "dMgLEGhmqsgaetVq1ZIuBZj5S4j2apBJCDpF6GBfpBOfwIZs0Tpmlw==\r\n"
+			+ "=84Nd\r"
+			+ "-----END PGP SIGNATURE-----\r\n";
+
+		public override string Name
+		{
+			get { return "PGPClearSignedSignature"; }
+		}
+
+		private void messageTest(
+			string message,
+			string type)
+		{
+			ArmoredInputStream aIn = new ArmoredInputStream(
+				new MemoryStream(Encoding.ASCII.GetBytes(message)));
+
+			string[] headers = aIn.GetArmorHeaders();
+
+			if (headers == null || headers.Length != 1)
+			{
+				Fail("wrong number of headers found");
+			}
+
+			if (!"Hash: SHA256".Equals(headers[0]))
+			{
+				Fail("header value wrong: " + headers[0]);
+			}
+
+			//
+			// read the input, making sure we ingore the last newline.
+			//
+			MemoryStream bOut = new MemoryStream();
+			int ch;
+
+			while ((ch = aIn.ReadByte()) >= 0 && aIn.IsClearText())
+			{
+				bOut.WriteByte((byte)ch);
+			}
+
+			PgpPublicKeyRingBundle pgpRings = new PgpPublicKeyRingBundle(publicKey);
+
+			PgpObjectFactory	pgpFact = new PgpObjectFactory(aIn);
+			PgpSignatureList	p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+			PgpSignature		sig = p3[0];
+
+			sig.InitVerify(pgpRings.GetPublicKey(sig.KeyId));
+
+			MemoryStream lineOut = new MemoryStream();
+			Stream sigIn = new MemoryStream(bOut.ToArray(), false);
+			int lookAhead = ReadInputLine(lineOut, sigIn);
+
+			ProcessLine(sig, lineOut.ToArray());
+
+			if (lookAhead != -1)
+			{
+				do
+				{
+					lookAhead = ReadInputLine(lineOut, lookAhead, sigIn);
+
+					sig.Update((byte) '\r');
+					sig.Update((byte) '\n');
+
+					ProcessLine(sig, lineOut.ToArray());
+				}
+				while (lookAhead != -1);
+			}
+
+			if (!sig.Verify())
+			{
+				Fail("signature failed to verify m_in " + type);
+			}
+		}
+
+		private PgpSecretKey ReadSecretKey(
+			Stream    inputStream)
+		{
+			PgpSecretKeyRingBundle        pgpSec = new PgpSecretKeyRingBundle(inputStream);
+
+			//
+			// we just loop through the collection till we find a key suitable for encryption, in the real
+			// world you would probably want to be a bit smarter about this.
+			//
+			//
+			// iterate through the key rings.
+			//
+			foreach (PgpSecretKeyRing kRing in pgpSec.GetKeyRings())
+			{
+				foreach (PgpSecretKey k in kRing.GetSecretKeys())
+				{
+					if (k.IsSigningKey)
+					{
+						return k;
+					}
+				}
+			}
+
+			throw new ArgumentException("Can't find signing key in key ring.");
+		}
+
+		private void generateTest(
+			string message,
+			string type)
+		{
+			PgpSecretKey                    pgpSecKey = ReadSecretKey(new MemoryStream(secretKey));
+			PgpPrivateKey                   pgpPrivKey = pgpSecKey.ExtractPrivateKey("".ToCharArray());
+			PgpSignatureGenerator           sGen = new PgpSignatureGenerator(pgpSecKey.PublicKey.Algorithm, HashAlgorithmTag.Sha256);
+			PgpSignatureSubpacketGenerator  spGen = new PgpSignatureSubpacketGenerator();
+
+			sGen.InitSign(PgpSignature.CanonicalTextDocument, pgpPrivKey);
+
+			IEnumerator    it = pgpSecKey.PublicKey.GetUserIds().GetEnumerator();
+			if (it.MoveNext())
+			{
+				spGen.SetSignerUserId(false, (string)it.Current);
+				sGen.SetHashedSubpackets(spGen.Generate());
+			}
+
+			MemoryStream bOut = new MemoryStream();
+			ArmoredOutputStream aOut = new ArmoredOutputStream(bOut);
+			MemoryStream bIn = new MemoryStream(Encoding.ASCII.GetBytes(message), false);
+
+			aOut.BeginClearText(HashAlgorithmTag.Sha256);
+
+			//
+			// note the last \n m_in the file is ignored
+			//
+			MemoryStream lineOut = new MemoryStream();
+			int lookAhead = ReadInputLine(lineOut, bIn);
+
+			ProcessLine(aOut, sGen, lineOut.ToArray());
+
+			if (lookAhead != -1)
+			{
+				do
+				{
+					lookAhead = ReadInputLine(lineOut, lookAhead, bIn);
+
+					sGen.Update((byte) '\r');
+					sGen.Update((byte) '\n');
+
+					ProcessLine(aOut, sGen, lineOut.ToArray());
+				}
+				while (lookAhead != -1);
+			}
+
+			aOut.EndClearText();
+
+			BcpgOutputStream bcpgOut = new BcpgOutputStream(aOut);
+
+			sGen.Generate().Encode(bcpgOut);
+
+			aOut.Close();
+
+			byte[] bs = bOut.ToArray();
+			messageTest(Encoding.ASCII.GetString(bs, 0, bs.Length), type);
+		}
+
+		private static int ReadInputLine(
+			MemoryStream	bOut,
+			Stream			fIn)
+		{
+			bOut.SetLength(0);
+
+			int lookAhead = -1;
+			int ch;
+
+			while ((ch = fIn.ReadByte()) >= 0)
+			{
+				bOut.WriteByte((byte) ch);
+				if (ch == '\r' || ch == '\n')
+				{
+					lookAhead = ReadPassedEol(bOut, ch, fIn);
+					break;
+				}
+			}
+
+			return lookAhead;
+		}
+
+		private static int ReadInputLine(
+			MemoryStream	bOut,
+			int				lookAhead,
+			Stream			fIn)
+		{
+			bOut.SetLength(0);
+
+			int ch = lookAhead;
+
+			do
+			{
+				bOut.WriteByte((byte) ch);
+				if (ch == '\r' || ch == '\n')
+				{
+					lookAhead = ReadPassedEol(bOut, ch, fIn);
+					break;
+				}
+			}
+			while ((ch = fIn.ReadByte()) >= 0);
+
+			return lookAhead;
+		}
+
+		private static int ReadPassedEol(
+			MemoryStream	bOut,
+			int				lastCh,
+			Stream			fIn)
+		{
+			int lookAhead = fIn.ReadByte();
+
+			if (lastCh == '\r' && lookAhead == '\n')
+			{
+				bOut.WriteByte((byte) lookAhead);
+				lookAhead = fIn.ReadByte();
+			}
+
+			return lookAhead;
+		}
+
+		private static void ProcessLine(
+			PgpSignature	sig,
+			byte[]			line)
+		{
+			int length = GetLengthWithoutWhiteSpace(line);
+			if (length > 0)
+			{
+				sig.Update(line, 0, length);
+			}
+		}
+
+		private static void ProcessLine(
+			Stream					aOut,
+			PgpSignatureGenerator	sGen,
+			byte[]					line)
+		{
+			int length = GetLengthWithoutWhiteSpace(line);
+			if (length > 0)
+			{
+				sGen.Update(line, 0, length);
+			}
+
+			aOut.Write(line, 0, line.Length);
+		}
+
+		private static int GetLengthWithoutWhiteSpace(
+			byte[] line)
+		{
+			int end = line.Length - 1;
+
+			while (end >= 0 && IsWhiteSpace(line[end]))
+			{
+				end--;
+			}
+
+			return end + 1;
+		}
+
+		private static bool IsWhiteSpace(
+			byte b)
+		{
+			return b == '\r' || b == '\n' || b == '\t' || b == ' ';
+		}
+
+		public override void PerformTest()
+		{
+			messageTest(crOnlySignedMessage, "\\r");
+			messageTest(nlOnlySignedMessage, "\\n");
+			messageTest(crNlSignedMessage, "\\r\\n");
+			messageTest(crNlSignedMessageTrailingWhiteSpace, "\\r\\n");
+
+			generateTest(nlOnlyMessage, "\\r");
+			generateTest(crOnlyMessage, "\\n");
+			generateTest(crNlMessage, "\\r\\n");
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PgpClearSignedSignatureTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/test/PGPCompressionTest.cs b/crypto/test/src/openpgp/test/PGPCompressionTest.cs
new file mode 100644
index 000000000..fdcf7222c
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPCompressionTest.cs
@@ -0,0 +1,117 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+	[TestFixture]
+	public class PgpCompressionTest
+		: SimpleTest
+	{
+		private static readonly byte[] Data = Encoding.ASCII.GetBytes("hello world! !dlrow olleh");
+
+		[Test]
+		public void TestUncompressed()
+		{
+			doTestCompression(CompressionAlgorithmTag.Uncompressed);
+		}
+
+		[Test]
+		public void TestZip()
+		{
+			doTestCompression(CompressionAlgorithmTag.Zip);
+		}
+
+		[Test]
+		public void TestZLib()
+		{
+			doTestCompression(CompressionAlgorithmTag.ZLib);
+		}
+
+		[Test]
+		public void TestBZip2()
+		{
+			doTestCompression(CompressionAlgorithmTag.BZip2);
+		}
+
+		public override void PerformTest()
+		{
+			doTestCompression(CompressionAlgorithmTag.Uncompressed);
+			doTestCompression(CompressionAlgorithmTag.Zip);
+			doTestCompression(CompressionAlgorithmTag.ZLib);
+			doTestCompression(CompressionAlgorithmTag.BZip2);
+		}
+
+		private void doTestCompression(
+			CompressionAlgorithmTag type)
+		{
+			doTestCompression(type, true);
+			doTestCompression(type, false);
+		}
+
+		private void doTestCompression(
+			CompressionAlgorithmTag	type,
+			bool					streamClose)
+		{
+			MemoryStream bOut = new MemoryStream();
+			PgpCompressedDataGenerator cPacket = new PgpCompressedDataGenerator(type);
+			Stream os = cPacket.Open(new UncloseableStream(bOut), new byte[Data.Length - 1]);
+			os.Write(Data, 0, Data.Length);
+
+			if (streamClose)
+			{
+				os.Close();
+			}
+			else
+			{
+				cPacket.Close();
+			}
+
+			ValidateData(bOut.ToArray());
+
+			try
+			{
+				os.Close();
+				cPacket.Close();
+			}
+			catch (Exception)
+			{
+				Fail("Redundant Close() should be ignored");
+			}
+		}
+
+		private void ValidateData(
+			byte[] compressed)
+		{
+			PgpObjectFactory pgpFact = new PgpObjectFactory(compressed);
+			PgpCompressedData c1 = (PgpCompressedData) pgpFact.NextPgpObject();
+
+			Stream pIn = c1.GetDataStream();
+			byte[] bytes = Streams.ReadAll(pIn);
+			pIn.Close();
+
+			if (!AreEqual(bytes, Data))
+			{
+				Fail("compression test failed");
+			}
+		}
+
+		public override string Name
+		{
+			get { return "PGPCompressionTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PgpCompressionTest());
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/test/PGPDSAElGamalTest.cs b/crypto/test/src/openpgp/test/PGPDSAElGamalTest.cs
new file mode 100644
index 000000000..b86324954
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPDSAElGamalTest.cs
@@ -0,0 +1,492 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+	[TestFixture]
+	public class PgpDsaElGamalTest
+		: SimpleTest
+	{
+		private static readonly byte[] testPubKeyRing = Base64.Decode(
+			  "mQGiBEAR8jYRBADNifuSopd20JOQ5x30ljIaY0M6927+vo09NeNxS3KqItba"
+			+ "nz9o5e2aqdT0W1xgdHYZmdElOHTTsugZxdXTEhghyxoo3KhVcNnTABQyrrvX"
+			+ "qouvmP2fEDEw0Vpyk+90BpyY9YlgeX/dEA8OfooRLCJde/iDTl7r9FT+mts8"
+			+ "g3azjwCgx+pOLD9LPBF5E4FhUOdXISJ0f4EEAKXSOi9nZzajpdhe8W2ZL9gc"
+			+ "BpzZi6AcrRZBHOEMqd69gtUxA4eD8xycUQ42yH89imEcwLz8XdJ98uHUxGJi"
+			+ "qp6hq4oakmw8GQfiL7yQIFgaM0dOAI9Afe3m84cEYZsoAFYpB4/s9pVMpPRH"
+			+ "NsVspU0qd3NHnSZ0QXs8L8DXGO1uBACjDUj+8GsfDCIP2QF3JC+nPUNa0Y5t"
+			+ "wKPKl+T8hX/0FBD7fnNeC6c9j5Ir/Fp/QtdaDAOoBKiyNLh1JaB1NY6US5zc"
+			+ "qFks2seZPjXEiE6OIDXYra494mjNKGUobA4hqT2peKWXt/uBcuL1mjKOy8Qf"
+			+ "JxgEd0MOcGJO+1PFFZWGzLQ3RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSBv"
+			+ "bmx5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPohZBBMRAgAZBQJAEfI2BAsH"
+			+ "AwIDFQIDAxYCAQIeAQIXgAAKCRAOtk6iUOgnkDdnAKC/CfLWikSBdbngY6OK"
+			+ "5UN3+o7q1ACcDRqjT3yjBU3WmRUNlxBg3tSuljmwAgAAuQENBEAR8jgQBAC2"
+			+ "kr57iuOaV7Ga1xcU14MNbKcA0PVembRCjcVjei/3yVfT/fuCVtGHOmYLEBqH"
+			+ "bn5aaJ0P/6vMbLCHKuN61NZlts+LEctfwoya43RtcubqMc7eKw4k0JnnoYgB"
+			+ "ocLXOtloCb7jfubOsnfORvrUkK0+Ne6anRhFBYfaBmGU75cQgwADBQP/XxR2"
+			+ "qGHiwn+0YiMioRDRiIAxp6UiC/JQIri2AKSqAi0zeAMdrRsBN7kyzYVVpWwN"
+			+ "5u13gPdQ2HnJ7d4wLWAuizUdKIQxBG8VoCxkbipnwh2RR4xCXFDhJrJFQUm+"
+			+ "4nKx9JvAmZTBIlI5Wsi5qxst/9p5MgP3flXsNi1tRbTmRhqIRgQYEQIABgUC"
+			+ "QBHyOAAKCRAOtk6iUOgnkBStAJoCZBVM61B1LG2xip294MZecMtCwQCbBbsk"
+			+ "JVCXP0/Szm05GB+WN+MOCT2wAgAA");
+
+		private static readonly byte[] testPrivKeyRing = Base64.Decode(
+			  "lQHhBEAR8jYRBADNifuSopd20JOQ5x30ljIaY0M6927+vo09NeNxS3KqItba"
+			+ "nz9o5e2aqdT0W1xgdHYZmdElOHTTsugZxdXTEhghyxoo3KhVcNnTABQyrrvX"
+			+ "qouvmP2fEDEw0Vpyk+90BpyY9YlgeX/dEA8OfooRLCJde/iDTl7r9FT+mts8"
+			+ "g3azjwCgx+pOLD9LPBF5E4FhUOdXISJ0f4EEAKXSOi9nZzajpdhe8W2ZL9gc"
+			+ "BpzZi6AcrRZBHOEMqd69gtUxA4eD8xycUQ42yH89imEcwLz8XdJ98uHUxGJi"
+			+ "qp6hq4oakmw8GQfiL7yQIFgaM0dOAI9Afe3m84cEYZsoAFYpB4/s9pVMpPRH"
+			+ "NsVspU0qd3NHnSZ0QXs8L8DXGO1uBACjDUj+8GsfDCIP2QF3JC+nPUNa0Y5t"
+			+ "wKPKl+T8hX/0FBD7fnNeC6c9j5Ir/Fp/QtdaDAOoBKiyNLh1JaB1NY6US5zc"
+			+ "qFks2seZPjXEiE6OIDXYra494mjNKGUobA4hqT2peKWXt/uBcuL1mjKOy8Qf"
+			+ "JxgEd0MOcGJO+1PFFZWGzP4DAwLeUcsVxIC2s2Bb9ab2XD860TQ2BI2rMD/r"
+			+ "7/psx9WQ+Vz/aFAT3rXkEJ97nFeqEACgKmUCAEk9939EwLQ3RXJpYyBILiBF"
+			+ "Y2hpZG5hICh0ZXN0IGtleSBvbmx5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3Jn"
+			+ "PohZBBMRAgAZBQJAEfI2BAsHAwIDFQIDAxYCAQIeAQIXgAAKCRAOtk6iUOgn"
+			+ "kDdnAJ9Ala3OcwEV1DbK906CheYWo4zIQwCfUqUOLMp/zj6QAk02bbJAhV1r"
+			+ "sAewAgAAnQFYBEAR8jgQBAC2kr57iuOaV7Ga1xcU14MNbKcA0PVembRCjcVj"
+			+ "ei/3yVfT/fuCVtGHOmYLEBqHbn5aaJ0P/6vMbLCHKuN61NZlts+LEctfwoya"
+			+ "43RtcubqMc7eKw4k0JnnoYgBocLXOtloCb7jfubOsnfORvrUkK0+Ne6anRhF"
+			+ "BYfaBmGU75cQgwADBQP/XxR2qGHiwn+0YiMioRDRiIAxp6UiC/JQIri2AKSq"
+			+ "Ai0zeAMdrRsBN7kyzYVVpWwN5u13gPdQ2HnJ7d4wLWAuizUdKIQxBG8VoCxk"
+			+ "bipnwh2RR4xCXFDhJrJFQUm+4nKx9JvAmZTBIlI5Wsi5qxst/9p5MgP3flXs"
+			+ "Ni1tRbTmRhr+AwMC3lHLFcSAtrNg/EiWFLAnKNXH27zjwuhje8u2r+9iMTYs"
+			+ "GjbRxaxRY0GKRhttCwqe2BC0lHhzifdlEcc9yjIjuKfepG2fnnSIRgQYEQIA"
+			+ "BgUCQBHyOAAKCRAOtk6iUOgnkBStAJ9HFejVtVJ/A9LM/mDPe0ExhEXt/QCg"
+			+ "m/KM7hJ/JrfnLQl7IaZsdg1F6vCwAgAA");
+
+		private static readonly byte[] encMessage = Base64.Decode(
+			  "hQEOAynbo4lhNjcHEAP/dgCkMtPB6mIgjFvNiotjaoh4sAXf4vFNkSeehQ2c"
+			+ "r+IMt9CgIYodJI3FoJXxOuTcwesqTp5hRzgUBJS0adLDJwcNubFMy0M2tp5o"
+			+ "KTWpXulIiqyO6f5jI/oEDHPzFoYgBmR4x72l/YpMy8UoYGtNxNvR7LVOfqJv"
+			+ "uDY/71KMtPQEAIadOWpf1P5Td+61Zqn2VH2UV7H8eI6hGa6Lsy4sb9iZNE7f"
+			+ "c+spGJlgkiOt8TrQoq3iOK9UN9nHZLiCSIEGCzsEn3uNuorD++Qs065ij+Oy"
+			+ "36TKeuJ+38CfT7u47dEshHCPqWhBKEYrxZWHUJU/izw2Q1Yxd2XRxN+nafTL"
+			+ "X1fQ0lABQUASa18s0BkkEERIdcKQXVLEswWcGqWNv1ZghC7xO2VDBX4HrPjp"
+			+ "drjL63p2UHzJ7/4gPWGGtnqq1Xita/1mrImn7pzLThDWiT55vjw6Hw==");
+
+		private static readonly byte[] signedAndEncMessage = Base64.Decode(
+			  "hQEOAynbo4lhNjcHEAP+K20MVhzdX57hf/cU8TH0prP0VePr9mmeBedzqqMn"
+			+ "fp2p8Zb68zmcMlI/WiL5XMNLYRmCgEcXyWbKdP/XV9m9LDBe1CMAGrkCeGBy"
+			+ "je69IQQ5LS9vDPyEMF4iAAv/EqACjqHkizdY/a/FRx/t2ioXYdEC2jA6kS9C"
+			+ "McpsNz16DE8EAIk3uKn4bGo/+15TXkyFYzW5Cf71SfRoHNmU2zAI93zhjN+T"
+			+ "B7mGJwWXzsMkIO6FkMU5TCSrwZS3DBWCIaJ6SYoaawE/C/2j9D7bX1Jv8kum"
+			+ "4cq+eZM7z6JYs6xend+WAwittpUxbEiyC2AJb3fBSXPAbLqWd6J6xbZZ7GDK"
+			+ "r2Ca0pwBxwGhbMDyi2zpHLzw95H7Ah2wMcGU6kMLB+hzBSZ6mSTGFehqFQE3"
+			+ "2BnAj7MtnbghiefogacJ891jj8Y2ggJeKDuRz8j2iICaTOy+Y2rXnnJwfYzm"
+			+ "BMWcd2h1C5+UeBJ9CrrLniCCI8s5u8z36Rno3sfhBnXdRmWSxExXtocbg1Ht"
+			+ "dyiThf6TK3W29Yy/T6x45Ws5zOasaJdsFKM=");
+
+		private static readonly char[] pass = "hello world".ToCharArray();
+
+		private static readonly SecureRandom random = new SecureRandom();
+
+		public override void PerformTest()
+		{
+			PgpPublicKey pubKey = null;
+
+			//
+			// Read the public key
+			//
+			PgpObjectFactory pgpFact = new PgpObjectFactory(testPubKeyRing);
+			PgpPublicKeyRing pgpPub = (PgpPublicKeyRing)pgpFact.NextPgpObject();
+
+			pubKey = pgpPub.GetPublicKey();
+
+			if (pubKey.BitStrength != 1024)
+			{
+				Fail("failed - key strength reported incorrectly.");
+			}
+
+			//
+			// Read the private key
+			//
+			PgpSecretKeyRing	sKey = new PgpSecretKeyRing(testPrivKeyRing);
+			PgpSecretKey		secretKey = sKey.GetSecretKey();
+			PgpPrivateKey		pgpPrivKey = secretKey.ExtractPrivateKey(pass);
+
+			//
+			// signature generation
+			//
+			const string data = "hello world!";
+			byte[] dataBytes = Encoding.ASCII.GetBytes(data);
+			MemoryStream bOut = new MemoryStream();
+			MemoryStream testIn = new MemoryStream(dataBytes, false);
+			PgpSignatureGenerator sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.Dsa,
+				HashAlgorithmTag.Sha1);
+
+			sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
+
+			PgpCompressedDataGenerator cGen = new PgpCompressedDataGenerator(
+				CompressionAlgorithmTag.Zip);
+
+			BcpgOutputStream bcOut = new BcpgOutputStream(
+				cGen.Open(new UncloseableStream(bOut)));
+
+			sGen.GenerateOnePassVersion(false).Encode(bcOut);
+
+			PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+
+			DateTime testDateTime = new DateTime(1973, 7, 27);
+			Stream lOut = lGen.Open(
+				new UncloseableStream(bcOut),
+				PgpLiteralData.Binary,
+				"_CONSOLE",
+				dataBytes.Length,
+				testDateTime);
+
+			int ch;
+			while ((ch = testIn.ReadByte()) >= 0)
+			{
+				lOut.WriteByte((byte) ch);
+				sGen.Update((byte) ch);
+			}
+
+			lGen.Close();
+
+			sGen.Generate().Encode(bcOut);
+
+			cGen.Close();
+
+			//
+			// verify Generated signature
+			//
+			pgpFact = new PgpObjectFactory(bOut.ToArray());
+
+			PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+			pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+			PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+
+			PgpOnePassSignature ops = p1[0];
+
+			PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+			if (!p2.ModificationTime.Equals(testDateTime))
+			{
+				Fail("Modification time not preserved");
+			}
+
+			Stream    dIn = p2.GetInputStream();
+
+			ops.InitVerify(pubKey);
+
+			while ((ch = dIn.ReadByte()) >= 0)
+			{
+				ops.Update((byte)ch);
+			}
+
+			PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+
+			if (!ops.Verify(p3[0]))
+			{
+				Fail("Failed Generated signature check");
+			}
+
+			//
+			// test encryption
+			//
+
+			//
+			// find a key sutiable for encryption
+			//
+			long pgpKeyID = 0;
+			AsymmetricKeyParameter pKey = null;
+
+			foreach (PgpPublicKey pgpKey in pgpPub.GetPublicKeys())
+			{
+				if (pgpKey.Algorithm == PublicKeyAlgorithmTag.ElGamalEncrypt
+					|| pgpKey.Algorithm == PublicKeyAlgorithmTag.ElGamalGeneral)
+				{
+					pKey = pgpKey.GetKey();
+					pgpKeyID = pgpKey.KeyId;
+					if (pgpKey.BitStrength != 1024)
+					{
+						Fail("failed - key strength reported incorrectly.");
+					}
+
+					//
+					// verify the key
+					//
+
+				}
+			}
+
+			IBufferedCipher c = CipherUtilities.GetCipher("ElGamal/None/PKCS1Padding");
+
+			c.Init(true, pKey);
+
+			byte[] inBytes = Encoding.ASCII.GetBytes("hello world");
+			byte[] outBytes = c.DoFinal(inBytes);
+
+			pgpPrivKey = sKey.GetSecretKey(pgpKeyID).ExtractPrivateKey(pass);
+
+			c.Init(false, pgpPrivKey.Key);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!Arrays.AreEqual(inBytes, outBytes))
+			{
+				Fail("decryption failed.");
+			}
+
+			//
+			// encrypted message
+			//
+			byte[] text = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o',
+								(byte)' ', (byte)'w', (byte)'o', (byte)'r', (byte)'l', (byte)'d', (byte)'!', (byte)'\n' };
+
+			PgpObjectFactory pgpF = new PgpObjectFactory(encMessage);
+
+			PgpEncryptedDataList encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+			PgpPublicKeyEncryptedData encP = (PgpPublicKeyEncryptedData)encList[0];
+
+			Stream clear = encP.GetDataStream(pgpPrivKey);
+
+			pgpFact = new PgpObjectFactory(clear);
+
+			c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+			pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+			PgpLiteralData ld = (PgpLiteralData)pgpFact.NextPgpObject();
+
+			if (!ld.FileName.Equals("test.txt"))
+			{
+				throw new Exception("wrong filename in packet");
+			}
+
+			Stream inLd = ld.GetDataStream();
+			byte[] bytes = Streams.ReadAll(inLd);
+
+			if (!Arrays.AreEqual(bytes, text))
+			{
+				Fail("wrong plain text in decrypted packet");
+			}
+
+			//
+			// signed and encrypted message
+			//
+			pgpF = new PgpObjectFactory(signedAndEncMessage);
+
+			encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+			encP = (PgpPublicKeyEncryptedData)encList[0];
+
+			clear = encP.GetDataStream(pgpPrivKey);
+
+			pgpFact = new PgpObjectFactory(clear);
+
+			c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+			pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+			p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+
+			ops = p1[0];
+
+			ld = (PgpLiteralData)pgpFact.NextPgpObject();
+
+			bOut = new MemoryStream();
+
+			if (!ld.FileName.Equals("test.txt"))
+			{
+				throw new Exception("wrong filename in packet");
+			}
+
+			inLd = ld.GetDataStream();
+
+			//
+			// note: we use the DSA public key here.
+			//
+			ops.InitVerify(pgpPub.GetPublicKey());
+
+			while ((ch = inLd.ReadByte()) >= 0)
+			{
+				ops.Update((byte) ch);
+				bOut.WriteByte((byte) ch);
+			}
+
+			p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+
+			if (!ops.Verify(p3[0]))
+			{
+				Fail("Failed signature check");
+			}
+
+			if (!Arrays.AreEqual(bOut.ToArray(), text))
+			{
+				Fail("wrong plain text in decrypted packet");
+			}
+
+			//
+			// encrypt
+			//
+			MemoryStream cbOut = new MemoryStream();
+			PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(
+				SymmetricKeyAlgorithmTag.TripleDes, random);
+			PgpPublicKey puK = sKey.GetSecretKey(pgpKeyID).PublicKey;
+
+			cPk.AddMethod(puK);
+
+			Stream cOut = cPk.Open(new UncloseableStream(cbOut), bOut.ToArray().Length);
+
+			cOut.Write(text, 0, text.Length);
+
+			cOut.Close();
+
+			pgpF = new PgpObjectFactory(cbOut.ToArray());
+
+			encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+			encP = (PgpPublicKeyEncryptedData)encList[0];
+
+			pgpPrivKey = sKey.GetSecretKey(pgpKeyID).ExtractPrivateKey(pass);
+
+			clear = encP.GetDataStream(pgpPrivKey);
+			outBytes = Streams.ReadAll(clear);
+
+			if (!Arrays.AreEqual(outBytes, text))
+			{
+				Fail("wrong plain text in Generated packet");
+			}
+
+			//
+			// use of PgpKeyPair
+			//
+			BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+			BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+			ElGamalParameters elParams = new ElGamalParameters(p, g);
+
+			IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator("ELGAMAL");
+			kpg.Init(new ElGamalKeyGenerationParameters(random, elParams));
+
+			AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+
+			PgpKeyPair pgpKp = new PgpKeyPair(PublicKeyAlgorithmTag.ElGamalGeneral ,
+				kp.Public, kp.Private, DateTime.UtcNow);
+
+			PgpPublicKey k1 = pgpKp.PublicKey;
+			PgpPrivateKey k2 = pgpKp.PrivateKey;
+
+
+
+
+
+			// Test bug with ElGamal P size != 0 mod 8 (don't use these sizes at home!)
+			for (int pSize = 257; pSize < 264; ++pSize)
+			{
+				// Generate some parameters of the given size
+				ElGamalParametersGenerator epg = new ElGamalParametersGenerator();
+				epg.Init(pSize, 2, random);
+
+				elParams = epg.GenerateParameters();
+
+				kpg = GeneratorUtilities.GetKeyPairGenerator("ELGAMAL");
+				kpg.Init(new ElGamalKeyGenerationParameters(random, elParams));
+
+
+				// Run a short encrypt/decrypt test with random key for the given parameters
+				kp = kpg.GenerateKeyPair();
+
+				PgpKeyPair elGamalKeyPair = new PgpKeyPair(
+					PublicKeyAlgorithmTag.ElGamalGeneral, kp, DateTime.UtcNow);
+
+				cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, random);
+
+				puK = elGamalKeyPair.PublicKey;
+
+				cPk.AddMethod(puK);
+
+				cbOut = new MemoryStream();
+
+				cOut = cPk.Open(new UncloseableStream(cbOut), text.Length);
+
+				cOut.Write(text, 0, text.Length);
+
+				cOut.Close();
+
+				pgpF = new PgpObjectFactory(cbOut.ToArray());
+
+				encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+				encP = (PgpPublicKeyEncryptedData)encList[0];
+
+				pgpPrivKey = elGamalKeyPair.PrivateKey;
+
+				// Note: This is where an exception would be expected if the P size causes problems
+				clear = encP.GetDataStream(pgpPrivKey);
+				byte[] decText = Streams.ReadAll(clear);
+
+				if (!Arrays.AreEqual(text, decText))
+				{
+					Fail("decrypted message incorrect");
+				}
+			}
+
+
+			// check sub key encoding
+
+			foreach (PgpPublicKey pgpKey in pgpPub.GetPublicKeys())
+			{
+				if (!pgpKey.IsMasterKey)
+				{
+					byte[] kEnc = pgpKey.GetEncoded();
+
+					PgpObjectFactory objF = new PgpObjectFactory(kEnc);
+
+					// TODO Make PgpPublicKey a PgpObject or return a PgpPublicKeyRing
+//					PgpPublicKey k = (PgpPublicKey)objF.NextPgpObject();
+//
+//					pKey = k.GetKey();
+//					pgpKeyID = k.KeyId;
+//					if (k.BitStrength != 1024)
+//					{
+//						Fail("failed - key strength reported incorrectly.");
+//					}
+//
+//					if (objF.NextPgpObject() != null)
+//					{
+//						Fail("failed - stream not fully parsed.");
+//					}
+                }
+            }
+		}
+
+		public override string Name
+		{
+			get { return "PGPDSAElGamalTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PgpDsaElGamalTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/openpgp/test/PGPDSATest.cs b/crypto/test/src/openpgp/test/PGPDSATest.cs
new file mode 100644
index 000000000..7808ed6cd
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPDSATest.cs
@@ -0,0 +1,597 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+	[TestFixture]
+    public class PgpDsaTest
+		: SimpleTest
+    {
+		private static readonly byte[] testPubKey = Base64.Decode(
+              "mQGiBD9HBzURBACzkxRCVGJg5+Ld9DU4Xpnd4LCKgMq7YOY7Gi0EgK92gbaa6+zQ"
+            + "oQFqz1tt3QUmpz3YVkm/zLESBBtC1ACIXGggUdFMUr5I87+1Cb6vzefAtGt8N5VV"
+            + "1F/MXv1gJz4Bu6HyxL/ncfe71jsNhav0i4yAjf2etWFj53zK6R+Ojg5H6wCgpL9/"
+            + "tXVfGP8SqFvyrN/437MlFSUEAIN3V6j/MUllyrZglrtr2+RWIwRrG/ACmrF6hTug"
+            + "Ol4cQxaDYNcntXbhlTlJs9MxjTH3xxzylyirCyq7HzGJxZzSt6FTeh1DFYzhJ7Qu"
+            + "YR1xrSdA6Y0mUv0ixD5A4nPHjupQ5QCqHGeRfFD/oHzD4zqBnJp/BJ3LvQ66bERJ"
+            + "mKl5A/4uj3HoVxpb0vvyENfRqKMmGBISycY4MoH5uWfb23FffsT9r9KL6nJ4syLz"
+            + "aRR0gvcbcjkc9Z3epI7gr3jTrb4d8WPxsDbT/W1tv9bG/EHawomLcihtuUU68Uej"
+            + "6/wZot1XJqu2nQlku57+M/V2X1y26VKsipolPfja4uyBOOyvbLQzRXJpYyBFY2hp"
+            + "ZG5hIChEU0EgVGVzdCBLZXkpIDxlcmljQGJvdW5jeWNhc3RsZS5vcmc+iFkEExEC"
+            + "ABkFAj9HBzUECwcDAgMVAgMDFgIBAh4BAheAAAoJEM0j9enEyjRDAlwAn2rrom0s"
+            + "MhufWK5vIRwg7gj5qsLEAJ4vnT5dPBVblofsG+pDoCVeJXGGng==");
+
+		private static readonly byte[] testPrivKey = Base64.Decode(
+			  "lQHhBD9HBzURBACzkxRCVGJg5+Ld9DU4Xpnd4LCKgMq7YOY7Gi0EgK92gbaa6+zQ"
+            + "oQFqz1tt3QUmpz3YVkm/zLESBBtC1ACIXGggUdFMUr5I87+1Cb6vzefAtGt8N5VV"
+            + "1F/MXv1gJz4Bu6HyxL/ncfe71jsNhav0i4yAjf2etWFj53zK6R+Ojg5H6wCgpL9/"
+            + "tXVfGP8SqFvyrN/437MlFSUEAIN3V6j/MUllyrZglrtr2+RWIwRrG/ACmrF6hTug"
+            + "Ol4cQxaDYNcntXbhlTlJs9MxjTH3xxzylyirCyq7HzGJxZzSt6FTeh1DFYzhJ7Qu"
+            + "YR1xrSdA6Y0mUv0ixD5A4nPHjupQ5QCqHGeRfFD/oHzD4zqBnJp/BJ3LvQ66bERJ"
+            + "mKl5A/4uj3HoVxpb0vvyENfRqKMmGBISycY4MoH5uWfb23FffsT9r9KL6nJ4syLz"
+            + "aRR0gvcbcjkc9Z3epI7gr3jTrb4d8WPxsDbT/W1tv9bG/EHawomLcihtuUU68Uej"
+            + "6/wZot1XJqu2nQlku57+M/V2X1y26VKsipolPfja4uyBOOyvbP4DAwIDIBTxWjkC"
+            + "GGAWQO2jy9CTvLHJEoTO7moHrp1FxOVpQ8iJHyRqZzLllO26OzgohbiPYz8u9qCu"
+            + "lZ9Xn7QzRXJpYyBFY2hpZG5hIChEU0EgVGVzdCBLZXkpIDxlcmljQGJvdW5jeWNh"
+            + "c3RsZS5vcmc+iFkEExECABkFAj9HBzUECwcDAgMVAgMDFgIBAh4BAheAAAoJEM0j"
+            + "9enEyjRDAlwAnjTjjt57NKIgyym7OTCwzIU3xgFpAJ0VO5m5PfQKmGJRhaewLSZD"
+            + "4nXkHg==");
+
+		private static readonly byte[] testPrivKey2 = Base64.Decode(
+              "lQHhBEAnoewRBADRvKgDhbV6pMzqYfUgBsLxSHzmycpuxGbjMrpyKHDOEemj"
+            + "iQb6TyyBKUoR28/pfshFP9R5urtKIT7wjVrDuOkxYkgRhNm+xmPXW2Lw3D++"
+            + "MQrC5VWe8ywBltz6T9msmChsaKo2hDhIiRI/mg9Q6rH9pJKtVGi4R7CgGxM2"
+            + "STQ5fwCgub38qGS1W2O4hUsa+3gva5gaNZUEAItegda4/H4t88XdWxW3D8pv"
+            + "RnFz26/ADdImVaQlBoumD15VmcgYoT1Djizey7X8vfV+pntudESzLbn3GHlI"
+            + "6C09seH4e8eYP63t7KU/qbUCDomlSswd1OgQ/RxfN86q765K2t3K1i3wDSxe"
+            + "EgSRyGKee0VNvOBFOFhuWt+patXaBADE1riNkUxg2P4lBNWwu8tEZRmsl/Ys"
+            + "DBIzXBshoMzZCvS5PnNXMW4G3SAaC9OC9jvKSx9IEWhKjfjs3QcWzXR28mcm"
+            + "5na0bTxeOMlaPPhBdkTCmFl0IITWlH/pFlR2ah9WYoWYhZEL2tqB82wByzxH"
+            + "SkSeD9V5oeSCdCcqiqkEmv4DAwLeNsQ2XGJVRmA4lld+CR5vRxpT/+/2xklp"
+            + "lxVf/nx0+thrHDpro3u/nINIIObk0gh59+zaEEe3APlHqbQVYWFhIGJiYiA8"
+            + "Y2NjQGRkZC5lZWU+iFoEExECABoFAkAnoewFCwcDAgEDFQIDAxYCAQIeAQIX"
+            + "gAAKCRA5nBpCS63az85BAKCbPfU8ATrFvkXhzGNGlc1BJo6DWQCgnK125xVK"
+            + "lWLpt6ZJJ7TXcx3nkm6wAgAAnQFXBEAnoe0QBACsQxPvaeBcv2TkbgU/5Wc/"
+            + "tO222dPE1mxFbXjGTKfb+6ge96iyD8kTRLrKCkEEeVBa8AZqMSoXUVN6tV8j"
+            + "/zD8Bc76o5iJ6wgpg3Mmy2GxInVfsfZN6/G3Y2ukmouz+CDNvQdUw8cTguIb"
+            + "QoV3XhQ03MLbfVmNcHsku9F4CuKNWwADBQP0DSSe8v5PXF9CSCXOIxBDcQ5x"
+            + "RKjyYOveqoH/4lbOV0YNUbIDZq4RaUdotpADuPREFmWf0zTB6KV/WIiag8XU"
+            + "WU9zdDvLKR483Bo6Do5pDBcN+NqfQ+ntGY9WJ7BSFnhQ3+07i1K+NsfFTRfv"
+            + "hf9X3MP75rCf7MxAIWHTabEmUf4DAwLeNsQ2XGJVRmA8DssBUCghogG9n8T3"
+            + "qfBeKsplGyCcF+JjPeQXkKQaoYGJ0aJz36qFP9d8DuWtT9soQcqIxVf6mTa8"
+            + "kN1594hGBBgRAgAGBQJAJ6HtAAoJEDmcGkJLrdrPpMkAnRyjQSKugz0YJqOB"
+            + "yGasMLQLxd2OAKCEIlhtCarlufVQNGZsuWxHVbU8crACAAA=");
+
+		private static readonly byte[] sig1 = Base64.Decode(
+              "owGbwMvMwCR4VvnryyOnTJwZ10gncZSkFpfolVSU2Ltz78hIzcnJVyjPL8pJUeTq"
+            + "sGdmZQCJwpQLMq3ayTA/0Fj3xf4jbwPfK/H3zj55Z9L1n2k/GOapKJrvMZ4tLiCW"
+            + "GtP/XeDqX4fORDUA");
+
+		private static readonly byte[] sig1crc = Base64.Decode("OZa/");
+
+		private static readonly byte[] testPubWithUserAttr = Base64.Decode(
+              "mQGiBD2Rqv0RBADqKCkhVEtB/lEEr/9CubuHEy2oN/yU5j+2GXSdcNdVnRI/rwFy"
+            + "fHEQIk3uU7zHSUKFrC59yDm0sODYyjEdE3BVb0xvEJ5LE/OdndcIMXT1DungZ1vB"
+            + "zIK/3lr33W/PHixYxv9jduH3WrTehBpiKkgMZp8XloSFj2Cnw9LDyfqB7QCg/8K1"
+            + "o2k75NkOd9ZjnA9ye7Ri3bEEAKyr61Mo7viPWBK1joWAEsxG0OBWM+iSlG7kwh31"
+            + "8efgC/7Os6x4Y0jzs8mpcbBjeZtZjS9lRbfp7RinhF269xL0TZ3JxIdtaAV/6yDQ"
+            + "9NXfZY9dskN++HIR/5GCEEgq/qTJZt6ti5k7aV19ZFfO6wiK3NUy08wOrVsdOkVE"
+            + "w9IcBADaplhpcel3201uU3OCboogJtw81R5MJMZ4Y9cKL/ca2jGISn0nA7KrAw9v"
+            + "ShheSixGO4BV9JECkLEbtg7i+W/j/De6S+x2GLNcphuTP3UmgtKbhs0ItRqzW561"
+            + "s6gLkqi6aWmgaFLd8E1pMJcd9DSY95P13EYB9VJIUxFNUopzo7QcUmFsZiBIYXVz"
+            + "ZXIgPGhhdXNlckBhY20ub3JnPokAWAQQEQIAGAUCPZGq/QgLAwkIBwIBCgIZAQUb"
+            + "AwAAAAAKCRAqIBiOh4JvOKg4AJ9j14yygOqqzqiLKeaasIzqT8LCIgCggx14WuLO"
+            + "wOUTUswTaVKMFnU7tseJAJwEEAECAAYFAj2Rqx8ACgkQ9aWTKMpUDFV+9QP/RiWT"
+            + "5FAF5Rgb7beaApsgXsME+Pw7HEYFtqGa6VcXEpbcUXO6rjaXsgMgY90klWlWCF1T"
+            + "HOyKITvj2FdhE+0j8NQn4vaGpiTwORW/zMf/BZ0abdSWQybp10Yjs8gXw30UheO+"
+            + "F1E524MC+s2AeUi2hwHMiS+AVYd4WhxWHmWuBpTRypP/AAALTgEQAAEBAAAAAQAA"
+            + "AAABAAAA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQ"
+            + "Dg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/"
+            + "2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7"
+            + "Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCABqAF0DASIAAhEBAxEB/8QAHwAAAQUB"
+            + "AQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQID"
+            + "AAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0"
+            + "NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKT"
+            + "lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl"
+            + "5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL"
+            + "/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHB"
+            + "CSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpj"
+            + "ZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3"
+            + "uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIR"
+            + "AxEAPwD2aiiq9xcxWsRllcKqjOT06E/0oAsVm6jrmm6VGXvLuOPGflz8x+grzXxV"
+            + "8U51u5LXRgBGowZHXknnkc9OQcV51caneXdw9xPOXlckl2AJHY4J6cD1oA9J1z4p"
+            + "TRkrYQhRyQ0hIY5/2QRx7k9ulczN8SvEEshdZkX0UorDrznI759a5Mksckkknqec"
+            + "mkoA7WD4oavEoEttbTepYEZ+mCMVv6H8SLTULhbe/gFozAYkD5Unp3Ax/kV5XRQB"
+            + "9EAhgCDkHkEcgilryTwd4zn0m4WzvpTJZSMBuY5MfbueletKyugZWDKwyCOc/j3o"
+            + "AduyWLDeWB5Ynj8jSUUUAdFXn/xU15dO0RbGGYC5uWwUB6L1Jx+n413F1cJa2stz"
+            + "J92JC5+gGa+bdfvp9S1q4urmRneQg5Yk4HGAPYZoAzySxySSSep5yaSvQvAPhOHU"
+            + "rB7u5iLGUlIwQRx7HPr/AJ9LGsfC+dJGngc+X12gc8nvx1/rQB5rRXS3Xg28t9ye"
+            + "VLvA7Ddj8MDt6Vnx6JKJCsocnBwqqQSOxPH+fWgDKorTl0SaLGXxkZ+ZcZ4z1yfb"
+            + "P1qg0MqLueN1A6kqRigCOvVPh74mF9YjS7tgLi3GIm6b17c+oOfrXlda3haeW38R"
+            + "WjxfeMgBOCcD/PHpzQB7nRRRQBqarZjUNLubPJXz4yhI64PFfO3iDRrnRtdm0+cq"
+            + "0ocEbehzyOv1xX0vXnHxU8Kf2hYf23aRk3VsMTAZO6MZ5x7UAbfga1W00WzjRSF8"
+            + "kbsg5z744HT/ADmuoysikdQSVP8AI1yPgq6il0axk27V8sDcTg5x7V1qSxOcJIrH"
+            + "/ZOaAKV5p8JgJSPJGMr97PNcxqOiRXLiRI8nONoIGO55z/8AqyeldhPcQxwyOzoQ"
+            + "owRkflXH6t4q0nTLjy57mNXfJCA5x+Qx0NAGXd6LD5iiaPYwTAAx07+vXvXOXmiR"
+            + "Qu6u5VTk/MQQV7cdvxPT866KbxTpt7HGR8p7SMw5HuOP8/Ws/ULlb2No0bKMOGBJ"
+            + "BHrjHHXn6D8QDzWZQk8iAYVWIA9K6LwDZNeeJ4sEqsaF2YHBHpz2/wA/WsG+V0vZ"
+            + "kkGGVsEZz9OcntXffC62iiS7vJTsklKxRFuAw6nBP+eKAPRKKKKAOiqOSNJYzHIo"
+            + "ZGGCD0NSUUAeRajIunwzQG4e3tYZTHGsPzOxJ6ADuQcH8Pw5v+19Q0rVJVgl1JG3"
+            + "cxykEj13cnHT1r1C38OQ3l063cIkkhmkZDKSeCfx9R/kVLeeGIRKs7hVVDn5OCx9"
+            + "yeTjqMf0oAo3k1xP4biuJFeKV4w7gDaQcen1/wAjt5gbK81HW41kIiJBZppULe47"
+            + "eoxx+YzivW9Vh/0FAE+XPIJGCOR0rnbPT7eG+LyxlkAG1wQSPXrjvg9MfjQBycNj"
+            + "4hMRZgJkUjETQqAy/UAY6DoO/wCNbVlYTNbSNJbmBlBwoUfM30B7j2/lz20VhbKA"
+            + "wHmZOQWbOfyrO1G3jil8tBhWToOcdu+c/wAvagDzbUdGlu9aRxFiB/vsuBggZOfq"
+            + "cfWujSIR2dnNZTEeXKgMcb4BUHjofbjNKmI5juiabaGGxVJLcdh/nFWtI0oxagsD"
+            + "DIkkWXYp4VQDnOemSfyHbigDtgSQMjBI6HqKKKKAOiopoPXjGKdQBnXLiDUI5SMK"
+            + "VwxHGf8APFUtW1A+YkMKmbnc23njuf6D/ObWquoaNSQCM/rwP1rMYxxTGWR1UsoU"
+            + "biAcdep+o/KgDG1LxdpracIirCVRjaykHr6cHGQe1cv/AGjNcXBW3sntyT/rHcjj"
+            + "Hp6Z+nQdAK6PXIdIvcE3Fv5rEfNgP9eRn8c8d/rgzX2i2sqo1y8745CD5WPseOnH"
+            + "f8aANiz1O9gjiR5FMUhAV1wcH0Ix6jHHSrMsskz7pGy2MZNc8PEEM7xxWsM/lr8r"
+            + "b4jtI9CcHt7nr7Vqi4JuEjB2qse9y2Ace47dRn/OQDMuRMl8RHw7SgDBPGT6jpwf"
+            + "yzXa2NmbYF3IMrDB2kkAe3HP5Vwk99u1hdg3ANuOOOB0z6ZwPz6c8eiAhgCDkHkE"
+            + "cgigBaKKKAOiqJiMEb9mBknjim3LFIGcOU285ArNa8mKIN3QclScn6+/FADL9xOc"
+            + "K2Tj7xAxnAwQPqOmawdSNpeSJBfQyGNXwQpIAPvjqOPyPT12nYsxYnJIGSeMnHP+"
+            + "e9UL7TUumEqOYp1GNw6N/vDv/wDXoA5+70vSbFGlhtopUxkBl3EZ45z7/kKwTdpN"
+            + "cIsOmeSCduUiCnB9cdeg/M/j0v8AbFtY5hu0gjmGSRICT19cdMDt3+lULzxPZGZv"
+            + "LXcBnCrwB6Y4PX+ZoAptMRbiMDAGSSMksf8A9Q6DuKzJtVYs+BvcPgMTkEdOTnrx"
+            + "/KoLzVmvZZQjjaT82DyPbqcdx+GKitLf7TNsLYAGWPfH+TQBcsYJDE0rOyu4wjHk"
+            + "gfQ+p/zzWjpnja5sdSOm6yyK0Z2pMCQjZ+6SM9CCMdhnp3E1hYy393FaW0eXfjAx"
+            + "gAdT26D+X4Vg/EuFLbxOsCYBitkQkEdsgcADsB+lAHplvqUbsu5vlYA5PIB7468e"
+            + "nPf8lfUlDkRRrIvqZNn6EV41o3iO/wBFcCJ/MhBP7pjwD6g9ua7G08b6TcRl7h5L"
+            + "eTPKvGz5+hUH9cUAeo3uFDrt+Y4O7HOOB69Pr/8AXqhUlx/r2/z2qOgBCQoJJwBy"
+            + "SeABXHeIfHVvbXcemaW4luHlVJJlIKxjODgg8nqKq/Em6uItOhWOeVAx5CuRnrXn"
+            + "+jf8hyw/6+Y//QhQB6xrmlxzXc0NyuHVyQcdjnBz379D1BGeK5u88LMJGlt2RlX7"
+            + "qkEsPXn6/pXo/ilVzbttG7DDOOeornqAONbRpI4v3pKOQcAqQD+Y/P6j052NK0p5"
+            + "HWHy3IBPyqrfN6gZz+P4/hpXoGzOOiP/ACNdH4XRftsp2jIBxx70AX9E0pdMtvMm"
+            + "VRNt5xyEGOgPf3NeDeLdVOs+J768zlGkKx+yjgfy/WvoPXeNEvMcfujXzJQAUUUU"
+            + "Af/ZiQBGBBARAgAGBQI9katEAAoJECogGI6Hgm84xz8AoNGz1fJrVPxqkBrUDmWA"
+            + "GsP6qVGYAJ0ZOftw/GfQHzdGR8pOK85DLUPEErQkUmFsZiBIYXVzZXIgPGhhdXNl"
+            + "ckBwcml2YXNwaGVyZS5jb20+iQBGBBARAgAGBQI9katmAAoJECogGI6Hgm84m0oA"
+            + "oJS3CTrgpqRZfhgPtHGtUVjRCJbbAJ9stJgPcbqA2xXEg9yl2TQToWdWxbQkUmFs"
+            + "ZiBIYXVzZXIgPGhhdXNlckBwcml2YXNwaGVyZS5vcmc+iQBGBBARAgAGBQI9kauJ"
+            + "AAoJECogGI6Hgm84GfAAnRswktLMzDfIjv6ni76Qp5B850byAJ90I0LEHOLhda7r"
+            + "kqTwZ8rguNssUrQkUmFsZiBIYXVzZXIgPGhhdXNlckBwcml2YXNwaGVyZS5uZXQ+"
+            + "iQBGBBARAgAGBQI9kaubAAoJECogGI6Hgm84zi0An16C4s/B9Z0/AtfoN4ealMh3"
+            + "i3/7AJ9Jg4GOUqGCGRRKUA9Gs5pk8yM8GbQmUmFsZiBDLiBIYXVzZXIgPHJhbGZo"
+            + "YXVzZXJAYmx1ZXdpbi5jaD6JAEYEEBECAAYFAj2Rq8oACgkQKiAYjoeCbzhPOACg"
+            + "iiTohKuIa66FNiI24mQ+XR9nTisAoLmh3lJf16/06qLPsRd9shTkLfmHtB9SYWxm"
+            + "IEhhdXNlciA8cmFsZmhhdXNlckBnbXguY2g+iQBGBBARAgAGBQI9kavvAAoJECog"
+            + "GI6Hgm84ZE8An0RlgL8mPBa/P08S5e/lD35MlDdgAJ99pjCeY46S9+nVyx7ACyKO"
+            + "SZ4OcLQmUmFsZiBIYXVzZXIgPGhhdXNlci5yYWxmQG15c3VucmlzZS5jaD6JAEYE"
+            + "EBECAAYFAj2RrEEACgkQKiAYjoeCbzjz0wCg+q801XrXk+Rf+koSI50MW5OaaKYA"
+            + "oKOVA8SLxE29qSR/bJeuW0ryzRLqtCVSYWxmIEhhdXNlciA8aGF1c2VyLnJhbGZA"
+            + "ZnJlZXN1cmYuY2g+iQBGBBARAgAGBQI9kaxXAAoJECogGI6Hgm848zoAnRBtWH6e"
+            + "fTb3is63s8J2zTfpsyS0AKDxTjl+ZZV0COHLrSCaNLZVcpImFrkEDQQ9kar+EBAA"
+            + "+RigfloGYXpDkJXcBWyHhuxh7M1FHw7Y4KN5xsncegus5D/jRpS2MEpT13wCFkiA"
+            + "tRXlKZmpnwd00//jocWWIE6YZbjYDe4QXau2FxxR2FDKIldDKb6V6FYrOHhcC9v4"
+            + "TE3V46pGzPvOF+gqnRRh44SpT9GDhKh5tu+Pp0NGCMbMHXdXJDhK4sTw6I4TZ5dO"
+            + "khNh9tvrJQ4X/faY98h8ebByHTh1+/bBc8SDESYrQ2DD4+jWCv2hKCYLrqmus2UP"
+            + "ogBTAaB81qujEh76DyrOH3SET8rzF/OkQOnX0ne2Qi0CNsEmy2henXyYCQqNfi3t"
+            + "5F159dSST5sYjvwqp0t8MvZCV7cIfwgXcqK61qlC8wXo+VMROU+28W65Szgg2gGn"
+            + "VqMU6Y9AVfPQB8bLQ6mUrfdMZIZJ+AyDvWXpF9Sh01D49Vlf3HZSTz09jdvOmeFX"
+            + "klnN/biudE/F/Ha8g8VHMGHOfMlm/xX5u/2RXscBqtNbno2gpXI61Brwv0YAWCvl"
+            + "9Ij9WE5J280gtJ3kkQc2azNsOA1FHQ98iLMcfFstjvbzySPAQ/ClWxiNjrtVjLhd"
+            + "ONM0/XwXV0OjHRhs3jMhLLUq/zzhsSlAGBGNfISnCnLWhsQDGcgHKXrKlQzZlp+r"
+            + "0ApQmwJG0wg9ZqRdQZ+cfL2JSyIZJrqrol7DVes91hcAAgIQAKD9MGkS8SUD2irI"
+            + "AiwVHU0WXLBnk2CvvueSmT9YtC34UKkIkDPZ7VoeuXDfqTOlbiE6T16zPvArZfbl"
+            + "JGdrU7HhsTdu+ADxRt1dPur0G0ICJ3pBD3ydGWpdLI/94x1BvTY4rsR5mS4YWmpf"
+            + "e2kWc7ZqezhP7Xt9q7m4EK456ddeUZWtkwGU+PKyRAZ+CK82Uhouw+4aW0NjiqmX"
+            + "hfH9/BUhI1P/8R9VkTfAFGPmZzqoHr4AuO5tLRLD2RFSmQCP8nZTiP9nP+wBBvn7"
+            + "vuqKRQsj9PwwPD4V5SM+kpW+rUIWr9TZYl3UqSnlXlpEZFd2Bfl6NloeH0cfU69E"
+            + "gtjcWGvGxYKPS0cg5yhVb4okka6RqIPQiYl6eJgv4tRTKoPRX29o0aUVdqVvDr5u"
+            + "tnFzcINq7jTo8GiO8Ia3cIFWfo0LyQBd1cf1U+eEOz+DleEFqyljaz9VCbDPE4GP"
+            + "o+ALESBlOwn5daUSaah9iU8aVPaSjn45hoQqxOKPwJxnCKKQ01iy0Gir+CDU8JJB"
+            + "7bmbvQN4bke30EGAeED3oi+3VaBHrhjYLv7SHIxP5jtCJKWMJuLRV709HsWJi3kn"
+            + "fGHwH+yCDF8+PDeROAzpXBaD2EFhKgeUTjP5Rgn6ltRf8TQnfbW4qlwyiXMhPOfC"
+            + "x6qNmwaFPKQJpIkVq5VGfRXAERfkiQBMBBgRAgAMBQI9kar+BRsMAAAAAAoJECog"
+            + "GI6Hgm84CDMAoNrNeP4c8XqFJnsLLPcjk5YGLaVIAKCrL5KFuLQVIp7d0Fkscx3/"
+            + "7DGrzw==");
+
+		private static readonly byte[] aesSecretKey = Base64.Decode(
+              "lQHpBEBSdIYRBADpd7MeIxRk4RsvyMnJNIYe4FiVv6i7I7+LPRvnIjDct0bN"
+            + "1gCV48QFej7g/PsvXRjYSowV3VIvchWX8OERd/5i10cLbcs7X52EP1vwYaLj"
+            + "uRfNUBg8Q51RQsKR+/rBmnVsi68rjU4yTH6wpo6FOO4pz4wFV+tWwGOwOitA"
+            + "K31L4wCgqh59eFFBrOlRFAbDvaL7emoCIR8EAOLxDKiLQJYQrKZfXdZnifeo"
+            + "dhEP0uuV4O5TG6nrqkhWffzC9cSoFD0BhMl979d8IB2Uft4FNvQc2u8hbJL5"
+            + "7OCGDCUAidlB9jSdu0/J+kfRaTGhYDjBgw7AA42576BBSMNouJg/aOOQENEN"
+            + "Nn4n7NxR3viBzIsL/OIeU8HSkBgaA/41PsvcgZ3kwpdltJ/FVRWhmMmv/q/X"
+            + "qp1YOnF8xPU9bv2ofELrxJfRsbS4GW1etzD+nXs/woW4Vfixs01x+cutR4iF"
+            + "3hw+eU+yLToMPmmo8D2LUvX1SRODJpx5yBBeRIYv6nz9H3sQRDx3kaLASxDV"
+            + "jTxKmrLYnZz5w5qyVpvRyv4JAwKyWlhdblPudWBFXNkW5ydKn0AV2f51wEtj"
+            + "Zy0aLIeutVMSJf1ytLqjFqrnFe6pdJrHO3G00TE8OuFhftWosLGLbEGytDtF"
+            + "cmljIEguIEVjaGlkbmEgKHRlc3Qga2V5IC0gQUVTMjU2KSA8ZXJpY0Bib3Vu"
+            + "Y3ljYXN0bGUub3JnPohZBBMRAgAZBQJAUnSGBAsHAwIDFQIDAxYCAQIeAQIX"
+            + "gAAKCRBYt1NnUiCgeFKaAKCiqtOO+NQES1gJW6XuOGmSkXt8bQCfcuW7SXZH"
+            + "zxK1FfdcG2HEDs3YEVawAgAA");
+
+		private static readonly byte[] aesPublicKey = Base64.Decode(
+              "mQGiBEBSdIYRBADpd7MeIxRk4RsvyMnJNIYe4FiVv6i7I7+LPRvnIjDct0bN"
+            + "1gCV48QFej7g/PsvXRjYSowV3VIvchWX8OERd/5i10cLbcs7X52EP1vwYaLj"
+            + "uRfNUBg8Q51RQsKR+/rBmnVsi68rjU4yTH6wpo6FOO4pz4wFV+tWwGOwOitA"
+            + "K31L4wCgqh59eFFBrOlRFAbDvaL7emoCIR8EAOLxDKiLQJYQrKZfXdZnifeo"
+            + "dhEP0uuV4O5TG6nrqkhWffzC9cSoFD0BhMl979d8IB2Uft4FNvQc2u8hbJL5"
+            + "7OCGDCUAidlB9jSdu0/J+kfRaTGhYDjBgw7AA42576BBSMNouJg/aOOQENEN"
+            + "Nn4n7NxR3viBzIsL/OIeU8HSkBgaA/41PsvcgZ3kwpdltJ/FVRWhmMmv/q/X"
+            + "qp1YOnF8xPU9bv2ofELrxJfRsbS4GW1etzD+nXs/woW4Vfixs01x+cutR4iF"
+            + "3hw+eU+yLToMPmmo8D2LUvX1SRODJpx5yBBeRIYv6nz9H3sQRDx3kaLASxDV"
+            + "jTxKmrLYnZz5w5qyVpvRyrQ7RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSAt"
+            + "IEFFUzI1NikgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IWQQTEQIAGQUCQFJ0"
+            + "hgQLBwMCAxUCAwMWAgECHgECF4AACgkQWLdTZ1IgoHhSmgCfU83BLBF2nCua"
+            + "zk2dXB9zO1l6XS8AnA07U4cq5W0GrKM6/kP9HWtPhgOFsAIAAA==");
+
+		private static readonly byte[] twofishSecretKey = Base64.Decode(
+              "lQHpBEBSdtIRBACf7WfrqTl8F051+EbaljPf/8/ajFpAfMq/7p3Hri8OCsuc"
+            + "fJJIufEEOV1/Lt/wkN67MmSyrU0fUCsRbEckRiB4EJ0zGHVFfAnku2lzdgc8"
+            + "AVounqcHOmqA/gliFDEnhYOx3bOIAOav+yiOqfKVBhWRCpFdOTE+w/XoDM+p"
+            + "p8bH5wCgmP2FuWpzfSut7GVKp51xNEBRNuED/3t2Q+Mq834FVynmLKEmeXB/"
+            + "qtIz5reHEQR8eMogsOoJS3bXs6v3Oblj4in1gLyTVfcID5tku6kLP20xMRM2"
+            + "zx2oRbz7TyOCrs15IpRXyqqJxUWD8ipgJPkPXE7hK8dh4YSTUi4i5a1ug8xG"
+            + "314twlPzrchpWZiutDvZ+ks1rzOtBACHrEFG2frUu+qVkL43tySE0cV2bnuK"
+            + "LVhXbpzF3Qdkfxou2nuzsCbl6m87OWocJX8uYcQGlHLKv8Q2cfxZyieLFg6v"
+            + "06LSFdE9drGBWz7mbrT4OJjxPyvnkffPfLOOqae3PMYIIuscvswuhm4X5aoj"
+            + "KJs01YT3L6f0iIj03hCeV/4KAwLcGrxT3X0qR2CZyZYSVBdjXeNYKXuGBtOf"
+            + "ood26WOtwLw4+l9sHVoiXNv0LomkO58ndJRPGCeZWZEDMVrfkS7rcOlktDxF"
+            + "cmljIEguIEVjaGlkbmEgKHRlc3Qga2V5IC0gdHdvZmlzaCkgPGVyaWNAYm91"
+            + "bmN5Y2FzdGxlLm9yZz6IWQQTEQIAGQUCQFJ20gQLBwMCAxUCAwMWAgECHgEC"
+            + "F4AACgkQaCCMaHh9zR2+RQCghcQwlt4B4YmNxp2b3v6rP3E8M0kAn2Gspi4u"
+            + "A/ynoqnC1O8HNlbjPdlVsAIAAA==");
+
+		private static readonly byte[] twofishPublicKey = Base64.Decode(
+              "mQGiBEBSdtIRBACf7WfrqTl8F051+EbaljPf/8/ajFpAfMq/7p3Hri8OCsuc"
+            + "fJJIufEEOV1/Lt/wkN67MmSyrU0fUCsRbEckRiB4EJ0zGHVFfAnku2lzdgc8"
+            + "AVounqcHOmqA/gliFDEnhYOx3bOIAOav+yiOqfKVBhWRCpFdOTE+w/XoDM+p"
+            + "p8bH5wCgmP2FuWpzfSut7GVKp51xNEBRNuED/3t2Q+Mq834FVynmLKEmeXB/"
+            + "qtIz5reHEQR8eMogsOoJS3bXs6v3Oblj4in1gLyTVfcID5tku6kLP20xMRM2"
+            + "zx2oRbz7TyOCrs15IpRXyqqJxUWD8ipgJPkPXE7hK8dh4YSTUi4i5a1ug8xG"
+            + "314twlPzrchpWZiutDvZ+ks1rzOtBACHrEFG2frUu+qVkL43tySE0cV2bnuK"
+            + "LVhXbpzF3Qdkfxou2nuzsCbl6m87OWocJX8uYcQGlHLKv8Q2cfxZyieLFg6v"
+            + "06LSFdE9drGBWz7mbrT4OJjxPyvnkffPfLOOqae3PMYIIuscvswuhm4X5aoj"
+            + "KJs01YT3L6f0iIj03hCeV7Q8RXJpYyBILiBFY2hpZG5hICh0ZXN0IGtleSAt"
+            + "IHR3b2Zpc2gpIDxlcmljQGJvdW5jeWNhc3RsZS5vcmc+iFkEExECABkFAkBS"
+            + "dtIECwcDAgMVAgMDFgIBAh4BAheAAAoJEGggjGh4fc0dvkUAn2QGdNk8Wrrd"
+            + "+DvKECrO5+yoPRx3AJ91DhCMme6uMrQorKSDYxHlgc7iT7ACAAA=");
+
+		private static readonly char[] pass = "hello world".ToCharArray();
+
+		/**
+        * Generated signature test
+        *
+        * @param sKey
+        * @param pgpPrivKey
+        * @return test result
+        */
+        public void GenerateTest(
+            PgpSecretKeyRing sKey,
+            PgpPublicKey     pgpPubKey,
+            PgpPrivateKey    pgpPrivKey)
+        {
+            string data = "hello world!";
+            MemoryStream bOut = new MemoryStream();
+
+            byte[] dataBytes = Encoding.ASCII.GetBytes(data);
+            MemoryStream testIn = new MemoryStream(dataBytes, false);
+
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
+
+            PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
+
+            IEnumerator enumerator = sKey.GetSecretKey().PublicKey.GetUserIds().GetEnumerator();
+            enumerator.MoveNext();
+            string primaryUserId = (string) enumerator.Current;
+
+            spGen.SetSignerUserId(true, primaryUserId);
+
+            sGen.SetHashedSubpackets(spGen.Generate());
+
+            PgpCompressedDataGenerator cGen = new PgpCompressedDataGenerator(
+                CompressionAlgorithmTag.Zip);
+
+            BcpgOutputStream bcOut = new BcpgOutputStream(cGen.Open(new UncloseableStream(bOut)));
+
+            sGen.GenerateOnePassVersion(false).Encode(bcOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+
+			DateTime testDateTime = new DateTime(1973, 7, 27);
+			Stream lOut = lGen.Open(
+				new UncloseableStream(bcOut),
+				PgpLiteralData.Binary,
+				"_CONSOLE",
+				dataBytes.Length,
+				testDateTime);
+
+			int ch;
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte) ch);
+                sGen.Update((byte)ch);
+            }
+
+            lGen.Close();
+
+            sGen.Generate().Encode(bcOut);
+
+            cGen.Close();
+
+            PgpObjectFactory pgpFact = new PgpObjectFactory(bOut.ToArray());
+            PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+			PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+            PgpOnePassSignature ops = p1[0];
+
+            PgpLiteralData p2 = (PgpLiteralData) pgpFact.NextPgpObject();
+			if (!p2.ModificationTime.Equals(testDateTime))
+			{
+				Fail("Modification time not preserved");
+			}
+
+			Stream dIn = p2.GetInputStream();
+
+            ops.InitVerify(pgpPubKey);
+
+			while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte) ch);
+            }
+
+			PgpSignatureList p3 = (PgpSignatureList) pgpFact.NextPgpObject();
+
+			if (!ops.Verify(p3[0]))
+            {
+                Fail("Failed generated signature check");
+            }
+        }
+
+		public override void PerformTest()
+        {
+            PgpPublicKey pubKey = null;
+
+			//
+            // Read the public key
+            //
+            PgpPublicKeyRing pgpPub = new PgpPublicKeyRing(testPubKey);
+
+			pubKey = pgpPub.GetPublicKey();
+
+            //
+            // Read the private key
+            //
+            PgpSecretKeyRing sKey = new PgpSecretKeyRing(testPrivKey);
+            PgpSecretKey secretKey = sKey.GetSecretKey();
+            PgpPrivateKey pgpPrivKey = secretKey.ExtractPrivateKey(pass);
+
+            //
+            // test signature message
+            //
+            PgpObjectFactory pgpFact = new PgpObjectFactory(sig1);
+            PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+			pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+            PgpOnePassSignature ops = p1[0];
+
+            PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+
+            Stream dIn = p2.GetInputStream();
+
+            ops.InitVerify(pubKey);
+
+			int ch;
+			while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte) ch);
+            }
+
+            PgpSignatureList p3 = (PgpSignatureList) pgpFact.NextPgpObject();
+
+            if (!ops.Verify(p3[0]))
+            {
+                Fail("Failed signature check");
+            }
+
+            //
+            // signature generation
+            //
+            GenerateTest(sKey, pubKey, pgpPrivKey);
+
+            //
+            // signature generation - canonical text
+            //
+            const string data = "hello world!";
+            byte[] dataBytes = Encoding.ASCII.GetBytes(data);
+            MemoryStream bOut = new MemoryStream();
+            MemoryStream testIn = new MemoryStream(dataBytes, false);
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+                PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1);
+
+			sGen.InitSign(PgpSignature.CanonicalTextDocument, pgpPrivKey);
+
+            PgpCompressedDataGenerator  cGen = new PgpCompressedDataGenerator(
+                CompressionAlgorithmTag.Zip);
+
+            BcpgOutputStream bcOut = new BcpgOutputStream(cGen.Open(new UncloseableStream(bOut)));
+
+            sGen.GenerateOnePassVersion(false).Encode(bcOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+			DateTime testDateTime = new DateTime(1973, 7, 27);
+			Stream lOut = lGen.Open(
+				new UncloseableStream(bcOut),
+				PgpLiteralData.Text,
+				"_CONSOLE",
+				dataBytes.Length,
+				testDateTime);
+
+			while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte) ch);
+                sGen.Update((byte)ch);
+            }
+
+			lGen.Close();
+
+			sGen.Generate().Encode(bcOut);
+
+            cGen.Close();
+
+            //
+            // verify Generated signature - canconical text
+            //
+            pgpFact = new PgpObjectFactory(bOut.ToArray());
+
+            c1 = (PgpCompressedData) pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            p1 = (PgpOnePassSignatureList) pgpFact.NextPgpObject();
+
+            ops = p1[0];
+
+            p2 = (PgpLiteralData) pgpFact.NextPgpObject();
+			if (!p2.ModificationTime.Equals(testDateTime))
+			{
+				Fail("Modification time not preserved");
+			}
+
+            dIn = p2.GetInputStream();
+
+            ops.InitVerify(pubKey);
+
+            while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte)ch);
+            }
+
+            p3 = (PgpSignatureList) pgpFact.NextPgpObject();
+
+            if (!ops.Verify(p3[0]))
+            {
+                Fail("Failed generated signature check");
+            }
+
+            //
+            // Read the public key with user attributes
+            //
+            pgpPub = new PgpPublicKeyRing(testPubWithUserAttr);
+
+            pubKey = pgpPub.GetPublicKey();
+
+            int count = 0;
+            foreach (PgpUserAttributeSubpacketVector attributes in pubKey.GetUserAttributes())
+            {
+                int sigCount = 0;
+                foreach (object sigs in pubKey.GetSignaturesForUserAttribute(attributes))
+                {
+					if (sigs == null)
+						Fail("null signature found");
+
+					sigCount++;
+                }
+
+                if (sigCount != 1)
+                {
+                    Fail("Failed user attributes signature check");
+                }
+
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("Failed user attributes check");
+            }
+
+            byte[]  pgpPubBytes = pgpPub.GetEncoded();
+            pgpPub = new PgpPublicKeyRing(pgpPubBytes);
+            pubKey = pgpPub.GetPublicKey();
+            count = 0;
+
+			foreach (object ua in pubKey.GetUserAttributes())
+            {
+				if (ua == null)
+					Fail("null user attribute found");
+
+				count++;
+            }
+
+			if (count != 1)
+            {
+                Fail("Failed user attributes reread");
+            }
+
+            //
+            // reading test extra data - key with edge condition for DSA key password.
+            //
+            char[] passPhrase = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
+
+			sKey = new PgpSecretKeyRing(testPrivKey2);
+            pgpPrivKey = sKey.GetSecretKey().ExtractPrivateKey(passPhrase);
+
+			//
+            // reading test - aes256 encrypted passphrase.
+            //
+            sKey = new PgpSecretKeyRing(aesSecretKey);
+            pgpPrivKey = sKey.GetSecretKey().ExtractPrivateKey(pass);
+
+            //
+            // reading test - twofish encrypted passphrase.
+            //
+            sKey = new PgpSecretKeyRing(twofishSecretKey);
+            pgpPrivKey = sKey.GetSecretKey().ExtractPrivateKey(pass);
+
+			//
+            // use of PgpKeyPair
+            //
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+            pGen.Init(512, 80, new SecureRandom()); // TODO Is the certainty okay?
+            DsaParameters dsaParams = pGen.GenerateParameters();
+            DsaKeyGenerationParameters kgp = new DsaKeyGenerationParameters(new SecureRandom(), dsaParams);
+			IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator("DSA");
+			kpg.Init(kgp);
+
+
+			AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+
+            PgpKeyPair pgpKp = new PgpKeyPair(PublicKeyAlgorithmTag.Dsa,
+                kp.Public, kp.Private, DateTime.UtcNow);
+
+			PgpPublicKey k1 = pgpKp.PublicKey;
+            PgpPrivateKey k2 = pgpKp.PrivateKey;
+        }
+
+		public override string Name
+        {
+			get { return "PGPDSATest"; }
+        }
+
+		public static void Main(
+			string[] args)
+        {
+			RunTest(new PgpDsaTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs b/crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs
new file mode 100644
index 000000000..edb96b149
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPNoPrivateKeyTest.cs
@@ -0,0 +1,169 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    [TestFixture]
+    public class PGPNoPrivateKeyTest
+        : SimpleTest
+    {
+        private static string pgpOldPass = "test";
+        private static string pgpNewPass = "newtest";
+
+        private static readonly byte[] pgpPrivateEmpty = Base64.Decode(
+              "lQCVBFGSNGwBBACwABZRIEW/4vDQajcO0FW39yNDcsHBDwPkGT95D7jiVTTRoSs6"
+            + "ACWRAAwGlz4V62U0+nEgasxpifHnu6jati5zxwS16qNvBcxcqZrdZWdvolzCWWsr"
+            + "pFd0juhwesrvvUb5dN/xCJKyLPkp6A+uwv35/cxVSOHFvbW7nnronwinYQARAQAB"
+            + "/gJlAkdOVQG0HlRlc3QgVGVzdGVyc29uIDx0ZXN0QHRlc3QubmV0Poi4BBMBAgAi"
+            + "BQJRkjRsAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDSr6Hh9tuk5NfI"
+            + "A/4iMPF9k2/7KanWksNrBqhKemsyI7hLTxAwv+AA9B0rOO2QoJYe9OjuKn199fNO"
+            + "JPsAgwy7okvDe3QAUz3WA9GlghM5STYvonFJtl7o4kyjcZ4HO2ZI5Bdc5O9i63QA"
+            + "rNv40qVp++A3Mf+13z7cftKufj0vOfw6YeayLVXcV4h95J0B/gRRkjSNAQQA2l3d"
+            + "ZnFFYXYDoNHz1cOX4787CbKdBIfiALFfdbyQ6TzYkCTJTnVCZlQs2aeyrcdTSZUx"
+            + "N4y9bih4nfJ8uRKyQvLm6O0u6bG16kUDDnnwlsGn3uvTXfUwnSPq8pFY2acde6ZG"
+            + "N25vezNK1R6C7kU3+puNHqBIRANfHTsBElaD2V0AEQEAAf4CAwIUI0+QlwBVFdNa"
+            + "S/ppOwSht7Gr19AK4SHe92VWDKnCBPN2W3vhM4NcZSQCV2oiEMI0akLZ26jqCiRl"
+            + "AvTjLSVDho1rUWbaSxFfKlDQNbxCJKlMQeVfbsWXJMeDkn1AhPru3PBLl6Y1jocd"
+            + "vIVM7aQugNQlwEuFWgtZeODxcgBfX2lQeEMIv0AtWTAMt6MVT8AgnFqiqC4+14t0"
+            + "j2CHP2hqCDr5zw9gerAYQ0F03OS34vDm4Y5DmQFjyB05QO2cIN4DZ9gJg8NAQT+P"
+            + "+bwWR3/i9pTq3InNkoi2uT41OnHsYWgKoEQn62BDxjbvO359crUiq9VvS52v2UXh"
+            + "b6Z+fF3PoXXsobS1QQwTPXAeA/mlAflTp+HrkckatY7DgWbON1SSn4Z1XcWPKBSY"
+            + "epS5+90Tj3byZvN7Laj61ZlXVBvU3x7z6MaBZDf4479fklcUnJ13v+P6uGnTI4YE"
+            + "Q5pPjHn1dDqD2Nl8ZW9ufK9pPYkBPQQYAQIACQUCUZI0jQIbAgCoCRDSr6Hh9tuk"
+            + "5J0gBBkBAgAGBQJRkjSNAAoJEPIU7wJ5Ws2K0F0D/jHx4jrZq7SCv69/4hictjgz"
+            + "nNNFSOm20/brHXMBdp6p9mBqt28WU8fgRkxS0mz+1i7VNTv6ZwUXawfTyOVCPR5B"
+            + "QEC+FA+LvdX0UcJBJpa9tT4koz1JBxmppxxLYdS2A5sslPD5If8QHUaOMEX9O1I+"
+            + "So3rEh3+DuhQj88FUuG8uJAD/3Xtpf/5nEpghLOZdQ/7QkLCoRZk7fwjChQNFSJU"
+            + "5xiZbZ/GsSvU1IqAP/NZBmBO0qDm5m7ahXy71O1bMFtaiUaw2Mb7dwqqDvppbjIB"
+            + "OHdIhSnAorRLcnjm8z51QVMzHmgvKt5/e1q1fzsVzza6DWtYr2X/1VsuouSC1uz1"
+            + "nPdgnQH+BFGSNJ4BBAC3KliQlchs0rctsXbhA/GEfiO0s9tAgVsfJL1PWUkC+26M"
+            + "yBbqkVg5RV+J6dyTSeT6cDI8PMu8XFPO6H2WWdovfs7X9K1lxfnNWxQB2L6t2xre"
+            + "XyFqvTsYEFuGvYmbNyUYvA+daHD0xqX8UrC0J6TYg5ie5I685X8gFKVEtGYG/wAR"
+            + "AQAB/gIDAuMt34hcdJPX03uBj9LtjcnrMNLyF7PVJv4wBXEt7T9Kp8cYZ80Sxpd2"
+            + "11LHzjgiPg1kkkImJ9Ie1qbPZjc9tyiGf47m0TIORnKtwNb2YN+sKLpqZ+ienfTs"
+            + "vc0uyuVGW+8PCt409M9R++0q66sxvb3oKBp2zsr3BbGaISs4OVxY2L8uU3t5j9pi"
+            + "qKdV2XTiV9OZJ+2f1au1tMwhNPzjVJ4GH53TxewSkshRJTZtw2ouUJkdA/bizfNO"
+            + "9XYYvV8sW1/ASe1dnOs+ANDGzumzSA00dWPSveURroG+ZtVXVgkakJJtDwdAYutP"
+            + "kSm28cnsl1OmrBKPonB5N3uDjTlq56vji1d2F5ugAXTTD5PptiML1wEB/TqsRJRX"
+            + "uY7DLy+8iukOVOyoVw63UMX27YUz61JJZYcB7U28gNeRyBsnTEbjmvteoFsYnaGg"
+            + "Owgc+1Zx4rQdZEqxZRmfwmiUgHGyI9OpvoVaTIuDIqDd2ZRWiJ8EGAECAAkFAlGS"
+            + "NJ4CGwwACgkQ0q+h4fbbpOScsgQAmMymSfAmltnHQzKr5k2GvlAqIzl9MqKVm9wA"
+            + "0Cx3grwzPaiqmfspPIueQ8Phexiy6dwfPrwNoKnJOEjM6/sOcWEmLiIoYi+/oQjU"
+            + "12zwogOfzT/1hPpG5zs+GBGX4sorCK663PuovwCEoNrWm+7nItfTwdnFavNuj7s4"
+            + "+b3JLdM=");
+
+        private static readonly byte[] pgpPrivateFull = Base64.Decode(
+              "lQH+BFGSNGwBBACwABZRIEW/4vDQajcO0FW39yNDcsHBDwPkGT95D7jiVTTRoSs6"
+            + "ACWRAAwGlz4V62U0+nEgasxpifHnu6jati5zxwS16qNvBcxcqZrdZWdvolzCWWsr"
+            + "pFd0juhwesrvvUb5dN/xCJKyLPkp6A+uwv35/cxVSOHFvbW7nnronwinYQARAQAB"
+            + "/gIDAuqTuDp/Chfq0TKnSxmm2ZpDuiHD+NFVnCyNuJpvCQk0PnVwmGMH4xvsAZB2"
+            + "TOrfh2XHf/n9J4vjxB6p6Zs1kGBgg9hcHoWf+oEf1Tz/PE/c1tUXG2Hz9wlAgstU"
+            + "my2NpDTYUjQs45p+LaM+WFtLNXzBeqELKlMevs8Xb7n+VHwiTuM3KfXETLCoLz0Q"
+            + "3GmmpOuNnvXBdza7RsDwke0r66HzwX4Le8cMH9Pe7kSMakx9S1UR/uIsxsZYZOKb"
+            + "BieGEumxiAnew0Ri5/8wTd5yYC7BWbYvBUgdMQ1gzkzmJcVky8NVfoZKQ0GkdvMo"
+            + "fMThIVXN1U6+aqzAuUMFCPYQ7fEpfoNLhCnzQPv3RE7Wo2vFMjWBod2J4MSLhBuq"
+            + "Ut+FYLqYqU21Qe4PEyPmGnkVu7Wd8FGjBF+IKZg+ycPi++h/twloD/h7LEaq907C"
+            + "4R3rdOzjZnefDfxVWjLLhqKSSuXxtjSSKwMNdbjYVVJ/tB5UZXN0IFRlc3RlcnNv"
+            + "biA8dGVzdEB0ZXN0Lm5ldD6IuAQTAQIAIgUCUZI0bAIbAwYLCQgHAwIGFQgCCQoL"
+            + "BBYCAwECHgECF4AACgkQ0q+h4fbbpOTXyAP+IjDxfZNv+ymp1pLDawaoSnprMiO4"
+            + "S08QML/gAPQdKzjtkKCWHvTo7ip9ffXzTiT7AIMMu6JLw3t0AFM91gPRpYITOUk2"
+            + "L6JxSbZe6OJMo3GeBztmSOQXXOTvYut0AKzb+NKlafvgNzH/td8+3H7Srn49Lzn8"
+            + "OmHmsi1V3FeIfeSdAf4EUZI0jQEEANpd3WZxRWF2A6DR89XDl+O/OwmynQSH4gCx"
+            + "X3W8kOk82JAkyU51QmZULNmnsq3HU0mVMTeMvW4oeJ3yfLkSskLy5ujtLumxtepF"
+            + "Aw558JbBp97r0131MJ0j6vKRWNmnHXumRjdub3szStUegu5FN/qbjR6gSEQDXx07"
+            + "ARJWg9ldABEBAAH+AgMCFCNPkJcAVRXTWkv6aTsEobexq9fQCuEh3vdlVgypwgTz"
+            + "dlt74TODXGUkAldqIhDCNGpC2duo6gokZQL04y0lQ4aNa1Fm2ksRXypQ0DW8QiSp"
+            + "TEHlX27FlyTHg5J9QIT67tzwS5emNY6HHbyFTO2kLoDUJcBLhVoLWXjg8XIAX19p"
+            + "UHhDCL9ALVkwDLejFU/AIJxaoqguPteLdI9ghz9oagg6+c8PYHqwGENBdNzkt+Lw"
+            + "5uGOQ5kBY8gdOUDtnCDeA2fYCYPDQEE/j/m8Fkd/4vaU6tyJzZKItrk+NTpx7GFo"
+            + "CqBEJ+tgQ8Y27zt+fXK1IqvVb0udr9lF4W+mfnxdz6F17KG0tUEMEz1wHgP5pQH5"
+            + "U6fh65HJGrWOw4FmzjdUkp+GdV3FjygUmHqUufvdE4928mbzey2o+tWZV1Qb1N8e"
+            + "8+jGgWQ3+OO/X5JXFJydd7/j+rhp0yOGBEOaT4x59XQ6g9jZfGVvbnyvaT2JAT0E"
+            + "GAECAAkFAlGSNI0CGwIAqAkQ0q+h4fbbpOSdIAQZAQIABgUCUZI0jQAKCRDyFO8C"
+            + "eVrNitBdA/4x8eI62au0gr+vf+IYnLY4M5zTRUjpttP26x1zAXaeqfZgardvFlPH"
+            + "4EZMUtJs/tYu1TU7+mcFF2sH08jlQj0eQUBAvhQPi73V9FHCQSaWvbU+JKM9SQcZ"
+            + "qaccS2HUtgObLJTw+SH/EB1GjjBF/TtSPkqN6xId/g7oUI/PBVLhvLiQA/917aX/"
+            + "+ZxKYISzmXUP+0JCwqEWZO38IwoUDRUiVOcYmW2fxrEr1NSKgD/zWQZgTtKg5uZu"
+            + "2oV8u9TtWzBbWolGsNjG+3cKqg76aW4yATh3SIUpwKK0S3J45vM+dUFTMx5oLyre"
+            + "f3tatX87Fc82ug1rWK9l/9VbLqLkgtbs9Zz3YJ0B/gRRkjSeAQQAtypYkJXIbNK3"
+            + "LbF24QPxhH4jtLPbQIFbHyS9T1lJAvtujMgW6pFYOUVfienck0nk+nAyPDzLvFxT"
+            + "zuh9llnaL37O1/StZcX5zVsUAdi+rdsa3l8har07GBBbhr2JmzclGLwPnWhw9Mal"
+            + "/FKwtCek2IOYnuSOvOV/IBSlRLRmBv8AEQEAAf4CAwLjLd+IXHST19N7gY/S7Y3J"
+            + "6zDS8hez1Sb+MAVxLe0/SqfHGGfNEsaXdtdSx844Ij4NZJJCJifSHtamz2Y3Pbco"
+            + "hn+O5tEyDkZyrcDW9mDfrCi6amfonp307L3NLsrlRlvvDwreNPTPUfvtKuurMb29"
+            + "6Cgads7K9wWxmiErODlcWNi/LlN7eY/aYqinVdl04lfTmSftn9WrtbTMITT841Se"
+            + "Bh+d08XsEpLIUSU2bcNqLlCZHQP24s3zTvV2GL1fLFtfwEntXZzrPgDQxs7ps0gN"
+            + "NHVj0r3lEa6BvmbVV1YJGpCSbQ8HQGLrT5EptvHJ7JdTpqwSj6JweTd7g405auer"
+            + "44tXdheboAF00w+T6bYjC9cBAf06rESUV7mOwy8vvIrpDlTsqFcOt1DF9u2FM+tS"
+            + "SWWHAe1NvIDXkcgbJ0xG45r7XqBbGJ2hoDsIHPtWceK0HWRKsWUZn8JolIBxsiPT"
+            + "qb6FWkyLgyKg3dmUVoifBBgBAgAJBQJRkjSeAhsMAAoJENKvoeH226TknLIEAJjM"
+            + "pknwJpbZx0Myq+ZNhr5QKiM5fTKilZvcANAsd4K8Mz2oqpn7KTyLnkPD4XsYsunc"
+            + "Hz68DaCpyThIzOv7DnFhJi4iKGIvv6EI1Nds8KIDn80/9YT6Ruc7PhgRl+LKKwiu"
+            + "utz7qL8AhKDa1pvu5yLX08HZxWrzbo+7OPm9yS3T");
+
+        public override void PerformTest()
+        {
+            PgpSecretKeyRing pgpSecRing = new PgpSecretKeyRing(pgpPrivateFull);
+            PgpSecretKey pgpSecKey = pgpSecRing.GetSecretKey();
+            bool isFullEmpty = pgpSecKey.IsPrivateKeyEmpty;
+
+            pgpSecRing = new PgpSecretKeyRing(pgpPrivateEmpty);
+            pgpSecKey = pgpSecRing.GetSecretKey();
+            bool isEmptyEmpty = pgpSecKey.IsPrivateKeyEmpty;
+
+            //
+            // Check isPrivateKeyEmpty() is public
+            //
+
+            if (isFullEmpty || !isEmptyEmpty)
+            {
+                Fail("Empty private keys not detected correctly.");
+            }
+
+            //
+            // Check copyWithNewPassword doesn't throw an exception for secret
+            // keys without private keys (PGPException: unknown S2K type: 101).
+            //
+
+            SecureRandom rand = new SecureRandom();
+
+            try
+            {
+                PgpSecretKey pgpChangedKey = PgpSecretKey.CopyWithNewPassword(pgpSecKey,
+                    pgpOldPass.ToCharArray(), pgpNewPass.ToCharArray(), pgpSecKey.KeyEncryptionAlgorithm, rand);
+            }
+            catch (PgpException e)
+            {
+                if (!e.Message.Equals("no private key in this SecretKey - public key present only."))
+                {
+                    Fail("wrong exception.");
+                }
+            }
+        }
+
+        public override string Name
+        {
+            get { return "PGPNoPrivateKeyTest"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new PGPNoPrivateKeyTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PGPPBETest.cs b/crypto/test/src/openpgp/test/PGPPBETest.cs
new file mode 100644
index 000000000..621cef684
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPPBETest.cs
@@ -0,0 +1,384 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    [TestFixture]
+    public class PgpPbeTest
+		: SimpleTest
+    {
+		private static readonly DateTime TestDateTime = new DateTime(2003, 8, 29, 23, 35, 11, 0);
+
+		private static readonly byte[] enc1 = Base64.Decode(
+            "jA0EAwMC5M5wWBP2HBZgySvUwWFAmMRLn7dWiZN6AkQMvpE3b6qwN3SSun7zInw2"
+            + "hxxdgFzVGfbjuB8w");
+//        private static readonly byte[] enc1crc = Base64.Decode("H66L");
+		private static readonly char[] pass = "hello world".ToCharArray();
+
+		/**
+		 * Message with both PBE and symmetric
+		 */
+		private static readonly byte[] testPBEAsym = Base64.Decode(
+			"hQIOA/ZlQEFWB5vuEAf/covEUaBve7NlWWdiO5NZubdtTHGElEXzG9hyBycp9At8" +
+			"nZGi27xOZtEGFQo7pfz4JySRc3O0s6w7PpjJSonFJyNSxuze2LuqRwFWBYYcbS8/" +
+			"7YcjB6PqutrT939OWsozfNqivI9/QyZCjBvFU89pp7dtUngiZ6MVv81ds2I+vcvk" +
+			"GlIFcxcE1XoCIB3EvbqWNaoOotgEPT60unnB2BeDV1KD3lDRouMIYHfZ3SzBwOOI" +
+			"6aK39sWnY5sAK7JjFvnDAMBdueOiI0Fy+gxbFD/zFDt4cWAVSAGTC4w371iqppmT" +
+			"25TM7zAtCgpiq5IsELPlUZZnXKmnYQ7OCeysF0eeVwf+OFB9fyvCEv/zVQocJCg8" +
+			"fWxfCBlIVFNeNQpeGygn/ZmRaILvB7IXDWP0oOw7/F2Ym66IdYYIp2HeEZv+jFwa" +
+			"l41w5W4BH/gtbwGjFQ6CvF/m+lfUv6ZZdzsMIeEOwhP5g7rXBxrbcnGBaU+PXbho" +
+			"gjDqaYzAWGlrmAd6aPSj51AGeYXkb2T1T/yoJ++M3GvhH4C4hvitamDkksh/qRnM" +
+			"M/s8Nku6z1+RXO3M6p5QC1nlAVqieU8esT43945eSoC77K8WyujDNbysDyUCUTzt" +
+			"p/aoQwe/HgkeOTJNelKR9y2W3xinZLFzep0SqpNI/e468yB/2/LGsykIyQa7JX6r" +
+			"BYwuBAIDAkOKfv5rK8v0YDfnN+eFqwhTcrfBj5rDH7hER6nW3lNWcMataUiHEaMg" +
+			"o6Q0OO1vptIGxW8jClTD4N1sCNwNu9vKny8dKYDDHbCjE06DNTv7XYVW3+JqTL5E" +
+			"BnidvGgOmA==");
+
+		/**
+        * decrypt the passed in message stream
+        */
+        private byte[] DecryptMessage(
+            byte[] message)
+        {
+            PgpObjectFactory		pgpF = new PgpObjectFactory(message);
+            PgpEncryptedDataList	enc = (PgpEncryptedDataList) pgpF.NextPgpObject();
+            PgpPbeEncryptedData		pbe = (PgpPbeEncryptedData) enc[0];
+            Stream					clear = pbe.GetDataStream(pass);
+
+			PgpObjectFactory		pgpFact = new PgpObjectFactory(clear);
+            PgpCompressedData		cData = (PgpCompressedData) pgpFact.NextPgpObject();
+            pgpFact = new PgpObjectFactory(cData.GetDataStream());
+
+			PgpLiteralData ld = (PgpLiteralData) pgpFact.NextPgpObject();
+
+            if (!ld.FileName.Equals("test.txt")
+                && !ld.FileName.Equals("_CONSOLE"))
+            {
+                Fail("wrong filename in packet");
+            }
+
+			if (!ld.ModificationTime.Equals(TestDateTime))
+			{
+				Fail("wrong modification time in packet: " + ld.ModificationTime + " vs " + TestDateTime);
+			}
+
+			Stream unc = ld.GetInputStream();
+			byte[] bytes = Streams.ReadAll(unc);
+
+			if (pbe.IsIntegrityProtected() && !pbe.Verify())
+			{
+				Fail("integrity check failed");
+			}
+
+			return bytes;
+        }
+
+		private byte[] DecryptMessageBuffered(
+			byte[] message)
+		{
+			PgpObjectFactory		pgpF = new PgpObjectFactory(message);
+			PgpEncryptedDataList	enc = (PgpEncryptedDataList) pgpF.NextPgpObject();
+			PgpPbeEncryptedData		pbe = (PgpPbeEncryptedData) enc[0];
+
+			Stream clear = pbe.GetDataStream(pass);
+
+			PgpObjectFactory	pgpFact = new PgpObjectFactory(clear);
+			PgpCompressedData	cData = (PgpCompressedData) pgpFact.NextPgpObject();
+
+			pgpFact = new PgpObjectFactory(cData.GetDataStream());
+
+			PgpLiteralData ld = (PgpLiteralData) pgpFact.NextPgpObject();
+
+			MemoryStream bOut = new MemoryStream();
+			if (!ld.FileName.Equals("test.txt")
+				&& !ld.FileName.Equals("_CONSOLE"))
+			{
+				Fail("wrong filename in packet");
+			}
+			if (!ld.ModificationTime.Equals(TestDateTime))
+			{
+				Fail("wrong modification time in packet: " + ld.ModificationTime.Ticks + " " + TestDateTime.Ticks);
+			}
+
+			Stream unc = ld.GetInputStream();
+			byte[] buf = new byte[1024];
+
+			int len;
+			while ((len = unc.Read(buf, 0, buf.Length)) > 0)
+			{
+				bOut.Write(buf, 0, len);
+			}
+
+			if (pbe.IsIntegrityProtected() && !pbe.Verify())
+			{
+				Fail("integrity check failed");
+			}
+
+			return bOut.ToArray();
+		}
+
+		public override void PerformTest()
+        {
+            byte[] data = DecryptMessage(enc1);
+            if (data[0] != 'h' || data[1] != 'e' || data[2] != 'l')
+            {
+                Fail("wrong plain text in packet");
+            }
+
+			//
+            // create a PBE encrypted message and read it back.
+            //
+			byte[] text = Encoding.ASCII.GetBytes("hello world!\n");
+
+			//
+            // encryption step - convert to literal data, compress, encode.
+            //
+            MemoryStream bOut = new UncloseableMemoryStream();
+
+            PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(
+                CompressionAlgorithmTag.Zip);
+
+            PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
+			Stream comOut = comData.Open(new UncloseableStream(bOut));
+            Stream ldOut = lData.Open(
+				new UncloseableStream(comOut),
+                PgpLiteralData.Binary,
+                PgpLiteralData.Console,
+                text.Length,
+                TestDateTime);
+
+			ldOut.Write(text, 0, text.Length);
+			ldOut.Close();
+
+			comOut.Close();
+
+			//
+            // encrypt - with stream close
+            //
+            MemoryStream cbOut = new UncloseableMemoryStream();
+            PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(
+				SymmetricKeyAlgorithmTag.Cast5, new SecureRandom());
+
+            cPk.AddMethod(pass);
+
+			byte[] bOutData = bOut.ToArray();
+			Stream cOut = cPk.Open(new UncloseableStream(cbOut), bOutData.Length);
+            cOut.Write(bOutData, 0, bOutData.Length);
+            cOut.Close();
+
+			data = DecryptMessage(cbOut.ToArray());
+            if (!Arrays.AreEqual(data, text))
+            {
+                Fail("wrong plain text in generated packet");
+            }
+
+			//
+			// encrypt - with generator close
+			//
+			cbOut = new UncloseableMemoryStream();
+			cPk = new PgpEncryptedDataGenerator(
+				SymmetricKeyAlgorithmTag.Cast5, new SecureRandom());
+
+			cPk.AddMethod(pass);
+
+			bOutData = bOut.ToArray();
+			cOut = cPk.Open(new UncloseableStream(cbOut), bOutData.Length);
+			cOut.Write(bOutData, 0, bOutData.Length);
+
+			cPk.Close();
+
+			data = DecryptMessage(cbOut.ToArray());
+
+			if (!AreEqual(data, text))
+			{
+				Fail("wrong plain text in generated packet");
+			}
+
+			//
+            // encrypt - partial packet style.
+            //
+            SecureRandom rand = new SecureRandom();
+            byte[] test = new byte[1233];
+
+            rand.NextBytes(test);
+
+			bOut = new UncloseableMemoryStream();
+
+			comData = new PgpCompressedDataGenerator(
+				CompressionAlgorithmTag.Zip);
+			comOut = comData.Open(new UncloseableStream(bOut));
+
+			lData = new PgpLiteralDataGenerator();
+            ldOut = lData.Open(
+				new UncloseableStream(comOut),
+                PgpLiteralData.Binary,
+                PgpLiteralData.Console,
+                TestDateTime,
+                new byte[16]);
+
+            ldOut.Write(test, 0, test.Length);
+            lData.Close();
+
+			comData.Close();
+            cbOut = new UncloseableMemoryStream();
+            cPk = new PgpEncryptedDataGenerator(
+				SymmetricKeyAlgorithmTag.Cast5, rand);
+
+            cPk.AddMethod(pass);
+
+			cOut = cPk.Open(new UncloseableStream(cbOut), new byte[16]);
+            {
+                byte[] tmp = bOut.ToArray();
+                cOut.Write(tmp, 0, tmp.Length);
+            }
+
+			cPk.Close();
+
+			data = DecryptMessage(cbOut.ToArray());
+            if (!Arrays.AreEqual(data, test))
+            {
+                Fail("wrong plain text in generated packet");
+            }
+
+            //
+            // with integrity packet
+            //
+            cbOut = new UncloseableMemoryStream();
+            cPk = new PgpEncryptedDataGenerator(
+				SymmetricKeyAlgorithmTag.Cast5, true, rand);
+
+            cPk.AddMethod(pass);
+
+            cOut = cPk.Open(new UncloseableStream(cbOut), new byte[16]);
+            bOutData = bOut.ToArray();
+            cOut.Write(bOutData, 0, bOutData.Length);
+            cPk.Close();
+
+			data = DecryptMessage(cbOut.ToArray());
+            if (!Arrays.AreEqual(data, test))
+            {
+                Fail("wrong plain text in generated packet");
+            }
+
+			//
+			// decrypt with buffering
+			//
+			data = DecryptMessageBuffered(cbOut.ToArray());
+			if (!AreEqual(data, test))
+			{
+				Fail("wrong plain text in buffer generated packet");
+			}
+
+			//
+			// sample message
+			//
+			PgpObjectFactory pgpFact = new PgpObjectFactory(testPBEAsym);
+
+			PgpEncryptedDataList enc = (PgpEncryptedDataList)pgpFact.NextPgpObject();
+
+			PgpPbeEncryptedData pbe = (PgpPbeEncryptedData) enc[1];
+
+			Stream clear = pbe.GetDataStream("password".ToCharArray());
+
+			pgpFact = new PgpObjectFactory(clear);
+
+			PgpLiteralData ld = (PgpLiteralData) pgpFact.NextPgpObject();
+
+			Stream unc = ld.GetInputStream();
+			byte[] bytes = Streams.ReadAll(unc);
+
+			if (!AreEqual(bytes, Hex.Decode("5361742031302e30322e30370d0a")))
+			{
+				Fail("data mismatch on combined PBE");
+			}
+
+			//
+			// with integrity packet - one byte message
+			//
+			byte[] msg = new byte[1];
+			bOut = new MemoryStream();
+
+			comData = new PgpCompressedDataGenerator(
+				CompressionAlgorithmTag.Zip);
+
+			lData = new PgpLiteralDataGenerator();
+			comOut = comData.Open(new UncloseableStream(bOut));
+			ldOut = lData.Open(
+				new UncloseableStream(comOut),
+				PgpLiteralData.Binary,
+				PgpLiteralData.Console,
+				msg.Length,
+				TestDateTime);
+
+			ldOut.Write(msg, 0, msg.Length);
+
+			ldOut.Close();
+
+			comOut.Close();
+        
+			cbOut = new MemoryStream();
+			cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, true, rand);
+
+			cPk.AddMethod(pass);
+
+			cOut = cPk.Open(new UncloseableStream(cbOut), new byte[16]);
+
+			data = bOut.ToArray();
+			cOut.Write(data, 0, data.Length);
+
+			cOut.Close();
+
+			data = DecryptMessage(cbOut.ToArray());
+			if (!AreEqual(data, msg))
+			{
+				Fail("wrong plain text in generated packet");
+			}
+
+			//
+			// decrypt with buffering
+			//
+			data = DecryptMessageBuffered(cbOut.ToArray());
+			if (!AreEqual(data, msg))
+			{
+				Fail("wrong plain text in buffer generated packet");
+			}
+		}
+
+		private class UncloseableMemoryStream
+			: MemoryStream
+		{
+			public override void Close()
+			{
+				throw new Exception("Close() called on underlying stream");
+			}
+		}
+
+		public override string Name
+        {
+			get { return "PGPPBETest"; }
+        }
+
+		public static void Main(
+			string[] args)
+        {
+			RunTest(new PgpPbeTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PGPPacketTest.cs b/crypto/test/src/openpgp/test/PGPPacketTest.cs
new file mode 100644
index 000000000..b82f8526f
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPPacketTest.cs
@@ -0,0 +1,80 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    [TestFixture]
+    public class PgpPacketTest
+        : SimpleTest
+    {
+        private static int MAX = 32000;
+
+        private void ReadBackTest(
+            PgpLiteralDataGenerator generator)
+        {
+            Random rand = new Random();
+            byte[] buf = new byte[MAX];
+
+            rand.NextBytes(buf);
+
+            for (int i = 1; i != MAX; i++)
+            {
+                MemoryStream bOut = new MemoryStream();
+
+                Stream outputStream = generator.Open(
+					new UncloseableStream(bOut),
+					PgpLiteralData.Binary,
+					PgpLiteralData.Console,
+					i,
+					DateTime.UtcNow);
+
+				outputStream.Write(buf, 0, i);
+
+                generator.Close();
+
+                PgpObjectFactory fact = new PgpObjectFactory(bOut.ToArray());
+
+                PgpLiteralData data = (PgpLiteralData)fact.NextPgpObject();
+
+                Stream inputStream = data.GetInputStream();
+
+                for (int count = 0; count != i; count++)
+                {
+                    if (inputStream.ReadByte() != (buf[count] & 0xff))
+                    {
+                        Fail("failed readback test - length = " + i);
+                    }
+                }
+            }
+        }
+
+        public override void PerformTest()
+        {
+            ReadBackTest(new PgpLiteralDataGenerator(true));
+			ReadBackTest(new PgpLiteralDataGenerator(false));
+        }
+
+		public override string Name
+        {
+			get { return "PGPPacketTest"; }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+			RunTest(new PgpPacketTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PGPRSATest.cs b/crypto/test/src/openpgp/test/PGPRSATest.cs
new file mode 100644
index 000000000..35f844483
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPRSATest.cs
@@ -0,0 +1,1233 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Bcpg.Attr;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    [TestFixture]
+    public class PgpRsaTest
+        : SimpleTest
+    {
+        private static readonly byte[] testPubKey = Base64.Decode(
+              "mIsEPz2nJAEEAOTVqWMvqYE693qTgzKv/TJpIj3hI8LlYPC6m1dk0z3bDLwVVk9F"
+            + "FAB+CWS8RdFOWt/FG3tEv2nzcoNdRvjv9WALyIGNawtae4Ml6oAT06/511yUzXHO"
+            + "k+9xK3wkXN5jdzUhf4cA2oGpLSV/pZlocsIDL+jCUQtumUPwFodmSHhzAAYptC9F"
+            + "cmljIEVjaGlkbmEgKHRlc3Qga2V5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPoi4"
+            + "BBMBAgAiBQI/PackAhsDBQkAg9YABAsHAwIDFQIDAxYCAQIeAQIXgAAKCRA1WGFG"
+            + "/fPzc8WMA/9BbjuB8E48QAlxoiVf9U8SfNelrz/ONJA/bMvWr/JnOGA9PPmFD5Uc"
+            + "+kV/q+i94dEMjsC5CQ1moUHWSP2xlQhbOzBP2+oPXw3z2fBs9XJgnTH6QWMAAvLs"
+            + "3ug9po0loNHLobT/D/XdXvcrb3wvwvPT2FptZqrtonH/OdzT9JdfrA==");
+
+        private static readonly byte[] testPrivKey = Base64.Decode(
+              "lQH8BD89pyQBBADk1aljL6mBOvd6k4Myr/0yaSI94SPC5WDwuptXZNM92wy8FVZP"
+            + "RRQAfglkvEXRTlrfxRt7RL9p83KDXUb47/VgC8iBjWsLWnuDJeqAE9Ov+ddclM1x"
+            + "zpPvcSt8JFzeY3c1IX+HANqBqS0lf6WZaHLCAy/owlELbplD8BaHZkh4cwAGKf4D"
+            + "AwKbLeIOVYTEdWD5v/YgW8ERs0pDsSIfBTvsJp2qA798KeFuED6jGsHUzdi1M990"
+            + "6PRtplQgnoYmYQrzEc6DXAiAtBR4Kuxi4XHx0ZR2wpVlVxm2Ypgz7pbBNWcWqzvw"
+            + "33inl7tR4IDsRdJOY8cFlN+1tSCf16sDidtKXUVjRjZNYJytH18VfSPlGXMeYgtw"
+            + "3cSGNTERwKaq5E/SozT2MKTiORO0g0Mtyz+9MEB6XVXFavMun/mXURqbZN/k9BFb"
+            + "z+TadpkihrLD1xw3Hp+tpe4CwPQ2GdWKI9KNo5gEnbkJgLrSMGgWalPhknlNHRyY"
+            + "bSq6lbIMJEE3LoOwvYWwweR1+GrV9farJESdunl1mDr5/d6rKru+FFDwZM3na1IF"
+            + "4Ei4FpqhivZ4zG6pN5XqLy+AK85EiW4XH0yAKX1O4YlbmDU4BjxhiwTdwuVMCjLO"
+            + "5++jkz5BBQWdFX8CCMA4FJl36G70IbGzuFfOj07ly7QvRXJpYyBFY2hpZG5hICh0"
+            + "ZXN0IGtleSkgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IuAQTAQIAIgUCPz2nJAIb"
+            + "AwUJAIPWAAQLBwMCAxUCAwMWAgECHgECF4AACgkQNVhhRv3z83PFjAP/QW47gfBO"
+            + "PEAJcaIlX/VPEnzXpa8/zjSQP2zL1q/yZzhgPTz5hQ+VHPpFf6voveHRDI7AuQkN"
+            + "ZqFB1kj9sZUIWzswT9vqD18N89nwbPVyYJ0x+kFjAALy7N7oPaaNJaDRy6G0/w/1"
+            + "3V73K298L8Lz09habWaq7aJx/znc0/SXX6w=");
+
+        private static readonly byte[] testPubKeyV3 = Base64.Decode(
+              "mQCNAz+zvlEAAAEEAMS22jgXbOZ/D3xWgM2kauSdzrwlU7Ms5hDW05ObqQyO"
+            + "FfQoKKMhfupyoa7J3x04VVBKu6Eomvr1es+VImH0esoeWFFahNOYq/I+jRRB"
+            + "woOhAGZ5UB2/hRd7rFmxqp6sCXi8wmLO2tAorlTzAiNNvl7xF4cQZpc0z56F"
+            + "wdi2fBUJAAURtApGSVhDSVRZX1FBiQCVAwUQP7O+UZ6Fwdi2fBUJAQFMwwQA"
+            + "qRnFsdg4xQnB8Y5d4cOpXkIn9AZgYS3cxtuSJB84vG2CgC39nfv4c+nlLkWP"
+            + "4puG+mZuJNgVoE84cuAF4I//1anKjlU7q1M6rFQnt5S4uxPyG3dFXmgyU1b4"
+            + "PBOnA0tIxjPzlIhJAMsPCGGA5+5M2JP0ad6RnzqzE3EENMX+GqY=");
+
+        private static readonly byte[] testPrivKeyV3 = Base64.Decode(
+              "lQHfAz+zvlEAAAEEAMS22jgXbOZ/D3xWgM2kauSdzrwlU7Ms5hDW05ObqQyO"
+            + "FfQoKKMhfupyoa7J3x04VVBKu6Eomvr1es+VImH0esoeWFFahNOYq/I+jRRB"
+            + "woOhAGZ5UB2/hRd7rFmxqp6sCXi8wmLO2tAorlTzAiNNvl7xF4cQZpc0z56F"
+            + "wdi2fBUJAAURAXWwRBZQHNikA/f0ScLLjrXi4s0hgQecg+dkpDow94eu5+AR"
+            + "0DzZnfurpgfUJCNiDi5W/5c3Zj/xyrfMAgkbCgJ1m6FZqAQh7Mq73l7Kfu4/"
+            + "XIkyDF3tDgRuZNezB+JuElX10tV03xumHepp6M6CfhXqNJ15F33F99TA5hXY"
+            + "CPYD7SiSOpIhQkCOAgDAA63imxbpuKE2W7Y4I1BUHB7WQi8ZdkZd04njNTv+"
+            + "rFUuOPapQVfbWG0Vq8ld3YmJB4QWsa2mmqn+qToXbwufAgBpXkjvqK5yPiHF"
+            + "Px2QbFc1VqoCJB6PO5JRIqEiUZBFGdDlLxt3VSyqz7IZ/zEnxZq+tPCGGGSm"
+            + "/sAGiMvENcHVAfy0kTXU42TxEAYJyyNyqjXOobDJpEV1mKhFskRXt7tbMfOS"
+            + "Yf91oX8f6xw6O2Nal+hU8dS0Bmfmk5/enHmvRLHQocO0CkZJWENJVFlfUUE=");
+
+        private static readonly byte[] sig1 = Base64.Decode(
+              "owGbwMvMwMRoGpHo9vfz52LGNTJJnBmpOTn5eiUVJfb23JvAHIXy/KKcFEWuToap"
+            + "zKwMIGG4Bqav0SwMy3yParsEKi2LMGI9xhh65sBxb05n5++ZLcWNJ/eLFKdWbm95"
+            + "tHbDV7GMwj/tUctUpFUXWPYFCLdNsDiVNuXbQvZtdXV/5xzY+9w1nCnijH9JoNiJ"
+            + "22n2jo0zo30/TZLo+jDl2vTzIvPeLEsPM3ZUE/1Ytqs4SG2TxIQbH7xf3uzcYXq2"
+            + "5Fw9AA==");
+
+//		private static readonly byte[] sig1crc = Base64.Decode("+3i0");
+
+        private static readonly byte[] subKey = Base64.Decode(
+              "lQH8BD89pyQBBADk1aljL6mBOvd6k4Myr/0yaSI94SPC5WDwuptXZNM92wy8FVZP"
+            + "RRQAfglkvEXRTlrfxRt7RL9p83KDXUb47/VgC8iBjWsLWnuDJeqAE9Ov+ddclM1x"
+            + "zpPvcSt8JFzeY3c1IX+HANqBqS0lf6WZaHLCAy/owlELbplD8BaHZkh4cwAGKf4D"
+            + "AwKt6ZC7iqsQHGDNn2ZAuhS+ZwiFC+BToW9Vq6rwggWjgM/SThv55rfDk7keiXUT"
+            + "MyUcZVeYBe4Jttb4fAAm83hNztFu6Jvm9ITcm7YvnasBtVQjppaB+oYZgsTtwK99"
+            + "LGC3mdexnriCLxPN6tDFkGhzdOcYZfK6py4Ska8Dmq9nOZU9Qtv7Pm3qa5tuBvYw"
+            + "myTxeaJYifZTu/sky3Gj+REb8WonbgAJX/sLNBPUt+vYko+lxU8uqZpVEMU//hGG"
+            + "Rns2gIHdbSbIe1vGgIRUEd7Z0b7jfVQLUwqHDyfh5DGvAUhvtJogjUyFIXZzpU+E"
+            + "9ES9t7LZKdwNZSIdNUjM2eaf4g8BpuQobBVkj/GUcotKyeBjwvKxHlRefL4CCw28"
+            + "DO3SnLRKxd7uBSqeOGUKxqasgdekM/xIFOrJ85k7p89n6ncLQLHCPGVkzmVeRZro"
+            + "/T7zE91J57qBGZOUAP1vllcYLty1cs9PCc5oWnj3XbQvRXJpYyBFY2hpZG5hICh0"
+            + "ZXN0IGtleSkgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IuAQTAQIAIgUCPz2nJAIb"
+            + "AwUJAIPWAAQLBwMCAxUCAwMWAgECHgECF4AACgkQNVhhRv3z83PFjAP/QW47gfBO"
+            + "PEAJcaIlX/VPEnzXpa8/zjSQP2zL1q/yZzhgPTz5hQ+VHPpFf6voveHRDI7AuQkN"
+            + "ZqFB1kj9sZUIWzswT9vqD18N89nwbPVyYJ0x+kFjAALy7N7oPaaNJaDRy6G0/w/1"
+            + "3V73K298L8Lz09habWaq7aJx/znc0/SXX6y0JEVyaWMgRWNoaWRuYSA8ZXJpY0Bi"
+            + "b3VuY3ljYXN0bGUub3JnPoi4BBMBAgAiBQI/RxQNAhsDBQkAg9YABAsHAwIDFQID"
+            + "AxYCAQIeAQIXgAAKCRA1WGFG/fPzc3O6A/49tXFCiiP8vg77OXvnmbnzPBA1G6jC"
+            + "RZNP1yIXusOjpHqyLN5K9hw6lq/o4pNiCuiq32osqGRX3lv/nDduJU1kn2Ow+I2V"
+            + "ci+ojMXdCGdEqPwZfv47jHLwRrIUJ22OOoWsORtgvSeRUd4Izg8jruaFM7ufr5hr"
+            + "jEl1cuLW1Hr8Lp0B/AQ/RxxQAQQA0J2BIdqb8JtDGKjvYxrju0urJVVzyI1CnCjA"
+            + "p7CtLoHQJUQU7PajnV4Jd12ukfcoK7MRraYydQEjxh2MqPpuQgJS3dgQVrxOParD"
+            + "QYBFrZNd2tZxOjYakhErvUmRo6yWFaxChwqMgl8XWugBNg1Dva+/YcoGQ+ly+Jg4"
+            + "RWZoH88ABin+AwMCldD/2v8TyT1ghK70IuFs4MZBhdm6VgyGR8DQ/Ago6IAjA4BY"
+            + "Sol3lJb7+IIGsZaXwEuMRUvn6dWfa3r2I0p1t75vZb1Ng1YK32RZ5DNzl4Xb3L8V"
+            + "D+1Fiz9mHO8wiplAwDudB+RmQMlth3DNi/UsjeCTdEJAT+TTC7D40DiHDb1bR86Y"
+            + "2O5Y7MQ3SZs3/x0D/Ob6PStjfQ1kiqbruAMROKoavG0zVgxvspkoKN7h7BapnwJM"
+            + "6yf4qN/aByhAx9sFvADxu6z3SVcxiFw3IgAmabyWYb85LP8AsTYAG/HBoC6yob47"
+            + "Mt+GEDeyPifzzGXBWYIH4heZbSQivvA0eRwY5VZsMsBkbY5VR0FLVWgplbuO21bS"
+            + "rPS1T0crC+Zfj7FQBAkTfsg8RZQ8MPaHng01+gnFd243DDFvTAHygvm6a2X2fiRw"
+            + "5epAST4wWfY/BZNOxmfSKH6QS0oQMRscw79He6vGTB7vunLrKQYD4veInwQYAQIA"
+            + "CQUCP0ccUAIbDAAKCRA1WGFG/fPzczmFA/wMg5HhN5NkqmjnHUFfeXNXdHzmekyw"
+            + "38RnuCMKmfc43AiDs+FtJ62gpQ6PEsZF4o9S5fxcjVk3VSg00XMDtQ/0BsKBc5Gx"
+            + "hJTq7G+/SoeM433WG19uoS0+5Lf/31wNoTnpv6npOaYpcTQ7L9LCnzwAF4H0hJPE"
+            + "6bhmW2CMcsE/IZUB4QQ/Rwc1EQQAs5MUQlRiYOfi3fQ1OF6Z3eCwioDKu2DmOxot"
+            + "BICvdoG2muvs0KEBas9bbd0FJqc92FZJv8yxEgQbQtQAiFxoIFHRTFK+SPO/tQm+"
+            + "r83nwLRrfDeVVdRfzF79YCc+Abuh8sS/53H3u9Y7DYWr9IuMgI39nrVhY+d8yukf"
+            + "jo4OR+sAoKS/f7V1Xxj/Eqhb8qzf+N+zJRUlBACDd1eo/zFJZcq2YJa7a9vkViME"
+            + "axvwApqxeoU7oDpeHEMWg2DXJ7V24ZU5SbPTMY0x98cc8pcoqwsqux8xicWc0reh"
+            + "U3odQxWM4Se0LmEdca0nQOmNJlL9IsQ+QOJzx47qUOUAqhxnkXxQ/6B8w+M6gZya"
+            + "fwSdy70OumxESZipeQP+Lo9x6FcaW9L78hDX0aijJhgSEsnGODKB+bln29txX37E"
+            + "/a/Si+pyeLMi82kUdIL3G3I5HPWd3qSO4K94062+HfFj8bA20/1tbb/WxvxB2sKJ"
+            + "i3IobblFOvFHo+v8GaLdVyartp0JZLue/jP1dl9ctulSrIqaJT342uLsgTjsr2z+"
+            + "AwMCAyAU8Vo5AhhgFkDto8vQk7yxyRKEzu5qB66dRcTlaUPIiR8kamcy5ZTtujs4"
+            + "KIW4j2M/LvagrpWfV5+0M0VyaWMgRWNoaWRuYSAoRFNBIFRlc3QgS2V5KSA8ZXJp"
+            + "Y0Bib3VuY3ljYXN0bGUub3JnPohZBBMRAgAZBQI/Rwc1BAsHAwIDFQIDAxYCAQIe"
+            + "AQIXgAAKCRDNI/XpxMo0QwJcAJ40447eezSiIMspuzkwsMyFN8YBaQCdFTuZuT30"
+            + "CphiUYWnsC0mQ+J15B4=");
+
+        private static readonly byte[] enc1 = Base64.Decode(
+              "hIwDKwfQexPJboABA/4/7prhYYMORTiQ5avQKx0XYpCLujzGefYjnyuWZnx3Iev8"
+            + "Pmsguumm+OLLvtXhhkXQmkJRXbIg6Otj2ubPYWflRPgpJSgOrNOreOl5jeABOrtw"
+            + "bV6TJb9OTtZuB7cTQSCq2gmYiSZkluIiDjNs3R3mEanILbYzOQ3zKSggKpzlv9JQ"
+            + "AZUqTyDyJ6/OUbJF5fI5uiv76DCsw1zyMWotUIu5/X01q+AVP5Ly3STzI7xkWg/J"
+            + "APz4zUHism7kSYz2viAQaJx9/bNnH3AM6qm1Fuyikl4=");
+
+//		private static readonly byte[] enc1crc = Base64.Decode("lv4o");
+
+//        private static readonly byte[] enc2 = Base64.Decode(
+//			  "hIwDKwfQexPJboABBAC62jcJH8xKnKb1neDVmiovYON04+7VQ2v4BmeHwJrdag1g"
+//			+ "Ya++6PeBlQ2Q9lSGBwLobVuJmQ7cOnPUJP727JeSGWlMyFtMbBSHekOaTenT5lj7"
+//			+ "Zk7oRHxMp/hByzlMacIDzOn8LPSh515RHM57eDLCOwqnAxGQwk67GRl8f5dFH9JQ"
+//			+ "Aa7xx8rjCqPbiIQW6t5LqCNvPZOiSCmftll6+se1XJhFEuq8WS4nXtPfTiJ3vib4"
+//			+ "3soJdHzGB6AOs+BQ6aKmmNTVAxa5owhtSt1Z/6dfSSk=");
+
+        private static readonly byte[] subPubKey = Base64.Decode(
+              "mIsEPz2nJAEEAOTVqWMvqYE693qTgzKv/TJpIj3hI8LlYPC6m1dk0z3bDLwVVk9F"
+            + "FAB+CWS8RdFOWt/FG3tEv2nzcoNdRvjv9WALyIGNawtae4Ml6oAT06/511yUzXHO"
+            + "k+9xK3wkXN5jdzUhf4cA2oGpLSV/pZlocsIDL+jCUQtumUPwFodmSHhzAAYptC9F"
+            + "cmljIEVjaGlkbmEgKHRlc3Qga2V5KSA8ZXJpY0Bib3VuY3ljYXN0bGUub3JnPoi4"
+            + "BBMBAgAiBQI/PackAhsDBQkAg9YABAsHAwIDFQIDAxYCAQIeAQIXgAAKCRA1WGFG"
+            + "/fPzc8WMA/9BbjuB8E48QAlxoiVf9U8SfNelrz/ONJA/bMvWr/JnOGA9PPmFD5Uc"
+            + "+kV/q+i94dEMjsC5CQ1moUHWSP2xlQhbOzBP2+oPXw3z2fBs9XJgnTH6QWMAAvLs"
+            + "3ug9po0loNHLobT/D/XdXvcrb3wvwvPT2FptZqrtonH/OdzT9JdfrIhMBBARAgAM"
+            + "BQI/RxooBYMAemL8AAoJEM0j9enEyjRDiBgAn3RcLK+gq90PvnQFTw2DNqdq7KA0"
+            + "AKCS0EEIXCzbV1tfTdCUJ3hVh3btF7QkRXJpYyBFY2hpZG5hIDxlcmljQGJvdW5j"
+            + "eWNhc3RsZS5vcmc+iLgEEwECACIFAj9HFA0CGwMFCQCD1gAECwcDAgMVAgMDFgIB"
+            + "Ah4BAheAAAoJEDVYYUb98/Nzc7oD/j21cUKKI/y+Dvs5e+eZufM8EDUbqMJFk0/X"
+            + "Ihe6w6OkerIs3kr2HDqWr+jik2IK6KrfaiyoZFfeW/+cN24lTWSfY7D4jZVyL6iM"
+            + "xd0IZ0So/Bl+/juMcvBGshQnbY46haw5G2C9J5FR3gjODyOu5oUzu5+vmGuMSXVy"
+            + "4tbUevwuiEwEEBECAAwFAj9HGigFgwB6YvwACgkQzSP16cTKNEPwBQCdHm0Amwza"
+            + "NmVmDHm3rmqI7rp2oQ0An2YbiP/H/kmBNnmTeH55kd253QOhuIsEP0ccUAEEANCd"
+            + "gSHam/CbQxio72Ma47tLqyVVc8iNQpwowKewrS6B0CVEFOz2o51eCXddrpH3KCuz"
+            + "Ea2mMnUBI8YdjKj6bkICUt3YEFa8Tj2qw0GARa2TXdrWcTo2GpIRK71JkaOslhWs"
+            + "QocKjIJfF1roATYNQ72vv2HKBkPpcviYOEVmaB/PAAYpiJ8EGAECAAkFAj9HHFAC"
+            + "GwwACgkQNVhhRv3z83M5hQP8DIOR4TeTZKpo5x1BX3lzV3R85npMsN/EZ7gjCpn3"
+            + "ONwIg7PhbSetoKUOjxLGReKPUuX8XI1ZN1UoNNFzA7UP9AbCgXORsYSU6uxvv0qH"
+            + "jON91htfbqEtPuS3/99cDaE56b+p6TmmKXE0Oy/Swp88ABeB9ISTxOm4ZltgjHLB"
+            + "PyGZAaIEP0cHNREEALOTFEJUYmDn4t30NThemd3gsIqAyrtg5jsaLQSAr3aBtprr"
+            + "7NChAWrPW23dBSanPdhWSb/MsRIEG0LUAIhcaCBR0UxSvkjzv7UJvq/N58C0a3w3"
+            + "lVXUX8xe/WAnPgG7ofLEv+dx97vWOw2Fq/SLjICN/Z61YWPnfMrpH46ODkfrAKCk"
+            + "v3+1dV8Y/xKoW/Ks3/jfsyUVJQQAg3dXqP8xSWXKtmCWu2vb5FYjBGsb8AKasXqF"
+            + "O6A6XhxDFoNg1ye1duGVOUmz0zGNMffHHPKXKKsLKrsfMYnFnNK3oVN6HUMVjOEn"
+            + "tC5hHXGtJ0DpjSZS/SLEPkDic8eO6lDlAKocZ5F8UP+gfMPjOoGcmn8Encu9Drps"
+            + "REmYqXkD/i6PcehXGlvS+/IQ19GooyYYEhLJxjgygfm5Z9vbcV9+xP2v0ovqcniz"
+            + "IvNpFHSC9xtyORz1nd6kjuCveNOtvh3xY/GwNtP9bW2/1sb8QdrCiYtyKG25RTrx"
+            + "R6Pr/Bmi3Vcmq7adCWS7nv4z9XZfXLbpUqyKmiU9+Nri7IE47K9stDNFcmljIEVj"
+            + "aGlkbmEgKERTQSBUZXN0IEtleSkgPGVyaWNAYm91bmN5Y2FzdGxlLm9yZz6IWQQT"
+            + "EQIAGQUCP0cHNQQLBwMCAxUCAwMWAgECHgECF4AACgkQzSP16cTKNEMCXACfauui"
+            + "bSwyG59Yrm8hHCDuCPmqwsQAni+dPl08FVuWh+wb6kOgJV4lcYae");
+
+//		private static readonly byte[] subPubCrc = Base64.Decode("rikt");
+
+        private static readonly byte[] pgp8Key = Base64.Decode(
+              "lQIEBEBXUNMBBADScQczBibewnbCzCswc/9ut8R0fwlltBRxMW0NMdKJY2LF"
+            + "7k2COeLOCIU95loJGV6ulbpDCXEO2Jyq8/qGw1qD3SCZNXxKs3GS8Iyh9Uwd"
+            + "VL07nMMYl5NiQRsFB7wOb86+94tYWgvikVA5BRP5y3+O3GItnXnpWSJyREUy"
+            + "6WI2QQAGKf4JAwIVmnRs4jtTX2DD05zy2mepEQ8bsqVAKIx7lEwvMVNcvg4Y"
+            + "8vFLh9Mf/uNciwL4Se/ehfKQ/AT0JmBZduYMqRU2zhiBmxj4cXUQ0s36ysj7"
+            + "fyDngGocDnM3cwPxaTF1ZRBQHSLewP7dqE7M73usFSz8vwD/0xNOHFRLKbsO"
+            + "RqDlLA1Cg2Yd0wWPS0o7+qqk9ndqrjjSwMM8ftnzFGjShAdg4Ca7fFkcNePP"
+            + "/rrwIH472FuRb7RbWzwXA4+4ZBdl8D4An0dwtfvAO+jCZSrLjmSpxEOveJxY"
+            + "GduyR4IA4lemvAG51YHTHd4NXheuEqsIkn1yarwaaj47lFPnxNOElOREMdZb"
+            + "nkWQb1jfgqO24imEZgrLMkK9bJfoDnlF4k6r6hZOp5FSFvc5kJB4cVo1QJl4"
+            + "pwCSdoU6luwCggrlZhDnkGCSuQUUW45NE7Br22NGqn4/gHs0KCsWbAezApGj"
+            + "qYUCfX1bcpPzUMzUlBaD5rz2vPeO58CDtBJ0ZXN0ZXIgPHRlc3RAdGVzdD6I"
+            + "sgQTAQIAHAUCQFdQ0wIbAwQLBwMCAxUCAwMWAgECHgECF4AACgkQs8JyyQfH"
+            + "97I1QgP8Cd+35maM2cbWV9iVRO+c5456KDi3oIUSNdPf1NQrCAtJqEUhmMSt"
+            + "QbdiaFEkPrORISI/2htXruYn0aIpkCfbUheHOu0sef7s6pHmI2kOQPzR+C/j"
+            + "8D9QvWsPOOso81KU2axUY8zIer64Uzqc4szMIlLw06c8vea27RfgjBpSCryw"
+            + "AgAA");
+
+        private static readonly char[] pgp8Pass = "2002 Buffalo Sabres".ToCharArray();
+
+        private static readonly char[] pass = "hello world".ToCharArray();
+
+        private static readonly byte[] fingerprintKey = Base64.Decode(
+              "mQEPA0CiJdUAAAEIAMI+znDlPd2kQoEcnxqxLcRz56Z7ttFKHpnYp0UkljZdquVc"
+            + "By1jMfXGVV64xN1IvMcyenLXUE0IUeUBCQs6tHunFRAPSeCxJ3FdFe1B5MpqQG8A"
+            + "BnEpAds/hAUfRDZD5y/lolk1hjvFMrRh6WXckaA/QQ2t00NmTrJ1pYUpkw9tnVQb"
+            + "LUjWJhfZDBBcN0ADtATzgkugxMtcDxR6I5x8Ndn+IilqIm23kxGIcmMd/BHOec4c"
+            + "jRwJXXDb7u8tl+2knAf9cwhPHp3+Zy4uGSQPdzQnXOhBlA+4WDa0RROOevWgq8uq"
+            + "8/9Xp/OlTVL+OoIzjsI6mJP1Joa4qmqAnaHAmXcAEQEAAbQoQk9BM1JTS1kgPEJP"
+            + "QSBNb25pdG9yaW5nIEAgODg4LTI2OS01MjY2PokBFQMFEECiJdWqaoCdocCZdwEB"
+            + "0RsH/3HPxoUZ3G3K7T3jgOnJUckTSHWU3XspHzMVgqOxjTrcexi5IsAM5M+BulfW"
+            + "T2aO+Kqf5w8cKTKgW02DNpHUiPjHx0nzDE+Do95zbIErGeK+Twkc4O/aVsvU9GGO"
+            + "81VFI6WMvDQ4CUAUnAdk03MRrzI2nAuhn4NJ5LQS+uJrnqUJ4HmFAz6CQZQKd/kS"
+            + "Xgq+A6i7aI1LG80YxWa9ooQgaCrb9dwY/kPQ+yC22zQ3FExtv+Fv3VtAKTilO3vn"
+            + "BA4Y9uTHuObHfI+1yxUS2PrlRUX0m48ZjpIX+cEN3QblGBJudI/A1QSd6P0LZeBr"
+            + "7F1Z1aF7ZDo0KzgiAIBvgXkeTpw=");
+
+//		private static readonly byte[] fingerprintCheck = Base64.Decode("CTv2");
+
+        private static readonly byte[] jpegImage = Base64.Decode(
+              "/9j/4AAQSkZJRgABAQEASABIAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD/2wBDAAUDBAQEAwUE"
+            + "BAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/"
+            + "wAALCAA6AFABASIA/8QAHAAAAgMAAwEAAAAAAAAAAAAABQcABAYBAggD/8QAMRAAAgEDBAEDAwME"
+            + "AQUAAAAAAQIDBAURAAYSITEHIkETFFEjYXEVMkKRCCUzQ4Gh/9oACAEBAAA/APX1TdKCmlaOoqoo"
+            + "WXzzbiP9nWaS71lXuA2tqrgopBOxpyGyWLAEEd4GAf3+fOjLPXoVaOcNzYAhl8HskADwAPz37f3z"
+            + "opSvI9Mjypwcr7l/B1XuFwSmoTVooljB9xDYAH51Vor191F9dKGb6Py3yo4huwcHwf8AYP7ZLIyu"
+            + "gZSGBGQQejrnU1NKn1EqVi3sZJOBCwxxIp9xzksfb5PR+Mdga+ljqIKje1TNBBNToYYgU4477HwQ"
+            + "Bn9z8/nW6mqxLR0NzpJkMLx8lJUkOGAIx4I/0f41lJ93UkkrRxVKvNKVjZfpSe6RyqhCp7wCSD89"
+            + "EEDRWppEkgqKdYohGcoZAjAlSMMcZ+PHH/3odsG6VLW2qaoqV+nTyFZpHOFQL0Sc9ADGTnHWtZap"
+            + "EpoamJm/TgYkfgJ5H/zGuKieVJIGkqCgmfCJFFy64s3Z+Oh58fHyNfGavipIJ2BrZcKXA+mzEd9Y"
+            + "OCcHI/gDV62SzvBGKhQHaNWzj8jvP750oN/xM3qkshLPEstOhj7IVyvkY+f7Nd7hf9vbc9QbVb7n"
+            + "dadLldqc00FMCwlmZnCrgL2v/cAySPBPwSD+/wC+3HbWx3rLbaqW81CVHOWnetMZjRm9h7VvClcj"
+            + "oDB7PymPTvem+a6roxvC10sd3ScmlucdEyUtRADxdice9wY3PQGRgj4OnHU3u5RW+op6imo4q+KA"
+            + "1UKGQ/bzrnt0biWxkgFOJK9ZyCCVX6f3T1Rh9RawbltdQNv18CGe2wxBDQyvGrowIJd15HEnHvP+"
+            + "OBjXoGzS0tNTpQipFTIw48Xn5SSBVUMw5e5wMgZ/j86yVNvvZ9TeDR1c9XSV0bl443dmYZXiCSCR"
+            + "jvxkjR1L1b46iWpStpIRLOWkCqyniP8AJjxPIniBjr+etFdu11DVu321WZiFHRjZcA/gsO+seNYf"
+            + "fVpq6n1Eo5KNATIYmb5Bx7csP4z/AKz8aX1N6Q7W3FuWWrS1TRzi+tXSutUESQhCGiVAvJVRgfcc"
+            + "HkeidM6tSmTbps9RHIH4KoqC8j/VC8R0+CSScZLdknPZGgNfYpUUUzfewxxcWpopWbhL715KgBIQ"
+            + "MCQc4A84+dD963X7ywQ0NIVW60qqzkzIfoszAMGUNyUHORkDrHxo3sSaOhtX2hnp3uNRF9b7hqtO"
+            + "DxM3Rcj3dMCPHXLGfOkLuPddp9R/ViOa62KppqK3Vctvsz0UylKtWfgXy3+L8WIZFBGRhs407rTT"
+            + "bcuFDRWmtsNGIZ1MMEU9GPqRorKPcJEzhich8Anz350Wk2zs2OsT7D7RZJpChMEk0MoypJZWVwM9"
+            + "ZzjWw2lbKaioFjQy/U9shLyu7Esi5JLEnsgnQlaSqhqayWSRZ5JaiSSNPoBCiq54jPuJyA2W+QfA"
+            + "+FrSXq4bdulZHRpWRzpArPK0SSNUExh14qB4c5X9ipz41Zud0juVouVooHN6rrZKVaoek/VhYgqE"
+            + "4v7cZPTfPHwT7tZX0e2NVUV5rK2ku9TeY6aFZJ6GuLALKzNnizE4CsqHIyBxJCk4AYFNt2wSUExm"
+            + "pP1lqgq1zkfXUtIgkiOFHQCsCM/kfOtZU7GsNZU1FFc1lrqCSNSlFOQ8SJk8kC4/tJx1rMwbWt0V"
+            + "CW21VW+krVoFTCRrPC0bf+NF8ocqMcT/AIg6EVF5/p9U6zPXLVFGpoKlSpMiEkniSCcqVY+eQIPW"
+            + "NULf/UNxJNS0dhklu8SK9Lco6pUcEr0JOu1HQ7z+R5OndaI5leWV0VQ54kA5KlWIx/Gqd2t6vcqe"
+            + "FIXNJMs71SoCMsQuG5jsN8AAjyTnrGlt6mVlqswtS0SG71NTXpSiCQFpogckll6Y4wvyD/OToVd7"
+            + "3tLedda4Nr3iRK2mqJhW1K0qxSSGJf1OTOAwwVADLkA9fPV2W77msVfPTClNRUyJCla0SqS5dR5J"
+            + "b2kluKlQc5BbHnWu2xTS0G4qmjvSq6RwrPHJUMHkkYDhzJHXIhmBAHnxpaL6j3il3D6g1VLuSz1k"
+            + "1ht//S6SZQ4KoTI6MyMOb9hR85HedM/0wqn3RsC0bhgq/pQV9J9WELEFaNWGARg+04xkd95xjQTe"
+            + "df6c7U+ysl3mtMFJe5JYGkkmAVKgKZCZGzlVbBySemA/OgvpZUQxvaqitgoqSsiX6XKh5RwVCBP0"
+            + "8KCTIoU8VJyDjIA8Bs2e5CprDTR8VXi8pRgyyZMh8qQMDHz850ZOlVv30RsW5blcL5S3a626+1cq"
+            + "TirFQ0qJIgAQCNjgIMeFKn9wQCMA3o2vprca/ctp29Jv6/3aoZ4IRRx08dC5D8nWQv7FJYHByeuv"
+            + "zo5SWn1Z2ttahutFZqbcG6JK5ZLu1TNEzzUq5ASNyVw6pxUMc5Oc5znR6KyXffldUVW4rBcbAqos"
+            + "EUq1qrUzUkwy8bFB+m4ZI2IBbAJAbOdau0+nmybJYqe027atvNHTRlYomhVz+Tln8knyScn50j/+"
+            + "SOyd3VO2oDtmPcNPYqJgDt23xKtOIiTy6gYO/Z5YOcAHGsJ/x39NgbzuDc+0bNt6/wAySmltbXGv"
+            + "flaT8ST07xBjIR30RjsL+dex9uwT/wBKo6i5UtPFdHp4/u/pgECTiOQDYBIByB+w0RVEVmZUUM39"
+            + "xA7P867ampqampqaq09BQwV9RWwUVNFU1AUTTJEoeQLnHJgMnGTjP51a1Nf/2Q==");
+
+        private static readonly byte[] embeddedJPEGKey = Base64.Decode(
+              "mI0ER0JXuwEEAKNqsXwLU6gu6P2Q/HJqEJVt3A7Kp1yucn8HWVeJF9JLAKVjVU8jrvz9Bw4NwaRJ"
+            + "NGYEAgdRq8Hx3WP9FXFCIVfCdi+oQrphcHWzzBFul8sykUGT+LmcBdqQGU9WaWSJyCOmUht4j7t0"
+            + "zk/IXX0YxGmkqR+no5rTj9LMDG8AQQrFABEBAAG0P0VyaWMgSCBFY2hpZG5hIChpbWFnZSB0ZXN0"
+            + "IGtleSkgPGVyaWMuZWNoaWRuYUBib3VuY3ljYXN0bGUub3JnPoi2BBMBAgAgBQJHQle7AhsDBgsJ"
+            + "CAcDAgQVAggDBBYCAwECHgECF4AACgkQ1+RWqFFpjMTKtgP+Okqkn0gVpQyNYXM/hWX6f3UQcyXk"
+            + "2Sd/fWW0XG+LBjhhBo+lXRWK0uYF8OMdZwsSl9HimpgYD5/kNs0Seh417DioP1diOgxkgezyQgMa"
+            + "+ODZfNnIvVaBr1pHLPLeqIBxBVMWBfa4wDXnLLGu8018uvI2yBhz5vByB1ntxwgKMXCwAgAD0cf3"
+            + "x/UBEAABAQAAAAAAAAAAAAAAAP/Y/+AAEEpGSUYAAQEBAEgASAAA/+EAFkV4aWYAAE1NACoAAAAI"
+            + "AAAAAAAA/9sAQwAFAwQEBAMFBAQEBQUFBgcMCAcHBwcPCwsJDBEPEhIRDxERExYcFxMUGhURERgh"
+            + "GBodHR8fHxMXIiQiHiQcHh8e/8AACwgAOgBQAQEiAP/EABwAAAIDAAMBAAAAAAAAAAAAAAUHAAQG"
+            + "AQIIA//EADEQAAIBAwQBAwMDBAEFAAAAAAECAwQFEQAGEiExByJBExRRI2FxFTJCkQglM0OBof/a"
+            + "AAgBAQAAPwD19U3SgppWjqKqKFl8824j/Z1mku9ZV7gNraq4KKQTsachsliwBBHeBgH9/nzoyz16"
+            + "FWjnDc2AIZfB7JAA8AD89+3986KUryPTI8qcHK+5fwdV7hcEpqE1aKJYwfcQ2AB+dVaK9fdRfXSh"
+            + "m+j8t8qOIbsHB8H/AGD+2SyMroGUhgRkEHo651NTSp9RKlYt7GSTgQsMcSKfcc5LH2+T0fjHYGvp"
+            + "Y6iCo3tUzQQTU6GGIFOOO+x8EAZ/c/P51upqsS0dDc6SZDC8fJSVJDhgCMeCP9H+NZSfd1JJK0cV"
+            + "SrzSlY2X6UnukcqoQqe8Akg/PRBA0VqaRJIKinWKIRnKGQIwJUjDHGfjxx/96HbBulS1tqmqKlfp"
+            + "08hWaRzhUC9EnPQAxk5x1rWWqRKaGpiZv04GJH4CeR/8xrionlSSBpKgoJnwiRRcuuLN2fjoefHx"
+            + "8jXxmr4qSCdga2XClwPpsxHfWDgnByP4A1etks7wRioUB2jVs4/I7z++dKDf8TN6pLISzxLLToY+"
+            + "yFcr5GPn+zXe4X/b23PUG1W+53WnS5XanNNBTAsJZmZwq4C9r/3AMkjwT8Eg/v8Avtx21sd6y22q"
+            + "lvNQlRzlp3rTGY0ZvYe1bwpXI6Awez8pj073pvmuq6MbwtdLHd0nJpbnHRMlLUQA8XYnHvcGNz0B"
+            + "kYI+Dpx1N7uUVvqKeopqOKvigNVChkP28657dG4lsZIBTiSvWcgglV+n909UYfUWsG5bXUDb9fAh"
+            + "ntsMQQ0Mrxq6MCCXdeRxJx7z/jgY16Bs0tLTU6UIqRUyMOPF5+UkgVVDMOXucDIGf4/OslTb72fU"
+            + "3g0dXPV0ldG5eON3ZmGV4gkgkY78ZI0dS9W+OolqUraSESzlpAqsp4j/ACY8TyJ4gY6/nrRXbtdQ"
+            + "1bt9tVmYhR0Y2XAP4LDvrHjWH31aaup9RKOSjQEyGJm+Qce3LD+M/wCs/Gl9TekO1txbllq0tU0c"
+            + "4vrV0rrVBEkIQholQLyVUYH3HB5HonTOrUpk26bPURyB+CqKgvI/1QvEdPgkknGS3ZJz2RoDX2KV"
+            + "FFM33sMcXFqaKVm4S+9eSoASEDAkHOAPOPnQ/et1+8sENDSFVutKqs5MyH6LMwDBlDclBzkZA6x8"
+            + "aN7EmjobV9oZ6d7jURfW+4arTg8TN0XI93TAjx1yxnzpC7j3XafUf1Yjmutiqaait1XLb7M9FMpS"
+            + "rVn4F8t/i/FiGRQRkYbONO60023LhQ0VprbDRiGdTDBFPRj6kaKyj3CRM4YnIfAJ89+dFpNs7Njr"
+            + "E+w+0WSaQoTBJNDKMqSWVlcDPWc41sNpWymoqBY0Mv1PbIS8ruxLIuSSxJ7IJ0JWkqoamslkkWeS"
+            + "WokkjT6AQoqueIz7icgNlvkHwPha0l6uG3bpWR0aVkc6QKzytEkjVBMYdeKgeHOV/Yqc+NWbndI7"
+            + "laLlaKBzeq62SlWqHpP1YWIKhOL+3GT03zx8E+7WV9HtjVVFeaytpLvU3mOmhWSehriwCyszZ4sx"
+            + "OArKhyMgcSQpOAGBTbdsElBMZqT9ZaoKtc5H11LSIJIjhR0ArAjP5HzrWVOxrDWVNRRXNZa6gkjU"
+            + "pRTkPEiZPJAuP7ScdazMG1rdFQlttVVvpK1aBUwkazwtG3/jRfKHKjHE/wCIOhFRef6fVOsz1y1R"
+            + "RqaCpUqTIhJJ4kgnKlWPnkCD1jVC3/1DcSTUtHYZJbvEivS3KOqVHBK9CTrtR0O8/keTp3WiOZXl"
+            + "ldFUOeJAOSpViMfxqndrer3KnhSFzSTLO9UqAjLELhuY7DfAAI8k56xpbeplZarMLUtEhu9TU16U"
+            + "ogkBaaIHJJZemOML8g/zk6FXe97S3nXWuDa94kStpqiYVtStKsUkhiX9TkzgMMFQAy5APXz1dlu+"
+            + "5rFXz0wpTUVMiQpWtEqkuXUeSW9pJbipUHOQWx51rtsU0tBuKpo70qukcKzxyVDB5JGA4cyR1yIZ"
+            + "gQB58aWi+o94pdw+oNVS7ks9ZNYbf/0ukmUOCqEyOjMjDm/YUfOR3nTP9MKp90bAtG4YKv6UFfSf"
+            + "VhCxBWjVhgEYPtOMZHfecY0E3nX+nO1PsrJd5rTBSXuSWBpJJgFSoCmQmRs5VWwcknpgPzoL6WVE"
+            + "Mb2qorYKKkrIl+lyoeUcFQgT9PCgkyKFPFScg4yAPAbNnuQqaw00fFV4vKUYMsmTIfKkDAx8/OdG"
+            + "TpVb99EbFuW5XC+Ut2utuvtXKk4qxUNKiSIAEAjY4CDHhSp/cEAjAN6Nr6a3Gv3LadvSb+v92qGe"
+            + "CEUcdPHQuQ/J1kL+xSWBwcnrr86OUlp9WdrbWobrRWam3BuiSuWS7tUzRM81KuQEjclcOqcVDHOT"
+            + "nOc50eisl335XVFVuKwXGwKqLBFKtaq1M1JMMvGxQfpuGSNiAWwCQGznWrtPp5smyWKntNu2rbzR"
+            + "00ZWKJoVc/k5Z/JJ8knJ+dI//kjsnd1TtqA7Zj3DT2KiYA7dt8SrTiIk8uoGDv2eWDnABxrCf8d/"
+            + "TYG87g3PtGzbev8AMkppbW1xr35Wk/Ek9O8QYyEd9EY7C/nXsfbsE/8ASqOouVLTxXR6eP7v6YBA"
+            + "k4jkA2ASAcgfsNEVRFZmVFDN/cQOz/Ou2pqampqamqtPQUMFfUVsFFTRVNQFE0yRKHkC5xyYDJxk"
+            + "4z+dWtTX/9mItgQTAQIAIAUCR0JYkAIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJENfkVqhR"
+            + "aYzEAPYD/iHdLOAE8r8HHF3F4z28vtIT8iiRB9aPC/YH0xqV1qeEKG8+VosBaQAOCEquONtRWsww"
+            + "gO3XB0d6VAq2kMOKc2YiB4ZtZcFvvmP9KdmVIZxVjpa9ozjP5j9zFso1HOpFcsn/VDBEqy5TvsNx"
+            + "Qvmtc8X7lqK/zLRVkSSBItik2IIhsAIAAw==");
+
+        private void FingerPrintTest()
+        {
+            //
+            // version 3
+            //
+            PgpPublicKeyRing pgpPub = new PgpPublicKeyRing(fingerprintKey);
+
+            PgpPublicKey pubKey = pgpPub.GetPublicKey();
+
+            if (!Arrays.AreEqual(pubKey.GetFingerprint(), Hex.Decode("4FFB9F0884266C715D1CEAC804A3BBFA")))
+            {
+                Fail("version 3 fingerprint test failed");
+            }
+
+            //
+            // version 4
+            //
+            pgpPub = new PgpPublicKeyRing(testPubKey);
+
+            pubKey = pgpPub.GetPublicKey();
+
+            if (!Arrays.AreEqual(pubKey.GetFingerprint(), Hex.Decode("3062363c1046a01a751946bb35586146fdf3f373")))
+            {
+               Fail("version 4 fingerprint test failed");
+            }
+        }
+
+        private void MixedTest(
+            PgpPrivateKey	pgpPrivKey,
+            PgpPublicKey	pgpPubKey)
+        {
+            byte[] text = Encoding.ASCII.GetBytes("hello world!\n");
+
+            //
+            // literal data
+            //
+            MemoryStream bOut = new MemoryStream();
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+            Stream lOut = lGen.Open(
+                bOut,
+                PgpLiteralData.Binary,
+                PgpLiteralData.Console,
+                text.Length,
+                DateTime.UtcNow);
+
+            lOut.Write(text, 0, text.Length);
+
+            lGen.Close();
+
+            byte[] bytes = bOut.ToArray();
+
+            PgpObjectFactory f = new PgpObjectFactory(bytes);
+            CheckLiteralData((PgpLiteralData)f.NextPgpObject(), text);
+
+            MemoryStream bcOut = new MemoryStream();
+
+            PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(
+                SymmetricKeyAlgorithmTag.Aes128,
+                true,
+                new SecureRandom());
+
+            encGen.AddMethod(pgpPubKey);
+
+            encGen.AddMethod("password".ToCharArray());
+
+            Stream cOut = encGen.Open(bcOut, bytes.Length);
+
+            cOut.Write(bytes, 0, bytes.Length);
+
+            cOut.Close();
+
+            byte[] encData = bcOut.ToArray();
+
+            //
+            // asymmetric
+            //
+            PgpObjectFactory pgpF = new PgpObjectFactory(encData);
+
+            PgpEncryptedDataList encList = (PgpEncryptedDataList) pgpF.NextPgpObject();
+
+            PgpPublicKeyEncryptedData  encP = (PgpPublicKeyEncryptedData)encList[0];
+
+            Stream clear = encP.GetDataStream(pgpPrivKey);
+
+            PgpObjectFactory pgpFact = new PgpObjectFactory(clear);
+
+            CheckLiteralData((PgpLiteralData)pgpFact.NextPgpObject(), text);
+
+            //
+            // PBE
+            //
+            pgpF = new PgpObjectFactory(encData);
+
+            encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+            PgpPbeEncryptedData encPbe = (PgpPbeEncryptedData) encList[1];
+
+            clear = encPbe.GetDataStream("password".ToCharArray());
+
+            pgpF = new PgpObjectFactory(clear);
+
+            CheckLiteralData((PgpLiteralData) pgpF.NextPgpObject(), text);
+        }
+
+        private void CheckLiteralData(
+            PgpLiteralData	ld,
+            byte[]			data)
+        {
+            if (!ld.FileName.Equals(PgpLiteralData.Console))
+                throw new Exception("wrong filename in packet");
+
+            Stream inLd = ld.GetDataStream();
+            byte[] bytes = Streams.ReadAll(inLd);
+
+            if (!AreEqual(bytes, data))
+            {
+                Fail("wrong plain text in decrypted packet");
+            }
+        }
+
+        private void ExistingEmbeddedJpegTest()
+        {
+            PgpPublicKeyRing pgpPub = new PgpPublicKeyRing(embeddedJPEGKey);
+
+            PgpPublicKey pubKey = pgpPub.GetPublicKey();
+
+            int count = 0;
+            foreach (PgpUserAttributeSubpacketVector attributes in pubKey.GetUserAttributes())
+            {
+                int sigCount = 0;
+                foreach (PgpSignature sig in pubKey.GetSignaturesForUserAttribute(attributes))
+                {
+                    sig.InitVerify(pubKey);
+
+                    if (!sig.VerifyCertification(attributes, pubKey))
+                    {
+                        Fail("signature failed verification");
+                    }
+
+                    sigCount++;
+                }
+
+                if (sigCount != 1)
+                {
+                    Fail("Failed user attributes signature check");
+                }
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("didn't find user attributes");
+            }
+        }
+
+        private void EmbeddedJpegTest()
+        {
+            PgpPublicKeyRing pgpPub = new PgpPublicKeyRing(testPubKey);
+            PgpSecretKeyRing pgpSec = new PgpSecretKeyRing(testPrivKey);
+
+            PgpPublicKey pubKey = pgpPub.GetPublicKey();
+
+            PgpUserAttributeSubpacketVectorGenerator vGen = new PgpUserAttributeSubpacketVectorGenerator();
+
+            vGen.SetImageAttribute(ImageAttrib.Format.Jpeg, jpegImage);
+
+            PgpUserAttributeSubpacketVector uVec = vGen.Generate();
+
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(
+                PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.PositiveCertification, pgpSec.GetSecretKey().ExtractPrivateKey(pass));
+
+            PgpSignature sig = sGen.GenerateCertification(uVec, pubKey);
+
+            PgpPublicKey nKey = PgpPublicKey.AddCertification(pubKey, uVec, sig);
+
+            int count = 0;
+            foreach (PgpUserAttributeSubpacketVector attributes in nKey.GetUserAttributes())
+            {
+                int sigCount = 0;
+                foreach (PgpSignature s in nKey.GetSignaturesForUserAttribute(attributes))
+                {
+                    s.InitVerify(pubKey);
+
+                    if (!s.VerifyCertification(attributes, pubKey))
+                    {
+                        Fail("added signature failed verification");
+                    }
+
+                    sigCount++;
+                }
+
+                if (sigCount != 1)
+                {
+                    Fail("Failed added user attributes signature check");
+                }
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("didn't find added user attributes");
+            }
+
+            nKey = PgpPublicKey.RemoveCertification(nKey, uVec);
+
+            if (nKey.GetUserAttributes().GetEnumerator().MoveNext())
+            {
+                Fail("found attributes where none expected");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            //
+            // Read the public key
+            //
+            PgpPublicKeyRing pgpPub = new PgpPublicKeyRing(testPubKey);
+
+            AsymmetricKeyParameter pubKey = pgpPub.GetPublicKey().GetKey();
+
+            IEnumerator enumerator = pgpPub.GetPublicKey().GetUserIds().GetEnumerator();
+            enumerator.MoveNext();
+            string uid = (string) enumerator.Current;
+
+
+            enumerator = pgpPub.GetPublicKey().GetSignaturesForId(uid).GetEnumerator();
+            enumerator.MoveNext();
+            PgpSignature sig = (PgpSignature) enumerator.Current;
+
+            sig.InitVerify(pgpPub.GetPublicKey());
+
+            if (!sig.VerifyCertification(uid, pgpPub.GetPublicKey()))
+            {
+                Fail("failed to verify certification");
+            }
+
+            //
+            // write a public key
+            //
+            MemoryStream bOut = new UncloseableMemoryStream();
+            BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+            pgpPub.Encode(pOut);
+
+            if (!Arrays.AreEqual(bOut.ToArray(), testPubKey))
+            {
+                Fail("public key rewrite failed");
+            }
+
+            //
+            // Read the public key
+            //
+            PgpPublicKeyRing pgpPubV3 = new PgpPublicKeyRing(testPubKeyV3);
+            AsymmetricKeyParameter pubKeyV3 = pgpPub.GetPublicKey().GetKey();
+
+            //
+            // write a V3 public key
+            //
+            bOut = new UncloseableMemoryStream();
+            pOut = new BcpgOutputStream(bOut);
+
+            pgpPubV3.Encode(pOut);
+
+            //
+            // Read a v3 private key
+            //
+            char[] passP = "FIXCITY_QA".ToCharArray();
+
+            {
+                PgpSecretKeyRing pgpPriv2 = new PgpSecretKeyRing(testPrivKeyV3);
+                PgpSecretKey pgpPrivSecretKey = pgpPriv2.GetSecretKey();
+                PgpPrivateKey pgpPrivKey2 = pgpPrivSecretKey.ExtractPrivateKey(passP);
+
+                //
+                // write a v3 private key
+                //
+                bOut = new UncloseableMemoryStream();
+                pOut = new BcpgOutputStream(bOut);
+
+                pgpPriv2.Encode(pOut);
+
+                byte[] result = bOut.ToArray();
+                if (!Arrays.AreEqual(result, testPrivKeyV3))
+                {
+                    Fail("private key V3 rewrite failed");
+                }
+            }
+
+            //
+            // Read the private key
+            //
+            PgpSecretKeyRing pgpPriv = new PgpSecretKeyRing(testPrivKey);
+            PgpPrivateKey pgpPrivKey = pgpPriv.GetSecretKey().ExtractPrivateKey(pass);
+
+            //
+            // write a private key
+            //
+            bOut = new UncloseableMemoryStream();
+            pOut = new BcpgOutputStream(bOut);
+
+            pgpPriv.Encode(pOut);
+
+            if (!Arrays.AreEqual(bOut.ToArray(), testPrivKey))
+            {
+                Fail("private key rewrite failed");
+            }
+
+            //
+            // test encryption
+            //
+            IBufferedCipher c = CipherUtilities.GetCipher("RSA");
+
+//                c.Init(Cipher.ENCRYPT_MODE, pubKey);
+            c.Init(true, pubKey);
+
+            byte[] inBytes = Encoding.ASCII.GetBytes("hello world");
+            byte[] outBytes = c.DoFinal(inBytes);
+
+//                c.Init(Cipher.DECRYPT_MODE, pgpPrivKey.GetKey());
+            c.Init(false, pgpPrivKey.Key);
+
+            outBytes = c.DoFinal(outBytes);
+
+            if (!Arrays.AreEqual(inBytes, outBytes))
+            {
+                Fail("decryption failed.");
+            }
+
+            //
+            // test signature message
+            //
+            PgpObjectFactory pgpFact = new PgpObjectFactory(sig1);
+
+            PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+
+            PgpOnePassSignature ops = p1[0];
+
+            PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+
+            Stream dIn = p2.GetInputStream();
+
+            ops.InitVerify(pgpPub.GetPublicKey(ops.KeyId));
+
+            int ch;
+            while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte)ch);
+            }
+
+            PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+
+            if (!ops.Verify(p3[0]))
+            {
+                Fail("Failed signature check");
+            }
+
+            //
+            // encrypted message - read subkey
+            //
+            pgpPriv = new PgpSecretKeyRing(subKey);
+
+            //
+            // encrypted message
+            //
+            byte[] text = Encoding.ASCII.GetBytes("hello world!\n");
+
+            PgpObjectFactory pgpF = new PgpObjectFactory(enc1);
+
+            PgpEncryptedDataList encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+            PgpPublicKeyEncryptedData encP = (PgpPublicKeyEncryptedData)encList[0];
+
+            pgpPrivKey = pgpPriv.GetSecretKey(encP.KeyId).ExtractPrivateKey(pass);
+
+            Stream clear = encP.GetDataStream(pgpPrivKey);
+
+            pgpFact = new PgpObjectFactory(clear);
+
+            c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            PgpLiteralData ld = (PgpLiteralData)pgpFact.NextPgpObject();
+
+            if (!ld.FileName.Equals("test.txt"))
+            {
+                throw new Exception("wrong filename in packet");
+            }
+
+            Stream inLd = ld.GetDataStream();
+            byte[] bytes = Streams.ReadAll(inLd);
+
+            if (!Arrays.AreEqual(bytes, text))
+            {
+                Fail("wrong plain text in decrypted packet");
+            }
+
+            //
+            // encrypt - short message
+            //
+            byte[] shortText = { (byte)'h', (byte)'e', (byte)'l', (byte)'l', (byte)'o' };
+
+            MemoryStream cbOut = new UncloseableMemoryStream();
+            PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, new SecureRandom());
+            PgpPublicKey puK = pgpPriv.GetSecretKey(encP.KeyId).PublicKey;
+
+            cPk.AddMethod(puK);
+
+            Stream cOut = cPk.Open(new UncloseableStream(cbOut), shortText.Length);
+
+            cOut.Write(shortText, 0, shortText.Length);
+
+            cOut.Close();
+
+            pgpF = new PgpObjectFactory(cbOut.ToArray());
+
+            encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+            encP = (PgpPublicKeyEncryptedData)encList[0];
+
+            pgpPrivKey = pgpPriv.GetSecretKey(encP.KeyId).ExtractPrivateKey(pass);
+
+            if (encP.GetSymmetricAlgorithm(pgpPrivKey) != SymmetricKeyAlgorithmTag.Cast5)
+            {
+                Fail("symmetric algorithm mismatch");
+            }
+
+            clear = encP.GetDataStream(pgpPrivKey);
+            outBytes = Streams.ReadAll(clear);
+
+            if (!Arrays.AreEqual(outBytes, shortText))
+            {
+                Fail("wrong plain text in generated short text packet");
+            }
+
+            //
+            // encrypt
+            //
+            cbOut = new UncloseableMemoryStream();
+            cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, new SecureRandom());
+            puK = pgpPriv.GetSecretKey(encP.KeyId).PublicKey;
+
+            cPk.AddMethod(puK);
+
+            cOut = cPk.Open(new UncloseableStream(cbOut), text.Length);
+
+            cOut.Write(text, 0, text.Length);
+
+            cOut.Close();
+
+            pgpF = new PgpObjectFactory(cbOut.ToArray());
+
+            encList = (PgpEncryptedDataList)pgpF.NextPgpObject();
+
+            encP = (PgpPublicKeyEncryptedData)encList[0];
+
+            pgpPrivKey = pgpPriv.GetSecretKey(encP.KeyId).ExtractPrivateKey(pass);
+
+            clear = encP.GetDataStream(pgpPrivKey);
+            outBytes = Streams.ReadAll(clear);
+
+            if (!Arrays.AreEqual(outBytes, text))
+            {
+                Fail("wrong plain text in generated packet");
+            }
+
+            //
+            // read public key with sub key.
+            //
+            pgpF = new PgpObjectFactory(subPubKey);
+            object o;
+            while ((o = pgpFact.NextPgpObject()) != null)
+            {
+                // TODO Should something be tested here?
+                // Console.WriteLine(o);
+            }
+
+            //
+            // key pair generation - CAST5 encryption
+            //
+            char[] passPhrase = "hello".ToCharArray();
+            IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            RsaKeyGenerationParameters genParam = new RsaKeyGenerationParameters(
+                BigInteger.ValueOf(0x10001), new SecureRandom(), 1024, 25);
+
+            kpg.Init(genParam);
+
+
+            AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+
+            PgpSecretKey secretKey = new PgpSecretKey(
+                PgpSignature.DefaultCertification,
+                PublicKeyAlgorithmTag.RsaGeneral,
+                kp.Public,
+                kp.Private,
+                DateTime.UtcNow,
+                "fred",
+                SymmetricKeyAlgorithmTag.Cast5,
+                passPhrase,
+                null,
+                null,
+                new SecureRandom()
+                );
+
+            PgpPublicKey key = secretKey.PublicKey;
+
+
+            enumerator = key.GetUserIds().GetEnumerator();
+            enumerator.MoveNext();
+            uid = (string) enumerator.Current;
+
+
+            enumerator = key.GetSignaturesForId(uid).GetEnumerator();
+            enumerator.MoveNext();
+            sig = (PgpSignature) enumerator.Current;
+
+            sig.InitVerify(key);
+
+            if (!sig.VerifyCertification(uid, key))
+            {
+                Fail("failed to verify certification");
+            }
+
+            pgpPrivKey = secretKey.ExtractPrivateKey(passPhrase);
+
+            key = PgpPublicKey.RemoveCertification(key, uid, sig);
+
+            if (key == null)
+            {
+                Fail("failed certification removal");
+            }
+
+            byte[] keyEnc = key.GetEncoded();
+
+            key = PgpPublicKey.AddCertification(key, uid, sig);
+
+            keyEnc = key.GetEncoded();
+
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.KeyRevocation, secretKey.ExtractPrivateKey(passPhrase));
+
+            sig = sGen.GenerateCertification(key);
+
+            key = PgpPublicKey.AddCertification(key, sig);
+
+            keyEnc = key.GetEncoded();
+
+            PgpPublicKeyRing tmpRing = new PgpPublicKeyRing(keyEnc);
+
+            key = tmpRing.GetPublicKey();
+
+            IEnumerator sgEnum = key.GetSignaturesOfType(PgpSignature.KeyRevocation).GetEnumerator();
+            sgEnum.MoveNext();
+            sig = (PgpSignature) sgEnum.Current;
+
+            sig.InitVerify(key);
+
+            if (!sig.VerifyCertification(key))
+            {
+                Fail("failed to verify revocation certification");
+            }
+
+            //
+            // use of PgpKeyPair
+            //
+            PgpKeyPair pgpKp = new PgpKeyPair(PublicKeyAlgorithmTag.RsaGeneral,
+                kp.Public, kp.Private, DateTime.UtcNow);
+
+            PgpPublicKey k1 = pgpKp.PublicKey;
+            PgpPrivateKey k2 = pgpKp.PrivateKey;
+
+            k1.GetEncoded();
+
+            MixedTest(k2, k1);
+
+            //
+            // key pair generation - AES_256 encryption.
+            //
+            kp = kpg.GenerateKeyPair();
+
+            secretKey = new PgpSecretKey(PgpSignature.DefaultCertification, PublicKeyAlgorithmTag.RsaGeneral, kp.Public, kp.Private, DateTime.UtcNow, "fred", SymmetricKeyAlgorithmTag.Aes256, passPhrase, null, null, new SecureRandom());
+
+            secretKey.ExtractPrivateKey(passPhrase);
+
+            secretKey.Encode(new UncloseableMemoryStream());
+
+            //
+            // secret key password changing.
+            //
+            const string newPass = "newPass";
+
+            secretKey = PgpSecretKey.CopyWithNewPassword(secretKey, passPhrase, newPass.ToCharArray(), secretKey.KeyEncryptionAlgorithm, new SecureRandom());
+
+            secretKey.ExtractPrivateKey(newPass.ToCharArray());
+
+            secretKey.Encode(new UncloseableMemoryStream());
+
+            key = secretKey.PublicKey;
+
+            key.Encode(new UncloseableMemoryStream());
+
+
+            enumerator = key.GetUserIds().GetEnumerator();
+            enumerator.MoveNext();
+            uid = (string) enumerator.Current;
+
+
+            enumerator = key.GetSignaturesForId(uid).GetEnumerator();
+            enumerator.MoveNext();
+            sig = (PgpSignature) enumerator.Current;
+
+            sig.InitVerify(key);
+
+            if (!sig.VerifyCertification(uid, key))
+            {
+                Fail("failed to verify certification");
+            }
+
+            pgpPrivKey = secretKey.ExtractPrivateKey(newPass.ToCharArray());
+
+            //
+            // signature generation
+            //
+            const string data = "hello world!";
+            byte[] dataBytes = Encoding.ASCII.GetBytes(data);
+
+            bOut = new UncloseableMemoryStream();
+
+            MemoryStream testIn = new MemoryStream(dataBytes, false);
+
+            sGen = new PgpSignatureGenerator(
+                PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
+
+            PgpCompressedDataGenerator cGen = new PgpCompressedDataGenerator(
+                CompressionAlgorithmTag.Zip);
+
+            BcpgOutputStream bcOut = new BcpgOutputStream(cGen.Open(new UncloseableStream(bOut)));
+
+            sGen.GenerateOnePassVersion(false).Encode(bcOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+
+            DateTime testDateTime = new DateTime(1973, 7, 27);
+            Stream lOut = lGen.Open(new UncloseableStream(bcOut), PgpLiteralData.Binary, "_CONSOLE",
+                dataBytes.Length, testDateTime);
+
+            // TODO Need a stream object to automatically call Update?
+            // (via ISigner implementation of PgpSignatureGenerator)
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte)ch);
+                sGen.Update((byte)ch);
+            }
+
+            lOut.Close();
+
+            sGen.Generate().Encode(bcOut);
+
+            bcOut.Close();
+
+            //
+            // verify generated signature
+            //
+            pgpFact = new PgpObjectFactory(bOut.ToArray());
+
+            c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+
+            ops = p1[0];
+
+            p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+            if (!p2.ModificationTime.Equals(testDateTime))
+            {
+                Fail("Modification time not preserved");
+            }
+
+            dIn = p2.GetInputStream();
+
+            ops.InitVerify(secretKey.PublicKey);
+
+            // TODO Need a stream object to automatically call Update?
+            // (via ISigner implementation of PgpSignatureGenerator)
+            while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte)ch);
+            }
+
+            p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+
+            if (!ops.Verify(p3[0]))
+            {
+                Fail("Failed generated signature check");
+            }
+
+            //
+            // signature generation - version 3
+            //
+            bOut = new UncloseableMemoryStream();
+
+            testIn = new MemoryStream(dataBytes);
+            PgpV3SignatureGenerator sGenV3 = new PgpV3SignatureGenerator(
+                PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey);
+
+            cGen = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
+
+            bcOut = new BcpgOutputStream(cGen.Open(new UncloseableStream(bOut)));
+
+            sGen.GenerateOnePassVersion(false).Encode(bcOut);
+
+            lGen = new PgpLiteralDataGenerator();
+            lOut = lGen.Open(
+                new UncloseableStream(bcOut),
+                PgpLiteralData.Binary,
+                "_CONSOLE",
+                dataBytes.Length,
+                testDateTime);
+
+            // TODO Need a stream object to automatically call Update?
+            // (via ISigner implementation of PgpSignatureGenerator)
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte) ch);
+                sGen.Update((byte)ch);
+            }
+
+            lOut.Close();
+
+            sGen.Generate().Encode(bcOut);
+
+            bcOut.Close();
+
+            //
+            // verify generated signature
+            //
+            pgpFact = new PgpObjectFactory(bOut.ToArray());
+
+            c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+
+            ops = p1[0];
+
+            p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+            if (!p2.ModificationTime.Equals(testDateTime))
+            {
+                Fail("Modification time not preserved");
+            }
+
+            dIn = p2.GetInputStream();
+
+            ops.InitVerify(secretKey.PublicKey);
+
+            // TODO Need a stream object to automatically call Update?
+            // (via ISigner implementation of PgpSignatureGenerator)
+            while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte)ch);
+            }
+
+            p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+
+            if (!ops.Verify(p3[0]))
+            {
+                Fail("Failed v3 generated signature check");
+            }
+
+            //
+            // extract PGP 8 private key
+            //
+            pgpPriv = new PgpSecretKeyRing(pgp8Key);
+
+            secretKey = pgpPriv.GetSecretKey();
+
+            pgpPrivKey = secretKey.ExtractPrivateKey(pgp8Pass);
+
+            //
+            // other sig tests
+            //
+            PerformTestSig(HashAlgorithmTag.Sha256, secretKey.PublicKey, pgpPrivKey);
+            PerformTestSig(HashAlgorithmTag.Sha384, secretKey.PublicKey, pgpPrivKey);
+            PerformTestSig(HashAlgorithmTag.Sha512, secretKey.PublicKey, pgpPrivKey);
+            FingerPrintTest();
+            ExistingEmbeddedJpegTest();
+            EmbeddedJpegTest();
+        }
+
+        private void PerformTestSig(
+            HashAlgorithmTag	hashAlgorithm,
+            PgpPublicKey		pubKey,
+            PgpPrivateKey		privKey)
+        {
+            const string data = "hello world!";
+            byte[] dataBytes = Encoding.ASCII.GetBytes(data);
+
+            MemoryStream bOut = new UncloseableMemoryStream();
+            MemoryStream testIn = new MemoryStream(dataBytes, false);
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.RsaGeneral, hashAlgorithm);
+
+            sGen.InitSign(PgpSignature.BinaryDocument, privKey);
+
+            PgpCompressedDataGenerator cGen = new PgpCompressedDataGenerator(CompressionAlgorithmTag.Zip);
+
+            BcpgOutputStream bcOut = new BcpgOutputStream(cGen.Open(new UncloseableStream(bOut)));
+
+            sGen.GenerateOnePassVersion(false).Encode(bcOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+            DateTime testDateTime = new DateTime(1973, 7, 27);
+            Stream lOut = lGen.Open(
+                new UncloseableStream(bcOut),
+                PgpLiteralData.Binary,
+                "_CONSOLE",
+                dataBytes.Length,
+                testDateTime);
+
+            // TODO Need a stream object to automatically call Update?
+            // (via ISigner implementation of PgpSignatureGenerator)
+            int ch;
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte)ch);
+                sGen.Update((byte)ch);
+            }
+
+            lOut.Close();
+
+            sGen.Generate().Encode(bcOut);
+
+            bcOut.Close();
+
+            //
+            // verify generated signature
+            //
+            PgpObjectFactory pgpFact = new PgpObjectFactory(bOut.ToArray());
+
+            PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject();
+
+            pgpFact = new PgpObjectFactory(c1.GetDataStream());
+
+            PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+
+            PgpOnePassSignature ops = p1[0];
+
+            PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+            if (!p2.ModificationTime.Equals(testDateTime))
+            {
+                Fail("Modification time not preserved");
+            }
+
+            Stream dIn = p2.GetInputStream();
+
+            ops.InitVerify(pubKey);
+
+            // TODO Need a stream object to automatically call Update?
+            // (via ISigner implementation of PgpSignatureGenerator)
+            while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte)ch);
+            }
+
+            PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+
+            if (!ops.Verify(p3[0]))
+            {
+                Fail("Failed generated signature check - " + hashAlgorithm);
+            }
+        }
+
+        private class UncloseableMemoryStream
+            : MemoryStream
+        {
+            public override void Close()
+            {
+                throw new Exception("Close() called on underlying stream");
+            }
+        }
+
+        public override string Name
+        {
+            get { return "PGPRSATest"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new PgpRsaTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PGPSignatureTest.cs b/crypto/test/src/openpgp/test/PGPSignatureTest.cs
new file mode 100644
index 000000000..0d8235307
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PGPSignatureTest.cs
@@ -0,0 +1,1045 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    [TestFixture]
+    public class PgpSignatureTest
+        : SimpleTest
+    {
+        private const int[] NO_PREFERENCES = null;
+        private static readonly int[] PREFERRED_SYMMETRIC_ALGORITHMS
+            = new int[] { (int)SymmetricKeyAlgorithmTag.Aes128, (int)SymmetricKeyAlgorithmTag.TripleDes };
+        private static readonly int[] PREFERRED_HASH_ALGORITHMS
+            = new int[] { (int)HashAlgorithmTag.Sha1, (int)HashAlgorithmTag.Sha256 };
+        private static readonly int[] PREFERRED_COMPRESSION_ALGORITHMS
+            = new int[] { (int)CompressionAlgorithmTag.ZLib };
+
+        private const int TEST_EXPIRATION_TIME = 10000;
+        private const string TEST_USER_ID = "test user id";
+        private static readonly byte[] TEST_DATA = Encoding.ASCII.GetBytes("hello world!\nhello world!\n");
+        private static readonly byte[] TEST_DATA_WITH_CRLF = Encoding.ASCII.GetBytes("hello world!\r\nhello world!\r\n");
+
+        private static readonly byte[] dsaKeyRing = Base64.Decode(
+            "lQHhBD9HBzURBACzkxRCVGJg5+Ld9DU4Xpnd4LCKgMq7YOY7Gi0EgK92gbaa6+zQ"
+            + "oQFqz1tt3QUmpz3YVkm/zLESBBtC1ACIXGggUdFMUr5I87+1Cb6vzefAtGt8N5VV"
+            + "1F/MXv1gJz4Bu6HyxL/ncfe71jsNhav0i4yAjf2etWFj53zK6R+Ojg5H6wCgpL9/"
+            + "tXVfGP8SqFvyrN/437MlFSUEAIN3V6j/MUllyrZglrtr2+RWIwRrG/ACmrF6hTug"
+            + "Ol4cQxaDYNcntXbhlTlJs9MxjTH3xxzylyirCyq7HzGJxZzSt6FTeh1DFYzhJ7Qu"
+            + "YR1xrSdA6Y0mUv0ixD5A4nPHjupQ5QCqHGeRfFD/oHzD4zqBnJp/BJ3LvQ66bERJ"
+            + "mKl5A/4uj3HoVxpb0vvyENfRqKMmGBISycY4MoH5uWfb23FffsT9r9KL6nJ4syLz"
+            + "aRR0gvcbcjkc9Z3epI7gr3jTrb4d8WPxsDbT/W1tv9bG/EHawomLcihtuUU68Uej"
+            + "6/wZot1XJqu2nQlku57+M/V2X1y26VKsipolPfja4uyBOOyvbP4DAwIDIBTxWjkC"
+            + "GGAWQO2jy9CTvLHJEoTO7moHrp1FxOVpQ8iJHyRqZzLllO26OzgohbiPYz8u9qCu"
+            + "lZ9Xn7QzRXJpYyBFY2hpZG5hIChEU0EgVGVzdCBLZXkpIDxlcmljQGJvdW5jeWNh"
+            + "c3RsZS5vcmc+iFkEExECABkFAj9HBzUECwcDAgMVAgMDFgIBAh4BAheAAAoJEM0j"
+            + "9enEyjRDAlwAnjTjjt57NKIgyym7OTCwzIU3xgFpAJ0VO5m5PfQKmGJRhaewLSZD"
+            + "4nXkHg==");
+
+        private static readonly char[] dsaPass = "hello world".ToCharArray();
+
+        private static readonly byte[] rsaKeyRing = Base64.Decode(
+              "lQIEBEBXUNMBBADScQczBibewnbCzCswc/9ut8R0fwlltBRxMW0NMdKJY2LF"
+            + "7k2COeLOCIU95loJGV6ulbpDCXEO2Jyq8/qGw1qD3SCZNXxKs3GS8Iyh9Uwd"
+            + "VL07nMMYl5NiQRsFB7wOb86+94tYWgvikVA5BRP5y3+O3GItnXnpWSJyREUy"
+            + "6WI2QQAGKf4JAwIVmnRs4jtTX2DD05zy2mepEQ8bsqVAKIx7lEwvMVNcvg4Y"
+            + "8vFLh9Mf/uNciwL4Se/ehfKQ/AT0JmBZduYMqRU2zhiBmxj4cXUQ0s36ysj7"
+            + "fyDngGocDnM3cwPxaTF1ZRBQHSLewP7dqE7M73usFSz8vwD/0xNOHFRLKbsO"
+            + "RqDlLA1Cg2Yd0wWPS0o7+qqk9ndqrjjSwMM8ftnzFGjShAdg4Ca7fFkcNePP"
+            + "/rrwIH472FuRb7RbWzwXA4+4ZBdl8D4An0dwtfvAO+jCZSrLjmSpxEOveJxY"
+            + "GduyR4IA4lemvAG51YHTHd4NXheuEqsIkn1yarwaaj47lFPnxNOElOREMdZb"
+            + "nkWQb1jfgqO24imEZgrLMkK9bJfoDnlF4k6r6hZOp5FSFvc5kJB4cVo1QJl4"
+            + "pwCSdoU6luwCggrlZhDnkGCSuQUUW45NE7Br22NGqn4/gHs0KCsWbAezApGj"
+            + "qYUCfX1bcpPzUMzUlBaD5rz2vPeO58CDtBJ0ZXN0ZXIgPHRlc3RAdGVzdD6I"
+            + "sgQTAQIAHAUCQFdQ0wIbAwQLBwMCAxUCAwMWAgECHgECF4AACgkQs8JyyQfH"
+            + "97I1QgP8Cd+35maM2cbWV9iVRO+c5456KDi3oIUSNdPf1NQrCAtJqEUhmMSt"
+            + "QbdiaFEkPrORISI/2htXruYn0aIpkCfbUheHOu0sef7s6pHmI2kOQPzR+C/j"
+            + "8D9QvWsPOOso81KU2axUY8zIer64Uzqc4szMIlLw06c8vea27RfgjBpSCryw"
+            + "AgAA");
+
+        private static readonly char[] rsaPass = "2002 Buffalo Sabres".ToCharArray();
+
+        private static readonly byte[] nullPacketsSubKeyBinding = Base64.Decode(
+            "iDYEGBECAAAAACp9AJ9PlJCrFpi+INwG7z61eku2Wg1HaQCgl33X5Egj+Kf7F9CXIWj2iFCvQDo=");
+
+        private static readonly byte[] okAttr = Base64.Decode(
+                "mQENBFOkuoMBCAC+8WcWLBZovlR5pLW4tbOoH3APia+poMEeTNkXKe8yAH0f"
+              + "ZmTQgeXFBIizd4Ka1QETbayv+C6Axt6Ipdwf+3N/lqcOqg6PEwuIX4MBrv5R"
+              + "ILMH5QyM3a3RlyXa7xES3I9t2VHiZvl15OrTZe67YNGtxlXyeawt6v/9d/a3"
+              + "M1EaUzjN4H2EfI3P/VWpMUvQkn70996UKInOyaSB0hef/QS10jshG9DdgmLM"
+              + "1/mJFRp8ynZOV4yGLnAdoEoPGG/HJZEzWfqOiwmWZOIrZIwedY1eKuMIhUGv"
+              + "LTC9u+9X0h+Y0st5eb1pf8OLvrpRpEyHMrxXfj/V3rxom4d160ifGihPABEB"
+              + "AAG0GndpdGggYXR0dHIgPGF0dHJAYXR0ci5uZXQ+iQE4BBMBAgAiBQJTpLqD"
+              + "AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBCjbg0bKVgCXJiB/wO"
+              + "6ksdrAy+zVxygFhk6Ju2vpMAOGnLl1nqBVT1mA5XiJu3rSiJmROLF2l21K0M"
+              + "BICZfz+mjIwN56RZNzZnEmXk/E2+PgADV5VTRRsjqlyoeN/NrLWuTm9FyngJ"
+              + "f96jVPysN6FzYRUB5Fuys57P+nu0RMoLGkHmQhp4L5hgNJTBy1SRnXukoIgJ"
+              + "2Ra3EBQ7dBrzuWW1ycwU5acfOoxfcVqgXkiXaxgvujFChZGWT6djbnbbzlMm"
+              + "sMKr6POKChEPWo1HJXXz1OaPsd75JA8bImgnrHhB3dHhD2wIqzQrtTxvraqz"
+              + "ZWWR2xYZPltzBSlaAdn8Hf0GGBoMhutb3tJLzbAX0cybzJkBEAABAQAAAAAA"
+              + "AAAAAAAAAP/Y/+AAEEpGSUYAAQEAAAEAAQAA/9sAQwAKBwcIBwYKCAgICwoK"
+              + "Cw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYpNCkhIjBBMTQ5Oz4+PiUuRElD"
+              + "PEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7"
+              + "Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7/8AAEQgAkAB4AwEiAAIR"
+              + "AQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIB"
+              + "AwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHw"
+              + "JDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVm"
+              + "Z2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4"
+              + "ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8B"
+              + "AAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQE"
+              + "AAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDTh"
+              + "JfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2"
+              + "d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG"
+              + "x8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A"
+              + "9moqtf30Gm2cl3cvtijGSa4a++LNlGStlZvKR0ZuBWkKU6nwomU4x3PQqK8g"
+              + "uPinrEzYhhihX86ns/Ffia/XzElJUHOV4/rW/wBUqJXlZEe2i9j1iivMP+Ex"
+              + "1q3+/KCw6gip4PiXdREC5tUkHcrwaTwlVbK4e1iekUVzmheNdO1ycWyK8U5G"
+              + "drf410QOa55RcXaSNE09ULRRRUjCiiigAooooAKKKKAOY+IblfCN1g9cA/rX"
+              + "h1fQPiXT4dU0o2dwXEcrclCARgE8ZB9K4J/AGkKeJr38ZU/+Ir0MLiIUoNSO"
+              + "erTlJ3R54v3hXpfg3UdNGmrHPMsToOc9+KrQeBdAd2SS7vkYdPnX/wCIqy3g"
+              + "fRoThb+9GP8AaQ/+yVdavRqxs2yYU5wdzH164t57+V7XHlZOCOh5rn5n5Ndr"
+              + "J4U0xBt/tC8x16p/8RTP+EK0uRQ32q9IPfzE/wDiKuGKpRSSYnSm3c5/wjP5"
+              + "XiKFywUDqScelevR6/pCR4k1S0DDqPOXI/WvPLjwdplpbtPG9zI6so2yspU5"
+              + "YDoFHrW7pOmRWpEiqVyuPlHH41xYmPgpPmibU4uKszqY9f0aZtseq2bN6eeu"
+              + "f51fVldQyMGU9CDkGueMCOpxtYe3NYWoabJJOZrWV7V1yFe1cxnH1HX8a57G"
+              + "lz0CiuFg8U6rpjql2PtkXTMgCv8Agw4/MfjXU6VrthrCH7NKRIoy8LjDr+Hp"
+              + "7jIosFzRooopDCiiigClqXKRD1c/+gtWPLFitnUfuRH/AG//AGUiqDKGFAzA"
+              + "mFzG7rGhAJJyB604XtzGGjeAuD3GR2x260t1fTJf3EChAsLKo+XOcorZP/fV"
+              + "Qm8lPXZ/3yKLCJDPIBsjUjIHUewFWoYWS2jDDBArPN1IQR8o/wCAirdvcERw"
+              + "u33ZYkdgOgLKCcfnRYBL0f8AEvmz6x/+jUqxbzyCLCKoC92NRaiMWLkHhmj/"
+              + "AB+dTWlarutdoIXI64oQETXJ25MbA9DsolCEY4zjpVswL5QXgMB1xWZMRDIy"
+              + "woJn6HnAWmIzb+GZyyIisD0Vl4Nc5I0ulXSO8zQtnMTrkGM/71dVNpufnMkm"
+              + "7Odwfmqd5CGi8tuQB0b5v51SEzf8M+Kl1QixvdqXoHysOFmA7j0PqPxHoOlr"
+              + "xm5DROrRkxvGQVZOCpHQivSPCfiEa9px80gXlvhZ1Hf0Yex/mDRKNtQTN6ii"
+              + "ioKKmoD9zGfSVf1OP61QrUuovOgZM4PBB9CDkH865PxJrVx4d057yS0inAcI"
+              + "qq5TJJ+hoAqXg/4m9/8A9dU/9FR1CRUGlan/AG7Fcal9n+z+dNjy9+/btRV6"
+              + "4GemelWiKoRHVuIf6Ha/9e0X/oC1VIrIt/FtxNGsFtoxk+zoITI1zhWKjbn7"
+              + "vt0zSYzfvJSLAIennIB+p/pWtZy4hXmuQa71fUzGhtre1jR920MXLHGMk+2T"
+              + "6da1oZb22ULM6FDwGCkHNFhGzNqCbjAmXkPGF7VJFAkEQHBNQWkMUcQIwc85"
+              + "9fepJJeOtNIVyK4bg1jXjda0LiTg1k3b9atEsxr3qai0LWDoOvQXpYiEny5x"
+              + "6oep/Dg/hT7s9ayLoZVs1VriPeQcjIorC8F37ah4Vs3kbdLCvkyexXjn3xg/"
+              + "jRWBqb1ee/FqYLpun24P+snLMPoOK9Crzb4uKQumSfwl2H44qo7iexB4JQHR"
+              + "wCMj7Q39K2roRRXTkqPLU8iuB8NFl8S6ftdgrSHIycH5T2rvb8b2uap6MS1R"
+              + "DJcWsq7YUCt65J4rA0FUCHKjh2/9CNYfjDUSkS2lskrlHDTSR/8ALPjocUaH"
+              + "4msUtVjCM0qLyqkAH8TyKSBnoELoOgFJf3VoITFcTBNy546gevtzXM6Rqd3f"
+              + "akWadyigsYw3y+gAH410O/PDZHHcU7E3LWnXED2SC2nE0ajG4HJ/GpJJeOtY"
+              + "lxYpJdxXMcssLxkE+SwXdj14qrf6jrP22SK0t4RFkFZZMYx/n8aANieXg1mX"
+              + "MnWla5lKRCSMFmB8xoz8qHHvzg1TnlzVIRTuW61l3MyQRSTuNwjXdt9T2FXZ"
+              + "3zWfcRpPG8Mn3JBtJ9PQ/nVCO7+Dl49z4f1BJG3Mt6XJ/wB5V/woqD4LwvDp"
+              + "urK45W5VT9QtFYPc1Wx6VXDfFi0M3hmG6A5trhSfoRj/AAruaz9d01dY0O80"
+              + "9v8AlvEVX2bt+uKFowZ4z4Zbd4h04/8ATRv/AEBq7+T53ufrXnXhffF4ls4J"
+              + "QVkildWB7EKwNehwnfLcD/aFXLcUThGs5bDUpYrgFWZ2dGHR1J6ip57C0voR"
+              + "HcQq6htwI+Ug4xkEVo+MJ0jksrYA+ZuMhPouMfzP6VnQyEqKqOqJejMmfSr/"
+              + "AE8NNbzC6hjG7aQVlA/kcVueFtR+12Mrpceagk4Abdt4/rUiMeOeaqS6UhuV"
+              + "ubSaWymxtdrbC+YvoR6+9FhHRPcCNGaRgiqNzFjgAVmya/pYkZftSnH8QQlT"
+              + "9D3rmdbefT4o7KO6ne3ky+yV9xBB9euO+Kw2mfruNAj0OW8t/K837TB5eM7/"
+              + "ADBjFVp3IAOQQwyCDkEexrz95W9vrirula1LYyiOQu9s2Q0YPT3GehpgdJK2"
+              + "apzt8hottQgv1k8pZEeMZIYg5GcZyKjuFkkKQxKXklYKijqSeAKdwPUvhdbe"
+              + "X4ZmutpH2y7eUZ9AAv8ANTRXSaJpqaPotnpyYP2eIKxHdv4j+JyaKwe5qi/R"
+              + "RRSGeaeJ/Dx03x7Yavbr/o967eZj+GQI38xz+dXdPffczD1cVu+Lzi0tT6Tj"
+              + "/wBBNc3oz7r5x6uKroIwPFt5BeazFbQKGa1BWSQdycfL+GP1qCCPgU3+yprC"
+              + "/ltrpcSqxOezAnhge9aMNv04rRaIh7jEiNSSFLeF55c7I1LNjrgVcjt/alu9"
+              + "O+12U1uSUEqFNyjlcjrRcVjzzVL6bU5xJIioqjCIo4Uf1NUDEfStiXTLizuH"
+              + "tboL5qc7l6OvZhTTZ+1K4WMZoSe1NFuSelbP2M9xT47As2FXJp3FYqaUptJ2"
+              + "fZu3IVwSR1r0L4f6FHqmsf2w8bC3sjhA2CGlx29duc/UisHQ/DlzreoiwtPl"
+              + "24NxPjKwL/Vj2H9K9m07T7bStPhsbOPy4IV2qO/uT6knkmoky4otUUUVBYUU"
+              + "UUAc54yP+hWv/XwB+hrntOTyNbSP+84rs9Z04ajaqu7a8bh0OMjI9a5O6gvo"
+              + "b3zjZAuDwyOMfryKaegEHjZTYva6qV8yFf3MqKMsueQw9uDmq+nPZahGJLSd"
+              + "Hz2zyKsXEOpagyC4IWOM5WNOmfUnuaxtT8NOJPtFoGt5uu6PjP4U0xNHSx2b"
+              + "jtmrC2p/u1xEOr+J9MO1sXCj++OavxeO9Tj4m0vJ9jTuI09c8NrqUavGfKuI"
+              + "/wDVyhc49iO4rnToV/A/lXCI5xkPGCFI/HvWhL491BhiLSufc1l6hrXiTVZQ"
+              + "IALaPGOFyfc0gHzadBZxGW9nSFBydxp+nafPrEii0RrOyP3rmRfncf7Cn+Z/"
+              + "Wo9K8NXEl0Lm+L3EgOQZTux9K7W0s5BgYNFwsbOg2tlpVilnYxCOMHJ7s7Hq"
+              + "xPc1sqcjNZNnbsuM1qoMLUlD6KKKACiiigBCM1E9tG55UVNRQBWNlF2UVC+m"
+              + "xP8Aw1fooAx5NDgfqg/KoG8N2p/5ZL+Vb9FAHPjw1ag/6pfyqZNBt06IPyra"
+              + "ooAzU0qJOiirCWcadBVqigBixhegp1LRQAUUUUAf/9mJATgEEwECACIFAlOk"
+              + "xL4CGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEEKNuDRspWAJhi8I"
+              + "AKhIemGlaKtuZxBA4bQcJOy/ZdGJriJuu3OQl2m6CAwxaGMncpxHFVTT6GqI"
+              + "Vu4/b4SSwYP1pI24MqAkdEudjFSi15ByogPFpUoDJC44zrO64b/mv3L5iq1C"
+              + "PY+VvgLMAdvA3Tsoj/rNYlD0fieBa9EF8BtoAkaA4X6pihNPGsVe0AxlJhQw"
+              + "eMgLXwTjllJm1iWa/fEQvv5Uk01gzayH1TIwkNAJ0E8s6Ontu2szUHjFGRNA"
+              + "llR5OJzt/loo9p53zWddFfxlCfn2w+smHyB4i+FfpQfFSMLnwew7wncHs6XE"
+              + "PevLPcW66T3w2/oMd0fC7GwhnCiebDYjl8ymF+4b0N65AQ0EU6S6gwEIAOAC"
+              + "NRzXH0dc5wwkucFdTMs1nxr16y+Kk3zF3R21OkHLHazXVC7ZP2HurTFGd5VP"
+              + "Yd+vv0CrYHCjjMu0lIeMfTlpJswvJRBxVw8vIVLpOSqxtJS+zysE8/LpKw6i"
+              + "ti51ydalhm6VYGPm+OAoAAO1pLriwR132caoye5vqxGKEUCmkaNLl8LCljyH"
+              + "kMgL5nQr+7cerTcGd2MaC8Y5vQuZBpVVBZcVt004iP3bCJu2l2RKskIoSysC"
+              + "68bqV4XLMnoVeM97VPdwdb0Y7tGXCW8YodN8ni43YOaQxfr7fHx8nyzQ5S8w"
+              + "a701GKWcQqCb0DR1ngCRAgWLzj8HDlZoofPL8d0AEQEAAYkBHwQYAQIACQUC"
+              + "U6S6gwIbDAAKCRBCjbg0bKVgCWPSB/wN9Z5ayWiox5xxouAQv4W2JZGPiqk8"
+              + "nFF5fzSgQxV4Xo63IaC1bD8411pgRlj1aWtt8pvWjEW9WWxvyPnkz0xldErb"
+              + "NRZ9482TknY0dsrbmg6jwLOlNvLhLVhWUWt+DkH20daVCADV/0p2/2OPodn+"
+              + "MYnueL5ljoJxzTO84WMz1u7qumMdX4EcLAFblelmPsGiNsnGabc148+TgYZI"
+              + "1fBucn5Xrk4fxVCuqa8QjOa37aHHT5Li/xGIDCbtCqPPIi7M7O1yq8gXLWP9"
+              + "TV7nsu99t4EiZT4zov9rCS+tgvBiFrRqsHL37PGrS27s+gMw3GR7F6BiDiqa"
+              + "0GvLdt0Lx24c"
+            );
+
+        private static readonly byte[] attrLongLength = Base64.Decode(
+                "mQENBEGz0vIBCADLb2Sb5QbOhRIzfOg3u9F338gK1XZWJG8JwXP8DSGbQEof"
+              + "0+YoT/7bA+3h1ljh3LG0m8JUEdolrxLz/8Mguu2TA2UQiMwRaRChSVvBgkCR"
+              + "Ykr97+kClNgmi+PLuUN1z4tspqdE761nRVvUl2x4XvLTJ21hU5eXGGsC+qFP"
+              + "4Efe8B5kH+FexAfnFPPzou3GjbDbYv4CYi0pyhTxmauxyJyQrQ/MQUt0RFRk"
+              + "L8qCzWCR2BmH3jM3M0Wt0oKn8C8+fWItUh5U9fzv/K9GeO/SV8+zdL4MrdqD"
+              + "stgqXNs27H+WeIgbXlUGIs0mONE6TtKZ5PXG5zFM1bz1vDdAYbY4eUWDABEB"
+              + "AAGJAhwEHwEIAAYFAlLd55oACgkQ5ppjUk3RnxANSBAAqzYF/9hu7x7wtmi7"
+              + "ScmIal6bXP14ZJaRVibMnAPEPIHAULPVa8x9QX/fGW8px5tK9YU41wigLXe6"
+              + "3eC5MOLc+wkouELsBeeA3zap51/5HhsuHq5AYtL2tigce9epYUVNV9LaZd2U"
+              + "vQOQ6RqyTMhSADN9mD0kR+Nu1+ns7Ur7qAq6UI39hFIGKPoZQ61pTrVsi8N7"
+              + "GxHoNwa1FAxm0Dm4XvyiJHPOYs0K4OnNWLKLCcSVOx453Zj3JnllRrCFLpIt"
+              + "H27jAxcbGStxWpJvlVMSylcP/x0ATjGfp+kSv2TpU2wK0W5iUtrn30W+WZp4"
+              + "+BIXL0NSi4XPksoUoM9dOTsOCPh/ntiWJBlzIdhQuxgcwymoYnaAG0ermI+R"
+              + "djB0gCj0AfMDZEOW+thFKg1kEkYrUnAISNDt+VZNUtk26tJ7PDitC9EY6IA6"
+              + "vbKeh47LmqpyK3gqQiIA/XuWhdUOr1Wv3H8qxumFjxQQh9sr72IbWFJ+tSNl"
+              + "UtrohK7N6CoJQidkj2qFsuGLcFKypAdS7Y0s0t9uOYJLwj1c+2KG0mrA2PvW"
+              + "1vng9mMN6AHIx9oRSwQc1+OV29ws2hfNB3JQnpdzBYAy8C5haUWG7E7WFg+j"
+              + "pNpeREVX0S+1ibmWDVs+trSQI8hd58j91Kc2YvwE13YigC9nlU2R853Gsox4"
+              + "oazn75iJAhwEHwEIAAYFAlMkBMIACgkQcssEwQwvQ5L2yxAAmND9w3OZsJpF"
+              + "tTAJFpfg8Bacy0Xs/+LipA1hB8vG+mvaiedcqc5KTpuFQ4bffH1swMRjXAM7"
+              + "ZP/u/6qX2LL9kjxCtwDUjDT8YcphTnRxSu5Jv3w4Rf0zWIRWHhnbswiBuGwE"
+              + "zQN8V20AYxfZ+ffkR0wymm/y8qLQ1oNynweijXHSlaG/sVmvDxkuc77n4hLi"
+              + "4UVQiSAP7dRIkcOh6QCBW4TxoZkDfxIhASFQWl1paCagO1rwyo7YY42O4c16"
+              + "+UZBMZtWTvRO2rThz1g9SxAyx8FZ7SxMv140C7VGQmdag97dA1WgBOCuLzLi"
+              + "cYT+o/bL9vpFXSI7LVflQEqauzL4fs2X8ggckoI4lkjcDe8DhiDmCoju5Lat"
+              + "Q/7DqV8T6z/Gv0sK2hqKr4ULC3By4N11WDCg6wXa72tMQoFBT1vOC+UzLHOj"
+              + "vgWBJKE7q3E7kFfq22D0ZX0BPTYy2mcrghMzvvOe74Dx495zlUJhtBfr8MC2"
+              + "uPnjsv6PjCYAaomQcvvI0o/5k8JIFi1P0pwLM5VjfujdAuCpAwQuy9AeGlz2"
+              + "TEuZZlWBZuyBqZ7JyHx5xz1aVXbY7kofqO+njyyZ+MakZRLYpBI+B/8KomQP"
+              + "pqWVARw4uPAXVTd1fjW2CTQtt7Ia6BRWMSblxTv3VWosTSgPnCXmzYEpGvCL"
+              + "bIauL8UEhzS0JVBHUCBHbG9iYWwgRGlyZWN0b3J5IFZlcmlmaWNhdGlvbiBL"
+              + "ZXmJAV4EEAECAEAFAkJRtHAHCwkIBwMCCgIZARkYbGRhcDovL2tleXNlcnZl"
+              + "ci5wZ3AuY29tBRsDAAAAAxYCAQUeAQAAAAQVCAIKABIJEJcQuJvKV618B2VH"
+              + "UEcAAQH35ggAnVHdAh2KqrvwSnPos73YdlVbeF9Lcbxs4oYPDCk6AHiDpjr2"
+              + "nxu48i1BiLea7aTEEwwAkcIa/3lCLP02NjGXq5gRnWpW/d0xtsaDDj8yYWus"
+              + "WGhEJsUlrq5Cz2KjwxNQHXRhHXEDR8vq9uzw5EjCB0u69vlwNmo8+fa17YMN"
+              + "VdXaXsmXJlJciVHazdvGoscTzZOuKDHdaJmY8nJcCydk4qsFOiGOcFm5UOKP"
+              + "nzdBh31NKglqw/xh+1nTA2z5orsY4jVFIB6sWqutIcVQYt/J78diAKFemkEO"
+              + "Qe0kU5JZrY34E8pp4BmS6mfPyr8NtHFfMOAE4m8acFeaZK1X6+uW57QpRE5S"
+              + "IEtTMSA8ZG8tbm90LXJlcGx5QGtleXNlcnZlcjEucGdwLmNvbT6JAVMEEAEC"
+              + "AD0FAkmgVoIHCwkIBwMCChkYbGRhcDovL2tleXNlcnZlci5wZ3AuY29tBRsD"
+              + "AAAAAxYCAQUeAQAAAAQVCAIKAAoJEJcQuJvKV618t6wH/1RFTp9Z7QUZFR5h"
+              + "r8eHFWhPoeTCMXF3Vikgw2mZsjN43ZyzpxrIdUwwHROQXn1BzAvOS0rGNiDs"
+              + "fOOmQFulz+Oc14xxGox2TZbdnDnXEb8ReZnimQCWYERfpRtY6GSY7uWzNjG2"
+              + "dLB1y3XfsOBG+QqTULSJSZqRYD+2IpwPlAdl6qncqRvFzGcPXPIp0RS6nvoP"
+              + "Jfe0u2sETDRAUDwivr7ZU/xCA12txELhcsvMQP0fy0CRNgN+pQ2b6iBL2x1l"
+              + "jHgSG1r3g3gQjHEk3UCTEKHq9+mFhd/Gi0RXz6i1AmrvW4pKhbtN76WrXeF+"
+              + "FXTsB09f1xKnWi4c303Ms1tIJQC0KUROUi1LUzIgPGRvLW5vdC1yZXBseUBr"
+              + "ZXlzZXJ2ZXIyLnBncC5jb20+iQFTBBABAgA9BQJJoFabBwsJCAcDAgoZGGxk"
+              + "YXA6Ly9rZXlzZXJ2ZXIucGdwLmNvbQUbAwAAAAMWAgEFHgEAAAAEFQgCCgAK"
+              + "CRCXELibyletfBwzB/41/OkBDVLgEYnGJ78rKHLtgMdRfrL8gmZn9KhMi44H"
+              + "nlFl1NAgi1yuWA2wC8DziVKIiu8YCaCVP0FFXuBK1BF8uZDRp8lZuT3Isf0/"
+              + "4DX4yuvZwY5nmtDu3qXrjZ7bZi1W2A8c9Hgc+5A30R9PtiYy5Lz2m8xZl4P6"
+              + "wDrYCQA2RLfzGC887bIPBK/tvXTRUFZfj2X1o/q4pr8z4NJTaFUl/XrseGcJ"
+              + "R2PP3S2/fU5LErqLJhlj690xofRkf9oYrUiyyb1/UbWmNJsOHSHyy8FEc9lv"
+              + "lSJIa39niSQKK6I0Mh1LheXNL7aG152KkXiH0mi6bH4EOzaTR7dfLey3o9Ph"
+              + "0cye/wAADVkBEAABAQAAAAAAAAAAAAAAAP/Y/+AAEEpGSUYAAQEAAAEAAQAA"
+              + "/9sAQwAKBwcIBwYKCAgICwoKCw4YEA4NDQ4dFRYRGCMfJSQiHyIhJis3LyYp"
+              + "NCkhIjBBMTQ5Oz4+PiUuRElDPEg3PT47/9sAQwEKCwsODQ4cEBAcOygiKDs7"
+              + "Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7"
+              + "Ozs7/8AAEQgAkAB4AwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAAB"
+              + "AgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNR"
+              + "YQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNE"
+              + "RUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeY"
+              + "mZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn"
+              + "6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkK"
+              + "C//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRC"
+              + "kaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNU"
+              + "VVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWm"
+              + "p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX2"
+              + "9/j5+v/aAAwDAQACEQMRAD8A9moqtf30Gm2cl3cvtijGSa4a++LNlGStlZvK"
+              + "R0ZuBWkKU6nwomU4x3PQqK8guPinrEzYhhihX86ns/Ffia/XzElJUHOV4/rW"
+              + "/wBUqJXlZEe2i9j1iivMP+Ex1q3+/KCw6gip4PiXdREC5tUkHcrwaTwlVbK4"
+              + "e1iekUVzmheNdO1ycWyK8U5Gdrf410QOa55RcXaSNE09ULRRRUjCiiigAooo"
+              + "oAKKKKAOY+IblfCN1g9cA/rXh1fQPiXT4dU0o2dwXEcrclCARgE8ZB9K4J/A"
+              + "GkKeJr38ZU/+Ir0MLiIUoNSOerTlJ3R54v3hXpfg3UdNGmrHPMsToOc9+KrQ"
+              + "eBdAd2SS7vkYdPnX/wCIqy3gfRoThb+9GP8AaQ/+yVdavRqxs2yYU5wdzH16"
+              + "4t57+V7XHlZOCOh5rn5n5NdrJ4U0xBt/tC8x16p/8RTP+EK0uRQ32q9IPfzE"
+              + "/wDiKuGKpRSSYnSm3c5/wjP5XiKFywUDqScelevR6/pCR4k1S0DDqPOXI/Wv"
+              + "PLjwdplpbtPG9zI6so2yspU5YDoFHrW7pOmRWpEiqVyuPlHH41xYmPgpPmib"
+              + "U4uKszqY9f0aZtseq2bN6eeuf51fVldQyMGU9CDkGueMCOpxtYe3NYWoabJJ"
+              + "OZrWV7V1yFe1cxnH1HX8a57Glz0CiuFg8U6rpjql2PtkXTMgCv8Agw4/MfjX"
+              + "U6VrthrCH7NKRIoy8LjDr+Hp7jIosFzRooopDCiiigClqXKRD1c/+gtWPLFi"
+              + "tnUfuRH/AG//AGUiqDKGFAzAmFzG7rGhAJJyB604XtzGGjeAuD3GR2x260t1"
+              + "fTJf3EChAsLKo+XOcorZP/fVQm8lPXZ/3yKLCJDPIBsjUjIHUewFWoYWS2jD"
+              + "DBArPN1IQR8o/wCAirdvcERwu33ZYkdgOgLKCcfnRYBL0f8AEvmz6x/+jUqx"
+              + "bzyCLCKoC92NRaiMWLkHhmj/AB+dTWlarutdoIXI64oQETXJ25MbA9DsolCE"
+              + "Y4zjpVswL5QXgMB1xWZMRDIywoJn6HnAWmIzb+GZyyIisD0Vl4Nc5I0ulXSO"
+              + "8zQtnMTrkGM/71dVNpufnMkm7Odwfmqd5CGi8tuQB0b5v51SEzf8M+Kl1Qix"
+              + "vdqXoHysOFmA7j0PqPxHoOlrxm5DROrRkxvGQVZOCpHQivSPCfiEa9px80gX"
+              + "lvhZ1Hf0Yex/mDRKNtQTN6iiioKKmoD9zGfSVf1OP61QrUuovOgZM4PBB9CD"
+              + "kH865PxJrVx4d057yS0inAcIqq5TJJ+hoAqXg/4m9/8A9dU/9FR1CRUGlan/"
+              + "AG7Fcal9n+z+dNjy9+/btRV64GemelWiKoRHVuIf6Ha/9e0X/oC1VIrIt/Ft"
+              + "xNGsFtoxk+zoITI1zhWKjbn7vt0zSYzfvJSLAIennIB+p/pWtZy4hXmuQa71"
+              + "fUzGhtre1jR920MXLHGMk+2T6da1oZb22ULM6FDwGCkHNFhGzNqCbjAmXkPG"
+              + "F7VJFAkEQHBNQWkMUcQIwc859fepJJeOtNIVyK4bg1jXjda0LiTg1k3b9atE"
+              + "sxr3qai0LWDoOvQXpYiEny5x6oep/Dg/hT7s9ayLoZVs1VriPeQcjIorC8F3"
+              + "7ah4Vs3kbdLCvkyexXjn3xg/jRWBqb1ee/FqYLpun24P+snLMPoOK9Crzb4u"
+              + "KQumSfwl2H44qo7iexB4JQHRwCMj7Q39K2roRRXTkqPLU8iuB8NFl8S6ftdg"
+              + "rSHIycH5T2rvb8b2uap6MS1RDJcWsq7YUCt65J4rA0FUCHKjh2/9CNYfjDUS"
+              + "kS2lskrlHDTSR/8ALPjocUaH4msUtVjCM0qLyqkAH8TyKSBnoELoOgFJf3Vo"
+              + "ITFcTBNy546gevtzXM6Rqd3fakWadyigsYw3y+gAH410O/PDZHHcU7E3LWnX"
+              + "ED2SC2nE0ajG4HJ/GpJJeOtYlxYpJdxXMcssLxkE+SwXdj14qrf6jrP22SK0"
+              + "t4RFkFZZMYx/n8aANieXg1mXMnWla5lKRCSMFmB8xoz8qHHvzg1TnlzVIRTu"
+              + "W61l3MyQRSTuNwjXdt9T2FXZ3zWfcRpPG8Mn3JBtJ9PQ/nVCO7+Dl49z4f1B"
+              + "JG3Mt6XJ/wB5V/woqD4LwvDpurK45W5VT9QtFYPc1Wx6VXDfFi0M3hmG6A5t"
+              + "rhSfoRj/AAruaz9d01dY0O809v8AlvEVX2bt+uKFowZ4z4Zbd4h04/8ATRv/"
+              + "AEBq7+T53ufrXnXhffF4ls4JQVkildWB7EKwNehwnfLcD/aFXLcUThGs5bDU"
+              + "pYrgFWZ2dGHR1J6ip57C0voRHcQq6htwI+Ug4xkEVo+MJ0jksrYA+ZuMhPou"
+              + "MfzP6VnQyEqKqOqJejMmfSr/AE8NNbzC6hjG7aQVlA/kcVueFtR+12Mrpcea"
+              + "gk4Abdt4/rUiMeOeaqS6UhuVubSaWymxtdrbC+YvoR6+9FhHRPcCNGaRgiqN"
+              + "zFjgAVmya/pYkZftSnH8QQlT9D3rmdbefT4o7KO6ne3ky+yV9xBB9euO+Kw2"
+              + "mfruNAj0OW8t/K837TB5eM7/ADBjFVp3IAOQQwyCDkEexrz95W9vrirula1L"
+              + "YyiOQu9s2Q0YPT3GehpgdJK2apzt8hottQgv1k8pZEeMZIYg5GcZyKjuFkkK"
+              + "QxKXklYKijqSeAKdwPUvhdbeX4ZmutpH2y7eUZ9AAv8ANTRXSaJpqaPotnpy"
+              + "YP2eIKxHdv4j+JyaKwe5qi/RRRSGeaeJ/Dx03x7Yavbr/o967eZj+GQI38xz"
+              + "+dXdPffczD1cVu+Lzi0tT6Tj/wBBNc3oz7r5x6uKroIwPFt5BeazFbQKGa1B"
+              + "WSQdycfL+GP1qCCPgU3+yprC/ltrpcSqxOezAnhge9aMNv04rRaIh7jEiNSS"
+              + "FLeF55c7I1LNjrgVcjt/alu9O+12U1uSUEqFNyjlcjrRcVjzzVL6bU5xJIio"
+              + "qjCIo4Uf1NUDEfStiXTLizuHtboL5qc7l6OvZhTTZ+1K4WMZoSe1NFuSelbP"
+              + "2M9xT47As2FXJp3FYqaUptJ2fZu3IVwSR1r0L4f6FHqmsf2w8bC3sjhA2CGl"
+              + "x29duc/UisHQ/DlzreoiwtPl24NxPjKwL/Vj2H9K9m07T7bStPhsbOPy4IV2"
+              + "qO/uT6knkmoky4otUUUVBYUUUUAc54yP+hWv/XwB+hrntOTyNbSP+84rs9Z0"
+              + "4ajaqu7a8bh0OMjI9a5O6gvob3zjZAuDwyOMfryKaegEHjZTYva6qV8yFf3M"
+              + "qKMsueQw9uDmq+nPZahGJLSdHz2zyKsXEOpagyC4IWOM5WNOmfUnuaxtT8NO"
+              + "JPtFoGt5uu6PjP4U0xNHSx2bjtmrC2p/u1xEOr+J9MO1sXCj++OavxeO9Tj4"
+              + "m0vJ9jTuI09c8NrqUavGfKuI/wDVyhc49iO4rnToV/A/lXCI5xkPGCFI/HvW"
+              + "hL491BhiLSufc1l6hrXiTVZQIALaPGOFyfc0gHzadBZxGW9nSFBydxp+nafP"
+              + "rEii0RrOyP3rmRfncf7Cn+Z/Wo9K8NXEl0Lm+L3EgOQZTux9K7W0s5BgYNFw"
+              + "sbOg2tlpVilnYxCOMHJ7s7HqxPc1sqcjNZNnbsuM1qoMLUlD6KKKACiiigBC"
+              + "M1E9tG55UVNRQBWNlF2UVC+mxP8Aw1fooAx5NDgfqg/KoG8N2p/5ZL+Vb9FA"
+              + "HPjw1ag/6pfyqZNBt06IPyraooAzU0qJOiirCWcadBVqigBixhegp1LRQAUU"
+              + "UUAf/9mJAVYEEAECADgFAkJRtHAHCwkIBwMCChkYbGRhcDovL2tleXNlcnZl"
+              + "ci5wZ3AuY29tBRsDAAAAAxYCAQUeAQAAAAASCRCXELibyletfAdlR1BHAAEB"
+              + "SBIH/j+RGcMuHmVoZq4+XbmCunnbft4T0Ta4o6mxNkc6wk5P9PpcE9ixztjV"
+              + "ysMmv2i4Y746dCY9B1tfhQW10S39HzrYHh3I4a2wb9zQniZCf1XnbCe1eRss"
+              + "NhTpLVXXnXKEsc9EwD5MtiPICluZIXB08Zx2uJSZ+/i9TqSM5EUuJk+lXqgX"
+              + "GUiTaSXN63I/4BnbFzCw8SaST7d7nok45UC9I/+gcKVO+oYETgrsU7AL6uk1"
+              + "6YD9JpfYZHEFmpYoS+qQ3tLfPCG3gaS/djBZWWkNt5z7e6sbRko49XEj3EUh"
+              + "33HgjrOlL8uJNbhlZ5NeILcxHqGTHji+5wMEDBjfNT/C6m0=");
+
+        public override void PerformTest()
+        {
+            //
+            // RSA tests
+            //
+            PgpSecretKeyRing pgpPriv = new PgpSecretKeyRing(rsaKeyRing);
+            PgpSecretKey secretKey = pgpPriv.GetSecretKey();
+            PgpPrivateKey pgpPrivKey = secretKey.ExtractPrivateKey(rsaPass);
+
+            try
+            {
+                doTestSig(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey);
+
+                Fail("RSA wrong key test failed.");
+            }
+            catch (PgpException)
+            {
+                // expected
+            }
+
+            try
+            {
+                doTestSigV3(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey);
+
+                Fail("RSA V3 wrong key test failed.");
+            }
+            catch (PgpException)
+            {
+                // expected
+            }
+
+            //
+            // certifications
+            //
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.KeyRevocation, pgpPrivKey);
+
+            PgpSignature sig = sGen.GenerateCertification(secretKey.PublicKey);
+
+            sig.InitVerify(secretKey.PublicKey);
+
+            if (!sig.VerifyCertification(secretKey.PublicKey))
+            {
+                Fail("revocation verification failed.");
+            }
+
+            PgpSecretKeyRing pgpDSAPriv = new PgpSecretKeyRing(dsaKeyRing);
+            PgpSecretKey secretDSAKey = pgpDSAPriv.GetSecretKey();
+            PgpPrivateKey pgpPrivDSAKey = secretDSAKey.ExtractPrivateKey(dsaPass);
+
+            sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.SubkeyBinding, pgpPrivDSAKey);
+
+            PgpSignatureSubpacketGenerator    unhashedGen = new PgpSignatureSubpacketGenerator();
+            PgpSignatureSubpacketGenerator    hashedGen = new PgpSignatureSubpacketGenerator();
+
+            hashedGen.SetSignatureExpirationTime(false, TEST_EXPIRATION_TIME);
+            hashedGen.SetSignerUserId(true, TEST_USER_ID);
+            hashedGen.SetPreferredCompressionAlgorithms(false, PREFERRED_COMPRESSION_ALGORITHMS);
+            hashedGen.SetPreferredHashAlgorithms(false, PREFERRED_HASH_ALGORITHMS);
+            hashedGen.SetPreferredSymmetricAlgorithms(false, PREFERRED_SYMMETRIC_ALGORITHMS);
+
+            sGen.SetHashedSubpackets(hashedGen.Generate());
+            sGen.SetUnhashedSubpackets(unhashedGen.Generate());
+
+            sig = sGen.GenerateCertification(secretDSAKey.PublicKey, secretKey.PublicKey);
+
+            byte[] sigBytes = sig.GetEncoded();
+
+            PgpObjectFactory f = new PgpObjectFactory(sigBytes);
+
+            sig = ((PgpSignatureList) f.NextPgpObject())[0];
+
+            sig.InitVerify(secretDSAKey.PublicKey);
+
+            if (!sig.VerifyCertification(secretDSAKey.PublicKey, secretKey.PublicKey))
+            {
+                Fail("subkey binding verification failed.");
+            }
+
+            PgpSignatureSubpacketVector hashedPcks = sig.GetHashedSubPackets();
+            PgpSignatureSubpacketVector unhashedPcks = sig.GetUnhashedSubPackets();
+
+            if (hashedPcks.Count != 6)
+            {
+                Fail("wrong number of hashed packets found.");
+            }
+
+            if (unhashedPcks.Count != 1)
+            {
+                Fail("wrong number of unhashed packets found.");
+            }
+
+            if (!hashedPcks.GetSignerUserId().Equals(TEST_USER_ID))
+            {
+                Fail("test userid not matching");
+            }
+
+            if (hashedPcks.GetSignatureExpirationTime() != TEST_EXPIRATION_TIME)
+            {
+                Fail("test signature expiration time not matching");
+            }
+
+            if (unhashedPcks.GetIssuerKeyId() != secretDSAKey.KeyId)
+            {
+                Fail("wrong issuer key ID found in certification");
+            }
+
+            int[] prefAlgs = hashedPcks.GetPreferredCompressionAlgorithms();
+            preferredAlgorithmCheck("compression", PREFERRED_COMPRESSION_ALGORITHMS, prefAlgs);
+
+            prefAlgs = hashedPcks.GetPreferredHashAlgorithms();
+            preferredAlgorithmCheck("hash", PREFERRED_HASH_ALGORITHMS, prefAlgs);
+
+            prefAlgs = hashedPcks.GetPreferredSymmetricAlgorithms();
+            preferredAlgorithmCheck("symmetric", PREFERRED_SYMMETRIC_ALGORITHMS, prefAlgs);
+
+            SignatureSubpacketTag[] criticalHashed = hashedPcks.GetCriticalTags();
+
+            if (criticalHashed.Length != 1)
+            {
+                Fail("wrong number of critical packets found.");
+            }
+
+            if (criticalHashed[0] != SignatureSubpacketTag.SignerUserId)
+            {
+                Fail("wrong critical packet found in tag list.");
+            }
+
+            //
+            // no packets passed
+            //
+            sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.SubkeyBinding, pgpPrivDSAKey);
+
+            sGen.SetHashedSubpackets(null);
+            sGen.SetUnhashedSubpackets(null);
+
+            sig = sGen.GenerateCertification(TEST_USER_ID, secretKey.PublicKey);
+
+            sig.InitVerify(secretDSAKey.PublicKey);
+
+            if (!sig.VerifyCertification(TEST_USER_ID, secretKey.PublicKey))
+            {
+                Fail("subkey binding verification failed.");
+            }
+
+            hashedPcks = sig.GetHashedSubPackets();
+
+            if (hashedPcks.Count != 1)
+            {
+                Fail("found wrong number of hashed packets");
+            }
+
+            unhashedPcks = sig.GetUnhashedSubPackets();
+
+            if (unhashedPcks.Count != 1)
+            {
+                Fail("found wrong number of unhashed packets");
+            }
+
+            try
+            {
+                sig.VerifyCertification(secretKey.PublicKey);
+
+                Fail("failed to detect non-key signature.");
+            }
+            catch (InvalidOperationException)
+            {
+                // expected
+            }
+
+            //
+            // override hash packets
+            //
+            sGen = new PgpSignatureGenerator(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1);
+
+            sGen.InitSign(PgpSignature.SubkeyBinding, pgpPrivDSAKey);
+
+            hashedGen = new PgpSignatureSubpacketGenerator();
+
+            DateTime creationTime = new DateTime(1973, 7, 27);
+            hashedGen.SetSignatureCreationTime(false, creationTime);
+
+            sGen.SetHashedSubpackets(hashedGen.Generate());
+
+            sGen.SetUnhashedSubpackets(null);
+
+            sig = sGen.GenerateCertification(TEST_USER_ID, secretKey.PublicKey);
+
+            sig.InitVerify(secretDSAKey.PublicKey);
+
+            if (!sig.VerifyCertification(TEST_USER_ID, secretKey.PublicKey))
+            {
+                Fail("subkey binding verification failed.");
+            }
+
+            hashedPcks = sig.GetHashedSubPackets();
+
+            if (hashedPcks.Count != 1)
+            {
+                Fail("found wrong number of hashed packets in override test");
+            }
+
+            if (!hashedPcks.HasSubpacket(SignatureSubpacketTag.CreationTime))
+            {
+                Fail("hasSubpacket test for creation time failed");
+            }
+
+            DateTime sigCreationTime = hashedPcks.GetSignatureCreationTime();
+            if (!sigCreationTime.Equals(creationTime))
+            {
+                Fail("creation of overridden date failed.");
+            }
+
+            prefAlgs = hashedPcks.GetPreferredCompressionAlgorithms();
+            preferredAlgorithmCheck("compression", NO_PREFERENCES, prefAlgs);
+
+            prefAlgs = hashedPcks.GetPreferredHashAlgorithms();
+            preferredAlgorithmCheck("hash", NO_PREFERENCES, prefAlgs);
+
+            prefAlgs = hashedPcks.GetPreferredSymmetricAlgorithms();
+            preferredAlgorithmCheck("symmetric", NO_PREFERENCES, prefAlgs);
+
+            if (hashedPcks.GetKeyExpirationTime() != 0)
+            {
+                Fail("unexpected key expiration time found");
+            }
+
+            if (hashedPcks.GetSignatureExpirationTime() != 0)
+            {
+                Fail("unexpected signature expiration time found");
+            }
+
+            if (hashedPcks.GetSignerUserId() != null)
+            {
+                Fail("unexpected signer user ID found");
+            }
+
+            criticalHashed = hashedPcks.GetCriticalTags();
+
+            if (criticalHashed.Length != 0)
+            {
+                Fail("critical packets found when none expected");
+            }
+
+            unhashedPcks = sig.GetUnhashedSubPackets();
+
+            if (unhashedPcks.Count != 1)
+            {
+                Fail("found wrong number of unhashed packets in override test");
+            }
+
+            //
+            // general signatures
+            //
+            doTestSig(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha256, secretKey.PublicKey, pgpPrivKey);
+            doTestSig(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha384, secretKey.PublicKey, pgpPrivKey);
+            doTestSig(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha512, secretKey.PublicKey, pgpPrivKey);
+            doTestSigV3(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey);
+            doTestTextSig(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF);
+            doTestTextSig(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF);
+            doTestTextSigV3(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF);
+            doTestTextSigV3(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF);
+
+            //
+            // DSA Tests
+            //
+            pgpPriv = new PgpSecretKeyRing(dsaKeyRing);
+            secretKey = pgpPriv.GetSecretKey();
+            pgpPrivKey = secretKey.ExtractPrivateKey(dsaPass);
+
+            try
+            {
+                doTestSig(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey);
+
+                Fail("DSA wrong key test failed.");
+            }
+            catch (PgpException)
+            {
+                // expected
+            }
+
+            try
+            {
+                doTestSigV3(PublicKeyAlgorithmTag.RsaGeneral, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey);
+
+                Fail("DSA V3 wrong key test failed.");
+            }
+            catch (PgpException)
+            {
+                // expected
+            }
+
+            doTestSig(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey);
+            doTestSigV3(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey);
+            doTestTextSig(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF);
+            doTestTextSig(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF);
+            doTestTextSigV3(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA_WITH_CRLF, TEST_DATA_WITH_CRLF);
+            doTestTextSigV3(PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1, secretKey.PublicKey, pgpPrivKey, TEST_DATA, TEST_DATA_WITH_CRLF);
+
+            // special cases
+            //
+            doTestMissingSubpackets(nullPacketsSubKeyBinding);
+
+            doTestMissingSubpackets(generateV3BinarySig(pgpPrivKey, PublicKeyAlgorithmTag.Dsa, HashAlgorithmTag.Sha1));
+
+            // keyflags
+            doTestKeyFlagsValues();
+
+            // TODO Seems to depend on some other functionality that's yet to be ported
+            //doTestUserAttributeEncoding();
+        }
+
+        //private void doTestUserAttributeEncoding()
+        //{
+        //    PgpPublicKeyRing pkr = new PgpPublicKeyRing(okAttr);
+
+        //    CheckUserAttribute("normal", pkr, pkr.GetPublicKey());
+
+        //    pkr = new PgpPublicKeyRing(attrLongLength);
+
+        //    CheckUserAttribute("long", pkr, pkr.GetPublicKey());
+        //}
+
+        //private void CheckUserAttribute(String type, PgpPublicKeyRing pkr, PgpPublicKey masterPk)
+        //{
+        //    foreach (PgpUserAttributeSubpacketVector attr in pkr.GetPublicKey().GetUserAttributes())
+        //    {
+        //        foreach (PgpSignature sig in masterPk.GetSignaturesForUserAttribute(attr))
+        //        {
+        //            sig.InitVerify(masterPk);
+        //            if (!sig.VerifyCertification(attr, masterPk))
+        //            {
+        //                Fail("user attribute sig failed to verify on " + type);
+        //            }
+        //        }
+        //    }
+        //}
+
+        private void doTestKeyFlagsValues()
+        {
+            checkValue(KeyFlags.CertifyOther, 0x01);
+            checkValue(KeyFlags.SignData, 0x02);
+            checkValue(KeyFlags.EncryptComms, 0x04);
+            checkValue(KeyFlags.EncryptStorage, 0x08);
+            checkValue(KeyFlags.Split, 0x10);
+            checkValue(KeyFlags.Authentication, 0x20);
+            checkValue(KeyFlags.Shared, 0x80);
+
+            // yes this actually happens
+            checkValue(new byte[] { 4, 0, 0, 0 }, 0x04);
+            checkValue(new byte[] { 4, 0, 0 }, 0x04);
+            checkValue(new byte[] { 4, 0 }, 0x04);
+            checkValue(new byte[] { 4 }, 0x04);
+        }
+
+        private void checkValue(int flag, int val)
+        {
+            KeyFlags f = new KeyFlags(true, flag);
+
+            if (f.Flags != val)
+            {
+                Fail("flag value mismatch");
+            }
+        }
+
+        private void checkValue(byte[] flag, int val)
+        {
+            KeyFlags f = new KeyFlags(true, flag);
+
+            if (f.Flags != val)
+            {
+                Fail("flag value mismatch");
+            }
+        }
+
+        private void doTestMissingSubpackets(byte[] signature)
+        {
+            PgpObjectFactory f = new PgpObjectFactory(signature);
+            object obj = f.NextPgpObject();
+
+            while (!(obj is PgpSignatureList))
+            {
+                obj = f.NextPgpObject();
+                if (obj is PgpLiteralData)
+                {
+                    Stream input = ((PgpLiteralData)obj).GetDataStream();
+                    Streams.Drain(input);
+                }
+            }
+
+            PgpSignature sig = ((PgpSignatureList)obj)[0];
+
+            if (sig.Version > 3)
+            {
+                PgpSignatureSubpacketVector v = sig.GetHashedSubPackets();
+
+                if (v.GetKeyExpirationTime() != 0)
+                {
+                    Fail("key expiration time not zero for missing subpackets");
+                }
+
+                if (!sig.HasSubpackets)
+                {
+                    Fail("HasSubpackets property was false with packets");
+                }
+            }
+            else
+            {
+                if (sig.GetHashedSubPackets() != null)
+                {
+                    Fail("hashed sub packets found when none expected");
+                }
+
+                if (sig.GetUnhashedSubPackets() != null)
+                {
+                    Fail("unhashed sub packets found when none expected");
+                }
+
+                if (sig.HasSubpackets)
+                {
+                    Fail("HasSubpackets property was true with no packets");
+                }
+            }
+        }
+
+        private void preferredAlgorithmCheck(
+            string	type,
+            int[]	expected,
+            int[]	prefAlgs)
+        {
+            if (expected == null)
+            {
+                if (prefAlgs != null)
+                {
+                    Fail("preferences for " + type + " found when none expected");
+                }
+            }
+            else
+            {
+                if (prefAlgs.Length != expected.Length)
+                {
+                    Fail("wrong number of preferred " + type + " algorithms found");
+                }
+
+                for (int i = 0; i != expected.Length; i++)
+                {
+                    if (expected[i] != prefAlgs[i])
+                    {
+                        Fail("wrong algorithm found for " + type + ": expected " + expected[i] + " got " + prefAlgs);
+                    }
+                }
+            }
+        }
+
+        private void doTestSig(
+            PublicKeyAlgorithmTag	encAlgorithm,
+            HashAlgorithmTag		hashAlgorithm,
+            PgpPublicKey			pubKey,
+            PgpPrivateKey			privKey)
+        {
+            MemoryStream bOut = new MemoryStream();
+            MemoryStream testIn = new MemoryStream(TEST_DATA, false);
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(encAlgorithm, hashAlgorithm);
+
+            sGen.InitSign(PgpSignature.BinaryDocument, privKey);
+            sGen.GenerateOnePassVersion(false).Encode(bOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+            Stream lOut = lGen.Open(
+                new UncloseableStream(bOut),
+                PgpLiteralData.Binary,
+                "_CONSOLE",
+                TEST_DATA.Length * 2,
+                DateTime.UtcNow);
+
+            int ch;
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte)ch);
+                sGen.Update((byte)ch);
+            }
+
+            lOut.Write(TEST_DATA, 0, TEST_DATA.Length);
+            sGen.Update(TEST_DATA);
+
+            lGen.Close();
+
+            sGen.Generate().Encode(bOut);
+
+            verifySignature(bOut.ToArray(), hashAlgorithm, pubKey, TEST_DATA);
+        }
+
+        private void doTestTextSig(
+            PublicKeyAlgorithmTag	encAlgorithm,
+            HashAlgorithmTag		hashAlgorithm,
+            PgpPublicKey			pubKey,
+            PgpPrivateKey			privKey,
+            byte[]					data,
+            byte[]					canonicalData)
+        {
+            PgpSignatureGenerator sGen = new PgpSignatureGenerator(encAlgorithm, HashAlgorithmTag.Sha1);
+            MemoryStream bOut = new MemoryStream();
+            MemoryStream testIn = new MemoryStream(data, false);
+            DateTime creationTime = DateTime.UtcNow;
+
+            sGen.InitSign(PgpSignature.CanonicalTextDocument, privKey);
+            sGen.GenerateOnePassVersion(false).Encode(bOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+            Stream lOut = lGen.Open(
+                new UncloseableStream(bOut),
+                PgpLiteralData.Text,
+                "_CONSOLE",
+                data.Length * 2,
+                creationTime);
+
+            int ch;
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte)ch);
+                sGen.Update((byte)ch);
+            }
+
+            lOut.Write(data, 0, data.Length);
+            sGen.Update(data);
+
+            lGen.Close();
+
+            PgpSignature sig = sGen.Generate();
+
+            if (sig.CreationTime == DateTimeUtilities.UnixMsToDateTime(0))
+            {
+                Fail("creation time not set in v4 signature");
+            }
+
+            sig.Encode(bOut);
+
+            verifySignature(bOut.ToArray(), hashAlgorithm, pubKey, canonicalData);
+        }
+
+        private void doTestSigV3(
+            PublicKeyAlgorithmTag	encAlgorithm,
+            HashAlgorithmTag		hashAlgorithm,
+            PgpPublicKey			pubKey,
+            PgpPrivateKey			privKey)
+        {
+            byte[] bytes = generateV3BinarySig(privKey, encAlgorithm, hashAlgorithm);
+
+            verifySignature(bytes, hashAlgorithm, pubKey, TEST_DATA);
+        }
+
+        private byte[] generateV3BinarySig(
+            PgpPrivateKey			privKey,
+            PublicKeyAlgorithmTag	encAlgorithm,
+            HashAlgorithmTag		hashAlgorithm)
+        {
+            MemoryStream bOut = new MemoryStream();
+            MemoryStream testIn = new MemoryStream(TEST_DATA, false);
+            PgpV3SignatureGenerator sGen = new PgpV3SignatureGenerator(encAlgorithm, hashAlgorithm);
+
+            sGen.InitSign(PgpSignature.BinaryDocument, privKey);
+            sGen.GenerateOnePassVersion(false).Encode(bOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+            Stream lOut = lGen.Open(
+                new UncloseableStream(bOut),
+                PgpLiteralData.Binary,
+                "_CONSOLE",
+                TEST_DATA.Length * 2,
+                DateTime.UtcNow);
+
+            int ch;
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte)ch);
+                sGen.Update((byte)ch);
+            }
+
+            lOut.Write(TEST_DATA, 0, TEST_DATA.Length);
+            sGen.Update(TEST_DATA);
+
+            lGen.Close();
+
+            sGen.Generate().Encode(bOut);
+
+            return bOut.ToArray();
+        }
+
+        private void doTestTextSigV3(
+            PublicKeyAlgorithmTag	encAlgorithm,
+            HashAlgorithmTag		hashAlgorithm,
+            PgpPublicKey			pubKey,
+            PgpPrivateKey			privKey,
+            byte[]					data,
+            byte[]					canonicalData)
+        {
+            PgpV3SignatureGenerator sGen = new PgpV3SignatureGenerator(encAlgorithm, HashAlgorithmTag.Sha1);
+            MemoryStream bOut = new MemoryStream();
+            MemoryStream testIn = new MemoryStream(data, false);
+
+            sGen.InitSign(PgpSignature.CanonicalTextDocument, privKey);
+            sGen.GenerateOnePassVersion(false).Encode(bOut);
+
+            PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator();
+            Stream lOut = lGen.Open(
+                new UncloseableStream(bOut),
+                PgpLiteralData.Text,
+                "_CONSOLE",
+                data.Length * 2,
+                DateTime.UtcNow);
+
+            int ch;
+            while ((ch = testIn.ReadByte()) >= 0)
+            {
+                lOut.WriteByte((byte)ch);
+                sGen.Update((byte)ch);
+            }
+
+            lOut.Write(data, 0, data.Length);
+            sGen.Update(data);
+
+            lGen.Close();
+
+            PgpSignature sig = sGen.Generate();
+
+            if (sig.CreationTime == DateTimeUtilities.UnixMsToDateTime(0))
+            {
+                Fail("creation time not set in v3 signature");
+            }
+
+            sig.Encode(bOut);
+
+            verifySignature(bOut.ToArray(), hashAlgorithm, pubKey, canonicalData);
+        }
+
+        private void verifySignature(
+            byte[] encodedSig,
+            HashAlgorithmTag hashAlgorithm,
+            PgpPublicKey pubKey,
+            byte[] original)
+        {
+            PgpObjectFactory        pgpFact = new PgpObjectFactory(encodedSig);
+            PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject();
+            PgpOnePassSignature     ops = p1[0];
+            PgpLiteralData          p2 = (PgpLiteralData)pgpFact.NextPgpObject();
+            Stream					dIn = p2.GetInputStream();
+
+            ops.InitVerify(pubKey);
+
+            int ch;
+            while ((ch = dIn.ReadByte()) >= 0)
+            {
+                ops.Update((byte)ch);
+            }
+
+            PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject();
+            PgpSignature sig = p3[0];
+
+            DateTime creationTime = sig.CreationTime;
+
+            // Check creationTime is recent
+            if (creationTime.CompareTo(DateTime.UtcNow) > 0
+                || creationTime.CompareTo(DateTime.UtcNow.AddMinutes(-10)) < 0)
+            {
+                Fail("bad creation time in signature: " + creationTime);
+            }
+
+            if (sig.KeyId != pubKey.KeyId)
+            {
+                Fail("key id mismatch in signature");
+            }
+
+            if (!ops.Verify(sig))
+            {
+                Fail("Failed generated signature check - " + hashAlgorithm);
+            }
+
+            sig.InitVerify(pubKey);
+
+            for (int i = 0; i != original.Length; i++)
+            {
+                sig.Update(original[i]);
+            }
+
+            sig.Update(original);
+
+            if (!sig.Verify())
+            {
+                Fail("Failed generated signature check against original data");
+            }
+        }
+
+        public override string Name
+        {
+            get { return "PGPSignatureTest"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new PgpSignatureTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PgpKeyRingTest.cs b/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
new file mode 100644
index 000000000..2ac2f0c97
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
@@ -0,0 +1,2161 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    [TestFixture]
+    public class PgpKeyRingTest
+        : SimpleTest
+    {
+        private static readonly byte[] pub1 = Base64.Decode(
+            "mQGiBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn"
+            + "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg"
+            + "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf"
+            + "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ"
+            + "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G"
+            + "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ"
+            + "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG"
+            + "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP"
+            + "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif"
+            + "IIeLOTI5Dc4XKeV32a+bWrQidGVzdCAoVGVzdCBrZXkpIDx0ZXN0QHViaWNh"
+            + "bGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB4TOABgsJCAcDAgMVAgMDFgIB"
+            + "Ah4BAheAAAoJEJh8Njfhe8KmGDcAoJWr8xgPr75y/Cp1kKn12oCCOb8zAJ4p"
+            + "xSvk4K6tB2jYbdeSrmoWBZLdMLACAAC5AQ0EQDzfARAEAJeUAPvUzJJbKcc5"
+            + "5Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj47UPAD/tQxwz8VAwJySx82ggN"
+            + "LxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j2BVqZAaX3q79a3eMiql1T0oE"
+            + "AGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOHAAQNBACD0mVMlAUgd7REYy/1"
+            + "mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWaHz6CN1XptdwpDeSYEOFZ0PSu"
+            + "qH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85efMBA9jUv/DeBOzRWMFG6sC6y"
+            + "k8NGG7Swea7EHKeQI40G3jgO/+xANtMyTIhPBBgRAgAPBQJAPN8BAhsMBQkB"
+            + "4TOAAAoJEJh8Njfhe8KmG7kAn00mTPGJCWqmskmzgdzeky5fWd7rAKCNCp3u"
+            + "ZJhfg0htdgAfIy8ppm05vLACAAA=");
+
+        private static readonly byte[] sec1 = Base64.Decode(
+            "lQHhBEA83v0RBADzKVLVCnpWQxX0LCsevw/3OLs0H7MOcLBQ4wMO9sYmzGYn"
+            + "xpVj+4e4PiCP7QBayWyy4lugL6Lnw7tESvq3A4v3fefcxaCTkJrryiKn4+Cg"
+            + "y5rIBbrSKNtCEhVi7xjtdnDjP5kFKgHYjVOeIKn4Cz/yzPG3qz75kDknldLf"
+            + "yHxp2wCgwW1vAE5EnZU4/UmY7l8kTNkMltMEAJP4/uY4zcRwLI9Q2raPqAOJ"
+            + "TYLd7h+3k/BxI0gIw96niQ3KmUZDlobbWBI+VHM6H99vcttKU3BgevNf8M9G"
+            + "x/AbtW3SS4De64wNSU3189XDG8vXf0vuyW/K6Pcrb8exJWY0E1zZQ1WXT0gZ"
+            + "W0kH3g5ro//Tusuil9q2lVLF2ovJA/0W+57bPzi318dWeNs0tTq6Njbc/GTG"
+            + "FUAVJ8Ss5v2u6h7gyJ1DB334ExF/UdqZGldp0ugkEXaSwBa2R7d3HBgaYcoP"
+            + "Ck1TrovZzEY8gm7JNVy7GW6mdOZuDOHTxyADEEP2JPxh6eRcZbzhGuJuYIif"
+            + "IIeLOTI5Dc4XKeV32a+bWv4CAwJ5KgazImo+sGBfMhDiBcBTqyDGhKHNgHic"
+            + "0Pky9FeRvfXTc2AO+jGmFPjcs8BnTWuDD0/jkQnRZpp1TrQidGVzdCAoVGVz"
+            + "dCBrZXkpIDx0ZXN0QHViaWNhbGwuY29tPohkBBMRAgAkBQJAPN79AhsDBQkB"
+            + "4TOABgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEJh8Njfhe8KmGDcAn3XeXDMg"
+            + "BZgrZzFWU2IKtA/5LG2TAJ0Vf/jjyq0jZNZfGfoqGTvD2MAl0rACAACdAVgE"
+            + "QDzfARAEAJeUAPvUzJJbKcc55Iyb13+Gfb8xBWE3HinQzhGr1v6A1aIZbRj4"
+            + "7UPAD/tQxwz8VAwJySx82ggNLxCk4jW9YtTL3uZqfczsJngV25GoIN10f4/j"
+            + "2BVqZAaX3q79a3eMiql1T0oEAGmD7tO1LkTvWfm3VvA0+t8/6ZeRLEiIqAOH"
+            + "AAQNBACD0mVMlAUgd7REYy/1mL99Zlu9XU0uKyUex99sJNrcx1aj8rIiZtWa"
+            + "Hz6CN1XptdwpDeSYEOFZ0PSuqH9ByM3OfjU/ya0//xdvhwYXupn6P1Kep85e"
+            + "fMBA9jUv/DeBOzRWMFG6sC6yk8NGG7Swea7EHKeQI40G3jgO/+xANtMyTP4C"
+            + "AwJ5KgazImo+sGBl2C7CFuI+5KM4ZhbtVie7l+OiTpr5JW2z5VgnV3EX9p04"
+            + "LcGKfQvD65+ELwli6yh8B2zGcipqTaYk3QoYNIhPBBgRAgAPBQJAPN8BAhsM"
+            + "BQkB4TOAAAoJEJh8Njfhe8KmG7kAniuRkaFFv1pdCBN8JJXpcorHmyouAJ9L"
+            + "xxmusffR6OI7WgD3XZ0AL8zUC7ACAAA=");
+
+//		private static readonly char[] pass1 = "qwertzuiop".ToCharArray();
+
+        private static readonly byte[] pub2 = Base64.Decode(
+            "mQGiBEBtfW8RBADfWjTxFedIbGBNVgh064D/OCf6ul7x4PGsCl+BkAyheYkr"
+            + "mVUsChmBKoeXaY+Fb85wwusXzyM/6JFK58Rg+vEb3Z19pue8Ixxq7cRtCtOA"
+            + "tOP1eKXLNtTRWJutvLkQmeOa19UZ6ziIq23aWuWKSq+KKMWek2GUnGycnx5M"
+            + "W0pn1QCg/39r9RKhY9cdKYqRcqsr9b2B/AsD/Ru24Q15Jmrsl9zZ6EC47J49"
+            + "iNW5sLQx1qf/mgfVWQTmU2j6gq4ND1OuK7+0OP/1yMOUpkjjcqxFgTnDAAoM"
+            + "hHDTzCv/aZzIzmMvgLsYU3aIMfbz+ojpuASMCMh+te01cEMjiPWwDtdWWOdS"
+            + "OSyX9ylzhO3PiNDks8R83onsacYpA/9WhTcg4bvkjaj66I7wGZkm3BmTxNSb"
+            + "pE4b5HZDh31rRYhY9tmrryCfFnU4BS2Enjj5KQe9zFv7pUBCBW2oFo8i8Osn"
+            + "O6fa1wVN4fBHC6wqWmmpnkFerNPkiC9V75KUFIfeWHmT3r2DVSO3dfdHDERA"
+            + "jFIAioMLjhaX6DnODF5KQrABh7QmU2FpIFB1bGxhYmhvdGxhIDxwc2FpQG15"
+            + "amF2YXdvcmxkLmNvbT6wAwP//4kAVwQQEQIAFwUCQG19bwcLCQgHAwIKAhkB"
+            + "BRsDAAAAAAoJEKXQf/RT99uYmfAAoMKxV5g2owIfmy2w7vSLvOQUpvvOAJ4n"
+            + "jB6xJot523rPAQW9itPoGGekirABZ7kCDQRAbX1vEAgA9kJXtwh/CBdyorrW"
+            + "qULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9"
+            + "ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/"
+            + "Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4"
+            + "DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGzeMyEs"
+            + "tSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1B"
+            + "n5x8vYlLIhkmuquiXsNV6TILOwACAgf9F7/nJHDayJ3pBVTTVSq2g5WKUXMg"
+            + "xxGKTvOahiVRcbO03w0pKAkH85COakVfe56sMYpWRl36adjNoKOxaciow74D"
+            + "1R5snY/hv/kBXPBkzo4UMkbANIVaZ0IcnLp+rkkXcDVbRCibZf8FfCY1zXbq"
+            + "d680UtEgRbv1D8wFBqfMt7kLsuf9FnIw6vK4DU06z5ZDg25RHGmswaDyY6Mw"
+            + "NGCrKGbHf9I/T7MMuhGF/in8UU8hv8uREOjseOqklG3/nsI1hD/MdUC7fzXi"
+            + "MRO4RvahLoeXOuaDkMYALdJk5nmNuCL1YPpbFGttI3XsK7UrP/Fhd8ND6Nro"
+            + "wCqrN6keduK+uLABh4kATAQYEQIADAUCQG19bwUbDAAAAAAKCRCl0H/0U/fb"
+            + "mC/0AJ4r1yvyu4qfOXlDgmVuCsvHFWo63gCfRIrCB2Jv/N1cgpmq0L8LGHM7"
+            + "G/KwAWeZAQ0EQG19owEIAMnavLYqR7ffaDPbbq+lQZvLCK/3uA0QlyngNyTa"
+            + "sDW0WC1/ryy2dx7ypOOCicjnPYfg3LP5TkYAGoMjxH5+xzM6xfOR+8/EwK1z"
+            + "N3A5+X/PSBDlYjQ9dEVKrvvc7iMOp+1K1VMf4Ug8Yah22Ot4eLGP0HRCXiv5"
+            + "vgdBNsAl/uXnBJuDYQmLrEniqq/6UxJHKHxZoS/5p13Cq7NfKB1CJCuJXaCE"
+            + "TW2do+cDpN6r0ltkF/r+ES+2L7jxyoHcvQ4YorJoDMlAN6xpIZQ8dNaTYP/n"
+            + "Mx/pDS3shUzbU+UYPQrreJLMF1pD+YWP5MTKaZTo+U/qPjDFGcadInhPxvh3"
+            + "1ssAEQEAAbABh7QuU2FuZGh5YSBQdWxsYWJob3RsYSA8cHNhbmRoeWFAbXlq"
+            + "YXZhd29ybGQuY29tPrADA///iQEtBBABAgAXBQJAbX2jBwsJCAcDAgoCGQEF"
+            + "GwMAAAAACgkQx87DL9gOvoeVUwgAkQXYiF0CxhKbDnuabAssnOEwJrutgCRO"
+            + "CJRQvIwTe3fe6hQaWn2Yowt8OQtNFiR8GfAY6EYxyFLKzZbAI/qtq5fHmN3e"
+            + "RSyNWe6d6e17hqZZL7kf2sVkyGTChHj7Jiuo7vWkdqT2MJN6BW5tS9CRH7Me"
+            + "D839STv+4mAAO9auGvSvicP6UEQikAyCy/ihoJxLQlspfbSNpi0vrUjCPT7N"
+            + "tWwfP0qF64i9LYkjzLqihnu+UareqOPhXcWnyFKrjmg4ezQkweNU2pdvCLbc"
+            + "W24FhT92ivHgpLyWTswXcqjhFjVlRr0+2sIz7v1k0budCsJ7PjzOoH0hJxCv"
+            + "sJQMlZR/e7ABZ7kBDQRAbX2kAQgAm5j+/LO2M4pKm/VUPkYuj3eefHkzjM6n"
+            + "KbvRZX1Oqyf+6CJTxQskUWKAtkzzKafPdS5Wg0CMqeXov+EFod4bPEYccszn"
+            + "cKd1U8NRwacbEpCvvvB84Yl2YwdWpDpkryyyLI4PbCHkeuwx9Dc2z7t4XDB6"
+            + "FyAJTMAkia7nzYa/kbeUO3c2snDb/dU7uyCsyKtTZyTyhTgtl/f9L03Bgh95"
+            + "y3mOUz0PimJ0Sg4ANczF4d04BpWkjLNVJi489ifWodPlHm1hag5drYekYpWJ"
+            + "+3g0uxs5AwayV9BcOkPKb1uU3EoYQw+nn0Kn314Nvx2M1tKYunuVNLEm0PhA"
+            + "/+B8PTq8BQARAQABsAGHiQEiBBgBAgAMBQJAbX2kBRsMAAAAAAoJEMfOwy/Y"
+            + "Dr6HkLoH/RBY8lvUv1r8IdTs5/fN8e/MnGeThLl+JrlYF/4t3tjXYIf5xUj/"
+            + "c9NdjreKYgHfMtrbVM08LlxUVQlkjuF3DIk5bVH9Blq8aXmyiwiM5GrCry+z"
+            + "WiqkpZze1G577C38mMJbHDwbqNCLALMzo+W2q04Avl5sniNnDNGbGz9EjhRg"
+            + "o7oS16KkkD6Ls4RnHTEZ0vyZOXodDHu+sk/2kzj8K07kKaM8rvR7aDKiI7HH"
+            + "1GxJz70fn1gkKuV2iAIIiU25bty+S3wr+5h030YBsUZF1qeKCdGOmpK7e9Of"
+            + "yv9U7rf6Z5l8q+akjqLZvej9RnxeH2Um7W+tGg2me482J+z6WOawAWc=");
+
+        private static readonly byte[] sec2 = Base64.Decode(
+            "lQHpBEBtfW8RBADfWjTxFedIbGBNVgh064D/OCf6ul7x4PGsCl+BkAyheYkr"
+            + "mVUsChmBKoeXaY+Fb85wwusXzyM/6JFK58Rg+vEb3Z19pue8Ixxq7cRtCtOA"
+            + "tOP1eKXLNtTRWJutvLkQmeOa19UZ6ziIq23aWuWKSq+KKMWek2GUnGycnx5M"
+            + "W0pn1QCg/39r9RKhY9cdKYqRcqsr9b2B/AsD/Ru24Q15Jmrsl9zZ6EC47J49"
+            + "iNW5sLQx1qf/mgfVWQTmU2j6gq4ND1OuK7+0OP/1yMOUpkjjcqxFgTnDAAoM"
+            + "hHDTzCv/aZzIzmMvgLsYU3aIMfbz+ojpuASMCMh+te01cEMjiPWwDtdWWOdS"
+            + "OSyX9ylzhO3PiNDks8R83onsacYpA/9WhTcg4bvkjaj66I7wGZkm3BmTxNSb"
+            + "pE4b5HZDh31rRYhY9tmrryCfFnU4BS2Enjj5KQe9zFv7pUBCBW2oFo8i8Osn"
+            + "O6fa1wVN4fBHC6wqWmmpnkFerNPkiC9V75KUFIfeWHmT3r2DVSO3dfdHDERA"
+            + "jFIAioMLjhaX6DnODF5KQv4JAwIJH6A/rzqmMGAG4e+b8Whdvp8jaTGVT4CG"
+            + "M1b65rbiDyAuf5KTFymQBOIi9towgFzG9NXAZC07nEYSukN56tUTUDNVsAGH"
+            + "tCZTYWkgUHVsbGFiaG90bGEgPHBzYWlAbXlqYXZhd29ybGQuY29tPrADA///"
+            + "iQBXBBARAgAXBQJAbX1vBwsJCAcDAgoCGQEFGwMAAAAACgkQpdB/9FP325iZ"
+            + "8ACgwrFXmDajAh+bLbDu9Iu85BSm+84AnieMHrEmi3nbes8BBb2K0+gYZ6SK"
+            + "sAFnnQJqBEBtfW8QCAD2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoB"
+            + "p1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3b"
+            + "zpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa"
+            + "8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPw"
+            + "pVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obE"
+            + "AxnIByl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7"
+            + "AAICB/0Xv+ckcNrInekFVNNVKraDlYpRcyDHEYpO85qGJVFxs7TfDSkoCQfz"
+            + "kI5qRV97nqwxilZGXfpp2M2go7FpyKjDvgPVHmydj+G/+QFc8GTOjhQyRsA0"
+            + "hVpnQhycun6uSRdwNVtEKJtl/wV8JjXNdup3rzRS0SBFu/UPzAUGp8y3uQuy"
+            + "5/0WcjDq8rgNTTrPlkODblEcaazBoPJjozA0YKsoZsd/0j9Pswy6EYX+KfxR"
+            + "TyG/y5EQ6Ox46qSUbf+ewjWEP8x1QLt/NeIxE7hG9qEuh5c65oOQxgAt0mTm"
+            + "eY24IvVg+lsUa20jdewrtSs/8WF3w0Po2ujAKqs3qR524r64/gkDAmmp39NN"
+            + "U2pqYHokufIOab2VpD7iQo8UjHZNwR6dpjyky9dVfIe4MA0H+t0ju8UDdWoe"
+            + "IkRu8guWsI83mjGPbIq8lmsZOXPCA8hPuBmL0iaj8TnuotmsBjIBsAGHiQBM"
+            + "BBgRAgAMBQJAbX1vBRsMAAAAAAoJEKXQf/RT99uYL/QAnivXK/K7ip85eUOC"
+            + "ZW4Ky8cVajreAJ9EisIHYm/83VyCmarQvwsYczsb8rABZ5UDqARAbX2jAQgA"
+            + "ydq8tipHt99oM9tur6VBm8sIr/e4DRCXKeA3JNqwNbRYLX+vLLZ3HvKk44KJ"
+            + "yOc9h+Dcs/lORgAagyPEfn7HMzrF85H7z8TArXM3cDn5f89IEOViND10RUqu"
+            + "+9zuIw6n7UrVUx/hSDxhqHbY63h4sY/QdEJeK/m+B0E2wCX+5ecEm4NhCYus"
+            + "SeKqr/pTEkcofFmhL/mnXcKrs18oHUIkK4ldoIRNbZ2j5wOk3qvSW2QX+v4R"
+            + "L7YvuPHKgdy9DhiismgMyUA3rGkhlDx01pNg/+czH+kNLeyFTNtT5Rg9Cut4"
+            + "kswXWkP5hY/kxMpplOj5T+o+MMUZxp0ieE/G+HfWywARAQABCWEWL2cKQKcm"
+            + "XFTNsWgRoOcOkKyJ/osERh2PzNWvOF6/ir1BMRsg0qhd+hEcoWHaT+7Vt12i"
+            + "5Y2Ogm2HFrVrS5/DlV/rw0mkALp/3cR6jLOPyhmq7QGwhG27Iy++pLIksXQa"
+            + "RTboa7ZasEWw8zTqa4w17M5Ebm8dtB9Mwl/kqU9cnIYnFXj38BWeia3iFBNG"
+            + "PD00hqwhPUCTUAcH9qQPSqKqnFJVPe0KQWpq78zhCh1zPUIa27CE86xRBf45"
+            + "XbJwN+LmjCuQEnSNlloXJSPTRjEpla+gWAZz90fb0uVIR1dMMRFxsuaO6aCF"
+            + "QMN2Mu1wR/xzTzNCiQf8cVzq7YkkJD8ChJvu/4BtWp3BlU9dehAz43mbMhaw"
+            + "Qx3NmhKR/2dv1cJy/5VmRuljuzC+MRtuIjJ+ChoTa9ubNjsT6BF5McRAnVzf"
+            + "raZK+KVWCGA8VEZwe/K6ouYLsBr6+ekCKIkGZdM29927m9HjdFwEFjnzQlWO"
+            + "NZCeYgDcK22v7CzobKjdo2wdC7XIOUVCzMWMl+ch1guO/Y4KVuslfeQG5X1i"
+            + "PJqV+bwJriCx5/j3eE/aezK/vtZU6cchifmvefKvaNL34tY0Myz2bOx44tl8"
+            + "qNcGZbkYF7xrNCutzI63xa2ruN1p3hNxicZV1FJSOje6+ITXkU5Jmufto7IJ"
+            + "t/4Q2dQefBQ1x/d0EdX31yK6+1z9dF/k3HpcSMb5cAWa2u2g4duAmREHc3Jz"
+            + "lHCsNgyzt5mkb6kS43B6og8Mm2SOx78dBIOA8ANzi5B6Sqk3/uN5eQFLY+sQ"
+            + "qGxXzimyfbMjyq9DdqXThx4vlp3h/GC39KxL5MPeB0oe6P3fSP3C2ZGjsn3+"
+            + "XcYk0Ti1cBwBOFOZ59WYuc61B0wlkiU/WGeaebABh7QuU2FuZGh5YSBQdWxs"
+            + "YWJob3RsYSA8cHNhbmRoeWFAbXlqYXZhd29ybGQuY29tPrADA///iQEtBBAB"
+            + "AgAXBQJAbX2jBwsJCAcDAgoCGQEFGwMAAAAACgkQx87DL9gOvoeVUwgAkQXY"
+            + "iF0CxhKbDnuabAssnOEwJrutgCROCJRQvIwTe3fe6hQaWn2Yowt8OQtNFiR8"
+            + "GfAY6EYxyFLKzZbAI/qtq5fHmN3eRSyNWe6d6e17hqZZL7kf2sVkyGTChHj7"
+            + "Jiuo7vWkdqT2MJN6BW5tS9CRH7MeD839STv+4mAAO9auGvSvicP6UEQikAyC"
+            + "y/ihoJxLQlspfbSNpi0vrUjCPT7NtWwfP0qF64i9LYkjzLqihnu+UareqOPh"
+            + "XcWnyFKrjmg4ezQkweNU2pdvCLbcW24FhT92ivHgpLyWTswXcqjhFjVlRr0+"
+            + "2sIz7v1k0budCsJ7PjzOoH0hJxCvsJQMlZR/e7ABZ50DqARAbX2kAQgAm5j+"
+            + "/LO2M4pKm/VUPkYuj3eefHkzjM6nKbvRZX1Oqyf+6CJTxQskUWKAtkzzKafP"
+            + "dS5Wg0CMqeXov+EFod4bPEYccszncKd1U8NRwacbEpCvvvB84Yl2YwdWpDpk"
+            + "ryyyLI4PbCHkeuwx9Dc2z7t4XDB6FyAJTMAkia7nzYa/kbeUO3c2snDb/dU7"
+            + "uyCsyKtTZyTyhTgtl/f9L03Bgh95y3mOUz0PimJ0Sg4ANczF4d04BpWkjLNV"
+            + "Ji489ifWodPlHm1hag5drYekYpWJ+3g0uxs5AwayV9BcOkPKb1uU3EoYQw+n"
+            + "n0Kn314Nvx2M1tKYunuVNLEm0PhA/+B8PTq8BQARAQABCXo6bD6qi3s4U8Pp"
+            + "Uf9l3DyGuwiVPGuyb2P+sEmRFysi2AvxMe9CkF+CLCVYfZ32H3Fcr6XQ8+K8"
+            + "ZGH6bJwijtV4QRnWDZIuhUQDS7dsbGqTh4Aw81Fm0Bz9fpufViM9RPVEysxs"
+            + "CZRID+9jDrACthVsbq/xKomkKdBfNTK7XzGeZ/CBr9F4EPlnBWClURi9txc0"
+            + "pz9YP5ZRy4XTFgx+jCbHgKWUIz4yNaWQqpSgkHEDrGZwstXeRaaPftcfQN+s"
+            + "EO7OGl/Hd9XepGLez4vKSbT35CnqTwMzCK1IwUDUzyB4BYEFZ+p9TI18HQDW"
+            + "hA0Wmf6E8pjS16m/SDXoiRY43u1jUVZFNFzz25uLFWitfRNHCLl+VfgnetZQ"
+            + "jMFr36HGVQ65fogs3avkgvpgPwDc0z+VMj6ujTyXXgnCP/FdhzgkRFJqgmdJ"
+            + "yOlC+wFmZJEs0MX7L/VXEXdpR27XIGYm24CC7BTFKSdlmR1qqenXHmCCg4Wp"
+            + "00fV8+aAsnesgwPvxhCbZQVp4v4jqhVuB/rvsQu9t0rZnKdDnWeom/F3StYo"
+            + "A025l1rrt0wRP8YS4XlslwzZBqgdhN4urnzLH0/F3X/MfjP79Efj7Zk07vOH"
+            + "o/TPjz8lXroPTscOyXWHwtQqcMhnVsj9jvrzhZZSdUuvnT30DR7b8xcHyvAo"
+            + "WG2cnF/pNSQX11RlyyAOlw9TOEiDJ4aLbFdkUt+qZdRKeC8mEC2xsQ87HqFR"
+            + "pWKWABWaoUO0nxBEmvNOy97PkIeGVFNHDLlIeL++Ry03+JvuNNg4qAnwacbJ"
+            + "TwQzWP4vJqre7Gl/9D0tVlD4Yy6Xz3qyosxdoFpeMSKHhgKVt1bk0SQP7eXA"
+            + "C1c+eDc4gN/ZWpl+QLqdk2T9vr4wRAaK5LABh4kBIgQYAQIADAUCQG19pAUb"
+            + "DAAAAAAKCRDHzsMv2A6+h5C6B/0QWPJb1L9a/CHU7Of3zfHvzJxnk4S5fia5"
+            + "WBf+Ld7Y12CH+cVI/3PTXY63imIB3zLa21TNPC5cVFUJZI7hdwyJOW1R/QZa"
+            + "vGl5sosIjORqwq8vs1oqpKWc3tRue+wt/JjCWxw8G6jQiwCzM6PltqtOAL5e"
+            + "bJ4jZwzRmxs/RI4UYKO6EteipJA+i7OEZx0xGdL8mTl6HQx7vrJP9pM4/CtO"
+            + "5CmjPK70e2gyoiOxx9RsSc+9H59YJCrldogCCIlNuW7cvkt8K/uYdN9GAbFG"
+            + "RdanignRjpqSu3vTn8r/VO63+meZfKvmpI6i2b3o/UZ8Xh9lJu1vrRoNpnuP"
+            + "Nifs+ljmsAFn");
+
+        private static readonly char[] sec2pass1 = "sandhya".ToCharArray();
+        private static readonly char[] sec2pass2 = "psai".ToCharArray();
+
+        private static readonly byte[] pub3 = Base64.Decode(
+            "mQGiBEB9BH0RBACtYQtE7tna6hgGyGLpq+ds3r2cLC0ISn5dNw7tm9vwiNVF"
+            + "JA2N37RRrifw4PvgelRSvLaX3M3ZBqC9s1Metg3v4FSlIRtSLWCNpHSvNw7i"
+            + "X8C2Xy9Hdlbh6Y/50o+iscojLRE14upfR1bIkcCZQGSyvGV52V2wBImUUZjV"
+            + "s2ZngwCg7mu852vK7+euz4WaL7ERVYtq9CMEAJ5swrljerDpz/RQ4Lhp6KER"
+            + "KyuI0PUttO57xINGshEINgYlZdGaZHRueHe7uKfI19mb0T4N3NJWaZ0wF+Cn"
+            + "rixsq0VrTUfiwfZeGluNG73aTCeY45fVXMGTTSYXzS8T0LW100Xn/0g9HRyA"
+            + "xUpuWo8IazxkMqHJis2uwriYKpAfA/9anvj5BS9p5pfPjp9dGM7GTMIYl5f2"
+            + "fcP57f+AW1TVR6IZiMJAvAdeWuLtwLnJiFpGlnFz273pfl+sAuqm1yNceImR"
+            + "2SDDP4+vtyycWy8nZhgEuhZx3W3cWMQz5WyNJSY1JJHh9TCQkCoN8E7XpVP4"
+            + "zEPboB2GzD93mfD8JLHP+7QtVGVzdCBLZXkgKG5vIGNvbW1lbnQpIDx0ZXN0"
+            + "QGJvdW5jeWNhc3RsZS5vcmc+iFkEExECABkFAkB9BH0ECwcDAgMVAgMDFgIB"
+            + "Ah4BAheAAAoJEKnMV8vjZQOpSRQAnidAQswYkrXQAFcLBzhxQTknI9QMAKDR"
+            + "ryV3l6xuCCgHST8JlxpbjcXhlLACAAPRwXPBcQEQAAEBAAAAAAAAAAAAAAAA"
+            + "/9j/4AAQSkZJRgABAQEASABIAAD//gAXQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q"
+            + "/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAi"
+            + "LCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIy"
+            + "MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy"
+            + "MjIy/8AAEQgAFAAUAwEiAAIRAQMRAf/EABoAAQACAwEAAAAAAAAAAAAAAAAE"
+            + "BQIDBgf/xAAoEAABAgUDBAEFAAAAAAAAAAABAgMABBEhMQUSQQYTIiNhFFGB"
+            + "kcH/xAAXAQEAAwAAAAAAAAAAAAAAAAAEAgMF/8QAJBEAAQQAAwkAAAAAAAAA"
+            + "AAAAAQACERIEIfATMTJBUZGx0fH/2gAMAwEAAhEDEQA/APMuotJlJVxstqaP"
+            + "o22NlAUp+YsNO0qSUtBcMu6n6EtOHcfPAHHFI16++oajQtTA3DapK02HFR8U"
+            + "pE9pTbQWtKm2WG2rlxVyQTcfGbn7Qm0OIjL77Wrs2NNm9lzTmmSxQ0PX4opS"
+            + "prk5tmESF6syggzGwOLG6gXgHFbZhBixk8XlIDcOQLRKt+rX+3qC5ZLTQblp"
+            + "Qlvwvxn9CMpZturVGkJHapQJphRH8hCLXbzrqpYsCx1zC5rtpJNuYQhASc0U"
+            + "AQv/2YhcBBMRAgAcBQJAfQV+AhsDBAsHAwIDFQIDAxYCAQIeAQIXgAAKCRCp"
+            + "zFfL42UDqfa2AJ9hjtEeDTbTEAuuSbzhYFxN/qc0FACgsmzysdbBpuN65yK0"
+            + "1tbEaeIMtqCwAgADuM0EQH0EfhADAKpG5Y6vGbm//xZYG08RRmdi67dZjF59"
+            + "Eqfo43mRrliangB8qkqoqqf3za2OUbXcZUQ/ajDXUvjJAoY2b5XJURqmbtKk"
+            + "wPRIeD2+wnKABat8wmcFhZKATX1bqjdyRRGxawADBgMAoMJKJLELdnn885oJ"
+            + "6HDmIez++ZWTlafzfUtJkQTCRKiE0NsgSvKJr/20VdK3XUA/iy0m1nQwfzv/"
+            + "okFuIhEPgldzH7N/NyEvtN5zOv/TpAymFKewAQ26luEu6l+lH4FsiEYEGBEC"
+            + "AAYFAkB9BH4ACgkQqcxXy+NlA6mtMgCgtQMFBaKymktM+DQmCgy2qjW7WY0A"
+            + "n3FaE6UZE9GMDmCIAjhI+0X9aH6CsAIAAw==");
+
+        private static readonly byte[] sec3 = Base64.Decode(
+            "lQHhBEB9BH0RBACtYQtE7tna6hgGyGLpq+ds3r2cLC0ISn5dNw7tm9vwiNVF"
+            + "JA2N37RRrifw4PvgelRSvLaX3M3ZBqC9s1Metg3v4FSlIRtSLWCNpHSvNw7i"
+            + "X8C2Xy9Hdlbh6Y/50o+iscojLRE14upfR1bIkcCZQGSyvGV52V2wBImUUZjV"
+            + "s2ZngwCg7mu852vK7+euz4WaL7ERVYtq9CMEAJ5swrljerDpz/RQ4Lhp6KER"
+            + "KyuI0PUttO57xINGshEINgYlZdGaZHRueHe7uKfI19mb0T4N3NJWaZ0wF+Cn"
+            + "rixsq0VrTUfiwfZeGluNG73aTCeY45fVXMGTTSYXzS8T0LW100Xn/0g9HRyA"
+            + "xUpuWo8IazxkMqHJis2uwriYKpAfA/9anvj5BS9p5pfPjp9dGM7GTMIYl5f2"
+            + "fcP57f+AW1TVR6IZiMJAvAdeWuLtwLnJiFpGlnFz273pfl+sAuqm1yNceImR"
+            + "2SDDP4+vtyycWy8nZhgEuhZx3W3cWMQz5WyNJSY1JJHh9TCQkCoN8E7XpVP4"
+            + "zEPboB2GzD93mfD8JLHP+/4DAwIvYrn+YqRaaGAu19XUj895g/GROyP8WEaU"
+            + "Bd/JNqWc4kE/0guetGnPzq7G3bLVwiKfFd4X7BrgHAo3mrQtVGVzdCBLZXkg"
+            + "KG5vIGNvbW1lbnQpIDx0ZXN0QGJvdW5jeWNhc3RsZS5vcmc+iFkEExECABkF"
+            + "AkB9BH0ECwcDAgMVAgMDFgIBAh4BAheAAAoJEKnMV8vjZQOpSRQAoKZy6YS1"
+            + "irF5/Q3JlWiwbkN6dEuLAJ9lldRLOlXsuQ5JW1+SLEc6K9ho4rACAADRwXPB"
+            + "cQEQAAEBAAAAAAAAAAAAAAAA/9j/4AAQSkZJRgABAQEASABIAAD//gAXQ3Jl"
+            + "YXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZ"
+            + "EhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sA"
+            + "QwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy"
+            + "MjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAFAAUAwEiAAIRAQMRAf/EABoA"
+            + "AQACAwEAAAAAAAAAAAAAAAAEBQIDBgf/xAAoEAABAgUDBAEFAAAAAAAAAAAB"
+            + "AgMABBEhMQUSQQYTIiNhFFGBkcH/xAAXAQEAAwAAAAAAAAAAAAAAAAAEAgMF"
+            + "/8QAJBEAAQQAAwkAAAAAAAAAAAAAAQACERIEIfATMTJBUZGx0fH/2gAMAwEA"
+            + "AhEDEQA/APMuotJlJVxstqaPo22NlAUp+YsNO0qSUtBcMu6n6EtOHcfPAHHF"
+            + "I16++oajQtTA3DapK02HFR8UpE9pTbQWtKm2WG2rlxVyQTcfGbn7Qm0OIjL7"
+            + "7Wrs2NNm9lzTmmSxQ0PX4opSprk5tmESF6syggzGwOLG6gXgHFbZhBixk8Xl"
+            + "IDcOQLRKt+rX+3qC5ZLTQblpQlvwvxn9CMpZturVGkJHapQJphRH8hCLXbzr"
+            + "qpYsCx1zC5rtpJNuYQhASc0UAQv/2YhcBBMRAgAcBQJAfQV+AhsDBAsHAwID"
+            + "FQIDAxYCAQIeAQIXgAAKCRCpzFfL42UDqfa2AJ9hjtEeDTbTEAuuSbzhYFxN"
+            + "/qc0FACgsmzysdbBpuN65yK01tbEaeIMtqCwAgAAnQEUBEB9BH4QAwCqRuWO"
+            + "rxm5v/8WWBtPEUZnYuu3WYxefRKn6ON5ka5Ymp4AfKpKqKqn982tjlG13GVE"
+            + "P2ow11L4yQKGNm+VyVEapm7SpMD0SHg9vsJygAWrfMJnBYWSgE19W6o3ckUR"
+            + "sWsAAwYDAKDCSiSxC3Z5/POaCehw5iHs/vmVk5Wn831LSZEEwkSohNDbIEry"
+            + "ia/9tFXSt11AP4stJtZ0MH87/6JBbiIRD4JXcx+zfzchL7Teczr/06QMphSn"
+            + "sAENupbhLupfpR+BbP4DAwIvYrn+YqRaaGBjvFK1fbxCt7ZM4I2W/3BC0lCX"
+            + "m/NypKNspGflec8u96uUlA0fNCnxm6f9nbB0jpvoKi0g4iqAf+P2iEYEGBEC"
+            + "AAYFAkB9BH4ACgkQqcxXy+NlA6mtMgCgvccZA/Sg7BXVpxli47SYhxSHoM4A"
+            + "oNCOMplSnYTuh5ikKeBWtz36gC1psAIAAA==");
+
+        private static readonly char[] sec3pass1 = "123456".ToCharArray();
+
+        //
+        // GPG comment packets.
+        //
+        private static readonly byte[] sec4 = Base64.Decode(
+            "lQG7BD0PbK8RBAC0cW4Y2MZXmAmqYp5Txyw0kSQsFvwZKHNMFRv996IsN57URVF5"
+            + "BGMVPRBi9dNucWbjiSYpiYN13wE9IuLZsvVaQojV4XWGRDc+Rxz9ElsXnsYQ3mZU"
+            + "7H1bNQEofstChk4z+dlvPBN4GFahrIzn/CeVUn6Ut7dVdYbiTqviANqNXwCglfVA"
+            + "2OEePvqFnGxs1jhJyPSOnTED/RwRvsLH/k43mk6UEvOyN1RIpBXN+Ieqs7h1gFrQ"
+            + "kB+WMgeP5ZUsotTffVDSUS9UMxRQggVUW1Xml0geGwQsNfkr/ztWMs/T4xp1v5j+"
+            + "QyJx6OqNlkGdqOsoqkzJx0SQ1zBxdinFyyC4H95SDAb/RQOu5LQmxFG7quexztMs"
+            + "infEA/9cVc9+qCo92yRAaXRqKNVVQIQuPxeUsGMyVeJQvJBD4An8KTMCdjpF10Cp"
+            + "qA3t+n1S0zKr5WRUtvS6y60MOONO+EJWVWBNkx8HJDaIMNkfoqQoz3Krn7w6FE/v"
+            + "/5uwMd6jY3N3yJZn5nDZT9Yzv9Nx3j+BrY+henRlSU0c6xDc9QAAnjJYg0Z83VJG"
+            + "6HrBcgc4+4K6lHulCqH9JiM6RFNBX2ZhY3RvcjoAAK9hV206agp99GI6x5qE9+pU"
+            + "vs6O+Ich/SYjOkRTQV9mYWN0b3I6AACvYAfGn2FGrpBYbjnpTuFOHJMS/T5xg/0m"
+            + "IzpEU0FfZmFjdG9yOgAAr0dAQz6XxMwxWIn8xIZR/v2iN2L9C6O0EkZvbyBCYXIg"
+            + "PGJhekBxdXV4PohXBBMRAgAXBQI9D2yvBQsHCgMEAxUDAgMWAgECF4AACgkQUGLI"
+            + "YCIktfoGogCfZiXMJUKrScqozv5tMwzTTk2AaT8AniM5iRr0Du/Y08SL/NMhtF6H"
+            + "hJ89nO4EPQ9ssRADAI6Ggxj6ZBfoavuXd/ye99osW8HsNlbqhXObu5mCMNySX2wa"
+            + "HoWyRUEaUkI9eQw+MlHzIwzA32E7y2mU3OQBKdgLcBg4jxtcWVEg8ESKF9MpFXxl"
+            + "pExxWrr4DFBfCRcsTwAFEQL9G3OvwJuEZXgx2JSS41D3pG4/qiHYICVa0u3p/14i"
+            + "cq0kXajIk5ZJ6frCIAHIzuQ3n7jjzr05yR8s/qCrNbBA+nlkVNa/samk+jCzxxxa"
+            + "cR/Dbh2wkvTFuDFFETwQYLuZAADcDck4YGQAmHivVT2NNDCf/aTz0+CJWl+xRc2l"
+            + "Qw7D/SQjOkVMR19mYWN0b3I6AACbBnv9m5/bb/pjYAm2PtDp0CysQ9X9JCM6RUxH"
+            + "X2ZhY3RvcjoAAJsFyHnSmaWguTFf6lJ/j39LtUNtmf0kIzpFTEdfZmFjdG9yOgAA"
+            + "mwfwMD3LxmWtuCWBE9BptWMNH07Z/SQjOkVMR19mYWN0b3I6AACbBdhBrbSiM4UN"
+            + "y7khDW2Sk0e4v9mIRgQYEQIABgUCPQ9ssQAKCRBQYshgIiS1+jCMAJ9txwHnb1Kl"
+            + "6i/fSoDs8SkdM7w48wCdFvPEV0sSxE73073YhBgPZtMWbBo=");
+
+        //
+        // PGP freeware version 7
+        //
+        private static readonly byte[] pub5 = Base64.Decode(
+            "mQENBEBrBE4BCACjXVcNIFDQSofaIyZnALb2CRg+WY9uUqgHEEAOlPe03Cs5STM5"
+            + "HDlNmrh4TdFceJ46rxk1mQOjULES1YfHay8lCIzrD7FX4oj0r4DC14Fs1vXaSar2"
+            + "1szIpttOw3obL4A1e0p6N4jjsoG7N/pA0fEL0lSw92SoBrMbAheXRg4qNTZvdjOR"
+            + "grcuOuwgJRvPLtRXlhyLBoyhkd5mmrIDGv8QHJ/UjpeIcRXY9kn9oGXnEYcRbMaU"
+            + "VwXB4pLzWqz3ZejFI3lOxRWjm760puPOnGYlzSVBxlt2LgzUgSj1Mn+lIpWmAzsa"
+            + "xEiU4xUwEomQns72yYRZ6D3euNCibcte4SeXABEBAAG0KXBhbGFzaCBrYXNvZGhh"
+            + "biA8cGthc29kaGFuQHRpYWEtY3JlZi5vcmc+iQEuBBABAgAYBQJAawROCAsBAwkI"
+            + "BwIKAhkBBRsDAAAAAAoJEOfelumuiOrYqPEH+wYrdP5Tq5j+E5yN1pyCg1rwbSOt"
+            + "Dka0y0p7Oq/VIGLk692IWPItLEunnBXQtGBcWqklrvogvlhxtf16FgoyScfLJx1e"
+            + "1cJa+QQnVuH+VOESN6iS9Gp9lUfVOHv74mEMXw0l2Djfy/lnrkAMBatggyGnF9xF"
+            + "VXOLk1J2WVFm9KUE23o6qdB7RGkf31pN2eA7SWmkdJSkUH7o/QSFBI+UTRZ/IY5P"
+            + "ZIJpsdiIOqd9YMG/4RoSZuPqNRR6x7BSs8nQVR9bYs4PPlp4GfdRnOcRonoTeJCZ"
+            + "83RnsraWJnJTg34gRLBcqumhTuFKc8nuCNK98D6zkQESdcHLLTquCOaF5L+5AQ0E"
+            + "QGsETwEIAOVwNCTaDZvW4dowPbET1bI5UeYY8rAGLYsWSUfgaFv2srMiApyBVltf"
+            + "i6OLcPjcUCHDBjCv4pwx/C4qcHWb8av4xQIpqQXOpO9NxYE1eZnel/QB7DtH12ZO"
+            + "nrDNmHtaXlulcKNGe1i1utlFhgzfFx6rWkRL0ENmkTkaQmPY4gTGymJTUhBbsSRq"
+            + "2ivWqQA1TPwBuda73UgslIAHRd/SUaxjXoLpMbGOTeqzcKGjr5XMPTs7/YgBpWPP"
+            + "UxMlEQIiU3ia1bxpEhx05k97ceK6TSH2oCPQA7gumjxOSjKT+jEm+8jACVzymEmc"
+            + "XRy4D5Ztqkw/Z16pvNcu1DI5m6xHwr8AEQEAAYkBIgQYAQIADAUCQGsETwUbDAAA"
+            + "AAAKCRDn3pbprojq2EynB/4/cEOtKbI5UisUd3vkTzvWOcqWUqGqi5wjjioNtIM5"
+            + "pur2nFvhQE7SZ+PbAa87HRJU/4WcWMcoLkHD48JrQwHCHOLHSV5muYowb78X4Yh9"
+            + "epYtSJ0uUahcn4Gp48p4BkhgsPYXkxEImSYzAOWStv21/7WEMqItMYl89BV6Upm8"
+            + "HyTJx5MPTDbMR7X51hRg3OeQs6po3WTCWRzFIMyGm1rd/VK1L5ZDFPqO3S6YUJ0z"
+            + "cxecYruvfK0Wp7q834wE8Zkl/PQ3NhfEPL1ZiLr/L00Ty+77/FZqt8SHRCICzOfP"
+            + "OawcVGI+xHVXW6lijMpB5VaVIH8i2KdBMHXHtduIkPr9");
+
+        private static readonly byte[] sec5 = Base64.Decode(
+            "lQOgBEBrBE4BCACjXVcNIFDQSofaIyZnALb2CRg+WY9uUqgHEEAOlPe03Cs5STM5"
+            + "HDlNmrh4TdFceJ46rxk1mQOjULES1YfHay8lCIzrD7FX4oj0r4DC14Fs1vXaSar2"
+            + "1szIpttOw3obL4A1e0p6N4jjsoG7N/pA0fEL0lSw92SoBrMbAheXRg4qNTZvdjOR"
+            + "grcuOuwgJRvPLtRXlhyLBoyhkd5mmrIDGv8QHJ/UjpeIcRXY9kn9oGXnEYcRbMaU"
+            + "VwXB4pLzWqz3ZejFI3lOxRWjm760puPOnGYlzSVBxlt2LgzUgSj1Mn+lIpWmAzsa"
+            + "xEiU4xUwEomQns72yYRZ6D3euNCibcte4SeXABEBAAEB8wqP7JkKN6oMNi1xJNqU"
+            + "vvt0OV4CCnrIFiOPCjebjH/NC4T/9pJ6BYSjYdo3VEPNhPhRS9U3071Kqbdt35J5"
+            + "kmzMq1yNStC1jkxHRCNTMsb1yIEY1v+fv8/Cy+tBpvAYiJKaox8jW3ppi9vTHZjW"
+            + "tYYq0kwAVojMovz1O3wW/pEF69UPBmPYsze+AHA1UucYYqdWO8U2tsdFJET/hYpe"
+            + "o7ppHJJCdqWzeiE1vDUrih9pP3MPpzcRS/gU7HRDb5HbfP7ghSLzByEa+2mvg5eK"
+            + "eLwNAx2OUtrVg9rJswXX7DOLa1nKPhdGrSV/qwuK4rBdaqJ/OvszVJ0Vln0T/aus"
+            + "it1PAuVROLUPqTVVN8/zkMenFbf5vtryC3GQYXvvZq+l3a4EXwrR/1pqrTfnfOuD"
+            + "GwlFhRJAqPfthxZS68/xC8qAmTtkl7j4nscNM9kSoZ3BFwSyD9B/vYHPWGlqnpGF"
+            + "k/hBXuIgl07KIeNIyEC3f1eRyaiMFqEz5yXbbTfEKirSVpHM/mpeKxG8w96aK3Je"
+            + "AV0X6ZkC4oLTp6HCG2TITUIeNxCh2rX3fhr9HvBDXBbMHgYlIcLwzNkwDX74cz/7"
+            + "nIclcubaWjEkDHP20XFicuChFc9zx6kBYuYy170snltTBgTWSuRH15W4NQqrLo37"
+            + "zyzZQubX7CObgQJu4ahquiOg4SWl6uEI7+36U0SED7sZzw8ns1LxrwOWbXuHie1i"
+            + "xCvsJ4RpJJ03iEdNdUIb77qf6AriqE92tXzcVXToBv5S2K5LdFYNJ1rWdwaKJRkt"
+            + "kmjCL67KM9WT/IagsUyU+57ao3COtqw9VWZi6ev+ubM6fIV0ZK46NEggOLph1hi2"
+            + "gZ9ew9uVuruYg7lG2Ku82N0fjrQpcGFsYXNoIGthc29kaGFuIDxwa2Fzb2RoYW5A"
+            + "dGlhYS1jcmVmLm9yZz6dA6AEQGsETwEIAOVwNCTaDZvW4dowPbET1bI5UeYY8rAG"
+            + "LYsWSUfgaFv2srMiApyBVltfi6OLcPjcUCHDBjCv4pwx/C4qcHWb8av4xQIpqQXO"
+            + "pO9NxYE1eZnel/QB7DtH12ZOnrDNmHtaXlulcKNGe1i1utlFhgzfFx6rWkRL0ENm"
+            + "kTkaQmPY4gTGymJTUhBbsSRq2ivWqQA1TPwBuda73UgslIAHRd/SUaxjXoLpMbGO"
+            + "TeqzcKGjr5XMPTs7/YgBpWPPUxMlEQIiU3ia1bxpEhx05k97ceK6TSH2oCPQA7gu"
+            + "mjxOSjKT+jEm+8jACVzymEmcXRy4D5Ztqkw/Z16pvNcu1DI5m6xHwr8AEQEAAQF7"
+            + "osMrvQieBAJFYY+x9jKPVclm+pVaMaIcHKwCTv6yUZMqbHNRTfwdCVKTdAzdlh5d"
+            + "zJNXXRu8eNwOcfnG3WrWAy59cYE389hA0pQPOh7iL2V1nITf1qdLru1HJqqLC+dy"
+            + "E5GtkNcgvQYbv7ACjQacscvnyBioYC6TATtPnHipMO0S1sXEnmUugNlW88pDln4y"
+            + "VxCtQXMBjuqMt0bURqmb+RoYhHhoCibo6sexxSnbEAPHBaW1b1Rm7l4UBSW6S5U0"
+            + "MXURE60IHfP1TBe1l/xOIxOi8qdBQCyaFW2up00EhRBy/WOO6KAYXQrRRpOs9TBq"
+            + "ic2wquwZePmErTbIttnnBcAKmpodrM/JBkn/we5fVg+FDTP8sM/Ubv0ZuM70aWmF"
+            + "v0/ZKbkCkh2YORLWl5+HR/RKShdkmmFgZZ5uzbOGxxEGKhw+Q3+QFUF7PmYOnOtv"
+            + "s9PZE3dV7ovRDoXIjfniD1+8sLUWwW5d+3NHAQnCHJrLnPx4sTHx6C0yWMcyZk6V"
+            + "fNHpLK4xDTbgoTmxJa/4l+wa0iD69h9K/Nxw/6+X/GEM5w3d/vjlK1Da6urN9myc"
+            + "GMsfiIll5DNIWdLLxCBPFmhJy653CICQLY5xkycWB7JOZUBTOEVrYr0AbBZSTkuB"
+            + "fq5p9MfH4N51M5TWnwlJnqEiGnpaK+VDeP8GniwCidTYyiocNPvghvWIzG8QGWMY"
+            + "PFncRpjFxmcY4XScYYpyRme4qyPbJhbZcgGpfeLvFKBPmNxVKJ2nXTdx6O6EbHDj"
+            + "XctWqNd1EQas7rUN728u7bk8G7m37MGqQuKCpNvOScH4TnPROBY8get0G3bC4mWz"
+            + "6emPeENnuyElfWQiHEtCZr1InjnNbb/C97O+vWu9PfsE");
+
+        private static readonly char[] sec5pass1 = "12345678".ToCharArray();
+
+        //
+        // Werner Koch "odd keys"
+        //
+        private static readonly byte[] pub6 = Base64.Decode(
+            "mQGiBDWiHh4RBAD+l0rg5p9rW4M3sKvmeyzhs2mDxhRKDTVVUnTwpMIR2kIA9pT4"
+            + "3No/coPajDvhZTaDM/vSz25IZDZWJ7gEu86RpoEdtr/eK8GuDcgsWvFs5+YpCDwW"
+            + "G2dx39ME7DN+SRvEE1xUm4E9G2Nnd2UNtLgg82wgi/ZK4Ih9CYDyo0a9awCgisn3"
+            + "RvZ/MREJmQq1+SjJgDx+c2sEAOEnxGYisqIKcOTdPOTTie7o7x+nem2uac7uOW68"
+            + "N+wRWxhGPIxsOdueMIa7U94Wg/Ydn4f2WngJpBvKNaHYmW8j1Q5zvZXXpIWRXSvy"
+            + "TR641BceGHNdYiR/PiDBJsGQ3ac7n7pwhV4qex3IViRDJWz5Dzr88x+Oju63KtxY"
+            + "urUIBACi7d1rUlHr4ok7iBRlWHYXU2hpUIQ8C+UOE1XXT+HB7mZLSRONQnWMyXnq"
+            + "bAAW+EUUX2xpb54CevAg4eOilt0es8GZMmU6c0wdUsnMWWqOKHBFFlDIvyI27aZ9"
+            + "quf0yvby63kFCanQKc0QnqGXQKzuXbFqBYW2UQrYgjXji8rd8bQnV2VybmVyIEtv"
+            + "Y2ggKGdudXBnIHNpZykgPGRkOWpuQGdudS5vcmc+iGUEExECAB0FAjZVoKYFCQht"
+            + "DIgDCwQDBRUDAgYBAxYCAQIXgAASCRBot6uJV1SNzQdlR1BHAAEBLj4AoId15gcy"
+            + "YpBX2YLtEQTlXPp3mtEGAJ9UxzJE/t3EHCHK2bAIOkBwIW8ItIkBXwMFEDWiHkMD"
+            + "bxG4/z6qCxADYzIFHR6I9Si9gzPQNRcFs2znrTp5pV5Mk6f1aqRgZxL3E4qUZ3xe"
+            + "PQhwAo3fSy3kCwLmFGqvzautSMHn8K5V1u+T5CSHqLFYKqj5FGtuB/xwoKDXH6UO"
+            + "P0+l5IP8H1RTjme3Fhqahec+zPG3NT57vc2Ru2t6PmuAwry2BMuSFMBs7wzXkyC3"
+            + "DbI54MV+IKPjHMORivK8uI8jmna9hdNVyBifCk1GcxkHBSCFvU8xJePsA/Q//zCe"
+            + "lvrnrIiMfY4CQTmKzke9MSzbAZQIRddgrGAsiX1tE8Z3YMd8lDpuujHLVEdWZo6s"
+            + "54OJuynHrtFFObdapu0uIrT+dEXSASMUbEuNCLL3aCnrEtGJCwxB2TPQvCCvR2BK"
+            + "zol6MGWxA+nmddeQib2r+GXoKXLdnHcpsAjA7lkXk3IFyJ7MLFK6uDrjGbGJs2FK"
+            + "SduUjS/Ib4hGBBARAgAGBQI1oic8AAoJEGx+4bhiHMATftYAn1fOaKDUOt+dS38r"
+            + "B+CJ2Q+iElWJAKDRPpp8q5GylbM8DPlMpClWN3TYqYhGBBARAgAGBQI27U5sAAoJ"
+            + "EF3iSZZbA1iiarYAn35qU3ZOlVECELE/3V6q98Q30eAaAKCtO+lacH0Qq1E6v4BP"
+            + "/9y6MoLIhohiBBMRAgAiAhsDBAsHAwIDFQIDAxYCAQIeAQIXgAUCP+mCaQUJDDMj"
+            + "ywAKCRBot6uJV1SNzaLvAJwLsPV1yfc2D+yT+2W11H/ftNMDvwCbBweORhCb/O/E"
+            + "Okg2UTXJBR4ekoCIXQQTEQIAHQMLBAMFFQMCBgEDFgIBAheABQI/6YJzBQkMMyPL"
+            + "AAoJEGi3q4lXVI3NgroAn2Z+4KgVo2nzW72TgCJwkAP0cOc2AJ0ZMilsOWmxmEG6"
+            + "B4sHMLkB4ir4GIhdBBMRAgAdAwsEAwUVAwIGAQMWAgECF4AFAj/pgnMFCQwzI8sA"
+            + "CgkQaLeriVdUjc2CugCfRrOIfllp3mSmGpHgIxvg5V8vtMcAn0BvKVehOn+12Yvn"
+            + "9BCHfg34jUZbiF0EExECAB0DCwQDBRUDAgYBAxYCAQIXgAUCP+mCcwUJDDMjywAK"
+            + "CRBot6uJV1SNzYK6AJ9x7R+daNIjkieNW6lJeVUIoj1UHgCeLZm025uULML/5DFs"
+            + "4tUvXs8n9XiZAaIENaIg8xEEALYPe0XNsPjx+inTQ+Izz527ZJnoc6BhWik/4a2b"
+            + "ZYENSOQXAMKTDQMv2lLeI0i6ceB967MNubhHeVdNeOWYHFSM1UGRfhmZERISho3b"
+            + "p+wVZvVG8GBVwpw34PJjgYU/0tDwnJaJ8BzX6j0ecTSTjQPnaUEtdJ/u/gmG9j02"
+            + "18TzAKDihdNoKJEU9IKUiSjdGomSuem/VwQArHfaucSiDmY8+zyZbVLLnK6UJMqt"
+            + "sIv1LvAg20xwXoUk2bY8H3tXL4UZ8YcoSXYozwALq3cIo5UZJ0q9Of71mI8WLK2i"
+            + "FSYVplpTX0WMClAdkGt3HgVb7xtOhGt1mEKeRQjNZ2LteUQrRDD9MTQ+XxcvEN0I"
+            + "pAj4kBJe9bR6HzAD/iecCmGwSlHUZZrgqWzv78o79XxDdcuLdl4i2fL7kwEOf9js"
+            + "De7hGs27yrdJEmAG9QF9TOF9LJFmE1CqkgW+EpKxsY01Wjm0BFJB1R7iPUaUtFRZ"
+            + "xYqfgXarmPjql2iBi+cVjLzGu+4BSojVAPgP/hhcnIowf4M4edPiICMP1GVjtCFX"
+            + "ZXJuZXIgS29jaCA8d2VybmVyLmtvY2hAZ3V1Zy5kZT6IYwQTEQIAGwUCNs8JNwUJ"
+            + "CCCxRAMLCgMDFQMCAxYCAQIXgAASCRBsfuG4YhzAEwdlR1BHAAEBaSAAn3YkpT5h"
+            + "xgehGFfnX7izd+c8jI0SAJ9qJZ6jJvXnGB07p60aIPYxgJbLmYkAdQMFEDWjdxQd"
+            + "GfTBDJhXpQEBPfMC/0cxo+4xYVAplFO0nIYyjQgP7D8O0ufzPsIwF3kvb7b5FNNj"
+            + "fp+DAhN6G0HOIgkL3GsWtCfH5UHali+mtNFIKDpTtr+F/lPpZP3OPzzsLZS4hYTq"
+            + "mMs1O/ACq8axKgAilYkBXwMFEDWiJw4DbxG4/z6qCxADB9wFH0i6mmn6rWYKFepJ"
+            + "hXyhE4wWqRPJAnvfoiWUntDp4aIQys6lORigVXIWo4k4SK/FH59YnzF7578qrTZW"
+            + "/RcA0bIqJqzqaqsOdTYEFa49cCjvLnBW4OebJlLTUs/nnmU0FWKW8OwwL+pCu8d7"
+            + "fLSSnggBsrUQwbepuw0cJoctFPAz5T1nQJieQKVsHaCNwL2du0XefOgF5ujB1jK1"
+            + "q3p4UysF9hEcBR9ltE3THr+iv4jtZXmC1P4at9W5LFWsYuwr0U3yJcaKSKp0v/wG"
+            + "EWe2J/gFQZ0hB1+35RrCZPgiWsEv87CHaG6XtQ+3HhirBCJsYhmOikVKoEan6PhU"
+            + "VR1qlXEytpAt389TBnvyceAX8hcHOE3diuGvILEgYes3gw3s5ZmM7bUX3jm2BrX8"
+            + "WchexUFUQIuKW2cL379MFXR8TbxpVxrsRYE/4jHZBYhGBBARAgAGBQI27U4LAAoJ"
+            + "EF3iSZZbA1iifJoAoLEsGy16hV/CfmDku6D1CBUIxXvpAJ9GBApdC/3OXig7sBrV"
+            + "CWOb3MQzcLkBjQQ2zwcIEAYA9zWEKm5eZpMMBRsipL0IUeSKEyeKUjABX4vYNurl"
+            + "44+2h6Y8rHn7rG1l/PNj39UJXBkLFj1jk8Q32v+3BQDjvwv8U5e/kTgGlf7hH3WS"
+            + "W38RkZw18OXYCvnoWkYneIuDj6/HH2bVNXmTac05RkBUPUv4yhqlaFpkVcswKGuE"
+            + "NRxujv/UWvVF+/2P8uSQgkmGp/cbwfMTkC8JBVLLBRrJhl1uap2JjZuSVklUUBez"
+            + "Vf3NJMagVzx47HPqLVl4yr4bAAMGBf9PujlH5I5OUnvZpz+DXbV/WQVfV1tGRCra"
+            + "kIj3mpN6GnUDF1LAbe6vayUUJ+LxkM1SqQVcmuy/maHXJ+qrvNLlPqUZPmU5cINl"
+            + "sA7bCo1ljVUp54J1y8PZUx6HxfEl/LzLVkr+ITWnyqeiRikDecUf4kix2teTlx6I"
+            + "3ecqT5oNqZSRXWwnN4SbkXtAd7rSgEptUYhQXgSEarp1pXJ4J4rgqFa49jKISDJq"
+            + "rn/ElltHe5Fx1bpfkCIYlYk45Cga9bOIVAQYEQIADAUCNs8HCAUJBvPJAAASCRBs"
+            + "fuG4YhzAEwdlR1BHAAEBeRUAoIGpCDmMy195TatlloHAJEjZu5KaAJwOvW989hOb"
+            + "8cg924YIFVA1+4/Ia7kBjQQ1oiE8FAYAkQmAlOXixb8wra83rE1i7LCENLzlvBZW"
+            + "KBXN4ONelZAnnkOm7IqRjMhtKRJN75zqVyKUaUwDKjpf9J5K2t75mSxBtnbNRqL3"
+            + "XodjHK93OcAUkz3ci7iuC/b24JI2q4XeQG/v4YR1VodM0zEQ1IC0JCq4Pl39QZyX"
+            + "JdZCrUFvMcXq5ruNSldztBqTFFUiFbkw1Fug/ZyXJve2FVcbsRXFrB7EEuy+iiU/"
+            + "kZ/NViKk0L4T6KRHVsEiriNlCiibW19fAAMFBf9Tbv67KFMDrLqQan/0oSSodjDQ"
+            + "KDGqtoh7KQYIKPXqfqT8ced9yd5MLFwPKf3t7AWG1ucW2x118ANYkPSU122UTndP"
+            + "sax0cY4XkaHxaNwpNFCotGQ0URShxKNpcqbdfvy+1d8ppEavgOyxnV1JOkLjZJLw"
+            + "K8bgxFdbPWcsJJnjuuH3Pwz87CzTgOSYQxMPnIwQcx5buZIV5NeELJtcbbd3RVua"
+            + "K/GQht8QJpuXSji8Nl1FihYDjACR8TaRlAh50GmIRgQoEQIABgUCOCv7gwAKCRBs"
+            + "fuG4YhzAE9hTAJ9cRHu+7q2hkxpFfnok4mRisofCTgCgzoPjNIuYiiV6+wLB5o11"
+            + "7MNWPZCIVAQYEQIADAUCNaIhPAUJB4TOAAASCRBsfuG4YhzAEwdlR1BHAAEBDfUA"
+            + "oLstR8cg5QtHwSQ3nFCOKEREUFIwAKDID3K3hM+b6jW1o+tNX9dnjb+YMZkAbQIw"
+            + "bYOUAAABAwC7ltmO5vdKssohwzXEZeYvDW2ll3CYD2I+ruiNq0ybxkfFBopq9cxt"
+            + "a0OvVML4LK/TH+60f/Fqx9wg2yk9APXyaomdLrXfWyfZ91YtNCfj3ElC4XB4qqm0"
+            + "HRn0wQyYV6UABRG0IVdlcm5lciBLb2NoIDx3ZXJuZXIua29jaEBndXVnLmRlPokA"
+            + "lQMFEDRfoOmOB31Gi6BmjQEBzwgD/2fHcdDXuRRY+SHvIVESweijstB+2/sVRp+F"
+            + "CDjR74Kg576sJHfTJCxtSSmzpaVpelb5z4URGJ/Byi5L9AU7hC75S1ZnJ+MjBT6V"
+            + "ePyk/r0uBrMkU/lMG7lk/y2By3Hll+edjzJsdwn6aoNPiyen4Ch4UGTEguxYsLq0"
+            + "HES/UvojiQEVAwUTNECE2gnp+QqKck5FAQH+1Af/QMlYPlLG+5E19qP6AilKQUzN"
+            + "kd1TWMenXTS66hGIVwkLVQDi6RCimhnLMq/F7ENA8bSbyyMuncaBz5dH4kjfiDp1"
+            + "o64LULcTmN1LW9ctpTAIeLLJZnwxoJLkUbLUYKADKqIBXHMt2B0zRmhFOqEjRN+P"
+            + "hI7XCcHeHWHiDeUB58QKMyeoJ/QG/7zLwnNgDN2PVqq2E72C3ye5FOkYLcHfWKyB"
+            + "Rrn6BdUphAB0LxZujSGk8ohZFbia+zxpWdE8xSBhZbjVGlwLurmS2UTjjxByBNih"
+            + "eUD6IC3u5P6psld0OfqnpriZofP0CBP2oTk65r529f/1lsy2kfWrVPYIFJXEnIkA"
+            + "lQMFEDQyneGkWMS9SnJfMQEBMBMD/1ADuhhuY9kyN7Oj6DPrDt5SpPQDGS0Jtw3y"
+            + "uIPoed+xyzlrEuL2HeaOj1O9urpn8XLN7V21ajkzlqsxnGkOuifbE9UT67o2b2vC"
+            + "ldCcY4nV5n+U1snMDwNv+RkcEgNa8ANiWkm03UItd7/FpHDQP0FIgbPEPwRoBN87"
+            + "I4gaebfRiQCVAwUQNDUSwxRNm5Suj3z1AQGMTAP/UaXXMhPzcjjLxBW0AccTdHUt"
+            + "Li+K+rS5PNxxef2nnasEhCdK4GkM9nwJgsP0EZxCG3ZSAIlWIgQ3MK3ZAV1Au5pL"
+            + "KolRjFyEZF420wAtiE7V+4lw3FCqNoXDJEFC3BW431kx1wAhDk9VaIHHadYcof4d"
+            + "dmMLQOW2cJ7LDEEBW/WJAJUDBRA0M/VQImbGhU33abUBARcoA/9eerDBZGPCuGyE"
+            + "mQBcr24KPJHWv/EZIKl5DM/Ynz1YZZbzLcvEFww34mvY0jCfoVcCKIeFFBMKiSKr"
+            + "OMtoVC6cQMKpmhE9hYRStw4E0bcf0BD/stepdVtpwRnG8SDP2ZbmtgyjYT/7T4Yt"
+            + "6/0f6N/0NC7E9qfq4ZlpU3uCGGu/44kAlQMFEDQz8kp2sPVxuCQEdQEBc5YD/Rix"
+            + "vFcLTO1HznbblrO0WMzQc+R4qQ50CmCpWcFMwvVeQHo/bxoxGggNMmuVT0bqf7Mo"
+            + "lZDSJNS96IAN32uf25tYHgERnQaMhmi1aSHvRDh4jxFu8gGVgL6lWit/vBDW/BiF"
+            + "BCH6sZJJrGSuSdpecTtaWC8OJGDoKTO9PqAA/HQRiQB1AwUQNDJSx011eFs7VOAZ"
+            + "AQGdKQL/ea3qD2OP3wVTzXvfjQL1CosX4wyKusBBhdt9u2vOT+KWkiRk1o35nIOG"
+            + "uZLHtSFQDY8CVDOkqg6g4sVbOcTl8QUwHA+A4AVDInwTm1m4Bk4oeCIwk4Bp6mDd"
+            + "W11g28k/iQEVAgUSNDIWPm/Y4wPDeaMxAQGvBQgAqGhzA/21K7oL/L5S5Xz//eO7"
+            + "J8hgvqqGXWd13drNy3bHbKPn7TxilkA3ca24st+6YPZDdSUHLMCqg16YOMyQF8gE"
+            + "kX7ZHWPacVoUpCmSz1uQ3p6W3+u5UCkRpgQN8wBbJx5ZpBBqeq5q/31okaoNjzA2"
+            + "ghEWyR5Ll+U0C87MY7pc7PlNHGCr0ZNOhhtf1jU+H9ag5UyT6exIYim3QqWYruiC"
+            + "LSUcim0l3wK7LMW1w/7Q6cWfAFQvl3rGjt3rg6OWg9J4H2h5ukf5JNiRybkupmat"
+            + "UM+OVMRkf93jzU62kbyZpJBHiQZuxxJaLkhpv2RgWib9pbkftwEy/ZnmjkxlIIkA"
+            + "lQMFEDQvWjh4313xYR8/NQEB37QEAIi9vR9h9ennz8Vi7RNU413h1ZoZjxfEbOpk"
+            + "QAjE/LrZ/L5WiWdoStSiyqCLPoyPpQafiU8nTOr1KmY4RgceJNgxIW4OiSMoSvrh"
+            + "c2kqP+skb8A2B4+47Aqjr5fSAVfVfrDMqDGireOguhQ/hf9BOYsM0gs+ROdtyLWP"
+            + "tMjRnFlviD8DBRAz8qQSj6lRT5YOKXIRAntSAJ9StSEMBoFvk8iRWpXb6+LDNLUW"
+            + "zACfT8iY3IxwvMF6jjCHrbuxQkL7chSJARUDBRA0MMO7569NIyeqD3EBATIAB/4t"
+            + "CPZ1sLWO07g2ZCpiP1HlYpf5PENaXtaasFvhWch7eUe3DksuMEPzB5GnauoQZAku"
+            + "hEGkoEfrfL3AXtXH+WMm2t7dIcTBD4p3XkeZ+PgJpKiASXDyul9rumXXvMxSL4KV"
+            + "7ar+F1ZJ0ycCx2r2au0prPao70hDAzLTy16hrWgvdHSK7+wwaYO5TPCL5JDmcB+d"
+            + "HKW72qNUOD0pxbe0uCkkb+gDxeVX28pZEkIIOMMV/eAs5bs/smV+eJqWT/EyfVBD"
+            + "o7heF2aeyJj5ecxNOODr88xKF7qEpqazCQ4xhvFY+Yn6+vNCcYfkoZbOn0XQAvqf"
+            + "a2Vab9woVIVSaDji/mlPiQB1AwUQNDC233FfeD4HYGBJAQFh6QL/XCgm5O3q9kWp"
+            + "gts1MHKoHoh7vxSSQGSP2k7flNP1UB2nv4sKvyGM8eJKApuROIodcTkccM4qXaBu"
+            + "XunMr5kJlvDJPm+NLzKyhtQP2fWI7xGYwiCiB29gm1GFMjdur4amiQEVAwUQNDBR"
+            + "9fjDdqGixRdJAQE+mAf+JyqJZEVFwNwZ2hSIMewekC1r7N97p924nqfZKnzn6weF"
+            + "pE80KIJSWtEVzI0XvHlVCOnS+WRxn7zxwrOTbrcEOy0goVbNgUsP5ypZa2/EM546"
+            + "uyyJTvgD0nwA45Q4bP5sGhjh0G63r9Vwov7itFe4RDBGM8ibGnZTr9hHo469jpom"
+            + "HSNeavcaUYyEqcr4GbpQmdpJTnn/H0A+fMl7ZHRoaclNx9ZksxihuCRrkQvUOb3u"
+            + "RD9lFIhCvNwEardN62dKOKJXmn1TOtyanZvnmWigU5AmGuk6FpsClm3p5vvlid64"
+            + "i49fZt9vW5krs2XfUevR4oL0IyUl+qW2HN0DIlDiAYkAlQMFEDQvbv2wcgJwUPMh"
+            + "JQEBVBID/iOtS8CQfMxtG0EmrfaeVUU8R/pegBmVWDBULAp8CLTtdfxjVzs/6DXw"
+            + "0RogXMRRl2aFfu1Yp0xhBYjII6Kque/FzAFXY9VNF1peqnPt7ADdeptYMppZa8sG"
+            + "n9BBRu9Fsw69z6JkyqvMiVxGcKy3XEpVGr0JHx8Xt6BYdrULiKr2iQB1AwUQNC68"
+            + "n6jZR/ntlUftAQFaYgL+NUYEj/sX9M5xq1ORX0SsVPMpNamHO3JBSmZSIzjiox5M"
+            + "AqoFOCigAkonuzk5aBy/bRHy1cmDBOxf4mNhzrH8N6IkGvPE70cimDnbFvr+hoZS"
+            + "jIqxtELNZsLuLVavLPAXiQCVAwUQNC6vWocCuHlnLQXBAQHb1gQAugp62aVzDCuz"
+            + "4ntfXsmlGbLY7o5oZXYIKdPP4riOj4imcJh6cSgYFL6OMzeIp9VW/PHo2mk8kkdk"
+            + "z5uif5LqOkEuIxgra7p1Yq/LL4YVhWGQeD8hwpmu+ulYoPOw40dVYS36PwrHIH9a"
+            + "fNhl8Or5O2VIHIWnoQ++9r6gwngFQOyJAJUDBRAzHnkh1sNKtX1rroUBAWphBACd"
+            + "huqm7GHoiXptQ/Y5F6BivCjxr9ch+gPSjaLMhq0kBHVO+TbXyVefVVGVgCYvFPjo"
+            + "zM8PEVykQAtY//eJ475aGXjF+BOAhl2z0IMkQKCJMExoEDHbcj0jIIMZ2/+ptgtb"
+            + "FSyJ2DQ3vvCdbw/1kyPHTPfP+L2u40GWMIYVBbyouokAlQMFEDMe7+UZsymln7HG"
+            + "2QEBzMED/3L0DyPK/u6PyAd1AdpjUODTkWTZjZ6XA2ubc6IXXsZWpmCgB/24v8js"
+            + "J3DIsvUD3Ke55kTr6xV+au+mAkwOQqWUTUWfQCkSrSDlbUJ1VPBzhyTpuzjBopte"
+            + "7o3R6XXfcLiC5jY6eCX0QtLGhKpLjTr5uRhf1fYODGsAGXmCByDviQB1AgUQMy6U"
+            + "MB0Z9MEMmFelAQHV4AMAjdFUIyFtpTr5jkyZSd3y//0JGO0z9U9hLVxeBBCwvdEQ"
+            + "xsrpeTtVdqpeKZxHN1GhPCYvgLFZAQlcPh/Gc8u9uO7wVSgJc3zYKFThKpQevdF/"
+            + "rzjTCHfgigf5Iui0qiqBiQCVAwUQMx22bAtzgG/ED06dAQFi0gQAkosqTMWy+1eU"
+            + "Xbi2azFK3RX5ERf9wlN7mqh7TvwcPXvVWzUARnwRv+4kk3uOWI18q5UPis7KH3KY"
+            + "OVeRrPd8bbp6SjhBh82ourTEQUXLBDQiI1V1cZZmwwEdlnAnhFnkXgMBNM2q7oBe"
+            + "fRHADfYDfGo90wXyrVVL+GihDNpzUwOJAJUDBRAzHUFnOWvfULwOR3EBAbOYA/90"
+            + "JIrKmxhwP6quaheFOjjPoxDGEZpGJEOwejEByYj+AgONCRmQS3BydtubA+nm/32D"
+            + "FeG8pe/dnFvGc+QgNW560hK21C2KJj72mhjRlg/na7jz4/MmBAv5k61Q7roWi0rw"
+            + "x+R9NSHxpshC8A92zmvo8w/XzVSogC8pJ04jcnY6YokAlQMFEDMdPtta9LwlvuSC"
+            + "3QEBvPMD/3TJGroHhHYjHhiEpDZZVszeRQ0cvVI/uLLi5yq3W4F6Jy47DF8VckA7"
+            + "mw0bXrOMNACN7Je7uyaU85qvJC2wgoQpFGdFlkjmkAwDAjR+koEysiE8FomiOHhv"
+            + "EpEY/SjSS4jj4IPmgV8Vq66XjPw+i7Z0RsPLOIf67yZHxypNiBiYiQCVAwUQMxxw"
+            + "pKrq6G7/78D5AQHo2QQAjnp6KxOl6Vvv5rLQ/4rj3OemvF7IUUq34xb25i/BSvGB"
+            + "UpDQVUmhv/qIfWvDqWGZedyM+AlNSfUWPWnP41S8OH+lcERH2g2dGKGl7kH1F2Bx"
+            + "ByZlqREHm2q624wPPA35RLXtXIx06yYjLtJ7b+FCAX6PUgZktZYk5gwjdoAGrC2J"
+            + "AJUDBRAzGvcCKC6c7f53PGUBAUozA/9l/qKmcqbi8RtLsKQSh3vHds9d22zcbkuJ"
+            + "PBSoOv2D7i2VLshaQFjq+62uYZGE6nU1WP5sZcBDuWjoX4t4NrffnOG/1R9D0t1t"
+            + "9F47D77HJzjvo+J52SN520YHcbT8VoHdPRoEOXPN4tzhvn2GapVVdaAlWM0MLloh"
+            + "NH3I9jap9okAdQMFEDMZlUAnyXglSykrxQEBnuwC/jXbFL+jzs2HQCuo4gyVrPlU"
+            + "ksQCLYZjNnZtw1ca697GV3NhBhSXR9WHLQH+ZWnpTzg2iL3WYSdi9tbPs78iY1FS"
+            + "d4EG8H9V700oQG8dlICF5W2VjzR7fByNosKM70WSXYkBFQMFEDMWBsGCy1t9eckW"
+            + "HQEBHzMH/jmrsHwSPrA5R055VCTuDzdS0AJ+tuWkqIyqQQpqbost89Hxper3MmjL"
+            + "Jas/VJv8EheuU3vQ9a8sG2SnlWKLtzFqpk7TCkyq/H3blub0agREbNnYhHHTGQFC"
+            + "YJb4lWjWvMjfP+N5jvlLcnDqQPloXfAOgy7W90POoqFrsvhxdpnXgoLrzyNNja1O"
+            + "1NRj+Cdv/GmJYNi6sQe43zmXWeA7syLKMw6058joDqEJFKndgSp3Zy/yXmObOZ/H"
+            + "C2OJwA3gzEaAu8Pqd1svwGIGznqtTNCn9k1+rMvJPaxglg7PXIJS282hmBl9AcJl"
+            + "wmh2GUCswl9/sj+REWTb8SgJUbkFcp6JAJUDBRAwdboVMPfsgxioXMEBAQ/LA/9B"
+            + "FTZ9T95P/TtsxeC7lm9imk2mpNQCBEvXk286FQnGFtDodGfBfcH5SeKHaUNxFaXr"
+            + "39rDGUtoTE98iAX3qgCElf4V2rzgoHLpuQzCg3U35dfs1rIxlpcSDk5ivaHpPV3S"
+            + "v+mlqWL049y+3bGaZeAnwM6kvGMP2uccS9U6cbhpw4hGBBARAgAGBQI3GtRfAAoJ"
+            + "EF3iSZZbA1iikWUAoIpSuXzuN/CI63dZtT7RL7c/KtWUAJ929SAtTr9SlpSgxMC8"
+            + "Vk1T1i5/SYkBFQMFEzccnFnSJilEzmrGwQEBJxwH/2oauG+JlUC3zBUsoWhRQwqo"
+            + "7DdqaPl7sH5oCGDKS4x4CRA23U15NicDI7ox6EizkwCjk0dRr1EeRK+RqL1b/2T4"
+            + "2B6nynOLhRG2A0BPHRRJLcoL4nKfoPSo/6dIC+3iVliGEl90KZZD5bnONrVJQkRj"
+            + "ZL8Ao+9IpmoYh8XjS5xMLEF9oAQqAkA93nVBm56lKmaL1kl+M3dJFtNKtVB8de1Z"
+            + "XifDs8HykD42qYVtcseCKxZXhC3UTG5YLNhPvgZKH8WBCr3zcR13hFDxuecUmu0M"
+            + "VhvEzoKyBYYt0rrqnyWrxwbv4gSTUWH5ZbgsTjc1SYKZxz6hrPQnfYWzNkznlFWJ"
+            + "ARUDBRM0xL43CdxwOTnzf10BATOCB/0Q6WrpzwPMofjHj54MiGLKVP++Yfwzdvns"
+            + "HxVpTZLZ5Ux8ErDsnLmvUGphnLVELZwEkEGRjln7a19h9oL8UYZaV+IcR6tQ06Fb"
+            + "1ldR+q+3nXtBYzGhleXdgJQSKLJkzPF72tvY0DHUB//GUV9IBLQMvfG8If/AFsih"
+            + "4iXi96DOtUAbeuIhnMlWwLJFeGjLLsX1u6HSX33xy4bGX6v/UcHbTSSYaxzb92GR"
+            + "/xpP2Xt332hOFRkDZL52g27HS0UrEJWdAVZbh25KbZEl7C6zX/82OZ5nTEziHo20"
+            + "eOS6Nrt2+gLSeA9X5h/+qUx30kTPz2LUPBQyIqLCJkHM8+0q5j9ciQCiAwUTNMS+"
+            + "HZFeTizbCJMJAQFrGgRlEAkG1FYU4ufTxsaxhFZy7xv18527Yxpls6mSCi1HL55n"
+            + "Joce6TI+Z34MrLOaiZljeQP3EUgzA+cs1sFRago4qz2wS8McmQ9w0FNQQMz4vVg9"
+            + "CVi1JUVd4EWYvJpA8swDd5b9+AodYFEsfxt9Z3aP+AcWFb10RlVVsNw9EhObc6IM"
+            + "nwAOHCEI9vp5FzzFiQCVAwUQNxyr6UyjTSyISdw9AQHf+wP+K+q6hIQ09tkgaYaD"
+            + "LlWKLbuxePXqM4oO72qi70Gkg0PV5nU4l368R6W5xgR8ZkxlQlg85sJ0bL6wW/Sj"
+            + "Mz7pP9hkhNwk0x3IFkGMTYG8i6Gt8Nm7x70dzJoiC+A496PryYC0rvGVf+Om8j5u"
+            + "TexBBjb/jpJhAQ/SGqeDeCHheOC0Lldlcm5lciBLb2NoIChtZWluIGFsdGVyIGtl"
+            + "eSkgPHdrQGNvbXB1dGVyLm9yZz6JAHUDBRM2G2MyHRn0wQyYV6UBASKKAv4wzmK7"
+            + "a9Z+g0KH+6W8ffIhzrQo8wDAU9X1WJKzJjS205tx4mmdnAt58yReBc/+5HXTI8IK"
+            + "R8IgF+LVXKWAGv5P5AqGhnPMeQSCs1JYdf9MPvbe34jD8wA1LTWFXn9e/cWIRgQQ"
+            + "EQIABgUCNxrUaQAKCRBd4kmWWwNYovRiAJ9dJBVfjx9lGARoFXmAieYrMGDrmwCZ"
+            + "AQyO4Wo0ntQ+iq4do9M3/FTFjiCZAaIENu1I6REEAJRGEqcYgXJch5frUYBj2EkD"
+            + "kWAbhRqVXnmiF3PjCEGAPMMYsTddiU7wcKfiCAqKWWXow7BjTJl6Do8RT1jdKpPO"
+            + "lBJXqqPYzsyBxLzE6mLps0K7SLJlSKTQqSVRcx0jx78JWYGlAlP0Kh9sPV2w/rPh"
+            + "0LrPeOKXT7lZt/DrIhfPAKDL/sVqCrmY3QfvrT8kSKJcgtLWfQP/cfbqVNrGjW8a"
+            + "m631N3UVA3tWfpgM/T9OjmKmw44NE5XfPJTAXlCV5j7zNMUkDeoPkrFF8DvbpYQs"
+            + "4XWYHozDjhR2Q+eI6gZ0wfmhLHqqc2eVVkEG7dT57Wp9DAtCMe7RZfhnarTQMqlY"
+            + "tOEa/suiHk0qLo59NsyF8eh68IDNCeYD/Apzonwaq2EQ1OEpfFlp6LcSnS34+UGZ"
+            + "tTO4BgJdmEjr/QrIPp6bJDstgho+/2oR8yQwuHGJwbS/8ADA4IFEpLduSpzrABho"
+            + "7RuNQcm96bceRY+7Hza3zf7pg/JGdWOb+bC3S4TIpK+3sx3YNWs7eURwpGREeJi5"
+            + "/Seic+GXlGzltBpXZXJuZXIgS29jaCA8d2tAZ251cGcub3JnPohjBBMRAgAbBQI3"
+            + "Gs+QBQkMyXyAAwsKAwMVAwIDFgIBAheAABIJEF3iSZZbA1iiB2VHUEcAAQFdwgCe"
+            + "O/s43kCLDMIsHCb2H3LC59clC5UAn1EyrqWk+qcOXLpQIrP6Qa3QSmXIiEYEEBEC"
+            + "AAYFAjca0T0ACgkQbH7huGIcwBOF9ACeNwO8G2G0ei03z0g/n3QZIpjbzvEAnRaE"
+            + "qX2PuBbClWoIP6h9yrRlAEbUiQB1AwUQNxrRYx0Z9MEMmFelAQHRrgL/QDNKPV5J"
+            + "gWziyzbHvEKfTIw/Ewv6El2MadVvQI8kbPN4qkPr2mZWwPzuc9rneCPQ1eL8AOdC"
+            + "8+ZyxWzx2vsrk/FcU5donMObva2ct4kqJN6xl8xjsxDTJhBSFRaiBJjxiEYEEBEC"
+            + "AAYFAjca0aMACgkQaLeriVdUjc0t+ACghK37H2vTYeXXieNJ8aZkiPJSte4An0WH"
+            + "FOotQdTW4NmZJK+Uqk5wbWlgiEYEEBECAAYFAjdPH10ACgkQ9u7fIBhLxNktvgCe"
+            + "LnQ5eOxAJz+Cvkb7FnL/Ko6qc5YAnjhWWW5c1o3onvKEH2Je2wQa8T6iiEYEEBEC"
+            + "AAYFAjenJv4ACgkQmDRl2yFDlCJ+yQCfSy1zLftEfLuIHZsUHis9U0MlqLMAn2EI"
+            + "f7TI1M5OKysQcuFLRC58CfcfiEUEEBECAAYFAjfhQTMACgkQNmdg8X0u14h55wCf"
+            + "d5OZCV3L8Ahi4QW/JoXUU+ZB0M0AmPe2uw7WYDLOzv48H76tm6cy956IRgQQEQIA"
+            + "BgUCOCpiDwAKCRDj8lhUEo8OeRsdAJ9FHupRibBPG2t/4XDqF+xiMLL/8ACfV5F2"
+            + "SR0ITE4k/C+scS1nJ1KZUDW0C1dlcm5lciBLb2NoiGMEExECABsFAjbtSOoFCQzJ"
+            + "fIADCwoDAxUDAgMWAgECF4AAEgkQXeJJllsDWKIHZUdQRwABAbXWAJ9SCW0ieOpL"
+            + "7AY6vF+OIaMmw2ZW1gCgkto0eWfgpjAuVg6jXqR1wHt2pQOJAh4EEBQDAAYFAjcv"
+            + "WdQACgkQbEwxpbHVFWcNxQf/bg14WGJ0GWMNSuuOOR0WYzUaNtzYpiLSVyLrreXt"
+            + "o8LBNwzbgzj2ramW7Ri+tYJAHLhtua8ZgSeibmgBuZasF8db1m5NN1ZcHBXGTysA"
+            + "jp+KnicTZ9Orj75D9o3oSmMyRcisEhr+gkj0tVhGfOAOC6eKbufVuyYFDVIyOyUB"
+            + "GlW7ApemzAzYemfs3DdjHn87lkjHMVESO4fM5rtLuSc7cBfL/e6ljaWQc5W8S0gI"
+            + "Dv0VtL39pMW4BlpKa25r14oJywuUpvWCZusvDm7ZJnqZ/WmgOHQUsyYudTROpGIb"
+            + "lsNg8iqC6huWpGSBRdu3oRQRhkqpfVdszz6BB/nAx01q2wf/Q+U9XId1jyzxUL1S"
+            + "GgaYMf6QdyjHQ1oxuFLNxzM6C/M069twbNgXJ71RsDDXVxFZfSTjSiH100AP9+9h"
+            + "b5mycaXLUOXYDvOSFzHBd/LsjFNVrrFbDs5Xw+cLGVHOIgR5IWAfgu5d1PAZU9uQ"
+            + "VgdGnQfmZg383RSPxvR3fnZz1rHNUGmS6w7x6FVbxa1QU2t38gNacIwHATAPcBpy"
+            + "JLfXoznbpg3ADbgCGyDjBwnuPQEQkYwRakbczRrge8IaPZbt2HYPoUsduXMZyJI8"
+            + "z5tvu7pUDws51nV1EX15BcN3++aY5pUyA1ItaaDymQVmoFbQC0BNMzMO53dMnFko"
+            + "4i42kohGBBARAgAGBQI3OvmjAAoJEHUPZJXInZM+hosAnRntCkj/70shGTPxgpUF"
+            + "74zA+EbzAKCcMkyHXIz2W0Isw3gDt27Z9ggsE4hGBBARAgAGBQI3NyPFAAoJEPbu"
+            + "3yAYS8TZh2UAoJVmzw85yHJzsXQ1vpO2IAPfv59NAJ9WY0oiYqb3q1MSxBRwG0gV"
+            + "iNCJ7YkBFQMFEDdD3tNSgFdEdlNAHQEByHEH/2JMfg71GgiyGJTKxCAymdyf2j2y"
+            + "fH6wI782JK4BWV4c0E/V38q+jpIYslihV9t8s8w1XK5niMaLwlCOyBWOkDP3ech6"
+            + "+GPPtfB3cmlL2hS896PWZ1adQHgCeQpB837n56yj0aTs4L1xarbSVT22lUwMiU6P"
+            + "wYdH2Rh8nh8FvN0IZsbln2nOj73qANQzNflmseUKF1Xh4ck8yLrRd4r6amhxAVAf"
+            + "cYFRJN4zdLL3cmhgkt0ADZlzAwXnEjwdHHy7SvAJk1ecNOA9pFsOJbvnzufd1afs"
+            + "/CbG78I+0JDhg75Z2Nwq8eKjsKqiO0zz/vG5yWSndZvWkTWz3D3b1xr1Id2IRgQQ"
+            + "EQIABgUCOCpiHgAKCRDj8lhUEo8OeQ+QAKCbOTscyUnWHSrDo4fIy0MThEjhOgCe"
+            + "L4Kb7TWkd/OHQScVBO8sTUz0+2g=");
+
+//		private static readonly byte[] pub6check = Base64.Decode("62O9");
+
+        //
+        // revoked sub key
+        //
+        private static readonly byte[] pub7 = Base64.Decode(
+            "mQGiBEFOsIwRBADcjRx7nAs4RaWsQU6p8/ECLZD9sSeYc6CN6UDI96RKj0/hCzMs"
+            + "qlA0+9fzGZ7ZEJ34nuvDKlhKGC7co5eOiE0a9EijxgcrZU/LClZWa4YfyNg/ri6I"
+            + "yTyfOfrPQ33GNQt2iImDf3FKp7XKuY9nIxicGQEaW0kkuAmbV3oh0+9q8QCg/+fS"
+            + "epDEqEE/+nKONULGizKUjMED/RtL6RThRftZ9DOSdBytGYd48z35pca/qZ6HA36K"
+            + "PVQwi7V77VKQyKFLTOXPLnVyO85hyYB/Nv4DFHN+vcC7/49lfoyYMZlN+LarckHi"
+            + "NL154wmmzygB/KKysvWBLgkErEBCD0xBDd89iTQNlDtVQAWGORVffl6WWjOAkliG"
+            + "3dL6A/9A288HfFRnywqi3xddriV6wCPmStC3dkCS4vHk2ofS8uw4ZNoRlp1iEPna"
+            + "ai2Xa9DX1tkhaGk2k96MqqbBdGpbW8sMA9otJ9xdMjWEm/CgJUFUFQf3zaVy3mkM"
+            + "S2Lvb6P4Wc2l/diEEIyK8+PqJItSh0OVU3K9oM7ngHwVcalKILQVUkV2b2tlZCA8"
+            + "UmV2b2tlZEB0ZWQ+iQBOBBARAgAOBQJBTrCMBAsDAgECGQEACgkQvglkcFA/c63+"
+            + "QgCguh8rsJbPTtbhZcrqBi5Mo1bntLEAoPZQ0Kjmu2knRUpHBeUemHDB6zQeuQIN"
+            + "BEFOsIwQCAD2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4INoBp1ajFOmPQFXz"
+            + "0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3bzpnhV5JZzf24rnRP"
+            + "xfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9GAFgr5fSI/VhOSdvN"
+            + "ILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67VYy4XTjTNP18F1dD"
+            + "ox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMI"
+            + "PWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICB/93zriSvSHqsi1FeEmUBo431Jkh"
+            + "VerIzb6Plb1j6FIq+s3vyvx9K+dMvjotZqylWZj4GXpH+2xLJTjWkrGSfUZVI2Nk"
+            + "nyOFxUCKLLqaqVBFAQIjULfvQfGEWiGQKk9aRLkdG+D+8Y2N9zYoBXoQ9arvvS/t"
+            + "4mlOsiuaTe+BZ4x+BXTpF4b9sKZl7V8QP/TkoJWUdydkvxciHdWp7ssqyiKOFRhG"
+            + "818knDfFQ3cn2w/RnOb+7AF9wDncXDPYLfpPv9b2qZoLrXcyvlLffGDUdWs553ut"
+            + "1F5AprMURs8BGmY9BnjggfVubHdhTUoA4gVvrdaf+D9NwZAl0xK/5Y/oPuMZiQBG"
+            + "BBgRAgAGBQJBTrCMAAoJEL4JZHBQP3Ot09gAoMmLKloVDP+WhDXnsM5VikxysZ4+"
+            + "AKCrJAUO+lYAyPYwEwgK+bKmUGeKrIkARgQoEQIABgUCQU6wpQAKCRC+CWRwUD9z"
+            + "rQK4AJ98kKFxGU6yhHPr6jYBJPWemTNOXgCfeGB3ox4PXeS4DJDuLy9yllytOjo=");
+
+//		private static readonly byte[] pub7check = Base64.Decode("f/YQ");
+
+        private static readonly byte[] pub8 = Base64.Decode(
+            "mQGiBEEcraYRBADFYj+uFOhHz5SdECvJ3Z03P47gzmWLQ5HH8fPYC9rrv7AgqFFX"
+            + "aWlJJVMLua9e6xoCiDWJs/n4BbZ/weL/11ELg6XqUnzFhYyz0H2KFsPgQ/b9lWLY"
+            + "MtcPMFy5jE33hv/ixHgYLFqoNaAIbg0lzYEW/otQ9IhRl16fO1Q/CQZZrQCg/9M2"
+            + "V2BTmm9RYog86CXJtjawRBcD/RIqU0zulxZ2Zt4javKVxrGIwW3iBU935ebmJEIK"
+            + "Y5EVkGKBOCvsApZ+RGzpYeR2uMsTnQi8RJgiAnjaoVPCdsVJE7uQ0h8XuJ5n5mJ2"
+            + "kLCFlF2hj5ViicZzse+crC12CGtgRe8z23ubLRcd6IUGhVutK8/b5knZ22vE14JD"
+            + "ykKdA/96ObzJQdiuuPsEWN799nUUCaYWPAoLAmiXuICSP4GEnxLbYHWo8zhMrVMT"
+            + "9Q5x3h8cszUz7Acu2BXjP1m96msUNoxPOZtt88NlaFz1Q/JSbQTsVOMd9b/IRN6S"
+            + "A/uU0BiKEMHXuT8HUHVPK49oCKhZrGFP3RT8HZxDKLmR/qrgZ7ABh7QhSmlhIFlp"
+            + "eXUgPHl5amlhQG5vd21lZGlhdGVjaC5jb20+sAMD//+JAF0EEBECAB0FAkEcraYH"
+            + "CwkIBwMCCgIZAQUbAwAAAAUeAQAAAAAKCRD0/lb4K/9iFJlhAKCRMifQewiX5o8F"
+            + "U099FG3QnLVUZgCfWpMOsHulGHfNrxdBSkE5Urqh1ymwAWe5Ag0EQRytphAIAPZC"
+            + "V7cIfwgXcqK61qlC8wXo+VMROU+28W65Szgg2gGnVqMU6Y9AVfPQB8bLQ6mUrfdM"
+            + "ZIZJ+AyDvWXpF9Sh01D49Vlf3HZSTz09jdvOmeFXklnN/biudE/F/Ha8g8VHMGHO"
+            + "fMlm/xX5u/2RXscBqtNbno2gpXI61Brwv0YAWCvl9Ij9WE5J280gtJ3kkQc2azNs"
+            + "OA1FHQ98iLMcfFstjvbzySPAQ/ClWxiNjrtVjLhdONM0/XwXV0OjHRhs3jMhLLUq"
+            + "/zzhsSlAGBGNfISnCnLWhsQDGcgHKXrKlQzZlp+r0ApQmwJG0wg9ZqRdQZ+cfL2J"
+            + "SyIZJrqrol7DVekyCzsAAgIH/3K2wKRSzkIpDfZR25+tnQ8brv3TYoDZo3/wN3F/"
+            + "r6PGjx0150Q8g8EAC0bqm4rXWzOqdSxYxvIPOAGm5P4y+884yS6j3vKcXitT7vj+"
+            + "ODc2pVwGDLDjrMRrosSK89ycPCK6R/5pD7Rv4l9DWi2fgLvXqJHS2/ujUf2uda9q"
+            + "i9xNMnBXIietR82Sih4undFUOwh6Mws/o3eed9DIdaqv2Y2Aw43z/rJ6cjSGV3C7"
+            + "Rkf9x85AajYA3LwpS8d99tgFig2u6V/A16oi6/M51oT0aR/ZAk50qUc4WBk9uRUX"
+            + "L3Y+P6v6FCBE/06fgVltwcQHO1oKYKhH532tDL+9mW5/dYGwAYeJAEwEGBECAAwF"
+            + "AkEcraYFGwwAAAAACgkQ9P5W+Cv/YhShrgCg+JW8m5nF3R/oZGuG87bXQBszkjMA"
+            + "oLhGPncuGKowJXMRVc70/8qwXQJLsAFnmQGiBD2K5rYRBADD6kznWZA9nH/pMlk0"
+            + "bsG4nI3ELgyI7KpgRSS+Dr17+CCNExxCetT+fRFpiEvUcSxeW4pOe55h0bQWSqLo"
+            + "MNErXVJEXrm1VPkC08W8D/gZuPIsdtKJu4nowvdoA+WrI473pbeONGjaEDbuIJak"
+            + "yeKM1VMSGhsImdKtxqhndq2/6QCg/xARUIzPRvKr2TJ52K393895X1kEAMCdjSs+"
+            + "vABnhaeNNR5+NNkkIOCCjCS8qZRZ4ZnIayvn9ueG3KrhZeBIHoajUHrlTXBVj7XO"
+            + "wXVfGpW17jCDiqhU8Pu6VwEwX1iFbuUwqBffiRLXKg0zfcN+MyFKToi+VsJi4jiZ"
+            + "zcwUFMb8jE8tvR/muXti7zKPRPCbNBExoCt4A/0TgkzAosG/W4dUkkbc6XoHrjob"
+            + "iYuy6Xbs/JYlV0vf2CyuKCZC6UoznO5x2GkvOyVtAgyG4HSh1WybdrutZ8k0ysks"
+            + "mOthE7n7iczdj9Uwg2h+TfgDUnxcCAwxnOsX5UaBqGdkX1PjCWs+O3ZhUDg6UsZc"
+            + "7O5a3kstf16lHpf4q7ABAIkAYQQfEQIAIQUCPYrmtgIHABcMgBHRi/xlIgI+Q6LT"
+            + "kNJ7zKvTd87NHAAKCRDJM3gHb/sRj7bxAJ9f6mdlXQH7gMaYiY5tBe/FRtPr1gCf"
+            + "UhDJQG0ARvORFWHjwhhBMLxW7j2wAWC0KkRlc21vbmQgS2VlIDxkZXNtb25kLmtl"
+            + "ZUBub3dtZWRpYXRlY2guY29tPrADAQD9iQBYBBARAgAYBQI9iua2CAsDCQgHAgEK"
+            + "AhkBBRsDAAAAAAoJEMkzeAdv+xGP7v4An19iqadBCCgDIe2DTpspOMidwQYPAJ4/"
+            + "5QXbcn4ClhOKTO3ZEZefQvvL27ABYLkCDQQ9iua2EAgA9kJXtwh/CBdyorrWqULz"
+            + "Bej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHT"
+            + "UPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq"
+            + "01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O"
+            + "9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcK"
+            + "ctaGxAMZyAcpesqVDNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TIL"
+            + "OwACAgf/SO+bbg+owbFKVN5HgOjOElQZVnCsegwCLqTeQzPPzsWmkGX2qZJPDIRN"
+            + "RZfJzti6+oLJwaRA/3krjviUty4VKhZ3lKg8fd9U0jEdnw+ePA7yJ6gZmBHL15U5"
+            + "OKH4Zo+OVgDhO0c+oetFpend+eKcvtoUcRoQoi8VqzYUNG0b/nmZGDlxQe1/ZNbP"
+            + "HpNf1BAtJXivCEKMD6PVzsLPg2L4tFIvD9faeeuKYQ4jcWtTkBLuIaZba3i3a4wG"
+            + "xTN20j9HpISVuLW/EfZAK1ef4DNjLmHEU9dMzDqfi+hPmMbGlFqcKr+VjcYIDuje"
+            + "o+92xm/EWAmlti88r2hZ3MySamHDrLABAIkATAQYEQIADAUCPYrmtgUbDAAAAAAK"
+            + "CRDJM3gHb/sRjzVTAKDVS+OJLMeS9VLAmT8atVCB42MwIQCgoh1j3ccWnhc/h6B7"
+            + "9Uqz3fUvGoewAWA=");
+
+        private static readonly byte[] sec8 = Base64.Decode(
+            "lQHpBEEcraYRBADFYj+uFOhHz5SdECvJ3Z03P47gzmWLQ5HH8fPYC9rrv7AgqFFX"
+            + "aWlJJVMLua9e6xoCiDWJs/n4BbZ/weL/11ELg6XqUnzFhYyz0H2KFsPgQ/b9lWLY"
+            + "MtcPMFy5jE33hv/ixHgYLFqoNaAIbg0lzYEW/otQ9IhRl16fO1Q/CQZZrQCg/9M2"
+            + "V2BTmm9RYog86CXJtjawRBcD/RIqU0zulxZ2Zt4javKVxrGIwW3iBU935ebmJEIK"
+            + "Y5EVkGKBOCvsApZ+RGzpYeR2uMsTnQi8RJgiAnjaoVPCdsVJE7uQ0h8XuJ5n5mJ2"
+            + "kLCFlF2hj5ViicZzse+crC12CGtgRe8z23ubLRcd6IUGhVutK8/b5knZ22vE14JD"
+            + "ykKdA/96ObzJQdiuuPsEWN799nUUCaYWPAoLAmiXuICSP4GEnxLbYHWo8zhMrVMT"
+            + "9Q5x3h8cszUz7Acu2BXjP1m96msUNoxPOZtt88NlaFz1Q/JSbQTsVOMd9b/IRN6S"
+            + "A/uU0BiKEMHXuT8HUHVPK49oCKhZrGFP3RT8HZxDKLmR/qrgZ/4JAwLXyWhb4pf4"
+            + "nmCmD0lDwoYvatLiR7UQVM2MamxClIiT0lCPN9C2AYIFgRWAJNS215Tjx7P/dh7e"
+            + "8sYfh5XEHErT3dMbsAGHtCFKaWEgWWl5dSA8eXlqaWFAbm93bWVkaWF0ZWNoLmNv"
+            + "bT6wAwP//4kAXQQQEQIAHQUCQRytpgcLCQgHAwIKAhkBBRsDAAAABR4BAAAAAAoJ"
+            + "EPT+Vvgr/2IUmWEAoJEyJ9B7CJfmjwVTT30UbdCctVRmAJ9akw6we6UYd82vF0FK"
+            + "QTlSuqHXKbABZ50CawRBHK2mEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlL"
+            + "OCDaAadWoxTpj0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N"
+            + "286Z4VeSWc39uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/"
+            + "RgBYK+X0iP1YTknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2O"
+            + "u1WMuF040zT9fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqV"
+            + "DNmWn6vQClCbAkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAgf/crbApFLO"
+            + "QikN9lHbn62dDxuu/dNigNmjf/A3cX+vo8aPHTXnRDyDwQALRuqbitdbM6p1LFjG"
+            + "8g84Aabk/jL7zzjJLqPe8pxeK1Pu+P44NzalXAYMsOOsxGuixIrz3Jw8IrpH/mkP"
+            + "tG/iX0NaLZ+Au9eokdLb+6NR/a51r2qL3E0ycFciJ61HzZKKHi6d0VQ7CHozCz+j"
+            + "d5530Mh1qq/ZjYDDjfP+snpyNIZXcLtGR/3HzkBqNgDcvClLx3322AWKDa7pX8DX"
+            + "qiLr8znWhPRpH9kCTnSpRzhYGT25FRcvdj4/q/oUIET/Tp+BWW3BxAc7WgpgqEfn"
+            + "fa0Mv72Zbn91gf4JAwITijME9IlFBGAwH6YmBtWIlnDiRbsq/Pxozuhbnes831il"
+            + "KmdpUKXkiIfHY0MqrEWl3Dfn6PMJGTnhgqXMrDxx3uHrq0Jl2swRnAWIIO8gID7j"
+            + "uPetUqEviPiwAYeJAEwEGBECAAwFAkEcraYFGwwAAAAACgkQ9P5W+Cv/YhShrgCg"
+            + "+JW8m5nF3R/oZGuG87bXQBszkjMAoLhGPncuGKowJXMRVc70/8qwXQJLsAFn");
+
+        private static readonly char[] sec8pass = "qwertyui".ToCharArray();
+
+        private static readonly byte[] sec9 = Base64.Decode(
+            "lQGqBEHCokERBAC9rh5SzC1sX1y1zoFuBB/v0SGhoKMEvLYf8Qv/j4deAMrc"
+            + "w5dxasYoD9oxivIUfTbZKo8cqr+dKLgu8tycigTM5b/T2ms69SUAxSBtj2uR"
+            + "LZrh4vjC/93kF+vzYJ4fNaBs9DGfCnsTouKjXqmfN3SlPMKNcGutO7FaUC3d"
+            + "zcpYfwCg7qyONHvXPhS0Iw4QL3mJ/6wMl0UD/0PaonqW0lfGeSjJSM9Jx5Bt"
+            + "fTSlwl6GmvYmI8HKvOBXAUSTZSbEkMsMVcIgf577iupzgWCgNF6WsNqQpKaq"
+            + "QIq1Kjdd0Y00xU1AKflOkhl6eufTigjviM+RdDlRYsOO5rzgwDTRTu9giErs"
+            + "XIyJAIZIdu2iaBHX1zHTfJ1r7nlAA/9H4T8JIhppUk/fLGsoPNZzypzVip8O"
+            + "mFb9PgvLn5GmuIC2maiocT7ibbPa7XuXTO6+k+323v7PoOUaKD3uD93zHViY"
+            + "Ma4Q5pL5Ajc7isnLXJgJb/hvvB1oo+wSDo9vJX8OCSq1eUPUERs4jm90/oqy"
+            + "3UG2QVqs5gcKKR4o48jTiv4DZQJHTlUBtB1mb28ga2V5IDxmb28ua2V5QGlu"
+            + "dmFsaWQuY29tPoheBBMRAgAeBQJBwqJCAhsDBgsJCAcDAgMVAgMDFgIBAh4B"
+            + "AheAAAoJEOKcXvehtw4ajJMAoK9nLfsrRY6peq56l/KzmjzuaLacAKCXnmiU"
+            + "waI7+uITZ0dihJ3puJgUz50BWARBwqJDEAQA0DPcNIn1BQ4CDEzIiQkegNPY"
+            + "mkYyYWDQjb6QFUXkuk1WEB73TzMoemsA0UKXwNuwrUgVhdpkB1+K0OR/e5ik"
+            + "GhlFdrDCqyT+mw6dRWbJ2i4AmFXZaRKO8AozZeWojsfP1/AMxQoIiBEteMFv"
+            + "iuXnZ3pGxSfZYm2+33IuPAV8KKMAAwUD/0C2xZQXgVWTiVz70HUviOmeTQ+f"
+            + "b1Hj0U9NMXWB383oQRBZCvQDM12cqGsvPZuZZ0fkGehGAIoyXtIjJ9lejzZN"
+            + "1TE9fnXZ9okXI4yCl7XLSE26OAbNsis4EtKTNScNaU9Dk3CS5XD/pkRjrkPN"
+            + "2hdUFtshuGmYkqhb9BIlrwE7/gMDAglbVSwecr9mYJcDYCH62U9TScWDTzsQ"
+            + "NFEfhMez3hGnNHNfHe+7yN3+Q9/LIhbba3IJEN5LsE5BFvudLbArp56EusIn"
+            + "JCxgiEkEGBECAAkFAkHCokMCGwwACgkQ4pxe96G3Dho2UQCeN3VPwx3dROZ+"
+            + "4Od8Qj+cLrBndGEAn0vaQdy6eIGeDw2I9u3Quwy6JnROnQHhBEHCozMRBADH"
+            + "ZBlB6xsAnqFYtYQOHr4pX6Q8TrqXCiHHc/q56G2iGbI9IlbfykQzaPHgWqZw"
+            + "9P0QGgF/QZh8TitiED+imLlGDqj3nhzpazqDh5S6sg6LYkQPqhwG/wT5sZQQ"
+            + "fzdeupxupjI5YN8RdIqkWF+ILOjk0+awZ4z0TSY/f6OSWpOXlwCgjIquR3KR"
+            + "tlCLk+fBlPnOXaOjX+kEAJw7umykNIHNaoY/2sxNhQhjqHVxKyN44y6FCSv9"
+            + "jRyW8Q/Qc8YhqBIHdmlcXoNWkDtlvErjdYMvOKFqKB1e2bGpjvhtIhNVQWdk"
+            + "oHap9ZuM1nV0+fD/7g/NM6D9rOOVCahBG2fEEeIwxa2CQ7zHZYfg9Umn3vbh"
+            + "TYi68R3AmgLOA/wKIVkfFKioI7iX4crQviQHJK3/A90SkrjdMQwLoiUjdgtk"
+            + "s7hJsTP1OPb2RggS1wCsh4sv9nOyDULj0T0ySGv7cpyv5Nq0FY8gw2oogHs5"
+            + "fjUnG4VeYW0zcIzI8KCaJT4UhR9An0A1jF6COrYCcjuzkflFbQLtQb9uNj8a"
+            + "hCpU4/4DAwIUxXlRMYE8uWCranzPo83FnBPRnGJ2aC9SqZWJYVUKIn4Vf2nu"
+            + "pVvCGFja0usl1WfV72hqlNKEONq7lohJBBgRAgAJBQJBwqMzAhsCAAoJEOKc"
+            + "Xvehtw4afisAoME/t8xz/rj/N7QRN9p8Ji8VPGSqAJ9K8eFJ+V0mxR+octJr"
+            + "6neEEX/i1Q==");
+
+        public char[] sec9pass = "foo".ToCharArray();
+
+        // version 4 keys with expiry dates
+        private static readonly byte[] pub10 = Base64.Decode(
+            "mQGiBEKqia0RBACc3hkufmscRSC4UvPZqMDsHm4+d/GXIr+3iNMSSEySJu8yk+k0"
+            + "Xs11C/K+n+v1rnn2jGGknv+1lDY6w75TIcTE6o6HGKeIDxsAm8P3MhoGU1GNPamA"
+            + "eTDeNybtrN/g6C65fCY9uI11hsUboYgQZ8ND22PB0VtvdOgq9D85qNUzxwCg1BbJ"
+            + "ycAKd4VqEvQ2Zglp3dCSrFMD/Ambq1kZqYa69sp3b9BPKuAgUgUPoytOArEej3Bk"
+            + "easAgAxNhWJy4GxigES3vk50rVi7w8XBuqbD1mQCzldF0HX0/A7PxLBv6od5uqqF"
+            + "HFxIyxg/KBZLd9ZOrsSaoUWH58jZq98X/sFtJtRi5VuJagMxCIJD4mLgtMv7Unlb"
+            + "/GrsA/9DEnObA/fNTgK70T+ZmPIS5tSt+bio30Aw4YGpPCGqpnm1u73b5kqX3U3B"
+            + "P+vGDvFuqZYpqQA8byAueH0MbaDHI4CFugvShXvgysJxN7ov7/8qsZZUMfK1t2Nr"
+            + "SAsPuKRbcY4gNKXIElKeXbyaET7vX7uAEKuxEwdYGFp/lNTkHLQgdGVzdCBrZXkg"
+            + "KHRlc3QpIDx0ZXN0QHRlc3QudGVzdD6IZAQTEQIAJAUCQqqJrQIbAwUJACTqAAYL"
+            + "CQgHAwIDFQIDAxYCAQIeAQIXgAAKCRDjDROQZRqIzDzLAJ42AeCRIBBjv8r8qw9y"
+            + "laNj2GZ1sACgiWYHVXMA6B1H9I1kS3YsCd3Oq7qwAgAAuM0EQqqJrhADAKWkix8l"
+            + "pJN7MMTXob4xFF1TvGll0UD1bDGOMMbes6aeXSbT9QXee/fH3GnijLY7wB+qTPv9"
+            + "ohubrSpnv3yen3CEBW6Q2YK+NlCskma42Py8YMV2idmYjtJi1ckvHFWt5wADBQL/"
+            + "fkB5Q5xSGgspMaTZmtmX3zG7ZDeZ0avP8e8mRL8UszCTpqs6vMZrXwyQLZPbtMYv"
+            + "PQpuRGEeKj0ysimwYRA5rrLQjnRER3nyuuEUUgc4j+aeRxPf9WVsJ/a1FCHtaAP1"
+            + "iE8EGBECAA8FAkKqia4CGwwFCQAk6gAACgkQ4w0TkGUaiMzdqgCfd66H7DL7kFGd"
+            + "IoS+NIp8JO+noxAAn25si4QAF7og8+4T5YQUuhIhx/NesAIAAA==");
+
+        private static readonly byte[] sec10 = Base64.Decode(
+            "lQHhBEKqia0RBACc3hkufmscRSC4UvPZqMDsHm4+d/GXIr+3iNMSSEySJu8yk+k0"
+            + "Xs11C/K+n+v1rnn2jGGknv+1lDY6w75TIcTE6o6HGKeIDxsAm8P3MhoGU1GNPamA"
+            + "eTDeNybtrN/g6C65fCY9uI11hsUboYgQZ8ND22PB0VtvdOgq9D85qNUzxwCg1BbJ"
+            + "ycAKd4VqEvQ2Zglp3dCSrFMD/Ambq1kZqYa69sp3b9BPKuAgUgUPoytOArEej3Bk"
+            + "easAgAxNhWJy4GxigES3vk50rVi7w8XBuqbD1mQCzldF0HX0/A7PxLBv6od5uqqF"
+            + "HFxIyxg/KBZLd9ZOrsSaoUWH58jZq98X/sFtJtRi5VuJagMxCIJD4mLgtMv7Unlb"
+            + "/GrsA/9DEnObA/fNTgK70T+ZmPIS5tSt+bio30Aw4YGpPCGqpnm1u73b5kqX3U3B"
+            + "P+vGDvFuqZYpqQA8byAueH0MbaDHI4CFugvShXvgysJxN7ov7/8qsZZUMfK1t2Nr"
+            + "SAsPuKRbcY4gNKXIElKeXbyaET7vX7uAEKuxEwdYGFp/lNTkHP4DAwLssmOjVC+d"
+            + "mWB783Lpzjb9evKzsxisTdx8/jHpUSS+r//6/Guyx3aA/zUw5bbftItW57mhuNNb"
+            + "JTu7WrQgdGVzdCBrZXkgKHRlc3QpIDx0ZXN0QHRlc3QudGVzdD6IZAQTEQIAJAUC"
+            + "QqqJrQIbAwUJACTqAAYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRDjDROQZRqIzDzL"
+            + "AJ0cYPwKeoSReY14LqJtAjnkX7URHACgsRZWfpbalrSyDnq3TtZeGPUqGX+wAgAA"
+            + "nQEUBEKqia4QAwClpIsfJaSTezDE16G+MRRdU7xpZdFA9WwxjjDG3rOmnl0m0/UF"
+            + "3nv3x9xp4oy2O8Afqkz7/aIbm60qZ798np9whAVukNmCvjZQrJJmuNj8vGDFdonZ"
+            + "mI7SYtXJLxxVrecAAwUC/35AeUOcUhoLKTGk2ZrZl98xu2Q3mdGrz/HvJkS/FLMw"
+            + "k6arOrzGa18MkC2T27TGLz0KbkRhHio9MrIpsGEQOa6y0I50REd58rrhFFIHOI/m"
+            + "nkcT3/VlbCf2tRQh7WgD9f4DAwLssmOjVC+dmWDXVLRopzxbBGOvodp/LZoSDb56"
+            + "gNJjDMJ1aXqWW9qTAg1CFjBq73J3oFpVzInXZ8+Q8inxv7bnWiHbiE8EGBECAA8F"
+            + "AkKqia4CGwwFCQAk6gAACgkQ4w0TkGUaiMzdqgCgl2jw5hfk/JsyjulQqe1Nps1q"
+            + "Lx0AoMdnFMZmTMLHn8scUW2j9XO312tmsAIAAA==");
+
+//		private static readonly char[] sec10pass = "test".ToCharArray();
+
+        private static readonly byte[] subKeyBindingKey = Base64.Decode(
+            "mQGiBDWagYwRBAD7UcH4TAIp7tmUoHBNxVxCVz2ZrNo79M6fV63riOiH2uDxfIpr"
+            + "IrL0cM4ehEKoqlhngjDhX60eJrOw1nC5BpYZRnDnyDYT4wTWRguxObzGq9pqA1dM"
+            + "oPTJhkFZVIBgFY99/ULRqaUYIhFGgBtnwS70J8/L/PGVc3DmWRLMkTDjSQCg/5Nh"
+            + "MCjMK++MdYMcMl/ziaKRT6EEAOtw6PnU9afdohbpx9CK4UvCCEagfbnUtkSCQKSk"
+            + "6cUp6VsqyzY0pai/BwJ3h4apFMMMpVrtBAtchVgqo4xTr0Sve2j0k+ase6FSImiB"
+            + "g+AR7hvTUTcBjwtIExBc8TuCTqmn4GG8F7UMdl5Z0AZYj/FfAQYaRVZYP/pRVFNx"
+            + "Lw65BAC/Fi3qgiGCJFvXnHIckTfcAmZnKSEXWY9NJ4YQb4+/nH7Vsw0wR/ZObUHR"
+            + "bWgTc9Vw1uZIMe0XVj6Yk1dhGRehUnrm3mE7UJxu7pgkBCbFECFSlSSqP4MEJwZV"
+            + "09YP/msu50kjoxyoTpt+16uX/8B4at24GF1aTHBxwDLd8X0QWrQsTWVycmlsbCBM"
+            + "eW5jaCBDTEVBUiBzeXN0ZW0gREggPGNsZWFyQG1sLmNvbT6JAEsEEBECAAsFAjWa"
+            + "gYwECwMBAgAKCRDyAGjiP47/XanfAKCs6BPURWVQlGh635VgL+pdkUVNUwCdFcNa"
+            + "1isw+eAcopXPMj6ACOapepu5Ag0ENZqBlBAIAPZCV7cIfwgXcqK61qlC8wXo+VMR"
+            + "OU+28W65Szgg2gGnVqMU6Y9AVfPQB8bLQ6mUrfdMZIZJ+AyDvWXpF9Sh01D49Vlf"
+            + "3HZSTz09jdvOmeFXklnN/biudE/F/Ha8g8VHMGHOfMlm/xX5u/2RXscBqtNbno2g"
+            + "pXI61Brwv0YAWCvl9Ij9WE5J280gtJ3kkQc2azNsOA1FHQ98iLMcfFstjvbzySPA"
+            + "Q/ClWxiNjrtVjLhdONM0/XwXV0OjHRhs3jMhLLUq/zzhsSlAGBGNfISnCnLWhsQD"
+            + "GcgHKXrKlQzZlp+r0ApQmwJG0wg9ZqRdQZ+cfL2JSyIZJrqrol7DVekyCzsAAgIH"
+            + "/RYtVo+HROZ6jrNjrATEwQm1fUQrk6n5+2dniN881lF0CNkB4NkHw1Xxz4Ejnu/0"
+            + "iLg8fkOAsmanOsKpOkRtqUnVpsVL5mLJpFEyCY5jbcfj+KY9/25bs0ga7kLHNZia"
+            + "zbCxJdF+W179z3nudQxRaXG/0XISIH7ziZbSVni69sKc1osk1+OoOMbSuZ86z535"
+            + "Pln4fXclkFE927HxfbWoO+60hkOLKh7x+8fC82b3x9vCETujEaxrscO2xS7/MYXP"
+            + "8t1ffriTDmhuIuQS2q4fLgeWdqrODrMhrD8Dq7e558gzp30ZCqpiS7EmKGczL7B8"
+            + "gXxbBCVSTxYMJheXt2xMXsuJAD8DBRg1moGU8gBo4j+O/10RAgWdAKCPhaFIXuC8"
+            + "/cdiNMxTDw9ug3De5QCfYXmDzRSFUu/nrCi8yz/l09wsnxo=");
+
+//		private static readonly byte[] subKeyBindingCheckSum = Base64.Decode("3HU+");
+
+        //
+        // PGP8 with SHA1 checksum.
+        //
+        private static readonly byte[] rewrapKey = Base64.Decode(
+            "lQOWBEUPOQgBCADdjPTtl8oOwqJFA5WU8p7oDK5KRWfmXeXUZr+ZJipemY5RSvAM"
+            + "rxqsM47LKYbmXOJznXCQ8+PPa+VxXAsI1CXFHIFqrXSwvB/DUmb4Ec9EuvNd18Zl"
+            + "hJAybzmV2KMkaUp9oG/DUvxZJqkpUddNfwqZu0KKKZWF5gwW5Oy05VCpaJxQVXFS"
+            + "whdbRfwEENJiNx4RB3OlWhIjY2p+TgZfgQjiGB9i15R+37sV7TqzBUZF4WWcnIRQ"
+            + "DnpUfxHgxQ0wO/h/aooyRHSpIx5i4oNpMYq9FNIyakEx/Bomdbs5hW9dFxhrE8Es"
+            + "UViAYITgTsyROxmgGatGG09dcmVDJVYF4i7JAAYpAAf/VnVyUDs8HrxYTOIt4rYY"
+            + "jIHToBsV0IiLpA8fEA7k078L1MwSwERVVe6oHVTjeR4A9OxE52Vroh2eOLnF3ftf"
+            + "6QThVVZr+gr5qeG3yvQ36N7PXNEVOlkyBzGmFQNe4oCA+NR2iqnAIspnekVmwJV6"
+            + "xVvPCjWw/A7ZArDARpfthspwNcJAp4SWfoa2eKzvUTznTyqFu2PSS5fwQZUgOB0P"
+            + "Y2FNaKeqV8vEZu4SUWwLOqXBQIZXiaLvdKNgwFvUe3kSHdCNsrVzW7SYxFwaEog2"
+            + "o6YLKPVPqjlGX1cMOponGp+7n9nDYkQjtEsGSSMQkQRDAcBdSVJmLO07kFOQSOhL"
+            + "WQQA49BcgTZyhyH6TnDBMBHsGCYj43FnBigypGT9FrQHoWybfX47yZaZFROAaaMa"
+            + "U6man50YcYZPwzDzXHrK2MoGALY+DzB3mGeXVB45D/KYtlMHPLgntV9T5b14Scbc"
+            + "w1ES2OUtsSIUs0zelkoXqjLuKnSIYK3mMb67Au7AEp6LXM8EAPj2NypvC86VEnn+"
+            + "FH0QHvUwBpmDw0EZe25xQs0brvAG00uIbiZnTH66qsIfRhXV/gbKK9J5DTGIqQ15"
+            + "DuPpz7lcxg/n2+SmjQLNfXCnG8hmtBjhTe+udXAUrmIcfafXyu68SAtebgm1ga56"
+            + "zUfqsgN3FFuMUffLl3myjyGsg5DnA/oCFWL4WCNClOgL6A5VkNIUait8QtSdCACT"
+            + "Y7jdSOguSNXfln0QT5lTv+q1AjU7zjRl/LsFNmIJ5g2qdDyK937FOXM44FEEjZty"
+            + "/4P2dzYpThUI4QUohIj8Qi9f2pZQueC5ztH6rpqANv9geZKcciAeAbZ8Md0K2TEU"
+            + "RD3Lh+RSBzILtBtUZXN0IEtleSA8dGVzdEBleGFtcGxlLmNvbT6JATYEEwECACAF"
+            + "AkUPOQgCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRDYpknHeQaskD9NB/9W"
+            + "EbFuLaqZAl3yjLU5+vb75BdvcfL1lUs44LZVwobNp3/0XbZdY76xVPNZURtU4u3L"
+            + "sJfGlaF+EqZDE0Mqc+vs5SIb0OnCzNJ00KaUFraUtkByRV32T5ECHK0gMBjCs5RT"
+            + "I0vVv+Qmzl4+X1Y2bJ2mlpBejHIrOzrBD5NTJimTAzyfnNfipmbqL8p/cxXKKzS+"
+            + "OM++ZFNACj6lRM1W9GioXnivBRC88gFSQ4/GXc8yjcrMlKA27JxV+SZ9kRWwKH2f"
+            + "6o6mojUQxnHr+ZFKUpo6ocvTgBDlC57d8IpwJeZ2TvqD6EdA8rZ0YriVjxGMDrX1"
+            + "8esfw+iLchfEwXtBIRwS");
+
+        private static readonly char[] rewrapPass = "voltage123".ToCharArray();
+
+        private static readonly byte[] pubWithX509 = Base64.Decode(
+              "mQENBERabjABCACtmfyo6Nph9MQjv4nmCWjZrRYnhXbivomAdIwYkLZUj1bjqE+j"
+            + "uaLzjZV8xSI59odZvrmOiqlzOc4txitQ1OX7nRgbOJ7qku0dvwjtIn46+HQ+cAFn"
+            + "2mTi81RyXEpO2uiZXfsNTxUtMi+ZuFLufiMc2kdk27GZYWEuasdAPOaPJnA+wW6i"
+            + "ZHlt0NfXIGNz864gRwhD07fmBIr1dMFfATWxCbgMd/rH7Z/j4rvceHD2n9yrhPze"
+            + "YN7W4Nuhsr2w/Ft5Cm9xO7vXT/cpto45uxn8f7jERep6bnUwNOhH8G+6xLQgTLD0"
+            + "qFBGVSIneK3lobs6+xn6VaGN8W0tH3UOaxA1ABEBAAG0D0NOPXFhLWRlZXBzaWdo"
+            + "dIkFDgQQZAIFAQUCRFpuMAUDCWdU0gMF/3gCGwPELGQBAQQwggTkMIIDzKADAgEC"
+            + "AhBVUMV/M6rIiE+IzmnPheQWMA0GCSqGSIb3DQEBBQUAMG4xEzARBgoJkiaJk/Is"
+            + "ZAEZFgNjb20xEjAQBgoJkiaJk/IsZAEZFgJxYTEVMBMGCgmSJomT8ixkARkWBXRt"
+            + "czAxMRUwEwYKCZImiZPyLGQBGRYFV2ViZmUxFTATBgNVBAMTDHFhLWRlZXBzaWdo"
+            + "dDAeFw0wNjA1MDQyMTEyMTZaFw0xMTA1MDQyMTIwMDJaMG4xEzARBgoJkiaJk/Is"
+            + "ZAEZFgNjb20xEjAQBgoJkiaJk/IsZAEZFgJxYTEVMBMGCgmSJomT8ixkARkWBXRt"
+            + "czAxMRUwEwYKCZImiZPyLGQBGRYFV2ViZmUxFTATBgNVBAMTDHFhLWRlZXBzaWdo"
+            + "dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2Z/Kjo2mH0xCO/ieYJ"
+            + "aNmtFieFduK+iYB0jBiQtlSPVuOoT6O5ovONlXzFIjn2h1m+uY6KqXM5zi3GK1DU"
+            + "5fudGBs4nuqS7R2/CO0ifjr4dD5wAWfaZOLzVHJcSk7a6Jld+w1PFS0yL5m4Uu5+"
+            + "IxzaR2TbsZlhYS5qx0A85o8mcD7BbqJkeW3Q19cgY3PzriBHCEPTt+YEivV0wV8B"
+            + "NbEJuAx3+sftn+Piu9x4cPaf3KuE/N5g3tbg26GyvbD8W3kKb3E7u9dP9ym2jjm7"
+            + "Gfx/uMRF6npudTA06Efwb7rEtCBMsPSoUEZVIid4reWhuzr7GfpVoY3xbS0fdQ5r"
+            + "EDUCAwEAAaOCAXwwggF4MAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G"
+            + "A1UdDgQWBBSmFTRv5y65DHtTYae48zl0ExNWZzCCASUGA1UdHwSCARwwggEYMIIB"
+            + "FKCCARCgggEMhoHFbGRhcDovLy9DTj1xYS1kZWVwc2lnaHQsQ049cWEtd3VtYW4x"
+            + "LWRjLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNl"
+            + "cyxDTj1Db25maWd1cmF0aW9uLERDPVdlYmZlLERDPXRtczAxLERDPXFhLERDPWNv"
+            + "bT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JM"
+            + "RGlzdHJpYnV0aW9uUG9pbnSGQmh0dHA6Ly9xYS13dW1hbjEtZGMud2ViZmUudG1z"
+            + "MDEucWEuY29tL0NlcnRFbnJvbGwvcWEtZGVlcHNpZ2h0LmNybDAQBgkrBgEEAYI3"
+            + "FQEEAwIBADANBgkqhkiG9w0BAQUFAAOCAQEAfuZCW3XlB7Eok35zQbvYt9rhAndT"
+            + "DNw3wPNI4ZzD1nXoYWnwhNNvWRpsOt4ExOSNdaHErfgDXAMyyg66Sro0TkAx8eAj"
+            + "fPQsyRAh0nm0glzFmJN6TdOZbj7hqGZjc4opQ6nZo8h/ULnaEwMIUW4gcSkZt0ww"
+            + "CuErl5NUrN3DpkREeCG/fVvQZ8ays3ibQ5ZCZnYBkLYq/i0r3NLW34WfYhjDY48J"
+            + "oQWtvFSAxvRfz2NGmqnrCHPQZxqlfdta97kDa4VQ0zSeBaC70gZkLmD1GJMxWoXW"
+            + "6tmEcgPY5SghInUf+L2u52V55MjyAFzVp7kTK2KY+p7qw35vzckrWkwu8AAAAAAA"
+            + "AQE=");
+
+        private static readonly byte[] secWithPersonalCertificate = Base64.Decode(
+            "lQOYBEjGLGsBCACp1I1dZKsK4N/I0/4g02hDVNLdQkDZfefduJgyJUyBGo/I"
+            + "/ZBpc4vT1YwVIdic4ADjtGB4+7WohN4v8siGzwRSeXardSdZVIw2va0JDsQC"
+            + "yeoTnwVkUgn+w/MDgpL0BBhTpr9o3QYoo28/qKMni3eA8JevloZqlAbQ/sYq"
+            + "rToMAqn0EIdeVVh6n2lRQhUJaNkH/kA5qWBpI+eI8ot/Gm9kAy3i4e0Xqr3J"
+            + "Ff1lkGlZuV5H5p/ItZui9BDIRn4IDaeR511NQnKlxFalM/gP9R9yDVI1aXfy"
+            + "STcp3ZcsTOTGNzACtpvMvl6LZyL42DyhlOKlJQJS81wp4dg0LNrhMFOtABEB"
+            + "AAEAB/0QIH5UEg0pTqAG4r/3v1uKmUbKJVJ3KhJB5xeSG3dKWIqy3AaXR5ZN"
+            + "mrJfXK7EfC5ZcSAqx5br1mzVl3PHVBKQVQxvIlmG4r/LKvPVhQYZUFyJWckZ"
+            + "9QMR+EA0Dcran9Ds5fa4hH84jgcwalkj64XWRAKDdVh098g17HDw+IYnQanl"
+            + "7IXbYvh+1Lr2HyPo//vHX8DxXIJBv+E4skvqGoNfCIfwcMeLsrI5EKo+D2pu"
+            + "kAuBYI0VBiZkrJHFXWmQLW71Mc/Bj7wTG8Q1pCpu7YQ7acFSv+/IOCsB9l9S"
+            + "vdB7pNhB3lEjYFGoTgr03VfeixA7/x8uDuSXjnBdTZqmGqkZBADNwCqlzdaQ"
+            + "X6CjS5jc3vzwDSPgM7ovieypEL6NU3QDEUhuP6fVvD2NYOgVnAEbJzgOleZS"
+            + "W2AFXKAf5NDxfqHnBmo/jlYb5yZV5Y+8/poLLj/m8t7sAfAmcZqGXfYMbSbe"
+            + "tr6TGTUXcXgbRyU5oH1e4iq691LOwZ39QjL8lNQQywQA006XYEr/PS9uJkyM"
+            + "Cg+M+nmm40goW4hU/HboFh9Ru6ataHj+CLF42O9sfMAV02UcD3Agj6w4kb5L"
+            + "VswuwfmY+17IryT81d+dSmDLhpo6ufKoAp4qrdP+bzdlbfIim4Rdrw5vF/Yk"
+            + "rC/Nfm3CLJxTimHJhqFx4MG7yEC89lxgdmcD/iJ3m41fwS+bPN2rrCAf7j1u"
+            + "JNr/V/8GAnoXR8VV9150BcOneijftIIYKKyKkV5TGwcTfjaxRKp87LTeC3MV"
+            + "szFDw04MhlIKRA6nBdU0Ay8Yu+EjXHK2VSpLG/Ny+KGuNiFzhqgBxM8KJwYA"
+            + "ISa1UEqWjXoLU3qu1aD7cCvANPVCOASwAYe0GlBHUCBEZXNrdG9wIDxpbmZv"
+            + "QHBncC5jb20+sAMD//+JAW4EEAECAFgFAkjGLGswFIAAAAAAIAAHcHJlZmVy"
+            + "cmVkLWVtYWlsLWVuY29kaW5nQHBncC5jb21wZ3BtaW1lBwsJCAcDAgoCGQEF"
+            + "GwMAAAADFgECBR4BAAAABRUCCAkKAAoJEHHHqp2m1tlWsx8H/icpHl1Nw17A"
+            + "D6MJN6zJm+aGja+5BOFxOsntW+IV6JI+l5WwiIVE8xTDhoXW4zdH3IZTqoyY"
+            + "frtkqLGpvsPtAQmV6eiPgE3+25ahL+MmjXKsceyhbZeCPDtM2M382VCHYCZK"
+            + "DZ4vrHVgK/BpyTeP/mqoWra9+F5xErhody71/cLyIdImLqXgoAny6YywjuAD"
+            + "2TrFnzPEBmZrkISHVEso+V9sge/8HsuDqSI03BAVWnxcg6aipHtxm907sdVo"
+            + "jzl2yFbxCCCaDIKR7XVbmdX7VZgCYDvNSxX3WEOgFq9CYl4ZlXhyik6Vr4XP"
+            + "7EgqadtfwfMcf4XrYoImSQs0gPOd4QqwAWedA5gESMYsawEIALiazFREqBfi"
+            + "WouTjIdLuY09Ks7PCkn0eo/i40/8lEj1R6JKFQ5RlHNnabh+TLvjvb3nOSU0"
+            + "sDg+IKK/JUc8/Fo7TBdZvARX6BmltEGakqToDC3eaF9EQgHLEhyE/4xXiE4H"
+            + "EeIQeCHdC7k0pggEuWUn5lt6oeeiPUWhqdlUOvzjG+jqMPJL0bk9STbImHUR"
+            + "EiugCPTekC0X0Zn0yrwyqlJQMWnh7wbSl/uo4q45K7qOhxcijo+hNNrkRAMi"
+            + "fdNqD4s5qDERqqHdAAgpWqydo7zV5tx0YSz5fjh59Z7FxkUXpcu1WltT6uVn"
+            + "hubiMTWpXzXOQI8wZL2fb12JmRY47BEAEQEAAQAH+wZBeanj4zne+fBHrWAS"
+            + "2vx8LYiRV9EKg8I/PzKBVdGUnUs0vTqtXU1dXGXsAsPtu2r1bFh0TQH06gR1"
+            + "24iq2obgwkr6x54yj+sZlE6SU0SbF/mQc0NCNAXtSKV2hNXvy+7P+sVJR1bn"
+            + "b5ukuvkj1tgEln/0W4r20qJ60F+M5QxXg6kGh8GAlo2tetKEv1NunAyWY6iv"
+            + "FTnSaIJ/YaKQNcudNvOJjeIakkIzfzBL+trUiI5n1LTBB6+u3CF/BdZBTxOy"
+            + "QwjAh6epZr+GnQqeaomFxBc3mU00sjrsB1Loso84UIs6OKfjMkPoZWkQrQQW"
+            + "+xvQ78D33YwqNfXk/5zQAxkEANZxJGNKaAeDpN2GST/tFZg0R5GPC7uWYC7T"
+            + "pG100mir9ugRpdeIFvfAa7IX2jujxo9AJWo/b8hq0q0koUBdNAX3xxUaWy+q"
+            + "KVCRxBifpYVBfEViD3lsbMy+vLYUrXde9087YD0c0/XUrj+oowWJavblmZtS"
+            + "V9OjkQW9zoCigpf5BADcYV+6bkmJtstxJopJG4kD/lr1o35vOEgLkNsMLayc"
+            + "NuzES084qP+8yXPehkzSsDB83kc7rKfQCQMZ54V7KCCz+Rr4wVG7FCrFAw4e"
+            + "4YghfGVU/5whvbJohl/sXXCYGtVljvY/BSQrojRdP+/iZxFbeD4IKiTjV+XL"
+            + "WKSS56Fq2QQAzeoKBJFUq8nqc8/OCmc52WHSOLnB4AuHL5tNfdE9tjqfzZAE"
+            + "tx3QB7YGGP57tPQxPFDFJVRJDqw0YxI2tG9Pum8iriKGjHg+oEfFhxvCmPxf"
+            + "zDKaGibkLeD7I6ATpXq9If+Nqb5QjzPjFbXBIz/q2nGjamZmp4pujKt/aZxF"
+            + "+YRCebABh4kCQQQYAQIBKwUCSMYsbAUbDAAAAMBdIAQZAQgABgUCSMYsawAK"
+            + "CRCrkqZshpdZSNAiB/9+5nAny2O9/lp2K2z5KVXqlNAHUmd4S/dpqtsZCbAo"
+            + "8Lcr/VYayrNojga1U7cyhsvFky3N9wczzPHq3r9Z+R4WnRM1gpRWl+9+xxtd"
+            + "ZxGfGzMRlxX1n5rCqltKKk6IKuBAr2DtTnxThaQiISO2hEw+P1MT2HnSzMXt"
+            + "zse5CZ5OiOd/bm/rdvTRD/JmLqhXmOFaIwzdVP0dR9Ld4Dug2onOlIelIntC"
+            + "cywY6AmnL0DThaTy5J8MiMSPamSmATl4Bicm8YRbHHz58gCYxI5UMLwtwR1+"
+            + "rSEmrB6GwVHZt0/BzOpuGpvFZI5ZmC5yO/waR1hV+VYj025cIz+SNuDPyjy4"
+            + "AAoJEHHHqp2m1tlW/w0H/3w38SkB5n9D9JL3chp+8fex03t7CQowVMdsBYNY"
+            + "qI4QoVQkakkxzCz5eF7rijXt5eC3NE/quWhlMigT8LARiwBROBWgDRFW4WuX"
+            + "6MwYtjKKUkZSkBKxP3lmaqZrJpF6jfhPEN76zr/NxWPC/nHRNldUdqkzSu/r"
+            + "PeJyePMofJevzMkUzw7EVtbtWhZavCz+EZXRTZXub9M4mDMj64BG6JHMbVZI"
+            + "1iDF2yka5RmhXz9tOhYgq80m7UQUb1ttNn86v1zVbe5lmB8NG4Ndv+JaaSuq"
+            + "SBZOYQ0ZxtMAB3vVVLZCWxma1P5HdXloegh+hosqeu/bl0Wh90z5Bspt6eI4"
+            + "imqwAWeVAdgESMYtmwEEAM9ZeMFxor7oSoXnhQAXD9lXLLfBky6IcIWISY4F"
+            + "JWc8sK8+XiVzpOrefKro0QvmEGSYcDFQMHdScBLOTsiVJiqenA7fg1bkBr/M"
+            + "bnD7vTKMJe0DARlU27tE5hsWCDYTluxIFjGcAcecY2UqHkqpctYKY0WY9EIm"
+            + "dBA5TYaw3c0PABEBAAEAA/0Zg6318nC57cWLIp5dZiO/dRhTPZD0hI+BWZrg"
+            + "zJtPT8rXVY+qK3Jwquig8z29/r+nppEE+xQWVWDlv4M28BDJAbGE+qWKAZqT"
+            + "67lyKgc0c50W/lfbGvvs+F7ldCcNpFvlk79GODKxcEeTGDQKb9R6FnHFee/K"
+            + "cZum71O3Ku3vUQIA3B3PNM+tKocIUNDHnInuLyqLORwQBNGfjU/pLMM0MkpP"
+            + "lWeIfgUmn2zL/e0JrRoO0LQqX1LN/TlfcurDM0SEtwIA8Sba9OpDq99Yz360"
+            + "FiePJiGNNlbj9EZsuGJyMVXL1mTLA6WHnz5XZOfYqJXHlmKvaKDbARW4+0U7"
+            + "0/vPdYWSaQIAwYeo2Ce+b7M5ifbGMDWYBisEvGISg5xfvbe6qApmHS4QVQzE"
+            + "Ym81rdJJ8OfvgSbHcgn37S3OBXIQvNdejF4BWqM9sAGHtCBIeW5lay1JbnRy"
+            + "YW5ldCA8aHluZWtAYWxzb2Z0LmN6PrADA///iQDrBBABAgBVBQJIxi2bBQkB"
+            + "mgKAMBSAAAAAACAAB3ByZWZlcnJlZC1lbWFpbC1lbmNvZGluZ0BwZ3AuY29t"
+            + "cGdwbWltZQULBwgJAgIZAQUbAQAAAAUeAQAAAAIVAgAKCRDlTa3BE84gWVKW"
+            + "BACcoCFKvph9r9QiHT1Z3N4wZH36Uxqu/059EFALnBkEdVudX/p6S9mynGRk"
+            + "EfhmWFC1O6dMpnt+ZBEed/4XyFWVSLPwirML+6dxfXogdUsdFF1NCRHc3QGc"
+            + "txnNUT/zcZ9IRIQjUhp6RkIvJPHcyfTXKSbLviI+PxzHU2Padq8pV7ABZ7kA"
+            + "jQRIfg8tAQQAutJR/aRnfZYwlVv+KlUDYjG8YQUfHpTxpnmVu7W6N0tNg/Xr"
+            + "5dg50wq3I4HOamRxUwHpdPkXyNF1szpDSRZmlM+VmiIvJDBnyH5YVlxT6+zO"
+            + "8LUJ2VTbfPxoLFp539SQ0oJOm7IGMAGO7c0n/QV0N3hKUfWgCyJ+sENDa0Ft"
+            + "JycAEQEAAbABj4kEzQQYAQIENwUCSMYtnAUJAeEzgMLFFAAAAAAAFwNleDUw"
+            + "OWNlcnRpZmljYXRlQHBncC5jb20wggNhMIICyqADAgECAgkA1AoCoRKJCgsw"
+            + "DQYJKoZIhvcNAQEFBQAwgakxCzAJBgNVBAYTAkNaMRcwFQYDVQQIEw5DemVj"
+            + "aCBSZXB1YmxpYzESMBAGA1UEChQJQSYmTCBzb2Z0MSAwHgYDVQQLExdJbnRl"
+            + "cm5hbCBEZXZlbG9wbWVudCBDQTEqMCgGA1UEAxQhQSYmTCBzb2Z0IEludGVy"
+            + "bmFsIERldmVsb3BtZW50IENBMR8wHQYJKoZIhvcNAQkBFhBrYWRsZWNAYWxz"
+            + "b2Z0LmN6MB4XDTA4MDcxNjE1MDkzM1oXDTA5MDcxNjE1MDkzM1owaTELMAkG"
+            + "A1UEBhMCQ1oxFzAVBgNVBAgTDkN6ZWNoIFJlcHVibGljMRIwEAYDVQQKFAlB"
+            + "JiZMIHNvZnQxFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5IeW5l"
+            + "ay1JbnRyYW5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAutJR/aRn"
+            + "fZYwlVv+KlUDYjG8YQUfHpTxpnmVu7W6N0tNg/Xr5dg50wq3I4HOamRxUwHp"
+            + "dPkXyNF1szpDSRZmlM+VmiIvJDBnyH5YVlxT6+zO8LUJ2VTbfPxoLFp539SQ"
+            + "0oJOm7IGMAGO7c0n/QV0N3hKUfWgCyJ+sENDa0FtJycCAwEAAaOBzzCBzDAJ"
+            + "BgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBD"
+            + "ZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUNaw7A6r10PtYZzAvr9CrSKeRYJgwHwYD"
+            + "VR0jBBgwFoAUmqSRM8rN3+T1+tkGiqef8S5suYgwGgYDVR0RBBMwEYEPaHlu"
+            + "ZWtAYWxzb2Z0LmN6MCgGA1UdHwQhMB8wHaAboBmGF2h0dHA6Ly9wZXRyazIv"
+            + "Y2EvY2EuY3JsMAsGA1UdDwQEAwIF4DANBgkqhkiG9w0BAQUFAAOBgQCUdOWd"
+            + "7mBLWj1/GSiYgfwgdTrgk/VZOJvMKBiiFyy1iFEzldz6Xx+mAexnFJKfZXZb"
+            + "EMEGWHfWPmgJzAtuTT0Jz6tUwDmeLH3MP4m8uOZtmyUJ2aq41kciV3rGxF0G"
+            + "BVlZ/bWTaOzHdm6cjylt6xxLt6MJzpPBA/9ZfybSBh1DaAUbDgAAAJ0gBBkB"
+            + "AgAGBQJIxi2bAAoJEAdYkEWLb2R2fJED/RK+JErZ98uGo3Z81cHkdP3rk8is"
+            + "DUL/PR3odBPFH2SIA5wrzklteLK/ZXmBUzcvxqHEgI1F7goXbsBgeTuGgZdx"
+            + "pINErxkNpcMl9FTldWKGiapKrhkZ+G8knDizF/Y7Lg6uGd2nKVxzutLXdHJZ"
+            + "pU89Q5nzq6aJFAZo5TBIcchQAAoJEOVNrcETziBZXvQD/1mvFqBfWqwXxoj3"
+            + "8fHUuFrE2pcp32y3ciO2i+uNVEkNDoaVVNw5eHQaXXWpllI/Pe6LnBl4vkyc"
+            + "n3pjONa4PKrePkEsCUhRbIySqXIHuNwZumDOlKzZHDpCUw72LaC6S6zwuoEf"
+            + "ucOcxTeGIUViANWXyTIKkHfo7HfigixJIL8nsAFn");
+
+        [Test]
+        public void PerformTest1()
+        {
+            PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(pub1);
+
+            int count = 0;
+
+            foreach (PgpPublicKeyRing pgpPub1 in pubRings.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+                byte[] bytes = pgpPub1.GetEncoded();
+
+                PgpPublicKeyRing pgpPub2 = new PgpPublicKeyRing(bytes);
+
+                foreach (PgpPublicKey pubKey in pgpPub2.GetPublicKeys())
+                {
+                    keyCount++;
+
+                    foreach (PgpSignature sig in pubKey.GetSignatures())
+                    {
+                        if (sig == null)
+                            Fail("null signature found");
+                    }
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of public keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of public keyrings");
+            }
+
+            //
+            // exact match
+            //
+            count = 0;
+            foreach (PgpPublicKeyRing pgpPub3 in pubRings.GetKeyRings("test (Test key) <test@ubicall.com>"))
+            {
+                if (pgpPub3 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of public keyrings on exact match");
+            }
+
+            //
+            // partial match 1 expected
+            //
+            count = 0;
+            foreach (PgpPublicKeyRing pgpPub4 in pubRings.GetKeyRings("test", true))
+            {
+                if (pgpPub4 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of public keyrings on partial match 1");
+            }
+
+            //
+            // partial match 0 expected
+            //
+            count = 0;
+            foreach (PgpPublicKeyRing pgpPub5 in pubRings.GetKeyRings("XXX", true))
+            {
+                if (pgpPub5 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 0)
+            {
+                Fail("wrong number of public keyrings on partial match 0");
+            }
+
+            //
+            // case-insensitive partial match
+            //
+            count = 0;
+            foreach (PgpPublicKeyRing pgpPub6 in pubRings.GetKeyRings("TEST@ubicall.com", true, true))
+            {
+                if (pgpPub6 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of public keyrings on case-insensitive partial match");
+            }
+
+            PgpSecretKeyRingBundle secretRings = new PgpSecretKeyRingBundle(sec1);
+            count = 0;
+
+            foreach (PgpSecretKeyRing pgpSec1 in secretRings.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpSec1.GetEncoded();
+
+                PgpSecretKeyRing pgpSec2 = new PgpSecretKeyRing(bytes);
+
+                foreach (PgpSecretKey k in pgpSec2.GetSecretKeys())
+                {
+                    keyCount++;
+                    PgpPublicKey pk = k.PublicKey;
+
+                    pk.GetSignatures();
+
+                    byte[] pkBytes = pk.GetEncoded();
+
+                    PgpPublicKeyRing pkR = new PgpPublicKeyRing(pkBytes);
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of secret keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings");
+            }
+
+            //
+            // exact match
+            //
+            count = 0;
+            foreach (PgpSecretKeyRing o1 in secretRings.GetKeyRings("test (Test key) <test@ubicall.com>"))
+            {
+                if (o1 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings on exact match");
+            }
+
+            //
+            // partial match 1 expected
+            //
+            count = 0;
+            foreach (PgpSecretKeyRing o2 in secretRings.GetKeyRings("test", true))
+            {
+                if (o2 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings on partial match 1");
+            }
+
+            //
+            // exact match 0 expected
+            //
+            count = 0;
+            foreach (PgpSecretKeyRing o3 in secretRings.GetKeyRings("test", false))
+            {
+                if (o3 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 0)
+            {
+                Fail("wrong number of secret keyrings on partial match 0");
+            }
+
+            //
+            // case-insensitive partial match
+            //
+            count = 0;
+            foreach (PgpSecretKeyRing o4 in secretRings.GetKeyRings("TEST@ubicall.com", true, true))
+            {
+                if (o4 == null)
+                    Fail("null keyring found");
+
+                count++;
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings on case-insensitive partial match");
+            }
+        }
+
+        [Test]
+        public void PerformTest2()
+        {
+            PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(pub2);
+
+            int count = 0;
+
+            byte[] encRing = pubRings.GetEncoded();
+
+            pubRings = new PgpPublicKeyRingBundle(encRing);
+
+            foreach (PgpPublicKeyRing pgpPub1 in pubRings.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpPub1.GetEncoded();
+
+                PgpPublicKeyRing pgpPub2 = new PgpPublicKeyRing(bytes);
+
+                foreach (PgpPublicKey pk in pgpPub2.GetPublicKeys())
+                {
+                    byte[] pkBytes = pk.GetEncoded();
+
+                    PgpPublicKeyRing pkR = new PgpPublicKeyRing(pkBytes);
+
+                    keyCount++;
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of public keys");
+                }
+            }
+
+            if (count != 2)
+            {
+                Fail("wrong number of public keyrings");
+            }
+
+            PgpSecretKeyRingBundle secretRings2 = new PgpSecretKeyRingBundle(sec2);
+
+            count = 0;
+
+
+            encRing = secretRings2.GetEncoded();
+            PgpSecretKeyRingBundle secretRings = new PgpSecretKeyRingBundle(encRing);
+
+            foreach (PgpSecretKeyRing pgpSec1 in secretRings2.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpSec1.GetEncoded();
+
+                PgpSecretKeyRing pgpSec2 = new PgpSecretKeyRing(bytes);
+
+                foreach (PgpSecretKey k in pgpSec2.GetSecretKeys())
+                {
+                    keyCount++;
+                    PgpPublicKey pk = k.PublicKey;
+
+                    if (pk.KeyId == -1413891222336124627L)
+                    {
+                        int sCount = 0;
+
+                        foreach (PgpSignature pgpSignature in pk.GetSignaturesOfType(PgpSignature.SubkeyBinding))
+                        {
+                            int type = pgpSignature.SignatureType;
+                            if (type != PgpSignature.SubkeyBinding)
+                            {
+                                Fail("failed to return correct signature type");
+                            }
+                            sCount++;
+                        }
+
+                        if (sCount != 1)
+                        {
+                            Fail("failed to find binding signature");
+                        }
+                    }
+
+                    pk.GetSignatures();
+
+                    if (k.KeyId == -4049084404703773049L
+                        || k.KeyId == -1413891222336124627L)
+                    {
+                        k.ExtractPrivateKey(sec2pass1);
+                    }
+                    else if (k.KeyId == -6498553574938125416L
+                        || k.KeyId == 59034765524361024L)
+                    {
+                        k.ExtractPrivateKey(sec2pass2);
+                    }
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of secret keys");
+                }
+            }
+
+            if (count != 2)
+            {
+                Fail("wrong number of secret keyrings");
+            }
+        }
+
+        [Test]
+        public void PerformTest3()
+        {
+            PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(pub3);
+
+            int count = 0;
+
+            byte[] encRing = pubRings.GetEncoded();
+
+            pubRings = new PgpPublicKeyRingBundle(encRing);
+
+            foreach (PgpPublicKeyRing pgpPub1 in pubRings.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpPub1.GetEncoded();
+
+                PgpPublicKeyRing pgpPub2 = new PgpPublicKeyRing(bytes);
+
+                foreach (PgpPublicKey pubK in pgpPub2.GetPublicKeys())
+                {
+                    keyCount++;
+                    pubK.GetSignatures();
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of public keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of public keyrings");
+            }
+
+            PgpSecretKeyRingBundle secretRings2 = new PgpSecretKeyRingBundle(sec3);
+
+            count = 0;
+
+            encRing = secretRings2.GetEncoded();
+
+            PgpSecretKeyRingBundle secretRings = new PgpSecretKeyRingBundle(encRing);
+
+            foreach (PgpSecretKeyRing pgpSec1 in secretRings2.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpSec1.GetEncoded();
+
+                PgpSecretKeyRing pgpSec2 = new PgpSecretKeyRing(bytes);
+
+                foreach (PgpSecretKey k in pgpSec2.GetSecretKeys())
+                {
+                    keyCount++;
+                    k.ExtractPrivateKey(sec3pass1);
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of secret keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings");
+            }
+        }
+
+        [Test]
+        public void PerformTest4()
+        {
+            PgpSecretKeyRingBundle secretRings1 = new PgpSecretKeyRingBundle(sec4);
+            int count = 0;
+
+
+            byte[] encRing = secretRings1.GetEncoded();
+
+            PgpSecretKeyRingBundle secretRings2 = new PgpSecretKeyRingBundle(encRing);
+
+            foreach (PgpSecretKeyRing pgpSec1 in secretRings1.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpSec1.GetEncoded();
+
+                PgpSecretKeyRing pgpSec2 = new PgpSecretKeyRing(bytes);
+
+                foreach (PgpSecretKey k in pgpSec2.GetSecretKeys())
+                {
+                    keyCount++;
+                    k.ExtractPrivateKey(sec3pass1);
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of secret keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings");
+            }
+        }
+
+        [Test]
+        public void PerformTest5()
+        {
+            PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(pub5);
+
+            int count = 0;
+
+            byte[] encRing = pubRings.GetEncoded();
+
+            pubRings = new PgpPublicKeyRingBundle(encRing);
+
+            foreach (PgpPublicKeyRing pgpPub1 in pubRings.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpPub1.GetEncoded();
+
+                PgpPublicKeyRing pgpPub2 = new PgpPublicKeyRing(bytes);
+
+                foreach (PgpPublicKey o in pgpPub2.GetPublicKeys())
+                {
+                    if (o == null)
+                        Fail("null keyring found");
+
+                    keyCount++;
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of public keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of public keyrings");
+            }
+
+            PgpSecretKeyRingBundle secretRings1 = new PgpSecretKeyRingBundle(sec5);
+
+            count = 0;
+
+            encRing = secretRings1.GetEncoded();
+
+            PgpSecretKeyRingBundle secretRings2 = new PgpSecretKeyRingBundle(encRing);
+
+            foreach (PgpSecretKeyRing pgpSec1 in secretRings1.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpSec1.GetEncoded();
+
+                PgpSecretKeyRing pgpSec2 = new PgpSecretKeyRing(bytes);
+
+                foreach (PgpSecretKey k in pgpSec2.GetSecretKeys())
+                {
+                    keyCount++;
+                    k.ExtractPrivateKey(sec5pass1);
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of secret keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings");
+            }
+        }
+
+        [Test]
+        public void PerformTest6()
+        {
+            PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(pub6);
+
+            foreach (PgpPublicKeyRing pgpPub in pubRings.GetKeyRings())
+            {
+                foreach (PgpPublicKey k in pgpPub.GetPublicKeys())
+                {
+                    if (k.KeyId == 0x5ce086b5b5a18ff4L)
+                    {
+                        int count = 0;
+
+                        foreach (PgpSignature sig in k.GetSignaturesOfType(PgpSignature.SubkeyRevocation))
+                        {
+                            if (sig == null)
+                                Fail("null signature found");
+
+                            count++;
+                        }
+
+                        if (count != 1)
+                        {
+                            Fail("wrong number of revocations in test6.");
+                        }
+                    }
+                }
+            }
+
+            byte[] encRing = pubRings.GetEncoded();
+        }
+
+        [Test, Explicit]
+        public void PerformTest7()
+        {
+            PgpPublicKeyRing pgpPub = new PgpPublicKeyRing(pub7);
+            PgpPublicKey masterKey = null;
+
+            foreach (PgpPublicKey k in pgpPub.GetPublicKeys())
+            {
+                if (k.IsMasterKey)
+                {
+                    masterKey = k;
+                    continue;
+                }
+
+                int count = 0;
+                PgpSignature sig = null;
+
+                foreach (PgpSignature sigTemp in k.GetSignaturesOfType(PgpSignature.SubkeyRevocation))
+                {
+                    sig = sigTemp;
+                    count++;
+                }
+
+                if (count != 1)
+                {
+                    Fail("wrong number of revocations in test7.");
+                }
+
+                sig.InitVerify(masterKey);
+
+                if (!sig.VerifyCertification(k))
+                {
+                    Fail("failed to verify revocation certification");
+                }
+            }
+        }
+
+        [Test]
+        public void PerformTest8()
+        {
+            PgpPublicKeyRingBundle pubRings = new PgpPublicKeyRingBundle(pub8);
+
+            int count = 0;
+
+            byte[] encRing = pubRings.GetEncoded();
+
+            pubRings = new PgpPublicKeyRingBundle(encRing);
+
+            foreach (PgpPublicKeyRing pgpPub1 in pubRings.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpPub1.GetEncoded();
+
+                PgpPublicKeyRing pgpPub2 = new PgpPublicKeyRing(bytes);
+
+                foreach (PgpPublicKey o in pgpPub2.GetPublicKeys())
+                {
+                    if (o == null)
+                        Fail("null key found");
+
+                    keyCount++;
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of public keys");
+                }
+            }
+
+            if (count != 2)
+            {
+                Fail("wrong number of public keyrings");
+            }
+
+            PgpSecretKeyRingBundle secretRings1 = new PgpSecretKeyRingBundle(sec8);
+
+            count = 0;
+
+            encRing = secretRings1.GetEncoded();
+
+            PgpSecretKeyRingBundle secretRings2 = new PgpSecretKeyRingBundle(encRing);
+
+            foreach (PgpSecretKeyRing pgpSec1 in secretRings1.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpSec1.GetEncoded();
+
+                PgpSecretKeyRing pgpSec2 = new PgpSecretKeyRing(bytes);
+
+                foreach (PgpSecretKey k in pgpSec2.GetSecretKeys())
+                {
+                    keyCount++;
+                    k.ExtractPrivateKey(sec8pass);
+                }
+
+                if (keyCount != 2)
+                {
+                    Fail("wrong number of secret keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings");
+            }
+        }
+
+        [Test]
+        public void PerformTest9()
+        {
+            PgpSecretKeyRingBundle secretRings1 = new PgpSecretKeyRingBundle(sec9);
+
+            int count = 0;
+
+            byte[] encRing = secretRings1.GetEncoded();
+
+            PgpSecretKeyRingBundle secretRings2 = new PgpSecretKeyRingBundle(encRing);
+
+            foreach (PgpSecretKeyRing pgpSec1 in secretRings1.GetKeyRings())
+            {
+                count++;
+
+                int keyCount = 0;
+
+                byte[] bytes = pgpSec1.GetEncoded();
+
+                PgpSecretKeyRing pgpSec2 = new PgpSecretKeyRing(bytes);
+
+                foreach (PgpSecretKey k in pgpSec2.GetSecretKeys())
+                {
+                    keyCount++;
+
+                    PgpPrivateKey pKey = k.ExtractPrivateKey(sec9pass);
+                    if (keyCount == 1 && pKey != null)
+                    {
+                        Fail("primary secret key found, null expected");
+                    }
+                }
+
+                if (keyCount != 3)
+                {
+                    Fail("wrong number of secret keys");
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("wrong number of secret keyrings");
+            }
+        }
+
+        [Test]
+        public void PerformTest10()
+        {
+            PgpSecretKeyRing secretRing = new PgpSecretKeyRing(sec10);
+
+            foreach (PgpSecretKey secretKey in secretRing.GetSecretKeys())
+            {
+                PgpPublicKey pubKey = secretKey.PublicKey;
+
+                if (pubKey.ValidDays != 28)
+                {
+                    Fail("days wrong on secret key ring");
+                }
+
+                if (pubKey.GetValidSeconds() != 28 * 24 * 60 * 60)
+                {
+                    Fail("seconds wrong on secret key ring");
+                }
+            }
+
+            PgpPublicKeyRing publicRing = new PgpPublicKeyRing(pub10);
+
+            foreach (PgpPublicKey pubKey in publicRing.GetPublicKeys())
+            {
+                if (pubKey.ValidDays != 28)
+                {
+                    Fail("days wrong on public key ring");
+                }
+
+                if (pubKey.GetValidSeconds() != 28 * 24 * 60 * 60)
+                {
+                    Fail("seconds wrong on public key ring");
+                }
+            }
+        }
+
+        [Test]
+        public void PerformTest11()
+        {
+            PgpPublicKeyRing pubRing = new PgpPublicKeyRing(subKeyBindingKey);
+
+            foreach (PgpPublicKey key in pubRing.GetPublicKeys())
+            {
+                if (key.GetValidSeconds() != 0)
+                {
+                    Fail("expiration time non-zero");
+                }
+            }
+        }
+
+        [Test]
+        public void GenerateTest()
+        {
+            char[] passPhrase = "hello".ToCharArray();
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+            pGen.Init(512, 80, new SecureRandom());
+            DsaParameters dsaParams = pGen.GenerateParameters();
+            DsaKeyGenerationParameters dsaKgp = new DsaKeyGenerationParameters(new SecureRandom(), dsaParams);
+            IAsymmetricCipherKeyPairGenerator dsaKpg = GeneratorUtilities.GetKeyPairGenerator("DSA");
+            dsaKpg.Init(dsaKgp);
+
+
+            //
+            // this takes a while as the key generator has to Generate some DSA parameters
+            // before it Generates the key.
+            //
+            AsymmetricCipherKeyPair dsaKp = dsaKpg.GenerateKeyPair();
+            IAsymmetricCipherKeyPairGenerator elgKpg = GeneratorUtilities.GetKeyPairGenerator("ELGAMAL");
+
+            BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+            BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+            ElGamalParameters elParams = new ElGamalParameters(p, g);
+            ElGamalKeyGenerationParameters elKgp = new ElGamalKeyGenerationParameters(new SecureRandom(), elParams);
+            elgKpg.Init(elKgp);
+
+            //
+            // this is quicker because we are using preGenerated parameters.
+            //
+            AsymmetricCipherKeyPair elgKp = elgKpg.GenerateKeyPair();
+            PgpKeyPair dsaKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.Dsa, dsaKp, DateTime.UtcNow);
+            PgpKeyPair elgKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.ElGamalEncrypt, elgKp, DateTime.UtcNow);
+
+            PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification, dsaKeyPair,
+                "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, null, null, new SecureRandom());
+
+            keyRingGen.AddSubKey(elgKeyPair);
+
+            PgpSecretKeyRing keyRing = keyRingGen.GenerateSecretKeyRing();
+
+            keyRing.GetSecretKey().ExtractPrivateKey(passPhrase);
+
+            PgpPublicKeyRing pubRing = keyRingGen.GeneratePublicKeyRing();
+
+            PgpPublicKey vKey = null;
+            PgpPublicKey sKey = null;
+
+            foreach (PgpPublicKey pk in pubRing.GetPublicKeys())
+            {
+                if (pk.IsMasterKey)
+                {
+                    vKey = pk;
+                }
+                else
+                {
+                    sKey = pk;
+                }
+            }
+
+            foreach (PgpSignature sig in sKey.GetSignatures())
+            {
+                if (sig.KeyId == vKey.KeyId
+                    && sig.SignatureType == PgpSignature.SubkeyBinding)
+                {
+                    sig.InitVerify(vKey);
+
+                    if (!sig.VerifyCertification(vKey, sKey))
+                    {
+                        Fail("failed to verify sub-key signature.");
+                    }
+                }
+            }
+        }
+
+        [Test]
+        public void InsertMasterTest()
+        {
+            SecureRandom random = new SecureRandom();
+
+            char[] passPhrase = "hello".ToCharArray();
+            IAsymmetricCipherKeyPairGenerator rsaKpg = GeneratorUtilities.GetKeyPairGenerator("RSA");
+
+            rsaKpg.Init(new KeyGenerationParameters(random, 512));
+
+            //
+            // this is quicker because we are using pregenerated parameters.
+            //
+            AsymmetricCipherKeyPair rsaKp = rsaKpg.GenerateKeyPair();
+            PgpKeyPair rsaKeyPair1 = new PgpKeyPair(PublicKeyAlgorithmTag.RsaGeneral, rsaKp, DateTime.UtcNow);
+
+            rsaKp = rsaKpg.GenerateKeyPair();
+            PgpKeyPair rsaKeyPair2 = new PgpKeyPair(PublicKeyAlgorithmTag.RsaGeneral, rsaKp, DateTime.UtcNow);
+
+            PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification,
+                rsaKeyPair1, "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, null, null, random);
+            PgpSecretKeyRing secRing1 = keyRingGen.GenerateSecretKeyRing();
+            PgpPublicKeyRing pubRing1 = keyRingGen.GeneratePublicKeyRing();
+
+            keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification,
+                rsaKeyPair2, "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, null, null, random);
+            PgpSecretKeyRing secRing2 = keyRingGen.GenerateSecretKeyRing();
+            PgpPublicKeyRing pubRing2 = keyRingGen.GeneratePublicKeyRing();
+
+            try
+            {
+                PgpPublicKeyRing.InsertPublicKey(pubRing1, pubRing2.GetPublicKey());
+                Fail("adding second master key (public) should throw an ArgumentException");
+            }
+            catch (ArgumentException e)
+            {
+                if (!e.Message.Equals("cannot add a master key to a ring that already has one"))
+                {
+                    Fail("wrong message in public test");
+                }
+            }
+
+            try
+            {
+                PgpSecretKeyRing.InsertSecretKey(secRing1, secRing2.GetSecretKey());
+                Fail("adding second master key (secret) should throw an ArgumentException");
+            }
+            catch (ArgumentException e)
+            {
+                if (!e.Message.Equals("cannot add a master key to a ring that already has one"))
+                {
+                    Fail("wrong message in secret test");
+                }
+            }
+        }
+
+        [Test]
+        public void GenerateSha1Test()
+        {
+            char[] passPhrase = "hello".ToCharArray();
+
+            IAsymmetricCipherKeyPairGenerator dsaKpg = GeneratorUtilities.GetKeyPairGenerator("DSA");
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+            pGen.Init(512, 80, new SecureRandom());
+            DsaParameters dsaParams = pGen.GenerateParameters();
+            DsaKeyGenerationParameters kgp = new DsaKeyGenerationParameters(new SecureRandom(), dsaParams);
+            dsaKpg.Init(kgp);
+
+            //
+            // this takes a while as the key generator has to generate some DSA params
+            // before it generates the key.
+            //
+            AsymmetricCipherKeyPair dsaKp = dsaKpg.GenerateKeyPair();
+
+
+            IAsymmetricCipherKeyPairGenerator elgKpg = GeneratorUtilities.GetKeyPairGenerator("ELGAMAL");
+
+            BigInteger g = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+            BigInteger p = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+            ElGamalParameters elParams = new ElGamalParameters(p, g);
+            ElGamalKeyGenerationParameters elKgp = new ElGamalKeyGenerationParameters(new SecureRandom(), elParams);
+            elgKpg.Init(elKgp);
+
+            //
+            // this is quicker because we are using preGenerated parameters.
+            //
+            AsymmetricCipherKeyPair elgKp = elgKpg.GenerateKeyPair();
+
+
+            PgpKeyPair dsaKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.Dsa, dsaKp, DateTime.UtcNow);
+            PgpKeyPair elgKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.ElGamalEncrypt, elgKp, DateTime.UtcNow);
+
+            PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification, dsaKeyPair,
+                "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, true, null, null, new SecureRandom());
+
+            keyRingGen.AddSubKey(elgKeyPair);
+
+            PgpSecretKeyRing keyRing = keyRingGen.GenerateSecretKeyRing();
+
+            keyRing.GetSecretKey().ExtractPrivateKey(passPhrase);
+
+            PgpPublicKeyRing pubRing = keyRingGen.GeneratePublicKeyRing();
+
+            PgpPublicKey vKey = null;
+            PgpPublicKey sKey = null;
+
+            foreach (PgpPublicKey pk in pubRing.GetPublicKeys())
+            {
+                if (pk.IsMasterKey)
+                {
+                    vKey = pk;
+                }
+                else
+                {
+                    sKey = pk;
+                }
+            }
+
+            foreach (PgpSignature sig in sKey.GetSignatures())
+            {
+                if (sig.KeyId == vKey.KeyId
+                    && sig.SignatureType == PgpSignature.SubkeyBinding)
+                {
+                    sig.InitVerify(vKey);
+
+                    if (!sig.VerifyCertification(vKey, sKey))
+                    {
+                        Fail("failed to verify sub-key signature.");
+                    }
+                }
+            }
+        }
+
+        [Test]
+        public void RewrapTest()
+        {
+            SecureRandom rand = new SecureRandom();
+
+            // Read the secret key rings
+            PgpSecretKeyRingBundle privRings = new PgpSecretKeyRingBundle(
+                new MemoryStream(rewrapKey, false));
+
+            foreach (PgpSecretKeyRing pgpPrivEnum in privRings.GetKeyRings())
+            {
+                foreach (PgpSecretKey pgpKeyEnum in pgpPrivEnum.GetSecretKeys())
+                {
+                    // re-encrypt the key with an empty password
+                    PgpSecretKeyRing pgpPriv = PgpSecretKeyRing.RemoveSecretKey(pgpPrivEnum, pgpKeyEnum);
+                    PgpSecretKey pgpKey = PgpSecretKey.CopyWithNewPassword(
+                        pgpKeyEnum,
+                        rewrapPass,
+                        null,
+                        SymmetricKeyAlgorithmTag.Null,
+                        rand);
+                    pgpPriv = PgpSecretKeyRing.InsertSecretKey(pgpPriv, pgpKey);
+
+                    // this should succeed
+                    PgpPrivateKey privTmp = pgpKey.ExtractPrivateKey(null);
+                }
+            }
+        }
+
+        [Test]
+        public void PublicKeyRingWithX509Test()
+        {
+            checkPublicKeyRingWithX509(pubWithX509);
+
+            PgpPublicKeyRing pubRing = new PgpPublicKeyRing(pubWithX509);
+
+            checkPublicKeyRingWithX509(pubRing.GetEncoded());
+        }
+
+        [Test]
+        public void SecretKeyRingWithPersonalCertificateTest()
+        {
+            checkSecretKeyRingWithPersonalCertificate(secWithPersonalCertificate);
+            PgpSecretKeyRingBundle secRing = new PgpSecretKeyRingBundle(secWithPersonalCertificate);
+            checkSecretKeyRingWithPersonalCertificate(secRing.GetEncoded());
+        }
+
+        private void checkSecretKeyRingWithPersonalCertificate(
+            byte[] keyRing)
+        {
+            PgpSecretKeyRingBundle secCol = new PgpSecretKeyRingBundle(keyRing);
+
+            int count = 0;
+
+            foreach (PgpSecretKeyRing ring in secCol.GetKeyRings())
+            {
+                IEnumerator e = ring.GetExtraPublicKeys().GetEnumerator();
+                while (e.MoveNext())
+                {
+                    ++count;
+                }
+            }
+
+            if (count != 1)
+            {
+                Fail("personal certificate data subkey not found - count = " + count);
+            }
+        }
+
+        private void checkPublicKeyRingWithX509(
+            byte[] keyRing)
+        {
+            PgpPublicKeyRing pubRing = new PgpPublicKeyRing(keyRing);
+            IEnumerator en = pubRing.GetPublicKeys().GetEnumerator();
+
+            if (en.MoveNext())
+            {
+                PgpPublicKey key = (PgpPublicKey) en.Current;
+
+                IEnumerator sEn = key.GetSignatures().GetEnumerator();
+
+                if (sEn.MoveNext())
+                {
+                    PgpSignature sig = (PgpSignature) sEn.Current;
+                    if (sig.KeyAlgorithm != PublicKeyAlgorithmTag.Experimental_1)
+                    {
+                        Fail("experimental signature not found");
+                    }
+                    if (!AreEqual(sig.GetSignature(), Hex.Decode("000101")))
+                    {
+                        Fail("experimental encoding check failed");
+                    }
+                }
+                else
+                {
+                    Fail("no signature found");
+                }
+            }
+            else
+            {
+                Fail("no key found");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            PerformTest1();
+            PerformTest2();
+            PerformTest3();
+            PerformTest4();
+            PerformTest5();
+            PerformTest6();
+
+            // NB: This was commented out in the original Java source
+            //PerformTest7();
+
+            PerformTest8();
+            PerformTest9();
+            PerformTest10();
+            PerformTest11();
+
+            GenerateTest();
+            GenerateSha1Test();
+            RewrapTest();
+            PublicKeyRingWithX509Test();
+            SecretKeyRingWithPersonalCertificateTest();
+            InsertMasterTest();
+        }
+
+        public override string Name
+        {
+            get { return "PgpKeyRingTest"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new PgpKeyRingTest());
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/PgpMarkerTest.cs b/crypto/test/src/openpgp/test/PgpMarkerTest.cs
new file mode 100644
index 000000000..89be7cd52
--- /dev/null
+++ b/crypto/test/src/openpgp/test/PgpMarkerTest.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    [TestFixture]
+    public class PgpMarkerTest
+        : SimpleTest
+    {
+        private static readonly byte[] message1 = Base64.Decode(
+            "qANQR1DBwU4DdrlXatQSHgoQCADWlhY3bWWaOTm4t2espRWPFQmETeinnieHce64"
+            + "lmEIFzaryEWeSdQc8XGfDzcb7sxq7b5b9Hm6OrACcCbSp2KGEJNG5kJmo2A16UPq"
+            + "JdK4xNelpJRh3KcJPv+N/9VJrMdj4C+DRnGNFg1hTQf3RKsX+ms2V0OBC5vGlOZY"
+            + "zX+XZz/7hl1PXVLN23u4npZI/1xETI2VtRoM76S6oykGXxMtT3+sGU1fAVEKVS45"
+            + "pyQHWbBqApkWrURq0xBqpVfDwOgGw09dJxt2igW9hjvNAd9tJiMGrMF5o2OLlub7"
+            + "c7FiK+dWLLcw+nx7Hl6FQmo9E8qyW8x1Cb78HjR/JXMgH/ngB/4gba6xX+s5TJkW"
+            + "H2Wpp5ePTw39EqHosUMrm05R+C0ha3EyyaJIvKj2WWmImKu5PWo1t37Pi6KHFNC3"
+            + "wsYJMRKnnNtd34luMTOgLpDcdgClzfp2p6EqHMoB7Uj3etlLmbN+vpGgz9qkLBRV"
+            + "7MpR1yE9qrZNeGgbkry6N31w5E7HoAHu5JNcwxgzbJoj2lI8uvs6Gf7fEoQOuAPE"
+            + "W/SGlfR2BdBPiJ1yErMElc2O8LVS0wTwwifHpEsMV+1ntl1EC5d052lo+6q7zNqD"
+            + "uYt1/2if6h9W9fe+S9mzr0ZAtxIN2ZGOFJJRnqzjDQ4siB9nnwr6YgvUVRSr/lQB"
+            + "hDTd0bmjyWacCt0PPMJWchO6A5tzqKUpTWSYibpdks80kLQogQHsJTZd/kpS0I6f"
+            + "gD0HYYlMssZwhg2J2TWwXDpDTgQ6mzFKbGSdOSk/deTJj2+EubzxaZcxZEocCJA8"
+            + "bppCj4kLBnCj1LjYx7A=");
+
+        private static readonly byte[] message2 = Base64.Decode(
+            "qANQR1DBwU4DZlTzKj+E4aMQCADruFAojUIlHGcnswLIekvhbVnaHnbCt6Kp"
+            + "IL2zppmEIYJ9n1xCO1k+3Y5j9vNATbqCVWs1HD0aAL3PRI1eZ1l8GkIBCd2z"
+            + "tcZpSI/uyI/JCzVW2stCH0gpP2V7zcjk8HaIuBz4ZsyU9m7v6LwCDPB4CTrb"
+            + "Z5nn5Jm3eowonQsRL/3TpJtG+IjTaw29NbCBNNX8quM5LwfIsfWovqNv28r1"
+            + "aX8FsqoTRsWEfQ7dMV/swVGqv0PgKxqErdnZVJ2yOJqjLk+lBJT6zhqPijGV"
+            + "10pc68hdZxxLU1KZq25DAjS12xcAgagjRkOmYE/H1oEjGZlXfS4y/xQ7skHa"
+            + "HI+b04vECACTpQPwCXhxYiNWnf4XhJPONIGyrsXVtsTNwzOShFPmeUvpipP4"
+            + "HknakBkBuUY49xcffQogW/NlGCZnQOulDLE6fCH/krkSmI8WVP5Vhf6bM1Qm"
+            + "92dHZFoTrrcQ9NVGaCNHHWf7KXkNfKdTkE23LdggoVrVAzO4WcdqVc6s/or7"
+            + "jQYP9zXLeu8+GGFMxe/9FCtoIWbujGQHsdDEkCK4h+D44EVDPzbvWj39ZB4w"
+            + "hHoab8RLHd7njcrPeoCPdYkFVCKOSuLdxxYZDbbmgpISaafrafwefkkESeGu"
+            + "JzbNhmyS8zfOiejWzndaLYWUSE/sqISK9Pg+xKundnFPk04+AhIRyYEoUjG3"
+            + "LgGVyM49mrM8E7QwAGU0m/VCJLoOu+N74Z1rp1wFdA5yCllFlONNM4Czhd1D"
+            + "ZMyLFqGXiKlyVCPlUTN2uVisYQGr6iNGYSPxpKjwiAzdeeQBPOETG0vd3nTO"
+            + "MN4BMKcG+kRJd5FU72SRfmbGwPPjd1gts9xFvtj4Tvpkam8=");
+
+		public override void PerformTest()
+        {
+            //
+            // test encrypted message
+            //
+            PgpObjectFactory pgpFact = new PgpObjectFactory(message1);
+
+            if (pgpFact.NextPgpObject() is PgpMarker)
+            {
+                if (pgpFact.NextPgpObject() is PgpEncryptedDataList)
+                {
+                    return;
+                }
+                else
+                {
+                    Fail("error processing after marker.");
+                }
+            }
+
+			// TODO Does this even get called?
+			pgpFact = new PgpObjectFactory(message2);
+
+            if (pgpFact.NextPgpObject() is PgpMarker)
+            {
+                if (!(pgpFact.NextPgpObject() is PgpEncryptedDataList))
+                {
+                    return;
+                }
+                else
+                {
+                    Fail("error processing after marker.");
+                }
+            }
+        }
+
+		public override string Name
+        {
+			get { return "PgpMarkerTest"; }
+        }
+
+		public static void Main(
+            string[] args)
+        {
+            RunTest(new PgpMarkerTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openpgp/test/RegressionTest.cs b/crypto/test/src/openpgp/test/RegressionTest.cs
new file mode 100644
index 000000000..e8a3685c6
--- /dev/null
+++ b/crypto/test/src/openpgp/test/RegressionTest.cs
@@ -0,0 +1,35 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
+{
+    public class RegressionTest
+    {
+        public static ITest[] tests =
+        {
+            new PgpKeyRingTest(),
+            new PgpRsaTest(),
+            new PgpDsaTest(),
+            new PgpDsaElGamalTest(),
+            new PgpPbeTest(),
+            new PgpMarkerTest(),
+            new PgpPacketTest(),
+            new PgpArmoredTest(),
+            new PgpSignatureTest(),
+            new PgpClearSignedSignatureTest(),
+            new PgpCompressionTest(),
+            new PGPNoPrivateKeyTest(),
+        };
+
+        public static void Main(
+            string[] args)
+        {
+            foreach (ITest test in tests)
+            {
+                ITestResult result = test.Perform();
+                Console.WriteLine(result);
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/openssl/test/AllTests.cs b/crypto/test/src/openssl/test/AllTests.cs
new file mode 100644
index 000000000..921208179
--- /dev/null
+++ b/crypto/test/src/openssl/test/AllTests.cs
@@ -0,0 +1,133 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.OpenSsl.Tests
+{
+	[TestFixture]
+	public class AllTests
+	{
+		private class Password
+			: IPasswordFinder
+		{
+			private readonly char[] password;
+
+			public Password(
+				char[] word)
+			{
+				this.password = (char[]) word.Clone();
+			}
+
+			public char[] GetPassword()
+			{
+				return (char[]) password.Clone();
+			}
+		}
+		
+		[Suite]
+		public static TestSuite Suite
+		{
+			get
+			{
+				TestSuite suite = new TestSuite("OpenSSL Tests");
+				suite.Add(new AllTests());
+				return suite;
+			}
+		}
+
+		[Test]
+		public void TestOpenSsl()
+		{
+			Org.BouncyCastle.Utilities.Test.ITest[] tests = new Org.BouncyCastle.Utilities.Test.ITest[]{
+				new ReaderTest(),
+				new WriterTest()
+			};
+
+			foreach (Org.BouncyCastle.Utilities.Test.ITest test in tests)
+			{
+				SimpleTestResult result = (SimpleTestResult)test.Perform();
+
+				if (!result.IsSuccessful())
+				{
+					Assert.Fail(result.ToString());
+				}
+			}
+		}
+
+		[Test]
+		public void TestPkcs8Encrypted()
+		{
+			IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+			kpGen.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
+
+			AsymmetricKeyParameter privKey = kpGen.GenerateKeyPair().Private;
+
+			// FIXME see PbeUtilities and Pkcs8Generator
+//			EncryptedTest(privKey, Pkcs8Generator.Aes256Cbc);
+//			EncryptedTest(privKey, Pkcs8Generator.Des3Cbc);
+			EncryptedTest(privKey, Pkcs8Generator.PbeSha1_3DES);
+		}
+
+		private void EncryptedTest(AsymmetricKeyParameter privKey, string algorithm)
+		{
+			StringWriter sw = new StringWriter();
+			PemWriter pWrt = new PemWriter(sw);
+			Pkcs8Generator pkcs8 = new Pkcs8Generator(privKey, algorithm);
+			pkcs8.Password = "hello".ToCharArray();
+
+			pWrt.WriteObject(pkcs8);
+			pWrt.Writer.Close();
+
+			String result = sw.ToString();
+
+			PemReader pRd = new PemReader(new StringReader(result), new Password("hello".ToCharArray()));
+
+			AsymmetricKeyParameter rdKey = (AsymmetricKeyParameter)pRd.ReadObject();
+			pRd.Reader.Close();
+
+			Assert.AreEqual(privKey, rdKey);
+		}
+
+		[Test]
+		public void TestPkcs8Plain()
+		{
+			IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+			kpGen.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
+
+			AsymmetricKeyParameter privKey = kpGen.GenerateKeyPair().Private;
+
+			StringWriter sw = new StringWriter();
+			PemWriter pWrt = new PemWriter(sw);
+
+			Pkcs8Generator pkcs8 = new Pkcs8Generator(privKey);
+			pWrt.WriteObject(pkcs8);
+			pWrt.Writer.Close();
+
+			string result = sw.ToString();
+
+			PemReader pRd = new PemReader(new StringReader(result), new Password("hello".ToCharArray()));
+
+			AsymmetricKeyParameter rdKey = (AsymmetricKeyParameter)pRd.ReadObject();
+			pRd.Reader.Close();
+
+			Assert.AreEqual(privKey, rdKey);
+		}
+
+        public static void Main(
+			string[] args)
+        {
+            //junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            Suite.Run(el);
+        }
+	}
+}
diff --git a/crypto/test/src/openssl/test/ReaderTest.cs b/crypto/test/src/openssl/test/ReaderTest.cs
new file mode 100644
index 000000000..e3990b562
--- /dev/null
+++ b/crypto/test/src/openssl/test/ReaderTest.cs
@@ -0,0 +1,379 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.OpenSsl.Tests
+{
+    /**
+    * basic class for reading test.pem - the password is "secret"
+    */
+    [TestFixture]
+    public class ReaderTest
+        : SimpleTest
+    {
+        private class Password
+            : IPasswordFinder
+        {
+            private readonly char[] password;
+
+            public Password(
+                char[] word)
+            {
+                this.password = (char[]) word.Clone();
+            }
+
+            public char[] GetPassword()
+            {
+                return (char[]) password.Clone();
+            }
+        }
+
+        public override string Name
+        {
+            get { return "PEMReaderTest"; }
+        }
+
+        public override void PerformTest()
+        {
+            IPasswordFinder pGet = new Password("secret".ToCharArray());
+            PemReader pemRd = OpenPemResource("test.pem", pGet);
+            AsymmetricCipherKeyPair pair;
+
+            object o;
+            while ((o = pemRd.ReadObject()) != null)
+            {
+//				if (o is AsymmetricCipherKeyPair)
+//				{
+//					ackp = (AsymmetricCipherKeyPair)o;
+//
+//					Console.WriteLine(ackp.Public);
+//					Console.WriteLine(ackp.Private);
+//				}
+//				else
+//				{
+//					Console.WriteLine(o.ToString());
+//				}
+            }
+
+            //
+            // pkcs 7 data
+            //
+            pemRd = OpenPemResource("pkcs7.pem", null);
+
+            ContentInfo d = (ContentInfo)pemRd.ReadObject();    
+    
+            if (!d.ContentType.Equals(CmsObjectIdentifiers.EnvelopedData))
+            {
+                Fail("failed envelopedData check");
+            }
+
+            /*
+            {
+                //
+                // ECKey
+                //
+                pemRd = OpenPemResource("eckey.pem", null);
+    
+                // TODO Resolve return type issue with EC keys and fix PemReader to return parameters
+//				ECNamedCurveParameterSpec spec = (ECNamedCurveParameterSpec)pemRd.ReadObject();
+    
+                pair = (AsymmetricCipherKeyPair)pemRd.ReadObject();
+                ISigner sgr = SignerUtilities.GetSigner("ECDSA");
+    
+                sgr.Init(true, pair.Private);
+    
+                byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+    
+                sgr.BlockUpdate(message, 0, message.Length);
+    
+                byte[] sigBytes = sgr.GenerateSignature();
+    
+                sgr.Init(false, pair.Public);
+    
+                sgr.BlockUpdate(message, 0, message.Length);
+    
+                if (!sgr.VerifySignature(sigBytes))
+                {
+                    Fail("EC verification failed");
+                }
+
+                // TODO Resolve this issue with the algorithm name, study Java version
+//				if (!((ECPublicKeyParameters) pair.Public).AlgorithmName.Equals("ECDSA"))
+//				{
+//					Fail("wrong algorithm name on public got: " + ((ECPublicKeyParameters) pair.Public).AlgorithmName);
+//				}
+//	
+//				if (!((ECPrivateKeyParameters) pair.Private).AlgorithmName.Equals("ECDSA"))
+//				{
+//					Fail("wrong algorithm name on private got: " + ((ECPrivateKeyParameters) pair.Private).AlgorithmName);
+//				}
+            }
+            */
+
+            //
+            // writer/parser test
+            //
+            IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            kpGen.Init(
+                new RsaKeyGenerationParameters(
+                BigInteger.ValueOf(0x10001),
+                new SecureRandom(),
+                768,
+                25));
+
+            pair = kpGen.GenerateKeyPair();
+
+            keyPairTest("RSA", pair);
+
+//			kpGen = KeyPairGenerator.getInstance("DSA");
+//			kpGen.initialize(512, new SecureRandom());
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+            pGen.Init(512, 80, new SecureRandom());
+
+            kpGen = GeneratorUtilities.GetKeyPairGenerator("DSA");
+            kpGen.Init(
+                new DsaKeyGenerationParameters(
+                    new SecureRandom(),
+                    pGen.GenerateParameters()));
+
+            pair = kpGen.GenerateKeyPair();
+
+            keyPairTest("DSA", pair);
+
+            //
+            // PKCS7
+            //
+            MemoryStream bOut = new MemoryStream();
+            PemWriter pWrt = new PemWriter(new StreamWriter(bOut));
+
+            pWrt.WriteObject(d);
+            pWrt.Writer.Close();
+
+            pemRd = new PemReader(new StreamReader(new MemoryStream(bOut.ToArray(), false)));
+            d = (ContentInfo)pemRd.ReadObject();    
+
+            if (!d.ContentType.Equals(CmsObjectIdentifiers.EnvelopedData))
+            {
+                Fail("failed envelopedData recode check");
+            }
+
+
+            // OpenSSL test cases (as embedded resources)
+            doOpenSslDsaTest("unencrypted");
+            doOpenSslRsaTest("unencrypted");
+
+            doOpenSslTests("aes128");
+            doOpenSslTests("aes192");
+            doOpenSslTests("aes256");
+            doOpenSslTests("blowfish");
+            doOpenSslTests("des1");
+            doOpenSslTests("des2");
+            doOpenSslTests("des3");
+            doOpenSslTests("rc2_128");
+
+            doOpenSslDsaTest("rc2_40_cbc");
+            doOpenSslRsaTest("rc2_40_cbc");
+            doOpenSslDsaTest("rc2_64_cbc");
+            doOpenSslRsaTest("rc2_64_cbc");
+
+            doDudPasswordTest("7fd98", 0, "Corrupted stream - out of bounds length found");
+            doDudPasswordTest("ef677", 1, "Corrupted stream - out of bounds length found");
+            doDudPasswordTest("800ce", 2, "unknown tag 26 encountered");
+            doDudPasswordTest("b6cd8", 3, "DEF length 81 object truncated by 56");
+            doDudPasswordTest("28ce09", 4, "DEF length 110 object truncated by 28");
+            doDudPasswordTest("2ac3b9", 5, "DER length more than 4 bytes: 11");
+            doDudPasswordTest("2cba96", 6, "DEF length 100 object truncated by 35");
+            doDudPasswordTest("2e3354", 7, "DEF length 42 object truncated by 9");
+            doDudPasswordTest("2f4142", 8, "DER length more than 4 bytes: 14");
+            doDudPasswordTest("2fe9bb", 9, "DER length more than 4 bytes: 65");
+            doDudPasswordTest("3ee7a8", 10, "DER length more than 4 bytes: 57");
+            doDudPasswordTest("41af75", 11, "unknown tag 16 encountered");
+            doDudPasswordTest("1704a5", 12, "corrupted stream detected");
+            doDudPasswordTest("1c5822", 13, "Unknown object in GetInstance: Org.BouncyCastle.Asn1.DerUtf8String");
+            doDudPasswordTest("5a3d16", 14, "corrupted stream detected");
+            doDudPasswordTest("8d0c97", 15, "corrupted stream detected");
+            doDudPasswordTest("bc0daf", 16, "corrupted stream detected");
+            doDudPasswordTest("aaf9c4d",17, "Corrupted stream - out of bounds length found");
+
+            // encrypted private key test
+            pGet = new Password("password".ToCharArray());
+            pemRd = OpenPemResource("enckey.pem", pGet);
+
+            RsaPrivateCrtKeyParameters privKey = (RsaPrivateCrtKeyParameters)pemRd.ReadObject();
+
+            if (!privKey.PublicExponent.Equals(new BigInteger("10001", 16)))
+            {
+                Fail("decryption of private key data check failed");
+            }
+
+            // general PKCS8 test
+            pGet = new Password("password".ToCharArray());
+            pemRd = OpenPemResource("pkcs8test.pem", pGet);
+
+            while ((privKey = (RsaPrivateCrtKeyParameters)pemRd.ReadObject()) != null)
+            {
+                if (!privKey.PublicExponent.Equals(new BigInteger("10001", 16)))
+                {
+                    Fail("decryption of private key data check failed");
+                }
+            }
+        }
+
+        private void keyPairTest(
+            string					name,
+            AsymmetricCipherKeyPair	pair) 
+        {
+            MemoryStream bOut = new MemoryStream();
+            PemWriter pWrt = new PemWriter(new StreamWriter(bOut));
+
+            pWrt.WriteObject(pair.Public);
+            pWrt.Writer.Close();
+
+            PemReader pemRd = new PemReader(new StreamReader(new MemoryStream(bOut.ToArray(), false)));
+
+            AsymmetricKeyParameter pubK = (AsymmetricKeyParameter) pemRd.ReadObject();
+            if (!pubK.Equals(pair.Public))
+            {
+                Fail("Failed public key read: " + name);
+            }
+
+            bOut = new MemoryStream();
+            pWrt = new PemWriter(new StreamWriter(bOut));
+
+            pWrt.WriteObject(pair.Private);
+            pWrt.Writer.Close();
+
+            pemRd = new PemReader(new StreamReader(new MemoryStream(bOut.ToArray(), false)));
+
+            AsymmetricCipherKeyPair kPair = (AsymmetricCipherKeyPair) pemRd.ReadObject();
+            if (!kPair.Private.Equals(pair.Private))
+            {
+                Fail("Failed private key read: " + name);
+            }
+            
+            if (!kPair.Public.Equals(pair.Public))
+            {
+                Fail("Failed private key public read: " + name);
+            }
+        }
+
+        private void doOpenSslTests(
+            string baseName)
+        {
+            doOpenSslDsaModesTest(baseName);
+            doOpenSslRsaModesTest(baseName);
+        }
+
+        private void doOpenSslDsaModesTest(
+            string baseName)
+        {
+            doOpenSslDsaTest(baseName + "_cbc");
+            doOpenSslDsaTest(baseName + "_cfb");
+            doOpenSslDsaTest(baseName + "_ecb");
+            doOpenSslDsaTest(baseName + "_ofb");
+        }
+
+        private void doOpenSslRsaModesTest(
+            string baseName)
+        {
+            doOpenSslRsaTest(baseName + "_cbc");
+            doOpenSslRsaTest(baseName + "_cfb");
+            doOpenSslRsaTest(baseName + "_ecb");
+            doOpenSslRsaTest(baseName + "_ofb");
+        }
+
+        private void doOpenSslDsaTest(
+            string name)
+        {
+            string fileName = "dsa.openssl_dsa_" + name + ".pem";
+
+            doOpenSslTestFile(fileName, typeof(DsaPrivateKeyParameters));
+        }
+
+        private void doOpenSslRsaTest(
+            string name)
+        {
+            string fileName = "rsa.openssl_rsa_" + name + ".pem";
+
+            doOpenSslTestFile(fileName, typeof(RsaPrivateCrtKeyParameters));
+        }
+
+        private void doOpenSslTestFile(
+            string	fileName,
+            Type	expectedPrivKeyType)
+        {
+            PemReader pr = OpenPemResource(fileName, new Password("changeit".ToCharArray()));
+            AsymmetricCipherKeyPair kp = pr.ReadObject() as AsymmetricCipherKeyPair;
+            pr.Reader.Close();
+
+            if (kp == null)
+            {
+                Fail("Didn't find OpenSSL key");
+            }
+
+            if (!expectedPrivKeyType.IsInstanceOfType(kp.Private))
+            {
+                Fail("Returned key not of correct type");
+            }
+        }
+
+        private void doDudPasswordTest(string password, int index, string message)
+        {
+            // illegal state exception check - in this case the wrong password will
+            // cause an underlying class cast exception.
+            try
+            {
+                IPasswordFinder pGet = new Password(password.ToCharArray());
+                PemReader pemRd = OpenPemResource("test.pem", pGet);
+
+                Object o;
+                while ((o = pemRd.ReadObject()) != null)
+                {
+                }
+
+                Fail("issue not detected: " + index);
+            }
+            catch (IOException e)
+            {
+                if (e.Message.IndexOf(message) < 0)
+                {
+                    Console.Error.WriteLine(message);
+                    Console.Error.WriteLine(e.Message);
+                    Fail("issue " + index + " exception thrown, but wrong message");
+                }
+            }
+        }
+
+        private static PemReader OpenPemResource(
+            string			fileName,
+            IPasswordFinder	pGet)
+        {
+            Stream data = GetTestDataAsStream("openssl." + fileName);
+            TextReader tr = new StreamReader(data);
+            return new PemReader(tr, pGet);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ReaderTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/openssl/test/WriterTest.cs b/crypto/test/src/openssl/test/WriterTest.cs
new file mode 100644
index 000000000..41f371708
--- /dev/null
+++ b/crypto/test/src/openssl/test/WriterTest.cs
@@ -0,0 +1,185 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.OpenSsl.Tests
+{
+	[TestFixture]
+	public class WriterTest
+		: SimpleTest
+	{
+		private static readonly SecureRandom random = new SecureRandom();
+
+		// TODO Replace with a randomly generated key each test run?
+		private static readonly RsaPrivateCrtKeyParameters testRsaKey = new RsaPrivateCrtKeyParameters(
+			new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+			new BigInteger("11", 16),
+			new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+			new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+			new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+			new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+			new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+			new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+		private static readonly DsaParameters testDsaParams = new DsaParameters(
+			new BigInteger("7434410770759874867539421675728577177024889699586189000788950934679315164676852047058354758883833299702695428196962057871264685291775577130504050839126673"),
+			new BigInteger("1138656671590261728308283492178581223478058193247"),
+			new BigInteger("4182906737723181805517018315469082619513954319976782448649747742951189003482834321192692620856488639629011570381138542789803819092529658402611668375788410"));
+
+//		private static readonly PKCS8EncodedKeySpec testEcDsaKeySpec = new PKCS8EncodedKeySpec(
+//			Base64.Decode("MIG/AgEAMBAGByqGSM49AgEGBSuBBAAiBIGnMIGkAgEBBDCSBU3vo7ieeKs0ABQamy/ynxlde7Ylr8HmyfLaNnMr" +
+//				"jAwPp9R+KMUEhB7zxSAXv9KgBwYFK4EEACKhZANiAQQyyolMpg+TyB4o9kPWqafHIOe8o9K1glus+w2sY8OIPQQWGb5i5LdAyi" +
+//				"/SscwU24rZM0yiL3BHodp9ccwyhLrFYgXJUOQcCN2dno1GMols5497in5gL5+zn0yMsRtyv5o=")
+//		);
+		private static readonly byte[] testEcDsaKeyBytes = Base64.Decode(
+			  "MIG/AgEAMBAGByqGSM49AgEGBSuBBAAiBIGnMIGkAgEBBDCSBU3vo7ieeKs0ABQamy/ynxlde7Ylr8HmyfLaNnMr"
+			+ "jAwPp9R+KMUEhB7zxSAXv9KgBwYFK4EEACKhZANiAQQyyolMpg+TyB4o9kPWqafHIOe8o9K1glus+w2sY8OIPQQWGb5i5LdAyi"
+			+ "/SscwU24rZM0yiL3BHodp9ccwyhLrFYgXJUOQcCN2dno1GMols5497in5gL5+zn0yMsRtyv5o=");
+
+		private static readonly char[] testPassword = "bouncy".ToCharArray();
+
+		private static readonly string[] algorithms = new string[]
+		{
+			"AES-128-CBC", "AES-128-CFB", "AES-128-ECB", "AES-128-OFB",
+			"AES-192-CBC", "AES-192-CFB", "AES-192-ECB", "AES-192-OFB",
+			"AES-256-CBC", "AES-256-CFB", "AES-256-ECB", "AES-256-OFB",
+			"BF-CBC", "BF-CFB", "BF-ECB", "BF-OFB",
+			"DES-CBC", "DES-CFB", "DES-ECB", "DES-OFB",
+			"DES-EDE", "DES-EDE-CBC", "DES-EDE-CFB", "DES-EDE-ECB", "DES-EDE-OFB",
+			"DES-EDE3", "DES-EDE3-CBC", "DES-EDE3-CFB", "DES-EDE3-ECB", "DES-EDE3-OFB",
+			"RC2-CBC", "RC2-CFB", "RC2-ECB", "RC2-OFB",
+			"RC2-40-CBC",
+			"RC2-64-CBC",
+		};
+
+		private class Password
+			: IPasswordFinder
+		{
+			private readonly char[] password;
+
+			public Password(
+				char[] word)
+			{
+				this.password = (char[]) word.Clone();
+			}
+
+			public char[] GetPassword()
+			{
+				return (char[]) password.Clone();
+			}
+		}
+
+		public override string Name
+		{
+			get { return "PEMWriterTest"; }
+		}
+
+		public override void PerformTest()
+		{
+			IAsymmetricCipherKeyPairGenerator dsaKpg = GeneratorUtilities.GetKeyPairGenerator("DSA");
+			dsaKpg.Init(new DsaKeyGenerationParameters(random, testDsaParams));
+			AsymmetricCipherKeyPair testDsaKp = dsaKpg.GenerateKeyPair();
+			AsymmetricKeyParameter testDsaKey = testDsaKp.Private;
+
+			doWriteReadTest(testDsaKey);
+			doWriteReadTests(testDsaKey, algorithms);
+
+			doWriteReadTest(testRsaKey);
+			doWriteReadTests(testRsaKey, algorithms);
+
+			AsymmetricKeyParameter ecPriv = PrivateKeyFactory.CreateKey(testEcDsaKeyBytes);
+			doWriteReadTest(ecPriv);
+			doWriteReadTests(ecPriv, algorithms);
+
+			IAsymmetricCipherKeyPairGenerator ecKpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+			ecKpg.Init(new KeyGenerationParameters(random, 239));
+			ecPriv = ecKpg.GenerateKeyPair().Private;
+			doWriteReadTest(ecPriv);
+			doWriteReadTests(ecPriv, algorithms);
+
+			// override test
+			PemWriter pWrt = new PemWriter(new StringWriter());
+
+			object o = new PemObject("FRED", new byte[100]);
+			pWrt.WriteObject(o);
+
+			pWrt.Writer.Close();
+		}
+
+		private void doWriteReadTests(
+			AsymmetricKeyParameter	akp,
+			string[]				algorithms)
+		{
+			foreach (string algorithm in algorithms)
+			{
+				doWriteReadTest(akp, algorithm);
+			}
+		}
+
+		private void doWriteReadTest(
+			AsymmetricKeyParameter	akp)
+		{
+			StringWriter sw = new StringWriter();
+			PemWriter pw = new PemWriter(sw);
+
+			pw.WriteObject(akp);
+			pw.Writer.Close();
+
+			string data = sw.ToString();
+
+			PemReader pr = new PemReader(new StringReader(data));
+
+			AsymmetricCipherKeyPair kp = pr.ReadObject() as AsymmetricCipherKeyPair;
+
+			if (kp == null || !kp.Private.Equals(akp))
+			{
+				Fail("Failed to read back test key");
+			}
+		}
+
+		private void doWriteReadTest(
+			AsymmetricKeyParameter	akp,
+			string					algorithm)
+		{
+			StringWriter sw = new StringWriter();
+			PemWriter pw = new PemWriter(sw);
+
+			pw.WriteObject(akp, algorithm, testPassword, random);
+			pw.Writer.Close();
+
+			string data = sw.ToString();
+
+			PemReader pr = new PemReader(new StringReader(data), new Password(testPassword));
+
+			AsymmetricCipherKeyPair kp = pr.ReadObject() as AsymmetricCipherKeyPair;
+
+			if (kp == null || !kp.Private.Equals(akp))
+			{
+				Fail("Failed to read back test key encoded with: " + algorithm);
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new WriterTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/pkcs/examples/PKCS12Example.cs b/crypto/test/src/pkcs/examples/PKCS12Example.cs
new file mode 100644
index 000000000..002e14c38
--- /dev/null
+++ b/crypto/test/src/pkcs/examples/PKCS12Example.cs
@@ -0,0 +1,386 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.Pkcs.Examples
+{
+	/**
+	* Example of how to set up a certificate chain and a PKCS 12 store for
+	* a private individual - obviously you'll need to generate your own keys,
+	* and you may need to add a NetscapeCertType extension or add a key
+	* usage extension depending on your application, but you should get the
+	* idea! As always this is just an example...
+	*/
+	public class Pkcs12Example
+	{
+		private static readonly char[] passwd = "hello world".ToCharArray();
+
+		private static readonly X509V1CertificateGenerator v1CertGen = new X509V1CertificateGenerator();
+		private static readonly X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+		/**
+		* we generate the CA's certificate
+		*/
+		public static X509CertificateEntry CreateMasterCert(
+			AsymmetricKeyParameter	pubKey,
+			AsymmetricKeyParameter	privKey)
+		{
+			//
+			// signers name
+			//
+			string issuer = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+			//
+			// subjects name - the same as we are self signed.
+			//
+			string subject = "C=AU, O=The Legion of the Bouncy Castle, OU=Bouncy Primary Certificate";
+
+			//
+			// create the certificate - version 1
+			//
+
+			v1CertGen.SetSerialNumber(BigInteger.One);
+			v1CertGen.SetIssuerDN(new X509Name(issuer));
+			v1CertGen.SetNotBefore(DateTime.UtcNow.AddMonths(-1));
+			v1CertGen.SetNotAfter(DateTime.UtcNow.AddMonths(1));
+			v1CertGen.SetSubjectDN(new X509Name(subject));
+			v1CertGen.SetPublicKey(pubKey);
+			v1CertGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+
+			X509Certificate cert = v1CertGen.Generate(privKey);
+
+			cert.CheckValidity(DateTime.UtcNow);
+
+			cert.Verify(pubKey);
+
+//			PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)cert;
+			IDictionary bagAttr = new Hashtable();
+
+			//
+			// this is actually optional - but if you want to have control
+			// over setting the friendly name this is the way to do it...
+			//
+//			bagAttr.setBagAttribute(
+//				PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+//				new DERBMPString("Bouncy Primary Certificate"));
+			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id,
+				new DerBmpString("Bouncy Primary Certificate"));
+
+			return new X509CertificateEntry(cert, bagAttr);
+		}
+
+		/**
+		* we generate an intermediate certificate signed by our CA
+		*/
+		public static X509CertificateEntry CreateIntermediateCert(
+			AsymmetricKeyParameter	pubKey,
+			AsymmetricKeyParameter	caPrivKey,
+			X509Certificate			caCert)
+		{
+			//
+			// subject name table.
+			//
+			IDictionary attrs = new Hashtable();
+			IList order = new ArrayList();
+
+			attrs.Add(X509Name.C, "AU");
+			attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+			attrs.Add(X509Name.OU, "Bouncy Intermediate Certificate");
+			attrs.Add(X509Name.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+			order.Add(X509Name.C);
+			order.Add(X509Name.O);
+			order.Add(X509Name.OU);
+			order.Add(X509Name.EmailAddress);
+
+			//
+			// create the certificate - version 3
+			//
+			v3CertGen.Reset();
+
+			v3CertGen.SetSerialNumber(BigInteger.Two);
+			v3CertGen.SetIssuerDN(PrincipalUtilities.GetSubjectX509Principal(caCert));
+			v3CertGen.SetNotBefore(DateTime.UtcNow.AddMonths(-1));
+			v3CertGen.SetNotAfter(DateTime.UtcNow.AddMonths(1));
+			v3CertGen.SetSubjectDN(new X509Name(order, attrs));
+			v3CertGen.SetPublicKey(pubKey);
+			v3CertGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+
+			//
+			// extensions
+			//
+			v3CertGen.AddExtension(
+				X509Extensions.SubjectKeyIdentifier,
+				false,
+				new SubjectKeyIdentifierStructure(pubKey));
+
+			v3CertGen.AddExtension(
+				X509Extensions.AuthorityKeyIdentifier,
+				false,
+				new AuthorityKeyIdentifierStructure(caCert));
+
+			v3CertGen.AddExtension(
+				X509Extensions.BasicConstraints,
+				true,
+				new BasicConstraints(0));
+
+			X509Certificate cert = v3CertGen.Generate(caPrivKey);
+
+			cert.CheckValidity(DateTime.UtcNow);
+
+			cert.Verify(caCert.GetPublicKey());
+
+//			PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)cert;
+			IDictionary bagAttr = new Hashtable();
+
+			//
+			// this is actually optional - but if you want to have control
+			// over setting the friendly name this is the way to do it...
+			//
+//			bagAttr.setBagAttribute(
+//				PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+//				new DERBMPString("Bouncy Intermediate Certificate"));
+			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id,
+				new DerBmpString("Bouncy Intermediate Certificate"));
+
+			return new X509CertificateEntry(cert, bagAttr);
+		}
+
+		/**
+		* we generate a certificate signed by our CA's intermediate certficate
+		*/
+		public static X509CertificateEntry CreateCert(
+			AsymmetricKeyParameter	pubKey,
+			AsymmetricKeyParameter	caPrivKey,
+			AsymmetricKeyParameter	caPubKey)
+		{
+			//
+			// signers name table.
+			//
+			IDictionary sAttrs = new Hashtable();
+			IList sOrder = new ArrayList();
+
+			sAttrs.Add(X509Name.C, "AU");
+			sAttrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+			sAttrs.Add(X509Name.OU, "Bouncy Intermediate Certificate");
+			sAttrs.Add(X509Name.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+			sOrder.Add(X509Name.C);
+			sOrder.Add(X509Name.O);
+			sOrder.Add(X509Name.OU);
+			sOrder.Add(X509Name.EmailAddress);
+
+			//
+			// subjects name table.
+			//
+			IDictionary attrs = new Hashtable();
+			IList order = new ArrayList();
+
+			attrs.Add(X509Name.C, "AU");
+			attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+			attrs.Add(X509Name.L, "Melbourne");
+			attrs.Add(X509Name.CN, "Eric H. Echidna");
+			attrs.Add(X509Name.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+			order.Add(X509Name.C);
+			order.Add(X509Name.O);
+			order.Add(X509Name.L);
+			order.Add(X509Name.CN);
+			order.Add(X509Name.EmailAddress);
+
+			//
+			// create the certificate - version 3
+			//
+			v3CertGen.Reset();
+
+			v3CertGen.SetSerialNumber(BigInteger.Three);
+			v3CertGen.SetIssuerDN(new X509Name(sOrder, sAttrs));
+			v3CertGen.SetNotBefore(DateTime.UtcNow.AddMonths(-1));
+			v3CertGen.SetNotAfter(DateTime.UtcNow.AddMonths(1));
+			v3CertGen.SetSubjectDN(new X509Name(order, attrs));
+			v3CertGen.SetPublicKey(pubKey);
+			v3CertGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+
+			//
+			// add the extensions
+			//
+			v3CertGen.AddExtension(
+				X509Extensions.SubjectKeyIdentifier,
+				false,
+				new SubjectKeyIdentifierStructure(pubKey));
+
+			v3CertGen.AddExtension(
+				X509Extensions.AuthorityKeyIdentifier,
+				false,
+				new AuthorityKeyIdentifierStructure(caPubKey));
+
+			X509Certificate cert = v3CertGen.Generate(caPrivKey);
+
+			cert.CheckValidity(DateTime.UtcNow);
+
+			cert.Verify(caPubKey);
+
+//			PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)cert;
+			IDictionary bagAttr = new Hashtable();
+
+			//
+			// this is also optional - in the sense that if you leave this
+			// out the keystore will add it automatically, note though that
+			// for the browser to recognise the associated private key this
+			// you should at least use the pkcs_9_localKeyId OID and set it
+			// to the same as you do for the private key's localKeyId.
+			//
+//			bagAttr.setBagAttribute(
+//				PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+//				new DERBMPString("Eric's Key"));
+//			bagAttr.setBagAttribute(
+//				PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
+//				new SubjectKeyIdentifierStructure(pubKey));
+			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id,
+				new DerBmpString("Eric's Key"));
+			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id,
+				new SubjectKeyIdentifierStructure(pubKey));
+
+			return new X509CertificateEntry(cert, bagAttr);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+//			Security.addProvider(new BouncyCastleProvider());
+
+			//
+			// personal keys
+			//
+//			RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+			RsaKeyParameters pubKey = new RsaKeyParameters(false,
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16));
+
+//			RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+			RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16),
+				new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+				new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+				new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+				new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+				new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+				new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+			//
+			// intermediate keys.
+			//
+//			RSAPublicKeySpec intPubKeySpec = new RSAPublicKeySpec(
+			RsaKeyParameters intPubKey = new RsaKeyParameters(false,
+				new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
+				new BigInteger("ffff", 16));
+
+
+//			RSAPrivateCrtKeySpec intPrivKeySpec = new RSAPrivateCrtKeySpec(
+			RsaPrivateCrtKeyParameters intPrivKey = new RsaPrivateCrtKeyParameters(
+				new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
+				new BigInteger("ffff", 16),
+				new BigInteger("7deb1b194a85bcfd29cf871411468adbc987650903e3bacc8338c449ca7b32efd39ffc33bc84412fcd7df18d23ce9d7c25ea910b1ae9985373e0273b4dca7f2e0db3b7314056ac67fd277f8f89cf2fd73c34c6ca69f9ba477143d2b0e2445548aa0b4a8473095182631da46844c356f5e5c7522eb54b5a33f11d730ead9c0cff", 16),
+				new BigInteger("ef4cede573cea47f83699b814de4302edb60eefe426c52e17bd7870ec7c6b7a24fe55282ebb73775f369157726fcfb988def2b40350bdca9e5b418340288f649", 16),
+				new BigInteger("97c7737d1b9a0088c3c7b528539247fd2a1593e7e01cef18848755be82f4a45aa093276cb0cbf118cb41117540a78f3fc471ba5d69f0042274defc9161265721", 16),
+				new BigInteger("6c641094e24d172728b8da3c2777e69adfd0839085be7e38c7c4a2dd00b1ae969f2ec9d23e7e37090fcd449a40af0ed463fe1c612d6810d6b4f58b7bfa31eb5f", 16),
+				new BigInteger("70b7123e8e69dfa76feb1236d0a686144b00e9232ed52b73847e74ef3af71fb45ccb24261f40d27f98101e230cf27b977a5d5f1f15f6cf48d5cb1da2a3a3b87f", 16),
+				new BigInteger("e38f5750d97e270996a286df2e653fd26c242106436f5bab0f4c7a9e654ce02665d5a281f2c412456f2d1fa26586ef04a9adac9004ca7f913162cb28e13bf40d", 16));
+
+			//
+			// ca keys
+			//
+//			RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec(
+			RsaKeyParameters caPubKey = new RsaKeyParameters(false,
+				new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+				new BigInteger("11", 16));
+
+//			RSAPrivateCrtKeySpec   caPrivKeySpec = new RSAPrivateCrtKeySpec(
+			RsaPrivateCrtKeyParameters caPrivKey = new RsaPrivateCrtKeyParameters(
+				new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+				new BigInteger("11", 16),
+				new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16),
+				new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16),
+				new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16),
+				new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16),
+				new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16),
+				new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16));
+
+
+
+			//
+			// set up the keys
+			//
+//			KeyFactory          fact = KeyFactory.getInstance("RSA", "BC");
+//			PrivateKey          caPrivKey = fact.generatePrivate(caPrivKeySpec);
+//			PublicKey           caPubKey = fact.generatePublic(caPubKeySpec);
+//			PrivateKey          intPrivKey = fact.generatePrivate(intPrivKeySpec);
+//			PublicKey           intPubKey = fact.generatePublic(intPubKeySpec);
+//			PrivateKey          privKey = fact.generatePrivate(privKeySpec);
+//			PublicKey           pubKey = fact.generatePublic(pubKeySpec);
+
+			X509CertificateEntry[] chain = new X509CertificateEntry[3];
+
+			chain[2] = CreateMasterCert(caPubKey, caPrivKey);
+			chain[1] = CreateIntermediateCert(intPubKey, caPrivKey, chain[2].Certificate);
+			chain[0] = CreateCert(pubKey, intPrivKey, intPubKey);
+
+			//
+			// add the friendly name for the private key
+			//
+//			PKCS12BagAttributeCarrier   bagAttr = (PKCS12BagAttributeCarrier)privKey;
+			IDictionary bagAttr = new Hashtable();
+
+			//
+			// this is also optional - in the sense that if you leave this
+			// out the keystore will add it automatically, note though that
+			// for the browser to recognise which certificate the private key
+			// is associated with you should at least use the pkcs_9_localKeyId
+			// OID and set it to the same as you do for the private key's
+			// corresponding certificate.
+			//
+//			bagAttr.setBagAttribute(
+//				PKCSObjectIdentifiers.pkcs_9_at_friendlyName,
+//				new DERBMPString("Eric's Key"));
+//			bagAttr.setBagAttribute(
+//				PKCSObjectIdentifiers.pkcs_9_at_localKeyId,
+//				new SubjectKeyIdentifierStructure(pubKey));
+			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id,
+				new DerBmpString("Eric's Key"));
+			bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id,
+				new SubjectKeyIdentifierStructure(pubKey));
+
+			//
+			// store the key and the certificate chain
+			//
+//			KeyStore store = KeyStore.getInstance("PKCS12", "BC");
+//			store.load(null, null);
+			Pkcs12Store store = new Pkcs12StoreBuilder().Build();
+
+			//
+			// if you haven't set the friendly name and local key id above
+			// the name below will be the name of the key
+			//
+			store.SetKeyEntry("Eric's Key", new AsymmetricKeyEntry(privKey, bagAttr), chain);
+
+//			FileOutputStream fOut = new FileOutputStream("id.p12");
+//
+//			store.store(fOut, passwd);
+			FileStream fOut = File.Create("id.p12");
+			store.Save(fOut, passwd, new SecureRandom());
+			fOut.Close();
+		}
+	}
+}
diff --git a/crypto/test/src/pkcs/test/EncryptedPrivateKeyInfoTest.cs b/crypto/test/src/pkcs/test/EncryptedPrivateKeyInfoTest.cs
new file mode 100644
index 000000000..a41c99266
--- /dev/null
+++ b/crypto/test/src/pkcs/test/EncryptedPrivateKeyInfoTest.cs
@@ -0,0 +1,92 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Pkcs.Tests
+{
+    [TestFixture]
+    public class EncryptedPrivateKeyInfoTest
+        : SimpleTest
+    {
+        private readonly string alg = PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc.Id; // 3 key triple DES with SHA-1
+
+		public override string Name
+        {
+			get { return "EncryptedPrivateKeyInfoTest"; }
+        }
+
+		public override void PerformTest()
+        {
+            IAsymmetricCipherKeyPairGenerator pGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            RsaKeyGenerationParameters genParam = new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x10001), new SecureRandom(), 512, 25);
+
+			pGen.Init(genParam);
+
+			AsymmetricCipherKeyPair pair = pGen.GenerateKeyPair();
+
+            //
+            // set up the parameters
+            //
+            byte[] salt = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+            int iterationCount = 100;
+
+			//
+            // set up the key
+            //
+            char[] password1 = { 'h', 'e', 'l', 'l', 'o' };
+
+            EncryptedPrivateKeyInfo  encInfo = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(alg, password1, salt, iterationCount, PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.Private));
+
+            PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(password1, encInfo);
+
+            AsymmetricKeyParameter key = PrivateKeyFactory.CreateKey(info);
+
+            if (!key.Equals(pair.Private))
+            {
+                Fail("Key corrupted");
+            }
+
+			doOpensslTestKeys();
+		}
+
+		private void doOpensslTestKeys()
+		{
+			string[] names = GetTestDataEntries("keys");
+			foreach (string name in names)
+			{
+//				Console.Write(name + " => ");
+				Stream data = GetTestDataAsStream(name);
+				AsymmetricKeyParameter key = PrivateKeyFactory.DecryptKey("12345678a".ToCharArray(), data);
+//				Console.WriteLine(key.GetType().Name);
+				if (!(key is RsaPrivateCrtKeyParameters))
+				{
+					Fail("Sample key could not be decrypted: " + name);
+				}
+			}
+		}
+
+		public static void Main(
+            string[] args)
+        {
+			RunTest(new EncryptedPrivateKeyInfoTest());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/pkcs/test/PKCS10Test.cs b/crypto/test/src/pkcs/test/PKCS10Test.cs
new file mode 100644
index 000000000..d0227b9de
--- /dev/null
+++ b/crypto/test/src/pkcs/test/PKCS10Test.cs
@@ -0,0 +1,88 @@
+#region Using directives
+
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.Security;
+
+#endregion
+
+namespace Org.BouncyCastle.Pkcs.Tests
+{
+    [TestFixture]
+    public class Pkcs10Test
+        : SimpleTest
+    {
+        public override string Name
+        {
+			get { return "Pkcs10"; }
+        }
+
+		public override void PerformTest()
+        {
+            IAsymmetricCipherKeyPairGenerator pGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            RsaKeyGenerationParameters genParam = new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x10001), new SecureRandom(), 512, 25);
+
+            pGen.Init(genParam);
+
+            AsymmetricCipherKeyPair pair = pGen.GenerateKeyPair();
+
+            IDictionary attrs = new Hashtable();
+
+            attrs.Add(X509Name.C, "AU");
+            attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+            attrs.Add(X509Name.L, "Melbourne");
+            attrs.Add(X509Name.ST, "Victoria");
+            attrs.Add(X509Name.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+            X509Name subject = new X509Name(new ArrayList(attrs.Keys), attrs);
+
+            Pkcs10CertificationRequest req1 = new Pkcs10CertificationRequest(
+				"SHA1withRSA",
+				subject,
+				pair.Public,
+				null,
+				pair.Private);
+
+			byte[] bytes = req1.GetEncoded();
+
+			Pkcs10CertificationRequest req2 = new Pkcs10CertificationRequest(bytes);
+
+			if (!req2.Verify())
+            {
+                Fail("Failed verify check.");
+            }
+
+            if (!req2.GetPublicKey().Equals(req1.GetPublicKey()))
+            {
+                Fail("Failed public key check.");
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+			RunTest(new Pkcs10Test());
+        }
+
+		[Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/pkcs/test/PKCS12StoreTest.cs b/crypto/test/src/pkcs/test/PKCS12StoreTest.cs
new file mode 100644
index 000000000..c6b39135e
--- /dev/null
+++ b/crypto/test/src/pkcs/test/PKCS12StoreTest.cs
@@ -0,0 +1,921 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs.Tests
+{
+	/**
+	* Exercise the various key stores, making sure we at least get back what we put in!
+	* <p>This tests both the PKCS12 key store.</p>
+	*/
+	[TestFixture]
+	public class Pkcs12StoreTest
+		: SimpleTest
+	{
+		private static readonly char[] passwd = "hello world".ToCharArray();
+
+		//
+		// pkcs-12 pfx-pdu
+		//
+		private static readonly byte[] pkcs12 = Base64.Decode(
+			"MIACAQMwgAYJKoZIhvcNAQcBoIAkgAQBMAQBgAQBMAQBgAQBBgQBCQQJKoZI"
+			+ "hvcNAQcBBAGgBAGABAEkBAGABAEEBAEBBAEwBAEEBAEDBAOCAzQEAQQEAQEE"
+			+ "ATAEAQQEAQMEA4IDMAQBBAQBAQQBBgQBBAQBAQQBCwQBBAQBCwQLKoZIhvcN"
+			+ "AQwKAQIEAQQEAQEEAaAEAQQEAQMEA4ICpQQBBAQBAQQBMAQBBAQBAwQDggKh"
+			+ "BAEEBAEBBAEwBAEEBAEBBAEbBAEEBAEBBAEGBAEEBAEBBAEKBAEEBAEKBAoq"
+			+ "hkiG9w0BDAEDBAEEBAEPBA8wDQQIoagiwNZPJR4CAQEEAQQEAQEEAQQEAQQE"
+			+ "AQMEA4ICgAQBBAQDggKABIICgEPG0XlhMFyrs4ZWDrvEzl51ICfXd6K2ql2l"
+			+ "nnxhszUbigtSj6x49VEx4PfOB9fQFeidc5L5An+nKp646NBMIY0UwXGs8BLQ"
+			+ "au59jtOs987+l7QYIvl6fdGUIuLPhVSnZZDyqD+HQjU/0/ccKFHRif4tlEQq"
+			+ "aErvZbFeH0pg4ijf1HfgX6gBJGRKdO+msa4qKGnZdHCSLZehyyxvxAmURetg"
+			+ "yhtEl7RmedTB+4TDs7atekqxkNlD9tfwDUX6sb0IH6qbEA6P/DlVMdaD54Cl"
+			+ "QDxRzOfIIjklZhv5OMFWtPK0aYPcqyxzLpw1qRAyoTVXpidkj/hpIpgCVBP/"
+			+ "k5s2+WdGbLgA/4/zSrF6feRCE5llzM2IGxiHVq4oPzzngl3R+Fi5VCPDMcuW"
+			+ "NRuIOzJA+RNV2NPOE/P3knThDnwiImq+rfxmvZ1u6T06s20RmWK6cxp7fTEw"
+			+ "lQ9BOsv+mmyV8dr6cYJq4IlRzHdFOyEUBDwfHThyribNKKobO50xh2f93xYj"
+			+ "Rn5UMOQBJIe3b7OKZt5HOIMrJSZO02IZgvImi9yQWi96PnWa419D1cAsLWvM"
+			+ "xiN0HqZMbDFfxVM2BZmsxiexLhkHWKwLqfQDzRjJfmVww8fnXpWZhFXKyut9"
+			+ "gMGEyCNoba4RU3QI/wHKWYaK74qtJpsucuLWBH6UcsHsCry6VZkwRxWwC0lb"
+			+ "/F3Bm5UKHax5n9JHJ2amQm9zW3WJ0S5stpPObfmg5ArhbPY+pVOsTqBRlop1"
+			+ "bYJLD/X8Qbs468Bwzej0FhoEU59ZxFrbjLSBsMUYrVrwD83JE9kEazMLVchc"
+			+ "uCB9WT1g0hxYb7VA0BhOrWhL8F5ZH72RMCYLPI0EAQQEAQEEATEEAQQEAQEE"
+			+ "AXgEAQQEAQEEATAEAQQEAQEEAVEEAQQEAQEEAQYEAQQEAQEEAQkEAQQEAQkE"
+			+ "CSqGSIb3DQEJFAQBBAQBAQQBMQQBBAQBAQQBRAQBBAQBAQQBHgQBBAQBAQQB"
+			+ "QgQBBAQBQgRCAEQAYQB2AGkAZAAgAEcALgAgAEgAbwBvAGsAJwBzACAAVgBl"
+			+ "AHIAaQBTAGkAZwBuACwAIABJAG4AYwAuACAASQBEBAEEBAEBBAEwBAEEBAEB"
+			+ "BAEjBAEEBAEBBAEGBAEEBAEBBAEJBAEEBAEJBAkqhkiG9w0BCRUEAQQEAQEE"
+			+ "ATEEAQQEAQEEARYEAQQEAQEEAQQEAQQEAQEEARQEAQQEARQEFKEcMJ798oZL"
+			+ "FkH0OnpbUBnrTLgWBAIAAAQCAAAEAgAABAEwBAGABAEGBAEJBAkqhkiG9w0B"
+			+ "BwYEAaAEAYAEATAEAYAEAQIEAQEEAQAEATAEAYAEAQYEAQkECSqGSIb3DQEH"
+			+ "AQQBMAQBGwQBBgQBCgQKKoZIhvcNAQwBBgQPMA0ECEE7euvmxxwYAgEBBAGg"
+			+ "BAGABAEEBAEIBAgQIWDGlBWxnwQBBAQBCAQI2WsMhavhSCcEAQQEAQgECPol"
+			+ "uHJy9bm/BAEEBAEQBBCiRxtllKXkJS2anKD2q3FHBAEEBAEIBAjKy6BRFysf"
+			+ "7gQBBAQDggMwBIIDMJWRGu2ZLZild3oz7UBdpBDUVMOA6eSoWiRIfVTo4++l"
+			+ "RUBm8TpmmGrVkV32PEoLkoV+reqlyWCvqqSjRzi3epQiVwPQ6PV+ccLqxDhV"
+			+ "pGWDRQ5UttDBC2+u4fUQVZi2Z1i1g2tsk6SzB3MKUCrjoWKvaDUUwXo5k9Vz"
+			+ "qSLWCLTZCjs3RaY+jg3NbLZYtfMDdYovhCU2jMYV9adJ8MxxmJRz+zPWAJph"
+			+ "LH8hhfkKG+wJOSszqk9BqGZUa/mnZyzeQSMTEFga1ZB/kt2e8SZFWrTZEBgJ"
+			+ "oszsL5MObbwMDowNurnZsnS+Mf7xi01LeG0VT1fjd6rn9BzVwuMwhoqyoCNo"
+			+ "ziUqSUyLEwnGTYYpvXLxzhNiYzW8546KdoEKDkEjhfYsc4XqSjm9NYy/BW/M"
+			+ "qR+aL92j8hqnkrWkrWyvocUe3mWaiqt7/oOzNZiMTcV2dgjjh9HfnjSHjFGe"
+			+ "CVhnEWzV7dQIVyc/qvNzOuND8X5IyJ28xb6a/i1vScwGuo/UDgPAaMjGw28f"
+			+ "siOZBShzde0Kj82y8NilfYLHHeIGRW+N/grUFWhW25mAcBReXDd5JwOqM/eF"
+			+ "y+4+zBzlO84ws88T1pkSifwtMldglN0APwr4hvUH0swfiqQOWtwyeM4t+bHd"
+			+ "5buAlXOkSeF5rrLzZ2/Lx+JJmI2pJ/CQx3ej3bxPlx/BmarUGAxaI4le5go4"
+			+ "KNfs4GV8U+dbEHQz+yDYL+ksYNs1eb+DjI2khbl28jhoeAFKBtu2gGOL5M9M"
+			+ "CIP/JDOCHimu1YZRuOTAf6WISnG/0Ri3pYZsgQ0i4cXj+WfYwYVjhKX5AcDj"
+			+ "UKnc4/Cxp+TbbgZqEKRcYVb2q0kOAxkeaNo3WCm+qvUYrwAmKp4nVB+/24rK"
+			+ "khHiyYJQsETxtOEyvJkVxAS01djY4amuJ4jL0sYnXIhW3Ag93eavbzksGT7W"
+			+ "Fg1ywpr1x1xpXWIIuVt1k4e+g9fy7Yx7rx0IK1qCSjNwU3QPWbaef1rp0Q/X"
+			+ "P9IVXYkqo1g/T3SyXqrbZLO+sDjiG4IT3z3fJJqt81sRSVT0QN1ND8l93BG4"
+			+ "QKzghYw8sZ4FwKPtLky1dDcVTgQBBAQBCAQIK/85VMKWDWYEAQQEAQgECGsO"
+			+ "Q85CcFwPBAEEBAEIBAhaup6ot9XnQAQBBAQCgaAEgaCeCMadSm5fkLfhErYQ"
+			+ "DgePZl/rrjP9FQ3VJZ13XrjTSjTRknAbXi0DEu2tvAbmCf0sdoVNuZIZ92W0"
+			+ "iyaa2/A3RHA2RLPNQz5meTi1RE2N361yR0q181dC3ztkkJ8PLyd74nCtgPUX"
+			+ "0JlsvLRrdSjPBpBQ14GiM8VjqeIY7EVFy3vte6IbPzodxaviuSc70iXM4Yko"
+			+ "fQq6oaSjNBFRqkHrBAEEBAEIBAjlIvOf8SnfugQBBAQBCAQIutCF3Jovvl0E"
+			+ "AQQEAQgECO7jxbucdp/3BAEEBAEIBAidxK3XDLj+BwQBBAQBCAQI3m/HMbd3"
+			+ "TwwEAQQEA4ICOASCAjgtoCiMfTkjpCRuMhF5gNLRBiNv+xjg6GvZftR12qiJ"
+			+ "dLeCERI5bvXbh9GD6U+DjTUfhEab/37TbiI7VOFzsI/R137sYy9Tbnu7qkSx"
+			+ "u0bTvyXSSmio6sMRiWIcakmDbv+TDWR/xgtj7+7C6p+1jfUGXn/RjB3vlyjL"
+			+ "Q9lFe5F84qkZjnADo66p9gor2a48fgGm/nkABIUeyzFWCiTp9v6FEzuBfeuP"
+			+ "T9qoKSnCitaXRCru5qekF6L5LJHLNXLtIMSrbO0bS3hZK58FZAUVMaqawesJ"
+			+ "e/sVfQip9x/aFQ6U3KlSpJkmZK4TAqp9jIfxBC8CclbuwmoXPMomiCH57ykr"
+			+ "vkFHOGcxRcCxax5HySCwSyPDr8I4+6Kocty61i/1Xr4xJjb+3oyFStIpB24x"
+			+ "+ALb0Mz6mUa1ls76o+iQv0VM2YFwnx+TC8KC1+O4cNOE/gKeh0ircenVX83h"
+			+ "GNez8C5Ltg81g6p9HqZPc2pkwsneX2sJ4jMsjDhewV7TyyS3x3Uy3vTpZPek"
+			+ "VdjYeVIcgAz8VLJOpsIjyHMB57AyT7Yj87hVVy//VODnE1T88tRXZb+D+fCg"
+			+ "lj2weQ/bZtFzDX0ReiEQP6+yklGah59omeklIy9wctGV1o9GNZnGBSLvQ5NI"
+			+ "61e9zmQTJD2iDjihvQA/6+edKswCjGRX6rMjRWXT5Jv436l75DVoUj09tgR9"
+			+ "ytXSathCjQUL9MNXzUMtr7mgEUPETjM/kYBR7CNrsc+gWTWHYaSWuqKVBAEE"
+			+ "BAEIBAh6slfZ6iqkqwQBBAQBCAQI9McJKl5a+UwEAQQEATgEOBelrmiYMay3"
+			+ "q0OW2x2a8QQodYqdUs1TCUU4JhfFGFRy+g3yU1cP/9ZSI8gcI4skdPc31cFG"
+			+ "grP7BAEEBAEIBAhzv/wSV+RBJQQBBAQBCAQI837ImVqqlr4EAQQEAQgECGeU"
+			+ "gjULLnylBAEEBAEIBAjD3P4hlSBCvQQBBAQBCAQISP/qivIzf50EAQQEAQgE"
+			+ "CKIDMX9PKxICBAEEBAOCBOgEggTocP5VVT1vWvpAV6koZupKN1btJ3C01dR6"
+			+ "16g1zJ5FK5xL1PTdA0r6iAwVtgYdxQYnU8tht3bkNXdPJC1BdsC9oTkBg9Nr"
+			+ "dqlF5cCzXWIezcR3ObjGLpXu49SAHvChH4emT5rytv81MYxZ7bGmlQfp8BNa"
+			+ "0cMZz05A56LXw//WWDEzZcbKSk4tCsfMXBdGk/ngs7aILZ4FGM620PBPtD92"
+			+ "pz2Ui/tUZqtQ0WKdLzwga1E/rl02a/x78/OdlVRNeaIYWJWLmLavX98w0PhY"
+			+ "ha3Tbj/fqq+H3ua6Vv2Ff4VeXazkXpp4tTiqUxhc6aAGiRYckwZaP7OPSbos"
+			+ "RKFlRLVofSGu1IVSKO+7faxV4IrVaAAzqRwLGkpJZLV7NkzkU1BwgvsAZAI4"
+			+ "WClPDF228ygbhLwrSN2NK0s+5bKhTCNAR/LCUf3k7uip3ZSe18IwEkUMWiaZ"
+			+ "ayktcTYn2ZjmfIfV7wIxHgWPkP1DeB+RMS7VZe9zEgJKOA16L+9SNBwJSSs9"
+			+ "5Sb1+nmhquZmnAltsXMgwOrR12JLIgdfyyqGcNq997U0/KuHybqBVDVu0Fyr"
+			+ "6O+q5oRmQZq6rju7h+Hb/ZUqRxRoTTSPjGD4Cu9vUqkoNVgwYOT+88FIMYun"
+			+ "g9eChhio2kwPYwU/9BNGGzh+hAvAKcUpO016mGLImYin+FpQxodJXfpNCFpG"
+			+ "4v4HhIwKh71OOfL6ocM/518dYwuU4Ds2/JrDhYYFsn+KprLftjrnTBnSsfYS"
+			+ "t68b+Xr16qv9r6sseEkXbsaNbrGiZAhfHEVBOxQ4lchHrMp4zpduxG4crmpc"
+			+ "+Jy4SadvS0uaJvADgI03DpsDYffUdriECUqAfOg/Hr7HHyr6Q9XMo1GfIarz"
+			+ "eUHBgi1Ny0nDTWkdb7I3bIajG+Unr3KfK6dZz5Lb3g5NeclU5zintB1045Jr"
+			+ "j9fvGGk0/2lG0n17QViBiOzGs2poTlhn7YxmiskwlkRKVafxPZNPxKILpN9s"
+			+ "YaWGz93qER/pGMJarGJxu8sFi3+yt6FZ4pVPkvKE8JZMEPBBrmH41batS3sw"
+			+ "sfnJ5CicAkwd8bluQpoc6qQd81HdNpS6u7djaRSDwPtYnZWu/8Hhj4DXisje"
+			+ "FJBAjQdn2nK4MV7WKVwr+mNcVgOdc5IuOZbRLOfc3Sff6kYVuQFfcCGgAFpd"
+			+ "nbprF/FnYXR/rghWE7fT1gfzSMNv+z5UjZ5Rtg1S/IQfUM/P7t0UqQ01/w58"
+			+ "bTlMGihTxHiJ4Qf3o5GUzNmAyryLvID+nOFqxpr5es6kqSN4GPRHsmUIpB9t"
+			+ "f9Nw952vhsXI9uVkhQap3JvmdAKJaIyDz6Qi7JBZvhxpghVIDh73BQTaAFP9"
+			+ "5GUcPbYOYJzKaU5MeYEsorGoanSqPDeKDeZxjxJD4xFsqJCoutyssqIxnXUN"
+			+ "Y3Uojbz26IJOhqIBLaUn6QVFX79buWYjJ5ZkDS7D8kq6DZeqZclt5711AO5U"
+			+ "uz/eDSrx3d4iVHR+kSeopxFKsrK+KCH3CbBUMIFGX/GE9WPhDWCtjjNKEe8W"
+			+ "PinQtxvv8MlqGXtv3v7ObJ2BmfIfLD0rh3EB5WuRNKL7Ssxaq14KZGEBvc7G"
+			+ "Fx7jXLOW6ZV3SH+C3deJGlKM2kVhDdIVjjODvQzD8qw8a/ZKqDO5hGGKUTGD"
+			+ "Psdd7O/k/Wfn+XdE+YuKIhcEAQQEAQgECJJCZNJdIshRBAEEBAEIBAiGGrlG"
+			+ "HlKwrAQBBAQBCAQIkdvKinJYjJcEAQQEAUAEQBGiIgN/s1bvPQr+p1aQNh/X"
+			+ "UQFmay6Vm5HIvPhoNrX86gmMjr6/sg28/WCRtSfyuYjwQkK91n7MwFLOBaU3"
+			+ "RrsEAQQEAQgECLRqESFR50+zBAEEBAEIBAguqbAEWMTiPwQBBAQBGAQYKzUv"
+			+ "EetQEAe3cXEGlSsY4a/MNTbzu1WbBAEEBAEIBAiVpOv1dOWZ1AQCAAAEAgAA"
+			+ "BAIAAAQCAAAEAgAABAIAAAAAAAAAADA1MCEwCQYFKw4DAhoFAAQUvMkeVqe6"
+			+ "D4UmMHGEQwcb8O7ZwhgEEGiX9DeqtRwQnVi+iY/6Re8AAA==");
+
+		private static readonly byte[] certUTF = Base64.Decode(
+			"MIIGVQIBAzCCBg8GCSqGSIb3DQEHAaCCBgAEggX8MIIF+DCCAsUGCSqGSIb3"
+			+ "DQEHAaCCArYEggKyMIICrjCCAqoGCyqGSIb3DQEMCgEDoIIChTCCAoEGCiqG"
+			+ "SIb3DQEJFgGgggJxBIICbTCCAmkwggHSoAMCAQICAQcwDQYJKoZIhvcNAQEF"
+			+ "BQAwOTEPMA0GA1UEBxMGTGV1dmVuMRkwFwYDVQQKExBVdGltYWNvIFN1YiBD"
+			+ "QSAyMQswCQYDVQQGEwJCRTAeFw05OTEyMzEyMzAwMDBaFw0xOTEyMzEyMzAw"
+			+ "MDBaMFcxCzAJBgNVBAYTAkJFMQ8wDQYDVQQHEwZIYWFjaHQxEDAOBgNVBAoT"
+			+ "B1V0aW1hY28xDDAKBgNVBAsMA1ImRDEXMBUGA1UEAxMOR2VlcnQgRGUgUHJp"
+			+ "bnMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYGIyhTn/p0IA41ElLD"
+			+ "fZ44PS88AAcDCiOd2DIMLck56ea+5nhI0JLyz1XgPHecc8SLFdl7vSIBA0eb"
+			+ "tm/A7WIqIp0lcvgoyQ0qsak/dvzs+xw6r2xLCVogku4+/To6UebtfRsukXNI"
+			+ "ckP5lWV/Ui4l+XvGdmENlEE9/BvOZIvLAgMBAAGjYzBhMBEGA1UdIwQKMAiA"
+			+ "BlN1YkNBMjAQBgNVHQ4ECQQHVXNlcklEMjAOBgNVHQ8BAf8EBAMCBLAwGQYD"
+			+ "VR0RBBIwEIEOVXNlcklEMkB1dGkuYmUwDwYDVR0TAQH/BAUwAwEBADANBgkq"
+			+ "hkiG9w0BAQUFAAOBgQACS7iLLgMV4O5gFdriI7dqX55l7Qn6HiRNxlSH2kCX"
+			+ "41X82gae4MHFc41qqsC4qm6KZWi1yvTN9XgSBCXTaw1SXGTK7SuNdoYh6ufC"
+			+ "KuAwy5lsaetyARDksRiOIrNV9j+MRIjJMjPNg+S+ysIHTWZo2NTUuVuZ01D2"
+			+ "jDtYPhcDFDESMBAGCSqGSIb3DQEJFTEDBAE3MIIDKwYJKoZIhvcNAQcGoIID"
+			+ "HDCCAxgCAQAwggMRBgkqhkiG9w0BBwEwKAYKKoZIhvcNAQwBAzAaBBS5KxQC"
+			+ "BMuZ1To+yed2j/TT45td6gICCACAggLYxQS+fu7W2sLQTkslI0EoNxLoH/WO"
+			+ "L8NgiIgZ5temV3mgC2q0MxjVVq+SCvG89ZSTfptxOaSmYV772irFdzlrtotZ"
+			+ "wmYk1axuFDYQ1gH0M6i9FWuhOnbk7qHclmOroXqrrbP6g3IsjwztH0+iwBCg"
+			+ "39f63V0rr8DHiu7zZ2hBkU4/RHEsXLjaCBVNTUSssWhVLisLh2sqBJccPC2E"
+			+ "1lw4c4WrshGQ+syLGG38ttFgXT1c+xYNpUKqJiJTLVouOH9kK3nH1hPRHKMN"
+			+ "9CucBdUzibvkcRk1L53F3MfvjhCSNeWEmd9PKN+FtUtzRWQG3L84VGTM37Ws"
+			+ "YcxaDwDFGcw3u1W8WFsCCkjpZecKN8P2Kp/ai/iugcXY77bYwAwpETDvQFvD"
+			+ "nnL9oGi03HYdfeiXglC7x7dlojvnpkXDbE0nJiFwhe8Mxpx8GVlGHtP+siXg"
+			+ "tklubg1eTCSoG9m1rsBJM717ZHXUGf32HNun2dn4vOWGocgBmokZ46KKMb9v"
+			+ "reT39JTxi8Jlp+2cYb6Qr/oBzudR+D4iAiiVhhhEbJKPNHa61YyxF810fNI2"
+			+ "GWlNIyN3KcI8XU6WJutm/0H3X8Y+iCSWrJ2exUktj8GiqNQ6Yx0YgEk9HI7W"
+			+ "t9UVTIsPCgCqrV4SWCOPf6so1JqnpvlPvvNyNxSsAJ7DaJx1+oD2QQfhowk/"
+			+ "bygkKnRo5Y15ThrTsIyQKsJHTIVy+6K5uFZnlT1DGV3DcNpuk3AY26hrAzWO"
+			+ "TuWXsULZe7M6h6U2hTT/eplZ/mwHlXdF1VErIuusaCdkSI0doY4/Q223H40L"
+			+ "BNU3pTezl41PLceSll00WGVr2MunlNeXKnXDJW06lnfs9BmnpV2+Lkfmf30W"
+			+ "Pn4RKJQc+3D3SV4fCoQLIGrKiZLFfEdGJcMlySr+dJYcEtoZPuo6i/hb5xot"
+			+ "le63h65ihNtXlEDrNpYSQqnfhjOzk5/+ZvYEcOtDObEwPTAhMAkGBSsOAwIa"
+			+ "BQAEFMIeDI9l2Da24mtA1fbQIPc6+4dUBBQ8a4lD7j1CA1vRLhdEgPM+5hpD"
+			+ "RgICCAA=");
+
+		private static readonly byte[] pkcs12noFriendly = Base64.Decode(
+			"MIACAQMwgAYJKoZIhvcNAQcBoIAkgASCBAAwgDCABgkqhkiG9w0BBwGggCSA"
+			+ "BIICvjCCArowggK2BgsqhkiG9w0BDAoBAqCCAqUwggKhMBsGCiqGSIb3DQEM"
+			+ "AQMwDQQIyJDupEHvySECAQEEggKAupvM7RuZL3G4qNeJM3afElt03TVfynRT"
+			+ "xUxAZOfx+zekHJTlnEuHJ+a16cOV6dQUgYfyMw1xcq4E+l59rVeMX9V3Zr0K"
+			+ "tsMN9VYB/9zn62Kw6LQnY0rMlWYf4bt9Ut5ysq0hE5t9FL+NZ5FbFdWBOKsj"
+			+ "/3oC6eNXOkOFyrY2haPJtD1hVHUosrlC0ffecV0YxPDsReeyx0R4CiYZpAUy"
+			+ "ZD7rkxL+mSX7zTsShRiga2Q/NEhC1KZpbhO/qbyOgvH0r7CRumSMvijzDgaV"
+			+ "IGqtrIZ2E2k5kscjcuFTW0x3OZTLAW/UnAh4JXJzC6isbdiWuswbAEBHifUC"
+			+ "rk2f+bDJKe2gkH67J2K0yDQ3YSSibpjDX/bVfbtfmOoggK9MKQwqEeE0nbYE"
+			+ "jzInH2OK5jPtmwppjmVA7i3Uk25w2+z7b/suUbft9hPCNjxFvzdbyCcXK4Vv"
+			+ "xAgEbVWnIkvOQNbyaQi+DEF/4P26GwgJgXuJpMBn0zzsSZSIDLNl8eJHoKp2"
+			+ "ZXknTi0SZkLaYlBxZlNhFoyXLfvQd6TI2aR5aCVqg1aZMBXyOWfz5t0JTVX8"
+			+ "HTIcdXKis91iEsLB7vjcxIOASTAjKARr5tRp6OvaVterAyDOn2awYQJLLic5"
+			+ "pQfditRAlsLkTxlDdu0/QBMXSPptO8g3R+dS7ntvCjXgZZyxpOeKkssS2l5v"
+			+ "/B2EsfKmYA9hU4aBdW1S9o/PcF1wpVqABd8664TGJ77tCAkbdHe0VJ3Bop2X"
+			+ "lNxlWeEeD0v0QUZLqkJoMEwi5SUE6HAWjbqGhRuHyey9E+UsdCVnQ8AxXQzL"
+			+ "2UKOmIrXc6R25GsLPCysXuXPRFBB2Tul0V3re3hPcAAAAAAAADCABgkqhkiG"
+			+ "9w0BBwaggDCAAgEAMIAGCSqGSIb3DQEHATAbBgoqhkiG9w0BDAEGMA0ECDXn"
+			+ "UZu6xckzAgEBoIAEggTYQMbzAoGnRVJMbCaJJUYgaARJ4zMfxt2e12H4pX/e"
+			+ "vnZrR1eKAMck5c2vJoEasr0i2VUcAcK12AntVIEnBwuRBcA2WrZnC28WR+O7"
+			+ "rLdu9ymG2V3zmk66aTizaB6rcHAzs2lD74n+/zJhZNaDMBfu9LzAdWb/u6Rb"
+			+ "AThmbw764Zyv9802pET6xrB8ureffgyvQAdlcGHM+yxaOV3ZEtS0cp7i+pb/"
+			+ "NTiET4jAFoO1tbBrWGJSRrMKvx4ZREppMhG3e/pYglfMFl+1ejbDsOvEUKSt"
+			+ "H+MVrgDgAv4NsUtNmBu+BIIEAIOCjrBSK3brtV0NZOWsa6hZSSGBhflbEY8s"
+			+ "U1bDsgZIW4ZaJJvSYEXLmiWSBOgq9VxojMfjowY+zj6ePJJMyI3E7AcFa+on"
+			+ "zZjeKxkKypER+TtpBeraqUfgf01b6olH8L2i4+1yotCQ0PS+15qRYPK6D+d3"
+			+ "S+R4veOA6wEsNRijVcB3oQsBCi0FVdf+6MVDvjNzBCZXj0heVi+x0EE106Sz"
+			+ "B3HaDbB/KNHMPZvvs3J3z2lWLj5w7YZ9eVmrVJKsgG2HRKxtt2IQquRj4BkS"
+			+ "upFnMTBVgWxXgwXycauC9bgYZurs+DbijqhHfWpUrttDfavsP8aX6+i3gabK"
+			+ "DH4LQRL7xrTcKkcUHxOTcPHLgDPhi+RevkV+BX9tdajbk4tqw1d+0wOkf1pW"
+			+ "aTG8fUp0lUpra7EJ0lGy8t/MB3NEk/5tLk9qA2nsKKdNoEdZWiEBE0fMrH1o"
+			+ "tWJDew3VhspT+Lkor2dLN5ydjcr3wkb76OETPeMxS91onNj5mrAMUBt66vb6"
+			+ "Gx4CL8FTRNZ/l8Kzngzdv9PmmKPTIXbhYbn3XRGg3od2tC/oVfsqYlGAMgFO"
+			+ "STt+BZ1BR9Phyi4jsiy8R0seCEDRWYQLbwgwVj0V8Rx9VptqRoCnB4XhGJoJ"
+			+ "TdAz/MT7KOSxIh2F2FymTJpyImcV6X4Kcj9iY0AZQ4zj712g4yMR6xKGzRu6"
+			+ "oIBDkFW2bdA3Lb9ePpo5GFtNyA7IbggIko6VOeeOKxaq9nALS2gsZc1yaYtp"
+			+ "aKL8kB+dVTCXiLgQniO6eMzgonsuwFnG+42XM1vhEpAvFzeJRC0CYzebEK9n"
+			+ "nGXKCPoqPFuw3gcPMn57NCZJ8MjT/p0wANIEm6AsgqrdFKwTRVJ1ytB/X9Ri"
+			+ "ysmjMBs9zbFKjU9jVDg1vGBNtb7YnYg9IrYHa3e4yTu2wUJKGP2XWHVgjDR7"
+			+ "6RtzlO4ljw0kkSMMEDle2ZbGZ6lVXbFwV0wPNPmGA6+XGJRxcddTnrM6R/41"
+			+ "zqksFLgoNL2BdofMXwv7SzxGyvFhHdRRdBZ5dKj2K9OfXakEcm/asZGu87u8"
+			+ "y9m7Cckw8ilSNPMdvYiFRoThICx9NiwYl1IIKGcWlb9p6RAx6XNSkY6ZZ6pE"
+			+ "Vla1E26rbd7is1ssSeqxLXXV9anuG5HDwMIt+CIbD8fZmNTcWMzZRiaFajvR"
+			+ "gXdyTu/UhVdhiQPF+lrxp4odgF0cXrpcGaKvOtPq04F4ad3O5EkSGucI210Q"
+			+ "pR/jQs07Yp5xDPzsXAb8naHb84FvK1iONAEjWbfhDxqtH7KGrBbW4KEzJrv3"
+			+ "B8GLDp+wOAFjGEdGDPkOx3y2L2HuI1XiS9LwL+psCily/A96OiUyRU8yEz4A"
+			+ "AAAAAAAAAAAEAwAAAAAAAAAAADAtMCEwCQYFKw4DAhoFAAQU1NQjgVRH6Vg3"
+			+ "tTy3wnQisALy9aYECKiM2gZrLi+fAAA=");
+
+		private static readonly char[] noFriendlyPassword = "sschette12".ToCharArray();
+
+		private static readonly byte[] pkcs12StorageIssue = Base64.Decode(
+			"MIIO8QIBAzCCDrEGCSqGSIb3DQEHAaCCDqIEgg6eMIIOmjCCBBMGCSqGSIb3"
+			+ "DQEHAaCCBAQEggQAMIID/DCCA/gGCyqGSIb3DQEMCgECoIICtjCCArIwHAYK"
+			+ "KoZIhvcNAQwBAzAOBAgURJ+/5hA2pgICB9AEggKQYZ4POE8clgH9Bjd1XO8m"
+			+ "sr6NiRBiA08CllHSOn2RzyAgHTa+cKaWrEVVJ9mCd9XveSUCoBF9E1C3jSl0"
+			+ "XIqLNgYd6mWK9BpeMRImM/5crjy///K4ab9kymzkc5qc0pIpdCQCZ04YmtFP"
+			+ "B80VCgyaoh2xoxqgjBCIgdSg5XdepdA5nXkG9EsQ1oVUyCykv20lKgKKRseG"
+			+ "Jo23AX8YUYR7ANqP2gz9lvlX6RBczuoZ62ujopUexiQgt5SZx97sgo3o/b/C"
+			+ "px17A2L4wLdeAYCMCsZhC2UeaqnZCHSsvnPZfRGiuSEGbV5gHLmXszLDaEdQ"
+			+ "Bo873GTpKTTzBfRFzNCtYtZRqh2AUsInWZWQUcCeX6Ogwa0wTonkp18/tqsh"
+			+ "Fj1fVpnsRmjJTTXFxkPtUw5GPJnDAM0t1xqV7kOjN76XnZrMyk2azQ1Mf3Hn"
+			+ "sGpF+VRGH6JtxbM0Jm5zD9uHcmkSfNR3tP/+vHOB1mkIR9tD2cHvBg7pAlPD"
+			+ "RfDVWynhS+UBNlQ0SEM/pgR7PytRSUoKc/hhe3N8VerF7VL3BwWfBLlZFYZH"
+			+ "FvPQg4coxF7+We7nrSQfXvdVBP9Zf0PTdf3pbZelGCPVjOzbzY/o/cB23IwC"
+			+ "ONxlY8SC1nJDXrPZ5sY51cg/qUqor056YqipRlI6I+FoTMmMDKPAiV1V5ibo"
+			+ "DNQJkyv/CAbTX4+oFlxgddTwYcPZgd/GoGjiP9yBHHdRISatHwMcM06CzXJS"
+			+ "s3MhzXWD4aNxvvSpXAngDLdlB7cm4ja2klmMzL7IuxzLXFQFFvYf7IF5I1pC"
+			+ "YZOmTlJgp0efL9bHjuHFnh0S0lPtlGDOjJ/4YpWvSKDplcPiXhaFVjsUtclE"
+			+ "oxCC5xppRm8QWS8xggEtMA0GCSsGAQQBgjcRAjEAMBMGCSqGSIb3DQEJFTEG"
+			+ "BAQBAAAAMGkGCSsGAQQBgjcRATFcHloATQBpAGMAcgBvAHMAbwBmAHQAIABS"
+			+ "AFMAQQAgAFMAQwBoAGEAbgBuAGUAbAAgAEMAcgB5AHAAdABvAGcAcgBhAHAA"
+			+ "aABpAGMAIABQAHIAbwB2AGkAZABlAHIwgZsGCSqGSIb3DQEJFDGBjR6BigA3"
+			+ "AGQAZQBmADUAYgA0ADMANgBjAGEAYgBkADAAMAAyAGQAZAAyADkAMAAzAGIA"
+			+ "MQA2ADgANgBjADcAOQA0ADgAXwA0ADYAZgAyADYAZgBkADQALQA4ADEAMgBk"
+			+ "AC0ANABlAGYAYgAtADgAMAA4ADgALQA0ADUAYQBiADkAMQA5ADEAMAA3AGMA"
+			+ "YzCCCn8GCSqGSIb3DQEHBqCCCnAwggpsAgEAMIIKZQYJKoZIhvcNAQcBMBwG"
+			+ "CiqGSIb3DQEMAQYwDgQIbr2xdnQ9inMCAgfQgIIKOHg9VKz+jlM+3abi3cp6"
+			+ "/XMathxDSEJLrxJs6j5DAVX17S4sw1Q/1pptjdMdd8QtTfUB6JpfgJ5Kpn+h"
+			+ "gZMf6M8wWue0U/RZN0D9w7o+2n+X3ItdEXu80eJVDOm7I2p8qiXtijbMbXRL"
+			+ "Cup1lgfPM5uv2D63/hmWRXLeG8eySrJnKENngpM559V8TI2JcTUBy1ZP3kcH"
+			+ "KbcJ/tVPnIIe4qguxfsTmDtAQviGvWUohbt+RGFmtqfgntK7o6b+S8uRSwEs"
+			+ "fOU/pnVE9M1ugtNJZI/xeGJq6umZWXA/OrAcK7feWUwqRvfivDGQJEoggByd"
+			+ "4/g92PhK1JGkwlCb1HdfhOOKKChowQ4zVvSOm+uBxARGhk2i5uW9I20I0vSJ"
+			+ "px42O2VFVJweOchfp+wBtSHBKYP1ZXyXWMvOtULClosSeesbYMAwvyBfpYEz"
+			+ "3rQt/1iZkqDmEisXk8X1aEKG1KSWaSPyb/+6glWikDm+YdQw3Khu7IZt1l/H"
+			+ "qWGecccel+R9mT4YjRzHlahUYk4U+RNVasVpH1Kxz2j3CZqL+b3jQOwSAPd/"
+			+ "hKI+S/pjIpBPfiC4WxORAzGZzY2j+a79B70h1DO1D9jGur3vJDbdmGBNgs6d"
+			+ "nonE1B527SICcGeXY1MtnZCLOPvySih0AvOekbN9x2CJg+Hp9e7A3Fxni53/"
+			+ "oMLr9wGRRDki72eXCXW98mU8VJofoWYS1/VBLXGf/f+tJ9J02PpzxleqPH9T"
+			+ "4mE+YHnZId6cqjCXmwvMr2cMw2clDVfvkbAJRE3eZHzL7IWSO8+giXzzrTsl"
+			+ "VbMuXVkT4oniTN7TSRsBCT3zVVmCy1QL2hPBD6KsVc+bvLgAHRov84FPrI3f"
+			+ "kY/oJufT36VE34Eu+QjzULlvVsLE3lhjutOerVIGSP//FM4LE99hp214P0JF"
+			+ "DgBK+3J+ihmFdW8hUXOt6BU8/MBeiroiJMWo1/f/XcduekG2ZsdGv+GNPzXI"
+			+ "PyHRpCgAgmck1+qoUPXxHRJuNqv223OZ5MN14X7iLl5OZ+f8IWfxUnZeZ9gj"
+			+ "HNeceElwZ+YOup1CAi3haD9jxRWhZG4NDfB4IYi4Bc/TAkXE3jCPkYEvIbj9"
+			+ "ExaU1Ts0+lqOOcwRmBoYjVrz0xbtfR/OWlopyrDHbeL5iQcQCW/loYRapWCZ"
+			+ "E4ekHknpX9yoAwT355vtTkl0VKXeSZHE8jREhN95aY9zCoLYwbTQDTw7qUR5"
+			+ "UamabLew0oS0XALtuOrfX4OUOZZUstUsGBle/Pw1TE3Bhe1clhrikp0F+Xgb"
+			+ "Xx90KqxZX/36RMnCMAD7/q+57rV7WXp2Y5tT0AUgyUMjy1F1X/b1olUfqO1u"
+			+ "rlWIUTl2znmQ3D9uO3W4ytfgGd5DpKcl2w84MBAT9qGwKuQg/UYKbP4K/+4L"
+			+ "Y1DWCy3utmohQ28IJtlIUkPL1G7lHX1tfq/VA+bRNTJIhMrNn06ZJpuEJHDs"
+			+ "/ferdlMFt/d6MrwVivmPVYkb8mSbHSiI8jZOFE44sA974depsDyXafFaSsl0"
+			+ "bVzqOAu0C/n9dIednU0xxxgDF/djdZ/QhbaDIg2VJf11wx0nw9n76B0+eeyu"
+			+ "QLaapzxCpQNDVOAM9doBb5F1I5pXQHFQqzTNtLmqDC4x0g8IH7asyk5LCglT"
+			+ "b1pwMqPJOL2vGWKRLhPzT+9OfSpCmYGKytf593hmGmwIgEO13hQrw31F5TYt"
+			+ "btkbDr+Q5XilOKEczhEM+Ug7YHU7bxkckOAbxu0YeRp/57GdGLokeLJ0dRlQ"
+			+ "+V2CfQvWJoVC6PS4PUQtjwgK2p/LU10QsEFwM/S621fGq9zGrv7+FPBATRDb"
+			+ "k4E9D/WaRylnW11ZTrOlTchQkoHcOh0xztlFxU8jzuIuDrPQQWkoqdl6B+yf"
+			+ "lykRNJKKxwzFiPl40nLC3nEdIzCEvR4r/9QHiWQxAVSc/wQX+an5vakUmSXS"
+			+ "oLFjgVdY1jmvdsx2r5BQPuOR8ONGmw/muvVSMaHV85brA4uk0lxn00HD9/a0"
+			+ "A1LCeFkabNLn9wJT8RaJeOSNmFFllLR70OHaoPSb3GyzHpvd1e6aeaimdyVH"
+			+ "BQWJ6Ufx+HjbOGuOiN46WyE6Q27dnWxx8qF89dKB4T/J0mEXqueiUjAUnnnR"
+			+ "Cs4zPaX53hmNBdrZGaLs+xNG8xy+iyBUJIWWfQAQjCjfHYlT9nygiUWIbVQq"
+			+ "RHkGkAN62jsSNLgHvWVzQPNNsYq0U8TPhyyci/vc8MJytujjptcz8FPqUjg2"
+			+ "TPv34ef9buErsm4vsdEv/8Z+9aDaNex+O3Lo3N0Aw7M5NcntFBHjFY/nBFNZ"
+			+ "whH5YA4gQ8PLZ5qshlGvb0DFXHV/9zxnsdPkLwH47ERm5IlEAuoaWtZFxg27"
+			+ "BjLfwU1Opk+ybDSb5WZVZrs7ljsU85p3Vaf3a//yoyr9ITYj15tTXxSPoct0"
+			+ "fDUy1I6LjJH/+eZXKA1WSda9mDQlRocvJ0IIIlI4weJpTdm8aHIJ8OngCqOF"
+			+ "TufcSLDM41+nxEK1LqXeAScVy74kVvvqngj6mIrbylrINZOHheEgTXrUWEc0"
+			+ "uXS8l1YqY6K6Ru5km2jVyWi/ujrDGb6QGShC09oiDYUuUGy4gwJ3XLVX/dR3"
+			+ "pmMExohTGiVefFP400wVZaxB9g1BQmjSEZxIaW1U1K6fk8Yni8yWB3/L/PuD"
+			+ "0+OV+98i1sQGaPe35crIpEc7R2XJdngL0Ol1ZuvCIBfy5DQwGIawTtBnjPdi"
+			+ "hy//QTt/isdu7C5pGaJDkZFMrfxMibr6c3xXr7wwR75sTzPNmS8mquEdLsmG"
+			+ "h8gTUnB8/K6V11JtUExMqTimTbUw+j8PggpeBelG36breWJIz1O+dmCTGuLM"
+			+ "x/sK/i8eiUeRvWjqYpq5DYt4URWg2WlcpcKiUxQp07/NMx0svDC+mlQGwMnJ"
+			+ "8KOJMW1qr3TGEJ/VVKKVn6sXn/RxA+VPofYzhwZByRX87XmNdPeQKC2DHQsW"
+			+ "6v83dua5gcnv0cv/smXt7Yr/c12i0fbIaQvj3qjtUCDucjARoBey3eCyG5H6"
+			+ "5VHSsFnPZ2HCTum+jRSw/ENsu/77XU4BIM2fjAfswp7iIr2Xi4OZWKIj6o6q"
+			+ "+fNgnOJjemDYHAFK+hWxClrG8b+9Eaf21o4zcHkhCfBlYv4d+xcZOIDsDPwI"
+			+ "sf+4V+CfoBLALsa2K0pXlPplGom/a8h7CjlyaICbWpEDItqwu7NQwdMRCa7i"
+			+ "yAyM1sVjXUdcZByS1bjOFSeBe7ygAvEl78vApLxqt8Cw11XSsOtmwssecUN/"
+			+ "pb7iHE4OMyOgsYx9u7rZ2hMyl42n3c29IwDYMumiNqk9cwCBpQTJAQEv4VzO"
+			+ "QE5xYDBY9SEozni+4f7B7e2Wj/LOGb3vfNVYGNpDczBFxvr2FXTQla0lNYD/"
+			+ "aePuC++QW4KvwiGL1Zx4Jo0eoDKWYlYj0qiNlQbWfVw+raaaFnlrq+je0W6P"
+			+ "+BrKZCncho145y+CFKRLZrN5yl/cDxwsePMVhAIMr1DzVhgBXzA3MB8wBwYF"
+			+ "Kw4DAhoEFN4Cwj9AtArnRbOIAsRhaaoZlTNJBBTIVPqCrloqLns145CWXjb0"
+			+ "g141BQ==");
+
+		private static readonly char[] storagePassword = "pass".ToCharArray();
+
+		private static readonly byte[] pkcs12nopass = Base64.Decode(
+			"MIIMvgIBAzCCDIQGCSqGSIb3DQEHAaCCDHUEggxxMIIMbTCCCS8GCSqGSIb3"
+			+ "DQEHBqCCCSAwggkcAgEAMIIJFQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYw"
+			+ "DgQIfnlhuZRR6/YCAggAgIII6DYgeRwq5n9kzvohZ3JuK+fB+9jZ7Or6EGBA"
+			+ "GDxtBfHmSNUBWJEV/I8wV1zrKKoW/CaoZfA61pyrVZRd/roaqBx/koTFoh/g"
+			+ "woyyWTRV9gYTXSVqPQgCH+e2dISAa6UGO+/YOWOOwG2X3t8tS+3FduFQFLt5"
+			+ "cvUP98zENdm57Aef5pKpBSZDLIAoTASfmqwszWABRh2p/wKOHcCQ9Aj2e2vs"
+			+ "pls/ntIv81MqPuxHttwX8e+3dKWGFrJRztLpCD2aua8VkSsHFsPxEHkezX4O"
+			+ "6/VCjMCRFGophTS4dgKKtQIhZ9i/ESlr6sGKgIpyG99ALFpNEhtTKe+T3boE"
+			+ "sEkhGDquSpu4PGz2m0W5sej1DyFkKX4zIbeMDAb1y3O7aP0F+Llo9QSeGsOA"
+			+ "aCwND3NUAKBMOHzwdyNQcuCGCqY8j5rrSt99A5FMs3UVW3XU6hRCx7JlzO05"
+			+ "PNCkcPRSnKSNzBhIR5W0qj4PAZnQTfX+wbtUaDLIqsObX4Muh2l3gl+JmdpO"
+			+ "53U7ILqN8PAPly1eT+fIrUmlMmFhvo6LbTB7B2K728wsA/5wROlud/mOQz4s"
+			+ "quS288YsnVc9ExSZKodWa3Pqcdb/cgKNJYDxrR6/eBHOj+0RLK/1yTK9ghj7"
+			+ "IPYHoEqQbw768WK92RjM+RFGlXASkQhR9y4weWj/388uAWMIbQ+R2Zi4nb31"
+			+ "knjqRPFThysG1bsRL04/9PgysaasfS9KYOeAlLqp+Ar4gJrof5fytBuY+6wm"
+			+ "/J8eEdNw7VPV1cz/4rhrd2sfJQwDEN/iZoy8rTwe7wozpwZI0lwH11BBbav+"
+			+ "1AMfI79jjxhqOeo7uxE2NzUmSd05JYI7a94tcRzGQyGEKpGxYCRamzFW23qb"
+			+ "vG5Hcqi7Tdd7eTxw4c60l/vQLSo38g6ST5yZrK3URLiAtpioPyjrq2jnVfie"
+			+ "QLsiAHhpHF01+t+OcKv3UjwdEyBmQ34h9klwiG7iwBFXZaPXFCF2Np1TqFVG"
+			+ "jjBzmB+hRddEiYwN+XGCKB2Cvgc5ZMQ8LG9jQmEKLmOjuumz1ciAVY2qtl1s"
+			+ "HYSvfNsIAV/gGzHshOVF19JmGtcQt3pMtupoRh+sh8jY2/x5eIKrj2Jx6HPd"
+			+ "p/6IPUr54j0xSd6j7gWuXMj/eKp/utMNuBzAhkydnhXYedvTDYIj7SyPPIHa"
+			+ "qtam8rxTDWn2AOxp7OXTgPmo1GU2zW1OLL1D3MFlS+oaRMfhgNrhW+QP5ay6"
+			+ "ge4QLijpnSM+p0CbFAOClwzgdJV56bBVV09sDqSBXnG9MeEv5nDaH3I+GpPA"
+			+ "UgDkaI4zT61kaGgk0uNMf3czy2ycoQzTx0iHDTXSdSqvUC1yFza8UG4AYaKz"
+			+ "14gtSL7StvZtK0Y8oI084BINI1LgrWyrOLj7vkds4WrKhXm21BtM1GbN/pFh"
+			+ "XI41h+XoD8KnEPqJ36rAgBo1uHqTNJCC7YikDE/dEvq6MkOx+Nug1YZRHEyi"
+			+ "3AHry5u1HJHtxT34HXBwRXvnstuFhvU6cjc1WY1dJhu1p82TGnx7OBo/QbcM"
+			+ "8MRrWmWuU5eW4jWbriGNGYfvZy+tHnGwy0bIeqrsHOG6/JwvfmYYXe64sryH"
+			+ "5Qo96SZtcTJZaNFwuBY+bFUuOWm8YrT1L7Gl2Muf3pEVtNHLeYARBo1jEAym"
+			+ "Cb4jw0oodZqbPKdyyzUZu69fdTJiQkMUcKDfHJEGK0Li9SvtdqJLiiJs57Tb"
+			+ "YfOvn+TIuC40ssJFtmtlGCVH/0vtKLWYeW1NYAMzgI/nlhQ7W6Aroh8sZnqv"
+			+ "SwxeQmRJaVLxiV6YveTKuVlCbqNVLeEtKYAujgnJtPemGCPbwZpwlBw6V+Dz"
+			+ "oXveOBcUqATztWJeNv7RbU0Mk7k057+DNxXBIU+eHRGquyHQSBXxBbA+OFuu"
+			+ "4SPfEAyoYed0HEaoKN9lIsBW1xTROI30MZvaJXvPdLsa8izXGPLnTGmoI+fv"
+			+ "tJ644HtBCCCr3Reu82ZsTSDMxspZ9aa4ro9Oza+R5eULXDhVXedbhJBYiPPo"
+			+ "J37El5lRqOgu2SEilhhVQq3ZCugsinCaY9P/RtWG4CFnH1IcIT5+/mivB48I"
+			+ "2XfH6Xq6ziJdj2/r86mhEnz9sKunNvYPBDGlOvI7xucEf9AiEQoTR1xyFDbW"
+			+ "ljL4BsJqgsHN02LyUzLwqMstwv+/JH1wUuXSK40Kik/N7+jEFW2C+/N8tN7l"
+			+ "RPKSLaTjxVuTfdv/BH1dkV4iGFgpQrdWkWgkb+VZP9xE2mLz715eIAg13x6+"
+			+ "n97tc9Hh375xZJqwr3QyYTXWpsK/vx04RThv8p0qMdqKvf3jVQWwnCnoeBv2"
+			+ "L4h/uisOLY18qka/Y48ttympG+6DpmzXTwD1LycoG2SOWckCMmJhZK40+zr3"
+			+ "NVmWf6iJtbLGMxI/kzTqbTaOfXc2MroertyM1rILRSpgnJFxJfai5Enspr9b"
+			+ "SCwlP718jG2lQsnYlw8CuxoZAiaNy4MmC5Y3qNl3hlcggcHeLodyGkSyRsBg"
+			+ "cEiKSL7JNvqr0X/nUeW28zVxkmQsWlp3KmST8agf+r+sQvw52fXNLdYznGZV"
+			+ "rJrwgNOoRj0Z70MwTns3s/tCqDEsy5Sv/5dZW2uQEe7/wvmsP2WLu73Rwplg"
+			+ "1dwi/Uo9lO9dkEzmoIK5wMPCDINxL1K+0Y79q0tIAEMDgaIxmtRpEh8/TEsA"
+			+ "UwyEErkDsQqgGviH+ePmawJ/yehYHTRfYUgdUflwApJxRx65pDeSYkiYboMU"
+			+ "8WSAQY2nh/p9hLlS4zbz9dCK2tzVyRkJgqNy/c4IpiHEx2l1iipW9vENglqx"
+			+ "dYP4uqD8e3OOLjDQKizWx2t1u7GRwoEVQ3d3QzzOvsRcv7h+6vNsmYqE6phe"
+			+ "wKFZLctpSn21zkyut444ij4sSr1OG68dEXLY0t0mATfTmXXy5GJBsdK/lLfk"
+			+ "YTIPYYeDMle9aEicDqaKqkZUuYPnVchGp8UFMJ3M0n48OMDdDvpzBLTxxZeW"
+			+ "cK5v/m3OEo3jgxy9wXfZdz//J3zXXqvX8LpMy1K9X0uCBTz6ERlawviMQhg1"
+			+ "1okD5zCCAzYGCSqGSIb3DQEHAaCCAycEggMjMIIDHzCCAxsGCyqGSIb3DQEM"
+			+ "CgECoIICpjCCAqIwHAYKKoZIhvcNAQwBAzAOBAj3QoojTSbZqgICCAAEggKA"
+			+ "YOSp5XGdnG1pdm9CfvlAaUSHRCOyNLndoUTqteTZjHTEM9bGwNXAx4/R5H2Q"
+			+ "PnPm5HB/ynVSXX0uKdW6YlbqUyAdV3eqE4X3Nl+K7ZoXmgAFnMr0tveBhT1b"
+			+ "7rTi0TN4twjJzBTkKcxT8XKjvpVizUxGo+Ss5Wk8FrWLHAiC5dZvgRemtGcM"
+			+ "w5S09Pwj+qXpjUhX1pB5/63qWPrjVf+Bfmlz4bWcqogGk0i7eg+OdTeWMrW0"
+			+ "KR9nD1+/uNEyc4FdGtdIPnM+ax0E+vcco0ExQpTXe0xoX4JW7O71d550Wp89"
+			+ "hAVPNrJA5eUbSWNsuz+38gjUJ+4XaAEhcA7HZIp6ZyxtzSJUoh7oqpRktoxu"
+			+ "3cSVqVxIqAEqlNn6j0vbKfW91Od5DI5L+BIxY4xqXS7fdwipj9r6qWA8t9QU"
+			+ "C2r1A+xXpZ4jEh6inHW9qlfACBBrYf8pSDakSR6yTbaA07LExw0IXz5oiQYt"
+			+ "s7yx231CZlOH88bBmruLOIZsJjeg/lf63zI7Gg4F85QG3RqEJnY2pinLUTP7"
+			+ "R62VErFZPc2a85r2dbFH1mSQIj/rT1IKe32zIW8xoHC4VwrPkT3bcLFAu2TH"
+			+ "5k5zSI/gZUKjPDxb2dwLM4pvsj3gJ9vcFZp6BCuLkZc5rd7CyD8HK9PrBLKd"
+			+ "H3Yngy4A08W4U3XUtIux95WE+5O/UEmSF7fr2vT//DwZArGUpBPq4Bikb8cv"
+			+ "0wpOwUv8r0DXveeaPsxdipXlt29Ayywcs6KIidLtCaCX6/0u/XtMsGNFS+ah"
+			+ "OlumTGBFpbLnagvIf0GKNhbg2lTjflACnxIj8d+QWsnrIU1uC1JRRKCnhpi2"
+			+ "veeWd1m8GUb3aTFiMCMGCSqGSIb3DQEJFTEWBBS9g+Xmq/8B462FWFfaLWd/"
+			+ "rlFxOTA7BgkqhkiG9w0BCRQxLh4sAEMAZQByAHQAeQBmAGkAawBhAHQAIAB1"
+			+ "AHoAeQB0AGsAbwB3AG4AaQBrAGEwMTAhMAkGBSsOAwIaBQAEFKJpUOIj0OtI"
+			+ "j2CPp38YIFBEqvjsBAi8G+yhJe3A/wICCAA=");
+
+		/**
+		* we generate a self signed certificate for the sake of testing - RSA
+		*/
+		public X509CertificateEntry CreateCert(
+			AsymmetricKeyParameter	pubKey,
+			AsymmetricKeyParameter	privKey,
+			string					issuerEmail,
+			string					subjectEmail)
+		{
+			//
+			// distinguished name table.
+			//
+            IDictionary issuerAttrs = new Hashtable();
+			issuerAttrs.Add(X509Name.C, "AU");
+			issuerAttrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+			issuerAttrs.Add(X509Name.L, "Melbourne");
+			issuerAttrs.Add(X509Name.ST, "Victoria");
+			issuerAttrs.Add(X509Name.EmailAddress, issuerEmail);
+
+			IDictionary subjectAttrs = new Hashtable();
+			subjectAttrs.Add(X509Name.C, "AU");
+			subjectAttrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+			subjectAttrs.Add(X509Name.L, "Melbourne");
+			subjectAttrs.Add(X509Name.ST, "Victoria");
+			subjectAttrs.Add(X509Name.EmailAddress, subjectEmail);
+
+			IList order = new ArrayList();
+			order.Add(X509Name.C);
+			order.Add(X509Name.O);
+			order.Add(X509Name.L);
+			order.Add(X509Name.ST);
+			order.Add(X509Name.EmailAddress);
+
+			//
+			// extensions
+			//
+
+			//
+			// create the certificate - version 3
+			//
+			X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+			certGen.SetSerialNumber(BigInteger.One);
+			certGen.SetIssuerDN(new X509Name(order, issuerAttrs));
+			certGen.SetNotBefore(DateTime.UtcNow.AddDays(-30));
+			certGen.SetNotAfter(DateTime.UtcNow.AddDays(30));
+			certGen.SetSubjectDN(new X509Name(order, subjectAttrs));
+			certGen.SetPublicKey(pubKey);
+			certGen.SetSignatureAlgorithm("MD5WithRSAEncryption");
+
+			return new X509CertificateEntry(certGen.Generate(privKey));
+		}
+
+		public void doTestPkcs12Store()
+		{
+			BigInteger mod = new BigInteger("bb1be8074e4787a8d77967f1575ef72dd7582f9b3347724413c021beafad8f32dba5168e280cbf284df722283dad2fd4abc750e3d6487c2942064e2d8d80641aa5866d1f6f1f83eec26b9b46fecb3b1c9856a303148a5cc899c642fb16f3d9d72f52526c751dc81622c420c82e2cfda70fe8d13f16cc7d6a613a5b2a2b5894d1", 16);
+
+			MemoryStream stream = new MemoryStream(pkcs12, false);
+			Pkcs12Store store = new Pkcs12StoreBuilder().Build();
+			store.Load(stream, passwd);
+
+			string pName = null;
+			foreach (string n in store.Aliases)
+			{
+				if (store.IsKeyEntry(n))
+				{
+					pName = n;
+					//break;
+				}
+			}
+
+			AsymmetricKeyEntry key = store.GetKey(pName);
+
+			if (!((RsaKeyParameters) key.Key).Modulus.Equals(mod))
+			{
+				Fail("Modulus doesn't match.");
+			}
+
+			X509CertificateEntry[] ch = store.GetCertificateChain(pName);
+
+			if (ch.Length != 3)
+			{
+				Fail("chain was wrong length");
+			}
+
+			if (!ch[0].Certificate.SerialNumber.Equals(new BigInteger("96153094170511488342715101755496684211")))
+			{
+				Fail("chain[0] wrong certificate.");
+			}
+
+			if (!ch[1].Certificate.SerialNumber.Equals(new BigInteger("279751514312356623147411505294772931957")))
+			{
+				Fail("chain[1] wrong certificate.");
+			}
+
+			if (!ch[2].Certificate.SerialNumber.Equals(new BigInteger("11341398017")))
+			{
+				Fail("chain[2] wrong certificate.");
+			}
+
+			//
+			// save test
+			//
+			MemoryStream bOut = new MemoryStream();
+			store.Save(bOut, passwd, new SecureRandom());
+
+			stream = new MemoryStream(bOut.ToArray(), false);
+			store.Load(stream, passwd);
+
+			key = store.GetKey(pName);
+
+			if (!((RsaKeyParameters)key.Key).Modulus.Equals(mod))
+			{
+				Fail("Modulus doesn't match.");
+			}
+
+			store.DeleteEntry(pName);
+
+			if (store.GetKey(pName) != null)
+			{
+				Fail("Failed deletion test.");
+			}
+
+			//
+			// cert chain test
+			//
+			store.SetCertificateEntry("testCert", ch[2]);
+
+			if (store.GetCertificateChain("testCert") != null)
+			{
+				Fail("Failed null chain test.");
+			}
+
+			//
+			// UTF 8 single cert test
+			//
+			stream = new MemoryStream(certUTF, false);
+			store.Load(stream, "user".ToCharArray());
+
+			if (store.GetCertificate("37") == null)
+			{
+				Fail("Failed to find UTF cert.");
+			}
+
+			//
+			// try for a self generated certificate
+			//
+			RsaKeyParameters pubKey = new RsaKeyParameters(
+				false,
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16));
+
+			RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16),
+				new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+				new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+				new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+				new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+				new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+				new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+			X509CertificateEntry[] chain = new X509CertificateEntry[] {
+				CreateCert(pubKey, privKey, "issuer@bouncycastle.org", "subject@bouncycastle.org")
+			};
+
+			store = new Pkcs12StoreBuilder().Build();
+
+			store.SetKeyEntry("privateKey", new AsymmetricKeyEntry(privKey), chain);
+
+			if (!store.ContainsAlias("privateKey") || !store.ContainsAlias("PRIVATEKEY"))
+			{
+				Fail("couldn't find alias privateKey");
+			}
+
+			if (store.IsCertificateEntry("privateKey"))
+			{
+				Fail("key identified as certificate entry");
+			}
+
+			if (!store.IsKeyEntry("privateKey") || !store.IsKeyEntry("PRIVATEKEY"))
+			{
+				Fail("key not identified as key entry");
+			}
+
+			if (!"privateKey".Equals(store.GetCertificateAlias(chain[0].Certificate)))
+			{
+				Fail("Did not return alias for key certificate privateKey");
+			}
+
+			MemoryStream store1Stream = new MemoryStream();
+			store.Save(store1Stream, passwd, new SecureRandom());
+			testNoExtraLocalKeyID(store1Stream.ToArray());
+
+			//
+			// no friendly name test
+			//
+			stream = new MemoryStream(pkcs12noFriendly, false);
+			store.Load(stream, noFriendlyPassword);
+
+			pName = null;
+
+			foreach (string n in store.Aliases)
+			{
+				if (store.IsKeyEntry(n))
+				{
+					pName = n;
+					//break;
+				}
+			}
+
+			ch = store.GetCertificateChain(pName);
+
+			//for (int i = 0; i != ch.Length; i++)
+			//{
+			//	Console.WriteLine(ch[i]);
+			//}
+
+			if (ch.Length != 1)
+			{
+				Fail("no cert found in pkcs12noFriendly");
+			}
+
+			//
+			// failure tests
+			//
+			ch = store.GetCertificateChain("dummy");
+
+			store.GetCertificateChain("DUMMY");
+
+			store.GetCertificate("dummy");
+
+			store.GetCertificate("DUMMY");
+
+			//
+			// storage test
+			//
+			stream = new MemoryStream(pkcs12StorageIssue, false);
+			store.Load(stream, storagePassword);
+
+			pName = null;
+
+			foreach (string n in store.Aliases)
+			{
+				if (store.IsKeyEntry(n))
+				{
+					pName = n;
+					//break;
+				}
+			}
+
+			ch = store.GetCertificateChain(pName);
+			if (ch.Length != 2)
+			{
+				Fail("Certificate chain wrong length");
+			}
+
+			store.Save(new MemoryStream(), storagePassword, new SecureRandom());
+
+			//
+			// basic certificate check
+			//
+			store.SetCertificateEntry("cert", ch[1]);
+
+			if (!store.ContainsAlias("cert") || !store.ContainsAlias("CERT"))
+			{
+				Fail("couldn't find alias cert");
+			}
+
+			if (!store.IsCertificateEntry("cert") || !store.IsCertificateEntry("CERT"))
+			{
+				Fail("cert not identified as certificate entry");
+			}
+
+			if (store.IsKeyEntry("cert") || store.IsKeyEntry("CERT"))
+			{
+				Fail("cert identified as key entry");
+			}
+
+			if (!store.IsEntryOfType("cert", typeof(X509CertificateEntry)))
+			{
+				Fail("cert not identified as X509CertificateEntry");
+			}
+
+			if (!store.IsEntryOfType("CERT", typeof(X509CertificateEntry)))
+			{
+				Fail("CERT not identified as X509CertificateEntry");
+			}
+
+			if (store.IsEntryOfType("cert", typeof(AsymmetricKeyEntry)))
+			{
+				Fail("cert identified as key entry via AsymmetricKeyEntry");
+			}
+
+			if (!"cert".Equals(store.GetCertificateAlias(ch[1].Certificate)))
+			{
+				Fail("Did not return alias for certificate entry");
+			}
+
+			//
+			// test restoring of a certificate with private key originally as a ca certificate
+			//
+			store = new Pkcs12StoreBuilder().Build();
+
+			store.SetCertificateEntry("cert", ch[0]);
+
+			if (!store.ContainsAlias("cert") || !store.ContainsAlias("CERT"))
+			{
+				Fail("restore: couldn't find alias cert");
+			}
+
+			if (!store.IsCertificateEntry("cert") || !store.IsCertificateEntry("CERT"))
+			{
+				Fail("restore: cert not identified as certificate entry");
+			}
+
+			if (store.IsKeyEntry("cert") || store.IsKeyEntry("CERT"))
+			{
+				Fail("restore: cert identified as key entry");
+			}
+
+			if (store.IsEntryOfType("cert", typeof(AsymmetricKeyEntry)))
+			{
+				Fail("restore: cert identified as key entry via AsymmetricKeyEntry");
+			}
+
+			if (store.IsEntryOfType("CERT", typeof(AsymmetricKeyEntry)))
+			{
+				Fail("restore: cert identified as key entry via AsymmetricKeyEntry");
+			}
+
+			if (!store.IsEntryOfType("cert", typeof(X509CertificateEntry)))
+			{
+				Fail("restore: cert not identified as X509CertificateEntry");
+			}
+
+			//
+			// test of reading incorrect zero-length encoding
+			//
+			stream = new MemoryStream(pkcs12nopass, false);
+			store.Load(stream, "".ToCharArray());
+		}
+
+		private void testSupportedTypes(AsymmetricKeyEntry privKey, X509CertificateEntry[] chain)
+		{
+			basicStoreTest(privKey, chain,
+				PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
+				PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc );
+			basicStoreTest(privKey, chain,
+				PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
+				PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc );
+		}
+
+		private void basicStoreTest(AsymmetricKeyEntry privKey, X509CertificateEntry[] chain,
+			DerObjectIdentifier keyAlgorithm, DerObjectIdentifier certAlgorithm)
+		{
+			Pkcs12Store store = new Pkcs12StoreBuilder()
+				.SetKeyAlgorithm(keyAlgorithm)
+				.SetCertAlgorithm(certAlgorithm)
+				.Build();
+
+			store.SetKeyEntry("key", privKey, chain);
+
+			MemoryStream bOut = new MemoryStream();
+
+			store.Save(bOut, passwd, new SecureRandom());
+
+			store.Load(new MemoryStream(bOut.ToArray(), false), passwd);
+
+			AsymmetricKeyEntry k = store.GetKey("key");
+
+			if (!k.Equals(privKey))
+			{
+				Fail("private key didn't match");
+			}
+
+			X509CertificateEntry[] c = store.GetCertificateChain("key");
+
+			if (c.Length != chain.Length || !c[0].Equals(chain[0]))
+			{
+				Fail("certificates didn't match");
+			}
+
+			// check attributes
+			Pkcs12Entry b1 = k;
+			Pkcs12Entry b2 = chain[0];
+
+			if (b1[PkcsObjectIdentifiers.Pkcs9AtFriendlyName] != null)
+			{
+				DerBmpString name = (DerBmpString)b1[PkcsObjectIdentifiers.Pkcs9AtFriendlyName];
+
+				if (!name.Equals(new DerBmpString("key")))
+				{
+					Fail("friendly name wrong");
+				}
+			}
+			else
+			{
+				Fail("no friendly name found on key");
+			}
+
+			if (b1[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] != null)
+			{
+				Asn1OctetString id = (Asn1OctetString)b1[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID];
+
+				if (!id.Equals(b2[PkcsObjectIdentifiers.Pkcs9AtLocalKeyID]))
+				{
+					Fail("local key id mismatch");
+				}
+			}
+			else
+			{
+				Fail("no local key id found");
+			}
+
+			//
+			// check algorithm types.
+			//
+			Asn1InputStream aIn = new Asn1InputStream(bOut.ToArray());
+
+			Pfx pfx = new Pfx((Asn1Sequence)aIn.ReadObject());
+
+			ContentInfo cInfo = pfx.AuthSafe;
+
+			Asn1OctetString auth = (Asn1OctetString)cInfo.Content;
+
+			aIn = new Asn1InputStream(auth.GetOctets());
+			Asn1Sequence s1 = (Asn1Sequence)aIn.ReadObject();
+
+			ContentInfo c1 = ContentInfo.GetInstance(s1[0]);
+			ContentInfo c2 = ContentInfo.GetInstance(s1[1]);
+
+			aIn = new Asn1InputStream(((Asn1OctetString)c1.Content).GetOctets());
+
+			SafeBag sb = new SafeBag((Asn1Sequence)(((Asn1Sequence)aIn.ReadObject())[0]));
+
+			EncryptedPrivateKeyInfo encInfo = EncryptedPrivateKeyInfo.GetInstance(sb.BagValue);
+
+			// check the key encryption
+			if (!encInfo.EncryptionAlgorithm.ObjectID.Equals(keyAlgorithm))
+			{
+				Fail("key encryption algorithm wrong");
+			}
+
+			// check the certificate encryption
+			EncryptedData cb = EncryptedData.GetInstance(c2.Content);
+
+			if (!cb.EncryptionAlgorithm.ObjectID.Equals(certAlgorithm))
+			{
+				Fail("cert encryption algorithm wrong");
+			}
+		}
+
+		private void testNoExtraLocalKeyID(byte[] store1data)
+		{
+			IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator("RSA");
+			kpg.Init(new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x10001), new SecureRandom(), 512, 25));
+
+			AsymmetricCipherKeyPair newPair =  kpg.GenerateKeyPair();
+
+			Pkcs12Store store1 = new Pkcs12StoreBuilder().Build();
+			store1.Load(new MemoryStream(store1data, false), passwd);
+
+			Pkcs12Store store2 = new Pkcs12StoreBuilder().Build();
+
+			AsymmetricKeyEntry k1 = store1.GetKey("privatekey");
+			X509CertificateEntry[] chain1 = store1.GetCertificateChain("privatekey");
+
+			X509CertificateEntry[] chain2 = new X509CertificateEntry[chain1.Length + 1];
+
+			Array.Copy(chain1, 0, chain2, 1, chain1.Length);
+
+			chain2[0] = CreateCert(newPair.Public, k1.Key, "subject@bouncycastle.org", "extra@bouncycaste.org");
+
+			if (chain1[0][PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] == null)
+			{
+				Fail("localKeyID not found initially");
+			}
+
+			store2.SetKeyEntry("new", new AsymmetricKeyEntry(newPair.Private), chain2);
+
+			MemoryStream bOut = new MemoryStream();
+
+			store2.Save(bOut, passwd, new SecureRandom());
+
+			store2.Load(new MemoryStream(bOut.ToArray(), false), passwd);
+
+			chain2 = store2.GetCertificateChain("new");
+
+			if (chain2[1][PkcsObjectIdentifiers.Pkcs9AtLocalKeyID] != null)
+			{
+				Fail("localKeyID found after save");
+			}
+		}
+
+		public override string Name
+		{
+			get { return "PKCS12Store"; }
+		}
+
+		public override void PerformTest()
+		{
+			doTestPkcs12Store();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Pkcs12StoreTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/security/test/SecureRandomTest.cs b/crypto/test/src/security/test/SecureRandomTest.cs
new file mode 100644
index 000000000..12e4b9a47
--- /dev/null
+++ b/crypto/test/src/security/test/SecureRandomTest.cs
@@ -0,0 +1,150 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto.Prng;
+
+namespace Org.BouncyCastle.Security.Tests
+{
+	[TestFixture]
+	public class SecureRandomTest
+	{
+#if !NETCF_1_0
+		[Test]
+		public void TestCryptoApi()
+		{
+			SecureRandom random = new SecureRandom(
+				new CryptoApiRandomGenerator());
+
+			checkSecureRandom(random);
+		}
+#endif
+
+		[Test]
+		public void TestDefault()
+		{
+			SecureRandom random = new SecureRandom();
+
+			checkSecureRandom(random);
+		}
+
+		[Test]
+		public void TestSha1Prng()
+		{
+			SecureRandom random = SecureRandom.GetInstance("SHA1PRNG");
+			random.SetSeed(SecureRandom.GetSeed(20));
+
+			checkSecureRandom(random);
+		}
+
+		[Test]
+		public void TestSha256Prng()
+		{
+			SecureRandom random = SecureRandom.GetInstance("SHA256PRNG");
+			random.SetSeed(SecureRandom.GetSeed(32));
+
+			checkSecureRandom(random);
+		}
+
+		[Test]
+		public void TestThreadedSeed()
+		{
+			SecureRandom random = new SecureRandom(
+				new ThreadedSeedGenerator().GenerateSeed(20, false));
+
+			checkSecureRandom(random);
+		}
+
+		[Test]
+		public void TestVmpcPrng()
+		{
+			SecureRandom random = new SecureRandom(new VmpcRandomGenerator());
+			random.SetSeed(SecureRandom.GetSeed(32));
+
+			checkSecureRandom(random);
+		}
+
+
+		private static void checkSecureRandom(
+			SecureRandom random)
+		{
+			// Note: This will periodically (< 1e-6 probability) give a false alarm.
+			// That's randomness for you!
+			Assert.IsTrue(runChiSquaredTests(random), "Chi2 test detected possible non-randomness");
+		}
+
+		private static bool runChiSquaredTests(
+			SecureRandom random)
+		{
+			int passes = 0;
+
+			for (int tries = 0; tries < 100; ++tries)
+			{
+				double chi2 = measureChiSquared(random, 1000);
+				if (chi2 < 285.0) // 255 degrees of freedom in test => Q ~ 10.0% for 285
+					++passes;
+			}
+
+			return passes > 75;
+		}
+
+		private static double measureChiSquared(
+			SecureRandom	random,
+			int				rounds)
+		{
+			int[] counts = new int[256];
+
+			byte[] bs = new byte[256];
+			for (int i = 0; i < rounds; ++i)
+			{
+				random.NextBytes(bs);
+
+				for (int b = 0; b < 256; ++b)
+				{
+					++counts[bs[b]];
+				}
+			}
+
+			byte mask = SecureRandom.GetSeed(1)[0];
+			for (int i = 0; i < rounds; ++i)
+			{
+				random.NextBytes(bs);
+
+				for (int b = 0; b < 256; ++b)
+				{
+					++counts[bs[b] ^ mask];
+				}
+
+				++mask;
+			}
+
+			byte shift = SecureRandom.GetSeed(1)[0];
+			for (int i = 0; i < rounds; ++i)
+			{
+				random.NextBytes(bs);
+
+				for (int b = 0; b < 256; ++b)
+				{
+					++counts[(byte)(bs[b] + shift)];
+				}
+
+				++shift;
+			}
+
+			int total = 3 * rounds;
+
+			double chi2 = 0;
+			for (int k = 0; k < counts.Length; ++k)
+			{
+				double diff = ((double) counts[k]) - total;
+				double diff2 = diff * diff;
+
+				chi2 += diff2;
+			}
+
+			chi2 /= total;
+
+			return chi2;
+		}
+	}
+}
diff --git a/crypto/test/src/security/test/TestDigestUtil.cs b/crypto/test/src/security/test/TestDigestUtil.cs
new file mode 100644
index 000000000..0f169f931
--- /dev/null
+++ b/crypto/test/src/security/test/TestDigestUtil.cs
@@ -0,0 +1,63 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+
+namespace Org.BouncyCastle.Security.Tests
+{
+    [TestFixture]
+    public class TestDigestUtilities
+    {
+		private static readonly byte[] TestBytes = new byte[100];
+
+		static TestDigestUtilities()
+		{
+			new SecureRandom().NextBytes(TestBytes);
+		}
+
+		[Test]
+        public void TestAlgorithms()
+        {
+			CheckAlgorithm("GOST3411", new Gost3411Digest());
+			CheckAlgorithm("MD2", new MD2Digest());
+            CheckAlgorithm("MD4", new MD4Digest());
+            CheckAlgorithm("MD5", new MD5Digest());
+			CheckAlgorithm("RipeMD128", new RipeMD128Digest());
+			CheckAlgorithm("RipeMD160", new RipeMD160Digest());
+			CheckAlgorithm("RipeMD256", new RipeMD256Digest());
+			CheckAlgorithm("RipeMD320", new RipeMD320Digest());
+			CheckAlgorithm("SHA-1", new Sha1Digest());
+            CheckAlgorithm("SHA-224", new Sha224Digest());
+            CheckAlgorithm("SHA-256", new Sha256Digest());
+            CheckAlgorithm("SHA-384", new Sha384Digest());
+            CheckAlgorithm("SHA-512", new Sha512Digest());
+			CheckAlgorithm("Tiger", new TigerDigest());
+			CheckAlgorithm("Whirlpool", new WhirlpoolDigest());
+		}
+
+		private void CheckAlgorithm(
+            string	name,
+            IDigest	digest)
+        {
+            byte[] hash1 = MakeTestHash(digest);
+			byte[] hash2 = MakeTestHash(DigestUtilities.GetDigest(name));
+
+			Assert.AreEqual(hash1, hash2, name);
+        }
+
+		private byte[] MakeTestHash(
+			IDigest digest)
+		{
+			for (int i = 0; i < digest.GetDigestSize(); ++i)
+			{
+				digest.Update((byte) i);
+			}
+
+			digest.BlockUpdate(TestBytes, 0, TestBytes.Length);
+
+			return DigestUtilities.DoFinal(digest);
+		}
+    }
+}
diff --git a/crypto/test/src/security/test/TestDotNetUtil.cs b/crypto/test/src/security/test/TestDotNetUtil.cs
new file mode 100644
index 000000000..f880b388f
--- /dev/null
+++ b/crypto/test/src/security/test/TestDotNetUtil.cs
@@ -0,0 +1,88 @@
+#if !(NETCF_1_0 || SILVERLIGHT)
+
+using System;
+using System.Security.Cryptography;
+using SystemX509 = System.Security.Cryptography.X509Certificates;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Security.Tests
+{
+	[TestFixture]
+	public class TestDotNetUtilities
+	{
+		[Test]
+		public void TestRsaInterop()
+		{
+			for (int i = 0; i < 100; ++i)
+			{
+				RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
+				RSAParameters rp = rsa.ExportParameters(true);
+				AsymmetricCipherKeyPair kp = DotNetUtilities.GetRsaKeyPair(rp);
+
+				DotNetUtilities.ToRSA((RsaKeyParameters)kp.Public);
+				// TODO This method appears to not work for private keys (when no CRT info)
+				//DotNetUtilities.ToRSA((RsaKeyParameters)kp.Private);
+				DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)kp.Private);
+			}
+		}
+
+		[Test]
+		public void TestX509CertificateConversion()
+		{
+			BigInteger DSAParaG = new BigInteger(Base64.Decode("AL0fxOTq10OHFbCf8YldyGembqEu08EDVzxyLL29Zn/t4It661YNol1rnhPIs+cirw+yf9zeCe+KL1IbZ/qIMZM="));
+			BigInteger DSAParaP = new BigInteger(Base64.Decode("AM2b/UeQA+ovv3dL05wlDHEKJ+qhnJBsRT5OB9WuyRC830G79y0R8wuq8jyIYWCYcTn1TeqVPWqiTv6oAoiEeOs="));
+			BigInteger DSAParaQ = new BigInteger(Base64.Decode("AIlJT7mcKL6SUBMmvm24zX1EvjNx"));
+			BigInteger DSAPublicY = new BigInteger(Base64.Decode("TtWy2GuT9yGBWOHi1/EpCDa/bWJCk2+yAdr56rAcqP0eHGkMnA9s9GJD2nGU8sFjNHm55swpn6JQb8q0agrCfw=="));
+			BigInteger DsaPrivateX = new BigInteger(Base64.Decode("MMpBAxNlv7eYfxLTZ2BItJeD31A="));
+
+			DsaParameters para = new DsaParameters(DSAParaP, DSAParaQ, DSAParaG);
+			DsaPrivateKeyParameters dsaPriv = new DsaPrivateKeyParameters(DsaPrivateX, para);
+			DsaPublicKeyParameters dsaPub = new DsaPublicKeyParameters(DSAPublicY, para);
+
+			IDictionary attrs = new Hashtable();
+			attrs[X509Name.C] = "AU";
+			attrs[X509Name.O] = "The Legion of the Bouncy Castle";
+			attrs[X509Name.L] = "Melbourne";
+			attrs[X509Name.ST] = "Victoria";
+			attrs[X509Name.E] = "feedback-crypto@bouncycastle.org";
+
+			IList ord = new ArrayList(attrs.Keys);
+
+			X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+			certGen.SetSerialNumber(BigInteger.One);
+
+			certGen.SetIssuerDN(new X509Name(ord, attrs));
+			certGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));
+			certGen.SetNotAfter(DateTime.UtcNow.AddDays(1));
+			certGen.SetSubjectDN(new X509Name(ord, attrs));
+			certGen.SetPublicKey(dsaPub);
+			certGen.SetSignatureAlgorithm("SHA1WITHDSA");
+
+			X509Certificate cert = certGen.Generate(dsaPriv);
+
+			cert.CheckValidity();
+			cert.Verify(dsaPub);
+
+			SystemX509.X509Certificate dotNetCert = DotNetUtilities.ToX509Certificate(cert);
+
+			X509Certificate certCopy = DotNetUtilities.FromX509Certificate(dotNetCert);
+
+			Assert.AreEqual(cert, certCopy);
+
+			certCopy.CheckValidity();
+			certCopy.Verify(dsaPub);
+		}
+	}
+}
+
+#endif
diff --git a/crypto/test/src/security/test/TestEncodings.cs b/crypto/test/src/security/test/TestEncodings.cs
new file mode 100644
index 000000000..557d2dc51
--- /dev/null
+++ b/crypto/test/src/security/test/TestEncodings.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Security.Tests
+{
+    [TestFixture]
+    public class TestEncodings
+    {
+		[Test]
+		public void TestEC()
+		{
+			BigInteger ECParraGX = new BigInteger(Base64.Decode("D/qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqv"));
+			BigInteger ECParraGY = new BigInteger(Base64.Decode("AhQXGxb1olGRv6s1LPRfuatMF+cx3ZTGgzSE/Q5R"));
+			BigInteger ECParraH = new BigInteger(Base64.Decode("AQ=="));
+			BigInteger ECParraN = new BigInteger(Base64.Decode("f///////////////f///nl6an12QcfvRUiaIkJ0L"));
+			BigInteger ECPubQX = new BigInteger(Base64.Decode("HWWi17Yb+Bm3PYr/DMjLOYNFhyOwX1QY7ZvqqM+l"));
+			BigInteger ECPubQY = new BigInteger(Base64.Decode("JrlJfxu3WGhqwtL/55BOs/wsUeiDFsvXcGhB8DGx"));
+			BigInteger ECPrivD = new BigInteger(Base64.Decode("GYQmd/NF1B+He1iMkWt3by2Az6Eu07t0ynJ4YCAo"));
+
+			FpCurve curve = new FpCurve(
+				new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+			ECDomainParameters ecDomain =
+				new ECDomainParameters(
+					curve,
+					new FpPoint(curve,
+						curve.FromBigInteger(ECParraGX),
+						curve.FromBigInteger(ECParraGY)),
+				ECParraN);
+
+			ECPublicKeyParameters ecPub = new ECPublicKeyParameters(
+				new FpPoint(
+					curve,
+					curve.FromBigInteger(ECPubQX),
+					curve.FromBigInteger(ECPubQY)),
+				ecDomain);
+
+			ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters(ECPrivD, ecDomain);
+
+			SubjectPublicKeyInfo subinfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(ecPub);
+			PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(ecPriv);
+
+			ECPublicKeyParameters tecPub = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(subinfo);
+			ECPrivateKeyParameters tecPriv = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(privInfo);
+
+			Assert.IsTrue(tecPub.Equals(ecPub), "EC: public key to info back to public key");
+			Assert.IsTrue(tecPriv.Equals(ecPriv), "EC: private key to info back to private key");
+		}
+
+        [Test]
+        public void TestDH()
+        {
+            BigInteger DHParraP = new BigInteger(Base64.Decode("ALJCm1CUL6mOnyVqWTSV6Z2+DVSGOvgboOhmbyyxCrym59uVnXMmPjIgQTrmniFg7PvdcN7NNFwFmcZleULso1s="));
+            BigInteger DHParraQ = new BigInteger(Base64.Decode("WSFNqEoX1MdPkrUsmkr0zt8GqkMdfA3QdDM3lliFXlNz7crOuZMfGRAgnXNPELB2fe64b2aaLgLM4zK8oXZRrQ=="));
+            BigInteger DHPubY = new BigInteger(Base64.Decode("AIki+8/zggCS2e488AsTNULI4LujdUeQQsZI949Dc9lKXZRmrPIC1h8NRoneHQEhpAe4Rhe0nhUOGZJekT5++SA="));
+            BigInteger DHPrivX = new BigInteger(Base64.Decode("Apo67noMRO5eDWo/TtpRiBmKGw7ywh25shIu0Rs03krQmWKRbDPvdygWdJ5IpW6ZbKlCTAMhSxpz03YSeSEDmw=="));
+
+
+            DHParameters dhPara = new DHParameters(DHParraP, DHParraQ);
+            DHPublicKeyParameters dhPublic = new DHPublicKeyParameters(DHPubY, dhPara);
+            DHPrivateKeyParameters dhPrivate = new DHPrivateKeyParameters(DHPrivX, dhPara);
+
+            SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(dhPublic);
+            PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(dhPrivate);
+
+            DHPublicKeyParameters testPubKey = (DHPublicKeyParameters) PublicKeyFactory.CreateKey(pubInfo);
+            DHPrivateKeyParameters testPrivKey = (DHPrivateKeyParameters) PrivateKeyFactory.CreateKey(privInfo);
+
+            Assert.IsFalse(!testPrivKey.Equals(dhPrivate), "DH: Private key to info back to key");
+            Assert.IsFalse(!testPubKey.Equals(dhPublic), "DH: Public key to info back to key");
+
+            Assert.IsTrue(true, "Diffe Helman Test worked.");
+
+        }
+
+        [Test]
+        public void TestElGamal()
+        {
+
+                BigInteger ELGamalParaG = new BigInteger(Base64.Decode("QAZPRcsH8kHVKS5065R1Xy6QtsPvDkmDZtPuq18EJkvLrCIZivE/m5puQp3/VKJrG7dKgz4NBGpONp3HT+Cn/g=="));
+                BigInteger ELGamalParaP = new BigInteger(Base64.Decode("AKXmAwgkudDLI/Yxk6wk3APn+mSjX5QSyDwpchmegSIi1ZNC0Jb+IbxjroKNhRTBKjtv4/JTXtJS6IqaZv9uKes="));
+                BigInteger ELGamalPubY = new BigInteger(Base64.Decode("AJ/gXuZuCA2X044otNkzs8FI36XuFu1L/YHg5cEmDvICTigycRN2E1DnhP+CTqxEqgEqX8rBe5tuGDlkTLwgNqM="));
+                BigInteger ELGamalPriv = new BigInteger(Base64.Decode("CqVr+K0TpuJKQnc76MjKhxrJzGr93jnuE3mTpth486Meymt8uWEVAQj1tGc9DTt14F9aV9WIT2oYYbvLJRcwow=="));
+
+
+
+                ElGamalParameters elPara = new ElGamalParameters(ELGamalParaP, ELGamalParaG);
+
+                ElGamalPrivateKeyParameters elPriv = new ElGamalPrivateKeyParameters(ELGamalPriv, elPara);
+                ElGamalPublicKeyParameters elPub = new ElGamalPublicKeyParameters(ELGamalPubY, elPara);
+
+                SubjectPublicKeyInfo subInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(elPub);
+                PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(elPriv);
+
+                ElGamalPrivateKeyParameters telPriv = (ElGamalPrivateKeyParameters)PrivateKeyFactory.CreateKey(privInfo);
+                ElGamalPublicKeyParameters telPub = (ElGamalPublicKeyParameters)PublicKeyFactory.CreateKey(subInfo);
+
+
+                             // Console.WriteLine(telPriv.Equals(elPriv));
+
+
+
+                Assert.IsTrue(telPriv.Equals(elPriv), "ELGamal Private key to into back to private key.");
+                Assert.IsTrue(telPub.Equals(elPub), "ELGamal Public key to into back to private key.");
+
+                Assert.IsTrue(true, "ELGamal Test worked.");
+
+            }
+
+        [Test]
+        public void TestRsa()
+        {
+
+            BigInteger rsaPubMod = new BigInteger(Base64.Decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt"));
+            BigInteger rsaPubExp = new BigInteger(Base64.Decode("EQ=="));
+            BigInteger rsaPrivMod = new BigInteger(Base64.Decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt"));
+            BigInteger rsaPrivDP = new BigInteger(Base64.Decode("JXzfzG5v+HtLJIZqYMUefJfFLu8DPuJGaLD6lI3cZ0babWZ/oPGoJa5iHpX4Ul/7l3s1PFsuy1GhzCdOdlfRcQ=="));
+            BigInteger rsaPrivDQ = new BigInteger(Base64.Decode("YNdJhw3cn0gBoVmMIFRZzflPDNthBiWy/dUMSRfJCxoZjSnr1gysZHK01HteV1YYNGcwPdr3j4FbOfri5c6DUQ=="));
+            BigInteger rsaPrivExp = new BigInteger(Base64.Decode("DxFAOhDajr00rBjqX+7nyZ/9sHWRCCp9WEN5wCsFiWVRPtdB+NeLcou7mWXwf1Y+8xNgmmh//fPV45G2dsyBeZbXeJwB7bzx9NMEAfedchyOwjR8PYdjK3NpTLKtZlEJ6Jkh4QihrXpZMO4fKZWUm9bid3+lmiq43FwW+Hof8/E="));
+            BigInteger rsaPrivP = new BigInteger(Base64.Decode("AJ9StyTVW+AL/1s7RBtFwZGFBgd3zctBqzzwKPda6LbtIFDznmwDCqAlIQH9X14X7UPLokCDhuAa76OnDXb1OiE="));
+            BigInteger rsaPrivQ = new BigInteger(Base64.Decode("AM3JfD79dNJ5A3beScSzPtWxx/tSLi0QHFtkuhtSizeXdkv5FSba7lVzwEOGKHmW829bRoNxThDy4ds1IihW1w0="));
+            BigInteger rsaPrivQinv = new BigInteger(Base64.Decode("Lt0g7wrsNsQxuDdB8q/rH8fSFeBXMGLtCIqfOec1j7FEIuYA/ACiRDgXkHa0WgN7nLXSjHoy630wC5Toq8vvUg=="));
+            RsaKeyParameters rsaPublic = new RsaKeyParameters(false, rsaPubMod, rsaPubExp);
+			RsaPrivateCrtKeyParameters rsaPrivate = new RsaPrivateCrtKeyParameters(rsaPrivMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv);
+
+			SubjectPublicKeyInfo subInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rsaPublic);
+            RsaKeyParameters testResult = (RsaKeyParameters)PublicKeyFactory.CreateKey(subInfo);
+
+			// check RSA public key.
+
+            Assert.IsFalse(!testResult.Equals(rsaPublic), "RSA: test failed on public key to info and back to public key.");
+
+            PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(rsaPrivate);
+            testResult = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(privInfo);
+
+            Assert.IsFalse(!testResult.Equals(rsaPrivate), "RSA: private key to info back to private key.");
+
+            Assert.IsTrue(true, "RSATest worked.");
+
+        }
+
+        [Test]
+        public void TestDSA()
+        {
+            BigInteger DSAParaG = new BigInteger(Base64.Decode("AL0fxOTq10OHFbCf8YldyGembqEu08EDVzxyLL29Zn/t4It661YNol1rnhPIs+cirw+yf9zeCe+KL1IbZ/qIMZM="));
+            BigInteger DSAParaP = new BigInteger(Base64.Decode("AM2b/UeQA+ovv3dL05wlDHEKJ+qhnJBsRT5OB9WuyRC830G79y0R8wuq8jyIYWCYcTn1TeqVPWqiTv6oAoiEeOs="));
+            BigInteger DSAParaQ = new BigInteger(Base64.Decode("AIlJT7mcKL6SUBMmvm24zX1EvjNx"));
+            BigInteger DSAPublicY = new BigInteger(Base64.Decode("TtWy2GuT9yGBWOHi1/EpCDa/bWJCk2+yAdr56rAcqP0eHGkMnA9s9GJD2nGU8sFjNHm55swpn6JQb8q0agrCfw=="));
+            BigInteger DsaPrivateX = new BigInteger(Base64.Decode("MMpBAxNlv7eYfxLTZ2BItJeD31A="));
+
+            DsaParameters para = new DsaParameters(DSAParaP, DSAParaQ, DSAParaG);
+            DsaPrivateKeyParameters dsaPriv = new DsaPrivateKeyParameters(DsaPrivateX, para);
+            DsaPublicKeyParameters dsaPub = new DsaPublicKeyParameters(DSAPublicY, para);
+
+            SubjectPublicKeyInfo subInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(dsaPub);
+            DsaKeyParameters testResult = (DsaKeyParameters)PublicKeyFactory.CreateKey(subInfo);
+
+            // check RSA public key.
+
+            Assert.IsFalse(!testResult.Equals(dsaPub), "DSA: test failed on public key to info and back to public key.");
+
+            PrivateKeyInfo privInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(dsaPriv);
+            testResult = (DsaPrivateKeyParameters)PrivateKeyFactory.CreateKey(privInfo);
+
+            Assert.IsFalse(!testResult.Equals(dsaPriv), "DSA: private key to info back to private key.");
+
+            Assert.IsTrue(true, "DSATest worked.");
+
+        }
+    }
+}
diff --git a/crypto/test/src/security/test/TestParameterUtil.cs b/crypto/test/src/security/test/TestParameterUtil.cs
new file mode 100644
index 000000000..fe494212a
--- /dev/null
+++ b/crypto/test/src/security/test/TestParameterUtil.cs
@@ -0,0 +1,74 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security.Tests
+{
+	[TestFixture]
+	public class TestParameterUtilities
+	{
+		[Test]
+		public void TestCreateKeyParameter()
+		{
+			SecureRandom random = new SecureRandom();
+
+			doTestCreateKeyParameter("AES", NistObjectIdentifiers.IdAes128Cbc,
+				128, typeof(KeyParameter), random);
+			doTestCreateKeyParameter("DES", OiwObjectIdentifiers.DesCbc,
+				64, typeof(DesParameters), random);
+			doTestCreateKeyParameter("DESEDE", PkcsObjectIdentifiers.DesEde3Cbc,
+				192, typeof(DesEdeParameters), random);
+			doTestCreateKeyParameter("RC2", PkcsObjectIdentifiers.RC2Cbc,
+				128, typeof(RC2Parameters), random);
+		}
+
+		private void doTestCreateKeyParameter(
+			string				algorithm,
+			DerObjectIdentifier	oid,
+			int					keyBits,
+			Type				expectedType,
+			SecureRandom		random)
+		{
+			int keyLength = keyBits / 8;
+			byte[] bytes = new byte[keyLength];
+			random.NextBytes(bytes);
+
+			KeyParameter key;
+
+			key = ParameterUtilities.CreateKeyParameter(algorithm, bytes);
+			checkKeyParameter(key, expectedType, bytes);
+
+			key = ParameterUtilities.CreateKeyParameter(oid, bytes);
+			checkKeyParameter(key, expectedType, bytes);
+
+			bytes = new byte[keyLength * 2];
+			random.NextBytes(bytes);
+
+			int offset = random.Next(1, keyLength);
+			byte[] expected = new byte[keyLength];
+			Array.Copy(bytes, offset, expected, 0, keyLength);
+
+			key = ParameterUtilities.CreateKeyParameter(algorithm, bytes, offset, keyLength);
+			checkKeyParameter(key, expectedType, expected);
+
+			key = ParameterUtilities.CreateKeyParameter(oid, bytes, offset, keyLength);
+			checkKeyParameter(key, expectedType, expected);
+		}
+
+		private void checkKeyParameter(
+			KeyParameter	key,
+			Type			expectedType,
+			byte[]			expectedBytes)
+		{
+			Assert.IsTrue(expectedType.IsInstanceOfType(key));
+			Assert.IsTrue(Arrays.AreEqual(expectedBytes, key.GetKey()));
+		}
+	}
+}
diff --git a/crypto/test/src/security/test/TestSignerUtil.cs b/crypto/test/src/security/test/TestSignerUtil.cs
new file mode 100644
index 000000000..18b856e3f
--- /dev/null
+++ b/crypto/test/src/security/test/TestSignerUtil.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Security.Tests
+{
+    [TestFixture]
+    public class TestSignerUtilities
+    {
+        [Test]
+        public void TestAlgorithms()
+        {
+            //
+            // RSA parameters
+            //
+            BigInteger rsaMod = new BigInteger("a7295693155b1813bb84877fb45343556e0568043de5910872a3a518cc11e23e2db74eaf4545068c4e3d258a2718fbacdcc3eafa457695b957e88fbf110aed049a992d9c430232d02f3529c67a3419935ea9b569f85b1bcd37de6b899cd62697e843130ff0529d09c97d813cb15f293751ff56f943fbdabb63971cc7f4f6d5bff1594416b1f5907bde5a84a44f9802ef29b43bda1960f948f8afb8766c1ab80d32eec88ed66d0b65aebe44a6d0b3c5e0ab051aaa1b912fbcc17b8e751ddecc5365b6db6dab0020c3057db4013a51213a5798a3aab67985b0f4d88627a54a0f3f0285fbcb4afdfeb65cb153af66825656d43238b75503231500753f4e421e3c57", 16);
+            BigInteger rsaPubExp = new BigInteger("10001", 16);
+
+            BigInteger rsaPrivExp = new BigInteger("65dad56ac7df7abb434e4cb5eeadb16093aa6da7f0033aad3815289b04757d32bfee6ade7749c8e4a323b5050a2fb9e2a99e23469e1ed4ba5bab54336af20a5bfccb8b3424cc6923db2ffca5787ed87aa87aa614cd04cedaebc8f623a2d2063017910f436dff18bb06f01758610787f8b258f0a8efd8bd7de30007c47b2a1031696c7d6523bc191d4d918927a7e0b09584ed205bd2ff4fc4382678df82353f7532b3bbb81d69e3f39070aed3fb64fce032a089e8e64955afa5213a6eb241231bd98d702fba725a9b205952fda186412d9e0d9344d2998c455ad8c2bae85ee672751466d5288304032b5b7e02f7e558c7af82c7fbf58eea0bb4ef0f001e6cd0a9", 16);
+            BigInteger rsaPrivP = new BigInteger("d4fd9ac3474fb83aaf832470643609659e511b322632b239b688f3cd2aad87527d6cf652fb9c9ca67940e84789444f2e99b0cb0cfabbd4de95396106c865f38e2fb7b82b231260a94df0e01756bf73ce0386868d9c41645560a81af2f53c18e4f7cdf3d51d80267372e6e0216afbf67f655c9450769cca494e4f6631b239ce1b", 16);
+            BigInteger rsaPrivQ = new BigInteger("c8eaa0e2a1b3a4412a702bccda93f4d150da60d736c99c7c566fdea4dd1b401cbc0d8c063daaf0b579953d36343aa18b33dbf8b9eae94452490cc905245f8f7b9e29b1a288bc66731a29e1dd1a45c9fd7f8238ff727adc49fff73991d0dc096206b9d3a08f61e7462e2b804d78cb8c5eccdb9b7fbd2ad6a8fea46c1053e1be75", 16);
+            BigInteger rsaPrivDP = new BigInteger("10edcb544421c0f9e123624d1099feeb35c72a8b34e008ac6fa6b90210a7543f293af4e5299c8c12eb464e70092805c7256e18e5823455ba0f504d36f5ccacac1b7cd5c58ff710f9c3f92646949d88fdd1e7ea5fed1081820bb9b0d2a8cd4b093fecfdb96dabd6e28c3a6f8c186dc86cddc89afd3e403e0fcf8a9e0bcb27af0b", 16);
+            BigInteger rsaPrivDQ = new BigInteger("97fc25484b5a415eaa63c03e6efa8dafe9a1c8b004d9ee6e80548fefd6f2ce44ee5cb117e77e70285798f57d137566ce8ea4503b13e0f1b5ed5ca6942537c4aa96b2a395782a4cb5b58d0936e0b0fa63b1192954d39ced176d71ef32c6f42c84e2e19f9d4dd999c2151b032b97bd22aa73fd8c5bcd15a2dca4046d5acc997021", 16);
+            BigInteger rsaPrivQinv = new BigInteger("4bb8064e1eff7e9efc3c4578fcedb59ca4aef0993a8312dfdcb1b3decf458aa6650d3d0866f143cbf0d3825e9381181170a0a1651eefcd7def786b8eb356555d9fa07c85b5f5cbdd74382f1129b5e36b4166b6cc9157923699708648212c484958351fdc9cf14f218dbe7fbf7cbd93a209a4681fe23ceb44bab67d66f45d1c9d", 16);
+
+            RsaKeyParameters rsaPublic = new RsaKeyParameters(false, rsaMod, rsaPubExp);
+            RsaPrivateCrtKeyParameters rsaPrivate = new RsaPrivateCrtKeyParameters(
+                rsaMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv);
+
+            //
+            // ECDSA parameters
+            //
+            BigInteger ECParraGX = new BigInteger(Base64.Decode("D/qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqv"));
+            BigInteger ECParraGY = new BigInteger(Base64.Decode("AhQXGxb1olGRv6s1LPRfuatMF+cx3ZTGgzSE/Q5R"));
+            BigInteger ECParraH = new BigInteger(Base64.Decode("AQ=="));
+            BigInteger ECParraN = new BigInteger(Base64.Decode("f///////////////f///nl6an12QcfvRUiaIkJ0L"));
+            BigInteger ECPubQX = new BigInteger(Base64.Decode("HWWi17Yb+Bm3PYr/DMjLOYNFhyOwX1QY7ZvqqM+l"));
+            BigInteger ECPubQY = new BigInteger(Base64.Decode("JrlJfxu3WGhqwtL/55BOs/wsUeiDFsvXcGhB8DGx"));
+            BigInteger ECPrivD = new BigInteger(Base64.Decode("GYQmd/NF1B+He1iMkWt3by2Az6Eu07t0ynJ4YCAo"));
+
+            FpCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters ecDomain = new ECDomainParameters(curve,
+                new FpPoint(curve,
+                    curve.FromBigInteger(ECParraGX),
+                    curve.FromBigInteger(ECParraGY)),
+                ECParraN);
+
+            ECPublicKeyParameters ecPub = new ECPublicKeyParameters(
+                new FpPoint(curve,
+                    curve.FromBigInteger(ECPubQX),
+                    curve.FromBigInteger(ECPubQY)),
+                ecDomain);
+
+            ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters(ECPrivD, ecDomain);
+
+            //
+            // DSA parameters
+            //
+            BigInteger DSAParaG = new BigInteger(Base64.Decode("AL0fxOTq10OHFbCf8YldyGembqEu08EDVzxyLL29Zn/t4It661YNol1rnhPIs+cirw+yf9zeCe+KL1IbZ/qIMZM="));
+            BigInteger DSAParaP = new BigInteger(Base64.Decode("AM2b/UeQA+ovv3dL05wlDHEKJ+qhnJBsRT5OB9WuyRC830G79y0R8wuq8jyIYWCYcTn1TeqVPWqiTv6oAoiEeOs="));
+            BigInteger DSAParaQ = new BigInteger(Base64.Decode("AIlJT7mcKL6SUBMmvm24zX1EvjNx"));
+            BigInteger DSAPublicY = new BigInteger(Base64.Decode("TtWy2GuT9yGBWOHi1/EpCDa/bWJCk2+yAdr56rAcqP0eHGkMnA9s9GJD2nGU8sFjNHm55swpn6JQb8q0agrCfw=="));
+            BigInteger DsaPrivateX = new BigInteger(Base64.Decode("MMpBAxNlv7eYfxLTZ2BItJeD31A="));
+
+            DsaParameters para = new DsaParameters(DSAParaP, DSAParaQ, DSAParaG);
+            DsaPrivateKeyParameters dsaPriv = new DsaPrivateKeyParameters(DsaPrivateX, para);
+            DsaPublicKeyParameters dsaPub = new DsaPublicKeyParameters(DSAPublicY, para);
+
+            //
+            // ECGOST3410 parameters
+            //
+            IAsymmetricCipherKeyPairGenerator ecGostKpg = GeneratorUtilities.GetKeyPairGenerator("ECGOST3410");
+            ecGostKpg.Init(
+                new ECKeyGenerationParameters(
+                    CryptoProObjectIdentifiers.GostR3410x2001CryptoProA,
+                    new SecureRandom()));
+
+            AsymmetricCipherKeyPair ecGostPair = ecGostKpg.GenerateKeyPair();
+
+            //
+            // GOST3410 parameters
+            //
+            IAsymmetricCipherKeyPairGenerator gostKpg = GeneratorUtilities.GetKeyPairGenerator("GOST3410");
+            gostKpg.Init(
+                new Gost3410KeyGenerationParameters(
+                    new SecureRandom(),
+                    CryptoProObjectIdentifiers.GostR3410x94CryptoProA));
+
+            AsymmetricCipherKeyPair gostPair = gostKpg.GenerateKeyPair();
+
+
+
+            //
+            // signer loop
+            //
+            byte[] shortMsg = new byte[] { 1, 4, 5, 6, 8, 8, 4, 2, 1, 3 };
+            byte[] longMsg = new byte[100];
+            new SecureRandom().NextBytes(longMsg);
+
+            foreach (string algorithm in SignerUtilities.Algorithms)
+            {
+                ISigner signer = SignerUtilities.GetSigner(algorithm);
+
+                string upper = algorithm.ToUpper(CultureInfo.InvariantCulture);
+                int withPos = upper.LastIndexOf("WITH");
+
+                string cipherName = withPos < 0
+                    ?	upper
+                    :	upper.Substring(withPos + "WITH".Length);
+
+                ICipherParameters signParams = null, verifyParams = null;
+
+                if (cipherName == "RSA" || cipherName == "RSAANDMGF1")
+                {
+                    signParams = rsaPrivate;
+                    verifyParams = rsaPublic;
+                }
+                else if (cipherName == "ECDSA")
+                {
+                    signParams = ecPriv;
+                    verifyParams = ecPub;
+                }
+                else if (cipherName == "DSA")
+                {
+                    signParams = dsaPriv;
+                    verifyParams = dsaPub;
+                }
+                else if (cipherName == "ECGOST3410")
+                {
+                    signParams = ecGostPair.Private;
+                    verifyParams = ecGostPair.Public;
+                }
+                else if (cipherName == "GOST3410")
+                {
+                    signParams = gostPair.Private;
+                    verifyParams = gostPair.Public;
+                }
+                else
+                {
+                    Assert.Fail("Unknown algorithm encountered: " + cipherName);
+                }
+
+                signer.Init(true, signParams);
+                foreach (byte b in shortMsg)
+                {
+                    signer.Update(b);
+                }
+                signer.BlockUpdate(longMsg, 0, longMsg.Length);
+                byte[] sig = signer.GenerateSignature();
+
+                signer.Init(false, verifyParams);
+                foreach (byte b in shortMsg)
+                {
+                    signer.Update(b);
+                }
+                signer.BlockUpdate(longMsg, 0, longMsg.Length);
+
+                Assert.IsTrue(signer.VerifySignature(sig), cipherName + " signer " + algorithm + " failed.");
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/test/AESSICTest.cs b/crypto/test/src/test/AESSICTest.cs
new file mode 100644
index 000000000..f8de35efd
--- /dev/null
+++ b/crypto/test/src/test/AESSICTest.cs
@@ -0,0 +1,147 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <remarks>
+	/// Test vectors based on NIST Special Publication 800-38A,
+	/// "Recommendation for Block Cipher Modes of Operation"
+	/// </remarks>
+	[TestFixture]
+	public class AesSicTest
+		: SimpleTest
+	{
+		private static readonly byte[][] keys =
+		{
+			Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c"),
+			Hex.Decode("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"),
+			Hex.Decode("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4")
+		};
+
+		private static readonly byte[][] plain =
+		{
+			Hex.Decode("6bc1bee22e409f96e93d7e117393172a"),
+			Hex.Decode("ae2d8a571e03ac9c9eb76fac45af8e51"),
+			Hex.Decode("30c81c46a35ce411e5fbc1191a0a52ef"),
+			Hex.Decode("f69f2445df4f9b17ad2b417be66c3710")
+		};
+
+		private static readonly byte[,][] cipher =
+		{
+			{
+				Hex.Decode("874d6191b620e3261bef6864990db6ce"),
+				Hex.Decode("9806f66b7970fdff8617187bb9fffdff"),
+				Hex.Decode("5ae4df3edbd5d35e5b4f09020db03eab"),
+				Hex.Decode("1e031dda2fbe03d1792170a0f3009cee")
+			},
+			{
+				Hex.Decode("1abc932417521ca24f2b0459fe7e6e0b"),
+				Hex.Decode("090339ec0aa6faefd5ccc2c6f4ce8e94"),
+				Hex.Decode("1e36b26bd1ebc670d1bd1d665620abf7"),
+				Hex.Decode("4f78a7f6d29809585a97daec58c6b050")
+			},
+			{
+				Hex.Decode("601ec313775789a5b7a7f504bbf3d228"),
+				Hex.Decode("f443e3ca4d62b59aca84e990cacaf5c5"),
+				Hex.Decode("2b0930daa23de94ce87017ba2d84988d"),
+				Hex.Decode("dfc9c58db67aada613c2dd08457941a6")
+			}
+		};
+
+		public override string Name
+		{
+			get { return "AESSIC"; }
+		}
+
+		public override void PerformTest()
+		{
+			IBufferedCipher c = CipherUtilities.GetCipher("AES/SIC/NoPadding");
+
+			//
+			// NIST vectors
+			//
+			for (int i = 0; i != keys.Length; i++)
+			{
+				KeyParameter skey = ParameterUtilities.CreateKeyParameter("AES", keys[i]);
+				c.Init(true, new ParametersWithIV(skey, Hex.Decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF")));
+
+				for (int j = 0; j != plain.Length; j++)
+				{
+					byte[] enc = c.ProcessBytes(plain[j]);
+					if (!AreEqual(enc, cipher[i, j]))
+					{
+						Fail("AESSIC encrypt failed: key " + i + " block " + j);
+					}
+				}
+
+				c.Init(false, new ParametersWithIV(skey, Hex.Decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF")));
+
+				for (int j = 0; j != plain.Length; j++)
+				{
+					byte[] enc = c.ProcessBytes(cipher[i, j]);
+					if (!AreEqual(enc, plain[j]))
+					{
+						Fail("AESSIC decrypt failed: key " + i + " block " + j);
+					}
+				}
+			}
+
+			//
+			// check CTR also recognised.
+			//
+			c = CipherUtilities.GetCipher("AES/CTR/NoPadding");
+
+			KeyParameter sk = ParameterUtilities.CreateKeyParameter("AES", Hex.Decode("2B7E151628AED2A6ABF7158809CF4F3C"));
+
+			c.Init(true, new ParametersWithIV(sk, Hex.Decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFD0001")));
+
+			byte[] crypt = c.DoFinal(Hex.Decode("00000000000000000000000000000000"));
+
+			if (!AreEqual(crypt, Hex.Decode("D23513162B02D0F72A43A2FE4A5F97AB")))
+			{
+				Fail("AESSIC failed test 2");
+			}
+
+			//
+			// check partial block processing
+			//
+			c = CipherUtilities.GetCipher("AES/CTR/NoPadding");
+
+			sk = ParameterUtilities.CreateKeyParameter("AES", Hex.Decode("2B7E151628AED2A6ABF7158809CF4F3C"));
+
+			c.Init(true, new ParametersWithIV(sk, Hex.Decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFD0001")));
+
+			crypt = c.DoFinal(Hex.Decode("12345678"));
+
+			c.Init(false, new ParametersWithIV(sk, Hex.Decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFD0001")));
+
+			crypt = c.DoFinal(crypt);
+
+			if (!AreEqual(crypt, Hex.Decode("12345678")))
+			{
+				Fail("AESSIC failed partial test");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new AesSicTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/AESTest.cs b/crypto/test/src/test/AESTest.cs
new file mode 100644
index 000000000..5a1ce8046
--- /dev/null
+++ b/crypto/test/src/test/AESTest.cs
@@ -0,0 +1,363 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <remarks>Basic test class for the AES cipher vectors from FIPS-197</remarks>
+	[TestFixture]
+	public class AesTest
+		: BaseBlockCipherTest
+	{
+		internal static readonly string[] cipherTests =
+		{
+			"128",
+			"000102030405060708090a0b0c0d0e0f",
+			"00112233445566778899aabbccddeeff",
+			"69c4e0d86a7b0430d8cdb78070b4c55a",
+			"192",
+			"000102030405060708090a0b0c0d0e0f1011121314151617",
+			"00112233445566778899aabbccddeeff",
+			"dda97ca4864cdfe06eaf70a0ec0d7191",
+			"256",
+			"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+			"00112233445566778899aabbccddeeff",
+			"8ea2b7ca516745bfeafc49904b496089",
+		};
+
+		public AesTest()
+			: base("AES")
+		{
+		}
+
+		[Test]
+		public void TestCiphers()
+		{
+			for (int i = 0; i != cipherTests.Length; i += 4)
+			{
+				doCipherTest(int.Parse(cipherTests[i]),
+					Hex.Decode(cipherTests[i + 1]),
+					Hex.Decode(cipherTests[i + 2]),
+					Hex.Decode(cipherTests[i + 3]));
+			}
+		}
+
+		[Test]
+		public void TestOids()
+		{
+			string[] oids = {
+				NistObjectIdentifiers.IdAes128Ecb.Id,
+				NistObjectIdentifiers.IdAes128Cbc.Id,
+				NistObjectIdentifiers.IdAes128Ofb.Id,
+				NistObjectIdentifiers.IdAes128Cfb.Id,
+				NistObjectIdentifiers.IdAes192Ecb.Id,
+				NistObjectIdentifiers.IdAes192Cbc.Id,
+				NistObjectIdentifiers.IdAes192Ofb.Id,
+				NistObjectIdentifiers.IdAes192Cfb.Id,
+				NistObjectIdentifiers.IdAes256Ecb.Id,
+				NistObjectIdentifiers.IdAes256Cbc.Id,
+				NistObjectIdentifiers.IdAes256Ofb.Id,
+				NistObjectIdentifiers.IdAes256Cfb.Id
+			};
+
+			string[] names = {
+				"AES/ECB/PKCS7Padding",
+				"AES/CBC/PKCS7Padding",
+				"AES/OFB/NoPadding",
+				"AES/CFB/NoPadding",
+				"AES/ECB/PKCS7Padding",
+				"AES/CBC/PKCS7Padding",
+				"AES/OFB/NoPadding",
+				"AES/CFB/NoPadding",
+				"AES/ECB/PKCS7Padding",
+				"AES/CBC/PKCS7Padding",
+				"AES/OFB/NoPadding",
+				"AES/CFB/NoPadding"
+			};
+
+			oidTest(oids, names, 4);
+		}
+
+		[Test]
+		public void TestWrap()
+		{
+			byte[] kek1 = Hex.Decode("000102030405060708090a0b0c0d0e0f");
+			byte[] in1 = Hex.Decode("00112233445566778899aabbccddeeff");
+			byte[] out1 = Hex.Decode("1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5");
+
+			wrapTest(1, "AESWrap", kek1, in1, out1);
+		}
+
+		[Test]
+		public void TestWrapOids()
+		{
+			string[] wrapOids =
+			{
+				NistObjectIdentifiers.IdAes128Wrap.Id,
+				NistObjectIdentifiers.IdAes192Wrap.Id,
+				NistObjectIdentifiers.IdAes256Wrap.Id
+			};
+
+			wrapOidTest(wrapOids, "AESWrap");
+		}
+
+		private void doCipherTest(
+			int		strength,
+			byte[]	keyBytes,
+			byte[]	input,
+			byte[]	output)
+		{
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("AES", keyBytes);
+
+			IBufferedCipher inCipher = CipherUtilities.GetCipher("AES/ECB/NoPadding");
+			IBufferedCipher outCipher = CipherUtilities.GetCipher("AES/ECB/NoPadding");
+
+			try
+			{
+				outCipher.Init(true, key);
+			}
+			catch (Exception e)
+			{
+				Fail("AES failed initialisation - " + e, e);
+			}
+
+			try
+			{
+				inCipher.Init(false, key);
+			}
+			catch (Exception e)
+			{
+				Fail("AES failed initialisation - " + e, e);
+			}
+
+			//
+			// encryption pass
+			//
+			MemoryStream bOut = new MemoryStream();
+
+			CipherStream cOut = new CipherStream(bOut, null, outCipher);
+
+			try
+			{
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+					cOut.WriteByte(input[i]);
+				}
+				cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+				cOut.Close();
+			}
+			catch (IOException e)
+			{
+				Fail("AES failed encryption - " + e, e);
+			}
+
+			byte[] bytes = bOut.ToArray();
+
+			if (!AreEqual(bytes, output))
+			{
+				Fail("AES failed encryption - expected "
+					+ Hex.ToHexString(output) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+
+			//
+			// decryption pass
+			//
+			MemoryStream bIn = new MemoryStream(bytes, false);
+
+			CipherStream cIn = new CipherStream(bIn, inCipher, null);
+
+			try
+			{
+//				DataInputStream dIn = new DataInputStream(cIn);
+				BinaryReader dIn = new BinaryReader(cIn);
+
+				bytes = new byte[input.Length];
+
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+//					bytes[i] = (byte)dIn.read();
+					bytes[i] = dIn.ReadByte();
+				}
+
+				int remaining = bytes.Length - input.Length / 2;
+//				dIn.readFully(bytes, input.Length / 2, remaining);
+				byte[] extra = dIn.ReadBytes(remaining);
+				if (extra.Length < remaining)
+					throw new EndOfStreamException();
+				extra.CopyTo(bytes, input.Length / 2);
+			}
+			catch (Exception e)
+			{
+				Fail("AES failed encryption - " + e, e);
+			}
+
+			if (!AreEqual(bytes, input))
+			{
+				Fail("AES failed decryption - expected "
+					+ Hex.ToHexString(input) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+		}
+
+		[Test]
+		public void TestEax()
+		{
+			byte[] K = Hex.Decode("233952DEE4D5ED5F9B9C6D6FF80FF478");
+			byte[] N = Hex.Decode("62EC67F9C3A4A407FCB2A8C49031A8B3");
+			byte[] P = Hex.Decode("68656c6c6f20776f726c642121");
+			byte[] C = Hex.Decode("2f9f76cb7659c70e4be11670a3e193ae1bc6b5762a");
+
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("AES", K);
+			IBufferedCipher inCipher = CipherUtilities.GetCipher("AES/EAX/NoPadding");
+			IBufferedCipher outCipher = CipherUtilities.GetCipher("AES/EAX/NoPadding");
+
+			inCipher.Init(true, new ParametersWithIV(key, N));
+
+			byte[] enc = inCipher.DoFinal(P);
+			if (!AreEqual(enc, C))
+			{
+				Fail("ciphertext doesn't match in EAX");
+			}
+
+			outCipher.Init(false, new ParametersWithIV(key, N));
+
+			byte[] dec = outCipher.DoFinal(C);
+			if (!AreEqual(dec, P))
+			{
+				Fail("plaintext doesn't match in EAX");
+			}
+
+			try
+			{
+				inCipher = CipherUtilities.GetCipher("AES/EAX/PKCS5Padding");
+
+				Fail("bad padding missed in EAX");
+			}
+			catch (SecurityUtilityException)
+			{
+				// expected
+			}
+		}
+
+		[Test]
+		public void TestCcm()
+		{
+			byte[] K = Hex.Decode("404142434445464748494a4b4c4d4e4f");
+			byte[] N = Hex.Decode("10111213141516");
+			byte[] P = Hex.Decode("68656c6c6f20776f726c642121");
+			byte[] C = Hex.Decode("39264f148b54c456035de0a531c8344f46db12b388");
+
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("AES", K);
+
+			IBufferedCipher inCipher = CipherUtilities.GetCipher("AES/CCM/NoPadding");
+			IBufferedCipher outCipher = CipherUtilities.GetCipher("AES/CCM/NoPadding");
+
+			inCipher.Init(true, new ParametersWithIV(key, N));
+
+			byte[] enc = inCipher.DoFinal(P);
+			if (!AreEqual(enc, C))
+			{
+				Fail("ciphertext doesn't match in CCM");
+			}
+
+			outCipher.Init(false, new ParametersWithIV(key, N));
+
+			byte[] dec = outCipher.DoFinal(C);
+			if (!AreEqual(dec, P))
+			{
+				Fail("plaintext doesn't match in CCM");
+			}
+
+			try
+			{
+				inCipher = CipherUtilities.GetCipher("AES/CCM/PKCS5Padding");
+
+				Fail("bad padding missed in CCM");
+			}
+			catch (SecurityUtilityException)
+			{
+				// expected
+			}
+		}
+
+		[Test]
+		public void TestGcm()
+		{
+			// Test Case 15 from McGrew/Viega
+			byte[] K = Hex.Decode(
+				  "feffe9928665731c6d6a8f9467308308"
+				+ "feffe9928665731c6d6a8f9467308308");
+			byte[] P = Hex.Decode(
+				  "d9313225f88406e5a55909c5aff5269a"
+				+ "86a7a9531534f7da2e4c303d8a318a72"
+				+ "1c3c0c95956809532fcf0e2449a6b525"
+				+ "b16aedf5aa0de657ba637b391aafd255");
+			byte[] N = Hex.Decode("cafebabefacedbaddecaf888");
+			string T = "b094dac5d93471bdec1a502270e3cc6c";
+			byte[] C = Hex.Decode(
+				  "522dc1f099567d07f47f37a32a84427d"
+				+ "643a8cdcbfe5c0c97598a2bd2555d1aa"
+				+ "8cb08e48590dbb3da7b08b1056828838"
+				+ "c5f61e6393ba7a0abcc9f662898015ad"
+				+ T);
+
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("AES", K);
+			IBufferedCipher inCipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
+			IBufferedCipher outCipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
+
+			inCipher.Init(true, new ParametersWithIV(key, N));
+
+			byte[] enc = inCipher.DoFinal(P);
+			if (!AreEqual(enc, C))
+			{
+				Fail("ciphertext doesn't match in GCM");
+			}
+
+			outCipher.Init(false, new ParametersWithIV(key, N));
+
+			byte[] dec = outCipher.DoFinal(C);
+			if (!AreEqual(dec, P))
+			{
+				Fail("plaintext doesn't match in GCM");
+			}
+
+			try
+			{
+				inCipher = CipherUtilities.GetCipher("AES/GCM/PKCS5Padding");
+
+				Fail("bad padding missed in GCM");
+			}
+			catch (SecurityUtilityException)
+			{
+				// expected
+			}
+		}
+
+		public override void PerformTest()
+		{
+			TestCiphers();
+			TestWrap();
+			TestOids();
+			TestWrapOids();
+			TestEax();
+			TestCcm();
+			TestGcm();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new AesTest());
+		}
+	}
+}
diff --git a/crypto/test/src/test/AttrCertSelectorTest.cs b/crypto/test/src/test/AttrCertSelectorTest.cs
new file mode 100644
index 000000000..37c1e66d2
--- /dev/null
+++ b/crypto/test/src/test/AttrCertSelectorTest.cs
@@ -0,0 +1,214 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class AttrCertSelectorTest
+		: SimpleTest
+	{
+		private static readonly RsaPrivateCrtKeyParameters RsaPrivateKeySpec = new RsaPrivateCrtKeyParameters(
+			new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+			new BigInteger("11", 16),
+			new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+			new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+			new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+			new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+			new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+			new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+		private static readonly byte[] holderCert = Base64.Decode(
+			  "MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+			+ "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+			+ "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+			+ "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+			+ "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+			+ "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+			+ "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+			+ "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+			+ "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+			+ "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+			+ "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+			+ "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+			+ "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+			+ "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+			+ "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+			+ "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+			+ "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+			+ "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+			+ "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+			+ "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+			+ "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+			+ "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+			+ "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+			+ "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+			+ "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+			+ "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+			+ "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+			+ "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+			+ "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+			+ "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+			+ "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+			+ "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+			+ "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+			+ "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+			+ "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+			+ "3g==");
+
+		public override string Name
+		{
+			get { return "AttrCertSelector"; }
+		}
+
+		private IX509AttributeCertificate CreateAttrCert()
+		{
+//			CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC");
+//			X509Certificate iCert = (X509Certificate) fact
+//				.generateCertificate(new ByteArrayInputStream(holderCert));
+			X509Certificate iCert = new X509CertificateParser().ReadCertificate(holderCert);
+
+			//
+			// a sample key pair.
+			//
+			// RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+			// new BigInteger(
+			// "b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7",
+			// 16), new BigInteger("11", 16));
+
+			//
+			// set up the keys
+			//
+//			KeyFactory kFact = KeyFactory.getInstance("RSA", "BC");
+//			PrivateKey privKey = kFact.generatePrivate(RsaPrivateKeySpec);
+			AsymmetricKeyParameter privKey = RsaPrivateKeySpec;
+
+			X509V2AttributeCertificateGenerator gen = new X509V2AttributeCertificateGenerator();
+
+			// the actual attributes
+			GeneralName roleName = new GeneralName(GeneralName.Rfc822Name, "DAU123456789@test.com");
+			Asn1EncodableVector roleSyntax = new Asn1EncodableVector(roleName);
+
+			// roleSyntax OID: 2.5.24.72
+			X509Attribute attributes = new X509Attribute("2.5.24.72",
+				new DerSequence(roleSyntax));
+
+			gen.AddAttribute(attributes);
+			gen.SetHolder(new AttributeCertificateHolder(PrincipalUtilities.GetSubjectX509Principal(iCert)));
+			gen.SetIssuer(new AttributeCertificateIssuer(new X509Name("cn=test")));
+			gen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			gen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+			gen.SetSerialNumber(BigInteger.One);
+			gen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+
+			Target targetName = new Target(
+				Target.Choice.Name,
+				new GeneralName(GeneralName.DnsName, "www.test.com"));
+
+			Target targetGroup = new Target(
+				Target.Choice.Group,
+				new GeneralName(GeneralName.DirectoryName, "o=Test, ou=Test"));
+
+			Target[] targets = new Target[]{ targetName, targetGroup };
+
+			TargetInformation targetInformation = new TargetInformation(targets);
+			gen.AddExtension(X509Extensions.TargetInformation.Id, true, targetInformation);
+
+			return gen.Generate(privKey);
+		}
+
+		[Test]
+		public void TestSelector()
+		{
+			IX509AttributeCertificate aCert = CreateAttrCert();
+			X509AttrCertStoreSelector sel = new X509AttrCertStoreSelector();
+			sel.AttributeCert = aCert;
+			bool match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate.");
+			}
+			sel.AttributeCert = null;
+			match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate.");
+			}
+			sel.Holder = aCert.Holder;
+			match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate holder.");
+			}
+			sel.Holder = null;
+			sel.Issuer = aCert.Issuer;
+			match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate issuer.");
+			}
+			sel.Issuer = null;
+
+//			CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC");
+//			X509Certificate iCert = (X509Certificate) fact.generateCertificate(
+//				new ByteArrayInputStream(holderCert));
+			X509Certificate iCert = new X509CertificateParser().ReadCertificate(holderCert);
+			match = aCert.Holder.Match(iCert);
+			if (!match)
+			{
+				Fail("Issuer holder does not match signing certificate of attribute certificate.");
+			}
+
+			sel.SerialNumber = aCert.SerialNumber;
+			match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate serial number.");
+			}
+
+			sel.AttributeCertificateValid = new DateTimeObject(DateTime.UtcNow);
+			match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate time.");
+			}
+
+			sel.AddTargetName(new GeneralName(2, "www.test.com"));
+			match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate target name.");
+			}
+			sel.SetTargetNames(null);
+			sel.AddTargetGroup(new GeneralName(4, "o=Test, ou=Test"));
+			match = sel.Match(aCert);
+			if (!match)
+			{
+				Fail("Selector does not match attribute certificate target group.");
+			}
+			sel.SetTargetGroups(null);
+		}
+
+		public override void PerformTest()
+		{
+			TestSelector();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new AttrCertSelectorTest());
+		}
+	}
+}
diff --git a/crypto/test/src/test/AttrCertTest.cs b/crypto/test/src/test/AttrCertTest.cs
new file mode 100644
index 000000000..d701d007e
--- /dev/null
+++ b/crypto/test/src/test/AttrCertTest.cs
@@ -0,0 +1,621 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class AttrCertTest
+		: SimpleTest
+	{
+		private static readonly RsaPrivateCrtKeyParameters RSA_PRIVATE_KEY_SPEC = new RsaPrivateCrtKeyParameters(
+			new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+			new BigInteger("11", 16),
+			new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+			new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+			new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+			new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+			new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+			new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+		internal static readonly byte[] attrCert = Base64.Decode(
+			"MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2"
+			+ "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS"
+			+ "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2"
+			+ "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0"
+			+ "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn"
+			+ "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw"
+			+ "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY"
+			+ "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs"
+			+ "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K"
+			+ "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0"
+			+ "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j"
+			+ "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw"
+			+ "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg"
+			+ "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl"
+			+ "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt"
+			+ "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0"
+			+ "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8"
+			+ "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl"
+			+ "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ"
+			+ "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct"
+			+ "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3"
+			+ "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1"
+			+ "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy"
+			+ "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6"
+			+ "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov"
+			+ "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz"
+			+ "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0"
+			+ "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46"
+			+ "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+"
+			+ "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y"
+			+ "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv"
+			+ "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0"
+			+ "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph"
+			+ "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj"
+			+ "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+"
+			+ "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA"
+			+ "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr"
+			+ "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3"
+			+ "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv");
+
+		internal static readonly byte[] signCert = Base64.Decode(
+			"MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ"
+			+ "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm"
+			+ "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w"
+			+ "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz"
+			+ "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE"
+			+ "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK"
+			+ "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc"
+			+ "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS"
+			+ "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG"
+			+ "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV"
+			+ "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD"
+			+ "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE"
+			+ "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt"
+			+ "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp"
+			+ "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0"
+			+ "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg"
+			+ "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl"
+			+ "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52"
+			+ "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS"
+			+ "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn"
+			+ "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9"
+			+ "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv"
+			+ "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB"
+			+ "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j"
+			+ "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt"
+			+ "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx"
+			+ "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE"
+			+ "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt"
+			+ "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52"
+			+ "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67"
+			+ "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB"
+			+ "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm"
+			+ "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N"
+			+ "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz"
+			+ "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR"
+			+ "3g==");
+
+		internal static readonly byte[] certWithBaseCertificateID = Base64.Decode(
+			"MIIBqzCCARQCAQEwSKBGMD6kPDA6MQswCQYDVQQGEwJJVDEOMAwGA1UEChMFVU5JVE4xDDAKBgNV"
+			+ "BAsTA0RJVDENMAsGA1UEAxMEcm9vdAIEAVMVjqB6MHikdjB0MQswCQYDVQQGEwJBVTEoMCYGA1UE"
+			+ "ChMfVGhlIExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFByaW1h"
+			+ "cnkgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUJvdW5jeSBDYXN0bGUwDQYJKoZIhvcNAQEFBQACBQKW"
+			+ "RhnHMCIYDzIwMDUxMjEyMTIwMDQyWhgPMjAwNTEyMTkxMjAxMzJaMA8wDQYDVRhIMQaBBGVWSVAw"
+			+ "DQYJKoZIhvcNAQEFBQADgYEAUAVin9StDaA+InxtXq/av6rUQLI9p1X6louBcj4kYJnxRvTrHpsr"
+			+ "N3+i9Uq/uk5lRdAqmPFvcmSbuE3TRAsjrXON5uFiBBKZ1AouLqcr8nHbwcdwjJ9TyUNO9I4hfpSH"
+			+ "UHHXMtBKgp4MOkhhX8xTGyWg3hp23d3GaUeg/IYlXBI=");
+
+		internal static readonly byte[] holderCertWithBaseCertificateID = Base64.Decode(
+			"MIIBwDCCASmgAwIBAgIEAVMVjjANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJJVDEOMAwGA1UE"
+			+ "ChMFVU5JVE4xDDAKBgNVBAsTA0RJVDENMAsGA1UEAxMEcm9vdDAeFw0wNTExMTExMjAxMzJaFw0w"
+			+ "NjA2MTYxMjAxMzJaMD4xCzAJBgNVBAYTAklUMQ4wDAYDVQQKEwVVTklUTjEMMAoGA1UECxMDRElU"
+			+ "MREwDwYDVQQDEwhMdWNhQm9yejBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr"
+			+ "5YtqKmKXmEGb4ShypL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERoxUw"
+			+ "EzARBglghkgBhvhCAQEEBAMCBDAwDQYJKoZIhvcNAQEFBQADgYEAsX50VPQQCWmHvPq9y9DeCpmS"
+			+ "4szcpFAhpZyn6gYRwY9CRZVtmZKH8713XhkGDWcIEMcG0u3oTz3tdKgPU5uyIPrDEWr6w8ClUj4x"
+			+ "5aVz5c2223+dVY7KES//JSB2bE/KCIchN3kAioQ4K8O3e0OL6oDVjsqKGw5bfahgKuSIk/Q=");
+
+
+		public override string Name
+		{
+			get { return "AttrCertTest"; }
+		}
+
+		private void doTestCertWithBaseCertificateID()
+		{
+			IX509AttributeCertificate attrCert = new X509V2AttributeCertificate(certWithBaseCertificateID);
+			X509CertificateParser fact = new X509CertificateParser();
+			X509Certificate cert = fact.ReadCertificate(holderCertWithBaseCertificateID);
+
+			AttributeCertificateHolder holder = attrCert.Holder;
+
+			if (holder.GetEntityNames() != null)
+			{
+				Fail("entity names set when none expected");
+			}
+
+			if (!holder.SerialNumber.Equals(cert.SerialNumber))
+			{
+				Fail("holder serial number doesn't Match");
+			}
+
+			if (!holder.GetIssuer()[0].Equivalent(cert.IssuerDN))
+			{
+				Fail("holder issuer doesn't Match");
+			}
+
+			if (!holder.Match(cert))
+			{
+				Fail("holder not matching holder certificate");
+			}
+
+			if (!holder.Equals(holder.Clone()))
+			{
+				Fail("holder clone test failed");
+			}
+
+			if (!attrCert.Issuer.Equals(attrCert.Issuer.Clone()))
+			{
+				Fail("issuer clone test failed");
+			}
+
+			equalityAndHashCodeTest(attrCert, certWithBaseCertificateID);
+		}
+
+		private void equalityAndHashCodeTest(
+			IX509AttributeCertificate	attrCert,
+			byte[]						encoding)
+		{
+			if (!attrCert.Equals(attrCert))
+			{
+				Fail("same certificate not equal");
+			}
+
+			if (!attrCert.Holder.Equals(attrCert.Holder))
+			{
+				Fail("same holder not equal");
+			}
+
+			if (!attrCert.Issuer.Equals(attrCert.Issuer))
+			{
+				Fail("same issuer not equal");
+			}
+
+			if (attrCert.Holder.Equals(attrCert.Issuer))
+			{
+				Fail("wrong holder equal");
+			}
+
+			if (attrCert.Issuer.Equals(attrCert.Holder))
+			{
+				Fail("wrong issuer equal");
+			}
+
+			IX509AttributeCertificate attrCert2 = new X509V2AttributeCertificate(encoding);
+
+			if (attrCert2.Holder.GetHashCode() != attrCert.Holder.GetHashCode())
+			{
+				Fail("holder hashCode test failed");
+			}
+
+			if (!attrCert2.Holder.Equals(attrCert.Holder))
+			{
+				Fail("holder Equals test failed");
+			}
+
+			if (attrCert2.Issuer.GetHashCode() != attrCert.Issuer.GetHashCode())
+			{
+				Fail("issuer hashCode test failed");
+			}
+
+			if (!attrCert2.Issuer.Equals(attrCert.Issuer))
+			{
+				Fail("issuer Equals test failed");
+			}
+		}
+
+		private void doTestGenerateWithCert()
+		{
+			X509CertificateParser fact = new X509CertificateParser();
+			X509Certificate iCert = fact.ReadCertificate(signCert);
+
+			//
+			// a sample key pair.
+			//
+			RsaKeyParameters pubKey = new RsaKeyParameters(
+				false,
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16));
+
+			//
+			// set up the keys
+			//
+//			PrivateKey privKey;
+//			PublicKey pubKey;
+//
+//			KeyFactory  kFact = KeyFactory.getInstance("RSA");
+//
+//			privKey = kFact.generatePrivate(RSA_PRIVATE_KEY_SPEC);
+//			pubKey = kFact.generatePublic(pubKeySpec);
+			AsymmetricKeyParameter privKey = RSA_PRIVATE_KEY_SPEC;
+
+			X509V2AttributeCertificateGenerator gen = new X509V2AttributeCertificateGenerator();
+
+			// the actual attributes
+			GeneralName roleName = new GeneralName(GeneralName.Rfc822Name, "DAU123456789");
+
+			// roleSyntax OID: 2.5.24.72
+			X509Attribute attributes = new X509Attribute("2.5.24.72",
+				new DerSequence(roleName));
+
+			gen.AddAttribute(attributes);
+			gen.SetHolder(new AttributeCertificateHolder(iCert));
+			gen.SetIssuer(new AttributeCertificateIssuer(new X509Name("cn=test")));
+			gen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			gen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+			gen.SetSerialNumber(BigInteger.One);
+			gen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+
+			IX509AttributeCertificate aCert = gen.Generate(privKey);
+
+			aCert.CheckValidity();
+
+			aCert.Verify(pubKey);
+
+			AttributeCertificateHolder holder = aCert.Holder;
+
+			if (holder.GetEntityNames() != null)
+			{
+				Fail("entity names set when none expected");
+			}
+
+			if (!holder.SerialNumber.Equals(iCert.SerialNumber))
+			{
+				Fail("holder serial number doesn't Match");
+			}
+
+			if (!holder.GetIssuer()[0].Equivalent(iCert.IssuerDN))
+			{
+				Fail("holder issuer doesn't Match");
+			}
+
+			if (!holder.Match(iCert))
+			{
+				Fail("generated holder not matching holder certificate");
+			}
+
+			X509Attribute[] attrs = aCert.GetAttributes("2.5.24.72");
+
+			if (attrs == null)
+			{
+				Fail("attributes related to 2.5.24.72 not found");
+			}
+
+			X509Attribute attr = attrs[0];
+
+			if (!attr.Oid.Equals("2.5.24.72"))
+			{
+				Fail("attribute oid mismatch");
+			}
+
+			Asn1Encodable[] values = attr.GetValues();
+
+			GeneralName role = GeneralNames.GetInstance(values[0]).GetNames()[0];
+
+			if (role.TagNo != GeneralName.Rfc822Name)
+			{
+				Fail("wrong general name type found in role");
+			}
+
+			if (!((IAsn1String)role.Name).GetString().Equals("DAU123456789"))
+			{
+				Fail("wrong general name value found in role");
+			}
+
+			X509Certificate sCert = fact.ReadCertificate(holderCertWithBaseCertificateID);
+
+			if (holder.Match(sCert))
+			{
+				Fail("generated holder matching wrong certificate");
+			}
+
+			equalityAndHashCodeTest(aCert, aCert.GetEncoded());
+		}
+
+		private void doTestGenerateWithPrincipal()
+		{
+			X509CertificateParser fact = new X509CertificateParser();
+			X509Certificate iCert = fact.ReadCertificate(signCert);
+
+			//
+			// a sample key pair.
+			//
+			RsaKeyParameters pubKey = new RsaKeyParameters(
+				false,
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16));
+
+			//
+			// set up the keys
+			//
+//			PrivateKey          privKey;
+//			PublicKey           pubKey;
+//
+//			KeyFactory  kFact = KeyFactory.getInstance("RSA");
+//
+//			privKey = kFact.generatePrivate(RSA_PRIVATE_KEY_SPEC);
+//			pubKey = kFact.generatePublic(pubKeySpec);
+			AsymmetricKeyParameter privKey = RSA_PRIVATE_KEY_SPEC;
+
+			X509V2AttributeCertificateGenerator gen = new X509V2AttributeCertificateGenerator();
+
+			// the actual attributes
+			GeneralName roleName = new GeneralName(GeneralName.Rfc822Name, "DAU123456789");
+
+			// roleSyntax OID: 2.5.24.72
+			X509Attribute attributes = new X509Attribute("2.5.24.72",
+				new DerSequence(roleName));
+
+			gen.AddAttribute(attributes);
+			gen.SetHolder(new AttributeCertificateHolder(iCert.SubjectDN));
+			gen.SetIssuer(new AttributeCertificateIssuer(new X509Name("cn=test")));
+			gen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			gen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+			gen.SetSerialNumber(BigInteger.One);
+			gen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+
+			IX509AttributeCertificate aCert = gen.Generate(privKey);
+
+			aCert.CheckValidity();
+
+			aCert.Verify(pubKey);
+
+			AttributeCertificateHolder holder = aCert.Holder;
+
+			if (holder.GetEntityNames() == null)
+			{
+				Fail("entity names not set when expected");
+			}
+
+			if (holder.SerialNumber != null)
+			{
+				Fail("holder serial number found when none expected");
+			}
+
+			if (holder.GetIssuer() != null)
+			{
+				Fail("holder issuer found when none expected");
+			}
+
+			if (!holder.Match(iCert))
+			{
+				Fail("generated holder not matching holder certificate");
+			}
+
+			X509Certificate sCert = fact.ReadCertificate(holderCertWithBaseCertificateID);
+
+			if (holder.Match(sCert))
+			{
+				Fail("principal generated holder matching wrong certificate");
+			}
+
+			equalityAndHashCodeTest(aCert, aCert.GetEncoded());
+		}
+
+		public override void PerformTest()
+		{
+			IX509AttributeCertificate aCert = new X509V2AttributeCertificate(attrCert);
+			X509CertificateParser fact = new X509CertificateParser();
+			X509Certificate sCert = fact.ReadCertificate(signCert);
+
+			aCert.Verify(sCert.GetPublicKey());
+
+			//
+			// search test
+			//
+			IList list = new ArrayList();
+
+			list.Add(sCert);
+
+//			CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list);
+//			CertStore store = CertStore.getInstance("Collection", ccsp);
+			IX509Store store = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(list));
+
+			ArrayList certs = new ArrayList(
+//				store.getCertificates(aCert.getIssuer()));
+				store.GetMatches(aCert.Issuer));
+
+			if (certs.Count != 1 || !certs.Contains(sCert))
+			{
+				Fail("sCert not found by issuer");
+			}
+
+			X509Attribute[] attrs = aCert.GetAttributes("1.3.6.1.4.1.6760.8.1.1");
+			if (attrs == null || attrs.Length != 1)
+			{
+				Fail("attribute not found");
+			}
+
+			//
+			// reencode test
+			//
+			aCert = new X509V2AttributeCertificate(aCert.GetEncoded());
+
+			aCert.Verify(sCert.GetPublicKey());
+
+			IX509AttributeCertificate saCert = new X509V2AttributeCertificate(aCert.GetEncoded());
+
+			if (!aCert.NotAfter.Equals(saCert.NotAfter))
+			{
+				Fail("failed date comparison");
+			}
+
+			// base generator test
+
+			//
+			// a sample key pair.
+			//
+			RsaKeyParameters pubKey = new RsaKeyParameters(
+				false,
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16));
+
+			AsymmetricKeyParameter privKey = RSA_PRIVATE_KEY_SPEC;
+
+			//
+			// set up the keys
+			//
+//			PrivateKey          privKey;
+//			PublicKey           pubKey;
+//
+//			KeyFactory  kFact = KeyFactory.getInstance("RSA");
+//
+//			privKey = kFact.generatePrivate(privKeySpec);
+//			pubKey = kFact.generatePublic(pubKeySpec);
+
+			X509V2AttributeCertificateGenerator gen = new X509V2AttributeCertificateGenerator();
+
+			gen.AddAttribute(attrs[0]);
+			gen.SetHolder(aCert.Holder);
+			gen.SetIssuer(aCert.Issuer);
+			gen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			gen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+			gen.SetSerialNumber(aCert.SerialNumber);
+			gen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+
+			aCert = gen.Generate(privKey);
+
+			aCert.CheckValidity();
+
+			aCert.Verify(pubKey);
+
+			// as the issuer is the same this should still work (even though it is not
+			// technically correct
+
+			certs = new ArrayList(
+//				store.getCertificates(aCert.Issuer));
+				store.GetMatches(aCert.Issuer));
+
+			if (certs.Count != 1 || !certs.Contains(sCert))
+			{
+				Fail("sCert not found by issuer");
+			}
+
+			attrs = aCert.GetAttributes("1.3.6.1.4.1.6760.8.1.1");
+			if (attrs == null || attrs.Length != 1)
+			{
+				Fail("attribute not found");
+			}
+
+			//
+			// reencode test
+			//
+			aCert = new X509V2AttributeCertificate(aCert.GetEncoded());
+
+			aCert.Verify(pubKey);
+
+			AttributeCertificateIssuer issuer = aCert.Issuer;
+
+			X509Name[] principals = issuer.GetPrincipals();
+
+			//
+			// test holder
+			//
+			AttributeCertificateHolder holder = aCert.Holder;
+
+			if (holder.GetEntityNames() == null)
+			{
+				Fail("entity names not set");
+			}
+
+			if (holder.SerialNumber != null)
+			{
+				Fail("holder serial number set when none expected");
+			}
+
+			if (holder.GetIssuer() != null)
+			{
+				Fail("holder issuer set when none expected");
+			}
+
+			principals = holder.GetEntityNames();
+
+			string ps = principals[0].ToString();
+
+			// TODO Check that this is a good enough test
+//			if (!ps.Equals("C=US, O=vt, OU=Class 2, OU=Virginia Tech User, CN=Markus Lorch (mlorch), EMAILADDRESS=mlorch@vt.edu"))
+			if (!principals[0].Equivalent(new X509Name("C=US, O=vt, OU=Class 2, OU=Virginia Tech User, CN=Markus Lorch (mlorch), EMAILADDRESS=mlorch@vt.edu")))
+			{
+				Fail("principal[0] for entity names don't Match");
+			}
+
+			//
+			// extension test
+			//
+
+			gen.AddExtension("1.1", true, new DerOctetString(new byte[10]));
+
+			gen.AddExtension("2.2", false, new DerOctetString(new byte[20]));
+
+			aCert = gen.Generate(privKey);
+
+			ISet exts = aCert.GetCriticalExtensionOids();
+
+			if (exts.Count != 1 || !exts.Contains("1.1"))
+			{
+				Fail("critical extension test failed");
+			}
+
+			exts = aCert.GetNonCriticalExtensionOids();
+
+			if (exts.Count != 1 || !exts.Contains("2.2"))
+			{
+				Fail("non-critical extension test failed");
+			}
+
+			Asn1OctetString extString = aCert.GetExtensionValue(new DerObjectIdentifier("1.1"));
+			Asn1Encodable extValue = X509ExtensionUtilities.FromExtensionValue(extString);
+
+			if (!extValue.Equals(new DerOctetString(new byte[10])))
+			{
+				Fail("wrong extension value found for 1.1");
+			}
+
+			doTestCertWithBaseCertificateID();
+			doTestGenerateWithCert();
+			doTestGenerateWithPrincipal();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new AttrCertTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/BaseBlockCipherTest.cs b/crypto/test/src/test/BaseBlockCipherTest.cs
new file mode 100644
index 000000000..87fb01056
--- /dev/null
+++ b/crypto/test/src/test/BaseBlockCipherTest.cs
@@ -0,0 +1,146 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	public abstract class BaseBlockCipherTest
+		: SimpleTest
+	{
+		string algorithm;
+
+		internal BaseBlockCipherTest(
+			string algorithm)
+		{
+			this.algorithm = algorithm;
+		}
+
+		public override string Name
+		{
+			get { return algorithm; }
+		}
+
+		protected void oidTest(
+			string[]	oids,
+			string[]	names,
+			int			groupSize)
+		{
+			byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
+			for (int i = 0; i != oids.Length; i++)
+			{
+				IBufferedCipher c1 = CipherUtilities.GetCipher(oids[i]);
+				IBufferedCipher c2 = CipherUtilities.GetCipher(names[i]);
+				CipherKeyGenerator kg = GeneratorUtilities.GetKeyGenerator(oids[i]);
+
+				KeyParameter k = ParameterUtilities.CreateKeyParameter(oids[i], kg.GenerateKey());
+
+				ICipherParameters cp = k;
+				if (names[i].IndexOf("/ECB/") < 0)
+				{
+					cp = new ParametersWithIV(cp, new byte[16]);
+				}
+
+				c1.Init(true, cp);
+				c2.Init(false, cp);
+
+				byte[] result = c2.DoFinal(c1.DoFinal(data));
+
+				if (!AreEqual(data, result))
+				{
+					Fail("failed OID test");
+				}
+
+				if (k.GetKey().Length != (16 + ((i / groupSize) * 8)))
+				{
+					Fail("failed key length test");
+				}
+			}
+		}
+
+		protected void wrapOidTest(
+			string[]	oids,
+			string		name)
+		{
+			byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+
+			for (int i = 0; i != oids.Length; i++)
+			{
+				IWrapper c1 = WrapperUtilities.GetWrapper(oids[i]);
+				IWrapper c2 = WrapperUtilities.GetWrapper(name);
+				CipherKeyGenerator kg = GeneratorUtilities.GetKeyGenerator(oids[i]);
+
+				KeyParameter k = ParameterUtilities.CreateKeyParameter(oids[i], kg.GenerateKey());
+
+				c1.Init(true, k);
+				c2.Init(false, k);
+
+				byte[] wrapped = c1.Wrap(data, 0, data.Length);
+				byte[] wKeyBytes = c2.Unwrap(wrapped, 0, wrapped.Length);
+
+				if (!AreEqual(data, wKeyBytes))
+				{
+					Fail("failed wrap OID test");
+				}
+
+				if (k.GetKey().Length != (16 + (i * 8)))
+				{
+					Fail("failed key length test");
+				}
+			}
+		}
+
+		protected void wrapTest(
+			int		id,
+			string	wrappingAlgorithm,
+			byte[]	kek,
+			byte[]	inBytes,
+			byte[]	outBytes)
+		{
+			IWrapper wrapper = WrapperUtilities.GetWrapper(wrappingAlgorithm);
+
+			wrapper.Init(true, ParameterUtilities.CreateKeyParameter(algorithm, kek));
+
+			try
+			{
+				byte[] cText = wrapper.Wrap(inBytes, 0, inBytes.Length);
+				if (!AreEqual(cText, outBytes))
+				{
+					Fail("failed wrap test " + id  + " expected "
+						+ Hex.ToHexString(outBytes) + " got "
+						+ Hex.ToHexString(cText));
+				}
+			}
+			catch (TestFailedException e)
+			{
+				throw e;
+			}
+			catch (Exception e)
+			{
+				Fail("failed wrap test exception " + e.ToString(), e);
+			}
+
+			wrapper.Init(false, ParameterUtilities.CreateKeyParameter(algorithm, kek));
+
+			try
+			{
+				byte[] pTextBytes = wrapper.Unwrap(outBytes, 0, outBytes.Length);
+
+				if (!AreEqual(pTextBytes, inBytes))
+				{
+					Fail("failed unwrap test " + id  + " expected "
+						+ Hex.ToHexString(inBytes) + " got "
+						+ Hex.ToHexString(pTextBytes));
+				}
+			}
+			catch (Exception e)
+			{
+				Fail("failed unwrap test exception " + e.ToString(), e);
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/test/BlockCipherTest.cs b/crypto/test/src/test/BlockCipherTest.cs
new file mode 100644
index 000000000..2e8e8b0b8
--- /dev/null
+++ b/crypto/test/src/test/BlockCipherTest.cs
@@ -0,0 +1,972 @@
+using System;
+using System.Globalization;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    /**
+    * basic test class for a block cipher, basically this just exercises the provider, and makes sure we
+    * are behaving sensibly, correctness of the implementation is shown in the lightweight test classes.
+    */
+    [TestFixture]
+    public class BlockCipherTest
+        : SimpleTest
+    {
+        private static readonly ISet validModes = CollectionUtilities.ReadOnly(
+            new HashSet(new string[]{ "CBC", "CCM", "CFB", "CTR", "CTS", "EAX", "ECB", "GCM", "OCB", "OFB" }));
+
+        private static readonly string[] cipherTests1 =
+        {
+            "DES",
+            "466da00648ef0e1f9617b1f002e225251a3248d09172f46b9617b1f002e225250112ecb3da61bc99",
+            "DESede",
+            "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394",
+            "SKIPJACK",
+            "d4de46d52274dbb029f33b076043f8c40089f906751623de29f33b076043f8c4ac99b90f9396cb04",
+            "Blowfish",
+            "7870ebe7f6a52803eb9396ba6c5198216ce81d76d8d4c74beb9396ba6c5198211212473b05214e9f",
+            "Twofish",
+            "70336d9c9718a8a2ced1b19deed973a3c58af7ea71a69e7efc4df082dca581c0839e31468661bcfc57a14899ceeb0253",
+            "RC2",
+            "eb5b889bbcced12eb6b1a3da6a3d965bba66a5edfdd4c8a6b6b1a3da6a3d965b994a5b859e765797",
+            "RC5",
+            "220053543e3eca3bc9503a091ca67b08372560d8a4fdbee8c9503a091ca67b08a796d53bb8a4b7e0",
+            "RC5-64",
+            "e0b4a526ba3bc5f09199c3b1fe3737fe6d248cde70e565b0feea59ebfda375ae1946c386a48d8d8a74d7b1947ff6a788",
+            "RC6",
+            "44c97b67ca8486067f8b6c5b97632f3049e5e52c1d61fdd527dc3da39616540f19a3db39aac1ffd713795cd886cce0c0",
+            "IDEA",
+            "8c9fd56823ffdc523f6ccf7f614aa6173553e594fc7a21b53f6ccf7f614aa61740c54f7a66e95108",
+            "TEA",
+            "fcf45062104fda7c35712368b56dd4216a6ca998dc297b5435712368b56dd421208027ed2923cd0c",
+            "XTEA",
+            "4b427893d3d6aaded2afafabe25f7b233fb5589faa2b6389d2afafabe25f7b239d12979ac67e1c07",
+            "Camellia",
+            "3a68b4ad145bc2c76010669d68f2826359887afce763a78d9994143266adfaec8ba7ee562a1688ef9dfd7f897e5c44dc",
+            "SEED",
+            "d53d4ce1f48b9879420949467bfcbfbe2c6a7d4a8770bee0c71211def898d7c5024ce2007dd85accb3f69d906ae2164d",
+            "Noekeon",
+            "7e68ceb33aad9db04af6b878a16dd6c6b4f880d6c89027ba581884c10690bb6b3dbfd6ed5513e2c4f5670c3528023121",
+            "DES/CBC/NoPadding",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a",
+            "DESede/CBC/NoPadding",
+            "4d3d7931875cf25593dc402298add8b914761e4936c9585ae22b2c1441169231",
+            "SKIPJACK/CBC/NoPadding",
+            "ceebcc2e5e2b847f9ed797b4930b95f115b9e6cf49c457fc2ea0df79ad5c8334",
+            "Blowfish/CBC/NoPadding",
+            "80823abbabc109733e7ebf3ce3344d67fc387c306b782086b452f7fbe8e844ce",
+            "Twofish/CBC/NoPadding",
+            "f819694251a00bdd403928745cd1d8a094de61f49ddf8e7692e9d81a83812943",
+            "RC2/CBC/NoPadding",
+            "a51facdb3933c9676795cd38cc3146fd4694722b468b1a979a399c77606abf99",
+            "RC5/CBC/NoPadding",
+            "9ee7517eab0280445f3a7c60c90c0f75029d65bca8b1af83ace5399d388c83c3",
+            "RC6/CBC/NoPadding",
+            "c44695633c07010f3a0d8f7ea046a642d4a96bf4e44f89fd91b46830bc95b130",
+            "IDEA/CBC/NoPadding",
+            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d9",
+            "DES/CBC/PKCS5Padding",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122afdc70484fb9c0232",
+            "DES/CBC/ISO10126Padding",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a980639850a2cc3e8",
+            "DES/CBC/ISO7816-4Padding",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a1f80b9b0f1be49ac",
+            "DES/CBC/X9.23Padding",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a980639850a2cc3e8",
+            "DESede/CBC/PKCS7Padding",
+            "4d3d7931875cf25593dc402298add8b914761e4936c9585ae22b2c1441169231a41e40695f1cff84",
+            "SKIPJACK/CBC/PKCS7Padding",
+            "ceebcc2e5e2b847f9ed797b4930b95f115b9e6cf49c457fc2ea0df79ad5c8334df7042de5db89c96",
+            "Blowfish/CBC/PKCS7Padding",
+            "80823abbabc109733e7ebf3ce3344d67fc387c306b782086b452f7fbe8e844cef986562ab1a675e8",
+            "Twofish/CBC/PKCS7Padding",
+            "f819694251a00bdd403928745cd1d8a094de61f49ddf8e7692e9d81a838129433e5f1343d6cdb0b41838619da1541f04",
+            "RC2/CBC/PKCS7Padding",
+            "a51facdb3933c9676795cd38cc3146fd4694722b468b1a979a399c77606abf9958435525f770f137",
+            "RC5/CBC/PKCS7Padding",
+            "9ee7517eab0280445f3a7c60c90c0f75029d65bca8b1af83ace5399d388c83c3edd95ff49be76651",
+            "RC5-64/CBC/PKCS7Padding",
+            "e479fd11f89dab22d2f3dd062b1d2abd5b5962553421a5c562dc7214c3b23b8e21949fda87f2f820e5f032c552c6ec78",
+            "RC6/CBC/PKCS7Padding",
+            "c44695633c07010f3a0d8f7ea046a642d4a96bf4e44f89fd91b46830bc95b130824b972c9019a69d2dd05ef2d36b37ac",
+            "IDEA/CBC/PKCS7Padding",
+            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d9e584751325ef7c32",
+            "IDEA/CBC/ISO10126Padding",
+            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d978b3fd73135f033b",
+            "IDEA/CBC/X9.23Padding",
+            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d978b3fd73135f033b",
+            "AES/CBC/PKCS7Padding",
+            "cf87f4d8bb9d1abb36cdd9f44ead7d046db2f802d99e1ef0a5940f306079e08389a44c4a8cc1a47cbaee1128da55bbb7",
+            "AES/CBC/ISO7816-4Padding",
+            "cf87f4d8bb9d1abb36cdd9f44ead7d046db2f802d99e1ef0a5940f306079e08306d84876508a33efec701118d8eeaf6d",
+            "Rijndael/CBC/PKCS7Padding",
+            "cf87f4d8bb9d1abb36cdd9f44ead7d046db2f802d99e1ef0a5940f306079e08389a44c4a8cc1a47cbaee1128da55bbb7",
+            "Serpent/CBC/PKCS7Padding",
+            "f8940ca31aba8ce1e0693b1ae0b1e08daef6de03c80f019774280052f824ac44540bb8dd74dfad47f83f9c7ec268ca68",
+            "CAST5/CBC/PKCS7Padding",
+            "87b6dc0c5a1d23d42fa740b0548be0b298112000544610d889d6361994cf8e670a19d6af72d7289f",
+            "CAST6/CBC/PKCS7Padding",
+            "943445569cfdda174118e433828f84e137faee38cac5c827d87a3c9a5a46a07dd64e7ad8accd921f248eea627cd6826f",
+            "IDEA/CBC/PKCS7Padding",
+            "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d9e584751325ef7c32",
+            "DES/CBC/ZeroBytePadding",
+            "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122ad3b3f002c927f1fd",
+            "DES/CTS/NoPadding", // official style
+            "60fa2f8fae5aa2a38e9ac77d0246726bcf99f75cc6e0122aeb7511e4515feb12",
+            "DESede/CTS/NoPadding",
+            "4d3d7931875cf25593dc402298add8b9e22b2c144116923114761e4936c9585a",
+            "SKIPJACK/CTS/NoPadding",
+            "ceebcc2e5e2b847f9ed797b4930b95f12ea0df79ad5c833415b9e6cf49c457fc",
+            "Blowfish/CTS/NoPadding",
+            "80823abbabc109733e7ebf3ce3344d67b452f7fbe8e844cefc387c306b782086",
+            "Twofish/CTS/NoPadding",
+            "94de61f49ddf8e7692e9d81a83812943f819694251a00bdd403928745cd1d8a0",
+            "AES/CTS/NoPadding",
+            "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04",
+            "Rijndael/CTS/NoPadding",
+            "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04",
+            "Serpent/CTS/NoPadding",
+            "aef6de03c80f019774280052f824ac44f8940ca31aba8ce1e0693b1ae0b1e08d",
+            "CAST5/CTS/NoPadding",
+            "87b6dc0c5a1d23d42fa740b0548be0b289d6361994cf8e6798112000544610d8",
+            "CAST6/CTS/NoPadding",
+            "37faee38cac5c827d87a3c9a5a46a07d943445569cfdda174118e433828f84e1",
+            "RC2/CTS/NoPadding",
+            "a51facdb3933c9676795cd38cc3146fd9a399c77606abf994694722b468b1a97",
+            "RC5/CTS/NoPadding",
+            "9ee7517eab0280445f3a7c60c90c0f75ace5399d388c83c3029d65bca8b1af83",
+            "RC6/CTS/NoPadding",
+            "d4a96bf4e44f89fd91b46830bc95b130c44695633c07010f3a0d8f7ea046a642",
+            "IDEA/CTS/NoPadding",
+            "30cd990ebdae80fe12b6c6e4fcd1c06497351c8684e4c4d9a27d985c276b3d70",
+            "DES/CBC/WithCTS",                  // older style
+            "60fa2f8fae5aa2a38e9ac77d0246726bcf99f75cc6e0122aeb7511e4515feb12",
+            "DESede/CBC/WithCTS",
+            "4d3d7931875cf25593dc402298add8b9e22b2c144116923114761e4936c9585a",
+            "SKIPJACK/CBC/WithCTS",
+            "ceebcc2e5e2b847f9ed797b4930b95f12ea0df79ad5c833415b9e6cf49c457fc",
+            "Blowfish/CBC/WithCTS",
+            "80823abbabc109733e7ebf3ce3344d67b452f7fbe8e844cefc387c306b782086",
+            "Twofish/CBC/WithCTS",
+            "94de61f49ddf8e7692e9d81a83812943f819694251a00bdd403928745cd1d8a0",
+            "AES/CBC/WithCTS",
+            "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04",
+            "Rijndael/CBC/WithCTS",
+            "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04",
+            "Serpent/CBC/WithCTS",
+            "aef6de03c80f019774280052f824ac44f8940ca31aba8ce1e0693b1ae0b1e08d",
+            "CAST5/CBC/WithCTS",
+            "87b6dc0c5a1d23d42fa740b0548be0b289d6361994cf8e6798112000544610d8",
+            "CAST6/CBC/WithCTS",
+            "37faee38cac5c827d87a3c9a5a46a07d943445569cfdda174118e433828f84e1",
+            "RC2/CBC/WithCTS",
+            "a51facdb3933c9676795cd38cc3146fd9a399c77606abf994694722b468b1a97",
+            "RC5/CBC/WithCTS",
+            "9ee7517eab0280445f3a7c60c90c0f75ace5399d388c83c3029d65bca8b1af83",
+            "RC6/CBC/WithCTS",
+            "d4a96bf4e44f89fd91b46830bc95b130c44695633c07010f3a0d8f7ea046a642",
+            "IDEA/CBC/WithCTS",
+            "30cd990ebdae80fe12b6c6e4fcd1c06497351c8684e4c4d9a27d985c276b3d70",
+            "DES/OFB/NoPadding",
+            "537572e480c1714f5c9a4f3b874df824dc6681b1fd6c11982debcad91e3f78b7",
+            "DESede/OFB/NoPadding",
+            "481e9872acea7fcf8e29a453242da774e5f6a28f15f7723659a73e4ff4939f80",
+            "SKIPJACK/OFB/NoPadding",
+            "71143a124e3a0cde753b60fe9b200e559018b6a0fe0682659f7c13feb9df995c",
+            "Blowfish/OFB/NoPadding",
+            "6cd6f7c5d2c655556d7a9e98a1696d1875e9f1b2fc991e28a2d55b56861e80bd",
+            "Twofish/OFB/NoPadding",
+            "821c54b1b54ae113cf74595eefe10c83b61c9682fc81f92c52f39a3a693f88b8",
+            "RC2/OFB/NoPadding",
+            "0a07cb78537cb04c0c74e28a7b86b80f80acadf87d6ef32792f1a8cf74b39f74",
+            "RC5/OFB/NoPadding",
+            "c62b233df296283b918a2b4cc53a54fbf061850e781b97332ed1bd78b88d9670",
+            "IDEA/OFB/NoPadding",
+            "dd447da3cbdcf81f4053fb446596261cb00a3c49a66085485af5f7c10ba20dad",
+            "DES/OFB8/NoPadding",
+            "53cb5010d189f94cf584e5ff1c4a9d86443c45ddb6fa3c2d1a5dadfcdf01db8a",
+            "DESede/OFB8/NoPadding",
+            "482c0c1ccd0e6d218e1cffb0a295352c2357ffaa673f2257ef5c77b6c04f03b5",
+            "SKIPJACK/OFB8/NoPadding",
+            "719ea1b432b3d2c8011e5aa873f95978420022b5e2c9c1a1c1082cd1f4999da2",
+            "Blowfish/OFB8/NoPadding",
+            "6ca6078755b263f09787d830b6fda7b7748494634bdc73ab68540cf9f6b7eccf",
+            "Twofish/OFB8/NoPadding",
+            "825dcec234ad52253d6e064b0d769bc04b1142435933f4a510ffc20d70095a88",
+            "RC2/OFB8/NoPadding",
+            "0aa26c6f6a820fe7d38da97085995ad62e2e293323a76300fcd4eb572810f7c6",
+            "RC5/OFB8/NoPadding",
+            "c601a9074dbd874f4d3293f6a32d93d9f0a4f5685d8597f0102fcc96d444f976",
+            "IDEA/OFB8/NoPadding",
+            "dd7897b6ced43d060a518bb38d570308b83b4de577eb208130daabf619e9b1fb",
+            "DES/CFB/NoPadding",
+            "537572e480c1714fec3c7424f88d4202219244c5ca8f5e4361d64f08fe747bb2",
+            "DESede/CFB/NoPadding",
+            "481e9872acea7fcfb75bb58670fe64c59123265139e357d161cd4ddb5eba042a",
+            "SKIPJACK/CFB/NoPadding",
+            "71143a124e3a0cde70a69ede4ceb14376b1e6a80bafde0a6330508dfa86a7c41",
+            "Blowfish/CFB/NoPadding",
+            "6cd6f7c5d2c6555561167fe9b10665102206869339122f1ed89efa4a985397f6",
+            "Twofish/CFB/NoPadding",
+            "821c54b1b54ae113cf74595eefe10c8308b7a438277de4f40948ac2d172d53d2",
+            "RC2/CFB/NoPadding",
+            "0a07cb78537cb04ca1401450d5cd411c7da7fa5b6baaa17bb2137bd95c9f26a5",
+            "RC5/CFB/NoPadding",
+            "c62b233df296283b989352bbebf616a19e11503ac737f9e0eaf19049cde05d34",
+            "IDEA/CFB/NoPadding",
+            "dd447da3cbdcf81fcbe4661dcbed88aed899f87585118384bd0565067fa6c13a",
+            "DES/CFB8/NoPadding",
+            "53cb0cdff712a825eb283b23c31e7323aa12495e7e751428b5c4eb89b28a25d4",
+            "DESede/CFB8/NoPadding",
+            "482cd5bf87ca4cee0b573d66a077231bfea93843ce2d1f948550a1d208e18279",
+            "SKIPJACK/CFB8/NoPadding",
+            "719eef3906bef23f7b63599285437d8e34183b165acf3e855b4e160d4f036508",
+            "Blowfish/CFB8/NoPadding",
+            "6ca63aaada9188d2410c07513cc0736b9888770768c25a5befc776beea5bdc4c",
+            "Twofish/CFB8/NoPadding",
+            "825d12af040721cf5ed4a4798647837ac5eb14d752aace28728aeb37b2010abd",
+            "RC2/CFB8/NoPadding",
+            "0aa227f94be3a32ff927c5d25647ea41d7c2a1e94012fc7f2ad6767b9664bce5",
+            "RC5/CFB8/NoPadding",
+            "c601cf88725411f119965b9cd38d6c313b91128ed7c98c7604cc62d9b210be79",
+            "IDEA/CFB8/NoPadding",
+            "dd7839d2525420d10f95eec23dbaf3463302c445972a28c563c2635191bc19af",
+            // TODO Check that PGPCFB modes are obsolete for C# build
+//			"IDEA/PGPCFB/NoPadding",
+//			"dd447da3cbdcf81fcbe4661dcbed88aed899f87585118384bd0565067fa6c13a",
+//			"IDEA/PGPCFBwithIv/NoPadding",
+//			"ed5adbac0e730cc0f00df7e4f6fef672ab042673106435faf3ecf3996a72a0e127b440ba9e5313501de3",
+            "Twofish/ECB/TBCPadding",
+            "70336d9c9718a8a2ced1b19deed973a3c58af7ea71a69e7efc4df082dca581c019d7daa58d02b89aab6e8c0d17202439",
+            "RC2/ECB/TBCPadding",
+            "eb5b889bbcced12eb6b1a3da6a3d965bba66a5edfdd4c8a6b6b1a3da6a3d965b6b5359ba5e69b179"
+        };
+
+        private static readonly string[] cipherTests2 =
+        {
+            "DES/OFB64/NoPadding",
+            "537572e480c1714f5c9a4f3b874df824dc6681b1fd6c11982debcad91e",
+            "DES/CFB64/NoPadding",
+            "537572e480c1714fec3c7424f88d4202219244c5ca8f5e4361d64f08fe",
+            "DES/CTR/NoPadding",
+            "537572e480c1714fb47081d35eb18eaca9e0a5aee982f105438a0db6ce",
+            "DES/CTS/NoPadding",
+            "60fa2f8fae5aa2a38e9ac77d0246726b32df660db51a710ceb7511e451"
+        };
+
+        private static readonly byte[] input1 = Hex.Decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f");
+        private static readonly byte[] input2 = Hex.Decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c");
+
+//		static RC2ParameterSpec rc2Spec = new RC2ParameterSpec(128, Hex.decode("0123456789abcdef"));
+        private static readonly byte[] rc2IV = Hex.Decode("0123456789abcdef");
+
+//		static RC5ParameterSpec rc5Spec = new RC5ParameterSpec(16, 16, 32, Hex.decode("0123456789abcdef"));
+//		static RC5ParameterSpec rc564Spec = new RC5ParameterSpec(16, 16, 64, Hex.decode("0123456789abcdef0123456789abcdef"));
+        private static readonly byte[] rc5IV = Hex.Decode("0123456789abcdef");
+        private static readonly byte[] rc564IV = Hex.Decode("0123456789abcdef0123456789abcdef");
+        private const int rc5Rounds = 16;
+
+        /**
+        * a fake random number generator - we just want to make sure the random numbers
+        * aren't random so that we get the same output, while still getting to test the
+        * key generation facilities.
+        */
+        private class FixedSecureRandom
+            : SecureRandom
+        {
+            byte[] seed = {
+                    (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59,
+                    (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4,
+                    (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde,
+                    (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f
+            };
+
+            public override void NextBytes(
+                byte[] bytes)
+            {
+                int offset = 0;
+
+                while ((offset + seed.Length) < bytes.Length)
+                {
+                    Array.Copy(seed, 0, bytes, offset, seed.Length);
+                    offset += seed.Length;
+                }
+
+                Array.Copy(seed, 0, bytes, offset, bytes.Length- offset);
+            }
+        }
+
+        public override string Name
+        {
+            get { return "BlockCipher"; }
+        }
+
+        private int GetIVLength(
+            string algorithm)
+        {
+            string[] parts = algorithm.Split('/');
+
+            if (parts.Length < 2)
+                return 0;
+
+            string mode = parts[1];
+
+            int pos = mode.IndexOfAny(new char[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
+            string baseMode = pos < 0 ? mode : mode.Substring(0, pos);
+
+            if (!validModes.Contains(baseMode))
+                throw new Exception("Unhandled mode: " + mode);
+
+            if (baseMode == "ECB")
+                return 0;
+
+            string baseAlgorithm = parts[0];
+            IBufferedCipher baseCipher = CipherUtilities.GetCipher(baseAlgorithm);
+            return baseCipher.GetBlockSize();
+        }
+
+        private void doTest(
+            string	algorithm,
+            byte[]	input,
+            byte[]	output)
+        {
+            KeyParameter key = null;
+            CipherKeyGenerator keyGen;
+            SecureRandom rand;
+            IBufferedCipher inCipher = null, outCipher = null;
+            byte[] iv = null;
+            CipherStream cIn, cOut;
+            MemoryStream bIn, bOut;
+
+            rand = new FixedSecureRandom();
+
+            string[] parts = algorithm.ToUpper(CultureInfo.InvariantCulture).Split('/');
+            string baseAlgorithm = parts[0];
+            string mode = parts.Length > 1 ? parts[1] : null;
+
+            try
+            {
+                keyGen = GeneratorUtilities.GetKeyGenerator(baseAlgorithm);
+
+                // TODO Add Algorithm property to CipherKeyGenerator?
+//				if (!keyGen.getAlgorithm().Equals(baseAlgorithm))
+//				{
+//					Fail("wrong key generator returned!");
+//				}
+
+                // TODO Add new Init method to CipherKeyGenerator?
+//				keyGen.Init(rand);
+                keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+                byte[] keyBytes = keyGen.GenerateKey();
+
+                if (algorithm.StartsWith("RC5"))
+                {
+                    key = new RC5Parameters(keyBytes, rc5Rounds);
+                }
+                else
+                {
+                    key = ParameterUtilities.CreateKeyParameter(baseAlgorithm, keyBytes);
+                }
+
+                inCipher = CipherUtilities.GetCipher(algorithm);
+                outCipher = CipherUtilities.GetCipher(algorithm);
+
+                if (!inCipher.AlgorithmName.ToUpper(CultureInfo.InvariantCulture).StartsWith(baseAlgorithm))
+                {
+                    Fail("wrong cipher returned!");
+                }
+
+                ICipherParameters parameters = key;
+
+                int ivLength = GetIVLength(algorithm);
+
+                if (ivLength > 0)
+                {
+                    if (baseAlgorithm == "RC2")
+                    {
+                        iv = rc2IV;
+                    }
+                    else if (baseAlgorithm == "RC5")
+                    {
+                        iv = rc5IV;
+                    }
+                    else if (baseAlgorithm == "RC5-64")
+                    {
+                        iv = rc564IV;
+                    }
+                    else
+                    {
+                        // NB: rand always generates same values each test run
+                        iv = rand.GenerateSeed(ivLength);
+                    }
+
+                    parameters = new ParametersWithIV(key, iv);
+                }
+
+                // NB: 'rand' still needed e.g. for some paddings
+                parameters = new ParametersWithRandom(parameters, rand);
+
+                outCipher.Init(true, parameters);
+            }
+            catch (Exception e)
+            {
+                Fail("" + algorithm + " failed initialisation - " + e.ToString(), e);
+            }
+
+            //
+            // grab the iv if there is one
+            //
+            try
+            {
+                // The Java version set this implicitly, but we set it explicity
+                //byte[] iv = outCipher.getIV();
+
+                if (iv != null)
+                {
+                    // TODO Examine short IV handling for these FIPS-compliant modes in Java build
+                    if (mode.StartsWith("CFB")
+                        || mode.StartsWith("GOFB")
+                        || mode.StartsWith("OFB")
+                        || mode.StartsWith("OPENPGPCFB"))
+                    {
+                        // These modes automatically pad out the IV if it is short
+                    }
+                    else
+                    {
+                        try
+                        {
+                            byte[] nIv = new byte[iv.Length- 1];
+                            inCipher.Init(false, new ParametersWithIV(key, nIv));
+                            Fail("failed to pick up short IV");
+                        }
+                        //catch (InvalidAlgorithmParameterException e)
+                        catch (ArgumentException)
+                        {
+                            // ignore - this is what we want...
+                        }
+                    }
+
+                    //IvParameterSpec spec = new IvParameterSpec(iv);
+                    inCipher.Init(false, new ParametersWithIV(key, iv));
+                }
+                else
+                {
+                    inCipher.Init(false, key);
+                }
+            }
+            catch (Exception e)
+            {
+                Fail("" + algorithm + " failed initialisation - " + e.ToString());
+            }
+
+            //
+            // encryption pass
+            //
+            bOut = new MemoryStream();
+            cOut = new CipherStream(bOut, null, outCipher);
+
+            try
+            {
+                for (int i = 0; i != input.Length/ 2; i++)
+                {
+                    cOut.WriteByte(input[i]);
+                }
+                cOut.Write(input, input.Length/ 2, input.Length- input.Length/ 2);
+                cOut.Close();
+            }
+            catch (IOException e)
+            {
+                Fail("" + algorithm + " failed encryption - " + e.ToString());
+            }
+
+            byte[] bytes = bOut.ToArray();
+
+            if (!AreEqual(bytes, output))
+            {
+                Fail("" + algorithm + " failed encryption - expected "
+                    + Hex.ToHexString(output) + " got "
+                    + Hex.ToHexString(bytes));
+            }
+
+            //
+            // decryption pass
+            //
+            bIn = new MemoryStream(bytes, false);
+            cIn = new CipherStream(bIn, inCipher, null);
+
+            try
+            {
+                BinaryReader dIn = new BinaryReader(cIn);
+
+                bytes = new byte[input.Length];
+
+                for (int i = 0; i != input.Length/ 2; i++)
+                {
+                    bytes[i] = dIn.ReadByte();
+                }
+
+                int remaining = bytes.Length - input.Length / 2;
+                byte[] extra = dIn.ReadBytes(remaining);
+                if (extra.Length < remaining)
+                    throw new EndOfStreamException();
+                extra.CopyTo(bytes, input.Length / 2);
+            }
+            catch (Exception e)
+            {
+                Fail("" + algorithm + " failed decryption - " + e.ToString());
+            }
+
+            if (!AreEqual(bytes, input))
+            {
+                Fail("" + algorithm + " failed decryption - expected "
+                    + Hex.ToHexString(input) + " got "
+                    + Hex.ToHexString(bytes));
+            }
+        }
+
+        // TODO Make private again and call from PerformTest
+        public void doTestExceptions()
+        {
+            // TODO Put back in
+//			SecretKeyFactory skF = null;
+//	        
+//			try
+//			{
+//				skF = SecretKeyFactory.getInstance("DESede");
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("unexpected exception.", e);
+//			}
+//	        
+//			KeySpec ks = null;
+//			SecretKey secKey = null;
+//			byte[] bb = new byte[24];
+//
+//			try
+//			{
+//				skF.getKeySpec(null, null);
+//	            
+//				Fail("failed exception test - no exception thrown");
+//			}
+//			catch (InvalidKeySpecException e)
+//			{
+//				// ignore okay
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("failed exception test.", e);
+//			}
+//			try
+//			{
+//				ks = (KeySpec)new DESedeKeySpec(bb);
+//				skF.getKeySpec(null, ks.getClass());
+//	            
+//				Fail("failed exception test - no exception thrown");
+//			}
+//			catch (InvalidKeySpecException e)
+//			{
+//				// ignore okay;
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("failed exception test.", e);
+//			}
+//			try
+//			{
+//				skF.getKeySpec(secKey, null);
+//			}
+//			catch (InvalidKeySpecException e)
+//			{
+//				// ignore okay
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("failed exception test.", e);
+//			}
+            
+            try
+            {
+                CipherKeyGenerator kg = GeneratorUtilities.GetKeyGenerator("DESede");
+
+                try
+                {
+                    kg.Init(new KeyGenerationParameters(new SecureRandom(), int.MinValue));
+
+                    Fail("failed exception test - no exception thrown");
+                }
+//				catch (InvalidParameterException)
+                catch (ArgumentException)
+                {
+                    // ignore okay
+                }
+                catch (Exception e)
+                {
+                    Fail("failed exception test.", e);
+                }
+            }
+            catch (Exception e)
+            {
+                Fail("unexpected exception.", e);
+            }
+
+            // TODO Put back in
+//			try
+//			{
+//				skF = SecretKeyFactory.getInstance("DESede");
+//
+//				try
+//				{
+//					skF.translateKey(null);
+//	                
+//					Fail("failed exception test - no exception thrown");
+//				}
+//				catch (InvalidKeyException)
+//				{
+//					// ignore okay
+//				}
+//				catch (Exception e)
+//				{
+//					Fail("failed exception test.", e);
+//				}
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("unexpected exception.", e);
+//			}
+            
+//			try
+//			{
+//				byte[] rawDESKey = { (byte)128, (byte)131, (byte)133, (byte)134,
+//						(byte)137, (byte)138, (byte)140, (byte)143 };
+//
+////				SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES");
+//				KeyParameter cipherKey = new DesParameters(rawDESKey);
+//
+//				IBufferedCipher cipher = CipherUtilities.GetCipher("DES/CBC/NoPadding");
+//
+//				try
+//				{
+//					// According specification engineInit(int opmode, Key key,
+//					// SecureRandom random) throws InvalidKeyException if this
+//					// cipher is being
+//					// initialized for decryption and requires algorithm parameters
+//					// that cannot be determined from the given key
+////					cipher.Init(false, cipherKey, (SecureRandom)null);
+//					cipher.Init(false, new ParametersWithRandom(cipherKey, new SecureRandom()));
+//
+//					Fail("failed exception test - no InvalidKeyException thrown");
+//				}
+//				catch (InvalidKeyException)
+//				{
+//					// ignore
+//				}
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("unexpected exception.", e);
+//			}
+
+            try
+            {
+//				byte[] rawDESKey = { -128, -125, -123, -122, -119, -118 };
+                byte[] rawDESKey = { 128, 131, 133, 134, 137, 138 };
+
+//				SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES");
+
+//				IBufferedCipher cipher = CipherUtilities.GetCipher("DES/ECB/NoPadding");
+                try
+                {
+                    KeyParameter cipherKey = new DesParameters(rawDESKey);
+
+                    // According specification engineInit(int opmode, Key key,
+                    // SecureRandom random) throws InvalidKeyException if the given
+                    // key is inappropriate for initializing this cipher
+//					cipher.Init(true, cipherKey);
+
+//					Fail("failed exception test - no InvalidKeyException thrown");
+                    Fail("failed exception test - no ArgumentException thrown");
+                }
+//				catch (InvalidKeyException)
+                catch (ArgumentException)
+                {
+                    // ignore
+                }
+            }
+            catch (Exception e)
+            {
+                Fail("unexpected exception.", e);
+            }
+
+//			try
+//			{
+////				byte[] rawDESKey = { -128, -125, -123, -122, -119, -118, -117, -115, -114 };
+//				byte[] rawDESKey = { 128, 131, 133, 134, 137, 138, 139, 141, 142 };
+//
+////				SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES");
+//				KeyParameter cipherKey = new DesParameters(rawDESKey);
+//
+//				IBufferedCipher cipher = CipherUtilities.GetCipher("DES/ECB/NoPadding");
+//				try
+//				{
+//					// According specification engineInit(int opmode, Key key,
+//					// SecureRandom random) throws InvalidKeyException if the given
+//					// key is inappropriate for initializing this cipher
+//					cipher.Init(true, cipherKey);
+//	                
+//					Fail("failed exception test - no InvalidKeyException thrown");
+//				}
+//				catch (InvalidKeyException)
+//				{
+//					// ignore
+//				}
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("unexpected exception.", e);
+//			}
+
+
+            try
+            {
+                byte[] rawDESKey = { (byte)128, (byte)131, (byte)133, (byte)134,
+                    (byte)137, (byte)138, (byte)140, (byte)143 };
+
+//				SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES");
+                KeyParameter cipherKey = new DesParameters(rawDESKey);
+
+                IBufferedCipher ecipher = CipherUtilities.GetCipher("DES/ECB/PKCS5Padding");
+                ecipher.Init(true, cipherKey);
+
+                byte[] cipherText = new byte[0];
+                try
+                {
+                    // According specification Method engineUpdate(byte[] input,
+                    // int inputOffset, int inputLen, byte[] output, int
+                    // outputOffset)
+                    // throws ShortBufferException - if the given output buffer is
+                    // too
+                    // small to hold the result
+//					ecipher.update(new byte[20], 0, 20, cipherText);
+                    ecipher.ProcessBytes(new byte[20], 0, 20, cipherText, 0);
+
+//					Fail("failed exception test - no ShortBufferException thrown");
+                    Fail("failed exception test - no DataLengthException thrown");
+                }
+//				catch (ShortBufferException)
+                catch (DataLengthException)
+                {
+                    // ignore
+                }
+            }
+            catch (Exception e)
+            {
+                Fail("unexpected exception.", e);
+            }
+
+            // TODO Put back in
+//			try
+//			{
+//				KeyGenerator keyGen = KeyGenerator.getInstance("DES");
+//
+//				keyGen.init((SecureRandom)null);
+//
+//				// According specification engineGenerateKey() doesn't throw any exceptions.
+//
+//				SecretKey key = keyGen.generateKey();
+//				if (key == null)
+//				{
+//					Fail("key is null!");
+//				}
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("unexpected exception.", e);
+//			}
+//
+//			try
+//			{
+//				AlgorithmParameters algParams = AlgorithmParameters.getInstance("DES");
+//	            
+//				algParams.init(new IvParameterSpec(new byte[8]));
+//
+//				// According specification engineGetEncoded() returns
+//				// the parameters in their primary encoding format. The primary
+//				// encoding
+//				// format for parameters is ASN.1, if an ASN.1 specification for
+//				// this type
+//				// of parameters exists.
+//				byte[] iv = algParams.getEncoded();
+//	            
+//				if (iv.Length!= 10)
+//				{
+//					Fail("parameters encoding wrong length - "  + iv.Length);
+//				}
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("unexpected exception.", e);
+//			}
+
+            try
+            {
+                try
+                {
+//					AlgorithmParameters algParams = AlgorithmParameters.getInstance("DES");
+
+                    byte[] encoding = new byte[10];
+                    encoding[0] = 3;
+                    encoding[1] = 8;
+
+//					algParams.init(encoding, "ASN.1");
+                    ParameterUtilities.GetCipherParameters(
+                        "AES",
+                        ParameterUtilities.CreateKeyParameter("AES", new byte[16]),
+                        Asn1Object.FromByteArray(encoding));
+
+//					Fail("failed exception test - no IOException thrown");
+                    Fail("failed exception test - no Exception thrown");
+                }
+//				catch (IOException)
+                catch (ArgumentException)
+                {
+                    // okay
+                }
+
+//				try
+//				{
+//					IBufferedCipher c = CipherUtilities.GetCipher("DES");
+//
+//					Key k = new PublicKey()
+//					{
+//
+//						public string getAlgorithm()
+//						{
+//							return "STUB";
+//						}
+//
+//						public string getFormat()
+//						{
+//							return null;
+//						}
+//
+//						public byte[] getEncoded()
+//						{
+//							return null;
+//						}
+//	                    
+//					};
+//	    
+//					c.Init(true, k);
+//	    
+//					Fail("failed exception test - no InvalidKeyException thrown for public key");
+//				}
+//				catch (InvalidKeyException e)
+//				{
+//					// okay
+//				}
+//	            
+//				try
+//				{
+//					IBufferedCipher c = CipherUtilities.GetCipher("DES");
+//	    
+//					Key k = new PrivateKey()
+//					{
+//
+//						public string getAlgorithm()
+//						{
+//							return "STUB";
+//						}
+//
+//						public string getFormat()
+//						{
+//							return null;
+//						}
+//
+//						public byte[] getEncoded()
+//						{
+//							return null;
+//						}
+//	                    
+//					};
+//	    
+//					c.Init(false, k);
+//	    
+//					Fail("failed exception test - no InvalidKeyException thrown for private key");
+//				}
+//				catch (InvalidKeyException e)
+//				{
+//					// okay
+//				}
+            }
+            catch (Exception e)
+            {
+                Fail("unexpected exception.", e);
+            }
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i != cipherTests1.Length; i += 2)
+            {
+                doTest(cipherTests1[i], input1, Hex.Decode(cipherTests1[i + 1]));
+            }
+
+            for (int i = 0; i != cipherTests2.Length; i += 2)
+            {
+                doTest(cipherTests2[i], input2, Hex.Decode(cipherTests2[i + 1]));
+            }
+
+            //
+            // check for less than a block
+            //
+            try
+            {
+                IBufferedCipher c = CipherUtilities.GetCipher("AES/CTS/NoPadding");
+
+                c.Init(true, ParameterUtilities.CreateKeyParameter("AES", new byte[16]));
+
+                c.DoFinal(new byte[4]);
+
+                Fail("CTS failed to throw exception");
+            }
+            catch (Exception e)
+            {
+//				if (!(e is IllegalBlockSizeException))
+                if (!(e is DataLengthException))
+                {
+                    Fail("CTS exception test - " + e, e);
+                }
+            }
+
+            doTestExceptions();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new BlockCipherTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/CMacTest.cs b/crypto/test/src/test/CMacTest.cs
new file mode 100644
index 000000000..f80caca7d
--- /dev/null
+++ b/crypto/test/src/test/CMacTest.cs
@@ -0,0 +1,276 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/**
+	 * CMAC tester - <a href="http://www.nuee.nagoya-u.ac.jp/labs/tiwata/omac/tv/omac1-tv.txt">AES Official Test Vectors</a>.
+	 */
+	[TestFixture]
+	public class CMacTest
+		:	SimpleTest
+	{
+		private static readonly byte[] keyBytes128 = Hex.Decode("2b7e151628aed2a6abf7158809cf4f3c");
+		private static readonly byte[] keyBytes192 = Hex.Decode(
+			  "8e73b0f7da0e6452c810f32b809079e5"
+			+ "62f8ead2522c6b7b");
+		private static readonly byte[] keyBytes256 = Hex.Decode(
+			  "603deb1015ca71be2b73aef0857d7781"
+			+ "1f352c073b6108d72d9810a30914dff4");
+		
+		private static readonly byte[] input0 = Hex.Decode("");
+		private static readonly byte[] input16 = Hex.Decode("6bc1bee22e409f96e93d7e117393172a");
+		private static readonly byte[] input40 = Hex.Decode(
+			  "6bc1bee22e409f96e93d7e117393172a"
+			+ "ae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411");
+		private static readonly byte[] input64 = Hex.Decode(
+			  "6bc1bee22e409f96e93d7e117393172a"
+			+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+			+ "30c81c46a35ce411e5fbc1191a0a52ef"
+			+ "f69f2445df4f9b17ad2b417be66c3710");
+
+		private static readonly byte[] output_k128_m0 = Hex.Decode("bb1d6929e95937287fa37d129b756746");
+		private static readonly byte[] output_k128_m16 = Hex.Decode("070a16b46b4d4144f79bdd9dd04a287c");
+		private static readonly byte[] output_k128_m40 = Hex.Decode("dfa66747de9ae63030ca32611497c827");
+		private static readonly byte[] output_k128_m64 = Hex.Decode("51f0bebf7e3b9d92fc49741779363cfe");
+
+		private static readonly byte[] output_k192_m0 = Hex.Decode("d17ddf46adaacde531cac483de7a9367");
+		private static readonly byte[] output_k192_m16 = Hex.Decode("9e99a7bf31e710900662f65e617c5184");
+		private static readonly byte[] output_k192_m40 = Hex.Decode("8a1de5be2eb31aad089a82e6ee908b0e");
+		private static readonly byte[] output_k192_m64 = Hex.Decode("a1d5df0eed790f794d77589659f39a11");
+
+		private static readonly byte[] output_k256_m0 = Hex.Decode("028962f61b7bf89efc6b551f4667d983");
+		private static readonly byte[] output_k256_m16 = Hex.Decode("28a7023f452e8f82bd4bf28d8c37c35c");
+		private static readonly byte[] output_k256_m40 = Hex.Decode("aaf3d8f1de5640c232f5b169b9c911e6");
+		private static readonly byte[] output_k256_m64 = Hex.Decode("e1992190549f6ed5696a2c056c315410");
+
+		private static readonly byte[] output_des_ede = Hex.Decode("1ca670dea381d37c");
+
+		public CMacTest()
+		{
+		}
+		
+		public override void PerformTest()
+		{
+//			Mac mac = Mac.getInstance("AESCMAC", "BC");
+			IMac mac = MacUtilities.GetMac("AESCMAC");
+
+			//128 bytes key
+
+//			SecretKeySpec key = new SecretKeySpec(keyBytes128, "AES");
+			KeyParameter key = new KeyParameter(keyBytes128);
+
+			// 0 bytes message - 128 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input0, 0, input0.Length);
+
+			byte[] output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k128_m0))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k128_m0)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 16 bytes message - 128 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input16, 0, input16.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k128_m16))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k128_m16)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 40 bytes message - 128 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input40, 0, input40.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k128_m40))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k128_m40)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 64 bytes message - 128 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input64, 0, input64.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k128_m64))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k128_m64)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			//192 bytes key
+
+//			key = new SecretKeySpec(keyBytes192, "AES");
+			key = new KeyParameter(keyBytes192);
+
+			// 0 bytes message - 192 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input0, 0, input0.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k192_m0))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k192_m0)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 16 bytes message - 192 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input16, 0, input16.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k192_m16))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k192_m16)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 40 bytes message - 192 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input40, 0, input40.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k192_m40))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k192_m40)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 64 bytes message - 192 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input64, 0, input64.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k192_m64))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k192_m64)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			//256 bytes key
+
+//			key = new SecretKeySpec(keyBytes256, "AES");
+			key = new KeyParameter(keyBytes256);
+
+			// 0 bytes message - 256 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input0, 0, input0.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k256_m0))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k256_m0)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 16 bytes message - 256 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input16, 0, input16.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k256_m16))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k256_m16)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 40 bytes message - 256 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input40, 0, input40.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k256_m40))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k256_m40)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+			// 64 bytes message - 256 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input64, 0, input64.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_k256_m64))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_k256_m64)
+					+ " got " + Hex.ToHexString(output));
+			}
+
+//			mac = Mac.getInstance("DESedeCMAC", "BC");
+			mac = MacUtilities.GetMac("DESedeCMAC");
+
+			//DESede
+			
+//			key = new SecretKeySpec(keyBytes128, "DESede");
+			key = new KeyParameter(keyBytes128);
+
+			// 0 bytes message - 128 bytes key
+			mac.Init(key);
+
+			mac.BlockUpdate(input0, 0, input0.Length);
+
+			output = MacUtilities.DoFinal(mac);
+
+			if (!AreEqual(output, output_des_ede))
+			{
+				Fail("Failed - expected " + Hex.ToHexString(output_des_ede)
+					+ " got " + Hex.ToHexString(output));
+			}
+		}
+
+		public override string Name
+		{
+			get { return "CMac"; }
+		}
+
+		public static void Main(string[] args)
+		{
+			RunTest(new CMacTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/CRL5Test.cs b/crypto/test/src/test/CRL5Test.cs
new file mode 100644
index 000000000..ebd74af69
--- /dev/null
+++ b/crypto/test/src/test/CRL5Test.cs
@@ -0,0 +1,257 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class Crl5Test
+		: SimpleTest
+	{
+		private static readonly byte[] indirectCrl = Base64.Decode(
+			"MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV"
+			+"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0"
+			+"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO"
+			+"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3"
+			+"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+			+"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+			+"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV"
+			+"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+			+"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+			+"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+			+"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0"
+			+"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+			+"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+			+"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV"
+			+"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+			+"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+			+"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+			+"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/jFw0wMzAx"
+			+"MTMxMTI2NTZaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+			+"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+			+"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+QXDTAzMDExMzExMjY1NlowZzBlBgNV"
+			+"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+			+"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+			+"UE4wfgIEL64/4hcNMDQwNzEzMDc1ODM4WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+			+"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/eFw0wMzAy"
+			+"MTcwNjMzMjVaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+			+"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+			+"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP98XDTAzMDIxNzA2MzMyNVowZzBlBgNV"
+			+"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+			+"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+			+"UE4wfgIEL64/0xcNMDMwMjE3MDYzMzI1WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+			+"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/dFw0wMzAx"
+			+"MTMxMTI4MTRaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+			+"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+			+"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP9cXDTAzMDExMzExMjcwN1owZzBlBgNV"
+			+"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+			+"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+			+"UE4wfgIEL64/2BcNMDMwMTEzMTEyNzA3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+			+"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/VFw0wMzA0"
+			+"MzAxMjI3NTNaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+			+"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+			+"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP9YXDTAzMDQzMDEyMjc1M1owZzBlBgNV"
+			+"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+			+"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+			+"UE4wfgIEL64/xhcNMDMwMjEyMTM0NTQwWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+			+"BgEKBxQTATEwGAYDVQQDFBFUVEMgVGVzdCBDQSAxMTpQTjCBkAIEL64/xRcNMDMw"
+			+"MjEyMTM0NTQwWjB5MHcGA1UdHQEB/wRtMGukaTBnMQswCQYDVQQGEwJERTEcMBoG"
+			+"A1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEQMA4GA1UECxQHVGVsZVNlYzEoMAwG"
+			+"BwKCBgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNTpQTjB+AgQvrj/CFw0w"
+			+"MzAyMTIxMzA5MTZaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRww"
+			+"GgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNV"
+			+"BAMUEVRUQyBUZXN0IENBIDExOlBOMIGQAgQvrj/BFw0wMzAyMTIxMzA4NDBaMHkw"
+			+"dwYDVR0dAQH/BG0wa6RpMGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2No"
+			+"ZSBUZWxla29tIEFHMRAwDgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAY"
+			+"BgNVBAMUEVNpZ0cgVGVzdCBDQSA1OlBOMH4CBC+uP74XDTAzMDIxNzA2MzcyNVow"
+			+"ZzBlBgNVHR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRz"
+			+"Y2hlIFRlbGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRVFRDIFRlc3Qg"
+			+"Q0EgMTE6UE4wgZACBC+uP70XDTAzMDIxNzA2MzcyNVoweTB3BgNVHR0BAf8EbTBr"
+			+"pGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcx"
+			+"EDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBU"
+			+"ZXN0IENBIDU6UE4wgZACBC+uP7AXDTAzMDIxMjEzMDg1OVoweTB3BgNVHR0BAf8E"
+			+"bTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g"
+			+"QUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2ln"
+			+"RyBUZXN0IENBIDU6UE4wgZACBC+uP68XDTAzMDIxNzA2MzcyNVoweTB3BgNVHR0B"
+			+"Af8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVr"
+			+"b20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQR"
+			+"U2lnRyBUZXN0IENBIDU6UE4wfgIEL64/kxcNMDMwNDEwMDUyNjI4WjBnMGUGA1Ud"
+			+"HQEB/wRbMFmkVzBVMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVs"
+			+"ZWtvbSBBRzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFUVEMgVGVzdCBDQSAxMTpQ"
+			+"TjCBkAIEL64/khcNMDMwNDEwMDUyNjI4WjB5MHcGA1UdHQEB/wRtMGukaTBnMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEQMA4GA1UE"
+			+"CxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0Eg"
+			+"NTpQTjB+AgQvrj8/Fw0wMzAyMjYxMTA0NDRaMGcwZQYDVR0dAQH/BFswWaRXMFUx"
+			+"CzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYH"
+			+"AoIGAQoHFBMBMTAYBgNVBAMUEVRUQyBUZXN0IENBIDExOlBOMIGQAgQvrj8+Fw0w"
+			+"MzAyMjYxMTA0NDRaMHkwdwYDVR0dAQH/BG0wa6RpMGcxCzAJBgNVBAYTAkRFMRww"
+			+"GgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYDVQQLFAdUZWxlU2VjMSgw"
+			+"DAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBDQSA1OlBOMH4CBC+uPs0X"
+			+"DTAzMDUyMDA1MjczNlowZzBlBgNVHR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUx"
+			+"HDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgG"
+			+"A1UEAxQRVFRDIFRlc3QgQ0EgMTE6UE4wgZACBC+uPswXDTAzMDUyMDA1MjczNlow"
+			+"eTB3BgNVHR0BAf8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRz"
+			+"Y2hlIFRlbGVrb20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwEx"
+			+"MBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6UE4wfgIEL64+PBcNMDMwNjE3MTAzNDE2"
+			+"WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1"
+			+"dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFUVEMgVGVz"
+			+"dCBDQSAxMTpQTjCBkAIEL64+OxcNMDMwNjE3MTAzNDE2WjB5MHcGA1UdHQEB/wRt"
+			+"MGukaTBnMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBB"
+			+"RzEQMA4GA1UECxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFTaWdH"
+			+"IFRlc3QgQ0EgNjpQTjCBkAIEL64+OhcNMDMwNjE3MTAzNDE2WjB5MHcGA1UdHQEB"
+			+"/wRtMGukaTBnMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtv"
+			+"bSBBRzEQMA4GA1UECxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFT"
+			+"aWdHIFRlc3QgQ0EgNjpQTjB+AgQvrj45Fw0wMzA2MTcxMzAxMDBaMGcwZQYDVR0d"
+			+"AQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxl"
+			+"a29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVRUQyBUZXN0IENBIDExOlBO"
+			+"MIGQAgQvrj44Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6RpMGcxCzAJ"
+			+"BgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYDVQQL"
+			+"FAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBDQSA2"
+			+"OlBOMIGQAgQvrj43Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6RpMGcx"
+			+"CzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYD"
+			+"VQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBD"
+			+"QSA2OlBOMIGQAgQvrj42Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6Rp"
+			+"MGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAw"
+			+"DgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVz"
+			+"dCBDQSA2OlBOMIGQAgQvrj4zFw0wMzA2MTcxMDM3NDlaMHkwdwYDVR0dAQH/BG0w"
+			+"a6RpMGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFH"
+			+"MRAwDgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cg"
+			+"VGVzdCBDQSA2OlBOMH4CBC+uPjEXDTAzMDYxNzEwNDI1OFowZzBlBgNVHR0BAf8E"
+			+"WzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g"
+			+"QUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRVFRDIFRlc3QgQ0EgMTE6UE4wgZAC"
+			+"BC+uPjAXDTAzMDYxNzEwNDI1OFoweTB3BgNVHR0BAf8EbTBrpGkwZzELMAkGA1UE"
+			+"BhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNVBAsUB1Rl"
+			+"bGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6UE4w"
+			+"gZACBC+uPakXDTAzMTAyMjExMzIyNFoweTB3BgNVHR0BAf8EbTBrpGkwZzELMAkG"
+			+"A1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNVBAsU"
+			+"B1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6"
+			+"UE4wgZACBC+uPLIXDTA1MDMxMTA2NDQyNFoweTB3BgNVHR0BAf8EbTBrpGkwZzEL"
+			+"MAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNV"
+			+"BAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENB"
+			+"IDY6UE4wgZACBC+uPKsXDTA0MDQwMjA3NTQ1M1oweTB3BgNVHR0BAf8EbTBrpGkw"
+			+"ZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAO"
+			+"BgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0"
+			+"IENBIDY6UE4wgZACBC+uOugXDTA1MDEyNzEyMDMyNFoweTB3BgNVHR0BAf8EbTBr"
+			+"pGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcx"
+			+"EDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBU"
+			+"ZXN0IENBIDY6UE4wgZACBC+uOr4XDTA1MDIxNjA3NTcxNloweTB3BgNVHR0BAf8E"
+			+"bTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g"
+			+"QUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2ln"
+			+"RyBUZXN0IENBIDY6UE4wgZACBC+uOqcXDTA1MDMxMDA1NTkzNVoweTB3BgNVHR0B"
+			+"Af8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVr"
+			+"b20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQR"
+			+"U2lnRyBUZXN0IENBIDY6UE4wgZACBC+uOjwXDTA1MDUxMTEwNDk0NloweTB3BgNV"
+			+"HR0BAf8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+			+"bGVrb20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UE"
+			+"AxQRU2lnRyBUZXN0IENBIDY6UE4wgaoCBC+sbdUXDTA1MTExMTEwMDMyMVowgZIw"
+			+"gY8GA1UdHQEB/wSBhDCBgaR/MH0xCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0"
+			+"c2NoZSBUZWxla29tIEFHMR8wHQYDVQQLFBZQcm9kdWt0emVudHJ1bSBUZWxlU2Vj"
+			+"MS8wDAYHAoIGAQoHFBMBMTAfBgNVBAMUGFRlbGVTZWMgUEtTIFNpZ0cgQ0EgMTpQ"
+			+"TjCBlQIEL64uaBcNMDYwMTIzMTAyNTU1WjB+MHwGA1UdHQEB/wRyMHCkbjBsMQsw"
+			+"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEWMBQGA1UE"
+			+"CxQNWmVudHJhbGUgQm9ubjEnMAwGBwKCBgEKBxQTATEwFwYDVQQDFBBUVEMgVGVz"
+			+"dCBDQSA5OlBOMIGVAgQvribHFw0wNjA4MDEwOTQ4NDRaMH4wfAYDVR0dAQH/BHIw"
+			+"cKRuMGwxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFH"
+			+"MRYwFAYDVQQLFA1aZW50cmFsZSBCb25uMScwDAYHAoIGAQoHFBMBMTAXBgNVBAMU"
+			+"EFRUQyBUZXN0IENBIDk6UE6ggZswgZgwCwYDVR0UBAQCAhEMMB8GA1UdIwQYMBaA"
+			+"FANbyNumDI9545HwlCF26NuOJC45MA8GA1UdHAEB/wQFMAOEAf8wVwYDVR0SBFAw"
+			+"ToZMbGRhcDovL3Brc2xkYXAudHR0Yy5kZS9vdT1ULVRlbGVTZWMgVGVzdCBESVIg"
+			+"ODpQTixvPURldXRzY2hlIFRlbGVrb20gQUcsYz1kZTANBgkqhkiG9w0BAQUFAAOB"
+			+"gQBewL5gLFHpeOWO07Vk3Gg7pRDuAlvaovBH4coCyCWpk5jEhUfFSYEDuaQB7do4"
+			+"IlJmeTHvkI0PIZWJ7bwQ2PVdipPWDx0NVwS/Cz5jUKiS3BbAmZQZOueiKLFpQq3A"
+			+"b8aOHA7WHU4078/1lM+bgeu33Ln1CGykEbmSjA/oKPi/JA==");
+
+		private static readonly byte[] directCrl = Base64.Decode(
+			"MIIGXTCCBckCAQEwCgYGKyQDAwECBQAwdDELMAkGA1UEBhMCREUxHDAaBgNVBAoU"
+			+"E0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0MS4w"
+			+"DAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBOFw0w"
+			+"NjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIElTAVAgQvrj/pFw0wMzA3MjIw"
+			+"NTQxMjhaMBUCBC+uP+oXDTAzMDcyMjA1NDEyOFowFQIEL64/5xcNMDQwNDA1MTMx"
+			+"ODE3WjAVAgQvrj/oFw0wNDA0MDUxMzE4MTdaMBUCBC+uP+UXDTAzMDExMzExMTgx"
+			+"MVowFQIEL64/5hcNMDMwMTEzMTExODExWjAVAgQvrj/jFw0wMzAxMTMxMTI2NTZa"
+			+"MBUCBC+uP+QXDTAzMDExMzExMjY1NlowFQIEL64/4hcNMDQwNzEzMDc1ODM4WjAV"
+			+"AgQvrj/eFw0wMzAyMTcwNjMzMjVaMBUCBC+uP98XDTAzMDIxNzA2MzMyNVowFQIE"
+			+"L64/0xcNMDMwMjE3MDYzMzI1WjAVAgQvrj/dFw0wMzAxMTMxMTI4MTRaMBUCBC+u"
+			+"P9cXDTAzMDExMzExMjcwN1owFQIEL64/2BcNMDMwMTEzMTEyNzA3WjAVAgQvrj/V"
+			+"Fw0wMzA0MzAxMjI3NTNaMBUCBC+uP9YXDTAzMDQzMDEyMjc1M1owFQIEL64/xhcN"
+			+"MDMwMjEyMTM0NTQwWjAVAgQvrj/FFw0wMzAyMTIxMzQ1NDBaMBUCBC+uP8IXDTAz"
+			+"MDIxMjEzMDkxNlowFQIEL64/wRcNMDMwMjEyMTMwODQwWjAVAgQvrj++Fw0wMzAy"
+			+"MTcwNjM3MjVaMBUCBC+uP70XDTAzMDIxNzA2MzcyNVowFQIEL64/sBcNMDMwMjEy"
+			+"MTMwODU5WjAVAgQvrj+vFw0wMzAyMTcwNjM3MjVaMBUCBC+uP5MXDTAzMDQxMDA1"
+			+"MjYyOFowFQIEL64/khcNMDMwNDEwMDUyNjI4WjAVAgQvrj8/Fw0wMzAyMjYxMTA0"
+			+"NDRaMBUCBC+uPz4XDTAzMDIyNjExMDQ0NFowFQIEL64+zRcNMDMwNTIwMDUyNzM2"
+			+"WjAVAgQvrj7MFw0wMzA1MjAwNTI3MzZaMBUCBC+uPjwXDTAzMDYxNzEwMzQxNlow"
+			+"FQIEL64+OxcNMDMwNjE3MTAzNDE2WjAVAgQvrj46Fw0wMzA2MTcxMDM0MTZaMBUC"
+			+"BC+uPjkXDTAzMDYxNzEzMDEwMFowFQIEL64+OBcNMDMwNjE3MTMwMTAwWjAVAgQv"
+			+"rj43Fw0wMzA2MTcxMzAxMDBaMBUCBC+uPjYXDTAzMDYxNzEzMDEwMFowFQIEL64+"
+			+"MxcNMDMwNjE3MTAzNzQ5WjAVAgQvrj4xFw0wMzA2MTcxMDQyNThaMBUCBC+uPjAX"
+			+"DTAzMDYxNzEwNDI1OFowFQIEL649qRcNMDMxMDIyMTEzMjI0WjAVAgQvrjyyFw0w"
+			+"NTAzMTEwNjQ0MjRaMBUCBC+uPKsXDTA0MDQwMjA3NTQ1M1owFQIEL6466BcNMDUw"
+			+"MTI3MTIwMzI0WjAVAgQvrjq+Fw0wNTAyMTYwNzU3MTZaMBUCBC+uOqcXDTA1MDMx"
+			+"MDA1NTkzNVowFQIEL646PBcNMDUwNTExMTA0OTQ2WjAVAgQvrG3VFw0wNTExMTEx"
+			+"MDAzMjFaMBUCBC+uLmgXDTA2MDEyMzEwMjU1NVowFQIEL64mxxcNMDYwODAxMDk0"
+			+"ODQ0WqCBijCBhzALBgNVHRQEBAICEQwwHwYDVR0jBBgwFoAUA1vI26YMj3njkfCU"
+			+"IXbo244kLjkwVwYDVR0SBFAwToZMbGRhcDovL3Brc2xkYXAudHR0Yy5kZS9vdT1U"
+			+"LVRlbGVTZWMgVGVzdCBESVIgODpQTixvPURldXRzY2hlIFRlbGVrb20gQUcsYz1k"
+			+"ZTAKBgYrJAMDAQIFAAOBgQArj4eMlbAwuA2aS5O4UUUHQMKKdK/dtZi60+LJMiMY"
+			+"ojrMIf4+ZCkgm1Ca0Cd5T15MJxVHhh167Ehn/Hd48pdnAP6Dfz/6LeqkIHGWMHR+"
+			+"z6TXpwWB+P4BdUec1ztz04LypsznrHcLRa91ixg9TZCb1MrOG+InNhleRs1ImXk8"
+			+"MQ==");
+
+		public override string Name
+		{
+			get { return "CRL5"; }
+		}
+
+		[Test]
+		public void TestIndirectCrl()
+		{
+			X509Crl crl = new X509CrlParser().ReadCrl(indirectCrl);
+
+			foreach (X509CrlEntry crlEntry in crl.GetRevokedCertificates())
+			{
+				if (crlEntry.GetCertificateIssuer() == null)
+				{
+					Fail("certificate issuer CRL entry extension is null");
+				}
+			}
+		}
+
+		[Test]
+		public void TestDirectCrl()
+		{
+			X509Crl crl = new X509CrlParser().ReadCrl(directCrl);
+
+			foreach (X509CrlEntry crlEntry in crl.GetRevokedCertificates())
+			{
+				if (crlEntry.GetCertificateIssuer() != null)
+				{
+					Fail("certificate issuer CRL entry extension is not null");
+				}
+			}
+		}
+
+		public override void PerformTest()
+		{
+			TestIndirectCrl();
+			TestDirectCrl();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Crl5Test());
+		}
+	}
+}
diff --git a/crypto/test/src/test/CamelliaTest.cs b/crypto/test/src/test/CamelliaTest.cs
new file mode 100644
index 000000000..f8e3520a3
--- /dev/null
+++ b/crypto/test/src/test/CamelliaTest.cs
@@ -0,0 +1,204 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <summary>Basic test class for Camellia</summary>
+	[TestFixture]
+	public class CamelliaTest
+		: BaseBlockCipherTest
+	{
+		internal static readonly string[] cipherTests =
+		{
+			"128",
+			"0123456789abcdeffedcba9876543210",
+			"0123456789abcdeffedcba9876543210",
+			"67673138549669730857065648eabe43",
+			"192",
+			"0123456789abcdeffedcba98765432100011223344556677",
+			"0123456789abcdeffedcba9876543210",
+			"b4993401b3e996f84ee5cee7d79b09b9",
+			"256",
+			"0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff",
+			"0123456789abcdeffedcba9876543210",
+			"9acc237dff16d76c20ef7c919e3a7509",
+		};
+
+		public CamelliaTest()
+			: base("Camellia")
+		{
+		}
+
+		[Test]
+		public void TestCiphers()
+		{
+			for (int i = 0; i != cipherTests.Length; i += 4)
+			{
+				doCipherTest(int.Parse(cipherTests[i]),
+					Hex.Decode(cipherTests[i + 1]),
+					Hex.Decode(cipherTests[i + 2]),
+					Hex.Decode(cipherTests[i + 3]));
+			}
+		}
+
+		[Test]
+		public void TestWrap()
+		{
+			byte[] kek1 = Hex.Decode("000102030405060708090a0b0c0d0e0f");
+			byte[] in1 = Hex.Decode("00112233445566778899aabbccddeeff");
+			byte[] out1 = Hex.Decode("635d6ac46eedebd3a7f4a06421a4cbd1746b24795ba2f708");
+
+			wrapTest(1, "CamelliaWrap", kek1, in1, out1);
+		}
+
+		[Test]
+		public void TestOids()
+		{
+			string[] oids = {
+				NttObjectIdentifiers.IdCamellia128Cbc.Id,
+				NttObjectIdentifiers.IdCamellia192Cbc.Id,
+				NttObjectIdentifiers.IdCamellia256Cbc.Id
+			};
+
+			string[] names = {
+				"Camellia/CBC/PKCS7Padding",
+				"Camellia/CBC/PKCS7Padding",
+				"Camellia/CBC/PKCS7Padding"
+			};
+
+			oidTest(oids, names, 1);
+		}
+
+		[Test]
+		public void TestWrapOids()
+		{
+			string[] wrapOids = {
+				NttObjectIdentifiers.IdCamellia128Wrap.Id,
+				NttObjectIdentifiers.IdCamellia192Wrap.Id,
+				NttObjectIdentifiers.IdCamellia256Wrap.Id
+			};
+
+			wrapOidTest(wrapOids, "CamelliaWrap");
+		}
+
+		public void doCipherTest(
+			int		strength,
+			byte[]	keyBytes,
+			byte[]	input,
+			byte[]	output)
+		{
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("Camellia", keyBytes);
+
+			IBufferedCipher inCipher = CipherUtilities.GetCipher("Camellia/ECB/NoPadding");
+			IBufferedCipher outCipher = CipherUtilities.GetCipher("Camellia/ECB/NoPadding");
+
+			try
+			{
+				outCipher.Init(true, key);
+			}
+			catch (Exception e)
+			{
+				Fail("Camellia failed initialisation - " + e.ToString(), e);
+			}
+
+			try
+			{
+				inCipher.Init(false, key);
+			}
+			catch (Exception e)
+			{
+				Fail("Camellia failed initialisation - " + e.ToString(), e);
+			}
+
+			//
+			// encryption pass
+			//
+			MemoryStream bOut = new MemoryStream();
+			CipherStream cOut = new CipherStream(bOut, null, outCipher);
+
+			try
+			{
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+					cOut.WriteByte(input[i]);
+				}
+				cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+				cOut.Close();
+			}
+			catch (IOException e)
+			{
+				Fail("Camellia failed encryption - " + e.ToString(), e);
+			}
+
+			byte[] bytes = bOut.ToArray();
+
+			if (!AreEqual(bytes, output))
+			{
+				Fail("Camellia failed encryption - expected "
+					+ Hex.ToHexString(output) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+
+			//
+			// decryption pass
+			//
+			MemoryStream bIn = new MemoryStream(bytes, false);
+			CipherStream cIn = new CipherStream(bIn, inCipher, null);
+
+			try
+			{
+//				DataInputStream dIn = new DataInputStream(cIn);
+				BinaryReader dIn = new BinaryReader(cIn);
+
+				bytes = new byte[input.Length];
+
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+//					bytes[i] = (byte)dIn.read();
+					bytes[i] = dIn.ReadByte();
+				}
+
+				int remaining = bytes.Length - input.Length / 2;
+//				dIn.readFully(bytes, input.Length / 2, remaining);
+				byte[] extra = dIn.ReadBytes(remaining);
+				if (extra.Length < remaining)
+					throw new EndOfStreamException();
+				extra.CopyTo(bytes, input.Length / 2);
+			}
+			catch (Exception e)
+			{
+				Fail("Camellia failed encryption - " + e.ToString(), e);
+			}
+
+			if (!AreEqual(bytes, input))
+			{
+				Fail("Camellia failed decryption - expected "
+					+ Hex.ToHexString(input) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+		}
+
+		public override void PerformTest()
+		{
+			TestCiphers();
+			TestWrap();
+			TestOids();
+			TestWrapOids();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CamelliaTest());
+		}
+	}
+}
diff --git a/crypto/test/src/test/CertPathBuilderTest.cs b/crypto/test/src/test/CertPathBuilderTest.cs
new file mode 100644
index 000000000..e31bde866
--- /dev/null
+++ b/crypto/test/src/test/CertPathBuilderTest.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkix;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class CertPathBuilderTest
+        : SimpleTest
+    {
+        private void baseTest()
+        {
+//			CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
+            X509CertificateParser certParser = new X509CertificateParser();
+            X509CrlParser crlParser = new X509CrlParser();
+
+            // initialise CertStore
+            X509Certificate rootCert = certParser.ReadCertificate(CertPathTest.rootCertBin);
+            X509Certificate interCert = certParser.ReadCertificate(CertPathTest.interCertBin);
+            X509Certificate finalCert = certParser.ReadCertificate(CertPathTest.finalCertBin);
+            X509Crl rootCrl = crlParser.ReadCrl(CertPathTest.rootCrlBin);
+            X509Crl interCrl = crlParser.ReadCrl(CertPathTest.interCrlBin);
+
+            IList certList = new ArrayList();
+            certList.Add(rootCert);
+            certList.Add(interCert);
+            certList.Add(finalCert);
+
+            IList crlList = new ArrayList();
+            crlList.Add(rootCrl);
+            crlList.Add(interCrl);
+
+//			CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list);
+//			CertStore store = CertStore.getInstance("Collection", ccsp, "BC");
+            IX509Store x509CertStore = X509StoreFactory.Create(
+                "Certificate/Collection",
+                new X509CollectionStoreParameters(certList));
+            IX509Store x509CrlStore = X509StoreFactory.Create(
+                "CRL/Collection",
+                new X509CollectionStoreParameters(crlList));
+
+            // NB: Month is 1-based in .NET
+            //DateTime validDate = new DateTime(2008, 9, 4, 14, 49, 10).ToUniversalTime();
+            DateTime validDate = new DateTime(2008, 9, 4, 5, 49, 10);
+
+            //Searching for rootCert by subjectDN without CRL
+            ISet trust = new HashSet();
+            trust.Add(new TrustAnchor(rootCert, null));
+
+//			CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX","BC");
+            PkixCertPathBuilder cpb = new PkixCertPathBuilder();
+            X509CertStoreSelector targetConstraints = new X509CertStoreSelector();
+            targetConstraints.Subject = finalCert.SubjectDN;
+            PkixBuilderParameters parameters = new PkixBuilderParameters(trust, targetConstraints);
+//			parameters.addCertStore(store);
+            parameters.AddStore(x509CertStore);
+            parameters.AddStore(x509CrlStore);
+            parameters.Date = new DateTimeObject(validDate);
+            PkixCertPathBuilderResult result = cpb.Build(parameters);
+            PkixCertPath path = result.CertPath;
+
+            if (path.Certificates.Count != 2)
+            {
+                Fail("wrong number of certs in baseTest path");
+            }
+        }
+
+        private void v0Test()
+        {
+            // create certificates and CRLs
+            AsymmetricCipherKeyPair rootPair = TestUtilities.GenerateRsaKeyPair();
+            AsymmetricCipherKeyPair interPair = TestUtilities.GenerateRsaKeyPair();
+            AsymmetricCipherKeyPair endPair = TestUtilities.GenerateRsaKeyPair();
+
+            X509Certificate rootCert = TestUtilities.GenerateRootCert(rootPair);
+            X509Certificate interCert = TestUtilities.GenerateIntermediateCert(interPair.Public, rootPair.Private, rootCert);
+            X509Certificate endCert = TestUtilities.GenerateEndEntityCert(endPair.Public, interPair.Private, interCert);
+
+            BigInteger revokedSerialNumber = BigInteger.Two;
+            X509Crl rootCRL = TestUtilities.CreateCrl(rootCert, rootPair.Private, revokedSerialNumber);
+            X509Crl interCRL = TestUtilities.CreateCrl(interCert, interPair.Private, revokedSerialNumber);
+
+            // create CertStore to support path building
+            IList certList = new ArrayList();
+            certList.Add(rootCert);
+            certList.Add(interCert);
+            certList.Add(endCert);
+
+            IList crlList = new ArrayList();
+            crlList.Add(rootCRL);
+            crlList.Add(interCRL);
+
+//			CollectionCertStoreParameters parameters = new CollectionCertStoreParameters(list);
+//			CertStore                     store = CertStore.getInstance("Collection", parameters);
+            IX509Store x509CertStore = X509StoreFactory.Create(
+                "Certificate/Collection",
+                new X509CollectionStoreParameters(certList));
+            IX509Store x509CrlStore = X509StoreFactory.Create(
+                "CRL/Collection",
+                new X509CollectionStoreParameters(crlList));
+
+            ISet trust = new HashSet();
+            trust.Add(new TrustAnchor(rootCert, null));
+
+            // build the path
+//			CertPathBuilder  builder = CertPathBuilder.getInstance("PKIX", "BC");
+            PkixCertPathBuilder builder = new PkixCertPathBuilder();
+            X509CertStoreSelector pathConstraints = new X509CertStoreSelector();
+
+            pathConstraints.Subject = endCert.SubjectDN;
+
+            PkixBuilderParameters buildParams = new PkixBuilderParameters(trust, pathConstraints);
+//			buildParams.addCertStore(store);
+            buildParams.AddStore(x509CertStore);
+            buildParams.AddStore(x509CrlStore);
+
+            buildParams.Date = new DateTimeObject(DateTime.UtcNow);
+
+            PkixCertPathBuilderResult result = builder.Build(buildParams);
+            PkixCertPath path = result.CertPath;
+
+            if (path.Certificates.Count != 2)
+            {
+                Fail("wrong number of certs in v0Test path");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            baseTest();
+            v0Test();
+        }
+        
+        public override string Name
+        {
+            get { return "CertPathBuilder"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new CertPathBuilderTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/CertPathTest.cs b/crypto/test/src/test/CertPathTest.cs
new file mode 100644
index 000000000..f1a7c94f6
--- /dev/null
+++ b/crypto/test/src/test/CertPathTest.cs
@@ -0,0 +1,359 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkix;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class CertPathTest
+		: SimpleTest
+	{
+		internal static readonly byte[] rootCertBin = Base64.Decode(
+			"MIIBqzCCARQCAQEwDQYJKoZIhvcNAQEFBQAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRLUjhPe4YUdLo6EcjKcWUOG7CydFTH53Pr1lWjOkbmszYDpkhCTT9LOsI+disk18nkBxSl8DAHTqV+VxtuTPt64iyi10YxyDeep+DwZG/f8cVQv97U3hA9cLurZ2CofkMLGr6JpSGCMZ9FcstcTdHB4lbErIJ54YqfF4pNOs4/AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAgyrTEFY7ALpeY59jL6xFOLpuPqoBOWrUWv6O+zy5BCU0qiX71r3BpigtxRj+DYcfLIM9FNERDoHu3TthD3nwYWUBtFX8N0QUJIdJabxqAMhLjSC744koiFpCYse5Ye3ZvEdFwDzgAQsJTp5eFGgTZPkPzcdhkFJ2p9+OWs+cb24=");
+		internal static readonly byte[] interCertBin = Base64.Decode(
+			"MIICSzCCAbSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlMB4XDTA4MDkwNDA0NDUwOFoXDTA4MDkxMTA0NDUwOFowKDEmMCQGA1UEAxMdVGVzdCBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAISS9OOZ2wxzdWny9aVvk4Joq+dwSJ+oqvHUxX3PflZyuiLiCBUOUE4q59dGKdtNX5fIfwyK3cpV0e73Y/0fwfM3m9rOWFrCKOhfeswNTes0w/2PqPVVDDsF/nj7NApuqXwioeQlgTL251RDF4sVoxXqAU7lRkcqwZt3mwqS4KTJAgMBAAGjgY4wgYswRgYDVR0jBD8wPYAUhv8BOT27EB9JaCccJD4YASPP5XWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwHQYDVR0OBBYEFL/IwAGOkHzaQyPZegy79CwM5oTFMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4GBAE4TRgUz4sUvZyVdZxqV+XyNRnqXAeLOOqFGYv2D96tQrS+zjd0elVlT6lFrtchZdOmmX7R6/H/tjMWMcTBICZyRYrvK8cCAmDOI+EIdq5p6lj2Oq6Pbw/wruojAqNrpaR6IkwNpWtdOSSupv4IJL+YU9q2YFTh4R1j3tOkPoFGr");
+		internal static readonly byte[] finalCertBin = Base64.Decode(
+			"MIICRjCCAa+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB8xHTAbBgNVBAMTFFRlc3QgRW5kIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChpUeo0tPYywWKiLlbWKNJBcCpSaLSlaZ+4+yer1AxI5yJIVHP6SAlBghlbD5Qne5ImnN/15cz1xwYAiul6vGKJkVPlFEe2Mr+g/J/WJPQQPsjbZ1G+vxbAwXEDA4KaQrnpjRZFq+CdKHwOjuPLYS/MYQNgdIvDVEQcTbPQ8GaiQIDAQABo4GIMIGFMEYGA1UdIwQ/MD2AFL/IwAGOkHzaQyPZegy79CwM5oTFoSKkIDAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlggEBMB0GA1UdDgQWBBSVkw+VpqBf3zsLc/9GdkK9TzHPwDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDANBgkqhkiG9w0BAQUFAAOBgQBLv/0bVDjzTs/y1vN3FUiZNknEbzupIZduTuXJjqv/vBX+LDPjUfu/+iOCXOSKoRn6nlOWhwB1z6taG2usQkFG8InMkRcPREi2uVgFdhJ/1C3dAWhsdlubjdL926bftXvxnx/koDzyrePW5U96RlOQM2qLvbaky2Giz6hrc3Wl+w==");
+		internal static readonly byte[] rootCrlBin = Base64.Decode(
+			"MIIBYjCBzAIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlFw0wODA5MDQwNDQ1MDhaFw0wODA5MDQwNzMxNDhaMCIwIAIBAhcNMDgwOTA0MDQ0NTA4WjAMMAoGA1UdFQQDCgEJoFYwVDBGBgNVHSMEPzA9gBSG/wE5PbsQH0loJxwkPhgBI8/ldaEipCAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZYIBATAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOBgQCAbaFCo0BNG4AktVf6jjBLeawP1u0ELYkOCEGvYZE0mBpQ+OvFg7subZ6r3lRIj030nUli28sPFtu5ZQMBNcpE4nS1ziF44RfT3Lp5UgHx9x17Krz781iEyV+7zU8YxYMY9wULD+DCuK294kGKIssVNbmTYXZatBNoXQN5CLIocA==");
+		internal static readonly byte[] interCrlBin = Base64.Decode(
+			"MIIBbDCB1gIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZRcNMDgwOTA0MDQ0NTA4WhcNMDgwOTA0MDczMTQ4WjAiMCACAQIXDTA4MDkwNDA0NDUwOFowDDAKBgNVHRUEAwoBCaBWMFQwRgYDVR0jBD8wPYAUv8jAAY6QfNpDI9l6DLv0LAzmhMWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADgYEAEVCr5TKs5yguGgLH+dBzmSPoeSIWJFLsgWwJEit/iUDJH3dgYmaczOcGxIDtbYYHLWIHM+P2YRyQz3MEkCXEgm/cx4y7leAmux5l+xQWgmxFPz+197vaphPeCZo+B7V1CWtm518gcq4mrs9ovfgNqgyFj7KGjcBpWdJE32KMt50=");
+
+		/*
+		 * certpath with a circular reference
+		 */
+		internal static readonly byte[] certA = Base64.Decode(
+			"MIIC6jCCAlOgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBjTEPMA0GA1UEAxMGSW50"
+			+ "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+			+ "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+			+ "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2NTda"
+			+ "Fw0xNzAzMzAwODQ0MDBaMIGlMScwJQYDVQQDHh4AQQByAG0AaQBuACAASADkAGIA"
+			+ "ZQByAGwAaQBuAGcxCzAJBgNVBAYTAkNIMQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNV"
+			+ "BAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNwaGVyZSBBRzEQMA4GA1UECxMHVGVzdGlu"
+			+ "ZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5AcHJpdmFzcGhlcmUuY29tMIGfMA0GCSqG"
+			+ "SIb3DQEBAQUAA4GNADCBiQKBgQCfHfyVs5dbxG35H/Thd29qR4NZU88taCu/OWA1"
+			+ "GdACI02lXWYpmLWiDgnU0ULP+GG8OnVp1IES9fz2zcrXKQ19xZzsen/To3h5sNte"
+			+ "cJpS00XMM24q/jDwy5NvkBP9YIfFKQ1E/0hFHXcqwlw+b/y/v6YGsZCU2h6QDzc4"
+			+ "5m0+BwIDAQABo0AwPjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DAeBglg"
+			+ "hkgBhvhCAQ0EERYPeGNhIGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4GBAJEu"
+			+ "KiSfIwsY7SfobMLrv2v/BtLhGLi4RnmjiwzBhuv5rn4rRfBpq1ppmqQMJ2pmA67v"
+			+ "UWCY+mNwuyjHyivpCCyJGsZ9d5H09g2vqxzkDBMz7X9VNMZYFH8j/R3/Cfvqks31"
+			+ "z0OFslJkeKLa1I0P/dfVHsRKNkLRT3Ws5LKksErQ");
+
+		internal static readonly byte[] certB = Base64.Decode(
+			"MIICtTCCAh6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+			+ "ZXIyMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+			+ "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+			+ "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2Mzha"
+			+ "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjMxCzAJBgNVBAYTAkNI"
+			+ "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+			+ "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+			+ "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxCXIB"
+			+ "QRnmVvl2h7Q+0SsRxDLnyM1dJG9jMa+UCCmHy0k/ZHs5VirSbjEJSjkQ9BGeh9SC"
+			+ "7JwbMpXO7UE+gcVc2RnWUY+MA+fWIeTV4KtkYA8WPu8wVGCXbN8wwh/StOocszxb"
+			+ "g+iLvGeh8CYSRqg6QN3S/02etH3o8H4e7Z0PZwIDAQABoyMwITAPBgNVHRMBAf8E"
+			+ "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCtWdirSsmt"
+			+ "+CBBCNn6ZnbU3QqQfiiQIomjenNEHESJgaS/+PvPE5i3xWFXsunTHLW321/Km16I"
+			+ "7+ZvT8Su1cqHg79NAT8QB0yke1saKSy2C0Pic4HwrNqVBWFNSxMU0hQzpx/ZXDbZ"
+			+ "DqIXAp5EfyRYBy2ul+jm6Rot6aFgzuopKg==");
+
+		internal static readonly byte[] certC = Base64.Decode(
+			"MIICtTCCAh6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+			+ "ZXIxMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+			+ "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+			+ "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ0Mzla"
+			+ "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjIxCzAJBgNVBAYTAkNI"
+			+ "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+			+ "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+			+ "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0rLr6"
+			+ "f2/ONeJzTb0q9M/NNX+MnAFMSqiQGVBkT76u5nOH4KLkpHXkzI82JI7GuQMzoT3a"
+			+ "+RP1hO6FneO92ms2soC6xiOFb4EC69Dfhh87Nww5O35JxVF0bzmbmIAWd6P/7zGh"
+			+ "nd2S4tKkaZcubps+C0j9Fgi0hipVicAOUVVoDQIDAQABoyMwITAPBgNVHRMBAf8E"
+			+ "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCLPvc1IMA4"
+			+ "YP+PmnEldyUoRWRnvPWjBGeu0WheBP7fdcnGBf93Nmc5j68ZN+eTZ5VMuZ99YdvH"
+			+ "CXGNX6oodONLU//LlFKdLl5xjLAS5X9p1RbOEGytnalqeiEpjk4+C/7rIBG1kllO"
+			+ "dItmI6LlEMV09Hkpg6ZRAUmRkb8KrM4X7A==");
+
+		internal static readonly byte[] certD = Base64.Decode(
+			"MIICtTCCAh6gAwIBAgIBBjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50"
+			+ "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX"
+			+ "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq"
+			+ "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ5NTNa"
+			+ "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjExCzAJBgNVBAYTAkNI"
+			+ "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw"
+			+ "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A"
+			+ "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCae3TP"
+			+ "jIVKeASqvNabaiUHAMGUgFxB7L0yUsIj39azLcLtUj4S7XkDf7SMGtYV0JY1XNaQ"
+			+ "sHJAsnJivDZc50oiYvqDYfgFZx5+AsN5l5X5rjRzs/OX+Jo+k1OgsIyu6+mf9Kfb"
+			+ "5IdWOVB2EcOg4f9tPjLM8CIj9Pp7RbKLyqUUgwIDAQABoyMwITAPBgNVHRMBAf8E"
+			+ "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCgr9kUdWUT"
+			+ "Lt9UcztSzR3pnHRsyvS0E/z850OKQKS5/VxLEalpFvhj+3EcZ7Y6mFxaaS2B7vXg"
+			+ "2YWyqV1PRb6iF7/u9EXkpSTKGrJahwANirCa3V/HTUuPdCE2GITlnWI8h3eVA+xQ"
+			+ "D4LF0PXHOkXbwmhXRSb10lW1bSGkUxE9jg==");
+
+		private void doTestExceptions()
+		{
+			byte[] enc = { (byte)0, (byte)2, (byte)3, (byte)4, (byte)5 };
+//			MyCertPath mc = new MyCertPath(enc);
+			MemoryStream os = new MemoryStream();
+			MemoryStream ins;
+			byte[] arr;
+
+			// TODO Support serialization of cert paths?
+//			ObjectOutputStream oos = new ObjectOutputStream(os);
+//			oos.WriteObject(mc);
+//			oos.Flush();
+//			oos.Close();
+
+			try
+			{
+//				CertificateFactory cFac = CertificateFactory.GetInstance("X.509");
+				arr = os.ToArray();
+				ins = new MemoryStream(arr, false);
+//				cFac.generateCertPath(ins);
+				new PkixCertPath(ins);
+			}
+			catch (CertificateException)
+			{
+				// ignore okay
+			}
+
+//			CertificateFactory cf = CertificateFactory.GetInstance("X.509");
+			X509CertificateParser cf = new X509CertificateParser();
+			IList certCol = new ArrayList();
+
+			certCol.Add(cf.ReadCertificate(certA));
+			certCol.Add(cf.ReadCertificate(certB));
+			certCol.Add(cf.ReadCertificate(certC));
+			certCol.Add(cf.ReadCertificate(certD));
+
+//			CertPathBuilder pathBuilder = CertPathBuilder.GetInstance("PKIX");
+			PkixCertPathBuilder pathBuilder = new PkixCertPathBuilder();
+			X509CertStoreSelector select = new X509CertStoreSelector();
+			select.Subject = ((X509Certificate)certCol[0]).SubjectDN;
+
+			ISet trustanchors = new HashSet();
+			trustanchors.Add(new TrustAnchor(cf.ReadCertificate(rootCertBin), null));
+
+//			CertStore certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certCol));
+			IX509Store x509CertStore = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certCol));
+
+			PkixBuilderParameters parameters = new PkixBuilderParameters(trustanchors, select);
+			parameters.AddStore(x509CertStore);
+
+			try
+			{
+				PkixCertPathBuilderResult result = pathBuilder.Build(parameters);
+				PkixCertPath path = result.CertPath;
+				Fail("found cert path in circular set");
+			}
+			catch (PkixCertPathBuilderException)
+			{
+				// expected
+			}
+		}
+
+		public override void PerformTest()
+		{
+			X509CertificateParser cf = new X509CertificateParser();
+
+			X509Certificate rootCert = cf.ReadCertificate(rootCertBin);
+			X509Certificate interCert = cf.ReadCertificate(interCertBin);
+			X509Certificate finalCert = cf.ReadCertificate(finalCertBin);
+
+			//Testing CertPath generation from List
+			IList list = new ArrayList();
+			list.Add(interCert);
+//			CertPath certPath1 = cf.generateCertPath(list);
+			PkixCertPath certPath1 = new PkixCertPath(list);
+
+			//Testing CertPath encoding as PkiPath
+			byte[] encoded = certPath1.GetEncoded("PkiPath");
+
+			//Testing CertPath generation from InputStream
+			MemoryStream inStream = new MemoryStream(encoded, false);
+//			CertPath certPath2 = cf.generateCertPath(inStream, "PkiPath");
+			PkixCertPath certPath2 = new PkixCertPath(inStream, "PkiPath");
+
+			//Comparing both CertPathes
+			if (!certPath2.Equals(certPath1))
+			{
+				Fail("CertPath differ after encoding and decoding.");
+			}
+
+			encoded = certPath1.GetEncoded("PKCS7");
+
+			//Testing CertPath generation from InputStream
+			inStream = new MemoryStream(encoded, false);
+//			certPath2 = cf.generateCertPath(inStream, "PKCS7");
+			certPath2 = new PkixCertPath(inStream, "PKCS7");
+
+			//Comparing both CertPathes
+			if (!certPath2.Equals(certPath1))
+			{
+				Fail("CertPath differ after encoding and decoding.");
+			}
+
+			encoded = certPath1.GetEncoded("PEM");
+
+			//Testing CertPath generation from InputStream
+			inStream = new MemoryStream(encoded, false);
+//			certPath2 = cf.generateCertPath(inStream, "PEM");
+			certPath2 = new PkixCertPath(inStream, "PEM");
+
+			//Comparing both CertPathes
+			if (!certPath2.Equals(certPath1))
+			{
+				Fail("CertPath differ after encoding and decoding.");
+			}
+
+			//
+			// empty list test
+			//
+			list = new ArrayList();
+
+//			CertPath certPath = CertificateFactory.GetInstance("X.509","BC").generateCertPath(list);
+			PkixCertPath certPath = new PkixCertPath(list);
+			if (certPath.Certificates.Count != 0)
+			{
+				Fail("list wrong size.");
+			}
+
+			//
+			// exception tests
+			//
+			doTestExceptions();
+		}
+
+		public override string Name
+		{
+			get { return "CertPath"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CertPathTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+
+//		private class MyCertificate : X509Certificate
+//		{
+//			private readonly string type;
+//			private readonly byte[] encoding;
+//
+//			public MyCertificate(string type, byte[] encoding)
+////				: base(type)
+//			{
+//				this.type = type;
+//
+//				// don't copy to allow null parameter in test
+//				this.encoding = encoding;
+//			}
+//
+//			public override byte[] GetEncoded()
+//			{
+//				// do copy to force NPE in test
+//				return (byte[])encoding.Clone();
+//			}
+//
+//			public override void Verify(AsymmetricKeyParameter publicKey)
+//			{
+//			}
+//
+//			public override string ToString()
+//			{
+//				return "[My test Certificate, type: " + type + "]";
+//			}
+//
+//			public override AsymmetricKeyParameter GetPublicKey()
+//			{
+//				throw new NotImplementedException();
+//
+////            return new PublicKey()
+////            {
+////                public string getAlgorithm()
+////                {
+////                    return "TEST";
+////                }
+////
+////                public byte[] getEncoded()
+////                {
+////                    return new byte[] { (byte)1, (byte)2, (byte)3 };
+////                }
+////
+////                public string getFormat()
+////                {
+////                    return "TEST_FORMAT";
+////                }
+////            };
+//			}
+//		}
+
+//		private class MyCertPath : PkixCertPath
+//		{
+//			private readonly ArrayList certificates;
+//
+//			private readonly ArrayList encodingNames;
+//
+//			private readonly byte[] encoding;
+//
+//			public MyCertPath(byte[] encoding)
+//				: base("MyEncoding")
+//			{
+//				this.encoding = encoding;
+//				certificates = new ArrayList();
+//				certificates.Add(new MyCertificate("MyEncoding", encoding));
+//				encodingNames = new ArrayList();
+//				encodingNames.Add("MyEncoding");
+//			}
+//
+//			public override IList Certificates
+//			{
+//				get { return CollectionUtilities.ReadOnly(certificates); }
+//			}
+//
+//			public override byte[] GetEncoded()
+//			{
+//				return (byte[])encoding.Clone();
+//			}
+//
+//			public override byte[] GetEncoded(
+//				string encoding)
+//			{
+//				if (Type.Equals(encoding))
+//				{
+//					return (byte[])this.encoding.Clone();
+//				}
+//				throw new CertificateEncodingException("Encoding not supported: "
+//					+ encoding);
+//			}
+//
+//			public override IEnumerable Encodings
+//			{
+//				get { return new EnumerableProxy(encodingNames); }
+//			}
+//		}
+	}
+}
diff --git a/crypto/test/src/test/CertPathValidatorTest.cs b/crypto/test/src/test/CertPathValidatorTest.cs
new file mode 100644
index 000000000..a92bb9b31
--- /dev/null
+++ b/crypto/test/src/test/CertPathValidatorTest.cs
@@ -0,0 +1,304 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkix;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class CertPathValidatorTest
+        : SimpleTest
+    {
+        private byte[] AC_PR = Base64.Decode(
+            "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlFU1RDQ0F6R2dBd0lC"
+            + "QWdJQkJUQU5CZ2txaGtpRzl3MEJBUVVGQURDQnRERUxNQWtHQTFVRUJoTUNR"
+            + "bEl4DQpFekFSQmdOVkJBb1RDa2xEVUMxQ2NtRnphV3d4UFRBN0JnTlZCQXNU"
+            + "TkVsdWMzUnBkSFYwYnlCT1lXTnBiMjVoDQpiQ0JrWlNCVVpXTnViMnh2WjJs"
+            + "aElHUmhJRWx1Wm05eWJXRmpZVzhnTFNCSlZFa3hFVEFQQmdOVkJBY1RDRUp5"
+            + "DQpZWE5wYkdsaE1Rc3dDUVlEVlFRSUV3SkVSakV4TUM4R0ExVUVBeE1vUVhW"
+            + "MGIzSnBaR0ZrWlNCRFpYSjBhV1pwDQpZMkZrYjNKaElGSmhhWG9nUW5KaGMy"
+            + "bHNaV2x5WVRBZUZ3MHdNakEwTURReE9UTTVNREJhRncwd05UQTBNRFF5DQpN"
+            + "elU1TURCYU1HRXhDekFKQmdOVkJBWVRBa0pTTVJNd0VRWURWUVFLRXdwSlEx"
+            + "QXRRbkpoYzJsc01UMHdPd1lEDQpWUVFERXpSQmRYUnZjbWxrWVdSbElFTmxj"
+            + "blJwWm1sallXUnZjbUVnWkdFZ1VISmxjMmxrWlc1amFXRWdaR0VnDQpVbVZ3"
+            + "ZFdKc2FXTmhNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJD"
+            + "Z0tDQVFFQXMwc0t5NGsrDQp6b016aldyMTQxeTVYQ045UGJMZERFQXN2cjZ4"
+            + "Z0NCN1l5bEhIQ1NBYmpGR3dOQ0R5NlVxN1h0VjZ6UHdIMXpGDQpFWENlS3Jm"
+            + "UUl5YXBXSEZ4V1VKajBMblFrY1RZM1FOR1huK0JuVk9EVTZDV3M1c3NoZktH"
+            + "RXZyVlQ1Z214V1NmDQp4OFlsdDgzY1dwUE1QZzg3VDlCaHVIbHQzazh2M2Ev"
+            + "NmRPbmF2dytOYTAyZExBaDBlNzZqcCtQUS9LK0pHZlBuDQphQjVVWURrZkd0"
+            + "em5uTTNBV01tY3VJK0o0ek5OMDZaa3ZnbDFsdEo2UU1qcnZEUFlSak9ndDlT"
+            + "cklpY1NmbEo4DQptVDdHWGRRaXJnQUNXc3g1QURBSklRK253TU1vNHlyTUtx"
+            + "SlFhNFFDMHhhT0QvdkdVcG9SaDQzT0FTZFp3c3YvDQpPWFlybmVJeVAwVCs4"
+            + "UUlEQVFBQm80RzNNSUcwTUQwR0ExVWRId1EyTURRd01xQXdvQzZHTEdoMGRI"
+            + "QTZMeTloDQpZM0poYVhvdWFXTndZbkpoYzJsc0xtZHZkaTVpY2k5TVExSmhZ"
+            + "M0poYVhvdVkzSnNNQklHQTFVZElBUUxNQWt3DQpCd1lGWUV3QkFRRXdIUVlE"
+            + "VlIwT0JCWUVGREpUVFlKNE9TWVB5T09KZkVMZXhDaHppK2hiTUI4R0ExVWRJ"
+            + "d1FZDQpNQmFBRklyNjhWZUVFUk0xa0VMNlYwbFVhUTJreFBBM01BNEdBMVVk"
+            + "RHdFQi93UUVBd0lCQmpBUEJnTlZIUk1CDQpBZjhFQlRBREFRSC9NQTBHQ1Nx"
+            + "R1NJYjNEUUVCQlFVQUE0SUJBUUJRUFNoZ1lidnFjaWV2SDVVb3ZMeXhkbkYr"
+            + "DQpFcjlOeXF1SWNkMnZ3Y0N1SnpKMkQ3WDBUcWhHQ0JmUEpVVkdBVWorS0NP"
+            + "SDFCVkgva1l1OUhsVHB1MGtKWFBwDQpBQlZkb2hJUERqRHhkbjhXcFFSL0Yr"
+            + "ejFDaWtVcldIMDR4eTd1N1p6UUpLSlBuR0loY1FpOElyRm1PYkllMEc3DQpY"
+            + "WTZPTjdPRUZxY21KTFFHWWdtRzFXMklXcytQd1JwWTdENGhLVEFoVjFSNkVv"
+            + "amE1L3BPcmVDL09kZXlQWmVxDQo1SUZTOUZZZk02U0Npd2hrK3l2Q1FHbVo0"
+            + "YzE5SjM0ZjVFYkRrK1NQR2tEK25EQ0E3L3VMUWNUMlJURE14SzBaDQpuZlo2"
+            + "Nm1Sc0ZjcXRGaWdScjVFcmtKZDdoUVV6eHNOV0VrNzJEVUFIcVgvNlNjeWtt"
+            + "SkR2V0plSUpqZlcNCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0NCg==");
+
+        private byte[] AC_RAIZ_ICPBRASIL = Base64.Decode(
+            "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlFdURDQ0E2Q2dBd0lC"
+            + "QWdJQkJEQU5CZ2txaGtpRzl3MEJBUVVGQURDQnRERUxNQWtHQTFVRUJoTUNR"
+            + "bEl4DQpFekFSQmdOVkJBb1RDa2xEVUMxQ2NtRnphV3d4UFRBN0JnTlZCQXNU"
+            + "TkVsdWMzUnBkSFYwYnlCT1lXTnBiMjVoDQpiQ0JrWlNCVVpXTnViMnh2WjJs"
+            + "aElHUmhJRWx1Wm05eWJXRmpZVzhnTFNCSlZFa3hFVEFQQmdOVkJBY1RDRUp5"
+            + "DQpZWE5wYkdsaE1Rc3dDUVlEVlFRSUV3SkVSakV4TUM4R0ExVUVBeE1vUVhW"
+            + "MGIzSnBaR0ZrWlNCRFpYSjBhV1pwDQpZMkZrYjNKaElGSmhhWG9nUW5KaGMy"
+            + "bHNaV2x5WVRBZUZ3MHdNVEV4TXpBeE1qVTRNREJhRncweE1URXhNekF5DQpN"
+            + "elU1TURCYU1JRzBNUXN3Q1FZRFZRUUdFd0pDVWpFVE1CRUdBMVVFQ2hNS1NV"
+            + "TlFMVUp5WVhOcGJERTlNRHNHDQpBMVVFQ3hNMFNXNXpkR2wwZFhSdklFNWhZ"
+            + "Mmx2Ym1Gc0lHUmxJRlJsWTI1dmJHOW5hV0VnWkdFZ1NXNW1iM0p0DQpZV05o"
+            + "YnlBdElFbFVTVEVSTUE4R0ExVUVCeE1JUW5KaGMybHNhV0V4Q3pBSkJnTlZC"
+            + "QWdUQWtSR01URXdMd1lEDQpWUVFERXloQmRYUnZjbWxrWVdSbElFTmxjblJw"
+            + "Wm1sallXUnZjbUVnVW1GcGVpQkNjbUZ6YVd4bGFYSmhNSUlCDQpJakFOQmdr"
+            + "cWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBd1BNdWR3WC9odm0r"
+            + "VWgyYi9sUUFjSFZBDQppc2FtYUxrV2Rrd1A5L1MvdE9LSWdSckw2T3krWklH"
+            + "bE9VZGQ2dVl0azlNYS8zcFVwZ2NmTkFqMHZZbTVnc3lqDQpRbzllbXNjK3g2"
+            + "bTRWV3drOWlxTVpTQ0s1RVFrQXEvVXQ0bjdLdUxFMStnZGZ0d2RJZ3hmVXNQ"
+            + "dDRDeU5yWTUwDQpRVjU3S00yVVQ4eDVycm16RWpyN1RJQ0dwU1VBbDJnVnFl"
+            + "NnhhaWkrYm1ZUjFRcm1XYUJTQUc1OUxya3Jqcll0DQpiUmhGYm9VRGUxREsr"
+            + "NlQ4czVMNms4Yzhva3BiSHBhOXZlTXp0RFZDOXNQSjYwTVdYaDZhblZLbzFV"
+            + "Y0xjYlVSDQp5RWVOdlpuZVZSS0FBVTZvdXdkakR2d2xzYUt5ZEZLd2VkMFRv"
+            + "UTQ3Ym1VS2djbSt3VjNlVFJrMzZVT25Ud0lEDQpBUUFCbzRIU01JSFBNRTRH"
+            + "QTFVZElBUkhNRVV3UXdZRllFd0JBUUF3T2pBNEJnZ3JCZ0VGQlFjQ0FSWXNh"
+            + "SFIwDQpjRG92TDJGamNtRnBlaTVwWTNCaWNtRnphV3d1WjI5MkxtSnlMMFJR"
+            + "UTJGamNtRnBlaTV3WkdZd1BRWURWUjBmDQpCRFl3TkRBeW9EQ2dMb1lzYUhS"
+            + "MGNEb3ZMMkZqY21GcGVpNXBZM0JpY21GemFXd3VaMjkyTG1KeUwweERVbUZq"
+            + "DQpjbUZwZWk1amNtd3dIUVlEVlIwT0JCWUVGSXI2OFZlRUVSTTFrRUw2VjBs"
+            + "VWFRMmt4UEEzTUE4R0ExVWRFd0VCDQovd1FGTUFNQkFmOHdEZ1lEVlIwUEFR"
+            + "SC9CQVFEQWdFR01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQVpBNWMxDQpV"
+            + "L2hnSWg2T2NnTEFmaUpnRldwdm1EWldxbFYzMC9iSEZwajhpQm9iSlNtNXVE"
+            + "cHQ3VGlyWWgxVXhlM2ZRYUdsDQpZakplKzl6ZCtpelBSYkJxWFBWUUEzNEVY"
+            + "Y3drNHFwV3VmMWhIcmlXZmRyeDhBY3FTcXI2Q3VRRndTcjc1Rm9zDQpTemx3"
+            + "REFEYTcwbVQ3d1pqQW1RaG5aeDJ4SjZ3ZldsVDlWUWZTLy9KWWVJYzdGdWUy"
+            + "Sk5MZDAwVU9TTU1haUsvDQp0NzllbktOSEVBMmZ1cEgzdkVpZ2Y1RWg0YlZB"
+            + "TjVWb2hyVG02TVk1M3g3WFFaWnIxTUU3YTU1bEZFblNlVDB1DQptbE9BalIy"
+            + "bUFidlNNNVg1b1NaTnJtZXRkenlUajJmbENNOENDN01MYWIwa2tkbmdSSWxV"
+            + "QkdIRjEvUzVubVBiDQpLKzlBNDZzZDMzb3FLOG44DQotLS0tLUVORCBDRVJU"
+            + "SUZJQ0FURS0tLS0tDQo=");
+
+        private byte[] schefer = Base64.Decode(
+            "MIIEnDCCBAWgAwIBAgICIPAwDQYJKoZIhvcNAQEEBQAwgcAxCzAJBgNVBAYT"
+            + "AkRFMQ8wDQYDVQQIEwZIRVNTRU4xGDAWBgNVBAcTDzY1MDA4IFdpZXNiYWRl"
+            + "bjEaMBgGA1UEChMRU0NIVUZBIEhPTERJTkcgQUcxGjAYBgNVBAsTEVNDSFVG"
+            + "QSBIT0xESU5HIEFHMSIwIAYDVQQDExlJbnRlcm5ldCBCZW51dHplciBTZXJ2"
+            + "aWNlMSowKAYJKoZIhvcNAQkBFht6ZXJ0aWZpa2F0QHNjaHVmYS1vbmxpbmUu"
+            + "ZGUwHhcNMDQwMzMwMTEwODAzWhcNMDUwMzMwMTEwODAzWjCBnTELMAkGA1UE"
+            + "BhMCREUxCjAIBgNVBAcTASAxIzAhBgNVBAoTGlNIUyBJbmZvcm1hdGlvbnNz"
+            + "eXN0ZW1lIEFHMRwwGgYDVQQLExM2MDAvMDU5NDktNjAwLzA1OTQ5MRgwFgYD"
+            + "VQQDEw9TY2hldHRlciBTdGVmYW4xJTAjBgkqhkiG9w0BCQEWFlN0ZWZhbi5T"
+            + "Y2hldHRlckBzaHMuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJD0"
+            + "95Bi76fkAMjJNTGPDiLPHmZXNsmakngDeS0juzKMeJA+TjXFouhYh6QyE4Bl"
+            + "Nf18fT4mInlgLefwf4t6meIWbiseeTo7VQdM+YrbXERMx2uHsRcgZMsiMYHM"
+            + "kVfYMK3SMJ4nhCmZxrBkoTRed4gXzVA1AA8YjjTqMyyjvt4TAgMBAAGjggHE"
+            + "MIIBwDAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIEsDALBgNVHQ8EBAMC"
+            + "BNAwOQYJYIZIAYb4QgENBCwWKlplcnRpZmlrYXQgbnVyIGZ1ZXIgU0NIVUZB"
+            + "LU9ubGluZSBndWVsdGlnLjAdBgNVHQ4EFgQUXReirhBfg0Yhf6MsBWoo/nPa"
+            + "hGwwge0GA1UdIwSB5TCB4oAUf2UyCaBV9JUeG9lS1Yo6OFBUdEKhgcakgcMw"
+            + "gcAxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZIRVNTRU4xGDAWBgNVBAcTDzY1"
+            + "MDA4IFdpZXNiYWRlbjEaMBgGA1UEChMRU0NIVUZBIEhPTERJTkcgQUcxGjAY"
+            + "BgNVBAsTEVNDSFVGQSBIT0xESU5HIEFHMSIwIAYDVQQDExlJbnRlcm5ldCBC"
+            + "ZW51dHplciBTZXJ2aWNlMSowKAYJKoZIhvcNAQkBFht6ZXJ0aWZpa2F0QHNj"
+            + "aHVmYS1vbmxpbmUuZGWCAQAwIQYDVR0RBBowGIEWU3RlZmFuLlNjaGV0dGVy"
+            + "QHNocy5kZTAmBgNVHRIEHzAdgRt6ZXJ0aWZpa2F0QHNjaHVmYS1vbmxpbmUu"
+            + "ZGUwDQYJKoZIhvcNAQEEBQADgYEAWzZtN9XQ9uyrFXqSy3hViYwV751+XZr0"
+            + "YH5IFhIS+9ixNAu8orP3bxqTaMhpwoU7T/oSsyGGSkb3fhzclgUADbA2lrOI"
+            + "GkeB/m+FArTwRbwpqhCNTwZywOp0eDosgPjCX1t53BB/m/2EYkRiYdDGsot0"
+            + "kQPOVGSjQSQ4+/D+TM8=");
+
+        public override void PerformTest()
+        {
+            X509CertificateParser certParser = new X509CertificateParser();
+            X509CrlParser crlParser = new X509CrlParser();
+
+            // initialise CertStore
+            X509Certificate rootCert = certParser.ReadCertificate(CertPathTest.rootCertBin);
+            X509Certificate interCert = certParser.ReadCertificate(CertPathTest.interCertBin);
+            X509Certificate finalCert = certParser.ReadCertificate(CertPathTest.finalCertBin);
+            X509Crl rootCrl = crlParser.ReadCrl(CertPathTest.rootCrlBin);
+            X509Crl interCrl = crlParser.ReadCrl(CertPathTest.interCrlBin);
+
+            IList x509Certs = new ArrayList();
+            x509Certs.Add(rootCert);
+            x509Certs.Add(interCert);
+            x509Certs.Add(finalCert);
+
+            IList x509Crls = new ArrayList();
+            x509Crls.Add(rootCrl);
+            x509Crls.Add(interCrl);
+
+//			CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list);
+//			CertStore store = CertStore.GetInstance("Collection", ccsp);
+//			X509CollectionStoreParameters ccsp = new X509CollectionStoreParameters(list);
+            IX509Store x509CertStore = X509StoreFactory.Create(
+                "Certificate/Collection",
+                new X509CollectionStoreParameters(x509Certs));
+            IX509Store x509CrlStore = X509StoreFactory.Create(
+                "CRL/Collection",
+                new X509CollectionStoreParameters(x509Crls));
+
+            // NB: Month is 1-based in .NET
+            //DateTime validDate = new DateTime(2008,9,4,14,49,10).ToUniversalTime();
+            DateTime validDate = new DateTime(2008, 9, 4, 5, 49, 10);
+
+            //validating path
+            IList certchain = new ArrayList();
+            certchain.Add(finalCert);
+            certchain.Add(interCert);
+//			CertPath cp = CertificateFactory.GetInstance("X.509").GenerateCertPath(certchain);
+            PkixCertPath cp = new PkixCertPath(certchain);
+            ISet trust = new HashSet();
+            trust.Add(new TrustAnchor(rootCert, null));
+
+//			CertPathValidator cpv = CertPathValidator.GetInstance("PKIX");
+            PkixCertPathValidator cpv = new PkixCertPathValidator();
+            PkixParameters param = new PkixParameters(trust);
+            param.AddStore(x509CertStore);
+            param.AddStore(x509CrlStore);
+            param.Date = new DateTimeObject(validDate);
+            MyChecker checker = new MyChecker();
+            param.AddCertPathChecker(checker);
+
+            PkixCertPathValidatorResult result = (PkixCertPathValidatorResult) cpv.Validate(cp, param);
+            PkixPolicyNode policyTree = result.PolicyTree;
+            AsymmetricKeyParameter subjectPublicKey = result.SubjectPublicKey;
+
+            if (checker.GetCount() != 2)
+            {
+                Fail("checker not evaluated for each certificate");
+            }
+            
+            if (!subjectPublicKey.Equals(finalCert.GetPublicKey()))
+            {
+                Fail("wrong public key returned");
+            }
+
+            //
+            // invalid path containing a valid one test
+            //
+            try
+            {
+                // initialise CertStore
+                rootCert = certParser.ReadCertificate(AC_RAIZ_ICPBRASIL);
+                interCert = certParser.ReadCertificate(AC_PR);
+                finalCert = certParser.ReadCertificate(schefer);
+
+                x509Certs = new ArrayList();
+                x509Certs.Add(rootCert);
+                x509Certs.Add(interCert);
+                x509Certs.Add(finalCert);
+
+//				ccsp = new CollectionCertStoreParameters(list);
+//				store = CertStore.GetInstance("Collection", ccsp);
+//				ccsp = new X509CollectionStoreParameters(list);
+                x509CertStore = X509StoreFactory.Create(
+                    "Certificate/Collection",
+                    new X509CollectionStoreParameters(x509Certs));
+
+                // NB: Month is 1-based in .NET
+                //validDate = new DateTime(2004,3,21,2,21,10).ToUniversalTime();
+                validDate = new DateTime(2004, 3, 20, 19, 21, 10);
+
+                //validating path
+                certchain = new ArrayList();
+                certchain.Add(finalCert);
+                certchain.Add(interCert);
+//				cp = CertificateFactory.GetInstance("X.509").GenerateCertPath(certchain);
+                cp = new PkixCertPath(certchain);
+                trust = new HashSet();
+                trust.Add(new TrustAnchor(rootCert, null));
+
+//				cpv = CertPathValidator.GetInstance("PKIX");
+                cpv = new PkixCertPathValidator();
+                param = new PkixParameters(trust);
+                param.AddStore(x509CertStore);
+                param.IsRevocationEnabled = false;
+                param.Date = new DateTimeObject(validDate);
+
+                result =(PkixCertPathValidatorResult) cpv.Validate(cp, param);
+                policyTree = result.PolicyTree;
+                subjectPublicKey = result.SubjectPublicKey;
+
+                Fail("Invalid path validated");
+            }
+            catch (Exception e)
+            {
+                if (e is PkixCertPathValidatorException 
+                    && e.Message.StartsWith("Could not validate certificate signature."))
+                {
+                    return;
+                }
+                Fail("unexpected exception", e);
+            }
+        }
+
+        public override string Name
+        {
+            get { return "CertPathValidator"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new CertPathValidatorTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+
+        private class MyChecker
+            : PkixCertPathChecker
+        {
+            private static int count;
+
+            public override void Init(bool forward)
+            {
+            }
+
+            public override bool IsForwardCheckingSupported()
+            {
+                return true;
+            }
+
+            public override ISet GetSupportedExtensions()
+            {
+                return null;
+            }
+
+            public override void Check(X509Certificate cert, ICollection unresolvedCritExts)
+            {
+                count++;
+            }
+
+            public int GetCount()
+            {
+                return count;
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/test/CertTest.cs b/crypto/test/src/test/CertTest.cs
new file mode 100644
index 000000000..9bb4df7d1
--- /dev/null
+++ b/crypto/test/src/test/CertTest.cs
@@ -0,0 +1,2544 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class CertTest
+        : SimpleTest
+    {
+        //
+        // server.crt
+        //
+        private static readonly byte[] cert1 = Base64.Decode(
+            "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+            + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+            + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+            + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+            + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+            + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+            + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+            + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+            + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+            + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+            + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+            + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+            + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+            + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+            + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+            + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+            + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+            + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+            + "5/8=");
+
+        //
+        // ca.crt
+        //
+        private static readonly byte[] cert2 = Base64.Decode(
+            "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+            + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+            + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+            + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+            + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+            + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+            + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+            + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+            + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+            + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+            + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+            + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+            + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+            + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+            + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+            + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+            + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+            + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+            + "DhkaJ8VqOMajkQFma2r9iA==");
+
+        //
+        // testx509.pem
+        //
+        private static readonly byte[] cert3 = Base64.Decode(
+            "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+            + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+            + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+            + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+            + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+            + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+            + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+            + "zl9HYIMxATFyqSiD9jsx");
+
+        //
+        // v3-cert1.pem
+        //
+        private static readonly byte[] cert4 = Base64.Decode(
+            "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+            + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+            + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+            + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+            + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+            + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+            + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+            + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+            + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+            + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+            + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+            + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+            + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+            + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+        //
+        // v3-cert2.pem
+        //
+        private static readonly byte[] cert5 = Base64.Decode(
+            "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+            + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+            + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+            + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+            + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+            + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+            + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+            + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+            + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+            + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+            + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+            + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+            + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+            + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+        //
+        // pem encoded pkcs7
+        //
+        private static readonly byte[] cert6 = Base64.Decode(
+            "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+            + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+            + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+            + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+            + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+            + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+            + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+            + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+            + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+            + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+            + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+            + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+            + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+            + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+            + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+            + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+            + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+            + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+            + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+            + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+            + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+            + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+            + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+            + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+            + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+            + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+            + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+            + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+            + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+            + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+            + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+            + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+            + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+            + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+            + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+            + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+            + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+            + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+            + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+            + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+            + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+            + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+            + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+            + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+            + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+            + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+            + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+            + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+            + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+            + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+            + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+            + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+            + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+            + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+        //
+        // dsaWithSHA1 cert
+        //
+        private static readonly byte[] cert7 = Base64.Decode(
+            "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+            + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+            + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+            + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+            + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+            + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+            + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+            + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+            + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+            + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+            + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+            + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+            + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+            + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+            + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+            + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+            + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+            + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+            + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+            + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+            + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+            + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+            + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+            + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+            + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+            + "cg==");
+
+        //
+        // testcrl.pem
+        //
+        private static readonly byte[] crl1 = Base64.Decode(
+            "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT"
+            + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy"
+            + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw"
+            + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw"
+            + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw"
+            + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw"
+            + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw"
+            + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw"
+            + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw"
+            + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw"
+            + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF"
+            + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ"
+            + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt"
+            + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v");
+
+        //
+        // ecdsa cert with extra octet string.
+        //
+//		private static readonly byte[] oldEcdsa = Base64.Decode(
+//			"MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+//			+ "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+//			+ "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+//			+ "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+//			+ "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+//			+ "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+//			+ "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+//			+ "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+//			+ "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+//			+ "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+//			+ "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+//			+ "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+//			+ "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+//			+ "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+        private static readonly byte[] uncompressedPtEC = Base64.Decode(
+            "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ"
+            + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD"
+            + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw"
+            + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK"
+            + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G"
+            + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0"
+            + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ"
+            + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT"
+            + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2"
+            + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7"
+            + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA"
+            + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD"
+            + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn"
+            + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH"
+            + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB"
+            + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI"
+            + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt"
+            + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD"
+            + "z+fauEg=");
+
+        private static readonly byte[] keyUsage = Base64.Decode(
+            "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+            + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+            + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+            + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+            + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+            + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+            + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+            + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+            + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+            + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+            + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+            + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+            + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+            + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+            + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+            + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+            + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+            + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+            + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+            + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+            + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+            + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+            + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+            + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+            + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+            + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+            + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+            + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+            + "PHayXOw=");
+
+        private static readonly byte[] nameCert = Base64.Decode(
+            "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE"+
+            "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg"+
+            "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0"+
+            "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I"+
+            "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4"+
+            "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ"+
+            "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug"+
+            "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps"+
+            "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z"+
+            "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD"+
+            "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k"+
+            "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu"+
+            "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1"+
+            "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0"+
+            "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG"+
+            "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi"+
+            "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT"+
+            "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB"+
+            "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3"+
+            "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg"+
+            "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs"+
+            "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+        private static readonly byte[] probSelfSignedCert = Base64.Decode(
+            "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+            + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+            + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+            + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+            + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+            + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+            + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+            + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+            + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+            + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+            + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+            + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+            + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+            + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+            + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+
+        private static readonly byte[] gost34102001base = Base64.Decode(
+            "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G"
+            + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv"
+            + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw"
+            + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2"
+            + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK"
+            + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0"
+            + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA"
+            + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+"
+            + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA"
+            + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb"
+            + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA==");
+
+        private static readonly byte[] gost341094base = Base64.Decode(
+            "MIICDzCCAbwCEBcxKsIb0ghYvAQeUjfQdFAwCgYGKoUDAgIEBQAwaTEdMBsG"
+            + "A1UEAwwUR29zdFIzNDEwLTk0IGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1By"
+            + "bzELMAkGA1UEBhMCUlUxJzAlBgkqhkiG9w0BCQEWGEdvc3RSMzQxMC05NEBl"
+            + "eGFtcGxlLmNvbTAeFw0wNTAyMDMxNTE2NTFaFw0xNTAyMDMxNTE2NTFaMGkx"
+            + "HTAbBgNVBAMMFEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlw"
+            + "dG9Qcm8xCzAJBgNVBAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAt"
+            + "OTRAZXhhbXBsZS5jb20wgaUwHAYGKoUDAgIUMBIGByqFAwICIAIGByqFAwIC"
+            + "HgEDgYQABIGAu4Rm4XmeWzTYLIB/E6gZZnFX/oxUJSFHbzALJ3dGmMb7R1W+"
+            + "t7Lzk2w5tUI3JoTiDRCKJA4fDEJNKzsRK6i/ZjkyXJSLwaj+G2MS9gklh8x1"
+            + "G/TliYoJgmjTXHemD7aQEBON4z58nJHWrA0ILD54wbXCtrcaqCqLRYGTMjJ2"
+            + "+nswCgYGKoUDAgIEBQADQQBxKNhOmjgz/i5CEgLOyKyz9pFGkDcaymsWYQWV"
+            + "v7CZ0pTM8IzMzkUBW3GHsUjCFpanFZDfg2zuN+3kT+694n9B");
+
+        private static readonly byte[] gost341094A = Base64.Decode(
+            "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOZGVmYXVsdDM0MTAtOTQx"
+            + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1vbGExDDAKBgNVBAgT"
+            + "A01FTDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+            + "MzExNTdaFw0wNjAzMjkxMzExNTdaMIGBMRcwFQYDVQQDEw5kZWZhdWx0MzQxMC05NDENMAsGA1UE"
+            + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLW9sYTEMMAoGA1UECBMDTUVMMQsw"
+            + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+            + "hQMCAiACBgcqhQMCAh4BA4GEAASBgIQACDLEuxSdRDGgdZxHmy30g/DUYkRxO9Mi/uSHX5NjvZ31"
+            + "b7JMEMFqBtyhql1HC5xZfUwZ0aT3UnEFDfFjLP+Bf54gA+LPkQXw4SNNGOj+klnqgKlPvoqMGlwa"
+            + "+hLPKbS561WpvB2XSTgbV+pqqXR3j6j30STmybelEV3RdS2Now8wDTALBgNVHQ8EBAMCB4AwCgYG"
+            + "KoUDAgIEBQADQQBCFy7xWRXtNVXflKvDs0pBdBuPzjCMeZAXVxK8vUxsxxKu76d9CsvhgIFknFRi"
+            + "wWTPiZenvNoJ4R1uzeX+vREm");
+
+        private static readonly byte[] gost341094B = Base64.Decode(
+            "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOcGFyYW0xLTM0MTAtOTQx"
+            +  "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNVBAgT"
+            +  "A01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx"
+            +  "MzEzNTZaFw0wNjAzMjkxMzEzNTZaMIGBMRcwFQYDVQQDEw5wYXJhbTEtMzQxMC05NDENMAsGA1UE"
+            +  "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMDTWVsMQsw"
+            +  "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq"
+            +  "hQMCAiADBgcqhQMCAh4BA4GEAASBgEa+AAcZmijWs1M9x5Pn9efE8D9ztG1NMoIt0/hNZNqln3+j"
+            +  "lMZjyqPt+kTLIjtmvz9BRDmIDk6FZz+4LhG2OTL7yGpWfrMxMRr56nxomTN9aLWRqbyWmn3brz9Y"
+            +  "AUD3ifnwjjIuW7UM84JNlDTOdxx0XRUfLQIPMCXe9cO02Xskow8wDTALBgNVHQ8EBAMCB4AwCgYG"
+            +  "KoUDAgIEBQADQQBzFcnuYc/639OTW+L5Ecjw9KxGr+dwex7lsS9S1BUgKa3m1d5c+cqI0B2XUFi5"
+            +  "4iaHHJG0dCyjtQYLJr0OZjRw");
+
+        private static readonly byte[] gost34102001A = Base64.Decode(
+            "MIICCzCCAbigAwIBAgIBATAKBgYqhQMCAgMFADCBhDEaMBgGA1UEAxMRZGVmYXVsdC0zNDEwLTIw"
+            + "MDExDTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNV"
+            + "BAgTA01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAz"
+            + "MjkxMzE4MzFaFw0wNjAzMjkxMzE4MzFaMIGEMRowGAYDVQQDExFkZWZhdWx0LTM0MTAtMjAwMTEN"
+            + "MAsGA1UEChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMD"
+            + "TWVsMQswCQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MGMwHAYGKoUDAgIT"
+            + "MBIGByqFAwICIwEGByqFAwICHgEDQwAEQG/4c+ZWb10IpeHfmR+vKcbpmSOClJioYmCVgnojw0Xn"
+            + "ned0KTg7TJreRUc+VX7vca4hLQaZ1o/TxVtfEApK/O6jDzANMAsGA1UdDwQEAwIHgDAKBgYqhQMC"
+            + "AgMFAANBAN8y2b6HuIdkD3aWujpfQbS1VIA/7hro4vLgDhjgVmev/PLzFB8oTh3gKhExpDo82IEs"
+            + "ZftGNsbbyp1NFg7zda0=");
+
+        private static readonly byte[] gostCA1 = Base64.Decode(
+            "MIIDNDCCAuGgAwIBAgIQZLcKDcWcQopF+jp4p9jylDAKBgYqhQMCAgQFADBm"
+            + "MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5PT08g"
+            + "Q3J5cHRvLVBybzEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxFzAVBgNVBAMTDkNQ"
+            + "IENTUCBUZXN0IENBMB4XDTAyMDYwOTE1NTIyM1oXDTA5MDYwOTE1NTkyOVow"
+            + "ZjELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOT09P"
+            + "IENyeXB0by1Qcm8xFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5D"
+            + "UCBDU1AgVGVzdCBDQTCBpTAcBgYqhQMCAhQwEgYHKoUDAgIgAgYHKoUDAgIe"
+            + "AQOBhAAEgYAYglywKuz1nMc9UiBYOaulKy53jXnrqxZKbCCBSVaJ+aCKbsQm"
+            + "glhRFrw6Mwu8Cdeabo/ojmea7UDMZd0U2xhZFRti5EQ7OP6YpqD0alllo7za"
+            + "4dZNXdX+/ag6fOORSLFdMpVx5ganU0wHMPk67j+audnCPUj/plbeyccgcdcd"
+            + "WaOCASIwggEeMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+            + "DgQWBBTe840gTo4zt2twHilw3PD9wJaX0TCBygYDVR0fBIHCMIG/MDygOqA4"
+            + "hjYtaHR0cDovL2ZpZXdhbGwvQ2VydEVucm9sbC9DUCUyMENTUCUyMFRlc3Ql"
+            + "MjBDQSgzKS5jcmwwRKBCoECGPmh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0Nl"
+            + "cnRFbnJvbGwvQ1AlMjBDU1AlMjBUZXN0JTIwQ0EoMykuY3JsMDmgN6A1hjMt"
+            + "ZmlsZTovL1xcZmlld2FsbFxDZXJ0RW5yb2xsXENQIENTUCBUZXN0IENBKDMp"
+            + "LmNybC8wEgYJKwYBBAGCNxUBBAUCAwMAAzAKBgYqhQMCAgQFAANBAIJi7ni7"
+            + "9rwMR5rRGTFftt2k70GbqyUEfkZYOzrgdOoKiB4IIsIstyBX0/ne6GsL9Xan"
+            + "G2IN96RB7KrowEHeW+k=");
+
+        private static readonly byte[] gostCA2 = Base64.Decode(
+            "MIIC2DCCAoWgAwIBAgIQe9ZCugm42pRKNcHD8466zTAKBgYqhQMCAgMFADB+"
+            + "MRowGAYJKoZIhvcNAQkBFgtzYmFAZGlndC5ydTELMAkGA1UEBhMCUlUxDDAK"
+            + "BgNVBAgTA01FTDEUMBIGA1UEBxMLWW9zaGthci1PbGExDTALBgNVBAoTBERp"
+            + "Z3QxDzANBgNVBAsTBkNyeXB0bzEPMA0GA1UEAxMGc2JhLUNBMB4XDTA0MDgw"
+            + "MzEzMzE1OVoXDTE0MDgwMzEzNDAxMVowfjEaMBgGCSqGSIb3DQEJARYLc2Jh"
+            + "QGRpZ3QucnUxCzAJBgNVBAYTAlJVMQwwCgYDVQQIEwNNRUwxFDASBgNVBAcT"
+            + "C1lvc2hrYXItT2xhMQ0wCwYDVQQKEwREaWd0MQ8wDQYDVQQLEwZDcnlwdG8x"
+            + "DzANBgNVBAMTBnNiYS1DQTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMC"
+            + "Ah4BA0MABEDMSy10CuOH+i8QKG2UWA4XmCt6+BFrNTZQtS6bOalyDY8Lz+G7"
+            + "HybyipE3PqdTB4OIKAAPsEEeZOCZd2UXGQm5o4HaMIHXMBMGCSsGAQQBgjcU"
+            + "AgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud"
+            + "DgQWBBRJJl3LcNMxkZI818STfoi3ng1xoDBxBgNVHR8EajBoMDGgL6Athito"
+            + "dHRwOi8vc2JhLmRpZ3QubG9jYWwvQ2VydEVucm9sbC9zYmEtQ0EuY3JsMDOg"
+            + "MaAvhi1maWxlOi8vXFxzYmEuZGlndC5sb2NhbFxDZXJ0RW5yb2xsXHNiYS1D"
+            + "QS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwCgYGKoUDAgIDBQADQQA+BRJHbc/p"
+            + "q8EYl6iJqXCuR+ozRmH7hPAP3c4KqYSC38TClCgBloLapx/3/WdatctFJW/L"
+            + "mcTovpq088927shE");
+
+        private static readonly byte[] inDirectCrl = Base64.Decode(
+            "MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV"
+            +"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0"
+            +"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO"
+            +"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3"
+            +"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+            +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+            +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV"
+            +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+            +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+            +"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+            +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0"
+            +"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+            +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+            +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV"
+            +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+            +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+            +"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+            +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/jFw0wMzAx"
+            +"MTMxMTI2NTZaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+            +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+            +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+QXDTAzMDExMzExMjY1NlowZzBlBgNV"
+            +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+            +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+            +"UE4wfgIEL64/4hcNMDQwNzEzMDc1ODM4WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+            +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/eFw0wMzAy"
+            +"MTcwNjMzMjVaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+            +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+            +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP98XDTAzMDIxNzA2MzMyNVowZzBlBgNV"
+            +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+            +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+            +"UE4wfgIEL64/0xcNMDMwMjE3MDYzMzI1WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+            +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/dFw0wMzAx"
+            +"MTMxMTI4MTRaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+            +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+            +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP9cXDTAzMDExMzExMjcwN1owZzBlBgNV"
+            +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+            +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+            +"UE4wfgIEL64/2BcNMDMwMTEzMTEyNzA3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+            +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/VFw0wMzA0"
+            +"MzAxMjI3NTNaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD"
+            +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU"
+            +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP9YXDTAzMDQzMDEyMjc1M1owZzBlBgNV"
+            +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+            +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6"
+            +"UE4wfgIEL64/xhcNMDMwMjEyMTM0NTQwWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC"
+            +"BgEKBxQTATEwGAYDVQQDFBFUVEMgVGVzdCBDQSAxMTpQTjCBkAIEL64/xRcNMDMw"
+            +"MjEyMTM0NTQwWjB5MHcGA1UdHQEB/wRtMGukaTBnMQswCQYDVQQGEwJERTEcMBoG"
+            +"A1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEQMA4GA1UECxQHVGVsZVNlYzEoMAwG"
+            +"BwKCBgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNTpQTjB+AgQvrj/CFw0w"
+            +"MzAyMTIxMzA5MTZaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRww"
+            +"GgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNV"
+            +"BAMUEVRUQyBUZXN0IENBIDExOlBOMIGQAgQvrj/BFw0wMzAyMTIxMzA4NDBaMHkw"
+            +"dwYDVR0dAQH/BG0wa6RpMGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2No"
+            +"ZSBUZWxla29tIEFHMRAwDgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAY"
+            +"BgNVBAMUEVNpZ0cgVGVzdCBDQSA1OlBOMH4CBC+uP74XDTAzMDIxNzA2MzcyNVow"
+            +"ZzBlBgNVHR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRz"
+            +"Y2hlIFRlbGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRVFRDIFRlc3Qg"
+            +"Q0EgMTE6UE4wgZACBC+uP70XDTAzMDIxNzA2MzcyNVoweTB3BgNVHR0BAf8EbTBr"
+            +"pGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcx"
+            +"EDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBU"
+            +"ZXN0IENBIDU6UE4wgZACBC+uP7AXDTAzMDIxMjEzMDg1OVoweTB3BgNVHR0BAf8E"
+            +"bTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g"
+            +"QUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2ln"
+            +"RyBUZXN0IENBIDU6UE4wgZACBC+uP68XDTAzMDIxNzA2MzcyNVoweTB3BgNVHR0B"
+            +"Af8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVr"
+            +"b20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQR"
+            +"U2lnRyBUZXN0IENBIDU6UE4wfgIEL64/kxcNMDMwNDEwMDUyNjI4WjBnMGUGA1Ud"
+            +"HQEB/wRbMFmkVzBVMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVs"
+            +"ZWtvbSBBRzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFUVEMgVGVzdCBDQSAxMTpQ"
+            +"TjCBkAIEL64/khcNMDMwNDEwMDUyNjI4WjB5MHcGA1UdHQEB/wRtMGukaTBnMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEQMA4GA1UE"
+            +"CxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0Eg"
+            +"NTpQTjB+AgQvrj8/Fw0wMzAyMjYxMTA0NDRaMGcwZQYDVR0dAQH/BFswWaRXMFUx"
+            +"CzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYH"
+            +"AoIGAQoHFBMBMTAYBgNVBAMUEVRUQyBUZXN0IENBIDExOlBOMIGQAgQvrj8+Fw0w"
+            +"MzAyMjYxMTA0NDRaMHkwdwYDVR0dAQH/BG0wa6RpMGcxCzAJBgNVBAYTAkRFMRww"
+            +"GgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYDVQQLFAdUZWxlU2VjMSgw"
+            +"DAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBDQSA1OlBOMH4CBC+uPs0X"
+            +"DTAzMDUyMDA1MjczNlowZzBlBgNVHR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUx"
+            +"HDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgG"
+            +"A1UEAxQRVFRDIFRlc3QgQ0EgMTE6UE4wgZACBC+uPswXDTAzMDUyMDA1MjczNlow"
+            +"eTB3BgNVHR0BAf8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRz"
+            +"Y2hlIFRlbGVrb20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwEx"
+            +"MBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6UE4wfgIEL64+PBcNMDMwNjE3MTAzNDE2"
+            +"WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1"
+            +"dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFUVEMgVGVz"
+            +"dCBDQSAxMTpQTjCBkAIEL64+OxcNMDMwNjE3MTAzNDE2WjB5MHcGA1UdHQEB/wRt"
+            +"MGukaTBnMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBB"
+            +"RzEQMA4GA1UECxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFTaWdH"
+            +"IFRlc3QgQ0EgNjpQTjCBkAIEL64+OhcNMDMwNjE3MTAzNDE2WjB5MHcGA1UdHQEB"
+            +"/wRtMGukaTBnMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtv"
+            +"bSBBRzEQMA4GA1UECxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFT"
+            +"aWdHIFRlc3QgQ0EgNjpQTjB+AgQvrj45Fw0wMzA2MTcxMzAxMDBaMGcwZQYDVR0d"
+            +"AQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxl"
+            +"a29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVRUQyBUZXN0IENBIDExOlBO"
+            +"MIGQAgQvrj44Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6RpMGcxCzAJ"
+            +"BgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYDVQQL"
+            +"FAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBDQSA2"
+            +"OlBOMIGQAgQvrj43Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6RpMGcx"
+            +"CzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYD"
+            +"VQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBD"
+            +"QSA2OlBOMIGQAgQvrj42Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6Rp"
+            +"MGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAw"
+            +"DgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVz"
+            +"dCBDQSA2OlBOMIGQAgQvrj4zFw0wMzA2MTcxMDM3NDlaMHkwdwYDVR0dAQH/BG0w"
+            +"a6RpMGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFH"
+            +"MRAwDgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cg"
+            +"VGVzdCBDQSA2OlBOMH4CBC+uPjEXDTAzMDYxNzEwNDI1OFowZzBlBgNVHR0BAf8E"
+            +"WzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g"
+            +"QUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRVFRDIFRlc3QgQ0EgMTE6UE4wgZAC"
+            +"BC+uPjAXDTAzMDYxNzEwNDI1OFoweTB3BgNVHR0BAf8EbTBrpGkwZzELMAkGA1UE"
+            +"BhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNVBAsUB1Rl"
+            +"bGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6UE4w"
+            +"gZACBC+uPakXDTAzMTAyMjExMzIyNFoweTB3BgNVHR0BAf8EbTBrpGkwZzELMAkG"
+            +"A1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNVBAsU"
+            +"B1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6"
+            +"UE4wgZACBC+uPLIXDTA1MDMxMTA2NDQyNFoweTB3BgNVHR0BAf8EbTBrpGkwZzEL"
+            +"MAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNV"
+            +"BAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENB"
+            +"IDY6UE4wgZACBC+uPKsXDTA0MDQwMjA3NTQ1M1oweTB3BgNVHR0BAf8EbTBrpGkw"
+            +"ZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAO"
+            +"BgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0"
+            +"IENBIDY6UE4wgZACBC+uOugXDTA1MDEyNzEyMDMyNFoweTB3BgNVHR0BAf8EbTBr"
+            +"pGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcx"
+            +"EDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBU"
+            +"ZXN0IENBIDY6UE4wgZACBC+uOr4XDTA1MDIxNjA3NTcxNloweTB3BgNVHR0BAf8E"
+            +"bTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g"
+            +"QUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2ln"
+            +"RyBUZXN0IENBIDY6UE4wgZACBC+uOqcXDTA1MDMxMDA1NTkzNVoweTB3BgNVHR0B"
+            +"Af8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVr"
+            +"b20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQR"
+            +"U2lnRyBUZXN0IENBIDY6UE4wgZACBC+uOjwXDTA1MDUxMTEwNDk0NloweTB3BgNV"
+            +"HR0BAf8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl"
+            +"bGVrb20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UE"
+            +"AxQRU2lnRyBUZXN0IENBIDY6UE4wgaoCBC+sbdUXDTA1MTExMTEwMDMyMVowgZIw"
+            +"gY8GA1UdHQEB/wSBhDCBgaR/MH0xCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0"
+            +"c2NoZSBUZWxla29tIEFHMR8wHQYDVQQLFBZQcm9kdWt0emVudHJ1bSBUZWxlU2Vj"
+            +"MS8wDAYHAoIGAQoHFBMBMTAfBgNVBAMUGFRlbGVTZWMgUEtTIFNpZ0cgQ0EgMTpQ"
+            +"TjCBlQIEL64uaBcNMDYwMTIzMTAyNTU1WjB+MHwGA1UdHQEB/wRyMHCkbjBsMQsw"
+            +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEWMBQGA1UE"
+            +"CxQNWmVudHJhbGUgQm9ubjEnMAwGBwKCBgEKBxQTATEwFwYDVQQDFBBUVEMgVGVz"
+            +"dCBDQSA5OlBOMIGVAgQvribHFw0wNjA4MDEwOTQ4NDRaMH4wfAYDVR0dAQH/BHIw"
+            +"cKRuMGwxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFH"
+            +"MRYwFAYDVQQLFA1aZW50cmFsZSBCb25uMScwDAYHAoIGAQoHFBMBMTAXBgNVBAMU"
+            +"EFRUQyBUZXN0IENBIDk6UE6ggZswgZgwCwYDVR0UBAQCAhEMMB8GA1UdIwQYMBaA"
+            +"FANbyNumDI9545HwlCF26NuOJC45MA8GA1UdHAEB/wQFMAOEAf8wVwYDVR0SBFAw"
+            +"ToZMbGRhcDovL3Brc2xkYXAudHR0Yy5kZS9vdT1ULVRlbGVTZWMgVGVzdCBESVIg"
+            +"ODpQTixvPURldXRzY2hlIFRlbGVrb20gQUcsYz1kZTANBgkqhkiG9w0BAQUFAAOB"
+            +"gQBewL5gLFHpeOWO07Vk3Gg7pRDuAlvaovBH4coCyCWpk5jEhUfFSYEDuaQB7do4"
+            +"IlJmeTHvkI0PIZWJ7bwQ2PVdipPWDx0NVwS/Cz5jUKiS3BbAmZQZOueiKLFpQq3A"
+            +"b8aOHA7WHU4078/1lM+bgeu33Ln1CGykEbmSjA/oKPi/JA==");
+
+        private static readonly byte[] directCRL = Base64.Decode(
+            "MIIGXTCCBckCAQEwCgYGKyQDAwECBQAwdDELMAkGA1UEBhMCREUxHDAaBgNVBAoU"
+            +"E0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0MS4w"
+            +"DAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBOFw0w"
+            +"NjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIElTAVAgQvrj/pFw0wMzA3MjIw"
+            +"NTQxMjhaMBUCBC+uP+oXDTAzMDcyMjA1NDEyOFowFQIEL64/5xcNMDQwNDA1MTMx"
+            +"ODE3WjAVAgQvrj/oFw0wNDA0MDUxMzE4MTdaMBUCBC+uP+UXDTAzMDExMzExMTgx"
+            +"MVowFQIEL64/5hcNMDMwMTEzMTExODExWjAVAgQvrj/jFw0wMzAxMTMxMTI2NTZa"
+            +"MBUCBC+uP+QXDTAzMDExMzExMjY1NlowFQIEL64/4hcNMDQwNzEzMDc1ODM4WjAV"
+            +"AgQvrj/eFw0wMzAyMTcwNjMzMjVaMBUCBC+uP98XDTAzMDIxNzA2MzMyNVowFQIE"
+            +"L64/0xcNMDMwMjE3MDYzMzI1WjAVAgQvrj/dFw0wMzAxMTMxMTI4MTRaMBUCBC+u"
+            +"P9cXDTAzMDExMzExMjcwN1owFQIEL64/2BcNMDMwMTEzMTEyNzA3WjAVAgQvrj/V"
+            +"Fw0wMzA0MzAxMjI3NTNaMBUCBC+uP9YXDTAzMDQzMDEyMjc1M1owFQIEL64/xhcN"
+            +"MDMwMjEyMTM0NTQwWjAVAgQvrj/FFw0wMzAyMTIxMzQ1NDBaMBUCBC+uP8IXDTAz"
+            +"MDIxMjEzMDkxNlowFQIEL64/wRcNMDMwMjEyMTMwODQwWjAVAgQvrj++Fw0wMzAy"
+            +"MTcwNjM3MjVaMBUCBC+uP70XDTAzMDIxNzA2MzcyNVowFQIEL64/sBcNMDMwMjEy"
+            +"MTMwODU5WjAVAgQvrj+vFw0wMzAyMTcwNjM3MjVaMBUCBC+uP5MXDTAzMDQxMDA1"
+            +"MjYyOFowFQIEL64/khcNMDMwNDEwMDUyNjI4WjAVAgQvrj8/Fw0wMzAyMjYxMTA0"
+            +"NDRaMBUCBC+uPz4XDTAzMDIyNjExMDQ0NFowFQIEL64+zRcNMDMwNTIwMDUyNzM2"
+            +"WjAVAgQvrj7MFw0wMzA1MjAwNTI3MzZaMBUCBC+uPjwXDTAzMDYxNzEwMzQxNlow"
+            +"FQIEL64+OxcNMDMwNjE3MTAzNDE2WjAVAgQvrj46Fw0wMzA2MTcxMDM0MTZaMBUC"
+            +"BC+uPjkXDTAzMDYxNzEzMDEwMFowFQIEL64+OBcNMDMwNjE3MTMwMTAwWjAVAgQv"
+            +"rj43Fw0wMzA2MTcxMzAxMDBaMBUCBC+uPjYXDTAzMDYxNzEzMDEwMFowFQIEL64+"
+            +"MxcNMDMwNjE3MTAzNzQ5WjAVAgQvrj4xFw0wMzA2MTcxMDQyNThaMBUCBC+uPjAX"
+            +"DTAzMDYxNzEwNDI1OFowFQIEL649qRcNMDMxMDIyMTEzMjI0WjAVAgQvrjyyFw0w"
+            +"NTAzMTEwNjQ0MjRaMBUCBC+uPKsXDTA0MDQwMjA3NTQ1M1owFQIEL6466BcNMDUw"
+            +"MTI3MTIwMzI0WjAVAgQvrjq+Fw0wNTAyMTYwNzU3MTZaMBUCBC+uOqcXDTA1MDMx"
+            +"MDA1NTkzNVowFQIEL646PBcNMDUwNTExMTA0OTQ2WjAVAgQvrG3VFw0wNTExMTEx"
+            +"MDAzMjFaMBUCBC+uLmgXDTA2MDEyMzEwMjU1NVowFQIEL64mxxcNMDYwODAxMDk0"
+            +"ODQ0WqCBijCBhzALBgNVHRQEBAICEQwwHwYDVR0jBBgwFoAUA1vI26YMj3njkfCU"
+            +"IXbo244kLjkwVwYDVR0SBFAwToZMbGRhcDovL3Brc2xkYXAudHR0Yy5kZS9vdT1U"
+            +"LVRlbGVTZWMgVGVzdCBESVIgODpQTixvPURldXRzY2hlIFRlbGVrb20gQUcsYz1k"
+            +"ZTAKBgYrJAMDAQIFAAOBgQArj4eMlbAwuA2aS5O4UUUHQMKKdK/dtZi60+LJMiMY"
+            +"ojrMIf4+ZCkgm1Ca0Cd5T15MJxVHhh167Ehn/Hd48pdnAP6Dfz/6LeqkIHGWMHR+"
+            +"z6TXpwWB+P4BdUec1ztz04LypsznrHcLRa91ixg9TZCb1MrOG+InNhleRs1ImXk8"
+            +"MQ==");
+
+        private static readonly byte[] pkcs7CrlProblem = Base64.Decode(
+              "MIIwSAYJKoZIhvcNAQcCoIIwOTCCMDUCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+            + "SIb3DQEHAaCCEsAwggP4MIIC4KADAgECAgF1MA0GCSqGSIb3DQEBBQUAMEUx"
+            + "CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQD"
+            + "ExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUwHhcNMDQxMjAyMjEyNTM5WhcNMDYx"
+            + "MjMwMjEyNTM5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR2VvVHJ1c3Qg"
+            + "SW5jMSYwJAYDVQQDEx1HZW9UcnVzdCBBZG9iZSBPQ1NQIFJlc3BvbmRlcjCB"
+            + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4gnNYhtw7U6QeVXZODnGhHMj"
+            + "+OgZ0DB393rEk6a2q9kq129IA2e03yKBTfJfQR9aWKc2Qj90dsSqPjvTDHFG"
+            + "Qsagm2FQuhnA3fb1UWhPzeEIdm6bxDsnQ8nWqKqxnWZzELZbdp3I9bBLizIq"
+            + "obZovzt60LNMghn/unvvuhpeVSsCAwEAAaOCAW4wggFqMA4GA1UdDwEB/wQE"
+            + "AwIE8DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8BAgEwgcYwgZAGCCsG"
+            + "AQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQg"
+            + "aW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENyZWRlbnRpYWxzIENQ"
+            + "UyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNl"
+            + "cy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl"
+            + "c291cmNlcy9jcHMwEwYDVR0lBAwwCgYIKwYBBQUHAwkwOgYDVR0fBDMwMTAv"
+            + "oC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5j"
+            + "cmwwHwYDVR0jBBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwDQYJKoZIhvcN"
+            + "AQEFBQADggEBAENJf1BD7PX5ivuaawt90q1OGzXpIQL/ClzEeFVmOIxqPc1E"
+            + "TFRq92YuxG5b6+R+k+tGkmCwPLcY8ipg6ZcbJ/AirQhohzjlFuT6YAXsTfEj"
+            + "CqEZfWM2sS7crK2EYxCMmKE3xDfPclYtrAoz7qZvxfQj0TuxHSstHZv39wu2"
+            + "ZiG1BWiEcyDQyTgqTOXBoZmfJtshuAcXmTpgkrYSrS37zNlPTGh+pMYQ0yWD"
+            + "c8OQRJR4OY5ZXfdna01mjtJTOmj6/6XPoLPYTq2gQrc2BCeNJ4bEhLb7sFVB"
+            + "PbwPrpzTE/HRbQHDrzj0YimDxeOUV/UXctgvYwHNtEkcBLsOm/uytMYwggSh"
+            + "MIIDiaADAgECAgQ+HL0oMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVT"
+            + "MSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UE"
+            + "CxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3Qg"
+            + "Q0EwHhcNMDMwMTA4MjMzNzIzWhcNMjMwMTA5MDAwNzIzWjBpMQswCQYDVQQG"
+            + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+            + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+            + "b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzE9UhPen"
+            + "ouczU38/nBKIayyZR2d+Dx65rRSI+cMQ2B3w8NWfaQovWTWwzGypTJwVoJ/O"
+            + "IL+gz1Ti4CBmRT85hjh+nMSOByLGJPYBErA131XqaZCw24U3HuJOB7JCoWoT"
+            + "aaBm6oCREVkqmwh5WiBELcm9cziLPC/gQxtdswvwrzUaKf7vppLdgUydPVmO"
+            + "rTE8QH6bkTYG/OJcjdGNJtVcRc+vZT+xqtJilvSoOOq6YEL09BxKNRXO+E4i"
+            + "Vg+VGMX4lp+f+7C3eCXpgGu91grwxnSUnfMPUNuad85LcIMjjaDKeCBEXDxU"
+            + "ZPHqojAZn+pMBk0GeEtekt8i0slns3rSAQIDAQABo4IBTzCCAUswEQYJYIZI"
+            + "AYb4QgEBBAQDAgAHMIGOBgNVHR8EgYYwgYMwgYCgfqB8pHoweDELMAkGA1UE"
+            + "BhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkMR0w"
+            + "GwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UEAxMNQWRvYmUg"
+            + "Um9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAzMDEwODIz"
+            + "MzcyM1qBDzIwMjMwMTA5MDAwNzIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgw"
+            + "FoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFIK3OEqTqpsQ74C7"
+            + "2VTi8Q/7gJzeMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjYu"
+            + "MDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQAy2p9DdcH6b8lv26sdNjc+"
+            + "vGEZNrcCPB0jWZhsnu5NhedUyCAfp9S74r8Ad30ka3AvXME6dkm10+AjhCpx"
+            + "aiLzwScpmBX2NZDkBEzDjbyfYRzn/SSM0URDjBa6m02l1DUvvBHOvfdRN42f"
+            + "kOQU8Rg/vulZEjX5M5LznuDVa5pxm5lLyHHD4bFhCcTl+pHwQjo3fTT5cujN"
+            + "qmIcIenV9IIQ43sFti1oVgt+fpIsb01yggztVnSynbmrLSsdEF/bJ3Vwj/0d"
+            + "1+ICoHnlHOX/r2RAUS2em0fbQqV8H8KmSLDXvpJpTaT2KVfFeBEY3IdRyhOy"
+            + "Yp1PKzK9MaXB+lKrBYjIMIIEyzCCA7OgAwIBAgIEPhy9tTANBgkqhkiG9w0B"
+            + "AQUFADBpMQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJ"
+            + "bmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYw"
+            + "FAYDVQQDEw1BZG9iZSBSb290IENBMB4XDTA0MDExNzAwMDMzOVoXDTE1MDEx"
+            + "NTA4MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+            + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTCCASIwDQYJKoZI"
+            + "hvcNAQEBBQADggEPADCCAQoCggEBAKfld+BkeFrnOYW8r9L1WygTDlTdSfrO"
+            + "YvWS/Z6Ye5/l+HrBbOHqQCXBcSeCpz7kB2WdKMh1FOE4e9JlmICsHerBLdWk"
+            + "emU+/PDb69zh8E0cLoDfxukF6oVPXj6WSThdSG7H9aXFzRr6S3XGCuvgl+Qw"
+            + "DTLiLYW+ONF6DXwt3TQQtKReJjOJZk46ZZ0BvMStKyBaeB6DKZsmiIo89qso"
+            + "13VDZINH2w1KvXg0ygDizoNtbvgAPFymwnsINS1klfQlcvn0x0RJm9bYQXK3"
+            + "5GNZAgL3M7Lqrld0jMfIUaWvuHCLyivytRuzq1dJ7E8rmidjDEk/G+27pf13"
+            + "fNZ7vR7M+IkCAwEAAaOCAZ0wggGZMBIGA1UdEwEB/wQIMAYBAf8CAQEwUAYD"
+            + "VR0gBEkwRzBFBgkqhkiG9y8BAgEwODA2BggrBgEFBQcCARYqaHR0cHM6Ly93"
+            + "d3cuYWRvYmUuY29tL21pc2MvcGtpL2Nkc19jcC5odG1sMBQGA1UdJQQNMAsG"
+            + "CSqGSIb3LwEBBTCBsgYDVR0fBIGqMIGnMCKgIKAehhxodHRwOi8vY3JsLmFk"
+            + "b2JlLmNvbS9jZHMuY3JsMIGAoH6gfKR6MHgxCzAJBgNVBAYTAlVTMSMwIQYD"
+            + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+            + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0ExDTAL"
+            + "BgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIK3OEqTqpsQ"
+            + "74C72VTi8Q/7gJzeMB0GA1UdDgQWBBSrgFnDZYNtHX0TvRnD7BqPDUdqozAZ"
+            + "BgkqhkiG9n0HQQAEDDAKGwRWNi4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA"
+            + "PzlZLqIAjrFeEWEs0uC29YyJhkXOE9mf3YSaFGsITF+Gl1j0pajTjyH4R35Q"
+            + "r3floW2q3HfNzTeZ90Jnr1DhVERD6zEMgJpCtJqVuk0sixuXJHghS/KicKf4"
+            + "YXJJPx9epuIRF1siBRnznnF90svmOJMXApc0jGnYn3nQfk4kaShSnDaYaeYR"
+            + "DJKcsiWhl6S5zfwS7Gg8hDeyckhMQKKWnlG1CQrwlSFisKCduoodwRtWgft8"
+            + "kx13iyKK3sbalm6vnVc+5nufS4vI+TwMXoV63NqYaSroafBWk0nL53zGXPEy"
+            + "+A69QhzEViJKn2Wgqt5gt++jMMNImbRObIqgfgF1VjCCBUwwggQ0oAMCAQIC"
+            + "AgGDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1H"
+            + "ZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUw"
+            + "HhcNMDYwMzI0MTU0MjI5WhcNMDkwNDA2MTQ0MjI5WjBzMQswCQYDVQQGEwJV"
+            + "UzELMAkGA1UECBMCTUExETAPBgNVBAoTCEdlb1RydXN0MR0wGwYDVQQDExRN"
+            + "YXJrZXRpbmcgRGVwYXJ0bWVudDElMCMGCSqGSIb3DQEJARYWbWFya2V0aW5n"
+            + "QGdlb3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB"
+            + "ANmvajTO4XJvAU2nVcLmXeCnAQX7RZt+7+ML3InmqQ3LCGo1weop09zV069/"
+            + "1x/Nmieol7laEzeXxd2ghjGzwfXafqQEqHn6+vBCvqdNPoSi63fSWhnuDVWp"
+            + "KVDOYgxOonrXl+Cc43lu4zRSq+Pi5phhrjDWcH74a3/rdljUt4c4GFezFXfa"
+            + "w2oTzWkxj2cTSn0Szhpr17+p66UNt8uknlhmu4q44Speqql2HwmCEnpLYJrK"
+            + "W3fOq5D4qdsvsLR2EABLhrBezamLI3iGV8cRHOUTsbTMhWhv/lKfHAyf4XjA"
+            + "z9orzvPN5jthhIfICOFq/nStTgakyL4Ln+nFAB/SMPkCAwEAAaOCAhYwggIS"
+            + "MA4GA1UdDwEB/wQEAwIF4DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8B"
+            + "AgEwgcYwgZAGCCsGAQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMg"
+            + "YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENy"
+            + "ZWRlbnRpYWxzIENQUyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3Qu"
+            + "Y29tL3Jlc291cmNlcy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2Vv"
+            + "dHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwOgYDVR0fBDMwMTAvoC2gK4YpaHR0"
+            + "cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5jcmwwHwYDVR0j"
+            + "BBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwRAYIKwYBBQUHAQEEODA2MDQG"
+            + "CCsGAQUFBzABhihodHRwOi8vYWRvYmUtb2NzcC5nZW90cnVzdC5jb20vcmVz"
+            + "cG9uZGVyMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTA8BgoqhkiG9y8BAQkBBC4w"
+            + "LAIBAYYnaHR0cDovL2Fkb2JlLXRpbWVzdGFtcC5nZW90cnVzdC5jb20vdHNh"
+            + "MBMGCiqGSIb3LwEBCQIEBTADAgEBMAwGA1UdEwQFMAMCAQAwDQYJKoZIhvcN"
+            + "AQEFBQADggEBAAOhy6QxOo+i3h877fvDvTa0plGD2bIqK7wMdNqbMDoSWied"
+            + "FIcgcBOIm2wLxOjZBAVj/3lDq59q2rnVeNnfXM0/N0MHI9TumHRjU7WNk9e4"
+            + "+JfJ4M+c3anrWOG3NE5cICDVgles+UHjXetHWql/LlP04+K2ZOLb6LE2xGnI"
+            + "YyLW9REzCYNAVF+/WkYdmyceHtaBZdbyVAJq0NAJPsfgY1pWcBo31Mr1fpX9"
+            + "WrXNTYDCqMyxMImJTmN3iI68tkXlNrhweQoArKFqBysiBkXzG/sGKYY6tWKU"
+            + "pzjLc3vIp/LrXC5zilROes8BSvwu1w9qQrJNcGwo7O4uijoNtyYil1Exgh1Q"
+            + "MIIdTAIBATBLMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ"
+            + "bmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUCAgGDMAkGBSsO"
+            + "AwIaBQCgggxMMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwIwYJKoZIhvcN"
+            + "AQkEMRYEFP4R6qIdpQJzWyzrqO8X1ZfJOgChMIIMCQYJKoZIhvcvAQEIMYIL"
+            + "+jCCC/agggZ5MIIGdTCCA6gwggKQMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV"
+            + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9U"
+            + "cnVzdCBDQSBmb3IgQWRvYmUXDTA2MDQwNDE3NDAxMFoXDTA2MDQwNTE3NDAx"
+            + "MFowggIYMBMCAgC5Fw0wNTEwMTEyMDM2MzJaMBICAVsXDTA0MTEwNDE1MDk0"
+            + "MVowEwICALgXDTA1MTIxMjIyMzgzOFowEgIBWhcNMDQxMTA0MTUwOTMzWjAT"
+            + "AgIA5hcNMDUwODI3MDQwOTM4WjATAgIAtxcNMDYwMTE2MTc1NTEzWjATAgIA"
+            + "hhcNMDUxMjEyMjIzODU1WjATAgIAtRcNMDUwNzA2MTgzODQwWjATAgIA4BcN"
+            + "MDYwMzIwMDc0ODM0WjATAgIAgRcNMDUwODAyMjIzMTE1WjATAgIA3xcNMDUx"
+            + "MjEyMjIzNjUwWjASAgFKFw0wNDExMDQxNTA5MTZaMBICAUQXDTA0MTEwNDE1"
+            + "MDg1M1owEgIBQxcNMDQxMDAzMDEwMDQwWjASAgFsFw0wNDEyMDYxOTQ0MzFa"
+            + "MBMCAgEoFw0wNjAzMDkxMjA3MTJaMBMCAgEkFw0wNjAxMTYxNzU1MzRaMBIC"
+            + "AWcXDTA1MDMxODE3NTYxNFowEwICAVEXDTA2MDEzMTExMjcxMVowEgIBZBcN"
+            + "MDQxMTExMjI0ODQxWjATAgIA8RcNMDUwOTE2MTg0ODAxWjATAgIBThcNMDYw"
+            + "MjIxMjAxMDM2WjATAgIAwRcNMDUxMjEyMjIzODE2WjASAgFiFw0wNTAxMTAx"
+            + "NjE5MzRaMBICAWAXDTA1MDExMDE5MDAwNFowEwICAL4XDTA1MDUxNzE0NTYx"
+            + "MFowDQYJKoZIhvcNAQEFBQADggEBAEKhRMS3wVho1U3EvEQJZC8+JlUngmZQ"
+            + "A78KQbHPWNZWFlNvPuf/b0s7Lu16GfNHXh1QAW6Y5Hi1YtYZ3YOPyMd4Xugt"
+            + "gCdumbB6xtKsDyN5RvTht6ByXj+CYlYqsL7RX0izJZ6mJn4fjMkqzPKNOjb8"
+            + "kSn5T6rn93BjlATtCE8tPVOM8dnqGccRE0OV59+nDBXc90UMt5LdEbwaUOap"
+            + "snVB0oLcNm8d/HnlVH6RY5LnDjrT4vwfe/FApZtTecEWsllVUXDjSpwfcfD/"
+            + "476/lpGySB2otALqzImlA9R8Ok3hJ8dnF6hhQ5Oe6OJMnGYgdhkKbxsKkdib"
+            + "tTVl3qmH5QAwggLFMIIBrQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQG"
+            + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb"
+            + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS"
+            + "b290IENBFw0wNjAxMjcxODMzMzFaFw0wNzAxMjcwMDAwMDBaMIHeMCMCBD4c"
+            + "vUAXDTAzMDEyMTIzNDY1NlowDDAKBgNVHRUEAwoBBDAjAgQ+HL1BFw0wMzAx"
+            + "MjEyMzQ3MjJaMAwwCgYDVR0VBAMKAQQwIwIEPhy9YhcNMDMwMTIxMjM0NzQy"
+            + "WjAMMAoGA1UdFQQDCgEEMCMCBD4cvWEXDTA0MDExNzAxMDg0OFowDDAKBgNV"
+            + "HRUEAwoBBDAjAgQ+HL2qFw0wNDAxMTcwMTA5MDVaMAwwCgYDVR0VBAMKAQQw"
+            + "IwIEPhy9qBcNMDQwMTE3MDEzOTI5WjAMMAoGA1UdFQQDCgEEoC8wLTAKBgNV"
+            + "HRQEAwIBDzAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jANBgkq"
+            + "hkiG9w0BAQUFAAOCAQEAwtXF9042wG39icUlsotn5tpE3oCusLb/hBpEONhx"
+            + "OdfEQOq0w5hf/vqaxkcf71etA+KpbEUeSVaHMHRPhx/CmPrO9odE139dJdbt"
+            + "9iqbrC9iZokFK3h/es5kg73xujLKd7C/u5ngJ4mwBtvhMLjFjF2vJhPKHL4C"
+            + "IgMwdaUAhrcNzy16v+mw/VGJy3Fvc6oCESW1K9tvFW58qZSNXrMlsuidgunM"
+            + "hPKG+z0SXVyCqL7pnqKiaGddcgujYGOSY4S938oVcfZeZQEODtSYGlzldojX"
+            + "C1U1hCK5+tHAH0Ox/WqRBIol5VCZQwJftf44oG8oviYq52aaqSejXwmfT6zb"
+            + "76GCBXUwggVxMIIFbQoBAKCCBWYwggViBgkrBgEFBQcwAQEEggVTMIIFTzCB"
+            + "taIWBBS+8EpykfXdl4h3z7m/NZfdkAQQERgPMjAwNjA0MDQyMDIwMTVaMGUw"
+            + "YzA7MAkGBSsOAwIaBQAEFEb4BuZYkbjBjOjT6VeA/00fBvQaBBT3fTSQniOp"
+            + "BbHBSkz4xridlX0bsAICAYOAABgPMjAwNjA0MDQyMDIwMTVaoBEYDzIwMDYw"
+            + "NDA1MDgyMDE1WqEjMCEwHwYJKwYBBQUHMAECBBIEEFqooq/R2WltD7TposkT"
+            + "BhMwDQYJKoZIhvcNAQEFBQADgYEAMig6lty4b0JDsT/oanfQG5x6jVKPACpp"
+            + "1UA9SJ0apJJa7LeIdDFmu5C2S/CYiKZm4A4P9cAu0YzgLHxE4r6Op+HfVlAG"
+            + "6bzUe1P/hi1KCJ8r8wxOZAktQFPSzs85RAZwkHMfB0lP2e/h666Oye+Zf8VH"
+            + "RaE+/xZ7aswE89HXoumgggQAMIID/DCCA/gwggLgoAMCAQICAXUwDQYJKoZI"
+            + "hvcNAQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu"
+            + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNDEyMDIy"
+            + "MTI1MzlaFw0wNjEyMzAyMTI1MzlaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK"
+            + "EwxHZW9UcnVzdCBJbmMxJjAkBgNVBAMTHUdlb1RydXN0IEFkb2JlIE9DU1Ag"
+            + "UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiCc1iG3Dt"
+            + "TpB5Vdk4OcaEcyP46BnQMHf3esSTprar2SrXb0gDZ7TfIoFN8l9BH1pYpzZC"
+            + "P3R2xKo+O9MMcUZCxqCbYVC6GcDd9vVRaE/N4Qh2bpvEOydDydaoqrGdZnMQ"
+            + "tlt2ncj1sEuLMiqhtmi/O3rQs0yCGf+6e++6Gl5VKwIDAQABo4IBbjCCAWow"
+            + "DgYDVR0PAQH/BAQDAgTwMIHlBgNVHSABAf8EgdowgdcwgdQGCSqGSIb3LwEC"
+            + "ATCBxjCBkAYIKwYBBQUHAgIwgYMagYBUaGlzIGNlcnRpZmljYXRlIGhhcyBi"
+            + "ZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIEFjcm9iYXQgQ3Jl"
+            + "ZGVudGlhbHMgQ1BTIGxvY2F0ZWQgYXQgaHR0cDovL3d3dy5nZW90cnVzdC5j"
+            + "b20vcmVzb3VyY2VzL2NwczAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90"
+            + "cnVzdC5jb20vcmVzb3VyY2VzL2NwczATBgNVHSUEDDAKBggrBgEFBQcDCTA6"
+            + "BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz"
+            + "L2Fkb2JlY2ExLmNybDAfBgNVHSMEGDAWgBSrgFnDZYNtHX0TvRnD7BqPDUdq"
+            + "ozANBgkqhkiG9w0BAQUFAAOCAQEAQ0l/UEPs9fmK+5prC33SrU4bNekhAv8K"
+            + "XMR4VWY4jGo9zURMVGr3Zi7Eblvr5H6T60aSYLA8txjyKmDplxsn8CKtCGiH"
+            + "OOUW5PpgBexN8SMKoRl9YzaxLtysrYRjEIyYoTfEN89yVi2sCjPupm/F9CPR"
+            + "O7EdKy0dm/f3C7ZmIbUFaIRzINDJOCpM5cGhmZ8m2yG4BxeZOmCSthKtLfvM"
+            + "2U9MaH6kxhDTJYNzw5BElHg5jlld92drTWaO0lM6aPr/pc+gs9hOraBCtzYE"
+            + "J40nhsSEtvuwVUE9vA+unNMT8dFtAcOvOPRiKYPF45RX9Rdy2C9jAc20SRwE"
+            + "uw6b+7K0xjANBgkqhkiG9w0BAQEFAASCAQC7a4yICFGCEMPlJbydK5qLG3rV"
+            + "sip7Ojjz9TB4nLhC2DgsIHds8jjdq2zguInluH2nLaBCVS+qxDVlTjgbI2cB"
+            + "TaWS8nglC7nNjzkKAsa8vThA8FZUVXTW0pb74jNJJU2AA27bb4g+4WgunCrj"
+            + "fpYp+QjDyMmdrJVqRmt5eQN+dpVxMS9oq+NrhOSEhyIb4/rejgNg9wnVK1ms"
+            + "l5PxQ4x7kpm7+Ua41//owkJVWykRo4T1jo4eHEz1DolPykAaKie2VKH/sMqR"
+            + "Spjh4E5biKJLOV9fKivZWKAXByXfwUbbMsJvz4v/2yVHFy9xP+tqB5ZbRoDK"
+            + "k8PzUyCprozn+/22oYIPijCCD4YGCyqGSIb3DQEJEAIOMYIPdTCCD3EGCSqG"
+            + "SIb3DQEHAqCCD2Iwgg9eAgEDMQswCQYFKw4DAhoFADCB+gYLKoZIhvcNAQkQ"
+            + "AQSggeoEgecwgeQCAQEGAikCMCEwCQYFKw4DAhoFAAQUoT97qeCv3FXYaEcS"
+            + "gY8patCaCA8CAiMHGA8yMDA2MDQwNDIwMjA1N1owAwIBPAEB/wIIO0yRre3L"
+            + "8/6ggZCkgY0wgYoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl"
+            + "dHRzMRAwDgYDVQQHEwdOZWVkaGFtMRUwEwYDVQQKEwxHZW9UcnVzdCBJbmMx"
+            + "EzARBgNVBAsTClByb2R1Y3Rpb24xJTAjBgNVBAMTHGFkb2JlLXRpbWVzdGFt"
+            + "cC5nZW90cnVzdC5jb22gggzJMIIDUTCCAjmgAwIBAgICAI8wDQYJKoZIhvcN"
+            + "AQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4x"
+            + "HjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNTAxMTAwMTI5"
+            + "MTBaFw0xNTAxMTUwODAwMDBaMIGKMQswCQYDVQQGEwJVUzEWMBQGA1UECBMN"
+            + "TWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmVlZGhhbTEVMBMGA1UEChMMR2Vv"
+            + "VHJ1c3QgSW5jMRMwEQYDVQQLEwpQcm9kdWN0aW9uMSUwIwYDVQQDExxhZG9i"
+            + "ZS10aW1lc3RhbXAuZ2VvdHJ1c3QuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN"
+            + "ADCBiQKBgQDRbxJotLFPWQuuEDhKtOMaBUJepGxIvWxeahMbq1DVmqnk88+j"
+            + "w/5lfPICPzQZ1oHrcTLSAFM7Mrz3pyyQKQKMqUyiemzuG/77ESUNfBNSUfAF"
+            + "PdtHuDMU8Is8ABVnFk63L+wdlvvDIlKkE08+VTKCRdjmuBVltMpQ6QcLFQzm"
+            + "AQIDAQABo4GIMIGFMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuZ2Vv"
+            + "dHJ1c3QuY29tL2NybHMvYWRvYmVjYTEuY3JsMB8GA1UdIwQYMBaAFKuAWcNl"
+            + "g20dfRO9GcPsGo8NR2qjMA4GA1UdDwEB/wQEAwIGwDAWBgNVHSUBAf8EDDAK"
+            + "BggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAmnyXjdtX+F79Nf0KggTd"
+            + "6YC2MQD9s09IeXTd8TP3rBmizfM+7f3icggeCGakNfPRmIUMLoa0VM5Kt37T"
+            + "2X0TqzBWusfbKx7HnX4v1t/G8NJJlT4SShSHv+8bjjU4lUoCmW2oEcC5vXwP"
+            + "R5JfjCyois16npgcO05ZBT+LLDXyeBijE6qWmwLDfEpLyILzVRmyU4IE7jvm"
+            + "rgb3GXwDUvd3yQXGRRHbPCh3nj9hBGbuzyt7GnlqnEie3wzIyMG2ET/wvTX5"
+            + "4BFXKNe7lDLvZj/MXvd3V7gMTSVW0kAszKao56LfrVTgp1VX3UBQYwmQqaoA"
+            + "UwFezih+jEvjW6cYJo/ErDCCBKEwggOJoAMCAQICBD4cvSgwDQYJKoZIhvcN"
+            + "AQEFBQAwaTELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMg"
+            + "SW5jb3Jwb3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEW"
+            + "MBQGA1UEAxMNQWRvYmUgUm9vdCBDQTAeFw0wMzAxMDgyMzM3MjNaFw0yMzAx"
+            + "MDkwMDA3MjNaMGkxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0"
+            + "ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2Vydmlj"
+            + "ZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA"
+            + "A4IBDwAwggEKAoIBAQDMT1SE96ei5zNTfz+cEohrLJlHZ34PHrmtFIj5wxDY"
+            + "HfDw1Z9pCi9ZNbDMbKlMnBWgn84gv6DPVOLgIGZFPzmGOH6cxI4HIsYk9gES"
+            + "sDXfVeppkLDbhTce4k4HskKhahNpoGbqgJERWSqbCHlaIEQtyb1zOIs8L+BD"
+            + "G12zC/CvNRop/u+mkt2BTJ09WY6tMTxAfpuRNgb84lyN0Y0m1VxFz69lP7Gq"
+            + "0mKW9Kg46rpgQvT0HEo1Fc74TiJWD5UYxfiWn5/7sLd4JemAa73WCvDGdJSd"
+            + "8w9Q25p3zktwgyONoMp4IERcPFRk8eqiMBmf6kwGTQZ4S16S3yLSyWezetIB"
+            + "AgMBAAGjggFPMIIBSzARBglghkgBhvhCAQEEBAMCAAcwgY4GA1UdHwSBhjCB"
+            + "gzCBgKB+oHykejB4MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lz"
+            + "dGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZp"
+            + "Y2VzMRYwFAYDVQQDEw1BZG9iZSBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCsG"
+            + "A1UdEAQkMCKADzIwMDMwMTA4MjMzNzIzWoEPMjAyMzAxMDkwMDA3MjNaMAsG"
+            + "A1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jAd"
+            + "BgNVHQ4EFgQUgrc4SpOqmxDvgLvZVOLxD/uAnN4wDAYDVR0TBAUwAwEB/zAd"
+            + "BgkqhkiG9n0HQQAEEDAOGwhWNi4wOjQuMAMCBJAwDQYJKoZIhvcNAQEFBQAD"
+            + "ggEBADLan0N1wfpvyW/bqx02Nz68YRk2twI8HSNZmGye7k2F51TIIB+n1Lvi"
+            + "vwB3fSRrcC9cwTp2SbXT4COEKnFqIvPBJymYFfY1kOQETMONvJ9hHOf9JIzR"
+            + "REOMFrqbTaXUNS+8Ec6991E3jZ+Q5BTxGD++6VkSNfkzkvOe4NVrmnGbmUvI"
+            + "ccPhsWEJxOX6kfBCOjd9NPly6M2qYhwh6dX0ghDjewW2LWhWC35+kixvTXKC"
+            + "DO1WdLKduastKx0QX9sndXCP/R3X4gKgeeUc5f+vZEBRLZ6bR9tCpXwfwqZI"
+            + "sNe+kmlNpPYpV8V4ERjch1HKE7JinU8rMr0xpcH6UqsFiMgwggTLMIIDs6AD"
+            + "AgECAgQ+HL21MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVTMSMwIQYD"
+            + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv"
+            + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwHhcN"
+            + "MDQwMTE3MDAwMzM5WhcNMTUwMTE1MDgwMDAwWjBFMQswCQYDVQQGEwJVUzEW"
+            + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0Eg"
+            + "Zm9yIEFkb2JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+V3"
+            + "4GR4Wuc5hbyv0vVbKBMOVN1J+s5i9ZL9nph7n+X4esFs4epAJcFxJ4KnPuQH"
+            + "ZZ0oyHUU4Th70mWYgKwd6sEt1aR6ZT788Nvr3OHwTRwugN/G6QXqhU9ePpZJ"
+            + "OF1Ibsf1pcXNGvpLdcYK6+CX5DANMuIthb440XoNfC3dNBC0pF4mM4lmTjpl"
+            + "nQG8xK0rIFp4HoMpmyaIijz2qyjXdUNkg0fbDUq9eDTKAOLOg21u+AA8XKbC"
+            + "ewg1LWSV9CVy+fTHREmb1thBcrfkY1kCAvczsuquV3SMx8hRpa+4cIvKK/K1"
+            + "G7OrV0nsTyuaJ2MMST8b7bul/Xd81nu9Hsz4iQIDAQABo4IBnTCCAZkwEgYD"
+            + "VR0TAQH/BAgwBgEB/wIBATBQBgNVHSAESTBHMEUGCSqGSIb3LwECATA4MDYG"
+            + "CCsGAQUFBwIBFipodHRwczovL3d3dy5hZG9iZS5jb20vbWlzYy9wa2kvY2Rz"
+            + "X2NwLmh0bWwwFAYDVR0lBA0wCwYJKoZIhvcvAQEFMIGyBgNVHR8Egaowgacw"
+            + "IqAgoB6GHGh0dHA6Ly9jcmwuYWRvYmUuY29tL2Nkcy5jcmwwgYCgfqB8pHow"
+            + "eDELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jw"
+            + "b3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UE"
+            + "AxMNQWRvYmUgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTALBgNVHQ8EBAMCAQYw"
+            + "HwYDVR0jBBgwFoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFKuA"
+            + "WcNlg20dfRO9GcPsGo8NR2qjMBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQ"
+            + "MA0GCSqGSIb3DQEBBQUAA4IBAQA/OVkuogCOsV4RYSzS4Lb1jImGRc4T2Z/d"
+            + "hJoUawhMX4aXWPSlqNOPIfhHflCvd+Whbarcd83NN5n3QmevUOFUREPrMQyA"
+            + "mkK0mpW6TSyLG5ckeCFL8qJwp/hhckk/H16m4hEXWyIFGfOecX3Sy+Y4kxcC"
+            + "lzSMadifedB+TiRpKFKcNphp5hEMkpyyJaGXpLnN/BLsaDyEN7JySExAopae"
+            + "UbUJCvCVIWKwoJ26ih3BG1aB+3yTHXeLIorextqWbq+dVz7me59Li8j5PAxe"
+            + "hXrc2phpKuhp8FaTScvnfMZc8TL4Dr1CHMRWIkqfZaCq3mC376Mww0iZtE5s"
+            + "iqB+AXVWMYIBgDCCAXwCAQEwSzBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN"
+            + "R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0EgZm9yIEFkb2Jl"
+            + "AgIAjzAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB"
+            + "BDAcBgkqhkiG9w0BCQUxDxcNMDYwNDA0MjAyMDU3WjAjBgkqhkiG9w0BCQQx"
+            + "FgQUp7AnXBqoNcarvO7fMJut1og2U5AwKwYLKoZIhvcNAQkQAgwxHDAaMBgw"
+            + "FgQU1dH4eZTNhgxdiSABrat6zsPdth0wDQYJKoZIhvcNAQEBBQAEgYCinr/F"
+            + "rMiQz/MRm9ZD5YGcC0Qo2dRTPd0Aop8mZ4g1xAhKFLnp7lLsjCbkSDpVLDBh"
+            + "cnCk7CV+3FT5hlvt8OqZlR0CnkSnCswLFhrppiWle6cpxlwGqyAteC8uKtQu"
+            + "wjE5GtBKLcCOAzQYyyuNZZeB6oCZ+3mPhZ62FxrvvEGJCgAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
+            + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==");
+
+        private static readonly byte[] emptyDNCert = Base64.Decode(
+              "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD"
+            + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl"
+            + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw"
+            + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT"
+            + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ"
+            + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB"
+            + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV"
+            + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW"
+            + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA"
+            + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b"
+            + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc"
+            + "EHdUp0lioOCt6UOw7Cs=");
+
+        private static readonly byte[] gostRFC4491_94 = Base64.Decode(
+            "MIICCzCCAboCECMO42BGlSTOxwvklBgufuswCAYGKoUDAgIEMGkxHTAbBgNVBAMM" +
+            "FEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlwdG9Qcm8xCzAJBgNV" +
+            "BAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAtOTRAZXhhbXBsZS5jb20w" +
+            "HhcNMDUwODE2MTIzMjUwWhcNMTUwODE2MTIzMjUwWjBpMR0wGwYDVQQDDBRHb3N0" +
+            "UjM0MTAtOTQgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYDVQQGEwJS" +
+            "VTEnMCUGCSqGSIb3DQEJARYYR29zdFIzNDEwLTk0QGV4YW1wbGUuY29tMIGlMBwG" +
+            "BiqFAwICFDASBgcqhQMCAiACBgcqhQMCAh4BA4GEAASBgLuEZuF5nls02CyAfxOo" +
+            "GWZxV/6MVCUhR28wCyd3RpjG+0dVvrey85NsObVCNyaE4g0QiiQOHwxCTSs7ESuo" +
+            "v2Y5MlyUi8Go/htjEvYJJYfMdRv05YmKCYJo01x3pg+2kBATjeM+fJyR1qwNCCw+" +
+            "eMG1wra3Gqgqi0WBkzIydvp7MAgGBiqFAwICBANBABHHCH4S3ALxAiMpR3aPRyqB" +
+            "g1DjB8zy5DEjiULIc+HeIveF81W9lOxGkZxnrFjXBSqnjLeFKgF1hffXOAP7zUM=");
+
+        private static readonly byte[] gostRFC4491_2001 = Base64.Decode(
+            "MIIB0DCCAX8CECv1xh7CEb0Xx9zUYma0LiEwCAYGKoUDAgIDMG0xHzAdBgNVBAMM" +
+            "Fkdvc3RSMzQxMC0yMDAxIGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1BybzELMAkG" +
+            "A1UEBhMCUlUxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDAxQGV4YW1wbGUu" +
+            "Y29tMB4XDTA1MDgxNjE0MTgyMFoXDTE1MDgxNjE0MTgyMFowbTEfMB0GA1UEAwwW" +
+            "R29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYD" +
+            "VQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIwMDFAZXhhbXBsZS5j" +
+            "b20wYzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARAhJVodWACGkB1" +
+            "CM0TjDGJLP3lBQN6Q1z0bSsP508yfleP68wWuZWIA9CafIWuD+SN6qa7flbHy7Df" +
+            "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" +
+            "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i");
+
+        private class DudPublicKey
+            : AsymmetricKeyParameter
+        {
+            public DudPublicKey()
+                : base(false)
+            {
+            }
+
+            public string Algorithm
+            {
+                get { return null; }
+            }
+
+            public string Format
+            {
+                get { return null; }
+            }
+
+            public byte[] GetEncoded()
+            {
+                return null;
+            }
+        }
+
+        private AsymmetricKeyParameter dudPublicKey = new DudPublicKey();
+
+        public override string Name
+        {
+            get { return "CertTest"; }
+        }
+
+        internal void checkCertificate(
+            int		id,
+            byte[]	bytes)
+        {
+            string dump = "";
+
+            try
+            {
+                X509Certificate cert = new X509CertificateParser().ReadCertificate(bytes);
+
+                AsymmetricKeyParameter k = cert.GetPublicKey();
+                // Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail(dump + SimpleTest.NewLine + Name + ": "+ id + " failed - exception " + e.Message, e);
+            }
+        }
+
+        internal void checkNameCertificate(
+            int     id,
+            byte[]  bytes)
+        {
+            string dump = "";
+
+            try
+            {
+                X509Certificate cert = new X509CertificateParser().ReadCertificate(bytes);
+
+                AsymmetricKeyParameter k = cert.GetPublicKey();
+                if (!cert.IssuerDN.ToString().Equals("C=DE,O=DATEV eG,0.2.262.1.10.7.20=1+CN=CA DATEV D03 1:PN"))
+                {
+                    Fail(id + " failed - name test.");
+                }
+                // Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail(dump + SimpleTest.NewLine + Name + ": "+ id + " failed - exception " + e.Message, e);
+            }
+
+        }
+
+        internal void checkKeyUsage(
+            int		id,
+            byte[]	bytes)
+        {
+            string dump = "";
+
+            try
+            {
+                X509Certificate cert = new X509CertificateParser().ReadCertificate(bytes);
+
+                AsymmetricKeyParameter k = cert.GetPublicKey();
+
+                if (cert.GetKeyUsage()[7])
+                {
+                    Fail("error generating cert - key usage wrong.");
+                }
+
+                // Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail(dump + SimpleTest.NewLine + Name + ": "+ id + " failed - exception " + e.Message, e);
+            }
+
+        }
+
+        internal void checkSelfSignedCertificate(
+            int     id,
+            byte[]  bytes)
+        {
+            string dump = "";
+
+            try
+            {
+                X509Certificate cert = new X509CertificateParser().ReadCertificate(bytes);
+
+                AsymmetricKeyParameter k = cert.GetPublicKey();
+
+                cert.Verify(k);
+                // Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail(dump + SimpleTest.NewLine + Name + ": "+ id + " failed - exception " + e.Message, e);
+            }
+        }
+
+        /**
+         * we Generate a self signed certificate for the sake of testing - RSA
+         */
+        internal void checkCreation1()
+        {
+            //
+            // a sample key pair.
+            //
+            RsaKeyParameters pubKey = new RsaKeyParameters(
+                false,
+                new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+                new BigInteger("11", 16));
+
+            RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+                new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+                new BigInteger("11", 16),
+                new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+                new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+                new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+                new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+                new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+                new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+            //
+            // set up the keys
+            //
+//			AsymmetricKeyParameter privKey;
+//			AsymmetricKeyParameter pubKey;
+
+//			KeyFactory  fact = KeyFactory.GetInstance("RSA");
+//
+//			privKey = fact.generatePrivate(privKeySpec);
+//			pubKey = fact.generatePublic(pubKeySpec);
+
+            //
+            // distinguished name table.
+            //
+            IList ord = new ArrayList();
+            ord.Add(X509Name.C);
+            ord.Add(X509Name.O);
+            ord.Add(X509Name.L);
+            ord.Add(X509Name.ST);
+            ord.Add(X509Name.E);
+
+            IList values = new ArrayList();
+            values.Add("AU");
+            values.Add("The Legion of the Bouncy Castle");
+            values.Add("Melbourne");
+            values.Add("Victoria");
+            values.Add("feedback-crypto@bouncycastle.org");
+
+            //
+            // extensions
+            //
+
+            //
+            // create the certificate - version 3 - without extensions
+            //
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(ord, values));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(ord, values));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+            X509Certificate cert = certGen.Generate(privKey);
+
+            cert.CheckValidity(DateTime.UtcNow);
+
+            cert.Verify(pubKey);
+
+            ISet dummySet = cert.GetNonCriticalExtensionOids();
+            if (dummySet != null)
+            {
+                Fail("non-critical oid set should be null");
+            }
+            dummySet = cert.GetCriticalExtensionOids();
+            if (dummySet != null)
+            {
+                Fail("critical oid set should be null");
+            }
+
+            //
+            // create the certificate - version 3 - with extensions
+            //
+            certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(ord, values));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(ord, values));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("MD5WithRSAEncryption");
+            certGen.AddExtension("2.5.29.15", true,
+                new X509KeyUsage(X509KeyUsage.EncipherOnly));
+            certGen.AddExtension("2.5.29.37", true,
+                new DerSequence(KeyPurposeID.AnyExtendedKeyUsage));
+            certGen.AddExtension("2.5.29.17", true,
+                new GeneralNames(new GeneralName(GeneralName.Rfc822Name, "test@test.test")));
+
+            cert = certGen.Generate(privKey);
+
+            cert.CheckValidity(DateTime.UtcNow);
+
+            cert.Verify(pubKey);
+
+            cert = new X509CertificateParser().ReadCertificate(cert.GetEncoded());
+
+            if (!cert.GetKeyUsage()[7])
+            {
+                Fail("error generating cert - key usage wrong.");
+            }
+
+            IList l = cert.GetExtendedKeyUsage();
+            if (!l[0].Equals(KeyPurposeID.AnyExtendedKeyUsage.Id))
+            {
+                Fail("failed extended key usage test");
+            }
+
+            foreach (IList gn in cert.GetSubjectAlternativeNames())
+            {
+                if (!gn[1].Equals("test@test.test"))
+                {
+                    Fail("failed subject alternative names test");
+                }
+            }
+
+            // Console.WriteLine(cert);
+
+            //
+            // create the certificate - version 1
+            //
+            X509V1CertificateGenerator certGen1 = new X509V1CertificateGenerator();
+
+            certGen1.SetSerialNumber(BigInteger.One);
+            certGen1.SetIssuerDN(new X509Name(ord, values));
+            certGen1.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen1.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen1.SetSubjectDN(new X509Name(ord, values));
+            certGen1.SetPublicKey(pubKey);
+            certGen1.SetSignatureAlgorithm("MD5WithRSAEncryption");
+
+            cert = certGen1.Generate(privKey);
+
+            cert.CheckValidity(DateTime.UtcNow);
+
+            cert.Verify(pubKey);
+
+            cert = new X509CertificateParser().ReadCertificate(cert.GetEncoded());
+
+            // Console.WriteLine(cert);
+            if (!cert.IssuerDN.Equivalent(cert.SubjectDN))
+            {
+                Fail("name comparison fails");
+            }
+        }
+
+        /**
+         * we Generate a self signed certificate for the sake of testing - DSA
+         */
+        internal void checkCreation2()
+        {
+            //
+            // set up the keys
+            //
+            AsymmetricKeyParameter privKey;
+            AsymmetricKeyParameter pubKey;
+
+            try
+            {
+//				KeyPairGenerator g = KeyPairGenerator.GetInstance("DSA", "SUN");
+//				g.initialize(512, new SecureRandom());
+//				KeyPair p = g.generateKeyPair();
+                IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("DSA");
+                DsaParametersGenerator dpg = new DsaParametersGenerator();
+                dpg.Init(512, 25, new SecureRandom());
+                g.Init(new DsaKeyGenerationParameters(new SecureRandom(), dpg.GenerateParameters()));
+                AsymmetricCipherKeyPair p = g.GenerateKeyPair();
+
+                privKey = p.Private;
+                pubKey = p.Public;
+            }
+            catch (Exception e)
+            {
+                Fail("error setting up keys - " + e.ToString());
+                return;
+            }
+
+            //
+            // distinguished name table.
+            //
+            IList ord = new ArrayList();
+            ord.Add(X509Name.C);
+            ord.Add(X509Name.O);
+            ord.Add(X509Name.L);
+            ord.Add(X509Name.ST);
+            ord.Add(X509Name.E);
+
+            IList values = new ArrayList();
+            values.Add("AU");
+            values.Add("The Legion of the Bouncy Castle");
+            values.Add("Melbourne");
+            values.Add("Victoria");
+            values.Add("feedback-crypto@bouncycastle.org");
+
+            //
+            // extensions
+            //
+
+            //
+            // create the certificate - version 3
+            //
+            X509V3CertificateGenerator  certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(ord, values));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(ord, values));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("SHA1withDSA");
+
+            try
+            {
+                X509Certificate cert = certGen.Generate(privKey);
+
+                cert.CheckValidity(DateTime.UtcNow);
+
+                cert.Verify(pubKey);
+
+                cert = new X509CertificateParser().ReadCertificate(cert.GetEncoded());
+
+                // Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail("error setting generating cert - " + e.ToString());
+            }
+
+            //
+            // create the certificate - version 1
+            //
+            X509V1CertificateGenerator certGen1 = new X509V1CertificateGenerator();
+
+            certGen1.SetSerialNumber(BigInteger.One);
+            certGen1.SetIssuerDN(new X509Name(ord, values));
+            certGen1.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen1.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen1.SetSubjectDN(new X509Name(ord, values));
+            certGen1.SetPublicKey(pubKey);
+            certGen1.SetSignatureAlgorithm("SHA1withDSA");
+
+            try
+            {
+                X509Certificate cert = certGen1.Generate(privKey);
+
+                cert.CheckValidity(DateTime.UtcNow);
+
+                cert.Verify(pubKey);
+
+                cert = new X509CertificateParser().ReadCertificate(cert.GetEncoded());
+
+                //Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail("error setting generating cert - " + e.ToString());
+            }
+
+            //
+            // exception test
+            //
+            try
+            {
+                certGen.SetPublicKey(dudPublicKey);
+
+                Fail("key without encoding not detected in v1");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        /**
+         * we Generate a self signed certificate for the sake of testing - ECDSA
+         */
+        internal void checkCreation3()
+        {
+            ECCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters spec = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+            ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+                spec);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(Hex.Decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+                spec);
+
+            //
+            // set up the keys
+            //
+//			AsymmetricKeyParameter privKey;
+//			AsymmetricKeyParameter pubKey;
+//
+//			try
+//			{
+//				KeyFactory fact = KeyFactory.GetInstance("ECDSA");
+//
+//				privKey = fact.generatePrivate(privKeySpec);
+//				pubKey = fact.generatePublic(pubKeySpec);
+//			}
+//			catch (Exception e)
+//			{
+//				Fail("error setting up keys - " + e.ToString());
+//				return;
+//			}
+
+            //
+            // distinguished name table.
+            //
+            IDictionary attrs = new Hashtable();
+            IList order = new ArrayList();
+
+            attrs.Add(X509Name.C, "AU");
+            attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+            attrs.Add(X509Name.L, "Melbourne");
+            attrs.Add(X509Name.ST, "Victoria");
+            attrs.Add(X509Name.E, "feedback-crypto@bouncycastle.org");
+
+            order.Add(X509Name.C);
+            order.Add(X509Name.O);
+            order.Add(X509Name.L);
+            order.Add(X509Name.ST);
+            order.Add(X509Name.E);
+
+
+            //
+            // ToString test
+            //
+            X509Name p = new X509Name(order, attrs);
+            string s = p.ToString();
+
+            if (!s.Equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne,ST=Victoria,E=feedback-crypto@bouncycastle.org"))
+            {
+                Fail("ordered X509Principal test failed - s = " + s + ".");
+            }
+
+            //
+            // create the certificate - version 3
+            //
+            X509V3CertificateGenerator  certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(order, attrs));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(order, attrs));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("SHA1withECDSA");
+
+            try
+            {
+                X509Certificate cert = certGen.Generate(privKey);
+
+                cert.CheckValidity(DateTime.UtcNow);
+
+                cert.Verify(pubKey);
+
+                X509CertificateParser fact = new X509CertificateParser();
+                cert = fact.ReadCertificate(cert.GetEncoded());
+
+                //
+                // try with point compression turned off
+                //
+//				((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+                ECPoint q = pubKey.Q.Normalize();
+                pubKey = new ECPublicKeyParameters(
+                    pubKey.AlgorithmName,
+                    q.Curve.CreatePoint(q.XCoord.ToBigInteger(), q.YCoord.ToBigInteger()),
+                    pubKey.Parameters);
+
+                certGen.SetPublicKey(pubKey);
+
+                cert = certGen.Generate(privKey);
+
+                cert.CheckValidity(DateTime.UtcNow);
+
+                cert.Verify(pubKey);
+
+                cert = fact.ReadCertificate(cert.GetEncoded());
+
+                // Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail("error setting generating cert - " + e.ToString());
+            }
+
+            X509Name pr = new X509Name("O=\"The Bouncy Castle, The Legion of\",E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+            if (!pr.ToString().Equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+            {
+                Fail("string based X509Principal test failed.");
+            }
+
+            pr = new X509Name("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU");
+
+            if (!pr.ToString().Equals("O=The Bouncy Castle\\, The Legion of,E=feedback-crypto@bouncycastle.org,ST=Victoria,L=Melbourne,C=AU"))
+            {
+                Fail("string based X509Principal test failed.");
+            }
+        }
+
+        /**
+         * we Generate a self signed certificate for the sake of testing - SHA224withECDSA
+         */
+        private void createECCert(
+            string				algorithm,
+            DerObjectIdentifier	algOid)
+        {
+            FpCurve curve = new FpCurve(
+                new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16),   // a
+                new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16));  // b
+
+            ECDomainParameters spec = new ECDomainParameters(
+                curve,
+//				curve.DecodePoint(Hex.Decode("02C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+                curve.DecodePoint(Hex.Decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+            ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+                spec);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+//				curve.DecodePoint(Hex.Decode("026BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+                curve.DecodePoint(Hex.Decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+                spec);
+
+//			//
+//			// set up the keys
+//			//
+//			AsymmetricKeyParameter privKey;
+//			AsymmetricKeyParameter pubKey;
+//
+//			KeyFactory fact = KeyFactory.GetInstance("ECDSA");
+//
+//			privKey = fact.generatePrivate(privKeySpec);
+//			pubKey = fact.generatePublic(pubKeySpec);
+
+
+            //
+            // distinguished name table.
+            //
+            IDictionary attrs = new Hashtable();
+            IList order = new ArrayList();
+
+            attrs.Add(X509Name.C, "AU");
+            attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+            attrs.Add(X509Name.L, "Melbourne");
+            attrs.Add(X509Name.ST, "Victoria");
+            attrs.Add(X509Name.E, "feedback-crypto@bouncycastle.org");
+
+            order.Add(X509Name.C);
+            order.Add(X509Name.O);
+            order.Add(X509Name.L);
+            order.Add(X509Name.ST);
+            order.Add(X509Name.E);
+
+            //
+            // create the certificate - version 3
+            //
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(order, attrs));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(order, attrs));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm(algorithm);
+
+
+            X509Certificate cert = certGen.Generate(privKey);
+
+            cert.CheckValidity(DateTime.UtcNow);
+
+            cert.Verify(pubKey);
+
+            X509CertificateParser fact = new X509CertificateParser();
+            cert = fact.ReadCertificate(cert.GetEncoded());
+
+            //
+            // try with point compression turned off
+            //
+//			((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+            ECPoint q = pubKey.Q.Normalize();
+            pubKey = new ECPublicKeyParameters(
+                pubKey.AlgorithmName,
+                q.Curve.CreatePoint(q.XCoord.ToBigInteger(), q.YCoord.ToBigInteger()),
+                pubKey.Parameters);
+
+            certGen.SetPublicKey(pubKey);
+
+            cert = certGen.Generate(privKey);
+
+            cert.CheckValidity(DateTime.UtcNow);
+
+            cert.Verify(pubKey);
+
+            cert = fact.ReadCertificate(cert.GetEncoded());
+
+            if (!cert.SigAlgOid.Equals(algOid.ToString()))
+            {
+                Fail("ECDSA oid incorrect.");
+            }
+
+            if (cert.GetSigAlgParams() != null)
+            {
+                Fail("sig parameters present");
+            }
+
+            ISigner sig = SignerUtilities.GetSigner(algorithm);
+
+            sig.Init(false, pubKey);
+
+            byte[] b = cert.GetTbsCertificate();
+            sig.BlockUpdate(b, 0, b.Length);
+
+            if (!sig.VerifySignature(cert.GetSignature()))
+            {
+                Fail("EC certificate signature not mapped correctly.");
+            }
+            // Console.WriteLine(cert);
+        }
+
+        private void checkCrl(
+            int     id,
+            byte[]  bytes)
+        {
+            string dump = "";
+
+            try
+            {
+                X509Crl cert = new X509CrlParser().ReadCrl(bytes);
+
+                // Console.WriteLine(cert);
+            }
+            catch (Exception e)
+            {
+                Fail(dump + SimpleTest.NewLine + Name + ": "+ id + " failed - exception " + e.Message, e);
+            }
+
+        }
+
+        private void checkCrlCreation1()
+        {
+            IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            kpGen.Init(
+                new RsaKeyGenerationParameters(
+                    BigInteger.ValueOf(0x10001), new SecureRandom(), 768, 25));
+
+            X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
+            DateTime now = DateTime.UtcNow;
+            AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+            crlGen.SetIssuerDN(new X509Name("CN=Test CA"));
+
+            crlGen.SetThisUpdate(now);
+            crlGen.SetNextUpdate(now.AddSeconds(100));
+            crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+            crlGen.AddCrlEntry(BigInteger.One, now, CrlReason.PrivilegeWithdrawn);
+
+            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false,
+                new AuthorityKeyIdentifierStructure(pair.Public));
+
+            X509Crl crl = crlGen.Generate(pair.Private);
+
+            if (!crl.IssuerDN.Equivalent(new X509Name("CN=Test CA"), true))
+            {
+                Fail("failed CRL issuer test");
+            }
+
+            Asn1OctetString authExt = crl.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
+
+            if (authExt == null)
+            {
+                Fail("failed to find CRL extension");
+            }
+
+            AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+            X509CrlEntry entry = crl.GetRevokedCertificate(BigInteger.One);
+
+            if (entry == null)
+            {
+                Fail("failed to find CRL entry");
+            }
+
+            if (!entry.SerialNumber.Equals(BigInteger.One))
+            {
+                Fail("CRL cert serial number does not match");
+            }
+
+            if (!entry.HasExtensions)
+            {
+                Fail("CRL entry extension not found");
+            }
+
+            Asn1OctetString ext = entry.GetExtensionValue(X509Extensions.ReasonCode);
+
+            if (ext != null)
+            {
+                DerEnumerated reasonCode = (DerEnumerated)X509ExtensionUtilities.FromExtensionValue(ext);
+
+                if (reasonCode.Value.IntValue != CrlReason.PrivilegeWithdrawn)
+                {
+                    Fail("CRL entry reasonCode wrong");
+                }
+            }
+            else
+            {
+                Fail("CRL entry reasonCode not found");
+            }
+        }
+
+        private void checkCrlCreation2()
+        {
+            IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            kpGen.Init(
+                new RsaKeyGenerationParameters(
+                    BigInteger.ValueOf(0x10001), new SecureRandom(), 768, 25));
+
+            X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
+            DateTime now = DateTime.UtcNow;
+            AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+            crlGen.SetIssuerDN(new X509Name("CN=Test CA"));
+
+            crlGen.SetThisUpdate(now);
+            crlGen.SetNextUpdate(now.AddSeconds(100));
+            crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+            IList extOids = new ArrayList();
+            IList extValues = new ArrayList();
+
+            CrlReason crlReason = new CrlReason(CrlReason.PrivilegeWithdrawn);
+
+            try
+            {
+                extOids.Add(X509Extensions.ReasonCode);
+                extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
+            }
+            catch (IOException e)
+            {
+                throw new ArgumentException("error encoding reason: " + e);
+            }
+
+            X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+            crlGen.AddCrlEntry(BigInteger.One, now, entryExtensions);
+
+            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.Public));
+
+            X509Crl crl = crlGen.Generate(pair.Private);
+
+            if (!crl.IssuerDN.Equivalent(new X509Name("CN=Test CA"), true))
+            {
+                Fail("failed CRL issuer test");
+            }
+
+            Asn1OctetString authExt = crl.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
+
+            if (authExt == null)
+            {
+                Fail("failed to find CRL extension");
+            }
+
+            AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+            X509CrlEntry entry = crl.GetRevokedCertificate(BigInteger.One);
+
+            if (entry == null)
+            {
+                Fail("failed to find CRL entry");
+            }
+
+            if (!entry.SerialNumber.Equals(BigInteger.One))
+            {
+                Fail("CRL cert serial number does not match");
+            }
+
+            if (!entry.HasExtensions)
+            {
+                Fail("CRL entry extension not found");
+            }
+
+            Asn1OctetString ext = entry.GetExtensionValue(X509Extensions.ReasonCode);
+
+            if (ext != null)
+            {
+                DerEnumerated reasonCode = (DerEnumerated)X509ExtensionUtilities.FromExtensionValue(ext);
+
+                if (reasonCode.Value.IntValue != CrlReason.PrivilegeWithdrawn)
+                {
+                    Fail("CRL entry reasonCode wrong");
+                }
+            }
+            else
+            {
+                Fail("CRL entry reasonCode not found");
+            }
+        }
+
+        private void checkCrlCreation3()
+        {
+            IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            kpGen.Init(
+                new RsaKeyGenerationParameters(
+                    BigInteger.ValueOf(0x10001), new SecureRandom(), 768, 25));
+
+            X509V2CrlGenerator crlGen = new X509V2CrlGenerator();
+            DateTime now = DateTime.UtcNow;
+            AsymmetricCipherKeyPair pair = kpGen.GenerateKeyPair();
+
+            crlGen.SetIssuerDN(new X509Name("CN=Test CA"));
+
+            crlGen.SetThisUpdate(now);
+            crlGen.SetNextUpdate(now.AddSeconds(100));
+            crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+            IList extOids = new ArrayList();
+            IList extValues = new ArrayList();
+
+            CrlReason crlReason = new CrlReason(CrlReason.PrivilegeWithdrawn);
+
+            try
+            {
+                extOids.Add(X509Extensions.ReasonCode);
+                extValues.Add(new X509Extension(false, new DerOctetString(crlReason.GetEncoded())));
+            }
+            catch (IOException e)
+            {
+                throw new ArgumentException("error encoding reason: " + e);
+            }
+
+            X509Extensions entryExtensions = new X509Extensions(extOids, extValues);
+
+            crlGen.AddCrlEntry(BigInteger.One, now, entryExtensions);
+
+            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.Public));
+
+            X509Crl crl = crlGen.Generate(pair.Private);
+
+            if (!crl.IssuerDN.Equivalent(new X509Name("CN=Test CA"), true))
+            {
+                Fail("failed CRL issuer test");
+            }
+
+            Asn1OctetString authExt = crl.GetExtensionValue(X509Extensions.AuthorityKeyIdentifier);
+
+            if (authExt == null)
+            {
+                Fail("failed to find CRL extension");
+            }
+
+            AuthorityKeyIdentifier authId = new AuthorityKeyIdentifierStructure(authExt);
+
+            X509CrlEntry entry = crl.GetRevokedCertificate(BigInteger.One);
+
+            if (entry == null)
+            {
+                Fail("failed to find CRL entry");
+            }
+
+            if (!entry.SerialNumber.Equals(BigInteger.One))
+            {
+                Fail("CRL cert serial number does not match");
+            }
+
+            if (!entry.HasExtensions)
+            {
+                Fail("CRL entry extension not found");
+            }
+
+            Asn1OctetString ext = entry.GetExtensionValue(X509Extensions.ReasonCode);
+
+            if (ext != null)
+            {
+                DerEnumerated reasonCode = (DerEnumerated)X509ExtensionUtilities.FromExtensionValue(ext);
+
+                if (reasonCode.Value.IntValue != CrlReason.PrivilegeWithdrawn)
+                {
+                    Fail("CRL entry reasonCode wrong");
+                }
+            }
+            else
+            {
+                Fail("CRL entry reasonCode not found");
+            }
+
+            //
+            // check loading of existing CRL
+            //
+            crlGen = new X509V2CrlGenerator();
+            now = DateTime.UtcNow;
+
+            crlGen.SetIssuerDN(new X509Name("CN=Test CA"));
+
+            crlGen.SetThisUpdate(now);
+            crlGen.SetNextUpdate(now.AddSeconds(100));
+            crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+            crlGen.AddCrl(crl);
+
+            crlGen.AddCrlEntry(BigInteger.Two, now, entryExtensions);
+
+            crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(pair.Public));
+
+            X509Crl newCrl = crlGen.Generate(pair.Private);
+
+            int count = 0;
+            bool oneFound = false;
+            bool twoFound = false;
+
+            foreach (X509CrlEntry crlEnt in newCrl.GetRevokedCertificates())
+            {
+                if (crlEnt.SerialNumber.IntValue == 1)
+                {
+                    oneFound = true;
+                }
+                else if (crlEnt.SerialNumber.IntValue == 2)
+                {
+                    twoFound = true;
+                }
+
+                count++;
+            }
+
+            if (count != 2)
+            {
+                Fail("wrong number of CRLs found");
+            }
+
+            if (!oneFound || !twoFound)
+            {
+                Fail("wrong CRLs found in copied list");
+            }
+
+            //
+            // check factory read back
+            //
+            X509Crl readCrl = new X509CrlParser().ReadCrl(newCrl.GetEncoded());
+
+            if (readCrl == null)
+            {
+                Fail("crl not returned!");
+            }
+
+//			ICollection col = cFact.generateCRLs(new ByteArrayInputStream(newCrl.getEncoded()));
+            ICollection col = new X509CrlParser().ReadCrls(newCrl.GetEncoded());
+
+            if (col.Count != 1)
+            {
+                Fail("wrong number of CRLs found in collection");
+            }
+        }
+
+        /**
+         * we Generate a self signed certificate for the sake of testing - GOST3410
+         */
+        internal void checkCreation4()
+        {
+            //
+            // set up the keys
+            //
+            AsymmetricKeyParameter privKey;
+            AsymmetricKeyParameter pubKey;
+
+//			GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec("GostR3410-94-CryptoPro-A");
+//			g.initialize(gost3410P, new SecureRandom());
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("GOST3410");
+            g.Init(
+                new Gost3410KeyGenerationParameters(
+                    new SecureRandom(),
+                    CryptoProObjectIdentifiers.GostR3410x94CryptoProA));
+
+            AsymmetricCipherKeyPair p = g.GenerateKeyPair();
+
+            privKey = p.Private;
+            pubKey = p.Public;
+
+            //
+            // distinguished name table.
+            //
+            IDictionary attrs = new Hashtable();
+            attrs.Add(X509Name.C, "AU");
+            attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+            attrs.Add(X509Name.L, "Melbourne");
+            attrs.Add(X509Name.ST, "Victoria");
+            attrs.Add(X509Name.E, "feedback-crypto@bouncycastle.org");
+
+            IList order = new ArrayList();
+            order.Add(X509Name.C);
+            order.Add(X509Name.O);
+            order.Add(X509Name.L);
+            order.Add(X509Name.ST);
+            order.Add(X509Name.E);
+
+            //
+            // extensions
+            //
+
+            //
+            // create the certificate - version 3
+            //
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(order, attrs));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(order, attrs));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("GOST3411withGOST3410");
+
+            X509Certificate cert = certGen.Generate(privKey);
+
+            cert.CheckValidity(DateTime.UtcNow);
+
+            //
+            // check verifies in general
+            //
+            cert.Verify(pubKey);
+
+            //
+            // check verifies with contained key
+            //
+            cert.Verify(cert.GetPublicKey());
+
+            cert = new X509CertificateParser().ReadCertificate(cert.GetEncoded());
+
+            //Console.WriteLine(cert);
+
+            //check getEncoded()
+            byte[] bytesch = cert.GetEncoded();
+        }
+
+        internal void checkCreation5()
+        {
+            //
+            // a sample key pair.
+            //
+            RsaKeyParameters pubKey = new RsaKeyParameters(
+                false,
+                new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+                new BigInteger("11", 16));
+
+            RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+                new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+                new BigInteger("11", 16),
+                new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+                new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+                new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+                new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+                new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+                new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+            //
+            // set up the keys
+            //
+            SecureRandom rand = new SecureRandom();
+//			AsymmetricKeyParameter privKey;
+//			AsymmetricKeyParameter pubKey;
+//
+//			KeyFactory  fact = KeyFactory.GetInstance("RSA");
+//
+//			privKey = fact.generatePrivate(privKeySpec);
+//			pubKey = fact.generatePublic(pubKeySpec);
+
+            //
+            // distinguished name table.
+            //
+            IList ord = new ArrayList();
+            ord.Add(X509Name.C);
+            ord.Add(X509Name.O);
+            ord.Add(X509Name.L);
+            ord.Add(X509Name.ST);
+            ord.Add(X509Name.E);
+
+            IList values = new ArrayList();
+            values.Add("AU");
+            values.Add("The Legion of the Bouncy Castle");
+            values.Add("Melbourne");
+            values.Add("Victoria");
+            values.Add("feedback-crypto@bouncycastle.org");
+
+            //
+            // create base certificate - version 3
+            //
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(ord, values));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(ord, values));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("MD5WithRSAEncryption");
+            certGen.AddExtension("2.5.29.15", true,
+                new X509KeyUsage(X509KeyUsage.EncipherOnly));
+            certGen.AddExtension("2.5.29.37", true,
+                new DerSequence(KeyPurposeID.AnyExtendedKeyUsage));
+            certGen.AddExtension("2.5.29.17", true,
+                new GeneralNames(new GeneralName(GeneralName.Rfc822Name, "test@test.test")));
+
+            X509Certificate baseCert = certGen.Generate(privKey);
+
+            //
+            // copy certificate
+            //
+            certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(ord, values));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(ord, values));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("MD5WithRSAEncryption");
+
+            certGen.CopyAndAddExtension(new DerObjectIdentifier("2.5.29.15"), true, baseCert);
+            certGen.CopyAndAddExtension("2.5.29.37", false, baseCert);
+
+            X509Certificate cert = certGen.Generate(privKey);
+
+            cert.CheckValidity(DateTime.UtcNow);
+
+            cert.Verify(pubKey);
+
+            DerObjectIdentifier oid1 = new DerObjectIdentifier("2.5.29.15");
+            if (!baseCert.GetExtensionValue(oid1).Equals(cert.GetExtensionValue(oid1)))
+            {
+                Fail("2.5.29.15 differs");
+            }
+
+            DerObjectIdentifier oid2 = new DerObjectIdentifier("2.5.29.37");
+            if (!baseCert.GetExtensionValue(oid2).Equals(cert.GetExtensionValue(oid2)))
+            {
+                Fail("2.5.29.37 differs");
+            }
+
+            //
+            // exception test
+            //
+            try
+            {
+                certGen.CopyAndAddExtension("2.5.99.99", true, baseCert);
+
+                Fail("exception not thrown on dud extension copy");
+            }
+            catch (CertificateParsingException)
+            {
+                // expected
+            }
+
+            try
+            {
+                certGen.SetPublicKey(dudPublicKey);
+
+                certGen.Generate(privKey);
+
+                Fail("key without encoding not detected in v3");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        private void doTestForgedSignature()
+        {
+            string cert = "MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV"
+                + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD"
+                + "VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa"
+                + "Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs"
+                + "YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy"
+                + "IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD"
+                + "hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u"
+                + "12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU"
+                + "DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ"
+                + "e20sRA==";
+
+            X509Certificate x509 = new X509CertificateParser().ReadCertificate(Base64.Decode(cert));
+
+            try
+            {
+                x509.Verify(x509.GetPublicKey());
+
+                Fail("forged RSA signature passed");
+            }
+            catch (Exception)
+            {
+                // expected
+            }
+        }
+
+        private void pemTest()
+        {
+            X509Certificate cert = readPemCert(PemData.CERTIFICATE_1);
+            if (cert == null)
+            {
+                Fail("PEM cert not read");
+            }
+            cert = readPemCert("-----BEGIN CERTIFICATE-----" + PemData.CERTIFICATE_2);
+            if (cert == null)
+            {
+                Fail("PEM cert with extraneous header not read");
+            }
+            X509Crl crl = new X509CrlParser().ReadCrl(Encoding.ASCII.GetBytes(PemData.CRL_1));
+            if (crl == null)
+            {
+                Fail("PEM crl not read");
+            }
+            ArrayList col = new ArrayList(
+                new X509CertificateParser().ReadCertificates(Encoding.ASCII.GetBytes(PemData.CERTIFICATE_2)));
+            if (col.Count != 1 || !col.Contains(cert))
+            {
+                Fail("PEM cert collection not right");
+            }
+            col = new ArrayList(
+                new X509CrlParser().ReadCrls(Encoding.ASCII.GetBytes(PemData.CRL_2)));
+            if (col.Count != 1 || !col.Contains(crl))
+            {
+                Fail("PEM crl collection not right");
+            }
+        }
+
+        private static X509Certificate readPemCert(
+            string pemData)
+        {
+            return new X509CertificateParser().ReadCertificate(Encoding.ASCII.GetBytes(pemData));
+        }
+
+        private void pkcs7Test()
+        {
+            Asn1Encodable rootCert = Asn1Object.FromByteArray(CertPathTest.rootCertBin);
+            Asn1Encodable rootCrl = Asn1Object.FromByteArray(CertPathTest.rootCrlBin);
+
+            X509CertificateParser certParser = new X509CertificateParser();
+            X509CrlParser crlParser = new X509CrlParser();
+
+            SignedData sigData = new SignedData(
+                DerSet.Empty,
+                new ContentInfo(CmsObjectIdentifiers.Data, null),
+                new DerSet(
+                    rootCert,
+                    new DerTaggedObject(false, 2, Asn1Object.FromByteArray(AttrCertTest.attrCert))),
+                new DerSet(rootCrl),
+                DerSet.Empty);
+
+            ContentInfo info = new ContentInfo(CmsObjectIdentifiers.SignedData, sigData);
+
+            X509Certificate cert = certParser.ReadCertificate(info.GetEncoded());
+            if (cert == null || !AreEqual(cert.GetEncoded(), rootCert.ToAsn1Object().GetEncoded()))
+            {
+                Fail("PKCS7 cert not read");
+            }
+            X509Crl crl = crlParser.ReadCrl(info.GetEncoded());
+            if (crl == null || !AreEqual(crl.GetEncoded(), rootCrl.ToAsn1Object().GetEncoded()))
+            {
+                Fail("PKCS7 crl not read");
+            }
+            ArrayList col = new ArrayList(certParser.ReadCertificates(info.GetEncoded()));
+            if (col.Count != 1 || !col.Contains(cert))
+            {
+                Fail("PKCS7 cert collection not right");
+            }
+            col = new ArrayList(crlParser.ReadCrls(info.GetEncoded()));
+            if (col.Count != 1 || !col.Contains(crl))
+            {
+                Fail("PKCS7 crl collection not right");
+            }
+
+            // data with no certificates or CRLs
+
+            sigData = new SignedData(DerSet.Empty, new ContentInfo(CmsObjectIdentifiers.Data, null), DerSet.Empty, DerSet.Empty, DerSet.Empty);
+
+            info = new ContentInfo(CmsObjectIdentifiers.SignedData, sigData);
+
+            cert = certParser.ReadCertificate(info.GetEncoded());
+            if (cert != null)
+            {
+                Fail("PKCS7 cert present");
+            }
+            crl = crlParser.ReadCrl(info.GetEncoded());
+            if (crl != null)
+            {
+                Fail("PKCS7 crl present");
+            }
+
+            // data with absent certificates and CRLS
+
+            sigData = new SignedData(DerSet.Empty, new ContentInfo(CmsObjectIdentifiers.Data, null), null, null, DerSet.Empty);
+
+            info = new ContentInfo(CmsObjectIdentifiers.SignedData, sigData);
+
+            cert = certParser.ReadCertificate(info.GetEncoded());
+            if (cert != null)
+            {
+                Fail("PKCS7 cert present");
+            }
+            crl = crlParser.ReadCrl(info.GetEncoded());
+            if (crl != null)
+            {
+                Fail("PKCS7 crl present");
+            }
+
+            //
+            // sample message
+            //
+            ICollection certCol = certParser.ReadCertificates(pkcs7CrlProblem);
+            ICollection crlCol = crlParser.ReadCrls(pkcs7CrlProblem);
+
+            if (crlCol.Count != 0)
+            {
+                Fail("wrong number of CRLs: " + crlCol.Count);
+            }
+
+            if (certCol.Count != 4)
+            {
+                Fail("wrong number of Certs: " + certCol.Count);
+            }
+        }
+
+        private void createPssCert(
+            string algorithm)
+        {
+            AsymmetricCipherKeyPair keyPair = GenerateLongFixedKeys();
+
+            AsymmetricKeyParameter privKey = keyPair.Private;
+            AsymmetricKeyParameter pubKey = keyPair.Public;
+
+            //
+            // distinguished name table.
+            //
+            IList ord = new ArrayList();
+            ord.Add(X509Name.C);
+            ord.Add(X509Name.O);
+            ord.Add(X509Name.L);
+            ord.Add(X509Name.ST);
+            ord.Add(X509Name.E);
+
+            IList values = new ArrayList();
+            values.Add("AU");
+            values.Add("The Legion of the Bouncy Castle");
+            values.Add("Melbourne");
+            values.Add("Victoria");
+            values.Add("feedback-crypto@bouncycastle.org");
+
+            //
+            // create base certificate - version 3
+            //
+            X509V3CertificateGenerator  certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name(ord, values));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name(ord, values));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm(algorithm);
+            certGen.AddExtension("2.5.29.15", true,
+            new X509KeyUsage(X509KeyUsage.EncipherOnly));
+            certGen.AddExtension("2.5.29.37", true,
+            new DerSequence(KeyPurposeID.AnyExtendedKeyUsage));
+            certGen.AddExtension("2.5.29.17", true,
+            new GeneralNames(new GeneralName(GeneralName.Rfc822Name, "test@test.test")));
+
+            X509Certificate baseCert = certGen.Generate(privKey);
+
+            baseCert.Verify(pubKey);
+        }
+
+        private static AsymmetricCipherKeyPair GenerateLongFixedKeys()
+        {
+//			RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+            RsaKeyParameters pubKey = new RsaKeyParameters(false,
+                new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+                new BigInteger("010001",16));
+
+//			RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+            RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+                new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+                new BigInteger("010001",16),
+                new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+                new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+                new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+                new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+                new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+                new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+//			KeyFactory  fact = KeyFactory.getInstance("RSA", "BC");
+//
+//			PrivateKey privKey = fact.generatePrivate(privKeySpec);
+//			PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+            return new AsymmetricCipherKeyPair(pubKey, privKey);
+        }
+
+        private void doTestNullDerNullCert()
+        {
+            AsymmetricCipherKeyPair keyPair = GenerateLongFixedKeys();
+
+            AsymmetricKeyParameter pubKey = keyPair.Public;
+            AsymmetricKeyParameter privKey = keyPair.Private;
+
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name("CN=Test"));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name("CN=Test"));
+            certGen.SetPublicKey(pubKey);
+            certGen.SetSignatureAlgorithm("MD5WithRSAEncryption");
+            X509Certificate cert = certGen.Generate(privKey);
+
+            X509CertificateStructure certStruct = X509CertificateStructure.GetInstance(
+                Asn1Object.FromByteArray(cert.GetEncoded()));
+
+            Asn1Encodable tbsCertificate = certStruct.TbsCertificate;
+            AlgorithmIdentifier sig = certStruct.SignatureAlgorithm;
+
+            DerSequence seq = new DerSequence(
+                tbsCertificate,
+                new AlgorithmIdentifier(sig.ObjectID),
+                certStruct.Signature);
+
+            try
+            {
+                // verify
+                byte[] encoded = seq.GetEncoded();
+                X509CertificateParser fact = new X509CertificateParser();
+                cert = fact.ReadCertificate(encoded);
+                cert.Verify(cert.GetPublicKey());
+            }
+            catch (Exception e)
+            {
+                Fail("doTestNullDerNull failed - exception " + e.ToString(), e);
+            }
+        }
+
+        public override void PerformTest()
+        {
+            checkCertificate(1, cert1);
+            checkCertificate(2, cert2);
+            checkCertificate(3, cert3);
+            checkCertificate(4, cert4);
+            checkCertificate(5, cert5);
+            // This cert uses an incorrect encoding (compressed wrapped in extra octet string)
+            // which the Java build supports backwards, but we choose not to for C# build
+//			checkCertificate(6, oldEcdsa);
+            checkCertificate(7, cert7);
+
+            checkKeyUsage(8, keyUsage);
+            checkSelfSignedCertificate(9, uncompressedPtEC);
+            checkNameCertificate(10, nameCert);
+
+            checkSelfSignedCertificate(11, probSelfSignedCert);
+            checkSelfSignedCertificate(12, gostCA1);
+            checkSelfSignedCertificate(13, gostCA2);
+            checkSelfSignedCertificate(14, gost341094base);
+            checkSelfSignedCertificate(15, gost34102001base);
+            checkSelfSignedCertificate(16, gost341094A);
+            checkSelfSignedCertificate(17, gost341094B);
+            checkSelfSignedCertificate(17, gost34102001A);
+
+            checkCrl(1, crl1);
+
+            checkCreation1();
+            checkCreation2();
+            checkCreation3();
+            checkCreation4();
+            checkCreation5();
+
+            createECCert("SHA1withECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+            createECCert("SHA224withECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+            createECCert("SHA256withECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+            createECCert("SHA384withECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+            createECCert("SHA512withECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+
+            createPssCert("SHA1withRSAandMGF1");
+            createPssCert("SHA224withRSAandMGF1");
+            createPssCert("SHA256withRSAandMGF1");
+            createPssCert("SHA384withRSAandMGF1");
+
+            checkCrlCreation1();
+            checkCrlCreation2();
+            checkCrlCreation3();
+
+            pemTest();
+            pkcs7Test();
+
+            doTestForgedSignature();
+
+            doTestNullDerNullCert();
+
+            checkCertificate(18, emptyDNCert);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new CertTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/CipherStreamTest.cs b/crypto/test/src/test/CipherStreamTest.cs
new file mode 100644
index 000000000..0809dfe80
--- /dev/null
+++ b/crypto/test/src/test/CipherStreamTest.cs
@@ -0,0 +1,449 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <remarks>Check that cipher input/output streams are working correctly</remarks>
+	[TestFixture]
+	public class CipherStreamTest
+		: SimpleTest
+	{
+		private static readonly byte[] RK = Hex.Decode("0123456789ABCDEF");
+		private static readonly byte[] RIN = Hex.Decode("4e6f772069732074");
+		private static readonly byte[] ROUT = Hex.Decode("3afbb5c77938280d");
+
+		private static byte[] SIN = Hex.Decode(
+			"00000000000000000000000000000000"
+			+ "00000000000000000000000000000000"
+			+ "00000000000000000000000000000000"
+			+ "00000000000000000000000000000000");
+		private static readonly byte[] SK = Hex.Decode("80000000000000000000000000000000");
+		private static readonly byte[] SIV = Hex.Decode("0000000000000000");
+		private static readonly byte[] SOUT = Hex.Decode(
+			  "4DFA5E481DA23EA09A31022050859936"
+			+ "DA52FCEE218005164F267CB65F5CFD7F"
+			+ "2B4F97E0FF16924A52DF269515110A07"
+			+ "F9E460BC65EF95DA58F740B7D1DBB0AA");
+
+		private static readonly byte[] HCIN = new byte[64];
+		private static readonly byte[] HCIV = new byte[32];
+
+		private static readonly byte[] HCK256A = new byte[32];
+		private static readonly byte[] HC256A = Hex.Decode(
+			  "5B078985D8F6F30D42C5C02FA6B67951"
+			+ "53F06534801F89F24E74248B720B4818"
+			+ "CD9227ECEBCF4DBF8DBF6977E4AE14FA"
+			+ "E8504C7BC8A9F3EA6C0106F5327E6981");
+
+		private static readonly byte[] HCK128A = new byte[16];
+		private static readonly byte[] HC128A = Hex.Decode(
+			  "82001573A003FD3B7FD72FFB0EAF63AA"
+			+ "C62F12DEB629DCA72785A66268EC758B"
+			+ "1EDB36900560898178E0AD009ABF1F49"
+			+ "1330DC1C246E3D6CB264F6900271D59C");
+
+		private void doRunTest(
+			string	name,
+			int		ivLength)
+		{
+			string lCode = "ABCDEFGHIJKLMNOPQRSTUVWXY0123456789";
+
+			string baseName = name;
+			if (name.IndexOf('/') >= 0)
+			{
+				baseName = name.Substring(0, name.IndexOf('/'));
+			}
+
+			CipherKeyGenerator kGen = GeneratorUtilities.GetKeyGenerator(baseName);
+
+			IBufferedCipher inCipher = CipherUtilities.GetCipher(name);
+			IBufferedCipher outCipher = CipherUtilities.GetCipher(name);
+			KeyParameter key = ParameterUtilities.CreateKeyParameter(baseName, kGen.GenerateKey());
+			MemoryStream bIn = new MemoryStream(Encoding.ASCII.GetBytes(lCode), false);
+			MemoryStream bOut = new MemoryStream();
+
+			// In the Java build, this IV would be implicitly created and then retrieved with getIV()
+			ICipherParameters cipherParams = key;
+			if (ivLength > 0)
+			{
+				cipherParams = new ParametersWithIV(cipherParams, new byte[ivLength]);
+			}
+
+			inCipher.Init(true, cipherParams);
+
+			// TODO Should we provide GetIV() method on IBufferedCipher?
+			//if (inCipher.getIV() != null)
+			//{
+			//	outCipher.Init(false, new ParametersWithIV(key, inCipher.getIV()));
+			//}
+			//else
+			//{
+			//	outCipher.Init(false, key);
+			//}
+			outCipher.Init(false, cipherParams);
+
+			CipherStream cIn = new CipherStream(bIn, inCipher, null);
+			CipherStream cOut = new CipherStream(bOut, null, outCipher);
+
+			int c;
+
+			while ((c = cIn.ReadByte()) >= 0)
+			{
+				cOut.WriteByte((byte)c);
+			}
+
+			cIn.Close();
+
+			cOut.Flush();
+			cOut.Close();
+
+			byte[] bs = bOut.ToArray();
+			string res = Encoding.ASCII.GetString(bs, 0, bs.Length);
+
+			if (!res.Equals(lCode))
+			{
+				Fail("Failed - decrypted data doesn't match.");
+			}
+		}
+
+		private void doTestAlgorithm(
+			string	name,
+			byte[]	keyBytes,
+			byte[]	iv,
+			byte[]	plainText,
+			byte[]	cipherText)
+		{
+			KeyParameter key = ParameterUtilities.CreateKeyParameter(name, keyBytes);
+
+			IBufferedCipher inCipher = CipherUtilities.GetCipher(name);
+			IBufferedCipher outCipher = CipherUtilities.GetCipher(name);
+
+			if (iv != null)
+			{
+				inCipher.Init(true, new ParametersWithIV(key, iv));
+				outCipher.Init(false, new ParametersWithIV(key, iv));
+			}
+			else
+			{
+				inCipher.Init(true, key);
+				outCipher.Init(false, key);
+			}
+
+			byte[] enc = inCipher.DoFinal(plainText);
+			if (!AreEqual(enc, cipherText))
+			{
+				Fail(name + ": cipher text doesn't match");
+			}
+
+			byte[] dec = outCipher.DoFinal(enc);
+
+			if (!AreEqual(dec, plainText))
+			{
+				Fail(name + ": plain text doesn't match");
+			}
+		}
+
+		private void doTestException(
+			string	name,
+			int		ivLength)
+		{
+			try
+			{
+				byte[] key128 = {
+					(byte)128, (byte)131, (byte)133, (byte)134,
+					(byte)137, (byte)138, (byte)140, (byte)143,
+					(byte)128, (byte)131, (byte)133, (byte)134,
+					(byte)137, (byte)138, (byte)140, (byte)143
+				};
+
+				byte[] key256 = {
+					(byte)128, (byte)131, (byte)133, (byte)134,
+					(byte)137, (byte)138, (byte)140, (byte)143,
+					(byte)128, (byte)131, (byte)133, (byte)134,
+					(byte)137, (byte)138, (byte)140, (byte)143,
+					(byte)128, (byte)131, (byte)133, (byte)134,
+					(byte)137, (byte)138, (byte)140, (byte)143,
+					(byte)128, (byte)131, (byte)133, (byte)134,
+					(byte)137, (byte)138, (byte)140, (byte)143 };
+
+				byte[] keyBytes;
+				if (name.Equals("HC256"))
+				{
+					keyBytes = key256;
+				}
+				else
+				{
+					keyBytes = key128;
+				}
+
+				KeyParameter cipherKey = ParameterUtilities.CreateKeyParameter(name, keyBytes);
+
+				ICipherParameters cipherParams = cipherKey;
+				if (ivLength > 0)
+				{
+					cipherParams = new ParametersWithIV(cipherParams, new byte[ivLength]);
+				}
+
+				IBufferedCipher ecipher = CipherUtilities.GetCipher(name);
+				ecipher.Init(true, cipherParams);
+
+				byte[] cipherText = new byte[0];
+				try
+				{
+					// According specification Method engineUpdate(byte[] input,
+					// int inputOffset, int inputLen, byte[] output, int
+					// outputOffset)
+					// throws ShortBufferException - if the given output buffer is
+					// too
+					// small to hold the result
+					ecipher.ProcessBytes(new byte[20], 0, 20, cipherText, 0);
+
+//					Fail("failed exception test - no ShortBufferException thrown");
+					Fail("failed exception test - no DataLengthException thrown");
+				}
+//				catch (ShortBufferException e)
+				catch (DataLengthException)
+				{
+					// ignore
+				}
+
+				// NB: The lightweight engine doesn't take public/private keys
+//				try
+//				{
+//					IBufferedCipher c = CipherUtilities.GetCipher(name);
+//
+//					//                Key k = new PublicKey()
+//					//                {
+//					//
+//					//                    public string getAlgorithm()
+//					//                    {
+//					//                        return "STUB";
+//					//                    }
+//					//
+//					//                    public string getFormat()
+//					//                    {
+//					//                        return null;
+//					//                    }
+//					//
+//					//                    public byte[] getEncoded()
+//					//                    {
+//					//                        return null;
+//					//                    }
+//					//
+//					//                };
+//					AsymmetricKeyParameter k = new AsymmetricKeyParameter(false);
+//					c.Init(true, k);
+//
+//					Fail("failed exception test - no InvalidKeyException thrown for public key");
+//				}
+//				catch (InvalidKeyException)
+//				{
+//					// okay
+//				}
+//
+//				try
+//				{
+//					IBufferedCipher c = CipherUtilities.GetCipher(name);
+//
+//					//				Key k = new PrivateKey()
+//					//                {
+//					//
+//					//                    public string getAlgorithm()
+//					//                    {
+//					//                        return "STUB";
+//					//                    }
+//					//
+//					//                    public string getFormat()
+//					//                    {
+//					//                        return null;
+//					//                    }
+//					//
+//					//                    public byte[] getEncoded()
+//					//                    {
+//					//                        return null;
+//					//                    }
+//					//
+//					//                };
+//
+//					AsymmetricKeyParameter k = new AsymmetricKeyParameter(true);
+//					c.Init(false, k);
+//
+//					Fail("failed exception test - no InvalidKeyException thrown for private key");
+//				}
+//				catch (InvalidKeyException)
+//				{
+//					// okay
+//				}
+			}
+			catch (Exception e)
+			{
+				Fail("unexpected exception.", e);
+			}
+		}
+
+		[Test]
+		public void TestRC4()
+		{
+			doRunTest("RC4", 0);
+		}
+
+		[Test]
+		public void TestRC4Exception()
+		{
+			doTestException("RC4", 0);
+		}
+
+		[Test]
+		public void TestRC4Algorithm()
+		{
+			doTestAlgorithm("RC4", RK, null, RIN, ROUT);
+		}
+
+		[Test]
+		public void TestSalsa20()
+		{
+			doRunTest("Salsa20", 8);
+		}
+
+		[Test]
+		public void TestSalsa20Exception()
+		{
+			doTestException("Salsa20", 8);
+		}
+
+		[Test]
+		public void TestSalsa20Algorithm()
+		{
+			doTestAlgorithm("Salsa20", SK, SIV, SIN, SOUT);
+		}
+
+		[Test]
+		public void TestHC128()
+		{
+			doRunTest("HC128", 16);
+		}
+
+		[Test]
+		public void TestHC128Exception()
+		{
+			doTestException("HC128", 16);
+		}
+
+		[Test]
+		public void TestHC128Algorithm()
+		{
+			doTestAlgorithm("HC128", HCK128A, HCIV, HCIN, HC128A);
+		}
+
+		[Test]
+		public void TestHC256()
+		{
+			doRunTest("HC256", 32);
+		}
+
+		[Test]
+		public void TestHC256Exception()
+		{
+			doTestException("HC256", 32);
+		}
+
+		[Test]
+		public void TestHC256Algorithm()
+		{
+			doTestAlgorithm("HC256", HCK256A, HCIV, HCIN, HC256A);
+		}
+
+		[Test]
+		public void TestVmpc()
+		{
+			doRunTest("VMPC", 16);
+		}
+
+		[Test]
+		public void TestVmpcException()
+		{
+			doTestException("VMPC", 16);
+		}
+
+//		[Test]
+//		public void TestVmpcAlgorithm()
+//		{
+//			doTestAlgorithm("VMPC", a, iv, in, a);
+//		}
+
+		[Test]
+		public void TestVmpcKsa3()
+		{
+			doRunTest("VMPC-KSA3", 16);
+		}
+
+		[Test]
+		public void TestVmpcKsa3Exception()
+		{
+			doTestException("VMPC-KSA3", 16);
+		}
+
+//		[Test]
+//		public void TestVmpcKsa3Algorithm()
+//		{
+//			doTestAlgorithm("VMPC-KSA3", a, iv, in, a);
+//		}
+
+		[Test]
+		public void TestDesEcbPkcs7()
+		{
+			doRunTest("DES/ECB/PKCS7Padding", 0);
+		}
+
+		[Test]
+		public void TestDesCfbNoPadding()
+		{
+			doRunTest("DES/CFB8/NoPadding", 0);
+		}
+
+		public override void PerformTest()
+		{
+			TestRC4();
+			TestRC4Exception();
+			TestRC4Algorithm();
+			TestSalsa20();
+			TestSalsa20Exception();
+			TestSalsa20Algorithm();
+			TestHC128();
+			TestHC128Exception();
+			TestHC128Algorithm();
+			TestHC256();
+			TestHC256Exception();
+			TestHC256Algorithm();
+			TestVmpc();
+			TestVmpcException();
+//			TestVmpcAlgorithm();
+			TestVmpcKsa3();
+			TestVmpcKsa3Exception();
+//			TestVmpcKsa3Algorithm();
+			TestDesEcbPkcs7();
+			TestDesCfbNoPadding();
+		}
+
+		public override string Name
+		{
+			get { return "CipherStreamTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new CipherStreamTest());
+		}
+	}
+}
diff --git a/crypto/test/src/test/DESedeTest.cs b/crypto/test/src/test/DESedeTest.cs
new file mode 100644
index 000000000..d84b994f0
--- /dev/null
+++ b/crypto/test/src/test/DESedeTest.cs
@@ -0,0 +1,298 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    /// <remarks>
+    /// Basic test class for key generation for a DES-EDE block cipher, basically
+    /// this just exercises the provider, and makes sure we are behaving sensibly,
+    /// correctness of the implementation is shown in the lightweight test classes.
+    /// </remarks>
+    [TestFixture]
+    public class DesEdeTest
+        : SimpleTest
+    {
+        private static string[] cipherTests1 =
+    {
+        "112",
+        "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394",
+        "128",
+        "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394",
+        "168",
+        "50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89",
+        "192",
+        "50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89",
+        };
+
+        private static byte[] input1 = Hex.Decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f");
+
+        /**
+         * a fake random number generator - we just want to make sure the random numbers
+         * aren't random so that we get the same output, while still getting to test the
+         * key generation facilities.
+         */
+        private class FixedSecureRandom
+            : SecureRandom
+        {
+            private byte[] seed =
+        {
+            (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59,
+            (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4,
+            (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde,
+            (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f
+        };
+
+            public override void NextBytes(
+                byte[] bytes)
+            {
+                int offset = 0;
+
+                while ((offset + seed.Length) < bytes.Length)
+                {
+                    Array.Copy(seed, 0, bytes, offset, seed.Length);
+                    offset += seed.Length;
+                }
+
+                Array.Copy(seed, 0, bytes, offset, bytes.Length - offset);
+            }
+        }
+
+        public override string Name
+        {
+            get { return "DESEDE"; }
+        }
+
+        private void wrapTest(
+            string  alg,
+            int     id,
+            byte[]  kek,
+            byte[]  iv,
+            byte[]  input,
+            byte[]  output)
+        {
+            try
+            {
+                IWrapper wrapper = WrapperUtilities.GetWrapper(alg + "Wrap");
+
+                KeyParameter desEdeKey = new DesEdeParameters(kek);
+                wrapper.Init(true, new ParametersWithIV(desEdeKey, iv));
+
+                try
+                {
+//					byte[] cText = wrapper.Wrap(new SecretKeySpec(input, alg));
+                    byte[] cText = wrapper.Wrap(input, 0, input.Length);
+
+                    if (!Arrays.AreEqual(cText, output))
+                    {
+                        Fail("failed wrap test " + id  + " expected "
+                            + Hex.ToHexString(output) + " got " + Hex.ToHexString(cText));
+                    }
+                }
+                catch (Exception e)
+                {
+                    Fail("failed wrap test exception " + e.ToString());
+                }
+
+                wrapper.Init(false, desEdeKey);
+
+                try
+                {
+//					Key pText = wrapper.unwrap(output, alg, IBufferedCipher.SECRET_KEY);
+                    byte[] pText = wrapper.Unwrap(output, 0, output.Length);
+//					if (!Arrays.AreEqual(pText.getEncoded(), input))
+                    if (!Arrays.AreEqual(pText, input))
+                    {
+                        Fail("failed unwrap test " + id  + " expected "
+                            + Hex.ToHexString(input) + " got "
+                            + Hex.ToHexString(pText));
+                    }
+                }
+                catch (Exception e)
+                {
+                    Fail("failed unwrap test exception " + e.ToString());
+                }
+            }
+            catch (Exception ex)
+            {
+                Fail("failed exception " + ex.ToString());
+            }
+        }
+
+        private void doTest(
+            string  alg,
+            int     strength,
+            byte[]  input,
+            byte[]  output)
+        {
+            KeyParameter		key = null;
+            CipherKeyGenerator	keyGen;
+            SecureRandom		rand;
+            IBufferedCipher		inCipher = null;
+            IBufferedCipher		outCipher = null;
+            CipherStream		cIn;
+            CipherStream		cOut;
+            MemoryStream		bIn;
+            MemoryStream		bOut;
+
+            rand = new FixedSecureRandom();
+
+            try
+            {
+                keyGen = GeneratorUtilities.GetKeyGenerator(alg);
+                keyGen.Init(new KeyGenerationParameters(rand, strength));
+
+                key = new DesEdeParameters(keyGen.GenerateKey());
+
+                inCipher = CipherUtilities.GetCipher(alg + "/ECB/PKCS7Padding");
+                outCipher = CipherUtilities.GetCipher(alg + "/ECB/PKCS7Padding");
+
+                outCipher.Init(true, new ParametersWithRandom(key, rand));
+            }
+            catch (Exception e)
+            {
+                Fail(alg + " failed initialisation - " + e.ToString());
+            }
+
+            try
+            {
+                inCipher.Init(false, key);
+            }
+            catch (Exception e)
+            {
+                Fail(alg + " failed initialisation - " + e.ToString());
+            }
+
+            //
+            // encryption pass
+            //
+            bOut = new MemoryStream();
+
+            cOut = new CipherStream(bOut, null, outCipher);
+
+            try
+            {
+                for (int i = 0; i != input.Length / 2; i++)
+                {
+                    cOut.WriteByte(input[i]);
+                }
+                cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+                cOut.Close();
+            }
+            catch (IOException e)
+            {
+                Fail(alg + " failed encryption - " + e.ToString());
+            }
+
+            byte[] bytes = bOut.ToArray();
+
+            if (!Arrays.AreEqual(bytes, output))
+            {
+                Fail(alg + " failed encryption - expected "
+                    + Hex.ToHexString(output) + " got "
+                    + Hex.ToHexString(bytes));
+            }
+
+            //
+            // decryption pass
+            //
+            bIn = new MemoryStream(bytes, false);
+
+            cIn = new CipherStream(bIn, inCipher, null);
+
+            try
+            {
+//				DataInputStream dIn = new DataInputStream(cIn);
+                BinaryReader dIn = new BinaryReader(cIn);
+
+                bytes = new byte[input.Length];
+
+                for (int i = 0; i != input.Length / 2; i++)
+                {
+                    bytes[i] = (byte)dIn.ReadByte();
+                }
+//				dIn.readFully(bytes, input.Length / 2, bytes.Length - input.Length / 2);
+                int remaining = bytes.Length - input.Length / 2;
+                byte[] rest = dIn.ReadBytes(remaining);
+                if (rest.Length != remaining)
+                    throw new Exception("IO problem with BinaryReader");
+                rest.CopyTo(bytes, input.Length / 2);
+            }
+            catch (Exception e)
+            {
+                Fail(alg + " failed encryption - " + e.ToString());
+            }
+
+            if (!Arrays.AreEqual(bytes, input))
+            {
+                Fail(alg + " failed decryption - expected "
+                    + Hex.ToHexString(input) + " got "
+                    + Hex.ToHexString(bytes));
+            }
+
+            // TODO Put back in
+//			//
+//			// keyspec test
+//			//
+//			try
+//			{
+//				SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(alg);
+//				DESedeKeySpec keySpec = (DESedeKeySpec)keyFactory.getKeySpec((SecretKey)key, DESedeKeySpec.class);
+//
+//				if (!equalArray(key.getEncoded(), keySpec.getKey(), 16))
+//				{
+//					Fail(alg + " KeySpec does not match key.");
+//				}
+//			}
+//			catch (Exception e)
+//			{
+//				Fail(alg + " failed keyspec - " + e.ToString());
+//			}
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i != cipherTests1.Length; i += 2)
+            {
+                doTest("DESEDE", int.Parse(cipherTests1[i]), input1, Hex.Decode(cipherTests1[i + 1]));
+            }
+
+            for (int i = 0; i != cipherTests1.Length; i += 2)
+            {
+                doTest("TDEA", int.Parse(cipherTests1[i]), input1, Hex.Decode(cipherTests1[i + 1]));
+            }
+
+            byte[] kek1 = Hex.Decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f");
+            byte[] iv1 = Hex.Decode("5dd4cbfc96f5453b");
+            byte[] in1 = Hex.Decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98");
+            byte[] out1 = Hex.Decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4");
+
+            wrapTest("DESEDE", 1, kek1, iv1, in1, out1);
+            wrapTest("TDEA", 1, kek1, iv1, in1, out1);
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new DesEdeTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/DHTest.cs b/crypto/test/src/test/DHTest.cs
new file mode 100644
index 000000000..18a0d84d6
--- /dev/null
+++ b/crypto/test/src/test/DHTest.cs
@@ -0,0 +1,651 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class DHTest
+        : SimpleTest
+    {
+        private static readonly BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+        private static readonly BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+        private static readonly BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16);
+        private static readonly BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16);
+
+        private static readonly BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16);
+        private static readonly BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16);
+
+        // public key with mismatched oid/parameters
+        private byte[] oldPubEnc = Base64.Decode(
+            "MIIBnzCCARQGByqGSM4+AgEwggEHAoGBAPxSrN417g43VAM9sZRf1dt6AocAf7D6" +
+            "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" +
+            "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" +
+            "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" +
+            "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" +
+            "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" +
+            "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" +
+            "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" +
+            "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU=");
+
+        // bogus key with full PKCS parameter set
+        private byte[] oldFullParams = Base64.Decode(
+            "MIIBIzCCARgGByqGSM4+AgEwggELAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E" +
+            "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" +
+            "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" +
+            "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" +
+            "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" +
+            "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" +
+            "AwUAAgIH0A==");
+
+        private byte[] samplePubEnc = Base64.Decode(
+            "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" +
+            "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" +
+            "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" +
+            "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" +
+            "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" +
+            "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" +
+            "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" +
+            "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" +
+            "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB");
+
+        private byte[] samplePrivEnc = Base64.Decode(
+            "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" +
+            "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" +
+            "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" +
+            "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" +
+            "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" +
+            "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" +
+            "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" +
+            "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q=");
+
+        public override string Name
+        {
+            get { return "DH"; }
+        }
+
+        private void doTestGP(
+            string		algName,
+            int         size,
+            int         privateValueSize,
+            BigInteger  g,
+            BigInteger  p)
+        {
+            IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator(algName);
+
+            DHParameters dhParams = new DHParameters(p, g, null, privateValueSize);
+            KeyGenerationParameters kgp = new DHKeyGenerationParameters(new SecureRandom(), dhParams);
+
+            keyGen.Init(kgp);
+
+            //
+            // a side
+            //
+            AsymmetricCipherKeyPair aKeyPair = keyGen.GenerateKeyPair();
+
+            IBasicAgreement aKeyAgreeBasic = AgreementUtilities.GetBasicAgreement(algName);
+
+            checkKeySize(privateValueSize, aKeyPair);
+
+            aKeyAgreeBasic.Init(aKeyPair.Private);
+
+            //
+            // b side
+            //
+            AsymmetricCipherKeyPair bKeyPair = keyGen.GenerateKeyPair();
+
+            IBasicAgreement bKeyAgreeBasic = AgreementUtilities.GetBasicAgreement(algName);
+
+            checkKeySize(privateValueSize, bKeyPair);
+
+            bKeyAgreeBasic.Init(bKeyPair.Private);
+
+            //
+            // agreement
+            //
+//			aKeyAgreeBasic.doPhase(bKeyPair.Public, true);
+//			bKeyAgreeBasic.doPhase(aKeyPair.Public, true);
+//
+//			BigInteger  k1 = new BigInteger(aKeyAgreeBasic.generateSecret());
+//			BigInteger  k2 = new BigInteger(bKeyAgreeBasic.generateSecret());
+            BigInteger k1 = aKeyAgreeBasic.CalculateAgreement(bKeyPair.Public);
+            BigInteger k2 = bKeyAgreeBasic.CalculateAgreement(aKeyPair.Public);
+
+            if (!k1.Equals(k2))
+            {
+                Fail(size + " bit 2-way test failed");
+            }
+
+            //
+            // public key encoding test
+            //
+//			byte[]              pubEnc = aKeyPair.Public.GetEncoded();
+            byte[] pubEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(aKeyPair.Public).GetDerEncoded();
+
+//			KeyFactory          keyFac = KeyFactory.getInstance(algName);
+//			X509EncodedKeySpec  pubX509 = new X509EncodedKeySpec(pubEnc);
+//			DHPublicKey         pubKey = (DHPublicKey)keyFac.generatePublic(pubX509);
+            DHPublicKeyParameters pubKey = (DHPublicKeyParameters) PublicKeyFactory.CreateKey(pubEnc);
+//			DHParameterSpec     spec = pubKey.Parameters;
+            DHParameters spec = pubKey.Parameters;
+
+            if (!spec.G.Equals(dhParams.G) || !spec.P.Equals(dhParams.P))
+            {
+                Fail(size + " bit public key encoding/decoding test failed on parameters");
+            }
+
+            if (!((DHPublicKeyParameters)aKeyPair.Public).Y.Equals(pubKey.Y))
+            {
+                Fail(size + " bit public key encoding/decoding test failed on y value");
+            }
+
+            //
+            // public key serialisation test
+            //
+            // TODO Put back in
+//			MemoryStream bOut = new MemoryStream();
+//			ObjectOutputStream oOut = new ObjectOutputStream(bOut);
+//
+//			oOut.WriteObject(aKeyPair.Public);
+//
+//			MemoryStream bIn = new MemoryStream(bOut.ToArray(), false);
+//			ObjectInputStream oIn = new ObjectInputStream(bIn);
+//
+//			pubKey = (DHPublicKeyParameters)oIn.ReadObject();
+            spec = pubKey.Parameters;
+
+            if (!spec.G.Equals(dhParams.G) || !spec.P.Equals(dhParams.P))
+            {
+                Fail(size + " bit public key serialisation test failed on parameters");
+            }
+
+            if (!((DHPublicKeyParameters)aKeyPair.Public).Y.Equals(pubKey.Y))
+            {
+                Fail(size + " bit public key serialisation test failed on y value");
+            }
+
+            //
+            // private key encoding test
+            //
+//			byte[] privEnc = aKeyPair.Private.GetEncoded();
+            byte[] privEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(aKeyPair.Private).GetDerEncoded();
+//			PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
+//			DHPrivateKeyParameters privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8);
+            DHPrivateKeyParameters privKey = (DHPrivateKeyParameters) PrivateKeyFactory.CreateKey(privEnc);
+
+            spec = privKey.Parameters;
+
+            if (!spec.G.Equals(dhParams.G) || !spec.P.Equals(dhParams.P))
+            {
+                Fail(size + " bit private key encoding/decoding test failed on parameters");
+            }
+
+            if (!((DHPrivateKeyParameters)aKeyPair.Private).X.Equals(privKey.X))
+            {
+                Fail(size + " bit private key encoding/decoding test failed on y value");
+            }
+
+            //
+            // private key serialisation test
+            //
+            // TODO Put back in
+//			bOut = new MemoryStream();
+//			oOut = new ObjectOutputStream(bOut);
+//
+//			oOut.WriteObject(aKeyPair.Private);
+//
+//			bIn = new MemoryStream(bOut.ToArray(), false);
+//			oIn = new ObjectInputStream(bIn);
+//
+//			privKey = (DHPrivateKeyParameters)oIn.ReadObject();
+            spec = privKey.Parameters;
+
+            if (!spec.G.Equals(dhParams.G) || !spec.P.Equals(dhParams.P))
+            {
+                Fail(size + " bit private key serialisation test failed on parameters");
+            }
+
+            if (!((DHPrivateKeyParameters)aKeyPair.Private).X.Equals(privKey.X))
+            {
+                Fail(size + " bit private key serialisation test failed on y value");
+            }
+
+            //
+            // three party test
+            //
+            IAsymmetricCipherKeyPairGenerator aPairGen = GeneratorUtilities.GetKeyPairGenerator(algName);
+            aPairGen.Init(new DHKeyGenerationParameters(new SecureRandom(), spec));
+            AsymmetricCipherKeyPair aPair = aPairGen.GenerateKeyPair();
+
+            IAsymmetricCipherKeyPairGenerator bPairGen = GeneratorUtilities.GetKeyPairGenerator(algName);
+            bPairGen.Init(new DHKeyGenerationParameters(new SecureRandom(), spec));
+            AsymmetricCipherKeyPair bPair = bPairGen.GenerateKeyPair();
+
+            IAsymmetricCipherKeyPairGenerator cPairGen = GeneratorUtilities.GetKeyPairGenerator(algName);
+            cPairGen.Init(new DHKeyGenerationParameters(new SecureRandom(), spec));
+            AsymmetricCipherKeyPair cPair = cPairGen.GenerateKeyPair();
+
+
+            IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement(algName);
+            aKeyAgree.Init(aPair.Private);
+
+            IBasicAgreement bKeyAgree = AgreementUtilities.GetBasicAgreement(algName);
+            bKeyAgree.Init(bPair.Private);
+
+            IBasicAgreement cKeyAgree = AgreementUtilities.GetBasicAgreement(algName);
+            cKeyAgree.Init(cPair.Private);
+
+//			Key ac = aKeyAgree.doPhase(cPair.Public, false);
+//			Key ba = bKeyAgree.doPhase(aPair.Public, false);
+//			Key cb = cKeyAgree.doPhase(bPair.Public, false);
+//
+//			aKeyAgree.doPhase(cb, true);
+//			bKeyAgree.doPhase(ac, true);
+//			cKeyAgree.doPhase(ba, true);
+//
+//			BigInteger aShared = new BigInteger(aKeyAgree.generateSecret());
+//			BigInteger bShared = new BigInteger(bKeyAgree.generateSecret());
+//			BigInteger cShared = new BigInteger(cKeyAgree.generateSecret());
+
+            DHPublicKeyParameters ac = new DHPublicKeyParameters(aKeyAgree.CalculateAgreement(cPair.Public), spec);
+            DHPublicKeyParameters ba = new DHPublicKeyParameters(bKeyAgree.CalculateAgreement(aPair.Public), spec);
+            DHPublicKeyParameters cb = new DHPublicKeyParameters(cKeyAgree.CalculateAgreement(bPair.Public), spec);
+
+            BigInteger aShared = aKeyAgree.CalculateAgreement(cb);
+            BigInteger bShared = bKeyAgree.CalculateAgreement(ac);
+            BigInteger cShared = cKeyAgree.CalculateAgreement(ba);
+
+            if (!aShared.Equals(bShared))
+            {
+                Fail(size + " bit 3-way test failed (a and b differ)");
+            }
+
+            if (!cShared.Equals(bShared))
+            {
+                Fail(size + " bit 3-way test failed (c and b differ)");
+            }
+        }
+
+        private void doTestExplicitWrapping(
+            int			size,
+            int			privateValueSize,
+            BigInteger	g,
+            BigInteger	p)
+        {
+            DHParameters dhParams = new DHParameters(p, g, null, privateValueSize);
+
+            IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator("DH");
+
+            keyGen.Init(new DHKeyGenerationParameters(new SecureRandom(), dhParams));
+
+            //
+            // a side
+            //
+            AsymmetricCipherKeyPair aKeyPair = keyGen.GenerateKeyPair();
+
+            IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("DH");
+
+            checkKeySize(privateValueSize, aKeyPair);
+
+            aKeyAgree.Init(aKeyPair.Private);
+
+            //
+            // b side
+            //
+            AsymmetricCipherKeyPair bKeyPair = keyGen.GenerateKeyPair();
+
+            IBasicAgreement bKeyAgree = AgreementUtilities.GetBasicAgreement("DH");
+
+            checkKeySize(privateValueSize, bKeyPair);
+
+            bKeyAgree.Init(bKeyPair.Private);
+
+            //
+            // agreement
+            //
+//			aKeyAgree.doPhase(bKeyPair.Public, true);
+//			bKeyAgree.doPhase(aKeyPair.Public, true);
+//
+//			SecretKey k1 = aKeyAgree.generateSecret(PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id);
+//			SecretKey k2 = bKeyAgree.generateSecret(PkcsObjectIdentifiers.IdAlgCms3DesWrap.Id);
+
+            // TODO Does this really test the same thing as the above code?
+            BigInteger b1 = aKeyAgree.CalculateAgreement(bKeyPair.Public);
+            BigInteger b2 = bKeyAgree.CalculateAgreement(aKeyPair.Public);
+
+            if (!b1.Equals(b2))
+            {
+                Fail("Explicit wrapping test failed");
+            }
+        }
+
+        private void checkKeySize(
+            int						privateValueSize,
+            AsymmetricCipherKeyPair	aKeyPair)
+        {
+            if (privateValueSize != 0)
+            {
+                DHPrivateKeyParameters key = (DHPrivateKeyParameters)aKeyPair.Private;
+
+                if (key.X.BitLength != privateValueSize)
+                {
+                    Fail("limited key check failed for key size " + privateValueSize);
+                }
+            }
+        }
+
+// TODO Put back in
+//    private void doTestRandom(
+//        int         size)
+//    {
+//        AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DH");
+//        a.init(size, new SecureRandom());
+//        AlgorithmParameters parameters = a.generateParameters();
+//
+//        byte[] encodeParams = parameters.GetEncoded();
+//
+//        AlgorithmParameters a2 = AlgorithmParameters.getInstance("DH");
+//        a2.init(encodeParams);
+//
+//        // a and a2 should be equivalent!
+//        byte[] encodeParams_2 = a2.GetEncoded();
+//
+//        if (!areEqual(encodeParams, encodeParams_2))
+//        {
+//            Fail("encode/Decode parameters failed");
+//        }
+//
+//        DHParameterSpec dhP = (DHParameterSpec)parameters.getParameterSpec(DHParameterSpec.class);
+//
+//        doTestGP("DH", size, 0, dhP.G, dhP.P);
+//    }
+
+        [Test]
+        public void TestECDH()
+        {
+            doTestECDH("ECDH");
+        }
+
+        [Test]
+        public void TestECDHC()
+        {
+            doTestECDH("ECDHC");
+        }
+
+        private void doTestECDH(
+            string algorithm)
+        {
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator(algorithm);
+
+//			EllipticCurve curve = new EllipticCurve(
+//				new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
+//				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+//				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+            ECCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters ecSpec = new ECDomainParameters(
+                curve,
+//				ECPointUtil.DecodePoint(curve, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
+                BigInteger.One); //1); // h
+
+//			g.initialize(ecSpec, new SecureRandom());
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
+
+            //
+            // a side
+            //
+            AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();
+
+            IBasicAgreement aKeyAgreeBasic = AgreementUtilities.GetBasicAgreement(algorithm);
+
+            aKeyAgreeBasic.Init(aKeyPair.Private);
+
+            //
+            // b side
+            //
+            AsymmetricCipherKeyPair bKeyPair = g.GenerateKeyPair();
+
+            IBasicAgreement bKeyAgreeBasic = AgreementUtilities.GetBasicAgreement(algorithm);
+
+            bKeyAgreeBasic.Init(bKeyPair.Private);
+
+            //
+            // agreement
+            //
+//			aKeyAgreeBasic.doPhase(bKeyPair.Public, true);
+//			bKeyAgreeBasic.doPhase(aKeyPair.Public, true);
+//
+//			BigInteger k1 = new BigInteger(aKeyAgreeBasic.generateSecret());
+//			BigInteger k2 = new BigInteger(bKeyAgreeBasic.generateSecret());
+            BigInteger k1 = aKeyAgreeBasic.CalculateAgreement(bKeyPair.Public);
+            BigInteger k2 = bKeyAgreeBasic.CalculateAgreement(aKeyPair.Public);
+
+            if (!k1.Equals(k2))
+            {
+                Fail(algorithm + " 2-way test failed");
+            }
+
+            //
+            // public key encoding test
+            //
+//			byte[] pubEnc = aKeyPair.Public.GetEncoded();
+            byte[] pubEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(aKeyPair.Public).GetDerEncoded();
+
+//			KeyFactory keyFac = KeyFactory.getInstance(algorithm);
+//			X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
+//			ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509);
+            ECPublicKeyParameters pubKey = (ECPublicKeyParameters) PublicKeyFactory.CreateKey(pubEnc);
+
+            ECDomainParameters ecDP = pubKey.Parameters;
+
+//			if (!pubKey.getW().Equals(((ECPublicKeyParameters)aKeyPair.Public).getW()))
+            ECPoint pq1 = pubKey.Q.Normalize(), pq2 = ((ECPublicKeyParameters)aKeyPair.Public).Q.Normalize();
+            if (!pq1.Equals(pq2))
+            {
+//				Console.WriteLine(" expected " + pubKey.getW().getAffineX() + " got " + ((ECPublicKey)aKeyPair.Public).getW().getAffineX());
+//				Console.WriteLine(" expected " + pubKey.getW().getAffineY() + " got " + ((ECPublicKey)aKeyPair.Public).getW().getAffineY());
+//				Fail(algorithm + " public key encoding (W test) failed");
+                Console.WriteLine(" expected " + pq1.AffineXCoord.ToBigInteger()
+                    + " got " + pq2.AffineXCoord.ToBigInteger());
+                Console.WriteLine(" expected " + pq1.AffineYCoord.ToBigInteger()
+                    + " got " + pq2.AffineYCoord.ToBigInteger());
+                Fail(algorithm + " public key encoding (Q test) failed");
+            }
+
+//			if (!pubKey.Parameters.getGenerator().Equals(((ECPublicKeyParameters)aKeyPair.Public).Parameters.getGenerator()))
+            if (!pubKey.Parameters.G.Equals(((ECPublicKeyParameters)aKeyPair.Public).Parameters.G))
+            {
+                Fail(algorithm + " public key encoding (G test) failed");
+            }
+
+            //
+            // private key encoding test
+            //
+//			byte[] privEnc = aKeyPair.Private.GetEncoded();
+            byte[] privEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(aKeyPair.Private).GetDerEncoded();
+
+//			PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
+//			ECPrivateKey        privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8);
+            ECPrivateKeyParameters privKey = (ECPrivateKeyParameters) PrivateKeyFactory.CreateKey(privEnc);
+
+//			if (!privKey.getS().Equals(((ECPrivateKey)aKeyPair.Private).getS()))
+            if (!privKey.D.Equals(((ECPrivateKeyParameters)aKeyPair.Private).D))
+            {
+//				Fail(algorithm + " private key encoding (S test) failed");
+                Fail(algorithm + " private key encoding (D test) failed");
+            }
+
+//			if (!privKey.Parameters.getGenerator().Equals(((ECPrivateKey)aKeyPair.Private).Parameters.getGenerator()))
+            if (!privKey.Parameters.G.Equals(((ECPrivateKeyParameters)aKeyPair.Private).Parameters.G))
+            {
+                Fail(algorithm + " private key encoding (G test) failed");
+            }
+        }
+
+        [Test]
+        public void TestExceptions()
+        {
+            DHParameters dhParams = new DHParameters(p512, g512);
+
+            try
+            {
+                IBasicAgreement aKeyAgreeBasic = AgreementUtilities.GetBasicAgreement("DH");
+
+//				aKeyAgreeBasic.generateSecret("DES");
+                aKeyAgreeBasic.CalculateAgreement(null);
+            }
+            catch (InvalidOperationException)
+            {
+                // okay
+            }
+            catch (Exception e)
+            {
+                Fail("Unexpected exception: " + e, e);
+            }
+        }
+
+        private void doTestDesAndDesEde(
+            BigInteger	g,
+            BigInteger	p)
+        {
+            DHParameters dhParams = new DHParameters(p, g, null, 256);
+
+            IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator("DH");
+
+            keyGen.Init(new DHKeyGenerationParameters(new SecureRandom(), dhParams));
+
+            AsymmetricCipherKeyPair kp = keyGen.GenerateKeyPair();
+
+            IBasicAgreement keyAgreement = AgreementUtilities.GetBasicAgreement("DH");
+
+            keyAgreement.Init(kp.Private);
+            BigInteger agreed = keyAgreement.CalculateAgreement(kp.Public);
+            byte[] agreedBytes = agreed.ToByteArrayUnsigned();
+
+            // TODO Figure out where the magic happens of choosing the right
+            // bytes from 'agreedBytes' for each key type - need C# equivalent?
+            // (see JCEDHKeyAgreement.engineGenerateSecret)
+
+//			SecretKey key = keyAgreement.generateSecret("DES");
+//
+//			if (key.getEncoded().length != 8)
+//			{
+//				Fail("DES length wrong");
+//			}
+//
+//			if (!DESKeySpec.isParityAdjusted(key.getEncoded(), 0))
+//			{
+//				Fail("DES parity wrong");
+//			}
+//
+//			key = keyAgreement.generateSecret("DESEDE");
+//
+//			if (key.getEncoded().length != 24)
+//			{
+//				Fail("DESEDE length wrong");
+//			}
+//
+//			if (!DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0))
+//			{
+//				Fail("DESEDE parity wrong");
+//			}
+//
+//			key = keyAgreement.generateSecret("Blowfish");
+//
+//			if (key.getEncoded().length != 16)
+//			{
+//				Fail("Blowfish length wrong");
+//			}
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            doTestGP("DH", 512, 0, g512, p512);
+            doTestGP("DiffieHellman", 768, 0, g768, p768);
+            doTestGP("DIFFIEHELLMAN", 1024, 0, g1024, p1024);
+            doTestGP("DH", 512, 64, g512, p512);
+            doTestGP("DiffieHellman", 768, 128, g768, p768);
+            doTestGP("DIFFIEHELLMAN", 1024, 256, g1024, p1024);
+            doTestExplicitWrapping(512, 0, g512, p512);
+            doTestDesAndDesEde(g768, p768);
+
+            // TODO Put back in
+            //doTestRandom(256);
+        }
+
+        [Test]
+        public void TestEnc()
+        {
+//			KeyFactory kFact = KeyFactory.getInstance("DH", "BC");
+//			
+//			Key k = kFact.generatePrivate(new PKCS8EncodedKeySpec(samplePrivEnc));
+            AsymmetricKeyParameter k = PrivateKeyFactory.CreateKey(samplePrivEnc);
+            byte[] encoded = PrivateKeyInfoFactory.CreatePrivateKeyInfo(k).GetEncoded();
+
+            if (!Arrays.AreEqual(samplePrivEnc, encoded))
+            {
+                Fail("private key re-encode failed");
+            }
+
+//			k = kFact.generatePublic(new X509EncodedKeySpec(samplePubEnc));
+            k = PublicKeyFactory.CreateKey(samplePubEnc);
+            encoded = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(k).GetEncoded();
+
+            if (!Arrays.AreEqual(samplePubEnc, encoded))
+            {
+                Fail("public key re-encode failed");
+            }
+
+//			k = kFact.generatePublic(new X509EncodedKeySpec(oldPubEnc));
+            k = PublicKeyFactory.CreateKey(oldPubEnc);
+            encoded = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(k).GetEncoded();
+
+            if (!Arrays.AreEqual(oldPubEnc, encoded))
+            {
+                Fail("old public key re-encode failed");
+            }
+
+//			k = kFact.generatePublic(new X509EncodedKeySpec(oldFullParams));
+            k = PublicKeyFactory.CreateKey(oldFullParams);
+            encoded = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(k).GetEncoded();
+
+            if (!Arrays.AreEqual(oldFullParams, encoded))
+            {
+                Fail("old full public key re-encode failed");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            TestEnc();
+            TestFunction();
+            TestECDH();
+            TestECDHC();
+            TestExceptions();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new DHTest());
+        }
+    }
+}
diff --git a/crypto/test/src/test/DSATest.cs b/crypto/test/src/test/DSATest.cs
new file mode 100644
index 000000000..a8b8bec3b
--- /dev/null
+++ b/crypto/test/src/test/DSATest.cs
@@ -0,0 +1,888 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class DsaTest
+        : SimpleTest
+    {
+        private static readonly byte[] k1 = Hex.Decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
+        private static readonly byte[] k2 = Hex.Decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
+
+        private static readonly SecureRandom random = FixedSecureRandom.From(k1, k2);
+
+        // TODO How shall we satisfy this compatibility test?
+//		[Test]
+//		public void TestCompat()
+//		{
+//			if (Security.getProvider("SUN") == null)
+//				return;
+//			ISigner s = SignerUtilities.GetSigner("DSA", "SUN");
+//			KeyPairGenerator g = KeyPairGenerator.GetInstance("DSA", "SUN");
+//			byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+//
+//			g.initialize(512, new SecureRandom());
+//
+//			KeyPair p = g.generateKeyPair();
+//
+//			PrivateKey sKey = p.Private;
+//			PublicKey vKey = p.Public;
+//
+//			//
+//			// sign SUN - verify with BC
+//			//
+//			s.Init(true, sKey);
+//
+//			s.update(data);
+//
+//			byte[] sigBytes = s.GenerateSignature();
+//
+//			s = SignerUtilities.GetSigner("DSA");
+//
+//			s.Init(false, vKey);
+//
+//			s.update(data);
+//
+//			if (!s.VerifySignature(sigBytes))
+//			{
+//				Fail("SUN -> BC verification failed");
+//			}
+//
+//			//
+//			// sign BC - verify with SUN
+//			//
+//
+//			s.Init(true, sKey);
+//
+//			s.update(data);
+//
+//			sigBytes = s.GenerateSignature();
+//
+//			s = SignerUtilities.GetSigner("DSA", "SUN");
+//
+//			s.Init(false, vKey);
+//
+//			s.update(data);
+//
+//			if (!s.VerifySignature(sigBytes))
+//			{
+//				Fail("BC -> SUN verification failed");
+//			}
+//
+//			//
+//			// key encoding test - BC decoding Sun keys
+//			//
+//			KeyFactory f = KeyFactory.GetInstance("DSA");
+//			X509EncodedKeySpec x509s = new X509EncodedKeySpec(vKey.GetEncoded());
+//			DSAPublicKey k1 = (DSAPublicKey)f.generatePublic(x509s);
+//
+//			if (!k1.Y.Equals(((DSAPublicKey)vKey).Y))
+//			{
+//				Fail("public number not decoded properly");
+//			}
+//
+//			if (!k1.Parameters.G.Equals(((DSAPublicKey)vKey).Parameters.G))
+//			{
+//				Fail("public generator not decoded properly");
+//			}
+//
+//			if (!k1.Parameters.P.Equals(((DSAPublicKey)vKey).Parameters.P))
+//			{
+//				Fail("public p value not decoded properly");
+//			}
+//
+//			if (!k1.Parameters.Q.Equals(((DSAPublicKey)vKey).Parameters.Q))
+//			{
+//				Fail("public q value not decoded properly");
+//			}
+//
+//			PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(sKey.GetEncoded());
+//			DSAPrivateKey k2 = (DSAPrivateKey)f.generatePrivate(pkcs8);
+//
+//			if (!k2.X.Equals(((DSAPrivateKey)sKey).X))
+//			{
+//				Fail("private number not decoded properly");
+//			}
+//
+//			if (!k2.Parameters.G.Equals(((DSAPrivateKey)sKey).Parameters.G))
+//			{
+//				Fail("private generator not decoded properly");
+//			}
+//
+//			if (!k2.Parameters.P.Equals(((DSAPrivateKey)sKey).Parameters.P))
+//			{
+//				Fail("private p value not decoded properly");
+//			}
+//
+//			if (!k2.Parameters.Q.Equals(((DSAPrivateKey)sKey).Parameters.Q))
+//			{
+//				Fail("private q value not decoded properly");
+//			}
+//
+//			//
+//			// key decoding test - SUN decoding BC keys
+//			//
+//			f = KeyFactory.GetInstance("DSA", "SUN");
+//			x509s = new X509EncodedKeySpec(k1.GetEncoded());
+//
+//			vKey = (DSAPublicKey)f.generatePublic(x509s);
+//
+//			if (!k1.Y.Equals(((DSAPublicKey)vKey).Y))
+//			{
+//				Fail("public number not decoded properly");
+//			}
+//
+//			if (!k1.Parameters.G.Equals(((DSAPublicKey)vKey).Parameters.G))
+//			{
+//				Fail("public generator not decoded properly");
+//			}
+//
+//			if (!k1.Parameters.P.Equals(((DSAPublicKey)vKey).Parameters.P))
+//			{
+//				Fail("public p value not decoded properly");
+//			}
+//
+//			if (!k1.Parameters.Q.Equals(((DSAPublicKey)vKey).Parameters.Q))
+//			{
+//				Fail("public q value not decoded properly");
+//			}
+//
+//			pkcs8 = new PKCS8EncodedKeySpec(k2.GetEncoded());
+//			sKey = (DSAPrivateKey)f.generatePrivate(pkcs8);
+//
+//			if (!k2.X.Equals(((DSAPrivateKey)sKey).X))
+//			{
+//				Fail("private number not decoded properly");
+//			}
+//
+//			if (!k2.Parameters.G.Equals(((DSAPrivateKey)sKey).Parameters.G))
+//			{
+//				Fail("private generator not decoded properly");
+//			}
+//
+//			if (!k2.Parameters.P.Equals(((DSAPrivateKey)sKey).Parameters.P))
+//			{
+//				Fail("private p value not decoded properly");
+//			}
+//
+//			if (!k2.Parameters.Q.Equals(((DSAPrivateKey)sKey).Parameters.Q))
+//			{
+//				Fail("private q value not decoded properly");
+//			}
+//		}
+
+        [Test]
+        public void TestNONEwithDSA()
+        {
+            byte[] dummySha1 = Hex.Decode("01020304050607080910111213141516");
+
+            SecureRandom rand = new SecureRandom();
+
+            DsaParametersGenerator pGen = new DsaParametersGenerator();
+            pGen.Init(512, 80, rand);
+
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("DSA");
+            g.Init(new DsaKeyGenerationParameters(rand, pGen.GenerateParameters()));
+
+            AsymmetricCipherKeyPair kp = g.GenerateKeyPair();
+
+            ISigner sig = SignerUtilities.GetSigner("NONEwithDSA");
+            sig.Init(true, kp.Private);
+            sig.BlockUpdate(dummySha1, 0, dummySha1.Length);
+            byte[] sigBytes = sig.GenerateSignature();
+
+            sig.Init(false, kp.Public);
+            sig.BlockUpdate(dummySha1, 0, dummySha1.Length);
+            sig.VerifySignature(sigBytes);
+
+            // reset test
+
+            sig.BlockUpdate(dummySha1, 0, dummySha1.Length);
+
+            if (!sig.VerifySignature(sigBytes))
+            {
+                Fail("NONEwithDSA failed to reset");
+            }
+
+            // lightweight test
+            DsaSigner signer = new DsaSigner();
+            Asn1Sequence derSig = Asn1Sequence.GetInstance(Asn1Object.FromByteArray(sigBytes));
+
+            signer.Init(false, kp.Public);
+
+            if (!signer.VerifySignature(dummySha1,
+                DerInteger.GetInstance(derSig[0]).Value, DerInteger.GetInstance(derSig[1]).Value))
+            {
+                Fail("NONEwithDSA not really NONE!");
+            }
+        }
+
+        /**
+        * X9.62 - 1998,<br/>
+        * J.3.2, Page 155, ECDSA over the field Fp<br/>
+        * an example with 239 bit prime
+        */
+        [Test]
+        public void TestECDsa239BitPrime()
+        {
+            BigInteger r = new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176");
+            BigInteger s = new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(
+                new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            ECCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters spec = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+                spec);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(Hex.Decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+                spec);
+
+            ISigner sgr = SignerUtilities.GetSigner("ECDSA");
+
+//			KeyFactory f = KeyFactory.GetInstance("ECDSA");
+//			PrivateKey sKey = f.generatePrivate(priKey);
+//			PublicKey vKey = f.generatePublic(pubKey);
+            AsymmetricKeyParameter sKey = priKey;
+            AsymmetricKeyParameter vKey = pubKey;
+
+            sgr.Init(true, new ParametersWithRandom(sKey, k));
+
+            byte[] message = Encoding.ASCII.GetBytes("abc");
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail("239 Bit EC verification failed");
+            }
+
+            BigInteger[] sig = DerDecode(sigBytes);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                        + " expecting: " + r + SimpleTest.NewLine
+                        + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                        + " expecting: " + s + SimpleTest.NewLine
+                        + " got      : " + sig[1]);
+            }
+        }
+
+        /**
+        * X9.62 - 1998,<br/>
+        * J.2.1, Page 100, ECDSA over the field F2m<br/>
+        * an example with 191 bit binary field
+        */
+        [Test]
+        public void TestECDsa239BitBinary()
+        {
+            BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
+            BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(
+                new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            ECCurve curve = new F2mCurve(
+                239, // m
+                36, // k
+                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
+                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
+                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
+                BigInteger.ValueOf(4)); // h
+
+            ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
+                parameters);
+
+            ECPublicKeyParameters vKey = new ECPublicKeyParameters(
+                "ECDSA",
+                curve.DecodePoint(Hex.Decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
+                parameters);
+
+            ISigner sgr = SignerUtilities.GetSigner("ECDSA");
+            byte[] message = Encoding.ASCII.GetBytes("abc");
+
+            sgr.Init(true, new ParametersWithRandom(sKey, k));
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail("239 Bit EC verification failed");
+            }
+
+            BigInteger[] sig = DerDecode(sigBytes);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+        }
+
+        [Test]
+        public void TestECDsa239BitBinaryRipeMD160()
+        {
+            DoTestECDsa239BitBinary("RIPEMD160withECDSA", TeleTrusTObjectIdentifiers.ECSignWithRipeMD160);
+        }
+
+        [Test]
+        public void TestECDsa239BitBinarySha1()
+        {
+            DoTestECDsa239BitBinary("SHA1withECDSA", TeleTrusTObjectIdentifiers.ECSignWithSha1);
+        }
+
+        [Test]
+        public void TestECDsa239BitBinarySha224()
+        {
+            DoTestECDsa239BitBinary("SHA224withECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+        }
+
+        [Test]
+        public void TestECDsa239BitBinarySha256()
+        {
+            DoTestECDsa239BitBinary("SHA256withECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+        }
+
+        [Test]
+        public void TestECDsa239BitBinarySha384()
+        {
+            DoTestECDsa239BitBinary("SHA384withECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+        }
+
+        [Test]
+        public void TestECDsa239BitBinarySha512()
+        {
+            DoTestECDsa239BitBinary("SHA512withECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+        }
+
+        private void DoTestECDsa239BitBinary(
+            string				algorithm,
+            DerObjectIdentifier	oid)
+        {
+            BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
+            BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");
+
+            byte[] kData = BigIntegers.AsUnsignedByteArray(
+                new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363"));
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            ECCurve curve = new F2mCurve(
+                239, // m
+                36, // k
+                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
+                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
+                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
+                BigInteger.ValueOf(4)); // h
+
+            ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
+                new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
+                parameters);
+
+            ECPublicKeyParameters vKey = new ECPublicKeyParameters(
+                curve.DecodePoint(Hex.Decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
+                parameters);
+
+            ISigner sgr = SignerUtilities.GetSigner(algorithm);
+            byte[] message = Encoding.ASCII.GetBytes("abc");
+
+            sgr.Init(true, new ParametersWithRandom(sKey, k));
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr = SignerUtilities.GetSigner(oid.Id);
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail("239 Bit EC RIPEMD160 verification failed");
+            }
+        }
+
+        private void doTestBadStrength(
+            int strength)
+        {
+//			IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("DSA");
+
+            // test exception
+            //
+            try
+            {
+                SecureRandom rand = new SecureRandom();
+
+                DsaParametersGenerator pGen = new DsaParametersGenerator();
+                pGen.Init(strength, 80, rand);
+
+//				g.Init(new DsaKeyGenerationParameters(rand, pGen.GenerateParameters()));
+
+                Fail("illegal parameter " + strength + " check failed.");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public void TestGeneration()
+        {
+            ISigner s = SignerUtilities.GetSigner("DSA");
+            byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+            SecureRandom rand = new SecureRandom();
+
+            // KeyPairGenerator g = KeyPairGenerator.GetInstance("DSA");
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("DSA");
+
+            // test exception
+            //
+
+            doTestBadStrength(513);
+            doTestBadStrength(510);
+            doTestBadStrength(1025);
+
+            //g.initialize(512, rand);
+            {
+                DsaParametersGenerator pGen = new DsaParametersGenerator();
+                pGen.Init(512, 80, rand);
+
+                g.Init(new DsaKeyGenerationParameters(rand, pGen.GenerateParameters()));
+            }
+
+            AsymmetricCipherKeyPair p = g.GenerateKeyPair();
+
+            AsymmetricKeyParameter sKey = p.Private;
+            AsymmetricKeyParameter vKey = p.Public;
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            byte[] sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("DSA");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("DSA verification failed");
+            }
+
+
+
+            //
+            // ECDSA Fp generation test
+            //
+            s = SignerUtilities.GetSigner("ECDSA");
+
+            ECCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters ecSpec = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+            g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+            g.Init(new ECKeyGenerationParameters(ecSpec, rand));
+
+            p = g.GenerateKeyPair();
+
+            sKey = p.Private;
+            vKey = p.Public;
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("ECDSA");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("ECDSA verification failed");
+            }
+
+            //
+            // ECDSA F2m generation test
+            //
+            s = SignerUtilities.GetSigner("ECDSA");
+
+            curve = new F2mCurve(
+                    239, // m
+                    36, // k
+                    new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
+                    new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
+
+            ecSpec = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
+                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
+                BigInteger.ValueOf(4)); // h
+
+            g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+            g.Init(new ECKeyGenerationParameters(ecSpec, rand));
+
+            p = g.GenerateKeyPair();
+
+            sKey = p.Private;
+            vKey = p.Public;
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("ECDSA");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("ECDSA verification failed");
+            }
+        }
+
+        [Test]
+        public void TestParameters()
+        {
+//			AlgorithmParameterGenerator a = AlgorithmParameterGenerator.GetInstance("DSA");
+//			a.init(512, random);
+            DsaParametersGenerator a = new DsaParametersGenerator();
+            a.Init(512, 20, random);
+
+//			AlgorithmParameters parameters = a.generateParameters();
+            DsaParameters p = a.GenerateParameters();
+
+//			byte[] encodeParams = parameters.GetEncoded();
+            byte[] encodeParams = new DsaParameter(p.P, p.Q, p.G).GetDerEncoded();
+
+//			AlgorithmParameters a2 = AlgorithmParameters.GetInstance("DSA");
+//			a2.init(encodeParams);
+            DsaParameter dsaP = DsaParameter.GetInstance(Asn1Object.FromByteArray(encodeParams));
+            DsaParameters p2 = new DsaParameters(dsaP.P, dsaP.Q, dsaP.G);
+
+            // a and a2 should be equivalent!
+//			byte[] encodeParams_2 = a2.GetEncoded();
+            byte[] encodeParams_2 = new DsaParameter(p2.P, p2.Q, p2.G).GetDerEncoded();
+
+            if (!AreEqual(encodeParams, encodeParams_2))
+            {
+                Fail("encode/Decode parameters failed");
+            }
+
+//			DSAParameterSpec dsaP = (DSAParameterSpec)parameters.getParameterSpec(typeof(DSAParameterSpec));
+
+//			KeyPairGenerator g = KeyPairGenerator.GetInstance("DSA");
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("DSA");
+//			g.initialize(dsaP, new SecureRandom());
+            g.Init(new DsaKeyGenerationParameters(new SecureRandom(), p));
+//			KeyPair p = g.generateKeyPair();
+            AsymmetricCipherKeyPair pair = g.GenerateKeyPair();
+
+//			PrivateKey sKey = p.Private;
+//			PublicKey vKey = p.Public;
+            AsymmetricKeyParameter sKey = pair.Private;
+            AsymmetricKeyParameter vKey = pair.Public;
+
+            ISigner s = SignerUtilities.GetSigner("DSA");
+            byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            byte[] sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("DSA");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("DSA verification failed");
+            }
+        }
+
+        [Test]
+        public void TestDsa2Parameters()
+        {
+            byte[] seed = Hex.Decode("4783081972865EA95D43318AB2EAF9C61A2FC7BBF1B772A09017BDF5A58F4FF0");
+
+            //AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DSA", "BC");
+            //a.init(2048, new DSATestSecureRandom(seed));
+            DsaParametersGenerator a = new DsaParametersGenerator(new Sha256Digest());
+            a.Init(new DsaParameterGenerationParameters(2048, 256, 80, new DsaTestSecureRandom(seed)));
+
+            //AlgorithmParameters parameters = a.generateParameters();
+
+            //DSAParameterSpec dsaP = (DSAParameterSpec)parameters.getParameterSpec(DSAParameterSpec.class);
+            DsaParameters dsaP = a.GenerateParameters();
+
+            if (!dsaP.Q.Equals(new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16)))
+            {
+                Fail("Q incorrect");
+            }
+
+            if (!dsaP.P.Equals(new BigInteger(
+                "F56C2A7D366E3EBDEAA1891FD2A0D099" +
+                "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" +
+                "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" +
+                "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" +
+                "5909132627F51A0C866877E672E555342BDF9355347DBD43" +
+                "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" +
+                "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" +
+                "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" +
+                "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" +
+                "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" +
+                "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16)))
+            {
+                Fail("P incorrect");
+            }
+
+            if (!dsaP.G.Equals(new BigInteger(
+                "8DC6CC814CAE4A1C05A3E186A6FE27EA" +
+                "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" +
+                "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" +
+                "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" +
+                "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" +
+                "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" +
+                "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" +
+                "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" +
+                "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" +
+                "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" +
+                "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16)))
+            {
+                Fail("G incorrect");
+            }
+
+            //KeyPairGenerator    g = KeyPairGenerator.getInstance("DSA", "BC");
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("DSA");
+            //g.initialize(dsaP, FixedSecureRandom.From(Hex.Decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")));
+            g.Init(new DsaKeyGenerationParameters(FixedSecureRandom.From(Hex.Decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), dsaP));
+            //KeyPair p = g.generateKeyPair();
+            AsymmetricCipherKeyPair p = g.GenerateKeyPair();
+
+            //DSAPrivateKey  sKey = (DSAPrivateKey)p.getPrivate();
+            //DSAPublicKey   vKey = (DSAPublicKey)p.getPublic();
+            DsaPrivateKeyParameters sKey = (DsaPrivateKeyParameters)p.Private;
+            DsaPublicKeyParameters vKey = (DsaPublicKeyParameters)p.Public;
+
+            if (!vKey.Y.Equals(new BigInteger(
+                "2828003D7C747199143C370FDD07A286" +
+                "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" +
+                "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" +
+                "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" +
+                "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" +
+                "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" +
+                "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" +
+                "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" +
+                "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" +
+                "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" +
+                "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16)))
+            {
+                Fail("Y value incorrect");
+            }
+
+            if (!sKey.X.Equals(
+                new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16)))
+            {
+                Fail("X value incorrect");
+            }
+
+            //byte[] encodeParams = parameters.getEncoded();
+            byte[] encodeParams = new DsaParameter(dsaP.P, dsaP.Q, dsaP.G).GetDerEncoded();
+
+            //AlgorithmParameters a2 = AlgorithmParameters.getInstance("DSA", "BC");
+            //a2.init(encodeParams);
+            DsaParameter dsaP2 = DsaParameter.GetInstance(Asn1Object.FromByteArray(encodeParams));
+            DsaParameters p2 = new DsaParameters(dsaP.P, dsaP.Q, dsaP.G);
+
+            // a and a2 should be equivalent!
+            //byte[] encodeParams_2 = a2.GetEncoded();
+            byte[] encodeParams_2 = new DsaParameter(p2.P, p2.Q, p2.G).GetDerEncoded();
+
+            if (!AreEqual(encodeParams, encodeParams_2))
+            {
+                Fail("encode/decode parameters failed");
+            }
+
+            ISigner s = SignerUtilities.GetSigner("DSA");
+            byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            byte[] sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("DSA");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("DSA verification failed");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            // TODO
+//			TestCompat();
+            TestNONEwithDSA();
+            TestECDsa239BitPrime();
+            TestECDsa239BitBinary();
+            TestECDsa239BitBinaryRipeMD160();
+            TestECDsa239BitBinarySha1();
+            TestECDsa239BitBinarySha224();
+            TestECDsa239BitBinarySha256();
+            TestECDsa239BitBinarySha384();
+            TestECDsa239BitBinarySha512();
+
+            TestGeneration();
+            TestParameters();
+            TestDsa2Parameters();
+        }
+
+        protected BigInteger[] DerDecode(
+            byte[] encoding)
+        {
+            Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+            return new BigInteger[]
+            {
+                ((DerInteger)s[0]).Value,
+                ((DerInteger)s[1]).Value
+            };
+        }
+
+        public override string Name
+        {
+            get { return "DSA/ECDSA"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new DsaTest());
+        }
+
+        private class DsaTestSecureRandom
+            : FixedSecureRandom
+        {
+            private bool first = true;
+
+            public DsaTestSecureRandom(byte[] value)
+                : base(Arrays.Clone(value))
+            {
+            }
+
+            public override void NextBytes(byte[] bytes)
+            {
+                if (first)
+                {
+                    base.NextBytes(bytes);
+                    first = false;
+                }
+                else
+                {
+                    bytes[bytes.Length - 1] = 2;
+                }
+            }
+        }
+    }
+}
diff --git a/crypto/test/src/test/DigestTest.cs b/crypto/test/src/test/DigestTest.cs
new file mode 100644
index 000000000..5d840ee66
--- /dev/null
+++ b/crypto/test/src/test/DigestTest.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class DigestTest
+        : SimpleTest
+    {
+        private static string[,] abcVectors =
+        {
+            { "MD2", "da853b0d3f88d99b30283a69e6ded6bb" },
+            { "MD4", "a448017aaf21d8525fc10ae87aa6729d" },
+            { "MD5", "900150983cd24fb0d6963f7d28e17f72"},
+            { "SHA-1", "a9993e364706816aba3e25717850c26c9cd0d89d" },
+            { "SHA-224", "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" },
+            { "SHA-256", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" },
+            { "SHA-384", "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" },
+            { "SHA-512", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" },
+            { "SHA-512/224", "4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA" },
+            { "SHA-512/256", "53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23" },
+            { "RIPEMD128", "c14a12199c66e4ba84636b0f69144c77" },
+            { "RIPEMD160", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" },
+            { "RIPEMD256", "afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65" },
+            { "RIPEMD320", "de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d" },
+            { "Tiger", "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93" },
+            { "GOST3411", "b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c" },
+            { "WHIRLPOOL", "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5" }
+        };
+
+        public override string Name
+        {
+            get { return "Digest"; }
+        }
+
+        void doTest(
+            string algorithm)
+        {
+            byte[] message = Encoding.ASCII.GetBytes("hello world");
+
+            IDigest digest = DigestUtilities.GetDigest(algorithm);
+
+//			byte[] result = digest.digest(message);
+            digest.BlockUpdate(message, 0, message.Length);
+            byte[] result = DigestUtilities.DoFinal(digest);
+
+//			byte[] result2 = digest.digest(message);
+            digest.BlockUpdate(message, 0, message.Length);
+            byte[] result2 = DigestUtilities.DoFinal(digest);
+
+            // test one digest the same message with the same instance
+            if (!AreEqual(result, result2))
+            {
+                Fail("Result object 1 not equal");
+            }
+
+            // test two, single byte updates
+            for (int i = 0; i < message.Length; i++)
+            {
+                digest.Update(message[i]);
+            }
+//			result2 = digest.digest();
+            result2 = DigestUtilities.DoFinal(digest);
+
+            if (!AreEqual(result, result2))
+            {
+                Fail("Result object 2 not equal");
+            }
+
+            // test three, two half updates
+            digest.BlockUpdate(message, 0, message.Length/2);
+            digest.BlockUpdate(message, message.Length/2, message.Length-message.Length/2);
+//			result2 = digest.digest();
+            result2 = DigestUtilities.DoFinal(digest);
+
+            if (!AreEqual(result, result2))
+            {
+                Fail("Result object 3 not equal");
+            }
+
+            // TODO Should we support Clone'ing of digests?
+//			// test four, clone test
+//			digest.BlockUpdate(message, 0, message.Length/2);
+//			IDigest d = (IDigest)digest.Clone();
+//			digest.BlockUpdate(message, message.Length/2, message.Length-message.Length/2);
+////			result2 = digest.digest();
+//			result2 = new byte[digest.GetDigestSize()];
+//			digest.DoFinal(result2, 0);
+//
+//			if (!AreEqual(result, result2))
+//			{
+//				Fail("Result object 4(a) not equal");
+//			}
+//
+//			d.BlockUpdate(message, message.Length/2, message.Length-message.Length/2);
+////			result2 = d.digest();
+//			result2 = new byte[d.GetDigestSize()];
+//			d.DoFinal(result2, 0);
+//
+//			if (!AreEqual(result, result2))
+//			{
+//				Fail("Result object 4(b) not equal");
+//			}
+
+            // test five, check reset() method
+            digest.BlockUpdate(message, 0, message.Length/2);
+            digest.Reset();
+            digest.BlockUpdate(message, 0, message.Length/2);
+            digest.BlockUpdate(message, message.Length/2, message.Length-message.Length/2);
+//			result2 = digest.digest();
+            result2 = DigestUtilities.DoFinal(digest);
+
+            if (!AreEqual(result, result2))
+            {
+                Fail("Result object 5 not equal");
+            }
+        }
+
+        /**
+         * Test the hash against a standard value for the string "abc"
+         *
+         * @param algorithm algorithm to test
+         * @param hash expected value
+         * @return the test result.
+         */
+        void doAbcTest(
+            string algorithm,
+            string hash)
+        {
+            byte[] abc = { (byte)0x61, (byte)0x62, (byte)0x63 };
+
+            IDigest digest = DigestUtilities.GetDigest(algorithm);
+
+//			byte[] result = digest.digest(abc);
+            digest.BlockUpdate(abc, 0, abc.Length);
+            byte[] result = DigestUtilities.DoFinal(digest);
+
+            if (!AreEqual(result, Hex.Decode(hash)))
+            {
+                Fail("abc result not equal for " + algorithm);
+            }
+        }
+
+        public override void PerformTest()
+        {
+            for (int i = 0; i != abcVectors.GetLength(0); i++)
+            {
+                doTest(abcVectors[i, 0]);
+
+                doAbcTest(abcVectors[i, 0], abcVectors[i, 1]);
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new DigestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/ECDSA5Test.cs b/crypto/test/src/test/ECDSA5Test.cs
new file mode 100644
index 000000000..3bf746edb
--- /dev/null
+++ b/crypto/test/src/test/ECDSA5Test.cs
@@ -0,0 +1,300 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class ECDsa5Test
+        : SimpleTest
+    {
+//		private static readonly byte[] k1 = Hex.Decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
+//		private static readonly byte[] k2 = Hex.Decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
+//
+//		private SecureRandom random = FixedSecureRandom.From(k1, k2);
+
+        [Test]
+        public void DecodeTest()
+        {
+//			EllipticCurve curve = new EllipticCurve(
+//				new ECFieldFp(new BigInteger("6277101735386680763835789423207666416083908700390324961279")), // q
+//				new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+//				new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
+            ECCurve curve = new FpCurve(
+                new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q
+                new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a
+                new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b
+
+//			ECPoint p = ECPointUtil.DecodePoint(curve, Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"));
+            ECPoint p = curve.DecodePoint(Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"));
+
+            BigInteger x = p.XCoord.ToBigInteger(); //p.getAffineX();
+
+            if (!x.Equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16)))
+            {
+                Fail("x uncompressed incorrectly");
+            }
+
+            BigInteger y = p.YCoord.ToBigInteger(); //p.getAffineX();
+            if (!y.Equals(new BigInteger("7192b95ffc8da78631011ed6b24cdd573f977a11e794811", 16)))
+            {
+                Fail("y uncompressed incorrectly");
+            }
+        }
+
+        /**
+        * X9.62 - 1998,<br/>
+        * J.3.2, Page 155, ECDSA over the field Fp<br/>
+        * an example with 239 bit prime
+        */
+        [Test]
+        public void TestECDsa239BitPrime()
+        {
+            BigInteger r = new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176");
+            BigInteger s = new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783");
+
+            byte[] kData = new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655").ToByteArrayUnsigned();
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+//			EllipticCurve curve = new EllipticCurve(
+//				new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
+//				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+//				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+            ECCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters spec = new ECDomainParameters(
+                curve,
+//				ECPointUtil.DecodePoint(curve, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
+                BigInteger.One); //1); // h
+
+            ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+                spec);
+
+            ECPublicKeyParameters vKey = new ECPublicKeyParameters(
+                "ECDSA",
+//				ECPointUtil.DecodePoint(curve, Hex.Decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+                curve.DecodePoint(Hex.Decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+                spec);
+
+            ISigner sgr = SignerUtilities.GetSigner("ECDSA");
+//			KeyFactory f = KeyFactory.getInstance("ECDSA");
+//			AsymmetricKeyParameter sKey = f.generatePrivate(priKey);
+//			AsymmetricKeyParameter vKey = f.generatePublic(pubKey);
+
+            sgr.Init(true, new ParametersWithRandom(sKey, k));
+
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail("239 Bit EC verification failed");
+            }
+
+            BigInteger[] sig = derDecode(sigBytes);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+        }
+
+        /**
+        * X9.62 - 1998,<br/>
+        * J.2.1, Page 100, ECDSA over the field F2m<br/>
+        * an example with 191 bit binary field
+        */
+        [Test]
+        public void TestECDsa239BitBinary()
+        {
+            BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552");
+            BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174");
+        
+            byte[] kData = new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363").ToByteArrayUnsigned();
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+//			EllipticCurve curve = new EllipticCurve(
+//				new ECFieldF2m(239, // m
+//							new int[] { 36 }), // k
+//				new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
+//				new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
+            ECCurve curve = new F2mCurve(
+                239, // m
+                36, // k
+                new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a
+                new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b
+
+            ECDomainParameters parameters = new ECDomainParameters(
+                curve,
+//				ECPointUtil.DecodePoint(curve, Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
+                curve.DecodePoint(Hex.Decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G
+                new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n
+                BigInteger.ValueOf(4)); //4); // h
+
+            ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
+                "ECDSA",
+                new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d
+                parameters);
+
+            ECPublicKeyParameters vKey = new ECPublicKeyParameters(
+                "ECDSA",
+//				ECPointUtil.DecodePoint(curve, Hex.Decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
+                curve.DecodePoint(Hex.Decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q
+                parameters);
+
+            ISigner sgr = SignerUtilities.GetSigner("ECDSA");
+//			KeyFactory f = KeyFactory.getInstance("ECDSA");
+//			AsymmetricKeyParameter sKey = f.generatePrivate(priKeySpec);
+//			AsymmetricKeyParameter vKey = f.generatePublic(pubKeySpec);
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            sgr.Init(true, new ParametersWithRandom(sKey, k));
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail("239 Bit EC verification failed");
+            }
+
+            BigInteger[] sig = derDecode(sigBytes);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail("r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail("s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+        }
+
+        [Test]
+        public void TestGeneration()
+        {
+            //
+            // ECDSA generation test
+            //
+            byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+            ISigner s = SignerUtilities.GetSigner("ECDSA");
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+
+//			EllipticCurve curve = new EllipticCurve(
+//				new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
+//				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+//				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+            ECCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters ecSpec = new ECDomainParameters(
+                curve,
+//				ECPointUtil.DecodePoint(curve,
+                curve.DecodePoint(
+                    Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
+                BigInteger.One); //1); // h
+
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
+
+            AsymmetricCipherKeyPair p = g.GenerateKeyPair();
+
+            AsymmetricKeyParameter sKey = p.Private;
+            AsymmetricKeyParameter vKey = p.Public;
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            byte[] sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("ECDSA");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("ECDSA verification failed");
+            }
+        }
+
+        protected BigInteger[] derDecode(
+            byte[] encoding)
+        {
+            Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+            return new BigInteger[]
+            {
+                ((DerInteger)s[0]).Value,
+                ((DerInteger)s[1]).Value
+            };
+        }
+
+        public override string Name
+        {
+            get { return "ECDSA5"; }
+        }
+
+        public override void PerformTest()
+        {
+            DecodeTest();
+            TestECDsa239BitPrime();
+            TestECDsa239BitBinary();
+            TestGeneration();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ECDsa5Test());
+        }
+    }
+}
diff --git a/crypto/test/src/test/ECEncodingTest.cs b/crypto/test/src/test/ECEncodingTest.cs
new file mode 100644
index 000000000..f1a4d5e3a
--- /dev/null
+++ b/crypto/test/src/test/ECEncodingTest.cs
@@ -0,0 +1,243 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class ECEncodingTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "ECEncodingTest"; }
+		}
+
+		/** J.4.7 An Example with m = 304 */
+		private int m = 304;
+
+		/** f = 010000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000807 */
+		private int k1 = 1;
+		private int k2 = 2;
+		private int k3 = 11;
+		private static readonly byte[] hexa = {(byte)0xFD, 0x0D, 0x69, 0x31, 0x49, (byte)0xA1, 0x18, (byte)0xF6, 0x51
+			, (byte)0xE6, (byte)0xDC, (byte)0xE6, (byte)0x80, 0x20, (byte)0x85, 0x37, 0x7E, 0x5F, (byte)0x88, 0x2D, 0x1B, 0x51
+			, 0x0B, 0x44, 0x16, 0x00, 0x74, (byte)0xC1, 0x28, (byte)0x80, 0x78, 0x36, 0x5A, 0x03
+			, (byte)0x96, (byte)0xC8, (byte)0xE6, (byte)0x81};
+		private static readonly byte[] hexb = {(byte)0xBD, (byte)0xDB, (byte)0x97, (byte)0xE5, (byte)0x55
+			, (byte)0xA5, (byte)0x0A, (byte)0x90, (byte)0x8E, (byte)0x43, (byte)0xB0
+			, (byte)0x1C, (byte)0x79, (byte)0x8E, (byte)0xA5, (byte)0xDA, (byte)0xA6
+			, (byte)0x78, (byte)0x8F, (byte)0x1E, (byte)0xA2, (byte)0x79
+			, (byte)0x4E, (byte)0xFC, (byte)0xF5, (byte)0x71, (byte)0x66, (byte)0xB8
+			, (byte)0xC1, (byte)0x40, (byte)0x39, (byte)0x60, (byte)0x1E
+			, (byte)0x55, (byte)0x82, (byte)0x73, (byte)0x40, (byte)0xBE};
+		private static readonly BigInteger a = new BigInteger(1, hexa);
+		private static readonly BigInteger b = new BigInteger(1, hexb);
+
+		/** Base point G (with point compression) */
+		private byte[] enc = {0x02, 0x19, 0x7B, 0x07, (byte)0x84, 0x5E, (byte)0x9B, (byte)0xE2, (byte)0xD9, 0x6A, (byte)0xDB, 0x0F
+				, 0x5F, 0x3C, 0x7F, 0x2C, (byte)0xFF, (byte)0xBD, 0x7A, 0x3E, (byte)0xB8, (byte)0xB6, (byte)0xFE, 
+				(byte)0xC3, 0x5C, 0x7F, (byte)0xD6, 0x7F, 0x26, (byte)0xDD, (byte)0xF6
+				, 0x28, 0x5A, 0x64, 0x4F, 0x74, 0x0A, 0x26, 0x14};
+
+		private void doTestPointCompression() 
+		{
+			ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b);
+			curve.DecodePoint(enc);
+
+			int[] ks = new int[3];
+			ks[0] = k3;
+			ks[1] = k2;
+			ks[2] = k1;
+		}
+	    
+		public override void PerformTest()
+		{
+			byte[] ecParams = Hex.Decode("3081C8020101302806072A8648CE3D0101021D00D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF303C041C68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43041C2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B0439040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD021D00D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F020101");
+			doTestParams(ecParams, true);
+
+			doTestParams(ecParams, false);
+
+			ecParams = Hex.Decode("3081C8020101302806072A8648CE3D0101021D00D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF303C041C56E6C7E4F11A7B4B961A4DCB5BD282EB22E42E9BCBE3E7B361F18012041C4BE3E7B361F18012F2353D22975E02D8D05D2C6F3342DD8F57D4C76F0439048D127A0C27E0DE207ED3B7FB98F83C8BD5A2A57C827F4B97874DEB2C1BAEB0C006958CE61BB1FC81F5389E288CB3E86E2ED91FB47B08FCCA021D00D7C134AA264366862A18302575D11A5F7AABFBA3D897FF5CA727AF53020101");
+			doTestParams(ecParams, true);
+
+			doTestParams(ecParams, false);
+
+			ecParams = Hex.Decode("30820142020101303c06072a8648ce3d0101023100fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff3066043100fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc043100b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef046104aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f023100ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973020101");
+			doTestParams(ecParams, true);
+
+			doTestParams(ecParams, false);
+
+			doTestPointCompression();
+		}
+
+		private void doTestParams(
+			byte[]	ecParameterEncoded,
+			bool	compress)
+		{
+//			string keyStorePass = "myPass";
+			Asn1Sequence seq = (Asn1Sequence) Asn1Object.FromByteArray(ecParameterEncoded);
+			X9ECParameters x9 = new X9ECParameters(seq);
+			AsymmetricCipherKeyPair kp = null;
+			bool success = false;
+			while (!success)
+			{
+				IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+//				kpg.Init(new ECParameterSpec(x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed()));
+				ECDomainParameters ecParams = new ECDomainParameters(
+					x9.Curve, x9.G, x9.N, x9.H, x9.GetSeed());
+				kpg.Init(new ECKeyGenerationParameters(ecParams, new SecureRandom()));
+				kp = kpg.GenerateKeyPair();
+				// The very old Problem... we need a certificate chain to
+				// save a private key...
+				ECPublicKeyParameters pubKey = (ECPublicKeyParameters) kp.Public;
+
+				if (!compress)
+				{
+					//pubKey.setPointFormat("UNCOMPRESSED");
+					pubKey = SetPublicUncompressed(pubKey, false);
+				}
+
+				byte[] x = pubKey.Q.AffineXCoord.ToBigInteger().ToByteArrayUnsigned();
+				byte[] y = pubKey.Q.AffineYCoord.ToBigInteger().ToByteArrayUnsigned();
+				if (x.Length == y.Length)
+				{
+					success = true;
+				}
+			}
+
+			// The very old Problem... we need a certificate chain to
+			// save a private key...
+
+			X509CertificateEntry[] chain = new X509CertificateEntry[] {
+				new X509CertificateEntry(GenerateSelfSignedSoftECCert(kp, compress))
+			};
+
+//			KeyStore keyStore = KeyStore.getInstance("BKS");
+//			keyStore.load(null, keyStorePass.ToCharArray());
+			Pkcs12Store keyStore = new Pkcs12StoreBuilder().Build();
+
+			keyStore.SetCertificateEntry("ECCert", chain[0]);
+
+			ECPrivateKeyParameters privateECKey = (ECPrivateKeyParameters) kp.Private;
+			keyStore.SetKeyEntry("ECPrivKey", new AsymmetricKeyEntry(privateECKey), chain);
+
+			// Test ec sign / verify
+			ECPublicKeyParameters pub = (ECPublicKeyParameters) kp.Public;
+//			string oldPrivateKey = new string(Hex.encode(privateECKey.getEncoded()));
+			byte[] oldPrivateKeyBytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateECKey).GetDerEncoded();
+			string oldPrivateKey = Hex.ToHexString(oldPrivateKeyBytes);
+//			string oldPublicKey = new string(Hex.encode(pub.getEncoded()));
+			byte[] oldPublicKeyBytes = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub).GetDerEncoded();
+			string oldPublicKey = Hex.ToHexString(oldPublicKeyBytes);
+			ECPrivateKeyParameters newKey = (ECPrivateKeyParameters)
+				keyStore.GetKey("ECPrivKey").Key;
+			ECPublicKeyParameters newPubKey = (ECPublicKeyParameters)
+				keyStore.GetCertificate("ECCert").Certificate.GetPublicKey();
+
+			if (!compress)
+			{
+				// TODO Private key compression?
+				//newKey.setPointFormat("UNCOMPRESSED");
+				//newPubKey.setPointFormat("UNCOMPRESSED");
+				newPubKey = SetPublicUncompressed(newPubKey, false);
+			}
+
+//			string newPrivateKey = new string(Hex.encode(newKey.getEncoded()));
+			byte[] newPrivateKeyBytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(newKey).GetDerEncoded();
+			string newPrivateKey = Hex.ToHexString(newPrivateKeyBytes);
+//			string newPublicKey = new string(Hex.encode(newPubKey.getEncoded()));
+			byte[] newPublicKeyBytes = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(newPubKey).GetDerEncoded();
+			string newPublicKey = Hex.ToHexString(newPublicKeyBytes);
+
+			if (!oldPrivateKey.Equals(newPrivateKey))
+//			if (!privateECKey.Equals(newKey))
+			{
+				Fail("failed private key comparison");
+			}
+
+			if (!oldPublicKey.Equals(newPublicKey))
+//			if (!pub.Equals(newPubKey))
+			{
+				Fail("failed public key comparison");
+			}
+		}
+
+		/**
+		* Create a self signed cert for our software emulation
+		* 
+		* @param kp
+		*            is the keypair for our certificate
+		* @return a self signed cert for our software emulation
+		* @throws InvalidKeyException
+		*             on error
+		* @throws SignatureException
+		*             on error
+		*/
+		private X509Certificate GenerateSelfSignedSoftECCert(
+			AsymmetricCipherKeyPair	kp,
+			bool					compress)
+		{
+			X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+			ECPrivateKeyParameters privECKey = (ECPrivateKeyParameters) kp.Private;
+			ECPublicKeyParameters pubECKey = (ECPublicKeyParameters) kp.Public;
+
+			if (!compress)
+			{
+				// TODO Private key compression?
+				//privECKey.setPointFormat("UNCOMPRESSED");
+				//pubECKey.setPointFormat("UNCOMPRESSED");
+				pubECKey = SetPublicUncompressed(pubECKey, false);
+			}
+
+			certGen.SetSignatureAlgorithm("ECDSAwithSHA1");
+			certGen.SetSerialNumber(BigInteger.One);
+			certGen.SetIssuerDN(new X509Name("CN=Software emul (EC Cert)"));
+			certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50000));
+			certGen.SetSubjectDN(new X509Name("CN=Software emul (EC Cert)"));
+			certGen.SetPublicKey(pubECKey);
+
+			return certGen.Generate(privECKey);
+		}
+
+		private ECPublicKeyParameters SetPublicUncompressed(
+			ECPublicKeyParameters	key,
+			bool					withCompression)
+		{
+			ECPoint p = key.Q.Normalize();
+			return new ECPublicKeyParameters(
+				key.AlgorithmName,
+				p.Curve.CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), withCompression),
+				key.Parameters);
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ECEncodingTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/ECNRTest.cs b/crypto/test/src/test/ECNRTest.cs
new file mode 100644
index 000000000..8a24443c2
--- /dev/null
+++ b/crypto/test/src/test/ECNRTest.cs
@@ -0,0 +1,204 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class ECNRTest
+        : SimpleTest
+    {
+        private static readonly byte[] k1 = Hex.Decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
+        private static readonly byte[] k2 = Hex.Decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded");
+
+        private readonly SecureRandom random = FixedSecureRandom.From(k1, k2);
+
+        /**
+         * X9.62 - 1998,<br/>
+         * J.3.2, Page 155, ECDSA over the field Fp<br/>
+         * an example with 239 bit prime
+         */
+        [Test]
+        public void TestECNR239bitPrime()
+        {
+            BigInteger r = new BigInteger("308636143175167811492623515537541734843573549327605293463169625072911693");
+            BigInteger s = new BigInteger("852401710738814635664888632022555967400445256405412579597015412971797143");
+
+            byte[] kData = new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655").ToByteArrayUnsigned();
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            X9ECParameters p = X962NamedCurves.GetByOid(X9ObjectIdentifiers.Prime239v1);
+            ECDomainParameters spec = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECCurve curve = spec.Curve;
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d
+                spec);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                curve.DecodePoint(Hex.Decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q
+                spec);
+
+            ISigner sgr = SignerUtilities.GetSigner("SHA1withECNR");
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            checkSignature(239, priKey, pubKey, sgr, k, message, r, s);
+        }
+
+        // -------------------------------------------------------------------------
+
+        /**
+         * X9.62 - 1998,<br/>
+         * Page 104-105, ECDSA over the field Fp<br/>
+         * an example with 192 bit prime
+         */
+        [Test]
+        public void TestECNR192bitPrime()
+        {
+            BigInteger r  = new BigInteger("2474388605162950674935076940284692598330235697454145648371");
+            BigInteger s  = new BigInteger("2997192822503471356158280167065034437828486078932532073836");
+
+            byte[] kData = new BigInteger("dcc5d1f1020906df2782360d36b2de7a17ece37d503784af", 16).ToByteArrayUnsigned();
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            X9ECParameters p = X962NamedCurves.GetByOid(X9ObjectIdentifiers.Prime192v1);
+            ECDomainParameters spec = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECCurve curve = spec.Curve;
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d
+                spec);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                curve.DecodePoint(Hex.Decode("0262B12D60690CDCF330BABAB6E69763B471F994DD702D16A5")), // Q
+                spec);
+
+            ISigner sgr = SignerUtilities.GetSigner("SHA1withECNR");
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            checkSignature(192, priKey, pubKey, sgr, k, message, r, s);
+        }
+
+        // -------------------------------------------------------------------------
+
+        /**
+         * SEC 2: Recommended Elliptic Curve Domain Parameters - September 2000,<br/>
+         * Page 17-19, Recommended 521-bit Elliptic Curve Domain Parameters over Fp<br/>
+         * an ECC example with a 521 bit prime and a 512 bit hash
+         */
+        [Test]
+        public void TestECNR521bitPrime()
+        {
+            BigInteger r  = new BigInteger("1820641608112320695747745915744708800944302281118541146383656165330049339564439316345159057453301092391897040509935100825960342573871340486684575368150970954");
+            BigInteger s  = new BigInteger("6358277176448326821136601602749690343031826490505780896013143436153111780706227024847359990383467115737705919410755190867632280059161174165591324242446800763");
+
+            byte[] kData = new BigInteger("cdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", 16).ToByteArrayUnsigned();
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            X9ECParameters p = SecNamedCurves.GetByOid(SecObjectIdentifiers.SecP521r1);
+            ECDomainParameters spec = new ECDomainParameters(p.Curve, p.G, p.N, p.H);
+            ECCurve curve = spec.Curve;
+
+            ECPrivateKeyParameters priKey = new ECPrivateKeyParameters(
+                new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+                spec);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+                curve.DecodePoint(Hex.Decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+                spec);
+
+            ISigner sgr = SignerUtilities.GetSigner("SHA512withECNR");
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            checkSignature(521, priKey, pubKey, sgr, k, message, r, s);
+        }
+
+        private void checkSignature(
+            int						size,
+            ECPrivateKeyParameters	sKey,
+            ECPublicKeyParameters	vKey,
+            ISigner					sgr,
+            SecureRandom			k,
+            byte[]					message,
+            BigInteger				r,
+            BigInteger				s)
+        {
+            sgr.Init(true, new ParametersWithRandom(sKey, k));
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail(size + " bit EC verification failed");
+            }
+
+            BigInteger[] sig = derDecode(sigBytes);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail(size + "bit"
+                    + ": r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail(size + "bit"
+                    + ": s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+        }
+
+        protected BigInteger[] derDecode(
+            byte[] encoding)
+        {
+            Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+            return new BigInteger[]
+            {
+                ((DerInteger)s[0]).Value,
+                ((DerInteger)s[1]).Value
+            };
+        }
+
+        public override string Name
+        {
+            get { return "ECNR"; }
+        }
+
+        public override void PerformTest()
+        {
+            TestECNR192bitPrime();
+            TestECNR239bitPrime();
+            TestECNR521bitPrime();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new ECNRTest());
+        }
+    }
+}
diff --git a/crypto/test/src/test/ElGamalTest.cs b/crypto/test/src/test/ElGamalTest.cs
new file mode 100644
index 000000000..9a87ea9b1
--- /dev/null
+++ b/crypto/test/src/test/ElGamalTest.cs
@@ -0,0 +1,334 @@
+using System;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class ElGamalTest
+		: SimpleTest
+	{
+		private static readonly BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+		private static readonly BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+		private static readonly BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16);
+		private static readonly BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16);
+
+		private static readonly BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16);
+		private static readonly BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16);
+
+		public override string Name
+		{
+			get { return "ElGamal"; }
+		}
+
+		[Test]
+		public void TestGP512()
+		{
+			doTestGP(512, 0, g512, p512);
+			doTestGP(512, 64, g512, p512);
+		}
+
+		[Test]
+		public void TestGP768()
+		{
+			doTestGP(768, 0, g768, p768);
+			doTestGP(768, 128, g768, p768);
+		}
+
+		[Test]
+		public void TestGP1024()
+		{
+			doTestGP(1024, 0, g1024, p1024);
+			doTestGP(1024, 256, g1024, p1024);
+		}
+
+		[Test]
+		public void TestRandom256()
+		{
+			doTestRandom(256);
+		}
+
+		private void doTestGP(
+			int			size,
+			int         privateValueSize,
+			BigInteger	g,
+			BigInteger	p)
+		{
+			IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator("ElGamal");
+
+//			DHParameterSpec elParams = new DHParameterSpec(p, g);
+//			keyGen.initialize(elParams);
+			ElGamalParameters elParams = new ElGamalParameters(p, g, privateValueSize);
+			ElGamalKeyGenerationParameters elKgp = new ElGamalKeyGenerationParameters(
+				new SecureRandom(), elParams);
+			keyGen.Init(elKgp);
+
+			AsymmetricCipherKeyPair keyPair = keyGen.GenerateKeyPair();
+			SecureRandom rand = new SecureRandom();
+
+			checkKeySize(privateValueSize, keyPair);
+
+			IBufferedCipher cipher = CipherUtilities.GetCipher("ElGamal");
+
+			cipher.Init(true, new ParametersWithRandom(keyPair.Public, rand));
+
+			byte[] inBytes = Encoding.ASCII.GetBytes("This is a test");
+
+			if (cipher.GetOutputSize(inBytes.Length) != (size / 8) * 2)
+			{
+				Fail("getOutputSize wrong on encryption");
+			}
+
+			byte[] outBytes = cipher.DoFinal(inBytes);
+
+			cipher.Init(false, keyPair.Private);
+
+			if (cipher.GetOutputSize(outBytes.Length) != (size / 8) - 1)
+			{
+				Fail("GetOutputSize wrong on decryption");
+			}
+
+
+			//
+			// No Padding - maximum length
+			//
+			byte[] modBytes = ((ElGamalPublicKeyParameters)keyPair.Public).Parameters.P.ToByteArray();
+			byte[] maxInput = new byte[modBytes.Length - 1];
+
+			maxInput[0] |= 0x7f;
+
+			cipher.Init(true, new ParametersWithRandom(keyPair.Public, rand));
+
+			outBytes = cipher.DoFinal(maxInput);
+
+			cipher.Init(false, keyPair.Private);
+
+			outBytes = cipher.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, maxInput))
+			{
+				Fail("NoPadding test failed on decrypt expected "
+					+ Hex.ToHexString(maxInput) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+
+			//
+			// encrypt/decrypt
+			//
+			IBufferedCipher c1 = CipherUtilities.GetCipher("ElGamal");
+			IBufferedCipher c2 = CipherUtilities.GetCipher("ElGamal");
+
+			c1.Init(true, new ParametersWithRandom(keyPair.Public, rand));
+
+			byte[] out1 = c1.DoFinal(inBytes);
+
+			c2.Init(false, keyPair.Private);
+
+			byte[] out2 = c2.DoFinal(out1);
+
+			if (!AreEqual(inBytes, out2))
+			{
+				Fail(size + " encrypt test failed");
+			}
+
+
+			//
+			// encrypt/decrypt with update
+			//
+			int outLen = c1.ProcessBytes(inBytes, 0, 2, out1, 0);
+
+			outLen += c1.DoFinal(inBytes, 2, inBytes.Length - 2, out1, outLen);
+
+			outLen = c2.ProcessBytes(out1, 0, 2, out2, 0);
+
+			outLen += c2.DoFinal(out1, 2, out1.Length - 2, out2, outLen);
+
+			if (!AreEqual(inBytes, out2))
+			{
+				Fail(size + " encrypt with update test failed");
+			}
+
+
+
+			//
+			// public key encoding test
+			//
+//			byte[] pubEnc = keyPair.Public.GetEncoded();
+			byte[] pubEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public).GetDerEncoded();
+
+//			KeyFactory keyFac = KeyFactory.GetInstance("ElGamal");
+//			X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc);
+//			DHPublicKeyParameters pubKey = (DHPublicKeyParameters)keyFac.generatePublic(pubX509);
+			ElGamalPublicKeyParameters pubKey = (ElGamalPublicKeyParameters)
+				PublicKeyFactory.CreateKey(pubEnc);
+			ElGamalParameters spec = pubKey.Parameters;
+
+			if (!spec.G.Equals(elParams.G) || !spec.P.Equals(elParams.P))
+			{
+				Fail(size + " bit public key encoding/decoding test failed on parameters");
+			}
+
+			if (!((ElGamalPublicKeyParameters)keyPair.Public).Y.Equals(pubKey.Y))
+			{
+				Fail(size + " bit public key encoding/decoding test failed on y value");
+			}
+
+/*
+			//
+			// public key serialisation test
+			//
+			// TODO Is there some standard this serialization must conform to?
+			BinaryFormatter formatter = new BinaryFormatter();
+
+			MemoryStream bOut = new MemoryStream();
+//			ObjectOutputStream oOut = new ObjectOutputStream(bOut);
+//			oOut.writeObject(keyPair.Public);
+			formatter.Serialize(bOut, keyPair.Public);
+
+			MemoryStream bIn = new MemoryStream(bOut.ToArray(), false);
+//			ObjectInputStream oIn = new ObjectInputStream(bIn);
+//			pubKey = (DHPublicKeyParameters)oIn.readObject();
+			pubKey = (ElGamalPublicKeyParameters) formatter.Deserialize(bIn);
+			spec = pubKey.Parameters;
+
+			if (!spec.G.Equals(elParams.G) || !spec.P.Equals(elParams.P))
+			{
+				Fail(size + " bit public key serialisation test failed on parameters");
+			}
+
+			if (!((ElGamalPublicKeyParameters )keyPair.Public).Y.Equals(pubKey.Y))
+			{
+				Fail(size + " bit public key serialisation test failed on y value");
+			}
+*/
+
+			//
+			// private key encoding test
+			//
+			// TODO Keys don't support GetEncoded
+//			byte[] privEnc = keyPair.Private.GetEncoded();
+			byte[] privEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private).GetDerEncoded();
+
+//			PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
+//			DHPrivateKeyParameters privKey = (DHPrivateKeyParameters)keyFac.generatePrivate(privPKCS8);
+			ElGamalPrivateKeyParameters privKey = (ElGamalPrivateKeyParameters)
+				PrivateKeyFactory.CreateKey(privEnc);
+
+			spec = privKey.Parameters;
+
+			if (!spec.G.Equals(elParams.G) || !spec.P.Equals(elParams.P))
+			{
+				Fail(size + " bit private key encoding/decoding test failed on parameters");
+			}
+
+			if (!((ElGamalPrivateKeyParameters)keyPair.Private).X.Equals(privKey.X))
+			{
+				Fail(size + " bit private key encoding/decoding test failed on y value");
+			}
+
+/*
+			//
+			// private key serialisation test
+			//
+			bOut = new MemoryStream();
+//			oOut = new ObjectOutputStream(bOut);
+//			oOut.writeObject(keyPair.Private);
+			formatter.Serialize(bOut, keyPair.Private);
+
+			bIn = new MemoryStream(bOut.ToArray(), false);
+//			oIn = new ObjectInputStream(bIn);
+//			privKey = (DHPrivateKeyParameters)oIn.readObject();
+			privKey = (ElGamalPrivateKeyParameters) formatter.Deserialize(bIn);
+			spec = privKey.Parameters;
+
+			if (!spec.G.Equals(elParams.G) || !spec.P.Equals(elParams.P))
+			{
+				Fail(size + " bit private key serialisation test failed on parameters");
+			}
+
+			if (!((ElGamalPrivateKeyParameters) keyPair.Private).X.Equals(privKey.X))
+			{
+				Fail(size + " bit private key serialisation test failed on y value");
+			}
+*/
+		}
+
+		private void checkKeySize(int privateValueSize, AsymmetricCipherKeyPair aKeyPair)
+		{
+			if (privateValueSize != 0)
+			{
+//				DHPrivateKey key = (DHPrivateKey)aKeyPair.getPrivate();
+				ElGamalPrivateKeyParameters key = (ElGamalPrivateKeyParameters) aKeyPair.Private;
+
+				if (key.X.BitLength != privateValueSize)
+				{
+					Fail("limited key check failed for key size " + privateValueSize);
+				}
+			}
+		}
+
+		private void doTestRandom(
+			int size)
+		{
+//			AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("ElGamal");
+//			a.init(size, new SecureRandom());
+			ElGamalParametersGenerator a = new ElGamalParametersGenerator();
+			a.Init(size, 20, new SecureRandom());
+
+//			AlgorithmParameters parameters = a.generateParameters();
+			ElGamalParameters p = a.GenerateParameters();
+
+//			byte[] encodeParams = parameters.GetEncoded();
+			byte[] encodeParams = new ElGamalParameter(p.P, p.G).GetDerEncoded(); 
+
+//			AlgorithmParameters a2 = AlgorithmParameters.getInstance("ElGamal");
+//			a2.init(encodeParams);
+			ElGamalParameter elP = new ElGamalParameter((Asn1Sequence) Asn1Object.FromByteArray(encodeParams));
+			ElGamalParameters p2 = new ElGamalParameters(elP.P, elP.G);
+
+			// a and a2 should be equivalent!
+//			byte[] encodeParams_2 = a2.GetEncoded();
+			byte[] encodeParams_2 = new ElGamalParameter(p2.P, p2.G).GetDerEncoded(); 
+
+			if (!AreEqual(encodeParams, encodeParams_2))
+			{
+				Fail(this.Name + ": encode/decode parameters failed");
+			}
+
+//			DHParameters elP = (DHParameters)parameters.getParameterSpec(typeof(DHParameters));
+
+			doTestGP(size, 0, elP.G, elP.P);
+		}
+
+		public override void PerformTest()
+		{
+			TestGP512();
+			TestGP768();
+			TestGP1024();
+			TestRandom256();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new ElGamalTest());
+		}
+	}
+}
diff --git a/crypto/test/src/test/EncryptedPrivateKeyInfoTest.cs b/crypto/test/src/test/EncryptedPrivateKeyInfoTest.cs
new file mode 100644
index 000000000..baac5ff7f
--- /dev/null
+++ b/crypto/test/src/test/EncryptedPrivateKeyInfoTest.cs
@@ -0,0 +1,154 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class EncryptedPrivateKeyInfoTest
+		: SimpleTest
+	{
+		private const string alg = "1.2.840.113549.1.12.1.3"; // 3 key triple DES with SHA-1
+
+		public override void PerformTest()
+		{
+			IAsymmetricCipherKeyPairGenerator fact = GeneratorUtilities.GetKeyPairGenerator("RSA");
+			fact.Init(new KeyGenerationParameters(new SecureRandom(), 512));
+
+			AsymmetricCipherKeyPair keyPair = fact.GenerateKeyPair();
+
+			AsymmetricKeyParameter priKey = keyPair.Private;
+			AsymmetricKeyParameter pubKey = keyPair.Public;
+
+			//
+			// set up the parameters
+			//
+			byte[] salt = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+			int iterationCount = 100;
+			Asn1Encodable defParams = PbeUtilities.GenerateAlgorithmParameters(alg, salt, iterationCount);
+			char[] password1 = { 'h', 'e', 'l', 'l', 'o' };
+
+//				AlgorithmParameters parameters = AlgorithmParameters.getInstance(alg);
+//
+//				parameters.init(defParams);
+
+			//
+			// set up the key
+			//
+//				PBEKeySpec pbeSpec = new PBEKeySpec(password1);
+//				SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg);
+
+//				IBufferedCipher cipher = CipherUtilities.GetCipher(alg);
+			IWrapper wrapper = WrapperUtilities.GetWrapper(alg);
+
+			ICipherParameters parameters = PbeUtilities.GenerateCipherParameters(
+				alg, password1, defParams);
+
+//				cipher.Init(IBufferedCipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), parameters);
+			wrapper.Init(true, parameters);
+
+//				byte[] wrappedKey = cipher.Wrap(priKey);
+			byte[] pkb = PrivateKeyInfoFactory.CreatePrivateKeyInfo(priKey).GetDerEncoded();
+			byte[] wrappedKey = wrapper.Wrap(pkb, 0, pkb.Length);
+
+			//
+			// create encrypted object
+			//
+
+			// TODO Figure out what this was supposed to do
+//				EncryptedPrivateKeyInfo pInfo = new EncryptedPrivateKeyInfo(parameters, wrappedKey);
+			PrivateKeyInfo plain = PrivateKeyInfoFactory.CreatePrivateKeyInfo(priKey);
+			EncryptedPrivateKeyInfo pInfo = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+				alg, password1, salt, iterationCount,  plain);
+
+
+			//
+			// decryption step
+			//
+			char[] password2 = { 'h', 'e', 'l', 'l', 'o' };
+
+//				pbeSpec = new PBEKeySpec(password2);
+//
+//				cipher = CipherUtilities.GetCipher(pInfo.EncryptionAlgorithm);
+//
+//				cipher.Init(false, keyFact.generateSecret(pbeSpec), pInfo.getAlgParameters());
+//
+//				PKCS8EncodedKeySpec keySpec = pInfo.getKeySpec(cipher);
+			PrivateKeyInfo decrypted = PrivateKeyInfoFactory.CreatePrivateKeyInfo(password2, pInfo);
+
+//				if (!MessageDigest.isEqual(priKey.GetEncoded(), keySpec.GetEncoded()))
+			if (!decrypted.Equals(plain))
+			{
+				Fail("Private key does not match");
+			}
+
+			//
+			// using ICipherParameters test
+			//
+//			pbeSpec = new PBEKeySpec(password1);
+//			keyFact = SecretKeyFactory.getInstance(alg);
+//			cipher = CipherUtilities.GetCipher(alg);
+			wrapper = WrapperUtilities.GetWrapper(alg);
+
+//			cipher.init(IBufferedCipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), parameters);
+			wrapper.Init(true, parameters);
+
+//			wrappedKey = cipher.wrap(priKey);
+			wrappedKey = wrapper.Wrap(pkb, 0, pkb.Length);
+
+			//
+			// create encrypted object
+			//
+
+			// TODO Figure out what this was supposed to do
+//			pInfo = new EncryptedPrivateKeyInfo(cipher.getParameters(), wrappedKey);
+			plain = PrivateKeyInfoFactory.CreatePrivateKeyInfo(priKey);
+			pInfo = EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+				alg, password1, salt, iterationCount,  plain);
+
+			//
+			// decryption step
+			//
+//			pbeSpec = new PBEKeySpec(password2);
+//
+//			cipher = CipherUtilities.GetCipher(pInfo.getAlgName());
+//
+//			cipher.init(IBufferedCipher.DECRYPT_MODE, keyFact.generateSecret(pbeSpec), pInfo.getAlgParameters());
+//
+//			keySpec = pInfo.getKeySpec(cipher);
+			decrypted = PrivateKeyInfoFactory.CreatePrivateKeyInfo(password2, pInfo);
+
+//			if (!MessageDigest.isEqual(priKey.GetEncoded(), keySpec.GetEncoded()))
+			if (!decrypted.Equals(plain))
+			{
+				Fail("Private key does not match");
+			}
+		}
+
+		public override string Name
+		{
+			get { return "EncryptedPrivateKeyInfoTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new EncryptedPrivateKeyInfoTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/FIPSDESTest.cs b/crypto/test/src/test/FIPSDESTest.cs
new file mode 100644
index 000000000..1f40e1591
--- /dev/null
+++ b/crypto/test/src/test/FIPSDESTest.cs
@@ -0,0 +1,205 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <remarks>
+	/// Basic FIPS test class for a block cipher, just to make sure ECB/CBC/OFB/CFB are behaving
+	/// correctly. Tests from <a href="http://www.itl.nist.gov/fipspubs/fip81.htm">FIPS 81</a>.
+	/// </remarks>
+	[TestFixture]
+	public class FipsDesTest
+		: ITest
+	{
+		private static readonly string[] fips1Tests =
+		{
+			"DES/ECB/NoPadding",
+			"3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53",
+			"DES/CBC/NoPadding",
+			"e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6",
+			"DES/CFB/NoPadding",
+			"f3096249c7f46e51a69e839b1a92f78403467133898ea622"
+		};
+
+		private static readonly string[] fips2Tests =
+		{
+			"DES/CFB8/NoPadding",
+			"f31fda07011462ee187f",
+			"DES/OFB8/NoPadding",
+			"f34a2850c9c64985d684"
+		};
+
+		private static readonly byte[] input1 = Hex.Decode("4e6f77206973207468652074696d6520666f7220616c6c20");
+		private static readonly byte[] input2 = Hex.Decode("4e6f7720697320746865");
+
+		public string Name
+		{
+			get { return "FIPSDES"; }
+		}
+
+		public ITestResult doTest(
+			string	algorithm,
+			byte[]	input,
+			byte[]	output)
+		{
+			KeyParameter key;
+			IBufferedCipher inCipher, outCipher;
+			CipherStream cIn, cOut;
+			MemoryStream bIn, bOut;
+
+//			IvParameterSpec spec = new IvParameterSpec();
+			byte[] spec = Hex.Decode("1234567890abcdef");
+
+			try
+			{
+				key = new DesParameters(Hex.Decode("0123456789abcdef"));
+
+				inCipher = CipherUtilities.GetCipher(algorithm);
+				outCipher = CipherUtilities.GetCipher(algorithm);
+
+				if (algorithm.StartsWith("DES/ECB"))
+				{
+					outCipher.Init(true, key);
+				}
+				else
+				{
+					outCipher.Init(true, new ParametersWithIV(key, spec));
+				}
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": " + algorithm + " failed initialisation - " + e.ToString(), e);
+			}
+
+			try
+			{
+				if (algorithm.StartsWith("DES/ECB"))
+				{
+					inCipher.Init(false, key);
+				}
+				else
+				{
+					inCipher.Init(false, new ParametersWithIV(key, spec));
+				}
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": " + algorithm + " failed initialisation - " + e.ToString(), e);
+			}
+
+			//
+			// encryption pass
+			//
+			bOut = new MemoryStream();
+			cOut = new CipherStream(bOut, null, outCipher);
+
+			try
+			{
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+					cOut.WriteByte(input[i]);
+				}
+				cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+				cOut.Close();
+			}
+			catch (IOException e)
+			{
+				return new SimpleTestResult(false, Name + ": " + algorithm + " failed encryption - " + e.ToString());
+			}
+
+			byte[] bytes = bOut.ToArray();
+
+			if (!Arrays.AreEqual(bytes, output))
+			{
+				return new SimpleTestResult(false, Name + ": " + algorithm + " failed encryption - expected "
+					+ Hex.ToHexString(output) + " got " + Hex.ToHexString(bytes));
+			}
+
+			//
+			// decryption pass
+			//
+			bIn = new MemoryStream(bytes, false);
+			cIn = new CipherStream(bIn, inCipher, null);
+
+			try
+			{
+				BinaryReader dIn = new BinaryReader(cIn);
+
+				bytes = new byte[input.Length];
+
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+					bytes[i] = dIn.ReadByte();
+				}
+
+				int remaining = bytes.Length - input.Length / 2;
+				byte[] extra = dIn.ReadBytes(remaining);
+				if (extra.Length < remaining)
+					throw new EndOfStreamException();
+				extra.CopyTo(bytes, input.Length / 2);
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": " + algorithm + " failed encryption - " + e.ToString());
+			}
+
+			if (!Arrays.AreEqual(bytes, input))
+			{
+				return new SimpleTestResult(false, Name + ": " + algorithm + " failed decryption - expected "
+					+ Hex.ToHexString(input) + " got " + Hex.ToHexString(bytes));
+			}
+
+			return new SimpleTestResult(true, Name + ": " + algorithm + " Okay");
+		}
+
+		public ITestResult Perform()
+		{
+			for (int i = 0; i != fips1Tests.Length; i += 2)
+			{
+				ITestResult result = doTest(fips1Tests[i], input1, Hex.Decode(fips1Tests[i + 1]));
+				if (!result.IsSuccessful())
+				{
+					return result;
+				}
+			}
+
+			for (int i = 0; i != fips2Tests.Length; i += 2)
+			{
+				ITestResult result = doTest(fips2Tests[i], input2, Hex.Decode(fips2Tests[i + 1]));
+				if (!result.IsSuccessful())
+				{
+					return result;
+				}
+			}
+
+			return new SimpleTestResult(true, Name + ": Okay");
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new FipsDesTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/GOST28147Test.cs b/crypto/test/src/test/GOST28147Test.cs
new file mode 100644
index 000000000..0adfad334
--- /dev/null
+++ b/crypto/test/src/test/GOST28147Test.cs
@@ -0,0 +1,245 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <remarks>Basic test class for the GOST28147 cipher</remarks>
+	[TestFixture]
+	public class Gost28147Test
+		: SimpleTest
+	{
+		private static string[] cipherTests =
+		{
+			"256",
+			"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+			"4e6f77206973207468652074696d6520666f7220616c6c20",
+			"281630d0d5770030068c252d841e84149ccc1912052dbc02",
+
+			"256",
+			"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+			"4e6f77206973207468652074696d65208a920c6ed1a804f5",
+			"88e543dfc04dc4f764fa7b624741cec07de49b007bf36065"
+		};
+
+		public override string Name
+		{
+			get { return "GOST28147"; }
+		}
+
+		private void doTestEcb(
+			int		strength,
+			byte[]	keyBytes,
+			byte[]	input,
+			byte[]	output)
+		{
+			IBufferedCipher inCipher, outCipher;
+			CipherStream cIn, cOut;
+			MemoryStream bIn, bOut;
+
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("GOST28147", keyBytes);
+
+			inCipher = CipherUtilities.GetCipher("GOST28147/ECB/NoPadding");
+			outCipher = CipherUtilities.GetCipher("GOST28147/ECB/NoPadding");
+			outCipher.Init(true, key);
+			inCipher.Init(false, key);
+
+			//
+			// encryption pass
+			//
+			bOut = new MemoryStream();
+			cOut = new CipherStream(bOut, null, outCipher);
+
+			for (int i = 0; i != input.Length / 2; i++)
+			{
+				cOut.WriteByte(input[i]);
+			}
+			cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+			cOut.Close();
+
+			byte[] bytes = bOut.ToArray();
+
+			if (!AreEqual(bytes, output))
+			{
+				Fail("GOST28147 failed encryption - expected "
+					+ Hex.ToHexString(output) + " got " + Hex.ToHexString(bytes));
+			}
+
+			//
+			// decryption pass
+			//
+			bIn = new MemoryStream(bytes, false);
+			cIn = new CipherStream(bIn, inCipher, null);
+
+			BinaryReader dIn = new BinaryReader(cIn);
+
+			bytes = new byte[input.Length];
+
+			for (int i = 0; i != input.Length / 2; i++)
+			{
+				bytes[i] = dIn.ReadByte();
+			}
+
+			int remaining = bytes.Length - input.Length / 2;
+			byte[] extra = dIn.ReadBytes(remaining);
+			if (extra.Length < remaining)
+				throw new EndOfStreamException();
+			extra.CopyTo(bytes, input.Length / 2);
+
+			if (!AreEqual(bytes, input))
+			{
+				Fail("GOST28147 failed decryption - expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(bytes));
+			}
+		}
+
+		private void doTestCfb(
+			int         strength,
+			byte[]      keyBytes,
+			byte[]      input,
+			byte[]      output)
+		{
+			IBufferedCipher inCipher, outCipher;
+			CipherStream cIn, cOut;
+			MemoryStream bIn, bOut;
+
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("GOST28147", keyBytes);
+
+			inCipher = CipherUtilities.GetCipher("GOST28147/CFB8/NoPadding");
+			outCipher = CipherUtilities.GetCipher("GOST28147/CFB8/NoPadding");
+			byte[] iv = {1,2,3,4,5,6,7,8};
+
+			outCipher.Init(true, new ParametersWithIV(key, iv));
+			inCipher.Init(false, new ParametersWithIV(key, iv));
+
+			//
+			// encryption pass
+			//
+			bOut = new MemoryStream();
+			cOut = new CipherStream(bOut, null, outCipher);
+
+			for (int i = 0; i != input.Length / 2; i++)
+			{
+				cOut.WriteByte(input[i]);
+			}
+			cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+			cOut.Close();
+
+			byte[] bytes = bOut.ToArray();
+
+			if (!AreEqual(bytes, output))
+			{
+				Fail("GOST28147 failed encryption - expected " + Hex.ToHexString(output) + " got " + Hex.ToHexString(bytes));
+			}
+
+			//
+			// decryption pass
+			//
+			bIn = new MemoryStream(bytes, false);
+			cIn = new CipherStream(bIn, inCipher, null);
+
+			BinaryReader dIn = new BinaryReader(cIn);
+
+			bytes = new byte[input.Length];
+
+			for (int i = 0; i != input.Length / 2; i++)
+			{
+				bytes[i] = dIn.ReadByte();
+			}
+
+			int remaining = bytes.Length - input.Length / 2;
+			byte[] extra = dIn.ReadBytes(remaining);
+			if (extra.Length < remaining)
+				throw new EndOfStreamException();
+			extra.CopyTo(bytes, input.Length / 2);
+
+			if (!AreEqual(bytes, input))
+			{
+				Fail("GOST28147 failed decryption - expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(bytes));
+			}
+		}
+
+		private void doOidTest()
+		{
+			string[] oids = {
+					CryptoProObjectIdentifiers.GostR28147Cbc.Id,
+			};
+
+			string[] names = {
+				"GOST28147/CBC/PKCS7Padding"
+			};
+
+			try
+			{
+				byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+//				IvParameterSpec ivSpec = new IvParameterSpec(new byte[8]);
+				byte[] iv = new byte[8];
+			    
+				for (int i = 0; i != oids.Length; i++)
+				{
+					IBufferedCipher c1 = CipherUtilities.GetCipher(oids[i]);
+					IBufferedCipher c2 = CipherUtilities.GetCipher(names[i]);
+
+//					KeyGenerator kg = KeyGenerator.getInstance(oids[i]);
+//					SecretKey k = kg.generateKey();
+					CipherKeyGenerator kg = GeneratorUtilities.GetKeyGenerator(oids[i]);
+					KeyParameter k = ParameterUtilities.CreateKeyParameter(oids[i], kg.GenerateKey());
+
+					c1.Init(true, new ParametersWithIV(k, iv));
+					c2.Init(false, new ParametersWithIV(k, iv));
+
+					byte[] result = c2.DoFinal(c1.DoFinal(data));
+
+					if (!AreEqual(data, result))
+					{
+						Fail("failed OID test");
+					}
+				}
+			}
+			catch (Exception ex)
+			{
+				Fail("failed exception " + ex.ToString(), ex);
+			}
+		}
+
+		public override void PerformTest() 
+		{
+			for (int i = 0; i != cipherTests.Length; i += 8)
+			{
+				doTestEcb(int.Parse(cipherTests[i]),
+					Hex.Decode(cipherTests[i + 1]),
+					Hex.Decode(cipherTests[i + 2]),
+					Hex.Decode(cipherTests[i + 3]));
+
+				doTestCfb(int.Parse(cipherTests[i + 4]),
+					Hex.Decode(cipherTests[i + 4 + 1]),
+					Hex.Decode(cipherTests[i + 4 + 2]),
+					Hex.Decode(cipherTests[i + 4 + 3]));
+
+				doOidTest();
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new Gost28147Test());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/test/GOST3410Test.cs b/crypto/test/src/test/GOST3410Test.cs
new file mode 100644
index 000000000..db232c5a1
--- /dev/null
+++ b/crypto/test/src/test/GOST3410Test.cs
@@ -0,0 +1,380 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class Gost3410Test
+        : SimpleTest
+    {
+        private void ecGOST3410Test()
+        {
+            BigInteger r = new BigInteger("29700980915817952874371204983938256990422752107994319651632687982059210933395");
+            BigInteger s = new BigInteger("46959264877825372965922731380059061821746083849389763294914877353246631700866");
+
+            byte[] kData = new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395").ToByteArrayUnsigned();
+
+            SecureRandom k = FixedSecureRandom.From(kData);
+
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p
+
+            ECCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("7"), // a
+                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414")); // b
+
+            ECDomainParameters spec = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+                    new BigInteger("2"),
+                    new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")),
+                new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619")); // q
+
+            ECPrivateKeyParameters sKey = new ECPrivateKeyParameters(
+                "ECGOST3410",
+                new BigInteger("55441196065363246126355624130324183196576709222340016572108097750006097525544"), // d
+                spec);
+
+            ECPublicKeyParameters vKey = new ECPublicKeyParameters(
+                "ECGOST3410",
+                curve.CreatePoint(
+                    new BigInteger("57520216126176808443631405023338071176630104906313632182896741342206604859403"),
+                    new BigInteger("17614944419213781543809391949654080031942662045363639260709847859438286763994")),
+                spec);
+
+            ISigner sgr = SignerUtilities.GetSigner("ECGOST3410");
+
+            sgr.Init(true, new ParametersWithRandom(sKey, k));
+
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail("ECGOST3410 verification failed");
+            }
+
+            BigInteger[] sig = decode(sigBytes);
+
+            if (!r.Equals(sig[0]))
+            {
+                Fail(
+                    ": r component wrong." + SimpleTest.NewLine
+                    + " expecting: " + r + SimpleTest.NewLine
+                    + " got      : " + sig[0]);
+            }
+
+            if (!s.Equals(sig[1]))
+            {
+                Fail(
+                    ": s component wrong." + SimpleTest.NewLine
+                    + " expecting: " + s + SimpleTest.NewLine
+                    + " got      : " + sig[1]);
+            }
+        }
+
+        private void generationTest()
+        {
+            byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+            ISigner s = SignerUtilities.GetSigner("GOST3410");
+
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("GOST3410");
+            g.Init(
+                new Gost3410KeyGenerationParameters(
+                    new SecureRandom(),
+                    CryptoProObjectIdentifiers.GostR3410x94CryptoProA));
+
+            AsymmetricCipherKeyPair p = g.GenerateKeyPair();
+
+            AsymmetricKeyParameter sKey = p.Private;
+            AsymmetricKeyParameter vKey = p.Public;
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            byte[] sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("GOST3410");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("GOST3410 verification failed");
+            }
+
+            //
+            // default initialisation test
+            //
+            s = SignerUtilities.GetSigner("GOST3410");
+            g = GeneratorUtilities.GetKeyPairGenerator("GOST3410");
+
+            // TODO This is supposed to be a 'default initialisation' test, but don't have a factory
+            // These values are defaults from JCE provider
+            g.Init(
+                new Gost3410KeyGenerationParameters(
+                    new SecureRandom(),
+                    CryptoProObjectIdentifiers.GostR3410x94CryptoProA));
+
+            p = g.GenerateKeyPair();
+
+            sKey = p.Private;
+            vKey = p.Public;
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("GOST3410");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("GOST3410 verification failed");
+            }
+
+            //
+            // encoded test
+            //
+            //KeyFactory f = KeyFactory.getInstance("GOST3410");
+            //X509EncodedKeySpec  x509s = new X509EncodedKeySpec(vKey.GetEncoded());
+            //Gost3410PublicKeyParameters k1 = (Gost3410PublicKeyParameters)f.generatePublic(x509s);
+            byte[] vKeyEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(vKey).GetDerEncoded();
+            Gost3410PublicKeyParameters k1 = (Gost3410PublicKeyParameters)
+                PublicKeyFactory.CreateKey(vKeyEnc);
+
+            if (!k1.Y.Equals(((Gost3410PublicKeyParameters)vKey).Y))
+            {
+                Fail("public number not decoded properly");
+            }
+
+            //PKCS8EncodedKeySpec  pkcs8 = new PKCS8EncodedKeySpec(sKey.GetEncoded());
+            //Gost3410PrivateKeyParameters k2 = (Gost3410PrivateKeyParameters)f.generatePrivate(pkcs8);
+            byte[] sKeyEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(sKey).GetDerEncoded();
+            Gost3410PrivateKeyParameters k2 = (Gost3410PrivateKeyParameters)
+                PrivateKeyFactory.CreateKey(sKeyEnc);
+
+            if (!k2.X.Equals(((Gost3410PrivateKeyParameters)sKey).X))
+            {
+                Fail("private number not decoded properly");
+            }
+
+            //
+            // ECGOST3410 generation test
+            //
+            s = SignerUtilities.GetSigner("ECGOST3410");
+            g = GeneratorUtilities.GetKeyPairGenerator("ECGOST3410");
+
+            BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p
+
+            ECCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("7"), // a
+                new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414")); // b
+
+            ECDomainParameters ecSpec = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+                    new BigInteger("2"),
+                    new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")),
+                new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619")); // q
+
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
+
+            p = g.GenerateKeyPair();
+
+            sKey = p.Private;
+            vKey = p.Public;
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("ECGOST3410");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("ECGOST3410 verification failed");
+            }
+        }
+
+        private void keyStoreTest(
+            AsymmetricKeyParameter	sKey,
+            AsymmetricKeyParameter	vKey)
+//	        throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException, SignatureException, InvalidKeyException, UnrecoverableKeyException
+        {
+            //
+            // keystore test
+            //
+//			KeyStore ks = KeyStore.GetInstance("JKS");
+//			ks.Load(null, null);
+            Pkcs12StoreBuilder ksBuilder = new Pkcs12StoreBuilder();
+            Pkcs12Store ks = ksBuilder.Build();
+    
+            //
+            // create the certificate - version 3
+            //
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+    
+            certGen.SetSerialNumber(BigInteger.One);
+            certGen.SetIssuerDN(new X509Name("CN=Test"));
+            certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+            certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+            certGen.SetSubjectDN(new X509Name("CN=Test"));
+            certGen.SetPublicKey(vKey);
+            certGen.SetSignatureAlgorithm("GOST3411withGOST3410");
+    
+            X509Certificate cert = certGen.Generate(sKey);
+            X509CertificateEntry certEntry = new X509CertificateEntry(cert);
+
+//	        ks.SetKeyEntry("gost", sKey, "gost".ToCharArray(), new X509Certificate[] { cert });
+            ks.SetKeyEntry("gost", new AsymmetricKeyEntry(sKey), new X509CertificateEntry[] { certEntry });
+    
+            MemoryStream bOut = new MemoryStream();
+    
+            ks.Save(bOut, "gost".ToCharArray(), new SecureRandom());
+    
+//	        ks = KeyStore.getInstance("JKS");
+            ks = ksBuilder.Build();
+
+            ks.Load(new MemoryStream(bOut.ToArray(), false), "gost".ToCharArray());
+
+//	        AsymmetricKeyParameter gKey = (AsymmetricKeyParameter)ks.GetKey("gost", "gost".ToCharArray());
+//	        AsymmetricKeyEntry gKeyEntry = (AsymmetricKeyEntry)
+                ks.GetKey("gost");
+        }
+        
+        private void parametersTest()
+        {
+//	        AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("GOST3410");
+//	        a.init(512, random);
+//	        AlgorithmParameters params = a.generateParameters();
+//
+//	        byte[] encodeParams = params.getEncoded();
+//
+//	        AlgorithmParameters a2 = AlgorithmParameters.getInstance("GOST3410");
+//	        a2.init(encodeParams);
+//
+//	        // a and a2 should be equivalent!
+//	        byte[] encodeParams_2 = a2.getEncoded();
+//
+//	        if (!arrayEquals(encodeParams, encodeParams_2))
+//	        {
+//	            Fail("encode/decode parameters failed");
+//	        }
+
+//			GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec(
+//				CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_B.getId());
+//			g.initialize(gost3410P, new SecureRandom());
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("GOST3410");
+            g.Init(
+                new Gost3410KeyGenerationParameters(
+                    new SecureRandom(),
+                    CryptoProObjectIdentifiers.GostR3410x94CryptoProB));
+
+            AsymmetricCipherKeyPair p = g.GenerateKeyPair();
+
+            AsymmetricKeyParameter sKey = p.Private;
+            AsymmetricKeyParameter vKey = p.Public;
+
+            ISigner s = SignerUtilities.GetSigner("GOST3410");
+            byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+            s.Init(true, sKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            byte[] sigBytes = s.GenerateSignature();
+
+            s = SignerUtilities.GetSigner("GOST3410");
+
+            s.Init(false, vKey);
+
+            s.BlockUpdate(data, 0, data.Length);
+
+            if (!s.VerifySignature(sigBytes))
+            {
+                Fail("GOST3410 verification failed");
+            }
+
+            keyStoreTest(sKey, vKey);
+        }
+
+        private BigInteger[] decode(
+            byte[]  encoding)
+        {
+            byte[] r = new byte[32];
+            byte[] s = new byte[32];
+
+            Array.Copy(encoding, 0, s, 0, 32);
+            Array.Copy(encoding, 32, r, 0, 32);
+
+            BigInteger[] sig = new BigInteger[2];
+
+            sig[0] = new BigInteger(1, r);
+            sig[1] = new BigInteger(1, s);
+
+            return sig;
+        }
+
+        public override string Name
+        {
+            get { return "GOST3410/ECGOST3410"; }
+        }
+
+        public override void PerformTest()
+        {
+            ecGOST3410Test();
+            generationTest();
+            parametersTest();
+        }
+
+        public static void Main(
+            string[]	args)
+        {
+            RunTest(new Gost3410Test());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/HMacTest.cs b/crypto/test/src/test/HMacTest.cs
new file mode 100644
index 000000000..e4f5cb9c1
--- /dev/null
+++ b/crypto/test/src/test/HMacTest.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    /// <remarks>HMAC tester</remarks>
+    [TestFixture]
+    public class HMacTest
+        : SimpleTest
+    {
+        private static byte[] keyBytes = Hex.Decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
+        private static byte[] message = Encoding.ASCII.GetBytes("Hi There");
+        private static byte[] output1 = Hex.Decode("b617318655057264e28bc0b6fb378c8ef146be00");
+        private static byte[] outputMD5 = Hex.Decode("5ccec34ea9656392457fa1ac27f08fbc");
+        private static byte[] outputMD2 = Hex.Decode("dc1923ef5f161d35bef839ca8c807808");
+        private static byte[] outputMD4 = Hex.Decode("5570ce964ba8c11756cdc3970278ff5a");
+        private static byte[] output224 = Hex.Decode("896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22");
+        private static byte[] output256 = Hex.Decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7");
+        private static byte[] output384 = Hex.Decode("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6");
+        private static byte[] output512 = Hex.Decode("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854");
+        private static byte[] output512_224 = Hex.Decode("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039");
+        private static byte[] output512_256 = Hex.Decode("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab");
+        private static byte[] outputRipeMD128 = Hex.Decode("fda5717fb7e20cf05d30bb286a44b05d");
+        private static byte[] outputRipeMD160 = Hex.Decode("24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668");
+        private static byte[] outputTiger = Hex.Decode("1d7a658c75f8f004916e7b07e2a2e10aec7de2ae124d3647");
+        private static byte[] outputOld384 = Hex.Decode("0a046aaa0255e432912228f8ccda437c8a8363fb160afb0570ab5b1fd5ddc20eb1888b9ed4e5b6cb5bc034cd9ef70e40");
+        private static byte[] outputOld512 = Hex.Decode("9656975ee5de55e75f2976ecce9a04501060b9dc22a6eda2eaef638966280182477fe09f080b2bf564649cad42af8607a2bd8d02979df3a980f15e2326a0a22a");
+
+        public void doTestHMac(
+            string  hmacName,
+            byte[]  output)
+        {
+            KeyParameter key = new KeyParameter(keyBytes); //, hmacName);
+
+            IMac mac = MacUtilities.GetMac(hmacName);
+
+            mac.Init(key);
+
+            mac.Reset();
+
+            mac.BlockUpdate(message, 0, message.Length);
+
+//			byte[] outBytes = mac.DoFinal();
+            byte[] outBytes = new byte[mac.GetMacSize()];
+            mac.DoFinal(outBytes, 0);
+
+            if (!AreEqual(outBytes, output))
+            {
+                Fail("Failed - expected "
+                    + Hex.ToHexString(output) + " got "
+                    + Hex.ToHexString(outBytes));
+            }
+
+            // no key generator for the old algorithms
+            if (hmacName.StartsWith("Old"))
+            {
+                return;
+            }
+
+            CipherKeyGenerator kGen = GeneratorUtilities.GetKeyGenerator(hmacName);
+
+            mac.Init(new KeyParameter(kGen.GenerateKey())); // hmacName
+
+            mac.BlockUpdate(message, 0, message.Length);
+
+//			outBytes = mac.DoFinal();
+            outBytes = new byte[mac.GetMacSize()];
+            mac.DoFinal(outBytes, 0);
+        }
+
+        private void doTestExceptions()
+        {
+            IMac mac = MacUtilities.GetMac("HmacSHA1");
+
+            byte [] b = {(byte)1, (byte)2, (byte)3, (byte)4, (byte)5};
+//			KeyParameter sks = new KeyParameter(b); //, "HmacSHA1");
+//			RC5ParameterSpec algPS = new RC5ParameterSpec(100, 100, 100);
+            RC5Parameters rc5Parameters = new RC5Parameters(b, 100);
+
+            try
+            {
+//				mac.Init(sks, algPS);
+                mac.Init(rc5Parameters);
+            }
+//			catch (InvalidAlgorithmParameterException e)
+            catch (Exception)
+            {
+                // ignore okay
+            }
+
+            try
+            {
+                mac.Init(null); //, null);
+            }
+//			catch (InvalidKeyException)
+//			{
+//				// ignore okay
+//			}
+//			catch (InvalidAlgorithmParameterException e)
+            catch (Exception)
+            {
+                // ignore okay
+            }
+
+//			try
+//			{
+//				mac.Init(null);
+//			}
+//			catch (InvalidKeyException)
+//			{
+//				// ignore okay
+//			}
+        }
+
+        public override void PerformTest()
+        {
+            doTestHMac("HMac-SHA1", output1);
+            doTestHMac("HMac-MD5", outputMD5);
+            doTestHMac("HMac-MD4", outputMD4);
+            doTestHMac("HMac-MD2", outputMD2);
+            doTestHMac("HMac-SHA224", output224);
+            doTestHMac("HMac-SHA256", output256);
+            doTestHMac("HMac-SHA384", output384);
+            doTestHMac("HMac-SHA512", output512);
+            doTestHMac("HMac-SHA512/224", output512_224);
+            doTestHMac("HMac-SHA512/256", output512_256);
+            doTestHMac("HMac-RIPEMD128", outputRipeMD128);
+            doTestHMac("HMac-RIPEMD160", outputRipeMD160);
+            doTestHMac("HMac-TIGER", outputTiger);
+
+            doTestHMac("HMac/SHA1", output1);
+            doTestHMac("HMac/MD5", outputMD5);
+            doTestHMac("HMac/MD4", outputMD4);
+            doTestHMac("HMac/MD2", outputMD2);
+            doTestHMac("HMac/SHA224", output224);
+            doTestHMac("HMac/SHA256", output256);
+            doTestHMac("HMac/SHA384", output384);
+            doTestHMac("HMac/SHA512", output512);
+            doTestHMac("HMac/RIPEMD128", outputRipeMD128);
+            doTestHMac("HMac/RIPEMD160", outputRipeMD160);
+            doTestHMac("HMac/TIGER", outputTiger);
+
+            doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha1.Id, output1);
+            doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha224.Id, output224);
+            doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha256.Id, output256);
+            doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha384.Id, output384);
+            doTestHMac(PkcsObjectIdentifiers.IdHmacWithSha512.Id, output512);
+            doTestHMac(IanaObjectIdentifiers.HmacSha1.Id, output1);
+            doTestHMac(IanaObjectIdentifiers.HmacMD5.Id, outputMD5);
+            doTestHMac(IanaObjectIdentifiers.HmacRipeMD160.Id, outputRipeMD160);
+            doTestHMac(IanaObjectIdentifiers.HmacTiger.Id, outputTiger);
+
+//			// test for compatibility with broken HMac.
+//			doTestHMac("OldHMacSHA384", outputOld384);
+//			doTestHMac("OldHMacSHA512", outputOld512);
+
+            doTestExceptions();
+        }
+
+        public override string Name
+        {
+            get { return "HMac"; }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new HMacTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/IESTest.cs b/crypto/test/src/test/IESTest.cs
new file mode 100644
index 000000000..193fe1ae9
--- /dev/null
+++ b/crypto/test/src/test/IESTest.cs
@@ -0,0 +1,245 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/**
+	 * test for ECIES - Elliptic Curve Integrated Encryption Scheme
+	 */
+	[TestFixture]
+	public class IesTest
+		: SimpleTest
+	{
+		private static readonly BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16);
+		private static readonly BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16);
+
+		public override string Name
+		{
+			get { return "IES"; }
+		}
+
+		public override void PerformTest()
+		{
+			IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECIES");
+
+			ECCurve curve = new FpCurve(
+				new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+			ECDomainParameters ecSpec = new ECDomainParameters(
+				curve,
+				curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+				new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+			g.Init(
+				new ECKeyGenerationParameters(
+					ecSpec,
+					new SecureRandom()));
+
+			IBufferedCipher c1 = CipherUtilities.GetCipher("ECIES");
+			IBufferedCipher c2 = CipherUtilities.GetCipher("ECIES");
+
+			doTest(g, c1, c2);
+
+			g = GeneratorUtilities.GetKeyPairGenerator("ECIES");
+
+			g.Init(new KeyGenerationParameters(new SecureRandom(), 192));
+
+			doTest(g, c1, c2);
+
+			g = GeneratorUtilities.GetKeyPairGenerator("ECIES");
+
+			g.Init(new KeyGenerationParameters(new SecureRandom(), 239));
+
+			doTest(g, c1, c2);
+
+			g = GeneratorUtilities.GetKeyPairGenerator("ECIES");
+
+			g.Init(new KeyGenerationParameters(new SecureRandom(), 256));
+
+			doTest(g, c1, c2);
+
+			doDefTest(g, c1, c2);
+
+			c1 = CipherUtilities.GetCipher("IES");
+			c2 = CipherUtilities.GetCipher("IES");
+
+			g = GeneratorUtilities.GetKeyPairGenerator("DH");
+
+//			DHParameterSpec dhParams = new DHParameterSpec(p512, g512);
+//			g.initialize(dhParams);
+			g.Init(
+				new DHKeyGenerationParameters(
+					new SecureRandom(),
+					new DHParameters(p512, g512)));
+
+			doTest(g, c1, c2);
+
+			doDefTest(g, c1, c2);
+		}
+
+		public void doTest(
+			IAsymmetricCipherKeyPairGenerator	g,
+			IBufferedCipher						c1,
+			IBufferedCipher						c2)
+		{
+			//
+			// a side
+			//
+			AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();
+			AsymmetricKeyParameter aPub = aKeyPair.Public;
+			AsymmetricKeyParameter  aPriv = aKeyPair.Private;
+
+			//
+			// b side
+			//
+			AsymmetricCipherKeyPair bKeyPair = g.GenerateKeyPair();
+			AsymmetricKeyParameter bPub = bKeyPair.Public;
+			AsymmetricKeyParameter bPriv = bKeyPair.Private;
+
+			// TODO Put back in
+//			//
+//			// stream test
+//			//
+//			IEKeySpec c1Key = new IEKeySpec(aPriv, bPub);
+//			IEKeySpec c2Key = new IEKeySpec(bPriv, aPub);
+//
+//			byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+//			byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };
+//
+//			IESParameterSpec param = new IESParameterSpec(d, e, 128);
+//
+//			c1.Init(true, c1Key, param);
+//
+//			c2.Init(false, c2Key, param);
+//
+//			byte[] message = Hex.Decode("1234567890abcdef");
+//
+//			byte[] out1 = c1.DoFinal(message, 0, message.Length);
+//
+//			byte[] out2 = c2.DoFinal(out1, 0, out1.Length);
+//
+//			if (!AreEqual(out2, message))
+//			{
+//				Fail("stream cipher test failed");
+//			}
+		}
+
+		public void doDefTest(
+			IAsymmetricCipherKeyPairGenerator	g,
+			IBufferedCipher						c1,
+			IBufferedCipher						c2)
+		{
+			//
+			// a side
+			//
+			AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();
+			AsymmetricKeyParameter aPub = aKeyPair.Public;
+			AsymmetricKeyParameter aPriv = aKeyPair.Private;
+
+			//
+			// b side
+			//
+			AsymmetricCipherKeyPair bKeyPair = g.GenerateKeyPair();
+			AsymmetricKeyParameter bPub = bKeyPair.Public;
+			AsymmetricKeyParameter bPriv = bKeyPair.Private;
+
+			// TODO Put back in
+//			//
+//			// stream test
+//			//
+//			IEKeySpec c1Key = new IEKeySpec(aPriv, bPub);
+//			IEKeySpec c2Key = new IEKeySpec(bPriv, aPub);
+//
+//			c1.Init(true, c1Key);
+//
+//			AlgorithmParameters param = c1.getParameters();
+//
+//			c2.Init(false, c2Key, param);
+//
+//			byte[] message = Hex.Decode("1234567890abcdef");
+//
+//			byte[] out1 = c1.DoFinal(message, 0, message.Length);
+//
+//			byte[] out2 = c2.DoFinal(out1, 0, out1.Length);
+//
+//			if (!AreEqual(out2, message))
+//			{
+//				Fail("stream cipher test failed");
+//			}
+//
+//			//
+//			// int DoFinal
+//			//
+//			int len1 = c1.DoFinal(message, 0, message.Length, out1, 0);
+//
+//			if (len1 != out1.Length)
+//			{
+//				Fail("encryption length wrong");
+//			}
+//
+//			int len2 = c2.DoFinal(out1, 0, out1.Length, out2, 0);
+//
+//			if (len2 != out2.Length)
+//			{
+//				Fail("decryption length wrong");
+//			}
+//        
+//			if (!AreEqual(out2, message))
+//			{
+//				Fail("stream cipher test failed");
+//			}
+//        
+//			//
+//			// int DoFinal with update
+//			//
+//			len1 = c1.ProcessBytes(message, 0, 2, out1, 0);
+//
+//			len1 += c1.DoFinal(message, 2, message.Length - 2, out1, len1);
+//
+//			if (len1 != out1.Length)
+//			{
+//				Fail("update encryption length wrong");
+//			}
+//
+//			len2 = c2.ProcessBytes(out1, 0, 2, out2, 0);
+//
+//			len2 += c2.DoFinal(out1, 2, out1.Length - 2, out2, len2);
+//
+//			if (len2 != out2.Length)
+//			{
+//				Fail("update decryption length wrong");
+//			}
+//
+//			if (!AreEqual(out2, message))
+//			{
+//				Fail("update stream cipher test failed");
+//			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new IesTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/MacTest.cs b/crypto/test/src/test/MacTest.cs
new file mode 100644
index 000000000..d4b3188bd
--- /dev/null
+++ b/crypto/test/src/test/MacTest.cs
@@ -0,0 +1,216 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <remarks>
+	/// MAC tester - vectors from
+	/// <a href="http://www.itl.nist.gov/fipspubs/fip81.htm">FIP 81</a> and
+	/// <a href="http://www.itl.nist.gov/fipspubs/fip113.htm">FIP 113</a>.
+	/// </remarks>
+	[TestFixture]
+	public class MacTest
+		: SimpleTest
+	{
+		private static readonly byte[] keyBytes = Hex.Decode("0123456789abcdef");
+		private static readonly byte[] ivBytes = Hex.Decode("1234567890abcdef");
+
+		private static readonly byte[] input = Hex.Decode("37363534333231204e6f77206973207468652074696d6520666f7220");
+
+		private static readonly byte[] output1 = Hex.Decode("f1d30f68");
+		private static readonly byte[] output2 = Hex.Decode("58d2e77e");
+		private static readonly byte[] output3 = Hex.Decode("cd647403");
+
+		private static readonly byte[] keyBytesISO9797 = Hex.Decode("7CA110454A1A6E570131D9619DC1376E");
+
+		private static readonly byte[] inputISO9797 = Encoding.ASCII.GetBytes("Hello World !!!!");
+
+		private static readonly byte[] outputISO9797 = Hex.Decode("F09B856213BAB83B");
+
+		private static readonly byte[] inputDesEDE64 = Encoding.ASCII.GetBytes("Hello World !!!!");
+
+		private static readonly byte[] outputDesEDE64 = Hex.Decode("862304d33af01096");
+
+		private void aliasTest(
+			KeyParameter	key,
+			string			primary,
+			params string[]	aliases)
+		{
+			IMac mac = MacUtilities.GetMac(primary);
+
+			//
+			// standard DAC - zero IV
+			//
+			mac.Init(key);
+
+			mac.BlockUpdate(input, 0, input.Length);
+
+			byte[] refBytes = new byte[mac.GetMacSize()];
+			mac.DoFinal(refBytes, 0);
+
+			for (int i = 0; i != aliases.Length; i++)
+			{
+				mac = MacUtilities.GetMac(aliases[i]);
+
+				mac.Init(key);
+
+				mac.BlockUpdate(input, 0, input.Length);
+
+				byte[] outBytes = new byte[mac.GetMacSize()];
+				mac.DoFinal(outBytes, 0);
+
+				if (!AreEqual(outBytes, refBytes))
+				{
+					Fail("Failed - expected "
+						+ Hex.ToHexString(refBytes) + " got "
+						+ Hex.ToHexString(outBytes));
+				}
+			}
+		}
+
+		public override void PerformTest()
+		{
+			KeyParameter key = new DesParameters(keyBytes);
+			IMac mac = MacUtilities.GetMac("DESMac");
+
+			//
+			// standard DAC - zero IV
+			//
+			mac.Init(key);
+
+			mac.BlockUpdate(input, 0, input.Length);
+
+			//byte[] outBytes = mac.DoFinal();
+			byte[] outBytes = new byte[mac.GetMacSize()];
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, output1))
+			{
+				Fail("Failed - expected "
+					+ Hex.ToHexString(output1) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+			//
+			// mac with IV.
+			//
+			mac.Init(new ParametersWithIV(key, ivBytes));
+
+			mac.BlockUpdate(input, 0, input.Length);
+
+			//outBytes = mac.DoFinal();
+			outBytes = new byte[mac.GetMacSize()];
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, output2))
+			{
+				Fail("Failed - expected "
+					+ Hex.ToHexString(output2) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+			//
+			// CFB mac with IV - 8 bit CFB mode
+			//
+			mac = MacUtilities.GetMac("DESMac/CFB8");
+
+			mac.Init(new ParametersWithIV(key, ivBytes));
+
+			mac.BlockUpdate(input, 0, input.Length);
+
+			//outBytes = mac.DoFinal();
+			outBytes = new byte[mac.GetMacSize()];
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, output3))
+			{
+				Fail("Failed - expected "
+					+ Hex.ToHexString(output3) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+			//
+			// ISO9797 algorithm 3 using DESEDE
+			//
+			key = new DesEdeParameters(keyBytesISO9797);
+
+			mac = MacUtilities.GetMac("ISO9797ALG3");
+
+			mac.Init(key);
+
+			mac.BlockUpdate(inputISO9797, 0, inputISO9797.Length);
+
+			//outBytes = mac.DoFinal();
+			outBytes = new byte[mac.GetMacSize()];
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, outputISO9797))
+			{
+				Fail("Failed - expected "
+					+ Hex.ToHexString(outputISO9797) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+			//
+			// 64bit DESede Mac
+			//
+			key = new DesEdeParameters(keyBytesISO9797);
+
+			mac = MacUtilities.GetMac("DESEDE64");
+
+			mac.Init(key);
+
+			mac.BlockUpdate(inputDesEDE64, 0, inputDesEDE64.Length);
+
+			//outBytes = mac.DoFinal();
+			outBytes = new byte[mac.GetMacSize()];
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, outputDesEDE64))
+			{
+				Fail("Failed - expected "
+					+ Hex.ToHexString(outputDesEDE64) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+			aliasTest(
+				ParameterUtilities.CreateKeyParameter("DESede", keyBytesISO9797),
+				"DESedeMac64withISO7816-4Padding",
+				"DESEDE64WITHISO7816-4PADDING",
+				"DESEDEISO9797ALG1MACWITHISO7816-4PADDING",
+				"DESEDEISO9797ALG1WITHISO7816-4PADDING");
+
+			aliasTest(
+				ParameterUtilities.CreateKeyParameter("DESede", keyBytesISO9797),
+				"ISO9797ALG3WITHISO7816-4PADDING",
+				"ISO9797ALG3MACWITHISO7816-4PADDING");
+		}
+
+		public override string Name
+		{
+			get { return "Mac"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new MacTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/MqvTest.cs b/crypto/test/src/test/MqvTest.cs
new file mode 100644
index 000000000..ef36e1a23
--- /dev/null
+++ b/crypto/test/src/test/MqvTest.cs
@@ -0,0 +1,99 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class MqvTest
+		: SimpleTest
+	{
+		public override string Name
+		{
+			get { return "MQV"; }
+		}
+
+		public override void PerformTest()
+		{
+			TestECMqv();
+		}
+
+		[Test]
+		public void TestECMqv()
+		{
+			IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECMQV");
+
+//			EllipticCurve curve = new EllipticCurve(
+//				new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q
+//				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+//				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+			ECCurve curve = new FpCurve(
+				new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+				new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+				new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+			ECDomainParameters ecSpec = new ECDomainParameters(
+				curve,
+//				ECPointUtil.DecodePoint(curve, Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+				curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+				new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n
+				BigInteger.One); //1); // h
+
+//			g.initialize(ecSpec, new SecureRandom());
+			g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
+			
+			//
+			// U side
+			//
+			AsymmetricCipherKeyPair U1 = g.GenerateKeyPair();
+			AsymmetricCipherKeyPair U2 = g.GenerateKeyPair();
+			
+			IBasicAgreement uAgree = AgreementUtilities.GetBasicAgreement("ECMQV");
+			uAgree.Init(new MqvPrivateParameters(
+				(ECPrivateKeyParameters)U1.Private,
+				(ECPrivateKeyParameters)U2.Private,
+				(ECPublicKeyParameters)U2.Public));
+			
+			//
+			// V side
+			//
+			AsymmetricCipherKeyPair V1 = g.GenerateKeyPair();
+			AsymmetricCipherKeyPair V2 = g.GenerateKeyPair();
+
+			IBasicAgreement vAgree = AgreementUtilities.GetBasicAgreement("ECMQV");
+			vAgree.Init(new MqvPrivateParameters(
+				(ECPrivateKeyParameters)V1.Private,
+				(ECPrivateKeyParameters)V2.Private,
+				(ECPublicKeyParameters)V2.Public));
+			
+			//
+			// agreement
+			//
+			BigInteger ux = uAgree.CalculateAgreement(new MqvPublicParameters(
+				(ECPublicKeyParameters)V1.Public,
+				(ECPublicKeyParameters)V2.Public));
+			BigInteger vx = vAgree.CalculateAgreement(new MqvPublicParameters(
+				(ECPublicKeyParameters)U1.Public,
+				(ECPublicKeyParameters)U2.Public));
+
+			if (!ux.Equals(vx))
+			{
+				Fail("Agreement failed");
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new MqvTest());
+		}
+	}
+}
diff --git a/crypto/test/src/test/NamedCurveTest.cs b/crypto/test/src/test/NamedCurveTest.cs
new file mode 100644
index 000000000..bc8684aa5
--- /dev/null
+++ b/crypto/test/src/test/NamedCurveTest.cs
@@ -0,0 +1,381 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class NamedCurveTest
+        : SimpleTest
+    {
+//		private static readonly Hashtable CurveNames = new Hashtable();
+//		private static readonly Hashtable CurveAliases = new Hashtable();
+//
+//		static NamedCurveTest()
+//		{
+//			CurveNames.Add("prime192v1", "prime192v1"); // X9.62
+//			CurveNames.Add("sect571r1", "sect571r1"); // sec
+//			CurveNames.Add("secp224r1", "secp224r1");
+//			CurveNames.Add("B-409", SecNamedCurves.GetName(NistNamedCurves.GetOid("B-409")));   // nist
+//			CurveNames.Add("P-521", SecNamedCurves.GetName(NistNamedCurves.GetOid("P-521")));
+//			CurveNames.Add("brainpoolp160r1", "brainpoolp160r1");         // TeleTrusT
+//
+//			CurveAliases.Add("secp192r1", "prime192v1");
+//			CurveAliases.Add("secp256r1", "prime256v1");
+//		}
+
+        private static ECDomainParameters GetCurveParameters(
+            string name)
+        {
+            ECDomainParameters ecdp = ECGost3410NamedCurves.GetByName(name);
+
+            if (ecdp != null)
+                return ecdp;
+
+            X9ECParameters ecP = ECNamedCurveTable.GetByName(name);
+
+            if (ecP == null)
+                throw new Exception("unknown curve name: " + name);
+
+            return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+        }
+
+        public void doTestCurve(
+            string name)
+        {
+//			ECGenParameterSpec ecSpec = new ECGenParameterSpec(name);
+            ECDomainParameters ecSpec = GetCurveParameters(name);
+
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDH");
+
+//			g.initialize(ecSpec, new SecureRandom());
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); 
+
+            //
+            // a side
+            //
+            AsymmetricCipherKeyPair aKeyPair = g.GenerateKeyPair();
+
+//			KeyAgreement aKeyAgree = KeyAgreement.getInstance("ECDHC");
+            IBasicAgreement aKeyAgree = AgreementUtilities.GetBasicAgreement("ECDHC");
+
+            aKeyAgree.Init(aKeyPair.Private);
+
+            //
+            // b side
+            //
+            AsymmetricCipherKeyPair bKeyPair = g.GenerateKeyPair();
+
+//			KeyAgreement bKeyAgree = KeyAgreement.getInstance("ECDHC");
+            IBasicAgreement bKeyAgree = AgreementUtilities.GetBasicAgreement("ECDHC");
+
+            bKeyAgree.Init(bKeyPair.Private);
+
+            //
+            // agreement
+            //
+//			aKeyAgree.doPhase(bKeyPair.Public, true);
+//			bKeyAgree.doPhase(aKeyPair.Public, true);
+//
+//			BigInteger k1 = new BigInteger(aKeyAgree.generateSecret());
+//			BigInteger k2 = new BigInteger(bKeyAgree.generateSecret());
+            BigInteger k1 = aKeyAgree.CalculateAgreement(bKeyPair.Public);
+            BigInteger k2 = bKeyAgree.CalculateAgreement(aKeyPair.Public);
+
+            if (!k1.Equals(k2))
+            {
+                Fail("2-way test failed");
+            }
+
+            //
+            // public key encoding test
+            //
+//			byte[]              pubEnc = aKeyPair.Public.getEncoded();
+            byte[] pubEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(aKeyPair.Public).GetDerEncoded();
+
+//			KeyFactory          keyFac = KeyFactory.getInstance("ECDH");
+//			X509EncodedKeySpec  pubX509 = new X509EncodedKeySpec(pubEnc);
+//			ECPublicKey         pubKey = (ECPublicKey)keyFac.generatePublic(pubX509);
+            ECPublicKeyParameters pubKey = (ECPublicKeyParameters) PublicKeyFactory.CreateKey(pubEnc);
+
+//			if (!pubKey.getW().Equals(((ECPublicKey)aKeyPair.Public).getW()))
+            if (!pubKey.Q.Equals(((ECPublicKeyParameters)aKeyPair.Public).Q))
+            {
+                Fail("public key encoding (Q test) failed");
+            }
+
+            // TODO Put back in?
+//			if (!(pubKey.getParams() is ECNamedCurveSpec))
+//			{
+//				Fail("public key encoding not named curve");
+//			}
+
+            //
+            // private key encoding test
+            //
+//			byte[]              privEnc = aKeyPair.Private.getEncoded();
+            byte[] privEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(aKeyPair.Private).GetDerEncoded();
+
+//			PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
+//			ECPrivateKey        privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8);
+            ECPrivateKeyParameters privKey = (ECPrivateKeyParameters) PrivateKeyFactory.CreateKey(privEnc);
+
+//			if (!privKey.getS().Equals(((ECPrivateKey)aKeyPair.Private).getS()))
+            if (!privKey.D.Equals(((ECPrivateKeyParameters)aKeyPair.Private).D))
+            {
+                Fail("private key encoding (S test) failed");
+            }
+
+            // TODO Put back in?
+//			if (!(privKey.getParams() is ECNamedCurveSpec))
+//			{
+//				Fail("private key encoding not named curve");
+//			}
+//
+//			ECNamedCurveSpec privSpec = (ECNamedCurveSpec)privKey.getParams();
+//			if (!(privSpec.GetName().Equals(name) || privSpec.GetName().Equals(CurveNames.get(name))))
+//			{
+//				Fail("private key encoding wrong named curve. Expected: "
+//					+ CurveNames[name] + " got " + privSpec.GetName());
+//			}
+        }
+
+        public void doTestECDsa(
+            string name)
+        {
+//			ECGenParameterSpec ecSpec = new ECGenParameterSpec(name);
+            ECDomainParameters ecSpec = GetCurveParameters(name);
+
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+
+//			g.initialize(ecSpec, new SecureRandom());
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); 
+
+            ISigner sgr = SignerUtilities.GetSigner("ECDSA");
+            AsymmetricCipherKeyPair pair = g.GenerateKeyPair();
+            AsymmetricKeyParameter sKey = pair.Private;
+            AsymmetricKeyParameter vKey = pair.Public;
+
+            sgr.Init(true, sKey);
+
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail(name + " verification failed");
+            }
+
+            //
+            // public key encoding test
+            //
+//			byte[]              pubEnc = vKey.getEncoded();
+            byte[] pubEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(vKey).GetDerEncoded();
+
+//			KeyFactory          keyFac = KeyFactory.getInstance("ECDH");
+//			X509EncodedKeySpec  pubX509 = new X509EncodedKeySpec(pubEnc);
+//			ECPublicKey         pubKey = (ECPublicKey)keyFac.generatePublic(pubX509);
+            ECPublicKeyParameters pubKey = (ECPublicKeyParameters) PublicKeyFactory.CreateKey(pubEnc);
+
+//			if (!pubKey.getW().Equals(((ECPublicKey)vKey).getW()))
+            if (!pubKey.Q.Equals(((ECPublicKeyParameters)vKey).Q))
+            {
+                Fail("public key encoding (Q test) failed");
+            }
+
+            // TODO Put back in?
+//			if (!(pubKey.Parameters is ECNamedCurveSpec))
+//			{
+//				Fail("public key encoding not named curve");
+//			}
+
+            //
+            // private key encoding test
+            //
+//			byte[]              privEnc = sKey.getEncoded();
+            byte[] privEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(sKey).GetDerEncoded();
+
+//			PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
+//			ECPrivateKey        privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8);
+            ECPrivateKeyParameters privKey = (ECPrivateKeyParameters) PrivateKeyFactory.CreateKey(privEnc);
+
+//			if (!privKey.getS().Equals(((ECPrivateKey)sKey).getS()))
+            if (!privKey.D.Equals(((ECPrivateKeyParameters)sKey).D))
+            {
+                Fail("private key encoding (D test) failed");
+            }
+
+            // TODO Put back in?
+//			if (!(privKey.Parameters is ECNamedCurveSpec))
+//			{
+//				Fail("private key encoding not named curve");
+//			}
+//
+//			ECNamedCurveSpec privSpec = (ECNamedCurveSpec)privKey.getParams();
+//			if (!privSpec.GetName().EqualsIgnoreCase(name)
+//				&& !privSpec.GetName().EqualsIgnoreCase((string) CurveAliases[name]))
+//			{
+//				Fail("private key encoding wrong named curve. Expected: " + name + " got " + privSpec.GetName());
+//			}
+        }
+
+        public void doTestECGost(
+            string name)
+        {
+//			ECGenParameterSpec ecSpec = new ECGenParameterSpec(name);
+            ECDomainParameters ecSpec = GetCurveParameters(name);
+
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECGOST3410");
+
+//			g.initialize(ecSpec, new SecureRandom());
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom())); 
+
+            ISigner sgr = SignerUtilities.GetSigner("ECGOST3410");
+            AsymmetricCipherKeyPair pair = g.GenerateKeyPair();
+            AsymmetricKeyParameter sKey = pair.Private;
+            AsymmetricKeyParameter vKey = pair.Public;
+
+            sgr.Init(true, sKey);
+
+            byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' };
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            byte[] sigBytes = sgr.GenerateSignature();
+
+            sgr.Init(false, vKey);
+
+            sgr.BlockUpdate(message, 0, message.Length);
+
+            if (!sgr.VerifySignature(sigBytes))
+            {
+                Fail(name + " verification failed");
+            }
+
+            // TODO Get this working?
+//			//
+//			// public key encoding test
+//			//
+////			byte[]              pubEnc = vKey.getEncoded();
+//			byte[] pubEnc = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(vKey).GetDerEncoded();
+//
+////			KeyFactory          keyFac = KeyFactory.getInstance("ECGOST3410");
+////			X509EncodedKeySpec  pubX509 = new X509EncodedKeySpec(pubEnc);
+////			ECPublicKey         pubKey = (ECPublicKey)keyFac.generatePublic(pubX509);
+//			ECPublicKeyParameters pubKey = (ECPublicKeyParameters) PublicKeyFactory.CreateKey(pubEnc);
+//
+////			if (!pubKey.getW().equals(((ECPublicKey)vKey).getW()))
+//			if (!pubKey.Q.Equals(((ECPublicKeyParameters)vKey).Q))
+//			{
+//				Fail("public key encoding (Q test) failed");
+//			}
+
+            // TODO Put back in?
+//			if (!(pubKey.Parameters is ECNamedCurveSpec))
+//			{
+//				Fail("public key encoding not named curve");
+//			}
+
+            // TODO Get this working?
+//			//
+//			// private key encoding test
+//			//
+////			byte[]              privEnc = sKey.getEncoded();
+//			byte[] privEnc = PrivateKeyInfoFactory.CreatePrivateKeyInfo(sKey).GetDerEncoded();
+//
+////			PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc);
+////			ECPrivateKey        privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8);
+//			ECPrivateKeyParameters privKey = (ECPrivateKeyParameters) PrivateKeyFactory.CreateKey(privEnc);
+//
+////			if (!privKey.getS().Equals(((ECPrivateKey)sKey).getS()))
+//			if (!privKey.D.Equals(((ECPrivateKeyParameters)sKey).D))
+//			{
+//				Fail("GOST private key encoding (D test) failed");
+//			}
+
+            // TODO Put back in?
+//			if (!(privKey.Parameters is ECNamedCurveSpec))
+//			{
+//				Fail("GOST private key encoding not named curve");
+//			}
+//
+//			ECNamedCurveSpec privSpec = (ECNamedCurveSpec)privKey.getParams();
+//			if (!privSpec.getName().equalsIgnoreCase(name)
+//				&& !privSpec.getName().equalsIgnoreCase((String)CURVE_ALIASES[name]))
+//			{
+//				Fail("GOST private key encoding wrong named curve. Expected: " + name + " got " + privSpec.getName());
+//			}
+        }
+
+        public override string Name
+        {
+            get { return "NamedCurve"; }
+        }
+        
+        public override void PerformTest()
+        {
+            doTestCurve("prime192v1"); // X9.62
+            doTestCurve("sect571r1"); // sec
+            doTestCurve("secp224r1");
+            doTestCurve("B-409");   // nist
+            doTestCurve("P-521");
+            doTestCurve("brainpoolp160r1");    // TeleTrusT
+
+            foreach (string name in X962NamedCurves.Names)
+            {
+                doTestECDsa(name);
+            }
+
+            foreach (string name in SecNamedCurves.Names)
+            {
+                doTestECDsa(name);
+            }
+
+            foreach (string name in TeleTrusTNamedCurves.Names)
+            {
+                doTestECDsa(name);
+            }
+
+            foreach (string name in ECGost3410NamedCurves.Names)
+            {
+                doTestECGost(name);
+            }
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new NamedCurveTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/NistCertPathTest.cs b/crypto/test/src/test/NistCertPathTest.cs
new file mode 100644
index 000000000..0f42e24d0
--- /dev/null
+++ b/crypto/test/src/test/NistCertPathTest.cs
@@ -0,0 +1,5192 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Pkix;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class NistCertPathTest
+		: SimpleTest
+	{
+		/*
+		* These tests are taken from the NIST X.509 Validation Test Suite
+		* available at: http://csrc.nist.gov/pki/testing/x509paths.html
+		*
+		* Only the relevant certificate and crl data has been kept, in order
+		* to keep the class size to a minimum.
+		*
+		*/
+		private const string TEST_POLICY_1 = "2.16.840.1.101.3.1.48.1";
+		private const string TEST_POLICY_2 = "2.16.840.1.101.3.1.48.2";
+		private const string TEST_POLICY_3 = "2.16.840.1.101.3.1.48.3";
+		private const string TEST_POLICY_4 = "2.16.840.1.101.3.1.48.4";
+		private const string TEST_POLICY_5 = "2.16.840.1.101.3.1.48.5";
+
+		private static ISet ANY;
+		private static ISet TP1;
+		private static ISet TP2;
+		private static ISet TP3;
+		private static ISet TP4;
+		private static ISet TP1_TP2;
+
+		static NistCertPathTest()
+		{
+			ANY = new HashSet();
+
+			TP1 = new HashSet();
+			TP1.Add(TEST_POLICY_1);
+
+			TP2 = new HashSet();
+			TP2.Add(TEST_POLICY_2);
+
+			TP3 = new HashSet();
+			TP3.Add(TEST_POLICY_3);
+
+			TP4 = new HashSet();
+			TP4.Add(TEST_POLICY_4);
+
+			TP1_TP2 = new HashSet();
+			TP1_TP2.Add(TEST_POLICY_1);
+			TP1_TP2.Add(TEST_POLICY_2);
+		}
+
+		/*
+		 *  FIELDS
+		 */
+		private X509CertificateParser certParser = new X509CertificateParser();
+		private X509CrlParser crlParser = new X509CrlParser();
+
+		private X509Certificate trustedCert;
+		private X509Crl trustedCRL;
+		private ISet trustedSet;
+		private int testCount;
+		private IList testFail;
+		private StringBuilder resultBuf;
+
+		public override string Name
+		{
+			get { return "NistCertPathTest"; }
+		}
+
+		public override void PerformTest()
+		{
+			Init();
+
+			Test(" 1", TEST_1_DATA, true, false);
+			Test(" 2", TEST_2_DATA, false, false);
+			Test(" 3", TEST_3_DATA, false, false);
+			Test(" 4", TEST_4_DATA, true, false);
+			Test(" 5", TEST_5_DATA, false, false);
+			Test(" 6", TEST_6_DATA, false, false);
+			Test(" 7", TEST_7_DATA, true, false);
+			Test(" 8", TEST_8_DATA, false, false);
+			Test(" 9", TEST_9_DATA, false, false);
+
+			Test("10", TEST_10_DATA, false, false);
+			Test("11", TEST_11_DATA, false, false);
+			Test("12", TEST_12_DATA, true, false);
+			Test("13", TEST_13_DATA, false, false);
+			Test("14", TEST_14_DATA, false, false);
+			Test("15", TEST_15_DATA, true, false);
+			Test("16", TEST_16_DATA, true, false);
+			Test("17", TEST_17_DATA, true, false);
+			Test("18", TEST_18_DATA, true, false);
+			Test("19", TEST_19_DATA, false, false);
+
+			Test("20", TEST_20_DATA, false, false);
+			Test("21", TEST_21_DATA, false, false);
+			Test("22", TEST_22_DATA, false, false);
+			Test("23", TEST_23_DATA, false, false);
+			Test("24", TEST_24_DATA, true, false);
+			Test("25", TEST_25_DATA, false, false);
+			Test("26", TEST_26_DATA, true, false);
+			Test("27", TEST_27_DATA, true, false);
+			Test("28", TEST_28_DATA, false, false);
+			Test("29", TEST_29_DATA, false, false);
+
+			Test("30", TEST_30_DATA, true, false);
+			Test("31", TEST_31_DATA, false, false);
+			Test("32", TEST_32_DATA, false, false);
+			Test("33", TEST_33_DATA, true, false);
+
+			Test("34a", TEST_34_DATA, ANY, true, true, false);
+			Test("34b", TEST_34_DATA, ANY, false, true, false);
+			Test("34c", TEST_34_DATA, TP1, true, true, false);
+			Test("34d", TEST_34_DATA, TP1, false, true, false);
+			Test("34e", TEST_34_DATA, TP2, true, false, false);
+			Test("34f", TEST_34_DATA, TP2, false, true, false);
+
+			Test("35a", TEST_35_DATA, false, true, false);
+			Test("35b", TEST_35_DATA, true, false, false);
+
+			Test("36a", TEST_36_DATA, false, true, false);
+			Test("36b", TEST_36_DATA, true, false, false);
+
+			Test("37a", TEST_37_DATA, false, true, false);
+			Test("37b", TEST_37_DATA, true, false, false);
+
+			Test("38a", TEST_38_DATA, false, true, false);
+			Test("38b", TEST_38_DATA, true, false, false);
+
+			Test("39a", TEST_39_DATA, ANY, true, true, false);
+			Test("39b", TEST_39_DATA, ANY, false, true, false);
+			Test("39c", TEST_39_DATA, TP1, true, true, false);
+			Test("39d", TEST_39_DATA, TP1, false, true, false);
+			Test("39e", TEST_39_DATA, TP2, true, false, false);
+			Test("39f", TEST_39_DATA, TP2, false, true, false);
+
+			Test("40a", TEST_40_DATA, false, true, false);
+			Test("40b", TEST_40_DATA, true, false, false);
+
+			Test("41a", TEST_41_DATA, false, true, false);
+			Test("41b", TEST_41_DATA, true, false, false);
+
+			Test("42a", TEST_42_DATA, false, true, false);
+			Test("42b", TEST_42_DATA, true, false, false);
+
+			Test("43a", TEST_43_DATA, false, true, false);
+			Test("43b", TEST_43_DATA, true, false, false);
+
+			Test("44a", TEST_44_DATA, false, true, false);
+			Test("44b", TEST_44_DATA, true, false, false);
+
+			Test("45a", TEST_45_DATA, false, false, false);
+			Test("45b", TEST_45_DATA, true, false, false);
+
+			Test("46a", TEST_46_DATA, ANY, false, true, false);
+			Test("46b", TEST_46_DATA, ANY, true, true, false);
+			Test("46c", TEST_46_DATA, TP1, true, true, false);
+			Test("46d", TEST_46_DATA, TP1, false, true, false);
+			Test("46e", TEST_46_DATA, TP2, true, false, false);
+			Test("46f", TEST_46_DATA, TP2, false, false, false);
+
+			Test("47a", TEST_47_DATA, false, false, false);
+			Test("47b", TEST_47_DATA, true, false, false);
+
+			Test("48a", TEST_48_DATA, TP1, false, true, false);
+			Test("48b", TEST_48_DATA, TP1, true, true, false);
+			Test("48c", TEST_48_DATA, ANY, false, true, false);
+			Test("48d", TEST_48_DATA, ANY, true, true, false);
+			Test("48e", TEST_48_DATA, TP2, false, true, false);
+			Test("48f", TEST_48_DATA, TP2, true, false, false);
+
+			Test("49a", TEST_49_DATA, TP1, false, true, false);
+			Test("49b", TEST_49_DATA, TP1, true, true, false);
+			Test("49c", TEST_49_DATA, TP3, false, true, false);
+			Test("49d", TEST_49_DATA, TP3, true, false, false);
+			Test("49e", TEST_49_DATA, ANY, false, true, false);
+			Test("49f", TEST_49_DATA, ANY, true, true, false);
+
+			Test("50a", TEST_50_DATA, TP1, false, true, false);
+			Test("50b", TEST_50_DATA, TP1, true, true, false);
+			Test("50c", TEST_50_DATA, TP1_TP2, false, true, false);
+			Test("50d", TEST_50_DATA, TP1_TP2, true, true, false);
+			Test("50e", TEST_50_DATA, ANY, false, true, false);
+			Test("50f", TEST_50_DATA, ANY, true, true, false);
+
+			Test("51a", TEST_51_DATA, false, true, false);
+			Test("51b", TEST_51_DATA, true, false, false);
+
+			Test("52a", TEST_52_DATA, TP1, false, true, false);
+			Test("52b", TEST_52_DATA, TP1, true, false, false);
+			Test("52c", TEST_52_DATA, TP1_TP2, false, true, false);
+			Test("52d", TEST_52_DATA, TP1_TP2, true, false, false);
+			Test("52e", TEST_52_DATA, ANY, false, true, false);
+			Test("52f", TEST_52_DATA, ANY, true, true, false);
+
+			Test("53a", TEST_53_DATA, TP1, false, true, false);
+			Test("53b", TEST_53_DATA, TP1, true, true, false);
+			Test("53c", TEST_53_DATA, TP1_TP2, false, true, false);
+			Test("53d", TEST_53_DATA, TP1_TP2, true, true, false);
+			Test("53e", TEST_53_DATA, TP4, false, true, false);
+			Test("53f", TEST_53_DATA, TP4, true, false, false);
+			Test("53g", TEST_53_DATA, ANY, false, true, false);
+			Test("53h", TEST_53_DATA, ANY, true, true, false);
+
+			Test("54", TEST_54_DATA, false, false);
+			Test("55", TEST_55_DATA, false, false);
+			Test("56", TEST_56_DATA, true, false);
+			Test("57", TEST_57_DATA, true, false);
+			Test("58", TEST_58_DATA, false, false);
+			Test("59", TEST_59_DATA, false, false);
+
+			Test("60", TEST_60_DATA, false, false);
+			Test("61", TEST_61_DATA, false, false);
+			Test("62", TEST_62_DATA, true, false);
+			Test("63", TEST_63_DATA, true, false);
+			Test("64", TEST_64_DATA, false, false);
+			Test("65", TEST_65_DATA, false, false);
+			Test("66", TEST_66_DATA, false, false);
+			Test("67", TEST_67_DATA, true, false);
+			Test("68", TEST_68_DATA, false, false);
+			Test("69", TEST_69_DATA, false, false);
+
+			Test("70", TEST_70_DATA, false, false);
+			Test("71", TEST_71_DATA, false, false);
+			Test("72", TEST_72_DATA, false, false);
+			Test("73", TEST_73_DATA, false, false);
+			Test("74", TEST_74_DATA, true, false);
+			Test("75", TEST_75_DATA, false, false);
+			Test("76", TEST_76_DATA, false, false);
+
+			resultBuf.Append("NISTCertPathTest -- Failed: ");
+			resultBuf.Append(testFail.Count).Append('/').Append(testCount).Append("\n");
+
+			if (testFail.Count != 0)
+			{
+				resultBuf.Append("\n");
+				Fail(resultBuf.ToString());
+			}
+		}
+
+		private void Init()
+		{
+			try
+			{
+				trustedCert = certParser.ReadCertificate(Base64.Decode(Trust_Anchor_CP_01_01_crt));
+				trustedCRL = crlParser.ReadCrl(Base64.Decode(Trust_Anchor_CRL_CP_01_01_crl));
+				trustedSet = new HashSet();
+
+				byte[] _ncBytes = null;
+				Asn1OctetString _oct = trustedCert.GetExtensionValue(X509Extensions.NameConstraints);
+				if (_oct != null)
+				{
+					_ncBytes = _oct.GetOctets();
+				}
+
+				trustedSet.Add(new TrustAnchor(trustedCert, _ncBytes));
+				testCount = 0;
+				testFail = new ArrayList();
+				resultBuf = new StringBuilder("\n");
+			}
+			catch (Exception ex)
+			{
+				throw new Exception(ex.Message);
+			}
+		}
+
+		private X509Certificate DecodeCertificate(string _str)
+		{
+			return certParser.ReadCertificate(Base64.Decode(_str));
+		}
+
+		private X509Crl DecodeCRL(string _str)
+		{
+			return crlParser.ReadCrl(Base64.Decode(_str));
+		}
+
+		private void MakeCertStore(string[] _strs, out IX509Store certStore, out IX509Store crlStore)
+		{
+			ArrayList certs = new ArrayList();
+			ArrayList crls = new ArrayList();
+			crls.Add(trustedCRL);
+
+			for (int i = 0; i < _strs.Length; i++)
+			{
+				if (_strs[i].StartsWith("MIIC"))
+				{
+					certs.Add(certParser.ReadCertificate(Base64.Decode(_strs[i])));
+				}
+				else if (_strs[i].StartsWith("MIIB"))
+				{
+					crls.Add(crlParser.ReadCrl(Base64.Decode(_strs[i])));
+				}
+				else
+				{
+					throw new ArgumentException("Invalid certificate or crl");
+				}
+			}
+
+			// Insert elements backwards to muck up forward ordering dependency
+//            IList _vec2 = new ArrayList();
+//            for (int i = _vec.Count - 1; i >= 0; i--)
+//            {
+//                _vec2.Add(_vec[i]);
+//            }
+			certs.Reverse();
+			crls.Reverse();
+
+			certStore = X509StoreFactory.Create("Certificate/Collection",
+				new X509CollectionStoreParameters(certs));
+			crlStore = X509StoreFactory.Create("CRL/Collection",
+				new X509CollectionStoreParameters(crls));
+		}
+
+		private void Test(string _name, string[] _data, bool _accept,
+			bool _debug)
+		{
+			Test(_name, _data, null, false, _accept, _debug);
+		}
+
+		private void Test(string _name, string[] _data, bool _explicit,
+			bool _accept, bool _debug)
+		{
+			Test(_name, _data, null, _explicit, _accept, _debug);
+		}
+
+		private void Test(string _name, string[] _data, ISet _ipolset,
+			bool _explicit, bool _accept, bool _debug)
+		{
+			testCount++;
+			bool _pass = true;
+
+			try
+			{
+//				CertPathBuilder _cpb = CertPathBuilder.GetInstance("PKIX");
+				PkixCertPathBuilder _cpb = new PkixCertPathBuilder();
+
+				X509Certificate _ee = DecodeCertificate(_data[_data.Length - 1]);
+				X509CertStoreSelector _select = new X509CertStoreSelector();
+				_select.Subject = _ee.SubjectDN;
+
+				IX509Store certStore, crlStore;
+				MakeCertStore(_data, out certStore, out crlStore);
+
+				PkixBuilderParameters _param = new PkixBuilderParameters(
+					trustedSet, _select);
+				_param.IsExplicitPolicyRequired = _explicit;
+				_param.AddStore(certStore);
+				_param.AddStore(crlStore);
+				_param.IsRevocationEnabled = true;
+
+				if (_ipolset != null)
+				{
+					_param.SetInitialPolicies(_ipolset);
+				}
+
+				PkixCertPathBuilderResult _result = _cpb.Build(_param);
+
+				if (!_accept)
+				{
+					_pass = false;
+					testFail.Add(_name);
+				}
+			}
+			catch (Exception)
+			{
+				if (_accept)
+				{
+					_pass = false;
+					testFail.Add(_name);
+				}
+			}
+
+			resultBuf.Append("NISTCertPathTest -- ").Append(_name).Append(": ")
+				.Append(_pass ? "\n" : "Failed.\n");
+		}
+
+		/*
+		 *  Trust Anchor
+		 *
+		 */
+		public const string Trust_Anchor_CP_01_01_crt =
+			"MIICbDCCAdWgAwIBAgIDAYafMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMRgwFg" +
+			"YDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEQMA4GA1UECxMHVGVzdGlu" +
+			"ZzEVMBMGA1UEAxMMVHJ1c3QgQW5jaG9yMB4XDTk5MDEwMTEyMDEwMFoXDTQ4MDEwMTEyMD" +
+			"EwMFowXjELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" +
+			"CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANPzucEztz+nJ/ZBHVyceZ2q0pUQt4TO2qPlWAw+" +
+			"TotWvz6qIS1QE/7zGS56yxHP89O4X1efnZeArx2VVxLfNNS9865N53ymINQETtpjYT49Ko" +
+			"03z8U8yfn68DlIBHi9sN31JEYzoUafF58Eu883lAwTQ6qQrJF4HbrzGIQqgitHAgMBAAGj" +
+			"ODA2MBEGA1UdDgQKBAirmuv5wudUjzAMBgNVHRMEBTADAQH/MBMGA1UdIwQMMAqACKua6/" +
+			"nC51SPMA0GCSqGSIb3DQEBBQUAA4GBABZWD2Gsh4tP62QSG8OFWUpo4TulIcFZLpGsaP4T" +
+			"/2Nt7lXUoIJMN7wWjqkmYf5/Rvo4HxNcimq3EkeYcrm1VoDueJUYGvRjcCY5mxkghI27Yl" +
+			"/fLKE9/BvQOrvYzBs2EqKrrT7m4VK0dRMR7CeVpmPP08z0Tti6uK2tzBplp1pF";
+		public const string Trust_Anchor_CRL_CP_01_01_crl =
+			"MIIBbzCB2QIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDFRydXN0IEFuY2hvchcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAiMCACAS" +
+			"cXDTk5MDEwMTEyMDAwMFowDDAKBgNVHRUEAwoBAaAjMCEwCgYDVR0UBAMCAQEwEwYDVR0j" +
+			"BAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEAC7lqZwejJRW7QvzH11/7cYcL3r" +
+			"acgMxH3PSU/ufvyLk7ahR++RtHary/WeCvRdyznLiIOA8ZBiguWtVPqsNysNn7WLofQIVa" +
+			"+/TD3T+lece4e1NwGQvj5Q+e2wRtGXg+gCuTjTKUFfKRnWz7O7RyiJKKim0jtAF4RkCpLe" +
+			"bNChY=";
+
+
+		/*
+		 *  test1
+		 *
+		 */
+
+		public const string End_Certificate_CP_01_01_crt =
+			"MIIChjCCAe+gAwIBAgIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDEuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMY07G8M4FkOvF+6LpO7BKcDuXCKudfl1+bKSowj" +
+			"2GCza8uIiMfYSH5k+fYb43lGQeRh9yVHcfNQlE7yfGo3tgxGv5yWpeKvDMqL8Iy6Q0oIjm" +
+			"qH80ZOz21dUkermcckzTEOfe/R2fNpJPv8M24pq29SdYAqu+CpLDHFtws9O+q1AgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIrNv88bwFLtIwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEAK4hP" +
+			"goWtZbHf6qWfRfmrPrz9hDH1644NrJop2Y7MXzuTtpo1zp4NCG4+ii0CSOfvhugc8yOmq3" +
+			"I6olgE0V16VtC5br2892UHYZ55Q4oQ9BWouVVlOyY9rogOB160BnsqBELFhT0Wf6mnbsdD" +
+			"G+BB5fFyeK61aYDWV84kS7cSX5w=";
+		public readonly string[] TEST_1_DATA = new string[]
+		{
+			End_Certificate_CP_01_01_crt,
+		};
+
+		/*
+		 *  test2
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_01_02_crt =
+			"MIIClTCCAf6gAwIBAgIBAjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAxLjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDWOZ4hk+K6NX/l+OiHC4pfKCWFt+XM2n/TxwkqY+mt" +
+			"j9Co77rPPPtVA7mDKU4OiYT74mIWH52HQBZr+PRmOFh0Z9S1oTpLbxNLCDc6OmQKBo6iex" +
+			"SIt/jOatFFmzmTZ78Kq9s3nfrOVA83ggmPDTPkuG5GwcxPgFq0vRmAJ0CESQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQI5o5Am09NlOYwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEA3C7Ye5/Te14LIwo/LK2fnpobbQA3dhOn5UgqZ8lKbQ/HV1D8/eU9dK" +
+			"2v5gW43XvFq4whK0WKLBvBFchKtp9T1QX3CI2WCqdJRyqla6TkQsS36T17/ww2nzy1853Y" +
+			"hfDYNsge5XW8YZNfNjjVxcR3RnyFxPax1YIlISiGdI0dnag=";
+		public const string Intermediate_CRL_CP_01_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI5o5Am09NlOYwDQYJKoZIhvcNAQEFBQADgYEAl26W" +
+			"g1Gqq3R93XPjghABVocfeIi8zcSJ0YAKqbifh5V3JCC8Piy19GzZdL244GqBDls44IAhKj" +
+			"YuXN2mSohdqwULbye4agAgfl37XhhwsBDTYwaJiv3njFQ6Ml7KJ3STmoIpmlLvrXibDuHX" +
+			"ocuNGo72ckhOdBpXd+PhgGuoTis=";
+		public const string End_Certificate_CP_01_02_crt =
+			"MIIChjCCAe+gAwIBAgIBAzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMS4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDEuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALwJrZT6bJXQnZzc3socZ/mNsEag4BTdym99ZCP2" +
+			"3PGsTCfV2z7+p4DehIFrn/N/a1d1nvyqRqpQGPU86tl1CWgFtXS+zCctDR71P76bjd6yef" +
+			"5vxxdO/SBIRHfQTjM8F3BTLkrC+PVl5wbaLcEXRORXrFvBvsj0oqwZ4C8ZObh/AgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIf5mSjuNhs/gwEwYDVR0jBAwwCoAI5o5Am09NlOYwDQYJKoZIhvcNAQEFBQADgYEAK7wd" +
+			"MyLlIZ/Qsqj3/A3Gat0d5BORtFTZH0VdlVVOWN1JCZxrnjeIFB92NNzUROemxgBxzneuWN" +
+			"SlYlcpTk25pAbs6RMdbT8dovKQkQkF2TXeQ+4qktFaLQntVT8UsEzHR4Diw0/gH8tseGqF" +
+			"F7FyiW8ni6zInSO+embUKiibj9I=";
+		public readonly string[] TEST_2_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_01_02_crt,
+			Intermediate_CRL_CP_01_02_crl,
+			End_Certificate_CP_01_02_crt
+		};
+
+		/*
+		 *  test3
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_01_03_crt =
+			"MIIClTCCAf6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAxLjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC4RZ0R82sA+BfyynFeoIDG7c5IlZ8HorEv+O4Ij3Oy" +
+			"7FR1MB4no8hDEBPBf5fCrAR/8PVxCZjVj2HOwnSAqUQgxo6WPcmkabux12k8kK6yeKq3b7" +
+			"u5fL6tb7eKElQzsz8Je4z4rCDkI10vV+X0VZ5Ip/Es428dw2KoN8eyGmw3+QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIz08WhMpG2JswEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAQ+iqlFvbvDejO/m+RCHh2UuUau1FuABObkPOu2Tv9yTWvTSWDRygdO" +
+			"LQRiOLsjgrdXPdbDutVGjllBoTN8cdz3SWjCpampg5TBikArxmNEYMDQvL6n2lkUcetRJR" +
+			"gQ7TYLvFj9+SycKXfM5CUXAyCfcU/QwDghhZgc99AuDZtJc=";
+		public const string Intermediate_CRL_CP_01_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIz08WhMpG2JswDQYJKoZIhvcNAQEFBQADgYEAoyO/" +
+			"xcpJ0Obj4rTXhHFd7XMzslt79njkEgdwnon9BaYB3xSmkEXCMwLMurrjVYKaB6SWAiPeUv" +
+			"G7ScDHJE6UFVJwIt4vP/M7gTOJ7uak33aWi9e5DeIuLqE6pFqTGu+uoBkkd82SHg2GhJhZ" +
+			"VXDtJ3UcO/3JQPbslc02s9HiRBg=";
+		public const string End_Certificate_CP_01_03_crt =
+			"MIIChjCCAe+gAwIBAgIBBTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDEuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANAD1vQj//4BGEXW1Q7HX/AUyFJFyHoYcvg5y4u/" +
+			"8Sj6okriXj3knnBKDiJLpKfcsO5p5MQS5QzAc+lxErXD+duiw8lm61hj0StsRzhDFsaC1g" +
+			"akjzU70R2Tmz/djUnqO3aa2wICc4NVAXnIMMsH/b6XXFZpC0/C32TPTv9aa9mrAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIPw2wltiRqz4wEwYDVR0jBAwwCoAIz08WhMpG2JswDQYJKoZIhvcNAQEFBQADgYEAln42" +
+			"iR3eHyazF8CRjS9Jnas/26MaBtjUyDtcSjTVDWFlccwrQ7TgtzjkNm9fCmgSyvryDnUYGM" +
+			"DoEjwYNLIgtCAkVIEBTmJvlqiPHH+tV5oJvIav+Fn8okHpuuK44umDcdKiFWlOyxrShxzV" +
+			"3Bez/eHklaPTw/VsVhyh+Uru5zM=";
+		public readonly string[] TEST_3_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_01_03_crt,
+			Intermediate_CRL_CP_01_03_crl,
+			End_Certificate_CP_01_03_crt
+		};
+
+		/*
+		 *  test4
+		 *
+		 */
+		public const string Intermediate_Certificate_1_CP_02_01_crt =
+			"MIIClTCCAf6gAwIBAgIBBjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC/lQLtWKzklgYuzhjMiK2CzFmzODsEY/JIVNdn9T8M" +
+			"W4ufpGwnfIV62EUHCFeMYydKBm8Hyjbjrz1otINJmrGL5WSAX1/UPtHy1chgXOsFYD6nAH" +
+			"jZAJJGw74nUbKw5+L1wUHU8qXABaaTrRpS1UdKSq4TCZ18NCjC4Oxcf/yDdQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQINsJcxaBqdugwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAOQP3iUX7FtJlL9nvu4F+8o/N5vr+OB28OsbYtW+Q1FzEfjkUGtT9Ri" +
+			"teradpN/xUnS/oj3BfqFtNANkYKrBeqRtm2VeOC3kdCVFnWFME2aoRAQZbWvOwCFc3yLA7" +
+			"JBdENtDNI54yYHMHPA4/2CuNQq1Iu1ektAS95DIe7ddxL18=";
+		public const string Intermediate_Certificate_2_CP_02_01_crt =
+			"MIIClTCCAf6gAwIBAgIBBzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMi4wMTAeFw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLUNQLjAyLjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCx/mIo1Ma/IN8OR7KOjclvIwsv0JFXD/T258DruDZU" +
+			"uGoYiEbAc/ZN7R8OHI7dnv9pBfsvyEl7m2DVoLZnP0eXJTHjdZxb1TwPHoSIysi9u3xWlP" +
+			"Rg+v+GGfKLB9pL0m8SZh97SngerZI14w7vQy0kkXziGatSpBoXtWNmsHJNuQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIoI0mSmDmzZUwEwYDVR0jBAwwCoAINsJcxaBqdugwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAcfs1pH12Qwdhv4NOJO2xxgMZZo8+A9Zl9c7RxsvuoZOOyCxoE9wT/l" +
+			"PdUpGoGxtIPoWQs1qXEXnAlXJCXjLCJUHIG1/E6gQUXW0Ty6Ztpc5Dz06pPTN2gt+41B3J" +
+			"sL/Klqc4iyCaWr8sYgEPQ8nColWRmIwk9gAasPNkNhyxA3Y=";
+		public const string Intermediate_CRL_1_CP_02_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAINsJcxaBqdugwDQYJKoZIhvcNAQEFBQADgYEAlBaV" +
+			"VfrZqvyRhGXNYFik169nBHiNfKpw8k1YgFAQeNYdmfScq1KHmKzDhsx9kQteczBL7ltviK" +
+			"TN3CKlZW82c16mfd4yYx0l5tkU80lwKCHSUzx92+qrvYjSMup+bqSsi8JhqByBf6b0JbKf" +
+			"yx53Vpw1OCzjxrVHcfHPx8Q/vR4=";
+		public const string Intermediate_CRL_2_CP_02_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1DUC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIoI0mSmDmzZUwDQYJKoZIhvcNAQEFBQADgYEAhAHP" +
+			"QxpcrTTN0GXeOwoMXuQUoHMvezEpM0BYOVLzI3KbRXWa9iWZINr99cRQvonMtOGkhIH3iS" +
+			"wSNbsjmF9HX5UvNzrofOWataVP+macpCuNlK0NS3xxJjKRWOB9C1Ib7tiSSrQqIPcchlF6" +
+			"vofy2ALEL6Usa1UTVYMhzGYnVZU=";
+		public const string End_Certificate_CP_02_01_crt =
+			"MIIChjCCAe+gAwIBAgIBCDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1DUC4wMi4wMTAeFw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOzYq2murB5ZjQd4wReI51Lc1F5VwK90OMGRfi71" +
+			"YvwdRjgCudeDXZGW5ayid82y+eTDKFSzo1Li/BPTUXMpeqHHMCmLeefqxAWmz3aDoilF8I" +
+			"Q53PlejnXJdntsal44w6WdP6ssiXlwzcZDnobAfuDTPgsnWWfzAkr1/LqEw/QZAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIP5tVdEyxotcwEwYDVR0jBAwwCoAIoI0mSmDmzZUwDQYJKoZIhvcNAQEFBQADgYEAkVx9" +
+			"S/20Hir8qMnfMpMGTgMKoVeWoljxim83IkNs1Xqe1oLGHdyDUA66uF8wPkoTqGrfDYvgBa" +
+			"5Mi0iJREnMWoiWvCe467+L1b2gtvRBMl9bcRj40bvelk0Wn4lBl3VuKXarP5M0PKT5OWvN" +
+			"2cPLNeXHvV6ZIrC4rmK2ISpIXX4=";
+		public readonly string[] TEST_4_DATA = new string[]
+		{
+			Intermediate_Certificate_1_CP_02_01_crt,
+			Intermediate_Certificate_2_CP_02_01_crt,
+			Intermediate_CRL_1_CP_02_01_crl,
+			Intermediate_CRL_2_CP_02_01_crl,
+			End_Certificate_CP_02_01_crt
+		};
+
+		/*
+		 *  test5
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_02_02_crt =
+			"MIIClTCCAf6gAwIBAgIBCTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw00NzAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDHJmlRKb+mjc61iiqGe9gx/VUMLNmGrXGRYKMmYSxO" +
+			"Q5sGLoztd2XtEgtZEPwvzd9KLKGP3XmgTrc4BGohqoFoG9Qb+w2ZGFwVC22GpeSoXc+J2u" +
+			"2t3uRKYgboHpB0Jk42XLy+2wSEtS+/er7cFu2ufdPsvT4J1AqiuZSco96vtQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIBvoP1E6PGiMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAmOyFq2vZrUNDVWRcyzYvZhs1uQ4zgXtfqnPE0V19RgaYffCrSCI86z" +
+			"5kyDUyZwbGABMxBaVxEw536MesyDTdZdEVw6lN5RRtxr8/WEiSH6oI6t0xNxuNOkSNpz4d" +
+			"28HA4UfUvtXK8RK2YZnPAd6UXsRUPBPXKEpzy4v/9RyihSg=";
+		public const string Intermediate_CRL_CP_02_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIBvoP1E6PGiMwDQYJKoZIhvcNAQEFBQADgYEAALlA" +
+			"f3IDWexcdkMQHWTdGeFe+bG5dBvVPL5ZyQUw9DWbLwrjw/Jm4v9t+HLjETLSymsFT4bW21" +
+			"OwnEiAAdaKT96k5t+sTyU5QQ6HL/jRXLHLGdCQgMFCglm5iNqaCLIFoMAVCaFkYtFUE3m/" +
+			"iVt+319JOh5UyshMuWrAEW0IGGQ=";
+		public const string End_Certificate_CP_02_02_crt =
+			"MIIChjCCAe+gAwIBAgIBCjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL/Src6e8qXwL+KJs5+v+JsakZdSDqMAFJUMfA2O" +
+			"OO2TIqcvDFHzqesX+G+28MUwy6++ux07CD3FCaapgzBN4zO4RfKcamxFReKMKcEvNVVCOO" +
+			"wO4Lvku1Sad14oYyGLOMzZwZFjRp8paaz5g87k70EOPBLeDlFMcch36czw53sLAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIPoHc2Sfk6XUwEwYDVR0jBAwwCoAIBvoP1E6PGiMwDQYJKoZIhvcNAQEFBQADgYEAFHhm" +
+			"o6QRFdO1x1wp7Jb1QQAlChFfP8MrGVNK04Ur8f+wfkwIypTDifJ0AoFpjcM3Ohu9Ixvb9q" +
+			"3kCSIWKDnWtDWw1/dN8mPL5If5gGqPA0+wRbUKVKvduOg7hKr4mWjKw7oYiaJuIIoN9RRZ" +
+			"ejzltd0NEaODNPW/JaKeQUVgZbY=";
+		public readonly string[] TEST_5_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_02_02_crt,
+			Intermediate_CRL_CP_02_02_crl,
+			End_Certificate_CP_02_02_crt
+		};
+
+		/*
+		 *  test6
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_02_03_crt =
+			"MIIClTCCAf6gAwIBAgIBCzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCaJ7NcOvb22F6HjMF1R/AORa4+pKFfFfd9teXPpVWC" +
+			"9InTq+alY11QaSj27Qg0znOIItmf2W/8Dub9sjnbg+SgAkoV5+CAkplodRNC8AbD4x8rh/" +
+			"fioQ8lb0Qb4Dn9I0n2wjOgitmMRdE2uW4uwVpH52vsMyenbDVxVI7jA4NS/wIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIC2T+/BkG93AwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEApr6kDXVY5jYt23wC9n3LmhoxDoWh8cBQxcWmr1wpVxIrCbaP0/y00a" +
+			"29wbewKfucUoh/W2OfjNcohjpKRrnVmOpi5vN7SmbZIHaxbKLzyQ7JwF17aznyCSZVrGpF" +
+			"A/S49T5rlCm8KDBcc2ym7gRJzwUApbC0Wws4Pg46czrpQlg=";
+		public const string Intermediate_CRL_CP_02_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIC2T+/BkG93AwDQYJKoZIhvcNAQEFBQADgYEAlBFY" +
+			"vPxhFYsjFOIfQkd7MwKIi7vgPgoWTP5f+QlI0ison5n4N3rYJv31hTZRRRP99JZce1hY6J" +
+			"Qiv1OtkpG7VfQIhr0FAGxTNaJD6F6rLbGjG8cap4+VibFQf5gZv0XQcyW4akYiRqSXImYn" +
+			"NVlNyaxiJja+5GA9XVqvWOjjz4o=";
+		public const string End_Certificate_CP_02_03_crt =
+			"MIIChjCCAe+gAwIBAgIBDDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMi4wMzAeFw00NzAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMlW6FOLwhRsKZM6p0ww4QEWjQzjpjYhKnz3BnLw" +
+			"SdGZqMe4wzZnDWc/0eyDOMCSYXIWQhlDMqQn2zCVPbDKzMRkdEeRSvE6ghhYP/hn3ipjSw" +
+			"D8QwaqofCp0sFkbDPke+xD2tMhLdUyNKynPjpSQmYtfoA98PD7so3cSAtrYuSDAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIc/X6kp7teCQwEwYDVR0jBAwwCoAIC2T+/BkG93AwDQYJKoZIhvcNAQEFBQADgYEAStub" +
+			"g3DzhJgzYO+ZmRc0acldZGwZFm6F1Ckc1JzQDgVHU0bnCANgBcJj49UV2MwbNKPQdVzdwo" +
+			"c91rfwrSY/PrvVQ9tUonZ28y/esFRBAdJTLf4u++p/gI3vfCvEXa5xVTIz1Hc+iKzAGKrI" +
+			"cveDHy3ZZluQ3J6tbHs2BhnQFXM=";
+		public readonly string[] TEST_6_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_02_03_crt,
+			Intermediate_CRL_CP_02_03_crl,
+			End_Certificate_CP_02_03_crt
+		};
+
+		/*
+		 *  test7
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_02_04_crt =
+			"MIIClTCCAf6gAwIBAgIBDTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDgZy2Xs5pIoJrT7GuagmKLrn8F9rj8p8w2wELorGhM" +
+			"1HJMVOurH+o+y6RXd0oMGJkKNrhjEnbHKm3PBYiLgpCjVEcFNhQF1OOxJ7RdahvA9ifsuw" +
+			"jV1TxTGq35jeaJYASRXb2TiNfzuPWSVm0MWr5zz+YB6NNuvjxwEBgZvNiV8QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIWAOnkHkwSVkwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAMiHozz92EOhSXU/krwQVs0GNEWoAUH3LHt70Zr01dFzEF6QhA/wUa4" +
+			"+V4XwbMob+q4zGnTHj+tL9ChGWi3NDGELQ4cN64OMPsToGKkepLy+sDwdm9LaUP1bDvPxd" +
+			"v2hjlskJ7TEu4+6ltXSG/k36Jk8C0/I/ayNGbYcEcLyes3s=";
+		public const string Intermediate_CRL_CP_02_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIWAOnkHkwSVkwDQYJKoZIhvcNAQEFBQADgYEAVtCi" +
+			"IocktnWOwWiaOc7tTUJvvH5+IYVyB/XhmMhF7cDbL292gyrnuh1+3+lHwZQBPoF9kzF0vt" +
+			"WaweG7mDvYKxENQODdph/VcnypgUiFTWRTIPB1ZXfCTMWYf2QSalpHRDR4vVsqF748QbcG" +
+			"E9mbzvLUz6NDA+Vf8wEwZehqSDM=";
+		public const string End_Certificate_CP_02_04_crt =
+			"MIIChjCCAe+gAwIBAgIBDjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMi4wNDAeFw01MDAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDQwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALBX5GIQtvwswWwMDDPnphIk1rJSbcq7iClXLM2E" +
+			"kgvBu+hbOzb0v9mtl0KJB71TWJCfwceVQiXc3Gk+YduujAbZRVTkROf9UOWD9bfrI7g+52" +
+			"g4ms2n7evCO33b+kGEf4I014xl8dJDWtHK9Bhr+569RW9TzO06IeVeTD7whxMXAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIuKXv5WkUTWAwEwYDVR0jBAwwCoAIWAOnkHkwSVkwDQYJKoZIhvcNAQEFBQADgYEAiu0B" +
+			"yR5Ru8qVsgRqkOpCvrJnkqBAImbbR6+BUYH0juRxxKzKnbFOjU6a9WvkKpEBB8Q2xLynPN" +
+			"68ecLpnOynx3xj2sWWSVbsRKPy0iOesQblKrq3yHAm4lhzoWA8t1Xz29Ko1WxylDhyxGpR" +
+			"QAWsyGVCfJFlsZE0ibw3erlWTnA=";
+		public readonly string[] TEST_7_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_02_04_crt,
+			Intermediate_CRL_CP_02_04_crl,
+			End_Certificate_CP_02_04_crt
+		};
+
+		/*
+		 *  test8
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_02_05_crt =
+			"MIIClTCCAf6gAwIBAgIBDzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjA1MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC2d80bD1RounqjKizkZJYPFUuVWZQ8W2nZDkEp8qR9" +
+			"fRWCAGOZGs84tgHj5gasmxy1mxJc9ogyQ2mcZhJRitRm5LVNuGevO6JmfqYtJxbW54aZGE" +
+			"5AWSRXqjJKJEih4VmPjA3vjQaSZSZJnu0DSnO82qWfu1ZUDlvIG6dfKJWRQQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQI3uNhI+QuI4owEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAG/+Rpk8dYrSFdaEO8Ch5tuvvKTOMi7W/DRA4B4xR7WyRJmosPB+37c" +
+			"teGKVzqFND22Xc8xQH/b/nxYW08sCSLAfN0cRusoSWwWSRtPO2f9fyC/BqCy2B2kQLFNPM" +
+			"Bk22jNFwLqPUeZn1UHN05RFAqVx325kpl2m1V7tw/mrXATI=";
+		public const string Intermediate_CRL_CP_02_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI3uNhI+QuI4owDQYJKoZIhvcNAQEFBQADgYEAWZUI" +
+			"2VGY4pak0kICONP/CKvamYFs5txJfR69AC5tEJ+Fy3PmSeHkLUZf/oc9d8EEyr0MsIjRHj" +
+			"N4X4MquMlk4FflZcc8GblQK8LdXBK4Dy1SiXHA5GB3U1AmgzAzEQGwGRZnzWP5+rJ65upX" +
+			"vksAYyPQmruRM0O5sElctPn6B+Y=";
+		public const string End_Certificate_CP_02_05_crt =
+			"MIICiDCCAfGgAwIBAgIBEDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMi4wNTAgGA8yMDUwMDEwMTEyMDEwMFoXDTQ4MDEwMTEyMD" +
+			"EwMFowYDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" +
+			"CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRcwFQYDVQQDEw5Vc2VyMS1DUC4wMi4wNTCBnz" +
+			"ANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAviLKpW4iblWNLQfmBJJ+ruMgygmjRWfoFGya" +
+			"Ndv2ma0Ugqm5xXq8c0orbnezwSp+tnzZZhG5KDNZr5+z3krCkqOGGzuUvVLqeJxPOLu7Js" +
+			"y472nAA7+FhwfZrXUI+Vg9F4qF+Ye81ivDrYVAEmalCpCyHOAKdvwkwQjRucifu90CAwEA" +
+			"AaNSMFAwDgYDVR0PAQH/BAQDAgXgMBYGA1UdIAQPMA0wCwYJYIZIAWUDATABMBEGA1UdDg" +
+			"QKBAjgph7BA5L7dzATBgNVHSMEDDAKgAje42Ej5C4jijANBgkqhkiG9w0BAQUFAAOBgQBr" +
+			"MDMv9NWCTIQ3blMEqPiEyjiBhSJl88Cu797P4lIn+gc6E+0vZp61X7B2k5CHgsnxyVLK5e" +
+			"bwl0bYAPKwRI9yzHLrj71RNw8HA7PCRPn1GNrtBBbIpLE0/sqLo51UPu/377+CnzYhIycL" +
+			"tvS0KDLUTDSY/OowDcplF6Xwnt8cUQ==";
+		public readonly string[] TEST_8_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_02_05_crt,
+			Intermediate_CRL_CP_02_05_crl,
+			End_Certificate_CP_02_05_crt
+		};
+
+		/*
+		 *  test9
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_03_01_crt =
+			"MIIClTCCAf6gAwIBAgIBETANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw0wMDAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCuF8mub5cgUYZytrRjJ5Rhc2fgazGxWIj6EIKzeSpo" +
+			"FwScItRX9KxnTIXEBTguBk7eQUsbN8yu49/Mlq45EAnemyZRBWzLFLYLPCco7pyTsWm7Ps" +
+			"2FAGJ3vE9pC9xaZC+KrwF3Ho+DZNDwhj5InXTP8pChAIPfB8/7V/2mk0lN0wIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQI4mI6Ojs0onswEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAMVGzU6f4YOHpHla+YuGCjHOUZYrA9J25G3UFFoPr2JZEG+Fb5hRQUh" +
+			"4S1qUQKXn6dpVua+qTJDk3Tg2N8OdIHG/gy0hvYHsxhLCSDQBsfPN7p3FClM7r/VHOqgAN" +
+			"vzT+KYvxx6gwn6O+n7ERkrBIfkyrGFhnmjx3+VOCc9P4SDE=";
+		public const string Intermediate_CRL_CP_03_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMy4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI4mI6Ojs0onswDQYJKoZIhvcNAQEFBQADgYEAfwYf" +
+			"4kAG4srB2VxWimJs1HwXTaPDooellQclZ5hP/EluT7oe03+ReFef6uXbHt/xRdeaoQhJGy" +
+			"SP8dWf6UIbL82oaSYqChIvAZD6zTMavEgSET0PlUsK1aEMTpMEtKPvedFSOTNBaMNvMzSW" +
+			"t5xwurn63qyXTOxHf4m2L4w8+i0=";
+		public const string End_Certificate_CP_03_01_crt =
+			"MIIChjCCAe+gAwIBAgIBEjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMy4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDMuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ/ALaZ+MdNxKDH49+7jUm+17DII5QQEfjk8IaEU" +
+			"syApOhsByOG06HPItiBEnnfDDxU5kjsZDtw/9LlouBocNXAJt+ZmL3QYyOgeH4SQ4f21rw" +
+			"7j8fw57gUkP5oWhEc0loXr/hB92hoKbsBoRpv8F1zPZcPNLUnyUzqLH5+CeIibAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QI822isg/wPCowEwYDVR0jBAwwCoAI4mI6Ojs0onswDQYJKoZIhvcNAQEFBQADgYEAilIn" +
+			"OD0iQrLrHRkO4zr9S9VXAJXJV3l9wfbLBweXM3q/zt4HGKBw4Wq1Yn+AfDxXrBtJA5hP5e" +
+			"d7CDd4eM93yeKozdZCLNZfUM8sJ2/MRh07tvwJ19e2STklED8b/ndmr5my8H8jjJDaaYww" +
+			"qTSnXqpcqsUsj+kV4Mk0DvVWT3w=";
+		public readonly string[] TEST_9_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_03_01_crt,
+			Intermediate_CRL_CP_03_01_crl,
+			End_Certificate_CP_03_01_crt
+		};
+
+		/*
+		 *  test10
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_03_02_crt =
+			"MIIClTCCAf6gAwIBAgIBEzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC4AbP8gDUUcIa8w4pEsGgbYH2sz08QMUXd4xwx691i" +
+			"9QCcyWSovQO4Jozeb9JwtyN2+f3T+JqZL/gwUHuLO2IEXpzE2C8FzQg6Ma+TiSrlvGJfec" +
+			"TlSooFmEtD3Xh6I6N5PM1fpyyY2sOOhARN5S6qR9BOuxkBAqrAT0fgqD2TswIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQI97nJCqq6+kIwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAWwpfh9oOOvj9xHS0zcczaUIHTkpjgk09I+pERlu0Z0+rHvpZGge4Ov" +
+			"NDFtMc4TgthGcydbIwiKogjtGBM2/sNHIO2jcpNeOtNKLxrzD4Y0Ve164kXBu9Mmsxx4sG" +
+			"7XUXZWgiOPfu/HmyPVdzbIReJdQO515SNx7JdgVyUkyhBxM=";
+		public const string Intermediate_CRL_CP_03_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMy4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI97nJCqq6+kIwDQYJKoZIhvcNAQEFBQADgYEAC9Hv" +
+			"NevV6/Oz3wcgEbDgZYRKJRdr4OW4Es7R4ahjz3sH6GXZ1HiEjx2+frmp8LMshQ4D+hpjRk" +
+			"drSPko1M4a/fQCYxbonZ0xjpYw067dwLmr56+GPJAxkzcSmFKXx+ejyQpG+9+qCR+zm98V" +
+			"lop6besAaGUjZKnYShIQOfNzDZk=";
+		public const string End_Certificate_CP_03_02_crt =
+			"MIIChjCCAe+gAwIBAgIBFDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMy4wMjAeFw05ODAxMDExMjAxMDBaFw0wMDAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDMuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMJMiW+G4bgoRaYz2OUu/+PQ/yp4JgFOB3Vegf5/" +
+			"vIrF4gsnoQxOCCsO5JTLrbS5fi3COjvM5w9/SZpNHtSfyWb9afmx4DdrT1bNjma7I6PCid" +
+			"yxMzX4iTLeaMRnqBk4A+/0Wf2+4VzCqr8aViIiQ7u2JfZiTQ4dZxDoUW6G8lrbAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIEjny2GzFXGQwEwYDVR0jBAwwCoAI97nJCqq6+kIwDQYJKoZIhvcNAQEFBQADgYEAJw3T" +
+			"3aL3pYbZhswgshOvJ9Y1qv65R6rClSxB5lqBw6+Qki4ZpW57NK8LwaGS03XzDUPaDi4/9R" +
+			"hGCHpP24fIskS4n4jNZgKpGtt6VEVorUH7cOLNCw2cuwMlKbkyZnNdx2JqTMMlHzNJ3cmy" +
+			"aX3F70IY0OZbwCKdUo/uMVC6hss=";
+		public readonly string[] TEST_10_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_03_02_crt,
+			Intermediate_CRL_CP_03_02_crl,
+			End_Certificate_CP_03_02_crt
+		};
+
+		/*
+		 *  test11
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_03_03_crt =
+			"MIIClTCCAf6gAwIBAgIBFTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCjLYKGKEMJgC/r0NH7vubQZ5qPEFEEN6QdLUWWqf/O" +
+			"Yqo9hboQq6S8dFHp3DVR5x/4NOdNRjsTABbXsnz8U+L7+4CorhDhXj29weGMYIIfJ3XSIb" +
+			"T7sE/GOPmXeGhrTv2zucI1j80sN5nTEoiGFm10LQqAgoyV46BxDltf3/D7wwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIhCIOyzfScpAwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAA18kQijoJebmTQS7n/q/fQx2iblOJaJAWQLHeGCCGqKxCjUpOxuD+y" +
+			"xMspmTKdQqEkqQ5vpHdFYQ5MYuecqAdp6woWUNQGVd4HHPmHsAW3Oppwb0yLggYs8IVHjm" +
+			"dNO1pYb+YYciCKBtX8D1OnedIRcrQmDMJUjbfmAEv/4b0EM=";
+		public const string Intermediate_CRL_CP_03_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMy4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhCIOyzfScpAwDQYJKoZIhvcNAQEFBQADgYEAk34j" +
+			"SxMr8p1h1qJWlfoh4er9pu1AkkHujovan6Ctx89VwFdOS5Kw82OCvD+nmJAHrFuncNlClf" +
+			"51G8FCEAFLhMNwic4WAxrBX15hcUTaWk8Wj00dfUFwjG8/Kv3QUCDBN8f3KC8/oBeORRX9" +
+			"dHW5ei2IUKuD1ITCeIoyRDBxQIg=";
+		public const string End_Certificate_CP_03_03_crt =
+			"MIIChjCCAe+gAwIBAgIBFjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMy4wMzAeFw05ODAxMDExMjAxMDBaFw01MDA3MDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDMuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALSw1Ey7kzFzzjMS4oTSrZH/95NMHLxtUSaVGMCy" +
+			"0q2iLfGZ79eTS9megQUranYlIuK411yvFtskbFKf0idMKBtM8nX3Rxubm5EnbnpgvNrBEg" +
+			"0FbOPqpSaR+8pxZ6lweB45tkzLU3OZeAZSpGOY1UvT/htn6Ae8JQAVajSvYyfNAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIF014kOHikvcwEwYDVR0jBAwwCoAIhCIOyzfScpAwDQYJKoZIhvcNAQEFBQADgYEAdLMM" +
+			"zGPPvBLgPbhn2tba/7HiaZaayHIxTXmpW0KAhP+8hwapOitrtLGPwqVtxQ3GoSMZJPMDCV" +
+			"WsrT3OZm27G6ytqqNZ2ZO49UC7WwQ49TVlN79Ui9RZIBnRzlMIDNKsyuohfSRhFZTkWdoH" +
+			"/y8ulY8k4xBThV8e8IRgtYj3nhc=";
+		public readonly string[] TEST_11_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_03_03_crt,
+			Intermediate_CRL_CP_03_03_crl,
+			End_Certificate_CP_03_03_crt
+		};
+
+		/*
+		 *  test12
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_03_04_crt =
+			"MIIClTCCAf6gAwIBAgIBFzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDbUii3czeUQ2zNlxvrhnJ0LcBGxCDHFr3xx+plDg3f" +
+			"uasDKCY/VjCLEfQ5a2oqcovvGKsd2CPXbCFJtimW1R7Dvt+a0y95fppsdseorYDikiBlOj" +
+			"ja6LR3Cz3bslYc133C+W/MKHMJ0tdvtTk+SJrq7lqs+iv/b/xHC3k/gDjIswIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIFNw3o1kc4XkwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAn/pr7/noYyjXSKEe/eLk3l4Rb6PEhNAnzySmxGkjIjWKAgh5IVYSGV" +
+			"KFO/FaNOiYkRFHwXZFNj71q7gbM+HwALurN0Mr/MUA1TSpPy7YhFL0SWq3C3XsC/dVJ50b" +
+			"HmTW+dGcxboX0h9HeKFxp3VyOY/dUut2oc+s/TnmqQII1CU=";
+		public const string Intermediate_CRL_CP_03_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wMy4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIFNw3o1kc4XkwDQYJKoZIhvcNAQEFBQADgYEAMoJ5" +
+			"jGE1AxxfluixG8Sk7H4W2rqSEkQyNHfnlKSMbh9KZA3evI8HGKGGfkbBNoe4/HauZ4NVFw" +
+			"FXgllCp+TI8Qd+HafFoDv6ff1K7T86p6r7tE3AEM1XmbnfohP3/ivpIzustv/f2rqjxILK" +
+			"Ldvrth2/OlNygwY+D54lcWH1DX8=";
+		public const string End_Certificate_CP_03_04_crt =
+			"MIICiDCCAfGgAwIBAgIBGDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wMy4wNDAgFw05ODAxMDExMjAxMDBaGA8yMDUwMDEwMTEyMD" +
+			"EwMFowYDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" +
+			"CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRcwFQYDVQQDEw5Vc2VyMS1DUC4wMy4wNDCBnz" +
+			"ANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuSL9tB1JW6JPUO2Xw6TMYkPX41lru3EPyYko" +
+			"YgXy4giy6LGoqbgtskHehD22v3rfWjqOd9iV2PBio/vYE4zEz0H0n84dpnBvog6A1AlE19" +
+			"PkQ1txjzIA52FQIRwRfZ38LaulQEfJ0a+fiRHQiM960O3YvHXV+GEbNcw4jo8b0sUCAwEA" +
+			"AaNSMFAwDgYDVR0PAQH/BAQDAgXgMBYGA1UdIAQPMA0wCwYJYIZIAWUDATABMBEGA1UdDg" +
+			"QKBAh9/WgM+UT6bTATBgNVHSMEDDAKgAgU3DejWRzheTANBgkqhkiG9w0BAQUFAAOBgQDR" +
+			"I6PKUGg876/fSljtqxXCR4CoGAAurNFOcM4EWeoc6ZvuDOi3P7rNYiYAXXlmp7epOAgvZP" +
+			"EV4vS16ODaJO6qIMR1YsaGEPo0ecT2pEStvP37X6pb5TdyjyKYF3586IN6TJdFMFsW/Lqg" +
+			"tucl9bGlWmfTVwxTexq6+D8diK48KQ==";
+		public readonly string[] TEST_12_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_03_04_crt,
+			Intermediate_CRL_CP_03_04_crl,
+			End_Certificate_CP_03_04_crt
+		};
+
+		/*
+		 *  test13
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_04_01_crt =
+			"MIIClTCCAf6gAwIBAgIBGTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA0LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC5UJ+KMj8tAmzr3OGYL2gSFcNTf8ik+ZVxlaPVGHyS" +
+			"KjYQBAEbefhfg5Ps2aIuqBwYkbtFXuHif5GEhgObA4InCyESeRjYLGcVMqwSZzAOFAR0dP" +
+			"1LzgzQs3ZgG9JX5MO5wEZ8IMnVN4Otu4XIlWSgIpUNS2vyet8Zi7t9fX+JewIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIOZvfph4Uu9YwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAXMyscmGpKSLG3hQltMQLegy0+g5wzgOrbFOWxZmiVNR+zSsHDD3UAH" +
+			"H4SyTozlooC0jAY4yAhZ5RX6SSJKx9fHsOZD9ldCmst14qLk3pkI+M0QiPBZkVTx5/7dR2" +
+			"wGkuNKSVWH6woOq7BbEzpO7xMlrUr6tgHt4Dc6Evt1pVZls=";
+		public const string Intermediate_CRL_CP_04_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wNC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIOZvfph4Uu9YwDQYJKoZIhvcNAQEFBQADgYEAe79z" +
+			"iEUgP/mvouJ9ufit1y4SjnHQWik75W65eGn/XGArRrBqJ8jZVJE4/rpDBbzm2V0hQoWU8z" +
+			"zchZFlesUyqQZ9KUlT0YGR0YPcNw/V+58RonWWfmU3M2DvWDrXgCOXPm61+AYq4+kTowsG" +
+			"0stmeML6NxjDzWpfAgI/MpXqe80=";
+		public const string End_Certificate_CP_04_01_crt =
+			"MIIChjCCAe+gAwIBAgIBGjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC45OS45OTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDQuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPiAZKXPjK8jvaNj34VynyKPK7dQtFysBPKFW5Y1" +
+			"Bc+OMsyd2pPpQoJYcQTMMomlAqoBvSXUJCMNly/BxVuvn7l6I9crtx6PjBBUlEzdcsscaa" +
+			"EaHuCCVl+Msnr66cSV3GqVGAhujun81+lyurcTEog3ftsohwbQnfA76qNU/N3/AgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIJZPDbf2xNv8wEwYDVR0jBAwwCoAIOZvfph4Uu9YwDQYJKoZIhvcNAQEFBQADgYEAZf4L" +
+			"1RDHDXwwA2CgcIhM4CAfZ72CR2zOan0at38VVFB3u9vs4VLwFcrOQCIjDbdLijc0XWLima" +
+			"4vCD1qrsv6Hk5+6113HfFNmD8mp6X5jAwoNPa/I4kmFOA8iIm4TTk7M75vQyCQTPG0VzbU" +
+			"Nu3uwTbXKm5ME9C5MFMf7z347CM=";
+		public readonly string[] TEST_13_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_04_01_crt,
+			Intermediate_CRL_CP_04_01_crl,
+			End_Certificate_CP_04_01_crt
+		};
+
+		/*
+		 *  test14
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_04_02_crt =
+			"MIIClTCCAf6gAwIBAgIBGzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA0LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCteErspc5ekSOel/wmjn/XQ0HUy4XzxB5Zj0nGn9FD" +
+			"PbjF2LERCHOn5aBnIMHYhyr7PDynwbvSx2egzGC6wGe9Zrri1MteirQ9Ppw7062IIleloy" +
+			"UAiuwvD+s0npKsvboarQsCMfOB1hOB1tGG1bjXP6B5B187SZXuR3KawggyJwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIUjnGp96itUMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAR6fmN+9p5AWy/asEAiVBnbY9q7EQXyB8WuZK9FtFmupe3hlfcTq84E" +
+			"A+TGvXOlNr05/1iLRv82GsWXDif7DlGVPN8CS1+0kb5Ve8Pmv2ziiWVREqWx916ioPjDRp" +
+			"wvdGcCNC26+fyvv5TrP8uzojurl1ZlVRRqi2sIbopVX5r8w=";
+		public const string Intermediate_CRL_CP_04_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wNC4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUjnGp96itUMwDQYJKoZIhvcNAQEFBQADgYEAZkXJ" +
+			"aJG4QDE02wFURwaxWuv2VyD7m+N/2B0/9KR+6UKVpsMd2XHq+G3SlFOa6dA/fHUdhtUs2D" +
+			"gpx3SfQYbcgKFrryZHqJDK230eP3F41S9g5XJTRaNR5iZvxvh4bmSf4l6a5MXsKEoBoJoT" +
+			"j8cU4qg6j7Xk4NpIR1JbWiSIYQc=";
+		public const string End_Certificate_CP_04_02_crt =
+			"MIIChjCCAe+gAwIBAgIBHDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MRAwDgYDVQQLEwdUZXN0aW5nMQwwCgYDVQQLEwNEb0Qx" +
+			"FTATBgNVBAMTDENBMS1DUC4wNC4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDQuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALM7mfq+hpLfvQdqZUJfIx/2gFcgHS2AsgZn0An+" +
+			"Yn61WtG8K2+lt/a8aypa/q+J93RVkRYKWKFQcJHiRgx7DMlXElVnfQbSFuLX46ng4hqmQL" +
+			"sSOKmXDld2BlyMZ41B3rfdhJT8P12RMR6uAwvc9CH3b0UTcsc498Kj+JeaRbzxAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIo7S64S6t5nswEwYDVR0jBAwwCoAIUjnGp96itUMwDQYJKoZIhvcNAQEFBQADgYEApNT5" +
+			"Y+9Jc28m5Qwjm+/8SKk83iCPnIW3BsAvQUB9Wmd1+kMZvqLySQjm1tBBbcGYuSERMJ2Et5" +
+			"eoTdL9B6EG2CZYnPqu1vk0TVugRxs7IJm4h5z4MCInf2g1KTt0AMEasQW6ZTj7DIkkU48Z" +
+			"EKLPoBGXfD9t9Y9cmdj1e1RQbog=";
+		public readonly string[] TEST_14_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_04_02_crt,
+			Intermediate_CRL_CP_04_02_crl,
+			End_Certificate_CP_04_02_crt
+		};
+
+		/*
+		 *  test15
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_04_03_crt =
+			"MIICmzCCAgSgAwIBAgIBHTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGQxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEbMBkGA1UEAxMSICBDQTEgLSAgIENQLjA0LjAzMI" +
+			"GfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD11QBcw4P2rTUfPmbVNYqdo0AMmcB3Yxsx" +
+			"Iz5me/S1I2PJLtRh9KP7lUV20SMEFsFKtE1C+9O7ODtOUCJA/6ECeXbyj20SbG1E2oQrZe" +
+			"gkcn7IQDUgnuedzdFj4kTevok6ao9hycg+qeZrL6oeBD2XQCd9nqMmzhihNu/QOSnp5wID" +
+			"AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMA" +
+			"sGCWCGSAFlAwEwATARBgNVHQ4ECgQInx+ELo31rJMwEwYDVR0jBAwwCoAIq5rr+cLnVI8w" +
+			"DQYJKoZIhvcNAQEFBQADgYEAriYMoRDpSPI4HWrxN1rjqWIzggz8p1wpbEFgK5o/Fi2KT3" +
+			"jCd6bfCcIFDpoXNqlsc+dvzc4XB1Eg/Qbcror8HP8LSxrbFw/y7VhC+wCaDCmhcqQn3rp/" +
+			"WaOWnR7/H7HlKM9m1u7MBtwlxHINnLKwPHIA1XwmAnItAXIL2yHRJhU=";
+		public const string Intermediate_CRL_CP_04_03_crl =
+			"MIIBUTCBuwIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxGzAZBgNV" +
+			"BAMTEiAgQ0ExIC0gICBDUC4wNC4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWq" +
+			"AjMCEwCgYDVR0UBAMCAQEwEwYDVR0jBAwwCoAInx+ELo31rJMwDQYJKoZIhvcNAQEFBQAD" +
+			"gYEAvJgOX6tewnRbC9Ch+Fe4KjkB9IAhe5anQKGfnDHuLfga6JEjOzyfhonWZeppJwvYpl" +
+			"1rZbsKICNphMDkd/eaWnn8Q9w02ah4kzIb0LuzrNBrxpFv9AAidfGU2VeF0gRi02jtAZsh" +
+			"gUNbrdC+ovA8mAsBigy+HMzCi61+wrumwvo=";
+		public const string End_Certificate_CP_04_03_crt =
+			"MIICijCCAfOgAwIBAgIBHjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"GTAXBgNVBAMTEGNhMSAtIENQLjA0LjAzICAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMT" +
+			"IwMTAwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYD" +
+			"VQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLUNQLjA0LjAzMI" +
+			"GfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2Rd0VKnTIrME7hzpnpIPGXGXZCjpf5lSO" +
+			"19zvB3WdZumLGdwUBXpIQTrl5teYgL62PpOwNC93URZDEUt+rqoqvs8E7MpF3IulStp2+H" +
+			"/xa6Ihf4OmkgKjpHNTWOIFXeRJ4sVgWuH6cqQ+6GL+0fa1sed1crsEgTTAGYNhFi6ebwID" +
+			"AQABo1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR" +
+			"0OBAoECBNwCFdDgPCqMBMGA1UdIwQMMAqACJ8fhC6N9ayTMA0GCSqGSIb3DQEBBQUAA4GB" +
+			"ABAjSPg794yiVz9RqdNxic8TGnApNrZui/vwr1U8ZkETZfx8W1fWgQ0z7KjryML5IOmvps" +
+			"zycM7by6jb2kMmxI1SQCwjiNQ1fb1osrNAj2bRfpp2YgjjbHx1XkddommtVc0V8kvyQBcb" +
+			"7NdxfbwKr8AtpiWTWIajc2uqUlELsLzr";
+		public readonly string[] TEST_15_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_04_03_crt,
+			Intermediate_CRL_CP_04_03_crl,
+			End_Certificate_CP_04_03_crt
+		};
+
+		/*
+		 *  test16
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_04_04_crt =
+			"MIIClzCCAgCgAwIBAgIBHzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOQ0ExIC0gQ1AuMDQuMDQwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOFf5hr4R8IqTp53qQSiBEjOFQ3Q3ICcafl+FLzm" +
+			"K3xIFqERjyXARsTM4gDQ9yntFeNp2TiIi98xBrz7D8TlrbTAmxO/PUfAQ68tXpz9Id/XrU" +
+			"WeAKxMZULPL9nPFcGQoh0qq3JKpFRSb3Iobryfysblm7cCDDCJOI7uK14XZtTFAgMBAAGj" +
+			"YzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBYGA1UdIAQPMA0wCwYJYI" +
+			"ZIAWUDATABMBEGA1UdDgQKBAjior7qCuLBljATBgNVHSMEDDAKgAirmuv5wudUjzANBgkq" +
+			"hkiG9w0BAQUFAAOBgQBhh55gTy5htqjxW1Ch2hRrRikhBH7LJz1PmDuzwiIOtnWL+EiQOY" +
+			"T6h3NV1j8Kn5S4KhUOrhnvrPXRi22HdqRzEPl7y/wXm6G0XcgYlyy2ofZKdYVWCVStKAMW" +
+			"5SwV2wC5RPK2KphdhnlEqss6QVRUsliDDjnf9Saiey9nzJAfNw==";
+		public const string Intermediate_CRL_CP_04_04_crl =
+			"MIIBTTCBtwIBATANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNV" +
+			"BAMTDkNBMSAtIENQLjA0LjA0Fw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMDBaoCMwIT" +
+			"AKBgNVHRQEAwIBATATBgNVHSMEDDAKgAjior7qCuLBljANBgkqhkiG9w0BAQUFAAOBgQBI" +
+			"VlXD5FnIiO8tavLJ8qo/qRhbBNgUbFBdAgAY6yVnFNP6YN4qPineYPN6NV1XdqNDrZh2Nz" +
+			"GHzX3YDo1Uv9yABVR0NvXCaMIW5/raqZp/on6bPuQLgJe9UisOPKunzehTm/NmO1RW9dwU" +
+			"37UzC0XnVHyVipDVh07DrTKBUtQJQw==";
+		public const string End_Certificate_CP_04_04_crt =
+			"MIICjTCCAfagAwIBAgIBIDANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJVUzEZMBcGA1" +
+			"UEChMQVS5TLiAgR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRswGQYDVQQDExJDQTEgICAgLSAgQ1AuMDQuMDQwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMT" +
+			"AxMTIwMTAwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQww" +
+			"CgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLUNQLjA0Lj" +
+			"A0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCegy6qOnM14CS7+enBElgh2DLtF5bn" +
+			"ah0yfA18/hbqnmUaWOWJQllyXa8QFawnvdXOOEXJm1ErIm3rDYihkbUTP+ybOBH9dprWtl" +
+			"1cSGL9CkoxwzkJRLQTu5xG72EhET3S3kwqZsmYbgy4MduGKv9VGFbv75Wr17Vo9K4Lz6QK" +
+			"vQIDAQABo1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQ" +
+			"YDVR0OBAoECEc4b3BP059HMBMGA1UdIwQMMAqACOKivuoK4sGWMA0GCSqGSIb3DQEBBQUA" +
+			"A4GBADj73jXpPLev5crwZIoXCJd/nXXp1fJzEEbByWggsR9cFHN4wnp7N6gpIxQbLQwjmo" +
+			"cLPC1pHQ3A5VHVrCbxAk6nifmSvnKFWHTBftZGpfTGkrXbURFF64T/CB4O+JXr1eBUGheN" +
+			"Q0T8L17UNgi3oBENKjASWnpjxvD2QrOnH0rb";
+		public readonly string[] TEST_16_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_04_04_crt,
+			Intermediate_CRL_CP_04_04_crl,
+			End_Certificate_CP_04_04_crt
+		};
+
+		/*
+		 *  test17
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_04_05_crt =
+			"MIIClzCCAgCgAwIBAgIBITANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOICBDQTEtQ1AuMDQuMDUwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMBsWmrcKH0J9bkI3zHthZ0S3904f3fMUSasY5qp" +
+			"7CSQ0sbXTwP947sfAPK4Dso6Bpwl0WExRCdFHd6qfY9wR+NtfuI/DkFEY8WveoqM4Vskpi" +
+			"cutWghCx14PiPY5YGFn8VvXu7wbuHp4TnHtUCMEUt3EfYO5oqm+/I8y0eTKMNHAgMBAAGj" +
+			"YzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBYGA1UdIAQPMA0wCwYJYI" +
+			"ZIAWUDATABMBEGA1UdDgQKBAjOoKlp+BfGqTATBgNVHSMEDDAKgAirmuv5wudUjzANBgkq" +
+			"hkiG9w0BAQUFAAOBgQDLhQ/RJFqMDNRonAHZ30DYyphf8do4q6ARikhhXSSa6G2G/PzbpS" +
+			"x3T+3G8ot+NnFhtf9ZWo7KfwmFEbUA/B/X2vJaJbNImkMDT1aTY5sPXtA69B3QKQVz7HST" +
+			"f5XH6DjuoV0/m1M153A4vf1Z783dOPw1MzOq19t+6tYFeELEHQ==";
+		public const string Intermediate_CRL_CP_04_05_crl =
+			"MIIBTTCBtwIBATANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNV" +
+			"BAMTDiAgQ0ExLUNQLjA0LjA1Fw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMDBaoCMwIT" +
+			"AKBgNVHRQEAwIBATATBgNVHSMEDDAKgAjOoKlp+BfGqTANBgkqhkiG9w0BAQUFAAOBgQAp" +
+			"6gLCdPQw7Hisnr1i3QbD7GybqfD6b1s10GQ3c/j59RYDe1Fk47Srs9ol/baleasWjcdt8M" +
+			"SlTc66KvK9YPFAqIdYoOW4FidpJBF/1cvSc2hGYwVsxLnXKr9CJ5Py5vBCCjovIRiLdzoL" +
+			"ZoteOKFIEHkV7V8V2OTFawxpW9hkiA==";
+		public const string End_Certificate_CP_04_05_crt =
+			"MIICiDCCAfGgAwIBAgIBIjANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FzAVBgNVBAMTDkNBMS1DUC4wNC4wNSAgMB4XDTk4MDEwMTEyMDEwMFoXDTQ4MDEwMTEyMD" +
+			"EwMFowYDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" +
+			"CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRcwFQYDVQQDEw5Vc2VyMS1DUC4wNC4wNTCBnz" +
+			"ANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwZsiUhXiFHN9dfJb0Yyy+rYtV8gx+d0+8WkW" +
+			"5C68nQgSqqk2uSTpvZbx0bpHF+s+LKppj2M2tt/AfZgVQHTsp5rO0IftZE2iLwqejj0rYU" +
+			"Poprq1PE3vVhs818ZlDS0PTUP97YxLysQjq2jS/d/9lF5pS3sMlP4Usp24gXX0vG0CAwEA" +
+			"AaNSMFAwDgYDVR0PAQH/BAQDAgXgMBYGA1UdIAQPMA0wCwYJYIZIAWUDATABMBEGA1UdDg" +
+			"QKBAjpC0ZvCXrvBTATBgNVHSMEDDAKgAjOoKlp+BfGqTANBgkqhkiG9w0BAQUFAAOBgQB7" +
+			"YwJWcx+PU1sUZUOVleoB5amHFu0GT+Hy7cRa82UJMHFkz0bmnyEV8CBNcnn0xa5iVfwe2y" +
+			"5ZKwy61DLR3MPTar9eKITL67uZag9w+1tnIf594XRbEiUzn20uxuDFX3oPoZCemtWdVanj" +
+			"2T+9TVQKfrp15+qzOCObNNRHZw29EA==";
+		public readonly string[] TEST_17_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_04_05_crt,
+			Intermediate_CRL_CP_04_05_crl,
+			End_Certificate_CP_04_05_crt
+		};
+
+		/*
+		 *  test18
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_04_06_crt =
+			"MIIClTCCAf6gAwIBAgIBIzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA0LjA2MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQD0t0dfe82Su58bJdn4dh7E3OCam1AUPTzPnt7DwT2w" +
+			"1XwD76OCUYP7SBBjsLYDDfUCb2ek96pSK4jpzyE6/4IOtfObe7OW+iBT9YAB5WeW+SmvEO" +
+			"TIX+xo13sbz6rG6j9svcOxtth98yv7mxzV/ZwTNBSO72CcfDXIIq20TVunlwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQI0AufZEn1f9AwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAbfhxuNBYizxfMZNcyiN61j+7LXZZo3SmMU21UmOhPBTmdTbIkuVCI+" +
+			"F1jSWdu3eGShVNJ3jmkidDvojMm+E8ZZ1YGHYfgeG16dDQudaGUjGmOfYzzlkFmsaf0paG" +
+			"4y4sBerPsZCmhN7BanGh3qYPFvadSmp3OapGfEmDtS+BbVQ=";
+		public const string Intermediate_CRL_CP_04_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wNC4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI0AufZEn1f9AwDQYJKoZIhvcNAQEFBQADgYEAIAI7" +
+			"W6K69twJZnHx6CoIMs5+P9DrJ2yKHptmntlOCTSJirC/xdj0Zv2k5FW84VrTtdCSZDT1Ce" +
+			"4Dh69fT2sUUexJb/4IcDtzloiuASSJzKWCeVIj9A8e6+coNUJVKtRKRX8bHJ5Un7xpFrY6" +
+			"t1hdxt8gUecAAdXEFGuZ3QEHHN0=";
+		public const string End_Certificate_CP_04_06_crt =
+			"MIIChjCCAe+gAwIBAgIBJDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPdS5zLiBHT1ZFUk5NRU5UMQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1RFU1RJTkcx" +
+			"FTATBgNVBAMTDGNhMS1DUC4wNC4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDQuMDYwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKq8rAPXsu1RVm3vT7od7CDLn8k/C3x3wvfzoWrm" +
+			"W0cmlhp9xRy5a3HWiJATD8yCKY1psBgnrOpv37sdtUX4P2kf668HrYOaGo365fKPeT5Wjm" +
+			"gp0pL3sXKNNsCuJPd3wKAXGHAi1R9arZFYPsKJlfQl1774dwAvzxSOMr5+pbnzAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QI33MEYdo5YX4wEwYDVR0jBAwwCoAI0AufZEn1f9AwDQYJKoZIhvcNAQEFBQADgYEAo8Ge" +
+			"ADBoJFEIRzdO37uasuyIBhClTUgyFhEKemMBN6aelYeiJMX6FZIL3DgZOce4dg7Zg3Ak/w" +
+			"B5m8XlGQLW9xIbpEzY/Iq9kr+qK6k9YmvtcOiHFbnudCFNZngTQZpxjiDaj4eA48uqKIxs" +
+			"51taC5gOv9LYWPnugN8TsUUFZ1s=";
+		public readonly string[] TEST_18_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_04_06_crt,
+			Intermediate_CRL_CP_04_06_crl,
+			End_Certificate_CP_04_06_crt
+		};
+
+		/*
+		 *  test19
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_05_01_crt =
+			"MIIClTCCAf6gAwIBAgIBJTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA1LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCshocJtyGsxeEd2ouVTVKp+HuhDjnDk9eXtaLQIKaB" +
+			"7aTODHYbq1mC+1LO5DmRV5PBVd8NuuCA+1DmzFrfYl+nMCjjgOkC0//Gf9O85Hi/n21q0T" +
+			"F+oVa1j9fc7nAgLIziexaXrflYSbaeNWkwHHftGUninKPuNGM2re0krEeurQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIaUi/P20o4LcwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAWBLeJl4qlAPKxmBM5QZ2JYsbCV3VBeYGAKQ+4L7ehS63VQMCwIjBCI" +
+			"LaHGIFfCqecDNd6cpYIArdx4tY7X2/Zxm3j5ocngpI1Tv8zydQcFeraILglsHf2UZUuK/N" +
+			"6jKGjwL68C8YwmA+u6ZhcQFD2Xg4wSMC/xxzAs9zEAQGBPo=";
+		public const string End_Certificate_CP_05_01_crt =
+			"MIIChjCCAe+gAwIBAgIBJjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wNS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDUuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO9ODA12Fky/Md5AELkaOvOwB31UlfZq3SHAOvs0" +
+			"Y4NYoA7Q5KDIwW8RNzMSKD30z51VlgOAaBVR6HLo6rkcWB4wGiV7EPelewdSOdk72IrnYR" +
+			"npJEm2KEuLkHB+gejgk+paw8CejxMsrvT6loN8Pz0btBKxWaCfknTIyXVyQsolAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QI5LtSKs/inGMwEwYDVR0jBAwwCoAIaUi/P20o4LcwDQYJKoZIhvcNAQEFBQADgYEAOMrC" +
+			"38uzHckKMkiawXhPUHtDQfyR7bLweS2qro7GyndfxPpeMJwjzVxqvQBtMuHON+al8jyXpy" +
+			"BsEryV6qvdFC1vczLzJHAJZmLe5np27zQIXOObsyYcOG+aPq727/pKoD90DAlBvrxNW0ox" +
+			"x7citflEYpmOEv9Do5xiO3MuCFw=";
+		public readonly string[] TEST_19_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_05_01_crt,
+			End_Certificate_CP_05_01_crt
+		};
+
+		/*
+		 *  test20
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_06_01_crt =
+			"MIIClTCCAf6gAwIBAgIBJzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA2LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDI4MXZB08BfUHxo//4Re7Ax0qWkHgy6nb+/XaLQ2Fw" +
+			"Pbvpb5mkhLhqDZBSX3KQL0YiJ8p81tmdvRQH/LbFzX/3OKBTUfV5imYy979A2NEb4otFp6" +
+			"EDSskZhttY3d2IzUICoCWUXhObnmkHJ2jEc81bggFkK5Lir1m/tKq2IOPFJQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQICIAmlz6+Cc0wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEA0ZvIG2cnk32p6uxqGw8Bu40NrfHu9gNkJL5MhDHJXA6OxU5BX5bWZp" +
+			"LnKXLoHiqSdtEdmy5cLZw3kggxndxjsnRFMyCawaYupJBhlgquFbuvBtA8rMtkc5H4zudP" +
+			"ZcOcvXu7Xw58K+1caSGURL+A6uXFPnMUBd1+k+ejbtO8Pto=";
+		public const string Intermediate_CRL_CP_06_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAICIAmlz6+Cc0wDQYJKoZIhvcNAQEFBQADgYEAbkJe" +
+			"jfc1rztCbtC6xJZ3iZEDDMW2CxFvOvSwhmCjPqVY3lrCPNSQzdjmqepioCnu7ongP+HAA7" +
+			"hM7bm+SoN7KzXKufQ7C2ONoAwvoPZgnoidg7RVECxUByD6AJu04yd2wCLYRpCfS2tDtXLh" +
+			"HEDpe+ELwv35pbkCMlCO2u7J+Tc=";
+		public const string End_Certificate_CP_06_01_crt =
+			"MIIChjCCAe+gAwIBAgIBKDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDYuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOh7lUwMRet7t/ABI6mo27CsnRzQ64Xx7f1dqxrJ" +
+			"NuuSRslVShaWnwiGHjc+5/TS7Urfj9VO0dseBCzPsyYFoIX1q7Q5zlArwy24qpXTGMmlpE" +
+			"GByzi7jkXO8w5+wqh3+8RFrQQzr71zLtAVV/qPUyleuF8M8jzkwfPvawunmwdLAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIayC0PPU9zyswEwYDVR0jBAwwCoAICIAmlz6+Cc0wDQYJKoZIhvcNAQEFBQADgYEAPz7b" +
+			"UvaEV7Myjhe8LJO/soj84X71rvVPtBPrhYjWTJ6p69GCfJRyho3vAUIt8RFal1GFb72c45" +
+			"DQGkcVzLLJw8cDP3ajtWac5HZ9dNPJkW+Kh12l9gqjn061XAjQ4XnbbwQDYCuXhguPE9v3" +
+			"kzDbimwVwIEOB/4SARX37y7TUWk=";
+		public readonly string[] TEST_20_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_06_01_crt,
+			Intermediate_CRL_CP_06_01_crl,
+			End_Certificate_CP_06_01_crt
+		};
+
+		/*
+		 *  test21
+		 *
+		 */
+		public const string Intermediate_Certificate_CP_06_02_crt =
+			"MIIClTCCAf6gAwIBAgIBKTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA2LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC/IejV3DmeaLW8OwMfAGyr5+8NOxM1C+UBYslbOfWj" +
+			"KUGdhlX6TxFc5AOJVJBpS/QjeA+RWoUCxnxKb9QSlOrBmADrcnGz8zV0/c0JDLaU3oSgsV" +
+			"EWZE0SexBVWrKcl1j7wN0RuxMeAp342/YoyvBwea3VeqJkmSCc7Y2TjruWEQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIaHxWOdHsLbUwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAuzeq/lqp0qs62krK6EA81Silhy42l/KmynE3mVu9GPBgQS0BUDi7+r" +
+			"QQ+m0UxYElzj2SNO4J5aBYeC98lVJFCHX7QE8yVOoPBQd5rA+rrz4HD9QoP7glxTqLU6Tc" +
+			"9VFd+iaFpqsVtSh2bxH2BtUB2ARgebTklaNl5VPbu0+yc2I=";
+		public const string Intermediate_CRL_CP_06_02_crl =
+			"MIIBbzCB2QIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1DUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAiMCACAS" +
+			"oXDTk5MDEwMTEyMDAwMFowDDAKBgNVHRUEAwoBAaAjMCEwCgYDVR0UBAMCAQEwEwYDVR0j" +
+			"BAwwCoAIaHxWOdHsLbUwDQYJKoZIhvcNAQEFBQADgYEAYGaAzVoUdlSZ3uGKiRPfHAFIoK" +
+			"T79hNOvtOxaGA0aIek9OypDrDqYAh/s2jsXSheL0pr/v9WRIHvtCt7ytXDxVyn4Nxjpfv7" +
+			"BkAMMiccdUx1OH1VElTRkmmtMe7ROzUeHUGzXJNPex1Bc9BvSChH18bWYckyOZdYJBjctC" +
+			"KJFgw=";
+		public const string End_Certificate_CP_06_02_crt =
+			"MIIChjCCAe+gAwIBAgIBKjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1DUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDYuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK4D9H8JxeIrFuOmx0cSkIYNS0p7cDSBlcc57Na3" +
+			"+1k7lJD7mE9ZP6/47YsDVK2bwe4aTKCTXtPk/kGQ6bsLswJXbyW4k4+f5LeAYoXgbmZXjA" +
+			"WF+BKIl8uKetsqC3HkCeqhBaY1AGUqef4oOAkakEP+1jYFumNYtMaB+9x/0ncBAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIC9MiJNI71RMwEwYDVR0jBAwwCoAIaHxWOdHsLbUwDQYJKoZIhvcNAQEFBQADgYEAo/ib" +
+			"mIxteityjZlszjCc/s7yM/0snL78pYpMOZ3P2TPKkYh2Th4+Bw8JqX10+M/zwFBj5Bw7Im" +
+			"zCIRfS3GFuKmcVcyHB4OZLMcQZtXWA8GOZ94YvWq5TBINlVtThQtusQj15KBq2TJNNFUyD" +
+			"pBdvyo05AnEsRY0HbIQu6ZhNQ40=";
+		public readonly string[] TEST_21_DATA = new string[]
+		{
+			Intermediate_Certificate_CP_06_02_crt,
+			Intermediate_CRL_CP_06_02_crl,
+			End_Certificate_CP_06_02_crt
+		};
+
+		/*
+		 *  test22
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_01_01_crt =
+			"MIIChDCCAe2gAwIBAgIBKzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAxLjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDDOu1J/VIzbB4VcS2Dwf2fsHOmIj3iatM8y61V7CrN" +
+			"RCxCWTJ1Os8e/mFWOi/zN+0afizA0UzJDTe8L++/RlP68IFg5Ju2OhXqQC3HbUZmQ7ve9g" +
+			"QdWTfur3oEJV6/XoVE4WG0Ic7D1p7BENb3LUT+8MJdSboTvAggA1CiOI6zRQIDAQABo1Iw" +
+			"UDAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBAoECP" +
+			"RyRiSV+4XrMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqGSIb3DQEBBQUAA4GBAJlmJ9EW" +
+			"9ujUosqHZyZkniu2vX8VOL52OnxtLxw3LqxLyuxivjyYCaMAaJNr7/xfm3C2ozh9mQyZTQ" +
+			"6TpBapLFUH8QsEKUhy57MDUgIvZsyOvvjJh3AXfSkXDaMZ3ncLg6x0wwjN/Hxu9i+IhX1W" +
+			"1E7/5foGx7AEVfwY7Fo9S82d";
+		public const string Intermediate_CRL_IC_01_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI9HJGJJX7heswDQYJKoZIhvcNAQEFBQADgYEAV4DM" +
+			"F5gU8MZ6E/mnjAWS+dIRKUBJV1GZJ+hOysdbmK1hD0mj5Pd5qTzlcvLjuatIoIsB5DCpYd" +
+			"AcNRLVvF5EJFhVjqsPzRlfUZth0Xqa+U/DeHjVxHxYsLEOSt+v2bLkbGh88SmOAk6F8xj1" +
+			"l7YIfPX5cIkUBTVZlsUt51slMXc=";
+		public const string End_Certificate_IC_01_01_crt =
+			"MIIChjCCAe+gAwIBAgIBLDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wMS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDEuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPrk1fosBu0hemIKgTDCeV/RoFbbsm02X4LfZonX" +
+			"KeGRGYZXz4tpWgbNpjKBq1e/2bOO1DCn9I8I2kjvZdOkabk4MLeuRDo/sqlNndu4Ar5502" +
+			"pAo4A2V0QLR4IDHAJoDpxtSFrqELOiiyCx9O9V19ywe5pcBFrxVEWDqTnBUeDJAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIbI6BhABrmQ8wEwYDVR0jBAwwCoAI9HJGJJX7heswDQYJKoZIhvcNAQEFBQADgYEAYzYy" +
+			"M0wbzNhZftAWz7TfFi64uA9WmTmd4MeK9vga4ChswT4H1zlaV1Sr+3hqpGmOoP5AUd9XIq" +
+			"O/ui+/gFaeuOLI+ATmK+V2KHGAneMwzcw9qbXRc+xZqGGjbXMb3Bowe3qrj3mhyowfa1n7" +
+			"x5xB7XEOqO6sfWxLdDjLVo4sn88=";
+		public readonly string[] TEST_22_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_01_01_crt,
+			Intermediate_CRL_IC_01_01_crl,
+			End_Certificate_IC_01_01_crt
+		};
+
+		/*
+		 *  test23
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_02_01_crt =
+			"MIICkjCCAfugAwIBAgIBLTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDemJgZnOzXOwNGqRA3Xq9aMrAWQU4oFuhSELsEYfLZ" +
+			"GO3ntBjJLqCn+rs3FjR9N94cu63TduOAgqlXqrNbvyO1+SF9m35JXreqn/OS6KrK6c8W2I" +
+			"pDAWJcr89nGyyCXMoJeaOOtj8m2NjZblmCZvtAl5UMOew73GE7Z5fE+jtA2wIDAQABo2Aw" +
+			"XjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" +
+			"EwATARBgNVHQ4ECgQIhT9GjaaHj68wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" +
+			"AQEFBQADgYEAWhKJUujLapxpz/DoD/w48HMzkL6UQCxQPOAjwwHicX8wFcKmcrWLVBdVC3" +
+			"0+ywrzMraWhaq+QCOqsgtxCwTZrfUxbCNqhKS0lZijCMgNN4Jht+PAZ22tzEsw7nCwiMM2" +
+			"n1jeKF/3btoDEUvZn9SuzhkIyxy7Q8l2tbNOsANqpxE=";
+		public const string Intermediate_CRL_IC_02_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhT9GjaaHj68wDQYJKoZIhvcNAQEFBQADgYEAJsjf" +
+			"oS3F1KMpcVBOC1Z6P5N20TYLCCHG6KETlBA3Rjf8ehNxJKJW0lGd7qHpVHp4BGvkSfaOAa" +
+			"OrC0G59wjDEY+Ci4QS46OYzBcHXMFX5HF2xMq+y5SfQnyV6MQUVVkxJRjgsTLrYwP2JaYm" +
+			"BK/zExhqQgPfgcR+56swBPXqogo=";
+		public const string End_Certificate_IC_02_01_crt =
+			"MIIChjCCAe+gAwIBAgIBLjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wMi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANbTVeAxOibAO3KGqxxY3VqKXDr9tKJN+igpKb4w" +
+			"goR0ZnWGDusSVm4pvneZ9qfmi8A0sM0E91+B2hAwsU6Y9RoA7nPsTkFYi5F+hHGIF46Op6" +
+			"8blGrZraGf9bsWXCZFoLoxcgltwjGPQqyZ5mnnm8cxUbtaWmgo28MK1yBH/sS5AgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QI3gkBNo/SISMwEwYDVR0jBAwwCoAIhT9GjaaHj68wDQYJKoZIhvcNAQEFBQADgYEAQGl1" +
+			"7uT2xxYDks6HolrQIpesIoPqEiZ8TkizEBuLG3sUKsC7klHwy2iyVvA6nRUDwf/XzDLpGW" +
+			"/Gn0KTW6ZYIX6snOC1+7HX5OJglQx8tDpDvcAgyocK8PvCrHfu9o33J49aSeLAVpoCHwne" +
+			"tTtJxVfTMmjYWKeDbHHHi8a2YTI=";
+		public readonly string[] TEST_23_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_02_01_crt,
+			Intermediate_CRL_IC_02_01_crl,
+			End_Certificate_IC_02_01_crt
+		};
+
+		/*
+		 *  test24
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_02_02_crt =
+			"MIIClTCCAf6gAwIBAgIBLzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDoeA32BPwgq8pLJoR/tbOSjHtAz6fmzvzJrhJMvl64" +
+			"ccVuIzGxzOneYsO/ZYWy3ZGtlCoMZJRnS83tw0ikU9vQUwBw7DEcfRlLKYkY68rp25N1V5" +
+			"JEjnlHw+RvubdGkonWzUNJFbY1GA24J3no2GZHiLPgWmGb1jsA8Ag32MUrCQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIKx4Ybzu2PaYwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAotGeNFzmktvcxpCRcpuARHkv1lW+LegvbDBnSPvGnr1+Cn9rZcuLup" +
+			"u8ex6VJ7KWtgWBtzdOelerO6ytfWQ67uNpTOuc0SDdk/f3tCagdx44LBVQywuq/Kj57ZuN" +
+			"jpe4J8UPZSBFFK+P3gTX3S/lIKsDi6xjRnqFLSQYGX2XiIE=";
+		public const string Intermediate_CRL_IC_02_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wMi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIKx4Ybzu2PaYwDQYJKoZIhvcNAQEFBQADgYEAOfuX" +
+			"wRv4skbPZAbOH/LVXdc/cA7vCSTAnWecN3ZKm/eCsxbyRxqn7fcDyHmqg5H3Ac5UOlMHR4" +
+			"FMe0Dp+Yu4Xg8xg3zRvE/3M/5jyRILGGi7olh4ikkOMD+UlreysvYvUX2MVP1iM9qAkXh8" +
+			"E8n/LZIlABN2GGkFEMRMJA6KTXg=";
+		public const string End_Certificate_IC_02_02_crt =
+			"MIIChjCCAe+gAwIBAgIBMDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wMi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKogqWGx9EpJ/0G7ORopyIQ4IZXYKKTE48WqOJbu" +
+			"nLD3txGjMUb5Xefl/QyTfd6J758ddGzPiKs1zWO6riffJLIBoOFDmt8tchPBJuIM3gKgXe" +
+			"VcZMyF5mebm5/GZekMOjbs8P/zbLdrlu1D9CZWZMXONYitdluSg2moMGbewS2NAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIP8N7OmNGshEwEwYDVR0jBAwwCoAIKx4Ybzu2PaYwDQYJKoZIhvcNAQEFBQADgYEAwkpF" +
+			"j6Kv+OcKrUtOgnH9QddB0Ej0oU6B5/5Hhhf3liAPKtllDHnhUj6nqfh4APNq/iqYFOkKMR" +
+			"RUZoaj6kakJNSOlgvRIiQfuFIgv3CqLZnhr85YFRnKgoluZE1pq3TvunoiKyJbCjbmyCos" +
+			"Rd32gVcJq024xvY2eVBTl6tfn5A=";
+		public readonly string[] TEST_24_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_02_02_crt,
+			Intermediate_CRL_IC_02_02_crl,
+			End_Certificate_IC_02_02_crt
+		};
+
+		/*
+		 *  test25
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_02_03_crt =
+			"MIICjzCCAfigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC7LFt+yGItQFqSEPi03ICIr5ydWnFPQHZdEMNu2tRU" +
+			"3XiOpfam1wl0xgAPGBkQK768OfidpP/i1hgYOU/isOB5dyALscvIQ9XJG1OWQXBBLgKuCb" +
+			"MS5fuDhBNa4KiFuGMbJ3/UjluRsD9qaXwGUavc436JwbRHvW8FomaBYYY1hQIDAQABo10w" +
+			"WzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAwEwAT" +
+			"ARBgNVHQ4ECgQIPsBg9tMABhAwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEF" +
+			"BQADgYEANZcayTTX+FGhtRUJ+XuYA7jR14CJL6qTHPvdSMgHNw9mGXI/7sO5I4v1vayOCI" +
+			"YQ9luBvrTYlMPmuej8+bhM8YTYpiiOjVFANwvSKArI9U2CAGBcoBMXydykkm8qYw4gtYQT" +
+			"neiOz7VqI9plLWA111IRMgayD3CAt4Ntpzd1VSE=";
+		public const string Intermediate_CRL_IC_02_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wMi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIPsBg9tMABhAwDQYJKoZIhvcNAQEFBQADgYEAVeQi" +
+			"tT1FRUaJlhfpkfjZr6VHmvGnqYapdo4DRT/pm8tsp1LbZZXpYW638ztwgZNgeBRPFlcb+x" +
+			"8naQjEkoaYzLbCYfdY+PPVDv7ym15PE48Kve8ImvANY0YnTGS8pcKdK1dpNKBnYYMOG9JN" +
+			"+H5K/4cSm/WMCKIuKdsiAWFYauE=";
+		public const string End_Certificate_IC_02_03_crt =
+			"MIIChjCCAe+gAwIBAgIBMjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wMi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALGbo9yEujZ9RFU+Vmxb5+Rx1VdIG/3E/5hXV/xI" +
+			"OFu4mEfYh2tBhP2qIMH2KbrR1tiW5t4DvTCBM3NKKqp75wpiuu7E3q6imt1pLbGW13NVL+" +
+			"81gYWXnCnzHpxYjMTIqqCkPIAeOG+SBJ1MgERbL+NBl+AK3WG4TeQ8vw7r2CGrAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIS/HbII+ki/kwEwYDVR0jBAwwCoAIPsBg9tMABhAwDQYJKoZIhvcNAQEFBQADgYEAWHy4" +
+			"sHrTkqY1XjDBY5XpNEyhP6htcnjYD9bos4wjxPlJUyxdIWACWrLDE+R5iRCOYsh/nDAJEt" +
+			"CUcVASukvP6VLJaFjyxUOaCp6JCVV+txk7Fh0S/Ur3Zyysfp5LllP1plOA3N/k1Hliljp0" +
+			"+bnSiDhA1+3hJh0gDMjWUdRq9yM=";
+		public readonly string[] TEST_25_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_02_03_crt,
+			Intermediate_CRL_IC_02_03_crl,
+			End_Certificate_IC_02_03_crt
+		};
+
+		/*
+		 *  test26
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_02_04_crt =
+			"MIICkjCCAfugAwIBAgIBMzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDf5u5ouGQlQmdNfc4ell3RXKWmtq+ar9VKMme3kp8D" +
+			"cbDbUaVwlvhWTkOKxb9I208wfGG2nQiArezIwutlASf7sWo16EPapmGdCF+rp1dpjAPBUu" +
+			"fruEyCZ8nu2ITD52wuPY9OAcKHQE2/bBpCJWkw97fYX6Q9PPW5uobWoUJtOwIDAQABo2Aw" +
+			"XjAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" +
+			"EwATARBgNVHQ4ECgQIjDm8K5YcGakwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" +
+			"AQEFBQADgYEAEQIJeZj/HE3HvjjJV7PdU+2Ze8OeCYeeWDocxrA647xpeOksVXBXKmq2OV" +
+			"NqoFk7YNtlSUqiS2TlqjGqLtKYetk7a17qS/8EIQct+H5KWdvkLkYMkfIAAMJvJZHPGxEv" +
+			"j+oVPAi9FITRbFdN8Jvdo9MAuU2q8d2x8MF236RmEds=";
+		public const string Intermediate_CRL_IC_02_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wMi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIjDm8K5YcGakwDQYJKoZIhvcNAQEFBQADgYEAV5bX" +
+			"7WsT8sWeA0iQ7V/+ZQESDzvyHA7Ziju0iRsvTL7qOVF/Nl5v+zND+ZNPhdJDKEM/Q0lEaA" +
+			"ybe0E73NMmM1qRX1daAwE++jHukF9TMeNl750HJaS667H6jcjeRrHUJDD0+AgqrZY52dL6" +
+			"CPM3V4QSvdfc1/xtKmNIZWSSoqY=";
+		public const string End_Certificate_IC_02_04_crt =
+			"MIIChjCCAe+gAwIBAgIBNDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wMi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDQwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMW45d5dPrzUJbuRIDeQ5gIJRYxi80PxPvxSmJe8" +
+			"ScG1A+l75SAtgLGWAxBqxPSzL+teBBUsnmf2Xsc8/qQHHev74uat0lxq9YrZ3npLW2YNo2" +
+			"CfxLK0M7F1/bhkHK2f9ttIvOrrKI67BeEjfACULdJEhl431uWINWV0pY+fHq+pAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QII61NnUvgvjYwEwYDVR0jBAwwCoAIjDm8K5YcGakwDQYJKoZIhvcNAQEFBQADgYEAjwgL" +
+			"6qMnnqUvNspsDaYpPQzTCqXkqshZhsy5G/nLk621H/YbNGlnZ6asHGljYVYMzjmcny16y6" +
+			"ntiv9QPB7YorAx27WT7pQPFla96s+nM/rfwWHPWI6QGDsquPriwJm/MwQC+1oDXEFKvdIL" +
+			"0urejfd5hgiXYbRRwMI7km97iHg=";
+		public readonly string[] TEST_26_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_02_04_crt,
+			Intermediate_CRL_IC_02_04_crl,
+			End_Certificate_IC_02_04_crt
+		};
+
+		/*
+		 *  test27
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_04_01_crt =
+			"MIICjzCCAfigAwIBAgIBNTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA0LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDBtNwpr9LZBF2LRtAp9Tb1FZnfM3b/Jv2sdO5zc/Bk" +
+			"sO4ByUgY+Mux9dEvFrkVWBK110TvXn+dj+85TuboILv4MDKlu+tI/rtuadXGwwDIg8TQnz" +
+			"uyC7LWhxM5JZs1/Is+sPKUY4PTCHs3+EHPBWf2tFiP3l6ZftkySEiL6+2LSQIDAQABo10w" +
+			"WzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAwEwAT" +
+			"ARBgNVHQ4ECgQIbMuZ73onuZswEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEF" +
+			"BQADgYEAhaTSc2xafdP/QceMm9YJ/rZJ5gTgBR/SlmKQwd2BclHabG+Fozdg4delDjtRXS" +
+			"FKY3sFWBFZHVeprh4T93Oj6IVA5X4DIuUeBpprtS+psCnWZxdtcUWmbyYQwZNCifG5C5D0" +
+			"lRwxlMlv40xT2oCM1zPZpfmqemBDUPJ2OhkCjvo=";
+		public const string Intermediate_CRL_IC_04_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wNC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIbMuZ73onuZswDQYJKoZIhvcNAQEFBQADgYEAMk6D" +
+			"Rztz1AyFnFr1KAlbjLLwxtQplf2eIc//zUkDFVUHtX5TrEC/ijUaItjdkOoPGQfpnL0w8x" +
+			"wyqWndMh593QPCqIJTtv/iACoiJNZ90ZJS0adcdZ+AEmQpa0Zv0e1JOqRrPoAfTq4HrOfR" +
+			"vhBwhvKQNtTExupW/EBudznKC6Q=";
+		public const string End_Certificate_IC_04_01_crt =
+			"MIIChjCCAe+gAwIBAgIBNjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wNC4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDQuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM2dGkraKGdIi6EXxAu6/ekMqDloX5YSVBGh4Hp2" +
+			"faujr1u4j8Lp8afqjngRxFUpTqGbqH0ETgm4cVPXmc9rUvUzYTMdxTUmIZ+iW+ULZEvzNB" +
+			"712kxRPCD2kDFN2fH2ai8miXr434w+weLm8VQN4jJGo4nswhSs2w1gsUmWyn/ZAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QITsLx/sO1edwwEwYDVR0jBAwwCoAIbMuZ73onuZswDQYJKoZIhvcNAQEFBQADgYEAeKft" +
+			"0RM8/b3zQodaKrTdWiFyLg5fzoOsTecSfdFPXoqz9J5ejLVkvJevSmfXJrIUhKXySzsQi+" +
+			"GazuTh/hvWjwUTIvmupi+EiFudnMpXCro8bgi48+NkepNjXvjsSmOfzlrK3SxtpH5dqonL" +
+			"6LHjGyg+Xp0Nor1m5g1rLHyrcEk=";
+		public readonly string[] TEST_27_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_04_01_crt,
+			Intermediate_CRL_IC_04_01_crl,
+			End_Certificate_IC_04_01_crt
+		};
+
+		/*
+		 *  test28
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_05_01_crt =
+			"MIIClTCCAf6gAwIBAgIBNzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA1LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDM3aWmgX3OzAaBg6lnWjpFQ9ufeTOia3+lIUqn+Ypf" +
+			"5OH/s9dLRqg1ZynV3YIUyzaJPP/YlUEmrhheJn3Bjw25bHeIKdge73pfEbuBAugbUMS75D" +
+			"csBV7Ze9D+sVw8w/LtT3ZPcvM3Vju4d+c14Ip/8pC15jlgQPhwVQSf0x3V2QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBAjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIJ2DFtxoQnXkwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEASvdcfBOh2d1dC10pGLZLI3T+oSPCup/U9riynIR3RxZsIaS/+Q2s81" +
+			"oeg++WQV6pyYvCLneZIp0efvqh5DThNV9lhBcJjlYwm/T8Hi2IaRGsSMwIvzrFN7zxA/zu" +
+			"tW98wigAKM2myk/nlYxmholgbQkQ7ZxYM3lD1TDRl69N66Q=";
+		public const string Intermediate_CRL_IC_05_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wNS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIJ2DFtxoQnXkwDQYJKoZIhvcNAQEFBQADgYEAK7Ym" +
+			"Y9PjX5CpVewe2E9PNxj3dLYElghaQyapYoVtNq3jDqLMWspdmHdNdeaQoXsjlSJe0Zy8xH" +
+			"ZvpimwifnFZ5hq4yByzHjzNMpcA2yFtg2MtPWGEia+BmaZYZi3X0lR+OShKpNLFc4CfVM/" +
+			"aWG6W2BulHjIAThZhTg3uRekDzs=";
+		public const string End_Certificate_IC_05_01_crt =
+			"MIIChjCCAe+gAwIBAgIBODANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wNS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDUuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALlcUtceuxDznvI3pVM7YddPcBOrNvrOtpuLOa1L" +
+			"Lj9LeNH6+8CzRZnMsUtt+bRGqCKMEJLUIIstWwGg4SskXWk2m+nDKm5Ai6Kyx4nldpgtgQ" +
+			"xZSEwNcwRhpy7TtmLkxDVM9DoTbIbK0dZ7aWw4bXVHPK/lnOMtOaJbFDq0sLfxAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIiXgrRBVcDf0wEwYDVR0jBAwwCoAIJ2DFtxoQnXkwDQYJKoZIhvcNAQEFBQADgYEAhyO6" +
+			"SP6brWDDKZwdQGULno4Om5+DuilJKamyEcvSqE666z1KhvOCdLicqwVa6tQiAL6akrt5Kv" +
+			"R+TT0xqHR4JGosGLGolvK4DLrMeD+PRK7m1a+nJl44luo5Mn48HrKI7jn7n8Lp9bNdCHvr" +
+			"NHaQksCIR/Q8xoucPa+8sCTVSj4=";
+		public readonly string[] TEST_28_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_05_01_crt,
+			Intermediate_CRL_IC_05_01_crl,
+			End_Certificate_IC_05_01_crt
+		};
+
+		/*
+		 *  test29
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_05_02_crt =
+			"MIICkjCCAfugAwIBAgIBOTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA1LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCrtIYqo2Is8Cd6Ld+fyWC755oA6hQiiruooaR/6O4z" +
+			"ikyhOUztnHkOGMF5H4CKWafwwVrfFtqe7iop3N6AToEIpNlJLVy3cj14A/IASVYSSNFeHd" +
+			"O44Id1NWhPiKx3paPTWslMEdKQV9BlXb7gu8pQpvqTa/38hNQ9vdil/4QZbQIDAQABo2Aw" +
+			"XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBAjAWBgNVHSAEDzANMAsGCWCGSAFlAw" +
+			"EwATARBgNVHQ4ECgQI9P78RavuWW8wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" +
+			"AQEFBQADgYEA0sAEmWBYSazUav6RtuNFtZgNrlQ2i5i138VzRHoF/kq/CxeR/lINQqgJhC" +
+			"ZlUnlslUuM86g8OQGlR8SS0Wsi0MdCQCtPCKA2hStlTx9MMux2IZAGoyHy6P95UE9qINHE" +
+			"fYZUYjO9rh96fzNyJ5Oy2kJdJWdhFXtSh3BSOe0ZD+Y=";
+		public const string Intermediate_CRL_IC_05_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wNS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI9P78RavuWW8wDQYJKoZIhvcNAQEFBQADgYEAlPLh" +
+			"+CMqRcbLgUKEAL2UlSY5tjsF8At0hf000kec93TnBf7f1NKYVJ5eyeoh/WK4s+k4paAA5E" +
+			"/P2C8JMlGXNTrqKZXMy2zIlufE1ymXAZCKLOLC5ezXRSpwIsBWxko2nfw8Bz/mZO/bCSCT" +
+			"nDwkH8BJIbFV51vJFlyyOmZnCz4=";
+		public const string End_Certificate_IC_05_02_crt =
+			"MIIChjCCAe+gAwIBAgIBOjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wNS4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDUuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMPsWBfT8HqaiLnoUCPAFniq502odL4uVqzOOxkx" +
+			"evZtjh7NaFlRjuYjTofdkj/IAgg7lkkBEW3auK47Td3TvqnHO401PqvOFNTlbhr5wDLmXS" +
+			"WWcR6XrvgYL3Z3wx15/z6eojcSgu07kdvKqzuLzcDs+noG8lbcruokX0A186pVAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QImgomUTkzwbEwEwYDVR0jBAwwCoAI9P78RavuWW8wDQYJKoZIhvcNAQEFBQADgYEATAEq" +
+			"YVV0iYdYomPqxbTapSCJFAMQO/WZhN9brCXP88+jRfk6cAHzTodQOYTOAVe8YXa904505e" +
+			"RA11NNTViP3s/AseGWuqbWjsom9mbR+tVkvufGqPQtm1JhfLgR/68e29AI7tj7zIJyFVYD" +
+			"nLRXGwMGnosqSHDle+WYyfok6a8=";
+		public readonly string[] TEST_29_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_05_02_crt,
+			Intermediate_CRL_IC_05_02_crl,
+			End_Certificate_IC_05_02_crt
+		};
+
+		/*
+		 *  test30
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_05_03_crt =
+			"MIICkjCCAfugAwIBAgIBOzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA1LjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCajRjoRNL9HFTytLLx7C8WYouW0uONGsrtGS5tKMiW" +
+			"oLlQUkohqB2a2PhA1InNGQqnbDtNdqKbR1k6EzD6MyegvXK1sXs0ZE8gt0LZYio7Xp3k+Q" +
+			"7i4Rk5iTruAUrV8bFMYmeIXHXL/9rl5LQV8YRp/Ut3Bg3VECzfhQG4EavMlwIDAQABo2Aw" +
+			"XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" +
+			"EwATARBgNVHQ4ECgQI9041oiwvHsgwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" +
+			"AQEFBQADgYEAYwGYwLsA/kxYZG/RM+kvoH+mUebrBVZRBxjovYsYzNznD26fssjBFfiTmg" +
+			"zwZJfG7MZRsgDSRsS+bxuTlXMVeGRKH8fVj7PNq05sS18QZQOF0CCKzg9DLkCzkzkEWBxc" +
+			"5ersciPrL90UarOIPIJWUxQ/5sdMS/wZtYTU34rNNWE=";
+		public const string Intermediate_CRL_IC_05_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wNS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI9041oiwvHsgwDQYJKoZIhvcNAQEFBQADgYEAJHTp" +
+			"k+RRsD0dUv59J1GQMWjQTjVz39Xaonx2sk38WHcrHBB78L0W6Skjvt082PwZg32sb7FQBt" +
+			"boAQ3PIKpXMnFnkjnkyaFihrnMdfa0abCPtQhFl3yra+w+1a2RDjQBZOOdq3xlFcLi9unT" +
+			"YYome7eS93wchIvNWFpgwF5A5XY=";
+		public const string End_Certificate_IC_05_03_crt =
+			"MIIChjCCAe+gAwIBAgIBPDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wNS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDUuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYxdSZq7qRBdPOz6H+l0GGAtymAWTshfZZCubHK" +
+			"lQjbVq98qudORfhCOZgOy83j/mo2KAecBhxaxB9YA5ggWNAgaKtFvknvjFemtBCZwt6cVK" +
+			"8LCyUGKzStwAV1+HSDlHxdWo7pRwP0beXFvFECrX418osGt6E/v7Cz++ZtvaDhAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIgTuCLfTVa+QwEwYDVR0jBAwwCoAI9041oiwvHsgwDQYJKoZIhvcNAQEFBQADgYEAQRuC" +
+			"rAx9zzu9QwOq9weNit9PNgFHBpo3Gh9jPVYGJjOQxeSqqou503xi82H3W30FT/3ESCO7IF" +
+			"hfpr/uQZVEmUQnvDsVwbKvED1QF9qkTp6ILk38ITJJgfb+sdSL3bsUeNqVXd0C9wzVoErc" +
+			"OuoCulwkZzfoIOlO2YAjAnR1nUc=";
+		public readonly string[] TEST_30_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_05_03_crt,
+			Intermediate_CRL_IC_05_03_crl,
+			End_Certificate_IC_05_03_crt
+		};
+
+		/*
+		 *  test31
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_06_01_crt =
+			"MIIClTCCAf6gAwIBAgIBPTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA2LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDmutL9PY/BLXvXMEDQLQnWE7dCOsrLNvJiuSjDdznF" +
+			"vBz6WS/RqUr9zsDFknpOWB3Epo2syV4ZFto+v4VWNo61uaClIEsw5x1y0saG19px34KVpQ" +
+			"wkpvLeRZySdCydKdE1rptYR/JbHvPo5TU4mxOo6L7JeEwAvjSI4tK4rwJ4MwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQI1BB9j6Jyny4wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAajWMbY8zL8jS2VUjCPBMuIjUvBfy55+92EXg5pZnyNNwN1diZfJFiB" +
+			"rrPWEg3Fa4NMLgaDKWZsYkOcDDo8I+Qb9FsU9LphCzQ1ubIEuxu6KPX9X29BscFOxUnZCz" +
+			"yuzVfadACxi5Y7Bz5pN5LfC/jEb2iXjkdN5Rm8AqT81syIo=";
+		public const string Intermediate_CRL_IC_06_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI1BB9j6Jyny4wDQYJKoZIhvcNAQEFBQADgYEAxH4/" +
+			"mgACT847PyufmF1nob9TSqBj+cM5ye2bgv83gTVd3B1Gopr75Tnu4iP10d0PpSXjySWCjB" +
+			"0HPJ7BdxzkKxSrcM5vcb/jLdk9PqMUS30ohexsx1xK+E38pDJdLX4kbJ3E62AgyXm9WQlD" +
+			"9xsDk7TMXwuxHT4fX070HL6lWGI=";
+		public const string End_Certificate_IC_06_01_crt =
+			"MIIChjCCAe+gAwIBAgIBPjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDYuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO1VOl25MTf068LOgzmQOmyh8MXunBrQ4t6UYuEj" +
+			"H7v+owR9JTDXpfzLPcYfkR+BH2jjISSHIJsUDesKVhpmhABNXcOI5tiRNkeDlV2zKCBXKC" +
+			"wFi5qkhrE8FUCP0hL8YzbybOrYZYSVEP8GgIgMSQcTvhN/Tor0o1jdJvRLmevXAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIFJA9XGd9UZUwEwYDVR0jBAwwCoAI1BB9j6Jyny4wDQYJKoZIhvcNAQEFBQADgYEApRQC" +
+			"OTU9cp16BHM2n0TdZThgj9kSAQ4wHk/dKNOjYNEWu6n/GQ0alxy1dyRzpsr058FOvft23Z" +
+			"Kp0YhdKG/7F1hkcoNvC2yN+Re44n7S+F/jcEPTWnOX6h1Nkw8OS7Uz2fZ8t61iHjqjX4sv" +
+			"M/cKP+AkC8g7p2tfdkP1fQ6ww5E=";
+		public readonly string[] TEST_31_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_06_01_crt,
+			Intermediate_CRL_IC_06_01_crl,
+			End_Certificate_IC_06_01_crt
+		};
+
+		/*
+		 *  test32
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_06_02_crt =
+			"MIICkjCCAfugAwIBAgIBPzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA2LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC0JoTnPaI/HT2eAqCW1204nRNjcA8EQSp87tvHLpWy" +
+			"5aafmxeJxvk5V9Ba7Ye8eY8yX9losbNUpHJFNdE46fD5qp/oS7Cn3NXA0dwIDQEn1X9vaz" +
+			"nqtZtMjt1S/yGv2xDOb2LKT9zRrqSvxGszCHFUBcJ4HDFJMAdhXPUZiLyXVQIDAQABo2Aw" +
+			"XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwICBDAWBgNVHSAEDzANMAsGCWCGSAFlAw" +
+			"EwATARBgNVHQ4ECgQI7j2LO1CcsE4wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" +
+			"AQEFBQADgYEAfXIh0oYlM2pagAWzTuYqTl0NavtfqibPgolvhgIG/XmmjswHOg/JVCLb7O" +
+			"jIYtEG2MAD0xQXwu0mc9Deufed2embP/wc0qVG7rj7lxUq6p0aMQJNndBw4m9KlSnjdzyG" +
+			"lwE9pNd2BgEeD516J2k7dspCZHDw3qLer4i2JYoCo2Y=";
+		public const string Intermediate_CRL_IC_06_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI7j2LO1CcsE4wDQYJKoZIhvcNAQEFBQADgYEAJej7" +
+			"23qVtwkcvCTPb6afTosYMnVppPXWbtvqn0N5mAFHQfE27x1YPOXOQHBrpQuTyiUdUmPXiH" +
+			"xMKbuR5o2lfdQgew9hbYVk6GegSu+DBC1JKv2YSTgzgRAlJfyByDZ7mbJwZWHVHys08oGk" +
+			"adG6zstavg5EkEeRuAp47T+7cZc=";
+		public const string End_Certificate_IC_06_02_crt =
+			"MIIChjCCAe+gAwIBAgIBQDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDYuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMkIzl9+NRTZf/xaA8noiHRt65Zo6Zp57YvCKUe+" +
+			"YfoC8koMq12MBgrc0IyIfJoqEDEMfD1WbitZdGZMQZ7D9BP2Bk09NXLEAAuj+waFhYk0bW" +
+			"vHBH90O7HpMGmxwHmzOjDV3JHYsU8hq77/5gRFDNRkSCJe2A1Maj8Gcqi6tYf5AgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIYDfThEjNL28wEwYDVR0jBAwwCoAI7j2LO1CcsE4wDQYJKoZIhvcNAQEFBQADgYEAJiHT" +
+			"CjLGZK5Lyw+7ICDHs3eS1OGJH/wfsLcBP5sLER41qJfrXGTl2XdKvBMIpriUmJYzjkjof4" +
+			"bvS/VPDNlhI9AJadicW8LM4L3qpy7/YV4Dd/C/BJphJ6cZcT+hjaRKeC7gQVjMeC/npu/p" +
+			"jLgIgzf7HC4WYnaS3h9oYl0cMJk=";
+		public readonly string[] TEST_32_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_06_02_crt,
+			Intermediate_CRL_IC_06_02_crl,
+			End_Certificate_IC_06_02_crt
+		};
+
+		/*
+		 *  test33
+		 *
+		 */
+		public const string Intermediate_Certificate_IC_06_03_crt =
+			"MIICkjCCAfugAwIBAgIBQTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA2LjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCuUtIYFbVjg8VLLUqIEQ6r7hjTaqYVs8DJnJPHUWPA" +
+			"JW9HEIV+d6hj/so76Bff4KJRX7MgoXbvq4ivmn8656N7YSGk9GPuJ25SXK7RJyoqzG/x2R" +
+			"AVUCx/wG99VXVDZhd5ZAVBG2JCkHImsWAei6/Tz8UgXmmLBM8rZNJ/hNtTBwIDAQABo2Aw" +
+			"XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" +
+			"EwATARBgNVHQ4ECgQIpwUlwG1W+sMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" +
+			"AQEFBQADgYEAqJhUfgar10fl5qG+oH34s/JS3ku0dRm4cTQvqUNOWA9ALnBhSkmOpoMMzH" +
+			"sE9FXXcZ072a8/ecpviP04X5mt5QSLreh3hPVvgWv1LiZ9YkS4Z2kcr+3Gx7zj4gQgT5vG" +
+			"QPpbIBAtBRH5xNHIYQsk6kOe2+t7b0Q82Wnj8UoznmQ=";
+		public const string Intermediate_CRL_IC_06_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1JQy4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIpwUlwG1W+sMwDQYJKoZIhvcNAQEFBQADgYEAKCp7" +
+			"ViY1cajXpbjCIqe8yo/98SQRIxoTNgp7EUaaV17FeHZ59nJhRtsF1XnLP4cK0lPBkKFhHK" +
+			"2XyDEWx2hK3X7Z3lSAtn12WFJHOP5T5i0DmYfMJYAFbuPD0JQEWCM3aYsgbXKbbFH1BURh" +
+			"L/uy3arVBP4FaJB8gH678K4J1p4=";
+		public const string End_Certificate_IC_06_03_crt =
+			"MIIChjCCAe+gAwIBAgIBQjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1JQy4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDYuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZw+GpvdleGlmdqZ/zEO2DUGhwgrsselBUNnEzR" +
+			"bcuzr5O1WwiG6aLjrPxIXeL1wLS1/u9AD9p3CQU0XFhi+bEI9+LLnt2y3707O+AQxy1PnQ" +
+			"6qmYE4jMwqDGHn8WVanN2joFT3isLH5wJD0Jh74eoG0tqCHUyOiXaZNo78qgB3AgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIJOeyCnvfJtAwEwYDVR0jBAwwCoAIpwUlwG1W+sMwDQYJKoZIhvcNAQEFBQADgYEAJbz1" +
+			"RipbW6uu7B+f2Ol1iq4AVOUuET2S9vi9ojReyAIka3q1XUceZCm5Et0KqpOoOLiu8IRuNB" +
+			"bvKwRcZ4hcVEXv5bRMqaPEK2B0VrRAV/Llj5A+RGn6yc1ZdkJeBRhoSsaHn5whfICaiJX6" +
+			"j3lMpo/CiMRViL+gZLU3SdKqvdY=";
+		public readonly string[] TEST_33_DATA = new string[]
+		{
+			Intermediate_Certificate_IC_06_03_crt,
+			Intermediate_CRL_IC_06_03_crl,
+			End_Certificate_IC_06_03_crt
+		};
+
+		/*
+		 *  test34
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_01_01_crt =
+			"MIIClTCCAf6gAwIBAgIBQzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDRkBhJJVgOXHjydAHAnokd/XfEiW+bnWd2ZPJrMBmP" +
+			"7TlvVpxOGqLd6lGdbelbSyAzut1i8lyYn9NSDR0PcyehCSS+MsKS2uNKsTEuH3mlMK/7C5" +
+			"B1qggKqE8f7opyl9+U+Qyi1WQj01gY6XYXaCxksCB0Oqx2737d7QWMvl15dQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIO1U69B4DBHQwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAcHWV4Q4z7C+IC4bWgIf1+BzkszCN+LSb4JquR7GgICESbwF2JzR+xL" +
+			"7yoKvB/NBcCqtMY4Hi1DHACbIGJwRe68vVHzz4CmYEK50UUCbAtiAiy9Od6wwrTyFyacBd" +
+			"CBjiO6mkFEp6jOsoIgXRfxK4kDNcMkGUUwMbSR/wZKFuImc=";
+		public const string Intermediate_CRL_PP_01_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIO1U69B4DBHQwDQYJKoZIhvcNAQEFBQADgYEAHtbX" +
+			"MUofQlCnbJhgLQw96jsBRu0Kdx/Rk4LWxEbZQOWNaD7aukASjEv63d1qZIDgpefuUNTz5s" +
+			"3eascdtI6iyWFtBO3r6tihtkkSbxocN2Rz7OlR4rW9VwuUirxP0145nMd5CEL03/CNABP5" +
+			"zUo1bNgswHW3z/RaH6h0j0yTkbo=";
+		public const string End_Certificate_PP_01_01_crt =
+			"MIIChjCCAe+gAwIBAgIBRDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALQaTS1wvv551g3BP9JYBMM+KXXLzxtOwPlO5NR4" +
+			"LwuJJB2WuO4vmbn8AG35in/0JqwjZeroLQvbCPxZseXsyA0+7cMO0qcjRJ5l5WdFsahT6g" +
+			"z1YW8pYYY5i2eDUkIRsM7roHMiNjt3zpkuUGX0xZQfAxhuWnRIvlGg5J4r7UOdAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIeyLSANVaTpQwEwYDVR0jBAwwCoAIO1U69B4DBHQwDQYJKoZIhvcNAQEFBQADgYEAvZ4a" +
+			"SQMNl+Q++D9yVaGr+37XJyxs4yow5e5YM9LXn1qBASQ+GNfqPWoe2cPCPYKj32yulxyFEu" +
+			"RHrbhpEQe+nrKWJgO9W1bmfwgQDin29ne/JCQPlznhd3EPFvCkmPLnTyJmSLR6B2VxvndM" +
+			"GO8JEbj3KCf51uf3VnC/Qj11mX8=";
+		public readonly string[] TEST_34_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_01_01_crt,
+			Intermediate_CRL_PP_01_01_crl,
+			End_Certificate_PP_01_01_crt
+		};
+
+		/*
+		 *  test35
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_01_02_crt =
+			"MIICfTCCAeagAwIBAgIBRTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCkQQXRO+dnU2v7EbaqQNmfPD8v0s5Wa50hl9M1Gfr5" +
+			"5nuVUZs/RI//1VksTNrW10MVh11nsxpA/XRPntEIbHiH1OoECd4dnZBiA/2xEueM02fTjj" +
+			"fb/t7g+pr9dSU/TzCVZDVWFBcPn4VNz7BBqIrTAOXaJkyBZ8hh7vyiE1Y2VQIDAQABo0sw" +
+			"STAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHQ4ECgQIoTKVlZ8YCR" +
+			"AwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEADhtnd6ifr6kyfC5D" +
+			"UWuAXLtoccMj8Jaur/1YT1DgnH1XbBsEeZwm9Jkzr1a3cXPIHgaHYgXvBeGUtZ3XhbCSGp" +
+			"8U6clJz3lm3qKPKkb5rdDrpdTaPnEJJjS3C4ZK1L7UZtQga2Enlelm5vIkhjsF3Sexe1kY" +
+			"mzqiLZZ8yLxJ/Tg=";
+		public const string Intermediate_CRL_PP_01_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIoTKVlZ8YCRAwDQYJKoZIhvcNAQEFBQADgYEAn94u" +
+			"sT8ZYNzfHIdnx0+fV0jglL0Kn1duz+ehKHow+RGqH+J9opMYuXVD+rVQnLdZl5LbFBcv+5" +
+			"TSP9WR9QtyoXar4/jmY2FFdBjfgO9w7p7OHD4WxblJmfPVOvrzFm/slZE39Oe5Qn4KlS03" +
+			"9tttEFTKDH3qREQbT6g4k4ExxYM=";
+		public const string End_Certificate_PP_01_02_crt =
+			"MIICbjCCAdegAwIBAgIBRjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANBwkwTWdZ977UAx6CCpXc9T4MX9T3/Tt6LbtY9I" +
+			"eXxI9W15eXm/aqrKiXhULB+oF9/qNeUi2fAtrURZ7hgHbTaswr8CZ3Uwc6Rbkyj2GGiM6Z" +
+			"8sKFztYZfFyGBiNEwfTT0yaUUQ6etIFqPuL/6qLvqXmvNPxFb9gjTH/azs/MdNAgMBAAGj" +
+			"OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIW1/BRCbe3c0wEwYDVR0jBAwwCoAIoT" +
+			"KVlZ8YCRAwDQYJKoZIhvcNAQEFBQADgYEAPJg24q7wCU8CVlxFLchoe7txhkzApkVMIJ9G" +
+			"+QTnraHDn0CZS6undCsJw8mrTNBQPHFn2Ixa5lrPfJvwW4Med1bcJKbwR4TveL1WeYYq6+" +
+			"9k1kS/7KmqyKAKC/s504jAc7qgMd4b08oLxbGVfFVjWG/ZMbO770FrsyRHHs2rTOU=";
+		public readonly string[] TEST_35_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_01_02_crt,
+			Intermediate_CRL_PP_01_02_crl,
+			End_Certificate_PP_01_02_crt
+		};
+
+		/*
+		 *  test36
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_01_03_crt =
+			"MIIClTCCAf6gAwIBAgIBRzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDL/XgMvoeszcAzZqMYnv1At5u83Gb/CEX3fv6O1jL4" +
+			"W3XbdvBNIZpuTwQhTH4Iofk9rIuQdkR7xOmbk4AqZINuas3Y1CPdzss7teraK0CNralNl1" +
+			"jPYK+ClDBHt32Iw3bAl7RqWX73hl3YH6/7cvG4XCo1HqeeFFHUGa7HXGXq9QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwAjARBgNVHQ4ECgQITMu5Qbn1Cm4wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAuCnzXbHg87PIYYRbCCiXKDKA3MOcEKuxpNaSbtm12DQWpnvzmaK5nB" +
+			"D/Ebko97CS7u9Tpwa7TmTyi39bYzY0dmVaotCDzfSTpzw6qHZl/w8riS+cKr0mimnjW1cq" +
+			"kGPyHf0zBBqh0liGbd7EOLIBln0ASrn8V+G4Tj0Q6aQVcko=";
+		public const string Intermediate_Certificate_2_PP_01_03_crt =
+			"MIIClTCCAf6gAwIBAgIBSDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCu1Fq+gBJsBf5EjKKtNIxgdtgPMObby7tKH7fTJxYE" +
+			"5LPyPi/IiWQ5Mi/8BCG3zmQhu9ZdBbpal350qCGVTbaMlnpi98D4WwXSw7e8oHIJIK689p" +
+			"Q6Z5cf8hgwPnwDpYLeEaqxwhd4bu0x1lG1fUISA0ZZIQaEeNSJfdh15IkAswIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQILRhQwULcyPYwEwYDVR0jBAwwCoAITMu5Qbn1Cm4wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAlEVOqXcdeTU7wT0l+/BJhlG5iaAcanAsOaJFZsXPjLMSjhldQe11/z" +
+			"BsrrqjcpdctcmBarKO4MnwqVU9DN2RZ/v5Gps6OcPxj3T8wlrCGe4l6s9d1FncBMJ0RAUe" +
+			"QEn2JLkQW5JWRBQ00+RXJYFuIM6Ger2MipWj1oOciv9MMoc=";
+		public const string Intermediate_CRL_1_PP_01_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAITMu5Qbn1Cm4wDQYJKoZIhvcNAQEFBQADgYEAycux" +
+			"rzvy2IiYfFkTw7QgGuBhxIQPbSIbfudqyUumuviHJkIMZpPwYj2wltjyiRaozrDAWq8mlc" +
+			"PsFYNr2lUYN5Cj4BhNQCNZlyBw7LLdzRgza55zVjmYkHWedyZm3kPWe7Y0w8xc/XIvi3iC" +
+			"qlwV+X85cgHNJarx3GEYdb7Yos4=";
+		public const string Intermediate_CRL_2_PP_01_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAILRhQwULcyPYwDQYJKoZIhvcNAQEFBQADgYEAbcjU" +
+			"+8l6pSik8PcuIzWndAg/w8uRfAgR5W9hPSXZChlx7uM+48wK98DGEXuTkJcbeclZia+Mpi" +
+			"J5u3qG1zhoL1aHr+RqyJrjiWKC4/rDBuiUk/ftU54mrYn0qev3aSjf/GLtpcC8kC3gpqD+" +
+			"20bvxLjBG3Vc9ZrxDvzfj8cD9K4=";
+		public const string End_Certificate_PP_01_03_crt =
+			"MIIChjCCAe+gAwIBAgIBSTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wMS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMO0l0+X6jfT8cY4DumtseTryyIJ7h+nraogXmYo" +
+			"uhFGvMUWEAZVGD4x9QTTVEL/UCqNfzpI//Pp/uZpDudSgOX0ZdAbykObqCAEO85msK+eie" +
+			"8baS1cW1XGjCuWDqNZko3Uo3c5lLPlRMbZ3hjvA1zmYh3prYnOh032GZAArVcVAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIMh2aWvtm0mgwEwYDVR0jBAwwCoAILRhQwULcyPYwDQYJKoZIhvcNAQEFBQADgYEAigVE" +
+			"FlCgbgKLR9FWIiwnz1bZ0MKsfhytllCI+jGx0Q3o3CxCGXs9PvL6BPDdMOxNIT/oU2uG64" +
+			"EhZEjcZCnUknGx9OkkSSVq44P/pGuUx1g4Kx4i8gsJ/UPrPpYv/3heuMcKWCr92l33cxPT" +
+			"IU+kmAtqy0MBvBKL4p635+MSIVA=";
+		public readonly string[] TEST_36_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_01_03_crt,
+			Intermediate_Certificate_2_PP_01_03_crt,
+			Intermediate_CRL_1_PP_01_03_crl,
+			Intermediate_CRL_2_PP_01_03_crl,
+			End_Certificate_PP_01_03_crt
+		};
+
+		/*
+		 *  test37
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_01_04_crt =
+			"MIIClTCCAf6gAwIBAgIBSjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC9gxMP8j4L+ISffY9wkislQ/V5sO9LzZOncYK93lZf" +
+			"HXJG1MPSQzFPNzDLSc2zsilA03v6q+zr4NRrRWwWGmB34NGM4aqkoxox/7ngTn0MIq5gZ2" +
+			"eOx0FbjA9W9DHEceVDS6kgs9lFcN2W+muCG2/fGqQUED9Fzl9JSM/tE8XAKwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIgdUt9H4i6kwwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAxPe0vM0BvormJLF5HxkyFcTtoombfDGANoLoyj+PTWRD6z1/AcAx5K" +
+			"rn/0J1sZo13M2ezaZUABbbpNH9X0OS225IJF4mXNpfkYhsz/+jNPGjRpN2p0K+DhMSawUw" +
+			"QfGv2x6f31k6WCdy/769i1mwKP6Rpph2nkRyYW8MwO0N5HU=";
+		public const string Intermediate_Certificate_2_PP_01_04_crt =
+			"MIIClTCCAf6gAwIBAgIBSzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC7YCtN67S/ItOzaSGqTvfEE483HoQGiQZ0ob3+0beK" +
+			"kmbSGADBQVBKe/sLJEKddyV2Gl8S4x+cKaKBWUI8lMZViJwWqVnyAFd8ZiAB/BpXaKKgP5" +
+			"pFsg10Yo/EtsxGlLSTLurst0azNnFv7ca5Hb8te3T91eaI6y59IjbsRgilSQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIGazrt+QRNCkwEwYDVR0jBAwwCoAIgdUt9H4i6kwwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAUIz/MSc6K5eaIAg8skaAgm6rSPvcU/711b9G0qsIs6YqvEz4zhGi5X" +
+			"nalYYXfaSQzomuRuABNvuR1Ydaw/B9OdPMro0DhX8VpY6NzCL5Qj60/I4is5a+Hzgk82ck" +
+			"eAC3okPHbVMd7R9kdFsWNE3Capnv7rriqXO3vwFw8b9vXD4=";
+		public const string Intermediate_CRL_1_PP_01_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIgdUt9H4i6kwwDQYJKoZIhvcNAQEFBQADgYEAkR24" +
+			"ebKfvEhDA0C7sawukQbv/q8mjSS3CrhA/oqeb8bML1IlW8rjHSXuRU/n3oeyAZuxLCAQMU" +
+			"TPG6Vq4dOu8XC1RY74xIm8ps4mE0xB8/nI5kadHUSDPtUZhNzc8tv+z7fUGRaVGL7CBEpq" +
+			"ICyQKYytCwxyf4xu2Ip71Uy2tuo=";
+		public const string Intermediate_CRL_2_PP_01_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wMS4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIGazrt+QRNCkwDQYJKoZIhvcNAQEFBQADgYEAjpUo" +
+			"XSj0HX7Wm4w1FiRBBazInGOhSQX9VP2GcGb5lfr3GKt75Y+C+C9qd5X25DVkA4M1gPBK+u" +
+			"XjSMQoHAmFJychQG23rcGcuDJlzRMyfvPCF9dOGLFdmkuHSo5hQUyYsxnXV8cWLIkR1AUz" +
+			"PtUbTJL9g98R/OJFsCBiPi+By6w=";
+		public const string End_Certificate_PP_01_04_crt =
+			"MIIChjCCAe+gAwIBAgIBTDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wMS4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDQwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOtf65MaydWM3bmMT8tAGCX8gZkx1JlgQyBlJT67" +
+			"2APIkfmKRFK/dBtSwwCVGHZG4JYBrrwMpzUPrkGKYI6ZVIvvPnPfadZns9i5SM5LZFS+a5" +
+			"JfbRnSJd8dXhZsKHxqkxIWwG6+VgnRKXE/Uc4m8TePQJZEOra5ezna5yhvqUwPAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwAjARBgNVHQ4ECg" +
+			"QI4iNoMjKiXMkwEwYDVR0jBAwwCoAIGazrt+QRNCkwDQYJKoZIhvcNAQEFBQADgYEAmOjp" +
+			"2EupE1AmgjGfiGK1fk9kf39yQXK1EDsyO6KLdWL/bmWeYi/G7ZE57/+yVVADJuHI8xVIDZ" +
+			"LAC0u5p35OLgbcmmA5bs52KWJJfa0nbgGpVaUSMg9SkEGS997OsgExWMvYhdFIKXlq4Rwc" +
+			"ca89Hg1GlXdrpfD2OCDNBvcWB5Y=";
+		public readonly string[] TEST_37_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_01_04_crt,
+			Intermediate_Certificate_2_PP_01_04_crt,
+			Intermediate_CRL_1_PP_01_04_crl,
+			Intermediate_CRL_2_PP_01_04_crl,
+			End_Certificate_PP_01_04_crt
+		};
+
+		/*
+		 *  test38
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_01_05_crt =
+			"MIIClTCCAf6gAwIBAgIBTTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA1MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDFzEEzV/yUEORIOufyqpZzKpYz5aPyBbcDf8AMMCM5" +
+			"tEz7j39cf1f227cbrTcAaUfYFwkrb07RU4bTS2X+U2Ak7Q5OROz5rrZBbsfwF3yHhwHxCg" +
+			"KLjbwz7D+OJdNfv7x2HRckwfMUkmP4cEuJIIPwj1ieBbsnUi9dkWZePwl80QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIjsCjmszYCHMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAWMUBdOdHMB/SV5kPUk+zut9g/1v/GyxyB60mq9jGqjrIsk4a9JRqa5" +
+			"MWju+6kVfSLelAOCR24EQsXnZM/5Qqg3Wb/SFJXWDcBnfWQWgh8UmJfmPhD7jViG5QVIxn" +
+			"iALNCYtz373L+IDECLMO6S3wcTPsHdYv14jl6BKtabwIpE4=";
+		public const string Intermediate_Certificate_2_PP_01_05_crt =
+			"MIIClTCCAf6gAwIBAgIBTjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA1MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCZzdj+ixWCuxJGMjcoHUwSNqI9Wt9gYwXUTl+dWg/E" +
+			"lg2SPJP7lrBOibAhSmaTorhunUSEf2adhdxhuGrd5Ucp6G0oZAa6ZDWaID4rKYWsI7d5kv" +
+			"mrUhDEEdzk2s4PCoPiQm4dKwRg2rIvA5Dv+W1ldqSVSG376zVrQ5xdjDUX5QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwAjARBgNVHQ4ECgQIUASviIKBmJgwEwYDVR0jBAwwCoAIjsCjmszYCHMwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAa3c+0Drcq7iWP7K+gE6Mz/0ATQoiG87irXWfWBUGWtYnsh6K+1THMl" +
+			"ibmZjYhsztK1P5rm6qL6HAyw0PhrRE9imqZ16cgiMomh65BWQImOeiXx9YWIPvjXWsE6iV" +
+			"E31XShr9b9OZBA2+Zpydc3ID/SQzy9PiTAfL5yJiW/JZvFw=";
+		public const string Intermediate_CRL_1_PP_01_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIjsCjmszYCHMwDQYJKoZIhvcNAQEFBQADgYEAZIzN" +
+			"pXT89MplQgcXcA/K7YKlf62QCbw3rE+bUQiumJMlNGiVdaNJ8T66ObyoOWE+s+KN/Oetlu" +
+			"HglQ7r6RG68gHYtZZiO6kmxq+wor65dFGQyRggpD+D47yioEgR12wUUksL/8oBW1pfGW2B" +
+			"dR4sNWjzV5k5EWbLYu7wxj2/ubo=";
+		public const string Intermediate_CRL_2_PP_01_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUASviIKBmJgwDQYJKoZIhvcNAQEFBQADgYEAlZ06" +
+			"h2L/89GvCtU1K1VtbHPMN/LAUYJrWFID1Eo+Cf/5wKEGBr8hxRtvshTK436zqVQRQN/XTq" +
+			"7u0SLxvIixNRErlmUlGByi5vumN2OA77SxOyqYLCnBXTd5tWbFGz/udjaNk1MxOK0MQxPV" +
+			"9R+HHUUVojRnAIQvlcqx/sMzU5o=";
+		public const string End_Certificate_PP_01_05_crt =
+			"MIIChjCCAe+gAwIBAgIBTzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wMS4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDUwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALyBn2GKvoKNHcu3AEJRCbWOyUpCc/onvRoQgWRr" +
+			"wE7vMI7vjqnoR8mXdWDW5u9DFu9V5pb/yHBWn1zpgFGNnLrqn8irwR9i6Q+qlu4lXL5WSr" +
+			"DqBqEKxrOBDPgkVz8Ldjt/Hy57qEukBarvpAwTc4XEJPAmxNrboMeGCEn2UShbAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIaV3Cd/83r08wEwYDVR0jBAwwCoAIUASviIKBmJgwDQYJKoZIhvcNAQEFBQADgYEAVJXz" +
+			"gooT1qd6rdehnLxJMf1HZ6JuqpyoQjzWF1jA3SkJmBDMXvAkMmIcQ7r5CZHaVF0iMQl5JW" +
+			"fxPtM9Bws6jZhVL0TkwJHmbnSvbzUkJYeXPCP7ags4bu5I32co1nFVF6wf3aQDZeLFj/TU" +
+			"1GCQ4rh80T5oknuazD4xXAYx9sE=";
+		public readonly string[] TEST_38_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_01_05_crt,
+			Intermediate_Certificate_2_PP_01_05_crt,
+			Intermediate_CRL_1_PP_01_05_crl,
+			Intermediate_CRL_2_PP_01_05_crl,
+			End_Certificate_PP_01_05_crt
+		};
+
+		/*
+		 *  test39
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_01_06_crt =
+			"MIICvjCCAiegAwIBAgIBUDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA2MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCjeJAwaZ0cw6O76hu15XadwJiTsIJcXZxGAETq8H9p" +
+			"VJs7kJh57oLpO/lG8zG89QS9g1ozxaaGDWsSyXsDzv1eqDVZg3ISQu6XcKdDu8EwgQDY3S" +
+			"EGkJ2AidFue3l0kEwR9+rtsuVKd/P+ULF1hWcoyLB/sQD5z8GvIiDKyRBiFwIDAQABo4GL" +
+			"MIGIMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwCwYJYI" +
+			"ZIAWUDATABMAsGCWCGSAFlAwEwAjALBglghkgBZQMBMAMwCwYJYIZIAWUDATAEMBEGA1Ud" +
+			"DgQKBAh9i6tKUsPTgTATBgNVHSMEDDAKgAirmuv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQ" +
+			"B/Gxsb5lxSTN21CrjBp2aE+U1oTP2MpIFWUD1q8KWhZZF1iCQ7orcDVITqJPdPxDu1YwKk" +
+			"zOegc4YBSJzHZqF/W4Kw4wisMfnWLTsUAeP/Ucz4vXk5rsf7IRssFG6PLxVmtRZizoxl9a" +
+			"DO9abTM/jV8Mgi1IB6LdWgmtosBGBzbQ==";
+		public const string Intermediate_Certificate_2_PP_01_06_crt =
+			"MIICrzCCAhigAwIBAgIBUTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA2MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC8DbqYUf437toWlRkOQA5PloqYQjWYpiR67yGSjQHp" +
+			"j/HlduTYFS4qfUbLCjH4qsNUH8yQDvogImQw5M1IQOsUAqO6mYFxjqUWccuOaHT6XfUaOs" +
+			"DDHr/tQUvhz3LJryaILiPlNcQF8QiYpujM1utVRyFpmUrMAlOvWUB93c/xUQIDAQABo30w" +
+			"ezAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAwBgNVHSAEKTAnMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwCwYJYIZIAWUDATADMBEGA1UdDgQKBAgQxGVMTJml1TAT" +
+			"BgNVHSMEDDAKgAh9i6tKUsPTgTANBgkqhkiG9w0BAQUFAAOBgQALJtPqY5uROJ+2QYTekn" +
+			"fSUc0gC7j3/cngIvxGT385xDLTrd6TjYSi+12+vU7RNd3MIZoz1o7RpWQV6C751WtOFuZi" +
+			"iXeQ758aLqfhjYSVW/NHkO8vjrAMUzUbgjqb03k7q5JgtT6udB+9ySmou2/RxYW5p/IT17" +
+			"euMVGmQb/RFg==";
+		public const string Intermediate_Certificate_3_PP_01_06_crt =
+			"MIICojCCAgugAwIBAgIBUjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wMS4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA2MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCsQqIx0ayxpIE8NduclvK1ubbNkXyvr0RDqnGOoyTj" +
+			"yMtnfnwRbclkFCNBdalZYofuTWP0reqvqGqsBj+RS3uazvDBqVmn0J0AGRiLILummgEFRJ" +
+			"ow8IB1hduDYJpDMrHRpfXpbG2H3fzN1XeX/B0hUZgdQ86GyK2qrmyIcyqZXwIDAQABo3Aw" +
+			"bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECNKJMmEWCA+jMBMGA1UdIwQMMAqACBDE" +
+			"ZUxMmaXVMA0GCSqGSIb3DQEBBQUAA4GBAKv9F3+Y4N8RX4bRZ4fFTKri2rrB4BsVrBFpOr" +
+			"SLzKnuyO1O5gg45d70pSHUAVBn3pz0f/6WwWLECq9tB7/Fphi0TyqeFmkRnysygZGlvLgs" +
+			"L19bpIgVPkjFFziMGuzdAFIGy8vnV19yJ2euMygEHr20yiGBUaHHnKyuOGbDg4i7";
+		public const string Intermediate_CRL_1_PP_01_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIfYurSlLD04EwDQYJKoZIhvcNAQEFBQADgYEARL4u" +
+			"DZvfcQDYanTfwU/hWAJDdDO7m7oQZLy3o0PTqXkk2Jd2v3+M2U8UN2PcuqZXT1lwS/piiW" +
+			"Sc1x1YndD0qUtV4bOZ9SESPhCeOc1lQTk5mMf/zqFxQqYv8rfDB5O3QY4bjS7QQzSsvmal" +
+			"TGCnoHmUJ4skmZJrQAzYnXyD9G4=";
+		public const string Intermediate_CRL_2_PP_01_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIEMRlTEyZpdUwDQYJKoZIhvcNAQEFBQADgYEAcEyr" +
+			"sgLhVq0L6N5fww/U6TW4lqaVAEtjqxluWRyZnL3AJLEHfwh1lllCG5dNM5fahGDOW/53fV" +
+			"+gW5l92bsi2D/lAkDfNUdQdi5ZpQG9y2zhTArUlx9z1+KXklCi2Gg1X22gi+cYbK2hfzk6" +
+			"kNGP1v42bjrkF/ECczpy3e41rEg=";
+		public const string Intermediate_CRL_3_PP_01_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI0okyYRYID6MwDQYJKoZIhvcNAQEFBQADgYEAp3uQ" +
+			"Tn2HC65TFmSjzvjuStIJwJcVahNcTWiGdtfTalZrMtuC9vUgQq0K1QIa7QNC9C3hQlzb5e" +
+			"bO7JhJDs+5GZnnsqHN3pvdKEoueRfWBjUGpPnSGFD61ysf9aDFY2j9Amf3zcBFsXZs4+DM" +
+			"dIENndbjkwqCV4zRTajAqCsIy20=";
+		public const string End_Certificate_PP_01_06_crt =
+			"MIIClTCCAf6gAwIBAgIBUzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wMS4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA2MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC+IxiNJMOQG2gx1xd9ELNuzs9LrVJVRLvgP0lpWrx2" +
+			"2HTEXPDB6YmrEg/YgyptmQ5Z4K6CEgJz3EdDOarCSGcL7DmcSEwEw46MV3piS5DrHwQ4GH" +
+			"a2/ENSh3lF+6dliBwbQR2necmQ5g8ekqkWNb65pLl6RCNGkntJpdu8w5GWbwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIMf/eRyakKwgwEwYDVR0jBAwwCoAI0okyYRYID6MwDQYJKoZI" +
+			"hvcNAQEFBQADgYEADgpHRDgyPuK4dc+m2p0IELHUAK3qsdTZzBXsaA0rkkk1aRjI6DQ2qg" +
+			"b4crRU3spQgYwBC7KQYd/hp8Lk17iX6fdV/9wol0DxTGhamOJA0uRl768awRArf4cEUElF" +
+			"uWPN8D3wJEfL6BWgReUJWg8V9HEtdvXZZgzFN/CgHRkQ2RM=";
+		public readonly string[] TEST_39_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_01_06_crt,
+			Intermediate_Certificate_2_PP_01_06_crt,
+			Intermediate_Certificate_3_PP_01_06_crt,
+			Intermediate_CRL_1_PP_01_06_crl,
+			Intermediate_CRL_2_PP_01_06_crl,
+			Intermediate_CRL_3_PP_01_06_crl,
+			End_Certificate_PP_01_06_crt
+		};
+
+		/*
+		 *  test40
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_01_07_crt =
+			"MIICrzCCAhigAwIBAgIBVDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA3MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDs3Z/FfgJOyKp+Ds8xiQBM053cWylYbD+g+zuWDz3d" +
+			"nD0eF77TLPITL7hwI058Pn3tXHlveuKMFqbvzWUgFXaBoHmmRohIj1eqfJQhlmKLjlSYyC" +
+			"N4xhLVi7vg71ZjFdRk1k8ME1HDfpb2WXqXh9LyRYY8b/aqL+NHe1PUDbT6FQIDAQABo30w" +
+			"ezAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAwBgNVHSAEKTAnMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwCwYJYIZIAWUDATADMBEGA1UdDgQKBAgvehPxsTfSBDAT" +
+			"BgNVHSMEDDAKgAirmuv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQBpdMBEONGcpFitMN1ihf" +
+			"W441E4HVTQwtF+h56aagVFndUF1gQsVEdDNmvvN/jdlzXotcfdEj1lOahmcwWbPOlNx3PB" +
+			"LUPAcaNM9SCrXWi1gKJK3gXC2OAxj0mT5XhfPlAdfhZXTBZLqMqebmk6kVwa+VyPPZFHGy" +
+			"BW0fV2ClJ69Q==";
+		public const string Intermediate_Certificate_2_PP_01_07_crt =
+			"MIICojCCAgugAwIBAgIBVTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wNzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA3MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCrO/98w96Bg5YTTmtdc9sL8AOABGcYx5J8E1Y7/GhU" +
+			"2sInc/j0dtBbE0Tj4KFIKpVLD0m2mTyHVCUA0/QGiS1Tq6DzmZW/V36Clya3CoX9rDTJyU" +
+			"cKHpgntV19fFAK58aksyKCdP9jjLpbSspzOlIc+mVW+hkjgw3NcuY6fAOQvQIDAQABo3Aw" +
+			"bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECEmeATXRkM5EMBMGA1UdIwQMMAqACC96" +
+			"E/GxN9IEMA0GCSqGSIb3DQEBBQUAA4GBAG/Qv60jyImedUXtCYl0QpQ1Ne2ZLxvUHRLms8" +
+			"B1nXC/Rze7zfz5cwiyQn+6XN2rhuYFdTMDEFZDIjeeCLNllfan4GUAdRGtoJnfoLOGLlQf" +
+			"RW1ONc80cxd1NTxHqxOtqpWdoJQEn8070WLqQPACEs88XYKBZ00sF9ZdSg5vhHUu";
+		public const string Intermediate_Certificate_3_PP_01_07_crt =
+			"MIIClTCCAf6gAwIBAgIBVjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wMS4wNzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA3MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC+5b7o4iWl80ntDMKGcnquLQDTGlf6Gy/8y34Vw08/" +
+			"8ij+nuHMiKpo6UCF0OpDcnkJ2ovvMsY5dAb5ErhH64UbnMlKbghnGv0sVidtipoC8u7ey1" +
+			"YUIzDCdmbNvTfho6IXKzH8ev//K+FJd3qBuKHl9u2Kk5+igsyb+bPSid7d/QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIUDKu7h5EQ70wEwYDVR0jBAwwCoAISZ4BNdGQzkQwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAnKhR3OvdgtVtmio7ikCvjxlSoKVbUleazxONOxHUAKdXEv0/mSOTwp" +
+			"hPPIoE2xAqPOOHvXPmzmJpPADjrfhU6afJ7ThDRFTMk4ZLOkT1SvRlymK7uWhj5bhUgi6S" +
+			"UQ2LUmrY2hIN4cTrrzZvDw2Q/6UIuqpmySXEOHDL5T5MXEo=";
+		public const string Intermediate_CRL_1_PP_01_07_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIL3oT8bE30gQwDQYJKoZIhvcNAQEFBQADgYEA4gZR" +
+			"71wRXNdxWe7kaQPAw44UUw+cN1bDBU0RV7nwYAFDYxDIaDGOfjhUVTMBq4rb51S7uqIqYS" +
+			"F6j7BdLXl9WVRJobfkRH0t0cBnuSeQRz3ckrZrCuvyxb3PEL3pbf0UH1i/BfoG+EHJAY7R" +
+			"OVOL/dyoXeX6ehH6ImGhucDixS0=";
+		public const string Intermediate_CRL_2_PP_01_07_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAISZ4BNdGQzkQwDQYJKoZIhvcNAQEFBQADgYEAfzKw" +
+			"NHrl10PJDHa3olBYXYzXi94zxDsEQSIb+W4pPXUfDZijPqL1NzapLqc/uL1Sl28GmLDrbm" +
+			"nCrlMn1Kt/gI6XndOnSyC9Sg6WDxAI3HTHxlG5MHLBn9Lb36CHobnwep1BMo8zl2clh0Kz" +
+			"PIxQSGXM1BDpHkwF5eoFAolDih4=";
+		public const string Intermediate_CRL_3_PP_01_07_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUDKu7h5EQ70wDQYJKoZIhvcNAQEFBQADgYEAj7+M" +
+			"EeIe1GmJpbRUFqbNrDvT5tHjKQMNdbe5Y8F920U5t0ig1Up60kc7hs7LH57i6R/quPOpym" +
+			"a9Eo9Bql+P2Bg9FELih5/a4B021TZBmmdSI5fwQZ6Q5PjgG58Zl2cJitNYvGi7tVUBojA5" +
+			"CSN7KBMyipia9ivxm9a/llJPrQY=";
+		public const string End_Certificate_PP_01_07_crt =
+			"MIIClTCCAf6gAwIBAgIBVzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wMS4wNzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA3MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC/RmUcYHxgQRHCUh5cMug/J2o8DzYbT+2pIehJkNCr" +
+			"zfqemV3qshLdMct5GV73oEkG5b6n7tj3/hI1TLh/A3LQpKROAGZybdo9fk4Pa0+6V6ql/U" +
+			"NnSpcAKct/f3IvchGo9nBGdi9aE+j+xKhMM6E8xj1+Jc7Z0xz7zE4+qRbeZQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwAjARBgNVHQ4ECgQI/y572lfRyH4wEwYDVR0jBAwwCoAIUDKu7h5EQ70wDQYJKoZI" +
+			"hvcNAQEFBQADgYEANl9zdMKbaq14OP45PeK9D4ftOSuliW2di1qAX38FQoWPYLLoaDU0Q1" +
+			"9I54PDY/UYRR9jKDl1WPhV6cD+65eadtiOZVr/h1CaW/HxTloouzN4z1zCXMC7AxZKo+EI" +
+			"XLN8f4w7hKLFYgf6gP9+iVi+T2gKfH5Ch2zjRhlmGFRgsBQ=";
+		public readonly string[] TEST_40_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_01_07_crt,
+			Intermediate_Certificate_2_PP_01_07_crt,
+			Intermediate_Certificate_3_PP_01_07_crt,
+			Intermediate_CRL_1_PP_01_07_crl,
+			Intermediate_CRL_2_PP_01_07_crl,
+			Intermediate_CRL_3_PP_01_07_crl,
+			End_Certificate_PP_01_07_crt
+		};
+
+		/*
+		 *  test41
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_01_08_crt =
+			"MIICojCCAgugAwIBAgIBWDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA4MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDDe20HLq7R8b0fWTsEiNV3Z5IbQseZ8QCW+1cb6yM+" +
+			"ArKLJDnXx8zmTHSHQCpw3G7xhGsxA1btm0cSC5P/1bw/kFWsSLRe2NFF6oKU+7c+cgIUMB" +
+			"kzyXk+kpWAQRb7hcb50iKdKFtO8gMNGMAxlHRI05/1tThyAs9suI4TrxTS9QIDAQABo3Aw" +
+			"bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECFxr9vgF31fKMBMGA1UdIwQMMAqACKua" +
+			"6/nC51SPMA0GCSqGSIb3DQEBBQUAA4GBABaX7TYfmSyVmzGCVbTFweUuPilo4wzy7z/w0x" +
+			"y4uSaM/YMtixUdDPpTHOJNYDdeV85v+w9oezdL2ZYAaGn7tldC6k8ouq/6hOGGST+ziHJS" +
+			"gTOD8UVBQPRPvWEwgmDIprnzrVRz8rG6uqslXNiBDnO9BMGpRo4dy8YpOmV6BPCD";
+		public const string Intermediate_Certificate_2_PP_01_08_crt =
+			"MIIClTCCAf6gAwIBAgIBWTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wODAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA4MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC8nLZcMLHYKxVqbhwJiqQbAYhf7S6ck2O9AhNor935" +
+			"Bfm7/8qVZbBAotQy1PoCjSW0UYdknDolWvi8aAtO0f9XVrAv6BZVVW9j3osIGN/XUThaN+" +
+			"9dZ83kGpyjeoitpGK4wbFNDteuBFYp+8gFNupnX7JQwUK3aGwBUucbe7puRQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIL0xyFYBk4OcwEwYDVR0jBAwwCoAIXGv2+AXfV8owDQYJKoZI" +
+			"hvcNAQEFBQADgYEAPk+Lys0Ueoyhp544EH9Hqy9+gY+l/+N99v7KvBlZWKuhkwZDE+qAYT" +
+			"P/SOPsWe8ADZE2iQ4pOlpK8jSqtJSdK69RgGL9omLnR04L9c/zKLArBE+VmoV7mohcQp8x" +
+			"aB4q/g3QnAqwfFYDjIWW3H6gRAeQ5MOtKdz/4042fJxc5L8=";
+		public const string Intermediate_Certificate_3_PP_01_08_crt =
+			"MIIClTCCAf6gAwIBAgIBWjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wMS4wODAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA4MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCvy6bNOyVaP8JTwiySFa3Sj+rdSqzkalK5gA7DLk4q" +
+			"AyvnAK64HgbCsb8dpnSi94WBDsocrQ4C1Ltoahc/AZyRVLA/REsAh1r3/0FALZgYiIxvSF" +
+			"m3ihKb3P9URBbotzhl1ahRZPSrcxKwNXEmxB0gjixGW7GZTARq3Il5ressRwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwAjARBgNVHQ4ECgQIwFtfZBe/KqUwEwYDVR0jBAwwCoAIL0xyFYBk4OcwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAeZhpIDEYyV/LkOtUf1TryemJExQ1jdfirJ3AUtoFIoWz1p9aqnV6Po" +
+			"GAMozjtdyotfSA2O8c065DwD+CvUXPmdD+2vWpX/2hJPj+x++UvvntAokD2UE9HCeEvBHK" +
+			"rr59hvKKd6GChyhAjLris202eTLIiMEoyZy9X/Wt1nXF8/g=";
+		public const string Intermediate_CRL_1_PP_01_08_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIXGv2+AXfV8owDQYJKoZIhvcNAQEFBQADgYEAhkwT" +
+			"E/EGAe32J883qVrh1wG5xQzO/GGfp/zuDYGL2k1zZ2zq7MajKfzBoXXQ3WPh5dTK1sy5o5" +
+			"boPHG0pge0B4/2JvuDVS539+9HAPansUNsrMXzOblg1acjdKtuk4oS8PIYkM/lbA6yJl6F" +
+			"QMbdIthWqa2gjaWKll3R8fVUjxI=";
+		public const string Intermediate_CRL_2_PP_01_08_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIL0xyFYBk4OcwDQYJKoZIhvcNAQEFBQADgYEAN6BQ" +
+			"sEQT5YCvs9vlUSdG4gjTgNkyQTCdmSIcufpK4MG/AoW/Fn5zJXxiMyHmvT/dkk/UOf82/s" +
+			"41YI/Inz4qRmGF4IL7jo+l7V+OI1n+Vf4ClgZU6ocb9d1dFoBkJu3xI9dcWK6ExpzaBUXw" +
+			"rPJilV4M5luGbszdDCs9cLjmiRA=";
+		public const string Intermediate_CRL_3_PP_01_08_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIwFtfZBe/KqUwDQYJKoZIhvcNAQEFBQADgYEAkmDx" +
+			"t+r59llppKmm9mSTof9/BX2rNyG9LfIH7wweoDi9be2vYOLy0NU1kJ8f3/muEw2v7hWDri" +
+			"k9ROLDFnb/S8MYVT0l4rymRhpshPF1uMTOZmfJUCfTX9jIaShztSScqcGSP0a3EUfDD14R" +
+			"1yMu2pdlMM35llE0lV3uf/eUNr0=";
+		public const string End_Certificate_PP_01_08_crt =
+			"MIIClTCCAf6gAwIBAgIBWzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wMS4wODAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA4MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDTWNp6Oz39wwU8AFDzYVs3UfVvXg+t6j/qFavnvllI" +
+			"NO6aU1o4Hnk1wfmTPZPErc00/MfizMSumTYYRl21hEZWhjNO5uQIHrF9V/4OToo2iOfsPd" +
+			"gxwpSokwxcl7CJyadwUxhRDYCLhSORXoCK1CPQZjwb+uQz799O5ozb0WVNYQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwAjARBgNVHQ4ECgQIO1TNJtWwaiIwEwYDVR0jBAwwCoAIwFtfZBe/KqUwDQYJKoZI" +
+			"hvcNAQEFBQADgYEANmP9hyFnYvi8gdtRe8ERoEG90NwoyPTsB8sXd40f+Sm1QxKqMPzKPL" +
+			"7bOtY12JGwZ55a6HFVgpw4PnU+0iOcCMHS5OQQLtyirxX2HfioiXEmcmRJT6FvLHrGIHGv" +
+			"KNcfc3rUiksdOb6+j2k8x4IwQ6pBEHQwY8U4Y4DgqALlqM0=";
+		public readonly string[] TEST_41_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_01_08_crt,
+			Intermediate_Certificate_2_PP_01_08_crt,
+			Intermediate_Certificate_3_PP_01_08_crt,
+			Intermediate_CRL_1_PP_01_08_crl,
+			Intermediate_CRL_2_PP_01_08_crl,
+			Intermediate_CRL_3_PP_01_08_crl,
+			End_Certificate_PP_01_08_crt
+		};
+
+		/*
+		 *  test42
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_01_09_crt =
+			"MIICrzCCAhigAwIBAgIBXDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA5MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDJqSSqGjgI3JUJfA/XkloAOg2QtZeAGp2nCq1Oiply" +
+			"MTjJpMpEOSRYrEIgKMGnBPq33seP7X/obCT2jgexmbFT2TmPirM+h1aqbGQ7QAqsx80BdE" +
+			"ofdcfiNosLbbzli9qFrbarO7fJfBhzraBFGDJj3N8nLi2YtP9IieFYJ/MhKwIDAQABo30w" +
+			"ezAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAwBgNVHSAEKTAnMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwCwYJYIZIAWUDATADMBEGA1UdDgQKBAiVRMrZuHQ7VjAT" +
+			"BgNVHSMEDDAKgAirmuv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQCetZy9JMzUVveSPE2fQY" +
+			"4fRVChyvIc9nCE4wbzhnRl3zduBGmAwTFr7dRWSFTnEq1c2b6B5nJtCzmt4Ovapf69sIlM" +
+			"s3iV16eBB1WTNCY8YlAsnmZ7q/AR0t0vX+hh6QV6zN5xqulOM4Y8csZEx3RWJzV/LjE5w7" +
+			"mKvofBEUoqQA==";
+		public const string Intermediate_Certificate_2_PP_01_09_crt =
+			"MIICojCCAgugAwIBAgIBXTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA5MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDWUTlTieoi7aLGUYOAgqUC2J/6JarOWfv4vobpwjAA" +
+			"DjvQGqg/GCZP7FgD/72Z4YefZKJEFZTDnYfmy2qh6iBYxcvLsJ+PJGzPCObNSmyq8gpeXy" +
+			"KKEeCZtEev1tSywTT6E5Dhee4dX0QHE4ydZEliMMXGRW/8ffT6x54CPwVylQIDAQABo3Aw" +
+			"bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECAMhmGN8+qXoMBMGA1UdIwQMMAqACJVE" +
+			"ytm4dDtWMA0GCSqGSIb3DQEBBQUAA4GBALNjokGrTnWsPn5KrlO+g3R8tAGM90JQDjfrap" +
+			"xWM+nN+dUVVdGU6w2pAOAq2UhfySiP42qiFChnPK9oOqPF2Or7/kcmXZzBfZkE/FnJGNUA" +
+			"gs9je1nZvTPQYsF094OqE7QdJi2k3seA1tqejA1kihMHpwQNmIp8bFpqn4dPO6ys";
+		public const string Intermediate_Certificate_3_PP_01_09_crt =
+			"MIIClTCCAf6gAwIBAgIBXjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA5MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDHUpHhF4ANNLOywnvpqyDgzLMtatW3ZxgLBBRYk6TE" +
+			"jMgTVKmRasVRTA9uatGG4b2f70YWs9cOd4ylQDqPEDdKNZ47bqZdX6RAU3j1dO9LBwWDbp" +
+			"NvZ3zuDBRDoCZClIcBESDYweaZ9nUgKl/WxTeCnMwqkfSJGYBBcHIonRPnGwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwAjARBgNVHQ4ECgQIyppef22OmjEwEwYDVR0jBAwwCoAIAyGYY3z6pegwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAOySUCY+PZxomhWgTRSKRodOIe/QSfCMSC+0iw24a2TuJzFLjN9pSm9" +
+			"0C2PqWbfwD1uDjrteO1NK+1yhtIDySiptR9GmR/fhL7NJ+z7M4fEJBjjeeI9/aEIuHuBFT" +
+			"TVHfwsJxnZtjujtOdl56B825LsKW8Otumd2A43N9wIgSyBg=";
+		public const string Intermediate_Certificate_4_PP_01_09_crt =
+			"MIIClTCCAf6gAwIBAgIBXzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA5MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDR8/c35YqAswoRMgQswlTbKB9oYEzrFSC0G4dt8ydP" +
+			"O4PyQs+J8wUVrRVMiVDTLO9rUnzR1T3iA0dqM+SvWMIA8pMWKyNV58f73ZPJIejhxMmOZa" +
+			"sSLHceMmmMRy1zyk38i3ZJP3YhvxffTjWyTZ9k2xSDX+6KNnkiKkJSKpl6nwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIpcWcVIIu63kwEwYDVR0jBAwwCoAIyppef22OmjEwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAckgV11ND/D1vfPEMUbDGUvtmsziHiSuEoDLJqSAhOmcX+evKWOfoVo" +
+			"f7og+0ajuul7yuB+7YX1AakOw+33k++Rsgg4o+ImZq3+VScpgnIQ037OOhgH3umwFRC0r3" +
+			"NpWqhmQuz+mHnKiK3X+IDsQOFkhnpNs06CQSZzmrzbYlQU0=";
+		public const string Intermediate_CRL_1_PP_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIlUTK2bh0O1YwDQYJKoZIhvcNAQEFBQADgYEAkEc6" +
+			"qHGOWZXYTQ5fsWyJgEtuJyl8uJ+gMcikcMut5SIJTTtOz+q3wclYDevT8z1MM25kNdgwyg" +
+			"b1bwHNAG8I72eIDtGfLrChFwU3qpvVMTG9gPYJb05Q8On56nsBu/PnnzJervzxjViaeOuv" +
+			"kjwwfmWqGkyiK433WxzgPqE48eA=";
+		public const string Intermediate_CRL_2_PP_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIAyGYY3z6pegwDQYJKoZIhvcNAQEFBQADgYEAV9Md" +
+			"8PaNoIlT7WIwnelqrbwsR66vAaT8w3gu8XDYXu+MOYThfyERUvtH6AUrHWfiRvWEzKljHH" +
+			"3BQB0Zsa9Zz3U5cLzJcqtqDc1lH53aIA8MflrfMVrYSF684s28FikcukmA5Fw3+7S3TJ18" +
+			"Hq7plHwTCidVD6yG35hsPwcjTrE=";
+		public const string Intermediate_CRL_3_PP_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIyppef22OmjEwDQYJKoZIhvcNAQEFBQADgYEAjBaP" +
+			"V/TFQtDLxQFIBCbfqhlgpOfvJBatjNuvB0TuD2rsGS1eaLNfTfyVKlOLpxoKwKYMu36kIO" +
+			"l/+KEPDq+ofy7uDZ6GLK3KZ/WiJyriqBQjFCvlhNTW1cjA7Ejk2lOM/A46mrUS9xC+aITh" +
+			"d+/UYGt6O/e256cOwQCUaF2z328=";
+		public const string Intermediate_CRL_4_PP_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIpcWcVIIu63kwDQYJKoZIhvcNAQEFBQADgYEApZ1l" +
+			"w5SJoU8zeKwX5jpVWiFFFomDgKsNlkkX5mF88l0B6MiYbGqJIowJRfeIlxvPOf20imN7Z8" +
+			"l38DRXFacDQP4y5kxM420dp+ljQL5q9RsrC1+OS7I7TGgGwPoZTO4mHVk8nx9MyT+kW1OU" +
+			"x9qRYWN0CLmP22kutYBndny222Y=";
+		public const string End_Certificate_PP_01_09_crt =
+			"MIIChjCCAe+gAwIBAgIBYDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBNC1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDkwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALiOjwwwUk1HNwf2rdzPL2okKTgL+lMdzhC7cbq3" +
+			"6A409EY7iipPCcsDsheo9EaTNOHV9xjWDqOhqjA38h4hGNkRUVOlTW2r8SoHISn3gDXfrh" +
+			"aHbU3owscAmt1nuA7rzo7L1eBPsisIIxAY16uAmVN5RdiAAaP8VUdshcNI4/1jAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIGZIY3nffEXowEwYDVR0jBAwwCoAIpcWcVIIu63kwDQYJKoZIhvcNAQEFBQADgYEA0Svm" +
+			"aqjaeQx/lnF223xlCTsU7XzOxbHetRWfeCTw0QrWQaTrKjWTS/TNyzLhGuPBFg+NTTvWML" +
+			"gzteo/WWdF8+d2rOis9FVRCe/Euok6ZCL/xgzaE86ZSQg0jj6458TpuC2cszSaifRSlhL5" +
+			"ogy4ADWgJxdVcBrgADo6QZXkXXw=";
+		public readonly string[] TEST_42_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_01_09_crt,
+			Intermediate_Certificate_2_PP_01_09_crt,
+			Intermediate_Certificate_3_PP_01_09_crt,
+			Intermediate_Certificate_4_PP_01_09_crt,
+			Intermediate_CRL_1_PP_01_09_crl,
+			Intermediate_CRL_2_PP_01_09_crl,
+			Intermediate_CRL_3_PP_01_09_crl,
+			Intermediate_CRL_4_PP_01_09_crl,
+			End_Certificate_PP_01_09_crt
+		};
+
+		/*
+		 *  test43
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_06_01_crt =
+			"MIICozCCAgygAwIBAgIBYTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC4mu1oBHB9BeorCFJIuSw5tszmmYBD4bjTklsAfjrz" +
+			"OknQsYxEoHfifpdgivh1fMUk+mK5YWUz0G8/edquKbJhPBTTWp8opsGzTATsTLSEzkKbVM" +
+			"DQ84ttxrhJWlrVRlouZTnD5HoLUvujY4EdydmKsjj6UBt/tGL5EKodymcEtwIDAQABo3Ew" +
+			"bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATAMBgNVHSQEBTADgAEKMBEGA1UdDgQKBAiGRi8YRte8PzATBgNVHSMEDDAKgAir" +
+			"muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQDHOaIki9TogVJn54FRPl+7FyzBJ2DnR4RTM/" +
+			"q1K3COWRdtvmGqtBBtAccxWziQJ5TnAQn1XA0cFPoCgymGPRcUz+0+C+3VhJ/m9LggVP3/" +
+			"pjJEG0fsmJtUYPyphUlXeUzf4qSj34SlJws3DIHTR8ozAR75HZmlMRnxyZBLl+jAng==";
+		public const string Intermediate_Certificate_2_PP_06_01_crt =
+			"MIIClTCCAf6gAwIBAgIBYjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC2rptuREzhGfEJ3U8ILPBq+z0s+aafMvBRHpqkipDq" +
+			"bC7v9zpwg1K18F4MYiATpPAEfdEeprKs0mWfdusF93BoMBVm1y0zRgDRUNdyB5GFO8g8+2" +
+			"yNEO6L37c1PwrMLnvJakaqwbbnwlcMcKtLHoX19fyveQQg5DNj8WcKZj397wIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIJPt6qKdFeYEwEwYDVR0jBAwwCoAIhkYvGEbXvD8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAkFJGNze9/6YX7Rv8FR9obFGACIJ7Om4YQQRW9WM9pEDgKls7g9b9El" +
+			"dJxLKOlWoRoYZIrbEam19traE2O3dxqRevPoYvfAqkR089BkxH/cFYyfqw64IpjDG84dsY" +
+			"XieajI/Ov/HjgF0VQKF3+Y1ZiDjb2OHNgMkqs9VmUHaE+94=";
+		public const string Intermediate_Certificate_3_PP_06_01_crt =
+			"MIIClTCCAf6gAwIBAgIBYzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCzxfyi52gw/5tt6/9aNAXdY3wZYH1GifzGoN4cg8Mt" +
+			"++5xmTdrc2A9/5biaTUVC0x/Ml6mm940NA9mM/EoEu4SdnP2crNCIFHWNlYz3cJtYJ68rE" +
+			"rEU+S0gnYaYRiwNGhVpAjV+FPDr0Ghgp5rYQ61evAhmRuNAFwYocUw80G6JQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIZ9yMlboxCIEwEwYDVR0jBAwwCoAIJPt6qKdFeYEwDQYJKoZI" +
+			"hvcNAQEFBQADgYEATNnRMQmvTxRcSMUL4pa5bejuX2Ixy/OfZIAlJWt9AfLW2tHmdAaGpD" +
+			"GhTHKfyQQ+HrIMQ+lXau8Yu6nzWXAY8pKpKD1Hbd355VE4dYZ7aPvcAulZHeV0F2EFn09x" +
+			"qQ1frHDRoCOc11B5qV5hnwgDE/ByZh1+OWUcR4tBQKyEF4g=";
+		public const string Intermediate_Certificate_4_PP_06_01_crt =
+			"MIIClTCCAf6gAwIBAgIBZDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDB66hLZx1WGcCqmOxHK/rotXOpccJQOB2L3kpWP1M2" +
+			"ZiWufUguLw45XShdqu31OgmGw0/w9ugwy96aRL+Tiluj4xjIAxJCav5cXF8Dt2Ex7hjIHm" +
+			"XV0rHbJUiduHEh3fQphgtzlR4QxG6i/i4SbcsoJzsws8x3qOqRPaWDtyWs0QIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIyZsLNvyyIZEwEwYDVR0jBAwwCoAIZ9yMlboxCIEwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAc7G4BAUsQeqNp/Kv8TKJckfxWygz54PrkBICNw/eGuGamVJMRkYCP3" +
+			"yJ8NW4jY/rfxzKKyjVB09XuNBLDwYdR5Z5UHSg6Ijes3j8tehZ+9DwEQrR+WQf/adHIsxn" +
+			"/347MHrSQF7CJzE9tAu6AOu53lKxLeH6C/5YI611or2Ql1I=";
+		public const string Intermediate_CRL_1_PP_06_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhkYvGEbXvD8wDQYJKoZIhvcNAQEFBQADgYEAC7ev" +
+			"Pqe0veUX+zF51d/NiG6VwgEwOP1HlzD/saDn/FYXStTQDwoIyFjmZ9z0yLGIaVI1O9BWVD" +
+			"CTU3bCU1dBg61Blo3rI3TlNqmGrYRUSJ857QM9c/G+/+V0XJ/HgId39Pufd9Tob150XNMs" +
+			"9h0PvqjhYjG1bARMRa8JB4KTBU4=";
+		public const string Intermediate_CRL_2_PP_06_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIJPt6qKdFeYEwDQYJKoZIhvcNAQEFBQADgYEAiUbi" +
+			"qQ3X/hTgjhpQGDZi/7EnZcqSgiAFMreV30/mav2NtXDITE9DqZzCS9x1vHBp4BBsQwYVvp" +
+			"XvLVSgns4pFwR+0Whc+tPo2j9ScePq3sICsqleWTN1DvuoP9rBe8w7pDN4guA59Kbeku75" +
+			"5CMA5YjiTUomK4UaqI3htwkBlWo=";
+		public const string Intermediate_CRL_3_PP_06_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIZ9yMlboxCIEwDQYJKoZIhvcNAQEFBQADgYEANowv" +
+			"f/scWT6FFT393XEpWcTnA18hBT5Nkddw6mHjKBq7ndtBQkydMO8Wym1IeQ2qYbAqu3ifNZ" +
+			"SKF3PfgJjYPBKImzJdHTKfcclMC5H8Y9JDN0voeyONr9NiXcoj+p24YNYjb+PFI6avRYo7" +
+			"Xyrqvwnvng/IY9zLtc7SYYUIODk=";
+		public const string Intermediate_CRL_4_PP_06_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIyZsLNvyyIZEwDQYJKoZIhvcNAQEFBQADgYEAsnA9" +
+			"ERwsi2mK540oPL45mLdOjGnet7+HhNk14q0hvALTYGB1vEjijc+Yvf6mHJGRbiG207BpJ1" +
+			"DWeWBY8TLe4YJXlSrWwx1jD46rCt7gdqXAdLpMo+i35yfQ19ZqeWcRLkspmczoUJLJaJza" +
+			"eLRrnjv62GLJ09KVKpZBGhV3SUM=";
+		public const string End_Certificate_PP_06_01_crt =
+			"MIICbjCCAdegAwIBAgIBZTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBNC1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKrLB7XA0PKY0qtSC5lMBvvIvbyjBM8XmANrN9Wx" +
+			"66QxEuloRAz0D5uAu7TnJBv6qNuIPGFl74yusKCSkjEkBMdVpBCfDvpG1/Tz3sALSlxmnz" +
+			"xbK2ytOncbYuYrzvXttx6wkhLrBLlnfuwpZwGZOr/Pt6WwQJWjXxgTNJ6dcgXbAgMBAAGj" +
+			"OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIv0gg7LxDM+swEwYDVR0jBAwwCoAIyZ" +
+			"sLNvyyIZEwDQYJKoZIhvcNAQEFBQADgYEAgzlxBGGOBvHw20eOzSswMqrHopNMcvwuEO+Z" +
+			"Mr0h8U2/HIiRqKWQaxMyM8A0oULGJny3B/0WtkfVQ2EIibZGiKIjC1RPAB3QmL0vgSyUmF" +
+			"s/LZbzugpJW6jvfov7N4O+u0J5rYniRxa4bgrXa89TY9kwDMbr6/z4oiI8bq3gEsw=";
+		public readonly string[] TEST_43_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_06_01_crt,
+			Intermediate_Certificate_2_PP_06_01_crt,
+			Intermediate_Certificate_3_PP_06_01_crt,
+			Intermediate_Certificate_4_PP_06_01_crt,
+			Intermediate_CRL_1_PP_06_01_crl,
+			Intermediate_CRL_2_PP_06_01_crl,
+			Intermediate_CRL_3_PP_06_01_crl,
+			Intermediate_CRL_4_PP_06_01_crl,
+			End_Certificate_PP_06_01_crt
+		};
+
+		/*
+		 *  test44
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_06_02_crt =
+			"MIICozCCAgygAwIBAgIBZjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDjg5+XWZwW1gLAOldsRshbCXmUCmt1Vs+oZsvyH+6d" +
+			"2PwKs8ydrz+oD0/D8V7cRXucj7q7cJSLhEY1wJoTTgrWeRg1hQioAXzPW3ZkaZuzhpi+cC" +
+			"qeZzN5nPvqK18GWvpffNbUUVfOuaHzzHmhmhgQyZaNG7JHwpWM10UMzMawOwIDAQABo3Ew" +
+			"bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATAMBgNVHSQEBTADgAEFMBEGA1UdDgQKBAh5am+tkndt5zATBgNVHSMEDDAKgAir" +
+			"muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQAF0h1iaxxZUp43AjP5gSvbW6JfFRW/ugH9SU" +
+			"n3e1B29LMH3F/ML0joVhPx5CIVpX4nfaYzdeje9+E2/bHMBGSCFeHz9S/KoBLLiI0GNhzh" +
+			"I6MytvPMPRx7hkuROouQ69TnslJiGCcoo+MD0fA2YwO1bCtyLdeVHYhJZWQ2Sg8PHQ==";
+		public const string Intermediate_Certificate_2_PP_06_02_crt =
+			"MIIClTCCAf6gAwIBAgIBZzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDF4KSKxo8HvQ59E77LcuLpZ7ujNDjb30KB+EbIuRmy" +
+			"khXAkhq2Rp2Iqd3OhC0AXmhSF+enJq3h0dqyxNWP08SIuK5ia3OIeatl1UgEyukuAnrLuI" +
+			"A7PFUQAGZmDG4OuHv28zza4n/SwfCaKfi8qatIwpwF/29ycB8wYBrHThQD0wIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIKFZV4vjfOOQwEwYDVR0jBAwwCoAIeWpvrZJ3becwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAuj8P5ga8Xv9eFjk4AdRMx/Fj/doRAOLZfs+OnrduRXPLe7CFKDxhFx" +
+			"xYOma8In08cgXVVnRR+2nZ54h5qjCYpskGNx+yZRY8+HW3XXE3KpS7QgTnc/1XshUy9VGm" +
+			"2qX0k661f2d3KnSKiKVKtM/y/j/nNyxPugDz1Yy50NtzQOE=";
+		public const string Intermediate_Certificate_3_PP_06_02_crt =
+			"MIIClTCCAf6gAwIBAgIBaDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCitrzXkbO4hAQpBRQE880MFBPq84umX9pyKbV3iMqK" +
+			"Z7HBYwZOvEwGQxG+TX1PIj0Jz27oyvoqpLeMkbn9L3K0BuS0AZKlWIOGPPHWpYTDoQCCs9" +
+			"Mba1evVT/1CMxESsv2kgf49YHMs/6TtxQX0qj5TQzXrkM6CMBc5zyPBDWORQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIxLES0WIVZQYwEwYDVR0jBAwwCoAIKFZV4vjfOOQwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAdQeDAOFys//2xUFwBilhqr32/jh4gT/ijxRjG0msKTYXmWcCQv9Tms" +
+			"smtIMtiwwnByhjTdQAtOmEyDm/CFW0/NBnxlRvqZKt+PRtscpExVy7xnnm2MBITTa+9xkC" +
+			"A361jSDPnRPEOZoKdMRRzNnW4f59m0huibeFNRYJ7y8BnHs=";
+		public const string Intermediate_Certificate_4_PP_06_02_crt =
+			"MIIClTCCAf6gAwIBAgIBaTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCg0yQG7oewLD2eFfPuj2DPBgT47iEri2IVeS/r5hUD" +
+			"nZhxzT2/+UsQfiS+ufdC2Xq+QAcXFcAifPbvRs9xo2q0uLz26mwSq1TH8ilHLKatKwJ/Yf" +
+			"hcRAfEWDwhLJGRhZ7YrKu8xczZgyxwaeu5m38lEaLIRyaVfVSrw8WhN4z4ewIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQI/dKmuI1u6I0wEwYDVR0jBAwwCoAIxLES0WIVZQYwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAOEcMpdSAVKUzQ1A7LJnWOh5Tul6yXw6qMsdZNGOZ3vYBXH3vHnSHvp" +
+			"MqJQ1JIX/4XSiKF8En5dVI/ooNabgyORpPnLGDvrshvO/09iaDlQXxWRsoGAFhcIe7Ibp+" +
+			"3g6hnBO5U+0pbInioKVYf/1VyZSUK1QQMutshMIye/8gyZw=";
+		public const string Intermediate_CRL_1_PP_06_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIeWpvrZJ3becwDQYJKoZIhvcNAQEFBQADgYEAEJ28" +
+			"g5iyw3ZOqs5ly7O2X0YWtgKK3BnPztxygCUWO1xVy/QbMM5ybAU/UPbJC2pUnkOZMX+h30" +
+			"RYp/kV9w2o15V1hxj2M0tR8fQ0WXudwi20pZO56uHb+WSaETOmPVoNH5efeXsTvtbHQR5w" +
+			"95L2vNeEzJEy1l7S/sasUUoQvqY=";
+		public const string Intermediate_CRL_2_PP_06_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIKFZV4vjfOOQwDQYJKoZIhvcNAQEFBQADgYEApLIK" +
+			"X/YJYhSfn7yLTAlKjnhpH1QDlFeaE6/+uj6j7ZgpK6HBjHOvfwbrjurl+L3ZTLrY1FCL4/" +
+			"SUgXrJxbAyMANlg4Z8u6o73F9cur2gi3sgv5d6FjJ8VwuKYWY2dwZNeXwlWE/W0h01Vd9H" +
+			"QVuctFxzQaJQdQBadw/XqzvLlyw=";
+		public const string Intermediate_CRL_3_PP_06_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIxLES0WIVZQYwDQYJKoZIhvcNAQEFBQADgYEAE5J9" +
+			"wJKAb3veF4GhHeoIgy6JvMsrjv7d7dhT+ZIKq+wPNk1909X/Zo1GXxJSjMaMgkLlXa0QN6" +
+			"LtSJxbyMRCKSJfqTKOezFXirZ7MEQ04FT0z6Hp0m+E2Q7dGs52ZOV3YZBhQUlH+aQ8WNu2" +
+			"6clf4VqBiUYgGhkE95PhN5AAnOU=";
+		public const string Intermediate_CRL_4_PP_06_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI/dKmuI1u6I0wDQYJKoZIhvcNAQEFBQADgYEAKgk1" +
+			"HJ7OW203z9H7jNGxoLCN9bGDKOFcWlWuruzXWOAn+AomjSZpqZkZU1qyKrFaKM320sfn8C" +
+			"ZJPnVWaVMLBLNddDRWUjJrUHtNdnnZEuYPYlRVb0MmwaxHHR0ZBUIaniqoLuvtQIB9N++T" +
+			"bu4cjx33mN6MX0oWr4Bbq7ovPnE=";
+		public const string End_Certificate_PP_06_02_crt =
+			"MIICbjCCAdegAwIBAgIBajANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBNC1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANAr4hFku3Y6jI+vD6JTRFc7ZLL9tIxT7Mq+QcDd" +
+			"rRHgSEXhPL3MM//3ZFXca3w4rXOUVQyANQncywNM3uwl7T9jC0MD2kJ9PsNGQL2bQcSajX" +
+			"jrxT403PVFsa6ZrLMU0hwomSO4nJBLCJj3i1rlX9esYbRNCqzep2OMWgAWRUsrAgMBAAGj" +
+			"OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIMBvQP4Q8w2UwEwYDVR0jBAwwCoAI/d" +
+			"KmuI1u6I0wDQYJKoZIhvcNAQEFBQADgYEAnmNf+3jJp4mo4YDznASTMnrBBdXuskhnRXSQ" +
+			"Gj5dNq6PxEXM+CmBhaNlnFYcr7UCtcD8XwampfyO52tvAZW5kWQKsxyowVtsxtwkAtj6/f" +
+			"trIeulIM0B1xjyXJshmVST5u6gZ3OegsAyuqyAbo9B1IvkNFOldt624aEG43jq7ho=";
+		public readonly string[] TEST_44_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_06_02_crt,
+			Intermediate_Certificate_2_PP_06_02_crt,
+			Intermediate_Certificate_3_PP_06_02_crt,
+			Intermediate_Certificate_4_PP_06_02_crt,
+			Intermediate_CRL_1_PP_06_02_crl,
+			Intermediate_CRL_2_PP_06_02_crl,
+			Intermediate_CRL_3_PP_06_02_crl,
+			Intermediate_CRL_4_PP_06_02_crl,
+			End_Certificate_PP_06_02_crt
+		};
+
+		/*
+		 *  test45
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_06_03_crt =
+			"MIICozCCAgygAwIBAgIBazANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCrUMqMxZ4sSrH6sKv2y6nYKagLvUHaforCnf4z/5O1" +
+			"PeldaW4ANtNPA8SkVBES/zoKgvrLJUmqRi4b+BGhCVqLU77PvWyiPOS40tpJfw7m9pPK53" +
+			"aeaLC9M6rarjdOvF8MkdtytCMU/Ef1NsuJULwEP+XB90k4lHr9EzbgKhXvoQIDAQABo3Ew" +
+			"bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATAMBgNVHSQEBTADgAEEMBEGA1UdDgQKBAhF0iXZmlIKsTATBgNVHSMEDDAKgAir" +
+			"muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQCmab7noekyx5TzxAqWoQiC9S/aZJtvLkuH1p" +
+			"KiZnclMpRvIL1CVOukkzLTZXY0EcCHnXuVGjw+9vmiQWGGw8t6TGCXo/CtCo934HGBxOfQ" +
+			"MVysEjst7L7TDQsqxk4j9O8cU/TFWsghW9Ihu7SVIn8RJmknKMB2xkIhcDe8S8dmxw==";
+		public const string Intermediate_Certificate_2_PP_06_03_crt =
+			"MIIClTCCAf6gAwIBAgIBbDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCmT7wL9WwWBr1oY9bHIq4IrJOkbOARK3zOeyZSbBBB" +
+			"zxcky5kjC9pamMpyZjga+q0CGd2rq9eUjQ2FXZsBSgf/X9B0/g9trNMebYgGnYmHHX2JK+" +
+			"doyAX+h3afDbZzZ696S0Hw7yRx00+teQe/Gx4h4qKPwbJIW5Bep9SBysikJQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQInXHgY/+onu4wEwYDVR0jBAwwCoAIRdIl2ZpSCrEwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAhlboR5gzYWluWIaFM5R1Ko0/rprrv5BHONRiXjLfAPkzZmd7FLDE2j" +
+			"BlU7s7IenICeST4c7HG5zqBigK1814GG75nq5htCGUnM6pn8/gvc58+ckKeWgbJxC5I/0u" +
+			"olCCs8ORbWIEGWmghGg1USxeI1RQwXGgE8XwtabVibJOVBk=";
+		public const string Intermediate_Certificate_3_PP_06_03_crt =
+			"MIIClTCCAf6gAwIBAgIBbTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDEouRlqTFQiJQSwc+yhjpvA0dUIbRrNwLF+EPfUWq0" +
+			"FV1UV0a5lb5BGPW4RGUEbFwsgGCHsfLiY7WmUpC1e6332PZPnrnoJbf28paeiZ8KqcAKZE" +
+			"pGPWKCmFBwBW23q1w/v/CxcXJoBx5OC1yxG3fGH7CZSzc+4Z/+PxLk9yoASwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIc24GzUM6/LswEwYDVR0jBAwwCoAInXHgY/+onu4wDQYJKoZI" +
+			"hvcNAQEFBQADgYEANLxcLvJqjyu94HN+X6tTxGcN1s43kQh8yRGotW2ptuA2jmGlAhI8QQ" +
+			"sXHO0o0bFLBC/Uv0L0YlEJhK1w0ct7Awwn4UYgqupxug2f84yamcvFa1es3osIMJoi0GPz" +
+			"1WDBM711efRtbzvK6t/4fJ01nG2BlMeEbctVqrehuAip4p4=";
+		public const string Intermediate_Certificate_4_PP_06_03_crt =
+			"MIIClTCCAf6gAwIBAgIBbjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDNuzSN3BiT84M3Dy6KeTQkMqWNuYGTENWPP8WvQ0Ot" +
+			"ggue/lemC+IqYBtIEYtk3A30eKKnF28WIbPlB3oSykrPVV5dMhYGF9ysOtp4wyETHtzdv0" +
+			"7HyqlMHOCPiFplbwjUSo0uEIRVgS3luBJi9onTpcn97/i0S7VsM2nooooaowIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIDjpr8w0dRq0wEwYDVR0jBAwwCoAIc24GzUM6/LswDQYJKoZI" +
+			"hvcNAQEFBQADgYEArE6qUMnjXiB5eKiAFc9Elw1dYsQArtnDQAfFGtShDulxYKq9+pxory" +
+			"4kTMUZZCJc7awEC11tdJp7xJGcpjCJl4I2wBcHiCcVcnwQijqM719PqoQKydXB9MSrXqmU" +
+			"2CyakSzBpb82VooVNx0IZ3h0nXQSE3V0qSXXCaImJcOIGMo=";
+		public const string Intermediate_CRL_1_PP_06_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIRdIl2ZpSCrEwDQYJKoZIhvcNAQEFBQADgYEAQrHK" +
+			"VV2MJPJLNdPoEuqFXRTEclSmYhUWC5lthK0JnKUbCUj2cMAku2UdN5sRgVG0475dXV2nvn" +
+			"huxy+IQVt5OJ+PNZ9MYZlC2CfYsBiW9DEYMA603XhVvX/bxx80MwxNby18oyo/V9ycSyJw" +
+			"XzUmzYRUtohHk39r3eUSAt5H7zM=";
+		public const string Intermediate_CRL_2_PP_06_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAInXHgY/+onu4wDQYJKoZIhvcNAQEFBQADgYEADOEh" +
+			"jV8V8y17mFstkVwigOAKURbi7sD24RkLd1QG0Bn21JiwpkGY8Z4vetQps+VX586xKzz6v6" +
+			"Sj+TJk3jfHCiEAk6a7PLxRcVCCi6y70mzEBCwn6fS5NDfxzxYYLgq+dlUiVwqXsHksEvUz" +
+			"2Z5dpuLhbUGxHiqazNE9iq9pEEE=";
+		public const string Intermediate_CRL_3_PP_06_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIc24GzUM6/LswDQYJKoZIhvcNAQEFBQADgYEAK/zi" +
+			"r7ASgtWA0xGQVrqhHsXH9bdaj+FceW6ivoXo3z6xCFLvzu2uenEu5g849+YI0KMomHsDAY" +
+			"tX8qO3XEaLGchbhIfywgRVDlSF8ytMKhJTS05R/vZSZAl+eoT3mC92Grihsd3wublyNZ7a" +
+			"d925Py/oFp3J+geUkKJQK+RVu4M=";
+		public const string Intermediate_CRL_4_PP_06_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIDjpr8w0dRq0wDQYJKoZIhvcNAQEFBQADgYEAcBag" +
+			"81RFYMBAf8aRP5VXPcfu0OxgJvVE25ZHGLCkLD4TPKAXMjZMHWrf34+5FW7aigDO1YhGA+" +
+			"2zVtVj8k71DichiCCGXQvH50AqFgeNXNQwn9WcpQ8rRkfmyhlccfeM+MzHI1giRw/RjvCN" +
+			"0dfJL9g3c7peW+VCKn85REZ1ne4=";
+		public const string End_Certificate_PP_06_03_crt =
+			"MIICbjCCAdegAwIBAgIBbzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBNC1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKBSOacrUg5H5yuISkqmJuQcK2ao+Ib0FmIKCuek" +
+			"8mm2HEiux+K5/yIAYsQnz9eDKzKWaS73exPniKOXABHaL6dxsptbdBqWB6II2kIl0BFz9P" +
+			"82qjz6DMwpUhj5Pwfy5q0Bz8grTe31ZYP19y8AHgcWna+eiY4fNVXVkIEJOJ6tAgMBAAGj" +
+			"OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIaZQ3Q55so58wEwYDVR0jBAwwCoAIDj" +
+			"pr8w0dRq0wDQYJKoZIhvcNAQEFBQADgYEAnNYKc2pSFZ9PtR4gQyVI3j+gQ97tcWu6Alxm" +
+			"4T48fSb2KtFGuozJyCv0aYjtuZ9ava9r4v04lyFPoAjWYbALHC9F+vz7JLNr4VstuMdy5O" +
+			"ax+PvJjKGACSXD7QjXJ48qvm+v8OnMbkzf8+rY3LoTJ2KhXo9Ey4+UmU/YuZ0PXuY=";
+		public readonly string[] TEST_45_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_06_03_crt,
+			Intermediate_Certificate_2_PP_06_03_crt,
+			Intermediate_Certificate_3_PP_06_03_crt,
+			Intermediate_Certificate_4_PP_06_03_crt,
+			Intermediate_CRL_1_PP_06_03_crl,
+			Intermediate_CRL_2_PP_06_03_crl,
+			Intermediate_CRL_3_PP_06_03_crl,
+			Intermediate_CRL_4_PP_06_03_crl,
+			End_Certificate_PP_06_03_crt
+		};
+
+		/*
+		 *  test46
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_06_04_crt =
+			"MIICozCCAgygAwIBAgIBcDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDFoR/YTJlGYenu2IRsTiT6jwIA7yOnFbM9JXcqYIP5" +
+			"jSgtn/wVztPHgVWP+582foXJ+oEcThQVZ+RBXYt6VU5o7eVCsGJjqMd0DbRzTO+poelVoY" +
+			"1UEJMrKG0xSEex0T6XLQ+jPU9o5tlXoLYsXvpvbIrCJ0o8kuk4MWTzenDKJwIDAQABo3Ew" +
+			"bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATAMBgNVHSQEBTADgAEAMBEGA1UdDgQKBAgVwXynYDSYEDATBgNVHSMEDDAKgAir" +
+			"muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQC6MnYM9cY3CNb7/KKZvoaSwF/Se5iZYnbdPn" +
+			"WCnKydnN1AhlDN3kEw0gjTmZo/MkvPqku2aPzg5EiZ0eyeJaR6a4aiICU9z/Hiet19mBF6" +
+			"BtAUdt0fJ7aL5WPAc4BKXUbONd6vkQNv8uLcBmsqZ4wXDj7ZVBMGKcuDq7uClb0xYw==";
+		public const string Intermediate_Certificate_2_PP_06_04_crt =
+			"MIIClTCCAf6gAwIBAgIBcTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDHqX/4IZpOCsHWgdJ6mICN94nXz/KqsXPNymadVdZA" +
+			"nVU0fHdMcxehAvsBKju5d791Psly1Xyyda8KQ0BKPgGed6jNKb89JzuEtPBov0VMzskqwR" +
+			"irjaDCwYKtibiDe+T/kEN9Sq5pbexHcaTbAIeQrAIoSUmGdQ/Up6PYplb0jwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQISKcQDqdBecUwEwYDVR0jBAwwCoAIFcF8p2A0mBAwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAkAQaOoZYAZOCk881Ro+SIclAj2lp+arAkWPP/gwN4/0lpH62eWqlmY" +
+			"okWRBjk6+iwCgRxQ56uUjJhE08p5juZ5V32ie3RW+S1ZBPtL/T/+Tqp9HNQQ3GjW1yc/yI" +
+			"sWQxrd7QKzTER37HBiOr5WjEjn+dzuWlJtClcQetqMLtMgM=";
+		public const string Intermediate_Certificate_3_PP_06_04_crt =
+			"MIIClTCCAf6gAwIBAgIBcjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC2tnVj8KHGCm8XBPvDYWZMp3yOKQxuORze6a764qIC" +
+			"hkdO7hQbgJ9YiuAF/y62W17FnbhKPX6ninaZG0N77bznKvivSC3+T1jIVhw+kpxRh9MRya" +
+			"L2p+zHJEyO/9JaKWzJZiVi4kebW+hwNgSZc7FSYsAbW7lr4ujDei/yn/AJEwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIaAEiWf4JpfQwEwYDVR0jBAwwCoAISKcQDqdBecUwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAHNsZDCWtOqt741IJNA9OwpymTA4ES1BRJquEvGj5+4RH2pxi67bYd1" +
+			"kWTPF1qFC2R1sugSNhbU0wOBMdKUJtKWNacPsK0HbD7CPqt4THOcMXFO36b/2gqHqy9rc/" +
+			"slWuIwbtT/tEC+Mk67GEATWNPifoPT7TjWHM3RhsDnagZXw=";
+		public const string Intermediate_Certificate_4_PP_06_04_crt =
+			"MIIClTCCAf6gAwIBAgIBczANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjA0MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDgdk/smDJ5yZYJDH4SG7pIDCzGNZeLO9RI3ybOx4/B" +
+			"M3YQu3DDFSOv8kq6PgL8ThC8Dk6t1jSbT8QVzaGgx0KMV3p6pIMdaVNkOjVjUb+L0nXVfr" +
+			"XYpFLON6tZLgh8oIbiz4KznKmsxo6VdYwyUeHmkpGcL5y+8qLspCNdRJnDGwIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIgSY376EamQowEwYDVR0jBAwwCoAIaAEiWf4JpfQwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAEztvmGSVnDGGeNlIoR+wfRM8ndJogvUxLBZm4N96mDZ9Y+Nr99Dqvw" +
+			"+mMI3BU0miA5kDO9aFrKIgow3cpruoedhnBUsxTfhrNaFEwp+ORUb3tWn7sSxLfnTim4Vq" +
+			"y6j/EfUK2CS4ZAy7J5BADWSqDezPnrb5UaY1JFKMuLyGRac=";
+		public const string Intermediate_CRL_1_PP_06_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIFcF8p2A0mBAwDQYJKoZIhvcNAQEFBQADgYEAPlIW" +
+			"SxwW2LE8qxeD+M+HypNwai7j9XxUA2MhBbGVnsrhH+DKX5VeyP/nyZn2hBoGWhs05IpG2P" +
+			"S0odnyhbgGSXSj+IOfkZkVT0BmuEJmqv75R15LBzeyONks+eSEhoOIGAaIN4WgJ5mzjSrI" +
+			"ddDu3c4s6QO/OFVrNF1F6e4laSU=";
+		public const string Intermediate_CRL_2_PP_06_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAISKcQDqdBecUwDQYJKoZIhvcNAQEFBQADgYEAE5wt" +
+			"y3+jVnr8de/Yi0LV70v3JDHimwG2pQcuDRhR1NLPr4oC+2uxMqwxVzdHITDb3yI2ZT9pVh" +
+			"PV3UvX85avMdA0/JyaMWSKNpbSah1eNfMwMBY2vzh1Q7f5n+7HYYM+I2kz7HARPvwsLP9d" +
+			"j4mY7Kq7uiOFdnQzJ6LWjm8qEMs=";
+		public const string Intermediate_CRL_3_PP_06_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIaAEiWf4JpfQwDQYJKoZIhvcNAQEFBQADgYEAOm2f" +
+			"m3IdcDnIS915tEZzDmIbTFPBkIn0wjUreZKb9uNxE2a8Jixq+UP2uiyYWiWmXnRdVB1Gsb" +
+			"ofc5f8ctNgSPVTSYB0U5apIauXjV0y7WMUrLNrDFa5m9lxLRhF9kvXVL8zPhVfMpujnXre" +
+			"A8WS4UjDMuveyQL6yASGoZvB+Ps=";
+		public const string Intermediate_CRL_4_PP_06_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIgSY376EamQowDQYJKoZIhvcNAQEFBQADgYEAznK9" +
+			"ekskl4uWU+2Xqp3Pj14wvXuzfPAqFlHR0jl5By7T82JRiRa6LGX6T953vcwwJBsYG1hMqH" +
+			"pgbnUGB8APQ6YNXN+7ZkudaG6fMVX6bCr8zT+nVSj7PHIK2VFsC1Jpm5SoQMHH6DFit/oH" +
+			"tm4tdV8+nupMBQn1ZtxQHgUUF14=";
+		public const string End_Certificate_PP_06_04_crt =
+			"MIIChjCCAe+gAwIBAgIBdDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBNC1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDQwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOCVJmtrW8Z2WGGRNjEgyp2NJn1xaIVDwlxL4C0n" +
+			"UAPpo1WM/rarQTYejT2Yo8H39TdRfiAlggF0Qsce0W//atey8WewGsFlUem6a4OFwg1X2h" +
+			"CN/COL0eC4a6lwkdOKmqgxSyWNWeKxXRTM8+EYQIem78uY7A8XuzVUmOpzYWoLAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QION6UOZ2Eky4wEwYDVR0jBAwwCoAIgSY376EamQowDQYJKoZIhvcNAQEFBQADgYEAXota" +
+			"1N1UrMxj2a/vdII92Wi8uEetcHo9vmiJVYxwPFkp+qo1q93Ww8Qnfp7xzaZwLgVoUOAF8U" +
+			"TRUVnzqoSwmRrfyEMfrgej3eiBjcU+zS9mNlx9mUUSLmlY+xMeejyVDCntRn6YJWWLesVq" +
+			"eFOjyNux97/XnGT3T1w0J+wShu4=";
+		public readonly string[] TEST_46_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_06_04_crt,
+			Intermediate_Certificate_2_PP_06_04_crt,
+			Intermediate_Certificate_3_PP_06_04_crt,
+			Intermediate_Certificate_4_PP_06_04_crt,
+			Intermediate_CRL_1_PP_06_04_crl,
+			Intermediate_CRL_2_PP_06_04_crl,
+			Intermediate_CRL_3_PP_06_04_crl,
+			Intermediate_CRL_4_PP_06_04_crl,
+			End_Certificate_PP_06_04_crt
+		};
+
+		/*
+		 *  test47
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PP_06_05_crt =
+			"MIICozCCAgygAwIBAgIBdTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjA1MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDMIUtQ/CgudxHAwAAn8jUsdAY8u7WDslOC4nNbWn5C" +
+			"tILgZ2hGIZhEnhzP+VCV8ke8zLo1DX0hCRYAgzk5XTGAimExHFv/yDdhpJWEnqMRljkCHx" +
+			"Hg3XE1439qutBdmWvGUlRF0hQrd9Q/Ubr+PjEzP3a0EUmXo7LYuQKMcFsC4wIDAQABo3Ew" +
+			"bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATAMBgNVHSQEBTADgAEHMBEGA1UdDgQKBAgha8GqGbO1nDATBgNVHSMEDDAKgAir" +
+			"muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQAEG5C3P1A/MYpNJ0qvi26v04GGUWDQWRW1q9" +
+			"1392XpAxDdv7kODf1FUMpfBpcUblagxrX7Npthv6/6W8poBTjvJuq5BfnnOMQrCwnsNfRy" +
+			"Y7b1mAZIvcOBhWe+bFVqRLUqZ+JseWkw0YgZIGtX41Znwl0VcFQKJ4lNkuaBgXXdGw==";
+		public const string Intermediate_Certificate_2_PP_06_05_crt =
+			"MIICozCCAgygAwIBAgIBdjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjA1MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQC36j0YkXZZSw3qQaxD0g2BfrKYperkGjVAfLwOtOxB" +
+			"0A3Ufx2ECl/MqNOvi/QWlTkKwnrqw0aEnD25iS1DFM4jMZBmdfJg80oa+y6TJoZcIb+3bv" +
+			"SK5o3ArCFWkhTHHggIIY3H9dQOgAeYQF57Vb0iu59GPfnYJO8y8ZpxGIYcjQIDAQABo3Ew" +
+			"bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATAMBgNVHSQEBTADgAECMBEGA1UdDgQKBAhUpoGZzfV7EjATBgNVHSMEDDAKgAgh" +
+			"a8GqGbO1nDANBgkqhkiG9w0BAQUFAAOBgQAjrFHzC1FLvssJTfV5YsGfw7Luj4EqLDQd6b" +
+			"MgtBSwPnXqMTUAZpDETyeYvcgM+L2tasB26MSy6IttSKsaJpHPCP+BIs0jji5xosuCX6Cs" +
+			"wI2gE/LjF85rjZnldrlDShw01DlcmWlWwudit/ieO71Xc8i0F4EhSaTUJX12po5Xkg==";
+		public const string Intermediate_Certificate_3_PP_06_05_crt =
+			"MIICozCCAgygAwIBAgIBdzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMi1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjA1MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDFWhChPQNFYQpLBmVmXSGF2py1wcfhZgZurv0E5AgE" +
+			"BZwBo2bxSeC36lBQyR3OABGI4nQoEegSQWwuS2Pk3+emG2MZ8R5QINAkMlAKTp5Gj7KTlm" +
+			"3VVJRx7/VduoFx8sZPjkpvF1bSL+KOH4UZny1xqqTj4bJ+oGu58INeSNVa+wIDAQABo3Ew" +
+			"bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATAMBgNVHSQEBTADgAEEMBEGA1UdDgQKBAjN4PvsHY9+YzATBgNVHSMEDDAKgAhU" +
+			"poGZzfV7EjANBgkqhkiG9w0BAQUFAAOBgQA8KmWbAQOnM59zry9TNtLbA2P5y8R/sO771S" +
+			"yQYcu6undt9t7UEiOepDp/z3CGsITm9RdtXAobZ5ZqhW+3Ll+UnML1itiCytOPbfC7iiUO" +
+			"S5jviQnpgJncZD2Lp65yNAB7lMmMleFO15Bsk8VNmzMDMsFtzo508Bs6T33ZW69/vg==";
+		public const string Intermediate_Certificate_4_PP_06_05_crt =
+			"MIIClTCCAf6gAwIBAgIBeDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMy1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjA1MIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDxx57R4j64xdbjpTl7reLby/T2ym4rESC90aBkC2/E" +
+			"/YUSjsuGG9GiHEVgoGzoQGQNQV0v9ZMIvuoI6q7Fd6VZhIVGE0MGzTFNA9QEEDGPc10ZxC" +
+			"Gyh9mZYp77PMuhQ12Iv3aDW9KNTr09+HyhK7d3Se7toXLwjE5pKt+A4ZvBFQIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIwmq0fugIX0kwEwYDVR0jBAwwCoAIzeD77B2PfmMwDQYJKoZI" +
+			"hvcNAQEFBQADgYEAbAbRorTyh6zfAmdg0lfeZyCyW9k4NWfhUs46iSOl6lkZH8c1eoAF5/" +
+			"q0pOF+CtI3F9VMhfUXChEbVj7QENctU7kDiFe8300OWD5h1VUi+WTK4CG7B36/BjkrVOuG" +
+			"Os76P9l1WaC+/WRZdcqgFMfPjpn3R179dImBDwZiCMMbVqc=";
+		public const string Intermediate_CRL_1_PP_06_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIIWvBqhmztZwwDQYJKoZIhvcNAQEFBQADgYEADX3u" +
+			"wxpN+p8N2HqmhFw8w9LCeoR3Xa/uaqgqh4i/VkDuAC4Bi7VbIO6rcxDO2uAdZgNhb/hnRq" +
+			"cvKLcy0vrovCa2EPHcFo7dJl7si2q09EeuHT4+lZt/Ek/VOkwHhvh2o6yEvKOGXCnF9hZr" +
+			"8YbOIknboEz+tRfxoJArRBwpJkE=";
+		public const string Intermediate_CRL_2_PP_06_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIVKaBmc31exIwDQYJKoZIhvcNAQEFBQADgYEAQz7u" +
+			"dfU4yAHFLH5BgeZkYh0l2lZ95af+E/67MSCjQSF7RWWWTffbDMc4HmiRlZLvQdltyGCKmi" +
+			"kuzcPP8vyYOBQmoIKQ6c2LItBjXVavLdpe91yCOhCWXVVlnMFq5ztrvBEpfO0GVUOnPWfG" +
+			"1Ugit3SEd4DbhYFTBYHbbOKRWsU=";
+		public const string Intermediate_CRL_3_PP_06_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIzeD77B2PfmMwDQYJKoZIhvcNAQEFBQADgYEAkiW6" +
+			"h9a8v+IITd+p0jxukj2FYfmED59ZXAlYhQdQAGlPE71rOXn6ZPURYoGf7qlmBwQffpksOb" +
+			"Byb+PX+CBTUNXzhgTzD7ifM9xOhCEKVKai9acQfvokU56OHwfq5AnkRykLZ7IdvdYCP57k" +
+			"ynrNNV35dsMZXg23/PpreumlOkE=";
+		public const string Intermediate_CRL_4_PP_06_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIwmq0fugIX0kwDQYJKoZIhvcNAQEFBQADgYEAnTbS" +
+			"MBWyoPaslaLpAMmJ+D6kmmKAdRYurA0okU/QP+0W+YNPV4DducAQUDy8Cg3RkpRK2ze0ad" +
+			"l6TUW8g83hj9TXSBp+XZuVvzerMCjOeBqhskZN4Ly8101ZZmMmdYdSc3PEhqkme6iZzjwB" +
+			"ZooAN2dIYjuBj1c1/t5qH80CMAI=";
+		public const string End_Certificate_PP_06_05_crt =
+			"MIICbjCCAdegAwIBAgIBeTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBNC1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDUwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALyVMklPv3uwTPzLG70sXIwKSEt65yiU71ibHyhH" +
+			"wJ/6dXy3HK2UETkRBK7UVSOYq005EbO9s/3oR3zt7QTFifvRTsIjl1L4TCLC2a8ApBr3BH" +
+			"xmBWcJDf427Pk1fm5qDdEmZnpyIlpKaKIiBcdtwZfjr0lROL8RNcvgtJPdu/ndAgMBAAGj" +
+			"OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQISjAUfyAwSA0wEwYDVR0jBAwwCoAIwm" +
+			"q0fugIX0kwDQYJKoZIhvcNAQEFBQADgYEAC6Af3cJUh/IQgWdbC2Vmk96sYjDlAsbA2keY" +
+			"J0bgBcNaIVoJ/W0B3rSawqSU+Vv64p7kcuAl6cbvIXPB++19V23jj6HUs1JxtPJZ9IWkS/" +
+			"FRakv6lD7+j1OdzJvDR8AMZWmPFHJdQnJwQ+I1YOU/O/ShawOnGCmihpIULUINFhk=";
+		public readonly string[] TEST_47_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PP_06_05_crt,
+			Intermediate_Certificate_2_PP_06_05_crt,
+			Intermediate_Certificate_3_PP_06_05_crt,
+			Intermediate_Certificate_4_PP_06_05_crt,
+			Intermediate_CRL_1_PP_06_05_crl,
+			Intermediate_CRL_2_PP_06_05_crl,
+			Intermediate_CRL_3_PP_06_05_crl,
+			Intermediate_CRL_4_PP_06_05_crl,
+			End_Certificate_PP_06_05_crt
+		};
+
+		/*
+		 *  test48
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_08_01_crt =
+			"MIIClTCCAf6gAwIBAgIBejANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA4LjAxMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCp2vHVX08nyKe+S8NPkNJOZ9Xng22TbYXhUHtXw9yv" +
+			"ZmPkRhwDrZfBLXZcdZFixidkky3kCzv8Q3aPyPByM2ozH+AHJzEMbwifhyvUbANcS+Jts3" +
+			"lsZHarN7VyiXO+8J2OtYqX9qzmrAOHGleB2cJopEcmAMdrzgt1JIo98SUs4wIDAQABo2Mw" +
+			"YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" +
+			"FlAwEwATARBgNVHQ4ECgQIoRYqHNcbLacwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" +
+			"hvcNAQEFBQADgYEAXchRFC94Pl25d3Kl4wBcueQLyWPRuH9zS0ZPLAqKLcWVdcg3fYMuJ5" +
+			"SypMMpxLaVjN7xq0KjML1gLiPQPk18iA2TOAUMblvjUl1uFzDdD6SqQidEZh2h3wxFtbLP" +
+			"U7qBBki7i1+Xn072Bpn2paw/vlh4K+ut0tFQ2BAhqVnQGJ8=";
+		public const string Intermediate_CRL_PP_08_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wOC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIoRYqHNcbLacwDQYJKoZIhvcNAQEFBQADgYEARyX9" +
+			"2+LoXD2fIAACBMPDgds6m3Equ+Aawlr0kuppPO4ydCU4kiEgtVGK+kY5GzP6fUpAKjC8mh" +
+			"BrozojhAbkJekDoN0BIJ42Iab70VmdWXRQhPsUDhQwEt+9eSgy+HfiFfpcL1VJx8uY4XMh" +
+			"VB3hmapIe99P/T2QkZ+Pl8j0MgY=";
+		public const string End_Certificate_PP_08_01_crt =
+			"MIIChjCCAe+gAwIBAgIBezANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wOC4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDguMDEwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYtrtpgxNl+9jF3TN1B9bSEGQci+cQOKpFsmrtF" +
+			"AyiGBxKONgGSgSFFuFIhyBKZF5ROaKX1P8lsQkrpnuybUi+Z9ADdyoaLUDD/z/kp5sebAZ" +
+			"ujmF8HVlqHYj5Ls2smS9EdSN1zgPTXIOTeZd/lv1iFppRZv6cBqlaoapQJsb1JAgMBAAGj" +
+			"UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" +
+			"QIZjcOdw0ZTCYwEwYDVR0jBAwwCoAIoRYqHNcbLacwDQYJKoZIhvcNAQEFBQADgYEAarsn" +
+			"13/g0vOKxy0okOp2JXEsPdsP7aWnCfR8N4+7gFD6dVnkgCIyc5Kbs7MbhB9gtIxYhHOV9W" +
+			"MaW9QAcBH+eXciFDfQBfaMBkL34ssE/TsZ92r/bhBwKRcH54f96G0QWUnoNMt4U/1j2mKn" +
+			"faFirltqEPUu9mv4FiQ0pNT9yH0=";
+		public readonly string[] TEST_48_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_08_01_crt,
+			Intermediate_CRL_PP_08_01_crl,
+			End_Certificate_PP_08_01_crt
+		};
+
+		/*
+		 *  test49
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_08_02_crt =
+			"MIICojCCAgugAwIBAgIBfDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA4LjAyMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQCmAgNA68ABUEppM9Oo3guiGvguvtrWQzsQIJfMBrE4" +
+			"/Scwc4SPK4PiJD+kVwtXinXpVclBMQge10uZ48lSJTihfZscJw3RSHt70H4CpPQm44QS7P" +
+			"7fQqpcZKZvMWmY6A8jju3Phbuq2WgJCIxxVw886GNIAXW8C4ZFmXCjwiGGHwIDAQABo3Aw" +
+			"bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" +
+			"FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECOhZ4RAlqGGcMBMGA1UdIwQMMAqACKua" +
+			"6/nC51SPMA0GCSqGSIb3DQEBBQUAA4GBAGEVSOcNaUu50f6AgGBtz1MDdRiHe08W/nzCNn" +
+			"0K1/UqrIXVJ7IYgbOLkL3cdHy4PdngCyEblzl5Cwp9chh2zL0PTUbV1uJIBW32ks1HuAVQ" +
+			"FTZqx0iuopY5AqRCJVDJt4HB5PKObwnmLPNWicI4Juap13j/Tcnw1EP7E7n6OejC";
+		public const string Intermediate_CRL_PP_08_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wOC4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI6FnhECWoYZwwDQYJKoZIhvcNAQEFBQADgYEACLHw" +
+			"iDARFoF4GauIHnoZlfj6nlOHAFfNSXq06Vvl713bsoAiOSV+2goZjRG62uxhampE+gCdXx" +
+			"1nwhKQ5R5jOGGOxgLtBFNZwKmD0KiDOSvfIVJ0kYCcaB4mSm0a/7pcCPrrE5ofvkmTW6Wx" +
+			"k/YIuBZdDoqZC91v4tnu0fSch9Q=";
+		public const string End_Certificate_PP_08_02_crt =
+			"MIICkzCCAfygAwIBAgIBfTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wOC4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDguMDIwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJsz8ys71e8UB+VDTBAocVQvADiqh0LjdML3pET" +
+			"B6VvikiHgbB1PJufxDses+v0WD74ChZEa/octNcMFqMgBlhVBEfvbyGTjiN97LzdZ7SPyd" +
+			"DsDulqwBG9sACryUGHqwHYnUbjOqsThOXFB8Sg/CGGawpZAosm2AuH2gqNvNuJAgMBAAGj" +
+			"XzBdMA4GA1UdDwEB/wQEAwIF4DAjBgNVHSAEHDAaMAsGCWCGSAFlAwEwATALBglghkgBZQ" +
+			"MBMAIwEQYDVR0OBAoECOiMLE2l5u16MBMGA1UdIwQMMAqACOhZ4RAlqGGcMA0GCSqGSIb3" +
+			"DQEBBQUAA4GBAFf4BCbNtduwn5InkfdtFbQOqhPLAn/5eIhxhVhUu7TekWT7ktdaVQFzGF" +
+			"G2h1+gXgFP+YKjJy7kGzEVQjlWtuC0l74EwybNHnYAoDg4itKe+0OSNNXdyOmn+i0tE0nx" +
+			"sWN19VvhLGFC8p38gd0oDr1ziYdg0z2Mx4IlMDxl7QhT";
+		public readonly string[] TEST_49_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_08_02_crt,
+			Intermediate_CRL_PP_08_02_crl,
+			End_Certificate_PP_08_02_crt
+		};
+
+		/*
+		 *  test50
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_08_03_crt =
+			"MIICkDCCAfmgAwIBAgIBfjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA4LjAzMIGfMA0GCS" +
+			"qGSIb3DQEBAQUAA4GNADCBiQKBgQDKZDgBum5Ud5i8HWlCKInJ1x9goZ7TQJ+LdfA9iGU1" +
+			"47xJL5eFcERWy4dr5wM5GNRW/DHXlnA/qsRVE29EuRh6qAVgcPGAfmJxz7s5yhmErfmiQ3" +
+			"0rh6+pma/EhcjntXqwIqnk1qt6mEk7x9UKO3ksFCVsDEA67/dvownjcZB59wIDAQABo14w" +
+			"XDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUdIA" +
+			"AwEQYDVR0OBAoECGtTrZIwYYHbMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqGSIb3DQEB" +
+			"BQUAA4GBAM3t13xJJraRiJDAwZFxhTNR570wMdSRiF3yWSRtOjEv8NTVFj/T1oJJ8h9Gqh" +
+			"hMpTTHU7uGCyVB9S1HCelmS+1zteKr0B+WVzBl9yuhvku3farz6zgIVK3v5hQ6xC4H4Lac" +
+			"NDhTTKBkRfDf9KskFoxJ/AGxPdZtIEC92DFSblQB";
+		public const string Intermediate_CRL_PP_08_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wOC4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIa1OtkjBhgdswDQYJKoZIhvcNAQEFBQADgYEAcUHo" +
+			"D00X/pd3D5KGa5C6dY18RsnUovkjUkegGTpbhQfmYZIdBatj7Kv75FeUJ9UpqCUjxHgdiE" +
+			"EVy60NLVGP2VRuJ1m8vfDz8hu5PaiVjneQoRw2M9ieBnz3PjSETDdBGJLWHyCBZbp/W2+0" +
+			"iqcZK7Fm9O5EL4PUO6QIwuH76q0=";
+		public const string End_Certificate_PP_08_03_crt =
+			"MIICgTCCAeqgAwIBAgIBfzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" +
+			"UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" +
+			"FTATBgNVBAMTDENBMS1QUC4wOC4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" +
+			"BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" +
+			"A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDguMDMwgZ8wDQ" +
+			"YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsXEPrCg91CObTl5OrHIB5GshIDXgqBmjzxfWPK" +
+			"ih4STWeBe2eIFO9pONXcM5lstEu2XLBPP6QBMUMWOrphJejrJ3eDQHs404bBnt95O/x17i" +
+			"665CZtg1jUqoO1kOBOComx2AJGZ46RdBExbfd0tTtdHWtRhMsnQchI+WtEyotdAgMBAAGj" +
+			"TTBLMA4GA1UdDwEB/wQEAwIF4DARBgNVHSAECjAIMAYGBFUdIAAwEQYDVR0OBAoECEWZkJ" +
+			"TYQ3z5MBMGA1UdIwQMMAqACGtTrZIwYYHbMA0GCSqGSIb3DQEBBQUAA4GBAHki/TrpHiKW" +
+			"gvERhguQ/uOqHHZNXsog+fgGVFFMOWwJ9bq4aHKd1fDZpyZF4vBxW7llbhuSt+ob2TNlkR" +
+			"wkqzfGL+3xOTKNRgzDwJcil8akC1N5uBftrQk+eL7rM1PezWRM7fIbpmv5ZieIVswtTPF5" +
+			"1Rl3G+JXUBy9E95espls";
+		public readonly string[] TEST_50_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_08_03_crt,
+			Intermediate_CRL_PP_08_03_crl,
+			End_Certificate_PP_08_03_crt
+		};
+
+		/*
+		 *  test51
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_08_04_crt =
+			"MIICljCCAf+gAwIBAgICAIAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QUC4wOC4wNDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsrM3A06j1zDz6VuZh+O2UrAPcKtwSA6KxTShUpgr" +
+			"t9UB5iIAEvxcDTwDlubEv/cJjDcFj9N57otzW4ppnuT2ztE4ROmkNb0xL6u00deS1yGjXB" +
+			"wy1G9g8bYDdAXOJlv0tjHOBqXlyKoMny82BOBL2vsCstiqxl14Q3/wBD1w29MCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAMwEQYDVR0OBAoECJiAkexK6/c7MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAL4xwcpXZQPTTPYIQ8CMoVla/5P1x6BPmPqSkvh1D/o4ds9Ll9kHBz" +
+			"//X1ZM8SzYcEO+1r75JUzoHsvDw9yYAk2oclLsCORAPqD8Owhv3jv0QQtYSmf0Sxt5FLx0" +
+			"MRP9keY/DURRf9KitO4glOawtRtYMq2BeeJk1xusY0KqEnQr";
+		public const string Intermediate_CRL_PP_08_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wOC4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAImICR7Err9zswDQYJKoZIhvcNAQEFBQADgYEAcN3a" +
+			"jIEcXsQatb0fvVcFnO7d7lzNtgbqL3MtaqJ/PjkRJ/rO7JAXQRwdajUZF4ECHylZKE2HUG" +
+			"Dk+vidV98T8mNmb0TEuuLV+J1G0q8ezMXRJtDt/2m3y1VBireXlEMd1DdgpsDdCQ4va+XJ" +
+			"qv0TvVhfxWry+LrVb6Bf5ItexXg=";
+		public const string End_Certificate_PP_08_04_crt =
+			"MIIChzCCAfCgAwIBAgICAIEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUFAuMDguMDQwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBQLjA4LjA0MIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPJWa/cB7WW7tkGxFhcwxqE+BycXe3Ru2qGbun" +
+			"NPQZ/j44UT2C6rl1wZwugCY0sR6mXR/P/NR7czZvg4Tt6lwcNtc8PeafFMUeu0u0Kg9uWn" +
+			"fzQQKeIgRVcEzGTGMPGWXS0ed6X/1+Dj8A+T/tqXKUtM3Jpe0pCmm9CIrYCXLPRQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAQwEQYDVR0OBA" +
+			"oECKm9IOyOM1h+MBMGA1UdIwQMMAqACJiAkexK6/c7MA0GCSqGSIb3DQEBBQUAA4GBAEXy" +
+			"dlTkkZaYK6sUJCiPeCPxfj5cdo/G4RGBImMJbTeDyVTvXSH9G2yWUMqBGnYLrwdJJeXjF3" +
+			"89miJgnJ+1r/r3r2/NeAUuJDsOHRMFh0KXFmgubyw/kGsZBe3279hDnND8ZjfQBmKQD17f" +
+			"PycWTTAC5p6GM8tGERiDSnMc5rmm";
+		public readonly string[] TEST_51_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_08_04_crt,
+			Intermediate_CRL_PP_08_04_crl,
+			End_Certificate_PP_08_04_crt
+		};
+
+		/*
+		 *  test52
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_08_05_crt =
+			"MIICljCCAf+gAwIBAgICAIIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QUC4wOC4wNTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwH2d+D0pH8y4QJAPpE0s2oWucV1jlE4pBMGNNPJ5" +
+			"FIRmyRCt90IpzmK/EuqT6iSZYd9hIB9wa180ByN67PK1z4loLFMUL2RmbWeAFlGy5eEFOy" +
+			"4d479qfy6JCOzt0TKhYzhukLUqGLa4DDTzvnnUx0o86aLvGq0K5s6DRlNyc08CAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAMwEQYDVR0OBAoECDSeuxr4EVgaMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAKoGi6qlODB8Lc86PtGXfBhW769jB8xzgmENE59sqNBEvYa/oK9Xxm" +
+			"1JX1OGEQMq/mqwZXg6hSczpexCIO4tUH8QKTU68yvqcZoZCDV8FLM8aEUPtUoPIpluhAtN" +
+			"scGfb3uXoV9fg7q1Pi5YlKMnNrDIq1tH1CAGKMDRrjW63Q8C";
+		public const string Intermediate_CRL_PP_08_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wOC4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAINJ67GvgRWBowDQYJKoZIhvcNAQEFBQADgYEAv5Hs" +
+			"nYPZO1fGC/Z2lIbbUKjIv0+BrR9HbG+b76wXeJTVxfXMlZe0cpOR/KD29DyxI3G4IedHRy" +
+			"zL8iCDWYbA86arJzl5GZJ1MC2A586vNn/6wiiT6nP3iMj2z/nyvan8L30KNBm9IDXQExOu" +
+			"PNE/wOWYBxxCjg551fpXfJKqDIo=";
+		public const string End_Certificate_PP_08_05_crt =
+			"MIIChzCCAfCgAwIBAgICAIMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUFAuMDguMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBQLjA4LjA1MIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4BZFTwOqI+71v8CdiYbe7x0qYveN524h6+iLh" +
+			"oEqvzuVKVqvQgVSaSLPcMhoCGDv3nqyP57Znl/3I09vLU6F4HKLtjO9E0PZu8EXOKLjeWP" +
+			"XmJQkdHfODj/TrrWSsrdorl7s7gdWEUFlbiWvUVUtkqLNbGLJZ5Q1xZvBRLS7loQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAMwEQYDVR0OBA" +
+			"oECBDaTXbN11BBMBMGA1UdIwQMMAqACDSeuxr4EVgaMA0GCSqGSIb3DQEBBQUAA4GBAGVa" +
+			"QNtd4LgoVZQ+Uy1lSr6sog4fsGaoQJCZcvrMJwGpMF0FJsGtOb0R2mfwHi1YXqPF5qZY2I" +
+			"7cVbwVtRQzbXunk1z12k0iIesMtYUncxb/SBstC7VNS8HNZm9ese+YM6Ac8mGT+IUZsPcP" +
+			"gI9fQ1L/2u+/3L4fweca1R45xm5M";
+		public readonly string[] TEST_52_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_08_05_crt,
+			Intermediate_CRL_PP_08_05_crl,
+			End_Certificate_PP_08_05_crt
+		};
+
+		/*
+		 *  test53
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PP_08_06_crt =
+			"MIICsDCCAhmgAwIBAgICAIQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QUC4wOC4wNjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlSIH/+6DEL1P9tkgbsI2PcW0w9dmqMTLP3jKYPsr" +
+			"sSWI5bcv55sk6RItVr3hGgkaskZoHeamUBAiGPksVyrqmRwSCJzQDLnLdMnjjudvPjp1ZZ" +
+			"9UCufTtMPFvnEuVBx5e8A13AQ4OyHqaJgWRVoRJd6vwTa5jzfYCCMJZHHKpcUCAwEAAaN9" +
+			"MHswDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwMAYDVR0gBCkwJzALBglghk" +
+			"gBZQMBMAEwCwYJYIZIAWUDATACMAsGCWCGSAFlAwEwAzARBgNVHQ4ECgQI8837JGF7vMAw" +
+			"EwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEAKmgbxzWI6V2twYDp65" +
+			"Gu8zn883CnI08s2FEVupvrKduxYmg+ZDkTBE3ZJFxcOuxJf58MRfDWy8C4jJhLnT3JSSSg" +
+			"sY3n93jzc0s2h5y2wd1bUTDLqhqWCshisDG/88rpv938O8luiUEwltolzKTa+ScA6nXSQt" +
+			"LT4I6O3vbTx2g=";
+		public const string Intermediate_CRL_PP_08_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QUC4wOC4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8837JGF7vMAwDQYJKoZIhvcNAQEFBQADgYEAHua+" +
+			"lC3wP4G6796jjr6wuu7xEQqY1azsLVsGtL7YL8fm42rl7hgU40SuFIc7Kc+A7oEEkKgvmu" +
+			"SLMIv7q5O8J26fQOuduGWQAncPYB8w7sNWjCZbdjVbjp1XIApcAL3djCbLZ8/NYsCoOuwx" +
+			"hRQKX1hIn+rNDi1DMD4H99QdDGE=";
+		public const string End_Certificate_PP_08_06_crt =
+			"MIICoTCCAgqgAwIBAgICAIUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUFAuMDguMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBQLjA4LjA2MIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDnaYU/lu+u+LmLQwyACSsRyxQEEvgriE7ApmHj" +
+			"sNBcd3lovFQMfw9MyOOMsInOgQZU8p/invnhx11/pwi77ViQQ780unhHt5H/tteaYwcsDR" +
+			"cUxR/8jK0DBnbVWvm8S/NGb8BxfbRmDHBTWGZ70hDSCJypWRfHQj0I/SAqAW/VuwIDAQAB" +
+			"o2wwajAOBgNVHQ8BAf8EBAMCBeAwMAYDVR0gBCkwJzALBglghkgBZQMBMAEwCwYJYIZIAW" +
+			"UDATACMAsGCWCGSAFlAwEwAzARBgNVHQ4ECgQIhh/KikcKA7EwEwYDVR0jBAwwCoAI8837" +
+			"JGF7vMAwDQYJKoZIhvcNAQEFBQADgYEAbHK3lkqbGy61lu9d22uO2H3hzwvjmlccZo8pro" +
+			"ord45d2nRIxw2ag4dS1YRFrefVdxZtKeR9+5o+tQtvmTcDOer4u6NZ/sVVElTb1d6axtL0" +
+			"i4cmqv6bGWYECEwtwmPGqAavp9pPZjNRbkBGy9qhVNTXfDQYpA8yzXWO/xUrwNU=";
+		public readonly string[] TEST_53_DATA = new string[]
+		{
+			Intermediate_Certificate_PP_08_06_crt,
+			Intermediate_CRL_PP_08_06_crl,
+			End_Certificate_PP_08_06_crt
+		};
+
+		/*
+		 *  test54
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_01_crt =
+			"MIICmTCCAgKgAwIBAgICAIYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxDV2d7qXbpCvOzBimskBLsgexpEYaHv0s7gOaqhC" +
+			"4A3K8sxdjyW6QdGZhKX8tCMqnlPp9CNbpY4tQQ5oTSk5pj6HwAsTfGcDwXJnjKWx1FJ7rD" +
+			"meZZ8c2K7a8voBl6FoPGn8CMhO0WmM9Eyb/vDUPdCZzScb+z/BxTcV1BPFdq0CAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECBpj0+Gcq32oMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAB/9veHrkLeu8jkwXggJtwqPTmkrIBcX+pz85BTSETYeLOzF46" +
+			"onk+qt+IHptlrm3D7ny2Y5M0dQQ6tPzhGZxCEg9RoDibZGtsx+qeAh1ZjeEpEcQyp/idWY" +
+			"asH+EIuEIOZA9c1ySxI/3v3ZfzaSGS8jsgSDkLB4JumrE9ZkLNd1";
+		public const string Intermediate_Certificate_2_PL_01_01_crt =
+			"MIICljCCAf+gAwIBAgICAIcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3B3UKG3tEL6FQz6dL6iqSvzgGsm1Fg5uzK8npkEq" +
+			"g2caUM7huYFfXeur1mu6iKiROcGX8ZYxrPi9Orh39YVrSu2EUWvqQui4QScf4dIlzAOunv" +
+			"0gAa/lIVTHgZhIomKND6/tZLU251dJiFhoV6bXx2tor83vWFVPx2oVd5LL5S0CAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECJmK3jFTIl6lMBMGA1UdIwQMMAqACBpj0+Gcq32oMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBADkYLTg4RncTpAFmpUy7WGOMvoFV15nDoi91OMxhxVkbGSE0DJFxi3" +
+			"hPKcfUNvzy0bEUUTaqOXdbIkoLTG77NTckJxurSRyam0jA0+6SUYZ6F9fVotwMul2EiVl9" +
+			"XP5oCt7LkgqVgMASuwfzMnQozB6Oi/YP2OdSPXLipI6rl2dx";
+		public const string Intermediate_CRL_1_PL_01_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIGmPT4ZyrfagwDQYJKoZIhvcNAQEFBQADgYEAd8YZ" +
+			"8jibr8yjcGYSDicJuyUvHBZntTVQ1sP5XVmtCZcYcQCVjbC0auYTEP5snXbGPW5qeEaaXB" +
+			"MhekMr776hP4Kl3g4AjguFl3XQGcURlgNd8LsTpMMdNWC7XwooOF2FzFjD1ru0BSEWabzW" +
+			"NNaVeuMMbu2N0lc6NDJvRC8LkhA=";
+		public const string Intermediate_CRL_2_PL_01_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAImYreMVMiXqUwDQYJKoZIhvcNAQEFBQADgYEAZFec" +
+			"GtjOfp8pT0n1dMF/x9n8y5tM+G3LLnZvDJspLc/sqP3E3B/sHBiis81caEkQQAOTBU5goJ" +
+			"0KOFAUOfEq+IX5uvNhuPuinx0OsSak+2Annvi12zodMQKPNm1uMVt2bMHHHZVEVTqcv36g" +
+			"xgdbp0YKTmuvSy6s8NtGFpkNmnU=";
+		public const string End_Certificate_PL_01_01_crt =
+			"MIIChzCCAfCgAwIBAgICAIgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCAUPp5j4V5XTA44Ra1EWkp9HgS4w3uXJ7/Vhi" +
+			"K5bARFrDOOxjV8nmr5hoUYr4jwdi2Rl+60TQK/F08gdcGxdyc9p/yiU5HyAP6i+4iqmvaW" +
+			"9b2egNyZ5tOmpl/Q9FSFWa9d/PYBKM5Sj/r73RtA+/chc4uq3uyLekSRQGh1MieQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECAiL3A4CkaFyMBMGA1UdIwQMMAqACJmK3jFTIl6lMA0GCSqGSIb3DQEBBQUAA4GBAJtH" +
+			"mNNvCt/0uFbHdvUvCuBeZ9cggfpTyUS4X8zgcLDPFbw6VvX65umOZpceZI6hwcre+LZahi" +
+			"gUEPvXppncEObkeVTcYdOTSDoxh5tZyee1P4sbD9H+suGWeewqUDvFs2ymHtxlkpOttitR" +
+			"xQc2U6VlCuZ4XU8SwucyhW0z51e4";
+		public readonly string[] TEST_54_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_01_crt,
+			Intermediate_Certificate_2_PL_01_01_crt,
+			Intermediate_CRL_1_PL_01_01_crl,
+			Intermediate_CRL_2_PL_01_01_crl,
+			End_Certificate_PL_01_01_crt
+		};
+
+		/*
+		 *  test55
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_02_crt =
+			"MIICmTCCAgKgAwIBAgICAIkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wMjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4QmGXEeVKCn1aQx27r+EBuQqfi8fP7gyV5JLkaSu" +
+			"DOUrqXg8dQxHsBNCf3XilGIvjNFZjVUPdS8FNqC+if9D164VyGQlv/JUor/GlvwVfyotUO" +
+			"U1PqSzFrAALYTmfm/ZqhMvGYloStSDxlzjDmyKadskzOxZZDNSe5s8dvUpYn0CAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECGk7qDbbBgRbMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAD+eI+jg4jmeC3pJRGEF/hbPPYvL6aocjqqbZyNKN5FWItccQo" +
+			"PWg/GK1GpusDZadesZBDo6fLIUJzL+OumrIYJLB3HxQsmyOXB1gRg1hcva71RWFJYzx01U" +
+			"eB8lCbk8Zu24HzLzqjfVuwKOFFELWDEq7bd6Re/aKSHtNnDbsgSE";
+		public const string Intermediate_Certificate_2_PL_01_02_crt =
+			"MIICljCCAf+gAwIBAgICAIowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wMjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAl/HiHoos7eHaDIFhMmvIPk63UT33Z+0iiCIuKLW7" +
+			"tgkT8ia1Yg++np1pC3oqYVeKkXqMcjgonPGQhcek12vLt3/+2PYyYirOTVZaiO9pKQ5An8" +
+			"ZMWXIJmCEAMHabPO1RnetvRv5JZFxZY9jIUnD2fUADzzUh/eHN6Pur0DDrI6sCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECPk0C10KQLZuMBMGA1UdIwQMMAqACGk7qDbbBgRbMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAMJ4+BZQxpxWhNbo8bpGkbbcKT3kfKYrHjHsZADC+/gAJSVL854b1W" +
+			"VKsGr1YcCX10V1Gcqb6Jgziy+AzRLhcJngszcz0A7LxrMH+FIyWEPgZnOyQCa8B/9bnsh9" +
+			"bC1gEmXGOVtWboIFOEdGghEbm/ENnQyj+HbIk3jhF3QYbXhw";
+		public const string Intermediate_CRL_1_PL_01_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIaTuoNtsGBFswDQYJKoZIhvcNAQEFBQADgYEAZEt+" +
+			"FjRuXgnOZg70geqS4hVsF1VWWawlAVGmjPsbRH7rADXPUE2bYL54wLdwt/6QYwHqy2KwCf" +
+			"d4OkWkwn9xwGS4j+XBCw9Y4nbWI+wrsZ9W7vgbeIaVUUUZu6hoin1GxrGDcfbM+bhYzQAA" +
+			"gNmKIWdlJ4tKD2KNgg0KmZPoj/k=";
+		public const string Intermediate_CRL_2_PL_01_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI+TQLXQpAtm4wDQYJKoZIhvcNAQEFBQADgYEAXwZO" +
+			"wr9mrO6yUOoopNjcIcDssCUksYco1PFgWx9O/hGq9ktdoGoGcECGhdkHTLe2ab3WFl9jzW" +
+			"1/lkysD9Jl3VjbnbRB3dPQlrSfiv7cYBLnfKvyF/CxQg/wCtWo46GJJQgOx/WHzi9aF08m" +
+			"tQuJEtl7RgoByUSvLtmvKjQWEnc=";
+		public const string End_Certificate_PL_01_02_crt =
+			"MIICljCCAf+gAwIBAgICAIswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wMjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0/rXOZwUebRaHcPPFeKTB2OWIzIAgavqb5HerPAe" +
+			"c3sJCdNOSLc0OX0dFblso97WR8uueF9I7QeGg3ayQjzDVqm5Tu77ZaCuyb6UU8+fY2eqwD" +
+			"5lCVuLfJr9U2JD5b2TcdvAD9RqfhefclVjDj9rObLjvzLg3AefO3drsfBtAIMCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECDBWCFTOp3evMBMGA1UdIwQMMAqACPk0C10KQLZuMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAI/JpU3gHo8Izsbjlx6bkQo/e/hD634N5lSMtVHIGnoVLu99dvroRu" +
+			"2DO8Fhnv6VZpMvYoAc5oEgUqx9hw3bfS/XN9GXaeMssjwN/qM6lzCsvMG7DA9sf59xjf4Y" +
+			"2+u4KTye4PdpmWaseDDJ1wAihTHEaofnQdaoUffxQgw5UcAf";
+		public readonly string[] TEST_55_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_02_crt,
+			Intermediate_Certificate_2_PL_01_02_crt,
+			Intermediate_CRL_1_PL_01_02_crl,
+			Intermediate_CRL_2_PL_01_02_crl,
+			End_Certificate_PL_01_02_crt
+		};
+
+		/*
+		 *  test56
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PL_01_03_crt =
+			"MIICmTCCAgKgAwIBAgICAIwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wMzCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA60y6V2WkNCB34dcGfu+Jo3YHQZXzgp76+HgnyFmP" +
+			"DLj9DjZHqifD3gW8Zk7L+yK4PfLDSHjbrXM9GY1ser6XwhaJQDPUBBYW5X3XTOmDWmV63J" +
+			"YeRF5r7cfF2h3eEZ460GRLK5tt0Zr8V+hA9oOvwqynrIhDYC/tCzE28ciqA+sCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECPE2FCetVerZMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBABUOUWwyfyrRIw7dRIVfLlWyp5R1I+Kmq5e8st0AEMVpPAmLoy" +
+			"0s+46Xf+THXZy5em1P3bSVTSUhTs+XD6tbFFUcTrX0mQJlshR7yD/A0siMDUNzzt9LJQvP" +
+			"dwNjQSA2keOrV9q/2CAGce4daL4Wz54jfh33YVqJ8sHT4E8CxQb7";
+		public const string Intermediate_CRL_PL_01_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8TYUJ61V6tkwDQYJKoZIhvcNAQEFBQADgYEA6FnB" +
+			"LXWt4B/3oP0PXERYh7ZV39yu/tm9DHBQGcGDF8JIspU7F+mH/+37U/lT6BQxpKOpgOgGeP" +
+			"nTQeQzN9sRsXxFO22SkHbdPCao84qvv485epgzqFcVsCRBwBBLcnNLMg891q0EYsTW9vSw" +
+			"Dx7V4CawyYAYGz1MqYuY6SSs6Q0=";
+		public const string End_Certificate_PL_01_03_crt =
+			"MIIChzCCAfCgAwIBAgICAI0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDMwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjAzMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwt6B9gpDz/x/vnowXf1MdkAPeaCWZ3pYikgxE" +
+			"ZLrMuulFaI1UDnAzgSuSvoHE80VKGKjSkrzIX9OFfeilW5rNZAXoZrjtkaJd1Q8l5AtjFn" +
+			"0tlLytDzIMYo5Tiq/n3IiTdbEzGYzEOCcSyVaQdB7K1WgYI/z/UAaWV/GbqCX1zQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECMQHLiufEm0IMBMGA1UdIwQMMAqACPE2FCetVerZMA0GCSqGSIb3DQEBBQUAA4GBAD5/" +
+			"vGn/rpoHvny/mfh6n2zVNNQLTEBiddfAdCWpeBFcwxS5lpxfm4dAWgHhprZTMirF9yS+wO" +
+			"wWQ4G9/wiqfAtoaNN1qkHMlUMOAPsOSff6ClgP+1uzKVqQa9NTd5HAeMdYfYjMa/fcF/37" +
+			"plCs5ZsJjb9lhEjNd/tq4/aALQmt";
+		public readonly string[] TEST_56_DATA = new string[]
+		{
+			Intermediate_Certificate_PL_01_03_crt,
+			Intermediate_CRL_PL_01_03_crl,
+			End_Certificate_PL_01_03_crt
+		};
+
+		/*
+		 *  test57
+		 *
+		 */
+
+		public const string Intermediate_Certificate_PL_01_04_crt =
+			"MIICmTCCAgKgAwIBAgICAI4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06yd2NQEAgpv0kQQEOzhHHU4YqHgtvJgkdLYxb2W" +
+			"Zordrm4b/43UDnLmsI0790V76y9Aa+Y8SIMBBRBJgnlppFJrFsPaOMO98M3/mXkQotVbY1" +
+			"59P/AjWMxpzP9h8Bs8KuoPqnl5jN0UZAF4kRoNXHzyS445VBp4DtWz/jcCPm8CAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECHxLORDZ1KKNMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBACHmDOaoC0Hr2cmfuQvdyGDF7/RlvTUJ7cvGypCa724SwAZGZk" +
+			"Tf5GwxgjVcLHY5RlX2kDm9vjneDzP88U3587qA2ZRwxhheK0RGp1kudNQ5y2gAGKZ7YSc0" +
+			"SENMDxUAa6HUkn9Rfo4rf5ULuGNJZXQZ3DtP+lZSwzkUeCVjKhyQ";
+		public const string Intermediate_CRL_PL_01_04_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIfEs5ENnUoo0wDQYJKoZIhvcNAQEFBQADgYEAb8lX" +
+			"19SlVNRkc9SKNpRLZQom67djZfMSIPIDkBALfMepdevbquzgO7AufTuiDn5Zqe6J6odTv6" +
+			"RrQReo64XB4+Lx2pXOe8bZEbzZk0HvzLl9DjN7zxyNglNK+Hd2xS4yT4ps4fBdvXvWAXEx" +
+			"6DfvWHbGFDoH2auomCKJtCVXxCI=";
+		public const string End_Certificate_PL_01_04_crt =
+			"MIICljCCAf+gAwIBAgICAI8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDQwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA14bXc39XiWvb4r1jzbADzrpfbg2Y9sGBkefSQHsM" +
+			"QZ1SRLR7uexWD7MuDYh4ZYBL+WPhaJJr3a1jnAIp54h68m8mwS13DgrxBF2/hrVKEm9IRG" +
+			"s13hoM4Mjjogn/Lvc1xLvB5lctHjZrNRZjyrt+PqDDmqZqgCOmcD61PhrfAoECAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECB9hXgJfzBvTMBMGA1UdIwQMMAqACHxLORDZ1KKNMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAB0HgiURRd/REVfc5DenIPhMu8riVcwVgTUwatsCWragUhXpCtvJmf" +
+			"z4vGo1rKYai2dltVX6am+NDvN5tROcM0bvC8lOCc/iPfI5eWTy9SJ2nxvs1+q809Rj0rno" +
+			"zS77TIE8rD7Q8ZUd3qNUiBwdjBoc9misgyN7zUulg4Ueebvv";
+		public readonly string[] TEST_57_DATA = new string[]
+		{
+			Intermediate_Certificate_PL_01_04_crt,
+			Intermediate_CRL_PL_01_04_crl,
+			End_Certificate_PL_01_04_crt
+		};
+
+		/*
+		 *  test58
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_05_crt =
+			"MIICmTCCAgKgAwIBAgICAJAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA/rVBEGZ4jibDhREeRGV3jPnv05esRL8/En1Bu35y" +
+			"QrAHi32+kBu42vwwDbeuiTZd/B90bn5srJZoW83rxXxNnpxqbnjN3GgIcRiUVyaVRTp9/U" +
+			"IT8B9h09b9yT8gpQ5qR0+JDcOHCfJwpogAsyJJa6AM5p/q3TeF39ugfVOWt/cCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECJ7/mkuLuEIGMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBADC0A2KMMSSmGI9p85WG7XZVMBX/xdDYOHO0e3ORTRFS3kj9rK" +
+			"a0yUjc1X+p22AA8kUyOLpYIulfDjPrLKN2E/hWSf3+XWMiC7JfX01F+BBl/avEZoymaZB4" +
+			"dkH1Hym4IMJoSaEOgf5HFKBnFEA6aUcr+oDYGUP+Sc1dmJMjBW72";
+		public const string Intermediate_Certificate_2_PL_01_05_crt =
+			"MIICmTCCAgKgAwIBAgICAJEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEArir4GaS6r0Tv9PMbaOXYdPKADNpVbJe79G5t/F6x" +
+			"7Tz1rwUR+m10E+Jq9RsV+fU/nUzzjJXHbPLZnfodUVVmrXgzvQ8+B2N4jJtdNLG66j2PZG" +
+			"+P8GQzVK9drDh54VHXdvxAYCXs7GaIprWmCQsxZOKjhFU3YDiRRK8qJGpBG/cCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECMmrFr30fUzZMBMGA1UdIwQMMAqACJ7/mkuLuEIGMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAI4qJF6STCi+elUbpZIP7YmcaQsS0PE4G3+LJoMg1LT3rSeobK" +
+			"Aj/yUetmA7y0B5i0svKjRChLOpfClNPVPCx/+mc75+LG+dh1eVG/qk2UH/lrqLN0XLl8tA" +
+			"IwZeoPaegBQAIp9oEjhDN1fWtKIkOe6A6wYdH2VPvsqC8g02VcwD";
+		public const string Intermediate_Certificate_3_PL_01_05_crt =
+			"MIICmTCCAgKgAwIBAgICAJIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wNTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtRC2/PDG3kx8LpzfWC0yJph5h3LXZJZW0W2voss1" +
+			"HYPP1/MBoQY067dfbALilVRh9asCNL4F45uu0lT24qS9vjW8SzBOLA18GsVYRmWO7EP+Cd" +
+			"9f3mgPIMJ5n+UjW+yhBwh0Z2pzVElkX9CxECrs1Mt2ulyuwWA1lR8nRMaTUeMCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECAlV3mzXYPyuMBMGA1UdIwQMMAqACMmrFr30fUzZMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAG28iHdlA+nTs/b9pi+m9eMy7niELjIWL9fMgn1r4iXQ0TsPYi" +
+			"tgpoip+BB4G/jz7MPx/N4nwyAPV+C9wN8cAHALf/ka2MxAORYFVFI+5PDgXzm78ILqj91f" +
+			"vOFN4jemizTES4/dHxfmdctnsTRpU9ALQgfJLhxEQISOPwuemKB0";
+		public const string Intermediate_CRL_1_PL_01_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAInv+aS4u4QgYwDQYJKoZIhvcNAQEFBQADgYEA5i45" +
+			"gETFAw6l9Awex9IAVIqYTA1dnbDyrUYDRdzd0x6OxSPODvNfQCwqwlTJXrHidCPO8jRhMS" +
+			"Zcdn/MTlIeHa6OERFcjOiwOpeTgtchvpTdDchs5ve8Ik+myue+cfgpEVKOE+ZQ2T2tcyz/" +
+			"+DbeMptECfJ0lVfCKIY7ZOzBPaQ=";
+		public const string Intermediate_CRL_2_PL_01_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIyasWvfR9TNkwDQYJKoZIhvcNAQEFBQADgYEAdsNe" +
+			"ugM8sd8bmIDkYXce2WmS5Zx6QUQ0yT6Ij4OR5/F4CG4Vl+k3JkNPuAiNSs2Z9HeML+F/W8" +
+			"3yEPe/mdLV4nLw4B/b1/8DmgZN4r1ojaWuHAg+KrA3Zz3Rc/hwQfvBy49mf4NGtY4ArbeB" +
+			"DYKz5sVlrwR+gOCR5jm4IC7WEDs=";
+		public const string Intermediate_CRL_3_PL_01_05_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QTC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAICVXebNdg/K4wDQYJKoZIhvcNAQEFBQADgYEAqYex" +
+			"FaIykZo17O2URpofe8x04L/VsfA9jV28zUgNFruAGld/kUh4rYvgwrdbNZ8NmEFDp9J9aL" +
+			"93af3bzoNvWCik2VrQLd5nccCFiC04B+LUH9Y2p+7vV2ojrtBks5SMW0q4HaNyPSQu8Fst" +
+			"4mYVf+QIYZC3iVAF4rsKnaxwzIU=";
+		public const string End_Certificate_PL_01_05_crt =
+			"MIIChzCCAfCgAwIBAgICAJMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjA1MIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCXJjzKGcLyONTyOa6sQHvIKZIAh0pWdteUiXf" +
+			"b7yjCn6Z52SCHxB9GZERHwR7fbJpoE3oDcYUY+8pH65bIVm1p3zr5deo4v85DEZQ50cU9a" +
+			"WEUAO/5X57P7pYb9/47abu0cdsLIWeE+O94HpZS8vz8mxRQKLj27gPY1KzzTbrZQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECG8ILlM9oqZwMBMGA1UdIwQMMAqACAlV3mzXYPyuMA0GCSqGSIb3DQEBBQUAA4GBAF6S" +
+			"x3aunfgnDmo42aPOzDh536WSkTTbX9bmUNyg3IQHl/3xhVqjS76bMqreYhx5nh4VNx/Z3N" +
+			"LD0W75XmASCk0wtW9S1MoxzJMFIozRruaE3oykrbyMMOt0Br5CV12ofUd0WybDkXfNAIze" +
+			"IRgps3nORHWjV1GwXe8uNoUn6/z7";
+		public readonly string[] TEST_58_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_05_crt,
+			Intermediate_Certificate_2_PL_01_05_crt,
+			Intermediate_Certificate_3_PL_01_05_crt,
+			Intermediate_CRL_1_PL_01_05_crl,
+			Intermediate_CRL_2_PL_01_05_crl,
+			Intermediate_CRL_3_PL_01_05_crl,
+			End_Certificate_PL_01_05_crt
+		};
+
+		/*
+		 *  test59
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_06_crt =
+			"MIICmTCCAgKgAwIBAgICAJQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAweCAiEGMLycmodjrUMIWEEFshkvhX2r90wGl+/pU" +
+			"Ia9NSdT23zYzE4Uo8Is1ywyV+YfvgR22j/RXF6j8OK+XZ8jlgfjVTAhjCnTWY9LDR7qAyk" +
+			"8zuuITxJrYpiPoxqZs9BXLfGkDbye5VpVJXvQdbJNxgKO0hkBBDfe+T9+qw6ECAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECG1DiuoAwV6aMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAMFvtFiMDMP6n3CrqQLSzhpK5Qu0uxa56ARXIKSIqi0OUZAu9v" +
+			"sCXxMvaG/R5bElwi7ybYZ5KUSN+PnDmlUxWWL5Ib5RZdXgj7L83oyLTQmbDMvka6rSWHgw" +
+			"Jq8qHVslhh+l+YNOb4fzs8x9ctCrs/BgjX8wkORpQbigU0BUJ9sX";
+		public const string Intermediate_Certificate_2_PL_01_06_crt =
+			"MIICmTCCAgKgAwIBAgICAJUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwf6Nf0+r7JvE6BO4MbDbS1T1SCzn78haBAmqGZLS" +
+			"Ac4xQTydvmzr9PwiWlU0xjFfKItqRMt7rfzTTPfvvnwxsAfQNPtxKzi30yCNq/VotMA7j5" +
+			"iQYaVe2OWVHu13agbXLEZ0pL/ZkmQ3Gvo6UhF4dRmCnjFbd5cMTxQVHUrwgyECAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECE3tS4AYmwZDMBMGA1UdIwQMMAqACG1DiuoAwV6aMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBADcBTKbhx8PCunjRVJkcLBCcVGHs9HfkChDafwBO51fe5uhHE2" +
+			"QBpW3J8ZsevuFQiEZvuy2RVFktE6ZoKD8wxwBFhs+OIxe2mergQPy6jHuxoSUiPzr3CVXZ" +
+			"UsNxe7j3IcJLqbJ15UqGFH5yph7Sa4Ym6x747miF6W9knNkjcx3K";
+		public const string Intermediate_Certificate_3_PL_01_06_crt =
+			"MIICmTCCAgKgAwIBAgICAJYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wNjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwq2YlDLHX4KktKnzLCYjnk079IDgXENrkRBuZHTB" +
+			"IQyZoiBH4ZWHreZKs3LvznP8uSd8eEL8keNw4PwZ6aT1LF/Jr/UlrFQNnpLzQVXwGGAuzh" +
+			"tFJYRlOfI5cCZYAcpjnyUV4GW+MuwBdoqDycMjmqIv/8A8vupjahffcmBAassCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECB+qYFJjEkJ5MBMGA1UdIwQMMAqACE3tS4AYmwZDMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBADiXredACtRQTV2TKgu5SDdPlczj7cZZUARJiJKiRfjmxHCc1q" +
+			"m/Oh7sHkqRvlHqjoX8qp4iSchoZWdOAE5O/q4Ef6rViejDFVyN2ZmlhP6KIiRxznrvYfF1" +
+			"n08K7CHgHWvDaumm4pNmWeF03nuasHrY0W9h1uk5poVuzaWDpx3A";
+		public const string Intermediate_CRL_1_PL_01_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIbUOK6gDBXpowDQYJKoZIhvcNAQEFBQADgYEAiHM1" +
+			"xFuYt6tDscqzwj0mLHPHULnR44/vNyPUg0KnV03Dd4XbFHz0FtwDKgVTBZ8x7ybp83ubJH" +
+			"tE/p8nPW5kN25WQOlYkZoAcMpEXjTzlo9evU0W3nyzJjmlT8YEI7vnmWFz/ahzy6WFwPue" +
+			"h862EKh2zVO4hoqZYEuDQI33fOc=";
+		public const string Intermediate_CRL_2_PL_01_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAITe1LgBibBkMwDQYJKoZIhvcNAQEFBQADgYEAuDSF" +
+			"W1KOc4x41HGvdRaw/NtipD2y6zSh3mtRoo7Q6J2BvJvunymZNEziozBOiUgT8zMgbdbm4a" +
+			"PEwlHRaoJP8+yxJIlKaHa9Hc7Yz4SOwSrLicf7EnBSct3Mze0b48UYqbn1q+lf/zKaUGrP" +
+			"M6oqtE8Fam06T+WUfutU53zTtSs=";
+		public const string Intermediate_CRL_3_PL_01_06_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QTC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIH6pgUmMSQnkwDQYJKoZIhvcNAQEFBQADgYEAcPfO" +
+			"+Rj2KmO1CxjuKLEiOUAIq5YmR4U06IcCBGMxlrdHVXHM3vepBKUlMDaT4UGcleABMPX9Iz" +
+			"/31ofyXlZ/fQJOoTZt0CI7SOPQE5ZkUsR3BDuUqf1+sWwBYyBHkrC95JhJkM4LfGS5K19p" +
+			"fp0j0bguzNCXSBRTfjSZhy80tcs=";
+		public const string End_Certificate_PL_01_06_crt =
+			"MIICljCCAf+gAwIBAgICAJcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wNjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3asAqJcjXngEuyM/W3+TAE+Qr4JtNUdwBtmrpGlo" +
+			"fAvJdmXHARyiN/Zn6Si8bGI8Wz8J4Y+Ll7zLdaMU4MCZo6hwZiaQwkh9a+ZecCpLpjs4mz" +
+			"MSf5zHSwTYiXKMazlmnGEITVyKLmAiLSyGeeJvOJVqVo/NZXRGVlmnPxZFfgsCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECLZuS770NcDsMBMGA1UdIwQMMAqACB+qYFJjEkJ5MA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAGM18aR2i8vSywsWhcLrRN1Xckl/HiBPNphobfKoER4NG29cFjUPQX" +
+			"zukjQcJl2clAXNCVtcsKCoYRP3YUyAB6At+yskuuJXtES7FIzM3rt/UpDS5ktVC3gh+jgE" +
+			"pPhMILYIXFzYY1hifkpagfO+mkcr7RqHU3tHAr6LCWjqrB9g";
+		public readonly string[] TEST_59_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_06_crt,
+			Intermediate_Certificate_2_PL_01_06_crt,
+			Intermediate_Certificate_3_PL_01_06_crt,
+			Intermediate_CRL_1_PL_01_06_crl,
+			Intermediate_CRL_2_PL_01_06_crl,
+			Intermediate_CRL_3_PL_01_06_crl,
+			End_Certificate_PL_01_06_crt
+		};
+
+		/*
+		 *  test60
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_07_crt =
+			"MIICmTCCAgKgAwIBAgICAJgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNzCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5HkS45NLuqq9ZwF79+pTGtQnGWO7DFdetYeQTbeD" +
+			"sisjZMsK0sCCR5xAKYQsJSS4v/8LQUdxlQR30LMV0SQUKFMJyFsMiSsO8subb6sVINWn8A" +
+			"tL4zcQK0WiASUZOEkybAFJtP31PahzI5wfD1cikE1M4BlDij5WeaIjt/RTHKUCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECLSUEn5d8YywMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBANLO+kEiswkGzEh4ZcF5LtfnPZlnG4gTPSNugeWJc+Xedqmttp" +
+			"jZ35fr1hiRe2Q1UcyTd4ThkPknawwZednbsZVPqw8u1mo7kuAeL9KrCk199vL4bV8Ag/kj" +
+			"HJ8TAy40UDB6hMm7l4j8mEKwV03THVrz1Vvz59CQXj+iseH6yUNO";
+		public const string Intermediate_Certificate_2_PL_01_07_crt =
+			"MIICmTCCAgKgAwIBAgICAJkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNzCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAu78gmT5HwmBHEe+K8fLLgGaPpcv13ZjrgL4twTBS" +
+			"OkZn5LL9GcfkPuA5WIAZkVYfCWSDPqcAGoOWUIDADfBfdcyLteUH+xI01rHKiLDVexMvU9" +
+			"vqCmcBKhxK3S6wraW5YhOO0bx4oPrZXVIjyG8fh4e5WTEykzvUWJ8ZbzSJ9JsCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECCT+fDEaN7GaMBMGA1UdIwQMMAqACLSUEn5d8YywMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBANpKr98PiXAdcXlbgSgif0213H+tg3WwUNKZTw8MpqPyrN2/DZ" +
+			"HBi6e2KWXLTxttV9AZBRvcKwsveS6oc31eulMe8nHxRNRfadvF6dL3Tsig6HAQkartcJMI" +
+			"yfW4V3EhXbCdziQkre7XcR9WK5bpQoX04HWeew6YTxjG/cL9MIJR";
+		public const string Intermediate_Certificate_3_PL_01_07_crt =
+			"MIICmTCCAgKgAwIBAgICAJowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wNzCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr7YezMXvnkSuNCdXch2HRAEVuCqfzpVRCj6laJI9" +
+			"Q+NxgXwzaOwnImvwER3Hblh1l0MAt5/I/9hhqCN+918ueME50MkoM1wPbcmrRIlwWLGSVZ" +
+			"yBKeyPHrLbdPqVIexUlQk7PasLm/Qx4SvRGVe9IMLrEzPV3MFJtrJoWaMobQkCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECKw8JlHMvVfuMBMGA1UdIwQMMAqACCT+fDEaN7GaMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAA5JEDEDyqfZzTGzOoMV+8RVke+a4qgOo7rnOEdletgGFEwz8A" +
+			"tiMHBxR+UMxuHS82Hz3+F8XlyYIwlrG9wWVcB/tOyzgVyA28Yux9Q/meU7T6dco/AnmOdr" +
+			"2XL6Xm5iLnARG+PkUPHOsxuweyB/sSUSA8ZJPowNRWTik57ul/bO";
+		public const string Intermediate_Certificate_4_PL_01_07_crt =
+			"MIICljCCAf+gAwIBAgICAJswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wNzCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7mNS8dGz0gkXDbBRzP2ypdNMahJbM3cSMHO0hYpn" +
+			"uRsiXGUhIB0K4WVbnz6tr7Hch3yltK4H1Y12Lf8cXEETR2sE9lCY2A3r8/VM5OUbou5Y8k" +
+			"wIf03VhP7cGKonaFtlj/WD77fidDePVp1Nk28gV0T2F/l4pM5TEJrq5C9PSUcCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECJBEcZsMRq6CMBMGA1UdIwQMMAqACKw8JlHMvVfuMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBACfbHKpuRJnZ5UU0sih8RuywhUo6Getwl/p6fsi87wYI61pvYru+hm" +
+			"4R4eAMZvg7MrAarS3Iu3zKBU1HKeq1i+hpwTIXrngR8eL2fU/X6GPzdte3+3tjhah38bqF" +
+			"zDon+N6ap4MKWRk033SsFYo1K88Mena2tGuFForJlV9DOF1l";
+		public const string Intermediate_CRL_1_PL_01_07_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAItJQSfl3xjLAwDQYJKoZIhvcNAQEFBQADgYEAJtaE" +
+			"I1+PCNL1/bgEVKWUIwvh58ugnWhxzbFW6hNJwNEz9/yt+FLZfNrT/Ezort4VVQFLQg7+Gj" +
+			"KrkIujqfRJG4LXrXAV8ZsvSPuwyQ+hM1GdHGDPhj9x6DkjFusxJYUEs5BzlX7ovpnaIPSW" +
+			"RPsatheSzu48pMOCmyTKE3MpuZg=";
+		public const string Intermediate_CRL_2_PL_01_07_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIJP58MRo3sZowDQYJKoZIhvcNAQEFBQADgYEALiV+" +
+			"BFpXhgTjiMZBYLVuc/fqhHcXeXOGOmJZoKUnIXjETH3rzkkt5k4tMN00ycZVgpRwn3ZyQs" +
+			"cFLcW8taau1J7iQOmGY/7qIT0eFx2OlgNmxqirmwx4OM5VSH5mEpnp9NOr1rfut1GDRzw0" +
+			"tZ+nhD/PGDXYPu+QPX6jii0vdHo=";
+		public const string Intermediate_CRL_3_PL_01_07_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIrDwmUcy9V+4wDQYJKoZIhvcNAQEFBQADgYEASY47" +
+			"p94jEh9FZ1TrPS82nWC3Z6ZKdaD9pUbaJpRnAId59QdBaD2Cxq+SfM3HTlz8grCAPKwulv" +
+			"jDDhXhp4H/m63Q/pJbyl3bbMxnphMOoDwB9wwKIUQPM5wagMovF/UYtC8MoC++m2kuZ1eb" +
+			"fR/OIJuQr+k/kD5Axhw/xolKPdE=";
+		public const string Intermediate_CRL_4_PL_01_07_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIkERxmwxGroIwDQYJKoZIhvcNAQEFBQADgYEAMhIQ" +
+			"lE+BdCO6NBz+YgcH+tjP0n4OCdQ+7uxUxUYmPtPbsLwbDDEEZUjykgwiA6P47Cqh5fXB6G" +
+			"tfInh1cmQi3y2IEHK+bRSx321qczOh34Yx2hw5vp+JFttbQAEl/BHixklrFBrXjN0UsWGC" +
+			"ibXcZy0YjerWTp/yceoABz9p94U=";
+		public const string End_Certificate_PL_01_07_crt =
+			"MIIChzCCAfCgAwIBAgICAJwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTQtUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjA3MIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdH60mBM1eInACvOB83zLrtiebq9B5UBlAAVS8" +
+			"9ucDwGx1HOJwhwk2AmvhN7pYuDc+BFzuNtgHojqZSDpRMA3rVsGlgOkZ3sOQzvxB73w+/X" +
+			"XmCYpwcEGLpK4egl8r1aOYm0Zm4OxqWhNu9+Do7nrJczDLi8k/qh8/+Rfdtvt4kwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECEmVurZ+7UXFMBMGA1UdIwQMMAqACJBEcZsMRq6CMA0GCSqGSIb3DQEBBQUAA4GBAANe" +
+			"AbvpAHwBu9+FlI4DOb65Z+h5f2Ok59FVbVqAj3zkMRkawppngK3CMY/1BQlGXOlHvE+CGz" +
+			"x/7DsiV0O3rxOUjutt00PNxCyIM2pcOZeGUaAu5DJWn0SRwzTMJa4M5K+7wh/4sSPWyxKi" +
+			"ueDq2VXvIgAfEVC8Lv44sxcOduSZ";
+		public readonly string[] TEST_60_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_07_crt,
+			Intermediate_Certificate_2_PL_01_07_crt,
+			Intermediate_Certificate_3_PL_01_07_crt,
+			Intermediate_Certificate_4_PL_01_07_crt,
+			Intermediate_CRL_1_PL_01_07_crl,
+			Intermediate_CRL_2_PL_01_07_crl,
+			Intermediate_CRL_3_PL_01_07_crl,
+			Intermediate_CRL_4_PL_01_07_crl,
+			End_Certificate_PL_01_07_crt
+		};
+
+		/*
+		 *  test61
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_08_crt =
+			"MIICmTCCAgKgAwIBAgICAJ0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wODCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsr+i9HxgO6LnOa6xOHfe9BeLVTo4iZd8rp6UTc02" +
+			"C0MmsSjvIgn3UiayU7aoHcTH8tAXSV5bn0CIH4B46qLym//oE69hUFImy6d1kKgNoaUKWB" +
+			"HztKVtswSSPjIUf7pbyp0wasYMN6fIKYyLpLXUxzA2DrD0kP2Y8ElQJKl2HocCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECPMW3WMPtaowMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAH2N6S9ggfmRJkzhs82uOPXaHF62YEg1pbNxaCyJJbSt2iIIyy" +
+			"NPSlE1OufPPH3pO7p5xcYi90LCI//0tlUL8y7aULFNygbshFY3B8MSgCz3KPA3UKdtIZYe" +
+			"7lqP9/ob5wmkjtLpx6oZ4/38jxqe37pH1IwVjaUnoeElSo3EkCI5";
+		public const string Intermediate_Certificate_2_PL_01_08_crt =
+			"MIICmTCCAgKgAwIBAgICAJ4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wODCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqZZolrig33i1rEwdP1pin8a5PgzSk7fT+qhrJRCg" +
+			"UTOW5WyPtakrLTUipDcR07t8tIe0NsjRoph7+fAwbjWBfbJdydndHHGx5BqWg8Xi4zFhFd" +
+			"6Mc5O6KO7Yqxs8lmthv/RAdL4Eiir9d9hqskKOtQKbLWz+Bz3+9NwfLGzwzPcCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECFjxM3RkbbhNMBMGA1UdIwQMMAqACPMW3WMPtaowMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAJOJKBubTS/kLnfXN5YbQfggxbO2c7DTxx2LhrnPiyVDEow+Xf" +
+			"lMv4YK5olH6UUm02D8cv6Wxg4NeTtBBnwKQG/GV4Ssgc/rrpEzM7jFRQcUzPu0jfya2fX8" +
+			"ZNBnSDjovlN6vmZHtiksjh66h3a0aVusEuOQXD29ogMR8qAGYQaZ";
+		public const string Intermediate_Certificate_3_PL_01_08_crt =
+			"MIICmTCCAgKgAwIBAgICAJ8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wODCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAogLtEcWxzzkkIYe+KrwKhaQjjGQqy2KDsW00U5lx" +
+			"+XJoT8eKd5pxFdCa0SPn/jkNILVeh07mIHec1WF8SOeveVT4Ewd3nG/6ZGoVVq6l0j+3RM" +
+			"jpJbp26BPR69nFn6rmFUMoSNq0VG8Zl+UBqnjq83G3umJCJMMRekUTULSFEGUCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECGAFYeJIhrRzMBMGA1UdIwQMMAqACFjxM3RkbbhNMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBABHamiW7sPLQ83nXt3LZemcAp4QaDB8X94EuJGBwshEcKLoOHb" +
+			"/3cZkPRbOiRQUh/YdpfyApndGFSi0DtwM2Z7yup+MzdrR0wzQoNS95A51nHE7XdCuVFemc" +
+			"LTJ5rdd2BLK3OB5lQagVLzAY9Bs1vaeXKT2Cy+gSUkTIekWcsH3K";
+		public const string Intermediate_Certificate_4_PL_01_08_crt =
+			"MIICljCCAf+gAwIBAgICAKAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wODCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxVjjKlLlZzeZhamPO2NDnRtWM1oWZ3/kdwdBRn50" +
+			"o1NRXb60Ir2HjniK1dRdbijAvR5uItLe9tmj4nusBiaPUGM0HNlEdQWSzble8rvUsP0apw" +
+			"uJusV7zLvzwwbgLbMYT+8lMhxWXM34xszP+dgjWASQOVao1Uqs/MLLibOuueUCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECFMFrvh2hQ18MBMGA1UdIwQMMAqACGAFYeJIhrRzMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAFsCOJ4DzuMOKti5PvF71ZKOtcTHSv123ZNdPIbK6OatT9YhVuUOYB" +
+			"AjMavggywrb+QOXOFfJMctQlS3y/JE9YyoNNt/4UTdx1jQ3I2ablonmzjt8eN5GJ9jUXth" +
+			"fHjxnmGUeWlAvwMjEdzdigkyuWCi9LJfjyHtTjSf9n7w2rU+";
+		public const string Intermediate_CRL_1_PL_01_08_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8xbdYw+1qjAwDQYJKoZIhvcNAQEFBQADgYEAG2Aq" +
+			"R1oelnrTgh56m6Mm+Lsm0Sf+Ot1W7LzZmMDwoZgmGLcTduVktx+XrtiDDWsf58hmneT1q0" +
+			"5wl4yNH8y/VCAA3SM/gOq4ddOEiS8GbuEYo5P/julH/U3g6M0vfPUZ5y+7V0s35jIbTkjX" +
+			"76n3Rhf88nvTscYvMdqrYyUhAmg=";
+		public const string Intermediate_CRL_2_PL_01_08_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIWPEzdGRtuE0wDQYJKoZIhvcNAQEFBQADgYEAX/+I" +
+			"DkAx7PLTi2x6aYbLacPRaUSjMne84MDaEkYiA64Vo3eL6FbKe14z2mBsM2W7x8xDnxjZ0N" +
+			"RbhcFZ2E6A1ct6HMunuKxjoROIsdWhrYMqJfKKMTWMviz1UjtupsGUWS0dVQCquAr6DJmr" +
+			"W88P8wgiVH2VZsc+edDmCGDunrI=";
+		public const string Intermediate_CRL_3_PL_01_08_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIYAVh4kiGtHMwDQYJKoZIhvcNAQEFBQADgYEASw1+" +
+			"6rGDKgpUtXcCziQCjy8mHFD2zV6x/Ppxm2Gj0U+5eFnIbMPmr4TUYwfSOROUycsiJX/Wa8" +
+			"HEuqWJhIdcsHMA7TYf0iSXK597Bljjg4F/1Rgz0wqLjgMuA59eFbKjJ6zP1E6Sv2Ck0Ea9" +
+			"HJsv5zFA1ljVnNWoQwoHsuLk/wk=";
+		public const string Intermediate_CRL_4_PL_01_08_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUwWu+HaFDXwwDQYJKoZIhvcNAQEFBQADgYEAHHKd" +
+			"U1SccTsK99BUDrvF930ejNRAvHQM9xv80wcUAy18x+TLwBH8vDTmP210/C5Zk9pQs+rLDd" +
+			"doQQbWJrQkznyB1OSK0T41KZ9L0UE+YmFGJjz0PEzYHV0Kc57j5uc7Fsi8Xu20Y8JeTaJs" +
+			"FUXVsvnCuoSxYmwY1futFWHJG7Q=";
+		public const string End_Certificate_PL_01_08_crt =
+			"MIICljCCAf+gAwIBAgICAKEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTQtUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNS1QTC4wMS4wODCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwgNkhQrcqmjhkES6DNAW3uQLKILcFlrFvOlWfDPo" +
+			"ngXzCKeed85npqL+Enxo4sLarEiywuDLrDgPf0gKnZXQWBmzWViZhvTsiAemH7iNsNS68s" +
+			"hhb0vnLzlPpDUJDv7KVKW8VbM7nvplKptlEE6g5kmj3iEmM4l2u8Z/pmQoTsMCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECLfApJ09y/ZNMBMGA1UdIwQMMAqACFMFrvh2hQ18MA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAG2ANLc/ib9ayz0B0L6/XQf/xuwETEq8kb5vWml/PbcFD1b/uwRHI8" +
+			"vTvM559nZgtzkhS5ZAvNBTh1CB9Ox/nugHc4srbH6/Wcd94pMQx/sfCB/C6zZ5Tbm7Y4jp" +
+			"hkjnxwGUYTvgNzxmaAPLyCfqY7KwhCSzns2M+yuncEKqlzuT";
+		public readonly string[] TEST_61_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_08_crt,
+			Intermediate_Certificate_2_PL_01_08_crt,
+			Intermediate_Certificate_3_PL_01_08_crt,
+			Intermediate_Certificate_4_PL_01_08_crt,
+			Intermediate_CRL_1_PL_01_08_crl,
+			Intermediate_CRL_2_PL_01_08_crl,
+			Intermediate_CRL_3_PL_01_08_crl,
+			Intermediate_CRL_4_PL_01_08_crl,
+			End_Certificate_PL_01_08_crt
+		};
+
+		/*
+		 *  test62
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_09_crt =
+			"MIICmTCCAgKgAwIBAgICAKIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wOTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4slldx8rhfz5l2i0rwib2McrCyQkadTjJRoEGQCV" +
+			"xT0dmw7GhDa6wJg2ozXLLk5y7ZCwlmBOTEoNbigHvcKSnJT8R/S+F4KqBz5d5dbRMNEKYz" +
+			"jdbD7Sm7id+eyfq1s5cpmta2lBJ5gTaC9YPSOY2mucGcJ1muYzdOc6h+PCCNMCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECO7tq4dJC8OgMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAHbth0HjAygIoWVrz59ZBPntOn5nzgUGpH60aSDOS6i9ZOKSoC" +
+			"7wCOEt6IpKO7M7SNznxaX2uhFTYotneyq3qENvqZVXKhE6wQRsdK4kG10cxSB5AXPHJRgk" +
+			"W9+p+Nb0iYVKwHdDCW8KHYIroGhSkKxuflwxhK6DcwQuA7y5q7r7";
+		public const string Intermediate_Certificate_2_PL_01_09_crt =
+			"MIICmTCCAgKgAwIBAgICAKMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wOTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA70v7BFxmToZHF5M29JK6N0Ha6n729cv1U912mH9O" +
+			"NTz9tafa+jv4W7njScv21CJbNlUO5rlAFcTlXY0U9vbqHEufhtwRQqi7+pkfa+Ig8bwl26" +
+			"4U8L5rgmSvZJpEiiKfkmF2Rz9+zPPhHjk58ZcKoAcyhOdZ60KqmaaU/TVtEq8CAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECKOwR13+P/BlMBMGA1UdIwQMMAqACO7tq4dJC8OgMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAN71oLHr0+uf6zCOC5L7oeCOGMUwvZyROu8eTztZrPYGjaamSm" +
+			"Z0ZmUPOJP3g5nO6tHf34Tb9CTkwPdPicEaXuxflkSbJBV3mUFQ1BUDlyYTuaL8uT2N61dg" +
+			"xt5RgYTIGsW3/2XrRvXsH91gSiEkccoUyjKnQcX3oZmEeITb6H8m";
+		public const string Intermediate_Certificate_3_PL_01_09_crt =
+			"MIICmTCCAgKgAwIBAgICAKQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wOTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwMLmDs63ai7i4xC/1ufMFWeigJAlbKWMti/PeEKi" +
+			"7LBfNJDRaO+1kde6QIo1vhkhKtokNu9ue3Rfo1+xGuZVohjRbHnmamEm5G3jihegPQgGCR" +
+			"fDZoJDI9HMbwBa0RWw1Nes5igIVjdSHQKO/XTul1yyF2Dt03K2qeLwes+2FyECAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECPEAjG80q0FoMBMGA1UdIwQMMAqACKOwR13+P/BlMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAN9eiZXma2n0XgzdvYrlV/IEqBIhpcZ7gycjDumVBVITZJD2sJ" +
+			"bkBi+N8dg7uovgxGxWGsyxqgAboLhMgbpbFzGh+HyIhQu/CeAx93PWYc5rP2l2Y8d7KJvk" +
+			"p1GZEcG/nTakpjxTQ5MQYFsOHVsnDDOyaZYvqPuMrwGYsfoUa1wq";
+		public const string Intermediate_Certificate_4_PL_01_09_crt =
+			"MIICljCCAf+gAwIBAgICAKUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wOTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAo4L9QEqzq2VXzkZI3cvUWR5v6vreKKQPfJPfEwNH" +
+			"nMS0cgDjC4Fnw9ySI7Eb4A/OJGLIyg84mzTl6JX3kGoYr9/bJ8jOD7pN6CljXuHpwwmd7L" +
+			"6Nf5Hy0ltjAIr5s67e33OWdPi4gApS4FN6nPSDkZotY73d1xqJYQQZWuNEsGUCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECLfU7BuxzXeCMBMGA1UdIwQMMAqACPEAjG80q0FoMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBABmQZOvwRpVsTD8uazfQpLJUZkuTap4OOPHie5xJsvOhGend2k+LiP" +
+			"7btGoFrqmkyVV/+dNA8+45SRsnoOtgctiF2ubeqIvd7xf/J5C9Cmo+T89Mt7WEBEuDmEZm" +
+			"JPXvOvyh6lRcYVSBnvVW5ZSstNAQKa/8xuyN0OrE1hJWbucn";
+		public const string Intermediate_CRL_1_PL_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI7u2rh0kLw6AwDQYJKoZIhvcNAQEFBQADgYEAbXc1" +
+			"QgR2TAvOPqJmRFFrDQkPVIVyEEDTwZy5aNnoAKK+AmJ5FZkBtbPJ8qt9UeYRh8lbX8+EIk" +
+			"tyrAKw/1Kc3h7RDqAQ/p8t8kFwVQh2l4KTIukV8hYcj5sMKlt5f49ZwzWPyoOaLDomiUfI" +
+			"OY/jaDMw293AjQXxGCDtnaTvh0o=";
+		public const string Intermediate_CRL_2_PL_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIo7BHXf4/8GUwDQYJKoZIhvcNAQEFBQADgYEAq6en" +
+			"XtvIdh/DifGzWn11hqJIZxLQDGJZPoMmwSOLyB6OzsPrIg1xkOWZYEOELTR8+qP6emmx+D" +
+			"CaEbUDLj60rso0gRQCBwTgHgjeMRpv8fGnV8MJgMv5BdzsGAGQbLSSY9FxtqeCPfZ6olHC" +
+			"iUIopdZJZP8ZvGKQ6QGaMnLpJ78=";
+		public const string Intermediate_CRL_3_PL_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8QCMbzSrQWgwDQYJKoZIhvcNAQEFBQADgYEAraCx" +
+			"ruxopFbKvxOx/CIF4niG27ABB2ZwU6n4NBGYHo1Y9NjuytjjMZvQjMHyoayqpnF5TA1vXL" +
+			"jXjI3VgQcK7A4ah/0FNLFGtczyY8kXXrpbmdg8+xdNJEG3/e5rDW5VSf7OY1XqU85ySUJQ" +
+			"ZR5uiy8LxlDdaIT4WT7X5ezs3wk=";
+		public const string Intermediate_CRL_4_PL_01_09_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIt9TsG7HNd4IwDQYJKoZIhvcNAQEFBQADgYEATtjA" +
+			"BdSZYnIbv1bCL+aSiioJg9S9yWGD1mjsA/CDzvkzSffeSpvqaSy+Zwwf+NDMMG6Cs+SgU+" +
+			"sxQdJALAbb4sYGEyXj/Exh9BYHvgoVahH4NWuhm6LIN8RTcMDAtGoGYFNGXGuT8XRBUJZ/" +
+			"tH9re3gpWaE1rjWeB/2ZBR5ONcM=";
+		public const string End_Certificate_PL_01_09_crt =
+			"MIIChzCCAfCgAwIBAgICAKYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTQtUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjA5MIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+g1Puqjn+/Of35mqVVUricIV5x+bpZRCAgBDh" +
+			"VYcmZFXLB/XnRd/mYTu0RR4ISEerC1km5tjGeCN2k3NGdZwz/wEh9kEL8WikSqpxUSUD/N" +
+			"vQbliz4f3YECLcpNXKzkCvszeB5ZGHa0sLYDg3r62wy+1y2rtcrHzFEoMFgnnruwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECANGcL2klYf7MBMGA1UdIwQMMAqACLfU7BuxzXeCMA0GCSqGSIb3DQEBBQUAA4GBAHm+" +
+			"/vQ7VxDry3VqiqKnNoOhAHTTIUphNWF4jddRqVc32IsjVaeTbcGwCIRflRm/lUplRvXXxb" +
+			"JEbW9mP3nfTCREUdm49hjmo/szsPjgosFoEmuEKXThC81/y2vQkb4/jqRoOHEknU++38EU" +
+			"Juv6Y6psZNa37x8Yn3i7S+b3TM2q";
+		public readonly string[] TEST_62_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_09_crt,
+			Intermediate_Certificate_2_PL_01_09_crt,
+			Intermediate_Certificate_3_PL_01_09_crt,
+			Intermediate_Certificate_4_PL_01_09_crt,
+			Intermediate_CRL_1_PL_01_09_crl,
+			Intermediate_CRL_2_PL_01_09_crl,
+			Intermediate_CRL_3_PL_01_09_crl,
+			Intermediate_CRL_4_PL_01_09_crl,
+			End_Certificate_PL_01_09_crt
+		};
+
+		/*
+		 *  test63
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_PL_01_10_crt =
+			"MIICmTCCAgKgAwIBAgICAKcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4xMDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr4LmuvhSms70CnuAHIHwz45csKvBPVtcDjA1tWNb" +
+			"NIvvNHBzyt6G8U4CTVKmsFAZOzrWJem3b/ZywM1WlDarGJAAa/SRIYZ/jQwaOIoPW4OUfK" +
+			"ZQI6MO7uAPcIQ4ugtPth10viVqZYLZn/6O26Q905YsFltuPFl64KrJVJJBlLECAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECGRn9ckrcsEdMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBANK+1qalm7Nl+PJHT9nQLVJ3ruQNAoMlH9fN52Q9BZCr30iWCd" +
+			"+GhQIPRjxZ4GWojMnqbWzYQsxIR2PLdFc6SwjQrq+i2ES/LePDtaLQddS44/+GP/+qDpM9" +
+			"Mqp3/Nbe1MfOKRBT57qgrxa8eUVieysoKeYX6yQpa8bab3qDwOTH";
+		public const string Intermediate_Certificate_2_PL_01_10_crt =
+			"MIICmTCCAgKgAwIBAgICAKgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4xMDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAx5tMLJ3LRxi9jAzCSNkj8zyrSO0cImNGf6ZCIzEU" +
+			"V8LrmXjgiZboPTh9LWQ3msWDLpzaxVxDLBXG3eMO8ys46TfJKciyeoiB8wfuNGMKAccm8u" +
+			"43XjWs1KAdNikWEZupYPgdmA92oRlVcHshG9PqP4+xA6sydpu3V18Nyfa0n3MCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECDE3dDXkS7TxMBMGA1UdIwQMMAqACGRn9ckrcsEdMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAE+8cyOUQ7y4atc4BlZNZvGNRZ63dbGDCM2AItTEAf4ETM9v7j" +
+			"biUWTirJyoWsGxm2eIUk1V+EKxcuO3FotFUe7lS6thmVd6OYOSW+02RXMNklmptzK9I3AK" +
+			"DZNh82ugLNyrrd06BSiED+0MoGVVI4gi3wdFtRiai+MgQVeWIB4i";
+		public const string Intermediate_Certificate_3_PL_01_10_crt =
+			"MIICmTCCAgKgAwIBAgICAKkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4xMDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsmSUL/UZBYMdqU0PecjCd+9U+1Ld3mKkH303Fido" +
+			"K6k5S4ZObxVHKhYDJyp3CcVT2+nENjzIfQQQaA11UK7Uf/jmVs0IC8e2scWzq0W2BeOLef" +
+			"jVgNgXGsXyfLi9T4KJPPyGsKlIU2R2xKxgHmAOt/tw6OYX/OaEfM1jiQza5lkCAwEAAaNm" +
+			"MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" +
+			"lghkgBZQMBMAEwEQYDVR0OBAoECHYI07i4owpIMBMGA1UdIwQMMAqACDE3dDXkS7TxMA0G" +
+			"CSqGSIb3DQEBBQUAA4GBAK23Kx99Y9HtFBVnHWW/NfvNro7I5Wx/ZCko6ulHm84FPAjhnL" +
+			"tvc4jmfAZd0wYPKQKWwUKUDWNEwIU1qkxyJYACckue35GLzj8aLY/z+h037vGonFmNutMM" +
+			"rcRdiV7gVD17dYLVTt0RgxsDVDtut+twqHgIaKtKyJnl9dSgFFv1";
+		public const string Intermediate_Certificate_4_PL_01_10_crt =
+			"MIICljCCAf+gAwIBAgICAKowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTMtUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4xMDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEArgBnLCnqI6Sa7gXkZOvIKH4EL5i3CoG6eGG2R8aA" +
+			"kjBs78IKGYj9gY7rRajAKSpf19zvfcW8+2gBDDj5AoCy6uDnBICmqdu+hkdokVi8dJHiTU" +
+			"9LdS2TeuvFv47eiXoEBjMEAquCuSyHvW3lNrA+ESTnK3s7V4lBoO+o5mZD6dsCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECLTgYziQC9zmMBMGA1UdIwQMMAqACHYI07i4owpIMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAEx8wgBjBglU98rocddKAEKXkt4MNzrpUMq75C9HtnuOtFgM2oY/OC" +
+			"x67aZSTEph9ag6Hc+MyxWB5rzGD9j0y7OLsasE9AX8vjplUq50wq1xAFkGi1GnqRK/Oe7D" +
+			"S6R66+UFHW/3KAeNe96aaJuMcx0TRbfkGbW1ASSi/ixMd9Gi";
+		public const string Intermediate_CRL_1_PL_01_10_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIZGf1yStywR0wDQYJKoZIhvcNAQEFBQADgYEAjkY5" +
+			"nXjLst8CMz0fyEM7Ft2d9TOOJXV4TMAfSAP9QCnit8qzrdVdJ6TJIsJNZYBz9Ryr5K/iSw" +
+			"KbYk0g6y/pskcMoHG3vJwNAxBbkf+fV7Eyve+90Z6oWDXHKLGCQQpdZ0a0wAqYeiScok8+" +
+			"YHypEVLfbjWARR9fsci2Ps3tdvA=";
+		public const string Intermediate_CRL_2_PL_01_10_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIMTd0NeRLtPEwDQYJKoZIhvcNAQEFBQADgYEAdpTU" +
+			"xcywBjX2rD8Gu6zkDqlDmZfRXHDPtnf2RB4bHDx77kDEib6nH6DGoJdx8WnRTZsTjly3MG" +
+			"62LfVmjp/bJyKHUQqBDrilv21EWsaI9JOr673Nk5iTZa/645GdgyLzSmxvcVDN40BAH0py" +
+			"/2gvBQTPNzp2W1IR2mebuLdHwTI=";
+		public const string Intermediate_CRL_3_PL_01_10_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMy1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIdgjTuLijCkgwDQYJKoZIhvcNAQEFBQADgYEATVf2" +
+			"cEEGphsIe0AsqNJ5rENLe8DeDAV8R4XCKdeP5qmHmLMm9Z4pX8bIfU7bCoXiNIwGvIU6ag" +
+			"FmHPNHEj70cQFVqCX/ZESc02hit+Os9g7pcl7s9QgwVUCMZdCiF/+pSEp3eCL5tFoKmAZe" +
+			"nxkL0KOSuKmBzuqRtZufbhDvmbw=";
+		public const string Intermediate_CRL_4_PL_01_10_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBNC1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAItOBjOJAL3OYwDQYJKoZIhvcNAQEFBQADgYEAbG2B" +
+			"BhvRQ1pY/8VFeiCRFD8mBzq5iW5hWv2P7Zdp9zEbQo0fI4Kbis3OGemEttCxvAc/UPfogr" +
+			"UudImf3s8sLV9BS59xQUGQlxZ5XBNlripY8EjHNWrwgy7/x4hzlZ9yYBbqoNOqnHLy/gbM" +
+			"XZWoCbIK0co70lh1soOQ6eqLDKM=";
+		public const string End_Certificate_PL_01_10_crt =
+			"MIICljCCAf+gAwIBAgICAKswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTQtUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNS1QTC4wMS4xMDCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3bx0qx8s4Zse6Ri6NqkLEKUPLIOhTFj/9Dh7sxvE" +
+			"HpemBlTjbp2in08WTxEb9n8iAIWuGs3Vqm82ttBQmayjIaWD5oE/BE0oV/e91NAv/aRLsl" +
+			"f7VtOb6vi8Ef6muOAjI2dUaUD6QONkqkJhnZ353uR3LZnsAEAW+InePGFNEGkCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECIokB8m8Vi4QMBMGA1UdIwQMMAqACLTgYziQC9zmMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAKBGQwZQLQFXb+/kjP5xAtq+1rRtrblytjpv3ujJrKH1v2VB2+9boB" +
+			"0YYYGJTy2Wuj0ZBEMeTzMO8Hol4Mq9pnYv5DCmfnZN3FuDidgnRsCjM3ZL7NcXXG9YwlKF" +
+			"G2SXj0YfkSwN9gnyN11W8i+F/OSjlm+TDKHB3ePMcY8EnnXy";
+		public readonly string[] TEST_63_DATA = new string[]
+		{
+			Intermediate_Certificate_1_PL_01_10_crt,
+			Intermediate_Certificate_2_PL_01_10_crt,
+			Intermediate_Certificate_3_PL_01_10_crt,
+			Intermediate_Certificate_4_PL_01_10_crt,
+			Intermediate_CRL_1_PL_01_10_crl,
+			Intermediate_CRL_2_PL_01_10_crl,
+			Intermediate_CRL_3_PL_01_10_crl,
+			Intermediate_CRL_4_PL_01_10_crl,
+			End_Certificate_PL_01_10_crt
+		};
+
+		/*
+		 *  test64
+		 *
+		 */
+
+		public const string Intermediate_Certificate_RL_02_01_crt =
+			"MIICljCCAf+gAwIBAgICAKwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMi4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3AN+Y3Hl/9V0nKXHQotb/cA2VfZc5vrRu+ZjwKgK" +
+			"6KasGegAorKSTybYX/fTbnaPwykDPfSscAnzAW5WdF9+wTLmvYc+6pkcx1ryKkGmofFMXi" +
+			"bZ5LUO/oK0iuNjBKfLdWoi+hpciKyPb9Bs8SO/svKSNqTEbn9ts3q6tpbngoECAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECGXQ07qiAqv2MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBADKtN3OOaRdte0X4xLC6nTGaK/u7IEKQ0DjduDHwJR5w27zefrx48Z" +
+			"dlq8t5lAfQJqWmfk7iCIW1QJPLcZOouWDP2S9Cb0YooGQRIEkMjpBn3Xufx0XUphtCDs3W" +
+			"9LAMVXqfuce1tpZ6Dvrh6/H2X8rJMU29Czsz949bh6tcsHJi";
+		public const string Intermediate_CRL_RL_02_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIZdDTuqICq/YwDQYJKoZIhvcNAQEFBQADgYEAxrDH" +
+			"zKno1mkJqPTub0c9To6jC3CGTilV1E12oD0kFjkXqL40+W251qQ2wMC+G7ZrzBIc5dRuJ9" +
+			"3feHZ7cc03/s3TziXDvSyfNOYpHzkPwT48HuSgBYgJ3uswwk+tDiA64NzbOJqssxxhFRok" +
+			"9OpwC8eQkzgpA3a6816v2I3XL9s=";
+		public const string End_Certificate_RL_02_01_crt =
+			"MIIChzCCAfCgAwIBAgICAK0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDIuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAyLjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCykRGcIKuxia47yRmJT8XpNNi2LTTbUUTteIBp" +
+			"DZBfz2ExeWLruO9Rn1/oB/EP+4apx4r9rQ2tGsvr/7qQYeQK8W7eJzZgvxFadY57IMfUNq" +
+			"1nEnj0ZvuWrOSf+K9v6FWX5Y2uyZS5Uvb1VVQv0Ev890+yXTtthPTjepk3JkkouwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECFIkVrx7NRAdMBMGA1UdIwQMMAqACGXQ07qiAqv2MA0GCSqGSIb3DQEBBQUAA4GBAI+B" +
+			"T6bFZruoeFHXsYVjkQ42jSdYB9JuQkG7JLKte5gGlhyR+jMlJBzxBgNIfvlmYSnbRFPbE8" +
+			"eqsGm90hJJoUuVMkm0i03H13uddlS494O6HhTGpaKcYwp3hbLhVcaY3wFTqTCuZk1T7Oxq" +
+			"ggTrCDYvNH+/ZpQuy6nB/FH3SAHS";
+		public readonly string[] TEST_64_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_02_01_crt,
+			Intermediate_CRL_RL_02_01_crl,
+			End_Certificate_RL_02_01_crt
+		};
+
+		/*
+		 *  test65
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_RL_03_01_crt =
+			"MIICljCCAf+gAwIBAgICAK4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMy4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsZG8wsV3Kuo+jtnKxLYGBuAqQwUh6Cs7ioDTNUFI" +
+			"UDDJ0lOP1HVTMBA7DEcyTCGvnQ02dEVVuCddBTQvG5RvW7G7cCEW37cS56/3yPsU1bD/cp" +
+			"3C1pPJpoun04va91Sxtgcmx7jnz69QPVrucu6aI1sZyeOlvzb8K7DceaAfR98CAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECMNzJ3SpyOLxMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBABo7oKmQilgji3w1tGz1cMrWxZxqGJqOAKcHywli+oxFo2oxSfEuFS" +
+			"tN2aEd2Ja5HU5a0ySztvByXF1TTNurGez7ARxmcS2kpoQtQXTloywza4A5N7iQwk0yyo/E" +
+			"J4lrXUfVRwZHr7FwA7qMODtFb0+Zivv9JLaq19GhnRhzZyWp";
+		public const string Intermediate_Certificate_2_RL_03_01_crt =
+			"MIICljCCAf+gAwIBAgICAK8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1STC4wMy4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt7yNq1QZsV3p7OR8rgPuY7x7Bvs+nPhcLR7zFOgR" +
+			"+plQUwpWQ2PhuzReVV4jNasKtNK9MIWoeV+eV3pEiso5obb9+Byvha1F6gkYNZMPs9Iv86" +
+			"cJSMtownNJVGVAL9FEpof1QKLp7kfn08EjkoGmGy85xy9uFytd2S8n5TlrBqcCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECAVwoCPFqMtqMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAL9GufFieduzBJaMtsXtKHMf64O/KAGLSh1YDXS+a7Ku+EFw+WteKU" +
+			"Ob6+c1m7VH9P711eATQoACotCdKusPECqeYDEmT9keqA4f7cP4VcvGwhvSVQJsPuB3LL3S" +
+			"LIILE4zhT+O9G+5v+mkG/pEDirRYk6ZkdM91bsUuzsX40uyn";
+		public const string Intermediate_CRL_RL_03_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1STC4wMy4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIBXCgI8Woy2owDQYJKoZIhvcNAQEFBQADgYEAkwyA" +
+			"I1rrz6tOmEpBHDzuJfqY2nbXCIXFN6dVuaKNZWHJ4ZNIc4/t29Wa5GgXYrVXyXRcXP/u5k" +
+			"NEhOX2/NwCm6vL8+tclYP5qPLrh/Dk4v3nvcTFLKCvclAbf4Il0zfMQx+RRnO5PPqPDu5i" +
+			"1tHHwOtA8Q+oO71lZEwPE+pX1Sc=";
+		public const string End_Certificate_RL_03_01_crt =
+			"MIIChzCCAfCgAwIBAgICALAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDMuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAzLjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPGLfi8/T5p63cbGE98mqO5VzkeI1r2/2TLgvY" +
+			"RpL1h8i+CVYKoX37yYwNXf+HkHhj1OXJSNrm7853ctmDf2h1fv3f1+qJLg4VRVzlEgErNq" +
+			"74OR7XLXV77kGOmhip2g5BF5VKeqAdj0pCo1E5ZFHpRPFq/0DDmSda6GKJ6Dl8hwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECOHM3uWxFmcrMBMGA1UdIwQMMAqACMNzJ3SpyOLxMA0GCSqGSIb3DQEBBQUAA4GBAFBu" +
+			"doX0TZK/yoUcrSkP8AtFiv5c7QvyEtigFZTT+lbW/g4RX/oJGNZCu78yAxCczl+Z6ft+0V" +
+			"wInwahjyyAgw4QXxtw3b9CfqvT7HH7hcQ6r9ZA/NA9XpzNtxKfmXjzCZWdfmLJrd8KCnU/" +
+			"utKRAObRBKiaTGa178SEWvtkoIXd";
+		public readonly string[] TEST_65_DATA = new string[]
+		{
+			Intermediate_Certificate_1_RL_03_01_crt,
+			Intermediate_Certificate_2_RL_03_01_crt,
+			Intermediate_CRL_RL_03_01_crl,
+			End_Certificate_RL_03_01_crt
+		};
+
+		/*
+		 *  test66
+		 *
+		 */
+
+		public const string Intermediate_Certificate_RL_03_02_crt =
+			"MIICljCCAf+gAwIBAgICALEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMy4wMjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvoTuc2LYBOhziBe02f6F8l9MwX74O1lknBcJjGvq" +
+			"JcirQx/6hQgBQT4hz4RRXNy7DSBr3swEw4eDNSeyd6kvG0h9oI3+SVmVyPPVi5eKDL1roI" +
+			"OBzmfx1+Nn/CnwOf8VroKDutBBQ0gJ24IEjwp6er/8hEAVN/yIjIi/MTFeoRkCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECKtCUOlmMPu6MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAI9x8O/JgJuZV/s4OBUy3AvcW9QP3HWWBQSdxUdjSosT2schjn7wrR" +
+			"gttL7vWjT1djsbATAHa5C3inG+VjGIq/NqWaPoHAucRNMs4oZX2ACZFuBLOb/qhywsKh5+" +
+			"bjv4QgtqkUedzEratY6yQiJSiMSJVJSMzHosTVMX7oOp+cll";
+		public const string Intermediate_CRL_RL_03_02_crl =
+			"MIIBcDCB2gIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" +
+			"CyFw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgIzAhMAoGA1UdFAQDAgEBMBMGA1Ud" +
+			"IwQMMAqACKtCUOlmMPu6MA0GCSqGSIb3DQEBBQUAA4GBAAEZ0Hg6sKiVXIeK6zbQrKtMMz" +
+			"Vz2K68+SqN1LAjlNW6u+HSTlAvhRIFO1Hv5Zj7qbO226rLxas/X2XWXpMlm84NHN8T4dZU" +
+			"4Yo5rhhpCHckRxNYn3AFcfcV4ra1rrTtdx8e7e7/m0Ghog9Ny52ZuQThasL9caF0JxUx6d" +
+			"zbBHPm";
+		public const string End_Certificate_RL_03_02_crt =
+			"MIIChzCCAfCgAwIBAgICALIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDMuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAzLjAyMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNb6HGPRDulLMCCyCq6w2X8rHPtm1gN68JXFkX" +
+			"j/BZsHhu29Z9hXj76hO//7O775EPVMSLyRy8t15yzYpXfZRHFaGB5bs8U2R5ClvsD2FR0H" +
+			"t0JVfU6Ggn1lhO+jOiguJtXVRjofsfvHuiOe75ctaJ9lBpgwiV8tk4VRKz2e5xVwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECI3Gy0TgXMrwMBMGA1UdIwQMMAqACKtCUOlmMPu6MA0GCSqGSIb3DQEBBQUAA4GBAISQ" +
+			"Qh9+7D6nk3FL5YQOzyZ0BSHQYjpbIVykJ+Lr4jBPKyGgCqW6jqWNg7X4waB77J2z/OkavY" +
+			"A6qtpsk8r2wmG9thi8JyZZNhYMxAszHzFbBmSoxGRMvI0XarxgIu8Ky6V7jKVDLz12C3o9" +
+			"H0yd+nZXilCD+p9BTjjg5bGUogJS";
+		public readonly string[] TEST_66_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_03_02_crt,
+			Intermediate_CRL_RL_03_02_crl,
+			End_Certificate_RL_03_02_crt
+		};
+
+		/*
+		 *  test67
+		 *
+		 */
+
+		public const string Intermediate_Certificate_RL_03_03_crt =
+			"MIICljCCAf+gAwIBAgICALMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMy4wMzCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAu/o0uxgTrAvNDrMNuG2eTla+AmkLVCIXBbsIo0gs" +
+			"tLm29tLwfBh/8l5OC0y6Xeh5lx+NLdelsiZGRNaaWmWHj9Ji5V6rclr8sXRDUjxe12zLeh" +
+			"0G+a0TfpL380cx9RItqQyA1ZRiUNymmJHnm13hwrf7LPirR9BMrtyTT2EI3cMCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECHYt39LYdEn0MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAIoSGa7MxnOuHoWM/BoJKsCeBmBHYCYDKmQ19JfsDHW8z8oAFiikFb" +
+			"Gtw1Qpc0GFfJgN0cppaXfe5lDS6BWL2dPorhu3URfXKu84ATLwGmNhqLDY7zh/zPvLtG2m" +
+			"izaMLC6ZwZL5KELpYpcP15EHPDquyP1xpV3fT17GjpG9IH8k";
+		public const string Intermediate_CRL_1_RL_03_03_crl =
+			"MIIBcDCB2gIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" +
+			"C0Fw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgIzAhMAoGA1UdFAQDAgEBMBMGA1Ud" +
+			"IwQMMAqACHYt39LYdEn0MA0GCSqGSIb3DQEBBQUAA4GBAI3HsXanos/N6uO3QVUaBZzmCt" +
+			"w1HCHMrLVG614YlUQiEedQ/oEc7dwCeD1rUbGNVkFPIRvMkmUQo1klhKAlEUmrtW+aH+If" +
+			"6oqumifqxvaycWidacbgNLIAMQtlQmniPF6Pq0dv8sNeKq4CE0gjRHOPJ2zIqy3kJ3tZYB" +
+			"pTguwO";
+		public const string Intermediate_CRL_2_RL_03_03_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wMy4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIdi3f0th0SfQwDQYJKoZIhvcNAQEFBQADgYEAXZSZ" +
+			"ySsD7U6ETy9ZRmiKUCJMUV9CIhCY0mEihHjW0DhFTyV1Hr01yN5zUr/IFVuP/Xcx36IX4l" +
+			"dVv6/MgR1GeM/BUGZhm4z6YwfAosZ1N3zayIy/pP3fa1rVRl8cgCxc/8qxg9nH9p6yPpxM" +
+			"AOOu6TLYquk/dA7wJPEW7MPixXY=";
+		public const string End_Certificate_RL_03_03_crt =
+			"MIIChzCCAfCgAwIBAgICALQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDMuMDMwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAzLjAzMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5LNxAB+lm514Hk2ykrFUb7fCX0ryIEMg0mgeT" +
+			"/z8Iw7xisht57koK4PTXY863aunfNNh+8oFTHZnoLB5dbkROj1nFRgcWPezzv1wNkZEpxn" +
+			"NINtTPBogW22NPznoZ/rSk9JRFe0sCOVazkW9tZbY2ARqyJsYU1ez5tQIkDS47kQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECMWddsi+qmxKMBMGA1UdIwQMMAqACHYt39LYdEn0MA0GCSqGSIb3DQEBBQUAA4GBAAv8" +
+			"nrJaqEycAyIKdPBYTUqaxjkv4SmonDDJG9OqvD78/o9hUKKteoMkNUp8eexTkWk0L72L4N" +
+			"/eXB30+m65E841V+Dy8L4bXh15n4qz4cyMt8Kvm7nbCqcgpiyBJmBxzfaXDLSthlmhcJ4X" +
+			"zDFnav1LEw5fZklt7cnMl4YvLD8d";
+		public readonly string[] TEST_67_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_03_03_crt,
+			Intermediate_CRL_1_RL_03_03_crl,
+			Intermediate_CRL_2_RL_03_03_crl,
+			End_Certificate_RL_03_03_crt
+		};
+
+		/*
+		 *  test68
+		 *
+		 */
+
+		public const string Intermediate_Certificate_1_RL_05_01_crt =
+			"MIICljCCAf+gAwIBAgICALUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNS4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA59vHTe5A9AcT237mW7HdSfh8Pu4P2wJNLT7RXczN" +
+			"7DD/P6mAkugSgPTXwwlE1oSB/hCxAtEPhwONYZFYlRClFJidHDdVApalB7UbosTghsUzAg" +
+			"Lqw7NL+w9i3Un2G7JM2oWwugozQn/1hzr2Cii2TIB6K0RWKoPBJvaWUURS/G8CAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECP55Cc4eBca8MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBALX594y5uF4Rt7CoRHeKZ5h8QiG7mc+kQDMjaSU4KJwNVVL0mJatQG" +
+			"w90yFfhvprlgDt9UIAvpF6z5gysbrjHXJaEhVlXeg9D5mcxsL4THEc8f6oU1GjfT/SOD9l" +
+			"QrT/keX3D9lcFEaTOgi0HIZ7aFIJgoWjXF/9kNNMEAs8sJNI";
+		public const string Intermediate_Certificate_2_RL_05_01_crt =
+			"MIICljCCAf+gAwIBAgICALYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDUuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1STC4wNS4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtl4hX6HlF0M+lSBTG8jHiB06hOy87LL81yAE2JQt" +
+			"/6F+LZjuOBTCIc2yO2bVM3XzUnjyYDBYGnBFp/7XpRoiADuPJSfmkzmezpyJc+hm96UR1g" +
+			"Bpo+pPKbRTWuM+FYy+vPtaDk5wKOrmyNx440PwbzxTN3JeWz17xeYE98bXMc0CAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECJOjtwEYV9VSMBMGA1UdIwQMMAqACP55Cc4eBca8MA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAFbkOffoIjWSfxEuKszoK7Fj27Hf5jlV92xqXtBLURjNGi9jCLUIUd" +
+			"QLnONZLJYo70Z6XaGjpAK1EtZKVWsz11JDq5egE1zNES//9Tz8xDtJ7Lcq0mwneVFxmBuL" +
+			"gxkw4GKbBFKz10FoSP7VJWaeW080WwKnp96Me5GtZRe260N1";
+		public const string Intermediate_CRL_1_RL_05_01_crl =
+			"MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wNS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjA4MDYCAg" +
+			"C2Fw05OTAxMDExMjAwMDBaMCEwCgYDVR0VBAMKAQEwEwYJYIZIAWUCAQwCAQH/BAMCAQCg" +
+			"IzAhMAoGA1UdFAQDAgEBMBMGA1UdIwQMMAqACP55Cc4eBca8MA0GCSqGSIb3DQEBBQUAA4" +
+			"GBAIdOaBfpAEKWLrSvepVjk3UTfEfsSP6y+kFMl33YXy18xUvVpLarGu6YjQIpXiL+ulkP" +
+			"eF8TAc9AarUjvDf0kcslIOt3NhdMxR4/F614Ds/rPEXs4c7n4kCkvAlFg/19iIFeCaynx3" +
+			"X0s/v1SwzgAUHi3P+OwAGDApDTyKbnmzvt";
+		public const string Intermediate_CRL_2_RL_05_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1STC4wNS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIk6O3ARhX1VIwDQYJKoZIhvcNAQEFBQADgYEAfOOd" +
+			"JiLUCFSurAafQEBfxE9KVrgFC+W9m64cmERicO1QL9aDVIDGJAIY1pdvWVdhLBIKwSugwB" +
+			"ZH3ToptY+VizvFN1gkKGL2OuvDsXPHn1+QgmqvxYFPmvwDcwuxZ/3zD1VeHgEIKo9ugRnW" +
+			"F8G2Ph6SWUxJCjJQpB7WIbydowI=";
+		public const string End_Certificate_RL_05_01_crt =
+			"MIIChzCCAfCgAwIBAgICALcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUkwuMDUuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA1LjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9NWkW/mia20c5gM3DpcTsBWTNC/d/Cob+OVrS" +
+			"lYytMjK4htO3MavavMZNTLAYFCXWhZ+Uo/uiAF0ddE4HaFI418eKJMSSbQyed0TG5Udw/t" +
+			"3dhYeLzLEmVc0r00q5v+CLINsCNQAKaPV71UvoHrE092zZjmtacuAetBS1Q2ufpwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECGNPOXdCLpZ3MBMGA1UdIwQMMAqACJOjtwEYV9VSMA0GCSqGSIb3DQEBBQUAA4GBALTo" +
+			"hfBEPdzZ6A9QNStakOhmhHYox70xOPuWqzSbIugZv4chKXNQGiUAoOGImTw1mcun/uPNtd" +
+			"0bT+O+a9yX5gzW55CSmR/teHkTkND1mJhOMuYOmaCaBHnqgIIe1iEhMZQgag70+/tSmmQm" +
+			"UpWGpxeK2c02tBK6gEmnqk75bKRT";
+		public readonly string[] TEST_68_DATA = new string[]
+		{
+			Intermediate_Certificate_1_RL_05_01_crt,
+			Intermediate_Certificate_2_RL_05_01_crt,
+			Intermediate_CRL_1_RL_05_01_crl,
+			Intermediate_CRL_2_RL_05_01_crl,
+			End_Certificate_RL_05_01_crt
+		};
+
+		/*
+		 *  test69
+		 *
+		 */
+		public const string Intermediate_Certificate_RL_05_02_crt =
+			"MIICljCCAf+gAwIBAgICALgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNS4wMjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAouNcO1wHvKHPR15L7Fohr/QbTkPWGr9QYp2MXEDy" +
+			"BRGHt63Ob+yNvsP/C74GJA+PzvcRELSnJxmBVbdRN5y/u4S6Zt4yTTcrvp4vl//luoGLOX" +
+			"NHhCXbrGavyoP/iKpbfP7fy948AN34i95HuZENoGPjG5stX0uk12P087S2tPcCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECFi86MGPmMsXMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAFVZVMZEsaVuL0qX5Ls94+x8gBklxPfxgfG5LeBR2/YcqW+7BhsVA1" +
+			"GQhjBtwqCU9SOL16oTrqgw2+YeWBjaYuNYVlxfdifd0pQydpE1iDQWxmoKLzSDmtWgRYhz" +
+			"v0TB6j8q+0x5Q0OOrHX0jdIiBnHrLmReCK8dY1x6fb6I0tTH";
+		public const string Intermediate_CRL_RL_05_02_crl =
+			"MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wNS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjA4MDYCAg" +
+			"C5Fw05OTAxMDExMjAwMDBaMCEwCgYDVR0VBAMKAQEwEwYJYIZIAWUCAQwCAQH/BAMCAQCg" +
+			"IzAhMAoGA1UdFAQDAgEBMBMGA1UdIwQMMAqACFi86MGPmMsXMA0GCSqGSIb3DQEBBQUAA4" +
+			"GBAFMN6PWjz2bA1RRySYNXde2rKiYkZYghbtT4ig2yDJBKOiPnjdx+jriFJxGYpt7BvcNx" +
+			"cDfijmDZ1clzprIvz0lFO6IwsQiWtLxOz4Doj6K2AD+7IxuGLceaXmubvi4e6VVC3xXGsu" +
+			"OYsNgFzsdUXIazi74+eOcj4dqrHAepbhXT";
+		public const string End_Certificate_RL_05_02_crt =
+			"MIIChzCCAfCgAwIBAgICALkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDUuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA1LjAyMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuWE1aFx3Zjk6gM0Wy6ijcUegbiGvhjBgqIGwv" +
+			"YissT0v3KGAKoh5wGeKC+rePQNbZ91j4XDLvUNUdNw8HVNdNG/igIwsuaJ9teKSbqrAw9X" +
+			"aD2YjJz/I6X6WXFd/eQ+g9lY3eidOXJkglYSwWMxUV62RUZbGyqjR1so+XpmYxCQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECLLbuNyVkkK9MBMGA1UdIwQMMAqACFi86MGPmMsXMA0GCSqGSIb3DQEBBQUAA4GBACKt" +
+			"GgxIRXYHZGZgwYHjNzquM1pUJTbxxm3qYA4U6r44oAo1UzQTDpHOalflreGFvG05l1BCnQ" +
+			"olQ8rcXU25v/CDfyww7cl8l7IxjYz7PNht7R97vjfMVqqButbn+BmU6D5kR9YXDCDPzaQ5" +
+			"DrKNk+3tIjJNj6YhxhqC2tPG9RIN";
+		public readonly string[] TEST_69_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_05_02_crt,
+			Intermediate_CRL_RL_05_02_crl,
+			End_Certificate_RL_05_02_crt
+		};
+
+		/*
+		 *  test70
+		 *
+		 */
+		public const string Intermediate_Certificate_1_RL_06_01_crt =
+			"MIICljCCAf+gAwIBAgICALowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNi4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmhxr4ckU5C3E57odZjgcxl46ZF2QVy+K86YoLOGT" +
+			"mq34NSHTFxP93mrNqMYdFKFedUTNI68HkecFVvVKoXsDNBnhyyCTQ3xXhBcMUXFByB+55k" +
+			"W5LeQ8l1G2ugsyZ7Z+P8uylrpeGJt4RjOTilhcI2mnfZ7S+arFGe4KYgnsaFUCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECOS4X3XqhyJYMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBALCPtNwXGxVSUNGErkBHSYCHyqlA55jKQQvZ4P0PznWEQ/gBJx34hq" +
+			"LxiBO2G+iDomzHszeM77TXkQBpNxCUw26Jxv2HuvyBXuSprgjw5F1tvLqwsBAnD5vsb0uD" +
+			"NrkKIzJSIBFQ1SRhuCObaXnamfPJHBmkP25t4QqEvoXMtVHB";
+		public const string Intermediate_Certificate_2_RL_06_01_crt =
+			"MIICljCCAf+gAwIBAgICALswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDYuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1STC4wNi4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2IKrW6HDZJVFw3e4cC7v/jPGXAexI4B88707NhAc" +
+			"qxSVfGTPJBdfWo5pkptZKN5/L5n6+rixLItHnei/uwBCHvhwzeEIGo1yVCgz6R2MoNB966" +
+			"Q5CHWfT43BUjp0rZLJkK4hVKNyXB78NVv2Fly+XWBDEnzQvgVPWbGOvzE3zh0CAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECK/1z9Xbu2jGMBMGA1UdIwQMMAqACOS4X3XqhyJYMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAAa/MVC+8ozm9py40a4o/kHbkkmFNQr4s9yi3KXXuVxsNvquFMXm4a" +
+			"gC8GPoNjvV+RPRmU8wOM6I2/PPl2JEQRb7NDM8LkY/m/Au4GHVeln6FKlldiRm0A+YIr19" +
+			"ip2RHOldikAjUUYv7JT3SP34sjtq2e8bsXfWEPG5BA/wxtm7";
+		public const string Intermediate_CRL_1_RL_06_01_crl =
+			"MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" +
+			"C7Fw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgODA2MAoGA1UdFAQDAgEBMBMGCWCG" +
+			"SAFlAgEMAgEB/wQDAgEAMBMGA1UdIwQMMAqACOS4X3XqhyJYMA0GCSqGSIb3DQEBBQUAA4" +
+			"GBAJSexboWDaqLVY6iiWt8ZX5GwuNwDBN1R2TgM95H7JqjMgoWML887dKk24p4eKACFMWI" +
+			"Ji9nwsqdZ/h1FtPhYpSoJ8l8vo4imMKr+tTnMngDNpMMZPQyRY1AK1jSrLhEtUdjiEtrTY" +
+			"rG56RNt4YyUtNxxfkEymvwJxmO/4YcAz/l";
+		public const string Intermediate_CRL_2_RL_06_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMi1STC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIr/XP1du7aMYwDQYJKoZIhvcNAQEFBQADgYEAImRg" +
+			"n9A7px9exOJL4Se9jsSHzZ3sAd3y16LdAb+HLtYLl1swNB4KPE+OebtzEoYiSzVVwezdlm" +
+			"5WseZjfbd0q01srZI4FeACZe99iBSpKymdKxw2gRvfYZ8ZMwFpK2mQq9cmygFn53iOwP7j" +
+			"3KE+lllielu7sYyEnkliF9wsaG0=";
+		public const string End_Certificate_RL_06_01_crt =
+			"MIIChzCCAfCgAwIBAgICALwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTItUkwuMDYuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA2LjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZVBNzD7LZW6mC2GSbVPjpcJ7sWISYsL2eHqXb" +
+			"/PuxtbOneOjYqx0GeL9pxDGSSNl2NrlG0G1HTU2MaEOVA6h96W9e5ADV/pzGPMr97z+3BV" +
+			"unxLX+ciM3T7rUQm/LueQTEC2Ww19T6QOg2i8rEadYT0OoW6OcvyuomemspxgClQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECK5pHDrhL7xjMBMGA1UdIwQMMAqACK/1z9Xbu2jGMA0GCSqGSIb3DQEBBQUAA4GBAF3J" +
+			"Kskjs4jp+BBoei9YWYtmOupn9w3oGyhknNh2jz7api5Gtgk2SyKfYFvN6EhWZJEab0hPFe" +
+			"WuYwO7zNCLGHw0cFXT/R48ogd6JkH6xDwj4afZDkWVTu8oaVD4h1rTYS6WPRzizAozOzhi" +
+			"tmIo+MV/lCG8+jdVtFgeKycI8aX7";
+		public readonly string[] TEST_70_DATA = new string[]
+		{
+			Intermediate_Certificate_1_RL_06_01_crt,
+			Intermediate_Certificate_2_RL_06_01_crt,
+			Intermediate_CRL_1_RL_06_01_crl,
+			Intermediate_CRL_2_RL_06_01_crl,
+			End_Certificate_RL_06_01_crt
+		};
+
+		/*
+		 *  test71
+		 *
+		 */
+		public const string Intermediate_Certificate_RL_06_02_crt =
+			"MIICljCCAf+gAwIBAgICAL0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNi4wMjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxMlJ0vbkMRGzuEDTDGuPmwDzU1xn3dFDZ1Tx6ONP" +
+			"fwNN5gk6r9kYl5TZ8f5TbkQSnOzyhDSqX8dGumCSgukETXtYBU2+KiIAtliu5NJRbXe3La" +
+			"vn102HxaHDLGsR0FFLiFM9GVhOOXryJoXoGZqUwvqbWyaQQEzrV4RWmuOv7xMCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECFNaMo88Vb5MMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAJsjJG4/U1OWCJPB1u7UD3TPKRgOR9hT5l3LzFw5s0CEGt2Beg25LP" +
+			"GEGcr0sEdosVQI5m5CuPolpmlQv0FkZv5M1W+uXX+F/6edtMDEquDpdR97ihQSLZjFFqjE" +
+			"ytuaD4gqtL/BKBbz3e93mOmR9Wi+kWlXOYl0j8wpU9ePSjDV";
+		public const string Intermediate_CRL_RL_06_02_crl =
+			"MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" +
+			"C+Fw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgODA2MAoGA1UdFAQDAgEBMBMGCWCG" +
+			"SAFlAgEMAgEB/wQDAgEAMBMGA1UdIwQMMAqACFNaMo88Vb5MMA0GCSqGSIb3DQEBBQUAA4" +
+			"GBAAKNj5xmtE7wzO1p5igiAmCDV6KuYsiPAQPHPEBlmo85vzvWv2hpEtmk4nDhehogl0QX" +
+			"rhvRRqR+cPE5vBLB8mAStW+ZR6FXQPnmU5qGHqCQ4Wh6TWZesd7oyftoS7bJD5Xdf5ErA9" +
+			"qijWoz8FgxZHVnAFmjA0rUINkdQ5JfE5oj";
+		public const string End_Certificate_RL_06_02_crt =
+			"MIIChzCCAfCgAwIBAgICAL4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDYuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA2LjAyMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3UzwrnwKRlP00Pn49iI35S0wLn7c1I3rsmzdm" +
+			"YFicetxHNeOKXLg1CN1bqkbAJ+N39fKjrkusqb2T+R3zhAV5LeLT4fzbHYdU7f4r6xgW2/" +
+			"b2WLv+QVR+ldTsVxgPp/ZUgYi4/vAow4Q/6IT+zWtlawMBob/nLjVl+jQ9N4coFwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECPhq75noL+9WMBMGA1UdIwQMMAqACFNaMo88Vb5MMA0GCSqGSIb3DQEBBQUAA4GBAIU2" +
+			"5bLX/NyDC8dKUxRwVn8oc3YPQjK0zXGdUr15Ib+cLdRyFVCuAyxVdpTf/csuga6tDhGuTL" +
+			"B18mTE/fAjhUOiKiOLD6m4P77Nj67l2NTi86RimsI/Z6r5+bU31ahrls/7kr788+f4oEIY" +
+			"TyOJecojsJUOG3qzK9J50iszclxg";
+		public readonly string[] TEST_71_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_06_02_crt,
+			Intermediate_CRL_RL_06_02_crl,
+			End_Certificate_RL_06_02_crt
+		};
+
+		/*
+		 *  test72
+		 *
+		 */
+		public const string Intermediate_Certificate_RL_07_01_crt =
+			"MIICljCCAf+gAwIBAgICAL8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNy4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxjHxSRwJjEkLG9Al5uSQ22QI8N/hJ8hhkhh9qlaJ" +
+			"mHusM8sWpAp2vnuumlThTA2zZbptXZ8Krb7i/Kpym4wo3ZkEThwi/ijsM5QCunQJmESRGD" +
+			"yPZJjfhWjoC+lCjbmzsOGLMETpgSEMy+EyoXkRCnKmXcmCMS8HjLrqdnwiWBUCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECHPEkeIs8GuwMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBABCmgEnb8dfnG9lWQKT5BmQm459WqRQAiqdfqf9w0qRMuVrdfLMwqx" +
+			"oq4uh10A3d+auHohgT2fT9RzNaWnRoNaH9K6qLQsdCUZdqjbEGdyiIFzvWP9MkV9nhDlo2" +
+			"GgiU68HfnpKO/WA9EaRHyEzwT9o4SA7hAbz+3L12hB2WLSOg";
+		public const string Intermediate_CRL_RL_07_01_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wNy4wMRcNOTgwMTAxMDYwMTAwWhcNOTgwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIc8SR4izwa7AwDQYJKoZIhvcNAQEFBQADgYEAOyZr" +
+			"f1tRnuzoq7dgQo+eOYhb5JyRyrNaSwNnRy82wOP+/G3NH8V3NGonDFOOcd9SoLTbeW4o71" +
+			"vdOrKZgom5H2MZK5M4wTdfPAfXB1wBxOMzW5jXzsRtaha4l6EPI+GVL0eXN+aW3k/pscdA" +
+			"ToI+OxTmRRnCYS6yW3qL9RoTIXQ=";
+		public const string End_Certificate_RL_07_01_crt =
+			"MIIChzCCAfCgAwIBAgICAMAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDcuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA3LjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrm/Zem9Tt2UJFUKdAhTNwvhLo03uOax74ZgbV" +
+			"YNTCpKeEWkV5d5d7DRC4mCTX1yjIlg6K4l7T+sRGI4XAcDRgYLuoyG1X958XCXSdIPTdbK" +
+			"Hxs/tFv4mrCwi1kU+zjyzDoqgjT6kUxgM39rfcvDMH6qSzHQKgTFp7Tj/DHiELqwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECGFR8c6rRbhcMBMGA1UdIwQMMAqACHPEkeIs8GuwMA0GCSqGSIb3DQEBBQUAA4GBAANZ" +
+			"TVR288mKpDDzm9XZMZ9+K1kPZ+eQYX+vUul11luVw27AIJGR8Fb4PIGl4+ALvqU3NQP/6v" +
+			"d+zvS7IfiR6q7aLS3w111BUCgDhTJAp3oSo12qfcp+2DB1M9QfjrM9nKgmh5bBJigdJwJM" +
+			"W8HHKStUMLdxg+qkZJgZpnyowCFM";
+		public readonly string[] TEST_72_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_07_01_crt,
+			Intermediate_CRL_RL_07_01_crl,
+			End_Certificate_RL_07_01_crt
+		};
+
+		/*
+		 *  test73
+		 *
+		 */
+		public const string Intermediate_Certificate_RL_07_02_crt =
+			"MIICljCCAf+gAwIBAgICAMEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNNTAwMTAxMDYwMDMwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNy4wMjCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0CvEneaAPtxZOTqlh/TXBM6V0bQgKbO58yEyURcO" +
+			"Zi7jzYsmNtN9Tsr0wAlD41/ZONsW4MMzZ13UCc0aGa+eE8XRULBe5cgaGxJKwVnEqz3W8z" +
+			"v1MjOk7Anb8TkxMSlWlptC6V3eRA85p5Id9gXbIrP3E3NuSfyx6246oLjNnbECAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECIb5Ia6wKcHtMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAAYEHQY+Z4qv4bYLmd+sz4aNGwZF7FT6ZIQ43OSeb+t+ibL7rZ0X0y" +
+			"4SCTMs1mAB44IA6RFurmeCFk0ladRCn3A1xaVI1HlHen13ovzDA9ogL4CWbYXvCUv/znQY" +
+			"yVSQCTKwT8iVam8xS1MsNCe408iVjhRfR6u9Hi31M+Pf+AUe";
+		public const string Intermediate_CRL_RL_07_02_crl =
+			"MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wNy4wMhcNNTAwMTAxMDYwMTAwWhcNNTAwMTAxMTIwMTAwWqAjMCEwCg" +
+			"YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhvkhrrApwe0wDQYJKoZIhvcNAQEFBQADgYEALVUq" +
+			"3Wq/Opvp9ifmQ4VXz4dgLNR+5Nz3muJ4RZt5R5b4R3RYllhgXNYw2EbEVCFjnfm97z73Ke" +
+			"wzVV+fo/u5GbqJHN2cAVEHarOpasLxySktNA1Cwq5OTzUF0dYISqYbyBvVcaOQBvU/Lwj7" +
+			"MQJJVVq96iDKnAJYBX03EHKbBeg=";
+		public const string End_Certificate_RL_07_02_crt =
+			"MIIChzCCAfCgAwIBAgICAMIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDcuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA3LjAyMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD6YgsbjW9IL7/SBORKssFUZBUxmluOpxJK/7d7" +
+			"JA2pxbg7L96xHFPWN36CYDJzTscNpbGrD3G2MPkg4GqoTo0rU28NYVzj4SwqYoSLIbXB+r" +
+			"SVgWcxNgbJ+4x9bK3YccNLR1PWEFxz1NckhCLBmb5pI4E34MCxQ6PvFO02I19FwQIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECIutV9ItCIbZMBMGA1UdIwQMMAqACIb5Ia6wKcHtMA0GCSqGSIb3DQEBBQUAA4GBALQE" +
+			"cBr31h3jKUHcuf3yztr9NWUkGMDM0NCXHOpQl7JbV3P5BjvaiRYWlUrN7+92G8EaUFORto" +
+			"zp8GG+d/MvFooVQOvpOzyhautYWyqq3AWpZLppnxNk1mRAdjUAvJaONtv37eLsma0bhtLM" +
+			"j62sQQ6CdoKbMtIEGuJgpwWqHYwY";
+		public readonly string[] TEST_73_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_07_02_crt,
+			Intermediate_CRL_RL_07_02_crl,
+			End_Certificate_RL_07_02_crt
+		};
+
+		/*
+		 *  test74
+		 *
+		 */
+		public const string Intermediate_Certificate_RL_07_03_crt =
+			"MIICljCCAf+gAwIBAgICAMMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNy4wMzCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA8QzGjV0NVTNrOgkeqTkQFCOvl7M0qmjmYJjuw4R3" +
+			"YfQIXDN0m9HR2JKp5WKTSUedmWviGS7NbGSzLR7+6OkLwSoxN9PkA/fMko7O0KWBfduhvn" +
+			"jymlDMb2GPb1hBjScbq8fVJHwzqUm+BtEO2MXwXKYY2hZr+OEyEGhSEThp90MCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECFwl2XphEZRSMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAAb5GERgYVGuOb62gVZAAnhuk5K7CCkWZucOv6iI7pAgI6S7pvool/" +
+			"dXHC0tzgQ+/MkuWcr+22k/ya7f+iSfiYokjnQkgoYFYk3PkjyOXA3mzs5qhF0nOP6Gvmz4" +
+			"asONA+qZSqa4pjxF9Kn8L64f9yeyEXnckmbzdmbjAFCveQIP";
+		public const string Intermediate_CRL_RL_07_03_crl =
+			"MIIBTTCBtwIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wNy4wMxcNOTkwMTAxMDYwMTAwWhgPMjA1MDAxMDExMjAxMDBaoCMwIT" +
+			"AKBgNVHRQEAwIBATATBgNVHSMEDDAKgAhcJdl6YRGUUjANBgkqhkiG9w0BAQUFAAOBgQAz" +
+			"DMl8P16hylNkUEw4z9//PJFObNPZCYdmzBfp0K3tNRrOAouUVegyX0gDHi8O+bmmJNgcnC" +
+			"tMRXx+D4qP7bx5fDS2MVQhSsncf6u4UZ8pxbRc0JmwR5oGZLPQabrctgmEmg8ZKGApKtsf" +
+			"pGyvvTwaAzM+GaWXD68bBEN3VfVdeQ==";
+		public const string End_Certificate_RL_07_03_crt =
+			"MIIChzCCAfCgAwIBAgICAMQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDcuMDMwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA3LjAzMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDU6mec24uBaVip7fFWHas+o/lpZBOfj/IPHXQ9" +
+			"QaRZwmJZBB81AX3BJ60DD12o/+RXdHl7B2Eh9kYv/QEXOKmyhJFSPa0Lv7MQ/hCIcL4m1U" +
+			"FDGtJ3SUixZMqVBP0xjwXoNS88zzaCBL+co2TxhBrYMzeNQOX1eEkXMT4pvULmAwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECBBgFdYLuvk9MBMGA1UdIwQMMAqACFwl2XphEZRSMA0GCSqGSIb3DQEBBQUAA4GBAAof" +
+			"dPOGa4ZxRPcLw6zWM/NLzF3XYDqXAsZBsC75r0GRrogqEYn07tVUDNaQczDtjRLBRNmxWE" +
+			"+qCkJwc+wOBJqOFUxcuhK9oag6OE94+UIHdh3Td9i2ELZXj9RSNchnjyFohj5gk1dJSO41" +
+			"86Ls3mCT9JcssR0dSxxkF0ENfZCG";
+		public readonly string[] TEST_74_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_07_03_crt,
+			Intermediate_CRL_RL_07_03_crl,
+			End_Certificate_RL_07_03_crt
+		};
+
+		/*
+		 *  test75
+		 *
+		 */
+		public const string Intermediate_Certificate_RL_08_01_crt =
+			"MIICljCCAf+gAwIBAgICAMUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wOC4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAs2YRTEl3C1TmmneJ6K110nSACn+KXxSOTGAGN5xv" +
+			"XW751StpE2iEQIbRVPQdMzmcQX0bcg/WpdrewPQld9NRjFj7it+9YNQh7vMKhZwoAPoDmv" +
+			"TnTdTEuV0c1FLVDVhiaAD9KMBa4fBLRfTKVzgzAr+oNqLhm3YBd2JWRHg+fA8CAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECB4we8+hIrkKMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBABTQI82uCMwQ4bgUWr9lawSI5DyWg3KY13F45rAlmKyckgne9SHbCH" +
+			"+Lvm3XkkIqKmeHfJ3QTf7bpz6eErn3CxRrGm5JWblcYbVT+smjboJ9A0BXifqINYLy3qGc" +
+			"AnNRkPq8OUREj2sU1qWKagUIgA/Vk2WyZhcUiApJPHI4fwv9";
+		public const string Intermediate_CRL_RL_08_01_crl =
+			"MIIBWjCBxAIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wOC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAyMDAwCg" +
+			"YDVR0UBAMCAQEwDQYDVR0bAQH/BAMCAQEwEwYDVR0jBAwwCoAIHjB7z6EiuQowDQYJKoZI" +
+			"hvcNAQEFBQADgYEAkjF0oERt5XW2i70gyspkEYIHyGCHnqngky5yuwQSRrlW7t0vGdKV7W" +
+			"50evTeSVV41uhi1MBcccpx1MdRcB5vsatFSSKcKx4NF3PuHXxXCm2HkfXQy4K5zftE3jOZ" +
+			"5s+yTHiw3s/QSErtHRca+TQcEZwamI+p402TEa6e82l6xHI=";
+		public const string End_Certificate_RL_08_01_crt =
+			"MIIChzCCAfCgAwIBAgICAMYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDguMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA4LjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfEMqWMqk3Rre5m4ILtQIz45JImvU379Al/S6t" +
+			"2y/TzimJc4nhIKQp80VaZA/gwu/DcvMgJPM+FFz5U5rRkDaYASsc34tZUESF5LC6ZbtGqf" +
+			"J96IKdajvkGLsHyI7dseuwaQ0FlOwcmKMSR898MGNNbKxaQNLEXsIFypRDsN6JhwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECMT22ARjB1ABMBMGA1UdIwQMMAqACB4we8+hIrkKMA0GCSqGSIb3DQEBBQUAA4GBAIaP" +
+			"EqI7oHl/+h3MszG4VB1Va9NTN0kaysTyjQSVBi9jhOlPkzuXc2wI1bymBhatHEn6OrgP13" +
+			"vsOiH2BiyudYcYjKpwI4FUiyKLIc0CXzM0VYFoMzb91QtsK1EnvAPDKNYVVFXrL7ABVIK4" +
+			"hU6HfMMUbnpKWBxT5274iHScX8tL";
+		public readonly string[] TEST_75_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_08_01_crt,
+			Intermediate_CRL_RL_08_01_crl,
+			End_Certificate_RL_08_01_crt
+		};
+
+		/*
+		 *  test76
+		 *
+		 */
+		public const string Intermediate_Certificate_RL_09_01_crt =
+			"MIICljCCAf+gAwIBAgICAMcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wOS4wMTCBnzANBg" +
+			"kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsvkvLv5fMFYvohaXO8a7GgU4rDHe9iL7LP1VeNUg" +
+			"GIdJGqPEnuggQ/guhrBHafGh1NtmlEbmPJ4WQ99dBbPHHeO8sfCgkmWC0SqPODoI+t3qJE" +
+			"kf2z9dWoAij15RXPliywZz+S6bTtcEQAREyBQ6M8/HJ83wRXp/uCpdPOSxVPkCAwEAAaNj" +
+			"MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" +
+			"gBZQMBMAEwEQYDVR0OBAoECISY4bvGMEBTMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" +
+			"SIb3DQEBBQUAA4GBAAd7g+dWso4V/Vr+QIoNLueCBAYWdOF+Yz3VeomcsDAs2V8E+xcZaq" +
+			"jo2LrMygYCeMxVfXx/ZdhLPOaZ+ahNAbk+nWRwj35JdTNAAbMMWFdZUgR6N+uzx1v7i86p" +
+			"AWUpRJ9IYPgUoQ5pmjdf3Ru1nrLfRt4yp+kNHWp6IL/+MwcM";
+		public const string Intermediate_CRL_RL_09_01_crl =
+			"MIIBXDCBxgIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" +
+			"5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" +
+			"BAMTDENBMS1STC4wOS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqA0MDIwCg" +
+			"YDVR0UBAMCAQEwDwYDVR0cAQH/BAUwA4IB/zATBgNVHSMEDDAKgAiEmOG7xjBAUzANBgkq" +
+			"hkiG9w0BAQUFAAOBgQAKTXYgqlP+upFIwOSpdaVKDT8aqFzY9nSIsxHg5Wdl43U7p44LvQ" +
+			"lW8XKhw74oQl1ExU5s7mDaEqB0JIozGzmoNyKsErgWKNW+lpKSxR5+1EHOB6Oo2KijpTsv" +
+			"GFrHFCnF09f9JaTaMRIXOljx3rMO1UZsftKy/L9z3aUz8hQRnQ==";
+		public const string End_Certificate_RL_09_01_crt =
+			"MIIChzCCAfCgAwIBAgICAMgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" +
+			"NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" +
+			"MRUwEwYDVQQDEwxDQTEtUkwuMDkuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" +
+			"AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" +
+			"EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA5LjAxMIGfMA" +
+			"0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpz09VCXzAhH4/ifMk0RAzaBqJCXaHHqAdO/TW" +
+			"6uvOVtl+fGvWXhXmSSCUfzg5xBqdUXrqcyxOME3vdgF1uOFZ4q2K6+Zuxmm+GCOCIpe+Gl" +
+			"Jzqz4WKXG0iaXXQOYa56itNc/6Z6D/aAjNJavI19w0lmb9l6U2WBfn3LywxHp4dwIDAQAB" +
+			"o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" +
+			"oECOri1JgnJfLjMBMGA1UdIwQMMAqACISY4bvGMEBTMA0GCSqGSIb3DQEBBQUAA4GBADmV" +
+			"Ee0xy25Z0HtmWwprKPjJDr/p7TgzbmNC58pUPkgtxnJFP4yrzNB9FQBWSfnjZpzQkLSU7i" +
+			"7O6cf5HkqjQqoPErDnJLWgGzjbF80v2IIyZk7rEpAAM4MwjIk7hFvJK8QkTht9F4N1zj2X" +
+			"0TQkmlbo9Z4SFj/3fsbl9h2GdKuU";
+
+		public readonly string[] TEST_76_DATA = new string[]
+		{
+			Intermediate_Certificate_RL_09_01_crt,
+			Intermediate_CRL_RL_09_01_crl,
+			End_Certificate_RL_09_01_crt
+		};
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new NistCertPathTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/NoekeonTest.cs b/crypto/test/src/test/NoekeonTest.cs
new file mode 100644
index 000000000..c3745da1c
--- /dev/null
+++ b/crypto/test/src/test/NoekeonTest.cs
@@ -0,0 +1,157 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Tests
+{
+	/**
+	* basic test class for SEED
+	*/
+	[TestFixture]
+	public class NoekeonTest
+		: BaseBlockCipherTest
+	{
+		private static readonly string[] cipherTests =
+		{
+			"128",
+			"b1656851699e29fa24b70148503d2dfc",
+			"2a78421b87c7d0924f26113f1d1349b2",
+			"e2f687e07b75660ffc372233bc47532c"
+		};
+
+		public NoekeonTest()
+			: base("Noekeon")
+		{
+		}
+
+		public void DoTest(
+			int		strength,
+			byte[]	keyBytes,
+			byte[]	input,
+			byte[]	output)
+		{
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("Noekeon", keyBytes);
+
+			IBufferedCipher inCipher = CipherUtilities.GetCipher("Noekeon/ECB/NoPadding");
+			IBufferedCipher outCipher = CipherUtilities.GetCipher("Noekeon/ECB/NoPadding");
+
+			try
+			{
+				outCipher.Init(true, key);
+			}
+			catch (Exception e)
+			{
+				Fail("Noekeon failed initialisation - " + e.Message, e);
+			}
+
+			try
+			{
+				inCipher.Init(false, key);
+			}
+			catch (Exception e)
+			{
+				Fail("Noekeoen failed initialisation - " + e.Message, e);
+			}
+
+			//
+			// encryption pass
+			//
+			MemoryStream bOut = new MemoryStream();
+
+			CipherStream cOut = new CipherStream(bOut, null, outCipher);
+
+			try
+			{
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+					cOut.WriteByte(input[i]);
+				}
+				cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+				cOut.Close();
+			}
+			catch (IOException e)
+			{
+				Fail("Noekeon failed encryption - " + e.Message, e);
+			}
+
+			byte[] bytes = bOut.ToArray();
+
+			if (!AreEqual(bytes, output))
+			{
+				Fail("Noekeon failed encryption - expected "
+					+ Hex.ToHexString(output) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+
+			//
+			// decryption pass
+			//
+			MemoryStream bIn = new MemoryStream(bytes, false);
+
+			CipherStream cIn = new CipherStream(bIn, inCipher, null);
+
+			try
+			{
+//				DataInputStream dIn = new DataInputStream(cIn);
+				BinaryReader dIn = new BinaryReader(cIn);
+
+				bytes = new byte[input.Length];
+
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+//					bytes[i] = (byte)dIn.read();
+					bytes[i] = dIn.ReadByte();
+				}
+				int remaining = bytes.Length - input.Length / 2;
+//				dIn.readFully(bytes, input.Length / 2, remaining);
+				byte[] extra = dIn.ReadBytes(remaining);
+				if (extra.Length < remaining)
+					throw new EndOfStreamException();
+				extra.CopyTo(bytes, input.Length / 2);
+			}
+			catch (Exception e)
+			{
+				Fail("Noekeon failed encryption - " + e.Message, e);
+			}
+
+			if (!AreEqual(bytes, input))
+			{
+				Fail("Noekeon failed decryption - expected "
+					+ Hex.ToHexString(input) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+		}
+
+		public override void PerformTest()
+		{
+			for (int i = 0; i != cipherTests.Length; i += 4)
+			{
+				DoTest(int.Parse(cipherTests[i]),
+					Hex.Decode(cipherTests[i + 1]),
+					Hex.Decode(cipherTests[i + 2]),
+					Hex.Decode(cipherTests[i + 3]));
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new NoekeonTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/PBETest.cs b/crypto/test/src/test/PBETest.cs
new file mode 100644
index 000000000..ee61a027c
--- /dev/null
+++ b/crypto/test/src/test/PBETest.cs
@@ -0,0 +1,527 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/**
+	* test out the various PBE modes, making sure the JCE implementations
+	* are compatible woth the light weight ones.
+	*/
+	[TestFixture]
+	public class PbeTest
+		: SimpleTest
+	{
+		private class OpenSslTest
+			: SimpleTest
+		{
+			private char[] password;
+			private string baseAlgorithm;
+			private string algorithm;
+			private int keySize;
+			private int ivSize;
+
+			public OpenSslTest(
+				string	baseAlgorithm,
+				string	algorithm,
+				int		keySize,
+				int		ivSize)
+			{
+				this.password = algorithm.ToCharArray();
+				this.baseAlgorithm = baseAlgorithm;
+				this.algorithm = algorithm;
+				this.keySize = keySize;
+				this.ivSize = ivSize;
+			}
+
+			public override string Name
+			{
+				get { return "OpenSSLPBE"; }
+			}
+
+			public override void PerformTest()
+			{
+				byte[] salt = new byte[16];
+				int iCount = 100;
+
+				for (int i = 0; i != salt.Length; i++)
+				{
+					salt[i] = (byte)i;
+				}
+
+				PbeParametersGenerator pGen = new OpenSslPbeParametersGenerator();
+
+				pGen.Init(
+					PbeParametersGenerator.Pkcs5PasswordToBytes(password),
+					salt,
+					iCount);
+
+				ParametersWithIV parameters = (ParametersWithIV)
+					pGen.GenerateDerivedParameters(baseAlgorithm, keySize, ivSize);
+
+				KeyParameter encKey = (KeyParameter) parameters.Parameters;
+
+				IBufferedCipher c;
+				if (baseAlgorithm.Equals("RC4"))
+				{
+					c = CipherUtilities.GetCipher(baseAlgorithm);
+
+					c.Init(true, encKey);
+				}
+				else
+				{
+					c = CipherUtilities.GetCipher(baseAlgorithm + "/CBC/PKCS7Padding");
+
+					c.Init(true, parameters);
+				}
+
+				byte[] enc = c.DoFinal(salt);
+
+				c = CipherUtilities.GetCipher(algorithm);
+
+//					PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount);
+//					SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm);
+//
+//					c.Init(false, fact.generateSecret(keySpec));
+
+				Asn1Encodable algParams = PbeUtilities.GenerateAlgorithmParameters(
+					algorithm, salt, iCount);
+				ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+					algorithm, password, algParams);
+				c.Init(false, cipherParams);
+
+				byte[] dec = c.DoFinal(enc);
+
+				if (!AreEqual(salt, dec))
+				{
+					Fail("" + algorithm + "failed encryption/decryption test");
+				}
+			}
+		}
+
+		private class Pkcs12Test
+			: SimpleTest
+		{
+			private char[] password;
+			private string baseAlgorithm;
+			private string algorithm;
+			private IDigest digest;
+			private int keySize;
+			private int ivSize;
+
+			public Pkcs12Test(
+				string		baseAlgorithm,
+				string		algorithm,
+				IDigest		digest,
+				int			keySize,
+				int			ivSize)
+			{
+				this.password = algorithm.ToCharArray();
+				this.baseAlgorithm = baseAlgorithm;
+				this.algorithm = algorithm;
+				this.digest = digest;
+				this.keySize = keySize;
+				this.ivSize = ivSize;
+			}
+
+			public override string Name
+			{
+				get { return "PKCS12PBE"; }
+			}
+
+			public override void PerformTest()
+			{
+				int iCount = 100;
+				byte[] salt = DigestUtilities.DoFinal(digest);
+
+				PbeParametersGenerator pGen = new Pkcs12ParametersGenerator(digest);
+
+				pGen.Init(
+					PbeParametersGenerator.Pkcs12PasswordToBytes(password),
+					salt,
+					iCount);
+
+				ParametersWithIV parameters = (ParametersWithIV)
+					pGen.GenerateDerivedParameters(baseAlgorithm, keySize, ivSize);
+
+				KeyParameter encKey = (KeyParameter) parameters.Parameters;
+
+				IBufferedCipher c;
+				if (baseAlgorithm.Equals("RC4"))
+				{
+					c = CipherUtilities.GetCipher(baseAlgorithm);
+	                
+					c.Init(true, encKey);
+				}
+				else
+				{
+					c = CipherUtilities.GetCipher(baseAlgorithm + "/CBC/PKCS7Padding");
+	                
+					c.Init(true, parameters);
+				}
+
+				byte[] enc = c.DoFinal(salt);
+
+				c = CipherUtilities.GetCipher(algorithm);
+
+//					PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount);
+//					SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm);
+//
+//					c.Init(false, fact.generateSecret(keySpec));
+
+				Asn1Encodable algParams = PbeUtilities.GenerateAlgorithmParameters(
+					algorithm, salt, iCount);
+				ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+					algorithm, password, algParams);
+				c.Init(false, cipherParams);
+
+				byte[] dec = c.DoFinal(enc);
+
+				if (!AreEqual(salt, dec))
+				{
+					Fail("" + algorithm + "failed encryption/decryption test");
+				}
+
+				// NB: We don't support retrieving parameters from cipher
+//				//
+//				// get the parameters
+//				//
+//				AlgorithmParameters param = c.getParameters();
+//				PBEParameterSpec spec = (PBEParameterSpec)param.getParameterSpec(PBEParameterSpec.class);
+//
+//				if (!AreEqual(salt, spec.getSalt()))
+//				{
+//					Fail("" + algorithm + "failed salt test");
+//				}
+//	            
+//				if (iCount != spec.getIterationCount())
+//				{
+//					Fail("" + algorithm + "failed count test");
+//				}
+
+	            // NB: This section just repeats earlier test passing 'param' separately
+//				//
+//				// try using parameters
+//				//
+//				keySpec = new PBEKeySpec(password);
+//	            
+//				c.Init(false, fact.generateSecret(keySpec), param);
+//	            
+//				dec = c.DoFinal(enc);
+//	            
+//				if (!AreEqual(salt, dec))
+//				{
+//					Fail("" + algorithm + "failed encryption/decryption test");
+//				}
+			}
+		}
+
+		private Pkcs12Test[] pkcs12Tests = {
+			new Pkcs12Test("DESede", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC",  new Sha1Digest(),   192,  64),
+			new Pkcs12Test("DESede", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC",  new Sha1Digest(),   128,  64),
+			new Pkcs12Test("RC4",    "PBEWITHSHAAND128BITRC4",           new Sha1Digest(),   128,   0),
+			new Pkcs12Test("RC4",    "PBEWITHSHAAND40BITRC4",            new Sha1Digest(),    40,   0),
+			new Pkcs12Test("RC2",    "PBEWITHSHAAND128BITRC2-CBC",       new Sha1Digest(),   128,  64),
+			new Pkcs12Test("RC2",    "PBEWITHSHAAND40BITRC2-CBC",        new Sha1Digest(),    40,  64),
+			new Pkcs12Test("AES",    "PBEWithSHA1And128BitAES-CBC-BC",   new Sha1Digest(),   128, 128),
+			new Pkcs12Test("AES",    "PBEWithSHA1And192BitAES-CBC-BC",   new Sha1Digest(),   192, 128),
+			new Pkcs12Test("AES",    "PBEWithSHA1And256BitAES-CBC-BC",   new Sha1Digest(),   256, 128),
+			new Pkcs12Test("AES",    "PBEWithSHA256And128BitAES-CBC-BC", new Sha256Digest(), 128, 128),
+			new Pkcs12Test("AES",    "PBEWithSHA256And192BitAES-CBC-BC", new Sha256Digest(), 192, 128),   
+			new Pkcs12Test("AES",    "PBEWithSHA256And256BitAES-CBC-BC", new Sha256Digest(), 256, 128)
+		};
+
+		private OpenSslTest[] openSSLTests = {
+			new OpenSslTest("AES", "PBEWITHMD5AND128BITAES-CBC-OPENSSL", 128, 128),
+			new OpenSslTest("AES", "PBEWITHMD5AND192BITAES-CBC-OPENSSL", 192, 128),
+			new OpenSslTest("AES", "PBEWITHMD5AND256BITAES-CBC-OPENSSL", 256, 128)
+		};
+
+		static byte[] message = Hex.Decode("4869205468657265");
+
+		private byte[] hMac1 = Hex.Decode("bcc42174ccb04f425d9a5c8c4a95d6fd7c372911");
+		private byte[] hMac2 = Hex.Decode("cb1d8bdb6aca9e3fa8980d6eb41ab28a7eb2cfd6");
+
+		// NB: These two makePbeCipher... methods are same in .NET
+		private IBufferedCipher makePbeCipherUsingParam(
+			string  algorithm,
+			bool	forEncryption,
+			char[]  password,
+			byte[]  salt,
+			int     iterationCount)
+		{
+//			PBEKeySpec pbeSpec = new PBEKeySpec(password);
+//			SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm);
+//			PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+
+			Asn1Encodable algParams = PbeUtilities.GenerateAlgorithmParameters(
+				algorithm, salt, iterationCount);
+			ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+				algorithm, password, algParams);
+			
+			IBufferedCipher cipher = CipherUtilities.GetCipher(algorithm);
+
+//			cipher.Init(forEncryption, keyFact.generateSecret(pbeSpec), defParams);
+			cipher.Init(forEncryption, cipherParams);
+
+			return cipher;
+		}
+
+		// NB: These two makePbeCipher... methods are same in .NET
+		private IBufferedCipher makePbeCipherWithoutParam(
+			string  algorithm,
+			bool	forEncryption,
+			char[]  password,
+			byte[]  salt,
+			int     iterationCount)
+		{
+//			PBEKeySpec pbeSpec = new PBEKeySpec(password, salt, iterationCount);
+//			SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm);
+
+			Asn1Encodable algParams = PbeUtilities.GenerateAlgorithmParameters(
+				algorithm, salt, iterationCount);
+			ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(
+				algorithm, password, algParams);
+			
+			IBufferedCipher cipher = CipherUtilities.GetCipher(algorithm);
+
+//			cipher.Init(forEncryption, keyFact.generateSecret(pbeSpec));
+			cipher.Init(forEncryption, cipherParams);
+
+			return cipher;
+		}
+
+		private void doTestPbeHMac(
+			string	hmacName,
+			byte[]	output)
+		{
+			ICipherParameters key = null;
+			byte[] outBytes;
+			IMac mac = null;
+
+			try
+			{
+//				SecretKeyFactory fact = SecretKeyFactory.getInstance(hmacName);
+//
+//				key = fact.generateSecret(new PBEKeySpec("hello".ToCharArray()));
+
+				Asn1Encodable algParams = PbeUtilities.GenerateAlgorithmParameters(
+					hmacName, new byte[20], 100);
+				key = PbeUtilities.GenerateCipherParameters(
+					hmacName, "hello".ToCharArray(), algParams);
+				mac = MacUtilities.GetMac(hmacName);
+			}
+			catch (Exception e)
+			{
+				Fail("Failed - exception " + e.ToString(), e);
+			}
+
+			try
+			{
+//				mac.Init(key, new PBEParameterSpec(new byte[20], 100));
+				mac.Init(key);
+			}
+			catch (Exception e)
+			{
+				Fail("Failed - exception " + e.ToString(), e);
+			}
+
+			mac.Reset();
+
+			mac.BlockUpdate(message, 0, message.Length);
+
+//			outBytes = mac.DoFinal();
+			outBytes = new byte[mac.GetMacSize()];
+			mac.DoFinal(outBytes, 0);
+
+			if (!AreEqual(outBytes, output))
+			{
+				Fail("Failed - expected "
+					+ Hex.ToHexString(output) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+		}
+
+		public override void PerformTest()
+		{
+			byte[] input = Hex.Decode("1234567890abcdefabcdef1234567890fedbca098765");
+
+			//
+			// DES
+			//
+			IBufferedCipher cEnc = CipherUtilities.GetCipher("DES/CBC/PKCS7Padding");
+
+			cEnc.Init(
+				true,
+				new ParametersWithIV(
+					new DesParameters(Hex.Decode("30e69252758e5346")),
+					Hex.Decode("7c1c1ab9c454a688")));
+
+			byte[] outBytes = cEnc.DoFinal(input);
+			char[] password = "password".ToCharArray();
+
+			IBufferedCipher cDec = makePbeCipherUsingParam(
+				"PBEWithSHA1AndDES",
+				false,
+				password,
+				Hex.Decode("7d60435f02e9e0ae"),
+				2048);
+
+			byte[] inBytes = cDec.DoFinal(outBytes);
+
+			if (!AreEqual(input, inBytes))
+			{
+				Fail("DES failed");
+			}
+
+			cDec = makePbeCipherWithoutParam(
+				"PBEWithSHA1AndDES",
+				false,
+				password,
+				Hex.Decode("7d60435f02e9e0ae"),
+				2048);
+
+			inBytes = cDec.DoFinal(outBytes);
+
+			if (!AreEqual(input, inBytes))
+			{
+				Fail("DES failed without param");
+			}
+
+			//
+			// DESede
+			//
+			cEnc = CipherUtilities.GetCipher("DESede/CBC/PKCS7Padding");
+
+			cEnc.Init(
+				true,
+				new ParametersWithIV(
+					new DesParameters(Hex.Decode("732f2d33c801732b7206756cbd44f9c1c103ddd97c7cbe8e")),
+					Hex.Decode("b07bf522c8d608b8")));
+
+			outBytes = cEnc.DoFinal(input);
+
+			cDec = makePbeCipherUsingParam(
+				"PBEWithSHAAnd3-KeyTripleDES-CBC",
+				false,
+				password,
+				Hex.Decode("7d60435f02e9e0ae"),
+				2048);
+
+			inBytes = cDec.DoFinal(outBytes);
+
+			if (!AreEqual(input, inBytes))
+			{
+				Fail("DESede failed");
+			}
+
+			//
+			// 40Bit RC2
+			//
+			cEnc = CipherUtilities.GetCipher("RC2/CBC/PKCS7Padding");
+
+			cEnc.Init(
+				true,
+				new ParametersWithIV(
+					new RC2Parameters(Hex.Decode("732f2d33c8")),
+					Hex.Decode("b07bf522c8d608b8")));
+
+			outBytes = cEnc.DoFinal(input);
+
+			cDec = makePbeCipherUsingParam(
+				"PBEWithSHAAnd40BitRC2-CBC",
+				false,
+				password,
+				Hex.Decode("7d60435f02e9e0ae"),
+				2048);
+
+			inBytes = cDec.DoFinal(outBytes);
+
+			if (!AreEqual(input, inBytes))
+			{
+				Fail("RC2 failed");
+			}
+
+			//
+			// 128bit RC4
+			//
+			cEnc = CipherUtilities.GetCipher("RC4");
+
+			cEnc.Init(
+				true,
+				ParameterUtilities.CreateKeyParameter("RC4", Hex.Decode("732f2d33c801732b7206756cbd44f9c1")));
+
+			outBytes = cEnc.DoFinal(input);
+
+			cDec = makePbeCipherUsingParam(
+				"PBEWithSHAAnd128BitRC4",
+				false,
+				password,
+				Hex.Decode("7d60435f02e9e0ae"),
+				2048);
+
+			inBytes = cDec.DoFinal(outBytes);
+
+			if (!AreEqual(input, inBytes))
+			{
+				Fail("RC4 failed");
+			}
+
+			cDec = makePbeCipherWithoutParam(
+				"PBEWithSHAAnd128BitRC4",
+				false,
+				password,
+				Hex.Decode("7d60435f02e9e0ae"),
+				2048);
+
+			inBytes = cDec.DoFinal(outBytes);
+	        
+			if (!AreEqual(input, inBytes))
+			{
+				Fail("RC4 failed without param");
+			}
+
+			for (int i = 0; i != pkcs12Tests.Length; i++)
+			{
+				pkcs12Tests[i].PerformTest();
+			}
+
+			for (int i = 0; i != openSSLTests.Length; i++)
+			{
+				openSSLTests[i].PerformTest();
+			}
+
+			doTestPbeHMac("PBEWithHMacSHA1", hMac1);
+			doTestPbeHMac("PBEWithHMacRIPEMD160", hMac2);
+		}
+
+		public override string Name
+		{
+			get { return "PbeTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PbeTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/PEMData.cs b/crypto/test/src/test/PEMData.cs
new file mode 100644
index 000000000..ea783c88c
--- /dev/null
+++ b/crypto/test/src/test/PEMData.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace Org.BouncyCastle.Tests
+{
+	class PemData
+	{
+		internal static readonly string CERTIFICATE_1 =
+			"-----BEGIN X509 CERTIFICATE-----\r"
+			+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx\r"
+			+ "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY\r"
+			+ "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB\r"
+			+ "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ\r"
+			+ "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2\r"
+			+ "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW\r"
+			+ "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM\r"
+			+ "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l\r"
+			+ "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv\r"
+			+ "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re\r"
+			+ "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO\r"
+			+ "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE\r"
+			+ "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy\r"
+			+ "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0\r"
+			+ "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw\r"
+			+ "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL\r"
+			+ "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4\r"
+			+ "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF\r"
+			+ "5/8=\r"
+			+ "-----END X509 CERTIFICATE-----\r";
+
+		internal static readonly string CERTIFICATE_2 =
+			"-----BEGIN CERTIFICATE-----\n"
+			+ "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx\n"
+			+ "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY\n"
+			+ "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB\n"
+			+ "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ\n"
+			+ "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2\n"
+			+ "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW\n"
+			+ "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM\n"
+			+ "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l\n"
+			+ "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv\n"
+			+ "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re\n"
+			+ "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO\n"
+			+ "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE\n"
+			+ "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy\n"
+			+ "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0\n"
+			+ "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw\n"
+			+ "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL\n"
+			+ "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4\n"
+			+ "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF\n"
+			+ "5/8=\n"
+			+ "-----END CERTIFICATE-----\n";
+
+		internal static readonly string CRL_1 =
+			"-----BEGIN X509 CRL-----\r\n"
+			+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT\r\n"
+			+ "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy\r\n"
+			+ "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw\r\n"
+			+ "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw\r\n"
+			+ "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw\r\n"
+			+ "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw\r\n"
+			+ "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw\r\n"
+			+ "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw\r\n"
+			+ "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw\r\n"
+			+ "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw\r\n"
+			+ "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF\r\n"
+			+ "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ\r\n"
+			+ "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt\r\n"
+			+ "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v\r\n"
+			+ "-----END X509 CRL-----\r\n";
+
+		internal static readonly string CRL_2 =
+			"-----BEGIN CRL-----\r\n"
+			+ "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT\r\n"
+			+ "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy\r\n"
+			+ "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw\r\n"
+			+ "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw\r\n"
+			+ "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw\r\n"
+			+ "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw\r\n"
+			+ "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw\r\n"
+			+ "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw\r\n"
+			+ "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw\r\n"
+			+ "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw\r\n"
+			+ "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF\r\n"
+			+ "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ\r\n"
+			+ "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt\r\n"
+			+ "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v\r\n"
+			+ "-----END CRL-----\r\n";
+
+		internal static readonly string ATTRIBUTE_CERTIFICATE_1 =
+			"-----BEGIN X509 ATTRIBUTE CERTIFICATE-----\r\n"
+			+ "MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl\r\n"
+			+ "IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy\r\n"
+			+ "aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV\r\n"
+			+ "BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv\r\n"
+			+ "dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw\r\n"
+			+ "MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV\r\n"
+			+ "MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI\r\n"
+			+ "NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7\r\n"
+			+ "eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G\r\n"
+			+ "odUBlSsJwPPQjZSU\r\n"
+			+ "-----END X509 ATTRIBUTE CERTIFICATE-----\r\n";
+
+		internal static readonly string ATTRIBUTE_CERTIFICATE_2 =
+			"-----BEGIN ATTRIBUTE CERTIFICATE-----\r\n"
+			+ "MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl\r\n"
+			+ "IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy\r\n"
+			+ "aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV\r\n"
+			+ "BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv\r\n"
+			+ "dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw\r\n"
+			+ "MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV\r\n"
+			+ "MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI\r\n"
+			+ "NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7\r\n"
+			+ "eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G\r\n"
+			+ "odUBlSsJwPPQjZSU\r\n"
+			+ "-----END ATTRIBUTE CERTIFICATE-----\r\n";
+	}
+}
diff --git a/crypto/test/src/test/PKCS10CertRequestTest.cs b/crypto/test/src/test/PKCS10CertRequestTest.cs
new file mode 100644
index 000000000..819439cd8
--- /dev/null
+++ b/crypto/test/src/test/PKCS10CertRequestTest.cs
@@ -0,0 +1,470 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.Tests
+{
+    [TestFixture]
+    public class Pkcs10CertRequestTest
+        : SimpleTest
+    {
+        private static readonly byte[] gost3410EC_A = Base64.Decode(
+              "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+            +"BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+            +"MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMCAh4B"
+            +"A0MABEBYx0P2D7YuuZo5HgdIAUKAXcLBDZ+4LYFgbKjrfStVfH59lc40BQ2FZ7M703hLpXK8GiBQ"
+            +"GEYpKaAuQZnMIpByoAAwCAYGKoUDAgIDA0EAgXMcTrhdOY2Er2tHOSAgnMezqrYxocZTWhxmW5Rl"
+            +"JY6lbXH5rndCn4swFzXU+YhgAsJv1wQBaoZEWRl5WV4/nA==");
+
+        private static readonly byte[] gost3410EC_B = Base64.Decode(
+              "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+            +"A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+            +"MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwIC"
+            +"HgEDQwAEQI5SLoWT7dZVilbV9j5B/fyIDuDs6x4pjqNC2TtFYbpRHrk/Wc5g/mcHvD80tsm5o1C7"
+            +"7cizNzkvAVUM4VT4Dz6gADAIBgYqhQMCAgMDQQAoT5TwJ8o+bSrxckymyo3diwG7ZbSytX4sRiKy"
+            +"wXPWRS9LlBvPO2NqwpS2HUnxSU8rzfL9fJcybATf7Yt1OEVq");
+
+        private static readonly byte[] gost3410EC_C = Base64.Decode(
+              "MIIBRDCB9AIBADCBhzEVMBMGA1UEAxMMdGVzdCByZXF1ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBM"
+            +"dGQxHjAcBgNVBAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYD"
+            +"VQQGEwJydTEZMBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMD"
+            +"BgcqhQMCAh4BA0MABEBcmGh7OmR4iqqj+ycYo1S1fS7r5PhisSQU2Ezuz8wmmmR2zeTZkdMYCOBa"
+            +"UTMNms0msW3wuYDho7nTDNscHTB5oAAwCAYGKoUDAgIDA0EAVoOMbfyo1Un4Ss7WQrUjHJoiaYW8"
+            +"Ime5LeGGU2iW3ieAv6es/FdMrwTKkqn5dhd3aL/itFg5oQbhyfXw5yw/QQ==");
+
+        private static readonly byte[] gost3410EC_ExA = Base64.Decode(
+              "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV"
+            + "BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ"
+            + "MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiQABgcqhQMCAh4B"
+            + "A0MABEDkqNT/3f8NHj6EUiWnK4JbVZBh31bEpkwq9z3jf0u8ZndG56Vt+K1ZB6EpFxLT7hSIos0w"
+            + "weZ2YuTZ4w43OgodoAAwCAYGKoUDAgIDA0EASk/IUXWxoi6NtcUGVF23VRV1L3undB4sRZLp4Vho"
+            + "gQ7m3CMbZFfJ2cPu6QyarseXGYHmazoirH5lGjEo535c1g==");
+
+        private static readonly byte[] gost3410EC_ExB = Base64.Decode(
+              "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG"
+            + "A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1"
+            + "MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwIC"
+            + "HgEDQwAEQMBWYUKPy/1Kxad9ChAmgoSWSYOQxRnXo7KEGLU5RNSXA4qMUvArWzvhav+EYUfTbWLh"
+            + "09nELDyHt2XQcvgQHnSgADAIBgYqhQMCAgMDQQAdaNhgH/ElHp64mbMaEo1tPCg9Q22McxpH8rCz"
+            + "E0QBpF4H5mSSQVGI5OAXHToetnNuh7gHHSynyCupYDEHTbkZ");
+
+        public override string Name
+        {
+            get { return "PKCS10CertRequest"; }
+        }
+
+        private void generationTest(
+            int		keySize,
+            string	keyName,
+            string	sigName)
+        {
+            IAsymmetricCipherKeyPairGenerator kpg = GeneratorUtilities.GetKeyPairGenerator(keyName);
+
+//			kpg.initialize(keySize);
+            kpg.Init(new KeyGenerationParameters(new SecureRandom(), keySize));
+
+            AsymmetricCipherKeyPair kp = kpg.GenerateKeyPair();
+
+            IDictionary attrs = new Hashtable();
+            attrs.Add(X509Name.C, "AU");
+            attrs.Add(X509Name.O, "The Legion of the Bouncy Castle");
+            attrs.Add(X509Name.L, "Melbourne");
+            attrs.Add(X509Name.ST, "Victoria");
+            attrs.Add(X509Name.EmailAddress, "feedback-crypto@bouncycastle.org");
+
+            IList order = new ArrayList();
+            order.Add(X509Name.C);
+            order.Add(X509Name.O);
+            order.Add(X509Name.L);
+            order.Add(X509Name.ST);
+            order.Add(X509Name.EmailAddress);
+
+            X509Name subject = new X509Name(order, attrs);
+
+            Pkcs10CertificationRequest req1 = new Pkcs10CertificationRequest(
+                sigName,
+                subject,
+                kp.Public,
+                null,
+                kp.Private);
+
+            byte[] bytes = req1.GetEncoded();
+
+            Pkcs10CertificationRequest req2 = new Pkcs10CertificationRequest(bytes);
+
+            if (!req2.Verify())
+            {
+                Fail(sigName + ": Failed Verify check.");
+            }
+
+            if (!req2.GetPublicKey().Equals(req1.GetPublicKey()))
+            {
+                Fail(keyName + ": Failed public key check.");
+            }
+        }
+
+        /*
+         * we generate a self signed certificate for the sake of testing - SHA224withECDSA
+         */
+        private void createECRequest(
+            string				algorithm,
+            DerObjectIdentifier	algOid)
+        {
+            FpCurve curve = new FpCurve(
+                new BigInteger("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"), // q (or p)
+                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC", 16),   // a
+                new BigInteger("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 16));  // b
+
+            ECDomainParameters spec = new ECDomainParameters(
+                curve,
+//				curve.DecodePoint(Hex.Decode("02C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+                curve.DecodePoint(Hex.Decode("0200C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")), // G
+                new BigInteger("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", 16)); // n
+
+            ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(
+                new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d
+                spec);
+
+            ECPublicKeyParameters pubKey = new ECPublicKeyParameters(
+//				curve.DecodePoint(Hex.Decode("026BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+                curve.DecodePoint(Hex.Decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q
+                spec);
+
+//			//
+//			// set up the keys
+//			//
+//			AsymmetricKeyParameter privKey;
+//			AsymmetricKeyParameter pubKey;
+//
+//			KeyFactory fact = KeyFactory.getInstance("ECDSA");
+//
+//			privKey = fact.generatePrivate(privKeySpec);
+//			pubKey = fact.generatePublic(pubKeySpec);
+
+            Pkcs10CertificationRequest req = new Pkcs10CertificationRequest(
+                algorithm, new X509Name("CN=XXX"), pubKey, null, privKey);
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check EC.");
+            }
+
+            req = new Pkcs10CertificationRequest(req.GetEncoded());
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check EC encoded.");
+            }
+
+            //
+            // try with point compression turned off
+            //
+//			((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED");
+            ECPoint q = pubKey.Q.Normalize();
+            pubKey = new ECPublicKeyParameters(
+                pubKey.AlgorithmName,
+                q.Curve.CreatePoint(q.XCoord.ToBigInteger(), q.YCoord.ToBigInteger()),
+                pubKey.Parameters);
+
+            req = new Pkcs10CertificationRequest(
+                algorithm, new X509Name("CN=XXX"), pubKey, null, privKey);
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check EC uncompressed.");
+            }
+
+            req = new Pkcs10CertificationRequest(req.GetEncoded());
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check EC uncompressed encoded.");
+            }
+
+            if (!req.SignatureAlgorithm.ObjectID.Equals(algOid))
+            {
+                Fail("ECDSA oid incorrect.");
+            }
+
+            if (req.SignatureAlgorithm.Parameters != null)
+            {
+                Fail("ECDSA parameters incorrect.");
+            }
+
+            ISigner sig = SignerUtilities.GetSigner(algorithm);
+
+            sig.Init(false, pubKey);
+
+            byte[] b = req.GetCertificationRequestInfo().GetEncoded();
+            sig.BlockUpdate(b, 0, b.Length);
+
+            if (!sig.VerifySignature(req.Signature.GetBytes()))
+            {
+                Fail("signature not mapped correctly.");
+            }
+        }
+
+        private void createECGostRequest()
+        {
+            string algorithm = "GOST3411withECGOST3410";
+            IAsymmetricCipherKeyPairGenerator ecGostKpg = GeneratorUtilities.GetKeyPairGenerator("ECGOST3410");
+
+            ecGostKpg.Init(
+                new ECKeyGenerationParameters(
+                    CryptoProObjectIdentifiers.GostR3410x2001CryptoProA,
+                    new SecureRandom()));
+
+            //
+            // set up the keys
+            //
+            AsymmetricCipherKeyPair pair = ecGostKpg.GenerateKeyPair();
+            AsymmetricKeyParameter privKey = pair.Private;
+            AsymmetricKeyParameter pubKey = pair.Public;
+
+            Pkcs10CertificationRequest req = new Pkcs10CertificationRequest(
+                algorithm, new X509Name("CN=XXX"), pubKey, null, privKey);
+
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check EC.");
+            }
+
+            req = new Pkcs10CertificationRequest(req.GetEncoded());
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check EC encoded.");
+            }
+
+            if (!req.SignatureAlgorithm.ObjectID.Equals(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001))
+            {
+                Fail("ECGOST oid incorrect.");
+            }
+
+            if (req.SignatureAlgorithm.Parameters != null)
+            {
+                Fail("ECGOST parameters incorrect.");
+            }
+
+            ISigner sig = SignerUtilities.GetSigner(algorithm);
+
+            sig.Init(false, pubKey);
+
+            byte[] b = req.GetCertificationRequestInfo().GetEncoded();
+            sig.BlockUpdate(b, 0, b.Length);
+
+            if (!sig.VerifySignature(req.Signature.GetBytes()))
+            {
+                Fail("signature not mapped correctly.");
+            }
+        }
+
+        private void createPssTest(
+            string algorithm)
+        {
+//			RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
+            RsaKeyParameters pubKey = new RsaKeyParameters(false,
+                new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+                new BigInteger("010001",16));
+
+//			RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec(
+            RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+                new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+                new BigInteger("010001",16),
+                new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+                new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+                new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+                new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+                new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+                new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+//			KeyFactory  fact = KeyFactory.getInstance("RSA", "BC");
+//
+//			PrivateKey privKey = fact.generatePrivate(privKeySpec);
+//			PublicKey pubKey = fact.generatePublic(pubKeySpec);
+
+            Pkcs10CertificationRequest req = new Pkcs10CertificationRequest(
+                algorithm, new X509Name("CN=XXX"), pubKey, null, privKey);
+
+            if (!req.Verify())
+            {
+                Fail("Failed verify check PSS.");
+            }
+
+            req = new Pkcs10CertificationRequest(req.GetEncoded());
+            if (!req.Verify())
+            {
+                Fail("Failed verify check PSS encoded.");
+            }
+
+            if (!req.SignatureAlgorithm.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+            {
+                Fail("PSS oid incorrect.");
+            }
+
+            if (req.SignatureAlgorithm.Parameters == null)
+            {
+                Fail("PSS parameters incorrect.");
+            }
+
+            ISigner sig = SignerUtilities.GetSigner(algorithm);
+
+            sig.Init(false, pubKey);
+
+            byte[] encoded = req.GetCertificationRequestInfo().GetEncoded();
+            sig.BlockUpdate(encoded, 0, encoded.Length);
+
+            if (!sig.VerifySignature(req.Signature.GetBytes()))
+            {
+                Fail("signature not mapped correctly.");
+            }
+        }
+
+        // previous code found to cause a NullPointerException
+        private void nullPointerTest()
+        {
+            IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+            keyGen.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
+
+            AsymmetricCipherKeyPair pair = keyGen.GenerateKeyPair();
+
+            IList oids = new ArrayList();
+            IList values = new ArrayList();
+            oids.Add(X509Extensions.BasicConstraints);
+            values.Add(new X509Extension(true, new DerOctetString(new BasicConstraints(true))));
+            oids.Add(X509Extensions.KeyUsage);
+            values.Add(new X509Extension(true, new DerOctetString(
+                new KeyUsage(KeyUsage.KeyCertSign | KeyUsage.CrlSign))));
+            SubjectKeyIdentifier subjectKeyIdentifier = new SubjectKeyIdentifierStructure(pair.Public);
+            X509Extension ski = new X509Extension(false, new DerOctetString(subjectKeyIdentifier));
+            oids.Add(X509Extensions.SubjectKeyIdentifier);
+            values.Add(ski);
+
+            AttributePkcs attribute = new AttributePkcs(PkcsObjectIdentifiers.Pkcs9AtExtensionRequest,
+                new DerSet(new X509Extensions(oids, values)));
+
+            Pkcs10CertificationRequest p1 = new Pkcs10CertificationRequest(
+                "SHA1WithRSA", new X509Name("cn=csr"), pair.Public, new DerSet(attribute), pair.Private);
+            Pkcs10CertificationRequest p2 = new Pkcs10CertificationRequest(
+                "SHA1WithRSA", new X509Name("cn=csr"), pair.Public, new DerSet(attribute), pair.Private);
+
+            if (!p1.Equals(p2))
+            {
+                Fail("cert request comparison failed");
+            }
+        }
+
+        public override void PerformTest()
+        {
+            generationTest(512, "RSA", "SHA1withRSA");
+            generationTest(512, "GOST3410", "GOST3411withGOST3410");
+
+            //		if (Security.getProvider("SunRsaSign") != null)
+            //        {
+            //            generationTest(512, "RSA", "SHA1withRSA", "SunRsaSign");
+            //        }
+
+            // elliptic curve GOST A parameter set
+            Pkcs10CertificationRequest req = new Pkcs10CertificationRequest(gost3410EC_A);
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check gost3410EC_A.");
+            }
+
+            // elliptic curve GOST B parameter set
+            req = new Pkcs10CertificationRequest(gost3410EC_B);
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check gost3410EC_B.");
+            }
+
+            // elliptic curve GOST C parameter set
+            req = new Pkcs10CertificationRequest(gost3410EC_C);
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check gost3410EC_C.");
+            }
+
+            // elliptic curve GOST ExA parameter set
+            req = new Pkcs10CertificationRequest(gost3410EC_ExA);
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check gost3410EC_ExA.");
+            }
+
+            // elliptic curve GOST ExB parameter set
+            req = new Pkcs10CertificationRequest(gost3410EC_ExB);
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check gost3410EC_ExA.");
+            }
+
+            // elliptic curve openSSL
+            IAsymmetricCipherKeyPairGenerator g = GeneratorUtilities.GetKeyPairGenerator("ECDSA");
+
+            ECCurve curve = new FpCurve(
+                new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+
+            ECDomainParameters ecSpec = new ECDomainParameters(
+                curve,
+                curve.DecodePoint(Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G
+                new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307")); // n
+
+//			g.initialize(ecSpec, new SecureRandom());
+            g.Init(new ECKeyGenerationParameters(ecSpec, new SecureRandom()));
+
+            AsymmetricCipherKeyPair kp = g.GenerateKeyPair();
+
+            req = new Pkcs10CertificationRequest(
+                "ECDSAWITHSHA1", new X509Name("CN=XXX"), kp.Public, null, kp.Private);
+
+            if (!req.Verify())
+            {
+                Fail("Failed Verify check EC.");
+            }
+
+            createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+            createECRequest("SHA224withECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+            createECRequest("SHA256withECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+            createECRequest("SHA384withECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+            createECRequest("SHA512withECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+
+            createECGostRequest();
+
+            // TODO The setting of parameters for MGF algorithms is not implemented
+//			createPssTest("SHA1withRSAandMGF1");
+//			createPssTest("SHA224withRSAandMGF1");
+//			createPssTest("SHA256withRSAandMGF1");
+//			createPssTest("SHA384withRSAandMGF1");
+
+            nullPointerTest();
+        }
+
+        public static void Main(
+            string[] args)
+        {
+            RunTest(new Pkcs10CertRequestTest());
+        }
+
+        [Test]
+        public void TestFunction()
+        {
+            string resultText = Perform().ToString();
+
+            Assert.AreEqual(Name + ": Okay", resultText);
+        }
+    }
+}
diff --git a/crypto/test/src/test/PSSTest.cs b/crypto/test/src/test/PSSTest.cs
new file mode 100644
index 000000000..677289e7c
--- /dev/null
+++ b/crypto/test/src/test/PSSTest.cs
@@ -0,0 +1,253 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class PssTest
+		: SimpleTest
+	{
+		private class FixedRandom
+			: SecureRandom
+		{
+			private readonly byte[] vals;
+
+			public FixedRandom(
+				byte[] vals)
+			{
+				this.vals = vals;
+			}
+
+			public override void NextBytes(
+				byte[] bytes)
+			{
+				vals.CopyTo(bytes, 0);
+			}
+		}
+
+		private RsaKeyParameters pubKey = new RsaKeyParameters(false,
+			new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+			new BigInteger("010001",16));
+
+		private RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+			new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16),
+			new BigInteger("010001",16),
+			new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16),
+			new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16),
+			new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16),
+			new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16),
+			new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16),
+			new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16));
+
+		// PSSExample1.1
+
+		private static readonly byte[] msg1a = Hex.Decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0");
+
+		private static readonly byte[] slt1a = Hex.Decode("dee959c7e06411361420ff80185ed57f3e6776af");
+
+		private static readonly byte[] sig1a = Hex.Decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c");
+
+		private static readonly byte[] sig1b = Hex.Decode("96ea348db4db2947aee807bd687411a880913706f21b383a1002b97e43656e5450a9d1812efbedd1ed159f8307986adf48bada66a8efd14bd9e2f6f6f458e73b50c8ce6e3079011c5b4bd1600a2601a66198a1582574a43f13e0966c6c2337e6ca0886cd9e1b1037aeadef1382117d22b35e7e4403f90531c8cfccdf223f98e4");
+
+		private static readonly byte[] sig1c = Hex.Decode("9e64cc1062c537b142480bc5af407b55904ead970e20e0f8f6664279c96c6da6b03522160f224a85cc413dfe6bd00621485b665abac6d90ff38c9af06f4ddd6c7c81540439e5795601a1343d9feb465712ff8a5f5150391522fb5a9b8e2225a555f4efaa5e5c0ed7a19b27074c2d9f6dbbd0c893ba02c4a35b115d337bccd7a2");
+
+		public override void PerformTest()
+		{
+			ISigner s = SignerUtilities.GetSigner("SHA1withRSA/PSS");
+
+			s.Init(true, new ParametersWithRandom(privKey, new FixedRandom(slt1a)));
+			s.BlockUpdate(msg1a, 0, msg1a.Length);
+			byte[] sig = s.GenerateSignature();
+
+			if (!Arrays.AreEqual(sig1a, sig))
+			{
+				Fail("PSS Sign test expected "
+					+ Hex.ToHexString(sig1a) + " got "
+					+ Hex.ToHexString(sig));
+			}
+
+			s = SignerUtilities.GetSigner("SHA1withRSAandMGF1");
+
+			s.Init(false, pubKey);
+			s.BlockUpdate(msg1a, 0, msg1a.Length);
+			if (!s.VerifySignature(sig1a))
+			{
+				Fail("SHA1 signature verification failed");
+			}
+
+			s = SignerUtilities.GetSigner("SHA1withRSAandMGF1");
+
+			s.Init(false, pubKey);
+			s.BlockUpdate(msg1a, 0, msg1a.Length);
+			if (!s.VerifySignature(sig1a))
+			{
+				Fail("SHA1 signature verification with default parameters failed");
+			}
+
+//				AlgorithmParameters pss = s.getParameters();
+			// TODO Can we do some equivalent check?
+//				if (!Arrays.AreEqual(pss.getEncoded(), new byte[] { 0x30, 0x00 }))
+//				{
+//					Fail("failed default encoding test.");
+//				}
+
+			s = SignerUtilities.GetSigner("SHA256withRSA/PSS");
+
+			s.Init(true, new ParametersWithRandom(privKey, new FixedRandom(slt1a)));
+			s.BlockUpdate(msg1a, 0, msg1a.Length);
+			sig = s.GenerateSignature();
+
+			if (!Arrays.AreEqual(sig1b, sig))
+			{
+				Fail("PSS Sign test expected "
+					+ Hex.ToHexString(sig1b) + " got "
+					+ Hex.ToHexString(sig));
+			}
+
+			s = SignerUtilities.GetSigner("SHA256withRSAandMGF1");
+
+			s.Init(false, pubKey);
+			s.BlockUpdate(msg1a, 0, msg1a.Length);
+			if (!s.VerifySignature(sig1b))
+			{
+				Fail("SHA256 signature verification failed");
+			}
+
+			//
+			// 512 test -with zero salt length
+			//
+			//s = SignerUtilities.GetSigner("SHA512withRSAandMGF1");
+//				s.setParameter(
+//					new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 0, 1));
+
+			// TODO How to do this via SignerUtilities/Init
+			// trailerField=1 above means use default/implicit trailer?)
+			s = new PssSigner(new RsaEngine(), new Sha512Digest(), 0, PssSigner.TrailerImplicit);
+			s.Init(true, privKey);
+
+			s.BlockUpdate(msg1a, 0, msg1a.Length);
+			sig = s.GenerateSignature();
+
+//				pss = s.getParameters();
+
+			if (!Arrays.AreEqual(sig1c, sig))
+			{
+				Fail("PSS Sign test expected "
+					+ Hex.ToHexString(sig1c) + " got "
+					+ Hex.ToHexString(sig));
+			}
+
+
+
+//				s = SignerUtilities.GetSigner("SHA512withRSAandMGF1");
+
+			// TODO How to do this via SignerUtilities/Init
+			// trailerField=1 above means use default/implicit trailer?)
+			s = new PssSigner(new RsaEngine(), new Sha512Digest(), 0, PssSigner.TrailerImplicit);
+			s.Init(false, pubKey);
+
+			s.BlockUpdate(msg1a, 0, msg1a.Length);
+			if (!s.VerifySignature(sig1c))
+			{
+				Fail("SHA512 signature verification failed");
+			}
+
+			SecureRandom random = new SecureRandom();
+
+			// Note: PSS minimum key size determined by hash/salt lengths
+//			PrivateKey priv2048Key = fact.generatePrivate(RSATest.priv2048KeySpec);
+//			PublicKey pub2048Key = fact.generatePublic(RSATest.pub2048KeySpec);
+			AsymmetricKeyParameter priv2048Key = RsaTest.priv2048KeySpec;
+			AsymmetricKeyParameter pub2048Key = RsaTest.pub2048KeySpec;
+
+			rawModeTest("SHA1withRSA/PSS", X509ObjectIdentifiers.IdSha1, priv2048Key, pub2048Key, random);
+			// FIXME
+//			rawModeTest("SHA224withRSA/PSS", NistObjectIdentifiers.IdSha224, priv2048Key, pub2048Key, random);
+//			rawModeTest("SHA256withRSA/PSS", NistObjectIdentifiers.IdSha256, priv2048Key, pub2048Key, random);
+//			rawModeTest("SHA384withRSA/PSS", NistObjectIdentifiers.IdSha384, priv2048Key, pub2048Key, random);
+//			rawModeTest("SHA512withRSA/PSS", NistObjectIdentifiers.IdSha512, priv2048Key, pub2048Key, random);
+		}
+
+		private void rawModeTest(string sigName, DerObjectIdentifier digestOID,
+			AsymmetricKeyParameter privKey, AsymmetricKeyParameter pubKey, SecureRandom random)
+		{
+			byte[] sampleMessage = new byte[1000 + random.Next() % 100];
+			random.NextBytes(sampleMessage);
+
+			ISigner normalSig = SignerUtilities.GetSigner(sigName);
+
+			// FIXME
+//			PSSParameterSpec spec = (PSSParameterSpec)normalSig.getParameters().getParameterSpec(PSSParameterSpec.class);
+
+			// Make sure we generate the same 'random' salt for both normal and raw signers
+			// FIXME
+//			int saltLen = spec.getSaltLength();
+//			byte[] fixedRandomBytes = new byte[saltLen];
+			byte[] fixedRandomBytes = new byte[128];
+			random.NextBytes(fixedRandomBytes);
+
+			normalSig.Init(true, new ParametersWithRandom(privKey, FixedSecureRandom.From(fixedRandomBytes)));
+			normalSig.BlockUpdate(sampleMessage, 0, sampleMessage.Length);
+			byte[] normalResult = normalSig.GenerateSignature();
+
+			byte[] hash = DigestUtilities.CalculateDigest(digestOID.Id, sampleMessage);
+		
+			ISigner rawSig = SignerUtilities.GetSigner("RAWRSASSA-PSS");
+
+			// Need to init the params explicitly to avoid having a 'raw' variety of every PSS algorithm
+			// FIXME
+//			rawSig.setParameter(spec);
+
+			rawSig.Init(true, new ParametersWithRandom(privKey, FixedSecureRandom.From(fixedRandomBytes)));
+			rawSig.BlockUpdate(hash, 0, hash.Length);
+			byte[] rawResult = rawSig.GenerateSignature();
+
+			if (!Arrays.AreEqual(normalResult, rawResult))
+			{
+				Fail("raw mode signature differs from normal one");
+			}
+
+			rawSig.Init(false, pubKey);
+			rawSig.BlockUpdate(hash, 0, hash.Length);
+
+			if (!rawSig.VerifySignature(rawResult))
+			{
+				Fail("raw mode signature verification failed");
+			}
+		}
+
+		public override string Name
+		{
+			get { return "PSS"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PssTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/PkixNameConstraintsTest.cs b/crypto/test/src/test/PkixNameConstraintsTest.cs
new file mode 100644
index 000000000..a20fc33c4
--- /dev/null
+++ b/crypto/test/src/test/PkixNameConstraintsTest.cs
@@ -0,0 +1,433 @@
+using System;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Pkix;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <summary>
+	/// Test class for {@link PkixNameConstraintValidator}.
+	/// The field testXYZ is the name to test.
+	/// The field testXYZIsConstraint must be tested if it is permitted and excluded.
+	/// The field testXYZIsNotConstraint must be tested if it is not permitted and
+	/// not excluded.
+	/// Furthermore there are tests for the intersection and union of test names.
+	/// </summary>
+	[TestFixture]
+	public class PkixNameConstraintsTest
+		: SimpleTest
+	{
+		private readonly string testEmail = "test@abc.test.com";
+
+		private readonly string[] testEmailIsConstraint = { "test@abc.test.com", "abc.test.com", ".test.com" };
+
+		private readonly string[] testEmailIsNotConstraint = { ".abc.test.com", "www.test.com", "test1@abc.test.com", "bc.test.com" };
+
+		private readonly string[] email1 = {
+			"test@test.com", "test@test.com", "test@test.com", "test@abc.test.com",
+			"test@test.com", "test@test.com", ".test.com", ".test.com",
+			".test.com", ".test.com", "test.com", "abc.test.com",
+			"abc.test1.com", "test.com", "test.com", ".test.com" };
+
+		private readonly string[] email2 = {
+			"test@test.abc.com", "test@test.com", ".test.com", ".test.com",
+			"test.com", "test1.com", "test@test.com", ".test.com",
+			".test1.com", "test.com", "test.com", ".test.com", ".test.com",
+			"test1.com", ".test.com", "abc.test.com" };
+
+		private readonly string[] emailintersect = {
+			null, "test@test.com", null, "test@abc.test.com", "test@test.com", null,
+			null, ".test.com", null, null, "test.com", "abc.test.com", null,
+			null, null, "abc.test.com" };
+
+		private readonly string[][] emailunion = new string[16][] {
+			new string[] { "test@test.com", "test@test.abc.com" },
+			new string[] { "test@test.com" },
+			new string[] { "test@test.com", ".test.com" },
+			new string[] { ".test.com" },
+			new string[] { "test.com" },
+			new string[] { "test@test.com", "test1.com" },
+			new string[] { ".test.com", "test@test.com" },
+			new string[] { ".test.com" },
+			new string[] { ".test.com", ".test1.com" },
+			new string[] { ".test.com", "test.com" },
+			new string[] { "test.com" },
+			new string[] { ".test.com" },
+			new string[] { ".test.com", "abc.test1.com" },
+			new string[] { "test1.com", "test.com" },
+			new string[] { ".test.com", "test.com" },
+			new string[] { ".test.com" } };
+
+		private readonly string[] dn1 = { "O=test org, OU=test org unit, CN=John Doe" };
+
+		private readonly string[] dn2 = { "O=test org, OU=test org unit" };
+
+		private readonly string[][] dnUnion = new string[1][] {
+			new string[] { "O=test org, OU=test org unit" } };
+
+		private readonly string[] dnIntersection = { "O=test org, OU=test org unit, CN=John Doe" };
+
+		private readonly string testDN = "O=test org, OU=test org unit, CN=John Doe";
+
+		private readonly string[] testDNIsConstraint = {
+			"O=test org, OU=test org unit",
+			"O=test org, OU=test org unit, CN=John Doe" };
+
+		private readonly string[] testDNIsNotConstraint = {
+			"O=test org, OU=test org unit, CN=John Doe2",
+			"O=test org, OU=test org unit2",
+			"OU=test org unit, O=test org, CN=John Doe",
+			"O=test org, OU=test org unit, CN=John Doe, L=USA" };
+
+		private readonly string testDNS = "abc.test.com";
+
+		private readonly string[] testDNSIsConstraint = { "test.com", "abc.test.com", "test.com" };
+
+		private readonly string[] testDNSIsNotConstraint = { "wwww.test.com", "ww.test.com", "www.test.com" };
+
+		private readonly string[] dns1 = { "www.test.de", "www.test1.de", "www.test.de" };
+
+		private readonly string[] dns2 = { "test.de", "www.test.de", "www.test.de" };
+
+		private readonly string[] dnsintersect = { "www.test.de", null, null };
+
+		private readonly string[][] dnsunion = new string[3][] {
+			new string[] { "test.de" },
+			new string[] { "www.test1.de", "www.test.de" },
+			new string[] { "www.test.de" } };
+
+		private readonly string testURI = "http://karsten:password@abc.test.com:8080";
+
+		private readonly string[] testURIIsConstraint = { "abc.test.com", ".test.com" };
+
+		private readonly string[] testURIIsNotConstraint = { "xyz.test.com", ".abc.test.com" };
+
+		private readonly string[] uri1 = { "www.test.de", ".test.de", "test1.de", ".test.de" };
+
+		private readonly string[] uri2 = { "test.de", "www.test.de", "test1.de", ".test.de" };
+
+		private readonly string[] uriintersect = { null, "www.test.de", "test1.de", ".test.de" };
+
+		private readonly string[][] uriunion = new string[4][] {
+			new string[] { "www.test.de", "test.de" },
+			new string[] { ".test.de" },
+			new string[] { "test1.de" },
+			new string[] { ".test.de" } };
+
+		private readonly byte[] testIP = { (byte)192, (byte)168, 1, 2 };
+
+		private readonly byte[][] testIPIsConstraint = new byte[2][] {
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0 },
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 4 } };
+
+		private readonly byte[][] testIPIsNotConstraint = new byte[2][] {
+			new byte[] { (byte) 192, (byte) 168, 3, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 2 },
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 3 } };
+
+		private readonly byte[][] ip1 = new byte[3][] {
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFE, (byte) 0xFF },
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFF, (byte) 0xFF },
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFF, (byte) 0x00 } };
+
+		private readonly byte[][] ip2 = new byte[3][] {
+			new byte[] { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFC, 3 },
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFF, (byte) 0xFF },
+			new byte[] { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFF, (byte) 0x00 } };
+
+		private readonly byte[][] ipintersect = new byte[3][] {
+			new byte[] { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFE, (byte) 0xFF },
+			new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+						(byte) 0xFF, (byte) 0xFF }, null };
+
+		private readonly byte[][][] ipunion = new byte[3][][] {
+			new byte[2][] {
+							new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+											(byte) 0xFE, (byte) 0xFF },
+							new byte[] { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF,
+											(byte) 0xFC, 3 } },
+			new byte[1][] {
+							new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+											(byte) 0xFF, (byte) 0xFF } },
+			new byte[2][] {
+							new byte[] { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF,
+											(byte) 0xFF, (byte) 0x00 },
+							new byte[] { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF,
+											(byte) 0xFF, (byte) 0x00 } } };
+
+		public override string Name
+		{
+			get { return "PkixNameConstraintsTest"; }
+		}
+
+		public override void PerformTest()
+		{
+			TestConstraints(GeneralName.Rfc822Name, testEmail,
+				testEmailIsConstraint, testEmailIsNotConstraint, email1, email2,
+				emailunion, emailintersect);
+			TestConstraints(GeneralName.DnsName, testDNS, testDNSIsConstraint,
+				testDNSIsNotConstraint, dns1, dns2, dnsunion, dnsintersect);
+			TestConstraints(GeneralName.DirectoryName, testDN, testDNIsConstraint,
+				testDNIsNotConstraint, dn1, dn2, dnUnion, dnIntersection);
+			TestConstraints(GeneralName.UniformResourceIdentifier, testURI,
+				testURIIsConstraint, testURIIsNotConstraint, uri1, uri2, uriunion,
+				uriintersect);
+			TestConstraints(GeneralName.IPAddress, testIP, testIPIsConstraint,
+				testIPIsNotConstraint, ip1, ip2, ipunion, ipintersect);
+		}
+
+		/**
+		 * Tests string based GeneralNames for inclusion or exclusion.
+		 * 
+		 * @param nameType The {@link GeneralName} type to test.
+		 * @param testName The name to test.
+		 * @param testNameIsConstraint The names where <code>testName</code> must
+		 *            be included and excluded.
+		 * @param testNameIsNotConstraint The names where <code>testName</code>
+		 *            must not be excluded and included.
+		 * @param testNames1 Operand 1 of test names to use for union and
+		 *            intersection testing.
+		 * @param testNames2 Operand 2 of test names to use for union and
+		 *            intersection testing.
+		 * @param testUnion The union results.
+		 * @param testInterSection The intersection results.
+		 * @throws Exception If an unexpected exception occurs.
+		 */
+		private void TestConstraints(
+			int			nameType,
+			string		testName,
+			string[]	testNameIsConstraint,
+			string[]	testNameIsNotConstraint,
+			string[]	testNames1,
+			string[]	testNames2,
+			string[][]	testUnion,
+			string[]	testInterSection)
+		{
+			for (int i = 0; i < testNameIsConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, testNameIsConstraint[i]))));
+				constraintValidator.checkPermitted(new GeneralName(nameType, testName));
+			}
+			for (int i = 0; i < testNameIsNotConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, testNameIsNotConstraint[i]))));
+				try
+				{
+					constraintValidator.checkPermitted(new GeneralName(nameType, testName));
+					Fail("not permitted name allowed: " + nameType);
+				}
+				catch (PkixNameConstraintValidatorException)
+				{
+					// expected
+				}
+			}
+			for (int i = 0; i < testNameIsConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, testNameIsConstraint[i])));
+				try
+				{
+					constraintValidator.checkExcluded(new GeneralName(nameType, testName));
+					Fail("excluded name missed: " + nameType);
+				}
+				catch (PkixNameConstraintValidatorException)
+				{
+					// expected
+				}
+			}
+			for (int i = 0; i < testNameIsNotConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, testNameIsNotConstraint[i])));
+				constraintValidator.checkExcluded(new GeneralName(nameType, testName));
+			}
+			for (int i = 0; i < testNames1.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, testNames1[i])));
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, testNames2[i])));
+				PkixNameConstraintValidator constraints2 = new PkixNameConstraintValidator();
+				for (int j = 0; j < testUnion[i].Length; j++)
+				{
+					constraints2.AddExcludedSubtree(new GeneralSubtree(
+						new GeneralName(nameType, testUnion[i][j])));
+				}
+				if (!constraints2.Equals(constraintValidator))
+				{
+					Fail("union wrong: " + nameType);
+				}
+				constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, testNames1[i]))));
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, testNames2[i]))));
+				constraints2 = new PkixNameConstraintValidator();
+				if (testInterSection[i] != null)
+				{
+					constraints2.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+						new GeneralName(nameType, testInterSection[i]))));
+				}
+				else
+				{
+					constraints2.IntersectEmptyPermittedSubtree(nameType);
+				}
+				if (!constraints2.Equals(constraintValidator))
+				{
+					Fail("intersection wrong: " + nameType);
+				}
+			}
+		}
+
+		/**
+		 * Tests byte array based GeneralNames for inclusion or exclusion.
+		 * 
+		 * @param nameType The {@link GeneralName} type to test.
+		 * @param testName The name to test.
+		 * @param testNameIsConstraint The names where <code>testName</code> must
+		 *            be included and excluded.
+		 * @param testNameIsNotConstraint The names where <code>testName</code>
+		 *            must not be excluded and included.
+		 * @param testNames1 Operand 1 of test names to use for union and
+		 *            intersection testing.
+		 * @param testNames2 Operand 2 of test names to use for union and
+		 *            intersection testing.
+		 * @param testUnion The union results.
+		 * @param testInterSection The intersection results.
+		 * @throws Exception If an unexpected exception occurs.
+		 */
+		private void TestConstraints(
+			int nameType,
+			byte[] testName,
+			byte[][] testNameIsConstraint,
+			byte[][] testNameIsNotConstraint,
+			byte[][] testNames1,
+			byte[][] testNames2,
+			byte[][][] testUnion,
+			byte[][] testInterSection)
+		{
+			for (int i = 0; i < testNameIsConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, new DerOctetString(
+					testNameIsConstraint[i])))));
+				constraintValidator.checkPermitted(new GeneralName(nameType,
+					new DerOctetString(testName)));
+			}
+			for (int i = 0; i < testNameIsNotConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, new DerOctetString(
+					testNameIsNotConstraint[i])))));
+				try
+				{
+					constraintValidator.checkPermitted(new GeneralName(nameType,
+						new DerOctetString(testName)));
+					Fail("not permitted name allowed: " + nameType);
+				}
+				catch (PkixNameConstraintValidatorException)
+				{
+					// expected
+				}
+			}
+			for (int i = 0; i < testNameIsConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, new DerOctetString(testNameIsConstraint[i]))));
+				try
+				{
+					constraintValidator.checkExcluded(new GeneralName(nameType,
+						new DerOctetString(testName)));
+					Fail("excluded name missed: " + nameType);
+				}
+				catch (PkixNameConstraintValidatorException)
+				{
+					// expected
+				}
+			}
+			for (int i = 0; i < testNameIsNotConstraint.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, new DerOctetString(testNameIsNotConstraint[i]))));
+				constraintValidator.checkExcluded(new GeneralName(nameType,
+					new DerOctetString(testName)));
+			}
+			for (int i = 0; i < testNames1.Length; i++)
+			{
+				PkixNameConstraintValidator constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, new DerOctetString(testNames1[i]))));
+				constraintValidator.AddExcludedSubtree(new GeneralSubtree(new GeneralName(
+					nameType, new DerOctetString(testNames2[i]))));
+				PkixNameConstraintValidator constraints2 = new PkixNameConstraintValidator();
+				for (int j = 0; j < testUnion[i].Length; j++)
+				{
+					constraints2.AddExcludedSubtree(new GeneralSubtree(
+						new GeneralName(nameType, new DerOctetString(
+						testUnion[i][j]))));
+				}
+				if (!constraints2.Equals(constraintValidator))
+				{
+					Fail("union wrong: " + nameType);
+				}
+				constraintValidator = new PkixNameConstraintValidator();
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, new DerOctetString(testNames1[i])))));
+				constraintValidator.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+					new GeneralName(nameType, new DerOctetString(testNames2[i])))));
+				constraints2 = new PkixNameConstraintValidator();
+				if (testInterSection[i] != null)
+				{
+					constraints2.IntersectPermittedSubtree(new DerSequence(new GeneralSubtree(
+						new GeneralName(nameType, new DerOctetString(
+						testInterSection[i])))));
+				}
+				else
+				{
+					constraints2.IntersectEmptyPermittedSubtree(nameType);
+				}
+
+				if (!constraints2.Equals(constraintValidator))
+				{
+					Fail("intersection wrong: " + nameType);
+				}
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PkixNameConstraintsTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/PkixPolicyMappingTest.cs b/crypto/test/src/test/PkixPolicyMappingTest.cs
new file mode 100644
index 000000000..47e2c3120
--- /dev/null
+++ b/crypto/test/src/test/PkixPolicyMappingTest.cs
@@ -0,0 +1,419 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkix;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class PkixPolicyMappingTest : SimpleTest
+	{
+		static X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
+
+		public override string Name
+		{
+			get { return "PkixPolicyMapping"; }
+		}
+
+		/**
+		 * TrustAnchor's Cert
+		 */
+		private X509Certificate CreateTrustCert(
+			AsymmetricKeyParameter pubKey,
+			AsymmetricKeyParameter privKey)
+		{
+			string issuer = "C=JP, O=policyMappingAdditionalTest, OU=trustAnchor";
+			string subject = "C=JP, O=policyMappingAdditionalTest, OU=trustAnchor";
+			v3CertGen.SetSerialNumber(BigInteger.ValueOf(10));
+			v3CertGen.SetIssuerDN(new X509Name(issuer));
+			v3CertGen.SetNotBefore(DateTime.UtcNow.AddDays(-30));
+			v3CertGen.SetNotAfter(DateTime.UtcNow.AddDays(30));
+			v3CertGen.SetSubjectDN(new X509Name(subject));
+			v3CertGen.SetPublicKey(pubKey);
+			v3CertGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+			X509Certificate cert = v3CertGen.Generate(privKey);
+			return cert;
+		}
+
+		/**
+		 * intermediate cert
+		 */
+		private X509Certificate CreateIntmedCert(
+			AsymmetricKeyParameter pubKey,
+			AsymmetricKeyParameter caPrivKey,
+			AsymmetricKeyParameter caPubKey,
+			Asn1EncodableVector policies,
+			Hashtable policyMap)
+		{
+			string issuer = "C=JP, O=policyMappingAdditionalTest, OU=trustAnchor";
+			string subject = "C=JP, O=policyMappingAdditionalTest, OU=intmedCA";
+			v3CertGen.Reset();
+			v3CertGen.SetSerialNumber(BigInteger.ValueOf(20));
+			v3CertGen.SetIssuerDN(new X509Name(issuer));
+			v3CertGen.SetNotBefore(DateTime.UtcNow.AddDays(-30));
+			v3CertGen.SetNotAfter(DateTime.UtcNow.AddDays(30));
+			v3CertGen.SetSubjectDN(new X509Name(subject));
+			v3CertGen.SetPublicKey(pubKey);
+			v3CertGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+			v3CertGen.AddExtension(X509Extensions.CertificatePolicies, true, new DerSequence(policies));
+			v3CertGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));
+			v3CertGen.AddExtension(X509Extensions.PolicyMappings, true, new PolicyMappings(policyMap));
+			X509Certificate cert = v3CertGen.Generate(caPrivKey);
+			return cert;
+		}
+
+		/**
+		 * endEntity cert
+		 */
+		private X509Certificate CreateEndEntityCert(
+			AsymmetricKeyParameter pubKey,
+			AsymmetricKeyParameter caPrivKey,
+			AsymmetricKeyParameter caPubKey,
+			Asn1EncodableVector policies)
+		{
+			string issuer = "C=JP, O=policyMappingAdditionalTest, OU=intMedCA";
+			string subject = "C=JP, O=policyMappingAdditionalTest, OU=endEntity";
+			v3CertGen.Reset();
+			v3CertGen.SetSerialNumber(BigInteger.ValueOf(20));
+			v3CertGen.SetIssuerDN(new X509Name(issuer));
+			v3CertGen.SetNotBefore(DateTime.UtcNow.AddDays(-30));
+			v3CertGen.SetNotAfter(DateTime.UtcNow.AddDays(30));
+			v3CertGen.SetSubjectDN(new X509Name(subject));
+			v3CertGen.SetPublicKey(pubKey);
+			v3CertGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");
+			v3CertGen.AddExtension(X509Extensions.CertificatePolicies, true, new DerSequence(policies));
+			X509Certificate cert = v3CertGen.Generate(caPrivKey);
+			return cert;
+		}
+
+		private string TestPolicies(
+			int index,
+			X509Certificate trustCert,
+			X509Certificate intCert,
+			X509Certificate endCert,
+			ISet requirePolicies,
+			bool okay)
+		{
+			ISet trust = new HashSet();
+			trust.Add(new TrustAnchor(trustCert, null));
+			X509CertStoreSelector targetConstraints = new X509CertStoreSelector();
+			targetConstraints.Subject = endCert.SubjectDN;
+			PkixBuilderParameters pbParams = new PkixBuilderParameters(trust, targetConstraints);
+
+			ISet certs = new HashSet();
+			certs.Add(intCert);
+			certs.Add(endCert);
+
+			IX509Store store = X509StoreFactory.Create(
+				"CERTIFICATE/COLLECTION",
+				new X509CollectionStoreParameters(certs));
+			pbParams.AddStore(store);
+
+			pbParams.IsRevocationEnabled = false;
+			if (requirePolicies != null)
+			{
+				pbParams.IsExplicitPolicyRequired = true;
+				pbParams.SetInitialPolicies(requirePolicies);
+			}
+
+//			CertPathBuilder cpb = CertPathBuilder.GetInstance("PKIX");
+			PkixCertPathBuilder cpb = new PkixCertPathBuilder();
+			PkixCertPathBuilderResult result = null;
+
+			try
+			{
+				result = (PkixCertPathBuilderResult)cpb.Build(pbParams);
+
+				if (!okay)
+				{
+					Fail(index + ": path validated when failure expected.");
+				}
+
+//				if (result.getPolicyTree() != null)
+//				{
+//					Console.WriteLine("OK");
+//					Console.WriteLine("policy: " + result.getPolicyTree());
+//				}
+//				else
+//				{
+//					Console.WriteLine("OK: policy tree = null");
+//				}
+
+				return "";
+			}
+			catch (TestFailedException e)
+			{
+				throw e;
+			}
+			catch (Exception e)
+			{
+				if (okay)
+				{
+					Fail(index + ": path failed to validate when success expected.");
+				}
+
+				Exception ee = e.InnerException;
+				if (ee != null)
+				{
+					return ee.Message;
+				}
+
+				return e.Message;
+			}
+		}
+
+		public override void PerformTest()
+		{
+			//
+			// personal keys
+			//
+			RsaPublicKeyStructure pubKeySpec = new RsaPublicKeyStructure(
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16));
+
+			RsaPrivateCrtKeyParameters privKeySpec = new RsaPrivateCrtKeyParameters(
+				new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+				new BigInteger("11", 16),
+				new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+				new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+				new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+				new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+				new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+				new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+			//
+			// intermediate keys.
+			//
+			RsaPublicKeyStructure intPubKeySpec = new RsaPublicKeyStructure(
+				new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
+				new BigInteger("ffff", 16));
+
+
+			RsaPrivateCrtKeyParameters intPrivKeySpec = new RsaPrivateCrtKeyParameters(
+				new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16),
+				new BigInteger("ffff", 16),
+				new BigInteger("7deb1b194a85bcfd29cf871411468adbc987650903e3bacc8338c449ca7b32efd39ffc33bc84412fcd7df18d23ce9d7c25ea910b1ae9985373e0273b4dca7f2e0db3b7314056ac67fd277f8f89cf2fd73c34c6ca69f9ba477143d2b0e2445548aa0b4a8473095182631da46844c356f5e5c7522eb54b5a33f11d730ead9c0cff", 16),
+				new BigInteger("ef4cede573cea47f83699b814de4302edb60eefe426c52e17bd7870ec7c6b7a24fe55282ebb73775f369157726fcfb988def2b40350bdca9e5b418340288f649", 16),
+				new BigInteger("97c7737d1b9a0088c3c7b528539247fd2a1593e7e01cef18848755be82f4a45aa093276cb0cbf118cb41117540a78f3fc471ba5d69f0042274defc9161265721", 16),
+				new BigInteger("6c641094e24d172728b8da3c2777e69adfd0839085be7e38c7c4a2dd00b1ae969f2ec9d23e7e37090fcd449a40af0ed463fe1c612d6810d6b4f58b7bfa31eb5f", 16),
+				new BigInteger("70b7123e8e69dfa76feb1236d0a686144b00e9232ed52b73847e74ef3af71fb45ccb24261f40d27f98101e230cf27b977a5d5f1f15f6cf48d5cb1da2a3a3b87f", 16),
+				new BigInteger("e38f5750d97e270996a286df2e653fd26c242106436f5bab0f4c7a9e654ce02665d5a281f2c412456f2d1fa26586ef04a9adac9004ca7f913162cb28e13bf40d", 16));
+
+			//
+			// ca keys
+			//
+			RsaPublicKeyStructure caPubKeySpec = new RsaPublicKeyStructure(
+				new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+				new BigInteger("11", 16));
+
+			RsaPrivateCrtKeyParameters caPrivKeySpec = new RsaPrivateCrtKeyParameters(
+				new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16),
+				new BigInteger("11", 16),
+				new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16),
+				new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16),
+				new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16),
+				new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16),
+				new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16),
+				new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16));
+
+			//
+			// set up the keys
+			//
+			AsymmetricKeyParameter caPrivKey = caPrivKeySpec;
+			RsaKeyParameters caPubKey = new RsaKeyParameters(false, caPubKeySpec.Modulus, caPubKeySpec.PublicExponent);
+			AsymmetricKeyParameter intPrivKey = intPrivKeySpec;
+			RsaKeyParameters intPubKey = new RsaKeyParameters(false, intPubKeySpec.Modulus, intPubKeySpec.PublicExponent);
+			AsymmetricKeyParameter privKey = privKeySpec;
+			RsaKeyParameters pubKey = new RsaKeyParameters(false, pubKeySpec.Modulus, intPubKeySpec.PublicExponent);
+
+			X509Certificate trustCert = CreateTrustCert(caPubKey, caPrivKeySpec);
+			Asn1EncodableVector intPolicies = null;
+			Hashtable map = null;
+			Asn1EncodableVector policies = null;
+			ISet requirePolicies = null;
+			X509Certificate intCert = null;
+			X509Certificate endCert = null;
+
+			// valid test_00
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.2")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = null;
+			string msg = TestPolicies(0, trustCert, intCert, endCert, requirePolicies, true);
+			CheckMessage(0, msg, "");
+
+			// test_01
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.2")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.16.840.1.101.3.2.1.48.1");
+			msg = TestPolicies(1, trustCert, intCert, endCert, requirePolicies, true);
+			CheckMessage(1, msg, "");
+
+			// test_02
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.2")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.5.29.32.0");
+			msg = TestPolicies(2, trustCert, intCert, endCert, requirePolicies, true);
+			CheckMessage(2, msg, "");
+
+			// test_03
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.3")));
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.2")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.16.840.1.101.3.2.1.48.1");
+			msg = TestPolicies(3, trustCert, intCert, endCert, requirePolicies, true);
+			CheckMessage(3, msg, "");
+
+			// test_04
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.3")));
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.3")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.16.840.1.101.3.2.1.48.3");
+			msg = TestPolicies(4, trustCert, intCert, endCert, requirePolicies, true);
+			CheckMessage(4, msg, "");
+
+			// test_05
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.2")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.16.840.1.101.3.2.1.48.2");
+			msg = TestPolicies(5, trustCert, intCert, endCert, requirePolicies, false);
+			CheckMessage(5, msg, "Path processing failed on policy.");
+
+			// test_06
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.1")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.16.840.1.101.3.2.1.48.1");
+			msg = TestPolicies(6, trustCert, intCert, endCert, requirePolicies, true);
+			CheckMessage(6, msg, "");
+
+			// test_07
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.2")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.16.840.1.101.3.2.1.48.3");
+			msg = TestPolicies(7, trustCert, intCert, endCert, requirePolicies, false);
+			CheckMessage(7, msg, "Path processing failed on policy.");
+
+			// test_08
+			intPolicies = new Asn1EncodableVector();
+			intPolicies.Add(new PolicyInformation(new DerObjectIdentifier("2.5.29.32.0")));
+			map = new Hashtable();
+			map["2.16.840.1.101.3.2.1.48.1"] = "2.16.840.1.101.3.2.1.48.2";
+			intCert = CreateIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map);
+
+			policies = new Asn1EncodableVector();
+			policies.Add(new PolicyInformation(new DerObjectIdentifier("2.16.840.1.101.3.2.1.48.3")));
+			endCert = CreateEndEntityCert(pubKey, intPrivKey, intPubKey, policies);
+
+			requirePolicies = new HashSet();
+			requirePolicies.Add("2.16.840.1.101.3.2.1.48.1");
+			msg = TestPolicies(8, trustCert, intCert, endCert, requirePolicies, false);
+			CheckMessage(8, msg, "Path processing failed on policy.");
+		}
+
+		private void CheckMessage(
+			int		index,
+			string	msg,
+			string	expected)
+		{
+			if (!msg.Equals(expected))
+			{
+				Fail("test " + index + " failed got: " + msg + " expected: " + expected);
+			}
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PkixPolicyMappingTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/PkixTest.cs b/crypto/test/src/test/PkixTest.cs
new file mode 100644
index 000000000..882319610
--- /dev/null
+++ b/crypto/test/src/test/PkixTest.cs
@@ -0,0 +1,248 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+    public class PkixTest
+		: SimpleTest
+    {
+        /*
+         * The following certs and crls are described in:
+         * http://www.ietf.org/internet-drafts/draft-ietf-pkix-new-part1-08.txt
+         *
+         *   This section contains four examples: three certificates and a CRL.
+         *   The first two certificates and the CRL comprise a minimal
+         *   certification path.
+         *
+         *   Section C.1 contains an annotated hex dump of a "self-signed"
+         *   certificate issued by a CA whose distinguished name is
+         *   cn=us,o=gov,ou=nist.  The certificate contains a DSA public key with
+         *   parameters, and is signed by the corresponding DSA private key.
+         *
+         *   Section C.2 contains an annotated hex dump of an end entity
+         *   certificate.  The end entity certificate contains a DSA public key,
+         *   and is signed by the private key corresponding to the "self-signed"
+         *   certificate in section C.1.
+         *
+         *   Section C.3 contains a dump of an end entity certificate which
+         *   contains an RSA public key and is signed with RSA and MD5.  This
+         *   certificate is not part of the minimal certification path.
+         *
+         *   Section C.4 contains an annotated hex dump of a CRL.  The CRL is
+         *   issued by the CA whose distinguished name is cn=us,o=gov,ou=nist and
+         *   the list of revoked certificates includes the end entity certificate
+         *   presented in C.2.
+         */
+
+        /**
+         * C.1  Certificate
+         * 
+            * This section contains an annotated hex dump of a 699 byte version 3
+            * certificate.  The certificate contains the following information:
+            * (a)  the serial number is 23 (17 hex);
+            * (b)  the certificate is signed with DSA and the SHA-1 hash algorithm;
+            * (c)  the issuer's distinguished name is OU=NIST; O=gov; C=US
+            * (d)  and the subject's distinguished name is OU=NIST; O=gov; C=US
+            * (e)  the certificate was issued on June 30, 1997 and will expire on
+            * December 31, 1997;
+            * (f)  the certificate contains a 1024 bit DSA public key with
+            * parameters;
+            * (g)  the certificate contains a subject key identifier extension
+            * generated using method (1) of section 4.2.1.2; and
+            * (h)  the certificate is a CA certificate (as indicated through the
+            * basic constraints extension.)
+         */
+        static byte[] rootCertBin = Hex.Decode(
+            "308202bb3082027ba003020102020111300906072a8648ce380403302a310b30"
+            + "09060355040613025553310c300a060355040a1303676f76310d300b06035504"
+            + "0b13044e495354301e170d3937303633303030303030305a170d393731323331"
+            + "3030303030305a302a310b3009060355040613025553310c300a060355040a13"
+            + "03676f76310d300b060355040b13044e495354308201b83082012c06072a8648"
+            + "ce3804013082011f02818100b68b0f942b9acea525c6f2edfcfb9532ac011233"
+            + "b9e01cad909bbc48549ef394773c2c713555e6fe4f22cbd5d83e8993334dfcbd"
+            + "4f41643ea29870ec31b450deebf198280ac93e44b3fd22979683d018a3e3bd35"
+            + "5bffeea321726a7b96dab93f1e5a90af24d620f00d21a7d402b91afcac21fb9e"
+            + "949e4b42459e6ab24863fe43021500b20db0b101df0c6624fc1392ba55f77d57"
+            + "7481e5028181009abf46b1f53f443dc9a565fb91c08e47f10ac30147c2444236"
+            + "a99281de57c5e0688658007b1ff99b77a1c510a580917851513cf6fcfccc46c6"
+            + "817892843df4933d0c387e1a5b994eab1464f60c21224e28089c92b9669f40e8"
+            + "95f6d5312aef39a262c7b26d9e58c43aa81181846daff8b419b4c211aed0223b"
+            + "aa207fee1e57180381850002818100b59e1f490447d1dbf53addca0475e8dd75"
+            + "f69b8ab197d6596982d3034dfd3b365f4af2d14ec107f5d12ad378776356ea96"
+            + "614d420b7a1dfbab91a4cedeef77c8e5ef20aea62848afbe69c36aa530f2c2b9"
+            + "d9822b7dd9c4841fde0de854d71b992eb3d088f6d6639ba7e20e82d43b8a681b"
+            + "065631590b49eb99a5d581417bc955a3323030301d0603551d0e0416041486ca"
+            + "a5228162efad0a89bcad72412c2949f48656300f0603551d130101ff04053003"
+            + "0101ff300906072a8648ce380403032f00302c0214431bcf292545c04e52e77d"
+            + "d6fcb1664c83cf2d7702140b5b9a241198e8f3869004f608a9e18da5cc3ad4");
+
+
+        /**
+         * C.2  Certificate
+         * 
+            * This section contains an annotated hex dump of a 730 byte version 3
+            * certificate.  The certificate contains the following information:
+            * (a the serial number is 18 (12 hex);
+            * (b)  the certificate is signed with DSA and the SHA-1 hash algorithm;
+            * (c)  the issuer's distinguished name is OU=nist; O=gov; C=US
+            * (d)  and the subject's distinguished name is CN=Tim Polk; OU=nist;
+            * O=gov; C=US
+            * (e)  the certificate was valid from July 30, 1997 through December 1,
+            * 1997;
+            * (f)  the certificate contains a 1024 bit DSA public key;
+            * (g)  the certificate is an end entity certificate, as the basic
+            * constraints extension is not present;
+            * (h)  the certificate contains an authority key identifier extension
+            * matching the subject key identifier of the certificate in Appendix
+            * C.1; and
+            * (i)  the certificate includes one alternative name - an RFC 822
+            * address of "wpolk@nist.gov".
+         */
+        static byte[] userCert1Bin = Hex.Decode(
+            "308202da30820299a003020102020112300906072a8648ce380403302a310b30"
+            + "09060355040613025553310c300a060355040a1303676f76310d300b06035504"
+            + "0b13044e495354301e170d3937303733303030303030305a170d393731323031"
+            + "3030303030305a303d310b3009060355040613025553310c300a060355040a13"
+            + "03676f76310d300b060355040b13044e4953543111300f060355040313085469"
+            + "6d20506f6c6b308201b73082012c06072a8648ce3804013082011f02818100b6"
+            + "8b0f942b9acea525c6f2edfcfb9532ac011233b9e01cad909bbc48549ef39477"
+            + "3c2c713555e6fe4f22cbd5d83e8993334dfcbd4f41643ea29870ec31b450deeb"
+            + "f198280ac93e44b3fd22979683d018a3e3bd355bffeea321726a7b96dab93f1e"
+            + "5a90af24d620f00d21a7d402b91afcac21fb9e949e4b42459e6ab24863fe4302"
+            + "1500b20db0b101df0c6624fc1392ba55f77d577481e5028181009abf46b1f53f"
+            + "443dc9a565fb91c08e47f10ac30147c2444236a99281de57c5e0688658007b1f"
+            + "f99b77a1c510a580917851513cf6fcfccc46c6817892843df4933d0c387e1a5b"
+            + "994eab1464f60c21224e28089c92b9669f40e895f6d5312aef39a262c7b26d9e"
+            + "58c43aa81181846daff8b419b4c211aed0223baa207fee1e5718038184000281"
+            + "8030b675f77c2031ae38bb7e0d2baba09c4bdf20d524133ccd98e55f6cb7c1ba"
+            + "4abaa9958053f00d72dc3337f4010bf5041f9d2e1f62d8843a9b25095a2dc846"
+            + "8e2bd4f50d3bc72dc66cb998c1253a444e8eca9561357cce15315c23131ea205"
+            + "d17a241ccbd3720990ff9b9d28c0a10aec469f0db8d0dcd018a62b5ef98fb595"
+            + "bea33e303c30190603551d1104123010810e77706f6c6b406e6973742e676f76"
+            + "301f0603551d2304183016801486caa5228162efad0a89bcad72412c2949f486"
+            + "56300906072a8648ce380403033000302d02143697cbe3b42ce1bb61a9d3cc24"
+            + "cc22929ff4f587021500abc979afd2161ca9e368a91410b4a02eff225a73");
+
+		/**
+		* C.3  End Entity Certificate Using RSA
+		* 
+		* This section contains an annotated hex dump of a 654 byte version 3
+		* certificate.  The certificate contains the following information:
+		* (a)  the serial number is 256;
+		* (b)  the certificate is signed with RSA and the SHA-1 hash algorithm;
+		* (c)  the issuer's distinguished name is OU=NIST; O=gov; C=US
+		* (d)  and the subject's distinguished name is CN=Tim Polk; OU=NIST;
+		* O=gov; C=US
+		* (e)  the certificate was issued on May 21, 1996 at 09:58:26 and
+		* expired on May 21, 1997 at 09:58:26;
+		* (f)  the certificate contains a 1024 bit RSA public key;
+		* (g)  the certificate is an end entity certificate (not a CA
+		* certificate);
+		* (h)  the certificate includes an alternative subject name of
+		*    "&lt;http://www.itl.nist.gov/div893/staff/polk/index.html&gt;" and an
+		* alternative issuer name of "&lt;http://www.nist.gov/&gt;" - both are URLs;
+		* (i)  the certificate include an authority key identifier extension
+		* and a certificate policies extension psecifying the policy OID
+		* 2.16.840.1.101.3.2.1.48.9; and
+		* (j)  the certificate includes a critical key usage extension
+		* specifying that the public key is intended for verification of
+		* digital signatures.
+		*/
+        static byte[] userCert2Bin = Hex.Decode(
+            "3082028e308201f7a00302010202020100300d06092a864886f70d0101050500"
+            + "302a310b3009060355040613025553310c300a060355040b1303676f76310d30"
+            + "0b060355040a13044e495354301e170d3936303532313039353832365a170d39"
+            + "37303532313039353832365a303d310b3009060355040613025553310c300a06"
+            + "0355040b1303676f76310d300b060355040a13044e4953543111300f06035504"
+            + "03130854696d20506f6c6b30819f300d06092a864886f70d010101050003818d"
+            + "0030818902818100e16ae4033097023cf410f3b51e4d7f147bf6f5d078e9a48a"
+            + "f0a375ecedb656967f8899859af23e687787eb9ed19fc0b417dcab8923a41d7e"
+            + "16234c4fa84df531b87caae31a4909f44b26db2767308212014ae91ab6c10c53"
+            + "8b6cfc2f7a43ec33367e32b27bd5aacf0114c612ec13f22d147a8b215814134c"
+            + "46a39af21695ff230203010001a381af3081ac303f0603551d11043830368634"
+            + "687474703a2f2f7777772e69746c2e6e6973742e676f762f6469763839332f73"
+            + "746166662f706f6c6b2f696e6465782e68746d6c301f0603551d120418301686"
+            + "14687474703a2f2f7777772e6e6973742e676f762f301f0603551d2304183016"
+            + "80140868af8533c8394a7af882938e706a4a20842c3230170603551d20041030"
+            + "0e300c060a60864801650302013009300e0603551d0f0101ff04040302078030"
+            + "0d06092a864886f70d0101050500038181008e8e3656788bbfa13975172ee310"
+            + "dc832b6834521cf66c1d525e5420105e4ca940f94b729e82b961dceb32a5bdb1"
+            + "b148f99b01bbebaf9b83f6528cb06d7cd09a39543e6d206fcdd0debe275f204f"
+            + "b6ab0df5b7e1bab4dfdf3dd4f6ed01fb6ecb9859ac41fb489c1ff65b46e029e2"
+            + "76ecc43a0afc92c5c0d2a9c9d32952876533");
+
+        /**
+         * This section contains an annotated hex dump of a version 2 CRL with
+         * one extension (cRLNumber). The CRL was issued by OU=NIST; O=gov; C=US
+         * on August 7, 1997; the next scheduled issuance was September 7, 1997.
+         * The CRL includes one revoked certificates: serial number 18 (12 hex),
+         * which was revoked on July 31, 1997 due to keyCompromise.  The CRL
+         * itself is number 18, and it was signed with DSA and SHA-1.
+         */
+        static byte[] crlBin = Hex.Decode(
+            "3081cb30818c020101300906072a8648ce380403302a310b3009060355040613025553310c300a060355040a1303676f76310d300b060355040b13044e495354170d3937303830373030303030305a170d3937303930373030303030305a30223020020112170d3937303733313030303030305a300c300a0603551d1504030a0101a00e300c300a0603551d14040302010c300906072a8648ce380403032f00302c0214224e9f43ba950634f2bb5e65dba68005c03a29470214591a57c982d7022114c3d40b321b9616b11f465a");
+
+        public override void PerformTest()
+        {
+            try
+            {
+                X509CertificateParser certParser = new X509CertificateParser();
+                X509CrlParser crlParser = new X509CrlParser();
+
+                X509Certificate rootCert = certParser.ReadCertificate(rootCertBin);
+                X509Certificate userCert1 = certParser.ReadCertificate(userCert1Bin);
+                X509Certificate userCert2 = certParser.ReadCertificate(userCert2Bin);
+
+                X509Crl crl = crlParser.ReadCrl(crlBin);
+
+                rootCert.Verify(rootCert.GetPublicKey());
+                userCert1.Verify(rootCert.GetPublicKey());
+
+                crl.Verify(rootCert.GetPublicKey());
+
+                if (!crl.IsRevoked(userCert1))
+                {
+                    Fail(this.Name + ": usercert1 not revoked.");
+                }
+
+                if (crl.IsRevoked(userCert2))
+                {
+                    Fail(this.Name + ": usercert2 revoked.");
+                }
+
+            }
+            catch (Exception e)
+            {
+                Fail(this.Name + ": exception - " + e.ToString());
+            }
+        }
+
+		public override String Name
+		{
+			get { return "PkixTest"; }
+        }
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new PkixTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/RSATest.cs b/crypto/test/src/test/RSATest.cs
new file mode 100644
index 000000000..a765ff138
--- /dev/null
+++ b/crypto/test/src/test/RSATest.cs
@@ -0,0 +1,685 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class RsaTest
+		: SimpleTest
+	{
+		/**
+		* a fake random number generator - we just want to make sure the random numbers
+		* aren't random so that we get the same output, while still getting to test the
+		* key generation facilities.
+		*/
+		// TODO Use FixedSecureRandom instead?
+		private class MyFixedSecureRandom
+			: SecureRandom
+		{
+			byte[] seed =
+			{
+				(byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59,
+				(byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4,
+				(byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde,
+				(byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f
+			};
+
+			public override void NextBytes(
+				byte[] bytes)
+			{
+				int offset = 0;
+
+				while ((offset + seed.Length) < bytes.Length)
+				{
+					seed.CopyTo(bytes, offset);
+					offset += seed.Length;
+				}
+
+				Array.Copy(seed, 0, bytes, offset, bytes.Length - offset);
+			}
+		}
+
+		private static readonly byte[] seed =
+		{
+			(byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59,
+			(byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4,
+			(byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde,
+			(byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f
+		};
+
+		private RsaKeyParameters pubKeySpec = new RsaKeyParameters(
+			false,
+			new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+			new BigInteger("11", 16));
+
+		private RsaPrivateCrtKeyParameters privKeySpec = new RsaPrivateCrtKeyParameters(
+			new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16),
+			new BigInteger("11", 16),
+			new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16),
+			new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16),
+			new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16),
+			new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16),
+			new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16),
+			new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16));
+
+		private RsaKeyParameters isoPubKeySpec = new RsaKeyParameters(
+			false,
+			new BigInteger("0100000000000000000000000000000000bba2d15dbb303c8a21c5ebbcbae52b7125087920dd7cdf358ea119fd66fb064012ec8ce692f0a0b8e8321b041acd40b7", 16),
+			new BigInteger("03", 16));
+
+		private RsaKeyParameters isoPrivKeySpec = new RsaKeyParameters(
+			true,
+			new BigInteger("0100000000000000000000000000000000bba2d15dbb303c8a21c5ebbcbae52b7125087920dd7cdf358ea119fd66fb064012ec8ce692f0a0b8e8321b041acd40b7", 16),
+			new BigInteger("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac9f0783a49dd5f6c5af651f4c9d0dc9281c96a3f16a85f9572d7cc3f2d0f25a9dbf1149e4cdc32273faadd3fda5dcda7", 16));
+
+		internal static RsaKeyParameters pub2048KeySpec = new RsaKeyParameters(
+			false,
+			new BigInteger("a7295693155b1813bb84877fb45343556e0568043de5910872a3a518cc11e23e2db74eaf4545068c4e3d258a2718fbacdcc3eafa457695b957e88fbf110aed049a992d9c430232d02f3529c67a3419935ea9b569f85b1bcd37de6b899cd62697e843130ff0529d09c97d813cb15f293751ff56f943fbdabb63971cc7f4f6d5bff1594416b1f5907bde5a84a44f9802ef29b43bda1960f948f8afb8766c1ab80d32eec88ed66d0b65aebe44a6d0b3c5e0ab051aaa1b912fbcc17b8e751ddecc5365b6db6dab0020c3057db4013a51213a5798a3aab67985b0f4d88627a54a0f3f0285fbcb4afdfeb65cb153af66825656d43238b75503231500753f4e421e3c57", 16),
+			new BigInteger("10001", 16));
+
+		internal static RsaPrivateCrtKeyParameters priv2048KeySpec = new RsaPrivateCrtKeyParameters(
+			new BigInteger("a7295693155b1813bb84877fb45343556e0568043de5910872a3a518cc11e23e2db74eaf4545068c4e3d258a2718fbacdcc3eafa457695b957e88fbf110aed049a992d9c430232d02f3529c67a3419935ea9b569f85b1bcd37de6b899cd62697e843130ff0529d09c97d813cb15f293751ff56f943fbdabb63971cc7f4f6d5bff1594416b1f5907bde5a84a44f9802ef29b43bda1960f948f8afb8766c1ab80d32eec88ed66d0b65aebe44a6d0b3c5e0ab051aaa1b912fbcc17b8e751ddecc5365b6db6dab0020c3057db4013a51213a5798a3aab67985b0f4d88627a54a0f3f0285fbcb4afdfeb65cb153af66825656d43238b75503231500753f4e421e3c57", 16),
+			new BigInteger("10001", 16),
+			new BigInteger("65dad56ac7df7abb434e4cb5eeadb16093aa6da7f0033aad3815289b04757d32bfee6ade7749c8e4a323b5050a2fb9e2a99e23469e1ed4ba5bab54336af20a5bfccb8b3424cc6923db2ffca5787ed87aa87aa614cd04cedaebc8f623a2d2063017910f436dff18bb06f01758610787f8b258f0a8efd8bd7de30007c47b2a1031696c7d6523bc191d4d918927a7e0b09584ed205bd2ff4fc4382678df82353f7532b3bbb81d69e3f39070aed3fb64fce032a089e8e64955afa5213a6eb241231bd98d702fba725a9b205952fda186412d9e0d9344d2998c455ad8c2bae85ee672751466d5288304032b5b7e02f7e558c7af82c7fbf58eea0bb4ef0f001e6cd0a9", 16),
+			new BigInteger("d4fd9ac3474fb83aaf832470643609659e511b322632b239b688f3cd2aad87527d6cf652fb9c9ca67940e84789444f2e99b0cb0cfabbd4de95396106c865f38e2fb7b82b231260a94df0e01756bf73ce0386868d9c41645560a81af2f53c18e4f7cdf3d51d80267372e6e0216afbf67f655c9450769cca494e4f6631b239ce1b", 16),
+			new BigInteger("c8eaa0e2a1b3a4412a702bccda93f4d150da60d736c99c7c566fdea4dd1b401cbc0d8c063daaf0b579953d36343aa18b33dbf8b9eae94452490cc905245f8f7b9e29b1a288bc66731a29e1dd1a45c9fd7f8238ff727adc49fff73991d0dc096206b9d3a08f61e7462e2b804d78cb8c5eccdb9b7fbd2ad6a8fea46c1053e1be75", 16),
+			new BigInteger("10edcb544421c0f9e123624d1099feeb35c72a8b34e008ac6fa6b90210a7543f293af4e5299c8c12eb464e70092805c7256e18e5823455ba0f504d36f5ccacac1b7cd5c58ff710f9c3f92646949d88fdd1e7ea5fed1081820bb9b0d2a8cd4b093fecfdb96dabd6e28c3a6f8c186dc86cddc89afd3e403e0fcf8a9e0bcb27af0b", 16),
+			new BigInteger("97fc25484b5a415eaa63c03e6efa8dafe9a1c8b004d9ee6e80548fefd6f2ce44ee5cb117e77e70285798f57d137566ce8ea4503b13e0f1b5ed5ca6942537c4aa96b2a395782a4cb5b58d0936e0b0fa63b1192954d39ced176d71ef32c6f42c84e2e19f9d4dd999c2151b032b97bd22aa73fd8c5bcd15a2dca4046d5acc997021", 16),
+			new BigInteger("4bb8064e1eff7e9efc3c4578fcedb59ca4aef0993a8312dfdcb1b3decf458aa6650d3d0866f143cbf0d3825e9381181170a0a1651eefcd7def786b8eb356555d9fa07c85b5f5cbdd74382f1129b5e36b4166b6cc9157923699708648212c484958351fdc9cf14f218dbe7fbf7cbd93a209a4681fe23ceb44bab67d66f45d1c9d", 16));
+
+		public override void PerformTest()
+		{
+			byte[] input = new byte[]
+			{ (byte)0x54, (byte)0x85, (byte)0x9b, (byte)0x34, (byte)0x2c, (byte)0x49, (byte)0xea, (byte)0x2a };
+			byte[][] output = new byte[][]
+			{
+				Hex.Decode("8b427f781a2e59dd9def386f1956b996ee07f48c96880e65a368055ed8c0a8831669ef7250b40918b2b1d488547e72c84540e42bd07b03f14e226f04fbc2d929"),
+				Hex.Decode("2ec6e1a1711b6c7b8cd3f6a25db21ab8bb0a5f1d6df2ef375fa708a43997730ffc7c98856dbbe36edddcdd1b2d2a53867d8355af94fea3aeec128da908e08f4c"),
+				Hex.Decode("0850ac4e5a8118323200c8ed1e5aaa3d5e635172553ccac66a8e4153d35c79305c4440f11034ab147fccce21f18a50cf1c0099c08a577eb68237a91042278965"),
+				Hex.Decode("1c9649bdccb51056751fe43837f4eb43bada472accf26f65231666d5de7d11950d8379b3596dfdf75c6234274896fa8d18ad0865d3be2ac4d6687151abdf01e93941dcef18fa63186c9351d1506c89d09733c5ff4304208c812bdd21a50f56fde115e629e0e973721c9fcc87e89295a79853dee613962a0b2f2fc57163fd99057a3c776f13c20c26407eb8863998d7e53b543ba8d0a295a9a68d1a149833078c9809ad6a6dad7fc22a95ad615a73138c54c018f40d99bf8eeecd45f5be526f2d6b01aeb56381991c1ab31a2e756f15e052b9cd5638b2eff799795c5bae493307d5eb9f8c21d438de131fe505a4e7432547ab19224094f9e4be1968bd0793b79d"),
+				Hex.Decode("4c4afc0c24dddaedd4f9a3b23be30d35d8e005ffd36b3defc5d18acc830c3ed388ce20f43a00e614fd087c814197bc9fc2eff9ad4cc474a7a2ef3ed9c0f0a55eb23371e41ee8f2e2ed93ea3a06ca482589ab87e0d61dcffda5eea1241408e43ea1108726cdb87cc3aa5e9eaaa9f72507ca1352ac54a53920c94dccc768147933d8c50aefd9d1da10522a40133cd33dbc0524669e70f771a88d65c4716d471cd22b08b9f01f24e4e9fc7ffbcfa0e0a7aed47b345826399b26a73be112eb9c5e06fc6742fc3d0ef53d43896403c5105109cfc12e6deeaf4a48ba308e039774b9bdb31a9b9e133c81c321630cf0b4b2d1f90717b24c3268e1fea681ea9cdc709342"),
+				Hex.Decode("06b5b26bd13515f799e5e37ca43cace15cd82fd4bf36b25d285a6f0998d97c8cb0755a28f0ae66618b1cd03e27ac95eaaa4882bc6dc0078cd457d4f7de4154173a9c7a838cfc2ac2f74875df462aae0cfd341645dc51d9a01da9bdb01507f140fa8a016534379d838cc3b2a53ac33150af1b242fc88013cb8d914e66c8182864ee6de88ce2879d4c05dd125409620a96797c55c832fb2fb31d4310c190b8ed2c95fdfda2ed87f785002faaec3f35ec05cf70a3774ce185e4882df35719d582dd55ac31257344a9cba95189dcbea16e8c6cb7a235a0384bc83b6183ca8547e670fe33b1b91725ae0c250c9eca7b5ba78bd77145b70270bf8ac31653006c02ca9c"),
+				Hex.Decode("135f1be3d045526235bf9d5e43499d4ee1bfdf93370769ae56e85dbc339bc5b7ea3bee49717497ee8ac3f7cd6adb6fc0f17812390dcd65ac7b87fef7970d9ff9"),
+				Hex.Decode("03c05add1e030178c352face07cafc9447c8f369b8f95125c0d311c16b6da48ca2067104cce6cd21ae7b163cd18ffc13001aecebdc2eb02b9e92681f84033a98"),
+				Hex.Decode("00319bb9becb49f3ed1bca26d0fcf09b0b0a508e4d0bd43b350f959b72cd25b3af47d608fdcd248eada74fbe19990dbeb9bf0da4b4e1200243a14e5cab3f7e610c")
+			};
+			SecureRandom rand = new MyFixedSecureRandom();
+
+//			KeyFactory fact = KeyFactory.GetInstance("RSA");
+//
+//			PrivateKey  privKey = fact.generatePrivate(privKeySpec);
+//			PublicKey   pubKey = fact.generatePublic(pubKeySpec);
+			AsymmetricKeyParameter privKey = privKeySpec;
+			AsymmetricKeyParameter pubKey = pubKeySpec;
+
+//			PrivateKey  priv2048Key = fact.generatePrivate(priv2048KeySpec);
+//			PublicKey   pub2048Key = fact.generatePublic(pub2048KeySpec);
+			AsymmetricKeyParameter priv2048Key = priv2048KeySpec;
+			AsymmetricKeyParameter pub2048Key = pub2048KeySpec;
+
+			//
+			// No Padding
+			//
+//			Cipher c = Cipher.GetInstance("RSA");
+			IBufferedCipher c = CipherUtilities.GetCipher("RSA");
+
+//			c.init(Cipher.ENCRYPT_MODE, pubKey, rand);
+			c.Init(true, pubKey);// new ParametersWithRandom(pubKey, rand));
+
+			byte[] outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[0]))
+			{
+				Fail("NoPadding test failed on encrypt expected " + Hex.ToHexString(output[0]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+//			c.init(Cipher.DECRYPT_MODE, privKey);
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("NoPadding test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			//
+			// No Padding - incremental
+			//
+//			c = Cipher.GetInstance("RSA");
+			c = CipherUtilities.GetCipher("RSA");
+
+//			c.init(Cipher.ENCRYPT_MODE, pubKey, rand);
+			c.Init(true, pubKey);// new ParametersWithRandom(pubKey, rand));
+
+			c.ProcessBytes(input);
+
+			outBytes = c.DoFinal();
+
+			if (!AreEqual(outBytes, output[0]))
+			{
+				Fail("NoPadding test failed on encrypt expected " + Hex.ToHexString(output[0]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+//			c.init(Cipher.DECRYPT_MODE, privKey);
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("NoPadding test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			//
+			// No Padding - incremental - explicit use of NONE in mode.
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/NoPadding");
+
+//			c.init(Cipher.ENCRYPT_MODE, pubKey, rand);
+			c.Init(true, pubKey);// new ParametersWithRandom(pubKey, rand));
+			
+			c.ProcessBytes(input);
+
+			outBytes = c.DoFinal();
+
+			if (!AreEqual(outBytes, output[0]))
+			{
+				Fail("NoPadding test failed on encrypt expected " + Hex.ToHexString(output[0]) + " got " + Hex.ToHexString(outBytes));
+			}
+			
+//			c.init(Cipher.DECRYPT_MODE, privKey);
+			c.Init(false, privKey);
+			
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("NoPadding test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			//
+			// No Padding - maximum.Length
+			//
+			c = CipherUtilities.GetCipher("RSA");
+
+			byte[] modBytes = ((RsaKeyParameters) pubKey).Modulus.ToByteArray();
+
+			byte[] maxInput = new byte[modBytes.Length - 1];
+
+			maxInput[0] |= 0x7f;
+
+			c.Init(true, pubKey);// new ParametersWithRandom(pubKey, rand));
+
+			outBytes = c.DoFinal(maxInput);
+
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, maxInput))
+			{
+				Fail("NoPadding test failed on decrypt expected "
+					+ Hex.ToHexString(maxInput) + " got "
+					+ Hex.ToHexString(outBytes));
+			}
+
+			//
+			// PKCS1 V 1.5
+			//
+			c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
+
+			c.Init(true, new ParametersWithRandom(pubKey, rand));
+
+			outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[1]))
+			{
+				Fail("PKCS1 test failed on encrypt expected " + Hex.ToHexString(output[1]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("PKCS1 test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			//
+			// PKCS1 V 1.5 - NONE
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/PKCS1Padding");
+
+			c.Init(true, new ParametersWithRandom(pubKey, rand));
+
+			outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[1]))
+			{
+				Fail("PKCS1 test failed on encrypt expected " + Hex.ToHexString(output[1]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("PKCS1 test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+			
+			//
+			// OAEP - SHA1
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPPadding");
+
+			c.Init(true, new ParametersWithRandom(pubKey, rand));
+
+			outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[2]))
+			{
+				Fail("OAEP test failed on encrypt expected " + Hex.ToHexString(output[2]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPWithSHA1AndMGF1Padding");
+
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("OAEP test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+	        // TODO
+//			AlgorithmParameters oaepP = c.getParameters();
+	        byte[] rop = new RsaesOaepParameters(
+					new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance),
+					new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance)),
+					new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]))).GetEncoded();
+
+//			if (!AreEqual(oaepP.getEncoded(), rop.getEncoded()))
+//			{
+//				Fail("OAEP test failed default sha-1 parameters");
+//			}
+
+			//
+			// OAEP - SHA224
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPWithSHA224AndMGF1Padding");
+
+			c.Init(true, new ParametersWithRandom(pub2048Key, rand));
+
+			outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[3]))
+			{
+				Fail("OAEP SHA-224 test failed on encrypt expected " + Hex.ToHexString(output[2]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c.Init(false, priv2048Key);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("OAEP SHA-224 test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+//			oaepP = c.getParameters();
+			rop = new RsaesOaepParameters(
+				new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance)),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]))).GetEncoded();
+
+//			if (!AreEqual(oaepP.getEncoded(), rop.getEncoded())
+//			{
+//				Fail("OAEP test failed default sha-224 parameters");
+//			}
+
+			//
+			// OAEP - SHA 256
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPWithSHA256AndMGF1Padding");
+
+			c.Init(true, new ParametersWithRandom(pub2048Key, rand));
+
+			outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[4]))
+			{
+				Fail("OAEP SHA-256 test failed on encrypt expected " + Hex.ToHexString(output[2]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c.Init(false, priv2048Key);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("OAEP SHA-256 test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+//			oaepP = c.getParameters();
+			rop = new RsaesOaepParameters(
+				new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance)),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]))).GetEncoded();
+
+//			if (!AreEqual(oaepP.getEncoded(), rop.getEncoded())
+//			{
+//				Fail("OAEP test failed default sha-256 parameters");
+//			}
+
+			//
+			// OAEP - SHA 384
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPWithSHA384AndMGF1Padding");
+
+			c.Init(true, new ParametersWithRandom(pub2048Key, rand));
+
+			outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[5]))
+			{
+				Fail("OAEP SHA-384 test failed on encrypt expected " + Hex.ToHexString(output[2]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c.Init(false, priv2048Key);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("OAEP SHA-384 test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+//			oaepP = c.getParameters();
+			rop = new RsaesOaepParameters(
+				new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance)),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]))).GetEncoded();
+
+//			if (!AreEqual(oaepP.getEncoded(), rop.getEncoded())
+//			{
+//				Fail("OAEP test failed default sha-384 parameters");
+//			}
+
+			//
+			// OAEP - MD5
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPWithMD5AndMGF1Padding");
+
+			c.Init(true, new ParametersWithRandom(pubKey, rand));
+
+			outBytes = c.DoFinal(input);
+
+			if (!AreEqual(outBytes, output[6]))
+			{
+				Fail("OAEP MD5 test failed on encrypt expected " + Hex.ToHexString(output[2]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("OAEP MD5 test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+//			oaepP = c.getParameters();
+			rop = new RsaesOaepParameters(
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.MD5, DerNull.Instance),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(PkcsObjectIdentifiers.MD5, DerNull.Instance)),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]))).GetEncoded();
+
+//			if (!AreEqual(oaepP.getEncoded(), rop.getEncoded())
+//			{
+//				Fail("OAEP test failed default md5 parameters");
+//			}
+
+			//
+			// OAEP - SHA1 with default parameters
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPPadding");
+
+			// TODO
+//			c.init(Cipher.ENCRYPT_MODE, pubKey, OAEPParameterSpec.DEFAULT, rand);
+//
+//			outBytes = c.DoFinal(input);
+//
+//			if (!AreEqual(outBytes, output[2]))
+//			{
+//				Fail("OAEP test failed on encrypt expected " + Encoding.ASCII.GetString(Hex.Encode(output[2])) + " got " + Encoding.ASCII.GetString(Hex.Encode(outBytes)));
+//			}
+//
+//			c = CipherUtilities.GetCipher("RSA/NONE/OAEPWithSHA1AndMGF1Padding");
+//
+//			c.Init(false, privKey);
+//
+//			outBytes = c.DoFinal(outBytes);
+//
+//			if (!AreEqual(outBytes, input))
+//			{
+//				Fail("OAEP test failed on decrypt expected " + Encoding.ASCII.GetString(Hex.Encode(input)) + " got " + Encoding.ASCII.GetString(Hex.Encode(outBytes)));
+//			}
+//
+//			oaepP = c.getParameters();
+//
+//			if (!AreEqual(oaepP.getEncoded(), new byte[] { 0x30, 0x00 }))
+//			{
+//				Fail("OAEP test failed default parameters");
+//			}
+
+			//
+			// OAEP - SHA1 with specified string
+			//
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPPadding");
+
+			// TODO
+//			c.init(Cipher.ENCRYPT_MODE, pubKey, new OAEPParameterSpec("SHA1", "MGF1", new MGF1ParameterSpec("SHA1"), new PSource.PSpecified(new byte[] { 1, 2, 3, 4, 5 })), rand);
+//
+//			outBytes = c.DoFinal(input);
+//
+//			oaepP = c.getParameters();
+			rop = new RsaesOaepParameters(
+				new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance)),
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[] { 1, 2, 3, 4, 5 }))).GetEncoded();
+
+//			if (!AreEqual(oaepP.getEncoded())
+//			{
+//				Fail("OAEP test failed changed sha-1 parameters");
+//			}
+//
+//			if (!AreEqual(outBytes, output[7]))
+//			{
+//				Fail("OAEP test failed on encrypt expected " + Encoding.ASCII.GetString(Hex.Encode(output[2])) + " got " + Encoding.ASCII.GetString(Hex.Encode(outBytes)));
+//			}
+
+			c = CipherUtilities.GetCipher("RSA/NONE/OAEPWithSHA1AndMGF1Padding");
+
+	        // TODO
+//			c.init(Cipher.DECRYPT_MODE, privKey, oaepP);
+//
+//			outBytes = c.DoFinal(outBytes);
+//
+//			if (!AreEqual(outBytes, input))
+//			{
+//				Fail("OAEP test failed on decrypt expected " + Encoding.ASCII.GetString(Hex.Encode(input)) + " got " + Encoding.ASCII.GetString(Hex.Encode(outBytes)));
+//			}
+
+			//
+			// iso9796-1
+			//
+			byte[] isoInput =  Hex.Decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210");
+//			PrivateKey  isoPrivKey = fact.generatePrivate(isoPrivKeySpec);
+//			PublicKey   isoPubKey = fact.generatePublic(isoPubKeySpec);
+			AsymmetricKeyParameter isoPrivKey = isoPrivKeySpec;
+			AsymmetricKeyParameter isoPubKey = isoPubKeySpec;
+
+			c = CipherUtilities.GetCipher("RSA/NONE/ISO9796-1Padding");
+
+			c.Init(true, isoPrivKey);
+
+			outBytes = c.DoFinal(isoInput);
+
+			if (!AreEqual(outBytes, output[8]))
+			{
+				Fail("ISO9796-1 test failed on encrypt expected " + Hex.ToHexString(output[3]) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			c.Init(false, isoPubKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, isoInput))
+			{
+				Fail("ISO9796-1 test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			//
+			//
+			// generation with parameters test.
+			//
+			IAsymmetricCipherKeyPairGenerator keyPairGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+
+			//
+			// 768 bit RSA with e = 2^16-1
+			//
+			keyPairGen.Init(
+				new RsaKeyGenerationParameters(
+					BigInteger.ValueOf(0x10001),
+					new SecureRandom(),
+					768,
+					25));
+
+			AsymmetricCipherKeyPair kp = keyPairGen.GenerateKeyPair();
+
+			pubKey = kp.Public;
+			privKey = kp.Private;
+
+			c.Init(true, new ParametersWithRandom(pubKey, rand));
+
+			outBytes = c.DoFinal(input);
+
+			c.Init(false, privKey);
+
+			outBytes = c.DoFinal(outBytes);
+
+			if (!AreEqual(outBytes, input))
+			{
+				Fail("key generation test failed on decrypt expected " + Hex.ToHexString(input) + " got " + Hex.ToHexString(outBytes));
+			}
+
+			//
+			// comparison check
+			//
+//			KeyFactory keyFact = KeyFactory.GetInstance("RSA");
+//
+//			RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)keyFact.translateKey(privKey);
+			RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters) privKey;
+
+			if (!privKey.Equals(crtKey))
+			{
+				Fail("private key equality check failed");
+			}
+
+//			RSAPublicKey copyKey = (RSAPublicKey)keyFact.translateKey(pubKey);
+			RsaKeyParameters copyKey = (RsaKeyParameters) pubKey;
+
+			if (!pubKey.Equals(copyKey))
+			{
+				Fail("public key equality check failed");
+			}
+
+			SecureRandom random = new SecureRandom();
+			rawModeTest("SHA1withRSA", X509ObjectIdentifiers.IdSha1, priv2048Key, pub2048Key, random);
+			rawModeTest("MD5withRSA", PkcsObjectIdentifiers.MD5, priv2048Key, pub2048Key, random);
+			rawModeTest("RIPEMD128withRSA", TeleTrusTObjectIdentifiers.RipeMD128, priv2048Key, pub2048Key, random);
+		}
+		
+		private void rawModeTest(string sigName, DerObjectIdentifier digestOID,
+			AsymmetricKeyParameter privKey, AsymmetricKeyParameter pubKey, SecureRandom random)
+		{
+			byte[] sampleMessage = new byte[1000 + random.Next() % 100];
+			random.NextBytes(sampleMessage);
+
+			ISigner normalSig = SignerUtilities.GetSigner(sigName);
+			normalSig.Init(true, privKey);
+			normalSig.BlockUpdate(sampleMessage, 0, sampleMessage.Length);
+			byte[] normalResult = normalSig.GenerateSignature();
+			
+			byte[] hash = DigestUtilities.CalculateDigest(digestOID.Id, sampleMessage);
+			byte[] digInfo = derEncode(digestOID, hash);
+			
+			ISigner rawSig = SignerUtilities.GetSigner("RSA");
+			rawSig.Init(true, privKey);
+			rawSig.BlockUpdate(digInfo, 0, digInfo.Length);
+			byte[] rawResult = rawSig.GenerateSignature();
+			
+			if (!Arrays.AreEqual(normalResult, rawResult))
+			{
+				Fail("raw mode signature differs from normal one");
+			}
+
+			rawSig.Init(false, pubKey);
+			rawSig.BlockUpdate(digInfo, 0, digInfo.Length);
+
+			if (!rawSig.VerifySignature(rawResult))
+			{
+				Fail("raw mode signature verification failed");
+			}
+		}
+
+		private byte[] derEncode(DerObjectIdentifier oid, byte[] hash)
+		{
+			AlgorithmIdentifier algId = new AlgorithmIdentifier(oid, DerNull.Instance);
+			DigestInfo dInfo = new DigestInfo(algId, hash);
+
+			return dInfo.GetEncoded(Asn1Encodable.Der);
+		}
+		
+		public override string Name
+		{
+			get { return "RSATest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new RsaTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/RegressionTest.cs b/crypto/test/src/test/RegressionTest.cs
new file mode 100644
index 000000000..0ffde72e4
--- /dev/null
+++ b/crypto/test/src/test/RegressionTest.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+    public class RegressionTest
+    {
+		// These tests were ported from org.bouncycastle.jce.provider.test in Java build
+        public static ITest[] tests = new ITest[]
+		{
+			new FipsDesTest(),
+			new DesEdeTest(),
+			new AesTest(),
+			new CamelliaTest(),
+			new SeedTest(),
+			new AesSicTest(),
+			new Gost28147Test(),
+			new PbeTest(),
+			new BlockCipherTest(),
+			new MacTest(),
+			new HMacTest(),
+//			new SealedTest(),
+			new RsaTest(),
+			new DHTest(),
+			new DsaTest(),
+//			new ImplicitlyCaTest(),
+			new ECNRTest(),
+			new ECDsa5Test(),
+			new Gost3410Test(),
+			new ElGamalTest(),
+			new IesTest(),
+			new SigTest(),
+			new AttrCertTest(),
+			new CertTest(),
+			new Pkcs10CertRequestTest(),
+			new EncryptedPrivateKeyInfoTest(),  // Also in Org.BouncyCastle.Pkcs.Tests
+//			new KeyStoreTest(),
+//			new Pkcs12StoreTest(), // Already in Org.BouncyCastle.Pkcs.Tests
+			new DigestTest(),
+			new PssTest(),
+			new WrapTest(),
+//			new DoFinalTest(),
+			new CipherStreamTest(),
+			new NamedCurveTest(),
+			new PkixTest(),
+//			new NetscapeCertRequestTest(),
+			new X509StoreTest(),
+//			new X509StreamParserTest(),
+			new X509CertificatePairTest(),
+			new CertPathTest(),
+//			new CertStoreTest(),
+			new CertPathValidatorTest(),
+			new CertPathBuilderTest(),
+			new ECEncodingTest(),
+//			new AlgorithmParametersTest(),
+			new NistCertPathTest(),
+			new PkixPolicyMappingTest(),
+//			new SlotTwoTest(),
+			new PkixNameConstraintsTest(),
+			new NoekeonTest(),
+			new AttrCertSelectorTest(),
+//			new SerialisationTest(),
+			new MqvTest(),
+			new CMacTest(),
+			new Crl5Test(),
+		};
+
+		public static void Main(
+            string[] args)
+        {
+            for (int i = 0; i != tests.Length; i++)
+            {
+                ITestResult result = tests[i].Perform();
+
+				Console.WriteLine(result);
+            }
+		}
+    }
+}
diff --git a/crypto/test/src/test/SEEDTest.cs b/crypto/test/src/test/SEEDTest.cs
new file mode 100644
index 000000000..2b380d5b7
--- /dev/null
+++ b/crypto/test/src/test/SEEDTest.cs
@@ -0,0 +1,190 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Tests
+{
+	/// <summary>Basic test class for SEED</summary>
+	[TestFixture]
+	public class SeedTest
+		: BaseBlockCipherTest
+	{
+		internal static readonly string[] cipherTests =
+		{
+			"128",
+			"28DBC3BC49FFD87DCFA509B11D422BE7",
+			"B41E6BE2EBA84A148E2EED84593C5EC7",
+			"9B9B7BFCD1813CB95D0B3618F40F5122"
+		};
+
+		public SeedTest()
+			: base("SEED")
+		{
+		}
+
+		[Test]
+		public void TestCiphers()
+		{
+			for (int i = 0; i != cipherTests.Length; i += 4)
+			{
+				doCipherTest(int.Parse(cipherTests[i]),
+					Hex.Decode(cipherTests[i + 1]),
+					Hex.Decode(cipherTests[i + 2]),
+					Hex.Decode(cipherTests[i + 3]));
+			}
+		}
+
+		[Test]
+		public void TestWrap()
+		{
+			byte[] kek1 = Hex.Decode("000102030405060708090a0b0c0d0e0f");
+			byte[] in1 = Hex.Decode("00112233445566778899aabbccddeeff");
+			byte[] out1 = Hex.Decode("bf71f77138b5afea05232a8dad54024e812dc8dd7d132559");
+
+			wrapTest(1, "SEEDWrap", kek1, in1, out1);
+		}
+
+		[Test]
+		public void TestOids()
+		{
+			string[] oids = {
+				KisaObjectIdentifiers.IdSeedCbc.Id
+			};
+
+			string[] names = {
+				"SEED/CBC/PKCS7Padding"
+			};
+
+			oidTest(oids, names, 1);
+		}
+
+		[Test]
+		public void TestWrapOids()
+		{
+			string[] wrapOids = {
+				KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap.Id
+			};
+
+			wrapOidTest(wrapOids, "SEEDWrap");
+		}
+
+		public void doCipherTest(
+			int		strength,
+			byte[]	keyBytes,
+			byte[]	input,
+			byte[]	output)
+		{
+			KeyParameter key = ParameterUtilities.CreateKeyParameter("SEED", keyBytes);
+
+			IBufferedCipher inCipher = CipherUtilities.GetCipher("SEED/ECB/NoPadding");
+			IBufferedCipher outCipher = CipherUtilities.GetCipher("SEED/ECB/NoPadding");
+
+			try
+			{
+				outCipher.Init(true, key);
+			}
+			catch (Exception e)
+			{
+				Fail("SEED failed initialisation - " + e.ToString(), e);
+			}
+
+			try
+			{
+				inCipher.Init(false, key);
+			}
+			catch (Exception e)
+			{
+				Fail("SEED failed initialisation - " + e.ToString(), e);
+			}
+
+			//
+			// encryption pass
+			//
+			MemoryStream bOut = new MemoryStream();
+			CipherStream cOut = new CipherStream(bOut, null, outCipher);
+
+			try
+			{
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+					cOut.WriteByte(input[i]);
+				}
+				cOut.Write(input, input.Length / 2, input.Length - input.Length / 2);
+				cOut.Close();
+			}
+			catch (IOException e)
+			{
+				Fail("SEED failed encryption - " + e.ToString(), e);
+			}
+
+			byte[] bytes = bOut.ToArray();
+
+			if (!AreEqual(bytes, output))
+			{
+				Fail("SEED failed encryption - expected "
+					+ Hex.ToHexString(output) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+
+			//
+			// decryption pass
+			//
+			MemoryStream bIn = new MemoryStream(bytes, false);
+			CipherStream cIn = new CipherStream(bIn, inCipher, null);
+
+			try
+			{
+//				DataInputStream dIn = new DataInputStream(cIn);
+				BinaryReader dIn = new BinaryReader(cIn);
+
+				bytes = new byte[input.Length];
+
+				for (int i = 0; i != input.Length / 2; i++)
+				{
+//					bytes[i] = (byte)dIn.read();
+					bytes[i] = dIn.ReadByte();
+				}
+
+				int remaining = bytes.Length - input.Length / 2;
+//				dIn.readFully(bytes, input.Length / 2, remaining);
+				byte[] extra = dIn.ReadBytes(remaining);
+				if (extra.Length < remaining)
+					throw new EndOfStreamException();
+				extra.CopyTo(bytes, input.Length / 2);
+			}
+			catch (Exception e)
+			{
+				Fail("SEED failed encryption - " + e.ToString(), e);
+			}
+
+			if (!AreEqual(bytes, input))
+			{
+				Fail("SEED failed decryption - expected "
+					+ Hex.ToHexString(input) + " got "
+					+ Hex.ToHexString(bytes));
+			}
+		}
+
+		public override void PerformTest()
+		{
+			TestCiphers();
+			TestWrap();
+			TestOids();
+			TestWrapOids();
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SeedTest());
+		}
+	}
+}
diff --git a/crypto/test/src/test/SigTest.cs b/crypto/test/src/test/SigTest.cs
new file mode 100644
index 000000000..803a24493
--- /dev/null
+++ b/crypto/test/src/test/SigTest.cs
@@ -0,0 +1,378 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class SigTest
+		: SimpleTest
+	{
+		/**
+		 * signature with a "forged signature" (sig block not at end of plain text)
+		 */
+		private void doTestBadSig(
+			AsymmetricKeyParameter	priv,
+			AsymmetricKeyParameter	pub)
+		{
+			IDigest sha1 = DigestUtilities.GetDigest("SHA1");
+			IBufferedCipher signer = CipherUtilities.GetCipher("RSA//PKCS1Padding");
+
+			signer.Init(true, priv);
+
+			byte[] block = new byte[signer.GetBlockSize()];
+
+			sha1.Update((byte)0);
+
+			byte[] sigHeader = Hex.Decode("3021300906052b0e03021a05000414");
+			Array.Copy(sigHeader, 0, block, 0, sigHeader.Length);
+
+//			byte[] dig = sha1.digest();
+			byte[] dig = DigestUtilities.DoFinal(sha1);
+
+			Array.Copy(dig, 0, block, sigHeader.Length, dig.Length);
+
+			Array.Copy(sigHeader, 0, block,
+				sigHeader.Length + dig.Length, sigHeader.Length);
+
+			byte[] sig = signer.DoFinal(block);
+
+			ISigner verifier = SignerUtilities.GetSigner("SHA1WithRSA");
+
+			verifier.Init(false, pub);
+
+			verifier.Update((byte)0);
+
+			if (verifier.VerifySignature(sig))
+			{
+				Fail("bad signature passed");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
+
+			byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+			IAsymmetricCipherKeyPairGenerator fact = GeneratorUtilities.GetKeyPairGenerator("RSA");
+			fact.Init(
+				new RsaKeyGenerationParameters(
+					BigInteger.ValueOf(0x10001),
+					new SecureRandom(),
+					768,
+					25));
+
+			AsymmetricCipherKeyPair keyPair = fact.GenerateKeyPair();
+
+			AsymmetricKeyParameter signingKey = keyPair.Private;
+			AsymmetricKeyParameter verifyKey = keyPair.Public;
+
+			doTestBadSig(signingKey, verifyKey);
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			byte[] sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("SHA1 verification failed");
+			}
+
+			sig = SignerUtilities.GetSigner("MD2WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("MD2 verification failed");
+			}
+
+			sig = SignerUtilities.GetSigner("MD5WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("MD5 verification failed");
+			}
+
+			sig = SignerUtilities.GetSigner("RIPEMD160WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("RIPEMD160 verification failed");
+			}
+
+			//
+			// RIPEMD-128
+			//
+			sig = SignerUtilities.GetSigner("RIPEMD128WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("RIPEMD128 verification failed");
+			}
+
+			//
+			// RIPEMD256
+			//
+			sig = SignerUtilities.GetSigner("RIPEMD256WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("RIPEMD256 verification failed");
+			}
+
+			//
+			// SHA-224
+			//
+			sig = SignerUtilities.GetSigner("SHA224WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("SHA224 verification failed");
+			}
+
+			//
+			// SHA-256
+			//
+			sig = SignerUtilities.GetSigner("SHA256WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("SHA256 verification failed");
+			}
+
+			//
+			// SHA-384
+			//
+			sig = SignerUtilities.GetSigner("SHA384WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("SHA384 verification failed");
+			}
+
+			//
+			// SHA-512
+			//
+			sig = SignerUtilities.GetSigner("SHA512WithRSAEncryption");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("SHA512 verification failed");
+			}
+
+			//
+			// ISO Sigs.
+			//
+			sig = SignerUtilities.GetSigner("MD5WithRSA/ISO9796-2");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("MD5/ISO verification failed");
+			}
+
+			sig = SignerUtilities.GetSigner("SHA1WithRSA/ISO9796-2");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("SHA1/ISO verification failed");
+			}
+
+			sig = SignerUtilities.GetSigner("RIPEMD160WithRSA/ISO9796-2");
+
+			sig.Init(true, signingKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			sig.Init(false, verifyKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("RIPEMD160/ISO verification failed");
+			}
+
+			//
+			// standard vector test - B.1.3 RIPEMD160, implicit.
+			//
+			BigInteger  mod = new BigInteger("ffffffff78f6c55506c59785e871211ee120b0b5dd644aa796d82413a47b24573f1be5745b5cd9950f6b389b52350d4e01e90009669a8720bf265a2865994190a661dea3c7828e2e7ca1b19651adc2d5", 16);
+			BigInteger  pub = new BigInteger("03", 16);
+			BigInteger  pri = new BigInteger("2aaaaaaa942920e38120ee965168302fd0301d73a4e60c7143ceb0adf0bf30b9352f50e8b9e4ceedd65343b2179005b2f099915e4b0c37e41314bb0821ad8330d23cba7f589e0f129b04c46b67dfce9d", 16);
+
+//			KeyFactory  f = KeyFactory.getInstance("RSA");
+//			AsymmetricKeyParameter privKey = f.generatePrivate(new RSAPrivateKeySpec(mod, pri));
+//			AsymmetricKeyParameter pubKey = f.generatePublic(new RSAPublicKeySpec(mod, pub));
+			AsymmetricKeyParameter privKey = new RsaKeyParameters(true, mod, pri);
+			AsymmetricKeyParameter pubKey = new RsaKeyParameters(false, mod, pub);
+			byte[] testSig = Hex.Decode("5cf9a01854dbacaec83aae8efc563d74538192e95466babacd361d7c86000fe42dcb4581e48e4feb862d04698da9203b1803b262105104d510b365ee9c660857ba1c001aa57abfd1c8de92e47c275cae");
+
+			data = Hex.Decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210");
+
+			sig = SignerUtilities.GetSigner("RIPEMD160WithRSA/ISO9796-2");
+
+			sig.Init(true, privKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			sigBytes = sig.GenerateSignature();
+
+			if (!AreEqual(testSig, sigBytes))
+			{
+				Fail("SigTest: failed ISO9796-2 generation Test");
+			}
+
+			sig.Init(false, pubKey);
+
+			sig.BlockUpdate(data, 0, data.Length);
+
+			if (!sig.VerifySignature(sigBytes))
+			{
+				Fail("RIPEMD160/ISO verification failed");
+			}
+		}
+
+		public override string Name
+		{
+			get { return "SigTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new SigTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/TestUtilities.cs b/crypto/test/src/test/TestUtilities.cs
new file mode 100644
index 000000000..a79421207
--- /dev/null
+++ b/crypto/test/src/test/TestUtilities.cs
@@ -0,0 +1,264 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+
+namespace Org.BouncyCastle.Tests
+{
+	/**
+	 * Test Utils
+	 */
+	internal class TestUtilities
+	{
+		/**
+		 * Create a random 1024 bit RSA key pair
+		 */
+		public static AsymmetricCipherKeyPair GenerateRsaKeyPair()
+		{
+			IAsymmetricCipherKeyPairGenerator kpGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
+
+			kpGen.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
+
+			return kpGen.GenerateKeyPair();
+		}
+
+		public static X509Certificate GenerateRootCert(
+			AsymmetricCipherKeyPair pair)
+		{
+			X509V1CertificateGenerator  certGen = new X509V1CertificateGenerator();
+
+			certGen.SetSerialNumber(BigInteger.One);
+			certGen.SetIssuerDN(new X509Name("CN=Test CA Certificate"));
+			certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+			certGen.SetSubjectDN(new X509Name("CN=Test CA Certificate"));
+			certGen.SetPublicKey(pair.Public);
+			certGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+			return certGen.Generate(pair.Private);
+		}
+
+		public static X509Certificate GenerateIntermediateCert(
+			AsymmetricKeyParameter	intKey,
+			AsymmetricKeyParameter	caKey,
+			X509Certificate			caCert)
+		{
+			X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+			certGen.SetSerialNumber(BigInteger.One);
+			certGen.SetIssuerDN(PrincipalUtilities.GetSubjectX509Principal(caCert));
+			certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+			certGen.SetSubjectDN(new X509Name("CN=Test Intermediate Certificate"));
+			certGen.SetPublicKey(intKey);
+			certGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+			certGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert));
+			certGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(intKey));
+			certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(0));
+			certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyCertSign | KeyUsage.CrlSign));
+
+			return certGen.Generate(caKey);
+		}
+
+		public static X509Certificate GenerateEndEntityCert(
+			AsymmetricKeyParameter entityKey,
+			AsymmetricKeyParameter caKey,
+			X509Certificate caCert)
+		{
+			X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+			certGen.SetSerialNumber(BigInteger.One);
+			certGen.SetIssuerDN(PrincipalUtilities.GetSubjectX509Principal(caCert));
+			certGen.SetNotBefore(DateTime.UtcNow.AddSeconds(-50));
+			certGen.SetNotAfter(DateTime.UtcNow.AddSeconds(50));
+			certGen.SetSubjectDN(new X509Name("CN=Test End Certificate"));
+			certGen.SetPublicKey(entityKey);
+			certGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+			certGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert));
+			certGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(entityKey));
+			certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
+			certGen.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment));
+
+			return certGen.Generate(caKey);
+		}
+
+		public static X509Crl CreateCrl(
+			X509Certificate			caCert, 
+			AsymmetricKeyParameter	caKey, 
+			BigInteger				serialNumber)
+		{
+			X509V2CrlGenerator	crlGen = new X509V2CrlGenerator();
+			DateTime			now = DateTime.UtcNow;
+//			BigInteger			revokedSerialNumber = BigInteger.Two;
+
+			crlGen.SetIssuerDN(PrincipalUtilities.GetSubjectX509Principal(caCert));
+
+			crlGen.SetThisUpdate(now);
+			crlGen.SetNextUpdate(now.AddSeconds(100));
+			crlGen.SetSignatureAlgorithm("SHA256WithRSAEncryption");
+
+			crlGen.AddCrlEntry(serialNumber, now, CrlReason.PrivilegeWithdrawn);
+
+			crlGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert));
+			crlGen.AddExtension(X509Extensions.CrlNumber, false, new CrlNumber(BigInteger.One));
+
+			return crlGen.Generate(caKey);
+		}
+
+		public static X509Certificate CreateExceptionCertificate(
+			bool exceptionOnEncode)
+		{
+			return new ExceptionCertificate(exceptionOnEncode);
+		}
+
+		private class ExceptionCertificate
+			: X509Certificate
+		{
+			private bool _exceptionOnEncode;
+
+			public ExceptionCertificate(
+				bool exceptionOnEncode)
+			{
+				_exceptionOnEncode = exceptionOnEncode;
+			}
+
+			public override void CheckValidity()
+			{
+				throw new CertificateNotYetValidException();
+			}
+
+			public override void CheckValidity(
+				DateTime date)
+			{
+				throw new CertificateExpiredException();
+			}
+
+			public override int Version
+			{
+				get { return 0; }
+			}
+
+			public override BigInteger SerialNumber
+			{
+				get { return null; }
+			}
+
+			public override X509Name IssuerDN
+			{
+				get { return null; }
+			}
+
+			public override X509Name SubjectDN
+			{
+				get { return null; }
+			}
+
+			public override DateTime NotBefore
+			{
+				get { return DateTime.MaxValue; }
+			}
+
+			public override DateTime NotAfter
+			{
+				get { return DateTime.MinValue; }
+			}
+
+			public override byte[] GetTbsCertificate()
+			{
+				throw new CertificateEncodingException();
+			}
+
+			public override byte[] GetSignature()
+			{
+				return new byte[0];
+			}
+
+			public override string SigAlgName
+			{
+				get { return null; }
+			}
+
+			public override string SigAlgOid
+			{
+				get { return null; }
+			}
+
+			public override byte[] GetSigAlgParams()
+			{
+				return new byte[0];
+			}
+
+			public override DerBitString IssuerUniqueID
+			{
+				get { return null; }
+			}
+
+			public override DerBitString SubjectUniqueID
+			{
+				get { return null; }
+			}
+
+			public override bool[] GetKeyUsage()
+			{
+				return new bool[0];
+			}
+
+			public override int GetBasicConstraints()
+			{
+				return 0;
+			}
+
+			public override byte[] GetEncoded()
+			{
+				if (_exceptionOnEncode)
+				{
+					throw new CertificateEncodingException();
+				}
+
+				return new byte[0];
+			}
+
+			public override void Verify(
+				AsymmetricKeyParameter key)
+			{
+				throw new CertificateException();
+			}
+
+			public override string ToString()
+			{
+				return null;
+			}
+
+			public override AsymmetricKeyParameter GetPublicKey()
+			{
+				return null;
+			}
+
+			public override ISet GetCriticalExtensionOids()
+			{
+				return null;
+			}
+
+			public override ISet GetNonCriticalExtensionOids()
+			{
+				return null;
+			}
+
+			public override Asn1OctetString GetExtensionValue(
+				DerObjectIdentifier oid)
+			{
+				return null;
+			}
+		}
+	}
+}
diff --git a/crypto/test/src/test/WrapTest.cs b/crypto/test/src/test/WrapTest.cs
new file mode 100644
index 000000000..bb49446e7
--- /dev/null
+++ b/crypto/test/src/test/WrapTest.cs
@@ -0,0 +1,94 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class WrapTest
+		: ITest
+	{
+		public ITestResult Perform()
+		{
+			try
+			{
+//				IBufferedCipher cipher = CipherUtilities.GetCipher("DES/ECB/PKCS5Padding");
+				IWrapper cipher = WrapperUtilities.GetWrapper("DES/ECB/PKCS5Padding");
+
+				IAsymmetricCipherKeyPairGenerator fact = GeneratorUtilities.GetKeyPairGenerator("RSA");
+				fact.Init(
+					new RsaKeyGenerationParameters(
+						BigInteger.ValueOf(0x10001),
+						new SecureRandom(),
+						512,
+						25));
+
+				AsymmetricCipherKeyPair keyPair = fact.GenerateKeyPair();
+
+				AsymmetricKeyParameter priKey = keyPair.Private;
+				AsymmetricKeyParameter pubKey = keyPair.Public;
+
+				byte[] priKeyBytes = PrivateKeyInfoFactory.CreatePrivateKeyInfo(priKey).GetDerEncoded();
+
+				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator("DES");
+
+//				Key wrapKey = keyGen.generateKey();
+				byte[] wrapKeyBytes = keyGen.GenerateKey();
+				KeyParameter wrapKey = new DesParameters(wrapKeyBytes);
+
+//				cipher.Init(IBufferedCipher.WRAP_MODE, wrapKey);
+				cipher.Init(true, wrapKey);
+//				byte[] wrappedKey = cipher.Wrap(priKey);
+				byte[] wrappedKey = cipher.Wrap(priKeyBytes, 0, priKeyBytes.Length);
+
+//				cipher.Init(IBufferedCipher.UNWRAP_MODE, wrapKey);
+				cipher.Init(false, wrapKey);
+
+//				Key key = cipher.unwrap(wrappedKey, "RSA", IBufferedCipher.PRIVATE_KEY);
+				byte[] unwrapped = cipher.Unwrap(wrappedKey, 0, wrappedKey.Length);
+
+				//if (!Arrays.AreEqual(priKey.getEncoded(), key.getEncoded()))
+				if (!Arrays.AreEqual(priKeyBytes, unwrapped))
+				{
+					return new SimpleTestResult(false, "Unwrapped key does not match");
+				}
+
+				return new SimpleTestResult(true, Name + ": Okay");
+			}
+			catch (Exception e)
+			{
+				return new SimpleTestResult(false, Name + ": exception - " + e.ToString());
+			}
+		}
+
+		public string Name
+		{
+			get { return "WrapTest"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			ITest test = new WrapTest();
+			ITestResult result = test.Perform();
+
+			Console.WriteLine(result);
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/X509CertificatePairTest.cs b/crypto/test/src/test/X509CertificatePairTest.cs
new file mode 100644
index 000000000..a83de4cf0
--- /dev/null
+++ b/crypto/test/src/test/X509CertificatePairTest.cs
@@ -0,0 +1,149 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class X509CertificatePairTest
+		: SimpleTest
+	{
+		public override void PerformTest()
+		{
+			//CertificateFactory cf = CertificateFactory.getInstance("X.509");
+			X509CertificateParser cf = new X509CertificateParser();
+
+			X509Certificate rootCert = (X509Certificate) cf.ReadCertificate(CertPathTest.rootCertBin);
+			X509Certificate interCert = (X509Certificate) cf.ReadCertificate(CertPathTest.interCertBin);
+			X509Certificate finalCert = (X509Certificate) cf.ReadCertificate(CertPathTest.finalCertBin);
+
+			X509CertificatePair pair1 = new X509CertificatePair(rootCert, interCert);
+			X509CertificatePair pair2 = new X509CertificatePair(rootCert, interCert);
+			X509CertificatePair pair3 = new X509CertificatePair(interCert, finalCert);
+			X509CertificatePair pair4 = new X509CertificatePair(rootCert, finalCert);
+			X509CertificatePair pair5 = new X509CertificatePair(rootCert, null);
+			X509CertificatePair pair6 = new X509CertificatePair(rootCert, null);
+			X509CertificatePair pair7 = new X509CertificatePair(null, rootCert);
+			X509CertificatePair pair8 = new X509CertificatePair(null, rootCert);
+
+			if (!pair1.Equals(pair2))
+			{
+				Fail("pair1 pair2 equality test");
+			}
+
+			if (!pair5.Equals(pair6))
+			{
+				Fail("pair1 pair2 equality test");
+			}
+
+			if (!pair7.Equals(pair8))
+			{
+				Fail("pair1 pair2 equality test");
+			}
+
+			if (pair1.Equals(null))
+			{
+				Fail("pair1 null equality test");
+			}
+
+			if (pair1.GetHashCode() != pair2.GetHashCode())
+			{
+				Fail("pair1 pair2 hashCode equality test");
+			}
+
+			if (pair1.Equals(pair3))
+			{
+				Fail("pair1 pair3 inequality test");
+			}
+
+			if (pair1.Equals(pair4))
+			{
+				Fail("pair1 pair4 inequality test");
+			}
+
+			if (pair1.Equals(pair5))
+			{
+				Fail("pair1 pair5 inequality test");
+			}
+
+			if (pair1.Equals(pair7))
+			{
+				Fail("pair1 pair7 inequality test");
+			}
+
+			if (pair5.Equals(pair1))
+			{
+				Fail("pair5 pair1 inequality test");
+			}
+
+			if (pair7.Equals(pair1))
+			{
+				Fail("pair7 pair1 inequality test");
+			}
+
+			if (pair1.Forward != rootCert)
+			{
+				Fail("pair1 forward test");
+			}
+
+			if (pair1.Reverse != interCert)
+			{
+				Fail("pair1 reverse test");
+			}
+
+			if (!AreEqual(pair1.GetEncoded(), pair2.GetEncoded()))
+			{
+				Fail("encoding check");
+			}
+
+			pair4 = new X509CertificatePair(rootCert, TestUtilities.CreateExceptionCertificate(false));
+
+			try
+			{
+				pair4.GetEncoded();
+
+				Fail("no exception on bad GetEncoded()");
+			}
+			catch (CertificateEncodingException)
+			{
+				// expected
+			}
+
+			pair4 = new X509CertificatePair(rootCert, TestUtilities.CreateExceptionCertificate(true));
+
+			try
+			{
+				pair4.GetEncoded();
+
+				Fail("no exception on exception GetEncoded()");
+			}
+			catch (CertificateEncodingException)
+			{
+				// expected
+			}
+		}
+
+		public override string Name
+		{
+			get { return "X509CertificatePair"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new X509CertificatePairTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/X509StoreTest.cs b/crypto/test/src/test/X509StoreTest.cs
new file mode 100644
index 000000000..37673b8b4
--- /dev/null
+++ b/crypto/test/src/test/X509StoreTest.cs
@@ -0,0 +1,335 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests
+{
+	[TestFixture]
+	public class X509StoreTest
+		: SimpleTest
+	{
+		private void certPairTest()
+		{
+			X509CertificateParser certParser = new X509CertificateParser();
+
+			X509Certificate rootCert = certParser.ReadCertificate(CertPathTest.rootCertBin);
+			X509Certificate interCert = certParser.ReadCertificate(CertPathTest.interCertBin);
+			X509Certificate finalCert = certParser.ReadCertificate(CertPathTest.finalCertBin);
+
+			// Testing CollectionCertStore generation from List
+			X509CertificatePair pair1 = new X509CertificatePair(rootCert, interCert);
+
+			IList certList = new ArrayList();
+			certList.Add(pair1);
+			certList.Add(new X509CertificatePair(interCert, finalCert));
+
+			IX509Store certStore = X509StoreFactory.Create(
+				"CertificatePair/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			X509CertPairStoreSelector selector = new X509CertPairStoreSelector();
+			X509CertStoreSelector fwSelector = new X509CertStoreSelector();
+
+			fwSelector.SerialNumber = rootCert.SerialNumber;
+			fwSelector.Subject = rootCert.IssuerDN;
+
+			selector.ForwardSelector = fwSelector;
+
+			IList col = new ArrayList(certStore.GetMatches(selector));
+
+			if (col.Count != 1 || !col.Contains(pair1))
+			{
+				Fail("failed pair1 test");
+			}
+
+			col = new ArrayList(certStore.GetMatches(null));
+
+			if (col.Count != 2)
+			{
+				Fail("failed null test");
+			}
+		}
+
+		public override void PerformTest()
+		{
+			X509CertificateParser certParser = new X509CertificateParser();
+			X509CrlParser crlParser = new X509CrlParser();
+
+			X509Certificate rootCert = certParser.ReadCertificate(CertPathTest.rootCertBin);
+			X509Certificate interCert = certParser.ReadCertificate(CertPathTest.interCertBin);
+			X509Certificate finalCert = certParser.ReadCertificate(CertPathTest.finalCertBin);
+			X509Crl rootCrl = crlParser.ReadCrl(CertPathTest.rootCrlBin);
+			X509Crl interCrl = crlParser.ReadCrl(CertPathTest.interCrlBin);
+
+			// Testing CollectionCertStore generation from List
+			IList certList = new ArrayList();
+			certList.Add(rootCert);
+			certList.Add(interCert);
+			certList.Add(finalCert);
+
+			IX509Store certStore = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+			// set default to be the same as for SUN X500 name
+			X509Name.DefaultReverse = true;
+
+			// Searching for rootCert by subjectDN
+
+			X509CertStoreSelector targetConstraints = new X509CertStoreSelector();
+			targetConstraints.Subject = PrincipalUtilities.GetSubjectX509Principal(rootCert);
+			IList certs = new ArrayList(certStore.GetMatches(targetConstraints));
+			if (certs.Count != 1 || !certs.Contains(rootCert))
+			{
+				Fail("rootCert not found by subjectDN");
+			}
+
+			// Searching for rootCert by subjectDN encoded as byte
+			targetConstraints = new X509CertStoreSelector();
+			targetConstraints.Subject = PrincipalUtilities.GetSubjectX509Principal(rootCert);
+			certs = new ArrayList(certStore.GetMatches(targetConstraints));
+			if (certs.Count != 1 || !certs.Contains(rootCert))
+			{
+				Fail("rootCert not found by encoded subjectDN");
+			}
+
+			X509Name.DefaultReverse = false;
+
+			// Searching for rootCert by public key encoded as byte
+			targetConstraints = new X509CertStoreSelector();
+			targetConstraints.SubjectPublicKey =
+				SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rootCert.GetPublicKey());
+			certs = new ArrayList(certStore.GetMatches(targetConstraints));
+			if (certs.Count != 1 || !certs.Contains(rootCert))
+			{
+				Fail("rootCert not found by encoded public key");
+			}
+
+			// Searching for interCert by issuerDN
+			targetConstraints = new X509CertStoreSelector();
+			targetConstraints.Issuer = PrincipalUtilities.GetSubjectX509Principal(rootCert);
+			certs = new ArrayList(certStore.GetMatches(targetConstraints));
+			if (certs.Count != 2)
+			{
+				Fail("did not found 2 certs");
+			}
+			if (!certs.Contains(rootCert))
+			{
+				Fail("rootCert not found");
+			}
+			if (!certs.Contains(interCert))
+			{
+				Fail("interCert not found");
+			}
+
+			// Searching for rootCrl by issuerDN
+			IList crlList = new ArrayList();
+			crlList.Add(rootCrl);
+			crlList.Add(interCrl);
+			IX509Store store = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(crlList));
+
+			X509CrlStoreSelector targetConstraintsCRL = new X509CrlStoreSelector();
+
+			ArrayList issuers = new ArrayList();
+			issuers.Add(rootCrl.IssuerDN);
+			targetConstraintsCRL.Issuers = issuers;
+
+			IList crls = new ArrayList(store.GetMatches(targetConstraintsCRL));
+			if (crls.Count != 1 || !crls.Contains(rootCrl))
+			{
+				Fail("rootCrl not found");
+			}
+
+			crls = new ArrayList(certStore.GetMatches(targetConstraintsCRL));
+			if (crls.Count != 0)
+			{
+				Fail("error using wrong selector (CRL)");
+			}
+			certs = new ArrayList(store.GetMatches(targetConstraints));
+			if (certs.Count != 0)
+			{
+				Fail("error using wrong selector (certs)");
+			}
+			// Searching for attribute certificates
+			X509V2AttributeCertificate attrCert = new X509V2AttributeCertificate(AttrCertTest.attrCert);
+			IX509AttributeCertificate attrCert2 = new X509V2AttributeCertificate(AttrCertTest.certWithBaseCertificateID);
+
+			IList attrList = new ArrayList();
+			attrList.Add(attrCert);
+			attrList.Add(attrCert2);
+			store = X509StoreFactory.Create(
+				"AttributeCertificate/Collection",
+				new X509CollectionStoreParameters(attrList));
+
+			X509AttrCertStoreSelector attrSelector = new X509AttrCertStoreSelector();
+			attrSelector.Holder = attrCert.Holder;
+			if (!attrSelector.Holder.Equals(attrCert.Holder))
+			{
+				Fail("holder get not correct");
+			}
+			IList attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert))
+			{
+				Fail("attrCert not found on holder");
+			}
+			attrSelector.Holder = attrCert2.Holder;
+			if (attrSelector.Holder.Equals(attrCert.Holder))
+			{
+				Fail("holder get not correct");
+			}
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert2))
+			{
+				Fail("attrCert2 not found on holder");
+			}
+			attrSelector = new X509AttrCertStoreSelector();
+			attrSelector.Issuer = attrCert.Issuer;
+			if (!attrSelector.Issuer.Equals(attrCert.Issuer))
+			{
+				Fail("issuer get not correct");
+			}
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert))
+			{
+				Fail("attrCert not found on issuer");
+			}
+			attrSelector.Issuer = attrCert2.Issuer;
+			if (attrSelector.Issuer.Equals(attrCert.Issuer))
+			{
+				Fail("issuer get not correct");
+			}
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert2))
+			{
+				Fail("attrCert2 not found on issuer");
+			}
+			attrSelector = new X509AttrCertStoreSelector();
+			attrSelector.AttributeCert = attrCert;
+			if (!attrSelector.AttributeCert.Equals(attrCert))
+			{
+				Fail("attrCert get not correct");
+			}
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert))
+			{
+				Fail("attrCert not found on attrCert");
+			}
+			attrSelector = new X509AttrCertStoreSelector();
+			attrSelector.SerialNumber = attrCert.SerialNumber;
+			if (!attrSelector.SerialNumber.Equals(attrCert.SerialNumber))
+			{
+				Fail("serial number get not correct");
+			}
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert))
+			{
+				Fail("attrCert not found on serial number");
+			}
+			attrSelector = (X509AttrCertStoreSelector)attrSelector.Clone();
+			if (!attrSelector.SerialNumber.Equals(attrCert.SerialNumber))
+			{
+				Fail("serial number get not correct");
+			}
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert))
+			{
+				Fail("attrCert not found on serial number");
+			}
+
+			attrSelector = new X509AttrCertStoreSelector();
+			attrSelector.AttributeCertificateValid = new DateTimeObject(attrCert.NotBefore);
+			if (attrSelector.AttributeCertificateValid.Value != attrCert.NotBefore)
+			{
+				Fail("valid get not correct");
+			}
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 1 || !attrs.Contains(attrCert))
+			{
+				Fail("attrCert not found on valid");
+			}
+			attrSelector = new X509AttrCertStoreSelector();
+			attrSelector.AttributeCertificateValid = new DateTimeObject(attrCert.NotBefore.AddMilliseconds(-100));
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 0)
+			{
+				Fail("attrCert found on before");
+			}
+			attrSelector.AttributeCertificateValid = new DateTimeObject(attrCert.NotAfter.AddMilliseconds(100));
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 0)
+			{
+				Fail("attrCert found on after");
+			}
+			attrSelector.SerialNumber = BigInteger.ValueOf(10000);
+			attrs = new ArrayList(store.GetMatches(attrSelector));
+			if (attrs.Count != 0)
+			{
+				Fail("attrCert found on wrong serial number");
+			}
+
+			attrSelector.AttributeCert = null;
+			attrSelector.AttributeCertificateValid = null;
+			attrSelector.Holder = null;
+			attrSelector.Issuer = null;
+			attrSelector.SerialNumber = null;
+			if (attrSelector.AttributeCert != null)
+			{
+				Fail("null attrCert");
+			}
+			if (attrSelector.AttributeCertificateValid != null)
+			{
+				Fail("null attrCertValid");
+			}
+			if (attrSelector.Holder != null)
+			{
+				Fail("null attrCert holder");
+			}
+			if (attrSelector.Issuer != null)
+			{
+				Fail("null attrCert issuer");
+			}
+			if (attrSelector.SerialNumber != null)
+			{
+				Fail("null attrCert serial");
+			}
+
+			attrs = new ArrayList(certStore.GetMatches(attrSelector));
+			if (attrs.Count != 0)
+			{
+				Fail("error using wrong selector (attrs)");
+			}
+
+			certPairTest();
+		}
+
+		public override string Name
+		{
+			get { return "IX509Store"; }
+		}
+
+		public static void Main(
+			string[] args)
+		{
+			RunTest(new X509StoreTest());
+		}
+
+		[Test]
+		public void TestFunction()
+		{
+			string resultText = Perform().ToString();
+
+			Assert.AreEqual(Name + ": Okay", resultText);
+		}
+	}
+}
diff --git a/crypto/test/src/test/nist/NistCertPathTest.cs b/crypto/test/src/test/nist/NistCertPathTest.cs
new file mode 100644
index 000000000..fed98a778
--- /dev/null
+++ b/crypto/test/src/test/nist/NistCertPathTest.cs
@@ -0,0 +1,847 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Reflection;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Pkix;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tests.Nist
+{
+	[TestFixture]
+	public class NistCertPathTest
+	{
+		private static readonly string GOOD_CA_CERT = "GoodCACert";
+
+		private static readonly string GOOD_CA_CRL = "GoodCACRL";
+
+		private static readonly string TRUST_ANCHOR_ROOT_CRL = "TrustAnchorRootCRL";
+
+		private static readonly string TRUST_ANCHOR_ROOT_CERTIFICATE = "TrustAnchorRootCertificate";
+
+		private static readonly char[] PKCS12_PASSWORD = "password".ToCharArray();
+
+		private static readonly string ANY_POLICY = "2.5.29.32.0";
+		private static readonly string NIST_TEST_POLICY_1 = "2.16.840.1.101.3.2.1.48.1";
+		private static readonly string NIST_TEST_POLICY_2 = "2.16.840.1.101.3.2.1.48.2";
+		private static readonly string NIST_TEST_POLICY_3 = "2.16.840.1.101.3.2.1.48.3";
+
+		private static IDictionary certs = new Hashtable();
+		private static IDictionary crls = new Hashtable();
+
+		private static ISet noPolicies = new HashSet();
+		private static ISet anyPolicy = new HashSet();
+		private static ISet nistTestPolicy1 = new HashSet();
+		private static ISet nistTestPolicy2 = new HashSet();
+		private static ISet nistTestPolicy3 = new HashSet();
+		private static ISet nistTestPolicy1And2 = new HashSet();
+
+		static NistCertPathTest()
+		{
+			anyPolicy.Add(ANY_POLICY);
+
+			nistTestPolicy1.Add(NIST_TEST_POLICY_1);
+			nistTestPolicy2.Add(NIST_TEST_POLICY_2);
+			nistTestPolicy3.Add(NIST_TEST_POLICY_3);
+			nistTestPolicy1And2.Add(NIST_TEST_POLICY_1);
+			nistTestPolicy1And2.Add(NIST_TEST_POLICY_2);
+
+		}
+
+		[Test]
+		public void TestValidSignaturesTest1()
+		{
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "ValidCertificatePathTest1EE", GOOD_CA_CERT },
+				new string[] { GOOD_CA_CRL, TRUST_ANCHOR_ROOT_CRL });
+		}
+
+		[Test]
+		public void TestInvalidCASignatureTest2()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "ValidCertificatePathTest1EE", "BadSignedCACert" },
+				new string[] { "BadSignedCACRL", TRUST_ANCHOR_ROOT_CRL },
+				1,
+				"TrustAnchor found but certificate validation failed.");
+		}
+
+		[Test]
+		public void TestInvalidEESignatureTest3()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "InvalidEESignatureTest3EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL },
+				0,
+				"Could not validate certificate signature.");
+		}
+        
+		[Test]
+		public void TestValidDSASignaturesTest4()
+		{
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "DSACACert", "ValidDSASignaturesTest4EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "DSACACRL" });
+		}
+
+		[Test]
+		// 4.1.5
+		public void TestValidDSAParameterInheritanceTest5()
+		{
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "DSACACert", "DSAParametersInheritedCACert", "ValidDSAParameterInheritanceTest5EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "DSACACRL", "DSAParametersInheritedCACRL" });
+		}
+
+		[Test]
+		public void TestInvalidDSASignaturesTest6()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "DSACACert", "InvalidDSASignatureTest6EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "DSACACRL" },
+				0,
+				"Could not validate certificate signature.");
+		}
+
+		[Test]
+		public void TestCANotBeforeDateTest1()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "BadnotBeforeDateCACert", "InvalidCAnotBeforeDateTest1EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "BadnotBeforeDateCACRL" },
+				1,
+				"Could not validate certificate: certificate not valid until 20470101120100GMT+00:00");
+		}
+        
+		[Test]
+		public void TestInvalidEENotBeforeDateTest2()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "InvalidEEnotBeforeDateTest2EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL },
+				0,
+				"Could not validate certificate: certificate not valid until 20470101120100GMT+00:00");
+		}
+
+		[Test]
+		public void TestValidPre2000UTCNotBeforeDateTest3()
+		{
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "Validpre2000UTCnotBeforeDateTest3EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL });
+		}
+
+		[Test]
+		public void TestValidGeneralizedTimeNotBeforeDateTest4()
+		{
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "ValidGeneralizedTimenotBeforeDateTest4EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL });
+		}
+
+		[Test]
+		public void TestInvalidCANotAfterDateTest5()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "BadnotAfterDateCACert", "InvalidCAnotAfterDateTest5EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "BadnotAfterDateCACRL" },
+				1,
+				"Could not validate certificate: certificate expired on 20020101120100GMT+00:00");
+		}
+
+		[Test]
+		public void TestInvalidEENotAfterDateTest6()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "InvalidEEnotAfterDateTest6EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL },
+				0,
+				"Could not validate certificate: certificate expired on 20020101120100GMT+00:00");
+		}
+
+		[Test]
+		public void TestInvalidValidPre2000UTCNotAfterDateTest7()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "Invalidpre2000UTCEEnotAfterDateTest7EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL },
+				0,
+				"Could not validate certificate: certificate expired on 19990101120100GMT+00:00");
+		}
+
+		[Test]
+		public void TestInvalidNegativeSerialNumberTest15()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "NegativeSerialNumberCACert", "InvalidNegativeSerialNumberTest15EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "NegativeSerialNumberCACRL" },
+				0,
+				"Certificate revocation after Thu Apr 19 14:57:20",
+				"reason: keyCompromise");
+		}
+
+		//
+		// 4.8 Certificate Policies
+		//
+		[Test]
+		public void TestAllCertificatesSamePolicyTest1()
+		{
+			string[] certList = new string[] { GOOD_CA_CERT, "ValidCertificatePathTest1EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				certList,
+				crlList,
+				noPolicies);
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				certList,
+				crlList,
+				nistTestPolicy1);
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				certList,
+				crlList,
+				nistTestPolicy2,
+				-1,
+				"Path processing failed on policy.");
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				certList,
+				crlList,
+				nistTestPolicy1And2);
+		}
+
+		[Test]
+		public void TestAllCertificatesNoPoliciesTest2()
+		{
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "NoPoliciesCACert", "AllCertificatesNoPoliciesTest2EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "NoPoliciesCACRL" });
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { "NoPoliciesCACert", "AllCertificatesNoPoliciesTest2EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, "NoPoliciesCACRL" },
+				noPolicies,
+				1,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestDifferentPoliciesTest3()
+		{
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "PoliciesP2subCACert", "DifferentPoliciesTest3EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL, "PoliciesP2subCACRL" });
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "PoliciesP2subCACert", "DifferentPoliciesTest3EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL, "PoliciesP2subCACRL" },
+				noPolicies,
+				1,
+				"No valid policy tree found when one expected.");
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "PoliciesP2subCACert", "DifferentPoliciesTest3EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL, "PoliciesP2subCACRL" },
+				nistTestPolicy1And2,
+				1,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestDifferentPoliciesTest4()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "GoodsubCACert", "DifferentPoliciesTest4EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL, "GoodsubCACRL" },
+				0,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestDifferentPoliciesTest5()
+		{
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE,
+				new string[] { GOOD_CA_CERT, "PoliciesP2subCA2Cert", "DifferentPoliciesTest5EE" },
+				new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL, "PoliciesP2subCA2CRL" },
+				0,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestOverlappingPoliciesTest6()
+		{
+			string[] certList = new string[] { "PoliciesP1234CACert", "PoliciesP1234subCAP123Cert", "PoliciesP1234subsubCAP123P12Cert", "OverlappingPoliciesTest6EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP1234CACRL", "PoliciesP1234subCAP123CRL", "PoliciesP1234subsubCAP123P12CRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList);
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2,
+				-1,
+				"Path processing failed on policy.");
+		}
+
+		[Test]
+		public void TestDifferentPoliciesTest7()
+		{
+			string[] certList = new string[] { "PoliciesP123CACert", "PoliciesP123subCAP12Cert", "PoliciesP123subsubCAP12P1Cert", "DifferentPoliciesTest7EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP123CACRL", "PoliciesP123subCAP12CRL", "PoliciesP123subsubCAP12P1CRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList,
+				0,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestDifferentPoliciesTest8()
+		{
+			string[] certList = new string[] { "PoliciesP12CACert", "PoliciesP12subCAP1Cert", "PoliciesP12subsubCAP1P2Cert", "DifferentPoliciesTest8EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP12CACRL", "PoliciesP12subCAP1CRL", "PoliciesP12subsubCAP1P2CRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList,
+				1,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestDifferentPoliciesTest9()
+		{
+			string[] certList = new string[] { "PoliciesP123CACert", "PoliciesP123subCAP12Cert", "PoliciesP123subsubCAP12P2Cert", "PoliciesP123subsubsubCAP12P2P1Cert", "DifferentPoliciesTest9EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP123CACRL", "PoliciesP123subCAP12CRL", "PoliciesP123subsubCAP2P2CRL", "PoliciesP123subsubsubCAP12P2P1CRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList,
+				1,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestAllCertificatesSamePoliciesTest10()
+		{
+			string[] certList = new string[] { "PoliciesP12CACert", "AllCertificatesSamePoliciesTest10EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP12CACRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList);
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2);
+		}
+
+		[Test]
+		public void TestAllCertificatesAnyPolicyTest11()
+		{
+			string[] certList = new string[] { "anyPolicyCACert", "AllCertificatesanyPolicyTest11EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "anyPolicyCACRL" };
+
+			PkixCertPathValidatorResult result = DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList);
+
+			result = DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+		}
+
+		[Test]
+		public void TestDifferentPoliciesTest12()
+		{
+			string[] certList = new string[] { "PoliciesP3CACert", "DifferentPoliciesTest12EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP3CACRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList,
+				0,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestAllCertificatesSamePoliciesTest13()
+		{
+			string[] certList = new string[] { "PoliciesP123CACert", "AllCertificatesSamePoliciesTest13EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP123CACRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2);
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy3);
+		}
+
+		[Test]
+		public void TestAnyPolicyTest14()
+		{
+			string[] certList = new string[] { "anyPolicyCACert", "AnyPolicyTest14EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "anyPolicyCACRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2,
+				-1,
+				"Path processing failed on policy.");
+		}
+
+		[Test]
+		public void TestUserNoticeQualifierTest15()
+		{
+			string[] certList = new string[] { "UserNoticeQualifierTest15EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList);
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2,
+				-1,
+				"Path processing failed on policy.");
+		}
+
+		[Test]
+		public void TestUserNoticeQualifierTest16()
+		{
+			string[] certList = new string[] { GOOD_CA_CERT, "UserNoticeQualifierTest16EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL };
+
+			PkixCertPathValidatorResult result = DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList);
+
+			result = DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2,
+				-1,
+				"Path processing failed on policy.");
+		}
+
+		[Test] 
+		public void TestUserNoticeQualifierTest17()
+		{
+			string[] certList = new string[] { GOOD_CA_CERT, "UserNoticeQualifierTest17EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, GOOD_CA_CRL };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList);
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2,
+				-1,
+				"Path processing failed on policy.");
+		}
+
+		[Test]
+		public void TestUserNoticeQualifierTest18()
+		{
+			string[] certList = new string[] { "PoliciesP12CACert", "UserNoticeQualifierTest18EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "PoliciesP12CACRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2);
+		}
+
+		[Test]
+		public void TestUserNoticeQualifierTest19()
+		{
+			string[] certList = new string[] { "UserNoticeQualifierTest19EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy2,
+				-1,
+				"Path processing failed on policy.");
+		}
+
+		[Test]
+		public void TestInvalidInhibitPolicyMappingTest1()
+		{
+			string[] certList = new string[] { "inhibitPolicyMapping0CACert", "inhibitPolicyMapping0subCACert", "InvalidinhibitPolicyMappingTest1EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "inhibitPolicyMapping0CACRL", "inhibitPolicyMapping0subCACRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null,
+				0,
+				"No valid policy tree found when one expected.");
+		}
+
+		[Test]
+		public void TestValidInhibitPolicyMappingTest2()
+		{
+			string[] certList = new string[] { "inhibitPolicyMapping1P12CACert", "inhibitPolicyMapping1P12subCACert", "ValidinhibitPolicyMappingTest2EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "inhibitPolicyMapping1P12CACRL", "inhibitPolicyMapping1P12subCACRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, nistTestPolicy1);
+		}
+
+		// 4.12.7
+		[Test]
+		public void TestValidSelfIssuedInhibitAnyPolicyTest7()
+		{
+			string[] certList = new string[] { "inhibitAnyPolicy1CACert", "inhibitAnyPolicy1SelfIssuedCACert", "inhibitAnyPolicy1subCA2Cert", "ValidSelfIssuedinhibitAnyPolicyTest7EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "inhibitAnyPolicy1CACRL", "inhibitAnyPolicy1subCA2CRL" };
+
+			doBuilderTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null, false, false);
+		}
+
+		// 4.4.19
+		[Test]
+		public void TestValidSeparateCertificateandCRLKeysTest19()
+		{
+			string[] certList = new string[] { "SeparateCertificateandCRLKeysCertificateSigningCACert", "SeparateCertificateandCRLKeysCRLSigningCert", "ValidSeparateCertificateandCRLKeysTest19EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "SeparateCertificateandCRLKeysCRL" };
+
+			doBuilderTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null, false, false);
+		}
+
+		[Test]
+		public void TestValidpathLenConstraintTest13()
+		{
+			string[] certList = new string[] { "pathLenConstraint6CACert", "pathLenConstraint6subCA4Cert", "pathLenConstraint6subsubCA41Cert", "pathLenConstraint6subsubsubCA41XCert", "ValidpathLenConstraintTest13EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "pathLenConstraint6CACRL", "pathLenConstraint6subCA4CRL", "pathLenConstraint6subsubCA41CRL", "pathLenConstraint6subsubsubCA41XCRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null);
+		}
+
+		// 4.4.10
+		[Test]
+		public void TestInvalidUnknownCRLExtensionTest10()
+		{
+			string[] certList = new string[] { "UnknownCRLExtensionCACert", "InvalidUnknownCRLExtensionTest10EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "UnknownCRLExtensionCACRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null,
+				0,
+				"CRL contains unsupported critical extensions.");
+		}
+
+		// 4.14.3
+		[Test]
+		public void TestInvaliddistributionPointTest3()
+		{
+			string[] certList = new string[] { "distributionPoint1CACert", "InvaliddistributionPointTest3EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "distributionPoint1CACRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null,
+				0,
+				"No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+		}
+
+		// 4.14.5
+		[Test]
+		public void TestValiddistributionPointTest5()
+		{
+			string[] certList = new string[] { "distributionPoint2CACert", "ValiddistributionPointTest5EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "distributionPoint2CACRL" };
+
+			DoTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null);
+		}
+
+		// 4.14.8
+		[Test]
+		public void TestInvaliddistributionPointTest8()
+		{
+			string[] certList = new string[] { "distributionPoint2CACert", "InvaliddistributionPointTest8EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "distributionPoint2CACRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null,
+				0,
+				"No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+		}
+
+		// 4.14.9
+		[Test]
+		public void TestInvaliddistributionPointTest9()
+		{
+			string[] certList = new string[] { "distributionPoint2CACert", "InvaliddistributionPointTest9EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "distributionPoint2CACRL" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null,
+				0,
+				"No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+		}
+
+		// 4.14.17
+		[Test]
+		public void TestInvalidonlySomeReasonsTest17()
+		{
+			string[] certList = new string[] { "onlySomeReasonsCA2Cert", "InvalidonlySomeReasonsTest17EE" };
+			string[] crlList = new string[] { TRUST_ANCHOR_ROOT_CRL, "onlySomeReasonsCA2CRL1", "onlySomeReasonsCA2CRL2" };
+
+			DoExceptionTest(TRUST_ANCHOR_ROOT_CERTIFICATE, certList, crlList, null,
+				0,
+				"Certificate status could not be determined.");
+		}
+
+		// section 4.14: tests 17, 24, 25, 30, 31, 32, 33, 35
+
+		// section 4.15: tests 5, 7
+		private void DoExceptionTest(
+			string		trustAnchor,
+			string[]	certs,
+			string[]	crls,
+			int			index,
+			string		message)
+		{
+			try
+			{
+				DoTest(trustAnchor, certs, crls);
+
+				Assert.Fail("path accepted when should be rejected");
+			}
+			catch (PkixCertPathValidatorException e)
+			{
+				Assert.AreEqual(index, e.Index);
+				Assert.AreEqual(message, e.Message);
+			}
+		}
+
+		private void DoExceptionTest(
+			string		trustAnchor,
+			string[]	certs,
+			string[]	crls,
+			ISet		policies,
+			int			index,
+			string		message)
+		{
+			try
+			{
+				DoTest(trustAnchor, certs, crls, policies);
+				Assert.Fail("path accepted when should be rejected");
+			}
+			catch (PkixCertPathValidatorException e)
+			{
+				Assert.AreEqual(index, e.Index);
+				Assert.AreEqual(message, e.Message);
+			}
+		}
+
+		private void DoExceptionTest(
+			string		trustAnchor,
+			string[]	certs,
+			string[]	crls,
+			int			index,
+			string		mesStart,
+			string		mesEnd)
+		{
+			try
+			{
+				DoTest(trustAnchor, certs, crls);
+
+				Assert.Fail("path accepted when should be rejected");
+			}
+			catch (PkixCertPathValidatorException e)
+			{
+				Assert.AreEqual(index, e.Index);
+				Assert.IsTrue(e.Message.StartsWith(mesStart));
+				Assert.IsTrue(e.Message.EndsWith(mesEnd));
+			}
+		}
+
+		private PkixCertPathValidatorResult DoTest(
+			string trustAnchor,
+			string[] certs,
+			string[] crls)
+		{
+			return DoTest(trustAnchor, certs, crls, null);
+		}
+
+		private PkixCertPathValidatorResult DoTest(
+			string trustAnchor,
+			string[] certs,
+			string[] crls,
+			ISet policies)
+		{
+			ISet trustedSet = new HashSet();
+			trustedSet.Add(GetTrustAnchor(trustAnchor));
+
+			IList x509Certs = new ArrayList();
+			IList x509Crls = new ArrayList();
+			X509Certificate endCert = LoadCert(certs[certs.Length - 1]);
+
+			for (int i = 0; i != certs.Length - 1; i++)
+			{
+				x509Certs.Add(LoadCert(certs[i]));
+			}
+
+			x509Certs.Add(endCert);
+
+			PkixCertPath certPath = new PkixCertPath(x509Certs);
+
+			for (int i = 0; i != crls.Length; i++)
+			{
+				x509Crls.Add(LoadCrl(crls[i]));
+			}
+
+			IX509Store x509CertStore = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(x509Certs));
+			IX509Store x509CrlStore = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(x509Crls));
+
+//			CertPathValidator validator = CertPathValidator.GetInstance("PKIX");
+			PkixCertPathValidator validator = new PkixCertPathValidator();
+			PkixParameters parameters = new PkixParameters(trustedSet);
+
+			parameters.AddStore(x509CertStore);
+			parameters.AddStore(x509CrlStore);
+			parameters.IsRevocationEnabled = true;
+
+			if (policies != null)
+			{
+				parameters.IsExplicitPolicyRequired = true;
+				parameters.SetInitialPolicies(policies);
+			}
+
+			// Perform validation as of this date since test certs expired
+			parameters.Date = new DateTimeObject(DateTime.Parse("1/1/2011"));
+
+			return validator.Validate(certPath, parameters);
+		}
+
+		private PkixCertPathBuilderResult doBuilderTest(
+			string		trustAnchor,
+			string[]	certs,
+			string[]	crls,
+			ISet		initialPolicies,
+			bool		policyMappingInhibited,
+			bool		anyPolicyInhibited)
+		{
+			ISet trustedSet = new HashSet();
+			trustedSet.Add(GetTrustAnchor(trustAnchor));
+
+			IList x509Certs = new ArrayList();
+			IList x509Crls = new ArrayList();
+			X509Certificate endCert = LoadCert(certs[certs.Length - 1]);
+
+			for (int i = 0; i != certs.Length - 1; i++)
+			{
+				x509Certs.Add(LoadCert(certs[i]));
+			}
+
+			x509Certs.Add(endCert);
+
+			for (int i = 0; i != crls.Length; i++)
+			{
+				x509Crls.Add(LoadCrl(crls[i]));
+			}
+
+			IX509Store x509CertStore = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(x509Certs));
+			IX509Store x509CrlStore = X509StoreFactory.Create(
+				"CRL/Collection",
+				new X509CollectionStoreParameters(x509Crls));
+
+//			CertPathBuilder builder = CertPathBuilder.GetInstance("PKIX");   
+			PkixCertPathBuilder builder = new PkixCertPathBuilder();
+
+			X509CertStoreSelector endSelector = new X509CertStoreSelector();
+
+			endSelector.Certificate = endCert;
+
+			PkixBuilderParameters builderParams = new PkixBuilderParameters(trustedSet, endSelector);
+
+			if (initialPolicies != null)
+			{
+				builderParams.SetInitialPolicies(initialPolicies);
+				builderParams.IsExplicitPolicyRequired = true;
+			}
+			if (policyMappingInhibited)
+			{
+				builderParams.IsPolicyMappingInhibited = policyMappingInhibited;
+			}
+			if (anyPolicyInhibited)
+			{
+				builderParams.IsAnyPolicyInhibited = anyPolicyInhibited;
+			}
+
+			builderParams.AddStore(x509CertStore);
+			builderParams.AddStore(x509CrlStore);
+
+			// Perform validation as of this date since test certs expired
+			builderParams.Date = new DateTimeObject(DateTime.Parse("1/1/2011"));
+
+			try
+			{
+				return (PkixCertPathBuilderResult) builder.Build(builderParams);
+			}
+			catch (PkixCertPathBuilderException e)
+			{               
+				throw e.InnerException;
+			}
+		}
+
+		private X509Certificate LoadCert(
+			string certName)
+		{
+			X509Certificate cert = (X509Certificate)certs[certName];
+
+			if (cert != null)
+			{
+				return cert;
+			}
+
+			Stream fs = null;
+
+			try
+			{
+				fs = SimpleTest.GetTestDataAsStream("PKITS.certs." + certName + ".crt");
+
+				cert = new X509CertificateParser().ReadCertificate(fs);
+
+				certs[certName] = cert;
+
+				return cert;
+			}
+			catch (Exception e)
+			{
+				throw new InvalidOperationException("exception loading certificate " + certName + ": " + e);
+			}
+			finally
+			{
+				fs.Close();
+			}
+		}
+
+		private X509Crl LoadCrl(
+			string crlName)
+			//throws Exception
+		{
+			X509Crl crl = (X509Crl)certs[crlName];
+        
+			if (crl != null)
+			{
+				return crl;
+			}
+
+			Stream fs = null;
+
+			try
+			{
+				fs = SimpleTest.GetTestDataAsStream("PKITS.crls." + crlName + ".crl");
+
+				crl = new X509CrlParser().ReadCrl(fs);
+
+				crls[crlName] = crl;
+
+				return crl;
+			}
+			catch (Exception)
+			{
+				throw new InvalidOperationException("exception loading CRL: " + crlName);
+			}
+			finally
+			{
+				fs.Close();
+			}
+		}
+
+		private TrustAnchor GetTrustAnchor(string trustAnchorName)
+		{
+			X509Certificate cert = LoadCert(trustAnchorName);
+			Asn1OctetString extBytes = cert.GetExtensionValue(X509Extensions.NameConstraints);
+
+			if (extBytes != null)
+			{
+				Asn1Encodable extValue = X509ExtensionUtilities.FromExtensionValue(extBytes);
+
+				return new TrustAnchor(cert, extValue.GetDerEncoded());
+			}
+
+			return new TrustAnchor(cert, null);
+		}
+	}
+}
diff --git a/crypto/test/src/test/rsa3/RSA3CertTest.cs b/crypto/test/src/test/rsa3/RSA3CertTest.cs
new file mode 100644
index 000000000..913f4f015
--- /dev/null
+++ b/crypto/test/src/test/rsa3/RSA3CertTest.cs
@@ -0,0 +1,127 @@
+using System;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tests.Rsa3
+{
+	/**
+	* Marius Schilder's Bleichenbacher's Forgery Attack Tests
+	*/
+	[TestFixture]
+	public class RSA3CertTest
+		//extends TestCase
+	{
+		[Test]
+		public void TestA()
+		{
+			doTest("self-testcase-A.pem");
+		}
+
+		[Test]
+		public void TestB()
+		{
+			doTest("self-testcase-B.pem");
+		}
+
+		[Test]
+		public void TestC()
+		{
+			doTest("self-testcase-C.pem");
+		}
+
+		[Test]
+		public void TestD()
+		{
+			doTest("self-testcase-D.pem");
+		}
+
+		[Test]
+		public void TestE()
+		{
+			doTest("self-testcase-E.pem");
+		}
+
+		[Test]
+		public void TestF()
+		{
+			doTest("self-testcase-F.pem");
+		}
+
+		[Test]
+		public void TestG()
+		{
+			doTest("self-testcase-G.pem");
+		}
+
+		[Test]
+		public void TestH()
+		{
+			doTest("self-testcase-H.pem");
+		}
+
+		[Test]
+		public void TestI()
+		{
+			doTest("self-testcase-I.pem");
+		}
+
+		[Test]
+		public void TestJ()
+		{
+			doTest("self-testcase-J.pem");
+		}
+
+		[Test]
+		public void TestL()
+		{
+			doTest("self-testcase-L.pem");
+		}
+
+		private void doTest(
+			string certName)
+		{
+			X509Certificate cert = loadCert(certName);
+			byte[] tbs = cert.GetTbsCertificate();
+			ISigner sig = SignerUtilities.GetSigner(cert.SigAlgName);
+
+			sig.Init(false, cert.GetPublicKey());
+
+			sig.BlockUpdate(tbs, 0, tbs.Length);
+
+			Assert.IsFalse(sig.VerifySignature(cert.GetSignature()));
+		}
+
+		private X509Certificate loadCert(
+			string certName)
+		{
+			Stream s = SimpleTest.GetTestDataAsStream("rsa3." + certName);
+			TextReader tr = new StreamReader(s);
+			PemReader rd = new PemReader(tr);
+
+			return (X509Certificate) rd.ReadObject();
+		}
+
+//		public static void main (string[] args) 
+//			throws Exception
+//		{
+//			junit.textui.TestRunner.run(suite());
+//		}
+//	    
+//		public static Test suite() 
+//			throws Exception
+//		{   
+//			TestSuite suite = new TestSuite("Bleichenbacher's Forgery Attack Tests");
+//	        
+//			suite.addTestSuite(RSA3CertTest.class);
+//	        
+//			return suite;
+//		}
+	}
+}
diff --git a/crypto/test/src/tsp/test/AllTests.cs b/crypto/test/src/tsp/test/AllTests.cs
new file mode 100644
index 000000000..66dc9c480
--- /dev/null
+++ b/crypto/test/src/tsp/test/AllTests.cs
@@ -0,0 +1,32 @@
+using System;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Tsp.Tests
+{
+    public class AllTests
+    {
+        public static void Main(
+			string[] args)
+        {
+            //junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            suite().Run(el);
+        }
+
+		public static TestSuite suite()
+        {
+            TestSuite suite = new TestSuite("TSP Tests");
+
+			suite.Add(new GenTimeAccuracyUnitTest());
+			suite.Add(new ParseTest());
+			suite.Add(new TimeStampTokenInfoUnitTest());
+			suite.Add(new TspTest());
+
+			return suite;
+        }
+    }
+}
diff --git a/crypto/test/src/tsp/test/GenTimeAccuracyTest.cs b/crypto/test/src/tsp/test/GenTimeAccuracyTest.cs
new file mode 100644
index 000000000..01cc83d53
--- /dev/null
+++ b/crypto/test/src/tsp/test/GenTimeAccuracyTest.cs
@@ -0,0 +1,116 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+
+namespace Org.BouncyCastle.Tsp.Tests
+{
+	[TestFixture]
+	public class GenTimeAccuracyUnitTest
+	{
+		private static readonly DerInteger ZERO_VALUE = new DerInteger(0);
+		private static readonly DerInteger ONE_VALUE = new DerInteger(1);
+		private static readonly DerInteger TWO_VALUE = new DerInteger(2);
+		private static readonly DerInteger THREE_VALUE = new DerInteger(3);
+
+		[Test]
+		public void TestOneTwoThree()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ONE_VALUE, TWO_VALUE, THREE_VALUE));
+
+			checkValues(accuracy, ONE_VALUE, TWO_VALUE, THREE_VALUE);
+
+			checkTostring(accuracy, "1.002003");
+		}
+
+		[Test]
+		public void TestThreeTwoOne()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(THREE_VALUE, TWO_VALUE, ONE_VALUE));
+
+			checkValues(accuracy, THREE_VALUE, TWO_VALUE, ONE_VALUE);
+
+			checkTostring(accuracy, "3.002001");
+		}
+
+		[Test]
+		public void TestTwoThreeTwo()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(TWO_VALUE, THREE_VALUE, TWO_VALUE));
+
+			checkValues(accuracy, TWO_VALUE, THREE_VALUE, TWO_VALUE);
+
+			checkTostring(accuracy, "2.003002");
+		}
+
+		[Test]
+		public void TestZeroTwoThree()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ZERO_VALUE, TWO_VALUE, THREE_VALUE));
+
+			checkValues(accuracy, ZERO_VALUE, TWO_VALUE, THREE_VALUE);
+
+			checkTostring(accuracy, "0.002003");
+		}
+
+		[Test]
+		public void TestThreeTwoNull()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(THREE_VALUE, TWO_VALUE, null));
+
+			checkValues(accuracy, THREE_VALUE, TWO_VALUE, ZERO_VALUE);
+
+			checkTostring(accuracy, "3.002000");
+		}
+
+		[Test]
+		public void TestOneNullOne()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ONE_VALUE, null, ONE_VALUE));
+
+			checkValues(accuracy, ONE_VALUE, ZERO_VALUE, ONE_VALUE);
+
+			checkTostring(accuracy, "1.000001");
+		}
+
+		[Test]
+		public void TestZeroNullNull()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ZERO_VALUE, null, null));
+
+			checkValues(accuracy, ZERO_VALUE, ZERO_VALUE, ZERO_VALUE);
+
+			checkTostring(accuracy, "0.000000");
+		}
+
+		[Test]
+		public void TestNullNullNull()
+		{
+			GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(null, null, null));
+
+			checkValues(accuracy, ZERO_VALUE, ZERO_VALUE, ZERO_VALUE);
+
+			checkTostring(accuracy, "0.000000");
+		}
+
+		private void checkValues(
+			GenTimeAccuracy accuracy,
+			DerInteger      secs,
+			DerInteger      millis,
+			DerInteger      micros)
+		{
+			Assert.AreEqual(secs.Value.IntValue, accuracy.Seconds);
+			Assert.AreEqual(millis.Value.IntValue, accuracy.Millis);
+			Assert.AreEqual(micros.Value.IntValue, accuracy.Micros);
+		}
+
+		private void checkTostring(
+			GenTimeAccuracy	accuracy,
+			string			expected)
+		{
+			Assert.AreEqual(expected, accuracy.ToString());
+		}
+	}
+}
diff --git a/crypto/test/src/tsp/test/ParseTest.cs b/crypto/test/src/tsp/test/ParseTest.cs
new file mode 100644
index 000000000..ec9ba72f6
--- /dev/null
+++ b/crypto/test/src/tsp/test/ParseTest.cs
@@ -0,0 +1,396 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp.Tests
+{
+	[TestFixture]
+	public class ParseTest
+	{
+		private static readonly byte[] sha1Request = Base64.Decode("MDACAQEwITAJBgUrDgMCGgUABBT5UbEBmJssO3RxcQtOePxNvfoMpgIIC+GvYW2mtZQ=");
+		private static readonly byte[] sha1noNonse = Base64.Decode("MCYCAQEwITAJBgUrDgMCGgUABBT5UbEBmJssO3RxcQtOePxNvfoMpg==");
+		private static readonly byte[] md5Request = Base64.Decode("MDoCAQEwIDAMBggqhkiG9w0CBQUABBDIl9FBCvjyx0+6EbHbUR6eBgkrBgEEAakHBQECCDQluayIxIzn");
+		private static readonly byte[] ripemd160Request = Base64.Decode("MD8CAQEwITAJBgUrJAMCAQUABBSq03a/mk50Yd9lMF+BSqOp/RHGQQYJKwYBBAGpBwUBAgkA4SZs9NfqISMBAf8=");
+
+		private static readonly byte[] sha1Response = Base64.Decode(
+			  "MIICbDADAgEAMIICYwYJKoZIhvcNAQcCoIICVDCCAlACAQMxCzAJBgUrDgMC"
+			+ "GgUAMIHaBgsqhkiG9w0BCRABBKCBygSBxzCBxAIBAQYEKgMEATAhMAkGBSsO"
+			+ "AwIaBQAEFPlRsQGYmyw7dHFxC054/E29+gymAgEEGA8yMDA0MTIwOTA3NTIw"
+			+ "NVowCgIBAYACAfSBAWQBAf8CCAvhr2FtprWUoGmkZzBlMRgwFgYDVQQDEw9F"
+			+ "cmljIEguIEVjaGlkbmExJDAiBgkqhkiG9w0BCQEWFWVyaWNAYm91bmN5Y2Fz"
+			+ "dGxlLm9yZzEWMBQGA1UEChMNQm91bmN5IENhc3RsZTELMAkGA1UEBhMCQVUx"
+			+ "ggFfMIIBWwIBATAqMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNV"
+			+ "BAYTAkFVAgECMAkGBSsOAwIaBQCggYwwGgYJKoZIhvcNAQkDMQ0GCyqGSIb3"
+			+ "DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0wNDEyMDkwNzUyMDVaMCMGCSqGSIb3"
+			+ "DQEJBDEWBBTGR1cbm94tWbcpDWrH+bD8UYePsTArBgsqhkiG9w0BCRACDDEc"
+			+ "MBowGDAWBBS37aLzFcheqeJ5cla0gjNWHGKbRzANBgkqhkiG9w0BAQEFAASB"
+			+ "gBrc9CJ3xlcTQuWQXJUqPEn6f6vfJAINKsn22z8LIfS/2p/CTFU6+W/bz8j8"
+			+ "j+8uWEJe8okTsI0FflljIsspqOPTB/RrnXteajbkuk/rLmz1B2g/qWBGAzPI"
+			+ "D214raBc1a7Bpd76PkvSSdjqrEaaskd+7JJiPr9l9yeSoh1AIt0N");
+
+		private static readonly byte[] sha1noNonseResponse = Base64.Decode(
+			  "MIICYjADAgEAMIICWQYJKoZIhvcNAQcCoIICSjCCAkYCAQMxCzAJBgUrDgMC"
+			+ "GgUAMIHQBgsqhkiG9w0BCRABBKCBwASBvTCBugIBAQYEKgMEATAhMAkGBSsO"
+			+ "AwIaBQAEFPlRsQGYmyw7dHFxC054/E29+gymAgECGA8yMDA0MTIwOTA3MzQx"
+			+ "MlowCgIBAYACAfSBAWQBAf+gaaRnMGUxGDAWBgNVBAMTD0VyaWMgSC4gRWNo"
+			+ "aWRuYTEkMCIGCSqGSIb3DQEJARYVZXJpY0Bib3VuY3ljYXN0bGUub3JnMRYw"
+			+ "FAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVTGCAV8wggFbAgEB"
+			+ "MCowJTEWMBQGA1UEChMNQm91bmN5IENhc3RsZTELMAkGA1UEBhMCQVUCAQIw"
+			+ "CQYFKw4DAhoFAKCBjDAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJ"
+			+ "KoZIhvcNAQkFMQ8XDTA0MTIwOTA3MzQxMlowIwYJKoZIhvcNAQkEMRYEFMNA"
+			+ "xlscHYiByHL9DIEh3FewIhgSMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFLft"
+			+ "ovMVyF6p4nlyVrSCM1YcYptHMA0GCSqGSIb3DQEBAQUABIGAaj46Tarrg7V7"
+			+ "z13bbetrGv+xy159eE8kmIW9nPegru3DuK/GmbMx9W3l0ydx0zdXRwYi6NZc"
+			+ "nNqbEZQZ2L1biJVTflgWq4Nxu4gPGjH/BGHKdH/LyW4eDcXZR39AkNBMnDAK"
+			+ "EmhhJo1/Tc+S/WkV9lnHJCPIn+TAijBUO6EiTik=");
+
+		private static readonly byte[] md5Response = Base64.Decode(
+			  "MIICcDADAgEAMIICZwYJKoZIhvcNAQcCoIICWDCCAlQCAQMxCzAJBgUrDgMC"
+			+ "GgUAMIHeBgsqhkiG9w0BCRABBKCBzgSByzCByAIBAQYJKwYBBAGpBwUBMCAw"
+			+ "DAYIKoZIhvcNAgUFAAQQyJfRQQr48sdPuhGx21EengIBAxgPMjAwNDEyMDkw"
+			+ "NzQ2MTZaMAoCAQGAAgH0gQFkAQH/Agg0JbmsiMSM56BppGcwZTEYMBYGA1UE"
+			+ "AxMPRXJpYyBILiBFY2hpZG5hMSQwIgYJKoZIhvcNAQkBFhVlcmljQGJvdW5j"
+			+ "eWNhc3RsZS5vcmcxFjAUBgNVBAoTDUJvdW5jeSBDYXN0bGUxCzAJBgNVBAYT"
+			+ "AkFVMYIBXzCCAVsCAQEwKjAlMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxlMQsw"
+			+ "CQYDVQQGEwJBVQIBAjAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsq"
+			+ "hkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMDQxMjA5MDc0NjE2WjAjBgkq"
+			+ "hkiG9w0BCQQxFgQUFpRpaiRUUjiY7EbefbWLKDIY0XMwKwYLKoZIhvcNAQkQ"
+			+ "AgwxHDAaMBgwFgQUt+2i8xXIXqnieXJWtIIzVhxim0cwDQYJKoZIhvcNAQEB"
+			+ "BQAEgYBTwKsLLrQm+bvKV7Jwto/cMQh0KsVB5RoEeGn5CI9XyF2Bm+JRcvQL"
+			+ "Nm7SgSOBVt4A90TqujxirNeyQnXRiSnFvXd09Wet9WIQNpwpiGlE7lCrAhuq"
+			+ "/TAUe79VIpoQZDtyhbh0Vzxl24yRoechabC0zuPpOWOzrA4YC3Hv1J2tAA==");
+
+		private static readonly byte[] signingCert = Base64.Decode(
+			  "MIICWjCCAcOgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAlMRYwFAYDVQQKEw1Cb3Vu"
+			+ "Y3kgQ2FzdGxlMQswCQYDVQQGEwJBVTAeFw0wNDEyMDkwNzEzMTRaFw0wNTAzMTkw"
+			+ "NzEzMTRaMGUxGDAWBgNVBAMTD0VyaWMgSC4gRWNoaWRuYTEkMCIGCSqGSIb3DQEJ"
+			+ "ARYVZXJpY0Bib3VuY3ljYXN0bGUub3JnMRYwFAYDVQQKEw1Cb3VuY3kgQ2FzdGxl"
+			+ "MQswCQYDVQQGEwJBVTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqGAFO3dK"
+			+ "jB7Ca7u5Z3CabsbGr2Exg+3sztSPiRCIba03es4295EhtDF5bXQvrW2R1Bg72vED"
+			+ "5tWaQjVDetvDfCzVC3ErHLTVk3OgpLIP1gf2T0LcOH2pTh2LP9c5Ceta+uggK8zK"
+			+ "9sYUUnzGPSAZxrqHIIAlPIgqk0BMV+KApyECAwEAAaNaMFgwHQYDVR0OBBYEFO4F"
+			+ "YoqogtB9MjD0NB5x5HN3TrGUMB8GA1UdIwQYMBaAFPXAecuwLqNkCxYVLE/ngFQR"
+			+ "7RLIMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBBAUAA4GBADGi"
+			+ "D5/qmGvcBgswEM/z2dF4lOxbTNKUW31ZHiU8CXlN0IkFtNbBLBTbJOQIAUnNEabL"
+			+ "T7aYgj813OZKUbJTx4MuGChhot/TEP7hKo/xz9OnXLsqYDKbqbo8iLOode+SI7II"
+			+ "+yYghOtqvx32cL2Qmffi1LaMbhJP+8NbsIxowdRC");
+
+		private static readonly byte[] unacceptablePolicy = Base64.Decode(
+			"MDAwLgIBAjAkDCJSZXF1ZXN0ZWQgcG9saWN5IGlzIG5vdCBzdXBwb3J0ZWQuAwMAAAE=");
+
+		private static readonly byte[] generalizedTime = Base64.Decode(
+			  "MIIKPTADAgEAMIIKNAYJKoZIhvcNAQcCoIIKJTCCCiECAQMxCzAJBgUrDgMC"
+			+ "GgUAMIIBGwYLKoZIhvcNAQkQAQSgggEKBIIBBjCCAQICAQEGCisGAQQBhFkK"
+			+ "AwEwITAJBgUrDgMCGgUABBQAAAAAAAAAAAAAAAAAAAAAAAAAAAICUC8YEzIw"
+			+ "MDUwMzEwMTA1ODQzLjkzM1owBIACAfQBAf8CAWSggaikgaUwgaIxCzAJBgNV"
+			+ "BAYTAkdCMRcwFQYDVQQIEw5DYW1icmlkZ2VzaGlyZTESMBAGA1UEBxMJQ2Ft"
+			+ "YnJpZGdlMSQwIgYDVQQKExtuQ2lwaGVyIENvcnBvcmF0aW9uIExpbWl0ZWQx"
+			+ "JzAlBgNVBAsTHm5DaXBoZXIgRFNFIEVTTjozMjJBLUI1REQtNzI1QjEXMBUG"
+			+ "A1UEAxMOZGVtby1kc2UyMDAtMDGgggaFMIID2TCCA0KgAwIBAgICAIswDQYJ"
+			+ "KoZIhvcNAQEFBQAwgYwxCzAJBgNVBAYTAkdCMRcwFQYDVQQIEw5DYW1icmlk"
+			+ "Z2VzaGlyZTESMBAGA1UEBxMJQ2FtYnJpZGdlMSQwIgYDVQQKExtuQ2lwaGVy"
+			+ "IENvcnBvcmF0aW9uIExpbWl0ZWQxGDAWBgNVBAsTD1Byb2R1Y3Rpb24gVEVT"
+			+ "VDEQMA4GA1UEAxMHVEVTVCBDQTAeFw0wNDA2MTQxNDIzNTlaFw0wNTA2MTQx"
+			+ "NDIzNTlaMIGiMQswCQYDVQQGEwJHQjEXMBUGA1UECBMOQ2FtYnJpZGdlc2hp"
+			+ "cmUxEjAQBgNVBAcTCUNhbWJyaWRnZTEkMCIGA1UEChMbbkNpcGhlciBDb3Jw"
+			+ "b3JhdGlvbiBMaW1pdGVkMScwJQYDVQQLEx5uQ2lwaGVyIERTRSBFU046MzIy"
+			+ "QS1CNURELTcyNUIxFzAVBgNVBAMTDmRlbW8tZHNlMjAwLTAxMIGfMA0GCSqG"
+			+ "SIb3DQEBAQUAA4GNADCBiQKBgQC7zUamCeLIApddx1etW5YEFrL1WXnlCd7j"
+			+ "mMFI6RpSq056LBkF1z5LgucLY+e/c3u2Nw+XJuS3a2fKuBD7I1s/6IkVtIb/"
+			+ "KLDjjafOnottKhprH8K41siJUeuK3PRzfZ5kF0vwB3rNvWPCBJmp7kHtUQw3"
+			+ "RhIsJTYs7Wy8oVFHVwIDAQABo4IBMDCCASwwCQYDVR0TBAIwADAWBgNVHSUB"
+			+ "Af8EDDAKBggrBgEFBQcDCDAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5l"
+			+ "cmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFDlEe9Pd0WwQrtnEmFRI2Vmt"
+			+ "b+lCMIG5BgNVHSMEgbEwga6AFNy1VPweOQLC65bs6/0RcUYB19vJoYGSpIGP"
+			+ "MIGMMQswCQYDVQQGEwJHQjEXMBUGA1UECBMOQ2FtYnJpZGdlc2hpcmUxEjAQ"
+			+ "BgNVBAcTCUNhbWJyaWRnZTEkMCIGA1UEChMbbkNpcGhlciBDb3Jwb3JhdGlv"
+			+ "biBMaW1pdGVkMRgwFgYDVQQLEw9Qcm9kdWN0aW9uIFRFU1QxEDAOBgNVBAMT"
+			+ "B1RFU1QgQ0GCAQAwDQYJKoZIhvcNAQEFBQADgYEASEMlrpRE1RYZPxP3530e"
+			+ "hOYUDjgQbw0dwpPjQtLWkeJrePMzDBAbuWwpRI8dOzKP3Rnrm5rxJ7oLY2S0"
+			+ "A9ZfV+iwFKagEHFytfnPm2Y9AeNR7a3ladKd7NFMw+5Tbk7Asbetbb+NJfCl"
+			+ "9YzHwxLGiQbpKxgc+zYOjq74eGLKtcKhggKkMIICDQIBATCB0qGBqKSBpTCB"
+			+ "ojELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDkNhbWJyaWRnZXNoaXJlMRIwEAYD"
+			+ "VQQHEwlDYW1icmlkZ2UxJDAiBgNVBAoTG25DaXBoZXIgQ29ycG9yYXRpb24g"
+			+ "TGltaXRlZDEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjMyMkEtQjVERC03"
+			+ "MjVCMRcwFQYDVQQDEw5kZW1vLWRzZTIwMC0wMaIlCgEBMAkGBSsOAwIaBQAD"
+			+ "FQDaLe88TQvM+iMKmIXMmDSyPCZ/+KBmMGSkYjBgMQswCQYDVQQGEwJVUzEk"
+			+ "MCIGA1UEChMbbkNpcGhlciBDb3Jwb3JhdGlvbiBMaW1pdGVkMRgwFgYDVQQL"
+			+ "Ew9Qcm9kdWN0aW9uIFRlc3QxETAPBgNVBAMTCFRlc3QgVE1DMA0GCSqGSIb3"
+			+ "DQEBBQUAAgjF2jVbAAAAADAiGA8yMDA1MDMxMDAyNTQxOVoYDzIwMDUwMzEz"
+			+ "MDI1NDE5WjCBjTBLBgorBgEEAYRZCgQBMT0wOzAMAgTF2jVbAgQAAAAAMA8C"
+			+ "BAAAAAACBAAAaLkCAf8wDAIEAAAAAAIEAAKV/DAMAgTF3inbAgQAAAAAMD4G"
+			+ "CisGAQQBhFkKBAIxMDAuMAwGCisGAQQBhFkKAwGgDjAMAgQAAAAAAgQAB6Eg"
+			+ "oQ4wDAIEAAAAAAIEAAPQkDANBgkqhkiG9w0BAQUFAAOBgQB1q4d3GNWk7oAT"
+			+ "WkpYmZaTFvapMhTwAmAtSGgFmNOZhs21iHWl/X990/HEBsduwxohfrd8Pz64"
+			+ "hV/a76rpeJCVUfUNmbRIrsurFx6uKwe2HUHKW8grZWeCD1L8Y1pKQdrD41gu"
+			+ "v0msfOXzLWW+xe5BcJguKclN8HmT7s2odtgiMTGCAmUwggJhAgEBMIGTMIGM"
+			+ "MQswCQYDVQQGEwJHQjEXMBUGA1UECBMOQ2FtYnJpZGdlc2hpcmUxEjAQBgNV"
+			+ "BAcTCUNhbWJyaWRnZTEkMCIGA1UEChMbbkNpcGhlciBDb3Jwb3JhdGlvbiBM"
+			+ "aW1pdGVkMRgwFgYDVQQLEw9Qcm9kdWN0aW9uIFRFU1QxEDAOBgNVBAMTB1RF"
+			+ "U1QgQ0ECAgCLMAkGBSsOAwIaBQCgggEnMBoGCSqGSIb3DQEJAzENBgsqhkiG"
+			+ "9w0BCRABBDAjBgkqhkiG9w0BCQQxFgQUi1iYx5H3ACnvngWZTPfdxGswkSkw"
+			+ "geMGCyqGSIb3DQEJEAIMMYHTMIHQMIHNMIGyBBTaLe88TQvM+iMKmIXMmDSy"
+			+ "PCZ/+DCBmTCBkqSBjzCBjDELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDkNhbWJy"
+			+ "aWRnZXNoaXJlMRIwEAYDVQQHEwlDYW1icmlkZ2UxJDAiBgNVBAoTG25DaXBo"
+			+ "ZXIgQ29ycG9yYXRpb24gTGltaXRlZDEYMBYGA1UECxMPUHJvZHVjdGlvbiBU"
+			+ "RVNUMRAwDgYDVQQDEwdURVNUIENBAgIAizAWBBSpS/lH6bN/wf3E2z2X29vF"
+			+ "2U7YHTANBgkqhkiG9w0BAQUFAASBgGvDVsgsG5I5WKjEDVHvdRwUx+8Cp10l"
+			+ "zGF8o1h7aK5O3zQ4jLayYHea54E5+df35gG7Z3eoOy8E350J7BvHiwDLTqe8"
+			+ "SoRlGs9VhL6LMmCcERfGSlSn61Aa15iXZ8eHMSc5JTeJl+kqy4I3FPP4m2ai"
+			+ "8wy2fQhn7hUM8Ntg7Y2s");
+
+		private static readonly byte[] v2SigningCertResponse = Base64.Decode(
+			  "MIIPPTADAgEAMIIPNAYJKoZIhvcNAQcCoIIPJTCCDyECAQMxDzANBglghkgBZQMEAgEFADCB6QYL"
+			+ "KoZIhvcNAQkQAQSggdkEgdYwgdMCAQEGBgQAj2cBATAxMA0GCWCGSAFlAwQCAQUABCBcU0GN08TA"
+			+ "LUFi7AAwQwVkSXqGu9tAzvJ7EXW7SMXHHQIRAM7Fa7g6tMvZI3dgllwMfpcYDzIwMDcxMjExMTAy"
+			+ "MTU5WjADAgEBAgYBFsi5OlmgYqRgMF4xCzAJBgNVBAYTAkRFMSQwIgYDVQQKDBtEZXV0c2NoZSBS"
+			+ "ZW50ZW52ZXJzaWNoZXJ1bmcxEzARBgNVBAsMClFDIFJvb3QgQ0ExFDASBgNVBAMMC1FDIFJvb3Qg"
+			+ "VFNQoIILQjCCBwkwggXxoAMCAQICAwN1pjANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJERTEk"
+			+ "MCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVyc2ljaGVydW5nMRMwEQYDVQQLDApRQyBSb290IENB"
+			+ "MB4XDTA3MTEyMDE2MDcyMFoXDTEyMDcyNzIwMjExMVowXjELMAkGA1UEBhMCREUxJDAiBgNVBAoM"
+			+ "G0RldXRzY2hlIFJlbnRlbnZlcnNpY2hlcnVuZzETMBEGA1UECwwKUUMgUm9vdCBDQTEUMBIGA1UE"
+			+ "AwwLUUMgUm9vdCBUU1AwggEkMA0GCSqGSIb3DQEBAQUAA4IBEQAwggEMAoIBAQCv1vO+EtGnJNs0"
+			+ "atv76BAJXs4bmO8yzVwe3RUtgeu5z9iefh8P46i1g3EL2CD15NcTfoHksr5KudNY30olfjHG7lIu"
+			+ "MO3R5sAcrGDPP7riZJnaI6VD/e6kVR569VBid5z105fJAB7mID7+Bn7pdRwDW3Fy2CzfofXGuvrO"
+			+ "GPNEWq8x8kqqf75DB5nAs5QP8H41obkdkap2ttHkkPZCiMghTs8iHfpJ0STn47MKq+QrUmuATMZi"
+			+ "XrdEfb7f3TBMjO0UVJF64Mh+kC9GtUEHlcm0Tq2Pk5XIUxWEyL94rZ4UWcVdSVE7IjggV2MifMNx"
+			+ "geZO3SwsDZk71AhDBy30CSzBAgUAx3HB5aOCA+IwggPeMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI"
+			+ "MBMGA1UdIwQMMAqACECefuBmflfeMBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwUAYIKwYBBQUH"
+			+ "AQEERDBCMEAGCCsGAQUFBzABhjRodHRwOi8vb2NzcC1yb290cWMudGMuZGV1dHNjaGUtcmVudGVu"
+			+ "dmVyc2ljaGVydW5nLmRlMHcGA1UdIARwMG4wbAYNKwYBBAGBrTwBCAEBAzBbMFkGCCsGAQUFBwIB"
+			+ "Fk1odHRwOi8vd3d3LmRldXRzY2hlLXJlbnRlbnZlcnNpY2hlcnVuZy1idW5kLmRlL3N0YXRpYy90"
+			+ "cnVzdGNlbnRlci9wb2xpY3kuaHRtbDCCATwGA1UdHwSCATMwggEvMHygeqB4hnZsZGFwOi8vZGly"
+			+ "LnRjLmRldXRzY2hlLXJlbnRlbnZlcnNpY2hlcnVuZy5kZS9vdT1RQyUyMFJvb3QlMjBDQSxjbj1Q"
+			+ "dWJsaWMsbz1EUlYsYz1ERT9hdHRybmFtZT1jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0MIGuoIGr"
+			+ "oIGohoGlaHR0cDovL2Rpci50Yy5kZXV0c2NoZS1yZW50ZW52ZXJzaWNoZXJ1bmcuZGU6ODA4OS9z"
+			+ "ZXJ2bGV0L0Rpclh3ZWIvQ2EveC5jcmw/ZG49b3UlM0RRQyUyMFJvb3QlMjBDQSUyQ2NuJTNEUHVi"
+			+ "bGljJTJDbyUzRERSViUyQ2MlM0RERSZhdHRybmFtZT1jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0"
+			+ "MIIBLQYDVR0SBIIBJDCCASCGdGxkYXA6Ly9kaXIudGMuZGV1dHNjaGUtcmVudGVudmVyc2ljaGVy"
+			+ "dW5nLmRlL2NuPTE0NTUxOCxvdT1RQyUyMFJvb3QlMjBDQSxjbj1QdWJsaWMsbz1EUlYsYz1ERT9h"
+			+ "dHRybmFtZT1jQUNlcnRpZmljYXRlhoGnaHR0cDovL2Rpci50Yy5kZXV0c2NoZS1yZW50ZW52ZXJz"
+			+ "aWNoZXJ1bmcuZGU6ODA4OS9zZXJ2bGV0L0Rpclh3ZWIvQ2EveC5jZXI/ZG49Y24lM0QxNDU1MTgl"
+			+ "MkNvdSUzRFFDJTIwUm9vdCUyMENBJTJDY24lM0RQdWJsaWMlMkNvJTNERFJWJTJDYyUzRERFJmF0"
+			+ "dHJuYW1lPWNBQ2VydGlmaWNhdGUwDgYDVR0PAQH/BAQDAgZAMDsGA1UdCQQ0MDIwMAYDVQQDMSkT"
+			+ "J1FDIFRTUCBEZXV0c2NoZSBSZW50ZW52ZXJzaWNoZXJ1bmcgMTpQTjAMBgNVHRMBAf8EAjAAMA0G"
+			+ "CSqGSIb3DQEBCwUAA4IBAQCCrWe3Pd3ioX7d8phXvVAa859Rvgf0k3pZ6R4GMj8h/k6MNjNIrdAs"
+			+ "wgUVkBbXMLLBk0smsvTdFIVtTBdp1urb9l7vXjDA4MckXBOXPcz4fN8Oswk92d+fM9XU1jKVPsFG"
+			+ "PV6j8lAqfq5jwaRxOnS96UBGLKG+NdcrEyiMp/ZkpqnEQZZfu2mkeq6CPahnbBTZqsE0jgY351gU"
+			+ "9T6SFVvLIFH7cOxJqsoxPqv5YEcgiXPpOyyu2rpQqKYBYcnerF6/zx5hmWHxTd7MWaTHm0gJI/Im"
+			+ "d8esbW+xyaJuAVUcBA+sDmSe8AAoRVxwBRY+xi9ApaJHpmwT+0n2K2GsL3wIMIIEMTCCAxmgAwIB"
+			+ "AgIDAjhuMA0GCSqGSIb3DQEBCwUAMEgxCzAJBgNVBAYTAkRFMSQwIgYDVQQKDBtEZXV0c2NoZSBS"
+			+ "ZW50ZW52ZXJzaWNoZXJ1bmcxEzARBgNVBAsMClFDIFJvb3QgQ0EwHhcNMDcwNzI3MjAyMTExWhcN"
+			+ "MTIwNzI3MjAyMTExWjBIMQswCQYDVQQGEwJERTEkMCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVy"
+			+ "c2ljaGVydW5nMRMwEQYDVQQLDApRQyBSb290IENBMIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIB"
+			+ "DAKCAQEAzuhBdo9c84DdzsggjWOgfC4jJ2jYqpsOpBo3DVyem+5R26QK4feZdyFnaGvyG+TLcdLO"
+			+ "iCecGmrRGD+ey4IhjCONb7hsQQhJWTyDEtBblzYB0yjY8+9fnNeR61W+M/KlMgC6Rw/w+zwzklTM"
+			+ "MWwIbxLHm8l9jTSKFjAWTwjE8bCzpUCwN8+4JbFTwjwOJ5lsVA5Xa34wpgr6lgL3WrVTV1NSprqR"
+			+ "ZYDWg477tht0KkyOJt3guF3RONKBBuTO2qCbpUeI8m4v3tznoopYbV5Gp5wu5gqd6lTfgju3ldql"
+			+ "bxtuCLZd0nAI5rLEOPItDKl4vPXllmmtGIrtDZlwr86cbwIFAJvMJpGjggEgMIIBHDAPBgNVHRMB"
+			+ "Af8EBTADAQH/MBEGA1UdDgQKBAhAnn7gZn5X3jB3BgNVHSAEcDBuMGwGDSsGAQQBga08AQgBAQEw"
+			+ "WzBZBggrBgEFBQcCARZNaHR0cDovL3d3dy5kZXV0c2NoZS1yZW50ZW52ZXJzaWNoZXJ1bmctYnVu"
+			+ "ZC5kZS9zdGF0aWMvdHJ1c3RjZW50ZXIvcG9saWN5Lmh0bWwwUwYDVR0JBEwwSjBIBgNVBAMxQRM/"
+			+ "UUMgV3VyemVsemVydGlmaXppZXJ1bmdzc3RlbGxlIERldXRzY2hlIFJlbnRlbnZlcnNpY2hlcnVu"
+			+ "ZyAxOlBOMBgGCCsGAQUFBwEDBAwwCjAIBgYEAI5GAQEwDgYDVR0PAQH/BAQDAgIEMA0GCSqGSIb3"
+			+ "DQEBCwUAA4IBAQBNGs7Dnc1yzzpZrkuC+oLv+NhbORTEYNgpaOetB1JQ1EbUBoPuNN4ih0ngy/uJ"
+			+ "D2O+h4JsNkmELgaehLWyFwATqCYZY4cTAGVoEwgn93x3aW8JbMDQf+YEJDSDsXcm4oIDFPqv5M6o"
+			+ "HZUWfsPka3mxKivfKtWhooTz1/+BEGReVQ2oOAvlwXlkEab9e3GOqXQUcLPYDTl8BQxiYhtQtf3d"
+			+ "kORiUkuGiGX1YJ5JnZnG3ElMjPgOl8rOiYU7oj9uv1HVb5sdAwuVw0BR/eiMVDBT8DNyfoJmPeQQ"
+			+ "A9pXtoAYO0Ya7wNNmCY2Y63YfBlRCF+9VQv2RZ4TdO1KGWwxR98OMYIC1zCCAtMCAQEwTzBIMQsw"
+			+ "CQYDVQQGEwJERTEkMCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVyc2ljaGVydW5nMRMwEQYDVQQL"
+			+ "DApRQyBSb290IENBAgMDdaYwDQYJYIZIAWUDBAIBBQCgggFZMBoGCSqGSIb3DQEJAzENBgsqhkiG"
+			+ "9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgO7FFODWWwF5RUjo6wjIkgkD5u7dH+NICiCpSgRRqd/Aw"
+			+ "ggEIBgsqhkiG9w0BCRACLzGB+DCB9TCB8jB3BCAMMZqK/5pZxOb3ruCbcgxStaTDwDHaf2glEo6P"
+			+ "+89t8TBTMEykSjBIMQswCQYDVQQGEwJERTEkMCIGA1UECgwbRGV1dHNjaGUgUmVudGVudmVyc2lj"
+			+ "aGVydW5nMRMwEQYDVQQLDApRQyBSb290IENBAgMDdaYwdwQgl7vwI+P47kpxhWLoIdEco7UfGwZ2"
+			+ "X4el3jaZ67q5/9IwUzBMpEowSDELMAkGA1UEBhMCREUxJDAiBgNVBAoMG0RldXRzY2hlIFJlbnRl"
+			+ "bnZlcnNpY2hlcnVuZzETMBEGA1UECwwKUUMgUm9vdCBDQQIDAjhuMA0GCSqGSIb3DQEBCwUABIIB"
+			+ "AIOYgpDI0BaeG4RF/EB5QzkUqAZ9nX6w895+m2hHyRKrAKdj3913j5QI+aEVIG3DVbFaAfdKeKfn"
+			+ "xsTW48aWs6aARtPAc+1OXwoGUSYElOFqqVpSeTaXe+kjY5bsLSQeETB+EPvXl8EcKTaxTRCNOqJU"
+			+ "XbnyYRgWTI55A2jH6IsQQVHc5DaIcmbdI8iATaRTHY5eUeVuI+Q/3RMVBFAb5qRhM61Ddcrjq058"
+			+ "C0uiH9G2IB5QRyu6RsCUgrkeMTMBqlIBlnDBy+EgLouDU4Dehxy5uzEl5DBKZEewZpQZOTO/kAgL"
+			+ "WruAAg/Lj4r0f9vN12wRlHoS2UKDjrE1DnUBbrM=");
+
+		public string Name
+		{
+			get { return "ParseTest"; }
+		}
+
+		private static void requestParse(
+			byte[]	request,
+			string	algorithm)
+		{
+			TimeStampRequest req = new TimeStampRequest(request);
+
+			if (!req.MessageImprintAlgOid.Equals(algorithm))
+			{
+				Assert.Fail("failed to get expected algorithm - got "
+					+ req.MessageImprintAlgOid + " not " + algorithm);
+			}
+
+			if (request != sha1Request && request != sha1noNonse)
+			{
+				if (!req.ReqPolicy.Equals(TspTestUtil.EuroPkiTsaTestPolicy.Id))
+				{
+					Assert.Fail("" + algorithm + " failed policy check.");
+				}
+
+				if (request == ripemd160Request)
+				{
+					if (!req.CertReq)
+					{
+						Assert.Fail("" + algorithm + " failed certReq check.");
+					}
+				}
+			}
+
+			Assert.AreEqual(1, req.Version, "version not 1");
+
+			Assert.IsNull(req.GetCriticalExtensionOids(), "critical extensions found when none expected");
+
+			Assert.IsNull(req.GetNonCriticalExtensionOids(), "non-critical extensions found when none expected");
+
+			if (request != sha1noNonse)
+			{
+				if (req.Nonce == null)
+				{
+					Assert.Fail("" + algorithm + " nonse not found when one expected.");
+				}
+			}
+			else
+			{
+				if (req.Nonce != null)
+				{
+					Assert.Fail("" + algorithm + " nonse not found when one not expected.");
+				}
+			}
+
+			try
+			{
+				req.Validate(TspAlgorithms.Allowed, null, null);
+			}
+			catch (Exception)
+			{
+				Assert.Fail("validation exception.");
+			}
+
+			if (!Arrays.AreEqual(req.GetEncoded(), request))
+			{
+				Assert.Fail("" + algorithm + " failed encode check.");
+			}
+		}
+
+		private static void responseParse(
+			byte[]	request,
+			byte[]	response,
+			string	algorithm)
+		{
+			TimeStampRequest req = new TimeStampRequest(request);
+			TimeStampResponse resp = new TimeStampResponse(response);
+
+			resp.Validate(req);
+
+			X509Certificate cert = new X509CertificateParser().ReadCertificate(signingCert);
+
+			resp.TimeStampToken.Validate(cert);
+		}
+
+		private static void unacceptableResponseParse(
+			byte[] response)
+		{
+			TimeStampResponse resp = new TimeStampResponse(response);
+
+			if (resp.Status != (int) PkiStatus.Rejection)
+			{
+				Assert.Fail("request not rejected.");
+			}
+
+			if (resp.GetFailInfo().IntValue != PkiFailureInfo.UnacceptedPolicy)
+			{
+				Assert.Fail("request not rejected.");
+			}
+		}
+
+		private static void generalizedTimeParse(
+			byte[] response)
+		{
+			TimeStampResponse resp = new TimeStampResponse(response);
+
+			if (resp.Status != (int) PkiStatus.Granted)
+			{
+				Assert.Fail("request not rejected.");
+			}
+		}
+
+		[Test]
+		public void TestSha1()
+		{
+			requestParse(sha1Request, TspAlgorithms.Sha1);
+			requestParse(sha1noNonse, TspAlgorithms.Sha1);
+			responseParse(sha1Request, sha1Response, TspAlgorithms.Sha1);
+			responseParse(sha1noNonse, sha1noNonseResponse, TspAlgorithms.Sha1);
+		}
+
+		[Test]
+		public void TestMD5()
+		{
+			requestParse(md5Request, TspAlgorithms.MD5);
+			responseParse(md5Request, md5Response, TspAlgorithms.MD5);
+		}
+
+		[Test]
+		public void TestRipeMD160()
+		{
+			requestParse(ripemd160Request, TspAlgorithms.RipeMD160);
+		}
+
+		[Test]
+		public void TestUnacceptable()
+		{
+			unacceptableResponseParse(unacceptablePolicy);
+		}
+
+		[Test]
+		public void TestGeneralizedTime()
+		{
+			generalizedTimeParse(generalizedTime);
+		}
+
+		[Test]
+		public void TestV2SigningResponseParse()
+		{
+			v2SigningResponseParse(v2SigningCertResponse);
+		}
+
+		private void v2SigningResponseParse(
+			byte[] encoded)
+		{
+			TimeStampResponse response = new TimeStampResponse(encoded);
+
+			IX509Store store = response.TimeStampToken.GetCertificates("Collection");
+			X509Certificate cert = (X509Certificate)
+				new ArrayList(store.GetMatches(response.TimeStampToken.SignerID))[0];
+
+			response.TimeStampToken.Validate(cert);
+		}
+
+//		public static void parse(
+//			byte[]	encoded,
+//			bool	tokenPresent)
+//		{
+//			TimeStampResponse response = new TimeStampResponse(encoded);
+//
+//			if (tokenPresent && response.TimeStampToken == null)
+//			{
+//				Assert.Fail("token not found when expected.");
+//			}
+//		}
+	}
+}
diff --git a/crypto/test/src/tsp/test/TSPTest.cs b/crypto/test/src/tsp/test/TSPTest.cs
new file mode 100644
index 000000000..e56d4ec9f
--- /dev/null
+++ b/crypto/test/src/tsp/test/TSPTest.cs
@@ -0,0 +1,548 @@
+using System;
+using System.Collections;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Tsp.Tests
+{
+	[TestFixture]
+	public class TspTest
+	{
+		private static AsymmetricKeyParameter privateKey;
+		private static X509Certificate cert;
+		private static IX509Store certs;
+
+		static TspTest()
+		{
+			string signDN = "O=Bouncy Castle, C=AU";
+			AsymmetricCipherKeyPair signKP = TspTestUtil.MakeKeyPair();
+			X509Certificate signCert = TspTestUtil.MakeCACertificate(signKP, signDN, signKP, signDN);
+
+			string origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+			AsymmetricCipherKeyPair origKP = TspTestUtil.MakeKeyPair();
+			privateKey = origKP.Private;
+
+			cert = TspTestUtil.MakeCertificate(origKP, origDN, signKP, signDN);
+
+			IList certList = new ArrayList();
+			certList.Add(cert);
+			certList.Add(signCert);
+
+			certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+		}
+
+		[Test]
+		public void TestBasic()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken  tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			AttributeTable table = tsToken.SignedAttributes;
+
+			Assert.IsNotNull(table[PkcsObjectIdentifiers.IdAASigningCertificate], "no signingCertificate attribute found");
+		}
+
+		[Test]
+		public void TestResponseValidation()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.MD5, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			//
+			// check validation
+			//
+			tsResp.Validate(request);
+
+			try
+			{
+				request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(101));
+
+				tsResp.Validate(request);
+
+				Assert.Fail("response validation failed on invalid nonce.");
+			}
+			catch (TspValidationException)
+			{
+				// ignore
+			}
+
+			try
+			{
+				request = reqGen.Generate(TspAlgorithms.Sha1, new byte[22], BigInteger.ValueOf(100));
+
+				tsResp.Validate(request);
+
+				Assert.Fail("response validation failed on wrong digest.");
+			}
+			catch (TspValidationException)
+			{
+				// ignore
+			}
+
+			try
+			{
+				request = reqGen.Generate(TspAlgorithms.MD5, new byte[20], BigInteger.ValueOf(100));
+
+				tsResp.Validate(request);
+
+				Assert.Fail("response validation failed on wrong digest.");
+			}
+			catch (TspValidationException)
+			{
+				// ignore
+			}
+		}
+
+		[Test]
+		public void TestIncorrectHash()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[16]);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			if (tsToken != null)
+			{
+				Assert.Fail("incorrectHash - token not null.");
+			}
+
+			PkiFailureInfo failInfo = tsResp.GetFailInfo();
+
+			if (failInfo == null)
+			{
+				Assert.Fail("incorrectHash - failInfo set to null.");
+			}
+
+			if (failInfo.IntValue != PkiFailureInfo.BadDataFormat)
+			{
+				Assert.Fail("incorrectHash - wrong failure info returned.");
+			}
+		}
+
+		[Test]
+		public void TestBadAlgorithm()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate("1.2.3.4.5", new byte[20]);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken  tsToken = tsResp.TimeStampToken;
+
+			if (tsToken != null)
+			{
+				Assert.Fail("badAlgorithm - token not null.");
+			}
+
+			PkiFailureInfo failInfo = tsResp.GetFailInfo();
+
+			if (failInfo == null)
+			{
+				Assert.Fail("badAlgorithm - failInfo set to null.");
+			}
+
+			if (failInfo.IntValue != PkiFailureInfo.BadAlg)
+			{
+				Assert.Fail("badAlgorithm - wrong failure info returned.");
+			}
+		}
+
+		[Test]
+		public void TestTimeNotAvailable()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate("1.2.3.4.5", new byte[20]);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(
+				tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, new BigInteger("23"), null);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			if (tsToken != null)
+			{
+				Assert.Fail("timeNotAvailable - token not null.");
+			}
+
+			PkiFailureInfo failInfo = tsResp.GetFailInfo();
+
+			if (failInfo == null)
+			{
+				Assert.Fail("timeNotAvailable - failInfo set to null.");
+			}
+
+			if (failInfo.IntValue != PkiFailureInfo.TimeNotAvailable)
+			{
+				Assert.Fail("timeNotAvailable - wrong failure info returned.");
+			}
+		}
+
+		[Test]
+		public void TestBadPolicy()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+			reqGen.SetReqPolicy("1.1");
+
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20]);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed, new ArrayList());
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			if (tsToken != null)
+			{
+				Assert.Fail("badPolicy - token not null.");
+			}
+
+			PkiFailureInfo  failInfo = tsResp.GetFailInfo();
+
+			if (failInfo == null)
+			{
+				Assert.Fail("badPolicy - failInfo set to null.");
+			}
+
+			if (failInfo.IntValue != PkiFailureInfo.UnacceptedPolicy)
+			{
+				Assert.Fail("badPolicy - wrong failure info returned.");
+			}
+		}
+
+		[Test]
+		public void TestCertReq()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.MD5, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+			//
+			// request with certReq false
+			//
+			reqGen.SetCertReq(false);
+
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			Assert.IsNull(tsToken.TimeStampInfo.GenTimeAccuracy); // check for abscence of accuracy
+
+			Assert.AreEqual("1.2", tsToken.TimeStampInfo.Policy);
+
+			try
+			{
+				tsToken.Validate(cert);
+			}
+			catch (TspValidationException)
+			{
+				Assert.Fail("certReq(false) verification of token failed.");
+			}
+
+			IX509Store respCerts = tsToken.GetCertificates("Collection");
+
+			ICollection certsColl = respCerts.GetMatches(null);
+
+			if (certsColl.Count != 0)
+			{
+				Assert.Fail("certReq(false) found certificates in response.");
+			}
+		}
+
+		[Test]
+		public void TestTokenEncoding()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.Sha1, "1.2.3.4.5.6");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator  reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest           request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+			TimeStampResponse          tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampResponse tsResponse = new TimeStampResponse(tsResp.GetEncoded());
+
+			if (!Arrays.AreEqual(tsResponse.GetEncoded(), tsResp.GetEncoded())
+				|| !Arrays.AreEqual(tsResponse.TimeStampToken.GetEncoded(),
+							tsResp.TimeStampToken.GetEncoded()))
+			{
+				Assert.Fail();
+			}
+		}
+
+		[Test]
+		public void TestAccuracyZeroCerts()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.MD5, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			tsTokenGen.SetAccuracySeconds(1);
+			tsTokenGen.SetAccuracyMillis(2);
+			tsTokenGen.SetAccuracyMicros(3);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken  tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			//
+			// check validation
+			//
+			tsResp.Validate(request);
+
+			//
+			// check tstInfo
+			//
+			TimeStampTokenInfo tstInfo = tsToken.TimeStampInfo;
+
+			//
+			// check accuracy
+			//
+			GenTimeAccuracy accuracy = tstInfo.GenTimeAccuracy;
+
+			Assert.AreEqual(1, accuracy.Seconds);
+			Assert.AreEqual(2, accuracy.Millis);
+			Assert.AreEqual(3, accuracy.Micros);
+
+			Assert.AreEqual(BigInteger.ValueOf(23), tstInfo.SerialNumber);
+
+			Assert.AreEqual("1.2", tstInfo.Policy);
+
+			//
+			// test certReq
+			//
+			IX509Store store = tsToken.GetCertificates("Collection");
+
+			ICollection certificates = store.GetMatches(null);
+
+			Assert.AreEqual(0, certificates.Count);
+		}
+
+		[Test]
+		public void TestAccuracyWithCertsAndOrdering()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.MD5, "1.2.3");
+
+			tsTokenGen.SetCertificates(certs);
+
+			tsTokenGen.SetAccuracySeconds(3);
+			tsTokenGen.SetAccuracyMillis(1);
+			tsTokenGen.SetAccuracyMicros(2);
+
+			tsTokenGen.SetOrdering(true);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+
+			reqGen.SetCertReq(true);
+
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			Assert.IsTrue(request.CertReq);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			//
+			// check validation
+			//
+			tsResp.Validate(request);
+
+			//
+			// check tstInfo
+			//
+			TimeStampTokenInfo tstInfo = tsToken.TimeStampInfo;
+
+			//
+			// check accuracy
+			//
+			GenTimeAccuracy accuracy = tstInfo.GenTimeAccuracy;
+
+			Assert.AreEqual(3, accuracy.Seconds);
+			Assert.AreEqual(1, accuracy.Millis);
+			Assert.AreEqual(2, accuracy.Micros);
+
+			Assert.AreEqual(BigInteger.ValueOf(23), tstInfo.SerialNumber);
+
+			Assert.AreEqual("1.2.3", tstInfo.Policy);
+
+			Assert.AreEqual(true, tstInfo.IsOrdered);
+
+			Assert.AreEqual(tstInfo.Nonce, BigInteger.ValueOf(100));
+
+			//
+			// test certReq
+			//
+			IX509Store store = tsToken.GetCertificates("Collection");
+
+			ICollection certificates = store.GetMatches(null);
+
+			Assert.AreEqual(2, certificates.Count);
+		}
+
+		[Test]
+		public void TestNoNonce()
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				privateKey, cert, TspAlgorithms.MD5, "1.2.3");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20]);
+
+			Assert.IsFalse(request.CertReq);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(24), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			//
+			// check validation
+			//
+			tsResp.Validate(request);
+
+			//
+			// check tstInfo
+			//
+			TimeStampTokenInfo tstInfo = tsToken.TimeStampInfo;
+
+			//
+			// check accuracy
+			//
+			GenTimeAccuracy accuracy = tstInfo.GenTimeAccuracy;
+
+			Assert.IsNull(accuracy);
+
+			Assert.AreEqual(BigInteger.ValueOf(24), tstInfo.SerialNumber);
+
+			Assert.AreEqual("1.2.3", tstInfo.Policy);
+
+			Assert.IsFalse(tstInfo.IsOrdered);
+
+			Assert.IsNull(tstInfo.Nonce);
+
+			//
+			// test certReq
+			//
+			IX509Store store = tsToken.GetCertificates("Collection");
+
+			ICollection certificates = store.GetMatches(null);
+
+			Assert.AreEqual(0, certificates.Count);
+		}
+	}
+}
diff --git a/crypto/test/src/tsp/test/TSPTestUtil.cs b/crypto/test/src/tsp/test/TSPTestUtil.cs
new file mode 100644
index 000000000..f7b0c833a
--- /dev/null
+++ b/crypto/test/src/tsp/test/TSPTestUtil.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Tsp.Tests
+{
+	public class TspTestUtil
+	{
+		public static SecureRandom rand = new SecureRandom();
+		public static IAsymmetricCipherKeyPairGenerator kpg;
+		public static CipherKeyGenerator desede128kg;
+		public static CipherKeyGenerator desede192kg;
+		public static CipherKeyGenerator rc240kg;
+		public static CipherKeyGenerator rc264kg;
+		public static CipherKeyGenerator rc2128kg;
+		public static BigInteger serialNumber = BigInteger.One;
+		public static readonly bool Debug = true;
+		public static DerObjectIdentifier EuroPkiTsaTestPolicy = new DerObjectIdentifier("1.3.6.1.4.1.5255.5.1");
+
+		static TspTestUtil()
+		{
+			rand = new SecureRandom();
+
+			kpg = GeneratorUtilities.GetKeyPairGenerator("RSA");
+			kpg.Init(new RsaKeyGenerationParameters(
+				BigInteger.ValueOf(0x10001), rand, 1024, 25));
+
+			desede128kg = GeneratorUtilities.GetKeyGenerator("DESEDE");
+			desede128kg.Init(new KeyGenerationParameters(rand, 112));
+
+			desede192kg = GeneratorUtilities.GetKeyGenerator("DESEDE");
+			desede192kg.Init(new KeyGenerationParameters(rand, 168));
+
+			rc240kg = GeneratorUtilities.GetKeyGenerator("RC2");
+			rc240kg.Init(new KeyGenerationParameters(rand, 40));
+
+			rc264kg = GeneratorUtilities.GetKeyGenerator("RC2");
+			rc264kg.Init(new KeyGenerationParameters(rand, 64));
+
+			rc2128kg = GeneratorUtilities.GetKeyGenerator("RC2");
+			rc2128kg.Init(new KeyGenerationParameters(rand, 128));
+
+			serialNumber = BigInteger.One;
+		}
+
+		public static string DumpBase64(
+			byte[] data)
+		{
+			StringBuilder buf = new StringBuilder();
+
+			data = Base64.Encode(data);
+
+			for (int i = 0; i < data.Length; i += 64)
+			{
+				if (i + 64 < data.Length)
+				{
+					buf.Append(Encoding.ASCII.GetString(data, i, 64));
+				}
+				else
+				{
+					buf.Append(Encoding.ASCII.GetString(data, i, data.Length - i));
+				}
+				buf.Append('\n');
+			}
+
+			return buf.ToString();
+		}
+
+		public static AsymmetricCipherKeyPair MakeKeyPair()
+		{
+			return kpg.GenerateKeyPair();
+		}
+
+		public static KeyParameter MakeDesede128Key()
+		{
+			return new DesEdeParameters(desede128kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeDesede192Key()
+		{
+			return new DesEdeParameters(desede192kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeRC240Key()
+		{
+			return new RC2Parameters(rc240kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeRC264Key()
+		{
+			return new RC2Parameters(rc264kg.GenerateKey());
+		}
+
+		public static KeyParameter MakeRC2128Key()
+		{
+			return new RC2Parameters(rc2128kg.GenerateKey());
+		}
+
+		public static X509Certificate MakeCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN)
+		{
+			return MakeCertificate(_subKP, _subDN, _issKP, _issDN, false);
+		}
+
+		public static X509Certificate MakeCACertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN)
+		{
+			return MakeCertificate(_subKP, _subDN, _issKP, _issDN, true);
+		}
+
+		public static X509Certificate MakeCertificate(AsymmetricCipherKeyPair _subKP,
+			string _subDN, AsymmetricCipherKeyPair _issKP, string _issDN, bool _ca)
+		{
+			AsymmetricKeyParameter _subPub = _subKP.Public;
+			AsymmetricKeyParameter _issPriv = _issKP.Private;
+			AsymmetricKeyParameter _issPub = _issKP.Public;
+
+			X509V3CertificateGenerator _v3CertGen = new X509V3CertificateGenerator();
+
+			_v3CertGen.Reset();
+			_v3CertGen.SetSerialNumber(allocateSerialNumber());
+			_v3CertGen.SetIssuerDN(new X509Name(_issDN));
+			_v3CertGen.SetNotBefore(DateTime.UtcNow);
+			_v3CertGen.SetNotAfter(DateTime.UtcNow.AddDays(100));
+			_v3CertGen.SetSubjectDN(new X509Name(_subDN));
+			_v3CertGen.SetPublicKey(_subPub);
+			_v3CertGen.SetSignatureAlgorithm("MD5WithRSAEncryption");
+
+			_v3CertGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false,
+					createSubjectKeyId(_subPub));
+
+			_v3CertGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false,
+					createAuthorityKeyId(_issPub));
+
+			if (_ca)
+			{
+				_v3CertGen.AddExtension(X509Extensions.BasicConstraints, false,
+						new BasicConstraints(_ca));
+			}
+			else
+			{
+				_v3CertGen.AddExtension(X509Extensions.ExtendedKeyUsage, true,
+					ExtendedKeyUsage.GetInstance(new DerSequence(KeyPurposeID.IdKPTimeStamping)));
+			}
+
+			X509Certificate _cert = _v3CertGen.Generate(_issPriv);
+
+			_cert.CheckValidity(DateTime.UtcNow);
+			_cert.Verify(_issPub);
+
+			return _cert;
+		}
+
+		/*
+		*
+		*  INTERNAL METHODS
+		*
+		*/
+		private static AuthorityKeyIdentifier createAuthorityKeyId(
+			AsymmetricKeyParameter _pubKey)
+		{
+			return new AuthorityKeyIdentifier(
+				SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_pubKey));
+		}
+
+//		private static AuthorityKeyIdentifier createAuthorityKeyId(
+//			AsymmetricKeyParameter _pubKey, X509Name _name, int _sNumber)
+//		{
+//			SubjectPublicKeyInfo _info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_pubKey);
+//
+//			GeneralName _genName = new GeneralName(_name);
+//
+//			return new AuthorityKeyIdentifier(_info, GeneralNames.GetInstance(
+//				new DerSequence(_genName)), BigInteger.ValueOf(_sNumber));
+//		}
+
+		private static SubjectKeyIdentifier createSubjectKeyId(
+			AsymmetricKeyParameter _pubKey)
+		{
+			return new SubjectKeyIdentifier(
+				SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(_pubKey));
+		}
+
+		private static BigInteger allocateSerialNumber()
+		{
+			BigInteger _tmp = serialNumber;
+			serialNumber = serialNumber.Add(BigInteger.One);
+			return _tmp;
+		}
+	}
+}
\ No newline at end of file
diff --git a/crypto/test/src/tsp/test/TimeStampTokenInfoTest.cs b/crypto/test/src/tsp/test/TimeStampTokenInfoTest.cs
new file mode 100644
index 000000000..5a26f5ef6
--- /dev/null
+++ b/crypto/test/src/tsp/test/TimeStampTokenInfoTest.cs
@@ -0,0 +1,145 @@
+using System;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Tsp.Tests
+{
+	[TestFixture]
+	public class TimeStampTokenInfoUnitTest
+	{
+		private static readonly byte[] tstInfo1 = Hex.Decode(
+			  "303e02010106022a033021300906052b0e03021a050004140000000000000000000000000000000000000000"
+			+ "020118180f32303035313130313038313732315a");
+
+		private static readonly byte[] tstInfo2 = Hex.Decode(
+			  "304c02010106022a033021300906052b0e03021a05000414ffffffffffffffffffffffffffffffffffffffff"
+			+ "020117180f32303035313130313038323934355a3009020103800101810102020164");
+
+		private static readonly byte[] tstInfo3 = Hex.Decode(
+			  "304f02010106022a033021300906052b0e03021a050004140000000000000000000000000000000000000000"
+			+ "020117180f32303035313130313038343733355a30090201038001018101020101ff020164");
+
+		private static readonly byte[] tstInfoDudDate = Hex.Decode(
+			  "303e02010106022a033021300906052b0e03021a050004140000000000000000000000000000000000000000"
+			+ "020118180f32303056313130313038313732315a");
+
+		[Test]
+		public void TestTstInfo1()
+		{
+			TimeStampTokenInfo tstInfo = getTimeStampTokenInfo(tstInfo1);
+
+			//
+			// verify
+			//
+			GenTimeAccuracy accuracy = tstInfo.GenTimeAccuracy;
+
+			Assert.IsNull(accuracy);
+
+			Assert.AreEqual(new BigInteger("24"), tstInfo.SerialNumber);
+
+			Assert.AreEqual(1130833041000L, DateTimeUtilities.DateTimeToUnixMs(tstInfo.GenTime));
+
+			Assert.AreEqual("1.2.3", tstInfo.Policy);
+
+			Assert.AreEqual(false, tstInfo.IsOrdered);
+
+			Assert.IsNull(tstInfo.Nonce);
+
+			Assert.AreEqual(TspAlgorithms.Sha1, tstInfo.MessageImprintAlgOid);
+
+			Assert.IsTrue(Arrays.AreEqual(new byte[20], tstInfo.GetMessageImprintDigest()));
+
+			Assert.IsTrue(Arrays.AreEqual(tstInfo1, tstInfo.GetEncoded()));
+		}
+
+	    [Test]
+		public void TestTstInfo2()
+		{
+			TimeStampTokenInfo tstInfo = getTimeStampTokenInfo(tstInfo2);
+
+			//
+			// verify
+			//
+			GenTimeAccuracy accuracy = tstInfo.GenTimeAccuracy;
+
+			Assert.AreEqual(3, accuracy.Seconds);
+			Assert.AreEqual(1, accuracy.Millis);
+			Assert.AreEqual(2, accuracy.Micros);
+
+			Assert.AreEqual(new BigInteger("23"), tstInfo.SerialNumber);
+
+			Assert.AreEqual(1130833785000L, DateTimeUtilities.DateTimeToUnixMs(tstInfo.GenTime));
+
+			Assert.AreEqual("1.2.3", tstInfo.Policy);
+
+			Assert.AreEqual(false, tstInfo.IsOrdered);
+
+			Assert.AreEqual(tstInfo.Nonce, BigInteger.ValueOf(100));
+
+			Assert.IsTrue(Arrays.AreEqual(Hex.Decode("ffffffffffffffffffffffffffffffffffffffff"), tstInfo.GetMessageImprintDigest()));
+
+			Assert.IsTrue(Arrays.AreEqual(tstInfo2, tstInfo.GetEncoded()));
+		}
+
+	    [Test]
+		public void TestTstInfo3()
+		{
+			TimeStampTokenInfo tstInfo = getTimeStampTokenInfo(tstInfo3);
+
+			//
+			// verify
+			//
+			GenTimeAccuracy accuracy = tstInfo.GenTimeAccuracy;
+
+			Assert.AreEqual(3, accuracy.Seconds);
+			Assert.AreEqual(1, accuracy.Millis);
+			Assert.AreEqual(2, accuracy.Micros);
+
+			Assert.AreEqual(new BigInteger("23"), tstInfo.SerialNumber);
+
+			Assert.AreEqual(1130834855000L, DateTimeUtilities.DateTimeToUnixMs(tstInfo.GenTime));
+
+			Assert.AreEqual("1.2.3", tstInfo.Policy);
+
+			Assert.AreEqual(true, tstInfo.IsOrdered);
+
+			Assert.AreEqual(tstInfo.Nonce, BigInteger.ValueOf(100));
+
+			Assert.AreEqual(TspAlgorithms.Sha1, tstInfo.MessageImprintAlgOid);
+
+			Assert.IsTrue(Arrays.AreEqual(new byte[20], tstInfo.GetMessageImprintDigest()));
+
+			Assert.IsTrue(Arrays.AreEqual(tstInfo3, tstInfo.GetEncoded()));
+		}
+
+		[Test]
+		public void TestTstInfoDudDate()
+		{
+			try
+			{
+				getTimeStampTokenInfo(tstInfoDudDate);
+
+				Assert.Fail("dud date not detected.");
+			}
+			catch (TspException)
+			{
+				// expected
+			}
+		}
+
+		private TimeStampTokenInfo getTimeStampTokenInfo(
+			byte[] tstInfo)
+		{
+			return new TimeStampTokenInfo(
+				TstInfo.GetInstance(
+					Asn1Object.FromByteArray(tstInfo)));
+		}
+	}
+}
diff --git a/crypto/test/src/util/io/pem/test/AllTests.cs b/crypto/test/src/util/io/pem/test/AllTests.cs
new file mode 100644
index 000000000..b44949383
--- /dev/null
+++ b/crypto/test/src/util/io/pem/test/AllTests.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.IO;
+using System.Text;
+
+using NUnit.Core;
+using NUnit.Framework;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Test;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem.Tests
+{
+	[TestFixture]
+	public class AllTests
+	{
+		[Suite]
+		public static TestSuite Suite
+		{
+			get
+			{
+				TestSuite suite = new TestSuite("PEM Utilities Tests");
+				suite.Add(new AllTests());
+				return suite;
+			}
+		}
+
+		[Test]
+		public void TestPemLength()
+		{
+			for (int i = 1; i != 60; i++)
+			{
+				lengthTest("CERTIFICATE", new ArrayList(), new byte[i]);
+			}
+
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[100]);
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[101]);
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[102]);
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[103]);
+
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[1000]);
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[1001]);
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[1002]);
+			lengthTest("CERTIFICATE", new ArrayList(), new byte[1003]);
+
+			IList headers = new ArrayList();
+			headers.Add(new PemHeader("Proc-Type", "4,ENCRYPTED"));
+			headers.Add(new PemHeader("DEK-Info", "DES3,0001020304050607"));
+			lengthTest("RSA PRIVATE KEY", headers, new byte[103]);
+		}
+
+		private void lengthTest(string type, IList headers, byte[] data)
+		{
+			StringWriter sw = new StringWriter();
+			PemWriter pWrt = new PemWriter(sw);
+
+			PemObject pemObj = new PemObject(type, headers, data);
+			pWrt.WriteObject(pemObj);
+			pWrt.Writer.Close();
+
+			Assert.AreEqual(sw.ToString().Length, pWrt.GetOutputSize(pemObj));
+		}
+
+		public static void Main(
+			string[] args)
+        {
+            //junit.textui.TestRunner.run(suite());
+            EventListener el = new NullListener();
+            Suite.Run(el);
+        }
+	}
+}
diff --git a/crypto/test/src/util/net/test/IPAddressTest.cs b/crypto/test/src/util/net/test/IPAddressTest.cs
new file mode 100644
index 000000000..ec40c528a
--- /dev/null
+++ b/crypto/test/src/util/net/test/IPAddressTest.cs
@@ -0,0 +1,61 @@
+using System;
+
+using NUnit.Framework;
+
+namespace Org.BouncyCastle.Utilities.Net.Tests
+{
+	[TestFixture]
+	public class IPTest
+	{
+		private static readonly string[] validIP4v = new string[]
+		{ "0.0.0.0", "255.255.255.255", "192.168.0.0" };
+
+		private static readonly string[] invalidIP4v = new string[]
+		{ "0.0.0.0.1", "256.255.255.255", "1", "A.B.C", "1:.4.6.5" };
+
+		private static readonly string[] validIP6v = new string[]
+		{ "0:0:0:0:0:0:0:0", "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF",
+				"0:1:2:3:FFFF:5:FFFF:1" };
+
+		private static readonly string[] invalidIP6v = new string[]
+		{ "0.0.0.0:1", "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFFF" };
+
+		private void doTestIP(
+			string[]	valid,
+			string[]	invalid)
+		{
+			for (int i = 0; i < valid.Length; i++)
+			{
+				if (!IPAddress.IsValid(valid[i]))
+				{
+					Assert.Fail("Valid input string not accepted: " + valid[i] + ".");
+				}
+			}
+
+			for (int i = 0; i < invalid.Length; i++)
+			{
+				if (IPAddress.IsValid(invalid[i]))
+				{
+					Assert.Fail("Invalid input string accepted: " + invalid[i] + ".");
+				}
+			}
+		}
+
+		public string Name
+		{
+			get { return "IPTest"; }
+		}
+
+		[Test]
+		public void TestIPv4()
+		{
+			doTestIP(validIP4v, invalidIP4v);
+		}
+
+		[Test]
+		public void TestIPv6()
+		{
+			doTestIP(validIP6v, invalidIP6v);
+		}
+	}
+}
diff --git a/crypto/test/src/util/test/FixedSecureRandom.cs b/crypto/test/src/util/test/FixedSecureRandom.cs
new file mode 100644
index 000000000..15a2e9bb3
--- /dev/null
+++ b/crypto/test/src/util/test/FixedSecureRandom.cs
@@ -0,0 +1,64 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Utilities.Test
+{
+	public class FixedSecureRandom
+		: SecureRandom
+	{
+		private byte[]       _data;
+		private int          _index;
+
+		protected FixedSecureRandom(
+			byte[] data)
+		{
+			_data = data;
+		}
+
+		public static FixedSecureRandom From(
+			params byte[][] values)
+		{
+			MemoryStream bOut = new MemoryStream();
+
+			for (int i = 0; i != values.Length; i++)
+			{
+				try
+				{
+					byte[] v = values[i];
+					bOut.Write(v, 0, v.Length);
+				}
+				catch (IOException)
+				{
+					throw new ArgumentException("can't save value array.");
+				}
+			}
+
+			return new FixedSecureRandom(bOut.ToArray());
+		}
+
+		public override void NextBytes(
+			byte[] buf)
+		{
+			Array.Copy(_data, _index, buf, 0, buf.Length);
+
+			_index += buf.Length;
+		}
+
+		public override void NextBytes(
+			byte[]	buf,
+			int		off,
+			int		len)
+		{
+			Array.Copy(_data, _index, buf, off, len);
+
+			_index += len;
+		}
+
+		public bool IsExhausted
+		{
+			get { return _index == _data.Length; }
+		}
+	}
+}
diff --git a/crypto/test/src/util/test/ITest.cs b/crypto/test/src/util/test/ITest.cs
new file mode 100644
index 000000000..30ad82780
--- /dev/null
+++ b/crypto/test/src/util/test/ITest.cs
@@ -0,0 +1,17 @@
+using System;
+
+using NUnit.Framework;
+
+/*
+ Basic test interface
+ */
+namespace Org.BouncyCastle.Utilities.Test
+{
+    public interface ITest
+    {
+        string Name { get; }
+
+		[Test]
+        ITestResult Perform();
+    }
+}
diff --git a/crypto/test/src/util/test/ITestResult.cs b/crypto/test/src/util/test/ITestResult.cs
new file mode 100644
index 000000000..25f0442de
--- /dev/null
+++ b/crypto/test/src/util/test/ITestResult.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Test
+{
+    public interface ITestResult
+    {
+        bool IsSuccessful();
+
+        Exception GetException();
+
+        string ToString();
+    }
+}
diff --git a/crypto/test/src/util/test/NumberParsing.cs b/crypto/test/src/util/test/NumberParsing.cs
new file mode 100644
index 000000000..f9624ef0a
--- /dev/null
+++ b/crypto/test/src/util/test/NumberParsing.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Globalization;
+
+namespace Org.BouncyCastle.Utilities.Test
+{
+    /**
+    * Parsing
+    */
+    public sealed class NumberParsing
+    {
+        private NumberParsing()
+        {
+            // Hide constructor
+        }
+
+		public static long DecodeLongFromHex(
+			string longAsString)
+        {
+            if ((longAsString[1] == 'x')
+                || (longAsString[1] == 'X'))
+            {
+                longAsString = longAsString.Substring(2);
+            }
+
+			return long.Parse(longAsString, NumberStyles.HexNumber);
+        }
+
+		public static int DecodeIntFromHex(
+			string intAsString)
+        {
+            if ((intAsString[1] == 'x')
+                || (intAsString[1] == 'X'))
+            {
+                intAsString = intAsString.Substring(2);
+            }
+
+			return int.Parse(intAsString, NumberStyles.HexNumber);
+        }
+    }
+}
diff --git a/crypto/test/src/util/test/SimpleTest.cs b/crypto/test/src/util/test/SimpleTest.cs
new file mode 100644
index 000000000..be846e20f
--- /dev/null
+++ b/crypto/test/src/util/test/SimpleTest.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Utilities.Test
+{
+    public abstract class SimpleTest
+        : ITest
+    {
+		public abstract string Name
+		{
+			get;
+		}
+
+		private ITestResult Success()
+        {
+            return SimpleTestResult.Successful(this, "Okay");
+        }
+
+        internal void Fail(
+            string message)
+        {
+            throw new TestFailedException(SimpleTestResult.Failed(this, message));
+        }
+
+        internal void Fail(
+            string		message,
+            Exception	throwable)
+        {
+            throw new TestFailedException(SimpleTestResult.Failed(this, message, throwable));
+        }
+
+		internal void Fail(
+            string message,
+            object expected,
+            object found)
+        {
+            throw new TestFailedException(SimpleTestResult.Failed(this, message, expected, found));
+        }
+
+		internal bool AreEqual(
+            byte[] a,
+            byte[] b)
+        {
+			return Arrays.AreEqual(a, b);
+		}
+
+		public virtual ITestResult Perform()
+        {
+            try
+            {
+                PerformTest();
+
+				return Success();
+            }
+            catch (TestFailedException e)
+            {
+                return e.GetResult();
+            }
+            catch (Exception e)
+            {
+                return SimpleTestResult.Failed(this, "Exception: " +  e, e);
+            }
+        }
+
+		internal static void RunTest(
+            ITest test)
+        {
+            RunTest(test, Console.Out);
+        }
+
+		internal static void RunTest(
+            ITest		test,
+            TextWriter	outStream)
+        {
+            ITestResult result = test.Perform();
+
+			outStream.WriteLine(result.ToString());
+            if (result.GetException() != null)
+            {
+                outStream.WriteLine(result.GetException().StackTrace);
+            }
+        }
+
+		internal static Stream GetTestDataAsStream(
+			string name)
+		{
+			string fullName = GetFullName(name);
+
+			return Assembly.GetExecutingAssembly().GetManifestResourceStream(fullName);
+		}
+
+		internal static string[] GetTestDataEntries(
+			string prefix)
+		{
+			string fullPrefix = GetFullName(prefix);
+
+			ArrayList result = new ArrayList();
+			string[] fullNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
+			foreach (string fullName in fullNames)
+			{
+				if (fullName.StartsWith(fullPrefix))
+				{
+					string name = GetShortName(fullName);
+					result.Add(name);
+				}
+			}
+			return (string[])result.ToArray(typeof(String));
+		}
+
+		private static string GetFullName(
+			string name)
+		{
+// TODO MonoDevelop/Visual Studio embedded resource ids still inconsistent
+#if BC_BUILD_MONODEVELOP
+			return "test.data." + name;
+#else
+			return "crypto.test.data." + name;
+#endif
+		}
+
+		private static string GetShortName(
+			string fullName)
+		{
+// TODO MonoDevelop/Visual Studio embedded resource ids still inconsistent
+#if BC_BUILD_MONODEVELOP
+			return fullName.Substring("test.data.".Length);
+#else
+			return fullName.Substring("crypto.test.data.".Length);
+#endif
+		}
+
+#if NETCF_1_0 || NETCF_2_0
+		private static string GetNewLine()
+		{
+			MemoryStream buf = new MemoryStream();
+			StreamWriter w = new StreamWriter(buf, Encoding.ASCII);
+			w.WriteLine();
+			w.Close();
+			byte[] bs = buf.ToArray();
+			return Encoding.ASCII.GetString(bs, 0, bs.Length);
+		}
+
+		internal static string GetEnvironmentVariable(
+			string variable)
+		{
+			return null;
+		}
+#else
+		private static string GetNewLine()
+		{
+			return Environment.NewLine;
+		}
+#endif
+
+		internal static readonly string NewLine = GetNewLine();
+
+		public abstract void PerformTest();
+    }
+}
diff --git a/crypto/test/src/util/test/SimpleTestResult.cs b/crypto/test/src/util/test/SimpleTestResult.cs
new file mode 100644
index 000000000..294f575b7
--- /dev/null
+++ b/crypto/test/src/util/test/SimpleTestResult.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Test
+{
+    public class SimpleTestResult : ITestResult
+    {
+        private static readonly string Separator = SimpleTest.NewLine;
+
+        private bool success;
+        private string message;
+        private Exception exception;
+
+        public SimpleTestResult(
+			bool	success,
+			string	message)
+        {
+            this.success = success;
+            this.message = message;
+        }
+
+        public SimpleTestResult(
+			bool		success,
+			string		message,
+			Exception	exception)
+        {
+            this.success = success;
+            this.message = message;
+            this.exception = exception;
+        }
+
+		public static ITestResult Successful(
+            ITest	test,
+            string	message)
+        {
+            return new SimpleTestResult(true, test.Name + ": " + message);
+        }
+
+        public static ITestResult Failed(
+            ITest	test,
+            string	message)
+        {
+            return new SimpleTestResult(false, test.Name + ": " + message);
+        }
+
+        public static ITestResult Failed(
+            ITest		test,
+            string		message,
+            Exception	t)
+        {
+            return new SimpleTestResult(false, test.Name + ": " + message, t);
+        }
+
+        public static ITestResult Failed(
+            ITest	test,
+            string	message,
+            object	expected,
+            object	found)
+        {
+            return Failed(test, message + Separator + "Expected: " + expected + Separator + "Found   : " + found);
+        }
+
+        public static string FailedMessage(
+			string	algorithm,
+			string	testName,
+			string	expected,
+            string	actual)
+        {
+            StringBuilder sb = new StringBuilder(algorithm);
+            sb.Append(" failing ").Append(testName);
+            sb.Append(Separator).Append("    expected: ").Append(expected);
+            sb.Append(Separator).Append("    got     : ").Append(actual);
+            return sb.ToString();
+        }
+
+		public bool IsSuccessful()
+        {
+            return success;
+        }
+
+        public override string ToString()
+        {
+            return message;
+        }
+
+		public Exception GetException()
+        {
+            return exception;
+        }
+    }
+}
diff --git a/crypto/test/src/util/test/TestFailedException.cs b/crypto/test/src/util/test/TestFailedException.cs
new file mode 100644
index 000000000..ecd7e7d7a
--- /dev/null
+++ b/crypto/test/src/util/test/TestFailedException.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.Test
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT)
+    [Serializable]
+#endif
+    public class TestFailedException
+        : Exception
+    {
+        private ITestResult _result;
+
+        public TestFailedException(
+            ITestResult result)
+        {
+            _result = result;
+        }
+
+        public ITestResult GetResult()
+        {
+            return _result;
+        }
+    }
+}
diff --git a/crypto/test/src/util/test/UncloseableStream.cs b/crypto/test/src/util/test/UncloseableStream.cs
new file mode 100644
index 000000000..8b592cdd4
--- /dev/null
+++ b/crypto/test/src/util/test/UncloseableStream.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Utilities.Test
+{
+	public class UncloseableStream
+		: FilterStream
+	{
+		public UncloseableStream(
+			Stream s)
+			: base(s)
+		{
+		}
+
+		public override void Close()
+		{
+			throw new Exception("Close() called on UncloseableStream");
+		}
+	}
+}
diff --git a/crypto/test/src/x509/test/TestCertificateGen.cs b/crypto/test/src/x509/test/TestCertificateGen.cs
new file mode 100644
index 000000000..8ec5929c7
--- /dev/null
+++ b/crypto/test/src/x509/test/TestCertificateGen.cs
@@ -0,0 +1,715 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using NUnit.Framework;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.X509.Tests
+{
+    [TestFixture]
+    public class TestCertificateGen
+    {
+        public TestCertificateGen()
+        {
+        }
+
+		[Test]
+        public void TestRsaDigestSigner()
+        {
+            BigInteger rsaPubMod = new BigInteger(Base64.Decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt"));
+            BigInteger rsaPubExp = new BigInteger(Base64.Decode("EQ=="));
+            BigInteger rsaPrivMod = new BigInteger(Base64.Decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt"));
+            BigInteger rsaPrivDP = new BigInteger(Base64.Decode("JXzfzG5v+HtLJIZqYMUefJfFLu8DPuJGaLD6lI3cZ0babWZ/oPGoJa5iHpX4Ul/7l3s1PFsuy1GhzCdOdlfRcQ=="));
+            BigInteger rsaPrivDQ = new BigInteger(Base64.Decode("YNdJhw3cn0gBoVmMIFRZzflPDNthBiWy/dUMSRfJCxoZjSnr1gysZHK01HteV1YYNGcwPdr3j4FbOfri5c6DUQ=="));
+            BigInteger rsaPrivExp = new BigInteger(Base64.Decode("DxFAOhDajr00rBjqX+7nyZ/9sHWRCCp9WEN5wCsFiWVRPtdB+NeLcou7mWXwf1Y+8xNgmmh//fPV45G2dsyBeZbXeJwB7bzx9NMEAfedchyOwjR8PYdjK3NpTLKtZlEJ6Jkh4QihrXpZMO4fKZWUm9bid3+lmiq43FwW+Hof8/E="));
+            BigInteger rsaPrivP = new BigInteger(Base64.Decode("AJ9StyTVW+AL/1s7RBtFwZGFBgd3zctBqzzwKPda6LbtIFDznmwDCqAlIQH9X14X7UPLokCDhuAa76OnDXb1OiE="));
+            BigInteger rsaPrivQ = new BigInteger(Base64.Decode("AM3JfD79dNJ5A3beScSzPtWxx/tSLi0QHFtkuhtSizeXdkv5FSba7lVzwEOGKHmW829bRoNxThDy4ds1IihW1w0="));
+            BigInteger rsaPrivQinv = new BigInteger(Base64.Decode("Lt0g7wrsNsQxuDdB8q/rH8fSFeBXMGLtCIqfOec1j7FEIuYA/ACiRDgXkHa0WgN7nLXSjHoy630wC5Toq8vvUg=="));
+            RsaKeyParameters rsaPublic = new RsaKeyParameters(false, rsaPubMod, rsaPubExp);
+			RsaPrivateCrtKeyParameters rsaPrivate = new RsaPrivateCrtKeyParameters(rsaPrivMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv);
+
+            byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 };
+
+            RsaDigestSigner signer = new RsaDigestSigner(new Sha1Digest());
+            signer.Init(true, rsaPrivate);
+            signer.BlockUpdate(msg, 0, msg.Length);
+            byte[] sig = signer.GenerateSignature();
+
+            signer.Init(false,rsaPublic);
+            signer.BlockUpdate(msg, 0, msg.Length);
+            Assert.IsTrue(signer.VerifySignature(sig), "RSA IDigest Signer failed.");
+        }
+
+        [Test]
+        public void TestCreationRSA()
+        {
+            BigInteger rsaPubMod = new BigInteger(Base64.Decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt"));
+            BigInteger rsaPubExp = new BigInteger(Base64.Decode("EQ=="));
+            BigInteger rsaPrivMod = new BigInteger(Base64.Decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt"));
+            BigInteger rsaPrivDP = new BigInteger(Base64.Decode("JXzfzG5v+HtLJIZqYMUefJfFLu8DPuJGaLD6lI3cZ0babWZ/oPGoJa5iHpX4Ul/7l3s1PFsuy1GhzCdOdlfRcQ=="));
+            BigInteger rsaPrivDQ = new BigInteger(Base64.Decode("YNdJhw3cn0gBoVmMIFRZzflPDNthBiWy/dUMSRfJCxoZjSnr1gysZHK01HteV1YYNGcwPdr3j4FbOfri5c6DUQ=="));
+            BigInteger rsaPrivExp = new BigInteger(Base64.Decode("DxFAOhDajr00rBjqX+7nyZ/9sHWRCCp9WEN5wCsFiWVRPtdB+NeLcou7mWXwf1Y+8xNgmmh//fPV45G2dsyBeZbXeJwB7bzx9NMEAfedchyOwjR8PYdjK3NpTLKtZlEJ6Jkh4QihrXpZMO4fKZWUm9bid3+lmiq43FwW+Hof8/E="));
+            BigInteger rsaPrivP = new BigInteger(Base64.Decode("AJ9StyTVW+AL/1s7RBtFwZGFBgd3zctBqzzwKPda6LbtIFDznmwDCqAlIQH9X14X7UPLokCDhuAa76OnDXb1OiE="));
+            BigInteger rsaPrivQ = new BigInteger(Base64.Decode("AM3JfD79dNJ5A3beScSzPtWxx/tSLi0QHFtkuhtSizeXdkv5FSba7lVzwEOGKHmW829bRoNxThDy4ds1IihW1w0="));
+            BigInteger rsaPrivQinv = new BigInteger(Base64.Decode("Lt0g7wrsNsQxuDdB8q/rH8fSFeBXMGLtCIqfOec1j7FEIuYA/ACiRDgXkHa0WgN7nLXSjHoy630wC5Toq8vvUg=="));
+            RsaKeyParameters rsaPublic = new RsaKeyParameters(false, rsaPubMod, rsaPubExp);
+			RsaPrivateCrtKeyParameters rsaPrivate = new RsaPrivateCrtKeyParameters(rsaPrivMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv);
+
+			IDictionary attrs = new Hashtable();
+            attrs[X509Name.C] = "AU";
+            attrs[X509Name.O] = "The Legion of the Bouncy Castle";
+            attrs[X509Name.L] = "Melbourne";
+            attrs[X509Name.ST] = "Victoria";
+            attrs[X509Name.E] = "feedback-crypto@bouncycastle.org";
+
+            IList ord = new ArrayList();
+            ord.Add(X509Name.C);
+            ord.Add(X509Name.O);
+            ord.Add(X509Name.L);
+            ord.Add(X509Name.ST);
+            ord.Add(X509Name.E);
+
+			IList values = new ArrayList();
+			values.Add("AU");
+            values.Add("The Legion of the Bouncy Castle");
+            values.Add("Melbourne");
+            values.Add("Victoria");
+            values.Add("feedback-crypto@bouncycastle.org");
+
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+
+            certGen.SetIssuerDN(new X509Name(ord, attrs));
+			certGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));
+			certGen.SetNotAfter(DateTime.UtcNow.AddDays(1));
+            certGen.SetSubjectDN(new X509Name(ord, attrs));
+            certGen.SetPublicKey(rsaPublic);
+            certGen.SetSignatureAlgorithm("MD5WithRSAEncryption");
+
+			X509Certificate cert = certGen.Generate(rsaPrivate);
+
+//			Assert.IsTrue((cert.IsValidNow && cert.Verify(rsaPublic)),"Certificate failed to be valid (RSA)");
+			cert.CheckValidity();
+			cert.Verify(rsaPublic);
+
+			//Console.WriteLine(ASN1Dump.DumpAsString(cert.ToAsn1Object()));
+
+            //ISet dummySet = cert.GetNonCriticalExtensionOids();
+
+            //if (dummySet != null)
+            //{
+            //    foreach (string key in dummySet)
+            //    {
+            //        Console.WriteLine("\t{0}:\t{1}", key);
+            //    }
+            //}
+
+            //Console.WriteLine();
+
+            //dummySet = cert.GetNonCriticalExtensionOids();
+            //if (dummySet != null)
+            //{
+            //    foreach (string key in dummySet)
+            //    {
+            //        Console.WriteLine("\t{0}:\t{1}", key);
+            //    }
+            //}
+
+            //Console.WriteLine();
+        }
+
+		[Test]
+        public void TestCreationDSA()
+        {
+            BigInteger DSAParaG = new BigInteger(Base64.Decode("AL0fxOTq10OHFbCf8YldyGembqEu08EDVzxyLL29Zn/t4It661YNol1rnhPIs+cirw+yf9zeCe+KL1IbZ/qIMZM="));
+            BigInteger DSAParaP = new BigInteger(Base64.Decode("AM2b/UeQA+ovv3dL05wlDHEKJ+qhnJBsRT5OB9WuyRC830G79y0R8wuq8jyIYWCYcTn1TeqVPWqiTv6oAoiEeOs="));
+            BigInteger DSAParaQ = new BigInteger(Base64.Decode("AIlJT7mcKL6SUBMmvm24zX1EvjNx"));
+            BigInteger DSAPublicY = new BigInteger(Base64.Decode("TtWy2GuT9yGBWOHi1/EpCDa/bWJCk2+yAdr56rAcqP0eHGkMnA9s9GJD2nGU8sFjNHm55swpn6JQb8q0agrCfw=="));
+            BigInteger DsaPrivateX = new BigInteger(Base64.Decode("MMpBAxNlv7eYfxLTZ2BItJeD31A="));
+
+            DsaParameters para = new DsaParameters(DSAParaP, DSAParaQ, DSAParaG);
+            DsaPrivateKeyParameters dsaPriv = new DsaPrivateKeyParameters(DsaPrivateX, para);
+            DsaPublicKeyParameters dsaPub = new DsaPublicKeyParameters(DSAPublicY, para);
+
+            IDictionary attrs = new Hashtable();
+            attrs[X509Name.C] = "AU";
+            attrs[X509Name.O] = "The Legion of the Bouncy Castle";
+            attrs[X509Name.L] = "Melbourne";
+            attrs[X509Name.ST] = "Victoria";
+            attrs[X509Name.E] = "feedback-crypto@bouncycastle.org";
+
+            IList ord = new ArrayList();
+            ord.Add(X509Name.C);
+            ord.Add(X509Name.O);
+            ord.Add(X509Name.L);
+            ord.Add(X509Name.ST);
+            ord.Add(X509Name.E);
+
+            IList values = new ArrayList();
+			values.Add("AU");
+            values.Add("The Legion of the Bouncy Castle");
+            values.Add("Melbourne");
+            values.Add("Victoria");
+            values.Add("feedback-crypto@bouncycastle.org");
+
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+			certGen.SetSerialNumber(BigInteger.One);
+
+            certGen.SetIssuerDN(new X509Name(ord, attrs));
+			certGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));
+			certGen.SetNotAfter(DateTime.UtcNow.AddDays(1));
+            certGen.SetSubjectDN(new X509Name(ord, attrs));
+            certGen.SetPublicKey(dsaPub);
+            certGen.SetSignatureAlgorithm("SHA1WITHDSA");
+
+            X509Certificate cert = certGen.Generate(dsaPriv);
+
+//			Assert.IsTrue((cert.IsValidNow && cert.Verify(dsaPub)), "Certificate failed to be valid (DSA Test)");
+			cert.CheckValidity();
+			cert.Verify(dsaPub);
+
+            //ISet dummySet = cert.GetNonCriticalExtensionOids();
+
+            //if (dummySet != null)
+            //{
+            //    foreach (string key in dummySet)
+            //    {
+            //        Console.WriteLine("\t{0}:\t{1}", key);
+            //    }
+            //}
+
+            //Console.WriteLine();
+
+            //dummySet = cert.GetNonCriticalExtensionOids();
+            //if (dummySet != null)
+            //{
+            //    foreach (string key in dummySet)
+            //    {
+            //        Console.WriteLine("\t{0}:\t{1}", key);
+            //    }
+            //}
+
+            //Console.WriteLine();
+        }
+
+		[Test]
+        public void TestCreationECDSA()
+        {
+            BigInteger ECParraGX = new BigInteger(Base64.Decode("D/qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqv"));
+            BigInteger ECParraGY = new BigInteger(Base64.Decode("AhQXGxb1olGRv6s1LPRfuatMF+cx3ZTGgzSE/Q5R"));
+            BigInteger ECParraH = new BigInteger(Base64.Decode("AQ=="));
+            BigInteger ECParraN = new BigInteger(Base64.Decode("f///////////////f///nl6an12QcfvRUiaIkJ0L"));
+            BigInteger ECPubQX = new BigInteger(Base64.Decode("HWWi17Yb+Bm3PYr/DMjLOYNFhyOwX1QY7ZvqqM+l"));
+            BigInteger ECPubQY = new BigInteger(Base64.Decode("JrlJfxu3WGhqwtL/55BOs/wsUeiDFsvXcGhB8DGx"));
+            BigInteger ECPrivD = new BigInteger(Base64.Decode("GYQmd/NF1B+He1iMkWt3by2Az6Eu07t0ynJ4YCAo"));
+            FpCurve curve = new FpCurve(
+               new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q
+                new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a
+                new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b
+            ECDomainParameters ecDomain =
+                new ECDomainParameters(curve, new FpPoint(curve, curve.FromBigInteger(ECParraGX), curve.FromBigInteger(ECParraGY)), ECParraN);
+            ECPublicKeyParameters ecPub = new ECPublicKeyParameters(
+				"ECDSA",
+				new FpPoint(curve,
+					curve.FromBigInteger(ECPubQX),
+					curve.FromBigInteger(ECPubQY)),
+				ecDomain);
+            ECPrivateKeyParameters ecPriv = new ECPrivateKeyParameters("ECDSA", ECPrivD, ecDomain);
+
+
+            IDictionary attrs = new Hashtable();
+			attrs[X509Name.C] = "AU";
+            attrs[X509Name.O] = "The Legion of the Bouncy Castle";
+            attrs[X509Name.L] = "Melbourne";
+            attrs[X509Name.ST] = "Victoria";
+            attrs[X509Name.E] = "feedback-crypto@bouncycastle.org";
+
+            IList ord = new ArrayList();
+            ord.Add(X509Name.C);
+            ord.Add(X509Name.O);
+            ord.Add(X509Name.L);
+            ord.Add(X509Name.ST);
+            ord.Add(X509Name.E);
+
+			IList values = new ArrayList();
+			values.Add("AU");
+            values.Add("The Legion of the Bouncy Castle");
+            values.Add("Melbourne");
+            values.Add("Victoria");
+            values.Add("feedback-crypto@bouncycastle.org");
+
+            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+
+            certGen.SetSerialNumber(BigInteger.One);
+
+            certGen.SetIssuerDN(new X509Name(ord, attrs));
+            certGen.SetNotBefore(DateTime.Today.Subtract(new TimeSpan(1, 0, 0, 0)));
+            certGen.SetNotAfter(DateTime.Today.AddDays(1));
+            certGen.SetSubjectDN(new X509Name(ord, attrs));
+            certGen.SetPublicKey(ecPub);
+            certGen.SetSignatureAlgorithm("SHA1WITHECDSA");
+
+
+            X509Certificate cert = certGen.Generate(ecPriv);
+
+//            Assert.IsTrue((cert.IsValidNow && cert.Verify(ecPub)), "Certificate failed to be valid (ECDSA)");
+			cert.CheckValidity();
+			cert.Verify(ecPub);
+
+            //ISet dummySet = cert.GetNonCriticalExtensionOids();
+
+            //if (dummySet != null)
+            //{
+            //    foreach (string key in dummySet)
+            //    {
+            //        Console.WriteLine("\t{0}:\t{1}", key);
+            //    }
+            //}
+
+            //Console.WriteLine();
+
+            //dummySet = cert.GetNonCriticalExtensionOids();
+
+            //if (dummySet != null)
+            //{
+            //    foreach (string key in dummySet)
+            //    {
+            //        Console.WriteLine("\t{0}:\t{1}", key);
+            //    }
+            //}
+
+            //Console.WriteLine();
+        }
+
+		[Test]
+		public void TestCertLoading()
+        {
+            byte[] cert1 = Base64.Decode(
+                   "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+                 + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+                 + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+                 + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+                 + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2"
+                 + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+                 + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+                 + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l"
+                 + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv"
+                 + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re"
+                 + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO"
+                 + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE"
+                 + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy"
+                 + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0"
+                 + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw"
+                 + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL"
+                 + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4"
+                 + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF"
+                 + "5/8=");
+
+			try
+			{
+                Assert.IsNotNull(new X509CertificateParser().ReadCertificate(cert1));
+            }
+			catch (Exception)
+            {
+                Assert.Fail("Reading first test certificate.");
+            }
+
+
+			// ca.crt
+            //
+            byte[] cert2 = Base64.Decode(
+                   "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx"
+                 + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY"
+                 + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB"
+                 + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ"
+                 + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2"
+                 + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW"
+                 + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM"
+                 + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u"
+                 + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t"
+                 + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv"
+                 + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s"
+                 + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur"
+                 + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl"
+                 + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E"
+                 + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG"
+                 + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk"
+                 + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz"
+                 + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ"
+                 + "DhkaJ8VqOMajkQFma2r9iA==");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(cert2));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading second test certificate.");
+			}
+
+
+            //
+            // testx509.pem
+            //
+            byte[] cert3 = Base64.Decode(
+                   "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV"
+                 + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz"
+                 + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM"
+                 + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF"
+                 + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO"
+                 + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE"
+                 + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ"
+                 + "zl9HYIMxATFyqSiD9jsx");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(cert3));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading third test certificate. (X509.pem)");
+			}
+
+
+			//
+            // v3-cert1.pem
+            //
+            byte[] cert4 = Base64.Decode(
+                   "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx"
+                 + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz"
+                 + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw"
+                 + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu"
+                 + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2"
+                 + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp"
+                 + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C"
+                 + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK"
+                 + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x"
+                 + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR"
+                 + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB"
+                 + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21"
+                 + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3"
+                 + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(cert4));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading fourth test certificate. (X509 V3 Pem)");
+			}
+
+
+			//
+            // v3-cert2.pem
+            //
+            byte[] cert5 = Base64.Decode(
+                   "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD"
+                 + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0"
+                 + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu"
+                 + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1"
+                 + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV"
+                 + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx"
+                 + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA"
+                 + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT"
+                 + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ"
+                 + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm"
+                 + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc"
+                 + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz"
+                 + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap"
+                 + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU=");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(cert5));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading fifth test certificate. (X509 V3 Pem)");
+			}
+
+
+            //
+            // pem encoded pkcs7
+            //
+            byte[] cert6 = Base64.Decode(
+                  "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w"
+                + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG"
+                + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy"
+                + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw"
+                + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi"
+                + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A"
+                + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH"
+                + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF"
+                + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d"
+                + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix"
+                + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR"
+                + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD"
+                + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj"
+                + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy"
+                + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy"
+                + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j"
+                + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg"
+                + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B"
+                + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB"
+                + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc"
+                + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG"
+                + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv"
+                + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B"
+                + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0"
+                + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg"
+                + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ"
+                + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln"
+                + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB"
+                + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx"
+                + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy"
+                + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD"
+                + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl"
+                + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz"
+                + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m"
+                + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv"
+                + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb"
+                + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK"
+                + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB"
+                + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0"
+                + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo"
+                + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB"
+                + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R"
+                + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y"
+                + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j"
+                + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu"
+                + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE"
+                + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg"
+                + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG"
+                + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU"
+                + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG"
+                + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w"
+                + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O"
+                + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy"
+                + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA==");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(cert6));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading sixth test certificate. (Pkcs7)");
+			}
+
+
+            //
+            // dsaWithSHA1 cert
+            //
+            byte[] cert7 = Base64.Decode(
+                  "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG"
+                + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7"
+                + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh"
+                + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj"
+                + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z"
+                + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa"
+                + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw"
+                + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj"
+                + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE"
+                + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3"
+                + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn"
+                + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc"
+                + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg"
+                + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q"
+                + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH"
+                + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC"
+                + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC"
+                + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY"
+                + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1"
+                + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ"
+                + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T"
+                + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU"
+                + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji"
+                + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID"
+                + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh"
+                + "cg==");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(cert7));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading seventh test certificate. (DSAWITHSHA1)");
+			}
+
+
+            //
+            // ecdsa cert with extra octet string.
+            //
+            byte[] oldEcdsa = Base64.Decode(
+                  "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ"
+                + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw"
+                + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV"
+                + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w"
+                + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb"
+                + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ"
+                + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5"
+                + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///"
+                + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////"
+                + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/"
+                + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq"
+                + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw"
+                + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G"
+                + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(oldEcdsa));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading old ECDSA Certificate.");
+			}
+
+
+            byte[] uncompressedPtEC = Base64.Decode(
+                  "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ"
+                + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD"
+                + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw"
+                + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK"
+                + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G"
+                + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0"
+                + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ"
+                + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT"
+                + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2"
+                + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7"
+                + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA"
+                + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD"
+                + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn"
+                + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH"
+                + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB"
+                + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI"
+                + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt"
+                + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD"
+                + "z+fauEg=");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(uncompressedPtEC));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading uncompressed ECPoint Certificate.");
+			}
+
+
+			byte[] keyUsage = Base64.Decode(
+                  "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE"
+                + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50"
+                + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs"
+                + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp"
+                + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0"
+                + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa"
+                + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV"
+                + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw"
+                + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50"
+                + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50"
+                + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL"
+                + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv"
+                + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV"
+                + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173"
+                + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw"
+                + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50"
+                + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff"
+                + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE"
+                + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50"
+                + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD"
+                + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D"
+                + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx"
+                + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW"
+                + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG"
+                + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI"
+                + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ"
+                + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU"
+                + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE"
+                + "PHayXOw=");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(keyUsage));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading Cert with Key Usage.");
+			}
+
+
+            byte[] nameCert = Base64.Decode(
+                "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE" +
+                "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg" +
+                "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0" +
+                "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I" +
+                "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4" +
+                "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ" +
+                "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug" +
+                "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps" +
+                "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z" +
+                "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD" +
+                "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k" +
+                "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu" +
+                "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1" +
+                "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0" +
+                "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG" +
+                "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi" +
+                "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT" +
+                "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB" +
+                "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3" +
+                "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg" +
+                "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs" +
+                "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(nameCert));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading Named Certificate.");
+			}
+
+
+			byte[] probSelfSignedCert = Base64.Decode(
+                   "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF"
+                 + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV"
+                 + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy"
+                 + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT"
+                 + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB"
+                 + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m"
+                 + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt"
+                 + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB"
+                 + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU"
+                 + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB"
+                 + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0"
+                 + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN"
+                 + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9"
+                 + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/"
+                 + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs=");
+
+			try
+			{
+				Assert.IsNotNull(new X509CertificateParser().ReadCertificate(probSelfSignedCert));
+			}
+			catch (Exception)
+			{
+				Assert.Fail("Reading busted Certificate.");
+			}
+		}
+	}
+}
diff --git a/crypto/testcfg.nunit b/crypto/testcfg.nunit
new file mode 100644
index 000000000..e4061da06
--- /dev/null
+++ b/crypto/testcfg.nunit
@@ -0,0 +1,6 @@
+<NUnitProject>
+  <Settings activeconfig="Default" />
+  <Config name="Default" binpathtype="Auto">
+    <assembly path="./test/bin/BCTest.dll" />
+  </Config>
+</NUnitProject>
diff --git a/csharp.sln b/csharp.sln
new file mode 100644
index 000000000..ce64a084a
--- /dev/null
+++ b/csharp.sln
@@ -0,0 +1,29 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "crypto", "crypto\crypto.csproj", "{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "crypto-test", "crypto-test\crypto-test.csproj", "{C857AD68-8F1B-4C7A-A76B-3DC03CBE4FB0}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfiguration) = preSolution
+		Debug = Debug
+		Release = Release
+	EndGlobalSection
+	GlobalSection(ProjectConfiguration) = postSolution
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Debug.ActiveCfg = Debug|.NET
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Debug.Build.0 = Debug|.NET
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Release.ActiveCfg = Release|.NET
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Release.Build.0 = Release|.NET
+		{C857AD68-8F1B-4C7A-A76B-3DC03CBE4FB0}.Debug.ActiveCfg = Debug|.NET
+		{C857AD68-8F1B-4C7A-A76B-3DC03CBE4FB0}.Debug.Build.0 = Debug|.NET
+		{C857AD68-8F1B-4C7A-A76B-3DC03CBE4FB0}.Release.ActiveCfg = Release|.NET
+		{C857AD68-8F1B-4C7A-A76B-3DC03CBE4FB0}.Release.Build.0 = Release|.NET
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal